def getConst(self, item): if self.typ.normalName != "": return self.typ.const[item] def setConst(index): def inner(newTyp): self.typ.const[item][index] = unificaction( self.typ.const[item][index], newTyp, self.parser) typ = self.typ self.typ = Enum(typ.package, typ.name, typ.const, typ.generic) self.name = self.typ.name self.callback(self.typ) return inner parser = self.parser c = Scope.typeOfVar(Tree.PlaceHolder(self.parser), parser, parser.package, item) if type(c) is FuncPointer: enum = c.returnType args = c.args else: enum = c args = [] replaces = {} for i in enum.generic: replaces[i] = Unknown(parser, callback=setConst(i), typ=newT(parser)) r = replaceT(enum, replaces) self.compareType(r) return self.typ.const[item]
def parse(package, filename, cont, token): comment = token.token[4:-2] split = splitBy(comment) inCode = False for i in split: if len(i) > 0 and i[:3] == "```" and inCode: inCode = False cont.append(i) elif len(i) > 0 and i[:3] == "```" and not inCode: cont.append("```scala"+i[3:]) inCode = True elif len(i) > 0 and i[0] == "@": name = i[1:] cont.append("```scala\n") if name in parser.structs[package]: typ = parser.structs[package][name] cont.append("type " + name + gen(typ.generic) + " =") for c in Struct.offsetsToList(parser.structs[package][name].offsets): cont.append("\n " + c + ": " + typ.types[c].name + "") elif name in parser.interfaces[package]: typ = parser.interfaces[package][name] if type(typ) is Types.Interface: cont.append("type " + name + " with\n") for c in typ.types: cont.append(" " + c + ": " + typ.types[c].name + "\n") elif type(typ) is Types.Enum: cont.append("type " + name + " either\n") for c in typ.types: args = typ.types[c] if len(args) == 0: cont.append(" " + c + "\n") else: cont.append(" " + c + "(" + ", ".join([d.name for d in args]) + ")\n") else: try: n = Scope.typeOfVar(PlaceHolder(package, filename, token), parser, package, name) cont.append(name+": "+str(n)) except EOFError: try: PlaceHolder(package, filename, token).error("no variable named "+name) except EOFError as e: print(e, file=sys.stderr) sys.exit() cont.append("\n```") else: cont.append(i)
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 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 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