soiz1's picture
Upload 811 files
30c32c8 verified
raw
history blame
9.14 kB
const BlockType = require('../../extension-support/block-type');
const ArgumentType = require('../../extension-support/argument-type');
const Cast = require('../../util/cast');
/**
* Class
* @constructor
*/
class tempVars {
constructor (runtime) {
/**
* The runtime instantiating this block package.
* @type {runtime}
*/
this.runtime = runtime;
}
getThreadVars (thread) {
if (!thread.tempVars) {
thread.tempVars = Object.create(null);
}
return thread.tempVars;
}
/**
* @returns {object} metadata for this extension and its blocks.
*/
getInfo () {
return {
id: 'tempVars',
name: 'Temporary Variables',
color1: '#0069c2',
color2: '#0060B4',
color3: '#0060B4',
blocks: [
{
opcode: 'setVariable',
text: 'set [name] to [value]',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
},
value: {
type: ArgumentType.STRING,
defaultValue: 'Value'
}
},
blockType: BlockType.COMMAND
},
{
opcode: 'changeVariable',
text: 'change [name] by [value]',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
},
value: {
type: ArgumentType.NUMBER,
defaultValue: '1'
}
},
blockType: BlockType.COMMAND
},
{
opcode: 'getVariable',
text: 'get [name]',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
}
},
allowDropAnywhere: true,
blockType: BlockType.REPORTER
},
'---',
{
opcode: 'deleteVariable',
text: 'delete [name]',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
}
},
blockType: BlockType.COMMAND
},
{
opcode: 'deleteAllVariables',
text: 'delete all variables',
blockType: BlockType.COMMAND
},
{
opcode: 'variableExists',
text: 'variable [name] exists?',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
}
},
disableMonitor: true,
blockType: BlockType.BOOLEAN
},
{
opcode: 'allVariables',
text: 'current variables',
arguments: {
name: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
}
},
disableMonitor: true,
blockType: BlockType.REPORTER
},
'---',
{
opcode: 'forEachTempVar',
text: 'for each [NAME] in [REPEAT]',
branchCount: 1,
blockType: BlockType.LOOP,
arguments: {
NAME: {
type: ArgumentType.STRING,
defaultValue: 'Variable'
},
REPEAT: {
type: ArgumentType.NUMBER,
defaultValue: 10
}
}
}
]
};
}
/**
* This function is used for any compiled blocks in the extension if they exist.
* Data in this function is given to the IR & JS generators.
* Data must be valid otherwise errors may occur.
* @returns {object} functions that create data for compiled blocks.
* @deprecated nolonger in use as all of this is now inside the compiler
*/
getCompileInfoOld() {
return {
ir: {
forEachTempVar: (generator, block) => {
generator.analyzeLoop();
return {
kind: 'stack',
name: generator.descendInputOfBlock(block, 'NAME'),
repeat: generator.descendInputOfBlock(block, 'REPEAT'),
do: generator.descendSubstack(block, 'SUBSTACK')
};
}
},
js: {
forEachTempVar: (node, compiler, imports) => {
const index = compiler.localVariables.next();
const name = compiler.localVariables.next();
const inputName = compiler.descendInput(node.name).asString();
const realName = `('threadVar_' + ${inputName})`;
compiler.source += `var ${index} = 0; `;
compiler.source += `var ${name} = ${realName}; `;
compiler.source += `while (${index} < ${compiler.descendInput(node.repeat).asNumber()}) { `;
compiler.source += `${index}++; `;
compiler.source += `if (!thread.tempVars) { `;
compiler.source += `thread.tempVars = {}; `;
compiler.source += `}\n`;
compiler.source += `thread.tempVars[${name}] = ${index};\n`;
compiler.descendStack(node.do, new imports.Frame(true));
compiler.yieldLoop();
compiler.source += '}\n';
}
}
}
}
setVariable (args, util) {
const tempVars = this.getThreadVars(util.thread);
const name = `threadVar_${args.name}`;
tempVars[name] = args.value;
}
changeVariable (args, util) {
const tempVars = this.getThreadVars(util.thread);
const name = `threadVar_${args.name}`;
const oldNum = Number(tempVars[name]);
const newNum = oldNum + args.value;
if (!oldNum) {
tempVars[name] = Number(args.value);
return;
}
tempVars[name] = newNum;
}
getVariable (args, util) {
const tempVars = this.getThreadVars(util.thread);
const name = `threadVar_${args.name}`;
const value = tempVars[name];
if (!value) return '';
return value;
}
deleteVariable (args, util) {
const tempVars = this.getThreadVars(util.thread);
const name = `threadVar_${args.name}`;
if (!(name in tempVars)) return;
delete tempVars[name];
}
deleteAllVariables (_, util) {
// resets the vars
util.thread.tempVars = Object.create(null);
}
variableExists (args, util) {
const tempVars = this.getThreadVars(util.thread);
const name = `threadVar_${args.name}`;
return (name in tempVars);
}
allVariables (_, util) {
const tempVars = this.getThreadVars(util.thread);
const keys = Object.keys(tempVars);
const mapped = keys.map(name => name.replace('threadVar_', ''));
return JSON.stringify(mapped);
}
forEachTempVar (args, util) {
// compiled blocks need an interpreter version
// for edge activated hats
const count = Cast.toNumber(args.REPEAT);
const name = Cast.toString(args.NAME);
// Initialize loop
if (typeof util.stackFrame.loopCounter === 'undefined') {
util.stackFrame.loopCounter = count;
}
// Only execute once per frame.
// When the branch finishes, `repeat` will be executed again and
// the second branch will be taken, yielding for the rest of the frame.
// Decrease counter
util.stackFrame.loopCounter--;
// If we still have some left, start the branch.
if (util.stackFrame.loopCounter >= 0) {
const i = (count - (util.stackFrame.loopCounter)) - 1;
this.setVariable({ name: name, value: i + 1 }, util);
util.startBranch(1, true);
}
}
}
module.exports = tempVars;