ArkScript
A small, lisp-inspired, functional scripting language
Welder.cpp
Go to the documentation of this file.
1#include <Ark/Constants.hpp>
3
8#include <Ark/Utils/Files.hpp>
12
13#include <cassert>
14#include <sstream>
15#include <fmt/ostream.h>
16
17namespace Ark
18{
19 Welder::Welder(const unsigned debug, const std::vector<std::filesystem::path>& lib_env, const uint16_t features) :
20 m_lib_env(lib_env), m_features(features),
21 m_computed_ast(internal::NodeType::Unused),
22 m_parser(debug),
23 m_import_solver(debug, lib_env),
24 m_macro_processor(debug),
25 m_ast_optimizer(debug),
26 m_name_resolver(debug),
27 m_logger("Welder", debug),
28 m_lowerer(debug),
29 m_ir_optimizer(debug),
30 m_ir_compiler(debug)
31 {}
32
33 void Welder::registerSymbol(const std::string& name)
34 {
35 m_name_resolver.addDefinedSymbol(name, /* is_mutable= */ false);
36 }
37
38 bool Welder::computeASTFromFile(const std::string& filename)
39 {
40 m_root_file = std::filesystem::path(filename);
41 const std::string code = Utils::readFile(filename);
42
43 return computeAST(filename, code);
44 }
45
46 bool Welder::computeASTFromString(const std::string& code)
47 {
48 m_root_file = std::filesystem::current_path(); // No filename given, take the current working directory
49
50 return computeAST(ARK_NO_NAME_FILE, code);
51 }
52
53 bool Welder::computeASTFromStringWithKnownSymbols(const std::string& code, const std::vector<std::string>& symbols)
54 {
55 m_root_file = std::filesystem::current_path(); // No filename given, take the current working directory
56
57 for (const std::string& sym : symbols)
58 m_name_resolver.addDefinedSymbol(sym, /* is_mutable= */ true);
59 return computeAST(ARK_NO_NAME_FILE, code);
60 }
61
63 {
64 try
65 {
68
69 if ((m_features & FeatureIROptimizer) != 0)
70 {
73 }
74
77
78 if ((m_features & FeatureDumpIR) != 0)
80
81 return true;
82 }
83 catch (const CodeError& e)
84 {
86 throw;
87
89 return false;
90 }
91 }
92
93 bool Welder::generateBytecodeUsingTables(const std::vector<std::string>& symbols, const std::vector<Value>& constants, const std::size_t start_page_at_offset)
94 {
95 std::vector<internal::ValTableElem> values;
96 for (const Value& constant : constants)
97 {
98 switch (constant.valueType())
99 {
101 values.emplace_back(constant.number());
102 break;
103
105 values.emplace_back(constant.string());
106 break;
107
109 values.emplace_back(static_cast<std::size_t>(constant.pageAddr()));
110 break;
111
112 default:
113 assert(false && "This should not be possible to have a constant that isn't a Number, a String or a PageAddr");
114 break;
115 }
116 }
117
118 m_lowerer.addToTables(symbols, values);
119 m_lowerer.offsetPagesBy(start_page_at_offset);
120 return generateBytecode();
121 }
122
123 bool Welder::saveBytecodeToFile(const std::string& filename)
124 {
125 m_logger.info("Final bytecode size: {}B", m_bytecode.size() * sizeof(uint8_t));
126
127 if (m_bytecode.empty())
128 return false;
129
130 std::ofstream output(filename, std::ofstream::binary);
131 output.write(
132 reinterpret_cast<char*>(&m_bytecode[0]),
133 static_cast<std::streamsize>(m_bytecode.size() * sizeof(uint8_t)));
134 output.close();
135 return true;
136 }
137
149
150 const internal::Node& Welder::ast() const noexcept
151 {
152 return m_computed_ast;
153 }
154
155 std::string Welder::textualIR() const noexcept
156 {
157 std::stringstream stream;
159 return stream.str();
160 }
161
162 const bytecode_t& Welder::bytecode() const noexcept
163 {
164 return m_bytecode;
165 }
166
168 {
169 std::filesystem::path path = m_root_file;
170 if (is_directory(m_root_file))
171 path = path / ARK_CACHE_DIRNAME / "output.ark.ir";
172 else
173 {
174 const auto filename = path.filename().replace_extension(".ark.ir");
175 path.remove_filename();
176 path = path / ARK_CACHE_DIRNAME / filename;
177 }
178
179 std::ofstream output(path);
181 output.close();
182 }
183
184 bool Welder::computeAST(const std::string& filename, const std::string& code)
185 {
186 try
187 {
188 m_parser.process(filename, code);
190
191 if ((m_features & FeatureImportSolver) != 0)
192 {
196 }
197
199 {
202 }
203
204 if ((m_features & FeatureNameResolver) != 0)
205 {
208 }
209
210 if ((m_features & FeatureASTOptimizer) != 0)
211 {
214 }
215
216 return true;
217 }
218 catch (const CodeError& e)
219 {
221 throw;
222
223 if (filename != ARK_NO_NAME_FILE)
225 else
227 return false;
228 }
229 }
230}
Constants used by ArkScript.
#define ARK_NO_NAME_FILE
Definition Constants.hpp:28
#define ARK_CACHE_DIRNAME
Definition Constants.hpp:27
Tools to report code errors nicely to the user.
ArkScript homemade exceptions.
Lots of utilities about the filesystem.
Handle imports, resolve them with modules and everything.
Resolves names and fully qualify them in the AST (prefixing them with the package they are from)
Optimizes a given ArkScript AST.
Handles the macros and their expansion in ArkScript source code.
Default value type handled by the virtual machine.
In charge of welding everything needed to compile code.
bool computeAST(const std::string &filename, const std::string &code)
Definition Welder.cpp:184
internal::ImportSolver m_import_solver
Definition Welder.hpp:124
internal::Node m_computed_ast
Definition Welder.hpp:121
Welder(unsigned debug, const std::vector< std::filesystem::path > &lib_env, uint16_t features=DefaultFeatures)
Create a new Welder.
Definition Welder.cpp:19
internal::IROptimizer m_ir_optimizer
Definition Welder.hpp:131
void registerSymbol(const std::string &name)
Register a symbol as a global in the compiler.
Definition Welder.cpp:33
bool computeASTFromString(const std::string &code)
Definition Welder.cpp:46
std::string textualIR() const noexcept
Definition Welder.cpp:155
internal::Logger m_logger
Definition Welder.hpp:129
bool generateBytecodeUsingTables(const std::vector< std::string > &symbols, const std::vector< Value > &constants, std::size_t start_page_at_offset)
Compile the AST processed by computeASTFromFile / computeASTFromString, with prefilled symbols and co...
Definition Welder.cpp:93
std::vector< internal::IR::Block > m_ir
Definition Welder.hpp:119
internal::NameResolutionPass m_name_resolver
Definition Welder.hpp:127
std::filesystem::path m_root_file
Definition Welder.hpp:117
internal::ASTLowerer m_lowerer
Definition Welder.hpp:130
const bytecode_t & bytecode() const noexcept
Definition Welder.cpp:162
internal::Parser m_parser
Definition Welder.hpp:123
internal::IRCompiler m_ir_compiler
Definition Welder.hpp:132
internal::MacroProcessor m_macro_processor
Definition Welder.hpp:125
void redirectLogsTo(std::ostream &os)
Redirect the logs to a given stream.
Definition Welder.cpp:138
bool saveBytecodeToFile(const std::string &filename)
Save the generated bytecode to a given file.
Definition Welder.cpp:123
bool generateBytecode()
Compile the AST processed by computeASTFromFile / computeASTFromString.
Definition Welder.cpp:62
bool computeASTFromFile(const std::string &filename)
Definition Welder.cpp:38
uint16_t m_features
Definition Welder.hpp:115
internal::Optimizer m_ast_optimizer
Definition Welder.hpp:126
bool computeASTFromStringWithKnownSymbols(const std::string &code, const std::vector< std::string > &symbols)
Compile code from a string, with a set of known symbols (useful for the debugger)
Definition Welder.cpp:53
void dumpIRToFile() const
Definition Welder.cpp:167
bytecode_t m_bytecode
Definition Welder.hpp:120
const internal::Node & ast() const noexcept
Definition Welder.cpp:150
const std::vector< ValTableElem > & values() const noexcept
Return the value table pre-computed.
void process(Node &ast)
Start the compilation.
void offsetPagesBy(std::size_t offset)
Start bytecode pages at a given offset (by default, 0)
const std::vector< IR::Block > & intermediateRepresentation() const noexcept
Return the IR blocks (one per scope)
const std::vector< std::string > & symbols() const noexcept
Return the symbol table pre-computed.
void addToTables(const std::vector< std::string > &symbols, const std::vector< ValTableElem > &constants)
Pre-fill tables (used by the debugger)
void dumpToStream(std::ostream &stream) const
Dump the IR given to process to an output stream.
const bytecode_t & bytecode() const noexcept
Return the constructed bytecode object.
void process(const std::vector< IR::Block > &pages, const std::vector< std::string > &symbols, const std::vector< ValTableElem > &values)
Turn a given IR into bytecode.
const std::vector< IR::Block > & intermediateRepresentation() const noexcept
Return the IR blocks (one per scope)
void process(const std::vector< IR::Block > &pages, const std::vector< std::string > &symbols, const std::vector< ValTableElem > &values)
Turn a given IR into bytecode.
const Node & ast() const noexcept
ImportSolver & setup(const std::filesystem::path &root, const std::vector< Import > &origin_imports)
Configure the ImportSolver.
void process(const Node &origin_ast)
void info(const char *fmt, Args &&... args)
Write an info level log using fmtlib.
Definition Logger.hpp:63
void configureOutputStream(std::ostream *os)
Set a custom output stream to use for warnings. This will disable colors.
Definition Logger.hpp:147
const Node & ast() const noexcept
Return the modified AST.
Definition Processor.cpp:45
void process(const Node &ast)
Send the complete AST and work on it.
Definition Processor.cpp:30
const Node & ast() const noexcept
Unused overload that return the input AST (untouched as this pass only generates errors)
void process(const Node &ast)
Start visiting the given AST, checking for mutability violation and unbound variables.
std::string addDefinedSymbol(const std::string &sym, bool is_mutable)
Register a symbol as defined, so that later we can throw errors on undefined symbols.
A node of an Abstract Syntax Tree for ArkScript.
Definition Node.hpp:32
const Node & ast() const noexcept
Returns the modified AST.
Definition Optimizer.cpp:30
void process(const Node &ast)
Send the AST to the optimizer, then run the different optimization strategies on it.
Definition Optimizer.cpp:11
void process(const std::string &filename, const std::string &code)
Parse the given code.
Definition Parser.cpp:51
const Node & ast() const noexcept
Definition Parser.cpp:92
const std::vector< Import > & imports() const
Definition Parser.cpp:97
void configureLogger(std::ostream &os)
Set a custom output stream for the logger.
Definition Pass.cpp:10
ARK_API void generateWithCode(const CodeError &e, const std::string &code, std::ostream &os=std::cerr, bool colorize=true)
ARK_API void generate(const CodeError &e, std::ostream &os=std::cerr, bool colorize=true)
Generate a diagnostic from an error and print it to the standard error output.
std::string readFile(const std::string &name)
Helper to read a file.
Definition Files.hpp:47
NodeType
The different node types available.
Definition Common.hpp:44
constexpr uint16_t FeatureImportSolver
Definition Constants.hpp:54
constexpr uint16_t FeatureIROptimizer
Definition Constants.hpp:57
constexpr uint16_t FeatureMacroProcessor
Definition Constants.hpp:55
constexpr uint16_t FeatureTestFailOnException
This feature should only be used in tests, to disable diagnostics generation and enable exceptions to...
Definition Constants.hpp:64
std::vector< uint8_t > bytecode_t
Definition Common.hpp:22
constexpr uint16_t FeatureASTOptimizer
Disabled by default because embedding ArkScript should not prune nodes from the AST ; it is active in...
Definition Constants.hpp:56
constexpr uint16_t FeatureDumpIR
Definition Constants.hpp:62
constexpr uint16_t FeatureNameResolver
Definition Constants.hpp:58
CodeError thrown by the compiler (parser, macro processor, optimizer, and compiler itself)