mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 13:37:00 -04:00
added 'string mode' to script parser; added Keyword and related classes
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@85 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+4
-3
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
|
#include <data/keyword.hpp>
|
||||||
#include <data/statistics.hpp>
|
#include <data/statistics.hpp>
|
||||||
#include <util/io/package_manager.hpp>
|
#include <util/io/package_manager.hpp>
|
||||||
#include <script/script.hpp>
|
#include <script/script.hpp>
|
||||||
@@ -52,9 +53,9 @@ IMPLEMENT_REFLECTION(Game) {
|
|||||||
REFLECT(card_fields);
|
REFLECT(card_fields);
|
||||||
REFLECT(statistics_dimensions);
|
REFLECT(statistics_dimensions);
|
||||||
REFLECT(statistics_categories);
|
REFLECT(statistics_categories);
|
||||||
// REFLECT_N("keyword parameter type", keyword_params);
|
REFLECT(keyword_parameter_types);
|
||||||
// REFLECT_N("keyword separator type", keyword_separators);
|
REFLECT(keyword_modes);
|
||||||
// REFLECT(keywords);
|
REFLECT(keywords);
|
||||||
// REFLECT(word_lists);
|
// REFLECT(word_lists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ DECLARE_POINTER_TYPE(Field);
|
|||||||
DECLARE_POINTER_TYPE(Game);
|
DECLARE_POINTER_TYPE(Game);
|
||||||
DECLARE_POINTER_TYPE(StatsDimension);
|
DECLARE_POINTER_TYPE(StatsDimension);
|
||||||
DECLARE_POINTER_TYPE(StatsCategory);
|
DECLARE_POINTER_TYPE(StatsCategory);
|
||||||
|
DECLARE_POINTER_TYPE(KeywordParam);
|
||||||
|
DECLARE_POINTER_TYPE(KeywordMode);
|
||||||
|
DECLARE_POINTER_TYPE(Keyword);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Game
|
// ----------------------------------------------------------------------------- : Game
|
||||||
|
|
||||||
@@ -38,6 +41,10 @@ class Game : public Packaged {
|
|||||||
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
|
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
|
||||||
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
|
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
|
||||||
|
|
||||||
|
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
||||||
|
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
|
||||||
|
vector<KeywordP> keywords; ///< Keywords for use in text
|
||||||
|
|
||||||
vector<Dependency> dependent_scripts_cards; ///< scripts that depend on the card list
|
vector<Dependency> dependent_scripts_cards; ///< scripts that depend on the card list
|
||||||
vector<Dependency> dependent_scripts_keywords; ///< scripts that depend on the keywords
|
vector<Dependency> dependent_scripts_keywords; ///< scripts that depend on the keywords
|
||||||
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
|
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <data/keyword.hpp>
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Reflection
|
||||||
|
|
||||||
|
IMPLEMENT_REFLECTION(KeywordParam) {
|
||||||
|
REFLECT(name);
|
||||||
|
REFLECT(description);
|
||||||
|
REFLECT(match);
|
||||||
|
REFLECT(in_reminder);
|
||||||
|
}
|
||||||
|
IMPLEMENT_REFLECTION(KeywordMode) {
|
||||||
|
REFLECT(name);
|
||||||
|
REFLECT(description);
|
||||||
|
}
|
||||||
|
IMPLEMENT_REFLECTION(KeywordExpansion) {
|
||||||
|
REFLECT(before);
|
||||||
|
REFLECT(after);
|
||||||
|
REFLECT(reminder);
|
||||||
|
}
|
||||||
|
IMPLEMENT_REFLECTION(Keyword) {
|
||||||
|
REFLECT(keyword);
|
||||||
|
REFLECT(expansions);
|
||||||
|
REFLECT(rules);
|
||||||
|
REFLECT(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Using keywords
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
|
||||||
|
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
|
||||||
|
//| License: GNU General Public License 2 or later (see file COPYING) |
|
||||||
|
//+----------------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifndef HEADER_DATA_KEYWORD
|
||||||
|
#define HEADER_DATA_KEYWORD
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
|
#include <util/prec.hpp>
|
||||||
|
#include <script/scriptable.hpp>
|
||||||
|
#include <wx/regex.h>
|
||||||
|
|
||||||
|
DECLARE_POINTER_TYPE(KeywordParam);
|
||||||
|
DECLARE_POINTER_TYPE(KeywordExpansion);
|
||||||
|
DECLARE_POINTER_TYPE(KeywordMode);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Keyword components
|
||||||
|
|
||||||
|
/// Parameter type of keywords
|
||||||
|
class KeywordParam {
|
||||||
|
public:
|
||||||
|
String name; ///< Name of the parameter type
|
||||||
|
String description; ///< Description of the type
|
||||||
|
String match; ///< Uncompiled regex
|
||||||
|
wxRegEx matchRe; ///< Regular expression to match
|
||||||
|
OptionalScript in_reminder; ///< Transformation of the value for showing in the reminder text
|
||||||
|
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Keyword mode
|
||||||
|
|
||||||
|
/// Information on when and how to use a keyword
|
||||||
|
class KeywordMode {
|
||||||
|
String name; ///< Name of the mode
|
||||||
|
String description; ///< Description of the type
|
||||||
|
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Keyword expansion
|
||||||
|
|
||||||
|
/// A way to use a keyword
|
||||||
|
class KeywordExpansion {
|
||||||
|
public:
|
||||||
|
String before; ///< Components before the keyword: parameters and separators (tagged string)
|
||||||
|
String after; ///< Components after the keyword: parameters and separators
|
||||||
|
vector<KeywordParamP> parameters; ///< The types of parameters
|
||||||
|
wxRegEx splitter; ///< Regular expression to split/match the components, automatically generated
|
||||||
|
OptionalScript reminder; ///< Reminder text of the keyword
|
||||||
|
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Keyword
|
||||||
|
|
||||||
|
/// A keyword for a set or a game
|
||||||
|
class Keyword {
|
||||||
|
public:
|
||||||
|
String keyword; ///< The keyword
|
||||||
|
vector<KeywordExpansionP> expansions; ///< Expansions, i.e. ways to use this keyword
|
||||||
|
String rules; ///< Rules/explanation
|
||||||
|
String mode; ///< Mode of use, can be used by scripts (only gives the name)
|
||||||
|
|
||||||
|
DECLARE_REFLECTION();
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : Using keywords
|
||||||
|
|
||||||
|
/// Expand/update all keywords in the given string
|
||||||
|
String expand_keywords(const String& text);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
|
#endif
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
#include <data/stylesheet.hpp>
|
#include <data/stylesheet.hpp>
|
||||||
#include <data/card.hpp>
|
#include <data/card.hpp>
|
||||||
|
#include <data/keyword.hpp>
|
||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
#include <data/field/text.hpp> // for 0.2.7 fix
|
#include <data/field/text.hpp> // for 0.2.7 fix
|
||||||
#include <script/value.hpp>
|
#include <script/value.hpp>
|
||||||
@@ -116,6 +117,7 @@ IMPLEMENT_REFLECTION(Set) {
|
|||||||
REFLECT_N("styling", styling_data);
|
REFLECT_N("styling", styling_data);
|
||||||
}
|
}
|
||||||
REFLECT(cards);
|
REFLECT(cards);
|
||||||
|
REFLECT(keywords);
|
||||||
}
|
}
|
||||||
reflect_set_info_get_member(tag,data);
|
reflect_set_info_get_member(tag,data);
|
||||||
REFLECT(apprentice_code);
|
REFLECT(apprentice_code);
|
||||||
|
|||||||
+7
-10
@@ -22,6 +22,7 @@ DECLARE_POINTER_TYPE(StyleSheet);
|
|||||||
DECLARE_POINTER_TYPE(Styling);
|
DECLARE_POINTER_TYPE(Styling);
|
||||||
DECLARE_POINTER_TYPE(Field);
|
DECLARE_POINTER_TYPE(Field);
|
||||||
DECLARE_POINTER_TYPE(Value);
|
DECLARE_POINTER_TYPE(Value);
|
||||||
|
DECLARE_POINTER_TYPE(Keyword);
|
||||||
class ScriptManager;
|
class ScriptManager;
|
||||||
class Context;
|
class Context;
|
||||||
|
|
||||||
@@ -38,22 +39,18 @@ class Set : public Packaged {
|
|||||||
Set(const StyleSheetP& stylesheet);
|
Set(const StyleSheetP& stylesheet);
|
||||||
~Set();
|
~Set();
|
||||||
|
|
||||||
/// The game this set uses
|
GameP game; ///< The game this set uses
|
||||||
GameP game;
|
StyleSheetP stylesheet; ///< The default stylesheet
|
||||||
/// The default stylesheet
|
|
||||||
StyleSheetP stylesheet;
|
|
||||||
/// The values on the fields of the set
|
/// The values on the fields of the set
|
||||||
/** The indices should correspond to the set_fields in the Game */
|
/** The indices should correspond to the set_fields in the Game */
|
||||||
IndexMap<FieldP, ValueP> data;
|
IndexMap<FieldP, ValueP> data;
|
||||||
/// Extra values for specitic stylesheets, indexed by stylesheet name
|
/// Extra values for specitic stylesheets, indexed by stylesheet name
|
||||||
DECLARE_POINTER_TYPE(Styling);
|
DECLARE_POINTER_TYPE(Styling);
|
||||||
map<String, StylingP> styling_data;
|
map<String, StylingP> styling_data;
|
||||||
/// The cards in the set
|
vector<CardP> cards; ///< The cards in the set
|
||||||
vector<CardP> cards;
|
vector<KeywordP> keywords; ///< Additional keywords used in this set
|
||||||
/// Code to use for apprentice (Magic only)
|
String apprentice_code; ///< Code to use for apprentice (Magic only)
|
||||||
String apprentice_code;
|
ActionStack actions; ///< Actions performed on this set and the cards in it
|
||||||
/// Actions performed on this set and the cards in it
|
|
||||||
ActionStack actions;
|
|
||||||
|
|
||||||
/// A context for performing scripts
|
/// A context for performing scripts
|
||||||
/** Should only be used from the main thread! */
|
/** Should only be used from the main thread! */
|
||||||
|
|||||||
@@ -837,6 +837,12 @@
|
|||||||
<File
|
<File
|
||||||
RelativePath=".\data\game.hpp">
|
RelativePath=".\data\game.hpp">
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\data\keyword.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\data\keyword.hpp">
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\data\set.cpp">
|
RelativePath=".\data\set.cpp">
|
||||||
</File>
|
</File>
|
||||||
|
|||||||
@@ -291,6 +291,14 @@ SCRIPT_FUNCTION(substring) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// does a string contain a substring?
|
||||||
|
SCRIPT_FUNCTION(contains) {
|
||||||
|
SCRIPT_PARAM(String, input);
|
||||||
|
SCRIPT_PARAM(String, match);
|
||||||
|
SCRIPT_RETURN(input.find(match) != String::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Vector stuff
|
// ----------------------------------------------------------------------------- : Vector stuff
|
||||||
|
|
||||||
/// position of some element in a vector
|
/// position of some element in a vector
|
||||||
@@ -322,6 +330,7 @@ void init_script_functions(Context& ctx) {
|
|||||||
ctx.setVariable(_("to lower"), script_to_lower);
|
ctx.setVariable(_("to lower"), script_to_lower);
|
||||||
ctx.setVariable(_("to title"), script_to_title);
|
ctx.setVariable(_("to title"), script_to_title);
|
||||||
ctx.setVariable(_("substring"), script_substring);
|
ctx.setVariable(_("substring"), script_substring);
|
||||||
|
ctx.setVariable(_("contains"), script_contains);
|
||||||
ctx.setVariable(_("position"), script_position_of);
|
ctx.setVariable(_("position"), script_position_of);
|
||||||
ctx.setVariable(_("number of items"), script_number_of_items);
|
ctx.setVariable(_("number of items"), script_number_of_items);
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-18
@@ -44,11 +44,16 @@ struct Token {
|
|||||||
inline operator != (const String& s) const { return type == TOK_STRING || value != s; }
|
inline operator != (const String& s) const { return type == TOK_STRING || value != s; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum OpenBrace
|
||||||
|
{ BRACE_STRING // "
|
||||||
|
, BRACE_STRING_MODE // fake brace for string mode
|
||||||
|
, BRACE_PAREN // (, [, {
|
||||||
|
};
|
||||||
|
|
||||||
/// Iterator over a string, one token at a time
|
/// Iterator over a string, one token at a time
|
||||||
class TokenIterator {
|
class TokenIterator {
|
||||||
public:
|
public:
|
||||||
TokenIterator(const String& str);
|
TokenIterator(const String& str, bool string_mode);
|
||||||
|
|
||||||
/// Peek at the next token, doesn't move to the one after that
|
/// Peek at the next token, doesn't move to the one after that
|
||||||
/** Can peek further forward by using higher values of offset.
|
/** Can peek further forward by using higher values of offset.
|
||||||
@@ -65,9 +70,9 @@ class TokenIterator {
|
|||||||
private:
|
private:
|
||||||
String input;
|
String input;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
vector<Token> buffer; ///< buffer of unread tokens, front() = current
|
vector<Token> buffer; ///< buffer of unread tokens, front() = current
|
||||||
stack<bool> open_braces; ///< braces we entered, true if the brace was from a smart string escape
|
stack<OpenBrace> open_braces; ///< braces/quotes we entered from script mode
|
||||||
bool newline; ///< Did we just pass a newline?
|
bool newline; ///< Did we just pass a newline?
|
||||||
// more input?
|
// more input?
|
||||||
struct MoreInput {
|
struct MoreInput {
|
||||||
String input;
|
String input;
|
||||||
@@ -96,11 +101,17 @@ bool isLongOper(const String& s) { return s==_(":=") || s==_("==") || s==_("!=")
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Tokenizing
|
// ----------------------------------------------------------------------------- : Tokenizing
|
||||||
|
|
||||||
TokenIterator::TokenIterator(const String& str)
|
TokenIterator::TokenIterator(const String& str, bool string_mode)
|
||||||
: input(str)
|
: input(str)
|
||||||
, pos(0)
|
, pos(0)
|
||||||
, newline(false)
|
, newline(false)
|
||||||
{}
|
{
|
||||||
|
if (string_mode) {
|
||||||
|
open_braces.push(BRACE_STRING_MODE);
|
||||||
|
putBack();//dummy
|
||||||
|
readStringToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const Token& TokenIterator::peek(size_t offset) {
|
const Token& TokenIterator::peek(size_t offset) {
|
||||||
// read the next token until we have enough
|
// read the next token until we have enough
|
||||||
@@ -190,16 +201,16 @@ void TokenIterator::readToken() {
|
|||||||
}
|
}
|
||||||
} else if (c==_('"')) {
|
} else if (c==_('"')) {
|
||||||
// string
|
// string
|
||||||
|
open_braces.push(BRACE_STRING);
|
||||||
readStringToken();
|
readStringToken();
|
||||||
} else if (c == _('}') && !open_braces.empty() && open_braces.top()) {
|
} else if (c == _('}') && !open_braces.empty() && open_braces.top() != BRACE_PAREN) {
|
||||||
// closing smart string, resume to string parsing
|
// closing smart string, resume to string parsing
|
||||||
// "a{e}b" --> "a" "{ e }" "b"
|
// "a{e}b" --> "a" "{ e }" "b"
|
||||||
open_braces.pop();
|
|
||||||
addToken(TOK_RPAREN, _("}\""));
|
addToken(TOK_RPAREN, _("}\""));
|
||||||
readStringToken();
|
readStringToken();
|
||||||
} else if (isLparen(c)) {
|
} else if (isLparen(c)) {
|
||||||
// paranthesis/brace
|
// paranthesis/brace
|
||||||
open_braces.push(false);
|
open_braces.push(BRACE_PAREN);
|
||||||
addToken(TOK_LPAREN, String(1,c));
|
addToken(TOK_LPAREN, String(1,c));
|
||||||
} else if (isRparen(c)) {
|
} else if (isRparen(c)) {
|
||||||
// paranthesis/brace
|
// paranthesis/brace
|
||||||
@@ -216,17 +227,26 @@ void TokenIterator::readToken() {
|
|||||||
void TokenIterator::readStringToken() {
|
void TokenIterator::readStringToken() {
|
||||||
String str;
|
String str;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (pos >= input.size()) throw ScriptParseError(_("Unexpected end of input in string constant"));
|
if (pos >= input.size()) {
|
||||||
Char c = input[pos++]; //% input.GetChar(pos++);
|
if (!open_braces.empty() && open_braces.top() == BRACE_STRING_MODE) {
|
||||||
|
// in string mode: end of input = end of string
|
||||||
|
addToken(TOK_STRING, str);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
throw ScriptParseError(_("Unexpected end of input in string constant"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Char c = input.GetChar(pos++);
|
||||||
// parse the string constant
|
// parse the string constant
|
||||||
if (c == _('"')) {
|
if (c == _('"') && !open_braces.empty() && open_braces.top() == BRACE_STRING) {
|
||||||
// end of string
|
// end of string
|
||||||
addToken(TOK_STRING, str);
|
addToken(TOK_STRING, str);
|
||||||
|
open_braces.pop();
|
||||||
return;
|
return;
|
||||||
} else if (c == _('\\')) {
|
} else if (c == _('\\')) {
|
||||||
// escape
|
// escape
|
||||||
if (pos >= input.size()) throw ScriptParseError(_("Unexpected end of input in string constant"));
|
if (pos >= input.size()) throw ScriptParseError(_("Unexpected end of input in string constant"));
|
||||||
c = input[pos++];
|
c = input.GetChar(pos++);
|
||||||
if (c == _('n')) str += _('\n');
|
if (c == _('n')) str += _('\n');
|
||||||
if (c == _('<')) str += _('\1'); // escape for <
|
if (c == _('<')) str += _('\1'); // escape for <
|
||||||
else str += c; // \ or { or "
|
else str += c; // \ or { or "
|
||||||
@@ -234,7 +254,6 @@ void TokenIterator::readStringToken() {
|
|||||||
// smart string
|
// smart string
|
||||||
// "a{e}b" --> "a" "{ e }" "b"
|
// "a{e}b" --> "a" "{ e }" "b"
|
||||||
addToken(TOK_STRING, str);
|
addToken(TOK_STRING, str);
|
||||||
open_braces.push(true);
|
|
||||||
addToken(TOK_LPAREN, _("\"{"));
|
addToken(TOK_LPAREN, _("\"{"));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -280,8 +299,8 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec);
|
|||||||
*/
|
*/
|
||||||
void parseOper(TokenIterator& input, Script& script, Precedence minPrec, InstructionType closeWith = I_NOP, int closeWithData = 0);
|
void parseOper(TokenIterator& input, Script& script, Precedence minPrec, InstructionType closeWith = I_NOP, int closeWithData = 0);
|
||||||
|
|
||||||
ScriptP parse(const String& s) {
|
ScriptP parse(const String& s, bool string_mode) {
|
||||||
TokenIterator input(s);
|
TokenIterator input(s, string_mode);
|
||||||
ScriptP script(new Script);
|
ScriptP script(new Script);
|
||||||
parseOper(input, *script, PREC_ALL, I_RET);
|
parseOper(input, *script, PREC_ALL, I_RET);
|
||||||
if (input.peek() != TOK_EOF) {
|
if (input.peek() != TOK_EOF) {
|
||||||
@@ -500,9 +519,23 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
|
|||||||
}
|
}
|
||||||
} else if (minPrec <= PREC_STRING && token==_("\"{")) {
|
} else if (minPrec <= PREC_STRING && token==_("\"{")) {
|
||||||
// for smart strings: "x" {{ e }} "y"
|
// for smart strings: "x" {{ e }} "y"
|
||||||
parseOper(input, script, PREC_ALL, I_BINARY, I_ADD); // e
|
// optimize: "" + e -> e
|
||||||
|
Instruction i = script.getInstructions().back();
|
||||||
|
if (i.instr == I_PUSH_CONST && String(*script.getConstants()[i.data]).empty()) {
|
||||||
|
script.getInstructions().pop_back();
|
||||||
|
parseOper(input, script, PREC_ALL); // e
|
||||||
|
} else {
|
||||||
|
parseOper(input, script, PREC_ALL, I_BINARY, I_ADD); // e
|
||||||
|
}
|
||||||
expectToken(input, _("}\""));
|
expectToken(input, _("}\""));
|
||||||
parseOper(input, script, PREC_NONE, I_BINARY, I_ADD); // y
|
parseOper(input, script, PREC_NONE); // y
|
||||||
|
// optimize: e + "" -> e
|
||||||
|
i = script.getInstructions().back();
|
||||||
|
if (i.instr == I_PUSH_CONST && String(*script.getConstants()[i.data]).empty()) {
|
||||||
|
script.getInstructions().pop_back();
|
||||||
|
} else {
|
||||||
|
script.addInstruction(I_BINARY, I_ADD);
|
||||||
|
}
|
||||||
} else if (minPrec <= PREC_NEWLINE && token.newline) {
|
} else if (minPrec <= PREC_NEWLINE && token.newline) {
|
||||||
// newline functions as ;
|
// newline functions as ;
|
||||||
// only if we don't match another token!
|
// only if we don't match another token!
|
||||||
|
|||||||
@@ -14,8 +14,11 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Parser
|
// ----------------------------------------------------------------------------- : Parser
|
||||||
|
|
||||||
// Parse a String to a Script
|
/// Parse a String to a Script
|
||||||
ScriptP parse(const String& s);
|
/** If string_mode then s is interpreted as a string,
|
||||||
|
* escaping to script mode can be done with {}
|
||||||
|
*/
|
||||||
|
ScriptP parse(const String& s, bool string_mode = false);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EOF
|
// ----------------------------------------------------------------------------- : EOF
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ class Script : public ScriptValue {
|
|||||||
|
|
||||||
/// Get access to the vector of instructions
|
/// Get access to the vector of instructions
|
||||||
inline vector<Instruction>& getInstructions() { return instructions; }
|
inline vector<Instruction>& getInstructions() { return instructions; }
|
||||||
|
/// Get access to the vector of constants
|
||||||
|
inline vector<ScriptValueP>& getConstants() { return constants; }
|
||||||
|
|
||||||
/// Output the instructions in a human readable format
|
/// Output the instructions in a human readable format
|
||||||
String dumpScript() const;
|
String dumpScript() const;
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ ScriptValueP OptionalScript::invoke(Context& ctx, bool open_scope) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OptionalScript::parse(Reader& reader) {
|
void OptionalScript::parse(Reader& reader, bool string_mode) {
|
||||||
try {
|
try {
|
||||||
script = ::parse(unparsed);
|
script = ::parse(unparsed, string_mode);
|
||||||
} catch (const ParseError& e) {
|
} catch (const ParseError& e) {
|
||||||
reader.warning(e.what());
|
reader.warning(e.what());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class OptionalScript {
|
|||||||
ScriptP script; ///< The script, may be null if there is no script
|
ScriptP script; ///< The script, may be null if there is no script
|
||||||
String unparsed; ///< Unparsed script, for writing back to a file
|
String unparsed; ///< Unparsed script, for writing back to a file
|
||||||
// parse the unparsed string, while reading
|
// parse the unparsed string, while reading
|
||||||
void parse(Reader&);
|
void parse(Reader&, bool string_mode = false);
|
||||||
DECLARE_REFLECTION();
|
DECLARE_REFLECTION();
|
||||||
template <typename T> friend class Scriptable;
|
template <typename T> friend class Scriptable;
|
||||||
};
|
};
|
||||||
@@ -126,6 +126,8 @@ void Reader::handle(Scriptable<T>& s) {
|
|||||||
if (starts_with(s.script.unparsed, _("script:"))) {
|
if (starts_with(s.script.unparsed, _("script:"))) {
|
||||||
s.script.unparsed = s.script.unparsed.substr(7);
|
s.script.unparsed = s.script.unparsed.substr(7);
|
||||||
s.script.parse(*this);
|
s.script.parse(*this);
|
||||||
|
} else if (s.script.unparsed.find_first_of('{') != String.npos) {
|
||||||
|
s.script.parse(*this, true);
|
||||||
} else {
|
} else {
|
||||||
handle(s.value);
|
handle(s.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,6 +170,14 @@ class ScriptString : public ScriptValue {
|
|||||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
throw ScriptError(_("Not a number: '") + value + _("'"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual operator Color() const {
|
||||||
|
UInt r,g,b;
|
||||||
|
if (wxSscanf(value.c_str(),_("rgb(%u,%u,%u)"),&r,&g,&b)) {
|
||||||
|
return Color(r, g, b);
|
||||||
|
} else {
|
||||||
|
throw ScriptError(_("Not a color: '") + value + _("'"));
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual int itemCount() const { return (int)value.size(); }
|
virtual int itemCount() const { return (int)value.size(); }
|
||||||
virtual ScriptValueP getMember(const String& name) const {
|
virtual ScriptValueP getMember(const String& name) const {
|
||||||
// get member returns characters
|
// get member returns characters
|
||||||
@@ -198,6 +206,9 @@ class ScriptColor : public ScriptValue {
|
|||||||
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
||||||
virtual String typeName() const { return _("color"); }
|
virtual String typeName() const { return _("color"); }
|
||||||
virtual operator Color() const { return value; }
|
virtual operator Color() const { return value; }
|
||||||
|
virtual operator String() const {
|
||||||
|
return String::Format(_("rgb(%u,%u,%u)"), value.Red(), value.Green(), value.Blue());
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
Color value;
|
Color value;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user