Continue type check implementation
This commit is contained in:
parent
f0635bf330
commit
25852efcd6
@ -4,31 +4,25 @@ all_cards = {
|
||||
weapons = ['Rope' 'Lead_Pipe' 'Knife']
|
||||
}
|
||||
|
||||
is_ready_to_solve = |cards| => {
|
||||
is_ready_to_solve = |cards <map>| <bool> {
|
||||
((length cards:suspects) == 1)
|
||||
&& ((length cards:rooms) == 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)
|
||||
(make_guess current_room cards)
|
||||
cards
|
||||
}
|
||||
|
||||
remove_card = |opponent_card cards| => {
|
||||
remove card from cards:rooms {
|
||||
card == opponent_card
|
||||
}
|
||||
remove card from cards:weapons {
|
||||
card == opponent_card
|
||||
}
|
||||
remove card from cards:suspects {
|
||||
card == opponent_card
|
||||
}
|
||||
}
|
||||
|
||||
make_guess = |current_room cards| => {
|
||||
remove_card = |opponent_card <str>, cards <map>| {
|
||||
cards:rooms -= opponent_card
|
||||
cards:suspects -= opponent_card
|
||||
cards:weapons -= opponent_card
|
||||
}
|
||||
|
||||
make_guess = |current_room <str>, cards <map>| {
|
||||
if (is_ready_to_solve cards) {
|
||||
(output 'It was '
|
||||
+ cards:suspects:0
|
||||
|
@ -1,4 +1,4 @@
|
||||
fib = |i| => {
|
||||
fib = |i <int>| <int> {
|
||||
if i <= 1 {
|
||||
1
|
||||
} else {
|
||||
|
@ -1,13 +1,13 @@
|
||||
1 -> (output)
|
||||
|
||||
add_one = |list| => {
|
||||
new_list = []
|
||||
add_one = |numbers <list>| <list> {
|
||||
new_numbers = []
|
||||
|
||||
for number in list {
|
||||
for number in numbers {
|
||||
new_list += number + 1
|
||||
}
|
||||
|
||||
new_list
|
||||
new_numbers
|
||||
}
|
||||
|
||||
foo = [1, 2, 3] -> (add_one)
|
||||
|
@ -86,26 +86,8 @@ impl AbstractTree for Assignment {
|
||||
AssignmentOperator::Equal => value,
|
||||
};
|
||||
|
||||
let expected_type = self.r#type.as_ref().unwrap_or(&Type::Any);
|
||||
|
||||
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 }),
|
||||
if let Some(r#type) = &self.r#type {
|
||||
r#type.check(&new_value)?;
|
||||
}
|
||||
|
||||
context.variables_mut()?.insert(key, new_value);
|
||||
|
@ -50,7 +50,7 @@ impl AbstractTree for FunctionCall {
|
||||
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()) {
|
||||
value.as_function().cloned()
|
||||
} else {
|
||||
@ -63,19 +63,17 @@ impl AbstractTree for FunctionCall {
|
||||
}?;
|
||||
|
||||
let mut function_context = Map::clone_from(context)?;
|
||||
let parameter_expression_pairs = function.parameters().iter().zip(arguments.iter());
|
||||
|
||||
if let Some(parameters) = definition.identifiers() {
|
||||
let parameter_expression_pairs = parameters.iter().zip(arguments.iter());
|
||||
let mut variables = function_context.variables_mut()?;
|
||||
for ((identifier, r#type), expression) in parameter_expression_pairs {
|
||||
let key = identifier.clone().take_inner();
|
||||
let value = expression.run(source, context)?;
|
||||
|
||||
for ((identifier, _type), expression) in parameter_expression_pairs {
|
||||
let key = identifier.clone().take_inner();
|
||||
let value = expression.run(source, context)?;
|
||||
r#type.check(&value)?;
|
||||
|
||||
variables.insert(key, value);
|
||||
}
|
||||
function_context.variables_mut()?.insert(key, value);
|
||||
}
|
||||
|
||||
definition.body().run(source, &mut function_context)
|
||||
function.run(source, &mut function_context)
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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);
|
||||
}
|
||||
|
@ -16,6 +16,46 @@ pub enum Type {
|
||||
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 {
|
||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||
Error::expect_syntax_node(source, "type", node)?;
|
||||
@ -30,7 +70,7 @@ impl AbstractTree for Type {
|
||||
"int" => Type::Integer,
|
||||
"list" => Type::List,
|
||||
"map" => Type::Map,
|
||||
"string" => Type::String,
|
||||
"str" => Type::String,
|
||||
"table" => Type::Table,
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
|
@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize};
|
||||
use tree_sitter::Node;
|
||||
|
||||
use crate::{
|
||||
AbstractTree, Block, Error, Expression, Function, Identifier, List, Map, Result, Statement,
|
||||
Table, Type, Value, ValueType,
|
||||
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
|
||||
Value, ValueType,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
@ -90,39 +90,7 @@ impl AbstractTree for ValueNode {
|
||||
|
||||
ValueType::Map(child_nodes)
|
||||
}
|
||||
"function" => {
|
||||
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))
|
||||
}
|
||||
"function" => ValueType::Function(Function::from_syntax_node(source, child)?),
|
||||
_ => {
|
||||
return Err(Error::UnexpectedSyntaxNode {
|
||||
expected:
|
||||
|
@ -257,7 +257,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
evaluate(
|
||||
"
|
||||
foobar = |message| => { message }
|
||||
foobar = |message <str>| <str> { message }
|
||||
(foobar 'Hiya')
|
||||
",
|
||||
),
|
||||
|
@ -1,29 +1,74 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
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)]
|
||||
pub struct Function {
|
||||
parameters: Option<Vec<(Identifier, Type)>>,
|
||||
body: Box<Block>,
|
||||
parameters: Vec<(Identifier, Type)>,
|
||||
return_type: Option<Type>,
|
||||
body: Block,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(parameters: Option<Vec<(Identifier, Type)>>, body: Block) -> Self {
|
||||
Function {
|
||||
parameters,
|
||||
body: Box::new(body),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn identifiers(&self) -> &Option<Vec<(Identifier, Type)>> {
|
||||
pub fn parameters(&self) -> &Vec<(Identifier, Type)> {
|
||||
&self.parameters
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body(&self) -> &Block {
|
||||
&self.body
|
||||
impl AbstractTree for Function {
|
||||
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 {
|
||||
write!(
|
||||
f,
|
||||
"function < {:?} > {{ {:?} }}", // TODO: Correct this output
|
||||
self.parameters, self.body
|
||||
"Function {{ parameters: {:?}, return_type: {:?}, body: {:?} }}",
|
||||
self.parameters, self.return_type, self.body
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
Simple Function
|
||||
================================================================================
|
||||
|
||||
=> { "Hiya" }
|
||||
|| <str> { "Hiya" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -11,6 +11,7 @@ Simple Function
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type)
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
@ -21,7 +22,7 @@ Simple Function
|
||||
Function Assignment
|
||||
================================================================================
|
||||
|
||||
x = => { "Hiya" }
|
||||
x = || <str> { "Hiya" }
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -34,6 +35,7 @@ x = => { "Hiya" }
|
||||
(expression
|
||||
(value
|
||||
(function
|
||||
(type)
|
||||
(block
|
||||
(statement
|
||||
(expression
|
||||
@ -62,7 +64,7 @@ Function Call
|
||||
Complex Function
|
||||
================================================================================
|
||||
|
||||
|message <str> number <int>| => {
|
||||
|message <str> number <int>| {
|
||||
(output message)
|
||||
(output number)
|
||||
}
|
||||
|
@ -275,19 +275,19 @@ module.exports = grammar({
|
||||
),
|
||||
|
||||
function: $ => seq(
|
||||
optional(seq(
|
||||
'|',
|
||||
field('parameter', repeat(seq(
|
||||
$.identifier,
|
||||
$.type,
|
||||
optional(',')
|
||||
))),
|
||||
'|',
|
||||
)),
|
||||
'=>',
|
||||
'|',
|
||||
repeat($._function_parameters),
|
||||
'|',
|
||||
optional(field('return_type', $.type)),
|
||||
field('body', $.block),
|
||||
),
|
||||
|
||||
_function_parameters: $ => seq(
|
||||
$.identifier,
|
||||
$.type,
|
||||
optional(','),
|
||||
),
|
||||
|
||||
function_call: $ => prec.right(1, seq(
|
||||
'(',
|
||||
choice(
|
||||
|
@ -1158,63 +1158,37 @@
|
||||
"function": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "_function_parameters"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "parameter",
|
||||
"content": {
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
}
|
||||
]
|
||||
"type": "FIELD",
|
||||
"name": "return_type",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "=>"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "body",
|
||||
@ -1225,6 +1199,31 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"_function_parameters": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"function_call": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 1,
|
||||
|
@ -195,24 +195,30 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"parameter": {
|
||||
"multiple": true,
|
||||
"return_type": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": ",",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "identifier",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user