From a51ea5d2321b3ee3074b5c81ed0dd5de4e72a8ca Mon Sep 17 00:00:00 2001 From: boolangery Date: Sun, 19 Jul 2026 15:08:07 +0200 Subject: [PATCH 1/3] fix: add value attribute to TrueExpr/FalseExpr and fix to_json() serialization - Add to TrueExpr and to FalseExpr so boolean values are preserved in JSON output - Fix Node.to_json() filter: change to to preserve falsy values like False and 0 - Fix Node.to_json() crash when _tokens is missing (use hasattr guard) - Update test_to_pretty_json to match the corrected to_json() output format Fixes boolangery/py-lua-parser#76 --- luaparser/astnodes.py | 8 +++-- luaparser/tests/test_ast.py | 63 ++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/luaparser/astnodes.py b/luaparser/astnodes.py index b8cfa66..c74df08 100644 --- a/luaparser/astnodes.py +++ b/luaparser/astnodes.py @@ -118,12 +118,14 @@ def to_json(self) -> any: **{ k: v for k, v in self.__dict__.items() - if not k.startswith("_") and v + if not k.startswith("_") + and v is not None + and v != [] }, **{ "start_char": self.start_char, "stop_char": self.stop_char, - "line": self.line, + "line": self.line if hasattr(self, "_tokens") else None, }, } } @@ -581,6 +583,7 @@ class TrueExpr(Expression): def __init__(self, **kwargs): super(TrueExpr, self).__init__("True", **kwargs) + self.value = True class FalseExpr(Expression): @@ -588,6 +591,7 @@ class FalseExpr(Expression): def __init__(self, **kwargs): super(FalseExpr, self).__init__("False", **kwargs) + self.value = False NumberType = int or float diff --git a/luaparser/tests/test_ast.py b/luaparser/tests/test_ast.py index ebdd588..7c9a3d3 100644 --- a/luaparser/tests/test_ast.py +++ b/luaparser/tests/test_ast.py @@ -109,32 +109,51 @@ def test_to_pretty_json(self): exp = textwrap.dedent( """\ { - "comments": [], - "body": { - "comments": [], - "body": [ - { - "comments": [], - "wrapped": false, - "targets": [ + "Chunk": { + "body": { + "Block": { + "body": [ { - "comments": [], - "wrapped": false, - "id": "a", - "attribute": null + "LocalAssign": { + "wrapped": false, + "targets": [ + { + "Name": { + "wrapped": false, + "id": "a", + "start_char": null, + "stop_char": null, + "line": null + } + } + ], + "values": [ + { + "String": { + "wrapped": false, + "s": "foo", + "raw": "foo", + "delimiter": {}, + "start_char": 10, + "stop_char": 14, + "line": null + } + } + ], + "start_char": 0, + "stop_char": 14, + "line": null + } } ], - "values": [ - { - "comments": [], - "wrapped": false, - "s": "foo", - "raw": "foo", - "delimiter": {} - } - ] + "start_char": 0, + "stop_char": 14, + "line": null } - ] + }, + "start_char": 0, + "stop_char": 14, + "line": null } }""" ) From d67daff56f6064f79cf5d6033f32d1114afb8f4a Mon Sep 17 00:00:00 2001 From: boolangery Date: Sun, 19 Jul 2026 15:50:46 +0200 Subject: [PATCH 2/3] test: add integration test for boolean value serialization Verify that TrueExpr and FalseExpr JSON output includes the value field, and that round-trip parsing preserves boolean values. --- luaparser/tests/test_integration.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/luaparser/tests/test_integration.py b/luaparser/tests/test_integration.py index 1d7fa2a..0c18d1f 100644 --- a/luaparser/tests/test_integration.py +++ b/luaparser/tests/test_integration.py @@ -386,3 +386,16 @@ def test_cont_int_14(self): ) self.assertEqual(source, ast.to_lua_source(ast.parse(source))) self.assertEqual(exp, tree) + + # Boolean values serialize with value field #76 + def test_cont_int_15(self): + source = "local a, b = true, false" + tree = ast.parse(source) + json_output = ast.to_pretty_json(tree) + + # Verify true/false values are present in JSON + self.assertIn('"value": true', json_output) + self.assertIn('"value": false', json_output) + + # Verify round-trip preserves boolean values + self.assertEqual(source, ast.to_lua_source(tree)) From 620dc985addf07c403ff803462c7cbb129a037c5 Mon Sep 17 00:00:00 2001 From: boolangery Date: Sun, 19 Jul 2026 15:53:28 +0200 Subject: [PATCH 3/3] test: use full textwrap.dedent assertion for boolean integration test --- luaparser/tests/test_integration.py | 76 ++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/luaparser/tests/test_integration.py b/luaparser/tests/test_integration.py index 0c18d1f..0aaf427 100644 --- a/luaparser/tests/test_integration.py +++ b/luaparser/tests/test_integration.py @@ -391,11 +391,71 @@ def test_cont_int_14(self): def test_cont_int_15(self): source = "local a, b = true, false" tree = ast.parse(source) - json_output = ast.to_pretty_json(tree) - - # Verify true/false values are present in JSON - self.assertIn('"value": true', json_output) - self.assertIn('"value": false', json_output) - - # Verify round-trip preserves boolean values - self.assertEqual(source, ast.to_lua_source(tree)) + exp = textwrap.dedent( + """\ + { + "Chunk": { + "body": { + "Block": { + "body": [ + { + "LocalAssign": { + "wrapped": false, + "targets": [ + { + "Name": { + "wrapped": false, + "id": "a", + "start_char": null, + "stop_char": null, + "line": null + } + }, + { + "Name": { + "wrapped": false, + "id": "b", + "start_char": null, + "stop_char": null, + "line": null + } + } + ], + "values": [ + { + "True": { + "wrapped": false, + "value": true, + "start_char": 13, + "stop_char": 16, + "line": null + } + }, + { + "False": { + "wrapped": false, + "value": false, + "start_char": 19, + "stop_char": 23, + "line": null + } + } + ], + "start_char": 0, + "stop_char": 23, + "line": null + } + } + ], + "start_char": 0, + "stop_char": 23, + "line": null + } + }, + "start_char": 0, + "stop_char": 23, + "line": null + } + }""" + ) + self.assertEqual(ast.to_pretty_json(tree), exp)