Skip to content
This repository has been archived by the owner on Feb 4, 2025. It is now read-only.

Commit

Permalink
use SemanticError and convert the resulting fallout to use it too
Browse files Browse the repository at this point in the history
  • Loading branch information
Byter09 committed Mar 6, 2020
1 parent f856ab9 commit 69c1d82
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 40 deletions.
69 changes: 47 additions & 22 deletions src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl StructType {
unreachable!("cannot call struct_offset for member not in struct");
}
/// Get the offset of the next struct member given the current offset.
fn next_offset(mut current_offset: u64, ctype: &Type) -> Result<u64, &'static str> {
fn next_offset(mut current_offset: u64, ctype: &Type) -> Result<u64, SemanticError> {
let align = ctype.alignof()?;
// round up to the nearest multiple of align
let rem = current_offset % align;
Expand All @@ -69,7 +69,7 @@ impl StructType {
Ok(current_offset + ctype.sizeof()?)
}
/// Calculate the size of a struct: the sum of all member sizes
pub(crate) fn struct_size(&self) -> Result<SIZE_T, &'static str> {
pub(crate) fn struct_size(&self) -> Result<SIZE_T, SemanticError> {
let symbols = &self.members();

symbols
Expand All @@ -85,7 +85,7 @@ impl StructType {
})
}
/// Calculate the size of a union: the max of all member sizes
pub(crate) fn union_size(&self) -> Result<SIZE_T, &'static str> {
pub(crate) fn union_size(&self) -> Result<SIZE_T, SemanticError> {
let symbols = &self.members();
symbols
.iter()
Expand All @@ -94,7 +94,7 @@ impl StructType {
.try_fold(1, |n, size| Ok(max(n, size?)))
}
/// Calculate the alignment of a struct: the max of all member alignments
pub(crate) fn align(&self) -> Result<SIZE_T, &'static str> {
pub(crate) fn align(&self) -> Result<SIZE_T, SemanticError> {
let members = &self.members();
members.iter().try_fold(0, |max, member| {
Ok(std::cmp::max(member.ctype.alignof()?, max))
Expand All @@ -103,19 +103,19 @@ impl StructType {
}

impl Type {
/// Returns true if `other` can be converted to `self` without losing infomation.
pub fn can_represent(&self, other: &Type) -> bool {
self == other
/// Returns true if `other` can be converted to `self` without losing information.
pub fn can_represent(&self, other: &Type) -> Result<bool, SemanticError> {
Ok(self == other
|| *self == Type::Double && *other == Type::Float
|| (self.is_integral() && other.is_integral())
&& (self.sizeof() > other.sizeof()
|| self.sizeof() == other.sizeof() && self.is_signed() == other.is_signed())
&& (self.sizeof()? > other.sizeof()?
|| self.sizeof()? == other.sizeof()? && self.is_signed() == other.is_signed()))
}

/// Get the size of a type in bytes.
///
/// This is the `sizeof` operator in C.
pub fn sizeof(&self) -> Result<SIZE_T, &'static str> {
pub fn sizeof(&self) -> Result<SIZE_T, SemanticError> {
match self {
Bool => Ok(BOOL_SIZE.into()),
Char(_) => Ok(CHAR_SIZE.into()),
Expand All @@ -126,8 +126,13 @@ impl Type {
Double => Ok(DOUBLE_SIZE.into()),
Pointer(_) => Ok(PTR_SIZE.into()),
// now for the hard ones
Array(t, ArrayType::Fixed(l)) => t.sizeof().and_then(|n| Ok(n * l)),
Array(_, ArrayType::Unbounded) => Err("cannot take sizeof variable length array"),
Array(t, ArrayType::Fixed(l)) => t.sizeof().and_then(|n| {
n.checked_mul(*l)
.ok_or(SemanticError::ConstOverflow { is_positive: true })
}),
Array(_, ArrayType::Unbounded) => Err(SemanticError::Generic(
"cannot take sizeof variable length array".to_owned(),
)),
Enum(_, symbols) => {
let uchar = CHAR_BIT as usize;
// integer division, but taking the ceiling instead of the floor
Expand All @@ -137,21 +142,33 @@ impl Type {
9..=16 => 16,
17..=32 => 32,
33..=64 => 64,
_ => return Err("enum cannot be represented in SIZE_T bits"),
_ => {
return Err(SemanticError::Generic(
"enum cannot be represented in SIZE_T bits".to_owned(),
))
}
})
}
Union(struct_type) => struct_type.union_size(),
Struct(struct_type) => struct_type.struct_size(),
Bitfield(_) => unimplemented!("sizeof(bitfield)"),
// illegal operations
Function(_) => Err("cannot take `sizeof` a function"),
Void => Err("cannot take `sizeof` void"),
VaList => Err("cannot take `sizeof` va_list"),
Error => Err("cannot take `sizeof` <type error>"),
Function(_) => Err(SemanticError::Generic(
"cannot take `sizeof` a function".to_owned(),
)),
Void => Err(SemanticError::Generic(
"cannot take `sizeof` void".to_owned(),
)),
VaList => Err(SemanticError::Generic(
"cannot take `sizeof` va_list".to_owned(),
)),
Error => Err(SemanticError::Generic(
"cannot take `sizeof` <type error>".to_owned(),
)),
}
}
/// Get the alignment of a type in bytes.
pub fn alignof(&self) -> Result<SIZE_T, &'static str> {
pub fn alignof(&self) -> Result<SIZE_T, SemanticError> {
match self {
Bool
| Char(_)
Expand All @@ -168,10 +185,18 @@ impl Type {
// Anyway, Faerie panics if the alignment isn't a power of two so it's probably for the best
Union(struct_type) | Struct(struct_type) => struct_type.align(),
Bitfield(_) => unimplemented!("alignof bitfield"),
Function(_) => Err("cannot take `alignof` function"),
Void => Err("cannot take `alignof` void"),
VaList => Err("cannot take `alignof` va_list"),
Error => Err("cannot take `alignof` <type error>"),
Function(_) => Err(SemanticError::Generic(
"cannot take `alignof` function".to_owned(),
)),
Void => Err(SemanticError::Generic(
"cannot take `alignof` void".to_owned(),
)),
VaList => Err(SemanticError::Generic(
"cannot take `alignof` va_list".to_owned(),
)),
Error => Err(SemanticError::Generic(
"cannot take `alignof` <type error>".to_owned(),
)),
}
}
/// Return an IR integer type large enough to contain a pointer.
Expand Down
37 changes: 19 additions & 18 deletions src/parse/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,8 @@ impl Expr {
right: Expr,
) -> RecoverableResult<(Expr, Expr), Locatable<SemanticError>> {
let (left, right) = (left.rval(), right.rval());
let ctype = Type::binary_promote(left.ctype.clone(), right.ctype.clone());
let ctype = Type::binary_promote(left.ctype.clone(), right.ctype.clone())
.map_err(|e| (e.into(), (left, right)))?; //TODO: currently stuck here.
match (left.cast(&ctype), right.cast(&ctype)) {
(Ok(left_cast), Ok(right_cast)) => Ok((left_cast, right_cast)),
(Err((err, left)), Ok(right)) | (Ok(left), Err((err, right)))
Expand Down Expand Up @@ -1601,25 +1602,25 @@ impl Type {
}
}
// Perform the 'default promotions' from 6.5.2.2.6
fn default_promote(self) -> Type {
if self.is_integral() {
self.integer_promote()
fn default_promote(self) -> Result<Type, SemanticError> {
Ok(if self.is_integral() {
self.integer_promote()?
} else if self == Type::Float {
Type::Double
} else {
self
}
})
}
fn integer_promote(self) -> Type {
if self.rank() <= Type::Int(true).rank() {
if Type::Int(true).can_represent(&self) {
fn integer_promote(self) -> Result<Type, SemanticError> {
Ok(if self.rank() <= Type::Int(true).rank() {
if Type::Int(true).can_represent(&self)? {
Type::Int(true)
} else {
Type::Int(false)
}
} else {
self
}
})
}
/// Perform the 'usual arithmetic conversions' from 6.3.1.8 of the C standard.
///
Expand All @@ -1638,34 +1639,34 @@ impl Type {
///
/// Trying to promote derived types (pointers, functions, etc.) is an error.
/// Pointer arithmetic should not promote either argument, see 6.5.6 of the C standard.
fn binary_promote(mut left: Type, mut right: Type) -> Type {
fn binary_promote(mut left: Type, mut right: Type) -> Result<Type, SemanticError> {
use Type::*;
if left == Double || right == Double {
return Double; // toil and trouble
return Ok(Double); // toil and trouble
} else if left == Float || right == Float {
return Float;
return Ok(Float);
}
left = left.integer_promote();
right = right.integer_promote();
left = left.integer_promote()?;
right = right.integer_promote()?;
let signs = (left.sign(), right.sign());
// same sign
if signs.0 == signs.1 {
return if left.rank() >= right.rank() {
return Ok(if left.rank() >= right.rank() {
left
} else {
right
};
});
};
let (signed, unsigned) = if signs.0 {
(left, right)
} else {
(right, left)
};
if signed.can_represent(&unsigned) {
Ok(if signed.can_represent(&unsigned)? {
signed
} else {
unsigned
}
})
}
fn pointer_promote(left: &mut Expr, right: &mut Expr) -> bool {
if left.ctype == right.ctype {
Expand Down

0 comments on commit 69c1d82

Please sign in to comment.