Begin refactoring built-ins
This commit is contained in:
parent
6bdefd0698
commit
34cea3518d
@ -70,60 +70,6 @@ impl AbstractNode for Assignment {
|
||||
context.set_type(self.identifier.node.clone(), statement_type.clone())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||
let relevant_statement = self.statement.last_evaluated_statement();
|
||||
let statement_type = if let Some(r#type) = relevant_statement.expected_type(context)? {
|
||||
r#type
|
||||
} else {
|
||||
return Err(ValidationError::CannotAssignToNone(
|
||||
self.statement.position(),
|
||||
));
|
||||
};
|
||||
|
||||
if let Some(constructor) = &self.constructor {
|
||||
let r#type = constructor.clone().construct(&context)?;
|
||||
|
||||
r#type
|
||||
.check(&statement_type)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: self.statement.position(),
|
||||
expected_position: Some(constructor.position()),
|
||||
})?;
|
||||
|
||||
context.set_type(self.identifier.node.clone(), r#type.clone())?;
|
||||
} else {
|
||||
context.set_type(self.identifier.node.clone(), statement_type.clone())?;
|
||||
}
|
||||
|
||||
self.statement.validate(context, manage_memory)?;
|
||||
|
||||
if let (
|
||||
Some(TypeConstructor::Invokation(TypeInvokationConstructor {
|
||||
identifier,
|
||||
type_arguments,
|
||||
})),
|
||||
Statement::Expression(Expression::Value(_)),
|
||||
Type::Enum {
|
||||
type_parameters, ..
|
||||
},
|
||||
) = (&self.constructor, relevant_statement, &statement_type)
|
||||
{
|
||||
if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) {
|
||||
if parameters.len() != arguments.len() {
|
||||
return Err(ValidationError::FullTypeNotKnown {
|
||||
identifier: identifier.node.clone(),
|
||||
position: self.constructor.clone().unwrap().position(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let (Some(constructor), Statement::Expression(Expression::FunctionCall(function_call))) =
|
||||
(&self.constructor, relevant_statement)
|
||||
{
|
||||
@ -161,6 +107,43 @@ impl AbstractNode for Assignment {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> {
|
||||
let relevant_statement = self.statement.last_evaluated_statement();
|
||||
let statement_type = if let Some(r#type) = relevant_statement.expected_type(context)? {
|
||||
r#type
|
||||
} else {
|
||||
return Err(ValidationError::CannotAssignToNone(
|
||||
self.statement.position(),
|
||||
));
|
||||
};
|
||||
|
||||
self.statement.validate(context, manage_memory)?;
|
||||
|
||||
if let (
|
||||
Some(TypeConstructor::Invokation(TypeInvokationConstructor {
|
||||
identifier,
|
||||
type_arguments,
|
||||
})),
|
||||
Type::Enum {
|
||||
type_parameters, ..
|
||||
},
|
||||
) = (&self.constructor, &statement_type)
|
||||
{
|
||||
if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) {
|
||||
if parameters.len() != arguments.len() {
|
||||
return Err(ValidationError::FullTypeNotKnown {
|
||||
identifier: identifier.node.clone(),
|
||||
position: self.constructor.clone().unwrap().position(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &Context,
|
||||
|
118
dust-lang/src/abstract_tree/built_in_function.rs
Normal file
118
dust-lang/src/abstract_tree/built_in_function.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use std::{
|
||||
array,
|
||||
fs::read_to_string,
|
||||
io::{stdin, stdout, Write},
|
||||
slice,
|
||||
sync::OnceLock,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rayon::iter::IntoParallelIterator;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
value::{Function, ValueInner},
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{
|
||||
AbstractNode, Block, Evaluation, Expression, Statement, Type, TypeConstructor, WithPos,
|
||||
};
|
||||
|
||||
pub enum BuiltInExpression {
|
||||
Length(BuiltInFunctionCall<Length>),
|
||||
}
|
||||
|
||||
pub struct BuiltInFunctionCall<F> {
|
||||
function: F,
|
||||
context: Context,
|
||||
}
|
||||
|
||||
pub trait FunctionLogic {
|
||||
fn type_parameters() -> Option<impl IntoIterator<Item = (Identifier, Type)>>;
|
||||
fn value_parameters() -> impl IntoIterator<Item = Identifier>;
|
||||
fn return_type() -> Type;
|
||||
fn call(
|
||||
self,
|
||||
context: &Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Option<Evaluation>, RuntimeError>;
|
||||
}
|
||||
|
||||
impl<F: FunctionLogic> AbstractNode for BuiltInFunctionCall<F> {
|
||||
fn define_types(&self, _: &Context) -> Result<(), ValidationError> {
|
||||
if let Some(type_arguments) = F::type_parameters() {
|
||||
for (identifier, r#type) in type_arguments {
|
||||
self.context.set_type(identifier, r#type)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn evaluate(
|
||||
self,
|
||||
_: &Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||
self.function.call(&self.context, manage_memory)
|
||||
}
|
||||
|
||||
fn expected_type(&self, _: &Context) -> Result<Option<Type>, ValidationError> {
|
||||
Ok(Some(F::return_type()))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Length {
|
||||
argument: Expression,
|
||||
}
|
||||
|
||||
impl FunctionLogic for Length {
|
||||
fn type_parameters() -> Option<impl IntoIterator<Item = (Identifier, Type)>> {
|
||||
None::<array::IntoIter<(Identifier, Type), 0>>
|
||||
}
|
||||
|
||||
fn value_parameters() -> impl IntoIterator<Item = Identifier> {
|
||||
[(Identifier::new("list"))].into_iter()
|
||||
}
|
||||
|
||||
fn return_type() -> Type {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn call(
|
||||
self,
|
||||
context: &Context,
|
||||
manage_memory: bool,
|
||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||
let position = self.argument.position();
|
||||
let evaluation = self.argument.evaluate(context, manage_memory)?;
|
||||
let value = if let Some(Evaluation::Return(value)) = evaluation {
|
||||
value
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedExpression(position),
|
||||
));
|
||||
};
|
||||
let list = if let ValueInner::List(list) = value.inner().as_ref() {
|
||||
list
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedList {
|
||||
actual: value.r#type(context)?,
|
||||
position,
|
||||
},
|
||||
));
|
||||
};
|
||||
|
||||
Ok(Some(Evaluation::Return(Value::integer(list.len() as i64))))
|
||||
}
|
||||
}
|
@ -1,165 +0,0 @@
|
||||
use std::{
|
||||
fs::read_to_string,
|
||||
io::{stdin, stdout, Write},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
value::ValueInner,
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum BuiltInFunctionCall {
|
||||
JsonParse(TypeConstructor, Expression),
|
||||
Length(Expression),
|
||||
ReadFile(Expression),
|
||||
ReadLine,
|
||||
Sleep(Expression),
|
||||
WriteLine(Expression),
|
||||
}
|
||||
impl AbstractNode for BuiltInFunctionCall {
|
||||
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(_, expression) => expression.define_types(_context),
|
||||
BuiltInFunctionCall::Length(expression) => expression.define_types(_context),
|
||||
BuiltInFunctionCall::ReadFile(expression) => expression.define_types(_context),
|
||||
BuiltInFunctionCall::ReadLine => Ok(()),
|
||||
BuiltInFunctionCall::Sleep(expression) => expression.define_types(_context),
|
||||
BuiltInFunctionCall::WriteLine(expression) => expression.define_types(_context),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(_, expression) => {
|
||||
expression.validate(_context, _manage_memory)
|
||||
}
|
||||
BuiltInFunctionCall::Length(expression) => {
|
||||
expression.validate(_context, _manage_memory)
|
||||
}
|
||||
BuiltInFunctionCall::ReadFile(expression) => {
|
||||
expression.validate(_context, _manage_memory)
|
||||
}
|
||||
BuiltInFunctionCall::ReadLine => Ok(()),
|
||||
BuiltInFunctionCall::Sleep(expression) => expression.validate(_context, _manage_memory),
|
||||
BuiltInFunctionCall::WriteLine(expression) => {
|
||||
expression.validate(_context, _manage_memory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate(
|
||||
self,
|
||||
context: &Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Option<Evaluation>, RuntimeError> {
|
||||
fn evaluate_expression(
|
||||
expression: Expression,
|
||||
context: &Context,
|
||||
_manage_memory: bool,
|
||||
) -> Result<Value, RuntimeError> {
|
||||
let position = expression.position();
|
||||
let evaluation = expression.evaluate(context, _manage_memory)?;
|
||||
|
||||
if let Some(Evaluation::Return(value)) = evaluation {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedExpression(position),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(_type, expression) => {
|
||||
let position = expression.position();
|
||||
let value = evaluate_expression(expression, context, _manage_memory)?;
|
||||
|
||||
if let ValueInner::String(string) = value.inner().as_ref() {
|
||||
let deserialized = serde_json::from_str(&string)?;
|
||||
|
||||
Ok(Some(Evaluation::Return(deserialized)))
|
||||
} else {
|
||||
Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedString {
|
||||
actual: value.r#type(context)?,
|
||||
position,
|
||||
},
|
||||
))
|
||||
}
|
||||
}
|
||||
BuiltInFunctionCall::Length(expression) => {
|
||||
let value = evaluate_expression(expression, context, _manage_memory)?;
|
||||
let length = if let ValueInner::List(list) = value.inner().as_ref() {
|
||||
list.len() as i64
|
||||
} else {
|
||||
todo!("Create an error for this occurence.")
|
||||
};
|
||||
|
||||
Ok(Some(Evaluation::Return(Value::integer(length))))
|
||||
}
|
||||
BuiltInFunctionCall::ReadFile(expression) => {
|
||||
let value = evaluate_expression(expression, context, _manage_memory)?;
|
||||
let file_contents = if let ValueInner::String(path) = value.inner().as_ref() {
|
||||
read_to_string(path)?
|
||||
} else {
|
||||
String::with_capacity(0)
|
||||
};
|
||||
|
||||
Ok(Some(Evaluation::Return(Value::string(file_contents))))
|
||||
}
|
||||
BuiltInFunctionCall::ReadLine => {
|
||||
let mut buffer = String::new();
|
||||
|
||||
stdin().read_line(&mut buffer)?;
|
||||
|
||||
Ok(Some(Evaluation::Return(Value::string(
|
||||
buffer.strip_suffix('\n').unwrap_or(&buffer),
|
||||
))))
|
||||
}
|
||||
BuiltInFunctionCall::Sleep(expression) => {
|
||||
let value = evaluate_expression(expression, context, _manage_memory)?;
|
||||
|
||||
if let ValueInner::Integer(milliseconds) = value.inner().as_ref() {
|
||||
thread::sleep(Duration::from_millis(*milliseconds as u64));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
BuiltInFunctionCall::WriteLine(expression) => {
|
||||
let value = evaluate_expression(expression, context, _manage_memory)?;
|
||||
|
||||
if let ValueInner::String(output) = value.inner().as_ref() {
|
||||
let mut stdout = stdout();
|
||||
|
||||
stdout.write_all(output.as_bytes())?;
|
||||
stdout.write(b"\n")?;
|
||||
stdout.flush()?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Context) -> Result<Option<Type>, ValidationError> {
|
||||
match self {
|
||||
BuiltInFunctionCall::JsonParse(r#type, _) => {
|
||||
Ok(Some(r#type.clone().construct(&context)?))
|
||||
}
|
||||
BuiltInFunctionCall::Length(_) => Ok(Some(Type::Integer)),
|
||||
BuiltInFunctionCall::ReadFile(_) => Ok(Some(Type::String)),
|
||||
BuiltInFunctionCall::ReadLine => Ok(Some(Type::String)),
|
||||
BuiltInFunctionCall::Sleep(_) => Ok(None),
|
||||
BuiltInFunctionCall::WriteLine(_) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
identifier::Identifier,
|
||||
value::ValueInner,
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -47,24 +46,7 @@ impl AbstractNode for Expression {
|
||||
Expression::As(inner) => inner.node.define_types(_context),
|
||||
Expression::BuiltInFunctionCall(inner) => inner.node.define_types(_context),
|
||||
Expression::FunctionCall(inner) => inner.node.define_types(_context),
|
||||
Expression::Identifier(identifier) => {
|
||||
let found = _context.get_value(&identifier.node)?;
|
||||
|
||||
if let Some(value) = &found {
|
||||
if let ValueInner::Function(function) = value.inner().as_ref() {
|
||||
function.body().define_types(_context)?;
|
||||
}
|
||||
}
|
||||
|
||||
if found.is_some() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::VariableNotFound {
|
||||
identifier: identifier.node.clone(),
|
||||
position: identifier.position,
|
||||
})
|
||||
}
|
||||
}
|
||||
Expression::Identifier(_) => Ok(()),
|
||||
Expression::MapIndex(inner) => inner.node.define_types(_context),
|
||||
Expression::ListIndex(inner) => inner.node.define_types(_context),
|
||||
Expression::Logic(inner) => inner.node.define_types(_context),
|
||||
@ -83,15 +65,9 @@ impl AbstractNode for Expression {
|
||||
function_call.node.validate(context, manage_memory)
|
||||
}
|
||||
Expression::Identifier(identifier) => {
|
||||
let found = context.get_value(&identifier.node)?;
|
||||
let found = context.add_expected_use(&identifier.node)?;
|
||||
|
||||
if let Some(value) = &found {
|
||||
if let ValueInner::Function(function) = value.inner().as_ref() {
|
||||
function.body().validate(context, manage_memory)?;
|
||||
}
|
||||
}
|
||||
|
||||
if found.is_some() {
|
||||
if found {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::VariableNotFound {
|
||||
|
@ -2,7 +2,7 @@ pub mod r#as;
|
||||
pub mod assignment;
|
||||
pub mod async_block;
|
||||
pub mod block;
|
||||
pub mod built_in_function_call;
|
||||
pub mod built_in_function;
|
||||
pub mod enum_declaration;
|
||||
pub mod expression;
|
||||
pub mod function_call;
|
||||
@ -29,7 +29,7 @@ pub use self::{
|
||||
assignment::{Assignment, AssignmentOperator},
|
||||
async_block::AsyncBlock,
|
||||
block::Block,
|
||||
built_in_function_call::BuiltInFunctionCall,
|
||||
built_in_function::FunctionLogic,
|
||||
enum_declaration::{EnumDeclaration, EnumVariant},
|
||||
expression::Expression,
|
||||
function_call::FunctionCall,
|
||||
|
@ -33,6 +33,7 @@ pub enum ValueNode {
|
||||
},
|
||||
Function(FunctionNode),
|
||||
}
|
||||
|
||||
impl ValueNode {
|
||||
pub fn function(
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
@ -51,28 +52,28 @@ impl ValueNode {
|
||||
}
|
||||
|
||||
impl AbstractNode for ValueNode {
|
||||
fn define_types(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||
fn define_types(&self, outer_context: &Context) -> Result<(), ValidationError> {
|
||||
match self {
|
||||
ValueNode::EnumInstance { content, .. } => {
|
||||
if let Some(expressions) = content {
|
||||
for expression in expressions {
|
||||
expression.define_types(_context)?;
|
||||
expression.define_types(outer_context)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
ValueNode::List(expressions) => {
|
||||
for expression in expressions {
|
||||
expression.define_types(_context)?;
|
||||
expression.define_types(outer_context)?;
|
||||
}
|
||||
}
|
||||
ValueNode::Map(fields) => {
|
||||
for (_, _, expression) in fields {
|
||||
expression.define_types(_context)?;
|
||||
expression.define_types(outer_context)?;
|
||||
}
|
||||
}
|
||||
ValueNode::Structure { fields, .. } => {
|
||||
for (_, expression) in fields {
|
||||
expression.define_types(_context)?;
|
||||
expression.define_types(outer_context)?;
|
||||
}
|
||||
}
|
||||
ValueNode::Function(FunctionNode {
|
||||
@ -95,12 +96,12 @@ impl AbstractNode for ValueNode {
|
||||
}
|
||||
|
||||
for (identifier, type_constructor) in value_parameters {
|
||||
let r#type = type_constructor.clone().construct(&context_template)?;
|
||||
let r#type = type_constructor.clone().construct(outer_context)?;
|
||||
|
||||
context_template.set_type(identifier.clone(), r#type)?;
|
||||
}
|
||||
|
||||
body.node.define_types(_context)?;
|
||||
body.node.define_types(context_template)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -169,7 +170,10 @@ impl AbstractNode for ValueNode {
|
||||
let ((expected_return, expected_position), actual_return) =
|
||||
match (return_type, body.node.expected_type(&context_template)?) {
|
||||
(Some(constructor), Some(r#type)) => (
|
||||
(constructor.construct(context)?, constructor.position()),
|
||||
(
|
||||
constructor.construct(context_template)?,
|
||||
constructor.position(),
|
||||
),
|
||||
r#type,
|
||||
),
|
||||
(None, Some(_)) => return Err(ValidationError::ExpectedValue(body.position)),
|
||||
@ -312,11 +316,10 @@ impl AbstractNode for ValueNode {
|
||||
context_template,
|
||||
}) => {
|
||||
let outer_context = context;
|
||||
let function_context = context_template.create_child();
|
||||
let mut value_parameters = Vec::with_capacity(constructors.len());
|
||||
|
||||
for (identifier, constructor) in constructors {
|
||||
let r#type = constructor.construct(&function_context)?;
|
||||
let r#type = constructor.construct(&outer_context)?;
|
||||
|
||||
value_parameters.push((identifier, r#type));
|
||||
}
|
||||
|
@ -118,6 +118,10 @@ pub enum ValidationError {
|
||||
actual: Type,
|
||||
position: SourcePosition,
|
||||
},
|
||||
ExpectedList {
|
||||
actual: Type,
|
||||
position: SourcePosition,
|
||||
},
|
||||
ExpectedBoolean {
|
||||
actual: Type,
|
||||
position: SourcePosition,
|
||||
|
@ -49,7 +49,6 @@ pub enum Keyword {
|
||||
If,
|
||||
JsonParse,
|
||||
Length,
|
||||
List,
|
||||
Map,
|
||||
None,
|
||||
Range,
|
||||
@ -78,7 +77,6 @@ impl Display for Keyword {
|
||||
Keyword::Fn => write!(f, "fn"),
|
||||
Keyword::Int => write!(f, "int"),
|
||||
Keyword::If => write!(f, "if"),
|
||||
Keyword::List => write!(f, "list"),
|
||||
Keyword::Map => write!(f, "map"),
|
||||
Keyword::None => write!(f, "none"),
|
||||
Keyword::Range => write!(f, "range"),
|
||||
@ -263,7 +261,6 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
just("fn").to(Token::Keyword(Keyword::Fn)),
|
||||
just("int").to(Token::Keyword(Keyword::Int)),
|
||||
just("if").to(Token::Keyword(Keyword::If)),
|
||||
just("list").to(Token::Keyword(Keyword::List)),
|
||||
just("map").to(Token::Keyword(Keyword::Map)),
|
||||
just("none").to(Token::Keyword(Keyword::None)),
|
||||
just("range").to(Token::Keyword(Keyword::Range)),
|
||||
|
@ -721,6 +721,22 @@ pub struct Function {
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
value_parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Option<Type>,
|
||||
body: Block,
|
||||
context_template: Context,
|
||||
) -> Self {
|
||||
Self {
|
||||
type_parameters,
|
||||
value_parameters,
|
||||
return_type,
|
||||
body,
|
||||
context_template,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_template(&self) -> &Context {
|
||||
&self.context_template
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user