# New Ticket Created by chromatic # Please include the string: [perl #43485] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=43485 >
I don't have a good test case for this, but I've triggered the problem with some code that makes TGE sick.4 Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1212335920 (LWP 8882)] 0xb7dd7e4b in key_hash_STRING (interp=0x804e008, value=0x0, seed=3793) at src/hash.c:110 110 if (s->hashval) { (gdb) bt #0 0xb7dd7e4b in key_hash_STRING (interp=0x804e008, value=0x0, seed=3793) at src/hash.c:110 #1 0xb7dd8c3e in parrot_hash_get_bucket (interp=0x804e008, hash=0x82ff5b8, key=0x0) at src/hash.c:796 #2 0xb7eb87d3 in Parrot_Hash_exists_keyed (interp=0x804e008, pmc=0x828b534, key=0x0) at ./src/pmc/hash.pmc:900 #3 0xb7ce471b in Parrot_exists_i_p_kc (cur_opcode=0xb7be1230, interp=0x804e008) at src/ops/pmc.ops:327 #4 0xb7dd2fbd in runops_slow_core (interp=0x804e008, pc=0xb7be1230) at src/runops_cores.c:184 #5 0xb7dbd580 in runops_int (interp=0x804e008, offset=58) at src/interpreter.c:769 Here's a patch; I'm not positive it's the right solution, but if you can somehow pass in a Key that doesn't do the right thing, you can trigger the problem. I hope this isn't too vague for someone to look over my shoulder. -- c
=== languages/pheme/TODO ================================================================== --- languages/pheme/TODO (revision 4466) +++ languages/pheme/TODO (local) @@ -1,3 +1,8 @@ +Move __list_to_cons to __evaluate +Reactivate special form rewriting (handle_specials should still work) +- or maybe rewrite to special form at the atom level? + - may not work very well as they affect subsequent atoms... + http://schemers.org/Documents/Standards/R5RS/HTML/ Atom: === languages/pheme/lib/PhemeSymbols.pir ================================================================== --- languages/pheme/lib/PhemeSymbols.pir (revision 4466) +++ languages/pheme/lib/PhemeSymbols.pir (local) @@ -1,19 +1,20 @@ .namespace [ 'PhemeCompiler' ] -.sub __onload :load +.sub __onload :load :init .local pmc symbols symbols = new .Hash - symbols['car'] = 1 - symbols['cdr'] = 1 - symbols['cons'] = 1 - symbols['cond'] = 1 - symbols['include_file'] = 1 - symbols['write'] = 1 - symbols['+'] = 1 - symbols['-'] = 1 - symbols['*'] = 1 - symbols['/'] = 1 + symbols["'define'"] = 1 + symbols["'car'"] = 1 + symbols["'cdr'"] = 1 + symbols["'cons'"] = 1 + symbols["'cond'"] = 1 + symbols["'include_file'"] = 1 + symbols["'write'"] = 1 + symbols["'+'"] = 1 + symbols["'-'"] = 1 + symbols["'*'"] = 1 + symbols["'/'"] = 1 store_global 'PhemeCompiler', 'symbols', symbols .return() === languages/pheme/lib/past2post.tg ================================================================== --- languages/pheme/lib/past2post.tg (revision 4466) +++ languages/pheme/lib/past2post.tg (local) @@ -1,6 +1,6 @@ -grammar OSTGrammar is TGE::Grammar; +grammar Pheme::OST::Grammar is TGE::Grammar; -transform result (ROOT) :language('PIR') { +transform post (ROOT) :language('PIR') { .local pmc result result = new 'POST::Node' @@ -44,7 +44,7 @@ .return( symbols ) } -transform result (PAST::Sub) :language('PIR') { +transform post (PAST::Sub) :language('PIR') { .local pmc result result = new 'POST::Sub' @@ -240,7 +240,7 @@ .return( name ) } -transform result (PAST::Stmts) :language('PIR') { +transform post (PAST::Stmts) :language('PIR') { .local pmc result result = new 'POST::Ops' @@ -279,7 +279,7 @@ .return( resulty ) } -transform result (PAST::Exp) :language('PIR') { +transform post (PAST::Exp) :language('PIR') { .local pmc result result = new .ResizablePMCArray @@ -345,7 +345,7 @@ .return( result ) } -transform result (PAST::Op) :language('PIR') { +transform post (PAST::Op) :language('PIR') { .local pmc result .local pmc symbols @@ -373,7 +373,7 @@ .return( result ) } -transform result (PAST::Val) :language('PIR') { +transform post (PAST::Val) :language('PIR') { .local pmc result .local string value === languages/pheme/lib/pge2past.tg ================================================================== --- languages/pheme/lib/pge2past.tg (revision 4466) +++ languages/pheme/lib/pge2past.tg (local) @@ -1,393 +1,526 @@ -grammar ASTGrammar is TGE::Grammar; +grammar Pheme::AST::Grammar is TGE::Grammar; -transform result (ROOT) :language('PIR') { - # XXX: transform into a method on the TGE object, when it's possible - .local pmc specials - specials = new .Hash - specials['define'] = 1 - specials['quote'] = 1 - specials['cond'] = 1 +transform past (ROOT) :language('PIR') { + .local pmc result + result = new 'PAST::Block' + result.'namespace'( 'Pheme' ) - store_global 'specials', specials + .local pmc load_op, lib_name + load_op = new 'PAST::Op' + load_op.'init'( 'pasttype' => 'inline', 'inline' => " load_bytecode 'lib/PhemeObjects.pir' #%r" ) - .local pmc result - result = new 'Node' + result.'push'( load_op ) - .local pmc match - match = node['list'] + load_op = new 'PAST::Op' + load_op.'init'( 'pasttype' => 'inline', 'inline' => " load_bytecode 'lib/PhemeSymbols.pir' #%r" ) - .local pmc iter - iter = new Iterator, match # setup iterator for node - set iter, 0 # reset iterator, begin at start + result.'push'( load_op ) - .local pmc elem - .local pmc ast_elem + .local pmc lists + lists = node['list'] - .local pmc main_sub - main_sub = new 'PAST::Sub' - main_sub.'name'( 'main' ) + .local pmc iter + iter = new Iterator, lists - .local pmc main_statements - main_statements = new 'PAST::Stmts' + .local pmc elem - main_sub.'add_child'( main_statements ) + iter_loop: + unless iter goto iter_end + elem = shift iter + elem = tree.'get'( 'past', elem, 'list' ) - .local string elem_type + result.'push'( elem ) + goto iter_loop - iter_loop: - unless iter, iter_end # while (entries) ... - shift elem, iter # get key for next entry - ast_elem = tree.get('result', elem, 'list') + iter_end: + .return( result ) +} - elem_type = typeof ast_elem - if elem_type == 'PAST::Sub' goto save_elem - main_statements.'add_child'( ast_elem ) - goto iter_loop +transform past (list) :language('PIR') { + .local pmc iter + iter = new Iterator, node - save_elem: - result.'add_child'( ast_elem ) - goto iter_loop + .local string key_name + key_name = shift iter - iter_end: - result.'add_child'( main_sub ) + .local pmc elem + elem = node[key_name] - .return( result ) + .local pmc result + result = tree.'get'( 'past', elem, key_name ) + + .return( result ) } -transform result (list) :language('PIR') { - .local pmc result - result = new 'PAST::Exp' +transform past (list_item) :language('PIR') { + .local pmc iter + iter = new Iterator, node - .local pmc match - match = node['list_item'] + .local string key_name + key_name = shift iter - .local pmc iter - iter = new Iterator, match # setup iterator for node - set iter, 0 # reset iterator, begin at start + .local pmc elem + elem = node[key_name] - .local pmc children - children = result.'children'() + .local pmc result + result = tree.'get'( 'past', elem, key_name ) - .local pmc child - child = shift iter - child = tree.get( 'result', child, 'list_item' ) + .return( result ) +} - .local pmc op - op = tree.get( 'maybe_op', child ) - result.'add_child'( op ) +transform past (special_form) :language('PIR') { + .local pmc special + special = node['special'] - iter_loop: - unless iter, iter_end # while (entries) ... - shift child, iter # get key for next entry - child = tree.get( 'result', child, 'list_item' ) - result.'add_child'( child ) - goto iter_loop + .local pmc iter + iter = new Iterator, special - iter_end: - .local string child_type - child_type = typeof op - unless child_type == 'PAST::Op' goto return_result + .local string key_name + key_name = shift iter - result = tree.get( 'handle_specials', result ) + .local pmc result + result = tree.'get'( 'special_form', node, key_name ) - return_result: - .return( result ) + .return( result ) } -# XXX - don't know why I need this, but it prevents ambiguity errors -transform maybe_op (PAST::Exp) :language('PIR') { - .return( node ) -} +transform past (application) :language('PIR') { + .local pmc op + op = new 'PAST::Op' -transform maybe_op (PAST::Val) :language('PIR') { - .local string value - .local string valtype + .local pmc atom + atom = node['atom'] + atom = tree.'get'( 'past', atom, 'atom' ) - value = node.'value'() - valtype = node.'valtype'() + .local string atom_name + atom_name = atom.'name'() - unless valtype goto treat_as_op + .local int name_length + name_length = length atom_name - .local pmc val - val = new 'PAST::Val' - val.'value'( value ) - val.'valtype'( valtype ) + # strip off the quotes from the atom name + name_length -= 2 + atom_name = substr atom_name, 1, name_length - .return( val ) + .local pmc atom_func + atom_func = find_global 'Pheme', atom_name - treat_as_op: - .local pmc op - op = new 'PAST::Op' - op.'op'( value ) + .local int have_func + have_func = defined atom_func - .return( op ) + .local string rule_name + rule_name = 'evaluate_cons' + + unless have_func goto get_result + rule_name = 'call_func' + + get_result: + .local pmc result + result = tree.'get'( 'apply', node, rule_name ) + .return( result ) } -transform handle_specials (PAST::Exp) :language('PIR') { - .local pmc children - children = node.'children'() +transform apply (call_func) :language('PIR') { + .local pmc atom + atom = node['atom'] + atom = tree.'get'( 'past', atom, 'atom' ) - .local pmc op - op = children[0] + .local pmc op + op = new 'PAST::Op' - .local string name - name = op.'op'() + .local string name + name = atom.'name'() + op.'name'( name ) - .local pmc specials - specials = find_global 'specials' + .local pmc list + list = node['list_item'] - .local int special_exists - special_exists = exists specials[name] + .local pmc iter + iter = new Iterator, list - unless special_exists goto not_a_special + .local pmc item - node = tree.'get'( name, node ) + iter_loop: + unless iter goto iter_end + item = shift iter + item = tree.'get'( 'past', item, 'list_item' ) + op.'push'( item ) + goto iter_loop - not_a_special: - .return( node ) + iter_end: + .return( op ) } -transform define (PAST::Exp) :language('PIR') { - .local pmc children - children = node.'children'() +transform apply (evaluate_cons) :language('PIR') { + .local pmc atom + atom = node['atom'] + atom = tree.'get'( 'past', atom, 'atom' ) - .local pmc op - op = children[0] + .local pmc op + op = new 'PAST::Op' + op.'name'( '__list_to_cons' ) + op.'push'( atom ) - return_sub: - .local pmc sub_name - sub_name = children[1] + .local pmc list + list = node['list_item'] - .local pmc exp - exp = children[2] + .local pmc iter + iter = new Iterator, list - .local pmc sub_name_string - sub_name_string = sub_name.'value'() + .local pmc item - .local pmc result - result = new 'PAST::Sub' - result.'name'( sub_name_string ) + iter_loop: + unless iter goto iter_end + item = shift iter + item = tree.'get'( 'past', item, 'list_item' ) + op.'push'( item ) + goto iter_loop - .local pmc stmts - stmts = new 'PAST::Stmts' - stmts.'add_child'( exp ) + iter_end: + .local pmc result + result = new 'PAST::Op' + result.'name'( '__evaluate' ) + result.'push'( op ) - result.'add_child'( stmts ) - .return( result ) + .return( result ) } -transform quote (PAST::Exp) :language( 'PIR' ) { - .local pmc children - children = node.'children'() +transform past (cons) :language('PIR') { + .local pmc list_item + list_item = node['list_item'] - # remove this Exp and promote the first sibling - .local pmc sibling - sibling = children[1] - children = sibling.'children'() + .local pmc op + op = new 'PAST::Op' + op.'name'( '__list_to_cons' ) - .local pmc first_child - first_child = children[0] + .local pmc iter + iter = new Iterator, list_item - .local string child_type - child_type = typeof first_child + .local pmc item - unless child_type == 'PAST::Op' goto rewrite_op + iter_loop: + unless iter goto iter_end + item = shift iter + item = tree.'get'( 'past', item, 'list_item' ) + op.'push'( item ) + goto iter_loop - .local string op_name - op_name = first_child.'op'() + iter_end: + .return( op ) +} - # if it's an empty list, let it be an empty list - unless op_name == '__make_empty_cons' goto rewrite_op - .return( sibling ) - rewrite_op: - .local pmc val_child - val_child = new 'PAST::Val' +# XXX - bad below here +transform maybe_op (list) :language('PIR') { + .local pmc list_item + list_item = node['list_item'] - # XXX: this might fail unless the first kid is an op - .local string value - value = first_child.'op'() - val_child.'value'( value ) + .local pmc atom + atom = list_item['atom'] - children[0] = val_child - - .local pmc cons_op - cons_op = new 'PAST::Op' - cons_op.'op'( '__list_to_cons' ) + .local pmc symbols + symbols = find_global 'PhemeCompiler', 'symbols' - unshift children, cons_op + .local string name + name = atom.'name'() - .return( sibling ) -} + .local int is_symbol + is_symbol = exists symbols[name] -transform cond (PAST::Exp) :language( 'PIR' ) { - .local pmc result - result = new 'PAST::Exp' + .local pmc result - # cond takes a list of pairs - # ( condition to evaluate ) result - # rewrite so that there are no ops, only vals + if is_symbol goto handle_symbol + result = tree.'get'( 'make_cons', node ) + .return( result ) - .local pmc iter - iter = node.'child_iter'() + handle_symbol: + result = new 'PAST::Op' + result.'name'( name ) - .local pmc child - .local pmc new_child + .local pmc iter + iter = node.'iterator'() - # first node is the 'cond' node - child = shift iter - result.'add_child'( child ) - $S0 = child.'op'() + # throw away the first kid + .local pmc child + child = shift iter iter_loop: - unless iter goto iter_end - child = shift iter - new_child = tree.'get'( 'node_to_val', child ) - result.'add_child'( new_child ) - goto iter_loop + unless iter goto iter_end + child = shift iter + child = tree.'get'( 'past', child ) + result.'push'( child ) + goto iter_loop + iter_end: - - .return( result ) + .return( result ) } -transform node_to_val (PAST::Exp) :language('PIR') { - .local pmc result - result = new 'PAST::Exp' +transform make_cons (list) :language('PIR') { + .local pmc iter + iter = new .Iterator, node - .local pmc iter - iter = node.'child_iter'() + .local pmc cons + cons = new 'PAST::Op' + cons.'name'( '__list_to_cons' ) - .local pmc child - .local pmc new_child + .local pmc child iter_loop: - unless iter goto iter_end - child = shift iter - new_child = tree.'get'( 'node_to_val', child ) - result.'add_child'( new_child ) - goto iter_loop + unless iter, iter_end + child = shift iter + child = tree.get( 'past', child, 'list_item' ) + cons.'push'( child ) + goto iter_loop + iter_end: + .local pmc eval + eval = new 'PAST::Op' + eval.'name'( '__evaluate' ) + eval.'push'( cons ) - .return( result ) + .return( eval ) } -transform node_to_val (PAST::Op) :language('PIR') { - .local pmc result - .local string value +transform rewrite_cons (PAST::Op) :language('PIR') { + .local pmc result - result = new 'PAST::Val' - value = node.'op'() + .local pmc child + child = node[0] - result.'value'( value ) - result.'valtype'( 'literal' ) + .local string kid_type + kid_type = typeof child - .return( result ) + .local string value + value = child.'name'() + + .local pmc symbols + symbols = find_global 'Pheme', 'symbols' + + .local int symbol_exists + symbol_exists = exists symbols[value] + + if symbol_exists goto treat_as_op + + result = new 'PAST::Op' + result.'name'( '__evaluate' ) + result.'push'( node ) + .return( result ) + + treat_as_op: + .local pmc op + op = new 'PAST::Op' + op.'name'( value ) + + .local pmc iter + iter = node.'iterator'() + + .local pmc sibling + unless iter goto iter_end + sibling = shift iter + + iter_loop: + unless iter goto iter_end + sibling = shift iter + op.'push'( sibling ) + goto iter_loop + + iter_end: + .return( op ) } -transform node_to_val (PAST::Val) :language('PIR') { - .return( node ) +transform handle_specials (PAST::Val) :language('PIR') { + .local pmc iter + iter = node.'iterator'() + + if iter goto check_kids + .return( node ) + + check_kids: + .local pmc op + op = shift iter + + .local string name + name = op.'name'() + + .local pmc specials + specials = find_global 'specials' + + .local int special_exists + special_exists = exists specials[name] + + unless special_exists goto not_a_special + + node = tree.'get'( name, node ) + + not_a_special: + .return( node ) } -# XXX: almost certainly wrong -transform result (empty_list) :language('PIR') { - .local pmc result - result = new 'PAST::Exp' +transform define (PAST::Op) :language('PIR') { + .local pmc iter + iter = node.'iterator'() - .local pmc cons - cons = new 'PAST::Op' - cons.'op'( '__make_empty_cons' ) + .local pmc op, name, lambda + op = shift iter + name = shift iter + lambda = shift iter - result.'add_child'( cons ) - .return( result ) + .local pmc name_str + name_str = name.'name'() + + .local pmc result + result = new 'PAST::Block' + + result.'name'( name_str ) + result.'push'( lambda ) + + .return( result ) } -transform result (atom) :language('PIR') { - .local pmc result - result = new 'PAST::Val' +transform past (quote) :language( 'PIR' ) { + .local pmc children + children = node.'children'() - .local string value - value = node + # remove this Op and promote the first sibling + .local pmc sibling + sibling = children[1] + children = sibling.'children'() - .local string valtype - valtype = '' + .local pmc first_child + first_child = children[0] - .local int symbol - symbol = exists node[ 'symbol' ] - unless symbol goto check_quoted - valtype = 'symbol' + .local string child_type + child_type = typeof first_child - check_quoted: - .local int quote - .local int value_length - value_length = length value + unless child_type == 'PAST::Op' goto rewrite_op - quote = exists node['quote'] - unless quote goto check_double_quoted + .local string op_name + op_name = first_child.'name'() - dec value_length - value = substr value, 1, value_length - valtype = 'literal' - goto unquoted + # if it's an empty list, let it be an empty list + unless op_name == '__make_empty_cons' goto rewrite_op + .return( sibling ) - check_double_quoted: - quote = exists node['quoted_string'] - unless quote goto unquoted + rewrite_op: + .local pmc val_child + val_child = new 'PAST::Val' - sub value_length, 2 - value = substr value, 1, value_length - valtype = 'literal' - goto unquoted + # XXX: this might fail unless the first kid is an op + .local string value + value = first_child.'name'() + val_child.'name'( value ) - unquoted: - result.'value'( value ) - result.'valtype'( valtype ) - .return( result ) + children[0] = val_child + + .local pmc cons_op + cons_op = new 'PAST::Op' + cons_op.'name'( '__list_to_cons' ) + + unshift children, cons_op + + .return( sibling ) } -transform result (quoted_string) :language('PIR') { - .local pmc result - result = new 'PAST::Val' +transform cond (PAST::Op) :language( 'PIR' ) { + .local pmc result + result = new 'PAST::Op' - .local string value - value = node + # cond takes a list of pairs + # ( condition to evaluate ) result + # rewrite so that there are no ops, only vals - .local int string_length - string_length = length value - sub string_length, 2 + .local pmc iter + iter = node.'child_iter'() - .local string val_type - val_type = substr value, 0, 1 - if val_type == '"' goto double_quoted - result.'valtype'( 'single_quoted' ) - goto remove_quotes + .local pmc child + .local pmc new_child - double_quoted: - result.'valtype'( 'double_quoted' ) + # first node is the 'cond' node + child = shift iter + result.'push'( child ) + $S0 = child.'name'() - remove_quotes: - value = substr value, 1, string_length + iter_loop: + unless iter goto iter_end + child = shift iter + new_child = tree.'get'( 'node_to_val', child ) + result.'push'( new_child ) + goto iter_loop + iter_end: - result.'value'( value ) - - .return( result ) + .return( result ) } -transform result (list_item) :language('PIR') { - .local pmc result - .local pmc iter +transform node_to_val (PAST::Op) :language('PIR') { + .local pmc result + result = new 'PAST::Val' - iter = new .Iterator, node # setup iterator for node - set iter, 0 # reset iterator, begin at start + .local string value + value = node.'name'() - .local string key - .local pmc value + .local string quoted_value + quoted_value = "'" + quoted_value .= value + quoted_value .= "'" - iter_loop: - unless iter, iter_end # while (entries) ... - shift key, iter # get key for next entry - value = node[key] - result = tree.get('result', value, key) + result.'name'( quoted_value ) + result.'vtype'( '.Undef' ) - iter_end: - .return( result ) + .return( result ) } + +transform node_to_val (PAST::Val) :language('PIR') { + .local string value + value = node.'name'() + + .local string quoted_value + quoted_value = "'" + quoted_value .= value + quoted_value .= "'" + + node.'name'( quoted_value ) + node.'vtype'( '.Undef' ) + + .return( node ) +} + +# XXX: almost certainly wrong +transform past (empty_list) :language('PIR') { + .local pmc result + + result = new 'PAST::Op' + result.'name'( '__make_empty_cons' ) + + .return( result ) +} + +transform past (atom) :language('PIR') { + .local pmc result + result = new 'PAST::Val' + + .local string value + value = node + + .local string quoted_value + quoted_value = "'" + quoted_value .= value + quoted_value .= "'" + + result.'name'( quoted_value ) + result.'vtype'( '.Undef' ) + + .return( result ) +} + +transform past (quoted_string) :language('PIR') { + .local pmc result + result = new 'PAST::Val' + + .local string value + value = node + + result.'name'( value ) + result.'vtype'( '.Undef' ) + + .return( result ) +} === languages/pheme/lib/pheme.g ================================================================== --- languages/pheme/lib/pheme.g (revision 4466) +++ languages/pheme/lib/pheme.g (local) @@ -1,9 +1,15 @@ grammar Pheme::Grammar; -rule prog { <list>+ } +rule TOP { <list>+ } -rule list { \( <list_item>+ \) } +rule list { \( [ <special_form> | <application> | <cons> ] \) } +rule special_form { <special> <list_item>+ } + +rule application { <atom> <list_item>+ } + +rule cons { <list_item>+ } + # quoted_string has to come first rule list_item { <quoted_string> | <atom> | <list> | <empty_list> } @@ -18,3 +24,5 @@ token symbol_tag { \# } token ws { [ [ ; \N+ ]? \s+ ]* } + +token special { if | cond | define | lambda | quote } === languages/pheme/lib/post2pir.tg ================================================================== --- languages/pheme/lib/post2pir.tg (revision 4466) +++ languages/pheme/lib/post2pir.tg (local) @@ -1,6 +1,6 @@ -grammar PIRGrammar is TGE::Grammar; +grammar Pheme::PIR::Grammar is TGE::Grammar; -transform result (ROOT) :language('PIR') { +transform pir (ROOT) :language('PIR') { .local string result result = <<'EOT' .namespace [ 'Pheme' ] === languages/pheme/pheme.pir ================================================================== --- languages/pheme/pheme.pir (revision 4466) +++ languages/pheme/pheme.pir (local) @@ -1,87 +1,87 @@ -.include 'errors.pasm' +=head1 TITLE -.sub _main :main - .param pmc args +pheme.pir - A Pheme compiler. - errorson .PARROT_ERRORS_PARAM_COUNT_FLAG +=head2 Description - load_bytecode 'languages/pheme/lib/PhemeCompiler.pbc' - load_bytecode 'languages/pheme/lib/PhemeObjects.pir' - load_bytecode 'languages/pheme/lib/PhemeSymbols.pbc' - load_bytecode 'languages/pheme/lib/pheme_grammar_gen.pir' - load_bytecode 'languages/pheme/lib/ASTGrammar.pbc' - load_bytecode 'languages/pheme/lib/OSTGrammar.pbc' - load_bytecode 'languages/pheme/lib/PIRGrammar.pbc' +This is the base file for the Pheme compiler. - .local string source - source = _get_source( args ) +This file includes the parsing and grammar rules from +the src/ directory, loads the relevant PGE libraries, +and registers the compiler under the name 'Pheme'. - .local int compiler_type - .local pmc compiler +=head2 Functions - compiler_type = find_type 'PhemeCompiler' +=over 4 - .local pmc ast, ost, pir - ast = new 'ASTGrammar' - ost = new 'OSTGrammar' - pir = new 'PIRGrammar' +=item __onload() - compiler = new compiler_type - compiler.'init'( 'ast' => ast, 'ost' => ost, 'pir' => pir ) +Loads the PGE libraries needed for running the parser, +and registers the Pheme compiler using a C<HLLCompiler> +object. - .local pmc ast - ast = compiler.'compile'( source ) - end +=cut + +.namespace [ 'Pheme::Compiler' ] + +.sub '__onload' :load :init + load_bytecode 'PGE.pbc' + load_bytecode 'PGE/Text.pbc' + load_bytecode 'PGE/Util.pbc' + load_bytecode 'Parrot/HLLCompiler.pir' + load_bytecode 'PAST-pm.pbc' + + $P0 = subclass 'PGE::Match', 'Match' + $P0 = subclass 'Match', 'Grammar' + $P0 = subclass 'Grammar', 'Pheme::PGE::Grammar' + + $P0 = new [ 'HLLCompiler' ] + + $P0.'language'('Pheme') + $P0.'parsegrammar'( 'Pheme::Grammar' ) + $P0.'astgrammar'( 'Pheme::AST::Grammar' ) .end -.sub _get_source - .param pmc argv - .local string filename +=item main(args :slurpy) :main - .local int arg_count +Start compilation by passing any command line C<args> to the Pheme compiler. - arg_count = argv - unless arg_count == 2 goto err_no_file +=cut - # Read in the source file - filename = argv[1] +.const int SEVERITY_SLOT = 2 # _severity - .local string file_source - file_source = _slurp_file(filename) - .return( file_source ) +.sub 'main' :main + .param pmc args - err_no_file: - print "You must supply a Pheme file to parse.\n" - end -.end + $P0 = compreg 'Pheme' -.sub _slurp_file - .param string filename - .local pmc filehandle - filehandle = open filename, "<" - unless filehandle goto err_no_file - $S1 = read filehandle, 65535 - close filehandle - .return ($S1) + # push_eh exit_handler + $P1 = $P0.'command_line'(args) + # clear_eh + goto done - err_no_file: - print "Unable to open file " - print filename - print "\n" + exit_handler: + .get_results($P0, $S0) + .include 'except_severity.pasm' + $I0 = $P0[SEVERITY_SLOT] + if $I0 != .EXCEPT_EXIT goto rethrow_error + + done: end + + rethrow_error: + rethrow $P0 .end -=head1 LICENSE +.include 'languages/pheme/lib/PhemeObjects.pir' +.include 'languages/pheme/lib/PhemeSymbols.pir' +.include 'languages/pheme/lib/pheme_grammar_gen.pir' +.include 'languages/pheme/lib/ASTGrammar.pir' +.include 'languages/pheme/lib/OSTGrammar.pir' +.include 'languages/pheme/lib/PIRGrammar.pir' -Copyright (C) 2006, The Perl Foundation. +=back -This is free software; you may redistribute it and/or modify it under the same -terms as Parrot. - -=head1 AUTHOR - -chromatic <[EMAIL PROTECTED]> - =cut # Local Variables: === languages/pheme/t/null.t ================================================================== --- languages/pheme/t/null.t (revision 4466) +++ languages/pheme/t/null.t (local) @@ -2,14 +2,4 @@ (plan 6) -(ok (null? '()) "null? should be true given an empty list") - (ok (null? (quote ())) "... marked with quote") - -(ok (null? '()) "... or a single quote") - -(nok (null? (a list)) "null? should be false given a list with atoms") - -(nok (null? ((a list))) "... or a nested list") - -(nok (null? ( '() )) "... or even a list containing an empty list") === src/pmc/class.pmc ================================================================== --- src/pmc/class.pmc (revision 4466) +++ src/pmc/class.pmc (local) @@ -212,7 +212,33 @@ return type; } +static void +install_methods_from_ns(Parrot_Interp interp, PMC *self, PMC *_namespace) +{ + Parrot_Class *_class = PARROT_CLASS(self); + PMC *iter = VTABLE_get_iter(interp, _namespace); + PMC *vt_hash = _class->vtable_methods; + INTVAL n = VTABLE_elements(interp, _namespace); + INTVAL i; + for (i = 0; i < n; ++i) { + STRING *name = VTABLE_shift_string(interp, iter); + PMC *sub; + + Parrot_PCCINVOKE(interp, _namespace, + string_from_literal(interp, "find_sub"), "S->P", name, &sub); + + if (!PMC_IS_NULL(sub)) + if (PMC_sub(sub)->vtable_index != -1) { + VTABLE_set_pmc_keyed_int(interp, _class->vtable_methods, + PMC_sub(sub)->vtable_index, sub); + } + else + VTABLE_add_method(interp, self, name, sub); + } +} + + /* Takes a hash and initializes the class based on it. */ static void init_class_from_hash(Parrot_Interp interp, PMC *self, PMC *info) { @@ -280,11 +306,15 @@ Parrot_PCCINVOKE(interp, old_ns, string_from_literal(interp, "set_class"), "P->", PMCNULL); - /* Link namespace to this class, if there is one. */ - if (!PMC_IS_NULL(_class->_namespace)) + if (!PMC_IS_NULL(_class->_namespace)) { + /* Link namespace to this class, if there is one. */ Parrot_PCCINVOKE(interp, _class->_namespace, string_from_literal(interp, "set_class"), "P->", self); + /* slurp in methods from the namespace */ + install_methods_from_ns(interp, self, _class->_namespace); + } + /* Initialize resolve_method. */ if (VTABLE_exists_keyed_str(interp, info, string_from_literal(interp, "resolve_method"))) { @@ -1195,6 +1225,12 @@ PCCRETURN(PMC *PMCNULL); } + PCCMETHOD void find_vtable_entry(INTVAL idx) { + Parrot_Class *_class = PARROT_CLASS(SELF); + + return VTABLE_get_pmc_keyed_int(interp, _class->vtable_methods, idx); + } + /* =item C<void parents()> === src/pmc/hash.pmc ================================================================== --- src/pmc/hash.pmc (revision 4466) +++ src/pmc/hash.pmc (local) @@ -896,6 +896,9 @@ STRING * const sx = key_string(INTERP, key); HashBucket *b; + if (!sx) + return 0; + key = key_next(INTERP, key); b = parrot_hash_get_bucket(INTERP, h, sx); if (b == NULL) === src/pmc/namespace.pmc ================================================================== --- src/pmc/namespace.pmc (revision 4466) +++ src/pmc/namespace.pmc (local) @@ -508,19 +508,19 @@ */ - METHOD PMC* find_sub(STRING *key) { + PCCMETHOD void find_sub(STRING *key) { STRING *s_sub = CONST_STRING(INTERP, "Sub"); PMC *sub = (PMC *)parrot_hash_get(INTERP, (Hash *)PMC_struct_val(SELF), key); if (!sub) - return PMCNULL; + PCCRETURN(PMC *PMCNULL); /* it's a Sub */ if (VTABLE_isa(INTERP, sub, s_sub)) - return sub; + PCCRETURN(PMC *sub); - return PMCNULL; + PCCRETURN(PMC *PMCNULL); } /*