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; | |