Skip to content

Commit

Permalink
✨ Add primitive type checker
Browse files Browse the repository at this point in the history
semver: minor
  • Loading branch information
Somfic committed Nov 2, 2024
1 parent bd3c1e1 commit 8a13341
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 220 deletions.
15 changes: 4 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,7 @@ pub mod parser;
pub mod passer;

const INPUT: &str = "
fn main() {
fib(9999);
}
fn fib(n ~ int) ~ int {
let n = 12;
if n < 2 return n;
fib(n - 1) + fib(n - 20)
}
let a = 1 + 1.1 - true * 'c' / \"hello\"
";

fn main() {
Expand Down Expand Up @@ -87,7 +78,9 @@ impl miette::highlighters::HighlighterState for SomHighlighterState {
| TokenKind::Trait
| TokenKind::Return => Style::new().fg_rgb::<197, 120, 221>(),
TokenKind::Identifier => Style::new().fg_rgb::<224, 108, 117>(),
TokenKind::String => Style::new().fg_rgb::<152, 195, 121>().italic(),
TokenKind::String | TokenKind::Character => {
Style::new().fg_rgb::<152, 195, 121>().italic()
}
TokenKind::Integer | TokenKind::Decimal => {
Style::new().fg_rgb::<209, 154, 102>()
}
Expand Down
18 changes: 17 additions & 1 deletion src/parser/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, fmt::Display};

use miette::SourceSpan;

Expand Down Expand Up @@ -158,6 +158,22 @@ pub enum TypeValue<'de> {
Set(Box<Type<'de>>),
}

impl Display for Type<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self.value {
TypeValue::Unit => write!(f, "an unit"),
TypeValue::Boolean => write!(f, "a boolean"),
TypeValue::Integer => write!(f, "an integer"),
TypeValue::Decimal => write!(f, "a decimal"),
TypeValue::Character => write!(f, "a character"),
TypeValue::String => write!(f, "a string"),
TypeValue::Symbol(name) => write!(f, "{}", name),
TypeValue::Collection(element) => write!(f, "[{}]", element),
TypeValue::Set(element) => write!(f, "{{{}}}", element),
}
}
}

pub trait Spannable<'de>: Sized {
type Value;

Expand Down
231 changes: 93 additions & 138 deletions src/parser/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,77 +192,13 @@ pub fn enum_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
}

pub fn function_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
let token = parser
.lexer
.expect(TokenKind::Function, "expected a function keyword")?;

let identifier = parser
.lexer
.expect(TokenKind::Identifier, "expected function name")?;

let name = match identifier.value {
TokenValue::Identifier(identifier) => identifier,
_ => unreachable!(),
};

parser
.lexer
.expect(TokenKind::ParenOpen, "expected an open parenthesis")?;

let mut parameters = vec![];

while parser.lexer.peek().map_or(false, |token| {
token
.as_ref()
.map_or(false, |token| token.kind != TokenKind::ParenClose)
}) {
if !parameters.is_empty() {
parser
.lexer
.expect(TokenKind::Comma, "expected a comma between parameters")?;
}

let parameter = parser
.lexer
.expect(TokenKind::Identifier, "expected a parameter name")?;

let parameter = match parameter.value {
TokenValue::Identifier(parameter) => parameter,
_ => unreachable!(),
};

parser.lexer.expect(TokenKind::Tilde, "expected a tilde")?;

let explicit_type = typing::parse(parser, BindingPower::None)?;

parameters.push(ParameterDeclaration {
name: parameter,
explicit_type,
});
}

parser
.lexer
.expect(TokenKind::ParenClose, "expected a close parenthesis")?;

let explicit_return_type = match parser.lexer.peek_expect(TokenKind::Tilde) {
None => None,
Some(_) => {
parser.lexer.next();
Some(typing::parse(parser, BindingPower::None)?)
}
};

let header = parse_function_header(parser)?;
let body = expression::parse(parser, BindingPower::None)?;

Ok(Statement::at_multiple(vec![], value)::Function {
header: FunctionHeader {
name,
parameters,
explicit_return_type,
},
body,
})
Ok(Statement::at_multiple(
vec![body.span],
StatementValue::Function { header, body },
))
}

pub fn trait_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
Expand All @@ -274,7 +210,7 @@ pub fn trait_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
.lexer
.expect(TokenKind::Identifier, "expected a trait name")?;

let identifier = match identifier.value {
let name = match identifier.value {
TokenValue::Identifier(identifier) => identifier,
_ => unreachable!(),
};
Expand All @@ -294,87 +230,34 @@ pub fn trait_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
.expect(TokenKind::Comma, "expected a comma between functions")?;
}

parser
.lexer
.expect(TokenKind::Function, "expected a function keyword")?;

let function = parser
.lexer
.expect(TokenKind::Identifier, "expected a function name")?;

let function = match function.value {
TokenValue::Identifier(function) => function,
_ => unreachable!(),
};

parser
.lexer
.expect(TokenKind::ParenOpen, "expected an open parenthesis")?;

let mut parameters = vec![];

while parser.lexer.peek().map_or(false, |token| {
token
.as_ref()
.map_or(false, |token| token.kind != TokenKind::ParenClose)
}) {
if !parameters.is_empty() {
parser
.lexer
.expect(TokenKind::Comma, "expected a comma in between arguments")?;
}

let parameter = parser
.lexer
.expect(TokenKind::Identifier, "expected an argument name")?;

let parameter = match parameter.value {
TokenValue::Identifier(parameter) => parameter,
_ => unreachable!(),
};

parser.lexer.expect(TokenKind::Tilde, "expected a tilde")?;

let explicit_type = typing::parse(parser, BindingPower::None)?;

parameters.push(ParameterDeclaration {
name: parameter,
explicit_type,
});
}

parser
.lexer
.expect(TokenKind::ParenClose, "expected a close parenthesis")?;

functions.push(FunctionHeader {
name: function,
parameters,
})
functions.push(parse_function_header(parser)?);
}

parser
.lexer
.expect(TokenKind::Semicolon, "expected a semicolon")?;

Ok(Statement::Trait {
name: identifier,
functions,
})
Ok(Statement::at_multiple(
vec![identifier.span],
StatementValue::Trait { name, functions },
))
}

pub fn return_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
parser
let token = parser
.lexer
.expect(TokenKind::Return, "expected a return keyword")?;

let expression = expression::parse(parser, BindingPower::None)?;

Ok(Statement::Return(expression))
Ok(Statement::at_multiple(
vec![token.span, expression.span],
StatementValue::Return(expression),
))
}

pub fn if_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
parser
let token = parser
.lexer
.expect(TokenKind::If, "expected an if keyword")?;

Expand All @@ -393,9 +276,81 @@ pub fn if_<'de>(parser: &mut Parser<'de>) -> Result<Statement<'de>> {
None
};

Ok(Statement::Conditional {
condition: Box::new(condition),
truthy: Box::new(truthy),
falsy: falsy.map(Box::new),
Ok(Statement::at_multiple(
vec![token.span, condition.span],
StatementValue::Conditional {
condition: Box::new(condition),
truthy: Box::new(truthy),
falsy: falsy.map(Box::new),
},
))
}

fn parse_function_header<'de>(parser: &mut Parser<'de>) -> Result<FunctionHeader<'de>> {
let token = parser
.lexer
.expect(TokenKind::Function, "expected a function keyword")?;

let identifier = parser
.lexer
.expect(TokenKind::Identifier, "expected function name")?;

let name = match identifier.value {
TokenValue::Identifier(identifier) => identifier,
_ => unreachable!(),
};

parser
.lexer
.expect(TokenKind::ParenOpen, "expected an open parenthesis")?;

let mut parameters = vec![];

while parser.lexer.peek().map_or(false, |token| {
token
.as_ref()
.map_or(false, |token| token.kind != TokenKind::ParenClose)
}) {
if !parameters.is_empty() {
parser
.lexer
.expect(TokenKind::Comma, "expected a comma between parameters")?;
}

let parameter = parser
.lexer
.expect(TokenKind::Identifier, "expected a parameter name")?;

let parameter = match parameter.value {
TokenValue::Identifier(parameter) => parameter,
_ => unreachable!(),
};

parser.lexer.expect(TokenKind::Tilde, "expected a tilde")?;

let explicit_type = typing::parse(parser, BindingPower::None)?;

parameters.push(ParameterDeclaration {
name: parameter,
explicit_type,
});
}

parser
.lexer
.expect(TokenKind::ParenClose, "expected a close parenthesis")?;

let explicit_return_type = match parser.lexer.peek_expect(TokenKind::Tilde) {
None => None,
Some(_) => {
parser.lexer.next();
Some(typing::parse(parser, BindingPower::None)?)
}
};

Ok(FunctionHeader {
name,
parameters,
explicit_return_type,
})
}
Loading

0 comments on commit 8a13341

Please sign in to comment.