|
29 | 29 |
|
30 | 30 | //////////////////////////////////////////////////////////////////////////////// |
31 | 31 |
|
| 32 | +struct MCScriptHandlerContext |
| 33 | +{ |
| 34 | + MCScriptInstanceRef instance; |
| 35 | + MCScriptHandlerDefinition *definition; |
| 36 | +}; |
| 37 | + |
| 38 | +static bool MCScriptHandlerInvoke(void *context, MCValueRef *p_arguments, uindex_t p_argument_count, MCValueRef& r_value); |
| 39 | +static void MCScriptHandlerRelease(void *context); |
| 40 | + |
| 41 | +static const MCHandlerCallbacks kMCScriptHandlerCallbacks = |
| 42 | +{ |
| 43 | + sizeof(MCScriptHandlerContext), |
| 44 | + MCScriptHandlerRelease, |
| 45 | + MCScriptHandlerInvoke, |
| 46 | +}; |
| 47 | + |
| 48 | +//////////////////////////////////////////////////////////////////////////////// |
| 49 | + |
32 | 50 | bool MCScriptCreateInstanceOfModule(MCScriptModuleRef p_module, MCScriptInstanceRef& r_instance) |
33 | 51 | { |
34 | 52 | bool t_success; |
@@ -252,6 +270,11 @@ bool MCScriptThrowUnableToResolveMultiInvoke(MCScriptModuleRef p_module, MCScrip |
252 | 270 | return MCErrorCreateAndThrow(kMCScriptNoMatchingHandlerErrorTypeInfo, "handlers", *t_handler_list, "types", *t_type_list, nil); |
253 | 271 | } |
254 | 272 |
|
| 273 | +bool MCScriptThrowNotAHandlerValueError(MCValueRef p_value) |
| 274 | +{ |
| 275 | + return MCErrorCreateAndThrow(kMCScriptNotAHandlerValueErrorTypeInfo, "value", p_value, nil); |
| 276 | +} |
| 277 | + |
255 | 278 | /////////// |
256 | 279 |
|
257 | 280 | MCScriptVariableDefinition *MCScriptDefinitionAsVariable(MCScriptDefinition *self) |
@@ -684,6 +707,17 @@ static inline MCValueRef MCScriptFetchFromRegisterInFrame(MCScriptFrame *p_frame |
684 | 707 | return p_frame -> slots[p_frame -> handler -> register_offset + p_register]; |
685 | 708 | } |
686 | 709 |
|
| 710 | +static inline void MCScriptStoreToRegisterInFrameAndRelease(MCScriptFrame *p_frame, int p_register, MCValueRef p_value) |
| 711 | +{ |
| 712 | + /* LOAD CHECK */ __MCScriptAssert__(p_register >= 0 && p_register < p_frame -> handler -> slot_count - p_frame -> handler -> register_offset, |
| 713 | + "register out of range on store"); |
| 714 | + if (p_frame -> slots[p_frame -> handler -> register_offset + p_register] != p_value) |
| 715 | + { |
| 716 | + MCValueRelease(p_frame -> slots[p_frame -> handler -> register_offset + p_register]); |
| 717 | + p_frame -> slots[p_frame -> handler -> register_offset + p_register] = p_value; |
| 718 | + } |
| 719 | +} |
| 720 | + |
687 | 721 | static inline void MCScriptStoreToRegisterInFrame(MCScriptFrame *p_frame, int p_register, MCValueRef p_value) |
688 | 722 | { |
689 | 723 | /* LOAD CHECK */ __MCScriptAssert__(p_register >= 0 && p_register < p_frame -> handler -> slot_count - p_frame -> handler -> register_offset, |
@@ -1598,6 +1632,21 @@ bool MCScriptBytecodeIterate(byte_t*& x_bytecode, byte_t *p_bytecode_limit, MCSc |
1598 | 1632 | return true; |
1599 | 1633 | } |
1600 | 1634 |
|
| 1635 | +static bool MCScriptHandlerInvoke(void *p_context, MCValueRef *p_arguments, uindex_t p_argument_count, MCValueRef& r_result) |
| 1636 | +{ |
| 1637 | + MCScriptHandlerContext *context; |
| 1638 | + context = (MCScriptHandlerContext *)p_context; |
| 1639 | + |
| 1640 | + return MCScriptCallHandlerOfInstanceDirect(context -> instance, context -> definition, p_arguments, p_argument_count, r_result); |
| 1641 | +} |
| 1642 | + |
| 1643 | +static void MCScriptHandlerRelease(void *p_context) |
| 1644 | +{ |
| 1645 | + MCScriptHandlerContext *context; |
| 1646 | + context = (MCScriptHandlerContext *)p_context; |
| 1647 | + MCScriptReleaseInstance(context -> instance); |
| 1648 | +} |
| 1649 | + |
1601 | 1650 | bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHandlerDefinition *p_handler, MCValueRef *p_arguments, uindex_t p_argument_count, MCValueRef& r_value) |
1602 | 1651 | { |
1603 | 1652 | // As this method is called internally, we can be sure that the arguments conform |
@@ -1877,13 +1926,40 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan |
1877 | 1926 |
|
1878 | 1927 | __MCScriptAssert__(MCValueGetTypeCode(t_handler) == kMCValueTypeCodeHandler, |
1879 | 1928 | "handler argument to invoke not a handler"); |
| 1929 | + |
| 1930 | + if (MCValueGetTypeCode(t_handler) != kMCValueTypeCodeHandler) |
| 1931 | + t_success = MCScriptThrowNotAHandlerValueError(t_handler); |
| 1932 | + |
| 1933 | + // Build the argument list (arg_1 onwards). |
| 1934 | + MCValueRef *t_handler_args; |
| 1935 | + if (t_success) |
| 1936 | + t_success = MCMemoryNewArray(t_arity - 2, t_handler_args); |
1880 | 1937 |
|
1881 | | - MCScriptInstanceRef t_instance; |
1882 | | - MCScriptDefinition *t_definition; |
1883 | | - t_instance = (MCScriptInstanceRef)MCHandlerGetInstance((MCHandlerRef)t_handler); |
1884 | | - t_definition = (MCScriptDefinition *)MCHandlerGetDefinition((MCHandlerRef)t_handler); |
1885 | | - |
1886 | | - t_success = MCScriptPerformInvoke(t_frame, t_next_bytecode, t_instance, t_definition, t_arguments + 1, t_arity - 1); |
| 1938 | + if (t_success) |
| 1939 | + { |
| 1940 | + for(int i = 0; i < t_arity - 2; i++) |
| 1941 | + t_handler_args[i] = MCScriptFetchFromRegisterInFrame(t_frame, t_arguments[i + 2]); |
| 1942 | + |
| 1943 | + MCValueRef t_result; |
| 1944 | + t_success = MCHandlerInvoke((MCHandlerRef)t_handler, t_handler_args, t_arity - 2, t_result); |
| 1945 | + |
| 1946 | + // If the call succeeded, we must copy back all 'out' / 'inout' mode parameters |
| 1947 | + // to the register file, and also the result. |
| 1948 | + if (t_success) |
| 1949 | + { |
| 1950 | + MCTypeInfoRef t_signature; |
| 1951 | + t_signature = MCValueGetTypeInfo(t_handler); |
| 1952 | + |
| 1953 | + for(uindex_t i = 0; i < MCHandlerTypeInfoGetParameterCount(t_signature); i++) |
| 1954 | + if (MCHandlerTypeInfoGetParameterMode(t_signature, i) != kMCHandlerTypeFieldModeIn) |
| 1955 | + MCScriptStoreToRegisterInFrameAndRelease(t_frame, t_arguments[i + 2], t_handler_args[i]); |
| 1956 | + |
| 1957 | + |
| 1958 | + MCScriptStoreToRegisterInFrameAndRelease(t_frame, t_arguments[1], t_result); |
| 1959 | + } |
| 1960 | + |
| 1961 | + MCMemoryDeleteArray(t_handler_args); |
| 1962 | + } |
1887 | 1963 | } |
1888 | 1964 | break; |
1889 | 1965 | case kMCScriptBytecodeOpFetchLocal: |
@@ -1993,21 +2069,46 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan |
1993 | 2069 | MCScriptDefinition *t_definition; |
1994 | 2070 | MCScriptResolveDefinitionInFrame(t_frame, t_index, t_instance, t_definition); |
1995 | 2071 |
|
1996 | | - __MCScriptAssert__(t_definition -> kind == kMCScriptDefinitionKindVariable, |
1997 | | - "definition not a variable in fetch global"); |
1998 | | - |
1999 | | - MCScriptVariableDefinition *t_var_definition; |
2000 | | - t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition); |
2001 | | - |
| 2072 | + // Fetch the value - if it is a variable fetch from the slot; if |
| 2073 | + // it is a handler construct a handler value. |
2002 | 2074 | MCValueRef t_value; |
2003 | | - t_value = t_instance -> slots[t_var_definition -> slot_index]; |
| 2075 | + if (t_definition -> kind == kMCScriptDefinitionKindVariable) |
| 2076 | + { |
| 2077 | + MCScriptVariableDefinition *t_var_definition; |
| 2078 | + t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition); |
2004 | 2079 |
|
2005 | | - if (t_value == kMCNull && |
2006 | | - !MCTypeInfoIsOptional(t_instance -> module -> types[t_var_definition -> type] -> typeinfo)) |
2007 | | - t_success = MCScriptThrowGlobalVariableUsedBeforeDefinedError(t_frame -> instance -> module, t_index); |
| 2080 | + t_value = t_instance -> slots[t_var_definition -> slot_index]; |
| 2081 | + |
| 2082 | + if (t_value == kMCNull && |
| 2083 | + !MCTypeInfoIsOptional(t_instance -> module -> types[t_var_definition -> type] -> typeinfo)) |
| 2084 | + t_success = MCScriptThrowGlobalVariableUsedBeforeDefinedError(t_frame -> instance -> module, t_index); |
| 2085 | + } |
| 2086 | + else if (t_definition -> kind == kMCScriptDefinitionKindHandler) |
| 2087 | + { |
| 2088 | + MCScriptHandlerDefinition *t_handler_definition; |
| 2089 | + t_handler_definition = static_cast<MCScriptHandlerDefinition *>(t_definition); |
| 2090 | + |
| 2091 | + MCTypeInfoRef t_signature; |
| 2092 | + t_signature = t_instance -> module -> types[t_handler_definition -> type] -> typeinfo; |
| 2093 | + |
| 2094 | + // The context struct is 'moved' into the handlerref. |
| 2095 | + MCScriptHandlerContext t_context; |
| 2096 | + t_context . instance = MCScriptRetainInstance(t_instance); |
| 2097 | + t_context . definition = t_handler_definition; |
| 2098 | + |
| 2099 | + t_success = MCHandlerCreate(t_signature, &kMCScriptHandlerCallbacks, &t_context, (MCHandlerRef&)t_value); |
| 2100 | + } |
| 2101 | + else |
| 2102 | + { |
| 2103 | + // TODO: Implement support for foreign handler evaluation |
| 2104 | + t_success = false; |
| 2105 | + } |
2008 | 2106 |
|
2009 | 2107 | if (t_success) |
| 2108 | + { |
2010 | 2109 | MCScriptStoreToRegisterInFrame(t_frame, t_dst, t_value); |
| 2110 | + MCValueRelease(t_value); |
| 2111 | + } |
2011 | 2112 | } |
2012 | 2113 | break; |
2013 | 2114 | case kMCScriptBytecodeOpStoreGlobal: |
|
0 commit comments