diff --git a/setup/install.ab b/setup/install.ab index b51cae99..aabcecd1 100644 --- a/setup/install.ab +++ b/setup/install.ab @@ -20,36 +20,36 @@ let url = 'https://github.com/Ph0enixKM/{name}/releases/download/{tag}/amber_{os $test -d "{place}" > /dev/null$ if $echo \$?$ == '0' { - $echo "Amber already installed" $ - $echo "It seems that Amber is already installed on your system."$ - $echo "If you want to reinstall Amber - try to uninstall it first."$ - $echo "(Find out more at https://amber.marbl.cc)"$ + echo 'Amber already installed' + echo 'It seems that Amber is already installed on your system. ({place})' + echo 'If you want to reinstall Amber, uninstall it first.' + echo '(Find out more at https://amber.marbl.cc)' $exit 0$ } -$echo "Installing Amber" $ +echo 'Installing Amber' # Download Amber if { # Check if ruby is installed $ruby -v > /dev/null; echo \$?$ == '0' { let code = 'require "open-uri"; open("{target}", "wb") do |file|; file << open("{url}").read; end' - $echo "Using ruby as a download method..."$ + echo 'Using ruby as a download method...' $ruby -e "{code}"$ } # Check if curl is installed $curl -v > /dev/null; echo \$?$ == '0' { - $echo "Using curl as a download method..."$ + echo 'Using curl as a download method...' $curl -o "{target}" "{url}"$ } # Check if wget is installed $wget -v > /dev/null; echo \$?$ == '0' { - $echo "Using wget as a download method..."$ + echo 'Using wget as a download method...' $wget -O "{target}" "{url}"$ } else { - $echo "Neither ruby, curl or wget are installed on your system."$ - $echo "Please install one of them and try again."$ + echo 'Neither ruby, curl or wget are installed on your system.' + echo 'Please install one of them and try again.' $exit 1$ } } @@ -62,4 +62,4 @@ $sudo chmod +x {place}/{target}$ # Create amber symbol link $sudo ln -s {place}/{target} /usr/local/bin/{target}$ # Send success message -$echo "Amber has been installed successfully. 🎉"$ \ No newline at end of file +echo 'Amber has been installed successfully. 🎉' \ No newline at end of file diff --git a/setup/install.sh b/setup/install.sh index a7c01871..9546dcf1 100755 --- a/setup/install.sh +++ b/setup/install.sh @@ -1,36 +1,36 @@ -name="AmberNative"; -target="amber"; -tag="v0.1.1-alpha"; -place="/opt/amber"; -os=$(if [ $([ "_$(uname -s)" != "_Darwin" ]; echo $?) != 0 ]; then echo "macos"; else echo "linux"; fi); -arch=$(if [ $([ "_$(uname -m)" != "_arm64" ]; echo $?) != 0 ]; then echo "aarch64"; else echo "x86_64"; fi); -url="https://github.com/Ph0enixKM/${name}/releases/download/${tag}/amber_${os}_${arch}"; -test -d "${place}" > /dev/null; +__0_name="AmberNative"; +__1_target="amber"; +__2_tag="v0.1.1-alpha"; +__3_place="/opt/amber"; +__4_os=$(if [ $([ "_$(uname -s)" != "_Darwin" ]; echo $?) != 0 ]; then echo "macos"; else echo "linux"; fi); +__5_arch=$(if [ $([ "_$(uname -m)" != "_arm64" ]; echo $?) != 0 ]; then echo "aarch64"; else echo "x86_64"; fi); +__6_url="https://github.com/Ph0enixKM/${__0_name}/releases/download/${__2_tag}/amber_${__4_os}_${__5_arch}"; +test -d "${__3_place}" > /dev/null; if [ $([ "_$(echo $?)" != "_0" ]; echo $?) != 0 ]; then - echo "Amber already installed" ; - echo "It seems that Amber is already installed on your system."; - echo "If you want to reinstall Amber - try to uninstall it first."; + echo "Amber already installed"; + echo "It seems that Amber is already installed on your system. (${__3_place})"; + echo "If you want to reinstall Amber, uninstall it first."; echo "(Find out more at https://amber.marbl.cc)"; exit 0 fi; -echo "Installing Amber" ; +echo "Installing Amber"; if [ $([ "_$(ruby -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then - code="require \"open-uri\"; open(\"${target}\", \"wb\") do |file|; file << open(\"${url}\").read; end"; + __7_code="require \"open-uri\"; open(\"${__1_target}\", \"wb\") do |file|; file << open(\"${__6_url}\").read; end"; echo "Using ruby as a download method..."; - ruby -e "${code}" + ruby -e "${__7_code}" elif [ $([ "_$(curl -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then echo "Using curl as a download method..."; - curl -o "${target}" "${url}" + curl -o "${__1_target}" "${__6_url}" elif [ $([ "_$(wget -v > /dev/null; echo $?)" != "_0" ]; echo $?) != 0 ]; then echo "Using wget as a download method..."; - wget -O "${target}" "${url}" + wget -O "${__1_target}" "${__6_url}" else echo "Neither ruby, curl or wget are installed on your system."; echo "Please install one of them and try again."; exit 1 fi; -sudo mkdir ${place} > /dev/null; -sudo mv ${target} ${place}/${target}; -sudo chmod +x ${place}/${target}; -sudo ln -s ${place}/${target} /usr/local/bin/${target}; +sudo mkdir ${__3_place} > /dev/null; +sudo mv ${__1_target} ${__3_place}/${__1_target}; +sudo chmod +x ${__3_place}/${__1_target}; +sudo ln -s ${__3_place}/${__1_target} /usr/local/bin/${__1_target}; echo "Amber has been installed successfully. 🎉" \ No newline at end of file diff --git a/setup/uninstall.ab b/setup/uninstall.ab index 5ec11718..85d4d941 100644 --- a/setup/uninstall.ab +++ b/setup/uninstall.ab @@ -5,8 +5,8 @@ $test -d "{place}" > /dev/null$ if $echo \$?$ == '0' { $sudo rm -rf "{place}"$ $sudo rm '/usr/local/bin/amber'$ - $echo 'Uninstalled Amber successfully 🎉'$ + echo 'Uninstalled Amber successfully 🎉' } else { - $echo 'Amber is not installed'$ + echo 'Amber is not installed' } diff --git a/setup/uninstall.sh b/setup/uninstall.sh index a15729a3..7c2d6199 100755 --- a/setup/uninstall.sh +++ b/setup/uninstall.sh @@ -1,9 +1,9 @@ -place="/opt/amber"; -test -d "${place}" > /dev/null; +__0_place="/opt/amber"; +test -d "${__0_place}" > /dev/null; if [ $([ "_$(echo $?)" != "_0" ]; echo $?) != 0 ]; then - sudo rm -rf "${place}"; + sudo rm -rf "${__0_place}"; sudo rm '/usr/local/bin/amber'; - echo 'Uninstalled Amber successfully 🎉' + echo "Uninstalled Amber successfully 🎉" else - echo 'Amber is not installed' + echo "Amber is not installed" fi \ No newline at end of file diff --git a/src/compiler.rs b/src/compiler.rs index 93cfb6c6..eb1f75a2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -74,12 +74,13 @@ impl AmberCompiler { pub fn translate(&self, block: Block, meta: ParserMetadata) -> String { let imports_sorted = meta.import_history.topological_sort(); - let imports_blocks = meta.import_history.import_map.clone(); + let imports_blocks = meta.import_history.import_blocks.clone(); + let _imports = meta.import_history.imports.clone(); let mut meta = TranslateMetadata::new(&meta); let mut result = vec![]; for index in imports_sorted.iter() { - if *index != 0 { - result.push(imports_blocks[*index - 1].translate(&mut meta)); + if let Some(block) = imports_blocks[*index].clone() { + result.push(block.translate(&mut meta)); } } result.push(block.translate(&mut meta)); diff --git a/src/modules/function/declaration.rs b/src/modules/function/declaration.rs index 6588b64b..fb3b2e96 100644 --- a/src/modules/function/declaration.rs +++ b/src/modules/function/declaration.rs @@ -105,10 +105,7 @@ impl TranslateModule for FunctionDeclaration { let blocks = meta.mem.get_function_instances(self.id).unwrap().to_vec(); // Translate each one of them for (index, function) in blocks.iter().enumerate() { - let mut name = self.name.clone(); - if index != 0 { - name = format!("__{}_{}", index, name); - } + let name = format!("__{}_v{}_{}", self.id, index, self.name); // Parse the function body result.push(format!("function {} {{", name)); if let Some(args) = self.set_args_as_variables(meta) { diff --git a/src/modules/function/invocation.rs b/src/modules/function/invocation.rs index 9a00dc40..02091534 100644 --- a/src/modules/function/invocation.rs +++ b/src/modules/function/invocation.rs @@ -12,7 +12,8 @@ pub struct FunctionInvocation { name: String, args: Vec, kind: Type, - variant_id: usize + variant_id: usize, + id: usize } impl Typed for FunctionInvocation { @@ -29,7 +30,8 @@ impl SyntaxModule for FunctionInvocation { name: String::new(), args: vec![], kind: Type::Null, - variant_id: 0 + variant_id: 0, + id: 0 } } @@ -39,7 +41,7 @@ impl SyntaxModule for FunctionInvocation { self.name = variable(meta, variable_name_extensions())?; // Get the arguments token(meta, "(")?; - handle_function_reference(meta, tok.clone(), &self.name)?; + self.id = handle_function_reference(meta, tok.clone(), &self.name)?; loop { if token(meta, ")").is_ok() { break @@ -60,7 +62,7 @@ impl SyntaxModule for FunctionInvocation { impl TranslateModule for FunctionInvocation { fn translate(&self, meta: &mut TranslateMetadata) -> String { - let name = if self.variant_id != 0 { format!("__{}_{}", self.variant_id, self.name) } else { self.name.clone() }; + let name = format!("__{}_v{}_{}", self.id, self.variant_id, self.name); let args = self.args.iter().map(|arg| arg.translate(meta)).collect::>().join(" "); format!("$({name} {args})") } diff --git a/src/modules/function/invocation_utils.rs b/src/modules/function/invocation_utils.rs index 668be0e2..d4273d5c 100644 --- a/src/modules/function/invocation_utils.rs +++ b/src/modules/function/invocation_utils.rs @@ -28,7 +28,7 @@ fn run_function_with_args(meta: &mut ParserMetadata, name: &str, args: &[Type], // Create a sub context for new variables new_meta.mem.push_scope(); for (kind, (name, _generic)) in args.iter().zip(function.args.iter()) { - new_meta.mem.add_variable(name, kind.clone()); + new_meta.mem.add_variable(name, kind.clone(), false); } // Parse the function body syntax(&mut new_meta, &mut block)?; @@ -41,17 +41,19 @@ fn run_function_with_args(meta: &mut ParserMetadata, name: &str, args: &[Type], Ok(meta.mem.add_function_instance(function.id, args, function.returns, block)) } -pub fn handle_function_reference(meta: &mut ParserMetadata, tok: Option, name: &str) -> Result<(), Failure> { - if meta.mem.get_function(name).is_none() { - let message = format!("Function '{}' does not exist", name); - // Find other similar variable if exists - return if let Some(comment) = handle_similar_function(meta, name) { - error!(meta, tok, message, comment) - } else { - error!(meta, tok, message) +pub fn handle_function_reference(meta: &mut ParserMetadata, tok: Option, name: &str) -> Result { + match meta.mem.get_function(name) { + Some(fun_decl) => Ok(fun_decl.id), + None => { + let message = format!("Function '{}' does not exist", name); + // Find other similar variable if exists + if let Some(comment) = handle_similar_function(meta, name) { + error!(meta, tok, message, comment) + } else { + error!(meta, tok, message) + } } } - Ok(()) } pub fn handle_function_parameters(meta: &mut ParserMetadata, name: &str, args: &[Type], tok: Option) -> Result<(Type, usize), Failure> { diff --git a/src/modules/imports/import.rs b/src/modules/imports/import.rs index d46900bb..8c50a53e 100644 --- a/src/modules/imports/import.rs +++ b/src/modules/imports/import.rs @@ -1,5 +1,4 @@ use std::fs; -use std::path::Path; use heraclitus_compiler::prelude::*; use crate::compiler::AmberCompiler; use crate::modules::block::Block; @@ -14,7 +13,7 @@ pub struct Import { } impl Import { - fn handle_export(&mut self, meta: &mut ParserMetadata, exports: Exports) { + fn handle_export(&mut self, meta: &mut ParserMetadata, exports: Exports) -> SyntaxResult { for export in exports.get_exports().iter().cloned() { match export { ExportUnit::Function(mut func_decl) => { @@ -25,6 +24,7 @@ impl Import { } } } + Ok(()) } fn add_import(&mut self, meta: &mut ParserMetadata, tok: Option, path: &str) -> SyntaxResult { @@ -37,26 +37,8 @@ impl Import { Ok(()) } - fn resolve_path(&mut self, meta: &mut ParserMetadata, tok: Option) -> Result { - let mut path = meta.path.as_ref() - .map_or_else(|| Path::new("."), |path| Path::new(path)) - .to_path_buf(); - path.pop(); - path.push(&self.path.value); - match path.to_str() { - Some(path) => { - self.add_import(meta, tok, path)?; - Ok(path.to_string()) - } - None => error!(meta, tok => { - message: format!("Could not resolve path '{}'", path.display()), - comment: "Path is not valid UTF-8" - }) - } - } - fn resolve_import(&mut self, meta: &mut ParserMetadata, tok: Option) -> Result { - match fs::read_to_string(self.resolve_path(meta, tok.clone())?) { + match fs::read_to_string(self.path.value.clone()) { Ok(content) => Ok(content), Err(err) => error!(meta, tok => { message: format!("Could not read file '{}'", self.path.value), @@ -66,6 +48,13 @@ impl Import { } fn handle_import(&mut self, meta: &mut ParserMetadata, tok: Option, imported_code: String) -> SyntaxResult { + match meta.import_history.get_export(Some(self.path.value.clone())) { + Some(exports) => self.handle_export(meta, exports), + None => self.handle_compile_code(meta, tok, imported_code) + } + } + + fn handle_compile_code(&mut self, meta: &mut ParserMetadata, tok: Option, imported_code: String) -> SyntaxResult { match AmberCompiler::new(imported_code.clone(), Some(self.path.value.clone())).tokenize() { Ok(tokens) => { let mut block = Block::new(); @@ -85,8 +74,9 @@ impl Import { meta.mem.scopes = vec![]; syntax(meta, &mut block)?; meta.mem.scopes = scopes; - meta.import_history.import_map.push(block); - self.handle_export(meta, meta.mem.exports.clone()); + meta.import_history.add_import_block(Some(self.path.value.clone()), block); + meta.import_history.add_export(Some(self.path.value.clone()), meta.mem.exports.clone()); + self.handle_export(meta, meta.mem.exports.clone())?; // Restore snapshot of current file meta.code = code; meta.path = path; @@ -115,6 +105,9 @@ impl SyntaxModule for Import { fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { token(meta, "import")?; let tok = meta.get_current_token(); + if meta.mem.get_depth() > 1 { + return error!(meta, tok, "Imports must be in the global scope") + } token(meta, "*")?; token(meta, "from")?; let tok_str = meta.get_current_token(); @@ -123,6 +116,7 @@ impl SyntaxModule for Import { self.add_import(meta, tok_str, "[standard library]")?; AmberCompiler::import_std() } else { + self.add_import(meta, tok_str.clone(), &self.path.value.clone())?; self.resolve_import(meta, tok_str)? }; self.handle_import(meta, tok, imported_code)?; diff --git a/src/modules/imports/import_string.rs b/src/modules/imports/import_string.rs index 6932fc48..8e171d0e 100644 --- a/src/modules/imports/import_string.rs +++ b/src/modules/imports/import_string.rs @@ -1,4 +1,5 @@ use heraclitus_compiler::prelude::*; +use std::path::Path; use crate::utils::ParserMetadata; #[derive(Debug, Clone)] @@ -7,9 +8,26 @@ pub struct ImportString { } impl ImportString { - pub fn std_lib_path(&mut self) { + fn resolve_path(&mut self, meta: &mut ParserMetadata, tok: Option) -> SyntaxResult { if self.value == "std" { self.value = "[standard library]".to_string(); + return Ok(()) + + } + let mut path = meta.path.as_ref() + .map_or_else(|| Path::new("."), |path| Path::new(path)) + .to_path_buf(); + path.pop(); + path.push(&self.value); + match path.to_str() { + Some(path) => { + self.value = path.to_string(); + Ok(()) + } + None => error!(meta, tok => { + message: format!("Could not resolve path '{}'", path.display()), + comment: "Path is not valid UTF-8" + }) } } } @@ -24,10 +42,11 @@ impl SyntaxModule for ImportString { } fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { + let tok = meta.get_current_token(); let value = token_by(meta, |word| word.starts_with('\''))?; if value.ends_with('\'') { self.value = value[1..value.len() - 1].to_string(); - self.std_lib_path(); + self.resolve_path(meta, tok)?; } else { return error!(meta, meta.get_current_token(), "Import string cannot interpolate expressions") diff --git a/src/modules/main.rs b/src/modules/main.rs index b82b6dd6..24fbffe7 100644 --- a/src/modules/main.rs +++ b/src/modules/main.rs @@ -29,7 +29,7 @@ impl SyntaxModule for Main { token(meta, "main")?; // Main cannot be parsed inside of a block if meta.mem.get_depth() > 1 { - return error!(meta, tok, "Main module must be in the global scope") + return error!(meta, tok, "Main must be in the global scope") } // If this main is included in other file, skip it if !meta.trace.is_empty() { @@ -53,7 +53,7 @@ impl SyntaxModule for Main { meta.mem.push_scope(); // Create variables for arg in self.args.iter() { - meta.mem.add_variable(arg, Type::Text); + meta.mem.add_variable(arg, Type::Text, false); } // Parse the block syntax(meta, &mut self.block)?; diff --git a/src/modules/shorthand/add.rs b/src/modules/shorthand/add.rs index 7785a1cc..d81fb90e 100644 --- a/src/modules/shorthand/add.rs +++ b/src/modules/shorthand/add.rs @@ -9,7 +9,8 @@ use crate::modules::types::{Type, Typed}; pub struct ShorthandAdd { var: String, expr: Box, - kind: Type + kind: Type, + global_id: Option } impl SyntaxModule for ShorthandAdd { @@ -19,7 +20,8 @@ impl SyntaxModule for ShorthandAdd { Self { var: String::new(), expr: Box::new(Expr::new()), - kind: Type::Null + kind: Type::Null, + global_id: None } } @@ -28,7 +30,7 @@ impl SyntaxModule for ShorthandAdd { self.var = variable(meta, variable_name_extensions())?; let tok = meta.get_current_token(); token(meta, "+=")?; - self.kind = handle_variable_reference(meta, var_tok, &self.var)?; + (self.global_id, self.kind) = handle_variable_reference(meta, var_tok, &self.var)?; self.expr.parse(meta)?; let message = "Add operation can only add numbers or text"; expression_arms_of_type(meta, &self.kind, &self.expr.get_type(), &[Type::Num, Type::Text], tok, message)?; @@ -39,7 +41,10 @@ impl SyntaxModule for ShorthandAdd { impl TranslateModule for ShorthandAdd { fn translate(&self, meta: &mut TranslateMetadata) -> String { let expr = self.expr.translate(meta); - let name = self.var.clone(); + let name = match self.global_id { + Some(id) => format!("__{id}_{}", self.var), + None => self.var.clone() + }; let var = format!("${{{name}}}"); if self.kind == Type::Text { format!("{}+={}", name, expr) diff --git a/src/modules/shorthand/div.rs b/src/modules/shorthand/div.rs index 6285f95b..18682839 100644 --- a/src/modules/shorthand/div.rs +++ b/src/modules/shorthand/div.rs @@ -9,7 +9,8 @@ use crate::modules::types::{Type, Typed}; pub struct ShorthandDiv { var: String, expr: Box, - kind: Type + kind: Type, + global_id: Option } impl SyntaxModule for ShorthandDiv { @@ -19,7 +20,8 @@ impl SyntaxModule for ShorthandDiv { Self { var: String::new(), expr: Box::new(Expr::new()), - kind: Type::Null + kind: Type::Null, + global_id: None } } @@ -28,7 +30,7 @@ impl SyntaxModule for ShorthandDiv { self.var = variable(meta, variable_name_extensions())?; let tok = meta.get_current_token(); token(meta, "/=")?; - self.kind = handle_variable_reference(meta, var_tok, &self.var)?; + (self.global_id, self.kind) = handle_variable_reference(meta, var_tok, &self.var)?; self.expr.parse(meta)?; let message = "Division operation can only divide numbers"; expression_arms_of_type(meta, &self.kind, &self.expr.get_type(), &[Type::Num], tok, message)?; @@ -39,7 +41,10 @@ impl SyntaxModule for ShorthandDiv { impl TranslateModule for ShorthandDiv { fn translate(&self, meta: &mut TranslateMetadata) -> String { let expr = self.expr.translate(meta); - let name = self.var.clone(); + let name = match self.global_id { + Some(id) => format!("__{id}_{}", self.var), + None => self.var.clone() + }; let var = format!("${{{name}}}"); format!("{}={}", name, translate_computation(meta, ArithOp::Div, Some(var), Some(expr))) } diff --git a/src/modules/shorthand/modulo.rs b/src/modules/shorthand/modulo.rs index e2d0cc9b..d55a65f7 100644 --- a/src/modules/shorthand/modulo.rs +++ b/src/modules/shorthand/modulo.rs @@ -9,7 +9,8 @@ use crate::modules::types::{Type, Typed}; pub struct ShorthandModulo { var: String, expr: Box, - kind: Type + kind: Type, + global_id: Option } impl SyntaxModule for ShorthandModulo { @@ -19,7 +20,8 @@ impl SyntaxModule for ShorthandModulo { Self { var: String::new(), expr: Box::new(Expr::new()), - kind: Type::Null + kind: Type::Null, + global_id: None } } @@ -28,7 +30,7 @@ impl SyntaxModule for ShorthandModulo { self.var = variable(meta, variable_name_extensions())?; let tok = meta.get_current_token(); token(meta, "%=")?; - self.kind = handle_variable_reference(meta, var_tok, &self.var)?; + (self.global_id, self.kind) = handle_variable_reference(meta, var_tok, &self.var)?; self.expr.parse(meta)?; let message = "Modulo operation can only be applied to numbers"; expression_arms_of_type(meta, &self.kind, &self.expr.get_type(), &[Type::Num], tok, message)?; @@ -39,7 +41,10 @@ impl SyntaxModule for ShorthandModulo { impl TranslateModule for ShorthandModulo { fn translate(&self, meta: &mut TranslateMetadata) -> String { let expr = self.expr.translate(meta); - let name = self.var.clone(); + let name = match self.global_id { + Some(id) => format!("__{id}_{}", self.var), + None => self.var.clone() + }; let var = format!("${{{name}}}"); format!("{}={}", name, translate_computation(meta, ArithOp::Modulo, Some(var), Some(expr))) } diff --git a/src/modules/shorthand/mul.rs b/src/modules/shorthand/mul.rs index d0dc8d98..1f7acd57 100644 --- a/src/modules/shorthand/mul.rs +++ b/src/modules/shorthand/mul.rs @@ -9,7 +9,8 @@ use crate::modules::types::{Type, Typed}; pub struct ShorthandMul { var: String, expr: Box, - kind: Type + kind: Type, + global_id: Option } impl SyntaxModule for ShorthandMul { @@ -19,7 +20,8 @@ impl SyntaxModule for ShorthandMul { Self { var: String::new(), expr: Box::new(Expr::new()), - kind: Type::Null + kind: Type::Null, + global_id: None } } @@ -28,7 +30,7 @@ impl SyntaxModule for ShorthandMul { self.var = variable(meta, variable_name_extensions())?; let tok = meta.get_current_token(); token(meta, "*=")?; - self.kind = handle_variable_reference(meta, var_tok, &self.var)?; + (self.global_id, self.kind) = handle_variable_reference(meta, var_tok, &self.var)?; self.expr.parse(meta)?; let message = "Multiplication operation can only multiply numbers"; expression_arms_of_type(meta, &self.kind, &self.expr.get_type(), &[Type::Num, Type::Text], tok, message)?; @@ -39,7 +41,10 @@ impl SyntaxModule for ShorthandMul { impl TranslateModule for ShorthandMul { fn translate(&self, meta: &mut TranslateMetadata) -> String { let expr = self.expr.translate(meta); - let name = self.var.clone(); + let name = match self.global_id { + Some(id) => format!("__{id}_{}", self.var), + None => self.var.clone() + }; let var = format!("${{{name}}}"); format!("{}={}", name, translate_computation(meta, ArithOp::Mul, Some(var), Some(expr))) } diff --git a/src/modules/shorthand/sub.rs b/src/modules/shorthand/sub.rs index ba91ca11..19b7433b 100644 --- a/src/modules/shorthand/sub.rs +++ b/src/modules/shorthand/sub.rs @@ -9,7 +9,8 @@ use crate::modules::types::{Type, Typed}; pub struct ShorthandSub { var: String, expr: Box, - kind: Type + kind: Type, + global_id: Option } impl SyntaxModule for ShorthandSub { @@ -19,7 +20,8 @@ impl SyntaxModule for ShorthandSub { Self { var: String::new(), expr: Box::new(Expr::new()), - kind: Type::Null + kind: Type::Null, + global_id: None } } @@ -28,7 +30,7 @@ impl SyntaxModule for ShorthandSub { self.var = variable(meta, variable_name_extensions())?; let tok = meta.get_current_token(); token(meta, "-=")?; - self.kind = handle_variable_reference(meta, var_tok, &self.var)?; + (self.global_id, self.kind) = handle_variable_reference(meta, var_tok, &self.var)?; self.expr.parse(meta)?; let message = "Substract operation can only substract numbers"; expression_arms_of_type(meta, &self.kind, &self.expr.get_type(), &[Type::Num, Type::Text], tok, message)?; @@ -39,7 +41,10 @@ impl SyntaxModule for ShorthandSub { impl TranslateModule for ShorthandSub { fn translate(&self, meta: &mut TranslateMetadata) -> String { let expr = self.expr.translate(meta); - let name = self.var.clone(); + let name = match self.global_id { + Some(id) => format!("__{id}_{}", self.var), + None => self.var.clone() + }; let var = format!("${{{name}}}"); format!("{}={}", name, translate_computation(meta, ArithOp::Sub, Some(var), Some(expr))) } diff --git a/src/modules/variable/get.rs b/src/modules/variable/get.rs index 5b616ec6..ddd76413 100644 --- a/src/modules/variable/get.rs +++ b/src/modules/variable/get.rs @@ -6,7 +6,8 @@ use super::{variable_name_extensions, handle_variable_reference}; #[derive(Debug, Clone)] pub struct VariableGet { pub name: String, - kind: Type + kind: Type, + global_id: Option } impl Typed for VariableGet { @@ -21,20 +22,24 @@ impl SyntaxModule for VariableGet { fn new() -> Self { VariableGet { name: String::new(), - kind: Type::Null + kind: Type::Null, + global_id: None } } fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult { let tok = meta.get_current_token(); self.name = variable(meta, variable_name_extensions())?; - self.kind = handle_variable_reference(meta, tok, &self.name)?; + (self.global_id, self.kind) = handle_variable_reference(meta, tok, &self.name)?; Ok(()) } } impl TranslateModule for VariableGet { fn translate(&self, _meta: &mut TranslateMetadata) -> String { - format!("${{{}}}", self.name) + match self.global_id { + Some(id) => format!("${{__{id}_{}}}", self.name), + None => format!("${{{}}}", self.name) + } } } \ No newline at end of file diff --git a/src/modules/variable/init.rs b/src/modules/variable/init.rs index 2ee9eb62..a12a9ceb 100644 --- a/src/modules/variable/init.rs +++ b/src/modules/variable/init.rs @@ -9,13 +9,13 @@ use super::{variable_name_extensions, handle_identifier_name}; pub struct VariableInit { name: String, expr: Box, - function_ctx: bool + global_id: Option } impl VariableInit { - fn handle_add_variable(&self, meta: &mut ParserMetadata, name: &str, kind: Type, tok: Option) -> SyntaxResult { + fn handle_add_variable(&mut self, meta: &mut ParserMetadata, name: &str, kind: Type, tok: Option, is_global: bool) -> SyntaxResult { handle_identifier_name(meta, name, tok)?; - meta.mem.add_variable(name, kind); + self.global_id = meta.mem.add_variable(name, kind, is_global); Ok(()) } } @@ -27,7 +27,7 @@ impl SyntaxModule for VariableInit { VariableInit { name: String::new(), expr: Box::new(Expr::new()), - function_ctx: false + global_id: None } } @@ -36,12 +36,11 @@ impl SyntaxModule for VariableInit { // Get the variable name let tok = meta.get_current_token(); self.name = variable(meta, variable_name_extensions())?; - self.function_ctx = meta.function_ctx; context!({ token(meta, "=")?; syntax(meta, &mut *self.expr)?; // Add a variable to the memory - self.handle_add_variable(meta, &self.name, self.expr.get_type(), tok)?; + self.handle_add_variable(meta, &self.name.clone(), self.expr.get_type(), tok, !meta.function_ctx)?; Ok(()) }, |position| { error_pos!(meta, position, format!("Expected '=' after variable name '{}'", self.name)) @@ -53,10 +52,9 @@ impl TranslateModule for VariableInit { fn translate(&self, meta: &mut TranslateMetadata) -> String { let name = self.name.clone(); let expr = self.expr.translate(meta); - if self.function_ctx { - format!("local {name}={expr}") - } else { - format!("{name}={expr}") + match self.global_id { + Some(id) => format!("__{id}_{name}={expr}"), + None => format!("local {name}={expr}") } } } \ No newline at end of file diff --git a/src/modules/variable/mod.rs b/src/modules/variable/mod.rs index df0f9378..d97d1fbf 100644 --- a/src/modules/variable/mod.rs +++ b/src/modules/variable/mod.rs @@ -15,10 +15,10 @@ pub fn variable_name_keywords() -> Vec<&'static str> { } -pub fn handle_variable_reference(meta: &mut ParserMetadata, tok: Option, name: &str) -> Result { +pub fn handle_variable_reference(meta: &mut ParserMetadata, tok: Option, name: &str) -> Result<(Option, Type), Failure> { handle_identifier_name(meta, name, tok.clone())?; match meta.mem.get_variable(name) { - Some(variable_unit) => Ok(variable_unit.kind.clone()), + Some(variable_unit) => Ok((variable_unit.global_id, variable_unit.kind.clone())), None => { let message = format!("Variable '{}' does not exist", name); // Find other similar variable if exists diff --git a/src/modules/variable/set.rs b/src/modules/variable/set.rs index 1ce91ed8..0365e07d 100644 --- a/src/modules/variable/set.rs +++ b/src/modules/variable/set.rs @@ -6,7 +6,8 @@ use super::{variable_name_extensions, handle_variable_reference}; #[derive(Debug, Clone)] pub struct VariableSet { name: String, - value: Box + value: Box, + global_id: Option } impl SyntaxModule for VariableSet { @@ -15,7 +16,8 @@ impl SyntaxModule for VariableSet { fn new() -> Self { VariableSet { name: String::new(), - value: Box::new(Expr::new()) + value: Box::new(Expr::new()), + global_id: None } } @@ -24,7 +26,7 @@ impl SyntaxModule for VariableSet { self.name = variable(meta, variable_name_extensions())?; token(meta, "=")?; syntax(meta, &mut *self.value)?; - handle_variable_reference(meta, tok, &self.name)?; + (self.global_id, _) = handle_variable_reference(meta, tok, &self.name)?; Ok(()) } } @@ -33,6 +35,9 @@ impl TranslateModule for VariableSet { fn translate(&self, meta: &mut TranslateMetadata) -> String { let name = self.name.clone(); let expr = self.value.translate(meta); - format!("{name}={expr}") + match self.global_id { + Some(id) => format!("__{id}_{name}={expr}"), + None => format!("{name}={expr}") + } } } \ No newline at end of file diff --git a/src/utils/function_map.rs b/src/utils/function_map.rs index 4730e542..7ed10fe1 100644 --- a/src/utils/function_map.rs +++ b/src/utils/function_map.rs @@ -5,7 +5,7 @@ use crate::modules::{types::Type, block::Block}; pub struct FunctionInstance { pub args: Vec, pub returns: Type, - pub body: Block, + pub body: Block } #[derive(Clone, Debug)] diff --git a/src/utils/import_history.rs b/src/utils/import_history.rs index 9ec507ac..f0155e18 100644 --- a/src/utils/import_history.rs +++ b/src/utils/import_history.rs @@ -1,10 +1,15 @@ use crate::modules::block::Block; +use super::exports::Exports; + #[derive(Debug, Clone)] pub struct ImportHistory { pub imports: Vec, pub import_graph: Vec>, - pub import_map: Vec + // Used to resolve imports in the correct order (topological sort) + pub import_blocks: Vec>, + // Used to resolve problem with + pub exports: Vec> } impl ImportHistory { @@ -21,7 +26,8 @@ impl ImportHistory { ImportHistory { imports: vec![Self::get_path(initial_path)], import_graph: vec![vec![]], - import_map: vec![] + import_blocks: vec![None], + exports: vec![None] } } @@ -60,6 +66,8 @@ impl ImportHistory { None => { let dst_id = self.imports.len(); self.imports.push(path); + self.exports.push(None); + self.import_blocks.push(None); self.import_graph.push(vec![]); self.import_graph[src_id].push(dst_id); Some(dst_id) @@ -67,6 +75,24 @@ impl ImportHistory { } } + pub fn add_import_block(&mut self, path: Option, block: Block) { + let path_id = self.get_path_id(&Self::get_path(path)).unwrap(); + self.import_blocks[path_id] = Some(block); + } + + pub fn add_export(&mut self, path: Option, exports: Exports) { + let path_id = self.get_path_id(&Self::get_path(path)).unwrap(); + self.exports[path_id] = Some(exports); + } + + pub fn get_export(&mut self, path: Option) -> Option { + if let Some(path_id) = self.get_path_id(&Self::get_path(path)) { + self.exports[path_id].clone() + } else { + None + } + } + fn topological_sort_util(&self, v: usize, visited: &mut Vec, stack: &mut Vec) { visited[v] = true; for i in self.import_graph[v].iter() { diff --git a/src/utils/memory.rs b/src/utils/memory.rs index 7789639c..9290ed8b 100644 --- a/src/utils/memory.rs +++ b/src/utils/memory.rs @@ -18,7 +18,8 @@ pub struct FunctionDecl { #[derive(Clone, Debug)] pub struct VariableDecl { pub name: String, - pub kind: Type + pub kind: Type, + pub global_id: Option } #[derive(Clone, Debug)] @@ -41,6 +42,7 @@ pub struct Memory { pub scopes: Vec, // Map of all generated functions based on their invocations pub function_map: FunctionMap, + pub variable_id: usize, pub exports: Exports } @@ -49,7 +51,8 @@ impl Memory { Memory { scopes: vec![], function_map: FunctionMap::new(), - exports: Exports::new() + exports: Exports::new(), + variable_id: 0 } } @@ -65,12 +68,19 @@ impl Memory { self.scopes.pop() } - pub fn add_variable(&mut self, name: &str, kind: Type) -> bool { - if self.get_function(name).is_some() { - return false; + pub fn add_variable(&mut self, name: &str, kind: Type, global: bool) -> Option { + let mut global_id = None; + if global { + global_id = Some(self.variable_id); + self.variable_id += 1; } let scope = self.scopes.last_mut().unwrap(); - scope.vars.insert(name.to_string(), VariableDecl { name: name.to_string(), kind }).is_none() + scope.vars.insert(name.to_string(), VariableDecl { + name: name.to_string(), + kind, + global_id + }); + global_id } pub fn get_variable(&self, name: &str) -> Option<&VariableDecl> { @@ -93,15 +103,12 @@ impl Memory { } pub fn add_existing_function_declaration(&mut self, decl: FunctionDecl) -> bool { - // Make sure that there is no variable with the same name - if self.get_variable(&decl.name).is_some() { - return false - } let scope = self.scopes.last_mut().unwrap(); // Add function declaration to the exports self.exports.add_function(decl.clone()); // Add function declaration to the scope - scope.funs.insert(decl.name.to_string(), decl).is_none() + let res = scope.funs.insert(decl.name.to_string(), decl); + res.is_none() } pub fn add_function_declaration(&mut self, meta: ParserMetadata, decl: FunctionDeclSyntax) -> Option {