Skip to content

Commit

Permalink
Rework the next/peek functions to allow null to be returned
Browse files Browse the repository at this point in the history
  • Loading branch information
irh committed Mar 1, 2024
1 parent 1c2e53e commit 7159fc6
Show file tree
Hide file tree
Showing 16 changed files with 355 additions and 205 deletions.
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,20 @@ The Koto project adheres to
- An overload has been added that accepts a number base between 2 and 36.
- If the string doesn't contain a number, `null` is now returned instead of an
exception being thrown.
- Objects can be compared with `null` on the LHS without having to implement
`KotoObject::equal` and/or `not_equal`.
- `map.with_meta_map` has been renamed to `with_meta`, and `get_meta_map` has
been renamed to `get_meta`.
- `iterator.next`/`next_back` and `Peekble.peek`/`peek_back` now return
`IteratorOutput` for output values, and `null` when the iterator is exhausted.
- `.get()` needs to be called on the output to get the underlying value.

#### API

- `Vm` has been renamed to `KotoVm` for the sake of clarity.
- `Value` has been renamed to `KValue` for consistency with the other core
runtime value types, and to avoid polluting the prelude with a generic name.
- The VM-specific parts of `KotoSettings` are now defined via `KotoVmSettings`.
- Objects can be compared with `null` on the LHS without having to implement
`KotoObject::equal` and/or `not_equal`.

#### Internals

Expand Down
1 change: 1 addition & 0 deletions crates/koto/tests/docs_examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ mod guide {
test_lang_guide_examples!(functions_advanced);
test_lang_guide_examples!(generators);
test_lang_guide_examples!(getting_started);
test_lang_guide_examples!(iterators);
test_lang_guide_examples!(lists);
test_lang_guide_examples!(loops);
test_lang_guide_examples!(maps);
Expand Down
69 changes: 60 additions & 9 deletions crates/runtime/src/core_lib/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod adaptors;
pub mod generators;
pub mod peekable;

use crate::{prelude::*, KIteratorOutput as Output, KotoVm, Result};
use crate::{derive::*, prelude::*, KIteratorOutput as Output, KotoVm, Result};

/// Initializes the `iterator` core library module
pub fn make_module() -> KMap {
Expand Down Expand Up @@ -529,7 +529,12 @@ pub fn make_module() -> KMap {
(_, unexpected) => return type_error_with_slice(expected_error, unexpected),
};

iter_output_to_result(iter.next())
let output = match iter_output_to_result(iter.next())? {
None => KValue::Null,
Some(output) => IteratorOutput::from(output).into(),
};

Ok(output)
});

result.add_fn("next_back", |ctx| {
Expand All @@ -541,7 +546,12 @@ pub fn make_module() -> KMap {
(_, unexpected) => return type_error_with_slice(expected_error, unexpected),
};

iter_output_to_result(iter.next_back())
let output = match iter_output_to_result(iter.next_back())? {
None => KValue::Null,
Some(output) => IteratorOutput::from(output).into(),
};

Ok(output)
});

result.add_fn("once", |ctx| match ctx.args() {
Expand Down Expand Up @@ -868,12 +878,53 @@ pub(crate) fn collect_pair(iterator_output: Output) -> Output {
}
}

pub(crate) fn iter_output_to_result(iterator_output: Option<Output>) -> Result<KValue> {
match iterator_output {
Some(Output::Value(value)) => Ok(value),
Some(Output::ValuePair(first, second)) => Ok(KValue::Tuple(vec![first, second].into())),
Some(Output::Error(error)) => Err(error),
None => Ok(KValue::Null),
pub(crate) fn iter_output_to_result(iterator_output: Option<Output>) -> Result<Option<KValue>> {
let output = match iterator_output {
Some(Output::Value(value)) => Some(value),
Some(Output::ValuePair(first, second)) => Some(KValue::Tuple(vec![first, second].into())),
Some(Output::Error(error)) => return Err(error),
None => None,
};

Ok(output)
}

/// The output type used by operations like `iterator.next()` and `next_back()`
#[derive(Clone, KotoCopy, KotoType)]
pub struct IteratorOutput(KValue);

#[koto_impl(runtime = crate)]
impl IteratorOutput {
/// Returns the wrapped output value
#[koto_method]
pub fn get(&self) -> KValue {
self.0.clone()
}
}

impl KotoObject for IteratorOutput {
fn display(&self, ctx: &mut DisplayContext) -> Result<()> {
ctx.append(Self::type_static());
ctx.append('(');

let mut wrapped_ctx = DisplayContext::default();
self.0.display(&mut wrapped_ctx)?;
ctx.append(wrapped_ctx.result());

ctx.append(')');
Ok(())
}
}

impl From<KValue> for IteratorOutput {
fn from(value: KValue) -> Self {
Self(value)
}
}

impl From<IteratorOutput> for KValue {
fn from(output: IteratorOutput) -> Self {
KObject::from(output).into()
}
}

Expand Down
30 changes: 17 additions & 13 deletions crates/runtime/src/core_lib/iterator/peekable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use koto_derive::*;

use super::iter_output_to_result;
use super::{iter_output_to_result, IteratorOutput};
use crate::{prelude::*, KIteratorOutput as Output, KotoVm, Result};

/// A double-ended peekable iterator for Koto
Expand Down Expand Up @@ -47,30 +47,34 @@ impl Peekable {

#[koto_method]
fn peek(&mut self) -> Result<KValue> {
match self.peeked_front.clone() {
Some(peeked) => Ok(peeked),
let peeked = match self.peeked_front.clone() {
Some(peeked) => peeked,
None => match iter_output_to_result(self.next())? {
KValue::Null => Ok(KValue::Null),
peeked => {
None => return Ok(KValue::Null),
Some(peeked) => {
self.peeked_front = Some(peeked.clone());
Ok(peeked)
peeked
}
},
}
};

Ok(IteratorOutput::from(peeked).into())
}

#[koto_method]
fn peek_back(&mut self) -> Result<KValue> {
match self.peeked_back.clone() {
Some(peeked) => Ok(peeked),
let peeked = match self.peeked_back.clone() {
Some(peeked) => peeked,
None => match iter_output_to_result(self.next_back())? {
KValue::Null => Ok(KValue::Null),
peeked => {
None => return Ok(KValue::Null),
Some(peeked) => {
self.peeked_back = Some(peeked.clone());
Ok(peeked)
peeked
}
},
}
};

Ok(IteratorOutput::from(peeked).into())
}
}

Expand Down
Loading

0 comments on commit 7159fc6

Please sign in to comment.