Skip to content

Instantly share code, notes, and snippets.

@jkarmel
Created April 5, 2015 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkarmel/62a018891d33ffc00492 to your computer and use it in GitHub Desktop.
Save jkarmel/62a018891d33ffc00492 to your computer and use it in GitHub Desktop.
tiny_lisp.coffee
assert = require 'assert'
_ = require 'lodash'
globals =
'+': (a,b) -> a + b
'*': (a,b) -> a * b
parse = (input) ->
JSON.parse(input.replace(/\s/g,",").replace(/[a-z\+\*]+/g, '"$&"'))
evaluate = (x, env = globals)->
if (Array.isArray(x)) # x is an expression
evaluateExpression x, env
else if env[x]
env[x]
else
x
evaluateExpression = (x, env = globals) ->
if x[0] == 'let'
evaluateLet x, env
else if x[0] == 'fn'
evaluateFn x, env
else
results = x.map (expression) -> evaluate(expression)
results[0].apply {}, results[1..-1]
evaluateLet = (x, env = globals) ->
bindings = x[1]
body = x[2]
vars = {}
for i in _.range 0, bindings.length, 2
name = bindings[i]
expression = bindings[i + 1]
vars[name] = evaluate expression, env
evaluate body, _.merge env, vars
evaluateFn = (x, env = globals) ->
bindings = x[1]
body = x[2]
->
vars = {}
for name, i in bindings
vars[name] = arguments[i]
evaluate body, _.merge env, vars
assert 6 == evaluate parse "[* [+ 1 2] 2]"
assert 1 == evaluate parse "[let [x 1] x]"
assert 3 == evaluate parse "[let [x 1 y 2] [+ x y]]"
assert 4 == evaluate parse "[let [x [+ 1 1] y 2] [+ x y]]"
assert 2 == evaluate parse "[[fn [x] [+ x 1]] 1]"
assert 3 == evaluate parse "[let [addtwo [fn [x] [+ x 2]]] [addtwo 1]]"
assert 3 == evaluate parse "[let [add [fn [x y] [+ x y]]] [add 1 2]]"
assert 4 == evaluate parse "[let [add [fn [x y] [+ x y]]] [add [+ 1 1] 2]]”
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment