Beispiel #1
0
    public override AstNode ShallowClone()
    {
        var res = new AstCall(Source, Start, End, Expression, Optional);

        res.Args.AddRange(Args.AsReadOnlySpan());
        return(res);
    }
Beispiel #2
0
        private static AstExpression ParseNewExpr(TokenStream tks)
        {
            var si = tks.SourceInfo;

            tks.Expect(TokenType.New);
            var what = tks.Expect(TokenType.Ident).StringValue;

            if (tks.Accept(TokenType.LParen) != null)
            {
                var ctorCall = new AstCall(si, new AstIdent(si, what), ParseExpressionList(tks));
                tks.Expect(TokenType.RParen);
                return(new AstUnaryOp(si, TokenType.New, ctorCall));
            }
            var ptrDepth = 1;

            while (tks.Accept(TokenType.Star) != null)
            {
                ptrDepth++;
            }
            tks.Expect(TokenType.LSquBracket);
            var size = ParseExpression(tks);

            tks.Expect(TokenType.RSquBracket);
            return(new AstNewArrayOp(si, size, what, ptrDepth));
        }
Beispiel #3
0
        void InstrumentBlock(ref StructList <AstNode> block, bool seq = false)
        {
            var input = new StructList <AstNode>();

            input.TransferFrom(ref block);
            block.Reserve(input.Count * 2);
            for (var i = 0; i < input.Count; i++)
            {
                var ii = input[i];
                if (ShouldStatementCover(ii))
                {
                    var idx  = _owner.LastIndex++;
                    var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));
                    call.Args.Add(new AstNumber(idx));
                    if (seq)
                    {
                        block.Add(call);
                    }
                    else
                    {
                        block.Add(new AstSimpleStatement(call));
                    }

                    _owner.GetForFile(ii.Source !)
                    .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, ii.Start, ii.End));
                }

                ii = Transform(ii);
                block.Add(ii);
            }
        }
Beispiel #4
0
 static bool IsRequireCall(AstCall call)
 {
     if (call.Args.Count == 1 && call.Expression is AstSymbolRef symb && symb.Name == "require" &&
         call.Args[0] is AstString)
     {
         return(true);
     }
     return(false);
 }
Beispiel #5
0
        static bool IsSameCall(AstCall callA, AstCall callB)
        {
            // TODO write test for same call check
            if (!(callA.Expression is AstSymbolRef symbolRefA &&
                  callB.Expression is AstSymbolRef symbolRefB) ||
                !IsSameReference(symbolRefA, symbolRefB))
            {
                return(false);
            }
            var argsA = TrimEndingUndefined(callA.Args);
            var argsB = TrimEndingUndefined(callB.Args);

            if (argsA.Count != argsB.Count)
            {
                return(false);
            }
            for (var i = 0; i < argsA.Count; i++)
            {
                var argA = argsA[i];
                var argB = argsB[i];
                // Constant
                if (argA is AstConstant && argB is AstConstant)
                {
                    return(false);
                    // TODO all possible cases => + tests
                }
                // SymbolRef
                if (argA is AstSymbolRef argSymbolRefA &&
                    argB is AstSymbolRef argSymbolRefB)
                {
                    if (IsSameReference(argSymbolRefA, argSymbolRefB))
                    {
                        continue;
                    }
                    return(false);
                }
                // Call
                if (argA is AstCall argCallA &&
                    argB is AstCall argCallB)
                {
                    if (IsSameCall(argCallA, argCallB))
                    {
                        continue;
                    }
                    return(false);
                }

                return(false);
                // TODO another cases
            }

            return(true);
        }
Beispiel #6
0
        AstSwitchBranch InstrumentSwitchCase(AstSwitchBranch branch)
        {
            if (branch.Source == null)
            {
                return(branch);
            }
            var idx  = _owner.LastIndex++;
            var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));

            call.Args.Add(new AstNumber(idx));
            branch.Body.Insert(0) = new AstSimpleStatement(call);
            _owner.GetForFile(branch.Source)
            .AddInfo(new InstrumentedInfo(InstrumentedInfoType.SwitchBranch, idx, branch.Start, branch.End));
            return(branch);
        }
Beispiel #7
0
        AstNode InstrumentCondition(AstNode condition)
        {
            if (!ShouldConditionCover(condition))
            {
                return(condition);
            }
            var idx = _owner.LastIndex;

            _owner.LastIndex += 2;
            var res = new AstCall(new AstSymbolRef(_owner.FncNameCond));

            res.Args.Add(condition);
            res.Args.Add(new AstNumber(idx));
            _owner.GetForFile(condition.Source !)
            .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Condition, idx, condition.Start, condition.End));
            return(res);
        }
        public PartialExpression ResolveLookUp(AstCall lu)
        {
            var sym = CompileExpression(lu.Base);

            if (sym.IsInvalid)
            {
                return(PartialExpression.Invalid);
            }

            var candidates = new List <Property>();

            if (sym.ReturnType.IsInterface)
            {
                var dt = sym.ReturnType;
                dt.PopulateMembers();
                FindIndexers(dt, candidates, 0);

                var hideCount = candidates.Count;
                foreach (var it in dt.Interfaces)
                {
                    FindIndexers(it, candidates, hideCount);
                }
            }
            else
            {
                var bt = sym.ReturnType;
                bt.PopulateMembers();

                do
                {
                    FindIndexers(bt, candidates, candidates?.Count ?? 0);
                    bt = bt.Base;
                }while (bt != null);
            }

            Property indexer;

            Expression[] args;
            return(TryResolveIndexerOverload(lu.Source, candidates, lu.Arguments, out indexer, out args)
                    ? new PartialIndexer(lu.Source, sym.Address, indexer, args) :
                   sym.ReturnType.IsArray && args.Length == 1
                    ? new PartialArrayElement(lu.Source, sym, sym.ReturnType.ElementType, CompileImplicitCast(lu.Source, Essentials.Int, args[0]))
                    : PartialError(lu.Source, ErrorCode.E3103, sym.ReturnType.Quote() + " does not contain an indexer that matches the argument list"));
        }
Beispiel #9
0
        void InstrumentFunction(AstLambda lambda)
        {
            if (lambda.Source == null)
            {
                InstrumentBlock(ref lambda.Body);
                return;
            }

            var idx  = _owner.LastIndex++;
            var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));

            call.Args.Add(new AstNumber(idx));
            lambda.Body.Insert(0) = new AstSimpleStatement(call);
            _owner.GetForFile(lambda.Source)
            .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Function, idx, lambda.Start, lambda.End));
            var input = new StructList <AstNode>();

            input.TransferFrom(ref lambda.Body);
            lambda.Body.Reserve(input.Count * 2 - 1);
            lambda.Body.Add(input[0]);
            for (var i = 1; i < input.Count; i++)
            {
                var ii = input[i];
                if (ShouldStatementCover(ii))
                {
                    if (i != 1)
                    {
                        idx  = _owner.LastIndex++;
                        call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));
                        call.Args.Add(new AstNumber(idx));
                        lambda.Body.Add(new AstSimpleStatement(call));
                    }

                    _owner.GetForFile(ii.Source !)
                    .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, ii.Start, ii.End));
                }

                ii = Transform(ii);
                lambda.Body.Add(ii);
            }
        }
Beispiel #10
0
        AstNode InstrumentExpression(AstNode node)
        {
            if (node is AstSequence)
            {
                return(node);
            }
            if (node.Source == null)
            {
                return(node);
            }
            var res  = new AstSequence(node);
            var idx  = _owner.LastIndex++;
            var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));

            call.Args.Add(new AstNumber(idx));
            res.Expressions.Add(call);
            res.Expressions.Add(node);
            _owner.GetForFile(node.Source)
            .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, node.Start, node.End));
            return(res);
        }
Beispiel #11
0
        // <postfix-exp>        ::= <primary>
        //                      |   <postfix-exp> '(' <arg-list> ')'
        //                      |   <postfix-exp> '[' <expr> ']'
        private static AstExpression ParsePostfix(TokenStream tks)
        {
            var si   = tks.SourceInfo;
            var save = tks.Index;
            var expr = ParsePrimary(tks);

            if (expr == null)
            {
                tks.Restore(save);
                return(null);
            }
            Token tk;

            while ((tk = tks.Accept(TokenType.Dot, TokenType.LParen, TokenType.LSquBracket)) != null)
            {
                switch (tk.Type)
                {
                case TokenType.Dot:
                    var memberIdent = tks.Expect(TokenType.Ident).StringValue;
                    expr = new AstMemberAccess(si, expr, memberIdent);
                    break;

                case TokenType.LParen:
                    expr = new AstCall(si, expr, ParseExpressionList(tks));
                    tks.Expect(TokenType.RParen);
                    break;

                case TokenType.LSquBracket:
                    tks.ThrowIfTokenIs(TokenType.RSquBracket);
                    expr = new AstIndex(si, expr, ParseExpressionList(tks));
                    tks.Expect(TokenType.RSquBracket);
                    break;
                }
            }
            return(expr);
        }
        public Expression CompileCall(AstCall e)
        {
            // Builtin struct initialization
            if (e.Base is AstBuiltinType)
            {
                var dt = NameResolver.GetType(Namescope, e.Base);

                if (dt.IsStruct)
                {
                    // Default ctor
                    if (e.Arguments.Count == 0)
                    {
                        return(new Default(e.Source, dt));
                    }

                    dt.PopulateMembers();

                    Constructor  ctor;
                    Expression[] args;
                    return(TryResolveConstructorOverload(e.Source, dt.Constructors, e.Arguments, out ctor, out args)
                        ? new NewObject(e.Source, ctor, args)
                        : Error(e.Source, ErrorCode.E3125, dt.Quote() + " has no constructors matching the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(dt.Constructors)));
                }

                return(Error(e.Source, ErrorCode.E3126, dt.Quote() + " must be instantiated using 'new' because it is not a struct"));
            }

            var pe = ResolveExpression(e.Base, null);

            switch (pe.ExpressionType)
            {
            case PartialExpressionType.Block:
            case PartialExpressionType.Type:
            case PartialExpressionType.Namespace:
                if (e.Base is AstIdentifier)
                {
                    var p2 = NameResolver.TryResolveUsingType(Namescope, e.Base as AstIdentifier, null);
                    if (p2 != null)
                    {
                        pe = p2;
                    }
                }
                break;
            }

            var sym = CompilePartial(pe);

            if (sym.IsInvalid)
            {
                return(Expression.Invalid);
            }

            // Delegate call
            if (sym.ReturnType.IsDelegate)
            {
                var dt = (DelegateType)sym.ReturnType;
                dt.AssignBaseType();
                var args = TryApplyDefaultValuesOnArgumentList(sym.Source, dt.Parameters, CompileArgumentList(e.Arguments));
                return(TryApplyImplicitCastsOnArgumentList(dt.Parameters, args)
                    ? new CallDelegate(e.Source, sym, args)
                    : Error(e.Source, ErrorCode.E3127, "Call to delegate of type " + dt.Quote() + " has some invalid arguments " +
                            PrintableArgumentList(e.Arguments)));
            }

            // Using static fall back
            if (!(sym is MethodGroup) && e.Base is AstIdentifier)
            {
                var p2 = NameResolver.TryResolveUsingType(Namescope, e.Base as AstIdentifier, null);
                if (p2 != null)
                {
                    sym = CompilePartial(p2);
                    if (sym.IsInvalid)
                    {
                        return(Expression.Invalid);
                    }
                }
            }

            // Method call
            if (sym is MethodGroup)
            {
                var g = sym as MethodGroup;

                Method       method;
                Expression[] args;
                return(TryResolveMethodOverload(e.Source, g.Candidates, e.Arguments, out method, out args)
                    ? (g.IsQualified && g.Object != null && method.IsStatic
                            ? Error(sym.Source, ErrorCode.E3123, method.Quote() + " is static -- qualify with the type name") :
                       g.Object == null && !method.IsStatic
                            ? Error(sym.Source, ErrorCode.E3124, method.Quote() + " is non-static and cannot be accessed from a static context")
                            : new CallMethod(e.Source, method.IsStatic ? null : g.Object, method, args))
                    : g.Candidates.Count == 1
                        ? Error(e.Source, ErrorCode.E3128, "Call to " + g.Candidates[0].Quote() + " has some invalid arguments " +
                                PrintableArgumentList(e.Arguments))
                        : Error(e.Source, ErrorCode.E3129, "No overloads of " + g.CandidatesBaseName.Quote() + " matches the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(g.Candidates)));
            }

            // Extension method call
            if (sym is ExtensionGroup)
            {
                var g = sym as ExtensionGroup;

                Method       method;
                Expression[] args;
                var          astArgs = new AstArgument[e.Arguments.Count + 1];
                astArgs[0] = new AstIL(g.Object);
                for (int i = 0; i < e.Arguments.Count; i++)
                {
                    astArgs[i + 1] = e.Arguments[i];
                }

                return(TryResolveMethodOverload(e.Source, g.Candidates, astArgs, out method, out args)
                    ? new CallMethod(e.Source, null, method, args)
                    : g.Candidates.Count == 1
                        ? Error(e.Source, ErrorCode.E3128, "Call to " + g.Candidates[0].Quote() + " has some invalid arguments " +
                                PrintableArgumentList(astArgs))
                        : Error(e.Source, ErrorCode.E3129, "No overloads of " + g.CandidatesBaseName.Quote() + " matches the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(g.Candidates)));
            }

            return(Error(e.Source, ErrorCode.E3130, "Instances of type " + sym.ReturnType.Quote() + " cannot be called as a function"));
        }
Beispiel #13
0
        public IEntity GetEntity(Source src, string str, params Namescope[] scopes)
        {
            if (string.IsNullOrEmpty(str))
            {
                Log.Error(src, ErrorCode.E0000, "<null> could not be resolved");
                return(DataType.Invalid);
            }

            // Special case void because that is not a valid expression
            if (str == "void")
            {
                return(DataType.Void);
            }

            var log = new Log(TextWriter.Null);
            var e   = str[0] == '.' ? null : Parser.ParseExpression(log, src, str);

            if (log.HasErrors || e == null)
            {
                // Custom code to handle special cases not supported in the parser.
                // E.g.: foo(ref fixed float[8]), .ctor(), .cctor()

                string        basePart = null;
                AstArgument[] args     = null;

                str = str.Trim();

                if (str.EndsWith(')'))
                {
                    var parts = str.Split('(');

                    if (parts.Length == 2)
                    {
                        basePart = parts[0];
                        var argsPart = parts[1].Substring(0, parts[1].Length - 1);
                        if (argsPart.Length > 0)
                        {
                            var argParts = argsPart.Split(',');
                            args = new AstArgument[argParts.Length];

                            for (int i = 0; i < args.Length; i++)
                            {
                                var argPart = argParts[i].Trim();

                                if (argPart.StartsWith("ref fixed ", StringComparison.InvariantCulture) &&
                                    argPart.EndsWith(']'))
                                {
                                    argPart = argPart.Substring(10);

                                    var index    = argPart.LastIndexOf('[');
                                    var sizePart = argPart.Substring(index + 1, argPart.Length - index - 2);

                                    AstExpression size = null;
                                    if (sizePart.Length > 0)
                                    {
                                        size = Parser.ParseExpression(Log, src, sizePart);
                                    }

                                    var type = Parser.ParseType(Log, src, argPart.Substring(0, index));
                                    args[i] = new AstArgument(null, ParameterModifier.Ref, new AstFixedArray(src, type, size));
                                }
                                else if (argPart.StartsWith("ref ", StringComparison.InvariantCulture))
                                {
                                    args[i] = new AstArgument(null, ParameterModifier.Ref, Parser.ParseType(Log, src, argPart.Substring(4)));
                                }
                                else if (argPart.StartsWith("out ", StringComparison.InvariantCulture))
                                {
                                    args[i] = new AstArgument(null, ParameterModifier.Out, Parser.ParseType(Log, src, argPart.Substring(4)));
                                }
                                else
                                {
                                    args[i] = Parser.ParseType(Log, src, argPart);
                                }
                            }
                        }
                    }
                }

                if (basePart == null)
                {
                    basePart = str;
                }

                if (basePart == ".ctor" || basePart == ".cctor")
                {
                    e = new AstIdentifier(src, basePart);
                }
                else
                {
                    e = Parser.ParseExpression(Log, src, basePart);
                }

                if (args != null)
                {
                    e = new AstCall(AstCallType.Function, e, args);
                }
                else if (basePart != str)
                {
                    e = new AstCall(AstCallType.Function, e);
                }
            }

            var result = ResolveExpression(e, null, scopes ?? new Namescope[0]);

            if (result is Function && e.ExpressionType != AstExpressionType.Call)
            {
                Log.Error(src, ErrorCode.E3355, str.Quote() + " is a method and must include the parameter list");
                return(DataType.Invalid);
            }

            if (result is IEntity)
            {
                return(result as IEntity);
            }

            Log.Error(src, ErrorCode.E3356, str.Quote() + " could not be resolved");
            return(DataType.Invalid);
        }
Beispiel #14
0
    void InstrumentFunction(AstLambda lambda)
    {
        if (lambda is AstArrow arrow)
        {
            if (arrow.Body.Count == 1 && arrow.Body.Last.IsExpression())
            {
                var original = arrow.Body[0];
                arrow.Body[0] = new AstBlock(original)
                {
                    Body = new() { new AstReturn(original)
                                   {
                                       Value = original
                                   } }
                };
            }
        }
        if (lambda.Source == null)
        {
            InstrumentBlock(ref lambda.Body);
            return;
        }

        var idx  = _owner.LastIndex++;
        var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));

        call.Args.Add(new AstNumber(idx));
        lambda.Body.Insert(0) = new AstSimpleStatement(call);
        _owner.GetForFile(lambda.Source)
        .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Function, idx, lambda.Start, lambda.End));
        var input = new StructList <AstNode>();

        input.TransferFrom(ref lambda.Body);
        lambda.Body.Reserve(input.Count * 2 - 1);
        lambda.Body.Add(input[0]);
        for (var i = 1; i < input.Count; i++)
        {
            var ii = input[i];
            if (ShouldStatementCover(ii))
            {
                if (i != 1)
                {
                    idx  = _owner.LastIndex++;
                    call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));
                    call.Args.Add(new AstNumber(idx));
                    lambda.Body.Add(new AstSimpleStatement(call));
                }

                _owner.GetForFile(ii.Source !)
                .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, ii.Start, ii.End));
            }

            ii = Transform(ii);
            lambda.Body.Add(ii);
        }
    }

    AstNode InstrumentExpression(AstNode node)
    {
        if (node is AstSequence)
        {
            return(node);
        }
        if (node.Source == null)
        {
            return(node);
        }
        var res  = new AstSequence(node);
        var idx  = _owner.LastIndex++;
        var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));

        call.Args.Add(new AstNumber(idx));
        res.Expressions.Add(call);
        res.Expressions.Add(node);
        _owner.GetForFile(node.Source)
        .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, node.Start, node.End));
        return(res);
    }

    void InstrumentBlock(ref StructList <AstNode> block, bool seq = false)
    {
        var input = new StructList <AstNode>();

        input.TransferFrom(ref block);
        block.Reserve(input.Count * 2);
        for (var i = 0; i < input.Count; i++)
        {
            var ii = input[i];
            if (ShouldStatementCover(ii))
            {
                var idx  = _owner.LastIndex++;
                var call = new AstCall(new AstSymbolRef(_owner.FncNameStatement));
                call.Args.Add(new AstNumber(idx));
                if (seq)
                {
                    block.Add(call);
                }
                else
                {
                    block.Add(new AstSimpleStatement(call));
                }

                _owner.GetForFile(ii.Source !)
                .AddInfo(new InstrumentedInfo(InstrumentedInfoType.Statement, idx, ii.Start, ii.End));
            }

            ii = Transform(ii);
            block.Add(ii);
        }
    }
Beispiel #15
0
 public void WriteCall(AstCall a)
 {
     Write(a.Base);
     WriteArguments(a.Arguments);
 }
Beispiel #16
0
        private void CompileCall(AstCall node, Syt syt, StringBuilder sb)
        {
            var cparam = node.rgexprParam.Length;

            if (node.exprFunc is AstVarRef)
            {
                var nodeRef = (AstVarRef) node.exprFunc;
                var syte = syt.Lookup(nodeRef.StName);

                switch (syte.Ksyte)
                {
                    case Ksyte.StaticFunction:
                        break;
                    case Ksyte.MemberFunction:
                        sb.AppendLine("push pointer 0");
                        cparam++;
                        break;
                    default:
                        throw new Erparse(node, "unexpected ksyte " + syte.Ksyte);
                }

                foreach (var nodeParam in node.rgexprParam)
                    CompileRecursive(nodeParam, syt, sb);

                sb.AppendLine("call {0}.{1} {2}".StFormat(node.NodeAncestor<AstClass>().StName, syte.StName, cparam));
            }
            else if (node.exprFunc is AstDot)
            {
                var nodeDot = (AstDot) node.exprFunc;

                var syteLeft = syt.Lookup(nodeDot.varLeft.StName) ?? new Syte(Ksyte.Class, nodeDot.varLeft.StName, 0, nodeDot.varLeft.StName);

                if (!syteLeft.Ksyte.FIn(Ksyte.Arg, Ksyte.Field, Ksyte.Var, Ksyte.Static, Ksyte.Class))
                   throw new Erparse(node, "unexpected ksyte " + syteLeft.Ksyte);

                if (syteLeft.Ksyte.FIn(Ksyte.Arg, Ksyte.Field, Ksyte.Var, Ksyte.Static))
                {
                    cparam++;
                    CompileRecursive(nodeDot.varLeft, syt, sb);
                }

                Ksyte ksyteRight;
                if (syteLeft.Ksyte == Ksyte.Class && syteLeft.StName != node.NodeAncestor<AstClass>().StName)
                    ksyteRight = Ksyte.StaticFunction /*constuctor???*/;
                else
                {
                    var syte = syt.Lookup(nodeDot.varRight.StName);
                    ksyteRight = syte == null ? Ksyte.MemberFunction : syte.Ksyte;
                }

                switch (ksyteRight)
                {
                    case Ksyte.Constructor:
                        if (syteLeft.Ksyte != Ksyte.Class)
                            throw new Erparse(node, "cannot call constructor on instance");
                        break;
                    case Ksyte.StaticFunction:
                    case Ksyte.MemberFunction:
                        break;
                    default:
                        throw new Erparse(node, "unexpected ksyte " + ksyteRight);
                }

                foreach (var nodeParam in node.rgexprParam)
                    CompileRecursive(nodeParam, syt, sb);

                sb.AppendLine("call {0}.{1} {2}".StFormat(syteLeft.StType, nodeDot.varRight.StName, cparam));
            }
        }