Skip to content

Commit e262d6c

Browse files
committed
Merge pull request livecode#1808 from runrevmark/feature-lcb_context_vars
[[ LCB ]] Context Vars
2 parents 70f3ba0 + 6902a0f commit e262d6c

File tree

13 files changed

+304
-38
lines changed

13 files changed

+304
-38
lines changed

libscript/include/script.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ enum MCScriptDefinitionKind
260260
kMCScriptDefinitionKindEvent,
261261
kMCScriptDefinitionKindSyntax,
262262
kMCScriptDefinitionKindDefinitionGroup,
263+
kMCScriptDefinitionKindContextVariable,
263264

264265
kMCScriptDefinitionKind__Last,
265266
};
@@ -273,6 +274,14 @@ enum MCScriptHandlerTypeParameterMode
273274
kMCScriptHandlerTypeParameterMode__Last
274275
};
275276

277+
enum MCScriptHandlerScope
278+
{
279+
kMCScriptHandlerScopeNormal,
280+
kMCScriptHandlerScopeContext,
281+
282+
kMCScriptHandlerScope__Last,
283+
};
284+
276285
void MCScriptBeginModule(MCScriptModuleKind kind, MCNameRef name, MCScriptModuleBuilderRef& r_builder);
277286
bool MCScriptEndModule(MCScriptModuleBuilderRef builder, MCStreamRef stream);
278287

@@ -302,8 +311,9 @@ void MCScriptAddDefinitionToModule(MCScriptModuleBuilderRef builder, uindex_t& r
302311
void MCScriptAddTypeToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index);
303312
void MCScriptAddConstantToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t const_idx, uindex_t index);
304313
void MCScriptAddVariableToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index);
314+
void MCScriptAddContextVariableToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index, uindex_t def_index);
305315

306-
void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t signature, uindex_t index);
316+
void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef builder, MCScriptHandlerScope scope, MCNameRef name, uindex_t signature, uindex_t index);
307317
void MCScriptAddParameterToHandlerInModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t& r_index);
308318
void MCScriptAddVariableToHandlerInModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t& r_index);
309319
void MCScriptEndHandlerInModule(MCScriptModuleBuilderRef builder);

libscript/src/script-builder.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,29 @@ void MCScriptAddVariableToModule(MCScriptModuleBuilderRef self, MCNameRef p_name
391391
t_definition -> type = p_type;
392392
}
393393

394+
void MCScriptAddContextVariableToModule(MCScriptModuleBuilderRef self, MCNameRef p_name, uindex_t p_type, uindex_t p_def_index, uindex_t p_index)
395+
{
396+
if (self == nil || !self -> valid)
397+
return;
398+
399+
if (p_index >= self -> module . definition_count ||
400+
self -> module . definitions[p_index] != nil ||
401+
!MCMemoryNew((MCScriptContextVariableDefinition*&)self -> module . definitions[p_index]))
402+
{
403+
self -> valid = false;
404+
return;
405+
}
406+
407+
__assign_definition_name(self, p_index, p_name);
408+
409+
MCScriptContextVariableDefinition *t_definition;
410+
t_definition = static_cast<MCScriptContextVariableDefinition *>(self -> module . definitions[p_index]);
411+
412+
t_definition -> kind = kMCScriptDefinitionKindContextVariable;
413+
t_definition -> type = p_type;
414+
t_definition -> default_value = p_def_index;
415+
}
416+
394417
void MCScriptAddForeignHandlerToModule(MCScriptModuleBuilderRef self, MCNameRef p_name, uindex_t p_signature, MCStringRef p_binding, uindex_t p_index)
395418
{
396419
if (self == nil || !self -> valid)
@@ -1121,7 +1144,7 @@ static void __emit_position(MCScriptModuleBuilderRef self, uindex_t p_address, u
11211144
self -> module . positions[t_pindex] . line = p_line;
11221145
}
11231146

1124-
void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef self, MCNameRef p_name, uindex_t p_type, uindex_t p_index)
1147+
void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef self, MCScriptHandlerScope p_scope, MCNameRef p_name, uindex_t p_type, uindex_t p_index)
11251148
{
11261149
if (self == nil || !self -> valid)
11271150
return;
@@ -1142,6 +1165,7 @@ void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef self, MCNameRef p_nam
11421165
t_definition -> kind = kMCScriptDefinitionKindHandler;
11431166
t_definition -> type = p_type;
11441167
t_definition -> start_address = self -> module . bytecode_count;
1168+
t_definition -> scope = p_scope;
11451169

11461170
self -> current_handler = p_index;
11471171
self -> current_param_count = 0;

libscript/src/script-instance.cpp

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ bool MCScriptThrowInvalidValueForGlobalVariableError(MCScriptModuleRef p_module,
222222
return MCErrorCreateAndThrow(kMCScriptInvalidVariableValueErrorTypeInfo, "module", p_module -> name, "variable", MCScriptGetNameOfGlobalVariableInModule(p_module, p_index), "type", MCNamedTypeInfoGetName(p_expected_type), "value", p_value, nil);
223223
}
224224

225+
bool MCScriptThrowInvalidValueForContextVariableError(MCScriptModuleRef p_module, uindex_t p_index, MCTypeInfoRef p_expected_type, MCValueRef p_value)
226+
{
227+
return MCErrorCreateAndThrow(kMCScriptInvalidVariableValueErrorTypeInfo, "module", p_module -> name, "variable", MCScriptGetNameOfContextVariableInModule(p_module, p_index), "type", MCNamedTypeInfoGetName(p_expected_type), "value", p_value, nil);
228+
}
229+
225230
bool MCScriptThrowNotABooleanError(MCValueRef p_value)
226231
{
227232
return MCErrorCreateAndThrow(kMCScriptNotABooleanValueErrorTypeInfo, "value", p_value, nil);
@@ -285,6 +290,11 @@ bool MCScriptThrowNotAHandlerValueError(MCValueRef p_value)
285290
return MCErrorCreateAndThrow(kMCScriptNotAHandlerValueErrorTypeInfo, "value", p_value, nil);
286291
}
287292

293+
bool MCScriptThrowCannotCallContextHandlerError(MCScriptModuleRef p_module, MCScriptDefinition *p_handler)
294+
{
295+
return MCErrorCreateAndThrow(kMCScriptCannotCallContextHandlerErrorTypeInfo, "module", p_module -> name, "handler", MCScriptGetNameOfDefinitionInModule(p_module, p_handler), nil);
296+
}
297+
288298
///////////
289299

290300
MCScriptVariableDefinition *MCScriptDefinitionAsVariable(MCScriptDefinition *self)
@@ -464,6 +474,11 @@ static bool MCScriptCallHandlerOfInstanceDirect(MCScriptInstanceRef self, MCScri
464474
MCTypeInfoRef t_signature;
465475
t_signature = self -> module -> types[p_handler -> type] -> typeinfo;
466476

477+
// If the handler is of context scope, then we cannot call it directly - only
478+
// from a LCB frame.
479+
if (p_handler -> scope == kMCScriptHandlerScopeContext)
480+
return MCScriptThrowCannotCallContextHandlerError(self -> module, p_handler);
481+
467482
// Check the number of arguments.
468483
uindex_t t_required_param_count;
469484
t_required_param_count = MCHandlerTypeInfoGetParameterCount(t_signature);
@@ -526,6 +541,12 @@ bool MCScriptCallHandlerOfInstanceIfFound(MCScriptInstanceRef self, MCNameRef p_
526541

527542
////////////////////////////////////////////////////////////////////////////////
528543

544+
struct MCScriptFrameContext
545+
{
546+
uindex_t count;
547+
MCValueRef slots[1];
548+
};
549+
529550
// This structure is a single frame on the execution stack.
530551
struct MCScriptFrame
531552
{
@@ -546,6 +567,9 @@ struct MCScriptFrame
546567
// <locals>
547568
// <registers>
548569
MCValueRef *slots;
570+
571+
// The context slots for the current handler invocation (if initialized)
572+
MCScriptFrameContext *context;
549573

550574
// The result register in the caller.
551575
uindex_t result;
@@ -2155,7 +2179,31 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan
21552179

21562180
if (t_success)
21572181
t_success = MCScriptCheckedStoreToRegisterInFrame(t_frame, t_dst, t_value);
2182+
}
2183+
else if (t_definition -> kind == kMCScriptDefinitionKindContextVariable)
2184+
{
2185+
MCScriptContextVariableDefinition *t_var_definition;
2186+
t_var_definition = static_cast<MCScriptContextVariableDefinition *>(t_definition);
2187+
2188+
// If we are a normal handler we use the current frame.
2189+
// If we are context handler, we use the caller's frame.
2190+
MCScriptFrame *t_target_frame;
2191+
if (t_frame -> handler -> scope == kMCScriptHandlerScopeNormal)
2192+
t_target_frame = t_frame;
2193+
else if (t_frame -> caller != nil)
2194+
t_target_frame = t_frame -> caller;
2195+
2196+
// If there is no context table, or the value of the slot at the given
2197+
// index is nil then we use the default.
2198+
MCValueRef t_value;
2199+
if (t_target_frame -> context == nil ||
2200+
t_target_frame -> context -> count < t_var_definition -> slot_index ||
2201+
t_target_frame -> context -> slots[t_var_definition -> slot_index] == nil)
2202+
t_value = t_instance -> module -> values[t_var_definition -> default_value];
2203+
else
2204+
t_value = t_target_frame -> context -> slots[t_var_definition -> slot_index];
21582205

2206+
t_success = MCScriptCheckedStoreToRegisterInFrame(t_target_frame, t_dst, t_value);
21592207
}
21602208
else if (t_definition -> kind == kMCScriptDefinitionKindHandler)
21612209
{
@@ -2235,30 +2283,61 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan
22352283
MCScriptDefinition *t_definition;
22362284
MCScriptResolveDefinitionInFrame(t_frame, t_index, t_instance, t_definition);
22372285

2238-
__MCScriptAssert__(t_definition -> kind == kMCScriptDefinitionKindVariable,
2239-
"definition not a variable in store global");
2240-
2241-
MCScriptVariableDefinition *t_var_definition;
2242-
t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition);
2243-
2244-
MCTypeInfoRef t_output_type;
2245-
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2246-
22472286
MCValueRef t_value;
22482287
t_success = MCScriptCheckedFetchFromRegisterInFrame(t_frame, t_dst, t_value);
22492288

2250-
if (t_success &&
2251-
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2252-
t_success = MCScriptThrowInvalidValueForGlobalVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2253-
2254-
if (t_success)
2289+
if (t_definition -> kind == kMCScriptDefinitionKindVariable)
22552290
{
2256-
if (t_instance -> slots[t_var_definition -> slot_index] != t_value)
2291+
MCScriptVariableDefinition *t_var_definition;
2292+
t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition);
2293+
2294+
MCTypeInfoRef t_output_type;
2295+
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2296+
2297+
if (t_success &&
2298+
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2299+
t_success = MCScriptThrowInvalidValueForGlobalVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2300+
2301+
if (t_success)
2302+
MCValueAssign(t_instance -> slots[t_var_definition -> slot_index], t_value);
2303+
}
2304+
else if (t_definition -> kind == kMCScriptDefinitionKindContextVariable)
2305+
{
2306+
MCScriptContextVariableDefinition *t_var_definition;
2307+
t_var_definition = static_cast<MCScriptContextVariableDefinition *>(t_definition);
2308+
2309+
MCTypeInfoRef t_output_type;
2310+
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2311+
2312+
if (t_success &&
2313+
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2314+
t_success = MCScriptThrowInvalidValueForContextVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2315+
2316+
// If we are a normal handler we use the current frame.
2317+
// If we are context handler, we use the caller's frame.
2318+
MCScriptFrame *t_target_frame;
2319+
if (t_frame -> handler -> scope == kMCScriptHandlerScopeNormal)
2320+
t_target_frame = t_frame;
2321+
else if (t_frame -> caller != nil)
2322+
t_target_frame = t_frame -> caller;
2323+
2324+
if (t_success &&
2325+
(t_target_frame -> context == nil ||
2326+
t_target_frame -> context -> count <= t_var_definition -> slot_index))
22572327
{
2258-
MCValueRelease(t_instance -> slots[t_var_definition -> slot_index]);
2259-
t_instance -> slots[t_var_definition -> slot_index] = MCValueRetain(t_value);
2328+
// Note that MCScriptFrameContext has an implement MCValueRef
2329+
// so we don't need to adjust index to be a count.
2330+
if (MCMemoryReallocate(t_target_frame -> context, sizeof(MCScriptFrameContext) + (sizeof(MCValueRef) * t_var_definition -> slot_index), t_target_frame -> context))
2331+
t_target_frame -> context -> count = t_var_definition -> slot_index + 1;
2332+
else
2333+
t_success = false;
22602334
}
2335+
2336+
if (t_success)
2337+
MCValueAssign(t_target_frame -> context -> slots[t_var_definition -> slot_index], t_value);
22612338
}
2339+
else
2340+
MCUnreachable();
22622341
}
22632342
break;
22642343
case kMCScriptBytecodeOpAssignList:

libscript/src/script-module.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,18 @@ MC_PICKLE_BEGIN_RECORD(MCScriptVariableDefinition)
125125
MC_PICKLE_UINDEX(type)
126126
MC_PICKLE_END_RECORD()
127127

128+
MC_PICKLE_BEGIN_RECORD(MCScriptContextVariableDefinition)
129+
MC_PICKLE_UINDEX(type)
130+
MC_PICKLE_UINDEX(default_value)
131+
MC_PICKLE_END_RECORD()
132+
128133
MC_PICKLE_BEGIN_RECORD(MCScriptHandlerDefinition)
129134
MC_PICKLE_UINDEX(type)
130135
MC_PICKLE_ARRAY_OF_UINDEX(local_types, local_type_count)
131136
MC_PICKLE_ARRAY_OF_NAMEREF(local_names, local_name_count)
132137
MC_PICKLE_UINDEX(start_address)
133138
MC_PICKLE_UINDEX(finish_address)
139+
MC_PICKLE_INTENUM(MCScriptHandlerScope, scope)
134140
MC_PICKLE_END_RECORD()
135141

136142
MC_PICKLE_BEGIN_RECORD(MCScriptForeignHandlerDefinition)
@@ -167,6 +173,7 @@ MC_PICKLE_BEGIN_VARIANT(MCScriptDefinition, kind)
167173
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindEvent, MCScriptEventDefinition)
168174
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindSyntax, MCScriptSyntaxDefinition)
169175
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindDefinitionGroup, MCScriptDefinitionGroupDefinition)
176+
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindContextVariable, MCScriptContextVariableDefinition)
170177
MC_PICKLE_END_VARIANT()
171178

172179
MC_PICKLE_BEGIN_RECORD(MCScriptModule)
@@ -191,6 +198,8 @@ MC_PICKLE_END_RECORD()
191198
////////////////////////////////////////////////////////////////////////////////
192199

193200
static MCScriptModule *s_modules = nil;
201+
static MCScriptModule **s_context_slot_owners = nil;
202+
static uindex_t s_context_slot_count;
194203

195204
////////////////////////////////////////////////////////////////////////////////
196205

@@ -214,6 +223,11 @@ void MCScriptDestroyModule(MCScriptModuleRef self)
214223
MCMemoryDelete(t_def -> function_cif);
215224
}
216225

226+
// Remove ourselves from the context slot owners list.
227+
for(uindex_t i = 0; i < s_context_slot_count; i++)
228+
if (s_context_slot_owners[i] == self)
229+
s_context_slot_owners[i] = nil;
230+
217231
// Remove ourselves from the global module list.
218232
if (s_modules == self)
219233
s_modules = self -> next_module;
@@ -237,6 +251,30 @@ bool MCScriptValidateModule(MCScriptModuleRef self)
237251
t_variable = static_cast<MCScriptVariableDefinition *>(self -> definitions[i]);
238252
t_variable -> slot_index = self -> slot_count++;
239253
}
254+
else if (self -> definitions[i] -> kind == kMCScriptDefinitionKindContextVariable)
255+
{
256+
MCScriptContextVariableDefinition *t_variable;
257+
t_variable = static_cast<MCScriptContextVariableDefinition *>(self -> definitions[i]);
258+
259+
uindex_t t_index;
260+
t_index = UINDEX_MAX;
261+
for(uindex_t i = 0; i < s_context_slot_count; i++)
262+
if (s_context_slot_owners[i] == nil)
263+
{
264+
t_index = i;
265+
break;
266+
}
267+
268+
if (t_index == UINDEX_MAX)
269+
{
270+
if (!MCMemoryResizeArray(s_context_slot_count + 1, s_context_slot_owners, s_context_slot_count))
271+
return false;
272+
273+
t_index = s_context_slot_count - 1;
274+
}
275+
276+
s_context_slot_owners[t_index] = self;
277+
}
240278
else if (self -> definitions[i] -> kind == kMCScriptDefinitionKindHandler)
241279
{
242280
MCScriptHandlerDefinition *t_handler;
@@ -355,6 +393,8 @@ bool MCScriptValidateModule(MCScriptModuleRef self)
355393
t_handler -> slot_count = MCHandlerTypeInfoGetParameterCount(t_signature) + t_handler -> local_type_count + t_temporary_count;
356394
}
357395

396+
// If the module has context
397+
358398
return true;
359399
}
360400

@@ -960,6 +1000,13 @@ MCNameRef MCScriptGetNameOfGlobalVariableInModule(MCScriptModuleRef self, uindex
9601000
return kMCEmptyName;
9611001
}
9621002

1003+
MCNameRef MCScriptGetNameOfContextVariableInModule(MCScriptModuleRef self, uindex_t p_index)
1004+
{
1005+
if (self -> definition_name_count > 0)
1006+
return self -> definition_names[p_index];
1007+
return kMCEmptyName;
1008+
}
1009+
9631010
////////////////////////////////////////////////////////////////////////////////
9641011

9651012
static int s_current_indent = 0;

libscript/src/script-object.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ MCTypeInfoRef kMCScriptNoMatchingHandlerErrorTypeInfo;
3636
MCTypeInfoRef kMCScriptCannotSetReadOnlyPropertyErrorTypeInfo;
3737
MCTypeInfoRef kMCScriptInvalidPropertyValueErrorTypeInfo;
3838
MCTypeInfoRef kMCScriptNotAHandlerValueErrorTypeInfo;
39+
MCTypeInfoRef kMCScriptCannotCallContextHandlerErrorTypeInfo;
3940

4041
////////////////////////////////////////////////////////////////////////////////
4142

@@ -268,6 +269,7 @@ bool MCScriptInitialize(void)
268269
MCScriptCreateNamedErrorType(MCNAME("livecode.lang.CannotSetReadOnlyPropertyError"), MCSTR("Cannot set read-only property %{module}.%{property}"), kMCScriptCannotSetReadOnlyPropertyErrorTypeInfo);
269270
MCScriptCreateNamedErrorType(MCNAME("livecode.lang.PropertyValueTypeError"), MCSTR("Value is not of correct type for setting property - expected type %{type} for setting property %{module}.%{property}"), kMCScriptInvalidPropertyValueErrorTypeInfo);
270271
MCScriptCreateNamedErrorType(MCNAME("livecode.lang.NotAHandlerValueError"), MCSTR("Value is not a handler"), kMCScriptNotAHandlerValueErrorTypeInfo);
272+
MCScriptCreateNamedErrorType(MCNAME("livecode.lang.CannotCallContextHandlerError"), MCSTR("Cannot call context handler"), kMCScriptCannotCallContextHandlerErrorTypeInfo);
271273
}
272274

273275
return true;

0 commit comments

Comments
 (0)