Skip to content

Instantly share code, notes, and snippets.

@jameslaneconkling
Last active August 23, 2022 00:32
Show Gist options
  • Save jameslaneconkling/24acb8ea326a1c8fdf64225aa7d0f44e to your computer and use it in GitHub Desktop.
Save jameslaneconkling/24acb8ea326a1c8fdf64225aa7d0f44e to your computer and use it in GitHub Desktop.
A silly simple lisp parser in javascript
const rules = [
{ type: 'space', regex: /^\s/ },
{ type: 'lParen', regex: /^\(/ },
{ type: 'rParen', regex: /^\)/ },
{ type: 'number', regex: /^[0-9\.]+/ },
{ type: 'string', regex: /^".*?"/ },
{ type: 'variable', regex: /^[^\s\(\)]+/ } // take from the beginning 1+ characters until you hit a ' ', '(', or ')' // TODO - support escaped double quote
];
const tokenizer = rules => input => {
for (let i = 0; i < rules.length; i += 1) {
let tokenized = rules[i].regex.exec(input);
if (tokenized) {
return {
token: tokenized[0],
type: rules[i].type,
rest: input.slice(tokenized[0].length)
};
}
}
throw new Error(`no matching tokenize rule for ${JSON.stringify(input)}`);
};
const parser = tokenize => function parse(input, ast, parents = []) {
if (input === '') {
return ast;
}
const { token, type, rest } = tokenize(input);
if (type === 'space') {
// do nothing
return parse(rest, ast, parents);
} else if (type === 'variable') {
ast.push(token);
return parse(rest, ast, parents);
} else if (type === 'number') {
ast.push(Number(token));
return parse(rest, ast, parents);
} else if (type === 'string') {
ast.push(token.replace(/(^"|"$)/g, "'"));
return parse(rest, ast, parents);
} else if (type === 'lParen') {
parents.push(ast)
return parse(rest, [], parents)
} else if (type === 'rParen') {
const parentAst = parents.pop();
if (parentAst) {
parentAst.push(ast);
return parse(rest, parentAst, parents);
}
return parse(rest, ast, parents);
}
throw new Error(`Missing parse logic for rule ${JSON.stringify(type)}`);
};
const input = `(first
(list 1(+ 2 (inc 3)) "nine" 10 "ele ven"))`;
console.log(JSON.stringify(
parser(tokenizer(rules))(input)[0]
));
// ["first",["list",1,["+",2,["inc",3]],"'nine'",10,"'ele ven'"]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment