coco-tools 0.18__tar.gz → 0.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {coco-tools-0.18/coco_tools.egg-info → coco_tools-0.20}/PKG-INFO +71 -17
  2. coco-tools-0.18/PKG-INFO → coco_tools-0.20/README.md +58 -27
  3. {coco-tools-0.18 → coco_tools-0.20}/coco/__init__.py +1 -1
  4. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/compiler.py +16 -2
  5. coco_tools-0.20/coco/b09/configs.py +37 -0
  6. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/elements.py +70 -22
  7. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/grammar.py +15 -15
  8. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/parser.py +10 -4
  9. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/visitors.py +49 -24
  10. {coco-tools-0.18 → coco_tools-0.20}/coco/decb_to_b09.py +8 -0
  11. {coco-tools-0.18 → coco_tools-0.20}/coco/maxtoppm.py +1 -1
  12. {coco-tools-0.18 → coco_tools-0.20}/coco/resources/ecb.b09 +8 -0
  13. coco-tools-0.18/README.md → coco_tools-0.20/coco_tools.egg-info/PKG-INFO +81 -9
  14. coco_tools-0.20/coco_tools.egg-info/SOURCES.txt +67 -0
  15. {coco-tools-0.18 → coco_tools-0.20}/coco_tools.egg-info/requires.txt +2 -0
  16. coco_tools-0.20/coco_tools.egg-info/top_level.txt +5 -0
  17. coco_tools-0.20/pyproject.toml +87 -0
  18. coco_tools-0.20/tests/coco_tests/b09/__init__.py +0 -0
  19. coco_tools-0.20/tests/coco_tests/b09/test_b09.py +1465 -0
  20. coco_tools-0.20/tests/coco_tests/b09/test_configs.py +66 -0
  21. coco_tools-0.20/tests/coco_tests/b09/test_visitors.py +105 -0
  22. coco_tools-0.20/tests/coco_tests/fixtures/__init__.py +0 -0
  23. coco_tools-0.20/tests/test_error_handler.py +31 -0
  24. coco-tools-0.18/coco_tools.egg-info/SOURCES.txt +0 -31
  25. coco-tools-0.18/coco_tools.egg-info/top_level.txt +0 -1
  26. coco-tools-0.18/setup.py +0 -66
  27. {coco-tools-0.18 → coco_tools-0.20}/LICENSE +0 -0
  28. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/__init__.py +0 -0
  29. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/error_handler.py +0 -0
  30. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/procbank.py +0 -0
  31. {coco-tools-0.18 → coco_tools-0.20}/coco/b09/prog.py +0 -0
  32. {coco-tools-0.18 → coco_tools-0.20}/coco/cm3toppm.py +0 -0
  33. {coco-tools-0.18 → coco_tools-0.20}/coco/hrstoppm.py +0 -0
  34. {coco-tools-0.18 → coco_tools-0.20}/coco/mge_viewer2.py +0 -0
  35. {coco-tools-0.18 → coco_tools-0.20}/coco/mgetoppm.py +0 -0
  36. {coco-tools-0.18 → coco_tools-0.20}/coco/pixtopgm.py +0 -0
  37. {coco-tools-0.18 → coco_tools-0.20}/coco/rattoppm.py +0 -0
  38. {coco-tools-0.18 → coco_tools-0.20}/coco/resources/__init__.py +0 -0
  39. {coco-tools-0.18 → coco_tools-0.20}/coco/util.py +0 -0
  40. {coco-tools-0.18 → coco_tools-0.20}/coco/veftopng.py +0 -0
  41. {coco-tools-0.18 → coco_tools-0.20}/coco_tools.egg-info/dependency_links.txt +0 -0
  42. {coco-tools-0.18 → coco_tools-0.20}/coco_tools.egg-info/entry_points.txt +0 -0
  43. {coco-tools-0.18 → coco_tools-0.20}/setup.cfg +0 -0
@@ -1,20 +1,25 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: coco-tools
3
- Version: 0.18
3
+ Version: 0.20
4
4
  Summary: TRS-80 Color Computer Tools
5
- Home-page: https://github.com/jamieleecho/coco-tools
6
- Author: Jamie Cho
7
- Author-email: jamieleecho+coco_tools@gmail.com
8
- License: GPLv2
9
- Keywords: coco image conversion trs-80 tandy
5
+ Author-email: Jamie Cho <jamieleecho@gmail.com>
6
+ License-Expression: GPL-2.0
7
+ Project-URL: Repository, https://github.com/jamieleecho/coco-tools
8
+ Project-URL: Issues, https://github.com/jamieleecho/coco-tools/issues
9
+ Keywords: coco,image,conversion,trs-80,tandy
10
10
  Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: Intended Audience :: Developers
12
12
  Classifier: Topic :: Software Development :: Build Tools
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
15
14
  Requires-Python: >=3.9.19
16
15
  Description-Content-Type: text/markdown
17
16
  License-File: LICENSE
17
+ Requires-Dist: parsimonious>=0.10.0
18
+ Requires-Dist: Pillow>=7.0.0
19
+ Requires-Dist: pypng>=0.0.18
20
+ Requires-Dist: pydantic>=2.0.0
21
+ Requires-Dist: pydantic-yaml>=1.3.0
22
+ Dynamic: license-file
18
23
 
19
24
  # coco-tools
20
25
 
@@ -30,35 +35,63 @@ pip install coco-tools
30
35
  # To install from source
31
36
  git clone https://github.com/jamieleecho/coco-tools.git
32
37
  cd coco-tools
33
- python3 setup.py
38
+ make install-pre-commit
39
+ make install
34
40
  ```
35
41
 
42
+ The `Makefile` makes it easy to perform the most common operations:
43
+ * `make all` transpiles several exapmle ECB programs to Basic09
44
+ * `make check-all` runs linting and `uv.lock` checks
45
+ * `make check-lint` checks for linting issues
46
+ * `make check-lock` verifies the `uv.lock` is aligned to `pyproject.toml`
47
+ * `make clean` cleans the virtual environment and caches
48
+ * `make default` runs a default set of checks on the code
49
+ * `make fix-all` formats the code, fixes lint errors and runs locks `uv.lock` to `pyproject.toml`
50
+ * `make fix-format` formats the code
51
+ * `make fix-lint` fixes linting issues
52
+ * `make fix-lint-unsafe` fixes linting issues potentially adding inadvertant bugs
53
+ * `make help` outputs the different make options
54
+ * `make install` build install the distribution
55
+ * `make install-pre-commit` installs pre-commit hooks
56
+ * `make lock` locks `uv.lock` to `pyproject.toml`
57
+ * `make install-pre-commit` installs pre-commit hooks
58
+ * `make run-tests` runs the unit tests
59
+ * `make sync` syncs the python environment with `uv.lock`
60
+
61
+ `.vscode/settings.json` is set so that unit tests can be run without further configuration.
62
+
36
63
  ## Tools
37
64
 
38
65
  ### [decb-to-b09](./README.decb-to-b09.md)
39
66
 
40
67
  ```
41
- usage: decb-to-b09 [-h] [--version] [-l] [-z] [-D] [-w] program.bas program.b09
68
+ usage: decb-to-b09 [-h] [--version] [-l] [-z] [-s DEFAULT_STRING_STORAGE] [-D] [-w]
69
+ [-c CONFIG_FILE]
70
+ program.bas program.b09
42
71
 
43
72
  Convert a Color BASIC program to a BASIC09 program
44
73
  Copyright (c) 2023 by Jamie Cho
45
- Version: 0.8
74
+ Version: 0.18
46
75
 
47
76
  positional arguments:
48
77
  program.bas input DECB text program file
49
78
  program.b09 output BASIC09 text program file
50
79
 
51
- options:
80
+ optional arguments:
52
81
  -h, --help show this help message and exit
53
82
  --version show program's version number and exit
54
83
  -l, --filter-unused-linenum
55
84
  Filter out line numbers not referenced by the program
56
85
  -z, --dont-initialize-vars
57
86
  Don't pre-initialize all variables
87
+ -s DEFAULT_STRING_STORAGE, --default-string-storage DEFAULT_STRING_STORAGE
88
+ Bytes to allocate for each string
58
89
  -D, --dont-output-dependencies
59
90
  Don't output required dependencies
60
91
  -w, --dont-run-width-32
61
92
  if set don't run the default width 32
93
+ -c CONFIG_FILE, --config-file CONFIG_FILE
94
+ Optional compiler configuration file
62
95
  ```
63
96
 
64
97
  ### cm3toppm
@@ -242,18 +275,38 @@ options:
242
275
  ## Developing and Testing
243
276
 
244
277
  ```
278
+ # To set up pre-commit checks
279
+ pre-commit install
280
+
245
281
  # Build the docker image
246
- docker-compose build test
282
+ docker compose build test
247
283
 
248
284
  # Run tests using the source on the docker image
249
- docker-compose run test
285
+ docker compose run test
250
286
 
251
287
  # Run tests using the source on the host computer
252
- docker-compose run testv
288
+ docker compose run testv
253
289
 
254
- # To make changes and develop locally
290
+ # To develop locally
255
291
  pip install -r requirements.txt
256
- pre-commit install
292
+
293
+ # Run linting, build example disk images for basic conversion
294
+ make
295
+
296
+ # Remove built artifacts
297
+ make clean
298
+
299
+ # Reformats the code
300
+ make format
301
+
302
+ # Only runs linting
303
+ make lint
304
+
305
+ # Only run tests
306
+ make test
307
+
308
+ # Build basic and os-9 eample images
309
+ make basic.dsk os9boot.dsk
257
310
  ```
258
311
 
259
312
  ## Credits
@@ -263,6 +316,7 @@ The programs in the examples/decb and examples/other-decb-examples-to-try direct
263
316
  * banner.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/banner.c10
264
317
  * cadnza.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/cadnza.c10
265
318
  * cflip.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/cflip.c10
319
+ * flip.bas -- https://github.com/daftspaniel/RetroCornerRedux/blob/main/Dragon/Originals/FlipBits/flip.bas
266
320
  * loops.bas -- https://colorcomputerarchive.com/repo/Documents/Manuals/Hardware/Color%20Computer%203%20Extended%20Basic%20(Tandy).pdf
267
321
  * f15eagle.bas -- https://colorcomputerarchive.com/repo/Disks/Magazines/Rainbow%20On%20Disk.zip
268
322
  * mars.bas -- https://github.com/jggames/trs80mc10/tree/9df4c9578250009d68a03101d626faa3c22e7445/quicktype/Text%20Adventures/WorkInProgress/Mars
@@ -1,21 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: coco-tools
3
- Version: 0.18
4
- Summary: TRS-80 Color Computer Tools
5
- Home-page: https://github.com/jamieleecho/coco-tools
6
- Author: Jamie Cho
7
- Author-email: jamieleecho+coco_tools@gmail.com
8
- License: GPLv2
9
- Keywords: coco image conversion trs-80 tandy
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Intended Audience :: Developers
12
- Classifier: Topic :: Software Development :: Build Tools
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Requires-Python: >=3.9.19
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE
18
-
19
1
  # coco-tools
20
2
 
21
3
  This is a simple collection of tools to assist with developing software for
@@ -30,35 +12,63 @@ pip install coco-tools
30
12
  # To install from source
31
13
  git clone https://github.com/jamieleecho/coco-tools.git
32
14
  cd coco-tools
33
- python3 setup.py
15
+ make install-pre-commit
16
+ make install
34
17
  ```
35
18
 
19
+ The `Makefile` makes it easy to perform the most common operations:
20
+ * `make all` transpiles several exapmle ECB programs to Basic09
21
+ * `make check-all` runs linting and `uv.lock` checks
22
+ * `make check-lint` checks for linting issues
23
+ * `make check-lock` verifies the `uv.lock` is aligned to `pyproject.toml`
24
+ * `make clean` cleans the virtual environment and caches
25
+ * `make default` runs a default set of checks on the code
26
+ * `make fix-all` formats the code, fixes lint errors and runs locks `uv.lock` to `pyproject.toml`
27
+ * `make fix-format` formats the code
28
+ * `make fix-lint` fixes linting issues
29
+ * `make fix-lint-unsafe` fixes linting issues potentially adding inadvertant bugs
30
+ * `make help` outputs the different make options
31
+ * `make install` build install the distribution
32
+ * `make install-pre-commit` installs pre-commit hooks
33
+ * `make lock` locks `uv.lock` to `pyproject.toml`
34
+ * `make install-pre-commit` installs pre-commit hooks
35
+ * `make run-tests` runs the unit tests
36
+ * `make sync` syncs the python environment with `uv.lock`
37
+
38
+ `.vscode/settings.json` is set so that unit tests can be run without further configuration.
39
+
36
40
  ## Tools
37
41
 
38
42
  ### [decb-to-b09](./README.decb-to-b09.md)
39
43
 
40
44
  ```
41
- usage: decb-to-b09 [-h] [--version] [-l] [-z] [-D] [-w] program.bas program.b09
45
+ usage: decb-to-b09 [-h] [--version] [-l] [-z] [-s DEFAULT_STRING_STORAGE] [-D] [-w]
46
+ [-c CONFIG_FILE]
47
+ program.bas program.b09
42
48
 
43
49
  Convert a Color BASIC program to a BASIC09 program
44
50
  Copyright (c) 2023 by Jamie Cho
45
- Version: 0.8
51
+ Version: 0.18
46
52
 
47
53
  positional arguments:
48
54
  program.bas input DECB text program file
49
55
  program.b09 output BASIC09 text program file
50
56
 
51
- options:
57
+ optional arguments:
52
58
  -h, --help show this help message and exit
53
59
  --version show program's version number and exit
54
60
  -l, --filter-unused-linenum
55
61
  Filter out line numbers not referenced by the program
56
62
  -z, --dont-initialize-vars
57
63
  Don't pre-initialize all variables
64
+ -s DEFAULT_STRING_STORAGE, --default-string-storage DEFAULT_STRING_STORAGE
65
+ Bytes to allocate for each string
58
66
  -D, --dont-output-dependencies
59
67
  Don't output required dependencies
60
68
  -w, --dont-run-width-32
61
69
  if set don't run the default width 32
70
+ -c CONFIG_FILE, --config-file CONFIG_FILE
71
+ Optional compiler configuration file
62
72
  ```
63
73
 
64
74
  ### cm3toppm
@@ -242,18 +252,38 @@ options:
242
252
  ## Developing and Testing
243
253
 
244
254
  ```
255
+ # To set up pre-commit checks
256
+ pre-commit install
257
+
245
258
  # Build the docker image
246
- docker-compose build test
259
+ docker compose build test
247
260
 
248
261
  # Run tests using the source on the docker image
249
- docker-compose run test
262
+ docker compose run test
250
263
 
251
264
  # Run tests using the source on the host computer
252
- docker-compose run testv
265
+ docker compose run testv
253
266
 
254
- # To make changes and develop locally
267
+ # To develop locally
255
268
  pip install -r requirements.txt
256
- pre-commit install
269
+
270
+ # Run linting, build example disk images for basic conversion
271
+ make
272
+
273
+ # Remove built artifacts
274
+ make clean
275
+
276
+ # Reformats the code
277
+ make format
278
+
279
+ # Only runs linting
280
+ make lint
281
+
282
+ # Only run tests
283
+ make test
284
+
285
+ # Build basic and os-9 eample images
286
+ make basic.dsk os9boot.dsk
257
287
  ```
258
288
 
259
289
  ## Credits
@@ -263,6 +293,7 @@ The programs in the examples/decb and examples/other-decb-examples-to-try direct
263
293
  * banner.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/banner.c10
264
294
  * cadnza.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/cadnza.c10
265
295
  * cflip.bas -- https://colorcomputerarchive.com/repo/MC-10/Software/Books/TRS-80%20Color%20Computer%20%26%20MC-10%20Programs/cflip.c10
296
+ * flip.bas -- https://github.com/daftspaniel/RetroCornerRedux/blob/main/Dragon/Originals/FlipBits/flip.bas
266
297
  * loops.bas -- https://colorcomputerarchive.com/repo/Documents/Manuals/Hardware/Color%20Computer%203%20Extended%20Basic%20(Tandy).pdf
267
298
  * f15eagle.bas -- https://colorcomputerarchive.com/repo/Disks/Magazines/Rainbow%20On%20Disk.zip
268
299
  * mars.bas -- https://github.com/jggames/trs80mc10/tree/9df4c9578250009d68a03101d626faa3c22e7445/quicktype/Text%20Adventures/WorkInProgress/Mars
@@ -1,2 +1,2 @@
1
1
  # __version__ MUST be defined on line 2
2
- __version__ = "0.18"
2
+ __version__ = "0.20"
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  from typing import List
2
3
 
3
4
  from coco import b09
@@ -12,6 +13,7 @@ from coco.b09.elements import (
12
13
  BasicRunCall,
13
14
  BasicVar,
14
15
  )
16
+ from coco.b09.configs import CompilerConfigs
15
17
  from coco.b09.grammar import grammar, PROCNAME_REGEX
16
18
  from coco.b09.parser import BasicVisitor
17
19
  from coco.b09.procbank import ProcedureBank
@@ -32,6 +34,7 @@ from coco.b09.visitors import (
32
34
  LineReferenceVisitor,
33
35
  LineZeroFilterVisitor,
34
36
  SetDimStringStorageVisitor,
37
+ SetInitializeVisitor,
35
38
  StatementCollectorVisitor,
36
39
  StrVarAllocatorVisitor,
37
40
  VarInitializerVisitor,
@@ -47,6 +50,7 @@ def convert(
47
50
  *,
48
51
  add_standard_prefix: bool = True,
49
52
  add_suffix: bool = True,
53
+ compiler_configs: CompilerConfigs = None,
50
54
  default_str_storage: int = b09.DEFAULT_STR_STORAGE,
51
55
  default_width32: bool = True,
52
56
  filter_unused_linenum: bool = False,
@@ -55,6 +59,7 @@ def convert(
55
59
  procname: str = "",
56
60
  skip_procedure_headers: bool = False,
57
61
  ) -> str:
62
+ compiler_configs = compiler_configs or CompilerConfigs()
58
63
  tree = grammar.parse(progin)
59
64
  bv = BasicVisitor()
60
65
  basic_prog: BasicProg = bv.visit(tree)
@@ -124,7 +129,8 @@ def convert(
124
129
  basic_prog.visit(BasicFunctionalExpressionPatcherVisitor())
125
130
 
126
131
  set_string_storage_vistor: SetDimStringStorageVisitor = SetDimStringStorageVisitor(
127
- default_str_storage=default_str_storage
132
+ default_str_storage=default_str_storage,
133
+ string_configs=compiler_configs.string_configs,
128
134
  )
129
135
  basic_prog.visit(set_string_storage_vistor)
130
136
 
@@ -133,9 +139,10 @@ def convert(
133
139
  basic_prog.visit(dimmed_array_visitor)
134
140
  declare_array_visitor = DeclareImplicitArraysVisitor(
135
141
  dimmed_var_names=dimmed_array_visitor.dimmed_var_names,
142
+ initialize_vars=initialize_vars,
136
143
  )
137
144
  basic_prog.visit(declare_array_visitor)
138
- basic_prog.extend_prefix_lines(declare_array_visitor.dim_statements)
145
+ basic_prog.insert_lines_at_beginning(declare_array_visitor.dim_statements)
139
146
 
140
147
  # allocate sufficient string storage
141
148
  str_var_allocator: StrVarAllocatorVisitor = StrVarAllocatorVisitor(
@@ -150,6 +157,8 @@ def convert(
150
157
  var_initializer = VarInitializerVisitor()
151
158
  basic_prog.visit(var_initializer)
152
159
  basic_prog.extend_prefix_lines(var_initializer.assignment_lines)
160
+ set_init_visitor = SetInitializeVisitor(initialize_vars)
161
+ basic_prog.visit(set_init_visitor)
153
162
 
154
163
  # remove unused line numbers
155
164
  line_ref_visitor = LineReferenceVisitor()
@@ -238,6 +247,7 @@ def convert_file(
238
247
  output_program_file: str,
239
248
  *,
240
249
  add_standard_prefix: bool = True,
250
+ config_file: str = None,
241
251
  default_width32: bool = True,
242
252
  default_str_storage: int = b09.DEFAULT_STR_STORAGE,
243
253
  filter_unused_linenum: bool = False,
@@ -246,9 +256,13 @@ def convert_file(
246
256
  procname: str = "",
247
257
  ) -> None:
248
258
  progin = input_program_file.read()
259
+ compiler_configs = (
260
+ CompilerConfigs.load(Path(config_file)) if config_file else CompilerConfigs()
261
+ )
249
262
  progout = convert(
250
263
  progin,
251
264
  add_standard_prefix=add_standard_prefix,
265
+ compiler_configs=compiler_configs,
252
266
  default_str_storage=default_str_storage,
253
267
  default_width32=default_width32,
254
268
  filter_unused_linenum=filter_unused_linenum,
@@ -0,0 +1,37 @@
1
+ import re
2
+ from pathlib import Path
3
+ from pydantic import BaseModel, Field, field_validator
4
+ from pydantic_yaml import parse_yaml_raw_as
5
+ from typing import Dict
6
+
7
+
8
+ class StringConfigs(BaseModel):
9
+ strname_to_size: Dict[str, int] = Field(default_factory=lambda: {})
10
+
11
+ @field_validator("strname_to_size")
12
+ @classmethod
13
+ def check_mappings(cls, val: Dict[str, int]):
14
+ valid_var_regex = re.compile(r"[A-Z][A-Z_0-9]?")
15
+
16
+ for key, sz in val.items():
17
+ assert key.endswith("$") or key.endswith(
18
+ "$()"
19
+ ), f"{key} must end with a $ or $()"
20
+ assert key == key.upper(), f"{key} must be all caps"
21
+ var_only = key[: key.find("$")]
22
+ assert 1 <= len(var_only) <= 2, f"{var_only} must be 1 or 2 characters"
23
+ assert valid_var_regex.match(
24
+ var_only
25
+ ), f"{var_only} must be a valid BASIC name"
26
+ assert 0 < sz < 32767, f"{sz} for {key} must be between 0 and 32767"
27
+ return val
28
+
29
+
30
+ class CompilerConfigs(BaseModel):
31
+ string_configs: StringConfigs = Field(default_factory=lambda: StringConfigs())
32
+
33
+ @classmethod
34
+ def load(cls, path: Path) -> "CompilerConfigs":
35
+ with open(path) as handle:
36
+ yaml = handle.read()
37
+ return parse_yaml_raw_as(cls, yaml)
@@ -1,6 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
+ from collections import defaultdict
2
3
  from itertools import chain
3
- from typing import List, Literal, TYPE_CHECKING, Union
4
+ from typing import Dict, List, Literal, TYPE_CHECKING, Union
4
5
 
5
6
  from coco.b09 import DEFAULT_STR_STORAGE
6
7
 
@@ -492,7 +493,7 @@ class BasicLine(AbstractBasicConstruct):
492
493
 
493
494
  def basic09_text(self, indent_level) -> str:
494
495
  if self._is_referenced and self._num is not None:
495
- return f"{self._num} " f"{self._statements.basic09_text(indent_level)}"
496
+ return f"{self._num} {self._statements.basic09_text(indent_level)}"
496
497
  return f"{self._statements.basic09_text(indent_level)}"
497
498
 
498
499
  def visit(self, visitor: "BasicConstructVisitor") -> None:
@@ -826,7 +827,7 @@ class BasicFunctionCall(AbstractBasicExpression):
826
827
  self._args = args
827
828
 
828
829
  def basic09_text(self, indent_level: int) -> str:
829
- return f"{self._func}" f"{self._args.basic09_text(indent_level)}"
830
+ return f"{self._func}{self._args.basic09_text(indent_level)}"
830
831
 
831
832
 
832
833
  class BasicDataStatement(AbstractBasicStatement):
@@ -969,8 +970,15 @@ class BasicJoystkExpression(BasicFunctionalExpression):
969
970
  class BasicDimStatement(AbstractBasicStatement):
970
971
  _default_str_storage: int
971
972
  _dim_vars: List["BasicArrayRef | BasicVar"]
973
+ _initialize_vars: bool
974
+ _strname_to_size: Dict[str, int]
972
975
 
973
- def __init__(self, dim_vars: List["BasicArrayRef | BasicVar"]):
976
+ def __init__(
977
+ self,
978
+ dim_vars: List["BasicArrayRef | BasicVar"],
979
+ *,
980
+ initialize_vars: bool = False,
981
+ ):
974
982
  super().__init__()
975
983
  self._default_str_storage = DEFAULT_STR_STORAGE
976
984
  self._dim_vars = [
@@ -990,24 +998,44 @@ class BasicDimStatement(AbstractBasicStatement):
990
998
  )
991
999
  for var in dim_vars
992
1000
  ]
1001
+ self._initialize_vars = initialize_vars
1002
+ self._strname_to_size = {}
993
1003
 
994
1004
  @property
995
1005
  def default_str_storage(self):
996
1006
  return self._default_str_storage
997
1007
 
1008
+ @default_str_storage.setter
1009
+ def default_str_storage(self, val):
1010
+ self._default_str_storage = val
1011
+
998
1012
  @property
999
1013
  def dim_vars(self) -> List["BasicArrayRef | BasicVar"]:
1000
1014
  return self._dim_vars
1001
1015
 
1002
- @default_str_storage.setter
1003
- def default_str_storage(self, val):
1004
- self._default_str_storage = val
1016
+ @property
1017
+ def initialize_vars(self) -> bool:
1018
+ return self._initialize_vars
1019
+
1020
+ @initialize_vars.setter
1021
+ def initialize_vars(self, val: bool) -> None:
1022
+ self._initialize_vars = val
1023
+
1024
+ @property
1025
+ def strname_to_size(self):
1026
+ return self._strname_to_size
1027
+
1028
+ @strname_to_size.setter
1029
+ def strname_to_size(self, val):
1030
+ self._strname_to_size = val
1005
1031
 
1006
1032
  def init_text_for_var(self, dim_var: "BasicArrayRef | BasicVar") -> str:
1007
1033
  if isinstance(dim_var, BasicVar):
1008
1034
  return BasicStatements(
1009
1035
  [
1010
- BasicAssignment(dim_var, BasicLiteral("" if dim_var.is_str_expr else 0)),
1036
+ BasicAssignment(
1037
+ dim_var, BasicLiteral("" if dim_var.is_str_expr else 0)
1038
+ ),
1011
1039
  ],
1012
1040
  multi_line=False,
1013
1041
  ).basic09_text(0)
@@ -1065,19 +1093,39 @@ class BasicDimStatement(AbstractBasicStatement):
1065
1093
  )
1066
1094
  ]
1067
1095
 
1068
- str_vars_text: str = (
1096
+ str_var_names_to_exp = {
1097
+ str_var.name()
1098
+ if isinstance(str_var, BasicVar)
1099
+ else str_var.var.name(): str_var
1100
+ for str_var in str_vars
1101
+ }
1102
+
1103
+ str_var_to_size = {
1104
+ str_var: self.strname_to_size[str_name]
1105
+ if str_name in self.strname_to_size
1106
+ else self.default_str_storage
1107
+ for str_name, str_var in str_var_names_to_exp.items()
1108
+ }
1109
+
1110
+ str_size_to_strs: Dict[int, List[BasicVar | BasicArrayRef]] = defaultdict(list)
1111
+ for var, size in str_var_to_size.items():
1112
+ str_size_to_strs[size].append(var)
1113
+
1114
+ str_vars_text_list: List[str] = [
1069
1115
  self._basic09_text(
1070
- str_vars,
1071
- ""
1072
- if self.default_str_storage == DEFAULT_STR_STORAGE
1073
- else f": STRING[{self._default_str_storage}]",
1116
+ list_vars,
1117
+ "" if size == DEFAULT_STR_STORAGE else f": STRING[{size}]",
1074
1118
  indent_level,
1075
1119
  )
1076
- + ("\n" if non_str_vars else "")
1077
- if str_vars
1120
+ for size, list_vars in str_size_to_strs.items()
1121
+ ]
1122
+
1123
+ str_vars_text = (
1124
+ ("\n".join(str_vars_text_list) + ("\n" if non_str_vars else ""))
1125
+ if str_vars_text_list
1078
1126
  else ""
1079
1127
  )
1080
- non_str_vars_text: str = (
1128
+ non_str_vars_text = (
1081
1129
  self._basic09_text(non_str_vars, "", indent_level) if non_str_vars else ""
1082
1130
  )
1083
1131
 
@@ -1089,13 +1137,13 @@ class BasicDimStatement(AbstractBasicStatement):
1089
1137
  dim_var_text: str = ", ".join(
1090
1138
  (dim_var.basic09_text(indent_level) for dim_var in dim_vars)
1091
1139
  )
1092
- init_text = "\n".join(
1093
- (
1094
- self.init_text_for_var(dim_var)
1095
- for dim_var in dim_vars
1140
+ if self.initialize_vars:
1141
+ init_text = "\n".join(
1142
+ (self.init_text_for_var(dim_var) for dim_var in dim_vars)
1096
1143
  )
1097
- )
1098
- init_text = "\n" + init_text if init_text else ""
1144
+ init_text = "\n" + init_text if init_text else ""
1145
+ else:
1146
+ init_text = ""
1099
1147
 
1100
1148
  return (
1101
1149
  f"{super().basic09_text(indent_level)}"
@@ -49,7 +49,7 @@ QUOTED_STR3_FUNCTION_NAMES = [f'"{name}"' for name in STR3_FUNCTIONS]
49
49
 
50
50
  STR_NUM_FUNCTIONS = {
51
51
  "ASC": "ASC",
52
- "VAL": "VAL",
52
+ "VAL": "RUN ecb_val",
53
53
  "LEN": "LEN",
54
54
  }
55
55
 
@@ -133,7 +133,7 @@ KEYWORDS = "|".join(
133
133
  "GOSUB",
134
134
  "GOTO",
135
135
  "HBUFF",
136
- "HGET" "HCIRCLE",
136
+ "HGETHCIRCLE",
137
137
  "HCLS",
138
138
  "HCOLOR",
139
139
  "HEX$",
@@ -299,8 +299,8 @@ grammar = Grammar(
299
299
  / hget_statement
300
300
  / hput_statement
301
301
  / hpaint_statement
302
- statement2 = ({ ' / '.join(QUOTED_STATEMENTS2_NAMES)}) space* "(" space* exp space* "," space* exp space* ")" space*
303
- statement3 = ({ ' / '.join(QUOTED_STATEMENTS3_NAMES)}) space* "(" space* exp space* "," space* exp space* "," space* exp space* ")" space*
302
+ statement2 = ({" / ".join(QUOTED_STATEMENTS2_NAMES)}) space* "(" space* exp space* "," space* exp space* ")" space*
303
+ statement3 = ({" / ".join(QUOTED_STATEMENTS3_NAMES)}) space* "(" space* exp space* "," space* exp space* "," space* exp space* ")" space*
304
304
  statements = statement? space* statements_elements space* last_statement?
305
305
  last_statement = comment / partial_str_arr_assign / partial_str_assign
306
306
  partial_str_arr_assign = "LET"? space* str_array_ref_exp space* "=" space* partial_str_lit
@@ -342,8 +342,8 @@ grammar = Grammar(
342
342
  num_power_exp = val_exp space* num_power_sub_exps
343
343
  num_power_sub_exps = num_power_sub_exp*
344
344
  num_power_sub_exp = ("^" space* val_exp space*)
345
- func_exp = ({ ' / '.join(QUOTED_FUNCTION_NAMES)}) space* "(" space* exp space* ")" space*
346
- func_str_exp = ({ ' / '.join(QUOTED_STR_NUM_FUNCTIONS_NAMES)}) space* "(" space* str_exp space* ")" space*
345
+ func_exp = ({" / ".join(QUOTED_FUNCTION_NAMES)}) space* "(" space* exp space* ")" space*
346
+ func_str_exp = ({" / ".join(QUOTED_STR_NUM_FUNCTIONS_NAMES)}) space* "(" space* str_exp space* ")" space*
347
347
  val_exp = num_literal
348
348
  / hex_literal
349
349
  / paren_exp
@@ -363,11 +363,11 @@ grammar = Grammar(
363
363
  str_exp = str_simple_exp space* str_exp_elements
364
364
  str_exp_elements = str_exp_element*
365
365
  str_exp_element = "+" space* str_simple_exp space*
366
- str2_func_exp = ({ ' / '.join(QUOTED_STR2_FUNCTION_NAMES)}) space* "(" space* str_exp space* "," space* exp space* ")" space*
367
- str3_func_exp = ({ ' / '.join(QUOTED_STR3_FUNCTION_NAMES)}) space* "(" space* str_exp space* "," space* exp space* "," space* exp space* ")" space*
368
- num_str_func_exp = ({ ' / '.join(QUOTED_NUM_STR_FUNCTIONS_NAMES)}) space* "(" space* exp space* ")" space*
369
- num_str_func_exp_statements = ({ ' / '.join(QUOTED_NUM_STR_FUNCTIONS_TO_STATEMENTS_NAMES)}) space* "(" space* exp space* ")" space*
370
- str_func_exp_statements = ({ ' / '.join(QUOTED_STR_FUNCTIONS_TO_STATEMENTS_NAMES)}) space*
366
+ str2_func_exp = ({" / ".join(QUOTED_STR2_FUNCTION_NAMES)}) space* "(" space* str_exp space* "," space* exp space* ")" space*
367
+ str3_func_exp = ({" / ".join(QUOTED_STR3_FUNCTION_NAMES)}) space* "(" space* str_exp space* "," space* exp space* "," space* exp space* ")" space*
368
+ num_str_func_exp = ({" / ".join(QUOTED_NUM_STR_FUNCTIONS_NAMES)}) space* "(" space* exp space* ")" space*
369
+ num_str_func_exp_statements = ({" / ".join(QUOTED_NUM_STR_FUNCTIONS_TO_STATEMENTS_NAMES)}) space* "(" space* exp space* ")" space*
370
+ str_func_exp_statements = ({" / ".join(QUOTED_STR_FUNCTIONS_TO_STATEMENTS_NAMES)}) space*
371
371
  str_simple_exp = str_literal
372
372
  / str2_func_exp
373
373
  / str3_func_exp
@@ -413,7 +413,7 @@ grammar = Grammar(
413
413
  linenum_list = linenum space* linenum_list0
414
414
  linenum_list0 = linenum_list_elem*
415
415
  linenum_list_elem = "," space* linenum space*
416
- functions = ~r"{'|'.join(FUNCTIONS.keys())}"
416
+ functions = ~r"{"|".join(FUNCTIONS.keys())}"
417
417
  data_statement = "DATA" space* data_elements space*
418
418
  data_elements = data_element space* data_elements0
419
419
  data_element = data_num_element / data_str_element
@@ -425,7 +425,7 @@ grammar = Grammar(
425
425
  data_str_element0 = space* str_literal space*
426
426
  data_str_element1 = space* data_str_literal
427
427
  data_str_literal = ~r'[^",:\n]*'
428
- single_kw_statement = ({ ' / '.join(QUOTED_SINGLE_KEYWORD_STATEMENTS)}) space*
428
+ single_kw_statement = ({" / ".join(QUOTED_SINGLE_KEYWORD_STATEMENTS)}) space*
429
429
  for_statement = "FOR" space* var space* "=" space* exp space* "TO" space* exp space*
430
430
  for_step_statement = "FOR" space* var space* "=" space* exp space* "TO" space* exp space* "STEP" space* exp space*
431
431
  next_statement = next_var_statement / next_empty_statement
@@ -434,8 +434,8 @@ grammar = Grammar(
434
434
  var_list = var space* var_list_elements
435
435
  var_list_elements = var_list_element*
436
436
  var_list_element = "," space* var space*
437
- func_to_statements = ({ ' / '.join(QUOTED_FUNCTIONS_TO_STATEMENTS_NAMES)}) space* "(" space* exp space* ")" space*
438
- func_to_statements2 = ({ ' / '.join(QUOTED_FUNCTIONS_TO_STATEMENTS2_NAMES)}) space* "(" space* exp space* "," space* exp space*")" space*
437
+ func_to_statements = ({" / ".join(QUOTED_FUNCTIONS_TO_STATEMENTS_NAMES)}) space* "(" space* exp space* ")" space*
438
+ func_to_statements2 = ({" / ".join(QUOTED_FUNCTIONS_TO_STATEMENTS2_NAMES)}) space* "(" space* exp space* "," space* exp space*")" space*
439
439
  joystk_to_statement = "JOYSTK" space* "(" space* exp space* ")" space*
440
440
  dim_element0 = (int_literal / int_hex_literal)
441
441
  dim_var = (dim_array_var / str_var / var)