From 5630c5079ce21c60cea49a74cedbeec29f9429d2 Mon Sep 17 00:00:00 2001 From: ArnabRollin Date: Tue, 24 Oct 2023 10:33:55 +0530 Subject: [PATCH] Added more operators, functions, examples --- CHANGELOG.md | 21 +++++++- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 50 +++++++++++------ src/dwn.rs | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/lexer.rs | 96 ++++++++++++++++++++++++++++++++- src/main.rs | 2 +- 7 files changed, 298 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0b2290..a2c6ddc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.9.0] - 2023-10-24 + +### Added + +- `!=`, `lazy=` and `lazy!=` operators +- `vars` function which prints all the variables +- `int` and `float` converter functions +- Guessing game example to `README.md` + +### Changed + +- Changed the example in `README.md`. + +### Fixed + +- Scope build-up bug has now been fixed + ## [0.8.0] - 2023-10-21 ### Added @@ -94,7 +111,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Simple function and string parsing -[unreleased]: https://github.com/ArnabRollin/dwn/compare/v0.8.0...HEAD +[unreleased]: https://github.com/ArnabRollin/dwn/compare/v0.9.0...HEAD + +[0.9.0]: https://github.com/ArnabRollin/dwn/compare/v0.8.0...v0.9.0 [0.8.0]: https://github.com/ArnabRollin/dwn/compare/v0.7.0...v0.8.0 diff --git a/Cargo.lock b/Cargo.lock index e65476d..f73cd19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "dwn" -version = "0.8.0" +version = "0.9.0" dependencies = [ "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 5e28a3c..7f2b7b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dwn" -version = "0.8.0" +version = "0.9.0" edition = "2021" [dependencies] diff --git a/README.md b/README.md index 80e2ba7..95a491b 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,47 @@ `dwn` is the interpreter for the Dawn programming language. +## Installation options + +- [Go to book](https://arnabrollin.github.io/dwn-book) +- [Latest Release](https://github.com/ArnabRollin/dwn/release/latest) +- [Releases](https://arnabrollin.github.io/dwn/releases) + ## Examples -`code.dwn` +### User Greeting ```dwn -let username = (ask "What is your name? ") ; Asking the user their name... +say "Hello!" +let name = (ask "What is your name? ") -say "Hello" username "!" ; Greet the user... +say "Hello" name "!" +``` -let myname = "ExamplePerson" +### Guessing Game -say "My name is" myname "." +```dwn +let n = 1256 -say "1 - 1 is" (1 - 1) -say "The sum of 123 and 678 is" (sum 123 678) -say "100 + 0.5 is" (100 + 0.5) -``` +if (n == 1256) { ; test + say "Hello! Welcome to The Guesser" +} + +forever { + let gs = (ask "Guess the number > ") + let g = (int gs) + + if (g == n) { + say "Congratulations! The number was" n + break + } -```console -% dwn run code.dwn + if (g > n) { + say "Too big!" + } -What is your name? ArnabRollin -Hello ArnabRollin! -My name is ExamplePerson. -1 - 1 is 0 -The sum of 123 and 678 is 801 -100 + 0.5 is 100.5 + if (g < n) { + say "Too small!" + } +} ``` diff --git a/src/dwn.rs b/src/dwn.rs index f43e954..1753090 100644 --- a/src/dwn.rs +++ b/src/dwn.rs @@ -85,6 +85,10 @@ lazy_static! { "eq", eq as for<'a> fn(Vec, &'a mut Metadata) -> Result, ); + m.insert( + "ne", + ne as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); m.insert( "gt", gt as for<'a> fn(Vec, &'a mut Metadata) -> Result, @@ -113,6 +117,26 @@ lazy_static! { "break", break_ as for<'a> fn(Vec, &'a mut Metadata) -> Result, ); + m.insert( + "lazy_eq", + lazy_eq as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); + m.insert( + "lazy_ne", + lazy_ne as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); + m.insert( + "int", + int as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); + m.insert( + "float", + float as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); + m.insert( + "vars", + vars as for<'a> fn(Vec, &'a mut Metadata) -> Result, + ); RwLock::new(m) }; @@ -254,12 +278,11 @@ fn run_scope(token: &Token, meta: &mut Metadata) -> Token { } } - *meta.scope -= 1; let mut drop_vars: Vec = vec![]; let mut variables = VARIABLES.write().unwrap(); for (k, v) in variables.clone() { - if v.scope == *meta.scope + 1 { + if v.scope == *meta.scope { drop_vars.push(k); } } @@ -268,6 +291,8 @@ fn run_scope(token: &Token, meta: &mut Metadata) -> Token { variables.remove(&k); } + *meta.scope -= 1; + return ret; } _ => { @@ -681,6 +706,56 @@ fn eq(tokens: Vec, meta: &mut Metadata) -> Result { let first = &args[0]; let second = &args[1]; + if (first.ty == second.ty) && (first.val == second.val) { + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "true".to_string(), + }); + } + + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "false".to_string(), + }); +} + +fn ne(tokens: Vec, meta: &mut Metadata) -> Result { + let args = get_args(tokens, meta); + + if args.len() < 2 { + return Err("(!=) Not enough arguments!".to_string()); + } + + let first = &args[0]; + let second = &args[1]; + + if (first.ty == second.ty) && (first.val == second.val) { + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "false".to_string(), + }); + } + + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "true".to_string(), + }); +} + +fn lazy_eq(tokens: Vec, meta: &mut Metadata) -> Result { + let args = get_args(tokens, meta); + + if args.len() < 2 { + return Err("(lazy=) Not enough arguments!".to_string()); + } + + let first = &args[0].val; + let second = &args[1].val; + if first == second { return Ok(Token { ty: TokenTypes::BOOL, @@ -695,6 +770,32 @@ fn eq(tokens: Vec, meta: &mut Metadata) -> Result { val: "false".to_string(), }); } + +fn lazy_ne(tokens: Vec, meta: &mut Metadata) -> Result { + let args = get_args(tokens, meta); + + if args.len() < 2 { + return Err("(lazy!=) Not enough arguments!".to_string()); + } + + let first = &args[0].val; + let second = &args[1].val; + + if first == second { + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "false".to_string(), + }); + } + + return Ok(Token { + ty: TokenTypes::BOOL, + modifiers: vec![], + val: "true".to_string(), + }); +} + fn gt(tokens: Vec, meta: &mut Metadata) -> Result { let args = get_args(tokens, meta); @@ -1148,3 +1249,48 @@ fn break_(_tokens: Vec, _meta: &mut Metadata) -> Result { val: "break".to_string(), }); } + +fn int(tokens: Vec, meta: &mut Metadata) -> Result { + let args = get_args(tokens, meta); + + let convertable = &args[0].val; + match convertable.parse::() { + Ok(int) => int, + Err(_) => return Err("(int) Could not convert value to integer".to_string()), + }; + + return Ok(Token { + ty: TokenTypes::INT, + modifiers: vec![], + val: convertable.to_string(), + }); +} +fn float(tokens: Vec, meta: &mut Metadata) -> Result { + let args = get_args(tokens, meta); + + let convertable = &args[0].val; + match convertable.parse::() { + Ok(int) => int, + Err(_) => return Err("(float) Could not convert value to float".to_string()), + }; + + return Ok(Token { + ty: TokenTypes::FLOAT, + modifiers: vec![], + val: convertable.to_string(), + }); +} + +fn vars(_tokens: Vec, _meta: &mut Metadata) -> Result { + let variables = VARIABLES.read().unwrap(); + + for (k, v) in variables.iter() { + println!("{}: <{:?}>{}", k, v.value.ty, v.value.val); + } + + return Ok(Token { + ty: TokenTypes::NONE, + modifiers: vec![], + val: "None".to_string(), + }); +} diff --git a/src/lexer.rs b/src/lexer.rs index ab4e2e8..fa3e6e1 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -109,7 +109,6 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { let data = match data.strip_prefix("\t") { Some(l) => l, None => { - eprintln!("line {data}"); eprintln!( "Error on line {}: Expected indent with tabs!", meta.line_count @@ -274,6 +273,100 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { continue; } + if word == "!=" && !in_string { + if !in_literal { + let first = tokens.pop(); + + let first = match first { + Some(token) => token, + None => { + eprintln!( + "Error on line {}: No first value for comparison operator '!=' !", + meta.line_count + ); + exit(1); + } + }; + + tokens.push(Token { + ty: TokenTypes::FUNC, + modifiers: vec![], + val: "ne".to_string(), + }); + + tokens.push(Token { + modifiers: vec![TokenModifiers::ARGS], + ..first + }); + + in_compare = true; + }; + + continue; + } + if word == "lazy=" && !in_string { + if !in_literal { + let first = tokens.pop(); + + let first = match first { + Some(token) => token, + None => { + eprintln!( + "Error on line {}: No first value for comparison operator 'lazy=' !", + meta.line_count + ); + exit(1); + } + }; + + tokens.push(Token { + ty: TokenTypes::FUNC, + modifiers: vec![], + val: "lazy_eq".to_string(), + }); + + tokens.push(Token { + modifiers: vec![TokenModifiers::ARGS], + ..first + }); + + in_compare = true; + }; + + continue; + } + if word == "lazy!=" && !in_string { + if !in_literal { + let first = tokens.pop(); + + let first = match first { + Some(token) => token, + None => { + eprintln!( + "Error on line {}: No first value for comparison operator 'lazy!=' !", + meta.line_count + ); + exit(1); + } + }; + + tokens.push(Token { + ty: TokenTypes::FUNC, + modifiers: vec![], + val: "lazy_ne".to_string(), + }); + + tokens.push(Token { + modifiers: vec![TokenModifiers::ARGS], + ..first + }); + + in_compare = true; + }; + + continue; + } + if word == ">" && !in_string { if !in_literal { let first = tokens.pop(); @@ -719,7 +812,6 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { } if word == "{" && !in_string { - *meta.scope += 1; *meta.in_scope = true; *meta.current_tokens = tokens.clone(); diff --git a/src/main.rs b/src/main.rs index f007e10..7af8e2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ fn main() { if arguments.options.contains(&"version".to_string()) || arguments.flags.contains(&"v".to_string()) { - println!("0.8.0"); + println!("0.9.0"); exit(0); }