epoxylang 0.1.8 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin/epoxy.js +1 -1
- package/examples/hybrid.epx +18 -6
- package/examples/test.epx +4 -9
- package/package.json +4 -1
- package/src/generator/jsgenerator.js +5 -0
- package/src/lexer/lexer.js +26 -3
- package/src/lexer/tokens.js +1 -0
- package/src/parser/ast.js +8 -1
- package/src/parser/parser.js +8 -1
- package/src/runtime/runner.js +24 -1
- package/src/test.js +28 -5
package/README.md
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#experimenting right now.. <!not stable>
|
package/bin/epoxy.js
CHANGED
package/examples/hybrid.epx
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
show "Please enter a number and press enter, five times";
|
|
2
|
+
assign numbers as array = {};
|
|
3
|
+
repeat[x in 0 to 4, 1]{
|
|
4
|
+
show "Enter a number: ";
|
|
5
|
+
assign num_insert = :input;
|
|
6
|
+
@js :~
|
|
7
|
+
numbers.push(num_insert);
|
|
8
|
+
~:
|
|
9
|
+
}
|
|
10
|
+
show "The numbers you entered are: " + numbers;
|
|
11
|
+
repeat[i in numbers]{
|
|
12
|
+
assign n as int = numbers{i};
|
|
13
|
+
@js :~
|
|
14
|
+
if(n % 2 == 0){
|
|
15
|
+
console.log(n);
|
|
16
|
+
}
|
|
17
|
+
~:
|
|
18
|
+
}
|
package/examples/test.epx
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
assign
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
if(n % 2 == 0){
|
|
6
|
-
console.log(n);
|
|
7
|
-
}
|
|
8
|
-
~
|
|
9
|
-
}
|
|
1
|
+
assign name = "satya";
|
|
2
|
+
assign age = 18;
|
|
3
|
+
store msg = `my name is [name] and i'm [age] years old.`;
|
|
4
|
+
show msg;
|
package/package.json
CHANGED
|
@@ -24,6 +24,7 @@ class JSCodeGenerator {
|
|
|
24
24
|
case "BinaryExpression": return this.visitBinaryExpression(node);
|
|
25
25
|
case "Literal": return this.visitLiteral(node);
|
|
26
26
|
case "Identifier": return this.visitIdentifier(node);
|
|
27
|
+
case "InputExpression": return this.visitInputExpression(node);
|
|
27
28
|
case "StoreStatement": return this.visitStoreStatement(node);
|
|
28
29
|
case "ShowStatement": return this.visitShowStatement(node);
|
|
29
30
|
case "FunctionDeclaration": return this.visitFunctionDeclaration(node);
|
|
@@ -89,6 +90,10 @@ class JSCodeGenerator {
|
|
|
89
90
|
return node.name;
|
|
90
91
|
}
|
|
91
92
|
|
|
93
|
+
visitInputExpression(node) {
|
|
94
|
+
return "await input_of_epoxy_lang_dont_use_this_name()";
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
convertInterpolation(text) {
|
|
93
98
|
let result = "";
|
|
94
99
|
let i = 0;
|
package/src/lexer/lexer.js
CHANGED
|
@@ -104,6 +104,10 @@ class Lexer {
|
|
|
104
104
|
|
|
105
105
|
// Skip any whitespace before ~
|
|
106
106
|
this.skipWhitespace();
|
|
107
|
+
if (this.current !== ':') {
|
|
108
|
+
throw new Error("Expected ':' after '@js'");
|
|
109
|
+
}
|
|
110
|
+
this.advance();
|
|
107
111
|
|
|
108
112
|
if (this.current !== '~') {
|
|
109
113
|
throw new Error("Expected '~' after '@js'");
|
|
@@ -113,16 +117,17 @@ class Lexer {
|
|
|
113
117
|
// Capture everything until closing '~'
|
|
114
118
|
let code = "";
|
|
115
119
|
|
|
116
|
-
while (this.current && this.current !== '~') {
|
|
120
|
+
while (this.current && this.current !== '~' && this.peek !== ':') {
|
|
117
121
|
code += this.current;
|
|
118
122
|
this.advance();
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
if (this.current !== '~') {
|
|
122
|
-
throw new Error("Unterminated @js block - missing closing '
|
|
125
|
+
if (this.current !== '~' && this.peek !== ':') {
|
|
126
|
+
throw new Error("Unterminated @js block - missing closing '~:'");
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
this.advance(); // skip closing '~'
|
|
130
|
+
this.advance(); // skip closing ':'
|
|
126
131
|
|
|
127
132
|
return new Token(TokenType.JSBLOCK, code);
|
|
128
133
|
}
|
|
@@ -149,6 +154,24 @@ class Lexer {
|
|
|
149
154
|
if (/[a-zA-Z_]/.test(this.current)) return this.readWord();
|
|
150
155
|
if (`'"\``.includes(this.current)) return this.readString();
|
|
151
156
|
|
|
157
|
+
// :input special syntax
|
|
158
|
+
if (this.current === ":" && this.peek() === "i") {
|
|
159
|
+
// Check if it's ":input"
|
|
160
|
+
const saved = this.pos;
|
|
161
|
+
this.advance(); // skip ':'
|
|
162
|
+
let word = "";
|
|
163
|
+
while (this.current && /[a-zA-Z_]/.test(this.current)) {
|
|
164
|
+
word += this.current;
|
|
165
|
+
this.advance();
|
|
166
|
+
}
|
|
167
|
+
if (word === "input") {
|
|
168
|
+
return new Token(TokenType.INPUT);
|
|
169
|
+
}
|
|
170
|
+
// Not :input, restore position
|
|
171
|
+
this.pos = saved;
|
|
172
|
+
this.current = this.input[this.pos];
|
|
173
|
+
}
|
|
174
|
+
|
|
152
175
|
// double-char operators
|
|
153
176
|
const twoChar = this.current + this.peek();
|
|
154
177
|
if (twoChar === "==") { this.advance(); this.advance(); return new Token(TokenType.EQEQ); }
|
package/src/lexer/tokens.js
CHANGED
package/src/parser/ast.js
CHANGED
|
@@ -139,6 +139,12 @@ class RawJSBlock {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
class InputExpression {
|
|
143
|
+
constructor() {
|
|
144
|
+
this.type = "InputExpression";
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
142
148
|
export {
|
|
143
149
|
Program,
|
|
144
150
|
AssignStatement,
|
|
@@ -156,5 +162,6 @@ export {
|
|
|
156
162
|
RepeatUntil,
|
|
157
163
|
ShowStatement,
|
|
158
164
|
RepeatFor,
|
|
159
|
-
RawJSBlock
|
|
165
|
+
RawJSBlock,
|
|
166
|
+
InputExpression
|
|
160
167
|
};
|
package/src/parser/parser.js
CHANGED
|
@@ -15,7 +15,8 @@ import {
|
|
|
15
15
|
RepeatUntil,
|
|
16
16
|
ShowStatement,
|
|
17
17
|
RepeatFor,
|
|
18
|
-
RawJSBlock
|
|
18
|
+
RawJSBlock,
|
|
19
|
+
InputExpression
|
|
19
20
|
} from "./ast.js";
|
|
20
21
|
|
|
21
22
|
class Parser {
|
|
@@ -272,6 +273,12 @@ class Parser {
|
|
|
272
273
|
return new Literal(tok.value);
|
|
273
274
|
}
|
|
274
275
|
|
|
276
|
+
// :input special value
|
|
277
|
+
if (tok.type === TokenType.INPUT) {
|
|
278
|
+
this.pos++;
|
|
279
|
+
return new InputExpression();
|
|
280
|
+
}
|
|
281
|
+
|
|
275
282
|
// call expression
|
|
276
283
|
if (tok.type === TokenType.CALL) {
|
|
277
284
|
this.eat(TokenType.CALL);
|
package/src/runtime/runner.js
CHANGED
|
@@ -23,7 +23,30 @@ function compile(code) {
|
|
|
23
23
|
|
|
24
24
|
function run(code) {
|
|
25
25
|
const js = compile(code);
|
|
26
|
-
|
|
26
|
+
const finalcode_input = `
|
|
27
|
+
let buffer_of_epoxy_lang_dont_use_this_name = "";
|
|
28
|
+
let resolvers_of_epoxy_lang_dont_use_this_name = [];
|
|
29
|
+
process.stdin.setEncoding("utf8");
|
|
30
|
+
process.stdin.on("data", chunk => {
|
|
31
|
+
buffer_of_epoxy_lang_dont_use_this_name += chunk;
|
|
32
|
+
while (buffer_of_epoxy_lang_dont_use_this_name.includes("\\n") && resolvers_of_epoxy_lang_dont_use_this_name.length > 0) {
|
|
33
|
+
const line = buffer_of_epoxy_lang_dont_use_this_name.slice(0, buffer_of_epoxy_lang_dont_use_this_name.indexOf("\\n")).trim();
|
|
34
|
+
buffer_of_epoxy_lang_dont_use_this_name = buffer_of_epoxy_lang_dont_use_this_name.slice(buffer_of_epoxy_lang_dont_use_this_name.indexOf("\\n") + 1);
|
|
35
|
+
const resolve_of_epoxy_lang_dont_use_this_name = resolvers_of_epoxy_lang_dont_use_this_name.shift();
|
|
36
|
+
resolve_of_epoxy_lang_dont_use_this_name(line);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
function input_of_epoxy_lang_dont_use_this_name() {
|
|
40
|
+
return new Promise(resolve => {
|
|
41
|
+
resolvers_of_epoxy_lang_dont_use_this_name.push(resolve);
|
|
42
|
+
})}
|
|
43
|
+
async function main_of_epoxy_lang_dont_use_this_name() {
|
|
44
|
+
${js}
|
|
45
|
+
process.stdin.pause();
|
|
46
|
+
}
|
|
47
|
+
main_of_epoxy_lang_dont_use_this_name();`;
|
|
48
|
+
const thisisthecode = js.includes("input_of_epoxy_lang_dont_use_this_name()") ? finalcode_input : js;
|
|
49
|
+
return eval(thisisthecode);
|
|
27
50
|
}
|
|
28
51
|
|
|
29
52
|
export { tokenizeAll, compile, run };
|
package/src/test.js
CHANGED
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { compile } from './index.js';
|
|
2
2
|
import { readFileSync } from 'fs';
|
|
3
3
|
console.log("=== Testing test.epx ===");
|
|
4
|
-
const
|
|
4
|
+
const inputfile = readFileSync('./examples/square.epx', 'utf-8');
|
|
5
5
|
console.log("Epoxy code:");
|
|
6
|
-
console.log(
|
|
6
|
+
console.log(inputfile);
|
|
7
7
|
console.log("\nCompiled JavaScript:");
|
|
8
|
-
const
|
|
9
|
-
|
|
8
|
+
const epx_to_js_raw = compile(inputfile);
|
|
9
|
+
const finalcode_input = `
|
|
10
|
+
let buffer_of_epoxy_lang_dont_use_this_name = "";
|
|
11
|
+
let resolvers_of_epoxy_lang_dont_use_this_name = [];
|
|
12
|
+
process.stdin.setEncoding("utf8");
|
|
13
|
+
process.stdin.on("data", chunk => {
|
|
14
|
+
buffer_of_epoxy_lang_dont_use_this_name += chunk;
|
|
15
|
+
while (buffer_of_epoxy_lang_dont_use_this_name.includes("\\n") && resolvers_of_epoxy_lang_dont_use_this_name.length > 0) {
|
|
16
|
+
const line = buffer_of_epoxy_lang_dont_use_this_name.slice(0, buffer_of_epoxy_lang_dont_use_this_name.indexOf("\\n")).trim();
|
|
17
|
+
buffer_of_epoxy_lang_dont_use_this_name = buffer_of_epoxy_lang_dont_use_this_name.slice(buffer_of_epoxy_lang_dont_use_this_name.indexOf("\\n") + 1);
|
|
18
|
+
const resolve_of_epoxy_lang_dont_use_this_name = resolvers_of_epoxy_lang_dont_use_this_name.shift();
|
|
19
|
+
resolve_of_epoxy_lang_dont_use_this_name(line);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
function input_of_epoxy_lang_dont_use_this_name() {
|
|
23
|
+
return new Promise(resolve => {
|
|
24
|
+
resolvers_of_epoxy_lang_dont_use_this_name.push(resolve);
|
|
25
|
+
})}
|
|
26
|
+
async function main_of_epoxy_lang_dont_use_this_name() {
|
|
27
|
+
${epx_to_js_raw}
|
|
28
|
+
process.stdin.pause();
|
|
29
|
+
}
|
|
30
|
+
main_of_epoxy_lang_dont_use_this_name();`;
|
|
31
|
+
const thisisthecode = epx_to_js_raw.includes("input_of_epoxy_lang_dont_use_this_name()") ? finalcode_input : epx_to_js_raw;
|
|
32
|
+
console.log(thisisthecode);
|
|
10
33
|
console.log("\nRunning JavaScript:");
|
|
11
|
-
eval(
|
|
34
|
+
eval(thisisthecode);
|