Add history support, and fix parsing system.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "internal/trie/trie.h"
|
||||
#include "internal/vase/vase.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::syntax {
|
||||
@@ -75,7 +76,11 @@ struct ParseEvent {
|
||||
|
||||
struct Language {
|
||||
std::function<void *()> none_state;
|
||||
std::function<void(void **, std::string_view, bool, std::vector<Token> *, std::vector<ParseEvent> *)> parse;
|
||||
std::function<void(
|
||||
void **, std::string_view,
|
||||
bool, std::vector<Token> *, std::vector<ParseEvent> *
|
||||
)>
|
||||
parse;
|
||||
std::function<void *(void *)> copy;
|
||||
std::function<bool(void *, void *)> equal;
|
||||
std::function<void(void *)> destroy;
|
||||
@@ -85,35 +90,125 @@ struct ParseState {
|
||||
static constexpr uint64_t BRANCH_BIT = 1ull << 63;
|
||||
static constexpr uint64_t LINES_MASK = ~BRANCH_BIT;
|
||||
uint64_t header;
|
||||
uint16_t height;
|
||||
std::atomic_uint16_t refs;
|
||||
bool is_branch() const {
|
||||
return header & BRANCH_BIT;
|
||||
}
|
||||
uint64_t lines() const {
|
||||
return header & LINES_MASK;
|
||||
}
|
||||
explicit ParseState(bool branch, uint64_t lines, uint16_t height)
|
||||
: height(height), refs(1) {
|
||||
header = lines;
|
||||
header |= branch * BRANCH_BIT;
|
||||
};
|
||||
static void retain(ParseState *node);
|
||||
static void release(Language &lang, ParseState *node);
|
||||
static ParseState *build(Language &lang, ParseState **pieces, uint64_t lo, uint64_t hi);
|
||||
static ParseState *splice(
|
||||
Language &lang, ParseState *node, vase::Shard *vase,
|
||||
uint64_t line, uint64_t original, uint64_t final
|
||||
);
|
||||
static ParseState *concat(Language &lang, ParseState *a, ParseState *b);
|
||||
};
|
||||
|
||||
struct ParseStateBranch : ParseState {
|
||||
ParseState *left;
|
||||
ParseState *right;
|
||||
ParseStateBranch(ParseState *l, ParseState *r)
|
||||
: ParseState(
|
||||
true, l->lines() + r->lines(),
|
||||
1 + std::max(l->height, r->height)
|
||||
),
|
||||
left(l), right(r) {
|
||||
retain(l);
|
||||
retain(r);
|
||||
}
|
||||
};
|
||||
|
||||
struct ParseStateLeaf : ParseState {
|
||||
void *state;
|
||||
uint32_t n;
|
||||
uint32_t cap;
|
||||
uint16_t *blocks;
|
||||
static constexpr uint64_t MAX_CHUNK = 512;
|
||||
uint32_t n{0};
|
||||
static constexpr uint16_t IS_CLOSING = 0x8000;
|
||||
static constexpr uint16_t LINE_MASK = 0x7fff;
|
||||
uint16_t *blocks{nullptr};
|
||||
void *state;
|
||||
ParseStateLeaf(void *state, uint64_t lines, uint32_t n, uint16_t *blocks_)
|
||||
: ParseState(false, lines, 1), n(n), state(state) {
|
||||
blocks = (uint16_t *)malloc(sizeof(uint16_t) * n);
|
||||
memcpy(blocks, blocks_, sizeof(uint16_t) * n);
|
||||
};
|
||||
};
|
||||
|
||||
struct ParsePieceBuilder {
|
||||
Language ⟨
|
||||
std::vector<ParseState *> pieces;
|
||||
std::vector<uint16_t> blocks;
|
||||
void *piece_state{nullptr};
|
||||
uint64_t chunk_start{0};
|
||||
uint64_t chunk_lines{0};
|
||||
ParsePieceBuilder(Language &lang, uint64_t first_line)
|
||||
: lang(lang), chunk_start(first_line) {}
|
||||
void add(
|
||||
void *state,
|
||||
uint64_t line,
|
||||
const std::vector<ParseEvent> &events
|
||||
) {
|
||||
if (chunk_lines == 0) {
|
||||
chunk_start = line;
|
||||
piece_state = lang.copy(state);
|
||||
}
|
||||
for (const auto &ev : events) {
|
||||
blocks.push_back(
|
||||
(ev.closing ? ParseStateLeaf::IS_CLOSING : 0)
|
||||
| (line - chunk_start)
|
||||
);
|
||||
}
|
||||
++chunk_lines;
|
||||
if (chunk_lines == ParseStateLeaf::MAX_CHUNK)
|
||||
flush();
|
||||
}
|
||||
void flush() {
|
||||
if (chunk_lines == 0)
|
||||
return;
|
||||
pieces.push_back(new ParseStateLeaf(
|
||||
piece_state,
|
||||
chunk_lines,
|
||||
blocks.size(),
|
||||
blocks.data()
|
||||
));
|
||||
piece_state = nullptr;
|
||||
blocks.clear();
|
||||
chunk_lines = 0;
|
||||
}
|
||||
ParseState *finish() {
|
||||
flush();
|
||||
if (pieces.empty())
|
||||
return nullptr;
|
||||
ParseState *root = ParseState::build(lang, pieces.data(), 0, pieces.size());
|
||||
pieces.clear();
|
||||
return root;
|
||||
}
|
||||
};
|
||||
|
||||
struct TreeCursor {
|
||||
Language ⟨
|
||||
ParseState *root;
|
||||
ParseStateLeaf *leaf = nullptr;
|
||||
ParseStateBranch *stack[64];
|
||||
uint8_t depth = 0;
|
||||
bool went_left[64];
|
||||
TreeCursor(ParseState *root, uint64_t target_line, uint64_t *relative);
|
||||
TreeCursor(
|
||||
Language &lang, ParseState *root,
|
||||
uint64_t target_line, uint64_t *relative
|
||||
);
|
||||
~TreeCursor();
|
||||
TreeCursor(const TreeCursor &) = delete;
|
||||
TreeCursor &operator=(const TreeCursor &) = delete;
|
||||
void next();
|
||||
void prev();
|
||||
ParseState *prefix();
|
||||
ParseState *suffix();
|
||||
};
|
||||
} // namespace bed::internal::syntax
|
||||
|
||||
@@ -1,57 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "decl.h"
|
||||
#include "internal/vase/vase.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace bed::internal::syntax {
|
||||
struct Parser {
|
||||
static constexpr uint64_t MAX_CHUNK = 512;
|
||||
struct ParserSnapshot {
|
||||
ParseState *root = nullptr;
|
||||
Language *lang = nullptr;
|
||||
};
|
||||
|
||||
ParseState *root;
|
||||
Language lang;
|
||||
bool in_edit = false;
|
||||
ParserSnapshot make_parser(vase::Shard *vase, uint64_t lines, Language *lang);
|
||||
ParserSnapshot retain(const ParserSnapshot &snap);
|
||||
void release(ParserSnapshot &snap);
|
||||
|
||||
uint64_t next_closing(const ParserSnapshot &snap, uint64_t line);
|
||||
uint64_t prev_opening(const ParserSnapshot &snap, uint64_t line);
|
||||
|
||||
struct Iterator {
|
||||
ParserSnapshot snap;
|
||||
std::optional<vase::Iterator> it;
|
||||
void *state;
|
||||
uint64_t at;
|
||||
std::vector<Token> tokens;
|
||||
std::vector<ParseEvent> events;
|
||||
Iterator(uint64_t, ParserSnapshot, vase::Shard *);
|
||||
~Iterator();
|
||||
Iterator(const Iterator &) = delete;
|
||||
Iterator &operator=(const Iterator &) = delete;
|
||||
Iterator(Iterator &&other);
|
||||
Iterator &operator=(Iterator &&other);
|
||||
void next();
|
||||
};
|
||||
|
||||
std::optional<Iterator> get_hl(const ParserSnapshot &snap, vase::Shard *vase, uint64_t target);
|
||||
|
||||
void insert(ParserSnapshot &snap, vase::Shard *vase, uint64_t start, uint64_t count);
|
||||
void erase(ParserSnapshot &snap, vase::Shard *vase, uint64_t start, uint64_t count);
|
||||
|
||||
struct Edit {
|
||||
ParserSnapshot *target;
|
||||
bool dirty = false;
|
||||
uint64_t dirty_start = 0;
|
||||
uint64_t dirty_end = 0;
|
||||
int64_t edit_delta = 0;
|
||||
|
||||
Parser(vase::Shard *, uint64_t, Language);
|
||||
~Parser();
|
||||
Parser(const Parser &) = delete;
|
||||
Parser &operator=(const Parser &) = delete;
|
||||
explicit Edit(ParserSnapshot &snap) : target(&snap) {}
|
||||
|
||||
void reset(vase::Shard *, uint64_t, Language);
|
||||
void erase(vase::Shard *, uint64_t, uint64_t);
|
||||
void insert(vase::Shard *, uint64_t, uint64_t);
|
||||
void modify(vase::Shard *, uint64_t, uint64_t);
|
||||
|
||||
void begin_edit();
|
||||
void erase(uint64_t start, uint64_t count);
|
||||
void insert(uint64_t start, uint64_t count);
|
||||
void end_edit(vase::Shard *vase);
|
||||
void mark_dirty(uint64_t start, uint64_t end);
|
||||
|
||||
uint64_t next_closing(uint64_t line);
|
||||
uint64_t prev_opening(uint64_t line);
|
||||
|
||||
std::pair<ParseState *, ParseState *> split_tree(ParseState *node, uint64_t line);
|
||||
ParseState *join_tree(ParseState *a, ParseState *b);
|
||||
|
||||
struct Iterator {
|
||||
Parser *p;
|
||||
std::optional<vase::Iterator> it;
|
||||
void *state;
|
||||
uint64_t at;
|
||||
std::vector<Token> tokens;
|
||||
std::vector<ParseEvent> events;
|
||||
Iterator(uint64_t, Parser *, vase::Shard *);
|
||||
~Iterator();
|
||||
Iterator(const Iterator &) = delete;
|
||||
Iterator &operator=(const Iterator &) = delete;
|
||||
Iterator(Iterator &&other);
|
||||
Iterator &operator=(Iterator &&other);
|
||||
void next();
|
||||
};
|
||||
std::optional<Iterator> get_hl(vase::Shard *, uint64_t);
|
||||
void insert(uint64_t start, uint64_t count);
|
||||
void erase(uint64_t start, uint64_t count);
|
||||
void commit(vase::Shard *vase);
|
||||
};
|
||||
} // namespace bed::internal::syntax
|
||||
|
||||
Reference in New Issue
Block a user