Skip to content

Commit

Permalink
libnixf: remove green node design (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc authored Jan 11, 2024
2 parents 2d970a6 + c7fe835 commit ad23935
Show file tree
Hide file tree
Showing 60 changed files with 449 additions and 3,578 deletions.
15 changes: 5 additions & 10 deletions libnixf/include/nixf/Basic/Diagnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,19 @@ class Fix {

class PartialDiagnostic {
public:
virtual const char *format() const {
if (Result.empty())
Result = fmt::vformat(message(), Args);
return Result.c_str();
};

[[nodiscard]] virtual const char *message() const = 0;

virtual ~PartialDiagnostic() = default;

template <class T> PartialDiagnostic &operator<<(const T &Var) {
Args.push_back(Var);
PartialDiagnostic &operator<<(std::string Var) {
Args.emplace_back(std::move(Var));
return *this;
}

[[nodiscard]] const std::vector<std::string> &getArgs() const { return Args; }

protected:
mutable std::string Result;
fmt::dynamic_format_arg_store<fmt::format_context> Args;
std::vector<std::string> Args;
/// Location of this diagnostic
OffsetRange Range;
};
Expand Down
3 changes: 3 additions & 0 deletions libnixf/include/nixf/Basic/Range.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <cstdint>
#include <string_view>

namespace nixf {

Expand All @@ -12,6 +13,8 @@ struct OffsetRange {

OffsetRange(const char *Begin, const char *End) : Begin(Begin), End(End) {}
explicit OffsetRange(const char *Pos) : Begin(Pos), End(Pos) {}
operator std::string_view() const { return {Begin, End}; }
[[nodiscard]] std::string_view view() const { return {Begin, End}; }
};

} // namespace nixf
97 changes: 97 additions & 0 deletions libnixf/include/nixf/Parse/Nodes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/// \file
/// \brief AST nodes.
///
/// Declares the AST nodes used by the parser, the nodes may be used in latter
/// stages, for example semantic analysis.
/// It is expected that they may share some nodes, so they are reference
/// counted.

#pragma once

#include "nixf/Basic/Range.h"

#include <cassert>
#include <memory>
#include <string>
#include <vector>

namespace nixf {

class Node {
public:
enum NodeKind {
NK_InterpolableParts,
NK_BeginExpr,
NK_ExprInt,
NK_ExprFloat,
NK_EndExpr,
};

private:
NodeKind Kind;
OffsetRange Range;

protected:
explicit Node(NodeKind Kind, OffsetRange Range) : Kind(Kind), Range(Range) {}

public:
NodeKind getKind() { return Kind; }
OffsetRange getRange() { return Range; }
};

class Expr : public Node {
protected:
explicit Expr(NodeKind Kind, OffsetRange Range) : Node(Kind, Range) {
assert(NK_BeginExpr <= Kind && Kind <= NK_EndExpr);
}
};

using NixInt = int64_t;
using NixFloat = double;

class ExprInt : public Expr {
NixInt Value;

public:
ExprInt(OffsetRange Range, NixInt Value)
: Expr(NK_ExprInt, Range), Value(Value) {}
[[nodiscard]] NixInt getValue() const { return Value; }
};

class ExprFloat : public Expr {
NixFloat Value;

public:
ExprFloat(OffsetRange Range, NixFloat Value)
: Expr(NK_ExprFloat, Range), Value(Value) {}
[[nodiscard]] NixFloat getValue() const { return Value; }
};

class StringPart {
enum StringPartKind {
SPK_Escaped,
SPK_Interpolation,
} Kind;
std::string Escaped;
std::shared_ptr<Expr> Interpolation;

public:
explicit StringPart(std::string Escaped)
: Kind(SPK_Escaped), Escaped(std::move(Escaped)), Interpolation(nullptr) {
}

explicit StringPart(std::shared_ptr<Expr> Expr)
: Kind(SPK_Interpolation), Interpolation(std::move(Expr)) {}

StringPartKind getKind() { return Kind; }
};

class InterpolatedParts : public Node {
std::vector<StringPart> Fragments;

public:
InterpolatedParts(OffsetRange Range, std::vector<StringPart> Fragments)
: Node(NK_InterpolableParts, Range), Fragments(std::move(Fragments)) {}
};

} // namespace nixf
157 changes: 13 additions & 144 deletions libnixf/include/nixf/Parse/Parser.h
Original file line number Diff line number Diff line change
@@ -1,151 +1,20 @@
#include "nixf/Basic/DiagnosticEngine.h"
#include "nixf/Lex/Lexer.h"
#include "nixf/Syntax/RawSyntax.h"
#include "nixf/Syntax/Token.h"
/// \file
/// \brief Parser interface.
///
/// libnixf parser. This is a recursive descent parser, focusing on error
/// recovery.
#pragma once

#include <limits>
#include <map>
#include <queue>
#include <memory>
#include <string_view>

namespace nixf {

using GuardTokensTy = std::map<tok::TokenKind, std::size_t>;
struct GuardTokensRAII {
GuardTokensRAII(GuardTokensTy &GuardTokens, tok::TokenKind Kind)
: Kind(Kind), GuardTokens(GuardTokens) {
++GuardTokens[Kind];
}
class Node;
class DiagnosticEngine;

~GuardTokensRAII() {
assert(GuardTokens[Kind] > 0);
--GuardTokens[Kind];
}

tok::TokenKind Kind;
GuardTokensTy &GuardTokens;
};

class ExprSyntax;
class Parser {
std::string_view Src;
Lexer Lex;
RawTwineBuilder Builder;
DiagnosticEngine &Diag;

/// These tokens should not be consumed as unknown nodes from error recovery.
friend struct GuardTokensRAII;
GuardTokensTy GuardTokens;

std::deque<TokenAbs> LookAheadBuf;

std::optional<TokenView> LastToken;

TokenView peek(std::size_t N = 0, TokenAbs (Lexer::*Ptr)() = &Lexer::lex) {
while (N >= LookAheadBuf.size()) {
LookAheadBuf.emplace_back((Lex.*Ptr)());
}
return LookAheadBuf[N];
}

void consume() {
if (LookAheadBuf.empty())
peek(0);
Builder.push(LookAheadBuf.front().take());
popFront();
}

std::unique_ptr<Token> popFront() {
LastToken = LookAheadBuf.front();
std::unique_ptr<Token> Ptr = LookAheadBuf.front().take();
LookAheadBuf.pop_front();
return Ptr;
}

void resetCur(const char *NewCur) {
Lex.setCur(NewCur);
LookAheadBuf.clear();
}

std::size_t getOffset(const char *Cur) { return Cur - Src.begin(); }

// Private utilities.
void matchBracket(tok::TokenKind LeftKind,
std::unique_ptr<RawNode> (Parser::*InnerParse)(),
tok::TokenKind RightKind);

void addExprWithCheck(std::string As) {
return addExprWithCheck(std::move(As), parseExpr());
}

/// Check if \p Expr is nullptr.
/// Emit diagnostic if so.
void addExprWithCheck(std::string As, std::unique_ptr<RawNode> Expr);

// Concret n-terms.
std::unique_ptr<RawNode> parseInterpolation();

std::unique_ptr<RawNode> parseStringParts();
std::unique_ptr<RawNode> parseString();

std::unique_ptr<RawNode> parseIndString();
std::unique_ptr<RawNode> parseIndStringParts();

std::unique_ptr<RawNode> parsePath();
std::unique_ptr<RawNode> parseAttrPath();
std::unique_ptr<RawNode> parseAttrName();
std::unique_ptr<RawNode> parseBinding();
std::unique_ptr<RawNode> parseInherit();
std::unique_ptr<RawNode> parseBinds();
std::unique_ptr<RawNode> parseAttrSetExpr();
std::unique_ptr<RawNode> parseParenExpr();
std::unique_ptr<RawNode> parseLegacyLet();
std::unique_ptr<RawNode> parseListExpr();
std::unique_ptr<RawNode> parseListBody();

std::unique_ptr<RawNode> parseFormal();
std::unique_ptr<RawNode> parseFormals();
std::unique_ptr<RawNode> parseBracedFormals();
std::unique_ptr<RawNode> parseLambdaArg();
std::unique_ptr<RawNode> parseLambdaExpr();

std::unique_ptr<RawNode> parseIfExpr();
std::unique_ptr<RawNode> parseAssertExpr();
std::unique_ptr<RawNode> parseWithExpr();
std::unique_ptr<RawNode> parseLetInExpr();

// Abstract level, these functions may return nullptr.
std::unique_ptr<RawNode> parseExprSelect();
std::unique_ptr<RawNode> parseExprSimple();

/// Parse expr_app
/// \p Limit of expr_select should be consumed, default to +inf
std::unique_ptr<RawNode>
parseExprApp(unsigned Limit = std::numeric_limits<unsigned>::max());

std::unique_ptr<RawNode> parseExprOp() { return parseExprOpBP(0); }

/// \note Pratt Parser.
/// Pratt, Vaughan. "Top down operator precedence."
/// Proceedings of the 1st Annual ACM SIGACT-SIGPLAN Symposium on Principles
/// of Programming Languages (1973).
/// https://web.archive.org/web/20151223215421/http://hall.org.ua/halls/wizzard/pdf/Vaughan.Pratt.TDOP.pdf
/// \returns expr_op
std::unique_ptr<RawNode> parseExprOpBP(unsigned LeftRBP);

std::unique_ptr<RawNode> parseExpr();

/// Create an "Unknown" with many tokens until \p Predicate does not hold
std::unique_ptr<RawNode> parseUnknownUntilGuard();

public:
explicit Parser(std::string_view Src, DiagnosticEngine &Diag)
: Src(Src), Lex(Src, Diag), Diag(Diag) {}

/// \brief Top-level parsing.
/// \returns a "ROOT" node
/// printing this node will exactly get the source file.
/// \note non-null
std::unique_ptr<RawNode> parse();
};
/// \brief Parse a string.
/// \param Diag Diagnostics will be written here.
std::shared_ptr<Node> parse(std::string_view Src, DiagnosticEngine &Diag);

} // namespace nixf
File renamed without changes.
Loading

0 comments on commit ad23935

Please sign in to comment.