Example #1
0
    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]
Example #2
0
    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
Example #4
0
    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
Example #5
0
    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