/Users/alexjokela/projects/lattice/src/builtins.c
Line | Count | Source |
1 | | #include "builtins.h" |
2 | | #include "value.h" |
3 | | #include <stdlib.h> |
4 | | #include <string.h> |
5 | | #include <stdio.h> |
6 | | #include <errno.h> |
7 | | #ifndef __EMSCRIPTEN__ |
8 | | #if defined(LATTICE_HAS_EDITLINE) |
9 | | #include <editline/readline.h> |
10 | | #elif defined(LATTICE_HAS_READLINE) |
11 | | #include <readline/readline.h> |
12 | | #include <readline/history.h> |
13 | | #else |
14 | | static char *readline(const char *prompt) { |
15 | | if (prompt) fputs(prompt, stdout); |
16 | | fflush(stdout); |
17 | | char *buf = malloc(4096); |
18 | | if (!buf) return NULL; |
19 | | if (!fgets(buf, 4096, stdin)) { free(buf); return NULL; } |
20 | | size_t len = strlen(buf); |
21 | | if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0'; |
22 | | return buf; |
23 | | } |
24 | | static void add_history(const char *line) { (void)line; } |
25 | | #endif |
26 | | #endif |
27 | | |
28 | | /* ── builtin_input ── */ |
29 | | |
30 | 0 | char *builtin_input(const char *prompt) { |
31 | | #ifdef __EMSCRIPTEN__ |
32 | | (void)prompt; |
33 | | return NULL; |
34 | | #else |
35 | 0 | char *line = readline(prompt ? prompt : ""); |
36 | 0 | if (line == NULL) return NULL; |
37 | 0 | if (line[0] != '\0') add_history(line); |
38 | 0 | return line; |
39 | 0 | #endif |
40 | 0 | } |
41 | | |
42 | | /* ── builtin_read_file ── */ |
43 | | |
44 | 273 | char *builtin_read_file(const char *path) { |
45 | 273 | FILE *f = fopen(path, "r"); |
46 | 273 | if (f == NULL) { |
47 | 0 | return NULL; |
48 | 0 | } |
49 | | |
50 | 273 | fseek(f, 0, SEEK_END); |
51 | 273 | long len = ftell(f); |
52 | 273 | fseek(f, 0, SEEK_SET); |
53 | 273 | if (len < 0) { fclose(f); return NULL; } |
54 | | |
55 | 273 | char *buf = malloc((size_t)len + 1); |
56 | 273 | if (buf == NULL) { |
57 | 0 | fclose(f); |
58 | 0 | return NULL; |
59 | 0 | } |
60 | | |
61 | 273 | size_t read = fread(buf, 1, (size_t)len, f); |
62 | 273 | buf[read] = '\0'; |
63 | 273 | fclose(f); |
64 | | |
65 | 273 | return buf; |
66 | 273 | } |
67 | | |
68 | | /* ── builtin_write_file ── */ |
69 | | |
70 | 57 | bool builtin_write_file(const char *path, const char *content) { |
71 | 57 | FILE *f = fopen(path, "w"); |
72 | 57 | if (f == NULL) { |
73 | 0 | return false; |
74 | 0 | } |
75 | | |
76 | 57 | fputs(content, f); |
77 | 57 | fclose(f); |
78 | | |
79 | 57 | return true; |
80 | 57 | } |
81 | | |
82 | | /* ── builtin_typeof_str ── */ |
83 | | |
84 | 216 | const char *builtin_typeof_str(const LatValue *v) { |
85 | 216 | switch (v->type) { |
86 | 72 | case VAL_INT: return "Int"; |
87 | 18 | case VAL_FLOAT: return "Float"; |
88 | 9 | case VAL_BOOL: return "Bool"; |
89 | 51 | case VAL_STR: return "String"; |
90 | 12 | case VAL_ARRAY: return "Array"; |
91 | 0 | case VAL_STRUCT: return "Struct"; |
92 | 0 | case VAL_CLOSURE: return "Closure"; |
93 | 3 | case VAL_UNIT: return "Unit"; |
94 | 9 | case VAL_NIL: return "Nil"; |
95 | 0 | case VAL_RANGE: return "Range"; |
96 | 21 | case VAL_MAP: return "Map"; |
97 | 3 | case VAL_CHANNEL: return "Channel"; |
98 | 3 | case VAL_ENUM: return "Enum"; |
99 | 6 | case VAL_SET: return "Set"; |
100 | 3 | case VAL_TUPLE: return "Tuple"; |
101 | 3 | case VAL_BUFFER: return "Buffer"; |
102 | 3 | case VAL_REF: return "Ref"; |
103 | 216 | } |
104 | 0 | return "?"; |
105 | 216 | } |
106 | | |
107 | | /* ── builtin_phase_of_str ── */ |
108 | | |
109 | 177 | const char *builtin_phase_of_str(const LatValue *v) { |
110 | 177 | switch (v->phase) { |
111 | 60 | case VTAG_FLUID: return "fluid"; |
112 | 69 | case VTAG_CRYSTAL: return "crystal"; |
113 | 45 | case VTAG_UNPHASED: return "unphased"; |
114 | 3 | case VTAG_SUBLIMATED: return "sublimated"; |
115 | 177 | } |
116 | 0 | return "?"; |
117 | 177 | } |
118 | | |
119 | | /* ── builtin_to_string ── */ |
120 | | |
121 | 531 | char *builtin_to_string(const LatValue *v) { |
122 | 531 | return value_display(v); |
123 | 531 | } |
124 | | |
125 | | /* ── builtin_ord ── */ |
126 | | |
127 | 12 | int64_t builtin_ord(const char *s) { |
128 | 12 | if (s[0] == '\0') { |
129 | 0 | return -1; |
130 | 0 | } |
131 | 12 | return (int64_t)(unsigned char)s[0]; |
132 | 12 | } |
133 | | |
134 | | /* ── builtin_chr ── */ |
135 | | |
136 | 6 | char *builtin_chr(int64_t code) { |
137 | 6 | if (code >= 0 && code <= 127) { |
138 | 6 | char buf[2]; |
139 | 6 | buf[0] = (char)code; |
140 | 6 | buf[1] = '\0'; |
141 | 6 | return strdup(buf); |
142 | 6 | } |
143 | 0 | return strdup("?"); |
144 | 6 | } |
145 | | |
146 | | /* ── builtin_parse_int ── */ |
147 | | |
148 | 6 | int64_t builtin_parse_int(const char *s, bool *ok) { |
149 | 6 | char *endptr; |
150 | 6 | errno = 0; |
151 | 6 | long long val = strtoll(s, &endptr, 10); |
152 | 6 | if (errno != 0 || endptr == s || *endptr != '\0') { |
153 | 0 | *ok = false; |
154 | 0 | return 0; |
155 | 0 | } |
156 | 6 | *ok = true; |
157 | 6 | return (int64_t)val; |
158 | 6 | } |
159 | | |
160 | | /* ── builtin_parse_float ── */ |
161 | | |
162 | 3 | double builtin_parse_float(const char *s, bool *ok) { |
163 | 3 | char *endptr; |
164 | 3 | errno = 0; |
165 | 3 | double val = strtod(s, &endptr); |
166 | 3 | if (errno != 0 || endptr == s || *endptr != '\0') { |
167 | 0 | *ok = false; |
168 | 0 | return 0.0; |
169 | 0 | } |
170 | 3 | *ok = true; |
171 | 3 | return val; |
172 | 3 | } |