added some more code to support exception handling
This commit is contained in:
parent
2a88f5d503
commit
77f0bfad5d
@ -1,10 +1,16 @@
|
||||
#class(#pointer) Context(Apex)
|
||||
{
|
||||
#dcl sender ip sp ntmprs.
|
||||
|
||||
#method sender
|
||||
{
|
||||
^self.sender
|
||||
}
|
||||
}
|
||||
|
||||
#class(#pointer) MethodContext(Context)
|
||||
{
|
||||
#dcl sender ip sp ntmprs method receiver home origin.
|
||||
#dcl method receiver home origin.
|
||||
|
||||
#method pc
|
||||
{
|
||||
@ -33,11 +39,16 @@
|
||||
sp := aSP.
|
||||
##sp := sp - 1.
|
||||
}
|
||||
|
||||
#method isHandlerContext
|
||||
{
|
||||
^self.method primitive == 512
|
||||
}
|
||||
}
|
||||
|
||||
#class(#pointer) BlockContext(Context)
|
||||
{
|
||||
#dcl caller ip sp ntmprs nargs source home origin.
|
||||
#dcl nargs source home origin.
|
||||
|
||||
#method fork
|
||||
{
|
||||
@ -146,6 +157,12 @@
|
||||
## self value ifTrue: [ aBlock value. thisContext restart. ].
|
||||
}
|
||||
|
||||
#method whileTrue
|
||||
{
|
||||
(self value) ifFalse: [^nil].
|
||||
self whileTrue.
|
||||
}
|
||||
|
||||
#method whileFalse: aBlock
|
||||
{
|
||||
(self value) ifTrue: [^nil].
|
||||
@ -153,6 +170,12 @@
|
||||
self whileFalse: aBlock.
|
||||
}
|
||||
|
||||
#method whileFalse
|
||||
{
|
||||
(self value) ifTrue: [^nil].
|
||||
self whileFalse.
|
||||
}
|
||||
|
||||
#method pc
|
||||
{
|
||||
^ip
|
||||
@ -179,16 +202,30 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
"------ TODO: -------------------------------------"
|
||||
#method on: anException do: anExceptionBlock
|
||||
{
|
||||
<primitive: #block_on_do>
|
||||
self primitiveFailed.
|
||||
| handlerActive |
|
||||
<exception>
|
||||
handlerActive := true.
|
||||
|
||||
(thisContext basicAt: 9) dump.
|
||||
|
||||
^self value.
|
||||
}
|
||||
|
||||
#method ensure: aBlock
|
||||
{
|
||||
"##
|
||||
| complete returnValue |
|
||||
<ensure>
|
||||
|
||||
returnValue := self valueNoContextSwitch.
|
||||
complete ifNil: [
|
||||
complete := true.
|
||||
aBlock value.
|
||||
].
|
||||
^returnValue. ##"
|
||||
}
|
||||
|
||||
#method ifCurtailed: aBlock
|
||||
@ -198,3 +235,78 @@
|
||||
"------ TODO: -------------------------------------"
|
||||
}
|
||||
|
||||
#class Exception(Object)
|
||||
{
|
||||
#dcl signalContext handlerContext messageText.
|
||||
|
||||
#method(#class) signal
|
||||
{
|
||||
self new signal
|
||||
}
|
||||
|
||||
#method(#class) signal: text
|
||||
{
|
||||
self new signal: text
|
||||
}
|
||||
|
||||
#method signal
|
||||
{
|
||||
self.signalContext := thisContext.
|
||||
self isHandled
|
||||
ifTrue: [ self handle ]
|
||||
ifFalse: [ self notHandled ].
|
||||
}
|
||||
|
||||
#method signal: text
|
||||
{
|
||||
self.messageText := text.
|
||||
self signal.
|
||||
}
|
||||
|
||||
#method isHandled
|
||||
{
|
||||
^self handlerContext notNil
|
||||
}
|
||||
|
||||
#method handle
|
||||
{
|
||||
self return: (self.handlerContext handlerBlock value: self)
|
||||
}
|
||||
|
||||
#method notHandle
|
||||
{
|
||||
'EXCEPTION NOT HANDLED' dump.
|
||||
## TODO: debug the current process???? "
|
||||
Processor activeProcess terminate.
|
||||
}
|
||||
|
||||
#method handlerContext
|
||||
{
|
||||
(self.handlerContext notNil) ifTrue: [ ^self.handlerContext ].
|
||||
^self handlerContextStartingFrom: self.signalContext sender.
|
||||
}
|
||||
|
||||
#method handlerContextStartingFrom: aContext
|
||||
{
|
||||
## Find exception handling context starting from a given context
|
||||
|
||||
| ctx |
|
||||
|
||||
ctx := aContext.
|
||||
[ ctx notNil ]
|
||||
whileTrue: [
|
||||
(ctx handles: self) ifTrue: [ ^self.handlerContext := ctx ].
|
||||
ctx := ctx sender
|
||||
].
|
||||
^nil
|
||||
}
|
||||
|
||||
#method return: anObject
|
||||
{
|
||||
Processor return: anObject to: (self.handlerContext parent)
|
||||
}
|
||||
}
|
||||
|
||||
#class NoSuchMessageException(Exception)
|
||||
{
|
||||
}
|
||||
|
@ -380,4 +380,10 @@
|
||||
"#method signal: aSemaphore onOutput: file
|
||||
{
|
||||
}"
|
||||
|
||||
#method return: anObject to: aContext
|
||||
{
|
||||
<primitive: #_processor_return_to>
|
||||
self primitiveFailed.
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +254,11 @@
|
||||
#class(#pointer) CompiledMethod(Object)
|
||||
{
|
||||
#dcl owner preamble preamble_data_1 preamble_data_2 ntmprs nargs code source.
|
||||
|
||||
#method preamble
|
||||
{
|
||||
^self.preamble
|
||||
}
|
||||
}
|
||||
|
||||
#include 'Context.st'.
|
||||
|
@ -87,6 +87,7 @@ static struct voca_t
|
||||
{ 9, { 'c','l','a','s','s','i','n','s','t' } },
|
||||
{ 3, { 'd','c','l' } },
|
||||
{ 7, { 'd','e','c','l','a','r','e' } },
|
||||
{ 9, { 'e','x','c','e','p','t','i','o','n' } },
|
||||
{ 6, { 'e','x','t','e','n','d' } },
|
||||
{ 5, { 'f','a','l','s','e' } },
|
||||
{ 8, { 'h','a','l','f','w','o','r','d' } },
|
||||
@ -120,6 +121,7 @@ enum voca_id_t
|
||||
VOCA_CLASSINST,
|
||||
VOCA_DCL,
|
||||
VOCA_DECLARE,
|
||||
VOCA_EXCEPTION,
|
||||
VOCA_EXTEND,
|
||||
VOCA_FALSE,
|
||||
VOCA_HALFWORD,
|
||||
@ -2606,7 +2608,8 @@ static int compile_method_temporaries (stix_t* stix)
|
||||
static int compile_method_primitive (stix_t* stix)
|
||||
{
|
||||
/*
|
||||
* method-primitive := "<" "primitive:" integer ">"
|
||||
* method-primitive := "<" "primitive:" integer ">" |
|
||||
* "<" "exception" ">"
|
||||
*/
|
||||
stix_ooi_t prim_no;
|
||||
const stix_ooch_t* ptr, * end;
|
||||
@ -2618,18 +2621,10 @@ static int compile_method_primitive (stix_t* stix)
|
||||
}
|
||||
|
||||
GET_TOKEN (stix);
|
||||
if (!is_token_keyword(stix, VOCA_PRIMITIVE_COLON))
|
||||
print_oocs (&stix->c->tok.name);
|
||||
printf ("]]]]]]]]]]]]]]]]]]]]]]\n");
|
||||
if (is_token_keyword(stix, VOCA_PRIMITIVE_COLON))
|
||||
{
|
||||
set_syntax_error (stix, STIX_SYNERR_PRIMITIVE, &stix->c->tok.loc, &stix->c->tok.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO: other modifiers than primitive: ?
|
||||
* <primitive: 10>
|
||||
* <primitive: #primitive_name>
|
||||
* <some-other-modifier: xxxx>
|
||||
*/
|
||||
|
||||
GET_TOKEN (stix);
|
||||
switch (stix->c->tok.type)
|
||||
{
|
||||
@ -2692,6 +2687,18 @@ static int compile_method_primitive (stix_t* stix)
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
else if (is_token_word(stix, VOCA_EXCEPTION))
|
||||
{
|
||||
/* TODO: exception handler is supposed to be used by BlockContext on:do:.
|
||||
* it needs to check the number of arguments at least */
|
||||
stix->c->mth.prim_type = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
set_syntax_error (stix, STIX_SYNERR_PRIMITIVE, &stix->c->tok.loc, &stix->c->tok.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
GET_TOKEN (stix);
|
||||
if (!is_token_binary_selector(stix, VOCA_GT))
|
||||
@ -4273,12 +4280,17 @@ static int add_compiled_method (stix_t* stix)
|
||||
preamble_code = STIX_METHOD_PREAMBLE_PRIMITIVE;
|
||||
preamble_index = stix->c->mth.prim_no;
|
||||
}
|
||||
else
|
||||
else if (stix->c->mth.prim_type == 2)
|
||||
{
|
||||
STIX_ASSERT (stix->c->mth.prim_type == 2);
|
||||
preamble_code = STIX_METHOD_PREAMBLE_NAMED_PRIMITIVE;
|
||||
preamble_index = stix->c->mth.prim_no;
|
||||
}
|
||||
else
|
||||
{
|
||||
STIX_ASSERT (stix->c->mth.prim_type == 3);
|
||||
preamble_code = STIX_METHOD_PREAMBLE_EXCEPTION;
|
||||
preamble_index = 0;
|
||||
}
|
||||
|
||||
STIX_ASSERT (STIX_OOI_IN_PREAMBLE_INDEX_RANGE(preamble_index));
|
||||
|
||||
|
@ -1608,32 +1608,43 @@ printf ("PRIMITVE VALUE RECEIVER IS NOT A BLOCK CONTEXT\n");
|
||||
static int prim_block_on_do (stix_t* stix, stix_ooi_t nargs)
|
||||
{
|
||||
int x;
|
||||
stix_oop_t exblk, excls;
|
||||
stix_oop_oop_t exarr;
|
||||
stix_oop_context_t blkctx;
|
||||
stix_ooi_t i, j;
|
||||
|
||||
STIX_ASSERT (nargs == 2);
|
||||
STIX_ASSERT (nargs >= 2);
|
||||
|
||||
exblk = ACTIVE_STACK_GET(stix, stix->sp);
|
||||
excls = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
||||
if ((stix_oow_t)nargs & 1) return 0; /* it expects even number of arguments */
|
||||
|
||||
//for (i = 0; i < nargs; i += 2)
|
||||
//{
|
||||
// exblk = ACTIVE_STACK_GET(stix, stix->sp);
|
||||
// excls = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
||||
//}
|
||||
|
||||
stix_pushtmp (stix, &exblk);
|
||||
stix_pushtmp (stix, &excls);
|
||||
x = __block_value (stix, nargs, 0, 0, &blkctx);
|
||||
stix_poptmps (stix, 2);
|
||||
if (x <= 0) return x; /* hard failure and soft failure */
|
||||
|
||||
/* TOOD: implement zero-cost exception handling.
|
||||
* this implementation requires allocation of a new array
|
||||
* every time on:do: is executed */
|
||||
/*
|
||||
* stix_pushtmp (stix, &blkctx);
|
||||
blkctx->exception_info = stix_instantiate (stix, stix->_array, );
|
||||
|
||||
stix_pushtmp (stix, (stix_oop_t*)&blkctx);
|
||||
exarr = (stix_oop_oop_t)stix_instantiate (stix, stix->_array, STIX_NULL, nargs);
|
||||
stix_poptmp (stix);
|
||||
*/
|
||||
if (!exarr) return -1; /* hard failure */ /* TOOD: can't this be treated as a soft failure? */
|
||||
|
||||
for (i = nargs, j = 0; i > 0;)
|
||||
{
|
||||
--i;
|
||||
exarr->slot[j++] = ACTIVE_STACK_GET(stix, stix->sp - i);
|
||||
--i;
|
||||
exarr->slot[j++] = ACTIVE_STACK_GET(stix, stix->sp - i);
|
||||
}
|
||||
|
||||
|
||||
#if defined(STIX_DEBUG_EXEC_001)
|
||||
printf ("<<ENTERING BLOCK>> SP=%ld\n", (long int)stix->sp);
|
||||
printf ("<<ENTERING BLOCK BY ON:DO:>> SP=%ld\n", (long int)stix->sp);
|
||||
#endif
|
||||
SWITCH_ACTIVE_CONTEXT (stix, (stix_oop_context_t)blkctx);
|
||||
return 1;
|
||||
@ -1816,6 +1827,25 @@ static int prim_processor_remove_semaphore (stix_t* stix, stix_ooi_t nargs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int prim_processor_return_to (stix_t* stix, stix_ooi_t nargs)
|
||||
{
|
||||
stix_oop_t rcv, ret, ctx;
|
||||
|
||||
STIX_ASSERT (nargs == 2);
|
||||
|
||||
rcv = ACTIVE_STACK_GET(stix, stix->sp - 2);
|
||||
ret = ACTIVE_STACK_GET(stix, stix->sp - 1);
|
||||
ctx = ACTIVE_STACK_GET(stix, stix->sp);
|
||||
|
||||
if (rcv != (stix_oop_t)stix->processor) return 0;
|
||||
/* TODO: check if ctx is a block context or a method context */
|
||||
|
||||
ACTIVE_STACK_POPS (stix, nargs + 1); /* pop arguments and receiver */
|
||||
SWITCH_ACTIVE_CONTEXT (stix, ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int prim_integer_add (stix_t* stix, stix_ooi_t nargs)
|
||||
{
|
||||
stix_oop_t rcv, arg, res;
|
||||
@ -2493,7 +2523,7 @@ static prim_t primitives[] =
|
||||
|
||||
{ 0, MAX_NARGS, prim_block_value, "_block_value" },
|
||||
{ 0, MAX_NARGS, prim_block_new_process, "_block_new_process" },
|
||||
{ 2, 2, prim_block_on_do, "_block_on_do" },
|
||||
{ 2, MAX_NARGS, prim_block_on_do, "_block_on_do" },
|
||||
|
||||
{ 0, 0, prim_process_resume, "_process_resume" },
|
||||
{ 0, 0, prim_process_terminate, "_process_terminate" },
|
||||
@ -2504,6 +2534,7 @@ static prim_t primitives[] =
|
||||
{ 1, 1, prim_processor_schedule, "_processor_schedule" },
|
||||
{ 2, 3, prim_processor_add_timed_semaphore, "_processor_add_timed_semaphore" },
|
||||
{ 1, 1, prim_processor_remove_semaphore, "_processor_remove_semaphore" },
|
||||
{ 2, 2, prim_processor_return_to, "_processor_return_to" },
|
||||
|
||||
{ 1, 1, prim_integer_add, "_integer_add" },
|
||||
{ 1, 1, prim_integer_sub, "_integer_sub" },
|
||||
@ -2878,7 +2909,8 @@ printf ("]\n");
|
||||
}
|
||||
|
||||
default:
|
||||
STIX_ASSERT (preamble_code == STIX_METHOD_PREAMBLE_NONE);
|
||||
STIX_ASSERT (preamble_code == STIX_METHOD_PREAMBLE_NONE ||
|
||||
preamble_code == STIX_METHOD_PREAMBLE_EXCEPTION);
|
||||
if (activate_new_method (stix, method) <= -1) return -1;
|
||||
break;
|
||||
}
|
||||
@ -3642,8 +3674,6 @@ printf ("<<LEAVING>> SP=%d\n", (int)stix->sp);
|
||||
/* place the instruction pointer back at the return instruction.
|
||||
* even if the context is reentered, it will just return.
|
||||
*stix->ip--;*/
|
||||
|
||||
|
||||
#if defined(STIX_DEBUG_EXEC_002)
|
||||
printf ("TERMINATING A PROCESS RETURNING old_active context %p\n", stix->active_context);
|
||||
#endif
|
||||
@ -3659,8 +3689,6 @@ printf ("TERMINATED A PROCESS RETURNING %lld new active_context %p\n", (long lon
|
||||
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT orgin->ip %ld origin->sender->ip %ld\n",
|
||||
(long int)STIX_OOP_TO_SMOOI(stix->active_context->origin->ip), (long int)STIX_OOP_TO_SMOOI(stix->active_context->origin->sender->ip));
|
||||
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT origin %p origin->sender %p\n", stix->active_context->origin, stix->active_context->origin->sender);
|
||||
printf ("ERROR: CAN'T RETURN FROM DEAD METHOD CONTEXT\n");
|
||||
|
||||
/* TODO: proper error handling */
|
||||
stix->errnum = STIX_EINTERN; /* TODO: this should be caughtable at the stix level... */
|
||||
return -1;
|
||||
@ -3714,7 +3742,6 @@ printf (">>>>>>>>>>>>>>>> METHOD RETURN FROM WITHIN A BLOCK. NON-LOCAL RETURN..
|
||||
printf ("<<<RETURNIGN TO THE INITIAL CONTEXT>>> TERMINATING SP => %ld\n", (long int)stix->sp);
|
||||
#endif
|
||||
|
||||
|
||||
/* the stack contains the final return value so the stack pointer must be 0. */
|
||||
STIX_ASSERT (stix->sp == 0);
|
||||
|
||||
@ -3723,14 +3750,12 @@ printf ("<<<RETURNIGN TO THE INITIAL CONTEXT>>> TERMINATING SP => %ld\n", (long
|
||||
else
|
||||
goto done;
|
||||
|
||||
|
||||
/* TODO: store the return value to the VM register.
|
||||
* the caller to stix_execute() can fetch it to return it to the system */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case BCODE_RETURN_FROM_BLOCK:
|
||||
|
@ -342,7 +342,6 @@ struct stix_iotok_t
|
||||
STIX_IOTOK_IDENT_DOTTED,
|
||||
STIX_IOTOK_BINSEL,
|
||||
STIX_IOTOK_KEYWORD,
|
||||
STIX_IOTOK_PRIMITIVE,
|
||||
STIX_IOTOK_ASSIGN,
|
||||
STIX_IOTOK_COLON,
|
||||
STIX_IOTOK_RETURN,
|
||||
|
@ -464,6 +464,8 @@ struct stix_method_t
|
||||
* 6 - return -index.
|
||||
* 7 - return instvar[index]
|
||||
* 8 - do primitive[index]
|
||||
* 9 - do named primitive[index]
|
||||
* 10 - exception handler
|
||||
*/
|
||||
#define STIX_METHOD_MAKE_PREAMBLE(code,index) ((((stix_ooi_t)index) << 8) | ((stix_ooi_t)code))
|
||||
#define STIX_METHOD_GET_PREAMBLE_CODE(preamble) (((stix_ooi_t)preamble) & 0xFF)
|
||||
@ -479,13 +481,14 @@ struct stix_method_t
|
||||
#define STIX_METHOD_PREAMBLE_RETURN_INSTVAR 7
|
||||
#define STIX_METHOD_PREAMBLE_PRIMITIVE 8
|
||||
#define STIX_METHOD_PREAMBLE_NAMED_PRIMITIVE 9 /* index is an index to the symbol table */
|
||||
#define STIX_METHOD_PREAMBLE_EXCEPTION 10
|
||||
|
||||
/* the index is an 16-bit unsigned integer. */
|
||||
#define STIX_METHOD_PREAMBLE_INDEX_MIN 0x0000
|
||||
#define STIX_METHOD_PREAMBLE_INDEX_MAX 0xFFFF
|
||||
#define STIX_OOI_IN_PREAMBLE_INDEX_RANGE(num) ((num) >= STIX_METHOD_PREAMBLE_INDEX_MIN && (num) <= STIX_METHOD_PREAMBLE_INDEX_MAX)
|
||||
|
||||
#define STIX_CONTEXT_NAMED_INSTVARS 10
|
||||
#define STIX_CONTEXT_NAMED_INSTVARS 8
|
||||
typedef struct stix_context_t stix_context_t;
|
||||
typedef struct stix_context_t* stix_oop_context_t;
|
||||
struct stix_context_t
|
||||
@ -537,10 +540,6 @@ struct stix_context_t
|
||||
* the source block context. */
|
||||
stix_oop_context_t origin;
|
||||
|
||||
/* each even position (0, 2, 4, etc) contains an exception class
|
||||
* each odd position (1, 3, 5, etc) contains an exception handler block */
|
||||
stix_oop_t exception_info;
|
||||
|
||||
/* variable indexed part */
|
||||
stix_oop_t slot[1]; /* stack */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user