Skip to content

Commit

Permalink
Add class constants
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienTainon committed Aug 19, 2024
1 parent 28b452b commit 78b1dac
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 30 deletions.
1 change: 1 addition & 0 deletions frontend/buffers/editorAutocompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const addAutocompletion = function (blocks: Block[], strings: any) {
});
break;
case BlockType.Constant:
case BlockType.ClassConstant:
let name = block.name;
if (strings.constant && strings.constant[name]) {
name = strings.constant[name];
Expand Down
66 changes: 41 additions & 25 deletions frontend/stepper/python/python_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,37 @@ mod.${classInstance}.__variableName = '${classInstance}';
`;
}

private static _skulptifyClass(className: string, classMethods: string[]) {
private static _skulptifyClass(className: string, classComponents: string[]) {
return `
newClass${className} = function ($gbl, $loc) {
${classMethods.join("")}
${classComponents.join("")}
};
mod.${className} = Sk.misceval.buildClass(mod, newClass${className}, "${className}", []);
`;
}

private static _skulptifyConst(name, value) {
let handler = '';
if (typeof value === "number") {
handler = 'Sk.builtin.int_(' + value + ');';
} else if (typeof value === "boolean") {
handler = 'Sk.builtin.bool(' + value.toString() + ');';
} else if (typeof value === "string") {
handler = 'Sk.builtin.str(' + JSON.stringify(value) + ');';
} else {
throw "Unable to translate value '" + value + "' into a Skulpt constant.";
}

return '\nmod.' + name + ' = new ' + handler + '\n';
}

private static _skulptifyClassConstHandler(name, value) {
const handler = PythonRunner._skulptifyConst(name, value);

return handler.replace(/mod\./, '$loc.');
}

private _createBuiltin(name, generatorName, blockName, nbArgs, type) {
const self = this;

Expand Down Expand Up @@ -195,21 +216,6 @@ mod.${className} = Sk.misceval.buildClass(mod, newClass${className}, "${classNam
}
}

private static _skulptifyConst(name, value) {
let handler = '';
if (typeof value === "number") {
handler = 'Sk.builtin.int_(' + value + ');';
} else if (typeof value === "boolean") {
handler = 'Sk.builtin.bool(' + value.toString() + ');';
} else if (typeof value === "string") {
handler = 'Sk.builtin.str(' + JSON.stringify(value) + ');';
} else {
throw "Unable to translate value '" + value + "' into a Skulpt constant.";
}

return '\nmod.' + name + ' = new ' + handler + '\n';
}

private _injectFunctions() {
// Generate Python custom libraries from all generated blocks
log.getLogger('python_runner').debug('inject functions', this.availableBlocks);
Expand Down Expand Up @@ -237,20 +243,30 @@ mod.${className} = Sk.misceval.buildClass(mod, newClass${className}, "${classNam
}

const classInstancesToAdd: {[classInstance: string]: string} = {};
const classMethods: {[className: string]: {[methodName: string]: string}} = {};
const classParts: {[className: string]: {[methodName: string]: string}} = {};
for (let block of blocks.filter(block => block.type === BlockType.ClassFunction)) {
const {code, generatorName, name, params, type, methodName, className, classInstance} = block;
const {generatorName, name, params, type, methodName, className, classInstance} = block;
classInstancesToAdd[classInstance] = className;
if (!(className in classMethods)) {
classMethods[className] = {};
if (!(className in classParts)) {
classParts[className] = {};
}
if (!(methodName in classParts[className])) {
classParts[className][methodName] = PythonRunner._skulptifyClassHandler(methodName, generatorName, name, params, type, className);
}
}

for (let block of blocks.filter(block => block.type === BlockType.ClassConstant)) {
const {name, value, className, methodName} = block;
if (!(className in classParts)) {
classParts[className] = {};
}
if (!(methodName in classMethods[className])) {
classMethods[className][methodName] = PythonRunner._skulptifyClassHandler(methodName, generatorName, name, params, type, className);
if (!(name in classParts[className])) {
classParts[className][name] = PythonRunner._skulptifyClassConstHandler(methodName, value);
}
}

for (let [className, classMethodsList] of Object.entries(classMethods)) {
modContents += PythonRunner._skulptifyClass(className, Object.values(classMethodsList));
for (let [className, classPartsList] of Object.entries(classParts)) {
modContents += PythonRunner._skulptifyClass(className, Object.values(classPartsList));
}

for (let [classInstance, className] of Object.entries(classInstancesToAdd)) {
Expand Down
1 change: 1 addition & 0 deletions frontend/task/blocks/block_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum BlockType {
Function = 'function',
ClassFunction = 'class_function',
Constant = 'constant',
ClassConstant = 'class_constant',
Token = 'token',
Directive = 'directive',
}
Expand Down
27 changes: 24 additions & 3 deletions frontend/task/blocks/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,30 @@ export const getContextBlocksDataSelector = memoize(({state, context}: {state: A
for (let typeName in context.customClasses[generatorName]) {
for (let className in context.customClasses[generatorName][typeName]) {
let classRepresentation = context.customClasses[generatorName][typeName][className];
for (let iBlock = 0; iBlock < classRepresentation.length; iBlock++) {
let block = classRepresentation[iBlock];
blocksInfos[className + '.' + block.name] = generateBlockInfo(block, typeName);
if (classRepresentation.constructor) {
blocksInfos[className + '.init'] = generateBlockInfo(classRepresentation.constructor, typeName);
}
if (classRepresentation.blocks) {
for (let iBlock = 0; iBlock < classRepresentation.blocks.length; iBlock++) {
let block = classRepresentation.blocks[iBlock];
blocksInfos[className + '.' + block.name] = generateBlockInfo(block, typeName);
}
}
if (classRepresentation.constants) {
for (let iConst = 0; iConst < classRepresentation.constants.length; iConst++) {
let name = classRepresentation.constants[iConst].name;
availableBlocks.push({
generatorName,
name: `${className}.${name}`,
caption: `${className}.${name}`,
code: `${className}.${name}`,
category: 'constants',
type: BlockType.ClassConstant,
methodName: name,
className,
value: classRepresentation.constants[iConst].value,
});
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions frontend/task/libs/quickalgo_library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@ export interface LibraryEventListener {
}

export interface QuickalgoLibraryBlock {
name: string,
name?: string,
yieldsValue?: boolean,
params?: string[],
blocklyJson?: any,
anyArgs?: boolean,
variants?: any,
}

interface QuickAlgoCustomClass {
constructor: QuickalgoLibraryBlock,
blocks: QuickalgoLibraryBlock[],
constants: {name: string, value: any}[],
}

export abstract class QuickAlgoLibrary {
display: boolean;
infos: QuickalgoLibraryInfos;
Expand All @@ -39,7 +45,7 @@ export abstract class QuickAlgoLibrary {
strings: any;
customBlocks: {[generatorName: string]: {[categoryName: string]: QuickalgoLibraryBlock[]}};
customConstants: {[generatorName: string]: {name: string, value: any}[]};
customClasses: {[generatorName: string]: {[categoryName: string]: {[className: string]: any[]}}};
customClasses: {[generatorName: string]: {[categoryName: string]: {[className: string]: QuickAlgoCustomClass}}};
customClassInstances: {[generatorName: string]: {[instanceName: string]: string}};
conceptList: any[];
conceptDisabledList?: string[];
Expand Down

0 comments on commit 78b1dac

Please sign in to comment.