diff options
author | Adrian Thurston <thurston@colm.net> | 2020-03-14 15:29:52 +0200 |
---|---|---|
committer | Adrian Thurston <thurston@colm.net> | 2020-03-14 15:29:52 +0200 |
commit | f653735830d537715f2885bd832cf04851d35401 (patch) | |
tree | 95e6551e39407543366d4f49aedf7b78c6e8bbe1 /src/bytecode.c | |
parent | bcc54d5df10cf425e7134b06f70d7ffe1abee4e4 (diff) | |
download | colm-f653735830d537715f2885bd832cf04851d35401.tar.gz |
moved source files into commit repository
Diffstat (limited to 'src/bytecode.c')
-rw-r--r-- | src/bytecode.c | 5025 |
1 files changed, 5025 insertions, 0 deletions
diff --git a/src/bytecode.c b/src/bytecode.c new file mode 100644 index 00000000..39aee070 --- /dev/null +++ b/src/bytecode.c @@ -0,0 +1,5025 @@ +/* + * Copyright 2006-2018 Adrian Thurston <thurston@colm.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <colm/bytecode.h> + +#include <sys/types.h> +#if defined(HAVE_SYS_WAIT_H) +#include <sys/wait.h> +#endif +#include <assert.h> +#include <string.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> + +#include <colm/pool.h> +#include <colm/debug.h> +#include <colm/colm.h> + +#define TRUE_VAL 1 +#define FALSE_VAL 0 + +#if SIZEOF_LONG != 4 && SIZEOF_LONG != 8 + #error "SIZEOF_LONG contained an unexpected value" +#endif + +#define read_byte( i ) do { \ + i = ((uchar) *instr++); \ +} while(0) + +#define read_half( i ) do { \ + i = ((word_t) *instr++); \ + i |= ((word_t) *instr++) << 8; \ +} while(0) + +/* There are better ways. */ +#if SIZEOF_LONG == 4 + + #define read_type( type, i ) do { \ + word_t _w; \ + _w = ((word_t) *instr++); \ + _w |= ((word_t) *instr++) << 8; \ + _w |= ((word_t) *instr++) << 16; \ + _w |= ((word_t) *instr++) << 24; \ + i = (type) _w; \ + } while(0) + + #define read_type_p( Type, i, p ) do { \ + i = ((Type) p[0]); \ + i |= ((Type) p[1]) << 8; \ + i |= ((Type) p[2]) << 16; \ + i |= ((Type) p[3]) << 24; \ + } while(0) + + #define consume_word() instr += 4 + +#else + + #define read_type( type, i ) do { \ + word_t _w; \ + _w = ((word_t) *instr++); \ + _w |= ((word_t) *instr++) << 8; \ + _w |= ((word_t) *instr++) << 16; \ + _w |= ((word_t) *instr++) << 24; \ + _w |= ((word_t) *instr++) << 32; \ + _w |= ((word_t) *instr++) << 40; \ + _w |= ((word_t) *instr++) << 48; \ + _w |= ((word_t) *instr++) << 56; \ + i = (type) _w; \ + } while(0) + + #define read_type_p( type, i, p ) do { \ + i = ((type) p[0]); \ + i |= ((type) p[1]) << 8; \ + i |= ((type) p[2]) << 16; \ + i |= ((type) p[3]) << 24; \ + i |= ((type) p[4]) << 32; \ + i |= ((type) p[5]) << 40; \ + i |= ((type) p[6]) << 48; \ + i |= ((type) p[7]) << 56; \ + } while(0) + + #define consume_word() instr += 8 +#endif + +#define read_tree( i ) read_type( tree_t*, i ) +#define read_parser( i ) read_type( parser_t*, i ) +#define read_word( i ) read_type( word_t, i ) +#define read_stream( i ) read_type( stream_t*, i ) +#define read_input( i ) read_type( input_t*, i ) + +#define read_word_p( i, p ) read_type_p( word_t, i, p ) + +#define consume_byte() instr += 1 +#define consume_half() instr += 2 + +static void rcode_downref( program_t *prg, tree_t **sp, code_t *instr ); + +static void make_stdin( program_t *prg ) +{ + if ( prg->stdin_val == 0 ) + prg->stdin_val = colm_stream_open_fd( prg, "<stdin>", 0 ); +} + +static void make_stdout( program_t *prg ) +{ + if ( prg->stdout_val == 0 ) + prg->stdout_val = colm_stream_open_fd( prg, "<stdout>", 1 ); +} + +static void make_stderr( program_t *prg ) +{ + if ( prg->stderr_val == 0 ) + prg->stderr_val = colm_stream_open_fd( prg, "<stderr>", 2 ); +} + +static void flush_streams( program_t *prg ) +{ + if ( prg->stdout_val != 0 ) { + struct stream_impl *si = prg->stdout_val->impl; + si->funcs->flush_stream( prg, si ); + } + + if ( prg->stderr_val != 0 ) { + struct stream_impl *si = prg->stderr_val->impl; + si->funcs->flush_stream( prg, si ); + } +} + +void colm_parser_set_context( program_t *prg, tree_t **sp, parser_t *parser, struct_t *val ) +{ + parser->pda_run->context = val; +} + +static head_t *tree_to_str_xml( program_t *prg, tree_t **sp, tree_t *tree, int trim, int attrs ) +{ + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + + colm_print_tree_collect_xml( prg, sp, &collect, tree, trim ); + + /* Set up the input stream. */ + head_t *ret = string_alloc_full( prg, collect.data, collect.length ); + + str_collect_destroy( &collect ); + + return ret; +} + +static head_t *tree_to_str_xml_ac( program_t *prg, tree_t **sp, tree_t *tree, int trim, int attrs ) +{ + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + + colm_print_tree_collect_xml_ac( prg, sp, &collect, tree, trim ); + + /* Set up the input stream. */ + head_t *ret = string_alloc_full( prg, collect.data, collect.length ); + + str_collect_destroy( &collect ); + + return ret; +} + +static head_t *tree_to_str_postfix( program_t *prg, tree_t **sp, tree_t *tree, int trim, int attrs ) +{ + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + + colm_postfix_tree_collect( prg, sp, &collect, tree, trim ); + + /* Set up the input stream. */ + head_t *ret = string_alloc_full( prg, collect.data, collect.length ); + + str_collect_destroy( &collect ); + + return ret; +} + +static void input_push_text( struct colm_program *prg, struct input_impl *is, + struct colm_location *loc, const char *data, long length ) +{ + is->funcs->prepend_data( prg, is, loc, colm_alph_from_cstr( data ), length ); +} + +static void colm_stream_push_tree( struct colm_program *prg, struct input_impl *is, + tree_t *tree, int ignore ) +{ + is->funcs->prepend_tree( prg, is, tree, ignore ); +} + +static void colm_stream_push_stream( struct colm_program *prg, struct input_impl *is, stream_t *stream ) +{ + is->funcs->prepend_stream( prg, is, stream ); +} + +static void colm_undo_stream_push( program_t *prg, tree_t **sp, struct input_impl *is, long length ) +{ + if ( length < 0 ) { + /* tree_t *tree = */ is->funcs->undo_prepend_tree( prg, is ); + // colm_tree_downref( prg, sp, tree ); + } + else { + is->funcs->undo_prepend_data( prg, is, length ); + } +} + + +static word_t stream_append_text( program_t *prg, tree_t **sp, input_t *dest, tree_t *input, int trim ) +{ + long length = 0; + struct input_impl *impl = input_to_impl( dest ); + + if ( input->id == LEL_ID_PTR ) { + assert(false); + } + else { + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + colm_print_tree_collect( prg, sp, &collect, input, trim ); + + /* Load it into the input. */ + impl->funcs->append_data( prg, impl, colm_alph_from_cstr( collect.data ), collect.length ); + length = collect.length; + str_collect_destroy( &collect ); + } + + return length; +} + +static word_t stream_append_tree( program_t *prg, tree_t **sp, input_t *dest, tree_t *to_append ) +{ + long length = 0; + struct input_impl *impl = input_to_impl( dest ); + + if ( to_append->id == LEL_ID_PTR ) { + assert(false); + } + else if ( to_append->id == LEL_ID_STR ) { + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + colm_print_tree_collect( prg, sp, &collect, to_append, false ); + + /* Load it into the to_append. */ + impl->funcs->append_data( prg, impl, colm_alph_from_cstr( collect.data ), collect.length ); + length = collect.length; + str_collect_destroy( &collect ); + } + else { + colm_tree_upref( prg, to_append ); + impl->funcs->append_tree( prg, impl, to_append ); + } + + return length; +} + +static word_t stream_append_stream( program_t *prg, tree_t **sp, input_t *dest, stream_t *stream ) +{ + long length = 0; + + struct input_impl *impl = input_to_impl( dest ); + impl->funcs->append_stream( prg, impl, stream ); + + return length; +} + +static void stream_undo_append( program_t *prg, tree_t **sp, + struct input_impl *is, tree_t *input, long length ) +{ + if ( input->id == LEL_ID_PTR ) + assert(false); + else if ( input->id == LEL_ID_STR ) + is->funcs->undo_append_data( prg, is, length ); + else { + is->funcs->undo_append_data( prg, is, length ); + } +} + +static void stream_undo_append_stream( program_t *prg, tree_t **sp, struct input_impl *is, + tree_t *input, long length ) +{ + is->funcs->undo_append_stream( prg, is ); +} + +static tree_t *stream_pull_bc( program_t *prg, tree_t **sp, struct pda_run *pda_run, + input_t *input, tree_t *length ) +{ + long len = ((long)length); + struct input_impl *impl = input_to_impl( input ); + head_t *tokdata = colm_stream_pull( prg, sp, pda_run, impl, len ); + return construct_string( prg, tokdata ); +} + + +static void undo_stream_pull( struct colm_program *prg, struct input_impl *is, + const char *data, long length ) +{ + //debug( REALM_PARSE, "undoing stream pull\n" ); + is->funcs->undo_consume_data( prg, is, colm_alph_from_cstr( data ), length ); +} + +static void undo_pull( program_t *prg, input_t *input, tree_t *str ) +{ + struct input_impl *impl = input_to_impl( input ); + const char *data = string_data( ( (str_t*)str )->value ); + long length = string_length( ( (str_t*)str )->value ); + undo_stream_pull( prg, impl, data, length ); +} + +static long input_push( program_t *prg, tree_t **sp, struct input_impl *in, tree_t *tree, int ignore ) +{ + long length = -1; + if ( tree->id == LEL_ID_PTR ) { + assert(false); + } + else if ( tree->id == LEL_ID_STR ) { + /* This should become a compile error. If it's text, it's up to the + * scanner to decide. Want to force it then send a token. */ + assert( !ignore ); + + /* Collect the tree data. */ + str_collect_t collect; + init_str_collect( &collect ); + colm_print_tree_collect( prg, sp, &collect, tree, false ); + + input_push_text( prg, in, tree->tokdata->location, collect.data, collect.length ); + length = collect.length; + str_collect_destroy( &collect ); + } + else { + colm_tree_upref( prg, tree ); + colm_stream_push_tree( prg, in, tree, ignore ); + } + + return length; +} + +static long input_push_stream( program_t *prg, tree_t **sp, + struct input_impl *in, stream_t *stream ) +{ + colm_stream_push_stream( prg, in, stream ); + return -1; +} + +static void set_local( execution_t *exec, long field, tree_t *tree ) +{ + if ( tree != 0 ) + assert( tree->refs >= 1 ); + vm_set_local( exec, field, tree ); +} + +static tree_t *get_local_split( program_t *prg, execution_t *exec, long field ) +{ + tree_t *val = vm_get_local( exec, field ); + tree_t *split = split_tree( prg, val ); + vm_set_local( exec, field, split ); + return split; +} + +static void downref_local_trees( program_t *prg, tree_t **sp, + execution_t *exec, struct local_info *locals, long locals_len ) +{ + long i; + for ( i = locals_len-1; i >= 0; i-- ) { + if ( locals[i].type == LI_Tree ) { + debug( prg, REALM_BYTECODE, "local tree downref: %ld\n", + (long)locals[i].offset ); + + tree_t *tree = (tree_t*) vm_get_local( exec, (long)locals[i].offset ); + colm_tree_downref( prg, sp, tree ); + } + } +} + +static void downref_locals( program_t *prg, tree_t ***psp, + execution_t *exec, struct local_info *locals, long locals_len ) +{ + long i; + for ( i = locals_len-1; i >= 0; i-- ) { + switch ( locals[i].type ) { + case LI_Tree: { + debug( prg, REALM_BYTECODE, "local tree downref: %ld\n", + (long)locals[i].offset ); + tree_t *tree = (tree_t*) vm_get_local( exec, (long)locals[i].offset ); + colm_tree_downref( prg, *psp, tree ); + break; + } + case LI_Iter: { + debug( prg, REALM_BYTECODE, "local iter downref: %ld\n", + (long)locals[i].offset ); + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal( exec, (long)locals[i].offset ); + colm_tree_iter_destroy( prg, psp, iter ); + break; + } + case LI_RevIter: { + debug( prg, REALM_BYTECODE, "local rev iter downref: %ld\n", + (long)locals[i].offset ); + rev_tree_iter_t *riter = (rev_tree_iter_t*) vm_get_plocal( exec, + (long)locals[i].offset ); + colm_rev_tree_iter_destroy( prg, psp, riter ); + break; + } + case LI_UserIter: { + debug( prg, REALM_BYTECODE, "local user iter downref: %ld\n", + (long)locals[i].offset ); + user_iter_t *uiter = (user_iter_t*) vm_get_local( exec, locals[i].offset ); + colm_uiter_unwind( prg, psp, uiter ); + break; + } + } + } +} + + +static tree_t *construct_arg0( program_t *prg, int argc, const char **argv, const int *argl ) +{ + tree_t *arg0 = 0; + if ( argc > 0 ) { + const char *argv0 = argv[0]; + size_t len = argl != 0 ? argl[0] : strlen( argv[0] ); + head_t *head = colm_string_alloc_pointer( prg, argv0, len ); + arg0 = construct_string( prg, head ); + colm_tree_upref( prg, arg0 ); + } + return arg0; +} + +static list_t *construct_argv( program_t *prg, int argc, const char **argv, const int *argl ) +{ + list_t *list = (list_t*)colm_construct_generic( prg, prg->rtd->argv_generic_id, 0 ); + int i; + for ( i = 1; i < argc; i++ ) { + size_t len = argl != 0 ? argl[i] : strlen(argv[i]); + const char *argv_i = argv[i]; + head_t *head = colm_string_alloc_pointer( prg, argv_i, len ); + tree_t *arg = construct_string( prg, head ); + colm_tree_upref( prg, arg ); + + struct_t *strct = colm_struct_new_size( prg, 16 ); + strct->id = prg->rtd->argv_el_id; + colm_struct_set_field( strct, tree_t*, 0, arg ); + list_el_t *list_el = colm_struct_get_addr( strct, list_el_t*, 1 ); + colm_list_append( list, list_el ); + } + + return list; +} + + +static list_t *construct_stds( program_t *prg ) +{ + make_stdout( prg ); + + list_t *list = (list_t*)colm_construct_generic( prg, prg->rtd->stds_generic_id, 0 ); + + struct_t *strct = colm_struct_new_size( prg, 16 ); + strct->id = prg->rtd->stds_el_id; + colm_struct_set_field( strct, stream_t*, 0, prg->stdout_val ); + list_el_t *list_el = colm_struct_get_addr( strct, list_el_t*, 1 ); + colm_list_append( list, list_el ); + + return list; +} + +/* + * Execution environment + */ + +void colm_rcode_downref_all( program_t *prg, tree_t **sp, struct rt_code_vect *rev ) +{ + while ( rev->tab_len > 0 ) { + /* Read the length */ + code_t *prcode = rev->data + rev->tab_len - SIZEOF_WORD; + word_t len; + read_word_p( len, prcode ); + + /* Find the start of block. */ + long start = rev->tab_len - len - SIZEOF_WORD; + prcode = rev->data + start; + + /* Execute it. */ + rcode_downref( prg, sp, prcode ); + + /* Backup over it. */ + rev->tab_len -= len + SIZEOF_WORD; + } +} + +static code_t *pcr_call( program_t *prg, execution_t *exec, tree_t ***psp, code_t *instr, parser_t *parser ) +{ + tree_t **sp = *psp; + + int frame_size = 0; + if ( parser->pda_run->frame_id >= 0 ) { + struct frame_info *fi = &prg->rtd->frame_info[parser->pda_run->frame_id]; + frame_size = fi->frame_size; + } + + vm_contiguous( 8 + frame_size ); + + vm_push_type( tree_t**, exec->frame_ptr ); + vm_push_type( tree_t**, exec->iframe_ptr ); + vm_push_type( long, exec->frame_id ); + vm_push_type( word_t, exec->steps ); + vm_push_type( word_t, exec->pcr ); + vm_push_parser( exec->parser ); + vm_push_type( word_t, exec->WV ); + + /* Return back to this instruction. We are alternating between + * parsing and calling instructions. */ + code_t *return_to = instr - SIZEOF_CODE; + vm_push_type( code_t*, return_to ); + + exec->frame_ptr = 0; + exec->iframe_ptr = 0; + exec->frame_id = 0; + exec->steps = 0; + exec->parser = parser; + + instr = parser->pda_run->code; + exec->WV = 1; + + exec->frame_id = parser->pda_run->frame_id; + + if ( parser->pda_run->frame_id >= 0 ) { + struct frame_info *fi = &prg->rtd->frame_info[parser->pda_run->frame_id]; + + exec->frame_ptr = vm_ptop(); + vm_pushn( fi->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fi->frame_size ); + } + + *psp = sp; + return instr; +} + +void colm_execute( program_t *prg, execution_t *exec, code_t *code ) +{ + tree_t **sp = prg->stack_root; + + struct frame_info *fi = &prg->rtd->frame_info[prg->rtd->root_frame_id]; + + /* Set up the stack as if we have + * called. We allow a return value. */ + + long stretch = FR_AA + fi->frame_size; + vm_contiguous( stretch ); + + vm_push_tree( 0 ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + + exec->frame_ptr = vm_ptop(); + vm_pushn( fi->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fi->frame_size ); + + /* Execution loop. */ + sp = colm_execute_code( prg, exec, sp, code ); + + downref_locals( prg, &sp, exec, fi->locals, fi->locals_len ); + vm_popn( fi->frame_size ); + + vm_pop_ignore(); + vm_pop_ignore(); + colm_tree_downref( prg, sp, prg->return_val ); + prg->return_val = vm_pop_tree(); + vm_pop_ignore(); + + prg->stack_root = sp; +} + +tree_t *colm_run_func( struct colm_program *prg, int frame_id, + const char **params, int param_count ) +{ + /* Make the arguments available to the program. */ + prg->argc = 0; + prg->argv = 0; + prg->argl = 0; + + execution_t execution; + memset( &execution, 0, sizeof(execution) ); + + tree_t **sp = prg->stack_root; + + struct frame_info *fi = &prg->rtd->frame_info[frame_id]; + code_t *code = fi->codeWC; + + vm_pushn( param_count ); + execution.call_args = vm_ptop(); + memset( vm_ptop(), 0, sizeof(word_t) * param_count ); + + int p; + for ( p = 0; p < param_count; p++ ) { + if ( params[p] == 0 ) { + ((value_t*)execution.call_args)[p] = 0; + } + else { + const char *param_p = params[p]; + size_t param_len = strlen(params[p]); + head_t *head = colm_string_alloc_pointer( prg, param_p, param_len ); + tree_t *tree = construct_string( prg, head ); + colm_tree_upref( prg, tree ); + ((tree_t**)execution.call_args)[p] = tree; + } + } + + long stretch = FR_AA + fi->frame_size; + vm_contiguous( stretch ); + + /* Set up the stack as if we have called. We allow a return value. */ + vm_push_tree( (tree_t*)execution.call_args ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + vm_push_tree( 0 ); + + execution.frame_id = frame_id; + + execution.frame_ptr = vm_ptop(); + vm_pushn( fi->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fi->frame_size ); + + /* Execution loop. */ + sp = colm_execute_code( prg, &execution, sp, code ); + + colm_tree_downref( prg, sp, prg->return_val ); + prg->return_val = execution.ret_val; + + vm_popn( param_count ); + + assert( sp == prg->stack_root ); + + return prg->return_val; +}; + +int colm_make_reverse_code( struct pda_run *pda_run ) +{ + struct rt_code_vect *reverse_code = &pda_run->reverse_code; + struct rt_code_vect *rcode_collect = &pda_run->rcode_collect; + + /* Do we need to revert the left hand side? */ + + /* Check if there was anything generated. */ + if ( rcode_collect->tab_len == 0 ) + return false; + + if ( pda_run->rc_block_count == 0 ) { + /* One reverse code run for the DECK terminator. */ + append_code_val( reverse_code, IN_PCR_END_DECK ); + append_code_val( reverse_code, IN_PCR_RET ); + append_word( reverse_code, 2 ); + pda_run->rc_block_count += 1; + colm_increment_steps( pda_run ); + } + + long start_length = reverse_code->tab_len; + + /* Go backwards, group by group, through the reverse code. Push each group + * to the global reverse code stack. */ + code_t *p = rcode_collect->data + rcode_collect->tab_len; + while ( p != rcode_collect->data ) { + p--; + long len = *p; + p = p - len; + append_code_vect( reverse_code, p, len ); + } + + /* Stop, then place a total length in the global stack. */ + append_code_val( reverse_code, IN_PCR_RET ); + long length = reverse_code->tab_len - start_length; + append_word( reverse_code, length ); + + /* Clear the revere code buffer. */ + rcode_collect->tab_len = 0; + + pda_run->rc_block_count += 1; + colm_increment_steps( pda_run ); + + return true; +} + +void colm_transfer_reverse_code( struct pda_run *pda_run, parse_tree_t *parse_tree ) +{ + if ( pda_run->rc_block_count > 0 ) { + //debug( REALM_PARSE, "attaching reverse code to token\n" ); + parse_tree->flags |= PF_HAS_RCODE; + pda_run->rc_block_count = 0; + } +} + +static void rcode_unit_term( execution_t *exec ) +{ + append_code_val( &exec->parser->pda_run->rcode_collect, exec->rcode_unit_len ); + exec->rcode_unit_len = 0; +} + +static void rcode_unit_start( execution_t *exec ) +{ + exec->rcode_unit_len = 0; +} + +static void rcode_code( execution_t *exec, const code_t code ) +{ + append_code_val( &exec->parser->pda_run->rcode_collect, code ); + exec->rcode_unit_len += SIZEOF_CODE; +} + +static void rcode_half( execution_t *exec, const half_t half ) +{ + append_half( &exec->parser->pda_run->rcode_collect, half ); + exec->rcode_unit_len += SIZEOF_HALF; +} + +static void rcode_word( execution_t *exec, const word_t word ) +{ + append_word( &exec->parser->pda_run->rcode_collect, word ); + exec->rcode_unit_len += SIZEOF_WORD; +} + +code_t *colm_pop_reverse_code( struct rt_code_vect *all_rev ) +{ + /* Read the length */ + code_t *prcode = all_rev->data + all_rev->tab_len - SIZEOF_WORD; + word_t len; + read_word_p( len, prcode ); + + /* Find the start of block. */ + long start = all_rev->tab_len - len - SIZEOF_WORD; + prcode = all_rev->data + start; + + /* Backup over it. */ + all_rev->tab_len -= len + SIZEOF_WORD; + return prcode; +} + +tree_t **colm_execute_code( program_t *prg, execution_t *exec, tree_t **sp, code_t *instr ) +{ + /* When we exit we are going to verify that we did not eat up any stack + * space. */ + tree_t **root = sp; + code_t c; + +again: + c = *instr++; + //debug( REALM_BYTECODE, "--in 0x%x\n", c ); + + switch ( c ) { + case IN_RESTORE_LHS: { + tree_t *restore; + read_tree( restore ); + + debug( prg, REALM_BYTECODE, "IN_RESTORE_LHS\n" ); + colm_tree_downref( prg, sp, exec->parser->pda_run->parse_input->shadow->tree ); + exec->parser->pda_run->parse_input->shadow->tree = restore; + break; + } + case IN_LOAD_NIL: { + debug( prg, REALM_BYTECODE, "IN_LOAD_NIL\n" ); + vm_push_tree( 0 ); + break; + } + case IN_LOAD_TREE: { + tree_t *tree; + read_tree( tree ); + vm_push_tree( tree ); + debug( prg, REALM_BYTECODE, "IN_LOAD_TREE %p id: %d refs: %d\n", + tree, tree->id, tree->refs ); + break; + } + case IN_LOAD_WORD: { + debug( prg, REALM_BYTECODE, "IN_LOAD_WORD\n" ); + word_t w; + read_word( w ); + vm_push_type( word_t, w ); + break; + } + case IN_LOAD_TRUE: { + debug( prg, REALM_BYTECODE, "IN_LOAD_TRUE\n" ); + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case IN_LOAD_FALSE: { + debug( prg, REALM_BYTECODE, "IN_LOAD_FALSE\n" ); + //colm_tree_upref( prg, prg->falseVal ); + vm_push_tree( prg->false_val ); + break; + } + case IN_LOAD_INT: { + word_t i; + read_word( i ); + + debug( prg, REALM_BYTECODE, "IN_LOAD_INT %d\n", i ); + + value_t value = i; + vm_push_value( value ); + break; + } + case IN_LOAD_STR: { + word_t offset; + read_word( offset ); + + debug( prg, REALM_BYTECODE, "IN_LOAD_STR %d\n", offset ); + + head_t *lit = make_literal( prg, offset ); + tree_t *tree = construct_string( prg, lit ); + colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + case IN_READ_REDUCE: { + half_t generic_id; + half_t reducer_id; + read_half( generic_id ); + read_half( reducer_id ); + + input_t *input = vm_pop_input(); + + debug( prg, REALM_BYTECODE, "IN_READ_REDUCE %hd %hd\n", generic_id, reducer_id ); + + prg->rtd->read_reduce( prg, reducer_id, input ); + + vm_push_tree( 0 ); + + break; + } + + /* + * LOAD_GLOBAL + */ + case IN_LOAD_GLOBAL_R: { + debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_R\n" ); + + vm_push_struct( prg->global ); + break; + } + case IN_LOAD_GLOBAL_WV: { + debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_WV\n" ); + + assert( exec->WV ); + + vm_push_struct( prg->global ); + + /* Set up the reverse instruction. */ + rcode_unit_start( exec ); + rcode_code( exec, IN_LOAD_GLOBAL_BKT ); + break; + } + case IN_LOAD_GLOBAL_WC: { + debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_WC\n" ); + + assert( !exec->WV ); + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + vm_push_struct( prg->global ); + break; + } + case IN_LOAD_GLOBAL_BKT: { + debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_BKT\n" ); + + vm_push_struct( prg->global ); + break; + } + + case IN_LOAD_INPUT_R: { + debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_R\n" ); + + assert( exec->parser != 0 ); + vm_push_input( exec->parser->input ); + break; + } + case IN_LOAD_INPUT_WV: { + debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_WV\n" ); + + assert( exec->WV ); + + assert( exec->parser != 0 ); + vm_push_input( exec->parser->input ); + + /* Set up the reverse instruction. */ + rcode_unit_start( exec ); + rcode_code( exec, IN_LOAD_INPUT_BKT ); + rcode_word( exec, (word_t)exec->parser->input ); + break; + } + case IN_LOAD_INPUT_WC: { + debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_WC\n" ); + + assert( !exec->WV ); + + assert( exec->parser != 0 ); + vm_push_input( exec->parser->input ); + break; + } + case IN_LOAD_INPUT_BKT: { + tree_t *accum_stream; + read_tree( accum_stream ); + + debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_BKT\n" ); + + colm_tree_upref( prg, accum_stream ); + vm_push_tree( accum_stream ); + break; + } + + case IN_LOAD_CONTEXT_R: { + debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_R\n" ); + + vm_push_type( struct_t*, exec->parser->pda_run->context ); + break; + } + case IN_LOAD_CONTEXT_WV: { + debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_WV\n" ); + + assert( exec->WV ); + + vm_push_type( struct_t *, exec->parser->pda_run->context ); + + /* Set up the reverse instruction. */ + rcode_unit_start( exec ); + rcode_code( exec, IN_LOAD_CONTEXT_BKT ); + break; + } + case IN_LOAD_CONTEXT_WC: { + debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_WC\n" ); + + assert( !exec->WV ); + + /* This is identical to the _R version, but using it for writing + * would be confusing. */ + vm_push_type( struct_t *, exec->parser->pda_run->context ); + break; + } + case IN_LOAD_CONTEXT_BKT: { + debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_BKT\n" ); + + vm_push_type( struct_t *, exec->parser->pda_run->context ); + break; + } + + case IN_SET_PARSER_CONTEXT: { + debug( prg, REALM_BYTECODE, "IN_SET_PARSER_CONTEXT\n" ); + + struct_t *strct = vm_pop_struct(); + parser_t *parser = vm_pop_parser(); + + colm_parser_set_context( prg, sp, parser, strct ); + + vm_push_parser( parser ); + break; + } + + case IN_SET_PARSER_INPUT: { + debug( prg, REALM_BYTECODE, "IN_SET_PARSER_INPUT\n" ); + + input_t *to_replace_with = vm_pop_input(); + parser_t *parser = vm_pop_parser(); + + parser->input = to_replace_with; + + vm_push_parser( parser ); + + break; + } + + case IN_INIT_CAPTURES: { + consume_byte(); + + debug( prg, REALM_BYTECODE, "IN_INIT_CAPTURES\n" ); + + /* If there are captures (this is a translate block) then copy them into + * the local frame now. */ + struct lang_el_info *lel_info = prg->rtd->lel_info; + struct pda_run *pda_run = exec->parser->pda_run; + alph_t **mark = pda_run->mark; + + int i, num_capture_attr = lel_info[pda_run->token_id].num_capture_attr; + for ( i = 0; i < num_capture_attr; i++ ) { + struct lang_el_info *lei = &lel_info[exec->parser->pda_run->token_id]; + CaptureAttr *ca = &prg->rtd->capture_attr[lei->capture_attr + i]; + head_t *data = string_alloc_full( prg, + colm_cstr_from_alph( mark[ca->mark_enter] ), + mark[ca->mark_leave] - mark[ca->mark_enter] ); + tree_t *string = construct_string( prg, data ); + colm_tree_upref( prg, string ); + set_local( exec, -1 - i, string ); + } + break; + } + case IN_INIT_RHS_EL: { + half_t position; + short field; + read_half( position ); + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_INIT_RHS_EL %hd\n", field ); + + tree_t *val = get_rhs_el( prg, exec->parser->pda_run->red_lel->shadow->tree, position ); + colm_tree_upref( prg, val ); + vm_set_local(exec, field, val); + break; + } + + case IN_INIT_LHS_EL: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_INIT_LHS_EL %hd\n", field ); + + /* We transfer it to to the local field. Possibly take a copy. */ + tree_t *val = exec->parser->pda_run->red_lel->shadow->tree; + + /* Save it. */ + colm_tree_upref( prg, val ); + exec->parser->pda_run->parsed = val; + + exec->parser->pda_run->red_lel->shadow->tree = 0; + vm_set_local(exec, field, val); + break; + } + case IN_STORE_LHS_EL: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_STORE_LHS_EL %hd\n", field ); + + tree_t *val = vm_get_local(exec, field); + vm_set_local(exec, field, 0); + exec->parser->pda_run->red_lel->shadow->tree = val; + break; + } + case IN_UITER_ADVANCE: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_ADVANCE\n" ); + + /* Get the iterator. */ + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + + long yield_size = vm_ssize() - uiter->root_size; + assert( uiter->yield_size == yield_size ); + + /* Fix the return instruction pointer. */ + uiter->stack_root[-IFR_AA + IFR_RIN] = (SW)instr; + + instr = uiter->resume; + exec->frame_ptr = uiter->frame; + exec->iframe_ptr = &uiter->stack_root[-IFR_AA]; + break; + } + case IN_UITER_GET_CUR_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_GET_CUR_R\n" ); + + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + tree_t *val = uiter->ref.kid->tree; + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_UITER_GET_CUR_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_GET_CUR_WC\n" ); + + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + split_ref( prg, &sp, &uiter->ref ); + tree_t *split = uiter->ref.kid->tree; + colm_tree_upref( prg, split ); + vm_push_tree( split ); + break; + } + case IN_UITER_SET_CUR_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_SET_CUR_WC\n" ); + + tree_t *t = vm_pop_tree(); + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + split_ref( prg, &sp, &uiter->ref ); + tree_t *old = uiter->ref.kid->tree; + set_uiter_cur( prg, uiter, t ); + colm_tree_downref( prg, sp, old ); + break; + } + case IN_GET_LOCAL_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_R %hd\n", field ); + + tree_t *val = vm_get_local(exec, field); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_LOCAL_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_WC %hd\n", field ); + + tree_t *split = get_local_split( prg, exec, field ); + colm_tree_upref( prg, split ); + vm_push_tree( split ); + break; + } + case IN_SET_LOCAL_WC: { + short field; + read_half( field ); + debug( prg, REALM_BYTECODE, "IN_SET_LOCAL_WC %hd\n", field ); + + tree_t *val = vm_pop_tree(); + colm_tree_downref( prg, sp, vm_get_local(exec, field) ); + set_local( exec, field, val ); + break; + } + case IN_GET_LOCAL_VAL_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_VAL_R %hd\n", field ); + + tree_t *val = vm_get_local(exec, field); + vm_push_tree( val ); + break; + } + case IN_SET_LOCAL_VAL_WC: { + short field; + read_half( field ); + debug( prg, REALM_BYTECODE, "IN_SET_LOCAL_VAL_WC %hd\n", field ); + + tree_t *val = vm_pop_tree(); + vm_set_local(exec, field, val); + break; + } + case IN_SAVE_RET: { + debug( prg, REALM_BYTECODE, "IN_SAVE_RET\n" ); + + value_t val = vm_pop_value(); + vm_set_local(exec, FR_RV, (tree_t*)val); + break; + } + case IN_GET_LOCAL_REF_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_REF_R\n" ); + + ref_t *ref = (ref_t*) vm_get_plocal(exec, field); + tree_t *val = ref->kid->tree; + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_LOCAL_REF_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LOCAL_REF_WC\n" ); + + ref_t *ref = (ref_t*) vm_get_plocal(exec, field); + split_ref( prg, &sp, ref ); + tree_t *val = ref->kid->tree; + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_SET_LOCAL_REF_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_LOCAL_REF_WC\n" ); + + tree_t *val = vm_pop_tree(); + ref_t *ref = (ref_t*) vm_get_plocal(exec, field); + split_ref( prg, &sp, ref ); + ref_set_value( prg, sp, ref, val ); + break; + } + case IN_GET_FIELD_TREE_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_TREE_R %d\n", field ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = colm_tree_get_field( obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_FIELD_TREE_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_TREE_WC %d\n", field ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *split = get_field_split( prg, obj, field ); + colm_tree_upref( prg, split ); + vm_push_tree( split ); + break; + } + case IN_GET_FIELD_TREE_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_TREE_WV\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *split = get_field_split( prg, obj, field ); + colm_tree_upref( prg, split ); + vm_push_tree( split ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_GET_FIELD_TREE_BKT ); + rcode_half( exec, field ); + break; + } + case IN_GET_FIELD_TREE_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_TREE_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *split = get_field_split( prg, obj, field ); + colm_tree_upref( prg, split ); + vm_push_tree( split ); + break; + } + case IN_SET_FIELD_TREE_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_TREE_WC %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + /* Downref the old value. */ + tree_t *prev = colm_tree_get_field( obj, field ); + colm_tree_downref( prg, sp, prev ); + + colm_tree_set_field( prg, obj, field, val ); + break; + } + case IN_SET_FIELD_TREE_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_TREE_WV %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + /* Save the old value, then set the field. */ + tree_t *prev = colm_tree_get_field( obj, field ); + colm_tree_set_field( prg, obj, field, val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_SET_FIELD_TREE_BKT ); + rcode_half( exec, field ); + rcode_word( exec, (word_t)prev ); + rcode_unit_term( exec ); + break; + } + case IN_SET_FIELD_TREE_BKT: { + short field; + tree_t *val; + read_half( field ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_TREE_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + /* Downref the old value. */ + tree_t *prev = colm_tree_get_field( obj, field ); + colm_tree_downref( prg, sp, prev ); + + colm_tree_set_field( prg, obj, field, val ); + break; + } + case IN_SET_FIELD_TREE_LEAVE_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_TREE_LEAVE_WC\n" ); + + /* Note that we don't downref the object here because we are + * leaving it on the stack. */ + tree_t *obj = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + + /* Downref the old value. */ + tree_t *prev = colm_tree_get_field( obj, field ); + colm_tree_downref( prg, sp, prev ); + + /* Set the field. */ + colm_tree_set_field( prg, obj, field, val ); + + /* Leave the object on the top of the stack. */ + vm_push_tree( obj ); + break; + } + case IN_GET_FIELD_VAL_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_VAL_R %d\n", field ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *pointer = colm_tree_get_field( obj, field ); + value_t value = 0; + if ( pointer != 0 ) + value = colm_get_pointer_val( pointer ); + vm_push_value( value ); + break; + } + case IN_SET_FIELD_VAL_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_VAL_WC %d\n", field ); + + tree_t *obj = vm_pop_tree(); + value_t value = vm_pop_value(); + colm_tree_downref( prg, sp, obj ); + + /* Downref the old value. */ + tree_t *prev = colm_tree_get_field( obj, field ); + colm_tree_downref( prg, sp, prev ); + + /* Make it into a pointer. */ + tree_t *pointer = colm_construct_pointer( prg, value ); + colm_tree_upref( prg, pointer ); + + colm_tree_set_field( prg, obj, field, pointer ); + break; + } + case IN_NEW_STRUCT: { + short id; + read_half( id ); + + debug( prg, REALM_BYTECODE, "IN_NEW_STRUCT %hd\n", id ); + struct_t *item = colm_struct_new( prg, id ); + vm_push_struct( item ); + break; + } + case IN_NEW_STREAM: { + debug( prg, REALM_BYTECODE, "IN_NEW_STREAM\n" ); + stream_t *item = colm_stream_open_collect( prg ); + vm_push_stream( item ); + break; + } + case IN_GET_COLLECT_STRING: { + debug( prg, REALM_BYTECODE, "IN_GET_COLLECT_STRING\n" ); + stream_t *stream = vm_pop_stream(); + str_t *str = collect_string( prg, stream ); + colm_tree_upref( prg, (tree_t*)str ); + vm_push_string( str ); + break; + } + case IN_GET_STRUCT_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_STRUCT_R %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = colm_struct_get_field( obj, tree_t*, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_STRUCT_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_STRUCT_WC %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = colm_struct_get_field( obj, tree_t*, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + + break; + } + case IN_GET_STRUCT_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_STRUCT_WV\n" ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = colm_struct_get_field( obj, tree_t*, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_GET_STRUCT_BKT ); + rcode_half( exec, field ); + break; + } + case IN_GET_STRUCT_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_STRUCT_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *split = get_field_split( prg, obj, field ); + colm_tree_upref( prg, split ); + vm_push_tree( split ); + break; + } + case IN_SET_STRUCT_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_WC %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + + /* Downref the old value. */ + tree_t *prev = colm_struct_get_field( obj, tree_t*, field ); + colm_tree_downref( prg, sp, prev ); + colm_struct_set_field( obj, tree_t*, field, val ); + break; + } + case IN_SET_STRUCT_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_WV %d\n", field ); + + struct_t *obj = vm_pop_struct(); + tree_t *val = vm_pop_tree(); + + /* Save the old value, then set the field. */ + tree_t *prev = colm_struct_get_field( obj, tree_t*, field ); + colm_struct_set_field( obj, tree_t*, field, val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_SET_STRUCT_BKT ); + rcode_half( exec, field ); + rcode_word( exec, (word_t)prev ); + rcode_unit_term( exec ); + break; + } + case IN_SET_STRUCT_BKT: { + short field; + tree_t *val; + read_half( field ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + + /* Downref the old value. */ + tree_t *prev = colm_struct_get_field( obj, tree_t*, field ); + colm_tree_downref( prg, sp, prev ); + + colm_struct_set_field( obj, tree_t*, field, val ); + break; + } + case IN_GET_STRUCT_VAL_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_STRUCT_VAL_R %d\n", field ); + + tree_t *obj = vm_pop_tree(); + tree_t *val = colm_struct_get_field( obj, tree_t*, field ); + vm_push_tree( val ); + break; + } + case IN_SET_STRUCT_VAL_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_VAL_WC %d\n", field ); + + struct_t *strct = vm_pop_struct(); + tree_t *val = vm_pop_tree(); + + colm_struct_set_field( strct, tree_t*, field, val ); + break; + } + case IN_SET_STRUCT_VAL_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_VAL_WV %d\n", field ); + + struct_t *strct = vm_pop_struct(); + tree_t *val = vm_pop_tree(); + + tree_t *prev = colm_struct_get_field( strct, tree_t*, field ); + colm_struct_set_field( strct, tree_t*, field, val ); + + rcode_code( exec, IN_SET_STRUCT_VAL_BKT ); + rcode_half( exec, field ); + rcode_word( exec, (word_t)prev ); + rcode_unit_term( exec ); + break; + } + case IN_SET_STRUCT_VAL_BKT: { + short field; + tree_t *val; + read_half( field ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_VAL_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + + colm_struct_set_field( obj, tree_t*, field, val ); + break; + } + case IN_GET_RHS_VAL_R: { + debug( prg, REALM_BYTECODE, "IN_GET_RHS_VAL_R\n" ); + int i, done = 0; + uchar len; + + tree_t *obj = vm_pop_tree(), *val = 0; + colm_tree_downref( prg, sp, obj ); + + read_byte( len ); + for ( i = 0; i < len; i++ ) { + uchar prod_num, child_num; + read_byte( prod_num ); + read_byte( child_num ); + if ( !done && obj->prod_num == prod_num ) { + val = get_rhs_el( prg, obj, child_num ); + done = 1; + } + } + + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_RHS_VAL_WC: + fatal( "UNIMPLEMENTED INSRUCTION: IN_GET_RHS_VAL_WC\n" ); + break; + case IN_GET_RHS_VAL_WV: + fatal( "UNIMPLEMENTED INSRUCTION: IN_GET_RHS_VAL_WV\n" ); + break; + case IN_GET_RHS_VAL_BKT: + fatal( "UNIMPLEMENTED INSRUCTION: IN_GET_RHS_VAL_BKT\n" ); + break; + + case IN_SET_RHS_VAL_WC: + debug( prg, REALM_BYTECODE, "IN_SET_RHS_VAL_WC\n" ); + int i, done = 0; + uchar len; + + tree_t *obj = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + read_byte( len ); + for ( i = 0; i < len; i++ ) { + uchar prod_num, child_num; + read_byte( prod_num ); + read_byte( child_num ); + if ( !done && obj->prod_num == prod_num ) { + tree_t *prev = get_rhs_el( prg, obj, child_num ); + colm_tree_downref( prg, sp, prev ); + set_rhs_el( prg, obj, child_num, val ); + done = 1; + } + } + + //colm_tree_upref( prg, val ); + //vm_push_tree( val ); + break; + case IN_SET_RHS_VAL_WV: + fatal( "UNIMPLEMENTED INSRUCTION: IN_SET_RHS_VAL_WV\n" ); + break; + case IN_SET_RHS_VAL_BKT: + fatal( "UNIMPLEMENTED INSRUCTION: IN_SET_RHS_VAL_BKT\n" ); + break; + case IN_POP_TREE: { + debug( prg, REALM_BYTECODE, "IN_POP_TREE\n" ); + + tree_t *val = vm_pop_tree(); + colm_tree_downref( prg, sp, val ); + break; + } + case IN_POP_VAL: { + debug( prg, REALM_BYTECODE, "IN_POP_VAL\n" ); + + vm_pop_tree(); + break; + } + case IN_POP_N_WORDS: { + short n; + read_half( n ); + + debug( prg, REALM_BYTECODE, "IN_POP_N_WORDS %hd\n", n ); + + vm_popn( n ); + break; + } + case IN_INT_TO_STR: { + debug( prg, REALM_BYTECODE, "IN_INT_TO_STR\n" ); + + value_t i = vm_pop_value(); + head_t *res = int_to_str( prg, (long)i ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + break; + } + case IN_TREE_TO_STR_XML: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_XML_AC\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str_xml( prg, sp, tree, false, false ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TO_STR_XML_AC: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_XML_AC\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str_xml_ac( prg, sp, tree, false, false ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TO_STR_POSTFIX: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_XML_AC\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str_postfix( prg, sp, tree, false, false ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TO_STR: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str( prg, sp, tree, false, false ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TO_STR_TRIM: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_TRIM\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str( prg, sp, tree, true, false ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TO_STR_TRIM_A: { + debug( prg, REALM_BYTECODE, "IN_TREE_TO_STR_TRIM_A\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *res = tree_to_str( prg, sp, tree, true, true ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TREE_TRIM: { + debug( prg, REALM_BYTECODE, "IN_TREE_TRIM\n" ); + + tree_t *tree = vm_pop_tree(); + tree_t *trimmed = tree_trim( prg, sp, tree ); + vm_push_tree( trimmed ); + break; + } + case IN_CONCAT_STR: { + debug( prg, REALM_BYTECODE, "IN_CONCAT_STR\n" ); + + str_t *s2 = vm_pop_string(); + str_t *s1 = vm_pop_string(); + head_t *res = concat_str( s1->value, s2->value ); + tree_t *str = construct_string( prg, res ); + colm_tree_upref( prg, str ); + colm_tree_downref( prg, sp, (tree_t*)s1 ); + colm_tree_downref( prg, sp, (tree_t*)s2 ); + vm_push_tree( str ); + break; + } + + case IN_STR_LENGTH: { + debug( prg, REALM_BYTECODE, "IN_STR_LENGTH\n" ); + + str_t *str = vm_pop_string(); + long len = string_length( str->value ); + value_t res = len; + vm_push_value( res ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case IN_JMP_FALSE_TREE: { + short dist; + read_half( dist ); + + debug( prg, REALM_BYTECODE, "IN_JMP_FALSE_TREE %d\n", dist ); + + tree_t *tree = vm_pop_tree(); + if ( test_false( prg, tree ) ) + instr += dist; + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_JMP_TRUE_TREE: { + short dist; + read_half( dist ); + + debug( prg, REALM_BYTECODE, "IN_JMP_TRUE_TREE %d\n", dist ); + + tree_t *tree = vm_pop_tree(); + if ( !test_false( prg, tree ) ) + instr += dist; + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_JMP_FALSE_VAL: { + short dist; + read_half( dist ); + + debug( prg, REALM_BYTECODE, "IN_JMP_FALSE_VAL %d\n", dist ); + + tree_t *tree = vm_pop_tree(); + if ( tree == 0 ) + instr += dist; + break; + } + case IN_JMP_TRUE_VAL: { + short dist; + read_half( dist ); + + debug( prg, REALM_BYTECODE, "IN_JMP_TRUE_VAL %d\n", dist ); + + tree_t *tree = vm_pop_tree(); + if ( tree != 0 ) + instr += dist; + break; + } + case IN_JMP: { + short dist; + read_half( dist ); + + debug( prg, REALM_BYTECODE, "IN_JMP\n" ); + + instr += dist; + break; + } + case IN_REJECT: { + debug( prg, REALM_BYTECODE, "IN_REJECT\n" ); + exec->parser->pda_run->reject = true; + break; + } + + /* + * Binary comparison operators. + */ + case IN_TST_EQL_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_EQL_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r == 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_EQL_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_EQL_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = o1 == o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_NOT_EQL_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_NOT_EQL_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r != 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_NOT_EQL_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_NOT_EQL_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = o1 != o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_LESS_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_LESS_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t res = (long)o1 < (long)o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( res ); + break; + } + case IN_TST_LESS_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_LESS_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r < 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_LESS_EQL_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_LESS_EQL_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = (long)o1 <= (long)o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_LESS_EQL_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_LESS_EQL_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r <= 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_GRTR_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_GRTR_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = (long)o1 > (long)o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_GRTR_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_GRTR_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r > 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_GRTR_EQL_VAL: { + debug( prg, REALM_BYTECODE, "IN_TST_GRTR_EQL_VAL\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + + value_t val = (long)o1 >= (long)o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_GRTR_EQL_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_GRTR_EQL_TREE\n" ); + + tree_t *o2 = vm_pop_tree(); + tree_t *o1 = vm_pop_tree(); + long r = colm_cmp_tree( prg, o1, o2 ); + value_t val = r >= 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, o1 ); + colm_tree_downref( prg, sp, o2 ); + break; + } + case IN_TST_LOGICAL_AND: { + debug( prg, REALM_BYTECODE, "IN_TST_LOGICAL_AND\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = o1 && o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + case IN_TST_LOGICAL_OR: { + debug( prg, REALM_BYTECODE, "IN_TST_LOGICAL_OR\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + value_t val = o1 || o2 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + + case IN_TST_NZ_TREE: { + debug( prg, REALM_BYTECODE, "IN_TST_NZ_TREE\n" ); + + tree_t *tree = vm_pop_tree(); + long r = !test_false( prg, tree ); + colm_tree_downref( prg, sp, tree ); + vm_push_value( r ); + break; + } + + case IN_NOT_VAL: { + debug( prg, REALM_BYTECODE, "IN_NOT_VAL\n" ); + + value_t o1 = vm_pop_value(); + value_t val = o1 == 0 ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + break; + } + + case IN_NOT_TREE: { + debug( prg, REALM_BYTECODE, "IN_NOT_TREE\n" ); + + tree_t *tree = vm_pop_tree(); + long r = test_false( prg, tree ); + value_t val = r ? TRUE_VAL : FALSE_VAL; + vm_push_value( val ); + colm_tree_downref( prg, sp, tree ); + break; + } + + case IN_ADD_INT: { + debug( prg, REALM_BYTECODE, "IN_ADD_INT\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + long r = (long)o1 + (long)o2; + value_t val = r; + vm_push_value( val ); + break; + } + case IN_MULT_INT: { + debug( prg, REALM_BYTECODE, "IN_MULT_INT\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + long r = (long)o1 * (long)o2; + value_t val = r; + vm_push_value( val ); + break; + } + case IN_DIV_INT: { + debug( prg, REALM_BYTECODE, "IN_DIV_INT\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + long r = (long)o1 / (long)o2; + value_t val = r; + vm_push_value( val ); + break; + } + case IN_SUB_INT: { + debug( prg, REALM_BYTECODE, "IN_SUB_INT\n" ); + + value_t o2 = vm_pop_value(); + value_t o1 = vm_pop_value(); + long r = (long)o1 - (long)o2; + value_t val = r; + vm_push_value( val ); + break; + } + case IN_DUP_VAL: { + debug( prg, REALM_BYTECODE, "IN_DUP_VAL\n" ); + + word_t val = (word_t)vm_top(); + vm_push_type( word_t, val ); + break; + } + case IN_DUP_TREE: { + debug( prg, REALM_BYTECODE, "IN_DUP_TREE\n" ); + + tree_t *val = vm_top(); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_TRITER_FROM_REF: { + short field; + half_t arg_size; + half_t search_type_id; + read_half( field ); + read_half( arg_size ); + read_half( search_type_id ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_FROM_REF " + "%hd %hd %hd\n", field, arg_size, search_type_id ); + + ref_t root_ref; + root_ref.kid = vm_pop_kid(); + root_ref.next = vm_pop_ref(); + void *mem = vm_get_plocal(exec, field); + + tree_t **stack_root = vm_ptop(); + long root_size = vm_ssize(); + + colm_init_tree_iter( (tree_iter_t*)mem, stack_root, + arg_size, root_size, &root_ref, search_type_id ); + break; + } + case IN_TRITER_UNWIND: + case IN_TRITER_DESTROY: { + short field; + read_half( field ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + debug( prg, REALM_BYTECODE, "IN_TRITER_DESTROY %hd %d\n", + field, iter->yield_size ); + colm_tree_iter_destroy( prg, &sp, iter ); + break; + } + case IN_REV_TRITER_FROM_REF: { + short field; + half_t arg_size; + half_t search_type_id; + read_half( field ); + read_half( arg_size ); + read_half( search_type_id ); + + debug( prg, REALM_BYTECODE, "IN_REV_TRITER_FROM_REF " + "%hd %hd %hd\n", field, arg_size, search_type_id ); + + ref_t root_ref; + root_ref.kid = vm_pop_kid(); + root_ref.next = vm_pop_ref(); + + tree_t **stack_root = vm_ptop(); + long root_size = vm_ssize(); + + int children = 0; + kid_t *kid = tree_child( prg, root_ref.kid->tree ); + while ( kid != 0 ) { + vm_push_kid( kid ); + kid = kid->next; + children++; + } + + void *mem = vm_get_plocal(exec, field); + colm_init_rev_tree_iter( (rev_tree_iter_t*)mem, stack_root, + arg_size, root_size, &root_ref, search_type_id, children ); + break; + } + case IN_REV_TRITER_UNWIND: + case IN_REV_TRITER_DESTROY: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REV_TRITER_DESTROY\n" ); + + rev_tree_iter_t *iter = (rev_tree_iter_t*) vm_get_plocal(exec, field); + colm_rev_tree_iter_destroy( prg, &sp, iter ); + break; + } + case IN_TREE_SEARCH: { + word_t id; + read_word( id ); + + debug( prg, REALM_BYTECODE, "IN_TREE_SEARCH\n" ); + + tree_t *tree = vm_pop_tree(); + tree_t *res = tree_search( prg, tree, id ); + colm_tree_upref( prg, res ); + vm_push_tree( res ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_TRITER_ADVANCE: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_ADVANCE\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + tree_t *res = tree_iter_advance( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_TRITER_NEXT_CHILD: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_NEXT_CHILD\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + tree_t *res = tree_iter_next_child( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_REV_TRITER_PREV_CHILD: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REV_TRITER_PREV_CHILD\n" ); + + rev_tree_iter_t *iter = (rev_tree_iter_t*) vm_get_plocal(exec, field); + tree_t *res = tree_rev_iter_prev_child( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_TRITER_NEXT_REPEAT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_NEXT_REPEAT\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + tree_t *res = tree_iter_next_repeat( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_TRITER_PREV_REPEAT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_PREV_REPEAT\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + tree_t *res = tree_iter_prev_repeat( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_TRITER_GET_CUR_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_GET_CUR_R\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + tree_t *tree = tree_iter_deref_cur( iter ); + colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + case IN_TRITER_GET_CUR_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_GET_CUR_WC\n" ); + + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + split_iter_cur( prg, &sp, iter ); + tree_t *tree = tree_iter_deref_cur( iter ); + colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + case IN_TRITER_SET_CUR_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_SET_CUR_WC\n" ); + + tree_t *tree = vm_pop_tree(); + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + split_iter_cur( prg, &sp, iter ); + tree_t *old = tree_iter_deref_cur( iter ); + set_triter_cur( prg, iter, tree ); + colm_tree_downref( prg, sp, old ); + break; + } + case IN_GEN_ITER_FROM_REF: { + short field; + half_t arg_size; + half_t generic_id; + read_half( field ); + read_half( arg_size ); + read_half( generic_id ); + + debug( prg, REALM_BYTECODE, "IN_GEN_ITER_FROM_REF " + "%hd %hd %hd\n", field, arg_size, generic_id ); + + ref_t root_ref; + root_ref.kid = vm_pop_kid(); + root_ref.next = vm_pop_ref(); + void *mem = vm_get_plocal(exec, field); + + tree_t **stack_root = vm_ptop(); + long root_size = vm_ssize(); + + colm_init_list_iter( (generic_iter_t*)mem, stack_root, arg_size, + root_size, &root_ref, generic_id ); + break; + } + case IN_GEN_ITER_UNWIND: + case IN_GEN_ITER_DESTROY: { + short field; + read_half( field ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + + debug( prg, REALM_BYTECODE, "IN_LIST_ITER_DESTROY %d\n", iter->yield_size ); + + colm_list_iter_destroy( prg, &sp, iter ); + break; + } + case IN_LIST_ITER_ADVANCE: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_LIST_ITER_ADVANCE\n" ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + tree_t *res = colm_list_iter_advance( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_REV_LIST_ITER_ADVANCE: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REV_LIST_ITER_ADVANCE\n" ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + tree_t *res = colm_rev_list_iter_advance( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_MAP_ITER_ADVANCE: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_MAP_ITER_ADVANCE\n" ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + tree_t *res = colm_map_iter_advance( prg, &sp, iter ); + //colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_GEN_ITER_GET_CUR_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GEN_ITER_GET_CUR_R\n" ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + tree_t *tree = colm_list_iter_deref_cur( prg, iter ); + //colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + case IN_GEN_VITER_GET_CUR_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GEN_VITER_GET_CUR_R\n" ); + + generic_iter_t *iter = (generic_iter_t*) vm_get_plocal(exec, field); + value_t value = colm_viter_deref_cur( prg, iter ); + vm_push_value( value ); + break; + } + case IN_MATCH: { + half_t pattern_id; + read_half( pattern_id ); + + debug( prg, REALM_BYTECODE, "IN_MATCH\n" ); + + tree_t *tree = vm_pop_tree(); + + /* Run the match, push the result. */ + int root_node = prg->rtd->pat_repl_info[pattern_id].offset; + + /* Bindings are indexed starting at 1. Zero bindId to represent no + * binding. We make a space for it here rather than do math at + * access them. */ + long num_bindings = prg->rtd->pat_repl_info[pattern_id].num_bindings; + tree_t *bindings[1+num_bindings]; + memset( bindings, 0, sizeof(tree_t*)*(1+num_bindings) ); + + kid_t kid; + kid.tree = tree; + kid.next = 0; + int matched = match_pattern( bindings, prg, root_node, &kid, false ); + + if ( !matched ) + memset( bindings, 0, sizeof(tree_t*)*(1+num_bindings) ); + else { + int b; + for ( b = 1; b <= num_bindings; b++ ) + assert( bindings[b] != 0 ); + } + + tree_t *result = matched ? tree : 0; + colm_tree_upref( prg, result ); + vm_push_tree( result ? tree : 0 ); + int b; + for ( b = 1; b <= num_bindings; b++ ) { + colm_tree_upref( prg, bindings[b] ); + vm_push_tree( bindings[b] ); + } + + colm_tree_downref( prg, sp, tree ); + break; + } + + case IN_PROD_NUM: { + debug( prg, REALM_BYTECODE, "IN_PROD_NUM\n" ); + + tree_t *tree = vm_pop_tree(); + colm_tree_downref( prg, sp, tree ); + + value_t v = tree->prod_num; + vm_push_value( v ); + break; + } + + case IN_PRINT_TREE: { + uchar trim; + read_byte( trim ); + + debug( prg, REALM_BYTECODE, "IN_PRINT_TREE %d\n", (int)trim ); + + tree_t *to_send = vm_pop_tree(); + stream_t *stream = vm_pop_stream(); + + struct stream_impl *si = stream_to_impl( stream ); + + int auto_trim; + if ( trim == TRIM_YES ) + auto_trim = true; + else if ( trim == TRIM_NO ) + auto_trim = false; + else + auto_trim = si->funcs->get_option( prg, si, 0 ); + + si->funcs->print_tree( prg, sp, si, to_send, auto_trim ); + vm_push_stream( stream ); + colm_tree_downref( prg, sp, to_send ); + break; + } + + case IN_SEND_TEXT_W: { + uchar trim; + read_byte( trim ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TEXT_W %d\n", (int)trim ); + + tree_t *to_send = vm_pop_tree(); + parser_t *parser = vm_pop_parser(); + + struct input_impl *si = input_to_impl( parser->input ); + + int auto_trim; + if ( trim == TRIM_YES ) + auto_trim = true; + else if ( trim == TRIM_NO ) + auto_trim = false; + else + auto_trim = si->funcs->get_option( prg, si, 0 ); + + word_t len = stream_append_text( prg, sp, parser->input, to_send, auto_trim ); + + vm_push_parser( parser ); + + if ( !exec->WV ) + colm_tree_downref( prg, sp, to_send ); + else { + rcode_unit_start( exec ); + rcode_code( exec, IN_SEND_TEXT_BKT ); + rcode_word( exec, (word_t) parser ); + rcode_word( exec, (word_t) to_send ); + rcode_word( exec, (word_t) len ); + rcode_unit_term( exec ); + } + + exec->steps = parser->pda_run->steps; + exec->pcr = PCR_START; + break; + } + + case IN_SEND_TEXT_BKT: { + parser_t *parser; + tree_t *sent; + word_t len; + read_parser( parser ); + read_tree( sent ); + read_word( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TEXT_BKT\n" ); + + struct input_impl *si = input_to_impl( parser->input ); + stream_undo_append( prg, sp, si, sent, len ); + + colm_tree_downref( prg, sp, sent ); + break; + } + + case IN_SEND_TREE_W: { + uchar trim; + read_byte( trim ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TREE_W %d\n", (int)trim ); + + tree_t *to_send = vm_pop_tree(); + parser_t *parser = vm_pop_parser(); + + struct input_impl *si = input_to_impl( parser->input ); + + int auto_trim; + if ( trim == TRIM_YES ) + auto_trim = true; + else if ( trim == TRIM_NO ) + auto_trim = false; + else + auto_trim = si->funcs->get_option( prg, si, 0 ); + + if ( auto_trim ) + to_send = tree_trim( prg, sp, to_send ); + + word_t len = stream_append_tree( prg, sp, parser->input, to_send ); + + vm_push_parser( parser ); + + if ( !exec->WV ) + colm_tree_downref( prg, sp, to_send ); + else { + rcode_unit_start( exec ); + rcode_code( exec, IN_SEND_TREE_BKT ); + rcode_word( exec, (word_t) parser ); + rcode_word( exec, (word_t) to_send ); + rcode_word( exec, (word_t) len ); + rcode_unit_term( exec ); + } + + exec->steps = parser->pda_run->steps; + exec->pcr = PCR_START; + break; + } + + case IN_SEND_TREE_BKT: { + parser_t *parser; + tree_t *sent; + word_t len; + read_parser( parser ); + read_tree( sent ); + read_word( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TREE_BKT\n" ); + + struct input_impl *si = input_to_impl( parser->input ); + stream_undo_append( prg, sp, si, sent, len ); + + colm_tree_downref( prg, sp, sent ); + break; + } + + case IN_SEND_NOTHING: { + parser_t *parser = vm_pop_parser(); + vm_push_parser( parser ); + exec->steps = parser->pda_run->steps; + exec->pcr = PCR_START; + break; + } + case IN_SEND_STREAM_W: { + debug( prg, REALM_BYTECODE, "IN_SEND_STREAM_W\n" ); + + stream_t *to_send = vm_pop_stream(); + parser_t *parser = vm_pop_parser(); + + word_t len = stream_append_stream( prg, sp, parser->input, to_send ); + + vm_push_parser( parser ); + + if ( exec->WV ) { + rcode_unit_start( exec ); + rcode_code( exec, IN_SEND_STREAM_BKT ); + rcode_word( exec, (word_t) parser ); + rcode_word( exec, (word_t) to_send ); + rcode_word( exec, (word_t) len ); + rcode_unit_term( exec ); + } + + exec->steps = parser->pda_run->steps; + exec->pcr = PCR_START; + + break; + } + + case IN_SEND_STREAM_BKT: { + parser_t *parser; + tree_t *sent; + word_t len; + read_parser( parser ); + read_tree( sent ); + read_word( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_STREAM_BKT\n" ); + + struct input_impl *si = input_to_impl( parser->input ); + stream_undo_append_stream( prg, sp, si, sent, len ); + break; + } + + case IN_SEND_EOF_W: { + struct input_impl *si; + + debug( prg, REALM_BYTECODE, "IN_SEND_EOF_W\n" ); + parser_t *parser = vm_pop_parser(); + vm_push_parser( parser ); + + si = input_to_impl( parser->input ); + si->funcs->set_eof_mark( prg, si, true ); + + if ( exec->WV ) { + rcode_unit_start( exec ); + rcode_code( exec, IN_SEND_EOF_BKT ); + rcode_word( exec, (word_t) parser ); + rcode_unit_term( exec ); + } + + exec->steps = parser->pda_run->steps; + exec->pcr = PCR_START; + break; + } + + case IN_SEND_EOF_BKT: { + parser_t *parser; + read_parser( parser ); + + debug( prg, REALM_BYTECODE, "IN_SEND_EOF_BKT\n" ); + + struct input_impl *si = input_to_impl( parser->input ); + si->funcs->set_eof_mark( prg, si, false ); + break; + } + + case IN_INPUT_CLOSE_WC: { + debug( prg, REALM_BYTECODE, "IN_INPUT_CLOSE_WC\n" ); + + stream_t *stream = vm_pop_stream(); + struct stream_impl *si = stream->impl; + + si->funcs->close_stream( prg, si ); + + vm_push_stream( stream ); + break; + } + case IN_INPUT_AUTO_TRIM_WC: { + debug( prg, REALM_BYTECODE, "IN_INPUT_AUTO_TRIM_WC\n" ); + + stream_t *stream = vm_pop_stream(); + value_t auto_trim = vm_pop_value(); + struct stream_impl *si = stream->impl; + + si->funcs->set_option( prg, si, 0, (long) auto_trim ); + + vm_push_stream( stream ); + break; + } + case IN_IINPUT_AUTO_TRIM_WC: { + debug( prg, REALM_BYTECODE, "IN_INPUT_AUTO_TRIM_WC\n" ); + + input_t *input = vm_pop_input(); + value_t auto_trim = vm_pop_value(); + struct input_impl *ii = input->impl; + + ii->funcs->set_option( prg, ii, 0, (long) auto_trim ); + + vm_push_input( input ); + break; + } + + case IN_SET_ERROR: { + debug( prg, REALM_BYTECODE, "IN_SET_ERROR\n" ); + + tree_t *error = vm_pop_tree(); + colm_tree_downref( prg, sp, prg->error ); + prg->error = error; + break; + } + + case IN_GET_ERROR: { + debug( prg, REALM_BYTECODE, "IN_GET_ERROR\n" ); + + vm_pop_tree(); + colm_tree_upref( prg, prg->error ); + vm_push_tree( prg->error ); + break; + } + + /* stream: + * Push value and stash current on IN_PCR_CALL. The instructions + * exectued by a call need access to the stream the parser was called + * with. We need to preserver the stream for the caller, so we push + * first set it to the current stream. + * pcr: + * Need to preserve the pcr value between pda run invocations. Push + * current pcr value and start fresh with a new value on PCR_CALL. + * steps: + * Init from the PDA run when we start to parse. Need to preserve the + * starting steps value from the start of parsing to the moment we + * write the backtrack instruction. Start fresh with a private value + * on a PCR_CALL by pushing and initializing. */ + + case IN_PARSE_INIT_BKT: { + debug( prg, REALM_BYTECODE, "IN_PARSE_INIT_BKT\n" ); + + parser_t *parser; + word_t steps; + + read_parser( parser ); + read_word( steps ); + + vm_push_parser( parser ); + + exec->steps = steps; + exec->pcr = PCR_START; + break; + } + + case IN_LOAD_RETVAL: { + debug( prg, REALM_BYTECODE, "IN_LOAD_RETVAL\n" ); + vm_push_tree( exec->ret_val ); + break; + } + + case IN_PCR_RET: { + debug( prg, REALM_BYTECODE, "IN_PCR_RET\n" ); + + if ( exec->frame_id >= 0 ) { + struct frame_info *fi = &prg->rtd->frame_info[exec->frame_id]; + downref_local_trees( prg, sp, exec, fi->locals, fi->locals_len ); + debug( prg, REALM_BYTECODE, "RET: %d\n", fi->frame_size ); + + vm_popn( fi->frame_size ); + } + + instr = vm_pop_type(code_t*); + + exec->WV = vm_pop_type(word_t); + exec->parser = vm_pop_parser(); + exec->pcr = vm_pop_type(word_t); + exec->steps = vm_pop_type(word_t); + exec->frame_id = vm_pop_type(long); + exec->iframe_ptr = vm_pop_type(tree_t**); + exec->frame_ptr = vm_pop_type(tree_t**); + + assert( instr != 0 ); + break; + } + + case IN_PCR_END_DECK: { + debug( prg, REALM_BYTECODE, "IN_PCR_END_DECK\n" ); + exec->parser->pda_run->on_deck = false; + break; + } + + case IN_PARSE_FRAG_W: { + parser_t *parser = vm_pop_parser(); + vm_push_parser( parser ); + + debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_W\n" ); + + exec->pcr = colm_parse_frag( prg, sp, parser->pda_run, + parser->input, exec->pcr ); + + /* If done, jump to the terminating instruction, otherwise fall + * through to call some code, then jump back here. */ + if ( exec->pcr != PCR_DONE ) + instr = pcr_call( prg, exec, &sp, instr, parser ); + else { + if ( exec->WV ) { + rcode_unit_start( exec ); + + rcode_code( exec, IN_PARSE_INIT_BKT ); + rcode_word( exec, (word_t)parser ); + rcode_word( exec, (word_t)exec->steps ); + rcode_code( exec, IN_PARSE_FRAG_BKT ); + rcode_unit_term( exec ); + } + + if ( prg->induce_exit ) + goto out; + } + break; + } + + case IN_PARSE_FRAG_BKT: { + parser_t *parser = vm_pop_parser(); + vm_push_parser( parser ); + + debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_BKT\n" ); + + exec->pcr = colm_parse_undo_frag( prg, sp, parser->pda_run, + parser->input, exec->pcr, exec->steps ); + + if ( exec->pcr != PCR_DONE ) + instr = pcr_call( prg, exec, &sp, instr, parser ); + else { + vm_pop_parser(); + } + break; + } + + case IN_REDUCE_COMMIT: { + parser_t *parser = vm_pop_parser(); + vm_push_parser( parser ); + + debug( prg, REALM_BYTECODE, "IN_REDUCE_COMMIT\n" ); + + colm_parse_reduce_commit( prg, sp, parser->pda_run ); + break; + } + + + case IN_INPUT_PULL_WV: { + debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_WV\n" ); + + input_t *input = vm_pop_input(); + tree_t *len = vm_pop_tree(); + tree_t *string = stream_pull_bc( prg, sp, 0, input, len ); + colm_tree_upref( prg, string ); + vm_push_tree( string ); + + /* Single unit. */ + colm_tree_upref( prg, string ); + rcode_code( exec, IN_INPUT_PULL_BKT ); + rcode_word( exec, (word_t) string ); + rcode_unit_term( exec ); + + //colm_tree_downref( prg, sp, len ); + break; + } + + case IN_INPUT_PULL_WC: { + debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_WC\n" ); + + input_t *input = vm_pop_input(); + tree_t *len = vm_pop_tree(); + tree_t *string = stream_pull_bc( prg, sp, 0, input, len ); + colm_tree_upref( prg, string ); + vm_push_tree( string ); + + //colm_tree_downref( prg, sp, len ); + break; + } + case IN_INPUT_PULL_BKT: { + tree_t *string; + read_tree( string ); + + input_t *input = vm_pop_input(); + + debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_BKT\n" ); + + undo_pull( prg, input, string ); + colm_tree_downref( prg, sp, string ); + break; + } + case IN_INPUT_PUSH_WV: { + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_WV\n" ); + + input_t *input = vm_pop_input(); + tree_t *tree = vm_pop_tree(); + long len = input_push( prg, sp, input_to_impl( input ), tree, false ); + vm_push_tree( 0 ); + + /* Single unit. */ + rcode_code( exec, IN_INPUT_PUSH_BKT ); + rcode_word( exec, len ); + rcode_unit_term( exec ); + + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_INPUT_PUSH_IGNORE_WV: { + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_IGNORE_WV\n" ); + + input_t *input = vm_pop_input(); + tree_t *tree = vm_pop_tree(); + long len = input_push( prg, sp, input_to_impl( input ), tree, true ); + vm_push_tree( 0 ); + + /* Single unit. */ + rcode_code( exec, IN_INPUT_PUSH_BKT ); + rcode_word( exec, len ); + rcode_unit_term( exec ); + + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_INPUT_PUSH_BKT: { + word_t len; + read_word( len ); + + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_BKT %d\n", len ); + + input_t *input = vm_pop_input(); + colm_undo_stream_push( prg, sp, input_to_impl( input ), len ); + break; + } + case IN_INPUT_PUSH_STREAM_WV: { + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_STREAM_WV\n" ); + + input_t *input = vm_pop_input(); + stream_t *to_push = vm_pop_stream(); + long len = input_push_stream( prg, sp, input_to_impl( input ), to_push ); + vm_push_tree( 0 ); + + /* Single unit. */ + rcode_code( exec, IN_INPUT_PUSH_BKT ); + rcode_word( exec, len ); + rcode_unit_term( exec ); + break; + } + case IN_INPUT_PUSH_STREAM_BKT: { + word_t len; + read_word( len ); + + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_STREAM_BKT %d\n", len ); + + input_t *input = vm_pop_input(); + colm_undo_stream_push( prg, sp, input_to_impl( input ), len ); + break; + } + case IN_CONS_GENERIC: { + half_t generic_id; + half_t stop_id; + read_half( generic_id ); + read_half( stop_id ); + + debug( prg, REALM_BYTECODE, "IN_CONS_GENERIC %hd %hd\n", generic_id, stop_id ); + + struct_t *gen = colm_construct_generic( prg, generic_id, stop_id ); + vm_push_struct( gen ); + break; + } + case IN_CONS_REDUCER: { + half_t generic_id; + half_t reducer_id; + read_half( generic_id ); + read_half( reducer_id ); + + debug( prg, REALM_BYTECODE, "IN_CONS_REDUCER %hd\n", generic_id ); + + struct_t *gen = colm_construct_reducer( prg, generic_id, reducer_id ); + vm_push_struct( gen ); + break; + } + case IN_CONS_OBJECT: { + half_t lang_el_id; + read_half( lang_el_id ); + + debug( prg, REALM_BYTECODE, "IN_CONS_OBJECT %hd\n", lang_el_id ); + + tree_t *repl_tree = colm_construct_object( prg, 0, 0, lang_el_id ); + vm_push_tree( repl_tree ); + break; + } + case IN_CONSTRUCT: { + half_t pattern_id; + read_half( pattern_id ); + + debug( prg, REALM_BYTECODE, "IN_CONSTRUCT\n" ); + + //struct lang_el_info *lelInfo = prg->rtd->lelInfo; + //struct pat_cons_node *nodes = prg->rtd->patReplNodes; + int root_node = prg->rtd->pat_repl_info[pattern_id].offset; + + /* Note that bindIds are indexed at one. Add one spot for them. */ + int num_bindings = prg->rtd->pat_repl_info[pattern_id].num_bindings; + tree_t *bindings[1+num_bindings]; + + int b; + for ( b = 1; b <= num_bindings; b++ ) { + bindings[b] = vm_pop_tree(); + assert( bindings[b] != 0 ); + } + + tree_t *repl_tree = colm_construct_tree( prg, 0, bindings, root_node ); + + vm_push_tree( repl_tree ); + break; + } + case IN_CONSTRUCT_TERM: { + half_t token_id; + read_half( token_id ); + + debug( prg, REALM_BYTECODE, "IN_CONSTRUCT_TERM\n" ); + + /* Pop the string we are constructing the token from. */ + str_t *str = vm_pop_string(); + tree_t *res = colm_construct_term( prg, token_id, str->value ); + colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_MAKE_TOKEN: { + uchar nargs; + int i; + read_byte( nargs ); + + debug( prg, REALM_BYTECODE, "IN_MAKE_TOKEN\n" ); + + tree_t *arg[nargs]; + for ( i = nargs-1; i >= 0; i-- ) + arg[i] = vm_pop_tree(); + + tree_t *result = colm_construct_token( prg, arg, nargs ); + for ( i = 1; i < nargs; i++ ) + colm_tree_downref( prg, sp, arg[i] ); + vm_push_tree( result ); + break; + } + case IN_MAKE_TREE: { + uchar nargs; + int i; + read_byte( nargs ); + + debug( prg, REALM_BYTECODE, "IN_MAKE_TREE\n" ); + + tree_t *arg[nargs]; + for ( i = nargs-1; i >= 0; i-- ) + arg[i] = vm_pop_tree(); + + tree_t *result = make_tree( prg, arg, nargs ); + for ( i = 1; i < nargs; i++ ) + colm_tree_downref( prg, sp, arg[i] ); + + vm_push_tree( result ); + break; + } + case IN_TREE_CAST: { + half_t lang_el_id; + read_half( lang_el_id ); + + debug( prg, REALM_BYTECODE, "IN_TREE_CAST %hd\n", lang_el_id ); + + tree_t *tree = vm_pop_tree(); + tree_t *res = cast_tree( prg, lang_el_id, tree ); + colm_tree_upref( prg, res ); + colm_tree_downref( prg, sp, tree ); + vm_push_tree( res ); + break; + } + case IN_PTR_ACCESS_WV: { + debug( prg, REALM_BYTECODE, "IN_PTR_ACCESS_WV\n" ); + + struct_t *ptr = vm_pop_struct(); + vm_push_struct( ptr ); + + /* This is an initial global load. Need to reverse execute it. */ + rcode_unit_start( exec ); + rcode_code( exec, IN_PTR_ACCESS_BKT ); + rcode_word( exec, (word_t) ptr ); + break; + } + case IN_PTR_ACCESS_BKT: { + word_t p; + read_word( p ); + + debug( prg, REALM_BYTECODE, "IN_PTR_ACCESS_BKT\n" ); + + struct_t *ptr = (struct_t*)p; + vm_push_type( struct_t *, ptr ); + break; + } + case IN_REF_FROM_LOCAL: { + short int field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REF_FROM_LOCAL %hd\n", field ); + + /* First push the null next pointer, then the kid pointer. */ + kid_t *kid = (kid_t*)vm_get_plocal(exec, field); + vm_contiguous( 2 ); + vm_push_ref( 0 ); + vm_push_kid( kid ); + break; + } + case IN_REF_FROM_REF: { + short int field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REF_FROM_REF %hd\n", field ); + + ref_t *ref = (ref_t*)vm_get_plocal(exec, field); + vm_contiguous( 2 ); + vm_push_ref( ref ); + vm_push_kid( ref->kid ); + break; + } + case IN_REF_FROM_QUAL_REF: { + short int back; + short int field; + read_half( back ); + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_REF_FROM_QUAL_REF\n" ); + + ref_t *ref = (ref_t*)(sp + back); + + tree_t *obj = ref->kid->tree; + kid_t *attr_kid = get_field_kid( obj, field ); + + vm_contiguous( 2 ); + vm_push_ref( ref ); + vm_push_kid( attr_kid ); + break; + } + case IN_RHS_REF_FROM_QUAL_REF: { + short int back; + int i, done = 0; + uchar len; + + read_half( back ); + + debug( prg, REALM_BYTECODE, "IN_RHS_REF_FROM_QUAL_REF\n" ); + + ref_t *ref = (ref_t*)(sp + back); + + tree_t *obj = ref->kid->tree; + kid_t *attr_kid = 0; + + read_byte( len ); + for ( i = 0; i < len; i++ ) { + uchar prod_num, child_num; + read_byte( prod_num ); + read_byte( child_num ); + if ( !done && obj->prod_num == prod_num ) { + attr_kid = get_rhs_el_kid( prg, obj, child_num ); + done = 1; + } + } + + vm_contiguous( 2 ); + vm_push_ref( ref ); + vm_push_kid( attr_kid ); + break; + } + case IN_REF_FROM_BACK: { + short int back; + read_half( back ); + + debug( prg, REALM_BYTECODE, "IN_REF_FROM_BACK %hd\n", back ); + + kid_t *ptr = (kid_t*)(sp + back); + + vm_contiguous( 2 ); + vm_push_ref( 0 ); + vm_push_kid( ptr ); + break; + } + case IN_TRITER_REF_FROM_CUR: { + short int field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_TRITER_REF_FROM_CUR\n" ); + + /* Push the next pointer first, then the kid. */ + tree_iter_t *iter = (tree_iter_t*) vm_get_plocal(exec, field); + ref_t *ref = &iter->ref; + vm_contiguous( 2 ); + vm_push_ref( ref ); + vm_push_kid( iter->ref.kid ); + break; + } + case IN_UITER_REF_FROM_CUR: { + short int field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_REF_FROM_CUR\n" ); + + /* Push the next pointer first, then the kid. */ + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + vm_contiguous( 2 ); + vm_push_ref( uiter->ref.next ); + vm_push_kid( uiter->ref.kid ); + break; + } + case IN_GET_TOKEN_DATA_R: { + debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_DATA_R\n" ); + + tree_t *tree = vm_pop_tree(); + head_t *data = string_copy( prg, tree->tokdata ); + tree_t *str = construct_string( prg, data ); + colm_tree_upref( prg, str ); + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_SET_TOKEN_DATA_WC: { + debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_WC\n" ); + + tree_t *tree = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + head_t *head = string_copy( prg, ((str_t*)val)->value ); + string_free( prg, tree->tokdata ); + tree->tokdata = head; + + colm_tree_downref( prg, sp, tree ); + colm_tree_downref( prg, sp, val ); + break; + } + case IN_SET_TOKEN_DATA_WV: { + debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_WV\n" ); + + tree_t *tree = vm_pop_tree(); + tree_t *val = vm_pop_tree(); + + head_t *oldval = tree->tokdata; + head_t *head = string_copy( prg, ((str_t*)val)->value ); + tree->tokdata = head; + + /* Set up reverse code. Needs no args. */ + rcode_code( exec, IN_SET_TOKEN_DATA_BKT ); + rcode_word( exec, (word_t)oldval ); + rcode_unit_term( exec ); + + colm_tree_downref( prg, sp, tree ); + colm_tree_downref( prg, sp, val ); + break; + } + case IN_SET_TOKEN_DATA_BKT: { + debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_BKT \n" ); + + word_t oldval; + read_word( oldval ); + + tree_t *tree = vm_pop_tree(); + head_t *head = (head_t*)oldval; + string_free( prg, tree->tokdata ); + tree->tokdata = head; + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_GET_TOKEN_FILE_R: { + debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_FILE_R\n" ); + tree_t *tree = vm_pop_tree(); + tree_t *str = 0; + if ( tree->tokdata->location ) { + const char *fn = tree->tokdata->location->name; + size_t fnlen = strlen( fn ); + head_t *data = string_alloc_full( prg, fn, fnlen ); + str = construct_string( prg, data ); + colm_tree_upref( prg, str ); + } + vm_push_tree( str ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_GET_TOKEN_LINE_R: { + debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_LINE_R\n" ); + + tree_t *tree = vm_pop_tree(); + value_t integer = 0; + if ( tree->tokdata->location ) + integer = tree->tokdata->location->line; + vm_push_value( integer ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_GET_TOKEN_COL_R: { + debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_COL_R\n" ); + + tree_t *tree = vm_pop_tree(); + value_t integer = 0; + if ( tree->tokdata->location ) + integer = tree->tokdata->location->column; + vm_push_value( integer ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_GET_TOKEN_POS_R: { + debug( prg, REALM_BYTECODE, "IN_GET_TOKEN_POS_R\n" ); + + tree_t *tree = vm_pop_tree(); + value_t integer = 0; + if ( tree->tokdata->location ) + integer = tree->tokdata->location->byte; + vm_push_value( integer ); + colm_tree_downref( prg, sp, tree ); + break; + } + case IN_GET_MATCH_LENGTH_R: { + debug( prg, REALM_BYTECODE, "IN_GET_MATCH_LENGTH_R\n" ); + + value_t integer = string_length(exec->parser->pda_run->tokdata); + vm_push_value( integer ); + break; + } + case IN_GET_MATCH_TEXT_R: { + debug( prg, REALM_BYTECODE, "IN_GET_MATCH_TEXT_R\n" ); + + head_t *s = string_copy( prg, exec->parser->pda_run->tokdata ); + tree_t *tree = construct_string( prg, s ); + colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + case IN_LIST_LENGTH: { + debug( prg, REALM_BYTECODE, "IN_LIST_LENGTH\n" ); + + list_t *list = vm_pop_list(); + long len = colm_list_length( list ); + value_t res = len; + vm_push_value( res ); + break; + } + case IN_GET_LIST_EL_MEM_R: { + short gen_id, field; + read_half( gen_id ); + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LIST_EL_MEM_R\n" ); + + struct_t *s = vm_pop_struct(); + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + struct_t *val = colm_list_el_get( prg, list_el, gen_id, field ); + vm_push_struct( val ); + break; + } + case IN_GET_LIST_MEM_R: { + short gen_id, field; + read_half( gen_id ); + read_half( field ); + + debug( prg, REALM_BYTECODE, + "IN_GET_LIST_MEM_R %hd %hd\n", gen_id, field ); + + list_t *list = vm_pop_list(); + struct_t *val = colm_list_get( prg, list, gen_id, field ); + vm_push_struct( val ); + break; + } + case IN_GET_LIST_MEM_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_WC\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_LIST_MEM_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_WV\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_GET_LIST_MEM_BKT ); + rcode_half( exec, field ); + break; + } + case IN_GET_LIST_MEM_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *res = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_GET_VLIST_MEM_R: { + short gen_id, field; + read_half( gen_id ); + read_half( field ); + + debug( prg, REALM_BYTECODE, + "IN_GET_VLIST_MEM_R %hd %hd\n", gen_id, field ); + + list_t *list = vm_pop_list(); + struct_t *el = colm_list_get( prg, list, gen_id, field ); + + value_t val = colm_struct_get_field( el, value_t, 0 ); + vm_push_value( val ); + break; + } + case IN_GET_VLIST_MEM_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_VLIST_MEM_WC\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_VLIST_MEM_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_VLIST_MEM_WV\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_GET_LIST_MEM_BKT ); + rcode_half( exec, field ); + break; + } + case IN_GET_VLIST_MEM_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_VLIST_MEM_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *res = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + case IN_GET_PARSER_STREAM: { + debug( prg, REALM_BYTECODE, "IN_GET_PARSER_STREAM\n" ); + parser_t *parser = vm_pop_parser(); + vm_push_input( parser->input ); + break; + } + case IN_GET_PARSER_MEM_R: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_PARSER_MEM_R %hd\n", field ); + + parser_t *parser = vm_pop_parser(); + + tree_t *val = get_parser_mem( parser, field ); + + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + + case IN_GET_MAP_EL_MEM_R: { + short gen_id, field; + read_half( gen_id ); + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_MAP_EL_MEM_R\n" ); + + struct_t *strct = vm_pop_struct(); + + map_el_t *map_el = colm_struct_to_map_el( prg, strct, gen_id ); + struct_t *val = colm_map_el_get( prg, map_el, gen_id, field ); + vm_push_struct( val ); + break; + } + case IN_MAP_LENGTH: { + debug( prg, REALM_BYTECODE, "IN_MAP_LENGTH\n" ); + + tree_t *obj = vm_pop_tree(); + long len = map_length( (map_t*)obj ); + value_t res = len; + vm_push_value( res ); + break; + } + case IN_GET_MAP_MEM_R: { + short gen_id, field; + read_half( gen_id ); + read_half( field ); + + debug( prg, REALM_BYTECODE, + "IN_GET_MAP_MEM_R %hd %hd\n", gen_id, field ); + + map_t *map = vm_pop_map(); + struct_t *val = colm_map_get( prg, map, gen_id, field ); + vm_push_struct( val ); + break; + } + case IN_GET_MAP_MEM_WC: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_MAP_MEM_WC\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + break; + } + case IN_GET_MAP_MEM_WV: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_MAP_MEM_WV\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *val = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, val ); + vm_push_tree( val ); + + /* Set up the reverse instruction. */ + rcode_code( exec, IN_GET_MAP_MEM_BKT ); + rcode_half( exec, field ); + break; + } + case IN_GET_MAP_MEM_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_MAP_MEM_BKT\n" ); + + tree_t *obj = vm_pop_tree(); + colm_tree_downref( prg, sp, obj ); + + tree_t *res = get_list_mem_split( prg, (list_t*)obj, field ); + colm_tree_upref( prg, res ); + vm_push_tree( res ); + break; + } + + case IN_STASH_ARG: { + half_t pos; + half_t size; + read_half( pos ); + read_half( size ); + + debug( prg, REALM_BYTECODE, "IN_STASH_ARG %hd %hd\n", pos, size ); + + while ( size > 0 ) { + value_t v = vm_pop_value(); + ((value_t*)exec->call_args)[pos] = v; + size -= 1; + pos += 1; + } + + break; + } + + case IN_PREP_ARGS: { + half_t size; + read_half( size ); + + debug( prg, REALM_BYTECODE, "IN_PREP_ARGS %hd\n", size ); + + vm_push_type( tree_t**, exec->call_args ); + vm_pushn( size ); + exec->call_args = vm_ptop(); + memset( vm_ptop(), 0, sizeof(word_t) * size ); + break; + } + + case IN_CLEAR_ARGS: { + half_t size; + read_half( size ); + + debug( prg, REALM_BYTECODE, "IN_CLEAR_ARGS %hd\n", size ); + + vm_popn( size ); + exec->call_args = vm_pop_type( tree_t** ); + break; + } + + case IN_HOST: { + half_t func_id; + read_half( func_id ); + + debug( prg, REALM_BYTECODE, "IN_HOST %hd\n", func_id ); + + sp = prg->rtd->host_call( prg, func_id, sp ); + break; + } + case IN_CALL_WV: { + half_t func_id; + read_half( func_id ); + + struct function_info *fi = &prg->rtd->function_info[func_id]; + struct frame_info *fr = &prg->rtd->frame_info[fi->frame_id]; + + debug( prg, REALM_BYTECODE, "IN_CALL_WV %s\n", fr->name ); + + vm_contiguous( FR_AA + fi->frame_size ); + + vm_push_type( tree_t**, exec->call_args ); + vm_push_value( 0 ); /* Return value. */ + vm_push_type( code_t*, instr ); + vm_push_type( tree_t**, exec->frame_ptr ); + vm_push_type( long, exec->frame_id ); + + instr = fr->codeWV; + exec->frame_id = fi->frame_id; + + exec->frame_ptr = vm_ptop(); + vm_pushn( fr->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fr->frame_size ); + break; + } + case IN_CALL_WC: { + half_t func_id; + read_half( func_id ); + + struct function_info *fi = &prg->rtd->function_info[func_id]; + struct frame_info *fr = &prg->rtd->frame_info[fi->frame_id]; + + debug( prg, REALM_BYTECODE, "IN_CALL_WC %s %d\n", fr->name, fr->frame_size ); + + vm_contiguous( FR_AA + fi->frame_size ); + + vm_push_type( tree_t**, exec->call_args ); + vm_push_value( 0 ); /* Return value. */ + vm_push_type( code_t*, instr ); + vm_push_type( tree_t**, exec->frame_ptr ); + vm_push_type( long, exec->frame_id ); + + instr = fr->codeWC; + exec->frame_id = fi->frame_id; + + exec->frame_ptr = vm_ptop(); + vm_pushn( fr->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fr->frame_size ); + break; + } + case IN_YIELD: { + debug( prg, REALM_BYTECODE, "IN_YIELD\n" ); + + kid_t *kid = vm_pop_kid(); + ref_t *next = vm_pop_ref(); + user_iter_t *uiter = (user_iter_t*) vm_plocal_iframe( IFR_AA ); + + if ( kid == 0 || kid->tree == 0 || + kid->tree->id == uiter->search_id || + uiter->search_id == prg->rtd->any_id ) + { + /* Store the yeilded value. */ + uiter->ref.kid = kid; + uiter->ref.next = next; + uiter->yield_size = vm_ssize() - uiter->root_size; + uiter->resume = instr; + uiter->frame = exec->frame_ptr; + + /* Restore the instruction and frame pointer. */ + instr = (code_t*) vm_local_iframe(IFR_RIN); + exec->frame_ptr = (tree_t**) vm_local_iframe(IFR_RFR); + exec->iframe_ptr = (tree_t**) vm_local_iframe(IFR_RIF); + + /* Return the yield result on the top of the stack. */ + tree_t *result = uiter->ref.kid != 0 ? prg->true_val : prg->false_val; + //colm_tree_upref( prg, result ); + vm_push_tree( result ); + } + break; + } + case IN_UITER_CREATE_WV: { + short field; + half_t func_id, search_id; + read_half( field ); + read_half( func_id ); + read_half( search_id ); + + debug( prg, REALM_BYTECODE, "IN_UITER_CREATE_WV\n" ); + + struct function_info *fi = prg->rtd->function_info + func_id; + + vm_contiguous( (sizeof(user_iter_t) / sizeof(word_t)) + FR_AA + fi->frame_size ); + + user_iter_t *uiter = colm_uiter_create( prg, &sp, fi, search_id ); + vm_set_local(exec, field, (SW) uiter); + + /* This is a setup similar to as a call, only the frame structure + * is slightly different for user iterators. We aren't going to do + * the call. We don't need to set up the return ip because the + * uiter advance will set it. The frame we need to do because it + * is set once for the lifetime of the iterator. */ + vm_push_type( tree_t**, exec->call_args ); + vm_push_value( 0 ); + + vm_push_type( code_t*, 0 ); /* Return instruction pointer, */ + vm_push_type( tree_t**, exec->iframe_ptr ); /* Return iframe. */ + vm_push_type( tree_t**, exec->frame_ptr ); /* Return frame. */ + + uiter->frame = vm_ptop(); + vm_pushn( fi->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fi->frame_size ); + + uiter_init( prg, sp, uiter, fi, true ); + break; + } + case IN_UITER_CREATE_WC: { + short field; + half_t func_id, search_id; + read_half( field ); + read_half( func_id ); + read_half( search_id ); + + debug( prg, REALM_BYTECODE, "IN_UITER_CREATE_WC\n" ); + + struct function_info *fi = prg->rtd->function_info + func_id; + + vm_contiguous( (sizeof(user_iter_t) / sizeof(word_t)) + FR_AA + fi->frame_size ); + + user_iter_t *uiter = colm_uiter_create( prg, &sp, fi, search_id ); + vm_set_local(exec, field, (SW) uiter); + + /* This is a setup similar to as a call, only the frame structure + * is slightly different for user iterators. We aren't going to do + * the call. We don't need to set up the return ip because the + * uiter advance will set it. The frame we need to do because it + * is set once for the lifetime of the iterator. */ + vm_push_type( tree_t**, exec->call_args ); + vm_push_value( 0 ); + + vm_push_type( code_t*, 0 ); /* Return instruction pointer, */ + vm_push_type( tree_t**, exec->iframe_ptr ); /* Return iframe. */ + vm_push_type( tree_t**, exec->frame_ptr ); /* Return frame. */ + + uiter->frame = vm_ptop(); + vm_pushn( fi->frame_size ); + memset( vm_ptop(), 0, sizeof(word_t) * fi->frame_size ); + + uiter_init( prg, sp, uiter, fi, false ); + break; + } + case IN_UITER_DESTROY: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_DESTROY %hd\n", field ); + + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + colm_uiter_destroy( prg, &sp, uiter ); + break; + } + + case IN_UITER_UNWIND: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_UITER_UNWIND %hd\n", field ); + + user_iter_t *uiter = (user_iter_t*) vm_get_local(exec, field); + colm_uiter_unwind( prg, &sp, uiter ); + break; + } + + case IN_RET: { + struct frame_info *fi = &prg->rtd->frame_info[exec->frame_id]; + downref_local_trees( prg, sp, exec, fi->locals, fi->locals_len ); + vm_popn( fi->frame_size ); + + exec->frame_id = vm_pop_type(long); + exec->frame_ptr = vm_pop_type(tree_t**); + instr = vm_pop_type(code_t*); + exec->ret_val = vm_pop_tree(); + vm_pop_value(); + //vm_popn( fi->argSize ); + + fi = &prg->rtd->frame_info[exec->frame_id]; + debug( prg, REALM_BYTECODE, "IN_RET %s\n", fi->name ); + + /* This if for direct calls of functions. */ + if ( instr == 0 ){ + //assert( sp == root ); + return sp; + } + + /* Might be some unwind code. */ + { + short unwind_len; + read_half( unwind_len ); + if ( unwind_len > 0 ) { + instr += unwind_len; + debug( prg, REALM_BYTECODE, + "skipping unwind code length: %hd\n", unwind_len ); + } + } + + break; + } + case IN_TO_UPPER: { + debug( prg, REALM_BYTECODE, "IN_TO_UPPER\n" ); + + tree_t *in = vm_pop_tree(); + head_t *head = string_to_upper( in->tokdata ); + tree_t *upper = construct_string( prg, head ); + colm_tree_upref( prg, upper ); + vm_push_tree( upper ); + colm_tree_downref( prg, sp, in ); + break; + } + case IN_TO_LOWER: { + debug( prg, REALM_BYTECODE, "IN_TO_LOWER\n" ); + + tree_t *in = vm_pop_tree(); + head_t *head = string_to_lower( in->tokdata ); + tree_t *lower = construct_string( prg, head ); + colm_tree_upref( prg, lower ); + vm_push_tree( lower ); + colm_tree_downref( prg, sp, in ); + break; + } + case IN_OPEN_FILE: { + debug( prg, REALM_BYTECODE, "IN_OPEN_FILE\n" ); + + tree_t *mode = vm_pop_tree(); + tree_t *name = vm_pop_tree(); + stream_t *res = colm_stream_open_file( prg, name, mode ); + vm_push_stream( res ); + colm_tree_downref( prg, sp, name ); + colm_tree_downref( prg, sp, mode ); + break; + } + case IN_GET_CONST: { + short constValId; + read_half( constValId ); + + switch ( constValId ) { + case CONST_STDIN: { + debug( prg, REALM_BYTECODE, "CONST_STDIN\n" ); + + /* Pop the root object. */ + vm_pop_tree(); + + make_stdin( prg ); + + vm_push_stream( prg->stdin_val ); + break; + } + case CONST_STDOUT: { + debug( prg, REALM_BYTECODE, "CONST_STDOUT\n" ); + + /* Pop the root object. */ + vm_pop_tree(); + make_stdout( prg ); + + vm_push_stream( prg->stdout_val ); + break; + } + case CONST_STDERR: { + debug( prg, REALM_BYTECODE, "CONST_STDERR\n" ); + + /* Pop the root object. */ + vm_pop_tree(); + + make_stderr( prg ); + + vm_push_stream( prg->stderr_val ); + break; + } + case CONST_ARG: { + word_t offset; + read_word( offset ); + + debug( prg, REALM_BYTECODE, "CONST_ARG %d\n", offset ); + + /* Pop the root object. */ + vm_pop_tree(); + + head_t *lit = make_literal( prg, offset ); + tree_t *tree = construct_string( prg, lit ); + colm_tree_upref( prg, tree ); + vm_push_tree( tree ); + break; + } + } + break; + } + case IN_SYSTEM: { + debug( prg, REALM_BYTECODE, "IN_SYSTEM\n" ); + + vm_pop_tree(); + str_t *cmd = vm_pop_string(); + + char *cmd0 = malloc( cmd->value->length + 1 ); + memcpy( cmd0, cmd->value->data, cmd->value->length ); + cmd0[cmd->value->length] = 0; + + int res = system( cmd0 ); + + free( cmd0 ); + +#if defined(HAVE_SYS_WAIT_H) + if ( WIFSIGNALED( res ) ) + raise( WTERMSIG( res ) ); + res = WEXITSTATUS( res ); +#else + // WARNING: Check result +#endif + + colm_tree_downref( prg, sp, (tree_t*)cmd ); + + value_t val = res; + vm_push_value( val ); + break; + } + + case IN_DONE: + return sp; + + case IN_FN: { + c = *instr++; + switch ( c ) { + case FN_STR_ATOI: { + debug( prg, REALM_BYTECODE, "FN_STR_ATOI\n" ); + + str_t *str = vm_pop_string(); + word_t res = str_atoi( str->value ); + value_t integer = res; + vm_push_value( integer ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_STR_ATOO: { + debug( prg, REALM_BYTECODE, "FN_STR_ATOO\n" ); + + str_t *str = vm_pop_string(); + word_t res = str_atoo( str->value ); + value_t integer = res; + vm_push_value( integer ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_STR_UORD8: { + debug( prg, REALM_BYTECODE, "FN_STR_UORD8\n" ); + + str_t *str = vm_pop_string(); + word_t res = str_uord8( str->value ); + value_t integer = res; + vm_push_value( integer ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_STR_UORD16: { + debug( prg, REALM_BYTECODE, "FN_STR_UORD16\n" ); + + str_t *str = vm_pop_string(); + word_t res = str_uord16( str->value ); + value_t integer = res; + vm_push_value( integer ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_STR_PREFIX: { + debug( prg, REALM_BYTECODE, "FN_STR_PREFIX\n" ); + + str_t *str = vm_pop_string(); + value_t len = vm_pop_value(); + + str_t *res = string_prefix( prg, str, (long) len ); + colm_tree_upref( prg, (tree_t*) res ); + vm_push_string( res ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_STR_SUFFIX: { + debug( prg, REALM_BYTECODE, "FN_STR_SUFFIX\n" ); + + str_t *str = vm_pop_string(); + value_t pos = vm_pop_value(); + + str_t *res = string_suffix( prg, str, (long) pos ); + colm_tree_upref( prg, (tree_t*) res ); + vm_push_string( res ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_PREFIX: { + debug( prg, REALM_BYTECODE, "FN_PREFIX\n" ); + + value_t len = vm_pop_value(); + str_t *str = vm_pop_string(); + + str_t *res = string_prefix( prg, str, (long) len ); + colm_tree_upref( prg, (tree_t*) res ); + vm_push_string( res ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_SUFFIX: { + debug( prg, REALM_BYTECODE, "FN_SUFFIX\n" ); + + value_t pos = vm_pop_value(); + str_t *str = vm_pop_string(); + + str_t *res = string_suffix( prg, str, (long) pos ); + colm_tree_upref( prg, (tree_t*) res ); + vm_push_string( res ); + colm_tree_downref( prg, sp, (tree_t*)str ); + break; + } + case FN_SPRINTF: { + debug( prg, REALM_BYTECODE, "FN_SPRINTF\n" ); + + vm_pop_tree(); + value_t integer = vm_pop_value(); + str_t *format = vm_pop_string(); + head_t *res = string_sprintf( prg, format, (long)integer ); + str_t *str = (str_t*)construct_string( prg, res ); + colm_tree_upref( prg, (tree_t*)str ); + vm_push_string( str ); + colm_tree_downref( prg, sp, (tree_t*)format ); + break; + } + case FN_LOAD_ARG0: { + half_t field; + read_half( field ); + debug( prg, REALM_BYTECODE, "FN_LOAD_ARG0 %lu\n", field ); + + /* tree_t comes back upreffed. */ + tree_t *tree = construct_arg0( prg, prg->argc, prg->argv, prg->argl ); + tree_t *prev = colm_struct_get_field( prg->global, tree_t*, field ); + colm_tree_downref( prg, sp, prev ); + colm_struct_set_field( prg->global, tree_t*, field, tree ); + break; + } + case FN_LOAD_ARGV: { + half_t field; + read_half( field ); + debug( prg, REALM_BYTECODE, "FN_LOAD_ARGV %lu\n", field ); + + list_t *list = construct_argv( prg, prg->argc, prg->argv, prg->argl ); + colm_struct_set_field( prg->global, list_t*, field, list ); + break; + } + case FN_INIT_STDS: { + half_t field; + read_half( field ); + debug( prg, REALM_BYTECODE, "FN_INIT_STDS %lu\n", field ); + + list_t *list = construct_stds( prg ); + colm_struct_set_field( prg->global, list_t*, field, list ); + break; + } + case FN_STOP: { + debug( prg, REALM_BYTECODE, "FN_STOP\n" ); + + flush_streams( prg ); + goto out; + } + + case FN_LIST_PUSH_HEAD_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_HEAD_WC\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = vm_pop_struct(); + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + colm_list_prepend( list, list_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case FN_LIST_PUSH_HEAD_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_HEAD_WV\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = vm_pop_struct(); + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + colm_list_prepend( list, list_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + + /* Set up reverse code. Needs no args. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_LIST_PUSH_HEAD_BKT ); + rcode_unit_term( exec ); + break; + } + case FN_LIST_PUSH_HEAD_BKT: { + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_HEAD_BKT\n" ); + + list_t *list = vm_pop_list(); + colm_list_detach_head( list ); + break; + } + case FN_LIST_PUSH_TAIL_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_TAIL_WC\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = vm_pop_struct(); + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + colm_list_append( list, list_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case FN_LIST_PUSH_TAIL_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_TAIL_WV\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = vm_pop_struct(); + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + colm_list_append( list, list_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + + /* Set up reverse code. Needs no args. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_LIST_PUSH_TAIL_BKT ); + rcode_unit_term( exec ); + break; + } + case FN_LIST_PUSH_TAIL_BKT: { + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_TAIL_BKT\n" ); + + list_t *list = vm_pop_list(); + colm_list_detach_tail( list ); + break; + } + case FN_LIST_POP_TAIL_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_TAIL_WC\n" ); + + list_t *list = vm_pop_list(); + + list_el_t *tail = list->tail; + colm_list_detach_tail( list ); + struct_t *s = colm_generic_el_container( prg, tail, gen_id ); + + vm_push_struct( s ); + break; + } + case FN_LIST_POP_TAIL_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_TAIL_WV\n" ); + + list_t *list = vm_pop_list(); + + list_el_t *tail = list->tail; + colm_list_detach_tail( list ); + struct_t *s = colm_generic_el_container( prg, tail, gen_id ); + + vm_push_struct( s ); + + /* Set up reverse. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_LIST_POP_TAIL_BKT ); + rcode_half( exec, gen_id ); + rcode_word( exec, (word_t)s ); + rcode_unit_term( exec ); + break; + } + case FN_LIST_POP_TAIL_BKT: { + short gen_id; + tree_t *val; + read_half( gen_id ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_TAIL_BKT\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = (struct_t*) val; + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + + colm_list_append( list, list_el ); + break; + } + case FN_LIST_POP_HEAD_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_HEAD_WC\n" ); + + list_t *list = vm_pop_list(); + + list_el_t *head = list->head; + colm_list_detach_head( list ); + struct_t *s = colm_generic_el_container( prg, head, gen_id ); + + vm_push_struct( s ); + break; + } + case FN_LIST_POP_HEAD_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_HEAD_WV\n" ); + + list_t *list = vm_pop_list(); + + list_el_t *head = list->head; + colm_list_detach_head( list ); + struct_t *s = colm_generic_el_container( prg, head, gen_id ); + + vm_push_struct( s ); + + /* Set up reverse. The result comes off the list downrefed. + * Need it up referenced for the reverse code too. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_LIST_POP_HEAD_BKT ); + rcode_half( exec, gen_id ); + rcode_word( exec, (word_t)s ); + rcode_unit_term( exec ); + break; + } + case FN_LIST_POP_HEAD_BKT: { + short gen_id; + tree_t *val; + read_half( gen_id ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_HEAD_BKT\n" ); + + list_t *list = vm_pop_list(); + struct_t *s = (struct_t*) val; + + list_el_t *list_el = colm_struct_to_list_el( prg, s, gen_id ); + + colm_list_prepend( list, list_el ); + break; + } + case FN_MAP_FIND: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_MAP_FIND %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + tree_t *key = vm_pop_tree(); + + map_el_t *map_el = colm_map_find( prg, map, key ); + + struct colm_struct *strct = map_el != 0 ? + colm_generic_el_container( prg, map_el, gen_id ) : 0; + + vm_push_struct( strct ); + + if ( map->generic_info->key_type == TYPE_TREE ) + colm_tree_downref( prg, sp, key ); + break; + } + case FN_MAP_INSERT_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_MAP_INSERT_WC %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + struct_t *s = vm_pop_struct(); + + map_el_t *map_el = colm_struct_to_map_el( prg, s, gen_id ); + + colm_map_insert( prg, map, map_el ); + + vm_push_tree( prg->true_val ); + break; + } + case FN_MAP_INSERT_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_MAP_INSERT_WV %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + struct_t *s = vm_pop_struct(); + + map_el_t *map_el = colm_struct_to_map_el( prg, s, gen_id ); + + map_el_t *inserted = colm_map_insert( prg, map, map_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_MAP_INSERT_BKT ); + rcode_half( exec, gen_id ); + rcode_code( exec, inserted != 0 ? 1 : 0 ); + rcode_word( exec, (word_t)map_el ); + rcode_unit_term( exec ); + break; + } + + case FN_MAP_INSERT_BKT: { + short gen_id; + uchar inserted; + word_t wmap_el; + + read_half( gen_id ); + read_byte( inserted ); + read_word( wmap_el ); + + map_el_t *map_el = (map_el_t*)wmap_el; + + debug( prg, REALM_BYTECODE, "FN_MAP_INSERT_BKT %d\n", + (int)inserted ); + + map_t *map = vm_pop_map(); + + if ( inserted ) + colm_map_detach( prg, map, map_el ); + break; + } + case FN_MAP_DETACH_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_MAP_DETACH_WC %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + struct_t *s = vm_pop_struct(); + + map_el_t *map_el = colm_struct_to_map_el( prg, s, gen_id ); + + colm_map_detach( prg, map, map_el ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case FN_MAP_DETACH_WV: { + debug( prg, REALM_BYTECODE, "FN_MAP_DETACH_WV\n" ); + + tree_t *obj = vm_pop_tree(); + tree_t *key = vm_pop_tree(); + struct tree_pair pair = map_remove( prg, (map_t*)obj, key ); + + colm_tree_upref( prg, pair.val ); + vm_push_tree( pair.val ); + + /* Reverse instruction. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_MAP_DETACH_BKT ); + rcode_word( exec, (word_t)pair.key ); + rcode_word( exec, (word_t)pair.val ); + rcode_unit_term( exec ); + + colm_tree_downref( prg, sp, obj ); + colm_tree_downref( prg, sp, key ); + break; + } + case FN_MAP_DETACH_BKT: { + tree_t *key, *val; + read_tree( key ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_MAP_DETACH_BKT\n" ); + + /* Either both or neither. */ + assert( ( key == 0 ) ^ ( val != 0 ) ); + + tree_t *obj = vm_pop_tree(); + #if 0 + if ( key != 0 ) + map_unremove( prg, (map_t*)obj, key, val ); + #endif + + colm_tree_downref( prg, sp, obj ); + break; + } + case FN_VMAP_INSERT_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VMAP_INSERT_WC %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + struct_t *value = vm_pop_struct(); + struct_t *key = vm_pop_struct(); + + colm_vmap_insert( prg, map, key, value ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case FN_VMAP_INSERT_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VMAP_INSERT_WV %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + struct_t *value = vm_pop_struct(); + struct_t *key = vm_pop_struct(); + + map_el_t *inserted = colm_vmap_insert( prg, map, key, value ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_VMAP_INSERT_BKT ); + rcode_half( exec, gen_id ); + rcode_code( exec, inserted != 0 ? 1 : 0 ); + rcode_word( exec, (word_t)inserted ); + rcode_unit_term( exec ); + break; + } + case FN_VMAP_INSERT_BKT: { + short gen_id; + uchar inserted; + word_t wmap_el; + + read_half( gen_id ); + read_byte( inserted ); + read_word( wmap_el ); + + map_el_t *map_el = (map_el_t*)wmap_el; + + debug( prg, REALM_BYTECODE, "FN_VMAP_INSERT_BKT %d\n", + (int)inserted ); + + map_t *map = vm_pop_map(); + + if ( inserted ) + colm_map_detach( prg, map, map_el ); + break; + } + case FN_VMAP_REMOVE_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VMAP_REMOVE_WC %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + tree_t *key = vm_pop_tree(); + + colm_vmap_remove( prg, map, key ); + + //colm_tree_upref( prg, prg->trueVal ); + vm_push_tree( prg->true_val ); + break; + } + case FN_VMAP_FIND: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VMAP_FIND %hd\n", gen_id ); + + map_t *map = vm_pop_map(); + tree_t *key = vm_pop_tree(); + + tree_t *result = colm_vmap_find( prg, map, key ); + + vm_push_tree( result ); + + if ( map->generic_info->key_type == TYPE_TREE ) + colm_tree_downref( prg, sp, key ); + break; + } + case FN_VLIST_PUSH_TAIL_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_TAIL_WC %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + value_t value = vm_pop_value(); + + colm_vlist_append( prg, list, value ); + + vm_push_tree( prg->true_val ); + break; + } + case FN_VLIST_PUSH_TAIL_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_TAIL_WV %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + value_t value = vm_pop_value(); + + colm_vlist_append( prg, list, value ); + + vm_push_tree( prg->true_val ); + + /* Set up reverse code. Needs no args. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_VLIST_PUSH_TAIL_BKT ); + rcode_unit_term( exec ); + break; + } + case FN_VLIST_PUSH_TAIL_BKT: { + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_TAIL_BKT\n" ); + + list_t *list = vm_pop_list(); + colm_list_detach_tail( list ); + break; + } + case FN_VLIST_PUSH_HEAD_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_HEAD_WC %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + value_t value = vm_pop_value(); + + colm_vlist_prepend( prg, list, value ); + + vm_push_tree( prg->true_val ); + break; + } + case FN_VLIST_PUSH_HEAD_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_HEAD_WV %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + value_t value = vm_pop_value(); + + colm_vlist_prepend( prg, list, value ); + + vm_push_tree( prg->true_val ); + + /* Set up reverse code. Needs no args. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_VLIST_PUSH_HEAD_BKT ); + rcode_unit_term( exec ); + break; + } + case FN_VLIST_PUSH_HEAD_BKT: { + debug( prg, REALM_BYTECODE, "FN_VLIST_PUSH_HEAD_BKT\n" ); + + list_t *list = vm_pop_list(); + colm_list_detach_head( list ); + break; + } + case FN_VLIST_POP_HEAD_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_HEAD_WC %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + + value_t result = colm_vlist_detach_head( prg, list ); + vm_push_value( result ); + break; + } + case FN_VLIST_POP_HEAD_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_HEAD_WV %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + + value_t result = colm_vlist_detach_head( prg, list ); + vm_push_value( result ); + + /* Set up reverse. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_VLIST_POP_HEAD_BKT ); + rcode_half( exec, gen_id ); + rcode_word( exec, (word_t)result ); + rcode_unit_term( exec ); + break; + } + case FN_VLIST_POP_HEAD_BKT: { + short gen_id; + tree_t *val; + read_half( gen_id ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_HEAD_BKT\n" ); + + list_t *list = vm_pop_list(); + + colm_vlist_prepend( prg, list, (value_t)val ); + break; + } + case FN_VLIST_POP_TAIL_WC: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_TAIL_WC %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + + value_t result = colm_vlist_detach_tail( prg, list ); + vm_push_value( result ); + break; + } + case FN_VLIST_POP_TAIL_WV: { + short gen_id; + read_half( gen_id ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_TAIL_WV %hd\n", gen_id ); + + list_t *list = vm_pop_list(); + + value_t result = colm_vlist_detach_tail( prg, list ); + vm_push_value( result ); + + /* Set up reverse. */ + rcode_code( exec, IN_FN ); + rcode_code( exec, FN_VLIST_POP_TAIL_BKT ); + rcode_half( exec, gen_id ); + rcode_word( exec, (word_t)result ); + rcode_unit_term( exec ); + break; + } + case FN_VLIST_POP_TAIL_BKT: { + short gen_id; + tree_t *val; + read_half( gen_id ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_VLIST_POP_TAIL_BKT\n" ); + + list_t *list = vm_pop_list(); + + colm_vlist_append( prg, list, (value_t)val ); + break; + } + + case FN_EXIT_HARD: { + debug( prg, REALM_BYTECODE, "FN_EXIT\n" ); + + vm_pop_tree(); + prg->exit_status = vm_pop_type(long); + prg->induce_exit = 1; + exit( prg->exit_status ); + } + case FN_EXIT: { + /* The unwind code follows the exit call (exception, see + * synthesis). */ + short unwind_len; + read_half( unwind_len ); + + debug( prg, REALM_BYTECODE, "FN_EXIT, unwind len: %hd\n", unwind_len ); + + vm_pop_tree(); + prg->exit_status = vm_pop_type(long); + prg->induce_exit = 1; + + while ( true ) { + /* We stop on the root, leaving the psuedo-call setup on the + * stack. Note we exclude the local data. */ + if ( exec->frame_id == prg->rtd->root_frame_id ) + break; + + struct frame_info *fi = &prg->rtd->frame_info[exec->frame_id]; + + debug( prg, REALM_BYTECODE, "FN_EXIT, popping frame %s, " + "unwind-len %hd, arg-size %ld\n", + ( fi->name != 0 ? fi->name : "<no-name>" ), + unwind_len, fi->arg_size ); + + if ( unwind_len > 0 ) + sp = colm_execute_code( prg, exec, sp, instr ); + + downref_locals( prg, &sp, exec, fi->locals, fi->locals_len ); + vm_popn( fi->frame_size ); + + /* Call layout. */ + exec->frame_id = vm_pop_type(long); + exec->frame_ptr = vm_pop_type(tree_t**); + instr = vm_pop_type(code_t*); + + tree_t *ret_val = vm_pop_tree(); + vm_pop_value(); + + /* The IN_PREP_ARGS stack data. */ + vm_popn( fi->arg_size ); + vm_pop_value(); + + if ( fi->ret_tree ) { + /* Problem here. */ + colm_tree_downref( prg, sp, ret_val ); + } + + read_half( unwind_len ); + } + + goto out; + } + default: { + fatal( "UNKNOWN FUNCTION: 0x%02x -- something is wrong\n", c ); + break; + }} + break; + } + + /* Halt is a default instruction given by the compiler when it is + * asked to generate and instruction it doesn't have. It is deliberate + * and can represent "not implemented" or "compiler error" because a + * variable holding instructions was not properly initialize. */ + case IN_HALT: { + fatal( "IN_HALT -- compiler did something wrong\n" ); + exit(1); + break; + } + default: { + fatal( "UNKNOWN INSTRUCTION: 0x%02x -- something is wrong\n", *(instr-1) ); + assert(false); + break; + } + } + goto again; + +out: + if ( ! prg->induce_exit ) + assert( sp == root ); + return sp; +} + +/* + * Deleteing rcode required downreffing any trees held by it. + */ +static void rcode_downref( program_t *prg, tree_t **sp, code_t *instr ) +{ +again: + switch ( *instr++ ) { + case IN_PARSE_INIT_BKT: { + debug( prg, REALM_BYTECODE, "IN_PARSE_INIT_BKT\n" ); + + consume_word(); //( parser ); + consume_word(); //( steps ); + + break; + } + case IN_SEND_EOF_BKT: { + debug( prg, REALM_BYTECODE, "IN_SEND_EOF_BKT\n" ); + consume_word(); //( parser ); + break; + } + + case IN_LOAD_TREE: { + tree_t *w; + read_tree( w ); + debug( prg, REALM_BYTECODE, "IN_LOAD_TREE %p\n", w ); + colm_tree_downref( prg, sp, w ); + break; + } + case IN_LOAD_WORD: { + consume_word(); + debug( prg, REALM_BYTECODE, "IN_LOAD_WORD\n" ); + break; + } + case IN_RESTORE_LHS: { + tree_t *restore; + read_tree( restore ); + debug( prg, REALM_BYTECODE, "IN_RESTORE_LHS\n" ); + colm_tree_downref( prg, sp, restore ); + break; + } + + case IN_PARSE_FRAG_BKT: { + debug( prg, REALM_BYTECODE, "IN_PARSE_FRAG_BKT\n" ); + break; + } + case IN_PCR_RET: { + debug( prg, REALM_BYTECODE, "IN_PCR_RET\n" ); + return; + } + case IN_PCR_END_DECK: { + debug( prg, REALM_BYTECODE, "IN_PCR_END_DECK\n" ); + return; + } + case IN_SEND_TEXT_BKT: { + tree_t *input; + + consume_word(); //( parser ); + read_tree( input ); + consume_word(); //( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TEXT_BKT\n" ); + + colm_tree_downref( prg, sp, input ); + break; + } + case IN_SEND_TREE_BKT: { + tree_t *input; + + consume_word(); //( parser ); + read_tree( input ); + consume_word(); //( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_TREE_BKT\n" ); + + colm_tree_downref( prg, sp, input ); + break; + } + case IN_SEND_STREAM_BKT: { + consume_word(); //( sptr ); + consume_word(); //( input ); + consume_word(); //( len ); + + debug( prg, REALM_BYTECODE, "IN_SEND_STREAM_BKT\n" ); + break; + } + + case IN_INPUT_PULL_BKT: { + tree_t *string; + read_tree( string ); + + debug( prg, REALM_BYTECODE, "IN_INPUT_PULL_BKT\n" ); + + colm_tree_downref( prg, sp, string ); + break; + } + case IN_INPUT_PUSH_BKT: { + consume_word(); //( len ); + + debug( prg, REALM_BYTECODE, "IN_INPUT_PUSH_BKT\n" ); + break; + } + case IN_LOAD_GLOBAL_BKT: { + debug( prg, REALM_BYTECODE, "IN_LOAD_GLOBAL_BKT\n" ); + break; + } + case IN_LOAD_CONTEXT_BKT: { + debug( prg, REALM_BYTECODE, "IN_LOAD_CONTEXT_BKT\n" ); + break; + } + case IN_LOAD_INPUT_BKT: { + consume_word(); //( input ); + debug( prg, REALM_BYTECODE, "IN_LOAD_INPUT_BKT\n" ); + break; + } + case IN_GET_FIELD_TREE_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_FIELD_TREE_BKT %hd\n", field ); + break; + } + case IN_SET_FIELD_TREE_BKT: { + short field; + tree_t *val; + read_half( field ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_FIELD_TREE_BKT %hd\n", field ); + + colm_tree_downref( prg, sp, val ); + break; + } + case IN_SET_STRUCT_BKT: { + short field; + tree_t *val; + read_half( field ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_BKT %hd\n", field ); + + colm_tree_downref( prg, sp, val ); + break; + } + case IN_SET_STRUCT_VAL_BKT: { + consume_half(); //( field ); + consume_word(); //( val ); + + debug( prg, REALM_BYTECODE, "IN_SET_STRUCT_VAL_BKT\n" ); + break; + } + case IN_PTR_ACCESS_BKT: { + consume_word(); //( ptr ); + + debug( prg, REALM_BYTECODE, "IN_PTR_ACCESS_BKT\n" ); + break; + } + case IN_SET_TOKEN_DATA_BKT: { + word_t oldval; + read_word( oldval ); + + debug( prg, REALM_BYTECODE, "IN_SET_TOKEN_DATA_BKT\n" ); + + head_t *head = (head_t*)oldval; + string_free( prg, head ); + break; + } + case IN_GET_LIST_MEM_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_LIST_MEM_BKT %hd\n", field ); + break; + } + case IN_GET_MAP_MEM_BKT: { + short field; + read_half( field ); + + debug( prg, REALM_BYTECODE, "IN_GET_MAP_MEM_BKT %hd\n", field ); + break; + } + case IN_FN: { + switch ( *instr++ ) { + case FN_LIST_PUSH_HEAD_BKT: { + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_HEAD_BKT\n" ); + break; + } + case FN_LIST_POP_HEAD_BKT: { + consume_half(); //( genId ); + consume_word(); //( val ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_HEAD_BKT\n" ); + + break; + } + case FN_LIST_PUSH_TAIL_BKT: { + debug( prg, REALM_BYTECODE, "FN_LIST_PUSH_TAIL_BKT\n" ); + break; + } + case FN_LIST_POP_TAIL_BKT: { + consume_half(); //( genId ); + consume_word(); //( val ); + + debug( prg, REALM_BYTECODE, "FN_LIST_POP_TAIL_BKT\n" ); + + break; + } + case FN_MAP_INSERT_BKT: { + #ifdef DEBUG + uchar inserted; + consume_half(); //( genId ); + read_byte( inserted ); + consume_word(); //( wmapEl ); + #else + consume_half(); //( genId ); + consume_byte(); // inserted + consume_word(); //( wmapEl ); + #endif + + debug( prg, REALM_BYTECODE, "FN_MAP_INSERT_BKT %d\n", + (int)inserted ); + break; + } + case FN_VMAP_INSERT_BKT: { + short gen_id; + + #ifdef DEBUG + uchar inserted; + read_half( gen_id ); + read_byte( inserted ); + consume_word(); //read_word( wmap_el ); + #else + read_half( gen_id ); + consume_byte(); + consume_word(); //read_word( wmap_el ); + #endif + + //map_el_t *map_el = (map_el_t*)wmap_el; + + debug( prg, REALM_BYTECODE, "FN_VMAP_INSERT_BKT %d\n", + (int)inserted ); + + break; + } + case FN_MAP_DETACH_BKT: { + tree_t *key, *val; + read_tree( key ); + read_tree( val ); + + debug( prg, REALM_BYTECODE, "FN_MAP_DETACH_BKT\n" ); + + colm_tree_downref( prg, sp, key ); + colm_tree_downref( prg, sp, val ); + break; + } + + case FN_VLIST_PUSH_TAIL_BKT: { + break; + } + + case FN_VLIST_PUSH_HEAD_BKT: { + break; + } + + case FN_VLIST_POP_HEAD_BKT: { + short gen_id; + //word_t result; + read_half( gen_id ); + consume_word(); //read_word( result ); + break; + } + + case FN_VLIST_POP_TAIL_BKT: { + short gen_id; + //word_t result; + read_half( gen_id ); + consume_word(); //read_word( result ); + break; + } + + default: { + fatal( "UNKNOWN FUNCTION 0x%02x: -- reverse code downref\n", *(instr-1)); + assert(false); + }} + break; + } + default: { + fatal( "UNKNOWN INSTRUCTION 0x%02x: -- reverse code downref\n", *(instr-1)); + assert(false); + break; + } + } + goto again; +} + + |