From 3a6da296d4acf87c8ee6005f17d39c5626f92a52 Mon Sep 17 00:00:00 2001 From: Spu7Nix Date: Sun, 1 Aug 2021 23:15:35 +0200 Subject: [PATCH] ready for release i think --- spwn-lang/Cargo.lock | 84 ++++++++++++ spwn-lang/Cargo.toml | 2 + spwn-lang/src/ast.rs | 6 +- spwn-lang/src/builtin.rs | 4 +- spwn-lang/src/compiler.rs | 198 ++++++++++++++------------- spwn-lang/src/compiler_info.rs | 12 +- spwn-lang/src/compiler_types.rs | 60 ++++---- spwn-lang/src/documentation.rs | 7 +- spwn-lang/src/globals.rs | 10 +- spwn-lang/src/main.rs | 23 +++- spwn-lang/src/optimize.rs | 44 ++++-- spwn-lang/src/parser.rs | 21 +-- spwn-lang/src/value.rs | 82 +++++------ spwn-lang/src/value_storage.rs | 56 +++++--- spwn-lang/test/binaryCalculator.spwn | 98 ++++++------- spwn-lang/test/test.spwn | 6 +- 16 files changed, 430 insertions(+), 283 deletions(-) diff --git a/spwn-lang/Cargo.lock b/spwn-lang/Cargo.lock index 23a5c307..c58347b9 100644 --- a/spwn-lang/Cargo.lock +++ b/spwn-lang/Cargo.lock @@ -39,6 +39,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -95,6 +101,12 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "474a626a67200bd107d44179bb3d4fc61891172d11696609264589be6a0e6a43" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + [[package]] name = "block-modes" version = "0.7.0" @@ -337,6 +349,9 @@ name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash", +] [[package]] name = "ident_case" @@ -344,6 +359,25 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "instant" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "internment" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dd2533247278c752288772dabf321a22ed85213e4543d3ad51e5d1288098c8" +dependencies = [ + "hashbrown", + "parking_lot", +] + [[package]] name = "itertools" version = "0.8.2" @@ -377,6 +411,15 @@ dependencies = [ "take_mut", ] +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + [[package]] name = "logos" version = "0.11.4" @@ -428,6 +471,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + [[package]] name = "pin-project-lite" version = "0.2.7" @@ -479,6 +547,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -502,6 +579,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "slab" version = "0.4.3" @@ -525,6 +608,7 @@ dependencies = [ "cached", "core-foundation-sys", "crc32fast", + "internment", "itertools", "lazy_static", "libc", diff --git a/spwn-lang/Cargo.toml b/spwn-lang/Cargo.toml index ed8b8b90..26e9b8c1 100644 --- a/spwn-lang/Cargo.toml +++ b/spwn-lang/Cargo.toml @@ -18,6 +18,8 @@ smallvec = "1.4.2" text_io = "0.1.8" regex = "1.5.4" +internment = "0.5.4" + ariadne = "0.1.3" # errors aes = "0.6.0" diff --git a/spwn-lang/src/ast.rs b/spwn-lang/src/ast.rs index 1dd9fa9d..c71c600f 100644 --- a/spwn-lang/src/ast.rs +++ b/spwn-lang/src/ast.rs @@ -77,11 +77,11 @@ pub enum ValueBody { } impl ValueBody { - pub fn to_variable(&self) -> Variable { + pub fn to_variable(&self, pos: FileRange) -> Variable { Variable { value: ValueLiteral { body: self.clone() }, operator: None, - pos: (0, 0), + pos, //comment: (None, None), path: Vec::new(), tag: Attribute::new(), @@ -354,7 +354,7 @@ impl Expression { Variable { operator: None, value: ValueLiteral::new(ValueBody::Expression(self.clone())), - pos: (0, 0), + pos: self.get_pos(), path: Vec::new(), //comment: (None, None), tag: Attribute::new(), diff --git a/spwn-lang/src/builtin.rs b/spwn-lang/src/builtin.rs index 17a6e6c6..b715d751 100644 --- a/spwn-lang/src/builtin.rs +++ b/spwn-lang/src/builtin.rs @@ -289,7 +289,7 @@ macro_rules! typed_argument_check { #[allow(unused_variables)] #[allow(unused_mut)] #[allow(unused_parens)] - let ( $($arg_name),*) = clone_and_get_value($arguments[$arg_index], $globals.get_lifetime($arguments[$arg_index]), $globals, $context.start_group, true, $info.position.clone()); + let ( $($arg_name),*) = clone_and_get_value($arguments[$arg_index], $globals.get_lifetime($arguments[$arg_index]), $globals, $context.start_group, true); }; (($globals:ident, $arg_index:ident, $arguments:ident, $info:ident, $context:ident) mut ($($arg_name:ident),*)) => { @@ -304,7 +304,7 @@ macro_rules! typed_argument_check { #[allow(unused_mut)] #[allow(unused_parens)] - let ( $($arg_name),*) = match clone_and_get_value($arguments[$arg_index], $globals.get_lifetime($arguments[$arg_index]), $globals, $context.start_group, true, $info.position.clone()) { + let ( $($arg_name),*) = match clone_and_get_value($arguments[$arg_index], $globals.get_lifetime($arguments[$arg_index]), $globals, $context.start_group, true) { Value::$arg_type($($arg_name),*) => ($($arg_name),*), a => { diff --git a/spwn-lang/src/compiler.rs b/spwn-lang/src/compiler.rs index 96360304..0d7bcae3 100644 --- a/spwn-lang/src/compiler.rs +++ b/spwn-lang/src/compiler.rs @@ -21,6 +21,7 @@ use crate::print_with_color; pub const CONTEXT_MAX: usize = 2; use ariadne::Fmt; +use internment::Intern; use termcolor::Color as TColor; pub enum RuntimeError { @@ -47,6 +48,14 @@ pub enum RuntimeError { info: CompilerInfo, }, + PatternMismatchError { + pattern: String, + val: String, + pat_def: CodeArea, + val_def: CodeArea, + info: CompilerInfo, + }, + CustomError(ErrorReport), BuiltinError { @@ -133,7 +142,7 @@ pub fn create_report(rep: ErrorReport) -> ariadne::Report { let mut colors = RainbowColorGenerator::new(0.0, 1.5, 0.8); - let mut report = Report::build(ReportKind::Error, position.file.clone(), position.pos.0) + let mut report = Report::build(ReportKind::Error, position.file.as_ref(), position.pos.0) .with_config(Config::default().with_cross_gap(true)) .with_message(message.clone()); @@ -141,13 +150,14 @@ pub fn create_report(rep: ErrorReport) -> ariadne::Report { for area in info.call_stack { let color = colors.next(); report = report.with_label( - Label::new(area.clone()) + Label::new(area) .with_order(i) .with_message(&format!( "{}: Error comes from this macro call", i.to_string().fg(color) )) - .with_color(color), + .with_color(color) + .with_priority(1), ); i += 1; } @@ -158,25 +168,28 @@ pub fn create_report(rep: ErrorReport) -> ariadne::Report { Label::new(position) .with_order(i) .with_color(color) - .with_message(message), + .with_message(message) + .with_priority(2), ); } if i == 1 && labels.len() == 1 { let color = colors.next(); report = report.with_label( - Label::new(labels[0].0.clone()) + Label::new(labels[0].0) .with_message(labels[0].1.clone()) .with_order(i) - .with_color(color), + .with_color(color) + .with_priority(2), ); } else if !labels.is_empty() { for (area, label) in labels { let color = colors.next(); report = report.with_label( - Label::new(area.clone()) + Label::new(area) .with_message(&format!("{}: {}", i.to_string().fg(color), label)) .with_order(i) - .with_color(color), + .with_color(color) + .with_priority(2), ); i += 1; } @@ -194,11 +207,23 @@ pub fn create_error( note: Option<&str>, ) -> ErrorReport { ErrorReport { - info, + info: info.clone(), message: message.to_string(), labels: labels .iter() - .map(|(a, s)| (a.clone(), s.to_string())) + .map(|(a, s)| { + if !a.file.as_ref().exists() { + ( + CodeArea { + pos: (0, 0), + ..info.position + }, + s.to_string(), + ) + } else { + (*a, s.to_string()) + } + }) .collect(), note: note.map(|s| s.to_string()), } @@ -233,31 +258,15 @@ impl From for ErrorReport { ), RuntimeError::PackageSyntaxError { err, info } => { let syntax_error = ErrorReport::from(err); - let mut labels = vec![( - info.position.clone(), - "Error when parsing this library/module", - )]; - labels.extend( - syntax_error - .labels - .iter() - .map(|(a, b)| (a.clone(), b.as_str())), - ); + let mut labels = vec![(info.position, "Error when parsing this library/module")]; + labels.extend(syntax_error.labels.iter().map(|(a, b)| (*a, b.as_str()))); create_error(info, &syntax_error.message, &labels, None) } RuntimeError::PackageError { err, info } => { let syntax_error = ErrorReport::from(*err); - let mut labels = vec![( - info.position.clone(), - "Error when running this library/module", - )]; - labels.extend( - syntax_error - .labels - .iter() - .map(|(a, b)| (a.clone(), b.as_str())), - ); + let mut labels = vec![(info.position, "Error when running this library/module")]; + labels.extend(syntax_error.labels.iter().map(|(a, b)| (*a, b.as_str()))); create_error(info, &syntax_error.message, &labels, None) } @@ -282,6 +291,32 @@ impl From for ErrorReport { None, ), + RuntimeError::PatternMismatchError { + pattern, + val, + info, + val_def, + pat_def, + } => create_error( + info.clone(), + "Pattern mismatch", + &[ + ( + val_def, + &format!("Value defined as {} here", val.clone().fg(b)), + ), + ( + pat_def, + &format!("Pattern defined as {} here", pattern.clone().fg(b)), + ), + ( + info.position, + &format!("Expected {}, found {}", pattern.fg(a), val.fg(b)), + ), + ], + None, + ), + RuntimeError::CustomError(report) => report, RuntimeError::BuiltinError { message, info } => create_error( @@ -311,26 +346,23 @@ impl From for ErrorReport { #[allow(clippy::comparison_chain)] if context_changes.len() == 1 { labels.push(( - context_changes[0].clone(), + context_changes[0], "New trigger function context was defined here", )); } else if context_changes.len() > 1 { - labels.push(( - context_changes.last().unwrap().clone(), - "Context was changed here", - )); + labels.push((*context_changes.last().unwrap(), "Context was changed here")); for change in context_changes[1..(context_changes.len() - 1)].iter().rev() { - labels.push((change.clone(), "This changes the context inside the macro")); + labels.push((*change, "This changes the context inside the macro")); } labels.push(( - context_changes[0].clone(), + context_changes[0], "New trigger function context was defined here", )); } - labels.push((info.position.clone(), "Attempted to change value here")); + labels.push((info.position, "Attempted to change value here")); create_error( info, @@ -350,21 +382,18 @@ impl From for ErrorReport { #[allow(clippy::comparison_chain)] if context_changes.len() == 1 { labels.push(( - context_changes[0].clone(), + context_changes[0], "New trigger function context was defined here", )); } else if context_changes.len() > 1 { - labels.push(( - context_changes.last().unwrap().clone(), - "Context was changed here", - )); + labels.push((*context_changes.last().unwrap(), "Context was changed here")); for change in context_changes[1..(context_changes.len() - 1)].iter().rev() { - labels.push((change.clone(), "This changes the context inside the macro")); + labels.push((*change, "This changes the context inside the macro")); } labels.push(( - context_changes[0].clone(), + context_changes[0], "New trigger function context was defined here", )); } @@ -412,10 +441,11 @@ pub fn compile_spwn( ) -> Result { //variables that get changed throughout the compiling let mut globals = Globals::new(path.clone()); + globals.includes = included_paths; if statements.is_empty() { return Err(RuntimeError::CustomError(create_error( CompilerInfo::from_area(crate::compiler_info::CodeArea { - file: path, + file: Intern::new(path), pos: (0, 0), }), "this script is empty", @@ -429,9 +459,8 @@ pub fn compile_spwn( // store_value(Value::Null, 1, &mut globals, &start_context); let start_info = CompilerInfo { - includes: included_paths, ..CompilerInfo::from_area(crate::compiler_info::CodeArea { - file: path.clone(), + file: Intern::new(path.clone()), pos: statements[0].pos, }) }; @@ -490,7 +519,7 @@ pub fn compile_spwn( broke: i.position, dropped: CodeArea { pos: (end_pos, end_pos), - file: path, + file: Intern::new(path), }, reason: "the program ended".to_string(), }); @@ -640,7 +669,7 @@ pub fn compile_scope( new_context.start_group = start_group; let new_info = info.clone(); - new_context.fn_context_change_stack = vec![info.position.clone()]; + new_context.fn_context_change_stack = vec![info.position]; //new_info.last_context_change_stack = vec![info.position.clone()]; let (_, inner_returns) = compile_scope( &f.statements, @@ -698,7 +727,7 @@ pub fn compile_scope( globals, new_context.start_group, !mutable, - info.position.clone(), + info.position, ); globals.stored_values[storage] = @@ -744,7 +773,7 @@ pub fn compile_scope( globals, context.start_group, !globals.is_mutable(*v), - info.position.clone(), + globals.get_area(*v), ), ) }) @@ -758,7 +787,7 @@ pub fn compile_scope( 1, globals, &context, - info.position.clone(), + info.position, ); context.variables.insert(String::from(*name), p); @@ -782,24 +811,22 @@ pub fn compile_scope( //initialize type let already = globals.type_ids.get(name); if let Some(t) = already { - if !(t.1 == info.position.file && t.2 == info.position.pos) { + if t.1 != info.position { return Err(RuntimeError::CustomError(create_error( - info, + info.clone(), &format!("the type '{}' is already defined", name), - &[], + &[ + (t.1, "The type was first defined here"), + (info.position, "Attempted to redefine here"), + ], None, ))); } } else { (*globals).type_id_count += 1; - (*globals).type_ids.insert( - name.clone(), - ( - globals.type_id_count, - info.position.file.clone(), - info.position.pos, - ), - ); + (*globals) + .type_ids + .insert(name.clone(), (globals.type_id_count, info.position)); } //Value::TypeIndicator(globals.type_id_count) } @@ -1108,7 +1135,7 @@ pub fn compile_scope( 1, globals, c, - info.position.clone(), + info.position, ); let stored = store_const_value( // store the val key @@ -1116,7 +1143,7 @@ pub fn compile_scope( 1, globals, c, - info.position.clone(), + info.position, ); (*c).variables.insert(f.symbol.clone(), stored); } @@ -1174,7 +1201,7 @@ pub fn compile_scope( 1, globals, c, - info.position.clone(), + info.position, ); (*c).variables.insert(f.symbol.clone(), stored); } @@ -1232,7 +1259,7 @@ pub fn compile_scope( 0, globals, &context, - info.position.clone(), + info.position, ); for c in &mut new_contexts { (*c).variables = context.variables.clone(); @@ -1321,13 +1348,7 @@ pub fn compile_scope( let mut all_values: Returns = SmallVec::new(); for context in &contexts { all_values.push(( - store_value( - Value::Null, - 1, - globals, - context, - info.position.clone(), - ), + store_value(Value::Null, 1, globals, context, info.position), context.clone(), )); } @@ -1349,13 +1370,13 @@ pub fn compile_scope( let (evaled, _) = e.message.eval(context, globals, info.clone(), true)?; for (msg, _) in evaled { let err = globals.stored_values[msg].to_str(globals); - errors.push((info.position.clone(), err)) + errors.push((info.position, err)) } } let mut new_errors = Vec::new(); for (area, msg) in errors.iter() { - new_errors.push((area.clone(), msg.as_str())) + new_errors.push((*area, msg.as_str())) } let err = create_error(info, "Runtime Error", &new_errors, None); @@ -1460,9 +1481,9 @@ pub fn get_import_path( .join(&p), ImportType::Lib(name) => { - let mut outpath = info.includes[0].clone(); + let mut outpath = globals.includes[0].clone(); let mut found = false; - for path in &info.includes { + for path in &globals.includes { if path.join("libraries").join(name).exists() { outpath = path.to_path_buf(); found = true; @@ -1472,12 +1493,12 @@ pub fn get_import_path( if found { outpath } else { - let labels = info + let labels = globals .includes .iter() .map(|p| { ( - info.position.clone(), + info.position, format!("Not found in {}", p.to_string_lossy()), ) }) @@ -1485,7 +1506,7 @@ pub fn get_import_path( let mut new_labels = Vec::new(); for (area, text) in labels.iter() { - new_labels.push((area.clone(), text.as_str())); + new_labels.push((*area, text.as_str())); } return Err(RuntimeError::CustomError(create_error( info, @@ -1601,7 +1622,7 @@ pub fn import_module( let mut new_info = info.clone(); - new_info.position.file = module_path; + new_info.position.file = Intern::new(module_path); new_info.position.pos = (0, 0); if let ImportType::Lib(l) = path { @@ -1625,7 +1646,7 @@ pub fn import_module( return Err(RuntimeError::BreakNeverUsedError { breaktype: *r, info: i.clone(), - broke: i.position.clone(), + broke: i.position, dropped: info.position, reason: "the file ended".to_string(), }); @@ -1675,14 +1696,7 @@ pub fn import_module( }; if out.len() == 1 && &out[0].1 == context { - let cloned = clone_and_get_value( - out[0].0, - 9999, - globals, - context.start_group, - true, - info.position, - ); + let cloned = clone_and_get_value(out[0].0, 9999, globals, context.start_group, true); let s_impl = globals.implementations.clone(); globals.prev_imports.insert(path.clone(), (cloned, s_impl)); diff --git a/spwn-lang/src/compiler_info.rs b/spwn-lang/src/compiler_info.rs index 758b319c..572f8406 100644 --- a/spwn-lang/src/compiler_info.rs +++ b/spwn-lang/src/compiler_info.rs @@ -1,5 +1,5 @@ use crate::parser::FileRange; - +use internment::Intern; use std::path::{Path, PathBuf}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CompilerInfo { @@ -7,7 +7,6 @@ pub struct CompilerInfo { pub call_stack: Vec, pub current_module: String, // empty string means script pub position: CodeArea, - pub includes: Vec, } impl CompilerInfo { @@ -18,7 +17,6 @@ impl CompilerInfo { current_module: String::new(), position: CodeArea::new(), - includes: vec![], } } @@ -37,21 +35,21 @@ impl CompilerInfo { } pub fn add_to_call_stack(&mut self, new: CodeArea) { - self.call_stack.push(self.position.clone()); + self.call_stack.push(self.position); self.position = new; } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct CodeArea { - pub file: PathBuf, + pub file: Intern, pub pos: FileRange, } impl CodeArea { pub fn new() -> Self { CodeArea { - file: PathBuf::new(), + file: Intern::new(PathBuf::new()), pos: (0, 0), } } diff --git a/spwn-lang/src/compiler_types.rs b/spwn-lang/src/compiler_types.rs index 435e1665..a01975bf 100644 --- a/spwn-lang/src/compiler_types.rs +++ b/spwn-lang/src/compiler_types.rs @@ -98,7 +98,7 @@ pub fn handle_operator( 1, globals, context, - info.position.clone() + info.position ), context.clone(), )]); @@ -117,7 +117,7 @@ pub fn handle_operator( globals, context.start_group, false, - info.position.clone(), + info.position, ), info.position.pos, )], @@ -141,7 +141,7 @@ pub fn handle_operator( 1, globals, context, - info.position.clone() + info.position ), context.clone(), )] @@ -159,7 +159,7 @@ pub fn handle_operator( 1, globals, context, - info.position.clone() + info.position ), context.clone(), )] @@ -201,7 +201,7 @@ pub fn handle_unary_operator( 1, globals, context, - info.position.clone() + info.position ), context.clone(), )] @@ -213,7 +213,7 @@ pub fn handle_unary_operator( 1, globals, context, - info.position.clone() + info.position ), context.clone(), )] @@ -411,10 +411,11 @@ pub fn execute_macro( let pat = globals.stored_values[t].clone(); if !val.matches_pat(&pat, &info, globals, context)? { - return Err(RuntimeError::TypeError { - expected: pat.to_str(globals), - found: val.get_type_str(globals), + return Err(RuntimeError::PatternMismatchError { + pattern: pat.to_str(globals), + val: val.get_type_str(globals), val_def: globals.get_area(arg_values[i]), + pat_def: globals.get_area(t), info: info.clone().with_area(CodeArea { pos: arg.pos, ..info.position @@ -461,12 +462,13 @@ pub fn execute_macro( let pat = globals.stored_values[t].clone(); if !val.matches_pat(&pat, &info, globals, context)? { - return Err(RuntimeError::TypeError { - expected: pat.to_str(globals), + return Err(RuntimeError::PatternMismatchError { + pattern: pat.to_str(globals), + val: val.get_type_str(globals), val_def: globals.get_area(arg_values[i]), - found: val.get_type_str(globals), + pat_def: globals.get_area(t), info: info.clone().with_area(CodeArea { - pos: arg.value.get_pos(), + pos: arg.pos, ..info.position }), }); @@ -481,7 +483,7 @@ pub fn execute_macro( globals, context.start_group, true, - m.args[def_index].4.clone(), + m.args[def_index].4, ), ); def_index += 1; @@ -497,7 +499,7 @@ pub fn execute_macro( " This macro requires a parent (a \"self\" value), but it seems to have been called alone (or on a null value). Should be used like this: value.macro(arguments)", - &[(m.args[0].4.clone(), "Macro defined as taking a 'self' argument here"), (info.position, "Called alone here")], + &[(m.args[0].4, "Macro defined as taking a 'self' argument here"), (info.position, "Called alone here")], None, ))); } @@ -511,14 +513,7 @@ Should be used like this: value.macro(arguments)", Some(default) => { new_variables.insert( arg.0.clone(), - clone_value( - *default, - 1, - globals, - context.start_group, - true, - arg.4.clone(), - ), + clone_value(*default, 1, globals, context.start_group, true, arg.4), ); } @@ -527,7 +522,7 @@ Should be used like this: value.macro(arguments)", info.clone(), &format!("Non-optional argument '{}' not satisfied!", arg.0), &[ - (arg.4.clone(), "Value defined as mandatory here (because no default was given)"), + (arg.4, "Value defined as mandatory here (because no default was given)"), (info.position, "Argument not provided here") ], None, @@ -583,7 +578,7 @@ Should be used like this: value.macro(arguments)", return Err(RuntimeError::BreakNeverUsedError { breaktype: *r, info: i.clone(), - broke: i.position.clone(), + broke: i.position, dropped: info.position, reason: "the macro ended".to_string(), }); @@ -600,7 +595,7 @@ Should be used like this: value.macro(arguments)", for (_, c) in &mut returns { if c.start_group != fn_context { - c.fn_context_change_stack.push(info.position.clone()); + c.fn_context_change_stack.push(info.position); } } @@ -707,7 +702,7 @@ pub fn eval_dict( globals, expressions.1.start_group, !globals.is_mutable(expressions.0[expr_index]), - info.position.clone(), + info.position, ), ); } @@ -718,7 +713,6 @@ pub fn eval_dict( globals, expressions.1.start_group, !globals.is_mutable(expressions.0[expr_index]), - info.position.clone(), ); dict_out.extend(match val.clone() { Value::Dict(d) => d.clone(), @@ -735,13 +729,7 @@ pub fn eval_dict( }; } out.push(( - store_value( - Value::Dict(dict_out), - 1, - globals, - context, - info.position.clone(), - ), + store_value(Value::Dict(dict_out), 1, globals, context, info.position), expressions.1, )); } @@ -769,7 +757,7 @@ impl ast::CompoundStatement { new_context.start_group = start_group; let new_info = info.clone(); - new_context.fn_context_change_stack = vec![info.position.clone()]; + new_context.fn_context_change_stack = vec![info.position]; let (contexts, inner_returns) = compile_scope(&self.statements, smallvec![new_context], globals, new_info)?; diff --git a/spwn-lang/src/documentation.rs b/spwn-lang/src/documentation.rs index f6f114a2..52d9f9eb 100644 --- a/spwn-lang/src/documentation.rs +++ b/spwn-lang/src/documentation.rs @@ -31,10 +31,11 @@ pub fn document_lib(path: &str) -> Result<(), RuntimeError> { if !output_path.exists() { std::fs::create_dir(output_path.clone()).unwrap(); } - let mut info = CompilerInfo::new(); - info.includes + let info: CompilerInfo = CompilerInfo::new(); + globals + .includes .push(std::env::current_dir().expect("Cannot access current directory")); - info.includes.push( + globals.includes.push( std::env::current_exe() .expect("Cannot access directory of executable") .parent() diff --git a/spwn-lang/src/globals.rs b/spwn-lang/src/globals.rs index 20154256..e1054b72 100644 --- a/spwn-lang/src/globals.rs +++ b/spwn-lang/src/globals.rs @@ -1,3 +1,5 @@ +use internment::Intern; + ///types and functions used by the compiler use crate::builtin::*; use crate::compiler_info::CodeArea; @@ -28,7 +30,7 @@ pub struct Globals { pub stored_values: ValStorage, pub val_id: usize, - pub type_ids: HashMap, + pub type_ids: HashMap, pub type_id_count: u16, pub func_ids: Vec, @@ -42,6 +44,7 @@ pub struct Globals { pub implementations: Implementations, pub sync_groups: Vec, + pub includes: Vec, } impl Globals { @@ -97,7 +100,7 @@ impl Globals { pub fn get_area(&self, p: StoredValue) -> CodeArea { match self.stored_values.map.get(&p) { - Some(val) => val.def_area.clone(), + Some(val) => val.def_area, None => unreachable!(), } } @@ -151,12 +154,13 @@ impl Globals { parts: vec![0], groups_used: Vec::new(), }], + includes: Vec::new(), }; let mut add_type = |name: &str, id: u16| { globals .type_ids - .insert(String::from(name), (id, PathBuf::new(), (0, 0))) + .insert(String::from(name), (id, CodeArea::new())) }; add_type("group", 0); diff --git a/spwn-lang/src/main.rs b/spwn-lang/src/main.rs index df87dfe0..a0454fff 100644 --- a/spwn-lang/src/main.rs +++ b/spwn-lang/src/main.rs @@ -31,8 +31,8 @@ use optimize::optimize; use parser::*; -use std::env; use std::path::PathBuf; +use std::{collections::HashSet, env}; use std::fs; @@ -217,10 +217,29 @@ fn main() -> Result<(), Box> { } else { String::new() }; + let mut reserved_groups = HashSet::new(); + for obj in &compiled.objects { + for param in obj.params.values() { + match ¶m { + levelstring::ObjParam::Group(g) => { + reserved_groups.insert(*g); + } + levelstring::ObjParam::GroupList(g) => { + reserved_groups.extend(g); + } + _ => (), + } + } + } + let has_stuff = compiled.func_ids.iter().any(|x| !x.obj_list.is_empty()); if opti_enabled && has_stuff { print_with_color("Optimizing triggers...", Color::Cyan); - compiled.func_ids = optimize(compiled.func_ids, compiled.closed_groups); + compiled.func_ids = optimize( + compiled.func_ids, + compiled.closed_groups, + &reserved_groups, + ); } let mut objects = levelstring::apply_fn_ids(&compiled.func_ids); diff --git a/spwn-lang/src/optimize.rs b/spwn-lang/src/optimize.rs index a10877c2..738db270 100644 --- a/spwn-lang/src/optimize.rs +++ b/spwn-lang/src/optimize.rs @@ -90,7 +90,11 @@ const NO_GROUP: Group = Group { id: Id::Specific(0), }; -pub fn optimize(mut obj_in: Vec, mut closed_group: u16) -> Vec { +pub fn optimize( + mut obj_in: Vec, + mut closed_group: u16, + reserved_groups: &HashSet, +) -> Vec { let mut network = TriggerNetwork::new(); // sort all triggers by their group @@ -141,7 +145,12 @@ pub fn optimize(mut obj_in: Vec, mut closed_group: u16) -> Vec, ) { let mut swaps = HashMap::new(); for (group, gang) in network.clone() { - if let Id::Specific(_) = group.id { + if matches!(group.id, Id::Specific(_)) || reserved_groups.contains(&group) { for (i, trigger) in gang.triggers.iter().enumerate() { if trigger.role != TriggerRole::Output { - let (_, new_swaps) = optimize_from(network, objects, (group, i), closed_group); + let (_, new_swaps) = + optimize_from(network, objects, (group, i), closed_group, reserved_groups); swaps.extend(new_swaps); } else { (*network.get_mut(&group).unwrap()).triggers[i].deleted = false; @@ -322,6 +333,7 @@ fn get_targets<'a>( delay: u32, ignore_optimized: bool, closed_group: &mut u16, + reserved_groups: &HashSet, ) -> (Option>, Swaps) { //u32: delay in millis @@ -346,7 +358,7 @@ fn get_targets<'a>( let list: Vec<(usize, Group)>; if let Some(ObjParam::Group(g)) = start_obj.get(&51) { - if let Id::Specific(_) = g.id { + if matches!(g.id, Id::Specific(_)) || reserved_groups.contains(g) { //(*network.get_mut(&start.0).unwrap()).triggers[start.1].deleted = false; return (Some(vec![(*g, delay)]), swaps); } @@ -400,7 +412,8 @@ fn get_targets<'a>( } } else if network[&trigger_ptr.0].connections_in > 1 { (*network.get_mut(&trigger_ptr.0).unwrap()).triggers[trigger_ptr.1].deleted = false; - let (keep, new_swaps) = optimize_from(network, objects, trigger_ptr, closed_group); + let (keep, new_swaps) = + optimize_from(network, objects, trigger_ptr, closed_group, reserved_groups); swaps.extend(new_swaps); if keep { @@ -418,7 +431,7 @@ fn get_targets<'a>( } TriggerRole::Func => { let (keep, new_swaps) = - optimize_from(network, objects, trigger_ptr, closed_group); + optimize_from(network, objects, trigger_ptr, closed_group, reserved_groups); swaps.extend(new_swaps); if keep { (*network.get_mut(&trigger_ptr.0).unwrap()).triggers[trigger_ptr.1] @@ -434,6 +447,7 @@ fn get_targets<'a>( delay + added_delay, ignore_optimized, closed_group, + reserved_groups, ); swaps.extend(new_swaps); match result { @@ -519,6 +533,7 @@ fn optimize_from<'a>( objects: &mut Triggerlist, start: (Group, usize), closed_group: &mut u16, + reserved_groups: &HashSet, ) -> (bool, Swaps) { //returns weather to keep or delete the trigger let mut swaps = HashMap::new(); @@ -535,7 +550,15 @@ fn optimize_from<'a>( //let role = trigger.role; - let (targets, new_swaps) = get_targets(network, objects, start, 0, false, closed_group); + let (targets, new_swaps) = get_targets( + network, + objects, + start, + 0, + false, + closed_group, + reserved_groups, + ); let trigger = network[&start.0].triggers[start.1]; swaps.extend(new_swaps); @@ -633,7 +656,10 @@ fn optimize_from<'a>( // .collect::>() // .iter() { - if network[&g].connections_in == 1 && delay == 0 { + if !(matches!(g.id, Id::Specific(_)) || reserved_groups.contains(&g)) + && network[&g].connections_in == 1 + && delay == 0 + { swaps.insert(g, spawn_group); } else { create_spawn_trigger( diff --git a/spwn-lang/src/parser.rs b/spwn-lang/src/parser.rs index 4e2ecbab..9438475b 100644 --- a/spwn-lang/src/parser.rs +++ b/spwn-lang/src/parser.rs @@ -13,6 +13,7 @@ use std::path::PathBuf; use std::str::FromStr; use ariadne::Fmt; +use internment::Intern; //use ast::ValueLiteral; use logos::Lexer; use logos::Logos; @@ -92,13 +93,13 @@ impl From for ErrorReport { } => create_error( CompilerInfo::from_area(CodeArea { pos, - file: file.clone(), + file: Intern::new(file.clone()), }), "Syntax error", &[( CodeArea { pos, - file, + file: Intern::new(file), }, &format!( "{} {}, {} {}", @@ -114,13 +115,13 @@ impl From for ErrorReport { SyntaxError::UnexpectedErr { found, pos, file } => create_error( CompilerInfo::from_area(CodeArea { pos, - file: file.clone(), + file: Intern::new(file.clone()), }), "Syntax error", &[( CodeArea { pos, - file, + file: Intern::new(file), }, &format!("Unexpected {}", found), )], @@ -130,13 +131,13 @@ impl From for ErrorReport { SyntaxError::SyntaxError { message, pos, file } => create_error( CompilerInfo::from_area(CodeArea { pos, - file: file.clone(), + file: Intern::new(file.clone()), }), "Syntax error", &[( CodeArea { pos, - file, + file: Intern::new(file), }, &message, )], @@ -1394,7 +1395,9 @@ fn parse_dict( tokens.previous(); defs.push(ast::DictDef::Def(( symbol.clone(), - ast::ValueBody::Symbol(symbol).to_variable().to_expression(), + ast::ValueBody::Symbol(symbol) + .to_variable(tokens.position()) + .to_expression(), ))); } @@ -1409,7 +1412,9 @@ fn parse_dict( } defs.push(ast::DictDef::Def(( symbol.clone(), - ast::ValueBody::Symbol(symbol).to_variable().to_expression(), + ast::ValueBody::Symbol(symbol) + .to_variable(tokens.position()) + .to_expression(), ))); //tokens.previous(); break; diff --git a/spwn-lang/src/value.rs b/spwn-lang/src/value.rs index 8e16c651..acacf52a 100644 --- a/spwn-lang/src/value.rs +++ b/spwn-lang/src/value.rs @@ -8,6 +8,7 @@ use crate::compiler_info::CompilerInfo; use crate::{compiler_types::*, context::*, globals::Globals, levelstring::*, value_storage::*}; //use std::boxed::Box; +use internment::Intern; use smallvec::smallvec; use std::collections::HashMap; @@ -50,15 +51,15 @@ pub struct Macro { CodeArea, )>, pub def_context: Context, - pub def_file: PathBuf, + pub def_file: Intern, pub body: Vec, pub tag: ast::Attribute, } impl Macro { pub fn get_arg_area(&self) -> CodeArea { assert!(!self.args.is_empty()); - let first = self.args.first().unwrap().4.clone(); - let last = self.args.last().unwrap().4.clone(); + let first = self.args.first().unwrap().4; + let last = self.args.last().unwrap().4; assert_eq!(first.file, last.file); CodeArea { pos: (first.pos.0, last.pos.1), @@ -447,10 +448,10 @@ pub fn convert_type( (Value::Range(start, end, step), 10) => { Value::Array(if start < end { (*start..*end).step_by(*step).map(|x| - store_value(Value::Number(x as f64), 1, globals, context, info.position.clone())).collect::>() + store_value(Value::Number(x as f64), 1, globals, context, info.position)).collect::>() } else { (*end..*start).step_by(*step).rev().map(|x| - store_value(Value::Number(x as f64), 1, globals, context, info.position.clone())).collect::>() + store_value(Value::Number(x as f64), 1, globals, context, info.position)).collect::>() }) }, @@ -471,7 +472,7 @@ pub fn convert_type( } }, (Value::Str(s), 1) => { - Value::Array(s.chars().map(|x| store_value(Value::Str(x.to_string()), 1, globals, context, info.position.clone())).collect::>()) + Value::Array(s.chars().map(|x| store_value(Value::Str(x.to_string()), 1, globals, context, info.position)).collect::>()) }, @@ -519,7 +520,7 @@ pub fn convert_type( //copied from https://stackoverflow.com/questions/59401720/how-do-i-find-the-key-for-a-value-in-a-hashmap pub fn find_key_for_value( - map: &HashMap, + map: &HashMap, value: u16, ) -> Option<&String> { map.iter() @@ -570,7 +571,7 @@ pub fn macro_to_value( globals, defaults.1.start_group, true, - info.position.clone(), + info.position, )) } None => None, @@ -589,7 +590,7 @@ pub fn macro_to_value( pat, CodeArea { pos: *pos, - ..info.position.clone() + ..info.position }, )); } @@ -600,13 +601,13 @@ pub fn macro_to_value( args, body: m.body.statements.clone(), def_context: defaults.1.clone(), - def_file: info.position.file.clone(), + def_file: info.position.file, tag: m.properties.clone(), })), 1, globals, context, - info.position.clone(), + info.position, ), defaults.1, )) @@ -685,7 +686,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context.clone(), )), @@ -695,7 +696,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context.clone(), )), @@ -715,7 +716,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context.clone(), )); @@ -728,7 +729,7 @@ impl ast::Variable { } ast::ValueBody::Bool(b) => start_val.push(( - store_const_value(Value::Bool(*b), 1, globals, &context, info.position.clone()), + store_const_value(Value::Bool(*b), 1, globals, &context, info.position), context.clone(), )), ast::ValueBody::Symbol(string) => { @@ -753,7 +754,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context.clone(), )), @@ -778,7 +779,7 @@ impl ast::Variable { true, // will be changed CodeArea { pos: a[i].get_pos(), - ..info.position.clone() + ..info.position }, ) }) @@ -787,7 +788,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), x.1.clone(), ) @@ -807,7 +808,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), None => { return Err(RuntimeError::UndefinedErr { @@ -1076,7 +1077,7 @@ impl ast::Variable { val_def: globals.get_area(*id.unwrap()), info, }) - }, Some(globals.stored_values[*pattern.unwrap()].clone())) + }, Some((globals.stored_values[*pattern.unwrap()].clone(), *pattern.unwrap()))) } a => { @@ -1095,14 +1096,15 @@ impl ast::Variable { let val = globals.stored_values[o_val].clone(); if let Some(pat) = pattern { // check if pattern is actually enforced (not null) - if !val.matches_pat(&pat, &info, globals, &context)? { - - return Err(RuntimeError::TypeError { - expected: pat.to_str(globals), - found: val.get_type_str(globals), + if !val.matches_pat(&pat.0, &info, globals, &context)? { + return Err(RuntimeError::PatternMismatchError { + pattern: pat.0.to_str(globals), + val: val.get_type_str(globals), val_def: globals.get_area(o_val), - info, - }) + pat_def: globals.get_area(pat.1), + info + }); + } } let err = Err(RuntimeError::CustomError(create_error( @@ -1176,7 +1178,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context, )); @@ -1423,7 +1425,7 @@ impl ast::Variable { ObjParam::GroupList(g) => { let mut out = Vec::new(); for s in g { - let stored = store_const_value(Value::Group(*s), 1, globals, &index.1, info.position.clone()); + let stored = store_const_value(Value::Group(*s), 1, globals, &index.1, info.position); out.push(stored); } Value::Array(out) @@ -1431,12 +1433,12 @@ impl ast::Variable { ObjParam::Epsilon => { let mut map = HashMap::::new(); - let stored = store_const_value(Value::TypeIndicator(20), 1, globals, &index.1,info.position.clone()); + let stored = store_const_value(Value::TypeIndicator(20), 1, globals, &index.1,info.position); map.insert(TYPE_MEMBER_NAME.to_string(), stored); Value::Dict(map) } }; - let stored = store_const_value(out_val, globals.stored_values.map.get(&prev_v).unwrap().lifetime, globals, &index.1,info.position.clone()); + let stored = store_const_value(out_val, globals.stored_values.map.get(&prev_v).unwrap().lifetime, globals, &index.1,info.position); new_out.push((stored, index.1, prev_v)); break; } @@ -1507,7 +1509,7 @@ impl ast::Variable { 1, globals, &index.1, - info.position.clone(), + info.position, ); new_out.push((stored, index.1, prev_v)); @@ -1580,7 +1582,7 @@ impl ast::Variable { match globals.stored_values[*prev_v].clone() { Value::TypeIndicator(t) => { let (dicts, returns) = ast::ValueBody::Dictionary(defs.clone()) - .to_variable() + .to_variable(info.position.pos) .to_value(prev_c.clone(), globals, info.clone(), constant)?; inner_returns.extend(returns); for dict in &dicts { @@ -1589,7 +1591,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ); if let Value::Dict(map) = &mut globals.stored_values[dict.0] { (*map).insert(TYPE_MEMBER_NAME.to_string(), stored_type); @@ -1698,7 +1700,7 @@ impl ast::Variable { 1, globals, &context, - info.position.clone(), + info.position, ), context, )) @@ -1924,9 +1926,9 @@ impl ast::Variable { let value = match &self.operator { Some(ast::UnaryOperator::Let) => { - store_value(Value::Null, 1, globals, context, info.position.clone()) + store_value(Value::Null, 1, globals, context, info.position) } - None => store_const_value(Value::Null, 1, globals, context, info.position.clone()), + None => store_const_value(Value::Null, 1, globals, context, info.position), a => { @@ -1963,7 +1965,7 @@ impl ast::Variable { 1, globals, context, - info.position.clone(), + info.position, ) } else { return Err(RuntimeError::CustomError(create_error( @@ -2067,14 +2069,14 @@ impl ast::Variable { .unwrap(); if !stored.mutable { return Err(RuntimeError::MutabilityError { - val_def: stored.def_area.clone(), + val_def: stored.def_area, info: info.clone(), }); } let fn_context = context.start_group; if stored.fn_context != fn_context { return Err(RuntimeError::ContextChangeMutateError { - val_def: stored.def_area.clone(), + val_def: stored.def_area, info: info.clone(), context_changes: context.fn_context_change_stack.clone() }); diff --git a/spwn-lang/src/value_storage.rs b/spwn-lang/src/value_storage.rs index 961b819a..f0b3ad03 100644 --- a/spwn-lang/src/value_storage.rs +++ b/spwn-lang/src/value_storage.rs @@ -206,13 +206,13 @@ pub fn store_value( (*globals).val_id += 1; index } + pub fn clone_and_get_value( index: usize, lifetime: u16, globals: &mut Globals, fn_context: Group, constant: bool, - area: CodeArea, ) -> Value { let mut old_val = globals.stored_values[index].clone(); @@ -220,7 +220,7 @@ pub fn clone_and_get_value( Value::Array(arr) => { old_val = Value::Array( arr.iter() - .map(|x| clone_value(*x, lifetime, globals, fn_context, constant, area.clone())) + .map(|x| clone_value_preserve_area(*x, lifetime, globals, fn_context, constant)) .collect(), ); } @@ -231,7 +231,7 @@ pub fn clone_and_get_value( .map(|(k, v)| { ( k.clone(), - clone_value(*v, lifetime, globals, fn_context, constant, area.clone()), + clone_value_preserve_area(*v, lifetime, globals, fn_context, constant), ) }) .collect(), @@ -241,24 +241,14 @@ pub fn clone_and_get_value( Value::Macro(m) => { for arg in &mut m.args { if let Some(def_val) = &mut arg.1 { - (*def_val) = clone_value( - *def_val, - lifetime, - globals, - fn_context, - constant, - area.clone(), + (*def_val) = clone_value_preserve_area( + *def_val, lifetime, globals, fn_context, constant, ); } if let Some(def_val) = &mut arg.3 { - (*def_val) = clone_value( - *def_val, - lifetime, - globals, - fn_context, - constant, - area.clone(), + (*def_val) = clone_value_preserve_area( + *def_val, lifetime, globals, fn_context, constant, ); } } @@ -281,7 +271,7 @@ pub fn clone_value( constant: bool, area: CodeArea, ) -> StoredValue { - let old_val = clone_and_get_value(index, lifetime, globals, fn_context, constant, area.clone()); + let old_val = clone_and_get_value(index, lifetime, globals, fn_context, constant); //clone all inner values //do the thing @@ -304,6 +294,36 @@ pub fn clone_value( new_index } +pub fn clone_value_preserve_area( + index: usize, + lifetime: u16, + globals: &mut Globals, + fn_context: Group, + constant: bool, +) -> StoredValue { + let old_val = clone_and_get_value(index, lifetime, globals, fn_context, constant); + + //clone all inner values + //do the thing + //bing bang + //profit + let new_index = globals.val_id; + //println!("1index: {}, value: {}", new_index, old_val.to_str(&globals)); + + (*globals).stored_values.map.insert( + new_index, + StoredValData { + val: old_val, + fn_context, + mutable: !constant, + lifetime, + def_area: globals.get_area(index), + }, + ); + (*globals).val_id += 1; + new_index +} + // pub fn clone_value_to( // index: usize, // to: usize, diff --git a/spwn-lang/test/binaryCalculator.spwn b/spwn-lang/test/binaryCalculator.spwn index de1dccf9..b28dede4 100644 --- a/spwn-lang/test/binaryCalculator.spwn +++ b/spwn-lang/test/binaryCalculator.spwn @@ -1,62 +1,50 @@ extract obj_props; -type @binaryCalculator; - -impl @binaryCalculator { - - new: (bits: @number, x: @number, y: @number) { - let bitCounters = []; - - for i in ..bits { - item = ?i; - - $.add(obj { - OBJ_ID: 1615, - X: x + i * 30, - Y: y, - ITEM: item, - GROUPS: 999g - }); - - bitCounters.push(counter(item)); - } - - return { - bitCounters: bitCounters, - type: @binaryCalculator +decimalMemory = 10i; +decimalCounter = counter(decimalMemory); +binaryMemory = [11i, 12i, 13i, 14i, 15i, 16i, 17i, 18i]; +let binaryCounters = []; + +$.add(obj { + OBJ_ID: 1615, + X: 300, + Y: 300, + ITEM: decimalMemory, + GROUPS: 999g +}); + +for i in 0..binaryMemory.length { + $.add(obj { + OBJ_ID: 1615, + X: 300 + i * 30, + Y: 270, + ITEM: binaryMemory[i], + GROUPS: 999g + }); + binaryCounters.push(counter(binaryMemory[i])); +} + +binaryToNumeric = !{ + decimalCounter = 0; + wait(1); + + for i in 0..binaryCounters.length { + if binaryCounters[binaryCounters.length - 1 - i] as @bool { + decimalCounter += 2 ^ i; } - }, - binaryToDecimal: (self, target: @counter) { - target = 0; - wait(1); - - for i in ..self.bitCounters.length { - if self.bitCounters[self.bitCounters.length - 1 - i] as @bool { - target += 2 ^ i; - } - } - }, - decimalToBinary: (self, source: @counter, calcSpeed: @number = 5) { - let tempcounters = []; + } +} - for i in ..self.bitCounters.length { - tempcounters.push(counter()); - } +decimalToBinary = !{ + tempLength = binaryCounters.length + 1; - source.copy_to(tempcounters, speed = 10); + for i in 1..tempLength { + decimalCounter.divide(2, remainder = binaryCounters[binaryCounters.length - i], speed = 4); + } - for i in ..self.bitCounters.length { - -> () { - tempcounters[i].divide(2 ^ i, speed = calcSpeed); - tempcounters[i].divide(2, remainder = self.bitCounters[self.bitCounters.length - 1 - i], speed = calcSpeed); - }(); - } - }, - prettyDecimalToBinary: (self, source: @counter, calcSpeed: @number = 10) { - for i in ..self.bitCounters.length { - source.divide(2, remainder = self.bitCounters[self.bitCounters.length - 1 - i], speed = calcSpeed); - } + binaryToNumeric!; +} - self.binaryToDecimal(source); - } -} \ No newline at end of file +decimalCounter = 213; // Edit this +wait(1); +decimalToBinary!; \ No newline at end of file diff --git a/spwn-lang/test/test.spwn b/spwn-lang/test/test.spwn index 57add3a0..0e9dca67 100644 --- a/spwn-lang/test/test.spwn +++ b/spwn-lang/test/test.spwn @@ -1,5 +1 @@ - - -if !(counter(1i) == 0) { - 10g.move(10, 0) -} \ No newline at end of file +"hello".hi \ No newline at end of file