Skip to content

Commit

Permalink
Scripting|Info|libcore: No exception when parsing an embedded script
Browse files Browse the repository at this point in the history
ScriptLex can now be told to stop parsing statements when it encounters
a mismatched closing }. This occurs normally when a Doomsday Script
block is parsed inside an Info document, because the Info parser has
no way of knowing how long the embedded script is unless it actually
parses it using ScriptLex.

Previously ScriptLex just blindly tried to read statements until it
hit an exception.
  • Loading branch information
skyjake committed Aug 18, 2015
1 parent 6c93ced commit ed676b2
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 22 deletions.
20 changes: 16 additions & 4 deletions doomsday/sdk/libcore/include/de/scriptsys/scriptlex.h
Expand Up @@ -14,15 +14,17 @@
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy of
* the GNU Lesser General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_SCRIPTLEX_H
#define LIBDENG2_SCRIPTLEX_H

#include "../Lex"
#include "../TokenBuffer"

#include <QFlags>

namespace de {

#ifdef WIN32
Expand Down Expand Up @@ -88,17 +90,25 @@ class DENG2_PUBLIC ScriptLex : public Lex
static String const SCOPE_ASSIGN;
static String const WEAK_ASSIGN;

enum Behavior
{
DefaultBehavior = 0,
StopAtMismatchedCloseBrace = 0x1 ///< Mismatched } is treated as end of input.
};
Q_DECLARE_FLAGS(Behaviors, Behavior)

public:
ScriptLex(String const &input = "");

/**
* Analyze one complete statement from the input.
*
* @param output Buffer for output tokens.
* @param output Buffer for output tokens.
* @param behavior Parsing behavior.
*
* @return The number of tokens added to the output token buffer.
*/
duint getStatement(TokenBuffer &output);
duint getStatement(TokenBuffer &output, Behaviors const &behavior = DefaultBehavior);

/**
* Parse a string.
Expand Down Expand Up @@ -134,6 +144,8 @@ class DENG2_PUBLIC ScriptLex : public Lex
static ddouble tokenToNumber(Token const &token);
};

Q_DECLARE_OPERATORS_FOR_FLAGS(ScriptLex::Behaviors)

} // namespace de

#endif /* LIBDENG2_SCRIPTLEX_H */
25 changes: 8 additions & 17 deletions doomsday/sdk/libcore/src/data/info.cpp
Expand Up @@ -350,29 +350,20 @@ DENG2_PIMPL(Info)
return value;
}

InfoValue parseScript(int numStatements = 0)
InfoValue parseScript(int requiredStatementCount = 0)
{
int startPos = cursor - 1;
String remainder = content.substr(startPos);
ScriptLex lex(remainder);
try
{
TokenBuffer tokens;
int count = 0;

// Read an appropriate number of statements.
while(lex.getStatement(tokens))
{
if(numStatements > 0 && ++count == numStatements)
goto success;
}
throw SyntaxError("Info::parseScript",
QString("Unexpected end of script starting at line %1").arg(currentLine));
success:;
}
catch(ScriptLex::MismatchedBracketError const &)
TokenBuffer tokens;
int count = 0;

// Read an appropriate number of statements.
while(lex.getStatement(tokens, ScriptLex::StopAtMismatchedCloseBrace))
{
// A mismatched bracket signals the end of the script block.
if(requiredStatementCount > 0 &&
++count == requiredStatementCount) break; // We're good now.
}

// Continue parsing normally from here.
Expand Down
10 changes: 9 additions & 1 deletion doomsday/sdk/libcore/src/scriptsys/scriptlex.cpp
Expand Up @@ -60,7 +60,7 @@ String const ScriptLex::WEAK_ASSIGN("?=");
ScriptLex::ScriptLex(String const &input) : Lex(input)
{}

duint ScriptLex::getStatement(TokenBuffer &output)
duint ScriptLex::getStatement(TokenBuffer &output, Behaviors const &behavior)
{
// Get rid of the previous contents of the token buffer.
output.clear();
Expand Down Expand Up @@ -90,6 +90,14 @@ duint ScriptLex::getStatement(TokenBuffer &output)
// Tokens are primarily separated by whitespace.
skipWhiteExceptNewline();

if(behavior.testFlag(StopAtMismatchedCloseBrace) &&
!bracketLevel[BRACKET_CURLY] &&
peek() == '}')
{
// Don't read past the bracket.
break;
}

// This will be the first character of the token.
QChar c = get();

Expand Down

0 comments on commit ed676b2

Please sign in to comment.