Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/ast/grammar/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ use crate::ast::structs::expression::FunctionDeclaration;
use crate::ast::structs::r#type::TypeExpression;
use crate::ast::{DatexExpressionData, DatexParserTrait};
use chumsky::prelude::*;
fn return_type<'a>() -> impl DatexParserTrait<'a, Option<TypeExpression>> {
pub fn return_type<'a>() -> impl DatexParserTrait<'a, Option<TypeExpression>> {
just(Token::Arrow)
.padded_by(whitespace())
.ignore_then(ty().padded_by(whitespace()))
.or_not()
}

fn body<'a>(
pub fn body<'a>(
statements: impl DatexParserTrait<'a>,
) -> impl DatexParserTrait<'a> {
statements
.clone()
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
}

fn parameter<'a>() -> impl DatexParserTrait<'a, (String, TypeExpression)> {
pub fn parameter<'a>() -> impl DatexParserTrait<'a, (String, TypeExpression)> {
select! { Token::Identifier(name) => name }
.then(
just(Token::Colon)
Expand Down
1 change: 1 addition & 0 deletions src/ast/grammar/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::ast::spanned::Spanned;
use crate::values::core_values::integer::Integer;
use crate::values::core_values::integer::typed_integer::TypedInteger;
use chumsky::prelude::*;

pub fn integer<'a>() -> impl DatexParserTrait<'a> {
select! {
Token::DecimalIntegerLiteral(IntegerLiteral { value, variant }) => {
Expand Down
129 changes: 129 additions & 0 deletions src/ast/grammar/interface.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use chumsky::{IterParser, Parser, prelude::just, select};

use crate::ast::{
DatexParserTrait,
grammar::{
function::{body, parameter, return_type},
utils::whitespace,
},
lexer::Token,
spanned::Spanned,
structs::{
expression::{
DatexExpressionData, FunctionDeclaration, InterfaceDeclaration,
},
r#type::{TypeExpression, TypeExpressionData},
},
};

pub fn self_parameter<'a>()
-> impl DatexParserTrait<'a, (String, TypeExpression)> {
let amp = just(Token::Ampersand).or_not().padded_by(whitespace());
let mut_tok = just(Token::Mutable).or_not().padded_by(whitespace());

amp.then(mut_tok)
.then_ignore(just(Token::Identifier("self".to_string())))
.map_with(|(amp_opt, mut_opt), span| {
let ty = match (amp_opt, mut_opt) {
(None, _) => TypeExpressionData::SelfType, // self
(Some(_), None) => TypeExpressionData::ReferenceSelf, // &self
(Some(_), Some(_)) => TypeExpressionData::ReferenceSelfMut, // &mut self
};
("self".to_string(), ty.with_span(span.span()))
})
.padded_by(whitespace())
}

pub fn parameters<'a>()
-> impl DatexParserTrait<'a, Vec<(String, TypeExpression)>> {
let maybe_self = self_parameter().padded_by(whitespace()).or_not();

let normal_params = parameter()
.padded_by(whitespace())
.separated_by(just(Token::Comma).padded_by(whitespace()))
.collect::<Vec<(String, TypeExpression)>>();

maybe_self
.then(
just(Token::Comma)
.padded_by(whitespace())
.ignore_then(normal_params.clone())
.or(normal_params),
)
.map(
|(self_opt, params): (
Option<(String, TypeExpression)>,
Vec<(String, TypeExpression)>,
)| {
if let Some(self_param) = self_opt {
// Insert self parameter at the front
let mut all = Vec::with_capacity(params.len() + 1);
all.push(self_param);
all.extend(params);
all
} else {
params
}
},
)
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.padded_by(whitespace())
}

fn method<'a>(
statements: impl DatexParserTrait<'a>,
) -> impl DatexParserTrait<'a> {
let maybe_body = body(statements).map(Some);

select! { Token::Identifier(name) => name }
.padded_by(whitespace())
.then(parameters())
.then(return_type())
.then(
maybe_body
.or(just(Token::Semicolon).padded_by(whitespace()).to(None))
.or_not(),
)
.map_with(|(((name, params), return_type), body), e| {
let body_or_noop = body.flatten().unwrap_or_else(|| {
DatexExpressionData::Noop.with_default_span()
});
DatexExpressionData::FunctionDeclaration(FunctionDeclaration {
name,
parameters: params,
return_type,
body: Box::new(body_or_noop),
})
.with_span(e.span())
})
}

pub fn interface_declaration<'a>(
statements: impl DatexParserTrait<'a>,
) -> impl DatexParserTrait<'a> {
let method_decl = method(statements);

let method_list = method_decl
.padded_by(whitespace())
.separated_by(whitespace())
.collect::<Vec<_>>()
.padded_by(whitespace())
.delimited_by(
just(Token::LeftCurly).padded_by(whitespace()),
just(Token::RightCurly).padded_by(whitespace()),
)
.padded_by(whitespace());

just(Token::Identifier("interface".to_string()))
.padded_by(whitespace())
.ignore_then(select! { Token::Identifier(name) => name })
.padded_by(whitespace())
.then(method_list)
.map_with(|(name, methods), e| {
DatexExpressionData::InterfaceDeclaration(InterfaceDeclaration {
name,
methods,
})
.with_span(e.span())
})
}
1 change: 1 addition & 0 deletions src/ast/grammar/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod decimal;
pub mod endpoint;
pub mod function;
pub mod integer;
pub mod interface;
pub mod key;
pub mod list;
pub mod literal;
Expand Down
168 changes: 167 additions & 1 deletion src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::ast::grammar::binding::*;
use crate::ast::grammar::chain::*;
use crate::ast::grammar::comparison_operation::*;
use crate::ast::grammar::function::*;
use crate::ast::grammar::interface::interface_declaration;
use crate::ast::grammar::key::*;
use crate::ast::grammar::list::*;
use crate::ast::grammar::map::*;
Expand Down Expand Up @@ -158,6 +159,7 @@ pub fn create_parser<'a>() -> impl DatexParserTrait<'a, DatexExpression> {
let binary = binary_operation(chain);

// FIXME #363 WIP
let interface_declaration = interface_declaration(statements.clone());
let function_declaration = function(statements.clone());

// comparison (==, !=, is, …)
Expand Down Expand Up @@ -232,6 +234,7 @@ pub fn create_parser<'a>() -> impl DatexParserTrait<'a, DatexExpression> {
type_expression(),
if_expression,
declaration_or_assignment,
interface_declaration,
function_declaration,
comparison,
))
Expand Down Expand Up @@ -324,7 +327,8 @@ mod tests {
structs::{
expression::{
ApplyChain, BinaryOperation, ComparisonOperation,
FunctionDeclaration, TypeDeclaration, TypeDeclarationKind,
FunctionDeclaration, InterfaceDeclaration, TypeDeclaration,
TypeDeclarationKind,
},
r#type::{
Intersection, SliceList, StructuralMap, TypeExpression,
Expand Down Expand Up @@ -491,6 +495,168 @@ mod tests {
);
}

#[test]
fn interface() {
let src = r#"
interface User {
can_vote(age: integer) -> boolean;

is_adult(&self) -> boolean;

is_senior(&self) -> boolean;

hurt(&mut self) -> void;

kill(self) -> void;

get_name(&self) -> text (
self.name
)
}
"#;
let val = parse_unwrap_data(src);
assert_eq!(
val,
DatexExpressionData::InterfaceDeclaration(InterfaceDeclaration {
name: "User".to_string(),
methods: vec![
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "can_vote".to_string(),
parameters: vec![(
"age".to_string(),
TypeExpressionData::Literal(
"integer".to_string()
)
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal(
"boolean".to_string()
)
.with_default_span()
),
body: Box::new(
DatexExpressionData::Noop.with_default_span()
),
}
)
.with_default_span(),
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "is_adult".to_string(),
parameters: vec![(
"self".to_string(),
TypeExpressionData::ReferenceSelf
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal(
"boolean".to_string()
)
.with_default_span()
),
body: Box::new(
DatexExpressionData::Noop.with_default_span()
),
}
)
.with_default_span(),
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "is_senior".to_string(),
parameters: vec![(
"self".to_string(),
TypeExpressionData::ReferenceSelf
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal(
"boolean".to_string()
)
.with_default_span()
),
body: Box::new(
DatexExpressionData::Noop.with_default_span()
),
}
)
.with_default_span(),
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "hurt".to_string(),
parameters: vec![(
"self".to_string(),
TypeExpressionData::ReferenceSelfMut
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal("void".to_string())
.with_default_span()
),
body: Box::new(
DatexExpressionData::Noop.with_default_span()
),
}
)
.with_default_span(),
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "kill".to_string(),
parameters: vec![(
"self".to_string(),
TypeExpressionData::SelfType
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal("void".to_string())
.with_default_span()
),
body: Box::new(
DatexExpressionData::Noop.with_default_span()
),
}
)
.with_default_span(),
DatexExpressionData::FunctionDeclaration(
FunctionDeclaration {
name: "get_name".to_string(),
parameters: vec![(
"self".to_string(),
TypeExpressionData::ReferenceSelf
.with_default_span()
)],
return_type: Some(
TypeExpressionData::Literal("text".to_string())
.with_default_span()
),
body: Box::new(
DatexExpressionData::ApplyChain(ApplyChain {
base: Box::new(
DatexExpressionData::Identifier(
"self".to_string()
)
.with_default_span()
),
operations: vec![
ApplyOperation::PropertyAccess(
DatexExpressionData::Text(
"name".to_string()
)
.with_default_span()
)
]
})
.with_default_span()
),
}
)
.with_default_span(),
],
})
);
}

#[test]
#[ignore = "WIP"]
fn type_expression() {
Expand Down
Loading
Loading