def ExpSubTup(): yield ps.token(TOKEN.PAR_OPEN) a = yield Exp b = yield ExpClose if b is None: return a else: return AST.TUPLE(a=a, b=b)
def typecheck(expr, exp_type, symbol_table, ext_table, func=None, r=0, noErrors=False): if type(expr) is Token: if expr.typ == TOKEN.EMPTY_LIST: if type(exp_type) == AST.LISTTYPE: return True, expr else: ERROR_HANDLER.addError(ERR.UnexpectedEmptyList, [expr]) typ = tokenToNode(expr) if not AST.equalVals(typ, exp_type): if r == 0 and not noErrors: ERROR_HANDLER.addError(ERR.UnexpectedType, [subprint_type(typ), subprint_type(exp_type), expr]) return False, expr return True, expr elif type(expr) is AST.PARSEDEXPR: return typecheck(expr.val, exp_type, symbol_table, ext_table, func, r, noErrors) elif type(expr) is AST.RES_VARREF: if type(expr.val) is AST.RES_GLOBAL: if expr.val.module is None: typ = symbol_table.global_vars[expr.val.id.val].type.val else: typ = ext_table.global_vars[expr.val.id.val]['type'].val fields = list(reversed(expr.val.fields)) success, typ = getSubType(typ, fields, expr) if not success: return True, expr if not AST.equalVals(typ, exp_type): if r == 0 and not noErrors: ERROR_HANDLER.addError(ERR.UnexpectedType, [subprint_type(typ), subprint_type(exp_type), expr]) return False, expr elif type(expr.val) is AST.RES_NONGLOBAL: typ = None if expr.val.scope == NONGLOBALSCOPE.LocalVar: typ = func['local_vars'][expr.val.id.val].type.val else: typ = func['arg_vars'][expr.val.id.val]['type'].val fields = list(reversed(expr.val.fields)) success, typ = getSubType(typ, fields, expr) if not success: return True, expr if not AST.equalVals(typ, exp_type): if r == 0 and not noErrors: ERROR_HANDLER.addError(ERR.UnexpectedType, [subprint_type(typ), subprint_type(exp_type), expr]) return False, expr return True, expr elif type(expr) is AST.FUNCALL: identifier = (FunKindToUniq(expr.kind), expr.id.val) if identifier not in symbol_table.functions and identifier not in ext_table.functions: ERROR_HANDLER.addError(ERR.UndefinedFun, [expr.id.val, expr.id]) return True, expr # Symbol table functions matches = [] if identifier in symbol_table.functions: out_type_matches = {} i = 0 for o in symbol_table.functions[identifier]: if AST.equalVals(exp_type, o['type'].to_type.val) or exp_type is None: out_type_matches[i] = o i += 1 for k, o in out_type_matches.items(): args = [] if len(o['type'].from_types) == len(expr.args): input_matches = 0 for i in range(len(o['type'].from_types)): typ, arg_res = typecheck(expr.args[i], o['type'].from_types[i].val, symbol_table, ext_table, func, r, noErrors=True) args.append(arg_res) if typ: input_matches += 1 if input_matches == len(expr.args): matches.append({ 'id': k, 'module': None, 'args': args, 'returns': not AST.equalVals(o['type'].to_type, AST.TYPE(val=Token(Position(), TOKEN.TYPE_IDENTIFIER, "Void"))), }) if identifier in ext_table.functions: out_type_matches = {} i = 0 for o in ext_table.functions[identifier]: if AST.equalVals(exp_type, o['type'].to_type.val) or exp_type is None: if o['module'] not in out_type_matches: out_type_matches[o['module']] = {} out_type_matches[o['module']][i] = o i += 1 if len(out_type_matches) == 0 and len(matches) == 0: if not noErrors and exp_type is not None: if expr.kind == FunKind.FUNC: ERROR_HANDLER.addError(ERR.NoOverloadedFunDef, [expr.id.val, subprint_type(exp_type), expr.id]) else: ERROR_HANDLER.addError(ERR.NoOpDefWithType, [expr.id.val, subprint_type(exp_type), expr.id]) return False, expr for module, f in out_type_matches.items(): for oid, of in f.items(): args = [] if len(of['type'].from_types) == len(expr.args): input_matches = 0 for i in range(len(of['type'].from_types)): typ, arg_res = typecheck(expr.args[i], of['type'].from_types[i].val, symbol_table, ext_table, func, r, noErrors=True) args.append(arg_res) if typ: input_matches += 1 if input_matches == len(expr.args): matches.append({ 'id': oid, 'module': module, 'args': args, 'returns': not AST.equalVals(of['type'].to_type, AST.TYPE(val=Token(Position(), TOKEN.TYPE_IDENTIFIER, "Void"))), }) # Give preference to functions defined in current module if type is exactly the same. if len(matches) > 0: current_module_matches = 0 prefered_match = None for m in matches: if m['module'] is None: current_module_matches += 1 if current_module_matches > 1: break else: prefered_match = m if current_module_matches == 1: matches = [prefered_match] if len(matches) == 0: if not noErrors: if expr.kind == FunKind.FUNC: ERROR_HANDLER.addError(ERR.NoOverloadedFunWithArgs, [expr.id.val, expr.id]) else: ERROR_HANDLER.addError(ERR.NoOpDefWithInputType, [expr.id.val, expr.id]) return False, expr elif len(matches) > 1 and exp_type is None: if not noErrors: if expr.kind == FunKind.FUNC: ERROR_HANDLER.addError(ERR.AmbiguousFunCall, [expr.id.val, expr.id]) else: ERROR_HANDLER.addError(ERR.AmbiguousOp, [expr.id.val, expr.id]) return False, expr elif len(matches) > 1: if not noErrors: if expr.kind == FunKind.FUNC: ERROR_HANDLER.addError(ERR.AmbiguousNestedFunCall, [expr.id.val, expr.id]) else: ERROR_HANDLER.addError(ERR.AmbiguousOp, [expr.id.val, expr.id]) return False, expr else: if func is None and (matches[0]['module'] != 'builtins' or expr.kind == FunKind.FUNC): ERROR_HANDLER.addError(ERR.GlobalDefMustBeConstant, [expr.id]) return True, expr return True, AST.TYPED_FUNCALL(id=expr.id, uniq=FunKindToUniq(expr.kind), args=matches[0]['args'], oid=matches[0]['id'], module=matches[0]['module'], returns=matches[0]['returns']) elif type(expr) is AST.TUPLE: if type(exp_type) is not AST.TUPLETYPE: ERROR_HANDLER.addError(ERR.UnexpectedTuple, [exp_type, expr]) return True, expr type1, a = typecheck(expr.a, exp_type.a.val, symbol_table, ext_table, func) type2, b = typecheck(expr.b, exp_type.b.val, symbol_table, ext_table, func) return type1 or type2, AST.TUPLE(a=a, b=b) else: print(expr) print(type(expr)) raise Exception('Unknown type of expression encountered in typechecking')