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