From 4fa5724573c8301ddcf7246f2fc378050cb6c6f8 Mon Sep 17 00:00:00 2001 From: ArnabRollin Date: Thu, 26 Oct 2023 18:06:42 +0530 Subject: [PATCH] Added bytecode compiler + runner --- CHANGELOG.md | 17 ++- Cargo.lock | 2 +- Cargo.toml | 2 +- src/about.rs | 69 +++++++++- src/argparser.rs | 51 ++++++-- src/bytecode.rs | 327 +++++++++++++++++++++++++++++++++++++++++++++++ src/dwn.rs | 62 ++++----- src/lexer.rs | 6 +- src/main.rs | 8 +- src/runner.rs | 17 ++- 10 files changed, 507 insertions(+), 54 deletions(-) create mode 100644 src/bytecode.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index a2c6ddc..8ee6179 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.10.0] - 2023-10-26 + +### Added + +- Variable-options in CLI +- Bytecode compiler and runner (level 1) +- Better documentation in CLI. + +### Changed + +- Now there are two runner functions: `run_tokens` and `run` (which tokenizes the line and calls `run_tokens` with the tokens) +- Integers are now `i64` and floats are `f64` + ## [0.9.0] - 2023-10-24 ### Added @@ -111,7 +124,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.9.0...HEAD +[unreleased]: https://github.com/ArnabRollin/dwn/compare/v0.10.0...HEAD + +[0.10.0]: https://github.com/ArnabRollin/dwn/compare/v0.9.0...v0.10.0 [0.9.0]: https://github.com/ArnabRollin/dwn/compare/v0.8.0...v0.9.0 diff --git a/Cargo.lock b/Cargo.lock index f73cd19..3bcab0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "dwn" -version = "0.9.0" +version = "0.10.0" dependencies = [ "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 7f2b7b1..872c7d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dwn" -version = "0.9.0" +version = "0.10.0" edition = "2021" [dependencies] diff --git a/src/about.rs b/src/about.rs index 0ff92f0..2c2fbbf 100644 --- a/src/about.rs +++ b/src/about.rs @@ -8,8 +8,22 @@ /// ``` pub fn about() { let about = r#" - Usage: dwn [options...] [command] [args...] +Dawn (dwn) is the interpreter and bytecode compiler for the Dawn Programming Language. +Usage: + dwn -h | --help + dwn -v | --version + dwn help () + dwn run () + dwn bytec | bytecodec | bytc () [--level=] + dwn byterun | bytecoderun | bytrun () + dwn idle + dwn framework | fw +Options: + -h --help Show this message and exit. + -v --version Show the version and exit. + --level= Set the level of the engine which bytecode compiles the file. + Use `latest` (case insensitive) to set to the latest engine. [default: LATEST] "# .trim(); @@ -29,13 +43,60 @@ pub fn about() { /// ``` pub fn help(command: Option<&String>) { let info_help: &str = r#" -Usage: dwn help [command] - Shows information about a command and how to use it. -"# + +Usage: dwn help () + "# + .trim(); + let info_run: &str = r#" +Runs a Dawn project file. + +Usage: dwn run () + "# .trim(); + let info_bytec: &str = r#" +Bytecode compiles a Dawn project file. + +Usage: + dwn bytec () + dwn bytecodec () + dwn bytc () + dwn bytec () [--level=] + dwn bytecodec () [--level=] + dwn bytc () [--level=] + "# + .trim(); + let info_byterun: &str = r#" +Runs a Dawn bytecode file. + +Usage: + dwn byterun () + dwn bytecoderun () + dwn bytrun () + "# + .trim(); + let info_idle: &str = r#" +Starts the Integrated Development and Learning Environment (IDLE) + +Usage: dwn idle + "# + .trim(); + let info_framework: &str = r#" +Creates a framework for Dawn Programming Language extensions. + +Usage: + dwn framework + dwn fw + "# + .trim(); + match command.unwrap_or(&String::new()).as_str() { "help" => println!("{}", info_help), + "run" => println!("{}", info_run), + "bytec" | "bytecodec" | "bytc" => println!("{}", info_bytec), + "byterun" | "bytecoderun" | "bytrun" => println!("{}", info_byterun), + "idle" => println!("{}", info_idle), + "framework" | "fw" => println!("{}", info_framework), command => println!("Unknown command: {}", command), } } diff --git a/src/argparser.rs b/src/argparser.rs index 4284096..b9bfe5b 100644 --- a/src/argparser.rs +++ b/src/argparser.rs @@ -1,6 +1,6 @@ //! Argument parser for Dawn (dwn). -use std::env::Args; +use std::{collections::HashMap, env::Args}; /// Parses the arguments. /// @@ -24,14 +24,24 @@ pub fn argparse(mut args: Args) -> Arguments { let mut options: Vec = vec![]; let mut flags: Vec = vec![]; let mut arguments: Vec = vec![]; + let mut variables: HashMap = HashMap::new(); while let Some(arg) = args.next() { if arg.starts_with("--") { - options.extend( - arg.trim_start_matches("--") - .split('-') - .map(|s| s.to_string()), - ); + let varsplit: Vec<&str> = arg.split('=').collect(); + + if varsplit[..varsplit.len() - 1].is_empty() { + options.extend( + arg.trim_start_matches("--") + .split('-') + .map(|s| s.to_string()), + ); + } else { + variables.insert( + varsplit[0].trim_start_matches("--").to_string(), + varsplit[1].to_string(), + ); + } } else if arg.starts_with("-") { flags.extend(arg.chars().skip(1).map(|c| c.to_string())); } else { @@ -50,6 +60,7 @@ pub fn argparse(mut args: Args) -> Arguments { flags, command, arguments, + variables, } } @@ -62,6 +73,7 @@ pub fn argparse(mut args: Args) -> Arguments { /// flags: vec![String::from("f")], /// command: String::from("lawn"), /// arguments: vec![String::from("dig")], +/// variables: vec![], /// } /// ``` pub struct Arguments { @@ -69,6 +81,7 @@ pub struct Arguments { pub flags: Vec, pub command: String, pub arguments: Vec, + pub variables: HashMap, } #[test] @@ -77,16 +90,26 @@ fn argument_parser() { let mut options: Vec = vec![]; let mut flags: Vec = vec![]; let mut arguments: Vec = vec![]; + let mut variables: HashMap = HashMap::new(); let mut args = args.iter(); while let Some(arg) = args.next() { if arg.starts_with("--") { - options.extend( - arg.trim_start_matches("--") - .split('-') - .map(|s| s.to_string()), - ); + let varsplit: Vec<&str> = arg.split('=').collect(); + + if varsplit.is_empty() { + options.extend( + arg.trim_start_matches("--") + .split('-') + .map(|s| s.to_string()), + ); + } else { + variables.insert( + varsplit[0].trim_start_matches("--").to_string(), + varsplit[1].to_string(), + ); + } } else if arg.starts_with("-") { flags.extend(arg.chars().skip(1).map(|c| c.to_string())); } else { @@ -105,6 +128,7 @@ fn argument_parser() { flags, command, arguments, + variables, } } let args = argparse(vec![ @@ -112,8 +136,12 @@ fn argument_parser() { "--c-c-c".to_string(), "-dd".to_string(), "cey".to_string(), + "--level=1".to_string(), ]); + let mut variables_assert = HashMap::new(); + variables_assert.insert("level".to_string(), "1".to_string()); + assert_eq!(args.command, "klein".to_string()); assert_eq!(args.arguments, vec!["cey".to_string()]); assert_eq!( @@ -121,4 +149,5 @@ fn argument_parser() { vec!["c".to_string(), "c".to_string(), "c".to_string()] ); assert_eq!(args.flags, vec!["d".to_string(), "d".to_string()]); + assert_eq!(args.variables, variables_assert); } diff --git a/src/bytecode.rs b/src/bytecode.rs new file mode 100644 index 0000000..4209e9d --- /dev/null +++ b/src/bytecode.rs @@ -0,0 +1,327 @@ +//! The bytecode compiler for Dawn (dwn) + +use std::collections::HashMap; +use std::fs::{write, File}; +use std::io::{BufRead, BufReader, Read}; +use std::process::exit; + +use crate::dwn::{get_funcs, Metadata, Variable, VARIABLES}; +use crate::lexer::{tokenize, Token, TokenModifiers, TokenTypes}; +use crate::runner::run_tokens; + +lazy_static! { + static ref TYPES: HashMap<&'static str, TokenTypes> = { + let mut m = HashMap::new(); + m.insert("b", TokenTypes::BOOL); + m.insert("fl", TokenTypes::FLOAT); + m.insert("fu", TokenTypes::FUNC); + m.insert("i", TokenTypes::INT); + m.insert("l", TokenTypes::LITERAL); + m.insert("na", TokenTypes::NAME); + m.insert("no", TokenTypes::NONE); + m.insert("sc", TokenTypes::SCOPE); + m.insert("st", TokenTypes::STRING); + m.insert("v", TokenTypes::VARIABLE); + m + }; +} + +/// The function used to bytecode compile files. +pub fn bytecode_compile_file(file: Option<&String>, level: Option<&String>) { + if file.is_none() { + eprintln!("Error: Please provide a file to compile!"); + exit(1); + } + + let file = file.unwrap(); + + let max_level = 1; + let level = if level.is_none() { + max_level + } else { + let level = level.unwrap(); + if level.to_lowercase() == "latest".to_string() { + max_level + } else { + match level.parse::() { + Ok(level) => level, + Err(_) => { + eprintln!("Error: Level must be a number or 'latest' !"); + exit(1); + } + } + } + }; + + let reader = + BufReader::new(File::open(file).expect(format!("Cannot open file `{}`", file).as_str())); + + match level { + 1 => bytec_lvl1(reader, file), + lvl => { + eprintln!("Error: Bytecode compiler level {lvl} has not been implemented!"); + exit(1); + } + } +} + +fn bytec_lvl1(reader: BufReader, file: &String) { + let mut scope = 0; + let mut in_scope = false; + let mut scope_token = String::new(); + let mut current_tokens = vec![]; + + let mut bytecode = String::new(); + bytecode.push('1'); + bytecode.push('\x04'); + bytecode.push('\n'); + + for (count, line) in reader.lines().enumerate() { + let line = remove_all_after(line.unwrap(), ';'); + + if line.trim().is_empty() { + bytecode.push('\x03'); + continue; + } + + let tokens = tokenize( + line.trim_end().to_string(), + &mut Metadata { + line_count: count, + scope: &mut scope, + in_scope: &mut in_scope, + scope_token: &mut scope_token, + current_tokens: &mut current_tokens, + }, + ); + + if (tokens.len() > 0 + && tokens[0] + == Token { + ty: TokenTypes::FUNC, + modifiers: vec![], + val: "create_var".to_string(), + }) + { + VARIABLES.write().unwrap().insert( + tokens[1].val.to_string(), + Variable { + scope, + value: tokens[2].clone(), + }, + ); + } + + for token in tokens { + let mut type_ = "na"; + + for (&key, value) in TYPES.iter() { + if value == &token.ty { + type_ = key; + break; + } + } + + let mut modifiers: Vec<&str> = vec![]; + + for modifier in token.modifiers { + modifiers.push(match modifier { + TokenModifiers::ARGS => "a", + }) + } + + let value = token.val; + + bytecode.push_str(type_); + bytecode.push('\x00'); + + for modifier in modifiers { + bytecode.push_str(modifier); + bytecode.push('\x01'); + } + + bytecode.push('\x00'); + bytecode.push_str(&value); + bytecode.push('\x02'); + } + + bytecode.push('\x03'); + } + + let mut file_without_ext = file.split('.').collect::>(); + file_without_ext.pop(); + + let mut outfile = file_without_ext.join("."); + outfile.push_str(".light"); + + match write(outfile, bytecode) { + Ok(_) => {} + Err(e) => { + eprintln!("{e}"); + exit(1); + } + } +} + +pub fn bytecode_run(bytecode_file: Option<&String>) { + if bytecode_file.is_none() { + eprintln!("Error: Please provide a file to compile!"); + exit(1); + } + + let bytecode_file = bytecode_file.unwrap(); + + let mut reader = BufReader::new( + File::open(bytecode_file).expect(format!("Cannot open file `{}`", bytecode_file).as_str()), + ); + + let mut level = String::new(); + match reader.read_line(&mut level) { + Ok(_) => {} + Err(e) => { + eprintln!("{e}"); + exit(1); + } + } + + let level = match level.split('\x04').next() { + Some(l) => match l.parse::() { + Ok(l) => l, + Err(_) => { + eprintln!("Error: Level is not numeric in bytecode file!"); + exit(1); + } + }, + None => { + eprintln!("Error: Could not determine level from bytecode file!"); + exit(1); + } + }; + + match level { + 1 => byterun_lvl1(reader), + lvl => { + eprintln!("Error: Bytecode runner level {lvl} has not been implemented!"); + exit(1); + } + } +} + +fn byterun_lvl1(mut reader: BufReader) { + let mut text = String::new(); + + match reader.read_to_string(&mut text) { + Ok(_) => {} + Err(e) => { + eprintln!("{e}"); + exit(1); + } + } + + let bytecode_lines: Vec<&str> = text.split('\x03').collect(); + let mut scope = 0; + let mut in_scope = false; + let mut scope_token = String::new(); + let mut current_tokens = vec![]; + + for (count, bytecode_line) in bytecode_lines.iter().enumerate() { + let tokens: Vec<&str> = bytecode_line.split('\x02').collect(); + let mut tokens_vec: Vec = vec![]; + + for token in &tokens[..tokens.len() - 1] { + let token_parts: Vec<&str> = token.split('\x00').collect(); + + let mut token_parts = token_parts.iter(); + + let type_part = token_parts.next(); + let modifier_part = token_parts.next(); + let value_part = token_parts.next(); + + let type_ = match type_part { + Some(ty) => { + match TYPES.get(ty) { + Some(ty) => ty, + None => { + eprintln!("(type_get no_found: >>{ty}<<) Error: Invalid format in bytecode file!"); + exit(1); + } + } + } + None => { + eprintln!("(type_get no_part_found) Error: Invalid format in bytecode file!"); + exit(1); + } + }; + + let modifiers = match modifier_part { + Some(modifier_part) => { + let modifier_parts: Vec<&str> = modifier_part.split('\x01').collect(); + let mut modifiers: Vec = vec![]; + + for modifier_part in &modifier_parts[..modifier_parts.len() - 1] { + modifiers.push(match modifier_part { + &"a" => TokenModifiers::ARGS, + modifier => { + eprintln!("(modifier_get no_found: >>{modifier}<<) Error: Invalid format in bytecode file!"); + exit(1); + } + }) + } + + modifiers + } + None => { + eprintln!( + "(modifier_get no_part_found) Error: Invalid format in bytecode file!" + ); + exit(1); + } + }; + + let val = match value_part { + Some(val) => val.to_string(), + None => { + eprintln!("(val_get no_part_found) Error: Invalid format in bytecode file!"); + exit(1); + } + }; + + tokens_vec.push(Token { + ty: type_.clone(), + modifiers, + val, + }); + } + + run_tokens( + tokens_vec, + get_funcs(), + &mut Metadata { + line_count: count, + scope: &mut scope, + in_scope: &mut in_scope, + scope_token: &mut scope_token, + current_tokens: &mut current_tokens, + }, + ); + } +} + +/// The function to remove every character in `text` after `ch` is reached (including `ch`). +/// +/// Examples: +/// +/// ```rust +/// let new = remove_all_after("say \"Hello!\" ; abcdefghij...".to_string(), ';'); +/// +/// assert_eq!(new, "say \"Hello!\" ".to_string()); +/// ``` +fn remove_all_after(text: String, ch: char) -> String { + text.split(ch).next().unwrap().to_string() +} + +#[test] +fn removing_all_after() { + let new = remove_all_after("say \"Hello!\" ; abcdefghij...".to_string(), ';'); + assert_eq!(new, "say \"Hello!\" ".to_string()); +} diff --git a/src/dwn.rs b/src/dwn.rs index 1753090..793b2e9 100644 --- a/src/dwn.rs +++ b/src/dwn.rs @@ -14,7 +14,7 @@ use crate::{ #[derive(Clone)] pub struct Variable { - value: Token, + pub value: Token, pub scope: u32, } @@ -451,7 +451,7 @@ fn sum(tokens: Vec, meta: &mut Metadata) -> Result { } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(+) Invalid type: Cannot use operation '+' with type {ty:?}" @@ -459,7 +459,7 @@ fn sum(tokens: Vec, meta: &mut Metadata) -> Result { } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(+) Invalid type: Cannot use operation '+' with type {ty:?}" @@ -470,7 +470,7 @@ fn sum(tokens: Vec, meta: &mut Metadata) -> Result { let total = first + second; if total.fract() == 0.0 { - let total = total as i32; + let total = total as i64; return Ok(Token { ty: TokenTypes::INT, @@ -493,7 +493,7 @@ fn difference(tokens: Vec, meta: &mut Metadata) -> Result } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(-) Invalid type: Cannot use operation '-' with type {ty:?}" @@ -501,7 +501,7 @@ fn difference(tokens: Vec, meta: &mut Metadata) -> Result } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(-) Invalid type: Cannot use operation '-' with type {ty:?}" @@ -512,7 +512,7 @@ fn difference(tokens: Vec, meta: &mut Metadata) -> Result let difference = first - second; if difference.fract() == 0.0 { - let difference = difference as i32; + let difference = difference as i64; return Ok(Token { ty: TokenTypes::INT, @@ -535,7 +535,7 @@ fn product(tokens: Vec, meta: &mut Metadata) -> Result { } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(*) Invalid type: Cannot use operation '*' with type {ty:?}" @@ -543,7 +543,7 @@ fn product(tokens: Vec, meta: &mut Metadata) -> Result { } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(*) Invalid type: Cannot use operation '*' with type {ty:?}" @@ -554,7 +554,7 @@ fn product(tokens: Vec, meta: &mut Metadata) -> Result { let product = first * second; if product.fract() == 0.0 { - let product = product as i32; + let product = product as i64; return Ok(Token { ty: TokenTypes::INT, @@ -577,7 +577,7 @@ fn quotient(tokens: Vec, meta: &mut Metadata) -> Result { } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(/) Invalid type: Cannot use operation '/' with type {ty:?}" @@ -585,7 +585,7 @@ fn quotient(tokens: Vec, meta: &mut Metadata) -> Result { } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(/) Invalid type: Cannot use operation '/' with type {ty:?}" @@ -596,7 +596,7 @@ fn quotient(tokens: Vec, meta: &mut Metadata) -> Result { let quotient = first / second; if quotient.fract() == 0.0 { - let quotient = quotient as i32; + let quotient = quotient as i64; return Ok(Token { ty: TokenTypes::INT, @@ -804,7 +804,7 @@ fn gt(tokens: Vec, meta: &mut Metadata) -> Result { } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(>) Invalid type: Cannot use operation '>' with type {ty:?}" @@ -812,7 +812,7 @@ fn gt(tokens: Vec, meta: &mut Metadata) -> Result { } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(>) Invalid type: Cannot use operation '>' with type {ty:?}" @@ -842,7 +842,7 @@ fn lt(tokens: Vec, meta: &mut Metadata) -> Result { } let first = match args[0].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[0].val.parse::().unwrap(), ty => { return Err(format!( "(<) Invalid type: Cannot use operation '<' with type {ty:?}" @@ -850,7 +850,7 @@ fn lt(tokens: Vec, meta: &mut Metadata) -> Result { } }; let second = match args[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => args[1].val.parse::().unwrap(), ty => { return Err(format!( "(<) Invalid type: Cannot use operation '<' with type {ty:?}" @@ -969,7 +969,7 @@ fn add_assign(tokens: Vec, _meta: &mut Metadata) -> Result } }; let second = match tokens[1].ty.clone() { - TokenTypes::INT | TokenTypes::FLOAT => tokens[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => tokens[1].val.parse::().unwrap(), ty => { return Err(format!( "(+=) Invalid type: Cannot add thing of type {ty:?} to variable" @@ -986,7 +986,7 @@ fn add_assign(tokens: Vec, _meta: &mut Metadata) -> Result None => return Err(format!("(+=) Variable `{first}` not found")), }; - let value: f32 = match &variable.value.ty { + let value: f64 = match &variable.value.ty { TokenTypes::INT => variable.value.val.parse().unwrap(), TokenTypes::FLOAT => variable.value.val.parse().unwrap(), ty => { @@ -999,7 +999,7 @@ fn add_assign(tokens: Vec, _meta: &mut Metadata) -> Result let total = value + second; if total.fract() == 0.0 { - let total = total as i32; + let total = total as i64; *variable = Variable { value: Token { @@ -1040,7 +1040,7 @@ fn subtract_assign(tokens: Vec, _meta: &mut Metadata) -> Result tokens[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => tokens[1].val.parse::().unwrap(), ty => { return Err(format!( "(-=) Invalid type: Cannot subtract thing of type {ty:?} from variable" @@ -1057,7 +1057,7 @@ fn subtract_assign(tokens: Vec, _meta: &mut Metadata) -> Result return Err(format!("(-=) Variable `{first}` not found")), }; - let value: f32 = match &variable.value.ty { + let value: f64 = match &variable.value.ty { TokenTypes::INT => variable.value.val.parse().unwrap(), TokenTypes::FLOAT => variable.value.val.parse().unwrap(), ty => { @@ -1070,7 +1070,7 @@ fn subtract_assign(tokens: Vec, _meta: &mut Metadata) -> Result, _meta: &mut Metadata) -> Result tokens[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => tokens[1].val.parse::().unwrap(), ty => { return Err(format!( "(*=) Invalid type: Cannot multiply thing of type {ty:?} with variable" @@ -1129,7 +1129,7 @@ fn multiply_assign(tokens: Vec, _meta: &mut Metadata) -> Result return Err(format!("(*=) Variable `{first}` not found")), }; - let value: f32 = match &variable.value.ty { + let value: f64 = match &variable.value.ty { TokenTypes::INT => variable.value.val.parse().unwrap(), TokenTypes::FLOAT => variable.value.val.parse().unwrap(), ty => { @@ -1142,7 +1142,7 @@ fn multiply_assign(tokens: Vec, _meta: &mut Metadata) -> Result, _meta: &mut Metadata) -> Result tokens[1].val.parse::().unwrap(), + TokenTypes::INT | TokenTypes::FLOAT => tokens[1].val.parse::().unwrap(), ty => { return Err(format!( "(/=) Invalid type: Variable cannot be divided by thing of type {ty:?}" @@ -1201,7 +1201,7 @@ fn divide_assign(tokens: Vec, _meta: &mut Metadata) -> Result return Err(format!("(/=) Variable `{first}` not found")), }; - let value: f32 = match &variable.value.ty { + let value: f64 = match &variable.value.ty { TokenTypes::INT => variable.value.val.parse().unwrap(), TokenTypes::FLOAT => variable.value.val.parse().unwrap(), ty => { @@ -1214,7 +1214,7 @@ fn divide_assign(tokens: Vec, _meta: &mut Metadata) -> Result, meta: &mut Metadata) -> Result { let args = get_args(tokens, meta); let convertable = &args[0].val; - match convertable.parse::() { + match convertable.parse::() { Ok(int) => int, Err(_) => return Err("(int) Could not convert value to integer".to_string()), }; @@ -1269,7 +1269,7 @@ fn float(tokens: Vec, meta: &mut Metadata) -> Result { let args = get_args(tokens, meta); let convertable = &args[0].val; - match convertable.parse::() { + match convertable.parse::() { Ok(int) => int, Err(_) => return Err("(float) Could not convert value to float".to_string()), }; diff --git a/src/lexer.rs b/src/lexer.rs index fa3e6e1..75b83cc 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -771,7 +771,7 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { continue; } - if word.parse::().is_ok() && !in_string { + if word.parse::().is_ok() && !in_string { if !in_literal { tokens.push(Token { ty: TokenTypes::INT, @@ -791,7 +791,7 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { continue; } - if word.parse::().is_ok() && !in_string { + if word.parse::().is_ok() && !in_string { if !in_literal { tokens.push(Token { ty: TokenTypes::FLOAT, @@ -816,7 +816,7 @@ pub fn tokenize(data: String, meta: &mut Metadata) -> Vec { *meta.current_tokens = tokens.clone(); - continue; + return vec![]; } if word.starts_with('"') { diff --git a/src/main.rs b/src/main.rs index 7af8e2b..e2ed547 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate lazy_static; use about::{about, help}; use argparser::argparse; +use bytecode::{bytecode_compile_file, bytecode_run}; use framework::make_framework; use idle::idle; use interpreter::interpret_file; @@ -11,6 +12,7 @@ use std::{env::args, process::exit}; mod about; mod argparser; +mod bytecode; mod dwn; mod framework; mod idle; @@ -44,13 +46,17 @@ fn main() { if arguments.options.contains(&"version".to_string()) || arguments.flags.contains(&"v".to_string()) { - println!("0.9.0"); + println!("0.10.0"); exit(0); } match arguments.command.as_str() { "help" => help(arguments.arguments.get(0)), "run" | "r" => interpret_file(arguments.arguments.get(0)), + "bytec" | "bytecodec" | "bytc" => { + bytecode_compile_file(arguments.arguments.get(0), arguments.variables.get("level")) + } + "byterun" | "bytecoderun" | "bytrun" => bytecode_run(arguments.arguments.get(0)), "idle" => idle(), "framework" | "fw" => make_framework(), unknown_command => eprintln!("Unknown command: {}", unknown_command), diff --git a/src/runner.rs b/src/runner.rs index 702b5a2..f25e1c1 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -29,9 +29,24 @@ pub fn run( >, meta: &mut Metadata, ) -> Token { - let functions_ = functions.clone(); let tokens = tokenize(line, meta); + run_tokens(tokens, functions, meta) +} + +pub fn run_tokens( + tokens: Vec, + functions: RwLockReadGuard< + '_, + std::collections::HashMap< + &str, + for<'a> fn(Vec, &'a mut Metadata) -> Result, + >, + >, + meta: &mut Metadata, +) -> Token { + let functions_ = functions.clone(); + if tokens.len() > 0 { match tokens[0].ty.clone() { TokenTypes::FUNC => {