1
0

Implement type checking

This commit is contained in:
Jeff 2023-11-27 17:53:12 -05:00
parent 25852efcd6
commit 2bd4ccb40d
15 changed files with 113 additions and 227 deletions

View File

@ -1,6 +1,6 @@
(output "This will print first.")
create_random_numbers = |count| => {
create_random_numbers = |count <int>| {
numbers = [];
while (length numbers) < count {

View File

@ -4,7 +4,7 @@ add_one = |numbers <list>| <list> {
new_numbers = []
for number in numbers {
new_list += number + 1
new_numbers += number + 1
}
new_numbers
@ -13,4 +13,3 @@ add_one = |numbers <list>| <list> {
foo = [1, 2, 3] -> (add_one)
(assert_equal [2 3 4] foo)

View File

@ -63,24 +63,24 @@ impl AbstractTree for Assignment {
}
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
let key = self.identifier.inner().clone();
let key = self.identifier.inner();
let value = self.statement.run(source, context)?;
let new_value = match self.operator {
AssignmentOperator::PlusEqual => {
if let Some(mut previous_value) = context.variables()?.get(&key).cloned() {
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
previous_value += value;
previous_value
} else {
Value::Empty
return Err(Error::VariableIdentifierNotFound(key.clone()));
}
}
AssignmentOperator::MinusEqual => {
if let Some(mut previous_value) = context.variables()?.get(&key).cloned() {
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
previous_value -= value;
previous_value
} else {
Value::Empty
return Err(Error::VariableIdentifierNotFound(key.clone()));
}
}
AssignmentOperator::Equal => value,
@ -90,7 +90,7 @@ impl AbstractTree for Assignment {
r#type.check(&new_value)?;
}
context.variables_mut()?.insert(key, new_value);
context.variables_mut()?.insert(key.clone(), new_value);
Ok(Value::Empty)
}

View File

@ -4,7 +4,7 @@ use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{AbstractTree, Map, Result, Statement, Value};
use crate::{AbstractTree, Error, Map, Result, Statement, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Block {
@ -14,7 +14,7 @@ pub struct Block {
impl AbstractTree for Block {
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
debug_assert_eq!("block", node.kind());
Error::expect_syntax_node(source, "block", node)?;
let first_child = node.child(0).unwrap();
let is_async = first_child.kind() == "async";

View File

@ -11,7 +11,7 @@ use reqwest::blocking::get;
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
use crate::{AbstractTree, Error, Expression, List, Map, Result, Table, Value, ValueType};
use crate::{AbstractTree, Error, Expression, List, Map, Result, Table, Type, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum BuiltInFunction {
@ -367,9 +367,9 @@ impl AbstractTree for BuiltInFunction {
BuiltInFunction::Type(expression) => {
let run_expression = expression.run(source, context);
let value_type = if let Ok(value) = run_expression {
value.value_type()
value.r#type()
} else if let Err(Error::VariableIdentifierNotFound(_)) = run_expression {
ValueType::Empty
Type::Any
} else {
return run_expression;
};

View File

@ -14,6 +14,8 @@ pub struct For {
impl AbstractTree for For {
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
Error::expect_syntax_node(source, "for", node)?;
let for_node = node.child(0).unwrap();
let is_async = match for_node.kind() {
"for" => false,

View File

@ -1,3 +1,5 @@
use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
@ -89,3 +91,19 @@ impl AbstractTree for Type {
Ok(Value::Empty)
}
}
impl Display for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"),
Type::Float => write!(f, "float"),
Type::Function => write!(f, "function"),
Type::Integer => write!(f, "integer"),
Type::List => write!(f, "list"),
Type::Map => write!(f, "map"),
Type::String => write!(f, "string"),
Type::Table => write!(f, "table"),
}
}
}

View File

@ -5,19 +5,23 @@ use tree_sitter::Node;
use crate::{
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
Value, ValueType,
Value,
};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct ValueNode {
value_type: ValueType,
source: String,
}
impl ValueNode {
pub fn new(value_type: ValueType, source: String) -> Self {
Self { value_type, source }
}
pub enum ValueNode {
Boolean(String),
Float(String),
Integer(String),
String(String),
List(Vec<Expression>),
Empty,
Map(BTreeMap<String, Statement>),
Table {
column_names: Vec<Identifier>,
rows: Box<Expression>,
},
Function(Function),
}
impl AbstractTree for ValueNode {
@ -25,12 +29,15 @@ impl AbstractTree for ValueNode {
debug_assert_eq!("value", node.kind());
let child = node.child(0).unwrap();
let value_type = match child.kind() {
"integer" => ValueType::Integer,
"float" => ValueType::Float,
"string" => ValueType::String,
"boolean" => ValueType::Boolean,
"empty" => ValueType::Empty,
let value_node = match child.kind() {
"boolean" => ValueNode::Boolean(source[child.byte_range()].to_string()),
"float" => ValueNode::Float(source[child.byte_range()].to_string()),
"integer" => ValueNode::Integer(source[child.byte_range()].to_string()),
"string" => {
let without_quotes = child.start_byte() + 1..child.end_byte() - 1;
ValueNode::String(source[without_quotes].to_string())
}
"list" => {
let mut expressions = Vec::new();
@ -43,7 +50,7 @@ impl AbstractTree for ValueNode {
}
}
ValueType::List(expressions)
ValueNode::List(expressions)
}
"table" => {
let identifier_list_node = child.child(1).unwrap();
@ -63,7 +70,7 @@ impl AbstractTree for ValueNode {
let expression_node = child.child(2).unwrap();
let expression = Expression::from_syntax_node(source, expression_node)?;
ValueType::Table {
ValueNode::Table {
column_names,
rows: Box::new(expression),
}
@ -88,9 +95,9 @@ impl AbstractTree for ValueNode {
}
}
ValueType::Map(child_nodes)
ValueNode::Map(child_nodes)
}
"function" => ValueType::Function(Function::from_syntax_node(source, child)?),
"function" => ValueNode::Function(Function::from_syntax_node(source, child)?),
_ => {
return Err(Error::UnexpectedSyntaxNode {
expected:
@ -102,27 +109,19 @@ impl AbstractTree for ValueNode {
}
};
Ok(ValueNode {
value_type,
source: source[child.byte_range()].to_string(),
})
Ok(value_node)
}
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
let value = match &self.value_type {
ValueType::Any => todo!(),
ValueType::String => {
let without_quotes = &self.source[1..self.source.len() - 1];
let value = match self {
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
ValueNode::Float(value_source) => Value::Float(value_source.parse().unwrap()),
ValueNode::Integer(value_source) => Value::Integer(value_source.parse().unwrap()),
ValueNode::String(value_source) => Value::String(value_source.parse().unwrap()),
ValueNode::List(expressions) => {
let mut values = Vec::with_capacity(expressions.len());
Value::String(without_quotes.to_string())
}
ValueType::Float => Value::Float(self.source.parse().unwrap()),
ValueType::Integer => Value::Integer(self.source.parse().unwrap()),
ValueType::Boolean => Value::Boolean(self.source.parse().unwrap()),
ValueType::List(nodes) => {
let mut values = Vec::with_capacity(nodes.len());
for node in nodes {
for node in expressions {
let value = node.run(source, context)?;
values.push(value);
@ -130,15 +129,15 @@ impl AbstractTree for ValueNode {
Value::List(List::with_items(values))
}
ValueType::Empty => Value::Empty,
ValueType::Map(nodes) => {
ValueNode::Empty => Value::Empty,
ValueNode::Map(key_statement_pairs) => {
let map = Map::new();
{
let mut variables = map.variables_mut()?;
for (key, node) in nodes {
let value = node.run(source, context)?;
for (key, statement) in key_statement_pairs {
let value = statement.run(source, context)?;
variables.insert(key.clone(), value);
}
@ -146,7 +145,7 @@ impl AbstractTree for ValueNode {
Value::Map(map)
}
ValueType::Table {
ValueNode::Table {
column_names,
rows: row_expression,
} => {
@ -172,7 +171,7 @@ impl AbstractTree for ValueNode {
Value::Table(table)
}
ValueType::Function(function) => Value::Function(function.clone()),
ValueNode::Function(function) => Value::Function(function.clone()),
};
Ok(value)

View File

@ -3,7 +3,7 @@
//! To deal with errors from dependencies, either create a new error variant
//! or use the ToolFailure variant if the error can only occur inside a tool.
use tree_sitter::Node;
use tree_sitter::{Node, Point};
use crate::{value::Value, Identifier};
@ -16,7 +16,7 @@ pub enum Error {
UnexpectedSyntaxNode {
expected: &'static str,
actual: &'static str,
location: tree_sitter::Point,
location: Point,
relevant_source: String,
},
@ -127,12 +127,23 @@ pub enum Error {
/// A custom error explained by its message.
CustomMessage(String),
/// Invalid user input.
Syntax {
source: String,
location: Point,
},
}
impl Error {
pub fn expect_syntax_node(source: &str, expected: &'static str, actual: Node) -> Result<()> {
if expected == actual.kind() {
Ok(())
} else if actual.is_error() {
Err(Error::Syntax {
source: source[actual.byte_range()].to_string(),
location: actual.start_position(),
})
} else {
Err(Error::UnexpectedSyntaxNode {
expected,
@ -337,6 +348,9 @@ impl fmt::Display for Error {
),
ToolFailure(message) => write!(f, "{message}"),
CustomMessage(message) => write!(f, "{message}"),
Syntax { source, location } => {
write!(f, "Syntax error at {location}, this is not valid: {source}")
}
}
}
}

View File

@ -85,16 +85,18 @@ impl<'c, 's> Evaluator<'c, 's> {
}
pub fn run(self) -> Result<Value> {
let mut cursor = self.syntax_tree.walk();
let root_node = cursor.node();
let mut prev_result = Ok(Value::Empty);
let root_node = self.syntax_tree.root_node();
for statement_node in root_node.children(&mut cursor) {
let mut prev_result = Value::Empty;
for index in 0..root_node.child_count() {
let statement_node = root_node.child(index).unwrap();
let statement = Statement::from_syntax_node(self.source, statement_node)?;
prev_result = statement.run(self.source, self.context);
prev_result = statement.run(self.source, self.context)?;
}
prev_result
Ok(prev_result)
}
pub fn syntax_tree(&self) -> String {

View File

@ -8,7 +8,7 @@ pub use crate::{
abstract_tree::*,
error::*,
evaluator::*,
value::{function::Function, list::List, map::Map, table::Table, value_type::ValueType, Value},
value::{function::Function, list::List, map::Map, table::Table, Value},
};
mod abstract_tree;

View File

@ -56,8 +56,6 @@ impl AbstractTree for Function {
}
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
println!("{self}");
let return_value = self.body.run(source, context)?;
if let Some(r#type) = &self.return_type {

View File

@ -1,7 +1,7 @@
//! Types that represent runtime values.
use crate::{
error::{Error, Result},
Function, List, Map, Table, Type, ValueType,
Function, List, Map, Table, Type,
};
use serde::{
@ -22,7 +22,6 @@ pub mod function;
pub mod list;
pub mod map;
pub mod table;
pub mod value_type;
/// Dust value representation.
///
@ -58,10 +57,6 @@ impl Value {
}
}
pub fn value_type(&self) -> ValueType {
ValueType::from(self)
}
pub fn is_table(&self) -> bool {
matches!(self, Value::Table(_))
}
@ -348,6 +343,17 @@ impl SubAssign for Value {
(Value::Integer(left), Value::Integer(right)) => *left -= right,
(Value::Float(left), Value::Float(right)) => *left -= right,
(Value::Float(left), Value::Integer(right)) => *left -= right as f64,
(Value::List(list), value) => {
let index_to_remove = list
.items()
.iter()
.enumerate()
.find_map(|(i, list_value)| if list_value == &value { Some(i) } else { None });
if let Some(index) = index_to_remove {
list.items_mut().remove(index);
}
}
_ => {}
}
}

View File

@ -1,152 +0,0 @@
use std::{
collections::BTreeMap,
fmt::{self, Debug, Display, Formatter},
};
use serde::{Deserialize, Serialize};
use crate::{value_node::ValueNode, Expression, Function, Identifier, Statement, Value};
/// The type of a `Value`.
#[derive(Clone, Serialize, Deserialize, PartialOrd, Ord)]
pub enum ValueType {
Any,
String,
Float,
Integer,
Boolean,
List(Vec<Expression>),
Empty,
Map(BTreeMap<String, Statement>),
Table {
column_names: Vec<Identifier>,
rows: Box<Expression>,
},
Function(Function),
}
impl Eq for ValueType {}
impl PartialEq for ValueType {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(ValueType::Any, _) => true,
(_, ValueType::Any) => true,
(ValueType::String, ValueType::String) => true,
(ValueType::Float, ValueType::Float) => true,
(ValueType::Integer, ValueType::Integer) => true,
(ValueType::Boolean, ValueType::Boolean) => true,
(ValueType::List(left), ValueType::List(right)) => left == right,
(ValueType::Empty, ValueType::Empty) => true,
(ValueType::Map(left), ValueType::Map(right)) => left == right,
(
ValueType::Table {
column_names: left_columns,
rows: left_rows,
},
ValueType::Table {
column_names: right_columns,
rows: right_rows,
},
) => left_columns == right_columns && left_rows == right_rows,
(ValueType::Function(left), ValueType::Function(right)) => left == right,
_ => false,
}
}
}
impl Display for ValueType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match &self {
ValueType::Any => write!(f, "any"),
ValueType::String => write!(f, "string"),
ValueType::Float => write!(f, "float"),
ValueType::Integer => write!(f, "integer"),
ValueType::Boolean => write!(f, "boolean"),
ValueType::List(list) => {
write!(f, "(")?;
for (index, item) in list.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{item:?}")?;
}
write!(f, ")")
}
ValueType::Empty => write!(f, "empty"),
ValueType::Map(_map) => write!(f, "map"),
ValueType::Table {
column_names: _,
rows: _,
} => {
write!(f, "table")
}
ValueType::Function(function) => write!(f, "{function}"),
}
}
}
impl Debug for ValueType {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self}")
}
}
impl From<&Value> for ValueType {
fn from(value: &Value) -> Self {
match value {
Value::String(_) => ValueType::String,
Value::Float(_) => ValueType::Float,
Value::Integer(_) => ValueType::Integer,
Value::Boolean(_) => ValueType::Boolean,
Value::Empty => ValueType::Empty,
Value::List(list) => {
let value_nodes = list
.items()
.iter()
.map(|value| {
Expression::Value(ValueNode::new(
value.value_type(),
String::with_capacity(0),
))
})
.collect();
ValueType::List(value_nodes)
}
Value::Map(map) => {
let mut value_nodes = BTreeMap::new();
for (key, value) in map.variables().unwrap().iter() {
let value_type = value.value_type();
let value_node = ValueNode::new(value_type, String::with_capacity(0));
let statement = Statement::Expression(Expression::Value(value_node));
value_nodes.insert(key.to_string(), statement);
}
ValueType::Map(value_nodes)
}
Value::Table(table) => ValueType::Table {
column_names: table
.headers()
.iter()
.map(|column_name| Identifier::new(column_name.clone()))
.collect(),
rows: Box::new(Expression::Value(ValueNode::new(
ValueType::List(Vec::with_capacity(0)),
String::with_capacity(0),
))),
},
Value::Function(function) => ValueType::Function(function.clone()),
}
}
}
impl From<&mut Value> for ValueType {
fn from(value: &mut Value) -> Self {
From::<&Value>::from(value)
}
}

View File

@ -276,7 +276,7 @@ module.exports = grammar({
function: $ => seq(
'|',
repeat($._function_parameters),
field('parameters', repeat($._function_parameters)),
'|',
optional(field('return_type', $.type)),
field('body', $.block),