private void _expandPartialApplication(MacroContext context, int passThrough, List<AstExpr> arguments) { var flatArgs = new List<AstExpr>(arguments.Count); var directives = new List<int>(arguments.Count); //The call target is a "non-argument" in partial application terms. Do not include it in the // stream of directives. flatArgs.Add(arguments[0]); var opaqueSpan = 0; for (var i = 1; i < arguments.Count; i++) { var arg = arguments[i]; AstListLiteral lit; if (i < passThrough || !_isPartialList(arg, out lit)) { flatArgs.Add(arg); opaqueSpan++; } else { flatArgs.AddRange(lit.Elements); if (opaqueSpan > 0) { directives.Add(opaqueSpan); opaqueSpan = 0; } directives.Add(-lit.Elements.Count); } } var ppArgv = AstPartiallyApplicable.PreprocessPartialApplicationArguments(flatArgs); var argc = ppArgv.Count; var mappings8 = new int[argc + directives.Count + 1]; var closedArguments = new List<AstExpr>(argc); AstPartiallyApplicable.GetMapping(ppArgv, mappings8, closedArguments); _mergeDirectivesIntoMappings(directives, mappings8, argc); var mappings32 = PartialApplicationCommandBase.PackMappings32(mappings8); var implCall = context.Factory.Call(context.Invocation.Position, EntityRef.Command.Create(PartialCallStarImplCommand.Alias), context.Call); implCall.Arguments.AddRange(closedArguments); implCall.Arguments.AddRange(mappings32.Select(m => context.CreateConstant(m))); context.Block.Expression = implCall; }
private static AstGetSet _assembleImplCall(MacroContext context, SymbolEntry implementationSymbolEntry, ISourcePosition position) { var internalId = context.CreateConstant(implementationSymbolEntry.InternalId); var interpretation = implementationSymbolEntry.Interpretation.ToExpr(position); var moduleNameOpt = context.CreateConstantOrNull(implementationSymbolEntry.Module); var implCall = context.Factory.IndirectCall(context.Invocation.Position, context.Factory.Reference(context.Invocation.Position, EntityRef.Command.Create( Impl.Alias))); implCall.Arguments.Add(internalId); implCall.Arguments.Add(interpretation); implCall.Arguments.Add(moduleNameOpt); return implCall; }
protected override void DoExpand(MacroContext context) { if (context.Invocation.Arguments.Count == 0) { // Call with no arguments returns null. // The macro system will supply that null. return; } var p = context.Invocation.Arguments[0] as AstPlaceholder; if (context.Invocation.Arguments.Count == 1 && p != null && (p.Index.GetValueOrDefault(0) == 0)) { // call(?0) ⇒ call\perform(?0) context.Block.Expression = GetTrivialPartialApplication(context); return; } if (!context.Invocation.Arguments.Any(_hasPlaceholder)) { // no placeholders, invoke call\perform directly var call = context.Factory.IndirectCall(context.Invocation.Position, context.Factory.Reference(context.Invocation.Position, _callImplementation), context.Call); call.Arguments.AddRange(GetCallArguments(context)); context.Block.Expression = call; return; } // Assemble the invocation of call\*(passThrough,call\perform(?),callArguments...) // Note: this is a get-call in all cases, because we are computing a partial application // whether the programmer wrote a get or a set call needs to be captured by concrete // implementations of partial call wrapers (see Call_Member) var inv = context.Factory.Expand(context.Invocation.Position, EntityRef.MacroCommand.Create(CallStar.Instance.Id)); // Protect the first two arguments inv.Arguments.Add(context.CreateConstant(GetPassThroughArguments(context))); // Indicate the kind of call by passing `call\perform(?)`, a partial application of call var paCall = context.Factory.Call(context.Invocation.Position, _callImplementation, context.Call, new AstPlaceholder(context.Invocation.File, context.Invocation.Line, context.Invocation.Column, 0)); inv.Arguments.Add(paCall); // Pass all the other arguments through inv.Arguments.AddRange(GetCallArguments(context)); context.Block.Expression = inv; }