diff --git a/src/main.rs b/src/main.rs index a7bd084..01c9744 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use lexer::{Lexer, TokenKind}; use owo_colors::{Style, Styled}; use parser::{ - ast::{Expression, Statement}, + ast::{Expression, ExpressionValue, Statement}, Parser, }; use passer::{typing::Typing, Passer}; @@ -11,6 +11,19 @@ pub mod lexer; 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) +} +"; + fn main() { miette::set_hook(Box::new(|_| { Box::new( @@ -24,79 +37,24 @@ fn main() { })) .unwrap(); - let input = " - fn main() { - fib(9999); - } - - fn fib(n ~ int) ~ int { - let n = 12; - - if n < 2 return n; - fib(n - 1) + fib(n - 20) - } - "; - - let mut parser = Parser::new(input); + let mut parser = Parser::new(INPUT); let symbol = match parser.parse() { Ok(symbol) => symbol, Err(err) => { - println!("{:?}", err.with_source_code(input.to_string())); + println!("{:?}", err.with_source_code(INPUT)); return; } }; - match &symbol { - parser::ast::Symbol::Statement(statement) => print_statement(statement), - parser::ast::Symbol::Expression(expression) => print_expression(expression), - } - - // 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())); - // } -} + let typing_pass = passer::typing::TypingPasser::pass(&symbol).unwrap(); -fn print_expression(expression: &Expression) { - match &expression { - Expression::Block { - statements, - return_value, - } => { - for statement in statements { - print_statement(statement); - } - print_expression(return_value); - } - Expression::Group(expression) => print_expression(expression), - e => println!("{:?} typeof {:?}", e, e.possible_types()), + for note in typing_pass.non_critical { + println!("{:?}", note.with_source_code(INPUT)); } -} -fn print_statement(statement: &Statement) { - match statement { - Statement::Block(statements) => { - for statement in statements { - print_statement(statement); - } - } - Statement::Function { - header, - body, - explicit_return_type, - } => { - print_expression(body); - } - Statement::Return(expression) => print_expression(expression), - Statement::Expression(expression) => print_expression(expression), - Statement::Assignment { name, value } => print_expression(value), - _ => {} - }; + for note in typing_pass.critical { + println!("{:?}", note.with_source_code(INPUT)); + } } struct SomHighlighter {} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index b8afe58..e171ffa 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,5 +1,7 @@ use std::borrow::Cow; +use miette::SourceSpan; + #[derive(Debug, Clone)] pub enum Symbol<'de> { Statement(Statement<'de>), @@ -40,7 +42,47 @@ pub enum Statement<'de> { } #[derive(Debug, Clone)] -pub enum Expression<'de> { +pub struct Expression<'de> { + pub value: ExpressionValue<'de>, + pub span: miette::SourceSpan, +} + +impl<'de> Expression<'de> { + pub fn at(span: miette::SourceSpan, value: ExpressionValue<'de>) -> Self { + Self { value, span } + } + + pub fn at_multiple( + spans: Vec>, + value: ExpressionValue<'de>, + ) -> Expression<'de> { + let spans = spans.into_iter().map(|s| s.into()).collect::>(); + + let start = spans + .iter() + .min_by_key(|s| s.offset()) + .map(|s| s.offset()) + .unwrap_or(0); + + // Go through all the spans and find the one with the highest end offset + let end = spans + .iter() + .max_by_key(|s| s.offset() + s.len()) + .map(|s| s.offset() + s.len()) + .unwrap_or(0); + + let span = miette::SourceSpan::new(start.into(), end - start); + + Expression::at(span, value) + } + + pub fn label(&self, text: impl Into) -> miette::LabeledSpan { + miette::LabeledSpan::at(self.span, text.into()) + } +} + +#[derive(Debug, Clone)] +pub enum ExpressionValue<'de> { Primitive(Primitive<'de>), Binary { operator: BinaryOperator, diff --git a/src/parser/expression/binary.rs b/src/parser/expression/binary.rs index b1b2cb8..35ef41f 100644 --- a/src/parser/expression/binary.rs +++ b/src/parser/expression/binary.rs @@ -1,5 +1,5 @@ use crate::parser::{ - ast::{BinaryOperator, Expression}, + ast::{BinaryOperator, Expression, ExpressionValue}, lookup::BindingPower, Parser, }; @@ -13,11 +13,14 @@ pub fn parse_binary_expression<'de>( ) -> Result> { let rhs = crate::parser::expression::parse(parser, bp)?; - Ok(Expression::Binary { - operator, - left: Box::new(lhs), - right: Box::new(rhs), - }) + Ok(Expression::at_multiple( + vec![rhs.span, lhs.span], + ExpressionValue::Binary { + operator, + left: Box::new(lhs), + right: Box::new(rhs), + }, + )) } pub fn addition<'de>( diff --git a/src/parser/expression/mod.rs b/src/parser/expression/mod.rs index 8850455..b14a22f 100644 --- a/src/parser/expression/mod.rs +++ b/src/parser/expression/mod.rs @@ -1,6 +1,9 @@ use miette::Result; -use super::{ast::Expression, Parser}; +use super::{ + ast::{Expression, ExpressionValue}, + Parser, +}; use crate::{lexer::TokenKind, parser::lookup::BindingPower}; pub mod binary; @@ -94,8 +97,11 @@ pub fn call<'de>( .lexer .expect(TokenKind::ParenClose, "expected a closing parenthesis")?; - Ok(Expression::Call { - callee: Box::new(lhs), - arguments, - }) + Ok(Expression::at( + lhs.span, + ExpressionValue::Call { + callee: Box::new(lhs.clone()), + arguments, + }, + )) } diff --git a/src/parser/expression/primitive.rs b/src/parser/expression/primitive.rs index a234364..5fd33be 100644 --- a/src/parser/expression/primitive.rs +++ b/src/parser/expression/primitive.rs @@ -1,7 +1,7 @@ use crate::{ lexer::{TokenKind, TokenValue}, parser::{ - ast::{Expression, Primitive}, + ast::{Expression, ExpressionValue, Primitive}, Parser, }, }; @@ -17,7 +17,10 @@ pub fn integer<'de>(parser: &mut Parser) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::Integer(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::Integer(value)), + )) } pub fn decimal<'de>(parser: &mut Parser) -> Result> { @@ -30,7 +33,10 @@ pub fn decimal<'de>(parser: &mut Parser) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::Decimal(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::Decimal(value)), + )) } pub fn boolean<'de>(parser: &mut Parser) -> Result> { @@ -43,7 +49,10 @@ pub fn boolean<'de>(parser: &mut Parser) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::Boolean(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::Boolean(value)), + )) } pub fn character<'de>(parser: &mut Parser) -> Result> { @@ -56,7 +65,10 @@ pub fn character<'de>(parser: &mut Parser) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::Character(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::Character(value)), + )) } pub fn string<'de>(parser: &mut Parser<'de>) -> Result> { @@ -69,7 +81,10 @@ pub fn string<'de>(parser: &mut Parser<'de>) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::String(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::String(value)), + )) } pub fn identifier<'de>(parser: &mut Parser<'de>) -> Result> { @@ -82,5 +97,8 @@ pub fn identifier<'de>(parser: &mut Parser<'de>) -> Result> { _ => unreachable!(), }; - Ok(Expression::Primitive(Primitive::Identifier(value))) + Ok(Expression::at( + token.span, + ExpressionValue::Primitive(Primitive::Identifier(value)), + )) } diff --git a/src/parser/expression/unary.rs b/src/parser/expression/unary.rs index c5de31f..bf64043 100644 --- a/src/parser/expression/unary.rs +++ b/src/parser/expression/unary.rs @@ -1,7 +1,7 @@ use crate::{ lexer::TokenKind, parser::{ - ast::{Expression, UnaryOperator}, + ast::{Expression, ExpressionValue, UnaryOperator}, lookup::BindingPower, Parser, }, @@ -9,25 +9,31 @@ use crate::{ use miette::Result; pub fn negate<'de>(parser: &mut Parser<'de>) -> Result> { - parser + let token = parser .lexer .expect(TokenKind::Not, "expected a negate operator")?; let expression = crate::parser::expression::parse(parser, BindingPower::None)?; - Ok(Expression::Unary { - operator: UnaryOperator::Negate, - operand: Box::new(expression), - }) + Ok(Expression::at_multiple( + vec![token.span, expression.span], + ExpressionValue::Unary { + operator: UnaryOperator::Negate, + operand: Box::new(expression), + }, + )) } pub fn negative<'de>(parser: &mut Parser<'de>) -> Result> { - parser + let token = parser .lexer .expect(TokenKind::Minus, "expected a negative operator")?; let expression = crate::parser::expression::parse(parser, BindingPower::None)?; - Ok(Expression::Unary { - operator: UnaryOperator::Negative, - operand: Box::new(expression), - }) + Ok(Expression::at_multiple( + vec![token.span, expression.span], + ExpressionValue::Unary { + operator: UnaryOperator::Negative, + operand: Box::new(expression), + }, + )) } diff --git a/src/parser/lookup.rs b/src/parser/lookup.rs index d451f52..5e75a8b 100644 --- a/src/parser/lookup.rs +++ b/src/parser/lookup.rs @@ -1,9 +1,9 @@ use super::{ - ast::{Expression, Primitive, Statement, Type}, + ast::{Expression, ExpressionValue, Primitive, Statement, Type}, expression, statement, typing, Parser, }; -use crate::lexer::TokenKind; -use miette::Result; +use crate::lexer::{TokenKind, TokenValue}; +use miette::{Result, SourceSpan}; use std::collections::HashMap; #[derive(Debug, Clone, PartialEq, PartialOrd)] @@ -216,33 +216,39 @@ fn conditional<'de>( ) -> Result> { let condition = expression::parse(parser, binding_power.clone())?; - parser + let token = parser .lexer .expect(TokenKind::Else, "expected an else branch")?; let falsy = expression::parse(parser, binding_power)?; - Ok(Expression::Conditional { - condition: Box::new(condition), - truthy: Box::new(lhs), - falsy: Box::new(falsy), - }) + Ok(Expression::at_multiple( + vec![condition.span, token.span, falsy.span], + ExpressionValue::Conditional { + condition: Box::new(condition), + truthy: Box::new(lhs), + falsy: Box::new(falsy), + }, + )) } fn group<'de>(parser: &mut Parser<'de>) -> Result> { - parser + let open = parser .lexer .expect(TokenKind::ParenOpen, "expected a left parenthesis")?; let expression = expression::parse(parser, BindingPower::None)?; - parser + let close = parser .lexer .expect(TokenKind::ParenClose, "expected a right parenthesis")?; - Ok(Expression::Group(Box::new(expression))) + Ok(Expression::at_multiple( + vec![open.span, expression.span, close.span], + ExpressionValue::Group(Box::new(expression)), + )) } fn block<'de>(parser: &mut Parser<'de>) -> Result> { - parser + let open = parser .lexer .expect(TokenKind::CurlyOpen, "expected a left curly brace")?; @@ -286,20 +292,32 @@ fn block<'de>(parser: &mut Parser<'de>) -> Result> { Some(Statement::Expression(expression)) => expression, _ => unreachable!(), }, - _ => Expression::Primitive(Primitive::Unit), + _ => Expression::at( + SourceSpan::new(0.into(), 0), + ExpressionValue::Primitive(Primitive::Unit), + ), } } else { - Expression::Primitive(Primitive::Unit) + Expression::at( + SourceSpan::new(0.into(), 0), + ExpressionValue::Primitive(Primitive::Unit), + ) }; - let expression = Expression::Block { - statements, - return_value: Box::new(return_value), - }; + let expression = Expression::at( + return_value.span, + ExpressionValue::Block { + statements, + return_value: Box::new(return_value), + }, + ); - parser + let close = parser .lexer .expect(TokenKind::CurlyClose, "expected a right curly brace")?; - Ok(Expression::Group(Box::new(expression))) + Ok(Expression::at_multiple( + vec![open.span, close.span], + ExpressionValue::Group(Box::new(expression)), + )) } diff --git a/src/passer/typing/mod.rs b/src/passer/typing/mod.rs index 4ff33ce..113a81d 100644 --- a/src/passer/typing/mod.rs +++ b/src/passer/typing/mod.rs @@ -1,39 +1,67 @@ use super::{Passer, PasserResult}; -use crate::parser::ast::{Expression, Statement, Symbol, Type}; -use miette::{Result, Severity}; +use crate::parser::{ + ast::{Expression, ExpressionValue, Statement, Symbol, Type}, + expression, +}; +use miette::{Error, LabeledSpan, Report, Result}; pub struct TypingPasser; impl Passer for TypingPasser { fn pass(ast: &Symbol<'_>) -> Result { - let mut critical = vec![]; - let mut non_critical = vec![]; + todo!() + } +} + - Ok(PasserResult { - critical, - non_critical, - }) +pub fn walk_statement<'de>(statement: &Statement<'de>, statement_fn: fn(&Statement<'de>, expression_fn: fn(&Expression<'de>)) { + match statement { + Statement::Block(statements) => statements.iter().for_each(|statement| { + walk_statement(statement, statement_fn); + }), + Statement::Expression(expression) => walk_expression(expression), + Statement::Assignment { name, value } => walk_expression(expression, expression_fn), + Statement::Struct { name, fields } => todo!(), + Statement::Enum { name, variants } => todo!(), + Statement::Function { + header, + body, + explicit_return_type, + } => todo!(), + Statement::Trait { name, functions } => todo!(), + Statement::Return(expression) => todo!(), + Statement::Conditional { + condition, + truthy, + falsy, + } => todo!(), } } +pub fn walk_expression<'de, T>(expression: Expression<'de>, statement_fn: fn(&Statement<'de>, expression_fn: fn(&Expression<'de>)) { + +} + pub trait Typing { - fn possible_types(&self) -> Vec; + fn possible_types(&self) -> Vec<(Type, miette::SourceSpan)>; } 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, + fn possible_types(&self) -> Vec<(Type, miette::SourceSpan)> { + match &self.value { + ExpressionValue::Primitive(primitive) => vec![match primitive { + crate::parser::ast::Primitive::Integer(_) => (Type::Integer, self.span), + crate::parser::ast::Primitive::Decimal(_) => (Type::Decimal, self.span), + crate::parser::ast::Primitive::String(_) => (Type::String, self.span), + crate::parser::ast::Primitive::Identifier(value) => { + (Type::Symbol(value.clone()), self.span) + } + crate::parser::ast::Primitive::Character(_) => (Type::Character, self.span), + crate::parser::ast::Primitive::Boolean(_) => (Type::Boolean, self.span), + crate::parser::ast::Primitive::Unit => (Type::Unit, self.span), }], - Expression::Binary { - operator, + ExpressionValue::Binary { + operator: _, left, right, } => { @@ -41,14 +69,17 @@ impl Typing for Expression<'_> { types.extend(right.possible_types()); types } - Expression::Unary { operator, operand } => operand.possible_types(), - Expression::Group(expression) => expression.possible_types(), - Expression::Block { - statements, + ExpressionValue::Unary { + operator: _, + operand, + } => operand.possible_types(), + ExpressionValue::Group(expression) => expression.possible_types(), + ExpressionValue::Block { + statements: _, return_value, } => return_value.possible_types(), - Expression::Conditional { - condition, + ExpressionValue::Conditional { + condition: _, truthy, falsy, } => { @@ -56,7 +87,10 @@ impl Typing for Expression<'_> { types.extend(falsy.possible_types()); types } - Expression::Call { callee, arguments } => callee.possible_types(), + ExpressionValue::Call { + callee, + arguments: _, + } => callee.possible_types(), } } }