Commit 224f6238 authored by twanvl's avatar twanvl

scripting language now has support for list and map literals: " [a,b,c] "

parent 554c259e
......@@ -101,6 +101,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
}
break;
}
// Make an object
case I_MAKE_OBJECT: {
makeObject(i.data);
break;
}
// Function call
case I_CALL: {
......@@ -324,3 +329,20 @@ void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP&
break;
}
}
// ----------------------------------------------------------------------------- : Simple instructions : object
void Context::makeObject(size_t n) {
intrusive_ptr<ScriptCustomCollection> ret(new ScriptCustomCollection());
size_t begin = stack.size() - 2 * n;
for (size_t i = 0 ; i < n ; ++i) {
const ScriptValueP& key = stack[begin + 2 * i];
const ScriptValueP& val = stack[begin + 2 * i + 1];
ret->value.push_back(val);
if (key != script_nil) { // valid key
ret->key_value[key->toString()] = val;
}
}
stack.resize(begin);
stack.push_back(ret);
}
......@@ -94,6 +94,8 @@ class Context {
void getBindings(size_t scope, vector<Binding>&);
/// Remove all bindings made in the current scope
void resetBindings(size_t scope);
/// Make an object with n elements, popping 2n values from the stack, and push it onto the stack
void makeObject(size_t n);
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -231,6 +231,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
}
break;
}
// Make an object
case I_MAKE_OBJECT: {
makeObject(i.data);
break;
}
// Function call (as normal)
case I_CALL: {
......
......@@ -385,6 +385,31 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper(input, *subScript, PREC_ALL, I_RET);
expectToken(input, _("}"));
script.addInstruction(I_PUSH_CONST, subScript);
} else if (token == _("[")) {
// [] = list or map literal
unsigned int count = 0;
Token t = input.peek();
while (t != _("]") && t != TOK_EOF) {
if (input.peek(2) == _(":") && (t.type == TOK_NAME || t.type == TOK_INT || t.type == TOK_STRING)) {
// name: ...
script.addInstruction(I_PUSH_CONST, to_script(t.value));
input.read(); // skip the name
input.read(); // and the :
} else {
// implicit numbered element
script.addInstruction(I_PUSH_CONST, script_nil);
}
parseOper(input, script, PREC_SEQ);
++count;
t = input.peek();
if (t == _(",")) {
// Comma separating the elements
input.read();
t = input.peek();
}
}
expectToken(input, _("]"));
script.addInstruction(I_MAKE_OBJECT, count);
} else if (minPrec <= PREC_UNARY && token == _("-")) {
parseOper(input, script, PREC_UNARY, I_UNARY, I_NEGATE); // unary negation
} else if (token == TOK_NAME) {
......@@ -549,7 +574,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
vector<Variable> arguments;
Token t = input.peek();
while (t != _(")") && t != TOK_EOF) {
if (input.peek(2) == _(":")) {
if (input.peek(2) == _(":") && t.type == TOK_NAME) {
// name: ...
arguments.push_back(string_to_variable(t.value));
input.read(); // skip the name
......
......@@ -33,13 +33,14 @@ enum InstructionType
, I_MEMBER_C = 7 ///< arg = name : finds a member of the top of the stack replaces the top of the stack with the member
, I_LOOP = -8 ///< arg = int : loop over the elements of an iterator, which is the *second* element of the stack (this allows for combing the results of multiple iterations)
///< at the end performs a jump and pops the iterator. note: The second element of the stack must be an iterator!
, I_MAKE_OBJECT = -7 ///< arg = int : make a list/map with n elements, pops 2n values of the stack, n key/value pairs
// Functions
, I_CALL = -7 ///< arg = int, int+ : call the top item of the stack, with the given number of arguments (set with SET_VAR, but in the activation record of the call)
, I_RET = -6 ///< return from the current function
, I_CALL = -6 ///< arg = int, int+ : call the top item of the stack, with the given number of arguments (set with SET_VAR, but in the activation record of the call)
, I_RET = -5 ///< return from the current function
// Simple instructions
, I_UNARY = -5 ///< pop 1 value, apply a function, push the result
, I_BINARY = -4 ///< pop 2 values, apply a function, push the result
, I_TERNARY = -3 ///< pop 3 values, apply a function, push the result
, I_UNARY = -4 ///< pop 1 value, apply a function, push the result
, I_BINARY = -3 ///< pop 2 values, apply a function, push the result
, I_TERNARY = -2 ///< pop 3 values, apply a function, push the result
};
/// Types of unary instructions (taking one argument from the stack)
......
......@@ -147,8 +147,10 @@ class ScriptCustomCollection : public ScriptValue {
/// Collections can be compared by comparing pointers
virtual const void* comparePointer() const { return &value; }
/// The collection
/// The collection as a list (contains all values)
vector<ScriptValueP> value;
/// The collection as a map (contains only the values that have a key)
map<String,ScriptValueP> key_value;
};
// ----------------------------------------------------------------------------- : Objects
......
......@@ -257,11 +257,16 @@ class ScriptCustomCollectionIterator : public ScriptIterator {
};
ScriptValueP ScriptCustomCollection::getMember(const String& name) const {
long index;
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
return value.at(index);
map<String,ScriptValueP>::const_iterator it = key_value.find(name);
if (it != key_value.end()) {
return it->second;
} else {
return ScriptValue::getMember(name);
long index;
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) {
return value.at(index);
} else {
return ScriptValue::getMember(name);
}
}
}
ScriptValueP ScriptCustomCollection::makeIterator(const ScriptValueP& thisP) const {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment