def visit_Script(self, node): return_value = [] for stmt in node.statements: if not isinstance(stmt, structural_nodes.Push) and SInstructions.is_push_operation(stmt): msg = 'Implicit push of %s %s' % (stmt.__class__.__name__, SInstructions.format_op(stmt)) if not self.options.implicit_pushes: self.error(msg, stmt.lineno) raise IRImplicitPushError(msg, stmt.lineno) else: self.warning(msg, stmt.lineno) return_value.extend(self.visit(stmt)) return return_value
def test_conditional(self): for node, expected in [ (sir.If(test=sir.Int(1), truebranch=[sir.Int(5)], falsebranch=[]), 'if 1 {5;}'), (sir.If(test=sir.Int(1), truebranch=[sir.Int(5)], falsebranch=[sir.Int(6)]), 'if 1 {5;} else {6;}'), (sir.If(test=sir.Int(1), truebranch=[sir.Int(5)], falsebranch=[sir.Int(6), sir.Int(7)]), 'if 1 {5;} else {6; 7;}'), ]: self.assertEqual(expected, SInstructions.format_op(node))
def test_assignments(self): for node, expected in [ (sir.Declaration(name='foo', value=sir.Int(5), type_=SymbolType.Integer, mutable=True), 'let mutable foo = 5'), (sir.Declaration(name='foo', value=sir.Int(5), type_=SymbolType.Integer, mutable=False), 'let foo = 5'), (sir.Assignment(name='foo', value=sir.Int(5), type_=SymbolType.Integer), 'foo = 5'), (sir.Assignment(name='foo', value=sir.Bytes('05'), type_=SymbolType.Integer), 'foo = 05'), ]: self.assertEqual(expected, SInstructions.format_op(node))
def test_function_call(self): for node, expected in [ (sir.FunctionCall(name='foo', args=[]), 'foo()'), (sir.FunctionCall(name='foo', args=[sir.Int(5)]), 'foo(5)'), (sir.FunctionCall(name='foo', args=[sir.Int(5), sir.Int(6)]), 'foo(5, 6)'), (sir.FunctionCall(name='foo', args=[sir.Int(5), sir.Bytes('06')]), 'foo(5, 06)'), ]: self.assertEqual(expected, SInstructions.format_op(node))
def test_function(self): for node, expected in [ (sir.Function(name='foo', args=[sir.Symbol('a')], body=[sir.BinOpCode(name='OP_ADD', left=sir.Symbol('a'), right=sir.Int(2))]), 'func foo(a) {a + 2;}'), (sir.Function(name='foo', args=[sir.Symbol('a')], body=[sir.BinOpCode(name='OP_ADD', left=sir.Symbol('a'), right=sir.Int(2)), sir.Int(5)]), 'func foo(a) {a + 2; 5;}'), (sir.Function(name='foo', args=[sir.Symbol('a'), sir.Symbol('b')], body=[sir.BinOpCode(name='OP_ADD', left=sir.Symbol('a'), right=sir.Symbol('b')), sir.Int(5)]), 'func foo(a, b) {a + b; 5;}'), ]: self.assertEqual(expected, SInstructions.format_op(node))
def test_unary_op(self): for name, expected in [ ('OP_1ADD', '05++'), ('OP_1SUB', '05--'), ('OP_2MUL', '05 * 2'), ('OP_2DIV', '05 / 2'), ('OP_NEGATE', '-05'), ('OP_ABS', '|05|'), ]: op = sir.UnaryOpCode(name = name, operand = sir.Bytes('05')) self.assertEqual(expected, SInstructions.format_op(op))
def visit_UnaryOpCode(self, node): if SInstructions.is_arithmetic_op(node) and isinstance(node.operand, (structural_nodes.Int, structural_nodes.Bytes)): if not formats.is_strict_num(int(node.operand)): msg = 'Input value to %s is longer than 4 bytes: 0x%x' % (node.name, node.operand) if self.options.strict_num: self.error(msg, node.lineno) raise IRStrictNumError(msg) else: self.warning(msg, node.lineno) return_value = self.visit(node.operand) op = types.opcode_by_name(node.name)() return return_value + [op]
def check_types(self, node): """Check the operand types of node.""" if not isinstance(node, structural_nodes.OpCode): return args = node.get_args() if any(isinstance(arg, structural_nodes.Symbol) for arg in args): self.require_symbol_table('process operands') for i, arg in enumerate(args): if isinstance(arg, structural_nodes.Symbol): args[i] = self.symbol_table.lookup(arg.name).value if SInstructions.is_arithmetic_op(node): for arg in args: if isinstance(arg, structural_nodes.Bytes): msg = 'Byte array %s used in arithmetic operation' % (arg) self.warning(msg, node.lineno) elif SInstructions.is_byte_string_op(node): for arg in args: if isinstance(arg, structural_nodes.Int): msg = 'Integer %s used in byte string operation' % (arg) self.error(msg, node.lineno) raise IRTypeError(msg, node.lineno)
def cast_return_type(self, node, as_type): """Return node implicitly casted as as_type. This does not perform casting of types that have equal specificity (e.g. integers are not implicitly casted to byte arrays). """ value_type = SInstructions.get_symbol_type_for_node(node) line_number = node.lineno return_value = None if value_type == as_type: return_value = node if as_type == SymbolType.Expr: return_value = node if return_value: return_value.lineno = line_number return return_value raise IRTypeError('Function returned type %s (expected %s)' % (value_type, as_type))
def visit_BinOpCode(self, node): # Check for values longer than 4 bytes. if SInstructions.is_arithmetic_op(node): operands = [node.left, node.right] if all(isinstance(i, (structural_nodes.Int, structural_nodes.Bytes)) for i in operands): valid = [formats.is_strict_num(int(i)) for i in operands] if False in valid: msg = 'Input value to %s is longer than 4 bytes: 0x%x' % (node.name, operands[valid.index(False)]) if self.options.strict_num: self.error(msg, node.lineno) raise IRStrictNumError(msg) else: self.warning(msg, node.lineno) return_value = self.visit(node.left) return_value.extend(self.visit(node.right)) op = types.opcode_by_name(node.name)() return return_value + [op]
def visit_Symbol(self, node): """Attempt to simplify the value of a symbol.""" symbol = self.symbol_table.lookup(node.name) if not symbol: raise IRError('Symbol "%s" was not declared.' % node.name) value = symbol.value # Constant value. if get_const(value): return value # Try to evaluate and/or optimize the expression. if symbol.type_ == SymbolType.Expr: expr = self.visit(value) if get_const(expr): symbol.value = expr symbol.type_ = SInstructions.get_symbol_type_for_node(expr) return expr return node
def test_binary_op(self): for name, expected in [ ('OP_ADD', '05 + 06'), ('OP_SUB', '05 - 06'), ('OP_MUL', '05 * 06'), ('OP_DIV', '05 / 06'), ('OP_MOD', '05 % 06'), ('OP_LSHIFT', '05 << 06'), ('OP_RSHIFT', '05 >> 06'), ('OP_BOOLAND', '05 and 06'), ('OP_BOOLOR', '05 or 06'), ('OP_NUMEQUAL', '05 == 06'), ('OP_NUMNOTEQUAL', '05 != 06'), ('OP_LESSTHAN', '05 < 06'), ('OP_GREATERTHAN', '05 > 06'), ('OP_LESSTHANOREQUAL', '05 <= 06'), ('OP_GREATERTHANOREQUAL', '05 >= 06'), ]: op = sir.BinOpCode(name = name, left = sir.Bytes('05'), right = sir.Bytes('06')) self.assertEqual(expected, SInstructions.format_op(op))
def visit_Function(self, node): for stmt in node.body: if SInstructions.is_push_operation(stmt): msg = 'Functions cannot push values to the stack' self.error(msg, stmt.lineno) raise IRImplicitPushError(msg, stmt.lineno)
def _linearize(self, structural): return StructuralVisitor().transform(SInstructions(structural))
def test_innerscript(self): for node, expected in [ (sir.InnerScript(statements=[sir.Int(5)]), '5;'), (sir.InnerScript(statements=[sir.Int(5), sir.Int(6)]), '5; 6;'), ]: self.assertEqual(expected, SInstructions.format_op(node))
def _test(self, type_test): type_name = SInstructions.get_symbol_type_for_node(type_test.node) msg = '%s != %s (node: %s)' % (type_test.expected_type, type_name, type_test.node) self.assertEqual(type_test.expected_type, type_name, msg)