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); }
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 }
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); }
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); }
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)); }
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); }
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)); }
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); }
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)); }
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 }
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); }
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; }
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)); } }
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); } }
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)); }
private bool IsDefaultNewlineSuppressed(LNode node) { return(node.AttrNamed(S.TriviaAppendStatement) != null); }
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()); } }
private bool IsDefaultNewlineSuppressed(LNode node) { return node.AttrNamed(S.TriviaAppendStatement) != null || (_flags & Ambiguity.OneLiner) != 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); }
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))); }
public static bool IsParenthesizedExpr(this LNode node) { return(node.AttrNamed(CodeSymbols.TriviaInParens) != null); }
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); } }
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); } }
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; } } }
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); } }
private bool IsDefaultNewlineSuppressed(LNode node) { return(node.AttrNamed(S.TriviaAppendStatement) != null || (_flags & Ambiguity.OneLiner) != 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); }