Skip to content

Commit

Permalink
Constant variables are usable now (#630)
Browse files Browse the repository at this point in the history
* fix: constant variables are usable now

* feat: add function checking for variable existance in previous scope

* feat: add tests and resolve issues

* feat: test constant erroring

* fix: clippy linting

* fix: function naming

* fix: wrong files

* refactor: break down is_shadowing_prev_scope to separate lines

* refactor: test_amber
  • Loading branch information
Ph0enixKM authored Dec 16, 2024
1 parent a4bbf9e commit 19c3e35
Show file tree
Hide file tree
Showing 36 changed files with 265 additions and 226 deletions.
5 changes: 3 additions & 2 deletions src/modules/shorthand/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::error_type_match;
use crate::modules::expression::expr::Expr;
use crate::modules::variable::{variable_name_extensions, handle_variable_reference};
use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::translate::compute::translate_computation_eval;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::{module::TranslateModule, compute::{ArithOp, translate_computation}};
Expand Down Expand Up @@ -34,7 +34,8 @@ impl SyntaxModule<ParserMetadata> for ShorthandAdd {
let var_tok = meta.get_current_token();
self.var = variable(meta, variable_name_extensions())?;
token(meta, "+=")?;
let variable = handle_variable_reference(meta, var_tok, &self.var)?;
let variable = handle_variable_reference(meta, &var_tok, &self.var)?;
prevent_constant_mutation(meta, &var_tok, &self.var, variable.is_const)?;
self.kind = variable.kind;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
Expand Down
5 changes: 3 additions & 2 deletions src/modules/shorthand/div.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::error_type_match;
use crate::modules::expression::expr::Expr;
use crate::modules::variable::{variable_name_extensions, handle_variable_reference};
use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::translate::compute::translate_computation_eval;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::{module::TranslateModule, compute::{ArithOp, translate_computation}};
Expand Down Expand Up @@ -34,7 +34,8 @@ impl SyntaxModule<ParserMetadata> for ShorthandDiv {
let var_tok = meta.get_current_token();
self.var = variable(meta, variable_name_extensions())?;
token(meta, "/=")?;
let variable = handle_variable_reference(meta, var_tok, &self.var)?;
let variable = handle_variable_reference(meta, &var_tok, &self.var)?;
prevent_constant_mutation(meta, &var_tok, &self.var, variable.is_const)?;
self.kind = variable.kind;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
Expand Down
5 changes: 3 additions & 2 deletions src/modules/shorthand/modulo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::error_type_match;
use crate::modules::expression::expr::Expr;
use crate::modules::variable::{variable_name_extensions, handle_variable_reference};
use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::translate::compute::translate_computation_eval;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::{module::TranslateModule, compute::{ArithOp, translate_computation}};
Expand Down Expand Up @@ -34,7 +34,8 @@ impl SyntaxModule<ParserMetadata> for ShorthandModulo {
let var_tok = meta.get_current_token();
self.var = variable(meta, variable_name_extensions())?;
token(meta, "%=")?;
let variable = handle_variable_reference(meta, var_tok, &self.var)?;
let variable = handle_variable_reference(meta, &var_tok, &self.var)?;
prevent_constant_mutation(meta, &var_tok, &self.var, variable.is_const)?;
self.kind = variable.kind;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
Expand Down
5 changes: 3 additions & 2 deletions src/modules/shorthand/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::error_type_match;
use crate::modules::expression::expr::Expr;
use crate::modules::variable::{variable_name_extensions, handle_variable_reference};
use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::translate::compute::translate_computation_eval;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::{module::TranslateModule, compute::{ArithOp, translate_computation}};
Expand Down Expand Up @@ -34,7 +34,8 @@ impl SyntaxModule<ParserMetadata> for ShorthandMul {
let var_tok = meta.get_current_token();
self.var = variable(meta, variable_name_extensions())?;
token(meta, "*=")?;
let variable = handle_variable_reference(meta, var_tok, &self.var)?;
let variable = handle_variable_reference(meta, &var_tok, &self.var)?;
prevent_constant_mutation(meta, &var_tok, &self.var, variable.is_const)?;
self.kind = variable.kind;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
Expand Down
5 changes: 3 additions & 2 deletions src/modules/shorthand/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::error_type_match;
use crate::modules::expression::expr::Expr;
use crate::modules::variable::{variable_name_extensions, handle_variable_reference};
use crate::modules::variable::{handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::translate::compute::translate_computation_eval;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::translate::{module::TranslateModule, compute::{ArithOp, translate_computation}};
Expand Down Expand Up @@ -34,7 +34,8 @@ impl SyntaxModule<ParserMetadata> for ShorthandSub {
let var_tok = meta.get_current_token();
self.var = variable(meta, variable_name_extensions())?;
token(meta, "-=")?;
let variable = handle_variable_reference(meta, var_tok, &self.var)?;
let variable = handle_variable_reference(meta, &var_tok, &self.var)?;
prevent_constant_mutation(meta, &var_tok, &self.var, variable.is_const)?;
self.kind = variable.kind;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
Expand Down
4 changes: 1 addition & 3 deletions src/modules/statement/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use heraclitus_compiler::prelude::*;
use itertools::Itertools;
use crate::docs::module::DocumentationModule;
use crate::modules::variable::constinit::ConstInit;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use crate::modules::expression::expr::{Expr, ExprType};
use crate::translate::module::TranslateModule;
Expand Down Expand Up @@ -72,7 +71,6 @@ pub enum StatementType {
CommandModifier(CommandModifier),
Comment(Comment),
CommentDoc(CommentDoc),
ConstInit(ConstInit),
}

#[derive(Debug, Clone)]
Expand All @@ -91,7 +89,7 @@ impl Statement {
// Conditions
IfChain, IfCondition,
// Variables
VariableInit, VariableSet, ConstInit,
VariableInit, VariableSet,
// Short hand
ShorthandAdd, ShorthandSub,
ShorthandMul, ShorthandDiv,
Expand Down
73 changes: 0 additions & 73 deletions src/modules/variable/constinit.rs

This file was deleted.

2 changes: 1 addition & 1 deletion src/modules/variable/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl SyntaxModule<ParserMetadata> for VariableGet {
fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let tok = meta.get_current_token();
self.name = variable(meta, variable_name_extensions())?;
let variable = handle_variable_reference(meta, tok.clone(), &self.name)?;
let variable = handle_variable_reference(meta, &tok, &self.name)?;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
self.kind = variable.kind.clone();
Expand Down
21 changes: 14 additions & 7 deletions src/modules/variable/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ pub struct VariableInit {
name: String,
expr: Box<Expr>,
global_id: Option<usize>,
is_fun_ctx: bool
is_fun_ctx: bool,
is_const: bool,
}

impl VariableInit {
fn handle_add_variable(&mut self, meta: &mut ParserMetadata, name: &str, kind: Type, tok: Option<Token>) -> SyntaxResult {
handle_identifier_name(meta, name, tok)?;
self.global_id = meta.add_var(name, kind, false);
fn handle_add_variable(
&mut self,
meta: &mut ParserMetadata,
tok: Option<Token>
) -> SyntaxResult {
handle_identifier_name(meta, &self.name, tok)?;
self.global_id = meta.add_var(&self.name, self.expr.get_type(), self.is_const);
Ok(())
}
}
Expand All @@ -30,20 +35,22 @@ impl SyntaxModule<ParserMetadata> for VariableInit {
name: String::new(),
expr: Box::new(Expr::new()),
global_id: None,
is_fun_ctx: false
is_fun_ctx: false,
is_const: false
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "let")?;
let keyword = token_by(meta, |word| ["let", "const"].contains(&word.as_str()))?;
self.is_const = keyword == "const";
// Get the variable name
let tok = meta.get_current_token();
self.name = variable(meta, variable_name_extensions())?;
context!({
token(meta, "=")?;
syntax(meta, &mut *self.expr)?;
// Add a variable to the memory
self.handle_add_variable(meta, &self.name.clone(), self.expr.get_type(), tok)?;
self.handle_add_variable(meta, tok)?;
self.is_fun_ctx = meta.context.is_fun_ctx;
Ok(())
}, |position| {
Expand Down
15 changes: 11 additions & 4 deletions src/modules/variable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use similar_string::find_best_similarity;
pub mod init;
pub mod set;
pub mod get;
pub mod constinit;

pub fn variable_name_extensions() -> Vec<char> {
vec!['_']
Expand Down Expand Up @@ -40,22 +39,30 @@ pub fn variable_name_keywords() -> Vec<&'static str> {
}


pub fn handle_variable_reference(meta: &mut ParserMetadata, tok: Option<Token>, name: &str) -> Result<VariableDecl, Failure> {
pub fn handle_variable_reference(meta: &mut ParserMetadata, tok: &Option<Token>, name: &str) -> Result<VariableDecl, Failure> {
handle_identifier_name(meta, name, tok.clone())?;
match meta.get_var(name) {
Some(variable_unit) => Ok(variable_unit.clone()),
None => {
let message = format!("Variable '{}' does not exist", name);
// Find other similar variable if exists
if let Some(comment) = handle_similar_variable(meta, name) {
error!(meta, tok, message, comment)
error!(meta, tok.clone(), message, comment)
} else {
error!(meta, tok, message)
error!(meta, tok.clone(), message)
}
}
}
}

pub fn prevent_constant_mutation(meta: &mut ParserMetadata, tok: &Option<Token>, name: &str, is_const: bool) -> SyntaxResult {
if is_const {
error!(meta, tok.clone(), format!("Cannot reassign constant '{name}'"))
} else {
Ok(())
}
}

fn handle_similar_variable(meta: &ParserMetadata, name: &str) -> Option<String> {
let vars = Vec::from_iter(meta.get_var_names());
find_best_similarity(name, &vars)
Expand Down
9 changes: 3 additions & 6 deletions src/modules/variable/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::{modules::expression::expr::Expr, translate::module::TranslateModule};
use crate::utils::{ParserMetadata, TranslateMetadata};
use super::{variable_name_extensions, handle_variable_reference, handle_index_accessor};
use super::{handle_index_accessor, handle_variable_reference, prevent_constant_mutation, variable_name_extensions};
use crate::modules::types::{Typed, Type};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -43,13 +43,10 @@ impl SyntaxModule<ParserMetadata> for VariableSet {
self.index = handle_index_accessor(meta, false)?;
token(meta, "=")?;
syntax(meta, &mut *self.expr)?;
let variable = handle_variable_reference(meta, tok.clone(), &self.name)?;
let variable = handle_variable_reference(meta, &tok, &self.name)?;
self.global_id = variable.global_id;
self.is_ref = variable.is_ref;
// Check for constant reassignment
if variable.is_const {
return error!(meta, tok, format!("Cannot reassign constant"))
}
prevent_constant_mutation(meta, &tok, &self.name, variable.is_const)?;
// Typecheck the variable
let left_type = variable.kind.clone();
let right_type = self.expr.get_type();
Expand Down
9 changes: 9 additions & 0 deletions src/tests/erroring.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use super::script_test;
use super::TestOutcomeTarget;
use test_generator::test_resources;

/// Autoload the Amber test files in erroring, match the output in the comment
#[test_resources("src/tests/erroring/*.ab")]
fn test_erroring(input: &str) {
script_test(input, TestOutcomeTarget::Failure);
}
5 changes: 5 additions & 0 deletions src/tests/erroring/array_index_get_by_text.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Index accessor must be a number or range for right side of operation

let array = [0, 1, 2, 3]
let slice = array["foo"]
5 changes: 5 additions & 0 deletions src/tests/erroring/array_index_set_by_range.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Index accessor must be a number (and not a range) for left side of operation

let array = [0, 1, 2, 3]
array[1..=2] = [11, 22]
5 changes: 5 additions & 0 deletions src/tests/erroring/array_index_set_by_text.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Index accessor must be a number (and not a range) for left side of operation

let array = [0, 1, 2, 3]
array["foo"] = [11, 22]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Output
// Failable functions must return a Failable type

pub fun test(): Null {
fail 1
}
echo test() failed: echo "Failed"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Output
// Non-failable functions cannot return a Failable type

pub fun test(): Null? {
echo "Hello, World!"
}
echo test() failed: echo "Failed"
7 changes: 7 additions & 0 deletions src/tests/erroring/function_with_failable_typed_arg.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Output
// Failable types cannot be used as arguments

pub fun test(a: Text?) {
echo a
}
test("Hello, World!")
7 changes: 7 additions & 0 deletions src/tests/erroring/function_with_wrong_typed_return.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Output
// Return type does not match function return type

pub fun test(): Num {
return "Hello, World!"
}
echo test()
5 changes: 5 additions & 0 deletions src/tests/erroring/variable_constant.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Cannot reassign constant 'foo'

const foo = 12
foo = 13
5 changes: 5 additions & 0 deletions src/tests/erroring/variable_constant_shorthand_add.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Cannot reassign constant 'foo'

const foo = 12
foo += 13
5 changes: 5 additions & 0 deletions src/tests/erroring/variable_constant_shorthand_div.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Output
// Cannot reassign constant 'foo'

const foo = 12
foo /= 13
Loading

0 comments on commit 19c3e35

Please sign in to comment.