Skip to content

Commit

Permalink
Add: Translate ternary operator into varact2 if needed
Browse files Browse the repository at this point in the history
  • Loading branch information
glx22 committed Aug 27, 2022
1 parent 44ecff2 commit da20dc4
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 28 deletions.
67 changes: 58 additions & 9 deletions nml/actions/action2var.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,13 @@ def supported_by_actionD(self, raise_error):
# Class for var 7E procedure calls
class VarAction2ProcCallVar(VarAction2Var):
def __init__(self, sg_ref):
if not isinstance(action2.resolve_spritegroup(sg_ref.name), (switch.Switch, switch.RandomSwitch)):
raise generic.ScriptError("Block with name '{}' is not a valid procedure".format(sg_ref.name), sg_ref.pos)
if not sg_ref.is_procedure:
raise generic.ScriptError("Unexpected identifier encountered: '{}'".format(sg_ref.name), sg_ref.pos)
if not sg_ref.act2:
if not isinstance(action2.resolve_spritegroup(sg_ref.name), (switch.Switch, switch.RandomSwitch)):
raise generic.ScriptError(
"Block with name '{}' is not a valid procedure".format(sg_ref.name), sg_ref.pos
)
if not sg_ref.is_procedure:
raise generic.ScriptError("Unexpected identifier encountered: '{}'".format(sg_ref.name), sg_ref.pos)
VarAction2Var.__init__(self, 0x7E, 0, 0, comment=str(sg_ref))
# Reference to the called action2
self.sg_ref = sg_ref
Expand Down Expand Up @@ -406,6 +409,16 @@ def preprocess_binop(self, expr):

def preprocess_ternaryop(self, expr):
assert isinstance(expr, expression.TernaryOp)
if not expr.expr1.is_read_only() or not expr.expr2.is_read_only():
return create_ternary_action(
expr.guard,
expr.expr1,
expr.expr2,
self.extra_actions,
self.action_feature,
self.var_scope,
self.var_range,
)
guard = expression.Boolean(expr.guard).reduce()
self.parse(guard)
if isinstance(expr.expr1, expression.ConstantNumeric) and isinstance(expr.expr2, expression.ConstantNumeric):
Expand All @@ -419,10 +432,6 @@ def preprocess_ternaryop(self, expr):
self.var_list_size += 2 + diff_var.get_size()
return expr.expr2
else:
if not expr.is_read_only() and guard.is_read_only():
generic.print_warning(
generic.Warning.GENERIC, "Ternary operator may have unexpected side effects", expr.pos
)
guard_var = VarAction2StoreTempVar()
guard_var.comment = "guard"
inverted_guard_var = VarAction2StoreTempVar()
Expand Down Expand Up @@ -615,8 +624,9 @@ def parse_via_actionD(self, expr):

def parse_proc_call(self, expr):
assert isinstance(expr, expression.SpriteGroupRef)
assert not expr.param_list or not expr.act2
var_access = VarAction2ProcCallVar(expr)
target = action2.resolve_spritegroup(expr.name)
target = action2.resolve_spritegroup(expr.name) if not expr.act2 else None
refs = expr.collect_references()

# Fill param registers for the call
Expand Down Expand Up @@ -820,6 +830,45 @@ def parse_minmax(value, unit_str, action_list, act6, offset):
return_action_id = 0


def create_ternary_action(guard, expr_true, expr_false, action_list, feature, var_scope, var_range):
act6 = action6.Action6()

global return_action_id
name = "@ternary_action_{:d}".format(return_action_id)
varaction2 = Action2Var(feature, name, guard.pos, var_range)
return_action_id += 1

expr = reduce_varaction2_expr(guard, var_scope)

offset = 4 # first var

parser = Varaction2Parser(feature, var_range)
parser.parse_expr(expr)
action_list.extend(parser.extra_actions)
for mod in parser.mods:
act6.modify_bytes(mod.param, mod.size, mod.offset + offset)
varaction2.var_list = parser.var_list
offset += parser.var_list_size + 1 # +1 for the byte num-ranges
for proc in parser.proc_call_list:
action2.add_ref(proc, varaction2, True)

result, result_comment = parse_result(expr_false, action_list, act6, offset, varaction2, None, var_range)
offset += 2 # size of result
varaction2.ranges.append(
VarAction2Range(expression.ConstantNumeric(0), expression.ConstantNumeric(0), result, result_comment)
)

default, default_comment = parse_result(expr_true, action_list, act6, offset, varaction2, None, var_range)
varaction2.default_result = default
varaction2.default_comment = default_comment

if len(act6.modifications) > 0:
action_list.append(act6)

action_list.append(varaction2)
return expression.SpriteGroupRef(expression.Identifier(name), [], None, varaction2)


def create_return_action(expr, feature, name, var_range):
"""
Create a varaction2 to return the computed value
Expand Down
2 changes: 1 addition & 1 deletion regression/036_procedure_scope.nml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ switch(FEAT_INDUSTRIES, PARENT, proc_call_optimisation, population) {
return STORE_TEMP(0,0);
}

switch(FEAT_INDUSTRIES, SELF, ternary_optimisation, proc_call_optimisation() ? 1 : 0) { return 5; }
switch(FEAT_INDUSTRIES, SELF, ternary_optimisation, proc_call_optimisation() ? 1 : proc_call_optimisation()) { return 5; }

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

Expand Down
Binary file modified regression/expected/036_procedure_scope.grf
Binary file not shown.
40 changes: 22 additions & 18 deletions regression/expected/036_procedure_scope.nfo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// 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 \d17
0 * 4 \d18

1 * 54 14 "C" "INFO"
"B" "VRSN" \w4 \dx00000000
Expand All @@ -30,27 +30,31 @@
\wx8000 \dx00000000 \dx00000000 // 0 .. 0: return 0;
\wx00FF // default: return STORE_TEMP(0, 0)

// Name: @ternary_action_0
5 * 24 02 0A FF 89
7E FF 00 \dxFFFFFFFF // proc_call_optimisation
\b1
\wx00FF \dx00000000 \dx00000000 // proc_call_optimisation;
\wx8001 // return 1;

// Name: ternary_optimisation
5 * 45 02 0A FF 89
7E FF 20 \dxFFFFFFFF // proc_call_optimisation
\2u< 1A 20 \dx00000001
\2* 1A 20 \dx00000001 // expr1 - expr2
\2+ 1A 00 \dx00000000
6 * 24 02 0A FF 89
7E FF 00 \dxFFFFFFFF // @ternary_action_0
\b1
\wx8000 \dx00000001 \dx00000000 // Bogus range to avoid nvar == 0
\wx8005 // default: return 5;

// Name: dumb_add
// a : register 88
// b : register 89
6 * 22 02 0A FE 89
7 * 22 02 0A FE 89
7D 88 20 \dxFFFFFFFF // a
\2+ 7D 89 00 \dxFFFFFFFF // b
\b0
\wx8000 // Return computed value

// Name: @return_action_0
7 * 66 02 0A FD 8A
8 * 66 02 0A FD 8A
1A 20 \dx00000005
\2sto 1A 20 \dx00000088
\2r 7D 86 20 \dxFFFFFFFF // a
Expand All @@ -63,7 +67,7 @@
\wx8000 // Return computed value

// Name: @return_action_1
8 * 66 02 0A FC 8A
9 * 66 02 0A FC 8A
1A 20 \dx00000006
\2sto 1A 20 \dx00000088
\2r 7D 86 20 \dxFFFFFFFF // a
Expand All @@ -77,7 +81,7 @@

// Name: callee
// a : register 86
9 * 110 02 0A FC 8A
10 * 110 02 0A FC 8A
92 22 \dx00000001
\2* 1A 20 \dx00000004
\2sto 1A 20 \dx00000087
Expand All @@ -96,7 +100,7 @@
\wx00FC // default: return (a + dumb_add(6, a))

// Name: caller2
10 * 232 02 0A FD 89
11 * 232 02 0A FD 89
B3 20 \dx00000003
\2+ AA 20 \dx0000FFFF
\2sto 1A 20 \dx00000080
Expand Down Expand Up @@ -132,7 +136,7 @@ B3 20 \dx00000003
\wx8000 // Return computed value

// Name: caller1
11 * 145 02 0A FE 89
12 * 145 02 0A FE 89
B3 20 \dx00000003
\2+ AA 20 \dx0000FFFF
\2sto 1A 20 \dx00000080
Expand All @@ -155,33 +159,33 @@ B3 20 \dx00000003
\b0
\wx8000 // Return computed value

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

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

// Name: @CB_FAILED_PROD
14 * 15 02 0A FC 00 \wx0000 \wx0000 \wx0000 \wx0000 \wx0000 00
15 * 15 02 0A FC 00 \wx0000 \wx0000 \wx0000 \wx0000 \wx0000 00

// Name: @CB_FAILED0A
15 * 23 02 0A FC 89
16 * 23 02 0A FC 89
0C 00 \dx0000FFFF
\b1
\wx8000 \dx00000000 \dx00000000 // graphics callback -> return 0
\wx00FC // Non-graphics callback, return graphics result

// Name: @action3_0
16 * 43 02 0A FC 89
17 * 43 02 0A FC 89
0C 00 \dx0000FFFF
\b3
\wx00FF \dx00000022 \dx00000022 // ternary_optimisation;
\wx00FD \dx0000003B \dx0000003B // caller2;
\wx00FE \dx0000015F \dx0000015F // caller1;
\wx00FC // @CB_FAILED0A;

17 * 7 03 0A 01 00 \b0
18 * 7 03 0A 01 00 \b0
\wx00FC // @action3_0;

0 comments on commit da20dc4

Please sign in to comment.