parse: support parenthesized parallel <*> in pkg/script (grammar parity)#24
Merged
Conversation
…original grammar)
<*> parallel fan-out works in the original internal/agentscript grammar
and always has. The newer pkg/script parser — the path loom uses — was
built >=>-only (an MVP omission), so parallel pipelines that worked in
the CLI failed through loom. This restores parity: the same DSL that
parses in the original runtime now parses in pkg/script. No capability
the project had may be missing from the unified pipeline.
Parser (pkg/script/parse.go):
- Add a Fanout token (<*>) to the lexer.
- Grammar now: pipeline = stage ( >=> stage )* ; stage = call | group ;
group = ( pipeline ( <*> pipeline )* ). A one-branch group is pure
grouping; two+ branches is a parallel fan-out.
- toAST: new stageToAST / groupToAST emit ast.Parallel for multi-branch
groups; single-branch groups unwrap to their inner pipeline.
- INVARIANT PRESERVED: a block body is still always an ast.Pipeline
(even single-stage). Parallel appears only as a stage. (An earlier
draft collapsed single-stage pipelines and broke three existing parse
tests — reverted; the always-Pipeline contract that Lower and the
memory bridge depend on is kept.)
The downstream was already ready: ast.Parallel / resolved.Parallel exist,
Resolve has the ast.Parallel case, and the memory bridge maps
resolved.Parallel → the runtime's *Parallel. So this is purely the parser
catching up.
Verified end to end through the NEW pipeline:
memory static ( ( ssl_check "google.com" <*> dns_lookup "github.com" ) )
→ parse → resolve → RunMemory → BOTH branches execute in parallel.
Also the full complex grammar parses+resolves:
( search >=> analyze <*> search >=> analyze ) >=> merge >=> ask "..."
Tests (parse_parallel_test.go): parallel forms parse; multi-branch group
→ Parallel stage; single group is NOT parallel; complex grammar
parse+resolves. All prior parse tests still pass (regression guard).
CI: vet, gofmt, staticcheck, go test -race ./pkg/..., build pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
<*>parallel fan-out works in the originalinternal/agentscriptgrammar and always has. The newerpkg/scriptparser — the path loom uses — was built>=>-only (an MVP omission documented in the code), so parallel pipelines that ran fine in the CLI failed through loom. This restores parity: the same DSL that parses in the original runtime now parses inpkg/script. No capability the project already had should be missing from the unified pipeline.Parser changes (
pkg/script/parse.go)Fanouttoken (<*>) to the lexerpipeline = stage ( >=> stage )*;stage = call | group;group = ( pipeline ( <*> pipeline )* ). One-branch group = grouping; two+ branches = parallel fan-outtoAST: newstageToAST/groupToASTemitast.Parallelfor multi-branch groupsast.Pipeline;Parallelappears only as a stageDownstream was already ready
ast.Parallel/resolved.Parallelexist,Resolvehas theast.Parallelcase, and the memory bridge mapsresolved.Parallel→ the runtime's*Parallel. This PR is purely the parser catching up.Verified end-to-end (new pipeline)
Complex grammar parses + resolves:
Tests
parse_parallel_test.go: parallel forms parse; multi-branch group → Parallel stage; single group is not parallel; complex grammar parse+resolves. All prior parse tests still pass (regression guard).go test -race ./pkg/...