conlang: Add break, true, false keywords, and example file

This commit is contained in:
John 2023-09-28 01:31:46 -05:00
parent f25685560a
commit 48f5e5248c
2 changed files with 51 additions and 9 deletions

View File

@ -1,9 +1,24 @@
#!/ this is a shebang comment! #!/usr/local/bin/conlang
// This is an example Conlang file. // This is a Conlang file. Conlang is an expression-based language designed for maximum flexibility etc. etc. whatever
/* Conlang supports block comments! */ // This is a function. It can be called with the call operator.
ident // Identifier // The function called `main` is the program's entrypoint
.1 // literal float fn main() {
0.1 // literal float let x = 100;
0x1234 // literal integer
"str" // literal string // An if expression is like the ternary conditional operator in C
let y = if x < 50 {
0
} else {
x
};
// A `for` expression is like the for-else construct in Python, but it returns a value via the `break` keyword
let z = for i in 0..y {
// do a thing repeatedly
break true
} else {
false
};
// TODO: decide how to do IO
}

View File

@ -11,12 +11,15 @@ pub mod token {
Comment, Comment,
Identifier, Identifier,
// Keywords // Keywords
KwBreak,
KwElse, KwElse,
KwFalse,
KwFor, KwFor,
KwFn, KwFn,
KwIf, KwIf,
KwIn, KwIn,
KwLet, KwLet,
KwTrue,
KwWhile, KwWhile,
// Literals // Literals
LitInteger, LitInteger,
@ -151,12 +154,15 @@ pub mod lexer {
} }
/// Attempts to produce a Keyword /// Attempts to produce a Keyword
pub fn keyword(&mut self) -> Option<Token> { pub fn keyword(&mut self) -> Option<Token> {
None.or_else(|| self.kw_else()) None.or_else(|| self.kw_break())
.or_else(|| self.kw_else())
.or_else(|| self.kw_false())
.or_else(|| self.kw_for()) .or_else(|| self.kw_for())
.or_else(|| self.kw_fn()) .or_else(|| self.kw_fn())
.or_else(|| self.kw_if()) .or_else(|| self.kw_if())
.or_else(|| self.kw_in()) .or_else(|| self.kw_in())
.or_else(|| self.kw_let()) .or_else(|| self.kw_let())
.or_else(|| self.kw_true())
.or_else(|| self.kw_while()) .or_else(|| self.kw_while())
} }
/// Attempts to produce a [Type::LitString], [Type::LitFloat], or [Type::LitInteger] /// Attempts to produce a [Type::LitString], [Type::LitFloat], or [Type::LitInteger]
@ -230,9 +236,15 @@ pub mod lexer {
self.map_rule(|r| r.comment(), Type::Comment) self.map_rule(|r| r.comment(), Type::Comment)
} }
// keywords // keywords
pub fn kw_break(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("break"), Type::KwBreak)
}
pub fn kw_else(&mut self) -> Option<Token> { pub fn kw_else(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("else"), Type::KwElse) self.map_rule(|r| r.str("else"), Type::KwElse)
} }
pub fn kw_false(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("false"), Type::KwFalse)
}
pub fn kw_for(&mut self) -> Option<Token> { pub fn kw_for(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("for"), Type::KwFor) self.map_rule(|r| r.str("for"), Type::KwFor)
} }
@ -248,6 +260,9 @@ pub mod lexer {
pub fn kw_let(&mut self) -> Option<Token> { pub fn kw_let(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("let"), Type::KwLet) self.map_rule(|r| r.str("let"), Type::KwLet)
} }
pub fn kw_true(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("true"), Type::KwTrue)
}
pub fn kw_while(&mut self) -> Option<Token> { pub fn kw_while(&mut self) -> Option<Token> {
self.map_rule(|r| r.str("while"), Type::KwWhile) self.map_rule(|r| r.str("while"), Type::KwWhile)
} }
@ -696,11 +711,19 @@ mod tests {
mod keyword { mod keyword {
use super::*; use super::*;
#[test] #[test]
fn kw_break() {
assert_whole_input_is_token("break", Lexer::kw_break, Type::KwBreak);
}
#[test]
fn kw_else() { fn kw_else() {
assert_whole_input_is_token("else", Lexer::kw_else, Type::KwElse); assert_whole_input_is_token("else", Lexer::kw_else, Type::KwElse);
assert_has_type_and_range(" else ", Lexer::kw_else, Type::KwElse, 2..6); assert_has_type_and_range(" else ", Lexer::kw_else, Type::KwElse, 2..6);
} }
#[test] #[test]
fn kw_false() {
assert_whole_input_is_token("false", Lexer::kw_false, Type::KwFalse);
}
#[test]
fn kw_for() { fn kw_for() {
assert_whole_input_is_token("for", Lexer::kw_for, Type::KwFor); assert_whole_input_is_token("for", Lexer::kw_for, Type::KwFor);
} }
@ -721,6 +744,10 @@ mod tests {
assert_whole_input_is_token("let", Lexer::kw_let, Type::KwLet); assert_whole_input_is_token("let", Lexer::kw_let, Type::KwLet);
} }
#[test] #[test]
fn kw_true() {
assert_whole_input_is_token("true", Lexer::kw_true, Type::KwTrue);
}
#[test]
fn kw_while() { fn kw_while() {
assert_whole_input_is_token("while", Lexer::kw_while, Type::KwWhile); assert_whole_input_is_token("while", Lexer::kw_while, Type::KwWhile);
} }