Added new, throw, try/catch, hex numbers and ... operator support
This commit is contained in:
@@ -49,6 +49,9 @@ enum Expr {
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr> );
|
||||
ENew( cl : String, params : Array<Expr> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, ecatch : Expr );
|
||||
}
|
||||
|
||||
enum Error {
|
||||
|
||||
+58
-20
@@ -40,6 +40,7 @@ class Interp {
|
||||
|
||||
public function new() {
|
||||
locals = new Hash();
|
||||
declared = new Array();
|
||||
variables = new Hash();
|
||||
variables.set("null",null);
|
||||
variables.set("true",true);
|
||||
@@ -70,6 +71,7 @@ class Interp {
|
||||
binops.set("||",function(e1,e2) return me.expr(e1) == true || me.expr(e2) == true);
|
||||
binops.set("&&",function(e1,e2) return me.expr(e1) == true && me.expr(e2) == true);
|
||||
binops.set("=",assign);
|
||||
binops.set("...",function(e1,e2) return new IntIter(me.expr(e1),me.expr(e2)));
|
||||
assignOp("+=",function(v1:Dynamic,v2:Dynamic) return v1 + v2);
|
||||
assignOp("-=",function(v1:Float,v2:Float) return v1 - v2);
|
||||
assignOp("*=",function(v1:Float,v2:Float) return v1 * v2);
|
||||
@@ -191,16 +193,11 @@ class Interp {
|
||||
return h2;
|
||||
}
|
||||
|
||||
function block( exprs : Array<Expr> ) : Dynamic {
|
||||
var old = declared;
|
||||
declared = new Array();
|
||||
var v = null;
|
||||
for( e in exprs )
|
||||
v = expr(e);
|
||||
for( d in declared )
|
||||
function restore( old : Int ) {
|
||||
while( declared.length > old ) {
|
||||
var d = declared.pop();
|
||||
locals.set(d.n,d.old);
|
||||
declared = old;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
public function expr( e : Expr ) : Dynamic {
|
||||
@@ -220,13 +217,18 @@ class Interp {
|
||||
throw Error.EUnknownVariable(id);
|
||||
return v;
|
||||
case EVar(n,e):
|
||||
declared.unshift({ n : n, old : locals.get(n) });
|
||||
declared.push({ n : n, old : locals.get(n) });
|
||||
locals.set(n,{ r : (e == null)?null:expr(e) });
|
||||
return null;
|
||||
case EParent(e):
|
||||
return expr(e);
|
||||
case EBlock(exprs):
|
||||
return block(exprs);
|
||||
var old = declared.length;
|
||||
var v = null;
|
||||
for( e in exprs )
|
||||
v = expr(e);
|
||||
restore(old);
|
||||
return v;
|
||||
case EField(e,f):
|
||||
return get(expr(e),f);
|
||||
case EBinop(op,e1,e2):
|
||||
@@ -296,14 +298,40 @@ class Interp {
|
||||
return a;
|
||||
case EArray(e,index):
|
||||
return expr(e)[expr(index)];
|
||||
case ENew(cl,params):
|
||||
var a = new Array();
|
||||
for( e in params )
|
||||
a.push(expr(e));
|
||||
return cnew(cl,a);
|
||||
case EThrow(e):
|
||||
throw expr(e);
|
||||
case ETry(e,n,ecatch):
|
||||
var old = declared.length;
|
||||
try {
|
||||
var v : Dynamic = expr(e);
|
||||
restore(old);
|
||||
return v;
|
||||
} catch( err : Stop ) {
|
||||
throw err;
|
||||
} catch( err : Dynamic ) {
|
||||
// restore vars
|
||||
restore(old);
|
||||
// declare 'v'
|
||||
declared.push({ n : n, old : locals.get(n) });
|
||||
locals.set(n,{ r : err });
|
||||
var v : Dynamic = expr(ecatch);
|
||||
restore(old);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function whileLoop(econd,e) {
|
||||
var old = declared.length;
|
||||
while( expr(econd) == true ) {
|
||||
try {
|
||||
block([e]);
|
||||
expr(e);
|
||||
} catch( err : Stop ) {
|
||||
switch(err) {
|
||||
case SContinue:
|
||||
@@ -312,17 +340,23 @@ class Interp {
|
||||
}
|
||||
}
|
||||
}
|
||||
restore(old);
|
||||
}
|
||||
|
||||
function forLoop(v,it,e) {
|
||||
var old = locals.get(v);
|
||||
var it : Dynamic = expr(it);
|
||||
if( it.iterator != null ) it = it.iterator();
|
||||
if( it.hasNext == null || it.next == null ) throw Error.EInvalidIterator(v);
|
||||
function makeIterator( v : Dynamic ) : Iterator<Dynamic> {
|
||||
try v = v.iterator() catch( e : Dynamic ) {};
|
||||
if( v.hasNext == null || v.next == null ) throw Error.EInvalidIterator(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
function forLoop(n,it,e) {
|
||||
var old = declared.length;
|
||||
declared.push({ n : n, old : locals.get(n) });
|
||||
var it = makeIterator(expr(it));
|
||||
while( it.hasNext() ) {
|
||||
locals.set(v,{ r : it.next() });
|
||||
locals.set(n,{ r : it.next() });
|
||||
try {
|
||||
block([e]);
|
||||
expr(e);
|
||||
} catch( err : Stop ) {
|
||||
switch( err ) {
|
||||
case SContinue:
|
||||
@@ -331,7 +365,7 @@ class Interp {
|
||||
}
|
||||
}
|
||||
}
|
||||
locals.set(v,old);
|
||||
restore(old);
|
||||
}
|
||||
|
||||
function get( o : Dynamic, f : String ) : Dynamic {
|
||||
@@ -349,4 +383,8 @@ class Interp {
|
||||
return Reflect.callMethod(o,f,args);
|
||||
}
|
||||
|
||||
function cnew( cl : String, args : Array<Dynamic> ) : Dynamic {
|
||||
return Type.createInstance(Type.resolveClass(cl),args);
|
||||
}
|
||||
|
||||
}
|
||||
+106
-19
@@ -64,6 +64,7 @@ class Parser {
|
||||
opChars = "+*/-=!><&|^%";
|
||||
identChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
|
||||
opPriority = [
|
||||
"...",
|
||||
"=",
|
||||
"||","&&",
|
||||
"==","!=",">","<",">=","<=",
|
||||
@@ -162,7 +163,7 @@ class Parser {
|
||||
var found;
|
||||
for( x in unopsPrefix )
|
||||
if( x == op )
|
||||
return EUnop(op,true,parseExpr(s));
|
||||
return makeUnop(op,parseExpr(s));
|
||||
return unexpected(tk);
|
||||
case TBkOpen:
|
||||
return parseExprNext(s,EArrayDecl(parseExprList(s,TBkClose)));
|
||||
@@ -171,6 +172,29 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
function priority(op) {
|
||||
for( i in 0...opPriority.length )
|
||||
if( opPriority[i] == op )
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
function makeUnop( op, e ) {
|
||||
return switch( e ) {
|
||||
case EBinop(bop,e1,e2): EBinop(bop,makeUnop(op,e1),e2);
|
||||
default: EUnop(op,true,e);
|
||||
}
|
||||
}
|
||||
|
||||
function makeBinop( op, e1, e2 ) {
|
||||
return switch( e2 ) {
|
||||
case EBinop(op2,e2,e3):
|
||||
if( priority(op) > priority(op2) )
|
||||
return EBinop(op2,makeBinop(op,e1,e2),e3);
|
||||
default: EBinop(op,e1,e2);
|
||||
}
|
||||
}
|
||||
|
||||
function parseStructure( s, id ) {
|
||||
return switch( id ) {
|
||||
case "if":
|
||||
@@ -256,17 +280,54 @@ class Parser {
|
||||
var tk = token(s);
|
||||
tokens.add(tk);
|
||||
EReturn(if( tk == TSemicolon ) null else parseExpr(s));
|
||||
default: null;
|
||||
case "new":
|
||||
var a = new Array();
|
||||
var tk = token(s);
|
||||
switch( tk ) {
|
||||
case TId(id): a.push(id);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
while( true ) {
|
||||
tk = token(s);
|
||||
switch( tk ) {
|
||||
case TDot:
|
||||
tk = token(s);
|
||||
switch(tk) {
|
||||
case TId(id): a.push(id);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
case TPOpen:
|
||||
break;
|
||||
default:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
ENew(a.join("."),parseExprList(s,TPClose));
|
||||
case "throw":
|
||||
EThrow( parseExpr(s) );
|
||||
case "try":
|
||||
var e = parseExpr(s);
|
||||
var tk = token(s);
|
||||
if( !Type.enumEq(tk,TId("catch")) ) unexpected(tk);
|
||||
tk = token(s);
|
||||
if( tk != TPOpen ) unexpected(tk);
|
||||
tk = token(s);
|
||||
var vname = switch( tk ) {
|
||||
case TId(id): id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
tk = token(s);
|
||||
if( tk != TDoubleDot ) unexpected(tk);
|
||||
tk = token(s);
|
||||
if( !Type.enumEq(tk,TId("Dynamic")) ) unexpected(tk);
|
||||
tk = token(s);
|
||||
if( tk != TPClose ) unexpected(tk);
|
||||
ETry(e,vname,parseExpr(s));
|
||||
default:
|
||||
null;
|
||||
}
|
||||
}
|
||||
|
||||
function priority(op) {
|
||||
for( i in 0...opPriority.length )
|
||||
if( opPriority[i] == op )
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
function parseExprNext( s : haxe.io.Input, e1 : Expr ) {
|
||||
var tk = token(s);
|
||||
switch( tk ) {
|
||||
@@ -274,14 +335,7 @@ class Parser {
|
||||
for( x in unopsSuffix )
|
||||
if( x == op )
|
||||
return EUnop(op,false,e1);
|
||||
var e2 = parseExpr(s);
|
||||
switch( e2 ) {
|
||||
case EBinop(op2,e2,e3):
|
||||
if( priority(op) > priority(op2) )
|
||||
return EBinop(op2,EBinop(op,e1,e2),e3);
|
||||
default:
|
||||
}
|
||||
return EBinop(op,e1,e2);
|
||||
return makeBinop(op,e1,parseExpr(s));
|
||||
case TDot:
|
||||
tk = token(s);
|
||||
var field = null;
|
||||
@@ -392,9 +446,33 @@ class Parser {
|
||||
case 48,49,50,51,52,53,54,55,56,57:
|
||||
n = n * 10 + (char - 48);
|
||||
case 46:
|
||||
if( exp > 0 )
|
||||
if( exp > 0 ) {
|
||||
// in case of '...'
|
||||
if( exp == 10 && readChar(s) == 46 ) {
|
||||
tokens.add(TOp("..."));
|
||||
return TConst( CInt(n) );
|
||||
}
|
||||
throw Error.EInvalidChar(char);
|
||||
}
|
||||
exp = 1;
|
||||
case 120: // x
|
||||
if( n > 0 || exp > 0 )
|
||||
throw Error.EInvalidChar(char);
|
||||
// read hexa
|
||||
while( true ) {
|
||||
char = readChar(s);
|
||||
switch( char ) {
|
||||
case 48,49,50,51,52,53,54,55,56,57: // 0-9
|
||||
n = (n << 4) + (char - 48);
|
||||
case 65,66,67,68,69,70: // A-F
|
||||
n = (n << 4) + (char - 55);
|
||||
case 97,98,99,100,101,102: // a-f
|
||||
n = (n << 4) + (char - 87);
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst( CInt(n) );
|
||||
}
|
||||
}
|
||||
default:
|
||||
this.char = char;
|
||||
return TConst( (exp > 0) ? CFloat(n * 10 / exp) : CInt(n) );
|
||||
@@ -404,7 +482,16 @@ class Parser {
|
||||
case 40: return TPOpen;
|
||||
case 41: return TPClose;
|
||||
case 44: return TComma;
|
||||
case 46: return TDot;
|
||||
case 46:
|
||||
char = readChar(s);
|
||||
if( char != 46 ) {
|
||||
this.char = char;
|
||||
return TDot;
|
||||
}
|
||||
char = readChar(s);
|
||||
if( char != 46 )
|
||||
throw Error.EInvalidChar(char);
|
||||
return TOp("...");
|
||||
case 123: return TBrOpen;
|
||||
case 125: return TBrClose;
|
||||
case 91: return TBkOpen;
|
||||
|
||||
Reference in New Issue
Block a user