1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00
2021-09-27 14:02:44 -04:00

133 lines
4.7 KiB
C++

/*
* simplify_ctx.h --- Context for simplification transformation.
*
* (c) Seq project. All rights reserved.
* This file is subject to the terms and conditions defined in
* file 'LICENSE', which is part of this source code package.
*/
#pragma once
#include <deque>
#include <memory>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "parser/cache.h"
#include "parser/common.h"
#include "parser/ctx.h"
namespace seq {
namespace ast {
/**
* Simplification context object description.
* This represents an identifier that can be either a function, a class (type), a
* variable or an import.
*/
struct SimplifyItem {
/// Object kind (function, class, variable, or import).
enum Kind { Func, Type, Var } kind;
/// Object's base function
string base;
/// Object's unique identifier (canonical name)
string canonicalName;
/// True if an object is global.
bool global;
/// Non-empty string if a variable is import variable
string importPath;
public:
SimplifyItem(Kind k, string base, string canonicalName, bool global = false);
/// Convenience getters.
string getBase() const { return base; }
bool isGlobal() const { return global; }
bool isVar() const { return kind == Var; }
bool isFunc() const { return kind == Func; }
bool isType() const { return kind == Type; }
bool isImport() const { return !importPath.empty(); }
};
/**
* A variable table (context) for simplification stage.
*/
struct SimplifyContext : public Context<SimplifyItem> {
/// A pointer to the shared cache.
shared_ptr<Cache> cache;
/// A base scope definition. Each function or a class defines a new base scope.
struct Base {
/// Canonical name of a base-defining function or a class.
string name;
/// Declaration AST of a base-defining class (or nullptr otherwise) for
/// automatically annotating "self" and other parameters. For example, for
/// class Foo[T, N: int]: ..., AST is Foo[T, N: int]
ExprPtr ast;
/// Tracks function attributes (e.g. if it has @atomic or @test attributes).
int attributes;
explicit Base(string name, ExprPtr ast = nullptr, int attributes = 0);
bool isType() const { return ast != nullptr; }
};
/// A stack of bases enclosing the current statement (the topmost base is the last
/// base). Top-level has no base.
vector<Base> bases;
/// A stack of nested loops enclosing the current statement used for transforming
/// "break" statement in loop-else constructs. Each loop is defined by a "break"
/// variable created while parsing a loop-else construct. If a loop has no else block,
/// the corresponding loop variable is empty.
vector<string> loops;
/// A stack of nested maps that capture variables defined in enclosing bases (e.g.
/// variables not defined in a function). Maps captured canonical names to new
/// canonical names (used in the inner function). Used for capturing outer variables
/// in generators and lambda functions. A stack is needed because there might be
/// nested generator or lambda constructs.
vector<std::map<string, string>> captures;
/// True if standard library is being loaded.
bool isStdlibLoading;
/// Current module name (Python's __name__) and its source. The default module is
/// __main__.
ImportFile moduleName;
/// Tracks if we are in a dependent part of a short-circuiting expression (e.g. b in a
/// and b) to disallow assignment expressions there.
bool canAssign;
/// Allow type() expressions.
bool allowTypeOf;
/// Replacement expressions.
unordered_map<string, ExprPtr> *substitutions;
public:
SimplifyContext(string filename, shared_ptr<Cache> cache);
using Context<SimplifyItem>::add;
/// Convenience method for adding an object to the context.
shared_ptr<SimplifyItem> add(SimplifyItem::Kind kind, const string &name,
const string &canonicalName = "", bool global = false);
shared_ptr<SimplifyItem> find(const string &name) const override;
/// Return a canonical name of the top-most base, or an empty string if this is a
/// top-level base.
string getBase() const;
/// Return the current base nesting level (note: bases, not blocks).
int getLevel() const { return bases.size(); }
/// Pretty-print the current context state.
void dump() override { dump(0); }
/// Generate a unique identifier (name) for a given string.
string generateCanonicalName(const string &name, bool includeBase = false) const;
bool inFunction() const { return getLevel() && !bases.back().isType(); }
bool inClass() const { return getLevel() && bases.back().isType(); }
private:
/// Pretty-print the current context state.
void dump(int pad);
};
} // namespace ast
} // namespace seq