Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ The `<id>` can be a numeric literal (`0`, `1`, `42`) or a variable identifier (`
| Syntax | Description | Example |
| ------ | ----------- | ------- |
| `Int` | Integer type | `Int` |
| `Num` | Number (float) type | `Num` |
| `Bool` | Boolean type | `Bool` |
| `Null` | Null type | `Null` |
| `(T1, T2, ...)` | Tuple types | `(Int, Bool, Int)` |
Expand Down
5 changes: 1 addition & 4 deletions libs/@local/hashql/mir/src/body/constant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,11 @@
//! while preserving the semantics of complex primitive types that should not be
//! evaluated at compile time.

mod int;

use core::fmt;

use hashql_core::value::Primitive;

pub use self::int::{Int, TryFromIntegerError, TryFromPrimitiveError};
use crate::def::DefId;
use crate::{def::DefId, interpret::value::Int};

/// A constant value in the HashQL MIR.
///
Expand Down
8 changes: 6 additions & 2 deletions libs/@local/hashql/mir/src/body/rvalue/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ use crate::body::operand::Operand;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BinOp {
/// The `+` operator (addition).
Add(!),
Add,
/// The `-` operator (subtraction).
Sub(!),
Sub,
/// The `*` operator (multiplication).
Mul(!),
/// The `/` operator (division).
Expand Down Expand Up @@ -56,6 +56,8 @@ impl BinOp {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Add => "+",
Self::Sub => "-",
Self::BitAnd => "&",
Self::BitOr => "|",
Self::Eq => "==",
Expand All @@ -70,6 +72,8 @@ impl BinOp {
#[must_use]
pub const fn as_symbol(self) -> Symbol<'static> {
match self {
Self::Add => sym::symbol::add,
Self::Sub => sym::symbol::sub,
Self::BitAnd => sym::symbol::ampersand,
Self::BitOr => sym::symbol::pipe,
Self::Eq => sym::symbol::eq,
Expand Down
2 changes: 1 addition & 1 deletion libs/@local/hashql/mir/src/builder/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'env, 'heap> BaseBuilder<'env, 'heap> {

/// Creates an integer constant operand.
#[must_use]
pub fn const_int(self, value: i64) -> Operand<'heap> {
pub fn const_int(self, value: i128) -> Operand<'heap> {
Operand::Constant(Constant::Int(value.into()))
}

Expand Down
3 changes: 3 additions & 0 deletions libs/@local/hashql/mir/src/builder/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,9 @@ macro_rules! body {
(@type $types:ident; Int) => {
$types.integer()
};
(@type $types:ident; Num) => {
$types.number()
};
(@type $types:ident; ()) => {
$types.tuple([] as [hashql_core::r#type::TypeId; 0])
};
Expand Down
4 changes: 2 additions & 2 deletions libs/@local/hashql/mir/src/builder/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ impl<'heap> BuildOperand<'heap, f64> for OperandBuilder<'_, 'heap> {
}
}

impl<'heap> BuildOperand<'heap, i64> for OperandBuilder<'_, 'heap> {
fn build_operand(&self, value: i64) -> Operand<'heap> {
impl<'heap> BuildOperand<'heap, i128> for OperandBuilder<'_, 'heap> {
fn build_operand(&self, value: i128) -> Operand<'heap> {
self.base.const_int(value)
}
}
Expand Down
3 changes: 1 addition & 2 deletions libs/@local/hashql/mir/src/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ use hashql_diagnostics::{
};
use hashql_hir::node::operation::UnOp;

use super::value::{Ptr, Value, ValueTypeName};
use super::value::{Int, Ptr, Value, ValueTypeName};
use crate::body::{
constant::Int,
local::{Local, LocalDecl},
place::FieldIndex,
rvalue::BinOp,
Expand Down
7 changes: 5 additions & 2 deletions libs/@local/hashql/mir/src/interpret/locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,16 @@ mod tests {
use super::Locals;
use crate::{
body::{
constant::{Constant, Int},
constant::Constant,
local::{Local, LocalDecl, LocalSlice, LocalVec},
operand::Operand,
place::{FieldIndex, Place},
},
intern::Interner,
interpret::{error::RuntimeError, value::Value},
interpret::{
error::RuntimeError,
value::{Int, Value},
},
};

fn fill_decl(decl: &mut LocalVec<LocalDecl<'_>>, max_index: Local) {
Expand Down
34 changes: 34 additions & 0 deletions libs/@local/hashql/mir/src/interpret/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,40 @@ impl<'ctx, 'heap, A: Allocator + Clone> Runtime<'ctx, 'heap, A> {
let rhs = frame.locals.operand(right)?;

let value = match op {
BinOp::Add => {
return match (lhs.as_ref(), rhs.as_ref()) {
(Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::from(lhs + rhs)),
(Value::Integer(lhs), Value::Number(rhs)) => Ok(Value::Number(lhs + rhs)),
(Value::Number(lhs), Value::Integer(rhs)) => Ok(Value::Number(lhs + rhs)),
(Value::Number(lhs), Value::Number(rhs)) => Ok(Value::Number(lhs + rhs)),
_ => Err(RuntimeError::BinaryTypeMismatch(Box::new(
BinaryTypeMismatch {
op,
lhs_expected: TypeName::terse("Number"),
rhs_expected: TypeName::terse("Number"),
lhs: lhs.into_owned(),
rhs: rhs.into_owned(),
},
))),
};
}
BinOp::Sub => {
return match (lhs.as_ref(), rhs.as_ref()) {
(Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::from(lhs - rhs)),
(Value::Integer(lhs), Value::Number(rhs)) => Ok(Value::Number(lhs - rhs)),
(Value::Number(lhs), Value::Integer(rhs)) => Ok(Value::Number(lhs - rhs)),
(Value::Number(lhs), Value::Number(rhs)) => Ok(Value::Number(lhs - rhs)),
_ => Err(RuntimeError::BinaryTypeMismatch(Box::new(
BinaryTypeMismatch {
op,
lhs_expected: TypeName::terse("Number"),
rhs_expected: TypeName::terse("Number"),
lhs: lhs.into_owned(),
rhs: rhs.into_owned(),
},
))),
};
}
BinOp::BitAnd => {
return match (lhs.as_ref(), rhs.as_ref()) {
(Value::Integer(lhs), Value::Integer(rhs)) => Ok(Value::Integer(lhs & rhs)),
Expand Down
200 changes: 198 additions & 2 deletions libs/@local/hashql/mir/src/interpret/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ use hashql_core::{
r#type::{TypeId, environment::Environment},
};

use super::{CallStack, Runtime, RuntimeConfig, error::InterpretDiagnostic, value::Value};
use super::{
CallStack, Runtime, RuntimeConfig,
error::InterpretDiagnostic,
value::{Int, Num, Value},
};
use crate::{
body::{
Body,
constant::{Constant, Int},
constant::Constant,
operand::Operand,
rvalue::{Aggregate, AggregateKind, RValue},
},
Expand Down Expand Up @@ -289,6 +293,158 @@ fn binary_gte_integers() {
assert_eq!(result, Value::Integer(Int::from(true)));
}

#[test]
fn binary_add_integers() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Int {
decl result: Int;

bb0() {
result = bin.+ 2 3;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Integer(Int::from(5_i128)));
}

#[test]
fn binary_sub_integers() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Int {
decl result: Int;

bb0() {
result = bin.- 5 3;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Integer(Int::from(2_i128)));
}

#[test]
fn binary_add_numbers() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.+ 2.5 3.5;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(6.0)));
}

#[test]
fn binary_sub_numbers() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.- 5.5 3.0;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(2.5)));
}

#[test]
fn binary_add_int_number() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.+ 2 3.5;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(5.5)));
}

#[test]
fn binary_add_number_int() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.+ 2.5 3;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(5.5)));
}

#[test]
fn binary_sub_int_number() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.- 5 3.5;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(1.5)));
}

#[test]
fn binary_sub_number_int() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Num {
decl result: Num;

bb0() {
result = bin.- 5.5 3;
return result;
}
});

let result = run_body(body).expect("should succeed");
assert_eq!(result, Value::Number(Num::from(2.5)));
}

#[test]
fn binary_bitand_integers() {
let heap = Heap::new();
Expand Down Expand Up @@ -1111,6 +1267,46 @@ fn ice_unknown_field() {
assert_eq!(result.category, InterpretDiagnosticCategory::TypeInvariant);
}

#[test]
fn ice_binary_add_type_mismatch() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Int {
decl tup: (Int, Int), result: Int;

bb0() {
tup = tuple 1, 2;
result = bin.+ tup 3;
return result;
}
});

let result = run_body(body).expect_err("should fail with binary add type mismatch");
assert_eq!(result.category, InterpretDiagnosticCategory::TypeInvariant);
}

#[test]
fn ice_binary_sub_type_mismatch() {
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);

let body = body!(interner, env; fn@0/0 -> Int {
decl tup: (Int, Int), result: Int;

bb0() {
tup = tuple 1, 2;
result = bin.- 3 tup;
return result;
}
});

let result = run_body(body).expect_err("should fail with binary sub type mismatch");
assert_eq!(result.category, InterpretDiagnosticCategory::TypeInvariant);
}

#[test]
fn ice_binary_bitand_type_mismatch() {
let heap = Heap::new();
Expand Down
Loading
Loading