diff --git a/hscript.hxml b/hscript.hxml
index 7027c2a..8b9870c 100644
--- a/hscript.hxml
+++ b/hscript.hxml
@@ -1,5 +1,4 @@
--swf hscript.swf
--swf-version 9
+-swf9 hscript.swf
-swf-header 800:600:30:FFFFFF
--flash-strict
-main Test
diff --git a/hscript.hxproj b/hscript.hxproj
index 32c69f7..ea2de73 100644
--- a/hscript.hxproj
+++ b/hscript.hxproj
@@ -37,7 +37,14 @@
-
+
+
+
+
+
+
+
+
diff --git a/hscript/Bytes.hx b/hscript/Bytes.hx
index 32ad69a..2b499c4 100644
--- a/hscript/Bytes.hx
+++ b/hscript/Bytes.hx
@@ -132,7 +132,7 @@ class Bytes {
doEncodeConst(c);
case EIdent(v):
doEncodeString(v);
- case EVar(n,e):
+ case EVar(n,_,e):
doEncodeString(n);
if( e == null )
bout.addByte(255);
@@ -175,10 +175,10 @@ class Bytes {
doEncode(it);
doEncode(e);
case EBreak, EContinue:
- case EFunction(params,e,name):
+ case EFunction(params,e,name,_):
bout.addByte(params.length);
for( p in params )
- doEncodeString(p);
+ doEncodeString(p.name);
doEncode(e);
doEncodeString(name == null?"":name);
case EReturn(e):
@@ -201,7 +201,7 @@ class Bytes {
doEncode(e);
case EThrow(e):
doEncode(e);
- case ETry(e,v,ecatch):
+ case ETry(e,v,_,ecatch):
doEncode(e);
doEncodeString(v);
doEncode(ecatch);
@@ -214,7 +214,7 @@ class Bytes {
}
}
- function doDecode() {
+ function doDecode() : Expr {
return switch( bin.get(pin++) ) {
case 0:
EConst( doDecodeConst() );
@@ -265,7 +265,7 @@ class Bytes {
case 14:
var params = new Array();
for( i in 0...bin.get(pin++) )
- params.push(doDecodeString());
+ params.push({ name : doDecodeString(), t : null });
var e = doDecode();
var name = doDecodeString();
EFunction(params,e,(name == "") ? null: name);
@@ -290,7 +290,7 @@ class Bytes {
case 20:
var e = doDecode();
var v = doDecodeString();
- ETry(e,v,doDecode());
+ ETry(e,v,null,doDecode());
case 21:
var fl = new Array();
for( i in 0...bin.get(pin++) ) {
diff --git a/hscript/Expr.hx b/hscript/Expr.hx
index 8f4fd2a..b4382f4 100644
--- a/hscript/Expr.hx
+++ b/hscript/Expr.hx
@@ -34,7 +34,7 @@ enum Const {
enum Expr {
EConst( c : Const );
EIdent( v : String );
- EVar( n : String, ?e : Expr );
+ EVar( n : String, ?t : CType, ?e : Expr );
EParent( e : Expr );
EBlock( e : Array );
EField( e : Expr, f : String );
@@ -46,16 +46,23 @@ enum Expr {
EFor( v : String, it : Expr, e : Expr );
EBreak;
EContinue;
- EFunction( params : Array, e : Expr, ?name : String );
+ EFunction( args : Array<{ name : String, t : Null }>, e : Expr, ?name : String, ?ret : CType );
EReturn( ?e : Expr );
EArray( e : Expr, index : Expr );
EArrayDecl( e : Array );
ENew( cl : String, params : Array );
EThrow( e : Expr );
- ETry( e : Expr, v : String, ecatch : Expr );
+ ETry( e : Expr, v : String, t : Null, ecatch : Expr );
EObject( fl : Array<{ name : String, e : Expr }> );
}
+enum CType {
+ CTPath( path : Array, ?params : Array );
+ CTFun( args : Array, ret : CType );
+ CTAnon( fields : Array<{ name : String, t : CType }> );
+ CTParent( t : CType );
+}
+
enum Error {
EInvalidChar( c : Int );
EUnexpected( s : String );
diff --git a/hscript/Interp.hx b/hscript/Interp.hx
index a7cec3b..17231bb 100644
--- a/hscript/Interp.hx
+++ b/hscript/Interp.hx
@@ -218,7 +218,7 @@ class Interp {
if( v == null && !variables.exists(id) )
throw Error.EUnknownVariable(id);
return v;
- case EVar(n,e):
+ case EVar(n,_,e):
declared.push({ n : n, old : locals.get(n) });
locals.set(n,{ r : (e == null)?null:expr(e) });
return null;
@@ -282,7 +282,7 @@ class Interp {
throw SContinue;
case EReturn(e):
throw SReturn((e == null)?null:expr(e));
- case EFunction(params,fexpr,name):
+ case EFunction(params,fexpr,name,_):
var capturedLocals = duplicate(locals);
var me = this;
var f = function(args:Array) {
@@ -290,7 +290,7 @@ class Interp {
var old = me.locals;
me.locals = me.duplicate(capturedLocals);
for( i in 0...params.length )
- me.locals.set(params[i],{ r : args[i] });
+ me.locals.set(params[i].name,{ r : args[i] });
var r = null;
try {
r = me.exprReturn(fexpr);
@@ -323,7 +323,7 @@ class Interp {
return cnew(cl,a);
case EThrow(e):
throw expr(e);
- case ETry(e,n,ecatch):
+ case ETry(e,n,_,ecatch):
var old = declared.length;
try {
var v : Dynamic = expr(e);
diff --git a/hscript/Parser.hx b/hscript/Parser.hx
index c4b596f..fec8c19 100644
--- a/hscript/Parser.hx
+++ b/hscript/Parser.hx
@@ -57,6 +57,11 @@ class Parser {
activate JSON compatiblity
**/
public var allowJSON : Bool;
+
+ /**
+ allow types declarations
+ **/
+ public var allowTypes : Bool;
// implementation
var input : haxe.io.Input;
@@ -103,7 +108,7 @@ class Parser {
while( true ) {
var tk = token();
if( tk == TEof ) break;
- tokens.add(tk);
+ push(tk);
a.push(parseFullExpr());
}
return if( a.length == 1 ) a[0] else EBlock(a);
@@ -113,12 +118,21 @@ class Parser {
throw Error.EUnexpected(tokenString(tk));
return null;
}
+
+ inline function push(tk) {
+ tokens.add(tk);
+ }
+
+ inline function ensure(tk) {
+ var t = token();
+ if( t != tk ) unexpected(t);
+ }
function isBlock(e) {
return switch( e ) {
case EBlock(_), EObject(_): true;
- case EFunction(_,e,_): isBlock(e);
- case EVar(_,e): e != null && isBlock(e);
+ case EFunction(_,e,_,_): isBlock(e);
+ case EVar(_,_,e): e != null && isBlock(e);
case EIf(_,e1,e2): if( e2 != null ) isBlock(e2) else isBlock(e1);
case EBinop(_,_,e): isBlock(e);
case EUnop(_,prefix,e): !prefix && isBlock(e);
@@ -134,7 +148,7 @@ class Parser {
var tk = token();
if( tk != TSemicolon && tk != TEof ) {
if( isBlock(e) )
- tokens.add(tk);
+ push(tk);
else
unexpected(tk);
}
@@ -161,8 +175,7 @@ class Parser {
default:
unexpected(tk);
}
- tk = token();
- if( tk != TDoubleDot ) unexpected(tk);
+ ensure(TDoubleDot);
fl.push({ name : id, e : parseExpr() });
tk = token();
switch( tk ) {
@@ -188,8 +201,7 @@ class Parser {
return parseExprNext(EConst(c));
case TPOpen:
var e = parseExpr();
- tk = token();
- if( tk != TPClose ) unexpected(tk);
+ ensure(TPClose);
return parseExprNext(EParent(e));
case TBrOpen:
tk = token();
@@ -198,8 +210,8 @@ class Parser {
return parseExprNext(EObject([]));
case TId(id):
var tk2 = token();
- tokens.add(tk2);
- tokens.add(tk);
+ push(tk2);
+ push(tk);
switch( tk2 ) {
case TDoubleDot:
return parseExprNext(parseObject());
@@ -210,20 +222,20 @@ class Parser {
switch( c ) {
case CString(_):
var tk2 = token();
- tokens.add(tk2);
- tokens.add(tk);
+ push(tk2);
+ push(tk);
switch( tk2 ) {
case TDoubleDot:
return parseExprNext(parseObject());
default:
}
default:
- tokens.add(tk);
+ push(tk);
}
} else
- tokens.add(tk);
+ push(tk);
default:
- tokens.add(tk);
+ push(tk);
}
var a = new Array();
while( true ) {
@@ -231,7 +243,7 @@ class Parser {
tk = token();
if( tk == TBrClose )
break;
- tokens.add(tk);
+ push(tk);
}
return EBlock(a);
case TOp(op):
@@ -244,7 +256,7 @@ class Parser {
var a = new Array();
tk = token();
while( tk != TBkClose ) {
- tokens.add(tk);
+ push(tk);
a.push(parseExpr());
tk = token();
if( tk == TComma )
@@ -296,8 +308,8 @@ class Parser {
if( Type.enumEq(tk,TId("else")) )
e2 = parseExpr();
else {
- tokens.add(tk);
- if( semic ) tokens.add(TSemicolon);
+ push(tk);
+ if( semic ) push(TSemicolon);
}
EIf(cond,e1,e2);
case "var":
@@ -308,20 +320,24 @@ class Parser {
default: unexpected(tk);
}
tk = token();
+ var t = null;
+ if( tk == TDoubleDot && allowTypes ) {
+ t = parseType();
+ tk = token();
+ }
var e = null;
if( Type.enumEq(tk,TOp("=")) )
e = parseExpr();
else
- tokens.add(tk);
- EVar(ident,e);
+ push(tk);
+ EVar(ident,t,e);
case "while":
var econd = parseExpr();
var e = parseExpr();
EWhile(econd,e);
case "for":
+ ensure(TPOpen);
var tk = token();
- if( tk != TPOpen ) unexpected(tk);
- tk = token();
var vname = null;
switch( tk ) {
case TId(id): vname = id;
@@ -330,8 +346,7 @@ class Parser {
tk = token();
if( !Type.enumEq(tk,TId("in")) ) unexpected(tk);
var eiter = parseExpr();
- tk = token();
- if( tk != TPClose ) unexpected(tk);
+ ensure(TPClose);
EFor(vname,eiter,parseExpr());
case "break": EBreak;
case "continue": EContinue;
@@ -340,19 +355,26 @@ class Parser {
var tk = token();
var name = null;
switch( tk ) {
- case TId(id): name = id; tk = token();
- default:
+ case TId(id): name = id;
+ default: push(tk);
}
- if( tk != TPOpen ) unexpected(tk);
+ ensure(TPOpen);
var args = new Array();
tk = token();
if( tk != TPClose ) {
while( true ) {
+ var name = null;
switch( tk ) {
- case TId(id): args.push(id);
+ case TId(id): name = id;
default: unexpected(tk);
}
tk = token();
+ var t = null;
+ if( tk == TDoubleDot && allowTypes ) {
+ t = parseType();
+ tk = token();
+ }
+ args.push({ name : name, t : t });
switch( tk ) {
case TComma:
case TPClose: break;
@@ -361,10 +383,18 @@ class Parser {
tk = token();
}
}
- EFunction(args,parseExpr(),name);
+ var ret = null;
+ if( allowTypes ) {
+ tk = token();
+ if( tk != TDoubleDot )
+ push(tk);
+ else
+ ret = parseType();
+ }
+ EFunction(args, parseExpr(), name, ret);
case "return":
var tk = token();
- tokens.add(tk);
+ push(tk);
EReturn(if( tk == TSemicolon ) null else parseExpr());
case "new":
var a = new Array();
@@ -394,21 +424,23 @@ class Parser {
case "try":
var e = parseExpr();
var tk = token();
- if( !Type.enumEq(tk,TId("catch")) ) unexpected(tk);
- tk = token();
- if( tk != TPOpen ) unexpected(tk);
+ if( !Type.enumEq(tk, TId("catch")) ) unexpected(tk);
+ ensure(TPOpen);
tk = token();
var vname = switch( tk ) {
case TId(id): id;
default: unexpected(tk);
}
- tk = token();
- if( tk != TDoubleDot ) unexpected(tk);
- tk = token();
- if( !Type.enumEq(tk,TId("Dynamic")) ) unexpected(tk);
- tk = token();
- if( tk != TPClose ) unexpected(tk);
- ETry(e,vname,parseExpr());
+ ensure(TDoubleDot);
+ var t = null;
+ if( allowTypes )
+ t = parseType();
+ else {
+ tk = token();
+ if( !Type.enumEq(tk, TId("Dynamic")) ) unexpected(tk);
+ }
+ ensure(TPClose);
+ ETry(e,vname,t,parseExpr());
default:
null;
}
@@ -421,7 +453,7 @@ class Parser {
for( x in unopsSuffix )
if( x == op ) {
if( isBlock(e1) || switch(e1) { case EParent(_): true; default: false; } ) {
- tokens.add(tk);
+ push(tk);
return e1;
}
return parseExprNext(EUnop(op,false,e1));
@@ -439,21 +471,107 @@ class Parser {
return parseExprNext(ECall(e1,parseExprList(TPClose)));
case TBkOpen:
var e2 = parseExpr();
- tk = token();
- if( tk != TBkClose ) unexpected(tk);
+ ensure(TBkClose);
return parseExprNext(EArray(e1,e2));
case TQuestion:
var e2 = parseExpr();
- tk = token();
- if( tk != TDoubleDot ) unexpected(tk);
+ ensure(TDoubleDot);
var e3 = parseExpr();
return EIf(e1,e2,e3);
default:
- tokens.add(tk);
+ push(tk);
return e1;
}
}
+ function parseType() : CType {
+ var t = token();
+ switch( t ) {
+ case TId(v):
+ var path = [v];
+ while( true ) {
+ t = token();
+ if( t != TDot )
+ break;
+ t = token();
+ switch( t ) {
+ case TId(v):
+ path.push(v);
+ default:
+ unexpected(t);
+ }
+ }
+ var params = null;
+ switch( t ) {
+ case TOp(op):
+ if( op == "<" ) {
+ params = [];
+ while( true ) {
+ params.push(parseType());
+ t = token();
+ switch( t ) {
+ case TComma: continue;
+ case TOp(op): if( op == ">" ) break;
+ default:
+ }
+ unexpected(t);
+ }
+ }
+ default:
+ push(t);
+ }
+ return parseTypeNext(CTPath(path, params));
+ case TPOpen:
+ var t = parseType();
+ ensure(TPClose);
+ return parseTypeNext(CTParent(t));
+ case TBrOpen:
+ var fields = [];
+ while( true ) {
+ t = token();
+ switch( t ) {
+ case TBrClose: break;
+ case TId(name):
+ ensure(TDoubleDot);
+ fields.push( { name : name, t : parseType() } );
+ t = token();
+ switch( t ) {
+ case TComma:
+ case TBrClose: break;
+ default: unexpected(t);
+ }
+ default:
+ unexpected(t);
+ }
+ }
+ return parseTypeNext(CTAnon(fields));
+ default:
+ return unexpected(t);
+ }
+ }
+
+ function parseTypeNext( t : CType ) {
+ var tk = token();
+ switch( tk ) {
+ case TOp(op):
+ if( op != "->" ) {
+ push(tk);
+ return t;
+ }
+ default:
+ push(tk);
+ return t;
+ }
+ var t2 = parseType();
+ switch( t2 ) {
+ case CTFun(args, ret):
+ args.unshift(t);
+ return t2;
+ default:
+ return CTFun([t], t2);
+ }
+ }
+
function parseExprList( etk ) {
var args = new Array();
var tk = token();