#lang racket/base
(require "assemble.rkt"
"quote-cdata.rkt"
"../make/make.rkt"
"../make/make-structs.rkt"
"../parameters.rkt"
"../compiler/expression-structs.rkt"
"../parser/path-rewriter.rkt"
"../parser/parse-bytecode.rkt"
racket/match
(prefix-in query: "../lang/js/query.rkt")
(planet dyoo/closure-compile:1:1)
(prefix-in runtime: "get-runtime.rkt")
(prefix-in racket: racket/base))
(provide package
package-anonymous
package-standalone-xhtml
get-standalone-code
write-standalone-code
get-runtime
write-runtime)
(define (notify msg . args)
(displayln (apply format msg args)))
(define-struct js-impl (name real-path src )
#:transparent)
(define (package-anonymous source-code
#:should-follow-children? should-follow?
#:output-port op)
(fprintf op "(function() {\n")
(package source-code
#:should-follow-children? should-follow?
#:output-port op)
(fprintf op " return invoke; })\n"))
(define (source-is-javascript-module? src)
(cond
[(StatementsSource? src)
#f]
[(MainModuleSource? src)
(source-is-javascript-module? (MainModuleSource-source src))]
[(ModuleSource? src)
(query:has-javascript-implementation? `(file ,(path->string (ModuleSource-path src))))]
[(SexpSource? src)
#f]
[(UninterpretedSource? src)
#f]))
(define (get-javascript-implementation src)
(define (get-provided-name-code bytecode)
(match bytecode
[(struct Top [_ (struct Module (name path prefix requires provides code))])
(apply string-append
(map (lambda (p)
(format "modrec.namespace[~s] = exports[~s];\n"
(symbol->string (ModuleProvide-internal-name p))
(symbol->string (ModuleProvide-external-name p))))
provides))]
[else
""]))
(cond
[(StatementsSource? src)
(error 'get-javascript-implementation src)]
[(MainModuleSource? src)
(get-javascript-implementation (MainModuleSource-source src))]
[(ModuleSource? src)
(let ([name (rewrite-path (ModuleSource-path src))]
[text (query:query `(file ,(path->string (ModuleSource-path src))))]
[bytecode (parse-bytecode (ModuleSource-path src))])
(make-UninterpretedSource
(format "
MACHINE.modules[~s] =
new plt.runtime.ModuleRecord(~s,
function(MACHINE) {
if(--MACHINE.callsBeforeTrampoline<0) { throw arguments.callee; }
var modrec = MACHINE.modules[~s];
var exports = {};
modrec.isInvoked = true;
(function(MACHINE, RUNTIME, EXPORTS){~a})(MACHINE, plt.runtime, exports);
// FIXME: we need to inject the namespace with the values defined in exports.
~a
return MACHINE.control.pop().label(MACHINE);
});
"
(symbol->string name)
(symbol->string name)
(symbol->string name)
text
(get-provided-name-code bytecode))))]
[(SexpSource? src)
(error 'get-javascript-implementation)]
[(UninterpretedSource? src)
(error 'get-javascript-implementation)]))
(define (package source-code
#:should-follow-children? should-follow?
#:output-port op)
(define (wrap-source src)
(cond
[(source-is-javascript-module? src)
(get-javascript-implementation src)]
[else
src]))
(define (on-visit-src src ast stmts)
(cond
[(UninterpretedSource? src)
(fprintf op (UninterpretedSource-datum src))]
[else
(assemble/write-invoke stmts op)
(fprintf op "(MACHINE, function() { ")]))
(define (after-visit-src src ast stmts)
(cond
[(UninterpretedSource? src)
(void)]
[else
(fprintf op " }, FAIL, PARAMS);")]))
(define (on-last-src)
(fprintf op "SUCCESS();"))
(define packaging-configuration
(make-Configuration
wrap-source
should-follow?
on-visit-src
after-visit-src
on-last-src))
(fprintf op "var invoke = (function(MACHINE, SUCCESS, FAIL, PARAMS) {")
(fprintf op " plt.runtime.ready(function() {")
(make (list (make-MainModuleSource source-code))
packaging-configuration)
(fprintf op " });") (fprintf op "});\n"))
(define (package-standalone-xhtml source-code op)
(display *header* op)
(display (quote-cdata (get-runtime)) op)
(display (quote-cdata (get-code source-code)) op)
(display *footer* op))
(define (write-runtime op)
(define (wrap-source src) src)
(let ([packaging-configuration
(make-Configuration
wrap-source
(lambda (src) #t)
(lambda (src ast stmts)
(assemble/write-invoke stmts op)
(fprintf op "(MACHINE, function() { "))
(lambda (src ast stmts)
(fprintf op " }, FAIL, PARAMS);"))
(lambda ()
(fprintf op "SUCCESS();")))])
(display (runtime:get-runtime) op)
(newline op)
(fprintf op "(function(MACHINE, SUCCESS, FAIL, PARAMS) {")
(make (list only-bootstrapped-code) packaging-configuration)
(fprintf op "})(plt.runtime.currentMachine,\nfunction(){ plt.runtime.setReadyTrue(); },\nfunction(){},\n{});\n")))
(define (compress x)
(if (current-compress-javascript?)
(closure-compile x)
x))
(define *the-runtime*
(let ([buffer (open-output-string)])
(write-runtime buffer)
(compress
(get-output-string buffer))))
(define (get-runtime)
*the-runtime*)
(define *header*
#<<EOF
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta charset="utf-8"/>
<title>Example</title>
</head>
<script>
EOF
)
(define (get-code source-code)
(let ([buffer (open-output-string)])
(package source-code
#:should-follow-children? (lambda (src) #t)
#:output-port buffer)
(compress
(get-output-string buffer))))
(define (get-standalone-code source-code)
(let ([buffer (open-output-string)])
(write-standalone-code source-code buffer)
(compress
(get-output-string buffer))))
(define (write-standalone-code source-code op)
(package-anonymous source-code
#:should-follow-children? (lambda (src) #t)
#:output-port op)
(fprintf op "()(plt.runtime.currentMachine, function() {}, function() {}, {});\n"))
(define *footer*
#<<EOF
<![CDATA[
var invokeMainModule = function() {
var MACHINE = plt.runtime.currentMachine invoke(MACHINE,
function() {
plt.runtime.invokeMains(
MACHINE,
function() {
// On main module invokation success
},
function(MACHINE, e) {
// On main module invokation failure
if (console && console.log) {
console.log(e.stack || e) }
MACHINE.params.currentErrorDisplayer(
MACHINE, $(plt.helpers.toDomNode(e.stack || e)).css('color', 'red')) })},
function() {
// On module loading failure
if (console && console.log) {
console.log(e.stack || e) }
},
{})}
$(document).ready(invokeMainModule)]]>
</script>
<body></body>
</html>
EOF
)