BinOp, UnOp, FunctionCall
This commit is contained in:
nganhkhoa 2021-05-19 16:09:55 +07:00
parent 3e7bb062aa
commit 2ca5c18d66
3 changed files with 291 additions and 188 deletions

View File

@ -13,40 +13,34 @@ fn is_standard_library(name: String) -> bool {
} }
pub struct ConstantFolder { pub struct ConstantFolder {
locals: Vec<expression_reducer::Variable> locals: Box<Vec<expression_reducer::Variable>>
} }
impl ConstantFolder { impl ConstantFolder {
pub fn new() -> Self { pub fn new() -> Self {
ConstantFolder{ ConstantFolder{
locals: vec![] locals: Box::new(vec![])
} }
} }
fn register_local(&mut self, name: Option<String>, value: Option<Expression>) -> bool { fn register_local(&mut self, name: String, value: Option<Expression>) {
if name.is_none() { let locals = &*self.locals;
return false
}
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( let var = expression_reducer::Variable::with_value(
name.unwrap(), value, &self.locals name, value, locals
);
self.locals.push(var);
}
fn assign(&mut self, name: String, value: Option<Expression>) {
let locals = &*self.locals;
let var = expression_reducer::Variable::with_value(
name, value, locals
); );
{ {
let mut iter = self.locals.iter_mut(); let mut iter = self.locals.iter_mut();
let it = iter.find(|it| it.name() == var.name()); let it = iter.find(|it| it.name() == var.name());
it.map(|old| old.assign_value(var)); it.map(|old| old.assign_value(var));
}; };
true
} }
} }
@ -54,20 +48,22 @@ impl Visitor for ConstantFolder {
fn visit_assignment<'a>(&mut self, assignment: &Assignment<'a>) { fn visit_assignment<'a>(&mut self, assignment: &Assignment<'a>) {
let mut names = assignment.variables().iter(); let mut names = assignment.variables().iter();
let mut expressions = assignment.expressions().iter(); let mut expressions = assignment.expressions().iter();
loop { loop {
let name = names.next().map(|x| match x { let name = names.next().map(|x| match x {
Var::Expression(var_expr) => { Var::Expression(_var_expr) => {
var_expr.to_string() panic!("assignment Var::Expression is not supported")
} }
Var::Name(n) => n.token().to_string(), Var::Name(n) => n.token().to_string(),
_ => { _ => unreachable!()
"".to_string()
}
}); });
let expr = expressions.next().map(|x| x.clone() /* reduced */); let expr = expressions.next().map(|x| x.clone() /* reduced */);
if !self.assign(name, expr) { match name {
break Some(name) => {
self.assign(name, expr);
}
None => {
break;
}
} }
} }
} }
@ -78,6 +74,8 @@ impl Visitor for ConstantFolder {
fn visit_function_call<'a>(&mut self, function_call: &FunctionCall<'a>) { fn visit_function_call<'a>(&mut self, function_call: &FunctionCall<'a>) {
println!("visit function_call {}", function_call); println!("visit function_call {}", function_call);
let reduced = expression_reducer::reduce_expression_value_function_call(function_call.clone(), &*self.locals);
println!("{:?}", reduced);
} }
fn visit_function_declaration<'a>(&mut self, function_declaration: &FunctionDeclaration<'a>) { fn visit_function_declaration<'a>(&mut self, function_declaration: &FunctionDeclaration<'a>) {
@ -99,8 +97,13 @@ impl Visitor for ConstantFolder {
loop { loop {
let name = names.next().map(|x| x.token().to_string()); let name = names.next().map(|x| x.token().to_string());
let expr = expressions.next().map(|x| x.clone() /* reduced */); let expr = expressions.next().map(|x| x.clone() /* reduced */);
if !self.register_local(name, expr) { match name {
break Some(name) => {
self.register_local(name, expr);
}
None => {
break;
}
} }
} }
} }

View File

@ -58,38 +58,19 @@
use full_moon::ast; 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)] #[derive(Debug)]
pub struct Variable { pub struct Variable {
n: String, // name n: String,
t: VariableType, v: Expression
v: Option<Expression>
} }
impl Variable { impl Variable {
pub fn with_value(name: String, expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Self { pub fn with_value(name: String, expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Self {
let v = Expression::reduce(expr, locals); 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); println!("variable_with {} = {:?}", name, v);
Self { Self {
n: name, n: name,
v: v, v: v,
t: t,
} }
} }
@ -100,38 +81,117 @@ impl Variable {
pub fn assign_value(&mut self, var: Self) { pub fn assign_value(&mut self, var: Self) {
println!("variable_assign {} = {:?}", self.n, var.v); println!("variable_assign {} = {:?}", self.n, var.v);
self.v = var.v; self.v = var.v;
self.t = var.t;
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expression { pub enum BinOp {
And,
Caret,
GreaterThan,
GreaterThanEqual,
LessThan,
LessThanEqual,
Minus,
Or,
Percent,
Plus,
Slash,
Star,
TildeEqual,
TwoDots,
TwoEqual,
}
impl BinOp {
fn from<'a>(binop: ast::BinOp<'a>) -> Self {
match binop {
ast::BinOp::And(_) => BinOp::And,
ast::BinOp::Caret(_) => BinOp::Caret,
ast::BinOp::GreaterThan(_) => BinOp::GreaterThan,
ast::BinOp::GreaterThanEqual(_) => BinOp::GreaterThanEqual,
ast::BinOp::LessThan(_) => BinOp::LessThan,
ast::BinOp::LessThanEqual(_) => BinOp::LessThanEqual,
ast::BinOp::Minus(_) => BinOp::Minus,
ast::BinOp::Or(_) => BinOp::Or,
ast::BinOp::Percent(_) => BinOp::Percent,
ast::BinOp::Plus(_) => BinOp::Plus,
ast::BinOp::Slash(_) => BinOp::Slash,
ast::BinOp::Star(_) => BinOp::Star,
ast::BinOp::TildeEqual(_) => BinOp::TildeEqual,
ast::BinOp::TwoDots(_) => BinOp::TwoDots,
ast::BinOp::TwoEqual(_) => BinOp::TwoEqual,
_ => unreachable!()
}
}
}
#[derive(Debug, Clone)]
pub enum UnOp {
Minus,
Not,
Hash,
}
impl UnOp {
fn from<'a>(unop: ast::UnOp<'a>) -> Self {
match unop {
ast::UnOp::Minus(_) => UnOp::Minus,
ast::UnOp::Not(_) => UnOp::Not,
ast::UnOp::Hash(_) => UnOp::Hash,
_ => unreachable!()
}
}
}
#[derive(Debug, Clone)]
pub enum ExpressionType {
Number(f64), Number(f64),
Boolean(bool), Boolean(bool),
String(String), String(String),
Var(String), Var(String), // name
FunctionCall(String, Vec<Expression>), // name, param
BinOp(Box<Expression>, Box<Expression>, BinOp), // lhs, rhs, binop
UnOp(Box<Expression>, UnOp),
Index(Box<Expression>, Vec<Expression>), // name, index expr
Nil,
}
#[derive(Debug, Clone)]
pub struct Expression {
t: ExpressionType,
} }
impl Expression { impl Expression {
pub fn reduce(expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Option<Self> { pub fn reduce(expr: Option<ast::Expression>, locals: &Vec<Variable>) -> Self {
if expr.is_none() { if expr.is_none() {
return None Expression{
t: ExpressionType::Nil,
} }
} else {
let expr = expr.unwrap(); let expr = expr.unwrap();
Some(reduce_expression(expr, locals)) reduce_expression(expr, locals)
}
} }
pub fn assume_type(&self, locals: &Vec<Variable>) -> VariableType { fn is_number(&self) -> bool {
match self { match self.t {
Expression::Number(_) => { VariableType::Number } ExpressionType::Number(_) => true,
Expression::Boolean(_) => { VariableType::Boolean } _ => false,
Expression::String(_) => { VariableType::String }
Expression::Var(_) => {
VariableType::Number
} }
_ => {
VariableType::Nil
} }
fn is_string(&self) -> bool {
match self.t {
ExpressionType::String(_) => true,
_ => false,
}
}
fn is_boolean(&self) -> bool {
match self.t {
ExpressionType::Boolean(_) => true,
_ => false,
} }
} }
} }
@ -175,23 +235,38 @@ fn reduce_expression_value(value: ast::Value, locals: &Vec<Variable>) -> Express
panic!("reduce Expression::Function is unsupported"); panic!("reduce Expression::Function is unsupported");
} }
ast::Value::FunctionCall(function_call) => { ast::Value::FunctionCall(function_call) => {
panic!("reduce Expression::FunctionCall is unsupported"); reduce_expression_value_function_call(function_call, locals)
} }
ast::Value::TableConstructor(table_constructor) => { ast::Value::TableConstructor(table_constructor) => {
panic!("reduce Expression::TableConstructor is unsupported"); panic!("reduce Expression::TableConstructor is unsupported");
} }
ast::Value::Number(number) => { ast::Value::Number(number) => {
let num = number.token().to_string(); let num = number.token().to_string();
Expression::Number(num.parse::<f64>().unwrap()) Expression{
t: ExpressionType::Number(num.parse::<f64>().unwrap()),
}
} }
ast::Value::ParenthesesExpression(parentheses_expression) => { ast::Value::ParenthesesExpression(parentheses_expression) => {
reduce_expression(parentheses_expression, locals) reduce_expression(parentheses_expression, locals)
} }
ast::Value::String(string) => { ast::Value::String(string) => {
Expression::String(string.token().to_string()) Expression{
t: ExpressionType::String(string.token().to_string()),
}
} }
ast::Value::Symbol(symbol) => { ast::Value::Symbol(symbol) => {
panic!("reduce Expression::Symbol is unsupported"); let s = symbol.token().to_string();
if s == "true" {
Expression{
t: ExpressionType::Boolean(true),
}
} else if s == "false" {
Expression{
t: ExpressionType::Boolean(false),
}
} else {
panic!("reduce Expression::Symbol is not true/false");
}
} }
ast::Value::Var(var) => { ast::Value::Var(var) => {
reduce_expression_value_var(var, locals) reduce_expression_value_var(var, locals)
@ -212,7 +287,7 @@ fn reduce_expression_value_var(var: ast::Var, locals: &Vec<Variable>) -> Express
panic!("local variable not found") panic!("local variable not found")
} }
Some(v) => { Some(v) => {
v.v.as_ref().unwrap().clone() v.v.clone()
} }
} }
} }
@ -220,141 +295,150 @@ fn reduce_expression_value_var(var: ast::Var, locals: &Vec<Variable>) -> Express
} }
} }
pub fn reduce_expression_value_function_call(function_call: ast::FunctionCall, locals: &Vec<Variable>) -> Expression {
let function_name = match function_call.prefix() {
ast::Prefix::Name(name) => name.token().to_string(),
_ => panic!("Function name as expression is unsupported")
};
let args = {
let suf = function_call.suffixes().next().unwrap();
match suf {
ast::Suffix::Call(ast::Call::AnonymousCall(ast::FunctionArgs::Parentheses{
arguments,
..
})) => {
arguments.iter().map(|x| reduce_expression(x.clone(), locals)).collect::<Vec<_>>()
}
_ => panic!("Index not supported")
}
};
Expression {
t: ExpressionType::FunctionCall(function_name, args)
}
}
fn apply_binary_operator(lhs: Expression, rhs: Expression, binop: ast::BinOp) -> Expression { fn apply_binary_operator(lhs: Expression, rhs: Expression, binop: ast::BinOp) -> Expression {
match (&lhs.t, &rhs.t) {
(&ExpressionType::Number(lhs_), &ExpressionType::Number(rhs_)) => {
match binop { match binop {
ast::BinOp::And(_) => {
panic!("Binary And unimplemented")
}
ast::BinOp::Caret(_) => {
panic!("Binary Caret unimplemented")
}
ast::BinOp::GreaterThan(_) => { ast::BinOp::GreaterThan(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Boolean(lhs_ > rhs_),
Expression::Boolean(lhs_ > rhs_)
}
_ => {
panic!("Binary GreaterThan wrong argument")
}
}
} }
},
ast::BinOp::GreaterThanEqual(_) => { ast::BinOp::GreaterThanEqual(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Boolean(lhs_ >= rhs_),
Expression::Boolean(lhs_ >= rhs_)
}
_ => {
panic!("Binary GreaterThanEqual wrong argument")
}
} }
} }
ast::BinOp::LessThan(_) => { ast::BinOp::LessThan(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Boolean(lhs_ < rhs_),
Expression::Boolean(lhs_ < rhs_)
}
_ => {
panic!("Binary LessThan wrong argument")
}
} }
} }
ast::BinOp::LessThanEqual(_) => { ast::BinOp::LessThanEqual(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Boolean(lhs_ <= rhs_),
Expression::Boolean(lhs_ <= rhs_)
}
_ => {
panic!("Binary LessThanEqual wrong argument")
}
} }
} }
ast::BinOp::Minus(_) => { ast::BinOp::Minus(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Number(lhs_ - rhs_),
Expression::Number(lhs_ - rhs_)
} }
_ => {
panic!("Binary Minus wrong argument")
}
}
}
ast::BinOp::Or(_) => {
panic!("Binary Or unimplemented")
} }
ast::BinOp::Percent(_) => { ast::BinOp::Percent(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Number(lhs_ % rhs_),
Expression::Number(lhs_ % rhs_)
}
_ => {
panic!("Binary Percent wrong argument")
}
} }
} }
ast::BinOp::Plus(_) => { ast::BinOp::Plus(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Number(lhs_ + rhs_),
Expression::Number(lhs_ + rhs_)
}
_ => {
panic!("Binary Plus wrong argument")
}
} }
} }
ast::BinOp::Slash(_) => { ast::BinOp::Slash(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Number(lhs_ / rhs_),
Expression::Number(lhs_ / rhs_)
}
_ => {
panic!("Binary Slash wrong argument")
}
} }
} }
ast::BinOp::Star(_) => { ast::BinOp::Star(_) => {
match (lhs, rhs) { return Expression {
(Expression::Number(lhs_), Expression::Number(rhs_)) => { t: ExpressionType::Number(lhs_ * rhs_),
Expression::Number(lhs_ * rhs_)
} }
_ => {
panic!("Binary Star wrong argument")
} }
ast::BinOp::Caret(_) => {
return Expression {
t: ExpressionType::Number(lhs_.powf(rhs_)),
}
}
ast::BinOp::TwoEqual(_) => {
return Expression {
t: ExpressionType::Boolean(lhs_ == rhs_),
} }
} }
ast::BinOp::TildeEqual(_) => { ast::BinOp::TildeEqual(_) => {
panic!("Binary TildeEqual unimplemented") return Expression {
t: ExpressionType::Boolean(lhs_ != rhs_),
} }
}
_ => {}
}
}
_ => {}
};
match (&lhs.t, &rhs.t) {
(&ExpressionType::Boolean(lhs_), &ExpressionType::Boolean(rhs_)) => {
match binop {
ast::BinOp::And(_) => {
return Expression {
t: ExpressionType::Boolean(lhs_ & rhs_),
}
}
ast::BinOp::Or(_) => {
return Expression {
t: ExpressionType::Boolean(lhs_ | rhs_),
}
}
_ => {}
}
}
_ => {}
}
match (&lhs.t, &rhs.t) {
(&ExpressionType::String(ref lhs_), &ExpressionType::String(ref rhs_)) => {
match binop {
ast::BinOp::TwoDots(_) => { ast::BinOp::TwoDots(_) => {
panic!("Binary TwoDots unimplemented") return Expression {
} t: ExpressionType::String(lhs_.clone() + &rhs_),
ast::BinOp::TwoEqual(_) => {
match (lhs, rhs) {
(Expression::Number(lhs_), Expression::Number(rhs_)) => {
Expression::Boolean(lhs_ == rhs_)
}
_ => {
panic!("Binary TwoEqual wrong argument")
} }
} }
_ => {}
} }
_ => unreachable!() }
_ => {}
}
Expression {
t: ExpressionType::BinOp(Box::new(lhs), Box::new(rhs), BinOp::from(binop)),
} }
} }
fn apply_unary_operator(expr: Expression, unop: ast::UnOp) -> Expression { fn apply_unary_operator(expr: Expression, unop: ast::UnOp) -> Expression {
match unop { match unop {
ast::UnOp::Not(_) => { ast::UnOp::Not(_) => {
if let Expression::Boolean(e) = expr { if let ExpressionType::Boolean(e) = expr.t {
Expression::Boolean(!e) return Expression {
} else { t: ExpressionType::Boolean(!e),
panic!("Unary Not applied to non Number") }
} }
} }
ast::UnOp::Minus(_) => { ast::UnOp::Minus(_) => {
if let Expression::Number(e) = expr { if let ExpressionType::Number(e) = expr.t {
Expression::Number(-e) return Expression {
} else { t: ExpressionType::Number(-e),
panic!("Unary Minus applied to non Number") }
} }
} }
ast::UnOp::Hash(_) => { ast::UnOp::Hash(_) => {
@ -362,4 +446,8 @@ fn apply_unary_operator(expr: Expression, unop: ast::UnOp) -> Expression {
} }
_ => unreachable!() _ => unreachable!()
} }
Expression {
t: ExpressionType::UnOp(Box::new(expr), UnOp::from(unop)),
}
} }

View File

@ -1,3 +1,15 @@
local L1_1, L1_2 local L1_1, L1_2, L41_1, L42_1, L43_1, L44_1, L45_1, L46_1, L47_1, L37_1
L1_2 = 2 L1_2 = 2
L1_1 = 1 + L1_2 L1_1 = 1 + L1_2
L1_1 = true
L1_2 = false
L1_1 = L1_1 and L1_2
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))