wip
This commit is contained in:
16
src/ast.rs
16
src/ast.rs
@ -4,20 +4,28 @@ pub struct Module {
|
|||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
FunctionDeclaration {
|
FunctionDeclaration {
|
||||||
name: Token,
|
name: Token,
|
||||||
parameters: Vec<ParameterDeclaration>,
|
parameters: Vec<ParameterDeclaration>,
|
||||||
|
statements: Vec<Statement>,
|
||||||
},
|
},
|
||||||
Expression,
|
Expression(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ParameterDeclaration {
|
pub struct ParameterDeclaration {
|
||||||
name: Token,
|
pub name: Token,
|
||||||
typename: Token,
|
pub typename: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Identifier(Token),
|
Identifier(Token),
|
||||||
FunctionCall {},
|
FunctionCall {
|
||||||
|
function: Box<Expression>,
|
||||||
|
arguments: Vec<Expression>,
|
||||||
|
return_type: Option<Token>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
33
src/main.rs
33
src/main.rs
@ -1,4 +1,4 @@
|
|||||||
use token::Token;
|
use parse::Parser;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod format;
|
mod format;
|
||||||
@ -7,34 +7,21 @@ mod parse;
|
|||||||
mod token;
|
mod token;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
use format::Formatter;
|
||||||
}
|
use lexer::Lexer;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::{
|
|
||||||
format::Formatter,
|
|
||||||
lexer::{self, Lexer},
|
|
||||||
};
|
|
||||||
|
|
||||||
const BASIC: &str = r#"
|
const BASIC: &str = r#"
|
||||||
function hello(name: string){
|
function hello(name: string){
|
||||||
console.log("Hey, ", name);
|
println("Hey, ", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
console.log("Starting!");
|
println("Starting!");
|
||||||
|
|
||||||
hello();
|
hello();
|
||||||
"#;
|
"#;
|
||||||
#[test]
|
let lexer = Lexer::new(BASIC, Some("basic.file".to_string()));
|
||||||
fn lex() {
|
let tokens = lexer.lex();
|
||||||
println!("Running lex");
|
let mut parser = Parser::new(tokens);
|
||||||
let lexer = Lexer::new(BASIC, Some("basic.file".to_string()));
|
let statement = parser.statement();
|
||||||
let tokens = lexer.lex();
|
println!("{statement:?}");
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
tokens.format(crate::format::FormatterOptions {}).unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
13
src/parse.rs
13
src/parse.rs
@ -1,13 +0,0 @@
|
|||||||
use crate::token::Token;
|
|
||||||
|
|
||||||
pub struct Parser {
|
|
||||||
tokens: Vec<Token>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parser {
|
|
||||||
pub fn new(tokens: Vec<Token>) -> Parser {
|
|
||||||
Self { tokens }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse(&mut self) {}
|
|
||||||
}
|
|
55
src/parse/macros.rs
Normal file
55
src/parse/macros.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect_token {
|
||||||
|
($self:ident, $expect:pat) => {
|
||||||
|
let t = $self.consume();
|
||||||
|
if !matches!(t.kind, $expect) {
|
||||||
|
todo!("Expected token, found {:?}", t.kind)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect_identifier {
|
||||||
|
($self:ident) => {{
|
||||||
|
let t = $self.consume();
|
||||||
|
if !matches!(t.kind, TokenKind::Identifier(_)) {
|
||||||
|
todo!("Expected token, found {:?}", t.kind)
|
||||||
|
}
|
||||||
|
t
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! expect_any_keyword {
|
||||||
|
($self:ident) => {{
|
||||||
|
let t = $self.consume();
|
||||||
|
if !matches!(t.kind, TokenKind::Keyword(_)) {
|
||||||
|
todo!("Expected token, found {:?}", t.kind)
|
||||||
|
}
|
||||||
|
t
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! peek_keyword {
|
||||||
|
($self:ident, $keyword:pat) => {
|
||||||
|
matches!($self.peek().kind, TokenKind::Keyword($keyword))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! peek_match {
|
||||||
|
($self:ident, $p:pat) => {
|
||||||
|
matches!($self.peek().kind, $p)
|
||||||
|
};
|
||||||
|
}
|
77
src/parse/mod.rs
Normal file
77
src/parse/mod.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
mod macros;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast, expect_any_keyword, expect_identifier, expect_keyword, expect_token, peek_keyword,
|
||||||
|
peek_match,
|
||||||
|
token::{KeywordKind, Token, TokenKind},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Parser {
|
||||||
|
tokens: Vec<Token>,
|
||||||
|
current: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn new(tokens: Vec<Token>) -> Parser {
|
||||||
|
Self { tokens, current: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn statement(&mut self) -> ast::Statement {
|
||||||
|
if peek_keyword!(self, KeywordKind::function) {
|
||||||
|
return self.function_declaration();
|
||||||
|
}
|
||||||
|
return self.expression_statement();
|
||||||
|
todo!("No statement");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn function_declaration(&mut self) -> ast::Statement {
|
||||||
|
expect_keyword!(self, KeywordKind::function);
|
||||||
|
let id = expect_identifier!(self);
|
||||||
|
expect_token!(self, TokenKind::LeftParen);
|
||||||
|
|
||||||
|
let mut parameters = Vec::new();
|
||||||
|
while peek_match!(self, TokenKind::Identifier(_)) {
|
||||||
|
let name = expect_identifier!(self);
|
||||||
|
expect_token!(self, TokenKind::Colon);
|
||||||
|
let typename = expect_any_keyword!(self);
|
||||||
|
let parameter = ast::ParameterDeclaration {
|
||||||
|
name: name.clone(),
|
||||||
|
typename: typename.clone(),
|
||||||
|
};
|
||||||
|
parameters.push(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_token!(self, TokenKind::RightParen);
|
||||||
|
|
||||||
|
expect_token!(self, TokenKind::LeftCurly);
|
||||||
|
|
||||||
|
let mut statements = Vec::new();
|
||||||
|
while !peek_match!(self, TokenKind::RightCurly) {
|
||||||
|
let statement = self.statement();
|
||||||
|
statements.push(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_token!(self, TokenKind::RightCurly);
|
||||||
|
|
||||||
|
ast::Statement::FunctionDeclaration {
|
||||||
|
name: id.clone(),
|
||||||
|
parameters,
|
||||||
|
statements,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression_statement(&mut self) -> ast::Statement {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
fn peek(&self) -> &Token {
|
||||||
|
&self.tokens[self.current]
|
||||||
|
}
|
||||||
|
fn consume(&mut self) -> Token {
|
||||||
|
let token = &self.tokens[self.current];
|
||||||
|
self.current += 1;
|
||||||
|
token.clone()
|
||||||
|
}
|
||||||
|
}
|
14
src/token.rs
14
src/token.rs
@ -1,12 +1,12 @@
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub kind: TokenKind,
|
pub kind: TokenKind,
|
||||||
pub location: TokenLocation,
|
pub location: TokenLocation,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Literal(LiteralKind),
|
Literal(LiteralKind),
|
||||||
@ -25,14 +25,14 @@ pub enum TokenKind {
|
|||||||
EndOfFile,
|
EndOfFile,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum CommentKind {
|
pub enum CommentKind {
|
||||||
Line,
|
Line,
|
||||||
Block,
|
Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum KeywordKind {
|
pub enum KeywordKind {
|
||||||
function,
|
function,
|
||||||
string,
|
string,
|
||||||
@ -51,19 +51,19 @@ impl TryFrom<&str> for KeywordKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum LiteralKind {
|
pub enum LiteralKind {
|
||||||
String(String),
|
String(String),
|
||||||
Number(Number),
|
Number(Number),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Number {
|
pub enum Number {
|
||||||
Integer(usize),
|
Integer(usize),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TokenLocation {
|
pub struct TokenLocation {
|
||||||
pub file: Option<String>,
|
pub file: Option<String>,
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
|
Reference in New Issue
Block a user