Skip to content

Instantly share code, notes, and snippets.

@stla
Created June 21, 2015 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stla/10718cda54bc5c0aa6fb to your computer and use it in GitHub Desktop.
Save stla/10718cda54bc5c0aa6fb to your computer and use it in GitHub Desktop.
Javascript V8 engine in knitr - output at https://rpubs.com/stla/79457
```{r}
# group source lines into complete expressions (using a brutal-force method)
group_src_V8 = function(code, context) {
if ((n <- length(code)) < 1) return(list(code))
i = i1 = i2 = 1
x = list()
while (i2 <= n) {
piece = code[i1:i2]
if (eval(parse(text=sprintf("%s$validate(piece)", context))) && eval(parse(text=sprintf('%s$eval(piece)!="undefined"', context)))) {
x[[i]] = piece; i = i + 1
i1 = i2 + 1 # start from the next line
}
i2 = i2 + 1
}
if (i1 <= n) parse(text = piece) # must be an error there
x
}
#
library(knitr)
knit_engines$set(V8 = function(options) {
require(V8)
context <- ifelse(!is.null(options$V8.context), options$V8.context, "ct")
if(!exists(context)){
assign(context, new_context(), envir = .GlobalEnv)
if(!is.null(options$V8.libraries)){
for(library in options$V8.libraries){
eval(parse(text=sprintf('%s$source("%s")', context, library)))
}
}
}
code <- as.character(c(options$code))
if(!eval(parse(text=sprintf("%s$validate(code)", context)))) stop("unvalid javascript code")
if(!is.element(options$results, c("hide", "last"))){
code <- group_src_V8(code, context)
output <- sapply(code, function(code) eval(parse(text=sprintf("%s$eval(code)", context))) )
code <- sapply(code, function(code) knitr:::wrap.source(list(src= paste(code, collapse = "\n")), options))
}else{
if(options$results=="last") output <- eval(parse(text=sprintf("%s$eval(code)", context)))
code <- knitr:::wrap.source(list(src= paste(code, collapse = "\n")), options)
if(options$results=="hide") return(code)
return(c(code, knitr:::wrap.character(output, options)))
}
return(c(sapply(seq_along(code), function(i) c(code[i], knitr:::wrap.character(output[i], options)))))
})
```
Define `x` in Javascript context using the chunk option `engine='V8'`:
```{r, engine='V8'}
var x=[]
for(i = 0; i<3; i++){
x[i]=i;
}
x.push([3,4])
JSON.stringify(x)
```
In the previous chunk, the `results` option is set to its default value. You can use `results='hide'` to hide the output, or `results='last'` to show only the output generated by the last line:
```{r, engine='V8', results='last'}
var x=[]
x.push([1,2])
x.push([3,4])
JSON.stringify(x)
```
By default the Javascript context is a R variable named `ct`. You can set another name by doing `opts_chunk$set(V8.context="mycontext")`. Then using the context variable you can import a variable from the Javascript context to R or vice-versa (see `?V8::V8` for details) :
- Get `x` in R :
```{r}
( x.in.R <- ct$get("x") )
```
- Double `x` in R and assign in Javascript context :
```{r}
ct$assign("double_x", 2*x.in.R)
```
The Javascript `JSON.stringify` function is nice for displaying an object in a V8 chunk:
```{r, engine='V8'}
JSON.stringify(double_x);
```
You can load a Javascript library like this :
```{r}
ct$source(system.file("js/underscore.js", package="V8"))
```
As you can see, it works:
```{r, engine='V8'}
JSON.stringify(_.flatten(x))
```
Another way is to give the libraries as a character vector in the `V8.libraries` chunk option:
```{r, eval=FALSE}
opts_chunk$set(V8.libraries=c(system.file("js/underscore.js", package="V8"), "http://coffeescript.org/extras/coffee-script.js"))
```
The libraries given by this way are loaded only once, at the moment the Javascript context is created.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment