Skip to content

Commit

Permalink
Add remaining slice methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jfecher committed Jul 5, 2024
1 parent df73fe2 commit 6039c99
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 14 deletions.
137 changes: 123 additions & 14 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::rc::Rc;
use noirc_errors::Location;

use crate::{
ast::IntegerBitSize,
hir::comptime::{errors::IResult, InterpreterError, Value},
macros_api::NodeInterner,
macros_api::{NodeInterner, Signedness},
token::{SpannedToken, Token, Tokens},
QuotedType, Type,
};
Expand All @@ -18,10 +19,16 @@ pub(super) fn call_builtin(
match name {
"array_len" => array_len(interner, arguments, location),
"as_slice" => as_slice(interner, arguments, location),
"is_unconstrained" => Ok(Value::Bool(true)),
"slice_insert" => slice_insert(interner, arguments, location),
"slice_pop_back" => slice_pop_back(interner, arguments, location),
"slice_pop_front" => slice_pop_front(interner, arguments, location),
"slice_push_back" => slice_push_back(interner, arguments, location),
"slice_push_front" => slice_push_front(interner, arguments, location),
"slice_remove" => slice_remove(interner, arguments, location),
"struct_def_as_type" => struct_def_as_type(interner, arguments, location),
"struct_def_generics" => struct_def_generics(interner, arguments, location),
"struct_def_fields" => struct_def_fields(interner, arguments, location),
"struct_def_generics" => struct_def_generics(interner, arguments, location),
_ => {
let item = format!("Comptime evaluation for builtin function {name}");
Err(InterpreterError::Unimplemented { item, location })
Expand All @@ -42,6 +49,36 @@ fn check_argument_count(
}
}

fn failing_constraint<T>(message: impl Into<String>, location: Location) -> IResult<T> {
let message = Some(Value::String(Rc::new(message.into())));
Err(InterpreterError::FailingConstraint { message, location })
}

fn get_slice(
interner: &NodeInterner,
value: Value,
location: Location,
) -> IResult<(im::Vector<Value>, Type)> {
match value {
Value::Slice(values, typ) => Ok((values, typ)),
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Slice(type_var);
Err(InterpreterError::TypeMismatch { expected, value, location })
}
}
}

fn get_u32(value: Value, location: Location) -> IResult<u32> {
match value {
Value::U32(value) => Ok(value),
value => {
let expected = Type::Integer(Signedness::Unsigned, IntegerBitSize::ThirtyTwo);
Err(InterpreterError::TypeMismatch { expected, value, location })
}
}
}

fn array_len(
interner: &NodeInterner,
mut arguments: Vec<(Value, Location)>,
Expand Down Expand Up @@ -85,18 +122,9 @@ fn slice_push_back(
check_argument_count(2, &arguments, location)?;

let (element, _) = arguments.pop().unwrap();
let (slice, _) = arguments.pop().unwrap();
match slice {
Value::Slice(mut values, typ) => {
values.push_back(element);
Ok(Value::Slice(values, typ))
}
value => {
let type_var = Box::new(interner.next_type_variable());
let expected = Type::Slice(type_var);
Err(InterpreterError::TypeMismatch { expected, value, location })
}
}
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
values.push_back(element);
Ok(Value::Slice(values, typ))
}

/// fn as_type(self) -> Quoted
Expand Down Expand Up @@ -198,3 +226,84 @@ fn struct_def_fields(
])));
Ok(Value::Slice(fields, typ))
}

fn slice_remove(
interner: &mut NodeInterner,
mut arguments: Vec<(Value, Location)>,
location: Location,
) -> Result<Value, InterpreterError> {
check_argument_count(2, &arguments, location)?;

let index = get_u32(arguments.pop().unwrap().0, location)? as usize;
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;

if values.is_empty() {
return failing_constraint("slice_remove called on empty slice", location);
}

if index >= values.len() {
let message = format!(
"slice_remove: index {index} is out of bounds for a slice of length {}",
values.len()
);
return failing_constraint(message, location);
}

let element = values.remove(index);
Ok(Value::Tuple(vec![Value::Slice(values, typ), element]))
}

fn slice_push_front(
interner: &mut NodeInterner,
mut arguments: Vec<(Value, Location)>,
location: Location,
) -> Result<Value, InterpreterError> {
check_argument_count(2, &arguments, location)?;

let (element, _) = arguments.pop().unwrap();
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
values.push_front(element);
Ok(Value::Slice(values, typ))
}

fn slice_pop_front(
interner: &mut NodeInterner,
mut arguments: Vec<(Value, Location)>,
location: Location,
) -> Result<Value, InterpreterError> {
check_argument_count(1, &arguments, location)?;

let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
match values.pop_front() {
Some(element) => Ok(Value::Tuple(vec![element, Value::Slice(values, typ)])),
None => failing_constraint("slice_pop_front called on empty slice", location),
}
}

fn slice_pop_back(
interner: &mut NodeInterner,
mut arguments: Vec<(Value, Location)>,
location: Location,
) -> Result<Value, InterpreterError> {
check_argument_count(1, &arguments, location)?;

let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
match values.pop_back() {
Some(element) => Ok(Value::Tuple(vec![Value::Slice(values, typ), element])),
None => failing_constraint("slice_pop_back called on empty slice", location),
}
}

fn slice_insert(
interner: &mut NodeInterner,
mut arguments: Vec<(Value, Location)>,
location: Location,
) -> Result<Value, InterpreterError> {
check_argument_count(3, &arguments, location)?;

let (element, _) = arguments.pop().unwrap();
let index = get_u32(arguments.pop().unwrap().0, location)?;
let (mut values, typ) = get_slice(interner, arguments.pop().unwrap().0, location)?;
values.insert(index as usize, element);
Ok(Value::Slice(values, typ))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "comptime_slice_methods"
type = "bin"
authors = [""]
compiler_version = ">=0.31.0"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
fn main() {
comptime {
// Comptime scopes are counted as unconstrained
assert(std::runtime::is_unconstrained());

let slice = &[2];
let slice = slice.push_back(3);
let slice = slice.push_front(1);
assert_eq(slice, &[1, 2, 3]);

let slice = slice.insert(1, 10);
assert_eq(slice, &[1, 10, 2, 3]);

let (slice, ten) = slice.remove(1);
assert_eq(slice, &[1, 2, 3]);
assert_eq(ten, 10);

let (one, slice) = slice.pop_front();
assert_eq(slice, &[2, 3]);
assert_eq(one, 1);

let (slice, three) = slice.pop_back();
assert_eq(slice, &[2]);
assert_eq(three, 3);
}
}

0 comments on commit 6039c99

Please sign in to comment.