def test_assignment_complex(self): parser = Parser() tree = parser.run("x = y = 3") self.assertEqual(tree.op, Token(lexems.ASSIGNMENT, lexems.ASSIGNMENT)) self.assertEqual(tree.right.op, Token(lexems.ASSIGNMENT, lexems.ASSIGNMENT)) self.assertEqual(tree.left.val, Token(lexems.LETTER, 'x'))
def test_fn_def_add(self): parser = Parser() tree = parser.run("fn add x y => x + z") self.assertEqual(Token(lexems.LETTER, "add"), tree.name) self.assertEqual( [Token(lexems.LETTER, "x"), Token(lexems.LETTER, "y")], tree.arguments) self.assertEqual(Token(lexems.PLUS, lexems.PLUS), tree.definition.op)
def test_fn_def(self): parser = Parser() tree = parser.run("fn avg x y => (x + y) / 2") self.assertEqual(Token(lexems.LETTER, "avg"), tree.name) self.assertEqual( [Token(lexems.LETTER, "x"), Token(lexems.LETTER, "y")], tree.arguments) self.assertEqual(Token(lexems.DIVIDE, lexems.DIVIDE), tree.definition.op)
def test_fn_def_echo_call_no_def(self): parser = Parser() tree = parser.run("fn echo x => x") self.assertEqual(Token(lexems.LETTER, "echo"), tree.name) self.assertEqual([Token(lexems.LETTER, "x")], tree.arguments) self.assertEqual(Token(lexems.LETTER, "x"), tree.definition.val) with self.assertRaises(Exception) as context: tree = parser.run("echo1 11")
def test_adding(self): parser = Parser() tree = parser.run("1 + 7") self.assertEqual(tree.op, Token(lexems.PLUS, lexems.PLUS)) self.assertEqual(tree.left.val, Token(lexems.DIGIT, 1)) self.assertEqual(tree.right.val, Token(lexems.DIGIT, 7))
def test_fn_def_echo(self): parser = Parser() tree = parser.run("fn echo x => x") self.assertEqual(Token(lexems.LETTER, "echo"), tree.name) self.assertEqual([Token(lexems.LETTER, "x")], tree.arguments) self.assertEqual(Token(lexems.LETTER, "x"), tree.definition.val)
def test_bad_fn_def(self): parser = Parser() tree = parser.run("fn avg => (x + y) / 2") self.assertEqual(Token(lexems.LETTER, "avg"), tree.name)
def test_brackets(self): parser = Parser() tree = parser.run("(1 + 7) * 5") self.assertEqual(tree.op, Token(lexems.MULTIPLY, lexems.MULTIPLY)) self.assertEqual(tree.right.val, Token(lexems.DIGIT, 5.0))
def test_multiply(self): parser = Parser() tree = parser.run("1 + 7 * 5") self.assertEqual(tree.op, Token(lexems.PLUS, lexems.PLUS)) self.assertEqual(tree.left.val, Token(lexems.DIGIT, 1.0))
def test_fn_def_echo_call_no_args(self): parser = Parser() tree = parser.run("fn echo => 2") self.assertEqual(Token(lexems.LETTER, "echo"), tree.name)
def __init__(self): self.parser = Parser() self.variables = {} self.functions = {}
class Interpreter(NodeVisitor): def __init__(self): self.parser = Parser() self.variables = {} self.functions = {} def input(self, line): self.parser.clear() tree = self.parser.run(line) return self.visit(tree, None) def visit_BinaryNode(self, node, var_values, check): if check: self.visit(node.left, var_values, check) self.visit(node.right, var_values, check) return None if node.op.type == PLUS: return self.visit(node.left, var_values) + self.visit( node.right, var_values) elif node.op.type == MINUS: return self.visit(node.left, var_values) - self.visit( node.right, var_values) elif node.op.type == MULTIPLY: return self.visit(node.left, var_values) * self.visit( node.right, var_values) elif node.op.type == DIVIDE: return self.visit(node.left, var_values) / self.visit( node.right, var_values) elif node.op.type == PERCENT: return self.visit(node.left, var_values) % self.visit( node.right, var_values) elif node.op.type == ASSIGNMENT: left = self.visit(node.left, var_values) val = self.visit(node.right, var_values) self.variables[left] = val return val def visit_LiteralNode(self, node, var_values, check): if node.val.type == LETTER: vardict = self.variables if var_values != None: vardict = var_values if node.val.value not in vardict: raise Exception("Undefined variable {}".format(node.val.value)) return vardict[node.val.value] if check: return None if node.val.type == EOF: return node.val.value return node.val.value def visit_VariableDefinitionNode(self, node, var_values, check): if node.val.value in self.functions: raise Exception("Already defined variable {}".format( node.name.value)) return node.val.value def visit_FunctionDefinitionNode(self, node, var_values, check): if node.name.value in self.variables: raise Exception("Already defined variable {}".format( node.name.value)) self.functions[node.name.value] = node # calc parameters local_varvalues = {} for (i, argnode) in enumerate(node.arguments): local_varvalues[argnode.value] = None if len(local_varvalues) != len(node.arguments): raise Exception("Variable name duplication") # check variables self.visit(node.definition, local_varvalues, True) return "" def visit_FunctionCallNode(self, node, var_values, check): if node.name.value not in self.functions: raise Exception("Undefined function {}".format(node.name.value)) function_node = self.functions[node.name.value] #calc parameters local_varvalues = {} for (i, argnode) in enumerate(function_node.arguments): local_varvalues[argnode.value] = self.visit( node.arguments[i], None) return self.visit(function_node.definition, local_varvalues)