i386: Allow all register_operand SUBREGs in x86_ternlog_idx.
[official-gcc.git] / gcc / go / gofrontend / embed.cc
blob6dada5efc2a3928f6e75e71e52053a4e9dfb09d6
1 // embed.cc -- Go frontend go:embed handling.
3 // Copyright 2021 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
7 #include "go-system.h"
9 #include "operator.h"
10 #include "go-diagnostics.h"
11 #include "lex.h"
12 #include "types.h"
13 #include "expressions.h"
14 #include "gogo.h"
16 #ifndef O_BINARY
17 #define O_BINARY 0
18 #endif
20 // Read a file into *DATA. Returns false on error.
22 bool
23 Gogo::read_file(const char* filename, Location loc, std::string* data)
25 int fd = open(filename, O_RDONLY | O_BINARY);
26 if (fd < 0)
28 go_error_at(loc, "%s: %m", filename);
29 return false;
32 struct stat st;
33 if (fstat(fd, &st) < 0)
35 go_error_at(loc, "%s: %m", filename);
36 return false;
38 off_t want = st.st_size;
40 // Most files read here are going to be incorporated into the object file
41 // and then the executable. Set a limit on the size we will accept.
42 if (want > 2000000000)
44 go_error_at(loc, "%s: file too large", filename);
45 return false;
48 data->resize(want);
49 off_t got = 0;
50 while (want > 0)
52 // C++11 requires that std::string use contiguous bytes, so this
53 // is safe.
54 ssize_t n = read(fd, &(*data)[got], want);
55 if (n < 0)
57 close(fd);
58 go_error_at(loc, "%s: %m", filename);
59 return false;
61 if (n == 0)
63 data->resize(got);
64 break;
66 got += n;
67 want -= n;
70 close(fd);
71 return true;
74 // A JSON value as read from an embedcfg file. For our purposes a
75 // JSON value is a string, or a list of strings, or a mapping from
76 // strings to values. We don't expect any numbers. We also don't
77 // expect an array of anything other than strings; that is, we don't
78 // accept an array of general JSON values.
80 class Json_value
82 public:
83 // The types of values.
84 enum Json_value_classification
86 JSON_VALUE_UNKNOWN,
87 JSON_VALUE_STRING,
88 JSON_VALUE_ARRAY,
89 JSON_VALUE_MAP
92 Json_value()
93 : classification_(JSON_VALUE_UNKNOWN), string_(), array_(), map_()
94 { }
96 ~Json_value();
98 Json_value_classification
99 classification() const
100 { return this->classification_; }
102 // Set to a string value.
103 void
104 set_string(const std::string& str)
106 go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
107 this->classification_ = JSON_VALUE_STRING;
108 this->string_ = str;
111 // Start an array value.
112 void
113 start_array()
115 go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
116 this->classification_ = JSON_VALUE_ARRAY;
119 // Add an array entry.
120 void
121 add_array_entry(const std::string& s)
123 go_assert(this->classification_ == JSON_VALUE_ARRAY);
124 this->array_.push_back(s);
127 // Start a map value.
128 void
129 start_map()
131 go_assert(this->classification_ == JSON_VALUE_UNKNOWN);
132 this->classification_ = JSON_VALUE_MAP;
135 // Add a map entry.
136 void
137 add_map_entry(const std::string& key, Json_value* val)
139 go_assert(this->classification_ == JSON_VALUE_MAP);
140 this->map_[key] = val;
143 // Return the strings from a string value.
144 const std::string&
145 to_string() const
147 go_assert(this->classification_ == JSON_VALUE_STRING);
148 return this->string_;
151 // Fetch a vector of strings, and drop them from the JSON value.
152 void
153 get_and_clear_array(std::vector<std::string>* v)
155 go_assert(this->classification_ == JSON_VALUE_ARRAY);
156 std::swap(*v, this->array_);
159 // Look up a map entry. Returns NULL if not found.
160 Json_value*
161 lookup_map_entry(const std::string& key);
163 // Iterate over a map.
164 typedef Unordered_map(std::string, Json_value*)::iterator map_iterator;
166 map_iterator
167 map_begin()
169 go_assert(this->classification_ == JSON_VALUE_MAP);
170 return this->map_.begin();
173 map_iterator
174 map_end()
175 { return this->map_.end(); }
177 private:
178 // Classification.
179 Json_value_classification classification_;
180 // A string, for JSON_VALUE_STRING.
181 std::string string_;
182 // Array, for JSON_VALUE_ARRAY.
183 std::vector<std::string> array_;
184 // Mapping, for JSON_VALUE_MAP.
185 Unordered_map(std::string, Json_value*) map_;
188 // Delete a JSON value.
190 Json_value::~Json_value()
192 if (this->classification_ == JSON_VALUE_MAP)
194 for (map_iterator p = this->map_begin();
195 p != this->map_end();
196 ++p)
197 delete p->second;
201 // Look up a map entry in a JSON value.
203 Json_value*
204 Json_value::lookup_map_entry(const std::string& key)
206 go_assert(this->classification_ == JSON_VALUE_MAP);
207 Unordered_map(std::string, Json_value*)::iterator p = this->map_.find(key);
208 if (p == this->map_.end())
209 return NULL;
210 return p->second;
213 // Manage reading the embedcfg file.
215 class Embedcfg_reader
217 public:
218 Embedcfg_reader(const char* filename)
219 : filename_(filename), data_(), p_(NULL), pend_(NULL)
222 // Read the contents of FILENAME. Return whether it succeeded.
223 bool
224 initialize_from_file();
226 // Read a JSON object.
227 bool
228 read_object(Json_value*);
230 // Report an error if not at EOF.
231 void
232 check_eof();
234 // Report an error for the embedcfg file.
235 void
236 error(const char* msg);
238 private:
239 bool
240 read_value(Json_value*);
242 bool
243 read_array(Json_value*);
245 bool
246 read_string(std::string*);
248 bool
249 skip_whitespace(bool eof_ok);
251 // File name.
252 const char* filename_;
253 // File contents.
254 std::string data_;
255 // Next character to process.
256 const char *p_;
257 // End of data.
258 const char *pend_;
261 // Read the embedcfg file.
263 void
264 Gogo::read_embedcfg(const char *filename)
266 class Embedcfg_reader r(filename);
267 if (!r.initialize_from_file())
268 return;
270 Json_value val;
271 if (!r.read_object(&val))
272 return;
274 r.check_eof();
276 if (val.classification() != Json_value::JSON_VALUE_MAP)
278 r.error("invalid embedcfg: not a JSON object");
279 return;
282 Json_value* patterns = val.lookup_map_entry("Patterns");
283 if (patterns == NULL)
285 r.error("invalid embedcfg: missing Patterns");
286 return;
288 if (patterns->classification() != Json_value::JSON_VALUE_MAP)
290 r.error("invalid embedcfg: Patterns is not a JSON object");
291 return;
294 Json_value* files = val.lookup_map_entry("Files");
295 if (files == NULL)
297 r.error("invalid embedcfg: missing Files");
298 return;
300 if (files->classification() != Json_value::JSON_VALUE_MAP)
302 r.error("invalid embedcfg: Files is not a JSON object");
303 return;
306 for (Json_value::map_iterator p = patterns->map_begin();
307 p != patterns->map_end();
308 ++p)
310 if (p->second->classification() != Json_value::JSON_VALUE_ARRAY)
312 r.error("invalid embedcfg: Patterns entry is not an array");
313 return;
315 std::vector<std::string> files;
316 p->second->get_and_clear_array(&files);
318 std::pair<std::string, std::vector<std::string> > val;
319 val.first = p->first;
320 std::pair<Embed_patterns::iterator, bool> ins =
321 this->embed_patterns_.insert(val);
322 if (!ins.second)
324 r.error("invalid embedcfg: duplicate Patterns entry");
325 return;
327 std::swap(ins.first->second, files);
330 for (Json_value::map_iterator p = files->map_begin();
331 p != files->map_end();
332 ++p)
334 if (p->second->classification() != Json_value::JSON_VALUE_STRING)
336 r.error("invalid embedcfg: Files entry is not a string");
337 return;
339 this->embed_files_[p->first] = p->second->to_string();
343 // Read the contents of FILENAME into this->data_. Returns whether it
344 // succeeded.
346 bool
347 Embedcfg_reader::initialize_from_file()
349 if (!Gogo::read_file(this->filename_, Linemap::unknown_location(),
350 &this->data_))
351 return false;
352 if (this->data_.empty())
354 this->error("empty file");
355 return false;
357 this->p_ = this->data_.data();
358 this->pend_ = this->p_ + this->data_.size();
359 return true;
362 // Read a JSON object into VAL. Return whether it succeeded.
364 bool
365 Embedcfg_reader::read_object(Json_value* val)
367 if (!this->skip_whitespace(false))
368 return false;
369 if (*this->p_ != '{')
371 this->error("expected %<{%>");
372 return false;
374 ++this->p_;
376 val->start_map();
378 if (!this->skip_whitespace(false))
379 return false;
380 if (*this->p_ == '}')
382 ++this->p_;
383 return true;
386 while (true)
388 if (!this->skip_whitespace(false))
389 return false;
390 if (*this->p_ != '"')
392 this->error("expected %<\"%>");
393 return false;
396 std::string key;
397 if (!this->read_string(&key))
398 return false;
400 if (!this->skip_whitespace(false))
401 return false;
402 if (*this->p_ != ':')
404 this->error("expected %<:%>");
405 return false;
407 ++this->p_;
409 Json_value* subval = new Json_value();
410 if (!this->read_value(subval))
411 return false;
413 val->add_map_entry(key, subval);
415 if (!this->skip_whitespace(false))
416 return false;
417 if (*this->p_ == '}')
419 ++this->p_;
420 return true;
422 if (*this->p_ != ',')
424 this->error("expected %<,%> or %<}%>");
425 return false;
427 ++this->p_;
431 // Read a JSON array into VAL. Return whether it succeeded.
433 bool
434 Embedcfg_reader::read_array(Json_value* val)
436 if (!this->skip_whitespace(false))
437 return false;
438 if (*this->p_ != '[')
440 this->error("expected %<[%>");
441 return false;
443 ++this->p_;
445 val->start_array();
447 if (!this->skip_whitespace(false))
448 return false;
449 if (*this->p_ == ']')
451 ++this->p_;
452 return true;
455 while (true)
457 // If we were parsing full JSON we would call read_value here,
458 // not read_string.
460 std::string s;
461 if (!this->read_string(&s))
462 return false;
464 val->add_array_entry(s);
466 if (!this->skip_whitespace(false))
467 return false;
468 if (*this->p_ == ']')
470 ++this->p_;
471 return true;
473 if (*this->p_ != ',')
475 this->error("expected %<,%> or %<]%>");
476 return false;
478 ++this->p_;
482 // Read a JSON value into VAL. Return whether it succeeded.
484 bool
485 Embedcfg_reader::read_value(Json_value* val)
487 if (!this->skip_whitespace(false))
488 return false;
489 switch (*this->p_)
491 case '"':
493 std::string s;
494 if (!this->read_string(&s))
495 return false;
496 val->set_string(s);
497 return true;
500 case '{':
501 return this->read_object(val);
503 case '[':
504 return this->read_array(val);
506 default:
507 this->error("invalid JSON syntax");
508 return false;
512 // Read a JSON string. Return whether it succeeded.
514 bool
515 Embedcfg_reader::read_string(std::string* str)
517 if (!this->skip_whitespace(false))
518 return false;
519 if (*this->p_ != '"')
521 this->error("expected %<\"%>");
522 return false;
524 ++this->p_;
526 str->clear();
527 while (this->p_ < this->pend_ && *this->p_ != '"')
529 if (*this->p_ != '\\')
531 str->push_back(*this->p_);
532 ++this->p_;
533 continue;
536 ++this->p_;
537 if (this->p_ >= this->pend_)
539 this->error("unterminated string");
540 return false;
542 switch (*this->p_)
544 case '"': case '\\': case '/':
545 str->push_back(*this->p_);
546 ++this->p_;
547 break;
549 case 'b':
550 str->push_back('\b');
551 ++this->p_;
552 break;
554 case 'f':
555 str->push_back('\f');
556 ++this->p_;
557 break;
559 case 'n':
560 str->push_back('\n');
561 ++this->p_;
562 break;
564 case 'r':
565 str->push_back('\r');
566 ++this->p_;
567 break;
569 case 't':
570 str->push_back('\t');
571 ++this->p_;
572 break;
574 case 'u':
576 ++this->p_;
577 unsigned int rune = 0;
578 for (int i = 0; i < 4; i++)
580 if (this->p_ >= this->pend_)
582 this->error("unterminated string");
583 return false;
585 unsigned char c = *this->p_;
586 ++this->p_;
587 rune <<= 4;
588 if (c >= '0' && c <= '9')
589 rune += c - '0';
590 else if (c >= 'A' && c <= 'F')
591 rune += c - 'A' + 10;
592 else if (c >= 'a' && c <= 'f')
593 rune += c - 'a' + 10;
594 else
596 this->error("invalid hex digit");
597 return false;
600 Lex::append_char(rune, false, str, Linemap::unknown_location());
602 break;
604 default:
605 this->error("unrecognized string escape");
606 return false;
610 if (*this->p_ == '"')
612 ++this->p_;
613 return true;
616 this->error("unterminated string");
617 return false;
620 // Report an error if not at EOF.
622 void
623 Embedcfg_reader::check_eof()
625 if (this->skip_whitespace(true))
626 this->error("extraneous data at end of file");
629 // Skip whitespace. Return whether there is more to read.
631 bool
632 Embedcfg_reader::skip_whitespace(bool eof_ok)
634 while (this->p_ < this->pend_)
636 switch (*this->p_)
638 case ' ': case '\t': case '\n': case '\r':
639 ++this->p_;
640 break;
641 default:
642 return true;
645 if (!eof_ok)
646 this->error("unexpected EOF");
647 return false;
650 // Report an error.
652 void
653 Embedcfg_reader::error(const char* msg)
655 if (!this->data_.empty() && this->p_ != NULL)
656 go_error_at(Linemap::unknown_location(),
657 "%<-fgo-embedcfg%>: %s: %lu: %s",
658 this->filename_,
659 static_cast<unsigned long>(this->p_ - this->data_.data()),
660 msg);
661 else
662 go_error_at(Linemap::unknown_location(),
663 "%<-fgo-embedcfg%>: %s: %s",
664 this->filename_, msg);
667 // Implement the sort order for a list of embedded files, as discussed
668 // at the docs for embed.FS.
670 class Embedfs_sort
672 public:
673 bool
674 operator()(const std::string& p1, const std::string& p2) const;
676 private:
677 void
678 split(const std::string&, size_t*, size_t*, size_t*) const;
681 bool
682 Embedfs_sort::operator()(const std::string& p1, const std::string& p2) const
684 size_t dirlen1, elem1, elemlen1;
685 this->split(p1, &dirlen1, &elem1, &elemlen1);
686 size_t dirlen2, elem2, elemlen2;
687 this->split(p2, &dirlen2, &elem2, &elemlen2);
689 if (dirlen1 == 0)
691 if (dirlen2 > 0)
693 int i = p2.compare(0, dirlen2, ".");
694 if (i != 0)
695 return i > 0;
698 else if (dirlen2 == 0)
700 int i = p1.compare(0, dirlen1, ".");
701 if (i != 0)
702 return i < 0;
704 else
706 int i = p1.compare(0, dirlen1, p2, 0, dirlen2);
707 if (i != 0)
708 return i < 0;
711 int i = p1.compare(elem1, elemlen1, p2, elem2, elemlen2);
712 return i < 0;
715 // Pick out the directory and file name components for comparison.
717 void
718 Embedfs_sort::split(const std::string& s, size_t* dirlen, size_t* elem,
719 size_t* elemlen) const
721 size_t len = s.size();
722 if (len > 0 && s[len - 1] == '/')
723 --len;
724 size_t slash = s.rfind('/', len - 1);
725 if (slash == std::string::npos)
727 *dirlen = 0;
728 *elem = 0;
729 *elemlen = len;
731 else
733 *dirlen = slash;
734 *elem = slash + 1;
735 *elemlen = len - (slash + 1);
739 // Convert the go:embed directives for a variable into an initializer
740 // for that variable.
742 Expression*
743 Gogo::initializer_for_embeds(Type* type,
744 const std::vector<std::string>* embeds,
745 Location loc)
747 if (this->embed_patterns_.empty())
749 go_error_at(loc,
750 ("invalid go:embed: build system did not "
751 "supply embed configuration"));
752 return Expression::make_error(loc);
755 type = type->unalias();
757 enum {
758 EMBED_STRING = 0,
759 EMBED_BYTES = 1,
760 EMBED_FS = 2
761 } embed_kind;
763 const Named_type* nt = type->named_type();
764 if (nt != NULL
765 && nt->named_object()->package() != NULL
766 && nt->named_object()->package()->pkgpath() == "embed"
767 && nt->name() == "FS")
768 embed_kind = EMBED_FS;
769 else if (type->is_string_type())
770 embed_kind = EMBED_STRING;
771 else if (type->is_slice_type()
772 && type->array_type()->element_type()->integer_type() != NULL
773 && type->array_type()->element_type()->integer_type()->is_byte())
774 embed_kind = EMBED_BYTES;
775 else
777 go_error_at(loc, "invalid type for go:embed");
778 return Expression::make_error(loc);
781 // The patterns in the go:embed directive(s) are in EMBEDS. Find
782 // them in the patterns in the embedcfg file.
784 Unordered_set(std::string) have;
785 std::vector<std::string> paths;
786 for (std::vector<std::string>::const_iterator pe = embeds->begin();
787 pe != embeds->end();
788 pe++)
790 Embed_patterns::const_iterator pp = this->embed_patterns_.find(*pe);
791 if (pp == this->embed_patterns_.end())
793 go_error_at(loc,
794 ("invalid go:embed: build system did not "
795 "map pattern %<%s%>"),
796 pe->c_str());
797 continue;
800 // Each pattern in the embedcfg file maps to a list of file
801 // names. Add those file names to PATHS.
802 for (std::vector<std::string>::const_iterator pf = pp->second.begin();
803 pf != pp->second.end();
804 pf++)
806 if (this->embed_files_.find(*pf) == this->embed_files_.end())
808 go_error_at(loc,
809 ("invalid go:embed: build system did not "
810 "map file %<%s%>"),
811 pf->c_str());
812 continue;
815 std::pair<Unordered_set(std::string)::iterator, bool> ins
816 = have.insert(*pf);
817 if (ins.second)
819 const std::string& path(*pf);
820 paths.push_back(path);
822 if (embed_kind == EMBED_FS)
824 // Add each required directory, with a trailing slash.
825 size_t i = std::string::npos;
826 while (i > 0)
828 i = path.rfind('/', i);
829 if (i == std::string::npos)
830 break;
831 std::string dir = path.substr(0, i + 1);
832 ins = have.insert(dir);
833 if (ins.second)
834 paths.push_back(dir);
835 --i;
842 if (embed_kind == EMBED_STRING || embed_kind == EMBED_BYTES)
844 if (paths.size() > 1)
846 go_error_at(loc,
847 ("invalid go:embed: multiple files for "
848 "string or byte slice"));;
849 return Expression::make_error(loc);
852 std::string data;
853 if (!Gogo::read_file(this->embed_files_[paths[0]].c_str(), loc, &data))
854 return Expression::make_error(loc);
856 Expression* e = Expression::make_string(data, loc);
857 if (embed_kind == EMBED_BYTES)
858 e = Expression::make_cast(type, e, loc);
859 return e;
862 std::sort(paths.begin(), paths.end(), Embedfs_sort());
864 if (type->struct_type() == NULL
865 || type->struct_type()->field_count() != 1)
867 go_error_at(loc,
868 ("internal error: embed.FS should be struct type "
869 "with one field"));
870 return Expression::make_error(loc);
873 Type* ptr_type = type->struct_type()->field(0)->type();
874 if (ptr_type->points_to() == NULL)
876 go_error_at(loc,
877 "internal error: embed.FS struct field should be pointer");
878 return Expression::make_error(loc);
881 Type* slice_type = ptr_type->points_to();
882 if (!slice_type->is_slice_type())
884 go_error_at(loc,
885 ("internal error: embed.FS struct field should be "
886 "pointer to slice"));
887 return Expression::make_error(loc);
890 Type* file_type = slice_type->array_type()->element_type();
891 if (file_type->struct_type() == NULL
892 || (file_type->struct_type()->find_local_field(".embed.name", NULL)
893 == NULL)
894 || (file_type->struct_type()->find_local_field(".embed.data", NULL)
895 == NULL))
897 go_error_at(loc,
898 ("internal error: embed.FS slice element should be struct "
899 "with name and data fields"));
900 return Expression::make_error(loc);
903 const Struct_field_list* file_fields = file_type->struct_type()->fields();
904 Expression_list* file_vals = new(Expression_list);
905 file_vals->reserve(paths.size());
906 for (std::vector<std::string>::const_iterator pp = paths.begin();
907 pp != paths.end();
908 ++pp)
910 std::string data;
911 if ((*pp)[pp->size() - 1] != '/')
913 if (!Gogo::read_file(this->embed_files_[*pp].c_str(), loc, &data))
914 return Expression::make_error(loc);
917 Expression_list* field_vals = new(Expression_list);
918 for (Struct_field_list::const_iterator pf = file_fields->begin();
919 pf != file_fields->end();
920 ++pf)
922 if (pf->is_field_name(".embed.name"))
923 field_vals->push_back(Expression::make_string(*pp, loc));
924 else if (pf->is_field_name(".embed.data"))
925 field_vals->push_back(Expression::make_string(data, loc));
926 else
928 // FIXME: The embed.file type has a hash field, which is
929 // currently unused. We should fill it in, but don't.
930 // The hash is a SHA256, and we don't have convenient
931 // SHA256 code. Do this later when the field is
932 // actually used.
933 field_vals->push_back(NULL);
937 Expression* file_val =
938 Expression::make_struct_composite_literal(file_type, field_vals, loc);
939 file_vals->push_back(file_val);
942 Expression* slice_init =
943 Expression::make_slice_composite_literal(slice_type, file_vals, loc);
944 Expression* fs_init = Expression::make_heap_expression(slice_init, loc);
945 Expression_list* fs_vals = new Expression_list();
946 fs_vals->push_back(fs_init);
947 return Expression::make_struct_composite_literal(type, fs_vals, loc);