Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
196 lines (154 sloc) 4.67 KB
This defines infromaly fromaly the elm grammar
# Notes
## Syntax
All terminal characters are shown bare,
nonterminals are delimited in /Slashes/
I also use <Angled brackets>+ as grouping.
When something is followed by a
: + it appears one or more times
: * it appears zero to N times
: ? it appears zero or one time
## Newline handling
The Newline handling is a bit wonky: Mostly, only Newlines followed by
a token starting at the first column are of meaning, but inside expressions
they are important.
Getting rid of meaningless newline tokens is extremly useful for parsing,
but we need to know when to do so. What I did to handle them is that:
* Have a "pre-parse" phase dividing the token stream in N top level
declarations (divide on N0).
* Depending on which part of the source file we are processing, simply
remove the non-toplevel newlines and then feed the token stream into
the pertinent parser.
* When we know the given toplevel declaration contains an expression, keep
the newline tokens when feeding them to the parser.
## Lazy parsing
To avoid needless computation (parsing expressions or type declaration), I
(plan to) only parse subsets of declarations and stock the remaining tokens
in a data structure so I can parse them later if needed.
# Terminal symbols
DocString
Name -- a bare token, such as a variable or type names can have prefix
Operator
StringLit
ShaderLit
Number
Character
( , ) { } [ ] -> | = : .. _ ::
port module where exposing import as
type alias case of if then else let in
N0 -- Newline, with first character at column 0
CASE_INDENT -- Indentation aligning case pattern branches
LET_INDENT -- Indentation aligning let declarations
ENDCASE -- Implicit closing field of a case pattern branch list.
# Nonterminal symbols
GRAMMAR :=
/ModuleDeclr/ DocString N0 </Import/*> </TopDeclr/*>
/ModuleDeclr/ :=
Name module Name where { <Name = Name>+ } exposing /ExportList/ N0
port module Name exposing /ExportList/ N0
module Name exposing /ExportList/ N0
/ExportList/ :=
( .. )
(/ExportEntry/ <, /ExportEntry/>* )
/ExportEntry/ :=
Name
( Operator )
Name ( .. )
Name ( Name <, Name>* )
/Import/ :=
import Name <as Name>? <exposing /ExportList/>? N0
/TopDeclr/ :=
infixr Number Operator N0
infixl Number Operator N0
DocString N0
type alias Name <Name>* = /Type/ N0
type Name <Name>* = Name </EnclosedType/>* <| Name </EnclosedType/>*>* N0
port Name : /Type/ N0
Name : /Type/ N0
Name </EnclosedPattern/>* = /Expression/ N0
( Operator ) : /Type/ N0
( Operator ) </EnclosedPattern/>* = /Expression/ N0
/Type/ :=
</FunctionlessType/ ->>* /FunctionlessType/
/FunctionlessType/ :=
Name </EnclosedType/>+
/EnclosedType/
/EnclosedType/ :=
{ }
{ <Name |>? Name : /Type/ <, Name : /Type/>* }
( /Type/ <, /Type/>+ )
( /Type/ )
( )
Name
/Pattern/ :=
Name </EnclosedPattern/>+
/EnclosedPattern/
</EnclosedPattern/ ::>+ /EnclosedPattern/
/EnclosedPattern/ :=
{ Name <, Name>* }
( /Pattern/ as Name )
( /Pattern/ <, /Pattern/>+ )
( /Pattern/ )
( )
Name
StringLit
Number
Character
_
[ ]
[ /Pattern/ <, /Pattern/>* ]
/Expression/ :=
</ApplicationExpression/ Operator>+ /OpenExpression/
/OpenExpression/
-- /Expression/ but with terminated case expressions.
/EsacExpression/ :=
</ApplicationExpression/ Operator>+ /EsacOpenExpression/
/EsacOpenExpression/
/EsacOpenExpression/ :=
case /Expression/ of /Casebranche/ <CASE_INDENT /Casebranche/>* ENDCASE
\ </EnclosedPattern/>+ -> /EsacExpression/
if /Expression/ then /Expression/ else /EsacExpression/
let /Declr/ <LET_INDENT /Declr/>* in /EsacExpression/
/ApplicationExpr/
/OpenExpression/ :=
case /Expression/ of /Casebranche/ <CASE_INDENT /Casebranche/>*
\ </EnclosedPattern/>+ -> /Expression/
if /Expression/ then /Expression/ else /Expression/
let /Declr/ <LET_INDENT /Declr/>* in /Expression/
/ApplicationExpr/
/ApplicationExpression/ :=
</ClosedExpression/>+
/ClosedExpression/ :=
{ <Name |>? Name = /Expression/ <, Name = /Expression/>* }
{ }
[ ]
[ /Expression/ <, /Expression/>* ]
( /Expression/ <, /Expression/>+ )
( /Expression/ )
StringLit
Number
Character
ShaderLit
( )
( <,>+ )
( Operator )
Name
/Declr/ :=
<Name : /Type/ LET_INDENT>? Name </EnclosedPattern/>+ = /Expression/
/EnclosedPattern/ = /Expression/
/Casebranche/ :=
/Pattern/ -> /EsacExpression/
# Apendix: Funny elm expressions
```elm
x = case let y = () in y of () -> "hello world"
f (_ as x) = x -- f 10 -> 10
x = if if 0 == 0 then 1 == 1 else 1 /= 1 then 100 else 3
y = 10 {- hello -} -- good
y = 10 {-| hello |-} -- bad
\v -> v * x |> List.map --> \v -> List.map (v * x)
List.map <| \v -> v * x --> List.map (\v -> v * x)
if x > 0 then \v -> v * 10 else \v -> v / 10 -- good
let y = 10
x = 30
in x + y
```