
import ast
import rply

lg = rply.LexerGenerator()

lg.add('NUMBER', '\d+')
lg.add('STRING', "'.*?'|\".*?\"")
lg.add('NAME', '\w+')
lg.add('LSQB', '\[')
lg.add('RSQB', '\]')
lg.add('LPAREN', '\(')
lg.add('RPAREN', '\)')
lg.add('EQUALS', '=')
lg.add('COMMA', ',')
lg.add('DOT', '\.')


pg = rply.ParserGenerator(
    [rule.name for rule in lg.rules],
    precedence = [
    ],
)

'''

kwarg   :   NAME EQUALS expr

arg     :   expr

arg_list    :   arg
            |   arg COMMA arg_list

expr    :   NAME
        :   NUMBER
        :   STRING
        :   expr DOT NAME
        :   expr LSQB expr RSQB
        :   expr LPAREN RPAREN
        :   expr LPAREN arg_list RPAREN
        :   expr LPAREN kwarg_list RPAREN
        :   expr LPAREN arg_list COMMA kwarg_list RPAREN
'''

@pg.production('arg : expr')
def arg_expr(p):
    return p[0]

@pg.production('arg_list : arg')
def arg_list_arg(p):
    return p

@pg.production('arg_list : arg COMMA arg_list')
def arg_list_prepend(p):
    arg, _, arg_list = p
    arg_list.insert(0, arg)
    return arg_list

@pg.production('expr : NAME')
def expr_NAME(p):
    '''Look up a NAME in Context'''
    return ast.Subscript(
        value=ast.Name(id='context', ctx=ast.Load()),
        slice=ast.Index(value=ast.Str(s=p[0].getstr()), ctx=ast.Load()),
        ctx=ast.Load(),
    )

@pg.production('expr : STRING')
def expr_STRING(p):
    return ast.Str(s=p[0].getstr()[1:-1])

@pg.production('expr : NUMBER')
def expr_NUMBER(p):
    return ast.Number(n=int(p[0].getstr()))

@pg.production('expr : expr DOT NAME')
def expr_DOT_NAME(p):
    lterm, _, rterm = p
    return ast.Attribute(
        value=lterm,
        attr=rterm.getstr(),
        ctx=ast.Load(),
    )

@pg.production('expr : expr LSQB expr RSQB')
def expr_SUBSCRIPT(p):
    src, _, subscript, _ = p
    return ast.Subscript(
        value=src,
        slice=ast.Index(value=subscript, ctx=ast.Load()),
        ctx=ast.Load(),
    )

@pg.production('expr : expr LPAREN RPAREN')
def expr_empty_call(p):
    func, _, _ = p
    return ast.Call(
        func=func,
        args=[],
        keywords=[],
    )

@pg.production('expr : expr LPAREN arg_list RPAREN')
def expr_args_cll(p):
    func, _, args, _ = p
    print "CALL: %r" % p
    return ast.Call(
        func=func,
        args=args,
        keywords=[],
    )

@pg.error
def error(token):
    raise ValueError('Unexpected token: %r' % token)

@@ -408,16 +408,78 @@
 S expr%0A%0A
+kwarwg_list :   kwarg%0A            %7C   kwarg COMMA kwarg_list%0A%0A
 arg     
@@ -832,16 +832,393 @@
 EN%0A'''%0A%0A
+@pg.production('kwarg : NAME EQUALS expr')%0Adef keyword(p):%0A    name, _, expr = p%0A    return ask.keyword(arg=name.getstr(), value=expr)%0A%0A@pg.production('kwarg_list : kwarg')%0Adef kwarg_list_kwarg(p):%0A    return p%0A%0A@pg.production('kwarg_list : kwarg COMMA kwarg_list')%0Adef kwarg_list_prepend(p):%0A    kwarg, _, kwarg_list = p%0A    kwarg_list.insert(0, kwarg)%0A    return kwarg_list%0A%0A
 @pg.prod
@@ -2374,177 +2374,392 @@
  )%0A%0A
-@pg.production('expr : expr LPAREN RPAREN')%0Adef expr_empty_call(p):%0A    func, _, _ = p%0A    return ast.Call(%0A        func=func,%0A        args=%5B%5D,%0A        keywords=%5B%5D,%0A    
+def _build_call(func, args=%5B%5D, kwargs=%5B%5D):%0A    return ast.Call(%0A        func=func,%0A        args=args,%0A        keywords=kwargs,%0A%0A    )%0A@pg.production('expr : expr LPAREN RPAREN')%0Adef expr_empty_call(p):%0A    func, _, _ = p%0A    return _build_call(func)%0A%0A@pg.production('expr : expr LPAREN arg_list RPAREN')%0Adef expr_args_cll(p):%0A    func, _, args, _ = p%0A    return _build_call(func, args
 )%0A%0A@
@@ -2784,32 +2784,34 @@
 r : expr LPAREN 
+kw
 arg_list RPAREN'
@@ -2813,38 +2813,41 @@
 AREN')%0Adef expr_
+kw
 args_c
+a
 ll(p):%0A    func,
@@ -2842,32 +2842,34 @@
 ):%0A    func, _, 
+kw
 args, _ = p%0A    
@@ -2872,113 +2872,219 @@
     
-print %22CALL: %25r%22 %25 p%0A    return ast.Call(%0A        func=func,%0A        args=args,%0A        keywords=%5B%5D,%0A    
+return _build_call(func, kwargs=kwargs)%0A%0A@pg.production('expr : expr LPAREN arg_list COMMA kwarg_list RPAREN')%0Adef expr_full_call(p):%0A    func, _, args, _, kwargs, _ = p%0A    return _build_call(func, args, kwargs
 )%0A%0A@

Add kwarg support