Skip to content

Commit

Permalink
feat(typechecker): add method declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
H1ghBre4k3r committed May 10, 2024
1 parent f14f72d commit 78fa178
Show file tree
Hide file tree
Showing 10 changed files with 692 additions and 9 deletions.
7 changes: 7 additions & 0 deletions crates/why_lib/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ impl Span {

error_string
}

pub fn merge(&self, other: &Span) -> Span {
let Span { start, source, .. } = self.clone();
let Span { end, .. } = other.clone();

Span { start, end, source }
}
}

impl PartialEq<Span> for Span {
Expand Down
1 change: 1 addition & 0 deletions crates/why_lib/src/parser/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ pub enum AstNode {
StructInitialisation(StructInitialisation<()>),
StructFieldInitialisation(StructFieldInitialisation<()>),
Instance(Instance<()>),
MethodDeclaration(MethodDeclaration<()>),
}
82 changes: 78 additions & 4 deletions crates/why_lib/src/parser/ast/statement/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ use crate::{
},
};

use super::MethodDeclaration;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Instance<T> {
pub name: TypeName,
pub functions: Vec<Function<T>>,
pub declarations: Vec<MethodDeclaration<T>>,
pub info: T,
pub position: Span,
}
Expand All @@ -22,17 +25,22 @@ impl FromTokens<Token> for Instance<()> {
let matcher = Comb::INSTANCE_KEYWORD
>> Comb::TYPE_NAME
>> Comb::LBRACE
>> (Comb::FUNCTION ^ Comb::RBRACE);
>> ((Comb::FUNCTION | Comb::METHOD_DECLARATION) ^ Comb::RBRACE);
let mut result = matcher.parse(tokens)?.into_iter();

let Some(AstNode::TypeName(name)) = result.next() else {
unreachable!();
};

let mut functions = vec![];
let mut declarations = vec![];

while let Some(AstNode::Function(function)) = result.next() {
functions.push(function);
for next in result.by_ref() {
match next {
AstNode::Function(function) => functions.push(function),
AstNode::MethodDeclaration(declaration) => declarations.push(declaration),
_ => unreachable!(),
}
}

assert!(result.next().is_none());
Expand All @@ -42,6 +50,7 @@ impl FromTokens<Token> for Instance<()> {
Ok(Instance {
name,
functions,
declarations,
info: (),
position: Span {
start: position.start,
Expand All @@ -66,7 +75,7 @@ mod tests {
use crate::{
lexer::{Lexer, Span},
parser::{
ast::{Expression, Function, Id, Num, Statement, TypeName},
ast::{Expression, Function, Id, MethodDeclaration, Num, Statement, TypeName},
FromTokens,
},
};
Expand All @@ -84,6 +93,7 @@ mod tests {
Instance {
name: TypeName::Literal("Foo".into(), Span::default()),
functions: vec![],
declarations: vec![],
info: (),
position: Span::default()
}
Expand Down Expand Up @@ -125,6 +135,70 @@ mod tests {
info: (),
position: Span::default()
}],
declarations: vec![],
info: (),
position: Span::default()
}
.into()
);

Ok(())
}

#[test]
fn test_complext_instance() -> Result<()> {
let mut tokens = Lexer::new(
"instance Foo {
fn bar(): i64 {
42
}
declare foo(i64, (i64, f64)): i64;
}",
)
.lex()?
.into();

let result = Instance::parse(&mut tokens)?;

assert_eq!(
result,
Instance {
name: TypeName::Literal("Foo".into(), Span::default()),
functions: vec![Function {
id: Id {
name: "bar".into(),
info: (),
position: Span::default()
},
parameters: vec![],
return_type: TypeName::Literal("i64".into(), Span::default()),
statements: vec![Statement::YieldingExpression(Expression::Num(
Num::Integer(42, (), Span::default())
))],
info: (),
position: Span::default()
}],
declarations: vec![MethodDeclaration {
id: Id {
name: "foo".into(),
info: (),
position: Span::default()
},
parameter_types: vec![
TypeName::Literal("i64".into(), Span::default()),
TypeName::Tuple(
vec![
TypeName::Literal("i64".into(), Span::default()),
TypeName::Literal("f64".into(), Span::default())
],
Span::default()
)
],
return_type: TypeName::Literal("i64".into(), Span::default()),
info: (),
position: Span::default()
}],
info: (),
position: Span::default()
}
Expand Down
139 changes: 139 additions & 0 deletions crates/why_lib/src/parser/ast/statement/method_declaration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use crate::{
lexer::{Span, Token},
parser::{
ast::{AstNode, Id, TypeName},
combinators::Comb,
FromTokens, ParseError, ParseState,
},
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MethodDeclaration<T> {
pub id: Id<T>,
pub parameter_types: Vec<TypeName>,
pub return_type: TypeName,
pub info: T,
pub position: Span,
}

impl FromTokens<Token> for MethodDeclaration<()> {
fn parse(tokens: &mut ParseState<Token>) -> Result<AstNode, ParseError> {
let position = tokens.span()?;

let matcher = Comb::DECLARE_KEYWORD
>> Comb::ID
>> Comb::LPAREN
>> (Comb::TYPE_NAME % Comb::COMMA)
>> Comb::RPAREN;

let mut result = matcher.parse(tokens)?.into_iter();

let Some(AstNode::Id(id)) = result.next() else {
unreachable!()
};

let mut parameter_types = vec![];

while let Some(AstNode::TypeName(parameter)) = result.next() {
parameter_types.push(parameter);
}
assert!(result.next().is_none());

let matcher = Comb::COLON >> Comb::TYPE_NAME >> Comb::SEMI;

let mut result = matcher.parse(tokens)?.into_iter();

let Some(AstNode::TypeName(return_type)) = result.next() else {
unreachable!()
};

let end = tokens.prev_span()?;

Ok(MethodDeclaration {
id,
parameter_types,
return_type,
info: (),
position: position.merge(&end),
}
.into())
}
}

impl From<MethodDeclaration<()>> for AstNode {
fn from(value: MethodDeclaration<()>) -> Self {
AstNode::MethodDeclaration(value)
}
}

#[cfg(test)]
mod tests {
use anyhow::Result;

use crate::{
lexer::{Lexer, Span},
parser::{
ast::{AstNode, Id, TypeName},
FromTokens,
},
};

use super::MethodDeclaration;

#[test]
fn test_simple_method_declaration() -> Result<()> {
let mut tokens = Lexer::new("declare foo(): void;").lex()?.into();

let result = MethodDeclaration::parse(&mut tokens)?;

assert_eq!(
result,
AstNode::MethodDeclaration(MethodDeclaration {
id: Id {
name: "foo".into(),
info: (),
position: Span::default()
},
parameter_types: vec![],
return_type: TypeName::Literal("void".into(), Span::default()),
info: (),
position: Span::default()
})
);
Ok(())
}

#[test]
fn test_complex_method_declaration() -> Result<()> {
let mut tokens = Lexer::new("declare foo(i64, (i64, f64)): i64;")
.lex()?
.into();

let result = MethodDeclaration::parse(&mut tokens)?;

assert_eq!(
result,
AstNode::MethodDeclaration(MethodDeclaration {
id: Id {
name: "foo".into(),
info: (),
position: Span::default()
},
parameter_types: vec![
TypeName::Literal("i64".into(), Span::default()),
TypeName::Tuple(
vec![
TypeName::Literal("i64".into(), Span::default()),
TypeName::Literal("f64".into(), Span::default())
],
Span::default()
)
],
return_type: TypeName::Literal("i64".into(), Span::default()),
info: (),
position: Span::default()
})
);
Ok(())
}
}
2 changes: 2 additions & 0 deletions crates/why_lib/src/parser/ast/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod constant;
mod declaration;
mod initialisation;
mod instance;
mod method_declaration;
mod struct_declaration;
mod while_loop;

Expand All @@ -11,6 +12,7 @@ pub use self::constant::*;
pub use self::declaration::*;
pub use self::initialisation::*;
pub use self::instance::*;
pub use self::method_declaration::*;
pub use self::struct_declaration::*;
pub use self::while_loop::*;

Expand Down
8 changes: 5 additions & 3 deletions crates/why_lib/src/parser/combinators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::lexer::{GetPosition, Terminal, Token};
use super::{
ast::{
Array, Assignment, AstNode, Block, Constant, Declaration, Expression, Function,
FunctionParameter, Id, If, Initialisation, Instance, Lambda, LambdaParameter, Num,
Statement, StructDeclaration, StructFieldDeclaration, StructFieldInitialisation,
StructInitialisation, TypeName, WhileLoop,
FunctionParameter, Id, If, Initialisation, Instance, Lambda, LambdaParameter,
MethodDeclaration, Num, Statement, StructDeclaration, StructFieldDeclaration,
StructFieldInitialisation, StructInitialisation, TypeName, WhileLoop,
},
FromTokens, ParseError, ParseState,
};
Expand Down Expand Up @@ -256,6 +256,8 @@ impl<'a> Comb<'a, Token, Terminal, AstNode> {
node_comb!(STRUCT_FIELD_INITIALISATION, StructFieldInitialisation);

node_comb!(INSTANCE, Instance);

node_comb!(METHOD_DECLARATION, MethodDeclaration);
}

impl<'a, Tok, Term, Node> Comb<'a, Tok, Term, Node>
Expand Down
Loading

0 comments on commit 78fa178

Please sign in to comment.