Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7276653

Browse filesBrowse files
committed
Merge branch 'master' into docusaurus
# Conflicts: # README.md
2 parents 6891909 + c8ef825 commit 7276653
Copy full SHA for 7276653

File tree

Expand file treeCollapse file tree

6 files changed

+119
-72
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+119
-72
lines changed

‎index.html

Copy file name to clipboardExpand all lines: index.html
+2-5Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,8 @@
2828
<div class="container">
2929
<h4>JSPython development console</h4>
3030
<div id="editor">
31-
issue = {}
32-
tt = {ss: "sss"}
33-
issue["dd" + tt.ss] = "333sss"
34-
issue
35-
</div>
31+
x = """issue = {}"""
32+
x</div>
3633
<button onclick="runInterpreter()">Run</button>
3734
<textarea id="result"></textarea>
3835
</div>

‎package.json

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

‎src/eval/eval.expression.ts

Copy file name to clipboardExpand all lines: src/eval/eval.expression.ts
+32-26Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ function isFunctionCall(str: string): boolean {
1414

1515
function isValue(t: string): boolean {
1616
const lowerToken = t.toLowerCase();
17-
return (t[0] === '"' && t[t.length - 1] === '"')
17+
const result = (t[0] === '"' && t[t.length - 1] === '"')
1818
|| lowerToken === 'true' || lowerToken === 'false'
1919
|| lowerToken === 'null' || lowerToken === 'none'
2020
|| !isNaN(parseFloat(t))
2121
|| (t[0] === '[' && t[t.length - 1] === ']')
2222
|| (t[0] === '{' && t[t.length - 1] === '}');
23+
return result;
2324
}
2425

2526
async function invokeFunctionAsync(func: AnyFunc, fps: any[]): Promise<any> {
@@ -91,28 +92,28 @@ export class EvalExpression {
9192

9293
private jsonParse(context: BlockContext, json: string): any {
9394
const result: any = json[0] === '{' ? {} : [];
94-
95+
9596
function trimFirstAndLastItem(s: string): string {
9697
return s.substring(1, s.length - 1);
9798
}
98-
99-
const resolveEndValue = (str : string) : any => {
99+
100+
const resolveEndValue = (str: string): any => {
100101
const tokens = this.splitParameterToken(str);
101102
return this.evalExpression(context, tokens)
102103
}
103-
104+
104105
function parseJsonItems(innerJson: string, parentObj: any) {
105106
const items = Tokenizer.splitAll(innerJson, [',']).map(s => s.trim());
106-
107+
107108
for (const item of items) {
108-
109+
109110
if (Array.isArray(parentObj)) {
110111
// handle array
111112
if (item[0] === '{') {
112113
const newItem = {}
113114
parseJsonItems(trimFirstAndLastItem(item), newItem)
114115
parentObj.push(newItem)
115-
} else if (item[0] === '['){
116+
} else if (item[0] === '[') {
116117
const newItem = {}
117118
parseJsonItems(trimFirstAndLastItem(item), newItem)
118119
parentObj.push(newItem)
@@ -125,10 +126,10 @@ export class EvalExpression {
125126
if (sepInd <= 0) {
126127
throw Error('Error in parsing JSON.');
127128
}
128-
129+
129130
const key = item.substring(0, sepInd).trim()
130131
const strValue = item.substring(sepInd + 1).trim()
131-
132+
132133
if (strValue[0] === '{') {
133134
parentObj[key] = {};
134135
parseJsonItems(trimFirstAndLastItem(strValue), parentObj[key])
@@ -141,36 +142,36 @@ export class EvalExpression {
141142
}
142143
}
143144
};
144-
145+
145146
parseJsonItems(trimFirstAndLastItem(json), result);
146-
147+
147148
return result;
148149
}
149150

150151
private async jsonParseAsync(context: BlockContext, json: string): Promise<any> {
151152
const result: any = json[0] === '{' ? {} : [];
152-
153+
153154
function trimFirstAndLastItem(s: string): string {
154155
return s.substring(1, s.length - 1);
155156
}
156-
157-
const resolveEndValue = async (str : string) : Promise<any> => {
157+
158+
const resolveEndValue = async (str: string): Promise<any> => {
158159
const tokens = this.splitParameterToken(str);
159160
return await this.evalExpressionAsync(context, tokens)
160161
}
161-
162+
162163
async function parseJsonItemsAsync(innerJson: string, parentObj: any): Promise<void> {
163164
const items = Tokenizer.splitAll(innerJson, [',']).map(s => s.trim());
164-
165+
165166
for (const item of items) {
166-
167+
167168
if (Array.isArray(parentObj)) {
168169
// handle array
169170
if (item[0] === '{') {
170171
const newItem = {}
171172
await parseJsonItemsAsync(trimFirstAndLastItem(item), newItem)
172173
parentObj.push(newItem)
173-
} else if (item[0] === '['){
174+
} else if (item[0] === '[') {
174175
const newItem = {}
175176
await parseJsonItemsAsync(trimFirstAndLastItem(item), newItem)
176177
parentObj.push(newItem)
@@ -183,10 +184,10 @@ export class EvalExpression {
183184
if (sepInd <= 0) {
184185
throw Error('Error in parsing JSON.');
185186
}
186-
187+
187188
const key = item.substring(0, sepInd).trim()
188189
const strValue = item.substring(sepInd + 1).trim()
189-
190+
190191
if (strValue[0] === '{') {
191192
parentObj[key] = {};
192193
await parseJsonItemsAsync(trimFirstAndLastItem(strValue), parentObj[key])
@@ -199,15 +200,18 @@ export class EvalExpression {
199200
}
200201
}
201202
};
202-
203+
203204
await parseJsonItemsAsync(trimFirstAndLastItem(json), result);
204-
205+
205206
return result;
206207
}
207-
208+
208209
private resolveValue(context: BlockContext, token: string): any {
209210
const lowerToken = token.toLowerCase();
210-
if (token[0] === '"' && token[token.length - 1] === '"') {
211+
212+
if (token.startsWith('"""') && token.endsWith('"""')) {
213+
return token.substring(3, token.length - 3);
214+
} else if (token[0] === '"' && token[token.length - 1] === '"') {
211215
return token.substring(1, token.length - 1);
212216
} else if ((token[0] === '[' && token[token.length - 1] === ']') || (token[0] === '{' && token[token.length - 1] === '}')) {
213217
return this.jsonParse(context, token);
@@ -224,7 +228,9 @@ export class EvalExpression {
224228

225229
private async resolveValueAsync(context: BlockContext, token: string): Promise<any> {
226230
const lowerToken = token.toLowerCase();
227-
if (token[0] === '"' && token[token.length - 1] === '"') {
231+
if (token.startsWith('"""') && token.endsWith('"""')) {
232+
return token.substring(3, token.length - 3);
233+
} else if (token[0] === '"' && token[token.length - 1] === '"') {
228234
return token.substring(1, token.length - 1);
229235
} else if ((token[0] === '[' && token[token.length - 1] === ']') || (token[0] === '{' && token[token.length - 1] === '}')) {
230236
return await this.jsonParseAsync(context, token);

‎src/interpreter.spec.ts

Copy file name to clipboardExpand all lines: src/interpreter.spec.ts
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,32 @@ describe('Interpreter', () => {
2020
expect(r).toBe(88);
2121
});
2222

23+
it('Triple quote string as Comment', async () => {
24+
const text = `
25+
1
26+
2 3 4
27+
5
28+
`;
29+
expect(await e.evaluate('""" 12345 """')).toBe(' 12345 ');
30+
expect(await e.evaluate(`"""${text}"""`)).toBe(text);
31+
});
32+
33+
it('Triple quote string as an expression', async () => {
34+
const text = `
35+
1
36+
2 3 4
37+
5
38+
`;
39+
expect(await e.evaluate(`
40+
str = """ 12345 """
41+
str
42+
`)).toBe(' 12345 ');
43+
expect(await e.evaluate(`
44+
str = """${text}"""
45+
str
46+
`)).toBe(text);
47+
});
48+
2349
it('print(add(33, 2))', async () => {
2450
expect(await e.evaluate('print(add(33, 2, 45))'))
2551
.toBe(80);

‎src/interpreter.ts

Copy file name to clipboardExpand all lines: src/interpreter.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Tokenizer, CodeLine, PackageToImport } from './tokenizer';
22
import {
33
BlockContext, AnyFunc,
4-
EvalCodeBlock, EvalInstruction, EvalExpression, getLineIndent, sliceBlock, parseDatetimeOrNull
4+
EvalCodeBlock, EvalInstruction, EvalExpression, parseDatetimeOrNull
55
} from './eval/index';
66

77
export { PackageToImport } from './tokenizer';
@@ -21,7 +21,7 @@ function range(start: number, stop: number = NaN, step: number = 1): number[] {
2121

2222
const INITIAL_SCOPE = {
2323
jsPython(): string {
24-
return ["JSPython v0.1.2", "(c) FalconSoft Ltd"].join('\n')
24+
return ["JSPython v0.1.3", "(c) FalconSoft Ltd"].join('\n')
2525
},
2626
dateTime: (str: number | string | any = null) => (str && str.length)
2727
? parseDatetimeOrNull(str) || new Date() : new Date(),

‎src/tokenizer.ts

Copy file name to clipboardExpand all lines: src/tokenizer.ts
+56-38Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ export interface CodeLine {
66
}
77

88
export interface PackageToImport {
9-
name: string;
10-
properties?: {name: string, as?: string}[];
11-
as?: string;
9+
name: string;
10+
properties?: { name: string, as?: string }[];
11+
as?: string;
1212
}
1313

14-
15-
1614
const WHITE_SPACES = [' ', '\n', '\t', '\r', '\0'];
1715

1816
export class Tokenizer {
@@ -90,12 +88,32 @@ export class Tokenizer {
9088
* @param chr
9189
*/
9290
function iterateString(chr: string): void {
91+
const getChar = (str: string, strIndex: number): string => (strIndex < str.length) ? str[strIndex] : '';
92+
const isTripleQuoteFollowed = () => text[index] === stringChar && getChar(text, index + 1) === stringChar;
93+
const isTripleQuoteStr = isTripleQuoteFollowed();
94+
95+
if (isTripleQuoteStr) {
96+
appendToken(chr);
97+
chr = nextChar();
98+
appendToken(chr);
99+
chr = nextChar();
100+
}
101+
93102
do {
94103
appendToken(chr);
95104
chr = nextChar();
96105

97106
if (chr === stringChar) {
98-
break;
107+
if (isTripleQuoteStr) {
108+
if (isTripleQuoteFollowed()) {
109+
nextChar(); nextChar()
110+
appendToken(`""`);
111+
break;
112+
}
113+
114+
} else {
115+
break;
116+
}
99117
}
100118
}
101119
while (index < text.length);
@@ -162,16 +180,16 @@ export class Tokenizer {
162180
return result;
163181
}
164182

165-
static getPackagesList(importLines: Array<CodeLine|string> = []): PackageToImport[] {
166-
return importLines.map((codeLine) => {
167-
const line = typeof codeLine === 'string' ? codeLine : codeLine.line;
168-
if (line.startsWith('import')) {
169-
return getImportPackage(line);
170-
} else {
171-
return getFromPacakage(line);
172-
}
173-
});
174-
}
183+
static getPackagesList(importLines: Array<CodeLine | string> = []): PackageToImport[] {
184+
return importLines.map((codeLine) => {
185+
const line = typeof codeLine === 'string' ? codeLine : codeLine.line;
186+
if (line.startsWith('import')) {
187+
return getImportPackage(line);
188+
} else {
189+
return getFromPacakage(line);
190+
}
191+
});
192+
}
175193

176194
}
177195

@@ -181,16 +199,16 @@ export class Tokenizer {
181199
* @private
182200
*/
183201
function getImportPackage(line: string): PackageToImport {
184-
const importRe = /^import\s+([\w-]+)(\s+as\s+(\w+)){0,1}/;
185-
const res = line.match(importRe);
202+
const importRe = /^import\s+([\w-]+)(\s+as\s+(\w+)){0,1}/;
203+
const res = line.match(importRe);
186204
if (res && res.length === 4) {
187-
return {
188-
name: res[1],
189-
as: res[3]
190-
}
205+
return {
206+
name: res[1],
207+
as: res[3]
208+
}
191209
} else {
192-
throw Error(`Bad import for line: ${line}`);
193-
}
210+
throw Error(`Bad import for line: ${line}`);
211+
}
194212
}
195213

196214
/**
@@ -199,19 +217,19 @@ function getImportPackage(line: string): PackageToImport {
199217
* @private
200218
*/
201219
function getFromPacakage(line: string): PackageToImport {
202-
const fromRe = /^from\s+([\w-]+)\s+import\s+([\w+,\s+]{1,})/;
203-
const res = line.match(fromRe);
204-
if (res && res.length === 3) {
205-
return {
206-
name: res[1],
207-
properties: res[2].split(',').map(propStr => {
208-
const prop = propStr.split('as');
209-
const name = prop[0].trim();
210-
const as = prop.length > 1 ? prop[1].trim() : undefined;
211-
return { name, as }
212-
})
220+
const fromRe = /^from\s+([\w-]+)\s+import\s+([\w+,\s+]{1,})/;
221+
const res = line.match(fromRe);
222+
if (res && res.length === 3) {
223+
return {
224+
name: res[1],
225+
properties: res[2].split(',').map(propStr => {
226+
const prop = propStr.split('as');
227+
const name = prop[0].trim();
228+
const as = prop.length > 1 ? prop[1].trim() : undefined;
229+
return { name, as }
230+
})
231+
}
232+
} else {
233+
throw Error(`Bad import for line: ${line}`);
213234
}
214-
} else {
215-
throw Error(`Bad import for line: ${line}`);
216-
}
217235
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.