2023-01-09 03:24:10 +08:00
|
|
|
// Copyright (C) 2022-2023 Exaloop Inc. <https://exaloop.io>
|
2022-12-05 08:45:21 +08:00
|
|
|
|
2021-09-28 02:02:44 +08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <ostream>
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2023-01-17 23:21:59 +08:00
|
|
|
#include "codon/cir/cir.h"
|
2021-10-11 07:41:52 +08:00
|
|
|
#include "codon/parser/ast.h"
|
|
|
|
#include "codon/parser/common.h"
|
|
|
|
#include "codon/parser/ctx.h"
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
#define FILE_GENERATED "<generated>"
|
|
|
|
#define MODULE_MAIN "__main__"
|
|
|
|
#define MAIN_IMPORT ""
|
|
|
|
#define STDLIB_IMPORT ":stdlib:"
|
|
|
|
#define STDLIB_INTERNAL_MODULE "internal"
|
|
|
|
|
|
|
|
#define TYPE_TUPLE "Tuple.N"
|
|
|
|
#define TYPE_KWTUPLE "KwTuple.N"
|
2022-09-16 03:40:00 +08:00
|
|
|
#define TYPE_TYPEVAR "TypeVar"
|
2022-07-27 04:06:00 +08:00
|
|
|
#define TYPE_CALLABLE "Callable"
|
2021-09-28 02:02:44 +08:00
|
|
|
#define TYPE_PARTIAL "Partial.N"
|
|
|
|
#define TYPE_OPTIONAL "Optional"
|
|
|
|
#define TYPE_SLICE "std.internal.types.slice.Slice"
|
|
|
|
#define FN_UNWRAP "std.internal.types.optional.unwrap"
|
|
|
|
#define VAR_ARGV "__argv__"
|
2022-12-05 08:45:21 +08:00
|
|
|
#define VAR_VTABLE ".__vtable__"
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
#define MAX_INT_WIDTH 10000
|
|
|
|
#define MAX_REALIZATION_DEPTH 200
|
2022-09-16 03:40:00 +08:00
|
|
|
#define MAX_STATIC_ITER 1024
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
namespace codon::ast {
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Forward declarations
|
|
|
|
struct SimplifyContext;
|
|
|
|
class SimplifyVisitor;
|
|
|
|
struct TypeContext;
|
|
|
|
struct TranslateContext;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Cache encapsulation that holds data structures shared across various transformation
|
|
|
|
* stages (AST transformation, type checking etc.). The subsequent stages (e.g. type
|
|
|
|
* checking) assumes that previous stages populated this structure correctly.
|
|
|
|
* Implemented to avoid bunch of global objects.
|
|
|
|
*/
|
|
|
|
struct Cache : public std::enable_shared_from_this<Cache> {
|
|
|
|
/// Stores a count for each identifier (name) seen in the code.
|
|
|
|
/// Used to generate unique identifier for each name in the code (e.g. Foo -> Foo.2).
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, int> identifierCount;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Maps a unique identifier back to the original name in the code
|
|
|
|
/// (e.g. Foo.2 -> Foo).
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, std::string> reverseIdentifierLookup;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Number of code-generated source code positions. Used to generate the next unique
|
|
|
|
/// source-code position information.
|
|
|
|
int generatedSrcInfoCount;
|
|
|
|
/// Number of unbound variables so far. Used to generate the next unique unbound
|
|
|
|
/// identifier.
|
|
|
|
int unboundCount;
|
|
|
|
/// Number of auto-generated variables so far. Used to generate the next unique
|
|
|
|
/// variable name in getTemporaryVar() below.
|
|
|
|
int varCount;
|
|
|
|
/// Stores the count of imported files. Used to track class method ages
|
|
|
|
/// and to prevent using extended methods before they were seen.
|
|
|
|
int age;
|
|
|
|
|
|
|
|
/// Holds module import data.
|
|
|
|
struct Import {
|
|
|
|
/// Absolute filename of an import.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string filename;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Import simplify context.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<SimplifyContext> ctx;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Unique import variable for checking already loaded imports.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string importVar;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// File content (line:col indexable)
|
2021-10-14 03:38:23 +08:00
|
|
|
std::vector<std::string> content;
|
2022-12-05 08:45:21 +08:00
|
|
|
/// Relative module name (e.g., `foo.bar`)
|
|
|
|
std::string moduleName;
|
2021-09-28 02:02:44 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Absolute path of seqc executable (if available).
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string argv0;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Absolute path of the entry-point module (if available).
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string module0;
|
2021-12-01 00:50:28 +08:00
|
|
|
/// IR module.
|
|
|
|
ir::Module *module = nullptr;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Table of imported files that maps an absolute filename to a Import structure.
|
2021-12-01 00:50:28 +08:00
|
|
|
/// By convention, the key of the Codon's standard library is "".
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, Import> imports;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Set of unique (canonical) global identifiers for marking such variables as global
|
2021-12-01 00:50:28 +08:00
|
|
|
/// in code-generation step and in JIT.
|
|
|
|
std::map<std::string, ir::Var *> globals;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Stores class data for each class (type) in the source code.
|
|
|
|
struct Class {
|
|
|
|
/// Generic (unrealized) class template AST.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<ClassStmt> ast;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Non-simplified AST. Used for base class instantiation.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<ClassStmt> originalAst;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2022-01-12 09:39:15 +08:00
|
|
|
/// Class method lookup table. Each non-canonical name points
|
|
|
|
/// to a root function name of a corresponding method.
|
|
|
|
std::unordered_map<std::string, std::string> methods;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// A class field (member).
|
|
|
|
struct ClassField {
|
|
|
|
/// Field name.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string name;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// A corresponding generic field type.
|
|
|
|
types::TypePtr type;
|
|
|
|
};
|
|
|
|
/// A list of class' ClassField instances. List is needed (instead of map) because
|
|
|
|
/// the order of the fields matters.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::vector<ClassField> fields;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
/// Dictionary of class variables: a name maps to a canonical name.
|
|
|
|
std::unordered_map<std::string, std::string> classVars;
|
|
|
|
|
2021-09-28 02:02:44 +08:00
|
|
|
/// A class realization.
|
|
|
|
struct ClassRealization {
|
|
|
|
/// Realized class type.
|
|
|
|
types::ClassTypePtr type;
|
|
|
|
/// A list of field names and realization's realized field types.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::vector<std::pair<std::string, types::TypePtr>> fields;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// IR type pointer.
|
2022-12-05 08:45:21 +08:00
|
|
|
codon::ir::types::Type *ir = nullptr;
|
|
|
|
|
|
|
|
/// Realization vtable.
|
|
|
|
struct VTable {
|
|
|
|
// Maps {base, thunk signature} to {thunk realization, thunk ID}
|
|
|
|
std::map<std::pair<std::string, std::string>,
|
|
|
|
std::pair<types::FuncTypePtr, size_t>>
|
|
|
|
table;
|
|
|
|
codon::ir::Var *ir = nullptr;
|
|
|
|
};
|
|
|
|
/// All vtables (for each base class)
|
|
|
|
std::unordered_map<std::string, VTable> vtables;
|
|
|
|
/// Realization ID
|
|
|
|
size_t id = 0;
|
2021-09-28 02:02:44 +08:00
|
|
|
};
|
|
|
|
/// Realization lookup table that maps a realized class name to the corresponding
|
|
|
|
/// ClassRealization instance.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, std::shared_ptr<ClassRealization>> realizations;
|
2022-12-05 08:45:21 +08:00
|
|
|
|
|
|
|
/// List of virtual method names
|
|
|
|
std::unordered_set<std::string> virtuals;
|
|
|
|
/// MRO
|
|
|
|
std::vector<ExprPtr> mro;
|
|
|
|
|
|
|
|
/// List of statically inherited classes.
|
|
|
|
std::vector<std::string> staticParentClasses;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
Class() : ast(nullptr), originalAst(nullptr) {}
|
|
|
|
};
|
|
|
|
/// Class lookup table that maps a canonical class identifier to the corresponding
|
|
|
|
/// Class instance.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, Class> classes;
|
2022-12-05 08:45:21 +08:00
|
|
|
size_t classRealizationCnt = 0;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
struct Function {
|
|
|
|
/// Generic (unrealized) function template AST.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<FunctionStmt> ast;
|
2022-07-27 04:06:00 +08:00
|
|
|
/// Non-simplified AST.
|
|
|
|
std::shared_ptr<FunctionStmt> origAst;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// A function realization.
|
|
|
|
struct FunctionRealization {
|
|
|
|
/// Realized function type.
|
|
|
|
types::FuncTypePtr type;
|
|
|
|
/// Realized function AST (stored here for later realization in code generations
|
|
|
|
/// stage).
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<FunctionStmt> ast;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// IR function pointer.
|
|
|
|
ir::Func *ir;
|
|
|
|
};
|
|
|
|
/// Realization lookup table that maps a realized function name to the corresponding
|
|
|
|
/// FunctionRealization instance.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, std::shared_ptr<FunctionRealization>> realizations;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Unrealized function type.
|
|
|
|
types::FuncTypePtr type;
|
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
Function() : ast(nullptr), origAst(nullptr), type(nullptr) {}
|
2021-09-28 02:02:44 +08:00
|
|
|
};
|
|
|
|
/// Function lookup table that maps a canonical function identifier to the
|
|
|
|
/// corresponding Function instance.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string, Function> functions;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2022-01-12 09:39:15 +08:00
|
|
|
struct Overload {
|
|
|
|
/// Canonical name of an overload (e.g. Foo.__init__.1).
|
|
|
|
std::string name;
|
|
|
|
/// Overload age (how many class extension were seen before a method definition).
|
|
|
|
/// Used to prevent the usage of an overload before it was defined in the code.
|
|
|
|
/// TODO: I have no recollection of how this was supposed to work. Most likely
|
|
|
|
/// it does not work at all...
|
|
|
|
int age;
|
|
|
|
};
|
|
|
|
/// Maps a "root" name of each function to the list of names of the function
|
|
|
|
/// overloads.
|
|
|
|
std::unordered_map<std::string, std::vector<Overload>> overloads;
|
|
|
|
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Pointer to the later contexts needed for IR API access.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::shared_ptr<TypeContext> typeCtx;
|
|
|
|
std::shared_ptr<TranslateContext> codegenCtx;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Set of function realizations that are to be translated to IR.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::set<std::pair<std::string, std::string>> pendingRealizations;
|
2022-01-26 10:55:00 +08:00
|
|
|
/// Mapping of partial record names to function pointers and corresponding masks.
|
|
|
|
std::unordered_map<std::string, std::pair<types::FuncTypePtr, std::vector<char>>>
|
|
|
|
partials;
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Custom operators
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string,
|
|
|
|
std::pair<bool, std::function<StmtPtr(ast::SimplifyVisitor *,
|
|
|
|
ast::CustomStmt *)>>>
|
2021-09-28 02:02:44 +08:00
|
|
|
customBlockStmts;
|
2021-10-14 03:38:23 +08:00
|
|
|
std::unordered_map<std::string,
|
|
|
|
std::function<StmtPtr(ast::SimplifyVisitor *, ast::CustomStmt *)>>
|
2021-09-28 02:02:44 +08:00
|
|
|
customExprStmts;
|
|
|
|
|
2021-10-17 06:48:03 +08:00
|
|
|
/// Plugin-added import paths
|
|
|
|
std::vector<std::string> pluginImportPaths;
|
|
|
|
|
2021-12-01 00:50:28 +08:00
|
|
|
/// Set if the Codon is running in JIT mode.
|
|
|
|
bool isJit;
|
|
|
|
int jitCell;
|
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
std::unordered_map<std::string, std::pair<std::string, bool>> replacements;
|
|
|
|
std::unordered_map<std::string, int> generatedTuples;
|
|
|
|
std::vector<exc::ParserException> errors;
|
|
|
|
|
2022-09-16 03:40:00 +08:00
|
|
|
/// Set if Codon operates in Python compatibility mode (e.g., with Python numerics)
|
|
|
|
bool pythonCompat = false;
|
|
|
|
|
2021-09-28 02:02:44 +08:00
|
|
|
public:
|
2021-10-14 03:38:23 +08:00
|
|
|
explicit Cache(std::string argv0 = "");
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Return a uniquely named temporary variable of a format
|
|
|
|
/// "{sigil}_{prefix}{counter}". A sigil should be a non-lexable symbol.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string getTemporaryVar(const std::string &prefix = "", char sigil = '.');
|
2022-07-27 04:06:00 +08:00
|
|
|
/// Get the non-canonical version of a canonical name.
|
|
|
|
std::string rev(const std::string &s);
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Generate a unique SrcInfo for internally generated AST nodes.
|
|
|
|
SrcInfo generateSrcInfo();
|
|
|
|
/// Get file contents at the given location.
|
2021-10-14 03:38:23 +08:00
|
|
|
std::string getContent(const SrcInfo &info);
|
2022-09-16 03:40:00 +08:00
|
|
|
/// Register a global identifier.
|
|
|
|
void addGlobal(const std::string &name, ir::Var *var = nullptr);
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Realization API.
|
|
|
|
|
|
|
|
/// Find a class with a given canonical name and return a matching types::Type pointer
|
|
|
|
/// or a nullptr if a class is not found.
|
|
|
|
/// Returns an _uninstantiated_ type.
|
2021-10-14 03:38:23 +08:00
|
|
|
types::ClassTypePtr findClass(const std::string &name) const;
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Find a function with a given canonical name and return a matching types::Type
|
|
|
|
/// pointer or a nullptr if a function is not found.
|
|
|
|
/// Returns an _uninstantiated_ type.
|
2021-10-14 03:38:23 +08:00
|
|
|
types::FuncTypePtr findFunction(const std::string &name) const;
|
2022-07-27 04:06:00 +08:00
|
|
|
/// Find the canonical name of a class method.
|
|
|
|
std::string getMethod(const types::ClassTypePtr &typ, const std::string &member) {
|
|
|
|
if (auto m = in(classes, typ->name)) {
|
|
|
|
if (auto t = in(m->methods, member))
|
|
|
|
return *t;
|
|
|
|
}
|
|
|
|
seqassertn(false, "cannot find '{}' in '{}'", member, typ->toString());
|
|
|
|
return "";
|
|
|
|
}
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Find the class method in a given class type that best matches the given arguments.
|
|
|
|
/// Returns an _uninstantiated_ type.
|
2022-01-12 09:39:15 +08:00
|
|
|
types::FuncTypePtr findMethod(types::ClassType *typ, const std::string &member,
|
|
|
|
const std::vector<types::TypePtr> &args);
|
2021-09-28 02:02:44 +08:00
|
|
|
|
|
|
|
/// Given a class type and the matching generic vector, instantiate the type and
|
|
|
|
/// realize it.
|
|
|
|
ir::types::Type *realizeType(types::ClassTypePtr type,
|
2021-10-14 03:38:23 +08:00
|
|
|
const std::vector<types::TypePtr> &generics = {});
|
2021-09-28 02:02:44 +08:00
|
|
|
/// Given a function type and function arguments, instantiate the type and
|
|
|
|
/// realize it. The first argument is the function return type.
|
|
|
|
/// You can also pass function generics if a function has one (e.g. T in def
|
|
|
|
/// foo[T](...)). If a generic is used as an argument, it will be auto-deduced. Pass
|
|
|
|
/// only if a generic cannot be deduced from the provided args.
|
2021-10-14 03:38:23 +08:00
|
|
|
ir::Func *realizeFunction(types::FuncTypePtr type,
|
|
|
|
const std::vector<types::TypePtr> &args,
|
|
|
|
const std::vector<types::TypePtr> &generics = {},
|
2022-07-27 04:06:00 +08:00
|
|
|
const types::ClassTypePtr &parentClass = nullptr);
|
2021-09-28 02:02:44 +08:00
|
|
|
|
2021-10-14 03:38:23 +08:00
|
|
|
ir::types::Type *makeTuple(const std::vector<types::TypePtr> &types);
|
|
|
|
ir::types::Type *makeFunction(const std::vector<types::TypePtr> &types);
|
2022-12-05 08:45:21 +08:00
|
|
|
ir::types::Type *makeUnion(const std::vector<types::TypePtr> &types);
|
2022-07-09 07:17:50 +08:00
|
|
|
|
|
|
|
void parseCode(const std::string &code);
|
2022-12-05 08:45:21 +08:00
|
|
|
|
|
|
|
static std::vector<ExprPtr> mergeC3(std::vector<std::vector<ExprPtr>> &);
|
2021-09-28 02:02:44 +08:00
|
|
|
};
|
|
|
|
|
2022-07-27 04:06:00 +08:00
|
|
|
} // namespace codon::ast
|