예제 #1
0
        internal static Symbol DecodeSubstitutionExpr(LNode expr, out LNode condition, out bool isParams, out bool refExistingVar)
        {
            condition      = null;
            isParams       = false;
            refExistingVar = false;
            if (expr.Calls(S.Substitute, 1))
            {
                LNode id = expr.Args[0];
                if (id.AttrNamed(S.Params) != null)
                {
                    isParams = true;
                }
                else if (id.Calls(S.DotDotDot, 1) || id.Calls(S.DotDot, 1))
                {
                    isParams = true;
                    id       = id.Args[0];
                }

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

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

                if (condition != null)
                {
                    condition = condition.ReplaceRecursive(n => n.IsIdNamed(S._HashMark) ? id : null);
                }
                if (!id.IsId)
                {
                    return(null);
                }
                return(id.Name);
            }
            return(null);
        }
예제 #2
0
		public static LNode static_matchCode(LNode node, IMacroContext context)
		{
			if (node.AttrNamed(S.Static) == null && !node.HasSpecialName)
				return null; // handled by normal matchCode macro

			var args_body = context.GetArgsAndBody(false);
			VList<LNode> args = args_body.Item1, body = args_body.Item2;
			if (args.Count != 1)
				return Reject(context, args[1], "Expected only one expression to match");

			var expression = context.PreProcess(AutoStripBraces(args[0]));

			var cases = GetCases(body, context.Sink);
			// The `default:` case is represented by an empty list of patterns.
			if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty))
				context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched.");

			MMap<Symbol, LNode> captures = new MMap<Symbol, LNode>();
			foreach (Pair<VList<LNode>, VList<LNode>> pair in cases)
			{
				var patterns = pair.Key.IsEmpty ? new VList<LNode>((LNode)null) : pair.Key;
				foreach (var pattern in patterns)
				{
					captures.Clear();
					VList<LNode> _;
					if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _)) {
						captures[_hash] = expression; // define $#
						captures.Remove(__);
						return ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures);
					}
				}
			}
			return F.Call(S.Splice); // none of the cases matched
		}
예제 #3
0
        public virtual LNode VisitInput(LNode stmt, IMessageSink sink)
        {
            LNode aliasSet;

            if ((stmt.Calls(_alias, 1) || stmt.CallsMin(S.Alias, 1)) &&
                (aliasSet = stmt.Args[0]).Calls(S.Assign, 2))
            {
                IEnumerable <KeyValuePair <LNode, LNode> > q;
                LNode alias = aliasSet.Args[0], replacement = aliasSet.Args[1], old;
                if (_definedAliases.TryGetValue(alias, out old))
                {
                    if (stmt.AttrNamed(S.Partial) == null || !old.Equals(replacement))
                    {
                        sink.Warning(alias, "Redefinition of alias '{0}'", alias);
                    }
                }
                else if ((q = _definedAliases.Where(pair => replacement.Equals(pair.Value))).Any())
                {
                    sink.Warning(replacement, "Aliases '{0}' and '{1}' have the same replacement value", q.First().Key, alias);
                }
                _definedAliases[alias] = replacement;
                return(LNode.Call(S.Splice, VList <LNode> .Empty));              // erase alias from output
            }
            return(null);
        }
예제 #4
0
		public static LNode static_tryDeconstruct(LNode node, IMacroContext context)
		{
			if (node.AttrNamed(S.Static) == null && !node.HasSpecialName)
				return Reject(context, node, "Expected 'static' attribute");
			foreach (var arg in node.Args)
				DoDeconstruct(arg, context, printErrorOnFailure: false);
			return F.Call(S.Splice);
		}
예제 #5
0
        public static LNode StaticIf(LNode @if, IMacroContext context)
        {
            LNode @static;

            if ((@static = @if.AttrNamed(S.Static)) == null || [email protected])
            {
                return(null);
            }
            return(static_if(@if, context));
        }
예제 #6
0
 static bool IsParamsCapture(LNode pattern)
 {
     if (pattern.Calls(S.Substitute, 1))
     {
         LNode arg = pattern.Args.Last;
         return((arg.Calls(S.DotDot, 1) || arg.Calls(S.DotDotDot, 1) || arg.AttrNamed(S.Params) != null) &&
                GetCaptureIdentifier(pattern) != null);
     }
     return(false);
 }
예제 #7
0
        public static LNode StaticIf(LNode @if, IMessageSink sink)
        {
            LNode @static;

            if ((@static = @if.AttrNamed(S.Static)) == null || [email protected])
            {
                return(null);
            }
            return(static_if(@if, sink));
        }
예제 #8
0
 internal static Symbol GetSubstitutionVar(LNode expr, out LNode condition, out bool isParams, out bool refExistingVar)
 {
     condition      = null;
     isParams       = false;
     refExistingVar = false;
     if (expr.Calls(S.Substitute, 1))
     {
         LNode id = expr.Args[0];
         if (id.AttrNamed(S.Params) != null)
         {
             isParams = true;
         }
         else if (id.Calls(S.DotDot, 1))
         {
             isParams = true;
             id       = id.Args[0];
         }
         if (id.AttrNamed(S.Ref) != null)
         {
             refExistingVar = true;
         }
         if (id.Calls(S.IndexBracks, 2))
         {
             condition = id.Args[1];
             id        = id.Args[0];
         }
         else if (id.ArgCount == 1)
         {
             condition = id.Args[0];
             id        = id.Target;
         }
         if (condition != null)
         {
             condition = condition.ReplaceRecursive(n => n.IsIdNamed(S._HashMark) ? id : null);
         }
         if (!id.IsId)
         {
             return(null);
         }
         return(id.Name);
     }
     return(null);
 }
예제 #9
0
 public static LNode static_tryDeconstruct(LNode node, IMacroContext context)
 {
     if (node.AttrNamed(S.Static) == null && !node.HasSpecialName)
     {
         return(Reject(context, node, "Expected 'static' attribute"));
     }
     foreach (var arg in node.Args)
     {
         DoDeconstruct(arg, context, printErrorOnFailure: false);
     }
     return(F.Call(S.Splice));
 }
예제 #10
0
        public static LNode static_matchCode(LNode node, IMacroContext context)
        {
            if (node.AttrNamed(S.Static) == null && !node.HasSpecialName)
            {
                return(null);                // handled by normal matchCode macro
            }
            var           args_body = context.GetArgsAndBody(false);
            VList <LNode> args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1)
            {
                return(Reject(context, args[1], "Expected only one expression to match"));
            }

            var expression = context.PreProcess(AutoStripBraces(args[0]));

            var cases = GetCases(body, context.Sink);

            // The `default:` case is represented by an empty list of patterns.
            if (cases.WithoutLast(1).Any(pair => pair.Key.IsEmpty))
            {
                context.Write(Severity.Error, node, "The `default:` case must be the last one, because the cases are tested in the order they appear, so no case after `default:` can be matched.");
            }

            MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>();

            foreach (Pair <VList <LNode>, VList <LNode> > pair in cases)
            {
                var patterns = pair.Key.IsEmpty ? new VList <LNode>((LNode)null) : pair.Key;
                foreach (var pattern in patterns)
                {
                    captures.Clear();
                    VList <LNode> _;
                    if (pattern == null || LNodeExt.MatchesPattern(expression, pattern, ref captures, out _))
                    {
                        captures[_hash] = expression;                         // define $#
                        captures.Remove(__);
                        return(ReplaceCaptures(pair.Value.AsLNode(S.Splice), captures));
                    }
                }
            }
            return(F.Call(S.Splice));            // none of the cases matched
        }
예제 #11
0
		public static LNode StaticIf(LNode @if, IMessageSink sink)
		{
			LNode @static;
			if ((@static = @if.AttrNamed(S.Static)) == null || [email protected])
				return null;
			return static_if(@if, sink);
		}
예제 #12
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;
		}
예제 #13
0
        public static LNode matchCode(LNode node, IMacroContext context)
        {
            if (node.AttrNamed(S.Static) != null)
            {
                return(null);                   // this case is handled by static_matchCode macro
            }
            var       args_body = context.GetArgsAndBody(false);
            LNodeList args = args_body.Item1, body = args_body.Item2;

            if (args.Count != 1 || body.Count < 1)
            {
                return(null);
            }
            var cases = GetCases(body, context.Sink);

            if (cases.IsEmpty)
            {
                return(null);
            }

            var output = new WList <LNode>();
            var var    = MaybeAddTempVarDecl(context, args[0], output);

            var ifClauses = new List <Pair <LNode, LNode> >();
            var cmc       = new CodeMatchContext {
                Context = context
            };

            foreach (var @case in cases)
            {
                cmc.ThenClause.Clear();
                // e.g. case [$(..._)] Foo($x + 1, $y) =>
                //      LNode x, y, tmp9;
                //      if (var.Calls((Symbol) "Foo", 2) && (tmp9 = var.Args[0]).Calls(CodeSymbols.Plus, 2)
                //          && (x = tmp9.Args[0]) != null // this will never be null, but we want to put it the assignment in the 'if' statement
                //          && 1.Equals(tmp9.Args[1].Value) && (y = var.Args[1]) != null) { ... }
                LNode testExpr = null;
                if (@case.Key.Count > 0)
                {
                    if (cmc.IsMultiCase = @case.Key.Count > 1)
                    {
                        cmc.UsageCounters.Clear();
                        testExpr = @case.Key.Aggregate((LNode)null, (test, pattern) => {
                            test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, var), S.Or);
                            return(test);
                        });
                        foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count))
                        {
                            if (cmc.NodeVars.ContainsKey(pair.Key))
                            {
                                cmc.NodeVars[pair.Key] = true;
                            }
                            if (cmc.ListVars.ContainsKey(pair.Key))
                            {
                                cmc.ListVars[pair.Key] = true;
                            }
                        }
                    }
                    else
                    {
                        testExpr = cmc.MakeTopTestExpr(@case.Key[0], var);
                    }
                }
                var handler = F.Braces(@case.Value);
                if (cmc.ThenClause.Count > 0)
                {
                    handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces);
                }
                ifClauses.Add(Pair.Create(testExpr, handler));
            }

            LNode ifStmt = null;

            for (int i = ifClauses.Count - 1; i >= 0; i--)
            {
                if (ifClauses[i].Item1 == null)
                {
                    if (ifStmt == null)
                    {
                        ifStmt = ifClauses[i].Item2;
                    }
                    else
                    {
                        context.Sink.Error(node, "The default case must appear last, and there can be only one.");
                    }
                }
                else
                {
                    if (ifStmt == null)
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2);
                    }
                    else
                    {
                        ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt);
                    }
                }
            }

            if (cmc.NodeVars.Count > 0)
            {
                output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(
                                      cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key)))));
            }
            if (cmc.ListVars.Count > 0)
            {
                LNode type = LNode.Id((Symbol)"LNodeList");
                output.Add(F.Call(S.Var, ListExt.Single(type).Concat(
                                      cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key)))));
            }
            if (output.Count == 0)
            {
                return(ifStmt.IncludingTriviaFrom(node));
            }
            else
            {
                output.Add(ifStmt);
                return(F.Braces(output.ToVList()).IncludingTriviaFrom(node));
            }
        }
예제 #14
0
            void GetPatternComponents(LNode pattern, out LNode varBinding, out bool refExistingVar, out LNode cmpExpr, out LNode isType, out LNode inRange, out VList <LNode> subPatterns, out VList <LNode> conditions)
            {
                // Here's a typical pattern (case expr):
                //  is Shape(ShapeType.Circle, ref size, Location: p is Point<int>(x, y)):
                // When there is an arg list, we decode its Target and return the args.
                //
                // The caller is in charge of stripping out "Property:" prefix, if any,
                // so the most complex pattern that this method considers is something
                // like `(expr is Type in Range)(subPatterns) && conds` where `expr` is
                // a varName or $varName to deconstruct, or some expression to test for
                // equality. Assuming it's an equality test, the output will be
                //
                //   varBinding = null
                //   refExistingVar = false
                //   cmpExpr = quote(expr);
                //   isType = quote(Type);
                //   inRange = quote(Range);
                //   conds will have "conds" pushed to the front.
                //
                bool haveSubPatterns = false;

                subPatterns    = VList <LNode> .Empty;
                refExistingVar = pattern.AttrNamed(S.Ref) != null;

                // First, look for "pattern && condition"
                conditions = VList <LNode> .Empty;
                while (pattern.Calls(S.And, 2))
                {
                    conditions.Add(pattern.Args.Last);
                    pattern = pattern.Args[0];
                }

                LNode cmpExprOrBinding = null;

                varBinding = cmpExpr = isType = inRange = null;

                // Now decode the expression. Use three passes, each of which decodes
                // an "outer" layer such as A is B, A in B, or expr(args). Since you
                // can combine these operators, we may need multiple passes (e.g.
                // "X is T in R" and "X in R is T" are equivalent), and keep in mind
                // that operator trees like "A in B" are nearly identical to prefix-
                // calls like "foo(A, B)" except for the call target and the `BaseStyle`.
                for (int pass = 1; pass <= 3; pass++)
                {
                    LNode inRange2 = inRange, isType2 = isType;
                    {
                        LNode patternL;
                        if (pattern.Calls(CodeSymbols.In, 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol)"in", 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null)
                        {
                            pattern = patternL;
                            if (inRange2 != null)
                            {
                                _context.Sink.Error(inRange2, "match-case does not support multiple 'in' operators");
                            }
                        }
                        else if (pattern.Calls(CodeSymbols.Is, 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null || pattern.Calls((Symbol)"is", 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null)
                        {
                            pattern = cmpExprOrBinding;
                            if (isType2 != null)
                            {
                                _context.Sink.Error(isType2, "match-case does not support multiple 'is' operators");
                            }
                        }
                        else if (pattern.Calls(CodeSymbols.Is, 1) && (isType = pattern.Args[0]) != null || pattern.Calls((Symbol)"is", 1) && (isType = pattern.Args[0]) != null)
                        {
                            if (isType2 != null)
                            {
                                _context.Sink.Error(isType2, "match-case does not support multiple 'is' operators");
                            }
                            goto doneAnalysis;
                        }
                        else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1))
                        {
                            inRange = pattern;
                            goto doneAnalysis;
                        }
                        else if (pattern.Calls(CodeSymbols.Tuple))
                        {
                            subPatterns      = pattern.Args;
                            cmpExprOrBinding = null;
                        }
                        else
                        {
                            // It's very tempting to detect NodeStyle.PrefixNotation to distinguish,
                            // say, A.B<C> from id(A, B, C), but I'm reluctant to do so. BaseStyle
                            // is by convention "unsemantic" and not guaranteed to be preserved
                            // across serializations or supported the same way by different parsers.
                            // So instead of asking "is this in PrefixNotation?" I ask "does the
                            // target appear to be a normal identifier?"
                            LNode target = pattern.Target;
                            if (!haveSubPatterns && pattern.IsCall && (!target.IsId || target.AttrNamed(S.TriviaInParens) != null || (!target.HasSpecialName && Les2Printer.IsNormalIdentifier(target.Name)))
                                )

                            {
                                haveSubPatterns = true;
                                subPatterns     = pattern.Args;
                                pattern         = pattern.Target;
                            }
                            else
                            {
                                cmpExprOrBinding = pattern;
                            }
                        }
                    }
                }
doneAnalysis:

                if (cmpExprOrBinding != null)
                {
                    if (cmpExprOrBinding.Calls(S.Substitute, 1))
                    {
                        varBinding = cmpExprOrBinding[0];
                    }
                    else if (refExistingVar)
                    {
                        varBinding = cmpExprOrBinding;
                    }
                    else if ((varBinding ?? cmpExprOrBinding).IsIdNamed(__))
                    {
                        cmpExprOrBinding = varBinding = null;
                    }
                    // Originally a plain identifier would be a binding, like $identifier
                    //if (cmpExprOrBinding.IsId && cmpExprOrBinding.AttrNamed(S.TriviaInParens) == null)
                    //	varBinding = cmpExprOrBinding;
                    if (varBinding != null)
                    {
                        if (varBinding.AttrNamed(S.Ref) != null)
                        {
                            refExistingVar = true;
                            varBinding     = varBinding.WithoutAttrs();
                        }
                        if (!varBinding.IsId)
                        {
                            _context.Sink.Error(varBinding, "Invalid variable name in match-case: {0}", varBinding);
                            varBinding = null;
                        }
                    }
                    if (varBinding == null)
                    {
                        cmpExpr = cmpExprOrBinding;
                    }
                }

                if (refExistingVar && varBinding == null)
                {
                    refExistingVar = false;
                    var got = cmpExprOrBinding ?? pattern;
                    _context.Sink.Warning(got, "'ref' expected a variable name (got `{0}`)", got);
                }
            }
예제 #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));
        }
예제 #16
0
 private bool IsDefaultNewlineSuppressed(LNode node)
 {
     return(node.AttrNamed(S.TriviaAppendStatement) != null);
 }
예제 #17
0
		public static LNode matchCode(LNode node, IMacroContext context)
		{
			if (node.AttrNamed(S.Static) != null)
				return null;	// this case is handled by static_matchCode macro
			var args_body = context.GetArgsAndBody(false);
			VList<LNode> args = args_body.Item1, body = args_body.Item2;
			if (args.Count != 1 || body.Count < 1)
				return null;
			var cases = GetCases(body, context.Sink);
			if (cases.IsEmpty)
				return null;
		
			var output = new WList<LNode>();
			var @var = MaybeAddTempVarDecl(context, args[0], output);
		
			var ifClauses = new List<Pair<LNode, LNode>>();
			var cmc = new CodeMatchContext { 
				Context = context
			};
		
			foreach (var @case in cases)
			{
				cmc.ThenClause.Clear();
				// e.g. case [$(..._)] Foo($x + 1, $y) => 
				//      LNode x, y, tmp9; 
				//      if (var.Calls((Symbol) "Foo", 2) && (tmp9 = var.Args[0]).Calls(CodeSymbols.Plus, 2)
				//          && (x = tmp9.Args[0]) != null // this will never be null, but we want to put it the assignment in the 'if' statement
				//          && 1.Equals(tmp9.Args[1].Value) && (y = var.Args[1]) != null) { ... }
				LNode testExpr = null;
				if (@case.Key.Count > 0) {
					if (cmc.IsMultiCase = @case.Key.Count > 1) {
						cmc.UsageCounters.Clear();
						testExpr = @case.Key.Aggregate((LNode) null, (test, pattern) => {
							test = LNode.MergeBinary(test, cmc.MakeTopTestExpr(pattern, @var), S.Or);
							return test;
						});
						foreach (var pair in cmc.UsageCounters.Where(p => p.Value < @case.Key.Count)) {
							if (cmc.NodeVars.ContainsKey(pair.Key))
								cmc.NodeVars[pair.Key] = true;
							if (cmc.ListVars.ContainsKey(pair.Key))
								cmc.ListVars[pair.Key] = true;
						}
					} else
						testExpr = cmc.MakeTopTestExpr(@case.Key[0], @var);
				}
				var handler = @case.Value.AsLNode(S.Braces);
				if (cmc.ThenClause.Count > 0)
					handler = LNode.MergeLists(F.Braces(cmc.ThenClause), handler, S.Braces);
				ifClauses.Add(Pair.Create(testExpr, handler));
			}
		
			LNode ifStmt = null;
			for (int i = ifClauses.Count - 1; i >= 0; i--)
			{
				if (ifClauses[i].Item1 == null) {
					if (ifStmt == null)
						ifStmt = ifClauses[i].Item2;
					else
						context.Sink.Error(node, "The default case must appear last, and there can be only one.");
				} else {
					if (ifStmt == null)
						ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2);
					else
						ifStmt = F.Call(S.If, ifClauses[i].Item1, ifClauses[i].Item2, ifStmt);
				}
			}
		
			if (cmc.NodeVars.Count > 0)
				output.Add(F.Call(S.Var, ListExt.Single(F.Id("LNode")).Concat(
				cmc.NodeVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? F.Call(S.Assign, F.Id(kvp.Key), F.Null) : F.Id(kvp.Key)))));
			if (cmc.ListVars.Count > 0) {
				LNode type = LNode.Call(CodeSymbols.Of, LNode.List(LNode.Id((Symbol) "VList"), LNode.Id((Symbol) "LNode"))).SetStyle(NodeStyle.Operator);
				output.Add(F.Call(S.Var, ListExt.Single(type).Concat(
				cmc.ListVars.OrderBy(v => v.Key.Name).Select(kvp => kvp.Value ? LNode.Call(CodeSymbols.Assign, LNode.List(F.Id(kvp.Key), LNode.Call(CodeSymbols.Default, LNode.List(type)))).SetStyle(NodeStyle.Operator) : F.Id(kvp.Key)))));
			}
			if (output.Count == 0)
				return ifStmt;
			else {
				output.Add(ifStmt);
				return F.Braces(output.ToVList());
			}
		}
예제 #18
0
		private bool IsDefaultNewlineSuppressed(LNode node)
		{
			return node.AttrNamed(S.TriviaAppendStatement) != null || (_flags & Ambiguity.OneLiner) != 0;
		}
예제 #19
0
		public static LNode StaticIf(LNode @if, IMacroContext context)
		{
			LNode @static;
			if ((@static = @if.AttrNamed(S.Static)) == null || [email protected])
				return null;
			return static_if(@if, context);
		}
예제 #20
0
        public static LNode BackingField(LNode prop, IMessageSink sink)
        {
            LNode type, name, body;

            if (prop.ArgCount != 3 || !(body = prop.Args[2]).Calls(S.Braces))
            {
                return(null);
            }

            LNode fieldAttr = null, fieldVarAttr = null;
            LNode fieldName;
            bool  autoType = false;
            int   i;

            for (i = 0; i < prop.Attrs.Count; i++)
            {
                LNode attr = prop.Attrs[i];
                if (attr.IsIdNamed(_field) ||
                    attr.Calls(S.Var, 2) &&
                    ((autoType = attr.Args[0].IsIdNamed(_field)) ||
                     (fieldVarAttr = attr.AttrNamed(_field)) != null && fieldVarAttr.IsId))
                {
                    fieldAttr = attr;
                    break;
                }
            }
            if (fieldAttr == null)
            {
                return(null);
            }

            LNode field = fieldAttr;

            type = prop.Args[0];
            if (field.IsId)
            {
                name      = prop.Args[1];
                fieldName = F.Id(ChooseFieldName(Ecs.EcsNodePrinter.KeyNameComponentOf(name)));
                field     = F.Call(S.Var, type, fieldName).WithAttrs(fieldAttr.Attrs);
            }
            else
            {
                fieldName = field.Args[1];
                if (fieldName.Calls(S.Assign, 2))
                {
                    fieldName = fieldName.Args[0];
                }
            }
            if (autoType)
            {
                field = field.WithArgChanged(0, type);
            }
            if (fieldVarAttr != null)
            {
                field = field.WithoutAttrNamed(_field);
            }

            LNode newBody = body.WithArgs(body.Args.SmartSelect(stmt =>
            {
                var attrs = stmt.Attrs;
                if (stmt.IsIdNamed(S.get))
                {
                    stmt           = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Return, fieldName))).WithAttrs(attrs);
                    stmt.BaseStyle = NodeStyle.Special;
                }
                if (stmt.IsIdNamed(S.set))
                {
                    stmt           = F.Call(stmt.WithoutAttrs(), F.Braces(F.Call(S.Assign, fieldName, F.Id(S.value)))).WithAttrs(attrs);
                    stmt.BaseStyle = NodeStyle.Special;
                }
                return(stmt);
            }));

            if (newBody == body)
            {
                sink.Write(Severity.Warning, fieldAttr, "The body of the property does not contain a 'get;' or 'set;' statement without a body, so no code was generated to get or set the backing field.");
            }

            prop = prop.WithAttrs(prop.Attrs.RemoveAt(i)).WithArgChanged(2, newBody);
            return(F.Call(S.Splice, new RVList <LNode>(field, prop)));
        }
예제 #21
0
 public static bool IsParenthesizedExpr(this LNode node)
 {
     return(node.AttrNamed(CodeSymbols.TriviaInParens) != null);
 }
예제 #22
0
			void GetPatternComponents(LNode pattern, out LNode varBinding, out bool refExistingVar, out LNode cmpExpr, out LNode isType, out LNode inRange, out VList<LNode> subPatterns, out VList<LNode> conditions)
			{
				// Here's a typical pattern (case expr):
				//  is Shape(ShapeType.Circle, ref size, Location: p is Point<int>(x, y)):
				// When there is an arg list, we decode its Target and return the args.
				//
				// The caller is in charge of stripping out "Property:" prefix, if any,
				// so the most complex pattern that this method considers is something 
				// like `(expr is Type in Range)(subPatterns) && conds` where `expr` is 
				// a varName or $varName to deconstruct, or some expression to test for 
				// equality. Assuming it's an equality test, the output will be
				//
				//   varBinding = null
				//   refExistingVar = false
				//   cmpExpr = quote(expr);
				//   isType = quote(Type);
				//   inRange = quote(Range);
				//   conds will have "conds" pushed to the front.
				// 
				bool haveSubPatterns = false;
				subPatterns = VList<LNode>.Empty;
				refExistingVar = pattern.AttrNamed(S.Ref) != null;
			
				// First, look for "pattern && condition"
				conditions = VList<LNode>.Empty;
				while (pattern.Calls(S.And, 2)) {
					conditions.Add(pattern.Args.Last);
					pattern = pattern.Args[0];
				}
			
				LNode cmpExprOrBinding = null;
				varBinding = cmpExpr = isType = inRange = null;
			
				// Now decode the expression. Use three passes, each of which decodes 
				// an "outer" layer such as A is B, A in B, or expr(args). Since you 
				// can combine these operators, we may need multiple passes (e.g. 
				// "X is T in R" and "X in R is T" are equivalent), and keep in mind 
				// that operator trees like "A in B" are nearly identical to prefix-
				// calls like "foo(A, B)" except for the call target and the `BaseStyle`. 
				for (int pass = 1; pass <= 3; pass++) {
					LNode inRange2 = inRange, isType2 = isType;
					{
						LNode patternL;
						if (pattern.Calls(CodeSymbols.In, 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol) "in", 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null) {
							pattern = patternL;
							if (inRange2 != null)
								_context.Sink.Error(inRange2, "match-case does not support multiple 'in' operators");
						} else if (pattern.Calls(CodeSymbols.Is, 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null || pattern.Calls((Symbol) "is", 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null) {
							pattern = cmpExprOrBinding;
							if (isType2 != null)
								_context.Sink.Error(isType2, "match-case does not support multiple 'is' operators");
						} else if (pattern.Calls(CodeSymbols.Is, 1) && (isType = pattern.Args[0]) != null || pattern.Calls((Symbol) "is", 1) && (isType = pattern.Args[0]) != null) {
							if (isType2 != null)
								_context.Sink.Error(isType2, "match-case does not support multiple 'is' operators");
							goto doneAnalysis;
						} else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1)) {
							inRange = pattern;
							goto doneAnalysis;
						} else if (pattern.Calls(CodeSymbols.Tuple)) {
							subPatterns = pattern.Args;
							cmpExprOrBinding = null;
						} else {
							// It's very tempting to detect NodeStyle.PrefixNotation to distinguish, 
							// say, A.B<C> from id(A, B, C), but I'm reluctant to do so. BaseStyle 
							// is by convention "unsemantic" and not guaranteed to be preserved 
							// across serializations or supported the same way by different parsers. 
							// So instead of asking "is this in PrefixNotation?" I ask "does the 
							// target appear to be a normal identifier?" 
							LNode target = pattern.Target;
							if (!haveSubPatterns && pattern.IsCall && (!target.IsId || target.AttrNamed(S.TriviaInParens) != null || (!target.HasSpecialName && Les2Printer.IsNormalIdentifier(target.Name)))
							)
						
							{
								haveSubPatterns = true;
								subPatterns = pattern.Args;
								pattern = pattern.Target;
							} else
								cmpExprOrBinding = pattern;
						}
					}
				}
			doneAnalysis:
			
				if (cmpExprOrBinding != null) {
					if (cmpExprOrBinding.Calls(S.Substitute, 1))
						varBinding = cmpExprOrBinding[0];
					else if (refExistingVar)
						varBinding = cmpExprOrBinding;
					else if ((varBinding ?? cmpExprOrBinding).IsIdNamed(__))
						cmpExprOrBinding = varBinding = null;
						// Originally a plain identifier would be a binding, like $identifier
						//if (cmpExprOrBinding.IsId && cmpExprOrBinding.AttrNamed(S.TriviaInParens) == null)
						//	varBinding = cmpExprOrBinding;
					if (varBinding != null) {
						if (varBinding.AttrNamed(S.Ref) != null) {
							refExistingVar = true;
							varBinding = varBinding.WithoutAttrs();
						}
						if (!varBinding.IsId) {
							_context.Sink.Error(varBinding, "Invalid variable name in match-case: {0}", varBinding);
							varBinding = null;
						}
					}
					if (varBinding == null)
						cmpExpr = cmpExprOrBinding;
				}
			
				if (refExistingVar && varBinding == null) {
					refExistingVar = false;
					var got = cmpExprOrBinding ?? pattern;
					_context.Sink.Warning(got, "'ref' expected a variable name (got `{0}`)", got);
				}
			}
예제 #23
0
			void GetPatternComponents(LNode pattern, out LNode varBinding, out bool refExistingVar, out LNode cmpExpr, out LNode isType, out LNode inRange, out VList<LNode> subPatterns, out VList<LNode> conditions)
			{
				bool haveSubPatterns = false;
				subPatterns = VList<LNode>.Empty;
				refExistingVar = pattern.AttrNamed(S.Ref) != null;
				conditions = VList<LNode>.Empty;
				while (pattern.Calls(S.And, 2)) {
					conditions.Add(pattern.Args.Last);
					pattern = pattern.Args[0];
				}
				LNode cmpExprOrBinding = null;
				varBinding = cmpExpr = isType = inRange = null;
				for (int pass = 1; pass <= 3; pass++) {
					LNode inRange2 = inRange, isType2 = isType;
					{
						LNode patternL;
						if (pattern.Calls(CodeSymbols.In, 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol) "in", 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null) {
							pattern = patternL;
							if (inRange2 != null)
								_context.Write(Severity.Error, inRange2, "match-case does not support multiple 'in' operators");
						} else if (pattern.Calls(CodeSymbols.Is, 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null || pattern.Calls((Symbol) "is", 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null) {
							pattern = cmpExprOrBinding;
							if (isType2 != null)
								_context.Write(Severity.Error, isType2, "match-case does not support multiple 'is' operators");
						} else if (pattern.Calls(CodeSymbols.Is, 1) && (isType = pattern.Args[0]) != null || pattern.Calls((Symbol) "is", 1) && (isType = pattern.Args[0]) != null) {
							if (isType2 != null)
								_context.Write(Severity.Error, isType2, "match-case does not support multiple 'is' operators");
							goto doneAnalysis;
						} else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1)) {
							inRange = pattern;
							goto doneAnalysis;
						} else if (pattern.Calls(CodeSymbols.Tuple)) {
							subPatterns = pattern.Args;
							cmpExprOrBinding = null;
						} else {
							LNode target = pattern.Target;
							if (!haveSubPatterns && pattern.IsCall && (!target.IsId || target.AttrNamed(S.TriviaInParens) != null || (!target.HasSpecialName && LesNodePrinter.IsNormalIdentifier(target.Name)))) {
								haveSubPatterns = true;
								subPatterns = pattern.Args;
								pattern = pattern.Target;
							} else
								cmpExprOrBinding = pattern;
						}
					}
				}
			doneAnalysis:
				if (cmpExprOrBinding != null) {
					if (cmpExprOrBinding.Calls(S.Substitute, 1))
						varBinding = cmpExprOrBinding[0];
					else if (refExistingVar)
						varBinding = cmpExprOrBinding;
					else if ((varBinding ?? cmpExprOrBinding).IsIdNamed(__))
						cmpExprOrBinding = varBinding = null;
					if (varBinding != null) {
						if (varBinding.AttrNamed(S.Ref) != null) {
							refExistingVar = true;
							varBinding = varBinding.WithoutAttrs();
						}
						if (!varBinding.IsId) {
							_context.Write(Severity.Error, varBinding, "Invalid variable name in match-case: {0}", varBinding);
							varBinding = null;
						}
					}
					if (varBinding == null)
						cmpExpr = cmpExprOrBinding;
				}
				if (refExistingVar && varBinding == null) {
					refExistingVar = false;
					var got = cmpExprOrBinding ?? pattern;
					_context.Write(Severity.Warning, got, "'ref' expected a variable name (got `{0}`)", got);
				}
			}
예제 #24
0
            void GetPatternComponents(LNode pattern, out LNode propName,
                                      out LNode varBinding, out bool refExistingVar,
                                      out LNode cmpExpr, out LNode isType, out LNode inRange,
                                      out VList <LNode> subPatterns, out VList <LNode> conditions)
            {
                // Format: PropName: is DerivedClass name(...) in Range
                // Here's a typical pattern (case expr):
                //  is Shape(ShapeType.Circle, ref size, Location: p is Point<int>(x, y))
                // When there is an arg list, we decode its Target and return the args.
                //
                // The caller is in charge of stripping out "Property:" prefix, if any,
                // so the most complex pattern that this method considers is something
                // like `expr is Type x(subPatterns) in Range && conds` where `expr` is
                // a varName or $varName to deconstruct, or some expression to test for
                // equality. Assuming it's an equality test, the output will be
                //
                //   varBinding = null
                //   refExistingVar = false
                //   cmpExpr = quote(expr);
                //   isType = quote(Type);
                //   inRange = quote(Range);
                //   conds will have "conds" pushed to the front.
                //
                subPatterns    = VList <LNode> .Empty;
                refExistingVar = pattern.AttrNamed(S.Ref) != null;

                propName = varBinding = cmpExpr = isType = inRange = null;
                // Deconstruct `PropName: pattern` (fun fact: we can't use `matchCode`
                // to detect a named parameter here, because if we write
                // `case { $propName: $subPattern; }:` it is parsed as a goto-label,
                // not as a named parameter.)
                if (pattern.Calls(S.NamedArg, 2) || pattern.Calls(S.Colon, 2))
                {
                    propName = pattern[0]; pattern = pattern[1];
                }
                // Deconstruct `pattern && condition` (iteratively)
                conditions = VList <LNode> .Empty;
                while (pattern.Calls(S.And, 2))
                {
                    conditions.Add(pattern.Args.Last);
                    pattern = pattern.Args[0];
                }

                {
                    LNode lhs;
                    if (pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol)"in", 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.In, 2) && (lhs = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null)
                    {
                        pattern = lhs;
                    }
                }
                // Deconstruct `PropName is Type` with optional list of subpatterns.
                // In LES let's accept ``PropName `is` (Type `with` (subpatterns))`` instead.
                LNode subpatterns = null;

                {
                    LNode lhs, type;
                    if (pattern.Calls(CodeSymbols.Is, 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls(CodeSymbols.Is, 3) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null && (subpatterns = pattern.Args[2]) != null || pattern.Calls((Symbol)"is", 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null || pattern.Calls((Symbol)"'is", 2) && (lhs = pattern.Args[0]) != null && (type = pattern.Args[1]) != null)
                    {
                        if (subpatterns == null)
                        {
                            if (type.Calls((Symbol)"with", 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null || type.Calls((Symbol)"'with", 2) && (isType = type.Args[0]) != null && (subpatterns = type.Args[1]) != null)
                            {
                            }
                        }
                        if (type.Calls(CodeSymbols.Var, 2) && (isType = type.Args[0]) != null && (varBinding = type.Args[1]) != null)
                        {
                        }
                        else
                        {
                            isType = type;
                        }
                        if (lhs.Calls(S.Substitute, 1))
                        {
                            if (varBinding != null)
                            {
                                _context.Sink.Error(varBinding, "match: cannot bind two variable names to one value");
                            }
                            varBinding = lhs[0];
                        }
                        else if (propName != null)
                        {
                            _context.Sink.Error(varBinding, "match: property name already set to {0}", propName.Name);
                            if (varBinding == null)
                            {
                                varBinding = lhs;                                       // assume it was intended as a variable binding
                            }
                        }
                        if (type.IsIdNamed("")                          // is var x
                            )
                        {
                            isType = null;
                        }
                    }
                    else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1))
                    {
                        inRange = pattern;
                    }
                    else if (pattern.Calls(CodeSymbols.AltList) || pattern.Calls(CodeSymbols.Tuple))
                    {
                        subpatterns = pattern;
                    }
                    else if (pattern.Calls(S.Substitute, 1))
                    {
                        varBinding = pattern[0];
                    }
                    else
                    {
                        cmpExpr = pattern;
                    }
                }
                if (subpatterns != null)
                {
                    if (subpatterns.Calls(S.Tuple) || subpatterns.Calls(S.AltList))
                    {
                        subPatterns = subpatterns.Args;
                    }
                    else
                    {
                        _context.Sink.Error(subpatterns, "match: expected list of subpatterns (at '{0}')", subpatterns);
                    }
                }
                if (cmpExpr != null)
                {
                    if (cmpExpr.IsIdNamed(__))
                    {
                        cmpExpr = null;
                    }
                    else if (refExistingVar && varBinding == null)                              // Treat `ref expr` as var binding
                    {
                        varBinding = cmpExpr;
                        cmpExpr    = null;
                    }
                }
                if (varBinding != null)
                {
                    if (varBinding.AttrNamed(S.Ref) != null)
                    {
                        varBinding     = varBinding.WithoutAttrNamed(S.Ref);
                        refExistingVar = true;
                    }
                    else if (varBinding.IsIdNamed(__))
                    {
                        varBinding = null;
                    }
                    else if (!varBinding.IsId)
                    {
                        _context.Sink.Error(varBinding, "match: expected variable name (at '{0}')", varBinding);
                        varBinding = null;
                    }
                }
            }
예제 #25
0
            void GetPatternComponents(LNode pattern, out LNode varBinding, out bool refExistingVar, out LNode cmpExpr, out LNode isType, out LNode inRange, out VList <LNode> subPatterns, out VList <LNode> conditions)
            {
                bool haveSubPatterns = false;

                subPatterns    = VList <LNode> .Empty;
                refExistingVar = pattern.AttrNamed(S.Ref) != null;
                conditions     = VList <LNode> .Empty;
                while (pattern.Calls(S.And, 2))
                {
                    conditions.Add(pattern.Args.Last);
                    pattern = pattern.Args[0];
                }
                LNode cmpExprOrBinding = null;

                varBinding = cmpExpr = isType = inRange = null;
                for (int pass = 1; pass <= 3; pass++)
                {
                    LNode inRange2 = inRange, isType2 = isType;
                    {
                        LNode patternL;
                        if (pattern.Calls(CodeSymbols.In, 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null || pattern.Calls((Symbol)"in", 2) && (patternL = pattern.Args[0]) != null && (inRange = pattern.Args[1]) != null)
                        {
                            pattern = patternL;
                            if (inRange2 != null)
                            {
                                _context.Write(Severity.Error, inRange2, "match-case does not support multiple 'in' operators");
                            }
                        }
                        else if (pattern.Calls(CodeSymbols.Is, 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null || pattern.Calls((Symbol)"is", 2) && (cmpExprOrBinding = pattern.Args[0]) != null && (isType = pattern.Args[1]) != null)
                        {
                            pattern = cmpExprOrBinding;
                            if (isType2 != null)
                            {
                                _context.Write(Severity.Error, isType2, "match-case does not support multiple 'is' operators");
                            }
                        }
                        else if (pattern.Calls(CodeSymbols.Is, 1) && (isType = pattern.Args[0]) != null || pattern.Calls((Symbol)"is", 1) && (isType = pattern.Args[0]) != null)
                        {
                            if (isType2 != null)
                            {
                                _context.Write(Severity.Error, isType2, "match-case does not support multiple 'is' operators");
                            }
                            goto doneAnalysis;
                        }
                        else if (pattern.Calls(CodeSymbols.DotDotDot, 2) || pattern.Calls(CodeSymbols.DotDot, 2) || pattern.Calls(CodeSymbols.DotDotDot, 1) || pattern.Calls(CodeSymbols.DotDot, 1))
                        {
                            inRange = pattern;
                            goto doneAnalysis;
                        }
                        else if (pattern.Calls(CodeSymbols.Tuple))
                        {
                            subPatterns      = pattern.Args;
                            cmpExprOrBinding = null;
                        }
                        else
                        {
                            LNode target = pattern.Target;
                            if (!haveSubPatterns && pattern.IsCall && (!target.IsId || target.AttrNamed(S.TriviaInParens) != null || (!target.HasSpecialName && LesNodePrinter.IsNormalIdentifier(target.Name))))
                            {
                                haveSubPatterns = true;
                                subPatterns     = pattern.Args;
                                pattern         = pattern.Target;
                            }
                            else
                            {
                                cmpExprOrBinding = pattern;
                            }
                        }
                    }
                }
doneAnalysis:
                if (cmpExprOrBinding != null)
                {
                    if (cmpExprOrBinding.Calls(S.Substitute, 1))
                    {
                        varBinding = cmpExprOrBinding[0];
                    }
                    else if (refExistingVar)
                    {
                        varBinding = cmpExprOrBinding;
                    }
                    else if ((varBinding ?? cmpExprOrBinding).IsIdNamed(__))
                    {
                        cmpExprOrBinding = varBinding = null;
                    }
                    if (varBinding != null)
                    {
                        if (varBinding.AttrNamed(S.Ref) != null)
                        {
                            refExistingVar = true;
                            varBinding     = varBinding.WithoutAttrs();
                        }
                        if (!varBinding.IsId)
                        {
                            _context.Write(Severity.Error, varBinding, "Invalid variable name in match-case: {0}", varBinding);
                            varBinding = null;
                        }
                    }
                    if (varBinding == null)
                    {
                        cmpExpr = cmpExprOrBinding;
                    }
                }
                if (refExistingVar && varBinding == null)
                {
                    refExistingVar = false;
                    var got = cmpExprOrBinding ?? pattern;
                    _context.Write(Severity.Warning, got, "'ref' expected a variable name (got `{0}`)", got);
                }
            }
예제 #26
0
 private bool IsDefaultNewlineSuppressed(LNode node)
 {
     return(node.AttrNamed(S.TriviaAppendStatement) != null || (_flags & Ambiguity.OneLiner) != 0);
 }
예제 #27
0
		Pred BranchToPred(LNode expr, out BranchMode mode, Context ctx)
		{
			if (expr.Calls(_Default, 1) || expr.Calls(_Default2, 1)) {
				expr = expr.Args[0];
				mode = BranchMode.Default;
			} else if (expr.Calls(_Error, 1) || expr.IsIdNamed(_DefaultError)) {
				mode = (expr.AttrNamed(S.Continue) != null || expr.AttrNamed(GSymbol.Get("continue")) != null) 
				       ? BranchMode.ErrorContinue : BranchMode.ErrorExit;
				if (expr.Calls(_Error, 1))
					expr = expr.Args[0];
				else
					return DefaultErrorBranch.Value;
			} else
				mode = BranchMode.None;

			return NodeToPred(expr, ctx);
		}