rubymotionlisp 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +129 -2
- data/lib/rubylisp/atom.rb +25 -6
- data/lib/rubylisp/boolean.rb +9 -6
- data/lib/rubylisp/builtins.rb +33 -0
- data/lib/rubylisp/character.rb +14 -275
- data/lib/rubylisp/class_object.rb +56 -0
- data/lib/rubylisp/cons_cell.rb +50 -20
- data/lib/rubylisp/environment.rb +27 -0
- data/lib/rubylisp/environment_frame.rb +24 -6
- data/lib/rubylisp/eof_object.rb +26 -0
- data/lib/rubylisp/exception.rb +61 -61
- data/lib/rubylisp/ext.rb +32 -6
- data/lib/rubylisp/ffi_new.rb +2 -1
- data/lib/rubylisp/ffi_send.rb +15 -5
- data/lib/rubylisp/frame.rb +5 -164
- data/lib/rubylisp/function.rb +4 -3
- data/lib/rubylisp/macro.rb +13 -8
- data/lib/rubylisp/{object.rb → native_object.rb} +0 -15
- data/lib/rubylisp/number.rb +5 -0
- data/lib/rubylisp/parser.rb +81 -52
- data/lib/rubylisp/port.rb +27 -0
- data/lib/rubylisp/prim_alist.rb +115 -0
- data/lib/rubylisp/prim_assignment.rb +61 -0
- data/lib/rubylisp/prim_character.rb +273 -0
- data/lib/rubylisp/{ffi_class.rb → prim_class_object.rb} +16 -69
- data/lib/rubylisp/prim_environment.rb +203 -0
- data/lib/rubylisp/prim_equivalence.rb +93 -0
- data/lib/rubylisp/prim_frame.rb +166 -0
- data/lib/rubylisp/prim_io.rb +266 -0
- data/lib/rubylisp/prim_list_support.rb +496 -0
- data/lib/rubylisp/{logical.rb → prim_logical.rb} +9 -14
- data/lib/rubylisp/prim_math.rb +397 -0
- data/lib/rubylisp/prim_native_object.rb +21 -0
- data/lib/rubylisp/prim_relational.rb +42 -0
- data/lib/rubylisp/{special_forms.rb → prim_special_forms.rb} +97 -84
- data/lib/rubylisp/prim_string.rb +792 -0
- data/lib/rubylisp/prim_system.rb +55 -0
- data/lib/rubylisp/prim_type_checks.rb +58 -0
- data/lib/rubylisp/prim_vector.rb +497 -0
- data/lib/rubylisp/primitive.rb +51 -6
- data/lib/rubylisp/string.rb +4 -803
- data/lib/rubylisp/symbol.rb +0 -1
- data/lib/rubylisp/tokenizer.rb +160 -136
- data/lib/rubylisp/vector.rb +10 -31
- data/lib/rubymotion/debug.rb +40 -0
- data/lib/rubymotion/require-fix.rb +1 -0
- data/lib/rubymotionlisp.rb +4 -0
- metadata +28 -17
- data/lib/rubylisp/alist.rb +0 -230
- data/lib/rubylisp/assignment.rb +0 -65
- data/lib/rubylisp/equivalence.rb +0 -118
- data/lib/rubylisp/io.rb +0 -74
- data/lib/rubylisp/list_support.rb +0 -526
- data/lib/rubylisp/math.rb +0 -405
- data/lib/rubylisp/motion_builtins.rb +0 -31
- data/lib/rubylisp/relational.rb +0 -46
- data/lib/rubylisp/system.rb +0 -20
- data/lib/rubylisp/testing.rb +0 -136
- data/lib/rubylisp/type_checks.rb +0 -60
data/lib/rubylisp/frame.rb
CHANGED
@@ -2,172 +2,13 @@ module Lisp
|
|
2
2
|
|
3
3
|
class Frame < Atom
|
4
4
|
|
5
|
-
def self.register
|
6
|
-
Primitive.register("make-frame", "(make-frame slot-name slot-value ... )\n\nFrames can be created using the make-frame function, passing it an alternating sequence of slot names and values:\n\n (make-frame a: 1 b: 2)\n\nThis results in a frame with two slots, named a: and b: with values 1 and 2, respectively.") do |args, env|
|
7
|
-
Lisp::Frame::make_frame_impl(args, env)
|
8
|
-
end
|
9
|
-
|
10
|
-
Primitive.register("has-slot?", "(has-slot? frame slot-name)\n\nThe has-slot? function is used to query whether a frame contains (directly or in an ancestor) the particular slot.") do |args, env|
|
11
|
-
Lisp::Frame::has_slot_impl(args, env)
|
12
|
-
end
|
13
|
-
|
14
|
-
Primitive.register("get-slot", "(get-slot _frame_ _slot-name_)\n\nThe get-slot function is used to retrieve values from frame slots") do |args, env|
|
15
|
-
Lisp::Frame::get_slot_impl(args, env)
|
16
|
-
end
|
17
|
-
|
18
|
-
Primitive.register("get-slot-if", "(get-slot-if frame slot-name)\n\nThe same as above, except that if a matching slot is not found, nil is returned instead of raising an error.") do |args, env|
|
19
|
-
Lisp::Frame::get_slot_if_impl(args, env)
|
20
|
-
end
|
21
|
-
|
22
|
-
Primitive.register("remove-slot!", "(remove-slot! frame slot-name)\n\nThe remove-slot! function is used to function is used to remove a slot from a frame. It only removes slots from the frame itself. not any of it's parents. remove-slot! return #t if the slot was removed, #f otherwise.") do |args, env|
|
23
|
-
Lisp::Frame::remove_slot_impl(args, env)
|
24
|
-
end
|
25
|
-
|
26
|
-
Primitive.register("set-slot!", "(set-slot! frame slot-name new-value)\n\nThe set-slot! function is used to change values in frame slots") do |args, env|
|
27
|
-
Lisp::Frame::set_slot_impl(args, env)
|
28
|
-
end
|
29
|
-
|
30
|
-
Primitive.register("send", "(send frame slot-name arg...)\n\nSend the message slot-name to frame, passing along the arg collection. The result is what is returned by the code in that slot.") do |args, env|
|
31
|
-
Lisp::Frame::send_impl(args, env)
|
32
|
-
end
|
33
|
-
|
34
|
-
Primitive.register("send-super", "**(send-super slot-name arg...)\n\nLike send, but sends to the first parent that has the named slot. send-super can only be used from within a frame.") do |args, env|
|
35
|
-
Lisp::Frame::send_super_impl(args, env)
|
36
|
-
end
|
37
|
-
|
38
|
-
Primitive.register("clone", "(clone frame)\n\nFrames represent things. For example, you could use a frame that looks like {x: 1 y: 10} to represent a point. A system that would use point frames will typically need many independant points. The approach to this is to create a prototypical point data frame, and use the clone function to create individual, independant frames.") do |args, env|
|
39
|
-
Lisp::Frame::clone_impl(args, env)
|
40
|
-
end
|
41
|
-
|
42
|
-
Primitive.register("keys", "(keys frame)\n\nReturn a list of the keys in the frame.") do |args, env|
|
43
|
-
Lisp::Frame::keys_impl(args, env)
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
def self.make_frame_impl(args, env)
|
50
|
-
c = args
|
51
|
-
m = {}
|
52
|
-
while !c.nil?
|
53
|
-
k = c.car
|
54
|
-
return Lisp::Debug.process_error("Slot names must be a symbol, found a {k.type}.", env) unless k.symbol?
|
55
|
-
return Lisp::Debug.process_error("Slot names must end in a colon, found '#{k}'.", env) unless k.naked?
|
56
|
-
v = c.cadr.evaluate(env)
|
57
|
-
m[k] = v
|
58
|
-
c = c.cddr
|
59
|
-
end
|
60
|
-
|
61
|
-
Lisp::Frame.with_map(m)
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
def self.has_slot_impl(args, env)
|
66
|
-
frame = args.car.evaluate(env)
|
67
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
68
|
-
key = args.cadr.evaluate(env)
|
69
|
-
return Lisp::Debug.process_error("Frame key must be a symbol but was #{key.type}.", env) unless key.symbol?
|
70
|
-
return Lisp::TRUE if frame.has_slot?(key)
|
71
|
-
Lisp::FALSE
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
def self.get_slot_impl(args, env)
|
76
|
-
frame = args.car.evaluate(env)
|
77
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
78
|
-
key = args.cadr.evaluate(env)
|
79
|
-
return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
|
80
|
-
return Lisp::Debug.process_error("Frame key (#{key.to_s}) must name an existing slot.", env) unless frame.has_slot?(key)
|
81
|
-
frame.get(key)
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
def self.get_slot_if_impl(args, env)
|
86
|
-
frame = args.car.evaluate(env)
|
87
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
88
|
-
key = args.cadr.evaluate(env)
|
89
|
-
return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
|
90
|
-
frame.get(key)
|
91
|
-
end
|
92
|
-
|
93
|
-
|
94
|
-
def self.remove_slot_impl(args, env)
|
95
|
-
frame = args.car.evaluate(env)
|
96
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
97
|
-
key = args.cadr.evaluate(env)
|
98
|
-
return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
|
99
|
-
return Lisp::TRUE if frame.remove(key)
|
100
|
-
Lisp::FALSE
|
101
|
-
end
|
102
|
-
|
103
|
-
|
104
|
-
def self.set_slot_impl(args, env)
|
105
|
-
frame = args.car.evaluate(env)
|
106
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
107
|
-
key = args.cadr.evaluate(env)
|
108
|
-
return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
|
109
|
-
value = args.caddr.evaluate(env)
|
110
|
-
frame.at_put(key, value)
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
def self.send_impl(args, env)
|
115
|
-
frame = args.car.evaluate(env)
|
116
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
117
|
-
selector = args.cadr.evaluate(env)
|
118
|
-
return Lisp::Debug.process_error("Selector must be a symbol but was #{selector.type}.", env) unless selector.symbol?
|
119
|
-
return Lisp::Debug.process_error("Message sent must name an existing slot in the receiver.", env) unless frame.has_slot?(selector)
|
120
|
-
func = frame.get(selector)
|
121
|
-
return Lisp::Debug.process_error("Message sent must select a function slot but was #{func.type}.", env) unless func.function?
|
122
|
-
params = args.cddr
|
123
|
-
frame_env = Lisp::EnvironmentFrame.extending(env, frame)
|
124
|
-
frame_env.bind_locally(Symbol.named("self"), frame)
|
125
|
-
func.apply_to(params, frame_env)
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.get_super_function(selector, env)
|
129
|
-
f = env.frame
|
130
|
-
return nil if f.nil?
|
131
|
-
f.parents.each do |p|
|
132
|
-
func = p.get(selector)
|
133
|
-
return func unless func.nil?
|
134
|
-
end
|
135
|
-
nil
|
136
|
-
end
|
137
|
-
|
138
|
-
def self.send_super_impl(args, env)
|
139
|
-
return Lisp::Debug.process_error("super can only be used within the context of a frame.", env) unless env.frame
|
140
|
-
selector = args.car.evaluate(env)
|
141
|
-
return Lisp::Debug.process_error("Selector must be a symbol but was #{selector.type}.", env) unless selector.symbol?
|
142
|
-
func = get_super_function(selector, env)
|
143
|
-
return Lisp::Debug.process_error("Message sent must select a function slot but was #{func.type}.", env) unless func && func.function?
|
144
|
-
params = args.cdr
|
145
|
-
frame_env = Lisp::EnvironmentFrame.extending(env, env.frame)
|
146
|
-
frame_env.bind_locally(Symbol.named("self"), env.frame)
|
147
|
-
func.apply_to(params, frame_env)
|
148
|
-
end
|
149
|
-
|
150
|
-
|
151
|
-
def self.clone_impl(args, env)
|
152
|
-
frame = args.car.evaluate(env)
|
153
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
154
|
-
frame.clone
|
155
|
-
end
|
156
|
-
|
157
|
-
|
158
|
-
def self.keys_impl(args, env)
|
159
|
-
frame = args.car.evaluate(env)
|
160
|
-
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
161
|
-
ConsCell.array_to_list(frame.value.keys)
|
162
|
-
end
|
163
|
-
|
164
|
-
|
165
5
|
def self.with_map(m)
|
166
6
|
self.new(m)
|
167
7
|
end
|
168
8
|
|
169
|
-
def initialize(m=
|
170
|
-
@value = m
|
9
|
+
def initialize(m = {})
|
10
|
+
@value = m
|
11
|
+
self
|
171
12
|
end
|
172
13
|
|
173
14
|
|
@@ -285,11 +126,11 @@ module Lisp
|
|
285
126
|
nil
|
286
127
|
end
|
287
128
|
|
288
|
-
def
|
129
|
+
def equal?(other)
|
289
130
|
return false unless other.frame?
|
290
131
|
return false unless @value.length == other.value.length
|
291
132
|
@value.each do |k, v|
|
292
|
-
return false unless
|
133
|
+
return false unless other.value[k].equal?(v)
|
293
134
|
end
|
294
135
|
true
|
295
136
|
end
|
data/lib/rubylisp/function.rb
CHANGED
@@ -2,7 +2,7 @@ module Lisp
|
|
2
2
|
|
3
3
|
class Function < Atom
|
4
4
|
|
5
|
-
attr_reader :doc, :arity, :name
|
5
|
+
attr_reader :doc, :arity, :name, :env, :body
|
6
6
|
|
7
7
|
def compute_required_argument_count(args)
|
8
8
|
a = args
|
@@ -37,10 +37,11 @@ module Lisp
|
|
37
37
|
if @var_args
|
38
38
|
return Lisp::Debug.process_error("#{@name} expected at least #{@arity} parameters, received #{parameters.length}.", env) if parameters.length < @arity
|
39
39
|
else
|
40
|
+
puts "#{@name} #{@arguments.print_string} #{@body.print_string}" unless parameters.length == @arity
|
41
|
+
puts caller unless parameters.length == @arity
|
40
42
|
return Lisp::Debug.process_error("#{@name} expected #{@arity} parameters, received #{parameters.length}.", env) unless parameters.length == @arity
|
41
43
|
end
|
42
|
-
|
43
|
-
local_env = EnvironmentFrame.extending(@env, env.frame)
|
44
|
+
local_env = EnvironmentFrame.extending(@env, @name, env.frame)
|
44
45
|
local_env.previous = env
|
45
46
|
self_sym = Symbol.named("self")
|
46
47
|
if env.frame
|
data/lib/rubylisp/macro.rb
CHANGED
@@ -2,7 +2,7 @@ module Lisp
|
|
2
2
|
|
3
3
|
class Macro < Atom
|
4
4
|
|
5
|
-
attr_reader :doc
|
5
|
+
attr_reader :name, :doc, :body
|
6
6
|
|
7
7
|
def compute_required_argument_count(args)
|
8
8
|
a = args
|
@@ -20,6 +20,7 @@ module Lisp
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize(name, arguments, doc, body, env)
|
23
|
+
#puts "Macro#initialize #{name} #{arguments.to_a}"
|
23
24
|
sig = ([name] << arguments.to_a).flatten
|
24
25
|
@doc = "(#{(sig.collect {|e| e.to_s}).join(" ")})"
|
25
26
|
@name = name
|
@@ -33,14 +34,12 @@ module Lisp
|
|
33
34
|
|
34
35
|
def expand(parameters, env, should_eval)
|
35
36
|
if @var_args
|
36
|
-
return Lisp::Debug.process_error("#{@name} expected at least
|
37
|
-
##{@required_argument_count} parameters, received #{parameters.length}.", env) if parameters.length < @required_argument_count
|
37
|
+
return Lisp::Debug.process_error("#{@name} expected at least #{@required_argument_count} parameters, received #{parameters.length}.", env) if parameters.length < @required_argument_count
|
38
38
|
else
|
39
|
-
return Lisp::Debug.process_error("#{@name} expected
|
40
|
-
##{@required_argument_count} parameters, received #{parameters.length}.", env) unless parameters.length == @required_argument_count
|
39
|
+
return Lisp::Debug.process_error("#{@name} expected #{@required_argument_count} parameters, received #{parameters.length}.", env) unless parameters.length == @required_argument_count
|
41
40
|
end
|
42
41
|
|
43
|
-
local_env = EnvironmentFrame.extending(@env, env.frame)
|
42
|
+
local_env = EnvironmentFrame.extending(@env, @name, env.frame)
|
44
43
|
self_sym = Symbol.named("self")
|
45
44
|
if env.frame
|
46
45
|
local_env.bind_locally(self_sym, env.frame)
|
@@ -63,8 +62,14 @@ module Lisp
|
|
63
62
|
accumulating_arg = arg if arg.symbol?
|
64
63
|
end
|
65
64
|
local_env.bind_locally(accumulating_arg, Lisp::ConsCell.array_to_list(accumulated_params)) if accumulating_arg
|
65
|
+
|
66
|
+
#puts "expanding #{@name}"
|
67
|
+
#puts " #{@body.print_string}"
|
66
68
|
|
67
|
-
@body.evaluate(local_env)
|
69
|
+
result = @body.evaluate(local_env)
|
70
|
+
|
71
|
+
#puts " #{result.print_string}"
|
72
|
+
result
|
68
73
|
end
|
69
74
|
|
70
75
|
def internal_apply_to(parameters, env, should_eval)
|
@@ -91,7 +96,7 @@ module Lisp
|
|
91
96
|
def type
|
92
97
|
:macro
|
93
98
|
end
|
94
|
-
|
99
|
+
|
95
100
|
end
|
96
101
|
|
97
102
|
end
|
@@ -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)
|
data/lib/rubylisp/number.rb
CHANGED
data/lib/rubylisp/parser.rb
CHANGED
@@ -10,7 +10,7 @@ module Lisp
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def make_hex_number(str)
|
13
|
-
Lisp::Number.with_value(
|
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
|
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
|
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}",
|
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}",
|
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
|
-
|
60
|
+
Lisp::ConsCell.array_to_list(cells)
|
61
61
|
end
|
62
62
|
|
63
|
-
def
|
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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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 == :
|
96
|
+
if tok == :RPAREN
|
88
97
|
tokens.consume_token
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
128
|
-
when :
|
129
|
-
return
|
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.
|
164
|
-
tokenizer
|
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.
|
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
|