libexpr/static-analyzer: init
Change-Id: I606718fbe33db1f6c00ca34f45c6553ce468398c Signed-off-by: Raito Bezarius <raito@lix.systems>
This commit is contained in:
@@ -321,6 +321,74 @@ JSON printAttrPathToJson(const SymbolTable & symbols, const AttrPath & attrPath)
|
||||
/* Computing levels/displacements for variables. */
|
||||
|
||||
namespace {
|
||||
// This is a one-pass static analyzer for
|
||||
// various topics.
|
||||
struct StaticAnalyzer : ExprVisitor
|
||||
{
|
||||
std::set<Symbol> staticallyUsedVariables;
|
||||
bool usedDynamicVariables = false;
|
||||
|
||||
StaticAnalyzer() {}
|
||||
using ExprVisitor::visit;
|
||||
|
||||
void visit(ExprDebugFrame & e, std::unique_ptr<Expr> & ptr) override
|
||||
{
|
||||
visit(e.inner);
|
||||
}
|
||||
void visit(ExprLiteral & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprVar & e, std::unique_ptr<Expr> & ptr) override
|
||||
{
|
||||
staticallyUsedVariables.insert(e.name);
|
||||
}
|
||||
void visit(ExprInheritFrom & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprSelect & e, std::unique_ptr<Expr> & ptr) override
|
||||
{
|
||||
if (e.isDynamic()) {
|
||||
usedDynamicVariables = true;
|
||||
}
|
||||
|
||||
visit(e.def);
|
||||
visit(e.e);
|
||||
}
|
||||
void visit(ExprOpHasAttr & e, std::unique_ptr<Expr> & ptr) override
|
||||
{
|
||||
if (e.isDynamic()) {
|
||||
usedDynamicVariables = true;
|
||||
}
|
||||
|
||||
visit(e.e);
|
||||
}
|
||||
void visit(ExprSet & e, std::unique_ptr<Expr> & ptr) override
|
||||
{
|
||||
// TODO: oh bro, we need to analyze dynamic attributes for their value expressions.
|
||||
}
|
||||
void visit(ExprList & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprLambda & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprCall & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprLet & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprWith & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprIf & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprAssert & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprOpNot & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
#define BINOP(type) \
|
||||
/* NOLINTNEXTLINE(bugprone-macro-parentheses) */ \
|
||||
void visit(type & e, std::unique_ptr<Expr> & ptr) override \
|
||||
{ \
|
||||
visit(e.e1); \
|
||||
visit(e.e2); \
|
||||
}
|
||||
BINOP(ExprOpEq)
|
||||
BINOP(ExprOpNEq)
|
||||
BINOP(ExprOpAnd)
|
||||
BINOP(ExprOpOr)
|
||||
BINOP(ExprOpImpl)
|
||||
BINOP(ExprOpUpdate)
|
||||
BINOP(ExprOpConcatLists)
|
||||
#undef BINOP
|
||||
void visit(ExprConcatStrings & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprPos & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
void visit(ExprBlackHole & e, std::unique_ptr<Expr> & ptr) override {}
|
||||
};
|
||||
struct VarBinder : ExprVisitor
|
||||
{
|
||||
Evaluator & es;
|
||||
@@ -590,6 +658,13 @@ void VarBinder::visit(ExprLambda & e, std::unique_ptr<Expr> & ptr)
|
||||
{
|
||||
withEnv(e.pattern->buildEnv(env.get()), [&] {
|
||||
e.pattern->accept(*this);
|
||||
/* TODO: If statically, e.body makes only use of some parameters and not the whole scope.
|
||||
* We shouldn't have to keep around all the environment data which might contain trapped
|
||||
* pointers. Analyze `e.body` and return its statically known set of used variables.
|
||||
* */
|
||||
DirectCallAnalyzer analyzer{es, env};
|
||||
analyzer.visit(e.body);
|
||||
e.shortcut = analyzer.shortcut;
|
||||
visit(e.body);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -292,6 +292,17 @@ struct ExprSelect : Expr
|
||||
/** The path of attributes being selected. e.g. `bar.baz` in `foo.bar.baz.` */
|
||||
AttrPath attrPath;
|
||||
|
||||
bool isDynamic() const
|
||||
{
|
||||
for (auto & name : attrPath) {
|
||||
if (name.expr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath, std::unique_ptr<Expr> def) : Expr(pos), e(std::move(e)), def(std::move(def)), attrPath(std::move(attrPath)) { };
|
||||
ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, const PosIdx namePos, Symbol name) : Expr(pos), e(std::move(e)) { attrPath.push_back(AttrName(namePos, name)); };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
@@ -303,6 +314,16 @@ struct ExprOpHasAttr : Expr
|
||||
{
|
||||
std::unique_ptr<Expr> e;
|
||||
AttrPath attrPath;
|
||||
|
||||
bool isDynamic() const
|
||||
{
|
||||
for (auto & name : attrPath) {
|
||||
if (name.expr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ExprOpHasAttr(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath) : Expr(pos), e(std::move(e)), attrPath(std::move(attrPath)) { };
|
||||
JSON toJSON(const SymbolTable & symbols) const override;
|
||||
void eval(EvalState & state, Env & env, Value & v) override;
|
||||
@@ -479,6 +500,13 @@ struct ExprLambda : Expr
|
||||
Symbol name;
|
||||
std::unique_ptr<Pattern> pattern;
|
||||
std::unique_ptr<Expr> body;
|
||||
// This is a shortcut variant which
|
||||
// exhausts the body further lambda constructions
|
||||
// to transform x1: x2: …: xn: b
|
||||
// into { x1, …, xn }: b
|
||||
// This can be used when you know that you are
|
||||
// passing all the arguments at once.
|
||||
std::unique_ptr<ExprLambda> shortcut;
|
||||
ExprLambda(PosIdx pos, std::unique_ptr<Pattern> pattern, std::unique_ptr<Expr> body)
|
||||
: Expr(pos), pattern(std::move(pattern)), body(std::move(body))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user