mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Support for nested expressions (#616)
- Doesn't require any new opcode - temp_array is repurposed as sub-expression terminator - Accompanied by sslc update - Backwards compatible with old scripts using single-layer expressions
This commit is contained in:
@@ -757,7 +757,7 @@ end
|
||||
procedure debug_array_str_deep(variable arr, variable levels, variable prefix := false) begin
|
||||
#define _newline if (levels > 1) then s += "\n";
|
||||
#define _indent ii := 0; while (ii < levels - 1) do begin s += " "; ii++; end
|
||||
#define _value(v) (v if (levels <= 1 or not array_exists(v)) else debug_array_str_deep(v, levels - 1))
|
||||
#define _value(v) (v if (levels <= 1 or typeof(v) != VALTYPE_INT or not array_exists(v)) else debug_array_str_deep(v, levels - 1))
|
||||
variable i := 0, ii, k, v, s, len;
|
||||
len := len_array(arr);
|
||||
if (array_is_map(arr)) then begin // print assoc array
|
||||
@@ -776,7 +776,6 @@ procedure debug_array_str_deep(variable arr, variable levels, variable prefix :=
|
||||
s += "}";
|
||||
end else begin // print list
|
||||
s := ("List("+len+"): [") if prefix else "[";
|
||||
_newline
|
||||
while i < len do begin
|
||||
_newline
|
||||
v := get_array(arr, i);
|
||||
|
||||
@@ -45,7 +45,9 @@ ArrayKeysMap savedArrays;
|
||||
// auto-incremented ID
|
||||
DWORD nextArrayID = 1;
|
||||
// special array ID for array expressions, contains the ID number of the currently created array
|
||||
DWORD stackArrayId;
|
||||
DWORD expressionArrayId;
|
||||
// special stack for array expressions, contains ID numbers of the currently created arrays
|
||||
std::vector<DWORD> arrayExpressionStack;
|
||||
|
||||
static char get_all_arrays_special_key[] = "...all_arrays...";
|
||||
|
||||
@@ -429,7 +431,19 @@ DWORD CreateArray(int len, DWORD flags) {
|
||||
// var.key = sArrayElement(nextArrayID, DataType::INT);
|
||||
// savedArrays[var.key] = nextArrayID;
|
||||
//}
|
||||
stackArrayId = nextArrayID;
|
||||
if ((flags & ARRAYFLAG_EXPR_PUSH) != 0) {
|
||||
// When creating array for sub-expression, make sure to add array for base expression to stack
|
||||
// This is messy, but required to support older scripts:
|
||||
// - We must always assign expressionArrayId for one-layer expressions from older scripts to work like they did before
|
||||
// - We can't directly push first arrayID into stack b/c no way to distinguish between start of an expression and normal temp_array call
|
||||
// - Compiler will only add this flag for temp_array call generated from a sub-expression
|
||||
// - So only on this second call we know we are in expression and expressionArrayId definitely contains arrayId of the first layer
|
||||
if (arrayExpressionStack.empty() && expressionArrayId != 0) {
|
||||
arrayExpressionStack.push_back(expressionArrayId);
|
||||
}
|
||||
arrayExpressionStack.push_back(nextArrayID);
|
||||
}
|
||||
expressionArrayId = nextArrayID;
|
||||
arrays[nextArrayID] = var;
|
||||
return nextArrayID++;
|
||||
}
|
||||
@@ -757,16 +771,31 @@ void SaveArray(const ScriptValue& key, DWORD id) {
|
||||
|
||||
Should always return 0!
|
||||
*/
|
||||
long StackArray(const ScriptValue& key, const ScriptValue& val) {
|
||||
if (stackArrayId == 0 || !ArrayExists(stackArrayId)) return 0;
|
||||
void SetArrayFromExpression(const ScriptValue& key, const ScriptValue& val) {
|
||||
DWORD arrayId = !arrayExpressionStack.empty()
|
||||
? arrayExpressionStack.back()
|
||||
: expressionArrayId;
|
||||
|
||||
if (!arrays[stackArrayId].isAssoc()) { // automatically resize array to fit one new element
|
||||
size_t size = arrays[stackArrayId].val.size();
|
||||
if (size >= ARRAY_MAX_SIZE) return 0;
|
||||
if (key.rawValue() >= size) arrays[stackArrayId].val.resize(size + 1);
|
||||
if (arrayId == 0 || !ArrayExists(arrayId)) return;
|
||||
|
||||
if (!arrays[arrayId].isAssoc()) { // automatically resize array to fit one new element
|
||||
size_t size = arrays[arrayId].val.size();
|
||||
if (size >= ARRAY_MAX_SIZE) return;
|
||||
if (key.rawValue() >= size) arrays[arrayId].val.resize(size + 1);
|
||||
}
|
||||
SetArray(arrayId, key, val, false);
|
||||
}
|
||||
|
||||
void PopExpressionArray() {
|
||||
if (arrayExpressionStack.empty()) return;
|
||||
|
||||
arrayExpressionStack.pop_back();
|
||||
|
||||
// Reversing the hack from CreateArray
|
||||
if (arrayExpressionStack.size() == 1) {
|
||||
expressionArrayId = arrayExpressionStack.back();
|
||||
arrayExpressionStack.pop_back();
|
||||
}
|
||||
SetArray(stackArrayId, key, val, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sArrayVar* GetRawArray(DWORD id) {
|
||||
|
||||
@@ -109,6 +109,8 @@ struct sArrayVarOld
|
||||
#define ARRAYFLAG_ASSOC (1) // is map
|
||||
#define ARRAYFLAG_CONSTVAL (2) // don't update value of key if the key exists in map
|
||||
#define ARRAYFLAG_RESERVED (4)
|
||||
#define ARRAYFLAG_EXPR_PUSH (32) // is created as part of array sub-expression
|
||||
#define ARRAYFLAG_EXPR_POP (64) // is used to indicate end of array sub-expression, not used in actual array
|
||||
|
||||
typedef std::unordered_map<sArrayElement, DWORD, sArrayElement_HashFunc, sArrayElement_EqualFunc> ArrayKeysMap;
|
||||
|
||||
@@ -224,8 +226,11 @@ DWORD LoadArray(const ScriptValue& key);
|
||||
// make array saved into the savegame with associated key
|
||||
void SaveArray(const ScriptValue& key, DWORD id);
|
||||
|
||||
// special function that powers array expressions
|
||||
long StackArray(const ScriptValue& key, const ScriptValue& val);
|
||||
// sets array element from array expression
|
||||
void SetArrayFromExpression(const ScriptValue& key, const ScriptValue& val);
|
||||
|
||||
// used to indicate the end of array sub-expression
|
||||
void PopExpressionArray();
|
||||
|
||||
sArrayVar* GetRawArray(DWORD id);
|
||||
|
||||
|
||||
@@ -90,7 +90,15 @@ void op_resize_array(OpcodeContext& ctx) {
|
||||
}
|
||||
|
||||
void op_temp_array(OpcodeContext& ctx) {
|
||||
auto arrayId = CreateTempArray(ctx.arg(0).rawValue(), ctx.arg(1).rawValue());
|
||||
const auto& flags = ctx.arg(1);
|
||||
|
||||
// Special case for array sub-expressions.
|
||||
if ((flags.rawValue() & ARRAYFLAG_EXPR_POP) != 0) {
|
||||
PopExpressionArray();
|
||||
ctx.setReturn(0);
|
||||
return;
|
||||
}
|
||||
auto arrayId = CreateTempArray(ctx.arg(0).rawValue(), flags.rawValue());
|
||||
ctx.setReturn(arrayId);
|
||||
}
|
||||
|
||||
@@ -120,10 +128,9 @@ void op_get_array_key(OpcodeContext& ctx) {
|
||||
);
|
||||
}
|
||||
|
||||
void op_stack_array(OpcodeContext& ctx) {
|
||||
ctx.setReturn(
|
||||
StackArray(ctx.arg(0), ctx.arg(1))
|
||||
);
|
||||
void op_arrayexpr(OpcodeContext& ctx) {
|
||||
SetArrayFromExpression(ctx.arg(0), ctx.arg(1));
|
||||
ctx.setReturn(0);
|
||||
}
|
||||
|
||||
// object LISTS
|
||||
|
||||
@@ -51,7 +51,7 @@ void op_load_array(OpcodeContext&);
|
||||
|
||||
void op_get_array_key(OpcodeContext&);
|
||||
|
||||
void op_stack_array(OpcodeContext&);
|
||||
void op_arrayexpr(OpcodeContext&);
|
||||
|
||||
void op_list_begin(OpcodeContext&);
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
|
||||
{0x254, "save_array", op_save_array, 2, false, 0, {ARG_ANY, ARG_OBJECT}},
|
||||
{0x255, "load_array", op_load_array, 1, true, -1, {ARG_INTSTR}},
|
||||
{0x256, "array_key", op_get_array_key, 2, true, 0, {ARG_INT, ARG_INT}},
|
||||
{0x257, "arrayexpr", op_stack_array, 2, true},
|
||||
{0x257, "arrayexpr", op_arrayexpr, 2, true},
|
||||
// 0x258 // RESERVED for arrays
|
||||
// 0x259 // RESERVED for arrays
|
||||
{0x25a, "reg_anim_destroy", op_reg_anim_destroy, 1, false, 0, {ARG_OBJECT}},
|
||||
|
||||
Reference in New Issue
Block a user