Browse Source

Add while loop

github-actions
Garrit Franke 1 year ago
parent
commit
f43aa36432
  1. 1
      README.md
  2. 4
      TODO
  3. 7
      examples/playground.sb
  4. 11
      src/generator/js.rs
  5. 4
      src/lexer/mod.rs
  6. 9
      src/parser/rules.rs
  7. 15
      src/parser/tests.rs

1
README.md

@ -1,6 +1,7 @@
# The Sabre Programming language
[![builds.sr.ht status](https://builds.sr.ht/~garritfra/sabre/commits/ci.yml.svg)](https://builds.sr.ht/~garritfra/sabre/commits/ci.yml?)
[![docs](https://img.shields.io/badge/docs-mdBook-blue.svg)](https://garritfra.github.io/sabre/latest)
Sabre is a bullshit-free (©) programming language that gets out of your way.
It is meant to "just work", without adding unnecessary and bloated language features.

4
TODO

@ -2,8 +2,8 @@
# Features
- Add CLI
- Add else/if else branch to conditionals
- Variable reassignment
- Array access syntax
- Add while loop
- Add for loop
- Add type system

7
examples/playground.sb

@ -1,5 +1,6 @@
// There are no nested expressions yet, so we have to hack a little bit
fn main() {
let arr = ["Foo", "Bar", "Baz"]
let x = 5 * 2
while x > 0 {
return x
}
}

11
src/generator/js.rs

@ -73,7 +73,7 @@ fn generate_statement(statement: Statement) -> String {
generate_conditional(expr, *if_state, else_state.map(|x| *x))
}
Statement::Block(_) => generate_block(statement),
Statement::While(_, _) => todo!(),
Statement::While(expr, body) => generate_while_loop(expr, *body),
}
}
@ -89,6 +89,15 @@ fn generate_expression(expr: Expression) -> String {
}
}
fn generate_while_loop(expr: Expression, body: Statement) -> String {
let mut out_str = String::from("while (");
out_str += &generate_expression(expr);
out_str += ") ";
out_str += &generate_block(body);
out_str
}
fn generate_array(elements: Vec<Expression>) -> String {
let mut out_str = String::from("[");

4
src/lexer/mod.rs

@ -126,6 +126,9 @@ pub enum Keyword {
If,
Else,
Return,
While,
Break,
Continue,
Function,
Boolean,
Unknown,
@ -323,6 +326,7 @@ impl Cursor<'_> {
c if c == "true" || c == "false" => Keyword::Boolean,
c if c == "let" => Keyword::Let,
c if c == "return" => Keyword::Return,
c if c == "while" => Keyword::While,
_ => Keyword::Unknown,
}
}

9
src/parser/rules.rs

@ -94,6 +94,7 @@ impl Parser {
TokenKind::Keyword(Keyword::Let) => self.parse_declare(),
TokenKind::Keyword(Keyword::Return) => self.parse_return(),
TokenKind::Keyword(Keyword::If) => self.parse_conditional_statement(),
TokenKind::Keyword(Keyword::While) => self.parse_while_loop(),
TokenKind::Identifier(_) => {
let ident = self.match_identifier()?;
if let Ok(_) = self.peek_token(TokenKind::BraceOpen) {
@ -217,6 +218,14 @@ impl Parser {
Ok(Expression::Array(elements))
}
fn parse_while_loop(&mut self) -> Result<Statement, String> {
self.match_keyword(Keyword::While)?;
let expr = self.parse_expression()?;
let body = self.parse_block()?;
Ok(Statement::While(expr, Box::new(body)))
}
fn parse_conditional_statement(&mut self) -> Result<Statement, String> {
self.match_keyword(Keyword::If)?;
let condition = self.parse_expression()?;

15
src/parser/tests.rs

@ -376,3 +376,18 @@ fn test_string_array() {
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}
#[test]
fn test_basic_while_loop() {
let raw = "
fn main() {
let x = 5 * 2
while x > 0 {
return x
}
}
";
let tokens = tokenize(raw);
let tree = parse(tokens, Some(raw.to_string()));
assert!(tree.is_ok())
}

Loading…
Cancel
Save