From 78a18acf07ede97fe9116cf4ea33528e3e970743 Mon Sep 17 00:00:00 2001 From: Nicolas Cannasse Date: Sat, 19 Mar 2011 11:27:15 +0000 Subject: [PATCH] added possible type declarations (with Parser.allowTypes) --- hscript.hxml | 3 +- hscript.hxproj | 9 +- hscript/Bytes.hx | 14 +-- hscript/Expr.hx | 13 ++- hscript/Interp.hx | 8 +- hscript/Parser.hx | 212 ++++++++++++++++++++++++++++++++++++---------- 6 files changed, 195 insertions(+), 64 deletions(-) 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();