From 9baf34336aa2472d9749c15fd20e034efd95f6eb Mon Sep 17 00:00:00 2001 From: Doonv <58695417+doonv@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:26:11 +0200 Subject: [PATCH] Add typeof function --- src/builtin_parser/number.rs | 29 ++++++++++++++++++++++++++--- src/builtin_parser/runner.rs | 7 +++++-- src/builtin_parser/runner/error.rs | 4 ++-- src/builtin_parser/runner/stdlib.rs | 5 +++++ src/builtin_parser/runner/value.rs | 28 +++++++++++++++++++++++----- 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/builtin_parser/number.rs b/src/builtin_parser/number.rs index b6640e6..26b6463 100644 --- a/src/builtin_parser/number.rs +++ b/src/builtin_parser/number.rs @@ -78,8 +78,31 @@ impl Number { } } - /// Returns a [`&'static str`](str) represents the kind of the number. + /// Returns the kind of [`Number`] as a [string slice](str). + /// You may want to use [`natural_kind`](Self::natural_kind) + /// instead for more natural sounding error messsages pub fn kind(&self) -> &'static str { + match self { + Number::Float(_) => "float", + Number::Integer(_) => "integer", + Number::u8(_) => "u8", + Number::u16(_) => "u16", + Number::u32(_) => "u32", + Number::u64(_) => "u64", + Number::usize(_) => "usize", + Number::i8(_) => "i8", + Number::i16(_) => "i16", + Number::i32(_) => "i32", + Number::i64(_) => "i64", + Number::isize(_) => "usize", + Number::f32(_) => "f32", + Number::f64(_) => "f64", + } + } + + /// Returns the kind of [`Number`] as a [string slice](str) with an `a` or `an` prepended to it. + /// Used for more natural sounding error messages. + pub fn natural_kind(&self) -> &'static str { match self { Number::Float(_) => "a float", Number::Integer(_) => "an integer", @@ -167,8 +190,8 @@ macro_rules! impl_op { (Number::f32(left), Number::Float(right)) => Ok(Number::f32(left $op right as f32)), (Number::f64(left), Number::Float(right)) => Ok(Number::f64(left $op right as f64)), _ => Err(RunError::IncompatibleNumberTypes { - left: left.kind(), - right: right.kind(), + left: left.natural_kind(), + right: right.natural_kind(), span }) } diff --git a/src/builtin_parser/runner.rs b/src/builtin_parser/runner.rs index ee53e21..a9c7aca 100644 --- a/src/builtin_parser/runner.rs +++ b/src/builtin_parser/runner.rs @@ -157,7 +157,10 @@ fn eval_expression( }, )?; - *variable.upgrade().unwrap().borrow_mut() = value; + match variable.upgrade() { + Some(strong) => *strong.borrow_mut() = value, + None => todo_error!("cannot "), + } Ok(Value::Reference(variable)) } @@ -664,7 +667,7 @@ fn eval_path( Ok(expr.span.wrap(Path::Variable(reference.clone()))) } else { Err(RunError::CannotDereferenceValue( - expr.span.wrap(borrow.kind()), + expr.span.wrap(borrow.natural_kind()), )) } } diff --git a/src/builtin_parser/runner/error.rs b/src/builtin_parser/runner/error.rs index 945820c..f4bff1e 100644 --- a/src/builtin_parser/runner/error.rs +++ b/src/builtin_parser/runner/error.rs @@ -105,7 +105,7 @@ impl RunError { } ExpectedNumberAfterUnaryOperator(Spanned { value, .. }) => format!( "Expected a number after unary operator (-) but got {} instead.", - value.kind() + value.natural_kind() ) .into(), CannotIndexValue(_) => todo!(), @@ -144,7 +144,7 @@ impl RunError { } CannotNegateUnsignedInteger(Spanned { value, .. }) => format!( "Unsigned integers cannot be negated. (Type: {})", - value.kind() + value.natural_kind() ) .into(), IncompatibleNumberTypes { left, right, .. } => { diff --git a/src/builtin_parser/runner/stdlib.rs b/src/builtin_parser/runner/stdlib.rs index 78f7063..100cb2a 100644 --- a/src/builtin_parser/runner/stdlib.rs +++ b/src/builtin_parser/runner/stdlib.rs @@ -68,6 +68,10 @@ fn print_env(env: &mut Environment) { } } +fn typeof_value(value: Value) -> String { + value.kind().to_string() +} + /// Disposes of a [`Value`]. fn drop(_: Value) {} @@ -78,5 +82,6 @@ pub fn register(environment: &mut Environment) { fn ref_depth; fn drop; fn print_env; + fn typeof_value as "typeof"; }); } diff --git a/src/builtin_parser/runner/value.rs b/src/builtin_parser/runner/value.rs index 731a052..d38dd57 100644 --- a/src/builtin_parser/runner/value.rs +++ b/src/builtin_parser/runner/value.rs @@ -197,11 +197,29 @@ impl Value { } /// Returns the kind of [`Value`] as a [string slice](str). - /// Used for more natural sounding error messages. + /// You may want to use [`natural_kind`](Self::natural_kind) + /// instead for more natural sounding error messsages pub fn kind(&self) -> &'static str { match self { - Value::None => "nothing", + Value::None => "none", Value::Number(number) => number.kind(), + Value::Boolean(..) => "boolean", + Value::String(..) => "string", + Value::Reference(..) => "reference", + Value::Object(..) => "object", + Value::StructObject { .. } => "struct object", + Value::Tuple(..) => "tuple", + Value::StructTuple { .. } => "struct tuple", + Value::Resource(..) => "resource", + } + } + + /// Returns the kind of [`Value`] as a [string slice](str) with an `a` or `an` prepended to it. + /// Used for more natural sounding error messages. + pub fn natural_kind(&self) -> &'static str { + match self { + Value::None => "nothing", + Value::Number(number) => number.natural_kind(), Value::Boolean(..) => "a boolean", Value::String(..) => "a string", Value::Reference(..) => "a reference", @@ -482,7 +500,7 @@ macro_rules! impl_function_param_for_value { } else { Err(RunError::IncompatibleFunctionParameter { expected: stringify!($type), - actual: value.value.kind(), + actual: value.value.natural_kind(), span: value.span, }) } @@ -520,7 +538,7 @@ macro_rules! impl_function_param_for_numbers { Value::Number(Number::$generic(value)) => Ok(value as $number), _ => Err(RunError::IncompatibleFunctionParameter { expected: concat!("a ", stringify!($number)), - actual: value.value.kind(), + actual: value.value.natural_kind(), span: value.span, }) } @@ -535,7 +553,7 @@ macro_rules! impl_function_param_for_numbers { Value::Number(Number::$generic(value)) => Ok(value as $number), _ => Err(RunError::IncompatibleFunctionParameter { expected: concat!("a ", stringify!($number)), - actual: value.value.kind(), + actual: value.value.natural_kind(), span: value.span }) }