Standard extension methods for IMacroContext.
Esempio n. 1
0
        public static LNode use_symbols(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 + EcsNodePrinter.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));
        }
Esempio n. 2
0
        public static LNode UseSymbolsCore(VList <LNode> symbolAttrs, VList <LNode> options, VList <LNode> 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.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  = 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, UseSymbolsCore(symbolAttrs, options, body2.Args, context, true).WithName(body2.Name)));
                    }
                }
                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(F.Call(S.Splice, output));
        }