Skip to content

Commit

Permalink
Integer literals!
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanBrouwer committed Dec 1, 2023
1 parent 527501b commit 8dd8e57
Show file tree
Hide file tree
Showing 10 changed files with 87 additions and 21 deletions.
2 changes: 1 addition & 1 deletion compiler/src/passes/emit/elf/header.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
4 changes: 1 addition & 3 deletions compiler/src/passes/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
21 changes: 18 additions & 3 deletions compiler/src/passes/validate/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
63 changes: 51 additions & 12 deletions compiler/src/passes/validate/resolve.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<PrgValidated<'p>, TypeError> {
Expand Down Expand Up @@ -106,9 +108,52 @@ fn partial_type_to_type<'p>(
})
}

fn resolve_int_lit<T: FromStr>(s: &str) -> T {
fn resolve_int_lit(original_val: &str, span: Span) -> Result<i64, TypeError> {
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>(
Expand All @@ -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!(),
},
Expand Down
4 changes: 4 additions & 0 deletions programs/fail/validate/invalid_escape.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//* err: InvalidEscape
fn main() {
let x: I64 = b'\a';
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//* err: IntegerOutOfBounds
//* err: InvalidInteger
fn main() {
// 9_223_372_036_854_775_807 is the max for an I64.
9223372036854775808i64;
Expand Down
4 changes: 4 additions & 0 deletions programs/fail/validate/invalid_integer_2.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//* err: InvalidInteger
fn main() {
1a2i64;
}
4 changes: 4 additions & 0 deletions programs/fail/validate/invalid_integer_3.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//* err: InvalidInteger
fn main() {
0b3i64;
}
2 changes: 1 addition & 1 deletion programs/good/mutability/semicolons.test
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() -> Unit {
5i64;
6u64;
6i64;
7i64;
}
2 changes: 2 additions & 0 deletions programs/good/simple/wacky_literals.test
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 8dd8e57

Please sign in to comment.