#lang scheme/base
(require (only-in scheme/list empty? empty first rest)
scheme/runtime-path
scheme/port
"stx.ss"
"beginner-to-javascript.ss"
"helpers.ss")
(define-runtime-path
compiler-path
"../../support/js/runtime/compiler.js")
(define-runtime-path
standalone-compiler-path
"../../support/js/runtime/standalone-compiler.js")
(define-runtime-path permission-struct-path
"../../support/js/runtime/permission-struct.js")
(define-runtime-path syntax-path
"../../support/js/runtime/stx.js")
(define-runtime-path effect-struct-path
"../../support/js/runtime/effect-struct.js")
(define-runtime-path types.js "../../support/js/runtime/types.js")
(define-runtime-path kernel.js "../../support/js/runtime/kernel.js")
(define-runtime-path read.js "../../support/js/runtime/read.js")
(define (write-compiler)
(boot-compile-to-file "beginner-to-javascript.ss" compiler-path)
(boot-compile-to-file "stx.ss" syntax-path)
(boot-compile-to-file "permission.ss" permission-struct-path)
(boot-compile-to-file "effect-struct.ss" effect-struct-path)
(call-with-output-file standalone-compiler-path
(lambda (op)
(display "// This is the standalone compiler.\n" op)
(display "// It's been automatically generated by bootstrap-js-compiler.ss\n" op)
(display "// Please don't hand-edit this file.\n" op)
(display "// compile: string -> (list string, (listof string))\n" op)
(display "var compile = (function() {\n" op)
(copy-path-to-port types.js op)
(copy-path-to-port kernel.js op)
(copy-path-to-port read.js op)
(display (bootstrap-compile "beginner-to-javascript.ss") op)
(display "
function listToArray(aList) {
var anArray = [];
while (!aList.isEmpty()) {
anArray.push(aList.first());
aList = aList.rest();
}
return anArray;
}
var aPinfo = get_dash_base_dash_pinfo(plt.types.Symbol.makeInstance('moby'));
return function(s) {
var exprs = plt.reader.readSchemeExpressions(s);
var compiledProgram =
program_dash__greaterthan_compiled_dash_program_slash_pinfo(exprs, aPinfo);
var compiledSrc = compiled_dash_program_dash_main(compiledProgram);
var permList = pinfo_dash_permissions(compiled_dash_program_dash_pinfo(compiledProgram));
var perms = [];
while (!permList.isEmpty()) {
perms.push(
permission_dash__greaterthan_string(permList.first()));
permList = permList.rest();
}
return [compiledSrc, perms];
}})();"
op))
#:exists 'replace))
(define (boot-compile-to-file a-program-path an-output-path)
(call-with-output-file an-output-path
(lambda (op)
(display "// This is automatically generated by bootstrap-js-compiler.ss\n" op)
(display "// Please don't hand-edit this file.\n" op)
(display (bootstrap-compile a-program-path)
op))
#:exists 'replace))
(define (copy-path-to-port path outp)
(call-with-input-file path
(lambda (ip)
(copy-port ip outp))))
(define (bootstrap-compile a-path)
(compiled-program-main/expose
(program->compiled-program (get-big-program a-path))))
(define (get-big-program a-path)
(let* ([modules (find-transitive-required-modules a-path)]
[big-program (apply append (map (lambda (p)
(remove-requires
(remove-provide/contracts
(read-program p))))
modules))])
big-program))
(define (find-transitive-required-modules a-path)
(unique
(let loop ([a-path a-path])
(let ([new-paths
(get-require-paths (read-program a-path))])
(cond
[(empty? new-paths)
(list a-path)]
[else
(append
(apply append
(map loop new-paths))
(list a-path))])))))
(define (read-program a-path)
(call-with-input-file a-path
(lambda (ip)
(check-special-lang-line! a-path (read-line ip)) (stx-e
(datum->stx
(let loop ([elt (read ip)])
(cond
[(eof-object? elt)
empty]
[else
(cons elt (loop (read ip)))]))
(make-Loc 0 0 0 ""))))))
(define (check-special-lang-line! source a-line)
(unless (regexp-match #rx"^#lang s-exp \"lang.ss\"$" a-line)
(error 'check-special-line! "~s needs to be written in lang.ss language" source)))
(define (get-require-paths a-program)
(cond
[(empty? a-program)
empty]
[(library-require? (first a-program))
(append (map stx-e (rest (stx-e (first a-program))))
(get-require-paths (rest a-program)))]
[else
(get-require-paths (rest a-program))]))
(define (remove-provide/contracts a-program)
(filter (lambda (top-level)
(not (stx-begins-with? top-level 'provide/contract)))
a-program))
(define (remove-requires a-program)
(filter (lambda (top-level)
(not (stx-begins-with? top-level 'require)))
a-program))
(define (unique elts)
(let ([ht (make-hash)])
(let loop ([elts elts])
(cond
[(empty? elts)
empty]
[(hash-ref ht (first elts) #f)
(loop (rest elts))]
[else
(hash-set! ht (first elts) #t)
(cons (first elts)
(loop (rest elts)))]))))