Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ranges always max inclusive #16

Merged
merged 3 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions docs/config/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ Suppose we are trying to send the health of a player over the remote. We may def

<CodeBlock code="type Health = u8 (0..100)" />

Although, the type assertions will fail if 100 is passed. This is because **only the lower limit is inclusive**. To fix this, we must append a `=` to the end of the upper bound such as

<CodeBlock code="type Data = u8 (0..=100)" />

This works because limits are **inclusive**, and will include 0 and 100.
## Strings

Unlike numbers, strings do not have a maximum length across different types. They can be any length unless they are constrained.
Expand Down
10 changes: 1 addition & 9 deletions zap/src/irgen/gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,15 +228,7 @@ fn range_check(stmts: &mut Vec<Stmt>, val: Expr, range: Range<f64>) {
}

if let Some(max) = range.max() {
assert(
stmts,
if range.max_inclusive() {
val.lte(max.into())
} else {
val.lt(max.into())
},
None,
);
assert(stmts, val.lte(max.into()), None);
}
}

Expand Down
11 changes: 4 additions & 7 deletions zap/src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -162,15 +162,12 @@ Ty: Ty = {
Range: Range<f64> = {
".." => Range::default(),

".." <max:Number> => Range::with_max(max, false),
"..=" <max:Number> => Range::with_max(max, true),
".." <max:Number> => Range::new(None, Some(max)),

<min:Number> ".." => Range::with_min(min),
<min:Number> ".." => Range::new(Some(min), None),

<min:Number> ".." <max:Number> => Range::new(Some(min), Some(max), false),
<min:Number> "..=" <max:Number> => Range::new(Some(min), Some(max), true),

<num:Number> => Range::new(Some(num), Some(num), true),
<num:Number> => Range::new(Some(num), Some(num)),
<min:Number> ".." <max:Number> => Range::new(Some(min), Some(max)),
}

Comma<T>: Vec<T> = {
Expand Down
52 changes: 5 additions & 47 deletions zap/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,11 @@ use crate::parser::Casing;
pub struct Range<T: Num + NumCast + Copy + Display> {
min: Option<T>,
max: Option<T>,
max_inclusive: bool,
}

impl<T: Num + NumCast + Copy + Display> Range<T> {
pub fn new(min: Option<T>, max: Option<T>, max_inclusive: bool) -> Self {
Self {
min,
max,
max_inclusive,
}
}

pub fn with_min(min: T) -> Self {
Self {
min: Some(min),
max: None,
max_inclusive: false,
}
}

pub fn with_max(max: T, max_inclusive: bool) -> Self {
Self {
min: None,
max: Some(max),
max_inclusive,
}
pub fn new(min: Option<T>, max: Option<T>) -> Self {
Self { min, max }
}

pub fn min(&self) -> Option<T> {
Expand All @@ -44,15 +23,10 @@ impl<T: Num + NumCast + Copy + Display> Range<T> {
self.max
}

pub fn max_inclusive(&self) -> bool {
self.max_inclusive
}

pub fn cast<U: Num + NumCast + Copy + Display>(self) -> Range<U> {
Range {
min: self.min.map(|x| NumCast::from(x).unwrap()),
max: self.max.map(|x| NumCast::from(x).unwrap()),
max_inclusive: self.max_inclusive,
}
}
}
Expand All @@ -77,32 +51,16 @@ impl<T: Num + NumCast + Copy + Display + PrimInt> Range<T> {

impl<T: Num + NumCast + Copy + Display> Default for Range<T> {
fn default() -> Self {
Self {
min: None,
max: None,
max_inclusive: false,
}
Self { min: None, max: None }
}
}

impl<T: Num + NumCast + Copy + Display> Display for Range<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match (self.min, self.max) {
(Some(min), Some(max)) => {
if self.max_inclusive {
write!(f, "{}..={}", min, max)
} else {
write!(f, "{}..{}", min, max)
}
}
(Some(min), Some(max)) => write!(f, "{}..{}", min, max),
(Some(min), None) => write!(f, "{}..", min),
(None, Some(max)) => {
if self.max_inclusive {
write!(f, "..={}", max)
} else {
write!(f, "..{}", max)
}
}
(None, Some(max)) => write!(f, "..{}", max),
(None, None) => write!(f, ".."),
}
}
Expand Down
Loading