Permalink
Browse files

Merge branch 'mls/pct_exceptionhandlers'

  • Loading branch information...
2 parents c6ed574 + b5b2038 commit fad30eada4a639886548cc5e4e909805b3eb14ff @mlschroe mlschroe committed Oct 7, 2011
Showing with 118 additions and 61 deletions.
  1. +79 −46 compilers/pct/src/PAST/Compiler.pir
  2. +39 −15 compilers/pct/src/PAST/Node.pir
View
125 compilers/pct/src/PAST/Compiler.pir
@@ -849,8 +849,8 @@ Return the POST representation of a C<PAST::Control>.
.param pmc options :slurpy :named
# Probably not safe to use tempregs in an exception handler
- .local pmc tempregs
- null tempregs
+ .local pmc tempregs
+ null tempregs
.lex '%*TEMPREGS', tempregs
.local pmc ops, children, ishandled, nothandled
@@ -882,17 +882,61 @@ Return the POST representation of a C<PAST::Control>.
.return (ops)
.end
+.sub 'push_exception_handler' :method
+ .param pmc node
+ .param pmc ops
+ .param pmc label
+
+ .local string type, extype
+ type = node.'handle_types'()
+ extype = node.'handle_types_except'()
+ if type goto handler_need_exhandler
+ if extype goto handler_need_exhandler
+ ops.'push_pirop'('push_eh', label)
+ .return ()
+
+ handler_need_exhandler:
+ .local pmc controltypes, subpost
+ .local string ehreg
+ subpost = find_dynamic_lex '$*SUB'
+ ehreg = self.'uniquereg'('P')
+ ops.'push_pirop'('new', ehreg, "'ExceptionHandler'")
+ ops.'push_pirop'('set_label', ehreg, label)
+ controltypes = get_global '%!controltypes'
+ unless type, handle_types_done
+ type = controltypes[type]
+ unless type, handle_types_done
+ $P0 = split ',', type
+ ops.'push_pirop'('callmethod', '"handle_types"', ehreg, $P0 :flat)
+ subpost.'add_directive'('.include "except_types.pasm"')
+ handle_types_done:
+ unless extype, handle_types_except_done
+ extype = controltypes[extype]
+ unless extype, handle_types_except_done
+ $P0 = split ',', extype
+ ops.'push_pirop'('callmethod', '"handle_types_except"', ehreg, $P0 :flat)
+ subpost.'add_directive'('.include "except_types.pasm"')
+ handle_types_except_done:
+ ops.'push_pirop'('push_eh', ehreg)
+ .return ()
+.end
+
.sub 'wrap_handlers' :method
.param pmc child
.param pmc ehs
.param pmc options :slurpy :named
- .local string rtype
+ .local string rtype, result
+ .local int addreturn
rtype = options['rtype']
+ addreturn = options['addreturn']
+ if addreturn goto wrap_no_result
+ result = self.'tempreg'(rtype)
+ wrap_no_result:
- # Probably not safe to use tempregs in an exception handler
- .local pmc tempregs
- null tempregs
+ # Probably not safe to use tempregs in an exception handler
+ .local pmc tempregs
+ null tempregs
.lex '%*TEMPREGS', tempregs
.local pmc it, node, ops, pops, tail, skip
@@ -906,49 +950,35 @@ Return the POST representation of a C<PAST::Control>.
$S0 = self.'unique'('skip_handler_')
skip = $P0.'new'('result'=>$S0)
+ ops.'result'(result)
+ unless result goto wrap_child_no_result
+ child = self.'coerce'(child, result)
+ wrap_child_no_result:
+
it = iter ehs
handler_loop:
unless it, handler_loop_done
node = shift it
- .local pmc ehpir, label, controltypes, subpost
- .local string ehreg, type
+ .local pmc ehpir, label
$P0 = get_hll_global ['POST'], 'Label'
$S0 = self.'unique'('control_')
label = $P0.'new'('result'=>$S0)
-
- subpost = find_dynamic_lex '$*SUB'
-
- ehreg = self.'uniquereg'('P')
- ops.'push_pirop'('new', ehreg, "'ExceptionHandler'")
- ops.'push_pirop'('set_label', ehreg, label)
- controltypes = get_global '%!controltypes'
- type = node.'handle_types'()
- unless type, handle_types_done
- type = controltypes[type]
- unless type, handle_types_done
- $P0 = split ',', type
- ops.'push_pirop'('callmethod', '"handle_types"', ehreg, $P0 :flat)
- subpost.'add_directive'('.include "except_types.pasm"')
- handle_types_done:
- type = node.'handle_types_except'()
- unless type, handle_types_except_done
- type = controltypes[type]
- unless type, handle_types_except_done
- $P0 = split ',', type
- ops.'push_pirop'('callmethod', '"handle_types_except"', ehreg, $P0 :flat)
- subpost.'add_directive'('.include "except_types.pasm"')
- handle_types_except_done:
- ops.'push_pirop'('push_eh', ehreg)
-
+ self.'push_exception_handler'(node, ops, label)
# Add one pop_eh for every handler we push_eh
pops.'push_pirop'('pop_eh')
# Push the handler itself
tail.'push'(label)
ehpir = self.'as_post'(node, 'rtype'=>rtype)
+ unless result goto handler_loop_no_result
+ ehpir = self.'coerce'(ehpir, result)
+ handler_loop_no_result:
tail.'push'(ehpir)
-
+ unless addreturn goto handler_loop
+ .local pmc retval
+ retval = ehpir.'result'()
+ tail.'push_pirop'('return', retval)
goto handler_loop
handler_loop_done:
@@ -1117,18 +1147,14 @@ Return the POST representation of a C<PAST::Block>.
## convert children to post
.local pmc ops, retval
ops = self.'post_children'(node, 'signature'=>$S0)
+ ## result of last child is return from block
+ retval = ops[-1]
## wrap the child with appropriate exception handlers, if any
.local pmc eh
eh = node.'handlers'()
unless eh, no_eh
- $S0 = options['rtype']
- retval = ops[-1]
- ops = self.'wrap_handlers'(ops, eh, 'rtype'=>$S0)
- goto had_eh
+ ops = self.'wrap_handlers'(ops, eh, 'rtype'=>'*', 'addreturn'=>1)
no_eh:
- ## result of last child is return from block
- retval = ops[-1]
- had_eh:
bpost.'push'(ops)
bpost.'push_pirop'('return', retval)
@@ -1875,7 +1901,7 @@ a return value.
=item try(PAST::Op node)
Return the POST representation of a C<PAST::Op>
-node with a 'pasttype' of bind. The first child
+node with a 'pasttype' of try. The first child
is the code to be surrounded by an exception handler,
the second child (if any) is the code to process the
handler.
@@ -1897,13 +1923,18 @@ handler.
$S0 = concat $S0, '_end'
endlabel = $P0.'new'('result'=>$S0)
- .local string rtype
+ .local string rtype, result
rtype = options['rtype']
+ result = self.'tempreg'(rtype)
+ ops.'result'(result)
.local pmc trypast, trypost
trypast = node[0]
trypost = self.'as_post'(trypast, 'rtype'=>rtype)
- ops.'push_pirop'('push_eh', catchlabel)
+ unless result goto trypost_no_result
+ trypost = self.'coerce'(trypost, result)
+ trypost_no_result:
+ self.'push_exception_handler'(node, ops, catchlabel)
ops.'push'(trypost)
ops.'push_pirop'('pop_eh')
.local pmc elsepast, elsepost
@@ -1917,12 +1948,14 @@ handler.
.local pmc catchpast, catchpost
catchpast = node[1]
if null catchpast goto catch_done
- catchpost = self.'as_post'(catchpast, 'rtype'=>'v')
+ catchpost = self.'as_post'(catchpast, 'rtype'=>rtype)
+ unless result goto catchpost_no_result
+ catchpost = self.'coerce'(catchpost, result)
+ catchpost_no_result:
ops.'push'(catchpost)
ops.'push_pirop'('pop_eh') # FIXME: should be before catchpost
catch_done:
ops.'push'(endlabel)
- ops.'result'(trypost)
.return (ops)
.end
View
54 compilers/pct/src/PAST/Node.pir
@@ -104,13 +104,52 @@ Accessor method -- sets/returns the "flatten" flag on arguments.
.tailcall self.'attr'('flat', value, has_value)
.end
+
+=item handlers([node array])
+
+Accessor method -- sets/returns handlers associated with this node.
+Handlers can be used for PAST::Block and PAST::Stmts nodes.
+
+=cut
+
.sub 'handlers' :method
.param pmc value :optional
.param int has_value :opt_flag
.tailcall self.'attr'('handlers', value, has_value)
.end
+=item handle_types([value])
+
+Accessor method -- sets/returns the exception types this node
+handles. This is evaluated if the node is used as a block
+handler, the node is a PAST::Control node, or the node is
+a PAST::Op node of type 'try'.
+
+=cut
+
+.sub 'handle_types' :method
+ .param pmc value :optional
+ .param int has_value :opt_flag
+ .tailcall self.'attr'('handle_types', value, has_value)
+.end
+
+
+=item handle_types_except([value])
+
+Accessor method -- sets/returns the exception types this node
+does not handle. Same as handle_types, but all exceptions not
+matching the specified ones will be caught.
+
+=cut
+
+.sub 'handle_types_except' :method
+ .param pmc value :optional
+ .param int has_value :opt_flag
+ .tailcall self.'attr'('handle_types_except', value, has_value)
+.end
+
+
=item lvalue([flag])
Get/set the C<lvalue> attribute, which indicates whether this
@@ -842,21 +881,6 @@ outer statement.
.end
-.namespace [ 'PAST';'Control' ]
-
-.sub 'handle_types' :method
- .param pmc value :optional
- .param int has_value :opt_flag
- .tailcall self.'attr'('handle_types', value, has_value)
-.end
-
-.sub 'handle_types_except' :method
- .param pmc value :optional
- .param int has_value :opt_flag
- .tailcall self.'attr'('handle_types_except', value, has_value)
-.end
-
-
.namespace [ 'PAST';'VarList' ]
.sub 'bindvalue' :method

0 comments on commit fad30ea

Please sign in to comment.