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) { ...@@ -101,6 +101,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) {
} }
break; break;
} }
// Make an object
case I_MAKE_OBJECT: {
makeObject(i.data);
break;
}
// Function call // Function call
case I_CALL: { case I_CALL: {
...@@ -324,3 +329,20 @@ void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP& ...@@ -324,3 +329,20 @@ void instrTernary(TernaryInstructionType i, ScriptValueP& a, const ScriptValueP&
break; 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 { ...@@ -94,6 +94,8 @@ class Context {
void getBindings(size_t scope, vector<Binding>&); void getBindings(size_t scope, vector<Binding>&);
/// Remove all bindings made in the current scope /// Remove all bindings made in the current scope
void resetBindings(size_t 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 // ----------------------------------------------------------------------------- : EOF
......
...@@ -231,6 +231,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) ...@@ -231,6 +231,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script)
} }
break; break;
} }
// Make an object
case I_MAKE_OBJECT: {
makeObject(i.data);
break;
}
// Function call (as normal) // Function call (as normal)
case I_CALL: { case I_CALL: {
......
...@@ -385,6 +385,31 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) { ...@@ -385,6 +385,31 @@ void parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper(input, *subScript, PREC_ALL, I_RET); parseOper(input, *subScript, PREC_ALL, I_RET);
expectToken(input, _("}")); expectToken(input, _("}"));
script.addInstruction(I_PUSH_CONST, subScript); 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 == _("-")) { } else if (minPrec <= PREC_UNARY && token == _("-")) {
parseOper(input, script, PREC_UNARY, I_UNARY, I_NEGATE); // unary negation parseOper(input, script, PREC_UNARY, I_UNARY, I_NEGATE); // unary negation
} else if (token == TOK_NAME) { } else if (token == TOK_NAME) {
...@@ -549,7 +574,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc ...@@ -549,7 +574,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
vector<Variable> arguments; vector<Variable> arguments;
Token t = input.peek(); Token t = input.peek();
while (t != _(")") && t != TOK_EOF) { while (t != _(")") && t != TOK_EOF) {
if (input.peek(2) == _(":")) { if (input.peek(2) == _(":") && t.type == TOK_NAME) {
// name: ... // name: ...
arguments.push_back(string_to_variable(t.value)); arguments.push_back(string_to_variable(t.value));
input.read(); // skip the name input.read(); // skip the name
......
...@@ -33,13 +33,14 @@ enum InstructionType ...@@ -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_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) , 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! ///< 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 // 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_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 = -6 ///< return from the current function , I_RET = -5 ///< return from the current function
// Simple instructions // Simple instructions
, I_UNARY = -5 ///< pop 1 value, apply a function, push the result , I_UNARY = -4 ///< pop 1 value, apply a function, push the result
, I_BINARY = -4 ///< pop 2 values, apply a function, push the result , I_BINARY = -3 ///< pop 2 values, apply a function, push the result
, I_TERNARY = -3 ///< pop 3 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) /// Types of unary instructions (taking one argument from the stack)
......
...@@ -147,8 +147,10 @@ class ScriptCustomCollection : public ScriptValue { ...@@ -147,8 +147,10 @@ class ScriptCustomCollection : public ScriptValue {
/// Collections can be compared by comparing pointers /// Collections can be compared by comparing pointers
virtual const void* comparePointer() const { return &value; } virtual const void* comparePointer() const { return &value; }
/// The collection /// The collection as a list (contains all values)
vector<ScriptValueP> value; vector<ScriptValueP> value;
/// The collection as a map (contains only the values that have a key)
map<String,ScriptValueP> key_value;
}; };
// ----------------------------------------------------------------------------- : Objects // ----------------------------------------------------------------------------- : Objects
......
...@@ -257,11 +257,16 @@ class ScriptCustomCollectionIterator : public ScriptIterator { ...@@ -257,11 +257,16 @@ class ScriptCustomCollectionIterator : public ScriptIterator {
}; };
ScriptValueP ScriptCustomCollection::getMember(const String& name) const { ScriptValueP ScriptCustomCollection::getMember(const String& name) const {
long index; map<String,ScriptValueP>::const_iterator it = key_value.find(name);
if (name.ToLong(&index) && index >= 0 && (size_t)index < value.size()) { if (it != key_value.end()) {
return value.at(index); return it->second;
} else { } 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 { 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