Skip to content

Commit

Permalink
JSON: New list reporters (VM) (#60)
Browse files Browse the repository at this point in the history
* add getListArrayContents

* add kind for data_listarraycontents

* add sequence for list.arraycontents

* Update jsexecute.js

* fixes
  • Loading branch information
LilyMakesThings authored Sep 22, 2024
1 parent 95dae8d commit 96b3934
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
18 changes: 18 additions & 0 deletions src/blocks/scratch3_data.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Scratch3DataBlocks {
data_hidevariable: this.hideVariable,
data_showvariable: this.showVariable,
data_listcontents: this.getListContents,
data_listarraycontents: this.getListArrayContents,
data_addtolist: this.addToList,
data_deleteoflist: this.deleteOfList,
data_deletealloflist: this.deleteAllOfList,
Expand Down Expand Up @@ -90,6 +91,23 @@ class Scratch3DataBlocks {
this.changeMonitorVisibility(args.LIST.id, false);
}

getListArrayContents (args, util) {
const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);

// If block is running for monitors, return copy of list as an array if changed.
if (util.thread.updateMonitor) {
// Return original list value if up-to-date, which doesn't trigger monitor update.
if (list._monitorUpToDate) return list.value;
// If value changed, reset the flag and return a copy to trigger monitor update.
// Because monitors use Immutable data structures, only new objects trigger updates.
list._monitorUpToDate = true;
return list.value.slice();
}

return list.value;
}

getListContents (args, util) {
const list = util.target.lookupOrCreateList(
args.LIST.id, args.LIST.name);
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/irgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,11 @@ class ScriptTreeGenerator {
kind: 'list.contents',
list: this.descendVariable(block, 'LIST', LIST_TYPE)
};
case 'data_listarraycontents':
return {
kind: 'list.arraycontents',
list: this.descendVariable(block, 'LIST', LIST_TYPE)
};

case 'event_broadcast_menu': {
const broadcastOption = block.fields.BROADCAST_OPTION;
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/jsexecute.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,15 @@ runtimeFunctions.listContents = `const listContents = list => {
return list.value.join('');
}`;

/**
* Get the raw array form of a list.
* @param {import('../engine/variable')} list The list.
* @returns {string} Stringified form of the list.
*/
runtimeFunctions.listArrayContents = `const listArrayContents = list => {
return list.value;
}`;

/**
* Convert a color to an RGB list
* @param {*} color The color value to convert
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/jsgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ class JSGenerator {
return new TypedInput(`listContains(${this.referenceVariable(node.list)}, ${this.descendInput(node.item).asUnknown()})`, TYPE_BOOLEAN);
case 'list.contents':
return new TypedInput(`listContents(${this.referenceVariable(node.list)})`, TYPE_STRING);
case 'list.arraycontents':
return new TypedInput(`listArrayContents(${this.referenceVariable(node.list)})`, TYPE_STRING);
case 'list.get': {
const index = this.descendInput(node.index);
if (environment.supportsNullishCoalescing) {
Expand Down
10 changes: 7 additions & 3 deletions src/engine/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,8 @@ class Blocks {
// block but in the case of monitored reporters that have arguments,
// map the old id to a new id, creating a new monitor block if necessary
if (block.fields && Object.keys(block.fields).length > 0 &&
block.opcode !== 'data_variable' && block.opcode !== 'data_listcontents') {
block.opcode !== 'data_variable' && block.opcode !== 'data_listcontents' &&
block.opcode !== 'data_listarraycontents') {

// This block has an argument which needs to get separated out into
// multiple monitor blocks with ids based on the selected argument
Expand Down Expand Up @@ -779,6 +780,8 @@ class Blocks {
isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.VARIABLE.id]);
} else if (block.opcode === 'data_listcontents') {
isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.LIST.id]);
} else if (block.opcode === 'data_listarraycontents') {
isSpriteLocalVariable = !(this.runtime.getTargetForStage().variables[block.fields.LIST.id]);
}

const isSpriteSpecific = isSpriteLocalVariable ||
Expand Down Expand Up @@ -806,7 +809,8 @@ class Blocks {
params: this._getBlockParams(block),
// @todo(vm#565) for numerical values with decimals, some countries use comma
value: '',
mode: block.opcode === 'data_listcontents' ? 'list' : 'default'
// @todo let extensions use list monitors!
mode: (block.opcode === 'data_listcontents' || block.opcode === 'data_listarraycontents') ? 'list' : 'default'

Check failure on line 813 in src/engine/blocks.js

View workflow job for this annotation

GitHub Actions / build

This line has a length of 134. Maximum allowed is 120

Check failure on line 813 in src/engine/blocks.js

View workflow job for this annotation

GitHub Actions / build

This line has a length of 134. Maximum allowed is 120
}));
}
}
Expand Down Expand Up @@ -971,7 +975,7 @@ class Blocks {
truncatedOpcode = 'variable';
} else if (variable.type === Variable.LIST_TYPE) {
fieldName = 'LIST';
truncatedOpcode = 'listcontents';
truncatedOpcode = 'listarraycontents';
} else {
// TODO handle broadcast messages later
return [];
Expand Down

0 comments on commit 96b3934

Please sign in to comment.