Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 149 lines (127 sloc) 4.964 kb
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
# While the grammar represents the syntactic elements of our language and
# the actions take care of building up an AST to represent the semantics
# of it, the world is about the declarative aspects of a language. This
# includes:
#
# * Symbol table management
# * Creating meta-object instances
# * Parts of library loading (most likely it delegates to an actual loader)
# * Resolving references to objects, within or between compilation units
#
# Just as there is one AST produced per compilation unit, there is also a
# world produce per compilation unit.
#
# A world includes a serialization context. This contains a bunch of
# objects - often meta-objects - that we want to persist across the
# compile time / run time boundary. If we're doing pre-compilation
# rather than "immediate run" then we serialize the contents of the
# serialization context.

class HLL::World {
    # The serialization context that we're building.
    has $!sc;
    
    # The handle for the context.
    has $!handle;
    
    # Whether we're in pre-compilation mode.
    has $!precomp_mode;
    
    # The number of code refs we've added to the code refs root so far.
    has $!num_code_refs;
    
    # List of QAST blocks that map to the code refs table, for use in
    # building deserialization code.
    has $!code_ref_blocks;

    # List of QAST nodes specifying dependency loading related tasks. These
    # are done before the deserialization of the current context, or if in
    # immediate run mode before any of the other fixup tasks.
    has @!load_dependency_tasks;

    # List of QAST nodes specifying fixup tasks, either after deserialization
    # or between compile time and run time.
    has @!fixup_tasks;
    
    # Address => slot mapping, so we can quickly look up existing objects
    # in the context.
    # XXX LEGACY
    has %!addr_to_slot;
    
    method BUILD(:$handle!, :$description = '<unknown>') {
        # Initialize attributes.
        $!sc := pir::nqp_create_sc__PS($handle);
        $!handle := $handle;
        %!addr_to_slot := nqp::hash();
        @!fixup_tasks := nqp::list();
        @!load_dependency_tasks := nqp::list();
        $!precomp_mode := %*COMPILING<%?OPTIONS><target> eq 'pir';
        $!num_code_refs := 0;
        $!code_ref_blocks := [];
        $!sc.set_description($description);
        
        # Add to currently compiling SC stack.
        pir::nqp_push_compiling_sc__vP($!sc);
    }
    
    # Gets the slot for a given object. Dies if it is not in the context.
    method slot_for_object($obj) {
        my $slot := %!addr_to_slot{nqp::where($obj)};
        unless nqp::defined($slot) {
            nqp::die('slot_for_object called on object not in context');
        }
        $slot
    }

    # Adds an object to the root set, along with a mapping.
    method add_object($obj) {
        pir::nqp_set_sc_for_object__vPP($obj, $!sc);
        my $idx := $!sc.elems();
        $!sc[$idx] := $obj;
        %!addr_to_slot{nqp::where($obj)} := $idx;
        $idx
    }
    
    # Adds a code reference to the root set of code refs.
    method add_root_code_ref($code_ref, $past_block) {
        my $code_ref_idx := $!num_code_refs;
        $!num_code_refs := $!num_code_refs + 1;
        $!code_ref_blocks.push($past_block);
        pir::nqp_add_code_ref_to_sc__vPiP($!sc, $code_ref_idx, $code_ref);
        $code_ref_idx
    }
    
    # Updates a code reference in the root set.
    method update_root_code_ref($idx, $new_code_ref) {
        pir::nqp_add_code_ref_to_sc__vPiP($!sc, $idx, $new_code_ref);
    }

    # Checks if we are in pre-compilation mode.
    method is_precompilation_mode() {
        $!precomp_mode
    }
    
    # Add an event that we want to run before deserialization or before any
    # other fixup.
    method add_load_dependency_task(:$deserialize_past, :$fixup_past) {
        if $!precomp_mode {
            @!load_dependency_tasks.push($deserialize_past) if $deserialize_past;
        }
        else {
            @!load_dependency_tasks.push($fixup_past) if $fixup_past;
        }
    }
    
    # Add an event that we need to run at fixup time (after deserialization of
    # between compilation and runtime).
    method add_fixup_task(:$deserialize_past, :$fixup_past) {
        if $!precomp_mode {
            @!fixup_tasks.push($deserialize_past) if $deserialize_past;
        }
        else {
            @!fixup_tasks.push($fixup_past) if $fixup_past;
        }
    }
    
    # Gets the built serialization context.
    method sc() {
        $!sc
    }
    
    # Gets the SC handle.
    method handle() {
         $!handle
    }
    
    method code_ref_blocks() {
        $!code_ref_blocks
    }
    
    # Gets the list of load dependency tasks to do.
    method load_dependency_tasks() {
        @!load_dependency_tasks
    }
    
    # Gets the list of tasks to do at fixup time.
    method fixup_tasks() {
        @!fixup_tasks
    }
}
Something went wrong with that request. Please try again.