/// <summary> /// Provides macro environment to its implementing function. The resulting closure /// implements the expansion of the macro. /// </summary> /// <param name = "sctx">The stack context to use for wrapping the context.</param> /// <param name = "func">The implementation of the macro.</param> /// <param name = "context">The macro context for this expansion.</param> /// <returns>A closure that implements the expansion of this macro.</returns> public static Closure PrepareMacroImplementation(StackContext sctx, PFunction func, MacroContext context) { var contextVar = CompilerTarget.CreateReadonlyVariable(sctx.CreateNativePValue(context)); var env = new SymbolTable<PVariable>(1) {{MacroAliases.ContextAlias, contextVar}}; var sharedVariables = func.Meta[PFunction.SharedNamesKey].List.Select(entry => env[entry.Text]). ToArray(); return new Closure(func, sharedVariables); }
private static void _reportException(MacroContext context, IMacroExpander expander, Exception e) { context.ReportMessage(Message.Create(MessageSeverity.Error, String.Format( Resources.MacroSession_ExceptionDuringExpansionOfMacro, expander.HumanId, context.Function.LogicalId, e.Message), context.Invocation.Position, MessageClasses.ExceptionDuringCompilation)); #if DEBUG Console.WriteLine(e); #endif }
private static void _setupDefaultExpression(MacroContext context) { context.Block.Clear(); context.Block.Expression = CreateNeutralExpression(context.Invocation); context.SuppressDefaultExpression = false; }
private PValue _invokeMacroFunction(CompilerTarget target, MacroContext context) { var macro = PrepareMacroImplementation(target.Loader, MacroFunction, context); //Execute macro (argument nodes of the invocation node are passed as arguments to the macro) var macroInvocation = context.Invocation; var arguments = macroInvocation.Arguments.Select(target.Loader.CreateNativePValue).ToArray(); var parentApplication = MacroFunction.ParentApplication; PValue astRaw; try { parentApplication._SuppressInitialization = true; astRaw = macro.IndirectCall(target.Loader, arguments); } finally { parentApplication._SuppressInitialization = false; } return astRaw; }
public AstNode ExpandMacro(AstGetSet invocation, bool justEffect) { var target = Target; var context = new MacroContext(this, invocation, justEffect); //Delegate actual expansion to approriate expander var expander = _getExpander(invocation, target); if (expander != null) { expander.Initialize(target, invocation, justEffect); //Macro invocations need to be unique within a session if (_invocations.Contains(invocation)) { target.Loader.ReportMessage( Message.Create(MessageSeverity.Error, String.Format( Resources.MacroSession_MacroNotReentrant, expander.HumanId), invocation.Position, MessageClasses.MacroNotReentrant)); return CreateNeutralExpression(invocation); } _invocations.Add(invocation); //check if this macro is a partial application (illegal) if (invocation.Arguments.Any(AstPartiallyApplicable.IsPlaceholder)) { //Attempt to expand partial macro try { if (!expander.TryExpandPartially(target, context)) { target.Loader.ReportMessage( Message.Create( MessageSeverity.Error, string.Format( Resources.MacroSession_MacroCannotBeAppliedPartially, expander.HumanId), invocation.Position, MessageClasses.PartialApplicationNotSupported)); return CreateNeutralExpression(invocation); } } catch (Exception e) { _setupDefaultExpression(context); _reportException(context, expander, e); } } else { //Actual macro expansion takes place here try { var cub = target.CurrentBlock; expander.Expand(target, context); if(!ReferenceEquals(cub,target.CurrentBlock)) throw new PrexoniteException("Macro must restore previous lexical scope."); } catch (Exception e) { _setupDefaultExpression(context); _reportException(context, expander, e); } } } //Sanitize output var ast = context.Block; //ensure that there is at least null being pushed onto the stack)) if (!justEffect && ast.Expression == null && !context.SuppressDefaultExpression) ast.Expression = CreateNeutralExpression(invocation); var node = AstNode._GetOptimizedNode(Target, ast); return node; }
/// <summary> /// Expands the macro according to the supplied macro context. /// </summary> /// <param name = "context">Supplies call site information to the macro.</param> public void Expand(MacroContext context) { DoExpand(context); }
private void _implementMergeRules(MacroContext context, AstExpr ce, IEnumerable<AstNode> fs, AstExpr fe) { var contextBlock = context.Block; //cs is already stored in contextBlock, // the rules position cs always at the beginning, thus no need to handle cs. //At this point // { ce } iff (ce ∧ fs ∧ fe) // {tmp = ce} iff (ce ∧ fs ∧ ¬fe) // { } otherwise if (ce != null && fs != null) { if (fe != null) { contextBlock.Add(ce); } else { //Might at a later point become a warning var invocationPosition = context.Invocation.Position; context.ReportMessage(Message.Create(MessageSeverity.Info, String.Format( Resources.MacroFunctionExpander__UsedTemporaryVariable, HumanId), invocationPosition, MessageClasses.BlockMergingUsesVariable)); var tmpV = context.AllocateTemporaryVariable(); //Generate assignment to temporary variable var tmpVRef = context.Factory.Reference(invocationPosition, EntityRef.Variable.Local.Create(tmpV)); var assignTmpV = context.Factory.IndirectCall(invocationPosition,tmpVRef,PCall.Set); assignTmpV.Arguments.Add(ce); contextBlock.Add(assignTmpV); //Generate lookup of computed value ce = context.Factory.IndirectCall(invocationPosition,tmpVRef); } } //At this point // {fs} iff (fs) // { } otherwise if (fs != null) { foreach (var stmt in fs) contextBlock.Add(stmt); } //Finally determine expression // = fe iff (ce ∧ fe) // = ce iff (ce ∧ ¬fe ∧ ¬fs) // = tmp iff (ce ∧ ¬fe ∧ fs) // = ⊥ otherwise if (fe != null) contextBlock.Expression = fe; else if (ce != null) contextBlock.Expression = ce; //if tmp is involved, it has replaced ce else contextBlock.Expression = null; //macro session will cover this case }
public bool TryExpandPartially(CompilerTarget target, MacroContext context) { var pac = MacroCommand as PartialMacroCommand; return pac != null && pac.ExpandPartialApplication(context); }
public void Expand(CompilerTarget target, MacroContext context) { if (MacroFunction == null) return; var astRaw = _invokeMacroFunction(target, context); //Optimize AstNode ast; if (astRaw != null) ast = astRaw.Value as AstNode; else ast = null; var expr = ast as AstExpr; /*Merge with context expression block * cs = Statements from context * ce = Expression from context * fs = Statements from function return value * fe = Expression from function return value * Rules * general: * {cs;ce;fs} = fe * no-fe: * {cs;tmp = ce;fs} = tmp * no-f: * {cs} = ce * no-c: * {fs} = fe */ var contextBlock = context.Block; var macroBlock = ast as AstBlock; // ReSharper disable JoinDeclarationAndInitializer AstExpr ce, fe; IEnumerable<AstNode> fs; // ReSharper restore JoinDeclarationAndInitializer //determine ce ce = contextBlock.Expression; //determine fe if (macroBlock != null) fe = macroBlock.Expression; else if (expr != null) { fe = expr; //cannot be statement at the same time, set ast to null. ast = null; } else fe = null; //determine fs if (macroBlock != null) fs = macroBlock.Count > 0 ? macroBlock.Statements : null; else if (ast != null) fs = new[] {ast}; else fs = null; _implementMergeRules(context, ce, fs, fe); }
protected override int GetPassThroughArguments(MacroContext context) { return 3; }
public void Expand(CompilerTarget target, MacroContext context) { if (MacroCommand == null) return; MacroCommand.Expand(context); }
protected override AstGetSet GetTrivialPartialApplication(MacroContext context) { var pa = base.GetTrivialPartialApplication(context); pa.Arguments.Insert(1, _getIsSetExpr(context)); return pa; }
private static AstExpr _getIsSetExpr(MacroContext context) { return context.CreateConstant(context.Invocation.Call == PCall.Set); }
protected override IEnumerable<AstExpr> GetCallArguments(MacroContext context) { var argv = context.Invocation.Arguments; return argv.Take(1).Append(_getIsSetExpr(context)).Append(argv.Skip(1)); }
protected override void DoExpand(MacroContext context) { _specifyDeficiency(context); base.DoExpand(context); }
public bool TryExpandPartially(CompilerTarget target, MacroContext context) { if (!MacroFunction.Meta[PartialMacroKey].Switch) return false; var successRaw = _invokeMacroFunction(target, context); if (successRaw.Type != PType.Bool) { context.ReportMessage(Message.Create(MessageSeverity.Error, Resources.MacroFunctionExpander_PartialMacroMustIndicateSuccessWithBoolean, context.Invocation.Position, MessageClasses.PartialMacroMustReturnBoolean)); _setupDefaultExpression(context); return false; } return (bool) successRaw.Value; }
private static void _specifyDeficiency(MacroContext context) { context.Function.Meta[PFunction.VolatileKey] = true; MetaEntry deficiency; if (!context.Function.Meta.TryGetValue(PFunction.DeficiencyKey, out deficiency) || deficiency.Text == "") context.Function.Meta[PFunction.DeficiencyKey] = string.Format("Uses {0}.", Engine.Call_TailAlias); }
/// <summary> /// Implementation of the application of this macro. /// </summary> /// <param name = "context">The macro context for this macro expansion.</param> protected abstract void DoExpand(MacroContext context);