mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
'ported' scripting code to work with unicode and the rest of MSE
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@14 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+15
-12
@@ -20,7 +20,7 @@ DECLARE_TYPEOF_COLLECTION(Context::Binding);
|
||||
class DependencyDummy : public ScriptIterator {
|
||||
public:
|
||||
virtual ScriptType type() const { return SCRIPT_DUMMY; }
|
||||
virtual String typeName() const { return "dummy"; }
|
||||
virtual String typeName() const { return _("dummy"); }
|
||||
virtual ScriptValueP next() { return ScriptValueP(); }
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ class DependencyUnion : public ScriptValue {
|
||||
{}
|
||||
|
||||
virtual ScriptType type() const { return SCRIPT_DUMMY; }
|
||||
virtual String typeName() const { return "union of " + a->typeName() + " and " + b->typeName(); }
|
||||
virtual String typeName() const { return _("union of ") + a->typeName() + _(" and ") + b->typeName(); }
|
||||
|
||||
virtual ScriptValueP dependencies(Context& ctx, const Dependency& dep) const {
|
||||
return unified( a->dependencies(ctx,dep), b->dependencies(ctx,dep));
|
||||
@@ -85,22 +85,25 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
|
||||
// - member operator; and it signals a dependency.
|
||||
// - looper construction
|
||||
// - + for function composition
|
||||
// Variable assignments are performed as normall.
|
||||
// Jumps are tricky:
|
||||
// - I_JUMP: Just follow them, but see below
|
||||
// - I_JUMP_IF_NOT: We don't know the value of the condition, evaluate both branches.
|
||||
// The simple solution would be to use recursion to fork off one of the cases.
|
||||
// This could result in an exponential increase in execution time,
|
||||
// because the analysis after an if statement is duplicated.
|
||||
// A better solution is to evalutate branches 'in parallel'. After the if statement
|
||||
// the net stack effect is +1, the top element will then be a DependencyUnion object.
|
||||
// To detect the joining of the branches we look for I_JUMPs, the non jumping branch will have
|
||||
// a I_JUMP at the end, when we encounter it we start evaluating the other if branch.
|
||||
// - I_LOOP: We want to prevent infinite loops, the solution is that after the first
|
||||
// iteration we set the looper to a dummy value, so the loop is only executed once.
|
||||
// TODO: This could result in false negatives when iterating over things like fields.
|
||||
// We ignore this, because loops are usually only used for exporting, where dependency
|
||||
// analysis is not used anyway.
|
||||
// Variable assignments are performed as normall.
|
||||
// - I_JUMP_IF_NOT: We don't know the value of the condition, so we must evaluate both branches.
|
||||
// The simple solution would be to use recursion to fork off one of the cases.
|
||||
// This could result in an exponential increase in execution time,
|
||||
// because the analysis after an if statement is duplicated.
|
||||
// A better solution is to evalutate branches 'in parallel'.
|
||||
// We create a jump record for taking the branch, and evaluate the fall through case.
|
||||
// When later a jump record points to the current instruction the stack and variables of that
|
||||
// record are unify with the current execution path.
|
||||
// - I_JUMP: We must can not follow all jumps, because they may lead to a point beyond a jump record,
|
||||
// we can then no longer hope to unify with that jump record.
|
||||
// Instead we create a new jump record, and follow the jump record with the lowest target address.
|
||||
// This story doesn't hold for backwards jumps, we can safely follow those (see I_LOOP above)
|
||||
|
||||
// Scope for evaluating this script.
|
||||
size_t stack_size = stack.size();
|
||||
|
||||
+17
-17
@@ -10,10 +10,13 @@
|
||||
#include <script/parser.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <stack>
|
||||
#include <boost/lexical_cast.hpp> //%%
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(int);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#define TokenType TokenType_ // some stupid windows header uses our name
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------- : Tokenizing : class
|
||||
|
||||
enum TokenType
|
||||
@@ -70,8 +73,6 @@ class TokenIterator {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Characters
|
||||
|
||||
// TODO: isxx -> isXX!
|
||||
|
||||
bool isAlpha_(Char c) { return isAlpha(c) || c==_('_'); }
|
||||
bool isAlnum_(Char c) { return isAlnum(c) || c==_('_'); }
|
||||
bool isOper (Char c) { return c==_('+') || c==_('-') || c==_('*') || c==_('/') || c==_('!') || c==_('.') ||
|
||||
@@ -102,34 +103,34 @@ const Token& TokenIterator::read() {
|
||||
}
|
||||
|
||||
void TokenIterator::putBack() {
|
||||
Token t = {TOK_NEWLINE, "\n"};
|
||||
Token t = {TOK_NEWLINE, _("\n")};
|
||||
buffer.insert(buffer.begin(), t);
|
||||
}
|
||||
|
||||
void TokenIterator::addToken() {
|
||||
if (pos >= input.size()) {
|
||||
// EOF
|
||||
Token t = {TOK_EOF, "end of input"};
|
||||
Token t = {TOK_EOF, _("end of input")};
|
||||
buffer.push_back(t);
|
||||
return;
|
||||
}
|
||||
// read a character from the input
|
||||
Char c = input[pos++]; //% input.GetChar(pos++);
|
||||
Char c = input.GetChar(pos++);
|
||||
if (c == _('\n')) {
|
||||
Token t = { TOK_NEWLINE, "newline" };
|
||||
Token t = {TOK_NEWLINE, _("newline")};
|
||||
buffer.push_back(t);
|
||||
} else if (isSpace(c)) {
|
||||
// ignore
|
||||
} else if (isAlpha(c)) {
|
||||
// name
|
||||
size_t start = pos - 1;
|
||||
while (pos < input.size() && isalnum(input[pos])) ++pos; //%% isAlnum_(input.getChar(pos))) pos++;
|
||||
while (pos < input.size() && isAlnum_(input.GetChar(pos))) ++pos;
|
||||
Token t = {TOK_NAME, cannocialNameForm(input.substr(start, pos-start)) }; // convert name to cannocial form
|
||||
buffer.push_back(t);
|
||||
} else if (isDigit(c)) {
|
||||
// number
|
||||
size_t start = pos - 1;
|
||||
while (pos < input.size() && isDigitOrDot(input[pos])) ++pos;
|
||||
while (pos < input.size() && isDigitOrDot(input.GetChar(pos))) ++pos;
|
||||
String num = input.substr(start, pos-start);
|
||||
Token t = {
|
||||
num.find_first_of('.') == String::npos ? TOK_INT : TOK_DOUBLE,
|
||||
@@ -172,7 +173,6 @@ void TokenIterator::addToken() {
|
||||
while (pos < input.size() && input[pos] != _('\n')) ++pos;
|
||||
} else {
|
||||
throw ScriptParseError(_("Unknown character in script: '") + String(1,c) + _("'"));
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,14 +360,14 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
|
||||
script.addInstruction(I_GET_VAR, var);
|
||||
}
|
||||
} else if (token == TOK_INT) {
|
||||
long l;
|
||||
l = lexical_cast<long>(token.value);
|
||||
//token.value.toLong(l);
|
||||
long l = 0;
|
||||
//l = lexical_cast<long>(token.value);
|
||||
token.value.ToLong(&l);
|
||||
script.addInstruction(I_PUSH_CONST, toScript(l));
|
||||
} else if (token == TOK_DOUBLE) {
|
||||
double d;
|
||||
d = lexical_cast<double>(token.value);
|
||||
//token.value.toDouble(d);
|
||||
double d = 0;
|
||||
//d = lexical_cast<double>(token.value);
|
||||
token.value.ToDouble(&d);
|
||||
script.addInstruction(I_PUSH_CONST, toScript(d));
|
||||
} else if (token == TOK_STRING) {
|
||||
script.addInstruction(I_PUSH_CONST, toScript(token.value));
|
||||
@@ -404,7 +404,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
|
||||
// not an expression. Remove that instruction.
|
||||
Instruction instr = script.getInstructions().back();
|
||||
if (instr.instr != I_GET_VAR) {
|
||||
throw ScriptParseError("Can only assign to variables");
|
||||
throw ScriptParseError(_("Can only assign to variables"));
|
||||
} else {
|
||||
script.getInstructions().pop_back();
|
||||
parseOper(input, script, PREC_SET, I_SET_VAR, instr.data);
|
||||
|
||||
@@ -8,17 +8,17 @@
|
||||
|
||||
#include <script/script.hpp>
|
||||
#include <script/context.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <util/error.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Variables
|
||||
|
||||
typedef map<string, unsigned int> Variables;
|
||||
typedef map<String, unsigned int> Variables;
|
||||
Variables variables;
|
||||
DECLARE_TYPEOF(Variables);
|
||||
|
||||
/// Return a unique name for a variable to allow for faster loopups
|
||||
unsigned int stringToVariable(const String& s) {
|
||||
map<string, unsigned int>::iterator it = variables.find(s);
|
||||
map<String, unsigned int>::iterator it = variables.find(s);
|
||||
if (it == variables.end()) {
|
||||
unsigned int v = (unsigned int)variables.size();
|
||||
variables.insert(make_pair(s,v));
|
||||
@@ -35,7 +35,7 @@ String variableToString(unsigned int v) {
|
||||
FOR_EACH(vi, variables) {
|
||||
if (vi.second == v) return vi.first;
|
||||
}
|
||||
throw "Variable not found: " + lexical_cast<String>(v);
|
||||
throw ScriptError(String(_("Variable not found: ")) << v);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Script
|
||||
@@ -44,7 +44,7 @@ ScriptType Script::type() const {
|
||||
return SCRIPT_SCRIPT_FUN;
|
||||
}
|
||||
String Script::typeName() const {
|
||||
return "function";
|
||||
return _("function");
|
||||
}
|
||||
ScriptValueP Script::eval(Context& ctx) const {
|
||||
return ctx.eval(*this);
|
||||
@@ -90,6 +90,8 @@ unsigned int Script::getLabel() const {
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(Instruction);
|
||||
|
||||
#if 0 // debugging
|
||||
|
||||
String Script::dumpScript() const {
|
||||
String ret;
|
||||
int pos = 0;
|
||||
@@ -163,3 +165,4 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+33
-20
@@ -8,22 +8,21 @@
|
||||
|
||||
#include <script/value.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <boost/lexical_cast.hpp> //%%
|
||||
#include <boost/pool/singleton_pool.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptValue
|
||||
// Base cases
|
||||
|
||||
ScriptValue::operator String() const { return "[[" + typeName() + "]]"; }
|
||||
ScriptValue::operator int() const { throw ScriptError("Can't convert from "+typeName()+" to integer number"); }
|
||||
ScriptValue::operator double() const { throw ScriptError("Can't convert from "+typeName()+" to real number" ); }
|
||||
ScriptValue::operator Color() const { throw ScriptError("Can't convert from "+typeName()+" to color" ); }
|
||||
ScriptValue::operator String() const { return _("[[") + typeName() + _("]]"); }
|
||||
ScriptValue::operator int() const { throw ScriptError(_("Can't convert from ")+typeName()+_(" to integer number")); }
|
||||
ScriptValue::operator double() const { throw ScriptError(_("Can't convert from ")+typeName()+_(" to real number" )); }
|
||||
ScriptValue::operator Color() const { throw ScriptError(_("Can't convert from ")+typeName()+_(" to color" )); }
|
||||
ScriptValueP ScriptValue::eval(Context&) const
|
||||
{ throw ScriptError("Can't convert from "+typeName()+" to function" ); }
|
||||
{ throw ScriptError(_("Can't convert from ")+typeName()+_(" to function" )); }
|
||||
ScriptValueP ScriptValue::getMember(const String& name) const
|
||||
{ throw (typeName() + " has no member '" + name + "'"); }
|
||||
ScriptValueP ScriptValue::next() { throw InternalError("Can't convert from "+typeName()+" to iterator"); }
|
||||
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError("Can't convert from "+typeName()+" to collection"); }
|
||||
{ throw (typeName() + _(" has no member '") + name + _("'")); }
|
||||
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
|
||||
ScriptValueP ScriptValue::makeIterator() const { throw ScriptError( _("Can't convert from ")+typeName()+_(" to collection")); }
|
||||
|
||||
void ScriptValue::signalDependent(Context&, const Dependency&, const String& name) {}
|
||||
ScriptValueP ScriptValue::dependencies( Context&, const Dependency&) const { return scriptNil; }
|
||||
@@ -32,7 +31,7 @@ ScriptValueP ScriptValue::dependencies( Context&, const Dependency&) const { r
|
||||
// ----------------------------------------------------------------------------- : Iterators
|
||||
|
||||
ScriptType ScriptIterator::type() const { return SCRIPT_OBJECT; }
|
||||
String ScriptIterator::typeName() const { return "iterator"; }
|
||||
String ScriptIterator::typeName() const { return _("iterator"); }
|
||||
|
||||
// Iterator over a range of integers
|
||||
class ScriptRangeIterator : public ScriptIterator {
|
||||
@@ -62,8 +61,8 @@ class ScriptInt : public ScriptValue {
|
||||
public:
|
||||
ScriptInt(int v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_INT; }
|
||||
virtual String typeName() const { return "integer number"; }
|
||||
virtual operator String() const { return lexical_cast<String>(value); }
|
||||
virtual String typeName() const { return _("integer number"); }
|
||||
virtual operator String() const { return String() << value; }
|
||||
virtual operator double() const { return value; }
|
||||
virtual operator int() const { return value; }
|
||||
protected:
|
||||
@@ -93,8 +92,8 @@ class ScriptDouble : public ScriptValue {
|
||||
public:
|
||||
ScriptDouble(double v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_DOUBLE; }
|
||||
virtual String typeName() const { return "real number"; }
|
||||
virtual operator String() const { return lexical_cast<String>(value); }
|
||||
virtual String typeName() const { return _("real number"); }
|
||||
virtual operator String() const { return String() << value; }
|
||||
virtual operator double() const { return value; }
|
||||
virtual operator int() const { return (int)value; }
|
||||
private:
|
||||
@@ -112,10 +111,24 @@ class ScriptString : public ScriptValue {
|
||||
public:
|
||||
ScriptString(const String& v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_STRING; }
|
||||
virtual String typeName() const { return "string"; }
|
||||
virtual String typeName() const { return _("string"); }
|
||||
virtual operator String() const { return value; }
|
||||
virtual operator double() const { return lexical_cast<double>(value); }
|
||||
virtual operator int() const { return lexical_cast<int>(value); }
|
||||
virtual operator double() const {
|
||||
double d;
|
||||
if (value.ToDouble(&d)) {
|
||||
return d;
|
||||
} else {
|
||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
||||
}
|
||||
}
|
||||
virtual operator int() const {
|
||||
long l;
|
||||
if (value.ToLong(&l)) {
|
||||
return l;
|
||||
} else {
|
||||
throw ScriptError(_("Not a number: '") + value + _("'"));
|
||||
}
|
||||
}
|
||||
private:
|
||||
String value;
|
||||
};
|
||||
@@ -132,7 +145,7 @@ class ScriptColor : public ScriptValue {
|
||||
public:
|
||||
ScriptColor(const Color& v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_COLOR; }
|
||||
virtual String typeName() const { return "color"; }
|
||||
virtual String typeName() const { return _("color"); }
|
||||
private:
|
||||
Color value;
|
||||
};
|
||||
@@ -148,8 +161,8 @@ ScriptValueP toScript(const Color& v) {
|
||||
class ScriptNil : public ScriptValue {
|
||||
public:
|
||||
virtual ScriptType type() const { return SCRIPT_NIL; }
|
||||
virtual String typeName() const { return "nil"; }
|
||||
virtual operator String() const { return ""; }
|
||||
virtual String typeName() const { return _("nil"); }
|
||||
virtual operator String() const { return wxEmptyString; }
|
||||
virtual operator double() const { return 0.0; }
|
||||
virtual operator int() const { return 0; }
|
||||
};
|
||||
|
||||
+21
-29
@@ -10,35 +10,22 @@
|
||||
// ----------------------------------------------------------------------------- : Includes
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/lexical_cast.hpp> //%%
|
||||
|
||||
//#ifndef WINVER
|
||||
//#define WINVER 0x0501
|
||||
//#endif
|
||||
//#include <winresrc.h>
|
||||
//#include <windef.h>
|
||||
//#include <winbase.h> // Interlocked*crement
|
||||
#include <windows.h>
|
||||
#define TokenType TokenType_
|
||||
|
||||
extern "C" {
|
||||
LONG __cdecl _InterlockedIncrement(LONG volatile *Addend);
|
||||
LONG __cdecl _InterlockedDecrement(LONG volatile *Addend);
|
||||
}
|
||||
#pragma intrinsic (_InterlockedIncrement)
|
||||
#define InterlockedIncrement _InterlockedIncrement
|
||||
#pragma intrinsic (_InterlockedDecrement)
|
||||
#define InterlockedDecrement _InterlockedDecrement
|
||||
|
||||
//long __declspec(dllimport) __stdcall InterlockedDecrement(long volatile* Addend);
|
||||
//long __declspec(dllimport) __stdcall InterlockedIncrement(long volatile* Addend);
|
||||
//#pragma intrinsic(_InterlockedIncrement)
|
||||
//#pragma intrinsic( _InterlockedDecrement )
|
||||
|
||||
class Context;
|
||||
class Dependency;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
extern "C" {
|
||||
LONG __cdecl _InterlockedIncrement(LONG volatile *Addend);
|
||||
LONG __cdecl _InterlockedDecrement(LONG volatile *Addend);
|
||||
}
|
||||
#pragma intrinsic (_InterlockedIncrement)
|
||||
#define InterlockedIncrement _InterlockedIncrement
|
||||
#pragma intrinsic (_InterlockedDecrement)
|
||||
#define InterlockedDecrement _InterlockedDecrement
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------- : ScriptValue
|
||||
|
||||
//DECLARE_POINTER_TYPE(ScriptValue);
|
||||
@@ -161,10 +148,14 @@ class ScriptCollection : public ScriptValue {
|
||||
public:
|
||||
inline ScriptCollection(const Collection* v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_OBJECT; }
|
||||
virtual String typeName() const { return "collection"; }
|
||||
virtual String typeName() const { return _("collection"); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
int index = lexical_cast<int>(name);
|
||||
return toScript(value->at(index));
|
||||
long index;
|
||||
if (name.ToLong(&index)) {
|
||||
return toScript(value->at(index));
|
||||
} else {
|
||||
throw ScriptError(_("Collection has no member ") + name);
|
||||
}
|
||||
}
|
||||
virtual ScriptValueP makeIterator() const {
|
||||
return new_intrusive1<ScriptCollectionIterator<Collection> >(value);
|
||||
@@ -182,7 +173,7 @@ class ScriptObject : public ScriptValue {
|
||||
public:
|
||||
inline ScriptObject(const shared_ptr<T>& v) : value(v) {}
|
||||
virtual ScriptType type() const { return SCRIPT_OBJECT; }
|
||||
virtual String typeName() const { return "object"; }
|
||||
virtual String typeName() const { return _("object"); }
|
||||
virtual ScriptValueP getMember(const String& name) const {
|
||||
GetMember gm(name);
|
||||
gm.handle(*value);
|
||||
@@ -246,6 +237,7 @@ inline ScriptValueP toScript(const shared_ptr<T>& v) { return new_intrusive1<Scr
|
||||
* @code
|
||||
* SCRIPT_FUNCTION(my_function) {
|
||||
* SCRIPT_PARAM(String, my_string_param);
|
||||
* ...
|
||||
* }
|
||||
* @endcode
|
||||
* Throws an error if the parameter is not found.
|
||||
|
||||
Reference in New Issue
Block a user