building parser

This commit is contained in:
Tristan Smith 2024-09-17 09:48:20 -04:00
parent 6273dbdd7b
commit c08f292bd8
7 changed files with 142 additions and 24 deletions

View file

@ -1,3 +1,3 @@
func main() {
print(`hello, world in fddl`);
print("hello, world in fddl");
}

5
hello.fddl Normal file
View file

@ -0,0 +1,5 @@
!test
func main() {
print("Hello World");
}

View file

@ -27,11 +27,20 @@ To start experimenting with fddl, you can run it in two ways:
cargo run
```
### Run a fddl Script
### Parse a fddl Script
```sh
cargo run path/to/script.fddl
```
## Running the Project
Make sure your project compiles and the tests pass:
```bash
cargo build
cargo test
```
---
## Examples
@ -77,7 +86,7 @@ fddl is very much a work in progress, with lots of planned improvements and addi
- [ ] Currently a placeholder. Implement parsing for function calls, expressions, etc.
- **Compiler**:
- [ ] Currently a placeholder. Implement the compiler to execute parsed code.
- [ ] Currently a placeholder. Implement the compiler to compile parsed code.
- **Comments**:
- [x] Added support for single-line and documentation comments.
@ -85,26 +94,14 @@ fddl is very much a work in progress, with lots of planned improvements and addi
- [ ] Implement document building comments.
- **Error Handling**:
- [ ] Replace basic error reporting with a more robust error handling mechanism.
- **String Interpolation**:
- [ ] Implement string interpolation using backticks with `$variable` syntax.
- [ ] Replace `stderr` with a more robust error handling mechanism.
- **Testing**:
- [x] Added initial lexer tests.
- [x] Added initial `lexer` tests.
- [ ] Expand tests to cover more syntax and edge cases.
---
## Running the Project
Make sure your project compiles and the tests pass:
```bash
cargo build
cargo test
```
## License
This project is licensed under the MIT License.

View file

@ -23,7 +23,12 @@ impl Lexer {
while !self.is_at_end() {
self.start = self.current;
if let Some(token) = self.scan_token() {
if matches!(token, Token::Error(_)) {
tokens.push(token);
break;
} else {
tokens.push(token);
}
}
}
@ -71,7 +76,7 @@ impl Lexer {
if self.match_char('=') {
Some(Token::BangEqual)
} else {
None // Or handle as an error or another token if needed
Some(Token::Error(format!("Unexpected character '{}'", c)))
}
},
'=' => {
@ -111,7 +116,7 @@ impl Lexer {
// Any other character
_ => {
eprintln!("Unexpected character '{}' on line {}", c, self.line);
None
Some(Token::Error(format!("Unexpected character '{}'", c)))
}
}
}
@ -238,6 +243,8 @@ impl Lexer {
"print" => Token::Print,
"pub" => Token::Pub,
"sym" => Token::Sym,
"module" => Token::Module,
"import" => Token::Import,
_ => Token::Identifier(text),
};

View file

@ -43,9 +43,14 @@ pub enum Token {
Print,
Pub,
Sym,
Module,
Import,
// Comments
Comment(String),
// Errors
Error(String),
EOF,
}

View file

@ -1,9 +1,47 @@
// placeholder for ast defintions
pub enum Expression {
// Define expression types
Literal(Literal),
Variable(String),
Binary(Box<Expression>, Operator, Box<Expression>),
Unary(Operator, Box<Expression>),
Grouping(Box<Expression>),
Assignment(String, Box<Expression>),
FunctionCall(Box<Expression>, Vec<Expression>),
}
pub enum Literal {
Number(f64),
String(String),
Boolean(bool),
Nil,
}
pub enum Operator {
Plus,
Minux,
Multiply,
Divide,
Greater,
Less,
GreaterEqual,
LessEqual,
EqualEqual,
NotEqual,
AlmostEqual,
Almost,
}
pub enum Statement {
// Define statement types
ExpressionStatement(Expression),
PrintStatement(Expression),
VariableDeclaration(String, Option<Expression>),
Block(Vec<Statement>),
IfStatement(Expression, Box<Statement>, Option<Box<Statement>>),
WhileStatement(Expression, Box<Statement>),
ForStatement(Box<Statement>, Expression, Box<Statement>, Box<Statement>),
FunctionDeclaration {
name: String,
params: Vec<String>,
body: Vec<Statement>,
},
ReturnStatement(Option<Expression>),
}

66
src/parser/parser.rs Normal file
View file

@ -0,0 +1,66 @@
use crate::lexer::token::Token;
pub struct Parser {
tokens: Vec<Token>,
current: usize,
}
impl Parser {
fn parse_statement(&mut self) -> Option<Statement> {
if self.match_token(Token::Print) {
self.parse_print_statement()
}
}
pub fn new(tokens: Vec<Token>) -> Self {
Parser {
tokens,
current: 0,
}
}
fn current_token(&self) -> &Token {
&self.tokens[self.current]
}
fn peek(&self) -> &Token {
&self.tokens[self.current + 1]
}
fn is_at_end(&self) -> bool {
matches!(self.current_token(), Token::EOF)
}
fn advance(&mut self) -> &Token {
if !self.is_at_end() {
self.current += 1;
}
self.current_token()
}
fn match_token(&mut self, expected: Token) -> bool {
if self.current_token() == &expected {
self.advance();
true
} else {
false
}
}
fn previous_token(&self) -> &Token {
&self.tokens[self.current - 1]
}
}
fn main() {
let source = String::from("let x = 10;");
let mut lexer = Lexer::new(source);
let tokens = lexer.scan_tokens();
let mut parser = Parser::new(tokens);
while !parser.is_at_end() {
println!("{:?}", parser.current_token());
parser.advance();
}
}