Skip to content

Commit

Permalink
Add events handling on Blockly/Scratch
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastienTainon committed May 6, 2024
1 parent 5d7cd5e commit 8bfddd3
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 39 deletions.
3 changes: 2 additions & 1 deletion frontend/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {TaskLevelName} from "./task/platform/platform_slice";
import {SmartContractConfigType} from './task/libs/smart_contract/smart_contract_lib';
import {App, CodecastType} from './app_types';
import {CodecastPlatform} from './stepper/codecast_platform';
import AbstractRunner from './stepper/abstract_runner';

// Disabling auto-freeze is recommended by proxy-memoize, cf https://github.com/dai-shi/proxy-memoize
// This is because JavaScript does not support nested proxies of frozen objects
Expand Down Expand Up @@ -78,7 +79,7 @@ declare global {
store: EnhancedStore<AppStore>,
replayStore: EnhancedStore<AppStore>,
Codecast: CodecastType,
currentPythonRunner: any,
currentPythonRunner: AbstractRunner,
languageStrings: any,
currentPlatform?: CodecastPlatform,
__REDUX_DEVTOOLS_EXTENSION__: any,
Expand Down
7 changes: 7 additions & 0 deletions frontend/stepper/abstract_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,11 @@ export default abstract class AbstractRunner {

public async programInitialization(stepperContext: StepperContext): Promise<void> {
}

public makeQuickalgoCall(quickalgoMethod, callback) {
quickalgoMethod(callback);
}

public createNewThread(threadData: any) {
}
}
4 changes: 4 additions & 0 deletions frontend/stepper/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ async function executeSingleStep(stepperContext: StepperContext) {

stepperContext.hasMadeFinalInteract = false;

if (stepperContext.quickAlgoContext) {
await stepperContext.quickAlgoContext.checkEventListeners();
}

await Codecast.runner.runNewStep(stepperContext, stepperContext.noInteractive);

if (!stepperContext.hasMadeFinalInteract && stepperContext.noInteractive && makeInteraction) {
Expand Down
22 changes: 21 additions & 1 deletion frontend/stepper/js/blockly_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,9 @@ export default class BlocklyRunner extends AbstractRunner {
return function () {
let args = [];
for(let i=0; i < arguments.length-1; i++) {
if(typeof arguments[i] != 'undefined' && arguments[i].isObject) {
if (typeof arguments[i] != 'undefined' && arguments[i].isObject && 'Function' === arguments[i].class) {
args.push(arguments[i]);
} else if(typeof arguments[i] != 'undefined' && arguments[i].isObject) {
args.push(interpreter.pseudoToNative(arguments[i]));
} else {
args.push(arguments[i]);
Expand Down Expand Up @@ -646,4 +648,22 @@ export default class BlocklyRunner extends AbstractRunner {
stepperState.codecastAnalysis = convertAnalysisDAPToCodecastFormat(stepperState.analysis, stepperState.lastAnalysis);
log.getLogger('stepper').debug('codecast analysis', stepperState.codecastAnalysis);
}

public createNewThread(threadData: any) {
console.log('create thread', threadData);

const globalScope = this.interpreters[0].global;
const node = threadData.node;
const stack = new window.Interpreter.State(node['body'], globalScope);
console.log('stack', stack);

this.swapCurrentThread(stack);

return 5;
}

public swapCurrentThread(stack) {
// var stack = threads[n];
this.interpreters[0].stateStack = [stack];
}
}
5 changes: 5 additions & 0 deletions frontend/stepper/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ export function* loadBlocklyHelperSaga(context: QuickAlgoLibrary) {
return this.scratchMode ? {x: 20, y: 20} : {x: 20, y: 2};
};

if (context.infos.multithread) {
// Make generation of all blocks
blocklyHelper.startingBlock = false;
}

context.blocklyHelper = blocklyHelper;
context.onChange = () => {};

Expand Down
36 changes: 25 additions & 11 deletions frontend/stepper/python/python_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export default class PythonRunner extends AbstractRunner {
this._resetInterpreterState();

if (Sk.running) {
log.getLogger('python_runner').debug('running aleady');
log.getLogger('python_runner').debug('running already');
if (typeof Sk.runQueue === 'undefined') {
Sk.runQueue = [];
}
Expand All @@ -464,9 +464,9 @@ export default class PythonRunner extends AbstractRunner {
let promise = this._debugger.asyncToPromise(this._asyncCallback.bind(this), null, this._debugger);
promise.then((response) => {
console.log('on final response');
this._debugger.success.bind(this._debugger);
// this._debugger.success.bind(this._debugger);
}, (error) => {
this._debugger.error.bind(this._debugger);
// this._debugger.error.bind(this._debugger);

this.context.onError(error + "\n");
});
Expand All @@ -487,14 +487,11 @@ export default class PythonRunner extends AbstractRunner {
console.log('start running step');

return new Promise((resolve, reject) => {
this.context.checkEventListeners()
.then(() => {
this.stepMode = !noInteractive;
console.log('step', {running: this._isRunning, progress: this._stepInProgress});
if (this._isRunning && !this._stepInProgress) {
this.step(resolve, reject);
}
});
this.stepMode = !noInteractive;
console.log('step', {running: this._isRunning, progress: this._stepInProgress});
if (this._isRunning && !this._stepInProgress) {
this.step(resolve, reject);
}
}).then(() => {
if (this.hasCalledHandler) {
// Fix for Python: when Skulpt executes a custom handler it counts this as two execution steps.
Expand Down Expand Up @@ -729,4 +726,21 @@ export default class PythonRunner extends AbstractRunner {
});
}
}

public makeQuickalgoCall(quickalgoMethod, callback) {
quickalgoMethod((result: any) => {
this._resetCallstackOnNextStep = false;
const realResult = this.skToJs(result);
callback(realResult);
});
}

public createNewThread(threadData) {
const result = threadData();
console.log('callback result', result);
result
.then((aaa) => {
console.log('aaa', aaa);
})
}
}
27 changes: 6 additions & 21 deletions frontend/task/libs/quickalgo_library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {TaskSubmissionServerTestResult} from '../../submission/submission_types'
import {CodecastPlatform} from '../../stepper/codecast_platform';
import {App, Codecast} from '../../app_types';
import {mainQuickAlgoLogger} from './quick_algo_logger';
import AbstractRunner from '../../stepper/abstract_runner';

export interface LibraryEventListener {
condition: (callback: (result: boolean) => void) => void,
Expand All @@ -32,7 +33,7 @@ export abstract class QuickAlgoLibrary {
conceptList: any[];
conceptDisabledList?: string[];
notionsList: NotionArborescence;
runner: any;
runner: AbstractRunner;
curNode: any;
lost: boolean = false;
aceEditor: any;
Expand Down Expand Up @@ -408,7 +409,7 @@ export abstract class QuickAlgoLibrary {
return null;
}

waitForEvent(condition: (callback: (result: boolean) => void) => void, callback: () => void) {
waitForEvent(condition: (callback: (result: boolean) => void) => void, callback: () => Promise<void>) {
this.eventListeners.push({
condition,
callback,
Expand Down Expand Up @@ -440,31 +441,15 @@ export abstract class QuickAlgoLibrary {

isEventListenerConditionActive(listener: LibraryEventListener) {
return new Promise((resolve) => {
listener.condition((result) => {
// TODO: support other languages than Python
this.runner._resetCallstackOnNextStep = false;
const realResult = this.runner.skToJs(result);
console.log({result, realResult})
resolve(realResult);
})
this.runner.makeQuickalgoCall(listener.condition, resolve);
});
}

triggerEventListener(listener: LibraryEventListener) {
// TODO: Pause current execution and then do:
this.waitingEventListener = true;
// this.waitingEventListener = true;
console.log('trigger event listener', listener.callback);

return new Promise<void>((resolve) => {
const result = listener.callback();
console.log('callback result', result);
result
.then((aaa) => {
console.log('aaa', aaa);
this.waitingEventListener = false;
resolve();
})
});
this.runner.createNewThread(listener.callback);
}
}

12 changes: 7 additions & 5 deletions frontend/task/python_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,11 +371,13 @@ export const checkPythonCode = function (document: Document, context: QuickAlgoL
definedFunctions.push(match[1]);
}

let codeWithoutTextsBetweenQuotes = code.replace(/"[^"]+"/g, '').replace(/'[^']+'/g, '');
for (let j = 0; j < definedFunctions.length; j++) {
re = new RegExp('\\W' + definedFunctions[j] + '([^A-Za-z0-9_( ]| +[^ (]|$)');
if (re.exec(codeWithoutTextsBetweenQuotes)) {
throw getMessage('CODE_CONSTRAINTS_FUNCTIONS_WITHOUT_PARENTHESIS').format({funcName: definedFunctions[j]});
if (!context.infos.multithread) {
let codeWithoutTextsBetweenQuotes = code.replace(/"[^"]+"/g, '').replace(/'[^']+'/g, '');
for (let j = 0; j < definedFunctions.length; j++) {
re = new RegExp('\\W' + definedFunctions[j] + '([^A-Za-z0-9_( ]| +[^ (]|$)');
if (re.exec(codeWithoutTextsBetweenQuotes)) {
throw getMessage('CODE_CONSTRAINTS_FUNCTIONS_WITHOUT_PARENTHESIS').format({funcName: definedFunctions[j]});
}
}
}
}
1 change: 1 addition & 0 deletions frontend/task/task_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export interface QuickalgoTaskGridInfosNotLevelDependent {
remoteDebugEnabled?: boolean,
hideVariantsInDocumentation?: boolean,
blocksLanguage?: {[platform: string]: string},
multithread?: boolean,
}

export interface QuickalgoTaskGridInfos extends QuickalgoTaskGridInfosNotLevelDependent {
Expand Down

0 comments on commit 8bfddd3

Please sign in to comment.