Started work on keyword arguments.

pull/15/head
Jussi Pakkanen 12 years ago
parent da2e9f6688
commit 45ecded01d
  1. 19
      bparser.py
  2. 43
      interpreter.py
  3. 17
      nodes.py
  4. 6
      test cases/1 trivial/builder.txt

@ -42,6 +42,7 @@ tokens = ['LPAREN',
'INT', 'INT',
'EOL_CONTINUE', 'EOL_CONTINUE',
'EOL', 'EOL',
'COLON',
] + list(reserved.values()) ] + list(reserved.values())
t_ASSIGN = '=' t_ASSIGN = '='
@ -56,6 +57,7 @@ t_RBRACE = '\}'
t_COMMENT = '\#[^\n]*' t_COMMENT = '\#[^\n]*'
t_COMMA = ',' t_COMMA = ','
t_DOT = '\.' t_DOT = '\.'
t_COLON = ':'
t_ignore = ' \t' t_ignore = ' \t'
@ -162,19 +164,32 @@ def p_statement_expression(t):
'statement : expression' 'statement : expression'
t[0] = nodes.statement_from_expression(t[1]) t[0] = nodes.statement_from_expression(t[1])
def p_args_multiple(t): def p_args_multiple(t):
'args : statement COMMA args' 'args : statement COMMA args'
args = t[3] args = t[3]
args.prepend(t[1]) args.prepend(t[1])
t[0] = args t[0] = args
def p_args_single(t): def p_kwargs_multiple(t):
'args : expression COLON statement COMMA args'
args = t[5]
args.add_kwarg(t[1], t[3])
t[0] = args
def p_args_single_pos(t):
'args : statement' 'args : statement'
args = nodes.Arguments(t.lineno(1)) args = nodes.Arguments(t.lineno(1))
args.prepend(t[1]) args.prepend(t[1])
t[0] = args t[0] = args
def p_args_none(t): def p_args_single_kw(t):
'args : expression COLON statement'
a = nodes.Arguments(t.lineno(1))
a.set_kwarg(t[1], t[2])
t[0] = a
def p_posargs_none(t):
'args :' 'args :'
t[0] = nodes.Arguments(t.lineno(0)) t[0] = nodes.Arguments(t.lineno(0))

@ -465,7 +465,7 @@ class Interpreter():
t = Test(args[0], args[1]) t = Test(args[0], args[1])
self.build.tests.append(t) self.build.tests.append(t)
print('Adding test "%s"' % args[0]) print('Adding test "%s"' % args[0])
def func_headers(self, node, args): def func_headers(self, node, args):
for a in args: for a in args:
if not isinstance(a, str): if not isinstance(a, str):
@ -534,6 +534,8 @@ class Interpreter():
for a in args: for a in args:
if isinstance(a, list): if isinstance(a, list):
result = result + self.flatten(a) result = result + self.flatten(a)
if isinstance(a, nodes.StringStatement):
result.append(a.get_value())
else: else:
result.append(a) result.append(a)
return result return result
@ -559,9 +561,9 @@ class Interpreter():
def function_call(self, node): def function_call(self, node):
func_name = node.get_function_name() func_name = node.get_function_name()
args = self.reduce_arguments(node.arguments) (posargs, kwargs) = self.reduce_arguments(node.arguments)
if func_name in self.funcs: if func_name in self.funcs:
return self.funcs[func_name](node, args) return self.funcs[func_name](node, posargs)
else: else:
raise InvalidCode('Unknown function "%s".' % func_name) raise InvalidCode('Unknown function "%s".' % func_name)
@ -587,24 +589,27 @@ class Interpreter():
raise InvalidCode('Line %d: Tried to assign an invalid value to variable.' % node.lineno()) raise InvalidCode('Line %d: Tried to assign an invalid value to variable.' % node.lineno())
self.set_variable(var_name, value) self.set_variable(var_name, value)
return value return value
def reduce_single(self, arg):
if isinstance(arg, nodes.AtomExpression) or isinstance(arg, nodes.AtomStatement):
return self.get_variable(arg.value)
elif isinstance(arg, nodes.StringExpression) or isinstance(arg, nodes.StringStatement):
return arg.get_value()
elif isinstance(arg, nodes.FunctionCall):
return self.function_call(arg)
elif isinstance(arg, nodes.MethodCall):
return self.method_call(arg)
else:
raise InvalidCode('Line %d: Irreducible argument.' % args.lineno())
def reduce_arguments(self, args): def reduce_arguments(self, args):
assert(isinstance(args, nodes.Arguments)) assert(isinstance(args, nodes.Arguments))
reduced = [] reduced_pos = [self.reduce_single(arg) for arg in args.arguments]
for arg in args.arguments: for key in args.kwargs.keys():
if isinstance(arg, nodes.AtomExpression) or isinstance(arg, nodes.AtomStatement): if not isinstance(key, str):
r = self.get_variable(arg.value) raise InvalidArguments('Line %d: keyword argument name is not a string.' % args.lineno())
elif isinstance(arg, nodes.StringExpression) or isinstance(arg, nodes.StringStatement): reduced_kw = {}
r = arg.get_value() return (reduced_pos, reduced_kw)
elif isinstance(arg, nodes.FunctionCall):
r = self.function_call(arg)
elif isinstance(arg, nodes.MethodCall):
r = self.method_call(arg)
else:
raise InvalidCode('Line %d: Irreducible argument.' % args.lineno())
reduced.append(r)
assert(len(reduced) == len(args))
return reduced
def method_call(self, node): def method_call(self, node):
object_name = node.object_name.get_value() object_name = node.object_name.get_value()

@ -170,13 +170,26 @@ class Arguments(Statement):
def __init__(self, lineno): def __init__(self, lineno):
Statement.__init__(self, lineno) Statement.__init__(self, lineno)
self.arguments = [] self.arguments = []
self.kwargs = {}
self.order_error = False
def prepend(self, statement): def prepend(self, statement):
self.arguments = [statement] + self.arguments self.arguments = [statement] + self.arguments
def __len__(self): def set_kwarg(self, name, value):
if self.num_args() > 0:
self.order_error = True
self.kwargs[name.get_value()] = value
def num_args(self):
return len(self.arguments) return len(self.arguments)
def num_kwargs(self):
return len(self.kwargs)
def __len__(self):
return self.num_args() # Fixme
def statement_from_expression(expr): def statement_from_expression(expr):
if isinstance(expr, AtomExpression): if isinstance(expr, AtomExpression):
return AtomStatement(expr.value, expr.lineno()) return AtomStatement(expr.value, expr.lineno())

@ -1,3 +1,7 @@
project('trivial test', 'c') project('trivial test', 'c')
exe = executable('trivialprog', 'trivial.c')
sources = 'trivial.c'
exe = executable('trivialprog', sources : sources)
add_test('runtest', exe) add_test('runtest', exe)

Loading…
Cancel
Save