diff --git a/janet/myparser.janet b/janet/myparser.janet index d444de3..351dcd7 100644 --- a/janet/myparser.janet +++ b/janet/myparser.janet @@ -109,6 +109,9 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com "Renames a rule. By convention, rule names are keywords." [rule name] (put rule :name name)) +### As noted above: we should not use this +### Instead, combinators which might not advance should stash state +### These are: !, *, ...? (defn test "Tests a rule: returns whether a rule passes but does not consume any tokens." [rule parser] @@ -122,7 +125,9 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com [rule] @{:name (keyword (string "!" (name rule))) :rule (fn !* [parser] - (def result (test rule parser)) + (def origin (stash parser)) + (def result (apply-rule rule parser)) + (restore parser origin) (if-not result (do (advance parser) true) nil))}) @@ -164,10 +169,7 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com ~(set ,name (put ,name :rule (,rule :rule))) ~(var ,name (rename ,rule ,(keyword name))))) -# If we wanted to be robust, we wouldn't hard-code this -(defp stop (+ :newline :semicolon :break)) - -(defn panic +(comment (defn panic [rule &opt msg] @{:name (keyword (string "panic-" (name rule))) :rule (fn panic* [parser] @@ -184,7 +186,11 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com (array/push (parser :errors) the-error) (array/push (parser :captured) the-error) true - )}) + )})) + +# If we wanted to be robust, we wouldn't hard-code this +# To consider: use a stack of "panic-until" on a parser to dynamically decide how far to panic +(defp stop (+ :newline :semicolon :break)) (defn panic "Panics the parser, consuming all tokens until the rule matches (including the match). It also adds an error node to both the capture and the error stacks." @@ -196,7 +202,7 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com (while (not passing) (array/push skipped (current parser)) (advance parser) - (set passing (apply-rule rule parser)) ### compile error: unknown symbol rule + (set passing (apply-rule stop parser)) (print "phew; I'm done panicking") (pprint (current parser)) (def the-error {:type :error :expected expected :token origin :skipped skipped}) @@ -213,7 +219,8 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com (var passing true) (def origin (stash parser)) (pprint origin) - (set failing nil) ### compile error: unknonw symbol failing + (def failing nil) + (def passing true) (loop [rule :in rules :while passing] (def pass? (apply-rule rule parser)) (when (not pass?) @@ -242,13 +249,13 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com ## is this right? -(defn order-1 [& rules] +(comment (defn order-1 [& rules] @{:name (keyword (string/join (map name rules) "*")) :rule (fn order-1 [parser] (def result (test (first rules) parser)) (if result (apply-rule (order-0 ;rules)) ### compile error: unknown symbol order-0 - nil))}) + nil))})) (defn capture-group "Takes a parser and an origin state: takes everything captured since the origin, gathers it up in a single array, pops it all off the capture stack, and pushes the gathered captures back on the stack." @@ -330,7 +337,7 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com (do (apply-rule rule parser) parser) ([err] err))) -(upscope #XXX for repl use +(upscope #XXX for easier repl use (defn literal->ast [token] {:type (get token :type) :data (get token :literal) :token token}) @@ -342,7 +349,7 @@ The idea, however, is that Jesus: we must not have test-rule and apply-rule: com (declare expression simple nonbinding) -(defp separator (+ :newline :comma :break)) +(defp separator (some (+ :newline :comma :break))) (defp separators? (any (+ :newline :comma :break))) (defp terminator (some (+ :newline :semicolon :break))) (defp terminators? (any (+ :newline :semicolon :break)))