Begin implementing better built-in features

This commit is contained in:
Jeff 2024-08-07 18:24:25 -04:00
parent 06f3a9b746
commit 4d7f59aee2
8 changed files with 482 additions and 119 deletions

View File

@ -5,7 +5,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Identifier, ReservedIdentifier, Type, Value}; use crate::{Identifier, Type, Value};
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct AbstractSyntaxTree<P> { pub struct AbstractSyntaxTree<P> {
@ -40,6 +40,16 @@ pub enum Statement<P> {
// Expressions // Expressions
Add(Box<Node<P>>, Box<Node<P>>), Add(Box<Node<P>>, Box<Node<P>>),
BuiltInFunctionCall {
function: BuiltInFunction,
type_arguments: Option<Vec<Node<P>>>,
value_arguments: Option<Vec<Node<P>>>,
},
FunctionCall {
function: Box<Node<P>>,
type_arguments: Option<Vec<Node<P>>>,
value_arguments: Option<Vec<Node<P>>>,
},
PropertyAccess(Box<Node<P>>, Box<Node<P>>), PropertyAccess(Box<Node<P>>, Box<Node<P>>),
List(Vec<Node<P>>), List(Vec<Node<P>>),
Multiply(Box<Node<P>>, Box<Node<P>>), Multiply(Box<Node<P>>, Box<Node<P>>),
@ -47,7 +57,6 @@ pub enum Statement<P> {
// Hard-coded values // Hard-coded values
Constant(Value), Constant(Value),
Identifier(Identifier), Identifier(Identifier),
ReservedIdentifier(ReservedIdentifier),
} }
impl<P> Statement<P> { impl<P> Statement<P> {
@ -55,17 +64,15 @@ impl<P> Statement<P> {
match self { match self {
Statement::Add(left, _) => left.statement.expected_type(variables), Statement::Add(left, _) => left.statement.expected_type(variables),
Statement::Assign(_, _) => None, Statement::Assign(_, _) => None,
Statement::BuiltInFunctionCall { function, .. } => function.expected_type(),
Statement::Constant(value) => Some(value.r#type(variables)), Statement::Constant(value) => Some(value.r#type(variables)),
Statement::FunctionCall { function, .. } => function.statement.expected_type(variables),
Statement::Identifier(identifier) => variables Statement::Identifier(identifier) => variables
.get(identifier) .get(identifier)
.map(|value| value.r#type(variables)), .map(|value| value.r#type(variables)),
Statement::List(_) => None, Statement::List(_) => None,
Statement::Multiply(left, _) => left.statement.expected_type(variables), Statement::Multiply(left, _) => left.statement.expected_type(variables),
Statement::PropertyAccess(_, _) => None, Statement::PropertyAccess(_, _) => None,
Statement::ReservedIdentifier(reserved) => match reserved {
ReservedIdentifier::IsEven | ReservedIdentifier::IsOdd => Some(Type::Boolean),
ReservedIdentifier::Length => Some(Type::Integer),
},
} }
} }
} }
@ -75,6 +82,76 @@ impl<P> Display for Statement<P> {
match self { match self {
Statement::Assign(left, right) => write!(f, "{left} = {right}"), Statement::Assign(left, right) => write!(f, "{left} = {right}"),
Statement::Add(left, right) => write!(f, "{left} + {right}"), Statement::Add(left, right) => write!(f, "{left} + {right}"),
Statement::BuiltInFunctionCall {
function,
type_arguments: type_parameters,
value_arguments: value_parameters,
} => {
write!(f, "{function}")?;
if let Some(type_parameters) = type_parameters {
write!(f, "<")?;
for (i, type_parameter) in type_parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{type_parameter}")?;
}
write!(f, ">")?;
}
write!(f, "(")?;
if let Some(value_parameters) = value_parameters {
for (i, value_parameter) in value_parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{value_parameter}")?;
}
}
write!(f, ")")
}
Statement::FunctionCall {
function,
type_arguments: type_parameters,
value_arguments: value_parameters,
} => {
write!(f, "{function}")?;
if let Some(type_parameters) = type_parameters {
write!(f, "<")?;
for (i, type_parameter) in type_parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{type_parameter}")?;
}
write!(f, ">")?;
}
write!(f, "(")?;
if let Some(value_parameters) = value_parameters {
for (i, value_parameter) in value_parameters.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{value_parameter}")?;
}
}
write!(f, ")")
}
Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"), Statement::PropertyAccess(left, right) => write!(f, "{left}.{right}"),
Statement::List(nodes) => { Statement::List(nodes) => {
write!(f, "[")?; write!(f, "[")?;
@ -89,7 +166,69 @@ impl<P> Display for Statement<P> {
Statement::Multiply(left, right) => write!(f, "{left} * {right}"), Statement::Multiply(left, right) => write!(f, "{left} * {right}"),
Statement::Constant(value) => write!(f, "{value}"), Statement::Constant(value) => write!(f, "{value}"),
Statement::Identifier(identifier) => write!(f, "{identifier}"), Statement::Identifier(identifier) => write!(f, "{identifier}"),
Statement::ReservedIdentifier(identifier) => write!(f, "{identifier}"),
} }
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInFunction {
IsEven,
IsOdd,
Length,
}
impl BuiltInFunction {
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::IsEven => "is_even",
BuiltInFunction::IsOdd => "is_odd",
BuiltInFunction::Length => "length",
}
}
pub fn call(
&self,
_type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>,
) -> Result<Value, BuiltInFunctionError> {
match self {
BuiltInFunction::IsEven => {
if let Some(value_arguments) = value_arguments {
if value_arguments.len() == 1 {
if let Some(integer) = value_arguments[0].as_integer() {
Ok(Value::boolean(integer % 2 == 0))
} else {
Err(BuiltInFunctionError::ExpectedInteger)
}
} else {
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
}
} else {
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
}
}
BuiltInFunction::IsOdd => todo!(),
BuiltInFunction::Length => todo!(),
}
}
pub fn expected_type(&self) -> Option<Type> {
match self {
BuiltInFunction::IsEven => Some(Type::Boolean),
BuiltInFunction::IsOdd => Some(Type::Boolean),
BuiltInFunction::Length => Some(Type::Integer),
}
}
}
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum BuiltInFunctionError {
ExpectedInteger,
WrongNumberOfValueArguments,
}

View File

@ -103,7 +103,17 @@ impl<'a, P: Clone> Analyzer<'a, P> {
self.analyze_node(right)?; self.analyze_node(right)?;
} }
Statement::BuiltInFunctionCall { .. } => {}
Statement::Constant(_) => {} Statement::Constant(_) => {}
Statement::FunctionCall { function, .. } => {
if let Statement::Identifier(_) = &function.statement {
// Function is in the correct position
} else {
return Err(AnalyzerError::ExpectedIdentifier {
actual: function.as_ref().clone(),
});
}
}
Statement::Identifier(_) => { Statement::Identifier(_) => {
return Err(AnalyzerError::UnexpectedIdentifier { return Err(AnalyzerError::UnexpectedIdentifier {
identifier: node.clone(), identifier: node.clone(),
@ -149,7 +159,6 @@ impl<'a, P: Clone> Analyzer<'a, P> {
self.analyze_node(right)?; self.analyze_node(right)?;
} }
Statement::ReservedIdentifier(_) => {}
} }
Ok(()) Ok(())
@ -158,6 +167,7 @@ impl<'a, P: Clone> Analyzer<'a, P> {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum AnalyzerError<P> { pub enum AnalyzerError<P> {
ExpectedFunction { position: P },
ExpectedIdentifier { actual: Node<P> }, ExpectedIdentifier { actual: Node<P> },
ExpectedIntegerOrFloat { actual: Node<P> }, ExpectedIntegerOrFloat { actual: Node<P> },
UnexpectedIdentifier { identifier: Node<P> }, UnexpectedIdentifier { identifier: Node<P> },

View File

@ -5,7 +5,7 @@
//! - [`Lexer`], which lexes the input a token at a time //! - [`Lexer`], which lexes the input a token at a time
use std::num::{ParseFloatError, ParseIntError}; use std::num::{ParseFloatError, ParseIntError};
use crate::{Identifier, ReservedIdentifier, Span, Token}; use crate::{Identifier, Span, Token};
/// Lexes the input and return a vector of tokens and their positions. /// Lexes the input and return a vector of tokens and their positions.
/// ///
@ -245,9 +245,9 @@ impl<'a> Lexer<'a> {
let token = match string { let token = match string {
"true" => Token::Boolean(true), "true" => Token::Boolean(true),
"false" => Token::Boolean(false), "false" => Token::Boolean(false),
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven), "is_even" => Token::IsEven,
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd), "is_odd" => Token::IsOdd,
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length), "length" => Token::Length,
_ => Token::Identifier(Identifier::new(string)), _ => Token::Identifier(Identifier::new(string)),
}; };
@ -298,19 +298,18 @@ mod tests {
} }
#[test] #[test]
fn integer_property_access() { fn property_access_function_call() {
let input = "42.is_even"; let input = "42.is_even()";
assert_eq!( assert_eq!(
lex(input), lex(input),
Ok(vec![ Ok(vec![
(Token::Integer(42), (0, 2)), (Token::Integer(42), (0, 2)),
(Token::Dot, (2, 3)), (Token::Dot, (2, 3)),
( (Token::IsEven, (3, 10)),
Token::ReservedIdentifier(ReservedIdentifier::IsEven), (Token::LeftParenthesis, (10, 11)),
(3, 10) (Token::RightParenthesis, (11, 12)),
), (Token::Eof, (12, 12)),
(Token::Eof, (10, 10)),
]) ])
) )
} }
@ -328,13 +327,7 @@ mod tests {
assert_eq!( assert_eq!(
lex(input), lex(input),
Ok(vec![ Ok(vec![(Token::Length, (0, 6)), (Token::Eof, (6, 6)),])
(
Token::ReservedIdentifier(ReservedIdentifier::Length),
(0, 6)
),
(Token::Eof, (6, 6)),
])
) )
} }

View File

@ -15,13 +15,13 @@ pub mod r#type;
pub mod value; pub mod value;
pub mod vm; pub mod vm;
pub use abstract_tree::{AbstractSyntaxTree, Node, Statement}; pub use abstract_tree::{AbstractSyntaxTree, BuiltInFunction, Node, Statement};
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lex::{lex, LexError, Lexer}; pub use lex::{lex, LexError, Lexer};
pub use parse::{parse, ParseError, Parser}; pub use parse::{parse, ParseError, Parser};
pub use r#type::Type; pub use r#type::Type;
pub use token::{ReservedIdentifier, Token}; pub use token::Token;
pub use value::{Value, ValueError}; pub use value::{Value, ValueError};
pub use vm::{run, Vm, VmError}; pub use vm::{run, Vm, VmError};

View File

@ -5,7 +5,10 @@
/// - `Parser` struct, which parses the input a statement at a time /// - `Parser` struct, which parses the input a statement at a time
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::{AbstractSyntaxTree, LexError, Lexer, Node, Span, Statement, Token, Value}; use crate::{
abstract_tree::BuiltInFunction, AbstractSyntaxTree, LexError, Lexer, Node, Span, Statement,
Token, Value,
};
/// Parses the input into an abstract syntax tree. /// Parses the input into an abstract syntax tree.
/// ///
@ -206,15 +209,12 @@ impl<'src> Parser<'src> {
(Token::LeftParenthesis, left_span) => { (Token::LeftParenthesis, left_span) => {
self.next_token()?; self.next_token()?;
let instruction = self.parse_node(0)?; let node = self.parse_node(0)?;
if let (Token::RightParenthesis, right_span) = self.current { if let (Token::RightParenthesis, right_span) = self.current {
self.next_token()?; self.next_token()?;
Ok(Node::new( Ok(Node::new(node.statement, (left_span.0, right_span.1)))
instruction.statement,
(left_span.0, right_span.1),
))
} else { } else {
Err(ParseError::ExpectedClosingParenthesis { Err(ParseError::ExpectedClosingParenthesis {
actual: self.current.0.clone(), actual: self.current.0.clone(),
@ -225,14 +225,14 @@ impl<'src> Parser<'src> {
(Token::LeftSquareBrace, left_span) => { (Token::LeftSquareBrace, left_span) => {
self.next_token()?; self.next_token()?;
let mut instructions = Vec::new(); let mut nodes = Vec::new();
loop { loop {
if let (Token::RightSquareBrace, right_span) = self.current { if let (Token::RightSquareBrace, right_span) = self.current {
self.next_token()?; self.next_token()?;
return Ok(Node::new( return Ok(Node::new(
Statement::List(instructions), Statement::List(nodes),
(left_span.0, right_span.1), (left_span.0, right_span.1),
)); ));
} }
@ -244,7 +244,7 @@ impl<'src> Parser<'src> {
} }
if let Ok(instruction) = self.parse_node(0) { if let Ok(instruction) = self.parse_node(0) {
instructions.push(instruction); nodes.push(instruction);
} else { } else {
return Err(ParseError::ExpectedClosingSquareBrace { return Err(ParseError::ExpectedClosingSquareBrace {
actual: self.current.0.clone(), actual: self.current.0.clone(),
@ -253,12 +253,52 @@ impl<'src> Parser<'src> {
} }
} }
} }
(Token::ReservedIdentifier(reserved), _) => { (Token::IsEven, left_span) => {
self.next_token()?; self.next_token()?;
let mut value_parameters = None;
if let (Token::LeftParenthesis, _) = self.current {
self.next_token()?;
value_parameters = Some(vec![self.parse_node(0)?]);
loop {
self.next_token()?;
if let (Token::RightParenthesis, _) = self.current {
break;
}
if let (Token::Comma, _) = self.current {
self.next_token()?;
}
value_parameters.as_mut().unwrap().push(self.parse_node(0)?);
}
} else {
return Err(ParseError::ExpectedOpeningParenthesis {
actual: self.current.0.clone(),
span: self.current.1,
});
}
if let (Token::RightParenthesis, _) = self.current {
self.next_token()?;
} else {
return Err(ParseError::ExpectedClosingParenthesis {
actual: self.current.0.clone(),
span: self.current.1,
});
}
Ok(Node::new( Ok(Node::new(
Statement::ReservedIdentifier(reserved), Statement::BuiltInFunctionCall {
self.current.1, function: BuiltInFunction::IsEven,
type_arguments: None,
value_arguments: value_parameters,
},
left_span,
)) ))
} }
_ => Err(ParseError::UnexpectedToken(self.current.0.clone())), _ => Err(ParseError::UnexpectedToken(self.current.0.clone())),
@ -280,6 +320,7 @@ impl<'src> Parser<'src> {
pub enum ParseError { pub enum ParseError {
ExpectedClosingParenthesis { actual: Token, span: Span }, ExpectedClosingParenthesis { actual: Token, span: Span },
ExpectedClosingSquareBrace { actual: Token, span: Span }, ExpectedClosingSquareBrace { actual: Token, span: Span },
ExpectedOpeningParenthesis { actual: Token, span: Span },
LexError(LexError), LexError(LexError),
UnexpectedToken(Token), UnexpectedToken(Token),
} }
@ -308,6 +349,32 @@ mod tests {
); );
} }
#[test]
fn property_access_function_call() {
let input = "42.is_even()";
assert_eq!(
parse(input),
Ok(AbstractSyntaxTree {
nodes: [Node::new(
Statement::PropertyAccess(
Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))),
Box::new(Node::new(
Statement::BuiltInFunctionCall {
function: BuiltInFunction::IsEven,
type_arguments: None,
value_arguments: None
},
(3, 10)
)),
),
(0, 10),
)]
.into()
})
);
}
#[test] #[test]
fn list_access() { fn list_access() {
let input = "[1, 2, 3].0"; let input = "[1, 2, 3].0";

View File

@ -1,44 +1,57 @@
use std::fmt::Display; use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::Identifier; use crate::Identifier;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum Token { pub enum Token {
Eof,
Identifier(Identifier),
// Hard-coded values
Boolean(bool), Boolean(bool),
Float(f64),
Integer(i64),
// Keywords
IsEven,
IsOdd,
Length,
// Symbols
Comma, Comma,
Dot, Dot,
Eof,
Equal, Equal,
Identifier(Identifier),
ReservedIdentifier(ReservedIdentifier),
Integer(i64),
Plus, Plus,
Star, Star,
LeftParenthesis, LeftParenthesis,
RightParenthesis, RightParenthesis,
LeftSquareBrace, LeftSquareBrace,
RightSquareBrace, RightSquareBrace,
Float(f64),
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] impl Display for Token {
pub enum ReservedIdentifier { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
// Number properties
IsEven,
IsOdd,
// List properties
Length,
}
impl Display for ReservedIdentifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
ReservedIdentifier::IsEven => write!(f, "is_even"), Token::Eof => write!(f, "EOF"),
ReservedIdentifier::IsOdd => write!(f, "is_odd"), Token::Identifier(identifier) => write!(f, "{identifier}"),
ReservedIdentifier::Length => write!(f, "length"), Token::Boolean(boolean) => write!(f, "{boolean}"),
Token::Float(float) => write!(f, "{float}"),
Token::Integer(integer) => write!(f, "{integer}"),
Token::IsEven => write!(f, "is_even"),
Token::IsOdd => write!(f, "is_odd"),
Token::Length => write!(f, "length"),
Token::Comma => write!(f, ","),
Token::Dot => write!(f, "."),
Token::Equal => write!(f, "="),
Token::Plus => write!(f, "+"),
Token::Star => write!(f, "*"),
Token::LeftParenthesis => write!(f, "("),
Token::RightParenthesis => write!(f, ")"),
Token::LeftSquareBrace => write!(f, "["),
Token::RightSquareBrace => write!(f, "]"),
} }
} }
} }

View File

@ -12,7 +12,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Deserialize, Deserializer, Serialize,
}; };
use crate::{identifier::Identifier, Statement, Type}; use crate::{identifier::Identifier, AbstractSyntaxTree, Type, Vm, VmError};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Value(Arc<ValueInner>); pub struct Value(Arc<ValueInner>);
@ -30,6 +30,10 @@ impl Value {
Value(Arc::new(ValueInner::Float(float))) Value(Arc::new(ValueInner::Float(float)))
} }
pub fn function(function: Function) -> Self {
Value(Arc::new(ValueInner::Function(function)))
}
pub fn integer(integer: i64) -> Self { pub fn integer(integer: i64) -> Self {
Value(Arc::new(ValueInner::Integer(integer))) Value(Arc::new(ValueInner::Integer(integer)))
} }
@ -62,6 +66,14 @@ impl Value {
} }
} }
pub fn as_function(&self) -> Option<&Function> {
if let ValueInner::Function(function) = self.0.as_ref() {
Some(function)
} else {
None
}
}
pub fn as_list(&self) -> Option<&Vec<Value>> { pub fn as_list(&self) -> Option<&Vec<Value>> {
if let ValueInner::List(list) = self.inner().as_ref() { if let ValueInner::List(list) = self.inner().as_ref() {
Some(list) Some(list)
@ -539,12 +551,39 @@ pub struct Function {
pub name: Identifier, pub name: Identifier,
pub type_parameters: Option<Vec<Type>>, pub type_parameters: Option<Vec<Type>>,
pub value_parameters: Option<Vec<(Identifier, Type)>>, pub value_parameters: Option<Vec<(Identifier, Type)>>,
pub body: Vec<Statement<()>>, pub body: AbstractSyntaxTree<()>,
} }
impl Function { impl Function {
pub fn call(
self,
type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>,
variables: &HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError<()>> {
let mut new_variables = variables.clone();
if let (Some(value_parameters), Some(value_arguments)) =
(self.value_parameters, value_arguments)
{
for ((identifier, _), value) in value_parameters.into_iter().zip(value_arguments) {
new_variables.insert(identifier, value);
}
}
let mut vm = Vm::new(self.body);
vm.run(&mut new_variables)
}
pub fn return_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> { pub fn return_type(&self, variables: &HashMap<Identifier, Value>) -> Option<Type> {
self.body.last().unwrap().expected_type(variables) self.body
.nodes
.iter()
.last()
.unwrap()
.statement
.expected_type(variables)
} }
} }
@ -580,7 +619,7 @@ impl Display for Function {
write!(f, ") {{")?; write!(f, ") {{")?;
for statement in &self.body { for statement in &self.body.nodes {
write!(f, "{}", statement)?; write!(f, "{}", statement)?;
} }

View File

@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{ use crate::{
parse, AbstractSyntaxTree, Analyzer, AnalyzerError, Identifier, Node, ParseError, abstract_tree::BuiltInFunctionError, parse, AbstractSyntaxTree, Analyzer, AnalyzerError,
ReservedIdentifier, Span, Statement, Value, ValueError, Identifier, Node, ParseError, Span, Statement, Value, ValueError,
}; };
pub fn run( pub fn run(
@ -47,9 +47,6 @@ impl<P: Copy> Vm<P> {
variables: &mut HashMap<Identifier, Value>, variables: &mut HashMap<Identifier, Value>,
) -> Result<Option<Value>, VmError<P>> { ) -> Result<Option<Value>, VmError<P>> {
match node.statement { match node.statement {
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::Identifier(_) => Ok(None),
Statement::ReservedIdentifier(_) => Ok(None),
Statement::Add(left, right) => { Statement::Add(left, right) => {
let left_span = left.position; let left_span = left.position;
let left = if let Some(value) = self.run_node(*left, variables)? { let left = if let Some(value) = self.run_node(*left, variables)? {
@ -92,6 +89,84 @@ impl<P: Copy> Vm<P> {
Ok(None) Ok(None)
} }
Statement::BuiltInFunctionCall {
function,
type_arguments: _,
value_arguments: value_nodes,
} => {
let mut values = if let Some(nodes) = value_nodes {
let mut values = Vec::new();
for node in nodes {
let position = node.position;
let value = if let Some(value) = self.run_node(node, variables)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
values.push(value);
}
Some(values)
} else {
None
};
let function_call_return = function.call(None, values)?;
Ok(Some(function_call_return))
}
Statement::Constant(value) => Ok(Some(value.clone())),
Statement::FunctionCall {
function: function_node,
type_arguments: type_parameter_nodes,
value_arguments: value_parameter_nodes,
} => {
let function_position = function_node.position;
let function_value =
if let Some(value) = self.run_node(*function_node, variables)? {
value
} else {
return Err(VmError::ExpectedValue {
position: function_position,
});
};
let function = if let Some(function) = function_value.as_function() {
function
} else {
return Err(VmError::AnaylyzerError(AnalyzerError::ExpectedFunction {
position: function_position,
}));
};
let value_parameters = if let Some(value_nodes) = value_parameter_nodes {
let mut value_parameters = Vec::new();
for node in value_nodes {
let position = node.position;
let value = if let Some(value) = self.run_node(node, variables)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
value_parameters.push(value);
}
Some(value_parameters)
} else {
None
};
Ok(function
.clone()
.call(None, value_parameters, variables)
.map_err(|error| VmError::FunctionCallFailed {
error: Box::new(error),
position: function_position,
})?)
}
Statement::Identifier(_) => Ok(None),
Statement::List(nodes) => { Statement::List(nodes) => {
let values = nodes let values = nodes
.into_iter() .into_iter()
@ -110,7 +185,7 @@ impl<P: Copy> Vm<P> {
Statement::Multiply(_, _) => todo!(), Statement::Multiply(_, _) => todo!(),
Statement::PropertyAccess(left, right) => { Statement::PropertyAccess(left, right) => {
let left_span = left.position; let left_span = left.position;
let left = if let Some(value) = self.run_node(*left, variables)? { let left_value = if let Some(value) = self.run_node(*left, variables)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
@ -119,39 +194,8 @@ impl<P: Copy> Vm<P> {
}; };
let right_span = right.position; let right_span = right.position;
if let Statement::ReservedIdentifier(reserved) = &right.statement { if let (Some(list), Statement::Constant(value)) =
match reserved { (left_value.as_list(), &right.statement)
ReservedIdentifier::IsEven => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 == 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::IsOdd => {
if let Some(integer) = left.as_integer() {
return Ok(Some(Value::boolean(integer % 2 != 0)));
} else {
return Err(VmError::ExpectedInteger {
position: right_span,
});
}
}
ReservedIdentifier::Length => {
if let Some(list) = left.as_list() {
return Ok(Some(Value::integer(list.len() as i64)));
} else {
return Err(VmError::ExpectedList {
position: right_span,
});
}
}
}
}
if let (Some(list), Statement::Constant(value)) = (left.as_list(), &right.statement)
{ {
if let Some(index) = value.as_integer() { if let Some(index) = value.as_integer() {
let value = list.get(index as usize).cloned(); let value = list.get(index as usize).cloned();
@ -160,6 +204,43 @@ impl<P: Copy> Vm<P> {
} }
} }
if let (
value,
Statement::BuiltInFunctionCall {
function,
type_arguments,
value_arguments: mut value_argument_nodes,
},
) = (left_value, right.statement)
{
if let Some(mut nodes) = value_argument_nodes.take() {
nodes.insert(0, Node::new(Statement::Constant(value), right_span));
}
let value_arguments = if let Some(value_nodes) = value_argument_nodes {
let mut value_arguments = Vec::new();
for node in value_nodes {
let position = node.position;
let value = if let Some(value) = self.run_node(node, variables)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
value_arguments.push(value);
}
Some(value_arguments)
} else {
None
};
let function_call_return = function.call(None, value_arguments)?;
return Ok(Some(function_call_return));
}
Err(VmError::ExpectedIdentifierOrInteger { Err(VmError::ExpectedIdentifierOrInteger {
position: right_span, position: right_span,
}) })
@ -176,11 +257,32 @@ pub enum VmError<P> {
// Anaylsis Failures // Anaylsis Failures
// These should be prevented by running the analyzer before the VM // These should be prevented by running the analyzer before the VM
ExpectedIdentifier { position: P }, BuiltInFunctionCallFailed(BuiltInFunctionError),
ExpectedIdentifierOrInteger { position: P }, ExpectedIdentifier {
ExpectedInteger { position: P }, position: P,
ExpectedList { position: P }, },
ExpectedValue { position: P }, ExpectedIdentifierOrInteger {
position: P,
},
ExpectedInteger {
position: P,
},
ExpectedList {
position: P,
},
ExpectedValue {
position: P,
},
FunctionCallFailed {
error: Box<VmError<()>>,
position: P,
},
}
impl<P> From<BuiltInFunctionError> for VmError<P> {
fn from(v: BuiltInFunctionError) -> Self {
Self::BuiltInFunctionCallFailed(v)
}
} }
impl<P> From<AnalyzerError<P>> for VmError<P> { impl<P> From<AnalyzerError<P>> for VmError<P> {
@ -217,7 +319,7 @@ mod tests {
#[test] #[test]
fn is_even() { fn is_even() {
let input = "42.is_even"; let input = "42.is_even()";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut HashMap::new()),
@ -227,7 +329,7 @@ mod tests {
#[test] #[test]
fn is_odd() { fn is_odd() {
let input = "42.is_odd"; let input = "42.is_odd()";
assert_eq!( assert_eq!(
run(input, &mut HashMap::new()), run(input, &mut HashMap::new()),
@ -235,6 +337,13 @@ mod tests {
); );
} }
#[test]
fn length() {
let input = "[1, 2, 3].length()";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
}
#[test] #[test]
fn list_access() { fn list_access() {
let input = "[1, 2, 3].1"; let input = "[1, 2, 3].1";
@ -242,13 +351,6 @@ mod tests {
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2)))); assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(2))));
} }
#[test]
fn property_access() {
let input = "[1, 2, 3].length";
assert_eq!(run(input, &mut HashMap::new()), Ok(Some(Value::integer(3))));
}
#[test] #[test]
fn add() { fn add() {
let input = "1 + 2"; let input = "1 + 2";