Skip to content

Commit e0d178e

Browse files
PavloPavlo
authored andcommitted
insulated module scope.
1 parent c59afe9 commit e0d178e

File tree

5 files changed

+89
-16
lines changed

5 files changed

+89
-16
lines changed

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.1.1",
3+
"version": "2.1.2",
44
"description": "JSPython is a javascript implementation of Python language that runs within web browser or NodeJS environment",
55
"keywords": [
66
"python",

src/evaluator/evaluator.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,28 @@ export class Evaluator {
114114
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9]);
115115
}
116116

117-
if (fps.length > 10) {
117+
if (fps.length === 11) {
118+
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10]);
119+
}
120+
121+
if (fps.length === 12) {
122+
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11]);
123+
}
124+
125+
if (fps.length === 13) {
126+
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12]);
127+
}
128+
129+
if (fps.length === 14) {
130+
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12], fps[13]);
131+
}
132+
133+
if (fps.length === 15) {
134+
return func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12], fps[13], fps[14]);
135+
}
136+
137+
138+
if (fps.length > 15) {
118139
throw Error('Function has too many parameters. Current limitation is 10');
119140
}
120141

src/evaluator/evaluatorAsync.ts

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ 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')*/){
54+
if (!importNode.module.name.startsWith('/') /* || !importNode.module.name.endsWith('.jspy')*/) {
5555
// it is not JSPY imort. It is JS and should be handled externally
5656
continue;
5757
}
@@ -60,12 +60,19 @@ export class EvaluatorAsync {
6060
throw new Error('blockContextFactory is not initialized');
6161
}
6262

63-
const moduleAst = await this.moduleParser(importNode.module.name)
63+
const moduleAst = await this.moduleParser(importNode.module.name);
6464
const moduleBlockContext = this.blockContextFactory(importNode.module.name, moduleAst);
65-
await this.evalBlockAsync(moduleAst, moduleBlockContext)
65+
await this.evalBlockAsync(moduleAst, moduleBlockContext);
6666

67-
blockContext.blockScope.set(importNode.module.alias || this.defaultModuleName(importNode.module.name), moduleBlockContext.blockScope.getScope())
67+
let scope = blockContext.blockScope.getScope();
6868

69+
if (!importNode.parts?.length) {
70+
// if no parts, then we need to assign to a separate object
71+
scope = {};
72+
blockContext.blockScope.set(importNode.module.alias || this.defaultModuleName(importNode.module.name), scope);
73+
}
74+
75+
this.assignFunctionsToScope(scope, moduleBlockContext, moduleAst, importNode.parts?.map(p => p.name));
6976
continue;
7077
}
7178

@@ -102,6 +109,22 @@ export class EvaluatorAsync {
102109
return lastResult;
103110
}
104111

112+
private assignFunctionsToScope(scope: Record<string, unknown>, moduleBlockContext: BlockContext,
113+
moduleAst: AstBlock, parts?: string[]): void {
114+
115+
const funcs = moduleAst.funcs.filter(f => !parts || parts.indexOf(f.funcAst?.name) >= 0);
116+
117+
for (let i = 0; i < funcs.length; i++) {
118+
const funcDef = funcs[i] as FunctionDefNode;
119+
120+
const invoker = (funcDef.isAsync) ?
121+
async (...args: unknown[]): Promise<unknown> => await this.jspyFuncInvokerAsync(funcDef, moduleBlockContext, ...args)
122+
: (...args: unknown[]): unknown => new Evaluator().jspyFuncInvoker(funcDef, moduleBlockContext, ...args);
123+
124+
scope[funcDef.funcAst.name] = invoker;
125+
}
126+
}
127+
105128
private defaultModuleName(name: string): string {
106129
return name.substring(name.lastIndexOf('/') + 1, name.lastIndexOf('.'))
107130
}
@@ -156,7 +179,27 @@ export class EvaluatorAsync {
156179
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9]);
157180
}
158181

159-
if (fps.length > 10) {
182+
if (fps.length === 11) {
183+
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10]);
184+
}
185+
186+
if (fps.length === 12) {
187+
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11]);
188+
}
189+
190+
if (fps.length === 13) {
191+
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12]);
192+
}
193+
194+
if (fps.length === 14) {
195+
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12], fps[13]);
196+
}
197+
198+
if (fps.length === 15) {
199+
return await func(fps[0], fps[1], fps[2], fps[3], fps[4], fps[5], fps[6], fps[7], fps[8], fps[9], fps[10], fps[11], fps[12], fps[13], fps[14]);
200+
}
201+
202+
if (fps.length > 15) {
160203
throw Error('Function has too many parameters. Current limitation is 10');
161204
}
162205
}

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.1.1`, "(c) 2021 FalconSoft Ltd. All rights reserved."].join('\n')
5+
return [`JSPython v2.1.2`, "(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: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -644,10 +644,10 @@ describe('Interpreter', () => {
644644
const res = await interpreter.evaluate(`
645645
import '/service.jspy' as obj
646646
647-
return obj.func1(2, 3) + obj.multiply(2, 3) + obj.someNumber
647+
return obj.func1(2, 3) + obj.multiply(2, 3)
648648
`);
649649

650-
expect(res).toBe(122);
650+
expect(res).toBe(67);
651651
});
652652

653653

@@ -670,10 +670,10 @@ describe('Interpreter', () => {
670670
const res = await interpreter.evaluate(`
671671
import '/service.jspy' as obj
672672
673-
return obj.func1(2) + obj.multiply(2, 3) + obj.someNumber
673+
return obj.func1(2) + obj.multiply(2, 3)
674674
`);
675675

676-
expect(res).toBe(316);
676+
expect(res).toBe(261);
677677
});
678678

679679
it('Import with package loader', async () => {
@@ -682,9 +682,9 @@ describe('Interpreter', () => {
682682
interpreter.registerPackagesLoader(path =>
683683
(
684684
path === 'service' ? {
685-
add: (x, y) => x + y,
686-
remove: (x, y) => x - y,
687-
times: (x, y) => x * y,
685+
add: (x: number, y: number) => x + y,
686+
remove: (x: number, y: number) => x - y,
687+
times: (x: number, y: number) => x * y,
688688
}
689689
: null
690690
)
@@ -704,13 +704,22 @@ describe('Interpreter', () => {
704704
`);
705705
}));
706706

707-
const res = await interpreter.evaluate(`
707+
let res = await interpreter.evaluate(`
708708
import '/service.jspy' as obj
709709
710710
return obj.func1(2, 3)
711711
`);
712712

713713
expect(res).toBe(60);
714+
715+
res = await interpreter.evaluate(`
716+
from '/service.jspy' import func1
717+
718+
return func1(2, 3)
719+
`);
720+
721+
expect(res).toBe(60);
722+
714723
});
715724

716725

0 commit comments

Comments
 (0)