https://github.com/akkartik/mu1/blob/master/016dilated_reagent.cc
1
2
3
4
5 :(scenarios load)
6 :(scenario dilated_reagent)
7 def main [
8 {1: number, foo: bar} <- copy 34
9 ]
10 +parse: product: {1: "number", "foo": "bar"}
11
12 :(scenario load_trailing_space_after_curly_bracket)
13 def main [
14
15 {
16 ]
17
18
19 :(scenario dilated_reagent_with_comment)
20 def main [
21 {1: number, foo: bar} <- copy 34
22 ]
23 +parse: product: {1: "number", "foo": "bar"}
24 $error: 0
25
26 :(scenario dilated_reagent_with_comment_immediately_following)
27 def main [
28 1:number <- copy {34: literal}
29 ]
30 $error: 0
31
32
33
34 :(before "End next_word Special-cases")
35 if (in.peek() == '(')
36 return slurp_balanced_bracket(in);
37
38 if (start_of_dilated_reagent(in))
39 return slurp_balanced_bracket(in);
40
41 :(code)
42
43
44 bool start_of_dilated_reagent(istream& in) {
45 if (in.peek() != '{') return false;
46 int pos = in.tellg();
47 in.get();
48 skip_whitespace_but_not_newline(in);
49 char next = in.peek();
50 in.seekg(pos);
51 return next != '\n';
52 }
53
54
55
56
57 string slurp_balanced_bracket(istream& in) {
58 ostringstream result;
59 char c;
60 list<char> open_brackets;
61 while (in >> c) {
62 if (c == '(') open_brackets.push_back(c);
63 if (c == ')') {
64 if (open_brackets.empty() || open_brackets.back() != '(') {
65 raise << "unbalanced ')'\n" << end();
66 continue;
67 }
68 assert(open_brackets.back() == '(');
69 open_brackets.pop_back();
70 }
71 if (c == '[') open_brackets.push_back(c);
72 if (c == ']') {
73 if (open_brackets.empty() || open_brackets.back() != '[') {
74 raise << "unbalanced ']'\n" << end();
75 continue;
76 }
77 open_brackets.pop_back();
78 }
79 if (c == '{') open_brackets.push_back(c);
80 if (c == '}') {
81 if (open_brackets.empty() || open_brackets.back() != '{') {
82 raise << "unbalanced '}'\n" << end();
83 continue;
84 }
85 open_brackets.pop_back();
86 }
87 result << c;
88 if (open_brackets.empty()) break;
89 }
90 skip_whitespace_and_comments_but_not_newline(in);
91 return result.str();
92 }
93
94 :(after "Parsing reagent(string s)")
95 if (starts_with(s, "{")) {
96 assert(properties.empty());
97 istringstream in(s);
98 in >> std::noskipws;
99 in.get();
100 name = slurp_key(in);
101 if (name.empty()) {
102 raise << "invalid reagent '" << s << "' without a name\n" << end();
103 return;
104 }
105 if (name == "}") {
106 raise << "invalid empty reagent '" << s << "'\n" << end();
107 return;
108 }
109 {
110 string s = next_word(in);
111 if (s.empty()) {
112 assert(!has_data(in));
113 raise << "incomplete dilated reagent at end of file (0)\n" << end();
114 return;
115 }
116 string_tree* type_names = new string_tree(s);
117
118 type = new_type_tree(type_names);
119 delete type_names;
120 }
121 while (has_data(in)) {
122 string key = slurp_key(in);
123 if (key.empty()) continue;
124 if (key == "}") continue;
125 string s = next_word(in);
126 if (s.empty()) {
127 assert(!has_data(in));
128 raise << "incomplete dilated reagent at end of file (1)\n" << end();
129 return;
130 }
131 string_tree* value = new string_tree(s);
132
133 properties.push_back(pair<string, string_tree*>(key, value));
134 }
135 return;
136 }
137
138 :(code)
139 string slurp_key(istream& in) {
140 string result = next_word(in);
141 if (result.empty()) {
142 assert(!has_data(in));
143 raise << "incomplete dilated reagent at end of file (2)\n" << end();
144 return result;
145 }
146 while (!result.empty() && *result.rbegin() == ':')
147 strip_last(result);
148 while (isspace(in.peek()) || in.peek() == ':')
149 in.get();
150 return result;
151 }