-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathBuilder.cpp
More file actions
178 lines (155 loc) · 5.08 KB
/
Copy pathBuilder.cpp
File metadata and controls
178 lines (155 loc) · 5.08 KB
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
#include <algorithm>
#include <fstream>
#include <sstream>
#include <string>
#ifdef __WIN32__
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "Builder.h"
#include "CompilationProcess.h"
#include "FileUtil.h"
#include "Parser.h"
#include "QuoteUtil.h"
#include "Tokenizer.h"
#include "Transpiler.h"
// Where we store all the build directories
static const std::string BUILD_ROOT = "/tmp/fetlang_build";
// Four directory combinations for fetishes: debug, optimized lto, lto only,
// optimized only
// The prefix for each combination. Or, in the case of a debug build, this is
// just the directory name
static const std::string FETISH_DIR_BASE = "/fetish_obj";
// Add this to FETISH_DIR_BASE for -O
static const std::string FETISH_OPT_SUFFIX = "_optimized";
// Use this to FETISH_DIR_BASE for --lto
static const std::string FETISH_LTO_SUFFIX = "_lto";
// Where the compiled .fet file goes
static const std::string STAGE_DIR = "/output";
// Default output names
#ifndef __WIN32__
static const std::string DEFAULT_OUTPUT = "a.out";
#else
static const std::string DEFAULT_OUTPUT = "a.exe";
#endif
static const std::string DEFAULT_C_OUTPUT = "a.c"; // for when invoked with -c
Builder::Builder() {
// Just explicitly setting our defaults
optimization = false;
link_time_optimization = false;
compilation = true;
show_tokens = false;
show_tree = false;
source_path = "";
destination_path = DEFAULT_OUTPUT;
build_path = BUILD_ROOT;
}
std::string Builder::transpile() const {
// get source code
std::string source = FileUtil::getFileContents(source_path);
// Tokenize
Tokenizer tokenizer(source);
tokenizer.tokenize();
std::vector<Token> tokens = tokenizer.getTokens();
if (show_tokens) {
std::cout << "Displaying tokens:\n";
for (const Token& token : tokens) {
std::cout << token << "\n";
}
}
// Parse
Parser parser(tokens, tokenizer.getLineIndents());
parser.formTree();
if (show_tree) {
std::cout << "Displaying tree:\n";
parser.getTree().display();
}
// Transpile
Transpiler transpiler(parser.getTree(), parser.getVariables());
return transpiler.transpile();
}
void Builder::build() {
std::string c_code = transpile();
CompilationProcess comp_proc;
// No compilation, just output C code
if (!compilation) {
// Should end with ".c"
if (destination_path == DEFAULT_OUTPUT) {
destination_path = DEFAULT_C_OUTPUT;
}
// Write the c code
std::ofstream outfile(destination_path);
if (!(outfile << c_code)) {
outfile.close();
throw FetlangException("Could not write to " + destination_path);
}
outfile.close();
// And done with that
return;
}
// Okay, we do compiling
// Let's compile fetishes first
// Get the general fetish path
std::string fetish_path = build_path + FETISH_DIR_BASE;
if (optimization) fetish_path += FETISH_OPT_SUFFIX;
if (link_time_optimization) fetish_path += FETISH_LTO_SUFFIX;
// Let's make sure the build directories exist
FileUtil::ensureDirectoryExists(fetish_path);
FileUtil::ensureDirectoryExists(build_path + STAGE_DIR);
// General include paths
std::vector<std::string> include_paths;
for (const Fetish& fetish : manager.getFetishes()) {
std::string inc_path = fetish.getIncludePath();
if (std::find(include_paths.begin(), include_paths.end(), inc_path) ==
include_paths.end()) {
inc_path = FileUtil::getParentPath(inc_path);
inc_path = FileUtil::getParentPath(inc_path) + "/";
include_paths.push_back(inc_path);
}
}
if (include_paths.empty()) {
throw FetlangException("Include paths should not be empty");
}
// And compile each fetish
std::vector<std::string> all_objects;
for (const Fetish& fetish : manager.getFetishes()) {
FileUtil::ensureDirectoryExists(fetish_path + "/" + fetish.getName());
// Each source file gets compiled independently
for (const std::string& source_file : fetish.getSources()) {
all_objects.push_back(fetish_path + "/" + fetish.getName() + "/" + source_file + ".o");
std::string source_path = fetish.getSourcePath() + source_file;
if (!FileUtil::fileExists(all_objects.back())) {
comp_proc.clear()
.setOptimization(optimization)
.setLinkTimeOptimization(link_time_optimization)
.addIncludeDirectories(include_paths)
.addIncludeDirectory(fetish.getIncludePath())
.addLibraries(fetish.getLibraries())
.compile({source_path}, all_objects.back());
}
}
}
// Write the generated C file
std::string c_file_path = build_path + STAGE_DIR + "/stage.c";
std::ofstream generated_c_file(c_file_path);
generated_c_file << c_code;
generated_c_file.close();
all_objects.push_back(c_file_path + ".o");
// Compile the generated C file
comp_proc.clear()
.addIncludeDirectories(include_paths)
.setOptimization(optimization)
.setLinkTimeOptimization(link_time_optimization)
.compile({c_file_path}, all_objects.back());
// And link to create the output
comp_proc.clear()
.setOptimization(optimization)
.setLinkTimeOptimization(link_time_optimization)
.setLanguage("c++")
.link(all_objects, destination_path);
}
void Builder::clean() const {
FileUtil::ensureDirectoryDoesNotExist(build_path);
FileUtil::ensureDirectoryExists(build_path);
}