Compare commits
3 Commits
06f3a9b746
...
285e9e7217
Author | SHA1 | Date | |
---|---|---|---|
285e9e7217 | |||
b17da5ad3c | |||
4d7f59aee2 |
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Identifier, ReservedIdentifier, Type, Value};
|
||||
use crate::{Identifier, Type, Value};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct AbstractSyntaxTree<P> {
|
||||
@ -40,6 +40,16 @@ pub enum Statement<P> {
|
||||
|
||||
// Expressions
|
||||
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>>),
|
||||
List(Vec<Node<P>>),
|
||||
Multiply(Box<Node<P>>, Box<Node<P>>),
|
||||
@ -47,7 +57,6 @@ pub enum Statement<P> {
|
||||
// Hard-coded values
|
||||
Constant(Value),
|
||||
Identifier(Identifier),
|
||||
ReservedIdentifier(ReservedIdentifier),
|
||||
}
|
||||
|
||||
impl<P> Statement<P> {
|
||||
@ -55,17 +64,15 @@ impl<P> Statement<P> {
|
||||
match self {
|
||||
Statement::Add(left, _) => left.statement.expected_type(variables),
|
||||
Statement::Assign(_, _) => None,
|
||||
Statement::BuiltInFunctionCall { function, .. } => function.expected_type(),
|
||||
Statement::Constant(value) => Some(value.r#type(variables)),
|
||||
Statement::FunctionCall { function, .. } => function.statement.expected_type(variables),
|
||||
Statement::Identifier(identifier) => variables
|
||||
.get(identifier)
|
||||
.map(|value| value.r#type(variables)),
|
||||
Statement::List(_) => None,
|
||||
Statement::Multiply(left, _) => left.statement.expected_type(variables),
|
||||
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 {
|
||||
Statement::Assign(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::List(nodes) => {
|
||||
write!(f, "[")?;
|
||||
@ -89,7 +166,97 @@ impl<P> Display for Statement<P> {
|
||||
Statement::Multiply(left, right) => write!(f, "{left} * {right}"),
|
||||
Statement::Constant(value) => write!(f, "{value}"),
|
||||
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 => {
|
||||
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::Length => {
|
||||
if let Some(value_arguments) = value_arguments {
|
||||
if value_arguments.len() == 1 {
|
||||
if let Some(list) = value_arguments[0].as_list() {
|
||||
Ok(Value::integer(list.len() as i64))
|
||||
} else {
|
||||
Err(BuiltInFunctionError::ExpectedInteger)
|
||||
}
|
||||
} else {
|
||||
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
||||
}
|
||||
} else {
|
||||
Err(BuiltInFunctionError::WrongNumberOfValueArguments)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
@ -103,7 +103,17 @@ impl<'a, P: Clone> Analyzer<'a, P> {
|
||||
|
||||
self.analyze_node(right)?;
|
||||
}
|
||||
Statement::BuiltInFunctionCall { .. } => {}
|
||||
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(_) => {
|
||||
return Err(AnalyzerError::UnexpectedIdentifier {
|
||||
identifier: node.clone(),
|
||||
@ -149,7 +159,6 @@ impl<'a, P: Clone> Analyzer<'a, P> {
|
||||
|
||||
self.analyze_node(right)?;
|
||||
}
|
||||
Statement::ReservedIdentifier(_) => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -158,6 +167,7 @@ impl<'a, P: Clone> Analyzer<'a, P> {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AnalyzerError<P> {
|
||||
ExpectedFunction { position: P },
|
||||
ExpectedIdentifier { actual: Node<P> },
|
||||
ExpectedIntegerOrFloat { actual: Node<P> },
|
||||
UnexpectedIdentifier { identifier: Node<P> },
|
||||
|
@ -5,7 +5,7 @@
|
||||
//! - [`Lexer`], which lexes the input a token at a time
|
||||
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.
|
||||
///
|
||||
@ -245,9 +245,9 @@ impl<'a> Lexer<'a> {
|
||||
let token = match string {
|
||||
"true" => Token::Boolean(true),
|
||||
"false" => Token::Boolean(false),
|
||||
"is_even" => Token::ReservedIdentifier(ReservedIdentifier::IsEven),
|
||||
"is_odd" => Token::ReservedIdentifier(ReservedIdentifier::IsOdd),
|
||||
"length" => Token::ReservedIdentifier(ReservedIdentifier::Length),
|
||||
"is_even" => Token::IsEven,
|
||||
"is_odd" => Token::IsOdd,
|
||||
"length" => Token::Length,
|
||||
_ => Token::Identifier(Identifier::new(string)),
|
||||
};
|
||||
|
||||
@ -298,19 +298,18 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_property_access() {
|
||||
let input = "42.is_even";
|
||||
fn property_access_function_call() {
|
||||
let input = "42.is_even()";
|
||||
|
||||
assert_eq!(
|
||||
lex(input),
|
||||
Ok(vec![
|
||||
(Token::Integer(42), (0, 2)),
|
||||
(Token::Dot, (2, 3)),
|
||||
(
|
||||
Token::ReservedIdentifier(ReservedIdentifier::IsEven),
|
||||
(3, 10)
|
||||
),
|
||||
(Token::Eof, (10, 10)),
|
||||
(Token::IsEven, (3, 10)),
|
||||
(Token::LeftParenthesis, (10, 11)),
|
||||
(Token::RightParenthesis, (11, 12)),
|
||||
(Token::Eof, (12, 12)),
|
||||
])
|
||||
)
|
||||
}
|
||||
@ -328,13 +327,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
lex(input),
|
||||
Ok(vec![
|
||||
(
|
||||
Token::ReservedIdentifier(ReservedIdentifier::Length),
|
||||
(0, 6)
|
||||
),
|
||||
(Token::Eof, (6, 6)),
|
||||
])
|
||||
Ok(vec![(Token::Length, (0, 6)), (Token::Eof, (6, 6)),])
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,13 @@ pub mod r#type;
|
||||
pub mod value;
|
||||
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 identifier::Identifier;
|
||||
pub use lex::{lex, LexError, Lexer};
|
||||
pub use parse::{parse, ParseError, Parser};
|
||||
pub use r#type::Type;
|
||||
pub use token::{ReservedIdentifier, Token};
|
||||
pub use token::Token;
|
||||
pub use value::{Value, ValueError};
|
||||
pub use vm::{run, Vm, VmError};
|
||||
|
||||
|
@ -5,7 +5,10 @@
|
||||
/// - `Parser` struct, which parses the input a statement at a time
|
||||
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.
|
||||
///
|
||||
@ -206,15 +209,12 @@ impl<'src> Parser<'src> {
|
||||
(Token::LeftParenthesis, left_span) => {
|
||||
self.next_token()?;
|
||||
|
||||
let instruction = self.parse_node(0)?;
|
||||
let node = self.parse_node(0)?;
|
||||
|
||||
if let (Token::RightParenthesis, right_span) = self.current {
|
||||
self.next_token()?;
|
||||
|
||||
Ok(Node::new(
|
||||
instruction.statement,
|
||||
(left_span.0, right_span.1),
|
||||
))
|
||||
Ok(Node::new(node.statement, (left_span.0, right_span.1)))
|
||||
} else {
|
||||
Err(ParseError::ExpectedClosingParenthesis {
|
||||
actual: self.current.0.clone(),
|
||||
@ -225,14 +225,14 @@ impl<'src> Parser<'src> {
|
||||
(Token::LeftSquareBrace, left_span) => {
|
||||
self.next_token()?;
|
||||
|
||||
let mut instructions = Vec::new();
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
loop {
|
||||
if let (Token::RightSquareBrace, right_span) = self.current {
|
||||
self.next_token()?;
|
||||
|
||||
return Ok(Node::new(
|
||||
Statement::List(instructions),
|
||||
Statement::List(nodes),
|
||||
(left_span.0, right_span.1),
|
||||
));
|
||||
}
|
||||
@ -244,7 +244,7 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
if let Ok(instruction) = self.parse_node(0) {
|
||||
instructions.push(instruction);
|
||||
nodes.push(instruction);
|
||||
} else {
|
||||
return Err(ParseError::ExpectedClosingSquareBrace {
|
||||
actual: self.current.0.clone(),
|
||||
@ -253,12 +253,94 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
}
|
||||
(Token::ReservedIdentifier(reserved), _) => {
|
||||
(Token::IsEven, left_span) => {
|
||||
self.next_token()?;
|
||||
|
||||
if let (Token::LeftParenthesis, _) = self.current {
|
||||
self.next_token()?;
|
||||
} 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(
|
||||
Statement::ReservedIdentifier(reserved),
|
||||
self.current.1,
|
||||
Statement::BuiltInFunctionCall {
|
||||
function: BuiltInFunction::IsEven,
|
||||
type_arguments: None,
|
||||
value_arguments: None,
|
||||
},
|
||||
left_span,
|
||||
))
|
||||
}
|
||||
(Token::IsOdd, left_span) => {
|
||||
self.next_token()?;
|
||||
|
||||
if let (Token::LeftParenthesis, _) = self.current {
|
||||
self.next_token()?;
|
||||
} 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(
|
||||
Statement::BuiltInFunctionCall {
|
||||
function: BuiltInFunction::IsOdd,
|
||||
type_arguments: None,
|
||||
value_arguments: None,
|
||||
},
|
||||
left_span,
|
||||
))
|
||||
}
|
||||
(Token::Length, left_span) => {
|
||||
self.next_token()?;
|
||||
|
||||
if let (Token::LeftParenthesis, _) = self.current {
|
||||
self.next_token()?;
|
||||
} 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(
|
||||
Statement::BuiltInFunctionCall {
|
||||
function: BuiltInFunction::Length,
|
||||
type_arguments: None,
|
||||
value_arguments: None,
|
||||
},
|
||||
left_span,
|
||||
))
|
||||
}
|
||||
_ => Err(ParseError::UnexpectedToken(self.current.0.clone())),
|
||||
@ -280,6 +362,7 @@ impl<'src> Parser<'src> {
|
||||
pub enum ParseError {
|
||||
ExpectedClosingParenthesis { actual: Token, span: Span },
|
||||
ExpectedClosingSquareBrace { actual: Token, span: Span },
|
||||
ExpectedOpeningParenthesis { actual: Token, span: Span },
|
||||
LexError(LexError),
|
||||
UnexpectedToken(Token),
|
||||
}
|
||||
@ -308,6 +391,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]
|
||||
fn list_access() {
|
||||
let input = "[1, 2, 3].0";
|
||||
|
@ -1,44 +1,57 @@
|
||||
use std::fmt::Display;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Identifier;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
pub enum Token {
|
||||
Eof,
|
||||
|
||||
Identifier(Identifier),
|
||||
|
||||
// Hard-coded values
|
||||
Boolean(bool),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
|
||||
// Keywords
|
||||
IsEven,
|
||||
IsOdd,
|
||||
Length,
|
||||
|
||||
// Symbols
|
||||
Comma,
|
||||
Dot,
|
||||
Eof,
|
||||
Equal,
|
||||
Identifier(Identifier),
|
||||
ReservedIdentifier(ReservedIdentifier),
|
||||
Integer(i64),
|
||||
Plus,
|
||||
Star,
|
||||
LeftParenthesis,
|
||||
RightParenthesis,
|
||||
LeftSquareBrace,
|
||||
RightSquareBrace,
|
||||
Float(f64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum ReservedIdentifier {
|
||||
// Number properties
|
||||
IsEven,
|
||||
IsOdd,
|
||||
|
||||
// List properties
|
||||
Length,
|
||||
}
|
||||
|
||||
impl Display for ReservedIdentifier {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl Display for Token {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ReservedIdentifier::IsEven => write!(f, "is_even"),
|
||||
ReservedIdentifier::IsOdd => write!(f, "is_odd"),
|
||||
ReservedIdentifier::Length => write!(f, "length"),
|
||||
Token::Eof => write!(f, "EOF"),
|
||||
Token::Identifier(identifier) => write!(f, "{identifier}"),
|
||||
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, "]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use serde::{
|
||||
Deserialize, Deserializer, Serialize,
|
||||
};
|
||||
|
||||
use crate::{identifier::Identifier, Statement, Type};
|
||||
use crate::{identifier::Identifier, AbstractSyntaxTree, Type, Vm, VmError};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Value(Arc<ValueInner>);
|
||||
@ -30,6 +30,10 @@ impl Value {
|
||||
Value(Arc::new(ValueInner::Float(float)))
|
||||
}
|
||||
|
||||
pub fn function(function: Function) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(function)))
|
||||
}
|
||||
|
||||
pub fn integer(integer: i64) -> Self {
|
||||
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>> {
|
||||
if let ValueInner::List(list) = self.inner().as_ref() {
|
||||
Some(list)
|
||||
@ -539,12 +551,39 @@ pub struct Function {
|
||||
pub name: Identifier,
|
||||
pub type_parameters: Option<Vec<Type>>,
|
||||
pub value_parameters: Option<Vec<(Identifier, Type)>>,
|
||||
pub body: Vec<Statement<()>>,
|
||||
pub body: AbstractSyntaxTree<()>,
|
||||
}
|
||||
|
||||
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> {
|
||||
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, ") {{")?;
|
||||
|
||||
for statement in &self.body {
|
||||
for statement in &self.body.nodes {
|
||||
write!(f, "{}", statement)?;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
parse, AbstractSyntaxTree, Analyzer, AnalyzerError, Identifier, Node, ParseError,
|
||||
ReservedIdentifier, Span, Statement, Value, ValueError,
|
||||
abstract_tree::BuiltInFunctionError, parse, AbstractSyntaxTree, Analyzer, AnalyzerError,
|
||||
Identifier, Node, ParseError, Span, Statement, Value, ValueError,
|
||||
};
|
||||
|
||||
pub fn run(
|
||||
@ -47,9 +47,6 @@ impl<P: Copy> Vm<P> {
|
||||
variables: &mut HashMap<Identifier, Value>,
|
||||
) -> Result<Option<Value>, VmError<P>> {
|
||||
match node.statement {
|
||||
Statement::Constant(value) => Ok(Some(value.clone())),
|
||||
Statement::Identifier(_) => Ok(None),
|
||||
Statement::ReservedIdentifier(_) => Ok(None),
|
||||
Statement::Add(left, right) => {
|
||||
let left_span = left.position;
|
||||
let left = if let Some(value) = self.run_node(*left, variables)? {
|
||||
@ -92,6 +89,84 @@ impl<P: Copy> Vm<P> {
|
||||
|
||||
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) => {
|
||||
let values = nodes
|
||||
.into_iter()
|
||||
@ -110,7 +185,7 @@ impl<P: Copy> Vm<P> {
|
||||
Statement::Multiply(_, _) => todo!(),
|
||||
Statement::PropertyAccess(left, right) => {
|
||||
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
|
||||
} else {
|
||||
return Err(VmError::ExpectedValue {
|
||||
@ -119,39 +194,8 @@ impl<P: Copy> Vm<P> {
|
||||
};
|
||||
let right_span = right.position;
|
||||
|
||||
if let Statement::ReservedIdentifier(reserved) = &right.statement {
|
||||
match reserved {
|
||||
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(list), Statement::Constant(value)) =
|
||||
(left_value.as_list(), &right.statement)
|
||||
{
|
||||
if let Some(index) = value.as_integer() {
|
||||
let value = list.get(index as usize).cloned();
|
||||
@ -160,6 +204,37 @@ impl<P: Copy> Vm<P> {
|
||||
}
|
||||
}
|
||||
|
||||
if let (
|
||||
value,
|
||||
Statement::BuiltInFunctionCall {
|
||||
function,
|
||||
type_arguments,
|
||||
value_arguments: mut value_argument_nodes,
|
||||
},
|
||||
) = (left_value, right.statement)
|
||||
{
|
||||
let mut value_arguments = Vec::new();
|
||||
|
||||
value_arguments.push(value);
|
||||
|
||||
if let Some(value_nodes) = value_argument_nodes {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
let function_call_return = function.call(None, Some(value_arguments))?;
|
||||
|
||||
return Ok(Some(function_call_return));
|
||||
}
|
||||
|
||||
Err(VmError::ExpectedIdentifierOrInteger {
|
||||
position: right_span,
|
||||
})
|
||||
@ -176,11 +251,32 @@ pub enum VmError<P> {
|
||||
|
||||
// Anaylsis Failures
|
||||
// These should be prevented by running the analyzer before the VM
|
||||
ExpectedIdentifier { position: P },
|
||||
ExpectedIdentifierOrInteger { position: P },
|
||||
ExpectedInteger { position: P },
|
||||
ExpectedList { position: P },
|
||||
ExpectedValue { position: P },
|
||||
BuiltInFunctionCallFailed(BuiltInFunctionError),
|
||||
ExpectedIdentifier {
|
||||
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> {
|
||||
@ -217,7 +313,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn is_even() {
|
||||
let input = "42.is_even";
|
||||
let input = "42.is_even()";
|
||||
|
||||
assert_eq!(
|
||||
run(input, &mut HashMap::new()),
|
||||
@ -227,7 +323,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn is_odd() {
|
||||
let input = "42.is_odd";
|
||||
let input = "42.is_odd()";
|
||||
|
||||
assert_eq!(
|
||||
run(input, &mut HashMap::new()),
|
||||
@ -235,6 +331,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]
|
||||
fn list_access() {
|
||||
let input = "[1, 2, 3].1";
|
||||
@ -242,13 +345,6 @@ mod tests {
|
||||
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]
|
||||
fn add() {
|
||||
let input = "1 + 2";
|
||||
|
Loading…
Reference in New Issue
Block a user