Skip to content

Commit

Permalink
Refactor RpnStack to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
apesic committed Sep 16, 2020
1 parent 21c6b5d commit 108fa12
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 190 deletions.
194 changes: 4 additions & 190 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:url_launcher/url_launcher.dart';
import 'binary_operator_widget.dart';
import 'num_button_widget.dart';
import 'operators.dart';
import 'rpn_stack.dart';
import 'stack_item.dart';
import 'stack_item_widget.dart';

Expand All @@ -22,183 +23,6 @@ void main() {
runApp(const RpnCalc());
}

class RpnStack {
RpnStack() {
stack.add(EditableItem.blank());
}
RpnStack.clone(RpnStack source) {
// XXX need to deep copy items
stack.addAll(source.stack);
appendNew = source.appendNew;
}
final List<StackItem> stack = [];
// When true, the next append operation should create a new item.
bool appendNew = false;

int get length => stack.length;
StackItem get first => stack[0];
bool get isEmpty => length == 1 && first.isEmpty;

StackItem operator [](int i) => stack[i];

void _realizeStack() {
final first = this.first;
if (first is EditableItem) {
if (first.isEmpty) {
_pop();
} else {
stack[0] = first.realize();
}
}
assert(stack.every((element) => element is RealizedItem),
'Every element in stack should be realized.');
}

void push(StackItem v) {
stack.insert(0, v);
}

StackItem _pop() {
if (stack.isNotEmpty) {
return stack.removeAt(0);
}
return null;
}

void advance() {
_realizeStack();
push(EditableItem(stack[0]));
}

void drop() {
if (stack.length == 1) {
stack[0] = EditableItem.blank();
} else {
_pop();
}
}

void swap() {
if (stack.length < 2) {
return;
}
_realizeStack();
final first = stack[0];
final second = stack[1];
stack[0] = second;
stack[1] = first;
}

void rotateDown() {
if (stack.length < 2) {
return;
}
_realizeStack();
final first = _pop();
stack.add(first);
}

void rotateUp() {
if (stack.length < 2) {
return;
}
_realizeStack();
final last = stack.removeAt(stack.length - 1);
push(last);
}

void applyBinaryOperation(BinaryOperator o) {
if (stack.length < 2) {
return;
}
appendNew = true;
// If the first item is editable and empty , remove and skip the operation.
if (first.isEmpty) {
_pop();
return;
}
_realizeStack();
final fn = operations[o];
final b = _pop().value;
final a = _pop().value;
final res = fn(a, b);
push(RealizedItem(res));
}

void inverse() {
final v = first.value;
if (v != null && v != 0) {
stack[0] = RealizedItem(1 / v);
}
}

void reverseSign() {
final v = first.value;
stack[0] = RealizedItem(v * -1);
}

void percent() {
num res;
switch (stack.length) {
case 0:
return;
case 1:
res = _pop().value / 100;
break;
default:
res = (_pop().value / 100) * _pop().value;
break;
}
push(RealizedItem(res));
appendNew = true;
}

void clearCurrent() {
stack[0] = EditableItem.blank();
}

void appendCurrent(String c) {
final first = this.first;
EditableItem updated;
// Append new editable item.
if (first is EditableItem) {
// Update existing item.
first.appendChar(c);
} else if (appendNew) {
_realizeStack();
appendNew = false;
updated = EditableItem.blank()..appendChar(c);
push(updated);
} else if (first is RealizedItem) {
// Replace realized item with new editable item.
updated = EditableItem.blank()..appendChar(c);
stack[0] = updated;
}
}

void backspaceCurrent() {
final first = this.first;
if (first is RealizedItem) {
stack[0] = EditableItem(first)..removeChar();
} else if (first is EditableItem) {
first.removeChar();
}
}

void clearAll() {
stack.clear();
push(EditableItem.blank());
}

void remove(int index) {
stack.removeAt(index);
}

void replaceAt(int index, num newVal) {
stack[index] = RealizedItem(newVal);
}
}

class RpnCalc extends StatelessWidget {
const RpnCalc({Key key}) : super(key: key);
@override
Expand All @@ -220,22 +44,11 @@ class AppHome extends StatefulWidget {
_AppHomeState createState() => _AppHomeState();
}

const maxUndoBuffer = 5;

class _AppHomeState extends State<AppHome> {
RpnStack _stack = RpnStack();
// TODO improve undo implementation.
// TODO(alexei): improve undo implementation.
final List<RpnStack> _undoBuffer = [];

// void _onReorder(int oldIndex, newIndex) {
// setState(() {
// if (newIndex > oldIndex) {
// newIndex -= 1;
// }
// final num item = _stack.removeAt(oldIndex);
// _stack.insert(newIndex, item);
// });
// }
static const maxUndoBuffer = 5;

void _setStateWithUndo(Function f) {
setState(() {
Expand All @@ -253,6 +66,7 @@ class _AppHomeState extends State<AppHome> {
if (_undoBuffer.isEmpty) {
return;
}
HapticFeedback.selectionClick();
final prevState = _undoBuffer.removeAt(0);
_stack = prevState;
});
Expand Down
Loading

0 comments on commit 108fa12

Please sign in to comment.