#lang scheme/base
(require (planet "evector.scm" ("soegaard" "evector.plt" 1))
scheme/list
scheme/match
scheme/promise
"../syntax/ast-core.ss"
"../syntax/ast-utils.ss"
"../runtime/runtime.ss"
"helpers.ss"
"hoist.ss")
(require (for-template scheme/base)
(for-template "../runtime/runtime.ss"))
(provide (all-defined-out))
(define scope-chain-id (datum->syntax #f 'scope-chain))
(define variable-object-id (datum->syntax #f 'variable-object))
(define empty-scope #hasheq())
(define current-scope (make-parameter empty-scope))
(define current-compilation-context (make-parameter 'scheme))
(define current-lexical-context (make-parameter 'top))
(define current-eval-context (make-parameter #'here))
(define current-source-syntax (make-parameter #f))
(define current-nested? (make-parameter #f))
(define current-pragmas (make-parameter '#hash(((lexical scope) . #f))))
(define current-labels (make-parameter null))
(define-struct Variable (source compiled))
(define-struct (Import Variable) (module-spec module-path eval?))
(define (Variable=? v1 v2)
(Identifier=? (Variable-source v1) (Variable-source v2)))
(define-syntax-rule (with-scope e body ...)
(parameterize ([current-scope (and (current-scope) e)])
body ...))
(define (resolve x [env (or (current-scope) (error 'resolve "no current environment"))])
(hash-ref env (name x) (lambda () #f)))
(define (bound? x [env (or (current-scope) (error 'bound? "no current environment"))])
(and (hash-ref env (name x) (lambda () #f)) #t))
(define (name x)
(cond
[(Identifier? x) (Identifier-name x)]
[(Variable? x) (name (Variable-source x))]
[(symbol? x) x]
[else (error 'name "not a name: ~v~n" x)]))
(define (bind xs env)
(if (or (not env) (null? xs))
env
(let ([x (car xs)])
(bind (cdr xs) (hash-set env (name x) x)))))
(define (cast pred? x)
(and (pred? x) x))
(define (default-inits vars)
(for/list ([var vars])
#'(void)))
(define (with-bindings vars #:inits [inits (default-inits vars)] stx)
(cond
[(and (eq? (current-compilation-context) 'module)
(eq? (current-lexical-context) 'top)
(not (current-nested?)))
(with-module-bindings vars #:inits inits stx)]
[(current-scope)
(with-lexical-bindings vars #:inits inits stx)]
[else (with-dynamic-bindings vars #:inits inits stx)]))
(define (with-module-bindings vars #:inits [inits (default-inits vars)] stx)
(with-syntax ([(x ...) (map Variable-compiled vars)]
[(e ...) inits]
[body stx])
(syntax/loc stx
(begin
(define x e) ...
body))))
(define (with-lexical-bindings vars #:inits [inits (default-inits vars)] stx)
(with-syntax ([(x ...) (map Variable-compiled vars)]
[(e ...) (or inits (map (lambda (v) #'(void)) vars))]
[body stx])
(syntax/loc stx
(let ([x e] ...) body))))
(define (with-dynamic-bindings vars #:inits [inits (default-inits vars)] stx #:variable-object? [variable-object? #f])
(with-syntax ([scope-chain scope-chain-id]
[(prop ...)
(for/list ([var vars] [init inits])
(with-syntax ([x (Variable-compiled var)]
[e init])
#'[x e]))]
[frame (if variable-object? variable-object-id (car (generate-temporaries '(frame))))]
[body stx])
(syntax/loc stx
(let* ([frame (make-frame (object-table prop ...))]
[scope-chain (cons frame scope-chain)])
body))))
(define (direct-eval? expr)
(match expr
[(struct VarReference (_ (struct Identifier (_ sym))))
(if (eq? (current-compilation-context) 'module)
(cond
[(hash-ref (current-scope) sym (lambda () #f))
=> (lambda (var)
(and (Import? var)
(force (Import-eval? var))))]
[else #f])
(eq? sym 'eval))]
[_ #f]))
(define (contains-direct-eval? body)
(ormap Statement-contains-direct-eval? body))
(define (Statement-contains-direct-eval? stmt)
(and stmt
(match stmt
[(struct BlockStatement (_ stmts)) (ormap Statement-contains-direct-eval? stmts)]
[(struct EmptyStatement (_)) #f]
[(struct ExpressionStatement (_ expr)) (Expression-contains-direct-eval? expr)]
[(struct IfStatement (_ test cons alt)) (or (Expression-contains-direct-eval? test)
(Statement-contains-direct-eval? cons)
(Statement-contains-direct-eval? alt))]
[(struct DoWhileStatement (_ body test)) (or (Statement-contains-direct-eval? body)
(Expression-contains-direct-eval? test))]
[(struct WhileStatement (_ test body)) (or (Expression-contains-direct-eval? test)
(Statement-contains-direct-eval? body))]
[(struct ForStatement (_ init test incr body)) (or (and (Expression? init) (Expression-contains-direct-eval? init))
(and incr (Expression-contains-direct-eval? incr))
(and body (Expression-contains-direct-eval? body)))]
[(struct ForInStatement (_ lhs rhs body)) (or (and (Expression? lhs) (Expression-contains-direct-eval? lhs))
(Expression-contains-direct-eval? rhs)
(Statement-contains-direct-eval? body))]
[(struct ContinueStatement (_ label)) #f]
[(struct BreakStatement (_ label)) #f]
[(struct ReturnStatement (_ expr)) (and expr (Expression-contains-direct-eval? expr))]
[(struct LetStatement (_ head body)) (or (ormap VariableInitializer-contains-direct-eval? head)
(Statement-contains-direct-eval? body))]
[(struct WithStatement (_ ctxt body)) (Expression-contains-direct-eval? ctxt)]
[(struct SwitchStatement (_ expr cases)) (or (Expression-contains-direct-eval? expr)
(ormap CaseClause-contains-direct-eval? cases))]
[(struct LabelledStatement (_ label body)) (Statement-contains-direct-eval? body)]
[(struct ThrowStatement (_ expr)) (Expression-contains-direct-eval? expr)]
[(struct TryStatement (_ body catch finally)) (or (Statement-contains-direct-eval? body)
(ormap CatchClause-contains-direct-eval? catch)
(and finally (Statement-contains-direct-eval? finally)))])))
(define (optional-Expression-contains-direct-eval? expr?)
(and expr? (Expression-contains-direct-eval? expr?)))
(define (Expression-contains-direct-eval? expr)
(match expr
[(or (? StringLiteral?)
(? NumericLiteral?)
(? BooleanLiteral?)
(? RegexpLiteral?)
(? NullLiteral?))
#f]
[(struct ArrayLiteral (_ elts)) (ormap optional-Expression-contains-direct-eval? elts)]
[(struct ObjectLiteral (_ props)) (ormap (lambda (prop)
(Expression-contains-direct-eval? (cdr prop)))
props)]
[(struct ThisReference (_)) #f]
[(struct VarReference (_ id)) #f]
[(struct BracketReference (_ container key)) (or (Expression-contains-direct-eval? container)
(Expression-contains-direct-eval? key))]
[(struct DotReference (_ container id)) (Expression-contains-direct-eval? container)]
[(struct NewExpression (_ ctor args)) (or (Expression-contains-direct-eval? ctor)
(ormap Expression-contains-direct-eval? args))]
[(struct PostfixExpression (_ expr op)) (Expression-contains-direct-eval? expr)]
[(struct PrefixExpression (_ op expr)) (Expression-contains-direct-eval? expr)]
[(struct InfixExpression (_ left op right)) (or (Expression-contains-direct-eval? left)
(Expression-contains-direct-eval? right))]
[(struct ConditionalExpression (_ test cons alt)) (or (Expression-contains-direct-eval? test)
(Expression-contains-direct-eval? cons)
(Expression-contains-direct-eval? alt))]
[(struct AssignmentExpression (_ lhs op rhs)) (or (Expression-contains-direct-eval? lhs)
(Expression-contains-direct-eval? rhs))]
[(struct FunctionExpression/hoisted (_ name args body funs vars imports exports)) #f]
[(struct LetExpression (_ head body)) (or (ormap VariableInitializer-contains-direct-eval? head)
(Expression-contains-direct-eval? body))]
[(struct CallExpression (_ (struct VarReference (_ (struct Identifier (_ 'eval)))) args)) #t]
[(struct CallExpression (_ method args)) (or (Expression-contains-direct-eval? method)
(ormap Expression-contains-direct-eval? args))]
[(struct ParenExpression (_ expr)) (Expression-contains-direct-eval? expr)]
[(struct ListExpression (_ exprs)) (ormap Expression-contains-direct-eval? exprs)]))
(define (VariableInitializer-contains-direct-eval? init)
(match init
[(struct VariableInitializer (_ id expr))
(and expr (Expression-contains-direct-eval? expr))]))
(define (CaseClause-contains-direct-eval? clause)
(match clause
[(struct CaseClause (_ question answer))
(or (and question (Expression-contains-direct-eval? question))
(ormap Statement-contains-direct-eval? answer))]))
(define (CatchClause-contains-direct-eval? clause)
(match clause
[(struct CatchClause (_ id body))
(Statement-contains-direct-eval? body)]))