update
This commit is contained in:
parent
d19381964f
commit
3e7bb062aa
@ -8,12 +8,13 @@ use visitor::ConstantFolder;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// let contents = fs::read_to_string("main_android_org.lua")
|
// let contents = fs::read_to_string("main_android_org.lua")
|
||||||
let contents = fs::read_to_string("small.lua")
|
// let contents = fs::read_to_string("small.lua")
|
||||||
|
let contents = fs::read_to_string("very_small.lua")
|
||||||
.expect("Something went wrong reading the file");
|
.expect("Something went wrong reading the file");
|
||||||
|
|
||||||
let tree = parse(&contents).expect("Parsing gone wrong");
|
let tree = parse(&contents).expect("Parsing lua gone wrong");
|
||||||
|
|
||||||
let mut folder = ConstantFolder{};
|
let mut folder = ConstantFolder::new();
|
||||||
folder.visit(tree);
|
folder.visit(tree);
|
||||||
|
|
||||||
// let nodes = tree.nodes_mut();
|
// let nodes = tree.nodes_mut();
|
||||||
|
@ -1,69 +1,75 @@
|
|||||||
|
mod expression_reducer;
|
||||||
|
|
||||||
use full_moon::ast::*;
|
use full_moon::ast::*;
|
||||||
|
|
||||||
use crate::visitor::Visitor;
|
use crate::visitor::Visitor;
|
||||||
|
|
||||||
struct VariableValue {}
|
|
||||||
|
|
||||||
// value: Literal | String | Module | ReducedExpression
|
fn is_standard_library(name: String) -> bool {
|
||||||
struct Variable {
|
let standard_library_names: Vec<&str> = vec![
|
||||||
name: String,
|
"math", "string", "table", "bit"
|
||||||
value: VariableValue
|
];
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConstantFolder {
|
pub struct ConstantFolder {
|
||||||
locals: Vec<Variable>
|
locals: Vec<expression_reducer::Variable>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstantFolder {
|
impl ConstantFolder {
|
||||||
/// Return `Name` struct for a valid standard library name/function
|
pub fn new() -> Self {
|
||||||
///
|
ConstantFolder{
|
||||||
/// Lua has standard library modules like `math.max`, `math.min`
|
locals: vec![]
|
||||||
/// This function returns a Name if the given argument are valid
|
|
||||||
/// This is to disambiguate between Var.Name
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `module` - Standard library model
|
|
||||||
/// * `name` - The module
|
|
||||||
///
|
|
||||||
fn name_from_standard_library(name: &str) -> Option<&str> {
|
|
||||||
let standard_library_names = vec![
|
|
||||||
"math", "string", "table", "bit"
|
|
||||||
];
|
|
||||||
if standard_library_names.contains(&name) {
|
|
||||||
Some(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expression<'a>(&mut self, expression: Expression<'a>) {
|
fn register_local(&mut self, name: Option<String>, value: Option<Expression>) -> bool {
|
||||||
match expression {
|
if name.is_none() {
|
||||||
Expression::BinaryOperator {
|
return false
|
||||||
lhs,
|
|
||||||
rhs,
|
|
||||||
binop
|
|
||||||
} => {
|
|
||||||
}
|
|
||||||
Expression::Parentheses {
|
|
||||||
contained,
|
|
||||||
expression,
|
|
||||||
} => {}
|
|
||||||
Expression::UnaryOperator {
|
|
||||||
unop,
|
|
||||||
expression,
|
|
||||||
} => {}
|
|
||||||
Expression::Value {
|
|
||||||
value
|
|
||||||
} => {}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
self.locals.push(
|
||||||
|
expression_reducer::Variable::with_value(
|
||||||
|
name.unwrap(), value, &self.locals
|
||||||
|
));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assign(&mut self, name: Option<String>, value: Option<Expression>) -> bool {
|
||||||
|
if name.is_none() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let var = expression_reducer::Variable::with_value(
|
||||||
|
name.unwrap(), value, &self.locals
|
||||||
|
);
|
||||||
|
{
|
||||||
|
let mut iter = self.locals.iter_mut();
|
||||||
|
let it = iter.find(|it| it.name() == var.name());
|
||||||
|
it.map(|old| old.assign_value(var));
|
||||||
|
};
|
||||||
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor for ConstantFolder {
|
impl Visitor for ConstantFolder {
|
||||||
fn visit_assignment<'a>(&mut self, assignment: &Assignment<'a>) {
|
fn visit_assignment<'a>(&mut self, assignment: &Assignment<'a>) {
|
||||||
println!("visit assignment {}", assignment);
|
let mut names = assignment.variables().iter();
|
||||||
|
let mut expressions = assignment.expressions().iter();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let name = names.next().map(|x| match x {
|
||||||
|
Var::Expression(var_expr) => {
|
||||||
|
var_expr.to_string()
|
||||||
|
}
|
||||||
|
Var::Name(n) => n.token().to_string(),
|
||||||
|
_ => {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let expr = expressions.next().map(|x| x.clone() /* reduced */);
|
||||||
|
if !self.assign(name, expr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_do<'a>(&mut self, do_: &Do<'a>) {
|
fn visit_do<'a>(&mut self, do_: &Do<'a>) {
|
||||||
@ -87,7 +93,16 @@ impl Visitor for ConstantFolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local_assignment<'a>(&mut self, local_assignment: &LocalAssignment<'a>) {
|
fn visit_local_assignment<'a>(&mut self, local_assignment: &LocalAssignment<'a>) {
|
||||||
println!("visit local_assignment {}", local_assignment);
|
let mut names = local_assignment.names().iter();
|
||||||
|
let mut expressions = local_assignment.expressions().iter();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let name = names.next().map(|x| x.token().to_string());
|
||||||
|
let expr = expressions.next().map(|x| x.clone() /* reduced */);
|
||||||
|
if !self.register_local(name, expr) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_local_function<'a>(&mut self, local_function: &LocalFunction<'a>) {
|
fn visit_local_function<'a>(&mut self, local_function: &LocalFunction<'a>) {
|
||||||
|
365
src/visitor/constant_folder/expression_reducer.rs
Normal file
365
src/visitor/constant_folder/expression_reducer.rs
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
//! A compile-time expression folder (constant propagation)
|
||||||
|
//!
|
||||||
|
//! To do constant folding, we must be able to reduce expression at
|
||||||
|
//! the compile-time. We give each Variable an Expression and reduce it.
|
||||||
|
//! If there is some expression, the variable value is the expression reduced.
|
||||||
|
//! Else the variable has undefined value at compile-time.
|
||||||
|
//!
|
||||||
|
//! We try to reduce
|
||||||
|
//! ```lua
|
||||||
|
//! L41_1 = L37_1
|
||||||
|
//! L42_1 = 20
|
||||||
|
//! L43_1 = 76
|
||||||
|
//! L44_1 = 201
|
||||||
|
//! L45_1 = 132
|
||||||
|
//! L46_1 = 98
|
||||||
|
//! L47_1 = 93
|
||||||
|
//! L41_1 = (L41_1(L42_1, L43_1, L44_1, L45_1, L46_1, L47_1))
|
||||||
|
//! ```
|
||||||
|
//! into
|
||||||
|
//! ```lua
|
||||||
|
//! L41_1 = L37_1
|
||||||
|
//! L42_1 = 20
|
||||||
|
//! L43_1 = 76
|
||||||
|
//! L44_1 = 201
|
||||||
|
//! L45_1 = 132
|
||||||
|
//! L46_1 = 98
|
||||||
|
//! L47_1 = 93
|
||||||
|
//! L41_1 = L37_1(20, 76, 201, 132, 98, 93)
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! We reduce expression with a list of local variables.
|
||||||
|
//!
|
||||||
|
//! There are many cases where reduction fail to complete, these expression
|
||||||
|
//! won't reduced and kept the same.
|
||||||
|
//!
|
||||||
|
//! - Undefined or parameter
|
||||||
|
//! - Nil initialized
|
||||||
|
//! - Set {}
|
||||||
|
//! - For counter
|
||||||
|
//! - Function call
|
||||||
|
//! - Lambda function
|
||||||
|
//!
|
||||||
|
//! Every expression containing these won't be reduced furthur. Thus:
|
||||||
|
//! ```lua
|
||||||
|
//! L1 = 0
|
||||||
|
//! L2 = nil
|
||||||
|
//! L3 = L1 + L2
|
||||||
|
//! ```
|
||||||
|
//! reduces into
|
||||||
|
//! ```lua
|
||||||
|
//! L1 = 0
|
||||||
|
//! L2 = nil
|
||||||
|
//! L3 = 0 + L2
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Keep in mind that we do expression folding only, dead code elimination
|
||||||
|
//! is done through another pass
|
||||||
|
|
||||||
|
use full_moon::ast;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum VariableType {
|
||||||
|
Number,
|
||||||
|
String,
|
||||||
|
Boolean,
|
||||||
|
// Function(Vec<VariableType>, Vec<VariableType>), // name, param, result
|
||||||
|
// Array(Box<VariableType>),
|
||||||
|
// Dict(Box<VariableType>),
|
||||||
|
// Module(String, String),
|
||||||
|
Function,
|
||||||
|
Array,
|
||||||
|
Dict,
|
||||||
|
Module,
|
||||||
|
Nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Variable {
|
||||||
|
n: String, // name
|
||||||
|
t: VariableType,
|
||||||
|
v: Option<Expression>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Variable {
|
||||||
|
pub fn with_value(name: String, expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Self {
|
||||||
|
let v = Expression::reduce(expr, locals);
|
||||||
|
let t = v.as_ref().map_or(VariableType::Nil, |x| x.assume_type(locals));
|
||||||
|
println!("variable_with {} = {:?}", name, v);
|
||||||
|
Self {
|
||||||
|
n: name,
|
||||||
|
v: v,
|
||||||
|
t: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.n.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assign_value(&mut self, var: Self) {
|
||||||
|
println!("variable_assign {} = {:?}", self.n, var.v);
|
||||||
|
self.v = var.v;
|
||||||
|
self.t = var.t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Expression {
|
||||||
|
Number(f64),
|
||||||
|
Boolean(bool),
|
||||||
|
String(String),
|
||||||
|
Var(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
pub fn reduce(expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Option<Self> {
|
||||||
|
if expr.is_none() {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
let expr = expr.unwrap();
|
||||||
|
Some(reduce_expression(expr, locals))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assume_type(&self, locals: &Vec<Variable>) -> VariableType {
|
||||||
|
match self {
|
||||||
|
Expression::Number(_) => { VariableType::Number }
|
||||||
|
Expression::Boolean(_) => { VariableType::Boolean }
|
||||||
|
Expression::String(_) => { VariableType::String }
|
||||||
|
Expression::Var(_) => {
|
||||||
|
VariableType::Number
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
VariableType::Nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_expression(expr: ast::Expression, locals: &Vec<Variable>) -> Expression {
|
||||||
|
match expr {
|
||||||
|
ast::Expression::BinaryOperator {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
binop
|
||||||
|
} => {
|
||||||
|
let lhs_ = reduce_expression(*lhs, locals);
|
||||||
|
let rhs_ = reduce_expression(*rhs, locals);
|
||||||
|
apply_binary_operator(lhs_, rhs_, binop)
|
||||||
|
}
|
||||||
|
ast::Expression::Parentheses {
|
||||||
|
expression,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
reduce_expression(*expression, locals)
|
||||||
|
}
|
||||||
|
ast::Expression::UnaryOperator {
|
||||||
|
unop,
|
||||||
|
expression,
|
||||||
|
} => {
|
||||||
|
let expression_ = reduce_expression(*expression, locals);
|
||||||
|
apply_unary_operator(expression_, unop)
|
||||||
|
}
|
||||||
|
ast::Expression::Value {
|
||||||
|
value
|
||||||
|
} => {
|
||||||
|
reduce_expression_value(*value, locals)
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_expression_value(value: ast::Value, locals: &Vec<Variable>) -> Expression {
|
||||||
|
match value {
|
||||||
|
ast::Value::Function(function) => {
|
||||||
|
panic!("reduce Expression::Function is unsupported");
|
||||||
|
}
|
||||||
|
ast::Value::FunctionCall(function_call) => {
|
||||||
|
panic!("reduce Expression::FunctionCall is unsupported");
|
||||||
|
}
|
||||||
|
ast::Value::TableConstructor(table_constructor) => {
|
||||||
|
panic!("reduce Expression::TableConstructor is unsupported");
|
||||||
|
}
|
||||||
|
ast::Value::Number(number) => {
|
||||||
|
let num = number.token().to_string();
|
||||||
|
Expression::Number(num.parse::<f64>().unwrap())
|
||||||
|
}
|
||||||
|
ast::Value::ParenthesesExpression(parentheses_expression) => {
|
||||||
|
reduce_expression(parentheses_expression, locals)
|
||||||
|
}
|
||||||
|
ast::Value::String(string) => {
|
||||||
|
Expression::String(string.token().to_string())
|
||||||
|
}
|
||||||
|
ast::Value::Symbol(symbol) => {
|
||||||
|
panic!("reduce Expression::Symbol is unsupported");
|
||||||
|
}
|
||||||
|
ast::Value::Var(var) => {
|
||||||
|
reduce_expression_value_var(var, locals)
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_expression_value_var(var: ast::Var, locals: &Vec<Variable>) -> Expression {
|
||||||
|
match var {
|
||||||
|
ast::Var::Expression(expr) => {
|
||||||
|
panic!("reduce Var::Expression is unsupported")
|
||||||
|
}
|
||||||
|
ast::Var::Name(name) => {
|
||||||
|
let local_var = locals.iter().find(|it| it.name() == name.token().to_string());
|
||||||
|
match local_var {
|
||||||
|
None => {
|
||||||
|
panic!("local variable not found")
|
||||||
|
}
|
||||||
|
Some(v) => {
|
||||||
|
v.v.as_ref().unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_binary_operator(lhs: Expression, rhs: Expression, binop: ast::BinOp) -> Expression {
|
||||||
|
match binop {
|
||||||
|
ast::BinOp::And(_) => {
|
||||||
|
panic!("Binary And unimplemented")
|
||||||
|
}
|
||||||
|
ast::BinOp::Caret(_) => {
|
||||||
|
panic!("Binary Caret unimplemented")
|
||||||
|
}
|
||||||
|
ast::BinOp::GreaterThan(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Boolean(lhs_ > rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary GreaterThan wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::GreaterThanEqual(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Boolean(lhs_ >= rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary GreaterThanEqual wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::LessThan(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Boolean(lhs_ < rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary LessThan wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::LessThanEqual(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Boolean(lhs_ <= rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary LessThanEqual wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::Minus(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Number(lhs_ - rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary Minus wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::Or(_) => {
|
||||||
|
panic!("Binary Or unimplemented")
|
||||||
|
}
|
||||||
|
ast::BinOp::Percent(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Number(lhs_ % rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary Percent wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::Plus(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Number(lhs_ + rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary Plus wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::Slash(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Number(lhs_ / rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary Slash wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::Star(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Number(lhs_ * rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary Star wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::BinOp::TildeEqual(_) => {
|
||||||
|
panic!("Binary TildeEqual unimplemented")
|
||||||
|
}
|
||||||
|
ast::BinOp::TwoDots(_) => {
|
||||||
|
panic!("Binary TwoDots unimplemented")
|
||||||
|
}
|
||||||
|
ast::BinOp::TwoEqual(_) => {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
|
||||||
|
Expression::Boolean(lhs_ == rhs_)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Binary TwoEqual wrong argument")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_unary_operator(expr: Expression, unop: ast::UnOp) -> Expression {
|
||||||
|
match unop {
|
||||||
|
ast::UnOp::Not(_) => {
|
||||||
|
if let Expression::Boolean(e) = expr {
|
||||||
|
Expression::Boolean(!e)
|
||||||
|
} else {
|
||||||
|
panic!("Unary Not applied to non Number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::UnOp::Minus(_) => {
|
||||||
|
if let Expression::Number(e) = expr {
|
||||||
|
Expression::Number(-e)
|
||||||
|
} else {
|
||||||
|
panic!("Unary Minus applied to non Number")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::UnOp::Hash(_) => {
|
||||||
|
panic!("Unary Hash unimplemented")
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
144
src/visitor/constant_folder/variable_.rs
Normal file
144
src/visitor/constant_folder/variable_.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
/// A compile-time expression folder (constant propagation)
|
||||||
|
///
|
||||||
|
/// To do constant folding, we must be able to reduce expression at
|
||||||
|
/// the compile-time. We give each Variable an Expression and reduce it.
|
||||||
|
/// If there is some expression, the variable value is the expression reduced.
|
||||||
|
/// Else the variable has undefined value at compile-time.
|
||||||
|
///
|
||||||
|
/// We try to reduce
|
||||||
|
/// ```lua
|
||||||
|
/// L41_1 = L37_1
|
||||||
|
/// L42_1 = 20
|
||||||
|
/// L43_1 = 76
|
||||||
|
/// L44_1 = 201
|
||||||
|
/// L45_1 = 132
|
||||||
|
/// L46_1 = 98
|
||||||
|
/// L47_1 = 93
|
||||||
|
/// L41_1 = (L41_1(L42_1, L43_1, L44_1, L45_1, L46_1, L47_1))
|
||||||
|
/// ```
|
||||||
|
/// into
|
||||||
|
/// ```lua
|
||||||
|
/// L41_1 = L37_1
|
||||||
|
/// L42_1 = 20
|
||||||
|
/// L43_1 = 76
|
||||||
|
/// L44_1 = 201
|
||||||
|
/// L45_1 = 132
|
||||||
|
/// L46_1 = 98
|
||||||
|
/// L47_1 = 93
|
||||||
|
/// L41_1 = L37_1(20, 76, 201, 132, 98, 93)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// We reduce expression with a list of local variables.
|
||||||
|
///
|
||||||
|
/// There are many cases where reduction fail to complete, these expression
|
||||||
|
/// won't reduced and kept the same.
|
||||||
|
///
|
||||||
|
/// - Undefined or parameter
|
||||||
|
/// - Nil initialized
|
||||||
|
/// - Set {}
|
||||||
|
/// - For counter
|
||||||
|
///
|
||||||
|
/// Every expression containing these won't be reduced furthur. Thus:
|
||||||
|
/// ```lua
|
||||||
|
/// L1 = 0
|
||||||
|
/// L2 = nil
|
||||||
|
/// L3 = L1 + L2
|
||||||
|
/// ```
|
||||||
|
/// reduces into
|
||||||
|
/// ```lua
|
||||||
|
/// L1 = 0
|
||||||
|
/// L2 = nil
|
||||||
|
/// L3 = 0 + L2
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Keep in mind that we do expression folding only, dead code elimination
|
||||||
|
/// is done through another pass
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
enum BinOp {
|
||||||
|
Plus,
|
||||||
|
Minus,
|
||||||
|
Modulus,
|
||||||
|
Times,
|
||||||
|
Dividend,
|
||||||
|
Concat,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CompareOp {
|
||||||
|
Lt,
|
||||||
|
Eq,
|
||||||
|
Gt,
|
||||||
|
Lte,
|
||||||
|
Gte,
|
||||||
|
Ne,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Types of expression
|
||||||
|
enum Expression {
|
||||||
|
/// a number (int)
|
||||||
|
Literal(i64),
|
||||||
|
/// a string literal
|
||||||
|
String(String),
|
||||||
|
/// special name of library module.function (math.min)
|
||||||
|
Module(String, Vec<String>),
|
||||||
|
/// variable referencing
|
||||||
|
Var(Variable),
|
||||||
|
/// Binary operation between expression
|
||||||
|
BinOp(Box<Expression>, Box<Expression>, BinOp),
|
||||||
|
/// Index into array
|
||||||
|
Index(Box<Expression>, Box<Expression>),
|
||||||
|
/// Comparision expression (1 < 2)
|
||||||
|
Comparision(Box<Expression>, Box<Expression>, CompareOp),
|
||||||
|
/// Function call
|
||||||
|
FunctionCall(),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Variable has a name and the expression attached to it
|
||||||
|
pub struct Variable {
|
||||||
|
name: String,
|
||||||
|
value: Option<Box<Expression>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add for Expression {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, other: Self) -> Self {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ops::Sub for Expression {}
|
||||||
|
impl ops::Mul for Expression {}
|
||||||
|
impl ops::Div for Expression {}
|
||||||
|
impl ops::Rem for Expression {}
|
||||||
|
|
||||||
|
pub fn reduce_expression(expr: Expression, locals: Vec<Variable>) -> Expression {
|
||||||
|
match expr {
|
||||||
|
Expression::BinOp(lhs_, rhs_, op) => {
|
||||||
|
let lhs = reduce_expression(*lhs_, locals);
|
||||||
|
let rhs = reduce_expression(*rhs_, locals);
|
||||||
|
match op {
|
||||||
|
Plus => {
|
||||||
|
lhs + rhs
|
||||||
|
}
|
||||||
|
Minus => {
|
||||||
|
lhs - rhs
|
||||||
|
}
|
||||||
|
Modulus => {
|
||||||
|
lhs % rhs
|
||||||
|
}
|
||||||
|
Times => {
|
||||||
|
lhs * rhs
|
||||||
|
}
|
||||||
|
Dividend => {
|
||||||
|
lhs / rhs
|
||||||
|
}
|
||||||
|
Concat => {
|
||||||
|
lhs.concat(rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => expr
|
||||||
|
}
|
||||||
|
}
|
3
very_small.lua
Normal file
3
very_small.lua
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
local L1_1, L1_2
|
||||||
|
L1_2 = 2
|
||||||
|
L1_1 = 1 + L1_2
|
Loading…
Reference in New Issue
Block a user