ed

[hare] The standard editor
Log | Files | Refs | README | LICENSE

commit d2b6e43d61fc8fb96290ab84f4cb7505e703b041
parent c6c939e39da87ef9e4e3627a2fd7819de2c6adc9
Author: Byron Torres <b@torresjrjr.com>
Date:   Fri,  5 Jan 2024 23:21:27 +0000

progress

Diffstat:
MMakefile | 1+
Maddress.ha | 4++--
Mbuffer.ha | 5+++++
Mcommand.ha | 146+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mexecute.ha | 29+++++++++++++----------------
Ainteraction.ha | 23+++++++++++++++++++++++
Mmain.ha | 72++++++++++++++++++++++++++++++++++++++++++------------------------------
Mparse.ha | 37++++++++++++++++++++-----------------
Mutil.ha | 2+-
9 files changed, 194 insertions(+), 125 deletions(-)

diff --git a/Makefile b/Makefile @@ -6,6 +6,7 @@ source=\ address.ha \ buffer.ha \ command.ha \ + interaction.ha \ parse.ha \ util.ha \ diff --git a/address.ha b/address.ha @@ -1,12 +1,12 @@ use regex; type Address = struct { - addrtype: AddressType, + addrform: AddressForm, lineoffset: int, setcurrentline: bool, }; -type AddressType = (size | CurrentLine | LastLine | rune | RegexAddr); +type AddressForm = (size | CurrentLine | LastLine | rune | RegexAddr); // The dot '.' address. type CurrentLine = void; diff --git a/buffer.ha b/buffer.ha @@ -18,6 +18,11 @@ type Line = struct { globalmark: bool, }; +fn buffer_finish(buf: *Buffer) void = { + free(buf.filename); + // TODO: free other fields? +}; + fn buf_insert(buf: *Buffer, n: size, ls: *Line...) void = { debug("buf_insert(n={}), len(ls)={}", n, len(ls)); // for (let i = 0z; i < len(ls); i += 1) { diff --git a/command.ha b/command.ha @@ -14,7 +14,7 @@ type Command = struct { linenums: []size, cmdname: rune, printmode: PrintMode, - arg: str, + arg1: str, arg2: str, arg3: str, input: []str, @@ -52,6 +52,22 @@ type BufferModified = !void; type NoPrevShCmd = !void; +fn command_finish(cmd: *Command) void = { + debug("command_finish(): delete(cmd.linenums[..])"); + delete(cmd.linenums[..]); + debug("command_finish(): free(cmd.arg1)"); + free(cmd.arg1); + debug("command_finish(): free(cmd.arg2)"); + free(cmd.arg2); + debug("command_finish(): free(cmd.arg3)"); + free(cmd.arg3); + debug("command_finish(): delete(cmd.input[..])"); + delete(cmd.input[..]); + debug("command_finish(): END"); + // TODO: free other fields? + // TODO: make a separate "fn command_clear()" ? probably not +}; + fn lookupcmd(name: rune) CommandFn = { switch (name) { case 'a' => return &cmd_append; @@ -94,7 +110,7 @@ fn cmd_append(s: *Session, cmd: *Command) (void | Error) = { for (let i = 0z; i < len(cmd.input); i += 1) { const l = alloc(Line { text = cmd.input[i], ... }); debug("cmd_append(): l.text={}", l.text); - buf_insert(&s.buf, n + 1 + i, l); + buf_insert(s.buf, n + 1 + i, l); }; s.buf.cursor = n + len(cmd.input); @@ -114,12 +130,12 @@ fn cmd_change(s: *Session, cmd: *Command) (void | Error) = { }; }; - buf_delete(&s.buf, a, b); + buf_delete(s.buf, a, b); for (let i = 0z; i < len(cmd.input); i += 1) { const l = alloc(Line { text = cmd.input[i], ... }); debug("cmd_append(): l.text={}", l.text); - buf_insert(&s.buf, a + i, l); + buf_insert(s.buf, a + i, l); }; s.buf.cursor = if (len(cmd.input) == 0) { @@ -142,7 +158,7 @@ fn cmd_delete(s: *Session, cmd: *Command) (void | Error) = { )?; assert_nonzero(s, a)?; - buf_delete(&s.buf, a, b); + buf_delete(s.buf, a, b); s.buf.cursor = if (len(s.buf.lines) == 1) { yield 0; } else if (len(s.buf.lines) == a) { @@ -160,9 +176,10 @@ fn cmd_edit(s: *Session, cmd: *Command) (void | Error) = { return BufferModified; }; - const fname = if (len(cmd.arg) != 0) { - s.buf.filename = cmd.arg; - yield cmd.arg; + const fname = if (len(cmd.arg1) != 0) { + //free(s.buf.filename); + s.buf.filename = strings::dup(cmd.arg1); + yield cmd.arg1; } else if (len(s.buf.filename) != 0) { yield s.buf.filename; } else { @@ -177,8 +194,8 @@ fn cmd_edit(s: *Session, cmd: *Command) (void | Error) = { }; defer io::close(h)!; - buf_deleteall(&s.buf); - const (sz, _) = buf_read(&s.buf, h, 0)?; + buf_deleteall(s.buf); + const (sz, _) = buf_read(s.buf, h, 0)?; if (!s.suppressmode) { fmt::println(sz)!; }; @@ -189,10 +206,14 @@ fn cmd_edit_forced(s: *Session, cmd: *Command) (void | Error) = void; fn cmd_filename(s: *Session, cmd: *Command) (void | Error) = { assert_noaddrs(s, cmd.linenums)?; - if (len(cmd.arg) != 0) { - s.buf.filename = cmd.arg; - }; - if (len(s.buf.filename) == 0) { + if (cmd.arg1 != "") { + //debug("cmd_filename(): cmd.arg1 != 0"); + //free(s.buf.filename); + //debug("cmd_filename(): freed"); + debug("cmd_filename(): s.buf.filename = dup(cmd.arg1)"); + s.buf.filename = strings::dup(cmd.arg1); + }; + if (s.buf.filename == "") { return NoFilename; }; fmt::println(s.buf.filename)!; @@ -202,8 +223,8 @@ fn cmd_global(s: *Session, cmd: *Command) (void | Error) = { const (a, b) = get_range( s, &cmd.linenums, - addr_linenum(&s.buf, 1)?, - addr_lastline(&s.buf), + addr_linenum(s.buf, 1)?, + addr_lastline(s.buf), )?; assert_nonzero(s, a)?; @@ -214,11 +235,11 @@ fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = { const (a, b) = get_range( s, &cmd.linenums, - addr_linenum(&s.buf, 1)?, - addr_lastline(&s.buf), + addr_linenum(s.buf, 1)?, + addr_lastline(s.buf), )?; assert_nonzero(s, a)?; - const regex = regex::compile(cmd.arg)?; defer regex::finish(&regex); + const regex = regex::compile(cmd.arg1)?; defer regex::finish(&regex); for (let i = a; i <= b; i += 1) { const line = s.buf.lines[i]; @@ -245,17 +266,23 @@ fn cmd_global_interative(s: *Session, cmd: *Command) (void | Error) = { let cmd = Command { ... }; - const rawinput = match (bufio::read_line(os::stdin)?) { - case let bs: []u8 => - yield bs; - case io::EOF => - abort(); // TODO: ? - }; - defer free(rawinput); - const input = strings::fromutf8(rawinput)!; + // const rawinput = match (bufio::read_line(os::stdin)?) { + // case let bs: []u8 => + // yield bs; + // case io::EOF => + // return UnexpectedEOF; + // }; + // defer free(rawinput); + // const input = strings::fromutf8(rawinput)?; + const input = scanline(s)?; parse(&cmd, input)?; execute(s, &cmd)?; + + // TODO: test if line was modified. + // TODO: make cmd_ functions save to session whether line was + // modified, instead of here? + line.globalmark = false; }; }; @@ -281,7 +308,7 @@ fn cmd_insert(s: *Session, cmd: *Command) (void | Error) = { for (let i = 0z; i < len(cmd.input); i += 1) { const l = alloc(Line { text = cmd.input[i], ... }); debug("cmd_append(): l.text={}", l.text); - buf_insert(&s.buf, n + i, l); + buf_insert(s.buf, n + i, l); }; s.buf.cursor = if (len(cmd.input) == 0) { @@ -296,7 +323,7 @@ fn cmd_join(s: *Session, cmd: *Command) (void | Error) = { s, &cmd.linenums, s.buf.cursor, - addr_nextline(&s.buf, s.buf.cursor), + addr_nextline(s.buf, s.buf.cursor), )?; assert_nonzero(s, a)?; @@ -321,8 +348,8 @@ fn cmd_join(s: *Session, cmd: *Command) (void | Error) = { ... }); - buf_delete(&s.buf, a, b); - buf_insert(&s.buf, a, newline); + buf_delete(s.buf, a, b); + buf_insert(s.buf, a, newline); }; fn cmd_mark(s: *Session, cmd: *Command) (void | Error) = { @@ -332,7 +359,7 @@ fn cmd_mark(s: *Session, cmd: *Command) (void | Error) = { // TODO: this should use ".suffix", not ".arg", and parse() should // handle this // TODO: check len, etc... - const mark = strings::torunes(cmd.arg)[0]; + const mark = strings::torunes(cmd.arg1)[0]; debug("cmd_mark(): mark={}", mark); :search { @@ -372,7 +399,7 @@ fn cmd_list(s: *Session, cmd: *Command) (void | Error) = { assert_nonzero(s, a)?; debug("cmd_list(): (a, b)=({}, {})", a, b); - printlistlns(&s.buf, a, b)?; + printlistlns(s.buf, a, b)?; s.buf.cursor = b; }; @@ -386,7 +413,7 @@ fn cmd_move(s: *Session, cmd: *Command) (void | Error) = { assert_nonzero(s, a)?; // TODO: parse this properly in parse.ha? - const iter = strings::iter(cmd.arg); + const iter = strings::iter(cmd.arg1); const n = match (scan_addr(&iter)) { case let addr: Address => const n = match (exec_addr(s, addr)) { @@ -415,9 +442,9 @@ fn cmd_move(s: *Session, cmd: *Command) (void | Error) = { yield n; }; - const ls = alloc(s.buf.lines[a..b+1]...); defer free(ls); - buf_delete(&s.buf, a, b); - buf_insert(&s.buf, dest, ls...); + const ls = alloc(s.buf.lines[a..b+1]...); defer free(ls); // TODO: ? + buf_delete(s.buf, a, b); + buf_insert(s.buf, dest, ls...); s.buf.cursor = dest - 1 + len(ls); }; @@ -430,9 +457,9 @@ fn cmd_number(s: *Session, cmd: *Command) (void | Error) = { s.buf.cursor, )?; assert_nonzero(s, a)?; - debug("cmd_number(): (a, b)=({}, {})", a, b); + //debug("cmd_number(): (a, b)=({}, {})", a, b); - printnumberlns(&s.buf, a, b)?; + printnumberlns(s.buf, a, b)?; s.buf.cursor = b; }; @@ -445,7 +472,7 @@ fn cmd_print(s: *Session, cmd: *Command) (void | Error) = { )?; assert_nonzero(s, a)?; - printlns(&s.buf, a, b)?; + printlns(s.buf, a, b)?; s.buf.cursor = b; }; @@ -460,9 +487,9 @@ fn cmd_quit_forced(s: *Session, cmd: *Command) (void | Error) = void; fn cmd_read(s: *Session, cmd: *Command) (void | Error) = { const n = get_linenum(cmd.linenums, s.buf.cursor); - const fname = if (len(cmd.arg) != 0) { - s.buf.filename = cmd.arg; - yield cmd.arg; + const fname = if (len(cmd.arg1) != 0) { + s.buf.filename = cmd.arg1; + yield cmd.arg1; } else { yield if (len(s.buf.filename) != 0) { yield s.buf.filename; @@ -474,7 +501,7 @@ fn cmd_read(s: *Session, cmd: *Command) (void | Error) = { const h = os::open(fname)?: io::handle; defer io::close(h)!; - const (sz, _) = buf_read(&s.buf, h, n)?; + const (sz, _) = buf_read(s.buf, h, n)?; if (!s.suppressmode) { fmt::println(sz)!; }; @@ -491,7 +518,7 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = { assert_nonzero(s, a)?; const replacement = cmd.arg2; - const regex = regex::compile(cmd.arg)?; defer regex::finish(&regex); + const regex = regex::compile(cmd.arg1)?; defer regex::finish(&regex); for (let i = a; i <= b; i += 1) { const old = s.buf.lines[i].text; @@ -522,8 +549,8 @@ fn cmd_substitute(s: *Session, cmd: *Command) (void | Error) = { ... }); - buf_delete(&s.buf, i, i); - buf_insert(&s.buf, i, newline); + buf_delete(s.buf, i, i); + buf_insert(s.buf, i, newline); }; }; @@ -537,7 +564,7 @@ fn cmd_copy(s: *Session, cmd: *Command) (void | Error) = { assert_nonzero(s, a)?; // TODO: parse this properly in parse.ha? - const iter = strings::iter(cmd.arg); + const iter = strings::iter(cmd.arg1); const dest = match (scan_addr(&iter)) { case let addr: Address => yield 1 + (match (exec_addr(s, addr)) { @@ -551,8 +578,8 @@ fn cmd_copy(s: *Session, cmd: *Command) (void | Error) = { }; debug("cmd_copy(): dest={}", dest); - const ls = alloc(s.buf.lines[a..b+1]...); defer free(ls); - buf_insert(&s.buf, dest, ls...); + const ls = alloc(s.buf.lines[a..b+1]...); defer free(ls); // TODO: ? + buf_insert(s.buf, dest, ls...); s.buf.cursor = dest - 1 + len(ls); }; @@ -567,14 +594,15 @@ fn cmd_write(s: *Session, cmd: *Command) (void | Error) = { const (a, b) = get_range( s, &cmd.linenums, - addr_linenum(&s.buf, 1)?, - addr_lastline(&s.buf), + addr_linenum(s.buf, 1)?, + addr_lastline(s.buf), )?; assert_nonzero(s, a)?; - const fname = if (len(cmd.arg) != 0) { - s.buf.filename = cmd.arg; - yield cmd.arg; + const fname = if (len(cmd.arg1) != 0) { + // free(s.buf.filename); + s.buf.filename = strings::dup(cmd.arg1); + yield s.buf.filename; } else { yield if (len(s.buf.filename) != 0) { yield s.buf.filename; @@ -596,19 +624,19 @@ fn cmd_write(s: *Session, cmd: *Command) (void | Error) = { }; defer io::close(h)!; - const sz = buf_write(&s.buf, h, a, b)?; + const sz = buf_write(s.buf, h, a, b)?; if (!s.suppressmode) { fmt::println(sz)!; }; }; fn cmd_linenumber(s: *Session, cmd: *Command) (void | Error) = { - const n = get_linenum(cmd.linenums, addr_lastline(&s.buf)); + const n = get_linenum(cmd.linenums, addr_lastline(s.buf)); fmt::println(n)!; }; fn cmd_shellescape(s: *Session, cmd: *Command) (void | Error) = { - let iter = strings::iter(cmd.arg); + let iter = strings::iter(cmd.arg1); let new = memio::dynamic(); defer io::close(&new)!; let preview = false; @@ -674,7 +702,7 @@ fn cmd_shellescape(s: *Session, cmd: *Command) (void | Error) = { fn cmd_null(s: *Session, cmd: *Command) (void | Error) = { const n = get_linenum( cmd.linenums, - addr_nextline(&s.buf, s.buf.cursor), + addr_nextline(s.buf, s.buf.cursor), ); assert_nonzero(s, n)?; diff --git a/execute.ha b/execute.ha @@ -1,36 +1,33 @@ // Executes the Session's .cmd Command. -fn execute(s: *Session, cmd: *Command) (void | CmdError) = { +fn execute(s: *Session, cmd: *Command) (void | Error) = { // TODO: move this into the cmd_* functions? match (exec_addrs(s, cmd)) { case void => void; case let err: CmdError => - delete(cmd.linenums[..]); errormsg(s, err); return err; }; - // TODO: write finish_cmd() - // TODO: finish the Command at a higher level (main()) ?. - defer delete(cmd.linenums[..]); match (lookupcmd(cmd.cmdname)(s, cmd)) { case void => void; - case let err: CmdError => + case let err: Error => errormsg(s, err); return err; }; + debug("execute(): end"); }; fn exec_addrs(s: *Session, cmd: *Command) (void | CmdError) = { for (let i = 0z; i < len(cmd.addrs); i += 1) { const addr = cmd.addrs[i]; let n = exec_addr(s, addr)?; - debug("exec_addrs(): offs={}", addr.lineoffset); + //debug("exec_addrs(): offs={}", addr.lineoffset); n = n + addr.lineoffset: size; // beware of negatives - debug("exec_addrs(): n={}", n); + //debug("exec_addrs(): n={}", n); append(cmd.linenums, n); for (let j = 0z; j < len(cmd.linenums); j += 1) { - debug("exec_addrs(): cmd.linenums[{}]={}", j, cmd.linenums[j]); + void; //debug("exec_addrs(): cmd.linenums[{}]={}", j, cmd.linenums[j]); }; if (addr.setcurrentline) { @@ -40,23 +37,23 @@ fn exec_addrs(s: *Session, cmd: *Command) (void | CmdError) = { }; fn exec_addr(s: *Session, addr: Address) (size | CmdError) = { - match (addr.addrtype) { + match (addr.addrform) { case let n: size => - return addr_linenum(&s.buf, n)?; + return addr_linenum(s.buf, n)?; case CurrentLine => return s.buf.cursor; case LastLine => - return addr_lastline(&s.buf); + return addr_lastline(s.buf); case let m: rune => - return addr_mark(&s.buf, m)?; + return addr_mark(s.buf, m)?; case let rad: RegexAddr => - return addr_regex(&s.buf, rad, s.buf.cursor)?; + return addr_regex(s.buf, rad, s.buf.cursor)?; }; }; fn get_range(s: *Session, lns: *[]size, a: size, b: size) ((size, size) | InvalidAddress) = { - debug("get_range(): len(lns)={}", len(lns)); + //debug("get_range(): len(lns)={}", len(lns)); const (a, b) = if (len(lns) == 0) { yield (a, b); } else if (len(lns) == 1) { @@ -64,7 +61,7 @@ fn get_range(s: *Session, lns: *[]size, a: size, b: size) ((size, size) | Invali } else { yield (lns[ len(lns) - 2 ], lns[ len(lns) - 1 ]); }; - debug("get_range(): (a, b)=({}, {})", a, b); + //debug("get_range(): (a, b)=({}, {})", a, b); if (a < 0 || a > b || b >= len(s.buf.lines)) { return InvalidAddress; }; diff --git a/interaction.ha b/interaction.ha @@ -0,0 +1,23 @@ +use bufio; +use encoding::utf8; +use io; +use os; +use strings; +use types; + +type InteractionError = !( + UnexpectedEOF + | utf8::invalid + | io::error +); + +type UnexpectedEOF = !io::EOF; + +fn scanline(s: *Session) (str | InteractionError) = { + match (bufio::scan_line(s.input)?) { + case let string: const str => + return string; + case io::EOF => + return UnexpectedEOF; + }; +}; diff --git a/main.ha b/main.ha @@ -7,9 +7,11 @@ use io; use os; use regex; use strings; +use types; type Session = struct { - buf: Buffer, + input: *bufio::scanner, + buf: *Buffer, mode: InputMode, helpmode: bool, lasterror: (void | Error), @@ -25,7 +27,7 @@ type InputMode = enum { TEXT, }; -type Error = (ParseError | CmdError); +type Error = !(...InteractionError | ParseError | CmdError); export fn main() void = { const help: [_]getopt::help = [ @@ -37,20 +39,25 @@ export fn main() void = { const main_cmd = getopt::parse(os::args, help...); defer getopt::finish(&main_cmd); + const input = bufio::newscanner(os::stdin, types::SIZE_MAX); + defer bufio::finish(&input); + + const buffer = Buffer { + lines = *alloc([ alloc(Line { ... }) ]), + trash = *alloc([]: []*Line), + ... + }; + defer buffer_finish(&buffer); + let s = Session { - buf = Buffer { - lines = *alloc([ alloc(Line { ... }) ]), - trash = *alloc([]: []*Line), - ... - }, + input = &input, + buf = &buffer, prompt = "*", prev_shcmd = void, lasterror = void, ... }; - let cmd = Command { ... }; - for (let i = 0z; i < len(main_cmd.opts); i += 1) { const opt = main_cmd.opts[i]; switch (opt.0) { @@ -74,13 +81,14 @@ export fn main() void = { case "" => fmt::fatal("Invalid filename ''"); case => - s.buf.filename = main_cmd.args[0]; + s.buf.filename = strings::dup(main_cmd.args[0]); }; }; if (len(s.buf.filename) != 0) { - cmd.arg = s.buf.filename; - cmd_edit(&s, &cmd): void; + let cmd = Command { ... }; + cmd.arg1 = strings::dup(s.buf.filename); + cmd_edit(&s, &cmd): void; // TODO: handle error? }; let cmd = Command { ... }; @@ -90,28 +98,19 @@ export fn main() void = { fmt::error(s.prompt)!; }; - const rawline = match (bufio::read_line(os::stdin)) { - case let bs: []u8 => - yield bs; + const inputstr = match (bufio::scan_line(s.input)) { + case let s: const str => + yield s; case io::EOF => fmt::println()!; break; case let err: io::error => fmt::fatal(io::strerror(err)); }; - defer free(rawline); - - const input = match (strings::fromutf8(rawline)) { - case let s: str => - yield s; - case encoding::utf8::invalid => - fmt::errorln("Error: Invalid UTF-8 input")!; - continue; - }; switch (s.mode) { case InputMode::COMMAND => - const execnow = match (parse(&cmd, input)) { + const execnow = match (parse(&cmd, inputstr)) { case let err: ParseError => errormsg(&s, strerror(err)); continue; @@ -121,20 +120,22 @@ export fn main() void = { if (execnow) { // TODO: handle all ": void"s execute(&s, &cmd): void; - //cmd = command { ... }; + debug("main(): before command_finish()"); + command_finish(&cmd); + debug("main(): after command_finish()"); } else { s.mode = InputMode::TEXT; continue; }; case InputMode::TEXT => - if (input == ".") { + if (inputstr == ".") { execute(&s, &cmd): void; - delete(cmd.input[..]); + command_finish(&cmd); s.mode = InputMode::COMMAND; continue; }; - debug("repl: input={}", input); - append(cmd.input, strings::dup(input)); + debug("repl: input={}", inputstr); + append(cmd.input, strings::dup(inputstr)); }; }; @@ -157,6 +158,16 @@ fn errormsg(s: *Session, err: Error) void = { fn strerror(err: Error) str = { match (err) { + // InteractionError + case let e: InteractionError => + match (e) { + case UnexpectedEOF => + return "Unexpected end-of-file input"; + case let e: encoding::utf8::invalid => + return encoding::utf8::strerror(e); + case let e: io::error => + return io::strerror(e); + }; // CmdError case InvalidAddress => return "Invalid address"; @@ -175,6 +186,7 @@ fn strerror(err: Error) str = { case let e: regex::error => return regex::strerror(e); case let e: fs::error => + debug("foo"); return fs::strerror(e); // ParseError case UnknownCommand => diff --git a/parse.ha b/parse.ha @@ -1,4 +1,5 @@ use ascii; +use io; use regex; use strconv; use strings; @@ -54,7 +55,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { return true; }; } else { - cmd.arg = scan_rest(&iter); + cmd.arg1 = scan_rest(&iter); return true; }; @@ -62,7 +63,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { case 'k' => match (strings::next(&iter)) { case let r: rune => - cmd.arg = strings::fromrunes([r]); + cmd.arg1 = strings::fromrunes([r]); case void => return ExpectedMark; }; @@ -71,7 +72,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { // !<shellcmd> case '!' => - cmd.arg = scan_rest(&iter); + cmd.arg1 = scan_rest(&iter); return true; // .[s] where 's' is '(l|n|p)' @@ -89,7 +90,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { // .[s][ ]<addr> case 'm', 't' => cmd.printmode = scan_suffix(&iter); - cmd.arg = scan_rest(&iter); + cmd.arg1 = scan_rest(&iter); return true; // ./<regex>[/] where delimiter '/' is arbitrary @@ -104,7 +105,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { yield r; }; }; - cmd.arg = scan_item(&iter, delim); + cmd.arg1 = scan_item(&iter, delim); strings::next(&iter); // scan delimiter if exists scan_end_assert(&iter)?; return true; @@ -121,7 +122,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { yield r; }; }; - cmd.arg = scan_item(&iter, delim); + cmd.arg1 = scan_item(&iter, delim); strings::next(&iter); // scan delimiter if exists cmd.arg2 = scan_rest(&iter); if (strings::prev(&iter) as rune == '\\') { @@ -141,7 +142,7 @@ fn parse(cmd: *Command, input: str) (bool | ParseError) = { yield r; }; }; - cmd.arg = scan_item(&iter, delim); + cmd.arg1 = scan_item(&iter, delim); match (strings::next(&iter)) { case rune => void; case void => @@ -174,14 +175,14 @@ fn scan_addrs(iter: *strings::iterator) []Address = { case ',' => specialfirst = true; append(addrs, Address { - addrtype = 1z, + addrform = 1z, lineoffset = 0, setcurrentline = false, }); case ';' => specialfirst = true; append(addrs, Address { - addrtype = CurrentLine, + addrform = CurrentLine, lineoffset = 0, setcurrentline = true, }); @@ -195,7 +196,7 @@ fn scan_addrs(iter: *strings::iterator) []Address = { case void => yield if (specialfirst) { yield Address { - addrtype = LastLine, + addrform = LastLine, lineoffset = 0, ... }; @@ -246,7 +247,7 @@ fn scan_addr(iter: *strings::iterator) (Address | void) = { // debug("scan_addr(): r={}", r); - const addrtype: (AddressType | void) = + const addrform: (AddressForm | void) = if (r == '.') { yield CurrentLine; } else if (r == '$') { @@ -277,7 +278,7 @@ fn scan_addr(iter: *strings::iterator) (Address | void) = { const offs = scan_offsets(iter); - const addrtype: AddressType = match (addrtype) { + const addrform: AddressForm = match (addrform) { case void => yield if (len(offs) == 0) { return void; @@ -285,11 +286,11 @@ fn scan_addr(iter: *strings::iterator) (Address | void) = { yield CurrentLine; }; case => - yield addrtype as AddressType; + yield addrform as AddressForm; }; let addr = Address { - addrtype = addrtype, + addrform = addrform, lineoffset = 0, ... }; @@ -443,7 +444,8 @@ fn scan_mark(iter: *strings::iterator) rune = { // TODO: rename and appropriate to "scan_size()"? fn scan_uint(iter: *strings::iterator) uint = { - let num: []u8 = []; + // reimplement this function using another iterator + let num: []rune = []; defer free(num); for (true) { let r = match (strings::next(iter)) { @@ -454,18 +456,19 @@ fn scan_uint(iter: *strings::iterator) uint = { }; if (ascii::isdigit(r)) { - append(num, r: u32: u8); + append(num, r); } else { strings::prev(iter); break; }; }; + // TODO: return void instead? if (len(num) == 0) { return 0; }; - match (strconv::stou(strings::fromutf8(num)!)) { + match (strconv::stou(strings::fromrunes(num))) { case (strconv::invalid | strconv::overflow) => abort("Invalid"); case let u: uint => diff --git a/util.ha b/util.ha @@ -3,7 +3,7 @@ use io; use strings; fn cmd_dumpbuffer(s: *Session, cmd: *Command) (void | Error) = { - return dumpbuffer(&s.buf); + return dumpbuffer(s.buf); }; fn dumpbuffer(buf: *Buffer) void = {