Skip to content

Commit ea1b6cc

Browse files
committed
HeyLiz
1 parent 465d26f commit ea1b6cc

File tree

5 files changed

+158
-56
lines changed

5 files changed

+158
-56
lines changed

src/blocks/mrc_call_python_function.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { Order } from 'blockly/python';
2525

2626
import * as pythonUtils from './utils/generated/python';
2727
import { createFieldNonEditableText } from '../fields/FieldNonEditableText';
28-
import { getAllowedTypesForSetCheck, getOutputCheck } from './utils/python';
28+
import { RETURN_TYPE_NONE, getAllowedTypesForSetCheck, getOutputCheck } from './utils/python';
2929
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
3030
import { MRC_STYLE_FUNCTIONS } from '../themes/styles'
3131
import { ClassMethodDefExtraState } from './mrc_class_method_def'
@@ -34,16 +34,14 @@ import { ClassMethodDefExtraState } from './mrc_class_method_def'
3434

3535
export const BLOCK_NAME = 'mrc_call_python_function';
3636

37-
enum FunctionKind {
37+
export enum FunctionKind {
3838
MODULE = 'module',
3939
STATIC = 'static',
4040
CONSTRUCTOR = 'constructor',
4141
INSTANCE = 'instance',
4242
INSTANCE_WITHIN = 'instance_within',
4343
}
4444

45-
const RETURN_TYPE_NONE = 'None';
46-
4745
export type FunctionArg = {
4846
name: string,
4947
type: string,

src/editor/editor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export class Editor {
192192
return;
193193
}
194194
const exportedBlocks = commonStorage.extractExportedBlocks(
195-
this.currentModule.projectName, this.projectContent);
195+
this.projectPath, this.projectContent);
196196
this.setToolbox(getToolboxJSON(exportedBlocks, shownPythonToolboxCategories));
197197
}
198198
}

src/editor/extended_python_generator.ts

Lines changed: 150 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ import { Block } from '../toolbox/items';
2626
import { FunctionArg } from '../blocks/mrc_call_python_function';
2727
import * as commonStorage from '../storage/common_storage';
2828

29+
30+
const CLASS_NAME_PLACEHOLDER = '%class_name%';
31+
const FULL_CLASS_NAME_PLACEHOLDER = '%full_class_name%';
32+
const INSTANCE_LABEL_PLACEHOLDER = '%instance_label%';
33+
const INSTANCE_VARIABLE_NAME_PLACEHOLDER = '%instance_var_name%';
34+
2935
// Extends the python generator to collect some information about functions and
3036
// variables that have been defined so they can be used in other modules.
3137

@@ -121,53 +127,60 @@ export class ExtendedPythonGenerator extends PythonGenerator {
121127
}
122128

123129
private produceExportedBlocks(workspace: Blockly.Workspace): Block[] {
124-
// The exported blocks produced here have the extraState.importModule and fields.MODULE values
125-
// set to the MODULE_NAME_PLACEHOLDER. This is so blocks modules can be renamed and copied
126-
// without having to change the contents of the modules.
127-
// The placeholders will be replaced with the actual module name before they are added to the
128-
// toolbox.
130+
// The exported blocks produced here have some values set to placeholders.
131+
// This is so blocks modules can be renamed and copied without having to change the
132+
// contents of the modules. The placeholders will be replaced with the actual module
133+
// name before they are added to the toolbox. See function replacePlaceholders below.
129134

130135
const exportedBlocks = [];
131136

132-
// All functions are exported.
133-
// TODO(lizlooney): instead of looking at procedure blocks, this code needs
134-
// to look at mrc_class_method_def blocks.
135-
const allProcedures = Blockly.Procedures.allProcedures(workspace);
136-
const procedureTuples = allProcedures[0].concat(allProcedures[1]);
137-
for (const procedureTuple of procedureTuples) {
138-
const functionName = procedureTuple[0];
139-
const blockDefinition = Blockly.Procedures.getDefinition(functionName, workspace);
140-
if (!blockDefinition || !blockDefinition.isEnabled()) {
141-
continue;
137+
// Look at mrc_class_method_def blocks and make corresponding mrc_call_python_function blocks.
138+
workspace.getBlocksByType('mrc_class_method_def').forEach((classMethodDefBlock) => {
139+
if (!classMethodDefBlock.mrcCanBeCalledOutsideClass ||
140+
!classMethodDefBlock.isEnabled()) {
141+
return;
142142
}
143-
const actualFunctionName = super.getProcedureName(functionName);
144-
const hasReturnValue = procedureTuple[2];
145143
const args: FunctionArg[] = [];
146-
const parameterNames = procedureTuple[1];
147-
parameterNames.forEach((parameterName) => {
144+
args.push({
145+
'name': INSTANCE_LABEL_PLACEHOLDER,
146+
'type': FULL_CLASS_NAME_PLACEHOLDER,
147+
});
148+
classMethodDefBlock.mrcParameters.forEach((param) => {
148149
args.push({
149-
'name': parameterName,
150-
'type': '',
151-
})
150+
'name': param.name,
151+
'type': param.type,
152+
});
152153
});
153154
const callFunctionBlock: Block = {
154155
'kind': 'block',
155156
'type': 'mrc_call_python_function',
156157
'extraState': {
157-
'functionKind': 'module',
158-
'returnType': hasReturnValue ? '' : 'None',
158+
'functionKind': 'instance',
159+
'returnType': classMethodDefBlock.mrcPythonMethodName,
159160
'args': args,
160-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
161-
'actualFunctionName': actualFunctionName,
161+
'importModule': '',
162+
'actualFunctionName': classMethodDefBlock.mrcPythonMethodName,
162163
'exportedFunction': true,
163164
},
164165
'fields': {
165-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
166-
'FUNC': functionName,
166+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
167+
'FUNC': classMethodDefBlock.getFieldValue('NAME'),
167168
},
169+
'inputs': {
170+
'ARG0': {
171+
'block': {
172+
'type': 'variables_get',
173+
'fields': {
174+
'VAR': {
175+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
176+
}
177+
}
178+
}
179+
}
180+
}
168181
};
169182
exportedBlocks.push(callFunctionBlock);
170-
}
183+
});
171184

172185
const allVariables = workspace.getAllVariables();
173186
for (const variableModel of allVariables) {
@@ -197,32 +210,60 @@ export class ExtendedPythonGenerator extends PythonGenerator {
197210
'kind': 'block',
198211
'type': 'mrc_get_python_variable',
199212
'extraState': {
200-
'varKind': 'module',
201-
'moduleOrClassName': commonStorage.MODULE_NAME_PLACEHOLDER,
202-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
213+
'varKind': 'instance',
214+
'moduleOrClassName': FULL_CLASS_NAME_PLACEHOLDER,
215+
'importModule': '',
203216
'actualVariableName': actualVariableName,
217+
'selfLabel': INSTANCE_LABEL_PLACEHOLDER,
218+
'selfType': FULL_CLASS_NAME_PLACEHOLDER,
204219
'exportedVariable': true,
205220
},
206221
'fields': {
207-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
222+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
208223
'VAR': variableName,
209224
},
225+
'inputs': {
226+
'SELF': {
227+
'block': {
228+
'type': 'variables_get',
229+
'fields': {
230+
'VAR': {
231+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
232+
}
233+
}
234+
}
235+
}
236+
}
210237
};
211238
exportedBlocks.push(getPythonModuleVariableBlock);
212239
const setPythonModuleVariableBlock = {
213240
'kind': 'block',
214241
'type': 'mrc_set_python_variable',
215242
'extraState': {
216-
'varKind': 'module',
217-
'moduleOrClassName': commonStorage.MODULE_NAME_PLACEHOLDER,
218-
'importModule': commonStorage.MODULE_NAME_PLACEHOLDER,
243+
'varKind': 'instance',
244+
'moduleOrClassName': FULL_CLASS_NAME_PLACEHOLDER,
245+
'importModule': '',
219246
'actualVariableName': actualVariableName,
247+
'selfLabel': INSTANCE_LABEL_PLACEHOLDER,
248+
'selfType': FULL_CLASS_NAME_PLACEHOLDER,
220249
'exportedVariable': true,
221250
},
222251
'fields': {
223-
'MODULE_OR_CLASS': commonStorage.MODULE_NAME_PLACEHOLDER,
252+
'MODULE_OR_CLASS': FULL_CLASS_NAME_PLACEHOLDER,
224253
'VAR': variableName,
225254
},
255+
'inputs': {
256+
'SELF': {
257+
'block': {
258+
'type': 'variables_get',
259+
'fields': {
260+
'VAR': {
261+
'name': INSTANCE_VARIABLE_NAME_PLACEHOLDER,
262+
}
263+
}
264+
}
265+
}
266+
}
226267
};
227268
exportedBlocks.push(setPythonModuleVariableBlock);
228269
}
@@ -232,3 +273,75 @@ export class ExtendedPythonGenerator extends PythonGenerator {
232273
}
233274

234275
export const extendedPythonGenerator = new ExtendedPythonGenerator();
276+
277+
export function replacePlaceholders(modulePath: string, exportedBlocks: Block[]) {
278+
const moduleName = commonStorage.getModuleName(modulePath);
279+
const className = commonStorage.moduleNameToClassName(moduleName);
280+
const fullClassName = moduleName + '.' + className;
281+
const instanceLabel = className.charAt(0).toLowerCase() + className.slice(1);
282+
const instanceVariableName = instanceLabel;
283+
284+
exportedBlocks.forEach((block) => {
285+
if (block.type === 'mrc_call_python_function') {
286+
if (block.extraState.args.length > 0 &&
287+
block.extraState.args[0].name === INSTANCE_LABEL_PLACEHOLDER) {
288+
block.extraState.args[0].name = instanceLabel;
289+
}
290+
if (block.extraState.args.length > 0 &&
291+
block.extraState.args[0].type === FULL_CLASS_NAME_PLACEHOLDER) {
292+
block.extraState.args[0].type = fullClassName;
293+
}
294+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
295+
block.fields.MODULE_OR_CLASS = fullClassName;
296+
}
297+
if (block.inputs.ARG0.block.type === 'variables_get' &&
298+
block.inputs.ARG0.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
299+
block.inputs.ARG0.block.fields.VAR.name = instanceVariableName;
300+
}
301+
} else if (block.type === 'mrc_get_python_variable') {
302+
if (block.extraState.moduleOrClassName === FULL_CLASS_NAME_PLACEHOLDER) {
303+
block.extraState.moduleOrClassName = fullClassName;
304+
}
305+
if (block.extraState.selfLabel === INSTANCE_LABEL_PLACEHOLDER) {
306+
block.extraState.selfLabel = instanceLabel;
307+
}
308+
if (block.extraState.selfType === FULL_CLASS_NAME_PLACEHOLDER) {
309+
block.extraState.selfType = fullClassName;
310+
}
311+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
312+
block.fields.MODULE_OR_CLASS = fullClassName;
313+
}
314+
if (block.inputs.SELF.block.type === 'variables_get' &&
315+
block.inputs.SELF.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
316+
block.inputs.SELF.block.fields.VAR.name = instanceVariableName;
317+
}
318+
} else if (block.type === 'mrc_set_python_variable') {
319+
if (block.extraState.moduleOrClassName === FULL_CLASS_NAME_PLACEHOLDER) {
320+
block.extraState.moduleOrClassName = fullClassName;
321+
}
322+
if (block.extraState.selfLabel === INSTANCE_LABEL_PLACEHOLDER) {
323+
block.extraState.selfLabel = instanceLabel;
324+
}
325+
if (block.extraState.selfType === FULL_CLASS_NAME_PLACEHOLDER) {
326+
block.extraState.selfType = fullClassName;
327+
}
328+
if (block.fields.MODULE_OR_CLASS === FULL_CLASS_NAME_PLACEHOLDER) {
329+
block.fields.MODULE_OR_CLASS = fullClassName;
330+
}
331+
if (block.inputs.SELF.block.type === 'variables_get' &&
332+
block.inputs.SELF.block.fields.VAR.name === INSTANCE_VARIABLE_NAME_PLACEHOLDER) {
333+
block.inputs.SELF.block.fields.VAR.name = instanceVariableName;
334+
}
335+
}
336+
});
337+
338+
// HeyLiz begin
339+
const HeyLiz = JSON.stringify(exportedBlocks);
340+
if (HeyLiz.indexOf(CLASS_NAME_PLACEHOLDER) !== -1 ||
341+
HeyLiz.indexOf(FULL_CLASS_NAME_PLACEHOLDER) !== -1 ||
342+
HeyLiz.indexOf(INSTANCE_LABEL_PLACEHOLDER) !== -1 ||
343+
HeyLiz.indexOf(INSTANCE_VARIABLE_NAME_PLACEHOLDER) !== -1) {
344+
throw new Error('HeyLiz - A placeholder didn\'t get replaced: ' + HeyLiz);
345+
}
346+
// HeyLiz end
347+
}

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.
@@ -55,8 +55,6 @@ export const MODULE_TYPE_PROJECT = 'project';
5555
export const MODULE_TYPE_MECHANISM = 'mechanism';
5656
export const MODULE_TYPE_OPMODE = 'opmode';
5757

58-
export const MODULE_NAME_PLACEHOLDER = '%module_name%';
59-
6058
const DELIMITER_PREFIX = 'BlocksContent';
6159
const MARKER_MODULE_TYPE = 'moduleType: ';
6260
const MARKER_EXPORTED_BLOCKS = 'exportedBlocks: ';
@@ -372,22 +370,15 @@ export function extractBlocksContent(moduleContent: string): string {
372370
/**
373371
* Extract the exportedBlocks from the given module content.
374372
*/
375-
export function extractExportedBlocks(moduleName: string, moduleContent: string): Block[] {
373+
export function extractExportedBlocks(modulePath: string, moduleContent: string): Block[] {
376374
const parts = getParts(moduleContent);
377375
let exportedBlocksContent = parts[PARTS_INDEX_EXPORTED_BLOCKS];
378376
if (exportedBlocksContent.startsWith(MARKER_EXPORTED_BLOCKS)) {
379377
exportedBlocksContent = exportedBlocksContent.substring(MARKER_EXPORTED_BLOCKS.length);
380378
}
381379

382380
const exportedBlocks: Block[] = JSON.parse(exportedBlocksContent);
383-
exportedBlocks.forEach((block) => {
384-
if (block.extraState?.importModule === MODULE_NAME_PLACEHOLDER) {
385-
block.extraState.importModule = moduleName;
386-
}
387-
if (block.fields?.MODULE_OR_CLASS === MODULE_NAME_PLACEHOLDER) {
388-
block.fields.MODULE_OR_CLASS = moduleName;
389-
}
390-
});
381+
replacePlaceholders(modulePath, exportedBlocks);
391382
return exportedBlocks;
392383
}
393384

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'));
@@ -108,7 +108,7 @@ export class MethodsCategory {
108108
// For each mrc_class_method_def block in the blockly workspace, check if it
109109
// can be called from within the class, and if so, add a
110110
// mrc_call_python_function block.
111-
workspace.getBlocksByType('mrc_class_method_def', false).forEach((block) => {
111+
workspace.getBlocksByType('mrc_class_method_def').forEach((block) => {
112112
const classMethodDefBlock = block as ClassMethodDefBlock;
113113
if (classMethodDefBlock.mrcCanBeCalledWithinClass) {
114114
const callPythonFunctionBlock: toolboxItems.Block = {

0 commit comments

Comments
 (0)