Skip to content

Commit

Permalink
Factor intermediate language type declarations into separate files
Browse files Browse the repository at this point in the history
The `ast_files` was getting too large. This commit moves all types but the main
`DataType` into separate files.
  • Loading branch information
Sword-Smith committed Jan 2, 2024
1 parent 66796b3 commit 89bbd00
Show file tree
Hide file tree
Showing 10 changed files with 737 additions and 712 deletions.
732 changes: 20 additions & 712 deletions src/ast_types.rs

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions src/ast_types/abstract_argument.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::fmt::Display;

use super::{DataType, FunctionType};

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum AbstractArgument {
FunctionArgument(AbstractFunctionArg),
ValueArgument(AbstractValueArg),
}

impl Display for AbstractArgument {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
AbstractArgument::ValueArgument(val_arg) => {
format!("{}: {}", val_arg.name, val_arg.data_type)
}
AbstractArgument::FunctionArgument(fun_arg) => {
format!("fn ({}): {}", fun_arg.abstract_name, fun_arg.function_type)
}
}
)
}
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct AbstractFunctionArg {
pub abstract_name: String,
pub function_type: FunctionType,
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct AbstractValueArg {
pub name: String,
pub data_type: DataType,
pub mutable: bool,
}

impl Display for AbstractValueArg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.name, self.data_type)
}
}
13 changes: 13 additions & 0 deletions src/ast_types/array_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use super::DataType;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct ArrayType {
pub element_type: Box<DataType>,
pub length: usize,
}

impl ArrayType {
pub(crate) fn size_in_memory(&self) -> usize {
self.element_type.stack_size() * self.length
}
}
104 changes: 104 additions & 0 deletions src/ast_types/custom_type_oil.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use anyhow::bail;

use super::{DataType, EnumType, StructType};

/// Helper-type used during parsing to handle all
/// custom-types.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum CustomTypeOil {
Struct(StructType),
Enum(EnumType),
}

impl From<EnumType> for CustomTypeOil {
fn from(value: EnumType) -> Self {
CustomTypeOil::Enum(value)
}
}

impl From<&EnumType> for CustomTypeOil {
fn from(value: &EnumType) -> Self {
CustomTypeOil::Enum(value.to_owned())
}
}

impl TryFrom<&CustomTypeOil> for EnumType {
type Error = anyhow::Error;

fn try_from(value: &CustomTypeOil) -> Result<Self, Self::Error> {
match value {
CustomTypeOil::Struct(s) => bail!("Expected enum but found struct {s}"),
CustomTypeOil::Enum(e) => Ok(e.to_owned()),
}
}
}

impl TryFrom<DataType> for CustomTypeOil {
type Error = anyhow::Error;

fn try_from(value: DataType) -> Result<Self, Self::Error> {
match value {
DataType::Enum(enumt) => Ok(CustomTypeOil::Enum(*enumt.to_owned())),
DataType::Struct(structt) => Ok(CustomTypeOil::Struct(structt.to_owned())),
_ => bail!("Cannot convert {value} to specified type"),
}
}
}

impl TryFrom<CustomTypeOil> for EnumType {
type Error = anyhow::Error;

fn try_from(value: CustomTypeOil) -> Result<Self, Self::Error> {
match value {
CustomTypeOil::Struct(s) => bail!("Expected enum but found struct {s}"),
CustomTypeOil::Enum(e) => Ok(e),
}
}
}

impl From<StructType> for CustomTypeOil {
fn from(value: StructType) -> Self {
CustomTypeOil::Struct(value)
}
}

impl From<CustomTypeOil> for DataType {
fn from(value: CustomTypeOil) -> Self {
match value {
CustomTypeOil::Struct(s) => DataType::Struct(s),
CustomTypeOil::Enum(e) => DataType::Enum(Box::new(e)),
}
}
}

impl CustomTypeOil {
pub(crate) fn name(&self) -> &str {
match self {
CustomTypeOil::Struct(s) => &s.name,
CustomTypeOil::Enum(e) => &e.name,
}
}

pub(crate) fn is_prelude(&self) -> bool {
match self {
CustomTypeOil::Struct(_) => false,
CustomTypeOil::Enum(e) => e.is_prelude,
}
}

pub fn field_or_variant_types_mut<'a>(
&'a mut self,
) -> Box<dyn Iterator<Item = &'a mut DataType> + 'a> {
match self {
CustomTypeOil::Struct(struct_type) => struct_type.field_types_mut(),
CustomTypeOil::Enum(enum_type) => enum_type.variant_types_mut(),
}
}

pub fn field_or_variant_types<'a>(&'a self) -> Box<dyn Iterator<Item = &'a DataType> + 'a> {
match self {
CustomTypeOil::Struct(struct_type) => struct_type.field_types(),
CustomTypeOil::Enum(enum_type) => enum_type.variant_types(),
}
}
}
102 changes: 102 additions & 0 deletions src/ast_types/enum_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use itertools::Itertools;

use super::DataType;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct EnumType {
pub name: String,
pub is_copy: bool,
pub variants: Vec<(String, DataType)>,
pub is_prelude: bool,

// Use `type_parameter` to create differentiate between function labels
// for e.g. `Result<T>` and `Result<S>` types.
pub type_parameter: Option<DataType>,
}

impl From<&EnumType> for DataType {
fn from(value: &EnumType) -> Self {
Self::Enum(Box::new(value.to_owned()))
}
}

impl From<EnumType> for DataType {
fn from(value: EnumType) -> Self {
Self::Enum(Box::new(value))
}
}

impl EnumType {
/// Return an iterator over mutable references to the type's nested datatypes
pub(crate) fn variant_types_mut<'a>(
&'a mut self,
) -> Box<dyn Iterator<Item = &'a mut DataType> + 'a> {
Box::new(self.variants.iter_mut().map(|x| &mut x.1))
}

pub(crate) fn variant_types<'a>(&'a self) -> Box<dyn Iterator<Item = &'a DataType> + 'a> {
Box::new(self.variants.iter().map(|x| &x.1))
}

pub(crate) fn has_variant_of_name(&self, variant_name: &str) -> bool {
self.variants.iter().any(|x| x.0 == variant_name)
}

pub(crate) fn variant_data_type(&self, variant_name: &str) -> DataType {
for type_variant in self.variants.iter() {
if type_variant.0 == variant_name {
return type_variant.1.clone();
}
}

panic!(
"variant name \"{variant_name}\" is not defined for enum {}",
self.name
);
}

/// Return the "discriminant" of an enum variant, an integer showing
/// what variant the enum type takes.
pub(crate) fn variant_discriminant(&self, variant_name: &str) -> usize {
self.variants
.iter()
.find_position(|x| x.0 == variant_name)
.unwrap_or_else(|| {
panic!(
"Could not find variant {variant_name} in enum {}",
self.name,
)
})
.0
}

/// Returns the stack size that this enum type always occupies, assuming
/// it's on the stack, and not boxed.
pub(crate) fn stack_size(&self) -> usize {
self.variants
.iter()
.max_by_key(|x| x.1.stack_size())
.map(|x| x.1.stack_size() + 1)
.unwrap_or_default()
}

/// Return the words of padding used for a specific variant in this enum
pub(crate) fn padding_size(&self, variant_name: &str) -> usize {
self.stack_size() - self.variant_data_type(variant_name).stack_size() - 1
}

/// Decompose the type of a variant into its three consituent parts:
/// data, padding, discriminant. Must match layout defined by constructor
/// which is:
/// stack: _ [data] [padding] discriminator
pub fn decompose_variant(&self, variant_name: &str) -> Vec<DataType> {
[
self.variant_data_type(variant_name).as_tuple_type().fields,
vec![DataType::Tuple(
vec![DataType::Bfe; self.padding_size(variant_name)].into(),
)],
vec![DataType::Bfe],
]
.concat()
}
}
66 changes: 66 additions & 0 deletions src/ast_types/field_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use std::fmt::Display;

use anyhow::bail;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum FieldId {
NamedField(String),
UnnamedField(usize),
}

impl From<&str> for FieldId {
fn from(value: &str) -> Self {
Self::NamedField(value.to_owned())
}
}

impl From<&String> for FieldId {
fn from(value: &String) -> Self {
Self::NamedField(value.to_owned())
}
}

impl From<String> for FieldId {
fn from(value: String) -> Self {
Self::NamedField(value)
}
}

impl From<&usize> for FieldId {
fn from(value: &usize) -> Self {
Self::UnnamedField(*value)
}
}

impl From<usize> for FieldId {
fn from(value: usize) -> Self {
Self::UnnamedField(value)
}
}

impl From<u32> for FieldId {
fn from(value: u32) -> Self {
Self::UnnamedField(value as usize)
}
}

impl TryFrom<&FieldId> for usize {
type Error = anyhow::Error;

fn try_from(value: &FieldId) -> Result<Self, Self::Error> {
match value {
FieldId::NamedField(_) => bail!("Cannot convert named field to usize"),
FieldId::UnnamedField(tuple_index) => Ok(*tuple_index),
}
}
}

impl Display for FieldId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let output = match self {
FieldId::NamedField(name) => name.to_owned(),
FieldId::UnnamedField(tuple_index) => tuple_index.to_string(),
};
write!(f, "{output}")
}
}
15 changes: 15 additions & 0 deletions src/ast_types/function_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use std::fmt::Display;

use super::DataType;

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct FunctionType {
pub input_argument: DataType,
pub output: DataType,
}

impl Display for FunctionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} -> {}", self.input_argument, self.output)
}
}
Loading

0 comments on commit 89bbd00

Please sign in to comment.