Add a parser test; Pass VM test
This commit is contained in:
parent
8b5eb9977c
commit
cf9a9837c8
@ -6,7 +6,7 @@ use std::{
|
||||
|
||||
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};
|
||||
|
||||
@ -338,6 +338,9 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
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 {
|
||||
PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean),
|
||||
PrimitiveValueExpression::Character(_) => Some(Type::Character),
|
||||
@ -682,6 +685,7 @@ impl From<char> for LiteralExpression {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LiteralExpression {
|
||||
BuiltInFunction(BuiltInFunction),
|
||||
Primitive(PrimitiveValueExpression),
|
||||
String(String),
|
||||
}
|
||||
@ -689,6 +693,9 @@ pub enum LiteralExpression {
|
||||
impl Display for LiteralExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LiteralExpression::BuiltInFunction(built_in_function) => {
|
||||
write!(f, "{built_in_function}")
|
||||
}
|
||||
LiteralExpression::Primitive(primitive) => {
|
||||
write!(f, "{primitive}")
|
||||
}
|
||||
@ -708,6 +715,11 @@ impl PartialOrd for LiteralExpression {
|
||||
impl Ord for LiteralExpression {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(
|
||||
LiteralExpression::BuiltInFunction(left),
|
||||
LiteralExpression::BuiltInFunction(right),
|
||||
) => left.cmp(right),
|
||||
(LiteralExpression::BuiltInFunction(_), _) => Ordering::Greater,
|
||||
(LiteralExpression::Primitive(left), LiteralExpression::Primitive(right)) => {
|
||||
left.cmp(right)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use crate::{Identifier, Type, Value};
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum BuiltInFunction {
|
||||
// String tools
|
||||
ToString,
|
||||
ToString { argument: Box<Value> },
|
||||
|
||||
// Integer and float tools
|
||||
IsEven,
|
||||
@ -34,26 +34,46 @@ impl BuiltInFunction {
|
||||
BuiltInFunction::IsOdd => "is_odd",
|
||||
BuiltInFunction::Length => "length",
|
||||
BuiltInFunction::ReadLine => "read_line",
|
||||
BuiltInFunction::ToString => "to_string",
|
||||
BuiltInFunction::ToString { .. } => "to_string",
|
||||
BuiltInFunction::WriteLine => "write_line",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_parameters(&self) -> Vec<(Identifier, Type)> {
|
||||
pub fn type_parameters(&self) -> Option<Vec<Identifier>> {
|
||||
match self {
|
||||
BuiltInFunction::ToString => vec![("value".into(), Type::Any)],
|
||||
BuiltInFunction::IsEven => vec![("value".into(), Type::Number)],
|
||||
BuiltInFunction::IsOdd => vec![("value".into(), Type::Number)],
|
||||
BuiltInFunction::Length => {
|
||||
vec![(
|
||||
"value".into(),
|
||||
Type::ListOf {
|
||||
item_type: Box::new(Type::Any),
|
||||
},
|
||||
)]
|
||||
}
|
||||
BuiltInFunction::ReadLine => vec![],
|
||||
BuiltInFunction::WriteLine => vec![("output".into(), Type::Any)],
|
||||
BuiltInFunction::ToString { .. } => None,
|
||||
BuiltInFunction::IsEven => None,
|
||||
BuiltInFunction::IsOdd => None,
|
||||
BuiltInFunction::Length => None,
|
||||
BuiltInFunction::ReadLine => None,
|
||||
BuiltInFunction::WriteLine => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_parameters(&self) -> Option<Vec<(Identifier, Type)>> {
|
||||
match self {
|
||||
BuiltInFunction::ToString { .. } => Some(vec![("value".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>>,
|
||||
) -> Result<Option<Value>, BuiltInFunctionError> {
|
||||
match self {
|
||||
BuiltInFunction::ToString => {
|
||||
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::ToString { argument } => Ok(Some(Value::string(argument))),
|
||||
BuiltInFunction::IsEven => {
|
||||
if let Some(value_arguments) = value_arguments {
|
||||
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 {
|
||||
|
@ -1,8 +1,8 @@
|
||||
//! 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 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
|
||||
/// 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 {
|
||||
DustError::Runtime { runtime_error, .. } => runtime_error.position(),
|
||||
DustError::Analysis { analysis_error, .. } => analysis_error.position(),
|
||||
DustError::Parse { parse_error, .. } => parse_error.position(),
|
||||
DustError::Lex { lex_error, .. } => lex_error.position(),
|
||||
DustError::Analysis { analysis_error, .. } => Some(analysis_error.position()),
|
||||
DustError::Parse { parse_error, .. } => Some(parse_error.position()),
|
||||
DustError::Lex { lex_error, .. } => Some(lex_error.position()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,10 +83,18 @@ impl<'src> DustError<'src> {
|
||||
let title = self.title();
|
||||
let span = self.position();
|
||||
let label = self.to_string();
|
||||
let message = Level::Error.title(title).snippet(
|
||||
Snippet::source(self.source())
|
||||
.annotation(Level::Info.span(span.0..span.1).label(&label)),
|
||||
);
|
||||
|
||||
let message = if let Some(span) = span {
|
||||
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();
|
||||
|
||||
format!("{}", renderer.render(message))
|
||||
|
@ -437,7 +437,6 @@ impl<'src> Lexer<'src> {
|
||||
"mut" => Token::Mut,
|
||||
"read_line" => Token::ReadLine,
|
||||
"struct" => Token::Struct,
|
||||
"to_string" => Token::ToString,
|
||||
"true" => Token::Boolean("true"),
|
||||
"while" => Token::While,
|
||||
"write_line" => Token::WriteLine,
|
||||
|
@ -822,7 +822,7 @@ impl<'src> Parser<'src> {
|
||||
Expression::tuple_access(left, index_node, position)
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
@ -1145,6 +1145,26 @@ mod tests {
|
||||
|
||||
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]
|
||||
fn map_expression() {
|
||||
let source = "map { x = '1', y = 2, z = 3.0 }";
|
||||
|
@ -36,7 +36,6 @@ pub enum Token<'src> {
|
||||
ReadLine,
|
||||
Str,
|
||||
Struct,
|
||||
ToString,
|
||||
While,
|
||||
WriteLine,
|
||||
|
||||
@ -123,7 +122,6 @@ impl<'src> Token<'src> {
|
||||
Token::String(text) => TokenOwned::String(text.to_string()),
|
||||
Token::Str => TokenOwned::Str,
|
||||
Token::Struct => TokenOwned::Struct,
|
||||
Token::ToString => TokenOwned::ToString,
|
||||
Token::While => TokenOwned::While,
|
||||
Token::WriteLine => TokenOwned::WriteLine,
|
||||
}
|
||||
@ -181,7 +179,6 @@ impl<'src> Token<'src> {
|
||||
Token::Slash => "/",
|
||||
Token::Str => "str",
|
||||
Token::Struct => "struct",
|
||||
Token::ToString => "to_string",
|
||||
Token::While => "while",
|
||||
Token::WriteLine => "write_line",
|
||||
}
|
||||
@ -238,7 +235,6 @@ impl<'src> Token<'src> {
|
||||
Token::Str => TokenKind::Str,
|
||||
Token::String(_) => TokenKind::String,
|
||||
Token::Struct => TokenKind::Struct,
|
||||
Token::ToString => TokenKind::ToString,
|
||||
Token::While => TokenKind::While,
|
||||
Token::WriteLine => TokenKind::WriteLine,
|
||||
}
|
||||
@ -332,7 +328,6 @@ pub enum TokenOwned {
|
||||
Mut,
|
||||
ReadLine,
|
||||
Str,
|
||||
ToString,
|
||||
While,
|
||||
WriteLine,
|
||||
|
||||
@ -421,7 +416,6 @@ impl Display for TokenOwned {
|
||||
TokenOwned::Str => Token::Str.fmt(f),
|
||||
TokenOwned::String(string) => write!(f, "{string}"),
|
||||
TokenOwned::Struct => Token::Struct.fmt(f),
|
||||
TokenOwned::ToString => Token::ToString.fmt(f),
|
||||
TokenOwned::While => Token::While.fmt(f),
|
||||
TokenOwned::WriteLine => Token::WriteLine.fmt(f),
|
||||
}
|
||||
@ -455,7 +449,6 @@ pub enum TokenKind {
|
||||
Map,
|
||||
ReadLine,
|
||||
Str,
|
||||
ToString,
|
||||
While,
|
||||
WriteLine,
|
||||
|
||||
@ -544,7 +537,6 @@ impl Display for TokenKind {
|
||||
TokenKind::Slash => Token::Slash.fmt(f),
|
||||
TokenKind::String => write!(f, "string value"),
|
||||
TokenKind::Struct => Token::Struct.fmt(f),
|
||||
TokenKind::ToString => Token::ToString.fmt(f),
|
||||
TokenKind::While => Token::While.fmt(f),
|
||||
TokenKind::WriteLine => Token::WriteLine.fmt(f),
|
||||
}
|
||||
@ -555,7 +547,7 @@ impl Display for TokenKind {
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
pub fn all_tokens<'src>() -> [Token<'src>; 52] {
|
||||
pub fn all_tokens<'src>() -> [Token<'src>; 51] {
|
||||
[
|
||||
Token::Identifier("foobar"),
|
||||
Token::Boolean("true"),
|
||||
@ -606,7 +598,6 @@ pub(crate) mod tests {
|
||||
Token::Star,
|
||||
Token::Str,
|
||||
Token::Struct,
|
||||
Token::ToString,
|
||||
Token::While,
|
||||
Token::WriteLine,
|
||||
]
|
||||
|
@ -371,7 +371,7 @@ impl Ord for Type {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionType {
|
||||
pub name: Identifier,
|
||||
pub type_parameters: Option<Vec<Type>>,
|
||||
pub type_parameters: Option<Vec<Identifier>>,
|
||||
pub value_parameters: Option<Vec<(Identifier, Type)>>,
|
||||
pub return_type: Option<Box<Type>>,
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ use serde::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
AbstractSyntaxTree, Context, EnumType, FunctionType, Identifier, RangeableType, RuntimeError,
|
||||
StructType, Type, Vm,
|
||||
AbstractSyntaxTree, BuiltInFunction, Context, EnumType, FunctionType, Identifier,
|
||||
RangeableType, RuntimeError, StructType, Type, Vm,
|
||||
};
|
||||
|
||||
/// Dust value representation
|
||||
@ -194,7 +194,15 @@ impl Value {
|
||||
Value::Character(_) => Type::Character,
|
||||
Value::Enum(Enum { r#type, .. }) => Type::Enum(r#type.clone()),
|
||||
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::List(values) => {
|
||||
let item_type = values.first().unwrap().r#type();
|
||||
@ -255,6 +263,14 @@ impl 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 {
|
||||
Value::Mutable(inner) => inner.read().unwrap().get_field(field),
|
||||
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)]
|
||||
pub struct Function {
|
||||
pub name: Identifier,
|
||||
pub r#type: FunctionType,
|
||||
pub body: Arc<AbstractSyntaxTree>,
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum Function {
|
||||
BuiltIn(BuiltInFunction),
|
||||
Parsed {
|
||||
name: Identifier,
|
||||
r#type: FunctionType,
|
||||
body: AbstractSyntaxTree,
|
||||
},
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn call(
|
||||
&self,
|
||||
self,
|
||||
_type_arguments: Option<Vec<Type>>,
|
||||
value_arguments: Option<Vec<Value>>,
|
||||
context: &Context,
|
||||
) -> 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)) =
|
||||
(&self.r#type.value_parameters, value_arguments)
|
||||
{
|
||||
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
|
||||
new_context.set_variable_value(identifier.clone(), value);
|
||||
if let (Some(value_parameters), Some(value_arguments)) =
|
||||
(&r#type.value_parameters, value_arguments)
|
||||
{
|
||||
for ((identifier, _), value) in value_parameters.iter().zip(value_arguments) {
|
||||
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 {
|
||||
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 {
|
||||
write!(f, "<")?;
|
||||
if let Some(type_parameters) = &r#type.type_parameters {
|
||||
write!(f, "<")?;
|
||||
|
||||
for (index, type_parameter) in type_parameters.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
for (index, type_parameter) in type_parameters.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
||||
write!(f, "{}", type_parameter)?;
|
||||
}
|
||||
|
||||
write!(f, ">")?;
|
||||
}
|
||||
|
||||
write!(f, "{}", type_parameter)?;
|
||||
}
|
||||
write!(f, "(")?;
|
||||
|
||||
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()?);
|
||||
if let Some(value_paramers) = &r#type.value_parameters {
|
||||
for (index, (identifier, r#type)) in value_paramers.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
"type" => {
|
||||
if r#type.is_some() {
|
||||
return Err(de::Error::duplicate_field("type"));
|
||||
}
|
||||
|
||||
r#type = Some(map.next_value()?);
|
||||
}
|
||||
"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"]));
|
||||
}
|
||||
write!(f, "{identifier}: {type}")?;
|
||||
}
|
||||
}
|
||||
|
||||
let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
|
||||
let r#type = r#type.ok_or_else(|| de::Error::missing_field("type"))?;
|
||||
let body = body.ok_or_else(|| de::Error::missing_field("body"))?;
|
||||
write!(f, ") {{")?;
|
||||
|
||||
Ok(Function { name, r#type, body })
|
||||
for statement in &body.statements {
|
||||
write!(f, "{}", statement)?;
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_struct("Function", &["name", "type", "body"], FunctionVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,8 @@ use crate::{
|
||||
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
|
||||
StructDefinition, StructExpression,
|
||||
},
|
||||
constructor::FieldsConstructor,
|
||||
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.
|
||||
@ -609,6 +608,9 @@ impl Vm {
|
||||
|
||||
fn run_literal(&self, literal: LiteralExpression) -> Result<Evaluation, RuntimeError> {
|
||||
let value = match literal {
|
||||
LiteralExpression::BuiltInFunction(built_in_function) => {
|
||||
Value::Function(Function::BuiltIn(built_in_function))
|
||||
}
|
||||
LiteralExpression::String(string) => Value::String(string),
|
||||
LiteralExpression::Primitive(primitive_expression) => match primitive_expression {
|
||||
PrimitiveValueExpression::Boolean(boolean) => Value::Boolean(boolean),
|
||||
@ -934,7 +936,6 @@ pub enum RuntimeError {
|
||||
// These should be prevented by running the analyzer before the VM
|
||||
BuiltInFunctionError {
|
||||
error: BuiltInFunctionError,
|
||||
position: Span,
|
||||
},
|
||||
EnumVariantNotFound {
|
||||
identifier: Identifier,
|
||||
@ -1006,8 +1007,9 @@ pub enum RuntimeError {
|
||||
}
|
||||
|
||||
impl RuntimeError {
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
pub fn position(&self) -> Option<Span> {
|
||||
let position = match self {
|
||||
Self::BuiltInFunctionError { .. } => return None,
|
||||
Self::ParseError(parse_error) => parse_error.position(),
|
||||
Self::Expression { position, .. } => *position,
|
||||
Self::Statement { position, .. } => *position,
|
||||
@ -1016,7 +1018,6 @@ impl RuntimeError {
|
||||
right_position,
|
||||
..
|
||||
} => (left_position.0, right_position.1),
|
||||
Self::BuiltInFunctionError { position, .. } => *position,
|
||||
Self::EnumVariantNotFound { position, .. } => *position,
|
||||
Self::ExpectedBoolean { position } => *position,
|
||||
Self::ExpectedConstructor { position, .. } => *position,
|
||||
@ -1042,7 +1043,9 @@ impl RuntimeError {
|
||||
Self::UndefinedProperty {
|
||||
property_position, ..
|
||||
} => *property_position,
|
||||
}
|
||||
};
|
||||
|
||||
Some(position)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user