plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
54233aa
— Peter John
2026-10-26T14:44:33+05:30
feat(loader): clear error for duplicate top-level constants with both locations
- plum-core/src/ast.rs +2 -0
- plum-core/src/loader.rs +19 -0
- plum-core/src/parser.rs +5 -1
- plum-core/tests/loader_test.rs +42 -0
plum-core/src/ast.rs
CHANGED
|
@@ -142,6 +142,8 @@ pub struct Fn {
|
|
|
142
142
|
pub struct Const {
|
|
143
143
|
pub name: String,
|
|
144
144
|
pub value: Expr,
|
|
145
|
+
/// 1-based source line of the declaration (for duplicate diagnostics).
|
|
146
|
+
pub line: usize,
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
/// `test "description" { ... }` — compiled only by `plum test`, stripped from
|
plum-core/src/loader.rs
CHANGED
|
@@ -330,6 +330,25 @@ fn mergeItems(
|
|
|
330
330
|
continue;
|
|
331
331
|
}
|
|
332
332
|
let key = itemNameKey(item);
|
|
333
|
+
if let Item::Const(c) = item {
|
|
334
|
+
if let Some(prev) = items.iter().find_map(|i| match i {
|
|
335
|
+
Item::Const(p) if p.name == c.name => Some(p),
|
|
336
|
+
_ => None,
|
|
337
|
+
}) {
|
|
338
|
+
let prev_file = names
|
|
339
|
+
.get(&key)
|
|
340
|
+
.map(|f| f.display().to_string())
|
|
341
|
+
.unwrap_or_default();
|
|
342
|
+
return Err(format!(
|
|
343
|
+
"duplicate constant '{}': defined in {}:{} and {}:{}",
|
|
344
|
+
c.name,
|
|
345
|
+
prev_file,
|
|
346
|
+
prev.line,
|
|
347
|
+
file.display(),
|
|
348
|
+
c.line
|
|
349
|
+
));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
333
352
|
if let Some(existing_file) = names.get(&key) {
|
|
334
353
|
return Err(format!(
|
|
335
354
|
"duplicate declaration '{}': declared in both '{}' and '{}'",
|
plum-core/src/parser.rs
CHANGED
|
@@ -349,7 +349,11 @@ impl<'a> AstParser<'a> {
|
|
|
349
349
|
self.parseExpression(unwrapped)
|
|
350
350
|
})
|
|
351
351
|
.unwrap_or(Expr::Int(0));
|
|
352
|
-
Const {
|
|
352
|
+
Const {
|
|
353
|
+
name,
|
|
354
|
+
value,
|
|
355
|
+
line: node.start_position().row + 1,
|
|
356
|
+
}
|
|
353
357
|
}
|
|
354
358
|
|
|
355
359
|
fn parseTest(&self, node: Node) -> Test {
|
plum-core/tests/loader_test.rs
CHANGED
|
@@ -270,3 +270,45 @@ fn nullable_bang_rejected() {
|
|
|
270
270
|
let err = loadAndMerge(&entry, dir.path()).unwrap_err();
|
|
271
271
|
assert!(err.contains("Missing, X"), "{err}");
|
|
272
272
|
}
|
|
273
|
+
|
|
274
|
+
#[test]
|
|
275
|
+
fn duplicate_const_across_modules() {
|
|
276
|
+
let dir = TempDir::new().unwrap();
|
|
277
|
+
let lib_path = dir.path().join("libs");
|
|
278
|
+
writeLibFile(&lib_path, "helper", "module fixtures\n\nPI = 3.14\n");
|
|
279
|
+
let entry = writeLibFile(
|
|
280
|
+
&lib_path,
|
|
281
|
+
"main",
|
|
282
|
+
"module fixtures\n\nimport helper\n\nPI = 3.0\n",
|
|
283
|
+
);
|
|
284
|
+
let msg = loadAndMerge(&entry, &lib_path).unwrap_err();
|
|
285
|
+
assert!(msg.contains("duplicate constant 'PI': defined in "), "{}", msg);
|
|
286
|
+
assert!(msg.contains("main.plum:5") && msg.contains("helper.plum:3"), "{}", msg);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
#[test]
|
|
290
|
+
fn duplicate_const_same_file() {
|
|
291
|
+
let dir = TempDir::new().unwrap();
|
|
292
|
+
let lib_path = dir.path().join("libs");
|
|
293
|
+
let entry = writeLibFile(
|
|
294
|
+
&lib_path,
|
|
295
|
+
"main",
|
|
296
|
+
"module fixtures\n\nPI = 3.0\nPI = 4.0\n",
|
|
297
|
+
);
|
|
298
|
+
let msg = loadAndMerge(&entry, &lib_path).unwrap_err();
|
|
299
|
+
assert!(msg.contains("duplicate constant 'PI'"), "{}", msg);
|
|
300
|
+
assert!(msg.contains("main.plum:3") && msg.contains("main.plum:4"), "{}", msg);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
#[test]
|
|
304
|
+
fn distinct_consts_ok() {
|
|
305
|
+
let dir = TempDir::new().unwrap();
|
|
306
|
+
let lib_path = dir.path().join("libs");
|
|
307
|
+
writeLibFile(&lib_path, "helper", "module fixtures\n\nPI = 3.14\n");
|
|
308
|
+
let entry = writeLibFile(
|
|
309
|
+
&lib_path,
|
|
310
|
+
"main",
|
|
311
|
+
"module fixtures\n\nimport helper\n\nTAU = 6.28\n",
|
|
312
|
+
);
|
|
313
|
+
assert!(loadAndMerge(&entry, &lib_path).is_ok());
|
|
314
|
+
}
|