Class: Lisp::PrimFrame

Inherits:
Object show all
Defined in:
lib/rubylisp/prim_frame.rb

Class Method Summary collapse

Class Method Details

.clone_impl(args, env) ⇒ Object



151
152
153
154
155
# File 'lib/rubylisp/prim_frame.rb', line 151

def self.clone_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  frame.clone
end

.get_slot_if_impl(args, env) ⇒ Object



85
86
87
88
89
90
91
# File 'lib/rubylisp/prim_frame.rb', line 85

def self.get_slot_if_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  key = args.cadr
  return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
  frame.get(key)
end

.get_slot_impl(args, env) ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/rubylisp/prim_frame.rb', line 75

def self.get_slot_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  key = args.cadr
  return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
  return Lisp::Debug.process_error("Frame key (#{key.to_s}) must name an existing slot.", env) unless frame.has_slot?(key)
  frame.get(key)
end

.get_super_function(selector, env) ⇒ Object



128
129
130
131
132
133
134
135
136
# File 'lib/rubylisp/prim_frame.rb', line 128

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



65
66
67
68
69
70
71
72
# File 'lib/rubylisp/prim_frame.rb', line 65

def self.has_slot_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  key = args.cadr
  return Lisp::Debug.process_error("Frame key must be a symbol but was #{key.type}.", env) unless key.symbol?
  return Lisp::TRUE if frame.has_slot?(key)
  Lisp::FALSE
end

.keys_impl(args, env) ⇒ Object



158
159
160
161
162
# File 'lib/rubylisp/prim_frame.rb', line 158

def self.keys_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  ConsCell.array_to_list(frame.value.keys)
end

.make_frame_impl(args, env) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rubylisp/prim_frame.rb', line 49

def self.make_frame_impl(args, env)
  c = args
  m = {}
  while !c.nil?
    k = c.car
    return Lisp::Debug.process_error("Slot names must be a symbol, found a {k.type}.", env) unless k.symbol?
    return Lisp::Debug.process_error("Slot names must end in a colon, found '#{k}'.", env) unless k.naked?
    v = c.cadr
    m[k] = v
    c = c.cddr
  end

  Lisp::Frame.with_map(m)
end

.registerObject



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
43
44
45
46
# File 'lib/rubylisp/prim_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::PrimFrame::make_frame_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::has_slot_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::get_slot_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::get_slot_if_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::remove_slot_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::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::PrimFrame::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::PrimFrame::send_super_impl(args, env)
  end
  
  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|
    Lisp::PrimFrame::clone_impl(args, env)
  end
  
  Primitive.register("keys", "1", "(keys frame)\n\nReturn a list of the keys in the frame.") do |args, env|
    Lisp::PrimFrame::keys_impl(args, env)
  end
  
end

.remove_slot_impl(args, env) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/rubylisp/prim_frame.rb', line 94

def self.remove_slot_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  key = args.cadr
  return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
  return Lisp::TRUE if frame.remove(key)
  Lisp::FALSE
end

.send_impl(args, env) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rubylisp/prim_frame.rb', line 114

def self.send_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  selector = args.cadr
  return Lisp::Debug.process_error("Selector must be a symbol but was #{selector.type}.", env) unless selector.symbol?
  return Lisp::Debug.process_error("Message sent must name an existing slot in the receiver.", env) unless frame.has_slot?(selector)
  func = frame.get(selector)
  return Lisp::Debug.process_error("Message sent must select a function slot but was #{func.type}.", env) unless func.function?
  params = args.cddr
  frame_env = Lisp::EnvironmentFrame.extending(env, selector.to_s, frame)
  frame_env.bind_locally(Symbol.named("self"), frame)
  func.apply_to(params, frame_env)
end

.send_super_impl(args, env) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/rubylisp/prim_frame.rb', line 138

def self.send_super_impl(args, env)
  return Lisp::Debug.process_error("super can only be used within the context of a frame.", env) unless env.frame
  selector = args.car
  return Lisp::Debug.process_error("Selector must be a symbol but was #{selector.type}.", env) unless selector.symbol?
  func = get_super_function(selector, env)
  return Lisp::Debug.process_error("Message sent must select a function slot but was #{func.type}.", env) unless func && func.function?
  params = args.cdr
  frame_env = Lisp::EnvironmentFrame.extending(env, selector.to_s, env.frame)
  frame_env.bind_locally(Symbol.named("self"), env.frame)
  func.apply_to(params, frame_env)
end

.set_slot_impl(args, env) ⇒ Object



104
105
106
107
108
109
110
111
# File 'lib/rubylisp/prim_frame.rb', line 104

def self.set_slot_impl(args, env)
  frame = args.car
  return Lisp::Debug.process_error("Frame data must be a frame but was #{frame.type}.", env) unless frame.frame?
  key = args.cadr
  return Lisp::Debug.process_error("Frame key (#{key.to_s}) must be a symbol but was #{key.type}.", env) unless key.symbol?
  value = args.caddr
  frame.at_put(key, value)
end