epoxylang 0.1.5 → 0.1.7

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.
@@ -0,0 +1,8 @@
1
+ assign name = "satya";
2
+
3
+ @js{
4
+ let age = 18;
5
+ }
6
+
7
+ store msg = `my name is [name] and i'm [age] years old.`;
8
+ show msg;
package/examples/test.epx CHANGED
@@ -1,15 +1,9 @@
1
- assign okay as string;
2
- update okay = "satya";
3
- show okay;
4
-
5
- all assign hello as array = {"satya0", "satya1", "satya2"};
6
- show hello{0};
7
-
8
- assign numbers as array = {1, 2, 3, 4, 5, 6};
9
-
1
+ assign numbers as array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
10
2
  repeat[i in 0 to 5, 1]{
11
3
  assign n as int = numbers{i};
12
- check [(n / 2 == 1) or (n / 2 == 2) or (n / 2 == 3)] {
13
- show n;
4
+ @js {
5
+ if(n % 2 == 0){
6
+ console.log(n);
7
+ }
14
8
  }
15
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epoxylang",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "epoxy": "./bin/epoxy.js"
@@ -19,6 +19,8 @@ class JSCodeGenerator {
19
19
  return this.visitAssignStatement(node);
20
20
  case "UpdateStatement":
21
21
  return this.visitUpdateStatement(node);
22
+ case "RawJSBlock":
23
+ return this.visitRawJSBlock(node);
22
24
  case "BinaryExpression": return this.visitBinaryExpression(node);
23
25
  case "Literal": return this.visitLiteral(node);
24
26
  case "Identifier": return this.visitIdentifier(node);
@@ -63,6 +65,11 @@ class JSCodeGenerator {
63
65
  return `${node.name} = ${value};`;
64
66
  }
65
67
 
68
+ visitRawJSBlock(node) {
69
+ // Return the raw JavaScript code as-is
70
+ return node.code;
71
+ }
72
+
66
73
  visitBinaryExpression(node) {
67
74
  const left = this.visit(node.left);
68
75
  const right = this.visit(node.right);
@@ -87,6 +87,55 @@ class Lexer {
87
87
  });
88
88
  }
89
89
 
90
+ readJSBlock() {
91
+ // We're at '@', check if next chars are 'js{'
92
+ this.advance(); // skip '@'
93
+
94
+ // Read 'js'
95
+ if (this.current !== 'j') {
96
+ throw new Error("Expected 'js' after '@'");
97
+ }
98
+ this.advance();
99
+
100
+ if (this.current !== 's') {
101
+ throw new Error("Expected 'js' after '@'");
102
+ }
103
+ this.advance();
104
+
105
+ // Skip any whitespace before {
106
+ this.skipWhitespace();
107
+
108
+ if (this.current !== '{') {
109
+ throw new Error("Expected '{' after '@js'");
110
+ }
111
+ this.advance(); // skip '{'
112
+
113
+ // Capture everything until matching '}'
114
+ let code = "";
115
+ let braceDepth = 1;
116
+
117
+ while (this.current && braceDepth > 0) {
118
+ if (this.current === '{') {
119
+ braceDepth++;
120
+ } else if (this.current === '}') {
121
+ braceDepth--;
122
+ if (braceDepth === 0) {
123
+ break; // Don't include the closing brace
124
+ }
125
+ }
126
+ code += this.current;
127
+ this.advance();
128
+ }
129
+
130
+ if (braceDepth !== 0) {
131
+ throw new Error("Unmatched braces in @js block");
132
+ }
133
+
134
+ this.advance(); // skip final '}'
135
+
136
+ return new Token(TokenType.JSBLOCK, code);
137
+ }
138
+
90
139
  getNextToken() {
91
140
  while (this.current) {
92
141
  if (/\s/.test(this.current)) {
@@ -102,6 +151,9 @@ class Lexer {
102
151
  continue;
103
152
  }
104
153
 
154
+ // @js blocks for raw JavaScript
155
+ if (this.current === "@") return this.readJSBlock();
156
+
105
157
  if (/[0-9]/.test(this.current)) return this.readNumber();
106
158
  if (/[a-zA-Z_]/.test(this.current)) return this.readWord();
107
159
  if (`'"\``.includes(this.current)) return this.readString();
@@ -31,6 +31,9 @@ const TokenType = {
31
31
 
32
32
  IDENTIFIER: "IDENTIFIER",
33
33
 
34
+ // raw javascript
35
+ JSBLOCK: "JSBLOCK",
36
+
34
37
  // operators
35
38
  EQUAL: "EQUAL",
36
39
  PLUS: "PLUS",
package/src/parser/ast.js CHANGED
@@ -131,6 +131,13 @@ class RepeatFor {
131
131
  }
132
132
  }
133
133
 
134
+ class RawJSBlock {
135
+ constructor(code) {
136
+ this.type = "RawJSBlock";
137
+ this.code = code;
138
+ }
139
+ }
140
+
134
141
  export {
135
142
  Program,
136
143
  AssignStatement,
@@ -147,5 +154,6 @@ export {
147
154
  CallExpression,
148
155
  RepeatUntil,
149
156
  ShowStatement,
150
- RepeatFor
157
+ RepeatFor,
158
+ RawJSBlock
151
159
  };
@@ -14,7 +14,8 @@ import {
14
14
  CallExpression,
15
15
  RepeatUntil,
16
16
  ShowStatement,
17
- RepeatFor
17
+ RepeatFor,
18
+ RawJSBlock
18
19
  } from "./ast.js";
19
20
 
20
21
  class Parser {
@@ -84,6 +85,7 @@ class Parser {
84
85
  }
85
86
 
86
87
  if (t === TokenType.UPDATE) return this.parseUpdate();
88
+ if (t === TokenType.JSBLOCK) return this.parseJSBlock();
87
89
  if (t === TokenType.CHECK) return this.parseCheck();
88
90
  if (t === TokenType.MAKE) return this.parseMake();
89
91
  if (t === TokenType.CALL) return this.parseCall();
@@ -205,6 +207,12 @@ class Parser {
205
207
  return new UpdateStatement({ name, value });
206
208
  }
207
209
 
210
+ parseJSBlock() {
211
+ const code = this.current().value;
212
+ this.eat(TokenType.JSBLOCK);
213
+ return new RawJSBlock(code);
214
+ }
215
+
208
216
  parseValue() {
209
217
  const token = this.current();
210
218
 
File without changes