get the recursive descent framework worked out
This commit is contained in:
parent
402b444231
commit
98fcfe7eb4
|
@ -31,7 +31,12 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
### and some helper functions for interfacing with that data structure
|
### and some helper functions for interfacing with that data structure
|
||||||
(defn- current [parser] (get (parser :tokens) (parser :current)))
|
(defn- current [parser]
|
||||||
|
(def curr (get (parser :tokens) (parser :current)))
|
||||||
|
(if (not curr)
|
||||||
|
(error "no more tokens")
|
||||||
|
curr))
|
||||||
|
|
||||||
|
|
||||||
(defn- peek [parser] (get (parser :tokens) (inc (parser :current))))
|
(defn- peek [parser] (get (parser :tokens) (inc (parser :current))))
|
||||||
|
|
||||||
|
@ -39,46 +44,110 @@
|
||||||
|
|
||||||
(defn- type [token] (get token :type))
|
(defn- type [token] (get token :type))
|
||||||
|
|
||||||
(defn- expect [parser type]
|
(defn- check [parser type]
|
||||||
(def current-type (-> parser current (get :type)))
|
(def current-type (-> parser current (get :type)))
|
||||||
(= type current-type))
|
(= type current-type))
|
||||||
|
|
||||||
### Parsing functions
|
### Parsing functions
|
||||||
(declare expr)
|
(declare nonbinding binding)
|
||||||
|
|
||||||
|
# errors
|
||||||
|
(def terminators [:break :newline :semicolon :eof])
|
||||||
|
|
||||||
|
(defn- terminates? [parser]
|
||||||
|
(def curr (current parser))
|
||||||
|
(def ttype (type curr))
|
||||||
|
(has-value? terminators ttype))
|
||||||
|
|
||||||
|
(defn- panic [parser message]
|
||||||
|
(print "Panic in the parser: " message)
|
||||||
|
(def origin (current parser))
|
||||||
|
(advance parser)
|
||||||
|
(def skipped @[origin])
|
||||||
|
(while (not (terminates? parser))
|
||||||
|
(array/push skipped (current parser))
|
||||||
|
(advance parser))
|
||||||
|
(array/push skipped (current parser))
|
||||||
|
(advance parser)
|
||||||
|
(error {:type :error :data skipped :token origin}))
|
||||||
|
|
||||||
|
(defn- expected [parser ttype]
|
||||||
|
(panic parser (string "expected " ttype ", got " (-> parser current type))))
|
||||||
|
|
||||||
|
(defn- expect [parser type]
|
||||||
|
(if-not (check parser type) (expected parser type)))
|
||||||
|
|
||||||
# atoms
|
# atoms
|
||||||
(defn- bool [parser]
|
(defn- bool [parser]
|
||||||
|
(expect parser :bool)
|
||||||
(def curr (-> parser current))
|
(def curr (-> parser current))
|
||||||
(def ttype (type curr))
|
(def ttype (type curr))
|
||||||
(def value (if (= ttype :true) true false))
|
(def value (if (= ttype :true) true false))
|
||||||
(def ast {:type :bool :value value :token curr})
|
(advance parser)
|
||||||
(update parser :ast array/push ast)
|
{:type :bool :data value :token curr}
|
||||||
(advance parser))
|
)
|
||||||
|
|
||||||
(defn- num [parser]
|
(defn- num [parser]
|
||||||
|
(expect parser :number)
|
||||||
(def curr (-> parser current))
|
(def curr (-> parser current))
|
||||||
(def ast {:type :number :value (curr :literal) :token curr})
|
(advance parser)
|
||||||
(update parser :ast array/push ast)
|
{:type :number :data (curr :literal) :token curr}
|
||||||
(advance parser))
|
)
|
||||||
|
|
||||||
(defn- kw [parser]
|
(defn- kw [parser]
|
||||||
|
(expect parser :keyword)
|
||||||
(def curr (-> parser current))
|
(def curr (-> parser current))
|
||||||
(def ast {:type :keyword :value (curr :literal) :token curr})
|
(advance parser)
|
||||||
(update parser :ast array/push ast)
|
{:type :keyword :data (curr :literal) :token curr}
|
||||||
(advance parser))
|
)
|
||||||
|
|
||||||
(defn- nill [parser]
|
(defn- nill [parser]
|
||||||
(def ast {:type :nil :token (current parser)})
|
(expect parser :nil)
|
||||||
(update parser :ast array/push ast)
|
(advance parser)
|
||||||
(advance parser))
|
{:type :nil :token (current parser)}
|
||||||
|
)
|
||||||
|
|
||||||
(defn- str [parser]
|
(defn- str [parser]
|
||||||
|
(expect parser :string)
|
||||||
(def curr (-> parser current))
|
(def curr (-> parser current))
|
||||||
(def ast {:type :string :value (curr :literal) :token curr})
|
(advance parser)
|
||||||
(update parser :ast array/push ast)
|
{:type :string :data (curr :literal) :token curr}
|
||||||
(advance parser))
|
)
|
||||||
|
|
||||||
(defrec expr [parser]
|
(def separates [:break :newline :comma])
|
||||||
|
|
||||||
|
(defn- separates? [parser]
|
||||||
|
(def curr (current parser))
|
||||||
|
(def ttype (type curr))
|
||||||
|
(has-value? separates ttype))
|
||||||
|
|
||||||
|
(defn- separators [parser]
|
||||||
|
(if-not (separates? parser)
|
||||||
|
(panic parser (string "expected separator, got " (-> parser current type))))
|
||||||
|
(while (separates? parser) (advance parser)))
|
||||||
|
|
||||||
|
(defn- tup-term [parser]
|
||||||
|
(def term (nonbinding parser))
|
||||||
|
(if (separates? parser)
|
||||||
|
(do
|
||||||
|
(while (separates? parser) (advance parser))
|
||||||
|
term)
|
||||||
|
(panic parser (string "expected separator, got " (type (current parser))))))
|
||||||
|
|
||||||
|
(defn- tup [parser]
|
||||||
|
(def origin (current parser))
|
||||||
|
(advance parser) # consume the :lparen
|
||||||
|
(def ast {:type :tuple :data @[] :token origin})
|
||||||
|
(while (separates? parser) (advance parser)) # consume any separators
|
||||||
|
(while (not (check parser :rparen))
|
||||||
|
(def term (try (nonbinding parser) ([e] e)))
|
||||||
|
(array/push (ast :data) term)
|
||||||
|
(try (separators parser)
|
||||||
|
([e] (pp e) (array/push (ast :data) e))))
|
||||||
|
(advance parser)
|
||||||
|
ast)
|
||||||
|
|
||||||
|
(defrec nonbinding [parser]
|
||||||
(def curr (current parser))
|
(def curr (current parser))
|
||||||
(case (type curr)
|
(case (type curr)
|
||||||
# atoms
|
# atoms
|
||||||
|
@ -92,18 +161,30 @@
|
||||||
:string (str parser)
|
:string (str parser)
|
||||||
### TODO: interpolated strings
|
### TODO: interpolated strings
|
||||||
|
|
||||||
|
# tuples
|
||||||
|
:lparen (tup parser)
|
||||||
|
|
||||||
|
(panic parser (string "expected nonbinding expression, got " (type curr)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defrec binding [parser]
|
||||||
|
(def curr (current parser))
|
||||||
|
(case (type curr)
|
||||||
|
:let nil
|
||||||
|
:fn nil
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
(do
|
|
||||||
#(comment
|
|
||||||
(os/cd "janet") # For repl to do relative imports
|
(os/cd "janet") # For repl to do relative imports
|
||||||
(import ./scanner :as s)
|
(import ./scanner :as s)
|
||||||
|
(do
|
||||||
|
#(comment
|
||||||
|
|
||||||
(def scanned (s/scan "\"foo bar baz\""))
|
(def scanned (s/scan "(1, (2 3), 3)"))
|
||||||
(def a-parser (new-parser scanned))
|
(def a-parser (new-parser scanned))
|
||||||
(def parsed (expr a-parser))
|
(def parsed (nonbinding a-parser))
|
||||||
(-> parsed (get :ast) (get 0) (get :value))
|
(-> parsed (get :data) )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user