halunke 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,222 +1,11 @@
1
- # This file is not tested directly right now,
2
- # because I'm not sure if this structure is good
3
- # They are all prefixed with H to prevent collisions with Ruby's equivalents
4
- module Halunke
5
- class HClass
6
- def initialize(name, methods)
7
- @name = name
8
- @runtime_methods = methods
9
- end
10
-
11
- def create_instance(ruby_value = nil)
12
- HObject.new(self, ruby_value)
13
- end
14
-
15
- def lookup(message)
16
- @runtime_methods.fetch(message)
17
- rescue KeyError
18
- raise "Class #{@name} has no method to respond to message '#{message}'"
19
- end
20
- end
21
-
22
- class HObject
23
- attr_reader :ruby_value
24
-
25
- def initialize(runtime_class, ruby_value = nil)
26
- @runtime_class = runtime_class
27
- @ruby_value = ruby_value
28
- end
29
-
30
- def receive_message(context, message_name, message_value)
31
- m = @runtime_class.lookup(message_name)
32
- m.call(context, [self].concat(message_value))
33
- end
34
-
35
- def inspect(context)
36
- receive_message(context, "inspect", []).ruby_value
37
- end
38
- end
39
-
40
- class HFunction
41
- def initialize(signature, fn)
42
- @signature = signature
43
- @fn = fn
44
- end
45
-
46
- # TODO: This is a little bit of duplication that could probably be cleaned up by making functions proper objects
47
- def receive_message(context, message_name, message_value)
48
- raise "Class Function has no method to respond to message '#{message_name}'" unless message_name == "call"
49
- call(context, message_value[0].ruby_value)
50
- end
51
-
52
- def call(parent_context, args)
53
- context = parent_context.create_child
54
- @signature.zip(args).each do |name, value|
55
- context[name.to_s] = value
56
- end
57
- @fn.call(context)
58
- end
59
- end
60
-
61
- class HContext
62
- def initialize(parent_context = nil)
63
- @parent_context = parent_context
64
- @context = {}
65
- end
66
-
67
- def []=(name, value)
68
- @context[name] = value
69
- end
70
-
71
- def [](name)
72
- @context.fetch(name)
73
- rescue KeyError
74
- raise "Undefined bareword '#{name}'" if @parent_context.nil?
75
- @parent_context[name]
76
- end
77
-
78
- def parent
79
- @parent_context
80
- end
81
-
82
- def key?(name)
83
- @context.key?(name)
84
- end
85
-
86
- def create_child
87
- HContext.new(self)
88
- end
89
-
90
- def self.root_context
91
- context = new
92
-
93
- context["Number"] = HNumber
94
- context["String"] = HString
95
- context["Array"] = HArray
96
- context["UnassignedBareword"] = HUnassignedBareword
97
- context["True"] = HTrue
98
- context["False"] = HFalse
99
- context["true"] = HTrue.create_instance
100
- context["false"] = HFalse.create_instance
101
-
102
- context
103
- end
104
- end
105
-
106
- HNumber = HClass.new(
107
- "Number",
108
- "+" => HFunction.new([:self, :other], lambda { |context|
109
- HNumber.create_instance(context["self"].ruby_value + context["other"].ruby_value)
110
- }),
111
- "<" => HFunction.new([:self, :other], lambda { |context|
112
- if context["self"].ruby_value < context["other"].ruby_value
113
- HTrue.create_instance
114
- else
115
- HFalse.create_instance
116
- end
117
- }),
118
- ">" => HFunction.new([:self, :other], lambda { |context|
119
- if context["self"].ruby_value > context["other"].ruby_value
120
- HTrue.create_instance
121
- else
122
- HFalse.create_instance
123
- end
124
- }),
125
- "=" => HFunction.new([:self, :other], lambda { |context|
126
- if context["self"].ruby_value == context["other"].ruby_value
127
- HTrue.create_instance
128
- else
129
- HFalse.create_instance
130
- end
131
- }),
132
- "inspect" => HFunction.new([:self], lambda { |context|
133
- float_value = context["self"].ruby_value.to_f
134
- float_value = float_value.to_i if float_value.to_i == float_value
135
- HString.create_instance(float_value.to_s)
136
- })
137
- )
138
-
139
- HString = HClass.new(
140
- "String",
141
- "reverse" => HFunction.new([:self], lambda { |context|
142
- HString.create_instance(context["self"].ruby_value.reverse)
143
- }),
144
- "replace with" => HFunction.new([:self, :searchword, :replacement], lambda { |context|
145
- result = context["self"].ruby_value.gsub(
146
- context["searchword"].ruby_value,
147
- context["replacement"].ruby_value
148
- )
149
- HString.create_instance(result)
150
- }),
151
- "=" => HFunction.new([:self, :other], lambda { |context|
152
- if context["self"].ruby_value == context["other"].ruby_value
153
- HTrue.create_instance
154
- else
155
- HFalse.create_instance
156
- end
157
- }),
158
- "inspect" => HFunction.new([:self], lambda { |context|
159
- HString.create_instance(context["self"].ruby_value.inspect)
160
- })
161
- )
162
-
163
- HArray = HClass.new(
164
- "Array",
165
- "inspect" => HFunction.new([:self], lambda { |context|
166
- inspected_members = context["self"].ruby_value.map { |member| member.inspect(context) }
167
- HString.create_instance("[#{inspected_members.join(' ')}]")
168
- }),
169
- "=" => HFunction.new([:self, :other], lambda { |context|
170
- return HFalse.create_instance if context["self"].ruby_value.length != context["other"].ruby_value.length
171
-
172
- context["self"].ruby_value.zip(context["other"].ruby_value).map do |a, b|
173
- a.receive_message(context.parent, "=", [b])
174
- end.reduce(HTrue.create_instance) do |memo, value|
175
- memo.receive_message(context, "and", [value])
176
- end
177
- })
178
- )
179
-
180
- HUnassignedBareword = HClass.new(
181
- "UnassignedBareword",
182
- "=" => HFunction.new([:self, :other], lambda { |context|
183
- context.parent[context["self"].ruby_value] = context["other"]
184
- HTrue.create_instance
185
- }),
186
- "inspect" => HFunction.new([:self], lambda { |context|
187
- HString.create_instance("'#{context["self"].ruby_value}")
188
- })
189
- )
190
-
191
- HTrue = HClass.new(
192
- "True",
193
- "and" => HFunction.new([:self, :other], lambda { |context|
194
- context["other"]
195
- }),
196
- "or" => HFunction.new([:self, :other], lambda { |context|
197
- context["self"]
198
- }),
199
- "then else" => HFunction.new([:self, :true_branch, :false_branch], lambda { |context|
200
- context["true_branch"].receive_message(context, "call", [HArray.create_instance([])])
201
- }),
202
- "inspect" => HFunction.new([:self], lambda {|context|
203
- HString.create_instance("true")
204
- })
205
- )
206
-
207
- HFalse = HClass.new(
208
- "False",
209
- "and" => HFunction.new([:self, :other], lambda { |context|
210
- context["self"]
211
- }),
212
- "or" => HFunction.new([:self, :other], lambda { |context|
213
- context["other"]
214
- }),
215
- "then else" => HFunction.new([:self, :true_branch, :false_branch], lambda { |context|
216
- context["false_branch"].receive_message(context, "call", [HArray.create_instance([])])
217
- }),
218
- "inspect" => HFunction.new([:self], lambda {|context|
219
- HString.create_instance("false")
220
- })
221
- )
222
- end
1
+ require "halunke/runtime/hclass"
2
+ require "halunke/runtime/hobject"
3
+ require "halunke/runtime/hnative_object"
4
+ require "halunke/runtime/hfunction"
5
+ require "halunke/runtime/hnumber"
6
+ require "halunke/runtime/hstring"
7
+ require "halunke/runtime/harray"
8
+ require "halunke/runtime/hdictionary"
9
+ require "halunke/runtime/hunassigned_bareword"
10
+ require "halunke/runtime/hstdout"
11
+ require "halunke/runtime/hweb"
@@ -0,0 +1,18 @@
1
+ (Class new 'False
2
+ methods @[
3
+ "and" { |'self 'other|
4
+ self
5
+ }
6
+ "or" { |'self 'other|
7
+ other
8
+ }
9
+ "then else" { |'self 'true_branch 'false_branch|
10
+ (false_branch call [])
11
+ }
12
+ "inspect" { |'self 'other|
13
+ "false"
14
+ }
15
+ ]
16
+ )
17
+
18
+ ('false = (False new))
@@ -0,0 +1,30 @@
1
+ module Halunke
2
+ module Runtime
3
+ HArray = HClass.new(
4
+ "Array",
5
+ [],
6
+ {
7
+ "inspect" => HFunction.new([:self], lambda { |context|
8
+ inspected_members = context["self"].ruby_value.map { |member| member.inspect(context) }
9
+ HString.create_instance("[#{inspected_members.join(' ')}]")
10
+ }),
11
+ "=" => HFunction.new([:self, :other], lambda { |context|
12
+ return context["false"] if context["self"].ruby_value.length != context["other"].ruby_value.length
13
+
14
+ context["self"].ruby_value.zip(context["other"].ruby_value).map do |a, b|
15
+ a.receive_message(context.parent, "=", [b])
16
+ end.reduce(context["true"]) do |memo, value|
17
+ memo.receive_message(context, "and", [value])
18
+ end
19
+ }),
20
+ "map" => HFunction.new([:self, :fn], lambda { |context|
21
+ return HArray.create_instance(context["self"].ruby_value.map do |x|
22
+ context["fn"].receive_message(context, "call", [HArray.create_instance([x])])
23
+ end)
24
+ })
25
+ },
26
+ {},
27
+ true
28
+ )
29
+ end
30
+ end
@@ -0,0 +1,96 @@
1
+ module Halunke
2
+ module Runtime
3
+ class HClass
4
+ attr_reader :name
5
+
6
+ def initialize(name, allowed_attributes, instance_methods, class_methods, native)
7
+ @name = name
8
+ @allowed_attributes = allowed_attributes
9
+ @instance_methods = instance_methods
10
+ @class_methods = class_methods
11
+ @native = native
12
+ end
13
+
14
+ class << self
15
+ def receive_message(context, message_name, message_value)
16
+ case message_name
17
+ when "new attributes methods class_methods"
18
+ name = determine_name(message_value[0])
19
+ allowed_attributes = determine_allowed_attributes(message_value[1])
20
+ instance_methods = determine_methods(message_value[2])
21
+ class_methods = determine_methods(message_value[3])
22
+ when "new attributes methods"
23
+ name = determine_name(message_value[0])
24
+ allowed_attributes = determine_allowed_attributes(message_value[1])
25
+ instance_methods = determine_methods(message_value[2])
26
+ class_methods = {}
27
+ when "new methods"
28
+ name = determine_name(message_value[0])
29
+ allowed_attributes = []
30
+ instance_methods = determine_methods(message_value[1])
31
+ class_methods = {}
32
+ else
33
+ raise "Class Class has no method to respond to message '#{message_name}'"
34
+ end
35
+
36
+ context[name] = HClass.new(name, allowed_attributes, instance_methods, class_methods, false)
37
+ end
38
+
39
+ private
40
+
41
+ def determine_name(hstring)
42
+ hstring.ruby_value
43
+ end
44
+
45
+ def determine_allowed_attributes(harray)
46
+ harray.ruby_value.map(&:ruby_value)
47
+ end
48
+
49
+ def determine_methods(hdictionary)
50
+ instance_methods = {}
51
+ hdictionary.ruby_value.each_pair do |method_name, fn|
52
+ instance_methods[method_name.ruby_value] = fn
53
+ end
54
+ instance_methods
55
+ end
56
+ end
57
+
58
+ def receive_message(context, message_name, message_value)
59
+ if message_name == "new"
60
+ create_instance(message_value[0])
61
+ elsif @class_methods.keys.include? message_name
62
+ m = @class_methods[message_name]
63
+ m.receive_message(context, "call", [HArray.create_instance([self].concat(message_value))])
64
+ else
65
+ raise "Class #{@name} has no method to respond to message '#{message_name}'"
66
+ end
67
+ end
68
+
69
+ def allowed_attribute?(attribute_name)
70
+ @allowed_attributes.include? attribute_name
71
+ end
72
+
73
+ def create_instance(value = nil)
74
+ if native?
75
+ HNativeObject.new(self, value)
76
+ else
77
+ HObject.new(self, value ? value.ruby_value : {})
78
+ end
79
+ end
80
+
81
+ def lookup(message)
82
+ @instance_methods.fetch(message)
83
+ rescue KeyError
84
+ raise "Class #{@name} has no method to respond to message '#{message}'"
85
+ end
86
+
87
+ def inspect(_context)
88
+ "#<Class #{@name}>"
89
+ end
90
+
91
+ def native?
92
+ @native
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,26 @@
1
+ module Halunke
2
+ module Runtime
3
+ HDictionary = HClass.new(
4
+ "Dictionary",
5
+ [],
6
+ {
7
+ "inspect" => HFunction.new([:self], lambda { |context|
8
+ x = []
9
+ context["self"].ruby_value.each_pair do |key, value|
10
+ x.push(key.inspect(context))
11
+ x.push(value.inspect(context))
12
+ end
13
+ HString.create_instance("@[#{x.join(' ')}]")
14
+ }),
15
+ "@ else" => HFunction.new([:self, :search, :fallback], lambda { |context|
16
+ result = context["self"].ruby_value.find do |key, _value|
17
+ key.receive_message(context, "=", [context["search"]]).inspect(context) == "true"
18
+ end
19
+ result ? result[1] : context["fallback"]
20
+ })
21
+ },
22
+ {},
23
+ true
24
+ )
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ module Halunke
2
+ module Runtime
3
+ class HFunction
4
+ def initialize(signature, fn)
5
+ @signature = signature
6
+ @fn = fn
7
+ end
8
+
9
+ def receive_message(parent_context, message_name, message_value)
10
+ raise "Class Function has no method to respond to message '#{message_name}'" unless message_name == "call"
11
+
12
+ context = parent_context.create_child
13
+ args = message_value[0].ruby_value
14
+
15
+ @signature.zip(args).each do |name, value|
16
+ context[name.to_s] = value
17
+ end
18
+
19
+ @fn.call(context)
20
+ end
21
+
22
+ def inspect(_context)
23
+ "#<Function (#{@signature.length})>"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Halunke
2
+ module Runtime
3
+ class HNativeObject
4
+ attr_reader :ruby_value
5
+
6
+ def initialize(runtime_class, ruby_value = nil)
7
+ @runtime_class = runtime_class
8
+ @ruby_value = ruby_value
9
+ end
10
+
11
+ def receive_message(context, message_name, message_value)
12
+ m = @runtime_class.lookup(message_name)
13
+ m.receive_message(context, "call", [HArray.create_instance([self].concat(message_value))])
14
+ end
15
+
16
+ def inspect(context)
17
+ receive_message(context, "inspect", []).ruby_value
18
+ end
19
+ end
20
+ end
21
+ end