p-lang 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +38 -8
- data/Rakefile +0 -1
- data/VERSION.yml +3 -3
- data/bin/p-lang +36 -8
- data/lib/p-lang.rb +16 -26
- data/lib/parser/error.rb +32 -0
- data/lib/parser/lexer.rb +245 -0
- data/lib/parser/node.rb +23 -0
- data/lib/parser/syntax_analyser.rb +378 -0
- data/lib/parser/token.rb +19 -0
- data/lib/vm/core/pboolean.rb +27 -0
- data/lib/vm/core/pchar.rb +13 -0
- data/lib/vm/core/pdecimal.rb +130 -0
- data/lib/vm/core/pinteger.rb +125 -0
- data/lib/vm/core/pio.rb +16 -0
- data/lib/vm/core/plist.rb +33 -0
- data/lib/vm/core/pstring.rb +39 -0
- data/lib/vm/environment.rb +67 -42
- data/lib/vm/interpreter.rb +209 -0
- data/lib/vm/pfunctions.rb +46 -0
- data/lib/vm/plambda.rb +42 -0
- data/lib/vm/pobject.rb +44 -42
- data/test/test_lexer +34 -0
- data/test/test_lexer.rb +19 -0
- data/test/test_lexer_tokens +34 -0
- data/test/{test_parser_ok.txt → test_parser} +26 -27
- data/test/test_parser.rb +6 -13
- data/test/test_parser_build +73 -0
- data/test/test_vm +29 -0
- data/test/test_vm.rb +7 -10
- data/test/test_vm_result +29 -0
- metadata +31 -38
- data/bin/teste.p +0 -3
- data/lib/parser/ast.rb +0 -168
- data/lib/parser/nodes.rb +0 -212
- data/lib/parser/p-lang.treetop +0 -197
- data/lib/vm/perror.rb +0 -8
- data/lib/vm/proc.rb +0 -67
- data/lib/vm/std/pdecimal.rb +0 -42
- data/lib/vm/std/pinteger.rb +0 -42
- data/lib/vm/std/pio.rb +0 -17
- data/lib/vm/std/pstring.rb +0 -160
- data/lib/vm/vm.rb +0 -233
- data/test/test_parser_build.txt +0 -72
- data/test/test_vm_programs.txt +0 -64
- data/test/test_vm_results.txt +0 -64
data/lib/parser/node.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module PLang
|
2
|
+
module Parser
|
3
|
+
class Node
|
4
|
+
attr_reader :type
|
5
|
+
def initialize(type, params)
|
6
|
+
@type = type
|
7
|
+
@params = params
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(name, *args)
|
11
|
+
return @params[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
ret = [@type]
|
16
|
+
@params.each do |id, value|
|
17
|
+
ret << value
|
18
|
+
end
|
19
|
+
ret
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
module PLang
|
2
|
+
module Parser
|
3
|
+
class SyntaxAnalyser
|
4
|
+
def initialize(src)
|
5
|
+
@eof = Token.new(:eof)
|
6
|
+
@lexer = Lexer.new(src)
|
7
|
+
consume
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse
|
11
|
+
program
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def skip_breaks
|
17
|
+
while token
|
18
|
+
break unless token.type == :break
|
19
|
+
consume
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def program
|
24
|
+
p = []
|
25
|
+
skip_breaks
|
26
|
+
while token.type != :eof
|
27
|
+
p << expr
|
28
|
+
end
|
29
|
+
p
|
30
|
+
end
|
31
|
+
|
32
|
+
def expr
|
33
|
+
if token.type == :begin
|
34
|
+
ast = pbegin
|
35
|
+
elsif token.type == :list
|
36
|
+
ast = plist
|
37
|
+
elsif token.type == :if
|
38
|
+
ast = pif
|
39
|
+
elsif token.type == :not
|
40
|
+
ast = pnot
|
41
|
+
elsif ast = element
|
42
|
+
skip_breaks
|
43
|
+
case token.type
|
44
|
+
when :add, :sub, :mul, :div, :mod
|
45
|
+
ast = arithmetic(ast)
|
46
|
+
when :equal, :diff, :major, :major_equal, :minor, :minor_equal, :and, :or
|
47
|
+
ast = conditional(ast)
|
48
|
+
when :let
|
49
|
+
ast = let(ast)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
skip_breaks
|
53
|
+
ast
|
54
|
+
end
|
55
|
+
|
56
|
+
def plambda
|
57
|
+
|
58
|
+
if token.type == :lsquare
|
59
|
+
consume_and_skip_breaks
|
60
|
+
params = expr_list
|
61
|
+
if token.type == :pipe
|
62
|
+
consume_and_skip_breaks
|
63
|
+
body = expr
|
64
|
+
if token.type == :rsquare
|
65
|
+
consume
|
66
|
+
else
|
67
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ']'")
|
68
|
+
end
|
69
|
+
else
|
70
|
+
if token.type == :rsquare
|
71
|
+
if params.length == 1
|
72
|
+
body = params[0]
|
73
|
+
params = []
|
74
|
+
else
|
75
|
+
Error.syntax_error(token.line, token.src, token.i, "invalid function body")
|
76
|
+
end
|
77
|
+
consume
|
78
|
+
else
|
79
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ']'")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
if token.type == :colon
|
84
|
+
consume_and_skip_breaks
|
85
|
+
w = where
|
86
|
+
else
|
87
|
+
w = []
|
88
|
+
end
|
89
|
+
if token.type == :semicolon
|
90
|
+
consume_and_skip_breaks
|
91
|
+
return Node.new(:lambda, {:params => params, :body => body, :where => w, :next_lambda => plambda})
|
92
|
+
else
|
93
|
+
return Node.new(:lambda, {:params => params, :body => body, :where => w, :next_lambda => nil})
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def where
|
98
|
+
if token.type == :lround
|
99
|
+
consume_and_skip_breaks
|
100
|
+
ll = let_list
|
101
|
+
if token.type == :rround
|
102
|
+
consume
|
103
|
+
return ll
|
104
|
+
else
|
105
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def let_list
|
111
|
+
ll = []
|
112
|
+
e = element
|
113
|
+
if token.type == :let
|
114
|
+
e = let(e)
|
115
|
+
else
|
116
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '='")
|
117
|
+
end
|
118
|
+
ll << e
|
119
|
+
while token.type == :comma
|
120
|
+
consume_and_skip_breaks
|
121
|
+
e = element
|
122
|
+
if token.type == :let
|
123
|
+
e = let(e)
|
124
|
+
else
|
125
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '='")
|
126
|
+
end
|
127
|
+
ll << e
|
128
|
+
end
|
129
|
+
ll
|
130
|
+
end
|
131
|
+
|
132
|
+
def pobject
|
133
|
+
if token.type == :lcurly
|
134
|
+
consume_and_skip_breaks
|
135
|
+
id = token
|
136
|
+
if id.type == :id
|
137
|
+
consume_and_skip_breaks
|
138
|
+
if token.type == :colon
|
139
|
+
consume_and_skip_breaks
|
140
|
+
ast = Node.new(:object, {:id => Node.new(:id, {:value => id.value}), :params => expr_list})
|
141
|
+
if token.type == :rcurly
|
142
|
+
consume_and_skip_breaks
|
143
|
+
return ast
|
144
|
+
else
|
145
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '}'")
|
146
|
+
end
|
147
|
+
elsif token.type == :rcurly
|
148
|
+
consume_and_skip_breaks
|
149
|
+
ast = Node.new(:object, {:id => Node.new(:id, {:value => id.value}), :params => []})
|
150
|
+
else
|
151
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ':'")
|
152
|
+
end
|
153
|
+
else
|
154
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting an identifier")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def plist
|
160
|
+
if token.type == :list
|
161
|
+
consume
|
162
|
+
if token.type == :lround
|
163
|
+
consume_and_skip_breaks
|
164
|
+
if token.type == :rround
|
165
|
+
consume_and_skip_breaks
|
166
|
+
return Node.new(:list, {:elements => []})
|
167
|
+
end
|
168
|
+
e = expr_list
|
169
|
+
if token.type == :rround
|
170
|
+
consume_and_skip_breaks
|
171
|
+
return Node.new(:list, {:elements => e})
|
172
|
+
else
|
173
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
174
|
+
end
|
175
|
+
else
|
176
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '('")
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def pbegin
|
182
|
+
if token.type == :begin
|
183
|
+
consume
|
184
|
+
if token.type == :lround
|
185
|
+
consume_and_skip_breaks
|
186
|
+
e = expr_list
|
187
|
+
if token.type == :rround
|
188
|
+
consume_and_skip_breaks
|
189
|
+
return Node.new(:begin, {:expressions => e})
|
190
|
+
else
|
191
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
192
|
+
end
|
193
|
+
else
|
194
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '('")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def pif
|
200
|
+
if token.type == :if
|
201
|
+
consume
|
202
|
+
if token.type == :lround
|
203
|
+
consume_and_skip_breaks
|
204
|
+
cond = expr
|
205
|
+
if token.type == :comma
|
206
|
+
consume_and_skip_breaks
|
207
|
+
true_expr = expr
|
208
|
+
if token.type == :comma
|
209
|
+
consume_and_skip_breaks
|
210
|
+
false_expr = expr
|
211
|
+
if token.type == :rround
|
212
|
+
consume_and_skip_breaks
|
213
|
+
return Node.new(:if, {:condition=>cond, :true_expr => true_expr, :false_expr => false_expr})
|
214
|
+
else
|
215
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
216
|
+
end
|
217
|
+
else
|
218
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ','")
|
219
|
+
end
|
220
|
+
else
|
221
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ','")
|
222
|
+
end
|
223
|
+
else
|
224
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '('")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def expr_list
|
230
|
+
e = [expr]
|
231
|
+
while token.type == :comma
|
232
|
+
consume_and_skip_breaks
|
233
|
+
e << expr
|
234
|
+
end
|
235
|
+
e
|
236
|
+
end
|
237
|
+
|
238
|
+
def let(ast)
|
239
|
+
if token.type == :let
|
240
|
+
consume_and_skip_breaks
|
241
|
+
Node.new(:let, {:lhs => ast, :rhs => expr})
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def pnot
|
246
|
+
t = token
|
247
|
+
case t.type
|
248
|
+
when :not
|
249
|
+
consume_and_skip_breaks
|
250
|
+
Node.new(:not, {:lhs => expr})
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def conditional(ast)
|
255
|
+
t = token
|
256
|
+
case t.type
|
257
|
+
when :equal, :diff, :major, :major_equal, :minor, :minor_equal, :and, :or, :not
|
258
|
+
consume_and_skip_breaks
|
259
|
+
conditional(Node.new(t.type, {:lhs => ast, :rhs => element}))
|
260
|
+
else
|
261
|
+
ast
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def arithmetic(ast)
|
266
|
+
t = token
|
267
|
+
case t.type
|
268
|
+
when :add, :sub, :mul, :div, :mod
|
269
|
+
consume_and_skip_breaks
|
270
|
+
arithmetic(Node.new(t.type, {:lhs => ast, :rhs => element}))
|
271
|
+
else
|
272
|
+
ast
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def element
|
277
|
+
case token.type
|
278
|
+
when :integer, :decimal, :string, :char
|
279
|
+
t = token
|
280
|
+
consume
|
281
|
+
ast = Node.new(t.type, {:value => t.value})
|
282
|
+
when :true
|
283
|
+
t = token
|
284
|
+
consume
|
285
|
+
ast = Node.new(:boolean, {:value => :true})
|
286
|
+
when :false
|
287
|
+
t = token
|
288
|
+
consume
|
289
|
+
ast = Node.new(:boolean, {:value => :false})
|
290
|
+
when :lsquare
|
291
|
+
ast = plambda
|
292
|
+
if token.type == :lround
|
293
|
+
ast = pcall(ast)
|
294
|
+
end
|
295
|
+
when :lcurly
|
296
|
+
ast = pobject
|
297
|
+
when :id
|
298
|
+
t = token
|
299
|
+
consume
|
300
|
+
ast = Node.new(:id, {:value => t.value})
|
301
|
+
if token.type == :lround
|
302
|
+
ast = pcall(ast)
|
303
|
+
end
|
304
|
+
when :lround
|
305
|
+
consume_and_skip_breaks
|
306
|
+
e = expr
|
307
|
+
if token.type == :rround
|
308
|
+
consume
|
309
|
+
ast = e
|
310
|
+
else
|
311
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
312
|
+
end
|
313
|
+
else
|
314
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting '<element>'")
|
315
|
+
end
|
316
|
+
skip_breaks
|
317
|
+
if token.type == :arrow
|
318
|
+
ast = object_message(ast)
|
319
|
+
if token.type == :lround
|
320
|
+
ast = pcall(ast)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
ast
|
324
|
+
end
|
325
|
+
|
326
|
+
def pcall(ast)
|
327
|
+
consume_and_skip_breaks
|
328
|
+
params = []
|
329
|
+
params = expr_list unless token.type == :rround
|
330
|
+
if token.type == :rround
|
331
|
+
consume
|
332
|
+
ast = Node.new(:call, {:lambda => ast, :params => params})
|
333
|
+
if token.type == :lround
|
334
|
+
ast = pcall(ast)
|
335
|
+
end
|
336
|
+
if token.type == :arrow
|
337
|
+
ast = object_message(ast)
|
338
|
+
if token.type == :lround
|
339
|
+
ast = pcall(ast)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
else
|
343
|
+
Error.syntax_error(token.line, token.src, token.i, "unexpected '#{token.value}', expecting ')'")
|
344
|
+
end
|
345
|
+
ast
|
346
|
+
end
|
347
|
+
|
348
|
+
def object_message(ast)
|
349
|
+
if token.type == :arrow
|
350
|
+
consume_and_skip_breaks
|
351
|
+
id = token
|
352
|
+
if id.type == :id
|
353
|
+
consume
|
354
|
+
Node.new(:object_message, {:object => ast, :message => Node.new(:id, {:value=>id.value})})
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def consume
|
360
|
+
t = @lexer.next_token
|
361
|
+
if t
|
362
|
+
@token = t
|
363
|
+
else
|
364
|
+
@token.type = :eof
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def consume_and_skip_breaks
|
369
|
+
consume
|
370
|
+
skip_breaks
|
371
|
+
end
|
372
|
+
|
373
|
+
def token
|
374
|
+
@token || @eof
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
data/lib/parser/token.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module PLang
|
2
|
+
module Parser
|
3
|
+
class Token
|
4
|
+
attr_accessor :value
|
5
|
+
attr_accessor :type
|
6
|
+
attr_accessor :line
|
7
|
+
attr_accessor :i
|
8
|
+
attr_accessor :src
|
9
|
+
|
10
|
+
def initialize(type)
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"\#{#{type.to_s}: #{value}}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PLang
|
2
|
+
module VM
|
3
|
+
module PFunctions
|
4
|
+
def add_to_interpreter_boolean_functions
|
5
|
+
|
6
|
+
object_message "{boolean: x}", :_and do |object|
|
7
|
+
plambda "{boolean: y}" do |value|
|
8
|
+
PObject.new(:boolean, [(object.params[0] and value[0].params[0])])
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
object_message "{boolean: x}", :_or do |object|
|
13
|
+
plambda "{boolean: y}" do |value|
|
14
|
+
PObject.new(:boolean, [(object.params[0] or value[0].params[0])])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
object_message "{boolean: x}", :_not do |object|
|
19
|
+
plambda do
|
20
|
+
PObject.new(:boolean, [(not object.params[0])])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|