Calling convention for JavaScript?

hi all, We've been making some progress with GHCJS [1] recently (preemptive lightweight threads, async io, black holes and async exceptions work in the new code generator now), but have run into a problem with FFI imports. So far we've been using the ccall import syntax: foreign import ccall "sin" :: CDouble -> CDouble This would import the JavaScript function `h$sin` (in order to reduce clashes with other JavaScript functions in foreign imports of existing Haskell packages). Other than the ccall name, which is just a minor niggle, this worked completely fine. Now we would like to extend this, for example: foreign import ccall "@cos" :: CDouble -> CDouble (@ would escape the usual `h$` prefixing) foreign import ccall "$r = $1.someMethod($2)" :: JSObject -> CDouble -> CDouble (inline JavaScript macro, similar to Fay and UHC-JS) Unfortunately GHC rejects these, since they're not valid C identifiers. What we need is some calling convention that just accepts any import string, but otherwise behaves like ccall. What would be a good way of doing this, is it possible without changing GHC? If not, would it be acceptable to add a calling convention? Suggestions welcome! luite [1] https://github.com/ghcjs/ghcjs/tree/gen2-64-alth

My guess is that you're out of luck without extending FFI to support another convention. Here's a possible workaround, however: continue to use ccall import syntax, but provide the extra information you wanted to convey in the name out-of-band. Cheers, Edward Excerpts from Luite Stegeman's message of Sun Mar 17 23:55:41 -0700 2013:
hi all,
We've been making some progress with GHCJS [1] recently (preemptive lightweight threads, async io, black holes and async exceptions work in the new code generator now), but have run into a problem with FFI imports.
So far we've been using the ccall import syntax:
foreign import ccall "sin" :: CDouble -> CDouble
This would import the JavaScript function `h$sin` (in order to reduce clashes with other JavaScript functions in foreign imports of existing Haskell packages). Other than the ccall name, which is just a minor niggle, this worked completely fine.
Now we would like to extend this, for example:
foreign import ccall "@cos" :: CDouble -> CDouble (@ would escape the usual `h$` prefixing)
foreign import ccall "$r = $1.someMethod($2)" :: JSObject -> CDouble -> CDouble (inline JavaScript macro, similar to Fay and UHC-JS)
Unfortunately GHC rejects these, since they're not valid C identifiers. What we need is some calling convention that just accepts any import string, but otherwise behaves like ccall. What would be a good way of doing this, is it possible without changing GHC? If not, would it be acceptable to add a calling convention?
Suggestions welcome!
luite

On Mon, Mar 18, 2013 at 8:34 AM, Edward Z. Yang
My guess is that you're out of luck without extending FFI to support another convention. Here's a possible workaround, however: continue to use ccall import syntax, but provide the extra information you wanted to convey in the name out-of-band.
I've been thinking about this before, but I haven't found a good way to do that yet, other than with Template Haskell. The point of the inline JavaScript macros in particular is to give users a concise and orderly way to do more complex imports, without external files. We generate code from StgSyn, so that's pretty much the information we have from the source file. I talked with Duncan in #ghc and it looks like it's easy to add another calling convention. Since GHCJS requires HEAD anyway (aiming for a release on hackage when GHC 7.8.1 comes out) I'll make some patches. The result should look something like this: -- calculate the hyperbolic tangent foreign import javascript "var x = 2*$1; $r = Math.exp(x-1)/Math.exp(x+1);" js_tanh :: Double -> Double -- copy part of a byte array foreign import javascript "for(var i=0;i<$5;i++) { $3[i+$4] = $1[i+$2]; }" js_copyArray :: ByteArray# -> Int -> ByteArray# -> Int -> Int -> IO () -- do an async AJAX request with jQuery, return the status code -- the current Haskell thread is suspended (in interruptible state) -- until $c is called foreign import safe javascript "jQuery.get(h$decodeUtf8z($1_1,$1_2))\ \ .done(function(d,status) { $c(parseInt(status,10)); })\ \ .fail(function() { $c(-1); });" js_ajaxStatus :: CString -> IO Int main = do withCString "http://haskell.org/" $ \url -> do mstatus <- timeout 1000000 $ js_ajaxStatus url putStrLn $ maybe "server took too long to respond" (\x -> "http status: " ++ show x) mstatus Comments welcome! notes: 1. local variables declared in the javascript import macros are converted to unique names in the resulting code 2. safe imports can perform asynchronous actions, following the familiar callback pattern in JavaScript. They can also start new Haskell threads (and wait for their results) or otherwise interact with the GHCJS green thread scheduler. They're internally implemented with an MVar, a waiting thread can still receive async exceptions. 3. all of this, other than the "foreign import javacript" part already works, i pushed changes for adding threading, async exceptions and async ffi to the github repository this week. luite p.s. sorry Edward for sending the mail only to your address first
participants (2)
-
Edward Z. Yang
-
Luite Stegeman