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'