go: eval.sx — method dispatch + unary + e2e programs + 14 tests; Phase 4 bar crossed [nothing]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
Phase 4 cont. The crossings:
* Method dispatch — Methods record under #method/TYPE/NAME (same
mangled-key scheme the type checker uses, intentionally so eval
and type checker can converge on a shared method-table protocol
later). go-eval-method-call: lookup the receiver type's method,
bind receiver param to the struct value, evaluate body. Value and
pointer receivers treated the same in v0 (pointer semantics not
modelled yet).
* Method-call dispatch — In go-eval's :app branch, head=:select
routes to go-eval-method-call. If the receiver is not a struct,
falls back to the field-as-callable path.
* Unary prefix ops — go-eval's :app branch checks for 1-arg :var
head with op name "-" / "+" / "!". (Other unary ops like
*p / &v / <-ch / ^x deferred until pointer / channel / bitwise
semantics arrive.)
End-to-end programs verified:
* recursive fib(10) = 55
* struct + method + iterative loop (counter bump 7 times)
* linear search (returns index or -1)
* factorial via method on Counter (= 120)
* count odd numbers in 1..10 = 5
**Phase 4 acceptance bar (80+) crossed: eval 80/80, total 457/457.**
Remaining Phase 4 work (closures, multi-return, full slice triple,
pointer semantics) refines but doesn't gate Phase 5 (goroutines).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -779,6 +779,8 @@
|
||||
(go-eval-inc-dec env stmt)
|
||||
(and (list? stmt) (= (first stmt) :func-decl))
|
||||
(go-eval-func-decl env stmt)
|
||||
(and (list? stmt) (= (first stmt) :method-decl))
|
||||
(go-eval-method-decl env stmt)
|
||||
(and (list? stmt) (= (first stmt) :type-decl))
|
||||
(go-eval-type-decl env stmt)
|
||||
:else
|
||||
@@ -787,6 +789,77 @@
|
||||
(go-eval-error? v) v
|
||||
:else env)))))
|
||||
|
||||
(define
|
||||
go-eval-method-decl
|
||||
;; (:method-decl RECV NAME PARAMS RESULTS BODY) — register the method
|
||||
;; under #method/RECV-TYPE-NAME/METHOD-NAME, value is a :go-method.
|
||||
(fn (env stmt)
|
||||
(let ((recv (nth stmt 1)) (name (nth stmt 2))
|
||||
(params (nth stmt 3)) (body (nth stmt 5)))
|
||||
(let ((recv-names (nth recv 1)) (recv-ty (nth recv 2)))
|
||||
(let ((recv-name
|
||||
(cond
|
||||
(= (len recv-names) 0) "_"
|
||||
:else (first recv-names))))
|
||||
(let ((type-name (go-extract-recv-ty-name recv-ty)))
|
||||
(cond
|
||||
(= type-name nil) env
|
||||
:else
|
||||
(go-env-extend env
|
||||
(str "#method/" type-name "/" name)
|
||||
(list :go-method recv-name params body)))))))))
|
||||
|
||||
(define
|
||||
go-eval-method-call
|
||||
;; Method dispatch: lookup #method/TYPE/NAME in env, bind receiver
|
||||
;; to OBJ-value and params to ARGS, run body.
|
||||
(fn (env obj-expr method-name args)
|
||||
(let ((obj (go-eval env obj-expr)))
|
||||
(cond
|
||||
(go-eval-error? obj) obj
|
||||
(not (and (list? obj) (= (first obj) :go-struct)))
|
||||
;; Not a struct: maybe it's a callable field access? Try the
|
||||
;; normal select-then-call path.
|
||||
(let ((callee (go-eval env (list :select obj-expr method-name))))
|
||||
(cond
|
||||
(go-eval-error? callee) callee
|
||||
:else (go-eval-call env callee args)))
|
||||
:else
|
||||
(let ((type-name (nth obj 1)))
|
||||
(let ((method-val (go-env-lookup env
|
||||
(str "#method/" type-name "/" method-name))))
|
||||
(cond
|
||||
(= method-val nil)
|
||||
(list :eval-error :no-such-method type-name method-name)
|
||||
:else
|
||||
(let ((recv-name (nth method-val 1))
|
||||
(params (nth method-val 2))
|
||||
(body (nth method-val 3)))
|
||||
(let ((arg-vals (go-eval-args env args)))
|
||||
(cond
|
||||
(go-eval-error? arg-vals) arg-vals
|
||||
:else
|
||||
(let ((param-names (go-flatten-param-names params)))
|
||||
(cond
|
||||
(not (= (len param-names) (len arg-vals)))
|
||||
(list :eval-error :arity-mismatch
|
||||
(len param-names) (len arg-vals))
|
||||
:else
|
||||
(let ((call-env
|
||||
(go-env-extend
|
||||
(go-bind-names env param-names arg-vals)
|
||||
recv-name obj)))
|
||||
(cond
|
||||
(= body nil) nil
|
||||
(and (list? body) (= (first body) :block))
|
||||
(let ((r (go-eval-block call-env (nth body 1))))
|
||||
(cond
|
||||
(and (list? r) (= (first r) :return-value))
|
||||
(nth r 1)
|
||||
(go-eval-error? r) r
|
||||
:else nil))
|
||||
:else nil))))))))))))))
|
||||
|
||||
(define
|
||||
go-eval-type-decl
|
||||
;; (:type-decl NAME TYPE). For struct types we register the field-name
|
||||
@@ -864,6 +937,20 @@
|
||||
(go-eval-error? lv) lv
|
||||
(go-eval-error? rv) rv
|
||||
:else (go-eval-binop op lv rv))))
|
||||
;; Unary prefix op: head is :var with op name + 1 arg.
|
||||
(and (list? head) (= (first head) :var) (= (len args) 1)
|
||||
(some (fn (o) (= o (nth head 1)))
|
||||
(list "-" "+" "!")))
|
||||
(let ((op (nth head 1)) (v (go-eval env (first args))))
|
||||
(cond
|
||||
(go-eval-error? v) v
|
||||
(= op "-") (- 0 v)
|
||||
(= op "+") v
|
||||
(= op "!") (not v)
|
||||
:else (list :eval-error :unsupported-unary op)))
|
||||
;; Method-call shape: head is (:select OBJ METHOD-NAME).
|
||||
(and (list? head) (= (first head) :select))
|
||||
(go-eval-method-call env (nth head 1) (nth head 2) args)
|
||||
:else
|
||||
(let ((callee (go-eval env head)))
|
||||
(cond
|
||||
|
||||
Reference in New Issue
Block a user