public void Print(LNode node, StringBuilder target, IMessageSink sink = null, ParsingMode mode = null, ILNodePrinterOptions options = null) { if (_usePlainCsPrinter) EcsNodePrinter.PrintPlainCSharp(node, target, sink, mode, options); else EcsNodePrinter.PrintECSharp(node, target, sink, mode, options); }
public static LNode In(LNode node, IMacroContext context) { { LNode range, x; if (node.Calls(CodeSymbols.In, 2) && (x = node.Args[0]) != null && (range = node.Args[1]) != null) { LNode parens; range = range.WithoutAttrNamed(S.TriviaInParens, out parens); if (parens == null) { { LNode hi, lo; if (range.Calls(CodeSymbols.DotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) if (lo.IsIdNamed(__)) return LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (hi.IsIdNamed(__)) return LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator); else return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol) "IsInRangeExcludeHi"))).SetStyle(NodeStyle.Operator), LNode.List(lo, hi)); else if (range.Calls(CodeSymbols.DotDot, 1) && (hi = range.Args[0]) != null) return LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (range.Calls(CodeSymbols.DotDotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) if (lo.IsIdNamed(__)) return LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (hi.IsIdNamed(__)) return LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator); else return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol) "IsInRange"))).SetStyle(NodeStyle.Operator), LNode.List(lo, hi)); else if (range.Calls(CodeSymbols.DotDotDot, 1) && (hi = range.Args[0]) != null) return LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); } } return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(range, LNode.Id((Symbol) "Contains"))).SetStyle(NodeStyle.Operator), LNode.List(x)); } } return null; }
public static LNode replace(LNode node, IMacroContext context) { var args_body = context.GetArgsAndBody(true); var args = args_body.A; var body = args_body.B; if (args.Count >= 1) { var patterns = new Pair<LNode, LNode>[args.Count]; for (int i = 0; i < patterns.Length; i++) { var pair = args[i]; if (pair.Calls(S.Lambda, 2)) { LNode pattern = pair[0], repl = pair[1]; if (pattern.Calls(S.Braces, 1) && repl.Calls(S.Braces)) { pattern = pattern.Args[0]; repl = repl.WithTarget(S.Splice); } patterns[i] = Pair.Create(pattern, repl); } else { string msg = "Expected 'pattern => replacement'."; if (pair.Descendants().Any(n => n.Calls(S.Lambda, 2))) msg += " " + "(Using '=>' already? Put the pattern on the left-hand side in parentheses.)"; return Reject(context, pair, msg); } } int replacementCount; var output = Replace(body, patterns, out replacementCount); if (replacementCount == 0) context.Write(Severity.Warning, node, "No patterns recognized; no replacements were made."); return output.AsLNode(S.Splice); } return null; }
public static LNode on_finally(LNode node, IMacroContext context) { LNode firstArg, rest, on_handler = ValidateOnStmt(node, context, out rest, out firstArg); if (on_handler == null || firstArg != null) return null; return node.With(S.Try, rest, node.With(S.Finally, on_handler)); }
public static RVList<LNode> WithSpliced(this RVList<LNode> list, LNode node, Symbol listName) { if (node.Calls(listName)) return list.AddRange(node.Args); else return list.Add(node); }
public static LNode concat_id(LNode node, IMessageSink sink) { var args = node.Args; if (args.Count == 0) return null; if (args.Slice(0, args.Count - 1).Any(n => n.IsCall)) return Reject(sink, node, "All arguments to ##() or concat() must be identifiers or literals (except the last one)"); RVList<LNode> attrs = node.Attrs; LNode arg = null; StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Count; i++) { arg = args[i]; attrs.AddRange(arg.Attrs); if (arg.IsLiteral) sb.Append(arg.Value ?? "null"); else if (arg.IsId) sb.Append(arg.Name); else { // call if (i + 1 != args.Count || !arg.HasSimpleHead()) return Reject(sink, arg, "Expected simple identifier or literal"); sb.Append(arg.Name); } } Symbol combined = GSymbol.Get(sb.ToString()); LNode result; if (arg.IsCall) result = arg.WithTarget(combined); else result = LNode.Id(combined, node); return result.WithAttrs(attrs); }
/// <summary>Returns true if the specified child of the specified node /// can be an implicit child statement, i.e. a child statement that is /// not necessarily a braced block, e.g. the second child of a while /// loop.</summary> /// <remarks> /// This method helps the printer decide when a newline should be added /// before an unbraced child statement when there are no attributes /// dictating whether to add a newline or not. /// <para/> /// This method only cares about executable parent nodes. It returns /// false for class/space and function/property bodies, which are always /// braced blocks and therefore get a newline before every child statement /// automatically. /// </remarks> public static bool MayBeImplicitChildStatement(LNode node, int childIndex) { CheckParam.IsNotNull("node", node); if (childIndex < 0) // target or attributes return false; var n = node.Name; if (!LNode.IsSpecialName(n.Name)) return false; if (n == S.Braces) return true; if (n == S.Try) return childIndex == 0; switch (node.ArgCount) { case 1: if (n == S.Finally) return true; break; case 2: if (childIndex == 0 ? n == S.DoWhile : n == S.If || n == S.While || n == S.UsingStmt || n == S.Lock || n == S.Switch || n == S.Fixed) return true; break; case 3: if (childIndex != 0 && n == S.If) return true; if (childIndex == 2 && n == S.ForEach) return true; break; case 4: if (childIndex == 3 && (n == S.For || n == S.Catch)) return true; break; } return false; }
public static LNode @nameof(LNode nameof, IMacroContext context) { if (nameof.ArgCount != 1) return null; Symbol expr = EcsValidators.KeyNameComponentOf(nameof.Args[0]); return F.Literal(expr.Name); }
protected override void Stmt(string text, LNode expected, Action<EcsPrinterOptions> configure = null, Mode mode = Mode.Both) { bool exprMode = (mode & Mode.Expression) != 0; if ((mode & Mode.ParserTest) == 0) return; var sink = (mode & Mode.ExpectAndDropParserError) != 0 ? new MessageHolder() : (IMessageSink)ConsoleMessageSink.Value; // This is the easy way: //LNode result = EcsLanguageService.Value.ParseSingle(text, sink, exprMode ? ParsingMode.Expressions : ParsingMode.Statements, preserveComments: true); // But to make debugging easier, I'll do it the long way: ILexer<Token> lexer = EcsLanguageService.Value.Tokenize(new UString(text), "", ConsoleMessageSink.Value); var preprocessed = new EcsPreprocessor(lexer, true); var treeified = new TokensToTree(preprocessed, false); var parser = new EcsParser(treeified.Buffered(), lexer.SourceFile, sink); VList<LNode> results = exprMode ? LNode.List(parser.ExprStart(false)) : LNode.List(parser.ParseStmtsGreedy()); //if (!preprocessed.TriviaList.IsEmpty) { // Inject comments var injector = new EcsTriviaInjector(preprocessed.TriviaList, preprocessed.SourceFile, (int)TokenType.Newline, "/*", "*"+"/", "//"); results = LNode.List(injector.Run(results.GetEnumerator()).ToList()); } LNode result = results.AsLNode(S.Splice); AreEqual(TokenType.EOF, parser.LT0.Type(), string.Format("Parser stopped before EOF at [{0}] in {1}", parser.LT0.StartIndex, text)); if ((mode & Mode.IgnoreTrivia) != 0) result = result.ReplaceRecursive(n => n.IsTrivia ? Maybe<LNode>.NoValue : n, LNode.ReplaceOpt.ProcessAttrs).Value; AreEqual(expected, result); if (sink is MessageHolder) GreaterOrEqual(((MessageHolder)sink).List.Count, 1, "Expected an error but got none for "+text); }
LNode AutoRemoveParens(LNode node) { int i = node.Attrs.IndexWithName(S.TriviaInParens); if ((i > -1)) return node.WithAttrs(node.Attrs.RemoveAt(i)); return node; }
public static LNode NullDot(LNode node, IMacroContext context) { if (!node.Calls(S.NullDot, 2)) return null; var a = node.Args; LNode leftSide = a[0], rightSide = a[1]; // So our input will be something like a.b?.c().d<x>, which is parsed // (a.b) ?. (c().d<x>) // in EC# we would transform this to // a.b::tmp != null ? tmp.c().d<x> : null // but there's no EC# compiler yet, so instead use code that plain C# // can support: // a.b != null ? (a.b).c().d<x> : null LNode condition, thenExpr; if (StandardMacros.LooksLikeSimpleValue(leftSide)) { condition = F.Call(S.Neq, leftSide, F.@null); thenExpr = ConvertToNormalDot(leftSide, rightSide); } else { LNode tempVar = F.Id(StandardMacros.NextTempName(context, leftSide)); condition = F.Call(S.Neq, F.Var(F.Missing, tempVar, leftSide), F.@null); thenExpr = ConvertToNormalDot(tempVar, rightSide); } return F.InParens(F.Call(S.QuestionMark, condition, thenExpr, F.Null)); }
[LexicalMacro("x in lo..hi; x in lo...hi; x in ..hi; x in lo..._; x in range", "Converts an 'in' expression to a normal C# expression using the following rules " + "(keeping in mind that the EC# parser treats `..<` as an alias for `..`):\n" + "1. `x in _..hi` and `x in ..hi` become `x.IsInRangeExcl(hi)`\n" + "2. `x in _...hi` and `x in ...hi` become `x.IsInRangeIncl(hi)`\n" + "3. `x in lo.._` and `x in lo..._` become simply `x >= lo`\n" + "4. `x in lo..hi` becomes `x.IsInRangeExcludeHi(lo, hi)`\n" + "5. `x in lo...hi` becomes `x.IsInRange(lo, hi)`\n" + "6. `x in range` becomes `range.Contains(x)`\n" + "The first applicable rule is used.", "#in")] public static LNode In(LNode node, IMacroContext context) { { LNode range, x; if (node.Calls(CodeSymbols.In, 2) && (x = node.Args[0]) != null && (range = node.Args[1]) != null) { LNode parens; range = range.WithoutAttrNamed(S.TriviaInParens, out parens); if (parens == null) { { LNode hi, lo; if (range.Calls(CodeSymbols.DotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) if (lo.IsIdNamed(__)) return LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (hi.IsIdNamed(__)) return LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator); else return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol) "IsInRangeExcludeHi"))), LNode.List(lo, hi)); else if (range.Calls(CodeSymbols.DotDot, 1) && (hi = range.Args[0]) != null) return LNode.Call(CodeSymbols.LT, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (range.Calls(CodeSymbols.DotDotDot, 2) && (lo = range.Args[0]) != null && (hi = range.Args[1]) != null) if (lo.IsIdNamed(__)) return LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); else if (hi.IsIdNamed(__)) return LNode.Call(CodeSymbols.GE, LNode.List(x, lo)).SetStyle(NodeStyle.Operator); else return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(x, LNode.Id((Symbol) "IsInRange"))), LNode.List(lo, hi)); else if (range.Calls(CodeSymbols.DotDotDot, 1) && (hi = range.Args[0]) != null) return LNode.Call(CodeSymbols.LE, LNode.List(x, hi)).SetStyle(NodeStyle.Operator); } } return LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(range, LNode.Id((Symbol) "Contains"))), LNode.List(x)); } } return null; }
private RoundTripPerformance MakeBltRoundTrip(LNode[] Nodes) { using (var memStream = new MemoryStream()) { var timer = new Stopwatch(); timer.Start(); var writer = new LoycBinaryWriter(memStream); for (int i = 0; i < TimedRoundTripCount; i++) { writer.WriteFile(Nodes); memStream.Seek(0, SeekOrigin.Begin); } timer.Stop(); var writePerf = timer.Elapsed; long size = memStream.Length; timer.Restart(); for (int i = 0; i < TimedRoundTripCount; i++) { var reader = new LoycBinaryReader(memStream); reader.ReadFile("test.blt"); memStream.Seek(0, SeekOrigin.Begin); } timer.Stop(); var readPerf = timer.Elapsed; return new RoundTripPerformance(readPerf, writePerf, size); } }
public static void SpliceAdd(this RWList<LNode> list, LNode node, Symbol listName) { if (node.Calls(listName)) list.AddRange(node.Args); else list.Add(node); }
public static void SpliceInsert(this RWList<LNode> list, int index, LNode node, Symbol listName) { if (node.Calls(listName)) list.InsertRange(index, node.Args); else list.Insert(index, node); }
public static LNode saveAndRestore(LNode node, IMacroContext context) { var tmp_0 = context.GetArgsAndBody(true); var args = tmp_0.Item1; var body = tmp_0.Item2; if (args.Count == 1) { LNode newValue = null; { var tmp_1 = args[0]; LNode property; if (tmp_1.Calls(CodeSymbols.Assign, 2) && (property = tmp_1.Args[0]) != null && (newValue = tmp_1.Args[1]) != null || (property = tmp_1) != null) { string mainProp = KeyNameComponentOf(property).Name; string varPrefix = "old" + mainProp + "_"; LNode varName, varDecl = TempVarDecl(property, out varName, varPrefix); LNode tryFinally = LNode.Call(CodeSymbols.Try, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(body)).SetStyle(NodeStyle.Statement), LNode.Call(CodeSymbols.Finally, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Assign, LNode.List(property, varName)).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Statement))))); if (newValue != null) { return LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, LNode.Call(CodeSymbols.Assign, LNode.List(property, newValue)).SetStyle(NodeStyle.Operator), tryFinally)); } else { return LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, tryFinally)); } } } } return null; }
public static LNode BackingField(LNode prop, IMessageSink sink) { LNode type, name, body; if (prop.ArgCount != 3 || !(body = prop.Args[2]).Calls(S.Braces)) return null; LNode fieldAttr = null, fieldVarAttr = null; LNode fieldName; bool autoType = false; int i; for (i = 0; i < prop.Attrs.Count; i++) { LNode attr = prop.Attrs[i]; if (attr.IsIdNamed(_field) || attr.Calls(S.Var, 2) && ((autoType = attr.Args[0].IsIdNamed(_field)) || (fieldVarAttr = attr.AttrNamed(_field)) != null && fieldVarAttr.IsId)) { fieldAttr = attr; break; } } if (fieldAttr == null) return null; LNode field = fieldAttr; type = prop.Args[0]; if (field.IsId) { name = prop.Args[1]; fieldName = F.Id(ChooseFieldName(Ecs.EcsNodePrinter.KeyNameComponentOf(name))); field = F.Call(S.Var, type, fieldName).WithAttrs(fieldAttr.Attrs); } else { fieldName = field.Args[1]; if (fieldName.Calls(S.Assign, 2)) fieldName = fieldName.Args[0]; } if (autoType) field = field.WithArgChanged(0, type); if (fieldVarAttr != null) field = field.WithoutAttrNamed(_field); LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt => { var attrs = stmt.Attrs; if (stmt.IsIdNamed(S.get)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldName))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } if (stmt.IsIdNamed(S.set)) { stmt = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldName, F.Id(S.value)))).WithAttrs(attrs); stmt.BaseStyle = NodeStyle.Special; } return stmt; })); if (newBody == body) sink.Write(Severity.Warning, fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field."); prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(2, newBody); return F.Call(S.Splice, new RVList<LNode>(field, prop)); }
public static LNode ForwardProperty(LNode prop, IMacroContext context) { LNode name, fwd, body; if (prop.ArgCount != 4) return null; LNode target = GetForwardingTarget(name = prop.Args[1], fwd = prop.Args[3]); if (target != null) { body = F.Braces(F.Call(S.get, F.Braces(F.Call(S.Return, target))).SetBaseStyle(NodeStyle.Special)); return prop.WithArgChanged(3, body); } else if ((body = fwd).Calls(S.Braces)) { var body2 = body.WithArgs(stmt => { if (stmt.Calls(S.get, 1) && (target = GetForwardingTarget(name, stmt.Args[0])) != null) return stmt.WithArgs(new VList<LNode>(F.Braces(F.Call(S.Return, target)))); if (stmt.Calls(S.set, 1) && (target = GetForwardingTarget(name, stmt.Args[0])) != null) return stmt.WithArgs(new VList<LNode>(F.Braces(F.Call(S.Assign, target, F.Id(S.value))))); return stmt; }); if (body2 != body) return prop.WithArgChanged(3, body2); } return null; }
public static LNode ForwardMethod(LNode fn, IMessageSink sink) { LNode args, fwd, body; if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.List)) return null; RVList<LNode> formalArgs = args.Args; RVList<LNode> argList = RVList<LNode>.Empty; foreach (var formalArg in formalArgs) { if (!formalArg.Calls(S.Var, 2)) return Reject(sink, formalArg, "'==>' expected a variable declaration here"); LNode argName = formalArg.Args[1]; if (argName.Calls(S.Assign, 2)) argName = argName.Args[0]; LNode @ref = formalArg.AttrNamed(S.Ref) ?? formalArg.AttrNamed(S.Out); if (@ref != null) argName = argName.PlusAttr(@ref); argList.Add(argName); } LNode target = GetForwardingTarget(fwd, fn.Args[1]); LNode call = F.Call(target, argList); bool isVoidFn = fn.Args[0].IsIdNamed(S.Void); body = F.Braces(isVoidFn ? call : F.Call(S.Return, call)); return fn.WithArgChanged(3, body); }
public static LNode ForwardProperty(LNode prop, IMessageSink sink) { LNode name, fwd, body; if (prop.ArgCount != 3) return null; LNode target = GetForwardingTarget(fwd = prop.Args[2], name = prop.Args[1]); if (target != null) { body = F.Braces(new RVList<LNode>( F.Call(S.get, F.Braces(F.Call(S.Return, target))), F.Call(S.set, F.Braces(F.Call(S.Assign, target, F.Id(S.value)))))); return prop.WithArgChanged(2, body); } else if ((body = fwd).Calls(S.Braces)) { var body2 = body.WithArgs(stmt => { if (stmt.Calls(S.get, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null) return stmt.WithArgs(new RVList<LNode>(F.Braces(F.Call(S.Return, target)))); if (stmt.Calls(S.set, 1) && (target = GetForwardingTarget(stmt.Args[0], name)) != null) return stmt.WithArgs(new RVList<LNode>(F.Braces(F.Call(S.Assign, target, F.Id(S.value))))); return stmt; }); if (body2 != body) return prop.WithArgChanged(2, body2); } return null; }
public static LNode static_matchCode(LNode node, IMacroContext context) { if (node.AttrNamed(S.Static) == null && !node.HasSpecialName) return null; // handled by normal matchCode macro var args_body = context.GetArgsAndBody(false); VList<LNode> args = args_body.Item1, body = args_body.Item2; if (args.Count != 1) return Reject(context, args[1], "Expected only one expression to match"); var expression = context.PreProcess(AutoStripBraces(args[0])); var cases = GetCases(body, context.Sink); // The `default:` case is represented by an empty list of patterns. if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty)) context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched."); MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>(); foreach (Pair<VList<LNode>, VList<LNode>> pair in cases) { var patterns = pair.Key.IsEmpty ? new VList<LNode>((LNode)null) : pair.Key; foreach (var pattern in patterns) { captures.Clear(); VList<LNode> _; if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _)) { captures[_hash] = expression; // define $# captures.Remove(__); return ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures); } } } return F.Call(S.Splice); // none of the cases matched }
public override Pred CodeToTerminalPred(LNode expr, ref string errorMsg) { bool isInt = false; PGIntSet set; if (expr.IsIdNamed(_underscore)) { set = PGIntSet.AllExceptEOF; } else if (expr.IsIdNamed(_EOF)) { set = PGIntSet.EOF; } else if (expr.Calls(S.DotDot, 2)) { int? from = ConstValue(expr.Args[0], ref isInt); int? to = ConstValue(expr.Args[1], ref isInt); if (from == null || to == null) { errorMsg = "Expected int32 or character literal on each side of «..»"; return null; } set = PGIntSet.WithRanges(from.Value, to.Value); } else if (expr.Value is string) { return Pred.Seq((string)expr.Value); } else { int? num = ConstValue(expr, ref isInt); if (num == null) { errorMsg = "Unrecognized expression. Expected int32 or character literal instead of: " + expr.ToString(); // warning return null; } set = PGIntSet.With(num.Value); } set.IsCharSet = !isInt; return new TerminalPred(expr, set, true); }
public static LNode _set(LNode node, IMacroContext context) { var lhs = node.Args[0, LNode.Missing]; var name = lhs.Name; bool isSnippet = name == _hash_snippet; if ((isSnippet || name == _hash_set) && node.ArgCount == 2 && lhs.IsId) { node = context.PreProcessChildren(); Symbol newTarget = isSnippet ? _hash_setScopedPropertyQuote : _hash_setScopedProperty; var stmts = node.Args.Slice(1).Select(key => { LNode value = F.@true; if (key.Calls(S.Assign, 2)) { value = key.Args[1]; key = key.Args[0]; if (isSnippet && value.Calls(S.Braces)) value = value.Args.AsLNode(S.Splice); } if (!key.IsId) context.Write(Severity.Error, key, "Invalid key; expected an identifier."); return node.With(newTarget, LNode.Literal(key.Name, key), value); }); return F.Call(S.Splice, stmts); } return null; }
public static RVList<LNode> WithSpliced(this RVList<LNode> list, int index, LNode node, Symbol listName) { if (node.Calls(listName)) return list.InsertRange(index, node.Args); else return list.Insert(index, node); }
Mode = MacroMode.ProcessChildrenBefore)] // post-normal-macro-expansion public static LNode with(LNode fn, IMacroContext context) { LNode braces; if (fn.ArgCount != 2 || !(braces = fn.Args[1]).Calls(S.Braces)) return null; LNode tmp = F.Id(NextTempName(context)); WList<LNode> stmts = braces.Args.ToWList(); stmts = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(expr => { if (expr.Calls(S.Dot, 1)) return expr.WithArgs(new VList<LNode>(tmp, expr.Args.Last)); else if (expr.IsIdNamed("#")) return tmp; return null; })); stmts.Insert(0, F.Var(null, tmp.Name, fn.Args[0])); if (IsExpressionContext(context)) { stmts.Add(tmp); return F.Call("#runSequence", stmts.ToVList()); } else { return F.Braces(stmts.ToVList()); } }
public static LNode runSequence(LNode node, IMacroContext context) { if (context.Parent.Calls(S.Braces)) return node.With(S.Splice, MaybeRemoveNoOpFromRunSeq(node.Args)); if (!context.ScopedProperties.ContainsKey(_useSequenceExpressionsIsRunning)) Reject(context, node, "#useSequenceExpressions is required to make #runSequence work"); return null; }
public static LNode static_tryDeconstruct(LNode node, IMacroContext context) { if (node.AttrNamed(S.Static) == null && !node.HasSpecialName) return Reject(context, node, "Expected 'static' attribute"); foreach (var arg in node.Args) DoDeconstruct(arg, context, printErrorOnFailure: false); return F.Call(S.Splice); }
public Rule(LNode basis, Symbol name, Pred pred, bool isStartingRule = true) { Basis = basis; Pred = pred; Name = name; IsStartingRule = isStartingRule; EndOfRule = new EndOfRule(this); if (basis != null && basis.Calls(S.Fn) && basis.ArgCount >= 3) ReturnType = basis.Args[0]; }
public static LNode on_throw(LNode node, IMacroContext context) { LNode firstArg, rest, on_handler = ValidateOnStmt(node, context, out rest, out firstArg); if (on_handler == null) return null; on_handler = on_handler.PlusArg(F.Call(S.Throw)); return TransformOnCatch(node, firstArg, rest, on_handler); }
public static LNode useDefaultTupleTypes(LNode node, IMacroContext context) { if (node.ArgCount != 0) return null; context.ScopedProperties.Remove(TupleMakers); context.ScopedProperties.Remove(DefaultTupleMaker); return F.Call(S.Splice); }
public static LNode tom(LNode node, IMacroContext context) { return(LNode.Id("tommy")); }
public static string Print(this IParsingService self, LNode node) { return(self.Print(node, MessageSink.Current)); }
public static bool IsParenthesizedExpr(this LNode node) { return(node.AttrNamed(CodeSymbols.TriviaInParens) != null); }
protected LiteralNode(LNode ras) : base(ras) { }
protected CallNode(LNode ras) : base(ras) { }
public static LNode partlyDeprecatedMacro(LNode node, IMacroContext context) { return(LNode.Id("multi_name_macro")); }
public static VList <LNode> WithoutNodeNamed(this VList <LNode> list, Symbol name, out LNode removedNode) { removedNode = null; for (int i = 0, c = list.Count; i < c; i++) { if (list[i].Name == name) { removedNode = list[i]; return(list.RemoveAt(i)); } } return(list); }
private void Test(string input, string output, int maxExpand = 0xFFFF, IParsingService parser = null, ILNodePrinter printer = null, IMessageSink sink = null) { using (ParsingService.SetDefault(parser ?? Les2LanguageService.Value)) using (LNode.SetPrinter(printer ?? EcsLanguageService.WithPlainCSharpPrinter)) TestCompiler.Test(input, output, sink ?? _sink, maxExpand, "LeMP.les2.to.ecs"); }
public static LNode WithoutAttrNamed(this LNode self, Symbol name) { LNode _; return(WithoutAttrNamed(self, name, out _)); }
static void AddCapture(MMap <Symbol, LNode> captures, Symbol capName, LNode candidate) { LNode oldCap = captures.TryGetValue(capName, null); captures[capName] = LNode.MergeLists(oldCap, candidate, S.Splice); }
public static bool MatchesPattern(this LNode candidate, LNode pattern, out IDictionary <Symbol, LNode> captures) { VList <LNode> unmatchedAttrs; return(MatchesPattern(candidate, pattern, out captures, out unmatchedAttrs)); }
void PrintMessages(List <Result> results, LNode input, int accepted, Severity maxSeverity) { if (accepted > 1) { // Multiple macros accepted the input. If AllowDuplicates is used, // this is fine if as long as they produced the same result. bool allowed, equal = AreResultsEqual(results, out allowed); if (!equal || !allowed) { string list = results.Where(r => r.Node != null).Select(r => QualifiedName(r.Macro.Macro.Method)).Join(", "); if (equal) { _sink.Write(Severity.Warning, input, "Ambiguous macro call. {0} macros accepted the input and produced identical results: {1}", accepted, list); } else { _sink.Write(Severity.Error, input, "Ambiguous macro call. {0} macros accepted the input: {1}", accepted, list); } } } bool macroStyleCall = input.BaseStyle == NodeStyle.Special; if (accepted > 0 || macroStyleCall || maxSeverity >= Severity.Warning) { if (macroStyleCall && maxSeverity < Severity.Warning) { maxSeverity = Severity.Warning; } var rejected = results.Where(r => r.Node == null && (r.Macro.Mode & MacroMode.Passive) == 0); if (accepted == 0 && macroStyleCall && _sink.IsEnabled(maxSeverity) && rejected.Any()) { _sink.Write(maxSeverity, input, "{0} macro(s) saw the input and declined to process it: {1}", results.Count, rejected.Select(r => QualifiedName(r.Macro.Macro.Method)).Join(", ")); } foreach (var result in results) { bool printedLast = true; foreach (var msg in result.Msgs) { // Print all messages from macros that accepted the input. // For rejecting macros, print warning/error messages, and // other messages when macroStyleCall. if (_sink.IsEnabled(msg.Severity) && (result.Node != null || (msg.Severity == Severity.Detail && printedLast) || msg.Severity >= Severity.Warning || macroStyleCall)) { var msg2 = new MessageHolder.Message(msg.Severity, msg.Context, QualifiedName(result.Macro.Macro.Method) + ": " + msg.Format, msg.Args); msg2.WriteTo(_sink); printedLast = true; } else { printedLast = false; } } } } }
public static LNode WithoutAttr(this LNode self, LNode node) { return(self.WithAttrs(self.Attrs.Without(node))); }
public static LNode bob(LNode node, IMacroContext context) { return(LNode.Id("bobby")); }
public static LNode braceTheRest(LNode node, IMacroContext context) { context.DropRemainingNodes = true; return(LNode.Call(S.Braces, LNode.List(context.RemainingNodes))); }
/// <summary>Returns the same node with a parentheses attribute added.</summary> public static LNode InParens(this LNode node) { return(node.PlusAttrBefore(LNode.Id(CodeSymbols.TriviaInParens))); }
public static LNode splice(LNode node, IMessageSink sink) { return(node.WithName(S.Splice)); }
/// <summary>Interprets a node as a list by returning <c>block.Args</c> if /// <c>block.Calls(listIdentifier)</c>, otherwise returning a one-item list /// of nodes with <c>block</c> as the only item.</summary> public static VList <LNode> AsList(this LNode block, Symbol listIdentifier) { return(block.Calls(listIdentifier) ? block.Args : new VList <LNode>(block)); }
public static LNode uppercasemacro(LNode node, IMacroContext context) { return(LNode.Id("UPPERCASE")); }
/// <summary>Adds additional trailing trivia to a node.</summary> public static LNode PlusTrailingTrivia(this LNode node, LNode trivia) { return(node.WithAttrs(PlusTrailingTrivia(node.Attrs, trivia))); }
public static LNode DeprecatedMacro(LNode node, IMacroContext context) { return(LNode.Id("groovy_macro_dude")); }
private LNode Term() { TokenType la0; LNode first = default(LNode); List <LNode> rest = new List <LNode>(); LNode result = default(LNode); // Line 222: ( TT.Id | TT.Num | TT.LBrace TT.RBrace | TT.LBrace Expr (TT.Comma Expr)* TT.RBrace | TT.LParen Expr TT.RParen ) do { la0 = (TokenType)LA0; if (la0 == TT.Id) { var t = MatchAny(); // line 222 result = F.Id(t); } else if (la0 == TT.Num) { var t = MatchAny(); // line 223 result = F.Literal(t); } else if (la0 == TT.LBrace) { switch ((TokenType)LA(1)) { case TT.RBrace: { Skip(); Skip(); // line 224 result = F.AltList(); } break; case TT.Id: case TT.LBrace: case TT.LParen: case TT.Num: case TT.Sub: { Skip(); first = Expr(); // Line 225: (TT.Comma Expr)* for (;;) { la0 = (TokenType)LA0; if (la0 == TT.Comma) { Skip(); rest.Add(Expr()); } else { break; } } Match((int)TT.RBrace); // line 225 result = F.AltList(rest?.Prepend(first) ?? Enumerable.Repeat(first, 1)); } break; default: goto error; } } else if (la0 == TT.LParen) { Skip(); result = Expr(); Match((int)TT.RParen); // line 226 result = F.InParens(result); } else { goto error; } break; error: { // line 227 result = F.Missing; Error(0, "Expected identifer, number, or (parens)"); } } while (false); return(result); }
protected IdNode(LNode ras) : base(ras) { }
// Handle multiple precedence levels with one rule, as explained in Part 5 article private LNode Expr(int prec = 0) { LNode result = default(LNode); result = PrefixExpr(); // Line 198: greedy( &{prec <= 10} TT.LBrace Expr TT.RBrace | &{prec <= 20} TT.Assign Expr | &{prec < 30} (TT.Eq|TT.GE|TT.GT|TT.LE|TT.LT|TT.NotEq) Expr | &{prec < 40} (TT.Add|TT.Sub) Expr | &{prec < 50} (TT.Div|TT.Mul) Expr )* for (;;) { switch ((TokenType)LA0) { case TT.LBrace: { if (prec <= 10) { Skip(); var index = Expr(); Match((int)TT.RBrace); // line 200 result = F.Call(S.IndexBracks, F.AltList(result, index)); } else { goto stop; } } break; case TT.Assign: { if (prec <= 20) { var op = MatchAny(); var r = Expr(20); // line 203 result = BinOp((Symbol)op.Value, result, r); } else { goto stop; } } break; case TT.Eq: case TT.GE: case TT.GT: case TT.LE: case TT.LT: case TT.NotEq: { if (prec < 30) { var op = MatchAny(); var r = Expr(30); // line 206 result = BinOp((Symbol)op.Value, result, r); } else { goto stop; } } break; case TT.Add: case TT.Sub: { if (prec < 40) { var op = MatchAny(); var r = Expr(40); // line 209 result = BinOp((Symbol)op.Value, result, r); } else { goto stop; } } break; case TT.Div: case TT.Mul: { if (prec < 50) { var op = MatchAny(); var r = Expr(50); // line 212 result = BinOp((Symbol)op.Value, result, r); } else { goto stop; } } break; default: goto stop; } } stop :; return(result); }
LNode BinOp(Symbol type, LNode lhs, LNode rhs) => F.Call(type, lhs, rhs, lhs.Range.StartIndex, rhs.Range.EndIndex);
public static LNode ArgNamed(this LNode self, Symbol name) { return(self.Args.NodeNamed(name)); }
/// <summary>Returns the same node with a parentheses attribute added.</summary> public static LNode InParens(this LNode node, ISourceFile file, int startIndex, int endIndex) { return(InParens(node, new SourceRange(file, startIndex, endIndex - startIndex))); }
/// <summary>Gets all trailing trivia attached to the specified node.</summary> public static VList <LNode> GetTrailingTrivia(this LNode node) { return(GetTrailingTrivia(node.Attrs)); }
/// <summary>Returns the same node with a parentheses attribute added.</summary> /// <remarks>The node's range is changed to the provided <see cref="SourceRange"/> /// and the original range of the node is assigned to the parentheses attribute.</remarks> public static LNode InParens(this LNode node, SourceRange range) { return(node.WithRange(range).PlusAttrBefore(LNode.Id(CodeSymbols.TriviaInParens))); }
private LNode ApplyMacrosFound2(LNode input, int maxExpansions, ListSlice <MacroInfo> foundMacros, ref ApplyMacroState s) { s.results.Clear(); s.messageHolder.List.Clear(); int accepted = 0, acceptedIndex = -1; for (int i = 0; i < foundMacros.Count; i++) { var macro = foundMacros[i]; var macroInput = input; if ((macro.Mode & MacroMode.ProcessChildrenBefore) != 0) { if (maxExpansions == 1) { continue; // avoid expanding both this macro and its children } if (s.preprocessed == null) { // _foundMacros, _results, and _messageHolder are re-used // by callee for unrelated contexts, so make copies of the s.* // variables which point to them. s.foundMacros = new List <MacroInfo>(s.foundMacros); s.results = new List <Result>(s.results); s.messageHolder = s.messageHolder.Clone(); foundMacros = new List <MacroInfo>(foundMacros).Slice(0); s.preprocessed = ApplyMacrosToChildren(input, maxExpansions) ?? input; } macroInput = s.preprocessed; } LNode output = null; int mhi = s.messageHolder.List.Count; try { output = macro.Macro(macroInput, s.messageHolder); if (output != null) { accepted++; acceptedIndex = i; } } catch (ThreadAbortException e) { _sink.Write(Severity.Error, input, "Macro-processing thread aborted in {0}", QualifiedName(macro.Macro.Method)); _sink.Write(Severity.Detail, input, e.StackTrace); s.results.Add(new Result(macro, output, s.messageHolder.List.Slice(mhi, s.messageHolder.List.Count - mhi))); PrintMessages(s.results, input, accepted, Severity.Error); throw; } catch (Exception e) { s.messageHolder.Write(Severity.Error, input, "{0}: {1}", e.GetType().Name, e.Message); s.messageHolder.Write(Severity.Detail, input, e.StackTrace); } s.results.Add(new Result(macro, output, s.messageHolder.List.Slice(mhi, s.messageHolder.List.Count - mhi))); } PrintMessages(s.results, input, accepted, s.messageHolder.List.MaxOrDefault(msg => (int)msg.Severity).Severity); if (accepted >= 1) { var result = s.results[acceptedIndex]; Debug.Assert(result.Node != null); if ((result.Macro.Mode & MacroMode.ProcessChildrenBefore) != 0) { maxExpansions--; } if ((result.Macro.Mode & MacroMode.Normal) != 0) { if (result.Node == input) { return(ApplyMacrosToChildren(result.Node, maxExpansions - 1) ?? result.Node); } else { return(ApplyMacros(result.Node, maxExpansions - 1) ?? result.Node); } } else if ((result.Macro.Mode & MacroMode.ProcessChildrenAfter) != 0) { return(ApplyMacrosToChildren(result.Node, maxExpansions - 1) ?? result.Node); } else { return(result.Node); } } else { // "{}" needs special treatment if (input.Calls(S.Braces)) { try { return(s.preprocessed ?? ApplyMacrosToChildren(input, maxExpansions)); } finally { PopScope(); } } return(s.preprocessed ?? ApplyMacrosToChildren(input, maxExpansions)); } }