commit 8675dd398d1072afb380d699c83d32c8b937fea5
parent fdfff7510d9e645cd4d49b30e9a58371ea596aaa
Author: Demonstrandum <moi@knutsen.co>
Date: Tue, 6 Aug 2019 17:45:49 +0100
Rewrote constant folder.
Diffstat:
5 files changed, 59 insertions(+), 84 deletions(-)
diff --git a/src/compiler/block.rs b/src/compiler/block.rs
@@ -112,6 +112,13 @@ impl<'a> LocalBlock<'a> {
fn emit(&mut self, node : &'a ast::Nodes) {
match node {
ast::Nodes::Line(line_node) => {
+ let len = self.instructions.len();
+ if len > 1 {
+ if self.instructions[len - 2] == Instr::Operator(Operators::SET_LINE as u8) {
+ self.instructions.pop();
+ self.instructions.pop();
+ }
+ }
self.current_line = line_node.line;
self.instructions.push(Instr::Operator(Operators::SET_LINE as u8));
self.instructions.push(Instr::Operand(self.current_line as u16));
diff --git a/src/syntax/analyser.rs b/src/syntax/analyser.rs
@@ -6,81 +6,45 @@ use super::ast;
/// instead. This function takes a node and recurses down, looking
/// for arithmetic operations containing exactly two numeric type nodes
/// as operands, and performs the stated operation.
-fn constant_fold(node : &ast::Nodes) -> Option<ast::Nodes> {
- if node.num().is_some() { return Some(node.clone()); }
- if node.call().is_some() && node.call().unwrap().is_binary() {
- let operation = node.call().unwrap().callee.call().unwrap().callee.ident();
- if let Some(op) = operation {
- match op.value.as_str() {
- "+" | "-" | "*" | "/" => (),
- _ => {
- let mut new_call = *node.call().unwrap().callee.clone();
- let mut new_op = node.call().unwrap().operands[0].clone();
- let maybe_call = constant_fold(&new_call);
- let maybe_op = constant_fold(&new_op);
-
- if let Some(call) = maybe_call {
- new_call = call;
- }
- if maybe_op.is_some() {
- new_op = maybe_op.unwrap();
+fn const_fold(node : &ast::Nodes) -> ast::Nodes {
+ if let ast::Nodes::Call(call) = node {
+ if call.is_binary() {
+ let bin_op = call.callee.call().unwrap().callee.ident().unwrap();
+ let left = const_fold(&call.callee.call().unwrap().operands[0]);
+ let right = const_fold(&call.operands[0].clone());
+
+ let is_num_left = left.num().is_some();
+ let is_num_right = right.num().is_some();
+
+ if is_num_left && is_num_right {
+ let l_value = left.num().unwrap().value;
+ let r_value = right.num().unwrap().value;
+ let value = match bin_op.value.as_str() {
+ "+" => l_value + r_value,
+ "-" => l_value - r_value,
+ "*" => l_value * r_value,
+ "/" => {
+ if r_value == ast::Numerics::Natural(0) {
+ return node.clone();
+ }
+ l_value / r_value
+ },
+ _ => {
+ return node.to_owned();
}
- return Some(ast::CallNode::new(new_call, vec![new_op]));
- }
+ };
+ return ast::Nodes::Num(ast::NumNode { value });
}
- let right = node.call().unwrap().operands.get(0);
- let left = node.call().unwrap().callee.call().unwrap().operands.get(0);
-
- if left.is_none()
- || right.is_none()
- { return None; }
-
- let l_value;
- let r_value;
-
- if left.unwrap().num().is_some()
- && right.unwrap().num().is_some() {
- l_value = left.unwrap().num().unwrap().value;
- r_value = right.unwrap().num().unwrap().value;
- } else {
- let mut l = constant_fold(left.unwrap());
- let mut r = constant_fold(right.unwrap());
- if l.is_none() && r.is_none() { return None; }
- if l.is_some() {
- r = Some(right.unwrap().clone());
- } else {
- l = Some(left.unwrap().clone());
- }
-
- let foldl = constant_fold(&l.unwrap());
- let foldr = constant_fold(&r.unwrap());
- if foldl.is_none() || foldr.is_none() { return None; }
-
- l_value = foldl.unwrap().num().unwrap().value;
- r_value = foldr.unwrap().num().unwrap().value;
- }
- let value = match op.value.as_str() {
- "+" => l_value + r_value,
- "-" => l_value - r_value,
- "*" => l_value * r_value,
- "/" => {
- if r_value == ast::Numerics::Natural(0) {
- return Some(ast::CallNode::new(
- ast::CallNode::new(ast::IdentNode::new("/"),
- vec![ast::Nodes::Num(ast::NumNode { value : l_value })]),
- vec![ast::NumNode::new(0)]));
- }
- l_value / r_value
- },
- _ => return None
- };
- return Some(ast::Nodes::Num(ast::NumNode { value }));
}
+ return ast::CallNode::new(
+ const_fold(&*call.callee),
+ vec![const_fold(&call.operands[0])]);
}
- None
+ return node.to_owned();
}
+
fn create_cast(node : &ast::Nodes, cast : &ast::StaticTypes) -> ast::Nodes {
let to_type = match cast {
ast::StaticTypes::TReal => ":Real",
@@ -100,7 +64,7 @@ fn create_cast(node : &ast::Nodes, cast : &ast::StaticTypes) -> ast::Nodes {
cast_node
}
-fn cast_strenght(st : &ast::StaticTypes) -> i32 {
+fn cast_strength(st : &ast::StaticTypes) -> i32 {
match st {
ast::StaticTypes::TReal => 4,
ast::StaticTypes::TInteger => 2,
@@ -126,9 +90,9 @@ fn balance_types(node : &ast::Nodes) -> ast::Nodes {
let right_yield = right.yield_type();
if ["+", "-", "*", "/"].contains(&bin_op.value.as_str()) {
if left_yield.is_number() && right_yield.is_number() {
- if cast_strenght(&left_yield) != cast_strenght(&right_yield) {
+ if cast_strength(&left_yield) != cast_strength(&right_yield) {
- let casting_right = cast_strenght(&left_yield) > cast_strenght(&right_yield);
+ let casting_right = cast_strength(&left_yield) > cast_strength(&right_yield);
let cast_to = (if casting_right { &left } else { &right }).yield_type();
let mut new_call;
@@ -157,7 +121,7 @@ fn balance_types(node : &ast::Nodes) -> ast::Nodes {
}
} else if bin_op.value == "=" {
if left_yield.is_number() {
- if cast_strenght(&left_yield) > cast_strenght(&right_yield) {
+ if cast_strength(&left_yield) > cast_strength(&right_yield) {
let mut new_call = ast::CallNode::new(
*call.callee.clone(),
vec![create_cast(&right, &left_yield)]);
@@ -175,6 +139,7 @@ fn balance_types(node : &ast::Nodes) -> ast::Nodes {
if let ast::Nodes::Call(ref mut c) = non_bi {
c.set_return_type(node.yield_type());
}
+ return non_bi;
}
return node.to_owned();
}
@@ -184,10 +149,8 @@ pub fn replace(root : &mut ast::Root) {
let mut i = 0;
while i < length {
{ // START TOP-LEVEL CONSTANT FOLD
- let new = constant_fold(&root.branches[i]);
- if let Some(branch) = new {
- root.branches[i] = branch;
- }
+ let new = const_fold(&root.branches[i]);
+ root.branches[i] = new;
} // END TOP-LEVEL CONSTANT FOLD
{ // START TOP-LEVEL TYPE BALANCING
let new = balance_types(&root.branches[i]);
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
@@ -275,7 +275,7 @@ impl fmt::Display for StaticTypes {
StaticTypes::TSet(st) => format!("Set({})", st),
StaticTypes::TFunction(o, r) => format!("Function({}, {})", o, r),
StaticTypes::TNil => "Nil".to_string(),
- StaticTypes::TUnknown => "Unknown".to_string(),
+ StaticTypes::TUnknown => "Dynamic".to_string(),
};
write!(f, "{}", s)
}
@@ -298,13 +298,14 @@ pub enum Nodes {
impl fmt::Display for Nodes {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let yt = self.yield_type();
let printable = match self {
- Nodes::Ident(node) => format!("%ident{{ :value \"{}\" }}", node.value),
- Nodes::Num(node) => format!("%num{{ :value {} }}", node.value),
- Nodes::Str(node) => format!("%str{{ :value \"{}\" }}", node.value),
- Nodes::Sym(node) => format!("%sym{{ :value \":{}\" }}", node.value),
+ Nodes::Ident(node) => format!("%ident{{ :value \"{}\"; :yield :{} }}", node.value, yt),
+ Nodes::Num(node) => format!("%num{{ :value {}; :yield :{} }}", node.value, yt),
+ Nodes::Str(node) => format!("%str{{ :value \"{}\"; :yield :{} }}", node.value, yt),
+ Nodes::Sym(node) => format!("%sym{{ :value \":{}\"; :yield :{} }}", node.value, yt),
Nodes::Call(node) => format!(
- "%call{{\n :callee ({})\n :operands [|\n {}\n |]\n}}", node.callee,
+ "%call{{\n :yield :{}\n :callee ({})\n :operands [|\n {}\n |]\n}}", yt, node.callee,
node.operands.iter().map(Nodes::to_string).collect::<Vec<String>>().join("\n ")),
Nodes::Block(_) => format!("%block{{ ... }}"),
Nodes::Line(node) => format!("%newline{{ :line {} }}", node.line),
@@ -460,8 +461,9 @@ pub fn pretty_print(node : &Nodes, depth : usize) -> String {
let tab = TAB.repeat(depth);
let printable = match node {
Nodes::Call(n) => format!(
- "{tab}%call{{\n{tab}{T}:callee (\n{calling}\n{tab}{T})\n{tab}{T}:operand [|{op}|]\n{tab}}}",
+ "{tab}%call{{\n{tab}{T}:yield :{yt}\n{tab}{T}:callee (\n{calling}\n{tab}{T})\n{tab}{T}:operand [|{op}|]\n{tab}}}",
tab=tab, T=TAB,
+ yt=node.yield_type(),
calling=pretty_print(&*n.callee, depth + 2),
op=(if n.operands.is_empty() { String::from(" ") } else { format!(
"\n{ops}\n{tab}{T}",
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs
@@ -189,7 +189,7 @@ impl<'a> ParseEnvironment<'a> {
left = self.func_apply(left);
}
}
- if !left.call().unwrap().is_binary() { return left; }
+ if left.call().is_none() || !left.call().unwrap().is_binary() { return left; }
if let Some(call_ident) = left.call().unwrap().callee.call().unwrap().callee.ident() {
if call_ident.value == ":" {
self.annotations.push_back(left.call().unwrap().clone());
diff --git a/test.vh b/test.vh
@@ -4,3 +4,5 @@ a = 3 + 9
b : Real
b = a + 4
+c : XyZ
+c = hello (3 * 8)+
\ No newline at end of file