def check_code(self, args): if len(args) < len(self.args): raise StaticTypeError(f"Not enough arguments (needs {len(self.args)}), given {args}") if len(args) > len(self.args): raise StaticTypeError(f"Too many arguments (needs {len(self.args)})") for i, (supplied, needed) in enumerate(zip(args, self.args)): if not needed.can_coerce_from(supplied.tp): raise StaticTypeError(f"Argument {i + 1} should be {needed}, but is {supplied.tp} ")
def assign_target(self, node, value): if isinstance(value.tp, EmptyList): func_node = ast.Expr(value=ast.Call( func=ast.Attribute(value=node, attr="clear"), args=[])) try: self.visit(func_node) except UnknownVariable: raise StaticTypeError( "Must specify a list type when assigning an empty list") return if isinstance(node, ast.Name): left = self.context.assign_type(node.id, value.tp) self.start_line("{} = {};\n".format(left.code, value.as_value())) elif isinstance(node, ast.Subscript): container = self.get_expression_code(node.value) if isinstance(node.slice, ast.Index): index = self.get_expression_code(node.slice.value) setter = container.tp.get_method("set_item") code = setter.get_code(self.context, container, index, value) self.start_line(f"{code.code};\n") else: raise UnimplementedFeature("Slices not yet implemented") elif isinstance(node, ast.Attribute): owner = self.get_expression_code(node.value) owner.tp.set_attr(node.attr, value) left = self.get_expression_code(node) self.start_line(f"{left.code} = {value.code};\n")
def get_attr_code(self, attr: str, obj: Code) -> Code: if attr in self.cls.class_vars: return self.cls.class_vars[attr] else: try: val = self.cls.members[attr] text = f"{obj.as_accessor()}{attr}" return Code(tp=val.tp, code=text) except KeyError: raise StaticTypeError(f"Instance of {self.name} has no attribute {attr}")
def process_list(self, subscript: ast.AST): if isinstance(subscript, ast.Index): return TypeDB.get_list([self.visit(subscript.value)]) elif isinstance(subscript, ast.Slice): if isinstance(subscript.upper, ast.Num) and isinstance( subscript.upper.n, int): return TypeDB.get_list([self.visit(subscript.lower)], maxlen=subscript.upper.n) else: raise StaticTypeError("List length must be integer")
def assign_type(self, tp, additional_text=""): if self.tp is None: self.tp = tp return if self.tp.can_coerce_from(tp): return elif tp.can_coerce_from(self.tp): self.tp = tp return # not been able to match types - raise error raise StaticTypeError(f"Assigning {tp} to {self.tp}{additional_text}")
def get_binary_op_code(self, left: Code, op: ast.AST, right: Code): method_name = OPS_MAP[op.__class__] operation = op.__class__.__name__ try: func = left.tp.get_method(method_name) if not isinstance(func, InlineCMethod): raise StaticTypeError(f"Can't use {operation} at module level") result = func.get_code(self.context, left, right) except (StaticTypeError, InvalidOperation): try: func = right.tp.get_method( method_name) # ok try using right as function origin... if not isinstance(func, InlineCMethod): raise StaticTypeError( f"Can't use {operation} at module level") result = func.get_code(self.context, left, right) except (StaticTypeError, InvalidOperation): raise StaticTypeError( f"Arguments {left.tp}, {right.tp} not valid for operation {operation}" ) return result
def visit_Assign(self, node: ast.Assign): right = get_constant_code(node.value, self.context) for n in node.targets: if isinstance(n, ast.Name): if n.id in self.context: raise StaticTypeError("Cannot redefine global variables") self.context[n.id] = Code(tp=right.tp, code=n.id) left = self.context[n.id] self.globals += [ f"{left.tp.c_type} {n.id} = {right.as_value()};\n" ] else: raise InvalidOperation("Can only initialise global variables")
def get_binary_op_code(self, left, op, right): method_name = OPS_MAP[op.__class__] try: func = left.tp.get_method(method_name) result = func.get_code(self.context, left, right) except (StaticTypeError, InvalidOperation): try: func = right.tp.get_method( method_name) # ok try using right as function origin... result = func.get_code(self.context, left, right) except (StaticTypeError, InvalidOperation): operation = op.__class__.__name__ raise StaticTypeError( f"Arguments {left.tp}, {right.tp} not valid for operation {operation}" ) return result
def generic_visit(self, node): raise StaticTypeError( f"{node.__class__.__name__} not permitted in global definition")
def visit_Subscript(self, node: ast.Subscript): if isinstance(node.value, ast.Name): if node.value.id == "List": return self.process_list(node.slice) raise StaticTypeError("Annotation base must be List or Dict or Tuple")
def combine_types(a: "InferredType", b: "InferredType"): if a.can_coerce_from(b): return a if b.can_coerce_from(a): return b raise StaticTypeError(f"Incompatible types: {a} {b}")