diff --git a/racketscript-compiler/racketscript/compiler/expand.rkt b/racketscript-compiler/racketscript/compiler/expand.rkt index cbe1d51c..8649245f 100644 --- a/racketscript-compiler/racketscript/compiler/expand.rkt +++ b/racketscript-compiler/racketscript/compiler/expand.rkt @@ -218,14 +218,27 @@ (define unchecked? (syntax-property v 'racketscript-unchecked-lambda?)) (define fabsyn (formals->absyn #'formals)) (PlainLambda fabsyn (map to-absyn (syntax->list #'body)) unchecked?)] + ;; NOTE: js require cannot be used without define (see next 4 cases) [(define-values (name) (#%plain-app (~datum #%js-ffi) (quote (~datum require)) (quote mod:str))) - ;; HACK: Special case for JSRequire (JSRequire (syntax-e #'name) (syntax-e #'mod) 'default)] [(define-values (name) (#%plain-app (~datum #%js-ffi) (quote (~datum require)) (quote *) (quote mod:str))) - ;; HACK: Special case for JSRequire (JSRequire (syntax-e #'name) (syntax-e #'mod) '*)] + [(define-values (name) + (#%plain-app (~datum #%js-ffi) (quote (~datum requirerkt)) (quote mod:str))) + ;; js ids not part of dependency calculation, so manually add + (current-module-imports + (set-add (current-module-imports) + (path->complete-path (string->path (syntax-e #'mod))))) + (JSRequire (syntax-e #'name) (string-append "./" (syntax-e #'mod) ".js") 'default)] + [(define-values (name) + (#%plain-app (~datum #%js-ffi) (quote (~datum requirerkt)) (quote *) (quote mod:str))) + ;; js ids not part of dependency calculation, so manually add + (current-module-imports + (set-add (current-module-imports) + (path->complete-path (string->path (syntax-e #'mod))))) + (JSRequire (syntax-e #'name) (string-append "./" (syntax-e #'mod) ".js") '*)] [(define-values (id ...) b) (DefineValues (syntax->datum #'(id ...)) (to-absyn #'b))] [(#%top . x) (TopId (syntax-e #'x))] diff --git a/racketscript-compiler/racketscript/interop.rkt b/racketscript-compiler/racketscript/interop.rkt index ef492c27..2132db51 100644 --- a/racketscript-compiler/racketscript/interop.rkt +++ b/racketscript-compiler/racketscript/interop.rkt @@ -7,6 +7,7 @@ $/array $/require $/require/* + $/require/rkt $$ $> $/:= @@ -150,6 +151,13 @@ [(_ mod:str) #`(#%js-ffi 'require '* mod)])) +(define-syntax ($/require/rkt stx) + (syntax-parse stx + [(_ mod:str) + #`(#%js-ffi 'requirerkt mod)] + [(_ mod:str (~datum *)) + #`(#%js-ffi 'requirerkt '* mod)])) + (define-syntax ($> stx) (define-syntax-class chaincall (pattern [fieldname:id ρ:expr ...])) diff --git a/racketscript-doc/racketscript/scribblings/ffi.scrbl b/racketscript-doc/racketscript/scribblings/ffi.scrbl index 438d4f8b..83883dcb 100644 --- a/racketscript-doc/racketscript/scribblings/ffi.scrbl +++ b/racketscript-doc/racketscript/scribblings/ffi.scrbl @@ -43,6 +43,7 @@ which will expand to the appropriate call to @racket[#%js-ffi]. (#%js-ffi 'instanceof obj type) (#%js-ffi 'string str) (#%js-ffi 'require mod) + (#%js-ffi 'requirerkt mod) (#%js-ffi 'operator 'op operand ...)) ]{} @@ -64,6 +65,7 @@ Summary of JavaScript operations supported by @racket[#%js-ffi]: @item{@racket['instanceof]: JS @tt{instanceof} operation} @item{@racket['string]: JS strings (incompatible with Racket/RacketScript strings, see @racket[$/str])} @item{@racket['require]: JS @tt{import}, use to import JS libraries} + @item{@racket['requirerkt]: JS @tt{import}, use to import Racket libraries as JS} @item{@racket['operator]: Use to call JS functions requiring infix notation} ] @@ -135,7 +137,7 @@ Shorthand for multiple @racket[$]s. Allows more direct use of dot notation in Ra ([mod string?])]{ JavaScript import statement. - Often used with @racket[define], e.g., @racket[(define express ($/require "express"))] compiles to: + Must be used with @racket[define], e.g., @racket[(define express ($/require "express"))] compiles to: @tt{import * as express from "express";} @@ -149,6 +151,23 @@ Shorthand for multiple @racket[$]s. Allows more direct use of dot notation in Ra Shorthand for @racket[($/require mod *)]} +@defform*[#:literals (*) + (($/require/rkt mod) + ($/require/rkt mod *)) + #:contracts + ([mod string?])]{ + JavaScript import statement, but for Racket files, i.e., @racket[mod] + is a Racket file name whose compiled JS file gets required in the output JS. + + This form is needed because the RacketScript compiler's dependency + calculations skips JS identifiers. + + Must be used with @racket[define], e.g., @racket[(define lib ($/require/rkt "lib.rkt"))] compiles to: + + @tt{import * as lib from "lib.rkt.js";} + + Equivalent to @racket[(#%js-ffi 'requirerkt mod)] or @racket[(#%js-ffi 'requirerkt '* mod)]} + @defform[($> e call ...) #:grammar ([call id diff --git a/racketscript-doc/racketscript/scribblings/start.scrbl b/racketscript-doc/racketscript/scribblings/start.scrbl index 1fd5a3fc..b0983f39 100644 --- a/racketscript-doc/racketscript/scribblings/start.scrbl +++ b/racketscript-doc/racketscript/scribblings/start.scrbl @@ -1,7 +1,6 @@ #lang scribble/manual @title[#:tag "start"]{Getting Started} - } @section[#:tag "install"]{Installation} diff --git a/tests/ffi/requirerkt.rkt b/tests/ffi/requirerkt.rkt new file mode 100644 index 00000000..0cb458c0 --- /dev/null +++ b/tests/ffi/requirerkt.rkt @@ -0,0 +1,8 @@ +#lang racketscript/base +(require racketscript/interop) + +;; fixes pr#278 + +(define lib ($/require/rkt "rktlib.rkt")) + +(#js.lib.f 10) diff --git a/tests/ffi/rktlib.rkt b/tests/ffi/rktlib.rkt new file mode 100644 index 00000000..b10addd6 --- /dev/null +++ b/tests/ffi/rktlib.rkt @@ -0,0 +1,4 @@ +#lang racket/base +;; test for pr#278 +(provide f) +(define (f x) x)