Skip to content

Commit eecc1f3

Browse files
committed
add more eval tests and comments; undo change that caused failing tests
1 parent 0a9a3cb commit eecc1f3

6 files changed

Lines changed: 82 additions & 12 deletions

File tree

pymake/pymake.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,10 +370,10 @@ def _is_recipe_comment(tok):
370370
except Exception as err:
371371
# My code crashed. For shame!
372372
logger.exception(err)
373-
logger.error("INTERNAL ERROR eval exception during token makefile=\"\"\"\n%s\n\"\"\"", statement.makefile())
374-
logger.error("INTERNAL ERROR eval exception during token string=%s", str(statement))
373+
logger.error("INTERNAL ERROR exception during token makefile=\"\"\"\n%s\n\"\"\"", statement.makefile())
374+
logger.error("INTERNAL ERROR exception during token string=%s", str(statement))
375375
filename,pos = statement.get_pos()
376-
logger.error("eval failed statement=%r file=%s pos=%s", statement, filename, pos)
376+
logger.error("execute failed pos=%r file=%s statement=%r", pos, filename, statement)
377377
exit_code = 1
378378

379379
# leave early on error
@@ -580,7 +580,20 @@ def execute(makefile, args):
580580
# Basically, we have context sensitive evaluation.
581581
curr_rules = []
582582

583-
# XXX experimental for handling $(eval)
583+
# For handling $(eval) This is not my proudest moment. I originally
584+
# designed my make function implementations to be truly functional (no side
585+
# effects). My plan was for $(eval) to return a string of Make code that
586+
# would be re-interpretted. But now I'm deep enough into implementation to
587+
# understand that won't work. The $(eval) function is entirely a side
588+
# effect. The $(eval) function can add rules, execute other functions,
589+
# anything. And the $(eval) has to happen exactly in the place where it's
590+
# called.
591+
# $(info $(eval foo:bar)) # add a rule; $(info) would consume the string
592+
# if I simply returned "foo:bar" from $(eval)
593+
#
594+
# I need a way to send down the current state of the make (specifically,
595+
# rules). The symbol table is the only argument passed between make
596+
# functions.
584597
symtable.curr_rules = curr_rules
585598
symtable.rulesdb = rulesdb
586599

pymake/symbol.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,11 +381,25 @@ def eval(self, symbol_table):
381381
# pyfiles := $(wildcard foo*.py) $(wildcard bar*.py) $(wildcard baz*.py)
382382
assert len(self.token_list) == 3
383383

384-
lhs = self.token_list[0]
385-
assign_op = self.token_list[1]
386-
rhs = self.token_list[2]
384+
return self.assign(self.lhs, self.assign_op, self.rhs, symbol_table, self.modifier_flags)
385+
386+
@property
387+
def lhs(self):
388+
# convenience method to get the LHS (left hand side)
389+
assert isinstance(self.token_list[0], Expression), type(self.token_list[0])
390+
return self.token_list[0]
387391

388-
return self.assign(lhs, assign_op, rhs, symbol_table, self.modifier_flags)
392+
@property
393+
def assign_op(self):
394+
# convenience method to get the assignment operator
395+
assert isinstance(self.token_list[1], AssignOp), type(self.token_list[1])
396+
return self.token_list[1]
397+
398+
@property
399+
def rhs(self):
400+
# convenience method to get the RHS (right hand side)
401+
assert isinstance(self.token_list[2], Expression), type(self.token_list[2])
402+
return self.token_list[2]
389403

390404
def sanity(self):
391405
# AssignmentExpression := Expression AssignOp Expression

tests/eval.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Copyright (C) 2024-2025 David Poole david.poole@ericsson.com
3+
#
14
# test the eval function
25

36
$(eval FOO:=foo)

tests/test_define.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,13 +227,14 @@ def test_nested_define():
227227
with pytest.raises(StopIteration):
228228
s = next(vline_iter)
229229

230+
@pytest.mark.skip(reason="spaces handling in multi-line shell assign is broken")
230231
def test_shell_define():
231232
makefile = """
232233
define shell_example !=
233234
echo foo
234235
echo bar
235236
endef
236-
$(info $(shell_example))
237+
$(info >>$(shell_example)<<)
237238
@:;@:
238239
"""
239240
s1 = run.gnumake_string(makefile)

tests/test_eval.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,49 @@
11
# SPDX-License-Identifier: GPL-2.0
2-
# Copyright (C) 2024 David Poole david.poole@ericsson.com
2+
# Copyright (C) 2024-2025 David Poole david.poole@ericsson.com
33
#
44
# test the $(eval) function
55

6+
import run
67

78
def test1():
8-
pass
9+
makefile="""
10+
$(eval FOO:=foo)
11+
ifndef FOO
12+
$(error FOO is missing
13+
endif
14+
ifneq ($(FOO),foo)
15+
$(error FOO is wrong)
16+
endif
17+
@:;@:
18+
"""
19+
run.simple_test(makefile)
920

21+
def test_rule():
22+
makefile="""
23+
$(eval @:;@:)
24+
"""
25+
run.simple_test(makefile)
1026

27+
def test_two_eval():
28+
makefile="""
29+
$(eval BAR:=bar)
30+
$(eval FOO:=$(BAR))
31+
ifndef FOO
32+
$(error FOO is missing)
33+
endif
34+
ifneq ($(FOO),bar)
35+
$(error foo is wrong)
36+
endif
37+
@:;@:
38+
"""
39+
run.simple_test(makefile)
40+
41+
def test_eval_return():
42+
makefile="""
43+
$(info >>$(eval FOO:=foo)<<)
44+
ifneq ($(FOO),foo)
45+
$(error foo is wrong)
46+
endif
47+
@:;@:
48+
"""
49+
run.simple_test(makefile)

tests/test_makefile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def _run_pymake(infilename):
9393
# "file.mk",
9494
"call.mk",
9595
# "value.mk", # FIXME my .makefile() surrounds single letter varrefs with () even if not in the original
96-
# "eval.mk",
96+
"eval.mk",
9797
# "origin.mk",
9898
# "flavor.mk",
9999
# "shell.mk",

0 commit comments

Comments
 (0)