Adds postfix expression forms per Go spec:
f() f(x) f(x, y, z) — function calls
x.y x.y.z obj.method(x) — selector / member access
gp-parse-postfix sits between gp-parse-unary and gp-parse-primary,
so calls and selectors bind tighter than any unary prefix — `-f(x)`
parses as `-(f(x))`, not `(-f)(x)`. Postfix is left-associative
(`x.y.z` = `(x.y).z`), so the loop iterates rather than recurses
on the LHS.
AST shapes:
Call: (ast-app FN ARGS) — canonical
Selector: (list :select OBJ "field") — Go-specific tag
The selector shape is a kit gap — lib/guest/ast.sx ships ast-app but
no ast-select, despite `obj.field` being universal across Go, Rust,
Swift, TS, JS, Python, Ruby, Java, C#. Logged in Blockers; tagging
[proposes-ast]. Worth promoting on the next nominally-typed guest.
parse 49/49, total 178/178.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Go unary prefix operators per Go spec § Operators:
+x -x !x ^x *p &v <-ch
gp-parse-unary is recursive (so !!x and -^x chain correctly) and
sits between gp-parse-expr and gp-parse-primary — unary therefore
always binds tighter than any binary op without needing a unary
entry in the precedence table.
Symbols +, -, *, &, ^ are shared between unary and binary forms;
the positional split (expression-start sees unary, mid-expression
sees binary) disambiguates them cleanly with no lookback.
Unary nodes are single-arg ast-app:
(ast-app (ast-var OP) (list OPERAND))
parse 37/37, total 166/166.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gp-parse-expr / gp-pratt-loop implement classic Pratt climbing
against go-precedence-table (entry shape from lib/guest/pratt.sx).
The kit gives us pratt-op-lookup + accessors; the climbing loop
itself stays per-language (per kit header — Lua and Prolog have
opposite conventions).
Left-associative ops raise the right-recursion min by 1; right-
associative would keep prec. All Go binary operators are left-assoc.
AST shape: a binary node is emitted as
(ast-app (ast-var OP) [LHS RHS])
— canonical ast-app rather than a Go-specific binary node, since a
future evaluator can recognise operator-named apps without losing
information.
Coverage: equal-prec left-to-right, * tighter than +, && tighter
than ||, comparison tighter than &&, long left-assoc chains, mixed
literal+ident operands.
parse 26/26, total 155/155.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Starts Phase 2. lib/go/parse.sx defines:
* go-precedence-table — Go's five operator-precedence levels in the
(NAME PREC ASSOC) entry shape from lib/guest/pratt.sx, ready for the
binary-operator iteration to consume via pratt-op-lookup.
* go-parse(src) — tokenises and parses ONE primary expression: int,
float, imag, string, rune literals become (ast-literal VALUE);
identifiers become (ast-var NAME). Built directly on lib/guest/ast.sx
constructors — no intermediate AST shape.
Conformance.sh extended to load lib/guest/{ast,pratt}.sx and run the
new parse suite. Scoreboard cleanup: drop the "pending" parse row since
the suite is now real.
parse 17/17 (lex still 129/129). Total 146/146.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the missing tilde operator '~' (Go 1.18+ generics type-set
constraint, e.g. 'interface { ~int | ~float64 }') to the longest-match
operator table. Adds an exhaustive 'op-audit:' test block covering
every Go operator/punctuation token by category — arithmetic +
assignment, bitwise + assignment, comparison + logical, decls /
arrows / variadic / inc-dec, punctuation, and tilde.
Phase 1 (tokenizer) is now complete. Two kit gaps surfaced and logged
in plans/go-on-sx.md Blockers for the substrate maintainer / next
statically-typed guest loop:
* lib/guest/lex.sx lacks lex-oct-digit? / lex-bin-digit?
(we rolled local gl-* equivalents for 0o.. and 0b.. literals).
* lib/guest/lex.sx lacks a table-driven longest-prefix operator
matcher; our gl-match-op is a 25-clause cond ladder. Rust/Swift/TS
will each hit the same shape with 50+ ops apiece.
lex 129/129. Phase 2 (parser) next.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Go raw string literals per Go spec § String literals:
backtick-delimited, no escape processing, may span multiple
lines, '\r' chars discarded from the value.
gl-read-raw-string! mirrors gl-read-string! but skips escape
handling and the \r filter. scan! routes the leading backtick
to it; emits "string" type (same as interpreted strings — no
need to distinguish at parse/type time).
lex 123/123.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Go float and imaginary literal forms per Go spec § Floating-point
literals and § Imaginary literals:
3.14 .5 1. 1e10 1.5e-3 2.0e+2 1E5 (floats)
2i 3.14i 1e2i (imag)
gl-read-number! returns one of "int" / "float" / "imag"; gl-finish-number!
factors out the post-mantissa exponent + 'i' suffix logic so the int /
float / leading-dot-float paths all share it. scan! adds a .<digit>
branch ahead of the operator matcher so '.5' tokenises as float.
ASI trigger list extended to include float + imag (Go spec § Semicolons:
all literal types trigger).
Greedy-grammar pin (a single test '1.method' lexes as float ident),
since the Go spec says the '.' after a digit always belongs to the
number, never to a following identifier.
Hex floats (0x1.fp0) deferred — not commonly used.
lex 114/114.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds prefixed integer forms per Go spec § Integer literals:
0x.. / 0X.. (hex), 0b.. / 0B.. (binary), 0o.. / 0O.. (octal),
legacy 0123 octal also accepted. Underscores allowed between digits
in any run; lexer is permissive (parser/types phase can enforce
strict placement).
Dispatch lives in gl-read-number! against the first 1-2 chars;
hex digit run consumes lex-hex-digit? from lib/guest/lex.sx. Octal
and binary use local gl-oct-digit?/gl-bin-digit? — narrow enough
that promoting them to the kit is premature.
lex 92/92.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First Go-on-SX iteration. Tokenizer consumes lib/guest/lex.sx character-class
predicates. Automatic semicolon insertion per Go spec § Semicolons fires on
newline, EOF, and block comments containing a newline, after
ident/int/string/rune/{break,continue,fallthrough,return}/{++,--,),],}}.
Scoreboard + conformance.sh wired; lex 78/78. Plan Phase 1 sub-items
checked; floats/raw-strings/hex-ints still ⬜.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- go-on-sx.md: rewrite of 2026-04-26 draft to integrate lib/guest framework.
Adds Phase 3 (independent bidirectional type checker — first static-typed
guest), Phase 10 (extraction enabler), chisel discipline, conformance
scoreboard model. Phases 1-2 now consume lib/guest/core lex+pratt+ast.
- lib-guest-scheduler.md: NEW. Extraction plan for the fork/yield/block/
resume scheduler shared by Erlang (addressed processes + mailboxes) and
Go (anonymous channels + goroutines). Two-language rule blocks extraction
until both consumers independently work; rejected-extraction is a valid
outcome.
- lib-guest-static-types-bidirectional.md: NEW. Sister to lib/guest/hm.sx.
Bidirectional checker kit (synth/check judgments, pluggable subtype +
unify) for the languages HM doesn't fit — Go, Rust, TS, Swift, Kotlin,
Scala 3, Hack. First consumer: Go-on-SX. Second TBD; recommendation
TypeScript.
The three plans cross-reference each other. Go-on-SX implements scheduler +
checker independently of the kits; extraction is its own workstream once
two consumers exist.