hare

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

commit 16b3595b96c41c694008891e0e72ce8b836f9e6b
parent 63ca95ead948e3d1cf12269ded8c16fee8f58a8d
Author: Sebastian <sebastian@sebsite.pw>
Date:   Fri, 13 May 2022 23:34:37 -0400

hare::lex: fix nested tuple access lexing

Given a tuple named t, the expression t.0.1 now works as intended,
rather than erroring because 0.1 was lexed as a floating point literal.
This is done by requiring that a number literal lexed immediately after
a dot token is an integer.

Fixes: https://todo.sr.ht/~sircmpwn/hare/376
Signed-off-by: Sebastian <sebastian@sebsite.pw>

Diffstat:
Mhare/lex/+test.ha | 20++++++++++++++++++++
Mhare/lex/lex.ha | 25++++++++++++++++---------
2 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/hare/lex/+test.ha b/hare/lex/+test.ha @@ -396,3 +396,23 @@ type op = enum { && ploc.col == vector[i].1.col); }; }; + +@test fn access_tuple() void = { + const in = "((0, 1), 2).0.1"; + const expected: []token = [ + (ltok::LPAREN, void, loc(1, 1)), + (ltok::LPAREN, void, loc(1, 2)), + (ltok::LIT_ICONST, 0, loc(1, 3)), + (ltok::COMMA, void, loc(1, 4)), + (ltok::LIT_ICONST, 1, loc(1, 6)), + (ltok::RPAREN, void, loc(1, 7)), + (ltok::COMMA, void, loc(1, 8)), + (ltok::LIT_ICONST, 2, loc(1, 10)), + (ltok::RPAREN, void, loc(1, 11)), + (ltok::DOT, void, loc(1, 12)), + (ltok::LIT_ICONST, 0, loc(1, 13)), + (ltok::DOT, void, loc(1, 14)), + (ltok::LIT_ICONST, 1, loc(1, 15)), + ]; + lextest(in, expected); +}; diff --git a/hare/lex/lex.ha b/hare/lex/lex.ha @@ -27,6 +27,7 @@ export type lexer = struct { prevrlocs: [3]location, flags: flags, comment: str, + require_int: bool, }; // Flags which apply to this lexer @@ -70,7 +71,7 @@ export fn init(in: io::handle, path: str, flags: flags...) lexer = { prevunlocs = [(loc, loc)...], prevrlocs = [loc...], flags = f, - comment = "", + ... }; }; @@ -99,15 +100,17 @@ export fn lex(lex: *lexer) (token | error) = { yield r; }; - if (is_name(r.0, false)) { - unget(lex, r); - return lex_name(lex, r.1, false); - }; if (ascii::isdigit(r.0)) { unget(lex, r); return lex_literal(lex); }; + lex.require_int = false; + if (is_name(r.0, false)) { + unget(lex, r); + return lex_name(lex, r.1, false); + }; + let tok = switch (r.0) { case '"', '\'', '`' => unget(lex, r); @@ -454,7 +457,7 @@ fn lex_literal(lex: *lexer) (token | error) = { if (!strings::contains(basechrs, r.0)) switch (r.0) { case '.' => if (float || exp is size || suff is size - || base != 10) { + || base != 10 || lex.require_int) { unget(lex, r); break; } else { @@ -515,6 +518,7 @@ fn lex_literal(lex: *lexer) (token | error) = { } else append(chars, utf8::encoderune(r.0)...); }; if (end == 0) end = len(chars); + lex.require_int = false; let exp = match (exp) { case void => @@ -710,9 +714,12 @@ fn lex3(lex: *lexer) (token | error) = { let r = next(lex)? as (rune, location); let toks = switch (r.0) { case '.' => - let tok = if (try(lex, '.')? is void) ltok::DOT - else if (try(lex, '.')? is void) ltok::SLICE - else ltok::ELLIPSIS; + let tok = if (try(lex, '.')? is void) { + lex.require_int = true; + yield ltok::DOT; + } else if (try(lex, '.')? is void) { + yield ltok::SLICE; + } else ltok::ELLIPSIS; line_comment(lex)?; return (tok, void, r.1); case '<' =>