hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit f679ee1c3a82b2b0b2612e1c38859ff0039f7742
parent 76af771721b0fc611633b2c97b1f0e9bfdcb33e7
Author: Alexey Yerin <yyp@disroot.org>
Date:   Sun,  7 Nov 2021 15:00:55 +0300

shlex: fix whitespace folding

Previously this caused split("hello '' world") to return
["hello", "world"] without the empty string in between.

Signed-off-by: Alexey Yerin <yyp@disroot.org>

Diffstat:
Mshlex/+test.ha | 7+++++++
Mshlex/split.ha | 42++++++++++++++++++++++++++++++++----------
2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/shlex/+test.ha b/shlex/+test.ha @@ -19,6 +19,13 @@ assert(len(s) == 1); assert(s[0] == "hello \"world\""); + const s = split("hello '' world")!; + defer splitfree(s); + assert(len(s) == 3); + assert(s[0] == "hello"); + assert(s[1] == ""); + assert(s[2] == "world"); + const s = split("with\\ backslashes 'single quoted' \"double quoted\"")!; defer splitfree(s); assert(len(s) == 3); diff --git a/shlex/split.ha b/shlex/split.ha @@ -24,19 +24,28 @@ export fn split(in: const str) ([]str | syntaxerr) = { }; switch (r) { - case '\\' => - scan_backslash(s, in)?; - case '"' => - scan_double(s, in)?; - case '\'' => - scan_single(s, in)?; case ' ', '\t', '\n' => - if (len(strio::string(s)) > 0) { - append(slice, strio::finish(s)); - s = strio::dynamic(); + let r = :out { + for (true) match (bufio::scanrune(in)!) { + case r: rune => + if (r != ' ' && r != '\t' && r != '\n') { + yield :out, r; + }; + case io::EOF => + yield :out, void; + }; + abort(); // Unreachable + }; + append(slice, strio::finish(s)); + s = strio::dynamic(); + + match (r) { + case void => void; + case r: rune => + process(s, in, r)?; }; case => - strio::appendrune(s, r)!; + process(s, in, r)?; }; }; @@ -48,6 +57,19 @@ export fn split(in: const str) ([]str | syntaxerr) = { return slice; }; +fn process(out: io::handle, in: io::handle, r: rune) (void | syntaxerr) = { + switch (r) { + case '\\' => + scan_backslash(out, in)?; + case '"' => + scan_double(out, in)?; + case '\'' => + scan_single(out, in)?; + case => + strio::appendrune(out, r)!; + }; +}; + fn scan_backslash(out: io::handle, in: io::handle) (void | syntaxerr) = { const r = match (bufio::scanrune(in)!) { case r: rune =>