Skip to content

Commit cee0539

Browse files
author
ynn
committed
fix(in(number), in(char) command)!: fixes the way how stdin is read, making it more intuitive (#3)
1 parent b390b19 commit cee0539

File tree

5 files changed

+312
-51
lines changed

5 files changed

+312
-51
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ Dockerfile
1313
TODO.md
1414

1515
*.sh
16+
17+
#used for temporal testing while development
18+
src/bin/

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,45 @@ Practically, when the depth (i.e. the second top entry of a stack) is larger tha
120120

121121
> *Any operations which cannot be performed (such as popping values when not enough are on the stack) are simply ignored, and processing continues with the next command.*
122122
123-
### 3.8 `out(char)` command
123+
### 3.8 `in(number)`, `in(char)` command
124+
125+
The spec is vague about how to determine number/character boundaries; it only states:
126+
127+
> Reads a value from STDIN as either a number or character
128+
129+
> Data values exist only as integers, though they may be read in or printed as Unicode character values with appropriate commands.
130+
131+
Practically, we assume that, when users want to input a series of numbers, they would separate them by whitespace (e.g. `1 -2 -3`, `1\n-2\n-3`, etc.) though lining up numbers without whitespace is also theoretically possible (e.g. `123-5-6` may be interpreted as `[123, -5, -6]`, which is [how `std::cin` works in C++](https://wandbox.org/permlink/g1Kw3zdCA6RF3OoP)).
132+
133+
On the other hand, when users want to input a string, they typically do not want to ignore whitespace (e.g. `Hello, world!\n` should be read as is) though skipping whitespace is also theoretically possible (e.g. `a b c` may be interpreted as `['a', 'b', 'c']`, which is [how `std::cin` works in C++](https://wandbox.org/permlink/biiOtNLhCX77cs1x)).
134+
135+
To support both use-cases, we adopt the following implementation:
136+
137+
- `in(char)` literally reads the next Unicode character, including whitespace.
138+
139+
- `in(number)` reads the longest match of the (pseudo) regex `[ \t\n]*<non_blank_word>[ \t]*\n?`, where `<non_blank_word>` is defined as a sequence of non-whitespace characters.
140+
141+
- The reason that trailing whitespace is also consumed is to let `in(number)` followed by `in(char)` read `100` and `h` respectively from the stdin `100 hello`.
142+
143+
- The reasons that the consumption stops at the first newline are:
144+
145+
- Users may want to read integers on one line and then read the next line as it is as a string (including whitespace).
146+
147+
- If we don't stop at the first newline, then the command would wait indefinitely until it reaches EOF or a non whitespace character, which is especially problematic when the stdin is [canonical](https://stackoverflow.com/questions/358342/canonical-vs-non-canonical-terminal-input).
148+
149+
For example,
150+
151+
- if stdin contains `\n\n 123 hello`, then `in(number)` consumes `\n\n 123 ` and leaves `hello`
152+
153+
- if stdin contains `-5 \n hello`, then `in(number)` consumes `-5 \n` and leaves ` hello`
154+
155+
### 3.9 `out(char)` command
124156

125157
When the top entry of a stack exceeds the range `[0, char::MAX]` (i.e. when it isn't a valid Unicode character), the command is simply ignored according to
126158

127159
> *Any operations which cannot be performed (such as popping values when not enough are on the stack) are simply ignored, and processing continues with the next command.*
128160
129-
### 3.9 Commands
161+
### 3.10 Commands
130162

131163
Some important implementation details:
132164

src/command.rs

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -736,47 +736,94 @@ mod tests {
736736
let f = |v: Vec<char>| -> Vec<isize> { v.into_iter().map(|c| c as isize).collect_vec() };
737737

738738
command.execute(&mut ip, 1);
739-
assert_eq!(f(vec!['-']), ip.stack);
739+
assert_eq!(f(vec![' ']), ip.stack);
740740

741741
command.execute(&mut ip, 1);
742-
assert_eq!(f(vec!['-', '1']), ip.stack);
742+
assert_eq!(f(vec![' ', '-']), ip.stack);
743743

744744
command.execute(&mut ip, 1);
745-
assert_eq!(f(vec!['-', '1', 'a']), ip.stack);
745+
assert_eq!(f(vec![' ', '-', '1']), ip.stack);
746746

747747
command.execute(&mut ip, 1);
748-
assert_eq!(f(vec!['-', '1', 'a', '🌷']), ip.stack);
748+
assert_eq!(f(vec![' ', '-', '1', ' ']), ip.stack);
749749

750750
command.execute(&mut ip, 1);
751-
assert_eq!(f(vec!['-', '1', 'a', '🌷', '🍄']), ip.stack);
751+
assert_eq!(f(vec![' ', '-', '1', ' ', 'a']), ip.stack);
752752

753753
command.execute(&mut ip, 1);
754-
assert_eq!(f(vec!['-', '1', 'a', '🌷', '🍄', 'a']), ip.stack);
754+
assert_eq!(f(vec![' ', '-', '1', ' ', 'a', ' ']), ip.stack);
755755

756756
command.execute(&mut ip, 1);
757-
assert_eq!(f(vec!['-', '1', 'a', '🌷', '🍄', 'a', '🍄']), ip.stack);
757+
assert_eq!(f(vec![' ', '-', '1', ' ', 'a', ' ', '🌷']), ip.stack);
758+
759+
command.execute(&mut ip, 1);
760+
assert_eq!(f(vec![' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄']), ip.stack);
761+
762+
command.execute(&mut ip, 1);
763+
assert_eq!(
764+
f(vec![' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ']),
765+
ip.stack
766+
);
767+
768+
command.execute(&mut ip, 1);
769+
assert_eq!(
770+
f(vec![' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a']),
771+
ip.stack
772+
);
773+
774+
command.execute(&mut ip, 1);
775+
assert_eq!(
776+
f(vec![
777+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄'
778+
]),
779+
ip.stack
780+
);
781+
782+
command.execute(&mut ip, 1);
783+
assert_eq!(
784+
f(vec![
785+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' '
786+
]),
787+
ip.stack
788+
);
789+
790+
command.execute(&mut ip, 1);
791+
assert_eq!(
792+
f(vec![
793+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' ', '🍄'
794+
]),
795+
ip.stack
796+
);
758797

759798
command.execute(&mut ip, 1);
760799
assert_eq!(
761-
f(vec!['-', '1', 'a', '🌷', '🍄', 'a', '🍄', '🍄']),
800+
f(vec![
801+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' ', '🍄', 'a'
802+
]),
762803
ip.stack
763804
);
764805

765806
command.execute(&mut ip, 1);
766807
assert_eq!(
767-
f(vec!['-', '1', 'a', '🌷', '🍄', 'a', '🍄', '🍄', 'a']),
808+
f(vec![
809+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' ', '🍄', 'a', ' '
810+
]),
768811
ip.stack
769812
);
770813

771814
for _ in 0..2 {
772815
command.execute(&mut ip, 1);
773816
assert_eq!(
774-
f(vec!['-', '1', 'a', '🌷', '🍄', 'a', '🍄', '🍄', 'a']),
817+
f(vec![
818+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' ', '🍄', 'a', ' '
819+
]),
775820
ip.stack
776821
);
777822
command.execute(&mut ip, 1);
778823
assert_eq!(
779-
f(vec!['-', '1', 'a', '🌷', '🍄', 'a', '🍄', '🍄', 'a']),
824+
f(vec![
825+
' ', '-', '1', ' ', 'a', ' ', '🌷', '🍄', ' ', 'a', '🍄', ' ', '🍄', 'a', ' '
826+
]),
780827
ip.stack
781828
);
782829
}

0 commit comments

Comments
 (0)