diff --git a/doc/lang/flow.md b/doc/lang/flow.md index b414c769..0299c31b 100644 --- a/doc/lang/flow.md +++ b/doc/lang/flow.md @@ -61,6 +61,7 @@ Run all the bodies in parallel. Complete when all bodies have completed. This example uses two nested `fork` constructs. The second is synchronized with the first as it waits for an event the first branch is to emit. + ### halt ### @@ -73,17 +74,30 @@ Loop ---- Loops are so central HipHop program control flow that HipHop proposes -several loop constructs. +several loop constructs, see [derived forms](#derived-forms). These are +all based on a combination of the elementary `loop` construct and +[lexical espaces](#lexical-escapes). + ### loop { ... } ### ☆ [Formal syntax](../syntax/hiphop.bnf#HHLoop) -Implements an infinite loop +This is the basis loop construct that implements an infinite loop ★ Example: [sync1.hh.js](../../test/sync1.hh.js) +A loop can be interrupted by exiting with a `break` statement. + +★ Example: [trap-loop.hh.js](../../test/trap-loop.hh.js) + +> [!NOTE] +> It is not permitted to implement _instantaneous_ loops, that is +> a loop for which two iterations may execute during the same reaction. +> This will be rejected by the compiler. All loops must have a `yield` +> statement in their control flow. + Suspension ---------- diff --git a/preprocessor/parser.js b/preprocessor/parser.js index a0708aed..eb23f121 100644 --- a/preprocessor/parser.js +++ b/preprocessor/parser.js @@ -3,7 +3,7 @@ /* ------------------------------------------------------------- */ /* Author : Manuel Serrano */ /* Creation : Tue Jul 17 17:53:13 2018 */ -/* Last change : Fri Dec 22 11:12:06 2023 (serrano) */ +/* Last change : Fri Dec 22 16:50:29 2023 (serrano) */ /* Copyright : 2018-23 Manuel Serrano */ /* ------------------------------------------------------------- */ /* HipHop parser based on the genuine Hop parser */ @@ -825,7 +825,7 @@ function parsePragma(token) { loc, astutils.J2SString(loc, "apply"), astutils.J2SMethod(loc, "atomfun", [], block, self(loc))); - const tag = tagInit("hop", loc); + const tag = tagInit("pragma", loc); const attrs = astutils.J2SObjInit(loc, [locInit(loc), tag, appl]); const node = astutils.J2SCall(loc, hhref(loc, "ATOM"), null, [attrs].concat(accessors)); diff --git a/test/README.md b/test/README.md index ea056322..87292236 100644 --- a/test/README.md +++ b/test/README.md @@ -21,7 +21,7 @@ npm test 2. Using the builtin driver --------------------------- -Go into the `tests` directory and execute +Go into the `test` directory and execute ```node --enable-source-maps --no-warnings --loader ../lib/hiphop-loader.mjs ./all-test.js ``` @@ -29,7 +29,7 @@ Go into the `tests` directory and execute 3. Running an individual test ----------------------------- -Go into the `tests` directory and execute +Go into the `test` directory and execute ```node --enable-source-maps --no-warnings --loader ../lib/hiphop-loader.mjs ./all.test.js -- ./ ``` diff --git a/test/simple.hh.js b/test/simple.hh.js index de96f55a..51cecb44 100644 --- a/test/simple.hh.js +++ b/test/simple.hh.js @@ -1,12 +1,9 @@ -"use @hop/hiphop"; -"use hopscript"; - import * as hh from "@hop/hiphop"; import { format } from "util"; hiphop module prg() { inout OK, O, A, B, C, BBBB, NEVER; in STOP; in AIN; - abort( STOP.now ) { + abort(STOP.now) { loop { JMP: { emit O(); @@ -18,10 +15,10 @@ hiphop module prg() { } emit O(); - if( O.now ) emit OK(); + if(O.now) emit OK(); yield; emit O(); - if( O.now ) emit OK(); + if(O.now) emit OK(); yield; fork { @@ -37,10 +34,10 @@ hiphop module prg() { } emit NEVER(); yield; - await( STOP.now ); + await(STOP.now); emit B(); - await( AIN.now ); - if( AIN.now ) { + await(AIN.now); + if(AIN.now) { emit C(); } } @@ -54,7 +51,7 @@ hiphop module prg2() { yield; emit O(); - if( O.now ) { + if(O.now) { emit V(); } } @@ -73,14 +70,14 @@ hiphop module prg3() { hiphop module prg4() { out OK, O; emit O(); - if( O.now ) { + if(O.now) { emit OK(); } } hiphop module prg5() { out OK, O; - if( O.now ) { + if(O.now) { emit OK(); } } @@ -106,7 +103,7 @@ mach.react(); mach.outbuf += "will react" + "\n"; mach.react(); mach.outbuf += "will react STOP" + "\n"; -mach.inputAndReact( "STOP", undefined ); +mach.inputAndReact("STOP", undefined); mach.outbuf += "will react" + "\n"; mach.react(); mach.outbuf += "will react" + "\n"; @@ -116,13 +113,13 @@ mach.react(); mach.outbuf += "will react" + "\n"; mach.react(); mach.outbuf += "will react STOP" + "\n"; -mach.inputAndReact( "STOP", undefined ) +mach.inputAndReact("STOP", undefined) mach.outbuf += "will react" + "\n"; -mach.inputAndReact( "AIN", undefined ) +mach.inputAndReact("AIN", undefined) mach.outbuf += "will react" + "\n"; mach.react(); -const m2 = new hh.ReactiveMachine( prg2, "2" ); +const m2 = new hh.ReactiveMachine(prg2, "2"); m2.debug_emitted_func = val => { mach.outbuf += format(val) + "\n"; } @@ -133,7 +130,7 @@ m2.react(); m2.react(); m2.react(); -const m3 = new hh.ReactiveMachine( prg3, "3" ); +const m3 = new hh.ReactiveMachine(prg3, "3"); m3.debug_emitted_func = val => { mach.outbuf += format(val) + "\n"; } @@ -144,7 +141,7 @@ m3.react(); m3.react(); m3.react(); -const m4 = new hh.ReactiveMachine( prg4, "4" ); +const m4 = new hh.ReactiveMachine(prg4, "4"); m4.debug_emitted_func = val => { mach.outbuf += format(val) + "\n"; } @@ -155,7 +152,7 @@ m4.react() m4.react() m4.react() -const m5 = new hh.ReactiveMachine( prg5, "5" ); +const m5 = new hh.ReactiveMachine(prg5, "5"); m5.debug_emitted_func = val => { mach.outbuf += format(val) + "\n"; } diff --git a/test/trap-await-parallel.hh.js b/test/trap-await-parallel.hh.js index 75c388d9..f6b3157d 100644 --- a/test/trap-await-parallel.hh.js +++ b/test/trap-await-parallel.hh.js @@ -4,15 +4,15 @@ hiphop module prg() { inout A, B; EXIT: fork { await(A.now); - hop { mach.outbuf += "A\n"; } + pragma { mach.outbuf += "A\n"; } break EXIT; } par { await(B.now); - hop { mach.outbuf += "B\n"; } + pragma { mach.outbuf += "B\n"; } break EXIT; } - hop { mach.outbuf += "end\n"; } + pragma { mach.outbuf += "end\n"; } } export const mach = new hh.ReactiveMachine(prg); diff --git a/test/trap-error.hh.js b/test/trap-error.hh.js index 05ca40c4..7d36dee3 100644 --- a/test/trap-error.hh.js +++ b/test/trap-error.hh.js @@ -1,6 +1,3 @@ -"use @hop/hiphop"; -"use hopscript" - import * as hh from "@hop/hiphop"; hiphop module sub() { diff --git a/test/trap-loop.hh.js b/test/trap-loop.hh.js new file mode 100644 index 00000000..a00d007e --- /dev/null +++ b/test/trap-loop.hh.js @@ -0,0 +1,20 @@ +import * as hh from "@hop/hiphop"; + +hiphop module prg() { + out tick; + signal cnt = 5; + + exit: loop { + emit tick("loop" + cnt.preval); + emit cnt(cnt.preval - 1); + + yield; + + if (cnt.preval === 0) { + break exit; + } + } + emit tick("done"); +} + +export const mach = new hh.ReactiveMachine(prg, "TRAP-LOOP"); diff --git a/test/trap-loop.in b/test/trap-loop.in new file mode 100644 index 00000000..5d720d1f --- /dev/null +++ b/test/trap-loop.in @@ -0,0 +1,6 @@ +; +; +; +; +; +; diff --git a/test/trap-loop.out b/test/trap-loop.out new file mode 100644 index 00000000..edb6377a --- /dev/null +++ b/test/trap-loop.out @@ -0,0 +1,12 @@ +TRAP-LOOP> ; +--- Output: tick("loop5") +TRAP-LOOP> ; +--- Output: tick("loop4") +TRAP-LOOP> ; +--- Output: tick("loop3") +TRAP-LOOP> ; +--- Output: tick("loop2") +TRAP-LOOP> ; +--- Output: tick("loop1") +TRAP-LOOP> ; +--- Output: tick("done") diff --git a/test/trap-suspend.hh.js b/test/trap-suspend.hh.js index d16e301f..6c54190c 100644 --- a/test/trap-suspend.hh.js +++ b/test/trap-suspend.hh.js @@ -10,7 +10,7 @@ export const mach = new hh.ReactiveMachine( yield; } } - hop { mach.outbuf += "exit trap\n"; } + pragma { mach.outbuf += "exit trap\n"; } } ); mach.outbuf = "";