diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index 3f7a7f6..ebf8097 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -200,6 +200,7 @@ impl<'de> Iterator for Lexer<'de> { "dec" => Ok((TokenKind::DecimalType, TokenValue::None)), "str" => Ok((TokenKind::StringType, TokenValue::None)), "char" => Ok((TokenKind::CharacterType, TokenValue::None)), + "return" => Ok((TokenKind::Return, TokenValue::None)), ident => Ok(( TokenKind::Identifier, TokenValue::Identifier(ident.to_string().into()), diff --git a/src/main.rs b/src/main.rs index 944343c..0f3c371 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,10 @@ use lexer::{Lexer, TokenKind}; use owo_colors::{Style, Styled}; -use parser::Parser; -use passer::Passer; +use parser::{ + ast::{Expression, Statement}, + Parser, +}; +use passer::{typing::Typing, Passer}; use std::vec; pub mod lexer; @@ -21,15 +24,7 @@ fn main() { })) .unwrap(); - let input = " - fn main() { - fib(9999); - } - - fn fib(n ~ int) ~ int { - return n if n < 2; - fib(n - 1) + fib(n - 20) - } + let input = "true if true else 12 if true else 'h'; "; let mut parser = Parser::new(input); @@ -41,14 +36,39 @@ fn main() { } }; - let typing_pass = passer::typing::TypingPasser::pass(&symbol).unwrap(); - - for note in typing_pass.non_critical { - println!("{:?}", note.with_source_code(input.to_string())); + match symbol { + parser::ast::Symbol::Statement(statement) => print_statement(statement), + parser::ast::Symbol::Expression(expression) => print_expression(expression), } - for note in typing_pass.critical { - println!("{:?}", note.with_source_code(input.to_string())); + // let typing_pass = passer::typing::TypingPasser::pass(&symbol).unwrap(); + + // for note in typing_pass.non_critical { + // println!("{:?}", note.with_source_code(input.to_string())); + // } + + // for note in typing_pass.critical { + // println!("{:?}", note.with_source_code(input.to_string())); + // } +} + +fn print_expression(expression: Expression) { + println!( + "{:?} of type ({:?})", + expression, + expression.possible_types() + ); +} + +fn print_statement(statement: Statement) { + match statement { + Statement::Block(statements) => { + for statement in statements { + print_statement(statement); + } + } + Statement::Expression(expression) => print_expression(expression), + _ => println!("{:?}", statement), } } @@ -79,7 +99,8 @@ impl miette::highlighters::HighlighterState for SomHighlighterState { | TokenKind::Struct | TokenKind::Enum | TokenKind::Function - | TokenKind::Trait => Style::new().fg_rgb::<197, 120, 221>(), + | 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::Integer | TokenKind::Decimal => { diff --git a/src/parser/ast.rs b/src/parser/ast.rs index c59bac6..37d1f4a 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -31,6 +31,12 @@ pub enum Statement<'de> { name: Cow<'de, str>, functions: Vec>, }, + Return(Expression<'de>), + Conditional { + condition: Box>, + truthy: Box>, + falsy: Option>>, + }, } #[derive(Debug)] @@ -50,10 +56,10 @@ pub enum Expression<'de> { statements: Vec>, return_value: Box>, }, - If { + Conditional { condition: Box>, truthy: Box>, - falsy: Option>>, + falsy: Box>, }, Call { callee: Box>, diff --git a/src/parser/lookup.rs b/src/parser/lookup.rs index 3977343..d451f52 100644 --- a/src/parser/lookup.rs +++ b/src/parser/lookup.rs @@ -120,7 +120,7 @@ impl Default for Lookup<'_> { .add_expression_handler(TokenKind::String, expression::primitive::string) .add_expression_handler(TokenKind::Identifier, expression::primitive::identifier) .add_expression_handler(TokenKind::ParenOpen, group) - .add_left_expression_handler(TokenKind::If, BindingPower::None, if_) + .add_left_expression_handler(TokenKind::If, BindingPower::None, conditional) .add_left_expression_handler(TokenKind::ParenOpen, BindingPower::None, expression::call) .add_expression_handler(TokenKind::Not, expression::unary::negate) .add_expression_handler(TokenKind::Minus, expression::unary::negative) @@ -204,31 +204,28 @@ impl Default for Lookup<'_> { .add_type_handler(TokenKind::StringType, typing::string) .add_type_handler(TokenKind::SquareOpen, typing::collection) .add_type_handler(TokenKind::CurlyOpen, typing::set) + .add_statement_handler(TokenKind::Return, statement::return_) + .add_statement_handler(TokenKind::If, statement::if_) } } -fn if_<'de>( +fn conditional<'de>( parser: &mut Parser<'de>, lhs: Expression<'de>, binding_power: BindingPower, ) -> Result> { - let condition = expression::parse(parser, binding_power)?; + let condition = expression::parse(parser, binding_power.clone())?; - let falsy = if parser.lexer.peek().map_or(false, |token| { - token - .as_ref() - .map_or(false, |token| token.kind == TokenKind::Else) - }) { - parser.lexer.next(); - Some(expression::parse(parser, BindingPower::None)?) - } else { - None - }; + parser + .lexer + .expect(TokenKind::Else, "expected an else branch")?; + + let falsy = expression::parse(parser, binding_power)?; - Ok(Expression::If { + Ok(Expression::Conditional { condition: Box::new(condition), truthy: Box::new(lhs), - falsy: falsy.map(Box::new), + falsy: Box::new(falsy), }) } diff --git a/src/parser/statement.rs b/src/parser/statement.rs index 4d5fcba..1b7e766 100644 --- a/src/parser/statement.rs +++ b/src/parser/statement.rs @@ -5,7 +5,7 @@ use super::{ }, expression, lookup::BindingPower, - typing, Parser, + statement, typing, Parser, }; use crate::lexer::{TokenKind, TokenValue}; use miette::{Context, Result}; @@ -358,3 +358,40 @@ pub fn trait_<'de>(parser: &mut Parser<'de>) -> Result> { functions, }) } + +pub fn return_<'de>(parser: &mut Parser<'de>) -> Result> { + parser + .lexer + .expect(TokenKind::Return, "expected a return keyword")?; + + let expression = expression::parse(parser, BindingPower::None)?; + + Ok(Statement::Return(expression)) +} + +pub fn if_<'de>(parser: &mut Parser<'de>) -> Result> { + parser + .lexer + .expect(TokenKind::If, "expected an if keyword")?; + + let condition = expression::parse(parser, BindingPower::None)?; + + let truthy = statement::parse(parser, true)?; + + let falsy = if parser.lexer.peek().map_or(false, |token| { + token + .as_ref() + .map_or(false, |token| token.kind == TokenKind::Else) + }) { + parser.lexer.next(); + Some(statement::parse(parser, true)?) + } else { + None + }; + + Ok(Statement::Conditional { + condition: Box::new(condition), + truthy: Box::new(truthy), + falsy: falsy.map(Box::new), + }) +} diff --git a/src/passer/typing/mod.rs b/src/passer/typing/mod.rs index e126b41..4ff33ce 100644 --- a/src/passer/typing/mod.rs +++ b/src/passer/typing/mod.rs @@ -1,5 +1,5 @@ use super::{Passer, PasserResult}; -use crate::parser::ast::Symbol; +use crate::parser::ast::{Expression, Statement, Symbol, Type}; use miette::{Result, Severity}; pub struct TypingPasser; @@ -9,15 +9,54 @@ impl Passer for TypingPasser { let mut critical = vec![]; let mut non_critical = vec![]; - non_critical.push(miette::miette! { - severity = Severity::Warning, - labels = vec![miette::LabeledSpan::at(100, "uwu")], - "Typing is not yet implemented" - }); - Ok(PasserResult { critical, non_critical, }) } } + +pub trait Typing { + fn possible_types(&self) -> Vec; +} + +impl Typing for Expression<'_> { + fn possible_types(&self) -> Vec { + match self { + Expression::Primitive(primitive) => vec![match primitive { + crate::parser::ast::Primitive::Integer(_) => Type::Integer, + crate::parser::ast::Primitive::Decimal(_) => Type::Decimal, + crate::parser::ast::Primitive::String(_) => Type::String, + crate::parser::ast::Primitive::Identifier(value) => Type::Symbol(value.clone()), + crate::parser::ast::Primitive::Character(_) => Type::Character, + crate::parser::ast::Primitive::Boolean(_) => Type::Boolean, + crate::parser::ast::Primitive::Unit => Type::Unit, + }], + Expression::Binary { + operator, + left, + right, + } => { + let mut types = left.possible_types(); + types.extend(right.possible_types()); + types + } + Expression::Unary { operator, operand } => operand.possible_types(), + Expression::Group(expression) => expression.possible_types(), + Expression::Block { + statements, + return_value, + } => return_value.possible_types(), + Expression::Conditional { + condition, + truthy, + falsy, + } => { + let mut types = truthy.possible_types(); + types.extend(falsy.possible_types()); + types + } + Expression::Call { callee, arguments } => callee.possible_types(), + } + } +}