hi, attached a patch for languages/Pynie, adding:
* more grammar rules * statement.t for testing statements -- kinda simple, should be extended * keyword rule, so that id's are not recognized as identifiers regards, kjs
Index: languages/pynie/src/parser/Grammar.pg =================================================================== --- languages/pynie/src/parser/Grammar.pg (revision 17174) +++ languages/pynie/src/parser/Grammar.pg (working copy) @@ -37,6 +37,11 @@ token compound_stmt { | <if_stmt> | <while_stmt> + | <for_stmt> + | <try_stmt> + | <with_stmt> + | <funcdef> + | <classdef> } rule if_stmt { @@ -50,25 +55,174 @@ [ <'else'> <':'> <suite> ]? } +rule for_stmt { + <'for'> <target_list> <'in'> <expression_list> <':'> <suite> + [ <'else'> <':'> <suite> ]? +} + +rule try_stmt { + <try1_stmt> | <try2_stmt> +} + +rule try1_stmt { + <'try'> <':'> <suite> + [ <'except'> [ <expression> [ <','> <target> ]? ]? <':'> <suite> ]+ + [ <'else'> <':'> <suite> ]? + [ <'finally'> <':'> <suite> ]? +} + +rule try2_stmt { + <'try'> <':'> <suite> + <'finally'> <':'> <suite> +} + +rule with_stmt { + <'with'> <expression> [ <'as'> <target> ]? <':'> <suite> +} + +rule funcdef { + <decorators>? <'def'> <funcname> <'('> <parameter_list>? <')'> + [ <':'> | <?die: ':' expected> ] <suite> +} + + +rule decorators { + <decorator>+ +} + +rule decorator { + <'@'> <dotted_name> [ <'('> [ <argument_list> <','>? ]? <')'> ]? <?newline> +} + +rule dotted_name { + <identifier> [ <'.'> <identifier> ]* +} + +rule funcname { + <identifier> +} + +rule parameter_list { + [ <defparameter> <','> ]* + [ + <'*'> <identifier> [ <','> <'**'> <identifier> ]? + | <'**'> <identifier> + | <defparameter> <','>? + ] +} + +rule defparameter { + <parameter> [ <'='> <expression> ]? +} + +rule sublist { + <parameter> [ <','> <parameter> ]* <','>? +} + +rule parameter { + <identifier> | <'('> <sublist> <')'> +} + + +rule classdef { + <'class'> <classname> <inheritance>? <':'> <suite> +} + +rule classname { + <identifier> +} + +rule inheritance { + <'('> <expression_list> <')'> +} + token simple_stmt { + | <assert_stmt> + | <assignment_stmt> + | <augmented_assignment_stmt> + | <pass_stmt> + | <del_stmt> | <print_stmt> - | <assignment_stmt> + | <return_stmt> + | <yield_stmt> + | <raise_stmt> + | <break_stmt> + | <continue_stmt> + | <import_stmt> + | <global_stmt> | <expression> } +rule assert_stmt { + <'assert'> <expression> [ <','> <expression> ]? +} + rule assignment_stmt { [ <target_list> <'='> ]+ <expression_list> } +rule augmented_assignment_stmt { <target> <augop> <expression_list> } + rule target_list { <target> [ <','> <target> ]* (<','>)? } token target { <identifier> } -token identifier { [ <?alpha> | <'_'> ] \w* } +token identifier { <!reserved> [ <?alpha> | <'_'> ] \w* } +token name { <!reserved> <[a..z]> [ <alpha> | <'_'> ]* } + rule print_stmt { <'print'> [ <expression> [ <','> <expression> ]* (<','>?) ]? } +rule pass_stmt { + <'pass'> +} +rule del_stmt { + <'del'> <target_list> +} + +rule return_stmt { + <'return'> <expression_list>? +} + +rule yield_stmt { + <'yield'> <expression_list> +} + +rule break_stmt { + <'break'> +} + +rule continue_stmt { + <'continue'> +} + +rule raise_stmt { + <'raise'> [ <expression> [ <','> <expression> [ <','> <expression> ]? ]? ]? +} + +rule global_stmt { + <'global'> <identifier> [ <','> <identifier> ]* +} + +rule import_stmt { + | <'import'> <module> <import_alias>? + [ <','> <module> <import_alias>? ]* + | <'from'> <module> <'import'> <identifier> <import_alias>? + [ <','> <identifier> <import_alias>? ]* + | <'from'> <module> <'import'> <'('> <identifier> <import_alias>? + [ <','> <identifier> <import_alias>? ]* <','>? <')'> + | <'from'> <module> <'import'> <'*'> +} + +rule import_alias { + <'as'> <name> +} + +rule module { + [ <identifier> <'.'> ]* <identifier> +} + token literal { | <stringliteral> | <integer> @@ -93,6 +247,9 @@ rule listmaker { <expression> [ <','> <expression> ]* (<','>)? } +token augop { + <'+='> | <'-='> | <'*='> | <'/='> | <'\%='> | <'**='> +} ## This identifies operators for the bottom-up parser @@ -137,4 +294,19 @@ proto 'infix:<' is equiv('infix:==') { ... } proto 'infix:>' is equiv('infix:==') { ... } + +## Python reserved words and keywords + +token reserved { + <keyword> | <'None'> +} + +token keyword { + [ <'and'> | <'assert'> | <'break'> | <'class'> | <'continue'> | <'def'> + | <'del'> | <'elif'> | <'else'> | <'except'> | <'exec'> | <'finally'> + | <'for'> | <'from'> | <'global'> | <'if'> | <'import'> | <'in'> + | <'is'> | <'lambda'> | <'not'> | <'or'> | <'pass'> | <'print'> + | <'raise'> | <'return'> | <'try'> | <'while'> | <'with'> | <'yield'> ] \b +} + ## vim: expandtab sw=4 Index: languages/pynie/src/PAST/Grammar.tg =================================================================== --- languages/pynie/src/PAST/Grammar.tg (revision 17174) +++ languages/pynie/src/PAST/Grammar.tg (working copy) @@ -28,12 +28,33 @@ compound_stmt: $P0 = node['compound_stmt'] + if_stmt: $P1 = $P0['if_stmt'] if null $P1 goto while_stmt .return tree.'get'('past', $P1, 'Pynie::Grammar::if_stmt') while_stmt: $P1 = $P0['while_stmt'] + if null $P1 goto for_stmt .return tree.'get'('past', $P1, 'Pynie::Grammar::while_stmt') + for_stmt: + $P1 = $P0['for_stmt'] + if null $P1 goto try_stmt + .return tree.'get'('past', $P1, 'Pynie::Grammar::for_stmt') + try_stmt: + $P1 = $P0['try_stmt'] + if null $P1 goto with_stmt + .return tree.'get'('past', $P1, 'Pynie::Grammar::try_stmt') + with_stmt: + $P1 = $P0['with_stmt'] + if null $P1 goto funcdef + .return tree.'get'('past', $P1, 'Pynie::Grammar::with_stmt') + funcdef: + $P1 = $P0['funcdef'] + if null $P1 goto classdef + .return tree.'get'('past', $P1, 'Pynie::Grammar::funcdef') + classdef: + $P1 = $P0['classdef'] + .return tree.'get'('past', $P1, 'Pynie::Grammar::classdef') } @@ -68,7 +89,98 @@ .return tree.'get'('past', cnode, key) } +transform past (Pynie::Grammar::assert_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' +## From http://docs.python.org/ref/assert.html +## The simple form, "assert expression", is equivalent to +## +##if __debug__: +## if not expression: raise AssertionError +## +##The extended form, "assert expression1, expression2", is equivalent to +## +##if __debug__: +## if not expression1: raise AssertionError, expression2 +## + #past.'init'('node'=>node, 'pasttype'=>'if') + #$P0 = node['expression'] + + + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# assert_stmt not implemented') + .return (past) + +} + +transform past (Pynie::Grammar::augmented_assignment_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# augmented assignment stmt not implemented') + .return (past) +} + +transform past (Pynie::Grammar::del_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# del stmt not implemented') + .return (past) +} + +# Handle "pass" statement; only emit a comment +# Alternative would be to _not_ create a PAST node, but then +# extra logic would be necessary in both stmt_list() and simple_stmt(). +# +transform past (Pynie::Grammar::pass_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# pass') + .return (past) +} + +transform past (Pynie::Grammar::return_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'return') + $P0 = node['expression_list'] + +## FIX: +## Returning something does not work; 'method 'from' not found... + if null $P0 goto skip_expression_list + .local pmc expr_list_past + expr_list_past = tree.'get'('past', $P0, 'Pynie::Grammar::expression_list') + past.'push'(expr_list_past) + skip_expression_list: + .return (past) +} + +## FIX: +## generated code is nonsense for yield_stmt +transform past (Pynie::Grammar::yield_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'yield') + $P0 = node['expression_list'] + .local pmc expr_list_past + expr_list_past = tree.'get'('past', $P0, 'Pynie::Grammar::expression_list') + past.'push'(expr_list_past) + .return (past) +} + +transform past (Pynie::Grammar::break_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# break not implemented') + .return (past) +} + +transform past (Pynie::Grammar::continue_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# continue not implemented') + .return (past) +} + transform past (Pynie::Grammar::print_stmt) :language('PIR') { .local pmc past past = new 'PAST::Op' @@ -94,7 +206,29 @@ .return (past) } +transform past (Pynie::Grammar::import_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# import stmt not implemented') + .return (past) +} +transform past (Pynie::Grammar::raise_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# raise stmt not implemented') + .return (past) +} + +transform past (Pynie::Grammar::global_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# global stmt not implemented') + .return (past) +} + + + transform past (Pynie::Grammar::expression) :language('PIR') { $P0 = node['expr'] .return tree.'get'('past', $P0, 'Pynie::Grammar::expr') @@ -297,23 +431,170 @@ transform past (Pynie::Grammar::while_stmt) :language('PIR') { - .local pmc exprnode, stmtnode - exprnode = node['expression'] - stmtnode = node['suite'] - stmtnode = stmtnode[0] + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# while stmt not implemented') + .return (past) - .local pmc past, exprpast, stmtpast + # .local pmc exprnode, stmtnode + # exprnode = node['expression'] + # stmtnode = node['suite'] + # stmtnode = stmtnode[0] + # + # .local pmc past, exprpast, stmtpast + # past = new 'PAST::Op' + # past.'init'('node'=>node, 'pasttype'=>'while') + # exprpast = tree.'get'('past', exprnode, 'Pynie::Grammar::expression') + # past.'push'(exprpast) + # stmtpast = tree.'get'('past', stmtnode, 'Pynie::Grammar::suite') + # past.'push'(stmtpast) + # .return (past) +} + +## FIX: complete this +transform past (Pynie::Grammar::for_stmt) :language('PIR') { + + .local pmc past past = new 'PAST::Op' - past.'init'('node'=>node, 'pasttype'=>'while') - exprpast = tree.'get'('past', exprnode, 'Pynie::Grammar::expression') - past.'push'(exprpast) - stmtpast = tree.'get'('past', stmtnode, 'Pynie::Grammar::suite') - past.'push'(stmtpast) + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# for stmt not implemented') .return (past) + +# .local pmc tlistnode, elistnode, suitenode +# tlistnode = node['target_list'] +# elistnode = node['expression_list'] +# suitenode = node['suite'] +# +# .local pmc past, tlistpast, elistpast, suitepast +# past = new 'PAST::Op' +# past.'init'('node'=>node, 'pasttype'=>'while') +# +# tlistpast = tree.'get'('past', tlistnode, 'Pynie::Grammar::target_list') +# #past.'push'(tlistpast) +# +# elistpast = tree.'get'('past', elistnode, 'Pynie::Grammar::expression_list') +# past.'push'(elistpast) +# +# suitepast = tree.'get'('past', suitenode, 'Pynie::Grammar::suite') +# past.'push'(suitepast) +# +# .return (past) } +transform past (Pynie::Grammar::try_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# try stmt not implemented') + .return (past) +} +transform past (Pynie::Grammar::with_stmt) :language('PIR') { + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# with stmt not implemented') + .return (past) +} +transform past (Pynie::Grammar::funcdef) :language('PIR') { + + .local pmc past + past = new 'PAST::Block' + + .local pmc decnode, fnamenode, plistnode, suitenode +# decnode = node['decorators'] + fnamenode = node['funcname'] +# plistnode = node['parameter_list'] +# suitenode = node['suite'] +# +# .local pmc past +# past = new 'PAST::Block' +# +# if null decnode goto skip_decorators +# # handle decorators +# printerr "Function decorators not implemented!\n" +# exit 1 +# +# skip_decorators: + .local pmc fnamepast + fnamepast = tree.'get'('past', fnamenode, 'Pynie::Grammar::funcname') +# +# if null plistnode goto skip_parameter_list +# #.local plistpast +# #plistpast = tree.'get'('past', plistnode, 'Pynie::Grammar::parameter_list') +# printerr "Parameters not implemented!\n" +# exit 1 +# +# skip_parameter_list: +# .local pmc stmtpast +# stmtpast = tree.'get'('past', suitenode, 'Pynie::Grammar::suite') +# +# # FIX +# past.'init'('node'=>node, 'name'=>fnamepast) +# .local pmc past +# + past.'init'('node'=>node, 'name'=>fnamepast) + .return (past) +} + +transform past (Pynie::Grammar::funcname) :language('PIR') { + $P0 = node['identifier'] + .return tree.'get'('past', $P0, 'Pynie::Grammar::identifier') +} + + +## FIX: fix this, not sure about how to handle instructions such +## as subclass etc. +## +transform past (Pynie::Grammar::classdef) :language('PIR') { + + .local pmc past + past = new 'PAST::Op' + past.'init'('node'=>node, 'pasttype'=>'inline', 'inline'=>'# classdef stmt not implemented') + .return (past) + +# .local pmc past +# past = new 'PAST::Stmts' +# past.'init'('node'=>node) +# +# .local pmc instr +# instr = new 'PAST::Op' +# +# $P0 = node['inheritance'] +# if null $P0 goto skip_inheritance +# instr.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'subclass') +# # inheritancenot implemented right now +# goto handle_class_body +# +# skip_inheritance: +# instr.'init'('node'=>node, 'pasttype'=>'pirop', 'pirop'=>'newclass') +# $P0 = node['classname'] +# $P1 = tree.'get'('past', $P0, 'Pynie::Grammar::classname') +# instr.'push'($P1) +# +# handle_class_body: +# # add newclass or subclass instruction to Stmts node +# past.'push'(instr) +# +# # add a .namespace[ <class_id> ] instruction to add methods? +# $P0 = node['suite'] +# $P1 = tree.'get'('past', $P0, 'Pynie::Grammar::suite') +# past.'push'($P1) +# +# +# done: +# .return (past) +} + +## FIX: Return class name as a string, not using "get_global" as in identifier. +transform past (Pynie::Grammar::classname) :language('PIR') { + $P0 = node['identifier'] + .return tree.'get'('past', $P0, 'Pynie::Grammar::identifier') +} + +transform past (Pynie::Grammar::inheritance) :language('PIR') { + $P0 = node['expression_list'] + .return tree.'get'('past', $P0, 'Pynie::Grammar::expression_list') +} + transform past (Pynie::Grammar::suite) :language('PIR') { $P0 = node['stmt_list'] if null $P0 goto statements Index: languages/pynie/t/00-parrot/03-statement.t =================================================================== --- languages/pynie/t/00-parrot/03-statement.t (revision 0) +++ languages/pynie/t/00-parrot/03-statement.t (revision 0) @@ -0,0 +1,68 @@ + +print '1..12' + +while 1: + pass + +print 'ok 1\n' + +for x in 1: + pass + +print 'ok 2\n' + +class X: + pass + +print 'ok 3\n' + + +def foo ( ) : + pass + + +print 'ok 4\n' + + +with x as y: + pass + +print 'ok 5\n' + +del a, b, c + +print 'ok 6\n' + +raise 1 + +print 'ok 7\n' + +break + +print 'ok 8\n' + +continue + +print 'ok 9\n' + +global X, Y, Z + +print 'ok 10\n' + +import t as x + +print 'ok 11\n' + +from x import y + +import f + +from e import d + +from e import x as f + +from e import (a, b, c) + +from r import * + +print 'ok 12\n'