From 48f5e5248c6e477507b94e1f13c4a4dd4c95e6c0 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 28 Sep 2023 01:31:46 -0500 Subject: [PATCH] conlang: Add `break`, `true`, `false` keywords, and example file --- dummy.cl | 31 +++++++++++++++++++++++-------- libconlang/src/lib.rs | 29 ++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/dummy.cl b/dummy.cl index 8bf31e1..8d28727 100644 --- a/dummy.cl +++ b/dummy.cl @@ -1,9 +1,24 @@ -#!/ this is a shebang comment! -// This is an example Conlang file. +#!/usr/local/bin/conlang +// This is a Conlang file. Conlang is an expression-based language designed for maximum flexibility etc. etc. whatever -/* Conlang supports block comments! */ -ident // Identifier -.1 // literal float -0.1 // literal float -0x1234 // literal integer -"str" // literal string +// This is a function. It can be called with the call operator. +// The function called `main` is the program's entrypoint +fn main() { + let x = 100; + + // 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 +} diff --git a/libconlang/src/lib.rs b/libconlang/src/lib.rs index 464eeea..f7bec9d 100644 --- a/libconlang/src/lib.rs +++ b/libconlang/src/lib.rs @@ -11,12 +11,15 @@ pub mod token { Comment, Identifier, // Keywords + KwBreak, KwElse, + KwFalse, KwFor, KwFn, KwIf, KwIn, KwLet, + KwTrue, KwWhile, // Literals LitInteger, @@ -151,12 +154,15 @@ pub mod lexer { } /// Attempts to produce a Keyword pub fn keyword(&mut self) -> Option { - 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_fn()) .or_else(|| self.kw_if()) .or_else(|| self.kw_in()) .or_else(|| self.kw_let()) + .or_else(|| self.kw_true()) .or_else(|| self.kw_while()) } /// 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) } // keywords + pub fn kw_break(&mut self) -> Option { + self.map_rule(|r| r.str("break"), Type::KwBreak) + } pub fn kw_else(&mut self) -> Option { self.map_rule(|r| r.str("else"), Type::KwElse) } + pub fn kw_false(&mut self) -> Option { + self.map_rule(|r| r.str("false"), Type::KwFalse) + } pub fn kw_for(&mut self) -> Option { self.map_rule(|r| r.str("for"), Type::KwFor) } @@ -248,6 +260,9 @@ pub mod lexer { pub fn kw_let(&mut self) -> Option { self.map_rule(|r| r.str("let"), Type::KwLet) } + pub fn kw_true(&mut self) -> Option { + self.map_rule(|r| r.str("true"), Type::KwTrue) + } pub fn kw_while(&mut self) -> Option { self.map_rule(|r| r.str("while"), Type::KwWhile) } @@ -696,11 +711,19 @@ mod tests { mod keyword { use super::*; #[test] + fn kw_break() { + assert_whole_input_is_token("break", Lexer::kw_break, Type::KwBreak); + } + #[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_false() { + assert_whole_input_is_token("false", Lexer::kw_false, Type::KwFalse); + } + #[test] fn kw_for() { 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); } #[test] + fn kw_true() { + assert_whole_input_is_token("true", Lexer::kw_true, Type::KwTrue); + } + #[test] fn kw_while() { assert_whole_input_is_token("while", Lexer::kw_while, Type::KwWhile); }