1
0

Continue type check implementation

This commit is contained in:
Jeff 2023-11-27 15:02:08 -05:00
parent f0635bf330
commit 25852efcd6
15 changed files with 11706 additions and 15398 deletions

View File

@ -4,31 +4,25 @@ all_cards = {
weapons = ['Rope' 'Lead_Pipe' 'Knife'] weapons = ['Rope' 'Lead_Pipe' 'Knife']
} }
is_ready_to_solve = |cards| => { is_ready_to_solve = |cards <map>| <bool> {
((length cards:suspects) == 1) ((length cards:suspects) == 1)
&& ((length cards:rooms) == 1) && ((length cards:rooms) == 1)
&& ((length cards:weapons) == 1) && ((length cards:weapons) == 1)
} }
take_turn = |opponent_card, current_room, cards| => { take_turn = |opponent_card <str>, current_room <str>, cards <map>| <map> {
(remove_card opponent_card cards) (remove_card opponent_card cards)
(make_guess current_room cards) (make_guess current_room cards)
cards cards
} }
remove_card = |opponent_card cards| => { remove_card = |opponent_card <str>, cards <map>| {
remove card from cards:rooms { cards:rooms -= opponent_card
card == opponent_card cards:suspects -= opponent_card
} cards:weapons -= opponent_card
remove card from cards:weapons {
card == opponent_card
}
remove card from cards:suspects {
card == opponent_card
}
} }
make_guess = |current_room cards| => { make_guess = |current_room <str>, cards <map>| {
if (is_ready_to_solve cards) { if (is_ready_to_solve cards) {
(output 'It was ' (output 'It was '
+ cards:suspects:0 + cards:suspects:0

View File

@ -1,4 +1,4 @@
fib = |i| => { fib = |i <int>| <int> {
if i <= 1 { if i <= 1 {
1 1
} else { } else {

View File

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

View File

@ -86,26 +86,8 @@ impl AbstractTree for Assignment {
AssignmentOperator::Equal => value, AssignmentOperator::Equal => value,
}; };
let expected_type = self.r#type.as_ref().unwrap_or(&Type::Any); if let Some(r#type) = &self.r#type {
r#type.check(&new_value)?;
match (expected_type, new_value.r#type()) {
(Type::Any, _)
| (Type::Boolean, Type::Boolean)
| (Type::Float, Type::Float)
| (Type::Function, Type::Function)
| (Type::Integer, Type::Integer)
| (Type::List, Type::List)
| (Type::Map, Type::Map)
| (Type::String, Type::String)
| (Type::Table, Type::Table) => {}
(Type::Boolean, _) => return Err(Error::ExpectedBoolean { actual: new_value }),
(Type::Float, _) => return Err(Error::ExpectedFloat { actual: new_value }),
(Type::Function, _) => return Err(Error::ExpectedFunction { actual: new_value }),
(Type::Integer, _) => return Err(Error::ExpectedInteger { actual: new_value }),
(Type::List, _) => return Err(Error::ExpectedList { actual: new_value }),
(Type::Map, _) => return Err(Error::ExpectedMap { actual: new_value }),
(Type::String, _) => return Err(Error::ExpectedString { actual: new_value }),
(Type::Table, _) => return Err(Error::ExpectedTable { actual: new_value }),
} }
context.variables_mut()?.insert(key, new_value); context.variables_mut()?.insert(key, new_value);

View File

@ -50,7 +50,7 @@ impl AbstractTree for FunctionCall {
FunctionCall::ContextDefined { name, arguments } => (name, arguments), FunctionCall::ContextDefined { name, arguments } => (name, arguments),
}; };
let definition = if let Expression::Identifier(identifier) = name { let function = if let Expression::Identifier(identifier) = name {
if let Some(value) = context.variables()?.get(identifier.inner()) { if let Some(value) = context.variables()?.get(identifier.inner()) {
value.as_function().cloned() value.as_function().cloned()
} else { } else {
@ -63,19 +63,17 @@ impl AbstractTree for FunctionCall {
}?; }?;
let mut function_context = Map::clone_from(context)?; let mut function_context = Map::clone_from(context)?;
let parameter_expression_pairs = function.parameters().iter().zip(arguments.iter());
if let Some(parameters) = definition.identifiers() { for ((identifier, r#type), expression) in parameter_expression_pairs {
let parameter_expression_pairs = parameters.iter().zip(arguments.iter());
let mut variables = function_context.variables_mut()?;
for ((identifier, _type), expression) in parameter_expression_pairs {
let key = identifier.clone().take_inner(); let key = identifier.clone().take_inner();
let value = expression.run(source, context)?; let value = expression.run(source, context)?;
variables.insert(key, value); r#type.check(&value)?;
}
function_context.variables_mut()?.insert(key, value);
} }
definition.body().run(source, &mut function_context) function.run(source, &mut function_context)
} }
} }

View File

@ -96,7 +96,7 @@ mod tests {
#[test] #[test]
fn evaluate_complex_index() { fn evaluate_complex_index() {
let test = evaluate("x = [1 2 3]; y = || => {0}; x:((y));").unwrap(); let test = evaluate("x = [1 2 3]; y = || <int> { 0 } x:((y))").unwrap();
assert_eq!(Value::Integer(1), test); assert_eq!(Value::Integer(1), test);
} }

View File

@ -16,6 +16,46 @@ pub enum Type {
Table, Table,
} }
impl Type {
pub fn check(&self, value: &Value) -> Result<()> {
match (self, value.r#type()) {
(Type::Any, _)
| (Type::Boolean, Type::Boolean)
| (Type::Float, Type::Float)
| (Type::Function, Type::Function)
| (Type::Integer, Type::Integer)
| (Type::List, Type::List)
| (Type::Map, Type::Map)
| (Type::String, Type::String)
| (Type::Table, Type::Table) => Ok(()),
(Type::Boolean, _) => Err(Error::ExpectedBoolean {
actual: value.clone(),
}),
(Type::Float, _) => Err(Error::ExpectedFloat {
actual: value.clone(),
}),
(Type::Function, _) => Err(Error::ExpectedFunction {
actual: value.clone(),
}),
(Type::Integer, _) => Err(Error::ExpectedInteger {
actual: value.clone(),
}),
(Type::List, _) => Err(Error::ExpectedList {
actual: value.clone(),
}),
(Type::Map, _) => Err(Error::ExpectedMap {
actual: value.clone(),
}),
(Type::String, _) => Err(Error::ExpectedString {
actual: value.clone(),
}),
(Type::Table, _) => Err(Error::ExpectedTable {
actual: value.clone(),
}),
}
}
}
impl AbstractTree for Type { impl AbstractTree for Type {
fn from_syntax_node(source: &str, node: Node) -> Result<Self> { fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
Error::expect_syntax_node(source, "type", node)?; Error::expect_syntax_node(source, "type", node)?;
@ -30,7 +70,7 @@ impl AbstractTree for Type {
"int" => Type::Integer, "int" => Type::Integer,
"list" => Type::List, "list" => Type::List,
"map" => Type::Map, "map" => Type::Map,
"string" => Type::String, "str" => Type::String,
"table" => Type::Table, "table" => Type::Table,
_ => { _ => {
return Err(Error::UnexpectedSyntaxNode { return Err(Error::UnexpectedSyntaxNode {

View File

@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
AbstractTree, Block, Error, Expression, Function, Identifier, List, Map, Result, Statement, AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
Table, Type, Value, ValueType, Value, ValueType,
}; };
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
@ -90,39 +90,7 @@ impl AbstractTree for ValueNode {
ValueType::Map(child_nodes) ValueType::Map(child_nodes)
} }
"function" => { "function" => ValueType::Function(Function::from_syntax_node(source, child)?),
let mut parameter_list = Vec::new();
let mut index = 0;
while index < node.child_count() {
let current_node = node.child(index).unwrap();
let next_node = node.child(index + 1);
if current_node.kind() == "identifier" {
let parameter = Identifier::from_syntax_node(source, current_node)?;
if let Some(next_node) = next_node {
if next_node.kind() == "type_definition" {
let r#type = Type::from_syntax_node(source, next_node)?;
parameter_list.push((parameter, r#type));
}
}
}
index += 2
}
let body_node = child.child_by_field_name("body").unwrap();
let body = Block::from_syntax_node(source, body_node)?;
let parameters = if parameter_list.is_empty() {
None
} else {
Some(parameter_list)
};
ValueType::Function(Function::new(parameters, body))
}
_ => { _ => {
return Err(Error::UnexpectedSyntaxNode { return Err(Error::UnexpectedSyntaxNode {
expected: expected:

View File

@ -257,7 +257,7 @@ mod tests {
assert_eq!( assert_eq!(
evaluate( evaluate(
" "
foobar = |message| => { message } foobar = |message <str>| <str> { message }
(foobar 'Hiya') (foobar 'Hiya')
", ",
), ),

View File

@ -1,29 +1,74 @@
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::{Block, Identifier, Type}; use crate::{AbstractTree, Block, Error, Identifier, Map, Result, Type, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Function { pub struct Function {
parameters: Option<Vec<(Identifier, Type)>>, parameters: Vec<(Identifier, Type)>,
body: Box<Block>, return_type: Option<Type>,
body: Block,
} }
impl Function { impl Function {
pub fn new(parameters: Option<Vec<(Identifier, Type)>>, body: Block) -> Self { pub fn parameters(&self) -> &Vec<(Identifier, Type)> {
Function {
parameters,
body: Box::new(body),
}
}
pub fn identifiers(&self) -> &Option<Vec<(Identifier, Type)>> {
&self.parameters &self.parameters
} }
}
pub fn body(&self) -> &Block { impl AbstractTree for Function {
&self.body fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
let mut parameters = Vec::new();
let mut previous_identifier = None;
for index in 1..node.child_count() - 2 {
let child = node.child(index).unwrap();
if child.kind() == "identifier" {
previous_identifier = Some(Identifier::from_syntax_node(source, child)?);
}
if child.kind() == "type" {
let identifier = previous_identifier.take().unwrap();
let r#type = Type::from_syntax_node(source, child)?;
parameters.push((identifier, r#type))
}
}
let return_type_node = node.child_by_field_name("return_type");
let return_type = if let Some(child) = return_type_node {
Some(Type::from_syntax_node(source, child)?)
} else {
None
};
let body_node = node.child_by_field_name("body").unwrap();
let body = Block::from_syntax_node(source, body_node)?;
Ok(Function {
parameters,
return_type,
body,
})
}
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 {
r#type.check(&return_value)?;
} else if !return_value.is_empty() {
return Err(Error::ExpectedEmpty {
actual: return_value.clone(),
});
}
Ok(return_value)
} }
} }
@ -31,8 +76,8 @@ impl Display for Function {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!( write!(
f, f,
"function < {:?} > {{ {:?} }}", // TODO: Correct this output "Function {{ parameters: {:?}, return_type: {:?}, body: {:?} }}",
self.parameters, self.body self.parameters, self.return_type, self.body
) )
} }
} }

View File

@ -2,7 +2,7 @@
Simple Function Simple Function
================================================================================ ================================================================================
=> { "Hiya" } || <str> { "Hiya" }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -11,6 +11,7 @@ Simple Function
(expression (expression
(value (value
(function (function
(type)
(block (block
(statement (statement
(expression (expression
@ -21,7 +22,7 @@ Simple Function
Function Assignment Function Assignment
================================================================================ ================================================================================
x = => { "Hiya" } x = || <str> { "Hiya" }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -34,6 +35,7 @@ x = => { "Hiya" }
(expression (expression
(value (value
(function (function
(type)
(block (block
(statement (statement
(expression (expression
@ -62,7 +64,7 @@ Function Call
Complex Function Complex Function
================================================================================ ================================================================================
|message <str> number <int>| => { |message <str> number <int>| {
(output message) (output message)
(output number) (output number)
} }

View File

@ -275,17 +275,17 @@ module.exports = grammar({
), ),
function: $ => seq( function: $ => seq(
optional(seq(
'|', '|',
field('parameter', repeat(seq( repeat($._function_parameters),
'|',
optional(field('return_type', $.type)),
field('body', $.block),
),
_function_parameters: $ => seq(
$.identifier, $.identifier,
$.type, $.type,
optional(',') optional(','),
))),
'|',
)),
'=>',
field('body', $.block),
), ),
function_call: $ => prec.right(1, seq( function_call: $ => prec.right(1, seq(

View File

@ -1159,21 +1159,47 @@
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{ {
"type": "CHOICE", "type": "STRING",
"members": [ "value": "|"
},
{ {
"type": "SEQ", "type": "REPEAT",
"members": [ "content": {
"type": "SYMBOL",
"name": "_function_parameters"
}
},
{ {
"type": "STRING", "type": "STRING",
"value": "|" "value": "|"
}, },
{
"type": "CHOICE",
"members": [
{ {
"type": "FIELD", "type": "FIELD",
"name": "parameter", "name": "return_type",
"content": { "content": {
"type": "REPEAT", "type": "SYMBOL",
"name": "type"
}
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "body",
"content": { "content": {
"type": "SYMBOL",
"name": "block"
}
}
]
},
"_function_parameters": {
"type": "SEQ", "type": "SEQ",
"members": [ "members": [
{ {
@ -1197,33 +1223,6 @@
] ]
} }
] ]
}
}
},
{
"type": "STRING",
"value": "|"
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "=>"
},
{
"type": "FIELD",
"name": "body",
"content": {
"type": "SYMBOL",
"name": "block"
}
}
]
}, },
"function_call": { "function_call": {
"type": "PREC_RIGHT", "type": "PREC_RIGHT",

View File

@ -195,14 +195,21 @@
} }
] ]
}, },
"parameter": { "return_type": {
"multiple": true, "multiple": false,
"required": false, "required": false,
"types": [ "types": [
{ {
"type": ",", "type": "type",
"named": false "named": true
}
]
}
}, },
"children": {
"multiple": true,
"required": false,
"types": [
{ {
"type": "identifier", "type": "identifier",
"named": true "named": true
@ -213,7 +220,6 @@
} }
] ]
} }
}
}, },
{ {
"type": "function_call", "type": "function_call",

File diff suppressed because it is too large Load Diff