Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
2023e2c7e3 | |||
6b88fbf8b9 | |||
cc76ca89cc |
@ -9,7 +9,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct FunctionNode {
|
pub struct AnonymousFunction {
|
||||||
parameters: Vec<Identifier>,
|
parameters: Vec<Identifier>,
|
||||||
body: Block,
|
body: Block,
|
||||||
r#type: Type,
|
r#type: Type,
|
||||||
@ -19,7 +19,7 @@ pub struct FunctionNode {
|
|||||||
context: Context,
|
context: Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionNode {
|
impl AnonymousFunction {
|
||||||
pub fn parameters(&self) -> &Vec<Identifier> {
|
pub fn parameters(&self) -> &Vec<Identifier> {
|
||||||
&self.parameters
|
&self.parameters
|
||||||
}
|
}
|
||||||
@ -51,9 +51,9 @@ impl FunctionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionNode {
|
impl AbstractTree for AnonymousFunction {
|
||||||
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
|
fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result<Self, SyntaxError> {
|
||||||
SyntaxError::expect_syntax_node("function", node)?;
|
SyntaxError::expect_syntax_node("anonymous_function", node)?;
|
||||||
|
|
||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
let mut parameters = Vec::new();
|
let mut parameters = Vec::new();
|
||||||
@ -86,7 +86,7 @@ impl AbstractTree for FunctionNode {
|
|||||||
let r#type = Type::function(parameter_types, return_type.take_inner());
|
let r#type = Type::function(parameter_types, return_type.take_inner());
|
||||||
let syntax_position = node.range().into();
|
let syntax_position = node.range().into();
|
||||||
|
|
||||||
Ok(FunctionNode {
|
Ok(AnonymousFunction {
|
||||||
parameters,
|
parameters,
|
||||||
body,
|
body,
|
||||||
r#type,
|
r#type,
|
||||||
@ -141,7 +141,7 @@ impl AbstractTree for FunctionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Format for FunctionNode {
|
impl Format for AnonymousFunction {
|
||||||
fn format(&self, output: &mut String, indent_level: u8) {
|
fn format(&self, output: &mut String, indent_level: u8) {
|
||||||
let (parameter_types, return_type) = if let Type::Function {
|
let (parameter_types, return_type) = if let Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
@ -169,7 +169,7 @@ impl Format for FunctionNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for FunctionNode {
|
impl Display for AnonymousFunction {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
let mut string = String::new();
|
let mut string = String::new();
|
||||||
|
|
@ -90,8 +90,9 @@ impl AbstractTree for As {
|
|||||||
Value::List(list) => Value::List(list),
|
Value::List(list) => Value::List(list),
|
||||||
Value::String(string) => {
|
Value::String(string) => {
|
||||||
let chars = string
|
let chars = string
|
||||||
|
.read()?
|
||||||
.chars()
|
.chars()
|
||||||
.map(|char| Value::String(char.to_string()))
|
.map(|char| Value::string(char))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Value::List(List::with_items(chars))
|
Value::List(List::with_items(chars))
|
||||||
|
@ -65,7 +65,7 @@ impl AbstractTree for Command {
|
|||||||
.wait_with_output()?
|
.wait_with_output()?
|
||||||
.stdout;
|
.stdout;
|
||||||
|
|
||||||
Ok(Value::String(String::from_utf8(output)?))
|
Ok(Value::string(String::from_utf8(output)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let index_value = self.index.run(source, context)?;
|
let index_value = self.index.run(source, context)?;
|
||||||
let identifier = Identifier::new(index_value.as_string()?);
|
let identifier = Identifier::new(index_value.as_string()?.as_str());
|
||||||
|
|
||||||
if let Some(value) = map.get(&identifier) {
|
if let Some(value) = map.get(&identifier) {
|
||||||
value
|
value
|
||||||
@ -114,7 +114,7 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
Value::String(string) => {
|
Value::String(string) => {
|
||||||
let index = self.index.run(source, context)?.as_integer()? as usize;
|
let index = self.index.run(source, context)?.as_integer()? as usize;
|
||||||
let item = string.chars().nth(index).unwrap_or_default();
|
let item = string.read()?.chars().nth(index).unwrap_or_default();
|
||||||
|
|
||||||
Ok(Value::string(item.to_string()))
|
Ok(Value::string(item.to_string()))
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
identifier
|
identifier
|
||||||
} else {
|
} else {
|
||||||
let index_run = self.index.index.run(source, context)?;
|
let index_run = self.index.index.run(source, context)?;
|
||||||
let expected_identifier = Identifier::new(index_run.as_string()?);
|
let expected_identifier = Identifier::new(index_run.as_string()?.as_str());
|
||||||
|
|
||||||
return Err(RuntimeError::ValidationFailure(
|
return Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::VariableIdentifierNotFound(expected_identifier),
|
ValidationError::VariableIdentifierNotFound(expected_identifier),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! Abstract, executable representations of corresponding items found in Dust
|
//! Abstract, executable representations of corresponding items found in Dust
|
||||||
//! source code. The types that implement [AbstractTree] are inteded to be
|
//! source code. The types that implement [AbstractTree] are inteded to be
|
||||||
//! created by an [Interpreter].
|
//! created by an [Interpreter].
|
||||||
|
pub mod anonymous_function;
|
||||||
pub mod r#as;
|
pub mod r#as;
|
||||||
pub mod assignment;
|
pub mod assignment;
|
||||||
pub mod assignment_operator;
|
pub mod assignment_operator;
|
||||||
@ -12,7 +13,6 @@ pub mod expression;
|
|||||||
pub mod r#for;
|
pub mod r#for;
|
||||||
pub mod function_call;
|
pub mod function_call;
|
||||||
pub mod function_expression;
|
pub mod function_expression;
|
||||||
pub mod function_node;
|
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod if_else;
|
pub mod if_else;
|
||||||
pub mod index;
|
pub mod index;
|
||||||
@ -34,8 +34,8 @@ pub mod value_node;
|
|||||||
pub mod r#while;
|
pub mod r#while;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
assignment::*, assignment_operator::*, block::*, command::*, enum_defintion::*,
|
anonymous_function::*, assignment::*, assignment_operator::*, block::*, command::*,
|
||||||
enum_pattern::*, expression::*, function_call::*, function_expression::*, function_node::*,
|
enum_defintion::*, enum_pattern::*, expression::*, function_call::*, function_expression::*,
|
||||||
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
|
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
|
||||||
logic::*, logic_operator::*, map_node::*, match_pattern::*, math::*, math_operator::*, r#as::*,
|
logic::*, logic_operator::*, map_node::*, match_pattern::*, math::*, math_operator::*, r#as::*,
|
||||||
r#for::*, r#match::*, r#type::*, r#while::*, statement::*, struct_definition::*,
|
r#for::*, r#match::*, r#type::*, r#while::*, statement::*, struct_definition::*,
|
||||||
|
@ -5,7 +5,7 @@ use tree_sitter::Node as SyntaxNode;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RuntimeError, SyntaxError, ValidationError},
|
error::{RuntimeError, SyntaxError, ValidationError},
|
||||||
AbstractTree, Context, Expression, Format, Function, FunctionNode,
|
AbstractTree, Context, Expression, Format, Function, AnonymousFunction,
|
||||||
Identifier, List, Type, Value, TypeDefinition, MapNode,
|
Identifier, List, Type, Value, TypeDefinition, MapNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ impl AbstractTree for ValueNode {
|
|||||||
let value_node = match child.kind() {
|
let value_node = match child.kind() {
|
||||||
"boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()),
|
"boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()),
|
||||||
"float" => ValueNode::Float(source[child.byte_range()].to_string()),
|
"float" => ValueNode::Float(source[child.byte_range()].to_string()),
|
||||||
"function" => {
|
"anonymous_function" => {
|
||||||
let function_node = FunctionNode::from_syntax(child, source, context)?;
|
let function_node = AnonymousFunction::from_syntax(child, source, context)?;
|
||||||
|
|
||||||
ValueNode::Function(Function::ContextDefined(function_node))
|
ValueNode::Function(Function::ContextDefined(function_node))
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use crate::{error::RuntimeError, Context, Type, Value};
|
|||||||
|
|
||||||
use super::Callable;
|
use super::Callable;
|
||||||
|
|
||||||
pub fn fs_functions() -> impl Iterator<Item = Fs> {
|
pub fn all_fs_functions() -> impl Iterator<Item = Fs> {
|
||||||
all()
|
all()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ impl Callable for Fs {
|
|||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
|
||||||
let path = arguments.first().unwrap().as_string()?;
|
let path = arguments.first().unwrap().as_string()?;
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path.as_str())?;
|
||||||
let file_size = file.metadata()?.len() as usize;
|
let file_size = file.metadata()?.len() as usize;
|
||||||
let mut file_content = String::with_capacity(file_size);
|
let mut file_content = String::with_capacity(file_size);
|
||||||
|
|
||||||
|
56
src/built_in_functions/io.rs
Normal file
56
src/built_in_functions/io.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use enum_iterator::{all, Sequence};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{error::RuntimeError, Context, Type, Value};
|
||||||
|
|
||||||
|
use super::Callable;
|
||||||
|
|
||||||
|
pub fn all_io_functions() -> impl Iterator<Item = Io> {
|
||||||
|
all()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Sequence, Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub enum Io {
|
||||||
|
Stdin,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Callable for Io {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Io::Stdin => "stdin",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Io::Stdin => "Read input from stdin.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#type(&self) -> crate::Type {
|
||||||
|
match self {
|
||||||
|
Io::Stdin => Type::Function {
|
||||||
|
parameter_types: vec![],
|
||||||
|
return_type: Box::new(Type::String),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(
|
||||||
|
&self,
|
||||||
|
_arguments: &[Value],
|
||||||
|
_source: &str,
|
||||||
|
_context: &Context,
|
||||||
|
) -> Result<Value, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Io::Stdin => {
|
||||||
|
let mut input = String::new();
|
||||||
|
let stdin = std::io::stdin();
|
||||||
|
|
||||||
|
stdin.read_line(&mut input)?;
|
||||||
|
|
||||||
|
Ok(Value::string(input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -54,7 +54,7 @@ impl Callable for Json {
|
|||||||
let value = arguments.first().unwrap();
|
let value = arguments.first().unwrap();
|
||||||
let json_string = serde_json::to_string(value)?;
|
let json_string = serde_json::to_string(value)?;
|
||||||
|
|
||||||
Ok(Value::String(json_string))
|
Ok(Value::string(json_string))
|
||||||
}
|
}
|
||||||
Json::CreatePretty => {
|
Json::CreatePretty => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
@ -62,13 +62,13 @@ impl Callable for Json {
|
|||||||
let value = arguments.first().unwrap();
|
let value = arguments.first().unwrap();
|
||||||
let json_string = serde_json::to_string_pretty(value)?;
|
let json_string = serde_json::to_string_pretty(value)?;
|
||||||
|
|
||||||
Ok(Value::String(json_string))
|
Ok(Value::string(json_string))
|
||||||
}
|
}
|
||||||
Json::Parse => {
|
Json::Parse => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
|
||||||
let json_string = arguments.first().unwrap().as_string()?;
|
let json_string = arguments.first().unwrap().as_string()?;
|
||||||
let value = serde_json::from_str(json_string)?;
|
let value = serde_json::from_str(json_string.as_str())?;
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod fs;
|
pub mod fs;
|
||||||
|
pub mod io;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ use crate::{
|
|||||||
Context, EnumInstance, Format, Identifier, Type, Value,
|
Context, EnumInstance, Format, Identifier, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{fs::Fs, json::Json, str::StrFunction};
|
use self::{fs::Fs, io::Io, json::Json, str::StrFunction};
|
||||||
|
|
||||||
pub trait Callable {
|
pub trait Callable {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
@ -30,6 +31,7 @@ pub trait Callable {
|
|||||||
pub enum BuiltInFunction {
|
pub enum BuiltInFunction {
|
||||||
AssertEqual,
|
AssertEqual,
|
||||||
Fs(Fs),
|
Fs(Fs),
|
||||||
|
Io(Io),
|
||||||
Json(Json),
|
Json(Json),
|
||||||
Length,
|
Length,
|
||||||
Output,
|
Output,
|
||||||
@ -45,6 +47,7 @@ impl Callable for BuiltInFunction {
|
|||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => "assert_equal",
|
BuiltInFunction::AssertEqual => "assert_equal",
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.name(),
|
BuiltInFunction::Fs(fs_function) => fs_function.name(),
|
||||||
|
BuiltInFunction::Io(io_function) => io_function.name(),
|
||||||
BuiltInFunction::Json(json_function) => json_function.name(),
|
BuiltInFunction::Json(json_function) => json_function.name(),
|
||||||
BuiltInFunction::Length => "length",
|
BuiltInFunction::Length => "length",
|
||||||
BuiltInFunction::Output => "output",
|
BuiltInFunction::Output => "output",
|
||||||
@ -60,6 +63,7 @@ impl Callable for BuiltInFunction {
|
|||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => "assert_equal",
|
BuiltInFunction::AssertEqual => "assert_equal",
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.description(),
|
BuiltInFunction::Fs(fs_function) => fs_function.description(),
|
||||||
|
BuiltInFunction::Io(io_function) => io_function.description(),
|
||||||
BuiltInFunction::Json(json_function) => json_function.description(),
|
BuiltInFunction::Json(json_function) => json_function.description(),
|
||||||
BuiltInFunction::Length => "length",
|
BuiltInFunction::Length => "length",
|
||||||
BuiltInFunction::Output => "output",
|
BuiltInFunction::Output => "output",
|
||||||
@ -75,6 +79,7 @@ impl Callable for BuiltInFunction {
|
|||||||
match self {
|
match self {
|
||||||
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
|
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
||||||
|
BuiltInFunction::Io(io_function) => io_function.r#type(),
|
||||||
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
||||||
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
||||||
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
||||||
@ -113,6 +118,7 @@ impl Callable for BuiltInFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context),
|
BuiltInFunction::Fs(fs_function) => fs_function.call(arguments, _source, context),
|
||||||
|
BuiltInFunction::Io(io_function) => io_function.call(arguments, _source, context),
|
||||||
BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context),
|
BuiltInFunction::Json(json_function) => json_function.call(arguments, _source, context),
|
||||||
BuiltInFunction::Length => {
|
BuiltInFunction::Length => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
|
@ -221,19 +221,17 @@ impl Callable for StrFunction {
|
|||||||
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
||||||
|
|
||||||
let string = arguments.first().unwrap().as_string()?;
|
let string = arguments.first().unwrap().as_string()?;
|
||||||
let pattern_string = arguments.get(1).unwrap().as_string()?;
|
let pattern = arguments.get(1).unwrap().as_string()?;
|
||||||
let pattern = pattern_string.as_str();
|
|
||||||
|
|
||||||
Value::Boolean(string.ends_with(pattern))
|
Value::Boolean(string.ends_with(pattern.as_str()))
|
||||||
}
|
}
|
||||||
StrFunction::Find => {
|
StrFunction::Find => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
||||||
|
|
||||||
let string = arguments.first().unwrap().as_string()?;
|
let string = arguments.first().unwrap().as_string()?;
|
||||||
let pattern_string = arguments.get(1).unwrap().as_string()?;
|
let pattern = arguments.get(1).unwrap().as_string()?;
|
||||||
let pattern = pattern_string.as_str();
|
|
||||||
let find = string
|
let find = string
|
||||||
.find(pattern)
|
.find(pattern.as_str())
|
||||||
.map(|index| Value::Integer(index as i64));
|
.map(|index| Value::Integer(index as i64));
|
||||||
|
|
||||||
if let Some(index) = find {
|
if let Some(index) = find {
|
||||||
@ -271,9 +269,9 @@ impl Callable for StrFunction {
|
|||||||
let index = arguments.get(1).unwrap().as_integer()? as usize;
|
let index = arguments.get(1).unwrap().as_integer()? as usize;
|
||||||
let insertion = arguments.get(2).unwrap().as_string()?;
|
let insertion = arguments.get(2).unwrap().as_string()?;
|
||||||
|
|
||||||
string.insert_str(index, insertion);
|
string.insert_str(index, insertion.as_str());
|
||||||
|
|
||||||
Value::String(string)
|
Value::none()
|
||||||
}
|
}
|
||||||
StrFunction::Lines => {
|
StrFunction::Lines => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 1, arguments.len())?;
|
||||||
@ -339,9 +337,9 @@ impl Callable for StrFunction {
|
|||||||
let end = range[1].as_integer()? as usize;
|
let end = range[1].as_integer()? as usize;
|
||||||
let pattern = arguments.get(2).unwrap().as_string()?;
|
let pattern = arguments.get(2).unwrap().as_string()?;
|
||||||
|
|
||||||
string.replace_range(start..end, pattern);
|
string.replace_range(start..end, pattern.as_str());
|
||||||
|
|
||||||
Value::String(string)
|
Value::string(string)
|
||||||
}
|
}
|
||||||
StrFunction::Retain => {
|
StrFunction::Retain => {
|
||||||
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 2, arguments.len())?;
|
||||||
@ -576,13 +574,9 @@ impl Callable for StrFunction {
|
|||||||
let input_string = arguments.first().unwrap().as_string()?;
|
let input_string = arguments.first().unwrap().as_string()?;
|
||||||
let new_length = arguments.get(1).unwrap().as_integer()? as usize;
|
let new_length = arguments.get(1).unwrap().as_integer()? as usize;
|
||||||
|
|
||||||
let new_string = input_string
|
let new_string = input_string.chars().take(new_length).collect::<String>();
|
||||||
.chars()
|
|
||||||
.take(new_length)
|
|
||||||
.map(|char| char.to_string())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Value::String(new_string)
|
Value::string(new_string)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,12 +4,16 @@ use enum_iterator::{all, Sequence};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_functions::{fs::fs_functions, json::json_functions, str::string_functions, Callable},
|
built_in_functions::{
|
||||||
|
fs::all_fs_functions, io::all_io_functions, json::json_functions, str::string_functions,
|
||||||
|
Callable,
|
||||||
|
},
|
||||||
BuiltInFunction, EnumInstance, Function, Identifier, List, Map, Value,
|
BuiltInFunction, EnumInstance, Function, Identifier, List, Map, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ARGS: OnceLock<Value> = OnceLock::new();
|
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||||
static FS: OnceLock<Value> = OnceLock::new();
|
static FS: OnceLock<Value> = OnceLock::new();
|
||||||
|
static IO: OnceLock<Value> = OnceLock::new();
|
||||||
static JSON: OnceLock<Value> = OnceLock::new();
|
static JSON: OnceLock<Value> = OnceLock::new();
|
||||||
static NONE: OnceLock<Value> = OnceLock::new();
|
static NONE: OnceLock<Value> = OnceLock::new();
|
||||||
static RANDOM: OnceLock<Value> = OnceLock::new();
|
static RANDOM: OnceLock<Value> = OnceLock::new();
|
||||||
@ -32,6 +36,9 @@ pub enum BuiltInValue {
|
|||||||
/// File system tools.
|
/// File system tools.
|
||||||
Fs,
|
Fs,
|
||||||
|
|
||||||
|
/// Input and output tools.
|
||||||
|
Io,
|
||||||
|
|
||||||
/// JSON format tools.
|
/// JSON format tools.
|
||||||
Json,
|
Json,
|
||||||
|
|
||||||
@ -58,6 +65,7 @@ impl BuiltInValue {
|
|||||||
BuiltInValue::Args => "args",
|
BuiltInValue::Args => "args",
|
||||||
BuiltInValue::AssertEqual => "assert_equal",
|
BuiltInValue::AssertEqual => "assert_equal",
|
||||||
BuiltInValue::Fs => "fs",
|
BuiltInValue::Fs => "fs",
|
||||||
|
BuiltInValue::Io => "io",
|
||||||
BuiltInValue::Json => "json",
|
BuiltInValue::Json => "json",
|
||||||
BuiltInValue::Length => BuiltInFunction::Length.name(),
|
BuiltInValue::Length => BuiltInFunction::Length.name(),
|
||||||
BuiltInValue::None => "None",
|
BuiltInValue::None => "None",
|
||||||
@ -75,6 +83,7 @@ impl BuiltInValue {
|
|||||||
BuiltInValue::Args => "The command line arguments sent to this program.",
|
BuiltInValue::Args => "The command line arguments sent to this program.",
|
||||||
BuiltInValue::AssertEqual => "Error if the two values are not equal.",
|
BuiltInValue::AssertEqual => "Error if the two values are not equal.",
|
||||||
BuiltInValue::Fs => "File and directory tools.",
|
BuiltInValue::Fs => "File and directory tools.",
|
||||||
|
BuiltInValue::Io => "Input/output tools.",
|
||||||
BuiltInValue::Json => "JSON formatting tools.",
|
BuiltInValue::Json => "JSON formatting tools.",
|
||||||
BuiltInValue::Length => BuiltInFunction::Length.description(),
|
BuiltInValue::Length => BuiltInFunction::Length.description(),
|
||||||
BuiltInValue::None => "The absence of a value.",
|
BuiltInValue::None => "The absence of a value.",
|
||||||
@ -98,11 +107,26 @@ impl BuiltInValue {
|
|||||||
BuiltInValue::AssertEqual => {
|
BuiltInValue::AssertEqual => {
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||||
}
|
}
|
||||||
|
BuiltInValue::Io => IO
|
||||||
|
.get_or_init(|| {
|
||||||
|
let mut io_map = Map::new();
|
||||||
|
|
||||||
|
for io_function in all_io_functions() {
|
||||||
|
let key = io_function.name();
|
||||||
|
let value =
|
||||||
|
Value::Function(Function::BuiltIn(BuiltInFunction::Io(io_function)));
|
||||||
|
|
||||||
|
io_map.set(Identifier::new(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Map(io_map)
|
||||||
|
})
|
||||||
|
.clone(),
|
||||||
BuiltInValue::Fs => FS
|
BuiltInValue::Fs => FS
|
||||||
.get_or_init(|| {
|
.get_or_init(|| {
|
||||||
let mut fs_map = Map::new();
|
let mut fs_map = Map::new();
|
||||||
|
|
||||||
for fs_function in fs_functions() {
|
for fs_function in all_fs_functions() {
|
||||||
let key = fs_function.name();
|
let key = fs_function.name();
|
||||||
let value =
|
let value =
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
Value::Function(Function::BuiltIn(BuiltInFunction::Fs(fs_function)));
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::{
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
|
sync::PoisonError,
|
||||||
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use lyneate::Report;
|
use lyneate::Report;
|
||||||
@ -261,6 +264,12 @@ impl ValidationError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<PoisonError<T>> for ValidationError {
|
||||||
|
fn from(_: PoisonError<T>) -> Self {
|
||||||
|
ValidationError::RwLock(RwLockError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<RwLockError> for ValidationError {
|
impl From<RwLockError> for ValidationError {
|
||||||
fn from(_error: RwLockError) -> Self {
|
fn from(_error: RwLockError) -> Self {
|
||||||
ValidationError::RwLock(RwLockError)
|
ValidationError::RwLock(RwLockError)
|
||||||
|
@ -3,13 +3,13 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
built_in_functions::Callable, BuiltInFunction, Format, FunctionNode, Identifier, Type,
|
built_in_functions::Callable, AnonymousFunction, BuiltInFunction, Format, Identifier, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Function {
|
pub enum Function {
|
||||||
BuiltIn(BuiltInFunction),
|
BuiltIn(BuiltInFunction),
|
||||||
ContextDefined(FunctionNode),
|
ContextDefined(AnonymousFunction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
|
@ -18,6 +18,7 @@ use std::{
|
|||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::RangeInclusive,
|
ops::RangeInclusive,
|
||||||
|
sync::{Arc, RwLock, RwLockReadGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
@ -36,7 +37,7 @@ pub mod struct_instance;
|
|||||||
/// Every dust variable has a key and a Value. Variables are represented by
|
/// Every dust variable has a key and a Value. Variables are represented by
|
||||||
/// storing them in a VariableMap. This means the map of variables is itself a
|
/// storing them in a VariableMap. This means the map of variables is itself a
|
||||||
/// value that can be treated as any other.
|
/// value that can be treated as any other.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Enum(EnumInstance),
|
Enum(EnumInstance),
|
||||||
@ -46,7 +47,7 @@ pub enum Value {
|
|||||||
List(List),
|
List(List),
|
||||||
Map(Map),
|
Map(Map),
|
||||||
Range(RangeInclusive<i64>),
|
Range(RangeInclusive<i64>),
|
||||||
String(String),
|
String(Arc<RwLock<String>>),
|
||||||
Struct(StructInstance),
|
Struct(StructInstance),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn string<T: Into<String>>(string: T) -> Self {
|
pub fn string<T: Into<String>>(string: T) -> Self {
|
||||||
Value::String(string.into())
|
Value::String(Arc::new(RwLock::new(string.into())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn range(start: i64, end: i64) -> Self {
|
pub fn range(start: i64, end: i64) -> Self {
|
||||||
@ -157,11 +158,11 @@ impl Value {
|
|||||||
self == &Value::none()
|
self == &Value::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the value stored in `self` as `&String`, or returns `Err` if
|
/// Borrows the value stored in `self` as `&str`, or returns `Err` if
|
||||||
/// `self` is not a `Value::String`.
|
/// `self` is not a `Value::String`.
|
||||||
pub fn as_string(&self) -> Result<&String, ValidationError> {
|
pub fn as_string(&self) -> Result<RwLockReadGuard<String>, ValidationError> {
|
||||||
match self {
|
match self {
|
||||||
Value::String(string) => Ok(string),
|
Value::String(string) => Ok(string.read()?),
|
||||||
value => Err(ValidationError::ExpectedString {
|
value => Err(ValidationError::ExpectedString {
|
||||||
actual: value.clone(),
|
actual: value.clone(),
|
||||||
}),
|
}),
|
||||||
@ -274,7 +275,12 @@ impl Value {
|
|||||||
|
|
||||||
Ok(Value::List(list))
|
Ok(Value::List(list))
|
||||||
}
|
}
|
||||||
(Value::String(left), Value::String(right)) => Ok(Value::String(left + &right)),
|
(Value::String(left), Value::String(right)) => {
|
||||||
|
let left = left.read()?.to_string();
|
||||||
|
let right = right.read()?;
|
||||||
|
|
||||||
|
Ok(Value::string(left + right.as_str()))
|
||||||
|
}
|
||||||
(left, right) => Err(ValidationError::CannotAdd {
|
(left, right) => Err(ValidationError::CannotAdd {
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
@ -360,7 +366,13 @@ impl PartialEq for Value {
|
|||||||
(Value::Integer(left), Value::Integer(right)) => left == right,
|
(Value::Integer(left), Value::Integer(right)) => left == right,
|
||||||
(Value::Float(left), Value::Float(right)) => left == right,
|
(Value::Float(left), Value::Float(right)) => left == right,
|
||||||
(Value::Boolean(left), Value::Boolean(right)) => left == right,
|
(Value::Boolean(left), Value::Boolean(right)) => left == right,
|
||||||
(Value::String(left), Value::String(right)) => left == right,
|
(Value::String(left), Value::String(right)) => {
|
||||||
|
if let (Ok(left), Ok(right)) = (left.read(), right.read()) {
|
||||||
|
left.as_str() == right.as_str()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
(Value::List(left), Value::List(right)) => left == right,
|
(Value::List(left), Value::List(right)) => left == right,
|
||||||
(Value::Map(left), Value::Map(right)) => left == right,
|
(Value::Map(left), Value::Map(right)) => left == right,
|
||||||
(Value::Function(left), Value::Function(right)) => left == right,
|
(Value::Function(left), Value::Function(right)) => left == right,
|
||||||
@ -381,7 +393,13 @@ impl PartialOrd for Value {
|
|||||||
impl Ord for Value {
|
impl Ord for Value {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::String(left), Value::String(right)) => left.cmp(right),
|
(Value::String(left), Value::String(right)) => {
|
||||||
|
if let (Ok(left), Ok(right)) = (left.read(), right.read()) {
|
||||||
|
left.cmp(&right)
|
||||||
|
} else {
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
}
|
||||||
(Value::String(_), _) => Ordering::Greater,
|
(Value::String(_), _) => Ordering::Greater,
|
||||||
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
|
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
|
||||||
(Value::Integer(left), Value::Integer(right)) => left.cmp(right),
|
(Value::Integer(left), Value::Integer(right)) => left.cmp(right),
|
||||||
@ -424,7 +442,13 @@ impl Serialize for Value {
|
|||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Value::String(inner) => serializer.serialize_str(inner),
|
Value::String(inner) => {
|
||||||
|
let inner = inner
|
||||||
|
.read()
|
||||||
|
.map_err(|_| serde::ser::Error::custom("failed to get read lock on string"))?;
|
||||||
|
|
||||||
|
serializer.serialize_str(inner.as_str())
|
||||||
|
}
|
||||||
Value::Float(inner) => serializer.serialize_f64(*inner),
|
Value::Float(inner) => serializer.serialize_f64(*inner),
|
||||||
Value::Integer(inner) => serializer.serialize_i64(*inner),
|
Value::Integer(inner) => serializer.serialize_i64(*inner),
|
||||||
Value::Boolean(inner) => serializer.serialize_bool(*inner),
|
Value::Boolean(inner) => serializer.serialize_bool(*inner),
|
||||||
@ -461,10 +485,33 @@ impl Serialize for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for Value {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
log::trace!("Cloning value {self}");
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Value::Boolean(boolean) => Value::Boolean(*boolean),
|
||||||
|
Value::Enum(r#enum) => Value::Enum(r#enum.clone()),
|
||||||
|
Value::Float(float) => Value::Float(*float),
|
||||||
|
Value::Function(function) => Value::Function(function.clone()),
|
||||||
|
Value::Integer(integer) => Value::Integer(*integer),
|
||||||
|
Value::List(list) => Value::List(list.clone()),
|
||||||
|
Value::Map(map) => Value::Map(map.clone()),
|
||||||
|
Value::Range(range) => Value::Range(range.clone()),
|
||||||
|
Value::String(string) => Value::String(string.clone()),
|
||||||
|
Value::Struct(r#struct) => Value::Struct(r#struct.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Value {
|
impl Display for Value {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Value::String(string) => write!(f, "{string}"),
|
Value::String(string) => {
|
||||||
|
let string = string.read().map_err(|_| fmt::Error)?;
|
||||||
|
|
||||||
|
write!(f, "{}", string.as_str())
|
||||||
|
}
|
||||||
Value::Float(float) => write!(f, "{float}"),
|
Value::Float(float) => write!(f, "{float}"),
|
||||||
Value::Integer(int) => write!(f, "{int}"),
|
Value::Integer(int) => write!(f, "{int}"),
|
||||||
Value::Boolean(boolean) => write!(f, "{boolean}"),
|
Value::Boolean(boolean) => write!(f, "{boolean}"),
|
||||||
@ -531,7 +578,7 @@ impl TryFrom<Value> for String {
|
|||||||
|
|
||||||
fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
|
fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
|
||||||
if let Value::String(string) = value {
|
if let Value::String(string) = value {
|
||||||
Ok(string)
|
Ok(string.read()?.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::ExpectedString { actual: value },
|
ValidationError::ExpectedString { actual: value },
|
||||||
|
12
tests/as.rs
12
tests/as.rs
@ -8,12 +8,12 @@ fn string_as_string_list() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("'foobar' as [str]"),
|
interpret("'foobar' as [str]"),
|
||||||
Ok(Value::List(List::with_items(vec![
|
Ok(Value::List(List::with_items(vec![
|
||||||
Value::String("f".to_string()),
|
Value::string("f"),
|
||||||
Value::String("o".to_string()),
|
Value::string("o"),
|
||||||
Value::String("o".to_string()),
|
Value::string("o"),
|
||||||
Value::String("b".to_string()),
|
Value::string("b"),
|
||||||
Value::String("a".to_string()),
|
Value::string("a"),
|
||||||
Value::String("r".to_string()),
|
Value::string("r"),
|
||||||
])))
|
])))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,10 @@ fn find() {
|
|||||||
fn insert() {
|
fn insert() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("str:insert('ac', 1, 'b')"),
|
interpret("str:insert('ac', 1, 'b')"),
|
||||||
Ok(Value::String("abc".to_string()))
|
Ok(Value::string("abc"))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("str:insert('foo', 3, 'bar')"),
|
interpret("str:insert('foo', 3, 'bar')"),
|
||||||
Ok(Value::String("foobar".to_string()))
|
Ok(Value::string("foobar"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ fn override_built_ins() {
|
|||||||
Ok(Value::Enum(EnumInstance::new(
|
Ok(Value::Enum(EnumInstance::new(
|
||||||
Identifier::new("Option"),
|
Identifier::new("Option"),
|
||||||
Identifier::new("Some"),
|
Identifier::new("Some"),
|
||||||
Some(Value::String("foo".to_string())),
|
Some(Value::string("foo")),
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ fn result() {
|
|||||||
Ok(Value::Enum(EnumInstance::new(
|
Ok(Value::Enum(EnumInstance::new(
|
||||||
Identifier::new("Result"),
|
Identifier::new("Result"),
|
||||||
Identifier::new("Error"),
|
Identifier::new("Error"),
|
||||||
Some(Value::String("uh-oh!".to_string())),
|
Some(Value::string("uh-oh!")),
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use dust_lang::{interpret, Value};
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_command() {
|
fn simple_command() {
|
||||||
assert_eq!(interpret("^echo hi"), Ok(Value::String("hi\n".to_string())))
|
assert_eq!(interpret("^echo hi"), Ok(Value::string("hi\n")))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -18,7 +18,7 @@ fn simple_struct() {
|
|||||||
let mut map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set(Identifier::new("bar"), Value::Integer(0));
|
map.set(Identifier::new("bar"), Value::Integer(0));
|
||||||
map.set(Identifier::new("baz"), Value::String("hiya".to_string()));
|
map.set(Identifier::new("baz"), Value::string("hiya"));
|
||||||
|
|
||||||
let expected = Ok(Value::Struct(StructInstance::new(
|
let expected = Ok(Value::Struct(StructInstance::new(
|
||||||
Identifier::new("Foo"),
|
Identifier::new("Foo"),
|
||||||
|
@ -43,6 +43,9 @@ Block with Return
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))))
|
(integer)))))
|
||||||
|
(statement
|
||||||
|
(statement_kind
|
||||||
|
(return)))
|
||||||
(statement
|
(statement
|
||||||
(statement_kind
|
(statement_kind
|
||||||
(expression
|
(expression
|
||||||
|
@ -22,7 +22,7 @@ fib = (i <int>) <int> {
|
|||||||
(statement_kind
|
(statement_kind
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(function
|
(anonymous_function
|
||||||
(identifier)
|
(identifier)
|
||||||
(type_specification
|
(type_specification
|
||||||
(type))
|
(type))
|
||||||
|
@ -11,7 +11,7 @@ Anonymous Function
|
|||||||
(statement_kind
|
(statement_kind
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(function
|
(anonymous_function
|
||||||
(type_specification
|
(type_specification
|
||||||
(type))
|
(type))
|
||||||
(block
|
(block
|
||||||
@ -41,7 +41,7 @@ foobar = (x <int>, y <int>) <int> {
|
|||||||
(statement_kind
|
(statement_kind
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(function
|
(anonymous_function
|
||||||
(identifier)
|
(identifier)
|
||||||
(type_specification
|
(type_specification
|
||||||
(type))
|
(type))
|
||||||
@ -139,7 +139,7 @@ Anonymous Function Call
|
|||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(value
|
(value
|
||||||
(function
|
(anonymous_function
|
||||||
(identifier)
|
(identifier)
|
||||||
(type_specification
|
(type_specification
|
||||||
(type))
|
(type))
|
||||||
@ -215,7 +215,7 @@ x(() <bool> { true })
|
|||||||
(identifier))
|
(identifier))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(function
|
(anonymous_function
|
||||||
(type_specification
|
(type_specification
|
||||||
(type))
|
(type))
|
||||||
(block
|
(block
|
||||||
@ -247,3 +247,35 @@ from_json(read('file.json'))
|
|||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string))))))))))
|
(string))))))))))
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
Function Definition
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
fn foo<T> (bar <T>) <T> {
|
||||||
|
bar
|
||||||
|
}
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
(root
|
||||||
|
(statement
|
||||||
|
(statement_kind
|
||||||
|
(type_definition
|
||||||
|
(function_definition
|
||||||
|
(identifier)
|
||||||
|
(type_arguments
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
|
(identifier)
|
||||||
|
(type_specification
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
|
(type_specification
|
||||||
|
(type
|
||||||
|
(identifier)))
|
||||||
|
(block
|
||||||
|
(statement
|
||||||
|
(statement_kind
|
||||||
|
(expression
|
||||||
|
(identifier))))))))))
|
||||||
|
@ -14,19 +14,33 @@ module.exports = grammar({
|
|||||||
statement: $ =>
|
statement: $ =>
|
||||||
prec.left(
|
prec.left(
|
||||||
seq(
|
seq(
|
||||||
optional(
|
|
||||||
choice('return', 'break'),
|
|
||||||
),
|
|
||||||
$.statement_kind,
|
$.statement_kind,
|
||||||
optional(';'),
|
optional(';'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
break: $ =>
|
||||||
|
prec.left(
|
||||||
|
seq(
|
||||||
|
'break',
|
||||||
|
optional($.statement),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
return: $ =>
|
||||||
|
prec.left(
|
||||||
|
seq(
|
||||||
|
'return',
|
||||||
|
optional($.statement),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
statement_kind: $ =>
|
statement_kind: $ =>
|
||||||
prec.left(
|
prec.left(
|
||||||
choice(
|
choice(
|
||||||
$.assignment,
|
$.assignment,
|
||||||
$.block,
|
$.block,
|
||||||
|
$.break,
|
||||||
$.expression,
|
$.expression,
|
||||||
$.for,
|
$.for,
|
||||||
$.if_else,
|
$.if_else,
|
||||||
@ -34,6 +48,7 @@ module.exports = grammar({
|
|||||||
$.loop_node,
|
$.loop_node,
|
||||||
$.match,
|
$.match,
|
||||||
$.pipe,
|
$.pipe,
|
||||||
|
$.return,
|
||||||
$.while,
|
$.while,
|
||||||
$.type_definition,
|
$.type_definition,
|
||||||
),
|
),
|
||||||
@ -123,7 +138,7 @@ module.exports = grammar({
|
|||||||
|
|
||||||
value: $ =>
|
value: $ =>
|
||||||
choice(
|
choice(
|
||||||
$.function,
|
$.anonymous_function,
|
||||||
$.integer,
|
$.integer,
|
||||||
$.float,
|
$.float,
|
||||||
$.string,
|
$.string,
|
||||||
@ -329,10 +344,7 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
loop_node: $ =>
|
loop_node: $ =>
|
||||||
seq(
|
seq('loop', $.block),
|
||||||
'loop',
|
|
||||||
$.block,
|
|
||||||
),
|
|
||||||
|
|
||||||
while: $ =>
|
while: $ =>
|
||||||
seq(
|
seq(
|
||||||
@ -372,7 +384,7 @@ module.exports = grammar({
|
|||||||
// Custom type with arguments
|
// Custom type with arguments
|
||||||
seq(
|
seq(
|
||||||
$.identifier,
|
$.identifier,
|
||||||
$.type_arguments
|
$.type_arguments,
|
||||||
),
|
),
|
||||||
|
|
||||||
// Map with exact fields
|
// Map with exact fields
|
||||||
@ -417,7 +429,7 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
function: $ =>
|
anonymous_function: $ =>
|
||||||
seq(
|
seq(
|
||||||
'(',
|
'(',
|
||||||
repeat(
|
repeat(
|
||||||
@ -466,6 +478,7 @@ module.exports = grammar({
|
|||||||
type_definition: $ =>
|
type_definition: $ =>
|
||||||
choice(
|
choice(
|
||||||
$.enum_definition,
|
$.enum_definition,
|
||||||
|
$.function_definition,
|
||||||
$.struct_definition,
|
$.struct_definition,
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -473,10 +486,7 @@ module.exports = grammar({
|
|||||||
seq(
|
seq(
|
||||||
'<',
|
'<',
|
||||||
repeat1(
|
repeat1(
|
||||||
seq(
|
seq($.type, optional(',')),
|
||||||
$.type,
|
|
||||||
optional(','),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
'>',
|
'>',
|
||||||
),
|
),
|
||||||
@ -493,7 +503,9 @@ module.exports = grammar({
|
|||||||
repeat1(
|
repeat1(
|
||||||
seq(
|
seq(
|
||||||
$.identifier,
|
$.identifier,
|
||||||
optional($.type_arguments),
|
optional(
|
||||||
|
$.type_arguments,
|
||||||
|
),
|
||||||
optional(','),
|
optional(','),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -544,5 +556,23 @@ module.exports = grammar({
|
|||||||
|
|
||||||
struct_instance: $ =>
|
struct_instance: $ =>
|
||||||
seq($.identifier, '::', $.map),
|
seq($.identifier, '::', $.map),
|
||||||
|
|
||||||
|
function_definition: $ =>
|
||||||
|
seq(
|
||||||
|
'fn',
|
||||||
|
$.identifier,
|
||||||
|
optional($.type_arguments),
|
||||||
|
'(',
|
||||||
|
repeat(
|
||||||
|
seq(
|
||||||
|
$.identifier,
|
||||||
|
$.type_specification,
|
||||||
|
optional(','),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
')',
|
||||||
|
$.type_specification,
|
||||||
|
$.block,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -23,27 +23,6 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
|
||||||
"type": "CHOICE",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "CHOICE",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "return"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "break"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "BLANK"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "statement_kind"
|
"name": "statement_kind"
|
||||||
@ -63,6 +42,56 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"break": {
|
||||||
|
"type": "PREC_LEFT",
|
||||||
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "statement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"return": {
|
||||||
|
"type": "PREC_LEFT",
|
||||||
|
"value": 0,
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "return"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "statement"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"statement_kind": {
|
"statement_kind": {
|
||||||
"type": "PREC_LEFT",
|
"type": "PREC_LEFT",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
@ -77,6 +106,10 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "block"
|
"name": "block"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "break"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "expression"
|
"name": "expression"
|
||||||
@ -105,6 +138,10 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "pipe"
|
"name": "pipe"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "return"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "while"
|
"name": "while"
|
||||||
@ -353,7 +390,7 @@
|
|||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "function"
|
"name": "anonymous_function"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
@ -1274,7 +1311,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"function": {
|
"anonymous_function": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
@ -1414,6 +1451,10 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "enum_definition"
|
"name": "enum_definition"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "function_definition"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "struct_definition"
|
"name": "struct_definition"
|
||||||
@ -1680,6 +1721,75 @@
|
|||||||
"name": "map"
|
"name": "map"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"function_definition": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "fn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "type_arguments"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "("
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "REPEAT",
|
||||||
|
"content": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "identifier"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "type_specification"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ","
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ")"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "type_specification"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "block"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extras": [
|
"extras": [
|
||||||
|
@ -1,4 +1,27 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"type": "anonymous_function",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": true,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "block",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "identifier",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "type_specification",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "as_node",
|
"type": "as_node",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -70,6 +93,21 @@
|
|||||||
"named": true,
|
"named": true,
|
||||||
"fields": {}
|
"fields": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "break",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": false,
|
||||||
|
"required": false,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "statement",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -253,7 +291,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function_call",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": true,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function_expression",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function_definition",
|
||||||
"named": true,
|
"named": true,
|
||||||
"fields": {},
|
"fields": {},
|
||||||
"children": {
|
"children": {
|
||||||
@ -268,6 +325,10 @@
|
|||||||
"type": "identifier",
|
"type": "identifier",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "type_arguments",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "type_specification",
|
"type": "type_specification",
|
||||||
"named": true
|
"named": true
|
||||||
@ -275,25 +336,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "function_call",
|
|
||||||
"named": true,
|
|
||||||
"fields": {},
|
|
||||||
"children": {
|
|
||||||
"multiple": true,
|
|
||||||
"required": true,
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"type": "expression",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function_expression",
|
|
||||||
"named": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "function_expression",
|
"type": "function_expression",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -598,6 +640,21 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"named": true,
|
||||||
|
"fields": {},
|
||||||
|
"children": {
|
||||||
|
"multiple": false,
|
||||||
|
"required": false,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "statement",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "root",
|
"type": "root",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -644,6 +701,10 @@
|
|||||||
"type": "block",
|
"type": "block",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "break",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "expression",
|
"type": "expression",
|
||||||
"named": true
|
"named": true
|
||||||
@ -672,6 +733,10 @@
|
|||||||
"type": "pipe",
|
"type": "pipe",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "type_definition",
|
"type": "type_definition",
|
||||||
"named": true
|
"named": true
|
||||||
@ -784,6 +849,10 @@
|
|||||||
"type": "enum_definition",
|
"type": "enum_definition",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "function_definition",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "struct_definition",
|
"type": "struct_definition",
|
||||||
"named": true
|
"named": true
|
||||||
@ -814,6 +883,10 @@
|
|||||||
"multiple": false,
|
"multiple": false,
|
||||||
"required": true,
|
"required": true,
|
||||||
"types": [
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "anonymous_function",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"named": true
|
"named": true
|
||||||
@ -826,10 +899,6 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"named": true
|
"named": true
|
||||||
@ -1036,6 +1105,10 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "fn",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "for",
|
"type": "for",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user