Skip to content

Commit

Permalink
chore: Initial error testing and cleanup (#54)
Browse files Browse the repository at this point in the history
* Add automated compile failure testing of files in bad-programs
* Add compile failure tests for conflicting types, modifying immutable variables, and unbound identifiers
* Cleaned up the resolver logging
* Updated miette
  • Loading branch information
esoterra authored Sep 27, 2024
1 parent d280841 commit 21eb50b
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 91 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
# Not e.g. crates/codegen/allocator.wat
*.wat
*.wasm
*.claw

# The compiled publish script
publish
29 changes: 16 additions & 13 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ claw-codegen = { path = "./crates/codegen", version = "0.2.6" }

clap = { version = "3.0.0-rc.7", features = ["derive"] }
thiserror = "1.0.30"
miette = { version = "7.1.0", features = ["fancy"] }
miette = { version = "7.2.0", features = ["fancy"] }
logos = "0.13.0"
wasm-encoder = "0.207"
cranelift-entity = "0.105.3"
Expand Down
2 changes: 2 additions & 0 deletions crates/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ claw-parser = { workspace = true }
claw-resolver = { workspace = true }
claw-codegen = { workspace = true }
wit-parser = { workspace = true }
thiserror = { workspace = true }
miette = { workspace = true }

[dev-dependencies]
wasmtime = { workspace = true }
Expand Down
42 changes: 33 additions & 9 deletions crates/lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
use claw_codegen::generate;
use claw_common::{make_source, OkPretty};
use claw_parser::{parse, tokenize};
use claw_resolver::{resolve, wit::ResolvedWit};
use claw_codegen::{generate, GenerationError};
use claw_common::make_source;
use claw_parser::{parse, tokenize, LexerError, ParserError};
use claw_resolver::{resolve, wit::ResolvedWit, ResolverError};
use wit_parser::Resolve;

pub fn compile(source_name: String, source_code: &str, wit: Resolve) -> Option<Vec<u8>> {
use miette::Diagnostic;
use thiserror::Error;

#[derive(Error, Debug, Diagnostic)]
pub enum Error {
#[error(transparent)]
#[diagnostic(transparent)]
Lexer(#[from] LexerError),

#[error(transparent)]
#[diagnostic(transparent)]
Parser(#[from] ParserError),

#[error(transparent)]
#[diagnostic(transparent)]
Resolver(#[from] ResolverError),

#[error(transparent)]
#[diagnostic(transparent)]
Generator(#[from] GenerationError),
}

pub fn compile(source_name: String, source_code: &str, wit: Resolve) -> Result<Vec<u8>, Error> {
let src = make_source(source_name.as_str(), source_code);

let tokens = tokenize(src.clone(), source_code).ok_pretty()?;
let tokens = tokenize(src.clone(), source_code)?;

let ast = parse(src.clone(), tokens).ok_pretty()?;
let ast = parse(src.clone(), tokens)?;

let wit = ResolvedWit::new(wit);

let resolved = resolve(src, ast, wit).ok_pretty()?;
let resolved = resolve(src, ast, wit)?;

let output = generate(&resolved)?;

generate(&resolved).ok_pretty()
Ok(output)
}
5 changes: 5 additions & 0 deletions crates/lib/tests/bad-programs/adding-conflicting-types.claw
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
func foo() {
let a: u32 = 1;
let b: u64 = 2;
let c = a + b;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x Conflicting types inferred for expression type1 != type0
,-[adding-conflicting-types.claw:4:17]
3 | let b: u64 = 2;
4 | let c = a + b;
: |
: `-- This bit
5 | }
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
x Global variables must have explicit types annotated starting with ':'
,-[global-without-annotation.claw:1:7]
1 | let a = 0;
: |
: `-- Found Assign
2 |
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
x Global variables must be initialized starting with '='
,-[global-without-initialization.claw:1:11]
1 | let a: u32;
: |
: `-- Found Semicolon
2 |
`----
7 changes: 7 additions & 0 deletions crates/lib/tests/bad-programs/invalid-token.error.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
x Unable to tokenize input
,-[invalid-token.claw:1:10]
1 | func foo($a: u32) -> u32 {
: |
: `-- Here
2 | return $a;
`----
5 changes: 5 additions & 0 deletions crates/lib/tests/bad-programs/modifying-immutable-global.claw
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
let a: u32 = 1;

func foo() {
a = 2;
}
12 changes: 12 additions & 0 deletions crates/lib/tests/bad-programs/modifying-immutable-global.error.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
x Assigned to immutable variable "a"
,-[modifying-immutable-global.claw:1:5]
1 | let a: u32 = 1;
: |
: `-- Defined here
2 |
3 | func foo() {
4 | a = 2;
: |
: `-- Assigned here
5 | }
`----
4 changes: 4 additions & 0 deletions crates/lib/tests/bad-programs/modifying-immutable-local.claw
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
func foo() {
let a: u32 = 1;
a = 2;
}
11 changes: 11 additions & 0 deletions crates/lib/tests/bad-programs/modifying-immutable-local.error.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
x Assigned to immutable variable "a"
,-[modifying-immutable-local.claw:2:9]
1 | func foo() {
2 | let a: u32 = 1;
: |
: `-- Defined here
3 | a = 2;
: |
: `-- Assigned here
4 | }
`----
3 changes: 3 additions & 0 deletions crates/lib/tests/bad-programs/param-local-type-mismatch.claw
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func foo(a: u32) {
let b: u64 = a;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x Conflicting types inferred for expression type0 != type1
,-[param-local-type-mismatch.claw:2:18]
1 | func foo(a: u32) {
2 | let b: u64 = a;
: |
: `-- This bit
3 | }
`----
3 changes: 3 additions & 0 deletions crates/lib/tests/bad-programs/using-unbound-name.claw
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func foo() {
let a = b;
}
8 changes: 8 additions & 0 deletions crates/lib/tests/bad-programs/using-unbound-name.error.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
x Failed to resolve name "b"
,-[using-unbound-name.claw:2:13]
1 | func foo() {
2 | let a = b;
: |
: `-- Name referenced here
3 | }
`----
47 changes: 47 additions & 0 deletions crates/lib/tests/compile-error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use compile_claw::compile;
use miette::{GraphicalReportHandler, GraphicalTheme};

use std::fs;

use wit_parser::Resolve;

#[test]
fn test_bad_programs() {
for f in fs::read_dir("./tests/bad-programs").unwrap() {
let f = f.unwrap();
let source_name = f.file_name().into_string().unwrap();

if source_name.ends_with(".error.txt") {
continue; // skip error files
}

assert!(source_name.ends_with(".claw"));

let source_code = fs::read_to_string(f.path()).unwrap();

let mut error_file_path = f.path();
error_file_path.set_extension("error.txt");
let error_file_contents = fs::read_to_string(error_file_path).unwrap();

let wit = Resolve::new();

let result = compile(source_name.clone(), &source_code, wit);
match result {
Ok(_) => {
eprintln!(
"File '{}' compiled without error when the following error was expected:",
source_name
);
eprintln!("{}", error_file_contents);
panic!()
}
Err(error) => {
let mut error_string = String::new();
GraphicalReportHandler::new_themed(GraphicalTheme::none())
.render_report(&mut error_string, &error)
.unwrap();
assert_eq!(error_string, error_file_contents);
}
}
}
}
3 changes: 2 additions & 1 deletion crates/lib/tests/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use claw_common::UnwrapPretty;
use compile_claw::compile;

use std::fs;
Expand All @@ -20,7 +21,7 @@ impl Runtime {
let input = fs::read_to_string(path).unwrap();
let mut wit = Resolve::new();
wit.push_path("./tests/programs/wit").unwrap();
let component_bytes = compile(name.to_owned(), &input, wit).unwrap();
let component_bytes = compile(name.to_owned(), &input, wit).unwrap_pretty();

println!("{}", wasmprinter::print_bytes(&component_bytes).unwrap());

Expand Down
9 changes: 7 additions & 2 deletions crates/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use thiserror::Error;

use component::parse_component;

pub use lexer::tokenize;
pub use lexer::{tokenize, LexerError};

#[derive(Error, Debug, Diagnostic)]
pub enum ParserError {
Expand Down Expand Up @@ -76,7 +76,12 @@ impl ParseInput {
}

pub fn unexpected_token(&self, description: &str) -> ParserError {
let data = &self.tokens[self.index - 1];
let index = if self.index == 0 {
self.index
} else {
self.index - 1
};
let data = &self.tokens[index];
ParserError::UnexpectedToken {
src: self.src.clone(),
span: data.span,
Expand Down
Loading

0 comments on commit 21eb50b

Please sign in to comment.