Skip to content

Commit b991169

Browse files
committed
HeyLiz
1 parent ce70894 commit b991169

File tree

3 files changed

+156
-52
lines changed

3 files changed

+156
-52
lines changed

src/editor/extended_python_generator.ts

Lines changed: 151 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ import { FunctionArg } from '../blocks/mrc_call_python_function';
2727
import * as MechanismContainerHolder from '../blocks/mrc_mechanism_component_holder';
2828
import * as commonStorage from '../storage/common_storage';
2929

30+
31+
const CLASS_NAME_PLACEHOLDER = '%class_name%';
32+
const FULL_CLASS_NAME_PLACEHOLDER = '%full_class_name%';
33+
const INSTANCE_LABEL_PLACEHOLDER = '%instance_label%';
34+
const INSTANCE_VARIABLE_NAME_PLACEHOLDER = '%instance_var_name%';
35+
3036
export class OpModeDetails {
3137
constructor(private name: string, private group : string, private enabled : boolean, private type : string) {}
3238
annotations() : string{
@@ -56,7 +62,7 @@ export class ExtendedPythonGenerator extends PythonGenerator {
5662
private ports: {[key: string]: string} = Object.create(null);
5763
// Opmode details
5864
private details : OpModeDetails | null = null;
59-
65+
6066
constructor() {
6167
super('Python');
6268
}
@@ -180,53 +186,60 @@ export class ExtendedPythonGenerator extends PythonGenerator {
180186
}
181187

182188
private produceExportedBlocks(workspace: Blockly.Workspace): Block[] {
183-
// The exported blocks produced here have the extraState.importModule and fields.MODULE values
184-
// set to the MODULE_NAME_PLACEHOLDER. This is so blocks modules can be renamed and copied
185-
// without having to change the contents of the modules.
186-
// The placeholders will be replaced with the actual module name before they are added to the
187-
// toolbox.
189+
// The exported blocks produced here have some values set to placeholders.
190+
// This is so blocks modules can be renamed and copied without having to change the
191+
// contents of the modules. The placeholders will be replaced with the actual module
192+
// name before they are added to the toolbox. See function replacePlaceholders below.
188193

189194
const exportedBlocks = [];
190195

191-
// All functions are exported.
192-
// TODO(lizlooney): instead of looking at procedure blocks, this code needs
193-
// to look at mrc_class_method_def blocks.
194-
const allProcedures = Blockly.Procedures.allProcedures(workspace);
195-
const procedureTuples = allProcedures[0].concat(allProcedures[1]);
196-
for (const procedureTuple of procedureTuples) {
197-
const functionName = procedureTuple[0];
198-
const blockDefinition = Blockly.Procedures.getDefinition(functionName, workspace);
199-
if (!blockDefinition || !blockDefinition.isEnabled()) {
200-
continue;
196+
// Look at mrc_class_method_def blocks and make corresponding mrc_call_python_function blocks.
197+
workspace.getBlocksByType('mrc_class_method_def').forEach((classMethodDefBlock) => {
198+
if (!classMethodDefBlock.mrcCanBeCalledOutsideClass ||
199+
!classMethodDefBlock.isEnabled()) {
200+
return;
201201
}
202-
const actualFunctionName = super.getProcedureName(functionName);
203-
const hasReturnValue = procedureTuple[2];
204202
const args: FunctionArg[] = [];
205-
const parameterNames = procedureTuple[1];
206-
parameterNames.forEach((parameterName) => {
203+
args.push({
204+
'name': INSTANCE_LABEL_PLACEHOLDER,
205+
'type': FULL_CLASS_NAME_PLACEHOLDER,
206+
});
207+
classMethodDefBlock.mrcParameters.forEach((param) => {
207208
args.push({
208-
'name': parameterName,
209-
'type': '',
210-
})
209+
'name': param.name,
210+
'type': param.type,
211+
});
211212
});
212213
const callFunctionBlock: Block = {
213214
'kind': 'block',
214215
'type': 'mrc_call_python_function',
215216
'extraState': {
216-
'functionKind': 'module',
217-
'returnType': hasReturnValue ? '' : 'None',
217+
'functionKind': 'instance',
218+
'returnType': classMethodDefBlock.mrcPythonMethodName,
218219
'args': args,
219-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
220-
'actualFunctionName': actualFunctionName,
220+
'importModule': '',
221+
'actualFunctionName': classMethodDefBlock.mrcPythonMethodName,
221222
'exportedFunction': true,
222223
},
223224
'fields': {
224-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
225-
'FUNC': functionName,
225+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
226+
'FUNC': classMethodDefBlock.getFieldValue('NAME'),
226227
},
228+
'inputs': {
229+
'ARG0': {
230+
'block': {
231+
'type': 'variables_get',
232+
'fields': {
233+
'VAR': {
234+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
235+
}
236+
}
237+
}
238+
}
239+
}
227240
};
228241
exportedBlocks.push(callFunctionBlock);
229-
}
242+
});
230243

231244
const allVariables = workspace.getAllVariables();
232245
for (const variableModel of allVariables) {
@@ -256,32 +269,60 @@ export class ExtendedPythonGenerator extends PythonGenerator {
256269
'kind': 'block',
257270
'type': 'mrc_get_python_variable',
258271
'extraState': {
259-
'varKind': 'module',
260-
'moduleOrClassName': commonStorage.MODULE_NAME_PLACEHOLDER,
261-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
272+
'varKind': 'instance',
273+
'moduleOrClassName': FULL_CLASS_NAME_PLACEHOLDER,
274+
'importModule': '',
262275
'actualVariableName': actualVariableName,
276+
'selfLabel': INSTANCE_LABEL_PLACEHOLDER,
277+
'selfType': FULL_CLASS_NAME_PLACEHOLDER,
263278
'exportedVariable': true,
264279
},
265280
'fields': {
266-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
281+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
267282
'VAR': variableName,
268283
},
284+
'inputs': {
285+
'SELF': {
286+
'block': {
287+
'type': 'variables_get',
288+
'fields': {
289+
'VAR': {
290+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
291+
}
292+
}
293+
}
294+
}
295+
}
269296
};
270297
exportedBlocks.push(getPythonModuleVariableBlock);
271298
const setPythonModuleVariableBlock = {
272299
'kind': 'block',
273300
'type': 'mrc_set_python_variable',
274301
'extraState': {
275-
'varKind': 'module',
276-
'moduleOrClassName': commonStorage.MODULE_NAME_PLACEHOLDER,
277-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
302+
'varKind': 'instance',
303+
'moduleOrClassName': FULL_CLASS_NAME_PLACEHOLDER,
304+
'importModule': '',
278305
'actualVariableName': actualVariableName,
306+
'selfLabel': INSTANCE_LABEL_PLACEHOLDER,
307+
'selfType': FULL_CLASS_NAME_PLACEHOLDER,
279308
'exportedVariable': true,
280309
},
281310
'fields': {
282-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
311+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
283312
'VAR': variableName,
284313
},
314+
'inputs': {
315+
'SELF': {
316+
'block': {
317+
'type': 'variables_get',
318+
'fields': {
319+
'VAR': {
320+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
321+
}
322+
}
323+
}
324+
}
325+
}
285326
};
286327
exportedBlocks.push(setPythonModuleVariableBlock);
287328
}
@@ -301,3 +342,75 @@ export class ExtendedPythonGenerator extends PythonGenerator {
301342
}
302343

303344
export const extendedPythonGenerator = new ExtendedPythonGenerator();
345+
346+
export function replacePlaceholders(modulePath: string, exportedBlocks: Block[]) {
347+
const moduleName = commonStorage.getModuleName(modulePath);
348+
const className = commonStorage.moduleNameToClassName(moduleName);
349+
const fullClassName = moduleName + '.' + className;
350+
const instanceLabel = className.charAt(0).toLowerCase() + className.slice(1);
351+
const instanceVariableName = instanceLabel;
352+
353+
exportedBlocks.forEach((block) => {
354+
if (block.type === 'mrc_call_python_function') {
355+
if (block.extraState.args.length > 0 &&
356+
block.extraState.args[0].name === INSTANCE_LABEL_PLACEHOLDER) {
357+
block.extraState.args[0].name = instanceLabel;
358+
}
359+
if (block.extraState.args.length > 0 &&
360+
block.extraState.args[0].type === FULL_CLASS_NAME_PLACEHOLDER) {
361+
block.extraState.args[0].type = fullClassName;
362+
}
363+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
364+
block.fields.MODULE_OR_CLASS = fullClassName;
365+
}
366+
if (block.inputs.ARG0.block.type === 'variables_get' &&
367+
block.inputs.ARG0.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
368+
block.inputs.ARG0.block.fields.VAR.name = instanceVariableName;
369+
}
370+
} else if (block.type === 'mrc_get_python_variable') {
371+
if (block.extraState.moduleOrClassName === FULL_CLASS_NAME_PLACEHOLDER) {
372+
block.extraState.moduleOrClassName = fullClassName;
373+
}
374+
if (block.extraState.selfLabel === INSTANCE_LABEL_PLACEHOLDER) {
375+
block.extraState.selfLabel = instanceLabel;
376+
}
377+
if (block.extraState.selfType === FULL_CLASS_NAME_PLACEHOLDER) {
378+
block.extraState.selfType = fullClassName;
379+
}
380+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
381+
block.fields.MODULE_OR_CLASS = fullClassName;
382+
}
383+
if (block.inputs.SELF.block.type === 'variables_get' &&
384+
block.inputs.SELF.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
385+
block.inputs.SELF.block.fields.VAR.name = instanceVariableName;
386+
}
387+
} else if (block.type === 'mrc_set_python_variable') {
388+
if (block.extraState.moduleOrClassName === FULL_CLASS_NAME_PLACEHOLDER) {
389+
block.extraState.moduleOrClassName = fullClassName;
390+
}
391+
if (block.extraState.selfLabel === INSTANCE_LABEL_PLACEHOLDER) {
392+
block.extraState.selfLabel = instanceLabel;
393+
}
394+
if (block.extraState.selfType === FULL_CLASS_NAME_PLACEHOLDER) {
395+
block.extraState.selfType = fullClassName;
396+
}
397+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
398+
block.fields.MODULE_OR_CLASS = fullClassName;
399+
}
400+
if (block.inputs.SELF.block.type === 'variables_get' &&
401+
block.inputs.SELF.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
402+
block.inputs.SELF.block.fields.VAR.name = instanceVariableName;
403+
}
404+
}
405+
});
406+
407+
// HeyLiz begin
408+
const HeyLiz = JSON.stringify(exportedBlocks);
409+
if (HeyLiz.indexOf(CLASS_NAME_PLACEHOLDER) !== -1 ||
410+
HeyLiz.indexOf(FULL_CLASS_NAME_PLACEHOLDER) !== -1 ||
411+
HeyLiz.indexOf(INSTANCE_LABEL_PLACEHOLDER) !== -1 ||
412+
HeyLiz.indexOf(INSTANCE_VARIABLE_NAME_PLACEHOLDER) !== -1) {
413+
throw new Error('HeyLiz - A placeholder didn\'t get replaced: ' + HeyLiz);
414+
}
415+
// HeyLiz end
416+
}

src/storage/common_storage.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import startingOpModeBlocks from '../modules/opmode_start.json';
2828
import startingMechanismBlocks from '../modules/mechanism_start.json';
2929
import startingRobotBlocks from '../modules/robot_start.json';
3030

31-
import {extendedPythonGenerator} from '../editor/extended_python_generator';
31+
import { extendedPythonGenerator, replacePlaceholders } from '../editor/extended_python_generator';
3232
import { createGeneratorContext } from '../editor/generator_context';
3333

3434
// Types, constants, and functions related to modules, regardless of where the modules are stored.
@@ -60,8 +60,6 @@ export const MODULE_TYPE_PROJECT = 'project';
6060
export const MODULE_TYPE_MECHANISM = 'mechanism';
6161
export const MODULE_TYPE_OPMODE = 'opmode';
6262

63-
export const MODULE_NAME_PLACEHOLDER = '%module_name%';
64-
6563
const DELIMITER_PREFIX = 'BlocksContent';
6664
const MARKER_BLOCKS_CONTENT = 'blocksContent: ';
6765
const MARKER_EXPORTED_BLOCKS = 'exportedBlocks: ';
@@ -392,22 +390,15 @@ export function extractBlocksContent(moduleContent: string): string {
392390
/**
393391
* Extract the exportedBlocks from the given module content.
394392
*/
395-
export function extractExportedBlocks(moduleName: string, moduleContent: string): Block[] {
393+
export function extractExportedBlocks(modulePath: string, moduleContent: string): Block[] {
396394
const parts = getParts(moduleContent);
397395
let exportedBlocksContent = parts[PARTS_INDEX_EXPORTED_BLOCKS];
398396
if (exportedBlocksContent.startsWith(MARKER_EXPORTED_BLOCKS)) {
399397
exportedBlocksContent = exportedBlocksContent.substring(MARKER_EXPORTED_BLOCKS.length);
400398
}
401399

402400
const exportedBlocks: Block[] = JSON.parse(exportedBlocksContent);
403-
exportedBlocks.forEach((block) => {
404-
if (block.extraState?.importModule === MODULE_NAME_PLACEHOLDER) {
405-
block.extraState.importModule = moduleName;
406-
}
407-
if (block.fields?.MODULE_OR_CLASS === MODULE_NAME_PLACEHOLDER) {
408-
block.fields.MODULE_OR_CLASS = moduleName;
409-
}
410-
});
401+
replacePlaceholders(modulePath, exportedBlocks);
411402
return exportedBlocks;
412403
}
413404

src/toolbox/methods_category.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class MethodsCategory {
6060
// Collect the method names for mrc_class_method_def blocks that are
6161
// already in the blockly workspace.
6262
const methodNamesAlreadyUsed: string[] = [];
63-
workspace.getBlocksByType('mrc_class_method_def', false).forEach((block) => {
63+
workspace.getBlocksByType('mrc_class_method_def').forEach((block) => {
6464
const classMethodDefBlock = block as ClassMethodDefBlock;
6565
if (!classMethodDefBlock.mrcCanChangeSignature) {
6666
methodNamesAlreadyUsed.push(classMethodDefBlock.getFieldValue('NAME'));
@@ -112,7 +112,7 @@ export class MethodsCategory {
112112
// For each mrc_class_method_def block in the blockly workspace, check if it
113113
// can be called from within the class, and if so, add a
114114
// mrc_call_python_function block.
115-
workspace.getBlocksByType('mrc_class_method_def', false).forEach((block) => {
115+
workspace.getBlocksByType('mrc_class_method_def').forEach((block) => {
116116
const classMethodDefBlock = block as ClassMethodDefBlock;
117117
if (classMethodDefBlock.mrcCanBeCalledWithinClass) {
118118
const callPythonFunctionBlock: toolboxItems.Block = {

0 commit comments

Comments
 (0)