Skip to content

Commit 68a1913

Browse files
committed
[[ LCB ]] Added trial support for context variables.
A context variable is a module-scope variable which notionally resets to its default value on every new script frame. To declare a context variable use: context variable zFoo [ as FooType ] default DefaultValue The current implementation uses one flat vector for all context variables meaning they should be used sparingly. Each frame can have a list of context slots, but these are only initialized when a context variable is mutated in the context of the frame.
1 parent 9615af9 commit 68a1913

12 files changed

Lines changed: 224 additions & 21 deletions

File tree

libscript/include/script.h

Lines changed: 2 additions & 0 deletions
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
};
@@ -302,6 +303,7 @@ void MCScriptAddDefinitionToModule(MCScriptModuleBuilderRef builder, uindex_t& r
302303
void MCScriptAddTypeToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index);
303304
void MCScriptAddConstantToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t const_idx, uindex_t index);
304305
void MCScriptAddVariableToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index);
306+
void MCScriptAddContextVariableToModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t index, uindex_t def_index);
305307

306308
void MCScriptBeginHandlerInModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t signature, uindex_t index);
307309
void MCScriptAddParameterToHandlerInModule(MCScriptModuleBuilderRef builder, MCNameRef name, uindex_t type, uindex_t& r_index);

libscript/src/script-builder.cpp

Lines changed: 23 additions & 0 deletions
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)

libscript/src/script-instance.cpp

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

221+
bool MCScriptThrowInvalidValueForContextVariableError(MCScriptModuleRef p_module, uindex_t p_index, MCTypeInfoRef p_expected_type, MCValueRef p_value)
222+
{
223+
return MCErrorCreateAndThrow(kMCScriptInvalidVariableValueErrorTypeInfo, "module", p_module -> name, "variable", MCScriptGetNameOfContextVariableInModule(p_module, p_index), "type", MCNamedTypeInfoGetName(p_expected_type), "value", p_value, nil);
224+
}
225+
221226
bool MCScriptThrowNotABooleanError(MCValueRef p_value)
222227
{
223228
return MCErrorCreateAndThrow(kMCScriptNotABooleanValueErrorTypeInfo, "value", p_value, nil);
@@ -522,6 +527,12 @@ bool MCScriptCallHandlerOfInstanceIfFound(MCScriptInstanceRef self, MCNameRef p_
522527

523528
////////////////////////////////////////////////////////////////////////////////
524529

530+
struct MCScriptFrameContext
531+
{
532+
uindex_t count;
533+
MCValueRef slots[1];
534+
};
535+
525536
// This structure is a single frame on the execution stack.
526537
struct MCScriptFrame
527538
{
@@ -542,6 +553,9 @@ struct MCScriptFrame
542553
// <locals>
543554
// <registers>
544555
MCValueRef *slots;
556+
557+
// The context slots for the current handler invocation (if initialized)
558+
MCScriptFrameContext *context;
545559

546560
// The result register in the caller.
547561
uindex_t result;
@@ -2151,7 +2165,23 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan
21512165

21522166
if (t_success)
21532167
t_success = MCScriptCheckedStoreToRegisterInFrame(t_frame, t_dst, t_value);
2168+
}
2169+
else if (t_definition -> kind == kMCScriptDefinitionKindContextVariable)
2170+
{
2171+
MCScriptContextVariableDefinition *t_var_definition;
2172+
t_var_definition = static_cast<MCScriptContextVariableDefinition *>(t_definition);
21542173

2174+
// If there is no context table, or the value of the slot at the given
2175+
// index is nil then we use the default.
2176+
MCValueRef t_value;
2177+
if (t_frame -> context == nil ||
2178+
t_frame -> context -> count < t_var_definition -> slot_index ||
2179+
t_frame -> context -> slots[t_var_definition -> slot_index] == nil)
2180+
t_value = kMCFalse; // t_instance -> module -> values[t_var_definition -> default_value];
2181+
else
2182+
t_value = t_frame -> context -> slots[t_var_definition -> slot_index];
2183+
2184+
t_success = MCScriptCheckedStoreToRegisterInFrame(t_frame, t_dst, t_value);
21552185
}
21562186
else if (t_definition -> kind == kMCScriptDefinitionKindHandler)
21572187
{
@@ -2231,30 +2261,53 @@ bool MCScriptCallHandlerOfInstanceInternal(MCScriptInstanceRef self, MCScriptHan
22312261
MCScriptDefinition *t_definition;
22322262
MCScriptResolveDefinitionInFrame(t_frame, t_index, t_instance, t_definition);
22332263

2234-
__MCScriptAssert__(t_definition -> kind == kMCScriptDefinitionKindVariable,
2235-
"definition not a variable in store global");
2236-
2237-
MCScriptVariableDefinition *t_var_definition;
2238-
t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition);
2239-
2240-
MCTypeInfoRef t_output_type;
2241-
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2242-
22432264
MCValueRef t_value;
22442265
t_success = MCScriptCheckedFetchFromRegisterInFrame(t_frame, t_dst, t_value);
22452266

2246-
if (t_success &&
2247-
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2248-
t_success = MCScriptThrowInvalidValueForGlobalVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2249-
2250-
if (t_success)
2267+
if (t_definition -> kind == kMCScriptDefinitionKindVariable)
2268+
{
2269+
MCScriptVariableDefinition *t_var_definition;
2270+
t_var_definition = static_cast<MCScriptVariableDefinition *>(t_definition);
2271+
2272+
MCTypeInfoRef t_output_type;
2273+
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2274+
2275+
if (t_success &&
2276+
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2277+
t_success = MCScriptThrowInvalidValueForGlobalVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2278+
2279+
if (t_success)
2280+
MCValueAssign(t_instance -> slots[t_var_definition -> slot_index], t_value);
2281+
}
2282+
else if (t_definition -> kind == kMCScriptDefinitionKindContextVariable)
22512283
{
2252-
if (t_instance -> slots[t_var_definition -> slot_index] != t_value)
2284+
MCScriptContextVariableDefinition *t_var_definition;
2285+
t_var_definition = static_cast<MCScriptContextVariableDefinition *>(t_definition);
2286+
2287+
MCTypeInfoRef t_output_type;
2288+
t_output_type = t_instance -> module -> types[t_var_definition -> type] -> typeinfo;
2289+
2290+
if (t_success &&
2291+
!MCTypeInfoConforms(MCValueGetTypeInfo(t_value), t_output_type))
2292+
t_success = MCScriptThrowInvalidValueForContextVariableError(t_frame -> instance -> module, t_index, t_output_type, t_value);
2293+
2294+
if (t_success &&
2295+
(t_frame -> context == nil ||
2296+
t_frame -> context -> count <= t_var_definition -> slot_index))
22532297
{
2254-
MCValueRelease(t_instance -> slots[t_var_definition -> slot_index]);
2255-
t_instance -> slots[t_var_definition -> slot_index] = MCValueRetain(t_value);
2298+
// Note that MCScriptFrameContext has an implement MCValueRef
2299+
// so we don't need to adjust index to be a count.
2300+
if (MCMemoryReallocate(t_frame -> context, sizeof(MCScriptFrameContext) + (sizeof(MCValueRef) * t_var_definition -> slot_index), t_frame -> context))
2301+
t_frame -> context -> count = t_var_definition -> slot_index + 1;
2302+
else
2303+
t_success = false;
22562304
}
2305+
2306+
if (t_success)
2307+
MCValueAssign(t_frame -> context -> slots[t_var_definition -> slot_index], t_value);
22572308
}
2309+
else
2310+
MCUnreachable();
22582311
}
22592312
break;
22602313
case kMCScriptBytecodeOpAssignList:

libscript/src/script-module.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ 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)
@@ -167,6 +172,7 @@ MC_PICKLE_BEGIN_VARIANT(MCScriptDefinition, kind)
167172
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindEvent, MCScriptEventDefinition)
168173
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindSyntax, MCScriptSyntaxDefinition)
169174
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindDefinitionGroup, MCScriptDefinitionGroupDefinition)
175+
MC_PICKLE_VARIANT_CASE(kMCScriptDefinitionKindContextVariable, MCScriptContextVariableDefinition)
170176
MC_PICKLE_END_VARIANT()
171177

172178
MC_PICKLE_BEGIN_RECORD(MCScriptModule)
@@ -191,6 +197,8 @@ MC_PICKLE_END_RECORD()
191197
////////////////////////////////////////////////////////////////////////////////
192198

193199
static MCScriptModule *s_modules = nil;
200+
static MCScriptModule **s_context_slot_owners = nil;
201+
static uindex_t s_context_slot_count;
194202

195203
////////////////////////////////////////////////////////////////////////////////
196204

@@ -214,6 +222,11 @@ void MCScriptDestroyModule(MCScriptModuleRef self)
214222
MCMemoryDelete(t_def -> function_cif);
215223
}
216224

225+
// Remove ourselves from the context slot owners list.
226+
for(uindex_t i = 0; i < s_context_slot_count; i++)
227+
if (s_context_slot_owners[i] == self)
228+
s_context_slot_owners[i] = nil;
229+
217230
// Remove ourselves from the global module list.
218231
if (s_modules == self)
219232
s_modules = self -> next_module;
@@ -237,6 +250,30 @@ bool MCScriptValidateModule(MCScriptModuleRef self)
237250
t_variable = static_cast<MCScriptVariableDefinition *>(self -> definitions[i]);
238251
t_variable -> slot_index = self -> slot_count++;
239252
}
253+
else if (self -> definitions[i] -> kind == kMCScriptDefinitionKindContextVariable)
254+
{
255+
MCScriptContextVariableDefinition *t_variable;
256+
t_variable = static_cast<MCScriptContextVariableDefinition *>(self -> definitions[i]);
257+
258+
uindex_t t_index;
259+
t_index = UINDEX_MAX;
260+
for(uindex_t i = 0; i < s_context_slot_count; i++)
261+
if (s_context_slot_owners[i] == nil)
262+
{
263+
t_index = i;
264+
break;
265+
}
266+
267+
if (t_index == UINDEX_MAX)
268+
{
269+
if (!MCMemoryResizeArray(s_context_slot_count + 1, s_context_slot_owners, s_context_slot_count))
270+
return false;
271+
272+
t_index = s_context_slot_count - 1;
273+
}
274+
275+
s_context_slot_owners[t_index] = self;
276+
}
240277
else if (self -> definitions[i] -> kind == kMCScriptDefinitionKindHandler)
241278
{
242279
MCScriptHandlerDefinition *t_handler;
@@ -355,6 +392,8 @@ bool MCScriptValidateModule(MCScriptModuleRef self)
355392
t_handler -> slot_count = MCHandlerTypeInfoGetParameterCount(t_signature) + t_handler -> local_type_count + t_temporary_count;
356393
}
357394

395+
// If the module has context
396+
358397
return true;
359398
}
360399

@@ -957,6 +996,13 @@ MCNameRef MCScriptGetNameOfGlobalVariableInModule(MCScriptModuleRef self, uindex
957996
return kMCEmptyName;
958997
}
959998

999+
MCNameRef MCScriptGetNameOfContextVariableInModule(MCScriptModuleRef self, uindex_t p_index)
1000+
{
1001+
if (self -> definition_name_count > 0)
1002+
return self -> definition_names[p_index];
1003+
return kMCEmptyName;
1004+
}
1005+
9601006
////////////////////////////////////////////////////////////////////////////////
9611007

9621008
static int s_current_indent = 0;

libscript/src/script-private.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,15 @@ struct MCScriptVariableDefinition: public MCScriptDefinition
251251
uindex_t slot_index;
252252
};
253253

254+
struct MCScriptContextVariableDefinition: public MCScriptDefinition
255+
{
256+
uindex_t type;
257+
uindex_t default_value;
258+
259+
// (compute) The index of the variable in the context slot table - not pickled
260+
uindex_t slot_index;
261+
};
262+
254263
struct MCScriptCommonHandlerDefinition: public MCScriptDefinition
255264
{
256265
uindex_t type;
@@ -374,6 +383,12 @@ struct MCScriptModule: public MCScriptObject
374383
// (computed) The number of slots needed by an instance - not pickled
375384
uindex_t slot_count;
376385

386+
// (computed) The number of slots needed by this modules context - not pickled
387+
uindex_t context_slot_count;
388+
389+
// (computed) The index of this module's context info in a frame's context vector - not pickled
390+
uindex_t context_index;
391+
377392
// If this is a non-widget module, then it only has one instance - not pickled
378393
MCScriptInstanceRef shared_instance;
379394

@@ -397,6 +412,7 @@ MCNameRef MCScriptGetNameOfDefinitionInModule(MCScriptModuleRef module, MCScript
397412
MCNameRef MCScriptGetNameOfParameterInModule(MCScriptModuleRef module, MCScriptDefinition *definition, uindex_t index);
398413
MCNameRef MCScriptGetNameOfLocalVariableInModule(MCScriptModuleRef module, MCScriptDefinition *definition, uindex_t index);
399414
MCNameRef MCScriptGetNameOfGlobalVariableInModule(MCScriptModuleRef module, uindex_t index);
415+
MCNameRef MCScriptGetNameOfContextVariableInModule(MCScriptModuleRef module, uindex_t index);
400416

401417
////////////////////////////////////////////////////////////////////////////////
402418

toolchain/lc-compile/src/bind.g

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@
113113
'rule' DeclareImportedDefinitions(variable(Position, _, Name, _)):
114114
DeclareId(Name)
115115

116+
'rule' DeclareImportedDefinitions(contextvariable(Position, _, Name, _, _)):
117+
DeclareId(Name)
118+
116119
'rule' DeclareImportedDefinitions(handler(Position, _, Name, _, _, _)):
117120
DeclareId(Name)
118121

@@ -172,6 +175,9 @@
172175
'rule' Declare(variable(Position, _, Name, _)):
173176
DeclareId(Name)
174177
178+
'rule' Declare(contextvariable(Position, _, Name, _, _)):
179+
DeclareId(Name)
180+
175181
'rule' Declare(handler(Position, _, Name, _, _, _)):
176182
DeclareId(Name)
177183
@@ -241,6 +247,9 @@
241247
242248
'rule' Define(ModuleId, variable(Position, Access, Name, Type)):
243249
DefineSymbolId(Name, ModuleId, Access, variable, Type)
250+
251+
'rule' Define(ModuleId, contextvariable(Position, Access, Name, Type, _)):
252+
DefineSymbolId(Name, ModuleId, Access, context, Type)
244253
245254
'rule' Define(ModuleId, handler(Position, Access, Name, Signature:signature(Parameters, _), _, _)):
246255
DefineSymbolId(Name, ModuleId, Access, handler, handler(Position, Signature))
@@ -697,6 +706,9 @@
697706
'rule' DumpBindings(DEFINITION'variable(_, _, Name, Type)):
698707
DumpId("variable", Name)
699708
DumpBindings(Type)
709+
'rule' DumpBindings(DEFINITION'contextvariable(_, _, Name, Type, _)):
710+
DumpId("variable", Name)
711+
DumpBindings(Type)
700712
'rule' DumpBindings(DEFINITION'handler(_, _, Name, Signature, Definitions, Body)):
701713
DumpId("handler", Name)
702714
DumpBindings(Signature)

toolchain/lc-compile/src/check.g

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@
207207
'rule' CheckBindingIsVariableId(Id):
208208
QueryKindOfSymbolId(Id -> local)
209209
210+
'rule' CheckBindingIsVariableId(Id):
211+
QueryKindOfSymbolId(Id -> context)
212+
210213
'rule' CheckBindingIsVariableId(Id):
211214
Id'Name -> Name
212215
Id'Position -> Position
@@ -229,6 +232,9 @@
229232
'rule' CheckBindingIsVariableOrHandlerId(Id):
230233
QueryKindOfSymbolId(Id -> local)
231234

235+
'rule' CheckBindingIsVariableOrHandlerId(Id):
236+
QueryKindOfSymbolId(Id -> context)
237+
232238
'rule' CheckBindingIsVariableOrHandlerId(Id):
233239
QueryKindOfSymbolId(Id -> handler)
234240

@@ -1497,6 +1503,14 @@
14971503
--Error_VariableMustHaveHighLevelType(Position)
14981504
|)
14991505
1506+
'rule' CheckDeclaredTypes(DEFINITION'contextvariable(Position, _, _, Type, _)):
1507+
-- Variable types must be high-level
1508+
(|
1509+
IsHighLevelType(Type)
1510+
||
1511+
--Error_VariableMustHaveHighLevelType(Position)
1512+
|)
1513+
15001514
'rule' CheckDeclaredTypes(DEFINITION'foreignhandler(_, _, _, Signature, _)):
15011515
-- Foreign handler signatures can contain any type so no need to
15021516
-- check anything here.

0 commit comments

Comments
 (0)