p-lang 0.1.1 → 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.
@@ -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
@@ -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