···563563564564 #endregion
565565566566- #region Lambda lifting (capture by value)
567567-568568- /// <summary>
569569- /// Promotes captured variables to function parameters.
570570- /// </summary>
571571- /// <param name = "keepByRef">The set of captured variables that should be kept captured by reference (i.e. not promoted to parameters)</param>
572572- /// <returns>A list of expressions (get self) that should be added to the arguments list of any call to the lifted function.</returns>
573573- internal Func<Parser, IList<AstExpr>> _ToCaptureByValue(IEnumerable<string> keepByRef)
574574- {
575575- keepByRef = new HashSet<string>(keepByRef);
576576- var toPromote = OuterVariables.Except(keepByRef).ToList();
577577-578578- //Declare locally, remove from outer variables and add as parameter to the end
579579- var exprs = new List<Func<Parser, AstExpr>>();
580580- foreach (var outer in toPromote)
581581- {
582582- if (Symbols.TryGet(outer, out var sym))
583583- Symbols.Declare(outer, sym);
584584- OuterVariables.Remove(outer);
585585- Function.Parameters.Add(outer);
586586- {
587587- //Copy the value for capture by value in closure
588588- var byValOuter = outer;
589589- exprs.Add(p =>
590590- {
591591- var pos = p.GetPosition();
592592- return Factory.IndirectCall(
593593- pos,
594594- Factory.Reference(
595595- pos,
596596- Loader.Cache.EntityRefs.GetCached(
597597- EntityRef.Variable.Local.Create(byValOuter)
598598- )
599599- )
600600- );
601601- });
602602- }
603603- }
604604-605605- return p => exprs.Select(e => e(p)).ToList();
606606- }
607607-608608- #endregion
609609-610566 #endregion
611567612568 #region Source Mapping
+1-52
Prexonite/Compiler/Grammar/Parser.Expression.atg
···297297| CoroutineCreation<out expr>
298298| LoopExpr<out expr>
299299| ThrowExpression<out var th> (. expr = th; .)
300300-| LazyExpression<out expr>
301300| PrimaryForGetSetComplex<out expr>
302301| LPopExpr lpar Expr<out expr> (. //This is a hack that makes string interpolation with expressions possible
303302 //The non-verbal token "LPopExpr" (has no character representation) is
···472471 .)
473472.
474473475475-LazyExpression<out AstExpr expr>
476476- (. PFunction func = TargetApplication.CreateFunction(generateLocalId());
477477- ensureHasTarget();
478478- func.Meta[Application.ImportKey] = target.Function.Meta[Application.ImportKey];
479479- func.Meta[PFunction.ParentFunctionKey] = target.Function.Id;
480480- Loader.CreateFunctionTarget(func, target, GetPosition());
481481- CompilerTarget ft = FunctionTargets[func]!;
482482- ISourcePosition position;
483483-484484- //Switch to nested target
485485- _PushScope(ft);
486486- .)
487487-=
488488-lazy (. position = GetPosition(); .)
489489-( lbrace
490490- { Statement<ft.Ast> }
491491- rbrace
492492-| (. AstReturn ret = new AstReturn(this, ReturnVariant.Exit); .)
493493- Expr<out ret.Expression> (. ft.Ast.Add(ret); .)
494494-)
495495- (.
496496- //Turn into capture by value
497497- var cap = ft._ToCaptureByValue(let_bindings(ft));
498498-499499- //Restore parent target
500500- _PopScope(ft);
501501-502502- //Finish nested function
503503- if(errors.count == 0)
504504- {
505505- try {
506506- Ast[func].EmitCode(ft,true,StackSemantics.Effect);
507507- ft.FinishTarget();
508508- } catch(Exception e) {
509509- Loader.ReportMessage(Message.Error(
510510- "Exception during compilation of lazy expression.\n" + e,
511511- GetPosition(),
512512- MessageClasses.ParserInternal));
513513- }
514514- }
515515-516516- //Construct expr (appears in the place of lazy expression)
517517- var clo = Create.CreateClosure(position,EntityRef.Function.Create(func.Id,func.ParentApplication.Module.Name));
518518- var thunk = Create.IndirectCall(position,Create.Reference(position,EntityRef.Command.Create(Engine.ThunkAlias)));
519519- thunk.Arguments.Add(clo);
520520- thunk.Arguments.AddRange(cap(this)); //Add captured values
521521- expr = thunk;
522522- .)
523523-.
524524-525474ThrowExpression<out AstExpr th> (. AstExpr expr; .)
526475=
527476 throw (. var pos = GetPosition(); .)
···655604=
656605 Constant<out expr> (. args.Add(expr); .)
657606| lpar Expr<out expr> rpar (. args.Add(expr); .)
658658-.607607+.
+17-130
Prexonite/Compiler/Grammar/Parser.GlobalScope.atg
···526526 bool isNested = target != null;
527527 bool isCoroutine = false;
528528 bool isMacro = false;
529529- bool isLazy = false;
530530- PFunction? derBody = null; //The derived (coroutine/lazy) body function (carries a different name)
531531- PFunction? derStub = null; //The derived (coroutine/lazy) stub function (carries the name(s) specified)
529529+ PFunction? derBody = null; //The derived coroutine body function (carries a different name)
530530+ PFunction? derStub = null; //The derived coroutine stub function (carries the name(s) specified)
532531 string derId; //The name of the derived stub
533533- CompilerTarget? ct = null; //The compiler target for the function (as mentioned in the source code)
534534- CompilerTarget? cst = null; //The compiler target for a stub (coroutine/lazy)
532532+ CompilerTarget? cst = null; //The compiler target for a coroutine stub
535533 Symbol? symEntry = null;
536534 ISourcePosition position;
537535 bool missingArg = false; //Allow trailing comma, but not (,,) in formal arg list
538536 .)
539537=
540540- ( lazy [function] (. isLazy = true; .)
541541- | function
538538+ ( function
542539 | coroutine (. isCoroutine = true; .)
543540 | macro [function] (. isMacro = true; .)
544541 ) (. position = GetPosition(); .)
···554551 Loader.ReportMessage(Message.Error("Cannot define initialization code inside another function.",position,MessageClasses.IllegalInitializationFunction));
555552 if(isCoroutine)
556553 Loader.ReportMessage(Message.Error("Cannot define initialization code as a coroutine.",position,MessageClasses.IllegalInitializationFunction));
557557- if(isLazy)
558558- Loader.ReportMessage(Message.Error("Cannot define initialization code as a lazy function.",position,MessageClasses.IllegalInitializationFunction));
559554 if(isMacro)
560555 Loader.ReportMessage(Message.Error("Cannot define initialization code as a macro function.",position,MessageClasses.IllegalInitializationFunction));
561556 }
···596591 ensureHasTarget();
597592 localId ??= generateLocalId("inner");
598593 func.Meta[PFunction.LogicalIdKey] = localId;
599599- if(isLazy)
600600- mark_as_let(target.Function,localId);
601594 }
602595603596 Loader.CreateFunctionTarget(func, target, position);
···605598 CompilerTarget ft = FunctionTargets[func]!;
606599607600 //Generate derived stub
608608- if(isCoroutine || isLazy)
601601+ if(isCoroutine)
609602 {
610603 derStub = func;
611604···614607 derBody = TargetApplication.CreateFunction(derId);
615608 Loader.CreateFunctionTarget(derBody, ft, position);
616609 derBody.Meta[PFunction.LogicalIdKey] = id ?? funcId;
617617- if(isCoroutine)
618618- {
619619- derBody.Meta[PFunction.VolatileKey] = true;
620620- derBody.Meta[PFunction.DeficiencyKey] = "Coroutine body can only be executed by VM anyway.";
621621- derBody.Meta[Coroutine.IsCoroutineKey] = true;
622622- }
610610+ derBody.Meta[PFunction.VolatileKey] = true;
611611+ derBody.Meta[PFunction.DeficiencyKey] = "Coroutine body can only be executed by VM anyway.";
612612+ derBody.Meta[Coroutine.IsCoroutineKey] = true;
623613624614 //Swap compiler target references
625615 // -> Compile source code into derived body
626616 // -> Let derived stub have the physical function id
627627- ct = FunctionTargets[derBody];
628617 cst = ft;
629618 }
630619631631- if(isNested) //Link to parent in case of a nested function
632632- {
633633- if(isLazy && ct != null)
634634- ft = ct;
635635- }
636620 .)
637621 [ lpar
638622 [ FormalArg<ft>
···654638 { [comma]
655639 FormalArg<ft>
656640 }
657657- ] (. if(isNested && isLazy){ // keep this assignment for maintainability
658658- // ReSharper disable RedundantAssignment
659659- if(cst == null){
660660- Loader.ReportMessage(Message.Error("Internal compiler error: generated lazy function target not available.",
661661- GetPosition(),
662662- null));
663663- }
664664- ft = cst!;
665665- // ReSharper restore RedundantAssignment
666666- }
667667-641641+ ] (.
668642 if(target == null &&
669643 (!object.ReferenceEquals(func, TargetApplication._InitializationFunction)) &&
670644 (!isNested))
···687661 primaryAlias = null;
688662 }
689663690690- //Target the derived (coroutine/lazy) body instead of the stub
691691- if(isCoroutine || isLazy) {
664664+ //Target the derived coroutine body instead of the stub
665665+ if(isCoroutine) {
692666 if(derBody == null) {
693693- Loader.ReportMessage(Message.Error("Internal compiler error: generated lazy/coroutine function target not available.",
667667+ Loader.ReportMessage(Message.Error("Internal compiler error: generated coroutine function target not available.",
694668 GetPosition(),
695669 null));
696670 }
···732706 func!.Meta[Application.ImportKey] = target.Function.Meta[Application.ImportKey];
733707 }
734708735735- //Copy stub parameters to body of lazy function
736736- if(isLazy && !isNested)
737737- {
738738- foreach(var kvp in cst!.Symbols.LocalDeclarations)
739739- {
740740- var paramId = kvp.Key;
741741- var s = kvp.Value.ToSymbolEntry();
742742- //Lazy functions cannot have ref parameters
743743- if(s.Interpretation != SymbolInterpretations.LocalObjectVariable)
744744- Loader.ReportMessage(Message.Error(
745745- "Lazy functions can only have value parameters (ref is not allowed)",
746746- GetPosition(),
747747- MessageClasses.RefInLazyFunction));
748748- ct!.Function.Parameters.Add(s.InternalId!);
749749- ct.Symbols.Declare(paramId, kvp.Value);
750750- }
751751- }
752709 .)
753710 [ (. _pushLexerState(Lexer.Transfer);
754711 var importBuilder = SymbolStoreBuilder.Create();
···769726 .)
770727 ]
771728 (.
772772- if(isLazy || isCoroutine)
729729+ if(isCoroutine)
773730 {
774731 //Push the stub, because it is the lexical parent of the body
775732 _PushScope(cst!);
···792749 semicolon
793750 ) (. _popLexerState();
794751 _PopScope(FunctionTargets[func!]!);
795795- if(isLazy || isCoroutine)
752752+ if(isCoroutine)
796753 {
797754 _PopScope(cst!);
798755 }
···815772 else
816773 {
817774 try {
818818- //Apply compiler hooks for all kinds of functions (lazy/coroutine/macro)
775775+ //Apply compiler hooks for all kinds of functions (coroutine/macro)
819776 FunctionTargets[func]!.ExecuteCompilerHooks();
820777 //Emit code for top-level block
821778 Ast[func].EmitCode(FunctionTargets[func]!, true, StackSemantics.Effect);
···849806 MessageClasses.ParserInternal));
850807 }
851808 }
852852- else if(isLazy)
853853- {
854854- derStub!.Meta[PFunction.LazyKey] = true;
855855- derStub.Meta["strict"] = true;
856856-857857- //Stub has to be returned into the physical slot mentioned in the source code
858858- func = derStub;
859859-860860- //Generate code for the stub
861861- AstExpr retVal;
862862-863863- if(isNested)
864864- {
865865- //Nested lazy functions need a stub to capture their environment by value (handled by NestedFunction)
866866-867867- //Generate stub code
868868- retVal = Create.CreateClosure(position, EntityRef.Function.Create(ct!.Function.Id,
869869- ct.Function.ParentApplication.Module.Name));
870870-871871- //Inject asthunk-conversion code into body
872872- var inject = derStub.Parameters.Select(par =>
873873- {
874874- var getParam = Create.Call(position, EntityRef.Variable.Local.Create(par));
875875- var asThunkCall = Create.Call(position, EntityRef.Command.Create(Engine.AsThunkAlias));
876876- asThunkCall.Arguments.Add(getParam);
877877- var setParam = Create.Call(position, EntityRef.Variable.Local.Create(par));
878878- setParam.Arguments.Add(asThunkCall);
879879- return (AstNode) setParam;
880880- });
881881- ct.Ast.InsertRange(0,inject);
882882- }
883883- else
884884- {
885885- //Global lazy functions don't technically need a stub. Might be removed later on
886886- var call = Create.Call(position,EntityRef.Function.Create(ct!.Function.Id, TargetModule.Name));
887887-888888- //Generate code for arguments (each wrapped in a `asThunk` command call)
889889- foreach(var par in derStub.Parameters)
890890- {
891891- var getParam = Create.Call(position, EntityRef.Variable.Local.Create(par));
892892-893893- var asThunkCall = Create.Call(position, EntityRef.Command.Create(Engine.AsThunkAlias));
894894-895895- asThunkCall.Arguments.Add(getParam);
896896- call.Arguments.Add(asThunkCall);
897897- }
898898-899899- retVal = call;
900900- }
901901-902902-903903- //Assemble return statement
904904- var ret = new AstReturn(this, ReturnVariant.Exit);
905905- ret.Expression = retVal;
906906-907907- cst!.Ast.Add(ret);
908908-909909- try {
910910- //Emit code for stub
911911- cst.Ast.EmitCode(cst,true,StackSemantics.Effect);
912912- cst.FinishTarget();
913913- } catch(Exception e) {
914914- Loader.ReportMessage(Message.Error(
915915- "Exception during compilation of lazy function stub for " + id + ". " + e,
916916- GetPosition(),
917917- MessageClasses.ParserInternal));
918918- }
919919- }
920809 }
921810 .)
922811.
···928817=
929818 [ var | ref (. isAutodereferenced = true; .)
930819 ] (. idPos = GetPosition(); .)
931931- Id<out id> (. //Note: lazy functions need to copy the
932932- // parameters of the stub to the body!
933933- ft.Function.Parameters.Add(id);
820820+ Id<out id> (. ft.Function.Parameters.Add(id);
934821 var sym = Symbol.CreateDereference(Symbol.CreateReference(
935822 EntityRef.Variable.Local.Create(id),idPos),idPos);
936823 if(isAutodereferenced)
···12491136 .)
12501137 )
12511138) (. _updateNamespace(scope, exportBuilder); .)
12521252-.11391139+.
+1-5
Prexonite/Compiler/Grammar/Parser.Helper.atg
···6161 | then
6262 | uusing
6363 | macro
6464- | lazy
6565- | let
6664 | method
6765 | this
6866 | namespace
···185183| then
186184| uusing //Coco/R does not accept "using" as a token name.
187185| macro
188188-| lazy
189189-| let
190186| method
191187| this
192188| bitAnd
···239235 Version<out v> (. expr = new MExpr.MAtom(GetPosition(), v); .)
240236|
241237 Null (. expr = new MExpr.MAtom(GetPosition(), null); .)
242242-.238238+.
···113113 then
114114 uusing //Coco/R does not accept "using" as a token name.
115115 macro
116116- lazy
117117- let
118116 method
119117 this
120118 namespace
···128126129127/*------------------------------*/
130128/*---- Parser ------------------*/
131131-PRODUCTIONS129129+PRODUCTIONS
-4
Prexonite/Compiler/Lexer.Code.cs
···191191 return Parser._not;
192192 case "macro":
193193 return Parser._macro;
194194- case "lazy":
195195- return Parser._lazy;
196196- case "let":
197197- return Parser._let;
198194 case "namespace":
199195 return Parser._namespace;
200196 case "null":
-1
Prexonite/Compiler/MessageClasses.cs
···5151 public const string LoopExprNotSupported = "P.LoopExprNotSupported";
5252 public const string TupleNotSupported = "P.TupleNotSupported";
5353 public const string FunctionOverridingNotAllowed = "P.FunctionOverridingNotAllowed";
5454- public const string RefInLazyFunction = "P.RefInLazyFunction";
5554 public const string ReturnValueAssignment = "P.ReturnValueAssignment";
5655 public const string CatchWithoutException = "P.CatchWithoutException";
5756
···5858 /// </summary>
5959 public const string ParentFunctionKey = "ParentFunction";
60606161- /// <summary>
6262- /// Indicates whether a function requires its arguments to be lazy.
6363- /// </summary>
6464- public const string LazyKey = "lazy";
6565-6666- /// <summary>
6767- /// The list of let-bound local names (local variables and shared variables)
6868- /// </summary>
6969- public const string LetKey = "let";
7070-7161 #region Construction
72627363 /// <summary>