# 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);
     }
 
 /*

Reply via email to