1
0

Simplify built-in functions

This commit is contained in:
Jeff 2024-06-24 05:26:49 -04:00
parent c75dedb117
commit f106d64367
6 changed files with 141 additions and 259 deletions

View File

@ -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)))
} }
} }

View File

@ -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,
}) })

View File

@ -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,
}, },

View File

@ -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 } => {

View File

@ -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()),
) )
}), }),

View File

@ -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))
)) ))
); );