-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmain.cpp
228 lines (210 loc) · 6.5 KB
/
main.cpp
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#include "main.h"
void filename_change_ext(char* dst,const char* src,const char* new_ext){
strcpy(dst,src);
char* ss=dst;
char *s=nullptr;
bool dirs=false;
for (ss=dst;*ss;ss++){
if (*ss=='.') s=ss;
}
if (!s) {s=dst+strlen(dst);strcat(s,".");}
if (!strlen(new_ext)) {
s[0]=0;}
else
strcpy(s+1,new_ext);
}
bool has_dir(const char* fn){
for (const char*s=fn; *s; s++){
if (*s=='/'||*s=='\\')
return true;
}
return false;
}
int compile_and_run(const char *buffer, const char* filename, const char* outname, int flags,char** capture_output){
Lexer src(buffer,filename);
auto node=parse_block(src,0,SEMICOLON,nullptr);
g_pRoot=node;
Scope global(0); global.m_node=(ExprBlock*)node; global.global=&global;
if (flags & B_AST){
node->dump(0);
}
node->gather_symbols(&global);
if (flags & B_DEFS){
global.dump(0);
}
//node->verify();
node->resolve_if(&global,nullptr,R_FORWARD_ONLY);// 1st pass just like c++
node->resolve_if(&global,nullptr,0); // this is temporary until we do it properly setting up constraint graph, flood-fill
// node->resolve_if(&global,nullptr,0); // this is temporary until we do it properly setting up constraint graph, flood-fill
if (flags & B_DEFS){
global.dump(0);
}
if (flags & B_TYPES) {
node->dump(0);
}
node->resolved=COMPLETE;
node->resolve(&global,nullptr,(flags&(B_EXECUTABLE|B_RUN|B_LLVM)?R_FINAL:0)|R_FORWARD_ONLY);// if we just want to dump/search, we dont fail for final errors.
if (flags & B_LLVM) {
output_code(stdout, &global,0,EMIT_ALL);
}
printf("%x\n",flags);
if (outname && (flags & (B_EXECUTABLE|B_RUN|B_LLVM))){
FILE* ofp=fopen(outname,"wb");
if (ofp){
output_code(ofp, &global);
fprintf(ofp,"\n;end");
fclose(ofp);
if (flags & (B_EXECUTABLE|B_RUN)) {
char exename[256];
char wdir[512];getcwd(wdir,512);
filename_change_ext(exename,outname,"");
dbg(printf("invocation: wd=%s f=%s o=%s\n e=%s\n",wdir, filename, outname,exename));
char compile_cmd[512]; sprintf(compile_cmd,"clang++ %s -o %s", outname, exename);
if (flags & B_VERBOSE)printf("\nllvm src=%s\n executable=%s\nflags %x\n",outname,exename, flags);
if (flags & B_VERBOSE)printf("\n%s\n",compile_cmd);
auto ret= system(compile_cmd);
if (!ret && (flags & B_RUN)) {
if (flags & B_VERBOSE)printf("compiled ok, running executable %s \n", exename);
char invoke[512];snprintf(invoke,512,"%s%s",has_dir(exename)?"":"./",exename);
dbg(printf("invocation: %s\npwd=%s\n",invoke,wdir));
if (!capture_output){
return system(invoke);
} else{
auto fp=popen(invoke,"r");
int max_len=1024;
int i=0;
*capture_output=(char*)malloc(max_len);
char* dst=*capture_output;
int c;
while (0!=(c=getc(fp))){
if(c==EOF) break;
ASSERT(i<max_len-1);
i++;
putc(c,stdout);
*dst++=(char)c;
}
*dst++=0;
pclose(fp);
return 0;
}
return 0;
}
return ret;
}
} else {
printf("can't open output file %s\n",outname);
return -1;
}
}
return 0;
}
int compile_source_file(const char* filename, int options) {
char outname[256];
filename_change_ext(outname,filename,"ll");
dbg(options|=B_VERBOSE);
if (options & B_VERBOSE)printf("compiling %s\n -> %s\n",filename,outname);
auto fp=fopen(filename,"rb");
if (fp){
fseek(fp,0,SEEK_END); auto sz=ftell(fp); fseek(fp,0,SEEK_SET);
char* buffer = (char*)malloc(sz+1);
fread((void*)buffer,1,sz,fp);
buffer[sz]=0;
fclose(fp);
int ret=compile_and_run(buffer,filename,outname,options,nullptr);
free((void*)buffer);
return ret;
} else{
printf("can't open %s\n",filename);
return -1;
}
}
template<typename X,typename Y>
struct Union{
int tag;
union {X x; Y y;};
template<class FX,class FY,class R> R map(std::function<R(X)> fx,std::function<R(Y)> fy){
if (tag==0) return fx(x);
else return fy(y);
}
};
// Union<int,float> u;
// This is the sort of thing we want our language to handle - works fine in Rust.
// C++ can't infer through to 'R' from the given 'function types', even less so with poly lambdas.
// auto x=u.map([](int x)->int{return 0;}, [](float x)->int{return 1;});
// printf("%d x\n",x);
Option g_Options[]={
{'a',0,B_AST,"show AST"},
{'t',0,B_TYPES,"dump AST annotated with types"},
{'d',0,B_DEFS,"dump definitions"},
{'g',0,B_GENERICS,"dump generic type info"},
{'l',0,B_LLVM,"emit LLVM source"},
{'r',0,B_RUN|B_EXECUTABLE,"build & run"},
{'e',0,B_EXECUTABLE,"compile executable"},
{'v',0,B_VERBOSE,"verbose mode"},
{'T',0,0,"run tests"},
{'Y',0,0,"run first test, show types only"},
{'h',0,0,"help"},
{0,0,0,0}
};
void dump_help(){
printf("embryonic C++/Rust hybrid language\n");
printf("(we dont even have a name yet)\n");
printf("to run: \n");
printf(" hack srcfile [-options]\n");
printf("default is compile and run. -e to generate exe and not run.\n");
printf(" \n");
for (auto opt=g_Options;opt->name;opt++){
printf("%c - %s\n",opt->name,opt->help);
}
}
Vec<int> mk_list(){
Vec<int> tmp;
tmp.resize(4);
tmp[0]=0;
tmp[1]=1;
tmp[2]=2;
tmp[3]=3;
return tmp;
}
int main(int argc, const char** argv) {
// C++'s behaviour is good.
// value by default, moves from 'rvalues'
// what's not to like?
// SO in short you just need R-Value References, exactly like C++.
auto tmp=mk_list();
auto x=Vec<int>(mk_list(),4);
auto z=mk_list()+4;
dbg(printf("compiled with debug level=%d\n", DEBUG));
ASSERT(!strcmp(str(OPEN_PAREN),"(") && !strcmp(str(ASSIGN),"=")&& !strcmp(str(UNDERSCORE),"_") && !strcmp(str(OPEN_TYPARAM),"<[")&& "string table alignment?")
dbg_strings("paren=%s %s\nprecedences: ->%d *%d +%d &%d \n", str(OPEN_PAREN),str(CLOSE_PAREN),precedence(ARROW),precedence(MUL),precedence(ADD),precedence(AND));
// compile_source_file("~/hack/test_hack/prog.rs",0xf);
int options=0,given_opts=0;
for (auto i=1; i<argc; i++) {
const char* a=argv[i];
if (a[0]=='-'){
for (auto j=1; a[j];j++){
if (a[j]=='h') dump_help();
if (a[j]=='T') run_tests(B_AST|B_DEFS|B_TYPES|B_RUN);
if (a[j]=='Y') run_tests(B_AST|B_DEFS|B_TYPES,1);
for (auto opt=g_Options;opt->name;opt++){
if (opt->name==a[j]) {options&=~opt->clear;options|=opt->set;}
}
}
}
}
if (!options){
options=B_RUN|B_EXECUTABLE;
}
for (auto i=1; i<argc; i++) {
if (argv[i][0]!='-') {
if (options & B_VERBOSE)
printf("compile src file %s with options %x\n",argv[i],options);
compile_source_file(argv[i],options);
}
}
if (argc<=1) {
dump_help();
dbg(printf("no sources given so running inbuilt tests.\n"));
dbg(run_tests(B_AST|B_DEFS|B_TYPES|B_RUN));
}
}