Skip to content

Commit

Permalink
Add initial version of nqp:: pseudo-opcode space for low-level primit…
Browse files Browse the repository at this point in the history
…ives.
  • Loading branch information
pmichaud committed Jun 21, 2011
1 parent bcfe1f0 commit c62322b
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 0 deletions.
117 changes: 117 additions & 0 deletions docs/nqp-opcode.txt
@@ -0,0 +1,117 @@
General notes:
* Not really attempting to be exhaustive just yet -- only want
to get the most significant ones done in this pass.
* Avoid "set" -- use "bind" or "assign" if that's what we're really doing.
Or, if we want to keep "set", make sure it always means "bind".
* A suffix of _i, _n, or _s generally denotes an int/num/str version
of the opcode. Stick to lowercase letters here...
* ... except that bigints might be a _I suffix :-)
* Perhaps reserve _b for a boolean native type
* Might want to reserve _a and _h for "native" list/hash versions of opcodes
* Might want to reserve _o for object/instance versions of opcodes
* aim for consistency with underscores and the like
(i.e., unlike parrot, don't mix "get_foo" and "getbar")
* Use the p6-defined terms where possible (e.g., "elems" and "chars"
instead of "elements" and "length")
* Generally return an appropriate argument instead of void
* Items marked (?) mean that the opcode itself might be questionable
for inclusion in the set.


control opcodes:
nqp::if(test, iftrue, iffalse)
nqp::unless(test, iffalse, iftrue)
nqp::while(test, body)
nqp::loop(init, test, next, body)
nqp::throw pir::throw__P
nqp::die pir::die
nqp::exit pir::exit__vi
nqp::sleep pir::sleep__vn
(need ops to fetch caller, outer, context, etc?)

I/O:
nqp::print pir::print
nqp::say pir::say

arithmetic:
nqp::add_i pir::add__Iii
nqp::add_n pir::add__Nnn
...etc...

string:
nqp::concat pir::concat__Sss
nqp::join pir::join__SsP
nqp::substr pir::substr__Ssii
nqp::downcase pir::downcase__Ss
nqp::upcase pir::upcase__Ss
nqp::index pir::index__Issi
nqp::chr pir::chr__Si
nqp::ord pir::ord__Si
nqp::chars pir::length__Is
nqp::split pir::split__Pss
nqp::iscclass pir::iscclass__Isii (?)
nqp::findcclass pir::find_cclass__Isii (?)
nqp::findnotcclass pir::find_not_cclass__Isii (?)

relational:
nqp::iseq_i pir::iseq__Iii
nqp::iseq_n pir::iseq__Inn
nqp::iseq_s pir::iseq__Iss
...etc...

aggregate:
nqp::pop pir::pop__PP
nqp::push pir::push__0PP
nqp::shift pir::shift__PP
nqp::unshift pir::unshift__0PP
nqp::splice pir::splice__0PPii
nqp::bindpos pir::set__1QiP
nqp::bindkey pir::set__1QsP
nqp::atpos pir::set__PQi
nqp::atkey pir::set__PQs
nqp::existpos pir::exists__IQi
nqp::existkey pir::exists__IQs
nqp::elems pir::elements__IP

object:
nqp::bindattribute pir::setattribute__0PPsP
nqp::getattribute pir::getattribute__PPsP
nqp::findmethod pir::find_method__PPs (?)
nqp::null pir::null__P
nqp::isnull pir::isnull__IP
nqp::defined pir::defined__IP
nqp::?? pir::istrue__IP
nqp::clone pir::clone__PP
nqp::typecheck or ::isa pir::type_check__IPP
or ::istype
nqp::?? pir::repr_instance_of__PP (?)
nqp::unbox_i pir::repr_unbox_int__IP
nqp::unbox_n pir::repr_unbox_num__NP
nqp::unbox_s pir::repr_unbox_str__SP
nqp::box_i pir::repr_box_int__PPi
nqp::box_n pir::repr_box_num__PPn
nqp::box_s pir::repr_box_str__PPs
nqp::what or nqp::getwhat (?)
nqp::how or nqp::gethow (?)
nqp::?? pir::can__IPs (?)

Rakudo-specific:
nqp::p6box_i pir::perl6_box_int__Pi
nqp::p6box_n pir::perl6_box_num__Pn
nqp::p6box_s pir::perl6_box_str__Ps
nqp::p6iscontainer pir::is_container__IP
nqp::?? (::p6capturepos?) pir::perl6_current_args__P
nqp::p6assign or ::p6store pir::perl6_container_store__0PP
nqp::p6bool or ::p6box_b pir::perl6_booleanize__PI
nqp::p6list_a pir::perl6_list_from_rpa__PPPP
nqp::p6iter_a pir::perl6_iter_from_rpa__PPP

Lexical and variable ops (?)
nqp::bindlex pir::store_lex__1sP
nqp::getlex or ::lex pir::find_lex__Ps
nqp::getdynlex or ::dynlex pir::find_dynamic_lex__Ps
nqp::binddynlex pir::store_dynamic_lex__Ps

STable ops (?)
...??...

11 changes: 11 additions & 0 deletions src/NQP/Actions.pm
Expand Up @@ -1162,6 +1162,17 @@ class NQP::Actions is HLL::Actions {
make PAST::Val.new( :value(~$<const>), :returns<!macro_const>, :node($/) );
}

method term:sym<nqp::op>($/) {
my $op := ~$<op>;
my $args := $<args> ?? $<args>[0].ast.list !! [];
my $past := PAST::Node.'map_node'(|$args, :map<nqp>, :op($op),
:node($/));

pir::defined($past) ||
$/.CURSOR.panic("Unrecognized nqp:: opcode 'nqp::$op'");
make $past;
}

method term:sym<onlystar>($/) {
make PAST::Op.new(
:pirop('multi_dispatch_over_lexical_candidates P')
Expand Down
4 changes: 4 additions & 0 deletions src/NQP/Grammar.pm
Expand Up @@ -545,6 +545,10 @@ grammar NQP::Grammar is HLL::Grammar {
'pir::const::' $<const>=[\w+]
}

token term:sym<nqp::op> {
'nqp::' $<op>=[\w+] <args>?
}

token term:sym<onlystar> {
'{*}' <?ENDSTMT>
[ <?{ $*MULTINESS eq 'proto' }> || <.panic: '{*} may only appear in proto'> ]
Expand Down
228 changes: 228 additions & 0 deletions src/PAST/NQP.pir
Expand Up @@ -7,6 +7,10 @@
p6meta = new 'P6metaclass'
base = get_hll_global ['PAST'], 'Node'
p6meta.'new_class'('PAST::Want', 'parent'=>base)
# add the nqp:: opcode map
.const 'Sub' nqpmap = 'nqpmap'
base.'map_add'('nqp', nqpmap)
.end
Expand Down Expand Up @@ -58,3 +62,227 @@ Select a single past child based on rtype.
.end
=item map_add(mapid, [hash])
Add entries from any C<hash> arguments to the pseudo-opcode table
with identifier C<mapid>. Slurpy named arguments are also added to
the hash (after all hash arguments have been processed). The
resulting pseudo-opcode table hash for C<mapid> is returned.
The hash entries being added consist of pseudo-opcode (key, spec)
pairs describing the pseudo-opcode name and node type to be
constructed. If C<spec> is a plain string, it's assumed to be
a Parrot C<pirop> opcode name. (A future version may allow
strings of the form 'mapid::opcode' to reference an entry of
another map table.)

If C<spec> is a hash, it contains
attributes used to build a PAST node. For example, the following
pseudo-code would cause the 'ifelse' pseudo-op in the 'nqp'
mapping space to to translate to a PAST::Op node with 'pasttype'
set to 'if':

$x := hash( 'WHAT' => PAST::Op, 'pasttype'=>'if' );
PAST::Node.map_add('nqp', 'ifelse' => $x );

The 'WHAT' entry of such a hash defaults to PAST::Op if not specified.

=item map_node([args], 'map'=>mapid, 'op'=>opname, [options])

Create a node based on the mapping specification for C<opname>
from the pseudo-op mapping table given by C<mapid>. The
C<args> and C<options> are combined with the mapping table
entry to produce the node to be returned.

=cut

.namespace ['PAST';'Node']
.sub 'map_add' :method
.param string mapid
.param pmc args :slurpy
.param pmc opt_hash :slurpy :named

.local pmc maptables, maphash
maptables = get_global '%!maptables'
unless null maptables goto have_maptables
maptables = new ['Hash']
set_global '%!maptables', maptables
have_maptables:

maphash = maptables[mapid]
unless null maphash goto have_maphash
maphash = new ['Hash']
maptables[mapid] = maphash
have_maphash:

args_loop:
unless args goto args_done
.local pmc hash_it
$P0 = shift args
hash_it = iter $P0
args_merge_loop:
unless hash_it goto args_loop
$P0 = shift hash_it
$S1 = $P0.'key'()
$P1 = $P0.'value'()
maphash[$S1] = $P1
goto args_merge_loop
args_done:

hash_it = iter opt_hash
opts_loop:
unless hash_it goto opts_done
$P0 = shift hash_it
$S1 = $P0.'key'()
$P1 = $P0.'value'()
maphash[$S1] = $P1
goto opts_loop
opts_done:

.return (maphash)
.end

.namespace ['PAST';'Node']
.sub 'map_node' :method
.param pmc args :slurpy
.param string mapid :named('map')
.param string opcode :named('op')
.param pmc options :slurpy :named

.local pmc maphash, ophash, past
$P0 = get_global '%!maptables'
maphash = $P0[mapid]
if null maphash goto fail
ophash = maphash[opcode]
if null ophash goto fail

$I0 = isa ophash, ['Hash']
if $I0 goto have_ophash
# handle case where the opspec is a simple (pirop) string
$P0 = get_hll_global ['PAST'], 'Op'
past = $P0.'new'(args :flat, 'pirop'=>ophash, options :named :flat)
.return (past)

have_ophash:
# merge the ophash entries into options
.local pmc ophash_it, key, value
ophash_it = iter ophash
ophash_loop:
unless ophash_it goto ophash_done
$P0 = shift ophash_it
$S1 = $P0.'key'()
$P1 = $P0.'value'()
# don't overwrite an existing option
$I0 = exists options[$S1]
if $I0 goto ophash_loop
options[$S1] = $P1
goto ophash_loop
ophash_done:

# determine the 'what' value to use
.local pmc what
what = get_hll_global ['PAST'], 'Op'
$I0 = exists options['WHAT']
unless $I0 goto have_what
what = options['WHAT']
null $P0
options['WHAT'] = $P0
have_what:

past = what.'new'(args :flat, options :named :flat)
.return (past)

fail:
$P0 = new ['Undef']
.return ($P0)
.end


.sub 'nqpmap' :immediate :subid('nqpmap')
.local pmc maphash
maphash = new ['Hash']

# I/O opcodes
maphash['print'] = 'print'
maphash['say'] = 'say'

# arithmetic opcodes
maphash['add_i'] = 'add__Iii'
maphash['add_n'] = 'add__Nnn'
maphash['sub_i'] = 'sub__Iii'
maphash['sub_n'] = 'sub__Nnn'
maphash['mul_i'] = 'mul__Iii'
maphash['mul_n'] = 'mul__Nnn'
maphash['div_i'] = 'div__Iii'
maphash['div_n'] = 'div__Nnn'
maphash['mod_i'] = 'mod__Iii'

# string opcodes
maphash['chars'] = 'length__Is'
maphash['concat'] = 'concat' # allow either P or S form
maphash['join'] = 'join__SsP'
maphash['split'] = 'split__Pss'
maphash['index'] = 'index__Issi'
maphash['chr'] = 'chr__Si'
maphash['ord'] = 'ord__Is'
maphash['downcase'] = 'downcase__Ss'
maphash['upcase'] = 'upcase__Ss'

# relational opcodes
maphash['iseq_i'] = 'iseq__Iii'
maphash['isne_i'] = 'isne__Iii'
maphash['islt_i'] = 'islt__Iii'
maphash['isle_i'] = 'isle__Iii'
maphash['isgt_i'] = 'isgt__Iii'
maphash['isge_i'] = 'isge__Iii'

maphash['iseq_n'] = 'iseq__Inn'
maphash['isne_n'] = 'isne__Inn'
maphash['islt_n'] = 'islt__Inn'
maphash['isle_n'] = 'isle__Inn'
maphash['isgt_n'] = 'isgt__Inn'
maphash['isge_n'] = 'isge__Inn'

maphash['iseq_s'] = 'iseq__Iss'
maphash['isne_s'] = 'isne__Iss'
maphash['islt_s'] = 'islt__Iss'
maphash['isle_s'] = 'isle__Iss'
maphash['isgt_s'] = 'isgt__Iss'
maphash['isge_s'] = 'isge__Iss'

# aggregate opcodes
maphash['elems'] = 'elements__IP'
maphash['push'] = 'push__0PP'
maphash['pop'] = 'pop__PP'
maphash['shift'] = 'shift__PP'
maphash['unshift'] = 'unshift__0PP'
maphash['splice'] = 'splice__0PPii'
maphash['atpos'] = 'set__PQi'
maphash['bindpos'] = 'set__1QiP'
maphash['existspos'] = 'exists__IQi'
maphash['deletepos'] = 'delete__0Qi'
maphash['atkey'] = 'set__PQs'
maphash['bindkey'] = 'set__1QsP'
maphash['existskey'] = 'exists__IQs'
maphash['deletekey'] = 'delete__0Qs'

# object opcodes
maphash['unbox_i'] = 'repr_unbox_int__IP'
maphash['unbox_n'] = 'repr_unbox_num__NP'
maphash['unbox_s'] = 'repr_unbox_str__SP'

# control opcodes
$P0 = new ['Hash']
$P0['pasttype'] = 'if'
maphash['if'] = $P0

$P0 = new ['Hash']
$P0['pasttype'] = 'unless'
maphash['unless'] = $P0

$P0 = new ['Hash']
$P0['pasttype'] = 'while'
maphash['while'] = $P0

.return (maphash)
.end

0 comments on commit c62322b

Please sign in to comment.