diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..8fbc55d --- /dev/null +++ b/src/config.rs @@ -0,0 +1,35 @@ +use std::collections::HashMap; + +#[derive(Clone, Debug)] +pub struct Config { + pub builtin_functions: HashMap, +} + +impl Default for Config { + fn default() -> Self { + macro_rules! builtin_function { + ( $name:expr, $target_name:expr, $mutating:expr, $n_args:expr ) => { + ( + String::from($name), + (String::from($target_name), $mutating, $n_args), + ) + }; + } + Self { + builtin_functions: HashMap::from([ + builtin_function!("print_flush", "printflush", false, 1), + // TODO: write a special case for message + builtin_function!("print_message_mission", "message mission", false, 0), + builtin_function!("read", "read", true, 3), + // TODO: don't use a generic operation here + builtin_function!("write", "write", false, 3), + builtin_function!("wait", "wait", false, 1), + // TODO: don't use a generic operation here either + builtin_function!("set_flag", "setflag", false, 2), + builtin_function!("get_flag", "getflag", true, 2), + // TODO: same thing + builtin_function!("spawn", "spawn", false, 6), + ]), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 626aa04..4098c9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,14 @@ -pub mod common; -pub mod compile; +pub mod config; pub mod cursor; +pub mod optimize; pub mod parse; +pub mod repr; +pub mod translate; + +pub mod prelude { + pub use crate::config::Config; + pub use crate::cursor::Cursor; + pub use crate::repr::basic::*; + pub use crate::repr::mlog::*; + pub use crate::repr::operator::*; +} diff --git a/src/main.rs b/src/main.rs index eab7600..c021439 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use basic_to_mindustry::{ - common::Config, - compile::{optimize_constant, optimize_jump_always, optimize_jump_op, translate_ast, Namer}, + optimize::{optimize_constant, optimize_jump_always, optimize_jump_op}, parse::{build_ast, tokenize}, + prelude::*, + translate::{translate_ast, Namer}, }; fn main() { diff --git a/src/compile/optimize/constant.rs b/src/optimize/constant.rs similarity index 99% rename from src/compile/optimize/constant.rs rename to src/optimize/constant.rs index cc7c7d1..a674fab 100644 --- a/src/compile/optimize/constant.rs +++ b/src/optimize/constant.rs @@ -1,4 +1,7 @@ +use regex::Regex; + use super::*; +use crate::prelude::*; /// Optimizes away unnecessary `sets` pub fn optimize_constant(program: MindustryProgram) -> MindustryProgram { diff --git a/src/compile/optimize/dead.rs b/src/optimize/dead.rs similarity index 96% rename from src/compile/optimize/dead.rs rename to src/optimize/dead.rs index 0db9236..944dd90 100644 --- a/src/compile/optimize/dead.rs +++ b/src/optimize/dead.rs @@ -1,4 +1,8 @@ +use regex::Regex; +use std::collections::HashSet; + use super::*; +use crate::prelude::*; pub(crate) fn optimize_dead_code(program: MindustryProgram) -> MindustryProgram { let tmp_regex = Regex::new(r"__tmp_[0-9]+$").unwrap(); diff --git a/src/compile/optimize/jump.rs b/src/optimize/jump.rs similarity index 99% rename from src/compile/optimize/jump.rs rename to src/optimize/jump.rs index aac12bc..42eb7f9 100644 --- a/src/compile/optimize/jump.rs +++ b/src/optimize/jump.rs @@ -1,4 +1,7 @@ +use regex::Regex; + use super::*; +use crate::prelude::*; /// Tries to merge the condition in an `op` into the `jump` itself pub fn optimize_jump_op(program: MindustryProgram) -> MindustryProgram { diff --git a/src/compile/optimize/lookaround.rs b/src/optimize/lookaround.rs similarity index 98% rename from src/compile/optimize/lookaround.rs rename to src/optimize/lookaround.rs index 13367e6..2a50099 100644 --- a/src/compile/optimize/lookaround.rs +++ b/src/optimize/lookaround.rs @@ -1,6 +1,5 @@ //! Lookaround helpers for quickly implementing optimizations - -use super::*; +use crate::prelude::*; pub(crate) enum Lookaround { Stop(T), diff --git a/src/compile/optimize/mod.rs b/src/optimize/mod.rs similarity index 88% rename from src/compile/optimize/mod.rs rename to src/optimize/mod.rs index 4e2498e..8641c7b 100644 --- a/src/compile/optimize/mod.rs +++ b/src/optimize/mod.rs @@ -1,7 +1,3 @@ -use std::collections::HashSet; - -use super::*; - mod constant; pub use constant::*; diff --git a/src/compile/optimize/replace.rs b/src/optimize/replace.rs similarity index 96% rename from src/compile/optimize/replace.rs rename to src/optimize/replace.rs index 3c5c87a..a8679fc 100644 --- a/src/compile/optimize/replace.rs +++ b/src/optimize/replace.rs @@ -1,4 +1,4 @@ -use super::*; +use crate::prelude::*; pub(crate) fn replace_if(program: MindustryProgram, callback: F) -> MindustryProgram where diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 06bce7e..df279aa 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -1,46 +1,7 @@ use super::*; -use crate::common::*; use crate::cursor::Cursor; +use crate::prelude::*; -#[derive(Clone, Debug, PartialEq)] -pub enum BasicAstExpression { - Integer(i64), - Float(f64), - Variable(String), - String(String), - Binary(Operator, Box, Box), - Unary(UnaryOperator, Box), -} - -#[derive(Clone, Debug, PartialEq)] -pub enum BasicAstInstruction { - JumpLabel(String), - Assign(String, BasicAstExpression), - Jump(String), - IfThenElse(BasicAstExpression, BasicAstBlock, BasicAstBlock), - Print(Vec<(BasicAstExpression, bool)>), - CallBuiltin(String, Vec), - For { - variable: String, - start: BasicAstExpression, - end: BasicAstExpression, - step: BasicAstExpression, - instructions: BasicAstBlock, - }, -} - -#[derive(Clone, Debug, PartialEq, Default)] -pub struct BasicAstBlock { - pub instructions: Vec, -} - -impl BasicAstBlock { - pub fn new(instructions: impl IntoIterator) -> Self { - Self { - instructions: instructions.into_iter().collect(), - } - } -} pub fn build_ast(tokens: &[BasicToken], config: &Config) -> Result { enum Context { Main, diff --git a/src/parse/test.rs b/src/parse/test.rs index 99f3fce..95e4f91 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -1,7 +1,5 @@ -use crate::common::*; -use crate::cursor::Cursor; - use super::*; +use crate::prelude::*; #[test] fn test_tokenize_basic() { diff --git a/src/parse/tokenize.rs b/src/parse/tokenize.rs index 6a34807..f9b5e41 100644 --- a/src/parse/tokenize.rs +++ b/src/parse/tokenize.rs @@ -1,5 +1,5 @@ use super::ParseError; -use crate::common::*; +use crate::prelude::*; use regex::Regex; #[derive(PartialEq, Clone, Debug)] diff --git a/src/repr/basic.rs b/src/repr/basic.rs new file mode 100644 index 0000000..bf9d852 --- /dev/null +++ b/src/repr/basic.rs @@ -0,0 +1,41 @@ +use crate::prelude::*; + +#[derive(Clone, Debug, PartialEq)] +pub enum BasicAstExpression { + Integer(i64), + Float(f64), + Variable(String), + String(String), + Binary(Operator, Box, Box), + Unary(UnaryOperator, Box), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum BasicAstInstruction { + JumpLabel(String), + Assign(String, BasicAstExpression), + Jump(String), + IfThenElse(BasicAstExpression, BasicAstBlock, BasicAstBlock), + Print(Vec<(BasicAstExpression, bool)>), + CallBuiltin(String, Vec), + For { + variable: String, + start: BasicAstExpression, + end: BasicAstExpression, + step: BasicAstExpression, + instructions: BasicAstBlock, + }, +} + +#[derive(Clone, Debug, PartialEq, Default)] +pub struct BasicAstBlock { + pub instructions: Vec, +} + +impl BasicAstBlock { + pub fn new(instructions: impl IntoIterator) -> Self { + Self { + instructions: instructions.into_iter().collect(), + } + } +} diff --git a/src/repr/mlog.rs b/src/repr/mlog.rs new file mode 100644 index 0000000..4320866 --- /dev/null +++ b/src/repr/mlog.rs @@ -0,0 +1,111 @@ +use super::operator::*; + +#[derive(Debug, Clone)] +pub enum Operand { + Variable(String), + String(String), + Integer(i64), + Float(f64), +} + +impl std::fmt::Display for Operand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Operand::Variable(name) => write!(f, "{}", name), + Operand::String(string) => { + let escaped = string.replace('\\', r"\\").replace('"', r#"\""#); + write!(f, "\"{}\"", escaped) + } + Operand::Integer(int) => write!(f, "{}", int), + Operand::Float(float) => write!(f, "{}", float), + } + } +} + +#[derive(Debug, Clone)] +pub enum MindustryOperation { + JumpLabel(String), + Jump(String), + JumpIf(String, Operator, Operand, Operand), + Operator(String, Operator, Operand, Operand), + UnaryOperator(String, UnaryOperator, Operand), + // TODO: add RandOperator + Set(String, Operand), + /// A generic operation, with the following invariants: + /// - all of the operands are read-only + /// - there is no external dependency to other variables + /// - no external variable is modified + Generic(String, Vec), + /// A generic, mutating operation `(name, out_name, operands)`, with the following invariants: + /// - all of the operands are read-only + /// - there is no external dependency to other variables, except `out_name` + /// - only `out_name` is modified + GenericMut(String, String, Vec), +} + +impl MindustryOperation { + pub(crate) fn operands(&self) -> Box<[&Operand]> { + match self { + Self::JumpIf(_label, _operator, lhs, rhs) => Box::new([lhs, rhs]), + Self::Operator(_target, _operator, lhs, rhs) => Box::new([lhs, rhs]), + Self::UnaryOperator(_target, _operator, value) => Box::new([value]), + Self::Set(_target, value) => Box::new([value]), + Self::Generic(_name, operands) => { + operands.iter().collect::>().into_boxed_slice() + } + Self::GenericMut(_name, _out_name, operands) => { + operands.iter().collect::>().into_boxed_slice() + } + _ => Box::new([]), + } + } + + pub(crate) fn operands_mut(&mut self) -> Vec<&mut Operand> { + match self { + Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs], + Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs], + Self::UnaryOperator(_target, _operator, value) => vec![value], + Self::Set(_target, value) => vec![value], + Self::Generic(_name, operands) => operands.iter_mut().collect::>(), + Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::>(), + _ => vec![], + } + } + + pub(crate) fn mutates(&self, var_name: &str) -> bool { + match self { + MindustryOperation::JumpLabel(_) + | MindustryOperation::Jump(_) + | MindustryOperation::JumpIf(_, _, _, _) + | MindustryOperation::Generic(_, _) => false, + + MindustryOperation::Operator(out_name, _, _, _) + | MindustryOperation::UnaryOperator(out_name, _, _) + | MindustryOperation::Set(out_name, _) + | MindustryOperation::GenericMut(_, out_name, _) => out_name == var_name, + } + } +} + +#[derive(Debug, Clone, Default)] +pub struct MindustryProgram(pub Vec); + +impl MindustryProgram { + pub fn new() -> Self { + Self(Vec::new()) + } + + pub fn push(&mut self, operation: MindustryOperation) { + self.0.push(operation); + } + + pub fn append(&mut self, other: &mut Self) { + self.0.append(&mut other.0); + } +} + +impl From> for MindustryProgram { + fn from(value: Vec) -> Self { + Self(value) + } +} diff --git a/src/repr/mod.rs b/src/repr/mod.rs new file mode 100644 index 0000000..0ef22ad --- /dev/null +++ b/src/repr/mod.rs @@ -0,0 +1,3 @@ +pub mod basic; +pub mod mlog; +pub mod operator; diff --git a/src/common.rs b/src/repr/operator.rs similarity index 62% rename from src/common.rs rename to src/repr/operator.rs index e7434cf..d9d8a60 100644 --- a/src/common.rs +++ b/src/repr/operator.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Operator { Add, @@ -98,37 +96,3 @@ pub(crate) fn format_unary_operator(operator: UnaryOperator) -> &'static str { UnaryOperator::Sqrt => "sqrt", } } - -#[derive(Clone, Debug)] -pub struct Config { - pub builtin_functions: HashMap, -} - -impl Default for Config { - fn default() -> Self { - macro_rules! builtin_function { - ( $name:expr, $target_name:expr, $mutating:expr, $n_args:expr ) => { - ( - String::from($name), - (String::from($target_name), $mutating, $n_args), - ) - }; - } - Self { - builtin_functions: HashMap::from([ - builtin_function!("print_flush", "printflush", false, 1), - // TODO: write a special case for message - builtin_function!("print_message_mission", "message mission", false, 0), - builtin_function!("read", "read", true, 3), - // TODO: don't use a generic operation here - builtin_function!("write", "write", false, 3), - builtin_function!("wait", "wait", false, 1), - // TODO: don't use a generic operation here either - builtin_function!("set_flag", "setflag", false, 2), - builtin_function!("get_flag", "getflag", true, 2), - // TODO: same thing - builtin_function!("spawn", "spawn", false, 6), - ]), - } - } -} diff --git a/src/compile/mod.rs b/src/translate/mod.rs similarity index 75% rename from src/compile/mod.rs rename to src/translate/mod.rs index f529445..aacb94f 100644 --- a/src/compile/mod.rs +++ b/src/translate/mod.rs @@ -1,120 +1,6 @@ use regex::Regex; -use crate::common::*; -use crate::parse::{BasicAstBlock, BasicAstExpression}; - -mod optimize; -pub use optimize::*; - -#[derive(Debug, Clone)] -pub enum Operand { - Variable(String), - String(String), - Integer(i64), - Float(f64), -} - -impl std::fmt::Display for Operand { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Operand::Variable(name) => write!(f, "{}", name), - Operand::String(string) => { - let escaped = string.replace('\\', r"\\").replace('"', r#"\""#); - write!(f, "\"{}\"", escaped) - } - Operand::Integer(int) => write!(f, "{}", int), - Operand::Float(float) => write!(f, "{}", float), - } - } -} - -#[derive(Debug, Clone)] -pub enum MindustryOperation { - JumpLabel(String), - Jump(String), - JumpIf(String, Operator, Operand, Operand), - Operator(String, Operator, Operand, Operand), - UnaryOperator(String, UnaryOperator, Operand), - // TODO: add RandOperator - Set(String, Operand), - /// A generic operation, with the following invariants: - /// - all of the operands are read-only - /// - there is no external dependency to other variables - /// - no external variable is modified - Generic(String, Vec), - /// A generic, mutating operation `(name, out_name, operands)`, with the following invariants: - /// - all of the operands are read-only - /// - there is no external dependency to other variables, except `out_name` - /// - only `out_name` is modified - GenericMut(String, String, Vec), -} - -impl MindustryOperation { - fn operands(&self) -> Box<[&Operand]> { - match self { - Self::JumpIf(_label, _operator, lhs, rhs) => Box::new([lhs, rhs]), - Self::Operator(_target, _operator, lhs, rhs) => Box::new([lhs, rhs]), - Self::UnaryOperator(_target, _operator, value) => Box::new([value]), - Self::Set(_target, value) => Box::new([value]), - Self::Generic(_name, operands) => { - operands.iter().collect::>().into_boxed_slice() - } - Self::GenericMut(_name, _out_name, operands) => { - operands.iter().collect::>().into_boxed_slice() - } - _ => Box::new([]), - } - } - - fn operands_mut(&mut self) -> Vec<&mut Operand> { - match self { - Self::JumpIf(_label, _operator, lhs, rhs) => vec![lhs, rhs], - Self::Operator(_target, _operator, lhs, rhs) => vec![lhs, rhs], - Self::UnaryOperator(_target, _operator, value) => vec![value], - Self::Set(_target, value) => vec![value], - Self::Generic(_name, operands) => operands.iter_mut().collect::>(), - Self::GenericMut(_name, _out_name, operands) => operands.iter_mut().collect::>(), - _ => vec![], - } - } - - fn mutates(&self, var_name: &str) -> bool { - match self { - MindustryOperation::JumpLabel(_) - | MindustryOperation::Jump(_) - | MindustryOperation::JumpIf(_, _, _, _) - | MindustryOperation::Generic(_, _) => false, - - MindustryOperation::Operator(out_name, _, _, _) - | MindustryOperation::UnaryOperator(out_name, _, _) - | MindustryOperation::Set(out_name, _) - | MindustryOperation::GenericMut(_, out_name, _) => out_name == var_name, - } - } -} - -#[derive(Debug, Clone, Default)] -pub struct MindustryProgram(pub Vec); - -impl MindustryProgram { - pub fn new() -> Self { - Self(Vec::new()) - } - - pub fn push(&mut self, operation: MindustryOperation) { - self.0.push(operation); - } - - pub fn append(&mut self, other: &mut Self) { - self.0.append(&mut other.0); - } -} - -impl From> for MindustryProgram { - fn from(value: Vec) -> Self { - Self(value) - } -} +use crate::prelude::*; pub struct Namer { var_index: usize, @@ -205,7 +91,7 @@ pub fn translate_ast( namer: &mut Namer, config: &Config, ) -> MindustryProgram { - use crate::parse::BasicAstInstruction as Instr; + use crate::repr::basic::BasicAstInstruction as Instr; let mut res = MindustryProgram::new(); for instruction in basic_ast.instructions.iter() { diff --git a/tests/examples.rs b/tests/examples.rs index 1568138..29e86c8 100644 --- a/tests/examples.rs +++ b/tests/examples.rs @@ -2,11 +2,10 @@ use std::path::{Path, PathBuf}; -use basic_to_mindustry::common::Config; -use basic_to_mindustry::compile::{ - optimize_constant, optimize_jump_always, optimize_jump_op, translate_ast, -}; +use basic_to_mindustry::optimize::{optimize_constant, optimize_jump_always, optimize_jump_op}; use basic_to_mindustry::parse::{build_ast, tokenize}; +use basic_to_mindustry::prelude::*; +use basic_to_mindustry::translate::translate_ast; fn read_basic_examples() -> impl Iterator { Path::new("./examples/")