Wire functions through everything, with some unimplemented, and add a basic scoped map.

This commit is contained in:
2023-10-07 11:06:28 +02:00
parent eba5227ebc
commit 736d27953f
18 changed files with 392 additions and 97 deletions

View File

@@ -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);