use crate::artifact::ArtifactError;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Decl {
Import(ImportKind),
Defined(DefinedDecl),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ImportKind {
Function,
Data,
}
impl ImportKind {
pub fn from_decl(decl: &Decl) -> Option<Self> {
match decl {
Decl::Import(ik) => Some(*ik),
_ => None,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Scope {
Global,
Local,
Weak,
}
macro_rules! scope_methods {
() => {
pub fn global(self) -> Self {
self.with_scope(Scope::Global)
}
pub fn local(self) -> Self {
self.with_scope(Scope::Local)
}
pub fn weak(self) -> Self {
self.with_scope(Scope::Weak)
}
pub fn with_scope(mut self, scope: Scope) -> Self {
self.scope = scope;
self
}
pub fn get_scope(&self) -> Scope {
self.scope
}
pub fn set_scope(&mut self, scope: Scope) {
self.scope = scope;
}
pub fn is_global(&self) -> bool {
self.scope == Scope::Global
}
}}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Visibility {
Default,
Protected,
Hidden,
}
macro_rules! visibility_methods {
() => {
pub fn default_visibility(self) -> Self {
self.with_visibility(Visibility::Default)
}
pub fn protected(self) -> Self {
self.with_visibility(Visibility::Protected)
}
pub fn hidden(self) -> Self {
self.with_visibility(Visibility::Hidden)
}
pub fn with_visibility(mut self, visibility: Visibility) -> Self {
self.visibility =visibility;
self
}
pub fn get_visibility(&self) -> Visibility {
self.visibility
}
pub fn set_visibility(&mut self, visibility: Visibility) {
self.visibility = visibility;
}
}}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum DataType {
Bytes,
String,
}
macro_rules! datatype_methods {
() => {
pub fn with_datatype(mut self, datatype: DataType) -> Self {
self.datatype = datatype;
self
}
pub fn set_datatype(&mut self, datatype: DataType) {
self.datatype = datatype;
}
pub fn get_datatype(&self) -> DataType {
self.datatype
}
}
}
macro_rules! align_methods {
() => {
pub fn with_align(mut self, align: Option<usize>) -> Self {
self.align = align;
self
}
pub fn set_align(&mut self, align: Option<usize>) {
self.align = align;
}
pub fn get_align(&self) -> Option<usize> {
self.align
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum DefinedDecl {
Function(FunctionDecl),
Data(DataDecl),
DebugSection(DebugSectionDecl),
}
impl DefinedDecl {
pub fn is_function(&self) -> bool {
match self {
DefinedDecl::Function { .. } => true,
_ => false,
}
}
pub fn is_data(&self) -> bool {
match self {
DefinedDecl::Data { .. } => true,
_ => false,
}
}
pub fn is_debug_section(&self) -> bool {
match self {
DefinedDecl::DebugSection { .. } => true,
_ => false,
}
}
pub fn is_global(&self) -> bool {
match self {
DefinedDecl::Function(a) => a.is_global(),
DefinedDecl::Data(a) => a.is_global(),
DefinedDecl::DebugSection(a) => a.is_global(),
}
}
pub fn is_writable(&self) -> bool {
match self {
DefinedDecl::Data(a) => a.is_writable(),
DefinedDecl::Function(_) | DefinedDecl::DebugSection(_) => false,
}
}
}
impl Decl {
pub fn function_import() -> FunctionImportDecl {
FunctionImportDecl::default()
}
pub fn data_import() -> DataImportDecl {
DataImportDecl::default()
}
pub fn function() -> FunctionDecl {
FunctionDecl::default()
}
pub fn data() -> DataDecl {
DataDecl::default()
}
pub fn cstring() -> DataDecl {
DataDecl::default().with_datatype(DataType::String)
}
pub fn debug_section() -> DebugSectionDecl {
DebugSectionDecl::default()
}
pub fn absorb(&mut self, other: Self) -> Result<(), ArtifactError> {
match self.clone() {
Decl::Import(ImportKind::Data) => {
match other {
Decl::Defined(DefinedDecl::Data { .. }) => {
*self = other;
Ok(())
}
Decl::Import(ImportKind::Data) => Ok(()),
_ => Err(ArtifactError::IncompatibleDeclaration {
old: *self,
new: other,
}
.into()),
}
}
Decl::Import(ImportKind::Function) => {
match other {
Decl::Defined(DefinedDecl::Function { .. }) => {
*self = other;
Ok(())
}
Decl::Import(ImportKind::Function) => Ok(()),
_ => Err(ArtifactError::IncompatibleDeclaration {
old: *self,
new: other,
}
.into()),
}
}
decl @ Decl::Defined(DefinedDecl::Data { .. }) => match other {
Decl::Import(ImportKind::Data) => Ok(()),
other => {
if decl == other {
Ok(())
} else {
Err(ArtifactError::IncompatibleDeclaration {
old: *self,
new: other,
}
.into())
}
}
},
decl @ Decl::Defined(DefinedDecl::Function { .. }) => match other {
Decl::Import(ImportKind::Function) => Ok(()),
other => {
if decl == other {
Ok(())
} else {
Err(ArtifactError::IncompatibleDeclaration {
old: *self,
new: other,
}
.into())
}
}
},
decl => {
if decl == other {
Ok(())
} else {
Err(ArtifactError::IncompatibleDeclaration {
old: *self,
new: other,
}
.into())
}
}
}
}
pub fn is_import(&self) -> bool {
match *self {
Decl::Import(_) => true,
_ => false,
}
}
pub fn is_section(&self) -> bool {
match *self {
Decl::Defined(DefinedDecl::DebugSection { .. }) => true,
_ => false,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FunctionImportDecl {}
impl Default for FunctionImportDecl {
fn default() -> Self {
FunctionImportDecl {}
}
}
impl Into<Decl> for FunctionImportDecl {
fn into(self) -> Decl {
Decl::Import(ImportKind::Function)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DataImportDecl {}
impl Default for DataImportDecl {
fn default() -> Self {
DataImportDecl {}
}
}
impl Into<Decl> for DataImportDecl {
fn into(self) -> Decl {
Decl::Import(ImportKind::Data)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FunctionDecl {
scope: Scope,
visibility: Visibility,
align: Option<usize>,
}
impl Default for FunctionDecl {
fn default() -> Self {
FunctionDecl {
scope: Scope::Local,
visibility: Visibility::Default,
align: None,
}
}
}
impl FunctionDecl {
scope_methods!();
visibility_methods!();
align_methods!();
}
impl Into<Decl> for FunctionDecl {
fn into(self) -> Decl {
Decl::Defined(DefinedDecl::Function(self))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DataDecl {
scope: Scope,
visibility: Visibility,
writable: bool,
datatype: DataType,
align: Option<usize>,
}
impl Default for DataDecl {
fn default() -> Self {
DataDecl {
scope: Scope::Local,
visibility: Visibility::Default,
writable: false,
datatype: DataType::Bytes,
align: None,
}
}
}
impl DataDecl {
scope_methods!();
visibility_methods!();
datatype_methods!();
align_methods!();
pub fn with_writable(mut self, writable: bool) -> Self {
self.writable = writable;
self
}
pub fn writable(self) -> Self {
self.with_writable(true)
}
pub fn read_only(self) -> Self {
self.with_writable(false)
}
pub fn set_writable(&mut self, writable: bool) {
self.writable = writable;
}
pub fn is_writable(&self) -> bool {
self.writable
}
}
impl Into<Decl> for DataDecl {
fn into(self) -> Decl {
Decl::Defined(DefinedDecl::Data(self))
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct DebugSectionDecl {
datatype: DataType,
align: Option<usize>,
}
impl DebugSectionDecl {
datatype_methods!();
align_methods!();
pub fn is_global(&self) -> bool {
false
}
}
impl Default for DebugSectionDecl {
fn default() -> Self {
DebugSectionDecl {
datatype: DataType::Bytes,
align: None,
}
}
}
impl Into<Decl> for DebugSectionDecl {
fn into(self) -> Decl {
Decl::Defined(DefinedDecl::DebugSection(self))
}
}