diff --git a/hello-world.fddl b/hello-world.fddl index c267dfe..c4431d2 100644 --- a/hello-world.fddl +++ b/hello-world.fddl @@ -1,3 +1,3 @@ func main() { - print(`hello, world in fddl`); + print("hello, world in fddl"); } diff --git a/hello.fddl b/hello.fddl new file mode 100644 index 0000000..37b2f46 --- /dev/null +++ b/hello.fddl @@ -0,0 +1,5 @@ +!test + +func main() { + print("Hello World"); +} diff --git a/readme.md b/readme.md index c8dc30e..0d9646a 100644 --- a/readme.md +++ b/readme.md @@ -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. diff --git a/src/lexer/lexer.rs b/src/lexer/lexer.rs index 3216b3b..656968b 100644 --- a/src/lexer/lexer.rs +++ b/src/lexer/lexer.rs @@ -23,7 +23,12 @@ impl Lexer { while !self.is_at_end() { self.start = self.current; if let Some(token) = self.scan_token() { - tokens.push(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), }; diff --git a/src/lexer/token.rs b/src/lexer/token.rs index 0210082..1426a28 100644 --- a/src/lexer/token.rs +++ b/src/lexer/token.rs @@ -43,9 +43,14 @@ pub enum Token { Print, Pub, Sym, + Module, + Import, // Comments Comment(String), + // Errors + Error(String), + EOF, } diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 8567eb3..c3c7eb1 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -1,9 +1,47 @@ -// placeholder for ast defintions - pub enum Expression { - // Define expression types + Literal(Literal), + Variable(String), + Binary(Box, Operator, Box), + Unary(Operator, Box), + Grouping(Box), + Assignment(String, Box), + FunctionCall(Box, Vec), +} + +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), + Block(Vec), + IfStatement(Expression, Box, Option>), + WhileStatement(Expression, Box), + ForStatement(Box, Expression, Box, Box), + FunctionDeclaration { + name: String, + params: Vec, + body: Vec, + }, + ReturnStatement(Option), } \ No newline at end of file diff --git a/src/parser/parser.rs b/src/parser/parser.rs new file mode 100644 index 0000000..e2baa9e --- /dev/null +++ b/src/parser/parser.rs @@ -0,0 +1,66 @@ +use crate::lexer::token::Token; + +pub struct Parser { + tokens: Vec, + current: usize, +} + +impl Parser { + fn parse_statement(&mut self) -> Option { + if self.match_token(Token::Print) { + self.parse_print_statement() + } + } + + + pub fn new(tokens: Vec) -> 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(); + } +} \ No newline at end of file