Пример #1
0
        private Pred TranslateLoopExpr(LNode expr, Context ctx)
        {
            Symbol type   = expr.Name;
            bool?  greedy = null;
            bool   g;

            expr = expr.Args[0];
            if ((g = expr.Calls(_Greedy, 1)) || expr.Calls(_Nongreedy, 1))
            {
                greedy = g;
                expr   = expr.Args[0];
            }
            BranchMode branchMode;
            Pred       subpred = BranchToPred(expr, out branchMode, ctx);

            if (branchMode != BranchMode.None)
            {
                _sink.Write(Severity.Warning, expr, "'default' and 'error' only apply when there are multiple arms (a|b, a/b)");
            }

            if (type == _Star)
            {
                return(new Alts(expr, LoopMode.Star, subpred, greedy));
            }
            else if (type == _Plus)
            {
                return(new Seq(subpred, new Alts(expr, LoopMode.Star, subpred.Clone(), greedy), expr));
            }
            else               // type == _Opt
            {
                return(new Alts(expr, LoopMode.Opt, subpred, greedy));
            }
        }
Пример #2
0
 static LNode MergeIdentifiers(LNode left, LNode right)
 {
     if (left == null)
     {
         return(right);
     }
     if (right.IsIdNamed(S.Missing))
     {
         return(left);
     }
     {
         LNode right1, right2;
         if (right.Calls(CodeSymbols.Dot, 1) && (right2 = right.Args[0]) != null)
         {
             return(LNode.Call(CodeSymbols.Dot, LNode.List(left, right2)));
         }
         else if (right.Calls(CodeSymbols.Dot, 2) && (right1 = right.Args[0]) != null && (right2 = right.Args[1]) != null)
         {
             return(LNode.Call(CodeSymbols.Dot, LNode.List(MergeIdentifiers(left, right1), right2)));
         }
         else
         {
             throw new LogException(Severity.Note, right, "Multi-using statement seems malformed. Correct example: `using System(.Text, .Linq));`");
         }
     }
 }
Пример #3
0
		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) || expr.Calls(S.DotDotDot, 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);
		}
Пример #4
0
 // A complex identifier has the form Id, ComplexId.Id, or ComplexId!(ComplexId, ...)
 // where Id is a simple identifier and ComplexId is a complex identifier. Also, the
 // form X!Y!Z, i.e. #of(#of(...), ...) is not allowed. $Substitution is allowed.
 public static bool IsComplexId(LNode id, bool allowOf = true)
 {
     if (id.IsCall)
     {
         if (id.Name == S.Of)
         {
             if (allowOf)
             {
                 return((id.HasSimpleHead() || IsComplexId(id.Target, false)) && id.Args.All(a => IsComplexId(a)));
             }
             return(false);
         }
         else if (id.Calls(S.Dot, 2))
         {
             return(id.Args.Last.IsId && IsComplexId(id.Args[0]));
         }
         else if (id.Calls(S.Substitute, 1))
         {
             return(true);
         }
         else
         {
             return(false);
         }
     }
     else
     {
         return(id.IsId);
     }
 }
Пример #5
0
        Pred BranchToPred(LNode expr, out BranchMode mode, Context ctx)
        {
            if (expr.Calls(_Default, 1) || expr.Calls(_Default2, 1))
            {
                expr = expr.Args[0];
                mode = BranchMode.Default;
            }
            else if (expr.Calls(_Error, 1) || expr.IsIdNamed(_DefaultError))
            {
                mode = (expr.AttrNamed(S.Continue) != null || expr.AttrNamed(GSymbol.Get("continue")) != null)
                                       ? BranchMode.ErrorContinue : BranchMode.ErrorExit;
                if (expr.Calls(_Error, 1))
                {
                    expr = expr.Args[0];
                }
                else
                {
                    return(DefaultErrorBranch.Value);
                }
            }
            else
            {
                mode = BranchMode.None;
            }

            return(NodeToPred(expr, ctx));
        }
Пример #6
0
        public static LNode @prop(LNode node, IMessageSink sink)
        {
            var   parts = node.Args;
            LNode sig = parts.TryGet(0, null), body = parts.TryGet(1, null), name, retVal = null;

            if (parts.Count != 2 || !body.Calls(S.Braces))
            {
                return(Reject(sink, node, "A property definition must have the form prop(Name, { Body }), or prop(Name::type, { Body })"));
            }

            if (sig.Calls(S._RightArrow, 2) || sig.Calls(S.ColonColon, 2))
            {
                name   = sig.Args[0];
                retVal = sig.Args[1];
            }
            else
            {
                name   = sig;
                retVal = F.Missing;
            }
            if (!IsComplexId(name))
            {
                return(Reject(sink, name, "Property name must be a complex identifier"));
            }

            return(node.With(S.Property, retVal, name, F.Missing, body));
        }
Пример #7
0
 // Converts the subject of a substitution expr like $'*' to a valid ident-
 // ifier, under the assumption that it doesn't refer to a rule or label.
 static Symbol PickVarNameForLNode(LNode label)
 {
     if (label.IsId)
     {
         // Ignore the predefined special substitutions $LA and $LI
         //if (label.Name.Name == "LA" || label.Name.Name == "LI")
         //	return null;
         return(GSymbol.Get("tok_" + label.Name));
     }
     else if (label.IsLiteral)
     {
         return(LiteralToVarName(label.Value));
     }
     else if (label.Calls(S.Dot, 2))
     {
         return(GSymbol.Get("tok__" + label.Args[1].Name));
     }
     else if (label.Calls(S.DotDot, 2) || label.Calls(S.DotDotDot, 2))
     {
         return(GSymbol.Get(PickVarNameForLNode(label[0]).Name + "_" + PickVarNameForLNode(label[1]).Name));
     }
     else             // can't return null
     {
         return(GSymbol.Get(label.GetHashCode().ToString()));
     }
 }
Пример #8
0
        /// <summary>
        /// Decodes an LNode as a type definition.
        /// </summary>
        /// <param name="node">The node to decode.</param>
        /// <param name="state">The decoder's state.</param>
        /// <returns>A decoded type.</returns>
        public static IrType Decode(LNode node, DecoderState state)
        {
            QualifiedName name;

            if (!FeedbackHelpers.AssertArgCount(node, 4, state.Log) ||
                !state.AssertDecodeQualifiedName(node.Args[0], out name))
            {
                return(null);
            }
            else if (node.Calls(TypeParameterDefinitionSymbol))
            {
                return(new IrGenericParameter(node, state));
            }
            else if (node.Calls(TypeDefinitionSymbol))
            {
                return(new IrType(node, state));
            }
            else
            {
                state.Log.LogSyntaxError(
                    node,
                    FeedbackHelpers.QuoteEven(
                        "expected ",
                        TypeDefinitionSymbol.Name,
                        " or ",
                        TypeParameterDefinitionSymbol.Name,
                        "."));
                return(null);
            }
        }
Пример #9
0
        public static LNode ECSharpRule(LNode node, IMacroContext context)
        {
            // This will be called for all methods and properties, so we have to
            // examine it for the earmarks of a rule definition.
            bool isProp;

            if (!(isProp = node.Calls(S.Property, 4)) && !node.Calls(S.Fn, 4))
            {
                return(null);
            }
            LNode returnType = node.Args[0];
            bool  isToken;
            bool  retValIsRule = (isToken = returnType.IsIdNamed(_token)) || returnType.IsIdNamed(_rule);

            var   attrs    = node.Attrs;
            LNode lastAttr = null;

            if (!retValIsRule)
            {
                if (attrs.IsEmpty)
                {
                    return(null);
                }
                lastAttr = attrs.Last;
                if (!(isToken = lastAttr.IsIdNamed(_hash_token)) && !lastAttr.IsIdNamed(_hash_rule))
                {
                    return(null);
                }
                attrs.RemoveAt(attrs.Count - 1);
            }
            else
            {
                returnType = F.Void;
            }

            //node = context.PreProcessChildren();

            LNode name = node.Args[1];
            LNode args = node.Args[2];

            if (args.IsIdNamed(S.Missing))       // @``
            {
                args = F.List();                 // output will be a #fn, which does not allow @`` as its arg list
            }
            LNode newBody = ParseRuleBody(node.Args.Last, context);

            if (newBody != null)
            {
                return(LNode.Call(isToken ? _hash_token : _hash_rule,
                                  new VList <LNode> {
                    returnType, name, args, newBody
                },
                                  node.Range, node.Style).WithAttrs(attrs));
            }
            else
            {
                return(null);
            }
        }
Пример #10
0
        private static Symbol LinqClauseKind(LNode n, Pedantics p)
        {
            Symbol name = n.Name;
            var    args = n.Args;

            if (name == S.From)
            {
                if (!IsInExpr(args[0], p))
                {
                    return(null);
                }
            }
            else if (name == S.Let)
            {
                if (args.Count != 1)
                {
                    return(null);
                }
            }
            else if (n.Calls(S.WhereClause))
            {
                if (args.Count != 1)
                {
                    return(null);
                }
            }
            else if (n.Calls(S.Join))
            {
                if (args.Count < 2 || args.Count > 3)
                {
                    return(null);
                }
                if (!IsInExpr(args[0], p))
                {
                    return(null);
                }
                if (!args[1].Calls("#equals", 2))
                {
                    return(null);
                }
                if (args.Count >= 3)
                {
                    LNode into = args[2], id;
                    if (!(into.Calls(S.Into, 1) && !HasPAttrsOrParens(id = into[0], p) && (id.IsId || id.Calls(S.Substitute, 1))))
                    {
                        return(null);
                    }
                }
            }
            else if (n.Calls(S.OrderBy))
            {
                // All argument lists are acceptable
            }
            else
            {
                return(null);
            }
            return(name);
        }
Пример #11
0
 static bool IsCaseLabel(LNode @case)
 {
     if (@case.Calls(CodeSymbols.Case) || @case.Calls(CodeSymbols.Label, 1) && @case.Args[0].IsIdNamed((Symbol)"#default"))
     {
         return(true);
     }
     return(false);
 }
Пример #12
0
		internal static LNode GetName(LNode type)
		{
			{
				LNode name;
				if (type.Calls(CodeSymbols.Class, 3) && (name = type.Args[0]) != null && type.Args[1].Calls(CodeSymbols.AltList) && type.Args[2].Calls(CodeSymbols.Braces) || type.Calls(CodeSymbols.Struct, 3) && (name = type.Args[0]) != null && type.Args[1].Calls(CodeSymbols.AltList) && type.Args[2].Calls(CodeSymbols.Braces) || type.Calls(CodeSymbols.Enum, 3) && (name = type.Args[0]) != null && type.Args[1].Calls(CodeSymbols.AltList) && type.Args[2].Calls(CodeSymbols.Braces))
					return name;
				else
					return null;
			}
		}
Пример #13
0
 static bool IsParamsCapture(LNode pattern)
 {
     if (pattern.Calls(S.Substitute, 1))
     {
         LNode arg = pattern.Args.Last;
         return((arg.Calls(S.DotDot, 1) || arg.Calls(S.DotDotDot, 1) || arg.AttrNamed(S.Params) != null) &&
                GetCaptureIdentifier(pattern) != null);
     }
     return(false);
 }
Пример #14
0
		public static LNode unroll(LNode var, LNode cases, LNode body, IMessageSink sink)
		{
			if (!cases.Calls(S.Tuple) && !cases.Calls(S.Braces))
				return Reject(sink, cases, "unroll: the right-hand side of 'in' should be a tuple");

			// Maps identifiers => replacements. The integer counts how many times replacement occurred.
			var replacements = InternalList<Triplet<Symbol, LNode, int>>.Empty;
			if (var.IsId && !var.HasPAttrs()) {
				replacements.Add(Pair.Create(var.Name, (LNode)LNode.Missing, 0));
			} else {
				var vars = var.Args;
				if ((var.Calls(S.Tuple) || var.Calls(S.Braces)) && vars.All(a => a.IsId && !a.HasPAttrs())) {
					replacements = new Triplet<Symbol, LNode, int>[vars.Count].AsInternalList();
					for (int i = 0; i < vars.Count; i++) {
						replacements.InternalArray[i].A = vars[i].Name;
						
						// Check for duplicate names
						for (int j = 0; j < i; j++)
							if (replacements[i].A == replacements[j].A && replacements[i].A.Name != "_")
								sink.Write(Severity.Error, vars[i], "unroll: duplicate name in the left-hand tuple"); // non-fatal
					}
				} else
					return Reject(sink, cases, "unroll: the left-hand side of 'in' should be a simple identifier or a tuple of simple identifiers.");
			}

			UnrollCtx ctx = new UnrollCtx { Replacements = replacements };
			WList<LNode> output = new WList<LNode>();
			int iteration = 0;
			foreach (LNode replacement in cases.Args)
			{
				iteration++;
				bool tuple = replacement.Calls(S.Tuple) || replacement.Calls(S.Braces);
				int count = tuple ? replacement.ArgCount : 1;
				if (replacements.Count != count)
				{
					sink.Write(Severity.Error, replacement, "unroll, iteration {0}: Expected {1} replacement items, got {2}", iteration, replacements.Count, count);
					if (count < replacements.Count)
						continue; // too few
				}
				for (int i = 0; i < replacements.Count; i++)
					replacements.InternalArray[i].B = tuple ? replacement.Args[i] : replacement;

				if (body.Calls(S.Braces)) {
					foreach (LNode stmt in body.Args)
						output.Add(ctx.Replace(stmt).Value);
				} else
					output.Add(ctx.Replace(body).Value);
			}

			foreach (var r in replacements)
				if (r.C == 0 && !r.A.Name.StartsWith("_"))
					sink.Write(Severity.Warning, var, "Replacement variable '{0}' was never used", r.A);
			
			return body.With(S.Splice, output.ToVList());
		}
Пример #15
0
        public static LNode ECSharpRule(LNode node, IMacroContext context)
        {
            // This will be called for all methods and properties, so we have to
            // examine it for the earmarks of a rule definition.
            bool isProp;

            if (!(isProp = node.Calls(S.Property, 4)) && !node.Calls(S.Fn, 4))
            {
                return(null);
            }
            LNode returnType = node.Args[0];
            bool  isToken;
            bool  retValIsRule = (isToken = returnType.IsIdNamed(_token)) || returnType.IsIdNamed(_rule);

            var attrs = node.Attrs;

            if (!retValIsRule)
            {
                int?i_rule = attrs.FinalIndexWhere(n => n.IsIdNamed(_hash_token) || n.IsIdNamed(_hash_rule));
                if (i_rule == null)
                {
                    return(null);
                }
                isToken |= attrs[i_rule.Value].IsIdNamed(_hash_token);
                attrs.RemoveAt(i_rule.Value);
            }
            else
            {
                returnType = F.Void;
            }

            //node = context.PreProcessChildren();

            LNode name = node.Args[1];
            LNode args = node.Args[2];

            if (args.IsIdNamed(S.Missing))          // @``
            {
                args = F.AltList();                 // output will be a #fn, which does not allow @`` as its arg list
            }
            LNode newBody = ParseRuleBody(node.Args.Last, context);

            if (newBody != null)
            {
                // #rule($returnType, $name, $args, $newBody)
                return(LNode.Call(isToken ? _hash_token : _hash_rule,
                                  LNode.List(returnType, name, args, newBody),
                                  node.Range, node.Style).WithAttrs(attrs));
            }
            else
            {
                return(null);
            }
        }
Пример #16
0
        private static void DoDeconstruct(LNode arg, IMacroContext context, bool printErrorOnFailure)
        {
            LNode patternSpec = arg.Args[0, LNode.Missing], input = arg.Args[1, LNode.Missing];

            if (!arg.Calls(S.Assign, 2))
            {
                if (arg.Calls(S.Lambda, 2))
                {
                    G.Swap(ref patternSpec, ref input);
                }
                else
                {
                    context.Sink.Error(arg, "expected an assignment (`patterns = input`)");
                    return;
                }
            }

            // Build list of patterns out of the binary operator series p1 | p2 | p3
            var patterns = new FVList <LNode>();

            while (patternSpec.Calls(S.OrBits, 2) && !patternSpec.IsParenthesizedExpr())
            {
                patterns.Add(patternSpec[1]);
                patternSpec = patternSpec[0];
            }
            patterns.Add(patternSpec);

            // Remove outer braces, then run macros
            patterns = patterns.SmartSelect(p => p.Calls(S.Braces, 1) ? p[0] : p);
            input    = input.Calls(S.Braces, 1) ? input[0] : input;
            input    = context.PreProcess(input);

            // Perform matching & capturing
            foreach (var pattern in patterns)
            {
                IDictionary <Symbol, LNode> captures;
                if (LNodeExt.MatchesPattern(input, pattern, out captures))
                {
                    if (captures.Count == 0)
                    {
                        context.Write(printErrorOnFailure ? Severity.Warning : Severity.Error, pattern,
                                      "This pattern has no effect, since it does not use `$` to capture any variables.");
                    }
                    SetSyntaxVariables(captures, context);
                    return;
                }
            }

            if (printErrorOnFailure)
            {
                context.Sink.Error(arg, "Deconstruction failed.");
            }
        }
Пример #17
0
        public static LNode ECSharpRule(LNode node, IMessageSink sink)
        {
            // This will be called for all methods and properties, so we have to
            // examine it for the earmarks of a rule definition.
            bool isProp;

            if (!(isProp = node.Calls(S.Property, 3)) && !node.Calls(S.Fn, 4))
            {
                return(null);
            }
            LNode returnType = node.Args[0];
            bool  isToken;
            bool  ruleRetVal = (isToken = returnType.IsIdNamed(_token)) || returnType.IsIdNamed(_rule);

            var   attrs    = node.Attrs;
            LNode lastAttr = null;

            if (!ruleRetVal)
            {
                if (attrs.IsEmpty)
                {
                    return(null);
                }
                lastAttr = attrs.Last;
                if (!(isToken = lastAttr.IsIdNamed(_hash_token)) && !lastAttr.IsIdNamed(_hash_rule))
                {
                    return(null);
                }
                attrs.RemoveAt(attrs.Count - 1);
            }
            else
            {
                returnType = F.Void;
            }
            LNode name    = node.Args[1];
            LNode args    = isProp ? F.List() : node.Args[2];
            LNode newBody = ParseRuleBody(node.Args.Last, sink);

            if (newBody != null)
            {
                return(LNode.Call(isToken ? _hash_token : _hash_rule,
                                  new RVList <LNode> {
                    returnType, name, args, newBody
                },
                                  node.Range, node.Style).WithAttrs(attrs));
            }
            else
            {
                return(null);
            }
        }
Пример #18
0
        internal static Symbol DecodeSubstitutionExpr(LNode expr, out LNode condition, out bool isParams, out bool refExistingVar)
        {
            condition      = null;
            isParams       = false;
            refExistingVar = false;
            if (expr.Calls(S.Substitute, 1))
            {
                LNode id = expr.Args[0];
                if (id.AttrNamed(S.Params) != null)
                {
                    isParams = true;
                }
                else if (id.Calls(S.DotDotDot, 1) || id.Calls(S.DotDot, 1))
                {
                    isParams = true;
                    id       = id.Args[0];
                }

                if (id.AttrNamed(S.Ref) != null)
                {
                    refExistingVar = true;
                }

                if (id.Calls(S.IndexBracks, 2))
                {
                    // very old style
                    condition = id.Args[1];
                    id        = id.Args[0];
                }
                else
                {
                    while (id.Calls(S.And, 2) || id.Calls(S.When, 2))
                    {
                        // old style `&&` and new style `when`
                        condition = condition == null ? id.Args[1] : LNode.Call(CodeSymbols.And, LNode.List(id.Args[1], condition)).SetStyle(NodeStyle.Operator);
                        id        = id.Args[0];
                    }
                }

                if (condition != null)
                {
                    condition = condition.ReplaceRecursive(n => n.IsIdNamed(S._HashMark) ? id : null);
                }
                if (!id.IsId)
                {
                    return(null);
                }
                return(id.Name);
            }
            return(null);
        }
Пример #19
0
		static IEnumerable<LNode> GetNamespaces(LNode multiName)
		{
			{
				LNode outerNamespace;
				VList<LNode> args;
				if (multiName.Calls(CodeSymbols.Dot) || multiName.Calls(CodeSymbols.Of)) {
				} else if (multiName.IsCall && (outerNamespace = multiName.Target) != null) {
					args = multiName.Args;
					if (args.Count == 1 && args[0].Calls(S.Braces))
						args = args[0].Args;
					return args.SelectMany(arg => GetNamespaces(arg) ?? ListExt.Single(arg)).Select(subNS => MergeIdentifiers(outerNamespace, subNS));
				}
			}
			return null;
		}
Пример #20
0
 /// <summary>
 /// Decodes an LNode as a reference to a generic member.
 /// Logs an error if the decoding process fails.
 /// </summary>
 /// <param name="node">A node to decode as a generic member.</param>
 /// <param name="genericMember">The generic member described by <paramref name="node"/>.</param>
 /// <returns>
 /// <c>true</c> if <paramref name="node"/> can be decoded as a
 /// generic member; otherwise, <c>false</c>.
 /// </returns>
 public bool AssertDecodeGenericMember(
     LNode node,
     out IGenericMember genericMember)
 {
     if (node.Calls(EncoderState.typeHintSymbol))
     {
         if (!FeedbackHelpers.AssertArgCount(node, 1, Log))
         {
             genericMember = null;
             return(false);
         }
         else
         {
             var type = DecodeType(node.Args[0]);
             genericMember = type;
             return(!(type == null || type is ErrorType));
         }
     }
     else if (node.Calls(EncoderState.methodHintSymbol))
     {
         if (!FeedbackHelpers.AssertArgCount(node, 1, Log))
         {
             genericMember = null;
             return(false);
         }
         else
         {
             var method = DecodeMethod(node.Args[0]);
             genericMember = method;
             return(method != null);
         }
     }
     else
     {
         FeedbackHelpers.LogSyntaxError(
             Log,
             node,
             FeedbackHelpers.QuoteEven(
                 "unknown kind of generic member; " +
                 "generic member kinds must be hinted using either ",
                 EncoderState.methodHintSymbol.ToString(),
                 " or ",
                 EncoderState.typeHintSymbol.ToString(),
                 " nodes."));
         genericMember = null;
         return(false);
     }
 }
Пример #21
0
        bool SetPropertyHelper(string exprStr, bool quote)
        {
            LNode expr = (InLang ?? ParsingService.Default).ParseSingle(exprStr, Sink, ParsingMode.Expressions);

            if (expr.Calls(CodeSymbols.Assign, 2) && !expr[0].IsCall)
            {
                LNode keyNode = expr[0], valueNode = expr[1];
                if (!keyNode.IsCall)
                {
                    object key = keyNode.IsLiteral ? keyNode.Value : keyNode.Name;
                    if (quote)
                    {
                        valueNode = valueNode.Calls(CodeSymbols.Braces) ? valueNode.WithTarget(CodeSymbols.Splice) : valueNode;
                        MacroProcessor.DefaultScopedProperties[key] = valueNode;
                        return(true);
                    }
                    else if (!valueNode.IsCall)
                    {
                        object value = valueNode.IsLiteral ? valueNode.Value : valueNode.Name.Name;
                        MacroProcessor.DefaultScopedProperties[key] = value;
                        return(true);
                    }
                }
            }
            if (quote)
            {
                Sink.Error("Command line", "--snippet: syntax error. Expected `key=code` where `key` is a literal or identifier with which to associate a code snippet.");
            }
            else
            {
                Sink.Error("Command line", "--set: syntax error. Expected `key=value` where `key` and `value` are literals or identifiers.");
            }
            return(false);
        }
Пример #22
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;
		}
Пример #23
0
 LNode EliminateBlockExprsInExecStmt(LNode stmt)
 {
     if (!stmt.IsCall)
     {
         return(stmt);
     }
     {
         LNode         cond;
         VList <LNode> blocks;
         if (stmt.Calls(CodeSymbols.Braces))
         {
             return(stmt.WithArgs(EliminateBlockExprs(stmt.Args, false)));
         }
         else if (stmt.CallsMin(CodeSymbols.If, 1) && (cond = stmt.Args[0]) != null)
         {
             blocks = new VList <LNode>(stmt.Args.Slice(1));
             return(ProcessBlockCallStmt(stmt, 1));
         }
         else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces))
         {
             return(ProcessBlockCallStmt(stmt, stmt.ArgCount - 1));
         }
         else
         {
             stmt = BubbleUpBlocks(stmt);
             if (stmt.CallsMin(__runSequence, 1))
             {
                 return(stmt.Args.AsLNode(S.Splice));
             }
         }
     }
     return(stmt);
 }
Пример #24
0
		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);
		}
Пример #25
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;
		}
Пример #26
0
 /// <summary>Verifies that a declaration of a single variable is valid, and gets its parts.</summary>
 /// <param name="expr">Potential variable or field declaration</param>
 /// <param name="type">Variable type (empty identifier if `var`)</param>
 /// <param name="name">Variable name (identifier or $substutution expr)</param>
 /// <param name="initialValue">Initial value that is assigned in <c>expr</c>, or null if unassigned.</param>
 /// <returns>True if <c>expr</c> is declaration of a single variable.</returns>
 public static bool IsVariableDeclExpr(LNode expr, out LNode type, out LNode name, out LNode initialValue, Pedantics p = Pedantics.Lax)
 {
     type = name = initialValue = null;
     if (expr.Calls(S.Var, 2))
     {
         type = expr.Args[0];
         name = expr.Args[1];
         // don't need to call HasPAttrs(type, p) because IsComplexIdentifier will check for printable attrs
         if (HasPAttrs(expr, p) || HasPAttrs(name, p))
         {
             return(false);
         }
         if (name.Calls(S.Assign, 2))
         {
             initialValue = name.Args[1];
             name         = name.Args[0];
             if (HasPAttrs(name, p) || HasPAttrs(initialValue, p))
             {
                 return(false);
             }
         }
         return(IsComplexIdentifier(type, ICI.AllowAnyExprInOf, p) && (name.IsId || name.Calls(S.Substitute, 1)));
     }
     return(false);
 }
Пример #27
0
		public static void SpliceAdd(this RWList<LNode> list, LNode node, Symbol listName)
		{
			if (node.Calls(listName))
				list.AddRange(node.Args);
			else
				list.Add(node);
		}
Пример #28
0
        protected override void Stmt(string result, LNode input, Action <EcsPrinterOptions> configure = null, Mode mode = Mode.Both)
        {
            bool exprMode = (mode & Mode.Expression) != 0;

            if ((mode & Mode.PrinterTest) == 0)
            {
                return;
            }

            var options = new EcsPrinterOptions();

            options.IndentString = "  ";
            // by default, test the mode that is more difficult to get right
            options.AllowChangeParentheses = false;
            // TODO: make round tripping work without this
            options.NewlineOptions &= ~(NewlineOpt.AfterOpenBraceInNewExpr | NewlineOpt.BeforeCloseBraceInNewExpr);
            if (configure != null)
            {
                configure(options);
            }
            var sb    = new StringBuilder();
            var mode2 = exprMode ? ParsingMode.Expressions : ParsingMode.Statements;

            if (input.Calls(S.Splice))
            {
                EcsLanguageService.Value.Print(input.Args, sb, MessageSink.Default, mode2, options);
            }
            else
            {
                EcsLanguageService.Value.Print(input, sb, MessageSink.Default, mode2, options);
            }
            AreEqual(result, sb.ToString());
        }
Пример #29
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);
        }
Пример #30
0
        public virtual LNode VisitInput(LNode stmt, IMessageSink sink)
        {
            LNode aliasSet;

            if ((stmt.Calls(_alias, 1) || stmt.CallsMin(S.Alias, 1)) &&
                (aliasSet = stmt.Args[0]).Calls(S.Assign, 2))
            {
                IEnumerable <KeyValuePair <LNode, LNode> > q;
                LNode alias = aliasSet.Args[0], replacement = aliasSet.Args[1], old;
                if (_definedAliases.TryGetValue(alias, out old))
                {
                    if (stmt.AttrNamed(S.Partial) == null || !old.Equals(replacement))
                    {
                        sink.Warning(alias, "Redefinition of alias '{0}'", alias);
                    }
                }
                else if ((q = _definedAliases.Where(pair => replacement.Equals(pair.Value))).Any())
                {
                    sink.Warning(replacement, "Aliases '{0}' and '{1}' have the same replacement value", q.First().Key, alias);
                }
                _definedAliases[alias] = replacement;
                return(LNode.Call(S.Splice, VList <LNode> .Empty));              // erase alias from output
            }
            return(null);
        }
Пример #31
0
        bool SetPropertyHelper(string exprStr, bool quote)
        {
            LNode expr = (InLang ?? ParsingService.Current).ParseSingle(exprStr, Sink, ParsingMode.Expressions);

            if (expr.Calls(CodeSymbols.Assign, 2) && !expr[0].IsCall)
            {
                object key    = expr[0].IsLiteral ? expr[0].Value : expr[0].Name;
                LNode  valueN = expr[1];
                object value  = valueN.Value;
                if (quote)
                {
                    value = valueN.Calls(CodeSymbols.Braces) ? valueN.Args.AsLNode(CodeSymbols.Splice) : valueN;
                }
                if (!(value is NoValue))
                {
                    MacroProcessor.DefaultScopedProperties[key] = value;
                    return(true);
                }
            }
            if (quote)
            {
                Sink.Write(Severity.Error, "Command line", "--snippet: syntax error. Expected `key=code` where `key` is a literal or identifier with which to associate a code snippet.");
            }
            else
            {
                Sink.Write(Severity.Error, "Command line", "--set: syntax error. Expected `key=value` where `key` is a literal or identifier with which to associate a value.");
            }
            return(false);
        }
Пример #32
0
 /// <summary>Returns Basis if it's a method signature; otherwise constructs a default signature.</summary>
 public LNode GetMethodSignature()
 {
     if (Basis != null && Basis.Calls(S.Fn) && Basis.ArgCount.IsInRange(3, 4))
     {
         var parts = Basis.Args;
         if (parts.Count == 4)
         {
             parts.RemoveAt(3);
         }
         if (IsRecognizer)
         {
             parts[0] = F.Bool;
         }
         parts[1] = F.Id(Name);
         return(Basis.WithArgs(parts));
     }
     else
     {
         var method = F.Fn(IsRecognizer ? F.Bool : F.Void, F.Id(Name), F.List());
         if (IsPrivate)
         {
             method = F.Attr(F.Id(S.Private), method);
         }
         else if (IsStartingRule | IsToken)
         {
             method = F.Attr(F.Id(S.Public), method);
         }
         return(method);
     }
 }
Пример #33
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);
        }
Пример #34
0
		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);
		}
Пример #35
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));
		}
Пример #36
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)));
        }
Пример #37
0
		static LNode MergeIdentifiers(LNode left, LNode right)
		{
			if (left == null)
				return right;
			if (right.IsIdNamed(S.Missing))
				return left;
			{
				LNode right1, right2;
				if (right.Calls(CodeSymbols.Dot, 1) && (right2 = right.Args[0]) != null)
					return LNode.Call(CodeSymbols.Dot, LNode.List(left, right2));
				else if (right.Calls(CodeSymbols.Dot, 2) && (right1 = right.Args[0]) != null && (right2 = right.Args[1]) != null)
					return LNode.Call(CodeSymbols.Dot, LNode.List(MergeIdentifiers(left, right1), right2));
				else
					throw new LogException(Severity.Note, right, "Multi-using statement seems malformed. Correct example: `using System(.Text, .Linq));`");
			}
		}
Пример #38
0
		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);
		}
Пример #39
0
        internal static VList <LNode> GetArgNamesFromFormalArgList(LNode args, Action <LNode> onError)
        {
            VList <LNode> formalArgs = args.Args;
            VList <LNode> argList    = VList <LNode> .Empty;

            foreach (var formalArg in formalArgs)
            {
                if (!formalArg.Calls(S.Var, 2))
                {
                    onError(formalArg);
                }
                else
                {
                    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);
                }
            }
            return(argList);
        }
Пример #40
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)"));
            }
        }
Пример #41
0
        private void PrintWhereClauses(LNode name)
        {
            // Example: #of(Foo, [#where(#class, IEnumerable)] T)
            //          represents Foo<T> where T: class, IEnumerable
            if (!name.Calls(S.Of))
            {
                return;
            }

            // Look for "where" clauses and print them
            bool first = true;

            for (int i = 1, c = name.ArgCount; i < c; i++)
            {
                var param = name.Args[i];
                for (int a = 0, ac = param.AttrCount; a < ac; a++)
                {
                    var where = param.Attrs[a];
                    if (where.CallsMin(S.Where, 1))
                    {
                        using (Indented)
                        {
                            if (!Newline(first ? NewlineOpt.BeforeWhereClauses : NewlineOpt.BeforeEachWhereClause))
                            {
                                _out.Space();
                            }
                            first = false;
                            _out.Write("where", true);
                            PrintSimpleIdent(param.Name, 0);
                            Space(SpaceOpt.BeforeWhereClauseColon);
                            WriteThenSpace(':', SpaceOpt.AfterColon);
                            bool firstC = true;
                            foreach (var constraint in where.Args)
                            {
                                if (firstC)
                                {
                                    firstC = false;
                                }
                                else
                                {
                                    WriteThenSpace(',', SpaceOpt.AfterComma);
                                }
                                if (constraint.Name == S.New && constraint.ArgCount == 0)
                                {
                                    _out.Write("new()", true);
                                }
                                else if (constraint.IsId && (constraint.Name == S.Class || constraint.Name == S.Struct))
                                {
                                    WriteOperatorName(constraint.Name);
                                }
                                else
                                {
                                    PrintExpr(constraint, StartExpr);
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #42
0
        public static LNode static_if(LNode @if, IMessageSink sink)
        {
            if (!MathEx.IsInRange(@if.ArgCount, 2, 3))
            {
                return(null);
            }
            RVList <LNode> conds = MacroProcessor.Current.ProcessSynchronously(@if.Args[0]);
            object         @bool;

            if (conds.Count == 1 && (@bool = conds[0].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(sink, @if.Args[0], "'static if' is incredibly limited right now. Currently it only supports a literal boolean or (x `tree==` y)"));
            }
        }
Пример #43
0
		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];
		}
Пример #44
0
		/// <summary>Sets ListType and/or ListInitializer based on an expression.
		/// A statement like <c>Type x = expr</c> sets <c>ListType = Type</c> and <c>ListInitializer = expr</c>;
		/// A statement like <c>Type x</c> just sets <c>ListType = Type</c>; and any other
		/// expression <c>expr</c> sets <c>ListInitializer = expr</c>.</summary>
		public void SetListInitializer(LNode varDecl)
		{
			if (varDecl.Calls(S.Var, 2)) {
				ListType = varDecl.Args[0];
				if (varDecl.Args[1].Calls(S.Assign, 2))
					ListInitializer = varDecl.Args[1].Args[1];
			} else {
				ListInitializer = varDecl;
			}
		}
Пример #45
0
		static LNode GetForwardingTarget(LNode fwd, LNode methodName)
		{
			if (fwd.Calls(S.Forward, 1)) {
				LNode target = fwd.Args[0];
				if (target.Calls(S.Dot, 2) && target.Args[1].IsIdNamed(_hash))
					return target.WithArgChanged(1, target.Args[1].WithName(
						Ecs.EcsNodePrinter.KeyNameComponentOf(methodName)));
				return target;
			} else
				return null;
		}
Пример #46
0
		private static void DoDeconstruct(LNode arg, IMacroContext context, bool printErrorOnFailure)
		{
			LNode patternSpec = arg.Args[0, LNode.Missing], input = arg.Args[1, LNode.Missing];
			if (!arg.Calls(S.Assign, 2))
			{
				if (arg.Calls(S.Lambda, 2))
					G.Swap(ref patternSpec, ref input);
				else {
					context.Sink.Error(arg, "expected an assignment (`patterns = input`)");
					return;
				}
			}

			// Build list of patterns out of the binary operator series p1 | p2 | p3
			var patterns = new FVList<LNode>();
			while (patternSpec.Calls(S.OrBits, 2) && !patternSpec.IsParenthesizedExpr()) {
				patterns.Add(patternSpec[1]);
				patternSpec = patternSpec[0];
			}
			patterns.Add(patternSpec);

			// Remove outer braces, then run macros
			patterns = patterns.SmartSelect(p => p.Calls(S.Braces, 1) ? p[0] : p);
			input = input.Calls(S.Braces, 1) ? input[0] : input;
			input = context.PreProcess(input);

			// Perform matching & capturing
			foreach (var pattern in patterns) {
				IDictionary<Symbol, LNode> captures;
				if (LNodeExt.MatchesPattern(input, pattern, out captures)) {
					if (captures.Count == 0)
						context.Write(printErrorOnFailure ? Severity.Warning : Severity.Error, pattern,
							"This pattern has no effect, since it does not use `$` to capture any variables.");
					SetSyntaxVariables(captures, context);
					return;
				}
			}

			if (printErrorOnFailure)
				context.Sink.Error(arg, "Deconstruction failed.");
		}
Пример #47
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;
		}
Пример #48
0
		protected override VList<LNode> AttachTriviaTo(ref LNode node, IListSource<Token> trivia, TriviaLocation loc, LNode parent, int indexInParent)
		{
			int nli;
			if (loc == TriviaLocation.Trailing && indexInParent == 1 && parent != null && parent.Calls(CodeSymbols.If, 3) && 
				(nli = trivia.LastIndexWhere(t => t.Type() == TokenType.Newline)) != -1) {
				// The 'else' keyword is invisible here, but it often appears on a line by 
				// itself; remove a newline to avoid creating a blank line when printing.
				var triviaSans = new DList<Token>(trivia);
				triviaSans.RemoveAt(nli);
				trivia = triviaSans;
			}
			return base.AttachTriviaTo(ref node, trivia, loc, parent, indexInParent);
		}
Пример #49
0
		[LexicalMacro("using System(, .Collections.Generic, .Linq, .Text);", "Generates multiple using-statements from a single one.", "#import", Mode = MacroMode.Passive | MacroMode.Normal)] public static LNode UsingMulti(LNode stmt, IMacroContext context)
		{
			{
				LNode multiNamespace;
				if (stmt.Calls(CodeSymbols.Import, 1) && (multiNamespace = stmt.Args[0]) != null)
					try {
						var list = GetNamespaces(stmt[0]);
						if (list == null)
							return null;
						return LNode.Call(CodeSymbols.Splice, LNode.List(list.Select(namespc => (LNode) LNode.Call(CodeSymbols.Import, LNode.List(namespc)))));
					} catch (LogException exc) {
						exc.Msg.WriteTo(context.Sink);
					}
			}
			return null;
		}
Пример #50
0
		public static LNode UsingMulti(LNode stmt, IMacroContext context)
		{
			{
				LNode multiNamespace;
				if (stmt.Calls(CodeSymbols.Import, 1) && (multiNamespace = stmt.Args[0]) != null)
					try {
						var list = GetNamespaces(stmt[0]);
						if (list == null)
							return null;
						return LNode.Call(CodeSymbols.Splice, LNode.List(list.Select(namespc => (LNode) LNode.Call(CodeSymbols.Import, LNode.List(namespc)))));
					} catch (LogException exc) {
						exc.Msg.WriteTo(context.Sink);
					}
			}
			return null;
		}
Пример #51
0
		public static LNode NullDot(LNode node, IMessageSink sink)
		{
			if (!node.Calls(S.NullDot, 2))
				return null;

			var a = node.Args;
			LNode prefix = a[0], suffix = 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
			return F.Call(S.QuestionMark, F.Call(S.Neq, prefix, F.@null), 
				ConvertToNormalDot(prefix, suffix), F.Null);
		}
Пример #52
0
		[LexicalMacro("e.g. alt class Pair<A,B> { alt this(A Item1, B Item2); }", "Expands a short description of an 'algebraic data type' into a set of classes with a common base class. " + "All data members are read-only, and for each member (e.g. Item1 and Item2 above), " + "a With() method is generated to let users create modified versions.", "#class", Mode = MacroMode.Passive | MacroMode.Normal)] public static LNode AlgebraicDataType(LNode classDecl, IMacroContext context)
		{
			int i;
			{
				LNode baseName;
				VList<LNode> attrs, baseTypes, body;
				if ((attrs = classDecl.Attrs).IsEmpty | true && (i = attrs.IndexWhere(a => a.IsIdNamed(__alt))) > -1 && classDecl.Calls(CodeSymbols.Class, 3) && (baseName = classDecl.Args[0]) != null && classDecl.Args[1].Calls(CodeSymbols.AltList) && classDecl.Args[2].Calls(CodeSymbols.Braces)) {
					baseTypes = classDecl.Args[1].Args;
					body = classDecl.Args[2].Args;
					attrs = attrs.RemoveAt(i);
					var adt = new AltType(attrs, baseName, baseTypes, null);
					adt.ScanClassBody(body);
					var output = new VList<LNode>();
					adt.GenerateOutput(ref output);
					return LNode.Call(CodeSymbols.Splice, LNode.List(output));
				}
			}
			return null;
		}
Пример #53
0
		public static LNode AlgebraicDataType(LNode classDecl, IMacroContext context)
		{
			int i;
			{
				LNode baseName;
				VList<LNode> attrs, baseTypes, body;
				if ((attrs = classDecl.Attrs).IsEmpty | true && (i = attrs.IndexWhere(a => a.IsIdNamed(__alt))) > -1 && classDecl.Calls(CodeSymbols.Class, 3) && (baseName = classDecl.Args[0]) != null && classDecl.Args[1].Calls(CodeSymbols.AltList) && classDecl.Args[2].Calls(CodeSymbols.Braces)) {
					baseTypes = classDecl.Args[1].Args;
					body = classDecl.Args[2].Args;
					attrs = attrs.RemoveAt(i);
					var adt = new AltType(attrs, baseName, baseTypes, null);
					adt.ScanClassBody(body);
					var output = new VList<LNode>();
					adt.GenerateOutput(ref output);
					return LNode.Call(CodeSymbols.Splice, LNode.List(output));
				}
			}
			return null;
		}
Пример #54
0
		[LexicalMacro("e.g. alt class Tree<T> { alt Node(Tree<T> Left, Tree<T> Right); alt Leaf(T Value); }", "Expands a short description of an 'algebraic data type' into a set of classes with a common base class.", "#class", Mode = MacroMode.Passive | MacroMode.Normal)] public static LNode AlgebraicDataType(LNode classDecl, IMacroContext context)
		{
			int i;
			{
				LNode baseName;
				RVList<LNode> attrs, baseTypes, body;
				if ((attrs = classDecl.Attrs).IsEmpty | true && (i = attrs.IndexWhere(a => a.IsIdNamed(__alt))) > -1 && classDecl.Calls(CodeSymbols.Class, 3) && (baseName = classDecl.Args[0]) != null && classDecl.Args[1].Calls(CodeSymbols.AltList) && classDecl.Args[2].Calls(CodeSymbols.Braces)) {
					baseTypes = classDecl.Args[1].Args;
					body = classDecl.Args[2].Args;
					attrs = attrs.RemoveAt(i);
					var adt = new AltType(attrs, baseName, baseTypes, null);
					adt.ScanClassBody(body);
					var output = new RVList<LNode>();
					adt.GenerateOutput(ref output);
					return LNode.Call(CodeSymbols.Splice, new RVList<LNode>(output));
				}
			}
			return null;
		}
Пример #55
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, 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;
		}
Пример #56
0
		// Decides whether a value should be placed in a temporary variable
		// if it is evaluated more than once by a macro. This returns true for 
		// non-uppercase identifiers like "x" or "_Foo", for literals like 42,
		// and for dotted expressions in which all components are non-uppercase 
		// identifiers, e.g. foo.bar.baz. Returns false for everything else.
		internal protected static bool LooksLikeSimpleValue(LNode value)
		{
			if (value.IsCall) {
				if (value.Calls(S.Dot)) {
					if (value.ArgCount == 1)
						value = value.Args[0];
					else if (value.ArgCount == 2) {
						if (!LooksLikeSimpleValue(value.Args[0]))
							return false;
						value = value.Args[1];
					} else
						return false;
				} else
					return false;
			}
			if (value.IsId)
				return !char.IsUpper(value.Name.Name.TryGet(0, '\0'));
			if (value.IsLiteral)
				return true;
			return false;
		}
Пример #57
0
		protected override void Stmt(string result, LNode input, Action<EcsPrinterOptions> configure = null, Mode mode = Mode.Both)
		{
			bool exprMode = (mode & Mode.Expression) != 0;
			if ((mode & Mode.PrinterTest) == 0)
				return;

			var options = new EcsPrinterOptions();
			options.IndentString = "  ";
			// by default, test the mode that is more difficult to get right
			options.AllowChangeParentheses = false;
			// TODO: make round tripping work without this
			options.NewlineOptions &= ~(NewlineOpt.AfterOpenBraceInNewExpr | NewlineOpt.BeforeCloseBraceInNewExpr);
			if (configure != null)
				configure(options);
			var sb = new StringBuilder();
			var mode2 = exprMode ? ParsingMode.Expressions : ParsingMode.Statements;
			if (input.Calls(S.Splice))
				EcsLanguageService.Value.Print(input.Args, sb, MessageSink.Default, mode2, options);
			else
				EcsLanguageService.Value.Print(input, sb, MessageSink.Default, mode2, options);
			AreEqual(result, sb.ToString());
		}
Пример #58
0
			private bool SimpleEnoughToRepeat(LNode code)
			{
				Debug.Assert(code.Calls(S.Braces));
				// a simple heuristic
				if (code.ArgCount > 1)
					return false;
				return code.ArgCount == 1 && !code.Args[0].Calls(S.If) && code.ArgNamed(S.Braces) == null;
			}
Пример #59
0
		protected override LNode DoneAttaching(LNode node, LNode parent, int indexInParent)
		{
			// Constructors are funky in EC# because EC# generalizes constructors so
			// you can write, for example, `this() { F(); base(); G(); }`. 
			// Plain C# constructors like `this() : base() { G(); }`, `base(x)`
			// are actually stored like   `this() { base(); G(); }`, where the colon
			// is the beginning of the Range of the constructor body and the opening 
			// brace is the range of the Target of the method body. This makes it 
			// difficult to get the trivia attached the way we want. For example, this 
			// constructor:
			//
			//     Foo(int x) 
			//        : base(x)
			//     {
			//        Bar();
			//     }
			//
			// Gets trivia attached like this:
			//
			//     #cons(@``, Foo, #(int x), [#trivia_newline] ([#trivia_newline] @`'{}`)(
			//         [#trivia_appendStatement] base(x), Bar()));
			//
			// This code changes the trivia to something more reasonable:
			//
			//     #cons(@``, Foo, #(int x), [#trivia_newline] { base(x), Bar() });
			//
			LNode baseCall;
			if (node.CallsMin(S.Braces, 1) && parent != null && parent.Calls(S.Constructor) 
				&& (baseCall = node.Args[0]).Range.StartIndex < node.Target.Range.StartIndex)
			{
				if (RemoveLeadingNewline(ref node) != null)
					node = node.WithArgChanged(0, baseCall.WithoutAttrNamed(S.TriviaAppendStatement));
				LNode target = node.Target, newline_trivia;
				if ((newline_trivia = RemoveLeadingNewline(ref target)) != null) {
					node = node.WithTarget(target).PlusAttrBefore(newline_trivia);
				}
			}
			return node;
		}
Пример #60
0
		static LNode VarName(LNode varStmt)
		{
			if (varStmt.Calls(S.Var, 2)) {
				var nameAndInit = varStmt.Args[1];
				if (nameAndInit.Calls(S.Assign, 2))
					return nameAndInit.Args[0];
				else
					return nameAndInit;
			}
			return null;
		}