Skip to content

Instantly share code, notes, and snippets.

@lingsamuel
Created August 8, 2017 06:40
Show Gist options
  • Save lingsamuel/2a44674fb7b99d5161426f36d455f98f to your computer and use it in GitHub Desktop.
Save lingsamuel/2a44674fb7b99d5161426f36d455f98f to your computer and use it in GitHub Desktop.
Expression Transpiler
function tokenize(program) {
// this function can help you tokenize program
// you can use this function in attempt
const regex = /\s*(->|[-+*/\(\)\[\]\{\};,]|[A-Za-z]+|[0-9]+)\s*/g;
return program.replace(regex, ":$1").substring(1).split(':');
};
let parser;
let isNumeric = n => !isNaN(parseFloat(n)) && isFinite(n);
let isChar = char => char.length === 1 && char.match(/[a-z]/i);
function validVarLetter(char) {
return isNumeric(char) || (isChar(char) || char === "_")
}
function allMatch(str, fn) {
let match = true;
for (let i = 0; i < str.length; i++) {
match = fn(str.charAt(i)) && match;
if (match == false) return false
}
return true
}
function validVarName(str) {
return allMatch(str, validVarLetter) && !isNumeric(str.charAt(0))
}
function validNumber(str) {
return allMatch(token, isNumeric)
}
class Node {
constructor(name) {
this.name = name;
}
stream() { return this }
trans() { return "" }
}
class ExpNode extends Node {
constructor(expression) {
super("Exp")
this.actual = expression
}
stream() {
}
trans() {
return this.actual.trans()
}
}
class NumNode extends Node {
constructor(value) {
super("Num")
this.value = value
}
stream() {
return this
}
trans() { return this.name }
}
class VarNode extends Node {
constructor(name) {
super(name)
}
stream() {
return this
}
trans() { return this.name }
}
class FnNode extends Node {
constructor(expression, paras, lambda) {
// actual name or nothing
super("Fn")
this.exp = expression
this.paras = paras
this.lambda = lambda
}
stream() {
}
trans() {
}
}
class ParasNode extends Node {
constructor(list) {
super("Paras")
this.paras = list
}
stream() {
}
trans() {
}
}
class LambdaNode extends Node {
constructor(lambdaParas, lambdaStmt) {
super("Lambda")
this.paras = lambdaParas
this.stmt = lambdaStmt
}
stream() {
}
trans() {
}
}
class LambdaParasNode extends Node {
constructor(list) {
super("LParas")
this.paras = list;
}
stream() {
}
trans() {
}
}
class LambdaStmtNode extends Node {
constructor(body) {
super("LStmt")
this.stmt = body
}
stream() {
return this
}
trans() {
}
}
class Parser {
constructor(tokens) {
this.tokens = tokens;
this.id = 0;
}
matchExp() {
token = this.now()
this.next()
if (token == "") {
// Should not be empty string
return null
}
if (validNumber(token)) {
// in fact, as tokenizer's impl, number are automatically divided.
return new NumNode(token)
} else if (validVarName(token)) {
return new VarNode(token)
} else if (token === "{") {
return new LambdaNode(token)
} else {
return null
}
}
checkExp(expNode) {
if (expNode instanceof NumNode) {
return null
} else if (expNode instanceof VarNode) {
return this.matchFn(expNode)
} else if (expNode instanceof LambdaNode) {
return this.matchFn(expNode)
} else {
return null
}
}
matchFn(expNode) {
if (this.now() === "(") {
return new FnNode(expNode, this.matchOptionalParas(")", ","), this.matchLambda())
} else if (this.now() === "{") {
return new FnNode(expNode, null, this.matchLambda())
}
}
matchOptionalParas(stop, step) {
this.next() // from `(` or step(`,`) to element
if (this.now() === stop) {
return null // Optional failed, no paras
} else {
let paras = []
let paraNode = this.matchExp()
paras = paras.concat(paraNode)
if (this.next() === step) {
let append = this.matchOptionalParas(stop, step)
paras = paras.concat(append)
} else if (this.next() === stop){
this.next() // step over the stop condition
return paras
} else {
return null
}
}
}
parse() {
let expNode = matchExp()
let fnNode = checkExp(expNode)
}
hasNext() {
if (this.id >= this.tokens.length) {
return false
} else {
return true
}
}
now() {
if (this.id >= this.tokens.length) {
return undefined
}
return this.tokens[this.id]
}
next() {
this.id++
return this.now()
}
step(s) {
this.id += s
return this.now()
}
rollback() {
this.id -= 1
return this.now()
}
prev() {
let i = this.id - 1
return this.tokens[i]
}
remain() {
return this.tokens.slice(this.id)
}
}
function transpile(program, log = false) {
let tokens = tokenize(program)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment