View Source LixParser (LixParser v0.1.0)
Abstract
Lix is a simple Lisp dialect which is parsed by LixParser.parse into an AST.
This AST can then be interpreted as seen fit. An example of a useful interpretation can
be found in LixEval which defines a minimum of
special forms (def, fn, defn, let and use)
The syntax of Lix is defined by the following doctests
Syntax
Literals
Numbers
iex(1)> parse("42")
{:ok, {:lit, 42}}As long as we get an :ok result we can use parse! too
iex(2)> parse!("43")
{:lit, 43}There are floats too
iex(3)> parse!("-44.0")
{:lit, -44.0}Atoms
iex(4)> parse!(":atom")
{:lit, :atom}Strings
iex(5)> parse!(~s{"hello"})
{:lit, "hello"}Identifiers
As no semantic checks can be made by the parser, the ast is augemented by the position in case of all other constructs.
This will allow an interpreter, evaluator or semantic checker to point to the correct position in the source.
iex(6)> parse!("variable")
{:id, {1, 1}, ~W[variable]}The name of the identifier is a list because we can have compound names, as follows
iex(7)> parse!(" alpha.beta")
{:id, {3, 1}, ~W[alpha beta]}And we can have more of this of course
iex(8)> parse!("\n\t a.b.c")
{:id, {4, 2}, ~W[a b c]}Note that positioning does not know about tabwidth in this version of Minipeg and thus
just assumes tabwidth 1
Operators are just identifiers too
iex(9)> parse!("+")
{:id, {1, 1}, ["+"]}They can consist of up to three symbols
iex(10)> parse!("@@-")
{:id, {1, 1}, ["@@-"]}Compound Expressions
Literals and Identifiers are the only scalar expressions in Lix.
They can be combined into lists ((...)), quoted lists ([...]) and maps ({...}) as follows
Lists (s-expressions)
iex(11)> parse!("(+ 2 4)")
{:list, {1, 1}, [{:id, {2, 1}, ["+"]}, {:lit, 2}, {:lit, 4}]}Quoted lists
iex(12)> parse!(~s{[(:a) "b"]})
{:quoted, {1, 1}, [{:list, {2, 1}, [lit: :a]}, {:lit, "b"}]}Maps
iex(13)> parse!("{:a 1 b 2}")
{:map, {1, 1}, [{:lit, :a}, {:lit, 1}, {:id, {7, 1}, ~W[b]}, {:lit, 2}]}Error Handling
Few, experienced with parsing, would argue that error handling is the most difficult aspect of good parsing.
In this early version of the LixParser error handling is very rudimentary, which is just an euphemisim for
outright terrible. Hopefully this will get better along with better support from the underlying PEG library
which is Minipeg.
Bad number
This should not parse, but does
iex(14)> parse("42.")
{:ok, {:lit, 42}}
iex(15)> parse(".42")
{:error, "no alternative could be parsed in <binary>:1,1"}Missing closing parens
iex(16)> parse("(")
{:error, "no alternative could be parsed in <binary>:1,1"}Odd number of elements in a map
iex(17)> parse("{:a 1 :b}")
{:error, "no alternative could be parsed in <binary>:1,1"}
Summary
Types
@type ast_leaf_t() :: {:id, position_t(), binaries()} | {:literal, scalar_t()}
@type ast_t() :: ast_leaf_t() | {:list | :map | :quoted, position_t(), [ast_t()]}
@type binaries() :: [binary()]
@type position_t() :: {pos_integer(), pos_integer()}