1 ! Copyright (C) 2008 Chris Double.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: kernel accessors peg peg.ebnf peg.javascript.ast peg.javascript.tokenizer ;
4 IN: peg.javascript.parser
6 #! Grammar for JavaScript. Based on OMeta-JS example from:
7 #! http://jarrett.cs.ucla.edu/ometa-js/#JavaScript_Compiler
9 #! The interesting thing about this parser is the mixing of
10 #! a default and non-default tokenizer. The JavaScript tokenizer
11 #! removes all newlines. So when operating on tokens there is no
12 #! need for newline and space skipping in the grammar. But JavaScript
13 #! uses the newline in the 'automatic semicolon insertion' rule.
15 #! If a statement ends in a newline, sometimes the semicolon can be
16 #! skipped. So we define an 'nl' rule using the default tokenizer.
17 #! This operates a character at a time. Using this 'nl' in the parser
18 #! allows us to detect newlines when we need to for the semicolon
19 #! insertion rule, but ignore it in all other places.
24 tokenizer = <foreign tokenize-javascript Tok>
26 Space = " " | "\t" | "\n"
27 Spaces = Space* => [[ ignore ]]
28 Name = . ?[ ast-name? ]? => [[ value>> ]]
29 Number = . ?[ ast-number? ]?
30 String = . ?[ ast-string? ]?
31 RegExp = . ?[ ast-regexp? ]?
32 SpacesNoNl = (!(nl) Space)* => [[ ignore ]]
34 Expr = OrExpr:e "?" Expr:t ":" Expr:f => [[ e t f ast-cond-expr boa ]]
35 | OrExpr:e "=" Expr:rhs => [[ e rhs ast-set boa ]]
36 | OrExpr:e "+=" Expr:rhs => [[ e rhs "+" ast-mset boa ]]
37 | OrExpr:e "-=" Expr:rhs => [[ e rhs "-" ast-mset boa ]]
38 | OrExpr:e "*=" Expr:rhs => [[ e rhs "*" ast-mset boa ]]
39 | OrExpr:e "/=" Expr:rhs => [[ e rhs "/" ast-mset boa ]]
40 | OrExpr:e "%=" Expr:rhs => [[ e rhs "%" ast-mset boa ]]
41 | OrExpr:e "&&=" Expr:rhs => [[ e rhs "&&" ast-mset boa ]]
42 | OrExpr:e "||=" Expr:rhs => [[ e rhs "||" ast-mset boa ]]
43 | OrExpr:e "^=" Expr:rhs => [[ e rhs "^" ast-mset boa ]]
44 | OrExpr:e "&=" Expr:rhs => [[ e rhs "&" ast-mset boa ]]
45 | OrExpr:e "|=" Expr:rhs => [[ e rhs "|" ast-mset boa ]]
46 | OrExpr:e "<<=" Expr:rhs => [[ e rhs "<<" ast-mset boa ]]
47 | OrExpr:e ">>=" Expr:rhs => [[ e rhs ">>" ast-mset boa ]]
48 | OrExpr:e ">>>=" Expr:rhs => [[ e rhs ">>>" ast-mset boa ]]
51 ExprNoIn = OrExprNoIn:e "?" ExprNoIn:t ":" ExprNoIn:f => [[ e t f ast-cond-expr boa ]]
52 | OrExprNoIn:e "=" ExprNoIn:rhs => [[ e rhs ast-set boa ]]
53 | OrExprNoIn:e "+=" ExprNoIn:rhs => [[ e rhs "+" ast-mset boa ]]
54 | OrExprNoIn:e "-=" ExprNoIn:rhs => [[ e rhs "-" ast-mset boa ]]
55 | OrExprNoIn:e "*=" ExprNoIn:rhs => [[ e rhs "*" ast-mset boa ]]
56 | OrExprNoIn:e "/=" ExprNoIn:rhs => [[ e rhs "/" ast-mset boa ]]
57 | OrExprNoIn:e "%=" ExprNoIn:rhs => [[ e rhs "%" ast-mset boa ]]
58 | OrExprNoIn:e "&&=" ExprNoIn:rhs => [[ e rhs "&&" ast-mset boa ]]
59 | OrExprNoIn:e "||=" ExprNoIn:rhs => [[ e rhs "||" ast-mset boa ]]
60 | OrExprNoIn:e "^=" ExprNoIn:rhs => [[ e rhs "^" ast-mset boa ]]
61 | OrExprNoIn:e "&=" ExprNoIn:rhs => [[ e rhs "&" ast-mset boa ]]
62 | OrExprNoIn:e "|=" ExprNoIn:rhs => [[ e rhs "|" ast-mset boa ]]
63 | OrExprNoIn:e "<<=" ExprNoIn:rhs => [[ e rhs "<<" ast-mset boa ]]
64 | OrExprNoIn:e ">>=" ExprNoIn:rhs => [[ e rhs ">>" ast-mset boa ]]
65 | OrExprNoIn:e ">>>=" ExprNoIn:rhs => [[ e rhs ">>>" ast-mset boa ]]
66 | OrExprNoIn:e => [[ e ]]
68 OrExpr = OrExpr:x "||" AndExpr:y => [[ x y "||" ast-binop boa ]]
70 OrExprNoIn = OrExprNoIn:x "||" AndExprNoIn:y => [[ x y "||" ast-binop boa ]]
72 AndExpr = AndExpr:x "&&" BitOrExpr:y => [[ x y "&&" ast-binop boa ]]
74 AndExprNoIn = AndExprNoIn:x "&&" BitOrExprNoIn:y => [[ x y "&&" ast-binop boa ]]
76 BitOrExpr = BitOrExpr:x "|" BitXORExpr:y => [[ x y "|" ast-binop boa ]]
78 BitOrExprNoIn = BitOrExprNoIn:x "|" BitXORExprNoIn:y => [[ x y "|" ast-binop boa ]]
80 BitXORExpr = BitXORExpr:x "^" BitANDExpr:y => [[ x y "^" ast-binop boa ]]
82 BitXORExprNoIn = BitXORExprNoIn:x "^" BitANDExprNoIn:y => [[ x y "^" ast-binop boa ]]
84 BitANDExpr = BitANDExpr:x "&" EqExpr:y => [[ x y "&" ast-binop boa ]]
86 BitANDExprNoIn = BitANDExprNoIn:x "&" EqExprNoIn:y => [[ x y "&" ast-binop boa ]]
88 EqExpr = EqExpr:x "==" RelExpr:y => [[ x y "==" ast-binop boa ]]
89 | EqExpr:x "!=" RelExpr:y => [[ x y "!=" ast-binop boa ]]
90 | EqExpr:x "===" RelExpr:y => [[ x y "===" ast-binop boa ]]
91 | EqExpr:x "!==" RelExpr:y => [[ x y "!==" ast-binop boa ]]
93 EqExprNoIn = EqExprNoIn:x "==" RelExprNoIn:y => [[ x y "==" ast-binop boa ]]
94 | EqExprNoIn:x "!=" RelExprNoIn:y => [[ x y "!=" ast-binop boa ]]
95 | EqExprNoIn:x "===" RelExprNoIn:y => [[ x y "===" ast-binop boa ]]
96 | EqExprNoIn:x "!==" RelExprNoIn:y => [[ x y "!==" ast-binop boa ]]
98 RelExpr = RelExpr:x ">" ShiftExpr:y => [[ x y ">" ast-binop boa ]]
99 | RelExpr:x ">=" ShiftExpr:y => [[ x y ">=" ast-binop boa ]]
100 | RelExpr:x "<" ShiftExpr:y => [[ x y "<" ast-binop boa ]]
101 | RelExpr:x "<=" ShiftExpr:y => [[ x y "<=" ast-binop boa ]]
102 | RelExpr:x "instanceof" ShiftExpr:y => [[ x y "instanceof" ast-binop boa ]]
103 | RelExpr:x "in" ShiftExpr:y => [[ x y "in" ast-binop boa ]]
105 RelExprNoIn = RelExprNoIn:x ">" ShiftExpr:y => [[ x y ">" ast-binop boa ]]
106 | RelExprNoIn:x ">=" ShiftExpr:y => [[ x y ">=" ast-binop boa ]]
107 | RelExprNoIn:x "<" ShiftExpr:y => [[ x y "<" ast-binop boa ]]
108 | RelExprNoIn:x "<=" ShiftExpr:y => [[ x y "<=" ast-binop boa ]]
109 | RelExprNoIn:x "instanceof" ShiftExpr:y => [[ x y "instanceof" ast-binop boa ]]
111 ShiftExpr = ShiftExpr:x "<<" AddExpr:y => [[ x y "<<" ast-binop boa ]]
112 | ShiftExpr:x ">>>" AddExpr:y => [[ x y ">>>" ast-binop boa ]]
113 | ShiftExpr:x ">>" AddExpr:y => [[ x y ">>" ast-binop boa ]]
115 AddExpr = AddExpr:x "+" MulExpr:y => [[ x y "+" ast-binop boa ]]
116 | AddExpr:x "-" MulExpr:y => [[ x y "-" ast-binop boa ]]
118 MulExpr = MulExpr:x "*" Unary:y => [[ x y "*" ast-binop boa ]]
119 | MulExpr:x "/" Unary:y => [[ x y "/" ast-binop boa ]]
120 | MulExpr:x "%" Unary:y => [[ x y "%" ast-binop boa ]]
122 Unary = "-" Unary:p => [[ p "-" ast-unop boa ]]
123 | "+" Unary:p => [[ p ]]
124 | "++" Unary:p => [[ p "++" ast-preop boa ]]
125 | "--" Unary:p => [[ p "--" ast-preop boa ]]
126 | "!" Unary:p => [[ p "!" ast-unop boa ]]
127 | "typeof" Unary:p => [[ p "typeof" ast-unop boa ]]
128 | "void" Unary:p => [[ p "void" ast-unop boa ]]
129 | "delete" Unary:p => [[ p "delete" ast-unop boa ]]
131 Postfix = PrimExpr:p SpacesNoNl "++" => [[ p "++" ast-postop boa ]]
132 | PrimExpr:p SpacesNoNl "--" => [[ p "--" ast-postop boa ]]
134 Args = (Expr ("," Expr => [[ second ]])* => [[ first2 swap prefix ]])?
135 PrimExpr = PrimExpr:p "[" Expr:i "]" => [[ i p ast-getp boa ]]
136 | PrimExpr:p "." Name:m "(" Args:as ")" => [[ m p as ast-send boa ]]
137 | PrimExpr:p "." Name:f => [[ f p ast-getp boa ]]
138 | PrimExpr:p "(" Args:as ")" => [[ p as ast-call boa ]]
140 PrimExprHd = "(" Expr:e ")" => [[ e ]]
141 | "this" => [[ ast-this boa ]]
142 | Name => [[ ast-get boa ]]
146 | "function" FuncRest:fr => [[ fr ]]
147 | "new" PrimExpr:n "(" Args:as ")" => [[ n as ast-new boa ]]
148 | "new" PrimExpr:n => [[ n f ast-new boa ]]
149 | "[" Args:es "]" => [[ es ast-array boa ]]
151 JsonBindings = (JsonBinding ("," JsonBinding => [[ second ]])* => [[ first2 swap prefix ]])?
152 Json = "{" JsonBindings:bs "}" => [[ bs ast-json boa ]]
153 JsonBinding = JsonPropName:n ":" Expr:v => [[ n v ast-binding boa ]]
154 JsonPropName = Name | Number | String | RegExp
156 Formals = (Formal ("," Formal => [[ second ]])* => [[ first2 swap prefix ]])?
157 FuncRest = "(" Formals:fs ")" "{" SrcElems:body "}" => [[ fs body ast-func boa ]]
158 Sc = SpacesNoNl (nl | &("}") | End)| ";"
159 Binding = Name:n "=" Expr:v => [[ n v ast-var boa ]]
160 | Name:n => [[ n "undefined" ast-get boa ast-var boa ]]
161 Block = "{" SrcElems:ss "}" => [[ ss ]]
162 Bindings = (Binding ("," Binding => [[ second ]])* => [[ first2 swap prefix ]])?
163 For1 = "var" Bindings => [[ second ]]
165 | Spaces => [[ "undefined" ast-get boa ]]
167 | Spaces => [[ "true" ast-get boa ]]
169 | Spaces => [[ "undefined" ast-get boa ]]
170 ForIn1 = "var" Name:n => [[ n "undefined" ast-get boa ast-var boa ]]
172 Switch1 = "case" Expr:c ":" SrcElems:cs => [[ c cs ast-case boa ]]
173 | "default" ":" SrcElems:cs => [[ cs ast-default boa ]]
174 SwitchBody = Switch1*
175 Finally = "finally" Block:b => [[ b ]]
176 | Spaces => [[ "undefined" ast-get boa ]]
178 | "var" Bindings:bs Sc => [[ bs ast-begin boa ]]
179 | "if" "(" Expr:c ")" Stmt:t "else" Stmt:f => [[ c t f ast-if boa ]]
180 | "if" "(" Expr:c ")" Stmt:t => [[ c t "undefined" ast-get boa ast-if boa ]]
181 | "while" "(" Expr:c ")" Stmt:s => [[ c s ast-while boa ]]
182 | "do" Stmt:s "while" "(" Expr:c ")" Sc => [[ s c ast-do-while boa ]]
183 | "for" "(" For1:i ";" For2:c ";" For3:u ")" Stmt:s => [[ i c u s ast-for boa ]]
184 | "for" "(" ForIn1:v "in" Expr:e ")" Stmt:s => [[ v e s ast-for-in boa ]]
185 | "switch" "(" Expr:e ")" "{" SwitchBody:cs "}" => [[ e cs ast-switch boa ]]
186 | "break" Sc => [[ ast-break boa ]]
187 | "continue" Sc => [[ ast-continue boa ]]
188 | "throw" SpacesNoNl Expr:e Sc => [[ e ast-throw boa ]]
189 | "try" Block:t "catch" "(" Name:e ")" Block:c Finally:f => [[ t e c f ast-try boa ]]
190 | "return" Expr:e Sc => [[ e ast-return boa ]]
191 | "return" Sc => [[ "undefined" ast-get boa ast-return boa ]]
192 | "with" "(" Expr:e ")" Stmt:b => [[ e b ast-with boa ]]
193 | Expr:e Sc => [[ e ]]
194 | ";" => [[ "undefined" ast-get boa ]]
195 SrcElem = "function" Name:n FuncRest:f => [[ n f ast-var boa ]]
197 SrcElems = SrcElem* => [[ ast-begin boa ]]
198 TopLevel = SrcElems Spaces