diff --git a/janet/recursive.janet b/janet/recursive.janet index 4a40d66..199246c 100644 --- a/janet/recursive.janet +++ b/janet/recursive.janet @@ -116,8 +116,8 @@ (defn- expect-ret "Same as expect, but captures the error, returning it as a value" - [parser type] - (try (expect parser type) ([e] e))) + [parser type & types] + (try (expect parser type ;types) ([e] e))) (defn- capture "Applies the parse function to the parser, returning the parsed AST. If there is a panic, captures the panic and returns it as a value." @@ -126,13 +126,13 @@ (defn- accept-one "Accepts a single token of passed type, advancing the parser if a match, doing nothing if not." - [parser type] - (if (check parser type) (advance parser))) + [parser type & types] + (if (check parser type ;types) (advance parser))) (defn- accept-many "Accepts any number of tokens of a passed type, advancing the parser on match until there are no more matches. Does nothing on no match." - [parser type] - (while (check parser type) (advance parser))) + [parser type & types] + (while (check parser type ;types) (advance parser))) # atoms (defn- bool [parser] @@ -310,6 +310,8 @@ (advance parser) ast) +### patterns + ### conditional forms # if {simple} then {nonbinding} else {nonbinding} (defn- iff [parser] @@ -328,42 +330,39 @@ (array/push (ast :data) (capture nonbinding parser)) ast) -### XXX: We've got an off-by-one error here -# We're expecting a terminator, we panic until we get to a terminator, and we then return back to something that expects a terminator, and now we've started parsing again *at the terminator* (defn- terminator [parser] (if-not (terminates? parser) - # this line panics, captures the panic, advances the parser, and re-throws the error - (try (panic parser "expected terminator") ([e] (advance parser) (error e)))) + # this line panics, captures the panic, advances the parser, and re-throws the error; solves an off-by-one error + (panic parser "expected terminator")) (advance parser) (while (terminates? parser) (advance parser))) # {simple} -> {nonbinding} {terminator} (defn- when-clause [parser] - (def clause @[]) - (print "parsing lhs: " (-> parser current type)) - (array/push clause (capture simple parser)) - (print "parsing arrow") - (if-let [err (expect-ret parser :arrow)] - (array/push clause err) - (advance parser)) - (print "accepting newlines") - (accept-many parser :newline) - (print "parsing rhs") - (array/push clause (nonbinding parser)) - (print "parsing terminator") - (try (terminator parser) ([e] (array/push clause e))) - clause) + (try + (do + (def lhs (simple parser)) + (expect parser :arrow) + (advance parser) + (accept-many parser :newline) + (def rhs (nonbinding parser)) + (terminator parser) + [lhs rhs]) + ([err] + (advance parser) # consume the breaking token + (accept-many parser :newline :semicolon :break) # ...and any additional ones + err))) (defn- whenn [parser] (def ast {:type :when :data @[] :origin (current parser)}) - (advance parser) # consume cond + (advance parser) # consume when (if-let [err (expect-ret parser :lbrace)] (do (array/push (ast :data) err) - (break ast)) + (break ast)) # early return; just bail if we don't have { (advance parser)) (accept-many parser :newline) - (while (not (check parser :rbrace :eof)) + (while (not (check parser :rbrace :eof)) # make sure we don't roll past eof (array/push (ast :data) (capture when-clause parser))) (advance parser) ast) @@ -515,8 +514,10 @@ (do #(comment (def source `when { + a -> b foo -> bar quux - bar -> baz + -> baz + c -> d } `) (def scanned (s/scan source))