1
0

Add index expressions to fix parsing bug

This commit is contained in:
Jeff 2023-12-31 23:38:09 -05:00
parent 346ff1c0da
commit 2f0ec91c08
18 changed files with 21644 additions and 17757 deletions

View File

@ -30,10 +30,6 @@ impl AbstractTree for Identifier {
let text = &source[node.byte_range()];
if text.is_empty() {
println!("{node:?}");
}
debug_assert!(!text.is_empty());
Ok(Identifier(text.to_string()))

View File

@ -1,16 +1,16 @@
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, List, Map, Result, Type, Value};
use crate::{AbstractTree, Error, IndexExpression, List, Map, Result, Type, Value};
/// Abstract representation of an index expression.
///
/// An index is a means of accessing values stored in list, maps and strings.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Index {
pub collection: Expression,
pub index: Expression,
pub index_end: Option<Expression>,
pub collection: IndexExpression,
pub index: IndexExpression,
pub index_end: Option<IndexExpression>,
}
impl AbstractTree for Index {
@ -18,14 +18,14 @@ impl AbstractTree for Index {
Error::expect_syntax_node(source, "index", node)?;
let collection_node = node.child(0).unwrap();
let collection = Expression::from_syntax_node(source, collection_node, context)?;
let collection = IndexExpression::from_syntax_node(source, collection_node, context)?;
let index_node = node.child(2).unwrap();
let index = Expression::from_syntax_node(source, index_node, context)?;
let index = IndexExpression::from_syntax_node(source, index_node, context)?;
let index_end_node = node.child(4);
let index_end = if let Some(index_end_node) = index_end_node {
Some(Expression::from_syntax_node(
Some(IndexExpression::from_syntax_node(
source,
index_end_node,
context,
@ -60,7 +60,7 @@ impl AbstractTree for Index {
Ok(item)
}
Value::Map(map) => {
let value = if let Expression::Identifier(identifier) = &self.index {
let value = if let IndexExpression::Identifier(identifier) = &self.index {
let key = identifier.inner();
map.variables()?

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{AbstractTree, Error, Index, Map, Result, Statement, Type, Value};
use crate::{AbstractTree, Error, Index, IndexExpression, Map, Result, Statement, Type, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct IndexAssignment {
@ -52,7 +52,7 @@ impl AbstractTree for IndexAssignment {
fn run(&self, source: &str, context: &Map) -> Result<Value> {
let index_collection = self.index.collection.run(source, context)?;
let index_context = index_collection.as_map().unwrap_or(context);
let index_key = if let crate::Expression::Identifier(identifier) = &self.index.index {
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
identifier.inner()
} else {
return Err(Error::VariableIdentifierNotFound(

View File

@ -0,0 +1,68 @@
use serde::{Deserialize, Serialize};
use crate::{
value_node::ValueNode, AbstractTree, Error, FunctionCall, Identifier, Index, Map, Result, Type,
Value,
};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum IndexExpression {
Value(ValueNode),
Identifier(Identifier),
Index(Box<Index>),
FunctionCall(Box<FunctionCall>),
}
impl AbstractTree for IndexExpression {
fn from_syntax_node(source: &str, node: tree_sitter::Node, context: &Map) -> Result<Self> {
Error::expect_syntax_node(source, "index_expression", node)?;
let first_child = node.child(0).unwrap();
let child = if first_child.is_named() {
first_child
} else {
node.child(1).unwrap()
};
let abstract_node = match child.kind() {
"value" => IndexExpression::Value(ValueNode::from_syntax_node(source, child, context)?),
"identifier" => {
IndexExpression::Identifier(Identifier::from_syntax_node(source, child, context)?)
}
"index" => {
IndexExpression::Index(Box::new(Index::from_syntax_node(source, child, context)?))
}
"function_call" => IndexExpression::FunctionCall(Box::new(
FunctionCall::from_syntax_node(source, child, context)?,
)),
_ => {
return Err(Error::UnexpectedSyntaxNode {
expected: "value, identifier, index or function call".to_string(),
actual: child.kind().to_string(),
location: child.start_position(),
relevant_source: source[child.byte_range()].to_string(),
})
}
};
Ok(abstract_node)
}
fn run(&self, source: &str, context: &Map) -> Result<Value> {
match self {
IndexExpression::Value(value_node) => value_node.run(source, context),
IndexExpression::Identifier(identifier) => identifier.run(source, context),
IndexExpression::Index(index) => index.run(source, context),
IndexExpression::FunctionCall(function_call) => function_call.run(source, context),
}
}
fn expected_type(&self, context: &Map) -> Result<Type> {
match self {
IndexExpression::Value(value_node) => value_node.expected_type(context),
IndexExpression::Identifier(identifier) => identifier.expected_type(context),
IndexExpression::Index(index) => index.expected_type(context),
IndexExpression::FunctionCall(function_call) => function_call.expected_type(context),
}
}
}

View File

@ -16,6 +16,7 @@ pub mod identifier;
pub mod if_else;
pub mod index;
pub mod index_assignment;
pub mod index_expression;
pub mod logic;
pub mod r#match;
pub mod math;
@ -27,8 +28,9 @@ pub mod r#yield;
pub use {
assignment::*, block::*, expression::*, function_call::*, function_expression::*,
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, logic::*, math::*,
r#for::*, r#match::*, r#while::*, r#yield::*, statement::*, type_definition::*, value_node::*,
identifier::*, if_else::*, index::*, index_assignment::IndexAssignment, index_expression::*,
logic::*, math::*, r#for::*, r#match::*, r#while::*, r#yield::*, statement::*,
type_definition::*, value_node::*,
};
use tree_sitter::Node;

View File

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{
AbstractTree, Block, Error, Expression, Function, Identifier, List, Map, Result, Statement,
Type, TypeDefinition, Value,
value::BuiltInValue, AbstractTree, Block, Error, Expression, Function, Identifier, List, Map,
Result, Statement, Type, TypeDefinition, Value,
};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
@ -18,6 +18,7 @@ pub enum ValueNode {
List(Vec<Expression>),
Option(Option<Box<Expression>>),
Map(BTreeMap<String, (Statement, Option<Type>)>),
BuiltInValue(BuiltInValue),
}
impl AbstractTree for ValueNode {
@ -150,6 +151,15 @@ impl AbstractTree for ValueNode {
ValueNode::Option(Some(Box::new(expression)))
}
}
"built_in_value" => {
let built_in_value_node = child.child(0).unwrap();
ValueNode::BuiltInValue(BuiltInValue::from_syntax_node(
source,
built_in_value_node,
context,
)?)
}
_ => {
return Err(Error::UnexpectedSyntaxNode {
expected: "string, integer, float, boolean, list, map, or option".to_string(),
@ -203,6 +213,7 @@ impl AbstractTree for ValueNode {
Value::Map(map)
}
ValueNode::BuiltInValue(built_in_value) => built_in_value.run(source, context)?,
};
Ok(value)
@ -244,6 +255,7 @@ impl AbstractTree for ValueNode {
}
}
ValueNode::Map(_) => Type::Map,
ValueNode::BuiltInValue(built_in_value) => built_in_value.expected_type(context)?,
};
Ok(r#type)

View File

@ -223,5 +223,6 @@ fn display_value(value: &Value, ui: &mut egui::Ui) {
ui.label("none");
}
},
Value::BuiltIn(_) => todo!(),
}
}

View File

@ -11,14 +11,13 @@ mod option;
mod output;
mod packages;
mod random;
mod std;
mod r#type;
/// All built-in functions recognized by the interpreter.
///
/// This is the public interface to access built-in functions by iterating over
/// the references it holds.
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 22] = [
pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 21] = [
&assert::Assert,
&assert::AssertEqual,
&collections::Length,
@ -39,7 +38,6 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 22] = [
&random::RandomBoolean,
&random::RandomFloat,
&random::RandomInteger,
&std::Std,
&r#type::TypeFunction,
];

View File

@ -1,35 +0,0 @@
use std::sync::OnceLock;
use crate::{interpret_with_context, BuiltInFunction, Error, Map, Result, Type, Value};
static STD: OnceLock<Map> = OnceLock::new();
pub struct Std;
impl BuiltInFunction for Std {
fn name(&self) -> &'static str {
"std"
}
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
Error::expect_argument_amount(self, 0, arguments.len())?;
let std_context = STD.get_or_init(|| {
let std_source = "say_hi = () <none> { output('hi') }";
let std_context = Map::new();
interpret_with_context(std_source, std_context.clone()).unwrap();
std_context
});
Ok(Value::Map(std_context.clone()))
}
fn r#type(&self) -> Type {
Type::Function {
parameter_types: vec![],
return_type: Box::new(Type::Map),
}
}
}

View File

@ -1,7 +1,7 @@
//! Types that represent runtime values.
use crate::{
error::{Error, Result},
Function, List, Map, Type,
interpret_with_context, AbstractTree, Function, List, Map, Type,
};
use serde::{
@ -9,6 +9,7 @@ use serde::{
ser::SerializeTuple,
Deserialize, Serialize, Serializer,
};
use tree_sitter::Node;
use std::{
cmp::Ordering,
@ -16,12 +17,60 @@ use std::{
fmt::{self, Display, Formatter},
marker::PhantomData,
ops::{Add, AddAssign, Div, Mul, Rem, Sub, SubAssign},
sync::OnceLock,
};
pub mod function;
pub mod list;
pub mod map;
static STD: OnceLock<Value> = OnceLock::new();
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInValue {
Std,
}
impl BuiltInValue {
fn r#type(&self) -> Type {
match self {
BuiltInValue::Std => Type::Map,
}
}
fn get(&self) -> &Value {
STD.get_or_init(|| {
let std_source = "foobar = () <str> { 'foobar' }";
let std_context = Map::new();
interpret_with_context(std_source, std_context.clone()).unwrap();
Value::Map(std_context)
})
}
}
impl AbstractTree for BuiltInValue {
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
let built_in_value = match node.kind() {
"std" => BuiltInValue::Std,
_ => todo!(),
};
Ok(built_in_value)
}
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
Ok(self.get().clone())
}
fn expected_type(&self, _context: &Map) -> Result<Type> {
match self {
BuiltInValue::Std => Ok(Type::Map),
}
}
}
/// Dust value representation.
///
/// Every dust variable has a key and a Value. Variables are represented by
@ -37,6 +86,7 @@ pub enum Value {
Integer(i64),
Boolean(bool),
Option(Option<Box<Value>>),
BuiltIn(BuiltInValue),
}
impl Default for Value {
@ -82,6 +132,7 @@ impl Value {
Type::None
}
}
Value::BuiltIn(built_in_value) => built_in_value.r#type(),
};
r#type
@ -420,6 +471,8 @@ impl PartialOrd for Value {
impl Ord for Value {
fn cmp(&self, other: &Self) -> Ordering {
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(_), _) => Ordering::Greater,
(Value::Float(left), Value::Float(right)) => left.total_cmp(right),
@ -471,6 +524,7 @@ impl Serialize for Value {
Value::Option(inner) => inner.serialize(serializer),
Value::Map(inner) => inner.serialize(serializer),
Value::Function(inner) => inner.serialize(serializer),
Value::BuiltIn(inner) => inner.serialize(serializer),
}
}
}
@ -498,6 +552,7 @@ impl Display for Value {
}
Value::Map(map) => write!(f, "{map}"),
Value::Function(function) => write!(f, "{function}"),
Value::BuiltIn(_) => todo!(),
}
}
}

View File

@ -344,7 +344,7 @@ mod index {
"
x = [1 2 3]
y = () <int> { 2 }
x:y()
x:(y())
",
),
Ok(Value::Integer(3))
@ -356,7 +356,7 @@ mod index {
x = {
y = () <int> { 2 }
}
(x:y)()
x:y()
",
),
Ok(Value::Integer(2))

View File

@ -46,9 +46,9 @@ x:y = 1
(statement
(index_assignment
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(identifier)))
(assignment_operator)
(statement
@ -68,9 +68,9 @@ x:9 = 'foobar'
(statement
(index_assignment
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(value
(integer))))
(assignment_operator)

View File

@ -85,16 +85,16 @@ foo:bar("Hiya")
(root
(statement
(expression
(index
(expression
(identifier))
(expression
(function_call
(function_expression
(function_call
(function_expression
(index
(index_expression
(identifier))
(expression
(value
(string)))))))))
(index_expression
(identifier))))
(expression
(value
(string)))))))
================================================================================
Double Function Call

View File

@ -14,33 +14,33 @@ foobar:1:42
(statement
(expression
(index
(expression
(index_expression
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(value
(integer)))))
(expression
(index_expression
(identifier)))))
(statement
(expression
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(identifier)))))
(statement
(expression
(index
(expression
(index_expression
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(value
(integer)))))
(expression
(index_expression
(value
(integer)))))))
@ -56,11 +56,11 @@ Nested Indexes
(statement
(expression
(index
(expression
(index_expression
(index
(expression
(index_expression
(index
(expression
(index_expression
(value
(list
(expression
@ -78,13 +78,13 @@ Nested Indexes
(expression
(value
(integer))))))
(expression
(index_expression
(value
(integer)))))
(expression
(index_expression
(value
(integer)))))
(expression
(index_expression
(value
(integer)))
(expression
@ -95,7 +95,7 @@ Nested Indexes
Function Call Index
================================================================================
x:y():0
x:(y()):0
--------------------------------------------------------------------------------
@ -103,14 +103,14 @@ x:y():0
(statement
(expression
(index
(expression
(index_expression
(index
(expression
(index_expression
(identifier))
(expression
(index_expression
(function_call
(function_expression
(identifier))))))
(expression
(index_expression
(value
(integer)))))))

View File

@ -89,6 +89,7 @@ module.exports = grammar({
$.list,
$.map,
$.option,
$.built_in_value,
),
integer: $ =>
@ -202,15 +203,30 @@ module.exports = grammar({
prec.left(
1,
seq(
$.expression,
$.index_expression,
':',
$.expression,
$.index_expression,
optional(
seq('..', $.expression),
),
),
),
index_expression: $ =>
prec(
1,
choice(
seq(
'(',
$.function_call,
')',
),
$.identifier,
$.index,
$.value,
),
),
math: $ =>
prec.left(
seq(
@ -388,8 +404,9 @@ module.exports = grammar({
_function_expression_kind: $ =>
prec(
1,
2,
choice(
$.built_in_value,
$.function,
$.function_call,
$.identifier,
@ -397,6 +414,7 @@ module.exports = grammar({
$.yield,
),
),
function_call: $ =>
prec.right(
seq(
@ -447,5 +465,7 @@ module.exports = grammar({
'to_json',
'write',
),
built_in_value: $ => choice('std'),
},
});

View File

@ -253,6 +253,10 @@
{
"type": "SYMBOL",
"name": "option"
},
{
"type": "SYMBOL",
"name": "built_in_value"
}
]
},
@ -605,7 +609,7 @@
"members": [
{
"type": "SYMBOL",
"name": "expression"
"name": "index_expression"
},
{
"type": "STRING",
@ -613,7 +617,7 @@
},
{
"type": "SYMBOL",
"name": "expression"
"name": "index_expression"
},
{
"type": "CHOICE",
@ -639,6 +643,44 @@
]
}
},
"index_expression": {
"type": "PREC",
"value": 1,
"content": {
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "SYMBOL",
"name": "function_call"
},
{
"type": "STRING",
"value": ")"
}
]
},
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "SYMBOL",
"name": "index"
},
{
"type": "SYMBOL",
"name": "value"
}
]
}
},
"math": {
"type": "PREC_LEFT",
"value": 0,
@ -1258,10 +1300,14 @@
},
"_function_expression_kind": {
"type": "PREC",
"value": 1,
"value": 2,
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "built_in_value"
},
{
"type": "SYMBOL",
"name": "function"
@ -1448,6 +1494,15 @@
"value": "write"
}
]
},
"built_in_value": {
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": "std"
}
]
}
},
"extras": [

View File

@ -56,6 +56,11 @@
"named": true,
"fields": {}
},
{
"type": "built_in_value",
"named": true,
"fields": {}
},
{
"type": "else",
"named": true,
@ -202,6 +207,10 @@
"multiple": false,
"required": true,
"types": [
{
"type": "built_in_value",
"named": true
},
{
"type": "function",
"named": true
@ -293,6 +302,10 @@
{
"type": "expression",
"named": true
},
{
"type": "index_expression",
"named": true
}
]
}
@ -320,6 +333,33 @@
]
}
},
{
"type": "index_expression",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "function_call",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "index",
"named": true
},
{
"type": "value",
"named": true
}
]
}
},
{
"type": "list",
"named": true,
@ -559,6 +599,10 @@
"type": "boolean",
"named": true
},
{
"type": "built_in_value",
"named": true
},
{
"type": "float",
"named": true
@ -884,6 +928,10 @@
"type": "some",
"named": false
},
{
"type": "std",
"named": false
},
{
"type": "str",
"named": false

File diff suppressed because it is too large Load Diff