diff --git a/src/blocks/scratch3_data.js b/src/blocks/scratch3_data.js
index 551f717f7..8ec4f124e 100644
--- a/src/blocks/scratch3_data.js
+++ b/src/blocks/scratch3_data.js
@@ -52,8 +52,8 @@ class Scratch3DataBlocks {
// If it is, report contents joined together with no separator.
// If it's not, report contents joined together with a space.
let allSingleLetters = true;
- for (let i = 0; i < list.contents.length; i++) {
- const listItem = list.contents[i];
+ for (let i = 0; i < list.value.length; i++) {
+ const listItem = list.value[i];
if (!((typeof listItem === 'string') &&
(listItem.length === 1))) {
allSingleLetters = false;
@@ -61,73 +61,73 @@ class Scratch3DataBlocks {
}
}
if (allSingleLetters) {
- return list.contents.join('');
+ return list.value.join('');
}
- return list.contents.join(' ');
+ return list.value.join(' ');
}
addToList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST);
- list.contents.push(args.ITEM);
+ list.value.push(args.ITEM);
}
deleteOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST);
- const index = Cast.toListIndex(args.INDEX, list.contents.length);
+ const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) {
return;
} else if (index === Cast.LIST_ALL) {
- list.contents = [];
+ list.value = [];
return;
}
- list.contents.splice(index - 1, 1);
+ list.value.splice(index - 1, 1);
}
insertAtList (args, util) {
const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST);
- const index = Cast.toListIndex(args.INDEX, list.contents.length + 1);
+ const index = Cast.toListIndex(args.INDEX, list.value.length + 1);
if (index === Cast.LIST_INVALID) {
return;
}
- list.contents.splice(index - 1, 0, item);
+ list.value.splice(index - 1, 0, item);
}
replaceItemOfList (args, util) {
const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST);
- const index = Cast.toListIndex(args.INDEX, list.contents.length);
+ const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) {
return;
}
- list.contents.splice(index - 1, 1, item);
+ list.value.splice(index - 1, 1, item);
}
getItemOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST);
- const index = Cast.toListIndex(args.INDEX, list.contents.length);
+ const index = Cast.toListIndex(args.INDEX, list.value.length);
if (index === Cast.LIST_INVALID) {
return '';
}
- return list.contents[index - 1];
+ return list.value[index - 1];
}
lengthOfList (args, util) {
const list = util.target.lookupOrCreateList(args.LIST);
- return list.contents.length;
+ return list.value.length;
}
listContainsItem (args, util) {
const item = args.ITEM;
const list = util.target.lookupOrCreateList(args.LIST);
- if (list.contents.indexOf(item) >= 0) {
+ if (list.value.indexOf(item) >= 0) {
return true;
}
// Try using Scratch comparison operator on each item.
// (Scratch considers the string '123' equal to the number 123).
- for (let i = 0; i < list.contents.length; i++) {
- if (Cast.compare(list.contents[i], item) === 0) {
+ for (let i = 0; i < list.value.length; i++) {
+ if (Cast.compare(list.value[i], item) === 0) {
return true;
}
}
diff --git a/src/engine/blocks.js b/src/engine/blocks.js
index ba9077fc7..7a9ecbb88 100644
--- a/src/engine/blocks.js
+++ b/src/engine/blocks.js
@@ -260,7 +260,7 @@ class Blocks {
// If not, create it on the stage.
// TODO create global and local variables when UI provides a way.
if (!optRuntime.getEditingTarget().lookupVariableById(e.varId)) {
- stage.createVariable(e.varId, e.varName);
+ stage.createVariable(e.varId, e.varName, e.varType);
}
break;
case 'var_rename':
@@ -310,7 +310,7 @@ class Blocks {
case 'field':
// Update block value
if (!block.fields[args.name]) return;
- if (args.name === 'VARIABLE') {
+ if (args.name === 'VARIABLE' || args.name === 'LIST') {
// Get variable name using the id in args.value.
const variable = optRuntime.getEditingTarget().lookupVariableById(args.value);
if (variable) {
diff --git a/src/engine/execute.js b/src/engine/execute.js
index a4bf76b2a..8093a346d 100644
--- a/src/engine/execute.js
+++ b/src/engine/execute.js
@@ -138,7 +138,7 @@ const execute = function (sequencer, thread) {
// Add all fields on this block to the argValues.
for (const fieldName in fields) {
if (!fields.hasOwnProperty(fieldName)) continue;
- if (fieldName === 'VARIABLE') {
+ if (fieldName === 'VARIABLE' || fieldName === 'LIST') {
argValues[fieldName] = fields[fieldName].id;
} else {
argValues[fieldName] = fields[fieldName].value;
diff --git a/src/engine/list.js b/src/engine/list.js
deleted file mode 100644
index 0f3ec0f2b..000000000
--- a/src/engine/list.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * @fileoverview
- * Object representing a Scratch list.
- */
-
-/**
- * @param {!string} name Name of the list.
- * @param {Array} contents Contents of the list, as an array.
- * @constructor
- */
-class List {
- constructor (name, contents) {
- this.name = name;
- this.contents = contents;
- }
-}
-
-module.exports = List;
diff --git a/src/engine/target.js b/src/engine/target.js
index 2a6be81a6..764094daa 100644
--- a/src/engine/target.js
+++ b/src/engine/target.js
@@ -2,7 +2,6 @@ const EventEmitter = require('events');
const Blocks = require('./blocks');
const Variable = require('../engine/variable');
-const List = require('../engine/list');
const uid = require('../util/uid');
const {Map} = require('immutable');
@@ -88,7 +87,7 @@ class Target extends EventEmitter {
const variable = this.lookupVariableById(id);
if (variable) return variable;
// No variable with this name exists - create it locally.
- const newVariable = new Variable(id, name, 0, false);
+ const newVariable = new Variable(id, name, "", false);
this.variables[id] = newVariable;
return newVariable;
}
@@ -117,24 +116,16 @@ class Target extends EventEmitter {
/**
* Look up a list object for this target, and create it if one doesn't exist.
* Search begins for local lists; then look for globals.
+ * @param {!string} id Id of the list.
* @param {!string} name Name of the list.
* @return {!List} List object.
*/
- lookupOrCreateList (name) {
- // If we have a local copy, return it.
- if (this.lists.hasOwnProperty(name)) {
- return this.lists[name];
- }
- // If the stage has a global copy, return it.
- if (this.runtime && !this.isStage) {
- const stage = this.runtime.getTargetForStage();
- if (stage.lists.hasOwnProperty(name)) {
- return stage.lists[name];
- }
- }
- // No list with this name exists - create it locally.
- const newList = new List(name, []);
- this.lists[name] = newList;
+ lookupOrCreateList (id, name) {
+ const list = this.lookupVariableById(id);
+ if (list) return list;
+ // No variable with this name exists - create it locally.
+ const newList = new Variable(id, name, "list", false);
+ this.variables[id] = newList;
return newList;
}
@@ -143,11 +134,11 @@ class Target extends EventEmitter {
* dictionary of variables.
* @param {string} id Id of variable
* @param {string} name Name of variable.
+ * @param {string} type Type of variable, one of string, number, list
*/
- createVariable (id, name) {
+ createVariable (id, name, type) {
if (!this.variables.hasOwnProperty(id)) {
- const newVariable = new Variable(id, name, 0,
- false);
+ const newVariable = new Variable(id, name, type, false);
this.variables[id] = newVariable;
}
}
diff --git a/src/engine/variable.js b/src/engine/variable.js
index b79ab2975..9f047a73b 100644
--- a/src/engine/variable.js
+++ b/src/engine/variable.js
@@ -9,19 +9,27 @@ class Variable {
/**
* @param {string} id Id of the variable.
* @param {string} name Name of the variable.
- * @param {(string|number)} value Value of the variable.
+ * @param {(string|number)} type Type of the variable, one of "" or "list"
* @param {boolean} isCloud Whether the variable is stored in the cloud.
* @constructor
*/
- constructor (id, name, value, isCloud) {
+ constructor (id, name, type, isCloud) {
this.id = id || uid();
this.name = name;
- this.value = value;
+ this.type = type;
this.isCloud = isCloud;
+ switch (this.type) {
+ case "":
+ this.value = 0;
+ break;
+ case "list":
+ this.value = [];
+ break;
+ }
}
toXML () {
- return `${this.name}`;
+ return `${this.name}`;
}
}
diff --git a/src/serialization/sb2.js b/src/serialization/sb2.js
index 2a54d40a7..e76d6ee2b 100644
--- a/src/serialization/sb2.js
+++ b/src/serialization/sb2.js
@@ -13,7 +13,6 @@ const log = require('../util/log');
const uid = require('../util/uid');
const specMap = require('./sb2_specmap');
const Variable = require('../engine/variable');
-const List = require('../engine/list');
const {loadCostume} = require('../import/load-costume.js');
const {loadSound} = require('../import/load-sound.js');
@@ -235,9 +234,10 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
const newVariable = new Variable(
getVariableId(variable.name),
variable.name,
- variable.value,
+ "",
variable.isPersistent
);
+ newVariable.value = variable.value;
target.variables[newVariable.id] = newVariable;
}
}
@@ -251,10 +251,14 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
for (let k = 0; k < object.lists.length; k++) {
const list = object.lists[k];
// @todo: monitor properties.
- target.lists[list.listName] = new List(
+ const newVariable = new Variable(
+ getVariableId(list.listName),
list.listName,
- list.contents
+ "list",
+ list.isPersistent
);
+ newVariable.value = list.contents;
+ target.variables[newVariable.id] = newVariable;
}
}
if (object.hasOwnProperty('scratchX')) {
diff --git a/src/serialization/sb2_specmap.js b/src/serialization/sb2_specmap.js
index cf5be1c89..59200a06f 100644
--- a/src/serialization/sb2_specmap.js
+++ b/src/serialization/sb2_specmap.js
@@ -1252,7 +1252,7 @@ const specMap = {
]
},
'contentsOfList:': {
- opcode: 'data_list',
+ opcode: 'data_listcontents',
argMap: [
{
type: 'field',
diff --git a/src/serialization/sb3.js b/src/serialization/sb3.js
index 426f1004a..9e8bcbf4e 100644
--- a/src/serialization/sb3.js
+++ b/src/serialization/sb3.js
@@ -8,7 +8,6 @@ const vmPackage = require('../../package.json');
const Blocks = require('../engine/blocks');
const Sprite = require('../sprites/sprite');
const Variable = require('../engine/variable');
-const List = require('../engine/list');
const {loadCostume} = require('../import/load-costume.js');
const {loadSound} = require('../import/load-sound.js');
@@ -125,22 +124,13 @@ const parseScratchObject = function (object, runtime, extensions) {
const newVariable = new Variable(
variable.id,
variable.name,
- variable.value,
+ variable.type,
variable.isPersistent
);
+ newVariable.value = variable.value;
target.variables[newVariable.id] = newVariable;
}
}
- if (object.hasOwnProperty('lists')) {
- for (let k = 0; k < object.lists.length; k++) {
- const list = object.lists[k];
- // @todo: monitor properties.
- target.lists[list.listName] = new List(
- list.listName,
- list.contents
- );
- }
- }
if (object.hasOwnProperty('x')) {
target.x = object.x;
}