Skip to content

Commit c59afe9

Browse files
PavloPavlo
authored andcommitted
fixed module loader conflict with package Loader
1 parent f7c906d commit c59afe9

File tree

6 files changed

+75
-15
lines changed

6 files changed

+75
-15
lines changed

index.html

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ <h4>JSPython development console</h4>
5353
resultEditor.session.setMode("ace/mode/json");
5454

5555
const interpreter = jspython.jsPython();
56-
console.log({interpreter});
56+
console.log({ interpreter });
5757

5858
function tokenize() {
5959
tokenizer = (s) => console.log(`tokens => ${s}`, interpreter().tokenize(s))
@@ -95,14 +95,14 @@ <h4>JSPython development console</h4>
9595

9696
interpreter.registerModuleLoader((path => {
9797
return Promise.resolve(`
98+
from 'service' import add
99+
98100
def multiply(x, y):
99101
x * y
100102
101103
def func1(x, y):
102-
if y == null:
103-
y = 77
104-
105-
multiply(x, y) + someNumber
104+
print('++>>>', getExecutionContext())
105+
multiply(x, y) + add(x, y)
106106
107107
name = 'test'
108108
someNumber = 55
@@ -111,6 +111,16 @@ <h4>JSPython development console</h4>
111111
`);
112112
}));
113113

114+
interpreter.registerPackagesLoader(path =>
115+
(
116+
path === 'service' ? {
117+
add: (x, y) => x + y,
118+
remove: (x, y) => x - y,
119+
times: (x, y) => x * y,
120+
}
121+
: null
122+
)
123+
);
114124
const scope = {
115125
Math,
116126
errorFunc: p => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jspython-interpreter",
3-
"version": "2.0.18",
3+
"version": "2.1.1",
44
"description": "JSPython is a javascript implementation of Python language that runs within web browser or NodeJS environment",
55
"keywords": [
66
"python",

src/evaluator/evaluatorAsync.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ import { BlockContext, cloneContext, Scope } from './scope';
1818
export class EvaluatorAsync {
1919

2020
private moduleParser: (modulePath: string) => Promise<AstBlock> = () => Promise.reject('Module parser is not registered!');
21-
private blockContextFactory?: (modulePath: string) => BlockContext;
21+
private blockContextFactory?: (modulePath: string, ast: AstBlock) => BlockContext;
2222

2323
registerModuleParser(moduleParser: (modulePath: string) => Promise<AstBlock>): EvaluatorAsync {
2424
this.moduleParser = moduleParser;
2525
return this;
2626
}
2727

28-
registerBlockContextFactory(blockContextFactory: (modulePath: string) => BlockContext): EvaluatorAsync {
28+
registerBlockContextFactory(blockContextFactory: (modulePath: string, ast: AstBlock) => BlockContext): EvaluatorAsync {
2929
this.blockContextFactory = blockContextFactory;
3030
return this;
3131
}
@@ -51,12 +51,17 @@ export class EvaluatorAsync {
5151
if (node.type === 'import') {
5252
const importNode = node as ImportNode;
5353

54+
if(!importNode.module.name.startsWith('/') /* || !importNode.module.name.endsWith('.jspy')*/){
55+
// it is not JSPY imort. It is JS and should be handled externally
56+
continue;
57+
}
58+
5459
if (typeof this.blockContextFactory !== 'function') {
5560
throw new Error('blockContextFactory is not initialized');
5661
}
5762

5863
const moduleAst = await this.moduleParser(importNode.module.name)
59-
const moduleBlockContext = this.blockContextFactory(importNode.module.name);
64+
const moduleBlockContext = this.blockContextFactory(importNode.module.name, moduleAst);
6065
await this.evalBlockAsync(moduleAst, moduleBlockContext)
6166

6267
blockContext.blockScope.set(importNode.module.alias || this.defaultModuleName(importNode.module.name), moduleBlockContext.blockScope.getScope())

src/initialScope.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { parseDatetimeOrNull } from "./common/utils";
22

33
export const INITIAL_SCOPE = {
44
jsPython(): string {
5-
return [`JSPython v2.0.17`, "(c) 2021 FalconSoft Ltd. All rights reserved."].join('\n')
5+
return [`JSPython v2.1.1`, "(c) 2021 FalconSoft Ltd. All rights reserved."].join('\n')
66
},
77
dateTime: (str: number | string | any = null) => parseDatetimeOrNull(str) || new Date(),
88
range: range,

src/interpreter.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,5 +676,42 @@ describe('Interpreter', () => {
676676
expect(res).toBe(316);
677677
});
678678

679+
it('Import with package loader', async () => {
680+
const interpreter = Interpreter.create();
681+
682+
interpreter.registerPackagesLoader(path =>
683+
(
684+
path === 'service' ? {
685+
add: (x, y) => x + y,
686+
remove: (x, y) => x - y,
687+
times: (x, y) => x * y,
688+
}
689+
: null
690+
)
691+
);
692+
693+
interpreter.registerModuleLoader((path => {
694+
return Promise.resolve(`
695+
from 'service' import add
696+
697+
def multiply(x, y):
698+
x * y
699+
700+
def func1(x, y):
701+
add(x, y) + someNumber
702+
703+
someNumber = 55
704+
`);
705+
}));
706+
707+
const res = await interpreter.evaluate(`
708+
import '/service.jspy' as obj
709+
710+
return obj.func1(2, 3)
711+
`);
712+
713+
expect(res).toBe(60);
714+
});
715+
679716

680717
});

src/interpreter.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,16 @@ export class Interpreter {
9393
this._lastExecutionContext = blockContext.blockScope.getScope();
9494

9595
const result = await evaluator
96-
.registerModuleParser(async (modulePath)=> await this.moduleParser(modulePath))
97-
.registerBlockContextFactory((moduleName) => ({ moduleName, blockScope: new Scope(scope) }))
96+
.registerModuleParser(async (modulePath) => await this.moduleParser(modulePath))
97+
.registerBlockContextFactory((moduleName, ast: AstBlock) => {
98+
// this line will not be required when we have move package loaders to the evaluator
99+
const newContext = this.assignLegacyImportContext(ast, scope);
100+
101+
const moduleContext = { moduleName, blockScope: new Scope(newContext) }
102+
moduleContext.blockScope.set('printExecutionContext', () => console.log(moduleContext.blockScope.getScope()));
103+
moduleContext.blockScope.set('getExecutionContext', () => moduleContext.blockScope.getScope());
104+
return moduleContext;
105+
})
98106
.evalBlockAsync(ast, blockContext);
99107

100108
if (!entryFunctionName || !entryFunctionName.length) {
@@ -117,7 +125,7 @@ export class Interpreter {
117125
const ast = this.parse(script, moduleName);
118126

119127
context = (context && typeof context === 'object') ? context : {};
120-
context = await this.assignLegacyImportContext(ast, context);
128+
context = this.assignLegacyImportContext(ast, context);
121129

122130
const globalScope = {
123131
...this.initialScope,
@@ -128,7 +136,7 @@ export class Interpreter {
128136
}
129137

130138

131-
private async assignLegacyImportContext(ast: AstBlock, context: object): Promise<object> {
139+
private assignLegacyImportContext(ast: AstBlock, context: object): Record<string, unknown> {
132140
const importNodes = ast.body.filter(n => n.type === 'import') as ImportNode[];
133141

134142
const jsImport = importNodes
@@ -140,7 +148,7 @@ export class Interpreter {
140148
context = { ...context, ...libraries };
141149
}
142150

143-
return context;
151+
return context as Record<string, unknown>;
144152
}
145153

146154
registerPackagesLoader(loader: PackageLoader) {

0 commit comments

Comments
 (0)