diff --git a/Cargo.lock b/Cargo.lock
index 3e63598..b88f3be 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,22 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
[[package]]
name = "labast"
-version = "1.0.2"
+version = "1.0.3"
+dependencies = [
+ "fastrand",
+ "pico-args",
+]
+
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
diff --git a/Cargo.toml b/Cargo.toml
index 63f1dba..b85db34 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "labast"
-version = "1.0.2"
+version = "1.0.3"
authors = [ "n3tael" ]
edition = "2021"
description = "A zero-dependencies Labaski interpreter written in Rust."
@@ -17,3 +17,5 @@ lto = true
panic = "abort"
[dependencies]
+fastrand = "2.0.1"
+pico-args = "0.5.0"
diff --git a/README.md b/README.md
index 0ef8dc7..f50517d 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Labast
-A zero-dependencies Labaski interpreter written in Rust. Fully supports Labashki specs 1.10.
+A Labaski interpreter written in Rust. Fully supports Labashki specs 1.12.
## Examples
See `scripts` directory.
\ No newline at end of file
diff --git a/npp_labaski.xml b/npp_labaski.xml
new file mode 100644
index 0000000..1df2735
--- /dev/null
+++ b/npp_labaski.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+ 00; 01 02 03 04
+
+
+
+
+
+
+
+ ^ |
+
+
+
+
+ [
+
+ ]
+
+
+
+ #insert
+ push pop dup swap pick add sub mul div mod putc getc scan meow args dump maxsize size quit exit _unix_random
+ #print $print #exec #expr
+ and or xor nand not band bor bxor bnand bnot
+ > $ : \ + -
+ jmp jnz jz kjnz kjz
+ @
+ nop
+ 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/hello-world-old.lb b/scripts/hello-world-old.lb
index 922a4ff..bad7307 100644
--- a/scripts/hello-world-old.lb
+++ b/scripts/hello-world-old.lb
@@ -27,4 +27,4 @@ putc
push 105 ; i
putc
push 33 ; !
-putc
\ No newline at end of file
+putc
\ No newline at end of file
diff --git a/src/execute.rs b/src/execute.rs
index 49f3813..79f9416 100644
--- a/src/execute.rs
+++ b/src/execute.rs
@@ -102,12 +102,14 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name
"kjz" => instructions::kjz::kjz(&mut stack.memory, &mut stack.labels, &mut stack.program_counter, &instruction.data),
// Input/Output
- "putc" => instructions::putc::putc(&mut stack.memory),
- "getc" => instructions::getc::getc(&mut stack.memory),
- "scan" => instructions::scan::scan(&mut stack.memory),
- "meow" => instructions::meow::meow(&mut stack.memory),
- "#print" => instructions::print::print(&instruction.arg),
- "$print" => instructions::print::print(&instruction.arg),
+ "putc" => instructions::putc::putc(&mut stack.memory),
+ "getc" => instructions::getc::getc(&mut stack.memory),
+ "scan" => instructions::scan::scan(&mut stack.memory),
+ "meow" => instructions::meow::meow(&mut stack.memory),
+ "#print" => instructions::print::print(&instruction.arg),
+ "$print" => instructions::print::print(&instruction.arg),
+ "#println" => instructions::println::println(&instruction.arg),
+ "$println" => instructions::println::println(&instruction.arg),
// Modules
"args" => instructions::args::args(&mut stack.memory, &mut origin_stack, &instruction.data),
@@ -126,18 +128,21 @@ pub fn execute(stack: &mut Stack, mut origin_stack: Option<&mut Stack>, mod_name
},
// Special
- "dump" => instructions::dump::dump(&mut stack.memory),
- "size" => instructions::size::size(&mut stack.memory),
+ "dump" => instructions::dump::dump(&mut stack.memory),
+ "size" => instructions::size::size(&mut stack.memory),
"maxsize" => instructions::maxsize::maxsize(&mut stack.memory),
- "#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg),
- "nop" => continue,
- "quit" => std::process::exit(0),
- "exit" => instructions::exit::exit(&instruction.data),
+ "#expr" => instructions::expr::expr(&mut stack.memory, &instruction.arg),
+ "nop" => continue,
+ "quit" => std::process::exit(0),
+ "exit" => instructions::exit::exit(&instruction.data),
// Platform-specific
#[cfg(target_family = "unix")]
"_unix_random" => instructions::_unix_random::_unix_random(&mut stack.memory),
+ // Labast-specific
+ "random" => instructions::random::random(&mut stack.memory),
+
_ => {
eprintln!("Unknown instruction: {}", instruction.name);
std::process::exit(2);
diff --git a/src/instructions/_unix_random.rs b/src/instructions/_unix_random.rs
index 79258c1..75fa8b0 100644
--- a/src/instructions/_unix_random.rs
+++ b/src/instructions/_unix_random.rs
@@ -6,9 +6,9 @@ use crate::RunError;
pub fn _unix_random(memory: &mut Vec) {
let mut rng = File::open("/dev/urandom").unwrap();
- let mut buffer = [0u8; 1];
+ let mut buffer = [0u8; 2];
rng.read_exact(&mut buffer).unwrap();
let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty));
- memory.push((buffer[0] as u16) % (*data - 1));
+ memory.push((u16::from_ne_bytes(buffer)) % (*data - 1));
}
\ No newline at end of file
diff --git a/src/instructions/maxsize.rs b/src/instructions/maxsize.rs
index 5d7769d..4a3f1b7 100644
--- a/src/instructions/maxsize.rs
+++ b/src/instructions/maxsize.rs
@@ -1,3 +1,3 @@
pub fn maxsize(memory: &mut Vec) {
- memory.push(65535);
+ memory.push(u16::MAX);
}
\ No newline at end of file
diff --git a/src/instructions/mod.rs b/src/instructions/mod.rs
index 70ea4c9..516a864 100644
--- a/src/instructions/mod.rs
+++ b/src/instructions/mod.rs
@@ -36,4 +36,6 @@ pub mod not;
pub mod kjnz;
pub mod kjz;
pub mod print;
-pub mod insert;
\ No newline at end of file
+pub mod println;
+pub mod insert;
+pub mod random;
\ No newline at end of file
diff --git a/src/instructions/print.rs b/src/instructions/print.rs
index 86e8e56..679d7ca 100644
--- a/src/instructions/print.rs
+++ b/src/instructions/print.rs
@@ -1,3 +1,3 @@
pub fn print(arg: &String) {
- println!("{}", arg);
+ print!("{}", arg);
}
\ No newline at end of file
diff --git a/src/instructions/println.rs b/src/instructions/println.rs
new file mode 100644
index 0000000..927f406
--- /dev/null
+++ b/src/instructions/println.rs
@@ -0,0 +1,3 @@
+pub fn println(arg: &String) {
+ println!("{}", arg);
+}
\ No newline at end of file
diff --git a/src/instructions/random.rs b/src/instructions/random.rs
new file mode 100644
index 0000000..a63b609
--- /dev/null
+++ b/src/instructions/random.rs
@@ -0,0 +1,7 @@
+use fastrand;
+use crate::RunError;
+
+pub fn random(memory: &mut Vec) {
+ let data = &memory.pop().expect(&format!("{}", RunError::MemoryEmpty));
+ memory.push(fastrand::u16(..) % (*data - 1));
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 6d1850c..edf6a4d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,5 @@
-use std::{env, fs, io::{BufRead, Write}};
+use std::{fs, io::{BufRead, Write}};
+
use errors::RunError;
use execute::execute;
use parse::parse;
@@ -10,17 +11,28 @@ mod execute;
mod instructions;
mod errors;
+const HELP: &str = "\
+labast - Labaski interpreter written in Rust.
+
+usage: labast [options] [ file.lb ]
+
+options:
+ -h, --help prints help information
+ -v, --version prints version
+";
+
fn main() {
- let args: Vec = env::args().collect();
+ let args = match parse_args() {
+ Ok(v) => v,
+ Err(e) => {
+ eprintln!("Error: {}.", e);
+ std::process::exit(1);
+ }
+ };
- if args.get(2) == Some(&String::from("-h"))
- || args.get(2) == Some(&String::from("--help")) {
- eprintln!("Usage: {0} [file]", args[0]);
- return;
- }
+ let mut stack = Stack::new();
- if args.len() < 2 {
- let mut stack = Stack::new();
+ if args.input.is_none() {
let mut line = String::new();
loop {
@@ -37,12 +49,41 @@ fn main() {
parse(&mut stack, &line.trim());
execute(&mut stack, None, &"inline".to_string());
}
+ } else {
+ let input = &args.input.expect("error: no input file");
+ let lines = fs::read_to_string(&input).expect(&format!("{}", RunError::FailToReadFile));
+
+ parse(&mut stack, &lines);
+ execute(&mut stack, None, &String::from(input.file_name().expect("Failed to read file name.").to_str().expect("Failed to convert file name to string")));
+ }
+}
+
+#[derive(Debug)]
+struct AppArgs {
+ input: Option,
+}
+
+fn parse_args() -> Result {
+ let mut pargs = pico_args::Arguments::from_env();
+
+ if pargs.contains(["-h", "--help"]) {
+ print!("{}", HELP);
+ std::process::exit(0);
}
- let mut stack = Stack::new();
- let lines = fs::read_to_string(&args[1]).expect(&format!("{}", RunError::FailToReadFile));
+ if pargs.contains(["-v", "--version"]) {
+ println!("labast version {}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"));
+ std::process::exit(0);
+ }
- parse(&mut stack, &lines);
+ let args = AppArgs {
+ input: pargs.opt_free_from_str()?,
+ };
- execute(&mut stack, None, &args[1]);
+ let remaining = pargs.finish();
+ if !remaining.is_empty() {
+ eprintln!("Warning: unused arguments left: {:?}.", remaining);
+ }
+
+ return Ok(args);
}
\ No newline at end of file