Parse multi-clause match expressions
This commit is contained in:
parent
e4e984bacd
commit
069e3b4a7b
|
@ -251,17 +251,17 @@
|
||||||
|
|
||||||
::token/word
|
::token/word
|
||||||
(if (not current_member) (let [parsed (parse-word parser) word (get-in parsed [::ast :word])]
|
(if (not current_member) (let [parsed (parse-word parser) word (get-in parsed [::ast :word])]
|
||||||
(recur parsed members {(keyword word) (::ast parsed)}))
|
(recur parsed members {(keyword word) (::ast parsed)}))
|
||||||
(panic parser "Hashmap entries must be single words or keyword+expression pairs." #{::token/rbrace})
|
(panic parser "Hashmap entries must be single words or keyword+expression pairs." #{::token/rbrace})
|
||||||
)
|
)
|
||||||
|
|
||||||
::token/keyword
|
::token/keyword
|
||||||
(if (not current_member) (let [kw (parse-atom parser) expr (parse-expr kw #{::token/comma ::token/newline ::token/rbrace})]
|
(if (not current_member) (let [kw (parse-atom parser) expr (parse-expr kw #{::token/comma ::token/newline ::token/rbrace})]
|
||||||
(println "found keyword/expr pair:" (:value kw))
|
(println "found keyword/expr pair:" (:value kw))
|
||||||
(pp/pprint (::ast expr))
|
(pp/pprint (::ast expr))
|
||||||
(recur expr members {(:value (::ast kw)) (::ast expr)}))
|
(recur expr members {(:value (::ast kw)) (::ast expr)}))
|
||||||
(panic parser "Hashmap entries must be single words or keyword+expression pairs." #{::token/rbrace})
|
(panic parser "Hashmap entries must be single words or keyword+expression pairs." #{::token/rbrace})
|
||||||
)
|
)
|
||||||
|
|
||||||
(panic parser "Hashmap entries must be single words or keyword+expression pairs" #{::token/rbrace})))))
|
(panic parser "Hashmap entries must be single words or keyword+expression pairs" #{::token/rbrace})))))
|
||||||
|
|
||||||
|
@ -305,25 +305,25 @@
|
||||||
exprs []
|
exprs []
|
||||||
current_expr nil
|
current_expr nil
|
||||||
]
|
]
|
||||||
(case (token-type parser)
|
(case (token-type parser)
|
||||||
::token/eof (let [es (add-member exprs current_expr)]
|
::token/eof (let [es (add-member exprs current_expr)]
|
||||||
(if (empty? es)
|
(if (empty? es)
|
||||||
(panic parser "Scripts must have at least one expression")
|
(panic parser "Scripts must have at least one expression")
|
||||||
(assoc parser ::ast {::ast/type ::ast/script :exprs es})))
|
(assoc parser ::ast {::ast/type ::ast/script :exprs es})))
|
||||||
|
|
||||||
(::token/semicolon ::token/newline)
|
(::token/semicolon ::token/newline)
|
||||||
(recur
|
(recur
|
||||||
(accept-many #{::token/semicolon ::token/newline} parser)
|
(accept-many #{::token/semicolon ::token/newline} parser)
|
||||||
(add-member exprs current_expr)
|
(add-member exprs current_expr)
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
(let [parsed
|
(let [parsed
|
||||||
(if current_expr
|
(if current_expr
|
||||||
(panic parser "Expected end of expression" #{::token/semicolon ::token/newline})
|
(panic parser "Expected end of expression" #{::token/semicolon ::token/newline})
|
||||||
(parse-expr parser)
|
(parse-expr parser)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
(recur parsed exprs (::ast parsed))))))
|
(recur parsed exprs (::ast parsed))))))
|
||||||
|
|
||||||
(defn- parse-synthetic [parser]
|
(defn- parse-synthetic [parser]
|
||||||
(loop [parser parser
|
(loop [parser parser
|
||||||
|
@ -387,8 +387,8 @@
|
||||||
type (::token/type curr)]
|
type (::token/type curr)]
|
||||||
(case type
|
(case type
|
||||||
::token/placeholder (-> parser
|
::token/placeholder (-> parser
|
||||||
(advance)
|
(advance)
|
||||||
(assoc ::ast {::ast/type ::ast/placeholder}))
|
(assoc ::ast {::ast/type ::ast/placeholder}))
|
||||||
|
|
||||||
::token/word (parse-word parser)
|
::token/word (parse-word parser)
|
||||||
|
|
||||||
|
@ -448,100 +448,127 @@
|
||||||
|
|
||||||
(defn- parse-match-clause [parser]
|
(defn- parse-match-clause [parser]
|
||||||
(let [pattern (parse-pattern parser)
|
(let [pattern (parse-pattern parser)
|
||||||
rarrow (expect* #{::token/rarrow} "Expected arrow in match clause" pattern)
|
rarrow (expect* #{::token/rarrow} "Expected arrow after pattern" pattern)
|
||||||
]
|
]
|
||||||
(if (:success rarrow)
|
(if (:success rarrow)
|
||||||
(let [body (parse-expr (:parser rarrow))]
|
(let [body (parse-expr (:parser rarrow))]
|
||||||
(assoc body ::ast {::ast/type ::ast/clause
|
(assoc body ::ast {::ast/type ::ast/clause
|
||||||
:pattern (::ast pattern) :body (::ast body)})
|
:pattern (::ast pattern) :body (::ast body)})
|
||||||
)
|
)
|
||||||
(panic rarrow "Expected -> in match clause. Clauses must be in the form pattern -> expression")
|
(panic pattern "Expected -> in match clause. Clauses must be in the form pattern -> expression" #{::token/newline ::token/rbrace})
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(defn- parse-match-clauses [parser]
|
||||||
|
(loop [
|
||||||
|
parser (accept-many #{::token/newline} (advance parser))
|
||||||
|
clauses []]
|
||||||
|
(let [curr (current parser)]
|
||||||
|
(case (::token/type curr)
|
||||||
|
::token/rbrace
|
||||||
|
(assoc parser ::ast {::ast/type ::ast/clauses :clauses clauses})
|
||||||
|
|
||||||
|
::token/newline
|
||||||
|
(recur (accept-many #{::token/newline} parser) clauses)
|
||||||
|
|
||||||
|
(let [clause (parse-match-clause parser)]
|
||||||
|
(recur (accept-many #{::token/newline} clause) (conj clauses (::ast clause)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
(defn- parse-match [parser]
|
(defn- parse-match [parser]
|
||||||
(let [match-expr (parse-expr (advance parser) #{::token/lbrace ::token/lparen})
|
(let [match-expr (parse-expr (advance parser) #{::token/with})
|
||||||
match-header (expect* #{::token/with} "Expected with" match-expr)]
|
match-header (expect* #{::token/with} "Expected with" match-expr)]
|
||||||
(if (:success match-header)
|
(if (:success match-header)
|
||||||
(let [clauses (:parser match-header)]
|
(let [clauses (:parser match-header)]
|
||||||
(if (= (token-type clauses) ::token/lbrace)
|
(if (= (token-type clauses) ::token/lbrace)
|
||||||
(println "one or many clauses")
|
;; match expression with one or many clauses in braces
|
||||||
|
(let [clauses (parse-match-clauses clauses)]
|
||||||
|
(assoc clauses ::ast {::ast/type ::ast/match
|
||||||
|
:expr (::ast match-expr)
|
||||||
|
:clauses (get-in clauses [::ast :clauses])}))
|
||||||
|
;; match expression with single match clause
|
||||||
(let [clause (parse-match-clause clauses)]
|
(let [clause (parse-match-clause clauses)]
|
||||||
(assoc clause ::ast {::ast/type ::ast/match
|
(assoc clause ::ast {::ast/type ::ast/match
|
||||||
:expr (::ast match-expr)
|
:expr (::ast match-expr)
|
||||||
:clauses [(::ast clause)]})
|
:clauses [(::ast clause)]})
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
(panic parser "Expected with after match expression")
|
(panic parser "Expected with after match expression")
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(defn- parse-expr
|
(defn- parse-expr
|
||||||
([parser] (parse-expr parser sync-on))
|
([parser] (parse-expr parser sync-on))
|
||||||
([parser sync-on] (let [token (current parser)]
|
([parser sync-on]
|
||||||
(case (::token/type token)
|
(let [token (current parser)]
|
||||||
|
(case (::token/type token)
|
||||||
|
|
||||||
(::token/number ::token/string)
|
(::token/number ::token/string)
|
||||||
(parse-atom parser)
|
(parse-atom parser)
|
||||||
|
|
||||||
::token/keyword (let [next (peek parser)
|
::token/keyword
|
||||||
type (::token/type next)]
|
(let [next (peek parser)
|
||||||
(if (= type ::token/lparen)
|
type (::token/type next)]
|
||||||
(parse-synthetic parser)
|
(if (= type ::token/lparen)
|
||||||
(parse-atom parser)))
|
(parse-synthetic parser)
|
||||||
|
(parse-atom parser)))
|
||||||
|
|
||||||
::token/word (let [next (peek parser)
|
::token/word
|
||||||
type (::token/type next)]
|
(let [next (peek parser)
|
||||||
(case type
|
type (::token/type next)]
|
||||||
(::token/lparen ::token/keyword) (parse-synthetic parser)
|
(case type
|
||||||
(parse-word parser)))
|
(::token/lparen ::token/keyword) (parse-synthetic parser)
|
||||||
|
(parse-word parser)))
|
||||||
|
|
||||||
(::token/nil ::token/true ::token/false)
|
(::token/nil ::token/true ::token/false)
|
||||||
(parse-atomic-word parser)
|
(parse-atomic-word parser)
|
||||||
|
|
||||||
::token/lparen (parse-tuple parser)
|
::token/lparen (parse-tuple parser)
|
||||||
|
|
||||||
::token/lbracket (parse-list parser)
|
::token/lbracket (parse-list parser)
|
||||||
|
|
||||||
::token/startset (parse-set parser)
|
::token/startset (parse-set parser)
|
||||||
|
|
||||||
::token/starthash (parse-hash parser)
|
::token/starthash (parse-hash parser)
|
||||||
|
|
||||||
::token/lbrace (parse-block parser)
|
::token/lbrace (parse-block parser)
|
||||||
|
|
||||||
::token/let (parse-let parser)
|
::token/let (parse-let parser)
|
||||||
|
|
||||||
::token/if (parse-if parser)
|
::token/if (parse-if parser)
|
||||||
|
|
||||||
::token/match (parse-match parser)
|
::token/match (parse-match parser)
|
||||||
|
|
||||||
::token/comment (advance parser)
|
::token/comment (advance parser)
|
||||||
|
|
||||||
::token/error (panic parser (:message token) sync-on)
|
::token/error (panic parser (:message token) sync-on)
|
||||||
|
|
||||||
(::token/rparen ::token/rbrace ::token/rbracket)
|
(::token/rparen ::token/rbrace ::token/rbracket)
|
||||||
(panic parser (str "Unbalanced enclosure: " (::token/lexeme token)))
|
(panic parser (str "Unbalanced enclosure: " (::token/lexeme token)))
|
||||||
|
|
||||||
(::token/semicolon ::token/comma)
|
(::token/semicolon ::token/comma)
|
||||||
(panic parser (str "Unexpected delimiter: " (::token/lexeme token)))
|
(panic parser (str "Unexpected delimiter: " (::token/lexeme token)))
|
||||||
|
|
||||||
(panic parser "Expected expression" sync-on)
|
(panic parser "Expected expression" sync-on)
|
||||||
|
|
||||||
))))
|
))))
|
||||||
|
|
||||||
(defn parse [lexed]
|
(defn parse [lexed]
|
||||||
(-> lexed
|
(-> lexed
|
||||||
(:tokens)
|
(:tokens)
|
||||||
(parser)
|
(parser)
|
||||||
(parse-script)
|
(parse-script)
|
||||||
))
|
))
|
||||||
|
|
||||||
(do
|
(do
|
||||||
(def pp pp/pprint)
|
(def pp pp/pprint)
|
||||||
(def source "match foo with (foo, bar, 0) -> {
|
(def source "match foo with {
|
||||||
let foo = bar
|
_ -> foo
|
||||||
if foo then bar else baz
|
foo () -> bar
|
||||||
:foo
|
() -> baz
|
||||||
}")
|
}")
|
||||||
(def lexed (scanner/scan source))
|
(def lexed (scanner/scan source))
|
||||||
(def tokens (:tokens lexed))
|
(def tokens (:tokens lexed))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user