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()); }