Emjs is a lightweight JavaScript interpreter for embedded scenarios (C++17).
This document is aligned with the current implementation under src/, and examples are written according to actual behavior.
- Execution model: direct interpretation (no bytecode VM)
- Memory model: engine state + JS heap in a fixed buffer
- Project Layout
- Build
- CLI Tool (emjs)
- Quick Start
- C++ API
- Syntax and Semantics
- Built-in Methods (Core)
- Extension Modules
- Unsupported Features
- Errors and Debugging
- Build and Size Options
- Source Mapping
src/
core.h / core.cpp # lexer, parser, interpreter, object model, GC
engine.h / engine.cpp # public C++ API
internal.h / internal.cpp # internal runtime + array/string core methods
extension/
console.* # console.log/time/timeLog/timeEnd
date.* # Date.now / Date.format
global.* # parseInt / parseFloat
json.* # JSON.parse / JSON.stringify
math.* # Math constants + many math functions
string.* # String.fromCharCode
tests/
test_js.cpp # script runner with default extension binding
mkdir -p build
cd build
cmake ..
cmake --build .Current CMake targets:
emjs(CLI executable)libemjs-core.alibemjs-exts.atest_js
Note:
tests/unit_test.cppexists in the repository, butunit_testis not enabled as a default CMake target.
After build, the executable is available at build/emjs.
emjs <script.js>
emjs -h
emjs --help
emjsBehavior:
- script path argument: run that JS file
-h/--help: print help- no argument: start interactive mode (stdin line-by-line)
- press
Ctrl+Cto exit interactive mode
# run file
./build/emjs ./tests/script/types.js
# help
./build/emjs --help
# stdin / pipe mode
printf '%s\n' '1+2' 'let x=5; x+1;' | ./build/emjscmake -S . -B build
cmake --build build
cmake --install build --prefix /usr/localTypical installed files:
/usr/local/bin/emjs/usr/local/lib/libemjs-core.a/usr/local/lib/libemjs-exts.a/usr/local/include/emjs/*.h/usr/local/include/emjs/extension/*.h
If emjs is not found:
export PATH="/usr/local/bin:$PATH"Add it to ~/.zshrc or ~/.bashrc to persist.
#include "src/engine.h"
#include <cstdio>
using namespace Emjs;
int main() {
char mem[4096] = {0};
JsEngine* js = JsEngine::create(mem, sizeof(mem));
if (!js) return 1;
JsValue r = js->eval("let x=3; let y=4; x*y + 1;");
std::printf("%s\n", js->str(r)); // 13
JsEngine::destroy(js);
return 0;
}Header: src/engine.h
// external buffer
char mem[8192];
JsEngine* js = JsEngine::create(mem, sizeof(mem));
JsEngine::destroy(js);
// internally allocated
JsEngine* js2 = JsEngine::create(8192);
JsEngine::destroy(js2); // frees owned memoryJsValue v = js->eval("1+2+3"); // length defaults to ~0U
const char* s = js->str(v); // "6" or error stringjs->eval("function add(a,b){return a+b;};");
// pointer + count form
JsValue argv[2] = {JsEngine::makeNumber(10), JsEngine::makeNumber(32)};
JsValue r1 = js->callGlobal("add", argv, 2); // 42
// initializer_list form
JsValue r2 = js->callGlobal("add", {
JsEngine::makeNumber(1),
JsEngine::makeNumber(2),
}); // 3Signatures:
JsValue callGlobal(const char* functionName, const JsValue* args, int argCount);JsValue callGlobal(const char* functionName, std::initializer_list<JsValue> args = {});
Error semantics:
- bad arguments:
bad call - function not found:
'name' not found - symbol exists but not callable:
'name' not callable
JsValue add(JsEngine* js, JsValue* args, int nargs) {
if (!JsEngine::chkArgs(args, nargs, "dd")) return js->makeError("type mismatch");
return JsEngine::makeNumber(
JsEngine::getNumber(args[0]) + JsEngine::getNumber(args[1]));
}
js->set(js->glob(), "add", JsEngine::makeFunction(add));chkArgs format:
dnumberbbooleansstringjany JS value
js->setGcThreshold(1024);
js->setMaxCss(5000);
js->gc();
size_t total=0, lwm=0, css=0;
js->stats(&total, &lwm, &css);undefined; null; true; false;
123; 3.14; 0x10;
"abc"; 'xyz';
({a:1, b:2});
[1,2,3];- supported:
let,const - compound assignment:
+= -= *= /= %= <<= >>= >>>= &= ^= |= - postfix increments:
i++,i-- - reassigning
constraisesassignment to constant
- arithmetic:
+ - * / % ** - bitwise:
~ & | ^ << >> >>> - compare:
< <= > >= - equality:
== != === !== - logical:
! && || - ternary:
?: typeof
if / elsefor,while,do...whileswitchbreak,continuetry / catch / finallythrowreturn(inside function only)
- function declarations and function expressions
- IIFE
- arrow functions:
x => x * 2(a,b) => a + b(x) => { return x * 2; }
Semicolons are supported as expected.
There is also newline-based statement finish logic (js_stmt_finish), but explicit semicolons are still recommended.
From core runtime (internal.cpp), without extension modules.
lengthcharCodeAt(index)charAt(index)indexOf(substr[, from])substring(start[, end])
lengthpush,pop,shiftslice,reverse,sort,spliceforEach,map,every,some,find,findIndex,reduceindexOf,join
Callback signatures:
forEach/map/every/some/find/findIndex:(elem, index, array)reduce:(acc, elem, index, array)
Controlled by CMake options:
BUILD_CONSOLEBUILD_GLOBALBUILD_STRINGBUILD_DATEBUILD_JSONBUILD_MATH
Runtime binding example:
#include "src/extension/console.h"
#include "src/extension/global.h"
#include "src/extension/string.h"
#include "src/extension/date.h"
#include "src/extension/math.h"
#include "src/extension/json.h"
EConsole::bind(js);
EGlobal::bind(js);
EString::bind(js);
EDate::bind(js);
EMath::bind(js);
EJson::bind(js);console.log(...args)console.time(label?)console.timeLog(label, ...args)console.timeEnd(label?)
parseInt(str[, radix])parseFloat(str)
String.fromCharCode(...codes)
Date.now()Date.format([timestampMs][, format])
Constants:
E, LN10, LN2, LOG10E, LOG2E, PI, SQRT1_2, SQRT2
Functions:
abs acos acosh asin asinh atan atan2 atanh cbrt ceil clz32 cos cosh exp expm1 f16round floor fround hypot imul log log10 log1p log2 max min pow random round sign sin sinh sqrt sumPrecise tan tanh trunc
JSON.parse(text)JSON.stringify(value)
The following are currently unsupported and can produce not implemented or parse/runtime errors:
varclassnewthisdeletewithyieldvoidininstanceof
Also unsupported: ES module system, Promise-based async APIs, full prototype-chain behavior, etc.
Common errors from runtime:
parse error; expectedtype mismatchnot a functionnot arrayreduce emptyassignment to constantoomC stack'xxx' not found'xxx' not implemented
Most errors include at line N col M.
JsEngine::dump() is empty by default; enable with compile definition:
EMJS_ENABLE_DUMP=1
CMake option:
EMJS_OPTIMIZE_SIZE(defaultON)
Source macros:
JS_EXPR_MAX(default20)JS_GC_THRESHOLD(default0.25)EMJS_ENABLE_DUMP(default0)
- Interpreter core:
src/core.cpp - Public API:
src/engine.h,src/engine.cpp - Array/String runtime internals:
src/internal.cpp - Extension bind example:
tests/test_js.cpp - Script examples:
tests/script/*.js
When docs differ from behavior, source code and test output are the source of truth.