From 1f19a0ea1e5051ecea38ac8f60b7dab65b07fc2d Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Sun, 20 Mar 2022 18:30:30 -0400 Subject: [PATCH] Decide against refactoring beyond cljfmt, write basic fn parser --- src/ludus/parser.clj | 69 ++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/src/ludus/parser.clj b/src/ludus/parser.clj index eabd1b0..508a8fc 100644 --- a/src/ludus/parser.clj +++ b/src/ludus/parser.clj @@ -451,29 +451,58 @@ (panic parser "Expected with after match expression")))) +(defn- parse-fn-clause [parser] + (if (not (= ::token/lparen (token-type parser))) + (panic parser "Function clauses must begin with tuple patterns") + (let [pattern (parse-tuple-pattern parser) + arrow (expect* #{::token/rarrow} "Expected arrow" pattern) + body (parse-expr (:parser arrow))] + (if (:success arrow) + (assoc body ::ast {::ast/type ::ast/clause + :pattern (::ast pattern) :body (::ast body)}) + (panic pattern "Expected -> in function clause. Clauses must be in the form of (pattern) -> expression"))))) + +(defn- parse-fn-clauses [parser] + (loop [parser (accept-many #{::token/newline} (advance parser)) + clauses []] + (let [curr (current parser)] + (case (::token/type curr) + ::token/rbrace + (assoc (advance parser) ::ast {::ast/type ::ast/clauses :clauses clauses}) + + ::token/newline + (recur (accept-many #{::token/newline} parser) clauses) + + (let [clause (parse-fn-clause parser)] + (recur (accept-many #{::token/newline} clause) (conj clauses (::ast clause)))))))) + +(defn- parse-named-fn [parser] + (let [name (parse-word parser)] + (case (token-type name) + ::token/lparen + (let [clause (parse-fn-clause name)] + (assoc clause ::ast {::ast/type ::ast/fn + :name (get-in name [::ast :word]) + :clauses [(::ast clause)]})) + + ::token/lbrace + (let [clauses (parse-fn-clauses name)] + (assoc clauses ::ast {::ast/type ::ast/match + :name (get-in name [::ast :word]) + :clauses (get-in clauses [::ast :clauses])})) + + (panic name "Expected one or more function clauses")))) + (defn- parse-fn [parser] (let [first (advance parser)] (case (::token/type (current first)) ::token/lparen - (let [pattern (parse-tuple-pattern first) - arrow (expect* ::token/rarrow "Expected arrow after pattern" pattern)] - (if (:success arrow) - (let [body (parse-expr (:parser arrow))] - (assoc body ::ast {::ast/type ::ast/fn - :name "anonymous" - :clauses [{::ast/type ::ast/clause - :pattern (::ast pattern) - :body (::ast body)}]})) - (panic pattern "Expected arrow after pattern in fn clause"))) + (let [clause (parse-fn-clause first)] + (assoc clause ::ast {::ast/type ::ast/fn + :name "anonymous" + :clauses [(::ast clause)]})) -;; TODO: finish this - ;; right now it's broke - ::token/word - (let [name (parse-word first) - pattern (parse-tuple-pattern name) - arrow (expect* ::token/rarrow "Expected arrow after pattern" name) - body (parse-expr (:parser arrow))] - ()) + ::token/word (parse-named-fn first) (panic parser "Expected name or clause after fn")))) @@ -543,7 +572,9 @@ (do (def pp pp/pprint) - (def source "fn () -> :foo + (def source "fn foo { + (foo, bar, baz) -> {:foo} + } ") (def lexed (scanner/scan source))