1 |
|
|
#include "gwion_util.h" |
2 |
|
|
#include "gwion_ast.h" |
3 |
|
|
#include "gwion_env.h" |
4 |
|
|
#include "vm.h" |
5 |
|
|
#include "instr.h" |
6 |
|
|
#include "emit.h" |
7 |
|
|
#include "compile.h" |
8 |
|
|
#include "gwion.h" |
9 |
|
|
#include "pass.h" |
10 |
|
|
#include "clean.h" |
11 |
|
|
|
12 |
|
|
enum compile_type { |
13 |
|
|
COMPILE_NAME, |
14 |
|
|
COMPILE_MSTR, |
15 |
|
|
COMPILE_FILE |
16 |
|
|
}; |
17 |
|
|
|
18 |
|
|
struct Compiler { |
19 |
|
|
const m_str base; |
20 |
|
|
m_str name; |
21 |
|
|
m_str data; |
22 |
|
|
FILE* file; |
23 |
|
|
Ast ast; |
24 |
|
|
Vector args; |
25 |
|
|
enum compile_type type; |
26 |
|
|
}; |
27 |
|
|
|
28 |
|
1333 |
ANN static void compiler_name(MemPool p, struct Compiler* c) { |
29 |
|
1333 |
m_str d = strdup(c->base); |
30 |
|
1333 |
c->name = strsep(&d, ":"); |
31 |
✓✓ |
1333 |
if(d) |
32 |
|
2 |
c->args = new_vector(p); |
33 |
✓✓ |
2668 |
while(d) |
34 |
|
2 |
vector_add(c->args, (vtype)strdup(strsep(&d, ":"))); |
35 |
|
1333 |
free(d); |
36 |
|
1333 |
} |
37 |
|
|
|
38 |
|
695 |
ANN static inline void compiler_error(MemPool p, const struct Compiler* c) { |
39 |
✓✓ |
695 |
if(c->args) { |
40 |
✓✓ |
2 |
for(m_uint i = 0; i < vector_size(c->args); ++i) { |
41 |
|
1 |
const m_str str = (m_str)vector_at(c->args, i); |
42 |
✓✗ |
1 |
if(str) |
43 |
|
1 |
xfree((m_str)vector_at(c->args, i)); |
44 |
|
|
} |
45 |
|
1 |
free_vector(p, c->args); |
46 |
|
|
} |
47 |
|
695 |
} |
48 |
|
|
|
49 |
|
1333 |
ANN static void compiler_clean(const Gwion gwion, const struct Compiler* c) { |
50 |
✓✓ |
1333 |
if(c->name) |
51 |
|
638 |
xfree(c->name); |
52 |
|
|
/* test c->type because COMPILE_FILE does not own file */ |
53 |
✓✓✓✓
|
1333 |
if(c->type != COMPILE_FILE && c->file) |
54 |
|
637 |
fclose(c->file); |
55 |
✓✓ |
1333 |
if(c->ast) |
56 |
|
618 |
ast_cleaner(gwion, c->ast); |
57 |
|
1333 |
} |
58 |
|
|
|
59 |
|
1333 |
ANN static m_bool _compiler_open(struct Compiler* c) { |
60 |
✓✓ |
1333 |
if(c->type == COMPILE_NAME) { |
61 |
|
1331 |
m_str name = c->name; |
62 |
|
1331 |
c->name = realpath(name, NULL); |
63 |
|
1331 |
xfree(name); |
64 |
✓✓ |
1331 |
return c->name ? !!(c->file = fopen(c->name, "r")) : GW_ERROR; |
65 |
✓✓ |
2 |
} else if(c->type == COMPILE_MSTR) { |
66 |
✓✗ |
1 |
c->file = c->data ? fmemopen(c->data, strlen(c->data), "r") : NULL; |
67 |
✓✗ |
1 |
return c->file ? GW_OK : GW_ERROR; |
68 |
|
|
} |
69 |
|
1 |
return GW_OK; |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
#ifndef BUILD_ON_WINDOWS |
73 |
|
|
#include <sys/stat.h> |
74 |
|
1 |
ANN static int is_reg(const m_str path) { |
75 |
|
|
struct stat s; |
76 |
|
1 |
stat(path, &s); |
77 |
|
1 |
return S_ISREG(s.st_mode); |
78 |
|
|
} |
79 |
|
|
#else |
80 |
|
|
ANN static m_bool is_reg(const m_str path) { |
81 |
|
|
const DWORD dw = GetFileAttributes(path); |
82 |
|
|
return !(dw == INVALID_FILE_ATTRIBUTES || |
83 |
|
|
dw & FILE_ATTRIBUTE_DIRECTORY); |
84 |
|
|
} |
85 |
|
|
#endif |
86 |
|
|
|
87 |
|
1333 |
ANN static inline m_bool compiler_open(MemPool p, struct Compiler* c) { |
88 |
|
1333 |
char name[strlen(c->name) + 1]; |
89 |
|
1333 |
strcpy(name, c->name); |
90 |
|
|
#ifndef __FUZZING__ |
91 |
✓✓✗✓
|
1333 |
if(c->type == COMPILE_FILE && !is_reg(name)) { |
92 |
|
|
gw_err(_("'%s': is a not a regular file\n"), name); |
93 |
|
|
return GW_ERROR; |
94 |
|
|
} |
95 |
|
|
#endif |
96 |
✓✓ |
1333 |
if(_compiler_open(c) < 0) { |
97 |
|
695 |
compiler_error(p, c); |
98 |
|
695 |
gw_err(_("can't open '%s'\n"), name); |
99 |
|
695 |
return GW_ERROR; |
100 |
|
|
} |
101 |
|
638 |
return GW_OK; |
102 |
|
|
} |
103 |
|
|
|
104 |
|
638 |
ANN static inline m_bool _check(struct Gwion_* gwion, struct Compiler* c) { |
105 |
|
638 |
struct AstGetter_ arg = { c->name, c->file, gwion->st, .ppa=gwion->ppa }; |
106 |
✓✓ |
638 |
CHECK_OB((c->ast = parse(&arg))) |
107 |
|
618 |
gwion->env->name = c->name; |
108 |
✓✓ |
1438 |
for(m_uint i = 0; i < vector_size(&gwion->data->passes->vec); ++i) { |
109 |
|
1030 |
const compilation_pass pass = (compilation_pass)vector_at(&gwion->data->passes->vec, i); |
110 |
✓✓ |
1030 |
CHECK_BB(pass(gwion->env, c->ast)) |
111 |
|
|
} |
112 |
|
408 |
return GW_OK; |
113 |
|
|
} |
114 |
|
|
|
115 |
|
1333 |
ANN static m_uint _compile(struct Gwion_* gwion, struct Compiler* c) { |
116 |
|
|
// CHECK_BB(compiler_open(gwion->mp, c)) |
117 |
✓✓ |
1333 |
if(compiler_open(gwion->mp, c) < 0) |
118 |
|
695 |
return 0; |
119 |
✓✓ |
638 |
if(_check(gwion, c) < 0) { |
120 |
|
230 |
gw_err(_("while compiling file '%s'\n"), c->base); |
121 |
|
230 |
return 0; |
122 |
|
|
} |
123 |
✓✗ |
408 |
if(gwion->emit->info->code) { |
124 |
|
408 |
const VM_Shred shred = new_vm_shred(gwion->mp, gwion->emit->info->code); |
125 |
|
408 |
shred->info->args = c->args; |
126 |
|
408 |
vm_add_shred(gwion->vm, shred); |
127 |
|
408 |
gwion->emit->info->code = NULL; |
128 |
|
408 |
return shred->tick->xid; |
129 |
|
|
} |
130 |
|
|
return GW_OK; |
131 |
|
|
} |
132 |
|
|
|
133 |
|
1333 |
ANN static m_uint compile(struct Gwion_* gwion, struct Compiler* c) { |
134 |
|
1333 |
compiler_name(gwion->mp, c); |
135 |
|
1333 |
MUTEX_LOCK(gwion->data->mutex); |
136 |
|
1333 |
const m_uint ret = _compile(gwion, c); |
137 |
|
1333 |
MUTEX_UNLOCK(gwion->data->mutex); |
138 |
|
1333 |
compiler_clean(gwion, c); |
139 |
|
1333 |
return ret; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
1331 |
ANN m_uint compile_filename(struct Gwion_* gwion, const m_str filename) { |
143 |
|
1331 |
struct Compiler c = { .base=filename, .type=COMPILE_NAME }; |
144 |
|
1331 |
return compile(gwion, &c); |
145 |
|
|
} |
146 |
|
|
|
147 |
|
1 |
ANN m_uint compile_string(struct Gwion_* gwion, const m_str filename, const m_str data) { |
148 |
|
1 |
struct Compiler c = { .base=filename, .type=COMPILE_MSTR, .data=data }; |
149 |
|
1 |
return compile(gwion, &c); |
150 |
|
|
} |
151 |
|
|
|
152 |
|
1 |
ANN m_uint compile_file(struct Gwion_* gwion, const m_str filename, FILE* file) { |
153 |
|
1 |
struct Compiler c = { .base=filename, .type=COMPILE_FILE, .file=file }; |
154 |
|
1 |
return compile(gwion, &c); |
155 |
|
|
} |