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
@@ -0,0 +1,93 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class PrimEquivalence
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("=", "2", "(= n1 n2)\n\nEquivalent to (eqv? n1 n2)") do |args, env|
|
7
|
+
Lisp::PrimEquivalence::eqv_impl(args, env)
|
8
|
+
end
|
9
|
+
|
10
|
+
Primitive.register("==", "2", "(== n1 n2)\n\nEquivalent to (eqv? n1 n2)") do |args, env|
|
11
|
+
Lisp::PrimEquivalence::eqv_impl(args, env)
|
12
|
+
end
|
13
|
+
|
14
|
+
Primitive.register("!=", "2", "(!= n1 n2)\n\nEquivalent to (neqv? n1 n2).") do |args, env|
|
15
|
+
Lisp::PrimEquivalence::neqv_impl(args, env)
|
16
|
+
end
|
17
|
+
|
18
|
+
Primitive.register("/=", "2", "(/= n1 n2)\n\nEquivalent to (neqv? n1 n2).") do |args, env|
|
19
|
+
Lisp::PrimEquivalence::neqv_impl(args, env)
|
20
|
+
end
|
21
|
+
|
22
|
+
Primitive.register("eq?", "2") do |args, env|
|
23
|
+
Lisp::PrimEquivalence::eq_impl(args, env)
|
24
|
+
end
|
25
|
+
|
26
|
+
Primitive.register("neq?", "2") do |args, env|
|
27
|
+
Lisp::PrimEquivalence::neq_impl(args, env)
|
28
|
+
end
|
29
|
+
|
30
|
+
Primitive.register("eqv?", "2") do |args, env|
|
31
|
+
Lisp::PrimEquivalence::eqv_impl(args, env)
|
32
|
+
end
|
33
|
+
|
34
|
+
Primitive.register("neqv?", "2") do |args, env|
|
35
|
+
Lisp::PrimEquivalence::eqv_impl(args, env)
|
36
|
+
end
|
37
|
+
|
38
|
+
Primitive.register("equal?", "2") do |args, env|
|
39
|
+
Lisp::PrimEquivalence::equal_impl(args, env)
|
40
|
+
end
|
41
|
+
|
42
|
+
Primitive.register("nequal?", "2") do |args, env|
|
43
|
+
Lisp::PrimEquivalence::nequal_impl(args, env)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def self.eqv_impl(args, env)
|
50
|
+
o1 = args.car
|
51
|
+
o2 = args.cadr
|
52
|
+
Lisp::Boolean.with_value(o1.eqv?(o2))
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def self.neqv_impl(args, env)
|
57
|
+
o1 = args.car
|
58
|
+
o2 = args.cadr
|
59
|
+
Lisp::Boolean.with_value(!o1.eqv?(o2))
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def self.eq_impl(args, env)
|
64
|
+
o1 = args.car
|
65
|
+
o2 = args.cadr
|
66
|
+
Lisp::Boolean.with_value(o1.eq?(o2))
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def self.neq_impl(args, env)
|
71
|
+
o1 = args.car
|
72
|
+
o2 = args.cadr
|
73
|
+
Lisp::Boolean.with_value(!o1.eq?(o2))
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def self.equal_impl(args, env)
|
78
|
+
o1 = args.car
|
79
|
+
o2 = args.cadr
|
80
|
+
Lisp::Boolean.with_value(o1.equal?(o2))
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def self.nequal_impl(args, env)
|
85
|
+
o1 = args.car
|
86
|
+
o2 = args.cadr
|
87
|
+
Lisp::Boolean.with_value(!o1.equal?(o2))
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class PrimFrame
|
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::PrimFrame::make_frame_impl(args, env)
|
8
|
+
end
|
9
|
+
|
10
|
+
Primitive.register("has-slot?", "2", "(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::PrimFrame::has_slot_impl(args, env)
|
12
|
+
end
|
13
|
+
|
14
|
+
Primitive.register("get-slot", "2", "(get-slot _frame_ _slot-name_)\n\nThe get-slot function is used to retrieve values from frame slots") do |args, env|
|
15
|
+
Lisp::PrimFrame::get_slot_impl(args, env)
|
16
|
+
end
|
17
|
+
|
18
|
+
Primitive.register("get-slot-if", "2", "(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::PrimFrame::get_slot_if_impl(args, env)
|
20
|
+
end
|
21
|
+
|
22
|
+
Primitive.register("remove-slot!", "2", "(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::PrimFrame::remove_slot_impl(args, env)
|
24
|
+
end
|
25
|
+
|
26
|
+
Primitive.register("set-slot!", "3", "(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::PrimFrame::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::PrimFrame::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::PrimFrame::send_super_impl(args, env)
|
36
|
+
end
|
37
|
+
|
38
|
+
Primitive.register("clone", "1", "(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::PrimFrame::clone_impl(args, env)
|
40
|
+
end
|
41
|
+
|
42
|
+
Primitive.register("keys", "1", "(keys frame)\n\nReturn a list of the keys in the frame.") do |args, env|
|
43
|
+
Lisp::PrimFrame::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
|
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
|
67
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
68
|
+
key = args.cadr
|
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
|
77
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
78
|
+
key = args.cadr
|
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
|
87
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
88
|
+
key = args.cadr
|
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
|
96
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
97
|
+
key = args.cadr
|
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
|
106
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
107
|
+
key = args.cadr
|
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
|
110
|
+
frame.at_put(key, value)
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def self.send_impl(args, env)
|
115
|
+
frame = args.car
|
116
|
+
return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
|
117
|
+
selector = args.cadr
|
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, selector.to_s, 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
|
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, selector.to_s, 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
|
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
|
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
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module Lisp
|
2
|
+
|
3
|
+
class PrimIo
|
4
|
+
|
5
|
+
def self.register
|
6
|
+
Primitive.register("load", "1") {|args, env| Lisp::PrimIo::load_impl(args, env) }
|
7
|
+
Primitive.register("open-input-file", "1") {|args, env| Lisp::PrimIo::open_input_file_impl(args, env) }
|
8
|
+
Primitive.register("open-output-file", "1|2") {|args, env| Lisp::PrimIo::open_output_file_impl(args, env) }
|
9
|
+
Primitive.register("close-port", "1") {|args, env| Lisp::PrimIo::close_port_impl(args, env) }
|
10
|
+
Primitive.register("write-string", "1|2") {|args, env| Lisp::PrimIo::write_string_impl(args, env) }
|
11
|
+
Primitive.register("newline", "0|1") {|args, env| Lisp::PrimIo::newline_impl(args, env) }
|
12
|
+
Primitive.register("write", "1|2") {|args, env| Lisp::PrimIo::write_impl(args, env) }
|
13
|
+
Primitive.register("read", "0|1") {|args, env| Lisp::PrimIo::read_impl(args, env) }
|
14
|
+
Primitive.register("list-directory", "1|2") {|args, env| Lisp::PrimIo::list_directory_impl(args, env) }
|
15
|
+
Primitive.register("eof-object?", "1") {|args, env| Lisp::PrimIo::eof_objectp_impl(args, env) }
|
16
|
+
Primitive.register("format", ">=2") {|args, env| Lisp::PrimIo::format_impl(args, env) }
|
17
|
+
# Primitive.register("load-library", "1") {|args, env| Lisp::PrimIo::load_library_impl(args, env) }
|
18
|
+
# Primitive.register("load-project", "1") {|args, env| Lisp::PrimIo::load_project_impl(args, env) }
|
19
|
+
Primitive.register("trace", "*") {|args, env| puts "Trace: #{(args.to_a.map {|a| a.value.to_s}).join(' ')}"; nil}
|
20
|
+
Primitive.register("error", "*") {|args, env| App.alert((args.to_a.map {|a| a.value.to_s}).join(' '))}
|
21
|
+
Primitive.register("alert", "*") {|args, env| App.alert((args.to_a.map {|a| a.value.to_s}).join(' '))}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def self.load_impl(args, env)
|
26
|
+
fname = args.car
|
27
|
+
return Lisp::Debug.process_error("'load' requires a string argument.", env) unless fname.string?
|
28
|
+
filename = fname.value.end_with?(".lsp") ? fname.value : "#{fname.value}.lsp"
|
29
|
+
Lisp::Parser.new.process_file(filename)
|
30
|
+
Lisp::String.with_value("OK")
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.open_input_file_impl(args, env)
|
35
|
+
fname = args.car
|
36
|
+
return Lisp::Debug.process_error("'open-input-file' requires a string argument.", env) unless fname.string?
|
37
|
+
f = File.open(fname.value, "r")
|
38
|
+
f ? Lisp::Port.with_value(f) : nil
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
def self.open_output_file_impl(args, env)
|
43
|
+
fname = args.car
|
44
|
+
return Lisp::Debug.process_error("'load' requires a string argument.", env) unless fname.string?
|
45
|
+
mode = (args.length == 2 && args.cadr.true?) ? "a" : "w"
|
46
|
+
f = File.open(fname.value, mode)
|
47
|
+
f ? Lisp::Port.with_value(f) : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def self.close_port_impl(args, env)
|
52
|
+
p = args.car
|
53
|
+
return Lisp::Debug.process_error("'close-port' requires a port argument.", env) unless p.port?
|
54
|
+
p.value.close
|
55
|
+
Lisp::String.with_value("OK")
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def self.write_string_impl(args, env)
|
60
|
+
s = args.car
|
61
|
+
return Lisp::Debug.process_error("'write-string' requires a string first argument.", env) unless s.string?
|
62
|
+
|
63
|
+
if args.length == 2
|
64
|
+
p = args.cadr
|
65
|
+
return Lisp::Debug.process_error("'write-string' requires a port as it's second argument.", env) unless p.port?
|
66
|
+
port = p.value
|
67
|
+
else
|
68
|
+
port = $stdout
|
69
|
+
end
|
70
|
+
|
71
|
+
port.write(s.value)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def self.newline_impl(args, env)
|
76
|
+
if args.length == 1
|
77
|
+
p = args.car
|
78
|
+
return Lisp::Debug.process_error("'newline' requires a port as it's argument.", env) unless p.port?
|
79
|
+
port = p.value
|
80
|
+
else
|
81
|
+
port = $stdout
|
82
|
+
end
|
83
|
+
|
84
|
+
port.write("\n")
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
def self.write_impl(args, env)
|
89
|
+
if args.length == 2
|
90
|
+
p = args.cadr
|
91
|
+
return Lisp::Debug.process_error("'write' requires a port as it's second argument.", env) unless p.port?
|
92
|
+
port = p.value
|
93
|
+
else
|
94
|
+
port = $stdout
|
95
|
+
end
|
96
|
+
|
97
|
+
port.write(args.car.print_string)
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
def self.read_impl(args, env)
|
102
|
+
if args.length == 1
|
103
|
+
p = args.car
|
104
|
+
return Lisp::Debug.process_error("'read' requires a port as it's argument.", env) unless p.port?
|
105
|
+
port = p.value
|
106
|
+
else
|
107
|
+
port = $stdin
|
108
|
+
end
|
109
|
+
|
110
|
+
Lisp::Parser.new.parse_object_from_file(port)
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def self.list_directory_impl(args, env)
|
115
|
+
return Lisp::Debug.process_error("'list-directory' requires a string as it's first argument.", env) unless args.car.string?
|
116
|
+
dir = args.car.value
|
117
|
+
fpart = (args.length == 2) ? args.cadr.value : "*"
|
118
|
+
filenames = Dir.glob(File.join(dir, fpart))
|
119
|
+
Lisp::ConsCell.array_to_list(filenames.map {|f| Lisp::String.with_value(f)})
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
def self.eof_objectp_impl(args, env)
|
124
|
+
Boolean.with_value(args.car.eof_object?)
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def self.format_impl(args, env)
|
129
|
+
destination = args.car
|
130
|
+
return Lisp::Debug.process_error("'format' requires a port or boolean as it's first argument.", env) unless destination.port? || destination.boolean?
|
131
|
+
|
132
|
+
control_string_obj = args.cadr
|
133
|
+
return Lisp::Debug.process_error("'format' requires a string as it's second argument.", env) unless control_string_obj.string?
|
134
|
+
control_string = control_string_obj.value
|
135
|
+
|
136
|
+
arguments = args.cddr
|
137
|
+
|
138
|
+
number_of_substitutions = control_string.count('~')
|
139
|
+
parts = []
|
140
|
+
start = 0
|
141
|
+
i = 0
|
142
|
+
numeric_arg = 0
|
143
|
+
at_modifier = false
|
144
|
+
|
145
|
+
while i < control_string.length
|
146
|
+
numeric_arg = 0
|
147
|
+
at_modifier = false
|
148
|
+
|
149
|
+
if control_string[i] == '~'
|
150
|
+
parts << control_string[start...i]
|
151
|
+
i += 1
|
152
|
+
start = i
|
153
|
+
i += 1 while '0123456789'.include?(control_string[i])
|
154
|
+
if i == start
|
155
|
+
if control_string[i] == '#'
|
156
|
+
numeric_arg = arguments.length
|
157
|
+
i += 1
|
158
|
+
elsif 'vV'.include?(control_string[i])
|
159
|
+
if arguments.car.number?
|
160
|
+
numeric_arg = arguments.car.value
|
161
|
+
arguments = arguments.cdr
|
162
|
+
else
|
163
|
+
return Lisp::Debug.process_error("'format' encountered a size argument mismatch at index #{i}.", env)
|
164
|
+
end
|
165
|
+
i += 1
|
166
|
+
else
|
167
|
+
numeric_arg = 0
|
168
|
+
end
|
169
|
+
else
|
170
|
+
numeric_arg = control_string[start...i].to_i
|
171
|
+
end
|
172
|
+
if control_string[i] == '@'
|
173
|
+
at_modifier = true
|
174
|
+
i += 1
|
175
|
+
end
|
176
|
+
|
177
|
+
case control_string[i]
|
178
|
+
when 'A', 'a', 'S', 's'
|
179
|
+
substitution = ('Aa'.include?(control_string[i])) ? arguments.car.print_string : arguments.car.to_s
|
180
|
+
padding = substitution.length < numeric_arg ? (" " * (numeric_arg - substitution.length)) : ""
|
181
|
+
parts << padding if at_modifier
|
182
|
+
parts << substitution
|
183
|
+
parts << padding unless at_modifier
|
184
|
+
arguments = arguments.cdr
|
185
|
+
start = i + 1
|
186
|
+
when '%'
|
187
|
+
parts << ((numeric_arg > 0) ? ("\n" * numeric_arg) : "\n")
|
188
|
+
start = i + 1
|
189
|
+
when '~'
|
190
|
+
parts << ((numeric_arg > 0) ? ("~" * numeric_arg) : "~")
|
191
|
+
start = i + 1
|
192
|
+
when "\n"
|
193
|
+
while control_string[i] =~ /[[:space:]]/
|
194
|
+
i += 1
|
195
|
+
end
|
196
|
+
parts << "\n" if at_modifier
|
197
|
+
start = i
|
198
|
+
i -= 1
|
199
|
+
else
|
200
|
+
return Lisp::Debug.process_error("'format' encountered an unsupported substitution at index #{i}.", env)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
i += 1
|
204
|
+
end
|
205
|
+
parts << control_string[start..i] if start < control_string.length
|
206
|
+
return Lisp::Debug.process_error("'format' found a mismatch in the number of substitutions and arguments.", env) if i < control_string.length || !arguments.nil?
|
207
|
+
|
208
|
+
combined_string = parts.join
|
209
|
+
|
210
|
+
if destination.port?
|
211
|
+
destination.value.write(combined_string)
|
212
|
+
elsif destination.value
|
213
|
+
$stdout.write(combined_string)
|
214
|
+
else
|
215
|
+
return Lisp::String.with_value(combined_string)
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
|
221
|
+
# def self.load_library_impl(args, env)
|
222
|
+
# library_name = args.car
|
223
|
+
# return Lisp::Debug.process_error("'load-library' requires a string or symbol argument.", env) unless library_name.string? || library_name.symbol?
|
224
|
+
# Dir.chdir(File.join(App.documents_path, "libraries", "#{library_name}.lib")) do |d|
|
225
|
+
# if File.exists?("load.lsp")
|
226
|
+
# File.open("load.lsp") do |f|
|
227
|
+
# contents = f.read()
|
228
|
+
# Lisp::Parser.new.parse_and_eval_all(contents)
|
229
|
+
# end
|
230
|
+
# else
|
231
|
+
# Dir.glob("*.lsp") do |filename|
|
232
|
+
# File.open(filename) do |f|
|
233
|
+
# contents = f.read()
|
234
|
+
# Lisp::Parser.new.parse_and_eval_all(contents)
|
235
|
+
# end
|
236
|
+
# end
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
# Lisp::String.with_value("OK")
|
240
|
+
# end
|
241
|
+
|
242
|
+
|
243
|
+
# def self.load_project_impl(args, env)
|
244
|
+
# project_name = args.car
|
245
|
+
# return Lisp::Debug.process_error("'load-project' requires a string or symbol argument.", env) unless project_name.string? || project_name.symbol?
|
246
|
+
# Dir.chdir(File.join(App.documents_path, "projects", "#{project_name}.prj")) do |d|
|
247
|
+
# if File.exists?("load.lsp")
|
248
|
+
# File.open("load.lsp") do |f|
|
249
|
+
# contents = f.read()
|
250
|
+
# Lisp::Parser.new.parse_and_eval_all(contents)
|
251
|
+
# end
|
252
|
+
# else
|
253
|
+
# Dir.glob("*.lsp") do |filename|
|
254
|
+
# File.open(filename) do |f|
|
255
|
+
# contents = f.read()
|
256
|
+
# Lisp::Parser.new.parse_and_eval_all(contents)
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
# Lisp::String.with_value("OK")
|
262
|
+
# end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
end
|