1
0

Begin refactoring built-ins

This commit is contained in:
Jeff 2024-06-22 17:17:35 -04:00
parent 6bdefd0698
commit 34cea3518d
9 changed files with 193 additions and 261 deletions

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -118,6 +118,10 @@ pub enum ValidationError {
actual: Type,
position: SourcePosition,
},
ExpectedList {
actual: Type,
position: SourcePosition,
},
ExpectedBoolean {
actual: Type,
position: SourcePosition,

View File

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

View File

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