language-python-0.5.8: src/Language/Python/Version3/Parser/Parser.y
{
{-# LANGUAGE CPP #-}
#undef __GLASGOW_HASKELL__
#define __GLASGOW_HASKELL__ 709
-----------------------------------------------------------------------------
-- |
-- Module : Language.Python.Version3.Parser.Parser
-- Copyright : (c) 2009 Bernie Pope
-- License : BSD-style
-- Maintainer : bjpop@csse.unimelb.edu.au
-- Stability : experimental
-- Portability : ghc
--
-- Implementation of the Python version 3 parser. Generated by happy.
-----------------------------------------------------------------------------
module Language.Python.Version3.Parser.Parser (parseFileInput, parseSingleInput, parseEval) where
import Language.Python.Version3.Parser.Lexer
import Language.Python.Common.Token as Token
import Language.Python.Common.AST as AST
import Language.Python.Common.ParserUtils
import Language.Python.Common.ParserMonad
import Language.Python.Common.SrcLocation
import Data.Either (rights, either)
import Data.Maybe (isJust, maybeToList)
}
%name parseFileInput file_input
%name parseSingleInput single_input
%name parseEval eval_input
%tokentype { Token }
%error { parseError }
%monad { P } { thenP } { returnP }
%lexer { lexCont } { EOFToken {} }
%token
'=' { AssignToken {} }
'(' { LeftRoundBracketToken {} }
')' { RightRoundBracketToken {} }
'[' { LeftSquareBracketToken {} }
']' { RightSquareBracketToken {} }
'{' { LeftBraceToken {} }
'}' { RightBraceToken {} }
',' { CommaToken {} }
';' { SemiColonToken {} }
':' { ColonToken {} }
'+' { PlusToken {} }
'-' { MinusToken {} }
'*' { MultToken {} }
'**' { ExponentToken {} }
'/' { DivToken {} }
'//' { FloorDivToken {} }
'>' { GreaterThanToken {} }
'<' { LessThanToken {} }
'==' { EqualityToken {} }
'>=' { GreaterThanEqualsToken {} }
'<=' { LessThanEqualsToken {} }
'|' { BinaryOrToken {} }
'^' { XorToken {} }
'&' { BinaryAndToken {} }
'>>' { ShiftRightToken {} }
'<<' { ShiftLeftToken {} }
'%' { ModuloToken {} }
'~' { TildeToken {} }
'!=' { NotEqualsToken {} }
'.' { DotToken {} }
'...' { EllipsisToken {} }
'+=' { PlusAssignToken {} }
'-=' { MinusAssignToken {} }
'*=' { MultAssignToken {} }
'/=' { DivAssignToken {} }
'%=' { ModAssignToken {} }
'**=' { PowAssignToken {} }
'&=' { BinAndAssignToken {} }
'|=' { BinOrAssignToken {} }
'^=' { BinXorAssignToken {} }
'<<=' { LeftShiftAssignToken {} }
'>>=' { RightShiftAssignToken {} }
'//=' { FloorDivAssignToken {} }
'@=' { MatrixMultAssignToken {} }
'@' { AtToken {} }
'->' { RightArrowToken {} }
'and' { AndToken {} }
'as' { AsToken {} }
'assert' { AssertToken {} }
'async' { AsyncToken {} }
'await' { AwaitToken {} }
'break' { BreakToken {} }
'bytestring' { ByteStringToken {} }
'class' { ClassToken {} }
'continue' { ContinueToken {} }
'dedent' { DedentToken {} }
'def' { DefToken {} }
'del' { DeleteToken {} }
'elif' { ElifToken {} }
'else' { ElseToken {} }
'except' { ExceptToken {} }
'False' { FalseToken {} }
'finally' { FinallyToken {} }
'float' { FloatToken {} }
'for' { ForToken {} }
'from' { FromToken {} }
'global' { GlobalToken {} }
'ident' { IdentifierToken {} }
'if' { IfToken {} }
'imaginary' { ImaginaryToken {} }
'import' { ImportToken {} }
'indent' { IndentToken {} }
'in' { InToken {} }
'integer' { IntegerToken {} }
'is' { IsToken {} }
'lambda' { LambdaToken {} }
'NEWLINE' { NewlineToken {} }
'None' { NoneToken {} }
'nonlocal' { NonLocalToken {} }
'not' { NotToken {} }
'or' { OrToken {} }
'pass' { PassToken {} }
'raise' { RaiseToken {} }
'return' { ReturnToken {} }
'string' { StringToken {} }
'True' { TrueToken {} }
'try' { TryToken {} }
'unicodestring' { UnicodeStringToken {} }
'while' { WhileToken {} }
'with' { WithToken {} }
'yield' { YieldToken {} }
%%
pair(p,q): p q { ($1, $2) }
left(p,q): p q { $1 }
right(p,q): p q { $2 }
or(p,q)
: p { $1 }
| q { $1 }
either(p,q)
: p { Left $1 }
| q { Right $1 }
opt(p)
: { Nothing }
| p { Just $1 }
rev_list1(p)
: p { [$1] }
| rev_list1(p) p { $2 : $1 }
many1(p)
: rev_list1(p) { reverse $1 }
many0(p)
: many1(p) { $1 }
| { [] }
sepOptEndBy(p,sep)
: sepByRev(p,sep) ',' { reverse $1 }
| sepByRev(p,sep) { reverse $1 }
sepBy(p,sep): sepByRev(p,sep) { reverse $1 }
sepByRev(p,sep)
: p { [$1] }
| sepByRev(p,sep) sep p { $3 : $1 }
NAME :: { IdentSpan }
NAME : 'ident' { Ident (token_literal $1) (getSpan $1) }
{-
Note: newline tokens in the grammar:
It seems there are some dubious uses of NEWLINE in the grammar.
This is corroborated by this posting:
http://mail.python.org/pipermail/python-dev/2005-October/057014.html
The general idea is that the lexer does not generate NEWLINE tokens for
lines which contain only spaces or comments. However, the grammar sometimes
suggests that such tokens may exist.
-}
-- single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
{-
We don't support the newline at the end of a compound stmt
because the lexer would not produce a newline there. It seems like a weirdness
in the way the interactive input works.
-}
single_input :: { [StatementSpan] }
single_input
: 'NEWLINE' { [] }
| simple_stmt { $1 }
| compound_stmt {- No newline here! -} { [$1] }
-- file_input: (NEWLINE | stmt)* ENDMARKER
file_input :: { ModuleSpan }
file_input
: many0(either('NEWLINE',stmt)) {- No need to mention ENDMARKER -}
{ Module (concat (rights $1)) }
-- eval_input: testlist NEWLINE* ENDMARKER
eval_input :: { ExprSpan }
eval_input : testlist many0('NEWLINE') {- No need to mention ENDMARKER -} { $1 }
-- decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
opt_paren_arg_list :: { [ArgumentSpan] }
opt_paren_arg_list: opt(paren_arg_list) { (concat (maybeToList (fmap fst $1))) }
paren_arg_list :: { ([ArgumentSpan], SrcSpan) }
paren_arg_list : '(' optional_arg_list ')' { ($2, spanning $1 $3) }
decorator :: { DecoratorSpan }
decorator
: '@' dotted_name opt_paren_arg_list 'NEWLINE'
{ makeDecorator $1 $2 $3 }
-- decorators: decorator+
decorators :: { [DecoratorSpan] }
decorators : many1(decorator) { $1 }
-- decorated: decorators (classdef | funcdef)
decorated :: { StatementSpan }
decorated
: decorators classdef { makeDecorated $1 $2 }
| decorators funcdef { makeDecorated $1 $2 }
| decorators async_funcdef { makeDecorated $1 $2 }
-- funcdef: 'def' NAME parameters ['->' test] ':' suite
funcdef :: { StatementSpan }
funcdef
: 'def' NAME parameters opt(right('->',test)) ':' suite
{ makeFun $1 $2 $3 $4 $6 }
-- parameters: '(' [typedargslist] ')'
parameters :: { [ParameterSpan] }
parameters : '(' opt(typedargslist) ')' { concat (maybeToList $2) }
{-
typedargslist: ((tfpdef ['=' test] ',')*
('*' [tfpdef] (',' tfpdef ['=' test])* [',' '**' tfpdef] | '**' tfpdef)
| tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
-}
{- Same pattern as argslist and varargslist -}
typedargslist :: { [ParameterSpan] }
typedargslist: sepOptEndBy(one_typedargs_param,',') {% checkParameters $1 }
one_typedargs_param :: { ParameterSpan }
one_typedargs_param
: tfpdef optional_default { makeParam $1 $2 }
| '*' opt(tfpdef) { makeStarParam $1 $2 }
| '**' tfpdef { makeStarStarParam $1 $2 }
optional_default :: { Maybe ExprSpan }
optional_default: opt(equals_test) { $1 }
equals_test :: { ExprSpan }
equals_test: '=' test { $2 }
{- tfpdef: NAME [':' test] -}
tfpdef :: { (IdentSpan, Maybe ExprSpan) }
tfpdef : NAME opt(colon_test) { ($1, $2) }
colon_test :: { ExprSpan }
colon_test: ':' test { $2 }
{-
varargslist: ((vfpdef ['=' test] ',')* ('*' [vfpdef] (',' vfpdef ['=' test])* [',' '**' vfpdef] | '**' vfpdef) | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
-}
{-
There is some tedious similarity in these rules to the ones for
TypedArgsList. varargslist is used for lambda functions, and they
do not have parentheses around them (unlike function definitions).
Therefore lambda parameters cannot have the optional annotations
that normal functions can, because the annotations are introduced
using a colon. This would cause ambibguity with the colon
that marks the end of the lambda parameter list!
-}
varargslist :: { [ParameterSpan] }
varargslist : sepOptEndBy(one_varargs_param,',') {% checkParameters $1 }
one_varargs_param :: { ParameterSpan }
one_varargs_param
: '*' optvfpdef { makeStarParam $1 $2 }
| '**' vfpdef { makeStarStarParam $1 ($2, Nothing) }
| vfpdef optional_default { makeParam ($1, Nothing) $2 }
-- vfpdef: NAME
vfpdef :: { IdentSpan }
vfpdef : NAME { $1 }
optvfpdef :: { Maybe (IdentSpan, Maybe ExprSpan) }
optvfpdef
: {- empty -} { Nothing }
| vfpdef { Just ($1, Nothing) }
-- stmt: simple_stmt | compound_stmt
stmt :: { [StatementSpan] }
stmt
: simple_stmt { $1 }
| compound_stmt { [$1] }
-- simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
simple_stmt :: { [StatementSpan] }
simple_stmt : small_stmts opt(';') 'NEWLINE' { reverse $1 }
small_stmts :: { [StatementSpan] }
small_stmts
: small_stmt { [$1] }
| small_stmts ';' small_stmt { $3 : $1 }
{-
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
-}
small_stmt :: { StatementSpan }
small_stmt
: expr_stmt { $1 }
| del_stmt { $1 }
| pass_stmt { $1 }
| flow_stmt { $1 }
| import_stmt { $1 }
| global_stmt { $1 }
| nonlocal_stmt { $1 }
| assert_stmt { $1 }
{- expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) |
('=' (yield_expr|testlist_star_expr))*)
-}
expr_stmt :: { StatementSpan }
expr_stmt
: testlist_star_expr many_assign { makeNormalAssignment $1 $2 }
| testlist_star_expr augassign_yield_or_test_list { makeAugAssignment $1 $2 }
| testlist_star_expr annassign { makeAnnAssignment $1 $2 }
many_assign :: { [ExprSpan] }
many_assign : many0(right('=', yield_or_test_list_star)) { $1 }
yield_or_test_list :: { ExprSpan }
yield_or_test_list : or(yield_expr,testlist) { $1 }
yield_or_test_list_star :: { ExprSpan }
yield_or_test_list_star : or(yield_expr,testlist_star_expr) { $1 }
augassign_yield_or_test_list :: { (AssignOpSpan, ExprSpan) }
augassign_yield_or_test_list : augassign yield_or_test_list { ($1, $2) }
-- testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
testlist_star_expr :: { ExprSpan }
testlist_star_expr
: test_list_star_rev opt_comma
{ makeTupleOrExpr (reverse $1) $2 }
test_list_star_rev :: { [ExprSpan] }
test_list_star_rev
: or(test,star_expr) { [$1] }
| test_list_star_rev ',' or(test,star_expr) { $3 : $1 }
{-
augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
'<<=' | '>>=' | '**=' | '//=' | '@=')
-}
augassign :: { AssignOpSpan }
augassign
: '+=' { AST.PlusAssign (getSpan $1) }
| '-=' { AST.MinusAssign (getSpan $1) }
| '*=' { AST.MultAssign (getSpan $1) }
| '/=' { AST.DivAssign (getSpan $1) }
| '%=' { AST.ModAssign (getSpan $1) }
| '**=' { AST.PowAssign (getSpan $1) }
| '&=' { AST.BinAndAssign (getSpan $1) }
| '|=' { AST.BinOrAssign (getSpan $1) }
| '^=' { AST.BinXorAssign (getSpan $1) }
| '<<=' { AST.LeftShiftAssign (getSpan $1) }
| '>>=' { AST.RightShiftAssign (getSpan $1) }
| '//=' { AST.FloorDivAssign (getSpan $1) }
| '@=' { AST.MatrixMultAssign (getSpan $1) }
-- annassign: ':' test ['=' test]
annassign :: { (ExprSpan, Maybe ExprSpan) }
annassign : ':' test opt(right('=', test)) { ($2, $3) }
-- del_stmt: 'del' exprlist
del_stmt :: { StatementSpan }
del_stmt : 'del' exprlist { AST.Delete $2 (spanning $1 $2) }
-- pass_stmt: 'pass'
pass_stmt :: { StatementSpan }
pass_stmt : 'pass' { AST.Pass (getSpan $1) }
-- flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
flow_stmt :: { StatementSpan }
flow_stmt
: break_stmt { $1 }
| continue_stmt { $1 }
| return_stmt { $1 }
| raise_stmt { $1 }
| yield_stmt { $1 }
-- break_stmt: 'break'
break_stmt :: { StatementSpan }
break_stmt : 'break' { AST.Break (getSpan $1) }
-- continue_stmt: 'continue'
continue_stmt :: { StatementSpan }
continue_stmt : 'continue' { AST.Continue (getSpan $1) }
-- return_stmt: 'return' [testlist]
return_stmt :: { StatementSpan }
return_stmt : 'return' optional_testlist { makeReturn $1 $2 }
-- yield_stmt: yield_expr
yield_stmt :: { StatementSpan }
yield_stmt : yield_expr { StmtExpr $1 (getSpan $1) }
-- raise_stmt: 'raise' [test ['from' test]]
raise_stmt :: { StatementSpan }
raise_stmt : 'raise' opt(pair(test, opt(right('from', test))))
{ AST.Raise (RaiseV3 $2) (spanning $1 $2) }
-- import_stmt: import_name | import_from
import_stmt :: { StatementSpan }
import_stmt: or(import_name, import_from) { $1 }
-- import_name: 'import' dotted_as_names
import_name :: { StatementSpan }
import_name : 'import' dotted_as_names { AST.Import $2 (spanning $1 $2) }
{-
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
import_from: ('from' (('.' | '...')* dotted_name | ('.' | '...')+)
'import' ('*' | '(' import_as_names ')' | import_as_names))
-}
import_from :: { StatementSpan }
import_from : 'from' import_module 'import' star_or_as_names
{ FromImport $2 $4 (spanning $1 $4) }
import_module :: { ImportRelativeSpan }
import_module: import_module_dots { makeRelative $1 }
import_module_dots :: { [Either Token DottedNameSpan] }
import_module_dots
: '.' { [ Left $1 ] }
| '...' { [ Left $1 ] }
| dotted_name { [ Right $1 ] }
| '.' import_module_dots { Left $1 : $2 }
| '...' import_module_dots { Left $1 : $2 }
star_or_as_names :: { FromItemsSpan }
star_or_as_names
: '*' { ImportEverything (getSpan $1) }
| '(' import_as_names ')' { $2 }
| import_as_names { $1 }
-- import_as_name: NAME ['as' NAME]
import_as_name :: { FromItemSpan }
import_as_name
: NAME optional_as_name { FromItem $1 $2 (spanning $1 $2) }
-- dotted_as_name: dotted_name ['as' NAME]
dotted_as_name :: { ImportItemSpan }
dotted_as_name
: dotted_name optional_as_name
{ ImportItem $1 $2 (spanning $1 $2) }
-- import_as_names: import_as_name (',' import_as_name)* [',']
import_as_names :: { FromItemsSpan }
import_as_names : sepOptEndBy(import_as_name, ',') { FromItems $1 (getSpan $1) }
-- dotted_as_names: dotted_as_name (',' dotted_as_name)*
dotted_as_names :: { [ImportItemSpan] }
dotted_as_names : sepBy(dotted_as_name,',') { $1 }
-- dotted_name: NAME ('.' NAME)*
dotted_name :: { DottedNameSpan }
dotted_name : NAME many0(right('.', NAME)) { $1 : $2 }
-- global_stmt: 'global' NAME (',' NAME)*
global_stmt :: { StatementSpan }
global_stmt : 'global' one_or_more_names { AST.Global $2 (spanning $1 $2) }
one_or_more_names :: { [IdentSpan] }
one_or_more_names: sepBy(NAME, ',') { $1 }
-- nonlocal_stmt: 'nonlocal' NAME (',' NAME)*
nonlocal_stmt :: { StatementSpan }
nonlocal_stmt : 'nonlocal' one_or_more_names { AST.NonLocal $2 (spanning $1 $2) }
-- assert_stmt: 'assert' test [',' test]
assert_stmt :: { StatementSpan }
assert_stmt : 'assert' sepBy(test,',')
{ AST.Assert $2 (spanning $1 $2) }
-- compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
compound_stmt :: { StatementSpan }
compound_stmt
: if_stmt { $1 }
| while_stmt { $1 }
| for_stmt { $1 }
| try_stmt { $1 }
| with_stmt { $1 }
| funcdef { $1 }
| classdef { $1 }
| decorated { $1 }
| async_stmt { $1 }
-- if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
if_stmt :: { StatementSpan }
if_stmt : 'if' test ':' suite many0(elif) optional_else
{ Conditional (($2, $4):$5) $6 (spanning (spanning (spanning $1 $4) $5) $6) }
elif :: { (ExprSpan, [StatementSpan]) }
elif : 'elif' test ':' suite { ($2, $4) }
optional_else :: { [StatementSpan] }
optional_else
: {- empty -} { [] }
| 'else' ':' suite { $3 }
-- while_stmt: 'while' test ':' suite ['else' ':' suite]
while_stmt :: { StatementSpan }
while_stmt
: 'while' test ':' suite optional_else
{ AST.While $2 $4 $5 (spanning (spanning $1 $4) $5) }
-- for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
for_stmt :: { StatementSpan }
for_stmt
: 'for' exprlist 'in' testlist ':' suite optional_else
{ AST.For $2 $4 $6 $7 (spanning (spanning $1 $6) $7) }
-- async_stmt: ASYNC (funcdef | with_stmt | for_stmt)
async_stmt :: { StatementSpan }
async_stmt
: 'async' funcdef { AST.AsyncFun $2 (spanning $1 $2) }
| 'async' with_stmt { AST.AsyncWith $2 (spanning $1 $2) }
| 'async' for_stmt { AST.AsyncFor $2 (spanning $1 $2) }
-- async_fundef: ASYNC funcdef
async_funcdef :: { StatementSpan }
async_funcdef
: 'async' funcdef { AST.AsyncFun $2 (spanning $1 $2) }
{-
try_stmt: ('try' ':' suite
((except_clause ':' suite)+ ['else' ':' suite] ['finally' ':' suite] | 'finally' ':' suite))
-}
try_stmt :: { StatementSpan }
try_stmt : 'try' ':' suite handlers { makeTry $1 $3 $4 }
handlers :: { ([HandlerSpan], [StatementSpan], [StatementSpan]) }
handlers
: one_or_more_except_clauses optional_else optional_finally { ($1, $2, $3) }
| 'finally' ':' suite { ([], [], $3) }
optional_finally :: { [StatementSpan] }
optional_finally
: {- empty -} { [] }
| 'finally' ':' suite { $3 }
one_or_more_except_clauses :: { [HandlerSpan] }
one_or_more_except_clauses : many1(handler) { $1 }
handler :: { HandlerSpan }
handler : except_clause ':' suite { Handler $1 $3 (spanning $1 $3) }
-- with_stmt: 'with' with_item (',' with_item)* ':' suite
with_stmt :: { StatementSpan }
with_stmt : 'with' sepOptEndBy(with_item, ',') ':' suite
{ AST.With $2 $4 (spanning $1 $4) }
-- with_item: test ['as' expr]
with_item :: { (ExprSpan, Maybe ExprSpan) }
with_item: pair(test,opt(right('as',expr))) { $1 }
-- except_clause: 'except' [test ['as' NAME]]
-- XXX is this a bug in the grammar? In the online does the target is more complex than a NAME.
-- see: http://docs.python.org/3.1/reference/compound_stmts.html#the-try-statement
except_clause :: { ExceptClauseSpan }
except_clause : 'except' opt(pair(test, optional_as_expr)) { ExceptClause $2 (spanning $1 $2) }
optional_as_expr :: { Maybe ExprSpan}
optional_as_expr: opt(right('as', test)) { $1 }
optional_as_name :: { Maybe IdentSpan }
optional_as_name: opt(right('as', NAME)) { $1 }
-- suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
-- Note: we don't have a newline before indent b/c it is redundant
suite :: { [StatementSpan] }
suite
: simple_stmt { $1 }
| {- no newline here! -} 'indent' many1(stmt) 'dedent' { concat $2 }
-- test: or_test ['if' or_test 'else' test] | lambdef
test :: { ExprSpan }
test
: or_test opt(test_if_cond) { makeConditionalExpr $1 $2 }
| lambdef { $1 }
test_if_cond :: { (ExprSpan, ExprSpan) }
test_if_cond: 'if' or_test 'else' test { ($2, $4) }
-- test_nocond: or_test | lambdef_nocond
test_no_cond :: { ExprSpan }
test_no_cond: or(or_test, lambdef_nocond) { $1 }
-- lambdef: 'lambda' [varargslist] ':' test
lambdef :: { ExprSpan }
lambdef : 'lambda' opt_varargslist ':' test { AST.Lambda $2 $4 (spanning $1 $4) }
-- lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
lambdef_nocond :: { ExprSpan }
lambdef_nocond : 'lambda' opt_varargslist ':' test_no_cond { AST.Lambda $2 $4 (spanning $1 $4) }
opt_varargslist :: { [ParameterSpan] }
opt_varargslist: opt(varargslist) { concat (maybeToList $1) }
-- or_test: and_test ('or' and_test)*
or_test :: { ExprSpan }
or_test : and_test many0(pair(or_op,and_test)) { makeBinOp $1 $2 }
or_op :: { OpSpan }
or_op: 'or' { AST.Or (getSpan $1) }
-- and_test: not_test ('and' not_test)*
and_test :: { ExprSpan }
and_test : not_test many0(pair(and_op, not_test)) { makeBinOp $1 $2 }
and_op :: { OpSpan }
and_op: 'and' { AST.And (getSpan $1) }
-- not_test: 'not' not_test | comparison
not_test :: { ExprSpan }
not_test
: 'not' not_test { UnaryOp (AST.Not (getSpan $1)) $2 (spanning $1 $2) }
| comparison { $1 }
-- comparison: expr (comp_op expr)*
comparison :: { ExprSpan }
comparison : expr many0(pair(comp_op, expr)) { makeBinOp $1 $2 }
-- comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not'
comp_op :: { OpSpan }
comp_op
: '<' { AST.LessThan (getSpan $1) }
| '>' { AST.GreaterThan (getSpan $1) }
| '==' { AST.Equality (getSpan $1) }
| '>=' { AST.GreaterThanEquals (getSpan $1) }
| '<=' { AST.LessThanEquals (getSpan $1) }
| '!=' { AST.NotEquals (getSpan $1) }
| 'in' { AST.In (getSpan $1) }
| 'not' 'in' { AST.NotIn (spanning $1 $2) }
| 'is' { AST.Is (getSpan $1) }
| 'is' 'not' { AST.IsNot (spanning $1 $2) }
-- star_expr: '*' expr
star_expr :: { ExprSpan }
star_expr : '*' expr { Starred $2 (spanning $1 $2) }
-- expr: xor_expr ('|' xor_expr)*
expr :: { ExprSpan }
expr : xor_expr many0(pair(bar_op, xor_expr)) { makeBinOp $1 $2 }
bar_op :: { OpSpan }
bar_op: '|' { AST.BinaryOr (getSpan $1) }
-- xor_expr: and_expr ('^' and_expr)*
xor_expr :: { ExprSpan }
xor_expr : and_expr many0(pair(hat_op, and_expr)) { makeBinOp $1 $2 }
hat_op :: { OpSpan }
hat_op: '^' { AST.Xor (getSpan $1) }
-- and_expr: shift_expr ('&' shift_expr)*
and_expr :: { ExprSpan }
and_expr : shift_expr many0(pair(ampersand, shift_expr)) { makeBinOp $1 $2 }
ampersand :: { OpSpan }
ampersand: '&' { AST.BinaryAnd (getSpan $1) }
-- shift_expr: arith_expr (('<<'|'>>') arith_expr)*
shift_expr :: { ExprSpan }
shift_expr: arith_expr many0(pair(shift_op, arith_expr)) { makeBinOp $1 $2 }
shift_op :: { OpSpan }
shift_op
: '<<' { AST.ShiftLeft (getSpan $1) }
| '>>' { AST.ShiftRight (getSpan $1) }
-- arith_expr: term (('+'|'-') term)*
arith_expr :: { ExprSpan }
arith_expr: term many0(pair(arith_op, term)) { makeBinOp $1 $2 }
arith_op :: { OpSpan }
arith_op
: '+' { AST.Plus (getSpan $1) }
| '-' { AST.Minus (getSpan $1) }
-- term: factor (('*'|'/'|'%'|'//') factor)*
term :: { ExprSpan }
term : factor many0(pair(mult_div_mod_op, factor)) { makeBinOp $1 $2 }
mult_div_mod_op :: { OpSpan }
mult_div_mod_op
: '*' { AST.Multiply (getSpan $1) }
| '/' { AST.Divide (getSpan $1) }
| '%' { AST.Modulo (getSpan $1) }
| '//' { AST.FloorDivide (getSpan $1) }
| '@' { AST.MatrixMult (getSpan $1) }
-- factor: ('+'|'-'|'~') factor | power
factor :: { ExprSpan }
factor
: or(arith_op, tilde_op) factor { UnaryOp $1 $2 (spanning $1 $2) }
| power { $1 }
tilde_op :: { OpSpan }
tilde_op: '~' { AST.Invert (getSpan $1) }
-- await_expr: 'await' primary
await_expr :: { ExprSpan }
await_expr : 'await' atom { AST.Await $2 (spanning $1 $2) }
-- power: atom trailer* ['**' factor]
power :: { ExprSpan }
power : or(await_expr, atom) many0(trailer) opt(pair(exponent_op, factor))
{ makeBinOp (addTrailer $1 $2) (maybeToList $3) }
exponent_op :: { OpSpan }
exponent_op: '**' { AST.Exponent (getSpan $1) }
{-
atom: ('(' [yield_expr|testlist_comp] ')' |
'[' [testlist_comp] ']' |
'{' [dictorsetmaker] '}' |
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
-}
atom :: { ExprSpan }
atom : '(' yield_or_testlist_comp ')' { $2 (spanning $1 $3) }
| list_atom { $1 }
| dict_or_set_atom { $1 }
| NAME { AST.Var $1 (getSpan $1) }
| 'integer' { AST.Int (token_integer $1) (token_literal $1) (getSpan $1) }
| 'float' { AST.Float (token_double $1) (token_literal $1) (getSpan $1) }
| 'imaginary' { AST.Imaginary (token_double $1) (token_literal $1) (getSpan $1) }
| many1('string') { AST.Strings (map token_literal $1) (getSpan $1) }
| many1('bytestring') { AST.ByteStrings (map token_literal $1) (getSpan $1) }
| many1('unicodestring') { AST.UnicodeStrings (map token_literal $1) (getSpan $1) }
| '...' { AST.Ellipsis (getSpan $1) }
| 'None' { AST.None (getSpan $1) }
| 'True' { AST.Bool Prelude.True (getSpan $1) }
| 'False' { AST.Bool Prelude.False (getSpan $1) }
list_atom :: { ExprSpan }
list_atom
: '[' ']' { List [] (spanning $1 $2) }
| '[' testlist_comp ']' { makeListForm (spanning $1 $3) $2 }
dict_or_set_atom :: { ExprSpan }
dict_or_set_atom
: '{' '}' { Dictionary [] (spanning $1 $2) }
| '{' dictorsetmaker '}' { $2 (spanning $1 $3) }
yield_or_testlist_comp :: { SrcSpan -> ExprSpan }
yield_or_testlist_comp
: {- empty -} { Tuple [] }
| yield_expr { Paren $1 }
| testlist_comp { either Paren Generator $1 }
-- testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
testlist_comp :: { Either ExprSpan ComprehensionSpan }
testlist_comp
: testlist_star_expr { Left $1 }
| or(test,star_expr) comp_for { Right (makeComprehension $1 $2) }
-- trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
trailer :: { Trailer }
trailer
: paren_arg_list { TrailerCall (fst $1) (snd $1) }
| '[' subscriptlist ']' { TrailerSubscript $2 (spanning $1 $3) }
| '.' NAME { TrailerDot $2 (getSpan $1) (spanning $1 $2) }
-- subscriptlist: subscript (',' subscript)* [',']
subscriptlist :: { [Subscript] }
subscriptlist : sepOptEndBy(subscript, ',') { $1 }
-- subscript: test | [test] ':' [test] [sliceop]
subscript :: { Subscript }
subscript
: test { SubscriptExpr $1 (getSpan $1) }
| opt(test) ':' opt(test) opt(sliceop)
{ SubscriptSlice $1 $3 $4 (spanning (spanning (spanning $1 $2) $3) $4) }
-- sliceop: ':' [test]
sliceop :: { Maybe ExprSpan }
sliceop : ':' opt(test) { $2 }
-- exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
exprlist :: { [ExprSpan] }
exprlist: sepOptEndBy(or(expr,star_expr), ',') { $1 }
opt_comma :: { Maybe Token }
opt_comma
: {- empty -} { Nothing }
| ',' { Just $1 }
-- testlist: test (',' test)* [',']
-- Some trickery here because the of the optional trailing comma, which
-- could turn a normal expression into a tuple.
-- Very occasionally, testlist is used to generate something which is not
-- a tuple (such as the square bracket notation in list literals). Therefore
-- it would seem like a good idea to not return a tuple in this case, but
-- a list of expressions. However this would complicate a lot of code
-- since we would have to carry around the optional comma information.
-- I've decided to leave it as a tuple, and in special cases, unpack the
-- tuple and pull out the list of expressions.
testlist :: { ExprSpan }
testlist : testlistrev opt_comma { makeTupleOrExpr (reverse $1) $2 }
testlistrev :: { [ExprSpan] }
testlistrev
: test { [$1] }
| testlistrev ',' test { $3 : $1 }
{-
dictorsetmaker: ( ((test ':' test | '**' expr)
(comp_for | (',' (test ':' test | '**' expr))* [','])) |
((test | star_expr)
(comp_for | (',' (test | star_expr))* [','])) )
-}
dictorsetmaker :: { SrcSpan -> ExprSpan }
dictorsetmaker
: test ':' test dict_rest { makeDictionary (Left ($1, $3)) $4 }
| '**' expr dict_rest { makeDictionary (Right $2) $3 }
| test set_rest { makeSet $1 $2 }
dict_rest :: { Either CompForSpan [Either (ExprSpan, ExprSpan) ExprSpan] }
dict_rest
: comp_for { Left $1 }
| zero_or_more_dict_mappings_rev opt_comma { Right (reverse $1) }
zero_or_more_dict_mappings_rev :: { [Either (ExprSpan, ExprSpan) ExprSpan] }
zero_or_more_dict_mappings_rev
: {- empty -} { [] }
| zero_or_more_dict_mappings_rev ',' test ':' test { Left ($3,$5) : $1 }
| zero_or_more_dict_mappings_rev ',' '**' expr { Right $4 : $1 }
set_rest :: { Either CompForSpan [ExprSpan] }
set_rest
: comp_for { Left $1 }
| zero_or_more_comma_test_rev opt_comma { Right (reverse $1) }
zero_or_more_comma_test_rev :: { [ExprSpan] }
zero_or_more_comma_test_rev
: {- empty -} { [] }
| zero_or_more_comma_test_rev ',' test { $3 : $1 }
-- classdef: 'class' NAME ['(' [arglist] ')'] ':' suite
classdef :: { StatementSpan }
-- classdef: 'class' NAME optional_arg_list ':' suite
classdef: 'class' NAME opt_paren_arg_list ':' suite
{ AST.Class $2 $3 $5 (spanning $1 $5) }
optional_arg_list :: { [ArgumentSpan] }
optional_arg_list: opt(arglist) { concat (maybeToList $1) }
{-
arglist: (argument ',')* (argument [',']
|'*' test (',' argument)* [',' '**' test]
|'**' test)
-}
{-
We don't follow the grammar rules directly (though we do implement
something equivalent). The reason is that there is ambiguity over
the optional comma.
It is probably okay to allow the optional comma even after the *, and
** forms. It seems more consistent to me.
-}
arglist :: { [ArgumentSpan] }
arglist: sepOptEndBy(oneArgument,',') {% checkArguments $1 }
oneArgument
: '*' test { ArgVarArgsPos $2 (spanning $1 $2) }
| '**' test { ArgVarArgsKeyword $2 (spanning $1 $2) }
| argument { $1 }
-- argument: test [comp_for] | test '=' test # Really [keyword '='] test
argument :: { ArgumentSpan }
argument
: NAME '=' test { ArgKeyword $1 $3 (spanning $1 $3) }
| test { ArgExpr $1 (getSpan $1) }
| test comp_for
{ let span = spanning $1 $1 in ArgExpr (Generator (makeComprehension $1 $2) span) span }
-- comp_iter: comp_for | comp_if
comp_iter :: { CompIterSpan }
comp_iter
: comp_for { IterFor $1 (getSpan $1) }
| comp_if { IterIf $1 (getSpan $1) }
-- comp_for: 'for' exprlist 'in' or_test [comp_iter]
comp_for :: { CompForSpan }
comp_for
: opt('async') 'for' exprlist 'in' or_test opt(comp_iter)
{ CompFor (isJust $1) $3 $5 $6 (spanning $1 (spanning (spanning $2 $5) $6)) }
-- comp_if: 'if' test_nocond [comp_iter]
comp_if :: { CompIfSpan }
comp_if
: 'if' test_no_cond opt(comp_iter)
{ CompIf $2 $3 (spanning (spanning $1 $2) $3) }
-- encoding_decl: NAME
-- Not used in the rest of the grammar!
-- yield_expr: 'yield' [yield_arg]
yield_expr :: { ExprSpan }
yield_expr : 'yield' optional_yieldarg { AST.Yield $2 (spanning $1 $2) }
optional_testlist :: { Maybe ExprSpan }
optional_testlist: opt(testlist) { $1 }
optional_yieldarg :: { Maybe YieldArgSpan }
optional_yieldarg: opt(yieldarg) { $1 }
-- yield_arg: 'from' test | testlist
yieldarg :: { YieldArgSpan }
yieldarg
: 'from' test { YieldFrom $2 (spanning $1 $2) }
| testlist { YieldExpr $1 }
{
-- Put additional Haskell code in here if needed.
}