remaining buitlins for list and integer

Co-authored-by: rvcas <x@rvcas.dev>
This commit is contained in:
Kasey White 2022-08-23 23:58:19 -04:00 committed by Kasey White
parent 3f6ad6be60
commit 09ae98065c
6 changed files with 287 additions and 53 deletions

View File

@ -1,5 +1,5 @@
(program (program
1.0.0 1.0.0
[ (builtin divideInteger) (con integer 5) (con integer 2) ] [ (builtin remainderInteger) (con integer 5) (con integer 2)]
) )

View File

@ -450,7 +450,9 @@ impl Value {
Constant::String(s) => s.chars().count() as i64, Constant::String(s) => s.chars().count() as i64,
Constant::Unit => 1, Constant::Unit => 1,
Constant::Bool(_) => 1, Constant::Bool(_) => 1,
Constant::ProtoList(_, _) => todo!(), Constant::ProtoList(_, items) => items.iter().fold(0, |acc, constant| {
acc + Value::Con(constant.clone()).to_ex_mem()
}),
Constant::ProtoPair(_, _, _, _) => todo!(), Constant::ProtoPair(_, _, _, _) => todo!(),
Constant::Data(_) => todo!(), Constant::Data(_) => todo!(),
}, },
@ -461,17 +463,49 @@ impl Value {
} }
pub fn expect_type(&self, r#type: Type) -> Result<(), Error> { pub fn expect_type(&self, r#type: Type) -> Result<(), Error> {
match self { let constant: Constant = self.clone().try_into()?;
Value::Con(constant) => {
let constant_type = Type::from(constant);
if constant_type == r#type { let constant_type = Type::from(&constant);
Ok(())
} else { if constant_type == r#type {
Err(Error::TypeMismatch(r#type, constant_type)) Ok(())
} } else {
} Err(Error::TypeMismatch(r#type, constant_type))
rest => Err(Error::NotAConstant(rest.clone())), }
}
pub fn expect_list(&self) -> Result<(), Error> {
let constant: Constant = self.clone().try_into()?;
let constant_type = Type::from(&constant);
if matches!(constant_type, Type::List(_)) {
Ok(())
} else {
Err(Error::ListTypeMismatch(constant_type))
}
}
}
impl TryFrom<Value> for Type {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
let constant: Constant = value.try_into()?;
let constant_type = Type::from(&constant);
Ok(constant_type)
}
}
impl TryFrom<Value> for Constant {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Con(constant) => Ok(constant),
rest => Err(Error::NotAConstant(rest)),
} }
} }
} }

View File

@ -572,9 +572,36 @@ impl BuiltinCosts {
.cpu .cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()), .cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
}, },
DefaultFunction::QuotientInteger => todo!(), DefaultFunction::QuotientInteger => ExBudget {
DefaultFunction::RemainderInteger => todo!(), mem: self
DefaultFunction::ModInteger => todo!(), .quotient_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.quotient_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::RemainderInteger => ExBudget {
mem: self
.remainder_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.remainder_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::ModInteger => ExBudget {
mem: self
.mod_integer
.mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.mod_integer
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::EqualsInteger => ExBudget { DefaultFunction::EqualsInteger => ExBudget {
mem: self mem: self
.equals_integer .equals_integer
@ -770,10 +797,28 @@ impl BuiltinCosts {
DefaultFunction::FstPair => todo!(), DefaultFunction::FstPair => todo!(),
DefaultFunction::SndPair => todo!(), DefaultFunction::SndPair => todo!(),
DefaultFunction::ChooseList => todo!(), DefaultFunction::ChooseList => todo!(),
DefaultFunction::MkCons => todo!(), DefaultFunction::MkCons => ExBudget {
DefaultFunction::HeadList => todo!(), mem: self
DefaultFunction::TailList => todo!(), .mk_cons
DefaultFunction::NullList => todo!(), .mem
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
cpu: self
.mk_cons
.cpu
.cost(args[0].to_ex_mem(), args[1].to_ex_mem()),
},
DefaultFunction::HeadList => ExBudget {
mem: self.head_list.mem.cost(args[0].to_ex_mem()),
cpu: self.head_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::TailList => ExBudget {
mem: self.tail_list.mem.cost(args[0].to_ex_mem()),
cpu: self.tail_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::NullList => ExBudget {
mem: self.null_list.mem.cost(args[0].to_ex_mem()),
cpu: self.null_list.cpu.cost(args[0].to_ex_mem()),
},
DefaultFunction::ChooseData => todo!(), DefaultFunction::ChooseData => todo!(),
DefaultFunction::ConstrData => todo!(), DefaultFunction::ConstrData => todo!(),
DefaultFunction::MapData => todo!(), DefaultFunction::MapData => todo!(),

View File

@ -22,6 +22,10 @@ pub enum Error {
NonFunctionalApplication(Value), NonFunctionalApplication(Value),
#[error("Type mismatch expected '{0}' got '{1}'")] #[error("Type mismatch expected '{0}' got '{1}'")]
TypeMismatch(Type, Type), TypeMismatch(Type, Type),
#[error("Type mismatch expected '(list a)' got '{0}'")]
ListTypeMismatch(Type),
#[error("Empty List:\n\n{0:#?}")]
EmptyList(Value),
#[error("A builtin received a term argument when something else was expected:\n\n{0}\n\nYou probably forgot to wrap the builtin with a force.")] #[error("A builtin received a term argument when something else was expected:\n\n{0}\n\nYou probably forgot to wrap the builtin with a force.")]
UnexpectedBuiltinTermArgument(Term<NamedDeBruijn>), UnexpectedBuiltinTermArgument(Term<NamedDeBruijn>),
#[error("A builtin expected a term argument, but something else was received:\n\n{0}\n\nYou probably have an extra force wrapped around a builtin")] #[error("A builtin expected a term argument, but something else was received:\n\n{0}\n\nYou probably have an extra force wrapped around a builtin")]
@ -36,4 +40,8 @@ pub enum Error {
ByteStringOutOfBounds(isize, Vec<u8>), ByteStringOutOfBounds(isize, Vec<u8>),
#[error("Divide By Zero\n\n{0} / {1}")] #[error("Divide By Zero\n\n{0} / {1}")]
DivideByZero(isize, isize), DivideByZero(isize, isize),
#[error("Ed25519S PublicKey should be 32 bytes but it was {0}")]
UnexpectedEd25519PublicKeyLength(usize),
#[error("Ed25519S Signature should be 64 bytes but it was {0}")]
UnexpectedEd25519SignatureLength(usize),
} }

View File

@ -76,9 +76,9 @@ impl DefaultFunction {
DefaultFunction::SubtractInteger => 2, DefaultFunction::SubtractInteger => 2,
DefaultFunction::MultiplyInteger => 2, DefaultFunction::MultiplyInteger => 2,
DefaultFunction::DivideInteger => 2, DefaultFunction::DivideInteger => 2,
DefaultFunction::QuotientInteger => todo!(), DefaultFunction::QuotientInteger => 2,
DefaultFunction::RemainderInteger => todo!(), DefaultFunction::RemainderInteger => 2,
DefaultFunction::ModInteger => todo!(), DefaultFunction::ModInteger => 2,
DefaultFunction::EqualsInteger => 2, DefaultFunction::EqualsInteger => 2,
DefaultFunction::LessThanInteger => 2, DefaultFunction::LessThanInteger => 2,
DefaultFunction::LessThanEqualsInteger => 2, DefaultFunction::LessThanEqualsInteger => 2,
@ -106,10 +106,10 @@ impl DefaultFunction {
DefaultFunction::FstPair => todo!(), DefaultFunction::FstPair => todo!(),
DefaultFunction::SndPair => todo!(), DefaultFunction::SndPair => todo!(),
DefaultFunction::ChooseList => todo!(), DefaultFunction::ChooseList => todo!(),
DefaultFunction::MkCons => todo!(), DefaultFunction::MkCons => 2,
DefaultFunction::HeadList => todo!(), DefaultFunction::HeadList => 1,
DefaultFunction::TailList => todo!(), DefaultFunction::TailList => 1,
DefaultFunction::NullList => todo!(), DefaultFunction::NullList => 1,
DefaultFunction::ChooseData => todo!(), DefaultFunction::ChooseData => todo!(),
DefaultFunction::ConstrData => todo!(), DefaultFunction::ConstrData => todo!(),
DefaultFunction::MapData => todo!(), DefaultFunction::MapData => todo!(),
@ -135,9 +135,9 @@ impl DefaultFunction {
DefaultFunction::SubtractInteger => 0, DefaultFunction::SubtractInteger => 0,
DefaultFunction::MultiplyInteger => 0, DefaultFunction::MultiplyInteger => 0,
DefaultFunction::DivideInteger => 0, DefaultFunction::DivideInteger => 0,
DefaultFunction::QuotientInteger => todo!(), DefaultFunction::QuotientInteger => 0,
DefaultFunction::RemainderInteger => todo!(), DefaultFunction::RemainderInteger => 0,
DefaultFunction::ModInteger => todo!(), DefaultFunction::ModInteger => 0,
DefaultFunction::EqualsInteger => 0, DefaultFunction::EqualsInteger => 0,
DefaultFunction::LessThanInteger => 0, DefaultFunction::LessThanInteger => 0,
DefaultFunction::LessThanEqualsInteger => 0, DefaultFunction::LessThanEqualsInteger => 0,
@ -165,10 +165,10 @@ impl DefaultFunction {
DefaultFunction::FstPair => todo!(), DefaultFunction::FstPair => todo!(),
DefaultFunction::SndPair => todo!(), DefaultFunction::SndPair => todo!(),
DefaultFunction::ChooseList => todo!(), DefaultFunction::ChooseList => todo!(),
DefaultFunction::MkCons => todo!(), DefaultFunction::MkCons => 1,
DefaultFunction::HeadList => todo!(), DefaultFunction::HeadList => 1,
DefaultFunction::TailList => todo!(), DefaultFunction::TailList => 1,
DefaultFunction::NullList => todo!(), DefaultFunction::NullList => 1,
DefaultFunction::ChooseData => todo!(), DefaultFunction::ChooseData => todo!(),
DefaultFunction::ConstrData => todo!(), DefaultFunction::ConstrData => todo!(),
DefaultFunction::MapData => todo!(), DefaultFunction::MapData => todo!(),
@ -194,9 +194,9 @@ impl DefaultFunction {
DefaultFunction::SubtractInteger => arg.expect_type(Type::Integer), DefaultFunction::SubtractInteger => arg.expect_type(Type::Integer),
DefaultFunction::MultiplyInteger => arg.expect_type(Type::Integer), DefaultFunction::MultiplyInteger => arg.expect_type(Type::Integer),
DefaultFunction::DivideInteger => arg.expect_type(Type::Integer), DefaultFunction::DivideInteger => arg.expect_type(Type::Integer),
DefaultFunction::QuotientInteger => todo!(), DefaultFunction::QuotientInteger => arg.expect_type(Type::Integer),
DefaultFunction::RemainderInteger => todo!(), DefaultFunction::RemainderInteger => arg.expect_type(Type::Integer),
DefaultFunction::ModInteger => todo!(), DefaultFunction::ModInteger => arg.expect_type(Type::Integer),
DefaultFunction::EqualsInteger => arg.expect_type(Type::Integer), DefaultFunction::EqualsInteger => arg.expect_type(Type::Integer),
DefaultFunction::LessThanInteger => arg.expect_type(Type::Integer), DefaultFunction::LessThanInteger => arg.expect_type(Type::Integer),
DefaultFunction::LessThanEqualsInteger => arg.expect_type(Type::Integer), DefaultFunction::LessThanEqualsInteger => arg.expect_type(Type::Integer),
@ -260,10 +260,18 @@ impl DefaultFunction {
DefaultFunction::FstPair => todo!(), DefaultFunction::FstPair => todo!(),
DefaultFunction::SndPair => todo!(), DefaultFunction::SndPair => todo!(),
DefaultFunction::ChooseList => todo!(), DefaultFunction::ChooseList => todo!(),
DefaultFunction::MkCons => todo!(), DefaultFunction::MkCons => {
DefaultFunction::HeadList => todo!(), if args.is_empty() {
DefaultFunction::TailList => todo!(), Ok(())
DefaultFunction::NullList => todo!(), } else {
let first = args[0].clone();
arg.expect_type(Type::List(Box::new(first.try_into()?)))
}
}
DefaultFunction::HeadList => arg.expect_list(),
DefaultFunction::TailList => arg.expect_list(),
DefaultFunction::NullList => arg.expect_list(),
DefaultFunction::ChooseData => todo!(), DefaultFunction::ChooseData => todo!(),
DefaultFunction::ConstrData => todo!(), DefaultFunction::ConstrData => todo!(),
DefaultFunction::MapData => todo!(), DefaultFunction::MapData => todo!(),
@ -318,9 +326,44 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::QuotientInteger => todo!(), DefaultFunction::QuotientInteger => match (&args[0], &args[1]) {
DefaultFunction::RemainderInteger => todo!(), (Value::Con(Constant::Integer(arg1)), Value::Con(Constant::Integer(arg2))) => {
DefaultFunction::ModInteger => todo!(), if *arg2 != 0 {
let ret = (*arg1 as f64) / (*arg2 as f64);
let ret = if ret < 0. { ret.ceil() } else { ret.floor() };
Ok(Value::Con(Constant::Integer(ret as isize)))
} else {
Err(Error::DivideByZero(*arg1, *arg2))
}
}
_ => unreachable!(),
},
DefaultFunction::RemainderInteger => match (&args[0], &args[1]) {
(Value::Con(Constant::Integer(arg1)), Value::Con(Constant::Integer(arg2))) => {
if *arg2 != 0 {
let ret = arg1 % arg2;
Ok(Value::Con(Constant::Integer(ret)))
} else {
Err(Error::DivideByZero(*arg1, *arg2))
}
}
_ => unreachable!(),
},
DefaultFunction::ModInteger => match (&args[0], &args[1]) {
(Value::Con(Constant::Integer(arg1)), Value::Con(Constant::Integer(arg2))) => {
if *arg2 != 0 {
let ret = arg1 % arg2;
Ok(Value::Con(Constant::Integer(ret.abs())))
} else {
Err(Error::DivideByZero(*arg1, *arg2))
}
}
_ => unreachable!(),
},
DefaultFunction::EqualsInteger => match (&args[0], &args[1]) { DefaultFunction::EqualsInteger => match (&args[0], &args[1]) {
(Value::Con(Constant::Integer(arg1)), Value::Con(Constant::Integer(arg2))) => { (Value::Con(Constant::Integer(arg1)), Value::Con(Constant::Integer(arg2))) => {
Ok(Value::Con(Constant::Bool(arg1 == arg2))) Ok(Value::Con(Constant::Bool(arg1 == arg2)))
@ -461,11 +504,25 @@ impl DefaultFunction {
}, },
DefaultFunction::VerifyEd25519Signature => match (&args[0], &args[1], &args[2]) { DefaultFunction::VerifyEd25519Signature => match (&args[0], &args[1], &args[2]) {
( (
Value::Con(Constant::ByteString(_arg1)), Value::Con(Constant::ByteString(public_key)),
Value::Con(Constant::ByteString(_arg2)), Value::Con(Constant::ByteString(message)),
Value::Con(Constant::ByteString(_arg3)), Value::Con(Constant::ByteString(signature)),
) => { ) => {
todo!() use cryptoxide::ed25519;
let public_key: [u8; 32] = public_key
.clone()
.try_into()
.map_err(|e: Vec<u8>| Error::UnexpectedEd25519PublicKeyLength(e.len()))?;
let signature: [u8; 64] = signature
.clone()
.try_into()
.map_err(|e: Vec<u8>| Error::UnexpectedEd25519SignatureLength(e.len()))?;
let valid = ed25519::verify(message, &public_key, &signature);
Ok(Value::Con(Constant::Bool(valid)))
} }
_ => unreachable!(), _ => unreachable!(),
}, },
@ -524,10 +581,44 @@ impl DefaultFunction {
DefaultFunction::FstPair => todo!(), DefaultFunction::FstPair => todo!(),
DefaultFunction::SndPair => todo!(), DefaultFunction::SndPair => todo!(),
DefaultFunction::ChooseList => todo!(), DefaultFunction::ChooseList => todo!(),
DefaultFunction::MkCons => todo!(), DefaultFunction::MkCons => match (&args[0], &args[1]) {
DefaultFunction::HeadList => todo!(), (Value::Con(item), Value::Con(Constant::ProtoList(r#type, list))) => {
DefaultFunction::TailList => todo!(), let mut ret = vec![item.clone()];
DefaultFunction::NullList => todo!(), ret.extend(list.clone());
Ok(Value::Con(Constant::ProtoList(r#type.clone(), ret)))
}
_ => unreachable!(),
},
DefaultFunction::HeadList => match &args[0] {
c @ Value::Con(Constant::ProtoList(_, list)) => {
if list.is_empty() {
Err(Error::EmptyList(c.clone()))
} else {
Ok(Value::Con(list[0].clone()))
}
}
_ => unreachable!(),
},
DefaultFunction::TailList => match &args[0] {
c @ Value::Con(Constant::ProtoList(r#type, list)) => {
if list.is_empty() {
Err(Error::EmptyList(c.clone()))
} else {
Ok(Value::Con(Constant::ProtoList(
r#type.clone(),
list[1..].to_vec(),
)))
}
}
_ => unreachable!(),
},
DefaultFunction::NullList => match &args[0] {
Value::Con(Constant::ProtoList(_, list)) => {
Ok(Value::Con(Constant::Bool(list.is_empty())))
}
_ => unreachable!(),
},
DefaultFunction::ChooseData => todo!(), DefaultFunction::ChooseData => todo!(),
DefaultFunction::ConstrData => todo!(), DefaultFunction::ConstrData => todo!(),
DefaultFunction::MapData => todo!(), DefaultFunction::MapData => todo!(),

View File

@ -1,7 +1,7 @@
use pretty::RcDoc; use pretty::RcDoc;
use crate::{ use crate::{
ast::{Constant, Program, Term}, ast::{Constant, Program, Term, Type},
flat::Binder, flat::Binder,
}; };
@ -170,9 +170,65 @@ impl Constant {
Constant::Bool(b) => RcDoc::text("bool") Constant::Bool(b) => RcDoc::text("bool")
.append(RcDoc::line()) .append(RcDoc::line())
.append(RcDoc::text(if *b { "True" } else { "False" })), .append(RcDoc::text(if *b { "True" } else { "False" })),
Constant::ProtoList(_, _) => todo!(), Constant::ProtoList(r#type, items) => RcDoc::text("(")
.append(
RcDoc::text("list")
.append(RcDoc::line())
.append(r#type.to_doc()),
)
.append(RcDoc::line_())
.append(RcDoc::text(")"))
.append(RcDoc::line())
.append(RcDoc::text("["))
.append(RcDoc::intersperse(
items.iter().map(|c| c.to_doc_list()),
RcDoc::text(","),
))
.append(RcDoc::text("]")),
Constant::ProtoPair(_, _, _, _) => todo!(),
Constant::Data(_) => todo!(),
}
}
fn to_doc_list(&self) -> RcDoc<()> {
match self {
Constant::Integer(i) => RcDoc::as_string(i),
Constant::ByteString(bs) => RcDoc::text("#").append(RcDoc::text(hex::encode(bs))),
Constant::String(s) => RcDoc::text("\"")
.append(RcDoc::text(s))
.append(RcDoc::text("\"")),
Constant::Unit => RcDoc::text("()"),
Constant::Bool(b) => RcDoc::text(if *b { "True" } else { "False" }),
Constant::ProtoList(_, items) => RcDoc::text("[")
.append(RcDoc::intersperse(
items.iter().map(|c| c.to_doc_list()),
RcDoc::text(","),
))
.append(RcDoc::text("]")),
Constant::ProtoPair(_, _, _, _) => todo!(), Constant::ProtoPair(_, _, _, _) => todo!(),
Constant::Data(_) => todo!(), Constant::Data(_) => todo!(),
} }
} }
} }
impl Type {
fn to_doc(&self) -> RcDoc<()> {
match self {
Type::Bool => RcDoc::text("bool"),
Type::Integer => RcDoc::text("integer"),
Type::String => RcDoc::text("string"),
Type::ByteString => RcDoc::text("bytestring"),
Type::Unit => RcDoc::text("unit"),
Type::List(r#type) => RcDoc::text("(")
.append(
RcDoc::text("list")
.append(RcDoc::line())
.append(r#type.to_doc()),
)
.append(RcDoc::line_())
.append(RcDoc::text(")")),
Type::Pair(_, _) => todo!(),
Type::Data => todo!(),
}
}
}