halunke 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d34373e62580207f15e635b87cbbba8187f43aa5
4
- data.tar.gz: '08eebf0cc515092ff533c44a271d7fc4b3c4a451'
3
+ metadata.gz: b621079e4a57b2e4911784de31327cff6fa30a9b
4
+ data.tar.gz: 3980f6df3d46e58cb6ee08f5a7b7654bb629dbbc
5
5
  SHA512:
6
- metadata.gz: 41960737ac425cc20b7183ab8a506e64e11c55a7dab81d00abfa120d32b9b770e1500f69e595b0d4a73c19d5442e96adb2cfaf06ddace218b71415ec9df66a58
7
- data.tar.gz: f00d5bae53b39ae1c26b7bcde7ad8c16917b7e04a94c358680fc98850ead5e40284ec72cb3d1a6fb8802306dcbcb4d645236369b76fd9917b29ce26af4dbe1b0
6
+ metadata.gz: 218389d784fd2ba9332c3c24b7cb18079d529dfda97f9cdfbd060ba0b1a3be6fd02418da2ae0c1483e038ca59e5fdeba047111c831c2d00817901cf48ec663b5
7
+ data.tar.gz: e16520427aca78a5277fce868353cd73d96f2e65653da777b403fda407957ae2099c0c00e10cedeeb11dc9ac4378f44457fe29ebd5c3a6cec26a9bfcd90683a1
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- halunke (0.1.0)
4
+ halunke (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -7,6 +7,10 @@ interpreter = Halunke::Interpreter.new
7
7
 
8
8
  puts "Halunke REPL. Ctrl+d to quit"
9
9
  while (line = Readline.readline(">> ", true))
10
- value = interpreter.eval(line)
11
- puts "=> #{value}"
10
+ begin
11
+ value = interpreter.eval(line)
12
+ puts "=> #{value}"
13
+ rescue Exception => e
14
+ puts "An Error Occurred: #{e.message}"
15
+ end
12
16
  end
@@ -5,26 +5,43 @@ token STRING
5
5
  token BAREWORD
6
6
  token OPEN_PAREN
7
7
  token CLOSE_PAREN
8
+ token OPEN_CURLY
9
+ token CLOSE_CURLY
8
10
  token OPERATOR
11
+ token UNASSIGNED_BAREWORD
12
+ token OPEN_BRACKET
13
+ token CLOSE_BRACKET
14
+ token BAR
9
15
 
10
16
  rule
11
17
  Program:
12
- /* empty */ { result = Nodes.new }
13
- | Expressions { result = val[0] }
18
+ Expressions { result = val[0] }
14
19
  ;
15
20
 
16
21
  Expressions:
17
- Expression { result = Nodes.new(val) }
22
+ /* empty */ { result = Nodes.new }
23
+ | Expression Expressions { result = Nodes.new([val[0]]).concat(val[1]) }
18
24
  ;
19
25
 
20
26
  Expression:
21
27
  Literal
22
- | OPEN_PAREN Literal Literals CLOSE_PAREN { result = Halunke::MessageSendNode.new(val[1], MessageNode.new(val[2].nodes)) }
28
+ | OPEN_CURLY Expressions CLOSE_CURLY { result = Halunke::FunctionNode.new(Halunke::ArrayNode.new([]), val[1]) }
29
+ | OPEN_CURLY Args Expressions CLOSE_CURLY { result = Halunke::FunctionNode.new(val[1], val[2]) }
30
+ | OPEN_PAREN Expression Expressions CLOSE_PAREN { result = Halunke::MessageSendNode.new(val[1], MessageNode.new(val[2].nodes)) }
31
+ | OPEN_BRACKET Expressions CLOSE_BRACKET { result = ArrayNode.new(val[1].nodes) }
23
32
  ;
24
33
 
25
- Literals:
26
- /* empty */ { result = Nodes.new }
27
- | Literal Literals { result = Nodes.new([val[0]]).concat(val[1]) }
34
+ Args:
35
+ BAR UnassignedBarewords BAR { result = Halunke::ArrayNode.new(val[1].nodes) }
36
+ ;
37
+
38
+ UnassignedBarewords:
39
+ /* empty */ { result = Nodes.new }
40
+ | UnassignedBareword UnassignedBarewords { result = Nodes.new([val[0]]).concat(val[1]) }
41
+ ;
42
+
43
+ UnassignedBareword:
44
+ UNASSIGNED_BAREWORD { result = UnassignedNode.new(BarewordNode.new(val[0])) }
28
45
  ;
29
46
 
30
47
  Literal:
@@ -33,6 +50,7 @@ rule
33
50
  /* TODO: Are Operators just Barewords? */
34
51
  | BAREWORD { result = BarewordNode.new(val[0]) }
35
52
  | OPERATOR { result = BarewordNode.new(val[0]) }
53
+ | UNASSIGNED_BAREWORD { result = UnassignedNode.new(BarewordNode.new(val[0])) }
36
54
  ;
37
55
 
38
56
  end
@@ -4,25 +4,12 @@ module Halunke
4
4
  class Interpreter
5
5
  def initialize
6
6
  @parser = Parser.new
7
- @context = {}
8
- prelude
7
+ @context = HContext.root_context
9
8
  end
10
9
 
11
10
  def eval(str)
12
11
  nodes = @parser.parse(str)
13
- nodes.eval(@context)
14
- end
15
-
16
- private
17
-
18
- def prelude
19
- @context[:Number] = Halunke::NativeClass.new(
20
- "+" => Halunke::NativeFunction.new(->(receiver, args) { receiver.ruby_value + args.first.ruby_value })
21
- )
22
-
23
- @context[:String] = Halunke::NativeClass.new(
24
- "reverse" => Halunke::NativeFunction.new(->(receiver, _args) { receiver.ruby_value.reverse })
25
- )
12
+ nodes.eval(@context).inspect(@context)
26
13
  end
27
14
  end
28
15
  end
@@ -2,7 +2,7 @@
2
2
  # line 1 "lib/halunke/lexer.rl"
3
3
  =begin
4
4
 
5
- # line 24 "lib/halunke/lexer.rl"
5
+ # line 36 "lib/halunke/lexer.rl"
6
6
 
7
7
  =end
8
8
 
@@ -19,7 +19,10 @@ self._lexer_actions = [
19
19
  0, 1, 0, 1, 1, 1, 2, 1,
20
20
  5, 1, 6, 1, 7, 1, 8, 1,
21
21
  9, 1, 10, 1, 11, 1, 12, 1,
22
- 13, 2, 2, 3, 2, 2, 4
22
+ 13, 1, 14, 1, 15, 1, 16, 1,
23
+ 17, 1, 18, 1, 19, 1, 20, 1,
24
+ 21, 1, 22, 2, 2, 3, 2, 2,
25
+ 4
23
26
  ]
24
27
 
25
28
  class << self
@@ -27,7 +30,8 @@ class << self
27
30
  private :_lexer_key_offsets, :_lexer_key_offsets=
28
31
  end
29
32
  self._lexer_key_offsets = [
30
- 0, 1, 16, 17, 19
33
+ 0, 1, 3, 26, 27, 32, 34, 37,
34
+ 39
31
35
  ]
32
36
 
33
37
  class << self
@@ -35,10 +39,12 @@ class << self
35
39
  private :_lexer_trans_keys, :_lexer_trans_keys=
36
40
  end
37
41
  self._lexer_trans_keys = [
38
- 34, 32, 34, 40, 41, 43, 45, 95,
39
- 9, 13, 48, 57, 65, 90, 97, 122,
40
- 34, 48, 57, 95, 65, 90, 97, 122,
41
- 0
42
+ 34, 48, 57, 32, 34, 39, 40, 41,
43
+ 43, 45, 91, 93, 95, 123, 124, 125,
44
+ 9, 13, 48, 57, 60, 62, 65, 90,
45
+ 97, 122, 34, 95, 65, 90, 97, 122,
46
+ 48, 57, 46, 48, 57, 48, 57, 95,
47
+ 65, 90, 97, 122, 0
42
48
  ]
43
49
 
44
50
  class << self
@@ -46,7 +52,8 @@ class << self
46
52
  private :_lexer_single_lengths, :_lexer_single_lengths=
47
53
  end
48
54
  self._lexer_single_lengths = [
49
- 1, 7, 1, 0, 1
55
+ 1, 0, 13, 1, 1, 0, 1, 0,
56
+ 1
50
57
  ]
51
58
 
52
59
  class << self
@@ -54,7 +61,8 @@ class << self
54
61
  private :_lexer_range_lengths, :_lexer_range_lengths=
55
62
  end
56
63
  self._lexer_range_lengths = [
57
- 0, 4, 0, 1, 2
64
+ 0, 1, 5, 0, 2, 1, 1, 1,
65
+ 2
58
66
  ]
59
67
 
60
68
  class << self
@@ -62,7 +70,8 @@ class << self
62
70
  private :_lexer_index_offsets, :_lexer_index_offsets=
63
71
  end
64
72
  self._lexer_index_offsets = [
65
- 0, 2, 14, 16, 18
73
+ 0, 2, 4, 23, 25, 29, 31, 34,
74
+ 36
66
75
  ]
67
76
 
68
77
  class << self
@@ -70,10 +79,13 @@ class << self
70
79
  private :_lexer_trans_targs, :_lexer_trans_targs=
71
80
  end
72
81
  self._lexer_trans_targs = [
73
- 1, 0, 1, 2, 1, 1, 3, 3,
74
- 4, 1, 3, 4, 4, 1, 1, 0,
75
- 3, 1, 4, 4, 4, 1, 1, 1,
76
- 1, 1, 0
82
+ 2, 0, 7, 2, 2, 3, 4, 2,
83
+ 2, 5, 5, 2, 2, 8, 2, 2,
84
+ 2, 2, 6, 2, 8, 8, 2, 2,
85
+ 0, 4, 4, 4, 2, 6, 2, 1,
86
+ 6, 2, 7, 2, 8, 8, 8, 2,
87
+ 2, 2, 2, 2, 2, 2, 2, 2,
88
+ 0
77
89
  ]
78
90
 
79
91
  class << self
@@ -81,10 +93,13 @@ class << self
81
93
  private :_lexer_trans_actions, :_lexer_trans_actions=
82
94
  end
83
95
  self._lexer_trans_actions = [
84
- 7, 0, 13, 5, 9, 11, 28, 28,
85
- 0, 13, 25, 0, 0, 15, 7, 0,
86
- 25, 23, 0, 0, 0, 17, 21, 19,
87
- 23, 17, 0
96
+ 7, 0, 0, 37, 25, 5, 46, 9,
97
+ 11, 0, 0, 17, 19, 0, 13, 21,
98
+ 15, 25, 5, 23, 0, 0, 27, 7,
99
+ 0, 43, 43, 43, 41, 5, 33, 0,
100
+ 5, 29, 0, 29, 0, 0, 0, 31,
101
+ 39, 37, 35, 41, 33, 29, 29, 31,
102
+ 0
88
103
  ]
89
104
 
90
105
  class << self
@@ -92,7 +107,8 @@ class << self
92
107
  private :_lexer_to_state_actions, :_lexer_to_state_actions=
93
108
  end
94
109
  self._lexer_to_state_actions = [
95
- 0, 1, 0, 0, 0
110
+ 0, 0, 1, 0, 0, 0, 0, 0,
111
+ 0
96
112
  ]
97
113
 
98
114
  class << self
@@ -100,7 +116,8 @@ class << self
100
116
  private :_lexer_from_state_actions, :_lexer_from_state_actions=
101
117
  end
102
118
  self._lexer_from_state_actions = [
103
- 0, 3, 0, 0, 0
119
+ 0, 0, 3, 0, 0, 0, 0, 0,
120
+ 0
104
121
  ]
105
122
 
106
123
  class << self
@@ -108,17 +125,18 @@ class << self
108
125
  private :_lexer_eof_trans, :_lexer_eof_trans=
109
126
  end
110
127
  self._lexer_eof_trans = [
111
- 23, 0, 24, 25, 26
128
+ 41, 42, 0, 43, 44, 45, 47, 47,
129
+ 48
112
130
  ]
113
131
 
114
132
  class << self
115
133
  attr_accessor :lexer_start
116
134
  end
117
- self.lexer_start = 1;
135
+ self.lexer_start = 2;
118
136
  class << self
119
137
  attr_accessor :lexer_first_final
120
138
  end
121
- self.lexer_first_final = 1;
139
+ self.lexer_first_final = 2;
122
140
  class << self
123
141
  attr_accessor :lexer_error
124
142
  end
@@ -127,10 +145,10 @@ self.lexer_error = -1;
127
145
  class << self
128
146
  attr_accessor :lexer_en_main
129
147
  end
130
- self.lexer_en_main = 1;
148
+ self.lexer_en_main = 2;
131
149
 
132
150
 
133
- # line 31 "lib/halunke/lexer.rl"
151
+ # line 43 "lib/halunke/lexer.rl"
134
152
  @tokens = []
135
153
  end
136
154
 
@@ -139,7 +157,7 @@ self.lexer_en_main = 1;
139
157
  eof = data.length
140
158
 
141
159
 
142
- # line 143 "lib/halunke/lexer.rb"
160
+ # line 161 "lib/halunke/lexer.rb"
143
161
  begin
144
162
  p ||= 0
145
163
  pe ||= data.length
@@ -149,9 +167,9 @@ begin
149
167
  act = 0
150
168
  end
151
169
 
152
- # line 39 "lib/halunke/lexer.rl"
170
+ # line 51 "lib/halunke/lexer.rl"
153
171
 
154
- # line 155 "lib/halunke/lexer.rb"
172
+ # line 173 "lib/halunke/lexer.rb"
155
173
  begin
156
174
  _klen, _trans, _keys, _acts, _nacts = nil
157
175
  _goto_level = 0
@@ -181,7 +199,7 @@ begin
181
199
  begin
182
200
  ts = p
183
201
  end
184
- # line 185 "lib/halunke/lexer.rb"
202
+ # line 203 "lib/halunke/lexer.rb"
185
203
  end # from state action switch
186
204
  end
187
205
  if _trigger_goto
@@ -253,73 +271,127 @@ when 2 then
253
271
  te = p+1
254
272
  end
255
273
  when 3 then
256
- # line 14 "lib/halunke/lexer.rl"
274
+ # line 22 "lib/halunke/lexer.rl"
257
275
  begin
258
- act = 1; end
276
+ act = 3; end
259
277
  when 4 then
260
- # line 19 "lib/halunke/lexer.rl"
278
+ # line 33 "lib/halunke/lexer.rl"
261
279
  begin
262
- act = 6; end
280
+ act = 14; end
263
281
  when 5 then
264
- # line 15 "lib/halunke/lexer.rl"
282
+ # line 21 "lib/halunke/lexer.rl"
265
283
  begin
266
284
  te = p+1
267
285
  begin emit(:STRING, data[ts+1...te-1]) end
268
286
  end
269
287
  when 6 then
270
- # line 17 "lib/halunke/lexer.rl"
288
+ # line 24 "lib/halunke/lexer.rl"
271
289
  begin
272
290
  te = p+1
273
291
  begin emit(:OPEN_PAREN, data[ts...te]) end
274
292
  end
275
293
  when 7 then
276
- # line 18 "lib/halunke/lexer.rl"
294
+ # line 25 "lib/halunke/lexer.rl"
277
295
  begin
278
296
  te = p+1
279
297
  begin emit(:CLOSE_PAREN, data[ts...te]) end
280
298
  end
281
299
  when 8 then
282
- # line 20 "lib/halunke/lexer.rl"
300
+ # line 26 "lib/halunke/lexer.rl"
283
301
  begin
284
302
  te = p+1
303
+ begin emit(:OPEN_CURLY, data[ts...te]) end
285
304
  end
286
305
  when 9 then
287
- # line 21 "lib/halunke/lexer.rl"
306
+ # line 27 "lib/halunke/lexer.rl"
288
307
  begin
289
308
  te = p+1
290
- begin raise "Could not lex '#{ data[ts...te] }'" end
309
+ begin emit(:CLOSE_CURLY, data[ts...te]) end
291
310
  end
292
311
  when 10 then
293
- # line 16 "lib/halunke/lexer.rl"
312
+ # line 28 "lib/halunke/lexer.rl"
313
+ begin
314
+ te = p+1
315
+ begin emit(:OPEN_BRACKET, data[ts...te]) end
316
+ end
317
+ when 11 then
318
+ # line 29 "lib/halunke/lexer.rl"
319
+ begin
320
+ te = p+1
321
+ begin emit(:CLOSE_BRACKET, data[ts...te]) end
322
+ end
323
+ when 12 then
324
+ # line 30 "lib/halunke/lexer.rl"
325
+ begin
326
+ te = p+1
327
+ begin emit(:BAR, data[ts...te]) end
328
+ end
329
+ when 13 then
330
+ # line 31 "lib/halunke/lexer.rl"
331
+ begin
332
+ te = p+1
333
+ begin emit(:OPERATOR, data[ts ... te]) end
334
+ end
335
+ when 14 then
336
+ # line 32 "lib/halunke/lexer.rl"
337
+ begin
338
+ te = p+1
339
+ end
340
+ when 15 then
341
+ # line 33 "lib/halunke/lexer.rl"
342
+ begin
343
+ te = p+1
344
+ begin raise "Could not lex '#{ data[ts...te] }'" end
345
+ end
346
+ when 16 then
347
+ # line 20 "lib/halunke/lexer.rl"
348
+ begin
349
+ te = p
350
+ p = p - 1; begin emit(:NUMBER, data[ts...te].to_r) end
351
+ end
352
+ when 17 then
353
+ # line 23 "lib/halunke/lexer.rl"
294
354
  begin
295
355
  te = p
296
356
  p = p - 1; begin emit(:BAREWORD, data[ts...te]) end
297
357
  end
298
- when 11 then
299
- # line 21 "lib/halunke/lexer.rl"
358
+ when 18 then
359
+ # line 31 "lib/halunke/lexer.rl"
360
+ begin
361
+ te = p
362
+ p = p - 1; begin emit(:OPERATOR, data[ts ... te]) end
363
+ end
364
+ when 19 then
365
+ # line 33 "lib/halunke/lexer.rl"
300
366
  begin
301
367
  te = p
302
368
  p = p - 1; begin raise "Could not lex '#{ data[ts...te] }'" end
303
369
  end
304
- when 12 then
305
- # line 21 "lib/halunke/lexer.rl"
370
+ when 20 then
371
+ # line 20 "lib/halunke/lexer.rl"
372
+ begin
373
+ begin p = ((te))-1; end
374
+ begin emit(:NUMBER, data[ts...te].to_r) end
375
+ end
376
+ when 21 then
377
+ # line 33 "lib/halunke/lexer.rl"
306
378
  begin
307
379
  begin p = ((te))-1; end
308
380
  begin raise "Could not lex '#{ data[ts...te] }'" end
309
381
  end
310
- when 13 then
382
+ when 22 then
311
383
  # line 1 "NONE"
312
384
  begin
313
385
  case act
314
- when 1 then
386
+ when 3 then
315
387
  begin begin p = ((te))-1; end
316
- emit(:NUMBER, data[ts...te].to_i) end
317
- when 6 then
388
+ emit(:UNASSIGNED_BAREWORD, data[ts+1 ...te]) end
389
+ when 14 then
318
390
  begin begin p = ((te))-1; end
319
- emit(:OPERATOR, data[ts ... te]) end
391
+ raise "Could not lex '#{ data[ts...te] }'" end
320
392
  end
321
393
  end
322
- # line 323 "lib/halunke/lexer.rb"
394
+ # line 395 "lib/halunke/lexer.rb"
323
395
  end # action switch
324
396
  end
325
397
  end
@@ -339,7 +411,7 @@ when 0 then
339
411
  # line 1 "NONE"
340
412
  begin
341
413
  ts = nil; end
342
- # line 343 "lib/halunke/lexer.rb"
414
+ # line 415 "lib/halunke/lexer.rb"
343
415
  end # to state action switch
344
416
  end
345
417
  if _trigger_goto
@@ -366,7 +438,7 @@ end
366
438
  end
367
439
  end
368
440
 
369
- # line 40 "lib/halunke/lexer.rl"
441
+ # line 52 "lib/halunke/lexer.rl"
370
442
 
371
443
  @tokens
372
444
  end
@@ -2,20 +2,32 @@
2
2
  %%{
3
3
  machine lexer;
4
4
 
5
- number = ('+'|'-')?[0-9]+;
5
+ number = ('+'|'-')?[0-9]+('.'[0-9]+)?;
6
6
  string = '"' [^"]* '"';
7
+ unassigned_bareword = "'" [a-zA-Z_]+;
7
8
  bareword = [a-zA-Z_]+;
8
9
  open_paren = '(';
9
10
  close_paren = ')';
10
- operator = '+' | '-';
11
+ open_curly = '{';
12
+ close_curly = '}';
13
+ open_bracket = '[';
14
+ close_bracket = ']';
15
+ bar = "|";
16
+ operator = '+' | '-' | '<' | '>' | '=';
11
17
 
12
18
  main := |*
13
19
 
14
- number => { emit(:NUMBER, data[ts...te].to_i) };
20
+ number => { emit(:NUMBER, data[ts...te].to_r) };
15
21
  string => { emit(:STRING, data[ts+1...te-1]) };
22
+ unassigned_bareword => { emit(:UNASSIGNED_BAREWORD, data[ts+1 ...te]) };
16
23
  bareword => { emit(:BAREWORD, data[ts...te]) };
17
24
  open_paren => { emit(:OPEN_PAREN, data[ts...te]) };
18
25
  close_paren => { emit(:CLOSE_PAREN, data[ts...te]) };
26
+ open_curly => { emit(:OPEN_CURLY, data[ts...te]) };
27
+ close_curly => { emit(:CLOSE_CURLY, data[ts...te]) };
28
+ open_bracket => { emit(:OPEN_BRACKET, data[ts...te]) };
29
+ close_bracket => { emit(:CLOSE_BRACKET, data[ts...te]) };
30
+ bar => { emit(:BAR, data[ts...te]) };
19
31
  operator => { emit(:OPERATOR, data[ts ... te]) };
20
32
  space;
21
33
  any => { raise "Could not lex '#{ data[ts...te] }'" };
@@ -25,31 +25,69 @@ module Halunke
25
25
 
26
26
  class NumberNode < LiteralNode
27
27
  def eval(context)
28
- context[:Number].create_instance(value)
28
+ context["Number"].create_instance(value)
29
29
  end
30
30
  end
31
31
 
32
32
  class StringNode < LiteralNode
33
33
  def eval(context)
34
- context[:String].create_instance(value)
34
+ context["String"].create_instance(value)
35
35
  end
36
36
  end
37
37
 
38
38
  class BarewordNode < LiteralNode
39
+ def eval(context)
40
+ context[value]
41
+ end
42
+ end
43
+
44
+ UnassignedNode = Struct.new(:node) do
45
+ def eval(context)
46
+ raise "Not unassigned: #{node.value} has value #{context[node.value].inspect}" if context.key? node.value
47
+ context["UnassignedBareword"].create_instance(node.value)
48
+ end
49
+ end
50
+
51
+ FunctionNode = Struct.new(:params, :body) do
52
+ def eval(_context)
53
+ signature = params.nodes.map(&:node).map(&:value)
54
+
55
+ HFunction.new(signature, lambda { |context|
56
+ body.eval(context)
57
+ })
58
+ end
59
+ end
60
+
61
+ ArrayNode = Struct.new(:nodes) do
62
+ def initialize(nodes = [])
63
+ super(nodes)
64
+ end
65
+
66
+ def eval(context)
67
+ context["Array"].create_instance(nodes.map { |node| node.eval(context) })
68
+ end
39
69
  end
40
70
 
41
71
  MessageSendNode = Struct.new(:receiver, :message) do
42
72
  def eval(context)
43
- receiver.eval(context).receive_message(*message.eval(context))
73
+ receiver.eval(context).receive_message(context, *message.eval(context))
44
74
  end
45
75
  end
46
76
 
47
77
  MessageNode = Struct.new(:nodes) do
48
78
  def eval(context)
49
- case nodes.length
50
- when 1 then [nodes[0].value, []]
51
- when 2 then [nodes[0].value, [nodes[1].eval(context)]]
52
- else raise "Not implemented"
79
+ if nodes.length == 1
80
+ [nodes[0].value, []]
81
+ elsif nodes.length.even?
82
+ name = []
83
+ message = []
84
+ nodes.each_slice(2) do |name_part, value|
85
+ name.push(name_part.value)
86
+ message.push(value.eval(context))
87
+ end
88
+ [name.join(" "), message]
89
+ else
90
+ raise "Parse Error"
53
91
  end
54
92
  end
55
93
  end
@@ -13,7 +13,7 @@ require "halunke/nodes"
13
13
  module Halunke
14
14
  class Parser < Racc::Parser
15
15
 
16
- module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 46)
16
+ module_eval(<<'...end grammar.y/module_eval...', 'grammar.y', 64)
17
17
 
18
18
  def parse(code)
19
19
  @tokens = Lexer.new.tokenize(code)
@@ -27,52 +27,74 @@ end
27
27
  ##### State transition tables begin ###
28
28
 
29
29
  racc_action_table = [
30
- 6, 7, 8, 5, 10, 9, 6, 7, 8, 12,
31
- 15, 9, 6, 7, 8, nil, nil, 9, 6, 7,
32
- 8, nil, nil, 9 ]
30
+ 8, 9, 10, 6, 13, 5, 20, 11, 12, 7,
31
+ 21, 17, 8, 9, 10, 6, 25, 5, 27, 11,
32
+ 12, 7, 8, 9, 10, 6, 28, 5, 29, 11,
33
+ 12, 7, 8, 9, 10, 6, 25, 5, 31, 11,
34
+ 12, 7, 8, 9, 10, 6, nil, 5, nil, 11,
35
+ 12, 7, 8, 9, 10, 6, nil, 5, nil, 11,
36
+ 12, 7, 8, 9, 10, 6, nil, 5, nil, 11,
37
+ 12, 7 ]
33
38
 
34
39
  racc_action_check = [
35
- 0, 0, 0, 0, 1, 0, 5, 5, 5, 10,
36
- 13, 5, 11, 11, 11, nil, nil, 11, 14, 14,
37
- 14, nil, nil, 14 ]
40
+ 5, 5, 5, 5, 1, 5, 13, 5, 5, 5,
41
+ 15, 5, 0, 0, 0, 0, 17, 0, 19, 0,
42
+ 0, 0, 3, 3, 3, 3, 22, 3, 23, 3,
43
+ 3, 3, 6, 6, 6, 6, 24, 6, 26, 6,
44
+ 6, 6, 7, 7, 7, 7, nil, 7, nil, 7,
45
+ 7, 7, 16, 16, 16, 16, nil, 16, nil, 16,
46
+ 16, 16, 18, 18, 18, 18, nil, 18, nil, 18,
47
+ 18, 18 ]
38
48
 
39
49
  racc_action_pointer = [
40
- -2, 4, nil, nil, nil, 4, nil, nil, nil, nil,
41
- 9, 10, nil, 4, 16, nil, nil ]
50
+ 10, 4, nil, 20, nil, -2, 30, 40, nil, nil,
51
+ nil, nil, nil, 6, nil, 2, 50, 6, 60, 6,
52
+ nil, nil, 18, 15, 26, nil, 32, nil, nil, nil,
53
+ nil, nil ]
42
54
 
43
55
  racc_action_default = [
44
- -1, -12, -2, -3, -4, -12, -8, -9, -10, -11,
45
- -12, -6, 17, -12, -6, -5, -7 ]
56
+ -2, -18, -1, -2, -4, -2, -18, -2, -13, -14,
57
+ -15, -16, -17, -18, -3, -18, -2, -10, -2, -18,
58
+ 32, -5, -18, -18, -10, -12, -18, -8, -6, -9,
59
+ -11, -7 ]
46
60
 
47
61
  racc_goto_table = [
48
- 4, 13, 1, 2, 16, 11, 3 ]
62
+ 2, 23, 1, 14, 18, 15, 16, 19, 30, nil,
63
+ nil, nil, nil, nil, nil, nil, 22, nil, 26 ]
49
64
 
50
65
  racc_goto_check = [
51
- 4, 5, 1, 2, 5, 4, 3 ]
66
+ 2, 6, 1, 2, 3, 2, 5, 2, 6, nil,
67
+ nil, nil, nil, nil, nil, nil, 2, nil, 2 ]
52
68
 
53
69
  racc_goto_pointer = [
54
- nil, 2, 3, 6, 0, -10 ]
70
+ nil, 2, 0, -2, nil, 1, -16, nil ]
55
71
 
56
72
  racc_goto_default = [
57
- nil, nil, nil, nil, 14, nil ]
73
+ nil, nil, nil, 3, 4, nil, nil, 24 ]
58
74
 
59
75
  racc_reduce_table = [
60
76
  0, 0, :racc_error,
61
- 0, 9, :_reduce_1,
62
- 1, 9, :_reduce_2,
63
- 1, 10, :_reduce_3,
64
- 1, 11, :_reduce_none,
65
- 4, 11, :_reduce_5,
66
- 0, 13, :_reduce_6,
67
- 2, 13, :_reduce_7,
68
- 1, 12, :_reduce_8,
69
- 1, 12, :_reduce_9,
70
- 1, 12, :_reduce_10,
71
- 1, 12, :_reduce_11 ]
72
-
73
- racc_reduce_n = 12
74
-
75
- racc_shift_n = 17
77
+ 1, 15, :_reduce_1,
78
+ 0, 16, :_reduce_2,
79
+ 2, 16, :_reduce_3,
80
+ 1, 17, :_reduce_none,
81
+ 3, 17, :_reduce_5,
82
+ 4, 17, :_reduce_6,
83
+ 4, 17, :_reduce_7,
84
+ 3, 17, :_reduce_8,
85
+ 3, 19, :_reduce_9,
86
+ 0, 20, :_reduce_10,
87
+ 2, 20, :_reduce_11,
88
+ 1, 21, :_reduce_12,
89
+ 1, 18, :_reduce_13,
90
+ 1, 18, :_reduce_14,
91
+ 1, 18, :_reduce_15,
92
+ 1, 18, :_reduce_16,
93
+ 1, 18, :_reduce_17 ]
94
+
95
+ racc_reduce_n = 18
96
+
97
+ racc_shift_n = 32
76
98
 
77
99
  racc_token_table = {
78
100
  false => 0,
@@ -82,9 +104,15 @@ racc_token_table = {
82
104
  :BAREWORD => 4,
83
105
  :OPEN_PAREN => 5,
84
106
  :CLOSE_PAREN => 6,
85
- :OPERATOR => 7 }
107
+ :OPEN_CURLY => 7,
108
+ :CLOSE_CURLY => 8,
109
+ :OPERATOR => 9,
110
+ :UNASSIGNED_BAREWORD => 10,
111
+ :OPEN_BRACKET => 11,
112
+ :CLOSE_BRACKET => 12,
113
+ :BAR => 13 }
86
114
 
87
- racc_nt_base = 8
115
+ racc_nt_base = 14
88
116
 
89
117
  racc_use_result_var = true
90
118
 
@@ -112,13 +140,21 @@ Racc_token_to_s_table = [
112
140
  "BAREWORD",
113
141
  "OPEN_PAREN",
114
142
  "CLOSE_PAREN",
143
+ "OPEN_CURLY",
144
+ "CLOSE_CURLY",
115
145
  "OPERATOR",
146
+ "UNASSIGNED_BAREWORD",
147
+ "OPEN_BRACKET",
148
+ "CLOSE_BRACKET",
149
+ "BAR",
116
150
  "$start",
117
151
  "Program",
118
152
  "Expressions",
119
153
  "Expression",
120
154
  "Literal",
121
- "Literals" ]
155
+ "Args",
156
+ "UnassignedBarewords",
157
+ "UnassignedBareword" ]
122
158
 
123
159
  Racc_debug_parser = false
124
160
 
@@ -126,78 +162,120 @@ Racc_debug_parser = false
126
162
 
127
163
  # reduce 0 omitted
128
164
 
129
- module_eval(<<'.,.,', 'grammar.y', 11)
165
+ module_eval(<<'.,.,', 'grammar.y', 17)
130
166
  def _reduce_1(val, _values, result)
131
- result = Nodes.new
167
+ result = val[0]
132
168
  result
133
169
  end
134
170
  .,.,
135
171
 
136
- module_eval(<<'.,.,', 'grammar.y', 12)
172
+ module_eval(<<'.,.,', 'grammar.y', 21)
137
173
  def _reduce_2(val, _values, result)
138
- result = val[0]
174
+ result = Nodes.new
139
175
  result
140
176
  end
141
177
  .,.,
142
178
 
143
- module_eval(<<'.,.,', 'grammar.y', 16)
179
+ module_eval(<<'.,.,', 'grammar.y', 22)
144
180
  def _reduce_3(val, _values, result)
145
- result = Nodes.new(val)
181
+ result = Nodes.new([val[0]]).concat(val[1])
146
182
  result
147
183
  end
148
184
  .,.,
149
185
 
150
186
  # reduce 4 omitted
151
187
 
152
- module_eval(<<'.,.,', 'grammar.y', 21)
188
+ module_eval(<<'.,.,', 'grammar.y', 27)
153
189
  def _reduce_5(val, _values, result)
154
- result = Halunke::MessageSendNode.new(val[1], MessageNode.new(val[2].nodes))
190
+ result = Halunke::FunctionNode.new(Halunke::ArrayNode.new([]), val[1])
155
191
  result
156
192
  end
157
193
  .,.,
158
194
 
159
- module_eval(<<'.,.,', 'grammar.y', 25)
195
+ module_eval(<<'.,.,', 'grammar.y', 28)
160
196
  def _reduce_6(val, _values, result)
161
- result = Nodes.new
197
+ result = Halunke::FunctionNode.new(val[1], val[2])
162
198
  result
163
199
  end
164
200
  .,.,
165
201
 
166
- module_eval(<<'.,.,', 'grammar.y', 26)
202
+ module_eval(<<'.,.,', 'grammar.y', 29)
167
203
  def _reduce_7(val, _values, result)
168
- result = Nodes.new([val[0]]).concat(val[1])
204
+ result = Halunke::MessageSendNode.new(val[1], MessageNode.new(val[2].nodes))
169
205
  result
170
206
  end
171
207
  .,.,
172
208
 
173
209
  module_eval(<<'.,.,', 'grammar.y', 30)
174
210
  def _reduce_8(val, _values, result)
175
- result = NumberNode.new(val[0])
211
+ result = ArrayNode.new(val[1].nodes)
176
212
  result
177
213
  end
178
214
  .,.,
179
215
 
180
- module_eval(<<'.,.,', 'grammar.y', 31)
216
+ module_eval(<<'.,.,', 'grammar.y', 34)
181
217
  def _reduce_9(val, _values, result)
182
- result = StringNode.new(val[0])
218
+ result = Halunke::ArrayNode.new(val[1].nodes)
183
219
  result
184
220
  end
185
221
  .,.,
186
222
 
187
- module_eval(<<'.,.,', 'grammar.y', 33)
223
+ module_eval(<<'.,.,', 'grammar.y', 38)
188
224
  def _reduce_10(val, _values, result)
189
- result = BarewordNode.new(val[0])
225
+ result = Nodes.new
190
226
  result
191
227
  end
192
228
  .,.,
193
229
 
194
- module_eval(<<'.,.,', 'grammar.y', 34)
230
+ module_eval(<<'.,.,', 'grammar.y', 39)
195
231
  def _reduce_11(val, _values, result)
232
+ result = Nodes.new([val[0]]).concat(val[1])
233
+ result
234
+ end
235
+ .,.,
236
+
237
+ module_eval(<<'.,.,', 'grammar.y', 43)
238
+ def _reduce_12(val, _values, result)
239
+ result = UnassignedNode.new(BarewordNode.new(val[0]))
240
+ result
241
+ end
242
+ .,.,
243
+
244
+ module_eval(<<'.,.,', 'grammar.y', 47)
245
+ def _reduce_13(val, _values, result)
246
+ result = NumberNode.new(val[0])
247
+ result
248
+ end
249
+ .,.,
250
+
251
+ module_eval(<<'.,.,', 'grammar.y', 48)
252
+ def _reduce_14(val, _values, result)
253
+ result = StringNode.new(val[0])
254
+ result
255
+ end
256
+ .,.,
257
+
258
+ module_eval(<<'.,.,', 'grammar.y', 50)
259
+ def _reduce_15(val, _values, result)
196
260
  result = BarewordNode.new(val[0])
197
261
  result
198
262
  end
199
263
  .,.,
200
264
 
265
+ module_eval(<<'.,.,', 'grammar.y', 51)
266
+ def _reduce_16(val, _values, result)
267
+ result = BarewordNode.new(val[0])
268
+ result
269
+ end
270
+ .,.,
271
+
272
+ module_eval(<<'.,.,', 'grammar.y', 52)
273
+ def _reduce_17(val, _values, result)
274
+ result = UnassignedNode.new(BarewordNode.new(val[0]))
275
+ result
276
+ end
277
+ .,.,
278
+
201
279
  def _reduce_none(val, _values, result)
202
280
  val[0]
203
281
  end
@@ -1,41 +1,222 @@
1
1
  # This file is not tested directly right now,
2
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
3
4
  module Halunke
4
- class NativeClass
5
- def initialize(methods)
5
+ class HClass
6
+ def initialize(name, methods)
7
+ @name = name
6
8
  @runtime_methods = methods
7
9
  end
8
10
 
9
- def create_instance(ruby_value)
10
- NativeObject.new(self, ruby_value)
11
+ def create_instance(ruby_value = nil)
12
+ HObject.new(self, ruby_value)
11
13
  end
12
14
 
13
15
  def lookup(message)
14
- @runtime_methods[message]
16
+ @runtime_methods.fetch(message)
17
+ rescue KeyError
18
+ raise "Class #{@name} has no method to respond to message '#{message}'"
15
19
  end
16
20
  end
17
21
 
18
- class NativeObject
22
+ class HObject
19
23
  attr_reader :ruby_value
20
24
 
21
- def initialize(runtime_class, ruby_value)
25
+ def initialize(runtime_class, ruby_value = nil)
22
26
  @runtime_class = runtime_class
23
27
  @ruby_value = ruby_value
24
28
  end
25
29
 
26
- def receive_message(message_name, message_value)
30
+ def receive_message(context, message_name, message_value)
27
31
  m = @runtime_class.lookup(message_name)
28
- m.call(self, message_value)
32
+ m.call(context, [self].concat(message_value))
33
+ end
34
+
35
+ def inspect(context)
36
+ receive_message(context, "inspect", []).ruby_value
29
37
  end
30
38
  end
31
39
 
32
- class NativeFunction
33
- def initialize(fn)
40
+ class HFunction
41
+ def initialize(signature, fn)
42
+ @signature = signature
34
43
  @fn = fn
35
44
  end
36
45
 
37
- def call(receiver, args)
38
- @fn.call(receiver, args)
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
39
103
  end
40
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
+ )
41
222
  end
@@ -1,3 +1,3 @@
1
1
  module Halunke
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: halunke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lucas Dohmen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-03 00:00:00.000000000 Z
11
+ date: 2018-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler