Skip to content

Commit 5c8771e

Browse files
committed
3 files modified, 13 added, 1 deleted
1 parent 5fd26f1 commit 5c8771e

17 files changed

+1869
-12
lines changed

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"dependencies": {
66
"@types/react": "18.2.21",
77
"@types/react-dom": "18.2.7",
8+
"mathjs": "^11.11.0",
89
"react": "18.2.0",
910
"react-dom": "18.2.0"
1011
},
@@ -18,4 +19,4 @@
1819
"devDependencies": {
1920
"react-scripts": "latest"
2021
}
21-
}
22+
}

src/Main.tsx

-5
This file was deleted.

src/components/Main.tsx

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React, { useState } from "react";
2+
import parse from "../parser";
3+
4+
export default function App(): React.ReactElement {
5+
const [currentExpression, setCurrentExpression] = useState("");
6+
7+
return (
8+
<>
9+
<input value={currentExpression} onChange={e => setCurrentExpression(e.target.value)} />
10+
<div className="output">{parse(currentExpression)}</div>
11+
</>
12+
);
13+
}

src/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from "react";
22
import ReactDOM from "react-dom/client";
3-
import App from "@components/Main";
3+
import App from "./components/Main";
44

5-
ReactDOM.createRoot(document.getElementById("#app")!).render(
5+
ReactDOM.createRoot(document.querySelector("#app")!).render(
66
<React.StrictMode>
77
<App />
88
</React.StrictMode>

src/jsep/assignment.d.ts

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as jsep from "jsep";
2+
import { Expression, IPlugin } from "jsep";
3+
export const name: string;
4+
export const assignmentOperators: Set<string>;
5+
export const updateOperators: number[];
6+
export const assignmentPrecedence: number;
7+
export const PLUS_CODE: number;
8+
export const MINUS_CODE: number;
9+
export function init(this: typeof jsep): void;
10+
11+
export interface UpdateExpression extends Expression {
12+
type: "UpdateExpression";
13+
operator: "++" | "--";
14+
argument: Expression;
15+
prefix: boolean;
16+
}
17+
18+
export interface AssignmentExpression extends Expression {
19+
type: "AssignmentExpression";
20+
operator:
21+
| "="
22+
| "*="
23+
| "**="
24+
| "/="
25+
| "%="
26+
| "+="
27+
| "-="
28+
| "<<="
29+
| ">>="
30+
| ">>>="
31+
| "&="
32+
| "^="
33+
| "|=";
34+
left: Expression;
35+
right: Expression;
36+
}
37+
38+
declare const _export: IPlugin;
39+
export default _export;

src/jsep/assignment.js

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
export const PLUS_CODE = 43; // +
2+
export const MINUS_CODE = 45; // -
3+
4+
const plugin = {
5+
name: 'assignment',
6+
7+
assignmentOperators: new Set([
8+
'=',
9+
'*=',
10+
'**=',
11+
'/=',
12+
'%=',
13+
'+=',
14+
'-=',
15+
'<<=',
16+
'>>=',
17+
'>>>=',
18+
'&=',
19+
'^=',
20+
'|=',
21+
]),
22+
updateOperators: [PLUS_CODE, MINUS_CODE],
23+
assignmentPrecedence: 0.9,
24+
25+
init(jsep) {
26+
const updateNodeTypes = [jsep.IDENTIFIER, jsep.MEMBER_EXP];
27+
plugin.assignmentOperators.forEach(op => jsep.addBinaryOp(op, plugin.assignmentPrecedence, true));
28+
29+
jsep.hooks.add('gobble-token', function gobbleUpdatePrefix(env) {
30+
const code = this.code;
31+
if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) {
32+
this.index += 2;
33+
env.node = {
34+
type: 'UpdateExpression',
35+
operator: code === PLUS_CODE ? '++' : '--',
36+
argument: this.gobbleTokenProperty(this.gobbleIdentifier()),
37+
prefix: true,
38+
};
39+
if (!env.node.argument || !updateNodeTypes.includes(env.node.argument.type)) {
40+
this.throwError(`Unexpected ${env.node.operator}`);
41+
}
42+
}
43+
});
44+
45+
jsep.hooks.add('after-token', function gobbleUpdatePostfix(env) {
46+
if (env.node) {
47+
const code = this.code;
48+
if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) {
49+
if (!updateNodeTypes.includes(env.node.type)) {
50+
this.throwError(`Unexpected ${env.node.operator}`);
51+
}
52+
this.index += 2;
53+
env.node = {
54+
type: 'UpdateExpression',
55+
operator: code === PLUS_CODE ? '++' : '--',
56+
argument: env.node,
57+
prefix: false,
58+
};
59+
}
60+
}
61+
});
62+
63+
jsep.hooks.add('after-expression', function gobbleAssignment(env) {
64+
if (env.node) {
65+
// Note: Binaries can be chained in a single expression to respect
66+
// operator precedence (i.e. a = b = 1 + 2 + 3)
67+
// Update all binary assignment nodes in the tree
68+
updateBinariesToAssignments(env.node);
69+
}
70+
});
71+
72+
function updateBinariesToAssignments(node) {
73+
if (plugin.assignmentOperators.has(node.operator)) {
74+
node.type = 'AssignmentExpression';
75+
updateBinariesToAssignments(node.left);
76+
updateBinariesToAssignments(node.right);
77+
}
78+
else if (!node.operator) {
79+
Object.values(node).forEach((val) => {
80+
if (val && typeof val === 'object') {
81+
updateBinariesToAssignments(val);
82+
}
83+
});
84+
}
85+
}
86+
},
87+
};
88+
export default plugin;

src/jsep/comment.d.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import * as jsep from "jsep";
2+
import { IPlugin } from "jsep";
3+
export const name: string;
4+
export const FSLSH_CODE: number;
5+
export const ASTSK_CODE: number;
6+
export function init(this: typeof jsep): void;
7+
8+
declare const _export: IPlugin;
9+
export default _export;

src/jsep/comment.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export const FSLSH_CODE = 47; // /
2+
export const ASTSK_CODE = 42; // *
3+
4+
export default {
5+
name: "comment",
6+
7+
init(jsep) {
8+
// treat all comments as whitespace to remove from parsing
9+
jsep.hooks.add("gobble-spaces", function gobbleComment() {
10+
if (this.code === FSLSH_CODE) {
11+
let ch = this.expr.charCodeAt(this.index + 1);
12+
if (ch === FSLSH_CODE) {
13+
// '//': read to end of line/input
14+
this.index += 1;
15+
while (ch !== jsep.LF_CODE && !isNaN(ch)) {
16+
ch = this.expr.charCodeAt(++this.index);
17+
}
18+
this.gobbleSpaces();
19+
} else if (ch === ASTSK_CODE) {
20+
// read to */ or end of input
21+
this.index += 2;
22+
while (!isNaN(ch)) {
23+
ch = this.expr.charCodeAt(this.index++);
24+
if (ch === ASTSK_CODE) {
25+
ch = this.expr.charCodeAt(this.index++);
26+
if (ch === FSLSH_CODE) {
27+
this.gobbleSpaces();
28+
return;
29+
}
30+
}
31+
}
32+
33+
// missing closing */
34+
this.throwError("Missing closing comment, */");
35+
}
36+
}
37+
});
38+
},
39+
};

src/jsep/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import jsep from "./jsep.js";
2+
3+
export const jsep = jsep;
4+
export default jsep;

0 commit comments

Comments
 (0)