Пример #1
0
        public static Symbol NextTempName(IMacroContext ctx, LNode value)
        {
            string prefix = value.Name.Name;

            prefix = EcsValidators.IsPlainCsIdentifier(prefix) ? prefix + "_" : "tmp_";
            return(NextTempName(ctx, prefix));
        }
Пример #2
0
 public void SanitizeIdentifierTests()
 {
     AreEqual("I_aposd", EcsValidators.SanitizeIdentifier("I'd"));
     AreEqual("_123", EcsValidators.SanitizeIdentifier("123"));
     AreEqual("_plus5", EcsValidators.SanitizeIdentifier("+5"));
     AreEqual("__empty__", EcsValidators.SanitizeIdentifier(""));
     AreEqual("_lt_gt", EcsValidators.SanitizeIdentifier("<>"));
 }
Пример #3
0
 public static LNode methodStyleMacro(LNode node, IMacroContext context)
 {
     if (EcsValidators.MethodDefinitionKind(node, out var defineKw, out var macroName, out var args, out var body) == S.Fn && body != null && defineKw.IsIdNamed("macro"))
     {
         var pattern = args.WithTarget(macroName);
         return(CompileMacro(pattern, body, context, node.Attrs));
     }
     return(null);
 }
Пример #4
0
        public static LNode useSymbols(LNode input, IMacroContext context)
        {
            var args_body = context.GetArgsAndBody(true);

            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(args_body.A))
            {
                if (pair.Key.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Write(Severity.Warning, pair.Value, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var           symbols = new Dictionary <Symbol, LNode>();
            VList <LNode> output  = args_body.B.SmartSelect(stmt => stmt.ReplaceRecursive(n => {
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + EcsValidators.SanitizeIdentifier(sym.Name)));
                }
                return(null);
            }));

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(input.Attrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(F.Call(S.Splice, output));
        }
Пример #5
0
        public static LNode useSymbols(LNode input, IMacroContext context)
        {
            bool inType = context.Ancestors.Any(parent => {
                var kind = EcsValidators.SpaceDefinitionKind(parent);
                return(kind != null && kind != S.Namespace);
            });
            var args_body = context.GetArgsAndBody(true);

            return(UseSymbolsCore(input.Attrs, args_body.A, args_body.B, context, inType));
        }
Пример #6
0
        public static LNode @nameof(LNode nameof, IMacroContext context)
        {
            if (nameof.ArgCount != 1)
            {
                return(null);
            }
            Symbol expr = EcsValidators.KeyNameComponentOf(nameof.Args[0]);

            return(F.Literal(expr.Name));
        }
Пример #7
0
        public static LNode replaceFn(LNode node, IMacroContext context1)
        {
            var retType = node.Args[0, LNode.Missing].Name;

            if (retType != _replace && retType != _define)
            {
                return(null);
            }
            LNode replaceKw, macroName, args, body;

            if (EcsValidators.MethodDefinitionKind(node, out replaceKw, out macroName, out args, out body, allowDelegate: false) != S.Fn || body == null)
            {
                return(null);
            }

            MacroMode mode, modes = 0;
            var       leftoverAttrs = node.Attrs.SmartWhere(attr =>
            {
                if (attr.IsId && Loyc.Compatibility.EnumStatic.TryParse(attr.Name.Name, out mode))
                {
                    modes |= mode;
                    return(false);
                }
                return(true);
            });

            LNode pattern     = F.Call(macroName, args.Args).PlusAttrs(leftoverAttrs);
            LNode replacement = body.AsList(S.Braces).AsLNode(S.Splice).PlusAttrs(replaceKw.Attrs);

            replacement.Style &= ~NodeStyle.OneLiner;

            WarnAboutMissingDollarSigns(args, context1, pattern, replacement);

            // Note: we could fill out the macro's Syntax and Description with the
            // pattern and replacement converted to strings, but it's generally a
            // waste of CPU time as those strings are usually not requested.
            var lma = new LexicalMacroAttribute(
                string.Concat(macroName.Name, "(", args.Args.Count.ToString(), " args)"), "", macroName.Name.Name);
            var macroInfo = new MacroInfo(null, lma, (candidate, context2) =>
            {
                MMap <Symbol, LNode> captures = new MMap <Symbol, LNode>();
                VList <LNode> unmatchedAttrs;
                if (candidate.MatchesPattern(pattern, ref captures, out unmatchedAttrs))
                {
                    return(ReplaceCaptures(replacement, captures).PlusAttrsBefore(unmatchedAttrs));
                }
                return(null);
            })
            {
                Mode = modes
            };

            context1.RegisterMacro(macroInfo);
            return(F.Splice());
        }
Пример #8
0
        private static bool IsVar(LNode arg, out LNode type, out Symbol name, out LNode defaultValue)
        {
            name = null;
            LNode nameNode;

            if (!EcsValidators.IsVariableDeclExpr(arg, out type, out nameNode, out defaultValue))
            {
                return(false);
            }
            name = nameNode.Name;
            return(nameNode.IsId);
        }
Пример #9
0
 public void IsPlainCsIdentifierTests()
 {
     IsTrue(EcsValidators.IsPlainCsIdentifier("x"));
     IsTrue(EcsValidators.IsPlainCsIdentifier("aAzZ_"));
     IsTrue(EcsValidators.IsPlainCsIdentifier("_19aAzZ"));
     IsFalse(EcsValidators.IsPlainCsIdentifier("19aAzZ"));
     IsFalse(EcsValidators.IsPlainCsIdentifier("_<>_"));
     IsFalse(EcsValidators.IsPlainCsIdentifier("I'd"));
     IsFalse(EcsValidators.IsPlainCsIdentifier("C#"));
     IsFalse(EcsValidators.IsPlainCsIdentifier("#5"));
     IsFalse(EcsValidators.IsPlainCsIdentifier(""));
 }
Пример #10
0
        static LNode TempVarDecl(LNode value, out LNode tmpId)
        {
            string prefix = value.Name.Name;

            if (!EcsValidators.IsPlainCsIdentifier(prefix))
            {
                prefix = "tmp_";
            }
            else
            {
                prefix += "_";
            }
            return(TempVarDecl(value, out tmpId, prefix));
        }
Пример #11
0
 public static LNode Constructor(LNode cons, IMacroContext context)
 {
     if (cons.ArgCount >= 3 && cons.Args[1].IsIdNamed(S.This))
     {
         var    anc = context.Ancestors;
         LNode  space = anc.TryGet(anc.Count - 3, LNode.Missing), typeName;
         Symbol type = EcsValidators.SpaceStatementKind(space);
         if (type != null && anc[anc.Count - 2] == space.Args[2])
         {
             typeName = space.Args[0];
             return(cons.WithArgChanged(1, F.Id(KeyNameComponentOf(typeName))));
         }
     }
     return(null);
 }
Пример #12
0
        private static LNode CompileTimeMacro(string macroName, LNode node, IMacroContext context, bool alsoRuntime, bool wantPreprocess = true)
        {
            if (node.ArgCount != 1 || !node[0].Calls(S.Braces))
            {
                context.Error(node.Target, "{0} should have a single argument: a braced block.", macroName);
                return(null);
            }

            LNodeList code = node[0].Args;

            if (wantPreprocess)
            {
                if (context.Ancestors.Take(context.Ancestors.Count - 1).Any(
                        n => n.Name.IsOneOf(S.Class, S.Struct, S.Enum, S.Namespace) ||
                        n.Name.IsOneOf(S.Constructor, S.Fn, S.Property, S.Var)))
                {
                    context.Error(node.Target, "{0} is designed for use only at the top level of the file. It will be executed as though it is at the top level: any outer scopes will be ignored.", macroName);
                }

                code = context.PreProcess(code);
            }

            WriteHeaderCommentInSessionLog(node, context.Sink);

            // Remove namespace blocks (not supported by Roslyn scripting)
            LNode namespaceBlock     = null;
            var   codeSansNamespaces = code.RecursiveReplace(RemoveNamespaces);

            LNodeList?RemoveNamespaces(LNode n)
            {
                if (EcsValidators.SpaceDefinitionKind(n, out _, out _, out LNode body) == S.Namespace)
                {
                    namespaceBlock = n;
                    return(body.Args.RecursiveReplace(RemoveNamespaces));
                }
                return(null);
            }

            if (namespaceBlock != null && wantPreprocess)
            {
                context.Warning(namespaceBlock, "The C# scripting engine does not support namespaces. They will be ignored when running at compile time.");
            }

            RunCSharpCodeWithRoslyn(node, codeSansNamespaces, context);

            _roslynSessionLog?.Flush();
            return(alsoRuntime ? F.Splice(code) : F.Splice());
        }
Пример #13
0
        public static LNode defineId(LNode node, IMacroContext context)
        {
            if (node.Args[0, LNode.Missing].Name != _define)
            {
                return(null);
            }
            LNode defineKw, macroId, args, body, initialValue;

            if (!EcsValidators.IsPropertyDefinition(node, out defineKw, out macroId, out args, out body, out initialValue) ||
                body == null || args.ArgCount != 0 || initialValue != null)
            {
                return(null);
            }

            return(RegisterSimpleMacro(node.Attrs, macroId, body, context));
        }
Пример #14
0
        void CheckIsComplexIdentifier(bool?result, LNode expr)
        {
            _testNum++;
            var isCI = EcsValidators.IsComplexIdentifier(expr, ICI.Default, EcsValidators.Pedantics.Strict);

            if (result == null && !isCI)
            {
                return;
            }
            else if (result == isCI)
            {
                return;
            }

            Assert.Fail(string.Format(
                            "IsComplexIdentifier: fail on test #{0} '{1}'. Expected {2}, got {3}",
                            _testNum, expr.ToString(), result, isCI));
        }
Пример #15
0
 public static LNode DetectCurrentNamespace(LNode node, IMacroContext context)
 {
     if (EcsValidators.SpaceDefinitionKind(context.Parent, out LNode name, out _, out _) == S.Namespace)
     {
         var newNamespace     = name.Print(ParsingMode.Expressions);
         var currentNamespace = context.ScopedProperties.TryGetValue(_currentNamespace, null) as Symbol;
         if (currentNamespace == null)
         {
             currentNamespace = (Symbol)newNamespace;
         }
         else
         {
             currentNamespace = (Symbol)(currentNamespace.Name + "." + newNamespace);
         }
         context.OpenMacroNamespaces.Add(currentNamespace);
         context.ScopedProperties[_currentNamespace] = currentNamespace;
     }
     return(null);            // don't alter output
 }
Пример #16
0
        void CheckIsComplexIdentifier(bool?result, LNode expr)
        {
            var np = new EcsNodePrinter(expr, null);

            _testNum++;
            var isCI = EcsValidators.IsComplexIdentifier(expr);

            if (result == null && !isCI)
            {
                return;
            }
            else if (result == isCI)
            {
                return;
            }

            Assert.Fail(string.Format(
                            "IsComplexIdentifier: fail on test #{0} '{1}'. Expected {2}, got {3}",
                            _testNum, expr.ToString(), result, isCI));
        }
Пример #17
0
        public static LNode rule(LNode node, IMacroContext context)
        {
            bool isToken;

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

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

                LNode newBody = ParseRuleBody(node.Args[1], context);
                if (newBody != null)
                {
                    return(node.With(isToken ? _hash_token : _hash_rule,
                                     returnType, name, F.AltList(args), newBody));
                }
            }
            return(null);
        }
Пример #18
0
        private static object RunCSharpCodeWithRoslyn(LNode parent, LNodeList code, IMacroContext context, ParsingMode printMode = null)
        {
            // Note: when using compileTimeAndRuntime, the transforms here affect the version
            //       sent to Roslyn, but not the runtime version placed in the output file.
            code = code.SmartSelectMany(stmt =>
            {
                // Ensure #r gets an absolute path; I don't know what Roslyn does with a
                // relative path (maybe WithMetadataResolver would let me control this,
                // but it's easier not to)
                if ((stmt.Calls(S.CsiReference, 1) || stmt.Calls(S.CsiLoad, 1)) && stmt[0].Value is string fileName)
                {
                    fileName        = fileName.Trim().WithoutPrefix("\"").WithoutSuffix("\"");
                    var inputFolder = context.ScopedProperties.TryGetValue((Symbol)"#inputFolder", "").ToString();
                    var fullPath    = Path.Combine(inputFolder, fileName);
                    return(LNode.List(stmt.WithArgChanged(0, stmt[0].WithValue("\"" + fullPath + "\""))));
                }

                // For each (top-level) LexicalMacro method, call #macro_context.RegisterMacro().
                LNode attribute = null;
                if ((attribute = stmt.Attrs.FirstOrDefault(
                         attr => AppearsToCall(attr, "LeMP", nameof(LexicalMacroAttribute).WithoutSuffix("Attribute")) ||
                         AppearsToCall(attr, "LeMP", nameof(LexicalMacroAttribute)))) != null &&
                    EcsValidators.MethodDefinitionKind(stmt, out _, out var macroName, out _, out _) == S.Fn)
                {
                    var setters = SeparateAttributeSetters(ref attribute);
                    attribute   = attribute.WithTarget((Symbol)nameof(LexicalMacroAttribute));
                    setters.Insert(0, attribute);
                    var newAttribute        = F.Call(S.New, setters);
                    var registrationCommand =
                        F.Call(F.Dot(__macro_context, nameof(IMacroContext.RegisterMacro)),
                               F.Call(S.New, F.Call(nameof(MacroInfo), F.Null, newAttribute, macroName)));
                    return(LNode.List(stmt, registrationCommand));
                }
                return(LNode.List(stmt));
            });

            var outputLocationMapper = new LNodeRangeMapper();
            var options = new LNodePrinterOptions {
                IndentString = "  ", SaveRange = outputLocationMapper.SaveRange
            };
            string codeText = EcsLanguageService.WithPlainCSharpPrinter.Print(code, context.Sink, printMode, options);

            _roslynSessionLog?.WriteLine(codeText);
            _roslynSessionLog?.Flush();

            _roslynScriptState.GetVariable(__macro_context_sanitized).Value = context;
            try
            {
                // Allow users to write messages via MessageSink.Default
                using (MessageSink.SetDefault(new MessageSinkFromDelegate((sev, ctx, msg, args) => {
                    _roslynSessionLog?.Write("{0} from user ({1}): ", sev, MessageSink.GetLocationString(ctx));
                    _roslynSessionLog?.WriteLine(msg, args);
                    context.Sink.Write(sev, ctx, msg, args);
                })))
                {
                    _roslynScriptState = _roslynScriptState.ContinueWithAsync(codeText).Result;
                }
                return(_roslynScriptState.ReturnValue);
            }
            catch (CompilationErrorException e) when(e.Diagnostics.Length > 0 && e.Diagnostics[0].Location.IsInSource)
            {
                // Determine the best location in the source code at which to report the error.
                // Keep in mind that the error may have occurred in a synthetic location not
                // found in the original code, and we cannot report such a location.
                Microsoft.CodeAnalysis.Text.TextSpan range = e.Diagnostics[0].Location.SourceSpan;
                var errorLocation       = new IndexRange(range.Start, range.Length);
                var mappedErrorLocation = outputLocationMapper.FindRelatedNodes(errorLocation, 10)
                                          .FirstOrDefault(p => !p.A.Range.Source.Text.IsEmpty);
                string locationCaveat = "";

                if (mappedErrorLocation.A != null)
                {
                    bool mappedIsEarly = mappedErrorLocation.B.EndIndex <= errorLocation.StartIndex;
                    if (mappedIsEarly || mappedErrorLocation.B.StartIndex >= errorLocation.EndIndex)
                    {
                        locationCaveat = "; " +
                                         "The error occurred at a location ({0}) that doesn't seem to exist in the original code.".Localized(
                            mappedIsEarly ? "after the location indicated".Localized()
                                                                      : "before the location indicated".Localized());
                    }
                }

                // Extract the line where the error occurred, for inclusion in the error message
                int column    = e.Diagnostics[0].Location.GetLineSpan().StartLinePosition.Character;
                int lineStart = range.Start - column;
                int lineEnd   = codeText.IndexOf('\n', lineStart);

                if (lineEnd < lineStart)
                {
                    lineEnd = codeText.Length;
                }
                string line = codeText.Substring(lineStart, lineEnd - lineStart);

                string errorMsg = e.Message + " - in «{0}»{1}".Localized(line, locationCaveat);

                context.Sink.Error(mappedErrorLocation.A ?? parent, errorMsg);
                LogRoslynError(e, context.Sink, parent, compiling: true);
            }
            catch (Exception e)
            {
                while (e is AggregateException ae && ae.InnerExceptions.Count == 1)
                {
                    e = ae.InnerExceptions[0];
                }
                context.Sink.Error(parent, "An exception was thrown from your code:".Localized() +
                                   " " + e.ExceptionMessageAndType());
                LogRoslynError(e, context.Sink, parent, compiling: false);
            }
            return(NoValue.Value);
        }
            Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
            {
                var target           = expr.Target;
                var args             = expr.Args;
                var combinedSequence = LNode.List();

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

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

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

                if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null)
                {
                    // Space definition: class, struct, etc.
                    return(body == null ? stmt : stmt.WithArgChanged(2, EliminateSequenceExpressions(body, true)));
                }
                else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null)
                {
                    // Method definition
                    return(body == null ? stmt : stmt.WithArgChanged(3, EliminateSequenceExpressionsInLambdaExpr(body, retType)));
                }
                else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue))
                {
                    // Property definition
                    stmt = stmt.WithArgChanged(3,
                                               body.WithArgs(part => {
                        if (part.ArgCount == 1 && part[0].Calls(S.Braces))
                        {
                            part = part.WithArgChanged(0, EliminateSequenceExpressions(part[0], false));
                        }
                        return(part);
                    }));
                    if (initValue != null)
                    {
                        var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
                        if (initMethod != null)
                        {
                            stmt = stmt.WithArgChanged(4, initValue);
                            return(LNode.Call((Symbol)"#runSequence", LNode.List(stmt, initMethod)));
                        }
                    }
                    return(stmt);
                }
                else if (stmt.Calls(CodeSymbols.Braces))
                {
                    return(stmt.WithArgs(EliminateSequenceExpressions(stmt.Args, isDeclContext)));
                }
                else if (!isDeclContext)
                {
                    return(EliminateSequenceExpressionsInExecStmt(stmt));
                }
                else if (stmt.CallsMin(S.Var, 2))
                {
                    // Eliminate blocks from field member
                    var results = new List <LNode> {
                        stmt
                    };
                    var vars    = stmt.Args;
                    var varType = vars[0];
                    for (int i = 1; i < vars.Count; i++)
                    {
                        var @var = vars[i];
                        if (@var.Calls(CodeSymbols.Assign, 2) && (name = @var.Args[0]) != null && (initValue = @var.Args[1]) != null)
                        {
                            var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
                            if (initMethod != null)
                            {
                                results.Add(initMethod);
                                vars[i] = vars[i].WithArgChanged(1, initValue);
                            }
                        }
                    }
                    if (results.Count > 1)
                    {
                        results[0] = stmt.WithArgs(vars);
                        return(LNode.List(results).AsLNode(__numrunSequence));
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt);
                }
            }
Пример #21
0
 static string LiteralToIdent(object literal)
 {
     return(EcsValidators.SanitizeIdentifier((literal ?? "null").ToString()));
 }
Пример #22
0
            public LNode EliminateBlockExprs(LNode stmt, bool isDeclContext)
            {
                LNode retType, name, argList, bases, body, initValue;

                if (EcsValidators.SpaceDefinitionKind(stmt, out name, out bases, out body) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(2, EliminateBlockExprs(body, true)));
                }
                else if (EcsValidators.MethodDefinitionKind(stmt, out retType, out name, out argList, out body, true) != null)
                {
                    return(body == null ? stmt : stmt.WithArgChanged(3, EliminateBlockExprs(body, false)));
                }
                else if (EcsValidators.IsPropertyDefinition(stmt, out retType, out name, out argList, out body, out initValue))
                {
                    stmt = stmt.WithArgChanged(3, EliminateBlockExprs(body, false));
                    if (initValue != null)
                    {
                        var initMethod = EliminateRunSeqFromInitializer(retType, name, ref initValue);
                        if (initMethod != null)
                        {
                            stmt = stmt.WithArgChanged(4, initValue);
                            return(LNode.Call(CodeSymbols.Splice, LNode.List(stmt, initMethod)));
                        }
                    }
                    return(stmt);
                }
                else if (!isDeclContext)
                {
                    return(EliminateBlockExprsInExecStmt(stmt));
                }
                else if (stmt.CallsMin(S.Var, 2))
                {
                    var results = new List <LNode> {
                        stmt
                    };
                    var vars    = stmt.Args;
                    var varType = vars[0];
                    for (int i = 1; i < vars.Count; i++)
                    {
                        {
                            var tmp_1 = vars[i];
                            if (tmp_1.Calls(CodeSymbols.Assign, 2) && (name = tmp_1.Args[0]) != null && (initValue = tmp_1.Args[1]) != null)
                            {
                                var initMethod = EliminateRunSeqFromInitializer(varType, name, ref initValue);
                                if (initMethod != null)
                                {
                                    results.Add(initMethod);
                                    vars[i] = vars[i].WithArgChanged(1, initValue);
                                }
                            }
                        }
                    }
                    if (results.Count > 1)
                    {
                        results[0] = stmt.WithArgs(vars);
                        return(LNode.List(results).AsLNode(S.Splice));
                    }
                    return(stmt);
                }
                else
                {
                    return(stmt);
                }
            }
Пример #23
0
        public static LNode CompileMacro(LNode pattern, LNode body, IMacroContext context, LNodeList attrs)
        {
            var modeNodes = attrs.Where(a => Enum.TryParse(a.Name.Name, out MacroMode _));
            // unwrap braces (they're not part of the pattern, they just enable statement syntax in EC#)
            var       pattern_apos = pattern.UnwrapBraces();
            MacroMode modes        = GetMacroMode(ref attrs, pattern_apos);

            // compileTime {...} can recognize macro method definitions.
            // Take advantage of this by generating a macro method which it will register for us.
            LNode macroName   = pattern_apos.Target ?? pattern_apos;
            LNode syntax      = F.Literal(pattern_apos.ToString());
            LNode description = attrs.FirstOrDefault(a => a.Value is string) ?? F.Literal("User-defined macro at {0}".Localized(pattern.Range.Start));

            attrs = attrs.SmartWhere(a => !(a.Value is string));                // remove docstring, if any
            var extraArgs = LNode.List();

            if (macroName.IsId)
            {
                extraArgs.Add(F.Literal(macroName.Name.Name));
            }
            else
            {
                Debug.Assert((modes & (MacroMode.MatchEveryCall | MacroMode.MatchEveryIdentifier | MacroMode.MatchEveryLiteral)) != 0);
            }

            // ensure operator macros like `'+` are not printed as `operator+` which C# will reject
            if (EcsValidators.IsOperator(macroName.Name))
            {
                macroName = F.Id(EcsValidators.SanitizeIdentifier(macroName.Name.Name));
            }

            LNode modesExpr = null;

            foreach (LNode mode in modeNodes)
            {
                modesExpr = LNode.MergeBinary(modesExpr, LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"MacroMode"))).SetStyle(NodeStyle.Operator), mode)).SetStyle(NodeStyle.Operator), S.OrBits);
            }
            if (modesExpr != null)
            {
                extraArgs.Add(LNode.Call(CodeSymbols.Assign, LNode.List(LNode.Id((Symbol)"Mode"), modesExpr)).SetStyle(NodeStyle.Operator));
            }

            LNode lmAttribute = LNode.Call(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"LexicalMacroAttribute"))).SetStyle(NodeStyle.Operator), LNode.List().Add(syntax).Add(description).AddRange(extraArgs));

            if (!body.Calls(S.Braces))
            {
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Return, LNode.List(body)))).SetStyle(NodeStyle.StatementBlock);
            }

            body = context.PreProcess(body);

            // Look for "using" statements above the macro() call
            LNodeList usingDirectives = LNode.List(context.PreviousSiblings.Where(n => n.Calls(S.Import)));

            // Look for "using" and "#r" statements at the beginning of the body
            if (body.Calls(S.Braces))
            {
                var bodyUsings = body.Args.TakeNowWhile(stmt => stmt.Calls(S.Import) || stmt.Calls(S.CsiReference));
                usingDirectives.AddRange(bodyUsings);
                body = body.WithArgs(body.Args.Slice(bodyUsings.Count));
            }

            // Create a matchCode statement unless the pattern is MacroName($(.._)), which always matches
            if (!(pattern_apos.HasSimpleHeadWithoutPAttrs() && pattern_apos.Target.IsId &&
                  pattern_apos.ArgCount == 1 && pattern_apos[0].Equals(LNode.Call(CodeSymbols.Substitute, LNode.List(LNode.Call(CodeSymbols.DotDot, LNode.List(LNode.Id((Symbol)"_"))).SetStyle(NodeStyle.Operator))).SetStyle(NodeStyle.Operator))))
            {
                // Note: the body is already preprocessed; #noLexicalMacros prevents double-processing
                body = LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call((Symbol)"matchCode", LNode.List(LNode.Id((Symbol)"#node"), LNode.Call(CodeSymbols.Braces, LNode.List(LNode.Call(CodeSymbols.Case, LNode.List(pattern)), LNode.Call((Symbol)"#noLexicalMacros", LNode.List(body.AsList(S.Braces))))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special), LNode.Call(CodeSymbols.Return, LNode.List(LNode.Literal(null))))).SetStyle(NodeStyle.StatementBlock);
            }

            return(LNode.Call((Symbol)"compileTime", LNode.List(LNode.Call(CodeSymbols.Braces, LNode.List().AddRange(usingDirectives).Add(LNode.Call(LNode.List().Add(lmAttribute).AddRange(attrs).Add(LNode.Id(CodeSymbols.Public)).Add(LNode.Id(CodeSymbols.Static)), CodeSymbols.Fn, LNode.List(LNode.Id((Symbol)"LNode"), macroName, LNode.Call(CodeSymbols.AltList, LNode.List(LNode.Call(CodeSymbols.Var, LNode.List(LNode.Id((Symbol)"LNode"), LNode.Id((Symbol)"#node"))), LNode.Call(CodeSymbols.Var, LNode.List(LNode.Call(CodeSymbols.Dot, LNode.List(LNode.Call(CodeSymbols.ColonColon, LNode.List(LNode.Id((Symbol)"global"), LNode.Id((Symbol)"LeMP"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"IMacroContext"))).SetStyle(NodeStyle.Operator), LNode.Id((Symbol)"#context"))))), body)))).SetStyle(NodeStyle.StatementBlock))).SetStyle(NodeStyle.Special));
        }
Пример #24
0
            // Bubbles up a call. The returned pair consists of
            // 1. A sequence of statements to run before the call
            // 2. The call with all (outer) #runSequences removed
            Pair <VList <LNode>, LNode> BubbleUp_GeneralCall2(LNode expr)
            {
                var target           = expr.Target;
                var args             = expr.Args;
                var combinedSequence = LNode.List();

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

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

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

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

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

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

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

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

                return(Pair.Create(combinedSequence, expr));
            }
Пример #25
0
        private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode plainArg, out LNode propOrFieldDecl)
        {
            relevantAttribute = null;
            fieldName         = null;
            paramName         = null;
            plainArg          = null;
            propOrFieldDecl   = null;
            LNode _, type, name, defaultValue, propArgs;

            if (EcsValidators.IsPropertyDefinition(arg, out type, out name, out propArgs, out _, out defaultValue) && propArgs.ArgCount == 0)
            {
                // #property(Type, Name<T>, {...})
                relevantAttribute = S.Property;
                fieldName         = EcsNodePrinter.KeyNameComponentOf(name);
                paramName         = ChooseArgName(fieldName);
                if (defaultValue != null)                   // initializer is Args[4]
                {
                    plainArg        = F.Var(type, paramName, defaultValue);
                    propOrFieldDecl = arg.WithArgs(arg.Args.First(4));
                }
                else
                {
                    plainArg        = F.Var(type, paramName);
                    propOrFieldDecl = arg;
                }
                return(true);
            }
            else if (IsVar(arg, out type, out paramName, out defaultValue))
            {
                int a_i = 0;
                foreach (var attr in arg.Attrs)
                {
                    if (attr.IsId)
                    {
                        var a = attr.Name;
                        if (a == _set ||
                            a == S.Public || a == S.Internal || a == S.Protected || a == S.Private ||
                            a == S.ProtectedIn || a == S.Static || a == S.Partial)
                        {
                            relevantAttribute = a;
                            fieldName         = paramName;
                            paramName         = ChooseArgName(fieldName);
                            if (a == _set)
                            {
                                plainArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.Without(attr));
                            }
                            else
                            {
                                // in case of something like "[A] public params T arg = value",
                                // assume that "= value" represents a default value, not a field
                                // initializer, that [A] belongs on the field, except `params`
                                // which stays on the argument.
                                plainArg        = F.Var(type, paramName, defaultValue);
                                propOrFieldDecl = arg;
                                if (arg.Args[1].Calls(S.Assign, 2))
                                {
                                    propOrFieldDecl = arg.WithArgChanged(1,
                                                                         arg.Args[1].Args[0]);
                                }
                                int i_params = arg.Attrs.IndexWithName(S.Params);
                                if (i_params > -1)
                                {
                                    plainArg        = plainArg.PlusAttr(arg.Attrs[i_params]);
                                    propOrFieldDecl = propOrFieldDecl.WithAttrs(propOrFieldDecl.Attrs.RemoveAt(i_params));
                                }
                            }
                            break;
                        }
                    }
                    a_i++;
                }
                return(plainArg != null);
            }
            return(false);
        }
Пример #26
0
        public static LNodeList UseSymbolsCore(LNodeList symbolAttrs, LNodeList options, LNodeList body, IMacroContext context, bool inType)
        {
            // Decode options (TODO: invent a simpler approach)
            string prefix    = "sy_";
            var    inherited = new HashSet <Symbol>();

            foreach (var pair in MacroContext.GetOptions(options))
            {
                if (pair.Key.Name.Name == "prefix" && pair.Value.IsId)
                {
                    prefix = pair.Value.Name.Name;
                }
                else if (pair.Key.Name.Name == "inherit" && pair.Value.Value is Symbol)
                {
                    inherited.Add((Symbol)pair.Value.Value);
                }
                else if (pair.Key.Name.Name == "inherit" && (pair.Value.Calls(S.Braces) || pair.Value.Calls(S.Tuple)) && pair.Value.Args.All(n => n.Value is Symbol))
                {
                    foreach (var arg in pair.Value.Args)
                    {
                        inherited.Add((Symbol)arg.Value);
                    }
                }
                else
                {
                    context.Sink.Warning(pair.Key, "Unrecognized parameter. Expected prefix:id or inherit:{@@A; @@B; ...})");
                }
            }

            // Replace all symbols while collecting a list of them
            var       symbols = new Dictionary <Symbol, LNode>();
            LNodeList output  = body.SmartSelect(stmt =>
                                                 stmt.ReplaceRecursive(n => {
                if (!inType && n.ArgCount == 3)
                {
                    // Since we're outside any type, we must avoid creating symbol
                    // fields. When we cross into a type then we can start making
                    // Symbols by calling ourself recursively with inType=true
                    var kind = EcsValidators.SpaceDefinitionKind(n);
                    if (kind == S.Class || kind == S.Struct || kind == S.Interface || kind == S.Alias || kind == S.Trait)
                    {
                        var body2 = n.Args[2];
                        return(n.WithArgChanged(2, body2.WithArgs(UseSymbolsCore(symbolAttrs, options, body2.Args, context, true))));
                    }
                }
                var sym = n.Value as Symbol;
                if (n.IsLiteral && sym != null)
                {
                    return(symbols[sym] = LNode.Id(prefix + sym.Name));
                }
                return(null);
            })
                                                 );

            // Return updated code with variable declaration at the top for all non-inherit symbols used.
            var _Symbol = F.Id("Symbol");
            var vars    = (from sym in symbols
                           where !inherited.Contains(sym.Key)
                           select F.Call(S.Assign, sym.Value,
                                         F.Call(S.Cast, F.Literal(sym.Key.Name), _Symbol))).ToList();

            if (vars.Count > 0)
            {
                output.Insert(0, F.Call(S.Var, ListExt.Single(_Symbol).Concat(vars))
                              .WithAttrs(symbolAttrs.Add(F.Id(S.Static)).Add(F.Id(S.Readonly))));
            }
            return(output);
        }
Пример #27
0
        private static bool DetectSetOrCreateMember(LNode arg, out Symbol relevantAttribute, out Symbol fieldName, out Symbol paramName, out LNode newArg, out LNode propOrFieldDecl)
        {
            relevantAttribute = null;
            fieldName         = null;
            paramName         = null;
            newArg            = null;
            propOrFieldDecl   = null;
            LNode _, type, name, defaultValue, propArgs;

            if (EcsValidators.IsPropertyDefinition(arg, out type, out name, out propArgs, out _, out defaultValue) && propArgs.ArgCount == 0)
            {
                // #property(Type, Name<T>, {...})
                relevantAttribute = S.Property;
                fieldName         = EcsNodePrinter.KeyNameComponentOf(name);
                paramName         = ChooseArgName(fieldName);
                if (defaultValue != null)                   // initializer is Args[4]
                {
                    newArg          = LNode.Call(S.Var, LNode.List(type, F.Assign(paramName, defaultValue)), arg);
                    propOrFieldDecl = arg.WithArgs(arg.Args.Initial(4));
                }
                else
                {
                    newArg          = LNode.Call(S.Var, LNode.List(type, F.Id(paramName)), arg);
                    propOrFieldDecl = arg;
                }
                DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
                return(true);
            }
            else if (IsVar(arg, out type, out paramName, out defaultValue))
            {
                int a_i = 0;
                foreach (var attr in arg.Attrs)
                {
                    if (attr.IsId)
                    {
                        var a = attr.Name;
                        if (a == _set || FieldCreationAttributes.Contains(a))
                        {
                            relevantAttribute = a;
                            fieldName         = paramName;
                            paramName         = ChooseArgName(fieldName);
                            if (a == _set)
                            {
                                newArg = F.Var(type, paramName, defaultValue).WithAttrs(arg.Attrs.Without(attr));
                            }
                            else
                            {
                                // in case of something like "[A] public params T arg = value",
                                // assume that "= value" represents a default value, not a field
                                // initializer. Most attributes stay on the argument.
                                newArg = arg.WithArgChanged(1,
                                                            defaultValue != null ? F.Assign(paramName, defaultValue) : F.Id(paramName));
                                propOrFieldDecl = LNode.Call(S.Var, LNode.List(type, F.Id(fieldName)), arg);
                                DSOCM_DistributeAttributes(arg.Attrs, ref newArg, ref propOrFieldDecl);
                            }
                            break;
                        }
                    }
                    a_i++;
                }
                return(newArg != null);
            }
            return(false);
        }
Пример #28
0
        Pred NodeToPredCore(LNode expr, Context ctx = Context.Rule)
        {
            if (expr.IsCall)
            {
                bool slash = false, not;
                var  name = expr.Name;
                if (name == S.Tuple)
                {
                    // sequence: (a, b, c)
                    if (expr.Calls(S.Tuple, 1))
                    {
                        return(NodeToPred(expr.Args[0], ctx));
                    }
                    return(TranslateToSeq(expr, ctx));
                }
                else if (name == S.Braces)
                {
                    // User action {block}
                    if (ctx == Context.And || ctx == Context.GateLeft)
                    {
                        _sink.Error(expr, ctx == Context.And ?
                                    "Cannot use an action block inside an '&' or '&!' predicate; these predicates are for prediction only." :
                                    "Cannot use an action block on the left side of a '=>' gate; the left side is for prediction only.");
                    }
                    return(new ActionPred(expr, expr.Args));
                }
                else if (expr.Calls(S.OrBits, 2) || (slash = expr.Calls(S.Div, 2)))
                {
                    // alternatives: a | b, a || b, a / b
                    LNode      lhs = expr.Args[0], rhs = expr.Args[1];
                    BranchMode lhsMode, rhsMode;
                    Pred       left  = BranchToPred(lhs, out lhsMode, ctx);
                    Pred       right = BranchToPred(rhs, out rhsMode, ctx);
                    return(Pred.Or(left, right, slash, expr, lhsMode, rhsMode, _sink));
                }
                else if (expr.Calls(_Star, 1) || expr.Calls(_Plus, 1) || expr.Calls(_Opt, 1))
                {
                    // loop (a+, a*) or optional (a?)
                    return(TranslateLoopExpr(expr, ctx));
                }
                else if (expr.Calls(_Gate, 1) || expr.Calls(_EqGate, 1))
                {
                    // => foo (LES-based parser artifact)
                    return(new Gate(expr, new Seq(F.Missing),
                                    NodeToPred(expr.Args[0], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if (expr.Calls(_Gate, 2) || expr.Calls(_EqGate, 2))
                {
                    if (ctx == Context.GateLeft)
                    {
                        _sink.Error(expr, "Cannot use a gate in the left-hand side of another gate");
                    }

                    return(new Gate(expr, NodeToPred(expr.Args[0], Context.GateLeft),
                                    NodeToPred(expr.Args[1], Context.GateRight))
                    {
                        IsEquivalency = expr.Calls(_EqGate)
                    });
                }
                else if ((not = expr.Calls(_AndNot, 1)) || expr.Calls(_And, 1))
                {
                    return(TranslateAndPred(expr, not));
                }
                else if (expr.Calls(S.NotBits, 1))
                {
                    var subpred = NodeToPred(expr.Args[0], ctx);
                    if (subpred is TerminalPred)
                    {
                        var term = (TerminalPred)subpred;
                        term.Set = term.Set.Inverted().WithoutEOF();
                        return(term);
                    }
                    else
                    {
                        _sink.Error(expr,
                                    "The set-inversion operator ~ can only be applied to a single terminal, not a '{0}'", subpred.GetType().Name);
                        return(subpred);
                    }
                }
                else if ((name.Name.EndsWith(":") || name.Name.EndsWith("=")) && expr.ArgCount == 2)
                {
                    return(TranslateLabeledExpr(expr, ctx));
                }
                else if (expr.Calls(_Any, 2) && expr.Args[0].IsId)
                {
                    return(Translate_any_in_Expr(expr, ctx));
                }
            }

            // expr is an Id, literal, or non-special call
            Rule rule = TryGetRule(expr);

            if (rule != null)
            {
                LNode _, args;
                if (EcsValidators.MethodDefinitionKind(rule.Basis, out _, out _, out args, out _, false) == S.Fn)
                {
                    if (expr.ArgCount > args.ArgCount)                     // don't complain about too few args, in case there are default args (I'm too lazy to check)
                    {
                        _sink.Error(expr, "Rule '{0}' takes {1} arguments ({2} given)", rule.Name, args.ArgCount, expr.ArgCount);
                    }
                }

                return(new RuleRef(expr, rule)
                {
                    Params = expr.Args
                });
            }

            string errorMsg = null;
            Pred   terminal = _helper.CodeToTerminalPred(expr, ref errorMsg);

            if (terminal == null)
            {
                errorMsg = errorMsg ?? "LLLPG: unrecognized expression";
                terminal = new TerminalPred(expr, _helper.EmptySet);
                _sink.Error(expr, errorMsg);
            }
            else if (errorMsg != null)
            {
                _sink.Warning(expr, errorMsg);
            }
            return(terminal);
        }
Пример #29
0
 /// <summary>Retrieves the "key" name component for the nameof(...) macro.</summary>
 /// <remarks>
 /// The key name component of <c>global::Foo!int.Bar!T(x)</c> (in C# notation
 /// global::Foo&lt;int>.Bar&lt;T>(x)) is <c>Bar</c>. This example tree has the
 /// structure <c>((((global::Foo)!int).Bar)!T)(x)</c>).
 /// </remarks>
 public static Symbol KeyNameComponentOf(LNode name)
 {
     return(EcsValidators.KeyNameComponentOf(name));
 }