rubylisp 0.2.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +129 -2
  3. data/bin/rubylisp +87 -12
  4. data/lib/rubylisp/atom.rb +25 -6
  5. data/lib/rubylisp/boolean.rb +9 -6
  6. data/lib/rubylisp/builtins.rb +19 -18
  7. data/lib/rubylisp/character.rb +14 -275
  8. data/lib/rubylisp/class_object.rb +56 -0
  9. data/lib/rubylisp/cons_cell.rb +56 -25
  10. data/lib/rubylisp/debug.rb +15 -19
  11. data/lib/rubylisp/environment.rb +27 -0
  12. data/lib/rubylisp/environment_frame.rb +31 -6
  13. data/lib/rubylisp/eof_object.rb +26 -0
  14. data/lib/rubylisp/exception.rb +61 -61
  15. data/lib/rubylisp/ext.rb +32 -6
  16. data/lib/rubylisp/ffi_new.rb +2 -1
  17. data/lib/rubylisp/ffi_send.rb +15 -5
  18. data/lib/rubylisp/frame.rb +5 -164
  19. data/lib/rubylisp/function.rb +4 -3
  20. data/lib/rubylisp/macro.rb +13 -8
  21. data/lib/rubylisp/{object.rb → native_object.rb} +0 -15
  22. data/lib/rubylisp/number.rb +5 -0
  23. data/lib/rubylisp/parser.rb +81 -52
  24. data/lib/rubylisp/port.rb +27 -0
  25. data/lib/rubylisp/prim_alist.rb +115 -0
  26. data/lib/rubylisp/prim_assignment.rb +61 -0
  27. data/lib/rubylisp/prim_character.rb +273 -0
  28. data/lib/rubylisp/{ffi_class.rb → prim_class_object.rb} +16 -69
  29. data/lib/rubylisp/prim_environment.rb +203 -0
  30. data/lib/rubylisp/prim_equivalence.rb +93 -0
  31. data/lib/rubylisp/prim_frame.rb +166 -0
  32. data/lib/rubylisp/prim_io.rb +266 -0
  33. data/lib/rubylisp/prim_list_support.rb +496 -0
  34. data/lib/rubylisp/{logical.rb → prim_logical.rb} +9 -14
  35. data/lib/rubylisp/prim_math.rb +397 -0
  36. data/lib/rubylisp/prim_native_object.rb +21 -0
  37. data/lib/rubylisp/prim_relational.rb +42 -0
  38. data/lib/rubylisp/{special_forms.rb → prim_special_forms.rb} +98 -85
  39. data/lib/rubylisp/prim_string.rb +792 -0
  40. data/lib/rubylisp/prim_system.rb +55 -0
  41. data/lib/rubylisp/prim_type_checks.rb +58 -0
  42. data/lib/rubylisp/prim_vector.rb +497 -0
  43. data/lib/rubylisp/primitive.rb +51 -6
  44. data/lib/rubylisp/string.rb +4 -803
  45. data/lib/rubylisp/symbol.rb +0 -1
  46. data/lib/rubylisp/tokenizer.rb +161 -137
  47. data/lib/rubylisp/vector.rb +10 -31
  48. data/lib/rubylisp.rb +1 -0
  49. metadata +46 -17
  50. data/lib/rubylisp/alist.rb +0 -230
  51. data/lib/rubylisp/assignment.rb +0 -65
  52. data/lib/rubylisp/equivalence.rb +0 -118
  53. data/lib/rubylisp/io.rb +0 -74
  54. data/lib/rubylisp/list_support.rb +0 -526
  55. data/lib/rubylisp/math.rb +0 -405
  56. data/lib/rubylisp/relational.rb +0 -46
  57. data/lib/rubylisp/system.rb +0 -20
  58. data/lib/rubylisp/testing.rb +0 -136
  59. data/lib/rubylisp/type_checks.rb +0 -60
@@ -1,21 +1,6 @@
1
1
  module Lisp
2
2
 
3
3
  class NativeObject < Atom
4
-
5
- def self.register
6
- Primitive.register("wrap-object") {|args, env| Lisp::NativeObject::wrap_impl(args, env) }
7
- end
8
-
9
- def self.wrap_impl(args, env)
10
- return Lisp::Debug.process_error("wrap-object requires 1 argument", env) unless args.length == 1
11
- raw_val = args.car.evaluate(env)
12
- val = if raw_val.list?
13
- raw_val.to_a
14
- else
15
- raw_val
16
- end
17
- NativeObject.with_value(val)
18
- end
19
4
 
20
5
  def self.new_instance_of(c)
21
6
  self.new(c.alloc.init)
@@ -42,6 +42,11 @@ module Lisp
42
42
  @value < 0
43
43
  end
44
44
 
45
+ def eqv?(sexpr)
46
+ return false unless sexpr.number?
47
+ @value == sexpr.value
48
+ end
49
+
45
50
  def type
46
51
  :number
47
52
  end
@@ -10,7 +10,7 @@ module Lisp
10
10
  end
11
11
 
12
12
  def make_hex_number(str)
13
- Lisp::Number.with_value(str.gsub("#x", "0x").to_i(0))
13
+ Lisp::Number.with_value(["0x", str].join.to_i(0))
14
14
  end
15
15
 
16
16
  def make_float(str)
@@ -18,7 +18,7 @@ module Lisp
18
18
  end
19
19
 
20
20
  def make_string(str)
21
- Lisp::String.with_value(str[1...-1])
21
+ Lisp::String.with_value(str)
22
22
  end
23
23
 
24
24
  def make_symbol(str)
@@ -33,7 +33,7 @@ module Lisp
33
33
  tok, lit = tokens.next_token
34
34
  if tok == :RPAREN
35
35
  tokens.consume_token
36
- return nil
36
+ return Lisp::ConsCell.cons()
37
37
  end
38
38
 
39
39
  car = nil
@@ -45,67 +45,85 @@ module Lisp
45
45
  cdr = self.parse_sexpr(tokens)
46
46
  return nil if tokens.next_token[0] == :EOF
47
47
  tok, lit = tokens.next_token
48
- return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}", env) if tok != :RPAREN
48
+ return Lisp::Debug.process_error("Expected ')' to follow a dotted tail on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tok != :RPAREN
49
49
  tokens.consume_token
50
50
  return Lisp::ConsCell.array_to_list(cells, cdr)
51
51
  else
52
52
  car = self.parse_sexpr(tokens)
53
- return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
53
+ return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", Lisp::EnvironmentFrame.global) if tokens.next_token[0] == :EOF
54
54
  cells << car
55
55
  end
56
56
  tok, lit = tokens.next_token
57
57
  end
58
58
 
59
59
  tokens.consume_token
60
- return Lisp::ConsCell.array_to_list(cells)
60
+ Lisp::ConsCell.array_to_list(cells)
61
61
  end
62
62
 
63
- def parse_map(tokens)
63
+ def parse_frame(tokens, literal)
64
64
  m = {}
65
65
  tok, lit = tokens.next_token
66
66
  if tok == :RBRACE
67
67
  tokens.consume_token
68
- return ConsCell.cons(Symbol.named("make-frame"), nil)
69
- end
70
-
71
- cells = []
72
- while tok != :RBRACE
73
- item = self.parse_sexpr(tokens)
74
- return Lisp::Debug.process_error("Unexpected EOF (expected '}') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
75
- cells << item
76
- tok, lit = tokens.next_token
68
+ if literal
69
+ Lisp::Frame.new
70
+ else
71
+ Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), nil)
72
+ end
73
+ else
74
+ cells = []
75
+ while tok != :RBRACE
76
+ item = self.parse_sexpr(tokens)
77
+ return Lisp::Debug.process_error("Unexpected EOF (expected '}') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
78
+ cells << item
79
+ tok, lit = tokens.next_token
80
+ end
81
+
82
+ tokens.consume_token
83
+ keys_and_values = Lisp::ConsCell.array_to_list(cells)
84
+ if literal
85
+ Lisp::PrimFrame.make_frame_impl(keys_and_values, Lisp::EnvironmentFrame.global)
86
+ else
87
+ Lisp::ConsCell.cons(Lisp::Symbol.named("make-frame"), keys_and_values)
88
+ end
77
89
  end
78
-
79
- tokens.consume_token
80
- return ConsCell.cons(Symbol.named("make-frame"), ConsCell.array_to_list(cells))
81
90
  end
82
91
 
83
92
 
84
- def parse_vector(tokens)
93
+ def parse_vector(tokens, literal)
85
94
  v = []
86
95
  tok, lit = tokens.next_token
87
- if tok == :RBRACKET
96
+ if tok == :RPAREN
88
97
  tokens.consume_token
89
- return ConsCell.cons(Symbol.named("make-vector"), nil)
90
- end
91
-
92
- cells = []
93
- while tok != :RBRACKET
94
- item = self.parse_sexpr(tokens)
95
- return Lisp::Debug.process_error("Unexpected EOF (expected ']') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
96
- cells << item
97
- tok, lit = tokens.next_token
98
+ if literal
99
+ Lisp::Vector.new
100
+ else
101
+ Lisp::ConsCell.cons(Lis::Symbol.named("vector"), nil)
102
+ end
103
+ else
104
+ cells = []
105
+ while tok != :RPAREN
106
+ item = self.parse_sexpr(tokens)
107
+ return Lisp::Debug.process_error("Unexpected EOF (expected ')') on line #{tokens.line_number}", env) if tokens.next_token[0] == :EOF
108
+ cells << item
109
+ tok, lit = tokens.next_token
110
+ end
111
+
112
+ tokens.consume_token
113
+
114
+ if literal
115
+ Lisp::Vector.with_array(cells)
116
+ else
117
+ Lisp::ConsCell.cons(Lisp::Symbol.named("vector"), Lisp::ConsCell.array_to_list(cells))
118
+ end
98
119
  end
99
-
100
- tokens.consume_token
101
- return ConsCell.cons(Symbol.named("make-vector"), ConsCell.array_to_list(cells))
102
120
  end
103
121
 
104
122
 
105
123
  def parse_sexpr(tokens)
106
124
  while true
107
125
  tok, lit = tokens.next_token
108
- #puts "token: <#{tok}, #{lit}>"
126
+ # puts "token: <#{tok}, #{lit}>"
109
127
  return nil if tok == :EOF
110
128
  tokens.consume_token
111
129
  case tok
@@ -124,33 +142,37 @@ module Lisp
124
142
  when :LPAREN
125
143
  return parse_cons_cell(tokens)
126
144
  when :LBRACE
127
- return parse_map(tokens)
128
- when :LBRACKET
129
- return parse_vector(tokens)
145
+ return parse_frame(tokens, false)
146
+ when :QUOTE_LBRACE
147
+ return parse_frame(tokens, true)
148
+ when :HASH_LPAREN
149
+ return parse_vector(tokens, false)
150
+ when :QUOTE_HASH_LPAREN
151
+ return parse_vector(tokens, true)
130
152
  when :SYMBOL
131
153
  return make_symbol(lit)
132
154
  when :FFI_NEW_SYMBOL
133
- return FfiNew.new(lit)
155
+ return Lisp::FfiNew.new(lit)
134
156
  when :FFI_SEND_SYMBOL
135
- return FfiSend.new(lit)
157
+ return Lisp::FfiSend.new(lit)
136
158
  when :FFI_STATIC_SYMBOL
137
- return FfiStatic.new(lit)
159
+ return Lisp::FfiStatic.new(lit)
138
160
  when :FALSE
139
161
  return Lisp::FALSE
140
162
  when :TRUE
141
163
  return Lisp::TRUE
142
164
  when :QUOTE
143
165
  expr = parse_sexpr(tokens)
144
- return ConsCell.array_to_list([Symbol.named('quote'), expr])
166
+ return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quote'), expr])
145
167
  when :BACKQUOTE
146
168
  expr = parse_sexpr(tokens)
147
- return ConsCell.array_to_list([Symbol.named('quasiquote'), expr])
169
+ return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('quasiquote'), expr])
148
170
  when :COMMA
149
171
  expr = parse_sexpr(tokens)
150
- return ConsCell.array_to_list([Symbol.named('unquote'), expr])
172
+ return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote'), expr])
151
173
  when :COMMAAT
152
174
  expr = parse_sexpr(tokens)
153
- return ConsCell.array_to_list([Symbol.named('unquote-splicing'), expr])
175
+ return Lisp::ConsCell.array_to_list([Lisp::Symbol.named('unquote-splicing'), expr])
154
176
  when :ILLEGAL
155
177
  return Lisp::Debug.process_error("Illegal token: #{lit} on line #{tokens.line_number}", Lisp::EnvironmentFrame.global)
156
178
  else
@@ -160,21 +182,23 @@ module Lisp
160
182
  end
161
183
 
162
184
  def parse(src)
163
- tokenizer = Tokenizer.new(src)
164
- tokenizer.init
165
-
166
- sexpr = self.parse_sexpr(tokenizer)
167
- return sexpr
185
+ tokenizer = Tokenizer.from_string(src)
186
+ self.parse_sexpr(tokenizer)
168
187
  end
169
188
 
189
+ def parse_object_from_file(port, env=Lisp::EnvironmentFrame.global)
190
+ tokenizer = Tokenizer.from_file(port)
191
+ result = self.parse_sexpr(tokenizer)
192
+ result.nil? ? Lisp::EofObject.instance : result
193
+ end
194
+
170
195
  def parse_and_eval(src, env=Lisp::EnvironmentFrame.global)
171
196
  sexpr = self.parse(src)
172
197
  return sexpr.evaluate(env)
173
198
  end
174
199
 
175
200
  def parse_and_eval_all(src, env=Lisp::EnvironmentFrame.global)
176
- tokenizer = Tokenizer.new(src)
177
- tokenizer.init
201
+ tokenizer = Tokenizer.from_string(src)
178
202
  result = nil
179
203
  until tokenizer.eof?
180
204
  sexpr = self.parse_sexpr(tokenizer)
@@ -183,7 +207,12 @@ module Lisp
183
207
  result
184
208
  end
185
209
 
186
-
210
+ def process_file(fname)
211
+ File.open(fname) do |f|
212
+ parse_and_eval_all(f.read)
213
+ end
214
+ end
215
+
187
216
  end
188
217
 
189
218
  end
@@ -0,0 +1,27 @@
1
+ module Lisp
2
+
3
+ class Port < Atom
4
+
5
+ def self.with_value(p)
6
+ self.new(p)
7
+ end
8
+
9
+ def initialize(p)
10
+ @value = p
11
+ end
12
+
13
+ def type
14
+ :port
15
+ end
16
+
17
+ def port?
18
+ true
19
+ end
20
+
21
+ def to_s
22
+ "<port: #{@value}>"
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,115 @@
1
+ module Lisp
2
+
3
+ class PrimAlist
4
+
5
+
6
+ def self.register
7
+ Primitive.register("acons", "2|3") {|args, env| Lisp::PrimAlist::acons_impl(args, env) }
8
+ Primitive.register("assq", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.eq?(b) } }
9
+ Primitive.register("assv", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.eqv?(b) } }
10
+ Primitive.register("assoc", "2") {|args, env| Lisp::PrimAlist::assoc_impl(args, env) {|a, b| a.equal?(b) } }
11
+ Primitive.register("rassq", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.eq?(b) } }
12
+ Primitive.register("rassv", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.eqv?(b) } }
13
+ Primitive.register("rassoc", "2") {|args, env| Lisp::PrimAlist::rassoc_impl(args, env) {|a, b| a.equal?(b) } }
14
+ Primitive.register("del-assq", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eq?(b) } }
15
+ Primitive.register("dissq", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eq?(b) } }
16
+ Primitive.register("del-assv", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eqv?(b) } }
17
+ Primitive.register("dissv", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.eqv?(b) } }
18
+ Primitive.register("del-assoc", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.equal?(b) } }
19
+ Primitive.register("dissoc", "2") {|args, env| Lisp::PrimAlist::dissoc_impl(args, env) {|a, b| a.equal?(b) } }
20
+ Primitive.register("zip", "2|3") {|args, env| Lisp::PrimAlist::zip_impl(args, env) }
21
+ Primitive.register("pairlis", "2|3") {|args, env| Lisp::PrimAlist::zip_impl(args, env) }
22
+ end
23
+
24
+
25
+ def self.acons_impl(args, env)
26
+ key = args.car
27
+ value = args.cadr
28
+ alist = args.length == 2 ? nil : args.caddr
29
+ return Lisp::Debug.process_error("the last argument to acons has to be a list", env) unless alist.list?
30
+
31
+ pair = ConsCell.cons(key, value)
32
+ if alist.nil?
33
+ ConsCell.cons(pair)
34
+ else
35
+ ConsCell.cons(pair, alist)
36
+ end
37
+ end
38
+
39
+
40
+ def self.assoc_impl(args, env, &equivalence_block)
41
+ key = args.car
42
+ alist = args.cadr
43
+ return Lisp::Debug.process_error("the last argument to assoc has to be a list", env) unless alist.list?
44
+
45
+ alist.each do |pair|
46
+ if equivalence_block.call(pair.car, key)
47
+ return pair
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ def self.rassoc_impl(args, env, &equivalence_block)
54
+ value = args.car
55
+ alist = args.cadr
56
+ return Lisp::Debug.process_error("the last argument to rassoc has to be a list", env) unless alist.list?
57
+ alist.each do |pair|
58
+ if equivalence_block.call(pair.cdr, value)
59
+ return pair
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ def self.dissoc_impl(args, env, &equivalence_block)
66
+ key = args.car
67
+ alist = args.cadr
68
+ return Lisp::Debug.process_error("the last argument to dissoc has to be a list", env) unless alist.list?
69
+
70
+ new_prefix = nil
71
+ trailing_end = nil
72
+ crawler = alist
73
+ while !crawler.nil?
74
+ if equivalence_block.call(crawler.caar, key)
75
+ if new_prefix.nil?
76
+ new_prefix = crawler.cdr
77
+ else
78
+ trailing_end.set_cdr!(crawler.cdr)
79
+ end
80
+ return new_prefix
81
+ else
82
+ new_cell = ConsCell.cons(ConsCell.cons(crawler.caar, crawler.cdar))
83
+ if new_prefix.nil?
84
+ new_prefix = new_cell
85
+ trailing_end = new_prefix
86
+ else
87
+ trailing_end.set_cdr!(new_cell)
88
+ end
89
+ end
90
+ crawler = crawler.cdr
91
+ end
92
+ end
93
+
94
+
95
+ def self.zip_impl(args, env)
96
+ key_list = args.car
97
+ return Lisp::Debug.process_error("the keys supplied to zip has to be a list", env) unless key_list.list?
98
+ value_list = args.cadr
99
+ return Lisp::Debug.process_error("the values supplied to zip has to be a list", env) unless value_list.list?
100
+ return Lisp::Debug.process_error("zip requires the same number of keys and values", env) unless key_list.length == value_list.length
101
+
102
+ old_list = if args.length == 3
103
+ alist = args.caddr
104
+ return Lisp::Debug.process_error("the third argument to zip has to be a list", env) unless alist.list?
105
+ alist
106
+ else
107
+ nil
108
+ end
109
+ pairs = key_list.to_a.zip(value_list.to_a)
110
+ pairs.inject(old_list) {|alist, pair| ConsCell.cons(ConsCell.cons(*pair), alist)}
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,61 @@
1
+ module Lisp
2
+
3
+ class PrimAssignment
4
+
5
+ def self.register
6
+ Primitive.register("set!", "2",
7
+ "(set! name new-value)\n\nThe way to assign (i.e. rebind) a symbol. `name` is the symbol to be rebound.
8
+ The `new-value` sexpr is evaluated to arrive at the new value to be bound to. Use of `set!` is frowned upon, and should not be used without thought.",
9
+ true) { |args, env| Lisp::PrimAssignment::setbang_impl(args, env) }
10
+
11
+ Primitive.register("set-car!", "2",
12
+ "(set-car! cons-cell new-value)\n\nSet the `car` pointer of `cons-cell`.") { |args, env| Lisp::PrimAssignment::setcarbang_impl(args, env) }
13
+
14
+ Primitive.register("set-cdr!", "2",
15
+ "(set-cdr! cons-cell new-value)\n\nSet the `cdr` pointer of `cons-cell`.") { |args, env| Lisp::PrimAssignment::setcdrbang_impl(args, env) }
16
+
17
+ Primitive.register("set-nth!", "3",
18
+ "(set-nth! n list-or-vector new-value)\n\nSets the `n`th element of `list-or-vector` to `new-value`.") { |args, env| Lisp::PrimAssignment::setnthbang_impl(args, env) }
19
+
20
+ end
21
+
22
+
23
+ def self.setbang_impl(args, env)
24
+ sym = args.car
25
+ return Lisp::Debug.process_error("set! requires a raw (unevaluated) symbol as it's first argument.", env) unless sym.symbol?
26
+ value = args.cadr.evaluate(env)
27
+ env.set(sym, value)
28
+ end
29
+
30
+
31
+ def self.setcarbang_impl(args, env)
32
+ pair = args.car
33
+ return Lisp::Debug.process_error("set-car! requires a pair as it's first argument.", env) unless pair.pair?
34
+ value = args.cadr
35
+ pair.set_car!(value)
36
+ end
37
+
38
+
39
+ def self.setcdrbang_impl(args, env)
40
+ pair = args.car
41
+ return Lisp::Debug.process_error("set-cdr! requires a pair as it's first argument.", env) unless pair.pair?
42
+ value = args.cadr
43
+ pair.set_cdr!(value)
44
+ end
45
+
46
+
47
+ def self.setnthbang_impl(args, env)
48
+ n = args.car
49
+ return Lisp::Debug.process_error("The first argument of set-nth! has to be an number.", env) unless n.number?
50
+ return Lisp::Debug.process_error("The first argument of set-nth! has to be non negative.", env) unless n.value >= 0
51
+
52
+ l = args.cadr
53
+ return Lisp::Debug.process_error("set-nth! requires a list or vector as it's first argument.", env) unless l.list? || l.vector?
54
+ value = args.caddr
55
+ l.set_nth!(n.value, value)
56
+ l
57
+ end
58
+
59
+
60
+ end
61
+ end