diff --git a/dust-lang/src/abstract_tree.rs b/dust-lang/src/abstract_tree.rs index a0729b2..b86683d 100644 --- a/dust-lang/src/abstract_tree.rs +++ b/dust-lang/src/abstract_tree.rs @@ -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
{ @@ -40,6 +40,16 @@ pub enum Statement
{
// Expressions
Add(Box {
// Hard-coded values
Constant(Value),
Identifier(Identifier),
- ReservedIdentifier(ReservedIdentifier),
}
impl Statement {
@@ -55,17 +64,15 @@ impl Statement {
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 Display for Statement {
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,69 @@ impl Display for Statement {
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 {
+ ExpectedFunction { position: P },
ExpectedIdentifier { actual: Node },
ExpectedIntegerOrFloat { actual: Node },
UnexpectedIdentifier { identifier: Node },
diff --git a/dust-lang/src/lex.rs b/dust-lang/src/lex.rs
index aa88607..2ec2f94 100644
--- a/dust-lang/src/lex.rs
+++ b/dust-lang/src/lex.rs
@@ -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)),])
)
}
diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs
index 97f61f7..5007c1f 100644
--- a/dust-lang/src/lib.rs
+++ b/dust-lang/src/lib.rs
@@ -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};
diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs
index 89a4823..bb1844e 100644
--- a/dust-lang/src/parse.rs
+++ b/dust-lang/src/parse.rs
@@ -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,52 @@ impl<'src> Parser<'src> {
}
}
}
- (Token::ReservedIdentifier(reserved), _) => {
+ (Token::IsEven, left_span) => {
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(
- Statement::ReservedIdentifier(reserved),
- self.current.1,
+ Statement::BuiltInFunctionCall {
+ function: BuiltInFunction::IsEven,
+ type_arguments: None,
+ value_arguments: value_parameters,
+ },
+ left_span,
))
}
_ => Err(ParseError::UnexpectedToken(self.current.0.clone())),
@@ -280,6 +320,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 +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]
fn list_access() {
let input = "[1, 2, 3].0";
diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs
index 4725300..5b44181 100644
--- a/dust-lang/src/token.rs
+++ b/dust-lang/src/token.rs
@@ -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, "]"),
}
}
}
diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs
index 21083bd..c9a1899 100644
--- a/dust-lang/src/value.rs
+++ b/dust-lang/src/value.rs
@@ -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