spook

A "game" for the 2023 Autumn Lisp Game Jam. Won first place! (from the bottom...)
git clone https://kaka.farm/~git/spook
Log | Files | Refs | LICENSE

bind.scm (5667B)


      1 ;;;; bind.scm - highlevel foreign interface
      2 ;
      3 ; Binding syntax:
      4 ;
      5 ; ["function"] ID "(" [ARG {"," ARG}] ")" ["{" ... "}" | ";"]
      6 ; "var" ID ["=" TYPE] {"," ID ["=" TYPE]} [";"]
      7 ;
      8 ; ARG = TYPE [ "..." ]
      9 ;     | "..."
     10 ; TYPE = "number" | "string" | "function" | "object" | "null" | "undefined"
     11 ;      | "[" [ARG {"," ARG}] "]"
     12 ;      | "_" | "*"
     13 
     14 
     15 ;; needs honu.scm and match.scm
     16 
     17 (define (method-name? str)
     18   (and (memv #\. (string->list str)) #t))
     19 
     20 (define (method-name-split str)
     21   (if (char-upper-case? (string-ref str 0))
     22       str
     23       (let ((res (string-split str ".")))
     24          (if (= (length res) 1)
     25              (car res)
     26              (list (car res) (foldl (cut string-append <> "." <>)
     27                                     "" (cdr res)))))))
     28 
     29 (define parse-bindings 
     30   (let ((semicolon (string->symbol ";"))
     31 	(comma (string->symbol ","))
     32 	(dot (string->symbol ".")))
     33     (lambda (str)
     34       (let ((tokens
     35 	     (with-input-from-string str
     36 	       (lambda ()
     37 		 (let loop ((xs '()))
     38 		   (let ((x (read-honu)))
     39 		     (if (eof-object? x)
     40 			 (reverse xs)
     41 			 (loop (cons x xs))))))))
     42 	    (code '()))
     43 	(define (add expr)
     44 	  (set! code (cons expr code)))
     45 	(define (parse t)
     46 	  (match t
     47 	    (() (reverse code))
     48 	    (('function . more) 
     49 	     (parse (function more)))
     50 	    (('var . more)
     51 	     (parse (var more)))
     52 	    (((? symbol?) . _) 
     53 	     (parse (function t)))
     54 	    (_ (error "invalid binding syntax" t))))
     55 	(define (function t0)
     56 	  (match-let (((name . t) (parse-name t0)))
     57 	    (match t
     58 	      ((('%parens . args) . t)
     59 	       (let ((tl (typelist args)))
     60 		 (match t
     61 		   (((or (? semicolon?) ('%braces . _)) . t2)
     62 		    (set! t t2))
     63 		   (_ #f))
     64 		 (add (generate-function-binding name tl))
     65 		 t))
     66 	      (_ (error "invalid function binding syntax" t0)))))
     67 	(define (var t0)
     68 	  (match-let (((name . t) (parse-name t0)))
     69 	    (let ((type #f))
     70 	      (match t
     71 		(('= type2 . t2)
     72 		 (set! type (parse-type type2))
     73 		 (set! t t2))
     74 		(_ #f))
     75 	      (add (generate-variable-binding name type))
     76 	      (match t
     77 		(((? semicolon?) . t2) t2)
     78 		(((? comma?) . t2) (var t2))
     79 		(_ t)))))
     80 	(define (semicolon? t) (eq? t semicolon))
     81 	(define (comma? t) (eq? t comma))
     82 	(define (dot? t) (eq? t dot))
     83 	(define (dots? t) (eq? t '...))
     84 	(define (parse-type type)
     85 	  (case type
     86 	    ((number string object null undefined function) type)
     87 	    ((_ *) #f)
     88 	    (else 
     89 	     (match type
     90 	       (('%brackets) '())
     91 	       (('%brackets . args) (typelist args))
     92 	       (_ (error "invalid binding type" type))))))
     93 	(define (typelist lst)
     94 	  (let loop ((lst lst) (tl '()))
     95 	    (match lst
     96 	      (() (reverse tl))
     97 	      (((? dots?)) (reverse (cons '... tl)))
     98 	      ((type (? dots?)) 
     99 	       (reverse (cons (vector (parse-type type)) tl)))
    100 	      ((type (? comma?) . lst)
    101 	       (loop lst (cons (parse-type type) tl)))
    102 	      ((type)
    103 	       (reverse (cons (parse-type type) tl))))))
    104 	(define (parse-name t)
    105 	  (match t
    106 	    (((? symbol? s) . t)
    107 	     (let loop ((t t) (name (symbol->string s)))
    108 	       (match t
    109 		 (((? dot?) (? symbol? s2) . t)
    110 		  (loop t (string-append name "." (symbol->string s2))))
    111 		 (_ (cons name t)))))
    112 	    (_ (error "invalid binding name" t))))
    113 	(parse tokens)
    114 	`(begin ,@(reverse code))))))
    115 
    116 ;; these must generate expanded code, as parsing of bind expressions happens
    117 ;; during canonicalization
    118 (define (generate-function-binding name tl)
    119   ;;XXX doesn't handle methods (do we need to?)
    120   (let ((name (method-name-split name)))
    121     (define (finish wraps tmps rest rtmp)
    122       (let ((sname
    123 	     (if (string? name)
    124 		 name
    125 		 (cadr name))))
    126 	`(define-syntax ,(string->symbol sname)
    127 	   (syntax-rules ()
    128 	     ((_ ,@tmps ,@(if rest (list rtmp '...) '()))
    129 	      (%inline 
    130 	       ,sname
    131 	       ,@wraps
    132 	       ,@(cond ((eq? #t rest) (list rtmp '...))
    133 		       (rest (list rest '...))
    134 		       (else '()))))))	  ))
    135     (define (wrap type tmp)
    136       (case type
    137 	((number function object null undefined)
    138 	 `(%check ,(symbol->string type) ,tmp))
    139 	((string)
    140 	 `(%string->jstring ,tmp))
    141 	(else
    142 	 (if (pair? type)
    143 	     (wrap-vector type tmp)
    144 	     tmp))))
    145     (define (wrap-vector tl tmp)
    146       (let loop ((tl tl) (cs '()) (f #f) (i 0))
    147 	(match tl
    148 	  (()
    149 	   (if f 
    150 	       `(vector ,@(reverse cs))
    151 	       tmp))
    152 	  ;;XXX currently not handled
    153 	  ((type (? (cut eq? '... <>)))
    154 	   (loop '() cs f i))
    155 	  (((? (cut eq? <> '...)))
    156 	   (if f
    157 	       `(%inline 
    158 		 ".concat" 
    159 		 `(vector ,(reverse cs))
    160 		 (%inline ".slice" ,tmp ,i))
    161 	       tmp))
    162 	  ((type . tl) 
    163 	   (let* ((wt `(vector-ref ,tmp ,i)) ;XXX nested access will be inefficient
    164 		  (w (wrap type wt)))
    165 	     (loop tl (cons w cs) (not (equal? w wt)) (+ i 1)))))))
    166     (let loop ((tl tl) (wraps '()) (tmps '()))
    167       ;; (write tl (current-error-port))
    168       (match tl
    169 	(() (finish (reverse wraps) (reverse tmps) #f #f)) ; fixed
    170 	(((? (cut eq? <> '...)))
    171 	 (finish (reverse wraps) (reverse tmps) #t (temp))) ; N + rest
    172 	((#(type))
    173 	 (let ((tmp (temp)))
    174 	   (finish (reverse wraps) (reverse tmps) (wrap type tmp) tmp))) ; N + rest with type
    175 	((type . tl)
    176 	 (let ((tmp (temp)))
    177 	   (loop tl (cons (wrap type tmp) wraps) (cons tmp tmps))))))))
    178 		       
    179 (define (generate-variable-binding name type)
    180   (let ((sname (string->symbol name))
    181 	(tmp (temp))
    182 	(tmp2 (temp)))
    183     `(begin
    184        (define-syntax set!
    185 	 (let-syntax ((old-set! set!))
    186 	   (syntax-rules (,sname)
    187 	     ((_ ,sname ,tmp) 
    188 	      (%host-set! 
    189 	       ,name 
    190 	       ,(case type
    191 		  ((number function object null undefined)
    192 		   `(%check ,(symbol->string type) x))
    193 		  ((string)
    194 		   `(%string->jstring x))
    195 		  (else 'x))))
    196 	     ((_ ,tmp tmp2)
    197 	      (old-set! ,tmp ,tmp2)))))
    198        (define-syntax ,sname (%host-ref ,name)))))