parsed ast of basic application
This commit is contained in:
23
src/ast/expression.rs
Normal file
23
src/ast/expression.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::token::{LiteralKind, Number, Token};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expression {
|
||||
Literal {
|
||||
literal: LiteralKind,
|
||||
token: Token,
|
||||
},
|
||||
Unary,
|
||||
Binary,
|
||||
Call {
|
||||
callee: Box<Expression>,
|
||||
arguments: Vec<Expression>,
|
||||
},
|
||||
Grouping,
|
||||
Variable {
|
||||
name: String,
|
||||
token: Token,
|
||||
},
|
||||
}
|
||||
|
||||
pub enum BinaryOperator {}
|
||||
pub enum UnaryOperator {}
|
@ -1,5 +1,9 @@
|
||||
mod expression;
|
||||
pub use expression::*;
|
||||
|
||||
use crate::token::Token;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub statements: Vec<Statement>,
|
||||
}
|
||||
@ -19,13 +23,3 @@ pub struct ParameterDeclaration {
|
||||
pub name: Token,
|
||||
pub typename: Token,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expression {
|
||||
Identifier(Token),
|
||||
FunctionCall {
|
||||
function: Box<Expression>,
|
||||
arguments: Vec<Expression>,
|
||||
return_type: Option<Token>,
|
||||
},
|
||||
}
|
@ -31,6 +31,7 @@ impl Lexer {
|
||||
self.next_token();
|
||||
}
|
||||
self.clean_newlines();
|
||||
self.push(TokenKind::EndOfFile);
|
||||
self.tokens
|
||||
}
|
||||
|
||||
@ -118,9 +119,6 @@ impl Lexer {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if self.is_eof() {
|
||||
todo!("Not sure if handling is necessary")
|
||||
}
|
||||
let s = self.current_scan(0, 0);
|
||||
if let Ok(k) = TryInto::<KeywordKind>::try_into(s.as_str()) {
|
||||
self.push(TokenKind::Keyword(k));
|
||||
|
@ -7,7 +7,6 @@ mod parse;
|
||||
mod token;
|
||||
|
||||
fn main() {
|
||||
use format::Formatter;
|
||||
use lexer::Lexer;
|
||||
const BASIC: &str = r#"
|
||||
function hello(name: string){
|
||||
@ -22,6 +21,6 @@ hello();
|
||||
let lexer = Lexer::new(BASIC, Some("basic.file".to_string()));
|
||||
let tokens = lexer.lex();
|
||||
let mut parser = Parser::new(tokens);
|
||||
let statement = parser.statement();
|
||||
println!("{statement:?}");
|
||||
let module = parser.module();
|
||||
println!("{module:?}");
|
||||
}
|
||||
|
74
src/parse/expression.rs
Normal file
74
src/parse/expression.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use crate::{ast, expect_token, get_token, match_token, token::TokenKind};
|
||||
|
||||
use super::Parser;
|
||||
|
||||
impl Parser {
|
||||
pub fn expression(&mut self) -> ast::Expression {
|
||||
self.call()
|
||||
}
|
||||
fn equality(&mut self) -> ast::Expression {
|
||||
todo!()
|
||||
}
|
||||
fn comparison(&mut self) -> ast::Expression {
|
||||
todo!()
|
||||
}
|
||||
fn term(&mut self) -> ast::Expression {
|
||||
todo!()
|
||||
}
|
||||
fn factor(&mut self) -> ast::Expression {
|
||||
todo!()
|
||||
}
|
||||
fn unary(&mut self) -> ast::Expression {
|
||||
todo!()
|
||||
}
|
||||
fn call(&mut self) -> ast::Expression {
|
||||
let mut e = self.primary();
|
||||
|
||||
if match_token!(self, TokenKind::LeftParen) {
|
||||
let mut arguments = Vec::new();
|
||||
while !match_token!(self, TokenKind::RightParen) {
|
||||
arguments.push(self.expression());
|
||||
if !match_token!(self, TokenKind::Comma) {
|
||||
expect_token!(self, TokenKind::RightParen, "RightParen");
|
||||
break;
|
||||
}
|
||||
}
|
||||
e = ast::Expression::Call {
|
||||
callee: Box::new(e),
|
||||
arguments,
|
||||
}
|
||||
}
|
||||
|
||||
e
|
||||
}
|
||||
fn primary(&mut self) -> ast::Expression {
|
||||
if let Some((token, TokenKind::Literal(literal))) = get_token!(self, TokenKind::Literal(_))
|
||||
{
|
||||
return ast::Expression::Literal { literal, token };
|
||||
}
|
||||
|
||||
if let Some((token, TokenKind::Identifier(name))) =
|
||||
get_token!(self, TokenKind::Identifier(_))
|
||||
{
|
||||
return ast::Expression::Variable { name, token };
|
||||
}
|
||||
|
||||
todo!("Unknown expression {:?}", self.peek())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{ast::Expression, lexer::Lexer, parse::Parser, token::TokenKind};
|
||||
|
||||
#[test]
|
||||
fn test_identifier() {
|
||||
let tokens = Lexer::new("my_var", None).lex();
|
||||
let mut parser = Parser::new(tokens);
|
||||
let expr = parser.expression();
|
||||
let Expression::Variable { name, token } = expr else {
|
||||
panic!()
|
||||
};
|
||||
assert_eq!("my_var", name)
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
#[macro_export]
|
||||
macro_rules! expect_token {
|
||||
($self:ident, $expect:pat) => {
|
||||
($self:ident, $expect:pat, $help:literal) => {
|
||||
let t = $self.consume();
|
||||
if !matches!(t.kind, $expect) {
|
||||
todo!("Expected token, found {:?}", t.kind)
|
||||
let kind = t.as_ref().map(|t| &t.kind);
|
||||
if !matches!(kind, Some($expect)) {
|
||||
todo!("Expected token ({}), found {:?}.", $help, t)
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -12,10 +13,11 @@ macro_rules! expect_token {
|
||||
macro_rules! expect_identifier {
|
||||
($self:ident) => {{
|
||||
let t = $self.consume();
|
||||
if !matches!(t.kind, TokenKind::Identifier(_)) {
|
||||
todo!("Expected token, found {:?}", t.kind)
|
||||
let kind = t.as_ref().map(|t| &t.kind);
|
||||
if !matches!(kind, Some(TokenKind::Identifier(_))) {
|
||||
todo!("Expected identifier, found {:?}", t);
|
||||
}
|
||||
t
|
||||
t.unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
@ -23,10 +25,11 @@ macro_rules! expect_identifier {
|
||||
macro_rules! expect_any_keyword {
|
||||
($self:ident) => {{
|
||||
let t = $self.consume();
|
||||
if !matches!(t.kind, TokenKind::Keyword(_)) {
|
||||
todo!("Expected token, found {:?}", t.kind)
|
||||
let kind = t.as_ref().map(|t| &t.kind);
|
||||
if !matches!(kind, Some(TokenKind::Keyword(_))) {
|
||||
todo!("Expected keyword, found {:?}", t)
|
||||
}
|
||||
t
|
||||
t.unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ macro_rules! expect_any_keyword {
|
||||
macro_rules! expect_keyword {
|
||||
($self:ident, $keyword:pat) => {
|
||||
let t = $self.consume();
|
||||
if !matches!(t.kind, TokenKind::Keyword($keyword)) {
|
||||
todo!("Expected token, found {:?}", t.kind)
|
||||
let kind = t.as_ref().map(|t| &t.kind);
|
||||
if !matches!(kind, Some(TokenKind::Keyword($keyword))) {
|
||||
todo!("Expected keyword, found {:?}", t)
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -43,13 +47,39 @@ macro_rules! expect_keyword {
|
||||
#[macro_export]
|
||||
macro_rules! peek_keyword {
|
||||
($self:ident, $keyword:pat) => {
|
||||
matches!($self.peek().kind, TokenKind::Keyword($keyword))
|
||||
matches!(
|
||||
$self.peek().map(|t| &t.kind),
|
||||
Some(TokenKind::Keyword($keyword))
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! peek_match {
|
||||
($self:ident, $p:pat) => {
|
||||
matches!($self.peek().kind, $p)
|
||||
matches!($self.peek().map(|t| &t.kind), Some($p))
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! match_token {
|
||||
($self:ident, $p:pat) => {{
|
||||
let b = matches!($self.peek().map(|t| &t.kind), Some($p));
|
||||
if b {
|
||||
$self.consume();
|
||||
}
|
||||
b
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_token {
|
||||
($self:ident, $p:pat) => {{
|
||||
let b = matches!($self.peek().map(|t| &t.kind), Some($p));
|
||||
if b {
|
||||
$self.consume().map(|t| (t.clone(), t.kind))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
mod expression;
|
||||
mod macros;
|
||||
|
||||
use crate::{
|
||||
ast, expect_any_keyword, expect_identifier, expect_keyword, expect_token, peek_keyword,
|
||||
peek_match,
|
||||
ast, expect_any_keyword, expect_identifier, expect_keyword, expect_token, match_token,
|
||||
peek_keyword, peek_match,
|
||||
token::{KeywordKind, Token, TokenKind},
|
||||
};
|
||||
|
||||
@ -13,26 +14,40 @@ pub struct Parser {
|
||||
|
||||
impl Parser {
|
||||
pub fn new(tokens: Vec<Token>) -> Parser {
|
||||
let tokens = tokens
|
||||
.into_iter()
|
||||
.filter(|t| !matches!(t.kind, TokenKind::NewLine))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Self { tokens, current: 0 }
|
||||
}
|
||||
|
||||
pub fn statement(&mut self) -> ast::Statement {
|
||||
pub fn module(&mut self) -> ast::Module {
|
||||
let mut statements = Vec::new();
|
||||
while !match_token!(self, TokenKind::EndOfFile) {
|
||||
let s = self.statement();
|
||||
println!("Parsed Statement {s:?}");
|
||||
statements.push(s);
|
||||
}
|
||||
ast::Module { statements }
|
||||
}
|
||||
|
||||
fn statement(&mut self) -> ast::Statement {
|
||||
if peek_keyword!(self, KeywordKind::function) {
|
||||
return self.function_declaration();
|
||||
}
|
||||
return self.expression_statement();
|
||||
todo!("No statement");
|
||||
self.expression_statement()
|
||||
}
|
||||
|
||||
fn function_declaration(&mut self) -> ast::Statement {
|
||||
expect_keyword!(self, KeywordKind::function);
|
||||
let id = expect_identifier!(self);
|
||||
expect_token!(self, TokenKind::LeftParen);
|
||||
expect_token!(self, TokenKind::LeftParen, "LeftParen");
|
||||
|
||||
let mut parameters = Vec::new();
|
||||
while peek_match!(self, TokenKind::Identifier(_)) {
|
||||
let name = expect_identifier!(self);
|
||||
expect_token!(self, TokenKind::Colon);
|
||||
expect_token!(self, TokenKind::Colon, "Colon");
|
||||
let typename = expect_any_keyword!(self);
|
||||
let parameter = ast::ParameterDeclaration {
|
||||
name: name.clone(),
|
||||
@ -41,9 +56,9 @@ impl Parser {
|
||||
parameters.push(parameter);
|
||||
}
|
||||
|
||||
expect_token!(self, TokenKind::RightParen);
|
||||
expect_token!(self, TokenKind::RightParen, "RightParen");
|
||||
|
||||
expect_token!(self, TokenKind::LeftCurly);
|
||||
expect_token!(self, TokenKind::LeftCurly, "LeftCurly");
|
||||
|
||||
let mut statements = Vec::new();
|
||||
while !peek_match!(self, TokenKind::RightCurly) {
|
||||
@ -51,7 +66,7 @@ impl Parser {
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
expect_token!(self, TokenKind::RightCurly);
|
||||
expect_token!(self, TokenKind::RightCurly, "RightCurly");
|
||||
|
||||
ast::Statement::FunctionDeclaration {
|
||||
name: id.clone(),
|
||||
@ -61,17 +76,19 @@ impl Parser {
|
||||
}
|
||||
|
||||
fn expression_statement(&mut self) -> ast::Statement {
|
||||
todo!()
|
||||
let e = self.expression();
|
||||
expect_token!(self, TokenKind::Semicolon, "Semicolon");
|
||||
ast::Statement::Expression(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
fn peek(&self) -> &Token {
|
||||
&self.tokens[self.current]
|
||||
fn peek(&self) -> Option<&Token> {
|
||||
self.tokens.get(self.current)
|
||||
}
|
||||
fn consume(&mut self) -> Token {
|
||||
let token = &self.tokens[self.current];
|
||||
fn consume(&mut self) -> Option<Token> {
|
||||
let token = self.peek().cloned();
|
||||
self.current += 1;
|
||||
token.clone()
|
||||
token
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user