diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 9f6e48e..b8f959a 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,4 +1,7 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + hash::Hash, +}; use crate::scanner::lexeme::Token; @@ -30,8 +33,49 @@ pub enum Statement { Expression(Expression), Struct(String, HashMap), Enum(String, HashMap>), - Function(String, HashMap, Type, Box), + Function(Function), Return(Expression), + Trait(String, HashSet), + Implementation(String, Type, HashSet), +} + +#[derive(Debug, Clone)] +pub struct Function { + pub signature: FunctionSignature, + pub body: Box, +} + +impl PartialEq for Function { + fn eq(&self, other: &Self) -> bool { + self.signature == other.signature + } +} + +impl Eq for Function {} + +impl Hash for Function { + fn hash(&self, state: &mut H) { + self.signature.hash(state); + } +} + +#[derive(Debug, Clone, Eq)] +pub struct FunctionSignature { + pub name: String, + pub parameters: HashMap, + pub return_type: Type, +} + +impl PartialEq for FunctionSignature { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Hash for FunctionSignature { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/parser/macros.rs b/src/parser/macros.rs index 44c9a80..a9edf14 100644 --- a/src/parser/macros.rs +++ b/src/parser/macros.rs @@ -3,8 +3,6 @@ macro_rules! expect_token { use crate::diagnostic::Diagnostic; use crate::scanner::lexeme::TokenType; - println!("Expect token: {:?}", TokenType::$token); - if let Some(TokenType::$token) = $parser.peek().map(|t| &t.token_type) { Ok($parser.consume().unwrap().clone()) } else { diff --git a/src/parser/statement/enums.rs b/src/parser/statement/enums.rs index ad77441..390547e 100644 --- a/src/parser/statement/enums.rs +++ b/src/parser/statement/enums.rs @@ -42,7 +42,7 @@ fn parse_enum<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { .map(|_| typest::parse(parser, BindingPower::None)) .transpose()?; - if let Some(overwritten) = members.insert(member_name.clone(), typest) { + if let Some(_) = members.insert(member_name.clone(), typest) { warn_unneeded_token!(parser, member); } } diff --git a/src/parser/statement/functions.rs b/src/parser/statement/functions.rs index 795d7b1..fa7d542 100644 --- a/src/parser/statement/functions.rs +++ b/src/parser/statement/functions.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::{ parser::{ - ast::{Statement, Type}, + ast::{Function, FunctionSignature, Statement, Type}, lookup::{BindingPower, Lookup}, macros::{expect_token, expect_value, optional_token}, typest, ParseResult, Parser, @@ -15,7 +15,7 @@ pub fn register(lookup: &mut Lookup) { lookup.add_statement_handler(TokenType::LeftArrow, parse_return); } -fn parse_function<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { +pub fn parse_function_signature<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, FunctionSignature> { expect_token!(parser, Function)?; let identifier = expect_token!(parser, Identifier)?; let identifier = expect_value!(identifier, Identifier); @@ -38,7 +38,7 @@ fn parse_function<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { let typest = typest::parse(parser, BindingPower::None)?; - parameters.insert(parameter, typest); + parameters.insert(parameter, typest); // TODO: Error if parameter already exists optional_token!(parser, Comma); } @@ -50,16 +50,24 @@ fn parse_function<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { .transpose()? .unwrap_or(Type::Void); + Ok(FunctionSignature { + name: identifier, + parameters, + return_type, + }) +} + +pub fn parse_function<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { + let signature = parse_function_signature(parser)?; + expect_token!(parser, Colon)?; let body = crate::parser::statement::parse(parser)?; - Ok(Statement::Function( - identifier, - parameters, - return_type, - Box::new(body), - )) + Ok(Statement::Function(Function { + signature, + body: Box::new(body), + })) } fn parse_return<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { diff --git a/src/parser/statement/mod.rs b/src/parser/statement/mod.rs index 7463ff1..e32992a 100644 --- a/src/parser/statement/mod.rs +++ b/src/parser/statement/mod.rs @@ -6,6 +6,7 @@ pub mod blocks; pub mod enums; pub mod functions; pub mod structs; +pub mod traits; pub fn parse<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { let statement_handler = parser @@ -24,6 +25,7 @@ pub fn register(lookup: &mut super::lookup::Lookup) { structs::register(lookup); functions::register(lookup); blocks::register(lookup); + traits::register(lookup); } fn parse_expression<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { diff --git a/src/parser/statement/structs.rs b/src/parser/statement/structs.rs index 91af84d..bb9b0d5 100644 --- a/src/parser/statement/structs.rs +++ b/src/parser/statement/structs.rs @@ -41,7 +41,7 @@ pub fn parse_struct<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { let typest = typest::parse(parser, BindingPower::None)?; - members.insert(member_name, typest); + members.insert(member_name, typest); // TODO: Error if member already exists } if indentation.is_some() { diff --git a/src/parser/statement/traits.rs b/src/parser/statement/traits.rs new file mode 100644 index 0000000..cff2ba6 --- /dev/null +++ b/src/parser/statement/traits.rs @@ -0,0 +1,79 @@ +use std::collections::HashSet; + +use crate::{ + parser::{ + ast::{Function, Statement}, + lookup::{BindingPower, Lookup}, + macros::{expect_token, expect_value}, + ParseResult, Parser, + }, + scanner::lexeme::TokenType, +}; + +pub fn register(lookup: &mut Lookup) { + lookup.add_statement_handler(TokenType::Trait, parse_trait); + lookup.add_statement_handler(TokenType::Implementation, parse_impl); +} + +fn parse_trait<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { + expect_token!(parser, Trait)?; + let identifier = expect_token!(parser, Identifier)?; + let identifier = expect_value!(identifier, Identifier); + + expect_token!(parser, Colon)?; + + expect_token!(parser, IndentationOpen)?; + + let mut functions = HashSet::new(); + + loop { + let token = expect_token!(parser)?; + + if token.token_type == TokenType::IndentationClose { + break; + } + + let function = crate::parser::statement::functions::parse_function_signature(parser)?; + functions.insert(function); // TODO: Error if function already exists + } + + expect_token!(parser, IndentationClose)?; + + Ok(Statement::Trait(identifier, functions)) +} + +fn parse_impl<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Statement> { + expect_token!(parser, Implementation)?; + let identifier = expect_token!(parser, Identifier)?; + let identifier = expect_value!(identifier, Identifier); + + expect_token!(parser, For)?; + + let typest = crate::parser::typest::parse(parser, BindingPower::None)?; + + expect_token!(parser, Colon)?; + expect_token!(parser, IndentationOpen)?; + + let mut functions = HashSet::new(); + + loop { + let token = expect_token!(parser)?; + + if token.token_type == TokenType::IndentationClose { + break; + } + + let signature = crate::parser::statement::functions::parse_function_signature(parser)?; + expect_token!(parser, Colon)?; + let body = crate::parser::statement::parse(parser)?; + + functions.insert(Function { + signature, + body: Box::new(body), + }); // TODO: Error if function already exists + } + + expect_token!(parser, IndentationClose)?; + + Ok(Statement::Implementation(identifier, typest, functions)) +} diff --git a/src/scanner/lexeme.rs b/src/scanner/lexeme.rs index 01ef988..23d1bb1 100644 --- a/src/scanner/lexeme.rs +++ b/src/scanner/lexeme.rs @@ -106,6 +106,8 @@ pub enum TokenType { Dollar, /// A pipe; `|`. Pipe, + /// A fat arrow; `=>`. + FatArrow, /// A left arrow; `<-`. LeftArrow, /// A right arrow; `->`. @@ -173,9 +175,10 @@ pub enum TokenType { Struct, /// A enum keyword; `enum`. Enum, - - /// The end of the file. - EndOfFile, + /// A trait keyword; `trait`. + Trait, + /// An implementation keyword; `impl`. + Implementation, } impl Display for TokenType { @@ -198,6 +201,7 @@ impl Display for TokenType { TokenType::Hash => write!(f, "`#`"), TokenType::Dollar => write!(f, "`$`"), TokenType::Pipe => write!(f, "`|`"), + TokenType::FatArrow => write!(f, "`=>`"), TokenType::RightArrow => write!(f, "`->`"), TokenType::LeftArrow => write!(f, "`<-`"), TokenType::Plus => write!(f, "`+`"), @@ -227,7 +231,8 @@ impl Display for TokenType { TokenType::Identifier => write!(f, "an identifier"), TokenType::Struct => write!(f, "`struct`"), TokenType::Enum => write!(f, "`enum`"), - TokenType::EndOfFile => write!(f, "end of file"), + TokenType::Trait => write!(f, "`trait`"), + TokenType::Implementation => write!(f, "`impl`"), } } } diff --git a/src/scanner/mod.rs b/src/scanner/mod.rs index c880516..181c5f4 100644 --- a/src/scanner/mod.rs +++ b/src/scanner/mod.rs @@ -44,6 +44,7 @@ impl<'a> Scanner<'a> { (r!(r"(#)"), |_| (TokenType::Hash, TokenValue::None)), (r!(r"($)"), |_| (TokenType::Dollar, TokenValue::None)), (r!(r"(\|)"), |_| (TokenType::Pipe, TokenValue::None)), + (r!(r"(=>)"), |_| (TokenType::FatArrow, TokenValue::None)), (r!(r"(->)"), |_| (TokenType::RightArrow, TokenValue::None)), (r!(r"(<-)"), |_| (TokenType::LeftArrow, TokenValue::None)), (r!(r"(\+)"), |_| (TokenType::Plus, TokenValue::None)), @@ -71,6 +72,10 @@ impl<'a> Scanner<'a> { (r!(r"(return)"), |_| (TokenType::Return, TokenValue::None)), (r!(r"(struct)"), |_| (TokenType::Struct, TokenValue::None)), (r!(r"(enum)"), |_| (TokenType::Enum, TokenValue::None)), + (r!(r"(trait)"), |_| (TokenType::Trait, TokenValue::None)), + (r!(r"(impl)"), |_| { + (TokenType::Implementation, TokenValue::None) + }), (r!(r"(true)"), |_| { (TokenType::Boolean, TokenValue::Boolean(true)) }), diff --git a/src/transpiler/bend.rs b/src/transpiler/bend.rs index b678aa3..c8d8140 100644 --- a/src/transpiler/bend.rs +++ b/src/transpiler/bend.rs @@ -77,18 +77,52 @@ fn transpile_expression(expression: &Expression) -> String { fn transpile_statement(statement: &Statement) -> String { match statement { + Statement::Implementation(name, typest, implementations) => { + let mut output = String::new(); + output.push_str(&format!( + "impl {} for {} {{\n", + transpile_type(typest), + name + )); + for implementation in implementations { + output.push_str(&transpile_statement(&Statement::Function( + implementation.clone(), + ))); + } + output.push_str("}\n"); + output + } + Statement::Trait(name, functions) => { + let mut output = String::new(); + output.push_str(&format!("trait {} {{\n", name)); + for function in functions { + output.push_str(&format!("fn {}(", function.name)); + for (parameter, typing) in &function.parameters { + output.push_str(&format!("{}: {}, ", parameter, transpile_type(typing))); + } + output.push_str(&format!( + ") -> {};\n", + transpile_type(&function.return_type) + )); + } + output.push_str("}\n"); + output + } Statement::Return(expression) => { let expression = transpile_expression(expression); format!("return {};\n", expression) } - Statement::Function(name, parameters, return_type, body) => { + Statement::Function(function) => { let mut output = String::new(); - output.push_str(&format!("fn {}(", name)); - for (parameter, typing) in parameters { + output.push_str(&format!("fn {}(", function.signature.name)); + for (parameter, typing) in &function.signature.parameters { output.push_str(&format!("{}: {}, ", parameter, transpile_type(typing))); } - output.push_str(&format!(") -> {} ", transpile_type(return_type))); - output.push_str(&transpile_statement(body)); + output.push_str(&format!( + ") -> {} ", + transpile_type(&function.signature.return_type) + )); + output.push_str(&transpile_statement(&function.body)); output } Statement::Block(statements) => { diff --git a/test.som b/test.som index 13f81f9..a699038 100644 --- a/test.som +++ b/test.som @@ -1,16 +1,16 @@ -enum shape: - square ~ string +struct shape: + shape_type ~ shape_type + width ~ number + height ~ number + +enum shape_type: + square rectangle circle -enum color: - red blue green - -struct person: - names ~ [string] - age ~ number - -fn main(person ~ person, shapes ~ [shape]) -> number: <- 12 + 12 - -trait area: +trait area: fn area() -> number + +impl area for shape: + fn area() -> number: + width * height;