Skip to content

Commit

Permalink
Refactor core's Result type support into own module
Browse files Browse the repository at this point in the history
This should help keep the `core` library more manageable.
Sword-Smith committed Jan 2, 2024
1 parent 41225c6 commit 66796b3
Showing 3 changed files with 145 additions and 140 deletions.
6 changes: 3 additions & 3 deletions src/graft.rs
Original file line number Diff line number Diff line change
@@ -369,7 +369,7 @@ impl<'a> Graft<'a> {
if rust_type_as_string == "Result" {
// I guess, here we need to add the Result<T> type to our list of
// known types.
return self.rust_result_to_data_type(&rust_type_path.path.segments[0].arguments);
return self.rust_result_type_to_data_type(&rust_type_path.path.segments[0].arguments);
}

// We only allow the user to use types that are capitalized
@@ -418,7 +418,7 @@ impl<'a> Graft<'a> {
ast_types::DataType::Boxed(Box::new(inner_type))
}

fn rust_result_to_data_type(&mut self, path_args: &PathArguments) -> DataType {
fn rust_result_type_to_data_type(&mut self, path_args: &PathArguments) -> DataType {
use crate::libraries;
let PathArguments::AngleBracketed(generics) = path_args else {
panic!("Unsupported path argument {path_args:#?}");
@@ -431,7 +431,7 @@ impl<'a> Graft<'a> {
};
let ok_type = self.syn_type_to_ast_type(ok_type);

let resolved_type = libraries::core::result_type(ok_type);
let resolved_type = libraries::core::result_type::result_type(ok_type);
self.imported_custom_types
.add_type_context_if_new(resolved_type.clone());
ast_types::DataType::Enum(Box::new(resolved_type.composite_type.try_into().unwrap()))
140 changes: 3 additions & 137 deletions src/libraries/core.rs
Original file line number Diff line number Diff line change
@@ -2,48 +2,21 @@ use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::ExprMethodCall;
use triton_vm::instruction::LabelledInstruction;
use triton_vm::triton_asm;

use crate::ast::{self, Expr, FnSignature};
use crate::ast::{Expr, FnSignature};
use crate::ast_types::DataType;
use crate::ast_types::{self, AbstractArgument, AbstractValueArg};
use crate::graft::Graft;
use crate::libraries::{Annotation, Library};
use crate::tasm_code_generator;
use crate::tasm_code_generator::CompilerState;
use crate::type_checker::CheckState;
use crate::type_checker::Typing;

pub mod result_type;

/// Everything that lives in the Rust `core` module
/// belongs in here.
#[derive(Debug)]
pub struct Core {}

pub(crate) fn result_type(ok_type: DataType) -> crate::composite_types::TypeContext {
let enum_type = ast_types::EnumType {
is_copy: ok_type.is_copy(),
name: "Result".to_owned(),
variants: vec![
(
"Err".to_owned(),
DataType::Tuple(vec![DataType::unit()].into()),
),
("Ok".to_owned(), ok_type.clone()),
],
is_prelude: true,
type_parameter: Some(ok_type.clone()),
};
let is_ok_method = is_ok_method(&enum_type);
let is_err_method = is_err_method(&enum_type);
let unwrap_method = unwrap_method(&enum_type);

crate::composite_types::TypeContext {
composite_type: enum_type.into(),
methods: vec![is_ok_method, is_err_method, unwrap_method],
associated_functions: vec![],
}
}

impl Library for Core {
fn get_function_name(&self, _full_name: &str) -> Option<String> {
None
@@ -114,110 +87,3 @@ impl Library for Core {
None
}
}

fn unwrap_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let method_signature = FnSignature {
name: "unwrap".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: enum_type.into(),
mutable: false,
})],
output: enum_type.variant_data_type("Ok"),
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
assert // _ [ok_type]
)),
signature: method_signature,
}
}

fn is_err_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let stack_size = enum_type.stack_size();
let swap_to_bottom = match stack_size {
0 => unreachable!(),
1 => triton_asm!(),
2..=16 => triton_asm!(swap { stack_size - 1 }),
_ => panic!("Can't handle this yet"), // This should work with spilling
};
let remove_data = match stack_size {
0 => unreachable!(),
1 => triton_asm!(pop 1),
2..=16 => tasm_code_generator::pop_n(stack_size - 1),
_ => panic!("Can't handle this yet"),
};
let is_ok_input_data_type = DataType::Reference(Box::new(enum_type.into()));
let method_signature = FnSignature {
name: "is_err".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: is_ok_input_data_type,
mutable: false,
})],
output: DataType::Bool,
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
{&swap_to_bottom}
// _ discriminant [ok_type']

{&remove_data}
// _ discriminant

push 0
eq
// _ (discriminant == 0 :== variant is 'Err')
)),
signature: method_signature,
}
}

fn is_ok_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let stack_size = enum_type.stack_size();
let swap_to_bottom = match stack_size {
0 => unreachable!(),
1 => triton_asm!(),
2..=16 => triton_asm!(swap { stack_size - 1 }),
_ => panic!("Can't handle this yet"), // This should work with spilling
};
let remove_data = match stack_size {
0 => unreachable!(),
1 => triton_asm!(pop 1),
2..=16 => tasm_code_generator::pop_n(stack_size - 1),
_ => panic!("Can't handle this yet"),
};
let is_ok_input_data_type = DataType::Reference(Box::new(enum_type.into()));
let method_signature = FnSignature {
name: "is_ok".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: is_ok_input_data_type,
mutable: false,
})],
output: DataType::Bool,
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
{&swap_to_bottom}
// _ discriminant [ok_type']

{&remove_data}
// _ discriminant

push 1
eq
// _ (discriminant == 1 :== variant is 'Ok')
)),
signature: method_signature,
}
}
139 changes: 139 additions & 0 deletions src/libraries/core/result_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use triton_vm::triton_asm;

use crate::ast::{self, FnSignature};
use crate::ast_types::DataType;
use crate::ast_types::{self, AbstractArgument, AbstractValueArg};
use crate::tasm_code_generator;
use crate::type_checker::Typing;

pub(crate) fn result_type(ok_type: DataType) -> crate::composite_types::TypeContext {
let enum_type = ast_types::EnumType {
is_copy: ok_type.is_copy(),
name: "Result".to_owned(),
variants: vec![
(
"Err".to_owned(),
DataType::Tuple(vec![DataType::unit()].into()),
),
("Ok".to_owned(), ok_type.clone()),
],
is_prelude: true,
type_parameter: Some(ok_type.clone()),
};
let is_ok_method = result_is_ok_method(&enum_type);
let is_err_method = result_is_err_method(&enum_type);
let unwrap_method = result_unwrap_method(&enum_type);

crate::composite_types::TypeContext {
composite_type: enum_type.into(),
methods: vec![is_ok_method, is_err_method, unwrap_method],
associated_functions: vec![],
}
}

fn result_unwrap_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let method_signature = FnSignature {
name: "unwrap".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: enum_type.into(),
mutable: false,
})],
output: enum_type.variant_data_type("Ok"),
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
assert // _ [ok_type]
)),
signature: method_signature,
}
}

fn result_is_err_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let stack_size = enum_type.stack_size();
let swap_to_bottom = match stack_size {
0 => unreachable!(),
1 => triton_asm!(),
2..=16 => triton_asm!(swap { stack_size - 1 }),
_ => panic!("Can't handle this yet"), // This should work with spilling
};
let remove_data = match stack_size {
0 => unreachable!(),
1 => triton_asm!(pop 1),
2..=16 => tasm_code_generator::pop_n(stack_size - 1),
_ => panic!("Can't handle this yet"),
};
let is_ok_input_data_type = DataType::Reference(Box::new(enum_type.into()));
let method_signature = FnSignature {
name: "is_err".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: is_ok_input_data_type,
mutable: false,
})],
output: DataType::Bool,
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
{&swap_to_bottom}
// _ discriminant [ok_type']

{&remove_data}
// _ discriminant

push 0
eq
// _ (discriminant == 0 :== variant is 'Err')
)),
signature: method_signature,
}
}

fn result_is_ok_method(enum_type: &ast_types::EnumType) -> ast::Method<Typing> {
let stack_size = enum_type.stack_size();
let swap_to_bottom = match stack_size {
0 => unreachable!(),
1 => triton_asm!(),
2..=16 => triton_asm!(swap { stack_size - 1 }),
_ => panic!("Can't handle this yet"), // This should work with spilling
};
let remove_data = match stack_size {
0 => unreachable!(),
1 => triton_asm!(pop 1),
2..=16 => tasm_code_generator::pop_n(stack_size - 1),
_ => panic!("Can't handle this yet"),
};
let is_ok_input_data_type = DataType::Reference(Box::new(enum_type.into()));
let method_signature = FnSignature {
name: "is_ok".to_owned(),
args: vec![AbstractArgument::ValueArgument(AbstractValueArg {
name: "self".to_owned(),
data_type: is_ok_input_data_type,
mutable: false,
})],
output: DataType::Bool,
arg_evaluation_order: Default::default(),
};

ast::Method {
body: ast::RoutineBody::<Typing>::Instructions(triton_asm!(
// _ [ok_type] discriminant
{&swap_to_bottom}
// _ discriminant [ok_type']

{&remove_data}
// _ discriminant

push 1
eq
// _ (discriminant == 1 :== variant is 'Ok')
)),
signature: method_signature,
}
}

0 comments on commit 66796b3

Please sign in to comment.