parsing modes
This commit is contained in:
parent
3b5bbb50d5
commit
7b33b0aa4a
@ -10,3 +10,4 @@
|
||||
- [RcChars](./exercises/rcchars.md)
|
||||
- [Chapter 2](./chapter_2.md)
|
||||
- [AnyStr](./exercises/anystr.md)
|
||||
- [Mode](./exercises/mode.md)
|
||||
|
@ -1 +1 @@
|
||||
# Chapter 2
|
||||
# Chapter 2: Missing Requirements
|
||||
|
@ -1,3 +1,5 @@
|
||||
# `AnyStr`?
|
||||
|
||||
Create something similar to [Python's `typing.AnyStr`].
|
||||
|
||||
[Python's `typing.AnyStr`]: https://docs.python.org/3/library/typing.html#typing.AnyStr
|
||||
|
@ -1,6 +1,8 @@
|
||||
Make `test_covariance` compile by making `BoolStream<'a>` covariant `'a`. Restrictions:
|
||||
# Introducing variance to objects
|
||||
|
||||
Make `test_covariance` compile by making `BoolStream<'a>` covariant over `'a`. Restrictions:
|
||||
- Can only change implementation details of `BoolStream` and its methods and add extra items outside of what's given, i.e. no signature/test change.
|
||||
- Changed version must behave the same way.
|
||||
- Changed version must behave the same way as the original.
|
||||
|
||||
Consider the following code:
|
||||
```rust,compile_fail
|
||||
|
72
src/exercises/mode.md
Normal file
72
src/exercises/mode.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Parsing modes
|
||||
Merge implementations of `ConsumesStream` and `Deterministic` for tuple.
|
||||
|
||||
It's recommended to first solve [this exercise](./multiple_blanket.md).
|
||||
|
||||
```rust
|
||||
trait Stream: Sized {
|
||||
/// Try to read `n` bytes. Consumes the stream on failure.
|
||||
fn read_n<A, E>(
|
||||
self,
|
||||
n: usize,
|
||||
ok: impl FnOnce(&[u8]) -> A,
|
||||
err: impl FnOnce(&[u8]) -> E,
|
||||
) -> Result<(A, Self), E>;
|
||||
|
||||
/// Read all bytes, consuming the stream.
|
||||
fn read_all<A>(self, ok: impl FnOnce(&[u8]) -> A) -> A;
|
||||
}
|
||||
|
||||
trait Parsable: Sized {
|
||||
type Error;
|
||||
}
|
||||
|
||||
/// Can parse any length of data.
|
||||
trait ConsumesStream: Parsable {
|
||||
/// Try to parse the value. Can handle EOF, can ask for all data the stream has.
|
||||
fn parse(stream: impl Stream) -> Result<Self, Self::Error>;
|
||||
|
||||
/// Push extra data into the value.
|
||||
fn extend(self, data: &[u8]) -> Result<Self, Self::Error>;
|
||||
}
|
||||
|
||||
/// Whether the parsing is terminated, is only determined by the data already parsed.
|
||||
trait Deterministic: Parsable {
|
||||
/// Returns the stream, as it shouldn't succeed on unexpected EOF.
|
||||
fn parse<S: Stream>(stream: S) -> Result<(Self, S), Self::Error>;
|
||||
|
||||
/// Always fail on extra data.
|
||||
fn fail(data: &[u8]) -> Self::Error;
|
||||
}
|
||||
|
||||
enum Either<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
impl<A: Parsable, B: Parsable> Parsable for (A, B) {
|
||||
type Error = Either<A::Error, B::Error>;
|
||||
}
|
||||
|
||||
impl<A: Deterministic, B: ConsumesStream> ConsumesStream for (A, B) {
|
||||
fn parse(stream: impl Stream) -> Result<Self, Self::Error> {
|
||||
let (a, stream) = A::parse(stream).map_err(Either::Left)?;
|
||||
B::parse(stream).map_err(Either::Right).map(|b| (a, b))
|
||||
}
|
||||
|
||||
fn extend(self, data: &[u8]) -> Result<Self, Self::Error> {
|
||||
self.1.extend(data).map_err(Either::Right).map(|b| (self.0, b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Deterministic, B: Deterministic> Deterministic for (A, B) {
|
||||
fn parse<S: Stream>(stream: S) -> Result<(Self, S), Self::Error> {
|
||||
let (a, stream) = A::parse(stream).map_err(Either::Left)?;
|
||||
B::parse(stream).map_err(Either::Right).map(|(b, stream)| ((a, b), stream))
|
||||
}
|
||||
|
||||
fn fail(data: &[u8]) -> Self::Error {
|
||||
Either::Right(B::fail(data))
|
||||
}
|
||||
}
|
||||
```
|
@ -1,13 +1,14 @@
|
||||
# Blanket, blanket, blanket
|
||||
Make this compile with the following restrictions:
|
||||
- `A1` doesn't know about/depend on `A2`.
|
||||
- `A2` doesn't know about/depend on `A1`.
|
||||
- `A1` doesn't know about/depend on `A`.
|
||||
- `A2` doesn't know about/depend on `A`.
|
||||
- **Can't edit definitions of `A`, `test`, `tes1`, `test2`; can only add code outside of those items.**
|
||||
- **Some types are `A1` but not `A2`.**
|
||||
- **Some types are `A2` but not `A1`.**
|
||||
- Some types are `A` but not `A2`.
|
||||
- Some types are `A` but not `A1`.
|
||||
- **Can't edit definitions of `A`, `test`, `tes1`, `test2`; can only add code outside of those items.**
|
||||
- `A1` doesn't know about/depend on `A2`.
|
||||
- `A2` doesn't know about/depend on `A1`.
|
||||
- `A1` doesn't know about/depend on `A`.
|
||||
- `A2` doesn't know about/depend on `A`.
|
||||
|
||||
```rust
|
||||
trait A {
|
||||
|
@ -1,3 +1,5 @@
|
||||
# Owned [`Chars`]
|
||||
|
||||
[`Chars`] but keeping a strong reference ([`Rc`]) to the string.
|
||||
|
||||
[`Chars`]: https://doc.rust-lang.org/std/str/struct.Chars.html
|
||||
@ -41,10 +43,10 @@
|
||||
```
|
||||
|
||||
## Solutions
|
||||
- [Solution] used in rattlescript.
|
||||
- [Implementation] used in rattlescript.
|
||||
- [Same solution] but with some extra comments.
|
||||
- [Another solution].
|
||||
|
||||
[Solution]: https://github.com/HavenSelph/rattlescript/blob/f8bafb8b063b9bf056efb1ea14188db0624d981c/src/interpreter/value.rs#L21-L50
|
||||
[Implementation]: https://github.com/HavenSelph/rattlescript/blob/f8bafb8b063b9bf056efb1ea14188db0624d981c/src/interpreter/value.rs#L21-L50
|
||||
[Same solution]: https://gist.github.com/timotheyca/7e46c9734653b2fcbe826ea4d13b9aa0
|
||||
[Another solution]: https://gist.github.com/timotheyca/bc419e0997d6f7ea5722fd2823a78c62
|
||||
|
@ -1,13 +1,13 @@
|
||||
# Exercises
|
||||
|
||||
Random Rust exercises.
|
||||
Random Rust exercises. Mostly typesystem-oriented.
|
||||
|
||||
**Warning: this is a live-edited website, errors and accidental spoilers are to be expected.**
|
||||
**Warning if you're viewing this not on github.io: this is a live-edited website, errors and accidental spoilers are to be expected.**
|
||||
|
||||
# Solutions
|
||||
|
||||
Currently solutions are mostly provided in a non-human-readable form in the page source.
|
||||
Those are mostly intended for testing that the exercise is even possible to solve.
|
||||
Presently, solutions are often provided in a non-human-readable (compacted+misformatted) form as hidden code.
|
||||
Those are intended for testing that the exercise is even possible to solve.
|
||||
```rust
|
||||
# /*
|
||||
fn fix_me() { // Greyed out because the solution changes this line.
|
||||
@ -19,7 +19,7 @@ fn do_not_change_this() {
|
||||
fixed_name()
|
||||
}
|
||||
```
|
||||
Some exercises may not include have the replaced parts greyed out:
|
||||
Some exercises may not have the replaced parts greyed out:
|
||||
```rust
|
||||
# mod __ {
|
||||
fn fix_me() {
|
||||
|
Loading…
Reference in New Issue
Block a user