Public
Edited
May 30, 2023
Insert cell
Insert cell
g = ohm.grammar(grammarSource);
Insert cell
Insert cell
{
let result;
const m = g.match(`
(def age: 2)
(def name: "Alex")
(cmr: 2 21)
(print: "Name" + name)
`);

if (m.succeeded()) {
result = semantics(m).ast(); // Evaluate the expression.
} else {
result = m.message; // Extract the error message.
}


return result
}
Insert cell
Insert cell
semantics = {
const context = new Map()
return g.createSemantics().addOperation('ast', {
Program(statements) {
return new core.Program(statements.ast())
},
Stmt(argument) {
return new core.Statement(argument.ast())
},
Block(body) {
return new core.Block(body.ast())
},
FnCall(_left, fnName, _dots, params, _right) {
return new core.FnCall(fnName.sourceString, params.ast())
},
VarDec(_left, _def, id, _dots, exp, _right) {
const variable = new core.Variable(id.sourceString, 'any')
const initializer = exp.ast()

context.set(variable.name, variable)
return new core.VarDec(variable, initializer)
},
Exp_binary(left, op, right) {
return new core.BinaryExpression(op.sourceString, left.ast(), right.ast())
},
Condition_binary(left, op, right) {
return new core.BinaryExpression(op.sourceString, left.ast(), right.ast())
},
Term_binary(left, op, right) {
return new core.BinaryExpression(op.sourceString, left.ast(), right.ast())
},
Factor_binary(left, op, right) {
return new core.BinaryExpression(op.sourceString, left.ast(), right.ast())
},
Exp(val) {
return new core.Expression(val.ast())
},
Var(val) {
const entity = context.get(val.sourceString)
if (!entity) throw new Error(`Identifier "${val.sourceString}" not declared`)
return entity
},
true(_) {
return true
},
false(_) {
return false
},
intlit(digits) {
return parseInt(digits.ast())
},
floatlit(digits1, dot, digits2) {
return parseFloat(digits1.ast() + '.' + digits2.ast())
},
strlit(a1, chars, a2) {
return chars.ast().join('')
},
_terminal() {
return this.sourceString
},
_iter(...children) {
return children.map(c => c.ast())
}
})}
Insert cell
Insert cell
core = {
class Env {
constructor() {
this.env = {};
}
bind(name, value) {
this.env[name] = value;
}
get(name) {
if (!this.env[name]) {
throw new Error(`${name} not in env`);
}
return this.env[name];
}
// this could be replaced with parentEnv and "looking up" if something is not found
duplicate() {
const dupEnv = new Env();
Object.entries(this.env).forEach(([key, value]) => {
dupEnv.bind(key, value);
});
return dupEnv;
}
}
class Program {
constructor(statements) {
Object.assign(this, { statements })
}
}

class Statement {
constructor(argument) {
Object.assign(this, { argument })
}
}
class Block {
constructor(body) {
Object.assign(this, { body })
}
}

class VarDec {
constructor(variable, initializer) {
Object.assign(this, { variable, initializer })
}
}

class Variable {
constructor(name, type) {
Object.assign(this, { name, type })
}
}

class Expression {
constructor(value) {
Object.assign(this, { value })
}
}

class BinaryExpression {
constructor(op, left, right) {
Object.assign(this, { op, left, right })
}
}

class FnCall {
constructor(fnName, args) {
Object.assign(this, { fnName, args })
}
}

return { Env, Program, Statement, Block, VarDec, Variable, BinaryExpression, Expression, FnCall }
}
Insert cell
Insert cell
grammarSource = String.raw`
Zapant {
Program = Stmt+

Stmt (statement)
= FnCall
| VarDec

Block = Stmt+
FnCall = "(" id ":" Exp* ")"
VarDec = "(" def id ":" Exp ")"

Exp
= Condition relop Condition --binary
| Condition

Condition
= Exp ("+" | "-") Term --binary
| Term

Term
= Term ("*" | "/" | "%") Factor --binary
| Factor

Factor
= Primary "**" Factor --binary
| Primary

Primary
= FnCall
| Var
| strlit
| floatlit
| intlit
| boolean


Var = id

def = "def" ~alnum
if = "if" ~alnum
loop = "loop" ~alnum
in = "in" ~alnum
true = "true" ~alnum
false = "false" ~alnum
keywords
= def
| if
| loop
| in
| true
| false

strlit = "\"" char* "\""
char = ~"\"" ~"\n" any
boolean = true | false
intlit = digit+
floatlit = digit+ "." digit+
id = ~keywords letter idchar*
idchar = letter | digit | "_"
relop = "<=" | "<" | "==" | "!=" | ">=" | ">"
}
`;
Insert cell
Insert cell
ohm = import("https://cdn.skypack.dev/ohm-js@17")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more