diff --git a/compiler/src/passes/emit/elf/header.rs b/compiler/src/passes/emit/elf/header.rs index 7f4e186..1c4b36c 100644 --- a/compiler/src/passes/emit/elf/header.rs +++ b/compiler/src/passes/emit/elf/header.rs @@ -1,6 +1,6 @@ -use std::clone::Clone; use crate::passes::emit::elf::program::ProgramHeader; use crate::passes::emit::elf::section::SectionHeader; +use std::clone::Clone; use std::mem::size_of; use zerocopy::AsBytes; diff --git a/compiler/src/passes/parse/mod.rs b/compiler/src/passes/parse/mod.rs index e88b90c..54b75fc 100644 --- a/compiler/src/passes/parse/mod.rs +++ b/compiler/src/passes/parse/mod.rs @@ -336,9 +336,7 @@ pub enum BinaryOp { pub enum Lit<'p> { /// Integer literal, representing a signed 64-bit number. #[display(fmt = "{val}")] - Int { - val: &'p str, - }, + Int { val: &'p str }, /// Boolean literal, representing a value of *true* or *false*. #[display(fmt = "{}", r#"if *val { "true" } else { "false" }"#)] Bool { val: bool }, diff --git a/compiler/src/passes/validate/error.rs b/compiler/src/passes/validate/error.rs index f9b997f..eadb104 100644 --- a/compiler/src/passes/validate/error.rs +++ b/compiler/src/passes/validate/error.rs @@ -85,11 +85,26 @@ pub enum TypeError { #[label = "The type definition `{sym}` is not sized."] span: (usize, usize), }, - #[error("Integer out of bounds.")] - IntegerOutOfBounds { - #[label = "This number does not fit in type `{typ}`"] + #[error("Could not parse integer.")] + InvalidInteger { + #[label = "`{val}` is not a valid {typ}: {err}"] span: (usize, usize), + val: String, typ: &'static str, + err: String, + }, + #[error("Could not parse integer.")] + InvalidByteLit { + #[label = "`{val}` is not a valid {typ}"] + span: (usize, usize), + val: String, + typ: &'static str, + }, + #[error("Could not parse integer.")] + InvalidEscape { + #[label = "`{val}` is not an escape sequence (or has not been added to the compiler as an escape sequence!)"] + span: (usize, usize), + val: String, }, #[error("Integer ambiguous.")] IntegerAmbiguous { diff --git a/compiler/src/passes/validate/resolve.rs b/compiler/src/passes/validate/resolve.rs index b9489df..48d3148 100644 --- a/compiler/src/passes/validate/resolve.rs +++ b/compiler/src/passes/validate/resolve.rs @@ -1,6 +1,7 @@ -use std::str::FromStr; +use std::error::Error; +use std::fmt::format; use crate::passes::parse::types::Type; -use crate::passes::parse::{Constrained, Expr, Lit, Meta, Param, Spanned, TypeDef, Typed}; +use crate::passes::parse::{Constrained, Expr, Lit, Meta, Param, Spanned, TypeDef, Typed, Span}; use crate::passes::select::{Instr, VarArg}; use crate::passes::validate::error::TypeError; use crate::passes::validate::partial_type::PartialType; @@ -12,6 +13,7 @@ use crate::utils::gen_sym::UniqueSym; use crate::utils::union_find::{UnionFind, UnionIndex}; use crate::*; use functor_derive::Functor; +use std::str::FromStr; impl<'p> PrgConstrained<'p> { pub fn resolve(mut self) -> Result, TypeError> { @@ -106,9 +108,52 @@ fn partial_type_to_type<'p>( }) } -fn resolve_int_lit(s: &str) -> T { +fn resolve_int_lit(original_val: &str, span: Span) -> Result { + let mut val = original_val; + if val.ends_with("i64") || val.ends_with("u64") { + val = &val[..val.len() - 3]; + } + + let (base, val) = match val { + s if s.starts_with("b") => { + let mut s = s[1..].chars(); - todo!() + let int = match (s.next(), s.next(), s.next(), s.next(), s.next()) { + (Some('\''), Some(s), Some('\''), None, None) => { + s as i64 + }, + (Some('\''), Some('\\'), Some(s), Some('\''), None) => { + let int = match s { + 'n' => '\n', + 'r' => '\r', + '\\' => '\\', + '"' => '"', + '\'' => '\'', + '0' => '\0', + s => return Err(TypeError::InvalidEscape { + span, + val: format!("\\{s}"), + }), + }; + int as i64 + } , + _ => unreachable!("Congrats you made an invalid byte lit, plx tell us how"), + }; + + return Ok(int) + } + s if s.starts_with("0b") => (2, &s[2..]), + s if s.starts_with("0o") => (8, &s[2..]), + s if s.starts_with("0x") => (16, &s[2..]), + s => (10, s), + }; + + i64::from_str_radix(&val.replace("_", ""), base).map_err(|error| TypeError::InvalidInteger { + span, + val: original_val.to_string(), + typ: "I64", + err: error.to_string(), + }) } fn resolve_expr<'p>( @@ -129,16 +174,10 @@ fn resolve_expr<'p>( } Some(typ) => match typ { Type::I64 => TLit::I64 { - val: val.trim_end_matches("i64").parse().map_err(|_| TypeError::IntegerOutOfBounds { - span: expr.meta.span, - typ: "I64", - })?, + val: resolve_int_lit(val, expr.meta.span)?, }, Type::U64 => TLit::U64 { - val: val.trim_end_matches("u64").parse().map_err(|_| TypeError::IntegerOutOfBounds { - span: expr.meta.span, - typ: "U64", - })?, + val: todo!(), }, _ => unreachable!(), }, diff --git a/programs/fail/validate/invalid_escape.test b/programs/fail/validate/invalid_escape.test new file mode 100644 index 0000000..c0ea59b --- /dev/null +++ b/programs/fail/validate/invalid_escape.test @@ -0,0 +1,4 @@ +//* err: InvalidEscape +fn main() { + let x: I64 = b'\a'; +} diff --git a/programs/fail/validate/integer_out_of_bounds.test b/programs/fail/validate/invalid_integer_1.test similarity index 77% rename from programs/fail/validate/integer_out_of_bounds.test rename to programs/fail/validate/invalid_integer_1.test index 053ba31..95b9b3f 100644 --- a/programs/fail/validate/integer_out_of_bounds.test +++ b/programs/fail/validate/invalid_integer_1.test @@ -1,4 +1,4 @@ -//* err: IntegerOutOfBounds +//* err: InvalidInteger fn main() { // 9_223_372_036_854_775_807 is the max for an I64. 9223372036854775808i64; diff --git a/programs/fail/validate/invalid_integer_2.test b/programs/fail/validate/invalid_integer_2.test new file mode 100644 index 0000000..fef7760 --- /dev/null +++ b/programs/fail/validate/invalid_integer_2.test @@ -0,0 +1,4 @@ +//* err: InvalidInteger +fn main() { + 1a2i64; +} diff --git a/programs/fail/validate/invalid_integer_3.test b/programs/fail/validate/invalid_integer_3.test new file mode 100644 index 0000000..e382efa --- /dev/null +++ b/programs/fail/validate/invalid_integer_3.test @@ -0,0 +1,4 @@ +//* err: InvalidInteger +fn main() { + 0b3i64; +} diff --git a/programs/good/mutability/semicolons.test b/programs/good/mutability/semicolons.test index 2b0237a..1df3406 100644 --- a/programs/good/mutability/semicolons.test +++ b/programs/good/mutability/semicolons.test @@ -1,5 +1,5 @@ fn main() -> Unit { 5i64; - 6u64; + 6i64; 7i64; } diff --git a/programs/good/simple/wacky_literals.test b/programs/good/simple/wacky_literals.test index 67f68b6..371f691 100644 --- a/programs/good/simple/wacky_literals.test +++ b/programs/good/simple/wacky_literals.test @@ -10,4 +10,6 @@ fn main() { let i: I64 = 0o52; let j: I64 = 0o5_2; let k: I64 = b'\n'; // sadly this is not 42 + let l = b'*'i64; + let m = 4_2i64; }