Class: Lisp::Frame
Instance Attribute Summary
Attributes inherited from Atom
Class Method Summary collapse
- .clone_impl(args, env) ⇒ Object
- .get_slot_if_impl(args, env) ⇒ Object
- .get_slot_impl(args, env) ⇒ Object
- .get_super_function(selector, env) ⇒ Object
- .has_slot_impl(args, env) ⇒ Object
- .make_frame_impl(args, env) ⇒ Object
- .register ⇒ Object
- .remove_slot_impl(args, env) ⇒ Object
- .send_impl(args, env) ⇒ Object
- .send_super_impl(args, env) ⇒ Object
- .set_slot_impl(args, env) ⇒ Object
- .with_map(m) ⇒ Object
Instance Method Summary collapse
- #at_put(key, value) ⇒ Object
- #car ⇒ Object
- #cdr ⇒ Object
- #clone ⇒ Object
- #empty? ⇒ Boolean
- #eq?(other) ⇒ Boolean
- #frame? ⇒ Boolean
- #get(key) ⇒ Object
- #has_parent_slots? ⇒ Boolean
- #has_slot?(n) ⇒ Boolean
- #has_slot_locally?(n) ⇒ Boolean
- #inherited_value_slots ⇒ Object
-
#initialize(m = nil) ⇒ Frame
constructor
A new instance of Frame.
- #is_parent_key(k) ⇒ Object
- #length ⇒ Object
- #lisp_object? ⇒ Boolean
- #local_slots ⇒ Object
- #parent_slots ⇒ Object
- #parents ⇒ Object
- #remove(key) ⇒ Object
- #to_s ⇒ Object
- #type ⇒ Object
Methods inherited from Atom
#alist?, #all?, #apply_to, #character?, #class?, #copy, #doc, #evaluate, #false?, #function?, #list?, #macro?, #negative?, #number?, #object?, #pair?, #positive?, #primitive?, #print_string, #quoted, #set!, #special?, #string?, #symbol?, #true?, #vector?, #zero?
Constructor Details
#initialize(m = nil) ⇒ Frame
Returns a new instance of Frame.
158 159 160 |
# File 'lib/rubylisp/frame.rb', line 158 def initialize(m=nil) @value = m || {} end |
Class Method Details
.clone_impl(args, env) ⇒ Object
147 148 149 150 151 |
# File 'lib/rubylisp/frame.rb', line 147 def self.clone_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? frame.clone end |
.get_slot_if_impl(args, env) ⇒ Object
81 82 83 84 85 86 87 |
# File 'lib/rubylisp/frame.rb', line 81 def self.get_slot_if_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? key = args.cadr.evaluate(env) raise "Frame key (#{key.to_s}) must be a symbol but was #{key.type}." unless key.symbol? frame.get(key) end |
.get_slot_impl(args, env) ⇒ Object
71 72 73 74 75 76 77 78 |
# File 'lib/rubylisp/frame.rb', line 71 def self.get_slot_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? key = args.cadr.evaluate(env) raise "Frame key (#{key.to_s}) must be a symbol but was #{key.type}." unless key.symbol? raise "Frame key (#{key.to_s}) must name an existing slot." unless frame.has_slot?(key) frame.get(key) end |
.get_super_function(selector, env) ⇒ Object
124 125 126 127 128 129 130 131 132 |
# File 'lib/rubylisp/frame.rb', line 124 def self.get_super_function(selector, env) f = env.frame return nil if f.nil? f.parents.each do |p| func = p.get(selector) return func unless func.nil? end nil end |
.has_slot_impl(args, env) ⇒ Object
61 62 63 64 65 66 67 68 |
# File 'lib/rubylisp/frame.rb', line 61 def self.has_slot_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? key = args.cadr.evaluate(env) raise "Frame key must be a symbol but was #{key.type}." unless key.symbol? return Lisp::TRUE if frame.has_slot?(key) Lisp::FALSE end |
.make_frame_impl(args, env) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/rubylisp/frame.rb', line 45 def self.make_frame_impl(args, env) c = args m = {} while !c.nil? k = c.car raise "Slot names must be a symbol, found a {k.type}." unless k.symbol? raise "Slot names must end in a colon, found '#{k}'." unless k.naked? v = c.cadr.evaluate(env) m[k] = v c = c.cddr end Lisp::Frame.with_map(m) end |
.register ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/rubylisp/frame.rb', line 5 def self.register 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| Lisp::Frame::make_frame_impl(args, env) end 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| Lisp::Frame::has_slot_impl(args, env) end 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| Lisp::Frame::get_slot_impl(args, env) end 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| Lisp::Frame::get_slot_if_impl(args, env) end 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| Lisp::Frame::remove_slot_impl(args, env) end 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| Lisp::Frame::set_slot_impl(args, env) end 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| Lisp::Frame::send_impl(args, env) end 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| Lisp::Frame::send_super_impl(args, env) end 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| Lisp::Frame::clone_impl(args, env) end end |
.remove_slot_impl(args, env) ⇒ Object
90 91 92 93 94 95 96 97 |
# File 'lib/rubylisp/frame.rb', line 90 def self.remove_slot_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? key = args.cadr.evaluate(env) raise "Frame key (#{key.to_s}) must be a symbol but was #{key.type}." unless key.symbol? return Lisp::TRUE if frame.remove(key) Lisp::FALSE end |
.send_impl(args, env) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/rubylisp/frame.rb', line 110 def self.send_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? selector = args.cadr.evaluate(env) raise "Selector must be a symbol but was #{selector.type}." unless selector.symbol? raise "Message sent must name an existing slot in the receiver." unless frame.has_slot?(selector) func = frame.get(selector) raise "Message sent must select a function slot but was #{func.type}." unless func.function? params = args.cddr frame_env = Lisp::EnvironmentFrame.extending(env, frame) frame_env.bind_locally(Symbol.named("self"), frame) func.apply_to(params, frame_env) end |
.send_super_impl(args, env) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/rubylisp/frame.rb', line 134 def self.send_super_impl(args, env) raise "super can only be used within the context of a frame." unless env.frame selector = args.car.evaluate(env) raise "Selector must be a symbol but was #{selector.type}." unless selector.symbol? func = get_super_function(selector, env) raise "Message sent must select a function slot but was #{func.type}." unless func && func.function? params = args.cdr frame_env = Lisp::EnvironmentFrame.extending(env, env.frame) frame_env.bind_locally(Symbol.named("self"), env.frame) func.apply_to(params, frame_env) end |
.set_slot_impl(args, env) ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/rubylisp/frame.rb', line 100 def self.set_slot_impl(args, env) frame = args.car.evaluate(env) raise "Frame data must be a frame but was #{frame.type}." unless frame.frame? key = args.cadr.evaluate(env) raise "Frame key (#{key.to_s}) must be a symbol but was #{key.type}." unless key.symbol? value = args.caddr.evaluate(env) frame.at_put(key, value) end |
.with_map(m) ⇒ Object
154 155 156 |
# File 'lib/rubylisp/frame.rb', line 154 def self.with_map(m) self.new(m) end |
Instance Method Details
#at_put(key, value) ⇒ Object
230 231 232 233 234 235 236 237 |
# File 'lib/rubylisp/frame.rb', line 230 def at_put(key, value) return @value[key] = value if !has_slot?(key) || has_slot_locally?(key) parents.each do |p| v = p.at_put(key, value) return v unless v.nil? end nil end |
#car ⇒ Object
260 261 262 |
# File 'lib/rubylisp/frame.rb', line 260 def car nil end |
#cdr ⇒ Object
264 265 266 |
# File 'lib/rubylisp/frame.rb', line 264 def cdr nil end |
#clone ⇒ Object
163 164 165 |
# File 'lib/rubylisp/frame.rb', line 163 def clone Lisp::Frame.with_map(@value.clone) end |
#eq?(other) ⇒ Boolean
268 269 270 271 272 273 274 275 |
# File 'lib/rubylisp/frame.rb', line 268 def eq?(other) return false unless other.frame? return false unless @value.length == other.value.length @value.each do |k, v| return false unless Lisp::Equivalence.equal_check(other.value[k], v).value end true end |
#get(key) ⇒ Object
213 214 215 216 217 218 219 220 |
# File 'lib/rubylisp/frame.rb', line 213 def get(key) return @value[key] if has_slot_locally?(key) parents.each do |p| value = p.get(key) return value unless value.nil? end nil end |
#has_parent_slots? ⇒ Boolean
186 187 188 |
# File 'lib/rubylisp/frame.rb', line 186 def has_parent_slots? @value.keys.any? {|k| is_parent_key(k)} end |
#has_slot?(n) ⇒ Boolean
206 207 208 209 210 |
# File 'lib/rubylisp/frame.rb', line 206 def has_slot?(n) return true if has_slot_locally?(n) return false unless has_parent_slots? return parents.any? {|p| p.has_slot?(n)} end |
#has_slot_locally?(n) ⇒ Boolean
201 202 203 |
# File 'lib/rubylisp/frame.rb', line 201 def has_slot_locally?(n) @value.has_key?(n) end |
#inherited_value_slots ⇒ Object
178 179 180 181 182 183 |
# File 'lib/rubylisp/frame.rb', line 178 def inherited_value_slots parent_frames = parent_slots.collect {|pk| get(pk)} parent_slots = parent_frames.collect {|p| p.inherited_value_slots} local_value_slots = Set[local_slots.reject {|s| is_parent_key(k)}] parent_slots.inject(local_value_slots) {|all, s| all + s} end |
#is_parent_key(k) ⇒ Object
168 169 170 |
# File 'lib/rubylisp/frame.rb', line 168 def is_parent_key(k) k.to_s[-2] == "*" end |
#length ⇒ Object
256 257 258 |
# File 'lib/rubylisp/frame.rb', line 256 def length return @value.length end |
#lisp_object? ⇒ Boolean
240 241 242 |
# File 'lib/rubylisp/frame.rb', line 240 def lisp_object? true end |
#local_slots ⇒ Object
173 174 175 |
# File 'lib/rubylisp/frame.rb', line 173 def local_slots @value.keys end |
#parent_slots ⇒ Object
191 192 193 |
# File 'lib/rubylisp/frame.rb', line 191 def parent_slots @value.keys.select {|k| is_parent_key(k)} end |
#parents ⇒ Object
196 197 198 |
# File 'lib/rubylisp/frame.rb', line 196 def parents parent_slots.collect {|pk| @value[pk]} end |
#remove(key) ⇒ Object
223 224 225 226 227 |
# File 'lib/rubylisp/frame.rb', line 223 def remove(key) return false unless has_slot_locally?(key) @value.delete(key) true end |
#to_s ⇒ Object
277 278 279 280 |
# File 'lib/rubylisp/frame.rb', line 277 def to_s pairs = @value.collect {|k, v| "#{k.to_s} #{v.to_s}"} "{#{pairs.join(' ')}}" end |
#type ⇒ Object
244 245 246 |
# File 'lib/rubylisp/frame.rb', line 244 def type :frame end |