Skip to content

Commit

Permalink
Continued improving casting operations, and fixed a few improper conv…
Browse files Browse the repository at this point in the history
…ersions
  • Loading branch information
IsaacShelton committed Oct 21, 2024
1 parent c8023c0 commit fc26095
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 60 deletions.
5 changes: 1 addition & 4 deletions src/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,7 @@ impl<'a, S: SyscallHandler> Interpreter<'a, S> {
Value::StructLiteral(_) => Value::Undefined,
}
}
ir::Instruction::Negate(_) => todo!("Interpreter / ir::Instruction::Negate"),
ir::Instruction::NegateFloat(_) => {
todo!("Interpreter /ir::Instruction::NegateFloat")
}
ir::Instruction::Negate(..) => todo!("Interpreter / ir::Instruction::Negate"),
ir::Instruction::BitComplement(_) => {
todo!("Interpreter / ir::Instruction::BitComplement")
}
Expand Down
4 changes: 1 addition & 3 deletions src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,7 @@ pub enum Instruction {
StructLiteral(Type, Vec<Value>),
IsZero(Value, FloatOrInteger),
IsNonZero(Value, FloatOrInteger),
Negate(Value),
NegateFloat(Value),
Negate(Value, FloatOrInteger),
BitComplement(Value),
Break(Break),
ConditionalBreak(Value, ConditionalBreak),
Expand Down Expand Up @@ -585,7 +584,6 @@ impl Instruction {
Self::IsZero(..) => false,
Self::IsNonZero(..) => false,
Self::Negate(..) => false,
Self::NegateFloat(..) => false,
Self::BitComplement(..) => false,
Self::Break(..) => true,
Self::ConditionalBreak(..) => true,
Expand Down
6 changes: 5 additions & 1 deletion src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ impl<T: Text + Send> Lexer<T> {
'n' => state.value.push('\n'),
'r' => state.value.push('\r'),
't' => state.value.push('\t'),
'0' => state.value.push('\0'),
'"' | '\'' => state.value.push(next_c),
_ => return Has(TokenKind::Error("Unrecognized escape sequence".into()).at(c_source)),
}
Expand All @@ -441,7 +442,10 @@ impl<T: Text + Send> Lexer<T> {
state.can_neg = false;
state.value.push(self.characters.next().unwrap().0);
Waiting
} else if state.can_dot && self.characters.eat('.') {
} else if state.can_dot
&& self.characters.peek_nth(1).is_digit()
&& self.characters.eat('.')
{
state.can_dot = false;
state.value.push('.');
Waiting
Expand Down
16 changes: 10 additions & 6 deletions src/llvm_backend/functions/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,13 +600,17 @@ pub unsafe fn create_function_block(
),
})
}
Instruction::Negate(inner) => {
Instruction::Negate(inner, floating) => {
let value = build_value(ctx, value_catalog, builder, inner)?;
Some(LLVMBuildNeg(builder.get(), value, cstr!("").as_ptr()))
}
Instruction::NegateFloat(inner) => {
let value = build_value(ctx, value_catalog, builder, inner)?;
Some(LLVMBuildFNeg(builder.get(), value, cstr!("").as_ptr()))

Some(match floating {
FloatOrInteger::Integer => {
LLVMBuildNeg(builder.get(), value, cstr!("").as_ptr())
}
FloatOrInteger::Float => {
LLVMBuildFNeg(builder.get(), value, cstr!("").as_ptr())
}
})
}
Instruction::BitComplement(inner) => {
let value = build_value(ctx, value_catalog, builder, inner)?;
Expand Down
18 changes: 12 additions & 6 deletions src/lower/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,20 @@ pub fn integer_extend(
ir_module: &ir::Module,
function: &resolved::Function,
resolved_ast: &resolved::Ast,
cast: &Cast,
cast_from: &CastFrom,
) -> Result<Value, LowerError> {
let value = lower_expr(builder, ir_module, &cast.value, function, resolved_ast)?;
let ir_type = lower_type(&ir_module.target, &cast.target_type, resolved_ast)?;
let value = lower_expr(
builder,
ir_module,
&cast_from.cast.value,
function,
resolved_ast,
)?;
let ir_type = lower_type(&ir_module.target, &cast_from.cast.target_type, resolved_ast)?;

Ok(builder.push(
match cast
.target_type
match cast_from
.from_type
.kind
.sign(Some(&ir_module.target))
.expect("integer extend result type to be an integer type")
Expand All @@ -63,7 +69,7 @@ pub fn integer_cast(
.expect("to type to be an integer");

if from_size < to_size {
integer_extend(builder, ir_module, function, resolved_ast, &cast_from.cast)
integer_extend(builder, ir_module, function, resolved_ast, &cast_from)
} else if from_size > to_size {
integer_truncate(builder, ir_module, function, resolved_ast, &cast_from.cast)
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,8 +706,8 @@ fn lower_expr(
ExprKind::IntegerCast(cast_from) => {
integer_cast(builder, ir_module, function, resolved_ast, cast_from)
}
ExprKind::IntegerExtend(cast) => {
integer_extend(builder, ir_module, function, resolved_ast, cast)
ExprKind::IntegerExtend(cast_from) => {
integer_extend(builder, ir_module, function, resolved_ast, cast_from)
}
ExprKind::IntegerTruncate(cast) => {
integer_truncate(builder, ir_module, function, resolved_ast, cast)
Expand Down Expand Up @@ -826,7 +826,7 @@ fn lower_expr(
let instruction = match operator {
resolved::UnaryMathOperator::Not => ir::Instruction::IsZero(value, float_or_int),
resolved::UnaryMathOperator::BitComplement => ir::Instruction::BitComplement(value),
resolved::UnaryMathOperator::Negate => ir::Instruction::Negate(value),
resolved::UnaryMathOperator::Negate => ir::Instruction::Negate(value, float_or_int),
resolved::UnaryMathOperator::IsNonZero => {
ir::Instruction::IsNonZero(value, float_or_int)
}
Expand Down
41 changes: 27 additions & 14 deletions src/resolve/conform/from_integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub fn from_integer<O: Objective>(
TypeKind::Integer(to_bits, to_sign) => match behavior {
ConformBehavior::Adept(_) => from_integer_adept_mode::<O>(
&expr,
from_type,
mode,
from_bits,
from_sign,
Expand All @@ -28,6 +29,7 @@ pub fn from_integer<O: Objective>(
),
ConformBehavior::C => from_integer_c_mode::<O>(
&expr,
from_type,
mode,
from_bits,
from_sign,
Expand All @@ -53,6 +55,7 @@ pub fn from_integer<O: Objective>(

fn from_integer_c_mode<O: Objective>(
expr: &Expr,
from_type: &Type,
mode: ConformMode,
from_bits: IntegerBits,
from_sign: IntegerSign,
Expand All @@ -71,15 +74,18 @@ fn from_integer_c_mode<O: Objective>(
}

if mode.allow_lossy_integer() {
let cast = Cast::new(target_type.clone(), expr.clone());
return O::success(|| {
let cast = Cast::new(target_type.clone(), expr.clone());

let kind = if from_bits < to_bits {
ExprKind::IntegerExtend(Box::new(cast))
} else {
ExprKind::IntegerTruncate(Box::new(cast))
};
let kind = if from_bits < to_bits {
ExprKind::IntegerExtend(Box::new(CastFrom {
cast,
from_type: from_type.clone(),
}))
} else {
ExprKind::IntegerTruncate(Box::new(cast))
};

return O::success(|| {
TypedExpr::new(
target_type,
Expr {
Expand Down Expand Up @@ -118,12 +124,12 @@ fn conform_from_integer_to_c_integer<O: Objective>(
};

if mode.allow_lossy_integer() || is_lossless {
let cast_from = CastFrom {
cast: Cast::new(target_type.clone(), expr.clone()),
from_type: from_type.clone(),
};

return O::success(|| {
let cast_from = CastFrom {
cast: Cast::new(target_type.clone(), expr.clone()),
from_type: from_type.clone(),
};

TypedExpr::new(
target_type,
ExprKind::IntegerCast(Box::new(cast_from)).at(source),
Expand All @@ -136,6 +142,7 @@ fn conform_from_integer_to_c_integer<O: Objective>(

fn from_integer_adept_mode<O: Objective>(
expr: &Expr,
from_type: &Type,
mode: ConformMode,
from_bits: IntegerBits,
from_sign: IntegerSign,
Expand All @@ -158,9 +165,15 @@ fn from_integer_adept_mode<O: Objective>(
}

O::success(|| {
let cast = Cast::new(target_type.clone(), expr.clone());

TypedExpr::new(
target_type.clone(),
ExprKind::IntegerExtend(Box::new(Cast::new(target_type, expr.clone()))).at(expr.source),
target_type,
ExprKind::IntegerExtend(Box::new(CastFrom {
cast,
from_type: from_type.clone(),
}))
.at(expr.source),
)
})
}
72 changes: 55 additions & 17 deletions src/resolve/expr/call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{resolve_expr, PreferredType, ResolveExprCtx};
use crate::{
ast::{self, CInteger},
ast::{self, CInteger, FloatSize},
ir::IntegerSign,
resolve::{
conform::{conform_expr, to_default::conform_expr_to_default, ConformMode, Perform},
Expand All @@ -11,6 +11,7 @@ use crate::{
source_files::Source,
};
use itertools::Itertools;
use num::BigInt;

pub fn resolve_call_expr(
ctx: &mut ResolveExprCtx,
Expand Down Expand Up @@ -91,6 +92,21 @@ pub fn resolve_call_expr(
let argument_type_kind = &arguments[0].resolved_type.kind;

if let Some(target_type_kind) = target_type_kind {
if target_type_kind.is_boolean() && argument_type_kind.is_integer_literal() {
let argument = arguments.into_iter().next().unwrap();
let is_initialized = argument.is_initialized;

let resolved::ExprKind::IntegerLiteral(value) = &argument.expr.kind else {
unreachable!();
};

return Ok(TypedExpr {
resolved_type: target_type_kind.at(source),
expr: resolved::ExprKind::BooleanLiteral(*value != BigInt::ZERO).at(source),
is_initialized,
});
}

if target_type_kind.is_boolean()
&& (argument_type_kind.is_integer_like() || argument_type_kind.is_float_like())
{
Expand Down Expand Up @@ -151,34 +167,56 @@ pub fn resolve_call_expr(
}
}

let target_type_kind = match name.as_ref() {
"f32" | "float" => Some(resolved::TypeKind::f32()),
"f64" | "double" => Some(resolved::TypeKind::f64()),
let to_float = match name.as_ref() {
"f32" | "float" => Some((resolved::TypeKind::f32(), FloatSize::Bits32)),
"f64" | "double" => Some((resolved::TypeKind::f64(), FloatSize::Bits64)),
_ => None,
};

if let Some(target_type_kind) = target_type_kind {
if argument_type_kind.is_boolean() {
let target_type = target_type_kind.at(source);
if let Some((target_type_kind, float_size)) = to_float {
if argument_type_kind.is_integer_literal() {
let argument = arguments.into_iter().next().unwrap();
let is_initialized = argument.is_initialized;

let expr = resolved::ExprKind::UnaryMathOperation(Box::new(
resolved::UnaryMathOperation {
operator: resolved::UnaryMathOperator::IsNonZero,
inner: argument,
},
))
.at(source);
let resolved::ExprKind::IntegerLiteral(value) = &argument.expr.kind else {
unreachable!();
};

// TOOD: CLEANUP: This conversion could probably be cleaner
let Ok(value) = i64::try_from(value)
.map(|x| x as f64)
.or_else(|_| u64::try_from(value).map(|x| x as f64))
.or_else(|_| value.to_string().parse::<f64>())
else {
return Err(ResolveErrorKind::Other {
message: format!("Cannot create out-of-range floating-point number"),
}
.at(source));
};

return Ok(TypedExpr {
resolved_type: target_type,
expr,
resolved_type: target_type_kind.at(source),
expr: resolved::ExprKind::FloatingLiteral(float_size, value).at(source),
is_initialized,
});
}

if argument_type_kind.is_integer_like() {
if argument_type_kind.is_float_literal() {
let argument = arguments.into_iter().next().unwrap();
let is_initialized = argument.is_initialized;

let resolved::ExprKind::FloatingLiteral(_size, value) = &argument.expr.kind else {
unreachable!();
};

return Ok(TypedExpr {
resolved_type: target_type_kind.at(source),
expr: resolved::ExprKind::FloatingLiteral(float_size, *value).at(source),
is_initialized,
});
}

if argument_type_kind.is_integer_like() || argument_type_kind.is_boolean() {
let target_type = target_type_kind.at(source);
let argument = arguments.into_iter().next().unwrap();

Expand Down
28 changes: 23 additions & 5 deletions src/resolve/expr/unary_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,39 @@ pub fn resolve_unary_math_operation_expr(
let resolved_expr = resolve_expr(ctx, inner, preferred_type, Initialized::Require)
.and_then(|expr| conform_expr_to_default_or_error(expr, ctx.c_integer_assumptions()))?;

if resolved_expr.resolved_type.is_ambiguous() {
let from_type = &resolved_expr.resolved_type;

if from_type.is_ambiguous() {
return Err(ResolveErrorKind::CannotPerformUnaryOperationForType {
operator: operator.to_string(),
bad_type: resolved_expr.resolved_type.to_string(),
bad_type: from_type.to_string(),
}
.at(source));
}

let result_type = match operator {
UnaryMathOperator::Not | UnaryMathOperator::IsNonZero => TypeKind::Boolean.at(source),
UnaryMathOperator::BitComplement | UnaryMathOperator::Negate => {
resolved_expr.resolved_type.clone()
UnaryMathOperator::Not => (from_type.kind.is_boolean() || from_type.kind.is_integer_like())
.then(|| TypeKind::Boolean.at(source)),
UnaryMathOperator::IsNonZero => (from_type.kind.is_boolean()
|| from_type.kind.is_integer_like()
|| from_type.kind.is_float_like())
.then(|| TypeKind::Boolean.at(source)),
UnaryMathOperator::Negate => (from_type.kind.is_integer_like()
|| from_type.kind.is_float_like())
.then(|| from_type.clone()),
UnaryMathOperator::BitComplement => {
(from_type.kind.is_integer_like()).then(|| from_type.clone())
}
};

let Some(result_type) = result_type else {
return Err(ResolveErrorKind::CannotPerformUnaryOperationForType {
operator: operator.to_string(),
bad_type: from_type.to_string(),
}
.at(source));
};

Ok(TypedExpr::new(
result_type,
Expr::new(
Expand Down
Loading

0 comments on commit fc26095

Please sign in to comment.