27static void usage(
const char *prog) {
28 fprintf(stderr,
"Usage: %s [--fix] [--quiet] <file1.fun> [file2.fun ...]\n", prog);
41static int read_all(
const char *path,
char **out_buf,
size_t *out_len) {
44 FILE *f = fopen(path,
"rb");
46 if (fseek(f, 0, SEEK_END) != 0) {
55 if (fseek(f, 0, SEEK_SET) != 0) {
59 char *buf = (
char *)malloc((
size_t)sz + 1);
64 size_t rd = fread(buf, 1, (
size_t)sz, f);
80static int write_all(
const char *path,
const char *buf,
size_t len) {
81 FILE *f = fopen(path,
"wb");
83 size_t wr = fwrite(buf, 1, len, f);
95 return (c ==
'_' || isalnum(c));
116static char *
apply_fixes(
const char *src,
size_t len,
size_t *out_len) {
119 size_t cap = len + 32;
120 char *out = (
char *)malloc(cap);
121 if (!out)
return NULL;
129 char *n = (
char *)realloc(out, cap);
138 size_t line_start_out = o;
145 if (c ==
'\r' || c ==
'\n')
break;
146 if (at_bol && (c ==
' ' || c ==
'\t')) {
149 }
else if (c ==
'\t') {
159 int normalized = (spaces % 2 == 0) ? spaces : spaces + 1;
160 for (
int k = 0; k < normalized; k++) {
163 char *n = realloc(out, cap);
176 size_t line_content_start = i;
177 size_t line_end_i = i;
179 while (line_end_i < len) {
180 char c = src[line_end_i];
185 if (c ==
'\n')
break;
189 size_t trim_end = line_end_i;
190 while (trim_end > i && src[trim_end - 1] ==
' ')
195 while (p < trim_end) {
197 const char *keys[] = {
"sint8",
"sint16",
"sint32",
"sint64"};
198 const char *vals[] = {
"int8",
"int16",
"int32",
"int64"};
200 for (
int idx = 0; idx < 4; idx++) {
201 const char *k = keys[idx];
202 size_t klen = strlen(k);
203 if (p + klen <= trim_end && strncmp(&src[p], k, klen) == 0) {
204 int left_ok = (p == i) || !
is_word((
unsigned char)src[p - 1]);
205 int right_ok = (p + klen == trim_end) || !
is_word((
unsigned char)src[p + klen]);
206 if (left_ok && right_ok) {
207 const char *v = vals[idx];
208 size_t vlen = strlen(v);
209 if (o + vlen + 16 >= cap) {
211 char *n = realloc(out, cap);
218 memcpy(&out[o], v, vlen);
226 if (replaced)
continue;
227 if (o + 1 + 16 >= cap) {
229 char *n = realloc(out, cap);
240 if (line_end_i < len) {
242 if (src[line_end_i] ==
'\r') {
244 if (line_end_i < len && src[line_end_i] ==
'\n') line_end_i++;
245 }
else if (src[line_end_i] ==
'\n') {
250 char *n = realloc(out, cap);
261 (void)line_start_out;
262 (void)line_content_start;
267 if (o == 0 || out[o - 1] !=
'\n') {
270 char *n = (
char *)realloc(out, cap);
282 char *shr = (
char *)realloc(out, o + 1);
299int main(
int argc,
char **argv) {
302 int first_file_arg = 1;
305 for (
int i = 1; i < argc; i++) {
306 if (strcmp(argv[i],
"--fix") == 0) {
311 if (strcmp(argv[i],
"--quiet") == 0) {
317 if (argv[i][0] !=
'-')
break;
319 if (strncmp(argv[i],
"--", 2) == 0) {
326 if (first_file_arg >= argc) {
333 for (
int i = first_file_arg; i < argc; i++) {
334 const char *path = argv[i];
340 if (!
read_all(path, &orig, &orig_len)) {
341 fprintf(stderr,
"%s: cannot read file\n", path);
345 size_t fixed_len = 0;
346 char *fixed =
apply_fixes(orig, orig_len, &fixed_len);
348 fprintf(stderr,
"%s: out of memory while fixing\n", path);
358 int line = 0, col = 0;
360 fprintf(stderr,
"%s:%d:%d: syntax error after --fix attempt: %s\n", path, line, col, msg);
362 fprintf(stderr,
"%s: syntax error (unknown) after --fix attempt\n", path);
373 if (orig_len != fixed_len || memcmp(orig, fixed, (orig_len < fixed_len ? orig_len : fixed_len)) != 0) changed = 1;
375 if (!
write_all(path, fixed, fixed_len)) {
376 fprintf(stderr,
"%s: failed to write fixed file\n", path);
391 int line = 0, col = 0;
393 fprintf(stderr,
"%s:%d:%d: syntax error: %s\n", path, line, col, msg);
395 fprintf(stderr,
"%s: syntax error (unknown)\n", path);
401 if (!quiet)
fprintf(stdout,
"%s: OK\n", path);
405 return hadError ? 1 : 0;
void bytecode_free(Bytecode *bc)
Free a Bytecode and all memory it owns.
Definitions for the Fun VM bytecode: opcodes, instruction format, and bytecode container API.
int main(void)
Build and execute a demo bytecode program and print results.
static int is_word(int c)
Determine whether a character is an identifier constituent.
static int write_all(const char *path, const char *buf, size_t len)
Overwrite a file with the provided buffer.
static char * apply_fixes(const char *src, size_t len, size_t *out_len)
Apply conservative style/syntax auto-fixes to a Fun source buffer.
static void usage(const char *prog)
Print command-line usage for the funstx tool to stderr.
static int read_all(const char *path, char **out_buf, size_t *out_len)
Read entire file into a newly allocated buffer.
Bytecode * parse_string_to_bytecode(const char *source)
Parse a source string and return compiled bytecode.
int parser_last_error(char *msgBuf, unsigned long msgCap, int *outLine, int *outCol)
Retrieve the last parser/compiler error information, if any.
Bytecode * parse_file_to_bytecode(const char *path)
Parse a .fun source file and return compiled bytecode.
Public API for parsing Fun source into bytecode.