1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
#pragma once
#include "Core/Str.h"
#include "Compiler/Thread.h"
#include "TokenColor.h"
#include "Token.h"
#include "InfoIndent.h"
namespace storm {
namespace syntax {
STORM_PKG(lang.bnf);
class Production;
class InfoInternal;
class InfoLeaf;
class Node;
/**
* Syntax nodes containing all information about a parse. The main difference from 'Node' is
* that this representation contains all nodes, where 'Node' only contain the nodes the
* author of the syntax deemed interesting for generating further intermediate
* representations. This representation is also able to represent partial parses.
*
* A partial match is represented as usual, but the partial match may contain string nodes
* where an internal node would otherwise be expected. This represents failure to match a
* non-terminal.
*
* This representation is mainly intended for operations like syntax highlighting and
* indentation. It is also possible to incrementally update this representation when changes
* have been made to the source string since the nodes do not contain any absolute offsets
* into the original string.
*
* TODO: Skip ObjectOn<Compiler> to save some memory.
*/
class InfoNode : public ObjectOn<Compiler> {
STORM_CLASS;
public:
// Create.
STORM_CTOR InfoNode();
// Specified color of this node.
TokenColor color;
// Length of this match (in codepoints).
Nat STORM_FN length();
// Error occured during parsing of this node?
Bool STORM_FN error() const;
void STORM_FN error(Bool v);
// Does this node represent a node captured using a delimiter in the grammar?
Bool STORM_FN delimiter() const;
void STORM_FN delimiter(Bool v);
// Find the first leaf node with a non-zero length at position `pos` relative to this
// node. `pos` is a number of codepoints in the input string.
virtual MAYBE(InfoLeaf *) STORM_FN leafAt(Nat pos);
// Find the indentation of characters at offset 'pos'. This returns either an absolute
// number of indentation levels, or another position which indicates that the
// indentation should be the same as the indentation on that line.
virtual TextIndent STORM_FN indentAt(Nat pos);
// Format this info node into a human-readable representation.
Str *STORM_FN format() const;
// Generate the formatted string.
virtual void STORM_FN format(StrBuf *to) const;
// Get our parent.
MAYBE(InfoInternal *) STORM_FN parent() const { return parentNode; }
// Set parent.
inline void parent(InfoInternal *n) { parentNode = n; }
// Get the size of this node.
virtual Nat STORM_FN dbg_size();
protected:
// Compute the length of this node.
virtual Nat STORM_FN computeLength();
// Invalidate any pre-computed data. Also invalidate any parent nodes.
void STORM_FN invalidate();
private:
// Parent node.
InfoInternal *parentNode;
// Data stored here. Stores:
// msb: set if an error was corrected within this node (ignoring child nodes).
// rest: cached length of this node. If set to all ones: the length needs to be re-computed.
Nat data;
// Masks for 'data'.
static const Nat errorMask;
static const Nat delimMask;
static const Nat lengthMask;
};
/**
* Internal node. Contains a fixed number of children.
*/
class InfoInternal : public InfoNode {
STORM_CLASS;
public:
// Create and allocate space for a pre-defined number of child nodes. Make sure to
// initialize all elements in the array before letting Storm access this node!
InfoInternal(Production *prod, Nat children);
// Create a copy of another node with a different number of elements.
InfoInternal(InfoInternal *src, Nat children);
// Information about indentation.
MAYBE(InfoIndent *) indent;
// Get our production.
inline MAYBE(Production *) STORM_FN production() const { return prod; }
// Number of children.
inline Nat STORM_FN count() const {
return Nat(children->count);
}
// Get child at offset.
inline InfoNode *STORM_FN operator [](Nat id) { return at(id); }
InfoNode *at(Nat id) {
if (id < count()) {
return children->v[id];
} else {
outOfBounds(id);
return children->v[0];
}
}
// Set child at offset.
void STORM_FN set(Nat id, InfoNode *node);
// Find the first leaf node at position 'pos' relative to this node.
virtual MAYBE(InfoLeaf *) STORM_FN leafAt(Nat pos);
// Find the indentation for 'pos'.
virtual TextIndent STORM_FN indentAt(Nat pos);
// Create a "normal" syntax tree from this internal node. It assumes (but checks) that
// this segment of the syntax tree still represents a valid parse according to the
// grammar. Note that this function is mostly provided to avoid having to re-parse a
// string if one needs to inspect the info tree first and then extract a syntax tree of
// some subset later. If you need the parse tree at a later stage, it is often faster to
// just rely on `Parser:tree` directly.
//
// The `url` and `start` parameters are used to create `SrcPos` instances in the parse
// tree. If `start` is not provided, then 0 is assumed.
Node *STORM_FN tree(Url *url);
Node *STORM_FN tree(Url *url, Nat start);
// To string.
virtual void STORM_FN toS(StrBuf *to) const;
// Format.
using InfoNode::format;
virtual void STORM_FN format(StrBuf *to) const;
// Get the size of this node.
virtual Nat STORM_FN dbg_size();
protected:
// Compute the lenght of this node.
virtual Nat STORM_FN computeLength();
private:
// Instance of which production?
Production *prod;
// Data.
GcArray<InfoNode *> *children;
// Throw out of bounds error.
void outOfBounds(Nat id);
};
/**
* Leaf node. Contains the string matched at the leaf.
*/
class InfoLeaf : public InfoNode {
STORM_CLASS;
public:
// Create.
STORM_CTOR InfoLeaf(MAYBE(RegexToken *) regex, Str *match);
// Find leaf nodes.
virtual MAYBE(InfoLeaf *) STORM_FN leafAt(Nat pos);
// Set value.
void set(Str *v);
// Get the matching regex.
inline MAYBE(RegexToken *) STORM_FN matches() const { return regex; }
// Does the content of this node match the regex in here? Returns 'false' if this node
// does not contain a regex.
Bool STORM_FN matchesRegex() const;
Bool STORM_FN matchesRegex(Str *v) const;
// To string.
virtual Str *STORM_FN toS() const;
// To string.
virtual void STORM_FN toS(StrBuf *to) const;
// Format.
using InfoNode::format;
virtual void STORM_FN format(StrBuf *to) const;
// Get the size of this node.
virtual Nat STORM_FN dbg_size();
protected:
// Compute the lenght of this node.
virtual Nat STORM_FN computeLength();
private:
// Which regex did this leaf match?
MAYBE(RegexToken *) regex;
// The matched string.
Str *v;
};
}
}
|