From 2badd89a58b9666563746d71069abf16f05709ea Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 14 Mar 2016 01:00:48 -0700 Subject: 2778 - fix all layers --- 053dilated_reagent.cc | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 053dilated_reagent.cc (limited to '053dilated_reagent.cc') diff --git a/053dilated_reagent.cc b/053dilated_reagent.cc new file mode 100644 index 00000000..8e141a43 --- /dev/null +++ b/053dilated_reagent.cc @@ -0,0 +1,132 @@ +//: An alternative syntax for reagents that permits whitespace in properties, +//: grouped by brackets. We'll use this ability in the next layer, when we +//: generalize types from lists to trees of properties. + +:(scenarios load) +:(scenario dilated_reagent) +def main [ + {1: number, foo: bar} <- copy 34 +] ++parse: product: 1: "number", {"foo": "bar"} + +:(scenario load_trailing_space_after_curly_bracket) +def main [ + # line below has a space at the end + { +] +# successfully parsed + +:(scenarios run) +:(scenario dilated_reagent_with_comment) +def main [ + {1: number, foo: bar} <- copy 34 # test comment +] ++parse: product: 1: "number", {"foo": "bar"} +$error: 0 + +:(scenario dilated_reagent_with_comment_immediately_following) +def main [ + 1:number <- copy {34: literal} # test comment +] +$error: 0 + +//: First augment next_word to group balanced brackets together. + +:(before "End next_word Special-cases") +if (in.peek() == '(') + return slurp_balanced_bracket(in); +// treat curlies mostly like parens, but don't mess up labels +if (start_of_dilated_reagent(in)) + return slurp_balanced_bracket(in); + +:(code) +// A curly is considered a label if it's the last thing on a line. Dilated +// reagents should remain all on one line. +bool start_of_dilated_reagent(istream& in) { + if (in.peek() != '{') return false; + int pos = in.tellg(); + in.get(); // slurp '{' + skip_whitespace_but_not_newline(in); + char next = in.peek(); + in.seekg(pos); + return next != '\n'; +} + +// Assume the first letter is an open bracket, and read everything until the +// matching close bracket. +// We balance {} () and []. And we skip one character after '\'. +string slurp_balanced_bracket(istream& in) { + ostringstream result; + char c; + list open_brackets; + while (in >> c) { + if (c == '\\') { + // always silently skip the next character + result << c; + if (!(in >> c)) break; + result << c; + continue; + } + if (c == '(') open_brackets.push_back(c); + if (c == ')') { + assert(open_brackets.back() == '('); + open_brackets.pop_back(); + } + if (c == '[') open_brackets.push_back(c); + if (c == ']') { + assert(open_brackets.back() == '['); + open_brackets.pop_back(); + } + if (c == '{') open_brackets.push_back(c); + if (c == '}') { + assert(open_brackets.back() == '{'); + open_brackets.pop_back(); + } + result << c; + if (open_brackets.empty()) break; + } + skip_whitespace_and_comments_but_not_newline(in); + return result.str(); +} + +:(after "Parsing reagent(string s)") +if (s.at(0) == '{') { + assert(properties.empty()); + istringstream in(s); + in >> std::noskipws; + in.get(); // skip '{' + name = slurp_key(in); + if (name.empty()) { + raise << "invalid reagent " << s << " without a name\n" << end(); + return; + } + if (name == "}") { + raise << "invalid empty reagent " << s << '\n' << end(); + return; + } + { + string_tree* value = new string_tree(next_word(in)); + // End Parsing Reagent Type Property(value) + type = new_type_tree(value); + delete value; + } + while (has_data(in)) { + string key = slurp_key(in); + if (key.empty()) continue; + if (key == "}") continue; + string_tree* value = new string_tree(next_word(in)); + // End Parsing Reagent Property(value) + properties.push_back(pair(key, value)); + } + return; +} + +:(code) +string slurp_key(istream& in) { + string result = next_word(in); + while (!result.empty() && *result.rbegin() == ':') + strip_last(result); + while (isspace(in.peek()) || in.peek() == ':') + in.get(); + return result; +} -- cgit 1.4.1-2-gfad0