File Coverage

lib/Erlang/Parser/Parser.yp
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             # Copyright 2011-2012 Yuki Izumi. ( anneli AT cpan DOT org )
2             # This is free software; you can redistribute it and/or modify it under the
3             # same terms as Perl itself.
4              
5             %nonassoc KW_CATCH
6              
7             # ???
8             %nonassoc LARROW LDARROW
9              
10             %right MATCH SEND
11             %left KW_ORELSE
12             %left KW_ANDALSO
13             %nonassoc EQUAL NOT_EQUAL LTE GTE LT GT STRICTLY_EQUAL STRICTLY_NOT_EQUAL
14             %right LISTADD LISTSUBTRACT
15             %left ADD SUBTRACT KW_BOR KW_BXOR KW_BSL KW_BSR KW_OR KW_XOR
16             %left DIVIDE MULTIPLY KW_DIV KW_REM KW_AND KW_BAND
17             %left NEG POS KW_BNOT KW_NOT
18             %nonassoc OPENRECORD
19             %nonassoc COLON
20              
21             %{
22 1     1   8 use strict;
  1         2  
  1         36  
23 1     1   6 use warnings;
  1         2  
  1         35  
24              
25 1     1   543 use Erlang::Parser::Node::Directive;
  0            
  0            
26             use Erlang::Parser::Node::DefList;
27             use Erlang::Parser::Node::Def;
28             use Erlang::Parser::Node::WhenList;
29             use Erlang::Parser::Node::Atom;
30             use Erlang::Parser::Node::Integer;
31             use Erlang::Parser::Node::BinOp;
32             use Erlang::Parser::Node::List;
33             use Erlang::Parser::Node::Variable;
34             use Erlang::Parser::Node::Tuple;
35             use Erlang::Parser::Node::Macro;
36             use Erlang::Parser::Node::String;
37             use Erlang::Parser::Node::Call;
38             use Erlang::Parser::Node::Alt;
39             use Erlang::Parser::Node::Try;
40             use Erlang::Parser::Node::Literal;
41             use Erlang::Parser::Node::FunRef;
42             use Erlang::Parser::Node::FunLocal;
43             use Erlang::Parser::Node::FunLocalCase;
44             use Erlang::Parser::Node::Case;
45             use Erlang::Parser::Node::RecordNew;
46             use Erlang::Parser::Node::VariableRecordAccess;
47             use Erlang::Parser::Node::VariableRecordUpdate;
48             use Erlang::Parser::Node::Float;
49             use Erlang::Parser::Node::BaseInteger;
50             use Erlang::Parser::Node::BinaryExpr;
51             use Erlang::Parser::Node::Binary;
52             use Erlang::Parser::Node::UnOp;
53             use Erlang::Parser::Node::Begin;
54             use Erlang::Parser::Node::Comprehension;
55             use Erlang::Parser::Node::If;
56             use Erlang::Parser::Node::IfExpr;
57             use Erlang::Parser::Node::Receive;
58             use Erlang::Parser::Node::ReceiveAfter;
59              
60             sub new_node {
61             my ($kind, %args) = @_;
62             "Erlang::Parser::Node::$kind"->new(%args);
63             }
64             %}
65              
66             %%
67              
68             # TODO: A few of these lists are flawed in that their optional type isn't done correctly
69             # (they allow constructs like [, 1, 2]). Fix this.
70              
71             root:
72             { [] }
73             | root rootstmt { [@{$_[1]}, $_[2]] }
74             ;
75              
76             rootstmt:
77             SUBTRACT ATOM LPAREN exprlist RPAREN PERIOD { new_node 'Directive', directive => $_[2], args => $_[4] }
78             | deflist PERIOD { $_[1] }
79             ;
80              
81             deflist:
82             def { new_node('DefList')->_append($_[1]) }
83             | deflist SEMICOLON def { $_[1]->_append($_[3]) }
84             ;
85              
86             def:
87             ATOM LPAREN exprlist RPAREN whenlist RARROW stmtlist { new_node 'Def', def => $_[1], args => $_[3], whens => $_[5]->_group, stmts => $_[7] }
88             ;
89              
90             whenlist:
91             { new_node 'WhenList' }
92             | KW_WHEN expr { new_node('WhenList')->_append($_[2]) }
93             # TODO differentiate these. (a;b,c (A)||(B&&C))
94             | whenlist COMMA expr { $_[1]->_append($_[3]) }
95             | whenlist SEMICOLON expr { $_[1]->_group->_append($_[3]) }
96             ;
97              
98             # somehow this is an idiom. exprlist = 0 or more. stmtlist = 1 or more.
99             exprlist:
100             { [] }
101             | stmtlist { $_[1] }
102             ;
103              
104             stmtlist:
105             expr { [$_[1]] }
106             | stmtlist COMMA expr { [@{$_[1]}, $_[3]] }
107             ;
108              
109             unparenexpr:
110             immexpr
111             | case
112             | fun
113             | binary
114             | receive
115             | comprehension
116             | try
117             | if
118             | KW_BEGIN exprlist KW_END { new_node 'Begin', exprs => $_[2] }
119             | expr SEND expr { new_node 'BinOp', op => '!', a => $_[1], b => $_[3] }
120             | expr LT expr { new_node 'BinOp', op => '<', a => $_[1], b => $_[3] }
121             | expr LTE expr { new_node 'BinOp', op => '=<', a => $_[1], b => $_[3] }
122             | expr GT expr { new_node 'BinOp', op => '>', a => $_[1], b => $_[3] }
123             | expr GTE expr { new_node 'BinOp', op => '>=', a => $_[1], b => $_[3] }
124             | expr DIVIDE expr { new_node 'BinOp', op => '/', a => $_[1], b => $_[3] }
125             | expr KW_DIV expr { new_node 'BinOp', op => 'div', a => $_[1], b => $_[3] }
126             | expr MULTIPLY expr { new_node 'BinOp', op => '*', a => $_[1], b => $_[3] }
127             | expr ADD expr { new_node 'BinOp', op => '+', a => $_[1], b => $_[3] }
128             | expr SUBTRACT expr { new_node 'BinOp', op => '-', a => $_[1], b => $_[3] }
129             | expr MATCH expr { new_node 'BinOp', op => '=', a => $_[1], b => $_[3] }
130             | expr LISTADD expr { new_node 'BinOp', op => '++', a => $_[1], b => $_[3] }
131             | expr LISTSUBTRACT expr { new_node 'BinOp', op => '--', a => $_[1], b => $_[3] }
132             | expr EQUAL expr { new_node 'BinOp', op => '==', a => $_[1], b => $_[3] }
133             | expr STRICTLY_EQUAL expr { new_node 'BinOp', op => '=:=', a => $_[1], b => $_[3] }
134             | expr STRICTLY_NOT_EQUAL expr { new_node 'BinOp', op => '=/=', a => $_[1], b => $_[3] }
135             | expr NOT_EQUAL expr { new_node 'BinOp', op => '/=', a => $_[1], b => $_[3] }
136             | expr KW_BSL expr { new_node 'BinOp', op => 'bsl', a => $_[1], b => $_[3] }
137             | expr KW_BSR expr { new_node 'BinOp', op => 'bsr', a => $_[1], b => $_[3] }
138             | expr KW_BOR expr { new_node 'BinOp', op => 'bor', a => $_[1], b => $_[3] }
139             | expr KW_BAND expr { new_node 'BinOp', op => 'band', a => $_[1], b => $_[3] }
140             | expr KW_BXOR expr { new_node 'BinOp', op => 'bxor', a => $_[1], b => $_[3] }
141             | expr KW_XOR expr { new_node 'BinOp', op => 'xor', a => $_[1], b => $_[3] }
142             | expr KW_REM expr { new_node 'BinOp', op => 'rem', a => $_[1], b => $_[3] }
143             | expr KW_ANDALSO expr { new_node 'BinOp', op => 'andalso', a => $_[1], b => $_[3] }
144             | expr KW_ORELSE expr { new_node 'BinOp', op => 'orelse', a => $_[1], b => $_[3] }
145             | expr KW_AND expr { new_node 'BinOp', op => 'and', a => $_[1], b => $_[3] }
146             | expr KW_OR expr { new_node 'BinOp', op => 'or', a => $_[1], b => $_[3] }
147             | SUBTRACT expr %prec NEG { new_node 'UnOp', op => '-', a => $_[2] }
148             | ADD expr %prec POS { new_node 'UnOp', op => '+', a => $_[2] }
149             | KW_BNOT expr { new_node 'UnOp', op => 'bnot', a => $_[2] }
150             | KW_NOT expr { new_node 'UnOp', op => 'not', a => $_[2] }
151             | KW_CATCH expr { new_node 'UnOp', op => 'catch', a => $_[2] }
152              
153             # TODO: unhack this.
154             | expr LARROW expr { new_node 'BinOp', op => '<-', a => $_[1], b => $_[3] }
155             | expr LDARROW expr { new_node 'BinOp', op => '<=', a => $_[1], b => $_[3] }
156              
157             | call
158             ;
159              
160             parenexpr:
161             LPAREN expr RPAREN { $_[2] }
162             ;
163              
164             expr:
165             unparenexpr
166             | parenexpr
167             ;
168              
169             parenorimm:
170             parenexpr
171             | immexpr
172             ;
173              
174             immexpr:
175             FLOAT { new_node 'Float', float => $_[1] }
176             | BASE_INTEGER { new_node 'BaseInteger', baseinteger => $_[1] }
177             | INTEGER { new_node 'Integer', int => $_[1] }
178             | string
179             | variable OPENRECORD atom { new_node 'VariableRecordAccess', variable => $_[1], record => $_[3] }
180             | variable newrecord { new_node 'VariableRecordUpdate', variable => $_[1], update => $_[2] }
181             | LITERAL { new_node 'Literal', literal => substr($_[1], 1) }
182             | list
183             | tuple
184             | newrecord
185             | macro
186             | variable
187             | atom
188             ;
189              
190             atom:
191             ATOM { new_node 'Atom', atom => $_[1] }
192             ;
193              
194             macro:
195             MACRO { new_node 'Macro', macro => substr($_[1], 1) }
196             ;
197              
198             variable:
199             VARIABLE { new_node 'Variable', variable => $_[1] }
200             ;
201              
202             string:
203             STRING { new_node 'String', string => $_[1] }
204             | string STRING { $_[1]->_append($_[2]) }
205             ;
206              
207             call:
208             intcall
209             | extcall
210             ;
211              
212             intcall:
213             parenorimm LPAREN exprlist RPAREN { new_node 'Call', function => $_[1], args => $_[3] }
214             ;
215              
216             extcall:
217             parenorimm COLON intcall { $_[3]->module($_[1]); $_[3] }
218             ;
219              
220             list:
221             LISTOPEN exprlist listcdr LISTCLOSE { new_node 'List', elems => $_[2], cdr => $_[3] }
222             ;
223              
224             # This is not a full node.
225             listcdr:
226             { undef }
227             | PIPE expr { $_[2] }
228             ;
229              
230             comprehension:
231             LISTOPEN expr COMPREHENSION exprlist LISTCLOSE { new_node 'Comprehension', output => $_[2], generators => $_[4] }
232             | OPENBINARY binary COMPREHENSION exprlist CLOSEBINARY { new_node 'Comprehension', output => $_[2], generators => $_[4], binary => 1 }
233             ;
234              
235             tuple:
236             TUPLEOPEN exprlist TUPLECLOSE { new_node 'Tuple', elems => $_[2] }
237             ;
238              
239             case:
240             KW_CASE expr KW_OF altlist KW_END { new_node 'Case', of => $_[2], alts => $_[4] }
241             ;
242              
243             altlist:
244             alt { [$_[1]] }
245             | altlist SEMICOLON alt { [@{$_[1]}, $_[3]] }
246             ;
247              
248             alt:
249             expr whenlist RARROW stmtlist { new_node 'Alt', expr => $_[1], whens => $_[2]->_group, stmts => $_[4] }
250             ;
251              
252             fun:
253             funlocal
254             | KW_FUN atom COLON ATOM DIVIDE INTEGER { new_node 'FunRef', module => $_[2], function => $_[4], arity => $_[6] }
255             | KW_FUN macro COLON ATOM DIVIDE INTEGER { new_node 'FunRef', module => $_[2], function => $_[4], arity => $_[6] }
256             | KW_FUN variable COLON ATOM DIVIDE INTEGER { new_node 'FunRef', module => $_[2], function => $_[4], arity => $_[6] }
257             | KW_FUN ATOM DIVIDE INTEGER { new_node 'FunRef', function => $_[2], arity => $_[4] }
258             ;
259              
260             funlocal:
261             KW_FUN funlocallist KW_END { new_node 'FunLocal', cases => $_[2] }
262             ;
263            
264             # These are not full nodes.
265             funlocallist:
266             funlocalcase { [$_[1]] }
267             | funlocallist SEMICOLON funlocalcase { [@{$_[1]}, $_[3]] }
268             ;
269              
270             funlocalcase:
271             LPAREN exprlist RPAREN whenlist RARROW stmtlist { new_node 'FunLocalCase', args => $_[2], whens => $_[4]->_group, stmts => $_[6] }
272             ;
273              
274             newrecord:
275             OPENRECORD atom TUPLEOPEN exprlist TUPLECLOSE { new_node 'RecordNew', record => $_[2], exprs => $_[4] }
276             ;
277              
278             binary:
279             OPENBINARY optbinarylist CLOSEBINARY { new_node 'Binary', bexprs => $_[2] }
280             ;
281              
282             # These are not full nodes.
283             optbinarylist:
284             { [] }
285             | binarylist
286             ;
287              
288             binarylist:
289             binaryexpr { [$_[1]] }
290             | binarylist COMMA binaryexpr { [@{$_[1]}, $_[3]] }
291             ;
292              
293             binaryexpr:
294             parenorimm optbinarysize optbinaryqualifier { new_node 'BinaryExpr', output => $_[1], size => $_[2], qualifier => $_[3] }
295             ;
296              
297             # These are not full nodes.
298             optbinarysize:
299             { undef }
300             | COLON immexpr { $_[2] }
301             ;
302              
303             optbinaryqualifier:
304             { undef }
305             | DIVIDE binaryqualifier { $_[2] }
306             ;
307              
308             binaryqualifier:
309             ATOM
310             | binaryqualifier SUBTRACT ATOM { "$_[1]-$_[3]" }
311             ;
312              
313             receive:
314             KW_RECEIVE altlist after KW_END { new_node 'Receive', alts => $_[2], aft => $_[3] }
315             ;
316              
317             # This is not a full node.
318             after:
319             { undef }
320             | KW_AFTER expr RARROW stmtlist { new_node 'ReceiveAfter', time => $_[2], stmts => $_[4] }
321             ;
322              
323             try:
324             KW_TRY exprlist opttryof opttrycatch opttryafter KW_END { new_node 'Try', exprs => $_[2], of => $_[3], catch => $_[4], aft => $_[5] }
325             ;
326              
327             # These are not full nodes.
328             opttryof:
329             { undef }
330             | KW_OF altlist { $_[2] }
331             ;
332              
333             opttrycatch:
334             { undef }
335             | KW_CATCH catchaltlist { $_[2] }
336             ;
337              
338             opttryafter:
339             { undef }
340             | KW_AFTER exprlist { $_[2] }
341             ;
342              
343             catchaltlist:
344             catchalt { [$_[1]] }
345             | catchaltlist SEMICOLON catchalt { [@{$_[1]}, $_[3]] }
346             ;
347              
348             catchalt:
349             ATOM COLON expr whenlist RARROW stmtlist { new_node 'Alt', catch => 1, class => $_[1], expr => $_[3], whens => $_[4]->_group, stmts => $_[6] }
350             | VARIABLE COLON expr whenlist RARROW stmtlist { new_node 'Alt', catch => 1, class => $_[1], expr => $_[3], whens => $_[4]->_group, stmts => $_[6] }
351             | expr whenlist RARROW stmtlist { new_node 'Alt', catch => 1, expr => $_[1], whens => $_[2]->_group, stmts => $_[4] }
352             ;
353              
354             if:
355             KW_IF iflist KW_END { new_node 'If', cases => $_[2] }
356             ;
357              
358             iflist:
359             ifexpr { [$_[1]] }
360             | iflist SEMICOLON ifexpr { [@{$_[1]}, $_[3]] }
361             ;
362              
363             ifexpr:
364             ifseq RARROW stmtlist { new_node 'IfExpr', seq => $_[1], stmts => $_[3] }
365             ;
366              
367             ifseq:
368             expr { [$_[1]] }
369             | ifseq COMMA expr { [@{$_[1]}, $_[3]] }
370             ;
371             %%
372              
373             =over 4
374              
375             =item C<new>
376              
377             Creates a new parser object. See L<Parse::Yapp> for more information.
378              
379             =item C<new_node>
380              
381             Helper function used to create new nodes.
382              
383             # These are identical.
384             my $n1 = new_node('X', @y);
385             my $n2 = Erlang::Parser::Node::X->new(@y);
386              
387             =cut
388              
389             1;
390              
391             # vim: set sw=4 ts=4 et filetype=perl: