示例#1
0
        public static LNode static_if(LNode @if, IMacroContext context)
        {
            if (!Range.IsInRange(@if.ArgCount, 2, 3))
            {
                return(null);
            }
            LNode  cond = context.PreProcess(@if.Args[0]);
            object @bool;

            if ((@bool = cond.Value) is bool)
            {
                LNode output = (bool)@bool ? @if.Args[1] : @if.Args.TryGet(2, null) ?? F.Call(S.Splice);
                if (output.Calls(S.Braces))
                {
                    return(output.WithTarget(S.Splice));
                }
                else
                {
                    return(output);
                }
            }
            else
            {
                return(Reject(context, @if.Args[0], "'static if' is incredibly limited right now. Currently it only supports a literal boolean or (x `tree==` y)"));
            }
        }
示例#2
0
        public static LNode unroll(LNode node, IMacroContext context)
        {
            LNode clause;

            // unroll (X, Y) \in ((X, Y), (Y, X)) {...}
            // unroll ((X, Y) in ((X, Y), (Y, X))) {...}
            if (node.ArgCount == 2 && ((clause = node.Args[0]).Calls(@in, 2) || clause.Calls(S.In, 2)))
            {
                LNode identifiers = clause.Args[0], cases = clause.Args[1];
                if (!cases.Calls(S.Tuple) && !cases.Calls(S.Braces) && !cases.Calls(S.Splice))
                {
                    cases = context.PreProcess(cases);
                    if (!cases.Calls(S.Tuple) && !cases.Calls(S.Braces) && !cases.Calls(S.Splice))
                    {
                        return(Reject(context, cases, "The right-hand side of 'in' should be a tuple or braced block."));
                    }
                }
                var result = unroll(identifiers, cases.Args, node.Args[1], context.Sink);
                if (result != null && node.HasPAttrs())
                {
                    context.Sink.Warning(result.Attrs[0], "'unroll' does not support attributes.");
                }
                return(result);
            }
            return(null);
        }
示例#3
0
        public static Symbol NextTempName(IMacroContext ctx, LNode value)
        {
            string prefix = value.Name.Name;

            prefix = EcsValidators.IsPlainCsIdentifier(prefix) ? prefix + "_" : "tmp_";
            return(NextTempName(ctx, prefix));
        }
示例#4
0
        public static LNode match(LNode node, IMacroContext context)
        {
            {
                LNode         input;
                VList <LNode> contents;
                if (node.Args.Count == 2 && (input = node.Args[0]) != null && node.Args[1].Calls(CodeSymbols.Braces))
                {
                    contents = node.Args[1].Args;
                    var outputs = new WList <LNode>();
                    input = MaybeAddTempVarDecl(context, input, outputs);

                    int next_i = 0;
                    for (int case_i = 0; case_i < contents.Count; case_i = next_i)
                    {
                        var @case = contents[case_i];
                        if (!IsCaseLabel(@case))
                        {
                            return(Reject(context, contents[0], "In 'match': expected 'case' statement"));
                        }
                        for (next_i = case_i + 1; next_i < contents.Count; next_i++)
                        {
                            var stmt = contents[next_i];
                            if (IsCaseLabel(stmt))
                            {
                                break;
                            }
                            if (stmt.Calls(S.Break, 0))
                            {
                                next_i++;
                                break;
                            }
                        }
                        var handler = new VList <LNode>(contents.Slice(case_i + 1, next_i - (case_i + 1)));

                        if (@case.Calls(S.Case) && @case.Args.Count > 0)
                        {
                            var codeGen = new CodeGeneratorForMatchCase(context, input, handler);
                            foreach (var pattern in @case.Args)
                            {
                                outputs.Add(codeGen.GenCodeForPattern(pattern));
                            }
                        }
                        else                                    // default:
                        // Note: the extra {braces} around the handler are rarely
                        // needed. They are added just in case the handler declares a
                        // variable and a different handler declares another variable
                        // by the same name, which is illegal unless we add braces.
                        {
                            outputs.Add(LNode.Call(CodeSymbols.Braces, LNode.List(handler)).SetStyle(NodeStyle.Statement));
                            if (next_i < contents.Count)
                            {
                                context.Sink.Error(contents[next_i], "The default branch must be the final branch in a 'match' statement.");
                            }
                        }
                    }
                    return(LNode.Call(CodeSymbols.DoWhile, LNode.List(outputs.ToVList().AsLNode(S.Braces), LNode.Literal(false))));
                }
            }
            return(null);
        }
示例#5
0
		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;
		}
示例#6
0
        public static LNode getScopedProperty(LNode node, IMacroContext context)
        {
            LNode key;

            if (node.ArgCount >= 1 && !(key = context.PreProcess(node.Args[0])).IsCall)
            {
                var keyValue = key.IsId ? key.Name : key.Value;
                var @default = node.Args[1, node];
                var result   = context.ScopedProperties.TryGetValue(keyValue, @default);
                if (result == node)
                {
                    context.Write(Severity.Error, key, "The specified property does not exist.");
                }
                if (result is LNode)
                {
                    return((LNode)result);
                }
                else
                {
                    return(LNode.Literal(result, node));
                }
            }
            context.Write(Severity.Error, node, "Expected one argument, a key literal, with the default code as an optional second argument.");
            return(null);
        }
示例#7
0
        public static LNode ForwardProperty(LNode prop, IMacroContext context)
        {
            LNode name, fwd, body;

            if (prop.ArgCount != 4)
            {
                return(null);
            }
            LNode target = GetForwardingTarget(fwd = prop.Args[3], name = prop.Args[1]);

            if (target != null)
            {
                body = F.Braces(F.Call(S.get, F.Braces(F.Call(S.Return, target))));
                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(stmt.Args[0], name)) != null)
                    {
                        return(stmt.WithArgs(new VList <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 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);
        }
示例#8
0
        public static LNode LLLPG_lexer(LNode node, IMacroContext context)
        {
            return(LllpgMacro(node, context, _lexer, lexerCfg =>
            {
                var helper = new IntStreamCodeGenHelper();
                foreach (var option in MacroContext.GetOptions(lexerCfg.Args))
                {
                    LNode value = option.Value;
                    string key = (option.Key ?? (Symbol)"??").Name;
                    switch (key.ToLowerInvariant())
                    {
                    case "inputsource": helper.InputSource = value; break;

                    case "inputclass": helper.InputClass = value; break;

                    case "terminaltype": helper.TerminalType = value; break;

                    case "settype": helper.SetType = value; break;

                    case "listinitializer": helper.SetListInitializer(value); break;

                    default:
                        context.Write(Severity.Error, value, "Unrecognized option '{0}'. Available options: " +
                                      "inputSource: var, inputClass: type, terminalType: type, setType: type, listInitializer: var _ = new List<T>()", key);
                        break;
                    }
                }
                return helper;
            }));
        }
示例#9
0
		[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;
		}
示例#10
0
        static Symbol GetFnAndClassName(IMacroContext context, out LNode @class, out LNode fn)
        {
            @class = fn = null;
            var anc = context.Ancestors;

            for (int i = anc.Count - 1; i >= 0; i--)
            {
                var name = anc[i].Name;
                if (anc[i].ArgCount >= 2)
                {
                    if (fn == null)
                    {
                        if (name == S.Fn || name == S.Property || name == S.Constructor || name == S.Event)
                        {
                            fn = anc[i][1];
                        }
                    }
                    if (name == S.Struct || name == S.Class || name == S.Namespace || name == S.Interface || name == S.Trait || name == S.Alias)
                    {
                        @class = anc[i][0];
                        return(name);
                    }
                }
            }
            return(null);
        }
示例#11
0
        public static LNode on_throw_catch(LNode node, IMacroContext context)
        {
            VList <LNode> rest;
            LNode         firstArg, on_handler = ValidateOnStmt(node, context, out rest, out firstArg);

            return(TransformOnCatch(node, firstArg, F.Braces(rest), on_handler));
        }
示例#12
0
		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));
		}
示例#13
0
        public static LNode saveAndRestore(LNode node, IMacroContext context)
        {
            var tmp_10 = context.GetArgsAndBody(true);
            var args   = tmp_10.Item1;
            var body   = tmp_10.Item2;

            if (args.Count == 1)
            {
                LNode newValue = null;
                {
                    var   tmp_11 = args[0];
                    LNode property;
                    if (tmp_11.Calls(CodeSymbols.Assign, 2) && (property = tmp_11.Args[0]) != null && (newValue = tmp_11.Args[1]) != null || (property = tmp_11) != null)
                    {
                        string mainProp = KeyNameComponentOf(property).Name;
                        string varPrefix = "old" + mainProp + "_";
                        LNode  varName, varDecl = TempVarDecl(context, property, out varName, varPrefix);
                        LNode  tryFinally = LNode.Call(CodeSymbols.Try, LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List(body)).SetStyle(NodeStyle.StatementBlock), 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.StatementBlock)))));
                        if (newValue != null)
                        {
                            return(LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, LNode.Call(CodeSymbols.Assign, LNode.List(property, newValue)).SetStyle(NodeStyle.Operator), tryFinally)).IncludingTriviaFrom(node));
                        }
                        else
                        {
                            return(LNode.Call(CodeSymbols.Splice, LNode.List(varDecl, tryFinally)).IncludingTriviaFrom(node));
                        }
                    }
                }
            }
            return(null);
        }
示例#14
0
        private static LNode StmtToCSharp(LNode stmt, IMacroContext context, bool execContext, Symbol parentConstruct)
        {
            if (!stmt.IsCall)
            {
                return(stmt);
            }
            if (stmt.Calls(S.Braces))
            {
                return(null);
            }

            var      helpers = RVList <LNode> .Empty;
            ExecInfo info;

            if (!StatementTypes.TryGetValueSafe(stmt.Name, out info))
            {
                info = new ExecInfo(-1, execContext);
            }

            var args = stmt.Args;

            for (int i = info.IgnoreMax; i < stmt.Args.Count; i++)
            {
                if (i == info.BraceIndex)
                {
                    continue;
                }
            }

            return(stmt);
        }
示例#15
0
		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);
		}
示例#16
0
		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));
		}
示例#17
0
		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
		}
示例#18
0
        private static LNode ValidateOnStmt(LNode node, IMacroContext context, out VList <LNode> restOfStmts, out LNode firstArg)
        {
            var   a = node.Args;
            LNode on_handler;

            restOfStmts = LNode.List();
            firstArg    = null;
            if (a.Count == 2)
            {
                firstArg = a[0];
            }
            else if (a.Count != 1)
            {
                return(null);
            }
            if (!(on_handler = a.Last).Calls(S.Braces))
            {
                return(null);
            }
            if (context.RemainingNodes.Count == 0)
            {
                context.Write(Severity.Warning, node, "{0} should not be the final statement of a block.", node.Name);
            }
            restOfStmts = new VList <LNode>(context.RemainingNodes);
            context.DropRemainingNodes = true;
            return(on_handler);
        }
示例#19
0
        static string GetFnAndClassNameString(IMacroContext context)
        {
            LNode @class, fn;

            GetFnAndClassName(context, out @class, out fn);
            var ps = LNode.Printer;

            if (fn == null)
            {
                return(@class == null ? null : ps.Print(@class, MessageSink.Null, ParsingMode.Expressions));
            }
            else if (@class == null)
            {
                return(ps.Print(fn, MessageSink.Null, ParsingMode.Expressions));
            }
            else
            {
                while (fn.CallsMin(S.Dot, 2))
                {
                    fn = fn.Args.Last;
                }
                return(string.Format("{0}.{1}", ps.Print(@class, MessageSink.Null, ParsingMode.Expressions),
                                     ps.Print(fn, MessageSink.Null, ParsingMode.Expressions)));
            }
        }
示例#20
0
			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());
			}
		}
示例#21
0
		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;
		}
示例#22
0
        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 (LeMP.ecs.StandardMacros.LooksLikeSimpleValue(leftSide))
            {
                condition = F.Call(S.NotEq, leftSide, F.@null);
                thenExpr  = ConvertToNormalDot(leftSide, rightSide);
            }
            else
            {
                LNode tempVar = F.Id(StandardMacros.NextTempName(context, leftSide));
                condition = F.Call(S.NotEq, F.Var(F.Missing, tempVar, leftSide), F.@null);
                thenExpr  = ConvertToNormalDot(tempVar, rightSide);
            }
            return(F.InParens(F.Call(S.QuestionMark, condition, thenExpr, F.Null)));
        }
示例#23
0
        public static LNode static_if(LNode @if, IMacroContext context)
        {
            if ([email protected](2, 3))
            {
                return(null);
            }
            LNode cond = context.PreProcess(@if.Args[0]);

            cond = ReduceBooleanExpr(cond);
            object @bool;

            if ((@bool = cond.Value) is bool)
            {
                LNode output = (bool)@bool ? @if.Args[1] : @if.Args.TryGet(2, null) ?? F.Call(S.Splice);
                if (output.Calls(S.Braces))
                {
                    return(output.WithTarget(S.Splice));
                }
                else
                {
                    return(output);
                }
            }
            else
            {
                return(Reject(context, @if.Args[0], "Only boolean expressions can be evaluated."));
            }
        }
示例#24
0
        private static void WarnAboutMissingDollarSigns(LNode argList, IMacroContext context, LNode pattern, LNode replacement)
        {
            // Warn if a name appears in both pattern and replacement but uses $ in only one of the two.
            Dictionary <Symbol, LNode> pVars = ScanForVariables(pattern), rVars = ScanForVariables(replacement);
            // Also warn if it looks like all `$`s were forgotten.
            bool allIds = argList.Args.Count > 0 && argList.Args.All(n => !n.IsCall);

            foreach (var pair in pVars)
            {
                LNode rVar = rVars.TryGetValue(pair.Key, null);
                if (pair.Value.IsId)                 // id without `$` in pattern list
                {
                    if (rVar != null && (allIds || !rVar.IsId))
                    {
                        context.Sink.Warning(pair.Value, "`{0}` is written without `$`, so it may not match as intended.", pair.Value.Name);
                    }
                }
                else                 // $id in pattern list
                {
                    if (rVar != null && rVar.IsId)
                    {
                        context.Sink.Warning(rVar, "`{0}` appears in the output without `$` so replacement will not occur.", pair.Key);
                    }
                }
            }
        }
示例#25
0
        public static LNode ExpectAncestorStack(LNode node, IMacroContext context)
        {
            // Verify AncestorsAndPreviousSiblings
            Assert.AreEqual(node.ArgCount, context.AncestorsAndPreviousSiblings.Count);
            int index = 0;

            foreach (var expect in node.Args)
            {
                Assert.IsTrue(expect.Calls(S.Tuple));
                var pair = context.AncestorsAndPreviousSiblings[index];
                ExpectList(pair.Item1, expect.Args.WithoutLast(1));
                if (!expect.Args.Last.IsIdNamed("#skip"))
                {
                    Assert.AreEqual(expect.Args.Last, pair.Item2.Target);
                }
                index++;
            }

            // Verify PreviousSiblings
            var expectedPreviousSiblings = node.Args.Last.Args.WithoutLast(1);
            int i = 0;

            foreach (var expected in expectedPreviousSiblings)
            {
                if (!expected.IsIdNamed("#skip"))
                {
                    Assert.AreEqual(expected, context.PreviousSiblings[i]);
                }
                i++;
            }

            return(LNode.Call(S.Splice));            // delete this node
        }
示例#26
0
 internal CodeContractRewriter(LNode returnType, LNode fullMethodName, IMacroContext context)
 {
     ReturnType     = returnType;
     FullMethodName = fullMethodName;
     Context        = context;
     PrependStmts   = new VList <LNode>();
 }
示例#27
0
		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;
		}
示例#28
0
		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;
		}
示例#29
0
		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;
		}
示例#30
0
        public static Symbol NextTempName(IMacroContext ctx, LNode value)
        {
            string prefix = value.Name.Name;

            prefix = LNode.IsSpecialName(prefix) ? "tmp_" : prefix + "_";
            return(NextTempName(ctx, prefix));
        }
示例#31
0
        public static LNode ContractsOnMethod(LNode fn, IMacroContext context)
        {
            LNode oldFn = fn;

            if (fn.ArgCount >= 4)
            {
                var rw = new CodeContractRewriter(fn.Args[0], fn.Args[1], context);
                fn = ProcessArgContractAttributes(fn, 2, rw);
                if (fn.Args[0].HasAttrs)
                {
                    fn = fn.WithArgChanged(0, fn.Args[0].WithAttrs(rw.Process(fn.Args[0].Attrs, null)));
                }
                if (fn.HasAttrs)
                {
                    fn = fn.WithAttrs(rw.Process(fn.Attrs, null));
                }
                if (rw.PrependStmts.IsEmpty)
                {
                    return(null);
                }
                else
                {
                    var body = fn.Args[3];
                    if (!body.Calls(S.Braces))
                    {
                        body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement);
                    }
                    body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts));
                    fn   = fn.WithArgChanged(3, body);
                    return(fn);
                }
            }
            return(null);
        }
示例#32
0
        public static LNode ContractsOnLambda(LNode fn, IMacroContext context)
        {
            LNode oldFn = fn;

            if (fn.ArgCount == 2)
            {
                var rw = new CodeContractRewriter(LNode.Missing, Id_lambda_function, context);
                fn = ProcessArgContractAttributes(fn, 0, rw, isLambda: true);
                if (fn.HasAttrs)
                {
                    fn = fn.WithAttrs(rw.Process(fn.Attrs, null));
                }
                if (rw.PrependStmts.IsEmpty)
                {
                    return(null);
                }
                else
                {
                    var body = fn.Args[1];
                    if (!body.Calls(S.Braces))
                    {
                        body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.Statement);
                    }
                    body = body.WithArgs(body.Args.InsertRange(0, rw.PrependStmts));
                    fn   = fn.WithArgChanged(1, body);
                    return(fn);
                }
            }
            return(null);
        }
示例#33
0
        public static LNode scope(LNode node, IMacroContext context)
        {
            var a = node.Args;

            if (a.Count == 2 && a[1].Calls(S.Braces) && a[0].IsId)
            {
                Symbol name = a[0].Name;
                if (name == _exit || name == S.Finally)
                {
                    return(F.Call(_on_finally, a[1]));
                }
                else if (name == _success || name == S.Return)
                {
                    return(F.Call(_on_return, a[1]));
                }
                else if (name == _failure || name == S.Catch)
                {
                    return(F.Call(_on_throw_catch, a[1]));
                }
                else
                {
                    return(Reject(context, a[0], "Expected 'exit', 'success', or 'failure'"));
                }
            }
            return(null);
        }
示例#34
0
文件: Macros.cs 项目: dadhi/ecsharp
        /// <summary>This method helps do the stage-one transform from <c>LLLPG (config) {...}</c>
        /// to <c>run_LLLPG (helper literal) {...}</c> and also invokes the ANTLR-style
        /// parser if the second argument is a token literal. If <c>node[0]</c>
        /// calls <c>expectedConfigNode</c> then the delegate is called to
        /// construct a code generation helper object; otherwise, this method has
        /// no effect and returns null.</summary>
        public static LNode LllpgMacro(LNode node, IMacroContext context,
                                       Symbol expectedCodeGenMode, Func <LNode, IPGCodeGenHelper> makeCodeGenHelper, bool isDefault = false)
        {
            LNodeList args, body;
            LNode     tokenTree = null, codeGenOptions = null;

            if (node.ArgCount >= 1 && (tokenTree = node.Args.Last).Value is TokenTree)
            {
                args = node.Args.WithoutLast(1);
                body = LNodeList.Empty;
            }
            else
            {
                tokenTree = null;
                var p = context.GetArgsAndBody(orRemainingNodes: true);
                args = p.A;
                body = p.B;
            }

            if ((args.Count == 1 && (codeGenOptions = args[0]).Name == expectedCodeGenMode) ||
                (args.Count == 0 && isDefault))
            {
                if (tokenTree != null)
                {
                    body = AntlrStyleParser.ParseTokenTree(tokenTree.Value as TokenTree, context.Sink);
                }
                IPGCodeGenHelper helper = makeCodeGenHelper(codeGenOptions);
                return(node.WithTarget(_run_LLLPG).WithArgs(F.Literal(helper), F.Braces(body)));
            }
            return(null);
        }
示例#35
0
 public static LNode @defaultCase(LNode node, IMacroContext context)
 {
     if (node.ArgCount == 0)
     {
         return(node.With(S.Label, LNode.Id(S.Default, node)).SetBaseStyle(NodeStyle.Default));
     }
     else if (node.ArgCount == 1)
     {
         var arg = node.Args[0];
         if (arg.Calls(S.Colon, 1)                       // .default: {...}
             )
         {
             arg = arg.Args[0];
         }
         else if (!arg.Calls(S.Braces)                   // expecting .default {...}
                  )
         {
             return(null);
         }
         return(F.Call(S.Splice,
                       node.With(S.Label, LNode.Id(S.Default, node)).SetBaseStyle(NodeStyle.Default),
                       arg));
     }
     return(null);
 }
示例#36
0
文件: Macros.cs 项目: dadhi/ecsharp
        public static LNode LLLPG_lexer(LNode node, IMacroContext context)
        {
            return(LllpgMacro(node, context, _lexer, lexerCfg =>
            {
                var helper = new IntStreamCodeGenHelper();
                foreach (var option in MacroContext.GetOptions(lexerCfg.Args))
                {
                    LNode value = option.Value ?? LNode.Missing;
                    string key = option.Key.Name.Name;
                    switch (key.ToLowerInvariant())
                    {
                    case "inputsource":      helper.InputSource = value; break;

                    case "inputclass":       helper.InputClass = value; break;

                    case "terminaltype":     helper.TerminalType = value; break;

                    case "settype":          helper.SetType = value; break;

                    case "listinitializer":  helper.SetListInitializer(value); break;

                    case "nocheckbydefault": SetOption <bool>(context, option.Key, value.Value, b => helper.NoCheckByDefault = b); break;

                    default:
                        context.Sink.Error(option.Key, "Unrecognized option '{0}'. Available options: " +
                                           "InputSource: var, InputClass: type, TerminalType: type, SetType: type, " +
                                           "ListInitializer: var _ = new List<T>(), NoCheckByDefault: true", key);
                        break;
                    }
                }
                return helper;
            }));
        }
示例#37
0
        public static LNode RangeExcl(LNode node, IMacroContext context)
        {
            LNode lo = null;

            {
                LNode hi;
                if (node.Args.Count == 2 && (lo = node.Args[0]) != null && (hi = node.Args[1]) != null || node.Args.Count == 1 && (hi = node.Args[0]) != null)
                {
                    if (lo == null || lo.IsIdNamed(__))
                    {
                        if (hi.IsIdNamed(__))
                        {
                            return(Range_Everything);
                        }
                        else
                        {
                            return(LNode.Call(Range_UntilExclusive, LNode.List(hi)));
                        }
                    }
                    else if (hi.IsIdNamed(__))
                    {
                        return(LNode.Call(Range_StartingAt, LNode.List(lo)));
                    }
                    else
                    {
                        return(LNode.Call(Range_ExcludeHi, LNode.List(lo, hi)));
                    }
                }
            }
            return(null);
        }
示例#38
0
        public static LNode DollarSignVariable(LNode node, IMacroContext context)
        {
            LNode id;

            if (node.ArgCount == 1 && (id = node.Args[0]).IsId && !id.HasPAttrs())
            {
                object value;
                if (context.ScopedProperties.TryGetValue("$" + id.Name.Name, out value))
                {
                    if (value is LNode)
                    {
                        return(((LNode)value).WithRange(id.Range));
                    }
                    else
                    {
                        context.Sink.Warning(id, "The specified scoped property is not a syntax tree. " +
                                             "Use `#getScopedProperty({0})` to insert it as a literal.", EcsNodePrinter.PrintId(id.Name));
                    }
                }
                else
                {
                    context.Sink.Error(id, "There is no macro property in scope named `{0}`", id.Name);
                }
            }
            return(null);
        }
示例#39
0
        public static LNode UnpackTuple(LNode node, IMacroContext context)
        {
            var a = node.Args;

            if (a.Count == 2 && a[0].CallsMin(S.Tuple, 1))
            {
                var output = new WList <LNode>();
                var tuple  = a[0].Args;
                var rhs    = a[1];

                // Avoid evaluating rhs more than once, if it doesn't look like a simple variable
                rhs = MaybeAddTempVarDecl(context, rhs, output);

                for (int i = 0; i < tuple.Count; i++)
                {
                    var itemi = F.Dot(rhs, F.Id(GSymbol.Get("Item" + (i + 1))));
                    if (tuple[i].Calls(S.Var, 2))
                    {
                        output.Add(F.Var(tuple[i].Args[0], tuple[i].Args[1], itemi));
                    }
                    else
                    {
                        output.Add(F.Call(S.Assign, tuple[i], itemi));
                    }
                }
                return(F.Call(S.Splice, output.ToVList()));
            }
            return(null);
        }
示例#40
0
        static bool DetectMissingVoidReturn(IMacroContext context, LNode lastStmt)
        {
            if (!NextStatementMayBeReachable(lastStmt))
            {
                return(false);
            }

            var anc         = context.Ancestors;
            var parent      = anc.TryGet(anc.Count - 2, LNode.Missing);
            var grandparent = anc.TryGet(anc.Count - 3, LNode.Missing);

            do
            {
                if (parent.Calls(S.Braces))
                {
                    if (grandparent.CallsMin(S.Fn, 4) && grandparent.Args[0].IsIdNamed(S.Void))
                    {
                        return(true);
                    }
                    if (grandparent.Calls(S.Constructor))
                    {
                        return(true);
                    }
                    if (grandparent.Calls(S.set, 1) || grandparent.Calls(S.add, 1) || grandparent.Calls(S.remove, 1))
                    {
                        return(true);
                    }
                    if (grandparent.Calls(S.Lambda, 2))
                    {
                        return(true);
                    }
                }
                return(false);
            } while (false);
        }
示例#41
0
        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)
            {
                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];
                        value = context.PreProcess(value);
                        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((LNode)node.With(newTarget, LNode.Literal(key.Name, key), value));
                });
                return(F.Call(S.Splice, stmts));
            }
            return(null);
        }
示例#42
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);
		}
示例#43
0
		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 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;
		}
示例#45
0
		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);
		}
示例#46
0
		// Used to avoid evaluating `value` more than once by creating a 
		// declaration in `output` of a temporary variable to hold the value. 
		// If `value` looks simple (according to LooksLikeSimpleValue), this 
		// fn returns value and leaves output unchanged.
		protected static LNode MaybeAddTempVarDecl(IMacroContext ctx, LNode value, WList<LNode> output)
		{
			if (!LooksLikeSimpleValue(value)) {
				LNode tmpId;
				output.Add(TempVarDecl(ctx, value, out tmpId));
				return tmpId;
			}
			return value;
		}
示例#47
0
			internal CodeGeneratorForMatchCase(IMacroContext context, LNode input, VList<LNode> handler)
			{
				_context = context;
				_input = input;
				_handler = handler;
				var @break = LNode.Call(CodeSymbols.Break);
				if (_handler.IsEmpty || !_handler.Last.Equals(@break))
					_handler.Add(@break);
			}
示例#48
0
		public static LNode useSymbols(LNode input, IMacroContext context)
		{
			bool inType = context.Ancestors.Any(parent => {
				var kind = EcsValidators.SpaceDefinitionKind(parent);
				return kind != null && kind != S.Namespace;
			});
			var args_body = context.GetArgsAndBody(true);
			args_body.B = context.PreProcess(args_body.B);
			return UseSymbolsCore(input.Attrs, args_body.A, args_body.B, context, inType);
		}
示例#49
0
		public static LNode on_finally(LNode node, IMacroContext context)
		{
			VList<LNode> rest;
			LNode firstArg, on_handler = ValidateOnStmt(node, context, out rest, out firstArg);
			if (on_handler == null || firstArg != null)
				return null;

			node.Style &= ~NodeStyle.OneLiner; // avoid collapsing output to one line
			return node.With(S.Try, F.Braces(rest), node.With(S.Finally, on_handler));
		}
示例#50
0
		public static LNode AddCsLineDirectives(LNode node, IMacroContext context)
		{
			if (node.ArgCount != 0)
				return null;
			int sourceLine = -1;
			var list0 = new VList<LNode>(context.RemainingNodes);
			var list1 = context.PreProcess(list0);
			var list2 = AddLineDirectives(list1, true, ref sourceLine);
			context.DropRemainingNodes = true;
			return F.Call(S.Splice, list2);
		}
示例#51
0
		public static LNode replaceTarget(LNode outerNode, IMacroContext context1)
		{
			// Test the direct way to register a macro
			context1.RegisterMacro(
				new MacroInfo(null, outerNode[0].Name.Name, 
					(node, context2) =>
					{
						return node.WithTarget(outerNode[1]);
					}));
			return LNode.Call(S.Splice);
		}
示例#52
0
		public static LNode overrideTarget(LNode outerNode, IMacroContext context1)
		{
			// Test the indirect way to register a macro
			return LNode.Call((Symbol)"#registerMacro", LNode.List(LNode.Literal(
				new MacroInfo(null, outerNode[0].Name.Name, 
					(node, context2) =>
					{
						return node.WithTarget(outerNode[1]);
					}) {
						Mode = MacroMode.PriorityOverride // needed by the unit test
					})));
		}
示例#53
0
		public static LNode @using1(LNode node, IMacroContext sink)
		{
			if (node.ArgCount == 1 && IsComplexId(node.Args[0])) {
				// Looks like an import statement
				sink.Write(Severity.Warning, node.Target, "The 'import' statement replaces the 'using' statement in LeMP.");
				return node.WithTarget(S.Import);
			}
			var result = TranslateSpaceDefinition(node, sink, S.Alias);
			if (result != null)
				return result.PlusAttr(F.Id(S.FilePrivate));
			return null;
		}
示例#54
0
		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 && args[0].Calls(S.Tuple)) args = args[0].Args; // LESv2
			if (args.Count >= 1)
			{
				bool preprocess = node.Calls("replacePP");

				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 (preprocess)
						{
							pattern = context.PreProcess(pattern);
							repl = context.PreProcess(repl);
						}
						if (pattern.Calls(S.Braces)) {
							if (pattern.ArgCount == 1)
								pattern = pattern.Args[0];
							else
								context.Write(Severity.Error, pattern, "The braces must contain only a single statement. To search for braces literally, use `{{ ... }}`");
						}
						if (repl.Calls(S.Braces))
							repl = repl.Args.AsLNode(S.Splice);
						
						// Avoid StackOverflowException when pattern is $Id (sadly, it
						// is uncatchable so it can crash LeMP.exe and even Visual Studio)
						if (LNodeExt.GetCaptureIdentifier(pattern) != null)
 							return Reject(context, pattern, "The left side of `=>` cannot be a capture. Remove the `$`.");

						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.Sink.Warning(node, "No patterns recognized; no replacements were made.");
				return output.AsLNode(S.Splice);
			}
			return null;
		}
示例#55
0
		public static LNode TupleType(LNode node, IMacroContext context)
		{
			var stem = node.Args[0, F.Missing];
			if (stem.IsId && (stem.Name == S.AltList || stem.Name == S.Tuple)) {
				var tupleMakers = MaybeInitTupleMakers(context.ScopedProperties);
				
				var bareType = tupleMakers.TryGet(node.Args.Count - 1, new Pair<LNode, LNode>()).A;
				if (bareType == null)
					bareType = ((Pair<LNode, LNode>)context.ScopedProperties[DefaultTupleMaker]).A;
				if (bareType != null)
					return node.WithArgChanged(0, bareType);
			}
			return null;
		}
示例#56
0
		static string GetFnAndClassNameString(IMacroContext context)
		{
			LNode @class, fn;
			GetFnAndClassName(context, out @class, out fn);
			var ps = ParsingService.Current;
			if (fn == null)
				return @class == null ? null : ps.Print(@class, null, ParsingService.Exprs);
			else if (@class == null)
				return ps.Print(fn, null, ParsingService.Exprs);
			else {
				while (fn.CallsMin(S.Dot, 2))
					fn = fn.Args.Last;
				return string.Format("{0}.{1}", ps.Print(@class, null, ParsingService.Exprs), ps.Print(fn, null, ParsingService.Exprs));
			}
		}
示例#57
0
		public static LNode staticMatches(LNode node, IMacroContext context)
		{
			if (node.ArgCount != 2)
				return null;

			LNode candidate = context.PreProcess(AutoStripBraces(node[0]));
			LNode pattern = AutoStripBraces(node[1]);
			MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>();
			VList<LNode> _;
			if (LNodeExt.MatchesPattern(candidate, pattern, ref captures, out _)) {
				SetSyntaxVariables(captures, context);
				return F.True;
			}
			return F.False;
		}
示例#58
0
		public static LNode on_return(LNode node, IMacroContext context)
		{
			VList<LNode> rest;
			LNode varDecl, bracedHandler = ValidateOnStmt(node, context, out rest, out varDecl);
			if (bracedHandler == null)
				return null;
			rest = context.PreProcess(rest);
			bracedHandler = context.PreProcess(bracedHandler);
			LNode varName;
			if (varDecl == null) {
				varName = Id__result__;
				varDecl = F.Var(F.Missing, varName);
			} else {
				{
					LNode tmp_0;
					if (varDecl.Calls(CodeSymbols.Var, 2) && (tmp_0 = varDecl.Args[1]) != null && tmp_0.Calls(CodeSymbols.Assign, 2) && (varName = tmp_0.Args[0]) != null)
						context.Write(Severity.Error, varName, "The return value cannot be assigned here. The value of this variable must be placed on the return statement(s).");
					else if (varDecl.Calls(CodeSymbols.Var, 2) && (varName = varDecl.Args[1]) != null) {
					} else if ((varName = varDecl).IsId)
						varDecl = varName.With(S.Var, F.Missing, varName);
					else
						return Reject(context, varDecl, "The first parameter to on_return must be a simple identifier (the name of a variable to return) or a variable declaration (for a variable to be returned).");
				}
			}
			bool foundReturn = false;
			rest = rest.SmartSelect(arg => arg.ReplaceRecursive(rnode => {
				{
					LNode retVal;
					if (rnode.Calls(CodeSymbols.Lambda, 2))
						return rnode;
					else if (rnode.Calls(CodeSymbols.Return, 0)) {
						foundReturn = true;
						return LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(bracedHandler.Args).Add(rnode)).SetStyle(NodeStyle.Statement);
					} else if (rnode.Calls(CodeSymbols.Return, 1) && (retVal = rnode.Args[0]) != null) {
						foundReturn = true;
						var retValDecl = varDecl.WithArgChanged(1, LNode.Call(CodeSymbols.Assign, LNode.List(varName, retVal)).SetStyle(NodeStyle.Operator));
						rnode = rnode.WithArgs(varName);
						return LNode.Call(CodeSymbols.Braces, LNode.List().Add(retValDecl).AddRange(bracedHandler.Args).Add(rnode)).SetStyle(NodeStyle.Statement);
					} else
						return null;
				}
			}));
			if (DetectMissingVoidReturn(context, rest[rest.Count - 1, LNode.Missing]))
				rest.Add(bracedHandler.Args.AsLNode(S.Braces));
			else if (!foundReturn)
				context.Write(Severity.Warning, node, "'on_return': no 'return' statements were found in this context, so this macro had no effect.");
			return LNode.Call((Symbol) "#noLexicalMacros", LNode.List(rest));
		}
示例#59
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);
		}
示例#60
0
		public static LNode ForwardMethod(LNode fn, IMacroContext context)
		{
			LNode args, fwd, body;
			if (fn.ArgCount != 4 || !(fwd = fn.Args[3]).Calls(S.Forward, 1) || !(args = fn.Args[2]).Calls(S.AltList))
				return null;

			VList<LNode> argList = GetArgNamesFromFormalArgList(args, formalArg =>
				context.Write(Severity.Error, formalArg, "'==>': Expected a variable declaration here"));

			LNode target = GetForwardingTarget(fn.Args[1], fwd);
			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);
		}