mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-10-12 04:31:02 +08:00
fix(pkl): register call nodes in the ledgers and bind Pkl declarations
Merging main brought in three contracts this branch violated. repro_call_node_manifest requires a table row for every live call_node_types entry, so Pkl's unqualifiedAccessExpr/qualifiedAccessExpr (direct) and newExpr (constructor) each get one, with the partition totals moved to match. The historical-snapshot column is the audited ledger, not an archaeology record -- the suite hard-fails on a row that claims it was absent -- so a newly registered kind joins the snapshot with the change that registers it. repro_language_registry then requires every call-capable language to own exactly one call-argument matrix row, which turned out to be a real extractor gap rather than a bookkeeping entry. Pkl's grammar labels no production with a `name` field, so the generic declared-container rule never recognised a Pkl binding: method names, parameter names, and property names were each re-emitted as an ordinary read of themselves, which Go and Nickel do not do. Add a Pkl occurrence policy that binds the declared identifier of methodHeader, typedIdentifier, classProperty, objectProperty, clazz, and typeAlias, resolved against the nearest such container so annotations, defaults, and bodies stay reads. Recording the binding also supplies the lexical-shadow proof the matrix row asserts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Tony Thayer-Osborne <tony.thayerosborne@conductorone.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1d6a140f23
commit
7b72652a58
@@ -377,6 +377,7 @@ typedef enum {
|
||||
CBM_OCCURRENCE_VHDL_INTERFACE,
|
||||
CBM_OCCURRENCE_PINE_FUNCTION,
|
||||
CBM_OCCURRENCE_LLVM_FUNCTION,
|
||||
CBM_OCCURRENCE_PKL_DECLARATION,
|
||||
} CBMOccurrencePolicy;
|
||||
|
||||
typedef struct {
|
||||
@@ -495,6 +496,7 @@ static const CBMOccurrenceSpec occurrence_specs[CBM_LANG_COUNT] = {
|
||||
[CBM_LANG_PINE] = {NULL, NULL, CBM_OCCURRENCE_PINE_FUNCTION, false},
|
||||
[CBM_LANG_PUPPET] = {NULL, NULL, CBM_OCCURRENCE_STANDARD, true},
|
||||
[CBM_LANG_LLVM_IR] = {llvm_binding_nodes, NULL, CBM_OCCURRENCE_LLVM_FUNCTION, false},
|
||||
[CBM_LANG_PKL] = {NULL, NULL, CBM_OCCURRENCE_PKL_DECLARATION, false},
|
||||
[CBM_LANG_MESON] = {NULL, meson_write_nodes, CBM_OCCURRENCE_STANDARD, true},
|
||||
[CBM_LANG_GN] = {NULL, gn_write_nodes, CBM_OCCURRENCE_STANDARD, true},
|
||||
[CBM_LANG_LINKERSCRIPT] = {NULL, linkerscript_write_nodes, CBM_OCCURRENCE_STANDARD, true},
|
||||
@@ -988,6 +990,30 @@ static bool is_pine_function_binding(TSNode node) {
|
||||
return ancestor_field_binds(node, "function_declaration_statement", fields);
|
||||
}
|
||||
|
||||
/* Pkl declares names positionally: no production labels the declared identifier
|
||||
* with a `name` field, so the generic declared-container rule never binds them
|
||||
* and every method name, parameter name, and property name would be re-emitted
|
||||
* as an ordinary read of itself. Each container below holds its declared name
|
||||
* as named child 0; annotations, defaults, and bodies follow it and stay reads.
|
||||
* Resolve against the NEAREST container so a nested declaration's own name is
|
||||
* the only occurrence its parent can bind. */
|
||||
static bool is_pkl_declaration_binding(TSNode node) {
|
||||
static const char *const declaration_kinds[] = {"methodHeader",
|
||||
"typedIdentifier",
|
||||
"classProperty",
|
||||
"objectProperty",
|
||||
"clazz",
|
||||
"typeAlias",
|
||||
NULL};
|
||||
for (TSNode parent = ts_node_parent(node); !ts_node_is_null(parent);
|
||||
parent = ts_node_parent(parent)) {
|
||||
if (kind_in_exact_set(ts_node_type(parent), declaration_kinds)) {
|
||||
return named_child_contains(parent, 0, node);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_policy_binding(CBMExtractCtx *ctx, TSNode node,
|
||||
const CBMOccurrenceSpec *occurrence) {
|
||||
switch (occurrence->policy) {
|
||||
@@ -1044,6 +1070,8 @@ static bool is_policy_binding(CBMExtractCtx *ctx, TSNode node,
|
||||
return is_vhdl_interface_binding(node);
|
||||
case CBM_OCCURRENCE_PINE_FUNCTION:
|
||||
return is_pine_function_binding(node);
|
||||
case CBM_OCCURRENCE_PKL_DECLARATION:
|
||||
return is_pkl_declaration_binding(node);
|
||||
case CBM_OCCURRENCE_LLVM_FUNCTION:
|
||||
for (TSNode parent = ts_node_parent(node); !ts_node_is_null(parent);
|
||||
parent = ts_node_parent(parent)) {
|
||||
|
||||
@@ -752,6 +752,12 @@ static const char TLAPLUS_BOUNDED_QUANTIFICATION[] =
|
||||
"Guard(values) == \\A item \\in values : item = item\n"
|
||||
"====\n";
|
||||
|
||||
/* Pkl access expressions double as plain property reads, so the bare fixture
|
||||
* also proves the un-applied reference is not promoted to a call. */
|
||||
static const char PKL_INSIDE[] = "function accept(value: Int): Int = value\n"
|
||||
"function run(watched: Int): Int = accept(watched)\n";
|
||||
static const char PKL_BARE[] = "function run(watched: Int): Int = watched\n";
|
||||
|
||||
static const char APEX_INSIDE[] = "public class Sample {\n"
|
||||
" private static Integer accept(Integer value) {\n"
|
||||
" return value;\n"
|
||||
@@ -977,6 +983,9 @@ static const RoutineArgumentCase LLVM_IR_CASE = ROUTINE_ARGUMENT_CASE(
|
||||
static const RoutineArgumentCase TLAPLUS_CASE = ROUTINE_ARGUMENT_CASE(
|
||||
"TLAPLUS", CBM_LANG_TLAPLUS, "Sample.tla", TLAPLUS_INSIDE, TLAPLUS_BARE, "bound_op", "Guard",
|
||||
"Accept", "values", 1, 1, 0, "TLA+ operator application with a value argument");
|
||||
static const RoutineArgumentCase PKL_CASE = ROUTINE_ARGUMENT_CASE(
|
||||
"PKL", CBM_LANG_PKL, "sample.pkl", PKL_INSIDE, PKL_BARE, "unqualifiedAccessExpr", "run",
|
||||
"accept", "watched", 1, 1, 0, "native Pkl method application and property-read vocabulary");
|
||||
static const RoutineArgumentCase APEX_CASE = ROUTINE_ARGUMENT_CASE(
|
||||
"APEX", CBM_LANG_APEX, "Sample.cls", APEX_INSIDE, APEX_BARE, "method_invocation", "run",
|
||||
"accept", "watched", 1, 1, 0, "native method application");
|
||||
@@ -1188,6 +1197,7 @@ DEFINE_ROUTINE_ARGUMENT_TEST(func, FUNC_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(puppet, PUPPET_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(slang, SLANG_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(llvm_ir, LLVM_IR_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(pkl, PKL_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(apex, APEX_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(pine, PINE_CASE)
|
||||
DEFINE_ROUTINE_ARGUMENT_TEST(qml, QML_CASE)
|
||||
@@ -1266,15 +1276,15 @@ TEST(repro_call_argument_matrix_b_domain_bitbake) {
|
||||
}
|
||||
|
||||
enum {
|
||||
ROUTINE_ARGUMENT_LANGUAGE_COUNT = 37,
|
||||
ROUTINE_ARGUMENT_LANGUAGE_COUNT = 38,
|
||||
MODULE_ARGUMENT_LANGUAGE_COUNT = 4,
|
||||
DOMAIN_CONTROL_LANGUAGE_COUNT = 6,
|
||||
MATRIX_LANGUAGE_COUNT = ROUTINE_ARGUMENT_LANGUAGE_COUNT + MODULE_ARGUMENT_LANGUAGE_COUNT +
|
||||
DOMAIN_CONTROL_LANGUAGE_COUNT,
|
||||
};
|
||||
|
||||
_Static_assert(MATRIX_LANGUAGE_COUNT == 47,
|
||||
"RACKET..PLSQL call-capable matrix must contain exactly 47 "
|
||||
_Static_assert(MATRIX_LANGUAGE_COUNT == 48,
|
||||
"RACKET..PLSQL call-capable matrix must contain exactly 48 "
|
||||
"language rows");
|
||||
|
||||
#define MATRIX_B_LANGUAGE_ROWS(X) \
|
||||
@@ -1306,6 +1316,7 @@ _Static_assert(MATRIX_LANGUAGE_COUNT == 47,
|
||||
X(repro_call_argument_matrix_b_routine_slang, SLANG_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_llvm_ir, LLVM_IR_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_tlaplus, TLAPLUS_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_pkl, PKL_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_apex, APEX_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_pine, PINE_CASE.identity.language) \
|
||||
X(repro_call_argument_matrix_b_routine_qml, QML_CASE.identity.language) \
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
* TLA+ bound_op is historical direct-call metadata. Bounded quantification is
|
||||
* not a historical ledger row; repro_call_argument_matrix_b is its separate
|
||||
* negative behavior guard.
|
||||
*
|
||||
* The historical-snapshot column is the audited ledger, not an archaeology
|
||||
* record: every registered call node owns a row, so a newly registered kind
|
||||
* (Pkl's access/new expressions) joins the snapshot with the change that
|
||||
* registers it.
|
||||
*/
|
||||
#include "test_framework.h"
|
||||
#include "lang_specs.h"
|
||||
@@ -54,10 +59,10 @@ typedef struct {
|
||||
} CallNodeManifestEntry;
|
||||
|
||||
enum {
|
||||
EXPECTED_HISTORICAL_CALL_NODE_TOTAL = 222,
|
||||
EXPECTED_ACTIVE_PRIMARY_TOTAL = 192,
|
||||
EXPECTED_DIRECT_CALLS = 157,
|
||||
EXPECTED_CONSTRUCTOR_CALLS = 21,
|
||||
EXPECTED_HISTORICAL_CALL_NODE_TOTAL = 225,
|
||||
EXPECTED_ACTIVE_PRIMARY_TOTAL = 195,
|
||||
EXPECTED_DIRECT_CALLS = 159,
|
||||
EXPECTED_CONSTRUCTOR_CALLS = 22,
|
||||
EXPECTED_OPERATOR_CALLS = 12,
|
||||
EXPECTED_IMPLICIT_CALLS = 2,
|
||||
EXPECTED_DSL_INVOCATIONS = 14,
|
||||
@@ -65,7 +70,7 @@ enum {
|
||||
EXPECTED_CALLEE_WRAPPERS = 8,
|
||||
EXPECTED_ARGUMENT_WRAPPERS = 1,
|
||||
EXPECTED_CONTROL_OR_DOCUMENT_NONCALLS = 6,
|
||||
EXPECTED_PRIMARY_OWNERS = 192,
|
||||
EXPECTED_PRIMARY_OWNERS = 195,
|
||||
EXPECTED_SYNTHETIC_OWNERS = 10,
|
||||
EXPECTED_NO_CALL_EDGE_OWNERS = 20,
|
||||
EXPECTED_PRIMARY_OPERATOR_CALLS = 4,
|
||||
@@ -296,6 +301,9 @@ static const CallNodeManifestEntry CALL_NODE_MANIFEST[] = {
|
||||
ENTRY(CBM_LANG_TLAPLUS, "function_evaluation", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_TLAPLUS, "call", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_TLAPLUS, "bound_op", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_PKL, "unqualifiedAccessExpr", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_PKL, "qualifiedAccessExpr", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_PKL, "newExpr", CONSTRUCTOR_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_APEX, "method_invocation", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_PINE, "call", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
ENTRY(CBM_LANG_MOJO, "call", DIRECT_CALL, PRIMARY_EXTRACTOR, true, true),
|
||||
|
||||
@@ -195,7 +195,7 @@ static const LanguageCapabilityEntry LANGUAGE_CAPABILITIES[CBM_LANG_COUNT] = {
|
||||
NO_CALL(SMITHY),
|
||||
NO_CALL(WIT),
|
||||
CALL_WITH_REFERENCE_VOCAB(TLAPLUS),
|
||||
NO_CALL(PKL),
|
||||
CALL_WITH_REFERENCE_VOCAB(PKL),
|
||||
NO_CALL(GOMOD),
|
||||
CALL_WITH_REFERENCE_VOCAB(APEX),
|
||||
NO_CALL(SOQL),
|
||||
@@ -300,8 +300,8 @@ TEST(repro_language_capability_ledger_covers_every_enum) {
|
||||
}
|
||||
}
|
||||
|
||||
if (counts[CAP_CALL_WITH_REFERENCE_VOCAB] != 87 ||
|
||||
counts[CAP_CALL_WITHOUT_REFERENCE_VOCAB] != 26 || counts[CAP_NO_CALL] != 50 ||
|
||||
if (counts[CAP_CALL_WITH_REFERENCE_VOCAB] != 88 ||
|
||||
counts[CAP_CALL_WITHOUT_REFERENCE_VOCAB] != 26 || counts[CAP_NO_CALL] != 49 ||
|
||||
counts[CAP_TRANSFORM_ONLY] != 1 || counts[CAP_UNSUPPORTED] != 1) {
|
||||
fprintf(stderr,
|
||||
" [language-registry] invariant=capability_partition call_ref_vocab=%d ref_gap=%d "
|
||||
@@ -318,9 +318,9 @@ TEST(repro_language_capability_ledger_covers_every_enum) {
|
||||
TEST(repro_call_argument_matrices_equal_call_capability_ledger) {
|
||||
enum {
|
||||
EXPECTED_MATRIX_A_ROWS = 68,
|
||||
EXPECTED_MATRIX_B_ROWS = 47,
|
||||
EXPECTED_CALL_CAPABLE_LANGUAGES = 113,
|
||||
EXPECTED_NON_CALL_LANGUAGES = 52,
|
||||
EXPECTED_MATRIX_B_ROWS = 48,
|
||||
EXPECTED_CALL_CAPABLE_LANGUAGES = 114,
|
||||
EXPECTED_NON_CALL_LANGUAGES = 51,
|
||||
EXPECTED_NON_CALL_DOMAIN_CONTROLS = 2,
|
||||
};
|
||||
CBMLanguage matrix_a_ids[CBM_LANG_COUNT];
|
||||
|
||||
Reference in New Issue
Block a user