예제 #1
0
def binary_op(self, node):
    op = node.op
    left = self.visit(node.left)
    right = self.visit(node.right)

    if hasFunction(self, userdef_binary_str(op, left, right)):
        return self.builder.call(
            self.module.get_global(userdef_binary_str(op, left, right)),
            (left, right), "binop")
    elif op == CAST:
        return cast_ops(self, left, right, node)
    elif op in (IS, IS_NOT):
        return is_ops(self, op, left, right, node)
    elif isinstance(left.type, ir.IntType) and isinstance(
            right.type, ir.IntType):
        return int_ops(self, op, left, right, node)
    elif type(left.type) in NUM_TYPES and type(right.type) in NUM_TYPES:
        if isinstance(left.type, ir.IntType):
            left = cast_ops(self, left, right.type, node)
        elif isinstance(right.type, ir.IntType):
            right = cast_ops(self, right, left.type, node)
        return float_ops(self, op, left, right, node)
    elif is_enum(left.type) and is_enum(right.type):
        return enum_ops(self, op, left, right, node)
    else:
        error('file={} line={}: Unknown operator {} for {} and {}'.format(
            self.file_name, node.line_num, op, node.left, node.right))
예제 #2
0
    def visit_funccall(self, node):
        func_name = node.name
        func = self.search_scopes(func_name)
        parameters = None
        parameter_defaults = None
        if isinstance(func, (ClassSymbol, EnumSymbol)):
            parameters = func.fields
            parameter_defaults = func.fields
        else:
            parameters = func.parameters
            parameter_defaults = func.parameter_defaults

        for x, param in enumerate(parameters.values()):
            if x < len(node.arguments):
                var = self.visit(node.arguments[x])
                param_ss = self.search_scopes(param.value)
                # TODO: Hacky stuff, first line is made to bypass checks for first-class functions, to fix
                if not isinstance(var, FuncSymbol) and (var.type is not None and not types_compatible(var, param_ss) and (param_ss != self.search_scopes(ANY) and param.value != var.name and param.value != var.type.name)):
                    raise TypeError  # TODO: Make this an actual error
            else:
                func_param_keys = list(parameters.keys())
                if func_param_keys[x] not in node.named_arguments.keys() and func_param_keys[x] not in parameter_defaults.keys():
                    error('file={} line={}: Missing arguments to function: {}'.format(self.file_name, node.line_num, repr(func_name)))
                else:
                    if func_param_keys[x] in node.named_arguments.keys():
                        if not types_compatible(param.value, self.visit(node.named_arguments[func_param_keys[x]]).name):
                            raise TypeError
        if func is None:
            error('file={} line={}: Name Error: {}'.format(self.file_name, node.line_num, repr(func_name)))
        else:
            func.accessed = True
            return func.type
예제 #3
0
 def visit_dotaccess(self, node):
     obj = self.search_scopes(node.obj)
     obj.accessed = True
     if isinstance(obj, EnumSymbol):
         return obj
     elif node.field not in obj.type.fields:
         error('file={} line={}: Invalid property {} of variable {}'.format(
             self.file_name, node.line_num, node.field, node.obj))
     return self.visit(obj.type.fields[node.field])
예제 #4
0
 def visit_incrementassign(self, node):
     left = self.visit(node.left)
     left_type = self.infer_type(left)
     any_type = self.search_scopes(ANY)
     if left_type in (self.search_scopes(DOUBLE), self.search_scopes(FLOAT), self.search_scopes(INT)) \
        or left_type is any_type:
         return left_type
     else:
         error('file={} line={}: Things that should not be happening ARE happening (fix this message)'.format(self.file_name, node.line_num))
예제 #5
0
 def visit_var(self, node):
     var_name = node.value
     val = self.search_scopes(var_name)
     if val is None:
         error('file={} line={}: Name Error: {}'.format(self.file_name, node.line_num, repr(var_name)))
     else:
         if not val.val_assigned:
             error('file={} line={}: {} is being accessed before it was defined'.format(self.file_name, node.line_num, var_name))
         val.accessed = True
         return val
예제 #6
0
 def visit_opassign(self, node):
     left = self.visit(node.left)
     right = self.visit(node.right)
     left_type = self.infer_type(left)
     right_type = self.infer_type(right)
     any_type = self.search_scopes(ANY)
     if types_compatible(left_type, right_type) or left_type is any_type or right_type is any_type:
         return left_type
     else:
         error('file={} line={}: Things that should not be happening ARE happening (fix this message)'.format(self.file_name, node.line_num))
예제 #7
0
    def find_until(self, to_find, until):
        num = 0
        x = None
        while x != until:
            num += 1
            x = self.lexer.preview_token(num).value
            if x == to_find:
                return True
            elif x == EOF:
                error('file={} line={} Syntax Error: expected {}'.format(self.file_name, self.line_num, to_find))

        return False
예제 #8
0
    def visit_range(self, node):
        left = self.visit(node.left)
        right = self.visit(node.right)
        left_type = self.infer_type(left)
        right_type = self.infer_type(right)
        any_type = self.search_scopes(ANY)

        if left_type in (self.search_scopes(INT), self.search_scopes(DOUBLE), self.search_scopes(FLOAT)) and right_type in (self.search_scopes(INT), self.search_scopes(DOUBLE), self.search_scopes(FLOAT)):
            return self.search_scopes(LIST), left_type
        elif right_type is left_type or left_type is any_type or right_type is any_type:
            return self.search_scopes(LIST), left_type
        else:
            error('file={} line={}: Please don\'t do what you just did there ever again. It bad (fix this message)'.format(self.file_name, node.line_num))
예제 #9
0
 def visit_binop(self, node):
     if node.op == CAST or node.op in (IS, IS_NOT):
         self.visit(node.left)
         if node.right.value not in TYPES and not isinstance(self.search_scopes(node.right.value), (EnumSymbol, ClassSymbol)):
             error('file={} line={}: type expected for operation {}, got {} : {}'.format(self.file_name, node.line_num, node.op, node.left, node.right))
         return self.infer_type(self.visit(node.right))
     else:
         left = self.visit(node.left)
         right = self.visit(node.right)
         left_type = self.infer_type(left)
         right_type = self.infer_type(right)
         any_type = self.search_scopes(ANY)
         if types_compatible(left_type, right_type) or left_type is any_type or right_type is any_type:
             return left_type
         else:
             error('file={} line={}: types do not match for operation {}, got {} : {}'.format(self.file_name, node.line_num, node.op, left, right))
예제 #10
0
 def visit_anonymousfunc(self, node):
     func_type = self.search_scopes(node.return_type.value)
     self.new_scope()
     for k, v in node.parameters.items():
         var_type = self.search_scopes(v.value)
         if var_type is self.search_scopes(FUNC):
             sym = FuncSymbol(k, v.func_ret_type, None, None)
         else:
             sym = VarSymbol(k, var_type)
         sym.val_assigned = True
         self.define(sym.name, sym)
     func_symbol = FuncSymbol(ANON, func_type, node.parameters, node.body)
     return_var_type = self.visit(func_symbol.body)
     return_var_type = list(flatten(return_var_type))
     for ret_type in return_var_type:
         if self.infer_type(ret_type) is not func_type:
             error('file={} line={}: The actual return type does not match the declared return type'.format(self.file_name, node.line_num))
     self.drop_top_scope()
     return func_symbol
예제 #11
0
def unary_op(self, node):
    op = node.op
    expr = self.visit(node.expr)
    if hasFunction(self, userdef_unary_str(op, expr)) and \
       self.current_function.name != userdef_unary_str(op, expr):
        return self.builder.call(
            self.module.get_global(userdef_unary_str(op, expr)), [expr],
            "unop")
    elif op == MINUS:
        if isinstance(expr.type, ir.IntType):
            return self.builder.neg(expr)
        elif isinstance(expr.type, (ir.FloatType, ir.DoubleType)):
            return self.builder.fsub(ir.Constant(ir.DoubleType(), 0), expr)
    elif op == NOT:
        if isinstance(expr.type, ir.IntType) and str(
                expr.type).split("i")[1] == '1':
            return self.builder.not_(expr)
    elif op == BINARY_ONES_COMPLIMENT:
        if isinstance(expr.type, ir.IntType):
            return self.builder.not_(expr)
    else:
        error('file={} line={}: Unknown operator {} for {}'.format(
            self.file_name, node.line_num, op, expr))
예제 #12
0
    def visit_externfuncdecl(self, node):
        func_name = node.name
        func_type = self.search_scopes(node.return_type.value)

        if self.search_scopes(func_name) is not None:
            error('file={} line={}: Cannot redefine a declared function: {}'.format(self.file_name, node.line_num, func_name))

        if func_type and func_type.name == FUNC:
            func_type.func = FuncSymbol(ANON, self.visit(node.return_type.func_ret_type), node.parameters, node.body, node.parameter_defaults)

        self.define(func_name, FuncSymbol(func_name, func_type, node.parameters, None))
        self.new_scope()
        if node.varargs:
            varargs_type = self.search_scopes(LIST)
            varargs_type.type = node.varargs[1].value
            varargs = CollectionSymbol(node.varargs[0], varargs_type, self.search_scopes(node.varargs[1].value))
            varargs.val_assigned = True
            self.define(varargs.name, varargs)
        for k, v in node.parameters.items():
            var_type = self.search_scopes(v.value)
            if var_type is self.search_scopes(FUNC):
                sym = FuncSymbol(k, v.func_ret_type, None, None)
            elif isinstance(var_type, TypeSymbol):
                var_type.accessed = True
                if var_type.type is self.search_scopes(FUNC):
                    sym = FuncSymbol(k, var_type.type.return_type, None, None)
                else:
                    raise NotImplementedError
            else:
                sym = VarSymbol(k, var_type)
            sym.val_assigned = True
            self.define(sym.name, sym)

        func_symbol = FuncSymbol(func_name, func_type, node.parameters, None)
        self.define(func_name, func_symbol, 1)
        self.drop_top_scope()
예제 #13
0
 def visit_collectionaccess(self, node):
     collection = self.search_scopes(node.collection.value)
     collection.accessed = True
     if isinstance(node.key, Var):
         key = self.infer_type(node.key.value)
     else:
         key = self.visit(node.key)
     if collection.type is self.search_scopes(LIST) or collection.type is self.search_scopes(TUPLE) or collection.type is self.search_scopes(SET):
         if key is not self.search_scopes(INT) and key.type is not self.search_scopes(INT):
             error('file={} line={}: Something something error... huh? (fix this message)'.format(self.file_name, node.line_num))
         return collection.item_types
     elif collection.type is self.search_scopes(DICT) or collection.type is self.search_scopes(ENUM):
         if key is not self.search_scopes(STR) and key.type is not self.search_scopes(STR):
             error('file={} line={}: Dude....... don\'t (fix this message)'.format(self.file_name, node.line_num))
         return self.search_scopes(ANY)
     else:
         error('file={} line={}: WHY? (fix this message)'.format(self.file_name, node.line_num))
예제 #14
0
    def visit_funcdecl(self, node):
        func_name = node.name
        func_type = self.search_scopes(node.return_type.value)

        if self.search_scopes(func_name) is not None:
            error('file={} line={}: Cannot redefine a declared function: {}'.format(self.file_name, node.line_num, func_name))

        if func_type and func_type.name == FUNC:
            func_type.func = FuncSymbol(ANON, self.visit(node.return_type.func_ret_type), node.parameters, node.body, node.parameter_defaults)

        self.define(func_name, FuncSymbol(func_name, func_type, node.parameters, node.body, node.parameter_defaults))
        self.new_scope()
        if node.varargs:
            varargs_type = self.search_scopes(LIST)
            varargs_type.type = node.varargs[1].value
            varargs = CollectionSymbol(node.varargs[0], varargs_type, self.search_scopes(node.varargs[1].value))
            varargs.val_assigned = True
            self.define(varargs.name, varargs)
        for k, v in node.parameters.items():
            var_type = self.search_scopes(v.value)
            if var_type is self.search_scopes(FUNC):
                sym = FuncSymbol(k, v.func_ret_type, v.func_params, None)
            elif isinstance(var_type, TypeSymbol):
                var_type.accessed = True
                if var_type.type is self.search_scopes(FUNC):
                    sym = FuncSymbol(k, var_type.type.return_type, v.func_params, None)
                else:
                    raise NotImplementedError
            else:
                sym = VarSymbol(k, var_type)
            sym.val_assigned = True
            self.define(sym.name, sym)
        return_types = self.visit(node.body)
        return_types = list(flatten(return_types))
        if self.return_flag:
            self.return_flag = False
            for ret_type in return_types:
                infered_type = self.infer_type(ret_type)
                if infered_type is not func_type and not types_compatible(infered_type, func_type):
                    error('file={} line={}: The actual return type does not match the declared return type: {}'.format(self.file_name, node.line_num, func_name))
        elif func_type is not None:
            error('file={} line={}: No return value was specified for function: {}'.format(self.file_name, node.line_num, func_name))
        func_symbol = FuncSymbol(func_name, func_type, node.parameters, node.body, node.parameter_defaults)
        self.define(func_name, func_symbol, 1)
        self.drop_top_scope()
예제 #15
0
    def function_declaration(self):
        op_func = False
        extern_func = False
        self.eat_value(DEF)
        if self.current_token.value == LPAREN:
            name = ANON
        elif self.current_token.value == OPERATOR:
            self.eat_value(OPERATOR)
            op_func = True
            name = self.next_token()
        elif self.current_token.value == EXTERN:
            self.eat_value(EXTERN)
            extern_func = True
            name = self.next_token()
        else:
            name = self.next_token()
        self.eat_value(LPAREN)
        params = OrderedDict()
        param_defaults = {}
        vararg = None
        while self.current_token.value != RPAREN:
            param_name = self.current_token.value
            self.eat_type(NAME)
            if self.current_token.value == COLON:
                self.eat_value(COLON)
                param_type = self.type_spec()
            else:
                param_type = self.variable(self.current_token)

            params[param_name] = param_type
            if self.current_token.value != RPAREN:
                if self.current_token.value == ASSIGN:
                    if extern_func:
                        error("Extern functions cannot have defaults")
                    self.eat_value(ASSIGN)
                    param_defaults[param_name] = self.expr()
                if self.current_token.value == ELLIPSIS:
                    key, value = params.popitem()
                    if not vararg:
                        vararg = []
                    vararg.append(key)
                    vararg.append(value)
                    self.eat_value(ELLIPSIS)
                    break
                if self.current_token.value != RPAREN:
                    self.eat_value(COMMA)
        self.eat_value(RPAREN)

        if self.current_token.value != ARROW:
            return_type = Void()
        else:
            self.eat_value(ARROW)
            if self.current_token.value == VOID:
                return_type = Void()
                self.next_token()
            else:
                return_type = self.type_spec()

        if extern_func:
            return ExternFuncDecl(name.value, return_type, params, self.line_num, vararg)

        self.eat_type(NEWLINE)
        self.indent_level += 1
        stmts = self.compound_statement()
        self.indent_level -= 1
        if name == ANON:
            return AnonymousFunc(return_type, params, stmts, self.line_num, param_defaults, vararg)
        if op_func:
            if len(params) not in (1, 2):  # TODO: move this to type checker
                error("Operators can either be unary or binary, and the number of parameters do not match")

            name.value = OPERATOR + '.' + name.value
            for param in params:
                type_name = str(type_map[str(params[param].value)]) if str(params[param].value) in type_map else str(params[param].value)
                name.value += '.' + type_name

        return FuncDecl(name.value, return_type, params, stmts, self.line_num, param_defaults, vararg)
예제 #16
0
    def visit_assign(self, node):  # TODO clean up this mess of a function
        collection_type = None
        field_assignment = None
        collection_assignment = None
        if isinstance(node.left, VarDecl):
            var_name = node.left.value.value
            value = self.infer_type(node.left.type)
            value.accessed = True
            if isinstance(node.right, Collection) or isinstance(node.right, Range):
                _, collection_type = self.visit(node.right)

            if value.name in (TUPLE, LIST) and (not isinstance(node.right, Range) and node.right.type != value.name):
                error('file={} line={}: Contradicting {}-{} declaration'.format(self.file_name, node.line_num, value.name, node.right.type))
        elif hasattr(node.right, 'name') and isinstance(self.search_scopes(node.right.name), (EnumSymbol, ClassSymbol)):
            var_name = node.left.value
            value = self.search_scopes(node.right.name)
            value.accessed = True
        elif isinstance(node.right, Collection) or isinstance(node.right, Range):
            var_name = node.left.value
            value, collection_type = self.visit(node.right)
        elif isinstance(node.left, DotAccess):
            field_assignment = True
            var_name = self.visit(node.left)
            value = self.visit(node.right)
        elif isinstance(node.right, DotAccess):
            var_name = node.left.value
            value = self.search_scopes(node.right.obj)
            value.accessed = True
            value = self.infer_type(value)
        elif isinstance(node.left, CollectionAccess):
            collection_assignment = True
            var_name = node.left.collection.value
            value = self.visit(node.right)
        else:
            var_name = node.left.value
            value = self.visit(node.right)
            if isinstance(value, VarSymbol):
                value = value.type
        lookup_var = self.search_scopes(var_name)
        if not lookup_var:
            if collection_type:
                col_sym = CollectionSymbol(var_name, value, collection_type)
                col_sym.val_assigned = True
                self.define(var_name, col_sym)
            elif field_assignment:
                if var_name is value:
                    return
                else:
                    error('file={} line={} Type Error: What are you trying to do?!?! (fix this message)'.format(self.file_name, node.line_num))
            elif isinstance(value, FuncSymbol):
                value.name = var_name
                self.define(var_name, value)
            elif hasattr(value, 'name') and value.name == FUNC:
                var = self.visit(node.right)
                if isinstance(var, FuncSymbol):
                    self.define(var_name, var)
                elif isinstance(var, BuiltinTypeSymbol):
                    self.define(var_name, var.func)
                else:
                    val_info = self.search_scopes(node.right.value)
                    func_sym = FuncSymbol(var_name, val_info.type.return_type, val_info.parameters, val_info.body, val_info.parameter_defaults)
                    self.define(var_name, func_sym)
            else:
                var_sym = VarSymbol(var_name, value, node.left.read_only)
                var_sym.val_assigned = True
                self.define(var_name, var_sym)
        else:
            if isinstance(node.left, VarDecl):
                error('file={} line={}: Cannot redefine the type of a declared variable: {}'.format(self.file_name, node.line_num, var_name))

            if collection_assignment:
                col = self.search_scopes(node.left.collection.value)
                if col.type.name == TUPLE:
                    error('file={} line={}: Cannot change the elements of a tuple: {}'.format(self.file_name, node.line_num, var_name))
                elif lookup_var.item_types == value:
                    return
            if lookup_var.read_only:
                error('file={} line={}: Cannot change the value of a variable declared constant: {}'.format(self.file_name, node.line_num, var_name))

            lookup_var.val_assigned = True
            if lookup_var.type in (self.search_scopes(DOUBLE), self.search_scopes(FLOAT)):
                if value in (self.search_scopes(INT), self.search_scopes(DOUBLE), self.search_scopes(FLOAT)):
                    return
            if lookup_var.type is value:
                return
            if hasattr(value, 'type') and lookup_var.type is value.type:
                return
            if isinstance(value, TypeSymbol):
                value.accessed = True
                if value.type is self.search_scopes(FUNC):
                    if value.type.return_type == lookup_var.type:
                        return
            if hasattr(value, 'value'):
                if value.value == lookup_var.type.name:
                    return
            error('file={} line={} Type Error: Not good things happening (fix this message)'.format(self.file_name, node.line_num))
예제 #17
0
 def visit_switch(self, node):
     switch_var = self.visit(node.value)
     for case in node.cases:
         case_type = self.visit(case)
         if case_type != DEFAULT and case_type is not switch_var.type:
             error('file={} line={}: Types in switch do not match case'.format(self.file_name, node.line_num))
예제 #18
0
 def eat_value(self, *token_value):
     if self.current_token.value in token_value:
         self.next_token()
     else:
         error('file={} line={} Syntax Error: expected {}'.format(self.file_name, self.line_num, ", ".join(token_value)))
예제 #19
0
 def visit_methodcall(self, node):  # TODO: Finish this, make Symbols for Classes and Methods
     # TODO: hardcoded error for tuple methods, thing of a better way to do it
     if isinstance(self.search_scopes(node.obj), CollectionSymbol) and self.search_scopes(node.obj).type.name == TUPLE:
         if node.name in ('set', 'append'):
             error('file={} line={}: Immutable Error: cannot use `{}` method'.format(self.file_name, node.line_num, node.name))