Add integers and floats separately

This commit is contained in:
Sofia 2026-03-17 20:26:13 +02:00
parent 3b18b6c71e
commit 0795957d0d
4 changed files with 82 additions and 59 deletions

View File

@ -5,7 +5,7 @@ use crate::{
Parse, TokenRange, TokenStream, TokenStreamError,
lexer::{Keyword, Position, Token},
},
vm::LuaNumber,
vm::{LuaFloat, LuaInteger},
};
#[derive(Debug, Clone)]
@ -465,8 +465,8 @@ impl Parse for PrimaryExpression {
Expression::FunctionDefinition(function.kind.params, function.kind.block)
} else if let Some(Token::DecimalValue(value)) = peeked {
stream.next(); // Consume decimal value
Expression::Literal(Literal::Number(LuaNumber(
u64::from_str_radix(&value, 10).unwrap() as f64,
Expression::Literal(Literal::Integer(LuaInteger(
u64::from_str_radix(&value, 10).unwrap(),
)))
} else if let Some(Token::StringLit(value)) = peeked {
stream.next(); // Consume string-literal
@ -553,6 +553,7 @@ fn parse_binop_rhs(
#[derive(Debug, Clone)]
pub enum Literal {
Number(LuaNumber),
Float(LuaFloat),
Integer(LuaInteger),
String(String),
}

View File

@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use crate::{
ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator},
vm::{Constant, Instruction, VMNumber},
vm::{Constant, Instruction, VMFloat},
};
pub struct State {
@ -371,9 +371,14 @@ impl Expression {
constants
}
Expression::Literal(literal) => match literal {
Literal::Number(value) => {
Literal::Float(value) => {
let mut constants = HashSet::new();
constants.insert(Constant::Number(value.vm_number()));
constants.insert(Constant::Float(value.vm_number()));
constants
}
Literal::Integer(value) => {
let mut constants = HashSet::new();
constants.insert(Constant::Integer(*value));
constants
}
Literal::String(value) => {
@ -596,8 +601,9 @@ impl Expression {
instructions.push(Instruction::LoadK(
reg,
state.get_constant(&match literal {
Literal::Number(value) => Constant::Number(value.vm_number()),
Literal::Float(value) => Constant::Float(value.vm_number()),
Literal::String(value) => Constant::String(value.clone()),
Literal::Integer(lua_integer) => Constant::Integer(*lua_integer),
}),
));
(instructions, vec![reg])

View File

@ -6,7 +6,7 @@ use crate::{
TokenStream,
lexer::{Token, tokenize},
},
vm::{LuaNumber, RuntimeError, RustFunction, VirtualMachine},
vm::{LuaFloat, RuntimeError, RustFunction, VirtualMachine},
};
mod ast;
@ -23,7 +23,7 @@ impl RustFunction for Max {
let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil);
let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil);
match lhs.lt(&rhs)? {
vm::Value::Number(value) => {
vm::Value::Float(value) => {
let res = value.lua_number();
Ok(vec![if res.0 > 0. { rhs } else { lhs }])
}

114
src/vm.rs
View File

@ -14,30 +14,39 @@ use crate::{
};
#[derive(Clone, Hash, PartialEq, Eq, Copy)]
pub struct VMNumber(u64);
pub struct VMFloat(u64);
impl VMNumber {
pub fn lua_number(&self) -> LuaNumber {
LuaNumber(f64::from_bits(self.0))
impl VMFloat {
pub fn lua_number(&self) -> LuaFloat {
LuaFloat(f64::from_bits(self.0))
}
}
#[derive(Clone, Copy)]
pub struct LuaNumber(pub f64);
impl LuaNumber {
pub fn vm_number(&self) -> VMNumber {
VMNumber(f64::to_bits(self.0))
}
}
impl Debug for VMNumber {
impl Debug for VMFloat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.lua_number().fmt(f)
}
}
impl Debug for LuaNumber {
#[derive(Clone, Copy)]
pub struct LuaFloat(pub f64);
impl LuaFloat {
pub fn vm_number(&self) -> VMFloat {
VMFloat(f64::to_bits(self.0))
}
}
impl Debug for LuaFloat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct LuaInteger(pub u64);
impl Debug for LuaInteger {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
@ -46,14 +55,16 @@ impl Debug for LuaNumber {
#[derive(Clone, Hash, PartialEq, Eq)]
pub enum Constant {
String(String),
Number(VMNumber),
Float(VMFloat),
Integer(LuaInteger),
}
impl Debug for Constant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
Self::Number(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
Self::Float(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
}
}
}
@ -202,7 +213,8 @@ impl Environment {
#[derive(Clone)]
pub enum Value {
String(String),
Number(VMNumber),
Float(VMFloat),
Integer(LuaInteger),
RustFunction(Rc<RefCell<dyn RustFunction>>),
Function(Closure),
Nil,
@ -213,7 +225,8 @@ impl Value {
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
match self {
Value::String(value) => Ok(IndexableValue::String(value)),
Value::Number(value) => Ok(IndexableValue::Number(value)),
Value::Float(value) => Ok(IndexableValue::Number(value)),
Value::Integer(value) => Ok(IndexableValue::Integer(value)),
Value::RustFunction(value) => {
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
}
@ -227,7 +240,8 @@ impl Value {
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum IndexableValue {
String(String),
Number(VMNumber),
Number(VMFloat),
Integer(LuaInteger),
RustFunction(String),
Function(u32),
}
@ -235,9 +249,9 @@ pub enum IndexableValue {
impl Value {
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber(lhs.lua_number().0 + rhs.lua_number().0);
Ok(Value::Number(res.vm_number()))
(Value::Float(lhs), Value::Float(rhs)) => {
let res = LuaFloat(lhs.lua_number().0 + rhs.lua_number().0);
Ok(Value::Float(res.vm_number()))
}
_ => Err(RuntimeError::InvalidOperands(
BinaryOperator::Add,
@ -249,9 +263,9 @@ impl Value {
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber((lhs == rhs) as u64 as f64);
Ok(Value::Number(res.vm_number()))
(Value::Float(lhs), Value::Float(rhs)) => {
let res = LuaFloat((lhs == rhs) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
_ => Err(RuntimeError::InvalidOperands(
BinaryOperator::Equal,
@ -263,9 +277,9 @@ impl Value {
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber((lhs.lua_number().0 < rhs.lua_number().0) as u64 as f64);
Ok(Value::Number(res.vm_number()))
(Value::Float(lhs), Value::Float(rhs)) => {
let res = LuaFloat((lhs.lua_number().0 < rhs.lua_number().0) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
_ => Err(RuntimeError::InvalidOperands(
BinaryOperator::LessThan,
@ -277,9 +291,9 @@ impl Value {
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Number(lhs), Value::Number(rhs)) => {
let res = LuaNumber((lhs.lua_number().0 <= rhs.lua_number().0) as u64 as f64);
Ok(Value::Number(res.vm_number()))
(Value::Float(lhs), Value::Float(rhs)) => {
let res = LuaFloat((lhs.lua_number().0 <= rhs.lua_number().0) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
_ => Err(RuntimeError::InvalidOperands(
BinaryOperator::LessThanOrEqual,
@ -291,9 +305,9 @@ impl Value {
pub fn unm(&self) -> Result<Value, RuntimeError> {
match self {
Value::Number(lhs) => {
let res = LuaNumber(-lhs.lua_number().0);
Ok(Value::Number(res.vm_number()))
Value::Float(lhs) => {
let res = LuaFloat(-lhs.lua_number().0);
Ok(Value::Float(res.vm_number()))
}
_ => Err(RuntimeError::InvalidOperand(
UnaryOperator::Negation,
@ -305,14 +319,14 @@ impl Value {
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Nil, _) | (_, Value::Nil) => Ok(Value::Nil),
(Value::Number(lhs), Value::Number(rhs)) => {
(Value::Float(lhs), Value::Float(rhs)) => {
let res =
LuaNumber((lhs.lua_number().0 > 0. && rhs.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Number(res.vm_number()))
LuaFloat((lhs.lua_number().0 > 0. && rhs.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
(Value::Number(value), _) | (_, Value::Number(value)) => {
let res = LuaNumber((value.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Number(res.vm_number()))
(Value::Float(value), _) | (_, Value::Float(value)) => {
let res = LuaFloat((value.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
_ => Ok(Value::Nil),
}
@ -321,14 +335,14 @@ impl Value {
pub fn or(&self, other: &Value) -> Result<Value, RuntimeError> {
match (self, other) {
(Value::Nil, value) | (value, Value::Nil) => Ok(value.clone()),
(Value::Number(lhs), Value::Number(rhs)) => {
(Value::Float(lhs), Value::Float(rhs)) => {
let res =
LuaNumber((lhs.lua_number().0 > 0. || rhs.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Number(res.vm_number()))
LuaFloat((lhs.lua_number().0 > 0. || rhs.lua_number().0 > 0.) as u64 as f64);
Ok(Value::Float(res.vm_number()))
}
(Value::Number(value), other) => {
(Value::Float(value), other) => {
if value.lua_number().0 > 0. {
Ok(Value::Number(*value))
Ok(Value::Float(*value))
} else {
Ok(other.clone())
}
@ -342,7 +356,8 @@ impl Value {
impl Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Number(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
Value::Float(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
Value::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
Value::String(value) => f.debug_tuple("String").field(value).finish(),
Value::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
Value::Function(closure) => f
@ -567,7 +582,8 @@ impl ClosureRunner {
*reg,
StackValue::Value(match constants.get(*constant as usize).unwrap() {
Constant::String(value) => Value::String(value.clone()),
Constant::Number(value) => Value::Number(*value),
Constant::Float(value) => Value::Float(*value),
Constant::Integer(value) => Value::Integer(*value),
}),
);
}
@ -687,7 +703,7 @@ impl ClosureRunner {
.map(|v| v.borrow().clone())
.unwrap_or(Value::Nil)
{
Value::Number(val) => (val.lua_number().0 as u16) == *c,
Value::Float(val) => (val.lua_number().0 as u16) == *c,
_ => false,
};
if is_true {