Skip to content

Commit

Permalink
libnixf: support SPath (<nixpkgs>) (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc authored Apr 9, 2024
1 parent a01bcc6 commit 509eada
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 0 deletions.
1 change: 1 addition & 0 deletions libnixf/include/nixf/Basic/NodeKinds.inc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ EXPR(ExprFloat)
EXPR(ExprVar)
EXPR(ExprString)
EXPR(ExprPath)
EXPR(ExprSPath)
EXPR(ExprParen)
EXPR(ExprAttrs)
EXPR(ExprSelect)
Expand Down
12 changes: 12 additions & 0 deletions libnixf/include/nixf/Basic/Nodes/Simple.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ class ExprPath : public Expr {
[[nodiscard]] ChildVector children() const override { return {}; }
};

class ExprSPath : public Expr {
std::string Text;

public:
ExprSPath(LexerCursorRange Range, std::string Text)
: Expr(NK_ExprSPath, Range), Text(std::move(Text)) {}

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

[[nodiscard]] const std::string &text() const { return Text; }
};

class ExprParen : public Expr {
const std::shared_ptr<Expr> E;
const std::shared_ptr<Misc> LParen;
Expand Down
4 changes: 4 additions & 0 deletions libnixf/include/nixf/Basic/TokenKinds.inc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ TOK(quote2) // ''

// Path.
TOK(path_fragment)

// <path>
TOK(spath)

// URI.
TOK(uri)

Expand Down
18 changes: 18 additions & 0 deletions libnixf/src/Bytecode/Write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ void writeExprPath(std::ostream &OS, const ExprPath &Path) {
}
}

void writeExprSPath(std::ostream &OS, const ExprSPath &SPath) {
// Spath -> (Call __findFile, __nixPath, path)
writeBytecode(OS, mkHeader(EK_Call, SPath));

writeBytecode(OS, mkHeader(EK_Var, SPath));
writeBytecode(OS, std::string_view("__findFile"));

writeBytecode(OS, std::size_t(2));
writeBytecode(OS, mkHeader(EK_Var, SPath));
writeBytecode(OS, std::string_view("__nixPath"));

writeBytecode(OS, mkHeader(EK_String, SPath));
writeBytecode(OS, SPath.text());
}

void writeExprVar(std::ostream &OS, const ExprVar &Var) {
writeBytecode(OS, mkHeader(EK_Var, Var));
writeBytecode(OS, Var.id().name());
Expand Down Expand Up @@ -447,6 +462,9 @@ void nixf::writeBytecode(std::ostream &OS, const Node *N) {
case Node::NK_ExprPath:
writeExprPath(OS, static_cast<const ExprPath &>(*N));
break;
case Node::NK_ExprSPath:
writeExprSPath(OS, static_cast<const ExprSPath &>(*N));
break;
case Node::NK_ExprVar:
writeExprVar(OS, static_cast<const ExprVar &>(*N));
break;
Expand Down
45 changes: 45 additions & 0 deletions libnixf/src/Parse/Lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,41 @@ bool Lexer::consumeURI() {
return false;
}

bool Lexer::consumeSPath() {
// \<{PATH_CHAR}+(\/{PATH_CHAR}+)*\>
LexerCursor Saved = cur();

if (peek() == '<')
consume();

if (!eof() && isPathChar(peekUnwrap())) {
// {PATH_CHAR}+
while (!eof() && isPathChar(peekUnwrap()))
consume();
// (\/{PATH_CHAR}+)*
while (true) {
// \/
if (peek() == '/') {
consume();
// {PATH_CHAR}+
if (!eof() && isPathChar(peekUnwrap())) {
while (!eof() && isPathChar(peekUnwrap()))
consume();
continue;
}
}
break;
}
if (peek() == '>') {
consume();
return true;
}
}

Cur = Saved;
return false;
}

void Lexer::lexIdentifier() {
// identifier: [a-zA-Z_][a-zA-Z0-9_\'\-]*,
consume();
Expand Down Expand Up @@ -446,6 +481,16 @@ Token Lexer::lex() {
return finishToken();
}

if (*Ch == '<') {
// Perhaps this is an "SPATH".
// e.g. <nixpkgs>
// \<{PATH_CHAR}+(\/{PATH_CHAR}+)*\>
if (consumeSPath()) {
Tok = tok_spath;
return finishToken();
}
}

switch (*Ch) {
case '\'':
if (consumePrefix("''"))
Expand Down
2 changes: 2 additions & 0 deletions libnixf/src/Parse/Lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class Lexer {

bool consumeURI();

bool consumeSPath();

/// Should be called after lexing a "raw" identifier, we check if it is a
/// keyword and make assignment: `Tok <- tok_kw_*`
void maybeKW();
Expand Down
5 changes: 5 additions & 0 deletions libnixf/src/Parse/ParseSimple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ std::shared_ptr<Expr> Parser::parseExprSimple() {
NixFloat N = std::strtof(std::string(Tok.view()).c_str(), nullptr);
return std::make_shared<ExprFloat>(Tok.range(), N);
}
case tok_spath: {
consume();
return std::make_shared<ExprSPath>(
Tok.range(), std::string(Tok.view().substr(1, Tok.view().size() - 2)));
}
case tok_dquote: // " - normal strings
return parseString(/*IsIndented=*/false);
case tok_quote2: // '' - indented strings
Expand Down
1 change: 1 addition & 0 deletions libnixf/src/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ class Parser {
/// | string
/// | indented_string
/// | path
/// | spath
/// | hpath
/// | uri
/// | '(' expr ')'
Expand Down
14 changes: 14 additions & 0 deletions libnixf/test/Bytecode/Write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ TEST_F(WriteTest, SelectNullAttr) {
ASSERT_EQ(Kind, nixbc::ExprKind::EK_Select);
}

TEST_F(WriteTest, SPath) {
auto AST = nixf::parse(R"(<nixpkgs>)", Diags);
ASSERT_TRUE(AST);
nixf::writeBytecode(OS, AST.get());
std::string Str = OS.str();
std::string_view Data(Str);

ASSERT_EQ(Str.size(), 154);

auto Kind = bc::eat<nixbc::ExprKind>(Data);

ASSERT_EQ(Kind, nixbc::ExprKind::EK_Call);
}

const char *AllGrammar = R"(
let
x = 1;
Expand Down
26 changes: 26 additions & 0 deletions libnixf/test/Parse/ParseSimple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,32 @@ TEST(Parser, PathOK) {
ASSERT_EQ(Parts.fragments()[2].escaped(), "/d");
}

TEST(Parser, SPath) {
auto Src = R"(<nixpkgs>)"sv;

std::vector<Diagnostic> Diags;
auto AST = nixf::parse(Src, Diags);
ASSERT_TRUE(AST);

ASSERT_EQ(AST->kind(), Node::NK_ExprSPath);

auto &SPath = static_cast<ExprSPath &>(*AST);
ASSERT_EQ(SPath.text(), "nixpkgs");
}

TEST(Parser, SPath2) {
auto Src = R"(<nixpkgs/a/b>)"sv;

std::vector<Diagnostic> Diags;
auto AST = nixf::parse(Src, Diags);
ASSERT_TRUE(AST);

ASSERT_EQ(AST->kind(), Node::NK_ExprSPath);

auto &SPath = static_cast<ExprSPath &>(*AST);
ASSERT_EQ(SPath.text(), "nixpkgs/a/b");
}

TEST(Parser, ParenExpr) {
auto Src = R"((1))"sv;

Expand Down

0 comments on commit 509eada

Please sign in to comment.