public override AstNode ShallowClone() { var res = new AstCall(Source, Start, End, Expression, Optional); res.Args.AddRange(Args.AsReadOnlySpan()); return(res); }
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)); }
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); } }
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); }
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); }
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); }
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")); }
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); } }
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); }
// <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")); }
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); }
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); } }
public void WriteCall(AstCall a) { Write(a.Base); WriteArguments(a.Arguments); }
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)); } }