https://github.com/ubugeeei/glasper
Toy JavaScript Interpreter implementation in Rust
https://github.com/ubugeeei/glasper
interpreter javascript javascript-engine javascript-interpreter language-processing rust scratch-implementation
Last synced: 2 months ago
JSON representation
Toy JavaScript Interpreter implementation in Rust
- Host: GitHub
- URL: https://github.com/ubugeeei/glasper
- Owner: ubugeeei
- License: mit
- Created: 2022-08-20T15:57:42.000Z (almost 3 years ago)
- Default Branch: master
- Last Pushed: 2023-05-07T13:42:32.000Z (about 2 years ago)
- Last Synced: 2025-04-02T12:59:58.955Z (3 months ago)
- Topics: interpreter, javascript, javascript-engine, javascript-interpreter, language-processing, rust, scratch-implementation
- Language: Rust
- Homepage:
- Size: 363 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
![]()
[](https://github.com/Ubugeeei/Glasper/actions/workflows/rust.yml)
A toy JavaScript engine and runtime implementation in Rust.
# Installation
```sh
$ make install
# set path your shell
$ echo 'export PATH=/usr/local/bin/gls:$PATH' >> ~/.hogerc
```# Usage
## Run source code
```sh
$ gls example/main.js
```## Run interactive
```sh
$ gls
Welcome to Glasper v0.1.0
exit using ctrl+c or ctrl+d or exit()
> # input your source
```you can get more info by help command.
```sh
$ gls --help
```## Use as library (JavaScript engine)
### Basic Execution
```rs
use glasper::engine::*;let handle_scope = HandleScope::new();
let mut context = Context::new(handle_scope);
let mut isolate = Isolate::new(context);
let mut script = Script::compile(String::from("let a = 1;"), &mut isolate.context);
script.run()
```### Binding Objects
```rs
use glasper::engine::*;let handle_scope = HandleScope::new();
let mut context = Context::new(handle_scope);let global = context.global();
let console_builder = ConsoleBuilder::new();
let console = console_builder.build();
global.set("console", console);let mut isolate = Isolate::new(context);
let mut script = Script::compile(String::from("console.log(1, 2, 3);"), &mut isolate.context);
script.run()
```builtin console sample
```rs
use glasper::engine::*;pub struct ConsoleBuilder;
impl Default for ConsoleBuilder {
fn default() -> Self {
Self::new()
}
}
impl ConsoleBuilder {
pub fn new() -> Self {
Self
}
pub fn build(self) -> RuntimeObject {
let mut properties = HashMap::new();
properties.insert(
String::from("log"),
RuntimeObject::BuiltinFunction(JSBuiltinFunction::new("log", log)),
);
properties.insert(
String::from("debug"),
RuntimeObject::BuiltinFunction(JSBuiltinFunction::new("log", log)),
);
properties.insert(
String::from("warn"),
RuntimeObject::BuiltinFunction(JSBuiltinFunction::new("log", log)),
);RuntimeObject::Object(JSObject { properties })
}
}fn log(args: Vec) -> RuntimeObject {
for arg in args {
print!("{}", arg);
print!("\x20");
}
println!();RuntimeObject::Undefined(JSUndefined)
}
```# Syntax
## Console log
```js
console.log("Hello World!");
```## Expression
### Primitive literals
```js
// bool
console.log(true);
console.log(false);// number
console.log(1);
console.log(0x1111);
console.log(0o1111);
console.log(0b1111);
console.log(1.1);
console.log(1.1e3);
console.log(1.1e-3);// string
console.log("hello string");// undefined, null
console.log(undefined);
console.log(null);
```### Operators
```js
console.log(2 + 2);
console.log(2 - 2);
console.log(2 * 2);
console.log(2 / 2);
console.log(2 % 2);
console.log(2 ** 2);
console.log(2 + 2 * 2);// comp
console.log(2 == 2);
console.log(2 != 2);
console.log(2 === 2);
console.log(2 !== 2);
console.log(2 > 2);
console.log(2 < 2);
console.log(2 <= 2);
console.log(2 >= 2);// bit
console.log(2 << 2);
console.log(2 >> 2);
console.log(2 & 2);
console.log(2 | 2);
console.log(2 ^ 2);// bool
console.log(2 && 2);
console.log(2 || 2);// nullish
console.log(1 ?? 2); // 1
console.log(null ?? 2); // 2// typeof
console.log(typeof 1); // "number"
```## Array and prototype functions
```js
const arr = [1, 2, 3, 4, 5];console.log(arr[0]); // 1
console.log(arr[100]); // undefined
console.log(arr.length); // 5const last = arr.at(-1);
console.log(last); // 5const concat = arr.concat([6, 7, 8]);
console.log(concat[6]); // 6const every = arr.every(function (v) {
return v < 10;
});
console.log(every); // trueconst joined = arr.join("/");
console.log(joined); // "1/2/3/4/5/6/7/8"const mapped = arr.map(function (it) {
return it * 2;
});
console.log(mapped[0]); // 2const found = arr.find(function (it) {
return it % 2 === 0;
});
console.log(found); // 2
```## Object
```js
let o = {
message: "hello object",
};
console.log(o.message);o.message = "hello object again";
console.log(o.message);let o_cp = o;
o_cp.message = "hello object again by copy";
console.log(o.message);
```## Variable snd scope
### declare "var"
```js
a = 1;
console.log("variables a:", a); // 1
a = 5;
console.log("variables assigned a:", a); // 5
```### declare "let"
```js
let a = 2;
console.log("variables a:", a); // 2
a = 6;
console.log("variables assigned a:", a); // 6
```### declare "const"
```js
const c = 3;
console.log("variables c:", c); // 3
c = 7; // error
const c = 7; // error
```### scope
```js
let v = 1;
let global = 100;
{
let v = 2;
console.log("child scope v:", v); // 2
console.log("global in child:", global); // 100
}
console.log("parent scoped v:", v); // 1
```## Function
```js
const add = function (a, b) {
return a + b;
};console.log("add(1, 2):", add(1, 2));
``````js
// recursive
const factorial = function (num) {
if (num == 0) return 1;
return num * factorial(num - 1);
};
console.log("factorial(5):", factorial(5)); // 120
```## "this" in Function
```js
const inner_f = function () {
return this.value;
};
console.log(inner_f()); // undefinedconst o = {
value: 1,
f: inner_f,
};
console.log(o.f()); // { value: 1, f: [Function] }const oo = {
value: 2,
f: inner_f,
};
console.log(oo.f()); // { value: 2, f: [Function] }
```## Prototype
```js
Array.prototype = {
nth: function (n) {
return this[n];
},
};const arr = [1, 2, 3, 4, 5];
console.log(arr.nth(2)); // 3
```## Statements
### If
```js
let num = 2;
if (num % 2 == 0) {
console.log("even!");
} else {
console.log("odd!");
}
```### switch
```js
const match = function (num) {
switch (num) {
case 1: {
console.log("one");
break;
}
case 2: {
console.log("two");
break;
}
default: {
console.log("other");
break;
}
}
};
match(1);
match(2);
match(99);
``````js
const match_no_break = function (num) {
switch (num) {
case 1:
console.log("one");
case 2:
console.log("two");
default:
console.log("other");
}
};
match_no_break(1);
match_no_break(2);
match_no_break(99);
```### For
```js
const arr = [1, 2, 3, 4];for (let i = 0; i < arr.length; i++) {
if (i % 2) {
continue; // skip odd index
}console.log(arr[i] * 2);
}
```## FizzBuzz sample
```js
const fizzBuzz = function (num) {
// comment out
if (!num) return 0;if (num % 15 == 0) {
console.log("FizzBuzz");
} else if (num % 5 == 0) {
console.log("Buzz");
} else if (num % 3 == 0) {
console.log("Fizz");
} else {
console.log(num);
}fizzBuzz(num - 1);
};fizzBuzz(20);
```