Пример #1
0
 static LNode MaybeQuoteList(VList <LNode> list, bool substitutions)
 {
     if (list.IsEmpty)
     {
         return(null);
     }
     else if (substitutions && list.Any(a => VarArgExpr(a) != null))
     {
         if (list.Count == 1)
         {
             return(F.Call(LNode_List, VarArgExpr(list[0])));
         }
         // If you write something like quote(Foo($x, $(...y), $z)), a special
         // output style is used to accommodate the variable argument list.
         LNode argList = F.Call(LNode_List);
         foreach (LNode arg in list)
         {
             var vae = VarArgExpr(arg);
             if (vae != null)
             {
                 argList = F.Call(F.Dot(argList, F.Id("AddRange")), vae);
             }
             else
             {
                 argList = F.Call(F.Dot(argList, F.Id("Add")), QuoteOne(arg, substitutions));
             }
         }
         return(argList);
     }
     else
     {
         return(F.Call(LNode_List, list.SmartSelect(item => QuoteOne(item, substitutions))));
     }
 }
Пример #2
0
        /// <summary>Searches a list of expressions/statements for one or more
        /// patterns, and performs replacements.</summary>
        /// <param name="stmts">A list of expressions/statements in which to search.</param>
        /// <param name="patterns">Each pair consists of (A) something to search
        /// for and (B) a replacement expression. Part A can use the substitution
        /// operator with an identifier inside (e.g. $Foo) to "capture" any
        /// subexpression, and part B can use the same substitution (e.g. $Foo)
        /// to insert the captured subexpression(s) into the output.</param>
        /// <param name="replacementCount">Number of replacements that occurred.</param>
        /// <returns>The result of applying the replacements.</returns>
        /// <remarks><see cref="LNodeExt.MatchesPattern"/> is used for matching.</remarks>
        public static VList <LNode> Replace(VList <LNode> stmts, Pair <LNode, LNode>[] patterns, out int replacementCount)
        {
            // This list is used to support simple token replacement in TokenTrees
            _tokenTreeRepls = InternalList <Triplet <Symbol, LNode, int> > .Empty;
            foreach (var pair in patterns)             // Look for Id => Id or Id => Literal
            {
                if (pair.A.IsId && (pair.B.IsId || pair.B.IsLiteral))
                {
                    _tokenTreeRepls.Add(new Triplet <Symbol, LNode, int>(pair.A.Name, pair.B, 0));
                }
            }

            // Scan the syntax tree for things to replace...
            int count  = 0;
            var temp   = new MMap <Symbol, LNode>();
            var output = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
                LNode r = TryReplaceHere(n, patterns, temp);
                if (r != null)
                {
                    count++;
                }
                return(r);
            }));

            replacementCount = count;
            return(output);
        }
Пример #3
0
            LNode ESEInForLoop(LNode stmt, VList <LNode> attrs, VList <LNode> init, LNode cond, VList <LNode> inc, LNode block)
            {
                // TODO: handle multi-int and multi-inc
                var preInit   = VList <LNode> .Empty;
                var init_apos = init.SmartSelect(init1 => {
                    init1 = EliminateSequenceExpressionsInExecStmt(init1);
                    if (init1.CallsMin(__numrunSequence, 1))
                    {
                        preInit.AddRange(init1.Args.WithoutLast(1));
                        return(init1.Args.Last);
                    }
                    return(init1);
                });
                var cond_apos = BubbleUpBlocks(cond);
                var inc_apos  = inc.SmartSelectMany(inc1 => {
                    inc1 = BubbleUpBlocks(inc1);
                    return(inc1.AsList(__numrunSequence));
                });

                block = EliminateSequenceExpressionsInChildStmt(block);
                if (init_apos != init || cond_apos != cond || inc_apos != inc)
                {
                    init = init_apos;
                    if (inc_apos != inc)
                    {
                        var blockStmts = block.AsList(S.Braces).AddRange(inc_apos);
                        block = blockStmts.AsLNode(S.Braces);
                        inc   = LNode.List();
                    }
                    if (cond_apos.CallsMin(__numrunSequence, 1))
                    {
                        var preCond = cond_apos.Args.WithoutLast(1);
                        cond = cond_apos.Args.Last;
                        stmt = LNode.Call(CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), LNode.Missing, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preCond).Add(LNode.Call(CodeSymbols.If, LNode.List(cond, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
                    }
                    else
                    {
                        stmt = LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), cond, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), block));
                    }
                    if (preInit.Count != 0)
                    {
                        stmt = LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preInit).Add(stmt)).SetStyle(NodeStyle.Statement);
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt.WithArgChanged(3, block));
                }
            }
Пример #4
0
		public static LNode UseSymbolsCore(VList<LNode> symbolAttrs, VList<LNode> options, VList<LNode> body, IMacroContext context, bool inType)
		{
			// Decode options (TODO: invent a simpler approach)
			string prefix = "sy_";
			var inherited = new HashSet<Symbol>();
			foreach (var pair in MacroContext.GetOptions(options))
			{
				if (pair.Key.Name.Name == "prefix" && pair.Value.IsId)
					prefix = pair.Value.Name.Name;
				else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol)
					inherited.Add((Symbol)pair.Value.Value);
				else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
					foreach (var arg in pair.Value.Args)
						inherited.Add((Symbol)arg.Value);
				else
					context.Sink.Warning(pair.Value, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
			}

			// Replace all symbols while collecting a list of them
			var symbols = new Dictionary<Symbol, LNode>();
			VList<LNode> output = body.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
				if (!inType && n.ArgCount == 3) {
					// Since we're outside any type, we must avoid creating symbol 
					// fields. When we cross into a type then we can start making
					// Symbols by calling ourself recursively with inType=true
					var kind = EcsValidators.SpaceDefinitionKind(n);
					if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait) {
						var body2 = n.Args[2];
						return n.WithArgChanged(2, UseSymbolsCore(symbolAttrs, options, body2.Args, context, true).WithName(body2.Name));
					}
				}
				var sym = n.Value as Symbol;
				if (n.IsLiteral && sym != null)
					return symbols[sym] = LNode.Id(prefix + sym.Name);
				return null;
			}));

			// Return updated code with variable declaration at the top for all non-inherit symbols used.
			var _Symbol = F.Id("Symbol");
			var vars = (from sym in symbols
			            where !inherited.Contains(sym.Key)
			            select F.Call(S.Assign, sym.Value, 
			                   F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();
			if (vars.Count > 0)
				output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
					.WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
			return F.Call(S.Splice, output);
		}
Пример #5
0
 LNode MaybeQuoteList(VList <LNode> list, bool isAttributes = false)
 {
     if (isAttributes && _ignoreTrivia)
     {
         list = list.SmartWhere(n => !n.IsTrivia || n.IsIdNamed(S.TriviaInParens));
     }
     if (list.IsEmpty)
     {
         return(null);
     }
     else if (_doSubstitutions && list.Any(a => VarArgExpr(a) != null))
     {
         if (list.Count == 1)
         {
             return(F.Call(LNode_List, VarArgExpr(list[0])));
         }
         // If you write something like quote(Foo($x, $(...y), $z)), a special
         // output style is used to accommodate the variable argument list.
         LNode argList = F.Call(LNode_List);
         foreach (LNode arg in list)
         {
             var vae = VarArgExpr(arg);
             if (vae != null)
             {
                 argList = F.Call(F.Dot(argList, F.Id("AddRange")), vae);
             }
             else
             {
                 argList = F.Call(F.Dot(argList, F.Id("Add")), QuoteOne(arg));
             }
         }
         return(argList);
     }
     else
     {
         return(F.Call(LNode_List, list.SmartSelect(item => QuoteOne(item))));
     }
 }
Пример #6
0
        static VList <LNode> AddLineDirectives(VList <LNode> nodes, bool stmtContext, ref int sourceLine_)
        {
            int sourceLine = sourceLine_;

            nodes = nodes.SmartSelect(node => {
                if (stmtContext && sourceLine > 0 && node.AttrNamed(S.TriviaAppendStatement) == null)
                {
                    sourceLine++;                     // printer will print a newline by default
                }
                int explicitNewlines = node.Attrs.Count(n => n.IsIdNamed(S.TriviaNewline));
                sourceLine          += explicitNewlines;

                // Generate line directive if necessary; to avoid excess
                // clutter, don't consider emit #line directives within an expression.
                string lineDirective = null;
                if (stmtContext || explicitNewlines != 0)
                {
                    if (node.Range.Source is EmptySourceFile || string.IsNullOrEmpty(node.Range.Source.FileName))
                    {
                        // synthetic code: no source location
                        if (sourceLine != -1)
                        {
                            sourceLine    = -1;
                            lineDirective = "#line default";
                        }
                    }
                    else
                    {
                        var start = node.Range.Start;
                        if (sourceLine != start.Line)
                        {
                            sourceLine    = start.Line;
                            lineDirective = "#line " + start.Line + " " + EcsNodePrinter.PrintString(start.FileName, '"');
                        }
                    }
                }

                int sourceLineWas = sourceLine;

                if (node.Name.Name.StartsWith("#") && node.ArgCount > 1)
                {
                    // For some special calls like #if, #while, and #doWhile,
                    // printer might print newlines in places we don't know about,
                    // so erase our knowledge of what the current line is.
                    if (sourceLine > 0)
                    {
                        sourceLine = int.MinValue;
                    }
                }

                // Process children
                node = node.WithAttrs(AddLineDirectives(node.Attrs, false, ref sourceLine));
                if (node.IsCall)
                {
                    node = node.WithArgs(AddLineDirectives(node.Args, node.Calls(S.Braces), ref sourceLine));
                }

                if (sourceLine > 0)
                {
                    sourceLine += node.GetTrailingTrivia().Count(n => n.IsIdNamed(S.TriviaNewline));
                }

                // Finally, add a line directive if requested.
                if (lineDirective != null)
                {
                    var trivia = F.Trivia(S.TriviaCsPPRawText, lineDirective);
                    if (!node.Attrs.Contains(trivia))
                    {
                        // Trivia tends not to be included in the source range so adding #line
                        // before trivia is generally wrong, while adding #line after attributes
                        // tends to be wrong too. Sigh. Search for a good location to insert...
                        // unless inserting #line default which we can just put at the beginning
                        int insertIndex = 0;
                        if (sourceLineWas > 0)
                        {
                            insertIndex = node.Attrs.IndexWhere(n => n.Range.Start.Line == sourceLineWas && n.Range.Source == node.Range.Source);
                            if (insertIndex == -1)
                            {
                                insertIndex = node.Attrs.Count;
                            }
                        }
                        node = node.WithAttrs(node.Attrs.Insert(insertIndex, trivia));
                    }
                }

                return(node);
            });
            sourceLine_ = sourceLine;
            return(nodes);
        }
Пример #7
0
		/// <summary>Searches a list of expressions/statements for one or more 
		/// patterns, and performs replacements.</summary>
		/// <param name="stmts">A list of expressions/statements in which to search.</param>
		/// <param name="patterns">Each pair consists of (A) something to search 
		/// for and (B) a replacement expression. Part A can use the substitution
		/// operator with an identifier inside (e.g. $Foo) to "capture" any 
		/// subexpression, and part B can use the same substitution (e.g. $Foo)
		/// to insert the captured subexpression(s) into the output.</param>
		/// <param name="replacementCount">Number of replacements that occurred.</param>
		/// <returns>The result of applying the replacements.</returns>
		/// <remarks><see cref="LNodeExt.MatchesPattern"/> is used for matching.</remarks>
		public static VList<LNode> Replace(VList<LNode> stmts, Pair<LNode, LNode>[] patterns, out int replacementCount)
		{
			// This list is used to support simple token replacement in TokenTrees
			_tokenTreeRepls = InternalList<Triplet<Symbol, LNode, int>>.Empty;
			foreach (var pair in patterns) // Look for Id => Id or Id => Literal
				if (pair.A.IsId && (pair.B.IsId || pair.B.IsLiteral))
					_tokenTreeRepls.Add(new Triplet<Symbol,LNode,int>(pair.A.Name, pair.B, 0));

			// Scan the syntax tree for things to replace...
			int count = 0;
			var temp = new MMap<Symbol, LNode>();
			var output = stmts.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
				LNode r = TryReplaceHere(n, patterns, temp);
				if (r != null) count++;
				return r;
			}));
			replacementCount = count;
			return output;
		}
Пример #8
0
 public VList <LNode> EliminateBlockExprs(VList <LNode> stmts, bool isDeclContext)
 {
     return(stmts.SmartSelect(stmt => {
         return EliminateBlockExprs(stmt, isDeclContext);
     }));
 }
Пример #9
0
        public static LNode UseSymbolsCore(VList <LNode> symbolAttrs, VList <LNode> options, VList <LNode> body, IMacroContext context, bool inType)
        {
            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(options))
            {
                if (pair.Key.Name.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Warning(pair.Value, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var           symbols = new Dictionary <Symbol, LNode>();
            VList <LNode> output  = body.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
                if (!inType && n.ArgCount == 3)
                {
                    // Since we're outside any type, we must avoid creating symbol
                    // fields. When we cross into a type then we can start making
                    // Symbols by calling ourself recursively with inType=true
                    var kind = EcsValidators.SpaceDefinitionKind(n);
                    if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait)
                    {
                        var body2 = n.Args[2];
                        return(n.WithArgChanged(2, UseSymbolsCore(symbolAttrs, options, body2.Args, context, true).WithName(body2.Name)));
                    }
                }
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + sym.Name));
                }
                return(null);
            }));

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(F.Call(S.Splice, output));
        }
Пример #10
0
		static VList<LNode> AddLineDirectives(VList<LNode> nodes, bool stmtContext, ref int sourceLine_)
		{
			int sourceLine = sourceLine_;
			nodes = nodes.SmartSelect(node => {
				if (stmtContext && sourceLine > 0 && node.AttrNamed(S.TriviaAppendStatement) == null)
					sourceLine++; // printer will print a newline by default

				int explicitNewlines = node.Attrs.Count(n => n.IsIdNamed(S.TriviaNewline));
				sourceLine += explicitNewlines;

				// Generate line directive if necessary; to avoid excess 
				// clutter, don't consider emit #line directives within an expression.
				string lineDirective = null;
				if (stmtContext || explicitNewlines != 0) {
					if (node.Range.Source is EmptySourceFile || string.IsNullOrEmpty(node.Range.Source.FileName)) {
						// synthetic code: no source location
						if (sourceLine != -1) {
							sourceLine = -1;
							lineDirective = "#line default";
						}
					} else {
						var start = node.Range.Start;
						if (sourceLine != start.Line) {
							sourceLine = start.Line;
							lineDirective = "#line "+start.Line+" "+EcsNodePrinter.PrintString(start.FileName, '"');
						}
					}
				}

				int sourceLineWas = sourceLine;

				if (node.Name.Name.StartsWith("#") && node.ArgCount > 1) {
					// For some special calls like #if, #while, and #doWhile, 
					// printer might print newlines in places we don't know about,
					// so erase our knowledge of what the current line is.
					if (sourceLine > 0)
						sourceLine = int.MinValue;
				}

				// Process children
				node = node.WithAttrs(AddLineDirectives(node.Attrs, false, ref sourceLine));
				if (node.IsCall)
					node = node.WithArgs(AddLineDirectives(node.Args, node.Calls(S.Braces), ref sourceLine));

				if (sourceLine > 0)
					sourceLine += node.GetTrailingTrivia().Count(n => n.IsIdNamed(S.TriviaNewline));

				// Finally, add a line directive if requested.
				if (lineDirective != null) {
					var trivia = F.Trivia(S.TriviaCsPPRawText, lineDirective);
					if (!node.Attrs.Contains(trivia)) {
						// Trivia tends not to be included in the source range so adding #line
						// before trivia is generally wrong, while adding #line after attributes
						// tends to be wrong too. Sigh. Search for a good location to insert...
						// unless inserting #line default which we can just put at the beginning
						int insertIndex = 0;
						if (sourceLineWas > 0) {
							insertIndex = node.Attrs.IndexWhere(n => n.Range.Start.Line == sourceLineWas && n.Range.Source == node.Range.Source);
							if (insertIndex == -1)
								insertIndex = node.Attrs.Count;
						}
						node = node.WithAttrs(node.Attrs.Insert(insertIndex, trivia));
					}
				}

				return node;
			});
			sourceLine_ = sourceLine;
			return nodes;
		}
Пример #11
0
			LNode ESEInForLoop(LNode stmt, VList<LNode> attrs, VList<LNode> init, LNode cond, VList<LNode> inc, LNode block)
			{
				// TODO: handle multi-int and multi-inc
				var preInit = VList<LNode>.Empty;
				var init_apos = init.SmartSelect(init1 => {
					init1 = EliminateSequenceExpressionsInExecStmt(init1);
					if (init1.CallsMin(__numrunSequence, 1)) {
						preInit.AddRange(init1.Args.WithoutLast(1));
						return init1.Args.Last;
					}
					return init1;
				});
				var cond_apos = BubbleUpBlocks(cond);
				var inc_apos = inc.SmartSelectMany(inc1 => {
					inc1 = BubbleUpBlocks(inc1);
					return inc1.AsList(__numrunSequence);
				});
			
				block = EliminateSequenceExpressionsInChildStmt(block);
				if (init_apos != init || cond_apos != cond || inc_apos != inc) {
					init = init_apos;
					if (inc_apos != inc) {
						var blockStmts = block.AsList(S.Braces).AddRange(inc_apos);
						block = blockStmts.AsLNode(S.Braces);
						inc = LNode.List();
					}
					if (cond_apos.CallsMin(__numrunSequence, 1)) {
						var preCond = cond_apos.Args.WithoutLast(1);
						cond = cond_apos.Args.Last;
						stmt = LNode.Call(CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), LNode.Missing, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preCond).Add(LNode.Call(CodeSymbols.If, LNode.List(cond, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
					} else {
						stmt = LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(init)), cond, LNode.Call(CodeSymbols.AltList, LNode.List(inc)), block));
					}
					if (preInit.Count != 0) {
						stmt = LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(preInit).Add(stmt)).SetStyle(NodeStyle.Statement);
					}
					return stmt;
				} else {
					return stmt.WithArgChanged(3, block);
				}
			}