Skip to content

Instantly share code, notes, and snippets.

@sguzman
Created March 22, 2018 17:38
Show Gist options
  • Save sguzman/f51c0738ee379d06915d2923875d3039 to your computer and use it in GitHub Desktop.
Save sguzman/f51c0738ee379d06915d2923875d3039 to your computer and use it in GitHub Desktop.
A simple VM written in js
const environment = {};
class Number {
constructor(value) {
this.value = value;
}
reducible() {
return false;
}
reduce(env) {
return this;
}
}
class Bool {
constructor(value) {
this.value = value;
}
reducible() {
return false;
}
reduce(env) {
return this;
}
}
class Not {
constructor(a) {
this.a = a;
}
reducible() {
return true;
}
reduce(env) {
if (this.a.reducible()) {
return new Not(this.a.reduce(env));
} else {
return new Bool(! this.a.value);
}
}
}
class And {
constructor(a, b) {
this.a = a;
this.b = b;
}
reducible() {
return true;
}
reduce(env) {
if (this.a.reducible()) {
return new And(this.a.reduce(env), this.b);
} else if (this.b.reducible()) {
return new And(this.a, this.b.reduce(env));
} else {
return new Bool(this.a.value && this.b.value);
}
}
}
class Or {
constructor(a, b) {
this.a = a;
this.b = b;
}
reducible() {
return true;
}
reduce(env) {
if (this.a.reducible()) {
return new Or(this.a.reduce(env), this.b);
} else if (this.b.reducible()) {
return new Or(this.a, this.b.reduce(env));
} else {
return new Bool(this.a.value || this.b.value);
}
}
}
class Add {
constructor(a, b) {
this.a = a;
this.b = b;
}
reducible() {
return true;
}
reduce(env) {
if (this.a.reducible()) {
return new Add(this.a.reduce(env), this.b);
} else if (this.b.reducible()) {
return new Add(this.a, this.b.reduce(env));
} else {
return new Number(this.a.value + this.b.value);
}
}
}
class Mult {
constructor(a, b) {
this.a = a;
this.b = b;
}
reducible() {
return true;
}
reduce(env) {
if (this.a.reducible()) {
return new Mult(this.a.reduce(env), this.b);
} else if (this.b.reducible()) {
return new Mult(this.a, this.b.reduce(env));
} else {
return new Number(this.a.value * this.b.value);
}
}
}
class Machine {
constructor(value, env) {
this.value = value;
this.env = env;
}
step() {
this.value = this.value.reduce(this.env);
}
run() {
console.log('-----------------');
console.log(this.value);
console.log('-----------------');
if (this.value.reducible()) {
this.step();
return this.run();
}
}
}
class Variable {
constructor(symbol) {
this.symbol = symbol;
}
reducible() {
return true;
}
reduce(env) {
return env[this.symbol];
}
}
class If {
constructor(cond, trueValue, falseValue) {
this.cond = cond;
this.trueValue = trueValue;
this.falseValue = falseValue;
}
reducible() {
return true;
}
reduce(env) {
if (this.cond.reducible()) {
return new If(this.cond.reduce(env), this.trueValue, this.falseValue);
} else if (this.trueValue.reducible()) {
return new If(this.cond, this.trueValue.reduce(env), this.falseValue);
} else if (this.falseValue.reducible()) {
return new If(this.cond, this.trueValue, this.falseValue.reduce(env));
} else {
return new Number((this.cond.value) ? this.trueValue : this.falseValue);
}
}
}
new Machine(
new If(new And(
new Variable('x'),
new Not(new Variable('y'))
),
new Add(new Number(1), new Number(2)),
new Mult(new Number(3), new Number(2))),
{'x': new Bool(true), 'y': new Bool(false)}
).run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment