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:
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 '<' =>