about summary refs log tree commit diff stats
path: root/013literal_string.cc
diff options
context:
space:
mode:
Diffstat (limited to '013literal_string.cc')
-rw-r--r--013literal_string.cc73
1 files changed, 68 insertions, 5 deletions
diff --git a/013literal_string.cc b/013literal_string.cc
index 92db8f87..f1416384 100644
--- a/013literal_string.cc
+++ b/013literal_string.cc
@@ -26,15 +26,44 @@ Type_number["literal-string"] = 0;
     string result = slurp_quoted(in);
     skip_whitespace(in);
     skip_comment(in);
+//?     cerr << '^' << result << "$\n"; //? 1
     return result;
   }
 
 :(code)
 string slurp_quoted(istream& in) {
-  assert(!in.eof());
-  assert(in.peek() == '[');
   ostringstream out;
-  int brace_depth = 0;
+  assert(!in.eof());  assert(in.peek() == '[');  out << static_cast<char>(in.get());  // slurp the '['
+  if (code_string(in, out))
+    slurp_quoted_comment_aware(in, out);
+  else
+    slurp_quoted_comment_oblivious(in, out);
+  return out.str();
+}
+
+// A string is a code string if it contains a newline before any non-whitespace
+// todo: support comments before the newline. But that gets messy.
+bool code_string(istream& in, ostringstream& out) {
+  while (!in.eof()) {
+    char c = in.get();
+    if (!isspace(c)) {
+      in.putback(c);
+//?       cerr << "code_string: " << out.str() << '\n'; //? 1
+      return false;
+    }
+    out << c;
+    if (c == '\n') {
+//?       cerr << "code_string: " << out.str() << '\n'; //? 1
+      return true;
+    }
+  }
+  return false;
+}
+
+// Read a regular string. Regular strings can only contain other regular
+// strings.
+void slurp_quoted_comment_oblivious(istream& in, ostream& out) {
+  int brace_depth = 1;
   while (!in.eof()) {
     char c = in.get();
 //?     cout << (int)c << ": " << brace_depth << '\n'; //? 2
@@ -50,9 +79,28 @@ string slurp_quoted(istream& in) {
   }
   if (in.eof() && brace_depth > 0) {
     raise << "unbalanced '['\n";
-    return "";
+    out.clear();
+  }
+}
+
+// Read a code string. Code strings can contain either code or regular strings.
+void slurp_quoted_comment_aware(istream& in, ostream& out) {
+  char c;
+  while (in >> c) {
+    if (c == '#') {
+      out << c;
+      while (!in.eof() && in.peek() != '\n') out << static_cast<char>(in.get());
+      continue;
+    }
+    if (c == '[') {
+      in.putback(c);
+      // recurse
+      out << slurp_quoted(in);
+      continue;
+    }
+    out << c;
+    if (c == ']') break;
   }
-  return out.str();
 }
 
 :(after "reagent::reagent(string s)")
@@ -122,3 +170,18 @@ recipe main [
 def]
 ]
 +parse:   ingredient: {name: "abc\ndef", properties: [_: "literal-string"]}
+
+:(scenario string_literal_can_skip_past_comments)
+recipe main [
+  copy [
+    # ']' inside comment
+    bar
+  ]
+]
++parse:   ingredient: {name: "\n    # ']' inside comment\n    bar\n  ", properties: [_: "literal-string"]}
+
+:(scenario string_literal_empty)
+recipe main [
+  copy []
+]
++parse:   ingredient: {name: "", properties: [_: "literal-string"]}