Skip to content

Instantly share code, notes, and snippets.

@dtudury
Last active November 2, 2020 20:53
Show Gist options
  • Save dtudury/06e82d16c86244d616cf14dad097cb4f to your computer and use it in GitHub Desktop.
Save dtudury/06e82d16c86244d616cf14dad097cb4f to your computer and use it in GitHub Desktop.
basic lisp parser
// A *just* good-enough lisp parser
const WHITE_SPACE = /\s/
const OPEN_PAREN = /\(/
const CLOSE_PAREN = /\)/
const SUBATOMIC = /[^\s()]/
function parse (program) {
let i = 0
const charAt = (index) => program.charAt(index)
const nextCharIs = regex => charAt(i).match(regex)
const readNextChar = () => charAt(i++)
const skipWhiteSpace = () => {
while (nextCharIs(WHITE_SPACE)) readNextChar()
}
const nextCharMustBe = regex => {
if (!readNextChar().match(regex)) {
throw new Error(`char at ${i} is not ${regex}`)
}
}
const readParen = (parenType) => {
skipWhiteSpace()
nextCharMustBe(parenType)
skipWhiteSpace()
}
const readAtom = () => {
let parts = []
skipWhiteSpace()
while (nextCharIs(SUBATOMIC)) parts.push(readNextChar())
skipWhiteSpace()
return parts.join('')
}
const readList = () => {
const list = []
readParen(OPEN_PAREN)
while (!nextCharIs(CLOSE_PAREN)) list.push(readExpression())
readParen(CLOSE_PAREN)
return list
}
const readExpression = () => {
if (nextCharIs(OPEN_PAREN)) return readList()
else return readAtom()
}
const ast = []
while (i < program.length) {
ast.push(readList())
}
return ast
}
function interpret (program) {
const ops = {
'print': ([arg]) => console.log(arg),
'list': args => args,
'+': args => args.reduce((acc, item) => acc + item, 0),
'-': ([init, ...args]) => args.reduce((acc, item) => acc - item, init)
}
const evaluate = statement => {
if (Array.isArray(statement)) {
let [op, ...args] = statement
args = args.map(arg => evaluate(arg))
if (ops[op]) {
return ops[op](args)
}
throw new Error('no op for', op)
}
const num = Number(statement)
if (isNaN(num)) return statement
else return num
}
for (const statement of program) {
evaluate(statement)
}
}
const program = parse(`
(print(+ (- 7 6) (- 4 3)))
(print(list (- 7 6) (- 4 3)))
`)
console.log(JSON.stringify(program, null, ' '))
interpret(program)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment