;; lib/guest/ast.sx — canonical AST node shapes. ;; ;; A guest's parser may emit its own AST in whatever shape is convenient ;; for that language's evaluator/transpiler. This file gives a SHARED ;; canonical shape that cross-language tools (formatters, highlighters, ;; debuggers) can target without per-language adapters. ;; ;; Each canonical node is a tagged list: (KIND ...payload). ;; ;; Constructors (return a canonical node): ;; ;; (ast-literal VALUE) — number / string / bool / nil ;; (ast-var NAME) — identifier reference ;; (ast-app FN ARGS) — function application ;; (ast-lambda PARAMS BODY) — anonymous function ;; (ast-let BINDINGS BODY) — local bindings ;; (ast-letrec BINDINGS BODY) — recursive local bindings ;; (ast-if TEST THEN ELSE) — conditional ;; (ast-match-clause PATTERN BODY) — one match arm ;; (ast-module NAME BODY) — module declaration ;; (ast-import NAME) — import directive ;; ;; Predicates: (ast-literal? X), (ast-var? X), … ;; Generic: (ast? X) — any canonical node ;; (ast-kind X) — :literal / :var / :app / … ;; ;; Accessors (one per payload field): ;; (ast-literal-value N) ;; (ast-var-name N) ;; (ast-app-fn N) (ast-app-args N) ;; (ast-lambda-params N) (ast-lambda-body N) ;; (ast-let-bindings N) (ast-let-body N) ;; (ast-letrec-bindings N) (ast-letrec-body N) ;; (ast-if-test N) (ast-if-then N) (ast-if-else N) ;; (ast-match-clause-pattern N) ;; (ast-match-clause-body N) ;; (ast-module-name N) (ast-module-body N) ;; (ast-import-name N) (define ast-literal (fn (v) (list :literal v))) (define ast-var (fn (n) (list :var n))) (define ast-app (fn (f args) (list :app f args))) (define ast-lambda (fn (ps body) (list :lambda ps body))) (define ast-let (fn (bs body) (list :let bs body))) (define ast-letrec (fn (bs body) (list :letrec bs body))) (define ast-if (fn (t th el) (list :if t th el))) (define ast-match-clause (fn (p body) (list :match-clause p body))) (define ast-module (fn (n body) (list :module n body))) (define ast-import (fn (n) (list :import n))) (define ast-kind (fn (x) (if (and (list? x) (not (empty? x))) (first x) nil))) (define ast? (fn (x) (and (list? x) (not (empty? x)) (let ((k (first x))) (or (= k :literal) (= k :var) (= k :app) (= k :lambda) (= k :let) (= k :letrec) (= k :if) (= k :match-clause) (= k :module) (= k :import)))))) (define ast-literal? (fn (x) (and (ast? x) (= (first x) :literal)))) (define ast-var? (fn (x) (and (ast? x) (= (first x) :var)))) (define ast-app? (fn (x) (and (ast? x) (= (first x) :app)))) (define ast-lambda? (fn (x) (and (ast? x) (= (first x) :lambda)))) (define ast-let? (fn (x) (and (ast? x) (= (first x) :let)))) (define ast-letrec? (fn (x) (and (ast? x) (= (first x) :letrec)))) (define ast-if? (fn (x) (and (ast? x) (= (first x) :if)))) (define ast-match-clause? (fn (x) (and (ast? x) (= (first x) :match-clause)))) (define ast-module? (fn (x) (and (ast? x) (= (first x) :module)))) (define ast-import? (fn (x) (and (ast? x) (= (first x) :import)))) (define ast-literal-value (fn (n) (nth n 1))) (define ast-var-name (fn (n) (nth n 1))) (define ast-app-fn (fn (n) (nth n 1))) (define ast-app-args (fn (n) (nth n 2))) (define ast-lambda-params (fn (n) (nth n 1))) (define ast-lambda-body (fn (n) (nth n 2))) (define ast-let-bindings (fn (n) (nth n 1))) (define ast-let-body (fn (n) (nth n 2))) (define ast-letrec-bindings (fn (n) (nth n 1))) (define ast-letrec-body (fn (n) (nth n 2))) (define ast-if-test (fn (n) (nth n 1))) (define ast-if-then (fn (n) (nth n 2))) (define ast-if-else (fn (n) (nth n 3))) (define ast-match-clause-pattern (fn (n) (nth n 1))) (define ast-match-clause-body (fn (n) (nth n 2))) (define ast-module-name (fn (n) (nth n 1))) (define ast-module-body (fn (n) (nth n 2))) (define ast-import-name (fn (n) (nth n 1)))