Skip to content

Commit

Permalink
♻️ (parser): Refactor parser
Browse files Browse the repository at this point in the history
semver: chore
  • Loading branch information
Somfic committed Jul 10, 2024
1 parent 41bcd89 commit 6e9863c
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 36 deletions.
48 changes: 46 additions & 2 deletions src/parser/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
hash::Hash,
};

use crate::scanner::lexeme::Token;

Expand Down Expand Up @@ -30,8 +33,49 @@ pub enum Statement {
Expression(Expression),
Struct(String, HashMap<String, Type>),
Enum(String, HashMap<String, Option<Type>>),
Function(String, HashMap<String, Type>, Type, Box<Statement>),
Function(Function),
Return(Expression),
Trait(String, HashSet<FunctionSignature>),
Implementation(String, Type, HashSet<Function>),
}

#[derive(Debug, Clone)]
pub struct Function {
pub signature: FunctionSignature,
pub body: Box<Statement>,
}

impl PartialEq for Function {
fn eq(&self, other: &Self) -> bool {
self.signature == other.signature
}
}

impl Eq for Function {}

impl Hash for Function {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.signature.hash(state);
}
}

#[derive(Debug, Clone, Eq)]
pub struct FunctionSignature {
pub name: String,
pub parameters: HashMap<String, Type>,
pub return_type: Type,
}

impl PartialEq for FunctionSignature {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}

impl Hash for FunctionSignature {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
2 changes: 0 additions & 2 deletions src/parser/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/statement/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
26 changes: 17 additions & 9 deletions src/parser/statement/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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> {
Expand Down
2 changes: 2 additions & 0 deletions src/parser/statement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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> {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/statement/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
79 changes: 79 additions & 0 deletions src/parser/statement/traits.rs
Original file line number Diff line number Diff line change
@@ -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))
}
13 changes: 9 additions & 4 deletions src/scanner/lexeme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ pub enum TokenType {
Dollar,
/// A pipe; `|`.
Pipe,
/// A fat arrow; `=>`.
FatArrow,
/// A left arrow; `<-`.
LeftArrow,
/// A right arrow; `->`.
Expand Down Expand Up @@ -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 {
Expand All @@ -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, "`+`"),
Expand Down Expand Up @@ -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`"),
}
}
}
5 changes: 5 additions & 0 deletions src/scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down Expand Up @@ -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))
}),
Expand Down
44 changes: 39 additions & 5 deletions src/transpiler/bend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
24 changes: 12 additions & 12 deletions test.som
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 6e9863c

Please sign in to comment.