diff --git a/janet/recursive.janet b/janet/recursive.janet index a99dbef..c1c8161 100644 --- a/janet/recursive.janet +++ b/janet/recursive.janet @@ -1,5 +1,8 @@ ### A recursive descent parser for Ludus +### We still need to scan some things +(os/cd "janet") # when in repl to do relative imports +(import ./scanner :as s) ### First, some mutual recursion helpers (defn unreachable @@ -171,6 +174,76 @@ (advance parser) {:type :string :data (curr :literal) :token curr}) +# interpolated strings, which are a whole other scene +(defn- scan-interpolations [data] + (print "scanning interpolation: " data) + (when (buffer? data) (break data)) + (pp data) + (def to-scan (data :to-scan)) + (def {:tokens tokens :errors errors} (s/scan to-scan)) + (pp tokens) + (print "there are " (length tokens) " tokens") + (def first-token (first tokens)) + (cond + (first errors) (first errors) + (empty? tokens) + {:type :error :msg "string interpolations/patterns must be single words"} + (< 3 (length tokens)) + {:type :error :msg "string interpolations/patterns must be single words"} + (= :word (first-token :type)) + {:type :word :data (first-token :lexeme) :token first-token} + :else {:type :error :msg "string interpolations/patterns must be single words"})) + +(def foo [{:foo :bar}]) +(-> foo first (get :foo)) + +(defn- is-error? [data] + (cond + (buffer? data) false + (= :error (data :type)) true + false)) + +(defn- interpolated [parser] + (expect parser :interpolated) + (def origin (current parser)) + (def source (origin :literal)) + (def data @[]) + (var curr @"") + (var interp? false) + (var escape? false) + (each code source + (def char (string/from-bytes code)) + (cond + (= char "\\") (set escape? true) + escape? (if (= char "{") + (do + (buffer/push curr "{") + (set escape? false)) + (do + (buffer/push curr "\\") + (buffer/push curr char) + (set escape? false))) + (= char "{") (do + (set interp? true) + (array/push data curr) + (set curr @"")) + (= char "}") (if interp? (do + (set interp? false) + (array/push data {:to-scan curr}) + (set curr @"")) + (buffer/push curr char)) + :else (buffer/push curr char))) + (array/push data curr) + (def interpolated (map scan-interpolations data)) + (advance parser) + (def ast {:type :interpolated :data interpolated :token origin}) + (if (some is-error? interpolated) + (do + (def err {:type :error :msg "bad interpolated string" :data ast :token origin}) + (array/push (parser :errors) err) + err) + ast)) + # words & synthetic expressions (def separates [:break :newline :comma]) @@ -338,7 +411,7 @@ :true (bool parser) :false (bool parser) :keyword (kw parser) - :number (number parser) + :number (num parser) :string (str parser) :word (word-pattern parser) :placeholder (placeholder parser) @@ -434,6 +507,7 @@ :number (num parser) :keyword (kw parser) :string (str parser) + :interpolated (interpolated parser) :lparen (tup parser) :lbracket (list parser) :startdict (dict parser) @@ -516,7 +590,7 @@ ) (defrec toplevel [parser] - (def when (current parser)) + (def curr (current parser)) (case (type curr) :pkg (unreachable) :ns (unreachable) @@ -547,16 +621,12 @@ ) ) -(os/cd "janet") # when repl to do relative imports -(import ./scanner :as s) (do #(comment -(def source `"foo {bar} \{baz"`) +(def source `"foo { bar } baz \{quux} {fuzz}"`) (def scanned (s/scan source)) -# (def a-parser (new-parser scanned)) -# (def parsed (whenn a-parser)) -# (-> parsed) -(first (scanned :tokens)) +(def a-parser (new-parser scanned)) +(def parsed (simple a-parser)) +(-> parsed) ) -