You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
490 lines
19 KiB
Scheme
490 lines
19 KiB
Scheme
;; parser.ss
|
|
;;
|
|
;; Takes a zodiac:sexp, and an env: sym -> zodiac:bound,
|
|
;; and produces a zodiac:ast and a list of unbound zodiac:bounds
|
|
;; Only handles R4RS primitive syntax
|
|
;; ======================================================================
|
|
|
|
(define keywords
|
|
'(begin cond delay if set! set!-values quote begin lambda case-lambda
|
|
poly
|
|
let-values letrec*-values
|
|
unit compound-unit invoke-unit
|
|
: type:-quote
|
|
cache-exp-quote cache-inv-quote
|
|
struct typed-structure const-typed-structure
|
|
))
|
|
|
|
(define define-keywords
|
|
'(define-values
|
|
define-type
|
|
define-constructor
|
|
))
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
(define (top-level-parse-defs defs)
|
|
(set! unbound-env '())
|
|
(let-values ([(defs nuenv) (parse-defs defs empty-env)])
|
|
(values defs (map cdr unbound-env))))
|
|
|
|
(define (top-level-parse-exp exp)
|
|
(set! unbound-env '())
|
|
(let ([ast (parse exp empty-env)])
|
|
(values ast (map cdr unbound-env))))
|
|
|
|
(define unbound-env '())
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
(define syntax-error
|
|
(case-lambda
|
|
[(exp) (syntax-error exp "Bad syntax")]
|
|
[(exp s)
|
|
(mrspidey:error
|
|
(format "File ~s, Line ~s: ~a ~s"
|
|
(file-name-from-path
|
|
(zodiac:location-file (zodiac:zodiac-start exp)))
|
|
(zodiac:location-line (zodiac:zodiac-start exp))
|
|
s (zodiac:stripper exp)))]))
|
|
|
|
(define syntax-error-no-exp
|
|
(case-lambda
|
|
[(exp) (syntax-error-no-exp exp "Bad syntax")]
|
|
[(exp s)
|
|
(mrspidey:error
|
|
(format "File ~s, Line ~s: ~as"
|
|
(file-name-from-path
|
|
(zodiac:location-file (zodiac:zodiac-start exp)))
|
|
(zodiac:location-line (zodiac:zodiac-start exp))
|
|
s))]))
|
|
|
|
(define assert-syn
|
|
(case-lambda
|
|
[(exp x) (assert-syn exp x "Bad syntax")]
|
|
[(exp x s) (unless x (syntax-error exp s))]))
|
|
|
|
(define parse-body
|
|
(lambda (o s f body env)
|
|
(assert (list? body))
|
|
(recur loop ([rest body])
|
|
(match rest
|
|
[(exp) (parse exp env)]
|
|
[(exp . rest)
|
|
(zodiac:make-begin-form o s f (box 0)
|
|
(parse exp env)
|
|
(loop rest))]))))
|
|
|
|
(define do-bindings
|
|
(lambda (env syms)
|
|
(assert (list? syms))
|
|
(let* ([bindings
|
|
(map
|
|
(match-lambda
|
|
[($ zodiac:symbol o s f sym)
|
|
(let ([bound (zodiac:make-bound o s f (box 0) sym sym)])
|
|
(cons sym bound))]
|
|
[exp (syntax-error exp "Bad binding syntax")])
|
|
syms)]
|
|
[syms (map car bindings)]
|
|
[bounds (map cdr bindings)]
|
|
[nuenv (extend-env* env syms bounds)])
|
|
(values bounds nuenv))))
|
|
|
|
(define do-bindingss
|
|
(lambda (env symss)
|
|
(recur loop ([env env][symss symss][boundss '()])
|
|
(if (null? symss)
|
|
(values (reverse boundss) env)
|
|
(let-values
|
|
([(bounds env) (do-bindings env (car symss))])
|
|
(loop env (cdr symss) (cons bounds boundss)))))))
|
|
|
|
(define parse
|
|
;; parses an expression
|
|
(lambda (exp env)
|
|
(pretty-debug-front `(parse ,(zodiac:stripper exp)))
|
|
(letrec ([lookup-sym
|
|
(lambda (sym s f env)
|
|
(let ([bound
|
|
(or (lookup-or-#f env sym)
|
|
(lookup-or-#f unbound-env sym)
|
|
;; Add to unbound-env
|
|
(let ([n (zodiac:my-create-bound sym s f)])
|
|
(set! unbound-env (cons (cons sym n) unbound-env))
|
|
n))])
|
|
;;(set-bound-refs! bound (add1 (bound-refs bound)))
|
|
bound))]
|
|
[parse-sym-env
|
|
(lambda (env)
|
|
(match-lambda
|
|
[($ zodiac:symbol o s f sym)
|
|
;;(printf "ref sym ~s~n" sym)
|
|
(zodiac:make-lexical-varref o s f (box 0)
|
|
sym (lookup-sym sym s f env))]
|
|
[exp (syntax-error exp "Expected a variable:")]))]
|
|
[parse-sym (parse-sym-env env)]
|
|
[call-void
|
|
(lambda (o s f)
|
|
(zodiac:make-app
|
|
o s f (box 0)
|
|
(zodiac:make-lexical-varref o s f (box 0)
|
|
'void (lookup-sym 'void s f '()))
|
|
'()))]
|
|
[parse-exps
|
|
(lambda (exps env)
|
|
(map (lambda (e) (parse e env)) exps))]
|
|
[handle-args
|
|
(lambda (args env)
|
|
(match args
|
|
[($ zodiac:list _ _ _ args) (do-bindings env args)]
|
|
[($ zodiac:symbol)
|
|
(let-values
|
|
([(bounds nuenv) (do-bindings env (list args))])
|
|
(values (car bounds) nuenv))]
|
|
[($ zodiac:improper-list _ _ _ l)
|
|
(recur loop ([args '()][l l])
|
|
(match l
|
|
[(arg)
|
|
(let-values
|
|
([(bounds nuenv)
|
|
(do-bindings env (cons arg args))])
|
|
(values (append (reverse (cdr bounds)) (car bounds))
|
|
nuenv))]
|
|
[(arg . rest) (loop (cons arg args) rest)]))]))])
|
|
|
|
(pretty-debug-front `(parse ,(zodiac:stripper exp)))
|
|
(match exp
|
|
;; Identifiers
|
|
[($ zodiac:symbol o s f sym) (parse-sym exp)]
|
|
|
|
;; Scalars, vectors
|
|
[(or ($ zodiac:scalar o s f) ($ zodiac:vector o s f))
|
|
(zodiac:make-quote-form o s f (box 0) exp)]
|
|
|
|
;; Special forms
|
|
[($ zodiac:list o s f
|
|
(and l (($ zodiac:symbol _ _ _ sym) . body)))
|
|
(=> fail)
|
|
(let ([sym (strip-hash-percent sym)])
|
|
(cond
|
|
[(memq sym keywords)
|
|
(match (cons sym body)
|
|
[('cond)
|
|
(call-void o s f)]
|
|
[('delay exp)
|
|
(zodiac:make-delay-form o s f (box 0) (parse exp env))]
|
|
[('if test then else)
|
|
(zodiac:make-if-form o s f (box 0)
|
|
(parse test env)
|
|
(parse then env)
|
|
(parse else env))]
|
|
[('if test then)
|
|
(zodiac:make-if-form o s f (box 0)
|
|
(parse test env)
|
|
(parse then env)
|
|
(call-void o s f))]
|
|
[(or
|
|
('set! var exp)
|
|
('set!-values ($ zodiac:list _ _ _ (var)) exp))
|
|
|
|
(let ([var (parse-sym var)])
|
|
(when (zodiac:lexical-varref? var)
|
|
(zodiac:set-bound-mutated!
|
|
(zodiac:lexical-varref-binding var)
|
|
#t))
|
|
(zodiac:make-set!-form o s f (box 0)
|
|
var (parse exp env)))]
|
|
[('quote sexp)
|
|
(assert-syn exp (= (length body) 1))
|
|
(zodiac:make-quote-form o s f (box 0) sexp)]
|
|
[('begin . exps)
|
|
(recur loop ([exps exps])
|
|
(match exps
|
|
[() (call-void o s f)]
|
|
[(exp) (parse exp env)]
|
|
[(exp . exps)
|
|
(zodiac:make-begin-form o s f (box 0)
|
|
(parse exp env)
|
|
(loop exps))]))]
|
|
[('lambda args . bodies)
|
|
(let-values
|
|
([(bounds nuenv) (handle-args args env)])
|
|
(zodiac:make-lambda-form o s f (box 0)
|
|
bounds
|
|
(parse-body o s f bodies nuenv)))]
|
|
[('case-lambda . cases)
|
|
(zodiac:make-case-lambda-form
|
|
o s f (box 0)
|
|
(mapLR
|
|
(match-lambda
|
|
[($ zodiac:list _ _ _ (args . body))
|
|
(let-values
|
|
([(bounds nuenv) (handle-args args env)])
|
|
(cons bounds (parse-body o s f body nuenv)))]
|
|
[_ (syntax-error-no-exp exp "Bad case lambda")])
|
|
cases))]
|
|
|
|
[('let-values
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:list _ _ _
|
|
(($ zodiac:list _ _ _ varss)
|
|
exps))
|
|
...))
|
|
. bodies)
|
|
(let-values
|
|
([(boundss nuenv) (do-bindingss env varss)])
|
|
(zodiac:make-let-values-form
|
|
o s f (box 0)
|
|
boundss
|
|
(parse-exps exps env)
|
|
(parse-body o s f bodies nuenv)))]
|
|
|
|
[('letrec*-values
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:list _ _ _
|
|
(($ zodiac:list _ _ _ varss)
|
|
exps))
|
|
...))
|
|
. bodies)
|
|
(let-values
|
|
([(boundss nuenv) (do-bindingss env varss)])
|
|
(for-each
|
|
(lambda (name) (zodiac:set-bound-mutated! name #t))
|
|
(apply append boundss))
|
|
(zodiac:make-letrec-values-form
|
|
o s f (box 0)
|
|
boundss
|
|
(parse-exps exps nuenv)
|
|
(parse-body o s f bodies nuenv)))]
|
|
|
|
;; ---------------------------------------------------------
|
|
;; MzScheme specific code
|
|
|
|
;; --- units ---
|
|
[('unit ($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ 'import)
|
|
i-ids ...))
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ 'export)
|
|
(or ($ zodiac:list _ _ _
|
|
(i-eids
|
|
($ zodiac:symbol _ _ _ e-eids)))
|
|
(and i-eids
|
|
($ zodiac:symbol _ _ _ e-eids)))
|
|
...))
|
|
. body)
|
|
(let*-vals ([(i-names env1) (do-bindings env i-ids)]
|
|
[(defs env2) (parse-defs body env1)]
|
|
[e-vars
|
|
(map (parse-sym-env env2) i-eids)]
|
|
[exports (map cons e-vars e-eids)])
|
|
(zodiac:make-unit-form o s f (box 0)
|
|
i-names exports defs))]
|
|
|
|
;; --- compound-units ---
|
|
[('compound-unit
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ 'import)
|
|
($ zodiac:symbol _ _ _ imports) ...))
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ 'link) . links))
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ 'export) . exports)))
|
|
(let*-vals
|
|
([links
|
|
(map
|
|
(match-lambda
|
|
[($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ tag)
|
|
($ zodiac:list _ _ _ (exp . imports))))
|
|
(list tag
|
|
(parse exp env)
|
|
(apply append
|
|
(map
|
|
(match-lambda
|
|
[($ zodiac:symbol _ _ _ sym)
|
|
(list (cons #f sym))]
|
|
[($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ tag)
|
|
($ zodiac:symbol _ _ _ syms)
|
|
...))
|
|
(map (lambda (sym) (cons tag sym))
|
|
syms)]
|
|
[_ (syntax-error exp "Bad link imp")])
|
|
imports)))]
|
|
[_ (syntax-error exp "Bad link")])
|
|
links)]
|
|
[exports
|
|
(apply
|
|
append
|
|
(map
|
|
(match-lambda
|
|
[($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ tag)
|
|
(or ($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ i-eids)
|
|
($ zodiac:symbol _ _ _ e-eids)))
|
|
(and ($ zodiac:symbol _ _ _ i-eids)
|
|
($ zodiac:symbol _ _ _ e-eids))) ...))
|
|
(map
|
|
(lambda (i-eid e-eid) (list tag i-eid e-eid))
|
|
i-eids e-eids)]
|
|
[_ (syntax-error exp "Bad link export")])
|
|
exports))])
|
|
(zodiac:make-compound-unit-form
|
|
o s f (box 0) imports links exports))]
|
|
|
|
;; --- invoke-unit ---
|
|
[('invoke-unit exp . ((and vars ($ zodiac:symbol)) ...))
|
|
(zodiac:make-invoke-unit-form
|
|
o s f (box 0)
|
|
(parse exp env)
|
|
(map (lambda (var) (parse-sym var env)) vars))]
|
|
|
|
;; --- structures ---
|
|
[((or 'struct 'typed-structure 'const-typed-structure)
|
|
first
|
|
($ zodiac:list _ _ _ fields))
|
|
(let*-vals
|
|
([(tag parent)
|
|
(match first
|
|
[($ zodiac:symbol _ _ _ tag) (values tag #f)]
|
|
[($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ tag) parent))
|
|
(values tag (parse parent env))])]
|
|
[fields (map zodiac:stripper fields)])
|
|
(zodiac:make-struct-form
|
|
o s f (box 0)
|
|
tag (eq? sym 'const-typed-structure) parent fields))]
|
|
|
|
;; -------------------------------------------------------
|
|
;; MrSpidey specific code
|
|
|
|
[('poly exp)
|
|
(zodiac:make-poly-form
|
|
o s f (box 0) (parse exp env))]
|
|
[(': exp type)
|
|
(zodiac:make-:-form o s f (box 0)
|
|
(parse exp env)
|
|
(zodiac:stripper type))]
|
|
|
|
[('type:-quote
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ (or 'quote '#%quote))
|
|
($ zodiac:list _ _ _ (type . attrs)))))
|
|
(zodiac:make-type:-form o s f (box 0)
|
|
(zodiac:stripper type)
|
|
(map zodiac:stripper attrs))]
|
|
|
|
[('st:control para val)
|
|
(zodiac:make-st:control-form o s f (box 0)
|
|
(zodiac:stripper para)
|
|
(zodiac:stripper val))]
|
|
|
|
[((or 'cache-exp-quote 'cache-inv-quote)
|
|
($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ (or 'quote '#%quote)) exp))
|
|
($ zodiac:string _ _ _ za))
|
|
(when (string=? za (regexp-replace ".za$" za ""))
|
|
(syntax-error exp "Cache filename must end in .za"))
|
|
(zodiac:make-cache-form
|
|
o s f (box 0) exp
|
|
(normalize-path za)
|
|
(case sym
|
|
[cache-exp-quote 'exp]
|
|
[cache-inv-quote 'inv]
|
|
[else
|
|
(mrspidey:internal-error 'parser "Bad sym ~s" sym)])
|
|
(current-directory))]
|
|
|
|
;; -------------------------------------------------------
|
|
[else (syntax-error exp)])]
|
|
[(memq sym define-keywords)
|
|
(syntax-error-no-exp exp "Defines not allowed")]
|
|
[else (fail)]))]
|
|
|
|
;; Don't handle vectors or improper lists
|
|
;; Applications
|
|
|
|
[($ zodiac:list o s f (and l (fn . exps)))
|
|
(zodiac:make-app o s f (box 0)
|
|
(parse fn env)
|
|
(parse-exps exps env))]
|
|
[($ zodiac:list o s f ())
|
|
(zodiac:make-quote-form o s f (box 0) '())]
|
|
[_ (syntax-error exp)]))))
|
|
|
|
|
|
|
|
|
|
(define (parse-defs defs env)
|
|
(let*-vals
|
|
([varss (mapLR
|
|
(match-lambda
|
|
[($ zodiac:list _ _ _
|
|
(($ zodiac:symbol _ _ _ '#%define-values)
|
|
($ zodiac:list _ _ _ vars)
|
|
exp))
|
|
vars]
|
|
[_ '()])
|
|
defs)]
|
|
[(boundss nuenv) (do-bindingss env varss)]
|
|
[_ (for-each
|
|
(lambda (name) (zodiac:set-bound-mutated! name #t))
|
|
(apply append boundss))]
|
|
[defs
|
|
(map
|
|
(lambda (def bounds)
|
|
(pretty-debug-front `(parse-def ,(zodiac:stripper def)))
|
|
(mrspidey:zprogress "Parsing" (zodiac:zodiac-start def))
|
|
(match def
|
|
;; Special forms
|
|
[($ zodiac:list o s f
|
|
(and l (($ zodiac:symbol _ _ _ sym) . body)))
|
|
(=> fail)
|
|
(let ([sym (strip-hash-percent sym)])
|
|
(cond
|
|
[(not (memq sym define-keywords)) (fail)]
|
|
[else
|
|
(match (cons sym body)
|
|
|
|
[('define-values ($ zodiac:list _ _ _ vars) exp)
|
|
(zodiac:make-define-values-form
|
|
o s f (box 0)
|
|
(map
|
|
(match-lambda
|
|
[(and bound ($ zodiac:bound o s f _ sym))
|
|
(zodiac:make-lexical-varref o s f (box 0)
|
|
sym bound)])
|
|
bounds)
|
|
(parse exp nuenv))]
|
|
|
|
;; ----------------------------------------------------
|
|
;; MrSpidey specific code
|
|
|
|
[('define-type ($ zodiac:symbol _ _ _ sym) type)
|
|
(zodiac:make-define-type-form
|
|
o s f (box 0)
|
|
sym (zodiac:stripper type))]
|
|
|
|
[('define-constructor ($ zodiac:symbol _ _ _ sym)
|
|
. modes)
|
|
(let ([modes (map zodiac:stripper modes)])
|
|
(assert-syn def (andmap boolean? modes))
|
|
(zodiac:make-define-constructor-form o s f (box 0)
|
|
sym modes))]
|
|
|
|
;; ----------------------------------------------------
|
|
[else (fail)])]))]
|
|
|
|
[exp (parse exp nuenv)]))
|
|
defs boundss)])
|
|
(unless (null? defs)
|
|
(mrspidey:zprogress "Parsing" (zodiac:zodiac-finish (rac defs))))
|
|
(values defs nuenv)))
|
|
|
|
;; ----------------------------------------------------------------------
|
|
|
|
|