Skip to content
This repository was archived by the owner on Nov 12, 2025. It is now read-only.

Commit cc8ad43

Browse files
committed
Add try/catch. Fix preprocessor ordering
* Fixed ordering of preprocessor replacements since haxe's Maps do not have a defined order and since there's no OrderedMap, used an array that points to map keys. * Added try / catch. Transpiles to xpcall in lua. * Reverted binary operator switch. We're gonna try and keep this backwards compatible I guess. * All instructions will be prefixed with instr_ from now on to avoid syntax errors in both haxe and compiled C++.
1 parent a1ea0fe commit cc8ad43

6 files changed

Lines changed: 111 additions & 65 deletions

File tree

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ Normal is a type that came before ``number``, however nobody uses it and it just
1818

1919
### No inputs
2020
For obvious reasons, there's no io or entities in this as this is meant to be run in the browser, or simply on your pc.
21-
22-
### Fixed bitwise operators
23-
E2 randomly swapped || and | / & and &&. && was made into bitwise and rather than logical and.
24-
*It has been switched to match typical language spec. *
25-
2621
### Optimized
2722
The language is optimized for speed. E2 was known to be very slow, and this is no longer the case through typing and other optimizations.
2823
*Although, admittedly Haxe is nowhere near the best language for trying to get something to be fast.

script.e2

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,10 @@ switch (Var) {
2222
default,
2323
print("this won't")
2424
break
25+
}
26+
27+
try {
28+
error("Hello world")
29+
} catch(Err) {
30+
print(Err)
2531
}

src/Base/Parser.hx

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class Parser {
324324

325325
function acceptIfElseIf() {
326326
if (this.acceptRoamingToken("keyword", "elseif"))
327-
return this.instruction( this.getTokenTrace(), "_if", [this.acceptCondition(), this.acceptBlock("else if condition"), true, this.acceptIfElseIf()] );
327+
return this.instruction( this.getTokenTrace(), "if", [this.acceptCondition(), this.acceptBlock("else if condition"), true, this.acceptIfElseIf()] );
328328

329329
return this.acceptIfElse();
330330
}
@@ -523,7 +523,7 @@ class Parser {
523523
function stmt1() {
524524
if (this.acceptRoamingToken("keyword", "if")) {
525525
var trace = this.getTokenTrace();
526-
return this.instruction( trace, "_if", [this.acceptCondition(), this.acceptBlock("if condition"), false, this.acceptIfElseIf()] );
526+
return this.instruction( trace, "if", [this.acceptCondition(), this.acceptBlock("if condition"), false, this.acceptIfElseIf()] );
527527
}
528528
return this.stmt2();
529529
}
@@ -532,7 +532,7 @@ class Parser {
532532
if (this.acceptRoamingToken("keyword", "while")) {
533533
var trace = this.getTokenTrace();
534534
this.depth++;
535-
var whl = this.instruction( trace, "_while", [this.acceptCondition(), this.acceptBlock("while condition"), false] );
535+
var whl = this.instruction( trace, "while", [this.acceptCondition(), this.acceptBlock("while condition"), false] );
536536
this.depth--;
537537
return whl;
538538
}
@@ -570,7 +570,7 @@ class Parser {
570570
if (!this.acceptRoamingToken("grammar", ")"))
571571
this.error("Right parenthesis ()) missing, to close condition");
572572

573-
var sfor = this.instruction( trace, "_for", [v, estart, estop, estep, this.acceptBlock("for statement")] );
573+
var sfor = this.instruction( trace, "for", [v, estart, estop, estep, this.acceptBlock("for statement")] );
574574

575575
this.depth--;
576576
return sfor;
@@ -649,14 +649,14 @@ class Parser {
649649
if (this.acceptRoamingToken("keyword", "break")) {
650650
if (this.depth > 0) {
651651
var trace = this.getTokenTrace();
652-
return this.instruction(trace, "_break", []);
652+
return this.instruction(trace, "break", []);
653653
} else {
654654
this.error("Break may not exist outside of a loop");
655655
}
656656
} else if (this.acceptRoamingToken("keyword", "continue")) {
657657
if (this.depth > 0) {
658658
var trace = this.getTokenTrace();
659-
return this.instruction(trace, "_continue", []);
659+
return this.instruction(trace, "continue", []);
660660
} else {
661661
this.error("Continue may not exist outside of a loop");
662662
}
@@ -784,7 +784,7 @@ class Parser {
784784
var cases = this.acceptSwitchBlock();
785785
this.depth--;
786786

787-
return this.instruction(trace, "_switch", [expr, cases]);
787+
return this.instruction(trace, "switch", [expr, cases]);
788788
}
789789

790790
return stmt10();
@@ -882,14 +882,14 @@ class Parser {
882882

883883
// TODO: Make sure you can't overwrite existing functions with the signature.
884884

885-
return this.instruction( trace, "function_decl", [name, ret, type, sig, args, this.acceptBlock("function declaration")] );
885+
return this.instruction( trace, "fndecl", [name, ret, type, sig, args, this.acceptBlock("function declaration")] );
886886
} else if ( this.acceptRoamingToken("keyword", "return") ) {
887887
var trace = this.getTokenTrace();
888888

889889
if ( this.acceptRoamingToken("type", "void") || (this.readtoken != null && this.readtoken.raw == "}" /* check if readtoken is rcb */ ) )
890-
return this.instruction( trace, "_return", [] );
890+
return this.instruction( trace, "return", [] );
891891

892-
return this.instruction( trace, "_return", [this.expr1()] );
892+
return this.instruction( trace, "return", [this.expr1()] );
893893
} else if ( this.acceptRoamingToken("type", "void") ) {
894894
this.error("Void may only exist after return");
895895
}
@@ -910,10 +910,42 @@ class Parser {
910910

911911
var condition = this.acceptCondition();
912912

913-
final instr = this.instruction( trace, "_while", [condition, block, true] );
913+
final instr = this.instruction( trace, "while", [condition, block, true] );
914914
this.depth--;
915915
return instr;
916916
}
917+
return stmt12();
918+
}
919+
920+
/**
921+
* ```
922+
* try {
923+
* error("hi")
924+
* } catch(Err) {
925+
* print(Err)
926+
* }
927+
**/
928+
function stmt12(): Instruction {
929+
if (this.acceptRoamingToken("keyword", "try")) {
930+
var trace = this.getTokenTrace();
931+
var stmt = this.acceptBlock("try block");
932+
933+
if (!this.acceptRoamingToken("keyword", "catch"))
934+
this.error("Try block must be followed by catch statement");
935+
936+
if (!this.acceptRoamingToken("grammar", "("))
937+
this.error("Left parenthesis (() expected after catch keyword");
938+
939+
if (!this.acceptRoamingToken("identifier"))
940+
this.error("Variable expected after left parenthesis (() in catch statement");
941+
942+
var var_name = this.getTokenRaw();
943+
944+
if (!this.acceptRoamingToken("grammar", ")"))
945+
this.error("Right parenthesis ()) missing, to close catch statement");
946+
947+
return this.instruction(trace, "try", [stmt, var_name, this.acceptBlock("catch block")] );
948+
}
917949
return expr1();
918950
}
919951

@@ -962,12 +994,12 @@ class Parser {
962994
return expr;
963995
}
964996

965-
// We flipped the binary ops back to normal programming style.
966-
// || is logical OR, | is bitwise.
967-
function expr3() return this.recurseLeftOp(this.expr4, ["|"], ["bor"]); // bitwise or
968-
function expr4() return this.recurseLeftOp(this.expr5, ["&"], ["band"]); // bitwise and
969-
function expr5() return this.recurseLeftOp(this.expr6, ["||"], ["or"]); // logical or
970-
function expr6() return this.recurseLeftOp(this.expr7, ["&&"], ["and"]); // logical and
997+
// Yes, || and && are swapped. They should be logical ops but they are binary ops.
998+
// We're trying to keep parity with E2, so this will be kept.
999+
function expr3() return this.recurseLeftOp(this.expr4, ["||"], ["bor"]); // bitwise or
1000+
function expr4() return this.recurseLeftOp(this.expr5, ["&&"], ["band"]); // bitwise and
1001+
function expr5() return this.recurseLeftOp(this.expr6, ["|"], ["or"]); // logical or
1002+
function expr6() return this.recurseLeftOp(this.expr7, ["&"], ["and"]); // logical and
9711003
function expr7() return this.recurseLeftOp(this.expr8, ["^^"], ["xor"]); // binary xor
9721004
function expr8() return this.recurseLeftOp(this.expr9, ["==", "!="], ["eq", "neq"]);
9731005
function expr9() return this.recurseLeftOp(this.expr10, [">", "<", ">=", "<="], ["gt", "lt", "geq", "leq"]);

src/Base/Preprocessor.hx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,29 @@ private function FILL_WHITESPACE(x: EReg) {
1111
* You can modify the regexes to your needs but by default will remove comments & directives.
1212
*/
1313
class Preprocessor {
14-
var repl: Map<EReg, (EReg)->String>;
14+
var repl: Map<EReg, (EReg)->String> = [];
15+
var repl_order: Array<EReg> = [];
16+
var repl_order_index: UInt = 0;
1517

1618
public function process(script: String) {
1719
var processed = script;
1820

19-
for (regex => with in repl)
20-
processed = regex.map( processed, with );
21+
for (regex in repl_order)
22+
processed = regex.map( processed, this.repl[regex] );
2123

2224
return processed;
2325
}
2426

27+
public function add_replacement(regex: EReg, with: (EReg)->String) {
28+
// Haxe is dying with optionals for me so I can't have an override for repl_order_index. :/
29+
this.repl_order[repl_order_index] = regex;
30+
this.repl_order_index++;
31+
this.repl[regex] = with;
32+
}
33+
2534
public function new() {
26-
final repl = [
27-
~/#\[[\s\S]*\]#/g => FILL_WHITESPACE, // Single-line comment
28-
~/#[^\n]*/g => FILL_WHITESPACE, // Multiline
29-
~/@[^\n]*/g => FILL_WHITESPACE // Directive
30-
];
31-
this.repl = repl;
35+
this.add_replacement( ~/#\[[\s\S]*\]#/g, FILL_WHITESPACE ); // Multiline comment
36+
this.add_replacement( ~/#[^\n]*/g, FILL_WHITESPACE ); // Single line comment
37+
this.add_replacement( ~/@[^\n]*/g, FILL_WHITESPACE ); // Directive
3238
}
3339
}

src/Base/Transpiler/Lua.hx

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ var IN_SWITCH: Bool = false;
1515

1616
@:keep
1717
class Instructions {
18-
static function root(instrs: Array<Instruction>) {
18+
static function instr_root(instrs: Array<Instruction>) {
1919
var out = [];
2020
for (instr in instrs)
2121
out.push( callInstruction(instr.name, instr.args) );
2222
return out.join('\n\n').replaceAll("\t\n", '');
2323
}
2424

25-
static function call(name: String, kvargs: Map<Dynamic, Instruction>, iargs: Array<Instruction>) {
25+
static function instr_call(name: String, kvargs: Map<Dynamic, Instruction>, iargs: Array<Instruction>) {
2626
var args = [];
2727
if (iargs != null) {
2828
// Function was called with arguments
@@ -35,13 +35,13 @@ class Instructions {
3535
return '$name()';
3636
}
3737

38-
static function methodcall(meta_fname: String, meta_obj: Instruction, iargs: Array<Instruction>)
38+
static function instr_methodcall(meta_fname: String, meta_obj: Instruction, iargs: Array<Instruction>)
3939
return '${ callInline(meta_obj) }:$meta_fname(${ (iargs!=null) ? iargs.map(x -> callInline(x)).join(", ") : '' })';
4040

41-
static function literal(value: E2Type, raw: String)
41+
static function instr_literal(value: E2Type, raw: String)
4242
return raw;
4343

44-
static function _if(cond: Instruction, block: Instruction, is_elseif: Bool, ifeif: Instruction) {
44+
static function instr_if(cond: Instruction, block: Instruction, is_elseif: Bool, ifeif: Instruction) {
4545
if (is_elseif) {
4646
return 'is_elseif';
4747
}
@@ -68,7 +68,7 @@ class Instructions {
6868
'end [${ ifeif != null ? callBlock(ifeif, false) : "" }]';*/
6969
}
7070

71-
static function _for(varname: String, start: Instruction, end: Instruction, ?inc: Instruction, block: Instruction) {
71+
static function instr_for(varname: String, start: Instruction, end: Instruction, ?inc: Instruction, block: Instruction) {
7272
final startv = callInline(start);
7373
final endv = callInline(end);
7474

@@ -80,14 +80,14 @@ class Instructions {
8080
+ 'end';
8181
}
8282

83-
static function foreach(keyname: String, ?keytype: String, valname: String, valtype: String, tblexpr: Instruction, block: Instruction) {
83+
static function instr_foreach(keyname: String, ?keytype: String, valname: String, valtype: String, tblexpr: Instruction, block: Instruction) {
8484
return 'for $keyname, $valname in pairs(${ callInline(tblexpr) }) do\n' +
8585
'\t${callBlock(block, true)}\n' +
8686
'\t::continue::\n' +
8787
'end';
8888
}
8989

90-
static function _while(cond: Instruction, block: Instruction, is_dowhile: Bool) {
90+
static function instr_while(cond: Instruction, block: Instruction, is_dowhile: Bool) {
9191
if (is_dowhile) {
9292
// Not using a repeat until
9393
return 'while true do\n' +
@@ -102,10 +102,10 @@ class Instructions {
102102
'end';
103103
}
104104

105-
static function variable(name: String)
105+
static function instr_variable(name: String)
106106
return name;
107107

108-
static function _switch(topexpr: Instruction, cases: Array<{?match: Instruction, block: Instruction}>) {
108+
static function instr_switch(topexpr: Instruction, cases: Array<{?match: Instruction, block: Instruction}>) {
109109
IN_SWITCH = true;
110110
var topvar = callInline(topexpr);
111111

@@ -126,65 +126,73 @@ class Instructions {
126126
return out;
127127
}
128128

129-
static function _break()
129+
static function instr_break()
130130
return IN_SWITCH ? '' : "break";
131131

132-
static function _continue()
132+
static function instr_continue()
133133
return 'goto continue';
134134

135-
static function _return(val: Instruction)
135+
static function instr_return(val: Instruction)
136136
return 'return ${ callInline(val) }';
137137

138-
static function increment(varname: String)
138+
static function instr_increment(varname: String)
139139
return '$varname = $varname + 1';
140140

141-
static function decrement(varname: String)
141+
static function instr_decrement(varname: String)
142142
return '$varname = $varname - 1';
143143

144-
static function add(v: Instruction, addend: Instruction)
144+
static function instr_add(v: Instruction, addend: Instruction)
145145
return '${ callInline(v) } + ${ callInline(addend) }';
146146

147-
static function sub(v: Instruction, addend: Instruction)
147+
static function instr_sub(v: Instruction, addend: Instruction)
148148
return '${ callInline(v) } - ${ callInline(addend) }';
149149

150-
static function div(v: Instruction, addend: Instruction)
150+
static function instr_div(v: Instruction, addend: Instruction)
151151
return '${ callInline(v) } / ${ callInline(addend) }';
152152

153-
static function mul(v: Instruction, addend: Instruction)
153+
static function instr_mul(v: Instruction, addend: Instruction)
154154
return '${ callInline(v) } * ${ callInline(addend) }';
155155

156-
static function assign(varname: String, to: Instruction)
157-
return '$varname = ${ callInline(to) }';
158-
159-
static function eq(v1: Instruction, v2: Instruction)
156+
static function instr_eq(v1: Instruction, v2: Instruction)
160157
return '${ callInline(v1) } == ${ callInline(v2) }';
161158

162-
static function neq(v1: Instruction, v2: Instruction)
159+
static function instr_neq(v1: Instruction, v2: Instruction)
163160
return '${ callInline(v1) } ~= ${ callInline(v2) }';
164161

165-
static function leq(v1: Instruction, v2: Instruction)
162+
static function instr_leq(v1: Instruction, v2: Instruction)
166163
return '${ callInline(v1) } <= ${ callInline(v2) }';
167164

168-
static function geq(v1: Instruction, v2: Instruction)
165+
static function instr_geq(v1: Instruction, v2: Instruction)
169166
return '${ callInline(v1) } >= ${ callInline(v2) }';
170167

171-
static function grouped_equation(v1: Instruction)
168+
static function instr_grouped_equation(v1: Instruction)
172169
return '(${ callInline(v1) })';
173170

174-
static function assignlocal(varname: String, to: Instruction)
171+
static function instr_assign(varname: String, to: Instruction)
172+
return '$varname = ${ callInline(to) }';
173+
174+
static function instr_assignlocal(varname: String, to: Instruction)
175175
return 'local $varname = ${ callInline(to) }';
176176

177-
static function function_decl(name: String, ret_type: String, meta_type: String, sig: String, args: Array<{name: String, type: String}>, decl: Instruction) {
177+
static function instr_fndecl(name: String, ret_type: String, meta_type: String, sig: String, args: Array<{name: String, type: String}>, decl: Instruction) {
178178
return 'function ${(meta_type != null) ? '${meta_type}_' : ''}$name(${ args.map( (v) -> v.name ).join(", ") })\n' +
179179
'\t${ callBlock(decl, true) }\n' +
180180
'end';
181181
}
182182

183-
static function ternary(cond: Instruction, success: Instruction, fallback: Instruction)
183+
static function instr_ternary(cond: Instruction, success: Instruction, fallback: Instruction)
184184
return '${ callInline(cond) } and ${ callInline(success) } or ${ callInline(fallback) }';
185185

186+
static function instr_try(block: Instruction, var_name: String, catch_block: Instruction) {
187+
return 'xpcall(function()\n' +
188+
'\t${ callBlock(block, true) }\n' +
189+
'end, function($var_name)\n' +
190+
'\t${ callBlock(catch_block, true) }\n' +
191+
'end)';
192+
}
193+
186194
// Bitwise ops
187-
static function bor(v1: Instruction, v2: Instruction) {
195+
static function instr_bor(v1: Instruction, v2: Instruction) {
188196
#if LUA54
189197
return '${ callInline(v1) } | ${ callInline(v2) }';
190198
#else
@@ -195,6 +203,8 @@ class Instructions {
195203

196204
// Expr -> Lua
197205
function callInstruction(name: String, args: Array<Dynamic>): String {
206+
var name = 'instr_' + name;
207+
198208
if(!Reflect.hasField(Instructions, name))
199209
throw new NotImplementedException('Instruction ["$name"] does not exist.');
200210

tests/utest/Tokenizer.hx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@ class Tokenizer extends Test {
2020
/**
2121
* Make sure we properly get the literal number value out of a basic operation.
2222
*/
23-
/*
24-
Haxe/utest is fucking stupid 👍
2523
public function testLiteralNumber() {
2624
final tokens = this.tokenizer.process(this.script);
2725
Assert.equals( E2Type.Number(212), tokens[2].literal );
2826
}
29-
*/
3027
}

0 commit comments

Comments
 (0)