Skip to content

Commit faf23ec

Browse files
committed
refactor: Use push_error in compilation phases
1 parent 057f51b commit faf23ec

File tree

5 files changed

+42
-33
lines changed

5 files changed

+42
-33
lines changed

src/compiler/ast.rs

+20-20
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
9696
let mut value = node["value"].to_string();
9797

9898
if value.len() == 0 {
99-
scope.error(
99+
scope.push_error(
100100
traverse_node_offset(node),
101101
format!("Empty match not allowed"),
102102
);
@@ -204,7 +204,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
204204
);
205205

206206
if utils::identifier_is_consumable(&name) && !default.is_consuming() {
207-
scope.error(
207+
scope.push_error(
208208
offset,
209209
format!(
210210
"Generic '{}' defines consumable, but '{}' is not consuming",
@@ -219,7 +219,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
219219
};
220220

221221
if generics.insert(name.clone(), default).is_some() {
222-
scope.error(
222+
scope.push_error(
223223
offset,
224224
format!("Generic '{}' already defined in signature before", name),
225225
);
@@ -230,7 +230,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
230230

231231
// Check for correct identifier semantics
232232
if !first.is_lowercase() {
233-
scope.error(
233+
scope.push_error(
234234
traverse_node_offset(node),
235235
if first == '_' {
236236
format!(
@@ -265,7 +265,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
265265
)
266266
.is_some()
267267
{
268-
scope.error(
268+
scope.push_error(
269269
traverse_node_offset(node),
270270
format!("Argument '{}' already given in signature before", name),
271271
);
@@ -320,7 +320,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
320320
match emit.object::<Str>().unwrap().as_str() {
321321
"genarg" => {
322322
if !nargs.is_empty() {
323-
scope.error(
323+
scope.push_error(
324324
traverse_node_offset(node),
325325
format!(
326326
"Sequencial generics need to be specified before named generics."
@@ -345,7 +345,7 @@ fn traverse_node_value(scope: &Scope, node: &Dict, name: Option<String>) -> ImlV
345345
let ident = ident.object::<Str>().unwrap().as_str();
346346

347347
if nargs.contains_key(ident) {
348-
scope.error(
348+
scope.push_error(
349349
traverse_node_offset(genarg),
350350
format!("Named generic '{}' provided more than once.", ident),
351351
);
@@ -559,7 +559,7 @@ fn traverse_node_lvalue(scope: &Scope, node: &Dict, store: bool, hold: bool) ->
559559
}
560560
// Check for not assigning to a constant (at any level)
561561
Some(_) => {
562-
scope.error(
562+
scope.push_error(
563563
traverse_node_offset(node),
564564
format!("Cannot assign to constant '{}'", name),
565565
);
@@ -569,7 +569,7 @@ fn traverse_node_lvalue(scope: &Scope, node: &Dict, store: bool, hold: bool) ->
569569
None => {
570570
// Check if identifier is not a reserved word
571571
if scope.compiler.restrict && RESERVED_KEYWORDS.contains(&name) {
572-
scope.error(
572+
scope.push_error(
573573
traverse_node_offset(node),
574574
format!("Expected identifier, found reserved word '{}'", name),
575575
);
@@ -579,7 +579,7 @@ fn traverse_node_lvalue(scope: &Scope, node: &Dict, store: bool, hold: bool) ->
579579

580580
// Check if identifier is not defining a consumable
581581
if utils::identifier_is_consumable(name) {
582-
scope.error(
582+
scope.push_error(
583583
traverse_node_offset(node),
584584

585585
if &name[0..1] == "_" {
@@ -601,7 +601,7 @@ fn traverse_node_lvalue(scope: &Scope, node: &Dict, store: bool, hold: bool) ->
601601

602602
// When chained lvalue, name must be declared!
603603
if children.len() > 1 {
604-
scope.error(
604+
scope.push_error(
605605
traverse_node_offset(node),
606606
format!(
607607
"Undeclared variable '{}', please define it first",
@@ -684,7 +684,7 @@ fn traverse_node_rvalue(scope: &Scope, node: &Dict, mode: Rvalue) -> ImlOp {
684684

685685
// Check if identifier is not a reserved word
686686
if scope.compiler.restrict && RESERVED_KEYWORDS.contains(&name) {
687-
scope.error(
687+
scope.push_error(
688688
offset,
689689
format!("Expected identifier, found reserved word '{}'", name),
690690
);
@@ -869,7 +869,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
869869
}
870870
}
871871
} else {
872-
scope.error(
872+
scope.push_error(
873873
traverse_node_offset(node),
874874
format!("'{}' may only be used in parselet scope", emit),
875875
);
@@ -932,7 +932,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
932932
match emit.object::<Str>().unwrap().as_str() {
933933
"callarg" => {
934934
if nargs > 0 {
935-
scope.error(
935+
scope.push_error(
936936
traverse_node_offset(node),
937937
format!(
938938
"Sequencial arguments need to be specified before named arguments."
@@ -1101,7 +1101,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
11011101
if scope.compiler.restrict
11021102
&& (RESERVED_KEYWORDS.contains(&ident) || RESERVED_TOKENS.contains(&ident))
11031103
{
1104-
scope.error(
1104+
scope.push_error(
11051105
traverse_node_offset(node),
11061106
format!("Expected identifier, found reserved word '{}'", ident),
11071107
);
@@ -1117,7 +1117,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
11171117

11181118
if value.is_consuming() {
11191119
if !utils::identifier_is_consumable(ident) {
1120-
scope.error(
1120+
scope.push_error(
11211121
traverse_node_offset(node),
11221122
format!(
11231123
"Cannot assign to constant '{}' as consumable. Use an identifier starting in upper-case, e.g. '{}{}'",
@@ -1128,7 +1128,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
11281128
return ImlOp::Nop;
11291129
}
11301130
} else if utils::identifier_is_consumable(ident) {
1131-
scope.error(
1131+
scope.push_error(
11321132
traverse_node_offset(node),
11331133
if ident.starts_with("_") {
11341134
format!(
@@ -1203,7 +1203,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
12031203
let op = match parts[1] {
12041204
"accept" | "break" | "exit" | "push" => {
12051205
if parts[1] == "break" && !scope.is_loop() {
1206-
scope.error(
1206+
scope.push_error(
12071207
traverse_node_offset(node),
12081208
format!("'break' cannot be used outside of a loop."),
12091209
);
@@ -1237,7 +1237,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
12371237

12381238
"continue" => {
12391239
if !scope.is_loop() {
1240-
scope.error(
1240+
scope.push_error(
12411241
traverse_node_offset(node),
12421242
format!("'continue' cannot be used outside of a loop."),
12431243
);
@@ -1379,7 +1379,7 @@ fn traverse_node(scope: &Scope, node: &Dict) -> ImlOp {
13791379

13801380
/*
13811381
if !res.is_consuming() {
1382-
scope.error(
1382+
scope.push_error(
13831383
traverse_node_offset(node),
13841384
format!(
13851385
"Operator '{}' has no effect on non-consuming {}",

src/compiler/compiler.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ impl Compiler {
117117
// println!("usages = {:?}", global_scope.usages);
118118

119119
for usage in global_scope.usages.borrow_mut().drain(..) {
120-
global_scope.error(usage.offset(), format!("Use of undefined name '{}'", usage));
120+
global_scope
121+
.push_error(usage.offset(), format!("Use of undefined name '{}'", usage));
121122
}
122123

123124
// Break on error

src/compiler/iml/imlprogram.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! ImlProgram glues ImlParselet, ImlOp and ImlValue together to produce a VM program.
22
33
use super::*;
4+
use crate::reader::Offset;
45
use crate::value::Parselet;
56
use crate::vm::Program;
67
use crate::Error;
@@ -13,7 +14,7 @@ use std::collections::{HashMap, HashSet};
1314
pub(in crate::compiler) struct ImlProgram {
1415
main: ImlValue,
1516
statics: IndexMap<ImlValue, Option<Parselet>>, // static values with optional final parselet replacement
16-
pub errors: Vec<Error>, // errors collected during finalization (at least these are unresolved symbols)
17+
errors: Vec<Error>, // errors collected during compilation
1718
}
1819

1920
impl ImlProgram {
@@ -25,6 +26,11 @@ impl ImlProgram {
2526
}
2627
}
2728

29+
/// Push an Error to the programs's error log, with given offset and msg.
30+
pub fn push_error(&mut self, offset: Option<Offset>, msg: String) {
31+
self.errors.push(Error::new(offset, msg))
32+
}
33+
2834
/** Registers an ImlValue in the ImlProgram's statics map and returns its index.
2935
3036
Only resolved values can be registered.

src/compiler/iml/imlvalue.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use super::*;
33
use crate::reader::Offset;
44
use crate::utils;
55
use crate::value::{Object, RefValue, Value};
6-
use crate::Error;
76
use indexmap::IndexMap;
87
use log;
98
use num::ToPrimitive;
@@ -196,7 +195,7 @@ impl ImlValue {
196195
if let (offset, Some(value)) = &arg {
197196
if value.is_consuming() {
198197
if !utils::identifier_is_consumable(name) {
199-
scope.error(
198+
scope.push_error(
200199
*offset,
201200
format!(
202201
"Cannot assign consumable {} to non-consumable generic '{}'",
@@ -205,7 +204,7 @@ impl ImlValue {
205204
);
206205
}
207206
} else if utils::identifier_is_consumable(name) {
208-
scope.error(
207+
scope.push_error(
209208
*offset,
210209
format!(
211210
"Cannot assign non-consumable {} to consumable generic {} of {}",
@@ -214,16 +213,18 @@ impl ImlValue {
214213
);
215214
}
216215
} else {
217-
scope
218-
.error(arg.0, format!("Expecting argument for generic '{}'", name));
216+
scope.push_error(
217+
arg.0,
218+
format!("Expecting argument for generic '{}'", name),
219+
);
219220
}
220221

221222
generics.insert(name.clone(), arg.1);
222223
}
223224

224225
// Report any errors for unconsumed generic arguments.
225226
if !instance.args.is_empty() {
226-
scope.error(
227+
scope.push_error(
227228
instance.args[0].0, // report first parameter
228229
format!(
229230
"{} got too many generic arguments ({} given, {} expected)",
@@ -236,12 +237,12 @@ impl ImlValue {
236237

237238
for (name, (offset, _)) in instance.nargs {
238239
if generics.get(&name).is_some() {
239-
scope.error(
240+
scope.push_error(
240241
offset,
241242
format!("{} already got generic argument '{}'", target, name),
242243
);
243244
} else {
244-
scope.error(
245+
scope.push_error(
245246
offset,
246247
format!(
247248
"{} does not accept generic argument named '{}'",
@@ -380,7 +381,7 @@ impl ImlValue {
380381
_ => None,
381382
};
382383

383-
// Check if something has been pushed before.
384+
// Determine push or static load/call
384385
if let Some(op) = op {
385386
ops.push(op); // Push the op
386387

@@ -400,7 +401,7 @@ impl ImlValue {
400401
ImlValue::Parselet(parselet) => match parselet.derive(current.0) {
401402
Ok(parselet) => program.register(&ImlValue::Parselet(parselet)),
402403
Err(msg) => {
403-
program.errors.push(Error::new(offset.clone(), msg));
404+
program.push_error(offset.clone(), msg);
404405
return;
405406
}
406407
},

src/compiler/scope.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ impl<'compiler, 'parent> Scope<'compiler, 'parent> {
178178
}
179179
}
180180

181-
pub fn error(&self, offset: Option<Offset>, msg: String) {
181+
/// Push an Error to the scope's error log, with given offset and msg.
182+
pub fn push_error(&self, offset: Option<Offset>, msg: String) {
182183
self.errors.borrow_mut().push(Error::new(offset, msg))
183184
}
184185
}

0 commit comments

Comments
 (0)