V8/0000755000175100001440000000000013077564201010572 5ustar hornikusersV8/inst/0000755000175100001440000000000013017015710011535 5ustar hornikusersV8/inst/doc/0000755000175100001440000000000013062005777012316 5ustar hornikusersV8/inst/doc/npm.html0000644000175100001440000016406013077470237014010 0ustar hornikusers Using NPM packages in V8

Using NPM packages in V8

Jeroen Ooms

2017-04-24

What is V8 (not)

V8 is Google’s JavaScript engine that is used in Chrome, Node and other tools. However each of these programs implements most JavaScript functionality on top of V8. The naked V8 engine only provides basic ECMAscript, which does not include a lot of things that you might be used to. There is no I/O (network/disk), no event-loop and no DOM (window).

JS Engine Evented Network Disk DOM
Browser -
Node -
V8 - - - -

Currently the R package is just V8. Perhaps more will be added later, although both IO and DOM would require an event-loop, which disqualifies the simple eval-and-return pattern. In that case it would work more like a server (similar to the httpuv package). But for now we will be working with plain V8 and rely on R for I/O.

Can we use NPM?

Yes! But not all packages will work. Most libraries in npm are primarely written for Node or the browser. Obviously, anything that requires internet access, graphics or files is not going to work in plain V8. But there is quite a lot of stuff that does work.

Some general purpose libraries like underscore or crossfilter will work natively in V8:

ct <- v8()
ct$source(system.file("js/underscore.js", package="V8"))
ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}"))
                     mpg cyl disp  hp drat    wt  qsec vs am gear carb
Duster 360          14.3   8  360 245 3.21 3.570 15.84  0  0    3    4
Cadillac Fleetwood  10.4   8  472 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8  460 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8  440 230 3.23 5.345 17.42  0  0    3    4
Camaro Z28          13.3   8  350 245 3.73 3.840 15.41  0  0    3    4

However NPM assumes disk access to resolve dependencies. How is that going to work?

Browserify to the rescue

browserify logo

browserify logo

Browserify is a brilliant tool to bundle an npm package with all of its dependencies into a single js file that does not require disk access. It is mainly designed to make npm packages suitable for use on a webpage (duh) but it is useful with embedded V8 as well. To install it run:

npm install -g browserify

Example: beautify-js

Beautify-js is a simple npm package to fix linebreaks and indentation in JavaScript, HTML or CSS code. To bundle it up, run these three lines in a shell:

npm install js-beautify
echo "global.beautify = require('js-beautify');" > in.js
browserify in.js -o bundle.js

The first line will install js-beautify in a the current dir under node_modules. The second line creates the input file for browserify. In this case it consists of only one line that imports the js-beautify library and exports it to the global environment. The third line runs browserify and saves the output to a new file bundle.js.

We now have a file that we can load in V8. Assuming you ran the above commands in your Desktop directory:

ct <- v8()
ct$source("~/Desktop/bundle.js")

Let’s see whats in our global environment now:

ct$get(JS('Object.keys(global)'))
 [1] "console"      "print"        "global"       "ArrayBuffer" 
 [5] "Int8Array"    "Uint8Array"   "Int16Array"   "Uint16Array" 
 [9] "Int32Array"   "Uint32Array"  "Float32Array" "Float64Array"
[13] "DataView"     "beautify"    

The beautify library is available now.

Lets beautify stuff

To beautify JavaScript we need to use the js_beautify function. See the package homepage for a full list of options.

test <- "(function(x,y){x = x || 1; y = y || 1; return y * x;})(4, 9)"
pretty_test <- ct$call("beautify.js_beautify", test, list(indent_size = 2))
cat(pretty_test)
(function(x, y) {
  x = x || 1;
  y = y || 1;
  return y * x;
})(4, 9)

The package also includes functions to beautify css and html:

html <- "<ul><li>one</li><li>two</li><li>three</li></ul>"
cat(ct$call("beautify.html_beautify", html))
<ul>
    <li>one</li>
    <li>two</li>
    <li>three</li>
</ul>
V8/inst/doc/v8_intro.Rmd0000644000175100001440000002014713062005777014536 0ustar hornikusers--- title: "Introduction to V8 for R" date: "`r Sys.Date()`" output: html_document: highlight : "kate" vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{Introduction to V8 for R} \usepackage[utf8]{inputenc} --- ```{r, echo = FALSE, message = FALSE} knitr::opts_chunk$set(comment = "") library(V8) ``` V8 is Google’s open source, high performance JavaScript engine. It is written in C++ and implements ECMAScript as specified in ECMA-262, 5th edition. The V8 R package builds on the C++ library to provide a completely standalone JavaScript engine within R: ```{r} # Create a new context ct <- v8() # Evaluate some code ct$eval("var foo = 123") ct$eval("var bar = 456") ct$eval("foo + bar") ``` A major advantage over the other foreign language interfaces is that V8 requires no compilers, external executables or other run-time dependencies. The entire engine is contained within a 6MB package (2MB zipped) and works on all major platforms. ```{r} # Create some JSON cat(ct$eval("JSON.stringify({x:Math.random()})")) # Simple closure ct$eval("(function(x){return x+1;})(123)") ``` However note that V8 by itself is just the naked JavaScript engine. Currently, there is no DOM (i.e. no *window* object), no network or disk IO, not even an event loop. Which is fine because we already have all of those in R. In this sense V8 resembles other foreign language interfaces such as Rcpp or rJava, but then for JavaScript. ## Loading JavaScript Libraries The `ct$source` method is a convenience function for loading JavaScript libraries from a file or url. ```{r, eval=FALSE} ct$source(system.file("js/underscore.js", package="V8")) ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js") ``` ```{r echo=FALSE, results='hide'} ct$source(system.file("js/underscore.js", package="V8")) ct$source(system.file("js/crossfilter.js", package="V8")) ``` ## Data Interchange By default all data interchange between R and JavaScript happens via JSON using the bidirectional mapping implemented in the [jsonlite](http://arxiv.org/abs/1403.2805) package. ```{r} ct$assign("mydata", mtcars) ct$get("mydata") ``` Alternatively use `JS()` to assign the value of a JavaScript expression (without converting to JSON): ```{r} ct$assign("foo", JS("function(x){return x*x}")) ct$assign("bar", JS("foo(9)")) ct$get("bar") ``` ## Function Calls The `ct$call` method calls a JavaScript function, automatically converting objects (arguments and return value) between R and JavaScript: ```{r} ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}")) ``` It looks a bit like `.Call` but then for JavaScript instead of C. ## Interactive JavaScript Console A fun way to learn JavaScript or debug a session is by entering the interactive console: ```{r, eval=FALSE} # Load some data data(diamonds, package = "ggplot2") ct$assign("diamonds", diamonds) ct$console() ``` From here you can interactively work in JavaScript without typing `ct$eval` every time: ```javascript var cf = crossfilter(diamonds) var price = cf.dimension(function(x){return x.price}) var depth = cf.dimension(function(x){return x.depth}) price.filter([2000, 3000]) output = depth.top(10) ``` To exit the console, either press `ESC` or type `exit`. Afterwards you can retrieve the objects back into R: ```{r, eval=FALSE} output <- ct$get("output") print(output) ``` ## Conditions (warnings, errors and console.log) Evaluating invalid JavaScript code results in a SyntaxError: ```{r, error=TRUE, purl = FALSE} # A common typo ct$eval('var foo <- 123;') ``` JavaScript runtime exceptions are automatically propagated into R errors: ```{r, error=TRUE, purl = FALSE} # Runtime errors ct$eval("123 + doesnotexit") ``` Within JavaScript we can also call back to the R console manually using `console.log`, `console.warn` and `console.error`. This allows for explicilty generating output, warnings or errors from within a JavaScript application. ```{r, error = TRUE, purl = FALSE} ct$eval('console.log("this is a message")') ct$eval('console.warn("Heads up!")') ct$eval('console.error("Oh no! An error!")') ``` A example of using `console.error` is to verify that external resources were loaded: ```{r, eval=FALSE} ct <- v8() ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js") ct$eval('var cf = crossfilter || console.error("failed to load crossfilter!")') ``` ## The Global Namespace Unlike what you might be used to from Node or your browser, the global namespace for a new context if very minimal. By default it contains only a few objects: `global` (a refence to itself), `console` (for `console.log` and friends) and `print` (an alias of console.log needed by some JavaScript libraries) ```{r} ct <- v8(typed_arrays = FALSE); ct$get(JS("Object.keys(global)")) ``` If typed arrays are enabled it contains some additional functions: ```{r} ct <- v8(typed_arrays = TRUE); ct$get(JS("Object.keys(global)")) ``` A context always has a global scope, even when no name is set. When a context is initiated with `global = NULL`, it can still be reached by evaluating the `this` keyword within the global scope: ```{r} ct2 <- v8(global = NULL, console = FALSE) ct2$get(JS("Object.keys(this).length")) ct2$assign("cars", cars) ct2$eval("var foo = 123") ct2$eval("function test(x){x+1}") ct2$get(JS("Object.keys(this).length")) ct2$get(JS("Object.keys(this)")) ``` To create your own global you could use something like: ```{r} ct2$eval("var __global__ = this") ct2$eval("(function(){var bar = [1,2,3,4]; __global__.bar = bar; })()") ct2$get("bar") ``` ## Syntax Validation V8 also allows for validating JavaScript syntax, without actually evaluating it. ```{r} ct$validate("function foo(x){2*x}") ct$validate("foo = function(x){2*x}") ``` This might be useful for all those R libraries that generate browser graphics via templated JavaScript. Note that JavaScript does not allow for defining anonymous functions in the global scope: ```{r} ct$validate("function(x){2*x}") ``` To check if an anonymous function is syntactically valid, prefix it with `!` or wrap in `()`. These are OK: ```{r} ct$validate("(function(x){2*x})") ct$validate("!function(x){2*x}") ``` ## Callback To R A recently added feature is to interact with R from within JavaScript using the `console.r` API`. This is most easily demonstrated via the interactive console. ```{r, eval=FALSE} ctx <- v8() ctx$console() ``` From JavaScript we can read/write R objects via `console.r.get` and `console.r.assign`. The final argument is an optional list specifying arguments passed to `toJSON` or `fromJSON`. ```javascript // read the iris object into JS var iris = console.r.get("iris") var iris_col = console.r.get("iris", {dataframe : "col"}) //write an object back to the R session console.r.assign("iris2", iris) console.r.assign("iris3", iris, {simplifyVector : false}) ``` To call R functions use `console.r.call`. The first argument should be a string which evaluates to a function. The second argument contains a list of arguments passed to the function, similar to `do.call` in R. Both named and unnamed lists are supported. The return object is returned to JavaScript via JSON. ```javascript //calls rnorm(n=2, mean=10, sd=5) var out = console.r.call('rnorm', {n: 2,mean:10, sd:5}) var out = console.r.call('rnorm', [2, 20, 5]) //anonymous function var out = console.r.call('function(x){x^2}', {x:12}) ``` There is also an `console.r.eval` function, which evaluates some code. It takes only a single argument (the string to evaluate) and does not return anything. Output is printed to the console. ```javascript console.r.eval('sessionInfo()') ``` Besides automatically converting objects, V8 also propagates exceptions between R, C++ and JavaScript up and down the stack. Hence you can catch R errors as JavaScript exceptions when calling an R function from JavaScript or vice versa. If nothing gets caught, exceptions bubble all the way up as R errors in your top-level R session. ```javascript //raise an error in R console.r.call('stop("ouch!")') //catch error from JavaScript try { console.r.call('stop("ouch!")') } catch (e) { console.log("Uhoh R had an error: " + e) } //# Uhoh R had an error: ouch! ``` V8/inst/doc/npm.R0000644000175100001440000000212413077470236013234 0ustar hornikusers## ---- echo = FALSE, message = FALSE-------------------------------------- knitr::opts_chunk$set(comment = "") library(V8) ## ------------------------------------------------------------------------ ct <- v8() ct$source(system.file("js/underscore.js", package="V8")) ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}")) ## ----eval=FALSE---------------------------------------------------------- # ct <- v8() # ct$source("~/Desktop/bundle.js") ## ----echo=FALSE, results='hide'------------------------------------------ ct <- v8() ct$source("beautify.js") ## ------------------------------------------------------------------------ ct$get(JS('Object.keys(global)')) ## ------------------------------------------------------------------------ test <- "(function(x,y){x = x || 1; y = y || 1; return y * x;})(4, 9)" pretty_test <- ct$call("beautify.js_beautify", test, list(indent_size = 2)) cat(pretty_test) ## ------------------------------------------------------------------------ html <- "" cat(ct$call("beautify.html_beautify", html)) V8/inst/doc/npm.Rmd0000644000175100001440000000770013062005777013560 0ustar hornikusers--- title: "Using NPM packages in V8" author: "Jeroen Ooms" date: "`r Sys.Date()`" vignette: > %\VignetteEngine{knitr::rmarkdown} %\VignetteIndexEntry{Using NPM packages in V8} \usepackage[utf8]{inputenc} output: knitr:::html_vignette: toc: yes --- ```{r, echo = FALSE, message = FALSE} knitr::opts_chunk$set(comment = "") library(V8) ``` ## What is V8 (not) V8 is Google's JavaScript engine that is used in Chrome, Node and other tools. However each of these programs implements most JavaScript functionality on top of V8. The naked V8 engine only provides basic ECMAscript, which does not include a lot of things that you might be used to. There is no I/O (network/disk), no event-loop and no DOM (window). | | JS Engine | Evented | Network | Disk | DOM | |---------|--------|-----------|------|---------|-----| | Browser | ✔ | ✔ | ✔ | - | ✔ | | Node | ✔ | ✔ | ✔ | ✔ | - | | V8 | ✔ | - | - | - | - | Currently the R package is just V8. Perhaps more will be added later, although both IO and DOM would require an event-loop, which disqualifies the simple eval-and-return pattern. In that case it would work more like a server (similar to the httpuv package). But for now we will be working with plain V8 and rely on R for I/O. ## Can we use NPM? Yes! But not all packages will work. Most libraries in [npm](https://www.npmjs.com) are primarely written for Node or the browser. Obviously, anything that requires internet access, graphics or files is not going to work in plain V8. But there is quite a lot of stuff that does work. Some general purpose libraries like underscore or crossfilter will work natively in V8: ```{r} ct <- v8() ct$source(system.file("js/underscore.js", package="V8")) ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}")) ``` However NPM assumes disk access to resolve dependencies. How is that going to work? ## Browserify to the rescue ![browserify logo](http://jeroen.github.io/V8/browserify.png) [Browserify](http://browserify.org/) is a brilliant tool to bundle an npm package with all of its dependencies into a single js file that does not require disk access. It is mainly designed to make npm packages suitable for use on a webpage (duh) but it is useful with embedded V8 as well. To install it run: ```bash npm install -g browserify ``` ## Example: beautify-js [Beautify-js](https://www.npmjs.com/package/js-beautify) is a simple npm package to fix linebreaks and indentation in JavaScript, HTML or CSS code. To bundle it up, run these three lines in a shell: ```bash npm install js-beautify echo "global.beautify = require('js-beautify');" > in.js browserify in.js -o bundle.js ``` The first line will install js-beautify in a the current dir under `node_modules`. The second line creates the input file for browserify. In this case it consists of only one line that imports the js-beautify library and exports it to the global environment. The third line runs browserify and saves the output to a new file `bundle.js`. We now have a file that we can load in V8. Assuming you ran the above commands in your Desktop directory: ```{r eval=FALSE} ct <- v8() ct$source("~/Desktop/bundle.js") ``` ```{r echo=FALSE, results='hide'} ct <- v8() ct$source("beautify.js") ``` Let's see whats in our global environment now: ```{r} ct$get(JS('Object.keys(global)')) ``` The `beautify` library is available now. ## Lets beautify stuff To beautify JavaScript we need to use the `js_beautify` function. See the [package homepage](https://www.npmjs.com/package/js-beautify) for a full list of options. ```{r} test <- "(function(x,y){x = x || 1; y = y || 1; return y * x;})(4, 9)" pretty_test <- ct$call("beautify.js_beautify", test, list(indent_size = 2)) cat(pretty_test) ``` The package also includes functions to beautify css and html: ```{r} html <- "" cat(ct$call("beautify.html_beautify", html)) ``` V8/inst/doc/v8_intro.html0000644000175100001440000251127113077470240014762 0ustar hornikusers Introduction to V8 for R

V8 is Google’s open source, high performance JavaScript engine. It is written in C++ and implements ECMAScript as specified in ECMA-262, 5th edition. The V8 R package builds on the C++ library to provide a completely standalone JavaScript engine within R:

# Create a new context
ct <- v8()

# Evaluate some code
ct$eval("var foo = 123")
ct$eval("var bar = 456")
ct$eval("foo + bar")
[1] "579"

A major advantage over the other foreign language interfaces is that V8 requires no compilers, external executables or other run-time dependencies. The entire engine is contained within a 6MB package (2MB zipped) and works on all major platforms.

# Create some JSON
cat(ct$eval("JSON.stringify({x:Math.random()})"))
{"x":0.9552653292194009}
# Simple closure
ct$eval("(function(x){return x+1;})(123)")
[1] "124"

However note that V8 by itself is just the naked JavaScript engine. Currently, there is no DOM (i.e. no window object), no network or disk IO, not even an event loop. Which is fine because we already have all of those in R. In this sense V8 resembles other foreign language interfaces such as Rcpp or rJava, but then for JavaScript.

Loading JavaScript Libraries

The ct$source method is a convenience function for loading JavaScript libraries from a file or url.

ct$source(system.file("js/underscore.js", package="V8"))
ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js")

Data Interchange

By default all data interchange between R and JavaScript happens via JSON using the bidirectional mapping implemented in the jsonlite package.

ct$assign("mydata", mtcars)
ct$get("mydata")
                     mpg cyl  disp  hp drat    wt  qsec vs am gear carb
Mazda RX4           21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
Datsun 710          22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive      21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout   18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2
Valiant             18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
Duster 360          14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4
Merc 240D           24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2
Merc 230            22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2
Merc 280            19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
Merc 280C           17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
Merc 450SE          16.4   8 275.8 180 3.07 4.070 17.40  0  0    3    3
Merc 450SL          17.3   8 275.8 180 3.07 3.730 17.60  0  0    3    3
Merc 450SLC         15.2   8 275.8 180 3.07 3.780 18.00  0  0    3    3
Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8 440.0 230 3.23 5.345 17.42  0  0    3    4
Fiat 128            32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
Honda Civic         30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
Toyota Corolla      33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
Toyota Corona       21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1
Dodge Challenger    15.5   8 318.0 150 2.76 3.520 16.87  0  0    3    2
AMC Javelin         15.2   8 304.0 150 3.15 3.435 17.30  0  0    3    2
Camaro Z28          13.3   8 350.0 245 3.73 3.840 15.41  0  0    3    4
Pontiac Firebird    19.2   8 400.0 175 3.08 3.845 17.05  0  0    3    2
Fiat X1-9           27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
Porsche 914-2       26.0   4 120.3  91 4.43 2.140 16.70  0  1    5    2
Lotus Europa        30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
Ford Pantera L      15.8   8 351.0 264 4.22 3.170 14.50  0  1    5    4
Ferrari Dino        19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
Maserati Bora       15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
Volvo 142E          21.4   4 121.0 109 4.11 2.780 18.60  1  1    4    2

Alternatively use JS() to assign the value of a JavaScript expression (without converting to JSON):

ct$assign("foo", JS("function(x){return x*x}"))
ct$assign("bar", JS("foo(9)"))
ct$get("bar")
[1] 81

Function Calls

The ct$call method calls a JavaScript function, automatically converting objects (arguments and return value) between R and JavaScript:

ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}"))
                     mpg cyl disp  hp drat    wt  qsec vs am gear carb
Duster 360          14.3   8  360 245 3.21 3.570 15.84  0  0    3    4
Cadillac Fleetwood  10.4   8  472 205 2.93 5.250 17.98  0  0    3    4
Lincoln Continental 10.4   8  460 215 3.00 5.424 17.82  0  0    3    4
Chrysler Imperial   14.7   8  440 230 3.23 5.345 17.42  0  0    3    4
Camaro Z28          13.3   8  350 245 3.73 3.840 15.41  0  0    3    4

It looks a bit like .Call but then for JavaScript instead of C.

Interactive JavaScript Console

A fun way to learn JavaScript or debug a session is by entering the interactive console:

# Load some data
data(diamonds, package = "ggplot2")
ct$assign("diamonds", diamonds)
ct$console()

From here you can interactively work in JavaScript without typing ct$eval every time:

var cf = crossfilter(diamonds)
var price = cf.dimension(function(x){return x.price})
var depth = cf.dimension(function(x){return x.depth})
price.filter([2000, 3000])
output = depth.top(10)

To exit the console, either press ESC or type exit. Afterwards you can retrieve the objects back into R:

output <- ct$get("output")
print(output)

Conditions (warnings, errors and console.log)

Evaluating invalid JavaScript code results in a SyntaxError:

# A common typo
ct$eval('var foo <- 123;')
Error in context_eval(join(src), private$context): SyntaxError: Unexpected token <

JavaScript runtime exceptions are automatically propagated into R errors:

# Runtime errors
ct$eval("123 + doesnotexit")
Error in context_eval(join(src), private$context): ReferenceError: doesnotexit is not defined

Within JavaScript we can also call back to the R console manually using console.log, console.warn and console.error. This allows for explicilty generating output, warnings or errors from within a JavaScript application.

ct$eval('console.log("this is a message")')
this is a message
ct$eval('console.warn("Heads up!")')
Warning: Heads up!
ct$eval('console.error("Oh no! An error!")')
Error in context_eval(join(src), private$context): Oh no! An error!

A example of using console.error is to verify that external resources were loaded:

ct <- v8()
ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js")
ct$eval('var cf = crossfilter || console.error("failed to load crossfilter!")')

The Global Namespace

Unlike what you might be used to from Node or your browser, the global namespace for a new context if very minimal. By default it contains only a few objects: global (a refence to itself), console (for console.log and friends) and print (an alias of console.log needed by some JavaScript libraries)

ct <- v8(typed_arrays = FALSE);
ct$get(JS("Object.keys(global)"))
[1] "console" "print"   "global" 

If typed arrays are enabled it contains some additional functions:

ct <- v8(typed_arrays = TRUE);
ct$get(JS("Object.keys(global)"))
 [1] "console"      "print"        "global"       "ArrayBuffer" 
 [5] "Int8Array"    "Uint8Array"   "Int16Array"   "Uint16Array" 
 [9] "Int32Array"   "Uint32Array"  "Float32Array" "Float64Array"
[13] "DataView"    

A context always has a global scope, even when no name is set. When a context is initiated with global = NULL, it can still be reached by evaluating the this keyword within the global scope:

ct2 <- v8(global = NULL, console = FALSE)
ct2$get(JS("Object.keys(this).length"))
[1] 10
ct2$assign("cars", cars)
ct2$eval("var foo = 123")
ct2$eval("function test(x){x+1}")
ct2$get(JS("Object.keys(this).length"))
[1] 13
ct2$get(JS("Object.keys(this)"))
 [1] "ArrayBuffer"  "Int8Array"    "Uint8Array"   "Int16Array"  
 [5] "Uint16Array"  "Int32Array"   "Uint32Array"  "Float32Array"
 [9] "Float64Array" "DataView"     "cars"         "foo"         
[13] "test"        

To create your own global you could use something like:

ct2$eval("var __global__ = this")
ct2$eval("(function(){var bar = [1,2,3,4]; __global__.bar = bar; })()")
ct2$get("bar")
[1] 1 2 3 4

Syntax Validation

V8 also allows for validating JavaScript syntax, without actually evaluating it.

ct$validate("function foo(x){2*x}")
[1] TRUE
ct$validate("foo = function(x){2*x}")
[1] TRUE

This might be useful for all those R libraries that generate browser graphics via templated JavaScript. Note that JavaScript does not allow for defining anonymous functions in the global scope:

ct$validate("function(x){2*x}")
[1] FALSE

To check if an anonymous function is syntactically valid, prefix it with ! or wrap in (). These are OK:

ct$validate("(function(x){2*x})")
[1] TRUE
ct$validate("!function(x){2*x}")
[1] TRUE

Callback To R

A recently added feature is to interact with R from within JavaScript using the console.r API`. This is most easily demonstrated via the interactive console.

ctx <- v8()
ctx$console()

From JavaScript we can read/write R objects via console.r.get and console.r.assign. The final argument is an optional list specifying arguments passed to toJSON or fromJSON.

// read the iris object into JS
var iris = console.r.get("iris")
var iris_col = console.r.get("iris", {dataframe : "col"})

//write an object back to the R session
console.r.assign("iris2", iris)
console.r.assign("iris3", iris, {simplifyVector : false})

To call R functions use console.r.call. The first argument should be a string which evaluates to a function. The second argument contains a list of arguments passed to the function, similar to do.call in R. Both named and unnamed lists are supported. The return object is returned to JavaScript via JSON.

//calls rnorm(n=2, mean=10, sd=5)
var out = console.r.call('rnorm', {n: 2,mean:10, sd:5})
var out = console.r.call('rnorm', [2, 20, 5])

//anonymous function
var out = console.r.call('function(x){x^2}', {x:12})

There is also an console.r.eval function, which evaluates some code. It takes only a single argument (the string to evaluate) and does not return anything. Output is printed to the console.

console.r.eval('sessionInfo()')

Besides automatically converting objects, V8 also propagates exceptions between R, C++ and JavaScript up and down the stack. Hence you can catch R errors as JavaScript exceptions when calling an R function from JavaScript or vice versa. If nothing gets caught, exceptions bubble all the way up as R errors in your top-level R session.

//raise an error in R
console.r.call('stop("ouch!")')

//catch error from JavaScript
try {
  console.r.call('stop("ouch!")')
} catch (e) {
  console.log("Uhoh R had an error: " + e)
}
//# Uhoh R had an error: ouch!
V8/inst/doc/v8_intro.R0000644000175100001440000000632413077470240014213 0ustar hornikusers## ---- echo = FALSE, message = FALSE-------------------------------------- knitr::opts_chunk$set(comment = "") library(V8) ## ------------------------------------------------------------------------ # Create a new context ct <- v8() # Evaluate some code ct$eval("var foo = 123") ct$eval("var bar = 456") ct$eval("foo + bar") ## ------------------------------------------------------------------------ # Create some JSON cat(ct$eval("JSON.stringify({x:Math.random()})")) # Simple closure ct$eval("(function(x){return x+1;})(123)") ## ---- eval=FALSE--------------------------------------------------------- # ct$source(system.file("js/underscore.js", package="V8")) # ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js") ## ----echo=FALSE, results='hide'------------------------------------------ ct$source(system.file("js/underscore.js", package="V8")) ct$source(system.file("js/crossfilter.js", package="V8")) ## ------------------------------------------------------------------------ ct$assign("mydata", mtcars) ct$get("mydata") ## ------------------------------------------------------------------------ ct$assign("foo", JS("function(x){return x*x}")) ct$assign("bar", JS("foo(9)")) ct$get("bar") ## ------------------------------------------------------------------------ ct$call("_.filter", mtcars, JS("function(x){return x.mpg < 15}")) ## ---- eval=FALSE--------------------------------------------------------- # # Load some data # data(diamonds, package = "ggplot2") # ct$assign("diamonds", diamonds) # ct$console() ## ---- eval=FALSE--------------------------------------------------------- # output <- ct$get("output") # print(output) ## ---- eval=FALSE--------------------------------------------------------- # ct <- v8() # ct$source("https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.11/crossfilter.min.js") # ct$eval('var cf = crossfilter || console.error("failed to load crossfilter!")') ## ------------------------------------------------------------------------ ct <- v8(typed_arrays = FALSE); ct$get(JS("Object.keys(global)")) ## ------------------------------------------------------------------------ ct <- v8(typed_arrays = TRUE); ct$get(JS("Object.keys(global)")) ## ------------------------------------------------------------------------ ct2 <- v8(global = NULL, console = FALSE) ct2$get(JS("Object.keys(this).length")) ct2$assign("cars", cars) ct2$eval("var foo = 123") ct2$eval("function test(x){x+1}") ct2$get(JS("Object.keys(this).length")) ct2$get(JS("Object.keys(this)")) ## ------------------------------------------------------------------------ ct2$eval("var __global__ = this") ct2$eval("(function(){var bar = [1,2,3,4]; __global__.bar = bar; })()") ct2$get("bar") ## ------------------------------------------------------------------------ ct$validate("function foo(x){2*x}") ct$validate("foo = function(x){2*x}") ## ------------------------------------------------------------------------ ct$validate("function(x){2*x}") ## ------------------------------------------------------------------------ ct$validate("(function(x){2*x})") ct$validate("!function(x){2*x}") ## ---- eval=FALSE--------------------------------------------------------- # ctx <- v8() # ctx$console() V8/inst/js/0000755000175100001440000000000013062006450012152 5ustar hornikusersV8/inst/js/crossfilter.js0000644000175100001440000002253213062006450015053 0ustar hornikusers!function(r){function n(r){return r}function t(r,n){for(var t=0,e=n.length,u=Array(e);e>t;++t)u[t]=r[n[t]];return u}function e(r){function n(n,t,e,u){for(;u>e;){var f=e+u>>>1;r(n[f])e;){var f=e+u>>>1;t>>1)+1;--f>0;)e(r,f,u,n);return r}function t(r,n,t){for(var u,f=t-n;--f>0;)u=r[n],r[n]=r[n+f],r[n+f]=u,e(r,1,f,n);return r}function e(n,t,e,u){for(var f,o=n[--u+t],i=r(o);(f=t<<1)<=e&&(e>f&&r(n[u+f])>r(n[u+f+1])&&f++,!(i<=r(n[u+f])));)n[u+t]=n[u+f],t=f;n[u+t]=o}return n.sort=t,n}function f(r){function n(n,e,u,f){var o,i,a,c,l=Array(f=Math.min(u-e,f));for(i=0;f>i;++i)l[i]=n[e++];if(t(l,0,f),u>e){o=r(l[0]);do(a=r(c=n[e])>o)&&(l[0]=c,o=r(t(l,0,f)[0]));while(++eu;++u){for(var f=u,o=n[u],i=r(o);f>t&&r(n[f-1])>i;--f)n[f]=n[f-1];n[f]=o}return n}return n}function i(r){function n(r,n,u){return(N>u-n?e:t)(r,n,u)}function t(t,e,u){var f,o=0|(u-e)/6,i=e+o,a=u-1-o,c=e+u-1>>1,l=c-o,v=c+o,s=t[i],h=r(s),d=t[l],p=r(d),g=t[c],y=r(g),m=t[v],x=r(m),b=t[a],A=r(b);h>p&&(f=s,s=d,d=f,f=h,h=p,p=f),x>A&&(f=m,m=b,b=f,f=x,x=A,A=f),h>y&&(f=s,s=g,g=f,f=h,h=y,y=f),p>y&&(f=d,d=g,g=f,f=p,p=y,y=f),h>x&&(f=s,s=m,m=f,f=h,h=x,x=f),y>x&&(f=g,g=m,m=f,f=y,y=x,x=f),p>A&&(f=d,d=b,b=f,f=p,p=A,A=f),p>y&&(f=d,d=g,g=f,f=p,p=y,y=f),x>A&&(f=m,m=b,b=f,f=x,x=A,A=f);var k=d,O=p,w=m,E=x;t[i]=s,t[l]=t[e],t[c]=g,t[v]=t[u-1],t[a]=b;var M=e+1,U=u-2,z=E>=O&&O>=E;if(z)for(var N=M;U>=N;++N){var C=t[N],S=r(C);if(O>S)N!==M&&(t[N]=t[M],t[M]=C),++M;else if(S>O)for(;;){var q=r(t[U]);{if(!(q>O)){if(O>q){t[N]=t[M],t[M++]=t[U],t[U--]=C;break}t[N]=t[U],t[U--]=C;break}U--}}}else for(var N=M;U>=N;N++){var C=t[N],S=r(C);if(O>S)N!==M&&(t[N]=t[M],t[M]=C),++M;else if(S>E)for(;;){var q=r(t[U]);{if(!(q>E)){O>q?(t[N]=t[M],t[M++]=t[U],t[U--]=C):(t[N]=t[U],t[U--]=C);break}if(U--,N>U)break}}}if(t[e]=t[M-1],t[M-1]=k,t[u-1]=t[U+1],t[U+1]=w,n(t,e,M-1),n(t,U+2,u),z)return t;if(i>M&&U>a){for(var F,q;(F=r(t[M]))<=O&&F>=O;)++M;for(;(q=r(t[U]))<=E&&q>=E;)--U;for(var N=M;U>=N;N++){var C=t[N],S=r(C);if(O>=S&&S>=O)N!==M&&(t[N]=t[M],t[M]=C),M++;else if(E>=S&&S>=E)for(;;){var q=r(t[U]);{if(!(E>=q&&q>=E)){O>q?(t[N]=t[M],t[M++]=t[U],t[U--]=C):(t[N]=t[U],t[U--]=C);break}if(U--,N>U)break}}}}return n(t,M,U+1)}var e=o(r);return n}function a(r){for(var n=Array(r),t=-1;++tt;)r[t++]=0;return r}function l(r,n){if(n>32)throw Error("invalid array width!");return r}function v(r,n){return function(t){var e=t.length;return[r.left(t,n,0,e),r.right(t,n,0,e)]}}function s(r,n){var t=n[0],e=n[1];return function(n){var u=n.length;return[r.left(n,t,0,u),r.left(n,e,0,u)]}}function h(r){return[0,r.length]}function d(){return null}function p(){return 0}function g(r){return r+1}function y(r){return r-1}function m(r){return function(n,t){return n+ +r(t)}}function x(r){return function(n,t){return n-r(t)}}function b(){function r(r){var n=E,t=r.length;return t&&(b=b.concat(r),z=F(z,E+=t),S.forEach(function(e){e(r,n,t)})),l}function e(){for(var r=A(E,E),n=[],t=0,e=0;E>t;++t)z[t]?r[t]=e++:n.push(t);N.forEach(function(r){r(0,[],n)}),q.forEach(function(n){n(r)});for(var u,t=0,e=0;E>t;++t)(u=z[t])&&(t!==e&&(z[e]=u,b[e]=b[t]),++e);for(b.length=e;E>e;)z[--E]=0}function o(r){function e(n,e,u){T=n.map(r),V=$(k(u),0,u),T=t(T,V);var f,o=_(T),i=o[0],a=o[1];if(W)for(f=0;u>f;++f)W(T[f],f)||(z[V[f]+e]|=Y);else{for(f=0;i>f;++f)z[V[f]+e]|=Y;for(f=a;u>f;++f)z[V[f]+e]|=Y}if(!e)return P=T,Q=V,tn=i,en=a,void 0;var c=P,l=Q,v=0,s=0;for(P=Array(E),Q=A(E,E),f=0;e>v&&u>s;++f)c[v]v;++v,++f)P[f]=c[v],Q[f]=l[v];for(;u>s;++s,++f)P[f]=T[s],Q[f]=V[s]+e;o=_(P),tn=o[0],en=o[1]}function o(r,n,t){rn.forEach(function(r){r(T,V,n,t)}),T=V=null}function a(r){for(var n,t=0,e=0;E>t;++t)z[n=Q[t]]&&(t!==e&&(P[e]=P[t]),Q[e]=r[n],++e);for(P.length=e;E>e;)Q[e++]=0;var u=_(P);tn=u[0],en=u[1]}function c(r){var n=r[0],t=r[1];if(W)return W=null,G(function(r,e){return e>=n&&t>e}),tn=n,en=t,X;var e,u,f,o=[],i=[];if(tn>n)for(e=n,u=Math.min(tn,t);u>e;++e)z[f=Q[e]]^=Y,o.push(f);else if(n>tn)for(e=tn,u=Math.min(n,en);u>e;++e)z[f=Q[e]]^=Y,i.push(f);if(t>en)for(e=Math.max(n,en),u=t;u>e;++e)z[f=Q[e]]^=Y,o.push(f);else if(en>t)for(e=Math.max(tn,t),u=en;u>e;++e)z[f=Q[e]]^=Y,i.push(f);return tn=n,en=t,N.forEach(function(r){r(Y,o,i)}),X}function l(r){return null==r?B():Array.isArray(r)?j(r):"function"==typeof r?D(r):C(r)}function C(r){return c((_=v(w,r))(P))}function j(r){return c((_=s(w,r))(P))}function B(){return c((_=h)(P))}function D(r){return _=h,G(W=r),tn=0,en=E,X}function G(r){var n,t,e,u=[],f=[];for(n=0;E>n;++n)!(z[t=Q[n]]&Y)^!!(e=r(P[n],n))&&(e?(z[t]&=Z,u.push(t)):(z[t]|=Y,f.push(t)));N.forEach(function(r){r(Y,u,f)})}function H(r){for(var n,t=[],e=en;--e>=tn&&r>0;)z[n=Q[e]]||(t.push(b[n]),--r);return t}function I(r){for(var n,t=[],e=tn;en>e&&r>0;)z[n=Q[e]]||(t.push(b[n]),--r),e++;return t}function J(r){function t(n,t,e,u){function f(){++T===L&&(m=R(m,K<<=1),B=R(B,K),L=O(K))}var l,v,s,h,p,g,y=j,m=A(T,L),x=H,k=J,w=T,M=0,U=0;for(X&&(x=k=d),j=Array(T),T=0,B=w>1?F(B,E):A(E,L),w&&(s=(v=y[0]).key);u>U&&!((h=r(n[U]))>=h);)++U;for(;u>U;){for(v&&h>=s?(p=v,g=s,m[M]=T,(v=y[++M])&&(s=v.key)):(p={key:h,value:k()},g=h),j[T]=p;!(h>g||(B[l=t[U]+e]=T,z[l]&Z||(p.value=x(p.value,b[l])),++U>=u));)h=r(n[U]);f()}for(;w>M;)j[m[M]=T]=y[M++],f();if(T>M)for(M=0;e>M;++M)B[M]=m[B[M]];l=N.indexOf(V),T>1?(V=o,W=a):(!T&&$&&(T=1,j=[{key:null,value:k()}]),1===T?(V=i,W=c):(V=d,W=d),B=null),N[l]=V}function e(){if(T>1){for(var r=T,n=j,t=A(r,r),e=0,u=0;E>e;++e)z[e]&&(t[B[u]=B[e]]=1,++u);for(j=[],T=0,e=0;r>e;++e)t[e]&&(t[e]=T++,j.push(n[e]));if(T>1)for(var e=0;u>e;++e)B[e]=t[B[e]];else B=null;N[N.indexOf(V)]=T>1?(W=a,V=o):1===T?(W=c,V=i):W=V=d}else if(1===T){if($)return;for(var e=0;E>e;++e)if(z[e])return;j=[],T=0,N[N.indexOf(V)]=V=W=d}}function o(r,n,t){if(r!==Y&&!X){var e,u,f,o;for(e=0,f=n.length;f>e;++e)z[u=n[e]]&Z||(o=j[B[u]],o.value=H(o.value,b[u]));for(e=0,f=t.length;f>e;++e)(z[u=t[e]]&Z)===r&&(o=j[B[u]],o.value=I(o.value,b[u]))}}function i(r,n,t){if(r!==Y&&!X){var e,u,f,o=j[0];for(e=0,f=n.length;f>e;++e)z[u=n[e]]&Z||(o.value=H(o.value,b[u]));for(e=0,f=t.length;f>e;++e)(z[u=t[e]]&Z)===r&&(o.value=I(o.value,b[u]))}}function a(){var r,n;for(r=0;T>r;++r)j[r].value=J();for(r=0;E>r;++r)z[r]&Z||(n=j[B[r]],n.value=H(n.value,b[r]))}function c(){var r,n=j[0];for(n.value=J(),r=0;E>r;++r)z[r]&Z||(n.value=H(n.value,b[r]))}function l(){return X&&(W(),X=!1),j}function v(r){var n=D(l(),0,j.length,r);return G.sort(n,0,n.length)}function s(r,n,t){return H=r,I=n,J=t,X=!0,S}function h(){return s(g,y,p)}function k(r){return s(m(r),x(r),p)}function w(r){function n(n){return r(n.value)}return D=f(n),G=u(n),S}function M(){return w(n)}function U(){return T}function C(){var r=N.indexOf(V);return r>=0&&N.splice(r,1),r=rn.indexOf(t),r>=0&&rn.splice(r,1),r=q.indexOf(e),r>=0&&q.splice(r,1),S}var S={top:v,all:l,reduce:s,reduceCount:h,reduceSum:k,order:w,orderNatural:M,size:U,dispose:C,remove:C};nn.push(S);var j,B,D,G,H,I,J,K=8,L=O(K),T=0,V=d,W=d,X=!0,$=r===d;return arguments.length<1&&(r=n),N.push(V),rn.push(t),q.push(e),t(P,Q,0,E),h().orderNatural()}function K(){var r=J(d),n=r.all;return delete r.all,delete r.top,delete r.order,delete r.orderNatural,delete r.size,r.value=function(){return n()[0].value},r}function L(){nn.forEach(function(r){r.dispose()});var r=S.indexOf(e);return r>=0&&S.splice(r,1),r=S.indexOf(o),r>=0&&S.splice(r,1),r=q.indexOf(a),r>=0&&q.splice(r,1),M&=Z,B()}var P,Q,T,V,W,X={filter:l,filterExact:C,filterRange:j,filterFunction:D,filterAll:B,top:H,bottom:I,group:J,groupAll:K,dispose:L,remove:L},Y=~M&-~M,Z=~Y,$=i(function(r){return T[r]}),_=h,rn=[],nn=[],tn=0,en=0;return S.unshift(e),S.push(o),q.push(a),M|=Y,(U>=32?!Y:M&(1<t;++t)z[t]||(a=c(a,b[t]))}function n(r,n,t){var e,u,f;if(!h){for(e=0,f=n.length;f>e;++e)z[u=n[e]]||(a=c(a,b[u]));for(e=0,f=t.length;f>e;++e)z[u=t[e]]===r&&(a=l(a,b[u]))}}function t(){var r;for(a=v(),r=0;E>r;++r)z[r]||(a=c(a,b[r]))}function e(r,n,t){return c=r,l=n,v=t,h=!0,s}function u(){return e(g,y,p)}function f(r){return e(m(r),x(r),p)}function o(){return h&&(t(),h=!1),a}function i(){var t=N.indexOf(n);return t>=0&&N.splice(t),t=S.indexOf(r),t>=0&&S.splice(t),s}var a,c,l,v,s={reduce:e,reduceCount:u,reduceSum:f,value:o,dispose:i,remove:i},h=!0;return N.push(n),S.push(r),r(b,0,E),u()}function c(){return E}var l={add:r,remove:e,dimension:o,groupAll:a,size:c},b=[],E=0,M=0,U=8,z=C(0),N=[],S=[],q=[];return arguments.length?r(arguments[0]):l}function A(r,n){return(257>n?C:65537>n?S:q)(r)}function k(r){for(var n=A(r,r),t=-1;++t=n)return r;var t=new r.constructor(n);return t.set(r),t},R=function(r,n){var t;switch(n){case 16:t=S(r.length);break;case 32:t=q(r.length);break;default:throw Error("invalid array width!")}return t.set(r),t}),r.crossfilter=b}("undefined"!=typeof exports&&exports||this);V8/inst/js/underscore.js0000644000175100001440000003641213062006450014667 0ustar hornikusers// Underscore.js 1.7.0 // http://underscorejs.org // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function(){var n=this,t=n._,r=Array.prototype,e=Object.prototype,u=Function.prototype,i=r.push,a=r.slice,o=r.concat,l=e.toString,c=e.hasOwnProperty,f=Array.isArray,s=Object.keys,p=u.bind,h=function(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=h),exports._=h):n._=h,h.VERSION="1.7.0";var g=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}};h.iteratee=function(n,t,r){return null==n?h.identity:h.isFunction(n)?g(n,t,r):h.isObject(n)?h.matches(n):h.property(n)},h.each=h.forEach=function(n,t,r){if(null==n)return n;t=g(t,r);var e,u=n.length;if(u===+u)for(e=0;u>e;e++)t(n[e],e,n);else{var i=h.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},h.map=h.collect=function(n,t,r){if(null==n)return[];t=h.iteratee(t,r);for(var e,u=n.length!==+n.length&&h.keys(n),i=(u||n).length,a=Array(i),o=0;i>o;o++)e=u?u[o]:o,a[o]=t(n[e],e,n);return a};var v="Reduce of empty array with no initial value";h.reduce=h.foldl=h.inject=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length,o=0;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[o++]:o++]}for(;a>o;o++)u=i?i[o]:o,r=t(r,n[u],u,n);return r},h.reduceRight=h.foldr=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[--a]:--a]}for(;a--;)u=i?i[a]:a,r=t(r,n[u],u,n);return r},h.find=h.detect=function(n,t,r){var e;return t=h.iteratee(t,r),h.some(n,function(n,r,u){return t(n,r,u)?(e=n,!0):void 0}),e},h.filter=h.select=function(n,t,r){var e=[];return null==n?e:(t=h.iteratee(t,r),h.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e)},h.reject=function(n,t,r){return h.filter(n,h.negate(h.iteratee(t)),r)},h.every=h.all=function(n,t,r){if(null==n)return!0;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,!t(n[u],u,n))return!1;return!0},h.some=h.any=function(n,t,r){if(null==n)return!1;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,t(n[u],u,n))return!0;return!1},h.contains=h.include=function(n,t){return null==n?!1:(n.length!==+n.length&&(n=h.values(n)),h.indexOf(n,t)>=0)},h.invoke=function(n,t){var r=a.call(arguments,2),e=h.isFunction(t);return h.map(n,function(n){return(e?t:n[t]).apply(n,r)})},h.pluck=function(n,t){return h.map(n,h.property(t))},h.where=function(n,t){return h.filter(n,h.matches(t))},h.findWhere=function(n,t){return h.find(n,h.matches(t))},h.max=function(n,t,r){var e,u,i=-1/0,a=-1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],e>i&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(u>a||u===-1/0&&i===-1/0)&&(i=n,a=u)});return i},h.min=function(n,t,r){var e,u,i=1/0,a=1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],i>e&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(a>u||1/0===u&&1/0===i)&&(i=n,a=u)});return i},h.shuffle=function(n){for(var t,r=n&&n.length===+n.length?n:h.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=h.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},h.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=h.values(n)),n[h.random(n.length-1)]):h.shuffle(n).slice(0,Math.max(0,t))},h.sortBy=function(n,t,r){return t=h.iteratee(t,r),h.pluck(h.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var m=function(n){return function(t,r,e){var u={};return r=h.iteratee(r,e),h.each(t,function(e,i){var a=r(e,i,t);n(u,e,a)}),u}};h.groupBy=m(function(n,t,r){h.has(n,r)?n[r].push(t):n[r]=[t]}),h.indexBy=m(function(n,t,r){n[r]=t}),h.countBy=m(function(n,t,r){h.has(n,r)?n[r]++:n[r]=1}),h.sortedIndex=function(n,t,r,e){r=h.iteratee(r,e,1);for(var u=r(t),i=0,a=n.length;a>i;){var o=i+a>>>1;r(n[o])t?[]:a.call(n,0,t)},h.initial=function(n,t,r){return a.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},h.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:a.call(n,Math.max(n.length-t,0))},h.rest=h.tail=h.drop=function(n,t,r){return a.call(n,null==t||r?1:t)},h.compact=function(n){return h.filter(n,h.identity)};var y=function(n,t,r,e){if(t&&h.every(n,h.isArray))return o.apply(e,n);for(var u=0,a=n.length;a>u;u++){var l=n[u];h.isArray(l)||h.isArguments(l)?t?i.apply(e,l):y(l,t,r,e):r||e.push(l)}return e};h.flatten=function(n,t){return y(n,t,!1,[])},h.without=function(n){return h.difference(n,a.call(arguments,1))},h.uniq=h.unique=function(n,t,r,e){if(null==n)return[];h.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=h.iteratee(r,e));for(var u=[],i=[],a=0,o=n.length;o>a;a++){var l=n[a];if(t)a&&i===l||u.push(l),i=l;else if(r){var c=r(l,a,n);h.indexOf(i,c)<0&&(i.push(c),u.push(l))}else h.indexOf(u,l)<0&&u.push(l)}return u},h.union=function(){return h.uniq(y(arguments,!0,!0,[]))},h.intersection=function(n){if(null==n)return[];for(var t=[],r=arguments.length,e=0,u=n.length;u>e;e++){var i=n[e];if(!h.contains(t,i)){for(var a=1;r>a&&h.contains(arguments[a],i);a++);a===r&&t.push(i)}}return t},h.difference=function(n){var t=y(a.call(arguments,1),!0,!0,[]);return h.filter(n,function(n){return!h.contains(t,n)})},h.zip=function(n){if(null==n)return[];for(var t=h.max(arguments,"length").length,r=Array(t),e=0;t>e;e++)r[e]=h.pluck(arguments,e);return r},h.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},h.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=h.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}for(;u>e;e++)if(n[e]===t)return e;return-1},h.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=n.length;for("number"==typeof r&&(e=0>r?e+r+1:Math.min(e,r+1));--e>=0;)if(n[e]===t)return e;return-1},h.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var d=function(){};h.bind=function(n,t){var r,e;if(p&&n.bind===p)return p.apply(n,a.call(arguments,1));if(!h.isFunction(n))throw new TypeError("Bind must be called on a function");return r=a.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(a.call(arguments)));d.prototype=n.prototype;var u=new d;d.prototype=null;var i=n.apply(u,r.concat(a.call(arguments)));return h.isObject(i)?i:u}},h.partial=function(n){var t=a.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===h&&(e[u]=arguments[r++]);for(;r=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=h.bind(n[r],n);return n},h.memoize=function(n,t){var r=function(e){var u=r.cache,i=t?t.apply(this,arguments):e;return h.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},h.delay=function(n,t){var r=a.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},h.defer=function(n){return h.delay.apply(h,[n,1].concat(a.call(arguments,1)))},h.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var l=function(){o=r.leading===!1?0:h.now(),a=null,i=n.apply(e,u),a||(e=u=null)};return function(){var c=h.now();o||r.leading!==!1||(o=c);var f=t-(c-o);return e=this,u=arguments,0>=f||f>t?(clearTimeout(a),a=null,o=c,i=n.apply(e,u),a||(e=u=null)):a||r.trailing===!1||(a=setTimeout(l,f)),i}},h.debounce=function(n,t,r){var e,u,i,a,o,l=function(){var c=h.now()-a;t>c&&c>0?e=setTimeout(l,t-c):(e=null,r||(o=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,a=h.now();var c=r&&!e;return e||(e=setTimeout(l,t)),c&&(o=n.apply(i,u),i=u=null),o}},h.wrap=function(n,t){return h.partial(t,n)},h.negate=function(n){return function(){return!n.apply(this,arguments)}},h.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},h.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},h.before=function(n,t){var r;return function(){return--n>0?r=t.apply(this,arguments):t=null,r}},h.once=h.partial(h.before,2),h.keys=function(n){if(!h.isObject(n))return[];if(s)return s(n);var t=[];for(var r in n)h.has(n,r)&&t.push(r);return t},h.values=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},h.pairs=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},h.invert=function(n){for(var t={},r=h.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},h.functions=h.methods=function(n){var t=[];for(var r in n)h.isFunction(n[r])&&t.push(r);return t.sort()},h.extend=function(n){if(!h.isObject(n))return n;for(var t,r,e=1,u=arguments.length;u>e;e++){t=arguments[e];for(r in t)c.call(t,r)&&(n[r]=t[r])}return n},h.pick=function(n,t,r){var e,u={};if(null==n)return u;if(h.isFunction(t)){t=g(t,r);for(e in n){var i=n[e];t(i,e,n)&&(u[e]=i)}}else{var l=o.apply([],a.call(arguments,1));n=new Object(n);for(var c=0,f=l.length;f>c;c++)e=l[c],e in n&&(u[e]=n[e])}return u},h.omit=function(n,t,r){if(h.isFunction(t))t=h.negate(t);else{var e=h.map(o.apply([],a.call(arguments,1)),String);t=function(n,t){return!h.contains(e,t)}}return h.pick(n,t,r)},h.defaults=function(n){if(!h.isObject(n))return n;for(var t=1,r=arguments.length;r>t;t++){var e=arguments[t];for(var u in e)n[u]===void 0&&(n[u]=e[u])}return n},h.clone=function(n){return h.isObject(n)?h.isArray(n)?n.slice():h.extend({},n):n},h.tap=function(n,t){return t(n),n};var b=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof h&&(n=n._wrapped),t instanceof h&&(t=t._wrapped);var u=l.call(n);if(u!==l.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]===n)return e[i]===t;var a=n.constructor,o=t.constructor;if(a!==o&&"constructor"in n&&"constructor"in t&&!(h.isFunction(a)&&a instanceof a&&h.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c,f;if("[object Array]"===u){if(c=n.length,f=c===t.length)for(;c--&&(f=b(n[c],t[c],r,e)););}else{var s,p=h.keys(n);if(c=p.length,f=h.keys(t).length===c)for(;c--&&(s=p[c],f=h.has(t,s)&&b(n[s],t[s],r,e)););}return r.pop(),e.pop(),f};h.isEqual=function(n,t){return b(n,t,[],[])},h.isEmpty=function(n){if(null==n)return!0;if(h.isArray(n)||h.isString(n)||h.isArguments(n))return 0===n.length;for(var t in n)if(h.has(n,t))return!1;return!0},h.isElement=function(n){return!(!n||1!==n.nodeType)},h.isArray=f||function(n){return"[object Array]"===l.call(n)},h.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},h.each(["Arguments","Function","String","Number","Date","RegExp"],function(n){h["is"+n]=function(t){return l.call(t)==="[object "+n+"]"}}),h.isArguments(arguments)||(h.isArguments=function(n){return h.has(n,"callee")}),"function"!=typeof/./&&(h.isFunction=function(n){return"function"==typeof n||!1}),h.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},h.isNaN=function(n){return h.isNumber(n)&&n!==+n},h.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===l.call(n)},h.isNull=function(n){return null===n},h.isUndefined=function(n){return n===void 0},h.has=function(n,t){return null!=n&&c.call(n,t)},h.noConflict=function(){return n._=t,this},h.identity=function(n){return n},h.constant=function(n){return function(){return n}},h.noop=function(){},h.property=function(n){return function(t){return t[n]}},h.matches=function(n){var t=h.pairs(n),r=t.length;return function(n){if(null==n)return!r;n=new Object(n);for(var e=0;r>e;e++){var u=t[e],i=u[0];if(u[1]!==n[i]||!(i in n))return!1}return!0}},h.times=function(n,t,r){var e=Array(Math.max(0,n));t=g(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},h.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},h.now=Date.now||function(){return(new Date).getTime()};var _={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},w=h.invert(_),j=function(n){var t=function(t){return n[t]},r="(?:"+h.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};h.escape=j(_),h.unescape=j(w),h.result=function(n,t){if(null==n)return void 0;var r=n[t];return h.isFunction(r)?n[t]():r};var x=0;h.uniqueId=function(n){var t=++x+"";return n?n+t:t},h.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var A=/(.)^/,k={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},O=/\\|'|\r|\n|\u2028|\u2029/g,F=function(n){return"\\"+k[n]};h.template=function(n,t,r){!t&&r&&(t=r),t=h.defaults({},t,h.templateSettings);var e=RegExp([(t.escape||A).source,(t.interpolate||A).source,(t.evaluate||A).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(O,F),u=o+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":a&&(i+="';\n"+a+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=new Function(t.variable||"obj","_",i)}catch(o){throw o.source=i,o}var l=function(n){return a.call(this,n,h)},c=t.variable||"obj";return l.source="function("+c+"){\n"+i+"}",l},h.chain=function(n){var t=h(n);return t._chain=!0,t};var E=function(n){return this._chain?h(n).chain():n};h.mixin=function(n){h.each(h.functions(n),function(t){var r=h[t]=n[t];h.prototype[t]=function(){var n=[this._wrapped];return i.apply(n,arguments),E.call(this,r.apply(h,n))}})},h.mixin(h),h.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=r[n];h.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],E.call(this,r)}}),h.each(["concat","join","slice"],function(n){var t=r[n];h.prototype[n]=function(){return E.call(this,t.apply(this._wrapped,arguments))}}),h.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return h})}).call(this); //# sourceMappingURL=underscore-min.mapV8/tests/0000755000175100001440000000000013062005777011736 5ustar hornikusersV8/tests/testthat.R0000644000175100001440000000006013062005777013715 0ustar hornikuserslibrary(testthat) library(V8) test_check("V8") V8/tests/testthat/0000755000175100001440000000000013077564201013574 5ustar hornikusersV8/tests/testthat/test_callback.R0000644000175100001440000000231013062005777016510 0ustar hornikuserscontext("V8 Callback to R") ctx <- V8::v8() test_that("console.r.get", { ctx$eval('//get a data frame var iris = console.r.get("iris") var iris_col = console.r.get("iris", {dataframe:"col"}) ') expect_equal(ctx$get("iris.length"), nrow(iris)) expect_equal(ctx$get("Object.keys(iris_col)"), names(iris)) }) test_that("console.r.assign", { ctx$eval('//assign to R session console.r.assign("iris2", iris) console.r.assign("iris3", iris, {simplifyVector:false}) ') expect_is(iris2, "data.frame") expect_equal(length(iris2), 5) expect_equal(length(iris3), 150) rm(iris2, iris3, envir = globalenv()) }) test_that("console.r.call", { expect_equal(ctx$get("console.r.call('Sys.Date')"), as.character(Sys.Date())) expect_equal(length(ctx$get("console.r.call('rnorm', {n: 2,mean:10, sd:5})")), 2) expect_equal(length(ctx$get("console.r.call('rnorm', 3)")), 3) expect_equal(ctx$get("console.r.call('function(x){x^2}', {x:12})"), 144) expect_error(ctx$get("console.r.call('rnorm')"), "missing") }) test_that("console.r.eval", { expect_is(ctx$eval("console.r.eval('invisible(sessionInfo())')"), "character") expect_error(ctx$eval("console.r.eval('doesnotexists')"), "not found") }) V8/src/0000755000175100001440000000000013077470240011360 5ustar hornikusersV8/src/V8.cpp0000644000175100001440000001703713077470240012371 0ustar hornikusers/* R bindings to V8. Copyright 2014, Jeroen Ooms. Notes: - Implementation of Typed Arrays taken from node v0.6.21 V8 source parsing: - http://stackoverflow.com/questions/16613828/how-to-convert-stdstring-to-v8s-localstring Xptr examples: - https://github.com/RcppCore/Rcpp/blob/master/inst/unitTests/cpp/XPtr.cpp - http://romainfrancois.blog.free.fr/index.php?post/2010/01/08/External-pointers-with-Rcpp */ #include #include #include "v8_typed_array.h" #include "v8_json.h" using namespace v8; void ctx_finalizer( Persistent* context ){ if(context) context->Dispose(); delete context; } typedef Rcpp::XPtr, Rcpp::PreserveStorage, ctx_finalizer> ctxptr; /* Helper fun that compiles JavaScript source code */ Handle