Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libnixf: add descend(), with boost's small_vector #320

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions libnixf/include/nixf/Basic/Nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "nixf/Basic/Range.h"

#include <boost/container/small_vector.hpp>

#include <cassert>
#include <memory>
#include <string>
Expand Down Expand Up @@ -54,10 +56,30 @@ class Node {
public:
[[nodiscard]] NodeKind kind() const { return Kind; }
[[nodiscard]] LexerCursorRange range() const { return Range; }
[[nodiscard]] PositionRange positionRange() const {
return Range.positionRange();
}
[[nodiscard]] LexerCursor begin() const { return Range.begin(); }
[[nodiscard]] LexerCursor end() const { return Range.end(); }
[[nodiscard]] static const char *name(NodeKind Kind);
[[nodiscard]] const char *name() const { return name(Kind); }

using ChildVector = boost::container::small_vector<Node *, 8>;

[[nodiscard]] virtual ChildVector children() const = 0;

/// \brief Descendant node that contains the given range.
[[nodiscard]] const Node *descend(PositionRange Range) const {
if (!positionRange().contains(Range)) {
return nullptr;
}
for (const auto &Child : children()) {
if (Child->positionRange().contains(Range)) {
return Child->descend(Range);
}
}
return this;
}
};

class Expr : public Node {
Expand All @@ -77,6 +99,8 @@ class ExprInt : public Expr {
ExprInt(LexerCursorRange Range, NixInt Value)
: Expr(NK_ExprInt, Range), Value(Value) {}
[[nodiscard]] NixInt value() const { return Value; }

[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprFloat : public Expr {
Expand All @@ -86,6 +110,8 @@ class ExprFloat : public Expr {
ExprFloat(LexerCursorRange Range, NixFloat Value)
: Expr(NK_ExprFloat, Range), Value(Value) {}
[[nodiscard]] NixFloat value() const { return Value; }

[[nodiscard]] ChildVector children() const override { return {}; }
};

class InterpolablePart {
Expand Down Expand Up @@ -132,6 +158,8 @@ class InterpolatedParts : public Node {
[[nodiscard]] const std::vector<InterpolablePart> &fragments() const {
return Fragments;
};

[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprString : public Expr {
Expand All @@ -144,6 +172,8 @@ class ExprString : public Expr {
[[nodiscard]] const std::shared_ptr<InterpolatedParts> &parts() const {
return Parts;
}

[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprPath : public Expr {
Expand All @@ -156,6 +186,8 @@ class ExprPath : public Expr {
[[nodiscard]] const std::shared_ptr<InterpolatedParts> &parts() const {
return Parts;
}

[[nodiscard]] ChildVector children() const override { return {}; }
};

/// \brief Misc node, used for parentheses, keywords, etc.
Expand All @@ -165,6 +197,8 @@ class ExprPath : public Expr {
class Misc : public Node {
public:
Misc(LexerCursorRange Range) : Node(NK_Misc, Range) {}

[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprParen : public Expr {
Expand All @@ -181,6 +215,10 @@ class ExprParen : public Expr {
[[nodiscard]] const std::shared_ptr<Expr> &expr() const { return E; }
[[nodiscard]] const std::shared_ptr<Misc> &lparen() const { return LParen; }
[[nodiscard]] const std::shared_ptr<Misc> &rparen() const { return RParen; }

[[nodiscard]] ChildVector children() const override {
return {E.get(), LParen.get(), RParen.get()};
}
};

/// \brief Identifier. Variable names, attribute names, etc.
Expand All @@ -191,6 +229,8 @@ class Identifier : public Node {
Identifier(LexerCursorRange Range, std::string Name)
: Node(NK_Identifer, Range), Name(std::move(Name)) {}
[[nodiscard]] const std::string &name() const { return Name; }

[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprVar : public Expr {
Expand All @@ -200,6 +240,8 @@ class ExprVar : public Expr {
ExprVar(LexerCursorRange Range, std::shared_ptr<Identifier> ID)
: Expr(NK_ExprVar, Range), ID(std::move(ID)) {}
[[nodiscard]] const std::shared_ptr<Identifier> &id() const { return ID; }

[[nodiscard]] ChildVector children() const override { return {ID.get()}; }
};

class AttrName : public Node {
Expand Down Expand Up @@ -244,6 +286,19 @@ class AttrName : public Node {
assert(Kind == ANK_String);
return String;
}

[[nodiscard]] ChildVector children() const override {
switch (Kind) {
case ANK_ID:
return {ID.get()};
case ANK_String:
return {String.get()};
case ANK_Interpolation:
return {Interpolation.get()};
default:
assert(false && "invalid AttrNameKind");
}
}
};

class AttrPath : public Node {
Expand All @@ -256,6 +311,15 @@ class AttrPath : public Node {
[[nodiscard]] const std::vector<std::shared_ptr<AttrName>> &names() const {
return Names;
}

[[nodiscard]] ChildVector children() const override {
ChildVector Children;
Children.reserve(Names.size());
for (const auto &Name : Names) {
Children.push_back(Name.get());
}
return Children;
}
};

class Binding : public Node {
Expand All @@ -270,6 +334,10 @@ class Binding : public Node {

[[nodiscard]] const std::shared_ptr<AttrPath> &path() const { return Path; }
[[nodiscard]] const std::shared_ptr<Expr> &value() const { return Value; }

[[nodiscard]] ChildVector children() const override {
return {Path.get(), Value.get()};
}
};

class Binds : public Node {
Expand All @@ -282,6 +350,15 @@ class Binds : public Node {
[[nodiscard]] const std::vector<std::shared_ptr<Node>> &bindings() const {
return Bindings;
}

[[nodiscard]] ChildVector children() const override {
ChildVector Children;
Children.reserve(Bindings.size());
for (const auto &Binding : Bindings) {
Children.push_back(Binding.get());
}
return Children;
}
};

class ExprAttrs : public Expr {
Expand All @@ -297,6 +374,10 @@ class ExprAttrs : public Expr {
[[nodiscard]] const std::shared_ptr<Misc> &rec() const { return Rec; }

[[nodiscard]] bool isRecursive() const { return Rec != nullptr; }

[[nodiscard]] ChildVector children() const override {
return {Body.get(), Rec.get()};
}
};

} // namespace nixf
3 changes: 2 additions & 1 deletion libnixf/meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
libnixf_deps = [ ]
libnixf_deps = [ boost ]

libnixf_inc = include_directories('include')

Expand Down Expand Up @@ -30,6 +30,7 @@ nixf = declare_dependency(
test('unit/libnixf/Basic',
executable('unit-libnixf-basic',
'test/Basic/Diagnostic.cpp',
'test/Basic/Nodes.cpp',
dependencies: [ nixf, gtest_main ],
)
)
Expand Down
21 changes: 21 additions & 0 deletions libnixf/test/Basic/Nodes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include <gtest/gtest.h>

#include "nixf/Basic/Diagnostic.h"
#include "nixf/Basic/Nodes.h"
#include "nixf/Parse/Parser.h"

namespace {

using namespace std::literals;
using namespace nixf;

TEST(Node, Descend) {
auto Src = "{ a = 1; }"sv;
std::vector<Diagnostic> Diag;
auto Root = parse(Src, Diag);

ASSERT_EQ(Root->descend({{0, 2}, {0, 2}})->kind(), Node::NK_Identifer);
ASSERT_EQ(Root->descend({{0, 2}, {0, 4}})->kind(), Node::NK_Binding);
}

} // namespace