Add the current operator if it's not n-ary to the stack 'current_child' and it the operator to the stack.
( &self, parse_stack: &'s mut Vec<StackInfo<'a, 'op>>, current_child: Element<'a>, current_op: OperatorPair<'op>)
| 3409 | // Add the current operator if it's not n-ary to the stack |
| 3410 | // 'current_child' and it the operator to the stack. |
| 3411 | fn shift_stack<'s, 'a:'s, 'op:'a>( |
| 3412 | &self, parse_stack: &'s mut Vec<StackInfo<'a, 'op>>, |
| 3413 | current_child: Element<'a>, |
| 3414 | current_op: OperatorPair<'op>) -> (Element<'a>, OperatorPair<'op>) { |
| 3415 | let mut new_current_child = current_child; |
| 3416 | let mut new_current_op = current_op.clone(); |
| 3417 | let previous_op = top(parse_stack).op_pair.clone(); |
| 3418 | // debug!(" shift_stack: mrow len={}", top(parse_stack).mrow.children().len().to_string()); |
| 3419 | // debug!(" shift_stack: shift on '{}'; ops: prev '{}/{}', cur '{}/{}'", |
| 3420 | // element_summary(current_child),show_invisible_op_char(previous_op.ch), previous_op.op.priority, |
| 3421 | // show_invisible_op_char(current_op.ch), current_op.op.priority); |
| 3422 | if !current_op.op.is_nary(previous_op.op) { |
| 3423 | // grab operand on top of stack (if there is one) and make it part of the new mrow since current op has higher precedence |
| 3424 | // if operators are the same and are binary, then this push makes them act as left associative |
| 3425 | let mut top_of_stack = parse_stack.pop().unwrap(); |
| 3426 | if top_of_stack.mrow.children().is_empty() || (!top_of_stack.is_operand && !current_op.op.is_right_fence()) { |
| 3427 | // "bad" syntax - no operand on left -- don't grab operand (there is none) |
| 3428 | // just start a new mrow beginning with operator |
| 3429 | // FIX -- check this shouldn't happen: parse_stack.push(top_of_stack); |
| 3430 | parse_stack.push( top_of_stack ); // put top back on |
| 3431 | parse_stack.push( StackInfo::new(current_child.document()) ); |
| 3432 | } else if current_op.op.is_right_fence() { |
| 3433 | // likely, but not necessarily, there is a left fence to start the mrow |
| 3434 | // this is like the postfix case except we grab the entire mrow, push on the close, and make that the mrow |
| 3435 | // note: the code does these operations on the stack for consistency, but it could be optimized without push/popping the stack |
| 3436 | let mrow = top_of_stack.mrow; |
| 3437 | top_of_stack.add_child_to_mrow(current_child, current_op); |
| 3438 | // debug!("shift_stack: after adding right fence to mrow:\n{}", mml_to_string(&mrow)); |
| 3439 | new_current_op = OperatorPair::new(); // treat matched brackets as operand |
| 3440 | new_current_child = mrow; |
| 3441 | let children = mrow.children(); |
| 3442 | // debug!("looking for left fence: len={}, {:#?}", children.len(), self.find_operator(as_element(children[0]),None, None, Some(as_element(children[1])) )); |
| 3443 | if children.len() == 2 && (name(&as_element(children[0])) != "mo" || |
| 3444 | !self.find_operator(as_element(children[0]), |
| 3445 | None, Some(as_element(children[0])), Some(mrow) ).is_left_fence()) { |
| 3446 | // the mrow did *not* start with an open (hence no push) |
| 3447 | // since parser really wants balanced parens to keep stack state right, we do a push here |
| 3448 | parse_stack.push( StackInfo::new(mrow.document()) ); |
| 3449 | } else { |
| 3450 | // the mrow started with some open fence (which caused a push) -- add the close, pop, and push on the "operand" |
| 3451 | new_current_child = self.potentially_lift_script(mrow) |
| 3452 | } |
| 3453 | } else if current_op.op.is_postfix() { |
| 3454 | // grab the left operand and start a new mrow with it and the operator -- put those back on the stack |
| 3455 | // note: the code does these operations on the stack for consistency, but it could be optimized without push/popping the stack |
| 3456 | let previous_child = top_of_stack.remove_last_operand_from_mrow(); // remove operand from mrow |
| 3457 | parse_stack.push(top_of_stack); |
| 3458 | let mut new_top_of_stack = StackInfo::with_op(¤t_child.document(), previous_child, current_op.clone()); // begin new mrow with operand |
| 3459 | new_top_of_stack.add_child_to_mrow(current_child, current_op); // add on operator |
| 3460 | new_current_child = new_top_of_stack.mrow; // grab for pushing on old mrow |
| 3461 | new_current_op = OperatorPair::new(); // treat "reduced" postfix operator & operand as an operand |
| 3462 | // debug!("shift_stack: after adding postfix to mrow has len: {}", new_current_child.children().len().to_string()); |
| 3463 | } else { |
| 3464 | // normal infix op case -- grab the left operand and start a new mrow with it and the operator |
| 3465 | let previous_child = top_of_stack.remove_last_operand_from_mrow(); |
| 3466 | parse_stack.push(top_of_stack); |
| 3467 | parse_stack.push( StackInfo::with_op(¤t_child.document(),previous_child, current_op) ); |
| 3468 | } |
no test coverage detected