Skip to content

Commit

Permalink
On the way to improve the GUI parser.
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Nov 18, 2017
1 parent 4fa50d3 commit b515d2c
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 51 deletions.
186 changes: 141 additions & 45 deletions plugins/dm.gui/gui/GuiExpression.cpp
Expand Up @@ -7,40 +7,52 @@

#include "string/trim.h"
#include "string/convert.h"
#include "string/predicate.h"

namespace gui
{

namespace detail
{

// Specialised implementations of the GuiExpression below

// An expression representing a constant floating point number
class ConstantExpression :
public GuiExpression
ConstantExpression::ConstantExpression(const std::string& stringValue) :
GuiExpression(),
_stringValue(stringValue),
_floatValue(string::convert<float>(stringValue, 0.0f))
{}

ConstantExpression::ConstantExpression(float value) :
GuiExpression(),
_stringValue(string::to_string(value)),
_floatValue(value)
{}

float ConstantExpression::getFloatValue()
{
private:
float _floatValue;
std::string _stringValue;
return _floatValue;
}

public:
ConstantExpression(std::string stringValue) :
GuiExpression(),
_stringValue(stringValue),
_floatValue(string::convert<float>(stringValue, 0.0f))
{}
std::string ConstantExpression::getStringValue()
{
return _stringValue;
}

virtual float getFloatValue() override
{
return _floatValue;
}
// An expression referring to a GUI state variable
GuiStateVariableExpression::GuiStateVariableExpression(const std::string& variableName) :
_variableName(variableName)
{}

virtual std::string getStringValue() override
{
return _stringValue;
}
};
float GuiStateVariableExpression::getFloatValue()
{
return 0.0f; // TODO
}

std::string GuiStateVariableExpression::getStringValue()
{
return ""; // TODO
}

namespace detail
{

// Abstract base class for an expression taking two sub-expression as arguments
// Additions, Multiplications, Divisions, Modulo, comparisons, etc.
Expand Down Expand Up @@ -396,15 +408,113 @@ class GuiExpressionParser

bool lastTokenWasOperator = false; // to detect signs

enum {
SearchingForOperand,
SearchingForOperator,
} searchState;

searchState = SearchingForOperand;

while (_tokeniser.hasMoreTokens())
{
// Don't actually pull the token from the tokeniser, we might want to
// return the tokeniser to the caller if the token is not part of the expression
// The token will be exhausted from the stream once it is recognised as keyword
std::string token = _tokeniser.peek();

// Get a new term, push it on the stack
GuiExpressionPtr term;
if (searchState == SearchingForOperand)
{
// The parsed operand
GuiExpressionPtr term;

if (token == "(")
{
_tokeniser.nextToken(); // valid token, exhaust

// New scope, treat this as new expression
term = getExpression();
}
else if (token == ")")
{
_tokeniser.nextToken(); // valid token, exhaust

// End of scope reached, break the loop and roll up the expression
break;
}
else if (string::starts_with(token, "gui::"))
{
// This is a GUI state variable
_tokeniser.nextToken();
term = std::make_shared<GuiStateVariableExpression>(token.substr(5));
}
// If this is a + or -, take it as a sign operator
else if (token == "+")
{
// A leading +, just ignore it
_tokeniser.nextToken();
continue;
}
else if (token == "-")
{
// A leading -, interpret it as -1 *
operands.push(std::make_shared<ConstantExpression>(-1.0f));
operators.push(std::make_shared<MultiplyExpression>());

// Discard the - token
_tokeniser.nextToken();
continue;
}
else
{
// This might either be a float or a string constant
term = std::make_shared<ConstantExpression>(_tokeniser.nextToken());
}

if (!term)
{
break; // We've run out of terms
}

// The token has already been pulled from the tokeniser
operands.push(term);

// Look for an operator next
searchState = SearchingForOperator;
continue;
}
else if (searchState == SearchingForOperator)
{
// Get an operator
BinaryExpressionPtr op = getOperatorForToken(token);

if (op)
{
_tokeniser.nextToken(); // valid token, exhaust

// Check precedence if we have previous operators
while (!operators.empty())
{
if (operators.top()->getPrecedence() <= op->getPrecedence())
{
finaliseOperator(operands, operators);
}
else
{
break;
}
}

// Push this one on the operator stack
operators.push(op);
searchState = SearchingForOperand; // back to operand search mode
continue;
}

// Not an operator, break the loop
break;
}
#if 0


if (token == "(")
{
Expand All @@ -420,25 +530,10 @@ class GuiExpressionParser
// End of scope reached, break the loop and roll up the expression
break;
}
else
else if (string::starts_with(token, "gui::"))
{
// No parentheses
if (operands.empty())
{
// No operands yet, get a new one
term = getTerm(token);
operands.push(term);

lastTokenWasOperator = false;
}
else
{
// We already have an operand, require an operator next

}


continue;
// This is a GUI state variable
term = std::make_shared<GuiStateVariableExpression>(token.substr(5));
}

if (term)
Expand Down Expand Up @@ -507,6 +602,7 @@ class GuiExpressionParser

// Not an operand, not an operator, we seem to be done here
break;
#endif
}

// Roll up the operations
Expand Down Expand Up @@ -650,7 +746,7 @@ GuiExpressionPtr GuiExpression::createFromTokens(parser::DefTokeniser& tokeniser
}
catch (parser::ParseException& ex)
{
rWarning() << "[shaders] " << ex.what() << std::endl;
rWarning() << "[GuiExpressionParser] " << ex.what() << std::endl;
return GuiExpressionPtr();
}
}
Expand Down
29 changes: 29 additions & 0 deletions plugins/dm.gui/gui/GuiExpression.h
Expand Up @@ -26,5 +26,34 @@ class GuiExpression
static GuiExpressionPtr createFromTokens(parser::DefTokeniser& tokeniser);
};

// An expression representing a constant floating point number
class ConstantExpression :
public GuiExpression
{
private:
float _floatValue;
std::string _stringValue;

public:
ConstantExpression(const std::string& stringValue);

explicit ConstantExpression(float value);

virtual float getFloatValue();
virtual std::string getStringValue();
};

class GuiStateVariableExpression :
public GuiExpression
{
private:
std::string _variableName;
public:
GuiStateVariableExpression(const std::string& variableName);

virtual float getFloatValue() override;
virtual std::string getStringValue() override;
};

}

2 changes: 1 addition & 1 deletion plugins/dm.gui/gui/GuiScript.cpp
Expand Up @@ -77,7 +77,7 @@ void GuiScript::parseSetStatement(parser::DefTokeniser& tokeniser)
{
if (tokeniser.peek() == ";") break;

st->args.push_back(getExpression(tokeniser)); // argument
st->args.push_back(std::make_shared<ConstantExpression>(tokeniser.nextToken())); // argument
}

pushStatement(st);
Expand Down
29 changes: 24 additions & 5 deletions plugins/dm.gui/gui/GuiWindowDef.cpp
Expand Up @@ -9,6 +9,7 @@
#include "string/trim.h"
#include "string/case_conv.h"
#include "string/replace.h"
#include "string/predicate.h"

#include "GuiScript.h"

Expand Down Expand Up @@ -131,13 +132,18 @@ int GuiWindowDef::parseInt(parser::DefTokeniser& tokeniser)

std::string GuiWindowDef::parseString(parser::DefTokeniser& tokeniser)
{
GuiExpressionPtr expr = getExpression(tokeniser);
std::string token = tokeniser.peek();
GuiExpressionPtr expr;

if (!expr)
if (string::starts_with(token, "gui::"))
{
expr = std::make_shared<GuiStateVariableExpression>(tokeniser.nextToken().substr(5));
}
else
{
throw parser::ParseException("Failed to parse string expression.");
expr = std::make_shared<ConstantExpression>(tokeniser.nextToken());
}

return expr->getStringValue();
}

Expand All @@ -163,7 +169,7 @@ void GuiWindowDef::constructFromTokens(parser::DefTokeniser& tokeniser)
// The windowDef keyword has already been parsed, so expect a name plus an opening brace here
name = tokeniser.nextToken();

if (name == "LoadGameTextH")
if (name == "NewGameRefreshAction")
{
int i = 6;
}
Expand Down Expand Up @@ -196,6 +202,10 @@ void GuiWindowDef::constructFromTokens(parser::DefTokeniser& tokeniser)
{
forecolor = parseVector4(tokeniser);
}
else if (token == "hovercolor")
{
hovercolor = parseVector4(tokeniser);
}
else if (token == "backcolor")
{
backcolor = parseVector4(tokeniser);
Expand Down Expand Up @@ -354,6 +364,15 @@ void GuiWindowDef::constructFromTokens(parser::DefTokeniser& tokeniser)
std::string variableName = tokeniser.nextToken();
parseVector4(tokeniser);
}
else if (token == "listdef")
{
tokeniser.assertNextToken("{");

while (tokeniser.hasMoreTokens())
{
if (tokeniser.nextToken() == "}") break;
}
}
else if (token == "}")
{
break;
Expand Down

0 comments on commit b515d2c

Please sign in to comment.