Repository navigation
Conversation
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
DeusData
left a comment
There was a problem hiding this comment.
Thank you, @SarletteD. This is a very carefully built first slice. A few things make a language foundation reviewable, and you did all of them:
- vendoring the grammar unmodified (every file is byte-identical to upstream
00e24f50f8de, which made provenance trivial to verify); - keeping
extract_base_classesbyte-identical by routing ST throughclass_base_names; - fixing the stale count strings the contract test can't see;
- backing it all with a public proof on ThorstenBrach/SRCI at a pinned commit.
The 1a->1d table also makes it clear what this slice does and doesn't claim.
A few things before it lands:
-
Gate
.stby content..stis shared with Pharo/Tonel (*.class.st), GNU Smalltalk and StringTemplate; even GitHub's own classifier labels SRCI as Smalltalk. Graph quality comes first here, so we'd like a small content check followingcbm_disambiguate_m/cls/frminsrc/discover/language.c. Route a.stfile to ST only when its head carries an IEC POU keyword (PROGRAM,FUNCTION_BLOCK,FUNCTION,TYPE,INTERFACE,CLASS... as you see fit), and otherwise leave it unindexed. That way a Pharo repository doesn't pick up a pile of partial parses. A test with a Smalltalk-shaped.stfile asserting it is not indexed as ST would pin it. -
Credit for @ysfsmet in the history. Thank you for crediting #1810 in the description. The extraction commit follows #1810's design closely in three places:
- collecting every repeated
extends/implementsfield; - answering
find_class_bodywith the declaration node; - the
variable_declarationbinding row, withinitial_valuekept as a read.
PR descriptions don't survive in
git log, so could you addCo-authored-by: Yusuf S. Demirci <ysf-samet@outlook.com>to 4c7bc08? That keeps the credit with the code, the way we credited earlier groundwork in #2083. - collecting every repeated
-
MANIFEST.md:39says the dialect "is normalized ininternal/cbm/st_dialect.c", but that file arrives with 1b. The manifest is the ledger we audit vendoring against, so it should describe this tree. Could you move that sentence to 1b and regeneratevendored-checksums.txt? -
Merge order: we'll take #2396 first, and this sits cleanly on top.
Optional:
st_type_alias_keeps_its_nameexercises a STRUCT, so a rename (or an extraTYPE T : INT; END_TYPEcase) would match its name.- A named
st_binding_nodesarray would read like the neighbouring rows. - A question for the series: calls made directly in a FUNCTION_BLOCK/PROGRAM body seem to fall back to the file's Module node. If 1c changes that, great; otherwise a test pinning the intended source node would help.
- IEC identifiers are also case-insensitive while resolution is case-sensitive, which is worth keeping in mind for the resolution PRs.
Thank you again for picking this up so generously, and for splitting it so cleanly.
4c7bc08 to
91b215a
Compare
|
Thank you for the careful review, @DeusData. All four points are addressed; the branch is rebased on 1. 2. Credit. 3. MANIFEST.md. In this PR the 4. Merge order. Thanks for taking #2396; this branch is rebased onto Optional points
Checks (WSL2, same machine as the PR text): focused suites ( The PR description is refreshed accordingly (proof table, MANIFEST line, the Written with Claude Code (Anthropic) on behalf of @SarletteD. |
|
Thanks for addressing the Structured Text review points, preserving the groundwork credit, and updating the real-project table. I have read the follow-up; the revised first slice remains pending maintainer re-review. No additional scope is requested here. |
91b215a to
c7b113e
Compare
Vendors HeytalePazguato/tree-sitter-iec61131-3-st @ 00e24f50f8de (MIT,
(c) 2026 Jorge Centeno) unmodified as CBM_LANG_ST and registers it on
.st, with lang_specs node types for functions and methods, the
class-like POUs (FUNCTION_BLOCK, PROGRAM, INTERFACE, TYPE), properties,
calls, USING imports, branches, variables and assignments.
.st is also used by Smalltalk (Pharo/Tonel class files, GNU Smalltalk)
and StringTemplate, so the extension alone does not decide: like .m,
.cls and .frm, a .st file is routed by content, in the shared
cbm_language_classify() rule, so discovery and the test-impact
inventory agree. The probe reads the first 16 KB, skips a UTF-8 BOM, IEC comments ((* *), //, and
C-style block comments) and {...} pragmas, and accepts the file only
when its first token is an IEC declaration keyword (PROGRAM,
FUNCTION_BLOCK, FUNCTION, INTERFACE, CLASS, TYPE, NAMESPACE,
CONFIGURATION, VAR_GLOBAL, USING, or an ABSTRACT/FINAL/INTERNAL
modifier) followed by a name. Anything else, and a read failure, stays
unindexed. The name requirement keeps out "Class {" (Tonel) and
"program(x) ::=" (StringTemplate).
Vendoring: the grammar's LICENSE next to it, a THIRD_PARTY.md entry, a
MANIFEST.md paragraph and table row, regenerated
scripts/vendored-checksums.txt. The language-count surfaces that still
state a number move from 162 to 163 (README and the chocolatey nuspec),
and THIRD_PARTY.md, which still read 160 at the base, is corrected as
well.
Wired like the other languages: the language-name table in
userconfig.c, a grammar-regression fixture with its label golden, an
extension test, and the two ST call-node kinds plus the ST
routine-argument case in the call-node and language-registry repro
tests (the manifest assert message now states its real count). The
content gate is tested in the language suite (Tonel, GNU Smalltalk and
StringTemplate heads, a long comment header, each declaration head)
and end to end in the discovery suite.
Out of scope here: ST-specific definition and usage extraction, vendor
dialect normalization and the member layout of vendor exports; they
follow in separate changes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Sarlette <282189207+SarletteD@users.noreply.github.com>
- extract_defs.c: st_base_classes() collects every base named by a repeated `extends`/`implements` field on a FUNCTION_BLOCK or INTERFACE (the generic first-match field probe keeps only one); class_base_names() dispatches ST there and every other language to the unchanged extract_base_classes(). find_class_body() returns the declaration node itself for ST before the generic "body" field probe runs, so a trailing body statement tagged with that field name no longer hides the block's METHOD, PROPERTY and VAR members. - extract_usages.c: occurrence_specs[CBM_LANG_ST] binds the names of a variable_declaration (its plural `names` field), so declared VAR names are bindings, not usages; a declaration's `initial_value` stays an ordinary read (is_non_binding_decl_field() now holds that check together with the existing `type` field check). - extract_unified.c: the body of a FUNCTION_BLOCK or PROGRAM is the code that runs when the block is called, so inside one, calls and reads source to the block (its Class node) instead of the file's Module node; METHODs keep their own scope. - tests: the ST label golden now counts the block's METHOD as a Method (it was a Function while the block body was misread); function-block members, members before a trailing body statement, interface members, a STRUCT type and a type alias keeping their names, body calls and VAR type reads sourcing to their block, declared names vs. type and initializer usages, and every EXTENDS/IMPLEMENTS base collected. Co-authored-by: Yusuf S. Demirci <ysf-samet@outlook.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Sarlette <282189207+SarletteD@users.noreply.github.com>
998de5f to
7586283
Compare
|
Thank you again for addressing the Structured Text review and preserving the groundwork credit. The revised first slice is still waiting on our re-review, without additional scope requested. Sorry for the delay—I’ll follow up soon. |
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
Thank you so much, @SarletteD, for the careful rebase and for moving the .st check into the shared language classifier yourself - that was exactly the port we had in mind, and the new probe and classify tests make it easy to trust. We re-checked the vendored grammar against upstream (all six files identical to the upstream main tip, MIT, LICENSE vendored) and the recounted MANIFEST and checksums, and everything lines up. Main has moved since your last push, including changes in several files this PR touches, so we merged current main into your branch (one signed-off merge commit; it merged cleanly and your commits are untouched). The required checks will now run against today's tree. If you push to this branch again, please pull first so the merge commit is kept. We will come back here once CI is green. |
Refs #1810. Based on
main(the prerequisite #2396 is merged). This is the first of four Structured TextPRs (1a language, 1b dialect normalizer, 1c export layout, 1d real-world dialect).
What does this PR do?
Adds IEC 61131-3 Structured Text as
CBM_LANG_STon.st, with the vendored grammarHeytalePazguato/tree-sitter-iec61131-3-st
@
00e24f50f8de(MIT, (c) 2026 Jorge Centeno), a content gate for the shared.stextension, and theST-specific extraction the graph needs:
language.c/discover.c:.stis also used by Smalltalk (Pharo/Tonel, GNU Smalltalk) andStringTemplate, so like
.m/.cls/.frm/.resit is routed by content.cbm_disambiguate_streads the first 16 KB, skips a UTF-8 BOM, IEC comments (
(* *),//, C-style block comments) and{...}pragmas, and accepts the file only when its first token is an IEC declaration keyword(
PROGRAM,FUNCTION_BLOCK,FUNCTION,INTERFACE,CLASS,TYPE,NAMESPACE,CONFIGURATION,VAR_GLOBAL,USING, or anABSTRACT/FINAL/INTERNALmodifier) followed by a name. Anything else,and a read failure, stays unindexed.
lang_specs.c: node types for functions/methods (method_signaturefor INTERFACE members), theclass-like POUs (FUNCTION_BLOCK, PROGRAM, INTERFACE,
type_definition), properties, calls(
call_expression,invocation_statement),USINGimports, branches, variables, assignments.extract_defs.c: every base ofEXTENDS/IMPLEMENTSis collected byst_base_classes(the grammarrepeats the field per base, the generic probe kept one); a small
class_base_namesdispatches ST thereand leaves
extract_base_classesunchanged;find_class_bodyanswers ST before the genericbodyprobe,which would otherwise take a trailing body statement for the member container.
extract_usages.c: declared VAR names bind (pluralnamesfield, namedst_binding_nodesrow), adeclaration's
initial_valuestays a read; that check and the existingtype-field check now shareone helper,
is_non_binding_decl_field.extract_unified.c: the body of a FUNCTION_BLOCK or PROGRAM is the code that runs when the block iscalled, so its calls and reads source to the block (its Class node) instead of the file's Module node;
METHODs keep their own scope (
st_enter_block_body, called afterpush_boundary_scopes).Credit: @ysfsmet for the ST groundwork and the discussion in #1810; the extraction commit carries his
Co-authored-bytrailer.In scope / out of scope
extraction and the body-call source node, tests.
END_FUNCTION_BLOCK(1c), the remaining real-world dialect (1d). Without them most real exports parseonly partially (see the table: 86 % of the proof project's files at this stage).
Vendoring checklist
internal/cbm/vendored/grammars/st/LICENSE(MIT, upstream text)THIRD_PARTY.mdentryinternal/cbm/vendored/grammars/MANIFEST.md: paragraph + table row + recounted summary/ABI lines;the paragraph says "Vendored unmodified." (the normalizer sentence arrives with 1b)
scripts/vendored-checksums.txtregenerated;make -f Makefile.cbm securitypassesnuspec, scripts/package-release.sh, server.json. Four places that still read 158 on
main(README.md, docs/index.html twice, docs/llms.txt) are corrected too; the language-count contract
regex does not cover them.
LANG_NAME_TABLEinuserconfig.c, aCBM_GRAMMAR_CASESfixture, aLABEL_GOLDENSrow,lang_ext_st, call-node manifest and languageregistry repro rows (the manifest assert message now states the real count).
Commits
feat(lang): add IEC 61131-3 Structured Text (.st)(e084b1c)feat(st): extract definitions, bases and usages from .st(91b215a)Size
Production +284 / -8 (
language.c+108,discover.c/.h+15,lang_specs.c+39, other registration+6,
extract_defs.c+63 / -1,extract_usages.c+29 / -7,extract_unified.c+24), tests +435 / -16,docs and metadata +64 / -30 (including MANIFEST.md and
vendored-checksums.txt), vendored grammar+97,336 (generated
parser.cand friends, excluded from review size). Per commit: language +168 prod /+189 -11 test; extraction +116 / -8 prod, +246 / -5 test.
Checks
extraction grammar_regression grammar_labels language lang_contract discover): allpass except the known environment failure
test_extraction.c: sp is NULL(WSL/tmpis a 7.8 GB tmpfs;mainfails identically): 730 PASS lines on the first commit alone, 737 on the secondscripts/lint.sh --ci(clang-format 20, cppcheck 2.20): rc 0lint-tidy-diff(clang-tidy 21.1.6, diff againstmain): one finding, in upstream code the change hasto touch:
is_binding_occurrenceis over the cognitive-complexity threshold onmain(33). This PRlowers it to 32 (the
type-field check and the STinitial_valuecheck now shareis_non_binding_decl_field), but the diff-scoped run still reports the function because a changedline sits inside it.
extract_base_classes,push_boundary_scopesanddetect_file_languagekeeptheir
maincomplexity (the new logic lives in small helpers next to them).make -f Makefile.cbm security: rc 0 (vendored checksums match)scripts/test.shstops at its static step 0x onmainas well:tests/test_version_metadata_contract.shreports
pkg/scoop/codebase-memory-mcp.json is pinned at 0.11.0, which is now the newest release(pre-existing, unrelated to this PR); the language-count contract (163) passes.
Proof on a real project
.stfilesmain@ 80eb92aMachine: Linux 6.18.33.2-microsoft-standard-WSL2 x86_64 (WSL2 on Windows 11), 13th Gen Intel Core i9-13950HX, 32 logical CPUs, 15 GiB RAM visible to WSL. Release CLI (
make -f Makefile.cbm cbm, -O2),cli index_repositoryon ThorstenBrach/SRCI @ 67fd773 (956.stfiles, all of which pass the content gate at every stage), freshCBM_CACHE_DIRandCBM_RUNTIME_DIRper run, median of 3 wall-clock runs, nothing else running. Wall time includes process start and the non-ST files; it stays flat because the ST files are small (it is higher than in the first revision of this text formaintoo, so the machine, not the change, moved).Edges by type, 1a -> 1b: USAGE 4923 -> 4774. 1b -> 1c: CALLS 104 -> 4007, DEFINES_METHOD 2 -> 1606, USAGE 4774 -> 5803, WRITES 0 -> 460, OVERRIDE 0 -> 401. 1c -> 1d: DEFINES 3740 -> 3803 (types that parse now), USAGE 5803 -> 5765 (struct field names no longer read as usages).
Changes against the first revision of this table (review round 1): the
.stcontent gate admits all 956 files, so files, nodes and partial counts are unchanged at every stage. Edges move only because FUNCTION_BLOCK/PROGRAM body calls and reads now source to the block instead of the Module: at 1a +242 USAGE edges (4681 -> 4923; 242 targets in 119 files are now used both from the block and from the Module, the latter by METHODs exported afterEND_FUNCTION_BLOCKthat 1a cannot attach yet; no new targets), at 1b +262. From 1c on the counts per type are unchanged except SEMANTICALLY_RELATED 123 -> 109 (derived from the moved sources; not investigated further); the sources move: at 1c CALLS Module 24 -> Class 24, USAGE Module 1483 -> Class 806 + Module 677, WRITES Module 8 -> Class 8. Wall times of this revision were measured on a busier machine than the first (main itself 7.67 s then, 9.87 s now) and are noisy; compare within the column.Known limitations (this stage)
unindexed. A non-ST
.stfile that happens to open with, say,Program Foowould still be taken as ST.Written with Claude Code (Anthropic) on behalf of @SarletteD, who reviewed and signs off every commit.