Skip to content

Commit 62e3399

Browse files
authored
Updated methods_category.ts so it doesn't use implementation details of mrc_class_method_def.ts and mrc_call_python_function.ts. (#164)
1 parent ef1ee2c commit 62e3399

File tree

5 files changed

+149
-104
lines changed

5 files changed

+149
-104
lines changed

src/blocks/mrc_call_python_function.ts

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,9 @@ const WARNING_ID_FUNCTION_CHANGED = 'function changed';
7171
export function addBuiltInFunctionBlocks(
7272
functions: FunctionData[],
7373
contents: ToolboxItems.ContentsType[]) {
74-
for (const functionData of functions) {
75-
const block = createBuiltInMethodBlock(functionData);
76-
contents.push(block);
77-
}
74+
functions.forEach(functionData => {
75+
contents.push(createBuiltInMethodBlock(functionData));
76+
});
7877
}
7978

8079
function createBuiltInMethodBlock(
@@ -132,24 +131,24 @@ export function addModuleFunctionBlocks(
132131
moduleName: string,
133132
functions: FunctionData[],
134133
contents: ToolboxItems.ContentsType[]) {
135-
for (const functionData of functions) {
134+
functions.forEach(functionData => {
136135
const block = createModuleFunctionOrStaticMethodBlock(
137136
FunctionKind.MODULE, moduleName, moduleName, functionData);
138137
contents.push(block);
139-
}
138+
});
140139
}
141140

142141
export function addStaticMethodBlocks(
143142
importModule: string,
144143
functions: FunctionData[],
145144
contents: ToolboxItems.ContentsType[]) {
146-
for (const functionData of functions) {
145+
functions.forEach(functionData => {
147146
if (functionData.declaringClassName) {
148147
const block = createModuleFunctionOrStaticMethodBlock(
149148
FunctionKind.STATIC, importModule, functionData.declaringClassName, functionData);
150149
contents.push(block);
151150
}
152-
}
151+
});
153152
}
154153

155154
function createModuleFunctionOrStaticMethodBlock(
@@ -176,10 +175,9 @@ export function addConstructorBlocks(
176175
importModule: string,
177176
functions: FunctionData[],
178177
contents: ToolboxItems.ContentsType[]) {
179-
for (const functionData of functions) {
180-
const block = createConstructorBlock(importModule, functionData);
181-
contents.push(block);
182-
}
178+
functions.forEach(functionData => {
179+
contents.push(createConstructorBlock(importModule, functionData));
180+
});
183181
}
184182

185183
function createConstructorBlock(
@@ -202,10 +200,9 @@ function createConstructorBlock(
202200
export function addInstanceMethodBlocks(
203201
functions: FunctionData[],
204202
contents: ToolboxItems.ContentsType[]) {
205-
for (const functionData of functions) {
206-
const block = createInstanceMethodBlock(functionData);
207-
contents.push(block);
208-
}
203+
functions.forEach(functionData => {
204+
contents.push(createInstanceMethodBlock(functionData));
205+
});
209206
}
210207

211208
function createInstanceMethodBlock(
@@ -224,6 +221,39 @@ function createInstanceMethodBlock(
224221
return createBlock(extraState, fields, inputs);
225222
}
226223

224+
export function addInstanceWithinBlocks(
225+
methods: CommonStorage.Method[],
226+
contents: ToolboxItems.ContentsType[]) {
227+
methods.forEach(method => {
228+
contents.push(createInstanceWithinBlock(method));
229+
});
230+
}
231+
232+
function createInstanceWithinBlock(method: CommonStorage.Method): ToolboxItems.Block {
233+
const extraState: CallPythonFunctionExtraState = {
234+
functionKind: FunctionKind.INSTANCE_WITHIN,
235+
returnType: method.returnType,
236+
actualFunctionName: method.pythonName,
237+
args: [],
238+
classMethodDefBlockId: method.blockId,
239+
};
240+
const fields: {[key: string]: any} = {};
241+
fields[FIELD_FUNCTION_NAME] = method.visibleName;
242+
const inputs: {[key: string]: any} = {};
243+
// Convert method.args from CommonStorage.MethodArg[] to ArgData[].
244+
const args: ArgData[] = [];
245+
// We don't include the arg for the self argument.
246+
for (let i = 1; i < method.args.length; i++) {
247+
args.push({
248+
name: method.args[i].name,
249+
type: method.args[i].type,
250+
defaultValue: '',
251+
});
252+
}
253+
processArgs(args, extraState, inputs);
254+
return createBlock(extraState, fields, inputs);
255+
}
256+
227257
export function getInstanceComponentBlocks(
228258
component: CommonStorage.Component): ToolboxItems.ContentsType[] {
229259
const contents: ToolboxItems.ContentsType[] = [];
@@ -276,15 +306,12 @@ function createInstanceComponentBlock(
276306
return createBlock(extraState, fields, inputs);
277307
}
278308

279-
export function getInstanceRobotBlocks(methods: CommonStorage.Method[]): ToolboxItems.ContentsType[] {
280-
const contents: ToolboxItems.ContentsType[] = [];
281-
282-
for (const method of methods) {
283-
const block = createInstanceRobotBlock(method);
284-
contents.push(block);
285-
}
286-
287-
return contents;
309+
export function addInstanceRobotBlocks(
310+
methods: CommonStorage.Method[],
311+
contents: ToolboxItems.ContentsType[]) {
312+
methods.forEach(method => {
313+
contents.push(createInstanceRobotBlock(method));
314+
});
288315
}
289316

290317
function createInstanceRobotBlock(method: CommonStorage.Method): ToolboxItems.Block {

src/blocks/mrc_class_method_def.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,18 @@ const CLASS_METHOD_DEF = {
258258
}
259259
return legalName;
260260
},
261-
getMethod: function (this: ClassMethodDefBlock): commonStorage.Method | null {
262-
return this.mrcMethod;
263-
}
261+
getMethodForWithin: function (this: ClassMethodDefBlock): commonStorage.Method | null {
262+
return this.mrcCanBeCalledWithinClass ? this.mrcMethod : null;
263+
},
264+
getMethodForOutside: function (this: ClassMethodDefBlock): commonStorage.Method | null {
265+
return this.mrcCanBeCalledOutsideClass ? this.mrcMethod : null;
266+
},
267+
canChangeSignature: function (this: ClassMethodDefBlock): boolean {
268+
return this.mrcCanChangeSignature;
269+
},
270+
getMethodName: function (this: ClassMethodDefBlock): string {
271+
return this.getFieldValue('NAME');
272+
},
264273
};
265274

266275
/**
@@ -402,7 +411,7 @@ export const pythonFromBlock = function (
402411
code = generator.scrub_(block, code);
403412
generator.addClassMethodDefinition(funcName, code);
404413

405-
if (block.mrcCanBeCalledOutsideClass) {
414+
if (block.mrcCanBeCalledWithinClass || block.mrcCanBeCalledOutsideClass) {
406415
// Update the mrcMethod.
407416
block.mrcMethod = {
408417
blockId: block.id,

src/editor/editor.ts

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ export class Editor {
206206
this.blocklyWorkspace, this.generatorContext);
207207
const blocksContent = JSON.stringify(
208208
Blockly.serialization.workspaces.save(this.blocklyWorkspace));
209-
const methodsContent = JSON.stringify(this.getMethodsFromWorkspace());
209+
const methodsContent = (
210+
this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT ||
211+
this.currentModule?.moduleType === commonStorage.MODULE_TYPE_MECHANISM)
212+
? JSON.stringify(this.getMethodsForOutsideFromWorkspace())
213+
: '[]';
210214
const componentsContent = JSON.stringify(this.getComponentsFromWorkspace());
211215
return commonStorage.makeModuleContent(
212216
this.currentModule, pythonCode, blocksContent, methodsContent, componentsContent);
@@ -229,22 +233,53 @@ export class Editor {
229233
return components;
230234
}
231235

232-
public getMethodsFromWorkspace(): commonStorage.Method[] {
236+
public getMethodsForWithinFromWorkspace(): commonStorage.Method[] {
233237
const methods: commonStorage.Method[] = [];
234-
if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT ||
235-
this.currentModule?.moduleType === commonStorage.MODULE_TYPE_MECHANISM) {
236-
// Get the class method definition blocks.
237-
const methodDefBlocks = this.blocklyWorkspace.getBlocksByType(classMethodDef.BLOCK_NAME);
238-
methodDefBlocks.forEach(methodDefBlock => {
239-
const method = (methodDefBlock as classMethodDef.ClassMethodDefBlock).getMethod();
240-
if (method) {
241-
methods.push(method);
242-
}
243-
});
244-
}
238+
239+
// Get the class method definition blocks.
240+
const methodDefBlocks = this.blocklyWorkspace.getBlocksByType(classMethodDef.BLOCK_NAME);
241+
methodDefBlocks.forEach(methodDefBlock => {
242+
const method = (methodDefBlock as classMethodDef.ClassMethodDefBlock).getMethodForWithin();
243+
if (method) {
244+
methods.push(method);
245+
}
246+
});
247+
245248
return methods;
246249
}
247250

251+
public getMethodsForOutsideFromWorkspace(): commonStorage.Method[] {
252+
const methods: commonStorage.Method[] = [];
253+
254+
// Get the class method definition blocks.
255+
const methodDefBlocks = this.blocklyWorkspace.getBlocksByType(classMethodDef.BLOCK_NAME);
256+
methodDefBlocks.forEach(methodDefBlock => {
257+
const method = (methodDefBlock as classMethodDef.ClassMethodDefBlock).getMethodForOutside();
258+
if (method) {
259+
methods.push(method);
260+
}
261+
});
262+
263+
return methods;
264+
}
265+
266+
public getMethodNamesAlreadyOverriddenInWorkspace(): string[] {
267+
const methodNamesAlreadyOverridden: string[] = [];
268+
269+
// Get the class method definition blocks.
270+
const methodDefBlocks = this.blocklyWorkspace.getBlocksByType(classMethodDef.BLOCK_NAME);
271+
methodDefBlocks.forEach(block => {
272+
const methodDefBlock = block as classMethodDef.ClassMethodDefBlock;
273+
// If the user cannot change the signature, it means the block defines a method that overrides a baseclass method.
274+
// That's what we are looking for here.
275+
if (!methodDefBlock.canChangeSignature()) {
276+
methodNamesAlreadyOverridden.push(methodDefBlock.getMethodName());
277+
}
278+
});
279+
280+
return methodNamesAlreadyOverridden;
281+
}
282+
248283
public async saveBlocks() {
249284
const moduleContent = this.getModuleContent();
250285
try {
@@ -273,7 +308,7 @@ export class Editor {
273308
*/
274309
public getMethodsFromRobot(): commonStorage.Method[] {
275310
if (this.currentModule?.moduleType === commonStorage.MODULE_TYPE_ROBOT) {
276-
return this.getMethodsFromWorkspace();
311+
return this.getMethodsForWithinFromWorkspace();
277312
}
278313
if (!this.robotContent) {
279314
throw new Error('getMethodsFromRobot: this.robotContent is null.');

src/toolbox/hardware_category.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import * as commonStorage from '../storage/common_storage';
2424
import * as toolboxItems from './items';
2525
import { getAllPossibleMechanisms } from './blocks_mechanisms';
2626
import * as Component from '../blocks/mrc_component';
27-
import { getInstanceComponentBlocks, getInstanceRobotBlocks } from '../blocks/mrc_call_python_function';
27+
import { getInstanceComponentBlocks, addInstanceRobotBlocks } from '../blocks/mrc_call_python_function';
2828
import { Editor } from '../editor/editor';
2929

3030
export function getHardwareCategory(currentModule: commonStorage.Module): toolboxItems.Category {
@@ -253,7 +253,7 @@ function getRobotMethodsBlocks(): toolboxItems.Category {
253253
const editor = Editor.getEditorForBlocklyWorkspace(workspace);
254254
if (editor) {
255255
const methodsFromRobot = editor.getMethodsFromRobot();
256-
contents.push(...getInstanceRobotBlocks(methodsFromRobot));
256+
addInstanceRobotBlocks(methodsFromRobot, contents);
257257
}
258258
}
259259

src/toolbox/methods_category.ts

Lines changed: 33 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import { mechanism_class_blocks } from './mechanism_class_methods';
2828
import { opmode_class_blocks } from './opmode_class_methods';
2929
import { robot_class_blocks } from './robot_class_methods';
3030
import { ClassMethodDefBlock } from '../blocks/mrc_class_method_def'
31+
import { addInstanceWithinBlocks } from '../blocks/mrc_call_python_function'
32+
import { Editor } from '../editor/editor';
3133

3234

3335
const CUSTOM_CATEGORY_METHODS = 'METHODS';
@@ -56,32 +58,29 @@ export class MethodsCategory {
5658
// Add blocks for defining any methods that can be defined in the current
5759
// module. For example, if the current module is an OpMode, add blocks to
5860
// define the methods declared in the OpMode class.
59-
if (this.currentModule) {
60-
// Collect the method names for mrc_class_method_def blocks that are
61-
// already in the blockly workspace.
62-
const methodNamesAlreadyUsed: string[] = [];
63-
workspace.getBlocksByType('mrc_class_method_def', false).forEach((block) => {
64-
const classMethodDefBlock = block as ClassMethodDefBlock;
65-
if (!classMethodDefBlock.mrcCanChangeSignature) {
66-
methodNamesAlreadyUsed.push(classMethodDefBlock.getFieldValue('NAME'));
61+
62+
const editor = Editor.getEditorForBlocklyWorkspace(workspace);
63+
if (editor) {
64+
// Collect the method names that are already overridden in the blockly workspace.
65+
const methodNamesAlreadyOverridden = editor.getMethodNamesAlreadyOverriddenInWorkspace();
66+
67+
if (this.currentModule) {
68+
if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_ROBOT) {
69+
// Add the methods for a Robot.
70+
this.addClassBlocksForCurrentModule(
71+
'More Robot Methods', robot_class_blocks,
72+
methodNamesAlreadyOverridden, contents);
73+
} else if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_MECHANISM) {
74+
// Add the methods for a Mechanism.
75+
this.addClassBlocksForCurrentModule(
76+
'More Mechanism Methods', mechanism_class_blocks,
77+
methodNamesAlreadyOverridden, contents);
78+
} else if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_OPMODE) {
79+
// Add the methods for an OpMode.
80+
this.addClassBlocksForCurrentModule(
81+
'More OpMode Methods', opmode_class_blocks,
82+
methodNamesAlreadyOverridden, contents);
6783
}
68-
});
69-
70-
if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_ROBOT) {
71-
// Add the methods for a Robot.
72-
this.addClassBlocksForCurrentModule(
73-
'More Robot Methods', robot_class_blocks,
74-
methodNamesAlreadyUsed, contents);
75-
} else if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_MECHANISM) {
76-
// Add the methods for a Mechanism.
77-
this.addClassBlocksForCurrentModule(
78-
'More Mechanism Methods', mechanism_class_blocks,
79-
methodNamesAlreadyUsed, contents);
80-
} else if (this.currentModule.moduleType == commonStorage.MODULE_TYPE_OPMODE) {
81-
// Add the methods for an OpMode.
82-
this.addClassBlocksForCurrentModule(
83-
'More OpMode Methods', opmode_class_blocks,
84-
methodNamesAlreadyUsed, contents);
8584
}
8685
}
8786

@@ -103,39 +102,14 @@ export class MethodsCategory {
103102
returnType: 'None',
104103
params: [],
105104
},
106-
});
107-
108-
// For each mrc_class_method_def block in the blockly workspace, check if it
109-
// can be called from within the class, and if so, add a
110-
// mrc_call_python_function block.
111-
workspace.getBlocksByType('mrc_class_method_def', false).forEach((block) => {
112-
const classMethodDefBlock = block as ClassMethodDefBlock;
113-
if (classMethodDefBlock.mrcCanBeCalledWithinClass) {
114-
const callPythonFunctionBlock: toolboxItems.Block = {
115-
kind: 'block',
116-
type: 'mrc_call_python_function',
117-
extraState: {
118-
functionKind: 'instance_within',
119-
returnType: classMethodDefBlock.mrcReturnType,
120-
args: [],
121-
importModule: '',
122-
},
123-
fields: {
124-
FUNC: classMethodDefBlock.getFieldValue('NAME'),
125-
},
126-
};
127-
classMethodDefBlock.mrcParameters.forEach((param) => {
128-
if (callPythonFunctionBlock.extraState) {
129-
callPythonFunctionBlock.extraState.args.push(
130-
{
131-
name: param.name,
132-
type: param.type ?? '',
133-
});
134-
}
135-
});
136-
contents.push(callPythonFunctionBlock);
137105
}
138-
});
106+
);
107+
108+
// Get blocks for calling methods defined in the current workspace.
109+
if (editor) {
110+
const methodsFromWorkspace = editor.getMethodsForWithinFromWorkspace();
111+
addInstanceWithinBlocks(methodsFromWorkspace, contents);
112+
}
139113

140114
const toolboxInfo = {
141115
contents: contents,
@@ -146,12 +120,12 @@ export class MethodsCategory {
146120

147121
private addClassBlocksForCurrentModule(
148122
label: string, class_blocks: toolboxItems.Block[],
149-
methodNamesAlreadyUsed: string[], contents: toolboxItems.ContentsType[]) {
123+
methodNamesAlreadyOverridden: string[], contents: toolboxItems.ContentsType[]) {
150124
let labelAdded = false;
151125
class_blocks.forEach((blockInfo) => {
152126
if (blockInfo.fields) {
153127
const methodName = blockInfo.fields['NAME'];
154-
if (!methodNamesAlreadyUsed.includes(methodName)) {
128+
if (!methodNamesAlreadyOverridden.includes(methodName)) {
155129
if (!labelAdded) {
156130
contents.push(
157131
{

0 commit comments

Comments
 (0)