Skip to content

Commit 60d0b3e

Browse files
committed
Feature: for token
1 parent ae36010 commit 60d0b3e

File tree

3 files changed

+93
-3
lines changed

3 files changed

+93
-3
lines changed

nml/ast/for_.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
__license__ = """
2+
NML is free software; you can redistribute it and/or modify
3+
it under the terms of the GNU General Public License as published by
4+
the Free Software Foundation; either version 2 of the License, or
5+
(at your option) any later version.
6+
7+
NML is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License along
13+
with NML; if not, write to the Free Software Foundation, Inc.,
14+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA."""
15+
16+
from nml import expression, generic, global_constants
17+
from nml.actions import action2, action2layout, action2real, real_sprite
18+
from nml.ast import base_statement
19+
20+
21+
class InArrayFor(base_statement.BaseStatement):
22+
def __init__(self, array, param, expressions, pos=None):
23+
base_statement.BaseStatement.__init__(self, "for", pos, False, False)
24+
self.array = array
25+
self.param = param
26+
self.expressions = expressions
27+
28+
29+
class For(base_statement.BaseStatementList):
30+
def __init__(self, name, param_list, layout_sprite_list, pos=None):
31+
base_statement.BaseStatement.__init__(self, "spritelayout", pos, False, False)
32+
self.initialize(name, None, len(param_list))
33+
self.param_list = param_list
34+
self.register_map = {} # Set during action generation for easier referencing
35+
self.layout_sprite_list = layout_sprite_list
36+
37+
# Do not reduce expressions here as they may contain variables
38+
# And the feature is not known yet
39+
def pre_process(self):
40+
# Check parameter names
41+
seen_names = set()
42+
for param in self.param_list:
43+
if not isinstance(param, expression.Identifier):
44+
raise generic.ScriptError("spritelayout parameter names must be identifiers.", param.pos)
45+
if param.value in seen_names:
46+
raise generic.ScriptError("Duplicate parameter name '{}' encountered.".format(param.value), param.pos)
47+
seen_names.add(param.value)
48+
# spritelayout_base_class.pre_process(self)
49+
50+
def collect_references(self):
51+
return []
52+
53+
def debug_print(self, indentation):
54+
generic.print_dbg(indentation, "Sprite layout:", self.name.value)
55+
generic.print_dbg(indentation + 2, "Parameters:")
56+
for param in self.param_list:
57+
param.debug_print(indentation + 4)
58+
generic.print_dbg(indentation + 2, "Sprites:")
59+
for layout_sprite in self.layout_sprite_list:
60+
layout_sprite.debug_print(indentation + 4)
61+
62+
def __str__(self):
63+
params = "" if not self.param_list else "({})".format(", ".join(str(x) for x in self.param_list))
64+
return "spritelayout {}{} {{\n{}\n}}\n".format(
65+
str(self.name), params, "\n".join(str(x) for x in self.layout_sprite_list)
66+
)
67+
68+
def get_action_list(self):
69+
action_list = []
70+
if self.prepare_act2_output():
71+
for feature in sorted(self.feature_set):
72+
if feature == 0x04:
73+
continue
74+
action_list.extend(action2layout.get_layout_action2s(self, feature))
75+
return action_list

nml/parser.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
disable_item,
3030
error,
3131
font,
32+
for_,
3233
general,
3334
grf,
3435
item,
@@ -145,7 +146,8 @@ def p_main_block(self, t):
145146
| engine_override
146147
| sort_vehicles
147148
| basecost
148-
| constant"""
149+
| constant
150+
| for"""
149151
t[0] = t[1]
150152

151153
#
@@ -389,7 +391,9 @@ def p_property_assignment(self, t):
389391
"""property_assignment : ID COLON expression SEMICOLON
390392
| ID COLON expression UNIT SEMICOLON
391393
| NUMBER COLON expression SEMICOLON
392-
| NUMBER COLON expression UNIT SEMICOLON"""
394+
| NUMBER COLON expression UNIT SEMICOLON
395+
| ID COLON for SEMICOLON
396+
| NUMBER COLON for SEMICOLON"""
393397
name = t[1]
394398
unit_value = None if len(t) == 5 else unit.get_unit(t[4])
395399
t[0] = item.Property(name, t[3], unit_value, t.lineno(1))
@@ -835,3 +839,12 @@ def p_tilelayout_item_prop(self, t):
835839
def p_constant(self, t):
836840
"constant : CONST expression EQ expression SEMICOLON"
837841
t[0] = constant.Constant(t[2], t[4])
842+
843+
def p_for(self, t):
844+
"""for : FOR ID LPAREN id_list RPAREN LBRACE layout_sprite_list RBRACE
845+
| LBRACKET non_empty_expression_list FOR ID IN expression RBRACKET"""
846+
if t[1] == "[" :
847+
t[0] = for_.InArrayFor(t[6], t[4], t[2], t.lineno(1))
848+
else:
849+
t[0] = for_.For(t[2], t[4], t[7])
850+

nml/tokens.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@
6161
"recolour_sprite": "RECOLOUR_SPRITE",
6262
"engine_override": "ENGINE_OVERRIDE",
6363
"sort": "SORT_VEHICLES",
64-
"const": "CONST"
64+
"const": "CONST",
65+
"for": "FOR",
66+
"in": "IN",
6567
}
6668
# fmt: on
6769

0 commit comments

Comments
 (0)