forked from rakudo/rakudo
-
Notifications
You must be signed in to change notification settings - Fork 1
/
perl6.pir
488 lines (409 loc) · 11.9 KB
/
perl6.pir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
=head1 TITLE
perl6.pir - The Rakudo Perl 6 compiler.
=head2 Description
This is the base file for the Rakudo Perl 6 compiler.
=cut
# Set RAKUDO_HLL to 'perl6' to try compiling Rakudo in its own HLL.
# MUST BE LOWERCASE
.macro_const RAKUDO_HLL 'perl6'
.HLL .RAKUDO_HLL
.loadlib 'perl6_group'
.loadlib 'perl6_ops'
.namespace []
.sub '' :anon :init :load
.local pmc p6meta
load_bytecode 'PCT.pbc'
$P0 = get_root_global ['parrot'], 'P6metaclass'
$P0.'new_class'('Perl6Object', 'name'=>'Object')
p6meta = $P0.'HOW'()
set_hll_global ['Perl6Object'], '$!P6META', p6meta
.local pmc hllns, parrotns, imports, exports
hllns = get_hll_namespace
parrotns = get_root_namespace ['parrot']
imports = split ' ', 'PAST PGE PCT'
exports = split ' ', '!DISPATCH_JUNCTION_MULTI'
parrotns.'export_to'(hllns, imports)
hllns.'export_to'(parrotns, exports)
.end
.include 'src/gen_builtins.pir'
=head2 Functions
=over 4
=item onload()
Creates the Perl 6 compiler by subclassing a C<PCT::HLLCompiler> object.
=cut
.namespace ['Perl6';'Compiler']
.sub 'onload' :load :init :anon
load_bytecode 'PCT.pbc'
.local pmc p6meta, perl6
p6meta = get_hll_global ['Perl6Object'], '$!P6META'
perl6 = p6meta.'new_class'('Perl6::Compiler', 'parent'=>'PCT::HLLCompiler')
load_bytecode 'config.pbc'
perl6.'language'('perl6')
$P0 = get_hll_namespace ['Perl6';'Grammar']
perl6.'parsegrammar'($P0)
$P0 = get_hll_namespace ['Perl6';'Grammar';'Actions']
perl6.'parseactions'($P0)
## set the compilation stages in the @stages attribute
$P0 = split ' ', 'parse past check_syntax post pir evalpmc'
setattribute perl6, '@stages', $P0
## set the command line options
$P0 = split ' ', 'c e=s help|h target=s dumper=s trace|t=s encoding=s output|o=s version|v'
setattribute perl6, '@cmdoptions', $P0
## set the $usage attribute
$P0 = new 'String'
$P0 = <<'USAGE'
Usage: perl6 [switches] [--] [programfile] [arguments]
-c check syntax only (runs BEGIN and CHECK blocks)
-e program one line of program
-h, --help display this help text
--target=[stage] specify compilation stage to emit
-t, --trace=[flags] enable trace flags
--encoding=[mode] specify string encoding mode
-o, --output=[name] specify name of output file
-v, --version display version information
USAGE
setattribute perl6, '$usage', $P0
## set the $version attribute
.local pmc cfg
$P0 = new 'String'
$P0 = 'This is Rakudo Perl 6'
push_eh _handler
# currently works in the build tree, but not in the install tree
cfg = _config()
$P0 .= ', revision '
$S0 = cfg['revision']
$P0 .= $S0
$P0 .= ' built on parrot '
$S0 = cfg['VERSION']
$P0 .= $S0
$S0 = cfg['DEVEL']
$P0 .= $S0
$P0 .= "\n"
$P0 .= 'for '
$S0 = cfg['archname']
$P0 .= $S0
_handler:
pop_eh
$P0 .= ".\n\nCopyright 2006-2008, The Perl Foundation.\n"
setattribute perl6, '$version', $P0
$P0 = box .RAKUDO_HLL
set_hll_global ['Perl6';'Grammar';'Actions'], '$?RAKUDO_HLL', $P0
## create an array for holding the stack of nested blocks
$P99 = get_hll_global 'Array'
$P0 = $P99.'new'()
set_hll_global ['Perl6';'Grammar';'Actions'], '@?BLOCK', $P0
## create a list for holding the stack of nested package
## declarators
$P0 = $P99.'new'()
set_hll_global ['Perl6';'Grammar';'Actions'], '@?PKGDECL', $P0
## create a list for holding the stack of nested scope
## declarators
$P0 = $P99.'new'()
set_hll_global ['Perl6';'Grammar';'Actions'], '@?SCOPE', $P0
## create a list of END blocks to be run
$P0 = $P99.'new'()
set_hll_global ['Perl6'], '@?END_BLOCKS', $P0
## create a list for holding the stack of nested package
## namespaces (we store the namespace as a flat, ::
## separated string for now, for handing to .parse_name)
$P0 = $P99.'new'()
set_hll_global ['Perl6';'Grammar';'Actions'], '@?NS', $P0
## create a (shared) metaclass node
$P0 = get_hll_global ['PAST'], 'Var'
$P0 = $P0.'new'( 'name'=>'metaclass', 'scope'=>'register' )
set_hll_global ['Perl6';'Grammar';'Actions'], '$?METACLASS', $P0
## create the $?CLASSMAP hash
$P0 = get_root_namespace ['parrot';'Hash']
$P0 = new $P0
set_hll_global ['Perl6';'Grammar';'Actions'], '%?CLASSMAP', $P0
## tell PAST::Var how to encode Perl6Str and Str values
$P0 = get_hll_global ['PAST';'Compiler'], '%valflags'
$P0['Perl6Str'] = 'e'
$P0['Str'] = 'e'
.end
.include 'src/gen_setting.pir'
.include 'src/gen_grammar.pir'
.include 'src/parser/expression.pir'
.include 'src/parser/methods.pir'
.include 'src/parser/quote_expression.pir'
.include 'src/gen_actions.pir'
.include 'src/gen_metaop.pir'
.include 'src/gen_junction.pir'
.include 'src/gen_whatever.pir'
.namespace ['Perl6';'Compiler']
=item check_syntax(source [, "option" => value, ...])
Check the syntax of C<source> after PAST tree has been built,
to ensure C<BEGIN> and C<CHECK> blocks have been executed.
=cut
.sub 'check_syntax' :method
.param pmc source
.param pmc adverbs :slurpy :named
$I0 = adverbs['c']
if $I0 goto check_syntax
.return ()
check_syntax:
## if we're here, then syntax is OK
say 'syntax OK'
exit 0
.end
=item eval(code [, "option" => value, ...])
Compile and execute the given C<code> taking into account any
options provided. We subclass the HLLCompiler version to catch
and report exceptions.
=cut
.sub 'eval' :method
.param pmc code
.param pmc args :slurpy
.param pmc adverbs :slurpy :named
$P0 = get_root_global ['parrot';'PCT';'HLLCompiler'], 'eval'
push_eh trap_errors
$P0 = $P0(self, code, args :flat, adverbs :flat :named)
pop_eh
.return ($P0)
trap_errors:
.local pmc exception, bt, it, cur_block, anno
.get_results (exception)
$I0 = exception['severity']
if $I0 == .EXCEPT_EXIT goto exit
if $I0 != .EXCEPT_WARNING goto not_warning
printerr exception
printerr "\n"
$P0 = exception["resume"]
$P0()
not_warning:
pop_eh
bt = exception.'backtrace'()
it = iter bt
# If the first entry is "die", skip it.
cur_block = bt[0]
if null cur_block goto not_die
$P0 = cur_block['sub']
$S0 = $P0
if $S0 != 'die' goto not_die
$P0 = shift bt
not_die:
# Show the exception message.
$S0 = exception
if $S0 == "" goto no_message
printerr $S0
$I0 = index $S0, "\n"
if $I0 > 0 goto message_done
printerr "\n"
goto message_done
no_message:
$I0 = exception['type']
if $I0 == .CONTROL_RETURN goto uncaught_return
printerr "Died\n"
goto message_done
uncaught_return:
printerr "Can't return outside a routine\n"
message_done:
# Now we'll go back, printing one line/file per routine.
.local pmc cur_sub
.local string cur_info
.local string intro
cur_info = ""
intro = "in "
it_loop:
unless it goto it_loop_end
cur_block = shift it
if cur_info != "" goto got_cur_info
cur_info = 'format_location'(cur_block)
got_cur_info:
cur_sub = cur_block['sub']
if null cur_sub goto it_loop
$P0 = getprop '$!real_self', cur_sub
if null $P0 goto already_real
cur_sub = $P0
already_real:
$I0 = isa cur_sub, 'Routine'
unless $I0 goto it_loop
# Show entry.
printerr intro
intro = "called from "
$P0 = cur_sub.'WHAT'()
$S0 = $P0.'perl'()
$S0 = downcase $S0
printerr $S0
printerr " "
$P0 = cur_sub.'get_namespace'()
if null $P0 goto ns_done
$P0 = $P0.'get_name'()
$P1 = shift $P0
$S0 = join '::', $P0
if $S0 == "" goto ns_done
printerr $S0
printerr '::'
ns_done:
printerr cur_sub
printerr " "
printerr cur_info
printerr "\n"
cur_info = ""
goto it_loop
it_loop_end:
if cur_info == "" goto done
if cur_info == "(<unknown>:0)" goto done
printerr intro
printerr "Main "
printerr cur_info
printerr "\n"
done:
exit 1
exit:
pop_eh
exit 0
.end
.sub 'format_location'
.param pmc cur_block
.local pmc anno
anno = cur_block['annotations']
if null anno goto unknown
$S1 = anno['file']
if $S1 != "" goto have_file
$S1 = "<unknown>"
have_file:
$S0 = concat "(", $S1
concat $S0, ":"
$S1 = anno['line']
if $S1 != "" goto have_line
if $S0 == "(<unknown>:" goto unknown
$S1 = "<unknown>"
have_line:
concat $S0, $S1
concat $S0, ")"
.return ($S0)
unknown:
.return ("")
.end
=item main(args :slurpy) :main
Start compilation by passing any command line C<args>
to the Perl 6 compiler.
=cut
.sub 'main' :main
.param pmc args_str
$S0 = args_str[2]
$I0 = index $S0, '@INC'
if $I0 < 0 goto not_harness
exit 0
not_harness:
$P0 = compreg 'perl6'
$P1 = $P0.'command_line'(args_str, 'encoding'=>'utf8', 'transcode'=>'ascii')
.include 'iterator.pasm'
.local pmc iter
$P0 = get_hll_global ['Perl6'], '@?END_BLOCKS'
iter = new 'Iterator', $P0
iter = .ITERATE_FROM_END
iter_loop:
unless iter goto iter_end
$P0 = pop iter
$P0()
goto iter_loop
iter_end:
.end
.sub 'parse_name' :method
.param string name
## remove any type parameterization for now
.local string type_param
type_param = ''
$I0 = index name, '['
if $I0 == -1 goto type_param_done
type_param = substr name, $I0
name = substr name, 0, $I0
type_param_done:
## divide name based on ::
.local pmc list
list = split '::', name
## move any leading sigil to the last item
.local string sigil
$S0 = list[0]
sigil = substr $S0, 0, 1
$I0 = index '$@%&', $S1
if $I0 < 0 goto sigil_done
substr $S0, 0, 1, ''
list[0] = $S0
$S0 = list[-1]
$S0 = concat sigil, $S0
list[-1] = $S0
sigil_done:
## remove any empty items from the list
$P0 = iter list
list = new 'ResizablePMCArray'
iter_loop:
unless $P0 goto iter_done
$S0 = shift $P0
unless $S0 goto iter_loop
push list, $S0
goto iter_loop
iter_done:
if type_param == '' goto no_add_type_param
$S0 = pop list
concat $S0, type_param
push list, $S0
no_add_type_param:
.return (list)
.end
.sub 'fetch-library' :method
.param pmc request
.local pmc name, retval, library, inc_hash
name = request['name']
$S0 = join '::', name
retval = 'require'($S0, 'module'=>1)
if null retval goto fail
library = new 'Hash'
library['name'] = name
inc_hash = get_hll_global '%INC'
$S0 = inc_hash[$S0]
library['filename'] = $S0
$P0 = get_hll_global name, 'EXPORT'
library['symbols'] = $P0
$P0 = get_hll_namespace name
library['namespace'] = $P0
.return (library)
fail:
.return (retval)
.end
=back
=item postload()
Perform any tasks that need to be done at the end of loading.
Currently this does the equivalent of EXPORTALL on the core namespaces.
=cut
.namespace []
.sub '' :anon :load :init
.local pmc perl6, nslist, nsiter
perl6 = get_hll_global ['Perl6'], 'Compiler'
nslist = split ' ', 'Any'
nsiter = iter nslist
ns_loop:
unless nsiter goto ns_done
$S0 = shift nsiter
$S0 .= '::EXPORT::ALL'
$P0 = perl6.'parse_name'($S0)
.local pmc ns, symiter
ns = get_hll_namespace $P0
if null ns goto ns_loop
symiter = iter ns
sym_loop:
unless symiter goto sym_done
$S0 = shift symiter
$P0 = ns[$S0]
set_global $S0, $P0
goto sym_loop
sym_done:
goto ns_loop
ns_done:
.end
## This goes at the bottom because the methods end up in the 'parrot'
## HLL namespace.
.HLL 'parrot'
.include 'src/parrot/ClassHOW.pir'
.include 'src/parrot/Role.pir'
.include 'src/parrot/Protoobject.pir'
.include 'src/parrot/misc.pir'
.include 'src/parrot/state.pir'
.include 'src/gen_uprop.pir'
# Local Variables:
# mode: pir
# fill-column: 100
# End:
# vim: expandtab shiftwidth=4 ft=pir: