summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2026-06-05 20:32:17 -0400
committerLLLL Colonq <llll@colonq>2026-06-05 20:32:17 -0400
commitb456aa44a172171d4b6120ec566c1499ec25a690 (patch)
tree7a835e42351ffd39e5620f5d8e705ef8c69d838e /src
parent48ab2cb8e3de88dbd0722337bd4617ad22de1a12 (diff)
Fix integer parsing
Diffstat (limited to 'src')
-rw-r--r--src/lexer.c37
-rw-r--r--src/parser.c11
-rw-r--r--src/utils.c1
3 files changed, 37 insertions, 12 deletions
diff --git a/src/lexer.c b/src/lexer.c
index adfe8d3..5d9c5e7 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -1,6 +1,7 @@
#include <lcq/pit/utils.h>
#include <lcq/pit/lexer.h>
#include <lcq/pit/types.h>
+#include <stdio.h>
const char *PIT_LEX_TOKEN_NAMES[PIT_LEX_TOKEN__SENTINEL] = {
/* [PIT_LEX_TOKEN_EOF] = */ "eof",
@@ -92,20 +93,34 @@ restart:
}
advance(st);
return PIT_LEX_TOKEN_STRING_LITERAL;
- default:
+ default: {
if (pit_ctype_isspace(c)) goto restart;
- if (pit_ctype_isdigit(c)) {
- if (c == '0') {
- int next = peek(st);
- if (next != 'x' && next != 'o' && next != 'b') return PIT_LEX_TOKEN_INTEGER_LITERAL;
- advance(st); /* skip base specifier */
- }
- while (match(st, is_hexdigit)) {}
- return PIT_LEX_TOKEN_INTEGER_LITERAL;
+ pit_lex_token ret = PIT_LEX_TOKEN_INTEGER_LITERAL;
+ int num_idx = 0;
+ bool leading_dash = false;
+ bool zero_prefix = false;
+ if (!is_symchar(c)) {
+ st->error = "unknown character";
+ return PIT_LEX_TOKEN_ERROR;
} else {
- while (match(st, is_symchar)) {}
- return PIT_LEX_TOKEN_SYMBOL;
+ do {
+ leading_dash = false;
+ switch (num_idx) {
+ case 0:
+ if (c == '0') zero_prefix = true;
+ else if (c == '-') { leading_dash = true; continue; }
+ break;
+ case 1:
+ if (zero_prefix && (c == 'x' || c == 'o' || c == 'b')) continue;
+ break;
+ }
+ if (!is_hexdigit(c)) ret = PIT_LEX_TOKEN_SYMBOL;
+ ++num_idx;
+ } while (c = peek(st), match(st, is_symchar));
}
+ if (leading_dash) return PIT_LEX_TOKEN_SYMBOL;
+ return ret;
+ }
}
}
diff --git a/src/parser.c b/src/parser.c
index 5dc57db..77b4172 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -129,7 +129,16 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
i64 idx = st->cur.start;
i64 base = 10;
i64 total = 0;
+ bool neg = false;
char c = st->lexer->input[idx++];
+ if (c == '-') {
+ neg = true;
+ if (idx < st->cur.end) {
+ c = st->lexer->input[idx++];
+ } else {
+ pit_error(rt, "malformed negative integer literal"); return PIT_NIL;
+ }
+ }
if (c == '0' && idx + 1 < st->cur.end) {
switch (st->lexer->input[idx++]) {
case 'b': base = 2; break;
@@ -145,7 +154,7 @@ pit_value pit_parse(pit_runtime *rt, pit_parser *st, bool *eof) {
pit_error(rt, "integer literal too large"); return PIT_NIL;
}
}
- return pit_integer_new(rt, total);
+ return pit_integer_new(rt, neg ? -total : total);
}
case PIT_LEX_TOKEN_STRING_LITERAL: {
char buf[256] = {0};
diff --git a/src/utils.c b/src/utils.c
index 7f2831b..53a9ebf 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -45,6 +45,7 @@ int pit_string_vsnprintf(char *buf, size_t len, char *format, va_list ap) {
if (length_mod == 'l') arg = va_arg(ap, long); else arg = va_arg(ap, int);
if (arg == 0) { WRITE('0') }
else {
+ if (arg < 0) { WRITE('-'); arg = -arg; }
while (arg != 0) { WRITE_SCRATCH('0' + (char) (arg % 10)); arg /= 10; }
while (sidx > 0) { WRITE(scratch[sidx - 1]); sidx -= 1; }
}