Simplify built-in functions
This commit is contained in:
parent
c75dedb117
commit
f106d64367
@ -1,4 +1,4 @@
|
|||||||
use std::{array, fs::read_to_string, io::stdin};
|
use std::{fs::read_to_string, io::stdin};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::from_str;
|
use serde_json::from_str;
|
||||||
@ -15,64 +15,21 @@ use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum BuiltInFunctionCall {
|
pub enum BuiltInFunctionCall {
|
||||||
Length(BuiltInContextBinding<Length>),
|
Length(Length),
|
||||||
ReadFile(BuiltInContextBinding<ReadFile>),
|
ReadFile(ReadFile),
|
||||||
ReadLine(BuiltInContextBinding<ReadLine>),
|
ReadLine(ReadLine),
|
||||||
Sleep(BuiltInContextBinding<Sleep>),
|
Sleep(Sleep),
|
||||||
WriteLine(BuiltInContextBinding<WriteLine>),
|
WriteLine(WriteLine),
|
||||||
JsonParse(BuiltInContextBinding<JsonParse>),
|
JsonParse(JsonParse),
|
||||||
}
|
|
||||||
|
|
||||||
impl BuiltInFunctionCall {
|
|
||||||
pub fn length(argument: Expression) -> Self {
|
|
||||||
BuiltInFunctionCall::Length(BuiltInContextBinding::new(Length(Box::new(argument))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_file(argument: Expression) -> Self {
|
|
||||||
BuiltInFunctionCall::ReadFile(BuiltInContextBinding::new(ReadFile(Box::new(argument))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_line() -> Self {
|
|
||||||
BuiltInFunctionCall::ReadLine(BuiltInContextBinding::new(ReadLine))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sleep(argument: Expression) -> Self {
|
|
||||||
BuiltInFunctionCall::Sleep(BuiltInContextBinding::new(Sleep(Box::new(argument))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write_line(argument: Expression) -> Self {
|
|
||||||
BuiltInFunctionCall::WriteLine(BuiltInContextBinding::new(WriteLine(Box::new(argument))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn json_parse(r#type: TypeConstructor, argument: Expression) -> Self {
|
|
||||||
BuiltInFunctionCall::JsonParse(BuiltInContextBinding::new(JsonParse(
|
|
||||||
r#type,
|
|
||||||
Box::new(argument),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractNode for BuiltInFunctionCall {
|
impl AbstractNode for BuiltInFunctionCall {
|
||||||
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||||
match self {
|
Ok(())
|
||||||
BuiltInFunctionCall::Length(inner) => inner.define_types(_context),
|
|
||||||
BuiltInFunctionCall::ReadFile(inner) => inner.define_types(_context),
|
|
||||||
BuiltInFunctionCall::ReadLine(inner) => inner.define_types(_context),
|
|
||||||
BuiltInFunctionCall::Sleep(inner) => inner.define_types(_context),
|
|
||||||
BuiltInFunctionCall::WriteLine(inner) => inner.define_types(_context),
|
|
||||||
BuiltInFunctionCall::JsonParse(inner) => inner.define_types(_context),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
match self {
|
Ok(())
|
||||||
BuiltInFunctionCall::Length(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
BuiltInFunctionCall::ReadFile(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
BuiltInFunctionCall::ReadLine(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
BuiltInFunctionCall::Sleep(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
BuiltInFunctionCall::WriteLine(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
BuiltInFunctionCall::JsonParse(inner) => inner.validate(_context, _manage_memory),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(
|
fn evaluate(
|
||||||
@ -81,70 +38,28 @@ impl AbstractNode for BuiltInFunctionCall {
|
|||||||
_manage_memory: bool,
|
_manage_memory: bool,
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunctionCall::Length(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::Length(inner) => inner.call(_context, _manage_memory),
|
||||||
BuiltInFunctionCall::ReadFile(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::ReadFile(inner) => inner.call(_context, _manage_memory),
|
||||||
BuiltInFunctionCall::ReadLine(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::ReadLine(inner) => inner.call(_context, _manage_memory),
|
||||||
BuiltInFunctionCall::Sleep(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::Sleep(inner) => inner.call(_context, _manage_memory),
|
||||||
BuiltInFunctionCall::WriteLine(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::WriteLine(inner) => inner.call(_context, _manage_memory),
|
||||||
BuiltInFunctionCall::JsonParse(inner) => inner.evaluate(_context, _manage_memory),
|
BuiltInFunctionCall::JsonParse(inner) => inner.call(_context, _manage_memory),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Context) -> Result<Option<Type>, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
BuiltInFunctionCall::Length(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::Length(inner) => inner.return_type(_context),
|
||||||
BuiltInFunctionCall::ReadFile(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::ReadFile(inner) => inner.return_type(_context),
|
||||||
BuiltInFunctionCall::ReadLine(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::ReadLine(inner) => inner.return_type(_context),
|
||||||
BuiltInFunctionCall::Sleep(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::Sleep(inner) => inner.return_type(_context),
|
||||||
BuiltInFunctionCall::WriteLine(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::WriteLine(inner) => inner.return_type(_context),
|
||||||
BuiltInFunctionCall::JsonParse(inner) => inner.expected_type(_context),
|
BuiltInFunctionCall::JsonParse(inner) => inner.return_type(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct BuiltInContextBinding<F> {
|
|
||||||
function: F,
|
|
||||||
#[serde(skip)]
|
|
||||||
context: Context,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> BuiltInContextBinding<F> {
|
|
||||||
pub fn new(function: F) -> Self {
|
|
||||||
Self {
|
|
||||||
function,
|
|
||||||
context: Context::new(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Eq> Eq for BuiltInContextBinding<F> {}
|
|
||||||
|
|
||||||
impl<F: PartialEq> PartialEq for BuiltInContextBinding<F> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.function == other.function
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Ord> PartialOrd for BuiltInContextBinding<F> {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
||||||
Some(self.function.cmp(&other.function))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F: Ord> Ord for BuiltInContextBinding<F> {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
||||||
self.function.cmp(&other.function)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait FunctionLogic {
|
trait FunctionLogic {
|
||||||
fn arguments(
|
|
||||||
self,
|
|
||||||
) -> (
|
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
);
|
|
||||||
fn return_type(&self, context: &Context) -> Result<Option<Type>, ValidationError>;
|
fn return_type(&self, context: &Context) -> Result<Option<Type>, ValidationError>;
|
||||||
fn call(
|
fn call(
|
||||||
self,
|
self,
|
||||||
@ -153,68 +68,16 @@ trait FunctionLogic {
|
|||||||
) -> Result<Option<Evaluation>, RuntimeError>;
|
) -> Result<Option<Evaluation>, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> AbstractNode for BuiltInContextBinding<F>
|
|
||||||
where
|
|
||||||
F: FunctionLogic + Clone,
|
|
||||||
{
|
|
||||||
fn define_types(&self, _: &Context) -> Result<(), ValidationError> {
|
|
||||||
let (type_arguments, value_arguments) = self.function.clone().arguments();
|
|
||||||
|
|
||||||
if let Some(type_arguments) = type_arguments {
|
|
||||||
for identifier in type_arguments {
|
|
||||||
self.context.set_type(
|
|
||||||
identifier.clone(),
|
|
||||||
Type::Generic {
|
|
||||||
identifier,
|
|
||||||
concrete_type: None,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(value_arguments) = value_arguments {
|
|
||||||
for (identifier, r#type) in value_arguments {
|
|
||||||
self.context.set_type(identifier, r#type)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn evaluate(
|
|
||||||
self,
|
|
||||||
context: &Context,
|
|
||||||
manage_memory: bool,
|
|
||||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
|
||||||
self.context.set_parent(context.clone())?;
|
|
||||||
self.function.call(&self.context, manage_memory)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
|
|
||||||
self.function.return_type(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Length(Box<Expression>);
|
pub struct Length(Box<Expression>);
|
||||||
|
|
||||||
impl FunctionLogic for Length {
|
impl Length {
|
||||||
fn arguments(
|
pub fn new(expression: Expression) -> Self {
|
||||||
self,
|
Length(Box::new(expression))
|
||||||
) -> (
|
}
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
None::<array::IntoIter<Identifier, 0>>,
|
|
||||||
Some([(Identifier::new("list"), Type::ListOf(Box::new(Type::Any)))].into_iter()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionLogic for Length {
|
||||||
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
Ok(Some(Type::Integer))
|
Ok(Some(Type::Integer))
|
||||||
}
|
}
|
||||||
@ -251,19 +114,13 @@ impl FunctionLogic for Length {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct ReadFile(Box<Expression>);
|
pub struct ReadFile(Box<Expression>);
|
||||||
|
|
||||||
impl FunctionLogic for ReadFile {
|
impl ReadFile {
|
||||||
fn arguments(
|
pub fn new(expression: Expression) -> Self {
|
||||||
self,
|
ReadFile(Box::new(expression))
|
||||||
) -> (
|
}
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
None::<array::IntoIter<Identifier, 0>>,
|
|
||||||
Some([(Identifier::new("path"), Type::ListOf(Box::new(Type::Any)))].into_iter()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionLogic for ReadFile {
|
||||||
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
Ok(Some(Type::String))
|
Ok(Some(Type::String))
|
||||||
}
|
}
|
||||||
@ -287,18 +144,6 @@ impl FunctionLogic for ReadFile {
|
|||||||
pub struct ReadLine;
|
pub struct ReadLine;
|
||||||
|
|
||||||
impl FunctionLogic for ReadLine {
|
impl FunctionLogic for ReadLine {
|
||||||
fn arguments(
|
|
||||||
self,
|
|
||||||
) -> (
|
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
None::<array::IntoIter<Identifier, 0>>,
|
|
||||||
None::<array::IntoIter<(Identifier, Type), 0>>,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
Ok(Some(Type::String))
|
Ok(Some(Type::String))
|
||||||
}
|
}
|
||||||
@ -317,19 +162,13 @@ impl FunctionLogic for ReadLine {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Sleep(Box<Expression>);
|
pub struct Sleep(Box<Expression>);
|
||||||
|
|
||||||
impl FunctionLogic for Sleep {
|
impl Sleep {
|
||||||
fn arguments(
|
pub fn new(expression: Expression) -> Self {
|
||||||
self,
|
Sleep(Box::new(expression))
|
||||||
) -> (
|
}
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
None::<array::IntoIter<Identifier, 0>>,
|
|
||||||
Some([(Identifier::new("milliseconds"), Type::Integer)].into_iter()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionLogic for Sleep {
|
||||||
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -342,19 +181,13 @@ impl FunctionLogic for Sleep {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct WriteLine(Box<Expression>);
|
pub struct WriteLine(Box<Expression>);
|
||||||
|
|
||||||
impl FunctionLogic for WriteLine {
|
impl WriteLine {
|
||||||
fn arguments(
|
pub fn new(expression: Expression) -> Self {
|
||||||
self,
|
WriteLine(Box::new(expression))
|
||||||
) -> (
|
}
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
None::<array::IntoIter<Identifier, 0>>,
|
|
||||||
Some([(Identifier::new("output"), Type::Any)].into_iter()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionLogic for WriteLine {
|
||||||
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
@ -383,57 +216,71 @@ impl FunctionLogic for WriteLine {
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct JsonParse(TypeConstructor, Box<Expression>);
|
pub struct JsonParse(TypeConstructor, Box<Expression>);
|
||||||
|
|
||||||
impl FunctionLogic for JsonParse {
|
impl JsonParse {
|
||||||
fn arguments(
|
pub fn new(constructor: TypeConstructor, expression: Expression) -> Self {
|
||||||
self,
|
JsonParse(constructor, Box::new(expression))
|
||||||
) -> (
|
}
|
||||||
Option<impl IntoIterator<Item = Identifier>>,
|
|
||||||
Option<impl IntoIterator<Item = (Identifier, Type)>>,
|
|
||||||
) {
|
|
||||||
(
|
|
||||||
Some([Identifier::new("T")].into_iter()),
|
|
||||||
Some([(Identifier::new("input"), Type::Any)].into_iter()),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FunctionLogic for JsonParse {
|
||||||
fn return_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
|
fn return_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
|
||||||
self.0.construct(context).map(|r#type| Some(r#type))
|
self.0.construct(context).map(|r#type| Some(r#type))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(self, context: &Context, _: bool) -> Result<Option<Evaluation>, RuntimeError> {
|
fn call(
|
||||||
let target_type = context.get_type(&Identifier::new("T"))?;
|
self,
|
||||||
let input = context.get_value(&Identifier::new("input"))?;
|
context: &Context,
|
||||||
|
manage_memory: bool,
|
||||||
if let (Some(r#type), Some(value)) = (target_type, input) {
|
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||||
let input_string = if let ValueInner::String(string) = value.inner().as_ref() {
|
let target_type = self.0.construct(context)?;
|
||||||
|
let position = self.1.position();
|
||||||
|
let evaluation = self.1.evaluate(context, manage_memory)?;
|
||||||
|
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||||
|
value
|
||||||
|
} else {
|
||||||
|
return Err(RuntimeError::ValidationFailure(
|
||||||
|
ValidationError::ExpectedExpression(position),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let input = if let ValueInner::String(string) = value.inner().as_ref() {
|
||||||
string
|
string
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::BuiltInFunctionFailure(self.0.position()),
|
ValidationError::ExpectedString {
|
||||||
|
actual: value.r#type(context)?,
|
||||||
|
position,
|
||||||
|
},
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let parsed_value = match r#type {
|
fn parse_value(input: &str, r#type: Type) -> Result<Value, RuntimeError> {
|
||||||
Type::Any => from_str::<Value>(input_string)?,
|
let value = match r#type {
|
||||||
Type::Boolean => Value::boolean(from_str::<bool>(input_string)?),
|
Type::Any => from_str::<Value>(input)?,
|
||||||
|
Type::Boolean => Value::boolean(from_str::<bool>(input)?),
|
||||||
Type::Enum { .. } => todo!(),
|
Type::Enum { .. } => todo!(),
|
||||||
Type::Float => Value::float(from_str::<f64>(input_string)?),
|
Type::Float => Value::float(from_str::<f64>(input)?),
|
||||||
Type::Function { .. } => todo!(),
|
Type::Function { .. } => todo!(),
|
||||||
Type::Generic { .. } => todo!(),
|
Type::Generic { concrete_type, .. } => {
|
||||||
Type::Integer => Value::integer(from_str::<i64>(input_string)?),
|
if let Some(r#type) = concrete_type {
|
||||||
|
parse_value(input, *r#type)?
|
||||||
|
} else {
|
||||||
|
todo!("Create an error for this occurence");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type::Integer => Value::integer(from_str::<i64>(input)?),
|
||||||
Type::List { .. } => todo!(),
|
Type::List { .. } => todo!(),
|
||||||
Type::ListOf(_) => todo!(),
|
Type::ListOf(_) => todo!(),
|
||||||
Type::Map(_) => todo!(),
|
Type::Map(_) => todo!(),
|
||||||
Type::Range => todo!(),
|
Type::Range => todo!(),
|
||||||
Type::String => Value::string(from_str::<String>(input_string)?),
|
Type::String => Value::string(from_str::<String>(input)?),
|
||||||
Type::Structure { .. } => todo!(),
|
Type::Structure { .. } => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Some(Evaluation::Return(parsed_value)));
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(RuntimeError::ValidationFailure(
|
let value = parse_value(&input, target_type)?;
|
||||||
ValidationError::BuiltInFunctionFailure(self.0.position()),
|
|
||||||
))
|
Ok(Some(Evaluation::Return(value)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,32 @@ impl AbstractNode for MapIndex {
|
|||||||
self.index.define_types(_context)
|
self.index.define_types(_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||||
self.collection.validate(_context, _manage_memory)?;
|
self.collection.validate(context, _manage_memory)?;
|
||||||
|
|
||||||
if let Expression::Identifier(identifier) = &self.index {
|
let collection_type = if let Some(r#type) = self.collection.expected_type(context)? {
|
||||||
|
r#type
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::ExpectedExpression(
|
||||||
|
self.collection.position(),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
if let (Type::Map(fields), Expression::Identifier(identifier)) =
|
||||||
|
(collection_type, &self.index)
|
||||||
|
{
|
||||||
|
if !fields.contains_key(&identifier.node) {
|
||||||
|
return Err(ValidationError::FieldNotFound {
|
||||||
|
identifier: identifier.node.clone(),
|
||||||
|
position: identifier.position,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Expression::Identifier(_) = &self.index {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
self.index.validate(_context, _manage_memory)
|
self.index.validate(context, _manage_memory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +109,7 @@ impl AbstractNode for MapIndex {
|
|||||||
return if let Some(value) = map.get(&index.node) {
|
return if let Some(value) = map.get(&index.node) {
|
||||||
Ok(Some(value.r#type(context)?))
|
Ok(Some(value.r#type(context)?))
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::PropertyNotFound {
|
Err(ValidationError::FieldNotFound {
|
||||||
identifier: index.node.clone(),
|
identifier: index.node.clone(),
|
||||||
position: index.position,
|
position: index.position,
|
||||||
})
|
})
|
||||||
|
@ -165,7 +165,7 @@ pub enum ValidationError {
|
|||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: SourcePosition,
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
PropertyNotFound {
|
FieldNotFound {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: SourcePosition,
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
@ -434,7 +434,17 @@ impl InterpreterError {
|
|||||||
ValidationError::ExpectedExpression(_) => todo!(),
|
ValidationError::ExpectedExpression(_) => todo!(),
|
||||||
ValidationError::ExpectedFunction { .. } => todo!(),
|
ValidationError::ExpectedFunction { .. } => todo!(),
|
||||||
ValidationError::ExpectedValue(_) => todo!(),
|
ValidationError::ExpectedValue(_) => todo!(),
|
||||||
ValidationError::PropertyNotFound { .. } => todo!(),
|
ValidationError::FieldNotFound {
|
||||||
|
identifier,
|
||||||
|
position,
|
||||||
|
} => builder.add_label(
|
||||||
|
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
|
||||||
|
format!(
|
||||||
|
"This map has no field named {}.",
|
||||||
|
identifier.fg(identifier_color)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
ValidationError::WrongArguments { .. } => todo!(),
|
ValidationError::WrongArguments { .. } => todo!(),
|
||||||
ValidationError::WrongTypeArgumentCount { .. } => todo!(),
|
ValidationError::WrongTypeArgumentCount { .. } => todo!(),
|
||||||
ValidationError::ExpectedIntegerFloatOrString { actual, position } => {
|
ValidationError::ExpectedIntegerFloatOrString { actual, position } => {
|
||||||
|
@ -13,7 +13,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
built_in_function::BuiltInFunctionCall,
|
built_in_function::{
|
||||||
|
BuiltInFunctionCall, JsonParse, Length, ReadFile, ReadLine, Sleep, WriteLine,
|
||||||
|
},
|
||||||
enum_declaration::EnumVariant,
|
enum_declaration::EnumVariant,
|
||||||
type_constructor::{RawTypeConstructor, TypeInvokationConstructor},
|
type_constructor::{RawTypeConstructor, TypeInvokationConstructor},
|
||||||
};
|
};
|
||||||
@ -385,33 +387,37 @@ pub fn parser<'src>(
|
|||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
.map_with(|argument, state| {
|
.map_with(|argument, state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::length(argument).with_position(state.span()),
|
BuiltInFunctionCall::Length(Length::new(argument))
|
||||||
|
.with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
_built_in_function(Keyword::ReadFile)
|
_built_in_function(Keyword::ReadFile)
|
||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
.map_with(|argument, state| {
|
.map_with(|argument, state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::read_file(argument).with_position(state.span()),
|
BuiltInFunctionCall::ReadFile(ReadFile::new(argument))
|
||||||
|
.with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
_built_in_function(Keyword::ReadLine).map_with(|_, state| {
|
_built_in_function(Keyword::ReadLine).map_with(|_, state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::read_line().with_position(state.span()),
|
BuiltInFunctionCall::ReadLine(ReadLine).with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
_built_in_function(Keyword::Sleep)
|
_built_in_function(Keyword::Sleep)
|
||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
.map_with(|argument, state| {
|
.map_with(|argument, state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::sleep(argument).with_position(state.span()),
|
BuiltInFunctionCall::Sleep(Sleep::new(argument))
|
||||||
|
.with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
_built_in_function(Keyword::WriteLine)
|
_built_in_function(Keyword::WriteLine)
|
||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
.map_with(|argument, state| {
|
.map_with(|argument, state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::write_line(argument).with_position(state.span()),
|
BuiltInFunctionCall::WriteLine(WriteLine::new(argument))
|
||||||
|
.with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
_built_in_function(Keyword::JsonParse)
|
_built_in_function(Keyword::JsonParse)
|
||||||
@ -419,7 +425,7 @@ pub fn parser<'src>(
|
|||||||
.then(expression.clone())
|
.then(expression.clone())
|
||||||
.map_with(|(constructor, argument), state| {
|
.map_with(|(constructor, argument), state| {
|
||||||
Expression::BuiltIn(
|
Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::json_parse(constructor, argument)
|
BuiltInFunctionCall::JsonParse(JsonParse::new(constructor, argument))
|
||||||
.with_position(state.span()),
|
.with_position(state.span()),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
@ -271,7 +271,7 @@ fn built_in_function() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
statements[0],
|
statements[0],
|
||||||
Statement::Expression(Expression::BuiltIn(
|
Statement::Expression(Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::read_line().with_position((0, 13))
|
BuiltInFunctionCall::ReadLine(ReadLine).with_position((0, 13))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -293,9 +293,9 @@ fn built_in_function_with_arg() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
statements[0],
|
statements[0],
|
||||||
Statement::Expression(Expression::BuiltIn(
|
Statement::Expression(Expression::BuiltIn(
|
||||||
BuiltInFunctionCall::write_line(Expression::Value(
|
BuiltInFunctionCall::WriteLine(WriteLine::new(Expression::Value(
|
||||||
ValueNode::String("hiya".to_string()).with_position((15, 21))
|
ValueNode::String("hiya".to_string()).with_position((15, 21))
|
||||||
))
|
)))
|
||||||
.with_position((0, 21))
|
.with_position((0, 21))
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user