added optional metadata support in toplevel expr and anon types
This commit is contained in:
+5
-2
@@ -70,14 +70,17 @@ enum Expr {
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<{ values : Array<Expr>, expr : Expr }>, ?defaultExpr : Expr);
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
}
|
||||
|
||||
typedef Argument = { name : String, ?t : CType, ?opt : Bool };
|
||||
|
||||
typedef Metadata = Array<{ name : String, params : Array<Expr> }>;
|
||||
|
||||
enum CType {
|
||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType }> );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
}
|
||||
|
||||
@@ -99,7 +102,7 @@ class Error {
|
||||
private function errorDefToString(): String {
|
||||
switch (e) {
|
||||
case EInvalidChar(c):
|
||||
return "Invalid character: '"+c+"'";
|
||||
return "Invalid character: '"+String.fromCharCode(c)+"' ("+c+")";
|
||||
|
||||
case EUnexpected(s):
|
||||
return "Unexpected token: \""+s+"\"";
|
||||
|
||||
+5
-3
@@ -137,7 +137,7 @@ class Interp {
|
||||
else {
|
||||
arr[index] = v;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
error(EInvalidOp("="));
|
||||
}
|
||||
@@ -560,6 +560,8 @@ class Interp {
|
||||
if( !match )
|
||||
val = def == null ? null : expr(def);
|
||||
return val;
|
||||
case EMeta(_, _, e):
|
||||
return expr(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -629,7 +631,7 @@ class Interp {
|
||||
inline function isMap(o:Dynamic):Bool {
|
||||
return Std.is(o, haxe.Constraints.IMap);
|
||||
}
|
||||
|
||||
|
||||
inline function getMapValue(map:Dynamic, key:Dynamic):Dynamic {
|
||||
return cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).get(key);
|
||||
}
|
||||
@@ -637,7 +639,7 @@ class Interp {
|
||||
inline function setMapValue(map:Dynamic, key:Dynamic, value:Dynamic):Void {
|
||||
cast(map, haxe.Constraints.IMap<Dynamic, Dynamic>).set(key, value);
|
||||
}
|
||||
|
||||
|
||||
function get( o : Dynamic, f : String ) : Dynamic {
|
||||
if ( o == null ) error(EInvalidAccess(f));
|
||||
return {
|
||||
|
||||
@@ -231,6 +231,9 @@ class Macro {
|
||||
ETernary(convert(cond), convert(e1), convert(e2));
|
||||
case ESwitch(e, cases, edef):
|
||||
ESwitch(convert(e), [for( c in cases ) { values : [for( v in c.values ) convert(v)], expr : convert(c.expr) } ], edef == null ? null : convert(edef));
|
||||
case EMeta(m, params, esub):
|
||||
var mpos = #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end;
|
||||
EMeta({ name : m, params : params == null ? [] : [for( p in params ) convert(p)], pos : mpos }, convert(esub));
|
||||
}, pos : #if hscriptPos { file : p.file, min : e.pmin, max : e.pmax } #else p #end }
|
||||
}
|
||||
|
||||
|
||||
+79
-44
@@ -41,6 +41,7 @@ enum Token {
|
||||
TBkClose;
|
||||
TQuestion;
|
||||
TDoubleDot;
|
||||
TMeta( s : String );
|
||||
}
|
||||
|
||||
class Parser {
|
||||
@@ -69,6 +70,11 @@ class Parser {
|
||||
**/
|
||||
public var allowTypes : Bool;
|
||||
|
||||
/**
|
||||
allow haxe metadata declarations
|
||||
**/
|
||||
public var allowMetadata : Bool;
|
||||
|
||||
// implementation
|
||||
var input : haxe.io.Input;
|
||||
var char : Int;
|
||||
@@ -200,6 +206,16 @@ class Parser {
|
||||
if( t != tk ) unexpected(t);
|
||||
}
|
||||
|
||||
function getIdent() {
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TId(id): return id;
|
||||
default:
|
||||
unexpected(tk);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
inline function expr(e:Expr) {
|
||||
#if hscriptPos
|
||||
return e.e;
|
||||
@@ -384,12 +400,39 @@ class Parser {
|
||||
return parseExprNext(e);
|
||||
default:
|
||||
}
|
||||
return parseExprNext(mk(EArrayDecl(a),p1));
|
||||
return parseExprNext(mk(EArrayDecl(a), p1));
|
||||
case TMeta(id) if( allowMetadata ):
|
||||
var args = parseMetaArgs();
|
||||
return mk(EMeta(id, args, parseExpr()),p1);
|
||||
default:
|
||||
return unexpected(tk);
|
||||
}
|
||||
}
|
||||
|
||||
function parseMetaArgs() {
|
||||
var tk = token();
|
||||
if( tk != TPOpen ) {
|
||||
push(tk);
|
||||
return null;
|
||||
}
|
||||
var args = [];
|
||||
tk = token();
|
||||
if( tk != TPClose ) {
|
||||
push(tk);
|
||||
while( true ) {
|
||||
args.push(parseExpr());
|
||||
switch( token() ) {
|
||||
case TComma:
|
||||
case TPClose:
|
||||
break;
|
||||
case tk:
|
||||
unexpected(tk);
|
||||
}
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
function mapCompr( tmp : String, e : Expr ) {
|
||||
var edef = switch( expr(e) ) {
|
||||
case EFor(v, it, e2):
|
||||
@@ -460,13 +503,8 @@ class Parser {
|
||||
}
|
||||
mk(EIf(cond,e1,e2),p1,(e2 == null) ? tokenMax : pmax(e2));
|
||||
case "var":
|
||||
var ident = getIdent();
|
||||
var tk = token();
|
||||
var ident = null;
|
||||
switch(tk) {
|
||||
case TId(id): ident = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
tk = token();
|
||||
var t = null;
|
||||
if( tk == TDoubleDot && allowTypes ) {
|
||||
t = parseType();
|
||||
@@ -494,13 +532,8 @@ class Parser {
|
||||
mk(EDoWhile(econd,e),p1,pmax(econd));
|
||||
case "for":
|
||||
ensure(TPOpen);
|
||||
var vname = getIdent();
|
||||
var tk = token();
|
||||
var vname = null;
|
||||
switch( tk ) {
|
||||
case TId(id): vname = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
tk = token();
|
||||
if( !Type.enumEq(tk,TId("in")) ) unexpected(tk);
|
||||
var eiter = parseExpr();
|
||||
ensure(TPClose);
|
||||
@@ -568,21 +601,13 @@ class Parser {
|
||||
mk(EReturn(e),p1,if( e == null ) tokenMax else pmax(e));
|
||||
case "new":
|
||||
var a = new Array();
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TId(id): a.push(id);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
a.push(getIdent());
|
||||
var next = true;
|
||||
while( next ) {
|
||||
tk = token();
|
||||
var tk = token();
|
||||
switch( tk ) {
|
||||
case TDot:
|
||||
tk = token();
|
||||
switch(tk) {
|
||||
case TId(id): a.push(id);
|
||||
default: unexpected(tk);
|
||||
}
|
||||
a.push(getIdent());
|
||||
case TPOpen:
|
||||
next = false;
|
||||
default:
|
||||
@@ -599,11 +624,7 @@ class Parser {
|
||||
var tk = token();
|
||||
if( !Type.enumEq(tk, TId("catch")) ) unexpected(tk);
|
||||
ensure(TPOpen);
|
||||
tk = token();
|
||||
var vname = switch( tk ) {
|
||||
case TId(id): id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
var vname = getIdent();
|
||||
ensure(TDoubleDot);
|
||||
var t = null;
|
||||
if( allowTypes )
|
||||
@@ -700,12 +721,7 @@ class Parser {
|
||||
}
|
||||
return makeBinop(op,e1,parseExpr());
|
||||
case TDot:
|
||||
tk = token();
|
||||
var field = null;
|
||||
switch(tk) {
|
||||
case TId(id): field = id;
|
||||
default: unexpected(tk);
|
||||
}
|
||||
var field = getIdent();
|
||||
return parseExprNext(mk(EField(e1,field),pmin(e1)));
|
||||
case TPOpen:
|
||||
return parseExprNext(mk(ECall(e1,parseExprList(TPClose)),pmin(e1)));
|
||||
@@ -733,13 +749,7 @@ class Parser {
|
||||
t = token();
|
||||
if( t != TDot )
|
||||
break;
|
||||
t = token();
|
||||
switch( t ) {
|
||||
case TId(v):
|
||||
path.push(v);
|
||||
default:
|
||||
unexpected(t);
|
||||
}
|
||||
path.push(getIdent());
|
||||
}
|
||||
var params = null;
|
||||
switch( t ) {
|
||||
@@ -758,7 +768,7 @@ class Parser {
|
||||
tokens.add({ t : TOp(op.substr(1)), min : tokenMax - op.length - 1, max : tokenMax });
|
||||
#else
|
||||
tokens.add(TOp(op.substr(1)));
|
||||
#end
|
||||
#end
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -777,19 +787,29 @@ class Parser {
|
||||
return parseTypeNext(CTParent(t));
|
||||
case TBrOpen:
|
||||
var fields = [];
|
||||
var meta = null;
|
||||
while( true ) {
|
||||
t = token();
|
||||
switch( t ) {
|
||||
case TBrClose: break;
|
||||
case TId("var"):
|
||||
var name = getIdent();
|
||||
ensure(TDoubleDot);
|
||||
fields.push( { name : name, t : parseType(), meta : meta } );
|
||||
meta = null;
|
||||
ensure(TSemicolon);
|
||||
case TId(name):
|
||||
ensure(TDoubleDot);
|
||||
fields.push( { name : name, t : parseType() } );
|
||||
fields.push( { name : name, t : parseType(), meta : meta } );
|
||||
t = token();
|
||||
switch( t ) {
|
||||
case TComma:
|
||||
case TBrClose: break;
|
||||
default: unexpected(t);
|
||||
}
|
||||
case TMeta(name):
|
||||
if( meta == null ) meta = [];
|
||||
meta.push({ name : name, params : parseMetaArgs() });
|
||||
default:
|
||||
unexpected(t);
|
||||
}
|
||||
@@ -1082,6 +1102,20 @@ class Parser {
|
||||
return TOp("=>");
|
||||
this.char = char;
|
||||
return TOp("=");
|
||||
case '@'.code:
|
||||
char = readChar();
|
||||
if( idents[char] || char == ':'.code ) {
|
||||
var id = String.fromCharCode(char);
|
||||
while( true ) {
|
||||
char = readChar();
|
||||
if( !idents[char] ) {
|
||||
this.char = char;
|
||||
return TMeta(id);
|
||||
}
|
||||
id += String.fromCharCode(char);
|
||||
}
|
||||
}
|
||||
invalidChar(char);
|
||||
default:
|
||||
if( ops[char] ) {
|
||||
var op = String.fromCharCode(char);
|
||||
@@ -1186,6 +1220,7 @@ class Parser {
|
||||
case TBkClose: "]";
|
||||
case TQuestion: "?";
|
||||
case TDoubleDot: ":";
|
||||
case TMeta(id): "@" + id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user