Kronos improvements: empty docstring no longer swallows following line, improved error messages in parsing stage
5 files changed, 20 insertions(+), 16 deletions(-)

M ast.cpp
M grammar/kronos.cpp
M grammar/kronos_tags.inc
M lithe.cpp
M lithe.h
M ast.cpp +2 -2
@@ 47,8 47,8 @@ namespace lithe {
 
 			if (indent == 0) s << "Parse error: "; 
 			else {
-				if (children.size() > 1) s << "in ";
-				else s << "did not find ";
+				if (children.size() > 1) s << "- ";
+				else s << "Expected ";
 			}
 			auto er = (error_report*)strend;
 			if (er) { er->write(s); s << "\n"; }

          
M grammar/kronos.cpp +10 -6
@@ 225,7 225,9 @@ namespace lithe {
 			lithe::rule package_version() {
 				using namespace grammar::common;
 				auto space = I(grammar::common::whitespace());
-				auto remote_version = identifier() | (digits(1) << O(T(".") << digits(1) << O(T(".") << digits(1))));
+				auto remote_version = identifier() | L(
+					"Version tag",
+					(digits(1) << O(T(".") << digits(1) << O(T(".") << digits(1)))));
 				return E(tag::package, I("[") << O(space) << identifier() << space << remote_version << O(space << identifier()) << O(space) << I("]"));
 			}
 

          
@@ 239,7 241,9 @@ namespace lithe {
 
 				auto check_brace = bad("Unmatched parens/bracket/brace", characters("braces", ")]}"));
 
-				auto docstring = custom("docstring", I(T(";") << O(whitespace)) << upto_eol, [](const lithe::node& n) {
+				auto docstring = custom(
+					"docstring", I(T(";") << O(characters("space","\t "))) << (upto_eol | T("\n")), 
+				[](const lithe::node& n) {
 					if (docstrings().size()) {
 						docstrings().top().children.emplace_back(n);
 					}

          
@@ 253,11 257,11 @@ namespace lithe {
 				lithe::rule comment, space;
 
 				if (keep_comments) {
-					comment = E(tag::comment, T(";") << (docstring | upto_eol));
-					space = repeat(I(whitespace) | comment | I(","), 1);
+					comment = E(tag::comment, T(";") << (docstring | upto_eol | T("\n")));
+					space = L("whitespace", repeat(I(whitespace) | comment | I(","), 1));
 				} else {
-					comment = IE(tag::comment, T(";") << (docstring | upto_eol));
-					space = I(repeat(whitespace | comment | T(","), 1));
+					comment = IE(tag::comment, T(";") << (docstring | upto_eol | T("\n")));
+					space = L("whitespace", I(repeat(whitespace | comment | T(","), 1)));
 				}
 
 				auto opt_sp = O(space);

          
M grammar/kronos_tags.inc +1 -1
@@ 30,4 30,4 @@ namespace tag {
 	TAG(immediate, "immediate")
 	TAG(free_var, "free variable")
 	TAG(docstring, "documentation")
-};
+ };

          
M lithe.cpp +6 -7
@@ 513,8 513,9 @@ namespace lithe {
 			}
 
 			void write(std::ostream& os)  const override {
-				os << "optional ";
+				os << "(optional ";
 				wrapper::write(os);
+				os << ")";
 			}
 		};
 

          
@@ 591,12 592,6 @@ namespace lithe {
 				if (tmp.is_error()) return tmp;
 				return {};
 			}
-
-			void write(std::ostream& s) const override {
-				s << "(";
-				wrapper::write(s);
-				s << ")";
-			}
 		};
 
 		struct indirect : public recursive {

          
@@ 749,6 744,10 @@ namespace lithe {
 		return r->ignore(r);
 	}
 
+	rule L(const char* label, rule r) {
+		return make_shared<rules::wrapper>(r, label);
+	}
+
 	rule O(rule r) {
 		return make_shared<rules::optional>(r);
 	}

          
M lithe.h +1 -0
@@ 59,6 59,7 @@ namespace lithe {
 	rule IE(const char *tag, rule content);
 	rule T(const char *literal_text);
 	rule I(rule ignore);
+	rule L(const char* label, rule content);
 	static inline rule I(const char *ignore) { return I(T(ignore)); }
 	rule O(rule r);
 	rule repeat(rule element, int minimum = 1);