Skip to content

Commit

Permalink
Merge pull request #2 from Pandicon/dev
Browse files Browse the repository at this point in the history
Version 0.3.0
  • Loading branch information
Pandicon committed Aug 30, 2022
2 parents ae8228f + 99b5cfc commit 99bb885
Show file tree
Hide file tree
Showing 13 changed files with 803 additions and 26 deletions.
45 changes: 29 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
4. [Important notes](#important-notes)
5. [Mechanics](#mechanics)
6. [Syntax](#syntax)
7. [Incoming features](#incoming-features)
8. [Examples](#examples)
7. [Preprocessor](#preprocessor)<br>
7.1 [Using it](#preprocessor-using-it)<br>
7.2 [Supported statements](#preprocessor-supported-statements)
8. [Incoming features](#incoming-features)
9. [Examples](#examples)

## Basic info <a name="basic-info"></a>

Expand Down Expand Up @@ -42,6 +45,7 @@ See the table below for some flags you can provide when running your code.
| --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 |

## Main features <a name="main-features"></a>
Expand Down Expand Up @@ -87,19 +91,8 @@ The magic of Brainfuck-like syntax is that it is easy and extremely difficult at
| ~ | 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) | <code>`</code> | 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 |
| _ | 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) | <code>`</code> | 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 |
Expand All @@ -112,6 +105,26 @@ The magic of Brainfuck-like syntax is that it is easy and extremely difficult at

Each line has to end with a punctuation (`:`) or else the program will crash.

## Preprocessor <a name="preprocessor"></a>

The preprocessor allows you to include flags into the code itself, so you don't have to rely on the user to run the code with the correct flags.<br>
The values parsed by the preprocessor are overridden by the flags passed in from the command line.

### Using it <a name="preprocessor-using-it"></a>

The statements are put into the code file and begin with a `#`.

### Supported statements <a name="preprocessor-supported-statements"></a>

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 (`<n>`), zero itself (`<z>`), and positive numbers (`<p>`), separated by `\|`: `<n>\|<z>\|<p>` | 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 <a name="incoming-features"></a>

- Functions
Expand All @@ -133,4 +146,4 @@ Fibonacci sequence:
!>|10|!<^>|10|!<[@^+\.>\,<@]:
```

You can find all the examples in the [examples folder](https://github.com/Pandicon/The-Golden/tree/main/examples).
You can find all the examples in the [examples folder](https://github.com/Pandicon/The-Golden/tree/main/examples).
2 changes: 1 addition & 1 deletion the-golden/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "the-golden"
version = "0.1.0"
version = "0.3.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
9 changes: 9 additions & 0 deletions the-golden/src/flags.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::Utils;

#[derive(Clone, Debug)]
pub struct Warnings {
pub too_left_pointer: bool,
Expand All @@ -13,6 +15,7 @@ pub struct Flags {
pub debug_heavy: bool,
pub no_console: bool,
pub raw_code_to_run: Option<String>,
pub sebek: [Option<f64>; 3],
pub version: Option<String>,
}

Expand All @@ -27,6 +30,7 @@ impl Flags {
debug_heavy: false,
no_console: false,
raw_code_to_run: None,
sebek: [None, None, None],
version: None,
}
}
Expand All @@ -51,6 +55,11 @@ impl Flags {
}
"--disable-warnings" => self.disabled_warnings = Warnings { too_left_pointer: true },
"--disable-too-left-pointer-warning" => self.disabled_warnings.too_left_pointer = true,
"--sebek" => {
if i + 1 < args_count {
self.sebek = Utils::parse_sebek(&args[i + 1]);
}
}
"-" => {
if self.raw_code_to_run.is_none() && i + 1 < args_count {
self.raw_code_to_run = Some(args[i + 1].clone());
Expand Down
22 changes: 19 additions & 3 deletions the-golden/src/interpreter/interpreter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::Flags;

#[path = "./preprocessor.rs"]
mod preprocessor;
#[path = "./versions/handler.rs"]
mod versions_handler;

Expand All @@ -14,14 +16,28 @@ pub struct Interpreter {
}

impl Interpreter {
pub fn new(mut version: String, code: String, code_path: std::path::PathBuf, flags: Flags, ansi_enabled: bool) -> Self {
pub fn new(version: Option<String>, 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_console |= preprocessor.no_console;
let final_version = if let Some(ver) = version {
ver
} else if let Some(ver) = preprocessor.version {
ver
} else {
String::from("latest")
};
if !flags.sebek.iter().any(|val| val.is_some()) {
flags.sebek = preprocessor.sebek;
};
let versions_handler = versions_handler::Handler::new();
version = versions_handler.parse_version(version, ansi_enabled);
let parsed_version = versions_handler.parse_version(final_version, ansi_enabled);

Self {
flags,
ansi_enabled,
code,
version,
version: parsed_version,
versions_handler,
code_path,
}
Expand Down
79 changes: 79 additions & 0 deletions the-golden/src/interpreter/preprocessor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use regex::Regex;

use crate::Utils;

#[derive(Clone, Debug)]
pub struct Warnings {
pub too_left_pointer: bool,
}

#[derive(Clone, Debug)]
pub struct Preprocessor {
pub disabled_warnings: Warnings,

pub no_console: bool,
pub sebek: [Option<f64>; 3],
pub version: Option<String>,
}

impl Preprocessor {
pub fn new() -> Self {
Self {
disabled_warnings: Warnings { too_left_pointer: false },

no_console: false,
sebek: [None, None, None],
version: None,
}
}

pub fn run(&mut self, code: &str) {
let rule = Regex::new(crate::PREPROCESSOR_REGEX).unwrap();
let statements = rule.find_iter(code).map(|m| m.as_str().trim()).collect::<Vec<&str>>();
for &statement in &statements {
let mut statement_chars = statement.chars();
statement_chars.next();
if statement.ends_with(':') {
statement_chars.next_back();
}
let args = statement_chars.as_str().split(' ').collect::<Vec<&str>>();
if args.is_empty() {
continue;
}
let args_count = args.len();
match args[0].to_lowercase().as_str() {
"version" => {
if args_count < 2 {
continue;
}
self.version = Some(args[1].to_string());
}
"noconsole" | "no-console" | "no_console" => {
if args_count < 2 {
self.no_console = true;
continue;
}
self.no_console = args[1].to_lowercase() != "false";
}
"disablewarnings" | "disable-warnings" | "disable_warnings" => {
if args_count < 2 {
continue;
}
match args[1].to_lowercase().as_str() {
"too-left-pointer" | "tooleftpointer" => {
self.disabled_warnings.too_left_pointer = true;
}
_ => {}
}
}
"sebek" => {
if args_count < 2 {
continue;
}
self.sebek = Utils::parse_sebek(args[1]);
}
_ => {}
}
}
}
}
16 changes: 12 additions & 4 deletions the-golden/src/interpreter/versions/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::Flags;
mod v0_1_0;
#[path = "./v0-2-0/main.rs"]
mod v0_2_0;
#[path = "./v0-3-0/main.rs"]
mod v0_3_0;

pub struct Handler {
versions: Versions,
Expand All @@ -16,6 +18,7 @@ impl Handler {
vec![
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![])]),
],
);
let versions = Versions::new(vec![versions_0]);
Expand All @@ -32,13 +35,13 @@ impl Handler {
for _ in 0..3 - parts.len() {
parts.push(String::from("x"));
}
let s = parts[2].split("-").map(|x| x.to_string()).collect::<Vec<String>>();
let s = parts[2].split('-').map(|x| x.to_string()).collect::<Vec<String>>();
let (parts, prerelease, _build_metadata) = if s.len() > 1 {
let s_joined = s[1..].join("-");
let p = s_joined.clone();
let s2 = p.split("+").map(|x| x.to_string()).collect::<Vec<String>>();
let s2 = p.split('+').map(|x| x.to_string()).collect::<Vec<String>>();
if s2.len() > 1 {
(vec![parts[0].clone(), parts[1].clone(), s[0].clone()], Some(s2[0].clone()), Some(s2[1..].join("+").clone()))
(vec![parts[0].clone(), parts[1].clone(), s[0].clone()], Some(s2[0].clone()), Some(s2[1..].join("+")))
} else {
(vec![parts[0].clone(), parts[1].clone(), s[0].clone()], Some(s_joined), None)
}
Expand Down Expand Up @@ -118,13 +121,18 @@ impl Handler {
};
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));
};
v0_3_0::Runner::new(code, code_path, flags, ansi_enabled).run()
}
_ => {
println!(
"{}Couldn't run version {}",
crate::Utils::ansi_escape_text("91", "ERROR", v0_1_0::INFO_PREFIX_LENGTH, ansi_enabled),
version
);
return;
}
}
}
Expand Down
77 changes: 77 additions & 0 deletions the-golden/src/interpreter/versions/v0-3-0/brackets_matcher.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::collections::HashMap;

pub struct BracketsMatcher {
pub brackets: HashMap<String, HashMap<usize, usize>>,
brackets_mem: Vec<(String, usize, isize)>,
bracket_keys: HashMap<String, String>,
ending_brackets_keys: HashMap<String, String>
}

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
}
}
Loading

0 comments on commit 99bb885

Please sign in to comment.