1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
/*
* transpiler from a catskill intermediate translation unit,
* to the c programming language, as the main translation target.
*
* walks a fully-lowered translation unit and emits (slightly ugly)
* c source code.
*
* Copyright (c) 2025-2026, Mel G. <mel@rnrd.eu>
*
* SPDX-License-Identifier: MPL-2.0
*/
#pragma once
#include "catboot.h"
// the output of the transpilation pass.
// used for both file output and string buffer output.
struct Transpile_Output
{
FILE* file;
struct String_Buffer string;
};
struct Transpile_Output
transpile_output_from_file(FILE* file)
{
check(file != nil, "transpile output file is nil");
return (struct Transpile_Output){
.file = file,
.string = string_buffer_empty(),
};
}
#define TRANSPILE_OUTPUT_MAX_LENGTH 262144 // 256 KiB
struct Transpile_Output
transpile_output_from_string(void)
{
return (struct Transpile_Output){
.file = nil,
.string = string_buffer_new(TRANSPILE_OUTPUT_MAX_LENGTH),
};
}
#define TRANSPILE_OUTPUT_MAX_WRITE_LENGTH 4096
void
transpile_output_write(struct Transpile_Output* output, const ascii* format, ...)
{
va_list args;
va_start(args, format);
if (output->file) {
vfprintf(output->file, format, args);
} else {
ascii buffer[TRANSPILE_OUTPUT_MAX_WRITE_LENGTH];
int written = vsnprintf(buffer, TRANSPILE_OUTPUT_MAX_WRITE_LENGTH, format, args);
check(written >= 0 && (uint)written < TRANSPILE_OUTPUT_MAX_LENGTH,
"transpile output string buffer overflow");
string_buffer_append_c_str(&output->string, buffer);
}
va_end(args);
}
struct String
transpile_output_string(struct Transpile_Output* output)
{
check(output->file == nil, "transpile output is not a string");
return string_buffer_to_string(&output->string);
}
FILE*
transpile_output_file(struct Transpile_Output* output)
{
check(output->file != nil, "transpile output is not a file");
return output->file;
}
struct Transpiler
{
struct Transpile_Output output;
};
void
transpiler_new(struct Transpiler* transpiler, struct Transpile_Output output)
{
*transpiler = (struct Transpiler){
.output = output,
};
}
// walk a lowered translation unit and emit c source into the transpiler's output.
// TODO: actual emission!
int
transpile_unit(struct Transpiler* transpiler, struct Unit* unit)
{
(void)transpiler;
(void)unit;
return 0;
}
|