feat: establish first-class lexical language parity #2

Merged
trevon merged 14 commits from feat/language-parity-foundation into bench/yams-architecture-reproducibility 2026-08-30 22:09:40 +00:00
8 changed files with 201 additions and 0 deletions
Showing only changes of commit 1935710459 - Show all commits

test(scan): add first-class language fixtures

trvon 2026-08-30 14:53:30 -06:00
Signed by: trevon
GPG key ID: 38686EA797D7A8A7

View file

@ -49,6 +49,11 @@ fixtures for:
- duplicate symbols, nested scopes, strings, comments, and unsupported syntax; - duplicate symbols, nested scopes, strings, comments, and unsupported syntax;
- stable graph identities and evidence under repeated scans. - stable graph identities and evidence under repeated scans.
The positive baseline corpus lives in `tests/fixtures/languages`, with its
shared contract in `tests/language_parity.rs`. Gap slices should extend these
fixtures with a positive construct and its nearest clean negative before
changing extraction behavior.
Real-repository benchmarks supplement these fixtures but do not replace them. Real-repository benchmarks supplement these fixtures but do not replace them.
Compare graph counts and health metrics only after confirming that analyzed Compare graph counts and health metrics only after confirming that analyzed
files, constructs, and evidence coverage remain stable. A lower health score can files, constructs, and evidence coverage remain stable. A lower health score can

13
tests/fixtures/languages/c/basic.c vendored Normal file
View file

@ -0,0 +1,13 @@
#include "support.h"
struct Worker {
int state;
};
int start() {
return helper();
}
int helper() {
return 0;
}

12
tests/fixtures/languages/cpp/basic.cpp vendored Normal file
View file

@ -0,0 +1,12 @@
#include "support.hpp"
class Worker : public Base {
public:
void start() {
helper();
}
};
int helper() {
return 0;
}

View file

@ -0,0 +1,9 @@
import 'package:example/base.dart';
class Controller extends Base {
void start() {
helper();
}
void helper() {}
}

View file

@ -0,0 +1,9 @@
import { Base } from './base.js';
class Worker extends Base {}
function start() {
helper();
}
function helper() {}

View file

@ -0,0 +1,9 @@
use crate::support::Dependency;
pub struct Worker;
pub fn start() {
helper();
}
fn helper() {}

View file

@ -0,0 +1,9 @@
import { Base } from './base.js';
class Worker extends Base {}
function start(): void {
helper();
}
function helper(): void {}

135
tests/language_parity.rs Normal file
View file

@ -0,0 +1,135 @@
use brick::model::{EdgeKind, NodeKind};
use brick::scan::scan;
use std::path::PathBuf;
struct FixtureCase {
directory: &'static str,
language: &'static str,
classes: &'static [&'static str],
functions: &'static [&'static str],
imports: usize,
inherits: usize,
calls: usize,
}
#[test]
fn first_class_language_fixtures_have_stable_baseline_evidence() {
let cases = [
FixtureCase {
directory: "dart",
language: "dart",
classes: &["Controller"],
functions: &["helper", "start"],
imports: 1,
inherits: 1,
calls: 1,
},
FixtureCase {
directory: "rust",
language: "rust",
classes: &["Worker"],
functions: &["helper", "start"],
imports: 1,
inherits: 0,
calls: 1,
},
FixtureCase {
directory: "c",
language: "cpp",
classes: &["Worker"],
functions: &["helper", "start"],
imports: 1,
inherits: 0,
calls: 1,
},
FixtureCase {
directory: "cpp",
language: "cpp",
classes: &["Worker"],
functions: &["helper", "start"],
imports: 1,
inherits: 1,
calls: 1,
},
FixtureCase {
directory: "javascript",
language: "javascript",
classes: &["Worker"],
functions: &["helper", "start"],
imports: 1,
inherits: 1,
calls: 1,
},
FixtureCase {
directory: "typescript",
language: "typescript",
classes: &["Worker"],
functions: &["helper", "start"],
imports: 1,
inherits: 1,
calls: 1,
},
];
for case in cases {
assert_fixture(case);
}
}
fn assert_fixture(case: FixtureCase) {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/languages")
.join(case.directory);
let building = scan(&root).unwrap();
let mut classes: Vec<_> = building
.nodes
.iter()
.filter(|node| {
node.language.as_deref() == Some(case.language) && node.kind == NodeKind::Class
})
.map(|node| node.name.as_str())
.collect();
let mut functions: Vec<_> = building
.nodes
.iter()
.filter(|node| {
node.language.as_deref() == Some(case.language) && node.kind == NodeKind::Function
})
.map(|node| node.name.as_str())
.collect();
classes.sort_unstable();
functions.sort_unstable();
assert_eq!(classes, case.classes, "{} class baseline", case.directory);
assert_eq!(
functions, case.functions,
"{} function baseline",
case.directory
);
assert_eq!(
edge_count(&building, EdgeKind::Imports),
case.imports,
"{} import baseline",
case.directory
);
assert_eq!(
edge_count(&building, EdgeKind::Inherits),
case.inherits,
"{} inheritance baseline",
case.directory
);
assert_eq!(
edge_count(&building, EdgeKind::Calls),
case.calls,
"{} call baseline",
case.directory
);
}
fn edge_count(building: &brick::Building, kind: EdgeKind) -> usize {
building
.edges
.iter()
.filter(|edge| edge.kind == kind)
.count()
}