Implement new built-in values
This commit is contained in:
parent
2f0ec91c08
commit
ae66e2a211
@ -1,13 +1,13 @@
|
|||||||
stuff = [
|
stuff = [
|
||||||
random_integer()
|
random:integer()
|
||||||
random_integer()
|
random:integer()
|
||||||
random_integer()
|
random:integer()
|
||||||
random_float()
|
random:float()
|
||||||
random_float()
|
random:float()
|
||||||
random_float()
|
random:float()
|
||||||
random_boolean()
|
random:boolean()
|
||||||
random_boolean()
|
random:boolean()
|
||||||
random_boolean()
|
random:boolean()
|
||||||
]
|
]
|
||||||
|
|
||||||
random(stuff)
|
random:from(stuff)
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{AbstractTree, Error, Expression, FunctionExpression, Map, Result, Type, Value};
|
||||||
AbstractTree, Error, Expression, FunctionExpression, Map, Result, Type, Value,
|
|
||||||
BUILT_IN_FUNCTIONS,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct FunctionCall {
|
pub struct FunctionCall {
|
||||||
@ -84,21 +81,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
let value = match &self.function_expression {
|
let value = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
|
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
|
||||||
if key == built_in_function.name() {
|
|
||||||
let mut arguments = Vec::with_capacity(self.arguments.len());
|
|
||||||
|
|
||||||
for expression in &self.arguments {
|
|
||||||
let value = expression.run(source, context)?;
|
|
||||||
|
|
||||||
arguments.push(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return built_in_function.run(&arguments, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let variables = context.variables()?;
|
let variables = context.variables()?;
|
||||||
|
|
||||||
if let Some((value, _)) = variables.get(key) {
|
if let Some((value, _)) = variables.get(key) {
|
||||||
@ -131,18 +113,6 @@ impl AbstractTree for FunctionCall {
|
|||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match &self.function_expression {
|
match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
|
||||||
if identifier.inner() == built_in_function.name() {
|
|
||||||
if let Type::Function {
|
|
||||||
parameter_types: _,
|
|
||||||
return_type,
|
|
||||||
} = built_in_function.r#type()
|
|
||||||
{
|
|
||||||
return Ok(*return_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
let identifier_type = identifier.expected_type(context)?;
|
||||||
|
|
||||||
if let Type::Function {
|
if let Type::Function {
|
||||||
@ -156,7 +126,15 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context),
|
FunctionExpression::FunctionCall(function_call) => function_call.expected_type(context),
|
||||||
FunctionExpression::Value(value_node) => value_node.expected_type(context),
|
FunctionExpression::Value(value_node) => {
|
||||||
|
let value_type = value_node.expected_type(context)?;
|
||||||
|
|
||||||
|
if let Type::Function { return_type, .. } = value_type {
|
||||||
|
Ok(*return_type)
|
||||||
|
} else {
|
||||||
|
Ok(value_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
FunctionExpression::Index(index) => index.expected_type(context),
|
FunctionExpression::Index(index) => index.expected_type(context),
|
||||||
FunctionExpression::Yield(r#yield) => r#yield.expected_type(context),
|
FunctionExpression::Yield(r#yield) => r#yield.expected_type(context),
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ impl AbstractTree for FunctionExpression {
|
|||||||
"identifier" => FunctionExpression::Identifier(Identifier::from_syntax_node(
|
"identifier" => FunctionExpression::Identifier(Identifier::from_syntax_node(
|
||||||
source, child, context,
|
source, child, context,
|
||||||
)?),
|
)?),
|
||||||
|
|
||||||
"function_call" => FunctionExpression::FunctionCall(Box::new(
|
"function_call" => FunctionExpression::FunctionCall(Box::new(
|
||||||
FunctionCall::from_syntax_node(source, child, context)?,
|
FunctionCall::from_syntax_node(source, child, context)?,
|
||||||
)),
|
)),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Map, Result, Type, Value, BUILT_IN_FUNCTIONS};
|
use crate::{AbstractTree, Error, Map, Result, Type, Value};
|
||||||
|
|
||||||
/// A string by which a variable is known to a context.
|
/// A string by which a variable is known to a context.
|
||||||
///
|
///
|
||||||
@ -47,12 +47,6 @@ impl AbstractTree for Identifier {
|
|||||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
||||||
Ok(r#type.clone())
|
Ok(r#type.clone())
|
||||||
} else {
|
} else {
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
|
||||||
if self.0 == built_in_function.name() {
|
|
||||||
return Ok(built_in_function.r#type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,17 @@ pub enum Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
|
pub fn list_of(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 check(&self, other: &Type) -> Result<()> {
|
pub fn check(&self, other: &Type) -> Result<()> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Type::Any, _)
|
(Type::Any, _)
|
||||||
|
@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value::BuiltInValue, AbstractTree, Block, Error, Expression, Function, Identifier, List, Map,
|
AbstractTree, BuiltInValue, Error, Expression, Function, Identifier, List, Map, Result,
|
||||||
Result, Statement, Type, TypeDefinition, Value,
|
Statement, Type, TypeDefinition, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -29,58 +29,7 @@ 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" => {
|
"function" => ValueNode::Function(Function::from_syntax_node(source, child, context)?),
|
||||||
let child_count = child.child_count();
|
|
||||||
let mut parameters = Vec::new();
|
|
||||||
let mut parameter_types = Vec::new();
|
|
||||||
|
|
||||||
for index in 1..child_count - 3 {
|
|
||||||
let child = child.child(index).unwrap();
|
|
||||||
|
|
||||||
if child.kind() == "identifier" {
|
|
||||||
let identifier = Identifier::from_syntax_node(source, child, context)?;
|
|
||||||
|
|
||||||
parameters.push(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
if child.kind() == "type_definition" {
|
|
||||||
let type_definition =
|
|
||||||
TypeDefinition::from_syntax_node(source, child, context)?;
|
|
||||||
|
|
||||||
parameter_types.push(type_definition.take_inner());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let function_context = Map::clone_from(context)?;
|
|
||||||
|
|
||||||
for (parameter_name, parameter_type) in
|
|
||||||
parameters.iter().zip(parameter_types.iter())
|
|
||||||
{
|
|
||||||
function_context.set(
|
|
||||||
parameter_name.inner().clone(),
|
|
||||||
Value::none(),
|
|
||||||
Some(parameter_type.clone()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let return_type_node = child.child(child_count - 2).unwrap();
|
|
||||||
let return_type =
|
|
||||||
TypeDefinition::from_syntax_node(source, return_type_node, context)?;
|
|
||||||
|
|
||||||
let body_node = child.child(child_count - 1).unwrap();
|
|
||||||
let body = Block::from_syntax_node(source, body_node, &function_context)?;
|
|
||||||
|
|
||||||
return_type
|
|
||||||
.inner()
|
|
||||||
.check(&body.expected_type(&function_context)?)?;
|
|
||||||
|
|
||||||
let r#type = Type::Function {
|
|
||||||
parameter_types,
|
|
||||||
return_type: Box::new(return_type.take_inner()),
|
|
||||||
};
|
|
||||||
|
|
||||||
ValueNode::Function(Function::new(parameters, body, Some(r#type)))
|
|
||||||
}
|
|
||||||
"integer" => ValueNode::Integer(source[child.byte_range()].to_string()),
|
"integer" => ValueNode::Integer(source[child.byte_range()].to_string()),
|
||||||
"string" => {
|
"string" => {
|
||||||
let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
|
let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
|
||||||
|
@ -223,6 +223,5 @@ fn display_value(value: &Value, ui: &mut egui::Ui) {
|
|||||||
ui.label("none");
|
ui.label("none");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Value::BuiltIn(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Assert;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Assert {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"assert"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
for argument in arguments {
|
|
||||||
if !argument.as_boolean()? {
|
|
||||||
return Err(Error::AssertFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::none())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Any],
|
|
||||||
return_type: Box::new(Type::None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AssertEqual;
|
|
||||||
|
|
||||||
impl BuiltInFunction for AssertEqual {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"assert_equal"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 2, arguments.len())?;
|
|
||||||
|
|
||||||
let left = arguments.get(0).unwrap();
|
|
||||||
let right = arguments.get(1).unwrap();
|
|
||||||
|
|
||||||
if left == right {
|
|
||||||
Ok(Value::none())
|
|
||||||
} else {
|
|
||||||
Err(Error::AssertEqualFailed {
|
|
||||||
expected: left.clone(),
|
|
||||||
actual: right.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Any, Type::Any],
|
|
||||||
return_type: Box::new(Type::Boolean),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Length;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Length {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"length"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let length = arguments.first().unwrap().as_list()?.items().len();
|
|
||||||
|
|
||||||
Ok(Value::Integer(length as i64))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::List(Box::new(Type::Any))],
|
|
||||||
return_type: Box::new(Type::Integer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Raw;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Raw {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"raw"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 2, arguments.len())?;
|
|
||||||
|
|
||||||
let program = arguments.first().unwrap().as_string()?;
|
|
||||||
let command_arguments = arguments.get(1).unwrap().as_list()?;
|
|
||||||
let mut command = Command::new(program);
|
|
||||||
|
|
||||||
for argument in command_arguments.items().iter() {
|
|
||||||
command.arg(argument.as_string()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = command.spawn()?.wait_with_output()?.stdout;
|
|
||||||
|
|
||||||
Ok(Value::String(String::from_utf8(output)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> crate::Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String, Type::List(Box::new(Type::String))],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Sh;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Sh {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"sh"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let command_text = arguments.first().unwrap().as_string()?;
|
|
||||||
let mut command = Command::new("sh");
|
|
||||||
|
|
||||||
command.arg("-c");
|
|
||||||
command.arg(command_text);
|
|
||||||
|
|
||||||
let extra_command_text = arguments.get(1).unwrap_or_default().as_option()?;
|
|
||||||
|
|
||||||
if let Some(text) = extra_command_text {
|
|
||||||
command.args(["--", text.as_string()?]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = command.spawn()?.wait_with_output()?.stdout;
|
|
||||||
|
|
||||||
Ok(Value::String(String::from_utf8(output)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> crate::Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String, Type::Option(Box::new(Type::String))],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct FromJson;
|
|
||||||
|
|
||||||
impl BuiltInFunction for FromJson {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"from_json"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let json_string = arguments.first().unwrap().as_string()?;
|
|
||||||
let value = serde_json::from_str(json_string)?;
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String],
|
|
||||||
return_type: Box::new(Type::Any),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ToJson;
|
|
||||||
|
|
||||||
impl BuiltInFunction for ToJson {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"to_json"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let value = arguments.first().unwrap();
|
|
||||||
let json_string = serde_json::to_string(&value)?;
|
|
||||||
|
|
||||||
Ok(Value::String(json_string))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Any],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
use std::{
|
|
||||||
fs::{read_dir, read_to_string, write, File},
|
|
||||||
io::Write as IoWrite,
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, List, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Read;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Read {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"read"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let path_string = arguments.first().unwrap_or_default().as_string()?;
|
|
||||||
let path = PathBuf::from(path_string);
|
|
||||||
|
|
||||||
if path.is_dir() {
|
|
||||||
let files = List::new();
|
|
||||||
|
|
||||||
for entry in read_dir(&path)? {
|
|
||||||
let entry = entry?;
|
|
||||||
let file_data = Map::new();
|
|
||||||
|
|
||||||
let name = entry.file_name().to_string_lossy().to_string();
|
|
||||||
let metadata = entry.metadata()?;
|
|
||||||
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
|
||||||
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
|
||||||
|
|
||||||
file_data.set("name".to_string(), Value::String(name), None)?;
|
|
||||||
file_data.set("created".to_string(), Value::Integer(created), None)?;
|
|
||||||
file_data.set("modified".to_string(), Value::Integer(modified), None)?;
|
|
||||||
|
|
||||||
files.items_mut().push(Value::Map(file_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(Value::List(files));
|
|
||||||
}
|
|
||||||
|
|
||||||
let file_content = read_to_string(path)?;
|
|
||||||
|
|
||||||
Ok(Value::String(file_content))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Write;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Write {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"write"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let file_content = arguments.first().unwrap_or_default().as_string()?;
|
|
||||||
let path = arguments.get(1).unwrap_or_default().as_string()?;
|
|
||||||
|
|
||||||
write(path, file_content)?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String],
|
|
||||||
return_type: Box::new(Type::None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Append;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Append {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"append"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let file_content = arguments.get(0).unwrap_or_default().as_string()?;
|
|
||||||
let path = arguments.get(1).unwrap_or_default().as_string()?;
|
|
||||||
|
|
||||||
File::options()
|
|
||||||
.append(true)
|
|
||||||
.create(true)
|
|
||||||
.open(path)?
|
|
||||||
.write_all(file_content.as_bytes())?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String, Type::String],
|
|
||||||
return_type: Box::new(Type::None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
//! Functions related to [Map][crate::Map] values.
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, List, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Keys;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Keys {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"keys"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let map = arguments.first().unwrap_or_default().as_map()?;
|
|
||||||
let variables = map.variables()?;
|
|
||||||
let mut keys = Vec::with_capacity(variables.len());
|
|
||||||
|
|
||||||
for (key, _) in variables.iter() {
|
|
||||||
keys.push(Value::String(key.clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::List(List::with_items(keys)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Map],
|
|
||||||
return_type: Box::new(Type::List(Box::new(Type::String))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +1,90 @@
|
|||||||
/// Built-in functions that are available to all Dust programs.
|
use std::{
|
||||||
use crate::{Map, Result, Type, Value};
|
fmt::{self, Display, Formatter},
|
||||||
|
fs::read_to_string,
|
||||||
|
};
|
||||||
|
|
||||||
mod assert;
|
use rand::random;
|
||||||
mod collections;
|
use serde::{Deserialize, Serialize};
|
||||||
mod commands;
|
|
||||||
mod data_formats;
|
|
||||||
mod fs;
|
|
||||||
mod network;
|
|
||||||
mod option;
|
|
||||||
mod output;
|
|
||||||
mod packages;
|
|
||||||
mod random;
|
|
||||||
mod r#type;
|
|
||||||
|
|
||||||
/// All built-in functions recognized by the interpreter.
|
use crate::{Error, Map, Result, Type, Value};
|
||||||
///
|
|
||||||
/// This is the public interface to access built-in functions by iterating over
|
|
||||||
/// the references it holds.
|
|
||||||
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 21] = [
|
|
||||||
&assert::Assert,
|
|
||||||
&assert::AssertEqual,
|
|
||||||
&collections::Length,
|
|
||||||
&commands::Raw,
|
|
||||||
&commands::Sh,
|
|
||||||
&data_formats::FromJson,
|
|
||||||
&data_formats::ToJson,
|
|
||||||
&fs::Read,
|
|
||||||
&fs::Write,
|
|
||||||
&fs::Append,
|
|
||||||
&network::Download,
|
|
||||||
&option::EitherOr,
|
|
||||||
&option::IsNone,
|
|
||||||
&option::IsSome,
|
|
||||||
&output::Output,
|
|
||||||
&packages::InstallPackages,
|
|
||||||
&random::Random,
|
|
||||||
&random::RandomBoolean,
|
|
||||||
&random::RandomFloat,
|
|
||||||
&random::RandomInteger,
|
|
||||||
&r#type::TypeFunction,
|
|
||||||
];
|
|
||||||
|
|
||||||
pub trait BuiltInFunction {
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
fn name(&self) -> &'static str;
|
pub enum BuiltInFunction {
|
||||||
fn run(&self, arguments: &[Value], context: &Map) -> Result<Value>;
|
AssertEqual,
|
||||||
fn r#type(&self) -> Type;
|
FsRead,
|
||||||
|
Output,
|
||||||
|
RandomBoolean,
|
||||||
|
Length,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltInFunction {
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
BuiltInFunction::AssertEqual => "assert_equal",
|
||||||
|
BuiltInFunction::FsRead => "fs_read",
|
||||||
|
BuiltInFunction::Output => "output",
|
||||||
|
BuiltInFunction::RandomBoolean => "boolean",
|
||||||
|
BuiltInFunction::Length => "length",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r#type(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
|
||||||
|
BuiltInFunction::FsRead => Type::function(vec![Type::String], Type::String),
|
||||||
|
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
|
||||||
|
BuiltInFunction::RandomBoolean => Type::function(vec![], Type::Boolean),
|
||||||
|
BuiltInFunction::Length => {
|
||||||
|
Type::function(vec![Type::list_of(Type::Any)], Type::Integer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
|
||||||
|
match self {
|
||||||
|
BuiltInFunction::AssertEqual => {
|
||||||
|
Error::expect_argument_amount(self, 2, arguments.len())?;
|
||||||
|
|
||||||
|
let left = arguments.get(0).unwrap();
|
||||||
|
let right = arguments.get(1).unwrap();
|
||||||
|
|
||||||
|
Ok(Value::Boolean(left == right))
|
||||||
|
}
|
||||||
|
BuiltInFunction::FsRead => {
|
||||||
|
Error::expect_argument_amount(self, 1, arguments.len())?;
|
||||||
|
|
||||||
|
let path = arguments.first().unwrap().as_string()?;
|
||||||
|
let file_content = read_to_string(path)?;
|
||||||
|
|
||||||
|
Ok(Value::String(file_content))
|
||||||
|
}
|
||||||
|
BuiltInFunction::Output => {
|
||||||
|
Error::expect_argument_amount(self, 1, arguments.len())?;
|
||||||
|
|
||||||
|
let value = arguments.first().unwrap();
|
||||||
|
|
||||||
|
println!("{value}");
|
||||||
|
|
||||||
|
Ok(Value::none())
|
||||||
|
}
|
||||||
|
BuiltInFunction::RandomBoolean => {
|
||||||
|
Error::expect_argument_amount(self, 0, arguments.len())?;
|
||||||
|
|
||||||
|
Ok(Value::Boolean(random()))
|
||||||
|
}
|
||||||
|
BuiltInFunction::Length => {
|
||||||
|
Error::expect_argument_amount(self, 1, arguments.len())?;
|
||||||
|
|
||||||
|
let list_len = arguments.first().unwrap().as_list()?.items().len() as i64;
|
||||||
|
|
||||||
|
Ok(Value::Integer(list_len))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for BuiltInFunction {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.r#type())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
use reqwest::blocking::get;
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Download;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Download {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"download"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let url = arguments.first().unwrap().as_string()?;
|
|
||||||
let response = get(url)?;
|
|
||||||
|
|
||||||
Ok(Value::String(response.text()?))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::String],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct EitherOr;
|
|
||||||
|
|
||||||
impl BuiltInFunction for EitherOr {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"either_or"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let option = arguments.first().unwrap_or_default().as_option()?;
|
|
||||||
let value = if let Some(value) = option {
|
|
||||||
*value.clone()
|
|
||||||
} else {
|
|
||||||
arguments.get(1).unwrap_or_default().clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Option(Box::new(Type::Any)), Type::Any],
|
|
||||||
return_type: Box::new(Type::Boolean),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IsNone;
|
|
||||||
|
|
||||||
impl BuiltInFunction for IsNone {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"is_none"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let option = arguments.first().unwrap_or_default().as_option()?;
|
|
||||||
|
|
||||||
Ok(Value::Boolean(option.is_none()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Option(Box::new(Type::Any))],
|
|
||||||
return_type: Box::new(Type::Boolean),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct IsSome;
|
|
||||||
|
|
||||||
impl BuiltInFunction for IsSome {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"is_some"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
let option = arguments.first().unwrap_or_default().as_option()?;
|
|
||||||
|
|
||||||
Ok(Value::Boolean(option.is_some()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Option(Box::new(Type::Any))],
|
|
||||||
return_type: Box::new(Type::Boolean),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Output;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Output {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"output"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let value = arguments.first().unwrap();
|
|
||||||
|
|
||||||
println!("{value}");
|
|
||||||
|
|
||||||
Ok(Value::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Any],
|
|
||||||
return_type: Box::new(Type::None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct InstallPackages;
|
|
||||||
|
|
||||||
impl BuiltInFunction for InstallPackages {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"install_packages"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let mut command = Command::new("sudo");
|
|
||||||
let argument_list = arguments.first().unwrap().as_list()?;
|
|
||||||
|
|
||||||
command.args(["dnf", "-y", "install"]);
|
|
||||||
|
|
||||||
for argument in argument_list.items().iter() {
|
|
||||||
command.arg(argument.as_string()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
command.spawn()?.wait()?;
|
|
||||||
|
|
||||||
Ok(Value::none())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::List(Box::new(Type::String))],
|
|
||||||
return_type: Box::new(Type::None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
use rand::{random, thread_rng, Rng};
|
|
||||||
|
|
||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct Random;
|
|
||||||
|
|
||||||
impl BuiltInFunction for Random {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"random"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let list = arguments.first().unwrap().as_list()?;
|
|
||||||
let items = list.items();
|
|
||||||
let random_index = thread_rng().gen_range(0..items.len());
|
|
||||||
let random_argument = items.get(random_index).unwrap();
|
|
||||||
|
|
||||||
Ok(random_argument.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::List(Box::new(Type::Any))],
|
|
||||||
return_type: Box::new(Type::Any),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RandomInteger;
|
|
||||||
|
|
||||||
impl BuiltInFunction for RandomInteger {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"random_integer"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 0, arguments.len())?;
|
|
||||||
|
|
||||||
Ok(Value::Integer(random()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: Vec::with_capacity(0),
|
|
||||||
return_type: Box::new(Type::Integer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RandomFloat;
|
|
||||||
|
|
||||||
impl BuiltInFunction for RandomFloat {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"random_float"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 0, arguments.len())?;
|
|
||||||
|
|
||||||
Ok(Value::Float(random()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: Vec::with_capacity(0),
|
|
||||||
return_type: Box::new(Type::Float),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RandomBoolean;
|
|
||||||
|
|
||||||
impl BuiltInFunction for RandomBoolean {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"random_boolean"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 0, arguments.len())?;
|
|
||||||
|
|
||||||
Ok(Value::Boolean(random()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: Vec::with_capacity(0),
|
|
||||||
return_type: Box::new(Type::Boolean),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Type, Value};
|
|
||||||
|
|
||||||
pub struct TypeFunction;
|
|
||||||
|
|
||||||
impl BuiltInFunction for TypeFunction {
|
|
||||||
fn name(&self) -> &'static str {
|
|
||||||
"type"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
|
||||||
Error::expect_argument_amount(self, 1, arguments.len())?;
|
|
||||||
|
|
||||||
let type_text = arguments.first().unwrap().r#type().to_string();
|
|
||||||
|
|
||||||
Ok(Value::String(type_text))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn r#type(&self) -> Type {
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: vec![Type::Any],
|
|
||||||
return_type: Box::new(Type::String),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -199,8 +199,8 @@ impl Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_argument_amount<F: BuiltInFunction>(
|
pub fn expect_argument_amount(
|
||||||
function: &F,
|
function: &BuiltInFunction,
|
||||||
expected: usize,
|
expected: usize,
|
||||||
actual: usize,
|
actual: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
@ -5,10 +5,15 @@
|
|||||||
//! interpreting Dust code. Most of the language's features are implemented in the [tools] module.
|
//! interpreting Dust code. Most of the language's features are implemented in the [tools] module.
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
abstract_tree::*,
|
abstract_tree::*,
|
||||||
built_in_functions::{BuiltInFunction, BUILT_IN_FUNCTIONS},
|
built_in_functions::BuiltInFunction,
|
||||||
error::*,
|
error::*,
|
||||||
interpret::*,
|
interpret::*,
|
||||||
value::{function::Function, list::List, map::Map, Value},
|
value::{
|
||||||
|
function::{ContextDefinedFunction, Function},
|
||||||
|
list::List,
|
||||||
|
map::Map,
|
||||||
|
BuiltInValue, Value,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod abstract_tree;
|
mod abstract_tree;
|
||||||
|
@ -1,17 +1,127 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Block, Identifier, Map, Result, Type, Value};
|
use crate::{
|
||||||
|
AbstractTree, Block, BuiltInFunction, Error, Identifier, Map, Result, Type, TypeDefinition,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Function {
|
pub enum Function {
|
||||||
|
BuiltIn(BuiltInFunction),
|
||||||
|
ContextDefined(ContextDefinedFunction),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Function {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Function::BuiltIn(inner) => write!(f, "{inner}"),
|
||||||
|
Function::ContextDefined(inner) => write!(f, "{inner}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result<Value> {
|
||||||
|
match self {
|
||||||
|
Function::BuiltIn(built_in_function) => {
|
||||||
|
built_in_function.call(arguments, source, outer_context)
|
||||||
|
}
|
||||||
|
Function::ContextDefined(context_defined_function) => {
|
||||||
|
context_defined_function.call(arguments, source, outer_context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r#type(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
Function::BuiltIn(built_in_function) => built_in_function.r#type(),
|
||||||
|
Function::ContextDefined(context_defined_function) => {
|
||||||
|
context_defined_function.r#type().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for Function {
|
||||||
|
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||||
|
Error::expect_syntax_node(source, "function", node)?;
|
||||||
|
|
||||||
|
let child_count = node.child_count();
|
||||||
|
let mut parameters = Vec::new();
|
||||||
|
let mut parameter_types = Vec::new();
|
||||||
|
|
||||||
|
for index in 1..child_count - 3 {
|
||||||
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
|
if child.kind() == "identifier" {
|
||||||
|
let identifier = Identifier::from_syntax_node(source, child, context)?;
|
||||||
|
|
||||||
|
parameters.push(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if child.kind() == "type_definition" {
|
||||||
|
let type_definition = TypeDefinition::from_syntax_node(source, child, context)?;
|
||||||
|
|
||||||
|
parameter_types.push(type_definition.take_inner());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let function_context = Map::clone_from(context)?;
|
||||||
|
|
||||||
|
for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
|
||||||
|
function_context.set(
|
||||||
|
parameter_name.inner().clone(),
|
||||||
|
Value::none(),
|
||||||
|
Some(parameter_type.clone()),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let return_type_node = node.child(child_count - 2).unwrap();
|
||||||
|
let return_type = TypeDefinition::from_syntax_node(source, return_type_node, context)?;
|
||||||
|
|
||||||
|
let body_node = node.child(child_count - 1).unwrap();
|
||||||
|
let body = Block::from_syntax_node(source, body_node, &function_context)?;
|
||||||
|
|
||||||
|
return_type
|
||||||
|
.inner()
|
||||||
|
.check(&body.expected_type(&function_context)?)
|
||||||
|
.map_err(|error| error.at_node(body_node, source))?;
|
||||||
|
|
||||||
|
let r#type = Type::Function {
|
||||||
|
parameter_types,
|
||||||
|
return_type: Box::new(return_type.take_inner()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self::ContextDefined(ContextDefinedFunction::new(
|
||||||
|
parameters,
|
||||||
|
body,
|
||||||
|
Some(r#type),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct ContextDefinedFunction {
|
||||||
parameters: Vec<Identifier>,
|
parameters: Vec<Identifier>,
|
||||||
body: Block,
|
body: Block,
|
||||||
r#type: Type,
|
r#type: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl ContextDefinedFunction {
|
||||||
pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Option<Type>) -> Self {
|
pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Option<Type>) -> Self {
|
||||||
let r#type = r#type.unwrap_or(Type::Function {
|
let r#type = r#type.unwrap_or(Type::Function {
|
||||||
parameter_types: vec![Type::Any; parameters.len()],
|
parameter_types: vec![Type::Any; parameters.len()],
|
||||||
@ -63,7 +173,7 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Function {
|
impl Display for ContextDefinedFunction {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ use std::{
|
|||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
sync::{Arc, RwLock, RwLockReadGuard},
|
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{value::Value, Result, Type};
|
use crate::{value::Value, Result, Type};
|
||||||
@ -46,6 +46,10 @@ impl Map {
|
|||||||
Ok(self.variables.read()?)
|
Ok(self.variables.read()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, (Value, Type)>>> {
|
||||||
|
Ok(self.variables.write()?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set(
|
pub fn set(
|
||||||
&self,
|
&self,
|
||||||
key: String,
|
key: String,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Types that represent runtime values.
|
//! Types that represent runtime values.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
interpret_with_context, AbstractTree, Function, List, Map, Type,
|
AbstractTree, BuiltInFunction, Function, List, Map, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -14,6 +14,7 @@ use tree_sitter::Node;
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
|
env::args,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
|
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
|
||||||
@ -24,36 +25,70 @@ pub mod function;
|
|||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
|
||||||
static STD: OnceLock<Value> = OnceLock::new();
|
static ARGS: OnceLock<Value> = OnceLock::new();
|
||||||
|
static RANDOM: OnceLock<Value> = OnceLock::new();
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum BuiltInValue {
|
pub enum BuiltInValue {
|
||||||
Std,
|
Args,
|
||||||
|
AssertEqual,
|
||||||
|
Length,
|
||||||
|
Output,
|
||||||
|
Random,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuiltInValue {
|
impl BuiltInValue {
|
||||||
fn r#type(&self) -> Type {
|
fn r#type(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
BuiltInValue::Std => Type::Map,
|
BuiltInValue::Args => Type::list_of(Type::String),
|
||||||
|
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
|
||||||
|
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
|
||||||
|
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
|
||||||
|
BuiltInValue::Random => Type::Map,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self) -> &Value {
|
fn get(&self) -> &Value {
|
||||||
STD.get_or_init(|| {
|
match self {
|
||||||
let std_source = "foobar = () <str> { 'foobar' }";
|
BuiltInValue::Args => ARGS.get_or_init(|| {
|
||||||
let std_context = Map::new();
|
let args = args().map(|arg| Value::String(arg.to_string())).collect();
|
||||||
|
|
||||||
interpret_with_context(std_source, std_context.clone()).unwrap();
|
Value::List(List::with_items(args))
|
||||||
|
}),
|
||||||
|
BuiltInValue::AssertEqual => {
|
||||||
|
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||||
|
}
|
||||||
|
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
||||||
|
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||||
|
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
||||||
|
let random_context = Map::new();
|
||||||
|
|
||||||
Value::Map(std_context)
|
{
|
||||||
})
|
let mut variables = random_context.variables_mut().unwrap();
|
||||||
|
|
||||||
|
for built_in_function in [BuiltInFunction::RandomBoolean] {
|
||||||
|
let key = built_in_function.name().to_string();
|
||||||
|
let value = Value::Function(Function::BuiltIn(built_in_function));
|
||||||
|
let r#type = built_in_function.r#type();
|
||||||
|
|
||||||
|
variables.insert(key, (value, r#type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Map(random_context)
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for BuiltInValue {
|
impl AbstractTree for BuiltInValue {
|
||||||
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
||||||
let built_in_value = match node.kind() {
|
let built_in_value = match node.kind() {
|
||||||
"std" => BuiltInValue::Std,
|
"args" => BuiltInValue::Args,
|
||||||
|
"assert_equal" => BuiltInValue::AssertEqual,
|
||||||
|
"length" => BuiltInValue::Length,
|
||||||
|
"output" => BuiltInValue::Output,
|
||||||
|
"random" => BuiltInValue::Random,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,9 +100,7 @@ impl AbstractTree for BuiltInValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
match self {
|
Ok(self.r#type())
|
||||||
BuiltInValue::Std => Ok(Type::Map),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +119,6 @@ pub enum Value {
|
|||||||
Integer(i64),
|
Integer(i64),
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Option(Option<Box<Value>>),
|
Option(Option<Box<Value>>),
|
||||||
BuiltIn(BuiltInValue),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Value {
|
impl Default for Value {
|
||||||
@ -132,7 +164,6 @@ impl Value {
|
|||||||
Type::None
|
Type::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::BuiltIn(built_in_value) => built_in_value.r#type(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
r#type
|
r#type
|
||||||
@ -471,8 +502,6 @@ 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::BuiltIn(left), Value::BuiltIn(right)) => left.cmp(right),
|
|
||||||
(Value::BuiltIn(_), _) => Ordering::Greater,
|
|
||||||
(Value::String(left), Value::String(right)) => left.cmp(right),
|
(Value::String(left), Value::String(right)) => left.cmp(right),
|
||||||
(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),
|
||||||
@ -524,7 +553,6 @@ impl Serialize for Value {
|
|||||||
Value::Option(inner) => inner.serialize(serializer),
|
Value::Option(inner) => inner.serialize(serializer),
|
||||||
Value::Map(inner) => inner.serialize(serializer),
|
Value::Map(inner) => inner.serialize(serializer),
|
||||||
Value::Function(inner) => inner.serialize(serializer),
|
Value::Function(inner) => inner.serialize(serializer),
|
||||||
Value::BuiltIn(inner) => inner.serialize(serializer),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,7 +580,6 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
Value::Map(map) => write!(f, "{map}"),
|
Value::Map(map) => write!(f, "{map}"),
|
||||||
Value::Function(function) => write!(f, "{function}"),
|
Value::Function(function) => write!(f, "{function}"),
|
||||||
Value::BuiltIn(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,11 @@ mod value {
|
|||||||
let result = interpret("() <int> { 1 }");
|
let result = interpret("() <int> { 1 }");
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
let function = value.as_function().unwrap();
|
let function = value.as_function().unwrap();
|
||||||
|
let function = if let Function::ContextDefined(function) = function {
|
||||||
|
function
|
||||||
|
} else {
|
||||||
|
panic!("Something is wrong with this test...");
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(&Vec::<Identifier>::with_capacity(0), function.parameters());
|
assert_eq!(&Vec::<Identifier>::with_capacity(0), function.parameters());
|
||||||
assert_eq!(&Type::Integer, function.return_type());
|
assert_eq!(&Type::Integer, function.return_type());
|
||||||
@ -190,6 +195,11 @@ mod value {
|
|||||||
let result = interpret("(x <bool>) <bool> { true }");
|
let result = interpret("(x <bool>) <bool> { true }");
|
||||||
let value = result.unwrap();
|
let value = result.unwrap();
|
||||||
let function = value.as_function().unwrap();
|
let function = value.as_function().unwrap();
|
||||||
|
let function = if let Function::ContextDefined(function) = function {
|
||||||
|
function
|
||||||
|
} else {
|
||||||
|
panic!("Something is wrong with this test...");
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&vec![Identifier::new("x".to_string())],
|
&vec![Identifier::new("x".to_string())],
|
||||||
@ -503,3 +513,15 @@ mod blocks {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod std {
|
||||||
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_std() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret("std:read"),
|
||||||
|
Ok(Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,8 +13,8 @@ async { output ('Whaddup') }
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))))))))
|
(string)))))))))
|
||||||
|
@ -15,8 +15,8 @@ Simple Block
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(integer)))))))))
|
(integer)))))))))
|
||||||
|
@ -29,8 +29,8 @@ for i in [1, 2, 3] {
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(identifier)))))))))
|
(identifier)))))))))
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ for list in list_of_lists {
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(identifier))))))))))))
|
(identifier))))))))))))
|
||||||
|
@ -129,16 +129,17 @@ Anonymous Function Call
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(function
|
(value
|
||||||
(identifier)
|
(function
|
||||||
(type_definition
|
(identifier)
|
||||||
(type))
|
(type_definition
|
||||||
(type_definition
|
(type))
|
||||||
(type))
|
(type_definition
|
||||||
(block
|
(type))
|
||||||
(statement
|
(block
|
||||||
(expression
|
(statement
|
||||||
(identifier))))))
|
(expression
|
||||||
|
(identifier)))))))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))))))
|
(string)))))))
|
||||||
@ -222,13 +223,11 @@ from_json(read('file.json'))
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(identifier))
|
||||||
(built_in_function)))
|
|
||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(identifier))
|
||||||
(built_in_function)))
|
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string)))))))))
|
(string)))))))))
|
||||||
|
@ -65,8 +65,8 @@ Complex Logic Sequence
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(identifier))))
|
||||||
(logic_operator)
|
(logic_operator)
|
||||||
@ -79,8 +79,8 @@ Complex Logic Sequence
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(identifier))))
|
||||||
(logic_operator)
|
(logic_operator)
|
||||||
@ -93,8 +93,8 @@ Complex Logic Sequence
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(identifier))))
|
||||||
(logic_operator)
|
(logic_operator)
|
||||||
|
@ -19,8 +19,8 @@ while true {
|
|||||||
(expression
|
(expression
|
||||||
(function_call
|
(function_call
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))
|
(built_in_value)))
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
(string))))))))))
|
(string))))))))))
|
||||||
|
@ -14,8 +14,8 @@ Simple Yield
|
|||||||
(value
|
(value
|
||||||
(integer)))
|
(integer)))
|
||||||
(function_expression
|
(function_expression
|
||||||
(identifier
|
(value
|
||||||
(built_in_function)))))))
|
(built_in_value)))))))
|
||||||
|
|
||||||
================================================================================
|
================================================================================
|
||||||
Yield Chain
|
Yield Chain
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module.exports = grammar({
|
module.exports = grammar({
|
||||||
name: 'dust',
|
name: 'dust',
|
||||||
|
|
||||||
word: $ => $._identifier_pattern,
|
word: $ => $.identifier,
|
||||||
|
|
||||||
extras: $ => [/\s/, $._comment],
|
extras: $ => [/\s/, $._comment],
|
||||||
|
|
||||||
@ -71,12 +71,6 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
identifier: $ =>
|
identifier: $ =>
|
||||||
choice(
|
|
||||||
$._identifier_pattern,
|
|
||||||
$.built_in_function,
|
|
||||||
),
|
|
||||||
|
|
||||||
_identifier_pattern: $ =>
|
|
||||||
/[_a-zA-Z]+[_a-zA-Z0-9]*[_a-zA-Z]?/,
|
/[_a-zA-Z]+[_a-zA-Z0-9]*[_a-zA-Z]?/,
|
||||||
|
|
||||||
value: $ =>
|
value: $ =>
|
||||||
@ -406,11 +400,10 @@ module.exports = grammar({
|
|||||||
prec(
|
prec(
|
||||||
2,
|
2,
|
||||||
choice(
|
choice(
|
||||||
$.built_in_value,
|
|
||||||
$.function,
|
|
||||||
$.function_call,
|
$.function_call,
|
||||||
$.identifier,
|
$.identifier,
|
||||||
$.index,
|
$.index,
|
||||||
|
$.value,
|
||||||
$.yield,
|
$.yield,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -442,30 +435,14 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
built_in_function: $ =>
|
built_in_value: $ =>
|
||||||
choice(
|
choice(
|
||||||
'assert',
|
'args',
|
||||||
'assert_equal',
|
'assert_equal',
|
||||||
'bash',
|
'env',
|
||||||
'download',
|
|
||||||
'either_or',
|
|
||||||
'fish',
|
|
||||||
'from_json',
|
|
||||||
'is_none',
|
|
||||||
'is_some',
|
|
||||||
'length',
|
'length',
|
||||||
'metadata',
|
|
||||||
'output',
|
'output',
|
||||||
'output_error',
|
|
||||||
'random',
|
'random',
|
||||||
'random_boolean',
|
|
||||||
'random_float',
|
|
||||||
'random_integer',
|
|
||||||
'read',
|
|
||||||
'to_json',
|
|
||||||
'write',
|
|
||||||
),
|
),
|
||||||
|
|
||||||
built_in_value: $ => choice('std'),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dust",
|
"name": "dust",
|
||||||
"word": "_identifier_pattern",
|
"word": "identifier",
|
||||||
"rules": {
|
"rules": {
|
||||||
"root": {
|
"root": {
|
||||||
"type": "PREC",
|
"type": "PREC",
|
||||||
@ -203,19 +203,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"identifier": {
|
"identifier": {
|
||||||
"type": "CHOICE",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "_identifier_pattern"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "built_in_function"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"_identifier_pattern": {
|
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[_a-zA-Z]+[_a-zA-Z0-9]*[_a-zA-Z]?"
|
"value": "[_a-zA-Z]+[_a-zA-Z0-9]*[_a-zA-Z]?"
|
||||||
},
|
},
|
||||||
@ -1304,14 +1291,6 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "built_in_value"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "SYMBOL",
|
|
||||||
"name": "function"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "function_call"
|
"name": "function_call"
|
||||||
@ -1324,6 +1303,10 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "index"
|
"name": "index"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "value"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "yield"
|
"name": "yield"
|
||||||
@ -1410,12 +1393,12 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"built_in_function": {
|
"built_in_value": {
|
||||||
"type": "CHOICE",
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "assert"
|
"value": "args"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
@ -1423,84 +1406,19 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "bash"
|
"value": "env"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "download"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "either_or"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "fish"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "from_json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "is_none"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "is_some"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "length"
|
"value": "length"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "metadata"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "output"
|
"value": "output"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "output_error"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "random"
|
"value": "random"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "random_boolean"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "random_float"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "random_integer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "read"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "to_json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "write"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"built_in_value": {
|
|
||||||
"type": "CHOICE",
|
|
||||||
"members": [
|
|
||||||
{
|
|
||||||
"type": "STRING",
|
|
||||||
"value": "std"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -51,11 +51,6 @@
|
|||||||
"named": true,
|
"named": true,
|
||||||
"fields": {}
|
"fields": {}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "built_in_function",
|
|
||||||
"named": true,
|
|
||||||
"fields": {}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "built_in_value",
|
"type": "built_in_value",
|
||||||
"named": true,
|
"named": true,
|
||||||
@ -207,14 +202,6 @@
|
|||||||
"multiple": false,
|
"multiple": false,
|
||||||
"required": true,
|
"required": true,
|
||||||
"types": [
|
"types": [
|
||||||
{
|
|
||||||
"type": "built_in_value",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "function_call",
|
"type": "function_call",
|
||||||
"named": true
|
"named": true
|
||||||
@ -228,22 +215,11 @@
|
|||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "yield",
|
"type": "value",
|
||||||
"named": true
|
"named": true
|
||||||
}
|
},
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "identifier",
|
|
||||||
"named": true,
|
|
||||||
"fields": {},
|
|
||||||
"children": {
|
|
||||||
"multiple": false,
|
|
||||||
"required": false,
|
|
||||||
"types": [
|
|
||||||
{
|
{
|
||||||
"type": "built_in_function",
|
"type": "yield",
|
||||||
"named": true
|
"named": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -777,7 +753,7 @@
|
|||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "assert",
|
"type": "args",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -792,22 +768,10 @@
|
|||||||
"type": "async for",
|
"type": "async for",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "bash",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "download",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "either_or",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "else",
|
"type": "else",
|
||||||
"named": false
|
"named": false
|
||||||
@ -817,11 +781,11 @@
|
|||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "false",
|
"type": "env",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "fish",
|
"type": "false",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -837,8 +801,8 @@
|
|||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "from_json",
|
"type": "identifier",
|
||||||
"named": false
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "if",
|
"type": "if",
|
||||||
@ -856,14 +820,6 @@
|
|||||||
"type": "integer",
|
"type": "integer",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "is_none",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "is_some",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "length",
|
"type": "length",
|
||||||
"named": false
|
"named": false
|
||||||
@ -876,10 +832,6 @@
|
|||||||
"type": "match",
|
"type": "match",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "metadata",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "none",
|
"type": "none",
|
||||||
"named": false
|
"named": false
|
||||||
@ -896,30 +848,10 @@
|
|||||||
"type": "output",
|
"type": "output",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "output_error",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "random",
|
"type": "random",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "random_boolean",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "random_float",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "random_integer",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "read",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "return",
|
"type": "return",
|
||||||
"named": false
|
"named": false
|
||||||
@ -928,10 +860,6 @@
|
|||||||
"type": "some",
|
"type": "some",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "std",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"named": false
|
"named": false
|
||||||
@ -940,10 +868,6 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "to_json",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "true",
|
"type": "true",
|
||||||
"named": false
|
"named": false
|
||||||
@ -952,10 +876,6 @@
|
|||||||
"type": "while",
|
"type": "while",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "write",
|
|
||||||
"named": false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "{",
|
"type": "{",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user