Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| 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 | |
| ``` |