halunke 0.2.0 → 0.3.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/Gemfile.lock +3 -1
- data/examples/hello.hal +19 -0
- data/examples/web.hal +20 -0
- data/exe/halunke +11 -7
- data/halunke.gemspec +2 -0
- data/lib/halunke/grammar.y +16 -32
- data/lib/halunke/interpreter.rb +56 -2
- data/lib/halunke/lexer.rb +95 -80
- data/lib/halunke/lexer.rl +7 -3
- data/lib/halunke/nodes.rb +24 -25
- data/lib/halunke/parser.rb +97 -112
- data/lib/halunke/runtime.rb +11 -222
- data/lib/halunke/runtime/false.hal +18 -0
- data/lib/halunke/runtime/harray.rb +30 -0
- data/lib/halunke/runtime/hclass.rb +96 -0
- data/lib/halunke/runtime/hdictionary.rb +26 -0
- data/lib/halunke/runtime/hfunction.rb +27 -0
- data/lib/halunke/runtime/hnative_object.rb +21 -0
- data/lib/halunke/runtime/hnumber.rb +41 -0
- data/lib/halunke/runtime/hobject.rb +30 -0
- data/lib/halunke/runtime/hstdout.rb +16 -0
- data/lib/halunke/runtime/hstring.rb +35 -0
- data/lib/halunke/runtime/hunassigned_bareword.rb +19 -0
- data/lib/halunke/runtime/hweb.rb +40 -0
- data/lib/halunke/runtime/true.hal +18 -0
- data/lib/halunke/version.rb +1 -1
- metadata +31 -2
data/lib/halunke/runtime.rb
CHANGED
@@ -1,222 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|