Skip to content

Commit

Permalink
Merge pull request #203 from Ph0enixKM/202-unsafeing-failable-functio…
Browse files Browse the repository at this point in the history
…n-seems-to-silence-output

Unsafe'ing failable function seems to silence output
  • Loading branch information
Ph0enixKM committed Jun 18, 2024
2 parents a2f6f07 + d26a5d9 commit 88749b0
Show file tree
Hide file tree
Showing 51 changed files with 284 additions and 349 deletions.
2 changes: 1 addition & 1 deletion src/modules/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,4 @@ impl TranslateModule for Block {
std::mem::swap(&mut meta.stmt_queue, &mut new_queue);
result
}
}
}
93 changes: 93 additions & 0 deletions src/modules/command/command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use std::mem::swap;

use heraclitus_compiler::prelude::*;
use crate::{modules::{condition::failed::Failed, expression::literal::bool, types::{Type, Typed}}, utils::{ParserMetadata, TranslateMetadata}};
use crate::modules::expression::expr::Expr;
use crate::translate::module::TranslateModule;
use crate::modules::expression::literal::{parse_interpolated_region, translate_interpolated_region};
use super::modifier::CommandModifier;

#[derive(Debug, Clone)]
pub struct Command {
strings: Vec<String>,
interps: Vec<Expr>,
modifier: CommandModifier,
failed: Failed
}

impl Typed for Command {
fn get_type(&self) -> Type {
Type::Text
}
}

impl SyntaxModule<ParserMetadata> for Command {
syntax_name!("Command");

fn new() -> Self {
Command {
strings: vec![],
interps: vec![],
modifier: CommandModifier::new().parse_expr(),
failed: Failed::new()
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
syntax(meta, &mut self.modifier)?;
self.modifier.use_modifiers(meta, |_this, meta| {
let tok = meta.get_current_token();
(self.strings, self.interps) = parse_interpolated_region(meta, '$')?;
match syntax(meta, &mut self.failed) {
Ok(_) => Ok(()),
Err(Failure::Quiet(_)) => error!(meta, tok => {
message: "Every command statement must handle failed execution",
comment: "You can use '?' in the end to propagate the failure"
}),
Err(err) => Err(err)
}
})
}
}

impl Command {
fn translate_command(&self, meta: &mut TranslateMetadata, is_statement: bool) -> String {
// Translate all interpolations
let interps = self.interps.iter()
.map(|item| item.translate(meta))
.collect::<Vec<String>>();
let failed = self.failed.translate(meta);
let mut is_silent = self.modifier.is_silent || meta.silenced;
swap(&mut is_silent, &mut meta.silenced);
let silent = meta.gen_silent();
let translation = translate_interpolated_region(self.strings.clone(), interps, false);
swap(&mut is_silent, &mut meta.silenced);
let translation = format!("{translation}{silent}");
if is_statement {
return if failed.is_empty() { translation } else {
meta.stmt_queue.push_back(translation);
failed
}
}
if failed.is_empty() {
meta.gen_subprocess(&translation)
} else {
let id = meta.gen_value_id();
let quote = meta.gen_quote();
let dollar = meta.gen_dollar();
meta.stmt_queue.push_back(format!("__AMBER_VAL_{id}=$({translation})"));
meta.stmt_queue.push_back(failed);
format!("{quote}{dollar}{{__AMBER_VAL_{id}}}{quote}")
}
}

pub fn translate_command_statement(&self, meta: &mut TranslateMetadata) -> String {
self.translate_command(meta, true)
}
}

impl TranslateModule for Command {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
self.translate_command(meta, false)
}
}
88 changes: 0 additions & 88 deletions src/modules/command/expr.rs

This file was deleted.

5 changes: 2 additions & 3 deletions src/modules/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
pub mod expr;
pub mod statement;
pub mod modifier;
pub mod command;
pub mod modifier;
140 changes: 54 additions & 86 deletions src/modules/command/modifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,134 +2,102 @@ use std::mem::swap;

use heraclitus_compiler::prelude::*;
use crate::modules::block::Block;
use crate::modules::expression::expr::{Expr, ExprType};
use crate::modules::statement::stmt::Statement;
use crate::modules::types::{Typed, Type};
use crate::translate::module::TranslateModule;
use crate::utils::metadata::{ParserMetadata, TranslateMetadata};

#[derive(Debug, Clone)]
pub struct CommandModifier {
pub block: Box<Block>,
pub expr: Box<Expr>,
pub is_expr: bool,
pub is_block: bool,
pub is_unsafe: bool,
pub is_silent: bool
}

pub struct CommandModifierExpr {
pub modifier: CommandModifier
}

impl Typed for CommandModifierExpr {
fn get_type(&self) -> Type {
self.modifier.expr.get_type()
}
}

impl CommandModifier {
pub fn parse_expr(mut self) -> Self {
self.is_expr = true;
self.is_block = false;
self
}

fn flip_unsafe(&mut self, meta: &mut ParserMetadata, is_unsafe: bool) {
if is_unsafe {
swap(&mut self.is_unsafe, &mut meta.context.is_unsafe_ctx);
pub fn use_modifiers<F>(
&mut self, meta: &mut ParserMetadata, context: F
) -> SyntaxResult where F: FnOnce(&mut Self, &mut ParserMetadata) -> SyntaxResult {
let mut is_unsafe_holder = self.is_unsafe;
if self.is_unsafe {
swap(&mut is_unsafe_holder, &mut meta.context.is_unsafe_ctx);
}
}
}

impl SyntaxModule<ParserMetadata> for CommandModifier {
syntax_name!("Command Modifier");

fn new() -> Self {
CommandModifier {
block: Box::new(Block::new()),
expr: Box::new(Expr::new()),
is_expr: false,
is_unsafe: false,
is_silent: false
let result = context(self, meta);
// Swap back the value
if self.is_unsafe {
swap(&mut is_unsafe_holder, &mut meta.context.is_unsafe_ctx);
}
result
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let mut is_matched = false;
let mut sequence = String::new();
let tok = meta.get_current_token();
fn parse_modifier_sequence(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
loop {
match meta.get_current_token() {
Some(tok) => {
match tok.word.as_str() {
"unsafe" => {
if self.is_unsafe {
return error!(meta, Some(tok.clone()), "You already declared `unsafe` modifier before");
}
self.is_unsafe = true;
is_matched = true;
meta.increment_index();
},
"silent" => {
if self.is_silent {
return error!(meta, Some(tok.clone()), "You already declared `silent` modifier before");
}
self.is_silent = true;
is_matched = true;
meta.increment_index();
},
_ => if is_matched {
break;
} else {
return Err(Failure::Quiet(PositionInfo::from_metadata(meta)))
}
_ => break
}
sequence.push_str(tok.word.as_str());
sequence.push(' ');
},
None => return Err(Failure::Quiet(PositionInfo::from_metadata(meta)))
}
}
let is_unsafe = self.is_unsafe;
self.flip_unsafe(meta, is_unsafe);
if self.is_expr {
if let Err(err) = syntax(meta, &mut *self.expr) {
self.flip_unsafe(meta, is_unsafe);
return Err(err)
}
if !matches!(self.expr.value, Some(ExprType::CommandExpr(_) | ExprType::FunctionInvocation(_))) {
sequence = sequence.trim().to_string();
let count = sequence.split_whitespace().count();
let plural = if count > 1 { "s" } else { "" };
self.flip_unsafe(meta, is_unsafe);
return error!(meta, tok, format!("Expected command or function call, after '{sequence}' command modifier{plural}."));
}
} else {
match token(meta, "{") {
Ok(_) => {
if let Err(err) = syntax(meta, &mut *self.block) {
self.flip_unsafe(meta, is_unsafe);
return Err(err)
}
token(meta, "}")?;
},
Err(_) => {
let mut statement = Statement::new();
if let Err(err) = syntax(meta, &mut statement) {
self.flip_unsafe(meta, is_unsafe);
return Err(err)
}
self.block.push_statement(statement);
}
}
Ok(())
}
}

impl SyntaxModule<ParserMetadata> for CommandModifier {
syntax_name!("Command Modifier");

fn new() -> Self {
CommandModifier {
block: Box::new(Block::new()),
is_block: true,
is_unsafe: false,
is_silent: false
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
self.parse_modifier_sequence(meta)?;
if self.is_block {
return self.use_modifiers(meta, |this, meta| {
token(meta, "{")?;
syntax(meta, &mut *this.block)?;
token(meta, "}")?;
Ok(())
})
}
self.flip_unsafe(meta, is_unsafe);
Ok(())
}
}

impl TranslateModule for CommandModifier {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
meta.silenced = self.is_silent;
let result = if self.is_expr {
return self.expr.translate(meta)
if self.is_block {
meta.silenced = self.is_silent;
let result = self.block.translate(meta);
meta.silenced = false;
result
} else {
self.block.translate(meta)
};
meta.silenced = false;
result
String::new()
}
}
}
}
Loading

0 comments on commit 88749b0

Please sign in to comment.