Yume
vals.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "ast/ast.hpp"
4#include "ast/parser.hpp"
6#include "token.hpp"
7#include "ty/substitution.hpp"
8#include "ty/type.hpp"
9#include "util.hpp"
10#include <algorithm>
11#include <compare>
12#include <functional>
13#include <iosfwd>
14#include <llvm/Support/Casting.h>
15#include <llvm/Support/raw_ostream.h>
16#include <map>
17#include <memory>
18#include <stdexcept>
19#include <string>
20#include <utility>
21#include <variant>
22#include <vector>
23
24namespace llvm {
25class Function;
26class Value;
27class GlobalVariable;
28} // namespace llvm
29
30namespace yume {
31
32struct FnArg {
34 string name;
35 const ast::AST& ast;
36
37 FnArg(ty::Type type, string name, const ast::AST& ast) : type{type}, name{move(name)}, ast{ast} {};
38};
39
41struct Def : public Def_t {
42 using Def_t::Def_t;
43};
44
45/// A function declaration in the compiler.
46/**
47 * The primary use of this structure is to bind together the AST declaration of a function (`ast::FnDecl`) and the
48 * bytecode body of a function (`llvm::Function`).
49 * A function template may also be a `Fn`. Since a template doesn't actually have a body, its `m_llvm_fn` is `nullptr`.
50 * All the instantiations of a template are stored in `instantiations`.
51 */
52struct Fn {
53 /// The ast node that defines this declaration.
56 /// If this function is in the body of a struct, this points to its type. Used for the `self` type.
57 optional<ty::Type> self_ty{};
58 /// The program this declaration is a member of.
60
61 vector<unique_ptr<ty::Generic>> primary_generics{};
62 /// If this is an instantiation of a template, a mapping between type variables and their substitutions.
64 /// The LLVM function definition corresponding to this function or constructor.
65 llvm::Function* llvm{};
66 std::unordered_map<Substitutions, unique_ptr<Fn>> instantiations{};
67
68 Fn(Def def, ast::Program* member, optional<ty::Type> parent, Substitutions subs)
69 : def{def}, self_ty{parent}, member{member}, subs(move(subs)) {}
70
71 Fn(Def def, ast::Program* member, optional<ty::Type> parent, nullable<Substitutions*> parent_subs,
72 vector<GenericKey> generic = {}, vector<unique_ptr<ty::Generic>> primary_generics = {})
73 : def{def}, self_ty{parent}, member{member},
74 primary_generics{move(primary_generics)}, subs{move(generic), this->primary_generics, parent_subs} {}
75
76 [[nodiscard]] auto fn_body() -> ast::FnDecl::Body&;
77 [[nodiscard]] auto compound_body() -> ast::Compound&;
78 [[nodiscard]] auto ast() const -> const ast::Stmt&;
79 [[nodiscard]] auto ast() -> ast::Stmt&;
80 [[nodiscard]] auto get_self_ty() const -> optional<ty::Type> { return self_ty; }
81 [[nodiscard]] auto get_subs() const -> const Substitutions& { return subs; }
82 [[nodiscard]] auto get_subs() -> Substitutions& { return subs; }
83
84 [[nodiscard]] auto ret() const -> optional<ty::Type>;
85 [[nodiscard]] auto arg_count() const -> size_t;
86 [[nodiscard]] auto arg_types() const -> vector<ty::Type>;
87 [[nodiscard]] auto arg_names() const -> vector<string>;
88 [[nodiscard]] auto arg_nodes() const -> const vector<ast::TypeName>&;
89 [[nodiscard]] auto args() const -> vector<FnArg>;
90 [[nodiscard]] auto varargs() const -> bool;
91 [[nodiscard]] auto primitive() const -> bool;
92 [[nodiscard]] auto abstract() const -> bool;
93 [[nodiscard]] auto extern_decl() const -> bool;
94 [[nodiscard]] auto local() const -> bool;
95 [[nodiscard]] auto extern_linkage() const -> bool;
96 void make_extern_linkage(bool value = true);
97 [[nodiscard]] auto has_annotation(const string& name) const -> bool;
98
99 [[nodiscard]] auto name() const noexcept -> string;
100
101 [[nodiscard]] auto get_or_create_instantiation(Substitutions& subs) noexcept -> std::pair<bool, Fn&>;
102 [[nodiscard]] auto create_instantiation(Substitutions& subs) noexcept -> Fn&;
103
104private:
105 template <std::invocable<ast::TypeName&> F, typename..., typename T = std::invoke_result_t<F, ast::TypeName&>>
106 auto visit_map_args(F fn) const -> std::vector<T> {
107 std::vector<T> vec = {};
108 vec.reserve(arg_count());
109 def.visit([&](auto* ast) {
110 for (auto& i : ast->args)
111 vec.emplace_back(std::move<T>(fn(i)));
112 });
113 return vec;
114 }
115};
116
118 string name;
119 vector<ty::Type> args;
120 optional<ty::Type> ret;
121
122 [[nodiscard]] auto operator==(const VTableEntry& other) const noexcept -> bool {
123 auto args = llvm::zip(this->args, other.args);
124 auto opaque_eq = [](const auto& p) { return std::get<0>(p).opaque_equal(std::get<1>(p)); };
125 return this->name == other.name && std::all_of(args.begin(), args.end(), opaque_eq) &&
126 this->ret.has_value() == other.ret.has_value() && (!this->ret || this->ret->opaque_equal(*other.ret));
127 };
128};
129
130/// A struct declaration in the compiler.
131/**
132 * Very similar to `Fn`, the primary use of this structure is to bind together the AST declaration of a struct
133 * (`ast::StructDecl`) and the type this struct defines. A struct template may also be a `Struct`. All the
134 * instantiations of a template are stored in `instantiations`.
135 */
136struct Struct {
138 /// The type of this struct. Used for the `self` type.
139 optional<ty::Type> self_ty{};
140 /// The program this declaration is a member of.
142
143 vector<unique_ptr<ty::Generic>> primary_generics{};
144 /// If this is an instantiation of a template, a mapping between type variables and their substitutions.
146 std::unordered_map<Substitutions, unique_ptr<Struct>> instantiations{};
147 std::vector<VTableEntry> vtable_members{};
149
150 Struct(ast::StructDecl& ast_decl, ast::Program* member, optional<ty::Type> type, Substitutions subs) noexcept
151 : st_ast(ast_decl), self_ty(type), member(member), subs(move(subs)) {}
152
153 Struct(ast::StructDecl& ast_decl, ast::Program* member, optional<ty::Type> type, nullable<Substitutions*> parent_subs,
154 vector<GenericKey> generic = {}, vector<unique_ptr<ty::Generic>> primary_generics = {}) noexcept
155 : st_ast(ast_decl), self_ty{type}, member{member},
156 primary_generics{move(primary_generics)}, subs{move(generic), this->primary_generics, parent_subs} {}
157
158 [[nodiscard]] auto ast() const noexcept -> const auto& { return st_ast; }
159 [[nodiscard]] auto ast() noexcept -> auto& { return st_ast; }
160 [[nodiscard]] auto body() const noexcept -> const auto& { return st_ast.body; }
161 [[nodiscard]] auto body() noexcept -> auto& { return st_ast.body; }
162 [[nodiscard]] auto get_self_ty() const noexcept -> optional<ty::Type> { return self_ty; };
163 [[nodiscard]] auto get_subs() const -> const Substitutions& { return subs; }
164 [[nodiscard]] auto get_subs() -> Substitutions& { return subs; }
165 [[nodiscard]] auto has_annotation(const string& name) const -> bool { return st_ast.annotations.contains(name); };
166
167 [[nodiscard]] auto name() const noexcept -> string;
168
169 [[nodiscard]] auto get_or_create_instantiation(Substitutions& subs) noexcept -> std::pair<bool, Struct&>;
170 [[nodiscard]] auto create_instantiation(Substitutions& subs) noexcept -> Struct&;
171};
172
173/// A constant declaration in the compiler.
174struct Const {
176 /// If this function is in the body of a struct, this points to its type.
177 optional<ty::Type> self_ty;
178 /// The program this declaration is a member of.
180 llvm::GlobalVariable* llvm{};
181
182 Const(ast::ConstDecl& ast_decl, ast::Program* member = nullptr, optional<ty::Type> parent = std::nullopt) noexcept
183 : cn_ast(ast_decl), self_ty(parent), member(member) {}
184
185 [[nodiscard]] auto ast() const noexcept -> const auto& { return cn_ast; }
186 [[nodiscard]] auto ast() noexcept -> auto& { return cn_ast; }
187 [[nodiscard]] auto get_self_ty() const noexcept -> optional<ty::Type> { return self_ty; };
188
189 [[nodiscard]] auto name() const noexcept -> string;
190 [[nodiscard]] auto referred_to_by(const ast::ConstExpr& expr) const -> bool {
191 if (name() != expr.name)
192 return false;
193
194 if (self_ty.has_value() != expr.parent.has_value())
195 return false;
196
197 if (self_ty.has_value() && expr.parent.has_value())
198 return self_ty->name() == expr.parent.value();
199
200 return true;
201 }
202};
203
205
206/// A common base between declarations in the compiler: `Fn`, `Struct` and `Const`. Its value may also be absent
207/// (`std::monostate`).
208struct DeclLike : public DeclLike_t {
209public:
211
212 [[nodiscard]] auto fully_substituted() const noexcept -> bool {
213 if (const auto* subs = this->subs(); subs != nullptr)
214 return subs->fully_substituted();
215 return true;
216 }
217
218 [[nodiscard]] auto subs() const noexcept -> const Substitutions* {
219 return visit([](std::monostate /*absent*/) noexcept -> const Substitutions* { return nullptr; },
220 [](Const* /*cn*/) noexcept -> const Substitutions* { return nullptr; },
221 [](auto* decl) noexcept -> const Substitutions* {
222 if (decl == nullptr)
223 return nullptr;
224 return &decl->get_subs();
225 });
226 };
227
228 [[nodiscard]] auto subs() noexcept -> Substitutions* {
229 return visit([](std::monostate /*absent*/) noexcept -> Substitutions* { return nullptr; },
230 [](Const* /*cn*/) noexcept -> Substitutions* { return nullptr; },
231 [](auto* decl) noexcept -> Substitutions* {
232 if (decl == nullptr)
233 return nullptr;
234 return &decl->get_subs();
235 });
236 };
237
238 [[nodiscard]] auto ast() const noexcept -> const ast::AST* {
239 return visit([](std::monostate /*absent*/) noexcept -> const ast::AST* { return nullptr; },
240 [](const auto* decl) noexcept -> const ast::AST* { return &decl->ast(); });
241 };
242
243 [[nodiscard]] auto ast() noexcept -> ast::AST* {
244 return visit([](std::monostate /*absent*/) noexcept -> ast::AST* { return nullptr; },
245 [](auto* decl) noexcept -> ast::AST* { return &decl->ast(); });
246 };
247
248 [[nodiscard]] auto self_ty() const noexcept -> optional<ty::Type> {
249 return visit([](std::monostate /*absent*/) noexcept { return optional<ty::Type>{}; },
250 [](const auto* decl) noexcept { return decl->get_self_ty(); });
251 };
252
253 [[nodiscard]] auto opaque_self() const noexcept -> bool {
254 return visit([](Fn* fn) noexcept { return fn->abstract() || fn->has_annotation(ast::FnDecl::ANN_OVERRIDE); },
255 [](auto&& /* default */) noexcept { return false; });
256 };
257};
258
259struct InScope;
260
261/// A value of a complied expression.
262struct Val {
263 llvm::Value* llvm{};
264 InScope* scope{};
265
266 /* implicit */ Val(llvm::Value* llvm_val) noexcept : llvm(llvm_val) {}
267 Val(llvm::Value* llvm_val, InScope* scope_val) noexcept : llvm(llvm_val), scope(scope_val) {}
268
269 /* implicit */ operator llvm::Value*() const { return llvm; }
270};
271
272/// A local variable in function scope. Used to track destructing when the scope ends.
273struct InScope {
275 const ast::AST& ast;
276 /// Whether the local scope "owns" the variable. Unowned variables are not destructed at the end of the scope.
277 bool owning{};
278};
279
280/// A source file with its associated Syntax Tree.
282 fs::path path;
283 string name;
284 vector<yume::Token> tokens;
286 unique_ptr<ast::Program> program;
288
289 static auto name_or_stdin(const fs::path& path) -> string { return path.empty() ? "<stdin>"s : path.native(); }
290
291 SourceFile(std::istream& in, fs::path path)
292 : path(move(path)), name(name_or_stdin(this->path)),
293 tokens(yume::tokenize(in, this->name)), iterator{tokens.begin(), tokens.end()} {
294#ifdef YUME_SPEW_LIST_TOKENS
295 llvm::outs() << "tokens:\n";
296 for (auto& i : tokens)
297 llvm::outs() << " " << i << "\n";
298 llvm::outs() << "\n";
299 llvm::outs().flush();
300#endif
301
302 program = ast::Program::parse(iterator, this->notes);
303 }
304};
305
306} // namespace yume
All nodes in the AST tree of the program inherit from this class.
Definition: ast.hpp:224
An iterator-like holding Tokens, used when parsing.
Definition: parser.hpp:31
A function pointer type.
Definition: type.hpp:129
A "qualified" type, with a non-stackable qualifier, i.e. mut.
Definition: type_base.hpp:66
string_view end
Definition: errors.cpp:42
Definition: ast.hpp:20
Definition: ast.cpp:8
visitable_variant< ast::FnDecl *, ast::CtorDecl *, ast::LambdaExpr * > Def_t
Definition: vals.hpp:40
T nullable
Definition: util.hpp:72
auto tokenize(std::istream &in, const string &source_file) -> vector< Token >
Consume the contents of the input stream and create corresponding tokens, ignoring insignificant whit...
Definition: token.cpp:282
visitable_variant< std::monostate, Fn *, Struct *, Const * > DeclLike_t
Definition: vals.hpp:204
A constant declaration in the compiler.
Definition: vals.hpp:174
auto get_self_ty() const noexcept -> optional< ty::Type >
Definition: vals.hpp:187
Const(ast::ConstDecl &ast_decl, ast::Program *member=nullptr, optional< ty::Type > parent=std::nullopt) noexcept
Definition: vals.hpp:182
optional< ty::Type > self_ty
If this function is in the body of a struct, this points to its type.
Definition: vals.hpp:177
auto ast() const noexcept -> const auto &
Definition: vals.hpp:185
auto ast() noexcept -> auto &
Definition: vals.hpp:186
ast::ConstDecl & cn_ast
Definition: vals.hpp:175
ast::Program * member
The program this declaration is a member of.
Definition: vals.hpp:179
A common base between declarations in the compiler: Fn, Struct and Const. Its value may also be absen...
Definition: vals.hpp:208
auto fully_substituted() const noexcept -> bool
Definition: vals.hpp:212
auto ast() noexcept -> ast::AST *
Definition: vals.hpp:243
auto subs() noexcept -> Substitutions *
Definition: vals.hpp:228
auto opaque_self() const noexcept -> bool
Definition: vals.hpp:253
auto subs() const noexcept -> const Substitutions *
Definition: vals.hpp:218
auto ast() const noexcept -> const ast::AST *
Definition: vals.hpp:238
auto self_ty() const noexcept -> optional< ty::Type >
Definition: vals.hpp:248
const ast::AST & ast
Definition: vals.hpp:35
string name
Definition: vals.hpp:34
ty::Type type
Definition: vals.hpp:33
FnArg(ty::Type type, string name, const ast::AST &ast)
Definition: vals.hpp:37
A function declaration in the compiler.
Definition: vals.hpp:52
ast::Program * member
The program this declaration is a member of.
Definition: vals.hpp:59
Fn(Def def, ast::Program *member, optional< ty::Type > parent, Substitutions subs)
Definition: vals.hpp:68
optional< ty::Type > self_ty
If this function is in the body of a struct, this points to its type. Used for the self type.
Definition: vals.hpp:57
auto arg_names() const -> vector< string >
Definition: vals.cpp:92
std::unordered_map< Substitutions, unique_ptr< Fn > > instantiations
Definition: vals.hpp:66
auto fn_body() -> ast::FnDecl::Body &
Definition: vals.cpp:134
auto create_instantiation(Substitutions &subs) noexcept -> Fn &
Definition: vals.cpp:20
Fn(Def def, ast::Program *member, optional< ty::Type > parent, nullable< Substitutions * > parent_subs, vector< GenericKey > generic={}, vector< unique_ptr< ty::Generic > > primary_generics={})
Definition: vals.hpp:71
auto primitive() const -> bool
Definition: vals.cpp:103
auto compound_body() -> ast::Compound &
Definition: vals.cpp:128
auto local() const -> bool
Definition: vals.cpp:112
Def def
The ast node that defines this declaration.
Definition: vals.hpp:54
auto extern_decl() const -> bool
Definition: vals.cpp:109
auto get_self_ty() const -> optional< ty::Type >
Definition: vals.hpp:80
auto arg_types() const -> vector< ty::Type >
Definition: vals.cpp:91
auto extern_linkage() const -> bool
Definition: vals.cpp:115
auto varargs() const -> bool
Definition: vals.cpp:100
auto get_subs() -> Substitutions &
Definition: vals.hpp:82
auto get_subs() const -> const Substitutions &
Definition: vals.hpp:81
auto abstract() const -> bool
Definition: vals.cpp:106
auto args() const -> vector< FnArg >
Definition: vals.cpp:96
auto arg_count() const -> size_t
Definition: vals.cpp:87
auto ast() const -> const ast::Stmt &
Definition: vals.cpp:74
void make_extern_linkage(bool value=true)
Definition: vals.cpp:123
Substitutions subs
If this is an instantiation of a template, a mapping between type variables and their substitutions.
Definition: vals.hpp:63
auto has_annotation(const string &name) const -> bool
Definition: vals.cpp:118
const ty::Function * fn_ty
Definition: vals.hpp:55
vector< unique_ptr< ty::Generic > > primary_generics
Definition: vals.hpp:61
auto arg_nodes() const -> const vector< ast::TypeName > &
Definition: vals.cpp:93
auto ret() const -> optional< ty::Type >
Definition: vals.cpp:78
auto name() const noexcept -> string
Definition: vals.cpp:64
auto get_or_create_instantiation(Substitutions &subs) noexcept -> std::pair< bool, Fn & >
Definition: vals.cpp:36
A local variable in function scope. Used to track destructing when the scope ends.
Definition: vals.hpp:273
const ast::AST & ast
Definition: vals.hpp:275
A source file with its associated Syntax Tree.
Definition: vals.hpp:281
vector< yume::Token > tokens
Definition: vals.hpp:284
string name
Definition: vals.hpp:283
static auto name_or_stdin(const fs::path &path) -> string
Definition: vals.hpp:289
SourceFile(std::istream &in, fs::path path)
Definition: vals.hpp:291
fs::path path
Definition: vals.hpp:282
ast::TokenIterator iterator
Definition: vals.hpp:285
unique_ptr< ast::Program > program
Definition: vals.hpp:286
A struct declaration in the compiler.
Definition: vals.hpp:136
Substitutions subs
If this is an instantiation of a template, a mapping between type variables and their substitutions.
Definition: vals.hpp:145
vector< unique_ptr< ty::Generic > > primary_generics
Definition: vals.hpp:143
auto name() const noexcept -> string
Definition: vals.cpp:68
auto has_annotation(const string &name) const -> bool
Definition: vals.hpp:165
ast::StructDecl & st_ast
Definition: vals.hpp:137
auto body() const noexcept -> const auto &
Definition: vals.hpp:160
auto get_subs() const -> const Substitutions &
Definition: vals.hpp:163
std::unordered_map< Substitutions, unique_ptr< Struct > > instantiations
Definition: vals.hpp:146
auto get_or_create_instantiation(Substitutions &subs) noexcept -> std::pair< bool, Struct & >
Definition: vals.cpp:56
auto body() noexcept -> auto &
Definition: vals.hpp:161
auto get_self_ty() const noexcept -> optional< ty::Type >
Definition: vals.hpp:162
auto get_subs() -> Substitutions &
Definition: vals.hpp:164
auto create_instantiation(Substitutions &subs) noexcept -> Struct &
Definition: vals.cpp:44
Struct(ast::StructDecl &ast_decl, ast::Program *member, optional< ty::Type > type, Substitutions subs) noexcept
Definition: vals.hpp:150
auto ast() const noexcept -> const auto &
Definition: vals.hpp:158
auto ast() noexcept -> auto &
Definition: vals.hpp:159
Struct(ast::StructDecl &ast_decl, ast::Program *member, optional< ty::Type > type, nullable< Substitutions * > parent_subs, vector< GenericKey > generic={}, vector< unique_ptr< ty::Generic > > primary_generics={}) noexcept
Definition: vals.hpp:153
std::vector< VTableEntry > vtable_members
Definition: vals.hpp:147
nullable< llvm::GlobalVariable * > vtable_memo
Definition: vals.hpp:148
optional< ty::Type > self_ty
The type of this struct. Used for the self type.
Definition: vals.hpp:139
ast::Program * member
The program this declaration is a member of.
Definition: vals.hpp:141
auto fully_substituted() const -> bool
vector< ty::Type > args
Definition: vals.hpp:119
auto operator==(const VTableEntry &other) const noexcept -> bool
Definition: vals.hpp:122
optional< ty::Type > ret
Definition: vals.hpp:120
A value of a complied expression.
Definition: vals.hpp:262
Val(llvm::Value *llvm_val) noexcept
Definition: vals.hpp:266
Val(llvm::Value *llvm_val, InScope *scope_val) noexcept
Definition: vals.hpp:267
A declaration of a constant (const).
Definition: ast.hpp:888
static constexpr auto ANN_OVERRIDE
Definition: ast.hpp:776
The top level structure of a file of source code.
Definition: ast.hpp:957
static auto parse(TokenIterator &tokens, diagnostic::NotesHolder &notes) -> unique_ptr< Program >
Definition: parser.cpp:913
A declaration of a struct (struct) or an interface (interface).
Definition: ast.hpp:847
std::unordered_set< string > annotations
Definition: ast.hpp:854
auto visit(Us... us) -> decltype(auto)
Definition: util.hpp:55