Skip to content

Commit

Permalink
Validate selections on the ParseTree
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnDTill committed Aug 5, 2023
1 parent 28e35a3 commit 192ef14
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 21 deletions.
9 changes: 8 additions & 1 deletion meta/ast_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,18 @@ def main():
source_file.write(
f"{T} ParseTree::{getter}(ParseNode pn) const noexcept {{\n"
" assert(isNode(pn));\n"
)
if field.property == "selection":
source_file.write(f" assert(({const_ref}).inValidState());\n")
source_file.write(
f" return {const_ref};\n"
"}\n\n"
)
source_file.write(
f"void ParseTree::{setter}(ParseNode pn, {T} {field.property}) noexcept {{\n"
f"void ParseTree::{setter}(ParseNode pn, {T} {field.property}) noexcept {{\n")
if field.property == "selection":
source_file.write(" //assert(selection.inValidState()); //DO THIS\n")
source_file.write(
" assert(isNode(pn));\n"
f" {ref} = {field.property};\n"
"}\n\n"
Expand Down
4 changes: 4 additions & 0 deletions src/forscape_parse_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,24 @@ bool ParseTree::empty() const noexcept {

const Typeset::Marker& ParseTree::getLeft(ParseNode pn) const noexcept {
assert(isNode(pn));
assert(reinterpret_cast<const Typeset::Marker*>(data.data()+pn+LEFT_MARKER_OFFSET)->inValidState());
return *reinterpret_cast<const Typeset::Marker*>(data.data()+pn+LEFT_MARKER_OFFSET);
}

void ParseTree::setLeft(ParseNode pn, const Typeset::Marker& m) noexcept {
assert(m.inValidState());
assert(isNode(pn));
*reinterpret_cast<Typeset::Marker*>(data.data()+pn+LEFT_MARKER_OFFSET) = m;
}

const Typeset::Marker& ParseTree::getRight(ParseNode pn) const noexcept {
assert(isNode(pn));
assert(reinterpret_cast<const Typeset::Marker*>(data.data()+pn+RIGHT_MARKER_OFFSET)->inValidState());
return *reinterpret_cast<const Typeset::Marker*>(data.data()+pn+RIGHT_MARKER_OFFSET);
}

void ParseTree::setRight(ParseNode pn, const Typeset::Marker& m) noexcept {
assert(m.inValidState());
assert(isNode(pn));
*reinterpret_cast<Typeset::Marker*>(data.data()+pn+RIGHT_MARKER_OFFSET) = m;
}
Expand Down
33 changes: 16 additions & 17 deletions src/forscape_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ ParseNode Parser::settingsStatement() alloc_except {
}

ParseNode Parser::switchStatement() alloc_except {
Typeset::Marker start;
Typeset::Marker start = lMark();
advance();
Typeset::Marker cond_l = lMark();
if(!match(LEFTPAREN)) return error(EXPECT_LPAREN);
Expand Down Expand Up @@ -948,7 +948,7 @@ ParseNode Parser::rightUnary(ParseNode n) alloc_except {
ParseNode pn = parse_tree.addNode<2>(OP_POWER, {n, implicitMult()});
return pn;
}
case TOKEN_SUPERSCRIPT: n = superscript(n); break;
case TOKEN_SUPERSCRIPT: n = superscript(n, parse_tree.getLeft(n)); break;
case TOKEN_SUBSCRIPT: n = subscript(n, rMark()); break;
case TOKEN_DUALSCRIPT: n = dualscript(n); break;
case PERIOD: advance();
Expand Down Expand Up @@ -1621,61 +1621,60 @@ ParseNode Parser::binomial() alloc_except {
return parse_tree.addNode<2>(OP_BINOMIAL, c, {n, k});
}

ParseNode Parser::superscript(ParseNode lhs) alloc_except {
Typeset::Marker left = parse_tree.getLeft(lhs);
Typeset::Marker right = rMark();
Typeset::Selection c(left, right);
ParseNode Parser::superscript(ParseNode lhs, Typeset::Marker left) alloc_except {
advance();

ParseNode n;

switch (currentType()) {
case TRANSPOSE:{
advance();
n = parse_tree.addUnary(OP_TRANSPOSE, c, lhs);
n = parse_tree.addUnary(OP_TRANSPOSE, Typeset::Selection(left, rMark()), lhs);
break;
}
case DAGGER:{
advance();
n = parse_tree.addUnary(OP_DAGGER, c, lhs);
n = parse_tree.addUnary(OP_DAGGER, Typeset::Selection(left, rMark()), lhs);
break;
}
case PLUS:{
advance();
n = parse_tree.addUnary(OP_PSEUDO_INVERSE, c, lhs);
n = parse_tree.addUnary(OP_PSEUDO_INVERSE, Typeset::Selection(left, rMark()), lhs);
break;
}
case CONJUNCTION:
case CARET:{
advance();
n = parse_tree.addUnary(OP_ACCENT_HAT, c, lhs);
n = parse_tree.addUnary(OP_ACCENT_HAT, Typeset::Selection(left, rMark()), lhs);
break;
}
case DISJUNCTION:{
advance();
n = parse_tree.addUnary(OP_BIJECTIVE_MAPPING, c, lhs);
n = parse_tree.addUnary(OP_BIJECTIVE_MAPPING, Typeset::Selection(left, rMark()), lhs);
break;
}
case COMPLEMENT:{
advance();
n = parse_tree.addUnary(OP_COMPLEMENT, c, lhs);
n = parse_tree.addUnary(OP_COMPLEMENT, Typeset::Selection(left, rMark()), lhs);
break;
}
default:
static constexpr size_t TYPESET_RATHER_THAN_CARET = 1;
if(parse_tree.getOp(lhs) == OP_POWER && parse_tree.getFlag(lhs) == TYPESET_RATHER_THAN_CARET){
//Due to typesetting the precedence of adjacent scritps x^{a}^{b} would parse incorrectly
//Due to typesetting the precedence of adjacent scripts x^{a}^{b} would parse incorrectly
//as (x^{a})^{b}, except that we patch it here
index--;
ParseNode new_power = superscript(parse_tree.rhs(lhs));
ParseNode new_power = superscript(parse_tree.rhs(lhs), parse_tree.getRight(parse_tree.lhs(lhs)));
parse_tree.setArg<1>(lhs, new_power);
parse_tree.setRight(lhs, right);
parse_tree.setRight(lhs, rMark());
return lhs;
}
n = parse_tree.addNode<2>(OP_POWER, c, {lhs, expression()});
ParseNode exponent = expression();
n = parse_tree.addNode<2>(OP_POWER, Typeset::Selection(left, rMark()), {lhs, exponent});
parse_tree.setFlag(n, TYPESET_RATHER_THAN_CARET);
}

//DO THIS: this will result in invalid selections (read: crashes)
consume(ARGCLOSE);

return n;
Expand Down Expand Up @@ -1778,7 +1777,6 @@ ParseNode Parser::matrix() alloc_except {
const Typeset::Selection& c = selection();
advance();
size_t argc = c.getConstructArgSize();
if(argc == 1) return error(SCALAR_MATRIX, c);

parse_tree.prepareNary();
for(size_t i = 0; i < argc; i++){
Expand All @@ -1788,6 +1786,7 @@ ParseNode Parser::matrix() alloc_except {

ParseNode m = parse_tree.finishNary(OP_MATRIX, c);
parse_tree.setFlag(m, c.getMatrixRows());
if(argc == 1) return error(SCALAR_MATRIX, c);
#ifndef FORSCAPE_TYPESET_HEADLESS
if(noErrors()) c.mapConstructToParseNode(m);
#endif
Expand Down
2 changes: 1 addition & 1 deletion src/forscape_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class Parser {
ParseNode fractionDeriv(const Typeset::Selection& c, Op type, ForscapeTokenType tt) alloc_except;
ParseNode fractionDefault(const Typeset::Selection& c) alloc_except;
ParseNode binomial() alloc_except;
ParseNode superscript(ParseNode lhs) alloc_except;
ParseNode superscript(ParseNode lhs, Typeset::Marker left) alloc_except;
ParseNode subscript(ParseNode lhs, const Typeset::Marker& right) alloc_except;
ParseNode dualscript(ParseNode lhs) alloc_except;
template<bool first_arg = false> ParseNode subExpr() alloc_except;
Expand Down
6 changes: 6 additions & 0 deletions src/typeset_marker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ bool Marker::goToCommandStart() noexcept {
}
}

#ifndef NDEBUG
bool Marker::inValidState() const noexcept {
return text != nullptr && index != NONE;
}
#endif

#ifndef FORSCAPE_TYPESET_HEADLESS
double Marker::x() const {
return text->xGlobal(index);
Expand Down
4 changes: 4 additions & 0 deletions src/typeset_marker.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ struct Marker{
void setToLeftOf(Text* t, double setpoint);
#endif

#ifndef NDEBUG
bool inValidState() const noexcept;
#endif

std::pair<ParseNode, ParseNode> parseNodesAround() const noexcept;
ParseNode parseNodeLeft() const noexcept;
ParseNode parseNodeRight() const noexcept;
Expand Down
17 changes: 16 additions & 1 deletion src/typeset_selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,22 @@ std::array<double, 4> Selection::getDimensionsLines() const noexcept {
#endif

#ifndef NDEBUG
bool Selection::inValidState() const {
bool Selection::inValidState() const noexcept {
if(!left.inValidState()){
std::cout << "Left marker invalid" << std::endl;
return false;
}

if(!right.inValidState()){
std::cout << "Right marker invalid" << std::endl;
return false;
}

if(left.getModel() != right.getModel()){
std::cout << "Markers are not from same model" << std::endl;
return false;
}

if(left.phrase() != right.phrase() && (left.isNested() || right.isNested())){
std::cout << "Markers are not on same level" << std::endl;
return false;
Expand Down
2 changes: 1 addition & 1 deletion src/typeset_selection.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Selection{
#endif

#ifndef NDEBUG
bool inValidState() const;
bool inValidState() const noexcept;
#endif

#ifdef QT_CORE_LIB
Expand Down

0 comments on commit 192ef14

Please sign in to comment.