Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented quote. #2

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ Features

- [x] __conditional__ - (if test conseq alt) Evaluate test; if true, evaluate and return conseq; otherwise evaluate and return alt. _Example: (if (< 10 20) (+ 1 1) (+ 3 3)) ⇒ 2_

- [ ] __quotation__ - (quote exp) Return the exp literally; do not evaluate it. _Example: (quote (a b c)) ⇒ (a b c)_
- [x] __quotation__ - (quote exp) Return the exp literally; do not evaluate it. _Example: (quote (a b c)) ⇒ (a b c)_

- [ ] __assignment__ - (set! var exp) Evaluate exp and assign that value to var, which must have been previously defined (with a define or as a parameter to an enclosing procedure). _Example: (set! x2 (* x x))_
- [x] __assignment__ - (set! var exp) Evaluate exp and assign that value to var, which must have been previously defined (with a define or as a parameter to an enclosing procedure). _Example: (set! x2 (* x x))_

- [ ] __sequencing__ - (begin exp...) Evaluate each of the expressions in left-to-right order, and return the final value. _Example: (begin (set! x 1) (set! x (+ x 1)) (* x 2)) ⇒ 4_
- [x] __sequencing__ - (begin exp...) Evaluate each of the expressions in left-to-right order, and return the final value. _Example: (begin (define x 1) (set! x (+ x 1)) (* x 2)) ⇒ 4_

- [x] __display__ - (display exp...) Evaluate each of the expressions in left-to-right order, and write each result to STDOUT. _Example: (display Hello World! 42) ⇒ Hello World! 42_
19 changes: 18 additions & 1 deletion lib/lisp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ def self.parse(tokens, tree = [])

def self.evaluator(token)
case token
when /\d/
when /\d*\.\d*/
token.to_f
when /\d/
token.to_i
else
token.to_sym
end
Expand All @@ -52,6 +54,21 @@ def self.execute(exp, scope = global)
_, test, conseq, alt = exp
exp = execute(test, scope) ? conseq : alt
execute(exp, scope)
when :quote
_, exp = exp
exp
when :set!
_, var, exp = exp
unless scope.has_key?(var)
raise "#{var} must be defined before you can set! it"
end
scope[var] = execute(exp, scope)
when :begin
_ = exp.shift
exp.map { |exp| execute(exp) }.last
when :display
_ = exp.shift
exp.map { |exp| execute(exp) || exp }.join(' ').tap { |str| puts str }
else
func, *args = exp.map { |exp| execute(exp, scope) }
func.call(*args)
Expand Down
25 changes: 25 additions & 0 deletions test/test_lisp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,29 @@ def test_lambda
Lisp.eval("(define fact (lambda (n) (if (<= n 1) 1 (* n (fact (- n 1))))))")
assert_equal 3628800, Lisp.eval("(fact 10)")
end

def test_quote
assert_equal [:a, :b, :c], Lisp.eval('(quote (a b c))')
end

def test_assignment
ex = assert_raises(RuntimeError) { Lisp.eval('(set! foo 42)') }
assert_equal 'foo must be defined before you can set! it', ex.message

Lisp.eval('(define foo 3.14)')
assert_equal 42, Lisp.eval('(set! foo 42)')
assert_equal 42, Lisp.eval('(* 1 foo)')

assert_equal -42, Lisp.eval('(set! foo (* -1 foo))')
end

def test_sequencing
assert_equal 4, Lisp.eval('(begin (define x 1) (set! x (+ x 1)) (* x 2))')
end

def test_display
assert_output("Hello World! 42\n") { Lisp.eval('(display Hello World! 42)') }
assert_output("Evaluated: 3.14\n") { Lisp.eval('(display Evaluated: (* 1 3.14))') }
end

end