Skip to content

Commit

Permalink
Integer oob errors
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanBrouwer committed Nov 7, 2023
1 parent 5d8ebac commit a8f26d2
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 55 deletions.
12 changes: 10 additions & 2 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ pub mod passes;
pub mod utils;

use crate::passes::parse::parse::parse_program;
use miette::{Diagnostic, IntoDiagnostic, NamedSource, Report};
use std::fs::File;
use std::path::Path;

pub fn compile(program: &str, filename: &str, output: &Path) -> miette::Result<()> {
let mut file = File::create(output).unwrap();

parse_program(program, filename)?
.validate()?
let add_source =
|error| Report::with_source_code(error, NamedSource::new(filename, program.to_string()));

parse_program(program)
.map_err(Into::into)
.map_err(add_source)?
.validate()
.map_err(Into::into)
.map_err(add_source)?
.uniquify()
.reveal()
.atomize()
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/passes/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ pub mod parse;
pub mod types;

use derive_more::Display;
use functor_derive::Functor;
use std::fmt::Display;
use std::hash::Hash;
use std::str::FromStr;
use functor_derive::Functor;
use types::Type;

/// A parsed program with global definitions and an entry point.
Expand Down Expand Up @@ -226,7 +226,7 @@ pub enum Expr<'p> {
#[derive(Debug, PartialEq, Functor)]
pub struct Spanned<T> {
pub span: (usize, usize),
pub expr: T
pub expr: T,
}

/// A primitive operation.
Expand Down
65 changes: 27 additions & 38 deletions compiler/src/passes/parse/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,54 @@ use crate::passes::parse::PrgParsed;
use itertools::Itertools;
use lalrpop_util::lexer::Token;
use lalrpop_util::ParseError;
use miette::{Diagnostic, NamedSource};
use miette::{Diagnostic};
use thiserror::Error;

#[derive(Error, Debug, Diagnostic)]
pub enum PrettyParseError {
#[error("Parse error: Invalid token.")]
InvalidToken {
#[source_code]
src: NamedSource,
#[label("Failed to parse here, invalid token starting here.")]
#[label("Failed to parse here, invalid token starting here")]
fail: (usize, usize),
},
#[error("Parse error: Unexpected token.")]
UnexpectedToken {
#[source_code]
src: NamedSource,
#[label("Failed to parse here, expected one of: {expected}.")]
#[label("Failed to parse here, expected one of: {expected}")]
fail: (usize, usize),
expected: String,
},
#[error("Parse error: Unexpected end of file.")]
UnexpectedEOF {
#[source_code]
src: NamedSource,
#[label("Unexpected end-of-file, expected one of: {expected}.")]
#[label("Unexpected end-of-file, expected one of: {expected}")]
fail: (usize, usize),
expected: String,
},
}

pub fn parse_program<'p>(src: &'p str, file: &'p str) -> Result<PrgParsed<'p>, PrettyParseError> {
ProgramParser::new()
.parse(src)
.map_err(|error| prettify_error(error, src, file))
pub fn parse_program(src: &str) -> Result<PrgParsed, PrettyParseError> {
ProgramParser::new().parse(src).map_err(From::from)
}

fn prettify_error<'p>(
err: ParseError<usize, Token<'p>, &'p str>,
src: &'p str,
file: &'p str,
) -> PrettyParseError {
let src = NamedSource::new(file, src.to_string());

match err {
ParseError::InvalidToken { location } => PrettyParseError::InvalidToken {
src,
fail: (location, 1),
},
ParseError::UnrecognizedEof { location, expected } => PrettyParseError::UnexpectedEOF {
src,
fail: (location, 1),
expected: expected.into_iter().format(", ").to_string(),
},
ParseError::UnrecognizedToken { token, expected } => PrettyParseError::UnexpectedToken {
src,
fail: (token.0, token.2 - token.0),
expected: expected.into_iter().format(", ").to_string(),
},
ParseError::ExtraToken { .. } => unreachable!("Our grammar always consumes the entire input."),
ParseError::User { .. } => unreachable!("No custom `ParseError`s are implemented."),
impl<'p> From<ParseError<usize, Token<'p>, &'p str>> for PrettyParseError {
fn from(value: ParseError<usize, Token<'p>, &'p str>) -> Self {
match value {
ParseError::InvalidToken { location } => PrettyParseError::InvalidToken {
fail: (location, 1),
},
ParseError::UnrecognizedEof { location, expected } => PrettyParseError::UnexpectedEOF {
fail: (location, 1),
expected: expected.into_iter().format(", ").to_string(),
},
ParseError::UnrecognizedToken { token, expected } => {
PrettyParseError::UnexpectedToken {
fail: (token.0, token.2 - token.0),
expected: expected.into_iter().format(", ").to_string(),
}
}
ParseError::ExtraToken { .. } => {
unreachable!("Our grammar always consumes the entire input.")
}
ParseError::User { .. } => unreachable!("No custom `ParseError`s are implemented."),
}
}
}
2 changes: 1 addition & 1 deletion compiler/src/passes/validate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ impl<'p, A: Copy + Hash + Eq + Display> TExpr<'p, A> {
}

#[derive(Debug, Error, Diagnostic)]
#[diagnostic()]
pub enum ValidateError {
#[error(transparent)]
#[diagnostic(transparent)]
TypeError(#[from] TypeError),
#[error("The program doesn't have a main function.")]
NoMain,
Expand Down
11 changes: 7 additions & 4 deletions compiler/src/passes/validate/type_check/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ use miette::Diagnostic;
use thiserror::Error;

#[derive(Debug, Error, Diagnostic)]
#[diagnostic()]
pub enum TypeError {
#[error("Variable '{sym}' was not declared yet.")]
UndeclaredVar {
sym: String
},
UndeclaredVar { sym: String },
#[error("Types were mismatched. Expected '{expect}', but found '{got}'.")]
TypeMismatchExpect {
expect: Type<String>,
Expand Down Expand Up @@ -42,4 +39,10 @@ pub enum TypeError {
TypeShouldBeStruct { typ: Type<String> },
#[error("The type definition `{sym}` is not sized.'")]
UnsizedType { sym: String },

#[error("Integer out of bounds.")]
IntegerOutOfBounds {
#[label = "This number does not fit in an i32: `-2147483648..=2147483647`"]
span: (usize, usize)
},
}
16 changes: 10 additions & 6 deletions compiler/src/passes/validate/type_check/validate_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ pub fn validate_expr<'p>(
expr: Spanned<Expr<'p>>,
env: &mut Env<'_, 'p>,
) -> Result<TExpr<'p, &'p str>, TypeError> {
let span = (expr.span.0, expr.span.1 - expr.span.0);

Ok(match expr.expr {
Expr::Lit { val, .. } => TExpr::Lit {
val,
typ: match val {
Lit::Int { .. } => Type::Int,
Lit::Bool { .. } => Type::Bool,
Lit::Unit => Type::Unit,
Expr::Lit { val } => match val {
Lit::Int { val } => {
// todo: fix this mess by passing in a string!
let val = i32::try_from(val).map_err(|_| IntegerOutOfBounds { span })?;
let val = val as i64;
TExpr::Lit { val: Lit::Int { val }, typ: Type::Int }
},
val @ Lit::Bool { .. } => TExpr::Lit { val, typ: Type::Bool },
val @ Lit::Unit => TExpr::Lit { val, typ : Type::Unit },
},
Expr::Var { sym, .. } => {
let entry = env.scope.get(&sym).ok_or(UndeclaredVar {
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/passes/validate/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mod tests {
use test_each_file::test_each_file;

fn validate([test]: [&str; 1], should_fail: bool) {
let res = parse_program(test, "test").unwrap().validate();
let res = parse_program(test).unwrap().validate();

match (res, should_fail) {
(Ok(_), true) => panic!("Program should not pass type-checking."),
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/utils/split_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ pub fn split_test(test: &str) -> (Vec<Lit>, Vec<Lit>, Lit, PrgParsed) {
input.take().unwrap_or_default(),
output.take().unwrap_or_default(),
expected_return.take().unwrap_or(Lit::Unit),
parse_program(test, "test").unwrap(), // todo: pass test file name
parse_program(test).unwrap(), // todo: pass test file name
)
}
Empty file added integer_oob
Empty file.
Empty file added invalid_token
Empty file.
3 changes: 3 additions & 0 deletions programs/fail/type_check/integer_oob.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() -> Int {
2147483648
}

0 comments on commit a8f26d2

Please sign in to comment.