Prexonite, a .NET hosted scripting language with a focus on meta-programming and embedded DSLs
0

Configure Feed

Select the types of activity you want to include in your feed.

Remove let and lazy language support

Christian Klauser (Jul 14, 2026, 11:15 PM +0200) d71c085f 839e8ed9

+159 -669
+1 -1
Prexonite Script.sublime-syntax
··· 241 241 - include: verbatim-escape-sequences 242 242 - include: interpolation 243 243 storage-keywords: 244 - - match: '(?i)(?<!\.)\b(var|ref|function|command|macro|lazy)\b(?!\$|''|\\|\p{Alnum})' 244 + - match: '(?i)(?<!\.)\b(var|ref|function|command|macro)\b(?!\$|''|\\|\p{Alnum})' 245 245 scope: storage.type.interpretation.source.pxs 246 246 verbatim-escape-sequences: 247 247 - match: '""'
-44
Prexonite/Compiler/CompilerTarget.cs
··· 563 563 564 564 #endregion 565 565 566 - #region Lambda lifting (capture by value) 567 - 568 - /// <summary> 569 - /// Promotes captured variables to function parameters. 570 - /// </summary> 571 - /// <param name = "keepByRef">The set of captured variables that should be kept captured by reference (i.e. not promoted to parameters)</param> 572 - /// <returns>A list of expressions (get self) that should be added to the arguments list of any call to the lifted function.</returns> 573 - internal Func<Parser, IList<AstExpr>> _ToCaptureByValue(IEnumerable<string> keepByRef) 574 - { 575 - keepByRef = new HashSet<string>(keepByRef); 576 - var toPromote = OuterVariables.Except(keepByRef).ToList(); 577 - 578 - //Declare locally, remove from outer variables and add as parameter to the end 579 - var exprs = new List<Func<Parser, AstExpr>>(); 580 - foreach (var outer in toPromote) 581 - { 582 - if (Symbols.TryGet(outer, out var sym)) 583 - Symbols.Declare(outer, sym); 584 - OuterVariables.Remove(outer); 585 - Function.Parameters.Add(outer); 586 - { 587 - //Copy the value for capture by value in closure 588 - var byValOuter = outer; 589 - exprs.Add(p => 590 - { 591 - var pos = p.GetPosition(); 592 - return Factory.IndirectCall( 593 - pos, 594 - Factory.Reference( 595 - pos, 596 - Loader.Cache.EntityRefs.GetCached( 597 - EntityRef.Variable.Local.Create(byValOuter) 598 - ) 599 - ) 600 - ); 601 - }); 602 - } 603 - } 604 - 605 - return p => exprs.Select(e => e(p)).ToList(); 606 - } 607 - 608 - #endregion 609 - 610 566 #endregion 611 567 612 568 #region Source Mapping
+1 -52
Prexonite/Compiler/Grammar/Parser.Expression.atg
··· 297 297 | CoroutineCreation<out expr> 298 298 | LoopExpr<out expr> 299 299 | ThrowExpression<out var th> (. expr = th; .) 300 - | LazyExpression<out expr> 301 300 | PrimaryForGetSetComplex<out expr> 302 301 | LPopExpr lpar Expr<out expr> (. //This is a hack that makes string interpolation with expressions possible 303 302 //The non-verbal token "LPopExpr" (has no character representation) is ··· 472 471 .) 473 472 . 474 473 475 - LazyExpression<out AstExpr expr> 476 - (. PFunction func = TargetApplication.CreateFunction(generateLocalId()); 477 - ensureHasTarget(); 478 - func.Meta[Application.ImportKey] = target.Function.Meta[Application.ImportKey]; 479 - func.Meta[PFunction.ParentFunctionKey] = target.Function.Id; 480 - Loader.CreateFunctionTarget(func, target, GetPosition()); 481 - CompilerTarget ft = FunctionTargets[func]!; 482 - ISourcePosition position; 483 - 484 - //Switch to nested target 485 - _PushScope(ft); 486 - .) 487 - = 488 - lazy (. position = GetPosition(); .) 489 - ( lbrace 490 - { Statement<ft.Ast> } 491 - rbrace 492 - | (. AstReturn ret = new AstReturn(this, ReturnVariant.Exit); .) 493 - Expr<out ret.Expression> (. ft.Ast.Add(ret); .) 494 - ) 495 - (. 496 - //Turn into capture by value 497 - var cap = ft._ToCaptureByValue(let_bindings(ft)); 498 - 499 - //Restore parent target 500 - _PopScope(ft); 501 - 502 - //Finish nested function 503 - if(errors.count == 0) 504 - { 505 - try { 506 - Ast[func].EmitCode(ft,true,StackSemantics.Effect); 507 - ft.FinishTarget(); 508 - } catch(Exception e) { 509 - Loader.ReportMessage(Message.Error( 510 - "Exception during compilation of lazy expression.\n" + e, 511 - GetPosition(), 512 - MessageClasses.ParserInternal)); 513 - } 514 - } 515 - 516 - //Construct expr (appears in the place of lazy expression) 517 - var clo = Create.CreateClosure(position,EntityRef.Function.Create(func.Id,func.ParentApplication.Module.Name)); 518 - var thunk = Create.IndirectCall(position,Create.Reference(position,EntityRef.Command.Create(Engine.ThunkAlias))); 519 - thunk.Arguments.Add(clo); 520 - thunk.Arguments.AddRange(cap(this)); //Add captured values 521 - expr = thunk; 522 - .) 523 - . 524 - 525 474 ThrowExpression<out AstExpr th> (. AstExpr expr; .) 526 475 = 527 476 throw (. var pos = GetPosition(); .) ··· 655 604 = 656 605 Constant<out expr> (. args.Add(expr); .) 657 606 | lpar Expr<out expr> rpar (. args.Add(expr); .) 658 - . 607 + .
+17 -130
Prexonite/Compiler/Grammar/Parser.GlobalScope.atg
··· 526 526 bool isNested = target != null; 527 527 bool isCoroutine = false; 528 528 bool isMacro = false; 529 - bool isLazy = false; 530 - PFunction? derBody = null; //The derived (coroutine/lazy) body function (carries a different name) 531 - PFunction? derStub = null; //The derived (coroutine/lazy) stub function (carries the name(s) specified) 529 + PFunction? derBody = null; //The derived coroutine body function (carries a different name) 530 + PFunction? derStub = null; //The derived coroutine stub function (carries the name(s) specified) 532 531 string derId; //The name of the derived stub 533 - CompilerTarget? ct = null; //The compiler target for the function (as mentioned in the source code) 534 - CompilerTarget? cst = null; //The compiler target for a stub (coroutine/lazy) 532 + CompilerTarget? cst = null; //The compiler target for a coroutine stub 535 533 Symbol? symEntry = null; 536 534 ISourcePosition position; 537 535 bool missingArg = false; //Allow trailing comma, but not (,,) in formal arg list 538 536 .) 539 537 = 540 - ( lazy [function] (. isLazy = true; .) 541 - | function 538 + ( function 542 539 | coroutine (. isCoroutine = true; .) 543 540 | macro [function] (. isMacro = true; .) 544 541 ) (. position = GetPosition(); .) ··· 554 551 Loader.ReportMessage(Message.Error("Cannot define initialization code inside another function.",position,MessageClasses.IllegalInitializationFunction)); 555 552 if(isCoroutine) 556 553 Loader.ReportMessage(Message.Error("Cannot define initialization code as a coroutine.",position,MessageClasses.IllegalInitializationFunction)); 557 - if(isLazy) 558 - Loader.ReportMessage(Message.Error("Cannot define initialization code as a lazy function.",position,MessageClasses.IllegalInitializationFunction)); 559 554 if(isMacro) 560 555 Loader.ReportMessage(Message.Error("Cannot define initialization code as a macro function.",position,MessageClasses.IllegalInitializationFunction)); 561 556 } ··· 596 591 ensureHasTarget(); 597 592 localId ??= generateLocalId("inner"); 598 593 func.Meta[PFunction.LogicalIdKey] = localId; 599 - if(isLazy) 600 - mark_as_let(target.Function,localId); 601 594 } 602 595 603 596 Loader.CreateFunctionTarget(func, target, position); ··· 605 598 CompilerTarget ft = FunctionTargets[func]!; 606 599 607 600 //Generate derived stub 608 - if(isCoroutine || isLazy) 601 + if(isCoroutine) 609 602 { 610 603 derStub = func; 611 604 ··· 614 607 derBody = TargetApplication.CreateFunction(derId); 615 608 Loader.CreateFunctionTarget(derBody, ft, position); 616 609 derBody.Meta[PFunction.LogicalIdKey] = id ?? funcId; 617 - if(isCoroutine) 618 - { 619 - derBody.Meta[PFunction.VolatileKey] = true; 620 - derBody.Meta[PFunction.DeficiencyKey] = "Coroutine body can only be executed by VM anyway."; 621 - derBody.Meta[Coroutine.IsCoroutineKey] = true; 622 - } 610 + derBody.Meta[PFunction.VolatileKey] = true; 611 + derBody.Meta[PFunction.DeficiencyKey] = "Coroutine body can only be executed by VM anyway."; 612 + derBody.Meta[Coroutine.IsCoroutineKey] = true; 623 613 624 614 //Swap compiler target references 625 615 // -> Compile source code into derived body 626 616 // -> Let derived stub have the physical function id 627 - ct = FunctionTargets[derBody]; 628 617 cst = ft; 629 618 } 630 619 631 - if(isNested) //Link to parent in case of a nested function 632 - { 633 - if(isLazy && ct != null) 634 - ft = ct; 635 - } 636 620 .) 637 621 [ lpar 638 622 [ FormalArg<ft> ··· 654 638 { [comma] 655 639 FormalArg<ft> 656 640 } 657 - ] (. if(isNested && isLazy){ // keep this assignment for maintainability 658 - // ReSharper disable RedundantAssignment 659 - if(cst == null){ 660 - Loader.ReportMessage(Message.Error("Internal compiler error: generated lazy function target not available.", 661 - GetPosition(), 662 - null)); 663 - } 664 - ft = cst!; 665 - // ReSharper restore RedundantAssignment 666 - } 667 - 641 + ] (. 668 642 if(target == null && 669 643 (!object.ReferenceEquals(func, TargetApplication._InitializationFunction)) && 670 644 (!isNested)) ··· 687 661 primaryAlias = null; 688 662 } 689 663 690 - //Target the derived (coroutine/lazy) body instead of the stub 691 - if(isCoroutine || isLazy) { 664 + //Target the derived coroutine body instead of the stub 665 + if(isCoroutine) { 692 666 if(derBody == null) { 693 - Loader.ReportMessage(Message.Error("Internal compiler error: generated lazy/coroutine function target not available.", 667 + Loader.ReportMessage(Message.Error("Internal compiler error: generated coroutine function target not available.", 694 668 GetPosition(), 695 669 null)); 696 670 } ··· 732 706 func!.Meta[Application.ImportKey] = target.Function.Meta[Application.ImportKey]; 733 707 } 734 708 735 - //Copy stub parameters to body of lazy function 736 - if(isLazy && !isNested) 737 - { 738 - foreach(var kvp in cst!.Symbols.LocalDeclarations) 739 - { 740 - var paramId = kvp.Key; 741 - var s = kvp.Value.ToSymbolEntry(); 742 - //Lazy functions cannot have ref parameters 743 - if(s.Interpretation != SymbolInterpretations.LocalObjectVariable) 744 - Loader.ReportMessage(Message.Error( 745 - "Lazy functions can only have value parameters (ref is not allowed)", 746 - GetPosition(), 747 - MessageClasses.RefInLazyFunction)); 748 - ct!.Function.Parameters.Add(s.InternalId!); 749 - ct.Symbols.Declare(paramId, kvp.Value); 750 - } 751 - } 752 709 .) 753 710 [ (. _pushLexerState(Lexer.Transfer); 754 711 var importBuilder = SymbolStoreBuilder.Create(); ··· 769 726 .) 770 727 ] 771 728 (. 772 - if(isLazy || isCoroutine) 729 + if(isCoroutine) 773 730 { 774 731 //Push the stub, because it is the lexical parent of the body 775 732 _PushScope(cst!); ··· 792 749 semicolon 793 750 ) (. _popLexerState(); 794 751 _PopScope(FunctionTargets[func!]!); 795 - if(isLazy || isCoroutine) 752 + if(isCoroutine) 796 753 { 797 754 _PopScope(cst!); 798 755 } ··· 815 772 else 816 773 { 817 774 try { 818 - //Apply compiler hooks for all kinds of functions (lazy/coroutine/macro) 775 + //Apply compiler hooks for all kinds of functions (coroutine/macro) 819 776 FunctionTargets[func]!.ExecuteCompilerHooks(); 820 777 //Emit code for top-level block 821 778 Ast[func].EmitCode(FunctionTargets[func]!, true, StackSemantics.Effect); ··· 849 806 MessageClasses.ParserInternal)); 850 807 } 851 808 } 852 - else if(isLazy) 853 - { 854 - derStub!.Meta[PFunction.LazyKey] = true; 855 - derStub.Meta["strict"] = true; 856 - 857 - //Stub has to be returned into the physical slot mentioned in the source code 858 - func = derStub; 859 - 860 - //Generate code for the stub 861 - AstExpr retVal; 862 - 863 - if(isNested) 864 - { 865 - //Nested lazy functions need a stub to capture their environment by value (handled by NestedFunction) 866 - 867 - //Generate stub code 868 - retVal = Create.CreateClosure(position, EntityRef.Function.Create(ct!.Function.Id, 869 - ct.Function.ParentApplication.Module.Name)); 870 - 871 - //Inject asthunk-conversion code into body 872 - var inject = derStub.Parameters.Select(par => 873 - { 874 - var getParam = Create.Call(position, EntityRef.Variable.Local.Create(par)); 875 - var asThunkCall = Create.Call(position, EntityRef.Command.Create(Engine.AsThunkAlias)); 876 - asThunkCall.Arguments.Add(getParam); 877 - var setParam = Create.Call(position, EntityRef.Variable.Local.Create(par)); 878 - setParam.Arguments.Add(asThunkCall); 879 - return (AstNode) setParam; 880 - }); 881 - ct.Ast.InsertRange(0,inject); 882 - } 883 - else 884 - { 885 - //Global lazy functions don't technically need a stub. Might be removed later on 886 - var call = Create.Call(position,EntityRef.Function.Create(ct!.Function.Id, TargetModule.Name)); 887 - 888 - //Generate code for arguments (each wrapped in a `asThunk` command call) 889 - foreach(var par in derStub.Parameters) 890 - { 891 - var getParam = Create.Call(position, EntityRef.Variable.Local.Create(par)); 892 - 893 - var asThunkCall = Create.Call(position, EntityRef.Command.Create(Engine.AsThunkAlias)); 894 - 895 - asThunkCall.Arguments.Add(getParam); 896 - call.Arguments.Add(asThunkCall); 897 - } 898 - 899 - retVal = call; 900 - } 901 - 902 - 903 - //Assemble return statement 904 - var ret = new AstReturn(this, ReturnVariant.Exit); 905 - ret.Expression = retVal; 906 - 907 - cst!.Ast.Add(ret); 908 - 909 - try { 910 - //Emit code for stub 911 - cst.Ast.EmitCode(cst,true,StackSemantics.Effect); 912 - cst.FinishTarget(); 913 - } catch(Exception e) { 914 - Loader.ReportMessage(Message.Error( 915 - "Exception during compilation of lazy function stub for " + id + ". " + e, 916 - GetPosition(), 917 - MessageClasses.ParserInternal)); 918 - } 919 - } 920 809 } 921 810 .) 922 811 . ··· 928 817 = 929 818 [ var | ref (. isAutodereferenced = true; .) 930 819 ] (. idPos = GetPosition(); .) 931 - Id<out id> (. //Note: lazy functions need to copy the 932 - // parameters of the stub to the body! 933 - ft.Function.Parameters.Add(id); 820 + Id<out id> (. ft.Function.Parameters.Add(id); 934 821 var sym = Symbol.CreateDereference(Symbol.CreateReference( 935 822 EntityRef.Variable.Local.Create(id),idPos),idPos); 936 823 if(isAutodereferenced) ··· 1249 1136 .) 1250 1137 ) 1251 1138 ) (. _updateNamespace(scope, exportBuilder); .) 1252 - . 1139 + .
+1 -5
Prexonite/Compiler/Grammar/Parser.Helper.atg
··· 61 61 | then 62 62 | uusing 63 63 | macro 64 - | lazy 65 - | let 66 64 | method 67 65 | this 68 66 | namespace ··· 185 183 | then 186 184 | uusing //Coco/R does not accept "using" as a token name. 187 185 | macro 188 - | lazy 189 - | let 190 186 | method 191 187 | this 192 188 | bitAnd ··· 239 235 Version<out v> (. expr = new MExpr.MAtom(GetPosition(), v); .) 240 236 | 241 237 Null (. expr = new MExpr.MAtom(GetPosition(), null); .) 242 - . 238 + .
+2 -43
Prexonite/Compiler/Grammar/Parser.Statement.atg
··· 22 22 | GetSetComplex<block> 23 23 | Return<block> 24 24 | Throw<block> 25 - | LetBindingStmt<block> 26 25 . 27 26 28 27 StructureStatement<AstBlock block> ··· 536 535 CompilerTarget ft = FunctionTargets[func]!; 537 536 var pos = GetPosition(); 538 537 var setVar = Create.IndirectCall(pos,Create.Reference(pos,EntityRef.Variable.Local.Create(logicalId)),PCall.Set); 539 - if(func.Meta[PFunction.LazyKey].Switch) 540 - { 541 - //Capture environment by value 542 - var ps = ft._ToCaptureByValue(let_bindings(ft)); 543 - ft._DetermineSharedNames(); //Need to re-determine shared names since 544 - // _ToCaptureByValue does not automatically modify shared names 545 - var clos = Create.CreateClosure(pos, EntityRef.Function.Create(func.Id, 546 - func.ParentApplication.Module.Name)); 547 - var callStub = Create.IndirectCall(pos, clos); 548 - callStub.Arguments.AddRange(ps(this)); 549 - setVar.Arguments.Add(callStub); 550 - } 551 - else if(ft.OuterVariables.Count > 0) 538 + if(ft.OuterVariables.Count > 0) 552 539 { 553 540 setVar.Arguments.Add( Create.CreateClosure(GetPosition(), EntityRef.Function.Create(func.Id, 554 541 func.ParentApplication.Module.Name)) ); ··· 559 546 } 560 547 block.Add(setVar); 561 548 .) 562 - . 563 - 564 - LetBindingStmt<AstBlock block> 565 - = 566 - let LetBinder<block> { comma LetBinder<block> } 567 - . 568 - 569 - LetBinder<AstBlock block> 570 - (. string id; 571 - AstExpr thunk; 572 - ensureHasTarget(); 573 - .) 574 - = (. var position = GetPosition(); .) 575 - Id<out id> (. //Declare local "let" variable 576 - _ensureDefinedLocal(id,id,false,position,false); 577 - mark_as_let(target.Function, id); 578 - if(la.kind == _assign) 579 - _inject(_lazy,"lazy"); 580 - .) 581 - [ assign 582 - LazyExpression<out thunk> 583 - (. 584 - //Assign thunk to that variable 585 - var assign = Create.Call(position, EntityRef.Variable.Local.Create(id), PCall.Set); 586 - assign.Arguments.Add(thunk); 587 - block.Add(assign); 588 - .) 589 - ] 590 549 . 591 550 592 551 TryCatchFinally<AstBlock block> ··· 720 679 | Expr<out expr> (. args.Add(expr); .) 721 680 ) 722 681 ] 723 - . 682 + .
+1 -3
Prexonite/Compiler/Grammar/Scanner.atg
··· 113 113 then 114 114 uusing //Coco/R does not accept "using" as a token name. 115 115 macro 116 - lazy 117 - let 118 116 method 119 117 this 120 118 namespace ··· 128 126 129 127 /*------------------------------*/ 130 128 /*---- Parser ------------------*/ 131 - PRODUCTIONS 129 + PRODUCTIONS
-4
Prexonite/Compiler/Lexer.Code.cs
··· 191 191 return Parser._not; 192 192 case "macro": 193 193 return Parser._macro; 194 - case "lazy": 195 - return Parser._lazy; 196 - case "let": 197 - return Parser._let; 198 194 case "namespace": 199 195 return Parser._namespace; 200 196 case "null":
-1
Prexonite/Compiler/MessageClasses.cs
··· 51 51 public const string LoopExprNotSupported = "P.LoopExprNotSupported"; 52 52 public const string TupleNotSupported = "P.TupleNotSupported"; 53 53 public const string FunctionOverridingNotAllowed = "P.FunctionOverridingNotAllowed"; 54 - public const string RefInLazyFunction = "P.RefInLazyFunction"; 55 54 public const string ReturnValueAssignment = "P.ReturnValueAssignment"; 56 55 public const string CatchWithoutException = "P.CatchWithoutException"; 57 56
-14
Prexonite/Compiler/Parser.Code.cs
··· 1024 1024 return varTok.kind != _var && varTok.kind != _ref; 1025 1025 } 1026 1026 1027 - static IEnumerable<string> let_bindings(CompilerTarget ft) 1028 - { 1029 - var lets = new HashSet<string>(Engine.DefaultStringComparer); 1030 - for (var ct = ft; ct != null; ct = ct.ParentTarget) 1031 - lets.UnionWith(ct.Function.Meta[PFunction.LetKey].List.Select(e => e.Text)); 1032 - return lets; 1033 - } 1034 - 1035 - static void mark_as_let(PFunction f, string local) 1036 - { 1037 - f.Meta[PFunction.LetKey] = (MetaEntry) 1038 - f.Meta[PFunction.LetKey].List.Union([(MetaEntry)local]).ToArray(); 1039 - } 1040 - 1041 1027 #region Assemble Invocation of Symbol 1042 1028 1043 1029 class ReferenceTransformer : SymbolHandler<int, Tuple<Symbol, bool>>
-10
Prexonite/PFunction.cs
··· 58 58 /// </summary> 59 59 public const string ParentFunctionKey = "ParentFunction"; 60 60 61 - /// <summary> 62 - /// Indicates whether a function requires its arguments to be lazy. 63 - /// </summary> 64 - public const string LazyKey = "lazy"; 65 - 66 - /// <summary> 67 - /// The list of let-bound local names (local variables and shared variables) 68 - /// </summary> 69 - public const string LetKey = "let"; 70 - 71 61 #region Construction 72 62 73 63 /// <summary>
-2
Prexonite/Types/StringPType.cs
··· 346 346 "inline", 347 347 "is", 348 348 "label", 349 - "lazy", 350 - "let", 351 349 "local", 352 350 "macro", 353 351 "mod",
+1 -1
PrexoniteTests.Generators/TestConfigurationGenerator.cs
··· 349 349 { 350 350 "PrexoniteTests.Tests.VMTests", 351 351 "PrexoniteTests.Tests.PartialApplication", 352 - "PrexoniteTests.Tests.Lazy", 352 + "PrexoniteTests.Tests.ThunkTests", 353 353 "PrexoniteTests.Tests.Translation", 354 354 "PrexoniteTests.Tests.BuiltInTypeTests", 355 355 "PrexoniteTests.Tests.ShellExtensions",
+1 -2
PrexoniteTests/Tests/Compiler.Parser.cs
··· 4132 4132 } 4133 4133 4134 4134 [Test] 4135 - public void NestedDerivedCapture() 4135 + public void NestedCoroutineCapture() 4136 4136 { 4137 4137 _compile( 4138 4138 """ ··· 4141 4141 { 4142 4142 var x; 4143 4143 coroutine nested = x; 4144 - lazy nested = x; 4145 4144 } 4146 4145 4147 4146 """
-345
PrexoniteTests/Tests/Lazy.cs
··· 1 - using System.Collections.Generic; 2 - using NUnit.Framework; 3 - using Prexonite; 4 - 5 - namespace PrexoniteTests.Tests; 6 - 7 - public abstract class Lazy : VMTestsBase 8 - { 9 - public Lazy() 10 - { 11 - CompileToCil = false; 12 - } 13 - 14 - [Test] 15 - public void SingularThunk() 16 - { 17 - Compile( 18 - """ 19 - 20 - function _idT xT = xT.force; 21 - 22 - function main(n) 23 - { 24 - var t = thunk(->_idT,n); 25 - return t.force; 26 - } 27 - 28 - """ 29 - ); 30 - const int n = 77; 31 - Expect(n, n); 32 - } 33 - 34 - [Test] 35 - public void BasicThunk() 36 - { 37 - Compile( 38 - """ 39 - 40 - function _addT xT yT = xT.force + yT.force; 41 - function _mulT xT yT = xT.force * yT.force; 42 - 43 - function main(x1,y1,x2,y2) 44 - { 45 - //x1*x2 + y1*y2 46 - var t = thunk(->_addT,thunk(->_mulT,x1,x2),thunk(->_mulT,y1,y2)); 47 - return t.force; 48 - } 49 - 50 - """ 51 - ); 52 - const int x1 = 15; 53 - const int x2 = 17; 54 - const int y1 = 5; 55 - const int y2 = -8; 56 - const int dot = x1 * x2 + y1 * y2; 57 - Expect(dot, x1, y1, x2, y2); 58 - } 59 - 60 - [Test] 61 - public void NotExecuted() 62 - { 63 - Compile( 64 - """ 65 - 66 - function _divT xT yT = xT.force / yT.force; 67 - function _throwT = throw "Invalid computation"; 68 - function _consT hT tT = [hT,tT]; 69 - function _headT xsT = xsT.force[0]; 70 - 71 - function main(x1) 72 - { 73 - var t1 = thunk(->_throwT); 74 - var t2 = thunk(->_divT,4,0); 75 - var t3 = thunk(->_divT,2*x1,2); 76 - var t4 = thunk(->_consT,t3,thunk(->_consT,t2,null)); 77 - var t5 = thunk(->_headT,t4); //x1 78 - return t5.force; 79 - } 80 - 81 - """ 82 - ); 83 - 84 - Expect(15, 15); 85 - } 86 - 87 - [Test] 88 - public void Repeat() 89 - { 90 - Compile( 91 - """ 92 - 93 - function _consT hT tT = [hT,tT]; 94 - function _headT xsT = xsT.force[0]; 95 - function _tailT xsT = xsT.force[1]; 96 - function _refT xT = xT.force.(); 97 - function _addT x1 x2 = x1.force + x2.force; 98 - 99 - function main(x1) 100 - { 101 - function repeatT(x) 102 - { 103 - var xsT; 104 - var xsT = thunk(->_consT,x,thunk(->_refT,->xsT)); 105 - return xsT; 106 - } 107 - 108 - var x1s = repeatT(x1); 109 - var y1 = thunk(->_headT,x1s); 110 - var y1s = thunk(->_tailT,x1s); 111 - var z1 = thunk(->_headT,y1s); 112 - var z1s = thunk(->_tailT,y1s); 113 - var a1 = thunk(->_headT,z1s); 114 - 115 - var result = thunk(->_addT,y1,thunk(->_addT,z1,a1)); 116 - 117 - return result.force; 118 - } 119 - 120 - """ 121 - ); 122 - 123 - Expect(3 * 4, 4); 124 - } 125 - 126 - [Test] 127 - public void ByValueCapture() 128 - { 129 - Compile( 130 - """ 131 - 132 - function main(xs) 133 - { 134 - var ys = []; 135 - foreach(var x in xs) 136 - { 137 - ys[] = lazy x; 138 - } 139 - return foldl((acc,z) => acc + z.force,"",ys); 140 - } 141 - 142 - """ 143 - ); 144 - 145 - var xs = new List<PValue> { 1, 2, 3 }; 146 - Expect("123", (PValue)xs); 147 - } 148 - 149 - [Test] 150 - public void AppendLazyFunction() 151 - { 152 - Compile( 153 - """ 154 - 155 - 156 - lazy function cons hdT tlT = hdT : tlT; 157 - lazy function head xsT = xsT.force.Key; 158 - lazy function tail xsT = xsT.force.Value; 159 - 160 - lazy function append xsT ysT 161 - { 162 - if(xsT.force is not null) 163 - { 164 - var xT = head << xsT; 165 - var xsT = tail << xsT; 166 - return cons(xT, lazy append(xsT, ysT)); 167 - } 168 - else 169 - { 170 - return ysT; 171 - } 172 - } 173 - 174 - lazy function to_lazy_list seq 175 - { 176 - var e = seq.force.GetEnumerator(); 177 - lazy function nextElement = 178 - if(e.MoveNext()) 179 - cons(e.Current, thunk(->nextElement)) 180 - else 181 - null; 182 - return nextElement; 183 - } 184 - 185 - coroutine to_seq xsT 186 - { 187 - while((var xs = asthunk(xsT).force) is not null) 188 - { 189 - yield asthunk(xs.Key).force; 190 - xsT = xs.Value; 191 - } 192 - } 193 - 194 - lazy function countlz(xsT) 195 - { 196 - var count = 0; 197 - while((var xs = xsT.force) is not null) 198 - { 199 - count++; 200 - xsT = tail << xsT; 201 - } 202 - return count; 203 - } 204 - 205 - function main(xs, ys, seed) 206 - { 207 - var xsT = to_lazy_list(xs); 208 - var ysT = to_lazy_list(ys); 209 - var zsT = append(xsT, ysT); 210 - println(countlz << xsT); 211 - return 212 - zsT 213 - >> to_seq 214 - >> foldl((a,b) => a + b,seed); 215 - } 216 - 217 - """ 218 - ); 219 - 220 - var xs = new List<PValue> { "a", "b", "c" }; 221 - var ys = new List<PValue> { 1, 2, 3 }; 222 - const string seed = ">>"; 223 - 224 - Expect(">>abc123", (PValue)xs, (PValue)ys, seed); 225 - } 226 - 227 - [Test] 228 - public void SimpleLetBindingStmt() 229 - { 230 - Compile( 231 - """ 232 - 233 - lazy function cons x xs = x : xs; 234 - 235 - lazy function repeat x 236 - { 237 - let xs = cons(x,xs); 238 - return xs; 239 - } 240 - 241 - coroutine to_seq xsT 242 - { 243 - while((var xs = asthunk(xsT).force) is not null) 244 - { 245 - yield asthunk(xs.Key).force; 246 - xsT = xs.Value; 247 - } 248 - } 249 - 250 - function main(x,n) 251 - { 252 - var one = 1; 253 - var zero = 0; 254 - let undefined = one/zero; 255 - return foldl((a,b) => a + b,"<<") << take(n) << to_seq << repeat << x; 256 - } 257 - 258 - 259 - """ 260 - ); 261 - 262 - Expect("<<xxx", "x", 3); 263 - } 264 - 265 - [Test] 266 - public void ArgumentLetBindingStmt() 267 - { 268 - Compile( 269 - """ 270 - 271 - lazy function cons x xs = x : xs; 272 - 273 - coroutine to_seq xsT 274 - { 275 - while((var xs = asthunk(xsT).force) is not null) 276 - { 277 - yield asthunk(xs.Key).force; 278 - xsT = xs.Value; 279 - } 280 - } 281 - 282 - function main(n) 283 - { 284 - let fib = 285 - { 286 - lazy function nextFib x1 x2 287 - { 288 - let x3 = x1.force + x2.force; 289 - return x3 : lazy nextFib(x2,x3); 290 - }; 291 - return cons(1) << lazy nextFib(0,1); 292 - }; 293 - 294 - return foldl((a,b) => a + b,"<<") << take(n) << to_seq << fib; 295 - } 296 - 297 - """ 298 - ); 299 - 300 - Expect("<<11235813", 7); 301 - } 302 - 303 - [Test] 304 - public void OutOfOrder() 305 - { 306 - Compile( 307 - """ 308 - 309 - function main(a) 310 - { 311 - let b; 312 - let c; 313 - let d = b.().(c); 314 - let c = 5; 315 - let b = (my_c) => force(a) + force(my_c); 316 - 317 - return d.(); 318 - } 319 - 320 - """ 321 - ); 322 - 323 - Expect(8, 3); 324 - } 325 - 326 - [Test] 327 - public void MutuallyRecursive() 328 - { 329 - Compile( 330 - """ 331 - 332 - function main(n) 333 - { 334 - let flip, flop, 335 - flip = 1 : flop, 336 - flop = 0 : flip; 337 - return foldl((a,b) => a + b, "<<") << take(n) << toseq(flip); 338 - } 339 - 340 - """ 341 - ); 342 - 343 - Expect("<<101010", 6); 344 - } 345 - }
+129
PrexoniteTests/Tests/ThunkTests.cs
··· 1 + using NUnit.Framework; 2 + using Prexonite; 3 + 4 + namespace PrexoniteTests.Tests; 5 + 6 + public abstract class ThunkTests : VMTestsBase 7 + { 8 + protected ThunkTests() 9 + { 10 + CompileToCil = false; 11 + } 12 + 13 + [Test] 14 + public void SingularThunk() 15 + { 16 + Compile( 17 + """ 18 + 19 + function _idT xT = xT.force; 20 + 21 + function main(n) 22 + { 23 + var t = thunk(->_idT,n); 24 + return t.force; 25 + } 26 + 27 + """ 28 + ); 29 + const int n = 77; 30 + Expect(n, n); 31 + } 32 + 33 + [Test] 34 + public void BasicThunk() 35 + { 36 + Compile( 37 + """ 38 + 39 + function _addT xT yT = xT.force + yT.force; 40 + function _mulT xT yT = xT.force * yT.force; 41 + 42 + function main(x1,y1,x2,y2) 43 + { 44 + //x1*x2 + y1*y2 45 + var t = thunk(->_addT,thunk(->_mulT,x1,x2),thunk(->_mulT,y1,y2)); 46 + return t.force; 47 + } 48 + 49 + """ 50 + ); 51 + const int x1 = 15; 52 + const int x2 = 17; 53 + const int y1 = 5; 54 + const int y2 = -8; 55 + const int dot = x1 * x2 + y1 * y2; 56 + Expect(dot, x1, y1, x2, y2); 57 + } 58 + 59 + [Test] 60 + public void NotExecuted() 61 + { 62 + Compile( 63 + """ 64 + 65 + function _divT xT yT = xT.force / yT.force; 66 + function _throwT = throw "Invalid computation"; 67 + function _consT hT tT = [hT,tT]; 68 + function _headT xsT = xsT.force[0]; 69 + 70 + function main(x1) 71 + { 72 + var t1 = thunk(->_throwT); 73 + var t2 = thunk(->_divT,4,0); 74 + var t3 = thunk(->_divT,2*x1,2); 75 + var t4 = thunk(->_consT,t3,thunk(->_consT,t2,null)); 76 + var t5 = thunk(->_headT,t4); //x1 77 + return t5.force; 78 + } 79 + 80 + """ 81 + ); 82 + 83 + Expect(15, 15); 84 + } 85 + 86 + [Test] 87 + public void Repeat() 88 + { 89 + Compile( 90 + """ 91 + 92 + function _consT hT tT = hT.force : tT; 93 + function _refT xT = xT.force.(); 94 + 95 + function repeatT(x) 96 + { 97 + var xsT; 98 + xsT = thunk(->_consT,x,thunk(->_refT,->xsT)); 99 + return xsT; 100 + } 101 + 102 + function main(x,n) = foldl((a,b) => a + b,0) << take(n) << toseq << repeatT << x; 103 + 104 + """ 105 + ); 106 + 107 + Expect(12, 4, 3); 108 + } 109 + 110 + [Test] 111 + public void RemovedKeywordsAreOrdinaryIdentifiers() 112 + { 113 + Compile( 114 + """ 115 + 116 + function lazy(let) = let; 117 + 118 + function main(value) 119 + { 120 + var let = lazy(value); 121 + return let; 122 + } 123 + 124 + """ 125 + ); 126 + 127 + Expect(42, 42); 128 + } 129 + }
+5 -3
PrexoniteTests/Tests/VMTests.Commands.cs
··· 381 381 Compile( 382 382 """ 383 383 384 - function fib_rec(n, /*lazy*/ fibT, ref combine) = 384 + function fib_rec(n, /*thunk*/ fibT, ref combine) = 385 385 if(n <= 0) 0 else if(n <= 2) 1 else combine(force(fibT).(n-1), force(fibT).(n-2)); 386 386 387 387 function main(n,m, i) 388 388 { 389 389 //Simple, background 390 - let simple_fib = fib_rec(?, simple_fib, ? + ?); 390 + var simple_fib; 391 + simple_fib = thunk(() => fib_rec(?, simple_fib, ? + ?)); 391 392 var f1 = call\async(fib_rec(?),[?, simple_fib, ? + ?]); 392 393 println(var c1 = f1.(n)); 393 394 394 395 //Recursive, background 395 - let rec_fib = call\async(fib_rec(?), [?, rec_fib, (ca,cb) => ca.receive + cb.receive]); 396 + var rec_fib; 397 + rec_fib = thunk(() => call\async(fib_rec(?), [?, rec_fib, (ca,cb) => ca.receive + cb.receive])); 396 398 var f2 = force(rec_fib); 397 399 println(var c2 = f2.(m)); 398 400
-9
Prx/psr/impl/misc.pxs
··· 71 71 return struct; 72 72 } 73 73 74 - function create_lazy\impl(factory) = lazy factory.(); 75 - macro create_lazy() 76 - { 77 - macro\report_warning("create_lazy is deprecated, use the lazy keyword instead."); 78 - var f = ast\func(->create_lazy\impl.Id); 79 - f.Arguments.AddRange(var args); 80 - return f; 81 - } 82 - 83 74 macro swap(x,y) 84 75 { 85 76 if(not (ast_is_GetSet(x) and ast_is_GetSet(y)))