finally get when clauses & forms right

This commit is contained in:
Scott Richmond 2024-05-08 17:14:51 -04:00
parent 942f55fb39
commit 4f16cf5cb0

View File

@ -116,8 +116,8 @@
(defn- expect-ret (defn- expect-ret
"Same as expect, but captures the error, returning it as a value" "Same as expect, but captures the error, returning it as a value"
[parser type] [parser type & types]
(try (expect parser type) ([e] e))) (try (expect parser type ;types) ([e] e)))
(defn- capture (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." "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 (defn- accept-one
"Accepts a single token of passed type, advancing the parser if a match, doing nothing if not." "Accepts a single token of passed type, advancing the parser if a match, doing nothing if not."
[parser type] [parser type & types]
(if (check parser type) (advance parser))) (if (check parser type ;types) (advance parser)))
(defn- accept-many (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." "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] [parser type & types]
(while (check parser type) (advance parser))) (while (check parser type ;types) (advance parser)))
# atoms # atoms
(defn- bool [parser] (defn- bool [parser]
@ -310,6 +310,8 @@
(advance parser) (advance parser)
ast) ast)
### patterns
### conditional forms ### conditional forms
# if {simple} then {nonbinding} else {nonbinding} # if {simple} then {nonbinding} else {nonbinding}
(defn- iff [parser] (defn- iff [parser]
@ -328,42 +330,39 @@
(array/push (ast :data) (capture nonbinding parser)) (array/push (ast :data) (capture nonbinding parser))
ast) 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] (defn- terminator [parser]
(if-not (terminates? parser) (if-not (terminates? parser)
# this line panics, captures the panic, advances the parser, and re-throws the error # this line panics, captures the panic, advances the parser, and re-throws the error; solves an off-by-one error
(try (panic parser "expected terminator") ([e] (advance parser) (error e)))) (panic parser "expected terminator"))
(advance parser) (advance parser)
(while (terminates? parser) (advance parser))) (while (terminates? parser) (advance parser)))
# {simple} -> {nonbinding} {terminator} # {simple} -> {nonbinding} {terminator}
(defn- when-clause [parser] (defn- when-clause [parser]
(def clause @[]) (try
(print "parsing lhs: " (-> parser current type)) (do
(array/push clause (capture simple parser)) (def lhs (simple parser))
(print "parsing arrow") (expect parser :arrow)
(if-let [err (expect-ret parser :arrow)] (advance parser)
(array/push clause err) (accept-many parser :newline)
(advance parser)) (def rhs (nonbinding parser))
(print "accepting newlines") (terminator parser)
(accept-many parser :newline) [lhs rhs])
(print "parsing rhs") ([err]
(array/push clause (nonbinding parser)) (advance parser) # consume the breaking token
(print "parsing terminator") (accept-many parser :newline :semicolon :break) # ...and any additional ones
(try (terminator parser) ([e] (array/push clause e))) err)))
clause)
(defn- whenn [parser] (defn- whenn [parser]
(def ast {:type :when :data @[] :origin (current parser)}) (def ast {:type :when :data @[] :origin (current parser)})
(advance parser) # consume cond (advance parser) # consume when
(if-let [err (expect-ret parser :lbrace)] (if-let [err (expect-ret parser :lbrace)]
(do (do
(array/push (ast :data) err) (array/push (ast :data) err)
(break ast)) (break ast)) # early return; just bail if we don't have {
(advance parser)) (advance parser))
(accept-many parser :newline) (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))) (array/push (ast :data) (capture when-clause parser)))
(advance parser) (advance parser)
ast) ast)
@ -515,8 +514,10 @@
(do (do
#(comment #(comment
(def source `when { (def source `when {
a -> b
foo -> bar quux foo -> bar quux
bar -> baz -> baz
c -> d
} }
`) `)
(def scanned (s/scan source)) (def scanned (s/scan source))