Example #1
0
        public static LNode IfUnless(LNode node, bool isUnless, IMessageSink sink)
        {
            var   args = node.Args;
            LNode cond = args.TryGet(0, null), then = args.TryGet(1, null),
                  elseKW = args.TryGet(2, null), @else = args.TryGet(3, null);

            if (cond == null)
            {
                return(null);
            }
            if (then == null)
            {
                return(Reject(sink, cond, "'{0}' statement ended early", isUnless ? "unless" : "if"));
            }
            if (isUnless)
            {
                cond = F.Call(S.Not, cond);
            }
            if (elseKW == null)
            {
                return(node.With(S.If, cond, then));
            }
            if (!elseKW.IsIdNamed(_else))
            {
                return(Reject(sink, elseKW, "'{0}': expected else clause or end-of-statement marker", isUnless ? "unless" : "if"));
            }
            if (@else.IsId && args.Count > 4)
            {
                @else = LNode.Call(@else.Name, new VList <LNode>(args.Slice(4)), node);
            }
            return(node.With(S.If, cond, then, @else));
        }
Example #2
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);
 }
Example #3
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));
		}
Example #4
0
		private static LNode TransformOnCatch(LNode node, LNode firstArg, LNode rest, LNode on_handler)
		{
			if (on_handler == null)
				return null;
			if (firstArg == null)
				firstArg = LNode.Missing;
			else if (firstArg.IsId)
				firstArg = firstArg.With(S.Var, F.Id(_Exception), firstArg);
			return node.With(S.Try, rest, node.With(S.Catch, firstArg, F.Missing, on_handler));
		}
Example #5
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));
		}
Example #6
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)));
        }
Example #7
0
		private static LNode TransformOnCatch(LNode node, LNode firstArg, LNode rest, LNode on_handler)
		{
			if (on_handler == null)
				return null;
			if (firstArg == null)
				firstArg = LNode.Missing;
			else if (firstArg.IsId)
				firstArg = firstArg.With(S.Var, F.Id(_Exception), firstArg);

			node.Style &= ~NodeStyle.OneLiner; // avoid collapsing output to one line
			return node.With(S.Try, rest, node.With(S.Catch, firstArg, F.Missing, on_handler));
		}
Example #8
0
 public static LNode @default1(LNode node, IMessageSink sink)
 {
     if (node.IsId)
     {
         return(node.With(S.Label, F.Id(S.Default)));
     }
     else if (node.ArgCount == 1 && node.Args[0].Calls(S.Braces))
     {
         return(F.Call(S.Splice, new VList <LNode>(node.With(S.Label, new VList <LNode>(F.Id(S.Default))), node.Args[0])));
     }
     return(null);
 }
Example #9
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)));
        }
Example #10
0
        public static LNode @do(LNode node, IMessageSink sink)
        {
            var args = node.Args;

            if (node.ArgCount == 2 && args.Last.Calls(_while, 1))
            {
                return(node.With(S.DoWhile, new VList <LNode>(node.Args[0], node.Args[1].Args[0])));
            }
            else if (node.ArgCount == 3 && args.TryGet(1, null).IsIdNamed(_while))
            {
                return(node.With(S.DoWhile, new VList <LNode>(node.Args[0], node.Args[2])));
            }
            return(null);
        }
Example #11
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));
        }
Example #12
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);
        }
 private static LNode TransformOnCatch(LNode node, LNode firstArg, LNode rest, LNode on_handler)
 {
     if (on_handler == null)
     {
         return(null);
     }
     if (firstArg == null)
     {
         firstArg = LNode.Missing;
     }
     else if (firstArg.IsId)
     {
         firstArg = firstArg.With(S.Var, F.Id(_Exception), firstArg);
     }
     return(node.With(S.Try, rest, node.With(S.Catch, firstArg, F.Missing, on_handler)));
 }
Example #14
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;
		}
Example #15
0
        public sealed override LNode Select(Func <LNode, LNode> selector)
        {
            LNode result = WithAttrs(n => Maybe.Value(selector(n)));
            LNode target = selector(Target);
            var   args   = Args.SmartSelect(selector);

            return(result.With(target, args));
        }
		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;
		}
Example #17
0
 public static LNode Do(LNode node, IMacroContext context)
 {
     if (node.ArgCount == 2 && node.Args[1].Calls(S.While, 1))
     {
         return(node.With(S.DoWhile, node[0], node[1].Args[0]));
     }
     return(null);
 }
Example #18
0
 public static LNode @throw(LNode node, IMessageSink sink)
 {
     if (node.ArgCount > 1)
     {
         return(null);
     }
     return(node.With(S.Throw, node.Args));            // change throw -> #throw() and throw(x) -> #throw(x)
 }
Example #19
0
 public static LNode QuestionMark(LNode node, IMessageSink sink)
 {
     if (node.ArgCount == 2 && node.Args[1].Calls(S.Colon, 2))
     {
         return(node.With(S.QuestionMark, node.Args[0], node.Args[1].Args[0], node.Args[1].Args[1]));
     }
     return(null);
 }
Example #20
0
 public static LNode GotoCase(LNode node, IMessageSink sink)
 {
     if (node.ArgCount == 2 && node.Args[0].IsIdNamed(_case))
     {
         return(node.With(S.GotoCase, node.Args[1]));
     }
     return(null);
 }
 LNode EliminateSequenceExpressionsInChildStmt(LNode stmt)
 {
     stmt = EliminateSequenceExpressionsInExecStmt(stmt);
     if (stmt.Calls(__numrunSequence))
     {
         return(stmt.With(S.Braces, MaybeRemoveNoOpFromRunSeq(stmt.Args)));
     }
     return(stmt);
 }
Example #22
0
        private static LNode TransformOnCatch(LNode node, LNode firstArg, LNode rest, LNode on_handler)
        {
            if (on_handler == null)
            {
                return(null);
            }
            if (firstArg == null)
            {
                firstArg = LNode.Missing;
            }
            else if (firstArg.IsId)
            {
                firstArg = firstArg.With(S.Var, F.Id(_Exception), firstArg);
            }

            node.Style &= ~NodeStyle.OneLiner;             // avoid collapsing output to one line
            return(node.With(S.Try, rest, node.With(S.Catch, firstArg, F.Missing, on_handler)));
        }
Example #23
0
        public static LNode QuickBind(LNode node, IMessageSink sink)
        {
            var a = node.Args;

            if (a.Count == 2)
            {
                return(node.With(S.Var, new VList <LNode>(F.Missing, F.Call(S.Assign, a[1], a[0]))));
            }
            return(null);
        }
Example #24
0
        public static LNode ColonEquals(LNode node, IMessageSink sink)
        {
            var a = node.Args;

            if (a.Count == 2)
            {
                LNode name = a[0], value = a[1];
                return(node.With(S.Var, F.Missing, F.Call(S.Assign, name, value)));
            }
            return(null);
        }
Example #25
0
        public static LNode ColonColon(LNode node, IMessageSink sink)
        {
            var a = node.Args;

            if (a.Count == 2)
            {
                var r = node.With(S.Var, a[1], a[0]);
                r.BaseStyle = NodeStyle.Operator;
                return(r);
            }
            return(null);
        }
 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);
 }
Example #27
0
        public static LNode ColonColonInit(LNode node, IMessageSink sink)
        {
            var a = node.Args;

            if (a.Count == 2)
            {
                LNode name = a[0], value = a[1];
                if (name.Calls(S.ColonColon, 2))
                {
                    return(node.With(S.Var, name.Args[1], F.Call(S.Assign, name.Args[0], value)));
                }
            }
            return(null);
        }
Example #28
0
        public static LNode @for(LNode node, IMessageSink sink)
        {
            LNode tuple;

            if (node.ArgCount == 2 && (tuple = node.Args[0]).Calls(S.Tuple, 3))
            {
                return(node.With(S.For, tuple.Args[0], tuple.Args[1], tuple.Args[2], node.Args[1]));
            }
            else if (node.ArgCount == 4)
            {
                return(node.WithTarget(S.For));
            }
            return(null);
        }
Example #29
0
        public static LNode @foreach(LNode node, IMessageSink sink)
        {
            var args = node.Args;

            if (args.Count == 2 && args[0].Calls(_in, 2))
            {
                LNode decl = args[0].Args[0], list = args[0].Args[1], body = args[1];
                if (decl.IsId)
                {
                    decl = F.Var(F.Missing, decl);
                }
                return(node.With(S.ForEach, decl, list, body));
            }
            return(null);
        }
Example #30
0
        public static LNode rule(LNode node, IMacroContext context)
        {
            bool isToken;

            if ((isToken = node.Calls(_token, 2)) || node.Calls(_rule, 2))
            {
                node = context.PreProcessChildren();
                LNode sig = node.Args[0];
                // Ugh. Because the rule has been macro-processed, "rule X::Y ..."
                // has become "rule #var(Y,X) ...". We must allow this, because in
                // case of something like "rule X(arg::int)::Y" we actually do want
                // the argument to become `#var(int, arg)`; so just reverse the
                // transform that we didn't want.
                if (sig.Calls(S.Var, 2))
                {
                    sig = F.Call(S.ColonColon, sig.Args[1], sig.Args[0]);
                }

                LNode name = sig, returnType = F.Void;
                if (sig.Calls(S.ColonColon, 2))
                {
                    returnType = sig.Args[1];
                    name       = sig.Args[0];
                }
                if (EcsValidators.IsComplexIdentifier(name))
                {
                    name = F.Call(name);                     // def requires an argument list
                }
                LNodeList args = name.Args;
                name = name.Target;

                LNode newBody = ParseRuleBody(node.Args[1], context);
                if (newBody != null)
                {
                    return(node.With(isToken ? _hash_token : _hash_rule,
                                     returnType, name, F.AltList(args), newBody));
                }
            }
            return(null);
        }
Example #31
0
        private static LNode ParseRuleBody(LNode ruleBody, IMessageSink sink)
        {
            TokenTree ruleTokens;

            if ((ruleTokens = ruleBody.Value as TokenTree) == null && !ruleBody.Calls(S.Braces))
            {
                return(null);
            }

            if (ruleTokens != null)
            {
                return(StageOneParser.ParseTokenTree(ruleTokens, sink, ruleBody));
            }
            else
            {
                if (ruleBody.Args.Any(stmt => stmt.Value is TokenTree))
                {
                    ruleBody = ruleBody.With(S.Tuple, ruleBody.Args.SmartSelect(stmt => ParseStmtInRule(stmt, sink)));
                }
            }
            return(ruleBody);
        }
Example #32
0
        public static LNode rule(LNode node, IMacroContext context)
        {
            bool isToken;

            if ((isToken = node.Calls(_token, 2)) || node.Calls(_rule, 2))
            {
                node = context.PreProcessChildren();
                LNode sig = node.Args[0];
                // Ugh. Because the rule has been macro-processed, "rule X::Y ..."
                // has become "rule #var(Y,X) ...". Reverse this transform.
                if (sig.Calls(S.Var, 2))
                {
                    sig = F.Call(S.ColonColon, sig.Args[1], sig.Args[0]);
                }

                LNode name = sig, returnType = F.Void;
                if (sig.Calls(S.ColonColon, 2))
                {
                    returnType = sig.Args[1];
                    name       = sig.Args[0];
                }
                if (LeMP.Prelude.Les.Macros.IsComplexId(name))
                {
                    name = F.Call(name);                     // def requires an argument list
                }
                RVList <LNode> args = name.Args;
                name = name.Target;

                LNode newBody = ParseRuleBody(node.Args[1], context);
                if (newBody != null)
                {
                    return(node.With(isToken ? _hash_token : _hash_rule,
                                     returnType, name, F.List(args), newBody));
                }
            }
            return(null);
        }
Example #33
0
        private static LNode ParseRuleBody(LNode ruleBody, IMessageSink sink)
        {
            TokenTree ruleTokens;

            // Expecting @{...} or {...}
            if ((ruleTokens = ruleBody.Value as TokenTree) == null && !ruleBody.Calls(S.Braces))
            {
                sink.Error(ruleBody, "Expected token tree or braced block");
                return(null);
            }

            if (ruleTokens != null)
            {
                return(StageOneParser.ParseTokenTree(ruleTokens, sink));
            }
            else
            {
                if (ruleBody.Args.Any(stmt => stmt.Value is TokenTree))
                {
                    ruleBody = ruleBody.With(S.Tuple, ruleBody.Args.SmartSelect(stmt => ParseStmtInRule(stmt, sink)));
                }
            }
            return(ruleBody);
        }
Example #34
0
        public static LNode VarDecl(LNode node, IMacroContext context)
        {
            var a = node.Args;

            if (a.Count == 2)
            {
                LNode name = a[0], type = a[1], nameAssignment = name;
                if (type.Calls(S.Assign, 2))
                {
                    nameAssignment = type.WithArgs(name, type[1]);
                    type           = type[0];
                }
                if (name.IsId)
                {
                    return(node.With(S.Var, type, nameAssignment).SetBaseStyle(NodeStyle.Default));
                }
                else
                {
                    context.Write(Severity.Note, node, "Unrecognized variable declaration syntax");
                    return(null);
                }
            }
            return(null);
        }
Example #35
0
		public static LNode IfUnless(LNode node, bool isUnless, IMessageSink sink)
		{
			var args = node.Args;
			LNode cond = args.TryGet(0, null), then = args.TryGet(1, null),
				elseKW = args.TryGet(2, null), @else = args.TryGet(3, null);
			if (cond == null)
				return null;
			if (then == null)
				return Reject(sink, cond, "'{0}' statement ended early", isUnless ? "unless" : "if");
			if (isUnless)
				cond = F.Call(S.Not, cond);
			if (elseKW == null)
				return node.With(S.If, cond, then);
			if (!elseKW.IsIdNamed(_else))
				return Reject(sink, elseKW, "'{0}': expected else clause or end-of-statement marker", isUnless ? "unless" : "if");
			if (@else.IsId && args.Count > 4)
				@else = LNode.Call(@else.Name, new RVList<LNode>(args.Slice(4)), node);
			return node.With(S.If, cond, then, @else);
		}
Example #36
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());
		}
			LNode EliminateSequenceExpressionsInChildStmt(LNode stmt)
			{
				stmt = EliminateSequenceExpressionsInExecStmt(stmt);
				if (stmt.Calls(__numrunSequence))
					return stmt.With(S.Braces, MaybeRemoveNoOpFromRunSeq(stmt.Args));
				return stmt;
			}
Example #38
0
		public static LNode QuickBind(LNode node, IMessageSink sink)
		{
			var a = node.Args;
			if (a.Count == 2)
				return node.With(S.Var, new RVList<LNode>(F._Missing, F.Call(S.Assign, a[1], a[0])));
			return null;
		}
Example #39
0
		public static LNode ColonColonInit(LNode node, IMessageSink sink)
		{
			var a = node.Args;
			if (a.Count == 2) {
				LNode name = a[0], value = a[1];
				if (name.Calls(S.ColonColon, 2))
					return node.With(S.Var, name.Args[1], F.Call(S.Assign, name.Args[0], value));
			}
			return null;
		}
Example #40
0
		public static LNode QuestionMark(LNode node, IMessageSink sink)
		{
			if (node.ArgCount == 2 && node.Args[1].Calls(S.Colon, 2))
				return node.With(S.QuestionMark, node.Args[0], node.Args[1].Args[0], node.Args[1].Args[1]);
			return null;
		}
Example #41
0
		public static LNode @try(LNode node, IMessageSink sink)
		{
			if (!node.IsCall)
				return null;

			// try(code, catch, Exception::e, handler, catch, ..., finally, handler)
			// ...becomes...
			// #try(#{ stmt1; stmt2; ... }, #catch(#var(Exception, e), handler), #finally(handler))
			LNode finallyCode = null;
			RWList<LNode> clauses = new RWList<LNode>();
			var parts = node.Args;
			
			for (int i = parts.Count-2; i >= 1; i -= 2)
			{
				var p = parts[i];
				if (p.IsIdNamed(_finally)) {
					if (clauses.Count != 0 || finallyCode != null)
						sink.Write(Severity.Error, p, "The «finally» clause must come last, there can only be one of them.");
					finallyCode = parts[i+1];
				} else if (p.Name == _catch) {
					if (p.ArgCount > 0) {
						// This is a normal catch clause
						clauses.Insert(0, F.Call(S.Catch, F.Call(S.Splice, p.Args), parts[i + 1]));
					} else {
						// This is a catch-all clause (the type argument is missing)
						if (clauses.Count != 0)
							sink.Write(Severity.Error, p, "The catch-all clause must be the last «catch» clause.");
						clauses.Add(F.Call(S.Catch, F._Missing, parts[i + 1]));
					}
				} else if (i > 1 && parts[i-1].IsIdNamed(_catch)) {
					// This is a normal catch clause
					clauses.Insert(0, F.Call(S.Catch, AutoRemoveParens(p), parts[i+1]));
					i--;
				} else {
					return Reject(sink, p, "Expected «catch» or «finally» clause here. Clause is missing or malformed.");
				}
				if (i == 2)
					return Reject(sink, parts[1], "Expected «catch» or «finally» clause here. Clause is missing or malformed.");
			}
			if (clauses.Count == 0 && finallyCode == null) {
				Debug.Assert(node.ArgCount <= 1);
				return Reject(sink, node, "Missing «catch, Type, Code» or «finally, Code» clause");
			}
			if (finallyCode != null)
				clauses.Add(F.Call(S.Finally, finallyCode));
			clauses.Insert(0, node.Args[0]);
			return node.With(S.Try, clauses.ToRVList());
		}
Example #42
0
		static LNode DefOrConstructor(LNode node, IMessageSink sink, bool isCons)
		{
			var parts = node.Args;
			LNode sig = parts.TryGet(0, null), body = parts.TryGet(1, null);
			if (!parts.Count.IsInRange(1, 2) || !sig.IsCall || (body != null && !body.Calls(S.Braces)))
				return null;
			
			LNode forwardTo = null, retVal = null;
			if (sig.Calls(S.Forward, 2)) {
				forwardTo = sig.Args[1];
				sig = sig.Args[0];
				if (body != null)
					return Reject(sink, sig.Target, "Cannot use ==> and a method body {...} at the same time.");
			}
			if (sig.Calls(S._RightArrow, 2) || sig.Calls(S.ColonColon, 2)) {
				retVal = sig.Args[1];
				sig = sig.Args[0];
			}
			if (retVal != null && retVal.Calls(S.Braces) && body == null) {
				body = retVal;
				retVal = F._Missing;
			}
			var name = sig.Target ?? sig;
			if (!IsTargetDefinitionId(sig, true))
				return Reject(sink, sig.Target, "Invalid method name");
			var argList = sig.ArgCount != 0 ? sig.WithTarget(S.AltList) : F.List();

			if (retVal == null)
				retVal = isCons ? F._Missing : F.Void;
			else if (isCons)
				return Reject(sink, retVal, "A constructor cannot have a return type");

			Symbol kind = isCons ? S.Cons : S.Fn;
			if (body != null)
				return node.With(kind, retVal, name, argList, body);
			else if (forwardTo != null)
				return node.With(kind, retVal, name, argList, F.Call(S.Forward, forwardTo));
			else
				return node.With(kind, retVal, name, argList);
		}
Example #43
0
		public static LNode TranslateSpaceDefinition(LNode node, IMacroContext context, Symbol newTarget)
		{
			if (!node.IsCall)
				return null;

			bool isAlias = newTarget == S.Alias, isNamespace = newTarget == S.Namespace;
			var args = node.Args;
			LNode nameEtc = args.TryGet(0, null), body = args.TryGet(1, null), oldName = null;

			if (args.Count == 1 ? !isAlias : (args.Count != 2 || !body.Calls(S.Braces))) {
				if (isNamespace && args.Count == 1) {
					// Special case: a namespace can auto-wrap whatever statements follow.
					body = F.Braces(context.RemainingNodes);
					context.DropRemainingNodes = true;
				} else
					return Reject(context, node, "A type definition must have the form kind(Name, { Body }) or kind(Name(Bases), { Body }) (where «kind» is struct/class/enum/trait/alias)");
			}
			if (isAlias) {
				if (!nameEtc.Calls(S.Assign, 2))
					return Reject(context, node, "An 'alias' (or 'using') definition must have the form alias(NewName = OldName, { Body }) or alias(NewName(Interfaces) = OldName, { Body })");
				oldName = nameEtc.Args[1];
				nameEtc = nameEtc.Args[0];
			}

			LNode name, bases;
			if (IsComplexId(nameEtc, true)) {
				name = nameEtc;
				bases = F.List();
			} else {
				name = nameEtc.Target ?? nameEtc;
				bases = nameEtc.WithTarget(S.AltList);
			}

			if (isNamespace) {
				if (!IsComplexId(name, true))
					return Reject(context, name, "Invalid namespace name (expected a complex identifier)");
			} else {
				if (!IsDefinitionId(name, false))
					return Reject(context, name, "Invalid type name (expected a simple name or Name!(T1,T2,...))");
			}

			if (isAlias) {
				if (body == null)
					return node.With(newTarget, F.Call(S.Assign, name, oldName), bases);
				else
					return node.With(newTarget, F.Call(S.Assign, name, oldName), bases, body);
			} else {
				Debug.Assert(body != null);
				return node.With(newTarget, name, bases, body);
			}
		}
Example #44
0
		public static LNode import_macros(LNode node, IMacroContext sink)
		{
			return node.With(_importMacros, node.Args);
		}
Example #45
0
		public static LNode @for(LNode node, IMessageSink sink)
		{
			LNode tuple;
			if (node.ArgCount == 2 && ((tuple = node.Args[0]).Calls(S.Tuple, 3) || tuple.Calls(S.Tuple, 2)))
				return node.With(S.For, 
					asAltList(tuple.Args[0]), 
					tuple.Args[1], 
					asAltList(tuple.Args[2, LNode.Missing]),
					node.Args[1]);
			else if (node.ArgCount == 4)
				return node.With(S.For,
					asAltList(node.Args[0]), 
					node.Args[1], 
					asAltList(node.Args[2]),
					node.Args[3]);
			return null;
		}
Example #46
0
		public static LNode ColonColon(LNode node, IMessageSink context)
		{
			var a = node.Args;
			if (a.Count == 2) {
				if (a[0].IsId) {
					var r = node.With(S.Var, a[1], a[0]);
					r.BaseStyle = NodeStyle.Operator;
					return r;
				} else if (a[0].CallsMin(S.Tuple, 1)) {
					var r = node.With(S.Var, new VList<LNode>(a[1]).AddRange(a[0].Args));
					r.BaseStyle = NodeStyle.Operator;
					return r;
				} else
					return Reject(context, node, "Expected a variable name or tuple to the left of `::`");
			}
			return null;
		}
Example #47
0
		public static LNode @default1(LNode node, IMessageSink sink)
		{
			if (node.IsId)
				return node.With(S.Label, F.Id(S.Default));
			else if (node.ArgCount == 1 && node.Args[0].Calls(S.Braces))
				return F.Call(S.Splice, new RVList<LNode>(node.With(S.Label, new RVList<LNode>(F.Id(S.Default))), node.Args[0]));
			return null;
		}
Example #48
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, body);
		}
Example #49
0
		public static LNode GotoCase(LNode node, IMessageSink sink)
		{
			if (node.ArgCount == 2 && node.Args[0].IsIdNamed(_case))
				return node.With(S.GotoCase, node.Args[1]);
			return null;
		}
Example #50
0
		public static LNode @var(LNode node, IMessageSink sink)
		{
			var parts = node.Args;
			if (parts.Count == 0)
				return Reject(sink, node, "A variable definition must have the form var(Name::Type), var(Name = value), or var(Name::Type = value)");
			if (parts[0].IsId)
				return null; // e.g. this is true for "static readonly x::Foo"

			RWList<LNode> varStmts = null;
			LNode varStmt = null;
			for (int i = 0; i < parts.Count; i++) {
				LNode part = parts[i], type = null, init = null;
				if (part.Calls(S.Assign, 2)) {
					init = part.Args[1];
					part = part.Args[0];
				}
				if (part.Calls(S.ColonColon, 2)) {
					type = part.Args[1];
					part = part.Args[0];
				}
				if (init == null && part.Calls(S.Assign, 2)) {
					init = part.Args[1];
					part = part.Args[0];
				}
				if (!part.IsId)
					return Reject(sink, part, "Expected a simple variable name here");
				if (type != null && !IsComplexId(type))
					return Reject(sink, type, "Expected a type name here");
				type = type ?? F._Missing;

				var nameAndInit = init == null ? part : F.Call(S.Assign, part, init);
				if (varStmt != null && varStmt.Args[0].Equals(type)) {
					// same type used again, e.g. (var x::int y::int) => (#var int x y)
					varStmt = varStmt.WithArgs(varStmt.Args.Add(nameAndInit));
				} else {
					// first item (var x::int => #var int x) or type changed (var a::A b::B => #var A a; #var B b)
					if (varStmt != null) {
						varStmts = varStmts ?? new RWList<LNode>();
						varStmts.Add(varStmt);
					}
					varStmt = node.With(S.Var, type, nameAndInit);
				}
			}
			
			// Return a single statement or a list of them if necessary
			if (varStmts != null) {
				varStmts.Add(varStmt);
				return F.Call(S.Splice, varStmts.ToRVList());
			} else {
				return varStmt;
			}
		}
Example #51
0
		public static LNode @throw(LNode node, IMessageSink sink)
		{
			if (node.ArgCount > 1) return null;
			return node.With(S.Throw, node.Args); // change throw -> #throw() and throw(x) -> #throw(x)
		}
Example #52
0
		public static LNode import_macros(LNode node, IMessageSink sink)
		{
			return node.With(_importMacros, node.Args);
		}
Example #53
0
		public static LNode ColonColon(LNode node, IMessageSink sink)
		{
			var a = node.Args;
			if (a.Count == 2) {
				var r = node.With(S.Var, a[1], a[0]);
				r.BaseStyle = NodeStyle.Operator;
				return r;
			}
			return null;
		}
Example #54
0
		public static LNode @for(LNode node, IMessageSink sink)
		{
			LNode tuple;
			if (node.ArgCount == 2 && (tuple = node.Args[0]).Calls(S.Tuple, 3))
				return node.With(S.For, tuple.Args[0], tuple.Args[1], tuple.Args[2], node.Args[1]);
			else if (node.ArgCount == 4)
				return node.WithTarget(S.For);
			return null;
		}
Example #55
0
		public static LNode ColonEquals(LNode node, IMessageSink sink)
		{
			var a = node.Args;
			if (a.Count == 2) {
				LNode name = a[0], value = a[1];
				return node.With(S.Var, F._Missing, F.Call(S.Assign, name, value));
			}
			return null;
		}
Example #56
0
		public static LNode @foreach(LNode node, IMessageSink sink)
		{
			var args = node.Args;
			if (args.Count == 2 && args[0].Calls(_in, 2)) {
				LNode decl = args[0].Args[0], list = args[0].Args[1], body = args[1];
				if (decl.IsId)
					decl = F.Var(F._Missing, decl);
				return node.With(S.ForEach, decl, list, body);
			}
			return null;
		}
Example #57
0
        private void InjectTriviaInChildren(LNode parent, out SourceRange triviaRange, out Maybe <Trivia> trivia, int indexInParent, ref LNode node)
        {
            // Current trivia's range is within node's range: Apply it to
            // the node's children, if any. First gather list of children
            // and sort by source-code order, if necessary:
            int min = node.Min;
            InternalList <Pair <LNode, int> > children = InternalList <Pair <LNode, int> > .Empty;

            children.Resize(node.Max - min + 1);
            bool inOrder = true;
            int  start, prevStart = int.MinValue;

            for (int i = 0; i < children.Count; i++, prevStart = start)
            {
                children[i] = Pair.Create(node[i + min], i + min);
                start       = children[i].A.Range.StartIndex;
                if (prevStart > start)
                {
                    inOrder = false;
                }
            }
            if (!inOrder)
            {
                children.Sort((a, b) => a.Item1.Range.StartIndex.CompareTo(b.Item1.Range.StartIndex));
            }

            // Call ourself recursively to apply trivia to children. Usually,
            // newChildren is the same length as children, but it may have extra
            // trivia attributes added.
            InternalList <Pair <LNode, int> > newChildren = new InternalList <Pair <LNode, int> >(children.Count);
            var  output  = RunCore(children.GetEnumerator(), node);
            bool changed = false;

            while (output.MoveNext())
            {
                var @new = output.Current;
                newChildren.Add(@new);
                if (@new.Item1 != children[@new.Item2 - min].Item1)
                {
                    changed = true;
                }
            }

            // At the end, gather up any remaining trivia
            InternalList <Trivia> triviaList = InternalList <Trivia> .Empty;

            trivia = CurrentTrivia(out triviaRange);
            while (trivia.HasValue && triviaRange.EndIndex <= node.Range.EndIndex)
            {
                triviaList.Add(trivia.Value);
                trivia  = AdvanceTrivia(out triviaRange);
                changed = true;
            }

            if (changed)
            {
                // If this is a call, attach any remaining trivia to the last child.
                if (node.IsCall && !triviaList.IsEmpty)
                {
                    int i    = newChildren.Count - 1;
                    var last = newChildren.InternalArray[i];
                    newChildren.InternalArray[i].A = AttachTriviaTo(last.A, triviaList, TriviaLocation.TrailingExtra, node, last.B) ?? last.A;
                }

                // Put the children back in their "conceptual" order
                if (!inOrder)
                {
                    newChildren.StableSort((a, b) => a.Item2.CompareTo(b.Item2));
                }

                // Update node's attributes, if any
                int numAttrs = newChildren.TakeWhile(p => p.B < -1).Count();
                if (numAttrs > 0)
                {
                    var attrs = LNode.List(newChildren.Slice(0, numAttrs).SelectArray(p => p.A));
                    node = node.WithAttrs(attrs);
                }

                if (node.IsCall)
                {
                    Debug.Assert(newChildren[numAttrs].B == -1);
                    var newArgs = newChildren.Slice(numAttrs + 1).SelectArray(p => p.A);
                    node = node.With(newChildren[numAttrs].A, LNode.List(newArgs));
                }
                else if (!triviaList.IsEmpty)
                {
                    // If current node is not a call, attach any remaining trivia to it.
                    node = AttachTriviaTo(node, triviaList, TriviaLocation.Ambiguous, parent, indexInParent);
                }
            }
        }
Example #58
0
		public static LNode @do(LNode node, IMessageSink sink)
		{
			var args = node.Args;
			if (node.ArgCount == 2 && args.Last.Calls(_while, 1)) {
				return node.With(S.DoWhile, new RVList<LNode>(node.Args[0], node.Args[1].Args[0]));
			} else if (node.ArgCount == 3 && args.TryGet(1, null).IsIdNamed(_while)) {
				return node.With(S.DoWhile, new RVList<LNode>(node.Args[0], node.Args[2]));
			}
			return null;
		}
Example #59
0
        public static LNode unroll(LNode var, VList <LNode> cases, LNode body, IMessageSink sink)
        {
            // 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.Error(vars[i], "Duplicate name in the left-hand tuple");                                 // non-fatal
                            }
                        }
                    }
                }
                else
                {
                    return(Reject(sink, var, "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)
            {
                iteration++;
                bool tuple = replacement.Calls(S.Tuple) || replacement.Calls(S.Braces);
                int  count = tuple ? replacement.ArgCount : 1;
                if (replacements.Count != count)
                {
                    sink.Error(replacement, "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()));
        }
Example #60
0
		public static LNode @unless(LNode node, IMessageSink sink)
		{
			var args = node.Args;
			LNode cond = args.TryGet(0, null), then = args.TryGet(1, null), @else = args.TryGet(3, null);
			if (node.ArgCount != 2 && (node.ArgCount != 4 || !args.TryGet(2, null).IsIdNamed(_else)))
				return Reject(sink, node, "An unless-statement must have the form «unless(Cond, expr)» or «unless(Cond, ThenClause, else, ElseClause)»");
			if (@else == null)
				return node.With(S.If, F.Call(S.Not, cond), then);
			else
				return node.With(S.If, F.Call(S.Not, cond), then, @else);
		}