Add a parser test; Pass VM test

This commit is contained in:
Jeff 2024-08-20 07:20:44 -04:00
parent 8b5eb9977c
commit cf9a9837c8
9 changed files with 173 additions and 188 deletions

View File

@ -6,7 +6,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Context, FunctionType, Identifier, RangeableType, StructType, Type}; use crate::{BuiltInFunction, Context, FunctionType, Identifier, RangeableType, StructType, Type};
use super::{Node, Span, Statement}; use super::{Node, Span, Statement};
@ -338,6 +338,9 @@ impl Expression {
} }
} }
Expression::Literal(literal_expression) => match literal_expression.inner.as_ref() { Expression::Literal(literal_expression) => match literal_expression.inner.as_ref() {
LiteralExpression::BuiltInFunction(built_in_function) => {
built_in_function.return_type()
}
LiteralExpression::Primitive(primitive_value) => match primitive_value { LiteralExpression::Primitive(primitive_value) => match primitive_value {
PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean), PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean),
PrimitiveValueExpression::Character(_) => Some(Type::Character), PrimitiveValueExpression::Character(_) => Some(Type::Character),
@ -682,6 +685,7 @@ impl From<char> for LiteralExpression {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum LiteralExpression { pub enum LiteralExpression {
BuiltInFunction(BuiltInFunction),
Primitive(PrimitiveValueExpression), Primitive(PrimitiveValueExpression),
String(String), String(String),
} }
@ -689,6 +693,9 @@ pub enum LiteralExpression {
impl Display for LiteralExpression { impl Display for LiteralExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
LiteralExpression::BuiltInFunction(built_in_function) => {
write!(f, "{built_in_function}")
}
LiteralExpression::Primitive(primitive) => { LiteralExpression::Primitive(primitive) => {
write!(f, "{primitive}") write!(f, "{primitive}")
} }
@ -708,6 +715,11 @@ impl PartialOrd for LiteralExpression {
impl Ord for LiteralExpression { impl Ord for LiteralExpression {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
match (self, other) { match (self, other) {
(
LiteralExpression::BuiltInFunction(left),
LiteralExpression::BuiltInFunction(right),
) => left.cmp(right),
(LiteralExpression::BuiltInFunction(_), _) => Ordering::Greater,
(LiteralExpression::Primitive(left), LiteralExpression::Primitive(right)) => { (LiteralExpression::Primitive(left), LiteralExpression::Primitive(right)) => {
left.cmp(right) left.cmp(right)
} }

View File

@ -13,7 +13,7 @@ use crate::{Identifier, Type, Value};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInFunction { pub enum BuiltInFunction {
// String tools // String tools
ToString, ToString { argument: Box<Value> },
// Integer and float tools // Integer and float tools
IsEven, IsEven,
@ -34,26 +34,46 @@ impl BuiltInFunction {
BuiltInFunction::IsOdd => "is_odd", BuiltInFunction::IsOdd => "is_odd",
BuiltInFunction::Length => "length", BuiltInFunction::Length => "length",
BuiltInFunction::ReadLine => "read_line", BuiltInFunction::ReadLine => "read_line",
BuiltInFunction::ToString => "to_string", BuiltInFunction::ToString { .. } => "to_string",
BuiltInFunction::WriteLine => "write_line", BuiltInFunction::WriteLine => "write_line",
} }
} }
pub fn value_parameters(&self) -> Vec<(Identifier, Type)> { pub fn type_parameters(&self) -> Option<Vec<Identifier>> {
match self { match self {
BuiltInFunction::ToString => vec![("value".into(), Type::Any)], BuiltInFunction::ToString { .. } => None,
BuiltInFunction::IsEven => vec![("value".into(), Type::Number)], BuiltInFunction::IsEven => None,
BuiltInFunction::IsOdd => vec![("value".into(), Type::Number)], BuiltInFunction::IsOdd => None,
BuiltInFunction::Length => { BuiltInFunction::Length => None,
vec![( BuiltInFunction::ReadLine => None,
"value".into(), BuiltInFunction::WriteLine => None,
Type::ListOf { }
item_type: Box::new(Type::Any), }
},
)] pub fn value_parameters(&self) -> Option<Vec<(Identifier, Type)>> {
} match self {
BuiltInFunction::ReadLine => vec![], BuiltInFunction::ToString { .. } => Some(vec![("value".into(), Type::Any)]),
BuiltInFunction::WriteLine => vec![("output".into(), Type::Any)], BuiltInFunction::IsEven => Some(vec![("value".into(), Type::Number)]),
BuiltInFunction::IsOdd => Some(vec![("value".into(), Type::Number)]),
BuiltInFunction::Length => Some(vec![(
"value".into(),
Type::ListOf {
item_type: Box::new(Type::Any),
},
)]),
BuiltInFunction::ReadLine => None,
BuiltInFunction::WriteLine => Some(vec![("output".into(), Type::Any)]),
}
}
pub fn return_type(&self) -> Option<Type> {
match self {
BuiltInFunction::ToString { .. } => Some(Type::String),
BuiltInFunction::IsEven => Some(Type::Boolean),
BuiltInFunction::IsOdd => Some(Type::Boolean),
BuiltInFunction::Length => Some(Type::Number),
BuiltInFunction::ReadLine => Some(Type::String),
BuiltInFunction::WriteLine => None,
} }
} }
@ -63,17 +83,7 @@ impl BuiltInFunction {
value_arguments: Option<Vec<Value>>, value_arguments: Option<Vec<Value>>,
) -> Result<Option<Value>, BuiltInFunctionError> { ) -> Result<Option<Value>, BuiltInFunctionError> {
match self { match self {
BuiltInFunction::ToString => { BuiltInFunction::ToString { argument } => Ok(Some(Value::string(argument))),
if let Some(value_arguments) = value_arguments {
if value_arguments.len() == 1 {
Ok(Some(Value::string(value_arguments[0].to_string())))
} else {
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
}
} else {
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
}
}
BuiltInFunction::IsEven => { BuiltInFunction::IsEven => {
if let Some(value_arguments) = value_arguments { if let Some(value_arguments) = value_arguments {
if value_arguments.len() == 1 { if value_arguments.len() == 1 {
@ -145,17 +155,6 @@ impl BuiltInFunction {
} }
} }
} }
pub fn expected_return_type(&self) -> Option<Type> {
match self {
BuiltInFunction::ToString => Some(Type::String),
BuiltInFunction::IsEven => Some(Type::Boolean),
BuiltInFunction::IsOdd => Some(Type::Boolean),
BuiltInFunction::Length => Some(Type::Integer),
BuiltInFunction::ReadLine => Some(Type::String),
BuiltInFunction::WriteLine => None,
}
}
} }
impl Display for BuiltInFunction { impl Display for BuiltInFunction {

View File

@ -1,8 +1,8 @@
//! Top-level error handling for the Dust language. //! Top-level error handling for the Dust language.
use annotate_snippets::{Level, Renderer, Snippet}; use annotate_snippets::{Level, Message, Renderer, Snippet};
use std::fmt::Display; use std::fmt::Display;
use crate::{AnalysisError, LexError, ParseError, RuntimeError}; use crate::{ast::Span, AnalysisError, LexError, ParseError, RuntimeError};
/// An error that occurred during the execution of the Dust language and its /// An error that occurred during the execution of the Dust language and its
/// corresponding source code. /// corresponding source code.
@ -61,12 +61,12 @@ impl<'src> DustError<'src> {
} }
} }
pub fn position(&self) -> (usize, usize) { pub fn position(&self) -> Option<Span> {
match self { match self {
DustError::Runtime { runtime_error, .. } => runtime_error.position(), DustError::Runtime { runtime_error, .. } => runtime_error.position(),
DustError::Analysis { analysis_error, .. } => analysis_error.position(), DustError::Analysis { analysis_error, .. } => Some(analysis_error.position()),
DustError::Parse { parse_error, .. } => parse_error.position(), DustError::Parse { parse_error, .. } => Some(parse_error.position()),
DustError::Lex { lex_error, .. } => lex_error.position(), DustError::Lex { lex_error, .. } => Some(lex_error.position()),
} }
} }
@ -83,10 +83,18 @@ impl<'src> DustError<'src> {
let title = self.title(); let title = self.title();
let span = self.position(); let span = self.position();
let label = self.to_string(); let label = self.to_string();
let message = Level::Error.title(title).snippet(
Snippet::source(self.source()) let message = if let Some(span) = span {
.annotation(Level::Info.span(span.0..span.1).label(&label)), Level::Error.title(title).snippet(
); Snippet::source(self.source())
.annotation(Level::Info.span(span.0..span.1).label(&label)),
)
} else {
Level::Error
.title(title)
.snippet(Snippet::source(self.source()))
.footer(Level::Info.title("No position information available"))
};
let renderer = Renderer::styled(); let renderer = Renderer::styled();
format!("{}", renderer.render(message)) format!("{}", renderer.render(message))

View File

@ -437,7 +437,6 @@ impl<'src> Lexer<'src> {
"mut" => Token::Mut, "mut" => Token::Mut,
"read_line" => Token::ReadLine, "read_line" => Token::ReadLine,
"struct" => Token::Struct, "struct" => Token::Struct,
"to_string" => Token::ToString,
"true" => Token::Boolean("true"), "true" => Token::Boolean("true"),
"while" => Token::While, "while" => Token::While,
"write_line" => Token::WriteLine, "write_line" => Token::WriteLine,

View File

@ -822,7 +822,7 @@ impl<'src> Parser<'src> {
Expression::tuple_access(left, index_node, position) Expression::tuple_access(left, index_node, position)
} else { } else {
let field = self.parse_identifier()?; let field = self.parse_identifier()?;
let position = (left.position().0, self.current_position.1); let position = (left.position().0, field.position.1);
Expression::field_access(left, field, position) Expression::field_access(left, field, position)
} }
@ -1145,6 +1145,26 @@ mod tests {
use super::*; use super::*;
#[test]
fn built_in_function() {
let source = "42.to_string()";
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::call(
Expression::field_access(
Expression::literal(42, (0, 2)),
Node::new(Identifier::new("to_string"), (3, 12)),
(0, 12)
),
vec![],
(0, 14)
))
]))
);
}
#[test] #[test]
fn map_expression() { fn map_expression() {
let source = "map { x = '1', y = 2, z = 3.0 }"; let source = "map { x = '1', y = 2, z = 3.0 }";

View File

@ -36,7 +36,6 @@ pub enum Token<'src> {
ReadLine, ReadLine,
Str, Str,
Struct, Struct,
ToString,
While, While,
WriteLine, WriteLine,
@ -123,7 +122,6 @@ impl<'src> Token<'src> {
Token::String(text) => TokenOwned::String(text.to_string()), Token::String(text) => TokenOwned::String(text.to_string()),
Token::Str => TokenOwned::Str, Token::Str => TokenOwned::Str,
Token::Struct => TokenOwned::Struct, Token::Struct => TokenOwned::Struct,
Token::ToString => TokenOwned::ToString,
Token::While => TokenOwned::While, Token::While => TokenOwned::While,
Token::WriteLine => TokenOwned::WriteLine, Token::WriteLine => TokenOwned::WriteLine,
} }
@ -181,7 +179,6 @@ impl<'src> Token<'src> {
Token::Slash => "/", Token::Slash => "/",
Token::Str => "str", Token::Str => "str",
Token::Struct => "struct", Token::Struct => "struct",
Token::ToString => "to_string",
Token::While => "while", Token::While => "while",
Token::WriteLine => "write_line", Token::WriteLine => "write_line",
} }
@ -238,7 +235,6 @@ impl<'src> Token<'src> {
Token::Str => TokenKind::Str, Token::Str => TokenKind::Str,
Token::String(_) => TokenKind::String, Token::String(_) => TokenKind::String,
Token::Struct => TokenKind::Struct, Token::Struct => TokenKind::Struct,
Token::ToString => TokenKind::ToString,
Token::While => TokenKind::While, Token::While => TokenKind::While,
Token::WriteLine => TokenKind::WriteLine, Token::WriteLine => TokenKind::WriteLine,
} }
@ -332,7 +328,6 @@ pub enum TokenOwned {
Mut, Mut,
ReadLine, ReadLine,
Str, Str,
ToString,
While, While,
WriteLine, WriteLine,
@ -421,7 +416,6 @@ impl Display for TokenOwned {
TokenOwned::Str => Token::Str.fmt(f), TokenOwned::Str => Token::Str.fmt(f),
TokenOwned::String(string) => write!(f, "{string}"), TokenOwned::String(string) => write!(f, "{string}"),
TokenOwned::Struct => Token::Struct.fmt(f), TokenOwned::Struct => Token::Struct.fmt(f),
TokenOwned::ToString => Token::ToString.fmt(f),
TokenOwned::While => Token::While.fmt(f), TokenOwned::While => Token::While.fmt(f),
TokenOwned::WriteLine => Token::WriteLine.fmt(f), TokenOwned::WriteLine => Token::WriteLine.fmt(f),
} }
@ -455,7 +449,6 @@ pub enum TokenKind {
Map, Map,
ReadLine, ReadLine,
Str, Str,
ToString,
While, While,
WriteLine, WriteLine,
@ -544,7 +537,6 @@ impl Display for TokenKind {
TokenKind::Slash => Token::Slash.fmt(f), TokenKind::Slash => Token::Slash.fmt(f),
TokenKind::String => write!(f, "string value"), TokenKind::String => write!(f, "string value"),
TokenKind::Struct => Token::Struct.fmt(f), TokenKind::Struct => Token::Struct.fmt(f),
TokenKind::ToString => Token::ToString.fmt(f),
TokenKind::While => Token::While.fmt(f), TokenKind::While => Token::While.fmt(f),
TokenKind::WriteLine => Token::WriteLine.fmt(f), TokenKind::WriteLine => Token::WriteLine.fmt(f),
} }
@ -555,7 +547,7 @@ impl Display for TokenKind {
pub(crate) mod tests { pub(crate) mod tests {
use super::*; use super::*;
pub fn all_tokens<'src>() -> [Token<'src>; 52] { pub fn all_tokens<'src>() -> [Token<'src>; 51] {
[ [
Token::Identifier("foobar"), Token::Identifier("foobar"),
Token::Boolean("true"), Token::Boolean("true"),
@ -606,7 +598,6 @@ pub(crate) mod tests {
Token::Star, Token::Star,
Token::Str, Token::Str,
Token::Struct, Token::Struct,
Token::ToString,
Token::While, Token::While,
Token::WriteLine, Token::WriteLine,
] ]

View File

@ -371,7 +371,7 @@ impl Ord for Type {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType { pub struct FunctionType {
pub name: Identifier, pub name: Identifier,
pub type_parameters: Option<Vec<Type>>, pub type_parameters: Option<Vec<Identifier>>,
pub value_parameters: Option<Vec<(Identifier, Type)>>, pub value_parameters: Option<Vec<(Identifier, Type)>>,
pub return_type: Option<Box<Type>>, pub return_type: Option<Box<Type>>,
} }

View File

@ -16,8 +16,8 @@ use serde::{
}; };
use crate::{ use crate::{
AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, RangeableType, RuntimeError, AbstractSyntaxTree, BuiltInFunction, Context, EnumType, FunctionType, Identifier,
StructType, Type, Vm, RangeableType, RuntimeError, StructType, Type, Vm,
}; };
/// Dust value representation /// Dust value representation
@ -194,7 +194,15 @@ impl Value {
Value::Character(_) => Type::Character, Value::Character(_) => Type::Character,
Value::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()), Value::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()),
Value::Float(_) => Type::Float, Value::Float(_) => Type::Float,
Value::Function(function) => Type::Function(function.r#type.clone()), Value::Function(Function::BuiltIn(built_in_function)) => Type::Function(FunctionType {
name: Identifier::new(built_in_function.name()),
type_parameters: built_in_function.type_parameters(),
value_parameters: built_in_function.value_parameters(),
return_type: built_in_function.return_type().map(Box::new),
}),
Value::Function(Function::Parsed { name, r#type, body }) => {
Type::Function(r#type.clone())
}
Value::Integer(_) => Type::Integer, Value::Integer(_) => Type::Integer,
Value::List(values) => { Value::List(values) => {
let item_type = values.first().unwrap().r#type(); let item_type = values.first().unwrap().r#type();
@ -255,6 +263,14 @@ impl Value {
} }
pub fn get_field(&self, field: &Identifier) -> Option<Value> { pub fn get_field(&self, field: &Identifier) -> Option<Value> {
if let "to_string" = field.as_str() {
return Some(Value::Function(Function::BuiltIn(
BuiltInFunction::ToString {
argument: Box::new(self.clone()),
},
)));
}
match self { match self {
Value::Mutable(inner) => inner.read().unwrap().get_field(field), Value::Mutable(inner) => inner.read().unwrap().get_field(field),
Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(), Value::Struct(Struct::Fields { fields, .. }) => fields.get(field).cloned(),
@ -1059,151 +1075,88 @@ impl<'de> Deserialize<'de> for Value {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Function { pub enum Function {
pub name: Identifier, BuiltIn(BuiltInFunction),
pub r#type: FunctionType, Parsed {
pub body: Arc<AbstractSyntaxTree>, name: Identifier,
r#type: FunctionType,
body: AbstractSyntaxTree,
},
} }
impl Function { impl Function {
pub fn call( pub fn call(
&self, self,
_type_arguments: Option<Vec<Type>>, _type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>, value_arguments: Option<Vec<Value>>,
context: &Context, context: &Context,
) -> Result<Option<Value>, RuntimeError> { ) -> Result<Option<Value>, RuntimeError> {
let new_context = Context::with_data_from(context); match self {
Function::BuiltIn(built_in_function) => built_in_function
.call(_type_arguments, value_arguments)
.map_err(|error| RuntimeError::BuiltInFunctionError { error }),
Function::Parsed { r#type, body, .. } => {
let new_context = Context::with_data_from(context);
if let (Some(value_parameters), Some(value_arguments)) = if let (Some(value_parameters), Some(value_arguments)) =
(&self.r#type.value_parameters, value_arguments) (&r#type.value_parameters, value_arguments)
{ {
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) { for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
new_context.set_variable_value(identifier.clone(), value); new_context.set_variable_value(identifier.clone(), value);
}
}
let mut vm = Vm::new(body, new_context);
vm.run()
} }
} }
let mut vm = Vm::new(self.body.as_ref().clone(), new_context);
vm.run()
} }
} }
impl Display for Function { impl Display for Function {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "fn {}", self.name)?; match self {
Function::BuiltIn(built_in_function) => write!(f, "{}", built_in_function),
Function::Parsed { name, r#type, body } => {
write!(f, "fn {}", name)?;
if let Some(type_parameters) = &self.r#type.type_parameters { if let Some(type_parameters) = &r#type.type_parameters {
write!(f, "<")?; write!(f, "<")?;
for (index, type_parameter) in type_parameters.iter().enumerate() { for (index, type_parameter) in type_parameters.iter().enumerate() {
if index > 0 { if index > 0 {
write!(f, ", ")?; write!(f, ", ")?;
}
write!(f, "{}", type_parameter)?;
}
write!(f, ">")?;
} }
write!(f, "{}", type_parameter)?; write!(f, "(")?;
}
write!(f, ">")?; if let Some(value_paramers) = &r#type.value_parameters {
} for (index, (identifier, r#type)) in value_paramers.iter().enumerate() {
if index > 0 {
write!(f, "(")?; write!(f, ", ")?;
if let Some(value_paramers) = &self.r#type.value_parameters {
for (index, (identifier, r#type)) in value_paramers.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{identifier}: {type}")?;
}
}
write!(f, ") {{")?;
for statement in &self.body.statements {
write!(f, "{}", statement)?;
}
write!(f, "}}")
}
}
impl Serialize for Function {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut ser = serializer.serialize_struct("Function", 3)?;
ser.serialize_field("name", &self.name)?;
ser.serialize_field("type", &self.r#type)?;
ser.serialize_field("body", self.body.as_ref())?;
ser.end()
}
}
impl<'de> Deserialize<'de> for Function {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FunctionVisitor;
impl<'de> Visitor<'de> for FunctionVisitor {
type Value = Function;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a function")
}
fn visit_map<A>(self, mut map: A) -> Result<Function, A::Error>
where
A: MapAccess<'de>,
{
let mut name = None;
let mut r#type = None;
let mut body = None;
while let Some(key) = map.next_key()? {
match key {
"name" => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
} }
"type" => {
if r#type.is_some() {
return Err(de::Error::duplicate_field("type"));
}
r#type = Some(map.next_value()?); write!(f, "{identifier}: {type}")?;
}
"body" => {
if body.is_some() {
return Err(de::Error::duplicate_field("body"));
}
body = Some(map.next_value().map(Arc::new)?);
}
_ => {
return Err(de::Error::unknown_field(key, &["name", "type", "body"]));
}
} }
} }
let name = name.ok_or_else(|| de::Error::missing_field("name"))?; write!(f, ") {{")?;
let r#type = r#type.ok_or_else(|| de::Error::missing_field("type"))?;
let body = body.ok_or_else(|| de::Error::missing_field("body"))?;
Ok(Function { name, r#type, body }) for statement in &body.statements {
write!(f, "{}", statement)?;
}
write!(f, "}}")
} }
} }
deserializer.deserialize_struct("Function", &["name", "type", "body"], FunctionVisitor)
} }
} }

View File

@ -20,9 +20,8 @@ use crate::{
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement, OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
StructDefinition, StructExpression, StructDefinition, StructExpression,
}, },
constructor::FieldsConstructor,
parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, DustError,
Expression, Identifier, ParseError, Struct, StructType, Type, Value, ValueError, Expression, Function, Identifier, ParseError, StructType, Type, Value, ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -609,6 +608,9 @@ impl Vm {
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> { fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> {
let value = match literal { let value = match literal {
LiteralExpression::BuiltInFunction(built_in_function) => {
Value::Function(Function::BuiltIn(built_in_function))
}
LiteralExpression::String(string) => Value::String(string), LiteralExpression::String(string) => Value::String(string),
LiteralExpression::Primitive(primitive_expression) => match primitive_expression { LiteralExpression::Primitive(primitive_expression) => match primitive_expression {
PrimitiveValueExpression::Boolean(boolean) => Value::Boolean(boolean), PrimitiveValueExpression::Boolean(boolean) => Value::Boolean(boolean),
@ -934,7 +936,6 @@ pub enum RuntimeError {
// These should be prevented by running the analyzer before the VM // These should be prevented by running the analyzer before the VM
BuiltInFunctionError { BuiltInFunctionError {
error: BuiltInFunctionError, error: BuiltInFunctionError,
position: Span,
}, },
EnumVariantNotFound { EnumVariantNotFound {
identifier: Identifier, identifier: Identifier,
@ -1006,8 +1007,9 @@ pub enum RuntimeError {
} }
impl RuntimeError { impl RuntimeError {
pub fn position(&self) -> Span { pub fn position(&self) -> Option<Span> {
match self { let position = match self {
Self::BuiltInFunctionError { .. } => return None,
Self::ParseError(parse_error) => parse_error.position(), Self::ParseError(parse_error) => parse_error.position(),
Self::Expression { position, .. } => *position, Self::Expression { position, .. } => *position,
Self::Statement { position, .. } => *position, Self::Statement { position, .. } => *position,
@ -1016,7 +1018,6 @@ impl RuntimeError {
right_position, right_position,
.. ..
} => (left_position.0, right_position.1), } => (left_position.0, right_position.1),
Self::BuiltInFunctionError { position, .. } => *position,
Self::EnumVariantNotFound { position, .. } => *position, Self::EnumVariantNotFound { position, .. } => *position,
Self::ExpectedBoolean { position } => *position, Self::ExpectedBoolean { position } => *position,
Self::ExpectedConstructor { position, .. } => *position, Self::ExpectedConstructor { position, .. } => *position,
@ -1042,7 +1043,9 @@ impl RuntimeError {
Self::UndefinedProperty { Self::UndefinedProperty {
property_position, .. property_position, ..
} => *property_position, } => *property_position,
} };
Some(position)
} }
} }