Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A40 Feature: Add main block #36

Merged
merged 1 commit into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cli/cli_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl CLI {
match self.flags.get_flag("-e").unwrap().value.clone() {
Some(code) => {
match AmberCompiler::new(code, None).compile() {
Ok(code) => AmberCompiler::execute(code),
Ok(code) => AmberCompiler::execute(code, self.flags.get_args()),
Err(err) => {
err.show();
std::process::exit(1);
Expand Down Expand Up @@ -71,7 +71,7 @@ impl CLI {
}
// Execute the code
else {
AmberCompiler::execute(code);
AmberCompiler::execute(code, self.flags.get_args());
}
},
Err(err) => {
Expand Down
20 changes: 18 additions & 2 deletions src/cli/flag_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ impl Flag {
}

pub struct FlagRegistry {
flags: HashMap<String, Flag>
flags: HashMap<String, Flag>,
args: Vec<String>
}

impl Default for FlagRegistry {
Expand All @@ -30,7 +31,8 @@ impl FlagRegistry {
#[inline]
pub fn new() -> Self {
FlagRegistry {
flags: HashMap::new()
flags: HashMap::new(),
args: vec![]
}
}

Expand All @@ -39,6 +41,11 @@ impl FlagRegistry {
self.flags.get(name.as_ref())
}

#[inline]
pub fn get_args(&self) -> &Vec<String> {
&self.args
}

#[inline]
pub fn flag_triggered(&self, name: impl AsRef<str>) -> bool {
match self.flags.get(name.as_ref()) {
Expand All @@ -55,7 +62,12 @@ impl FlagRegistry {
pub fn parse(&mut self, args: Vec<String>) -> Vec<String> {
let mut result = vec![];
let mut is_value_flag = None;
let mut is_args = false;
for arg in args.iter() {
if is_args {
self.args.push(arg.clone());
continue;
}
if let Some(name) = &is_value_flag {
let flag = self.flags.get_mut(name).unwrap();
flag.value = Some(arg.clone());
Expand All @@ -68,6 +80,10 @@ impl FlagRegistry {
}
continue
}
if arg == "--" {
is_args = true;
continue
}
result.push(arg.to_string())
}
result
Expand Down
3 changes: 2 additions & 1 deletion src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ impl AmberCompiler {
.map(|(block, meta)| self.translate(block, meta))
}

pub fn execute(code: String) {
pub fn execute(code: String, flags: &[String]) {
let code = format!("set -- {};\n\n{}", flags.join(" "), code);
Command::new("/bin/bash").arg("-c").arg(code).spawn().unwrap().wait().unwrap();
}

Expand Down
17 changes: 6 additions & 11 deletions src/modules/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use super::statement::stmt::Statement;

#[derive(Debug, Clone)]
pub struct Block {
statements: Vec<Statement>,
is_scope: bool
statements: Vec<Statement>
}

impl Block {
Expand All @@ -15,10 +14,6 @@ impl Block {
self.statements.is_empty()
}

pub fn set_scopeless(&mut self) {
self.is_scope = false;
}

// Push a parsed statement into the block
pub fn push_statement(&mut self, statement: Statement) {
self.statements.push(statement);
Expand All @@ -30,8 +25,7 @@ impl SyntaxModule<ParserMetadata> for Block {

fn new() -> Self {
Block {
statements: vec![],
is_scope: true
statements: vec![]
}
}

Expand Down Expand Up @@ -68,16 +62,17 @@ impl SyntaxModule<ParserMetadata> for Block {

impl TranslateModule for Block {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
if self.is_scope { meta.increase_indent(); }
meta.increase_indent();
let result = if self.is_empty() {
":".to_string()
}
else {
self.statements.iter()
.map(|module| meta.gen_indent() + &module.translate(meta))
.map(|statement| meta.gen_indent() + &statement.translate(meta))
.filter(|translation| !translation.trim().is_empty())
.collect::<Vec<_>>().join(";\n")
};
if self.is_scope { meta.decrease_indent(); }
meta.decrease_indent();
result
}
}
1 change: 0 additions & 1 deletion src/modules/condition/ifchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ impl SyntaxModule<ParserMetadata> for IfChain {
loop {
let mut cond = Expr::new();
let mut block = Block::new();
cond.cannot_fail();
// Handle comments and empty lines
if token_by(meta, |token| token.starts_with('#') || token.starts_with('\n')).is_ok() {
continue
Expand Down
8 changes: 1 addition & 7 deletions src/modules/expression/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ pub enum ExprType {
#[derive(Debug, Clone)]
pub struct Expr {
value: Option<ExprType>,
can_fail: bool,
kind: Type
}

Expand Down Expand Up @@ -89,10 +88,6 @@ impl Expr {
VariableGet
]);

pub fn cannot_fail(&mut self) {
self.can_fail = false;
}

// Get result out of the provided module and save it in the internal state
fn get<S>(&mut self, meta: &mut ParserMetadata, mut module: S, cb: impl Fn(S) -> ExprType) -> SyntaxResult
where
Expand All @@ -116,8 +111,7 @@ impl SyntaxModule<ParserMetadata> for Expr {
fn new() -> Self {
Expr {
value: None,
kind: Type::Null,
can_fail: true
kind: Type::Null
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/modules/imports/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,22 @@ impl Import {
fn handle_import(&mut self, meta: &mut ParserMetadata, tok: Option<Token>, imported_code: String) -> SyntaxResult {
match AmberCompiler::new(imported_code.clone(), meta.path.clone()).tokenize() {
Ok(tokens) => {
self.block.set_scopeless();
// Save snapshot of current file
let code = meta.code.clone();
let path = meta.path.clone();
let expr = meta.expr.clone();
let exports = meta.mem.exports.clone();
let index = meta.get_index();
let scopes = meta.mem.scopes.clone();
// Parse the imported file
meta.push_trace(PositionInfo::from_token(meta, tok));
meta.path = Some(self.path.value.clone());
meta.code = Some(imported_code);
meta.expr = tokens;
meta.set_index(0);
meta.mem.scopes = vec![];
syntax(meta, &mut self.block)?;
meta.mem.scopes = scopes;
self.handle_export(meta, meta.mem.exports.clone());
// Restore snapshot of current file
meta.code = code;
Expand Down
82 changes: 82 additions & 0 deletions src/modules/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use heraclitus_compiler::prelude::*;
use crate::translate::module::TranslateModule;
use crate::utils::{ParserMetadata, TranslateMetadata};
use crate::modules::types::Type;
use crate::modules::block::Block;

use super::variable::variable_name_extensions;

#[derive(Debug, Clone)]
pub struct Main {
pub args: Vec<String>,
pub block: Block,
pub is_skipped: bool
}

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

fn new() -> Self {
Self {
args: vec![],
block: Block::new(),
is_skipped: false
}
}

fn parse(&mut self, meta: &mut ParserMetadata) -> SyntaxResult {
let tok = meta.get_current_token();
token(meta, "main")?;
// Main cannot be parsed inside of a block
if meta.mem.get_depth() > 1 {
dbg!(meta.mem.get_depth());
return error!(meta, tok, "Main module must be in the global scope")
}
// If this main is included in other file, skip it
if !meta.trace.is_empty() {
self.is_skipped = true;
}
context!({
if token(meta, "(").is_ok() {
loop {
if token(meta, ")").is_ok() {
break;
}
self.args.push(variable(meta, variable_name_extensions())?);
match token(meta, ")") {
Ok(_) => break,
Err(_) => token(meta, ",")?
};
}
}
token(meta, "{")?;
// Create a new scope for variables
meta.mem.push_scope();
// Create variables
for arg in self.args.iter() {
meta.mem.add_variable(arg, Type::Text);
}
// Parse the block
syntax(meta, &mut self.block)?;
// Remove the scope made for variables
meta.mem.pop_scope();
token(meta, "}")?;
Ok(())
}, |pos| {
error_pos!(meta, pos, "Undefined syntax in main block")
})
}
}

impl TranslateModule for Main {
fn translate(&self, meta: &mut TranslateMetadata) -> String {
let variables = self.args.iter().enumerate()
.map(|(index, name)| format!("{name}=${}", index + 1))
.collect::<Vec<_>>().join("\n");
if self.is_skipped {
String::new()
} else {
format!("{variables}\n{}", self.block.translate(meta))
}
}
}
1 change: 1 addition & 0 deletions src/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod loops;
pub mod function;
pub mod types;
pub mod imports;
pub mod main;

#[macro_export]
macro_rules! handle_types {
Expand Down
20 changes: 11 additions & 9 deletions src/modules/statement/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::modules::function::{
use crate::modules::imports::{
import::Import
};
use crate::modules::main::Main;

#[derive(Debug, Clone)]
pub enum StatementType {
Expand All @@ -48,7 +49,8 @@ pub enum StatementType {
Break(Break),
Continue(Continue),
FunctionDeclaration(FunctionDeclaration),
Import(Import)
Import(Import),
Main(Main)
}

#[derive(Debug, Clone)]
Expand All @@ -61,7 +63,7 @@ impl Statement {
// Imports
Import,
// Functions
FunctionDeclaration,
FunctionDeclaration, Main,
// Loops
InfiniteLoop, Break, Continue,
// Conditions
Expand Down Expand Up @@ -107,18 +109,18 @@ impl SyntaxModule<ParserMetadata> for Statement {
let mut error = None;
let statements = self.get_modules();
for statement in statements {
// If the statement is an expression, we want it to not fire it's own error
let statement = if let StatementType::Expr(mut expr) = statement {
expr.cannot_fail();
StatementType::Expr(expr)
} else { statement };
// Try to parse the statement
match self.parse_match(meta, statement) {
Ok(()) => return Ok(()),
Err(details) => error = Some(details)
Err(failure) => {
match failure {
Failure::Loud(err) => return Err(Failure::Loud(err)),
Failure::Quiet(err) => error = Some(err)
}
}
}
}
Err(error.unwrap())
Err(Failure::Quiet(error.unwrap()))
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/utils/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ impl ScopeUnit {

#[derive(Clone, Debug)]
pub struct Memory {
scopes: Vec<ScopeUnit>,
pub scopes: Vec<ScopeUnit>,
// Map of all generated functions based on their invocations
function_map: FunctionMap,
pub function_map: FunctionMap,
pub exports: Exports
}

Expand All @@ -52,6 +52,10 @@ impl Memory {
exports: Exports::new()
}
}

pub fn get_depth(&self) -> usize {
self.scopes.len()
}

pub fn push_scope(&mut self) {
self.scopes.push(ScopeUnit::new())
Expand Down
4 changes: 4 additions & 0 deletions tests/io/print.ab
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
pub fun print(text) {
$echo {text}$
}

main {
print('Hello, World!')
}