Wire functions through everything, with some unimplemented, and add a basic scoped map.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
eval::PrimitiveType,
|
||||
syntax::{Expression, Location, Program, Statement},
|
||||
syntax::{Expression, Location, Program, Statement, TopLevel},
|
||||
util::scoped_map::ScopedMap,
|
||||
};
|
||||
use codespan_reporting::diagnostic::Diagnostic;
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// An error we found while validating the input program.
|
||||
///
|
||||
@@ -65,7 +66,7 @@ impl Program {
|
||||
/// example, and generates warnings for things that are inadvisable but not
|
||||
/// actually a problem.
|
||||
pub fn validate(&self) -> (Vec<Error>, Vec<Warning>) {
|
||||
let mut bound_variables = HashMap::new();
|
||||
let mut bound_variables = ScopedMap::new();
|
||||
self.validate_with_bindings(&mut bound_variables)
|
||||
}
|
||||
|
||||
@@ -76,13 +77,13 @@ impl Program {
|
||||
/// actually a problem.
|
||||
pub fn validate_with_bindings(
|
||||
&self,
|
||||
bound_variables: &mut HashMap<String, Location>,
|
||||
bound_variables: &mut ScopedMap<String, Location>,
|
||||
) -> (Vec<Error>, Vec<Warning>) {
|
||||
let mut errors = vec![];
|
||||
let mut warnings = vec![];
|
||||
|
||||
for stmt in self.statements.iter() {
|
||||
let (mut new_errors, mut new_warnings) = stmt.validate(bound_variables);
|
||||
for stmt in self.items.iter() {
|
||||
let (mut new_errors, mut new_warnings) = stmt.validate_with_bindings(bound_variables);
|
||||
errors.append(&mut new_errors);
|
||||
warnings.append(&mut new_warnings);
|
||||
}
|
||||
@@ -91,6 +92,44 @@ impl Program {
|
||||
}
|
||||
}
|
||||
|
||||
impl TopLevel {
|
||||
/// Validate that the top level item makes semantic sense, not just syntactic
|
||||
/// sense.
|
||||
///
|
||||
/// This checks for things like references to variables that don't exist, for
|
||||
/// example, and generates warnings for thins that are inadvisable but not
|
||||
/// actually a problem.
|
||||
pub fn validate(&self) -> (Vec<Error>, Vec<Warning>) {
|
||||
let mut bound_variables = ScopedMap::new();
|
||||
self.validate_with_bindings(&mut bound_variables)
|
||||
}
|
||||
|
||||
/// Validate that the top level item makes semantic sense, not just syntactic
|
||||
/// sense.
|
||||
///
|
||||
/// This checks for things like references to variables that don't exist, for
|
||||
/// example, and generates warnings for thins that are inadvisable but not
|
||||
/// actually a problem.
|
||||
pub fn validate_with_bindings(
|
||||
&self,
|
||||
bound_variables: &mut ScopedMap<String, Location>,
|
||||
) -> (Vec<Error>, Vec<Warning>) {
|
||||
match self {
|
||||
TopLevel::Function(name, arguments, body) => {
|
||||
bound_variables.new_scope();
|
||||
bound_variables.insert(name.name.clone(), name.location.clone());
|
||||
for arg in arguments.iter() {
|
||||
bound_variables.insert(arg.name.clone(), arg.location.clone());
|
||||
}
|
||||
let result = body.validate(&bound_variables);
|
||||
bound_variables.release_scope();
|
||||
result
|
||||
}
|
||||
TopLevel::Statement(stmt) => stmt.validate(bound_variables),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
/// Validate that the statement makes semantic sense, not just syntactic sense.
|
||||
///
|
||||
@@ -103,7 +142,7 @@ impl Statement {
|
||||
/// and warnings.
|
||||
fn validate(
|
||||
&self,
|
||||
bound_variables: &mut HashMap<String, Location>,
|
||||
bound_variables: &mut ScopedMap<String, Location>,
|
||||
) -> (Vec<Error>, Vec<Warning>) {
|
||||
let mut errors = vec![];
|
||||
let mut warnings = vec![];
|
||||
@@ -139,7 +178,7 @@ impl Statement {
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
fn validate(&self, variable_map: &HashMap<String, Location>) -> (Vec<Error>, Vec<Warning>) {
|
||||
fn validate(&self, variable_map: &ScopedMap<String, Location>) -> (Vec<Error>, Vec<Warning>) {
|
||||
match self {
|
||||
Expression::Value(_, _) => (vec![], vec![]),
|
||||
Expression::Reference(_, var) if variable_map.contains_key(var) => (vec![], vec![]),
|
||||
@@ -174,14 +213,14 @@ impl Expression {
|
||||
|
||||
#[test]
|
||||
fn cast_checks_are_reasonable() {
|
||||
let good_stmt = Statement::parse(0, "x = <u16>4u8;").expect("valid test case");
|
||||
let (good_errs, good_warns) = good_stmt.validate(&mut HashMap::new());
|
||||
let good_stmt = TopLevel::parse(0, "x = <u16>4u8;").expect("valid test case");
|
||||
let (good_errs, good_warns) = good_stmt.validate();
|
||||
|
||||
assert!(good_errs.is_empty());
|
||||
assert!(good_warns.is_empty());
|
||||
|
||||
let bad_stmt = Statement::parse(0, "x = <apple>4u8;").expect("valid test case");
|
||||
let (bad_errs, bad_warns) = bad_stmt.validate(&mut HashMap::new());
|
||||
let bad_stmt = TopLevel::parse(0, "x = <apple>4u8;").expect("valid test case");
|
||||
let (bad_errs, bad_warns) = bad_stmt.validate();
|
||||
|
||||
assert!(bad_warns.is_empty());
|
||||
assert_eq!(bad_errs.len(), 1);
|
||||
|
||||
Reference in New Issue
Block a user