Skip to content

Commit

Permalink
Fix: register_map must be accessed with the feature of the action, no…
Browse files Browse the repository at this point in the history
…t with the scope of the variables.
  • Loading branch information
frosch123 committed Dec 8, 2020
1 parent 6c78d7b commit bf55938
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 21 deletions.
2 changes: 1 addition & 1 deletion nml/actions/action2layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ def get_layout_action2s(spritelayout, feature, spr_pos):
actions.append(layout_action)

if temp_registers:
varact2parser = action2var.Varaction2Parser(feature)
varact2parser = action2var.Varaction2Parser(feature, feature)
for register_info in temp_registers:
reg, expr = register_info[1], register_info[2]
if reg is None:
Expand Down
4 changes: 2 additions & 2 deletions nml/actions/action2production.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def get_production_actions(produce):
action6.free_parameters.save()

result_list = []
varact2parser = action2var.Varaction2Parser(0x0A)
varact2parser = action2var.Varaction2Parser(0x0A, 0x0A)
if all(x.supported_by_actionD(False) for x in produce.param_list):
version = 0
offset = 4
Expand Down Expand Up @@ -180,7 +180,7 @@ def get_production_v2_actions(produce):
action_list = []
action6.free_parameters.save()

varact2parser = action2var.Varaction2Parser(0x0A)
varact2parser = action2var.Varaction2Parser(0x0A, 0x0A)

def resolve_cargoitem(item):
cargolabel = item.name.value
Expand Down
4 changes: 2 additions & 2 deletions nml/actions/action2random.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,11 +354,11 @@ def parse_randomswitch(random_switch):
if count_expr is None:
random_switch.set_action2(random_action2, feature)
else:
# Create intermediate varaction2
# Create intermediate varaction2 to compute parameter for type 0x84
varaction2 = action2var.Action2Var(
feature, "{}@registers".format(random_switch.name.value), random_switch.pos, 0x89
)
varact2parser = action2var.Varaction2Parser(feature)
varact2parser = action2var.Varaction2Parser(feature, feature)
varact2parser.parse_expr(count_expr)
varaction2.var_list = varact2parser.var_list
action_list.extend(varact2parser.extra_actions)
Expand Down
27 changes: 14 additions & 13 deletions nml/actions/action2var.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,8 +338,9 @@ def __init__(self, param, size, offset):


class Varaction2Parser:
def __init__(self, feature):
self.feature = feature # Depends on feature and var_range
def __init__(self, action_feature, var_feature):
self.action_feature = action_feature
self.var_feature = var_feature # Depends on action_feature and var_range
self.extra_actions = []
self.mods = []
self.var_list = []
Expand Down Expand Up @@ -437,9 +438,9 @@ def preprocess_ternaryop(self, expr):

def preprocess_storageop(self, expr):
assert isinstance(expr, expression.StorageOp)
if expr.info["perm"] and self.feature not in (0x08, 0x0A, 0x0D):
if expr.info["perm"] and self.var_feature not in (0x08, 0x0A, 0x0D):
raise generic.ScriptError(
"Persistent storage is not supported for feature '{}'".format(general.feature_name(self.feature)),
"Persistent storage is not supported for feature '{}'".format(general.feature_name(self.var_feature)),
expr.pos,
)

Expand All @@ -450,7 +451,7 @@ def preprocess_storageop(self, expr):
var_num = 0x7C if expr.info["perm"] else 0x7D
ret = expression.Variable(expression.ConstantNumeric(var_num), param=expr.register, pos=expr.pos)

if expr.info["perm"] and self.feature == 0x08:
if expr.info["perm"] and self.var_feature == 0x08:
# store grfid in register 0x100 for town persistent storage
grfid = expression.ConstantNumeric(
0xFFFFFFFF if expr.grfid is None else expression.parse_string_to_dword(expr.grfid)
Expand Down Expand Up @@ -605,10 +606,10 @@ def parse_proc_call(self, expr):
# For f(x, g(y)), x can be overwritten by y if f and g share the same param registers
# Use temporary variables as an intermediate step
store_tmp = VarAction2StoreTempVar()
tmp_vars.append((store_tmp, VarAction2StoreCallParam(target.register_map[self.feature][i])))
tmp_vars.append((store_tmp, VarAction2StoreCallParam(target.register_map[self.action_feature][i])))
else:
store_tmp = VarAction2StoreCallParam(target.register_map[self.feature][i])
self.parse_expr(reduce_varaction2_expr(param, self.feature))
store_tmp = VarAction2StoreCallParam(target.register_map[self.action_feature][i])
self.parse_expr(reduce_varaction2_expr(param, self.var_feature))
self.var_list.append(nmlop.STO_TMP)
self.var_list.append(store_tmp)
self.var_list_size += store_tmp.get_size() + 1 # Add 1 for operator
Expand Down Expand Up @@ -801,7 +802,7 @@ def create_return_action(expr, feature, name, var_range):
@rtype: C{tuple} of (C{list} of L{BaseAction}, L{SpriteGroupRef})
"""
varact2parser = Varaction2Parser(
feature if var_range == 0x89 else action2var_variables.varact2parent_scope[feature]
feature, feature if var_range == 0x89 else action2var_variables.varact2parent_scope[feature]
)
varact2parser.parse_expr(expr)

Expand Down Expand Up @@ -871,7 +872,7 @@ def get_failed_cb_result(feature, action_list, parent_action, pos):
action_list.append(act2)

# Create varaction2, to choose between returning graphics and 0, depending on CB
varact2parser = Varaction2Parser(feature)
varact2parser = Varaction2Parser(feature, feature)
varact2parser.parse_expr(
expression.Variable(expression.ConstantNumeric(0x0C), mask=expression.ConstantNumeric(0xFFFF))
)
Expand Down Expand Up @@ -930,7 +931,7 @@ def parse_sg_ref_result(result, action_list, parent_action, var_range):
var_feature = (
parent_action.feature if var_range == 0x89 else action2var_variables.varact2parent_scope[parent_action.feature]
)
varact2parser = Varaction2Parser(var_feature)
varact2parser = Varaction2Parser(parent_action.feature, var_feature)
layout = action2.resolve_spritegroup(result.name)
for i, param in enumerate(result.param_list):
if i > 0:
Expand Down Expand Up @@ -1093,14 +1094,14 @@ def parse_varaction2(switch_block):
switch_block.name.value,
switch_block.pos,
switch_block.var_range,
switch_block.register_map[get_feature(switch_block)],
switch_block.register_map[feature],
)

expr = reduce_varaction2_expr(switch_block.expr, get_feature(switch_block))

offset = 4 # first var

parser = Varaction2Parser(get_feature(switch_block))
parser = Varaction2Parser(feature, get_feature(switch_block))
parser.parse_expr(expr)
action_list.extend(parser.extra_actions)
for mod in parser.mods:
Expand Down
4 changes: 2 additions & 2 deletions nml/actions/action3.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def create_proc_call_varaction2(feature, proc, ret_value_function, pos):
@rtype: C{tuple} of (C{list} of L{BaseAction}, L{SpriteGroupRef}, C{str})
"""
proc.is_procedure = True
varact2parser = action2var.Varaction2Parser(feature)
varact2parser = action2var.Varaction2Parser(feature, feature)
varact2parser.parse_proc_call(proc)

mapping = {0xFFFF: (expression.SpriteGroupRef(expression.Identifier("CB_FAILED"), [], None), None)}
Expand Down Expand Up @@ -221,7 +221,7 @@ def create_cb_choice_varaction2(feature, expr, mapping, default, pos):
@return: A tuple containing the action list and a reference to the created action2
@rtype: C{tuple} of (C{list} of L{BaseAction}, L{SpriteGroupRef})
"""
varact2parser = action2var.Varaction2Parser(feature)
varact2parser = action2var.Varaction2Parser(feature, feature)
varact2parser.parse_expr(expr)
return create_intermediate_varaction2(feature, varact2parser, mapping, default, pos)

Expand Down
5 changes: 4 additions & 1 deletion nml/ast/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ def __init__(self, param_list, body, pos):
self.expr = param_list[-1]
self.body = body
self.param_list = param_list[3:-1]
# register_map is a dict to be duck-compatible with spritelayouts.
# But because feature_set has only one item for switches, register_map also has at most one item.
self.register_map = {}

def pre_process(self):
Expand All @@ -59,6 +61,7 @@ def pre_process(self):
raise generic.ScriptError("Duplicate parameter name '{}' encountered.".format(param.value), param.pos)
seen_names.add(param.value)

feature = next(iter(self.feature_set))
var_feature = action2var.get_feature(self) # Feature of the accessed variables

# Allocate registers
Expand All @@ -69,7 +72,7 @@ def pre_process(self):
param_registers.append(reg)
param_map[param.value] = reg
param_map = (param_map, lambda name, value, pos: action2var.VarAction2LoadCallParam(value, name))
self.register_map[var_feature] = param_registers
self.register_map[feature] = param_registers

self.expr = action2var.reduce_varaction2_expr(self.expr, var_feature, [param_map])
self.body.reduce_expressions(var_feature, [param_map])
Expand Down
34 changes: 34 additions & 0 deletions regression/036_procedure_scope.nml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
grf {
grfid: "NML\36";
name: string(STR_REGRESSION_NAME);
desc: string(STR_REGRESSION_DESC);
version: 0;
min_compatible_version: 0;
}

switch(FEAT_INDUSTRIES, SELF, dumb_add, a, b, a + b) { return; }

/* some computation that requires registers for intermediate values */
switch(FEAT_INDUSTRIES, PARENT, callee, a, (population+(has_church?500:1))*(num_houses-4*has_stadium)+a) {
0..5: return a + dumb_add(5, a);
default: return a + dumb_add(6, a);
}

switch(FEAT_INDUSTRIES, SELF, caller2, dumb_add(1,dumb_add(founder_colour2, build_date))*(water_distance+founder_colour1)*(random_bits+callee(1))*(founder_type+layout_num)*(build_type+counter)) {
return;
}

switch(FEAT_INDUSTRIES, SELF, caller1, (founder_colour2+build_date)*dumb_add(random_bits, callee(0))*(build_type+counter)) {
return;
}

item(FEAT_INDUSTRIES, coal_mine) {
property {
substitute: INDUSTRYTYPE_COAL_MINE;
override: INDUSTRYTYPE_COAL_MINE;
}
graphics {
build_prod_change: return caller1;
control_special: return caller2;
}
}
Binary file added regression/expected/036_procedure_scope.grf
Binary file not shown.
162 changes: 162 additions & 0 deletions regression/expected/036_procedure_scope.nfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Automatically generated by GRFCODEC. Do not modify!
// (Info version 32)
// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>>
// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C
// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D%
// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags

0 * 4 \d14

1 * 54 14 "C" "INFO"
"B" "VRSN" \w4 \dx00000000
"B" "MINV" \w4 \dx00000000
"B" "NPAR" \w1 00
"B" "PALS" \w1 "A"
"B" "BLTR" \w1 "8"
00
00
2 * 52 08 08 "NML\36" "NML regression test" 00 "A test newgrf testing NML" 00
// Name: dumb_add
// a : register 8A
// b : register 8B
3 * 22 02 0A FF 89
7D 8A 20 \dxFFFFFFFF // a
\2+ 7D 8B 00 \dxFFFFFFFF // b
\b0
\wx8000 // Return computed value

// Name: @return_action_0
4 * 66 02 0A FE 8A
1A 20 \dx00000005
\2sto 1A 20 \dx0000008A
\2r 7D 88 20 \dxFFFFFFFF // a
\2sto 1A 20 \dx0000008B
\2r 7E FF 20 \dxFFFFFFFF // dumb_add(5, a)
\2sto 1A 20 \dx00000089
\2r 7D 88 20 \dxFFFFFFFF // a
\2+ 7D 89 00 \dxFFFFFFFF
\b0
\wx8000 // Return computed value

// Name: @return_action_1
5 * 66 02 0A FD 8A
1A 20 \dx00000006
\2sto 1A 20 \dx0000008A
\2r 7D 88 20 \dxFFFFFFFF // a
\2sto 1A 20 \dx0000008B
\2r 7E FF 20 \dxFFFFFFFF // dumb_add(6, a)
\2sto 1A 20 \dx00000089
\2r 7D 88 20 \dxFFFFFFFF // a
\2+ 7D 89 00 \dxFFFFFFFF
\b0
\wx8000 // Return computed value

// Name: callee
// a : register 88
6 * 110 02 0A FD 8A
92 22 \dx00000001
\2* 1A 20 \dx00000004
\2sto 1A 20 \dx00000089
\2r B6 20 \dx0000FFFF
\2- 7D 89 20 \dxFFFFFFFF
\2sto 1A 20 \dx0000008A
\2r 92 21 \dx00000001
\2u< 1A 20 \dx00000001
\2* 1A 20 \dx000001F3 // expr1 - expr2
\2+ 1A 20 \dx00000001
\2+ 82 20 \dx0000FFFF
\2* 7D 8A 20 \dxFFFFFFFF
\2+ 7D 88 00 \dxFFFFFFFF // a
\b1
\wx00FE \dx00000000 \dx00000005 // 0 .. 5: return (a + dumb_add(5, a))
\wx00FD // default: return (a + dumb_add(6, a))

// Name: caller2
7 * 230 02 0A FE 89
B3 20 \dx00000003
\2+ AA 20 \dx0000FFFF
\2sto 1A 20 \dx00000080
\2r 45 30 \dx00000003
\2+ 44 20 \dx000000FF
\2sto 1A 20 \dx00000081
\2r 1A 20 \dx00000001
\2sto 1A 20 \dx00000088
\2r 7E FD 20 \dxFFFFFFFF // callee(1)
\2+ 5F 28 \dx0000FFFF
\2sto 1A 20 \dx00000082
\2r 43 20 \dxFFFFFFFF
\2+ 45 38 \dx0000000F
\2sto 1A 20 \dx00000083
\2r 1A 20 \dx00000001
\2sto 1A 20 \dx00000086
\2r 45 3C \dx0000000F
\2sto 1A 20 \dx0000008A
\2r 46 20 \dxFFFFFFFF
\2sto 1A 20 \dx0000008B
\2r 7E FF 20 \dxFFFFFFFF // dumb_add(var[0x45, 28, 15], var[0x46, 0, -1])
\2sto 1A 20 \dx00000087
\2r 1A 20 \dx00000086
\2sto 1A 20 \dx0000008A
\2r 1A 20 \dx00000087
\2sto 1A 20 \dx0000008B
\2r 7E FF 20 \dxFFFFFFFF // dumb_add(1, dumb_add(var[0x45, 28, 15], var[0x46, 0, -1]))
\2* 7D 83 20 \dxFFFFFFFF
\2* 7D 82 20 \dxFFFFFFFF
\2* 7D 81 20 \dxFFFFFFFF
\2* 7D 80 00 \dxFFFFFFFF
\b0
\wx8000 // Return computed value

// Name: caller1
8 * 143 02 0A FF 89
B3 20 \dx00000003
\2+ AA 20 \dx0000FFFF
\2sto 1A 20 \dx00000080
\2r 5F 28 \dx0000FFFF
\2sto 1A 20 \dx00000083
\2r 1A 20 \dx00000000
\2sto 1A 20 \dx00000088
\2r 7E FD 20 \dxFFFFFFFF // callee(0)
\2sto 1A 20 \dx00000084
\2r 1A 20 \dx00000083
\2sto 1A 20 \dx0000008A
\2r 1A 20 \dx00000084
\2sto 1A 20 \dx0000008B
\2r 7E FF 20 \dxFFFFFFFF // dumb_add(var[0x5F, 8, 65535], callee(0))
\2sto 1A 20 \dx00000085
\2r 45 3C \dx0000000F
\2+ 46 20 \dxFFFFFFFF
\2* 7D 85 20 \dxFFFFFFFF
\2* 7D 80 00 \dxFFFFFFFF
\b0
\wx8000 // Return computed value

9 * 11 00 0A \b2 01 FF \wx0000
08 00
09 00

10 * 11 00 0A \b2 01 FF \wx0000
21 00
22 42

// Name: @CB_FAILED_PROD
11 * 15 02 0A FD 00 \wx0000 \wx0000 \wx0000 \wx0000 \wx0000 00

// Name: @CB_FAILED0A
12 * 23 02 0A FD 89
0C 00 \dx0000FFFF
\b1
\wx8000 \dx00000000 \dx00000000 // graphics callback -> return 0
\wx00FD // Non-graphics callback, return graphics result

// Name: @action3_0
13 * 33 02 0A FD 89
0C 00 \dx0000FFFF
\b2
\wx00FE \dx0000003B \dx0000003B // caller2;
\wx00FF \dx0000015F \dx0000015F // caller1;
\wx00FD // @CB_FAILED0A;

14 * 7 03 0A 01 00 \b0
\wx00FD // @action3_0;

0 comments on commit bf55938

Please sign in to comment.