Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions nml/ast/for_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
__license__ = """
NML is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

NML is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with NML; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."""

from nml.ast import base_statement
from nml.expression.array import Array


class InArrayFor(base_statement.BaseStatement):
def __init__(self, array, param, expressions, pos=None):
base_statement.BaseStatement.__init__(self, "for", pos, False, False)
self.array = array
self.param = param
self.expressions = expressions

def __str__(self):
expressions_string = ""
for expression in self.expressions:
expressions_string += str(expression) + ", "
expressions_string = expressions_string[:-2]
return "[{} for {} in {}]".format(
expressions_string,
self.param,
self.array,
)

def reduce(self, id_dicts=None, unknown_id_fatal=True):
self.array = self.array.reduce(id_dicts, unknown_id_fatal)
out_list = []
for value in self.array.values:
param_tuple = ({self.param.value: value}, lambda name, x, pos: x)
id_dicts.append(param_tuple)
for expression in self.expressions:
out_list.append(expression.reduce(id_dicts, unknown_id_fatal))
id_dicts.remove(param_tuple)
return Array(out_list, self.pos)
8 changes: 8 additions & 0 deletions nml/expression/binop.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."""

from nml import generic, nmlop
from . import Array

from .base_expression import ConstantFloat, ConstantNumeric, Expression
from .boolean import Boolean
Expand Down Expand Up @@ -71,6 +72,7 @@ def reduce(self, id_dicts=None, unknown_id_fatal=True):
# - If both subexpressions are constant, compute the result and return it.
# - If the operator allows it and the second expression is more complex than
# the first one swap them.
# - If first subexpression is an array, compute the result and return it.
# - If the operation is a no-op, delete it.
# - Variables (as used in action2var) can have some computations attached to
# them, do that if possible.
Expand Down Expand Up @@ -116,6 +118,12 @@ def reduce(self, id_dicts=None, unknown_id_fatal=True):
elif op == nmlop.CMP_GT:
op = nmlop.CMP_LT

if isinstance(expr1, Array) and isinstance(expr2, ConstantNumeric) and self.op == nmlop.MUL:
return Array(self.op.compiletime_func(expr1.values, expr2.value), self.pos)

if isinstance(expr1, Array) and isinstance(expr2, Array) and self.op == nmlop.ADD:
return Array(self.op.compiletime_func(expr1.values, expr2.values), self.pos)

# - If the operation is a no-op, delete it.
if op == nmlop.AND and isinstance(expr2, ConstantNumeric) and (expr2.value == -1 or expr2.value == 0xFFFFFFFF):
return expr1
Expand Down
5 changes: 5 additions & 0 deletions nml/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
disable_item,
error,
font,
for_,
general,
grf,
item,
Expand Down Expand Up @@ -835,3 +836,7 @@ def p_tilelayout_item_prop(self, t):
def p_constant(self, t):
"constant : CONST expression EQ expression SEMICOLON"
t[0] = constant.Constant(t[2], t[4])

def p_in_array_for(self, t):
"""expression : LBRACKET non_empty_expression_list FOR ID IN expression RBRACKET"""
t[0] = for_.InArrayFor(t[6], t[4], t[2], t.lineno(1))
4 changes: 3 additions & 1 deletion nml/tokens.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@
"recolour_sprite": "RECOLOUR_SPRITE",
"engine_override": "ENGINE_OVERRIDE",
"sort": "SORT_VEHICLES",
"const": "CONST"
"const": "CONST",
"for": "FOR",
"in": "IN",
}
# fmt: on

Expand Down
122 changes: 122 additions & 0 deletions regression/042_for.nml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//Add action8, so we can test the vehicle in-game
grf {
grfid: "NML\42";
name: string(STR_REGRESSION_NAME);
desc: string(STR_REGRESSION_DESC);
version: 0;
min_compatible_version: 0;
}

cargotable {
COAL, LVST
}

spriteset(station_spriteset, "station.png") {
[ 1, 1, 5, 5, -2, -2]
[ 7, 1, 5, 5, -2, -2]
[ 2, 2, 3, 3, -1, -1]
[ 8, 2, 3, 3, -1, -1]
}

spritelayout station_sprite_layout_X(a) {
ground {
sprite: GROUNDSPRITE_RAIL_X;
}
building {
sprite: 0x42E;
xoffset: 0;
yoffset: 0;
zoffset: 0;
xextent: 16;
yextent: 5;
zextent: 2;
recolour_mode: RECOLOUR_REMAP;
palette: CUSTOM(0);
}
childsprite {
sprite: DEFAULT(a);
xoffset: 17;
yoffset: 11;
recolour_mode: RECOLOUR_REMAP;
palette: CUSTOM(1);
}
}

spritelayout station_sprite_layout_Y(a) {
ground {
sprite: GROUNDSPRITE_RAIL_Y;
}
building {
sprite: 0x42F;
xoffset: 0;
yoffset: 0;
zoffset: 0;
xextent: 5;
yextent: 16;
zextent: 2;
recolour_mode: RECOLOUR_REMAP;
palette: CUSTOM(2);
}
childsprite {
sprite: station_spriteset(a);
xoffset: 20;
yoffset: 11;
recolour_mode: RECOLOUR_REMAP;
palette: CUSTOM(3);
}
}

spriteset (palette_1) {
recolour_sprite {
0xC6:0xB3;0xC7:0xB4;0xC8:0xB5;0xC9:0xB6;0xCA:0xB7;0xCB:0xA4;0xCC:0xA5;0xCD:0xA6;
}
}
spriteset (palette_2) {
recolour_sprite {
0xC6:0x60;0xC7:0x61;0xC8:0x62;0xC9:0x63;0xCA:0x64;0xCB:0x65;0xCC:0x66;0xCD:0x67;
}
}
spriteset (palette_3) {
recolour_sprite {
0xC6:0xC6;0xC7:0xC7;0xC8:0xC8;0xC9:0xC9;0xCA:0xCA;0xCB:0xCB;0xCC:0xCC;0xCD:0xCD;
}
}
spriteset (palette_4) {
recolour_sprite {
0xC6:0x58;0xC7:0x59;0xC8:0x5A;0xC9:0x5B;0xCA:0x5C;0xCB:0x5D;0xCC:0x5E;0xCD:0x5F;
}
}

switch (FEAT_STATIONS, SELF, palette_switch, a, company_colour2-a) {
0 : palette_1;
1 : palette_2;
2 : palette_3;
palette_4;
}

item (FEAT_STATIONS, basic_station, 255) {
property {
class : "TEST";
classname: string(STR_STATION_TEST_CLASS);
name : string(STR_STATION_BASIC);
general_flags: bitmask(STAT_FLAG_EXTENDED_FOUNDATIONS);
cargo_random_triggers: [LVST];
disabled_platforms: bitmask(5, 6, 7, 8);
tile_flags: [a | bitmask(a) for a in [0, 1, 2, 3]];
station_layouts: [[[2]],[[a, a] for a in [4, 6]]];
}
graphics {
foundations: param[param[2]];
prepare_layout: [STORE_TEMP(0,nearby_tile_station_id(-1,2)), STORE_TEMP(1,1)];
purchase_prepare_layout: STORE_TEMP(3,3);
sprite_layouts: [
station_sprite_layout_X(a),
station_sprite_layout_Y(a) for a in [0, 1] + [2, 3]
];
custom_spritesets: [palette_switch(a) for a in [param[param[1]],5,6,10]];
anim_speed: company_colour1 + company_colour2;
LVST: station_spriteset;
COAL: station_spriteset;
station_spriteset;
}
}
Binary file added regression/expected/042_for.grf
Binary file not shown.
Loading
Loading