MCPcopy Create free account
hub / github.com/daisy/MathCAT / shift_stack

Method shift_stack

src/canonicalize.rs:3411–3471  ·  view source on GitHub ↗

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>)

Source from the content-addressed store, hash-verified

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(&current_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(&current_child.document(),previous_child, current_op) );
3468 }

Callers 1

Calls 15

topFunction · 0.85
nameFunction · 0.85
as_elementFunction · 0.85
is_naryMethod · 0.80
is_emptyMethod · 0.80
is_right_fenceMethod · 0.80
add_child_to_mrowMethod · 0.80
lenMethod · 0.80
is_left_fenceMethod · 0.80
find_operatorMethod · 0.80
is_postfixMethod · 0.80

Tested by

no test coverage detected