code / tomo

Lines41.3K C23.7K Markdown9.7K YAML5.0K Tomo2.3K
7 others 763
Python231 Shell230 make212 INI47 Text21 SVG16 Lua6
(82 lines)
1 // Logic for parsing numbers
3 #include <ctype.h>
4 #include <gc.h>
5 #include <stdarg.h>
6 #include <stdbool.h>
7 #include <string.h>
9 #include <unictype.h>
10 #include <uniname.h>
12 #include "../ast.h"
13 #include "context.h"
14 #include "errors.h"
15 #include "utils.h"
17 static const double RADIANS_PER_DEGREE = 0.0174532925199432957692369076848861271344287188854172545609719144;
19 ast_t *parse_int(parse_ctx_t *ctx, const char *pos) {
20 const char *start = pos;
21 (void)match(&pos, "-");
22 if (!isdigit(*pos)) return NULL;
23 if (match(&pos, "0x")) { // Hex
24 pos += strspn(pos, "0123456789abcdefABCDEF_");
25 } else if (match(&pos, "0b")) { // Binary
26 pos += strspn(pos, "01_");
27 } else if (match(&pos, "0o")) { // Octal
28 pos += strspn(pos, "01234567_");
29 } else { // Decimal
30 pos += strspn(pos, "0123456789_");
32 char *str = GC_MALLOC_ATOMIC((size_t)(pos - start) + 1);
33 memset(str, 0, (size_t)(pos - start) + 1);
34 for (char *src = (char *)start, *dest = str; src < pos; ++src) {
35 if (*src != '_') *(dest++) = *src;
38 if (match(&pos, "e") || match(&pos, "f")) // floating point literal
39 return NULL;
41 if (match(&pos, "%")) {
42 double n = strtod(str, NULL) / 100.;
43 return NewAST(ctx->file, start, pos, Num, .n = n);
44 } else if (match(&pos, "deg")) {
45 double n = strtod(str, NULL) * RADIANS_PER_DEGREE;
46 return NewAST(ctx->file, start, pos, Num, .n = n);
49 return NewAST(ctx->file, start, pos, Int, .str = str);
52 ast_t *parse_num(parse_ctx_t *ctx, const char *pos) {
53 const char *start = pos;
54 bool negative = match(&pos, "-");
55 if (!isdigit(*pos) && *pos != '.') return NULL;
56 else if (*pos == '.' && !isdigit(pos[1])) return NULL;
58 size_t len = strspn(pos, "0123456789_");
59 if (strncmp(pos + len, "..", 2) == 0) return NULL;
60 else if (pos[len] == '.' && is_xid_start_next(pos + len + 1)) return NULL;
61 else if (pos[len] == '.') len += 1 + strspn(pos + len + 1, "0123456789");
62 else if (pos[len] != 'e' && pos[len] != 'f' && pos[len] != '%') return NULL;
63 if (pos[len] == 'e') {
64 len += 1;
65 if (pos[len] == '-') len += 1;
66 len += strspn(pos + len, "0123456789_");
68 char *buf = GC_MALLOC_ATOMIC(len + 1);
69 memset(buf, 0, len + 1);
70 for (char *src = (char *)pos, *dest = buf; src < pos + len; ++src) {
71 if (*src != '_') *(dest++) = *src;
73 double d = strtod(buf, NULL);
74 pos += len;
76 if (negative) d *= -1;
78 if (match(&pos, "%")) d /= 100.;
79 else if (match(&pos, "deg")) d *= RADIANS_PER_DEGREE;
81 return NewAST(ctx->file, start, pos, Num, .n = d);