hivemind 0.1

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.
@@ -0,0 +1,169 @@
1
+ module Hivemind
2
+ module UniversalAST
3
+ class Element
4
+ def self.fields(*labels)
5
+ define_method(:initialize) do |*args|
6
+ args.zip(labels).each do |arg, label|
7
+ instance_variable_set "@#{label}", arg
8
+ end
9
+ end
10
+ attr_reader *labels
11
+ end
12
+
13
+ def offset(depth)
14
+ ' ' * depth
15
+ end
16
+ end
17
+
18
+ class IfStatement < Element
19
+ # if <test>:
20
+ # <<true-branch>>
21
+ # else:
22
+ # <<else-branch>>
23
+
24
+ fields :test, :true_branch, :else_branch
25
+
26
+ def render(depth = 0)
27
+ "#{offset(depth)}If\n#{offset(depth + 1)}#{@test.render(depth + 1)}\n"
28
+ "#{@true_branch.render(depth + 1)}\n#{@else_branch.render(depth + 1)}\n"
29
+ end
30
+ end
31
+
32
+ class Assign < Element
33
+ # <left> = <right>
34
+
35
+ fields :left, :right
36
+
37
+ def render(depth = 0)
38
+ "#{offset(depth)}Assign left: #{@left.render} right: #{@right.render}"
39
+ end
40
+ end
41
+
42
+ class Attribute < Element
43
+ # <object>.<label>
44
+
45
+ fields :object, :label
46
+
47
+ def render(depth = 0)
48
+ "#{offset(depth)}Attribute : #{@object.render} #{@label.render}"
49
+ end
50
+ end
51
+
52
+ class AttributeAssign < Element
53
+ # <object>.<label> = <right>
54
+
55
+ fields :object, :label, :right
56
+
57
+ def render(depth = 0)
58
+ "#{offset(depth)}AttributeAssign : #{@object.render} #{@label.render} #{@right.render}"
59
+ end
60
+ end
61
+
62
+ class Call < Element
63
+ # <function>(<<args:', '>>)
64
+
65
+ fields :function, :args
66
+
67
+ def render(depth = 0)
68
+ "#{offset(depth)}Call\n#{@function.render(depth + 1)}\n#{offset(depth + 1)}#{@args.map(&:render).join(' ')}\n"
69
+ end
70
+ end
71
+
72
+ class List < Element
73
+ # [el1, el2..]
74
+
75
+ fields :elements
76
+
77
+ def render(depth = 0)
78
+ "#{offset(depth)}List\n#{@elements.map { |e| e.render(depth + 1) }.join("\n")}"
79
+ end
80
+ end
81
+
82
+ class Dictionary < Element
83
+ # {key1: val1, key2: val2..}
84
+
85
+ fields :pairs
86
+ end
87
+
88
+ class Binary < Element
89
+ # <left> <operation> <right>
90
+
91
+ fields :left, :operation, :right
92
+
93
+ def render(depth = 0)
94
+ "#{offset(depth)}Binary #{@left.render} #{@operation.value} #{@right.render}"
95
+ end
96
+ end
97
+
98
+ class MethodStatement < Element
99
+ # method <method-name>(<<args:', '):
100
+ # <<body>>
101
+
102
+ fields :method_name, :args, :body
103
+
104
+ def render(depth = 0)
105
+ "#{offset(depth)}MethodStatement #{@method_name.value} #{@args.map(&:render).join(' ')}\n" +
106
+ "#{@body.map { |e| e.render(depth + 1) }.join("\n")}\n"
107
+ end
108
+ end
109
+
110
+ class ClassStatement < Element
111
+ # type <class-name>:
112
+ # <<methods>>
113
+
114
+ fields :class_name, :methods
115
+
116
+ def render(depth = 0)
117
+ "#{offset(depth)}ClassStatement #{@class_name.value}\n" +
118
+ "#{@methods.map { |e| e.render(depth + 1) }.join("\n")}\n"
119
+ end
120
+ end
121
+
122
+ class Value < Element
123
+ fields :value
124
+
125
+ def render(depth = 0)
126
+ "#{offset(depth)}#{@value}"
127
+ end
128
+ end
129
+
130
+ class Name < Value
131
+ end
132
+
133
+ class String < Value
134
+ end
135
+
136
+ class Number < Value
137
+ end
138
+
139
+ class Int < Number
140
+ end
141
+
142
+ class Float < Number
143
+ end
144
+
145
+ class Operation < Value
146
+ end
147
+
148
+ class ModuleStatement < Element
149
+ # module <module-name>:
150
+ # <<children>>
151
+
152
+ fields :module_name, :elements
153
+ end
154
+
155
+ class Pair < Element
156
+ # key => value
157
+ fields :key, :value
158
+ end
159
+
160
+ class Image < Element
161
+ fields :statements
162
+
163
+ def render(depth = 0)
164
+ @statements.map(&:render).join "\n"
165
+ end
166
+ end
167
+ end
168
+ end
169
+
@@ -0,0 +1,186 @@
1
+ require_relative 'runtime'
2
+ require_relative 'universal_ast'
3
+
4
+ module Hivemind
5
+ class VM
6
+ def initialize(ast)
7
+ @ast = ast
8
+ end
9
+
10
+ def run(env)
11
+ @ast.run env
12
+ end
13
+ end
14
+
15
+ class Runtime::HivemindObject
16
+ def call(function, args, env)
17
+ if function.is_a?(UniversalAST::MethodStatement)
18
+ args_values = {:self => self}
19
+ function.args[1..-1].zip(args) do |label, arg|
20
+ args_values[label.value.to_sym] = arg
21
+ end
22
+ body_env = Environment.new(env, **args_values)
23
+ function.body.map { |expr| expr.run(body_env) }[-1] || env.top[:@nil]
24
+ else
25
+ function.call self, *args, env
26
+ end
27
+ end
28
+ end
29
+
30
+ class Runtime::HivemindClass
31
+ def call(function, args, env)
32
+ h = Runtime::HivemindObject.new({}, self)
33
+ function = dispatch_method(:init)
34
+ if function.is_a?(UniversalAST::MethodStatement)
35
+ args_values = {:self => h}
36
+ function.args[1..-1].zip(args) do |label, arg|
37
+ args_values[label.value.to_sym] = arg
38
+ end
39
+ body_env = Environment.new(env, **args_values)
40
+ function.body.map { |expr| expr.run(body_env) }[-1] || env.top[:@nil]
41
+ else
42
+ function.call h, *args, env
43
+ end
44
+ h
45
+ end
46
+ end
47
+
48
+ module UniversalAST
49
+ class Image
50
+ def run(env)
51
+ @statements.each do |statement|
52
+ statement.run(env)
53
+ end
54
+ # puts env.top[:Object].methods.keys
55
+ if env.top[:Object].methods.key? :start
56
+ weird_object = Runtime::hivemind_object({})
57
+ weird_object.call(env.top[:Object].methods[:start], [], env)
58
+ else
59
+ env.top[:@nil]
60
+ end
61
+ end
62
+ end
63
+
64
+ class ModuleStatement
65
+ def run(env)
66
+ module_statement = Runtime::HivemindModule.new(@module_name)
67
+ @statements.each do |statement|
68
+ module_statement.elements[@statement.is_a?(ModuleStatement) ? @statement.module_name : @statement.class_name] =
69
+ statement.run(env)
70
+ end
71
+ env
72
+ end
73
+ end
74
+
75
+ class If
76
+ def run(env)
77
+ if @test.run(env) == env.top[:@true]
78
+ @true_branch.run env
79
+ else
80
+ @else_branch.run env
81
+ end
82
+ end
83
+ end
84
+
85
+ class Assign
86
+ def run(env)
87
+ env[@left.value.to_sym] = @right.run(env)
88
+ end
89
+ end
90
+
91
+ class Attribute
92
+ def run(env)
93
+ obj = @object.run(env)
94
+ env.current_self = obj
95
+
96
+ if obj.respond_to?(:data)
97
+ if obj.data.key? @label.value
98
+ obj.data[@label.value]
99
+ else
100
+ method = obj.klass.dispatch_method(@label.value)
101
+ if method
102
+ method
103
+ else
104
+ raise HivemindAccessError.new("No #{@label.value} in obj")
105
+ end
106
+ end
107
+ else
108
+ obj.methods[@label.value]
109
+ end
110
+ end
111
+ end
112
+
113
+ class AttributeAssign
114
+ def run(env)
115
+ @object.run(env).data[@label.value] = @right.run(env)
116
+ end
117
+ end
118
+
119
+ class Call
120
+ def run(env)
121
+ if !@function.is_a?(Attribute)
122
+ function = @function.run(env)
123
+ env.current_self.call(function, @args.map { |arg| arg.run(env) }, env)
124
+ elsif @function.label.value != :new
125
+ obj = @function.object.run(env)
126
+ function = obj.klass.dispatch_method(@function.label.value)
127
+ obj.call(function, @args.map { |arg| arg.run(env) }, env)
128
+ else
129
+ obj = @function.object.run(env)
130
+ function == obj.dispatch_method(:init)
131
+ obj.call(function, @args.map { |arg| arg.run(env) }, env)
132
+ end
133
+ end
134
+ end
135
+
136
+ class Binary
137
+ def run(env)
138
+ Runtime::hivemind_numbr(@left.run(env).data[:_value].send(@operation.value, @right.run(env).data[:_value]))
139
+ end
140
+ end
141
+
142
+ class List
143
+ def run(env)
144
+ Runtime::HivemindObject.new({_elements: @elements.map { |elem| elem.run(env) }}, env.top[:List])
145
+ end
146
+ end
147
+
148
+ class Dictionary
149
+ def run(env)
150
+ dict = {}
151
+ @pairs.each do |pair|
152
+ dict[pair.key.value.to_sym] = pair.value.run(env)
153
+ end
154
+ Runtime::HivemindObject.new({_dict: dict}, env.top[:Dict])
155
+ end
156
+ end
157
+
158
+ class Value
159
+ def run(env)
160
+ Runtime::HivemindObject.new({_value: @value}, env.top[self.class.name.split('::').last.to_sym])
161
+ end
162
+ end
163
+
164
+ class ClassStatement
165
+ def run(env)
166
+ definition = env.fetch(@class_name.value) || Runtime::HivemindClass.new(@class_name.value, env.top[:Object], {})
167
+ @methods.each do |method|
168
+ definition.methods[method.method_name.value] = method
169
+ end
170
+ env[@class_name.value] = definition
171
+ end
172
+ end
173
+
174
+ class MethodStatement
175
+ def run(env)
176
+ self
177
+ end
178
+ end
179
+
180
+ class Name
181
+ def run(env)
182
+ env[@value]
183
+ end
184
+ end
185
+ end
186
+ end
File without changes
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ module Hivemind
4
+ module UniversalAST
5
+ describe Element do
6
+ it 'fields initializes a class with given labels' do
7
+ class A < Element
8
+ fields :a
9
+ end
10
+
11
+ expect(A.new(2).a).to eq(2)
12
+ end
13
+ end
14
+
15
+ describe ModuleStatement do
16
+ it 'is initialized with an elements attribute' do
17
+ mod = ModuleStatement.new('ha', [])
18
+ expect(mod.elements).to eq([])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ module Hivemind
4
+ describe VM do
5
+ it 'should work for a program with a single number' do
6
+ vm = VM.new UniversalAST::Number.new(44)
7
+ expect(vm.run(Runtime::HivemindEnv).data[:_value]).to eq 44
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ # well, really, no time for a lot of tests now
2
+ # dirty fast prototyping
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ require 'rspec'
7
+ require 'hivemind'
@@ -0,0 +1,34 @@
1
+ #if_statement
2
+ <test> O RLY
3
+ YA RLY
4
+ <<true_branch>>
5
+ NO WAI
6
+ <<else_branch>>
7
+
8
+
9
+ #assign
10
+ DO <left> <right>
11
+
12
+ #method_statement
13
+ HOW DUZ I <method_name>(<<args:' '>>)
14
+ <<body>>
15
+ IF U SAY SO
16
+
17
+ #attribute
18
+ <object> HEY <label>
19
+
20
+ #attribute_assign
21
+ <object> BE <label> <right>
22
+
23
+ #call
24
+ GIMME <function> (<<args:' '>>)
25
+
26
+ #class_statement
27
+ TOM SAYS <class_name>
28
+ <<methods>>
29
+ LOVE
30
+
31
+ #module_statement
32
+ HAI <module_name>
33
+ <<elements>>
34
+ KTHXBYE
@@ -0,0 +1,34 @@
1
+ #if_statement
2
+ (if <test>
3
+ <true_branch>
4
+ <else_branch>)
5
+
6
+ #assign
7
+ (define <left> <right>)
8
+
9
+ #method_statement
10
+ (method <method_name> (<<args:' '>>)
11
+ <<body>>)
12
+
13
+ #attribute
14
+ <object>.<label>
15
+
16
+ #attribute_assign
17
+ (update <object>.<label> <right>)
18
+
19
+ #binary
20
+ (<operation> <left> <right>)
21
+
22
+ #call
23
+ (! <function> <<args:' '>>)
24
+
25
+ #list
26
+ _(<<elements:' '>>)
27
+
28
+ #class_statement
29
+ (class <class_name>
30
+ <<methods>>)
31
+
32
+ #module_statement
33
+ (module <module_name>
34
+ <<elements>>)