#lang scheme/base
(require scheme/match
parser-tools/lex
"../ast.ss")
(provide (all-defined-out))
(define-syntax-rule (debug sexp-expr)
(log-debug (format "~v" sexp-expr)))
(define-syntax-rule (warning sexp-expr)
(log-warning (format "~v" sexp-expr)))
(define-struct lexer-state
(read? source offset [declarators #:mutable] [brace-depth #:mutable] [parenthesis-depth #:mutable] [previous-token #:mutable]))
(define (new-lexer-state declarators [read? #f] [source #f] [offset #f])
(make-lexer-state read? source offset declarators 0 0 #f))
(define (parenthesis++ state)
(set-lexer-state-parenthesis-depth! state (add1 (lexer-state-parenthesis-depth state))))
(define (parenthesis-- state)
(set-lexer-state-parenthesis-depth! state (sub1 (lexer-state-parenthesis-depth state))))
(define (brace++ state)
(set-lexer-state-brace-depth! state (add1 (lexer-state-brace-depth state))))
(define (brace-- state)
(set-lexer-state-brace-depth! state (sub1 (lexer-state-brace-depth state))))
(define (save-token! state x)
(set-lexer-state-previous-token! state (if (position-token? x) (position-token-token x) x)))
(define-struct parser-state
([env #:mutable] [declarators #:mutable] [major-context #:mutable] [minor-context #:mutable]))
(define (new-parser-state declarators initial-env initial-context)
(make-parser-state (list initial-env) declarators (list initial-context) (list #f)))
(define (push-context! state major)
(set-parser-state-major-context! state (cons major (parser-state-major-context state)))
(set-parser-state-minor-context! state (cons #f (parser-state-minor-context state))))
(define (pop-context! state)
(set-parser-state-major-context! state (cdr (parser-state-major-context state)))
(set-parser-state-minor-context! state (cdr (parser-state-minor-context state))))
(define (set-minor-context! state minor)
(set-parser-state-minor-context! state (cons minor (cdr (parser-state-minor-context state)))))
(define (cache-declarator-id! ps id)
(set-box! (car (parser-state-declarators ps)) id))
(define (push-scope! state)
(set-parser-state-env! state (cons null (parser-state-env state))))
(define (pop-scope! state)
(set-parser-state-env! state (cdr (parser-state-env state))))
(define (add-binding! name kind state)
(match (parser-state-env state)
[(cons rib env)
(set-parser-state-env! state (cons (cons (cons name kind) rib) env))]))
(define (lookup x e)
(cond
[(null? e) #f]
[(assq x (car e)) => cdr]
[else (lookup x (cdr e))]))
(define (declarator-context? ps)
(and (memq (car (parser-state-major-context ps)) '(block formals preamble)) #t))
(define (typedef-context? ps)
(eq? (car (parser-state-minor-context ps)) 'typedef))
(define (new-state [read? #f] [source #f] [offset #f] [initial-env null] [initial-context 'block])
(let ([declarators (list (box #f))])
(values (new-parser-state declarators initial-env initial-context)
(new-lexer-state declarators read? source offset))))
(define (looking-ahead? ls ps)
(cond
[(eq? (car (lexer-state-declarators ls))
(car (parser-state-declarators ps)))
#t]
[(eq? (car (lexer-state-declarators ls))
(car (cdr (parser-state-declarators ps))))
#f]
[else
(warning '(C state "lexer and parser out of sync"))
(warning (marshall-state ps ls))
#t]))
(define (looked-ahead? ls ps)
(cond
[(eq? (car (lexer-state-declarators ls))
(car (parser-state-declarators ps)))
#f]
[(eq? (car (lexer-state-declarators ls))
(car (cdr (parser-state-declarators ps))))
#t]
[else
(warning '(C state "lexer and parser out of sync"))
(warning (marshall-state ps ls))
#f]))
(define (push-declarator! ps ls)
(let ([declarator (box #f)])
(set-lexer-state-declarators! ls (cons declarator (lexer-state-declarators ls)))
(set-parser-state-declarators! ps (cons declarator (parser-state-declarators ps)))))
(define (pop-declarator! ps ls)
(cond
[(unbox (car (parser-state-declarators ps)))
=> (lambda (id)
(debug `(C context pop-declarator ,id))
(add-binding! id (if (typedef-context? ps) 'type 'var) ps))]
[else (debug '(C context pop-declarator #f))])
(set-lexer-state-declarators! ls (cdr (lexer-state-declarators ls)))
(set-parser-state-declarators! ps (cdr (parser-state-declarators ps)))
(debug (marshall-state ps ls)))
(define (pop-parser-declarator! ps ls)
(cond
[(and (declarator-context? ps)
(not (looked-ahead? ls ps))
(unbox (car (parser-state-declarators ps))))
=> (lambda (id)
(debug `(C context pop-parser-declarator ,id))
(add-binding! id (if (typedef-context? ps) 'type 'var) ps))]
[else (debug `(C context pop-parser-declarator #f))])
(set-parser-state-declarators! ps (cdr (parser-state-declarators ps)))
(debug (marshall-state ps ls)))
(define (pop-lexer-declarator! ls ps token)
(when (looking-ahead? ls ps)
(cond
[(unbox (car (lexer-state-declarators ls)))
=> (lambda (id)
(debug `(C context pop-lexer-declarator (lookahead ,token) (popped ,id)))
(add-binding! id (if (typedef-context? ps) 'type 'var) ps))]
[(memq (token-name (lexer-state-previous-token ls)) '(IDENTIFIER TYPEDEF_NAME))
(debug `(C context pop-lexer-declarator (lookahead ,token) (previous ,(lexer-state-previous-token ls))))
(add-binding! (token-value (lexer-state-previous-token ls))
(if (typedef-context? ps) 'type 'var)
ps)]
[else
(debug `(C context pop-lexer-declarator (lookahead ,token) (popped #f) (previous #f)))]))
(set-lexer-state-declarators! ls (cdr (lexer-state-declarators ls))))
(define (marshall-state ps ls)
`(C context
(lexer ,(lexer-state-declarators ls)
,(lexer-state-brace-depth ls)
,(lexer-state-parenthesis-depth ls)
,(lexer-state-previous-token ls))
(parser ,(parser-state-declarators ps)
,(parser-state-major-context ps)
,(parser-state-minor-context ps)
,(parser-state-env ps))))