conlang: Add keyword types, rules, and tests

This commit is contained in:
John 2023-09-27 18:21:19 -05:00
parent 097e2c4f11
commit bed21941e8

View File

@ -9,6 +9,14 @@ pub mod token {
pub enum Type { pub enum Type {
Comment, Comment,
Identifier, Identifier,
// Keywords
KwElse,
KwFor,
KwFn,
KwIf,
KwIn,
KwLet,
KwWhile,
// Literals // Literals
LitInteger, LitInteger,
LitFloat, LitFloat,
@ -80,9 +88,19 @@ pub mod lexer {
// classifies a single arbitrary token // classifies a single arbitrary token
pub fn any(&mut self) -> Option<Token> { pub fn any(&mut self) -> Option<Token> {
None.or_else(|| self.comment()) None.or_else(|| self.comment())
.or_else(|| self.keyword())
.or_else(|| self.identifier()) .or_else(|| self.identifier())
.or_else(|| self.literal()) .or_else(|| self.literal())
} }
pub fn keyword(&mut self) -> Option<Token> {
None.or_else(|| self.kw_else())
.or_else(|| self.kw_for())
.or_else(|| self.kw_fn())
.or_else(|| self.kw_if())
.or_else(|| self.kw_in())
.or_else(|| self.kw_let())
.or_else(|| self.kw_while())
}
pub fn literal(&mut self) -> Option<Token> { pub fn literal(&mut self) -> Option<Token> {
None.or_else(|| self.lit_string()) None.or_else(|| self.lit_string())
.or_else(|| self.lit_float()) .or_else(|| self.lit_float())
@ -94,6 +112,35 @@ pub mod lexer {
self.skip_whitespace(); self.skip_whitespace();
self.produce_token(Type::Comment, Rule::new(self.text()).comment().end()?) self.produce_token(Type::Comment, Rule::new(self.text()).comment().end()?)
} }
// keywords
pub fn kw_else(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwElse, Rule::new(self.text()).str("else").end()?)
}
pub fn kw_for(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwFor, Rule::new(self.text()).str("for").end()?)
}
pub fn kw_fn(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwFn, Rule::new(self.text()).str("fn").end()?)
}
pub fn kw_if(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwIf, Rule::new(self.text()).str("if").end()?)
}
pub fn kw_in(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwIn, Rule::new(self.text()).str("in").end()?)
}
pub fn kw_let(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwLet, Rule::new(self.text()).str("let").end()?)
}
pub fn kw_while(&mut self) -> Option<Token> {
self.skip_whitespace();
self.produce_token(Type::KwWhile, Rule::new(self.text()).str("while").end()?)
}
// identifiers // identifiers
pub fn identifier(&mut self) -> Option<Token> { pub fn identifier(&mut self) -> Option<Token> {
self.skip_whitespace(); self.skip_whitespace();
@ -387,6 +434,38 @@ mod tests {
assert_whole_input_is_token("fn main() {}", Lexer::comment, Type::Comment); assert_whole_input_is_token("fn main() {}", Lexer::comment, Type::Comment);
} }
} }
mod keyword {
use super::*;
#[test]
fn kw_else() {
assert_whole_input_is_token("else", Lexer::kw_else, Type::KwElse);
assert_has_type_and_range(" else ", Lexer::kw_else, Type::KwElse, 2..6);
}
#[test]
fn kw_for() {
assert_whole_input_is_token("for", Lexer::kw_for, Type::KwFor);
}
#[test]
fn kw_fn() {
assert_whole_input_is_token("fn", Lexer::kw_fn, Type::KwFn);
}
#[test]
fn kw_if() {
assert_whole_input_is_token("if", Lexer::kw_if, Type::KwIf);
}
#[test]
fn kw_in() {
assert_whole_input_is_token("in", Lexer::kw_in, Type::KwIn);
}
#[test]
fn kw_let() {
assert_whole_input_is_token("let", Lexer::kw_let, Type::KwLet);
}
#[test]
fn kw_while() {
assert_whole_input_is_token("while", Lexer::kw_while, Type::KwWhile);
}
}
mod identifier { mod identifier {
use super::*; use super::*;