| `- '!!![~]:` | You can provide some code to be ran by the interpreter - no need to have a maumivu.au file |
-| --debug | `--debug` | Enabled debug mode - print parsed commands, which command was ran and the memory state at the end of execution |
-| --debug-heavy | `--debug-heavy` | Enabled heavy debug mode - print all the things printed in debug mode + stop for 0.5 seconds after each command and print the memory state |
-| --disable-warnings | `--disable-warnings` | Disable all warnings |
-| --disable-too-left-pointer-warning | `--disable-too-left-pointer-warning` | Disable the warning fired when you go to the -1 index in memory |
-| --hide-console | `--hide-console` | Hide the console when running the code |
-| --sebek | `--sebek -1|0|1` | Specify the results for division by 0. First number is for dividing a number < 0, second for dividing 0 itself, and the third is for dividing a number > 0 |
-| --version | `--version 0.1.0` | Run the code using a specific version of the interpreter |
+| Flag | Usage | Effect |
+| :--------------------------------- | :----------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| - \ | `- '!!![~]:` | You can provide some code to be ran by the interpreter - no need to have a maumivu.au file |
+| --debug | `--debug` | Enabled debug mode - print parsed commands, which command was ran and the memory state at the end of execution |
+| --debug-heavy | `--debug-heavy` | Enabled heavy debug mode - print all the things printed in debug mode + stop for 0.5 seconds after each command and print the memory state |
+| --disable-warnings | `--disable-warnings` | Disable all warnings |
+| --disable-too-left-pointer-warning | `--disable-too-left-pointer-warning` | Disable the warning fired when you go to the -1 index in memory |
+| --hide-console | `--hide-console` | Hide the console when running the code |
+| --no-brainfuck | `--no-brainfuck` | Set first cells of secondary memories to 0, removing the compatibility with Brainfuck |
+| --sebek | `--sebek -1\|0\|1` | Specify the results for division by 0. First number is for dividing a number < 0, second for dividing 0 itself, and the third is for dividing a number > 0 |
+| --version | `--version 0.1.0` | Run the code using a specific version of the interpreter |
## Main features
How good or bad the features of this language are is completely subjective, but here are some of them:
- Brainfuck-like syntax - other will have no idea wth your code does
-- Easy operations chaining - forget code looking like `>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<<<<<<<<<<<`, now you can do `|49|>\,|26|<` to achieve the exact same result
+- Easy operations chaining - forget code looking like `>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>.<<<<<<<<<<<<<<<<<<<<<<<<<<`, now you can do `|49|>.|26|<` to achieve the exact same result
- Easy arithmetics - tired of multiplication in O(N^2) time? The solution is here! Just do `*` and you are done in ~O(1)
- Decimal numbers - pretty self-explanatory, but now you can use decimal numbers in your code
- And much more!
@@ -72,38 +85,48 @@ If you go into memory index -1, a 0 is added at that position and the whole memo
Loops function the exact same way as in Brainfuck - they only run if the current cell value isn't 0. This language also offers do-while loops, which ignore the check the first time.
You can chain commands by putting `||` in front of them. You can also put a number between those pipes. If you decide to put a number in there, the command right after it will run `floor(the number)` times. If you leave it empty, the code will run `floor(cell value)` times. If the value is negative, the opposite command will be ran (see the table below). If the value is 0, it won't be ran at all.
| Command | Opposite command |
-|:-----|:------|
-| ! | ~ |
-| ~ | ! |
-| + | - |
-| - | + |
-| _ | / |
-| / | _ |
-| > | < |
-| < | > |
+| :------ | :--------------- |
+| ! | ~ |
+| ~ | ! |
+| + | - |
+| - | + |
+| _ | / |
+| / | _ |
+| > | < |
+| < | > |
## Syntax
The magic of Brainfuck-like syntax is that it is easy and extremely difficult at the same time. Here are all the commands the interpreter will understand:
-| Command | Explanation | Showcase | Chainable? | Usable on local memory? |
-|:-----|:------|:------|:------|:------|
-| ! | Adds one to the current cell | `!` | Yes | Yes |
-| ~ | Subtracts one from the current cell | `~` | Yes | Yes |
-| + | Adds the cell in the inactive row to the cell in the active row | `+` | Yes | Yes |
-| - | Subtracts the cell in the inactive row from the cell in the active row | `-` | Yes | Yes |
-| _ | Multiplies the cell in the active row by the cell in the inactive row | `_`| Yes | Yes | | / | Divides the cell in the active row by the cell in the inactive row |`/`| Yes | Yes | | _ | Floors the current cell value (towards -infinity) |`\_`| No | Yes | | & | Ceils the current cell value (towards +infinity) |`&`| No | Yes | | ` | Sets the cell to a random number from 0 (inclusive) to 1 (exclusive) | `
| No | Yes | | > | Move the cell pointer one to the right | `>`| Yes | Yes | | < | Move the cell pointer one to the left |`<`| Yes | Yes | | ^ | Switch active memory (sets the active as inactive and the inactive as active) |`^`| No | Yes | | $. | Sets the cell to the value of user input as a number (if they input 69, the cell value will be 69) | `$.` | No | Yes |
-| $, | Sets the cell to the value of user input as a character (if they input E, the cell value will be 69) | `$,`| No | Yes | | \\. | Output the cell as a number (if the cell value is 69, 69 will be printed) |`\.`| No | Yes | | \\, | Output the cell as a character (if the cell value is 69, E will be printed) |`\,`| No | Yes | | [ | Start a while loop |`[` | No | Yes |
-| ] | End a while loop | `]` | No | Yes |
-| [@ | Start a do-while loop | `[@` | No | Yes |
-| @] | End a do-while loop | `@]` | No | Yes |
-| ?? | Sets the cell value to its index | `??` | No | Yes |
-| ?= | If the cells in the active and inactive rows have the same value, break the loop | `[?=]` | Yes | Yes |
-| ?< | If the cell in the active row has a lower value than the cell in the inactive row, break the loop | `[?<]` | Yes | Yes |
-| ?> | If the cell in the active row has a higher value than the cell in the inactive row, break the loop | `[?>]` | Yes | Yes |
-| ; | Switch the values of the active global cell and the active local cell | `;` | No | Yes |
-| "" | Comments | `"This is a comment"` | No | No |
-
-Each line has to end with a punctuation (`:`) or else the program will crash.
+| Command | Explanation | Showcase | Chainable? | Usable on local memory? |
+| :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------- | :--------- | :---------------------- |
+| ! | Adds one to the current cell | `!` | Yes | Yes |
+| ~ | Subtracts one from the current cell | `~` | Yes | Yes |
+| + | Adds the cell in the inactive row to the cell in the active row (also adds one to the current cell in brainfuck compatible mode, because the inactive cell is 1) | `+` | Yes | Yes |
+| - | Subtracts the cell in the inactive row from the cell in the active row (also subtracts one from the current cell in brainfuck compatible mode, because the inactive cell is 1) | `-` | Yes | Yes |
+| * | Multiplies the cell in the active row by the cell in the inactive row | `*` | Yes | Yes |
+| / | Divides the cell in the active row by the cell in the inactive row | `/` | Yes | Yes |
+| _ | Floors the current cell value (towards -infinity) | `_` | No | Yes |
+| & | Ceils the current cell value (towards +infinity) | `&` | No | Yes |
+| \` | Sets the cell to a random number from 0 (inclusive) to 1 (exclusive) | \`
| No | Yes |
+| > | Move the cell pointer one to the right | `>` | Yes | Yes |
+| < | Move the cell pointer one to the left | `<` | Yes | Yes |
+| ^ | Switch active memory (sets the active as inactive and the inactive as active) | `^` | No | Yes |
+| $, | Sets the cell to the value of user input as a number (if they input 69, the cell value will be 69) | `$,` | No | Yes |
+| , | Sets the cell to the value of user input as a character (if they input E, the cell value will be 69) | `,` | No | Yes |
+| $. | Output the cell as a number (if the cell value is 69, 69 will be printed) | `$.` | Yes | Yes |
+| . | Output the cell as a character (if the cell value is 69, E will be printed) | `.` | Yes | Yes |
+| [ | Start a while loop | `[` | No | Yes |
+| ] | End a while loop | `]` | No | Yes |
+| [@ | Start a do-while loop | `[@` | No | Yes |
+| @] | End a do-while loop | `@]` | No | Yes |
+| ?? | Sets the cell value to its index | `??` | No | Yes |
+| ?= | If the cells in the active and inactive rows have the same value, break the loop | `[?=]` | Yes | Yes |
+| ?< | If the cell in the active row has a lower value than the cell in the inactive row, break the loop | `[?<]` | Yes | Yes |
+| ?> | If the cell in the active row has a higher value than the cell in the inactive row, break the loop | `[?>]` | Yes | Yes |
+| ; | Switches the values of the active global cell and the active local cell | `;` | No | Yes |
+| ' | Toggle if you are working with local or global memory | `'` | No | Yes |
+| "" | Comments | `"This is a comment"` | No | No |
## Preprocessor
@@ -112,18 +135,24 @@ The values parsed by the preprocessor are overridden by the flags passed in from
### Using it
-The statements are put into the code file and begin with a `#`.
+The statements are put into the code file and begin with a `#`. They can either end by a new line, a `#` and a new line, or just a `#`:
+```
+#version 0.4.0
+#sebek -1|0|1#
+#no-brainfuck#'!!!'$.'$.^|5|!$. "a"
+```
### Supported statements
Statement names are case-insensitive, so `version` is the same as `VERSION` and `VerSIoN`. However, this may not be true for other parts of the statement.
-| Statement | Aliases | Arguments | Explanation | Example |
-| :----------------- | :------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------- | :----------------------------------- |
-| `version` | None | None | Specifies the version of the interpreter to launch | `#version 0.3.0` |
-| `no-console` | `noconsole`, `no_console` | None | Hides the console when running the code | `#no-console` |
-| `disable-warnings` | `disablewarnings`, `disable_warnings` | The warning to disable: `too-left-pointer` (`tooleftpointer`) | Disables the specified warning | `#disable-warnings too-left-pointer` |
-| `sebek` | None | The results of division by zero for negative numbers (``), zero itself (``), and positive numbers (``), separated by `\|`: `\|\|` | Sets the result of division by zero to the specified number depending on the value of the number being divided | `sebek -1\|0\|1` (if a negative number was divided by 0 the result would be -1, if 0 was divided by 0 the result would be 0, and if a positive number was divided by 0 the result would be 1) |
+| Statement | Aliases | Arguments | Explanation | Example |
+| :----------------- | :------------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `version` | None | None | Specifies the version of the interpreter to launch | `#version 0.3.0` |
+| `no-console` | `noconsole`, `no_console` | None | Hides the console when running the code | `#no-console` |
+| `no-brainfuck` | `brainfuck`, `no_brainfuck` | None | Sets first cells of secondary memories to 0, removing the compatibility with Brainfuck, but preserving old memory values | `#no-brainfuck` |
+| `disable-warnings` | `disablewarnings`, `disable_warnings` | The warning to disable: `too-left-pointer` (`tooleftpointer`) | Disables the specified warning | `#disable-warnings too-left-pointer` |
+| `sebek` | None | The results of division by zero for negative numbers (``), zero itself (``), and positive numbers (``), separated by `\|`: `\|\|` | Sets the result of division by zero to the specified number depending on the value of the number being divided | `sebek -1\|0\|1` (if a negative number was divided by 0 the result would be -1, if 0 was divided by 0 the result would be 0, and if a positive number was divided by 0 the result would be 1) |
## Incoming features
@@ -137,13 +166,13 @@ Here are some examples written in this language:
"Hello, world!":
```
-|72|!\,|29|!\,|7|!\,\,|3|!\,|67|~\,|12|~\,|87|!\,|8|~\,|3|!\,|6|~\,|8|~\,|67|~\,:
+|72|!.|29|!.|7|!..|3|!.|67|~.|12|~.|87|!.|8|~.|3|!.|6|~.|8|~.|67|~.
```
Fibonacci sequence:
```
-!>|10|!<^>|10|!<[@^+\.>\,<@]:
+^~^!>|10|!<^>|10|!<[@^+$.>.<@]
```
You can find all the examples in the [examples folder](https://github.com/Pandicon/The-Golden/tree/main/examples).
\ No newline at end of file
diff --git a/examples/fibonacci.au b/examples/fibonacci.au
index 5db292b..2fb7b7b 100644
--- a/examples/fibonacci.au
+++ b/examples/fibonacci.au
@@ -1 +1 @@
-!>|10|!<^>|10|!<[@^+\.>\,<@]:
\ No newline at end of file
+^~^!>|10|!<^>|10|!<[@^+$.>.<@]
\ No newline at end of file
diff --git a/examples/fibonacci_zero.au b/examples/fibonacci_zero.au
index 223b828..615a21c 100644
--- a/examples/fibonacci_zero.au
+++ b/examples/fibonacci_zero.au
@@ -1 +1 @@
-!>|10|!<^>|10|!<\.>\,<[@^+\.>\,<@]:
\ No newline at end of file
+^~^!>|10|!<^>|10|!<$.>.<[@^+$.>.<@]
\ No newline at end of file
diff --git a/examples/hello_world.au b/examples/hello_world.au
index f4fa2bc..d815b78 100644
--- a/examples/hello_world.au
+++ b/examples/hello_world.au
@@ -1 +1 @@
-|72|!\,|29|!\,|7|!\,\,|3|!\,|67|~\,|12|~\,|87|!\,|8|~\,|3|!\,|6|~\,|8|~\,|67|~\,:
\ No newline at end of file
+|72|!.|29|!.|7|!..|3|!.|67|~.|12|~.|87|!.|8|~.|3|!.|6|~.|8|~.|67|~.
\ No newline at end of file
diff --git a/the-golden/Cargo.toml b/the-golden/Cargo.toml
index 3278517..cf2dda5 100644
--- a/the-golden/Cargo.toml
+++ b/the-golden/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "the-golden"
-version = "0.3.0"
+version = "0.4.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/the-golden/src/flags.rs b/the-golden/src/flags.rs
index f44b059..2af24c2 100644
--- a/the-golden/src/flags.rs
+++ b/the-golden/src/flags.rs
@@ -13,12 +13,19 @@ pub struct Flags {
pub code_path: Option,
pub debug: bool,
pub debug_heavy: bool,
+ pub no_brainfuck: bool,
pub no_console: bool,
pub raw_code_to_run: Option,
pub sebek: [Option; 3],
pub version: Option,
}
+impl Default for Flags {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
impl Flags {
pub fn new() -> Self {
Self {
@@ -28,6 +35,7 @@ impl Flags {
code_path: None,
debug: false,
debug_heavy: false,
+ no_brainfuck: false,
no_console: false,
raw_code_to_run: None,
sebek: [None, None, None],
@@ -55,6 +63,7 @@ impl Flags {
}
"--disable-warnings" => self.disabled_warnings = Warnings { too_left_pointer: true },
"--disable-too-left-pointer-warning" => self.disabled_warnings.too_left_pointer = true,
+ "--no-brainfuck" => self.no_brainfuck = true,
"--sebek" => {
if i + 1 < args_count {
self.sebek = Utils::parse_sebek(&args[i + 1]);
diff --git a/the-golden/src/interpreter/interpreter.rs b/the-golden/src/interpreter/interpreter.rs
index 0fd8788..38ad617 100644
--- a/the-golden/src/interpreter/interpreter.rs
+++ b/the-golden/src/interpreter/interpreter.rs
@@ -19,6 +19,7 @@ impl Interpreter {
pub fn new(version: Option, code: String, code_path: std::path::PathBuf, mut flags: Flags, ansi_enabled: bool) -> Self {
let mut preprocessor = preprocessor::Preprocessor::new();
preprocessor.run(&code);
+ flags.no_brainfuck |= preprocessor.no_brainfuck;
flags.no_console |= preprocessor.no_console;
let final_version = if let Some(ver) = version {
ver
diff --git a/the-golden/src/interpreter/preprocessor.rs b/the-golden/src/interpreter/preprocessor.rs
index 641a106..4ed4559 100644
--- a/the-golden/src/interpreter/preprocessor.rs
+++ b/the-golden/src/interpreter/preprocessor.rs
@@ -11,6 +11,7 @@ pub struct Warnings {
pub struct Preprocessor {
pub disabled_warnings: Warnings,
+ pub no_brainfuck: bool,
pub no_console: bool,
pub sebek: [Option; 3],
pub version: Option,
@@ -21,6 +22,7 @@ impl Preprocessor {
Self {
disabled_warnings: Warnings { too_left_pointer: false },
+ no_brainfuck: false,
no_console: false,
sebek: [None, None, None],
version: None,
@@ -36,6 +38,9 @@ impl Preprocessor {
if statement.ends_with(':') {
statement_chars.next_back();
}
+ if statement.ends_with('#') {
+ statement_chars.next_back();
+ }
let args = statement_chars.as_str().split(' ').collect::>();
if args.is_empty() {
continue;
@@ -48,6 +53,7 @@ impl Preprocessor {
}
self.version = Some(args[1].to_string());
}
+ "nobrainfuck" | "no-brainfuck" | "no_brainfuck" => self.no_brainfuck = true,
"noconsole" | "no-console" | "no_console" => {
if args_count < 2 {
self.no_console = true;
diff --git a/the-golden/src/interpreter/versions/handler.rs b/the-golden/src/interpreter/versions/handler.rs
index 2ca27b4..21fd6da 100644
--- a/the-golden/src/interpreter/versions/handler.rs
+++ b/the-golden/src/interpreter/versions/handler.rs
@@ -6,6 +6,8 @@ mod v0_1_0;
mod v0_2_0;
#[path = "./v0-3-0/main.rs"]
mod v0_3_0;
+#[path = "./v0-4-0/main.rs"]
+mod v0_4_0;
pub struct Handler {
versions: Versions,
@@ -19,6 +21,7 @@ impl Handler {
Version::new(String::from("1"), vec![Version::new(String::from("0"), vec![])]),
Version::new(String::from("2"), vec![Version::new(String::from("0"), vec![])]),
Version::new(String::from("3"), vec![Version::new(String::from("0"), vec![])]),
+ Version::new(String::from("4"), vec![Version::new(String::from("0"), vec![])]),
],
);
let versions = Versions::new(vec![versions_0]);
@@ -81,19 +84,19 @@ impl Handler {
}
version_parsed.push(current_subversion.value.clone());
}
- let prerelease = if prerelease.is_some() && !current_subversion.sub.is_empty() {
- let ver = prerelease.unwrap();
- let mut to_return: Option<&Version> = None;
- for subversion in ¤t_subversion.sub {
- if subversion.value == ver {
- to_return = Some(subversion);
- break;
+ let prerelease = match (prerelease, !current_subversion.sub.is_empty()) {
+ (Some(ver), true) => {
+ let mut to_return: Option<&Version> = None;
+ for subversion in ¤t_subversion.sub {
+ if subversion.value == ver {
+ to_return = Some(subversion);
+ break;
+ }
}
+ current_subversion = if let Some(to_return) = to_return { to_return } else { current_subversion.sub.last().unwrap() };
+ format!("-{}", current_subversion.value.clone())
}
- current_subversion = if let Some(to_return) = to_return { to_return } else { current_subversion.sub.last().unwrap() };
- format!("-{}", current_subversion.value.clone())
- } else {
- String::new()
+ _ => String::new(),
};
let version_final = format!("{}{}", version_parsed.join("."), prerelease);
if version_original != version_final && version_original.to_lowercase() != "latest" {
@@ -111,22 +114,28 @@ impl Handler {
match version.as_str() {
"0.1.0" => {
if flags.debug {
- println!("{}Running version 0.1.0", crate::Utils::ansi_escape_text("94", "DEBUG", v0_1_0::INFO_PREFIX_LENGTH, ansi_enabled));
+ println!("{}Running version {}", crate::Utils::ansi_escape_text("94", "DEBUG", v0_1_0::INFO_PREFIX_LENGTH, ansi_enabled), version);
};
v0_1_0::Runner::new(code, code_path, flags, ansi_enabled).run()
}
"0.2.0" => {
if flags.debug {
- println!("{}Running version 0.2.0", crate::Utils::ansi_escape_text("94", "DEBUG", v0_2_0::INFO_PREFIX_LENGTH, ansi_enabled));
+ println!("{}Running version {}", crate::Utils::ansi_escape_text("94", "DEBUG", v0_2_0::INFO_PREFIX_LENGTH, ansi_enabled), version);
};
v0_2_0::Runner::new(code, code_path, flags, ansi_enabled).run()
}
"0.3.0" => {
if flags.debug {
- println!("{}Running version 0.3.0", crate::Utils::ansi_escape_text("94", "DEBUG", v0_3_0::INFO_PREFIX_LENGTH, ansi_enabled));
+ println!("{}Running version {}", crate::Utils::ansi_escape_text("94", "DEBUG", v0_3_0::INFO_PREFIX_LENGTH, ansi_enabled), version);
};
v0_3_0::Runner::new(code, code_path, flags, ansi_enabled).run()
}
+ "0.4.0" => {
+ if flags.debug {
+ println!("{}Running version {}", crate::Utils::ansi_escape_text("94", "DEBUG", v0_4_0::INFO_PREFIX_LENGTH, ansi_enabled), version);
+ };
+ v0_4_0::Runner::new(code, code_path, flags, ansi_enabled).run()
+ }
_ => {
println!(
"{}Couldn't run version {}",
diff --git a/the-golden/src/interpreter/versions/v0-4-0/brackets_matcher.rs b/the-golden/src/interpreter/versions/v0-4-0/brackets_matcher.rs
new file mode 100644
index 0000000..4519556
--- /dev/null
+++ b/the-golden/src/interpreter/versions/v0-4-0/brackets_matcher.rs
@@ -0,0 +1,77 @@
+use std::collections::HashMap;
+
+pub struct BracketsMatcher {
+ pub brackets: HashMap>,
+ brackets_mem: Vec<(String, usize, isize)>,
+ bracket_keys: HashMap,
+ ending_brackets_keys: HashMap
+}
+
+impl BracketsMatcher {
+ pub fn new() -> Self {
+ Self {
+ brackets: HashMap::from([
+ ("while".to_string(), HashMap::new()),
+ ("do_while".to_string(), HashMap::new()),
+ ("while_local".to_string(), HashMap::new()),
+ ("do_while_local".to_string(), HashMap::new())
+ ]),
+ brackets_mem: vec![],
+ bracket_keys: HashMap::from([
+ ("[".to_string(), "while".to_string()),
+ ("]".to_string(), "while".to_string()),
+ ("[@".to_string(), "do_while".to_string()),
+ ("@]".to_string(), "do_while".to_string()),
+ ("'[".to_string(), "while_local".to_string()),
+ ("']".to_string(), "while_local".to_string()),
+ ("'[@".to_string(), "do_while_local".to_string()),
+ ("'@]".to_string(), "do_while_local".to_string()),
+ ]),
+ ending_brackets_keys: HashMap::from([
+ ("while".to_string(), "]".to_string()),
+ ("do_while".to_string(), "@]".to_string()),
+ ("while_local".to_string(), "']".to_string()),
+ ("do_while_local".to_string(), "'@]".to_string()),
+ ])
+ }
+ }
+
+ pub fn match_brackets(&mut self, code: &[String]) {
+ let starting_brackets = ["[", "[@", "'[", "'[@", ];
+ let ending_brackets = ["]", "@]", "']", "'@]"];
+ for (i, command) in code.iter().enumerate() {
+ let command_str = command.as_str();
+ if !starting_brackets.contains(&command_str) && !ending_brackets.contains(&command_str) {
+ continue;
+ }
+ if starting_brackets.contains(&command_str) {
+ self.brackets_mem.push((command.clone(), i, 0));
+ }
+ let mut keys_to_remove = vec![];
+ for key in 0..self.brackets_mem.len() {
+ self.brackets_mem[key].2 += self.num_equals(&self.brackets_mem[key].0, command);
+ let wanted_end = self.ending_brackets_keys.get(self.bracket_keys.get(&self.brackets_mem[key].0).unwrap()).unwrap();
+ if self.brackets_mem[key].2 == 0 && command == wanted_end {
+ let category = self.bracket_keys.get(wanted_end).unwrap();
+ let sub_map = self.brackets.get_mut(category).unwrap();
+ sub_map.insert(self.brackets_mem[key].1, i);
+ sub_map.insert(i, self.brackets_mem[key].1);
+ keys_to_remove.push(key);
+ }
+ }
+ for key in keys_to_remove {
+ self.brackets_mem.remove(key);
+ }
+ }
+ }
+
+ fn num_equals(&self, left: &String, right: &String) -> isize {
+ if self.bracket_keys.get(left) != self.bracket_keys.get(right) {
+ return 0;
+ }
+ if left == right {
+ return 1;
+ }
+ -1
+ }
+}
\ No newline at end of file
diff --git a/the-golden/src/interpreter/versions/v0-4-0/lexer.rs b/the-golden/src/interpreter/versions/v0-4-0/lexer.rs
new file mode 100644
index 0000000..e3877f1
--- /dev/null
+++ b/the-golden/src/interpreter/versions/v0-4-0/lexer.rs
@@ -0,0 +1,69 @@
+use lazy_static::lazy_static;
+use regex::Regex;
+
+lazy_static! {
+ static ref COMMENT_REGEX: Regex = Regex::new("^\"").unwrap();
+ static ref NEW_LINE_REGEX: Regex = Regex::new(r"^\r?\n").unwrap();
+}
+
+#[derive(Clone)]
+pub struct Lexer {
+ text: String,
+ rules: Vec,
+ line: usize,
+ column: usize,
+ comment: bool,
+ file_path: std::path::PathBuf,
+ position: usize,
+}
+
+impl Lexer {
+ pub fn new(text: String, rules: Vec, file_path: std::path::PathBuf) -> Self {
+ Self {
+ text,
+ rules,
+ line: 1,
+ column: 1,
+ comment: false,
+ file_path,
+ position: 0,
+ }
+ }
+
+ pub fn next(&mut self) -> Result