go: parse.sx scaffold — primary expressions + Go precedence table + 17 tests [consumes-pratt consumes-ast]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s

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>
This commit is contained in:
2026-05-27 07:33:31 +00:00
parent c1baca2e4e
commit 976c6dd0ef
6 changed files with 150 additions and 23 deletions

View File

@@ -28,13 +28,18 @@ trap "rm -f $TMPFILE $OUTFILE" EXIT
# Each suite: name | pass-counter | total-counter
SUITES=(
"lex|go-test-pass|go-test-count"
"parse|go-parse-test-pass|go-parse-test-count"
)
cat > "$TMPFILE" <<'EPOCHS'
(epoch 1)
(load "lib/guest/lex.sx")
(load "lib/guest/ast.sx")
(load "lib/guest/pratt.sx")
(load "lib/go/lex.sx")
(load "lib/go/parse.sx")
(load "lib/go/tests/lex.sx")
(load "lib/go/tests/parse.sx")
EPOCHS
idx=0
@@ -99,7 +104,6 @@ cat > lib/go/scoreboard.json <<JSON
"total_pass": $TOTAL_PASS,
"total": $TOTAL_COUNT,
"suites": [$JSON_SUITES,
{"name":"parse","pass":0,"total":0,"status":"pending"},
{"name":"types","pass":0,"total":0,"status":"pending"},
{"name":"eval","pass":0,"total":0,"status":"pending"},
{"name":"runtime","pass":0,"total":0,"status":"pending"},
@@ -116,8 +120,7 @@ cat > lib/go/scoreboard.md <<MD
| | Suite | Pass | Total |
|---|---|---|---|
$MD_ROWS|| parse | 0 | 0 |
|| types | 0 | 0 |
$MD_ROWS|| types | 0 | 0 |
|| eval | 0 | 0 |
|| runtime | 0 | 0 |
|| stdlib | 0 | 0 |

66
lib/go/parse.sx Normal file
View File

@@ -0,0 +1,66 @@
;; lib/go/parse.sx — Go parser. Tokenises via go-tokenize (lib/go/lex.sx),
;; builds canonical AST nodes per lib/guest/ast.sx, and uses the operator
;; entry shape from lib/guest/pratt.sx for precedence climbing (Pratt).
;;
;; First slice: primary expressions only —
;; int / float / imag / string / rune literal → (ast-literal VALUE)
;; identifier → (ast-var NAME)
;;
;; Subsequent slices add binary operators (via gp-precedence-table +
;; pratt-op-lookup), function calls, type expressions, declarations,
;; and statements.
;;
;; All scanner locals are gp- prefixed (mirrors lib/go/lex.sx's gl- prefix):
;; SX host primitives silently shadow guest-language defines.
(define
go-precedence-table
(list
(list "*" 5 :left)
(list "/" 5 :left)
(list "%" 5 :left)
(list "<<" 5 :left)
(list ">>" 5 :left)
(list "&" 5 :left)
(list "&^" 5 :left)
(list "+" 4 :left)
(list "-" 4 :left)
(list "|" 4 :left)
(list "^" 4 :left)
(list "==" 3 :left)
(list "!=" 3 :left)
(list "<" 3 :left)
(list "<=" 3 :left)
(list ">" 3 :left)
(list ">=" 3 :left)
(list "&&" 2 :left)
(list "||" 1 :left)))
(define
go-parse
(fn
(src)
(let
((gp-tokens (go-tokenize src)) (gp-idx 0))
(define gp-cur (fn () (nth gp-tokens gp-idx)))
(define gp-advance! (fn () (set! gp-idx (+ gp-idx 1))))
(define gp-tok-type (fn () (get (gp-cur) :type)))
(define gp-tok-value (fn () (get (gp-cur) :value)))
(define
gp-parse-primary
(fn
()
(let
((ty (gp-tok-type)) (v (gp-tok-value)))
(cond
(or
(= ty "int")
(= ty "float")
(= ty "imag")
(= ty "string")
(= ty "rune"))
(do (gp-advance!) (ast-literal v))
(= ty "ident")
(do (gp-advance!) (ast-var v))
:else nil))))
(gp-parse-primary))))

View File

@@ -1,10 +1,10 @@
{
"language": "go",
"total_pass": 129,
"total": 129,
"total_pass": 146,
"total": 146,
"suites": [
{"name":"lex","pass":129,"total":129,"status":"ok"},
{"name":"parse","pass":0,"total":0,"status":"pending"},
{"name":"parse","pass":17,"total":17,"status":"ok"},
{"name":"types","pass":0,"total":0,"status":"pending"},
{"name":"eval","pass":0,"total":0,"status":"pending"},
{"name":"runtime","pass":0,"total":0,"status":"pending"},

View File

@@ -1,11 +1,11 @@
# Go-on-SX Scoreboard
**Total: 129 / 129 tests passing**
**Total: 146 / 146 tests passing**
| | Suite | Pass | Total |
|---|---|---|---|
| ✅ | lex | 129 | 129 |
| | parse | 0 | 0 |
| | parse | 17 | 17 |
| ⬜ | types | 0 | 0 |
| ⬜ | eval | 0 | 0 |
| ⬜ | runtime | 0 | 0 |

43
lib/go/tests/parse.sx Normal file
View File

@@ -0,0 +1,43 @@
;; Go parser tests.
(define go-parse-test-count 0)
(define go-parse-test-pass 0)
(define go-parse-test-fails (list))
(define
go-parse-test
(fn
(name actual expected)
(set! go-parse-test-count (+ go-parse-test-count 1))
(if
(= actual expected)
(set! go-parse-test-pass (+ go-parse-test-pass 1))
(append! go-parse-test-fails {:name name :expected expected :actual actual}))))
;; ── primary: literals ─────────────────────────────────────────────
(go-parse-test "int literal" (go-parse "42") (ast-literal "42"))
(go-parse-test "zero literal" (go-parse "0") (ast-literal "0"))
(go-parse-test "hex literal" (go-parse "0xFF") (ast-literal "0xFF"))
(go-parse-test "float literal" (go-parse "3.14") (ast-literal "3.14"))
(go-parse-test "leading-dot float" (go-parse ".5") (ast-literal ".5"))
(go-parse-test "exponent float" (go-parse "1e10") (ast-literal "1e10"))
(go-parse-test "imag literal" (go-parse "2i") (ast-literal "2i"))
(go-parse-test "string literal" (go-parse "\"hi\"") (ast-literal "hi"))
(go-parse-test "empty string" (go-parse "\"\"") (ast-literal ""))
(go-parse-test "raw string" (go-parse "`a\nb`") (ast-literal "a\nb"))
(go-parse-test "rune literal" (go-parse "'a'") (ast-literal "a"))
;; ── primary: identifiers ──────────────────────────────────────────
(go-parse-test "ident: simple" (go-parse "x") (ast-var "x"))
(go-parse-test "ident: underscore" (go-parse "_foo") (ast-var "_foo"))
(go-parse-test "ident: mixed case" (go-parse "fooBar") (ast-var "fooBar"))
(go-parse-test "ident: with digit" (go-parse "x123") (ast-var "x123"))
;; ── primary: non-primary returns nil ──────────────────────────────
(go-parse-test "non-primary: '+'" (go-parse "+") nil)
(go-parse-test "non-primary: empty" (go-parse "") nil)
;; ── report ────────────────────────────────────────────────────────
(define
go-parse-test-summary
(str "parse " go-parse-test-pass "/" go-parse-test-count))

View File

@@ -154,21 +154,28 @@ Progress-log line → push `origin/loops/go`.
done** — hex floats deferred (rare). Move to Phase 2 next.
### Phase 2 — Parser (`lib/go/parse.sx`) ⬜
- Consume `lib/guest/core/pratt.sx` + `lib/guest/core/ast.sx`. Chisel notes
`consumes-pratt consumes-ast`.
- Grammar coverage:
- Declarations: `package`, `import`, `var`, `const`, `type`, `func`
- Types: basic, slice `[]T`, array `[N]T`, map `map[K]V`, chan `chan T`,
func `func(...)...`, struct, interface, pointer `*T`
- Expressions: literals, identifier, call, index `[]`, slice `[a:b]`,
type assertion `v.(T)`, operators
- Statements: `if`/`else`, `for` (C-style + range), `switch`, `select`,
`return`, `defer`, `go`, `break`/`continue`, assign, short-decl `:=`,
send `ch <- v`, recv `<-ch`
- Output: SX-shaped AST per `lib/guest/core/ast.sx` conventions.
- Tests: round-trip parse of hello world, fibonacci, FizzBuzz, goroutine
ping-pong, struct + method.
- **Acceptance:** parse/ suite at 80+ tests.
- [x] Parser scaffold + Go operator-precedence table (entry shape from
`lib/guest/pratt.sx`) + primary expressions (int/float/imag/string/
rune/ident → ast-literal / ast-var via `lib/guest/ast.sx`).
- [ ] Binary operators (Pratt precedence climbing using
`pratt-op-lookup` + Go precedence table).
- [ ] Unary operators (`!x`, `-x`, `^x`, `*p`, `&v`, `<-ch`).
- [ ] Function calls `f(a, b)` and member access `x.field`.
- [ ] Index `x[i]` and slice `x[a:b]`/`x[a:b:c]`.
- [ ] Type assertion `v.(T)`.
- [ ] Type expressions: basic, slice `[]T`, array `[N]T`, map `map[K]V`,
chan `chan T` / `chan<- T` / `<-chan T`, func, struct, interface,
pointer `*T`.
- [ ] Composite literals: `T{...}`, `[]T{...}`, `map[K]V{...}`,
`struct{...}{...}`.
- [ ] Declarations: `package`, `import`, `var`, `const`, `type`, `func`
(including methods, parameter lists, return types).
- [ ] Statements: `if`/`else`, `for` (C-style + range), `switch` (expr +
type), `select`, `return`, `defer`, `go`, `break`/`continue`,
assign, short-decl `:=`, send `ch <- v`, recv `<-ch`.
- [ ] End-to-end: hello-world, fibonacci, FizzBuzz, goroutine ping-pong,
struct + method.
- **Acceptance:** parse/ suite at 80+ tests. Current: 17/17.
### Phase 3 — Bidirectional type checker, MVP (`lib/go/types.sx`) ⬜
- **Independent implementation.** Do NOT use lib/guest/static-types-
@@ -427,6 +434,14 @@ Minimal repro: see `lib/go/lex.sx#gl-oct-digit?` and `#gl-match-op`.
_Newest first. Append one dated entry per commit._
- 2026-05-27 — Phase 2 first slice: `lib/go/parse.sx` parser scaffold.
Defines `go-precedence-table` using `lib/guest/pratt.sx` entry shape
`(NAME PREC ASSOC)` — five Go precedence levels, all left-associative
per Go spec § Operator precedence. `go-parse` tokenises via
`go-tokenize`, then `gp-parse-primary` reads one literal / identifier
and emits a canonical AST node via `lib/guest/ast.sx`'s `ast-literal`
/ `ast-var`. parse 17/17, lex still 129/129, total 146/146.
`[consumes-pratt consumes-ast]`.
- 2026-05-27 — **Phase 1 complete.** Operator-set audit: added missing
`~` (Go 1.18+ generics type-set), exhaustive op coverage tests grouped
by category. Two kit gaps observed and logged in Blockers: