Skip to content

Commit

Permalink
feature: add constant declarations (#423)
Browse files Browse the repository at this point in the history
Co-authored-by: Daniele Scasciafratte <[email protected]>
  • Loading branch information
b1ek and Mte90 authored Nov 20, 2024
1 parent 6a08f86 commit 3ea8242
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/modules/loops/iter_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ impl SyntaxModule<ParserMetadata> for IterLoop {
token(meta, "{")?;
// Create iterator variable
meta.with_push_scope(|meta| {
meta.add_var(&self.iter_name, self.iter_type.clone());
meta.add_var(&self.iter_name, self.iter_type.clone(), false);
if let Some(index) = self.iter_index.as_ref() {
meta.add_var(index, Type::Num);
meta.add_var(index, Type::Num, false);
}
// Save loop context state and set it to true
meta.with_context_fn(Context::set_is_loop_ctx, true, |meta| {
Expand Down
4 changes: 2 additions & 2 deletions src/modules/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl SyntaxModule<ParserMetadata> for Main {
meta.with_push_scope(|meta| {
// Create variables
for arg in self.args.iter() {
meta.add_var(arg, Type::Array(Box::new(Type::Text)));
meta.add_var(arg, Type::Array(Box::new(Type::Text)), true);
}
// Parse the block
syntax(meta, &mut self.block)?;
Expand All @@ -71,7 +71,7 @@ impl TranslateModule for Main {
let dollar = meta.gen_dollar();
let args = self.args.clone().map_or_else(
String::new,
|name| format!("{name}=({quote}{dollar}0{quote} {quote}{dollar}@{quote})")
|name| format!("declare -r {name}=({quote}{dollar}0{quote} {quote}{dollar}@{quote})")
);
format!("{args}\n{}", self.block.translate(meta))
}
Expand Down
4 changes: 3 additions & 1 deletion src/modules/statement/stmt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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 @@ -71,6 +72,7 @@ pub enum StatementType {
CommandModifier(CommandModifier),
Comment(Comment),
CommentDoc(CommentDoc),
ConstInit(ConstInit),
}

#[derive(Debug, Clone)]
Expand All @@ -89,7 +91,7 @@ impl Statement {
// Conditions
IfChain, IfCondition,
// Variables
VariableInit, VariableSet,
VariableInit, VariableSet, ConstInit,
// Short hand
ShorthandAdd, ShorthandSub,
ShorthandMul, ShorthandDiv,
Expand Down
73 changes: 73 additions & 0 deletions src/modules/variable/constinit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use heraclitus_compiler::prelude::*;
use crate::docs::module::DocumentationModule;
use crate::modules::types::{Typed, Type};
use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};
use super::{variable_name_extensions, handle_identifier_name};

#[derive(Debug, Clone)]
pub struct ConstInit {
name: String,
expr: Box<Expr>,
global_id: Option<usize>,
is_fun_ctx: bool
}

impl ConstInit {
fn handle_add_const(&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, true);
Ok(())
}
}

impl SyntaxModule<ParserMetadata> for ConstInit {
syntax_name!("Constant Initialize");

fn new() -> Self {
ConstInit {
name: String::new(),
expr: Box::new(Expr::new()),
global_id: None,
is_fun_ctx: false
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
token(meta, "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_const(meta, &self.name.clone(), self.expr.get_type(), tok)?;
self.is_fun_ctx = meta.context.is_fun_ctx;
Ok(())
}, |position| {
error_pos!(meta, position, format!("Expected '=' after variable name '{}'", self.name))
})
}
}

impl TranslateModule for ConstInit {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let name = self.name.clone();
let mut expr = self.expr.translate(meta);
if let Type::Array(_) = self.expr.get_type() {
expr = format!("({expr})");
}
match self.global_id {
Some(id) => format!("declare -r __{id}_{name}={expr}"),
None => format!("declare -r {name}={expr}")
}
}
}

impl DocumentationModule for ConstInit {
fn document(&self, _meta: &ParserMetadata) -> String {
"".to_string()
}
}
2 changes: 1 addition & 1 deletion src/modules/variable/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub struct VariableInit {
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);
self.global_id = meta.add_var(name, kind, false);
Ok(())
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/modules/variable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use super::expression::expr::Expr;
pub mod init;
pub mod set;
pub mod get;
pub mod constinit;

pub fn variable_name_extensions() -> Vec<char> {
vec!['_']
Expand All @@ -18,7 +19,7 @@ pub fn variable_name_keywords() -> Vec<&'static str> {
// Literals
"true", "false", "null",
// Variable keywords
"let", "as", "is",
"let", "as", "is", "const",
// Control flow keywords
"if", "then", "else",
// Loop keywords
Expand Down
4 changes: 4 additions & 0 deletions src/modules/variable/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ impl SyntaxModule<ParserMetadata> for VariableSet {
let variable = handle_variable_reference(meta, tok.clone(), &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"))
}
// Typecheck the variable
let left_type = variable.kind.clone();
let right_type = self.expr.get_type();
Expand Down
15 changes: 15 additions & 0 deletions src/tests/validity/constant.ab
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Output
// 1
// 42
// 1
// 42

main {
const x = 42
unsafe $ x=123 $
echo status // will output 1 if reassignment didnt succeed
echo x
unsafe $ unset x $
echo status // will output 1 if unsetting did not succeed
echo x
}
1 change: 1 addition & 0 deletions src/utils/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub struct VariableDecl {
pub kind: Type,
pub global_id: Option<usize>,
pub is_ref: bool,
pub is_const: bool,
}

#[derive(Clone, Debug)]
Expand Down
10 changes: 6 additions & 4 deletions src/utils/metadata/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,29 @@ impl ParserMetadata {
}

/// Adds a variable to the current scope
pub fn add_var(&mut self, name: &str, kind: Type) -> Option<usize> {
pub fn add_var(&mut self, name: &str, kind: Type, is_const: bool) -> Option<usize> {
let global_id = self.is_global_scope().then(|| self.gen_var_id());
let scope = self.context.scopes.last_mut().unwrap();
scope.add_var(VariableDecl {
name: name.to_string(),
kind,
global_id,
is_ref: false
is_ref: false,
is_const,
});
global_id
}

/// Adds a parameter as variable to the current scope
/// Adds a function parameter as variable to the current scope
pub fn add_param(&mut self, name: &str, kind: Type, is_ref: bool) -> Option<usize> {
let global_id = self.is_global_scope().then(|| self.gen_var_id());
let scope = self.context.scopes.last_mut().unwrap();
scope.add_var(VariableDecl {
name: name.to_string(),
kind,
global_id,
is_ref
is_ref,
is_const: false,
});
global_id
}
Expand Down

0 comments on commit 3ea8242

Please sign in to comment.