Add support for multiple integer types.
This commit is contained in:
@@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user