def aliasParser(parser, name, decl, generic): parser.nextToken() typ = False while not Parser.isEnd(parser): if parser.thisToken().token != "\n" and parser.thisToken().type != "indent": if typ: Error.parseError(parser, "Unexpected token " + parser.thisToken().token) typ = Types.parseType(parser) parser.nextToken() if decl: alias = parser.interfaces[parser.package][name] tmp = Types.Alias(parser.package, name, typ, generic) alias.name = tmp.name alias.normalName = tmp.normalName alias.typ = tmp.typ alias.generic = tmp.generic alias.remainingGen = tmp.remainingGen alias.types = tmp.types alias.methods = tmp.methods if decl: parser.interfaces[parser.package][name] = alias Scope.decrScope(parser)
def createParser(parser, name="", typ=None, check=True, imutable=True, attachTyp=False): # : creation if name == "": name = parser.lookBehind() if name.type != "identifier": Error.parseError( parser, "variable name must be of type identifier, not " + parser.lookBehind().type) name = name.token if name[0].lower() != name[0]: Error.parseError(parser, "variable name must be lower case") node = Tree.Create(name, Types.Null(), parser) node.package = parser.package node.imutable = imutable if attachTyp: node.attachTyp = attachTyp parser.currentNode.addNode(node) node.varType = typ if check and typ is None: parser.nextToken() typ = Types.parseType(parser) node.varType = typ
def enumParser(parser, name, decl, generic): const = parser.interfaces[parser.package][name].const existing_generics = parser.interfaces[parser.package][name].generic existing_generics.update(generic) #const = coll.OrderedDict() enum = Types.Enum(parser.package, name, const, existing_generics) if decl: parser.interfaces[parser.package][name] = enum """if parser.lookInfront().token == "\n": parser.nextToken() Parser.callToken(parser) parser.nextToken()"" \ """ while not Parser.isEnd(parser): t = parser.nextToken() if t.token == "\n" or t.type == "indent": Parser.callToken(parser) continue if t.type != "identifier": Error.parseError(parser, "expecting identifier") varName = t.token if varName[0].upper() != varName[0]: Error.parseError(parser, "constructor type must be capitalized") args = [] nextT = parser.nextToken() #print(varName) #print(nextT) if nextT.token == "(": args = Types.parseType(parser).list const[varName] = args if decl: Scope.addVar(Tree.PlaceHolder(parser), parser, varName, Scope.Type( True, Types.FuncPointer(args, enum, generic=generic) if len(args) > 0 else enum), _global=True) t = parser.thisToken() if t.token == "\n" or t.type == "indent": Parser.callToken(parser) parser.currentNode.addNode(Tree.Enum(const, name, parser, generic)) Scope.decrScope(parser)
def sizeofParser(parser): parser.nextToken() s = Tree.Sizeof(parser) typ = Types.parseType(parser) s.typ = typ s.type = Types.I32(unsigned= True) parser.currentNode.addNode(s)
def loop(n): if type(n) in [Tree.PlaceHolder, Tree.Place]: return B elif type(n) is Tree.Field: inner = loop(n.nodes[0]) return Types.Interface(False, {n.field: inner}) elif type(n) is Tree.ArrRead: inner = loop(n.nodes[0]) return Types.Array(False, inner) else: n.error("unexpected token " + n.token.token)
def parseJson(parser): parse = Tree.Decoder(parser) parser.currentNode.addNode(parse) parser.currentNode = parse parser.nextToken() typ = Types.parseType(parser) parse.type = Types.FuncPointer([Types.All], typ) parse.shouldBeTyp = typ parser.currentNode = parse.owner
def createParser(parser, name= "", typ= None, check= True, imutable= True, attachTyp= False): # : creation if name == "": name = parser.lookBehind() if name.type != "identifier": Error.parseError(parser, "variable name must be of type identifier, not "+parser.lookBehind().type) name = name.token if name[0].lower() != name[0]: Error.parseError(parser, "variable name must be lower case") node = Tree.Create(name, Types.Null(), parser) node.package = parser.package node.imutable = imutable if attachTyp: node.attachTyp = attachTyp parser.currentNode.addNode(node) node.varType = typ if check and typ is None: parser.nextToken() typ = Types.parseType(parser) node.varType = typ
def simplifyArrRead(operator, iter, parser): readMethodName = callMethodCode(operator.nodes[0], "op_get", operator.nodes[0].type, parser, False) readMethodName.type.args[1] = operator.nodes[1].type readMethodName.type.returnType = operator.type # if operator.nodes[0].type.isType(Types.Pointer): # readMethodName.replaced = operator.nodes[0].type.pType.remainingGen # else: # readMethodName.replaced = operator.nodes[0].type.remainingGen deref = Tree.Operator("*", operator) deref.unary = True deref.type = operator.type deref.owner = operator.owner func = Tree.FuncCall(operator) func.type = Types.Pointer(operator.type) func.addNode(readMethodName) func.addNode(operator.nodes[0]) func.addNode(operator.nodes[1]) deref.addNode(func) operator.owner.nodes[iter] = deref return deref
def generics(parser, fname): generic = coll.OrderedDict() while parser.thisToken().token != "]": name = parser.nextToken().token typ = Types.T(name, Types.All, parser.package+"."+fname) if parser.thisToken().type != "identifier": Error.parseError(parser, "type name must be an identifier") if not parser.nextToken().token in [":", ",", "]"]: Error.parseError(parser, "expecting ,") if parser.thisToken().token == ":": parser.nextToken() typ = Types.T(name, Types.parseType(parser), parser.package+"."+fname) if parser.lookInfront().token != "]": parser.nextToken() Scope.addVar(Tree.PlaceHolder(parser), parser, name, Scope.Type(False, typ)) generic[name] = typ if parser.lookInfront().token == "]": parser.nextToken() break parser.nextToken() return generic
def genericT(parser): parser.nextToken() if len(parser.currentNode.nodes) > 0: func = parser.currentNode.nodes.pop() else: Error.parseError(parser, "unexpected ::") generic = Tree.Generic(parser) parser.currentNode.addNode(generic) generic.addNode(func) generic.generic = [] if parser.thisToken().token != "[": Error.parseError(parser, "expecting [") parser.nextToken() while parser.thisToken().token != "]": if parser.thisToken().token == ",": parser.nextToken() parser.nodeBookmark[-1] = len(parser.currentNode.nodes) continue generic.generic.append(Types.parseType(parser)) t = parser.thisToken().token parser.nextToken()
def toCHelp(self, tree=None, isGlobal=True): if tree is None: tree = self.tree self.incrDeferred() includes = Types.TmpCodegen() for (iter, i) in enumerate(tree): if type(i) is Tree.CreateAssign and i.extern and i.nodes[0].name == "_": i.compileToC(includes) for (iter, i) in enumerate(tree): if type(i) is Tree.FuncStart: funcStart = i funcBrace = i.owner.nodes[iter+1] funcBody = i.owner.nodes[iter+2] Func.forwardRef(funcStart, funcBrace, funcBody, self) for i in tree: if type(i) in [Tree.Type, Tree.Enum] or (type(i) is Tree.CreateAssign and i.extern and i.nodes[0].name == "_"): continue i.compileToC(self) self.addSemicolon(i) self.decrDeferred() return "".join(includes.out_parts)
def compileToC(self, codegen): self.typ.toCType() #if self.typ.package == "_global" and type(self.typ) in [Types.Struct, Types.Enum]: # codegen.append("NULL") # return package = self.typ.package if self.typ.package != "" else "_global" fullName = SimplifyAst.toUniqueID(package, self.typ.normalName, self.typ.remainingGen) if not type(self.typ) in [Types.Interface, Types.Pointer, Types.Alias, Types.Null]: if type(self.typ) is Types.T: typeof_none = Typeof(self, Types.Null()) Tree.castFrom(typeof_none.type, Parser.IType, typeof_none, "", codegen) else: codegen.append(f"{fullName}_get_type(NULL," + codegen.getContext() + ")") else: if type(self.typ) is Types.Pointer: codegen.append("_global_boxPointerType(_global_PointerTypeInit(") tmp = Typeof(self, self.typ.pType) Cast.castFrom(tmp.type, Parser.IType, tmp, "", codegen) codegen.append(",0)," + codegen.getContext() + ")") elif type(self.typ) is Types.Null: codegen.append(f"&None_Type") else: codegen.append(f"&{fullName}_Type")
def index(parser, unary=False): if not unary: unary = ExprParser.isUnary(parser, parser.lookBehind()) if not unary and len(parser.currentNode.nodes) == 0: Error.parseError(parser, "unexpected .") field = parser.nextToken() if not field.type in ["identifier", "i32"]: Error.parseError(parser, "field name must be an identifier") acess = Tree.Field(0, Types.Null(), parser) acess.unary = unary acess.number = field.type == "i32" field = field.token acess.owner = parser.currentNode acess.field = field if not unary: acess.addNode(parser.currentNode.nodes[-1]) parser.currentNode.nodes[-1] = acess else: parser.currentNode.addNode(acess)
def generics(parser, fname): generic = coll.OrderedDict() while parser.thisToken().token != "]": name = parser.nextToken().token typ = Types.T( name, Types.All, parser.package + "." + fname if parser.package != "_global" else fname) if parser.thisToken().type != "identifier": Error.parseError(parser, "type name must be an identifier") if not parser.nextToken().token in [":", ",", "]"]: Error.parseError(parser, "expecting ,") Scope.addVar(Tree.PlaceHolder(parser), parser, name, Scope.Type(False, typ)) if parser.thisToken().token == ":": parser.nextToken() interface = Types.parseType(parser) if not type(interface) in [ Types.Interface, Types.EnumT, Types.Assign ]: Error.parseError( parser, "Type variable " + name + ", must either be a interface or enumT, not " + str(interface)) typ.fromObj( Types.T( name, interface, parser.package + "." + fname if parser.package != "_global" else fname)) if parser.lookInfront().token != "]": parser.nextToken() generic[typ.name] = typ if parser.lookInfront().token == "]": parser.nextToken() break parser.nextToken() return generic
def createAndAssignParser(parser, imutable= True): # let i assignment node = parser.currentNode parser.nextToken() #get current token to position of = checkIt = False attachTyp = False if parser.lookInfront().token == ".": attachTyp = Types.parseType(parser, attachTyp= True) parser.nextToken() if not imutable or not type(node) is Tree.Root: Error.parseError(parser, "expecting =, not .") parser.nextToken() name = parser.thisToken() typ = None if parser.nextToken().token == ":": checkIt = True parser.nextToken() typ = Types.parseType(parser) parser.nextToken() elif parser.thisToken().token != "=": Error.parseError(parser, "expecting =, not"+parser.thisToken().token) n = Tree.CreateAssign(parser) parser.currentNode.addNode(n) parser.currentNode = n createParser(parser, name= name, typ= typ, check= checkIt, imutable= imutable, attachTyp= attachTyp) if attachTyp: assignParser(parser, name=attachTyp.name+"_"+name.token, package= attachTyp.package, init=True) else: assignParser(parser, name= name.token, init= True) parser.currentNode = node
def asOperator(parser): lastToken = parser.lookBehind() if not isUnary(parser, lastToken): op = Tree.Operator("as", parser) parser.nextToken() op.type = Types.parseType(parser) Parser.Opcode(parser, "as", lambda: operatorPop(parser, op, 1, unary=True)) else: Error.parseError(parser, "unexpected as operator ")
def castParser(parser): if len(parser.currentNode.nodes) == 0: Error.parseError(parser, "Unexpected cast") parser.nextToken() node = Tree.CastToType(parser) node.type = Types.parseType(parser) node.addNode(parser.currentNode.nodes[-1]) parser.currentNode.nodes[-1] = node node.owner = parser.currentNode
def __init__(self): self.nodes = [] self.type = Types.Null() self.names = [] self.global_target = "full" self.name = "" self.inline = False self.called = 0 self.perCall = 0 self.before = []
def loop(node): for iter in range(len(node.nodes)): i = node.nodes[iter] if not i.isEnd(): loop(i) if type(i) is Tree.FuncCall and i.inline and i.type != Types.Null( ): if len(i.nodes) == 2: node.nodes[iter] = i.nodes[1] node.nodes[iter].owner = node
def typeOfVar(node, parser, package, name): if name in parser.imports: return Types.Package() if package == parser.package: for i in parser.scope["_global"]: if name in i: return i[name].type for i in parser.scope[package]: try: return i[name].type except: pass node.error("variable "+name+" does not exist")
def loop(node): for i in node: if type(i) is Tree.If and i.type != Types.Null(): for n in i.nodes[::2]: if len(n.nodes) != 1: break else: if not i.isEnd(): loop(i) continue i.ternary = True if not i.isEnd(): loop(i)
def offsetof(parser): parser.nextToken() s = Tree.Offsetof(parser) typ = Types.parseType(parser) if parser.nextToken().token != ",": Error.parseError(parser, "Expecting comma") field = parser.nextToken() if field.type != "identifier": Error.parseError(parser, "Expecting identifier, not " + field.type) if not field.token in typ.types: Error.parseError(parser, str(typ) + " does not have the field " + field.token) if type(typ) is Types.Array and typ.both and field.token == "length": Error.parseError(parser, "Cannot get offsetof parameter length on static array") s.typ = typ s.field = field.token s.type = Types.I32(unsigned=True) parser.currentNode.addNode(s)
def bind(): if type(i.owner) is Tree.FuncCall and i.owner.nodes[0] == i: return typ = type(i.type) if typ is Types.FuncPointer: if not type(i.nodes[0].type) in [Types.Struct]: bind = Tree.ArrBind(i.field, self.nodes[0], self) bind.type = i.type else: bind = Tree.Bind(r, self.nodes[0], self) bind.type = Types.FuncPointer(self.type.args[1:], self.type.returnType, generic= self.type.generic, do= self.type.do) self.owner.nodes[count] = bind bind.owner = self.owner
def aliasParser(parser, name, decl, generic): parser.nextToken() typ = False while not Parser.isEnd(parser): if parser.thisToken().token != "\n" and parser.thisToken( ).type != "indent": if typ: Error.parseError( parser, "Unexpected token " + parser.thisToken().token) typ = Types.parseType(parser) parser.nextToken() alias = Types.Alias(parser.package, name, typ, generic) if decl: del parser.structs[parser.package][ name] # = Struct.Struct(name, args, fields, coll.OrderedDict()) parser.interfaces[parser.package][name] = alias Scope.decrScope(parser)
def traitParser(parser, name, decl, generic): interface = parser.interfaces[parser.package][name] meth = {} while not Parser.isEnd(parser): parser.nextToken() t = parser.thisToken() if t.token == "def": currentNode = parser.currentNode p = PlaceHolder(parser) parser.currentNode = p (methodName, names, types, brace, returnType, do) = FuncParser.funcHead(parser, decl, dontAdd=True, interfaceMethod=True) Scope.decrScope(parser) if methodName in meth: Error.parseError(parser, "Method " + methodName + ", already defined") meth[methodName] = brace.ftype parser.currentNode = currentNode parser.nextToken() else: Parser.declareOnly(parser, noVar=True) if len(parser.currentNode.nodes) > 0 and type( parser.currentNode.nodes[0]) is Tree.Create: Error.parseError( parser, "Interfaces are abstract interfaces which is why only methods are supported" ) names = {i.name: i.varType for i in parser.currentNode} #args = [i.varType for i in parser.currentNode] #fields = parser.currentNode.nodes if decl: i = interface.fromObj( Types.Interface(False, names, generic, parser.package + "." + name if parser.package != "_global" else name, methods=meth)) parser.interfaces[parser.package][name] = i Scope.decrScope(parser)
def addMethod(node, parser, attachTyp, name, func, otherNode=False): if type(attachTyp) is Types.Struct: parser.structs[attachTyp.package][attachTyp.normalName].addMethod( parser, name, func) elif type(attachTyp) is Struct.Struct: if type(func) is Types.FuncPointer: if len(func.args) == 0: node.error( "the function attached must have a first parameter with type " + attachTyp.package + "." + attachTyp.name) Types.Struct(False, attachTyp.name, attachTyp.types, attachTyp.package, attachTyp.generic).duckType(parser, func.args[0], node, otherNode, 0) attachTyp.addMethod(parser, name, func) else: node.error("Can't add method to " + str(attachTyp))
def ifBody(parser): cond = Tree.IfCondition(parser) parser.currentNode.addNode(cond) parser.currentNode = cond single = 0 parser.nodeBookmark.append(0) then = False while not (Parser.isEnd(parser) and then) : token = parser.nextToken() if token.token == "then" and not then: then = True ExprParser.endExpr(parser) parser.nodeBookmark.pop() block = Tree.Block(parser) cond.owner.addNode(block) parser.currentNode = block continue isEnd = Parser.maybeEnd(parser) if (token.token in ["else", "elif"]) and isEnd: break token = parser.thisToken() Parser.callToken(parser) next = parser.lookInfront() if (next.token == "else" or next.token == "elif") and isEnd: break ExprParser.endExpr(parser) cond.type = Types.Bool() parser.currentNode = cond.owner.owner
def traitParser(parser, name, decl, generic): meth = {} while not Parser.isEnd(parser): parser.nextToken() t = parser.thisToken() Parser.declareOnly(parser, noVar=True) names = {i.name: i.varType for i in parser.currentNode} args = [i.varType for i in parser.currentNode] fields = parser.currentNode.nodes if decl: del parser.structs[parser.package][name]# = Struct.Struct(name, args, fields, coll.OrderedDict()) i = Types.Interface(False, names, generic, parser.package+"."+name) parser.interfaces[parser.package][name] = i Scope.decrScope(parser)
def isUseless(i): if i.repl: return if type(i) in [Tree.ReadVar, Tree.ArrRead]: i.error("useless read") elif type(i) in [Tree.Int, Tree.Array, Tree.ArrRead, Tree.String, Tree.Bool, Tree.Float]: i.error("useless literal") elif type(i) is Tree.Operator and not i.kind == "<-": i.error("useless operator") elif type(i) is Tree.FuncCall and not i.nodes[0].type.do: if i.type != Types.Null(): i.error("not using return of function") try: t = i.curry if t: i.error("useless curry") t = i.partial if t: i.error("useless function application") except AttributeError: pass
def buildContext(parser): from TopCompiler import Parser contextType = parser.contextType # build context data type context = "_global_context" typesGeneratedByContext = "" from TopCompiler import Parser from TopCompiler import topc if type(Parser.IType) is Parser.TmpType: topc.global_parser.setTypeIntrospection() Parser.PointerType.toCType() types = {} for field in contextType: t = contextType[field] if t.package in parser.structs: types[field] = t.toCType() string = [] (typesGen, mainC) = Types.getGeneratedDataTypes("_context") parser.typesInContext = list(Types.genericTypes.keys()) Types.compiledTypes = coll.OrderedDict() Types.dataTypes = [] string.append(typesGen) string.append("struct _global_Context {\n") for field in contextType: string.append(f"{types[field]} {field};") string.append("};\n") string.append(f"struct _global_Context {context};") return ("".join(string), mainC)
def callMethodCode(node, name, typ, parser, unary): isMethod = False if type(typ) is Types.Pointer and type(typ.pType) is Types.Alias: method = typ.pType.typ.hasMethod(parser, name, isP=True) if method: typ = typ.pType.typ isMethod = True elif type(typ) is Types.Alias: method = typ.typ.hasMethod(parser, name, isP= isMethod) if method: typ = typ.typ if not node.type.isType(Types.Pointer): name += "ByValue" length = 1 if unary else 2 if type(typ) is Types.Pointer: typ = typ.pType package = "_global" if typ.package == "" else typ.package var = Tree.ReadVar(typ.normalName + "_" + name, True, node) var.package = package var.type = Types.FuncPointer([node.type] * length, node.type) while True: if typ.isType(Types.Pointer): typ = typ.pType else: break #if type(typ) in [Types.Struct, Types.Alias, Types.Enum]: var.replaced = typ.remainingGen return var
def compile(self, opt): self.contexts = ["(&_global_context)"] self.parser.package = self.filename self.parser.imports = self.parser.allImports[self.filename] PostProcessing.simplifyAst(self.parser, self.tree) includes = self.toCHelp() mainCode = "" mainCode += ("".join(self.main_parts)) outerCode = "".join(self.out_parts) forward_ref = "".join(self.header_parts) (generatedTypes, mainC) = Types.getGeneratedDataTypes(self.filename) Types.compiledTypes = coll.OrderedDict() Types.dataTypes = [] mainC = "".join(self.init_types) + "\n" + mainC headerCode = f"{generatedTypes}\n{forward_ref}" print_code = "printf(" + '"' + self.filename + '\\n");' cCode = f"{outerCode}\nvoid {self.filename}InitTypes() {{ \n {mainC} }}\nvoid {self.filename}Init() {{ \n{mainCode};\n}};" #print("To C took :", time() - t) f = open("lib/" + self.filename + ".c", mode="w") f.write(cCode) f.close() f = open("lib/" + self.filename + ".h", mode="w") f.write(headerCode) f.close() return includes
def loop(node, pos= 0): deleted = 0 for iter in range(len(node.nodes)): iter -= deleted i = node.nodes[iter] if not i.isEnd(): loop(i, iter) if type(i) is Tree.Else and len(i.owner.nodes) == 2: if i.owner.ternary: i.owner.owner.nodes[pos] = i.owner.nodes[1].nodes[0] else: i.owner.owner.nodes[pos] = i.owner.nodes[1] i.owner.owner.nodes[pos].noBrackets = True i.owner.owner.nodes[pos].owner = i.owner.owner if type(i) is Tree.IfCondition: if isConstant(i.nodes[0]): t = evaluate(i.nodes[0]) if (i.owner.ternary or i.owner.type == Types.Null()): if t: if i.owner.ternary: i.owner.owner.nodes[pos] = i.owner.nodes[1].nodes[0] else: i.owner.owner.nodes[pos] = i.owner.nodes[1] i.owner.owner.nodes[pos].noBrackets = True i.owner.owner.nodes[pos].owner = i.owner.owner else: del i.owner.nodes[0] del i.owner.nodes[0] deleted += 2
def loop(n, always=copy.deepcopy(tree)): count = 0 for i in n: if type(i) is Tree.FuncStart: if not type(n) is Tree.Root: Scope.addVar(i, parser, i.name, Scope.Type(True, i.ftype)) Scope.incrScope(parser) elif type(i) in [Tree.If, Tree.While]: Scope.incrScope(parser) if not i.isEnd(): loop(i) if type(i) is Tree.CreateAssign: if i.nodes[0].varType is None and i.nodes[0].name != "_": i.nodes[0].varType = i.nodes[1].nodes[0].type if i.nodes[0].attachTyp: MethodParser.addMethod( i, parser, i.nodes[0].attachTyp, i.nodes[0].name, i.nodes[1].nodes[0].type ) i.nodes[0].isGlobal = True else: Scope.addVar( i, parser, i.nodes[0].name, Scope.Type(i.nodes[0].imutable, i.nodes[1].nodes[0].type) ) i.nodes[0].isGlobal = Scope.isGlobal(parser, i.nodes[0].package, i.nodes[0].name) elif type(i) is Tree.FuncBody: Scope.decrScope(parser) def check(n): for c in n: if type(c) is Tree.FuncCall: if c.nodes[0].type.do and not i.do: c.nodes[0].error("cannot call function with side effects in a pure function") if not c.isEnd(): check(c) check(i) elif type(i) is Tree.Create: if not i.varType is None: Scope.addVar(i, parser, i.name, Scope.Type(i.imutable, i.varType)) i.isGlobal = Scope.isGlobal(parser, i.package, i.name) elif type(i) is Tree.ReadVar: if i.name in parser.imports: if not type(i.owner) is Tree.Field: i.error("expecting .") elif type(i.type) is Tree.Type: i.error("unexpected type " + str(i.type)) i.type = Scope.typeOfVar(i, parser, i.package, i.name) self = i self.imutable = not Scope.isMutable(parser, self.package, self.name) self.isGlobal = Scope.isGlobal(parser, self.package, self.name) self.package = Scope.packageOfVar(parser, parser.package, self.name) elif type(i) is Tree.Field: def bind(): if type(i.owner) is Tree.FuncCall and i.owner.nodes[0] == i: return typ = type(i.type) if typ is Types.FuncPointer: if not type(i.nodes[0].type) in [Types.Struct]: bind = Tree.ArrBind(i.field, self.nodes[0], self) bind.type = i.type else: bind = Tree.Bind(r, self.nodes[0], self) bind.type = Types.FuncPointer(self.type.args[1:], self.type.returnType) self.owner.nodes[count] = bind bind.owner = self.owner typ = i.nodes[0].type t = i.nodes[0] if type(typ) is Types.Package: i.indexPackage = True i.type = Scope.typeOfVar(i, parser, i.nodes[0].name, i.field) i.nodes[0].package = i.nodes[0].name i.nodes[0].name = "" else: if type(typ) is Types.FuncPointer: i.error("type " + str(typ) + " has no field " + i.field) struct = typ self = i try: i.type = struct.types[self.field] if type(i.nodes[0].type) is Types.Array: bind() except KeyError: method = struct.hasMethod(parser, self.field) if not method: self.error("type " + str(typ) + " has no field " + self.field) self.type = method r = Tree.ReadVar(typ.normalName + "_" + self.field, self.type, self) r.type = self.type r.package = typ.package if not typ.package == "_global" else "" r.owner = self.owner if type(i.owner) is Tree.FuncCall and i.owner.nodes[0] == i: self.owner.nodes[0] = r self.owner.nodes.insert(1, self.nodes[0]) count += 1 else: bind() elif type(i) is Tree.Operator: if i.kind == "|>": self = i if len(self.nodes) != 2: self.error("chain operator cannot be curried") a = self.nodes[0].type b = self.nodes[1].type if not type(a) is Types.FuncPointer: self.nodes[0].error("function chain operator works on functions only") if not type(b) is Types.FuncPointer: self.nodes[1].error("function chain operator works on functions only") if len(b.args) == 0: self.nodes[1].error("function must take atleast one argument") if [a.returnType] != b.args: self.nodes[1].error( "function arguments don't match returnType of piped function: " + str(a.returnType) + " and " + ", ".join([str(i) for i in b.args]) ) self.type = Types.FuncPointer(a.args, b.returnType) elif i.kind == "concat": stringable = Types.Interface(False, {"toString": Types.FuncPointer([], Types.String(0))}) for c in i: stringable.duckType(parser, c.type, Tree.PlaceHolder(c), c, 0) i.type = Types.String(0) i.partial = False i.curry = False else: if len(i.nodes) == 0: import collections as coll if i.kind in ["not", "or", "and"]: T = Types.Bool() gen = [] else: T = Types.T("T", Types.All, "Operator") gen = [("T", Types.All)] i.type = Types.FuncPointer([T, T], T, coll.OrderedDict(gen)) if i.kind != "not": i.unary = False else: partial = False if type(i.nodes[0]) is Tree.Under: partial = True startType = False else: startType = i.nodes[0].type if i.kind in ["not", "and", "or"]: if startType != Types.Bool(): i.nodes[0].error("logical operator " + i.kind + " only works on boolean") for c in i.nodes[1:]: if type(c) is Tree.Under: partial = True else: if not partial and c.type != startType: c.error("Type mismatch " + str(startType) + " and " + str(c.type)) startType = c.type i.partial = partial typ = startType if i.kind in ["==", "!=", "not", "and", "or", "<", ">", "<=", ">="]: typ = Types.Bool() if i.curry or i.partial: normal = (1 if i.unary else 2) - len(i.nodes) for c in i.nodes: if type(c) is Tree.Under: normal += 1 if not startType: import collections as coll if i.kind in ["not", "or", "and"]: T = Types.Bool() gen = [] else: T = Types.T("t", Types.All, "Operator") gen = [("t", Types.All)] typ = Types.FuncPointer([T, T], T, coll.OrderedDict(gen)) if normal == (1 if i.unary else 2): i.partial = False i.curry = True i.nodes = [] else: typ = Types.FuncPointer([startType] * normal, typ) i.type = typ i.opT = startType elif type(i) is Tree.FuncCall: partial = False if not type(i.nodes[0].type) is Types.FuncPointer: i.nodes[0].error("type " + str(i.nodes[0].type) + " is not callable") args = i.nodes[0].type.args newArgs = [] if len(args) < len(i.nodes) - 1: c = str(len(i.nodes) - 1 - len(args)) i.nodes[-1].error(("1 argument" if c == "1" else c + " arguments") + " too many") generics = {} for iter in range(len(i.nodes[1:])): if type(i.nodes[iter + 1]) is Tree.Under: partial = True newArgs.append(iter) else: normalTyp = args[iter] myNode = i.nodes[iter + 1] normalNode = i if Types.isGeneric(normalTyp): normalTyp = resolveGen(normalTyp, myNode.type, generics, parser) normalTyp.duckType(parser, myNode.type, i, myNode, iter + 1) newArgs = [Types.replaceT(args[c], generics) for c in newArgs] if len(args) > len(i.nodes) - 1: i.curry = True i.type = Types.FuncPointer( [Types.replaceT(c, generics) for c in args[: len(args) - len(i.nodes) - 1]], Types.replaceT(i.nodes[0].type.returnType, generics), ) elif not partial: i.type = Types.replaceT(i.nodes[0].type.returnType, generics) else: i.partial = True i.type = Types.FuncPointer(newArgs, Types.replaceT(i.nodes[0].type.returnType, generics)) elif type(i) is Tree.If: ElseExpr.checkIf(parser, i) elif type(i) is Tree.Block: i.type = i.nodes[-1].type if len(i.nodes) > 0 else Types.Null() elif type(i) is Tree.Assign: if not (type(i.owner) is Tree.CreateAssign and i.owner.nodes[0].varType is None): normalNode = i.owner.nodes[0] if i.init else i.nodes[1] normalTyp = i.owner.nodes[0].varType if i.init else i.nodes[0].type myNode = i.nodes[0] if i.init else i.nodes[1] normalTyp.duckType(parser, myNode.type, normalNode, myNode, (0 if i.init else 1)) elif type(i) is Tree.Tuple: if len(i.nodes) == 0: i.error("unexpected )") i.type = i.nodes[0].type elif type(i) is Tree.Array: arr = i if len(i.nodes) > 0: if arr.init or arr.range: if arr.nodes[0].type != Types.I32(): arr.nodes[0].error("expecting integer for range start, not " + str(arr.nodes[1].type)) if arr.range: if arr.nodes[1].type != Types.I32(): arr.nodes[1].error("expecting integer for range end, not " + str(arr.nodes[1].type)) typ = Types.I32() else: typ = arr.nodes[1].type else: typ = arr.nodes[0].type if typ == Types.Null(): arr.error("array elements must be non none") for c in arr.nodes[1:]: if typ != c.type: c.error("type mismatch " + str(typ) + " and " + str(c.type)) arr.type = Types.Array(arr.mutable, typ) elif type(i) is Tree.InitPack: parser.imports.append(i.package) elif type(i) is Tree.InitStruct: s = i.s name = s.name args = s.fieldType if len(args) < len(i.nodes): c = str(len(i.nodes) - 1 - len(args)) i.nodes[-1].error(("1 argument" if c == "1" else c + " arguments") + " too many") gen = {} for iter in range(len(i.nodes)): normalTyp = args[iter] myNode = i.nodes[iter] normalNode = i if Types.isGeneric(normalTyp): normalTyp = resolveGen(normalTyp, myNode.type, gen) normalTyp.duckType(parser, myNode.type, i, myNode, iter) i.type = Types.Struct(i.mutable, name, s.types, i.package, gen) elif type(i) is Tree.ArrRead: if not type(i.nodes[0].type) is Types.Array: i.nodes[0].error("Type " + str(i.nodes[0].type) + "is not indexable") arrRead = i if len(arrRead.nodes) != 2 or not arrRead.nodes[1].type == Types.I32(): i.nodes[1].error("expecting single integer index") arrRead.type = arrRead.nodes[0].type.elemT elif type(i) is Tree.Generic: if not Types.isGeneric(i.nodes[0].type): i.nodes[0].error("expecting generic type") gen = i.nodes[0].type.generic if len(gen) > len(i.generic): i.error("missing " + str(len(gen) - len(i.generic)) + " generic parameters") elif len(gen) < len(i.generic): i.error(str(len(i.generic) - len(gen)) + " too many generic parameters") v = list(gen.keys()) replace = {v[index]: c for index, c in enumerate(i.generic)} for index, c in enumerate(gen): gen[c].duckType(parser, i.generic[index], i.nodes[0], i, 0) i.type = Types.replaceT(i.nodes[0].type, replace) i.nodes[0].type.duckType(parser, i.type, i, i.nodes[0]) if type(i) in [Tree.If, Tree.While]: Scope.decrScope(parser) count += 1
def funcHead(parser, decl= False, dontAdd= False, method= False, attachTyp = False): Scope.incrScope(parser) if parser.tokens[parser.iter+2].token == ".": if attachTyp: Error.parseError(parser, "unexpected .") parser.nextToken() name = parser.thisToken().token parser.nextToken() try: attachTyp = Types.Struct(False, name, parser.structs[parser.package][name].types, parser.package, {}) except KeyError: Error.parseError(parser, "no attachable data structure found, called "+name) return funcHead(parser, decl, dontAdd, True, attachTyp) name = parser.nextToken() if name.type != "identifier": Error.parseError(parser, "function name must be of type identifier, not "+name.type) parser.nextToken() name = name.token g = {} if parser.thisToken().token != "(": if parser.thisToken().token == "[": g = generics(parser, (str(attachTyp)+"." if method else "")+name) if parser.thisToken().token == ".": if attachTyp: Error.parseError(parser, "unexpected .") if not Scope.varExists(parser, parser.package, name): Error.parseError(parser, "cannot attach method to unknown type main."+name) try: attachTyp = Types.Struct(False, name, parser.structs[parser.package][name].types, parser.package, parserMethodGen(parser, g, parser.structs[parser.package][name])) except KeyError: Error.parseError(parser, "no attachable data structure found, called " + name) return funcHead(parser, decl, dontAdd, True, attachTyp) if parser.thisToken().token != "(": Error.parseError(parser, "expecting (") header = Tree.FuncStart(name, Types.Null(), parser) header.package = parser.package parser.currentNode.addNode(header) brace = Tree.FuncBraceOpen(parser) brace.name = name brace.package = parser.package parser.currentNode.addNode(brace) parser.currentNode = brace if method: if not type(parser.currentNode.owner) is Tree.Root and not decl: Error.parseError(parser, "method extension must be in out-most scope") typ = attachTyp self = parser.nextToken() if self.type != "identifier": Error.parseError(parser, "binding name must be identifier not "+self.type) self = self.token selfNode = Tree.Create(self, typ, parser) selfNode.package = parser.package selfNode.imutable = True parser.currentNode.addNode(selfNode) if not parser.lookInfront().token in [")", ","]: Error.parseError(parser, "expecting comma not "+parser.thisToken().token) if name[0].lower() != name[0]: Error.parseError(parser, "function name must be lower case") returnType = Types.Null() parser.paren += 1 parser.nextToken() while parser.paren != parser.parenBookmark[-1] : b = parser.thisToken().token if b == ",": parser.nextToken() continue elif b == ")": parser.paren -= 1 parser.nextToken() continue elif b == "(": Error.parseError(parser, "unexpected (") Parser.declareOnly(parser) parser.nextToken() t = parser.thisToken() do = False if t.token != "=" and t.token != "do": returnType = Types.parseType(parser) t = parser.nextToken() if t.token != "=" and t.token != "do": Error.parseError(parser, "expecting = or do") if t.token == "do": do = True parser.currentNode = brace.owner names = [i.name for i in brace.nodes] types = [i.varType for i in brace.nodes] func = Types.FuncPointer( types, returnType, g, do ) if method: Scope.decrScope(parser) header.method = True header.types = types[1:] header.attachTyp = attachTyp header.normalName = name header.name = attachTyp.normalName+"_"+header.normalName MethodParser.checkIfOperator(parser, attachTyp, name, func) if decl: MethodParser.addMethod(brace, parser, attachTyp, name, func) return attachTyp.normalName+"_"+name, names, types, header, returnType, do parser.func[parser.package][name] = func header.ftype = Types.FuncPointer(types, returnType, g) if decl: if not dontAdd: Scope.addFunc(header, parser, name, Types.FuncPointer(types, returnType, g, do)) return name, names, types, header, returnType, do