LICENSE=BSD-3-ClauseCGO_ENABLED=0go-embedded-r is in development: v0.5.0 (2026-11-05) completes milestones M0 (the oracle harness, against GNU R 4.6.2) and M1 (the parser and deparse, package syntax), identical to R's tree, tokens and deparse output on 842 of 842 files of R's base packages, and slices 1 to 3 of M2: the evaluator (package eval) has 102 of R's 210 primitives and 94 base closures, with replacement, subsetting, attributes, S3 dispatch, conditions, print, environments as values, the apply family, string functions and regular expressions, and 1 035 of 1 035 goldens match R 4.6.2. Regular expressions are an approximation on Go's regexp, not TRE (lazy quantifiers, capture priority in repeated groups and \</\> differ from R; back-references are refused); a faithful TRE port is in progress for v0.6.0. Since v0.4.0 a session is bounded by default (a breaking change): 30 000 000 steps, 16 GiB of cumulative allocation and 10 s per evaluation, with eval.Unbounded to opt out. Base, stats, regex, graphics, the notebook bridge, the playground and CRAN ports (M3 to M8) are planned. R cells are live in go-notebook v0.8.0 and playground v0.9.0: parsed and checked, not run yet. It will be a pure-Go, embeddable R interpreter for the r cells of go-notebook and its WebAssembly playground, written clean-room under the BSD-3-Clause licence.
release v0.5.0 (2026-11-05)
done M0 oracle harness (R 4.6.2)
done M1 parser + deparse: 842/842
done M2 slices 1-3: 102/210 prims
+ 94 closures, 1035/1035 goldens
caveat regex: not TRE (Go regexp)
planned M3 - M8 base ... CRAN
goal r cells in go-notebook
oracle GNU R 4.6.2, a black box
licence BSD-3-Clause, clean room
plan github.com/go-scikit/roadmapWhat exists is a parser, an oracle harness and the first three slices of the evaluator. The rest is the plan of the roadmap's bibliography, not a result.
github.com/go-embedded-r/r is the start of an R implementation written in Go (CGO_ENABLED=0), meant to be embedded in Go programs and to run in the browser through WebAssembly.
It will back the r cells of go-notebook, the way julia backs its Julia cells and rbgo its Ruby cells.
Every stage is checked against the reference implementation, the pinned GNU R 4.6.2 (CRAN tarball, SVN revision 90784), never against expectations written by hand. R runs as a black box and what it prints is recorded.
R cells are live in go-notebook v0.8.0 and playground v0.9.0: they are parsed and checked, not run yet. Running them needs the evaluator, which is planned.
Package syntax: lexer, parser, an AST with a source map, the tokens of getParseData(), R's own parse errors byte for byte, Deparse, and TopLevelNames, which names what a cell assigns and reads.
R's engine, TRE, is not ported. grepl, sub, gsub, regexpr, gregexpr and regmatches run on Go's regexp, an approximation: lazy quantifiers, capture priority in repeated groups and \</\> differ from R, and back-references and perl = TRUE are refused. A faithful TRE port is in progress for v0.6.0, not released.
Package eval (v0.5.0): 102 of R's 210 primitives and 94 base closures, with replacement, subsetting, attributes, S3 dispatch, conditions, print, environments as values, the apply family, string functions and regular expressions, judged by the oracle (1 035 of 1 035 goldens). Its API, eval.NewSession and Eval, is bounded by default since v0.4.0 (30 000 000 steps, 16 GiB of cumulative allocation, 10 s; eval.Unbounded opts out), a breaking change.
rds reads and writes R's serialization format (XDR, versions 2 and 3, gzip or bzip2): a decoded value encodes back to the same bytes. The decoder is built for untrusted input and fuzzed.
R's sources are GPL-2-or-later. R is an oracle, never a source: no R source file, test file, help page or transcript is copied here, and base R's R code is rewritten from the documented behaviour, not copied.
M0 and M1 are done, and M2 has slices 1 to 3 done. M3 to M8 are planned and not started.
internal/oracle starts one Rscript --vanilla process (the pinned release; any other version is refused) and talks to it in R's own serialization; rds reads and writes that format; cmd/roracle regenerates the golden files. The tests replay the goldens without R, and with R they check that R reads Go's bytes back unchanged.
Package syntax: the parser in v0.1.0, deparse in v0.2.0. syntax.ParseAll(src), syntax.TopLevelNames(cell) and syntax.Deparse(expr, nil). Tree, tokens, error text and deparse output are compared with R 4.6.2 (see the parity table below). Bounded in bytes, depth and nodes. Known gaps: the effect of #line directives on later error lines, parse(file=) encoding options, and the platform divergences of numeric constants in deparse (exp10 on macOS, 80-bit long double on x86-64).
Package eval, slice 3 released in v0.5.0 (limits bounded by default since v0.4.0). Slice 1: values, environments, promises, closures with R's argument matching, control flow, arithmetic. Slice 2: replacement with copy-on-modify, subsetting, attributes, S3 dispatch, conditions, print, and the Eval API with limits. Slice 3: environments as values, the apply family, string functions and regular expressions. 102 of R's 210 primitives and 94 base closures. Judged by the oracle: 1 035 of 1 035 goldens, 189 998 of 190 000 arithmetic fuzz expressions, 35 963 of 36 000 subsetting, 17 993 of 18 000 regex. Known divergences: regex is an approximation on Go's regexp, not TRE (a TRE port is in progress for v0.6.0), format of a factor is missing, sort and ls order by code point, not locale, function printing, some [[<- messages. The design is docs/m2-design.md of go-embedded-r/r.
Planned, not started: base, stats, regex, graphics, the notebook bridge, the WebAssembly playground and CRAN ports. The plan is bib/r.md of go-scikit/roadmap.
The same text is parsed by R and by Go, and the terminal tokens, the tree and the error text are compared (go run ./cmd/rparity). R's own sources are read where they are unpacked and never committed.
Every .R file of src/library (7.8 MB): 844 inputs, 842 parse and 2 are rejected. Tree 842 / 842, tokens 842 / 842, deparse 842 / 842, error text byte for byte 2 / 2. On R's tests/ (90 files that parse): tree, tokens and deparse 90 / 90. Deparse differs from R in the last digit for 5 of 100 000 random literals beyond exponent 200 (exp10 on macOS), and, on x86-64 Linux, in 6 of the 90 files of tests/ (80-bit long double).
95 files, 1 is not UTF-8 and is skipped: 94 inputs, 90 parse and 4 are rejected. Tree 90 / 90, tokens 90 / 90, error text 4 / 4.
42 snippets: tree and tokens 42 / 42. 52 error cases: 51 / 51 identical error texts. 93 edge cases (Unicode, raw strings, |>, \(x), ->>, hex, L and i numbers): 90 / 90, errors 3 / 3. 117 odd inputs (CRLF, tabs, bidi controls, invalid UTF-8): 81 / 81, errors 36 / 36.
Random edits of lines of R's sources (seeds 1, 2 and 11), about two thirds rejected: tree, tokens and error text all identical.
Random, up to 20 digits, exponents -330 to 330: 100 000 identical doubles. They match R on macOS arm64 (fused multiply-add, 64-bit long double); R on x86-64 Linux accumulates in 80-bit precision and can differ in the last place. Those literals are compared within 16 ulp and kept out of the goldens.
One core each, interleaved rounds, median of 11, 1-minute load 7.8 on an Apple M-series laptop: the 842 files of src/library (7.8 MB) take 0.214 s in Go (syntax.ParseAll, which also builds the source map and the token list) and 0.269 s in R's parse(text =, keep.source = FALSE). Go/R = 0.80.
The sources of R are GPL-2-or-later and this project is BSD-3-Clause. No R source file, test file, help page, .Rout.save transcript or text of R's manuals is copied, and none is downloaded at run time. The golden files are the answers of R 4.6.2 to inputs written here. Contributors work from specifications: the R Language Definition, the R Internals manual, the help pages and the oracle's behaviour.
The organization holds the interpreter's repository, r, and its landing and documentation.
The interpreter, github.com/go-embedded-r/r, released as v0.5.0 (2026-11-05): M0, the oracle harness against GNU R 4.6.2 (internal/oracle, cmd/roracle, the rds serialization reader and writer, golden files), and M1, the parser and deparse (package syntax). M2, the evaluator (package eval): slices 1 to 3 are done (its regular expressions are an approximation on Go's regexp, not TRE). Everything after is planned.