Skip to content

Commit

Permalink
libnixf: refactor parser header & remove legacy test
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc committed Jan 9, 2024
1 parent d6a9d80 commit acf2cc2
Show file tree
Hide file tree
Showing 41 changed files with 164 additions and 2,987 deletions.
26 changes: 23 additions & 3 deletions libnixf/include/nixf/Parse/Nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,39 @@

#include "nixf/Basic/Range.h"

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

namespace nixf {

class Node {
public:
enum NodeKind {
NK_BeginExpr,
NK_StringParts,
NK_EndExpr,
} Kind;
};

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; }
};

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

class StringPart {
enum StringPartKind {
Expand All @@ -41,6 +55,12 @@ class StringPart {
StringPartKind getKind() { return Kind; }
};

using String = std::vector<StringPart>;
class InterpolatedParts : public Expr {
std::vector<StringPart> Fragments;

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

} // namespace nixf
148 changes: 5 additions & 143 deletions libnixf/include/nixf/Parse/Parser.h
Original file line number Diff line number Diff line change
@@ -1,149 +1,11 @@
#include "Lexer.h"
#include "Nodes.h"
#include "Token.h"
#pragma once

#include "nixf/Basic/DiagnosticEngine.h"

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

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];
}

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

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

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

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

std::deque<Token> LookAheadBuf;

std::optional<Token> LastToken;

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

void consume() {
if (LookAheadBuf.empty())
peek(0);
popFront();
}

Token popFront() {
LastToken = LookAheadBuf.front();
LookAheadBuf.pop_front();
return *LastToken;
}

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<Node> (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<Node> Expr);

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

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

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

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

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

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

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

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

std::unique_ptr<Node> 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<Node> parseExprOpBP(unsigned LeftRBP);

std::unique_ptr<Expr> parseExpr();

/// Create an "Unknown" with many tokens until \p Predicate does not hold
std::unique_ptr<Node> 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<Node> parse();
};
class Node;
class DiagnosticEngine;
std::unique_ptr<Node> parse(std::string_view Src, DiagnosticEngine &Diag);

} // namespace nixf
Loading

0 comments on commit acf2cc2

Please sign in to comment.