5
src/builtins/op.pir - Perl 6 builtin operators
15
## This is used by integer computations, to upgrade the answer and return a
16
## Num if we overflow. We may want to return something like a BigInt in the
17
## future, but we don't have that yet and this gives something closer to the
18
## correct semantics than not upgrading an Int at all.
19
.sub '!upgrade_to_num_if_needed'
21
if test > 2147483647.0 goto upgrade
22
if test < -2147483648.0 goto upgrade
31
.sub 'prefix:++' :multi(_) :subid('!prefix:++')
34
unless $I0 goto inc_undef
36
.tailcall 'infix:='(a, $P1)
38
.tailcall 'infix:='(a, 1)
41
.sub 'postfix:++' :multi(_) :subid('!postfix:++')
44
.const 'Sub' $P1 = '!prefix:++'
49
.sub 'prefix:--' :multi(_) :subid('!prefix:--')
52
unless $I0 goto dec_undef
54
.tailcall 'infix:='(a, $P1)
56
.tailcall 'infix:='(a, -1)
59
.sub 'postfix:--' :multi(_)
62
.const 'Sub' $P1 = '!prefix:--'
67
.sub 'prefix:++' :multi(Integer) :subid('!prefix:++Int')
69
unless a < 2147483647 goto fallback
70
$P0 = getprop 'readonly', a
71
unless null $P0 goto fallback
72
$P0 = getprop 'type', a
73
if null $P0 goto fast_inc
74
$P1 = get_hll_global 'Int'
76
unless $I0 goto fallback
81
.const 'Sub' fb = '!prefix:++'
85
.sub 'postfix:++' :multi(Integer)
89
.const 'Sub' $P1 = '!prefix:++Int'
96
.sub 'prefix:!' :multi(_)
99
$P0 = get_hll_global ['Bool'], 'True'
102
$P0 = get_hll_global ['Bool'], 'False'
107
.sub 'prefix:^?' :multi(_)
109
.tailcall 'prefix:!'(a)
113
.sub 'prefix:+' :multi(_)
119
.sub 'prefix:+' :multi('Integer')
121
.tailcall '!upgrade_to_num_if_needed'(a)
125
.sub 'prefix:?' :multi(_)
128
$P0 = get_hll_global ['Bool'], 'False'
131
$P0 = get_hll_global ['Bool'], 'True'
136
## TODO: prefix:= prefix:* prefix:** prefix:~^ prefix:+^
139
.sub 'infix:xx' :multi(_,_)
144
unless n > 0 goto done
153
.sub 'infix:+&' :multi(_,_)
161
.sub 'infix:+<' :multi(_,_)
169
.sub 'infix:+>' :multi(_,_)
177
.sub 'infix:~&' :multi(_,_)
185
## TODO: infix:~< infix:~>
190
.sub 'infix:~' :multi(_,_)
259
.sub 'true' :multi(_)
261
.tailcall 'prefix:?'(a)
267
.tailcall 'prefix:!'(a)
274
.param pmc init_value :optional
275
.param int have_init_value :opt_flag
277
# Get the class of the variable we're adding roles to.
278
.local pmc p6meta, parrot_class
280
parrot_class = class var
282
# Derive a new class that does the role(s) specified.
284
derived = root_new ['parrot';'Class']
285
addparent derived, parrot_class
286
$I0 = isa role, ['Perl6Role']
287
if $I0 goto one_role_select
288
#$P0 = get_root_namespace ['parrot';'Role']
290
$I0 = isa role, 'P6role'
292
$I0 = isa role, ['List']
293
if $I0 goto many_roles
295
'die'("'does' expects a role or a list of roles")
298
role = role.'!select'()
300
addrole derived, role
301
'!compose_role_attributes'(derived, role)
305
.local pmc role_it, cur_role
308
unless role_it goto roles_loop_end
309
cur_role = shift role_it
310
$I0 = isa cur_role, 'Role'
311
if $I0 goto have_parrot_role
312
$I0 = isa cur_role, 'Perl6Role'
313
unless $I0 goto error
314
cur_role = cur_role.'!select'()
316
addrole derived, cur_role
317
'!compose_role_attributes'(derived, cur_role)
322
# Instantiate the class to make it form itself.
325
# Create a new meta-class, but associate with existing proto-object.
326
.local pmc p6meta, old_proto, new_proto
327
p6meta = get_hll_global ['Perl6Object'], '$!P6META'
328
new_proto = p6meta.'register'(derived)
329
$P0 = new_proto.'HOW'()
330
old_proto = var.'WHAT'()
331
setattribute $P0, 'protoobject', old_proto
333
# Re-bless the object into the subclass.
334
rebless_subclass var, derived
336
# We need to set any initial attribute values up.
337
.lex '$CLASS', new_proto
338
$P0 = find_method new_proto, 'BUILD'
341
# If we were given something to initialize with, do so.
342
unless have_init_value goto no_init
344
.local string attr_name
345
attrs = inspect role, "attributes"
346
attrs = attrs.'keys'()
348
if $I0 != 1 goto attr_error
350
attr_name = substr attr_name, 2 # lop off sigil and twigil
351
$P0 = var.attr_name()
352
'infix:='($P0, init_value)
355
# We're done - return.
359
'die'("Can only supply an initialization value to a role with one attribute")
366
.param pmc value :optional
367
.param int have_value :opt_flag
369
# First off, is the role actually a role?
370
$I0 = isa role, 'Perl6Role'
371
if $I0 goto have_role
372
$I0 = isa role, 'Role'
373
if $I0 goto have_role
375
# If not, it may be an enum. If we don't have a value, get the class of
376
# the thing passed as a role and find out.
377
if have_value goto error
378
.local pmc maybe_enum
379
maybe_enum = role.'WHAT'()
380
$P0 = getprop '$!is_enum', maybe_enum
381
if null $P0 goto error
382
unless $P0 goto error
386
unless null role goto have_role
388
# Did anything go wrong?
390
'die'("The but operator can only be used with a role or enum value on the right hand side")
392
# Now we have a role, copy the value and call does on the copy.
394
$I0 = isa var, 'ObjectRef'
395
unless $I0 goto not_obj_ref
399
if null value goto no_value
400
'infix:does'(var, role, value)
403
'infix:does'(var, role)
409
=item !generate_meta_ops
411
Generates meta-ops for user defined operators.
415
.sub '!generate_meta_ops'
416
.param string full_name
419
# If op is already generated, defined, we're done.
421
name = substr full_name, 6
422
$S0 = concat 'infix:R', name
423
$P0 = get_hll_global $S0
424
unless null $P0 goto done
426
# Generate all the names we'll need.
427
.local string assignment, reverse, cross, reduce, hyper1, hyper2, hyper3, hyper4
428
.local string hyper1_asc, hyper2_asc, hyper3_asc, hyper4_asc
429
assignment = concat 'infix:', name
430
concat assignment, '='
431
reverse = concat 'infix:R', name
432
cross = concat 'infix:X', name
433
reduce = concat 'prefix:[', name
435
hyper1_asc = concat 'infix:<<', name
436
concat hyper1_asc, '>>'
437
hyper2_asc = concat 'infix:>>', name
438
concat hyper2_asc, '<<'
439
hyper3_asc = concat 'infix:<<', name
440
concat hyper3_asc, '<<'
441
hyper4_asc = concat 'infix:>>', name
442
concat hyper4_asc, '>>'
443
hyper1 = concat unicode:"infix:\u00ab", name
444
concat hyper1, unicode:"\u00bb"
445
hyper2 = concat unicode:"infix:\u00bb", name
446
concat hyper2, unicode:"\u00ab"
447
hyper3 = concat unicode:"infix:\u00ab", name
448
concat hyper3, unicode:"\u00ab"
449
hyper4 = concat unicode:"infix:\u00bb", name
450
concat hyper4, unicode:"\u00bb"
452
# Add all of the tokens.
454
optable = get_hll_global ['Perl6';'Grammar'], '$optable'
455
optable.'newtok'(assignment, 'equiv'=>'infix::=', 'lvalue'=>1)
456
optable.'newtok'(reduce, 'equiv'=>'infix:=')
457
optable.'newtok'(reverse, 'equiv'=>equiv)
458
optable.'newtok'(cross, 'equiv'=>'infix:X')
459
optable.'newtok'(hyper1, 'equiv'=>equiv)
460
optable.'newtok'(hyper1_asc, 'equiv'=>equiv, 'subname'=>hyper1)
461
optable.'newtok'(hyper2, 'equiv'=>equiv)
462
optable.'newtok'(hyper2_asc, 'equiv'=>equiv, 'subname'=>hyper2)
463
optable.'newtok'(hyper3, 'equiv'=>equiv)
464
optable.'newtok'(hyper3_asc, 'equiv'=>equiv, 'subname'=>hyper3)
465
optable.'newtok'(hyper4, 'equiv'=>equiv)
466
optable.'newtok'(hyper4_asc, 'equiv'=>equiv, 'subname'=>hyper4)
468
# Now generate the subs.
469
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_simple', '!ASSIGNMETAOP', name)
470
set_hll_global assignment, $P0
471
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_reduce', name)
472
set_hll_global reduce, $P0
473
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_reverse', full_name)
474
set_hll_global reverse, $P0
476
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_cross', name)
477
set_hll_global cross, $P0
478
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_hyper', '!HYPEROP', name, 0, 0)
479
set_hll_global hyper1, $P0
480
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_hyper', '!HYPEROP', name, 1, 1)
481
set_hll_global hyper2, $P0
482
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_hyper', '!HYPEROP', name, 0, 1)
483
set_hll_global hyper3, $P0
484
$P0 = '!generate_meta_op_sub'('!generate_meta_op_helper_hyper', '!HYPEROP', name, 1, 0)
485
set_hll_global hyper4, $P0
488
.sub '!generate_meta_op_sub'
489
.param string which_helper
490
.param pmc delegate_to
491
.param pmc args :slurpy
492
.lex '$delegate_to', delegate_to
494
$P0 = find_name which_helper
498
.sub '!generate_meta_op_helper_simple' :outer('!generate_meta_op_sub')
501
$P0 = find_lex '$delegate_to'
504
$P1 = find_lex '@args'
505
.tailcall $P0($P1 :flat, a, b)
507
.sub '!generate_meta_op_helper_reverse' :outer('!generate_meta_op_sub')
510
$P0 = find_lex '$delegate_to'
515
.sub '!generate_meta_op_helper_reduce' :outer('!generate_meta_op_sub')
516
.param pmc args :slurpy
517
$P0 = find_lex '$delegate_to'
518
.tailcall '!REDUCEMETAOP'($P0, 0, args :flat)
520
.sub '!generate_meta_op_helper_cross' :outer('!generate_meta_op_sub')
521
.param pmc args :slurpy
522
$P0 = find_lex '$delegate_to'
523
.tailcall '!CROSSMETAOP'($P0, 0, 0, args :flat)
525
.sub '!generate_meta_op_helper_hyper' :outer('!generate_meta_op_sub')
528
$P0 = find_lex '$delegate_to'
531
$P1 = find_lex '@args'
534
.tailcall $P0($P1 :flat, a, b, $I0, $I1)
545
# vim: expandtab shiftwidth=4 ft=pir: