Skip to content

Commit

Permalink
Move to Range over Pair for internals
Browse files Browse the repository at this point in the history
Adding drop support
  • Loading branch information
jdunkerley committed Feb 19, 2022
1 parent 6fb7be3 commit 340fc72
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,30 @@ Text.drop_last count =
boundary = iterator.next -count
if boundary == -1 then '' else Text_Utils.substring this 0 boundary

## PRIVATE
Utility function taking a range and getting char indices
range_to_char_indices : Text -> Range -> Range ! Index_Out_Of_Bounds_Error
range_to_char_indices text range:
len = text.length
start = if range.start < 0 then range.start + len - 1 else range.start
end = if range.end == Nothing then len-1 else (if range.end < 0 then range.end + len - 1 else range.end)
valid = (Range 0 len).contains

case (Pair (valid start) (valid end)) of
Pair False False -> Error.throw Index_Out_Of_Bounds_Error range_start len
Pair False True -> Error.throw Index_Out_Of_Bounds_Error range_start len
Pair True False -> Error.throw Index_Out_Of_Bounds_Error range_end len
Pair True True ->
if start>=end then (Range 0 0) else
iterator = BreakIterator.getCharacterInstance
iterator.setText text

loop index start_char end_char start_index =
if index == end then (Range start_index end_char) else
@Tail_Call loop (index + 1) end_char iterator.next (if index == start then start_char else start_index)

indices = loop 0 0 iterator.next Nothing

## ALIAS first, last, left, right, mid, substring
Creates a new Text by selecting the specified range of the input.

Expand Down Expand Up @@ -869,34 +893,53 @@ Text.drop_last count =
"Hello World!".take (After_Last "o") == "rld!"
"Hello World!".take (While c->c!=" ") == "Hello"
"Hello World!".take (Range 3 5) == "lo"
"Hello World!".take (Range -3) == "ld!"
"Hello World!".take (Range -3 Nothing) == "ld!"
Text.take : (Text_Sub_Range | Range) -> Text ! Index_Out_Of_Bounds_Error
Text.take range =
case range of
Range range_start range_end ->
len = this.length
start = if range_start < 0 then range_start + len - 1 else range_start
end = if range_end == Nothing then len-1 else (if range_end < 0 then range_end + len - 1 else range_end)
valid = (Range 0 len).contains

case (Pair (valid start) (valid end)) of
Pair False False -> Error.throw Index_Out_Of_Bounds_Error range_start len
Pair False True -> Error.throw Index_Out_Of_Bounds_Error range_start len
Pair True False -> Error.throw Index_Out_Of_Bounds_Error range_end len
Pair True True ->
if start>=end then "" else
iterator = BreakIterator.getCharacterInstance
iterator.setText this

loop index start_char end_char start_index =
if index == end then (Pair start_index end_char) else
@Tail_Call loop (index + 1) end_char iterator.next (if index == start then start_char else start_index)

indices = loop 0 0 iterator.next Nothing
Text_Utils.substring this indices.first indices.second
_ ->
indices = range.get_indices this
Text_Utils.substring this indices.first indices.second
char_range = case range of
Range _ _ -> here.range_to_char_indices this range
_ -> range.get_indices this
if char_range.is_error then char_range else
Text_Utils.substring this char_range.start char_range.end

## Creates a new Text by removing the specified range of the input.

This can select a section of text from the beginning, end, or middle of the
input using various criteria defined by the range parameter.

Arguments:
- range: The section of the this text to return.
If a `Text_Sub_Range`, then the selection is interpreted following the rules of that type.
If a `Range`, the selection is specified by two indices, from and to.

Returns:
The part of the input as specified by the range parameter.

> Examples
Various different ways to take part of "Hello World!"

"Hello World!".drop First == "ello World!"
"Hello World!".drop (First 5) == " World!"
"Hello World!".drop (First 0) == "Hello World!"
"Hello World!".drop Last == "Hello World"
"Hello World!".drop (Last 6) == "Hello "
"Hello World!".drop (Before " ") == " World!"
"Hello World!".drop (Before_Last "o") == "orld!"
"Hello World!".drop (After " ") == "Hello "
"Hello World!".drop (After_Last "o") == "Hello Wo"
"Hello World!".drop (While c->c!=" ") == " World!"
"Hello World!".drop (Range 3 5) == "Hel World!"
"Hello World!".drop (Range -3 Nothing) == "Hello Wor"
Text.drop : (Text_Sub_Range | Range) -> Text ! Index_Out_Of_Bounds_Error
Text.drop range =
char_range = case range of
Range _ _ -> here.range_to_char_indices this range
_ -> range.get_indices this
if char_range.is_error then char_range else
if char_range.start == 0 then Text_Utils.drop_first this char_range.end else
prefix = Text_Utils.substring this 0 char_range.start
if char_range.end == (Text_Utils.char_length this) then prefix else
prefix + Text_Utils.drop_first this char_range.end

## ALIAS Lower Case

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ type Text_Sub_Range

## PRIVATE
Evaluates the Text_Sub_Range returning the underlying char array indices
get_indices : Text -> Pair
get_indices text =
to_char_range : Text -> Range
to_char_range text =

## Utility function to find char indices for Text_Sub_Range.
Arguments:
Expand All @@ -65,36 +65,36 @@ type Text_Sub_Range

case this of
First count ->
if count <= 0 then (Pair 0 0) else
if count <= 0 then (Range 0 0) else
indices = find_sub_range_end text (index->_->_-> index+1 == count)
Pair 0 indices.second
Range 0 indices.second
Last count ->
if count <= 0 then (Pair 0 0) else
if count <= 0 then (Range 0 0) else
first_count = text.length - count
indices = find_sub_range_end text (index->_->_-> index+1 == first_count)
if indices.first == -1 then (Pair 0 indices.second) else
(Pair indices.second (Text_Utils.char_length text))
if indices.first == -1 then (Range 0 indices.second) else
(Range indices.second (Text_Utils.char_length text))
Before delimiter ->
if delimiter.is_empty then (Pair 0 0) else
if delimiter.is_empty then (Range 0 0) else
index = Text_Utils.index_of text delimiter
if index == -1 then (Pair 0 (Text_Utils.char_length text)) else
(Pair 0 index)
if index == -1 then (Range 0 (Text_Utils.char_length text)) else
(Range 0 index)
Before_Last delimiter ->
if delimiter.is_empty then (Pair 0 0) else
if delimiter.is_empty then (Range 0 0) else
index = Text_Utils.last_index_of text delimiter
if index == -1 then (Pair 0 (Text_Utils.char_length text)) else
(Pair 0 index)
if index == -1 then (Range 0 (Text_Utils.char_length text)) else
(Range 0 index)
After delimiter ->
if delimiter.is_empty then (Pair 0 0) else
if delimiter.is_empty then (Range 0 0) else
index = Text_Utils.index_of text delimiter
if index == -1 then (Pair 0 (Text_Utils.char_length text)) else
(Pair (index + Text_Utils.char_length delimiter) (Text_Utils.char_length text))
if index == -1 then (Range 0 (Text_Utils.char_length text)) else
(Range (index + Text_Utils.char_length delimiter) (Text_Utils.char_length text))
After_Last delimiter ->
if delimiter.is_empty then (Pair 0 0) else
if delimiter.is_empty then (Range 0 0) else
index = Text_Utils.last_index_of text delimiter
if index == -1 then (Pair 0 (Text_Utils.char_length text)) else
(Pair (index + Text_Utils.char_length delimiter) (Text_Utils.char_length text))
if index == -1 then (Range 0 (Text_Utils.char_length text)) else
(Range (index + Text_Utils.char_length delimiter) (Text_Utils.char_length text))
While predicate ->
wrapped start end = predicate (Text_Utils.substring text start end) . not
indices = find_sub_range_end text (_->wrapped)
Pair 0 indices.second
Range 0 indices.second

0 comments on commit 340fc72

Please sign in to comment.