Implement formatting
This commit is contained in:
parent
731bf1cb98
commit
8737175df0
@ -1,10 +1,8 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Error, Identifier, Map, Result, Statement, SyntaxNode, SyntaxPosition, Type,
|
||||
TypeDefinition, Value,
|
||||
AbstractTree, AssignmentOperator, Error, Format, Identifier, Map, Result, Statement,
|
||||
SyntaxNode, SyntaxPosition, Type, TypeDefinition, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -34,24 +32,8 @@ impl AbstractTree for Assignment {
|
||||
None
|
||||
};
|
||||
|
||||
let operator_node = syntax_node
|
||||
.child(child_count - 2)
|
||||
.unwrap()
|
||||
.child(0)
|
||||
.unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"=" => AssignmentOperator::Equal,
|
||||
"+=" => AssignmentOperator::PlusEqual,
|
||||
"-=" => AssignmentOperator::MinusEqual,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "=, += or -=".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
let operator_node = syntax_node.child(child_count - 2).unwrap();
|
||||
let operator = AssignmentOperator::from_syntax_node(source, operator_node, context)?;
|
||||
|
||||
let statement_node = syntax_node.child(child_count - 1).unwrap();
|
||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||
@ -159,8 +141,8 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Assignment {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for Assignment {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
let Assignment {
|
||||
identifier,
|
||||
type_definition,
|
||||
@ -169,29 +151,16 @@ impl Display for Assignment {
|
||||
syntax_position: _,
|
||||
} = self;
|
||||
|
||||
write!(f, "{identifier}")?;
|
||||
self.identifier.format(output, indent_level);
|
||||
|
||||
if let Some(type_definition) = type_definition {
|
||||
write!(f, " {type_definition}")?;
|
||||
type_definition.format(output, indent_level);
|
||||
}
|
||||
|
||||
write!(f, " {operator} {statement}")
|
||||
}
|
||||
}
|
||||
output.push_str(" ");
|
||||
self.operator.format(output, indent_level);
|
||||
output.push_str(" ");
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum AssignmentOperator {
|
||||
Equal,
|
||||
PlusEqual,
|
||||
MinusEqual,
|
||||
}
|
||||
|
||||
impl Display for AssignmentOperator {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AssignmentOperator::Equal => write!(f, "="),
|
||||
AssignmentOperator::PlusEqual => write!(f, "-="),
|
||||
AssignmentOperator::MinusEqual => write!(f, "+="),
|
||||
}
|
||||
self.statement.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
55
src/abstract_tree/assignment_operator.rs
Normal file
55
src/abstract_tree/assignment_operator.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum AssignmentOperator {
|
||||
Equal,
|
||||
PlusEqual,
|
||||
MinusEqual,
|
||||
}
|
||||
|
||||
impl AbstractTree for AssignmentOperator {
|
||||
fn from_syntax_node(
|
||||
source: &str,
|
||||
node: tree_sitter::Node,
|
||||
context: &crate::Map,
|
||||
) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "assignment_operator", node)?;
|
||||
|
||||
let operator_node = node.child(0).unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"=" => AssignmentOperator::Equal,
|
||||
"+=" => AssignmentOperator::PlusEqual,
|
||||
"-=" => AssignmentOperator::MinusEqual,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "=, += or -=".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(operator)
|
||||
}
|
||||
|
||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for AssignmentOperator {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
AssignmentOperator::Equal => output.push('='),
|
||||
AssignmentOperator::PlusEqual => output.push_str("+="),
|
||||
AssignmentOperator::MinusEqual => output.push_str("-="),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,10 @@
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
sync::RwLock,
|
||||
};
|
||||
use std::sync::RwLock;
|
||||
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Statement, Type, Value};
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Statement, Type, Value};
|
||||
|
||||
/// Abstract representation of a block.
|
||||
///
|
||||
@ -131,18 +128,22 @@ impl AbstractTree for Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Block {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for Block {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
if self.is_async {
|
||||
writeln!(f, "async {{")?;
|
||||
output.push_str("async {");
|
||||
} else {
|
||||
writeln!(f, "{{")?;
|
||||
output.push('{');
|
||||
}
|
||||
|
||||
for statement in &self.statements {
|
||||
writeln!(f, " {statement}")?;
|
||||
for _ in 0..=indent_level {
|
||||
output.push_str(" ");
|
||||
}
|
||||
|
||||
writeln!(f, "}}")
|
||||
statement.format(output, indent_level);
|
||||
}
|
||||
|
||||
output.push('}');
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,11 @@
|
||||
use std::{
|
||||
env::args,
|
||||
fmt::{self, Display, Formatter},
|
||||
sync::OnceLock,
|
||||
};
|
||||
use std::{env::args, sync::OnceLock};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
built_in_functions::string_functions, AbstractTree, BuiltInFunction, Function, List, Map,
|
||||
Result, Type, Value,
|
||||
built_in_functions::string_functions, AbstractTree, BuiltInFunction, Format, Function, List,
|
||||
Map, Result, Type, Value,
|
||||
};
|
||||
|
||||
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||
@ -31,6 +27,19 @@ pub enum BuiltInValue {
|
||||
}
|
||||
|
||||
impl BuiltInValue {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
BuiltInValue::Args => "args",
|
||||
BuiltInValue::AssertEqual => "assert_equal",
|
||||
BuiltInValue::Fs => "fs",
|
||||
BuiltInValue::Json => "json",
|
||||
BuiltInValue::Length => "length",
|
||||
BuiltInValue::Output => "output",
|
||||
BuiltInValue::Random => "random",
|
||||
BuiltInValue::String => "string",
|
||||
}
|
||||
}
|
||||
|
||||
fn r#type(&self) -> Type {
|
||||
match self {
|
||||
BuiltInValue::Args => Type::list(Type::String),
|
||||
@ -72,7 +81,7 @@ impl BuiltInValue {
|
||||
|
||||
json_context
|
||||
.set(
|
||||
"parse".to_string(),
|
||||
BuiltInFunction::JsonParse.name().to_string(),
|
||||
Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)),
|
||||
None,
|
||||
)
|
||||
@ -153,8 +162,8 @@ impl AbstractTree for BuiltInValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuiltInValue {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.get())
|
||||
impl Format for BuiltInValue {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str(&self.get().to_string());
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, Type, Value, Yield,
|
||||
value_node::ValueNode, AbstractTree, Error, Format, Identifier, Index, Map, Result, Type,
|
||||
Value, Yield,
|
||||
};
|
||||
|
||||
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||
@ -104,16 +103,16 @@ impl AbstractTree for Expression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Expression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for Expression {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
Expression::Value(value_node) => write!(f, "{value_node}"),
|
||||
Expression::Identifier(identifier) => write!(f, "{identifier}"),
|
||||
Expression::Math(math) => write!(f, "{math}"),
|
||||
Expression::Logic(logic) => write!(f, "{logic}"),
|
||||
Expression::FunctionCall(function_call) => write!(f, "{function_call}"),
|
||||
Expression::Index(index) => write!(f, "{index}"),
|
||||
Expression::Yield(r#yield) => write!(f, "{}", r#yield),
|
||||
Expression::Value(value_node) => value_node.format(output, indent_level),
|
||||
Expression::Identifier(identifier) => identifier.format(output, indent_level),
|
||||
Expression::Math(math) => math.format(output, indent_level),
|
||||
Expression::Logic(logic) => logic.format(output, indent_level),
|
||||
Expression::FunctionCall(function_call) => function_call.format(output, indent_level),
|
||||
Expression::Index(index) => index.format(output, indent_level),
|
||||
Expression::Yield(r#yield) => r#yield.format(output, indent_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::Write;
|
||||
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Block, Error, Expression, Format, Identifier, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a for loop statement.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -81,21 +81,18 @@ impl AbstractTree for For {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for For {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let For {
|
||||
is_async,
|
||||
item_id,
|
||||
collection,
|
||||
block,
|
||||
} = self;
|
||||
|
||||
if *is_async {
|
||||
write!(f, "async for ")?;
|
||||
impl Format for For {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
if self.is_async {
|
||||
output.write_str("async for ");
|
||||
} else {
|
||||
write!(f, "for ")?;
|
||||
output.write_str("for ");
|
||||
}
|
||||
|
||||
write!(f, "{item_id} in {collection}, {{{block}}}")
|
||||
self.item_id.format(output, indent_level);
|
||||
output.push_str(" in ");
|
||||
self.collection.format(output, indent_level);
|
||||
output.push_str(" ");
|
||||
self.block.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Error, Expression, FunctionExpression, Map, Result, SyntaxPosition, Type, Value,
|
||||
AbstractTree, Error, Expression, Format, FunctionExpression, Map, Result, SyntaxPosition, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -162,20 +161,15 @@ impl AbstractTree for FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionCall {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let FunctionCall {
|
||||
function_expression,
|
||||
arguments,
|
||||
..
|
||||
} = self;
|
||||
impl Format for FunctionCall {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.function_expression.format(output, indent_level);
|
||||
output.push('(');
|
||||
|
||||
write!(f, "{function_expression}(")?;
|
||||
|
||||
for expression in arguments {
|
||||
write!(f, "{expression}")?;
|
||||
for expression in &self.arguments {
|
||||
expression.format(output, indent_level);
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
output.push(')');
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Error, FunctionCall, Identifier, Index, Map, Result, Type, Value, ValueNode,
|
||||
Yield,
|
||||
AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map, Result, Type, Value,
|
||||
ValueNode, Yield,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -77,14 +75,16 @@ impl AbstractTree for FunctionExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for FunctionExpression {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
FunctionExpression::Value(value_node) => write!(f, "{value_node}"),
|
||||
FunctionExpression::Identifier(identifier) => write!(f, "{identifier}"),
|
||||
FunctionExpression::FunctionCall(function_call) => write!(f, "{function_call}"),
|
||||
FunctionExpression::Index(index) => write!(f, "{index}"),
|
||||
FunctionExpression::Yield(r#yield) => write!(f, "{}", r#yield),
|
||||
FunctionExpression::Value(value_node) => value_node.format(output, indent_level),
|
||||
FunctionExpression::Identifier(identifier) => identifier.format(output, indent_level),
|
||||
FunctionExpression::FunctionCall(function_call) => {
|
||||
function_call.format(output, indent_level)
|
||||
}
|
||||
FunctionExpression::Index(index) => index.format(output, indent_level),
|
||||
FunctionExpression::Yield(r#yield) => r#yield.format(output, indent_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Block, Error, Function, Identifier, Map, Result, SyntaxPosition, Type,
|
||||
AbstractTree, Block, Error, Format, Function, Identifier, Map, Result, SyntaxPosition, Type,
|
||||
TypeDefinition, Value,
|
||||
};
|
||||
|
||||
@ -146,31 +146,39 @@ impl AbstractTree for FunctionNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionNode {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let FunctionNode {
|
||||
parameters,
|
||||
body,
|
||||
r#type,
|
||||
..
|
||||
} = self;
|
||||
|
||||
impl Format for FunctionNode {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
let (parameter_types, return_type) = if let Type::Function {
|
||||
parameter_types,
|
||||
return_type,
|
||||
} = r#type
|
||||
} = &self.r#type
|
||||
{
|
||||
(parameter_types, return_type)
|
||||
} else {
|
||||
return Ok(());
|
||||
return;
|
||||
};
|
||||
|
||||
write!(f, "(")?;
|
||||
output.push('(');
|
||||
|
||||
for (identifier, r#type) in parameters.iter().zip(parameter_types.iter()) {
|
||||
write!(f, "{identifier} <{}>", r#type)?;
|
||||
for (identifier, r#type) in self.parameters.iter().zip(parameter_types.iter()) {
|
||||
identifier.format(output, indent_level);
|
||||
output.push('<');
|
||||
r#type.format(output, indent_level);
|
||||
output.push('>');
|
||||
}
|
||||
|
||||
write!(f, ") <{return_type}> {body}")
|
||||
output.push_str(") <");
|
||||
return_type.format(output, indent_level);
|
||||
output.push_str("> ");
|
||||
self.body.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionNode {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let mut string = String::new();
|
||||
|
||||
self.format(&mut string, 0);
|
||||
f.write_str(&string)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Type, Value};
|
||||
|
||||
/// A string by which a variable is known to a context.
|
||||
///
|
||||
@ -13,8 +13,8 @@ use crate::{AbstractTree, Error, Map, Result, Type, Value};
|
||||
pub struct Identifier(String);
|
||||
|
||||
impl Identifier {
|
||||
pub fn new(inner: String) -> Self {
|
||||
Identifier(inner)
|
||||
pub fn new<T: Into<String>>(inner: T) -> Self {
|
||||
Identifier(inner.into())
|
||||
}
|
||||
|
||||
pub fn take_inner(self) -> String {
|
||||
@ -56,6 +56,12 @@ impl AbstractTree for Identifier {
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for Identifier {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str(&self.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Identifier {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Expression, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Block, Expression, Format, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct IfElse {
|
||||
@ -88,26 +86,28 @@ impl AbstractTree for IfElse {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IfElse {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let IfElse {
|
||||
if_expression,
|
||||
if_block,
|
||||
else_if_expressions,
|
||||
else_if_blocks,
|
||||
else_block,
|
||||
} = self;
|
||||
impl Format for IfElse {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str("if ");
|
||||
self.if_expression.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.if_block.format(output, indent_level);
|
||||
|
||||
write!(f, "if {if_expression} {{{if_block}}}")?;
|
||||
let else_ifs = self
|
||||
.else_if_expressions
|
||||
.iter()
|
||||
.zip(self.else_if_blocks.iter());
|
||||
|
||||
for (expression, block) in else_if_expressions.iter().zip(else_if_blocks.iter()) {
|
||||
write!(f, "else if {expression} {{{block}}}")?;
|
||||
for (expression, block) in else_ifs {
|
||||
output.push_str("else if ");
|
||||
expression.format(output, indent_level);
|
||||
output.push(' ');
|
||||
block.format(output, indent_level);
|
||||
}
|
||||
|
||||
if let Some(block) = else_block {
|
||||
write!(f, "else {{{block}}}")?;
|
||||
if let Some(block) = &self.else_block {
|
||||
output.push_str("else ");
|
||||
block.format(output, indent_level);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, IndexExpression, List, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Error, Format, IndexExpression, List, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of an index expression.
|
||||
///
|
||||
@ -101,20 +99,15 @@ impl AbstractTree for Index {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Index {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let Index {
|
||||
collection,
|
||||
index,
|
||||
index_end,
|
||||
} = self;
|
||||
impl Format for Index {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.collection.format(output, indent_level);
|
||||
output.push(':');
|
||||
self.index.format(output, indent_level);
|
||||
|
||||
write!(f, "{collection}:{index}")?;
|
||||
|
||||
if let Some(expression) = index_end {
|
||||
write!(f, "..{expression}")?;
|
||||
if let Some(expression) = &self.index_end {
|
||||
output.push_str("..");
|
||||
expression.format(output, indent_level);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, AssignmentOperator, Error, Index, IndexExpression, Map, Result, Statement, Type,
|
||||
Value,
|
||||
AbstractTree, AssignmentOperator, Error, Format, Index, IndexExpression, Map, Result,
|
||||
Statement, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -22,20 +20,8 @@ impl AbstractTree for IndexAssignment {
|
||||
let index_node = node.child(0).unwrap();
|
||||
let index = Index::from_syntax_node(source, index_node, context)?;
|
||||
|
||||
let operator_node = node.child(1).unwrap().child(0).unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"=" => AssignmentOperator::Equal,
|
||||
"+=" => AssignmentOperator::PlusEqual,
|
||||
"-=" => AssignmentOperator::MinusEqual,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "=, += or -=".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
let operator_node = node.child(1).unwrap();
|
||||
let operator = AssignmentOperator::from_syntax_node(source, operator_node, context)?;
|
||||
|
||||
let statement_node = node.child(2).unwrap();
|
||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||
@ -94,14 +80,12 @@ impl AbstractTree for IndexAssignment {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IndexAssignment {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let IndexAssignment {
|
||||
index,
|
||||
operator,
|
||||
statement,
|
||||
} = self;
|
||||
|
||||
write!(f, "{index} {operator} {statement}")
|
||||
impl Format for IndexAssignment {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.index.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.operator.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.statement.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
value_node::ValueNode, AbstractTree, Error, FunctionCall, Identifier, Index, Map, Result, Type,
|
||||
Value,
|
||||
value_node::ValueNode, AbstractTree, Error, Format, FunctionCall, Identifier, Index, Map,
|
||||
Result, Type, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -69,13 +67,21 @@ impl AbstractTree for IndexExpression {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for IndexExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for IndexExpression {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
IndexExpression::Value(value_node) => write!(f, "{value_node}"),
|
||||
IndexExpression::Identifier(identifier) => write!(f, "{identifier}"),
|
||||
IndexExpression::FunctionCall(function_call) => write!(f, "{function_call}"),
|
||||
IndexExpression::Index(index) => write!(f, "{index}"),
|
||||
IndexExpression::Value(value_node) => {
|
||||
if let ValueNode::BuiltInValue(built_in_value) = value_node {
|
||||
output.push_str(built_in_value.name());
|
||||
} else {
|
||||
value_node.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
IndexExpression::Identifier(identifier) => identifier.format(output, indent_level),
|
||||
IndexExpression::FunctionCall(function_call) => {
|
||||
function_call.format(output, indent_level)
|
||||
}
|
||||
IndexExpression::Index(index) => index.format(output, indent_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Format, LogicOperator, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a logic expression.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -20,38 +18,17 @@ impl AbstractTree for Logic {
|
||||
let first_node = node.child(0).unwrap();
|
||||
let (left_node, operator_node, right_node) = {
|
||||
if first_node.is_named() {
|
||||
(
|
||||
first_node,
|
||||
node.child(1).unwrap().child(0).unwrap(),
|
||||
node.child(2).unwrap(),
|
||||
)
|
||||
(first_node, node.child(1).unwrap(), node.child(2).unwrap())
|
||||
} else {
|
||||
(
|
||||
node.child(1).unwrap(),
|
||||
node.child(2).unwrap().child(0).unwrap(),
|
||||
node.child(2).unwrap(),
|
||||
node.child(3).unwrap(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let left = Expression::from_syntax_node(source, left_node, context)?;
|
||||
let operator = match operator_node.kind() {
|
||||
"==" => LogicOperator::Equal,
|
||||
"!=" => LogicOperator::NotEqual,
|
||||
"&&" => LogicOperator::And,
|
||||
"||" => LogicOperator::Or,
|
||||
">" => LogicOperator::Greater,
|
||||
"<" => LogicOperator::Less,
|
||||
">=" => LogicOperator::GreaterOrEqual,
|
||||
"<=" => LogicOperator::LessOrEqual,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "==, !=, &&, ||, >, <, >= or <=".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
let operator = LogicOperator::from_syntax_node(source, operator_node, context)?;
|
||||
let right = Expression::from_syntax_node(source, right_node, context)?;
|
||||
|
||||
Ok(Logic {
|
||||
@ -95,41 +72,12 @@ impl AbstractTree for Logic {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Logic {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let Logic {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} = self;
|
||||
|
||||
write!(f, "{left} {operator} {right}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum LogicOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
And,
|
||||
Or,
|
||||
Greater,
|
||||
Less,
|
||||
GreaterOrEqual,
|
||||
LessOrEqual,
|
||||
}
|
||||
|
||||
impl Display for LogicOperator {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LogicOperator::Equal => write!(f, "="),
|
||||
LogicOperator::NotEqual => write!(f, "!="),
|
||||
LogicOperator::And => write!(f, "&&"),
|
||||
LogicOperator::Or => write!(f, "||"),
|
||||
LogicOperator::Greater => write!(f, ">"),
|
||||
LogicOperator::Less => write!(f, "<"),
|
||||
LogicOperator::GreaterOrEqual => write!(f, ">="),
|
||||
LogicOperator::LessOrEqual => write!(f, "<="),
|
||||
}
|
||||
impl Format for Logic {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.left.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.operator.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.right.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
70
src/abstract_tree/logic_operator.rs
Normal file
70
src/abstract_tree/logic_operator.rs
Normal file
@ -0,0 +1,70 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum LogicOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
And,
|
||||
Or,
|
||||
Greater,
|
||||
Less,
|
||||
GreaterOrEqual,
|
||||
LessOrEqual,
|
||||
}
|
||||
|
||||
impl AbstractTree for LogicOperator {
|
||||
fn from_syntax_node(
|
||||
source: &str,
|
||||
node: tree_sitter::Node,
|
||||
_context: &crate::Map,
|
||||
) -> crate::Result<Self> {
|
||||
Error::expect_syntax_node(source, "logic_operator", node)?;
|
||||
|
||||
let operator_node = node.child(0).unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"==" => LogicOperator::Equal,
|
||||
"!=" => LogicOperator::NotEqual,
|
||||
"&&" => LogicOperator::And,
|
||||
"||" => LogicOperator::Or,
|
||||
">" => LogicOperator::Greater,
|
||||
"<" => LogicOperator::Less,
|
||||
">=" => LogicOperator::GreaterOrEqual,
|
||||
"<=" => LogicOperator::LessOrEqual,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "==, !=, &&, ||, >, <, >= or <=".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(operator)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for LogicOperator {
|
||||
fn format(&self, output: &mut String, _indent_level: u8) {
|
||||
match self {
|
||||
LogicOperator::Equal => output.push('='),
|
||||
LogicOperator::NotEqual => output.push_str("!="),
|
||||
LogicOperator::And => output.push_str("&&"),
|
||||
LogicOperator::Or => output.push_str("||"),
|
||||
LogicOperator::Greater => output.push('>'),
|
||||
LogicOperator::Less => output.push('<'),
|
||||
LogicOperator::GreaterOrEqual => output.push_str(">="),
|
||||
LogicOperator::LessOrEqual => output.push_str("<="),
|
||||
}
|
||||
}
|
||||
}
|
@ -2,13 +2,10 @@
|
||||
//!
|
||||
//! Note that this module is called "match" but is escaped as "r#match" because
|
||||
//! "match" is a keyword in Rust.
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Statement, Type, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Format, Map, Result, Statement, Type, Value};
|
||||
|
||||
/// Abstract representation of a match statement.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -85,24 +82,23 @@ impl AbstractTree for Match {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Match {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let Match {
|
||||
matcher,
|
||||
options,
|
||||
fallback,
|
||||
} = self;
|
||||
impl Format for Match {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str("match ");
|
||||
self.matcher.format(output, indent_level);
|
||||
output.push_str(" {");
|
||||
|
||||
write!(f, "match {matcher} {{")?;
|
||||
|
||||
for (expression, statement) in options {
|
||||
write!(f, "{expression} => {statement}")?;
|
||||
for (expression, statement) in &self.options {
|
||||
expression.format(output, indent_level);
|
||||
output.push_str(" => ");
|
||||
statement.format(output, indent_level);
|
||||
}
|
||||
|
||||
if let Some(statement) = fallback {
|
||||
write!(f, "* => {statement}")?;
|
||||
if let Some(statement) = &self.fallback {
|
||||
output.push_str("* => ");
|
||||
statement.format(output, indent_level);
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
output.push('}');
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Error, Expression, Format, Map, MathOperator, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a math operation.
|
||||
///
|
||||
@ -23,22 +21,8 @@ impl AbstractTree for Math {
|
||||
let left_node = node.child(0).unwrap();
|
||||
let left = Expression::from_syntax_node(source, left_node, context)?;
|
||||
|
||||
let operator_node = node.child(1).unwrap().child(0).unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"+" => MathOperator::Add,
|
||||
"-" => MathOperator::Subtract,
|
||||
"*" => MathOperator::Multiply,
|
||||
"/" => MathOperator::Divide,
|
||||
"%" => MathOperator::Modulo,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "+, -, *, / or %".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
let operator_node = node.child(1).unwrap();
|
||||
let operator = MathOperator::from_syntax_node(source, operator_node, context)?;
|
||||
|
||||
let right_node = node.child(2).unwrap();
|
||||
let right = Expression::from_syntax_node(source, right_node, context)?;
|
||||
@ -69,35 +53,12 @@ impl AbstractTree for Math {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Math {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let Math {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} = self;
|
||||
|
||||
write!(f, "{left} {operator} {right}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum MathOperator {
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
}
|
||||
|
||||
impl Display for MathOperator {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
MathOperator::Add => write!(f, "+"),
|
||||
MathOperator::Subtract => write!(f, "-"),
|
||||
MathOperator::Multiply => write!(f, "*"),
|
||||
MathOperator::Divide => write!(f, "/"),
|
||||
MathOperator::Modulo => write!(f, "%"),
|
||||
}
|
||||
impl Format for Math {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.left.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.operator.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.right.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
57
src/abstract_tree/math_operator.rs
Normal file
57
src/abstract_tree/math_operator.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum MathOperator {
|
||||
Add,
|
||||
Subtract,
|
||||
Multiply,
|
||||
Divide,
|
||||
Modulo,
|
||||
}
|
||||
|
||||
impl AbstractTree for MathOperator {
|
||||
fn from_syntax_node(source: &str, node: tree_sitter::Node, context: &Map) -> Result<Self> {
|
||||
let operator_node = node.child(0).unwrap();
|
||||
let operator = match operator_node.kind() {
|
||||
"+" => MathOperator::Add,
|
||||
"-" => MathOperator::Subtract,
|
||||
"*" => MathOperator::Multiply,
|
||||
"/" => MathOperator::Divide,
|
||||
"%" => MathOperator::Modulo,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "+, -, *, / or %".to_string(),
|
||||
actual: operator_node.kind().to_string(),
|
||||
location: operator_node.start_position(),
|
||||
relevant_source: source[operator_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(operator)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for MathOperator {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
let char = match self {
|
||||
MathOperator::Add => '+',
|
||||
MathOperator::Subtract => '-',
|
||||
MathOperator::Multiply => '*',
|
||||
MathOperator::Divide => '/',
|
||||
MathOperator::Modulo => '%',
|
||||
};
|
||||
|
||||
output.push(char);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@
|
||||
//! examples.
|
||||
|
||||
pub mod assignment;
|
||||
pub mod assignment_operator;
|
||||
pub mod block;
|
||||
pub mod built_in_value;
|
||||
pub mod expression;
|
||||
@ -20,23 +21,25 @@ pub mod index;
|
||||
pub mod index_assignment;
|
||||
pub mod index_expression;
|
||||
pub mod logic;
|
||||
pub mod logic_operator;
|
||||
pub mod r#match;
|
||||
pub mod math;
|
||||
pub mod math_operator;
|
||||
pub mod statement;
|
||||
pub mod r#type;
|
||||
pub mod type_definition;
|
||||
pub mod value_node;
|
||||
pub mod r#while;
|
||||
pub mod r#yield;
|
||||
|
||||
pub use {
|
||||
assignment::*, block::*, built_in_value::*, expression::*, function_call::*,
|
||||
function_expression::*, function_node::*, identifier::*, if_else::*, index::*,
|
||||
index_assignment::IndexAssignment, index_expression::*, logic::*, math::*, r#for::*,
|
||||
r#match::*, r#while::*, r#yield::*, statement::*, type_definition::*, value_node::*,
|
||||
assignment::*, assignment_operator::*, block::*, built_in_value::*, expression::*,
|
||||
function_call::*, function_expression::*, function_node::*, identifier::*, if_else::*,
|
||||
index::*, index_assignment::IndexAssignment, index_expression::*, logic::*, logic_operator::*,
|
||||
math::*, math_operator::*, r#for::*, r#match::*, r#type::*, r#while::*, r#yield::*,
|
||||
statement::*, type_definition::*, value_node::*,
|
||||
};
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
@ -118,19 +121,17 @@ impl AbstractTree for Root {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Root {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
impl Format for Root {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
for statement in &self.statements {
|
||||
write!(f, "{statement}")?;
|
||||
statement.format(output, indent_level);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait is implemented by the Evaluator's internal types to form an
|
||||
/// executable tree that resolves to a single value.
|
||||
pub trait AbstractTree: Sized {
|
||||
pub trait AbstractTree: Sized + Format {
|
||||
/// Interpret the syntax tree at the given node and return the abstraction.
|
||||
///
|
||||
/// This function is used to convert nodes in the Tree Sitter concrete
|
||||
@ -152,3 +153,7 @@ pub trait AbstractTree: Sized {
|
||||
|
||||
fn expected_type(&self, context: &Map) -> Result<Type>;
|
||||
}
|
||||
|
||||
pub trait Format {
|
||||
fn format(&self, output: &mut String, indent_level: u8);
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match,
|
||||
Result, Type, Value, While,
|
||||
AbstractTree, Assignment, Block, Error, Expression, For, Format, IfElse, IndexAssignment, Map,
|
||||
Match, Result, Type, Value, While,
|
||||
};
|
||||
|
||||
/// Abstract representation of a statement.
|
||||
@ -113,18 +111,20 @@ impl AbstractTree for Statement {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Statement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for Statement {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
Statement::Assignment(assignment) => write!(f, "{assignment}"),
|
||||
Statement::Expression(expression) => write!(f, "{expression}"),
|
||||
Statement::IfElse(if_else) => write!(f, "{if_else}"),
|
||||
Statement::Match(r#match) => write!(f, "{}", r#match),
|
||||
Statement::While(r#while) => write!(f, "{}", r#while),
|
||||
Statement::Block(block) => write!(f, "{block}"),
|
||||
Statement::For(r#for) => write!(f, "{}", r#for),
|
||||
Statement::IndexAssignment(index_assignment) => write!(f, "{index_assignment}"),
|
||||
Statement::Return(statement) => write!(f, "{statement}"),
|
||||
Statement::Assignment(assignment) => assignment.format(output, indent_level),
|
||||
Statement::Expression(expression) => expression.format(output, indent_level),
|
||||
Statement::IfElse(if_else) => if_else.format(output, indent_level),
|
||||
Statement::Match(r#match) => r#match.format(output, indent_level),
|
||||
Statement::While(r#while) => r#while.format(output, indent_level),
|
||||
Statement::Block(block) => block.format(output, indent_level),
|
||||
Statement::For(r#for) => r#for.format(output, indent_level),
|
||||
Statement::IndexAssignment(index_assignment) => {
|
||||
index_assignment.format(output, indent_level)
|
||||
}
|
||||
Statement::Return(statement) => statement.format(output, indent_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
290
src/abstract_tree/type.rs
Normal file
290
src/abstract_tree/type.rs
Normal file
@ -0,0 +1,290 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Structure, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Collection,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<Type>,
|
||||
return_type: Box<Type>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
Map(Option<Structure>),
|
||||
None,
|
||||
Number,
|
||||
String,
|
||||
Option(Box<Type>),
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn list(item_type: Type) -> Self {
|
||||
Type::List(Box::new(item_type))
|
||||
}
|
||||
|
||||
pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option(optional_type: Type) -> Self {
|
||||
Type::Option(Box::new(optional_type))
|
||||
}
|
||||
|
||||
pub fn check(&self, other: &Type) -> Result<()> {
|
||||
match (self, other) {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Collection, Type::Collection)
|
||||
| (Type::Collection, Type::List(_))
|
||||
| (Type::List(_), Type::Collection)
|
||||
| (Type::Collection, Type::Map(_))
|
||||
| (Type::Map(_), Type::Collection)
|
||||
| (Type::Collection, Type::String)
|
||||
| (Type::String, Type::Collection)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::Map(_), Type::Map(_))
|
||||
| (Type::Number, Type::Number)
|
||||
| (Type::Number, Type::Integer)
|
||||
| (Type::Number, Type::Float)
|
||||
| (Type::Integer, Type::Number)
|
||||
| (Type::Float, Type::Number)
|
||||
| (Type::None, Type::None)
|
||||
| (Type::String, Type::String) => Ok(()),
|
||||
(Type::Option(left), Type::Option(right)) => {
|
||||
if left == right {
|
||||
Ok(())
|
||||
} else if let Type::Any = left.as_ref() {
|
||||
Ok(())
|
||||
} else if let Type::Any = right.as_ref() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
(Type::Option(_), Type::None) | (Type::None, Type::Option(_)) => Ok(()),
|
||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||
if self_item_type.check(other_item_type).is_err() {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
(
|
||||
Type::Function {
|
||||
parameter_types: self_parameter_types,
|
||||
return_type: self_return_type,
|
||||
},
|
||||
Type::Function {
|
||||
parameter_types: other_parameter_types,
|
||||
return_type: other_return_type,
|
||||
},
|
||||
) => {
|
||||
let parameter_type_pairs = self_parameter_types
|
||||
.iter()
|
||||
.zip(other_parameter_types.iter());
|
||||
|
||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||
if self_parameter_type.check(other_parameter_type).is_err() {
|
||||
return Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if self_return_type.check(other_return_type).is_err() {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
_ => Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Type {
|
||||
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
||||
Error::expect_syntax_node(_source, "type", node)?;
|
||||
|
||||
let type_node = node.child(0).unwrap();
|
||||
|
||||
let r#type = match type_node.kind() {
|
||||
"[" => {
|
||||
let item_type_node = node.child(1).unwrap();
|
||||
let item_type = Type::from_syntax_node(_source, item_type_node, _context)?;
|
||||
|
||||
Type::List(Box::new(item_type))
|
||||
}
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"collection" => Type::Collection,
|
||||
"float" => Type::Float,
|
||||
"(" => {
|
||||
let child_count = node.child_count();
|
||||
let mut parameter_types = Vec::new();
|
||||
|
||||
for index in 1..child_count - 2 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.is_named() {
|
||||
let parameter_type = Type::from_syntax_node(_source, child, _context)?;
|
||||
|
||||
parameter_types.push(parameter_type);
|
||||
}
|
||||
}
|
||||
|
||||
let final_node = node.child(child_count - 1).unwrap();
|
||||
let return_type = if final_node.is_named() {
|
||||
Type::from_syntax_node(_source, final_node, _context)?
|
||||
} else {
|
||||
Type::None
|
||||
};
|
||||
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
"int" => Type::Integer,
|
||||
"map" => Type::Map(None),
|
||||
"num" => Type::Number,
|
||||
"none" => Type::None,
|
||||
"str" => Type::String,
|
||||
"option" => {
|
||||
let inner_type_node = node.child(2).unwrap();
|
||||
let inner_type = Type::from_syntax_node(_source, inner_type_node, _context)?;
|
||||
|
||||
Type::Option(Box::new(inner_type))
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, int, num, str, option, (, [ or {".to_string(),
|
||||
actual: type_node.kind().to_string(),
|
||||
location: type_node.start_position(),
|
||||
relevant_source: _source[type_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for Type {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
Type::Any => output.push_str("any"),
|
||||
Type::Boolean => output.push_str("bool"),
|
||||
Type::Collection => output.push_str("collection"),
|
||||
Type::Float => output.push_str("float"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type,
|
||||
} => {
|
||||
output.push('(');
|
||||
|
||||
for (index, parameter_type) in parameter_types.iter().enumerate() {
|
||||
parameter_type.format(output, indent_level);
|
||||
|
||||
if index != parameter_types.len() - 1 {
|
||||
output.push(' ');
|
||||
}
|
||||
}
|
||||
|
||||
output.push_str(") -> ");
|
||||
return_type.format(output, indent_level);
|
||||
}
|
||||
Type::Integer => output.push_str("int"),
|
||||
Type::List(item_type) => {
|
||||
output.push('[');
|
||||
item_type.format(output, indent_level);
|
||||
output.push(']');
|
||||
}
|
||||
Type::Map(structure_option) => {
|
||||
if let Some(structure) = structure_option {
|
||||
output.push_str(&structure.to_string());
|
||||
} else {
|
||||
output.push_str("map");
|
||||
}
|
||||
}
|
||||
Type::None => output.push_str("none"),
|
||||
Type::Number => output.push_str("number"),
|
||||
Type::String => output.push_str("str"),
|
||||
Type::Option(optional_type) => {
|
||||
output.push_str("option(");
|
||||
optional_type.format(output, indent_level);
|
||||
output.push(')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Collection => write!(f, "collection"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type,
|
||||
} => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (index, parameter_type) in parameter_types.iter().enumerate() {
|
||||
write!(f, "{parameter_type}")?;
|
||||
|
||||
if index != parameter_types.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, ")")?;
|
||||
write!(f, " -> {return_type}")
|
||||
}
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::Map(_) => write!(f, "map"),
|
||||
Type::Number => write!(f, "num"),
|
||||
Type::None => write!(f, "none"),
|
||||
Type::String => write!(f, "str"),
|
||||
Type::Option(inner_type) => {
|
||||
write!(f, "option({})", inner_type)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Error, Map, Result, Structure, Value};
|
||||
use crate::{AbstractTree, Error, Format, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct TypeDefinition {
|
||||
@ -43,243 +41,10 @@ impl AbstractTree for TypeDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for TypeDefinition {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "<{}>", self.r#type)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Collection,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<Type>,
|
||||
return_type: Box<Type>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
Map(Option<Structure>),
|
||||
None,
|
||||
Number,
|
||||
String,
|
||||
Option(Box<Type>),
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn list(item_type: Type) -> Self {
|
||||
Type::List(Box::new(item_type))
|
||||
}
|
||||
|
||||
pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option(optional_type: Type) -> Self {
|
||||
Type::Option(Box::new(optional_type))
|
||||
}
|
||||
|
||||
pub fn check(&self, other: &Type) -> Result<()> {
|
||||
match (self, other) {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Collection, Type::Collection)
|
||||
| (Type::Collection, Type::List(_))
|
||||
| (Type::List(_), Type::Collection)
|
||||
| (Type::Collection, Type::Map(_))
|
||||
| (Type::Map(_), Type::Collection)
|
||||
| (Type::Collection, Type::String)
|
||||
| (Type::String, Type::Collection)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::Map(_), Type::Map(_))
|
||||
| (Type::Number, Type::Number)
|
||||
| (Type::Number, Type::Integer)
|
||||
| (Type::Number, Type::Float)
|
||||
| (Type::Integer, Type::Number)
|
||||
| (Type::Float, Type::Number)
|
||||
| (Type::None, Type::None)
|
||||
| (Type::String, Type::String) => Ok(()),
|
||||
(Type::Option(left), Type::Option(right)) => {
|
||||
if left == right {
|
||||
Ok(())
|
||||
} else if let Type::Any = left.as_ref() {
|
||||
Ok(())
|
||||
} else if let Type::Any = right.as_ref() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
(Type::Option(_), Type::None) | (Type::None, Type::Option(_)) => Ok(()),
|
||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||
if self_item_type.check(other_item_type).is_err() {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
(
|
||||
Type::Function {
|
||||
parameter_types: self_parameter_types,
|
||||
return_type: self_return_type,
|
||||
},
|
||||
Type::Function {
|
||||
parameter_types: other_parameter_types,
|
||||
return_type: other_return_type,
|
||||
},
|
||||
) => {
|
||||
let parameter_type_pairs = self_parameter_types
|
||||
.iter()
|
||||
.zip(other_parameter_types.iter());
|
||||
|
||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||
if self_parameter_type.check(other_parameter_type).is_err() {
|
||||
return Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if self_return_type.check(other_return_type).is_err() {
|
||||
Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
_ => Err(Error::TypeCheck {
|
||||
expected: self.clone(),
|
||||
actual: other.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Type {
|
||||
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
||||
Error::expect_syntax_node(_source, "type", node)?;
|
||||
|
||||
let type_node = node.child(0).unwrap();
|
||||
|
||||
let r#type = match type_node.kind() {
|
||||
"[" => {
|
||||
let item_type_node = node.child(1).unwrap();
|
||||
let item_type = Type::from_syntax_node(_source, item_type_node, _context)?;
|
||||
|
||||
Type::List(Box::new(item_type))
|
||||
}
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
"collection" => Type::Collection,
|
||||
"float" => Type::Float,
|
||||
"(" => {
|
||||
let child_count = node.child_count();
|
||||
let mut parameter_types = Vec::new();
|
||||
|
||||
for index in 1..child_count - 2 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.is_named() {
|
||||
let parameter_type = Type::from_syntax_node(_source, child, _context)?;
|
||||
|
||||
parameter_types.push(parameter_type);
|
||||
}
|
||||
}
|
||||
|
||||
let final_node = node.child(child_count - 1).unwrap();
|
||||
let return_type = if final_node.is_named() {
|
||||
Type::from_syntax_node(_source, final_node, _context)?
|
||||
} else {
|
||||
Type::None
|
||||
};
|
||||
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
"int" => Type::Integer,
|
||||
"map" => Type::Map(None),
|
||||
"num" => Type::Number,
|
||||
"none" => Type::None,
|
||||
"str" => Type::String,
|
||||
"option" => {
|
||||
let inner_type_node = node.child(2).unwrap();
|
||||
let inner_type = Type::from_syntax_node(_source, inner_type_node, _context)?;
|
||||
|
||||
Type::Option(Box::new(inner_type))
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected: "any, bool, float, int, num, str, option, (, [ or {".to_string(),
|
||||
actual: type_node.kind().to_string(),
|
||||
location: type_node.start_position(),
|
||||
relevant_source: _source[type_node.byte_range()].to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
Ok(r#type)
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
Ok(Type::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Collection => write!(f, "collection"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function {
|
||||
parameter_types,
|
||||
return_type,
|
||||
} => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (index, parameter_type) in parameter_types.iter().enumerate() {
|
||||
write!(f, "{parameter_type}")?;
|
||||
|
||||
if index != parameter_types.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, ")")?;
|
||||
write!(f, " -> {return_type}")
|
||||
}
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::Map(_) => write!(f, "map"),
|
||||
Type::Number => write!(f, "num"),
|
||||
Type::None => write!(f, "none"),
|
||||
Type::String => write!(f, "str"),
|
||||
Type::Option(inner_type) => {
|
||||
write!(f, "option({})", inner_type)
|
||||
}
|
||||
}
|
||||
impl Format for TypeDefinition {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push('<');
|
||||
self.r#type.format(output, indent_level);
|
||||
output.push('>');
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
};
|
||||
use std::{collections::BTreeMap, fmt::Write};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, BuiltInValue, Error, Expression, Function, Identifier, List, Map, Result,
|
||||
Statement, Structure, Type, TypeDefinition, Value,
|
||||
AbstractTree, BuiltInValue, Error, Expression, Format, Function, FunctionNode, Identifier,
|
||||
List, Map, Result, Statement, Structure, Type, TypeDefinition, Value,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -33,7 +30,11 @@ impl AbstractTree for ValueNode {
|
||||
let value_node = match child.kind() {
|
||||
"boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()),
|
||||
"float" => ValueNode::Float(source[child.byte_range()].to_string()),
|
||||
"function" => ValueNode::Function(Function::from_syntax_node(source, child, context)?),
|
||||
"function" => {
|
||||
let function_node = FunctionNode::from_syntax_node(source, child, context)?;
|
||||
|
||||
ValueNode::Function(Function::ContextDefined(function_node))
|
||||
}
|
||||
"integer" => ValueNode::Integer(source[child.byte_range()].to_string()),
|
||||
"string" => {
|
||||
let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
|
||||
@ -300,53 +301,75 @@ impl AbstractTree for ValueNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ValueNode {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
impl Format for ValueNode {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
ValueNode::Boolean(source)
|
||||
| ValueNode::Float(source)
|
||||
| ValueNode::Integer(source)
|
||||
| ValueNode::String(source) => write!(f, "{source}"),
|
||||
ValueNode::Function(function) => write!(f, "{function}"),
|
||||
| ValueNode::String(source) => output.push_str(source),
|
||||
ValueNode::Function(function) => function.format(output, indent_level),
|
||||
ValueNode::List(expressions) => {
|
||||
output.push('[');
|
||||
|
||||
for expression in expressions {
|
||||
write!(f, "{expression}")?;
|
||||
expression.format(output, indent_level);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
output.push(']');
|
||||
}
|
||||
ValueNode::Option(option) => {
|
||||
if let Some(expression) = option {
|
||||
write!(f, "some({})", expression)
|
||||
output.push_str("some(");
|
||||
expression.format(output, indent_level);
|
||||
output.push(')');
|
||||
} else {
|
||||
write!(f, "none")
|
||||
output.push_str("none");
|
||||
}
|
||||
}
|
||||
ValueNode::Map(nodes) => {
|
||||
writeln!(f, "{{")?;
|
||||
output.push('{');
|
||||
|
||||
for (key, (statement, type_option)) in nodes {
|
||||
if let Some(r#type) = type_option {
|
||||
writeln!(f, " {key} <{}> = {statement}", r#type)?;
|
||||
output.push_str(" ");
|
||||
output.push_str(key);
|
||||
output.push_str(" <");
|
||||
r#type.format(output, indent_level);
|
||||
output.push_str("> = ");
|
||||
statement.format(output, indent_level);
|
||||
} else {
|
||||
writeln!(f, " {key} = {statement}")?;
|
||||
output.push_str(" ");
|
||||
output.push_str(key);
|
||||
output.push_str(" = ");
|
||||
statement.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
write!(f, "}}")
|
||||
|
||||
output.push('}');
|
||||
}
|
||||
ValueNode::BuiltInValue(built_in_value) => write!(f, "{built_in_value}"),
|
||||
ValueNode::BuiltInValue(built_in_value) => built_in_value.format(output, indent_level),
|
||||
ValueNode::Structure(nodes) => {
|
||||
writeln!(f, "{{")?;
|
||||
output.push('{');
|
||||
|
||||
for (key, (value_option, r#type)) in nodes {
|
||||
if let Some(value) = value_option {
|
||||
writeln!(f, " {key} <{}> = {value}", r#type)?;
|
||||
output.push_str(" ");
|
||||
output.push_str(key);
|
||||
output.push_str(" <");
|
||||
r#type.format(output, indent_level);
|
||||
output.push_str("> = ");
|
||||
value.format(output, indent_level);
|
||||
} else {
|
||||
writeln!(f, " {key} <{}>", r#type)?;
|
||||
output.push_str(" ");
|
||||
output.push_str(key);
|
||||
output.push_str(" <");
|
||||
r#type.format(output, indent_level);
|
||||
output.push('>');
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
output.push('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, Block, Error, Expression, Map, Result, Type, Value};
|
||||
use crate::{AbstractTree, Block, Error, Expression, Format, Map, Result, Type, Value};
|
||||
|
||||
/// Abstract representation of a while loop.
|
||||
///
|
||||
@ -40,10 +38,11 @@ impl AbstractTree for While {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for While {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let While { expression, block } = self;
|
||||
|
||||
write!(f, "while {expression} {{{block}}}")
|
||||
impl Format for While {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str("while ");
|
||||
self.expression.format(output, indent_level);
|
||||
output.push(' ');
|
||||
self.expression.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
function_expression::FunctionExpression, AbstractTree, Error, Expression, FunctionCall, Map,
|
||||
Result, Type, Value,
|
||||
function_expression::FunctionExpression, AbstractTree, Error, Expression, Format, FunctionCall,
|
||||
Map, Result, Type, Value,
|
||||
};
|
||||
|
||||
/// Abstract representation of a yield expression.
|
||||
@ -55,8 +53,8 @@ impl AbstractTree for Yield {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Yield {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.call)
|
||||
impl Format for Yield {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
self.call.format(output, indent_level);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
mod string;
|
||||
|
||||
use std::fs::read_to_string;
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
fs::read_to_string,
|
||||
};
|
||||
|
||||
use rand::{random, thread_rng, Rng};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Error, Map, Result, Type, Value};
|
||||
use crate::{Error, Format, Map, Result, Type, Value};
|
||||
|
||||
pub use string::{string_functions, StringFunction};
|
||||
|
||||
@ -148,3 +151,15 @@ impl BuiltInFunction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Format for BuiltInFunction {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
output.push_str(self.name());
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuiltInFunction {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name())
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
//! functions or by constructing your own Evaluator.
|
||||
use tree_sitter::{Node, Parser, Tree as TSTree, TreeCursor};
|
||||
|
||||
use crate::{language, AbstractTree, Error, Map, Result, Root, Value};
|
||||
use crate::{language, AbstractTree, Error, Format, Map, Result, Root, Value};
|
||||
|
||||
/// Interpret the given source code.
|
||||
///
|
||||
@ -132,7 +132,11 @@ impl Interpreter {
|
||||
|
||||
pub fn format(&self) -> String {
|
||||
if let Some(root_node) = &self.abstract_tree {
|
||||
root_node.to_string()
|
||||
let mut formatted_source = String::new();
|
||||
|
||||
root_node.format(&mut formatted_source, 0);
|
||||
|
||||
formatted_source
|
||||
} else {
|
||||
"".to_string()
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{AbstractTree, BuiltInFunction, FunctionNode, Map, Result, Type, Value};
|
||||
use crate::{BuiltInFunction, Format, FunctionNode, Map, Result, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Function {
|
||||
@ -11,17 +10,6 @@ pub enum Function {
|
||||
ContextDefined(FunctionNode),
|
||||
}
|
||||
|
||||
impl Display for Function {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Function::BuiltIn(built_in_function) => write!(f, "{}", built_in_function.r#type()),
|
||||
Function::ContextDefined(function_node) => {
|
||||
write!(f, "{}", function_node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn call(
|
||||
&self,
|
||||
@ -50,30 +38,20 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for Function {
|
||||
fn from_syntax_node(_source: &str, _node: Node, _context: &Map) -> Result<Self> {
|
||||
let inner_function = FunctionNode::from_syntax_node(_source, _node, _context)?;
|
||||
|
||||
Ok(Function::ContextDefined(inner_function))
|
||||
}
|
||||
|
||||
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||
impl Format for Function {
|
||||
fn format(&self, output: &mut String, indent_level: u8) {
|
||||
match self {
|
||||
Function::BuiltIn(_) => Ok(()),
|
||||
Function::ContextDefined(defined_function) => {
|
||||
defined_function.check_type(_source, _context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
||||
Ok(Value::Function(self.clone()))
|
||||
}
|
||||
|
||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||
match self {
|
||||
Function::BuiltIn(built_in) => Ok(built_in.r#type()),
|
||||
Function::ContextDefined(context_defined) => Ok(context_defined.r#type().clone()),
|
||||
Function::BuiltIn(built_in_function) => built_in_function.format(output, indent_level),
|
||||
Function::ContextDefined(function_node) => function_node.format(output, indent_level),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Function {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Function::BuiltIn(built_in_function) => write!(f, "{built_in_function}"),
|
||||
Function::ContextDefined(function_node) => write!(f, "{function_node}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ impl Serialize for Value {
|
||||
impl Display for Value {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Value::String(string) => write!(f, "{}", string.read().unwrap()),
|
||||
Value::String(string) => write!(f, "'{}'", string.read().unwrap()),
|
||||
Value::Float(float) => write!(f, "{float}"),
|
||||
Value::Integer(int) => write!(f, "{int}"),
|
||||
Value::Boolean(boolean) => write!(f, "{boolean}"),
|
||||
|
Loading…
Reference in New Issue
Block a user