Spaces:
Runtime error
Runtime error
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; | |