Esempio n. 1
0
			public AltType(VList<LNode> classAttrs, LNode typeName, VList<LNode> baseTypes, AltType parentType)
			{
				_classAttrs = classAttrs;
				TypeName = typeName;
				BaseTypes = baseTypes;
				ParentType = parentType;
				//matchCode (TypeName) {
				//	case $stem<$(..a)>, $stem: 
				//		_typeNameStem = stem;
				//		_genericArgs = a; 
				//  default:
				//		_genericArgs = new WList<LNode>();
				//}
				{	// Above matchCode expanded:
					LNode stem;
					VList<LNode> a = default(VList<LNode>);
					if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) {
						_typeNameStem = stem;
						_genericArgs = a.ToWList();
					} else {
						_genericArgs = new WList<LNode>();
					}
				}
				if (ParentType != null) {
					BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs);
				
					// Search for all 'where' clauses on the ParentType and make sure OUR generic args have them too.
					bool changed = false;
					for (int i = 0; i < _genericArgs.Count; i++) {
						var arg = _genericArgs[i];
						var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name));
						if (parentArg != null) {
							var wheres = new HashSet<LNode>(WhereTypes(arg));
							int oldCount = wheres.Count;
							var parentWheres = WhereTypes(parentArg);
							foreach (var where in parentWheres)
								wheres.Add(where);
							if (wheres.Count > oldCount) {
								arg = arg.WithAttrs(arg.Attrs.SmartWhere(a => !a.Calls(S.Where))
								.Add(LNode.Call(S.Where, LNode.List(wheres))));
								_genericArgs[i] = arg;
								changed = true;
							}
						}
					}
					if (changed)
						TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator);
				}
				TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs());
			}
Esempio n. 2
0
			public AltType(RVList<LNode> typeAttrs, LNode typeName, RVList<LNode> baseTypes, AltType parentType)
			{
				_typeAttrs = typeAttrs;
				TypeName = typeName;
				BaseTypes = baseTypes;
				ParentType = parentType;
				if (ParentType != null)
					BaseTypes.Add(ParentType.TypeName);
				{
					LNode stem;
					RVList<LNode> a = default(RVList<LNode>);
					if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new RVList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) {
						_typeNameStem = stem;
						_genericArgs = a;
					}
				}
			}
        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);
        }
Esempio n. 4
0
            Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
            {
                var target           = expr.Target;
                var args             = expr.Args;
                var combinedSequence = LNode.List();

                target = BubbleUpBlocks(target);
                if (target.CallsMin(__runSequence, 1))
                {
                    combinedSequence = target.Args.WithoutLast(1);
                    expr             = expr.WithTarget(target.Args.Last);
                }
                args = args.SmartSelect(arg => BubbleUpBlocks(arg));
                int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__runSequence, 1));

                if (lastRunSeq >= 0)
                {
                    if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark)))
                    {
                        Context.Write(Severity.Error, expr, "#useVarDeclExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code may be incorrect.");
                    }
                    var argsW = args.ToList();
                    for (int i = lastRunSeq - 1; i >= 0; i--)
                    {
                        if (!argsW[i].CallsMin(__runSequence, 1) && !argsW[i].IsLiteral)
                        {
                            LNode tmpVarName, tmpVarDecl = TempVarDecl(argsW[i], out tmpVarName);
                            argsW[i] = LNode.Call((Symbol)"#runSequence", LNode.List(tmpVarDecl, tmpVarName));
                        }
                    }
                    for (int i = 0; i <= lastRunSeq; i++)
                    {
                        LNode arg = argsW[i];
                        if (arg.CallsMin(__runSequence, 1))
                        {
                            combinedSequence.AddRange(arg.Args.WithoutLast(1));
                            argsW[i] = arg.Args.Last;
                        }
                    }
                    expr = expr.WithArgs(LNode.List(argsW));
                }
                return(Pair.Create(combinedSequence, expr));
            }
Esempio n. 5
0
        public static bool IsLinqExpression(LNode n, Pedantics p = Pedantics.Lax)
        {
            var parts = n.Args;

            if (n.CallsMin(S.Linq, 2) && parts[0].Calls(S.From))
            {
                if (IsValidIntoClause(parts.Last, p))
                {
                    parts = parts.WithoutLast(1);
                }
                if (DetectSelectOrGroupBy(parts.Last) == null)
                {
                    return(false);
                }
                parts = parts.WithoutLast(1);
                return(AreValidLinqClauses(parts, 1, p));
            }
            return(false);
        }
Esempio n. 6
0
 public AltType(RVList <LNode> typeAttrs, LNode typeName, RVList <LNode> baseTypes, AltType parentType)
 {
     _typeAttrs = typeAttrs;
     TypeName   = typeName;
     BaseTypes  = baseTypes;
     ParentType = parentType;
     if (ParentType != null)
     {
         BaseTypes.Add(ParentType.TypeName);
     }
     {
         LNode          stem;
         RVList <LNode> a = default(RVList <LNode>);
         if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new RVList <LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null)
         {
             _typeNameStem = stem;
             _genericArgs  = a;
         }
     }
 }
Esempio n. 7
0
			public AltType(VList<LNode> classAttrs, LNode typeName, VList<LNode> baseTypes, AltType parentType)
			{
				_classAttrs = classAttrs;
				TypeName = typeName;
				BaseTypes = baseTypes;
				ParentType = parentType;
				{
					LNode stem;
					VList<LNode> a = default(VList<LNode>);
					if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList<LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null) {
						_typeNameStem = stem;
						_genericArgs = a.ToWList();
					} else {
						_genericArgs = new WList<LNode>();
					}
				}
				if (ParentType != null) {
					BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs);
					bool changed = false;
					for (int i = 0; i < _genericArgs.Count; i++) {
						var arg = _genericArgs[i];
						var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name));
						if (parentArg != null) {
							var wheres = new HashSet<LNode>(WhereTypes(arg));
							int oldCount = wheres.Count;
							var parentWheres = WhereTypes(parentArg);
							foreach (var where in parentWheres)
								wheres.Add(where);
							if (wheres.Count > oldCount) {
								arg = arg.WithAttrs(arg.Attrs.Where(a => !a.Calls(S.Where)).Add(LNode.Call(S.Where, LNode.List(wheres))));
								_genericArgs[i] = arg;
								changed = true;
							}
						}
					}
					if (changed)
						TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs));
				}
				TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs());
			}
Esempio n. 8
0
            LNode ConvertVarDeclToRunSequence(VList <LNode> attrs, LNode varType, LNode varName, LNode initValue)
            {
                initValue = BubbleUpBlocks(initValue);
                varType   = varType ?? F.Missing;
                LNode @ref;

                attrs = attrs.WithoutNodeNamed(S.Ref, out @ref);
                {
                    LNode         resultValue;
                    VList <LNode> stmts;
                    if (initValue.CallsMin((Symbol)"#runSequence", 1) && (resultValue = initValue.Args[initValue.Args.Count - 1]) != null)
                    {
                        stmts = initValue.Args.WithoutLast(1);
                        var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, resultValue))));
                        return(initValue.WithArgs(stmts.Add(newVarDecl).Add(varName)));
                    }
                    else
                    {
                        var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, initValue))));
                        return(LNode.Call((Symbol)"#runSequence", LNode.List(newVarDecl, varName)));
                    }
                }
            }
Esempio n. 9
0
        internal static bool IsEventDefinition(LNode node, out LNode type, out LNode name, out LNode body, Pedantics p)
        {
            // Syntax should either be
            //   #event(EventHandler, Click, {...}), or
            //   #event(EventHandler, #(Click, DoubleClick)),
            // but we can also parse
            //   #event(EventHandler, #(Click, DoubleClick), {...})
            type = name = body = null;
            int argCount = node.ArgCount;

            if (!CallsMinWPAIH(node, S.Event, 2, p) || argCount > 3)
            {
                return(false);
            }

            type = node.Args[0];
            name = node.Args[1];
            if (!IsComplexIdentifier(type, ICI.Default, p))
            {
                return(false);
            }
            if (!IsComplexIdentifier(name, ICI.Default, p) &&
                !(name.CallsMin(S.AltList, 1) && name.Args.All(a => IsComplexIdentifier(a, ICI.Default, p))))
            {
                return(false);
            }

            if (argCount == 3)
            {
                body = node.Args[2];
                return(CallsWPAIH(body, S.Braces, p) || CallsWPAIH(body, S.Forward, p));
            }
            else
            {
                return(argCount == 2);
            }
        }
Esempio n. 10
0
        // A definition identifier has the form Name or Name!(Id,$Id,...)
        // where Id is a simple identifier and Name is either a simple identifier
        // or (if dots are allowed) a complex identifier with allowOf=false.
        public static bool IsDefinitionId(LNode id, bool allowDots)
        {
            var args = id.Args;

            if (id.CallsMin(S.Of, 1))
            {
                if (!(allowDots ? IsComplexId(args[0], false) : args[0].IsId))
                {
                    return(false);
                }
                for (int i = 1; i < args.Count; i++)
                {
                    if (!(args[i].IsId || args[i].Calls(S.Substitute, 1) && args[i].Args[0].IsId))
                    {
                        return(false);
                    }
                }
                return(true);
            }
            else
            {
                return(allowDots ? IsComplexId(id, false) : id.IsId);
            }
        }
Esempio n. 11
0
        static LNode ProcessArgContractAttributes(LNode fn, int argsIndex, CodeContractRewriter rw, bool isLambda = false)
        {
            LNode fnArgs = fn.Args[argsIndex];

            if (fnArgs.CallsMin(isLambda ? S.Tuple : S.AltList, 1))
            {
                return(fn.WithArgChanged(argsIndex, fnArgs.WithArgs(arg => {
                    if (arg.HasAttrs)
                    {
                        return arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg)));
                    }
                    return arg;
                })));
            }
            else if (isLambda)
            {
                var arg = fnArgs;
                if (arg.HasAttrs)
                {
                    fn = fn.WithArgChanged(argsIndex, arg.WithAttrs(rw.Process(arg.Attrs, GetVarName(arg))));
                }
            }
            return(fn);
        }
Esempio n. 12
0
		/// <summary>Retrieves the "key" name component for the nameof(...) macro.</summary>
		/// <remarks>
		/// The key name component of <c>global::Foo!int.Bar!T(x)</c> (which is 
		/// is structured <c>((((global::Foo)!int).Bar)!T)(x)</c>) is <c>Bar</c>. 
		/// </remarks>
		public static LNode KeyNameComponentOf(LNode name)
		{
			// So if #of, get first arg (which cannot itself be #of), then if @`.`, get second arg.
			// If it's a call, note that we have to check for #of and @`.` BEFORE stripping off the args.
			if (name.CallsMin(S.Of, 1))
				name = name.Args[0];
			if (name.CallsMin(S.Dot, 1))
				name = name.Args.Last;
			if (name.IsCall)
				return KeyNameComponentOf(name.Target);
			return name;
		}
Esempio n. 13
0
		void WhereClausesOpt(ref LNode name)
		{
			TokenType la0;
			#line 1163 "EcsParserGrammar.les"
			var list = new BMultiMap<Symbol,LNode>();
			#line default
			// Line 1164: (WhereClause)*
			for (;;) {
				la0 = LA0;
				if (la0 == TT.ContextualKeyword)
					list.Add(WhereClause());
				else
					break;
			}
			#line 1165 "EcsParserGrammar.les"
			if ((list.Count != 0)) {
				if ((!name.CallsMin(S.Of, 2))) {
					Error("'{0}' is not generic and cannot use 'where' clauses.", name.ToString());
				} else {
					var tparams = name.Args.ToRWList();
					for (int i = 1; i < tparams.Count; i++) {
						var wheres = list[TParamSymbol(tparams[i])];
						tparams[i] = tparams[i].PlusAttrs(wheres);
						wheres.Clear();
					}
					name = name.WithArgs(tparams.ToRVList());
					if ((list.Count > 0)) {
						Error(list[0].Value, "There is no type parameter named '{0}'", list[0].Key);
					}
				}
			}
			#line default
		}
 LNode EliminateSequenceExpressionsInExecStmt(LNode stmt)
 {
     {
         LNode         block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type;
         VList <LNode> attrs, incs, inits;
         if (stmt.Calls(CodeSymbols.Braces))
         {
             return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false)));
         }
         else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces))
         {
             return(ProcessBlockCallStmt(stmt, 1));
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null)
         {
             init  = EliminateSequenceExpressionsInExecStmt(init);
             block = EliminateSequenceExpressionsInChildStmt(block);
             if (init.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement));
             }
             else
             {
                 return(stmt.WithArgChanged(1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null)
         {
             cond  = BubbleUpBlocks(cond);
             block = EliminateSequenceExpressionsInChildStmt(block);
             if (cond.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement))));
             }
             else
             {
                 return(stmt.WithArgChanged(1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null)
         {
             block = EliminateSequenceExpressionsInChildStmt(block);
             cond  = BubbleUpBlocks(cond);
             if (cond.CallsMin(__numrunSequence, 1))
             {
                 var continue_N = F.Id(NextTempName(Context, "continue_"));
                 var bodyStmts  = block.AsList(S.Braces);
                 bodyStmts.AddRange(cond.Args.WithoutLast(1));
                 bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator));
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement))));
             }
             else
             {
                 return(stmt.WithArgChanged(0, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null)
         {
             inits = stmt.Args[0].Args;
             incs  = stmt.Args[2].Args;
             return(ESEInForLoop(stmt, attrs, inits, cond, incs, block));
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null)
         {
             block      = EliminateSequenceExpressionsInChildStmt(block);
             collection = BubbleUpBlocks(collection);
             if (collection.CallsMin(__numrunSequence, 1))
             {
                 return(LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement));
             }
             else
             {
                 return(stmt.WithArgChanged(stmt.Args.Count - 1, block));
             }
         }
         else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null)
         {
             var initValue_apos = BubbleUpBlocks(initValue);
             if (initValue_apos != initValue)
             {
                 {
                     LNode         last;
                     VList <LNode> stmts;
                     if (initValue_apos.CallsMin((Symbol)"#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null)
                     {
                         stmts = initValue_apos.Args.WithoutLast(1);
                         return(LNode.Call((Symbol)"#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last)))))));
                     }
                     else
                     {
                         return(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos)))));
                     }
                 }
             }
         }
         else if (stmt.CallsMin(S.Try, 2))
         {
             return(ESEInTryStmt(stmt));
         }
         else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces))
         {
             return(ProcessBlockCallStmt(stmt, stmt.ArgCount - 1));
         }
         else
         {
             // Ordinary expression statement
             return(BubbleUpBlocks(stmt, stmtContext: true));
         }
     }
     return(stmt);
 }
Esempio n. 15
0
        public SPResult AutoPrintMethodDefinition(Ambiguity flags)
        {
            // S.Fn, S.Delegate: #fn(#int32, Square, #(int x), { return x * x; });
            if (EcsValidators.MethodDefinitionKind(_n, true, Pedantics) == null)
            {
                return(SPResult.Fail);
            }

            LNode retType = _n.Args[0], name = _n.Args[1];
            LNode args          = _n.Args[2];
            LNode body          = _n.Args[3, null];
            bool  isConstructor = _n.Name == S.Constructor;
            bool  isDestructor  = !isConstructor && name.Calls(S._Destruct, 1);

            LNode firstStmt = null;

            if (isConstructor && body != null && body.CallsMin(S.Braces, 1))
            {
                // Detect ": this(...)" or ": base(...)"
                firstStmt = body.Args[0];
                if (!CallsWPAIH(firstStmt, S.This) &&
                    !CallsWPAIH(firstStmt, S.Base))
                {
                    firstStmt = null;
                }
            }

            if (!AllowConstructorAmbiguity)
            {
                if (isDestructor && _spaceName == S.Fn)
                {
                    // When destructor syntax is ambiguous, use prefix notation.
                    return(SPResult.Fail);
                }
                else if (isConstructor && firstStmt == null)
                {
                    // When constructor syntax is ambiguous, use prefix notation.
                    if (name.IsIdNamed(S.This))
                    {
                        if (_spaceName == S.Fn)
                        {
                            return(SPResult.Fail);
                        }
                    }
                    else if (!name.IsIdNamed(_spaceName))
                    {
                        return(SPResult.Fail);
                    }
                }
            }

            // A cast operator with the structure: #fn(Foo, operator`#cast`, #(...))
            // can be printed in a special format: operator Foo(...);
            bool isCastOperator = (name.Name == S.Cast && name.AttrNamed(S.TriviaUseOperatorKeyword) != null);

            var ifClause = PrintTypeAndName(isConstructor || isDestructor, isCastOperator,
                                            isConstructor && !name.IsIdNamed(S.This) ? AttrStyle.IsConstructor : AttrStyle.IsDefinition);

            PrintArgList(args.Args, ParenFor.MethodDecl, Ambiguity.AllowUnassignedVarDecl, OmitMissingArguments);

            PrintWhereClauses(name);

            // If this is a constructor where the first statement is this(...) or
            // base(...), we must change the notation to ": this(...) {...}" as
            // required in plain C#
            if (firstStmt != null)
            {
                using (Indented) {
                    if (!Newline(NewlineOpt.BeforeConstructorColon))
                    {
                        Space(SpaceOpt.BeforeConstructorColon);
                    }
                    WriteThenSpace(':', SpaceOpt.AfterColon);
                    PrintExpr(firstStmt, StartExpr, Ambiguity.NoBracedBlock);
                }
            }

            return(AutoPrintBodyOfMethodOrProperty(body, ifClause, firstStmt != null));
        }
Esempio n. 16
0
        private static void ApplyRuleOptions(ref LNode node, Rule rule, IMacroContext context)
        {
            node = node.WithAttrs(node.Attrs.WhereSelect(attr => {
                if (attr.ArgCount > 1)
                {
                    return(attr);
                }
                LNode key    = attr.Target ?? attr;
                object value = null;
                if (attr.ArgCount == 1)
                {
                    value = attr.Args[0].Value;
                }
                switch (key.Name.Name)
                {
                case "fullLLk":
                case "FullLLk":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.FullLLk = v);
                    break;

                case "#private":
                case "private":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsPrivate = v);
                    return(attr);                            // keep attribute

                case "#public":
                case "#internal":
                case "#protected":
                case "public":
                case "internal":
                case "protected":                            // this is before macros run, and non-special names are used in LES
                    rule.IsPrivate = false;
                    return(attr);                            // keep attribute

                case "token":
                case "Token":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsToken = v);
                    break;

                case "start":
                case "Start":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsStartingRule = v);
                    break;

                case "#extern":
                case "extern":
                case "Extern":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsExternal = v);
                    break;

                case "#inline":
                case "inline":
                case "Inline":
                case "#fragment":
                case "fragment":
                    SetOption <bool>(context, key, value ?? G.BoxedTrue, v => rule.IsInline = v);
                    break;

                case "k":
                case "K":
                case "LL":
                    SetOption <int>(context, key, value, k => rule.K = k);
                    break;

                case "recognizer":
                case "Recognizer":
                    LNode sig = attr.Args[0, null];
                    if (sig != null)
                    {
                        // Invoke macros here so that LES code like "public fn Foo()::bool"
                        // is transformed into a method signature.
                        sig = context.PreProcess(sig.UnwrapBraces());
                    }
                    if (sig != null && sig.CallsMin(S.Fn, 3))
                    {
                        sig = sig.WithoutAttrNamed(S.TriviaAppendStatement);                                 // prevent weird-looking output
                        rule.MakeRecognizerVersion(sig).TryWrapperNeeded();
                    }
                    else
                    {
                        context.Sink.Error(sig, "'recognizer' expects one parameter, a method signature.");
                    }
                    break;

                default:
                    return(attr);
                }
                return(NoValue.Value);
            }).ToArray());
        }
Esempio n. 17
0
		/// <summary>Given a complex name such as <c>global::Foo&lt;int>.Bar&lt;T></c>,
		/// this method identifies the base name component, which in this example 
		/// is Bar. This is used, for example, to identify the expected name for
		/// a constructor based on the class name, e.g. <c>Foo&lt;T></c> => Foo.</summary>
		/// <remarks>It is not verified that name is a complex identifier. There
		/// is no error detection but in some cases an empty name may be returned, 
		/// e.g. for input like <c>Foo."Hello"</c>.</remarks>
		public static Symbol KeyNameComponentOf(LNode name)
		{
			// global::Foo<int>.Bar<T> is structured (((global::Foo)<int>).Bar)<T>
			// So if #of, get first arg (which cannot itself be #of), then if #dot, 
			// get second arg.
			if (name.CallsMin(S.Of, 1))
				name = name.Args[0];
			if (name.CallsMin(S.Dot, 1))
				name = name.Args.Last;
			return name.Name;
		}
			public LNode EliminateSequenceExpressions(LNode stmt, bool isDeclContext)
			{
				LNode retType, name, argList, bases, body, initValue;
				if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null) {
					// Space definition: class, struct, etc.
					return body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true));
				} else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null) {
					// Method definition
					return body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType));
				} else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue)) {
					// Property definition
					stmt = stmt.WithArgChanged(3, 
					body.WithArgs(part => {
						if (part.ArgCount == 1 && part[0].Calls(S.Braces))
							part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false));
						return part;
					}));
					if (initValue != null) {
						var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
						if (initMethod != null) {
							stmt = stmt.WithArgChanged(4, initValue);
							return LNode.Call((Symbol) "#runSequence", LNode.List(stmt, initMethod));
						}
					}
					return stmt;
				} else if (stmt.Calls(CodeSymbols.Braces)) {
					return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext));
				} else if (!isDeclContext) {
					return EliminateSequenceExpressionsInExecStmt(stmt);
				} else if (stmt.CallsMin(S.Var, 2)) {
					// Eliminate blocks from field member
					var results = new List<LNode> { 
						stmt
					};
					var vars = stmt.Args;
					var varType = vars[0];
					for (int i = 1; i < vars.Count; i++) {
						var @var = vars[i];
						if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null) {
							var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
							if (initMethod != null) {
								results.Add(initMethod);
								vars[i] = vars[i].WithArgChanged(1, initValue);
							}
						}
					}
					if (results.Count > 1) {
						results[0] = stmt.WithArgs(vars);
						return LNode.List(results).AsLNode(__numrunSequence);
					}
					return stmt;
				} else
					return stmt;
			}
Esempio n. 19
0
		object AutoNodeToPred(LNode expr, Context ctx)
		{
			if (expr.CallsMin(S.Braces, 0))
				return RemoveBraces(expr);
			return NodeToPred(expr, ctx);
		}
			// Creates a temporary for an LValue (left side of `=`, or `ref` parameter)
			// e.g. f(x).Foo becomes f(x_N).Foo, and `var x_N = x` is added to `stmtSequence`,
			// where N is a unique integer for the temporary variable.
			LNode MaybeCreateTemporaryForLValue(LNode expr, ref VList<LNode> stmtSequence)
			{
				{
					LNode _, lhs;
					if (expr.Calls(CodeSymbols.Dot, 2) && (lhs = expr.Args[0]) != null || expr.CallsMin(CodeSymbols.Of, 1) && (lhs = expr.Args[0]) != null)
						return expr.WithArgChanged(0, MaybeCreateTemporaryForLValue(lhs, ref stmtSequence));
					else if ((_ = expr) != null && !_.IsCall)
						return expr;
					else {
						var args = expr.Args.ToWList();
						int i = 0;
						if (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1)) {
							// Consider foo[i]. We cannot always store `foo` in a temporary, as
							// this may change the code's behavior in case `foo` is a struct.
							i = 1;
						}
						for (; i < args.Count; i++) {
							if (!args[i].IsLiteral && !args[i].Attrs.Contains(_trivia_isTmpVar)) {
								LNode tmpVarName;
								stmtSequence.Add(TempVarDecl(Context, args[i], out tmpVarName));
								args[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
							}
						}
						return expr.WithArgs(args.ToVList());
					}
				}
			}
Esempio n. 21
0
        // Decides whether to add a "break" at the end of a switch case.
        internal protected static bool EndMayBeReachable(LNode stmt)
        {
            // The goal of this code is to avoid the dreaded compiler warning
            // "Unreachable code detected". We're conservative, to avoid a compiler
            // error about a missing "break". This is just a heuristic since we
            // don't have access to proper reachability analysis.
            if (stmt.CallsMin(S.Braces, 1))
            {
                return(EndMayBeReachable(stmt.Args.Last));
            }
            if (!stmt.HasSpecialName)
            {
                return(true);
            }

            if (stmt.Calls(S.Goto, 1))
            {
                return(false);
            }
            else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break))
            {
                return(false);
            }
            else if (stmt.Calls(S.Return))
            {
                return(false);
            }
            else if (stmt.Calls(S.GotoCase, 1))
            {
                return(false);
            }

            LNode body;

            if (stmt.Calls(S.If, 2))
            {
                return(true);
            }
            else if (stmt.Calls(S.If, 3))
            {
                return(EndMayBeReachable(stmt.Args[1]) ||
                       EndMayBeReachable(stmt.Args[2]));
            }
            else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2))
            {
                // for a switch statement, assume it exits normally if a break
                // statement is the last statement of any of the cases, or if
                // there is no "default" case.
                bool beforeCase     = true;
                bool hasDefaultCase = false;
                for (int i = body.ArgCount - 1; i > 0; i--)
                {
                    var substmt = body.Args[i];
                    if (beforeCase && substmt.Calls(S.Break))
                    {
                        return(true);
                    }
                    if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default))
                    {
                        hasDefaultCase = beforeCase = true;
                    }
                    else
                    {
                        beforeCase = substmt.Calls(S.Case);
                    }
                }
                return(hasDefaultCase == false);
            }
            else if (stmt.Calls(S.For) || stmt.Calls(S.While) || stmt.Calls(S.DoWhile))
            {
                return(true);
            }
            else if (stmt.CallsMin(S.Try, 1))
            {
                return(EndMayBeReachable(stmt.Args[0]));
            }
            else if (stmt.ArgCount >= 1)
            {
                Debug.Assert(stmt.HasSpecialName);
                return(EndMayBeReachable(stmt.Args.Last));
            }
            return(true);
        }
Esempio n. 22
0
		/// <summary>Given a complex name such as <c>global::Foo&lt;int>.Bar&lt;T></c>,
		/// this method identifies the base name component, which in this example 
		/// is Bar. This is used, for example, to identify the expected name for
		/// a constructor based on the class name, e.g. <c>Foo&lt;T></c> => Foo.</summary>
		/// <remarks>It is not verified that name is a complex identifier. There
		/// is no error detection but in some cases an empty name may be returned, 
		/// e.g. for input like <c>Foo."Hello"</c>.</remarks>
		public static Symbol KeyNameComponentOf(LNode name)
		{
			if (name == null)
				return null;
			// global::Foo<int>.Bar<T> is structured (global::(Foo<int>)).(Bar<T>)
			// so if `'.` or `'::` get second arg, then if #of, get first arg.
			if (name.CallsMin(S.Dot, 1) || name.Calls(S.ColonColon, 2))
				name = name.Args.Last;
			if (name.CallsMin(S.Of, 1))
				name = name.Args[0];
			if (name.IsCall)
				return KeyNameComponentOf(name.Target);
			return name.Name;
		}
Esempio n. 23
0
		internal static bool IsEventDefinition(LNode node, out LNode type, out LNode name, out LNode body, Pedantics p)
		{
			// Syntax should either be
			//   #event(EventHandler, Click, {...}), or
			//   #event(EventHandler, #(Click, DoubleClick)),
			// but we can also parse
			//   #event(EventHandler, #(Click, DoubleClick), {...})
			type = name = body = null;
			int argCount = node.ArgCount;
			if (!CallsMinWPAIH(node, S.Event, 2, p) || argCount > 3)
				return false;

			type = node.Args[0];
			name = node.Args[1];
			if (!IsComplexIdentifier(type, ICI.Default, p))
				return false;
			if (!IsComplexIdentifier(name, ICI.Default, p) && 
				!(name.CallsMin(S.AltList, 1) && name.Args.All(a => IsComplexIdentifier(a, ICI.Default, p))))
				return false;

			if (argCount == 3) {
				body = node.Args[2];
				return CallsWPAIH(body, S.Braces, p) || CallsWPAIH(body, S.Forward, p);
			} else
				return argCount == 2;
		}
Esempio n. 24
0
		internal static bool CallsMinWPAIH(LNode self, Symbol name, int argCount, Pedantics p)
		{
			return self.CallsMin(name, argCount) && HasSimpleHeadWPA(self, p);
		}
Esempio n. 25
0
		// quote @{ Hope.For(777, $cash) } => F.Call(F.Dot(F.Id("Hope"), F.Id("For")), F.Literal(777), cash)
		// declare_symbols @@Foo @@Bar {...} (braces optional, invoke replace_code)
		// replace_code (IntSet.Parse($s) \with ParseSet($s), IntSet \with HashSet!int) {...}
		// replace_code_after ($X($Y, -1) \with $X($Y, EOF)) {...}
		// with Foo.Bar {...} => replace_code (.($x) \with Foo.Bar.$x) {...}
		// include_here "../Util/Util.les"
		// specialize $T \in (int, float, double) { def Square!$T(T x) { x*x; }; class Foo!($T,U) {}; }
		// run_macros (specialize $T \in (int, float)) (replace Xyz \with Zyx) { ... }
		// Bob.Hair?.Brush()
		// cons Point(public field X::int, public field Y::int) { }
		// def SetX(public X::int) { }
		// prop X::int (public field _x) { get; set; };
		// def DoSomething(required X::string) { };
		// public override def ToString()::string ==> _obj;
		// forward_to _obj { def ToString()::string; def GetHashCode()::int; };
		// foo ??= Foo();
		// x - 0.5;
		// x in (1, 2, 3);
		// $"The value is {Value,-10:C}." => string.Format("The value is {0,-10:C}", Value)
		// save_and_restore _foo { Foo(_foo = true); } => var tmp17 = _foo; try { Foo(_foo = true); } finally { _foo = tmp17; }

		/// <summary>Given a statement, this method attempts to decide if the 
		/// immediately following statement (if any) is reachable.</summary>
		/// <returns>true if reachable/unsure, false if definitely unreachable.</returns>
		/// <remarks>
		/// The goal of this code is to avoid the dreaded compiler warning 
		/// "Unreachable code detected". This is just a heuristic since we 
		/// don't have access to proper reachability analysis. In fact, it's
		/// no doubt buggy.
		/// </remarks>
		public static bool NextStatementMayBeReachable(LNode stmt)
		{
			if (stmt.CallsMin(S.Braces, 1))
				return NextStatementMayBeReachable(stmt.Args.Last);
			if (!stmt.HasSpecialName)
				return true;

			if (stmt.Calls(S.Goto, 1))
				return false;
			else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break))
				return false;
			else if (stmt.Calls(S.Return))
				return false;
			else if (stmt.Calls(S.GotoCase, 1))
				return false;

			bool isFor;
			LNode body;
			if (stmt.Calls(S.If, 2))
				return true;
			else if (stmt.Calls(S.If, 3))
			{
				var r1 = NextStatementMayBeReachable(stmt.Args[1]);
				var r2 = NextStatementMayBeReachable(stmt.Args[2]);
				return r1 || r2;
			}
			else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2))
			{
				// for a switch statement, assume it exits normally if a break 
				// statement is the last statement of any of the cases, or if
				// there is no "default" case.
				bool beforeCase = true;
				bool hasDefaultCase = false;
				foreach (var substmt in body.Args.ToFVList())
				{
					if (beforeCase && substmt.Calls(S.Break))
						return true;
					if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default))
						hasDefaultCase = beforeCase = true;
					else
						beforeCase = substmt.Calls(S.Case);
				}
				return hasDefaultCase == false;
			}
			else if ((isFor = stmt.Calls(S.For, 4)) || stmt.Calls(S.While, 2) || stmt.Calls(S.DoWhile, 2))
			{   // Infinite loop?
				var cond = stmt.Args[isFor ? 1 : 0];
				if (cond.IsIdNamed(S.Missing) || true.Equals(cond.Value))
					return true; // ok, I don't know what to do
				return true;
			}
			else if (stmt.CallsMin(S.Try, 1))
			{
				return NextStatementMayBeReachable(stmt.Args[0]);
			}
			else if (stmt.ArgCount >= 1)
			{
				Debug.Assert(stmt.HasSpecialName);
				return NextStatementMayBeReachable(stmt.Args.Last);
			}
			return true;
		}
			// Bubbles up a call. The returned pair consists of 
			// 1. A sequence of statements to run before the call
			// 2. The call with all (outer) #runSequences removed
			Pair<VList<LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
			{
				var target = expr.Target;
				var args = expr.Args;
				var combinedSequence = LNode.List();
			
				// Bubbe up target
				target = BubbleUpBlocks(target);
				if (target.CallsMin(__numrunSequence, 1)) {
					combinedSequence = target.Args.WithoutLast(1);
					expr = expr.WithTarget(target.Args.Last);
				}
			
				// Bubble up each argument
				var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name);
				if (isAssignment) {
					LNode lhs = BubbleUpBlocks(expr.Args[0]);
					LNode rhs = BubbleUpBlocks(expr.Args[1]);
					args = LNode.List(lhs, rhs);
				} else {	// most common case
					args = args.SmartSelect(arg => BubbleUpBlocks(arg));
				}
			
				int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1));
				if (lastRunSeq >= 0) {
					// last index of #runSequence that is not marked pure
					int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a => 
					a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null);
				
					if (lastRunSeq > 0 && 
					(args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark)))
					{
						Context.Sink.Error(target, 
						"#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect.");
					}
				
					var argsW = args.ToList();
					for (int i = 0; i <= lastRunSeq; i++) {
						LNode arg = argsW[i];
						if (!arg.IsLiteral) {
							if (arg.CallsMin(__numrunSequence, 1)) {
								combinedSequence.AddRange(arg.Args.WithoutLast(1));
								argsW[i] = arg = arg.Args.Last;
							}
							if (i < lastRunSeqImpure) {
								if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1))) {
									// Consider foo[#runSequence(f(), i)]. In case this appears in
									// an lvalue context and `foo` is a struct, we cannot store `foo` in 
									// a temporary, as this may silently change the code's behavior.
									// Better to take the risk of evaluating `foo` after `f()`.
								 } else {
									if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out)))
										argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence);
									else {
										// Create a temporary variable to hold this argument
										LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName);
										combinedSequence.Add(tmpVarDecl);
										argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
									}
								}
							}
						}
					}
				
					expr = expr.WithArgs(LNode.List(argsW));
				}
			
				return Pair.Create(combinedSequence, expr);
			}
Esempio n. 27
0
        // quote @{ Hope.For(777, $cash) } => F.Call(F.Dot(F.Id("Hope"), F.Id("For")), F.Literal(777), cash)
        // declare_symbols @@Foo @@Bar {...} (braces optional, invoke replace_code)
        // replace_code (IntSet.Parse($s) \with ParseSet($s), IntSet \with HashSet!int) {...}
        // replace_code_after ($X($Y, -1) \with $X($Y, EOF)) {...}
        // with Foo.Bar {...} => replace_code (.($x) \with Foo.Bar.$x) {...}
        // include_here "../Util/Util.les"
        // specialize $T \in (int, float, double) { def Square!$T(T x) { x*x; }; class Foo!($T,U) {}; }
        // run_macros (specialize $T \in (int, float)) (replace Xyz \with Zyx) { ... }
        // Bob.Hair?.Brush()
        // cons Point(public field X::int, public field Y::int) { }
        // def SetX(public X::int) { }
        // prop X::int (public field _x) { get; set; };
        // def DoSomething(required X::string) { };
        // public override def ToString()::string ==> _obj;
        // forward_to _obj { def ToString()::string; def GetHashCode()::int; };
        // foo ??= Foo();
        // x - 0.5;
        // x in (1, 2, 3);
        // $"The value is {Value,-10:C}." => string.Format("The value is {0,-10:C}", Value)
        // save_and_restore _foo { Foo(_foo = true); } => var tmp17 = _foo; try { Foo(_foo = true); } finally { _foo = tmp17; }

        /// <summary>Given a statement, this method attempts to decide if the
        /// immediately following statement (if any) is reachable.</summary>
        /// <returns>true if reachable/unsure, false if definitely unreachable.</returns>
        /// <remarks>
        /// The goal of this code is to avoid the dreaded compiler warning
        /// "Unreachable code detected". This is just a heuristic since we
        /// don't have access to proper reachability analysis. In fact, it's
        /// no doubt buggy.
        /// </remarks>
        public static bool NextStatementMayBeReachable(LNode stmt)
        {
            if (stmt.CallsMin(S.Braces, 1))
            {
                return(NextStatementMayBeReachable(stmt.Args.Last));
            }
            if (!stmt.HasSpecialName)
            {
                return(true);
            }

            if (stmt.Calls(S.Goto, 1))
            {
                return(false);
            }
            else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break))
            {
                return(false);
            }
            else if (stmt.Calls(S.Return))
            {
                return(false);
            }
            else if (stmt.Calls(S.GotoCase, 1))
            {
                return(false);
            }

            bool  isFor;
            LNode body;

            if (stmt.Calls(S.If, 2))
            {
                return(true);
            }
            else if (stmt.Calls(S.If, 3))
            {
                var r1 = NextStatementMayBeReachable(stmt.Args[1]);
                var r2 = NextStatementMayBeReachable(stmt.Args[2]);
                return(r1 || r2);
            }
            else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2))
            {
                // for a switch statement, assume it exits normally if a break
                // statement is the last statement of any of the cases, or if
                // there is no "default" case.
                bool beforeCase     = true;
                bool hasDefaultCase = false;
                foreach (var substmt in body.Args.ToFVList())
                {
                    if (beforeCase && substmt.Calls(S.Break))
                    {
                        return(true);
                    }
                    if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default))
                    {
                        hasDefaultCase = beforeCase = true;
                    }
                    else
                    {
                        beforeCase = substmt.Calls(S.Case);
                    }
                }
                return(hasDefaultCase == false);
            }
            else if ((isFor = stmt.Calls(S.For, 4)) || stmt.Calls(S.While, 2) || stmt.Calls(S.DoWhile, 2))
            {               // Infinite loop?
                var cond = stmt.Args[isFor ? 1 : 0];
                if (cond.IsIdNamed(S.Missing) || true.Equals(cond.Value))
                {
                    return(true);                    // ok, I don't know what to do
                }
                return(true);
            }
            else if (stmt.CallsMin(S.Try, 1))
            {
                return(NextStatementMayBeReachable(stmt.Args[0]));
            }
            else if (stmt.ArgCount >= 1)
            {
                Debug.Assert(stmt.HasSpecialName);
                return(NextStatementMayBeReachable(stmt.Args.Last));
            }
            return(true);
        }
Esempio n. 28
0
 internal static bool CallsMinWPAIH(LNode self, Symbol name, int argCount, Pedantics p)
 {
     return(self.CallsMin(name, argCount) && HasSimpleHeadWPA(self, p));
 }
Esempio n. 29
0
		// Decides whether to add a "break" at the end of a switch case.
		internal protected static bool EndMayBeReachable(LNode stmt)
		{
			// The goal of this code is to avoid the dreaded compiler warning 
			// "Unreachable code detected". We're conservative, to avoid a compiler 
			// error about a missing "break". This is just a heuristic since we 
			// don't have access to proper reachability analysis.
			if (stmt.CallsMin(S.Braces, 1))
				return EndMayBeReachable(stmt.Args.Last);
			if (!stmt.HasSpecialName)
				return true;

			if (stmt.Calls(S.Goto, 1))
				return false;
			else if (stmt.Calls(S.Continue) || stmt.Calls(S.Break))
				return false;
			else if (stmt.Calls(S.Return))
				return false;
			else if (stmt.Calls(S.GotoCase, 1))
				return false;

			LNode body;
			if (stmt.Calls(S.If, 2))
				return true;
			else if (stmt.Calls(S.If, 3))
			{
				return EndMayBeReachable(stmt.Args[1])
					|| EndMayBeReachable(stmt.Args[2]);
			}
			else if (stmt.CallsMin(S.Switch, 2) && (body = stmt.Args[1]).CallsMin(S.Braces, 2))
			{
				// for a switch statement, assume it exits normally if a break 
				// statement is the last statement of any of the cases, or if
				// there is no "default" case.
				bool beforeCase = true;
				bool hasDefaultCase = false;
				for (int i = body.ArgCount - 1; i > 0; i--)
				{
					var substmt = body.Args[i];
					if (beforeCase && substmt.Calls(S.Break))
						return true;
					if (substmt.Calls(S.Label, 1) && substmt.Args[0].IsIdNamed(S.Default))
						hasDefaultCase = beforeCase = true;
					else
						beforeCase = substmt.Calls(S.Case);
				}
				return hasDefaultCase == false;
			}
			else if (stmt.Calls(S.For) || stmt.Calls(S.While) || stmt.Calls(S.DoWhile))
			{
				return true;
			}
			else if (stmt.CallsMin(S.Try, 1))
			{
				return EndMayBeReachable(stmt.Args[0]);
			}
			else if (stmt.ArgCount >= 1)
			{
				Debug.Assert(stmt.HasSpecialName);
				return EndMayBeReachable(stmt.Args.Last);
			}
			return true;
		}
            // Bubbles up a call. The returned pair consists of
            // 1. A sequence of statements to run before the call
            // 2. The call with all (outer) #runSequences removed
            Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
            {
                var target           = expr.Target;
                var args             = expr.Args;
                var combinedSequence = LNode.List();

                // Bubbe up target
                target = BubbleUpBlocks(target);
                if (target.CallsMin(__numrunSequence, 1))
                {
                    combinedSequence = target.Args.WithoutLast(1);
                    expr             = expr.WithTarget(target.Args.Last);
                }

                // Bubble up each argument
                var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name);

                if (isAssignment)
                {
                    LNode lhs = BubbleUpBlocks(expr.Args[0]);
                    LNode rhs = BubbleUpBlocks(expr.Args[1]);
                    args = LNode.List(lhs, rhs);
                }
                else                            // most common case
                {
                    args = args.SmartSelect(arg => BubbleUpBlocks(arg));
                }

                int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1));

                if (lastRunSeq >= 0)
                {
                    // last index of #runSequence that is not marked pure
                    int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a =>
                                                                                     a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null);

                    if (lastRunSeq > 0 &&
                        (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark)))
                    {
                        Context.Sink.Error(target,
                                           "#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect.");
                    }

                    var argsW = args.ToList();
                    for (int i = 0; i <= lastRunSeq; i++)
                    {
                        LNode arg = argsW[i];
                        if (!arg.IsLiteral)
                        {
                            if (arg.CallsMin(__numrunSequence, 1))
                            {
                                combinedSequence.AddRange(arg.Args.WithoutLast(1));
                                argsW[i] = arg = arg.Args.Last;
                            }
                            if (i < lastRunSeqImpure)
                            {
                                if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1)))
                                {
                                    // Consider foo[#runSequence(f(), i)]. In case this appears in
                                    // an lvalue context and `foo` is a struct, we cannot store `foo` in
                                    // a temporary, as this may silently change the code's behavior.
                                    // Better to take the risk of evaluating `foo` after `f()`.
                                }
                                else
                                {
                                    if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out)))
                                    {
                                        argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence);
                                    }
                                    else
                                    {
                                        // Create a temporary variable to hold this argument
                                        LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName);
                                        combinedSequence.Add(tmpVarDecl);
                                        argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
                                    }
                                }
                            }
                        }
                    }

                    expr = expr.WithArgs(LNode.List(argsW));
                }

                return(Pair.Create(combinedSequence, expr));
            }
            public LNode EliminateSequenceExpressions(LNode stmt, bool isDeclContext)
            {
                LNode retType, name, argList, bases, body, initValue;

                if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null)
                {
                    // Space definition: class, struct, etc.
                    return(body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true)));
                }
                else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null)
                {
                    // Method definition
                    return(body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType)));
                }
                else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue))
                {
                    // Property definition
                    stmt = stmt.WithArgChanged(3,
                                               body.WithArgs(part => {
                        if (part.ArgCount == 1 && part[0].Calls(S.Braces))
                        {
                            part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false));
                        }
                        return(part);
                    }));
                    if (initValue != null)
                    {
                        var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
                        if (initMethod != null)
                        {
                            stmt = stmt.WithArgChanged(4, initValue);
                            return(LNode.Call((Symbol)"#runSequence", LNode.List(stmt, initMethod)));
                        }
                    }
                    return(stmt);
                }
                else if (stmt.Calls(CodeSymbols.Braces))
                {
                    return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext)));
                }
                else if (!isDeclContext)
                {
                    return(EliminateSequenceExpressionsInExecStmt(stmt));
                }
                else if (stmt.CallsMin(S.Var, 2))
                {
                    // Eliminate blocks from field member
                    var results = new List <LNode> {
                        stmt
                    };
                    var vars    = stmt.Args;
                    var varType = vars[0];
                    for (int i = 1; i < vars.Count; i++)
                    {
                        var @var = vars[i];
                        if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null)
                        {
                            var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
                            if (initMethod != null)
                            {
                                results.Add(initMethod);
                                vars[i] = vars[i].WithArgChanged(1, initValue);
                            }
                        }
                    }
                    if (results.Count > 1)
                    {
                        results[0] = stmt.WithArgs(vars);
                        return(LNode.List(results).AsLNode(__numrunSequence));
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt);
                }
            }
Esempio n. 32
0
        public SPResult AutoPrintSpaceDefinition(Ambiguity flags)
        {
            // Spaces: S.Struct, S.Class, S.Trait, S.Enum, S.Alias, S.Interface, S.Namespace
            var kind = EcsValidators.SpaceDefinitionKind(_n, Pedantics);

            if (kind == null)
            {
                return(SPResult.Fail);
            }

            var ifClause = GetIfClause();

            int ai;
            var old_n = _n;

            if (kind == S.Alias && (ai = _n.Attrs.IndexWhere(a => a.IsIdNamed(S.FilePrivate))) > -1)
            {
                // Cause "[#filePrivate] #alias x = y;" to print as "using x = y;"
                _n   = _n.WithAttrs(_n.Attrs.RemoveAt(ai)).WithTarget(S.UsingStmt);
                kind = S.UsingStmt;
            }

            G.Verify(0 == PrintAttrs(StartStmt, AttrStyle.IsDefinition, flags, ifClause));

            LNode name = _n.Args[0], bases = _n.Args[1], body = _n.Args[2, null];

            WriteOperatorName(kind);

            _n = old_n;

            _out.Space();
            PrintExpr(name, ContinueExpr, Ambiguity.InDefinitionName);

            if (bases.CallsMin(S.AltList, 1))
            {
                Space(SpaceOpt.BeforeBaseListColon);
                WriteThenSpace(':', SpaceOpt.AfterColon);
                for (int i = 0, c = bases.ArgCount; i < c; i++)
                {
                    if (i != 0)
                    {
                        WriteThenSpace(',', SpaceOpt.AfterComma);
                    }
                    PrintType(bases.Args[i], ContinueExpr);
                }
            }
            bool alias = name.Calls(S.Assign, 2);
            var  name2 = name;

            if (name2.Calls(S.Of) || (alias && (name2 = name.Args[0]).Calls(S.Of)))
            {
                PrintWhereClauses(name2);
            }

            AutoPrintIfClause(ifClause);

            if (body == null)
            {
                return(SPResult.NeedSemicolon);
            }

            if (kind == S.Enum)
            {
                PrintEnumBody(body);
            }
            else
            {
                PrintBracedBlock(body, NewlineOpt.BeforeSpaceDefBrace, false, KeyNameComponentOf(name));
            }
            return(SPResult.NeedSuffixTrivia);
        }
			/// Eliminates run sequence(s) in a field initializer expression.
			/// If any are found, a method is returned to encapsulate the 
			/// initialization code, e.g.
			///   expr on entry: Foo()::foo.x + foo.y
			///   return value:  static retType fieldName_initializer() {
			///                      var foo = Foo();
			///                      return foo.x + foo.y;
			///                  }
			///   expr on exit:  fieldName_initializer()
			LNode EliminateRunSeqFromInitializer(LNode retType, LNode fieldName, ref LNode expr)
			{
				expr = BubbleUpBlocks(expr);
				if (expr.CallsMin(__numrunSequence, 1)) {
					var statements = expr.Args.WithoutLast(1);
					var finalResult = expr.Args.Last;
				
					LNode methodName = F.Id(KeyNameComponentOf(fieldName).Name + "_initializer");
					expr = LNode.Call(methodName);
					return LNode.Call(LNode.List(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(retType, methodName, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(statements).Add(LNode.Call(CodeSymbols.Return, LNode.List(finalResult)))).SetStyle(NodeStyle.Statement)));
				} else
					return null;	// most common case
			}
Esempio n. 34
0
		// A definition identifier has the form Name or Name!(Id,$Id,...)
		// where Id is a simple identifier and Name is either a simple identifier 
		// or (if dots are allowed) a complex identifier with allowOf=false.
		public static bool IsDefinitionId(LNode id, bool allowDots)
		{
			var args = id.Args;
			if (id.CallsMin(S.Of, 1)) {
				if (!(allowDots ? IsComplexId(args[0], false) : args[0].IsId))
					return false;
				for (int i = 1; i < args.Count; i++)
					if (!(args[i].IsId || args[i].Calls(S.Substitute, 1) && args[i].Args[0].IsId))
						return false;
				return true;
			} else
				return allowDots ? IsComplexId(id, false) : id.IsId;
		}
			LNode EliminateSequenceExpressionsInExecStmt(LNode stmt)
			{
				{
					LNode block, collection, cond, init, initValue, loopVar, name, tmp_11, tmp_12, type;
					VList<LNode> attrs, incs, inits;
					if (stmt.Calls(CodeSymbols.Braces))
						return stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, false));
					else if (stmt.CallsMin(CodeSymbols.If, 1) || stmt.Calls(CodeSymbols.UsingStmt, 2) || stmt.Calls(CodeSymbols.Lock, 2) || stmt.Calls(CodeSymbols.Switch, 2) && stmt.Args[1].Calls(CodeSymbols.Braces))
						return ProcessBlockCallStmt(stmt, 1);
					else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Fixed, 2) && (init = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) {
						init = EliminateSequenceExpressionsInExecStmt(init);
						block = EliminateSequenceExpressionsInChildStmt(block);
						if (init.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(init.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.Fixed, LNode.List(init.Args.Last, block)))).SetStyle(NodeStyle.Statement);
						} else
							return stmt.WithArgChanged(1, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.While, 2) && (cond = stmt.Args[0]) != null && (block = stmt.Args[1]) != null) {
						cond = BubbleUpBlocks(cond);
						block = EliminateSequenceExpressionsInChildStmt(block);
						if (cond.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList), LNode.Missing, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(cond.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.If, LNode.List(cond.Args.Last, block, LNode.Call(CodeSymbols.Break))))).SetStyle(NodeStyle.Statement)));
						} else
							return stmt.WithArgChanged(1, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.DoWhile, 2) && (block = stmt.Args[0]) != null && (cond = stmt.Args[1]) != null) {
						block = EliminateSequenceExpressionsInChildStmt(block);
						cond = BubbleUpBlocks(cond);
						if (cond.CallsMin(__numrunSequence, 1)) {
							var continue_N = F.Id(NextTempName(Context, "continue_"));
							var bodyStmts = block.AsList(S.Braces);
							bodyStmts.AddRange(cond.Args.WithoutLast(1));
							bodyStmts.Add(LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, cond.Args.Last)).SetStyle(NodeStyle.Operator));
							return LNode.Call(LNode.List(attrs), CodeSymbols.For, LNode.List(LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id(CodeSymbols.Bool), LNode.Call(CodeSymbols.Assign, LNode.List(continue_N, LNode.Literal(true))))))), continue_N, LNode.Call(CodeSymbols.AltList), LNode.Call(CodeSymbols.Braces, LNode.List(bodyStmts)).SetStyle(NodeStyle.Statement)));
						} else
							return stmt.WithArgChanged(0, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.For, 4) && stmt.Args[0].Calls(CodeSymbols.AltList) && (cond = stmt.Args[1]) != null && stmt.Args[2].Calls(CodeSymbols.AltList) && (block = stmt.Args[3]) != null) {
						inits = stmt.Args[0].Args;
						incs = stmt.Args[2].Args;
						return ESEInForLoop(stmt, attrs, inits, cond, incs, block);
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.ForEach, 3) && (tmp_11 = stmt.Args[0]) != null && tmp_11.Calls(CodeSymbols.Var, 2) && (type = tmp_11.Args[0]) != null && (loopVar = tmp_11.Args[1]) != null && (collection = stmt.Args[1]) != null && (block = stmt.Args[2]) != null) {
						block = EliminateSequenceExpressionsInChildStmt(block);
						collection = BubbleUpBlocks(collection);
						if (collection.CallsMin(__numrunSequence, 1)) {
							return LNode.Call(LNode.List(attrs), CodeSymbols.Braces, LNode.List().AddRange(collection.Args.WithoutLast(1)).Add(LNode.Call(CodeSymbols.ForEach, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(type, loopVar)), collection.Args.Last, block)))).SetStyle(NodeStyle.Statement);
						} else {
							return stmt.WithArgChanged(stmt.Args.Count - 1, block);
						}
					} else if ((attrs = stmt.Attrs).IsEmpty | true && stmt.Calls(CodeSymbols.Var, 2) && (type = stmt.Args[0]) != null && (tmp_12 = stmt.Args[1]) != null && tmp_12.Calls(CodeSymbols.Assign, 2) && (name = tmp_12.Args[0]) != null && (initValue = tmp_12.Args[1]) != null) {
						var initValue_apos = BubbleUpBlocks(initValue);
						if (initValue_apos != initValue) {
							{
								LNode last;
								VList<LNode> stmts;
								if (initValue_apos.CallsMin((Symbol) "#runSequence", 1) && (last = initValue_apos.Args[initValue_apos.Args.Count - 1]) != null) {
									stmts = initValue_apos.Args.WithoutLast(1);
									return LNode.Call((Symbol) "#runSequence", LNode.List().AddRange(stmts).Add(LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, last))))));
								} else
									return LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(type, LNode.Call(CodeSymbols.Assign, LNode.List(name, initValue_apos))));
							}
						}
					} else if (stmt.CallsMin(S.Try, 2)) {
						return ESEInTryStmt(stmt);
					} else if (stmt.HasSpecialName && stmt.ArgCount >= 1 && stmt.Args.Last.Calls(S.Braces)) {
						return ProcessBlockCallStmt(stmt, stmt.ArgCount - 1);
					} else {
						// Ordinary expression statement
						return BubbleUpBlocks(stmt, stmtContext: true);
					}
				}
				return stmt;
			}
Esempio n. 36
0
		LNode CoreName(LNode complexId)
		{
			if (complexId.IsId)
				 return complexId;
			if (complexId.CallsMin(S.Of, 1))
				 return CoreName(complexId.Args[0]);
			if (complexId.CallsMin(S.Dot, 1))
				 return complexId.Args.Last;
			if (complexId.CallsMin(S.Substitute, 1))
				 return complexId;
			Debug.Fail("Not a complex identifier");
			return complexId.Target;
		}
Esempio n. 37
0
            public LNode EliminateBlockExprs(LNode stmt, bool isDeclContext)
            {
                LNode retType, name, argList, bases, body, initValue;

                if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(2, EliminateBlockExprs(body, true)));
                }
                else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(3, EliminateBlockExprs(body, false)));
                }
                else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue))
                {
                    stmt = stmt.WithArgChanged(3, EliminateBlockExprs(body, false));
                    if (initValue != null)
                    {
                        var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
                        if (initMethod != null)
                        {
                            stmt = stmt.WithArgChanged(4, initValue);
                            return(LNode.Call(CodeSymbols.Splice, LNode.List(stmt, initMethod)));
                        }
                    }
                    return(stmt);
                }
                else if (!isDeclContext)
                {
                    return(EliminateBlockExprsInExecStmt(stmt));
                }
                else if (stmt.CallsMin(S.Var, 2))
                {
                    var results = new List <LNode> {
                        stmt
                    };
                    var vars    = stmt.Args;
                    var varType = vars[0];
                    for (int i = 1; i < vars.Count; i++)
                    {
                        {
                            var tmp_1 = vars[i];
                            if (tmp_1.Calls(CodeSymbols.Assign, 2) && (name = tmp_1.Args[0]) != null && (initValue = tmp_1.Args[1]) != null)
                            {
                                var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
                                if (initMethod != null)
                                {
                                    results.Add(initMethod);
                                    vars[i] = vars[i].WithArgChanged(1, initValue);
                                }
                            }
                        }
                    }
                    if (results.Count > 1)
                    {
                        results[0] = stmt.WithArgs(vars);
                        return(LNode.List(results).AsLNode(S.Splice));
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt);
                }
            }
Esempio n. 38
0
            public AltType(VList <LNode> classAttrs, LNode typeName, VList <LNode> baseTypes, AltType parentType)
            {
                _classAttrs = classAttrs;
                TypeName    = typeName;
                BaseTypes   = baseTypes;
                ParentType  = parentType;
                //matchCode (TypeName) {
                //	case $stem<$(..a)>, $stem:
                //		_typeNameStem = stem;
                //		_genericArgs = a;
                //  default:
                //		_genericArgs = new WList<LNode>();
                //}
                {                       // Above matchCode expanded:
                    LNode         stem;
                    VList <LNode> a = default(VList <LNode>);
                    if (TypeName.CallsMin(CodeSymbols.Of, 1) && (stem = TypeName.Args[0]) != null && (a = new VList <LNode>(TypeName.Args.Slice(1))).IsEmpty | true || (stem = TypeName) != null)
                    {
                        _typeNameStem = stem;
                        _genericArgs  = a.ToWList();
                    }
                    else
                    {
                        _genericArgs = new WList <LNode>();
                    }
                }
                if (ParentType != null)
                {
                    BaseTypes.Insert(0, ParentType.TypeNameWithoutAttrs);

                    // Search for all 'where' clauses on the ParentType and make sure OUR generic args have them too.
                    bool changed = false;
                    for (int i = 0; i < _genericArgs.Count; i++)
                    {
                        var arg       = _genericArgs[i];
                        var parentArg = ParentType._genericArgs.FirstOrDefault(a => a.IsIdNamed(arg.Name));
                        if (parentArg != null)
                        {
                            var wheres       = new HashSet <LNode>(WhereTypes(arg));
                            int oldCount     = wheres.Count;
                            var parentWheres = WhereTypes(parentArg);
                            foreach (var where in parentWheres)
                            {
                                wheres.Add(where);
                            }
                            if (wheres.Count > oldCount)
                            {
                                arg = arg.WithAttrs(arg.Attrs.SmartWhere(a => !a.Calls(S.Where))
                                                    .Add(LNode.Call(S.Where, LNode.List(wheres))));
                                _genericArgs[i] = arg;
                                changed         = true;
                            }
                        }
                    }
                    if (changed)
                    {
                        TypeName = LNode.Call(CodeSymbols.Of, LNode.List().Add(_typeNameStem).AddRange(_genericArgs)).SetStyle(NodeStyle.Operator);
                    }
                }
                TypeNameWithoutAttrs = TypeName.Select(n => n.WithoutAttrs());
            }
Esempio n. 39
0
        private static void ApplyRuleOptions(ref LNode node, Rule rule, IMessageSink sink)
        {
            node = node.WithAttrs(node.Attrs.Select(attr => {
                switch (attr.Name.Name)
                {
                case "fullLLk":
                case "FullLLk":
                    ReadOption <bool>(sink, attr, v => rule.FullLLk = v, true);
                    break;

                case "#private":
                case "private":
                case "priv":
                case "Private":
                    ReadOption <bool>(sink, attr, v => rule.IsPrivate = v, true);
                    break;

                case "token":
                case "Token":
                    ReadOption <bool>(sink, attr, v => rule.IsToken = v, true);
                    break;

                case "start":
                case "Start":
                    ReadOption <bool>(sink, attr, v => rule.IsStartingRule = v, true);
                    break;

                case "#extern":
                case "extern":
                case "Extern":
                    ReadOption <bool>(sink, attr, v => rule.IsExternal = v, true);
                    break;

                case "#inline":
                case "inline":
                case "Inline":
                    ReadOption <bool>(sink, attr, v => rule.IsInline = v, true);
                    break;

                case "k":
                case "K":
                case "LL":
                    ReadOption <int>(sink, attr, k => rule.K = k, null);
                    break;

                case "recognizer":
                case "Recognizer":
                    LNode sig = null;
                    if (attr.ArgCount == 1)
                    {
                        sig = attr.Args[0];
                        if (sig.Calls(S.Braces, 1))
                        {
                            sig = sig.Args[0];
                        }
                        // TODO: we need a way to invoke all applicable macros at a particular location
                        //       e.g. "public fn Foo()::bool;" is not supported by def() alone.
                        sig = LeMP.Prelude.Les.Macros.fn(sig, sink) ?? sig;
                    }
                    if (sig != null && sig.CallsMin(S.Fn, 3))
                    {
                        rule.MakeRecognizerVersion(sig).TryWrapperNeeded();
                    }
                    else
                    {
                        sink.Write(Severity.Error, sig, "'recognizer' expects one parameter, a method signature.");
                    }
                    break;

                default:
                    return(attr);
                }
                return(null);
            }).WhereNotNull().ToArray());
        }
Esempio n. 40
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.Write(Severity.Warning, alias, "Redefinition of alias '{0}'", alias);
				} else if ((q = _definedAliases.Where(pair => replacement.Equals(pair.Value))).Any())
					sink.Write(Severity.Warning, replacement, "Aliases '{0}' and '{1}' have the same replacement value", q.First().Key, alias);
				_definedAliases[alias] = replacement;
				return LNode.Call(S.Splice, RVList<LNode>.Empty); // erase alias from output
			}
			return null;
		}
			LNode ConvertVarDeclToRunSequence(VList<LNode> attrs, LNode varType, LNode varName, LNode initValue)
			{
				initValue = BubbleUpBlocks(initValue);
				varType = varType ?? F.Missing;
				LNode @ref;
				attrs = attrs.WithoutNodeNamed(S.Ref, out @ref);
				var varName_apos = varName.PlusAttr(_trivia_isTmpVar);
				if (@ref != null)
					varName_apos = varName_apos.PlusAttr(@ref);
				{
					LNode resultValue;
					VList<LNode> stmts;
					if (initValue.CallsMin((Symbol) "#runSequence", 1) && (resultValue = initValue.Args[initValue.Args.Count - 1]) != null) {
						stmts = initValue.Args.WithoutLast(1);
						var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, resultValue))));
						return initValue.WithArgs(stmts.Add(newVarDecl).Add(varName_apos));
					
					} else {
						var newVarDecl = LNode.Call(LNode.List(attrs), CodeSymbols.Var, LNode.List(varType, LNode.Call(CodeSymbols.Assign, LNode.List(varName, initValue))));
						return LNode.Call((Symbol) "#runSequence", LNode.List(newVarDecl, varName_apos));
					}
				}
			}
Esempio n. 42
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;
		}
            Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
            {
                var target           = expr.Target;
                var args             = expr.Args;
                var combinedSequence = LNode.List();

                target = BubbleUpBlocks(target);
                if (target.CallsMin(__numrunSequence, 1))
                {
                    combinedSequence = target.Args.WithoutLast(1);
                    expr             = expr.WithTarget(target.Args.Last);
                }
                var isAssignment = EcsValidators.IsAssignmentOperator(expr.Name);

                if (isAssignment)
                {
                    LNode lhs = BubbleUpBlocks(expr.Args[0]);
                    LNode rhs = BubbleUpBlocks(expr.Args[1]);
                    args = LNode.List(lhs, rhs);
                }
                else
                {
                    args = args.SmartSelect(arg => BubbleUpBlocks(arg));
                }
                int lastRunSeq = args.LastIndexWhere(a => a.CallsMin(__numrunSequence, 1));

                if (lastRunSeq >= 0)
                {
                    int lastRunSeqImpure = args.First(lastRunSeq + 1).LastIndexWhere(a => a.CallsMin(__numrunSequence, 1) && a.AttrNamed(_trivia_pure.Name) == null);
                    if (lastRunSeq > 0 && (args.Count == 2 && (target.IsIdNamed(S.And) || target.IsIdNamed(S.Or)) || args.Count == 3 && target.IsIdNamed(S.QuestionMark)))
                    {
                        Context.Write(Severity.Error, target, "#useSequenceExpressions is not designed to support sequences or variable declarations on the right-hand side of the `&&`, `||` or `?` operators. The generated code will be incorrect.");
                    }
                    var argsW = args.ToList();
                    for (int i = 0; i <= lastRunSeq; i++)
                    {
                        LNode arg = argsW[i];
                        if (!arg.IsLiteral)
                        {
                            if (arg.CallsMin(__numrunSequence, 1))
                            {
                                combinedSequence.AddRange(arg.Args.WithoutLast(1));
                                argsW[i] = arg = arg.Args.Last;
                            }
                            if (i < lastRunSeqImpure)
                            {
                                if (i == 0 && (expr.CallsMin(S.IndexBracks, 1) || expr.CallsMin(S.NullIndexBracks, 1)))
                                {
                                }
                                else
                                {
                                    if (isAssignment || arg.Attrs.Any(a => a.IsIdNamed(S.Ref) || a.IsIdNamed(S.Out)))
                                    {
                                        argsW[i] = MaybeCreateTemporaryForLValue(arg, ref combinedSequence);
                                    }
                                    else
                                    {
                                        LNode tmpVarName, tmpVarDecl = TempVarDecl(Context, arg, out tmpVarName);
                                        combinedSequence.Add(tmpVarDecl);
                                        argsW[i] = tmpVarName.PlusAttr(_trivia_isTmpVar);
                                    }
                                }
                            }
                        }
                    }
                    expr = expr.WithArgs(LNode.List(argsW));
                }
                return(Pair.Create(combinedSequence, expr));
            }