def funcBody(parser, name, names, types, header, returnType, do): body = Tree.FuncBody(parser) body.name = name body.returnType = returnType body.package = parser.package body.do = do parser.currentNode.addNode(body) parser.currentNode = body for i in range(len(names)): n = Tree.InitArg(names[i], body) n.package = parser.package n.varType = types[i] n.imutable = not Scope.isMutable(parser, parser.package, names[i]) body.addNode(n) parser.nextToken() Parser.callToken(parser) #incase next case is newline while not Parser.isEnd(parser): parser.nextToken() t = parser.thisToken().token Parser.callToken(parser) ExprParser.endExpr(parser) parser.currentNode = body.owner Scope.decrScope(parser)
def validate(self, parser): checkUseless(self) actReturnType = Types.Null() if type(self.returnType) is str: Scope.decrScope(parser) return if self.returnType == Types.Null(): pass elif len(self.nodes) > 0: if self.nodes[-1].type == Types.Null(): actReturnType = Types.Null() else: actReturnType = self.nodes[-1].type returnType = self.returnType name = self.name import AST as Tree try: returnType.duckType( parser, actReturnType, self, self.nodes[-1] if len(self.nodes) > 0 else Tree.Under(self), 0) except EOFError as e: Error.beforeError(e, "Return Type: ") if self.do: transform(self) Scope.decrScope(parser)
def funcBody(parser, name, names, types, brace, returnType, do): body = Tree.FuncBody(parser) body.name = name body.returnType = returnType body.package = parser.package body.do = do brace.body = body parser.currentNode.addNode(body) parser.currentNode = body for i in range(len(names)): n = Tree.InitArg(names[i], body) n.package = parser.package n.varType = types[i] n.imutable = not Scope.isMutable(parser, parser.package, names[i]) body.addNode(n) parser.nextToken() Parser.callToken(parser) #incase next case is newline while not Parser.isEnd(parser): parser.nextToken() t = parser.thisToken().token Parser.callToken(parser) ExprParser.endExpr(parser) parser.currentNode = body.owner Scope.decrScope(parser) return body
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 typeParser(parser, decl= False): name = parser.nextToken() Scope.incrScope(parser) if name.type != "identifier": Error.parseError(parser, "type name must be an identifier") name = name.token if name[0].lower() == name[0]: Error.parseError(parser, "struct name must be upper case") import collections as coll gen = coll.OrderedDict() if parser.nextToken().token == "[": gen = FuncParser.generics(parser, name) if parser.thisToken().token != "=": if parser.thisToken().token == "with": tmp = parser.currentNode parser.currentNode = Tree.PlaceHolder(parser) Interface.traitParser(parser, name, decl, gen) parser.currentNode = tmp return Error.parseError(parser, "expecting =") tmp = parser.currentNode typ = Tree.Type(parser.package, name, parser) typ.package = parser.package typ.normalName = name tmp.addNode(typ) parser.currentNode = typ while not Parser.isEnd(parser): parser.nextToken() Parser.declareOnly(parser, noVar=True) args = [i.varType for i in parser.currentNode] fields = parser.currentNode.nodes typ.fields = [i.name for i in typ] typ.nodes = [] parser.currentNode = tmp if decl: meth = parser.structs[parser.package][name].methods parser.structs[parser.package][name] = Struct(name, args, fields, gen) parser.structs[parser.package][name].methods = meth parser.structs[parser.package][name].package = parser.package Scope.decrScope(parser)
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 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 funcBody(parser, name, names, types, brace, returnType, do): body = Tree.FuncBody(parser) body.name = name body.returnType = returnType body.package = parser.package body.do = do body.types = types brace.body = body parser.currentNode.addNode(body) parser.currentNode = body if not parser.sc and not SimplifyAst.isGenericFunc(brace): body.sc = False if parser.nextToken().token == "\n": Parser.callToken(parser) while not Parser.isEnd(parser): if parser.nextToken().token == "\n": Parser.callToken(parser) parser.currentNode = body.owner Scope.decrScope(parser) #print("should not compile", name) return body for i in range(len(names)): n = Tree.InitArg(names[i], parser) n.package = parser.package n.varType = types[i] n.imutable = not Scope.isMutable(parser, parser.package, names[i]) body.addNode(n) parser.nextToken() Parser.callToken(parser) #incase next case is newline while not Parser.isEnd(parser): parser.nextToken() t = parser.thisToken().token Parser.callToken(parser) ExprParser.endExpr(parser) parser.currentNode = body.owner Scope.decrScope(parser) return body
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.interfaces[parser.package][name] = i Scope.decrScope(parser)
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 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 check(self, parser): if self.already: return name = ("do " if do else "") + "|" + ", ".join( [i.name for i in self.args]) + "| -> " + self.returnType.name self.already = True for i in self.args: if type(i) is Unknown: self.name = name return from TopCompiler import TypeInference from TopCompiler import Scope Scope.incrScope(parser) for (a, b) in zip(func.nodes[0], func.type.args): a.varType = b if type(self.returnType) is Unknown: TypeInference.infer(parser, func.nodes[0]) TypeInference.infer(parser, func.nodes[1]) Scope.decrScope(parser) if len(func.nodes[1]) == 0: typ = Types.Null() else: typ = func.nodes[1].nodes[-1].type self.returnType = typ func.nodes[1].returnType = typ else: TypeInference.infer(parser, func) name = ("do " if do else "") + "|" + ", ".join( [i.name for i in self.args]) + "| -> " + self.returnType.name self.name = name
def validate(self, parser): checkUseless(self) actReturnType = Types.Null() if self.returnType == Types.Null(): pass elif len(self.nodes) > 0: if self.nodes[-1].type == Types.Null(): actReturnType = Types.Null() else: actReturnType = self.nodes[-1].type returnType = self.returnType name = self.name import AST as Tree try: returnType.duckType(parser,actReturnType,self, self.nodes[-1] if len(self.nodes) > 0 else Tree.Under(self),0) except EOFError as e: Error.beforeError(e, "Return Type: ") Scope.decrScope(parser)
def funcHead(parser): (name, names, types, header, returnType, do) = FuncParser.funcHead(parser, True) Scope.decrScope(parser)
def typeParser(parser, decl=False): name = parser.nextToken() Scope.incrScope(parser) if name.type != "identifier" and name.token != "ext": Error.parseError(parser, "type name must be an identifier") externalStruct = False if name.token == "ext": externalStruct = True name = parser.nextToken() if name.type != "identifier" and name.token != "ext": Error.parseError(parser, "type name must be an identifier") name = name.token if name[0].lower() == name[0] and not externalStruct: Error.parseError(parser, "struct name must be upper case") import collections as coll gen = coll.OrderedDict() if parser.nextToken().token == "[": if externalStruct: Error.parseError(parser, "External structs cannot be generic") gen = FuncParser.generics(parser, name) if parser.thisToken().token != "=": if parser.thisToken().token in ["with", "either", "is"]: if externalStruct: Error.parseError( parser, "Can only define external structs not interfaces, enums or aliases" ) tmp = parser.currentNode if parser.thisToken().token == "either": Enum.enumParser(parser, name, decl, gen) elif parser.thisToken().token == "is": Alias.aliasParser(parser, name, decl, gen) else: parser.currentNode = Tree.PlaceHolder(parser) Interface.traitParser(parser, name, decl, gen) parser.currentNode = tmp return Error.parseError(parser, "expecting =") tmp = parser.currentNode typ = Tree.Type(parser.package, name, parser) typ.package = parser.package typ.normalName = name typ.externalStruct = externalStruct tmp.addNode(typ) parser.currentNode = typ while not Parser.isEnd(parser): parser.nextToken() Parser.declareOnly(parser, noVar=True) args = [i.varType for i in parser.currentNode] fields = parser.currentNode.nodes if not decl: using = parser.structs[parser.package][name].using for i in parser.currentNode: if type(i) is Tree.Using: using.append(i.name) typ.fields = [i.name for i in typ] typ.args = args typ.generics = gen typ.nodes = [] parser.currentNode = tmp if decl: meth = parser.structs[parser.package][name].methods _types = parser.structs[parser.package][name]._types #if name == "Channel": # print("Channel make") # print(id(_types)) parser.structs[parser.package][name] = Struct(name, args, fields, gen, typ, parser.package) tmp = parser.structs[parser.package][name]._types parser.structs[parser.package][name].methods = meth parser.structs[parser.package][name].package = parser.package parser.structs[parser.package][name]._types = _types parser.structs[parser.package][name].externalStruct = externalStruct _types.update(tmp) Scope.changeType(parser, name, parser.structs[parser.package][name]) typ.struct = parser.structs[parser.package][name] Scope.decrScope(parser)
def loop(n, o_iter): count = 0 for i in n: if type(n) is Tree.Root: o_iter += 1 if not sc and type(i) in [Tree.FuncStart, Tree.FuncBraceOpen, Tree.FuncBody]: count += 1 continue 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.Block, Tree.While]: Scope.incrScope(parser) if not (i.isEnd() or type(i) is Tree.MatchCase or (type(i) is Tree.Block and type(i.owner) is Tree.Match)): if not type(i) is Tree.Lambda: loop(i, o_iter) if type(i) is Tree.Match: typ = i.nodes[0].type first = False for c in range(1,len(i.nodes),2): body = i.nodes[c+1] Scope.incrScope(parser) Enum.checkCase(parser, i.nodes[c].nodes[0], typ, True) loop(body, o_iter) body.type = body.nodes[-1].type if len(body.nodes) > 0 else Types.Null() Scope.decrScope(parser) if first: if body.type != first: (body.nodes[-1] if len(body.nodes) > 0 else body).error( "type mismatch in arms of match, " + str(body.type) + " and " + str(first)) else: if len(i.nodes[2].nodes) > 0: first = i.nodes[2].nodes[-1].type else: first = Types.Null() i.nodes[2].type = first Enum.missingPattern(typ, i) i.type = first if first else Types.Null() elif type(i) is Tree.CreateAssign: if i.nodes[0].varType is None and i.nodes[0].name != "_": if i.extern: i.error("expecting type declaration, for external variable declaration") 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.global_target)) i.nodes[0].isGlobal = Scope.isGlobal(parser, i.nodes[0].package, i.nodes[0].name) if i.global_target != parser.global_target: #print(i.nodes[0].name) Scope.changeTarget(parser, i.nodes[0].name, i.global_target) #print("this variable can only be used in a specific target", i.global_target) elif type(i) is Tree.FuncBody: Scope.decrScope(parser) def check(n, _i): for c in n: if type(c) is Tree.FuncCall: if c.nodes[0].type.do and not _i.do and not c.partial and not c.curry: c.nodes[0].error("cannot call function with side effects in a pure function") if type(c) is Tree.FuncBody: check(c, c) elif not c.isEnd(): check(c, _i) check(i, i) if i.global_target != parser.global_target: #print(i.name) Scope.changeTarget(parser, i.name, i.global_target) #print("this function can only be used in a specific target", i.global_target) 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.owner.global_target)) i.isGlobal = Scope.isGlobal(parser, i.package, i.name) elif type(i) is Tree.ReadVar: if i.name == "newAtom": if not (type(i.owner) is Tree.FuncCall and i.owner.nodes[0] == i and not i.owner.curry and not i.owner.partial): i.error("expecting function call, with no currying or partial application") if parser.atoms > 0: i.error("can only have one atom per application") if not (type(i.owner) is Tree.Assign and type(i.owner.owner) is Tree.InitStruct and i.owner.nodes[0] == i): 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) target = Scope.targetOfVar(i, parser, parser.package, self.name) if target != parser.global_target: root = tree.nodes[o_iter] if type(root) is Tree.FuncBody: tree.nodes[o_iter-1].global_target = target tree.nodes[o_iter-2].global_target = target root.global_target = target elif tree.nodes[o_iter].global_target != target and target != "full": realT = tree.nodes[o_iter].global_target i.error("variable "+i.name+" is bound to target "+realT+" however, this variable is from target "+target) 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, generic= self.type.generic, do= self.type.do) 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) target = Scope.targetOfVar(i, parser, i.nodes[0].name, i.field) if target != parser.global_target: root = tree.nodes[o_iter] if type(root) is Tree.FuncBody: tree.nodes[o_iter-1].global_target = target tree.nodes[o_iter-2].global_target = target root.global_target = target 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 == "|>" or 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 i.kind == ">>": if not type(a) is Types.FuncPointer: self.nodes[1].error("right argument must be a function") a = a.returnType if not type(b) is Types.FuncPointer: self.nodes[1].error("left argument must be a function") if len(b.args) != 1: self.nodes[1].error("expecting one function argument that matches return type of piped function") try: b.args[0].duckType(parser, a, self.nodes[0], self.nodes[1], 1) except EOFError as e: if i.kind == ">>": Error.beforeError(e, "Function combining with: ") else: Error.beforeError(e, "Function piping to: ") if i.kind == ">>": a = self.nodes[0].type self.type = Types.FuncPointer(a.args, b.returnType, do= a.do or b.do, generic=a.generic) else: self.type = b.returnType elif i.kind == "<-": if i.unary: try: meth = i.nodes[0].type.types["unary_read"] except: meth = i.nodes[0].type.hasMethod(parser, "unary_read") if meth: i.type = meth.returnType i.opT = i.nodes[0].type else: try: meth = i.nodes[0].type.types["unary_read"] except: meth = i.nodes[0].type.hasMethod(parser, "unary_read") elif i.kind == "concat": stringable = Types.Interface(False, {"toString": Types.FuncPointer([], Types.String(0))}) for c in i: stringable.duckType(parser,c.type,i,i,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 = [("Operator.T", Types.All)] returnT = T if i.kind in ["==", "!=", "not", "and", "or", "<", ">", "<=", ">="]: returnT = Types.Bool() i.opT = T i.type = Types.FuncPointer([T,T], returnT, 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: c = i if i.nodes[0].name == "newAtom": i = i.nodes[0] if parser.hotswap: parser.atomTyp.duckType(parser, i.owner.nodes[1].type, i.owner.nodes[1], i, 0) f = Tree.Field(0, i.owner.nodes[1].type, i) f.field = "arg" f.type = parser.atomTyp r = Tree.ReadVar("previousState", True, i) r.package = "" f.addNode(r) i.owner.nodes[1] = f f.owner = i.owner parser.atomTyp = i.owner.nodes[1].type parser.atoms += 1 i = c 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") do = i.nodes[0].type.do returnType = i.nodes[0].type.returnType args = i.nodes[0].type.args newArgs = [] if len(args) < len(i.nodes)-1: c = str(len(i.nodes) - 1 - len(args)) i.error(("1 argument" if c == "1" else c+" arguments")+" too many, expecting "+str(len(args))+" arguments") generics = {} for iter in range(len(i.nodes[1:])): if type(i.nodes[iter+1]) is Tree.Under: partial = True newArgs.append(iter) else: xnormalTyp = args[iter] myNode = i.nodes[iter+1] normalNode = i if Types.isGeneric(xnormalTyp): normalTyp = resolveGen(xnormalTyp, myNode.type, generics, parser) else: normalTyp = xnormalTyp normalTyp.duckType(parser, myNode.type, i, myNode, iter + 1) """ try: normalTyp.duckType(parser, myNode.type, i, myNode, iter+1) except EOFError as e: normalTyp = resolveGen(xnormalTyp, myNode.type, {}, parser) print(e) """ 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(i.nodes)-1:]], Types.replaceT(i.nodes[0].type.returnType, generics), do= do) 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), returnType, do= do) 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 type(i.owner) is Tree.InitStruct: pass elif not (type(i.owner) is Tree.CreateAssign and i.owner.nodes[0].varType is None): if type(i.owner) is Tree.CreateAssign and i.owner.extern: if not type(i.nodes[0].type) is Types.String: i.error("expecting String") else: 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 )") elif len(i.nodes) > 1: i.type = Types.Tuple([c.type for c in i]) else: 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") count = 0 for c in arr.nodes[1:]: if typ != c.type: try: typ.duckType(parser, c.type, i, c, count) except EOFError as e: Error.beforeError(e, "Element type in array: ") count += 1 arr.type = Types.Array(arr.mutable, typ) elif type(i) is Tree.InitPack: parser.imports.append(i.package) elif type(i) is Tree.InitStruct: unary = i.unary if not unary: typ = i.constructor.type i.typ = typ assign = True if type(typ) is Struct.Struct: s = typ assign = False i.paramNames = Struct.offsetsToList(s.offsets) elif type(typ) is Types.Struct: assign = True s = typ else: i.constructor.error("type "+str(typ)+" can not be used as a constructor") i.s = s name = s.name if len(s.types) < len(i.nodes) - 1: c = str(len(i.nodes) - 1 - len(s.types)) i.error(("1 argument" if c == "1" else c + " arguments") + " too many") elif not assign and len(s.types) > len(i.nodes) - 1: c = str(len(s.types) + 1 - len(i.nodes)) i.error(("1 argument" if c == "1" else c + " arguments") + " too few") else: assign = True gen = {} randomOrder = False order = {} for iter in range(0 if unary else 1, len(i.nodes)): if type(i.nodes[iter]) is Tree.Assign: randomOrder = True elif assign: i.nodes[iter].error("expecting =") if not randomOrder: order[i.paramNames[iter-1]] = i.nodes[iter] myNode = i.nodes[iter] normalTyp = s.fieldType[iter-1] else: if not type(i.nodes[iter]) is Tree.Assign: i.nodes[iter].error("positional argument follows keyword argument") if i.nodes[iter].nodes[0].name in order: i.nodes[iter].nodes[0].error("duplicate parameter") order[i.nodes[iter].nodes[0].name] = i.nodes[iter] myNode = i.nodes[iter].nodes[1] xname = i.nodes[iter].nodes[0].name if not unary: try: normalTyp = s.types[xname] except KeyError: i.nodes[iter].nodes[0].error("type "+str(s)+" does not have the field "+ xname) normalNode = i if not unary: if Types.isGeneric(normalTyp): normalTyp = resolveGen(normalTyp, myNode.type, gen, parser) normalTyp.duckType(parser, myNode.type, i, myNode, iter) if not assign: for c in order: i.nodes[s.offsets[c]] = order[c] i.assign = assign if i.assign: if unary: types = {c: order[c].nodes[1].type for c in order} i.type = Types.Interface(False, types) else: i.type = typ else: i.type = Types.Struct(i.mutable, name, s.types, i.package, gen) elif type(i) is Tree.ArrRead: if not len(i.nodes) == 1: 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 else: i.error("expecting integer expression") 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): g = gen[c].type if type(gen[c]) is Types.T else gen[c] g.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]) elif type(i) is Tree.Lens: lensType = Types.Interface(False, { "query": Types.FuncPointer([i.lensType], i.nodes[0].type), "set": Types.FuncPointer([i.lensType, i.nodes[0].type], i.lensType), }) i.type = lensType elif type(i) is Tree.Block: if len(i.nodes) > 0: i.type = i.nodes[-1].type if type(i) in [Tree.Block, Tree.While]: Scope.decrScope(parser) count += 1
def parseLens(parser): #parser.nextToken() Scope.incrScope(parser) #lensType = Types.parseType(parser) Scope.decrScope(parser) place = Tree.Place(parser) lens = Tree.Lens(parser) lens.place = place parser.currentNode.addNode(lens) parser.currentNode = lens lens.addNode(place) #parser.nextToken() while not Parser.isEnd(parser): parser.nextToken() Parser.callToken(parser) ExprParser.endExpr(parser) parser.currentNode = lens.owner B = Types.T("B", Types.All, "Lens") 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) lens_typ = loop(lens.nodes[0]) A = Types.T("A", lens_typ, "Lens") self = Types.Interface(False, { "query": Types.FuncPointer([A], B), "set": Types.FuncPointer([A, B], A), "toString": Types.FuncPointer([], Types.String(0)), }, coll.OrderedDict([("Lens.A", A), ("Lens.B", B)]), name="Lens") Lens = Types.Interface(False, { "query": Types.FuncPointer([A], B), "set": Types.FuncPointer([A, B], A), "toString": Types.FuncPointer([], Types.String(0)), }, coll.OrderedDict([("Lens.A", A), ("Lens.B", B)]), name="Lens") #lens.type = Types.Interface(False, { # # "query": Types.FuncPointer([i.lensType], i.nodes[0].type), # "set": Types.FuncPointer([i.lensType, i.nodes[0].type], i.lensType), #}) lens.type = Lens
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: try: attachTyp = parser.interfaces[parser.package][name] if not type(attachTyp) is Types.Enum: Error.parseError( parser, "no attachable data structure found, called " + name) 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, (attachTyp.normalName + "." 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: try: tmp = parser.interfaces[parser.package][name] if not type(tmp) is Types.Enum: raise KeyError attachTyp = Types.replaceT( tmp, parserMethodGen(parser, g, tmp)) 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 (") if method and not type(parser.currentNode) is Tree.Root and not decl: Error.parseError(parser, "method extension must be in out-most scope") 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: 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) header.do = 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, brace, returnType, do #parser.func[parser.package][name] = func header.ftype = func if decl: if not dontAdd: Scope.addFunc(header, parser, name, func) return name, names, types, brace, returnType, do
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 typeParser(parser, decl= False): name = parser.nextToken() Scope.incrScope(parser) if name.type != "identifier": Error.parseError(parser, "type name must be an identifier") name = name.token if name[0].lower() == name[0]: Error.parseError(parser, "struct name must be upper case") import collections as coll gen = coll.OrderedDict() if parser.nextToken().token == "[": gen = FuncParser.generics(parser, name) if parser.thisToken().token != "=": if parser.thisToken().token in ["with", "either", "is"]: tmp = parser.currentNode if parser.thisToken().token == "either": Enum.enumParser(parser, name, decl, gen) elif parser.thisToken().token == "is": Alias.aliasParser(parser, name, decl, gen) else: parser.currentNode = Tree.PlaceHolder(parser) Interface.traitParser(parser, name, decl, gen) parser.currentNode = tmp return Error.parseError(parser, "expecting =") tmp = parser.currentNode typ = Tree.Type(parser.package, name, parser) typ.package = parser.package typ.normalName = name tmp.addNode(typ) parser.currentNode = typ while not Parser.isEnd(parser): parser.nextToken() Parser.declareOnly(parser, noVar=True) args = [i.varType for i in parser.currentNode] fields = parser.currentNode.nodes typ.fields = [i.name for i in typ] typ.nodes = [] parser.currentNode = tmp if decl: meth = parser.structs[parser.package][name].methods _types = parser.structs[parser.package][name]._types parser.structs[parser.package][name] = Struct(name, args, fields, gen, typ, parser.package) tmp = parser.structs[parser.package][name]._types parser.structs[parser.package][name].methods = meth parser.structs[parser.package][name].package = parser.package parser.structs[parser.package][name]._types = _types _types.update(tmp) Scope.changeType(parser, name, parser.structs[parser.package][name] ) typ.struct = parser.structs[parser.package][name] Scope.decrScope(parser)
def _resolve(self, tokens, filename, passN=0): target = self.global_target if self.package != "main": self.global_target = "full" if self.hotswap and not ImportParser.shouldCompile(False, self.package, self): return self.filename = filename self.iter = 0 self.tokens = tokens while self.iter < len(tokens) - 1: b = self.thisToken().token if passN == 2: if b == "import": ImportParser.importParser(self, True) elif b == "from": ImportParser.fromParser(self, True) elif b == "def": if self.indentLevel == 0: nex = self.lookInfront() Parser.addBookmark(self) funcHead(self) Parser.returnBookmark(self) elif passN == 1: if b == "import": ImportParser.importParser(self, True) elif b == "from": ImportParser.fromParser(self, True) elif b == "type": Parser.addBookmark(self) Struct.typeParser(self, decl=True) Parser.returnBookmark(self) elif passN == 0: if b == "type": name = self.nextToken().token if name == "ext": name = self.nextToken().token ofType = None gen = {} if self.nextToken().token == "[": Scope.incrScope(self) gen = FuncParser.generics(self, name) Scope.decrScope(self) ofType = self.thisToken().token else: ofType = self.thisToken().token Scope.addVar(Tree.Node(self), self, name, Scope.Type(True, Types.StructInit(name))) if ofType is None or ofType == "=": #""" self.structs[self.package][name] = Struct.Struct( name, [], [], gen, self, self.package) self.structs[self.package][name].methods = {} #""" elif ofType == "either": self.interfaces[self.package][name] = Types.Enum( self.package, name, coll.OrderedDict(), gen) elif ofType == "with": self.interfaces[self.package][name] = Types.Interface( False, {}, name=self.package + "." + name) elif ofType == "is": self.interfaces[self.package][name] = Types.Alias( self.package, name, Types.Null(), gen) if b == "\n": Parser.addBookmark(self) Parser.newLine(self) Parser.returnBookmark(self) self.nextToken() for i in self.imports: if not i in self.allImports[self.package]: self.allImports[self.package].append(i) self.imports = [] self.lineNumber = 1 self.normalIndent = 0 self.global_target = target
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
def loop(n, o_iter): count = 0 for i in n: if type(n) is type(tree): o_iter += 1 if not sc and type(i) in [ Tree.FuncStart, Tree.FuncBraceOpen, Tree.FuncBody ]: count += 1 continue 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.Block, Tree.While]: Scope.incrScope(parser) if type(i) is Tree.Lambda: count = Types.state.count Scope.incrScope(parser) if not (i.isEnd() or type(i) in [Tree.MatchCase, Tree.Lens] or (type(i) is Tree.Block and type(i.owner) is Tree.Match)): if type(i) is Tree.FuncBody: if i.method: parser.func.append(parser.package + "." + i.name[:i.name.find("_")]) else: parser.func.append(parser.package + "." + i.name.replace("_", ".")) loop(i, o_iter) if type(i) is Tree.FuncBody and len(parser.func) > 0: parser.func.pop() if type(i) is Tree.Lambda: if not i.returnTyp: if len(i.nodes) > 0: returnTyp = i.nodes[1].nodes[-1].type else: returnTyp = Types.Null() else: returnTyp = i.returnTyp args = [] gen = ODict() for c in i.args: if type(c) is Types.Unknown: if not c.typ: c.compareType(Types.newT(parser)) args.append(c.typ) genInC = Types.remainingT(c.typ) for d in genInC: gen[d] = genInC[d] else: args.append(c) if type(returnTyp) is Types.Unknown and not returnTyp.typ: i.error("Cannot infer return type of this function") replaces = {} #should only replace if only used once #""" inReturn = Types.remainingT(returnTyp) processGen = ODict() uselessGen = ODict() for c in gen: if c in inReturn: processGen[c] = gen[c] else: uselessGen[c] = gen[c] replaces = {} for c in uselessGen: replaces[c] = Types.replaceT(uselessGen[c].type, {}, unknown=True) gen = processGen #""" i.args = [] i.returnTyp = 0 i.type = Types.replaceT(Types.FuncPointer(args, returnTyp, do=i.do, generic=gen), replaces, unknown=True) print(i.type) i.nodes[1].returnType = i.type.returnType i.nodes[1].do = i.do #print(gen) #print(i.type) Types.state.count = count elif type(i) is Tree.Match: typ = i.nodes[0].type first = False for c in range(1, len(i.nodes), 2): body = i.nodes[c + 1] Scope.incrScope(parser) Enum.checkCase(parser, i.nodes[c].nodes[0], typ, True) loop(body, o_iter) body.type = body.nodes[-1].type if len( body.nodes) > 0 else Types.Null() Scope.decrScope(parser) if first: try: thisTyp = body.type first.duckType(parser, thisTyp, body, i, 0) except EOFError as e: try: thisTyp.duckType(parser, first, body, i, 0) first = thisTyp except EOFError: Error.beforeError( e, "Type mismatch, this arm has a different type : " ) #if body.type != first: # (body.nodes[-1] if len(body.nodes) > 0 else body).error( # "type mismatch in arms of match, " + str(body.type) + " and " + str(first)) else: if len(i.nodes[2].nodes) > 0: first = i.nodes[2].nodes[-1].type else: first = Types.Null() i.nodes[2].type = first Enum.missingPattern(typ, i) i.type = first if first else Types.Null() elif type(i) is Tree.CreateAssign: if type(i.nodes[0].name) is Tree.PlaceHolder: p = i.nodes[0].name.nodes[0] node = i.nodes[1].nodes[0] def recur(typ, pattern): if type(pattern) is Tree.Tuple: if len(pattern) > len(typ.list): diff = len(pattern) - len(typ.list) node.error(diff + " too few values to unpack") elif len(pattern) < len(typ.list): diff = len(typ.list) - len(pattern) node.error(diff + " too many values to unpack") for (index, p) in enumerate(pattern): recur(typ.list[index], p) elif type(pattern) is Tree.InitStruct: for p in pattern: if type(p) is Tree.Assign: name = p.nodes[0].name p = p.nodes[1] else: name = p.name if not name in typ.types: node.error("Object has no field " + name) recur(typ.types[name], p) else: Scope.addVar( node, parser, pattern.name, Scope.Type(True, typ, i.global_target)) pattern.isGlobal = Scope.isGlobal( parser, parser.package, pattern.name) recur(node.type, p) elif i.nodes[0].varType is None and i.nodes[0].name != "_": if i.extern: i.error( "expecting type declaration, for external variable declaration" ) 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.global_target)) i.nodes[0].isGlobal = Scope.isGlobal( parser, i.nodes[0].package, i.nodes[0].name) if i.global_target != parser.global_target: #print(i.nodes[0].name) Scope.changeTarget(parser, i.nodes[0].name, i.global_target) #print("this variable can only be used in a specific target", i.global_target) elif type(i) is Tree.FuncBody: Scope.decrScope(parser) def check(n, _i): for c in n: if type(c) is Tree.FuncCall: if not _i.do and not c.partial and not c.curry and c.nodes[ 0].type.do: c.nodes[0].error( "cannot call function with side effects in a pure function" ) if type(c) is Tree.FuncBody: pass # check(c, c) elif not c.isEnd(): check(c, _i) check(i, i) if i.global_target != parser.global_target: #print(i.name) Scope.changeTarget(parser, i.name, i.global_target) #print("this function can only be used in a specific target", i.global_target) elif type(i) is Tree.Create: if not i.varType is None: #print(i.owner.global_target) if parser.package != "main" and parser.global_target != "full": print("should be full") Scope.addVar( i, parser, i.name, Scope.Type(i.imutable, i.varType, i.owner.global_target)) i.isGlobal = Scope.isGlobal(parser, i.package, i.name) elif type(i) is Tree.ReadVar: if i.name == "newAtom": if not (type(i.owner) is Tree.FuncCall and i.owner.nodes[0] == i and not i.owner.curry and not i.owner.partial): i.error( "expecting function call, with no currying or partial application" ) if parser.atoms > 0: i.error("can only have one atom per application") if not (type(i.owner) is Tree.Assign and type(i.owner.owner) is Tree.InitStruct and i.owner.nodes[0] == i): if i.name in parser.imports: if not type(i.owner) is Tree.Field: i.error( "expecting ., cannot directly mention package name" ) 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) target = Scope.targetOfVar(i, parser, parser.package, self.name) realT = tree.nodes[o_iter].global_target if target != parser.global_target and (parser.global_target == "full"): root = tree.nodes[o_iter] if type(root) is Tree.FuncBody: try: tree.nodes[o_iter - 1].global_target = target tree.nodes[o_iter - 2].global_target = target except IndexError: pass root.global_target = target elif realT != target and target != "full" and realT != "full": i.error("variable " + i.name + " is of target " + target + ", but being used in a " + realT + " target") elif type(i) is Tree.Field: if i.unary: field = i.field T = Types.T("T", Types.All, "get" + i.field[0].upper() + i.field[1:]) I = Types.Interface(False, {field: T}) i.type = Types.FuncPointer([I], T, generic=ODict([("T", T)])) count += 1 continue 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 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) target = Scope.targetOfVar(i, parser, i.nodes[0].name, i.field) if target != parser.global_target: root = parser.currentNode.nodes[o_iter] if type(root) is Tree.FuncBody: tree.nodes[o_iter - 1].global_target = target tree.nodes[o_iter - 2].global_target = target root.global_target = target 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 == "|>" or 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 i.kind == ">>": if not type(a) is Types.FuncPointer: self.nodes[1].error( "right argument must be a function") a = a.returnType if not type(b) is Types.FuncPointer: self.nodes[1].error("left argument must be a function") if len(b.args) != 1: self.nodes[1].error( "expecting one function argument that matches return type of piped function" ) try: b.args[0].duckType(parser, a, self.nodes[0], self.nodes[1], 1) except EOFError as e: if i.kind == ">>": Error.beforeError(e, "Function combining with: ") else: Error.beforeError(e, "Function piping to: ") if i.kind == ">>": a = self.nodes[0].type self.type = Types.FuncPointer(a.args, b.returnType, do=a.do or b.do, generic=a.generic) else: self.type = b.returnType f = Tree.FuncCall(parser) f.addNode(self.nodes[1]) f.addNode(self.nodes[0]) f.owner = self.owner f.type = b.returnType self.owner.nodes[count] = f elif i.kind == "as": i.type.duckType(parser, i.nodes[0].type, i, i.nodes[0], 0) elif i.kind == "<-": if i.unary: try: meth = i.nodes[0].type.types["unary_read"] except KeyError: meth = i.nodes[0].type.hasMethod( parser, "unary_read") if meth: i.type = meth.returnType i.opT = i.nodes[0].type else: i.error("type " + str(i.nodes[0].type) + ", missing method unary_read") else: try: meth = i.nodes[0].type.types["op_set"] except KeyError: meth = i.nodes[0].type.hasMethod(parser, "op_set") if meth: meth.args[0].duckType(parser, i.nodes[1].type, i.nodes[1], i, 1) i.opT = i.nodes[0].type else: i.error("type " + str(i.nodes[0].type) + ", missing method op_set") #else: # i.nodes[0].error("Type " + str(i.nodes[0].type) + ", missing method op_set") elif i.kind == "concat": stringable = Types.Interface( False, {"toString": Types.FuncPointer([], Types.String(0))}) for c in i: stringable.duckType(parser, c.type, i, i, 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 = [("Operator.T", Types.All)] returnT = T if i.kind in [ "==", "!=", "not", "and", "or", "<", ">", "<=", ">=" ]: returnT = Types.Bool() i.opT = T i.type = Types.FuncPointer([T, T], returnT, 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 elif startType: try: c.type.duckType(parser, startType, i, c, 0) startType = c.type except EOFError: startType.duckType(parser, c.type, c, i, 0) else: 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 Tree.checkOperator(i, parser) elif type(i) is Tree.FuncCall: c = i partial = False if not i.nodes[0].type.isType(Types.FuncPointer): i.nodes[0].error("type " + str(i.nodes[0].type) + " is not callable") i.nodes[0].type = i.nodes[0].type.toRealType() do = i.nodes[0].type.do returnType = i.nodes[0].type.returnType args = i.nodes[0].type.args newArgs = [] if args.__len__() < len(i.nodes) - 1: c = str(len(i.nodes) - 1 - len(args)) i.error(("1 argument" if c == "1" else c + " arguments") + " too many, expecting " + str(len(args)) + " arguments") generics = {} for iter in range(len(i.nodes[1:])): if type(i.nodes[iter + 1]) is Tree.Under: partial = True newArgs.append(args[iter]) else: xnormalTyp = args[iter] myNode = i.nodes[iter + 1] myTyp = myNode.type normalNode = i isGen = Types.isGeneric(myTyp) if i.nodes[0].name == "startApp" and iter == 1: print("=====") if Types.isGeneric(xnormalTyp) or isGen: normalTyp = resolveGen(xnormalTyp, myNode.type, generics, parser, myNode, i) if isGen: myTyp = Types.replaceT(myTyp, generics) else: normalTyp = xnormalTyp if i.nodes[0].name == "startApp" and iter == 1: print(xnormalTyp) print(normalTyp) print(myTyp) print(myNode.type) normalTyp.duckType(parser, myTyp, i, myNode, iter + 1) if i.nodes[0].name == "newAtom": i = i.nodes[0] if parser.dev and parser.hotswap and parser.atomTyp: parser.atomTyp.duckType(parser, i.owner.nodes[1].type, i.owner.nodes[1], i, 0) f = Tree.Field(0, i.owner.nodes[1].type, i) f.field = "arg" f.type = parser.atomTyp r = Tree.ReadVar("previousState", True, i) r.package = "" f.addNode(r) i.owner.nodes[1] = f f.owner = i.owner parser.atomTyp = i.owner.nodes[1].type parser.atoms += 1 i = c if args.__len__() > len(i.nodes) - 1: i.curry = True newGenerics = ODict() for c in i.nodes[0].type.generic: if c in generics: newGenerics[c] = generics[c] else: newGenerics[c] = i.nodes[0].type.generic[c] i.type = Types.FuncPointer(args[len(i.nodes) - 1:], i.nodes[0].type.returnType, generic=newGenerics, do=i.nodes[0].type.do) #i.type = Types.FuncPointer([Types.replaceT(c, generics) for c in args[len(i.nodes)-1:]], Types.replaceT(i.nodes[0].type.returnType, generics),generic= newGenerics, do= do) elif not partial: i.type = Types.replaceT(i.nodes[0].type.returnType, generics) else: i.partial = True i.type = Types.replaceT( Types.FuncPointer(newArgs, i.nodes[0].type.returnType, do=do), 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 type(i.owner) is Tree.InitStruct: pass elif not (type(i.owner) is Tree.CreateAssign and i.owner.nodes[0].varType is None): if type(i.owner) is Tree.CreateAssign and i.owner.extern: if not type(i.nodes[0].type) is Types.String: i.error("expecting String") else: 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 )") elif len(i.nodes) > 1: i.type = Types.Tuple([c.type for c in i]) else: 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: if len(arr.nodes) > 1: typ = arr.nodes[1].type else: arr.nodes[0].error("expecting value after :") else: c = arr.nodes[0] if type(c) is Tree.Operator and c.kind == "..": if not type(c.nodes[0].type) is Types.Array: c.nodes[0].error("Expecting array") typ = c.nodes[0].type.elemT else: typ = c.type if typ == Types.Null(): arr.error("array elements must be non none") count = 0 for c in arr.nodes[1:]: err = False if typ != c.type: if type(c) is Tree.Operator and c.kind == "..": if not type( c.nodes[0].type) is Types.Array: c.nodes[0].error("Expecting array") ctype = c.nodes[0].type.elemT else: ctype = c.type try: typ.duckType(parser, ctype, i, c, count) except EOFError as e: try: ctype.duckType(parser, typ, c, i, count) typ = ctype except EOFError as e: err = e if err: Error.beforeError( err, "Element type in array: ") count += 1 arr.type = Types.Array(arr.mutable, typ) elif type(i) is Tree.InitPack: parser.imports.append(i.package) elif type(i) is Tree.InitStruct: unary = i.unary if not unary: typ = i.constructor.type i.typ = typ assign = True if typ.isType(Struct.Struct): s = typ assign = False i.paramNames = Struct.offsetsToList(s.offsets) elif typ.isType(Types.Interface) or typ.isType( Types.Struct): assign = True s = typ else: i.constructor.error( "type " + str(typ) + " can not be used as a constructor") i.s = s name = s.name types = normalTyp = s._types if type( s) is Struct.Struct else s.types if len(types) < len(i.nodes) - 1: c = str(len(i.nodes) - 1 - len(s.types)) i.error(("1 argument" if c == "1" else c + " arguments") + " too many") elif not assign and len(types) > len(i.nodes) - 1: c = str(len(types) + 1 - len(i.nodes)) i.error(("1 argument" if c == "1" else c + " arguments") + " too few") else: assign = True gen = {} randomOrder = False order = {} for iter in range(0 if unary else 1, len(i.nodes)): if type(i.nodes[iter]) is Tree.Assign: randomOrder = True elif assign: i.nodes[iter].error("expecting =") if not randomOrder: order[i.paramNames[iter - 1]] = i.nodes[iter] myNode = i.nodes[iter] normalTyp = s.fieldType[iter - 1] else: if not type(i.nodes[iter]) is Tree.Assign: i.nodes[iter].error( "positional argument follows keyword argument") if i.nodes[iter].nodes[0].name in order: i.nodes[iter].nodes[0].error("duplicate parameter") order[i.nodes[iter].nodes[0].name] = i.nodes[iter] myNode = i.nodes[iter].nodes[1] xname = i.nodes[iter].nodes[0].name if not unary: try: normalTyp = types[xname] except KeyError: i.nodes[iter].nodes[0].error( "type " + str(s) + " does not have the field " + xname) normalNode = i if not unary: xnormalTyp = normalTyp if i.package == "main": dcx = 90 isGen = Types.isGeneric(normalTyp) myIsGen = Types.isGeneric(myNode.type) myTyp = myNode.type if isGen: normalTyp = resolveGen(normalTyp, myNode.type, gen, parser, myNode, i) if myIsGen: myTyp = Types.replaceT(myNode.type, gen) else: myTyp = myNode.type normalTyp.duckType(parser, myTyp, i, myNode, iter) #resolveGen(xnormalTyp, myNode.type, gen, parser, myNode, i) if not assign: for c in order: i.nodes[s.offsets[c]] = order[c] i.assign = assign if i.assign: if unary: types = {c: order[c].nodes[1].type for c in order} i.type = Types.Interface(False, types) else: i.type = typ else: package = parser.structs[i.package][name].package i.type = Types.Struct(i.mutable, name, s._types, package, gen) elif type(i) is Tree.ArrRead: if len(i.nodes) == 2: typ = i.nodes[0].type try: func = typ.types["get"] except KeyError: func = typ.getMethod(parser, "get") if not func: i.nodes[0].error( "Type " + str(i.nodes[0].type) + " is not indexable, missing method get") arrRead = i if len(arrRead.nodes) != 2: i.nodes[1].error("expecting single index") if len(func.args) != 1: i.nodes[0].error( str(typ) + " is not indexable, method get should take 1 paramter, not " + len(func.args)) try: func.args[0].duckType(parser, i.nodes[1].type, i.nodes[1], i, 0) except EOFError as e: Error.beforeError(e, "Index : ") arrRead.type = func.returnType else: i.error("expecting single index") 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): g = gen[c].type if type(gen[c]) is Types.T else gen[c] g.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]) elif type(i) is Tree.Block: if len(i.nodes) > 0: i.type = i.nodes[-1].type else: for c in checkTyp: if checkTyp[c](i): break if type(i) in [Tree.Block, Tree.While]: Scope.decrScope(parser) count += 1