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,32 @@
1
+ require_relative 'errors'
2
+
3
+ module Hivemind
4
+ class Environment
5
+ attr_reader :parent, :values, :top
6
+ attr_accessor :current_self
7
+
8
+ def initialize(parent, **values)
9
+ @parent, @values, @top = parent, values, (parent.nil? ? values : parent.top)
10
+ end
11
+
12
+ def [](key)
13
+ value = fetch key
14
+ return value if value
15
+ raise HivemindMissingNameError.new("#{key} is missing")
16
+ end
17
+
18
+ def fetch(key)
19
+ current = self
20
+ until current.nil? || current.values.key?(key)
21
+ current = current.parent
22
+ end
23
+ return current.values[key] unless current.nil?
24
+ nil
25
+ end
26
+
27
+ def []=(key, value)
28
+ @values[key] = value
29
+ end
30
+ end
31
+ end
32
+
@@ -0,0 +1,7 @@
1
+ module Hivemind
2
+ class HivemindMissingNameError < StandardError
3
+ end
4
+
5
+ class HivemindAccessError < StandardError
6
+ end
7
+ end
@@ -0,0 +1,71 @@
1
+ require_relative 'syntax'
2
+
3
+ module Hivemind
4
+
5
+ BASE_RULES = {
6
+ image: -> element, depth = 0 do
7
+ element.statements.map { |s| render_element(s) }.join("\n")
8
+ end,
9
+
10
+ int: -> element, depth = 0 do
11
+ element.value.to_s
12
+ end,
13
+
14
+ float: -> element, depth = 0 do
15
+ element.value.to_s
16
+ end,
17
+
18
+ string: -> element, depth = 0 do
19
+ '"' + element.value.to_s + '"'
20
+ end,
21
+
22
+ name: -> element, depth = 0 do
23
+ element.value.to_s
24
+ end,
25
+
26
+ operation: -> element, depth = 0 do
27
+ element.value.to_s
28
+ end
29
+ }
30
+
31
+ class Renderer
32
+ def initialize(tree, syntax)
33
+ @tree, @syntax = tree, syntax
34
+ @rules = BASE_RULES.merge(Syntax.load_rules(syntax))
35
+ end
36
+
37
+ def render(depth = 0)
38
+ render_element(@tree, depth).gsub(/\n\n+/, "\n\n").gsub(/\)\s+\)/, '))').gsub(/\}\s+\}/, '}}')
39
+ end
40
+
41
+ def offset(depth = 0)
42
+ ' ' * depth
43
+ end
44
+
45
+ def render_element(element, depth = 0)
46
+ rule = @rules[element.class.name.split('::').last.downcase.gsub('attributeassign', 'attribute_assign').gsub('statement', '_statement').to_sym]
47
+ depth += 1 if element.class.name.end_with?('MethodStatement')
48
+ # p "for #{element.class.name.split('::').last.downcase.gsub('statement', '_statement').to_sym} #{depth}"
49
+ offset(depth) + if rule.is_a?(String)
50
+ render_template rule, element, depth
51
+ elsif rule.is_a?(Proc)
52
+ instance_exec element, depth, &rule
53
+ end
54
+ end
55
+
56
+ def render_template(plan, element, depth = 0)
57
+ plan = plan.gsub(/\<\<([a-zA-Z_]+)\:'([^\']*)'\>\>/) do
58
+ element.send(Regexp.last_match[1]).map(&method(:render_element)).join(Regexp.last_match[2])
59
+ end
60
+ # p plan
61
+ plan = plan.gsub(/\<\<([a-zA-Z_]+)\>\>/) do
62
+ element.send(Regexp.last_match[1]).map { |e| render_element(e, depth) }.join("\n")
63
+ end
64
+ p plan
65
+ plan = plan.gsub(/\<([a-zA-Z_]+)\>/) do
66
+ render_element(element.send(Regexp.last_match[1]))
67
+ end
68
+ plan
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,90 @@
1
+ require_relative 'environment'
2
+
3
+ module Hivemind
4
+ module Runtime
5
+ class HivemindObject
6
+ attr_reader :data, :klass
7
+
8
+ def initialize(data, klass)
9
+ @data, @klass = data, klass
10
+ end
11
+ end
12
+
13
+ class HivemindClass
14
+ attr_reader :label, :methods, :parent
15
+
16
+ def initialize(label, parent = nil, methods = {})
17
+ @label, @parent, @methods = label, parent, methods
18
+ end
19
+
20
+ def define_hivemind_method(label, &handler)
21
+ @methods[label] = handler
22
+ end
23
+
24
+ def dispatch_method(label)
25
+ current = self
26
+ until current.nil? || current.methods.key?(label)
27
+ current = current.parent
28
+ end
29
+ !current ? nil : current.methods[label]
30
+ end
31
+ end
32
+
33
+ class HivemindModule
34
+ attr_reader :label, :elements
35
+
36
+ def initialize(label, elements = [])
37
+ @elements = elements
38
+ end
39
+ end
40
+
41
+ def self.hivemind_string(value)
42
+ HivemindObject.new({_value: value}, HivemindEnv[:String])
43
+ end
44
+
45
+ def self.hivemind_numbr(value)
46
+ HivemindObject.new({_value: value}, HivemindEnv[value.is_a?(Fixnum) ? :Int : :Float])
47
+ end
48
+
49
+ def self.hivemind_object(data)
50
+ HivemindObject.new(data, HivemindEnv[:Object])
51
+ end
52
+
53
+ HivemindEnv = Environment.new(nil,
54
+ Object: HivemindClass.new('Object')
55
+ )
56
+
57
+ HivemindEnv[:Class] = HivemindClass.new('Class', HivemindEnv[:Object])
58
+ HivemindEnv[:String] = HivemindClass.new('String', HivemindEnv[:Object])
59
+ HivemindEnv[:Int] = HivemindClass.new('Int', HivemindEnv[:Object])
60
+ HivemindEnv[:Float] = HivemindClass.new('Float', HivemindEnv[:Object])
61
+ HivemindEnv[:Boolean] = HivemindClass.new('Boolean', HivemindEnv[:Object])
62
+ HivemindEnv[:@true] = HivemindObject.new({}, HivemindEnv[:Boolean])
63
+ HivemindEnv[:NilClass] = HivemindClass.new('NilClass', HivemindEnv[:Object])
64
+ HivemindEnv[:@nil] = HivemindObject.new({}, HivemindEnv[:NilClass])
65
+
66
+ HivemindEnv[:Object].define_hivemind_method(:display) do |hivemind_self, *args, env|
67
+ puts hivemind_self.call(hivemind_self.klass.dispatch_method(:to_string), args, env).data[:_value]
68
+ end
69
+
70
+ HivemindEnv[:Object].define_hivemind_method(:to_string) do |hivemind_self, *args, env|
71
+ # p hivemind_self
72
+ if [HivemindEnv[:Int], HivemindEnv[:Float], HivemindEnv[:String], HivemindEnv[:Boolean]].include? hivemind_self.klass
73
+ hivemind_string(hivemind_self.data[:_value])
74
+ elsif hivemind_self.klass == HivemindEnv[:NilClass]
75
+ hivemind_string('null')
76
+ else
77
+ y = ''
78
+ i = 0
79
+ y2 = []
80
+ hivemind_self.data.each do |key, value|
81
+ y2 << key.to_s + ':' + value.call(value.klass.dispatch_method(:to_string), [], env).data[:_value].to_s
82
+ end
83
+ y = y2.join(', ')
84
+ hivemind_string("{#{y}}")
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+
@@ -0,0 +1,404 @@
1
+ require_relative 'combinators'
2
+
3
+ module Hivemind
4
+
5
+ # BaseGrammar = Phoenix::Grammar.new
6
+ # BaseGrammar.rules = {
7
+ # segment: many(ref(:keyword_structure), as: :elements),
8
+ # keyword_structure: ref(:module) | ref(:class) | ref(:method),
9
+ # method: lit('module') & some(ws) & ref(:name, as: :module_name) &
10
+ # many(ref(:expr), as: :body),
11
+ # expr: ref(:if) | ref(:sequence) | ref(:attribute) | ref(:attribute_assign) |
12
+ # ref(:assign) | ref(:literal),
13
+ # sequence: ref(:list) | ref(:dictionary),
14
+ # list: lit('[') & join(ref(:expr), ', ', as: :elements) & lit(']'),
15
+ # dictionary: lit('{') & join(ref(:pair), ', ', as: :elements) & lit('}'),
16
+ # pair: ref(:expr, as: :key) & some(ws) & '=>' & some(ws) & ref(:expr, as: :value),
17
+ # attribute: ref(:expr, as: :object, except: :attribute) & '.' & ref(:name, as: :label),
18
+ # attribute_assign: ref(:expr, as: :object, except: :attribute) & '.' & ref(:name, as: :label) & some(ws) & lit('=') & some(ws) & ref(:expr, as: :right),
19
+ # assign: ref(:name, as: :left) & some(ws) & lit('=') & some(ws) & ref(:expr, as: :right),
20
+ # literal: ref(:string) | ref(:boolean) | ref(:nil_literal) | ref(:number) | ref(:name)
21
+ # name: regex(/[a-zA-Z_]+/, as: :value),
22
+ # string: lit('"') & regex(/[^"]*/, as: :value) + lit('"'),
23
+ # number: regex(/[0-9]+(\.[0-9]+)?/, as: :value),
24
+ # boolean: ref(:true_literal) | ref(:false_literal),
25
+ # true_literal: 'true',
26
+ # false_literal: 'false',
27
+ # nil_literal: 'nil',
28
+ # :if => lit('if') & some(ws) & ref(:expr, as: :test) & lit(':') & nl & indent & join(ref(:expr), "\n", as: :true_branch) &
29
+ # nl & dedent & lit('else') & lit(':') & nl & indent & join(ref(:expr), "\n", as: :else_branch) & nl & dedent,
30
+ # :class => lit('class') & some(ws) & ref(:name, as: :class_name) &
31
+ # many(ref(:ex)
32
+
33
+ # }
34
+
35
+
36
+ TYPES = {
37
+ assign: {
38
+ left: :name,
39
+ right: :expr
40
+ },
41
+
42
+ attribute: {
43
+ object: :expr_no_attr,
44
+ label: :name_or_attr
45
+ },
46
+
47
+ image: {
48
+ statements: :class_statement
49
+ },
50
+
51
+ binary: {
52
+ left: :expr_no_binary,
53
+ operation: :operation,
54
+ right: :expr
55
+ },
56
+
57
+ attribute_assign: {
58
+ object: :expr_no_attr,
59
+ label: :name_or_attr,
60
+ right: :expr
61
+ },
62
+
63
+ call: {
64
+ function: :expr_no_call,
65
+ args: :expr
66
+ },
67
+
68
+ list: {
69
+ elements: :expr
70
+ },
71
+
72
+ dictionary: {
73
+ pair: :pair
74
+ },
75
+
76
+ pair: {
77
+ key: :string,
78
+ value: :expr
79
+ },
80
+
81
+ method_statement: {
82
+ method_name: :name,
83
+ args: :name,
84
+ body: :expr
85
+ },
86
+
87
+ class_statement: {
88
+ class_name: :name,
89
+ methods: :method_statement
90
+ },
91
+
92
+ module_statement: {
93
+ module_name: :name,
94
+ elements: :statement
95
+ },
96
+
97
+ if_statement: {
98
+ test: :expr,
99
+ true_branch: :expr,
100
+ else_branch: :expr
101
+ }
102
+ }
103
+
104
+ class Syntax
105
+ def self.generate_syntax(bidirectional_grammar)
106
+ new(bidirectional_grammar).generate
107
+ end
108
+
109
+ def initialize(grammar)
110
+ @grammar_source = grammar
111
+ end
112
+
113
+ def generate
114
+ # parse grammar
115
+ # combine into base grammar
116
+ rules = self.class.load_rules(@grammar_source)
117
+ refs = {}
118
+
119
+ rules.each do |name, rule|
120
+ refs[:"_#{name}"] = parse_rule rule, TYPES[name]
121
+ end
122
+
123
+ [REFS[:image], REFS.merge(refs)]
124
+ end
125
+
126
+ def parse_rule(rule, types)
127
+ parsers = []
128
+ tokens = []
129
+ token = ''
130
+ i = 0
131
+ while i < rule.length
132
+ z = rule[i]
133
+ if '<>'.include?(z)
134
+ tokens << token unless token.empty?
135
+ token = ''
136
+ if z == '>'
137
+ if rule[i + 1] == '>'
138
+ tokens << '>>'
139
+ i += 1
140
+ else
141
+ tokens << '>'
142
+ end
143
+ elsif z == '<'
144
+ if rule[i + 1] == '<'
145
+ tokens << '<<'
146
+ i += 1
147
+ else
148
+ tokens << '<'
149
+ end
150
+ end
151
+ elsif z == "'"
152
+ tokens << token unless token.empty?
153
+ token = ''
154
+ j = i
155
+ i += 1
156
+ while rule[i] != "'"
157
+ i += 1
158
+ end
159
+ tokens << rule[j..i]
160
+ elsif z == ' '
161
+ tokens << token unless token.empty?
162
+ token = ''
163
+ j = i
164
+ while rule[i] == ' '
165
+ i += 1
166
+ end
167
+ tokens << rule[j..i - 1]
168
+ i -= 1
169
+ elsif z == "\n"
170
+ tokens << token unless token.empty?
171
+ tokens << "\n"
172
+ elsif z.match /[a-zA-Z_0-9]/
173
+ token += z
174
+ else
175
+ tokens << token unless token.empty?
176
+ token = ''
177
+ tokens << z
178
+ end
179
+ i += 1
180
+ end
181
+ tokens << token unless token.empty?
182
+
183
+ r = 0
184
+ in_var = false
185
+
186
+ tokens.each_with_index do |token, i|
187
+ if token == '>>'
188
+ if tokens[i - 2] == ':'
189
+ parsers << Join.new(
190
+ Ref.new(types[tokens[i - 3].to_sym]),
191
+ tokens[i - 1][1..-2], as: tokens[i - 3])
192
+ else
193
+ parsers << Join.new(Ref.new(types[tokens[i - 1].to_sym]), "\n#{' ' * r}", as: tokens[i - 1])
194
+ #Many.new(Ref.new(types[tokens[i - 1].to_sym]), as: tokens[i - 1])
195
+ end
196
+ in_var = false
197
+ elsif token == '>'
198
+ parsers << Ref.new(types[tokens[i - 1].to_sym])
199
+ in_var = false
200
+ elsif token == "\n"
201
+ parsers << Ref.new(:nl)
202
+ if tokens[i + 1] == "\n"
203
+ e = 2
204
+ elsif tokens[i + 1]
205
+ match = tokens[i + 1].match /([ ]+)/
206
+ if match.nil? || match.captures.empty?
207
+ indent = 0
208
+ else
209
+ indent = match.captures.first.size / 4
210
+ end
211
+ if indent > r
212
+ parsers << Ref.new(:indent)
213
+ elsif indent < r
214
+ parsers << Ref.new(:dedent)
215
+ end
216
+ r = indent
217
+ end
218
+ elsif token.match(/\A +\z/)
219
+ parsers << Ref.new(:ws)
220
+ elsif (token == '<<' || token == '<') && tokens[i + 1] >= 'a' && tokens[i + 1] <= 'z'
221
+ in_var = true
222
+ elsif !in_var
223
+ parsers << Lit.new(token)
224
+ end
225
+ end
226
+ # parsers.map { |pa| puts pa.inspect }
227
+ parsers.reduce(:&)
228
+ end
229
+
230
+ def self.load_rules(grammar)
231
+ lines = grammar.split("\n")
232
+ rules = {}
233
+ current_rule = nil
234
+ rule_body = []
235
+ lines.each do |line|
236
+ if line.start_with? '#'
237
+ if not current_rule.nil?
238
+ rule_body << "\n" if rule_body.length > 1
239
+ rules[current_rule.to_sym] = rule_body.join("\n")
240
+ rule_body = []
241
+ end
242
+ current_rule = line[1..-1].strip
243
+ elsif line.strip != ''
244
+ rule_body << line
245
+ end
246
+ end
247
+ rule_body << "\n" if rule_body.length > 1
248
+ rules[current_rule.to_sym] = rule_body.join("\n")
249
+ rules
250
+ end
251
+ end
252
+
253
+ Name = UniversalAST::Name
254
+ Number = UniversalAST::Number
255
+ Assign = UniversalAST::Assign
256
+ Element = UniversalAST::Element
257
+ Call = UniversalAST::Call
258
+ List = UniversalAST::List
259
+ Dictionary = UniversalAST::Dictionary
260
+ Pair = UniversalAST::Pair
261
+ Attribute = UniversalAST::Attribute
262
+ AttributeAssign = UniversalAST::AttributeAssign
263
+ IfStatement = UniversalAST::IfStatement
264
+ MethodStatement = UniversalAST::MethodStatement
265
+ ClassStatement = UniversalAST::ClassStatement
266
+ Image = UniversalAST::Image
267
+ Operation = UniversalAST::Operation
268
+ Float = UniversalAST::Float
269
+ Int = UniversalAST::Int
270
+
271
+ REFS = {
272
+ name: Apply.new(Mat.new(/[a-zA-Z][a-zA-Z_]*/)) do |result|
273
+ Name.new(result.to_sym)
274
+ end,
275
+
276
+ image: Apply.new(Join.new(Ref.new(:class_statement), "", as: :statements)) do |children|
277
+ # d = children.select { |child| child.is_a?(MethodStatement) }
278
+ e = children.select { |child| child.is_a?(ClassStatement) }
279
+ # obj = e.find { |element| element.is_a?(ClassStatement) && element.class_name == :Object }
280
+ # p e[0].class_name
281
+ # if obj.nil? && !d.empty?
282
+ # obj = ClassStatement.new(Name.new(:Object), d)
283
+ # e << obj
284
+ # elsif obj
285
+ # obj.methods += d
286
+ # end
287
+ Image.new(e)
288
+ end,
289
+
290
+ statement: Ref.new(:module_statement) | Ref.new(:class_statement) | Ref.new(:method_statement),
291
+
292
+ number: Ref.new(:float) | Ref.new(:int),
293
+
294
+ float: Apply.new(Mat.new(/[0-9]+\.[0-9]+/)) do |result|
295
+ Float.new(result.to_f)
296
+ end,
297
+
298
+ int: Apply.new(Mat.new(/[0-9]+/)) do |result|
299
+ Int.new(result.to_i)
300
+ end,
301
+
302
+ string: Apply.new(Mat.new(/\"[^\"]*\"/)) do |result|
303
+ String.new(result[1..-2])
304
+ end,
305
+
306
+ ws: Mat.new(/ +/),
307
+
308
+ nl: Mat.new(/\n*/),
309
+
310
+ indent: Lit.new(''),
311
+
312
+ dedent: Lit.new(''),
313
+
314
+ expr: Ref.new(:attribute_assign) | Ref.new(:assign) | Ref.new(:binary) | Ref.new(:call) | Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),
315
+
316
+ expr_no_attr: Ref.new(:number) | Ref.new(:nil) | Ref.new(:name) | Ref.new(:string),
317
+
318
+ expr_no_call: Ref.new(:binary) | Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),
319
+
320
+ nil: Lit.new('nil'),
321
+
322
+ name_or_attr: Ref.new(:name) | Ref.new(:attribute),
323
+
324
+ assign: Apply.new(Ref.new(:_assign)) do |results|
325
+ Assign.new(*results.select { |r| r.is_a?(Element) })
326
+ end,
327
+
328
+ attribute_assign: Apply.new(Ref.new(:_attribute_assign)) do |results|
329
+ AttributeAssign.new(*results.select { |r| r.is_a?(Element) })
330
+ end,
331
+
332
+ call: Apply.new(Ref.new(:_call)) do |results|
333
+ function, args = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
334
+ Call.new(function, args)
335
+ end,
336
+
337
+ list: Apply.new(Ref.new(:_list)) do |results|
338
+ List.new(results[1])
339
+ end,
340
+
341
+ dictionary: Apply.new(Ref.new(:_dictionary)) do |results|
342
+ Dictionary.new(results[1])
343
+ end,
344
+
345
+ pair: Apply.new(Ref.new(:_pair)) do |results|
346
+ key, value = results.select { |r| r.is_a?(Element) }
347
+ Pair.new(key, value)
348
+ end,
349
+
350
+ binary: Apply.new(Ref.new(:_binary)) do |results|
351
+ if results[0].is_a?(String)
352
+ results = results[1..-1]
353
+ end
354
+ # detect operation intelligently
355
+ tokens = results[0], results[2], results[4]
356
+ if tokens[0].is_a?(UniversalAST::Operation)
357
+ operation, left, right = tokens
358
+ elsif tokens[1].is_a?(UniversalAST::Operation)
359
+ left, operation, right = tokens
360
+ else
361
+ left, right, operation = tokens
362
+ end
363
+ # p results
364
+ UniversalAST::Binary.new(left, operation, right)
365
+ end,
366
+
367
+ expr_no_binary: Ref.new(:attribute) | Ref.new(:number) | Ref.new(:name) | Ref.new(:string),
368
+
369
+ operation: Apply.new(Lit.new('+') | Lit.new('-') | Lit.new('**') | Lit.new('/') | Lit.new('*') | Lit.new('||')) do |result|
370
+ Operation.new(result)
371
+ end,
372
+
373
+ attribute: Apply.new(Ref.new(:_attribute)) do |results|
374
+ object, label = results.select { |r| r.is_a?(Element) }
375
+ Attribute.new(object, label)
376
+ end,
377
+
378
+ if_statement: Apply.new(Ref.new(:_if_statement)) do |results|
379
+ test, true_branch, else_branch = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
380
+ IfStatement.new(test, true_branch, else_branch)
381
+ end,
382
+
383
+ method_statement: Apply.new(Ref.new(:_method_statement)) do |results|
384
+ method_name, args, body = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
385
+ MethodStatement.new(method_name, args, body)
386
+ end,
387
+
388
+ class_statement: Apply.new(Ref.new(:_class_statement)) do |results|
389
+ class_name, methods = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
390
+ ClassStatement.new(class_name, methods)
391
+ end,
392
+
393
+ module_statement: Apply.new(Ref.new(:_module_statement)) do |results|
394
+ module_name, classes = results.select { |r| r.is_a?(Element) || r.is_a?(Array) }
395
+ ModuleStatement.new(module_name, classes)
396
+ end
397
+ }
398
+
399
+ end
400
+
401
+
402
+
403
+
404
+