fix other mandelbrot variants
[mu.git] / archive / 1.vm / 016dilated_reagent.cc
blob1354ba458b2a4dab6be637bbc324f11f9c053694
1 //: An alternative syntax for reagents that permits whitespace in properties,
2 //: grouped by brackets. We'll use this ability in the next layer, when we
3 //: generalize types from lists to trees of properties.
5 void test_dilated_reagent() {
6 load(
7 "def main [\n"
8 " {1: number, foo: bar} <- copy 34\n"
9 "]\n"
11 CHECK_TRACE_CONTENTS(
12 "parse: product: {1: \"number\", \"foo\": \"bar\"}\n"
16 void test_load_trailing_space_after_curly_bracket() {
17 load(
18 "def main [\n"
19 " # line below has a space at the end\n"
20 " { \n"
21 "]\n"
22 "# successfully parsed\n"
26 void test_dilated_reagent_with_comment() {
27 load(
28 "def main [\n"
29 " {1: number, foo: bar} <- copy 34 # test comment\n"
30 "]\n"
32 CHECK_TRACE_CONTENTS(
33 "parse: product: {1: \"number\", \"foo\": \"bar\"}\n"
35 CHECK_TRACE_COUNT("error", 0);
38 void test_dilated_reagent_with_comment_immediately_following() {
39 load(
40 "def main [\n"
41 " 1:number <- copy {34: literal} # test comment\n"
42 "]\n"
44 CHECK_TRACE_COUNT("error", 0);
47 //: First augment next_word to group balanced brackets together.
49 :(before "End next_word Special-cases")
50 if (in.peek() == '(')
51 return slurp_balanced_bracket(in);
52 // treat curlies mostly like parens, but don't mess up labels
53 if (start_of_dilated_reagent(in))
54 return slurp_balanced_bracket(in);
56 :(code)
57 // A curly is considered a label if it's the last thing on a line. Dilated
58 // reagents should remain all on one line.
59 bool start_of_dilated_reagent(istream& in) {
60 if (in.peek() != '{') return false;
61 int pos = in.tellg();
62 in.get(); // slurp '{'
63 skip_whitespace_but_not_newline(in);
64 char next = in.peek();
65 in.seekg(pos);
66 return next != '\n';
69 // Assume the first letter is an open bracket, and read everything until the
70 // matching close bracket.
71 // We balance {} () and [].
72 string slurp_balanced_bracket(istream& in) {
73 ostringstream result;
74 char c;
75 list<char> open_brackets;
76 while (in >> c) {
77 if (c == '(') open_brackets.push_back(c);
78 if (c == ')') {
79 if (open_brackets.empty() || open_brackets.back() != '(') {
80 raise << "unbalanced ')'\n" << end();
81 continue;
83 assert(open_brackets.back() == '(');
84 open_brackets.pop_back();
86 if (c == '[') open_brackets.push_back(c);
87 if (c == ']') {
88 if (open_brackets.empty() || open_brackets.back() != '[') {
89 raise << "unbalanced ']'\n" << end();
90 continue;
92 open_brackets.pop_back();
94 if (c == '{') open_brackets.push_back(c);
95 if (c == '}') {
96 if (open_brackets.empty() || open_brackets.back() != '{') {
97 raise << "unbalanced '}'\n" << end();
98 continue;
100 open_brackets.pop_back();
102 result << c;
103 if (open_brackets.empty()) break;
105 skip_whitespace_and_comments_but_not_newline(in);
106 return result.str();
109 :(after "Parsing reagent(string s)")
110 if (starts_with(s, "{")) {
111 assert(properties.empty());
112 istringstream in(s);
113 in >> std::noskipws;
114 in.get(); // skip '{'
115 name = slurp_key(in);
116 if (name.empty()) {
117 raise << "invalid reagent '" << s << "' without a name\n" << end();
118 return;
120 if (name == "}") {
121 raise << "invalid empty reagent '" << s << "'\n" << end();
122 return;
125 string s = next_word(in);
126 if (s.empty()) {
127 assert(!has_data(in));
128 raise << "incomplete dilated reagent at end of file (0)\n" << end();
129 return;
131 string_tree* type_names = new string_tree(s);
132 // End Parsing Dilated Reagent Type Property(type_names)
133 type = new_type_tree(type_names);
134 delete type_names;
136 while (has_data(in)) {
137 string key = slurp_key(in);
138 if (key.empty()) continue;
139 if (key == "}") continue;
140 string s = next_word(in);
141 if (s.empty()) {
142 assert(!has_data(in));
143 raise << "incomplete dilated reagent at end of file (1)\n" << end();
144 return;
146 string_tree* value = new string_tree(s);
147 // End Parsing Dilated Reagent Property(value)
148 properties.push_back(pair<string, string_tree*>(key, value));
150 return;
153 :(code)
154 string slurp_key(istream& in) {
155 string result = next_word(in);
156 if (result.empty()) {
157 assert(!has_data(in));
158 raise << "incomplete dilated reagent at end of file (2)\n" << end();
159 return result;
161 while (!result.empty() && *result.rbegin() == ':')
162 strip_last(result);
163 while (isspace(in.peek()) || in.peek() == ':')
164 in.get();
165 return result;