Simplified compilation of 'assert' pseudo function;

Added remove_duplicates flag to sort_list function;
Fixed documentation of <size:> tag

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@1028 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2008-07-22 22:46:04 +00:00
parent 4a8c4ba14b
commit 13a37f4734
11 changed files with 146 additions and 65 deletions
+52 -11
View File
@@ -33,7 +33,26 @@ SCRIPT_FUNCTION(trace) {
SCRIPT_FUNCTION(warning) {
SCRIPT_PARAM_C(String, input);
handle_warning(input, true);
SCRIPT_PARAM_DEFAULT_C(bool, condition, true);
if (condition) {
handle_warning(input, true);
}
return script_nil;
}
SCRIPT_FUNCTION(warning_if_neq) {
SCRIPT_PARAM_C(String, input);
SCRIPT_PARAM_N(ScriptValueP, SCRIPT_VAR__1, v1);
SCRIPT_PARAM_N(ScriptValueP, SCRIPT_VAR__2, v2);
if (!equal(v1,v2)) {
String s1 = _("?"), s2 = _("?");
try {
s1 = v1->toCode();
} catch (...) {}
try {
s2 = v2->toCode();
} catch (...) {}
handle_warning(input + s1 + _(" != ") + s2, true);
}
return script_nil;
}
@@ -59,13 +78,17 @@ String format_input(const String& format, Context& ctx) {
SCRIPT_FUNCTION(to_string) {
ScriptValueP format = ctx.getVariable(SCRIPT_VAR_format);
if (format && format->type() == SCRIPT_STRING) {
// format specifier. Be careful, the built in function 'format' has the same name
SCRIPT_RETURN(format_input(*format, ctx));
} else {
// simple conversion
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(input);
try {
if (format && format->type() == SCRIPT_STRING) {
// format specifier. Be careful, the built in function 'format' has the same name
SCRIPT_RETURN(format_input(*format, ctx));
} else {
// simple conversion
SCRIPT_PARAM_C(String, input);
SCRIPT_RETURN(input);
}
} catch (const ScriptError& e) {
return new_intrusive1<ScriptDelayedError>(e);
}
}
@@ -145,6 +168,11 @@ SCRIPT_FUNCTION(to_color) {
}
}
SCRIPT_FUNCTION(to_code) {
SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_RETURN(input->toCode());
}
// ----------------------------------------------------------------------------- : Math
SCRIPT_FUNCTION(abs) {
@@ -344,14 +372,20 @@ int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const Scr
inline bool smart_less_first(const pair<String,ScriptValueP>& a, const pair<String,ScriptValueP>& b) {
return smart_less(a.first, b.first);
}
inline bool smart_equal_first(const pair<String,ScriptValueP>& a, const pair<String,ScriptValueP>& b) {
return smart_equal(a.first, b.first);
}
// sort a script list
ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& order_by) {
ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& order_by, bool remove_duplicates) {
ScriptType list_t = list->type();
if (list_t == SCRIPT_STRING) {
// sort a string
String s = list->toString();
sort(s.begin(), s.end());
if (remove_duplicates) {
s.erase( unique(s.begin(), s.end()), s.end() );
}
SCRIPT_RETURN(s);
} else {
// are we sorting a set?
@@ -364,6 +398,10 @@ ScriptValueP sort_script(Context& ctx, const ScriptValueP& list, ScriptValue& or
values.push_back(make_pair(order_by.eval(ctx)->toString(), v));
}
sort(values.begin(), values.end(), smart_less_first);
// unique
if (remove_duplicates) {
values.erase( unique(values.begin(), values.end(), smart_equal_first), values.end() );
}
// return collection
ScriptCustomCollectionP ret(new ScriptCustomCollection());
FOR_EACH(v, values) {
@@ -442,10 +480,12 @@ SCRIPT_FUNCTION(filter_list) {
SCRIPT_FUNCTION(sort_list) {
SCRIPT_PARAM_C(ScriptValueP, input);
SCRIPT_PARAM_N(ScriptValueP, _("order by"), order_by);
return sort_script(ctx, input, *order_by);
SCRIPT_PARAM_DEFAULT_N(ScriptValueP, _("order by"), order_by, script_nil);
SCRIPT_PARAM_DEFAULT_N(bool, _("remove duplicates"), remove_duplicates, false);
return sort_script(ctx, input, *order_by, remove_duplicates);
}
SCRIPT_FUNCTION(random_shuffle) {
SCRIPT_PARAM_C(ScriptValueP, input);
// convert to CustomCollection
@@ -571,6 +611,7 @@ void init_script_basic_functions(Context& ctx) {
ctx.setVariable(_("to number"), script_to_number);
ctx.setVariable(_("to boolean"), script_to_boolean);
ctx.setVariable(_("to color"), script_to_color);
ctx.setVariable(_("to code"), script_to_code);
// math
ctx.setVariable(_("abs"), script_abs);
ctx.setVariable(_("random_real"), script_random_real);
+17 -31
View File
@@ -23,6 +23,7 @@ DECLARE_TYPEOF_COLLECTION(Variable);
String read_utf8_line(wxInputStream& input, bool eat_bom = true, bool until_eof = false);
extern ScriptValueP script_warning;
extern ScriptValueP script_warning_if_neq;
// ----------------------------------------------------------------------------- : Tokenizing : class
@@ -557,45 +558,30 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
expectToken(input, _("("));
size_t start = input.peek().pos;
int line = input.getLineNumber();
size_t function_pos = script.getConstants().size();
script.addInstruction(I_PUSH_CONST, script_warning);
parseOper(input, script, PREC_ALL); // condition
size_t end = input.peek().pos;
String message = String::Format(_("Assertion failure on line %d:\n expected: "), line) + input.getSourceCode(start,end);
expectToken(input, _(")"), &token);
if (script.getInstructions().back().instr == I_BINARY && script.getInstructions().back().instr2 == I_EQ) {
// compile "assert(x == y)" into "
// compile "assert(x == y)" into
// warning_if_neq("condition", _1: x, _2: y)
message += _("\n found: ");
script.getInstructions().pop_back(); // remove ==
script.addInstruction(I_DUP, 1); // duplicate X
script.addInstruction(I_DUP, 1); // duplicate Y
script.addInstruction(I_BINARY, I_EQ); //
unsigned jmpElse = script.addInstruction(I_JUMP_IF_NOT); // jnz lbl_else
script.addInstruction(I_PUSH_CONST, script_nil); // push nil
unsigned jmpEnd = script.addInstruction(I_JUMP); // jump lbl_end
script.comeFrom(jmpElse); // lbl_else:
script.addInstruction(I_PUSH_CONST, script_warning); // push warning
script.addInstruction(I_PUSH_CONST, message); // push "condition"
script.addInstruction(I_DUP, 3); // duplicate X
script.addInstruction(I_BINARY, I_ADD); // add
script.addInstruction(I_PUSH_CONST, String(_(" != "))); // push " != "
script.addInstruction(I_BINARY, I_ADD); // add
script.addInstruction(I_DUP, 2); // duplicate Y
script.addInstruction(I_BINARY, I_ADD); // add
script.addInstruction(I_CALL, 1); // call
script.addInstruction(I_NOP, SCRIPT_VAR_input); // (input:)
script.comeFrom(jmpEnd); // lbl_end:
script.addInstruction(I_BINARY, I_POP); // pop Y_copy
script.addInstruction(I_BINARY, I_POP); // pop X_copy
} else {
// compile into: if condition then nil else warning("condition")
unsigned jmpElse = script.addInstruction(I_JUMP_IF_NOT); // jnz lbl_else
script.addInstruction(I_PUSH_CONST, script_nil); // push nil
unsigned jmpEnd = script.addInstruction(I_JUMP); // jump lbl_end
script.comeFrom(jmpElse); // lbl_else:
script.addInstruction(I_PUSH_CONST, script_warning); // push warning
script.getConstants()[function_pos] = script_warning_if_neq;
script.getInstructions().pop_back(); // POP == instruction
script.addInstruction(I_PUSH_CONST, message); // push "condition"
script.addInstruction(I_CALL, 1); // call
script.addInstruction(I_CALL, 3); // call
script.addInstruction(I_NOP, SCRIPT_VAR__1); // (_1:)
script.addInstruction(I_NOP, SCRIPT_VAR__2); // (_2:)
script.addInstruction(I_NOP, SCRIPT_VAR_input); // (input:)
} else {
// compile into: warning("condition", condition: not condition)
script.addInstruction(I_UNARY, I_NOT); // not
script.addInstruction(I_PUSH_CONST, message); // push "condition"
script.addInstruction(I_CALL, 2); // call
script.addInstruction(I_NOP, SCRIPT_VAR_condition); // (condition:)
script.addInstruction(I_NOP, SCRIPT_VAR_input); // (input:)
script.comeFrom(jmpEnd); // lbl_end:
}
} else {
// variable
+3
View File
@@ -52,6 +52,8 @@ void init_script_variables() {
#define VarN(X,name) if (SCRIPT_VAR_##X != string_to_variable(name)) assert(false);
#define Var(X) VarN(X,_(#X))
Var(input);
Var(_1);
Var(_2);
Var(in);
Var(match);
Var(replace);
@@ -73,6 +75,7 @@ void init_script_variables() {
Var(card);
Var(styling);
Var(value);
Var(condition);
assert(variables.size() == SCRIPT_VAR_CUSTOM_FIRST);
}
+3
View File
@@ -111,6 +111,8 @@ struct Instruction {
// for faster lookup from code
enum Variable
{ SCRIPT_VAR_input
, SCRIPT_VAR__1
, SCRIPT_VAR__2
, SCRIPT_VAR_in
, SCRIPT_VAR_match
, SCRIPT_VAR_replace
@@ -132,6 +134,7 @@ enum Variable
, SCRIPT_VAR_card
, SCRIPT_VAR_styling
, SCRIPT_VAR_value
, SCRIPT_VAR_condition
, SCRIPT_VAR_CUSTOM_FIRST // other variables start from here
, SCRIPT_VAR_CUSTOM_LOTS = 0xFFFFFF // ensure that sizeof(Variable) is large enough
};
+8 -4
View File
@@ -95,6 +95,12 @@ ScriptValueP rangeIterator(int start, int end);
// ----------------------------------------------------------------------------- : Collections
class ScriptCollectionBase : public ScriptValue {
public:
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String toCode() const;
};
// Iterator over a collection
template <typename Collection>
class ScriptCollectionIterator : public ScriptIterator {
@@ -114,10 +120,9 @@ class ScriptCollectionIterator : public ScriptIterator {
/// Script value containing a collection
template <typename Collection>
class ScriptCollection : public ScriptValue {
class ScriptCollection : public ScriptCollectionBase {
public:
inline ScriptCollection(const Collection* v) : value(v) {}
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _TYPE_1_("collection of", type_name(*value->begin())); }
virtual ScriptValueP getIndex(int index) const {
if (index >= 0 && index < (int)value->size()) {
@@ -190,9 +195,8 @@ class ScriptMap : public ScriptValue {
// ----------------------------------------------------------------------------- : Collections : from script
/// Script value containing a custom collection, returned from script functions
class ScriptCustomCollection : public ScriptValue {
class ScriptCustomCollection : public ScriptCollectionBase {
public:
virtual ScriptType type() const { return SCRIPT_COLLECTION; }
virtual String typeName() const { return _TYPE_("collection"); }
virtual ScriptValueP getMember(const String& name) const;
virtual ScriptValueP getIndex(int index) const;
+27 -2
View File
@@ -27,8 +27,9 @@ ScriptValueP ScriptValue::eval(Context&) const { return delay
ScriptValueP ScriptValue::next() { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
ScriptValueP ScriptValue::makeIterator(const ScriptValueP&) const { return delayError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
int ScriptValue::itemCount() const { throw ScriptError(_ERROR_2_("can't convert", typeName(), _TYPE_("collection"))); }
String ScriptValue::toCode() const { return *this; }
CompareWhat ScriptValue::compareAs(String& compare_str, void const*& compare_ptr) const {
compare_str = toString();
compare_str = toCode();
return COMPARE_AS_STRING;
}
ScriptValueP ScriptValue::getMember(const String& name) const {
@@ -322,12 +323,36 @@ class ScriptNil : public ScriptValue {
virtual operator double() const { return 0.0; }
virtual operator int() const { return 0; }
virtual operator bool() const { return false; }
virtual ScriptValueP eval(Context&) const { return script_nil; } // nil() == nil
virtual ScriptValueP eval(Context& ctx) const {
// nil(input) == input
return ctx.getVariable(SCRIPT_VAR_input);
}
};
/// The preallocated nil value
ScriptValueP script_nil(new ScriptNil);
// ----------------------------------------------------------------------------- : Collection base
String ScriptCollectionBase::toCode() const {
String ret = _("[");
bool first = true;
#ifdef USE_INTRUSIVE_PTR
// we can just turn this into a ScriptValueP
// TODO: remove thisP alltogether
ScriptValueP it = makeIterator(ScriptValueP(const_cast<ScriptValue*>((ScriptValue*)this)));
#else
#error "makeIterator needs a ScriptValueP :("
#endif
while (ScriptValueP v = it->next()) {
if (!first) ret += _(",");
first = false;
ret += v->toCode();
}
ret += _("]");
return ret;
}
// ----------------------------------------------------------------------------- : Custom collection
// Iterator over a custom collection
+3
View File
@@ -67,6 +67,9 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
/// Convert this value to a color
virtual operator AColor() const;
/// Script code to generate this value
virtual String toCode() const;
/// Explicit overload to convert to a string
/** This is sometimes necessary, because wxString has an int constructor,
* which confuses gcc. */