Add support for multiple integer types.

This commit is contained in:
2023-06-04 17:31:26 -07:00
parent 7efd2fb796
commit 469fe35e46
19 changed files with 528 additions and 169 deletions

View File

@@ -1,4 +1,4 @@
use crate::syntax::Location;
use crate::syntax::{self, ConstantType, Location};
use internment::ArcIntern;
use pretty::{DocAllocator, Pretty};
use proptest::{
@@ -224,14 +224,21 @@ impl From<ValueOrRef> for Expression {
}
/// A constant in the IR.
#[derive(Debug)]
///
/// The optional argument in numeric types is the base that was used by the
/// user to input the number. By retaining it, we can ensure that if we need
/// to print the number back out, we can do so in the form that the user
/// entered it.
#[derive(Clone, Debug)]
pub enum Value {
/// A numerical constant.
///
/// The optional argument is the base that was used by the user to input
/// the number. By retaining it, we can ensure that if we need to print the
/// number back out, we can do so in the form that the user entered it.
Number(Option<u8>, i64),
I8(Option<u8>, i8),
I16(Option<u8>, i16),
I32(Option<u8>, i32),
I64(Option<u8>, i64),
U8(Option<u8>, u8),
U16(Option<u8>, u16),
U32(Option<u8>, u32),
U64(Option<u8>, u64),
}
impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Value
@@ -240,19 +247,39 @@ where
D: ?Sized + DocAllocator<'a, A>,
{
fn pretty(self, allocator: &'a D) -> pretty::DocBuilder<'a, D, A> {
match self {
Value::Number(opt_base, value) => {
let value_str = match opt_base {
None => format!("{}", value),
Some(2) => format!("0b{:b}", value),
Some(8) => format!("0o{:o}", value),
Some(10) => format!("0d{}", value),
Some(16) => format!("0x{:x}", value),
Some(_) => format!("!!{:x}!!", value),
};
let pretty_internal = |opt_base: &Option<u8>, x, t| {
syntax::Value::Number(*opt_base, Some(t), x).pretty(allocator)
};
allocator.text(value_str)
let pretty_internal_signed = |opt_base, x: i64, t| {
let base = pretty_internal(opt_base, x.unsigned_abs(), t);
allocator.text("-").append(base)
};
match self {
Value::I8(opt_base, value) => {
pretty_internal_signed(opt_base, *value as i64, ConstantType::I8)
}
Value::I16(opt_base, value) => {
pretty_internal_signed(opt_base, *value as i64, ConstantType::I16)
}
Value::I32(opt_base, value) => {
pretty_internal_signed(opt_base, *value as i64, ConstantType::I32)
}
Value::I64(opt_base, value) => {
pretty_internal_signed(opt_base, *value, ConstantType::I64)
}
Value::U8(opt_base, value) => {
pretty_internal(opt_base, *value as u64, ConstantType::U8)
}
Value::U16(opt_base, value) => {
pretty_internal(opt_base, *value as u64, ConstantType::U16)
}
Value::U32(opt_base, value) => {
pretty_internal(opt_base, *value as u64, ConstantType::U32)
}
Value::U64(opt_base, value) => pretty_internal(opt_base, *value, ConstantType::U64),
}
}
}

View File

@@ -35,7 +35,14 @@ impl Expression {
fn eval(&self, env: &EvalEnvironment) -> Result<Value, EvalError> {
match self {
Expression::Value(_, v) => match v {
super::Value::Number(_, v) => Ok(Value::I64(*v)),
super::Value::I8(_, v) => Ok(Value::I8(*v)),
super::Value::I16(_, v) => Ok(Value::I16(*v)),
super::Value::I32(_, v) => Ok(Value::I32(*v)),
super::Value::I64(_, v) => Ok(Value::I64(*v)),
super::Value::U8(_, v) => Ok(Value::U8(*v)),
super::Value::U16(_, v) => Ok(Value::U16(*v)),
super::Value::U32(_, v) => Ok(Value::U32(*v)),
super::Value::U64(_, v) => Ok(Value::U64(*v)),
},
Expression::Reference(_, n) => Ok(env.lookup(n.clone())?),
@@ -49,8 +56,8 @@ impl Expression {
for arg in args.iter() {
match arg {
ValueOrRef::Ref(_, n) => arg_values.push(env.lookup(n.clone())?),
ValueOrRef::Value(_, super::Value::Number(_, v)) => {
arg_values.push(Value::I64(*v))
ValueOrRef::Value(loc, val) => {
arg_values.push(Expression::Value(loc.clone(), val.clone()).eval(env)?)
}
}
}
@@ -73,7 +80,7 @@ fn two_plus_three() {
let input = crate::syntax::Program::parse(0, "x = 2 + 3; print x;").expect("parse works");
let ir = Program::from(input);
let output = ir.eval().expect("runs successfully");
assert_eq!("x = 5i64\n", &output);
assert_eq!("x = 5u64\n", &output);
}
#[test]
@@ -82,5 +89,5 @@ fn lotsa_math() {
crate::syntax::Program::parse(0, "x = 2 + 3 * 10 / 5 - 1; print x;").expect("parse works");
let ir = Program::from(input);
let output = ir.eval().expect("runs successfully");
assert_eq!("x = 7i64\n", &output);
assert_eq!("x = 7u64\n", &output);
}

View File

@@ -149,7 +149,17 @@ impl syntax::Expression {
impl From<syntax::Value> for ir::Value {
fn from(value: syntax::Value) -> Self {
match value {
syntax::Value::Number(base, val) => ir::Value::Number(base, val),
syntax::Value::Number(base, ty, val) => match ty {
None => ir::Value::U64(base, val),
Some(syntax::ConstantType::I8) => ir::Value::I8(base, val as i8),
Some(syntax::ConstantType::I16) => ir::Value::I16(base, val as i16),
Some(syntax::ConstantType::I32) => ir::Value::I32(base, val as i32),
Some(syntax::ConstantType::I64) => ir::Value::I64(base, val as i64),
Some(syntax::ConstantType::U8) => ir::Value::U8(base, val as u8),
Some(syntax::ConstantType::U16) => ir::Value::U16(base, val as u16),
Some(syntax::ConstantType::U32) => ir::Value::U32(base, val as u32),
Some(syntax::ConstantType::U64) => ir::Value::U64(base, val),
},
}
}
}