opencrbasic 1.1.0__tar.gz → 1.1.1__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 (119) hide show
  1. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/PKG-INFO +4 -5
  2. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/README.md +3 -4
  3. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/pyproject.toml +4 -2
  4. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/__init__.py +1 -1
  5. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/analysis.py +1 -1
  6. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/__init__.py +3 -4
  7. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/cr3xx.py +3 -4
  8. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/expressions.py +3 -5
  9. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/instr_data.py +5 -7
  10. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/instr_rules.py +1 -1
  11. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/structure.py +8 -16
  12. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/terminals.py +3 -3
  13. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/warnings.py +4 -9
  14. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checks.py +4 -4
  15. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/cli.py +1 -1
  16. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/compiler.py +1 -1
  17. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/tests/corpus/README.md +21 -21
  18. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/.gitignore +0 -0
  19. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/LICENSE +0 -0
  20. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/__main__.py +0 -0
  21. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/bindings.py +0 -0
  22. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/catalog.py +0 -0
  23. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checkconfig.py +0 -0
  24. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/ess.py +0 -0
  25. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/instr_measure.py +0 -0
  26. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/instructions.py +0 -0
  27. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/intervals.py +0 -0
  28. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/longconv.py +0 -0
  29. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/scan_time.py +0 -0
  30. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/storage.py +0 -0
  31. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/structs.py +0 -0
  32. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/symbols.py +0 -0
  33. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/unused.py +0 -0
  34. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/checker/var_types.py +0 -0
  35. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/commands.py +0 -0
  36. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/consteval.py +0 -0
  37. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/background_calibration.json +0 -0
  38. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/before_beginprog.json +0 -0
  39. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/background_calibration.json +0 -0
  40. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/before_beginprog.json +0 -0
  41. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/ess_variables.json +0 -0
  42. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/fnotch.json +0 -0
  43. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/functions.json +0 -0
  44. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/instructions.json +0 -0
  45. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/measure.json +0 -0
  46. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/mode.json +0 -0
  47. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/pipeline_tasks.json +0 -0
  48. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/settings_fields.json +0 -0
  49. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/status_members.json +0 -0
  50. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/symbols.json +0 -0
  51. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr1000x/terminals.json +0 -0
  52. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/before_beginprog.json +0 -0
  53. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/ess_variables.json +0 -0
  54. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/fnotch.json +0 -0
  55. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/functions.json +0 -0
  56. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/instructions.json +0 -0
  57. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/measure.json +0 -0
  58. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/mode.json +0 -0
  59. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/settings_fields.json +0 -0
  60. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/status_members.json +0 -0
  61. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/symbols.json +0 -0
  62. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr300/terminals.json +0 -0
  63. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/before_beginprog.json +0 -0
  64. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/ess_variables.json +0 -0
  65. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/fnotch.json +0 -0
  66. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/functions.json +0 -0
  67. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/instructions.json +0 -0
  68. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/measure.json +0 -0
  69. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/mode.json +0 -0
  70. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/settings_fields.json +0 -0
  71. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/status_members.json +0 -0
  72. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/symbols.json +0 -0
  73. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/cr350/terminals.json +0 -0
  74. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/ess_variables.json +0 -0
  75. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/fnotch.json +0 -0
  76. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/functions.json +0 -0
  77. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/instructions.json +0 -0
  78. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/measure.json +0 -0
  79. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/mode.json +0 -0
  80. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/notices_cr6.json +0 -0
  81. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/pipeline_tasks.json +0 -0
  82. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/settings_fields.json +0 -0
  83. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/status_members.json +0 -0
  84. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/status_table.json +0 -0
  85. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/symbols.json +0 -0
  86. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/terminals.json +0 -0
  87. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/data/type_codes.json +0 -0
  88. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/diagnostics.py +0 -0
  89. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/editing.py +0 -0
  90. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/formatting.py +0 -0
  91. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/helpdocs.py +0 -0
  92. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/hover.py +0 -0
  93. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/inlay.py +0 -0
  94. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lexer.py +0 -0
  95. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/__init__.py +0 -0
  96. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/__main__.py +0 -0
  97. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/config.py +0 -0
  98. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/features.py +0 -0
  99. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/server.py +0 -0
  100. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/session.py +0 -0
  101. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/lsp/worker.py +0 -0
  102. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/macros.py +0 -0
  103. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/mode.py +0 -0
  104. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/navigation.py +0 -0
  105. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/parser.py +0 -0
  106. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/positions.py +0 -0
  107. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/preprocess.py +0 -0
  108. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/profiles.py +0 -0
  109. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/provenance.py +0 -0
  110. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/quickfix.py +0 -0
  111. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/rename.py +0 -0
  112. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/signature.py +0 -0
  113. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/source.py +0 -0
  114. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/sources.py +0 -0
  115. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/syntax.py +0 -0
  116. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/tables.py +0 -0
  117. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/tables_hook.py +0 -0
  118. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/tdf.py +0 -0
  119. {opencrbasic-1.1.0 → opencrbasic-1.1.1}/src/opencrbasic/timing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: opencrbasic
3
- Version: 1.1.0
3
+ Version: 1.1.1
4
4
  Summary: Open-source re-implementation of the Campbell Scientific CRBasic pre-compilers (CR6, CR1000X, CR300, CR350)
5
5
  Project-URL: Repository, https://github.com/UtrechtUniversity/open-crbasic
6
6
  Author: Utrecht University
@@ -38,8 +38,8 @@ Status, measured against the real compilers: `PROGRESS.md`. Design and the v1.0
38
38
  ## Scope
39
39
 
40
40
  - **Gated profiles: CR6 and CR1000X.** On these, v1.0 gates the reference verdict in the relevant
41
- area (the FirnMelt/GEUS instruction set and language constructs), the execution mode, and the
42
- first error for realistic mistakes on relevant rules, measured on the FirnMelt programs, the 507
41
+ area (the station/GEUS instruction set and language constructs), the execution mode, and the
42
+ first error for realistic mistakes on relevant rules, measured on the station programs, the 507
43
43
  CRBasic help examples, the 66 GEUS programs, the saved fuzz replay and fresh `--relevant` fuzz
44
44
  seeds. The help examples and GEUS programs are not redistributed here; see
45
45
  [tests/corpus/README.md](tests/corpus/README.md) for running against local copies. One relevant-area false accept is known: a `Sub` name that is also another routine's
@@ -159,8 +159,7 @@ result.tables # list of tdf.TdfTable (Status, DataTables, DataTableInfo, ConstT
159
159
  `parser.parse_file()` gives the syntax tree (`syntax.py`) for other tools.
160
160
 
161
161
  [openloggernet](https://github.com/UtrechtUniversity/open-loggernet) uses opencrbasic when
162
- `CR6COMP=opencrbasic` is set, and the FirnMelt station repository compiles every program with it in
163
- CI.
162
+ `CR6COMP=opencrbasic` is set.
164
163
 
165
164
  ## Editor support
166
165
 
@@ -21,8 +21,8 @@ Status, measured against the real compilers: `PROGRESS.md`. Design and the v1.0
21
21
  ## Scope
22
22
 
23
23
  - **Gated profiles: CR6 and CR1000X.** On these, v1.0 gates the reference verdict in the relevant
24
- area (the FirnMelt/GEUS instruction set and language constructs), the execution mode, and the
25
- first error for realistic mistakes on relevant rules, measured on the FirnMelt programs, the 507
24
+ area (the station/GEUS instruction set and language constructs), the execution mode, and the
25
+ first error for realistic mistakes on relevant rules, measured on the station programs, the 507
26
26
  CRBasic help examples, the 66 GEUS programs, the saved fuzz replay and fresh `--relevant` fuzz
27
27
  seeds. The help examples and GEUS programs are not redistributed here; see
28
28
  [tests/corpus/README.md](tests/corpus/README.md) for running against local copies. One relevant-area false accept is known: a `Sub` name that is also another routine's
@@ -142,8 +142,7 @@ result.tables # list of tdf.TdfTable (Status, DataTables, DataTableInfo, ConstT
142
142
  `parser.parse_file()` gives the syntax tree (`syntax.py`) for other tools.
143
143
 
144
144
  [openloggernet](https://github.com/UtrechtUniversity/open-loggernet) uses opencrbasic when
145
- `CR6COMP=opencrbasic` is set, and the FirnMelt station repository compiles every program with it in
146
- CI.
145
+ `CR6COMP=opencrbasic` is set.
147
146
 
148
147
  ## Editor support
149
148
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "opencrbasic"
3
- version = "1.1.0"
3
+ version = "1.1.1"
4
4
  description = "Open-source re-implementation of the Campbell Scientific CRBasic pre-compilers (CR6, CR1000X, CR300, CR350)"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -31,7 +31,8 @@ crbc-lsp = "opencrbasic.lsp.server:main"
31
31
  # `uv sync` installs `dev` by default: the test runner and the reverse-engineering tools
32
32
  # (`tools/extract_tables.py`, `tools/message_catalog.py` read the exe with pefile), and pygls
33
33
  # so the suite can test the language server; pytest-xdist for parallel test runs (`-n`); pyrefly
34
- # checks the repository (`[tool.pyrefly]`); pre-commit runs ruff and pyrefly before each commit.
34
+ # checks the repository (`[tool.pyrefly]`); pre-commit runs ruff and pyrefly before each commit;
35
+ # openloggernet drives a logger for `tools/logger_oracle.py`.
35
36
  dev = [
36
37
  "pytest>=8",
37
38
  "pefile>=2024.8.26",
@@ -39,6 +40,7 @@ dev = [
39
40
  "pytest-xdist>=3.6",
40
41
  "pyrefly==1.3.1",
41
42
  "pre-commit>=4",
43
+ "openloggernet>=0.3.0",
42
44
  ]
43
45
 
44
46
  [build-system]
@@ -1,3 +1,3 @@
1
1
  """Open-source CRBasic (CR6) pre-compiler."""
2
2
 
3
- __version__ = "1.1.0"
3
+ __version__ = "1.1.1"
@@ -14,7 +14,7 @@ from .compiler import compile_file
14
14
  from .sources import DiskSource, LimitedSource, OverlaySource, RecordingSource, SourceProvider
15
15
 
16
16
  API_VERSION = 2 # 2: findings, notices, config_error, AnalysisRequest.checks (M6)
17
- DOCS = "https://github.com/UtrechtUniversity/firnmelt-datalogger/blob/main/opencrbasic/"
17
+ DOCS = "https://github.com/UtrechtUniversity/open-crbasic/blob/main/"
18
18
 
19
19
 
20
20
  def _no_overlays() -> Mapping[Path, bytes]:
@@ -953,10 +953,9 @@ def _check(program: S.Program, profile: Profile, diags: Diagnostics, result) ->
953
953
 
954
954
  if not diags.errors:
955
955
  # `When Main Sequence Scan %d is running, background calibration will be disabled.`:
956
- # round 6, moved here from the unconditional `warnings.check_early` call above -- oracle-
957
- # confirmed *not* ungated the way `_check_reachability`/`_check_fnotch` are, unlike this
958
- # module's own docstring previously claimed for all of `check_early` (`checker/warnings.py`'s
959
- # `check_background_calibration` docstring has the oracle evidence). Independent of
956
+ # oracle-confirmed *not* ungated the way `_check_reachability`/`_check_fnotch` are
957
+ # (`checker/warnings.py`'s `check_background_calibration` docstring has the oracle evidence).
958
+ # Independent of
960
959
  # `tables_hook`'s own availability, so called ahead of that guard rather than inside it.
961
960
  _run_pass(warnings.check_background_calibration, program, profile, diags, env)
962
961
  _run_pass(warnings.check_slow_scan_skips, program, profile, diags, env)
@@ -389,9 +389,8 @@ def check(program: S.Program, profile, diags: Diagnostics) -> None:
389
389
  # `acceptdatarecords_1.CR6`, `SerialOpen (COMC1,...)`'s `COMC1 is not defined.` taints every
390
390
  # following two-plus-argument instruction to end of file, `Scan`'s own `Sec` and
391
391
  # `AcceptDataRecords`'s own `32769`, despite that finding being **ungated** and thus, in this
392
- # project's own pass model, skipping tier B -- where the *previous*, narrower version of this
393
- # function lived -- entirely), this is no longer called from inside the `if not diags.errors:`
394
- # tier-B block the way `check_expr_cascade` was: `checker/__init__.py` now calls it once,
392
+ # project's own pass model, skipping tier B entirely), this is not called from inside the
393
+ # `if not diags.errors:` tier-B block: `checker/__init__.py` calls it once,
395
394
  # unconditionally, after every other diagnostic-producing pass has run, so it can see -- and rewrite
396
395
  # -- the complete, final diagnostic list regardless of which tier first tainted the file. It is
397
396
  # still a no-op when nothing in the file ever taints (no `_is_cascade_trigger` match and no
@@ -555,7 +554,7 @@ def check_too_many_cascade(program: S.Program, profile, diags: Diagnostics) -> N
555
554
  """CR300/CR350 only; a no-op on every other logger and when nothing in the file ever taints
556
555
  (see this module's comment above for the oracle evidence and the exact shape implemented).
557
556
  Called from `checker/__init__.py` once, unconditionally, after every other pass -- see that
558
- comment for why this can no longer be tier-B-only the way `check_expr_cascade` was.
557
+ comment for why this cannot be tier-B-only.
559
558
  """
560
559
  if profile.name not in ("cr300", "cr350"):
561
560
  return
@@ -25,9 +25,8 @@ _TYPE_CODES_PATH = Path(__file__).resolve().parent.parent / "data" / "type_codes
25
25
  # separate function (`4`/`16`/`17`/`19` `FUN_004b5db0`, a different failure message). Restricting
26
26
  # to this explicit include-list (rather than excluding the handful of kinds known *not* to
27
27
  # resolve) is deliberate: the default for an unrecognised kind is "don't check", so a gap in this
28
- # list only under-reports, never falsely rejects (AGENTS.md's priority order); the `ConstTable`
29
- # regression this session found during development (`crbasic/Main.CR6`'s
30
- # `ConstTable(GlobalConfigTable)`, kind `expr_marker`) is the concrete case that shape of bug
28
+ # list only under-reports, never falsely rejects; the station corpus's `Main.CR6`
29
+ # `ConstTable(GlobalConfigTable)` (kind `expr_marker`) is the concrete case that shape of bug
31
30
  # looks like.
32
31
  _RESOLVED_KINDS = frozenset(
33
32
  {
@@ -74,8 +73,7 @@ _CONST_FAMILY_KINDS = frozenset({"const_expr", "const_expr_only", "datatype_kw"}
74
73
  # separate `FooBar is not defined.` / `BazQux is not defined.` lines on CR300/CR350, in the source
75
74
  # (left-to-right) order `_undefined_names` already walks in. Modelled below as a plain per-logger
76
75
  # branch on `profile.name` (both loggers in each pair share identical behaviour, oracle-confirmed
77
- # side by side) rather than a new `Profile` field, to keep this session's change inside
78
- # `checker/expressions.py`/`checker/symbols.py` (`PLAN.md`'s ownership split).
76
+ # side by side) rather than a new `Profile` field.
79
77
  _WHOLE_EXPR_ECHO_LOGGERS = frozenset({"cr6", "cr1000x"})
80
78
 
81
79
  # `NAN`/`INF` are accepted as predefined float constants on all four loggers (oracle-confirmed,
@@ -45,13 +45,11 @@ from . import symbols
45
45
  # `docs/instructions.md`'s "not independently oracle-confirmed" list for exactly which those are.
46
46
  # One more call site exists (the unlabelled string `"Et"`, near the `SampleFieldCal` call site)
47
47
  # that could not be attributed to a specific instruction with confidence and is deliberately left
48
- # out -- AGENTS.md: never guess into a false reject. The other originally-unlabelled string this
49
- # round found nearby, `"FFT"`, *was* independently confirmed (a fresh scratch probe, `tfft.cr6`,
50
- # and two CHM corpus files whose `DataTable` bodies contain only `FFT(...)` calls, `fft_1.CR6`/
51
- # `covspa_1.CR6` -- both were a **false-reject regression** this round's own full difftest re-run
52
- # caught, from `check_table_structure`'s sibling `Table %s declared with no output fields.` rule
53
- # below not yet recognising `FFT` as a field producer, before `FFT` was added here too) and is
54
- # included as `FFT`.
48
+ # out: never guess into a false reject. The other unlabelled string nearby, `"FFT"`, is
49
+ # independently confirmed (a scratch probe, `tfft.cr6`, and two CHM corpus files whose
50
+ # `DataTable` bodies contain only `FFT(...)` calls, `fft_1.CR6`/`covspa_1.CR6`, which compile
51
+ # only when `FFT` also counts as a field producer for `Table %s declared with no output
52
+ # fields.`) and is included as `FFT`.
55
53
  TABLE_ONLY_INSTRUCTIONS: dict[str, str] = {
56
54
  "CARDOUT": "CardOut", # checked with the oracle
57
55
  "MQTTPUBLISHTABLE": "MQTTPublishTable",
@@ -1223,7 +1223,7 @@ def check_data_interval(program: S.Program, profile, diags: Diagnostics, env: co
1223
1223
  per-logger difference, not shared with CR300/CR350 (`_SCAN_VALUE_CHECK_LOGGERS`; found the
1224
1224
  same way as `check_scan_params`'s own CR300/CR350 gate, same session).
1225
1225
  - `DataTable interval %d uSec not integrally divisible by scan interval %d uSec.` (function
1226
- `FUN_004f6540`) -- project knowledge (`knowledge/crbasic/lessons.md` "`DataInterval` versus
1226
+ `FUN_004f6540`) -- project knowledge (open-crbasic-skills `lessons.md` "`DataInterval` versus
1227
1227
  `Scan`": "a table interval must be at least the scan interval and an exact integer multiple
1228
1228
  of it", human-verified against `CR6Comp.exe`), reported at each `CallTable <name>` site whose
1229
1229
  table has a `DataInterval` and which sits directly inside a `Scan...NextScan` block (main
@@ -2186,7 +2186,7 @@ def check_pass2(
2186
2186
  "Before `BeginProg`" only means the top level of the program, never a statement lexically
2187
2187
  inside a `Sub`/`Function` body (regardless of that body's own textual position, almost always
2188
2188
  before `BeginProg` itself, `docs/checker.md` "Pass model": found as a **regression** against
2189
- this repository's own `crbasic/Main.CR6` and several siblings, all of which call a built-in
2189
+ the station corpus's `Main.CR6` and several siblings, all of which call a built-in
2190
2190
  function bare, with no `Call` keyword, e.g. `SerialOpen(...)` inside a `Function`/`Sub` defined
2191
2191
  above `BeginProg` -- perfectly ordinary CRBasic, since the body only executes when the
2192
2192
  `Sub`/`Function` is later called from inside `Scan`/`NextScan`, oracle-reconfirmed by re-running
@@ -5120,8 +5120,7 @@ def _check_array_dims(stmt: S.Declaration, diags: Diagnostics, env: consteval.En
5120
5120
  separate variables of the same declaration.
5121
5121
 
5122
5122
  A dimension that does not fold to a constant at all (`NotConstant`) is left alone: no oracle
5123
- evidence this session found supports guessing at that shape, and AGENTS.md's priority (never
5124
- reject an accepted program) rules out it.
5123
+ evidence supports guessing at that shape, and a guess could reject an accepted program.
5125
5124
  """
5126
5125
  for index, v in enumerate(stmt.vars):
5127
5126
  before = len(diags.items)
@@ -5779,24 +5778,17 @@ def _check_alias_dims(
5779
5778
  check in this project) into a single **row-major flat offset** (`_alias_flat_offset`:
5780
5779
  `flat = i_n + sum_{k<n} (i_k - 1) * prod(d_{k+1..n})`, the ordinary multi-dimensional-array-
5781
5780
  as-flat-buffer formula, last index varying fastest) that must land in `[1,
5782
- prod(all declared dims)]`. Round 6's own original account of this check ("only the *first*
5783
- index is ever checked, however far out of range a later one is") is **superseded**: it was
5784
- built from two probes (`Public grid(3,3)`: `Alias grid(2,4) = Ts` compiles, `Alias grid(4,2)
5785
- = Ts` fails) that happen to *also* agree with the flat-offset formula purely by coincidence
5786
- (`(2-1)*3+4=7` and `(4-1)*3+2=11`, both landing on the correct side of `[1,9]` for unrelated
5787
- reasons) -- a fresh, wider oracle sweep this round (`docs/checker.md` "Round 7") found the
5788
- "first index alone" account is wrong in general: `Alias grid(4,-2) = Ts` (first index `4`,
5789
- out of `[1,3]` by the old account) **compiles clean** (`(4-1)*3+(-2)=7`, in `[1,9]`), while
5790
- `Alias grid(2,-1) = Ts` (a valid first index, an out-of-range *second* index by the old
5791
- account, which the old rule never checked at all) also compiles clean
5792
- (`(2-1)*3+(-1)=2`, in `[1,9]`) -- both correctly predicted by the flat formula, neither by
5793
- "only check position 0". A **scalar** (no declared dimensions at all) behaves exactly like a
5781
+ prod(all declared dims)]`. Oracle evidence (`docs/checker.md` "Round 7"), for
5782
+ `Public grid(3,3)`: `Alias grid(2,4) = Ts` compiles (`(2-1)*3+4=7`), `Alias grid(4,2) = Ts`
5783
+ fails (`11`), and `Alias grid(4,-2) = Ts` (`7`) and `Alias grid(2,-1) = Ts` (`2`) both
5784
+ compile clean: the first index is not checked on its own. A **scalar** (no declared
5785
+ dimensions at all) behaves exactly like a
5794
5786
  size-1 array (`Public y` / `Alias y(1) = Ts` compiles, `Alias y(2) = Ts` fails: flat
5795
5787
  formula with `dims=(1,)` reduces to `flat=i1`, range `[1,1]`), which is why `declared_all_
5796
5788
  dims` maps every declared variable, not just array ones, the same convention `dim0_sizes`
5797
5789
  already used. Skipped (no check at all, under-reporting only) when any declared dimension or
5798
5790
  any index argument does not fold to a constant (`declared_all_dims`/the tuple-folding loop
5799
- below, both AGENTS.md-conservative the same way check 3 already was) or when the index
5791
+ below, both conservative the same way check 3 is) or when the index
5800
5792
  tuple's own length does not match the variable's own declared dimension count (no oracle
5801
5793
  evidence gathered for that shape either way).
5802
5794
  3. **`Duplicate Alias`** (round 7; no trailing period, no echoed name): the source side's own
@@ -1,8 +1,8 @@
1
1
  """Per-logger analog-channel and port terminal model.
2
2
 
3
- Generalises the analog-channel range check (originally CR6-only, hard-coded `U1..U12`) across all
4
- four loggers, driven by oracle-probed per-logger data (`data/<logger>/terminals.json`; evidence,
5
- probes and the message-text differences: `docs/loggers.md`, `docs/instructions.md`).
3
+ Models the analog-channel range check for all four loggers, driven by oracle-probed per-logger
4
+ data (`data/<logger>/terminals.json`; evidence, probes and the message-text differences:
5
+ `docs/loggers.md`, `docs/instructions.md`).
6
6
 
7
7
  Each logger's `terminals.json` names its own channel "kinds" -- CR6 has separate `u_terminal`
8
8
  (single-ended-shaped: any `U1..U12`, no oddness constraint; `ACPower`, `CS616`'s `CS616Chan`,
@@ -405,15 +405,10 @@ def check_background_calibration(program: S.Program, profile: Profile, diags: Di
405
405
  `Invalid symbol in expression` error present (`Delay never reached at run time.` alongside it,
406
406
  same probe file). A warning-only file (no errors, e.g. a reachability warning with no error
407
407
  anywhere) still gets *both* warnings together, confirming this is specifically errors, not "any
408
- diagnostic", that gates it. Moved to `checker/__init__.py`'s own final `if not diags.errors:`
409
- tier (alongside `warnings.check`/`tables_hook.attach`, the same "only on an otherwise-clean
410
- compile" gate already used there) instead of `check_early`'s unconditional call site -- this is
411
- the only change; the rule and message above are unchanged. Found as a side effect of developing
412
- `instr_rules.check_scan_min_interval` (this round): dozens of pre-existing `false_accept`/
413
- `message_diff` fuzz reproducers (`tests/corpus/fuzz/cr6/message_diff/ba333c2ee146.CR6` and
414
- siblings) already showed this exact extra, spurious warning line alongside an unrelated real
415
- error -- a genuine, previously-undocumented false-accept-shaped bug independent of this round's
416
- own `Scan`-interval work, not a regression it introduced.
408
+ diagnostic", that gates it. It is therefore called from `checker/__init__.py`'s final
409
+ `if not diags.errors:` tier (alongside `warnings.check`/`tables_hook.attach`), not from
410
+ `check_early`'s unconditional call site. Fuzz reproducers such as
411
+ `tests/corpus/fuzz/cr6/message_diff/ba333c2ee146.CR6` cover the gate.
417
412
  """
418
413
  data = profile.background_calibration
419
414
  if not data:
@@ -147,7 +147,7 @@ def _ambiguous_names(program: S.Program) -> set[str]:
147
147
  def _numeric_concatenation(program: S.Program, profile) -> list[Finding]:
148
148
  """OCB002: a String `+` (or `&`) assigned to a numeric variable (`L = 2000 + Mid(S,5,2)`). The
149
149
  reference accepts it, but `+` with a String operand concatenates, and the variable receives
150
- the converted text: a GPS clock set this way read 2057 (`knowledge/crbasic/lessons.md` "`+` with
150
+ the converted text: a GPS clock set this way read 2057 (open-crbasic-skills `lessons.md` "`+` with
151
151
  a string operand concatenates", hardware 2026-10-22). Only a chain mixing numeric and String
152
152
  operands is reported: a String alone (`X = Mid(...)`) is a plain conversion, and Strings joined
153
153
  into a number's text (`X = HexStr(6) + "." + HexStr(7)`, GEUS programs) are deliberate."""
@@ -263,8 +263,8 @@ def _zero_divisors(program: S.Program, profile) -> list[Finding]:
263
263
 
264
264
  def _unsized_string_parameters(program: S.Program, profile) -> list[Finding]:
265
265
  """OCB005: a `Sub`/`Function` String parameter without `* size`. It holds 23 characters (24
266
- bytes with the terminator) and a longer argument is cut (hardware, `knowledge/crbasic/
267
- lessons.md` "Default string parameter size"). Information only: a short argument is fine."""
266
+ bytes with the terminator) and a longer argument is cut (hardware, open-crbasic-skills
267
+ `lessons.md` "Default string parameter size"). Information only: a short argument is fine."""
268
268
  return [
269
269
  Finding(
270
270
  "OCB005",
@@ -284,7 +284,7 @@ def _unsized_string_parameters(program: S.Program, profile) -> list[Finding]:
284
284
  def _unaligned_intervals(program: S.Program, profile) -> list[Finding]:
285
285
  """OCB006: a constant `DataInterval` that divides neither an hour nor a day (`7 Min`, `25 Hr`).
286
286
  Its records are phased from the start hour and may not align with midnight (hardware,
287
- `knowledge/crbasic/lessons.md` "`DataInterval` phase"). Information only; an interval of 0
287
+ open-crbasic-skills `lessons.md` "`DataInterval` phase"). Information only; an interval of 0
288
288
  (every call) is not reported."""
289
289
  env, out = _const_env(program, profile), []
290
290
  for st in _statements(program):
@@ -142,7 +142,7 @@ def _message_bytes(lines: list[str]) -> bytes:
142
142
  """`lines` joined the way the message file actually wants them: CRLF throughout, except the
143
143
  blank line straight after a `-- Compile Failed!` header, which the real exe writes as a bare
144
144
  LF (oracle-confirmed on both a plain failing compile and a `-t`/`-b` one, `docs/cli.md`
145
- "Message file layout" -- previously assumed to be a uniform CRLF join, which this replaces).
145
+ "Message file layout").
146
146
  """
147
147
  if len(lines) >= 2 and lines[1] == "" and lines[0].endswith("Failed!"):
148
148
  return (lines[0] + "\r\n\n" + "\r\n".join(lines[2:]) + "\r\n").encode("latin-1", "replace")
@@ -156,7 +156,7 @@ class CompileResult:
156
156
  # no-line `-u` warning, regardless of which included file declared it, prints before every
157
157
  # "table declared but never called" warning). `_no_line_kind` below reproduces that
158
158
  # ordering by message shape rather than by which module raised it, so this stays correct
159
- # without `checker/warnings.py` (a concurrently-owned module) needing to tag its own
159
+ # without `checker/warnings.py` needing to tag its own
160
160
  # diagnostics; a stable sort keeps each kind's own relative (insertion) order within itself.
161
161
  # On one line the reachability warning follows that line's errors (oracle: 15 of 15 corpus
162
162
  # and fuzz transcripts); other warnings keep their check order.
@@ -1,21 +1,21 @@
1
- # Test corpora
2
-
3
- | Directory | Contents | In git |
4
- |---|---|---|
5
- | `firnmelt/` | The FirnMelt station programs and libraries, a snapshot of `crbasic/` in [firnmelt-station](https://github.com/UtrechtUniversity/firnmelt-station) at monorepo commit `bd4c30c1` (2026-11-01). Tests pin results to these exact files, so refresh them only together with the expectations. | yes |
6
- | `fuzz/` | Saved fuzz reproducers seeded from `firnmelt/`, replayed by `tools/fuzz_replay.py`. | yes |
7
- | `chm/` | The 507 complete example programs in Campbell's CRBasic help. | no |
8
- | `../../examples/Logger Programs/` | The 66 GEUS station programs used as a CR1000X corpus. | no |
9
-
10
- The help examples and GEUS programs belong to others and are not redistributed
11
- ([docs/legal.md](../../docs/legal.md)). Tests that need them skip when they are absent. To run
12
- those tests locally:
13
-
14
- 1. Extract the CRBasic help (the `.chm` installed with CRBasic Editor) into `extracted_chm/` at the
15
- repository root, for example with `7z x CRBasic.chm -oextracted_chm`.
16
- 2. `uv run python tools/extract_chm_examples.py` writes `tests/corpus/chm/`.
17
- 3. Put the GEUS programs, if you have them, in `examples/Logger Programs/`.
18
- 4. For the differential tools, copy the Campbell compilers into `compiler/` (README, "How it was
19
- built").
20
-
21
- All of these paths are git-ignored.
1
+ # Test corpora
2
+
3
+ | Directory | Contents | In git |
4
+ |---|---|---|
5
+ | `station/` | A field station's CR6 programs and libraries (2026-11-01 snapshot). Tests pin results to these exact files, so refresh them only together with the expectations. | yes |
6
+ | `fuzz/` | Saved fuzz reproducers seeded from `station/`, replayed by `tools/fuzz_replay.py`. | yes |
7
+ | `chm/` | The 507 complete example programs in Campbell's CRBasic help. | no |
8
+ | `../../examples/Logger Programs/` | The 66 GEUS station programs used as a CR1000X corpus. | no |
9
+
10
+ The help examples and GEUS programs belong to others and are not redistributed
11
+ ([docs/legal.md](../../docs/legal.md)). Tests that need them skip when they are absent. To run
12
+ those tests locally:
13
+
14
+ 1. Extract the CRBasic help (the `.chm` installed with CRBasic Editor) into `extracted_chm/` at the
15
+ repository root, for example with `7z x CRBasic.chm -oextracted_chm`.
16
+ 2. `uv run python tools/extract_chm_examples.py` writes `tests/corpus/chm/`.
17
+ 3. Put the GEUS programs, if you have them, in `examples/Logger Programs/`.
18
+ 4. For the differential tools, copy the Campbell compilers into `compiler/` (README, "How it was
19
+ built").
20
+
21
+ All of these paths are git-ignored.
File without changes
File without changes