aboutsummaryrefslogtreecommitdiff
path: root/ruby
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2015-03-02 21:33:10 -0600
committerJoel Martin <github@martintribe.org>2015-03-02 21:33:10 -0600
commit835fb7d8b06e2b44792a97ac89994658bf6d00af (patch)
tree578f67726ab9e3ce5fcbc50220e9761a66c5ddf1 /ruby
parent6b72e6078a7d505ecf9d711eb4a16fc4dfac36b6 (diff)
parent8a98ef9a3f3a6b6d05d02dc305a0c886c907e0f3 (diff)
downloadmal-835fb7d8b06e2b44792a97ac89994658bf6d00af.tar.gz
mal-835fb7d8b06e2b44792a97ac89994658bf6d00af.zip
Merge branch 'master' into gh-pages
Conflicts: .gitignore
Diffstat (limited to 'ruby')
-rw-r--r--ruby/Makefile2
-rw-r--r--ruby/core.rb12
-rw-r--r--ruby/mal_readline.rb2
-rw-r--r--ruby/printer.rb6
-rw-r--r--ruby/reader.rb6
-rw-r--r--ruby/step0_repl.rb3
-rw-r--r--ruby/step1_read_print.rb9
-rw-r--r--ruby/step2_eval.rb9
-rw-r--r--ruby/step3_env.rb11
-rw-r--r--ruby/step4_if_fn_do.rb13
-rw-r--r--ruby/step5_tco.rb13
-rw-r--r--ruby/step6_file.rb13
-rw-r--r--ruby/step7_quote.rb13
-rw-r--r--ruby/step8_macros.rb13
-rw-r--r--ruby/step9_try.rb (renamed from ruby/step9_interop.rb)30
-rw-r--r--ruby/stepA_mal.rb (renamed from ruby/stepA_more.rb)19
-rw-r--r--ruby/tests/stepA_mal.mal27
-rw-r--r--ruby/types.rb2
18 files changed, 120 insertions, 83 deletions
diff --git a/ruby/Makefile b/ruby/Makefile
index 71ab92c..2241a4e 100644
--- a/ruby/Makefile
+++ b/ruby/Makefile
@@ -1,7 +1,7 @@
TESTS =
SOURCES_BASE = mal_readline.rb types.rb reader.rb printer.rb
-SOURCES_LISP = env.rb core.rb stepA_more.rb
+SOURCES_LISP = env.rb core.rb stepA_mal.rb
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)
#all: mal.rb
diff --git a/ruby/core.rb b/ruby/core.rb
index 6b127ba..b82bddc 100644
--- a/ruby/core.rb
+++ b/ruby/core.rb
@@ -1,6 +1,6 @@
require "readline"
-require "reader"
-require "printer"
+require_relative "reader"
+require_relative "printer"
$core_ns = {
:"=" => lambda {|a,b| a == b},
@@ -8,8 +8,10 @@ $core_ns = {
:nil? => lambda {|a| a == nil},
:true? => lambda {|a| a == true},
:false? => lambda {|a| a == false},
+ :symbol => lambda {|a| a.to_sym},
:symbol? => lambda {|a| a.is_a? Symbol},
- :symbol? => lambda {|a| a.is_a? Symbol},
+ :keyword => lambda {|a| "\u029e"+a},
+ :keyword? => lambda {|a| (a.is_a? String) && "\u029e" == a[0]},
:"pr-str" => lambda {|*a| a.map {|e| _pr_str(e, true)}.join(" ")},
:str => lambda {|*a| a.map {|e| _pr_str(e, false)}.join("")},
@@ -44,11 +46,11 @@ $core_ns = {
:sequential? => lambda {|a| sequential?(a)},
:cons => lambda {|a,b| List.new(b.clone.insert(0,a))},
:concat => lambda {|*a| List.new(a && a.reduce(:concat) || [])},
- :nth => lambda {|a,b| a[b]},
+ :nth => lambda {|a,b| raise "nth: index out of range" if b >= a.size; a[b]},
:first => lambda {|a| a[0]},
:rest => lambda {|a| List.new(a.size > 0 && a.drop(1) || [])},
:empty? => lambda {|a| a.size == 0},
- :count => lambda {|a| a.size},
+ :count => lambda {|a| return 0 if a == nil; a.size},
:conj => lambda {|*a| a[0].clone.conj(a.drop(1))},
:apply => lambda {|*a| a[0][*a[1..-2].concat(a[-1])]},
:map => lambda {|a,b| List.new(b.map {|e| a[e]})},
diff --git a/ruby/mal_readline.rb b/ruby/mal_readline.rb
index 63c5571..3799783 100644
--- a/ruby/mal_readline.rb
+++ b/ruby/mal_readline.rb
@@ -4,7 +4,7 @@ $history_loaded = false
$histfile = "#{ENV['HOME']}/.mal-history"
def _readline(prompt)
- if not $history_loaded
+ if !$history_loaded && File.exist?($histfile)
$history_loaded = true
File.readlines($histfile).each {|l| Readline::HISTORY.push(l.chomp)}
end
diff --git a/ruby/printer.rb b/ruby/printer.rb
index cfcd064..ef067a5 100644
--- a/ruby/printer.rb
+++ b/ruby/printer.rb
@@ -1,4 +1,4 @@
-require "types"
+require_relative "types"
def _pr_str(obj, print_readably=true)
_r = print_readably
@@ -12,7 +12,9 @@ def _pr_str(obj, print_readably=true)
obj.each{|k,v| ret.push(_pr_str(k,_r), _pr_str(v,_r))}
"{" + ret.join(" ") + "}"
when String
- if _r
+ if obj[0] == "\u029e"
+ ":" + obj[1..-1]
+ elsif _r
obj.inspect # escape special characters
else
obj
diff --git a/ruby/reader.rb b/ruby/reader.rb
index 1039105..badc6ec 100644
--- a/ruby/reader.rb
+++ b/ruby/reader.rb
@@ -1,4 +1,4 @@
-require "types"
+require_relative "types"
class Reader
def initialize(tokens)
@@ -31,7 +31,8 @@ def read_atom(rdr)
return case token
when /^-?[0-9]+$/ then token.to_i # integer
when /^-?[0-9][0-9.]*$/ then token.to_f # float
- when /^"/ then parse_str(token) # string
+ when /^".*"$/ then parse_str(token) # string
+ when /^:/ then "\u029e" + token[1..-1] # keyword
when "nil" then nil
when "true" then true
when "false" then false
@@ -56,7 +57,6 @@ def read_list(rdr, klass, start="(", last =")")
end
def read_form(rdr)
- token = rdr.peek
return case rdr.peek
when ";" then nil
when "'" then rdr.next; List.new [:quote, read_form(rdr)]
diff --git a/ruby/step0_repl.rb b/ruby/step0_repl.rb
index 9c03cfa..2f9e6a9 100644
--- a/ruby/step0_repl.rb
+++ b/ruby/step0_repl.rb
@@ -1,5 +1,4 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
+require_relative "mal_readline"
# read
def READ(str)
diff --git a/ruby/step1_read_print.rb b/ruby/step1_read_print.rb
index ded992a..ef416c3 100644
--- a/ruby/step1_read_print.rb
+++ b/ruby/step1_read_print.rb
@@ -1,8 +1,7 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
# read
def READ(str)
diff --git a/ruby/step2_eval.rb b/ruby/step2_eval.rb
index 50a135d..d2b7e1a 100644
--- a/ruby/step2_eval.rb
+++ b/ruby/step2_eval.rb
@@ -1,8 +1,7 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
# read
def READ(str)
diff --git a/ruby/step3_env.rb b/ruby/step3_env.rb
index 17126c5..ec8405b 100644
--- a/ruby/step3_env.rb
+++ b/ruby/step3_env.rb
@@ -1,9 +1,8 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
# read
def READ(str)
diff --git a/ruby/step4_if_fn_do.rb b/ruby/step4_if_fn_do.rb
index a93463b..151ecf6 100644
--- a/ruby/step4_if_fn_do.rb
+++ b/ruby/step4_if_fn_do.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
diff --git a/ruby/step5_tco.rb b/ruby/step5_tco.rb
index 38bb204..80be457 100644
--- a/ruby/step5_tco.rb
+++ b/ruby/step5_tco.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
diff --git a/ruby/step6_file.rb b/ruby/step6_file.rb
index 0c99cee..4eeca86 100644
--- a/ruby/step6_file.rb
+++ b/ruby/step6_file.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
diff --git a/ruby/step7_quote.rb b/ruby/step7_quote.rb
index 48385f1..23d9499 100644
--- a/ruby/step7_quote.rb
+++ b/ruby/step7_quote.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
diff --git a/ruby/step8_macros.rb b/ruby/step8_macros.rb
index 58adaea..488db12 100644
--- a/ruby/step8_macros.rb
+++ b/ruby/step8_macros.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
diff --git a/ruby/step9_interop.rb b/ruby/step9_try.rb
index 6d2cbe2..533853b 100644
--- a/ruby/step9_interop.rb
+++ b/ruby/step9_try.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
@@ -95,8 +94,21 @@ def EVAL(ast, env)
return env.set(a1, func)
when :macroexpand
return macroexpand(a1, env)
- when :"rb*"
- return eval(a1)
+ when :"try*"
+ begin
+ return EVAL(a1, env)
+ rescue Exception => exc
+ if exc.is_a? MalException
+ exc = exc.data
+ else
+ exc = exc.message
+ end
+ if a2 && a2[0] == :"catch*"
+ return EVAL(a2[2], Env.new(env, [a2[1]], [exc]))
+ else
+ raise esc
+ end
+ end
when :do
eval_ast(ast[1..-2], env)
ast = ast.last # Continue loop (TCO)
diff --git a/ruby/stepA_more.rb b/ruby/stepA_mal.rb
index 6123293..115fc8a 100644
--- a/ruby/stepA_more.rb
+++ b/ruby/stepA_mal.rb
@@ -1,10 +1,9 @@
-$: << File.expand_path(File.dirname(__FILE__))
-require "mal_readline"
-require "types"
-require "reader"
-require "printer"
-require "env"
-require "core"
+require_relative "mal_readline"
+require_relative "types"
+require_relative "reader"
+require_relative "printer"
+require_relative "env"
+require_relative "core"
# read
def READ(str)
@@ -96,7 +95,11 @@ def EVAL(ast, env)
when :macroexpand
return macroexpand(a1, env)
when :"rb*"
- return eval(a1)
+ res = eval(a1)
+ return case res
+ when Array; List.new res
+ else; res
+ end
when :"try*"
begin
return EVAL(a1, env)
diff --git a/ruby/tests/stepA_mal.mal b/ruby/tests/stepA_mal.mal
new file mode 100644
index 0000000..2d7efb8
--- /dev/null
+++ b/ruby/tests/stepA_mal.mal
@@ -0,0 +1,27 @@
+;; Testing basic ruby interop
+
+(rb* "7")
+;=>7
+
+(rb* "'7'")
+;=>"7"
+
+(rb* "[7,8,9]")
+;=>(7 8 9)
+
+(rb* "{\"abc\" => 789}")
+;=>{"abc" 789}
+
+(rb* "print 'hello\n'")
+; hello
+;=>nil
+
+(rb* "$foo=8;")
+(rb* "$foo")
+;=>8
+
+(rb* "['a','b','c'].map{|x| 'X'+x+'Y'}.join(' ')")
+;=>"XaY XbY XcY"
+
+(rb* "[1,2,3].map{|x| 1+x}")
+;=>(2 3 4)
diff --git a/ruby/types.rb b/ruby/types.rb
index 72d24d1..d64664b 100644
--- a/ruby/types.rb
+++ b/ruby/types.rb
@@ -1,4 +1,4 @@
-require "env"
+require_relative "env"
class MalException < StandardError
attr_reader :data