= random parrot-targeting notes

AbsPIR: Prototype in P6, cross-compile to P5.
- nested exprs
- proper subs and attrs
- removal of toxic sugar in PIR
- everything a closure; scoping vars
- structural unpacking for aggregate types
- _not_ Pugs-specific

in PMC = invar PMC

inoutvar => invar # because the register never moves

"direction"
  outvar
 inconst
   invar
    "labelconst" == inconst "I"
    "labelvar" == invar "I"

[$P0] ==> $P0 (k)
[$S0] ==> $S0 (s)
[$S0,$S1] ==> [$S0,$S1] (kc)
[$P0,$P1] ==> [$P0,$P1] (kc)

$P0->"method"
$P0."method"

target = sub_call
targetlist = sub_call

.sub calc_state :immediate
    $P0 = .new FixedSizePMCArray
    .return($P0)
.end

foo = addr LABEL;

.sub Foo
    .const .Sub some_compile_state = "calc_state"
    push some_compile_state
.end

When there is only one key,
    "p/s" => "k"
    "sc"  => "sc"   # probably doesn't work
    "pc"  => "pc"   # probably doesn't work
    "i"   => "ki"
    "ic"  => "kic"
    _     => doesn't happen

"type"
  i  n p s    kc ::= [in * (i|n|p|s)]
  |    |
(ki)  (k)

  (var/const) * (PMC,STR,NUM,INT)


kc => key constant
    ["a";"b"]
ki => key uo


set(in PMC, invar STR)
set(in PMC, invar STR)
set(in PMC, inconst STR)

assign(in PMC, in INT)
            assign(inconst PMC, in INT)


cd editor ; make vim-install # very handy

upon class_init, "entry" is bound to the typenum of the current class

"map" means "autobox from" in pmc header

"make archclean" is like "realclean" except no costly pmc regens

"need_ext" is needed for all reference (paramatric) types

We _always_ turn on
    .pragma n_operators 1       # so prims become value-returning
    .HLL "Perl6", "pugs_group"  # pugs* PMCs

$Foo::Bar ::= 3;

multi ""
    newclass F, "^Int"
    .sub f :multi(^Int, ^Int)
    subclass()  # statically for SI
    addparent() # for each parents in MI

Toplevels:
    - DEFAULT-UNIT-NAMESPACE
        - "Main" by default, but if somebody did "module Test;"
          as 1st line, then the entire file is under "Test"
    - INIT sequence:
        .namespace []

        .sub _MAIN :main
            # Initialize all namespaces
            $P0 = find_global [""], "_INIT"
            $P0()
            $P0 = find_global ["Main"], "_INIT"
            $P0()
            $P0 = find_global ["Foo"], "_INIT"
            $P0()
            # ... go to &Main::MAIN ...
            $P0 = find_global ["Main"], "&MAIN"
            .return $P0()
        .end

        .sub _INIT :load :anon
            store_global "::Class", _C_CLASS
            store_global "::Object", _C_OBJECT
        .end

        .namespace [ "Main" ]
        .sub _INIT :load :anon
            .const .Sub _C_MAIN = "_INIT_C_MAIN"
            .const .Sub _S_FOURTY_FIVE = "_INIT_S_FOURTY_FIVE"
            # ... objspace setup ...
            store_global "&MAIN", _C_MAIN
            store_global "$FOURTY_FIVE", _S_FOURTY_FIVE
        .end

        # All the constant used in INIT
        .sub _INIT_S_FOURTY_FIVE :immediate :anon
            $P0 = new .PugsInt
            $P0 = 3
            $P0 = $P0 + 42
            .return($P0)
        .end

        # anon sub inside named sub
        sub f {
            my ($sym, $sym2);
            state $sym3 = 3;
            $sym2 = sub g { $sym };
            return $sym2;
        }

        .sub _INIT_C_F :anon :outer("_INIT_C_MAIN")
            .const .Sub __INIT_INNER_0__ = "_INIT_C_ANON_0"
            .sym pmc __DYN_INNER_0__
            __DYN_INNER_0__ = newclosure __INIT_INNER_0__
        .end

        .sub _INIT_C_ANON_0 :anon :outer("_INIT_C_F")
            $P0 = find_lex "$sym"
            .return($P0)
        .end


        # This applies only to Code constants - no ":immediate"
        .sub _INIT_C_MAIN :anon :outer("_INIT")
            .const .Sub __SUB__ = "_INIT_C_MAIN"
            .const .Sub __PRE__ = "_INIT_C_MAIN__PRE"
            .const .Sub __POST__ = "_INIT_C_MAIN__POST"
            .sym pmc _S_sym, _S_sym2, _S_sym3
            .lex "$sym", _S_sym
            .lex "$sym2", _S_sym2
            .lex "$sym3", _S_sym3

        FIRST:
            # ...populate "state" stuff...
            _S_sym3 = 3

            # horrible hack: reset entry point
            set_addr __SUB__, PRE

            X = global "foo"
            global "foo" = X

        PRE:
            pushmark 110287318023
            pushaction __POST__
            pushaction __UNDO__
            pushaction __CATCH__

            # Perl6's PRE{...} block, triggering on each sub call
            __PRE__();
        
        BODY:
            # ...main body...
            $P0 = find_global "$FOURTY_FIVE"
            $P0.say(); # assuming this works

        KEEP:
            popmark 110287318023
            __KEEP__();
            __POST__();
            # ...

        .end

        .sub _INIT_C_MAIN__PRE :anon :outer("_INIT_C_MAIN")
        .end
        .sub _INIT_C_MAIN__POST :anon :outer("_INIT_C_MAIN")
        .end
        .sub _INIT_C_MAIN__CATCH :anon :outer("_INIT_C_MAIN")
            .param int _seen_exception_
            # only deal it with _seen_exception_ == 1
        .end
        .sub _INIT_C_MAIN__UNDO :anon :outer("_INIT_C_MAIN")
            .param int _seen_exception_
            # only deal it with _seen_exception_ == 0
        .end


        .namespace [ "Foo" ]
        .sub _INIT :load :anon
            .const .PugsInt _S_Bar = "3"
            store_global "$Bar", _S_Foo_Bar
        .end

    - SUBS
        - &MAIN

For subs:
    - .namespace [ "Main" ]       # ::Main
      Sub (name)
        .sub "SUB_NAME" :outer("OUTER_NAME")
        .end
    - .namespace [ "Foo"; "Bar" ] # ::Foo::Bar
      Sub (unnamed)
        .sub "__ANON_0__" :anon :outer("OUTER_NAME")
        .end

Inside Sub:
    - Constant PMCs
        .const .PMC_Type identifier = "...some_string..."
        - ObjectSpace "constants" is loaded right there
    - Var lookup form


say "Hello":

    .const .PugsStr __ANON_PugsStr_0__ = "Hello"
    __ANON_PugsStr_0__.method();


= Plan for extensible attributes

We extend ParrotClass into PugsClass
We extend ParrotObject into PugsObject
Foreach PugsClass, a new Hash PMC is attached to it

Foo = newclass "Foo"
add_attribute Foo, "$.a"
add_attribute Foo, "$.b"
add_attribute Foo, "" # extra things! yay!
                      # note we "don't" emit this under pugs -O (finalized)

INIT-of-class, each object gets fresh SC_.a SC_.b and get are
    get_attr'd

class Foo {
    has $.a;
    has $.b;
}

# here is runtime
class Foo is also {
    has $.c;
}
Foo.HOW.add_attribute(...)

So, all $!foo $!bar access need to emit
    classoffset
in each method that talks about them.

-- get_attribute_str

= Plan for ProtoObjects

class Foo {
    has $.x;
    method bar { say 1 }
}
::Foo.x # error
::Foo.bar # 1
::Foo.new.x; # works
::Foo.new.bar # 1

To PugsClass PMC, we have a METHOD get_proto
    -> returns a PugsObject PMC with class-id at that PugsClass
    -> _but_ with the pristine vtable obtained by get_attrib_num(PCD_OBJECT_VTABLE)
    -> _and_ fill in the attr slots with null/error/whatever-larry-prefers

PugsObject

PugsInt.pmc
    METHOD

$P0 = get_namespace ["parrot"; "String"]
$P1 = find_global $P0, "lower"

= Either: Hack the NS distribution so that unsigiled is jsut for methods

class Foo {         # ->{str}   typed_ns
    my $boo;        # $boo      boo#var
    sub bar {       # &bar      bar#sub
    }
    method baz {    # &baz      baz#sub
                    #  baz
    }
    method Blah {}  # &Blah     Blah#sub
                    #  Blah
    class Blah {    # ::Blah    Blah#ns
    }
}

get_namespace ["Foo";"Blah"]
get_namespace(get_namespace(()))
->{"str"}{"str"}

# ALSO MAIL P6I
# remove_method => del_sub
# get_method_list => ns->hack_iterate
# compute_all_applicable_methods => metaclass->get_mro->iterate->>>ns->hack_iterate
# find_next_method_by_name => not-yet
    "super"
        # sketch pseudocode to implement the native "super" opcode
    shuffle an extra I* to mean the current-index-in-method-mro-chain
    pass in an MRO-iterator as an extra argument

class Foo { method f {} };
class Bar is Foo { method f {super}};
class Baz is Bar
Baz.new.f


Foo.can('bar'); # undef

# for foreign objects, create a PugsObj shim around it and fake
# the .can cache -- fortunately we are not bridging Python yet.

= Or: hack find_method so that it doesn't go into find_method_direct_1

# tail_yield()
&foo := &yield; foo()


= emit 

MAIL P6I:
- super
- tail_yield
