Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 12 additions & 16 deletions benches/iseriser_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
// Run with:
// cargo bench --bench iseriser_bench

use criterion::{black_box, criterion_group, criterion_main, Criterion};
use criterion::{Criterion, criterion_group, criterion_main};
use iseriser::manifest::{parse_manifest, validate};
use std::hint::black_box;

// ---------------------------------------------------------------------------
// Manifest TOML fixtures
Expand Down Expand Up @@ -100,8 +101,8 @@ description = "Gleam interop -iser targeting the BEAM runtime"
fn bench_parse_minimal(c: &mut Criterion) {
c.bench_function("parse_manifest/minimal", |b| {
b.iter(|| {
let m = parse_manifest(black_box(MINIMAL_MANIFEST))
.expect("minimal manifest must parse");
let m =
parse_manifest(black_box(MINIMAL_MANIFEST)).expect("minimal manifest must parse");
black_box(m);
});
});
Expand All @@ -111,8 +112,7 @@ fn bench_parse_minimal(c: &mut Criterion) {
fn bench_parse_rich(c: &mut Criterion) {
c.bench_function("parse_manifest/rich_20_primitives", |b| {
b.iter(|| {
let m = parse_manifest(black_box(RICH_MANIFEST))
.expect("rich manifest must parse");
let m = parse_manifest(black_box(RICH_MANIFEST)).expect("rich manifest must parse");
black_box(m);
});
});
Expand All @@ -122,8 +122,7 @@ fn bench_parse_rich(c: &mut Criterion) {
fn bench_parse_gleam(c: &mut Criterion) {
c.bench_function("parse_manifest/gleam_beam_target", |b| {
b.iter(|| {
let m = parse_manifest(black_box(GLEAM_MANIFEST))
.expect("gleam manifest must parse");
let m = parse_manifest(black_box(GLEAM_MANIFEST)).expect("gleam manifest must parse");
black_box(m);
});
});
Expand All @@ -139,7 +138,8 @@ fn bench_validate_valid(c: &mut Criterion) {
c.bench_function("validate/valid_manifest", |b| {
b.iter(|| {
let result = validate(black_box(&manifest));
black_box(result.expect("valid manifest must pass validation"));
result.expect("valid manifest must pass validation");
black_box(());
});
});
}
Expand All @@ -150,7 +150,8 @@ fn bench_validate_rich(c: &mut Criterion) {
c.bench_function("validate/rich_20_primitives", |b| {
b.iter(|| {
let result = validate(black_box(&manifest));
black_box(result.expect("rich manifest must pass validation"));
result.expect("rich manifest must pass validation");
black_box(());
});
});
}
Expand Down Expand Up @@ -200,8 +201,7 @@ fn bench_scan_repo(c: &mut Criterion) {

c.bench_function("scan_repo/iseriser_root", |b| {
b.iter(|| {
let recs = iseriser::scan::scan_repo(black_box(&repo_root))
.expect("scan must succeed");
let recs = iseriser::scan::scan_repo(black_box(&repo_root)).expect("scan must succeed");
black_box(recs);
});
});
Expand All @@ -218,11 +218,7 @@ criterion_group!(
bench_parse_gleam,
);

criterion_group!(
validate_benches,
bench_validate_valid,
bench_validate_rich,
);
criterion_group!(validate_benches, bench_validate_valid, bench_validate_rich,);

criterion_group!(
abi_benches,
Expand Down
16 changes: 4 additions & 12 deletions src/abi/idris_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,9 @@ fn find_data_keyword(src: &str) -> Option<usize> {
let mut search_from = 0;
while let Some(pos) = src[search_from..].find("data") {
let abs = search_from + pos;
let before_ok = abs == 0
|| matches!(bytes[abs - 1], b'\n' | b' ' | b'\t');
let before_ok = abs == 0 || matches!(bytes[abs - 1], b'\n' | b' ' | b'\t');
let after = abs + 4;
let after_ok = after < bytes.len()
&& matches!(bytes[after], b' ' | b'\t' | b'\n');
let after_ok = after < bytes.len() && matches!(bytes[after], b' ' | b'\t' | b'\n');
if before_ok && after_ok {
return Some(abs);
}
Expand Down Expand Up @@ -292,10 +290,7 @@ fn skip_gadt_block(src: &str) -> usize {
let header_end = match where_pos {
Some(w) => {
// Consume through the rest of that line.
src[w..]
.find('\n')
.map(|i| w + i + 1)
.unwrap_or(src.len())
src[w..].find('\n').map(|i| w + i + 1).unwrap_or(src.len())
}
None => {
// No `where` — single-line `data Foo : ...`. Consume through eol.
Expand Down Expand Up @@ -372,10 +367,7 @@ fn parse_to_int_equations(src: &str) -> Result<BTreeMap<String, BTreeMap<String,
/// Extract the head variant name from a pattern like `Empty`, `(Custom _)`,
/// `Custom`. Returns `None` for `_` or empty / non-identifier patterns.
fn extract_variant_from_pattern(pattern: &str) -> Option<String> {
let p = pattern
.trim_start_matches('(')
.trim_end_matches(')')
.trim();
let p = pattern.trim_start_matches('(').trim_end_matches(')').trim();
let head_end = p.find(|c: char| !is_ident_char(c)).unwrap_or(p.len());
if head_end == 0 {
return None;
Expand Down
58 changes: 50 additions & 8 deletions src/abi/manifest_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,56 @@ pub fn to_snake_case(s: &str) -> String {
/// the cartridge convention is to rename the variant in Zig — the
/// verifier accepts the cartridge convention as a valid alternative.
const ZIG_RESERVED: &[&str] = &[
"addrspace", "align", "allowzero", "and", "anyframe", "anytype", "asm",
"async", "await", "break", "callconv", "catch", "comptime", "const",
"continue", "defer", "else", "enum", "errdefer", "error", "export",
"extern", "fn", "for", "if", "inline", "linksection", "noalias",
"noinline", "nosuspend", "null", "opaque", "or", "orelse", "packed",
"pub", "resume", "return", "struct", "suspend", "switch", "test",
"threadlocal", "try", "union", "unreachable", "usingnamespace", "var",
"volatile", "while",
"addrspace",
"align",
"allowzero",
"and",
"anyframe",
"anytype",
"asm",
"async",
"await",
"break",
"callconv",
"catch",
"comptime",
"const",
"continue",
"defer",
"else",
"enum",
"errdefer",
"error",
"export",
"extern",
"fn",
"for",
"if",
"inline",
"linksection",
"noalias",
"noinline",
"nosuspend",
"null",
"opaque",
"or",
"orelse",
"packed",
"pub",
"resume",
"return",
"struct",
"suspend",
"switch",
"test",
"threadlocal",
"try",
"union",
"unreachable",
"usingnamespace",
"var",
"volatile",
"while",
];

pub fn is_zig_reserved(word: &str) -> bool {
Expand Down
77 changes: 64 additions & 13 deletions src/abi/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,18 +279,43 @@ mod tests {
enums: vec![EnumDecl {
name: "S".into(),
variants: vec![
EnumVariant { name: "Empty".into(), value: 0 },
EnumVariant { name: "Ready".into(), value: 1 },
EnumVariant { name: "Done".into(), value: 2 },
EnumVariant {
name: "Empty".into(),
value: 0,
},
EnumVariant {
name: "Ready".into(),
value: 1,
},
EnumVariant {
name: "Done".into(),
value: 2,
},
],
}],
transition_table: Some(TransitionTable {
state_enum: "S".into(),
rows: vec![
TransitionRow { from: "Empty".into(), to: "Ready".into(), allowed: true },
TransitionRow { from: "Ready".into(), to: "Done".into(), allowed: true },
TransitionRow { from: "Done".into(), to: "Empty".into(), allowed: true },
TransitionRow { from: "Empty".into(), to: "Done".into(), allowed: false },
TransitionRow {
from: "Empty".into(),
to: "Ready".into(),
allowed: true,
},
TransitionRow {
from: "Ready".into(),
to: "Done".into(),
allowed: true,
},
TransitionRow {
from: "Done".into(),
to: "Empty".into(),
allowed: true,
},
TransitionRow {
from: "Empty".into(),
to: "Done".into(),
allowed: false,
},
],
}),
}
Expand Down Expand Up @@ -331,8 +356,18 @@ mod tests {
}
"#;
let z = parse_zig(src).unwrap();
let report = verify(&make_manifest(), &z, Path::new("m.json"), Path::new("z.zig"));
assert!(report.findings.iter().any(|f| f.kind == "variant-value-mismatch"));
let report = verify(
&make_manifest(),
&z,
Path::new("m.json"),
Path::new("z.zig"),
);
assert!(
report
.findings
.iter()
.any(|f| f.kind == "variant-value-mismatch")
);
}

#[test]
Expand All @@ -348,9 +383,17 @@ mod tests {
}
"#;
let z = parse_zig(src).unwrap();
let report = verify(&make_manifest(), &z, Path::new("m.json"), Path::new("z.zig"));
let report = verify(
&make_manifest(),
&z,
Path::new("m.json"),
Path::new("z.zig"),
);
assert!(
report.findings.iter().any(|f| f.kind == "transition-forbidden-but-accepted"),
report
.findings
.iter()
.any(|f| f.kind == "transition-forbidden-but-accepted"),
"{:#?}",
report.findings
);
Expand All @@ -369,9 +412,17 @@ mod tests {
}
"#;
let z = parse_zig(src).unwrap();
let report = verify(&make_manifest(), &z, Path::new("m.json"), Path::new("z.zig"));
let report = verify(
&make_manifest(),
&z,
Path::new("m.json"),
Path::new("z.zig"),
);
assert!(
report.findings.iter().any(|f| f.kind == "transition-accepted-but-undeclared"),
report
.findings
.iter()
.any(|f| f.kind == "transition-accepted-but-undeclared"),
"{:#?}",
report.findings
);
Expand Down
14 changes: 6 additions & 8 deletions src/abi/zig_ffi_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ fn parse_enum_body(body: &str) -> Result<BTreeMap<String, i64>> {
.next()
.ok_or_else(|| anyhow!("variant `{}` missing `= <int>` value", name))?
.trim();
let value: i64 = value_str
.parse()
.with_context(|| format!("variant `{}` value `{}` is not an integer", name, value_str))?;
let value: i64 = value_str.parse().with_context(|| {
format!("variant `{}` value `{}` is not an integer", name, value_str)
})?;
if variants.insert(name.clone(), value).is_some() {
return Err(anyhow!("duplicate variant `{}` in enum body", name));
}
Expand Down Expand Up @@ -148,8 +148,7 @@ fn parse_transition_table(src: &str) -> Result<Option<ZigTransitionTable>> {
_ => {}
}
}
let end =
end_idx.ok_or_else(|| anyhow!("`switch (from)` body is unterminated"))?;
let end = end_idx.ok_or_else(|| anyhow!("`switch (from)` body is unterminated"))?;
let body = &body_src[..end];
let arms = parse_switch_arms(body)?;
Ok(Some(ZigTransitionTable {
Expand Down Expand Up @@ -234,9 +233,8 @@ fn parse_switch_arms(body: &str) -> Result<BTreeMap<String, Vec<String>>> {
.strip_prefix('.')
.ok_or_else(|| anyhow!("switch arm `{}` does not start with `.`", from))?
.to_string();
let tos = parse_arm_targets(body_part).with_context(|| {
format!("parsing targets of switch arm for `{}`", from)
})?;
let tos = parse_arm_targets(body_part)
.with_context(|| format!("parsing targets of switch arm for `{}`", from))?;
if arms.insert(from.clone(), tos).is_some() {
return Err(anyhow!("duplicate switch arm for `{}`", from));
}
Expand Down
5 changes: 1 addition & 4 deletions src/codegen/cartridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,7 @@ impl CartridgeRepo {
/// Scaffold a boj-server cartridge skeleton for the given manifest.
///
/// Writes `<output_dir>/<iser_name>-mcp/` and all its contents.
pub fn scaffold_cartridge(
manifest: &Manifest,
output_dir: &Path,
) -> CartridgeScaffoldResult {
pub fn scaffold_cartridge(manifest: &Manifest, output_dir: &Path) -> CartridgeScaffoldResult {
let model = manifest.to_language_model();
let iser_name = model.iser_name();
let cartridge_name = format!("{}-mcp", iser_name);
Expand Down
Loading
Loading