Implement enum abstract + fully qualified path functionality. (#15)
* enum * path functionality * allowTypes
This commit is contained in:
+246
-244
@@ -1,244 +1,246 @@
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||
|
||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String, ?i : Bool );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : String, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EPackage( ?n:String );
|
||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||
ECast(e:Expr, ?t:CType);
|
||||
ERegex(e:String, flags:String);
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class ObjectField {
|
||||
public var name : String;
|
||||
public var e : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class SwitchCase {
|
||||
public var values : Array<Expr>;
|
||||
public var expr : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class Argument {
|
||||
public var name : String;
|
||||
public var t : CType;
|
||||
public var opt : Bool;
|
||||
public var value : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class MetadataEntry {
|
||||
public var name : String;
|
||||
public var params : Array<Expr>;
|
||||
}
|
||||
|
||||
typedef Metadata = Array<MetadataEntry>;
|
||||
|
||||
@:structInit
|
||||
final class EnumDecl {
|
||||
public var name : String;
|
||||
public var fields : Array<EnumField>;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class EnumField {
|
||||
public var name : String;
|
||||
public var args : Array<Argument>;
|
||||
}
|
||||
|
||||
enum CType {
|
||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
CTOpt( t : CType );
|
||||
CTNamed( n : String, t : CType );
|
||||
CTExpr( e : Expr ); // for type parameters only
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
class Error {
|
||||
public var e : ErrorDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
public function new(e, pmin, pmax, origin, line) {
|
||||
this.e = e;
|
||||
this.pmin = pmin;
|
||||
this.pmax = pmax;
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
public function toString(): String {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
#else
|
||||
enum Error {
|
||||
#end
|
||||
EInvalidChar( c : Int );
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
EUnterminatedComment;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
}
|
||||
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
DImport( path : Array<String>, ?everything : Bool );
|
||||
DClass( c : ClassDecl );
|
||||
DTypedef( c : TypeDecl );
|
||||
}
|
||||
|
||||
typedef ModuleType = {
|
||||
var name : String;
|
||||
var params : {}; // TODO : not yet parsed
|
||||
var meta : Metadata;
|
||||
var isPrivate : Bool;
|
||||
}
|
||||
|
||||
typedef ClassDecl = {> ModuleType,
|
||||
var extend : Null<CType>;
|
||||
var implement : Array<CType>;
|
||||
var fields : Array<FieldDecl>;
|
||||
var isExtern : Bool;
|
||||
}
|
||||
|
||||
typedef TypeDecl = {> ModuleType,
|
||||
var t : CType;
|
||||
}
|
||||
|
||||
typedef FieldDecl = {
|
||||
var name : String;
|
||||
var meta : Metadata;
|
||||
var kind : FieldKind;
|
||||
var access : Array<FieldAccess>;
|
||||
}
|
||||
|
||||
enum abstract FieldAccess(UInt8) {
|
||||
var APublic;
|
||||
var APrivate;
|
||||
var AInline;
|
||||
var AOverride;
|
||||
var AStatic;
|
||||
var AMacro;
|
||||
}
|
||||
|
||||
enum abstract FieldPropertyAccess(UInt8) {
|
||||
var ADefault;
|
||||
var ANull;
|
||||
var AGet;
|
||||
var ASet;
|
||||
var ADynamic;
|
||||
var ANever;
|
||||
}
|
||||
|
||||
enum FieldKind {
|
||||
KFunction( f : FunctionDecl );
|
||||
KVar( v : VarDecl );
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class FunctionDecl {
|
||||
public var args : Array<Argument>;
|
||||
public var body : Expr;
|
||||
public var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
var get : Null<String>;
|
||||
var set : Null<String>;
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
/*
|
||||
* Copyright (C)2008-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package hscript;
|
||||
|
||||
typedef Int8 = #if cpp cpp.Int8 #elseif java java.Int8 #elseif cs cs.Int8 #else Int #end;
|
||||
typedef Int16 = #if cpp cpp.Int16 #elseif java java.Int16 #elseif cs cs.Int16 #else Int #end;
|
||||
typedef Int32 = #if cpp cpp.Int32 #else Int #end;
|
||||
typedef Int64 = #if cpp cpp.Int64 #elseif java java.Int64 #elseif cs cs.Int64 #else Int #end;
|
||||
|
||||
typedef UInt8 = #if cpp cpp.UInt8 #elseif cs cs.UInt8 #else Int #end;
|
||||
typedef UInt16 = #if cpp cpp.UInt16 #elseif cs cs.UInt16 #else Int #end;
|
||||
typedef UInt32 = #if cpp cpp.UInt32 #else Int #end;
|
||||
typedef UInt64 = #if cpp cpp.UInt64 #else Int #end;
|
||||
|
||||
enum Const {
|
||||
CInt( v : Int );
|
||||
CFloat( f : Float );
|
||||
CString( s : String, ?i : Bool );
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
@:structInit
|
||||
final class Expr {
|
||||
public var e : ExprDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
}
|
||||
enum ExprDef {
|
||||
#else
|
||||
typedef ExprDef = Expr;
|
||||
enum Expr {
|
||||
#end
|
||||
EConst( c : Const );
|
||||
EIdent( v : String );
|
||||
EVar( n : String, ?t : CType, ?e : Expr, ?isPublic : Bool, ?isStatic : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool, ?get : FieldPropertyAccess, ?set : FieldPropertyAccess, ?isVar:Bool );
|
||||
EParent( e : Expr );
|
||||
EBlock( e : Array<Expr> );
|
||||
EField( e : Expr, f : String , ?safe : Bool );
|
||||
EBinop( op : String, e1 : Expr, e2 : Expr );
|
||||
EUnop( op : String, prefix : Bool, e : Expr );
|
||||
ECall( e : Expr, params : Array<Expr> );
|
||||
EIf( cond : Expr, e1 : Expr, ?e2 : Expr );
|
||||
EWhile( cond : Expr, e : Expr );
|
||||
EFor( v : String, it : Expr, e : Expr, ?ithv: String);
|
||||
EBreak;
|
||||
EContinue;
|
||||
EFunction( args : Array<Argument>, e : Expr, ?name : String, ?ret : CType, ?isPublic : Bool, ?isStatic : Bool, ?isOverride : Bool, ?isPrivate : Bool, ?isFinal : Bool, ?isInline : Bool );
|
||||
EReturn( ?e : Expr );
|
||||
EArray( e : Expr, index : Expr );
|
||||
EArrayDecl( e : Array<Expr>, ?wantedType: CType );
|
||||
ENew( cl : String, params : Array<Expr>, ?paramType:Array<CType> );
|
||||
EThrow( e : Expr );
|
||||
ETry( e : Expr, v : String, t : Null<CType>, ecatch : Expr );
|
||||
EObject( fl : Array<ObjectField> );
|
||||
ETernary( cond : Expr, e1 : Expr, e2 : Expr );
|
||||
ESwitch( e : Expr, cases : Array<SwitchCase>, ?defaultExpr : Expr );
|
||||
EDoWhile( cond : Expr, e : Expr);
|
||||
EMeta( name : String, args : Array<Expr>, e : Expr );
|
||||
ECheckType( e : Expr, t : CType );
|
||||
|
||||
EPackage( ?n:String );
|
||||
EImport( c : String, ?asname:String, ?isUsing:Bool );
|
||||
EClass( name:String, fields:Array<Expr>, ?extend:String, interfaces:Array<String>, ?isFinal:Bool, ?isPrivate:Bool );
|
||||
EEnum( en:EnumDecl, ?isAbstract:Bool );
|
||||
ECast(e:Expr, ?t:CType);
|
||||
ERegex(e:String, flags:String);
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class ObjectField {
|
||||
public var name : String;
|
||||
public var e : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class SwitchCase {
|
||||
public var values : Array<Expr>;
|
||||
public var expr : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class Argument {
|
||||
public var name : String;
|
||||
public var t : CType;
|
||||
public var opt : Bool;
|
||||
public var value : Expr;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class MetadataEntry {
|
||||
public var name : String;
|
||||
public var params : Array<Expr>;
|
||||
}
|
||||
|
||||
typedef Metadata = Array<MetadataEntry>;
|
||||
|
||||
@:structInit
|
||||
final class EnumDecl {
|
||||
public var name : String;
|
||||
public var fields : Array<EnumField>;
|
||||
public var underlyingType : Null<CType>;
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class EnumField {
|
||||
public var name : String;
|
||||
public var args : Array<Argument>;
|
||||
public var value : Null<Expr>;
|
||||
}
|
||||
|
||||
enum CType {
|
||||
CTPath( path : Array<String>, ?params : Array<CType> );
|
||||
CTFun( args : Array<CType>, ret : CType );
|
||||
CTAnon( fields : Array<{ name : String, t : CType, ?meta : Metadata }> );
|
||||
CTParent( t : CType );
|
||||
CTOpt( t : CType );
|
||||
CTNamed( n : String, t : CType );
|
||||
CTExpr( e : Expr ); // for type parameters only
|
||||
}
|
||||
|
||||
#if hscriptPos
|
||||
class Error {
|
||||
public var e : ErrorDef;
|
||||
public var pmin : Int;
|
||||
public var pmax : Int;
|
||||
public var origin : String;
|
||||
public var line : Int;
|
||||
public function new(e, pmin, pmax, origin, line) {
|
||||
this.e = e;
|
||||
this.pmin = pmin;
|
||||
this.pmax = pmax;
|
||||
this.origin = origin;
|
||||
this.line = line;
|
||||
}
|
||||
public function toString(): String {
|
||||
return Printer.errorToString(this);
|
||||
}
|
||||
}
|
||||
enum ErrorDef {
|
||||
#else
|
||||
enum Error {
|
||||
#end
|
||||
EInvalidChar( c : Int );
|
||||
EUnexpected( s : String );
|
||||
EUnterminatedString;
|
||||
EUnterminatedComment;
|
||||
EInvalidPreprocessor( msg : String );
|
||||
EUnknownVariable( v : String );
|
||||
EInvalidIterator( v : String );
|
||||
EInvalidOp( op : String );
|
||||
EInvalidAccess( f : String );
|
||||
ECustom( msg : String );
|
||||
EInvalidClass( className : String);
|
||||
EAlreadyExistingClass( className : String);
|
||||
}
|
||||
|
||||
|
||||
enum ModuleDecl {
|
||||
DPackage( path : Array<String> );
|
||||
DImport( path : Array<String>, ?everything : Bool );
|
||||
DClass( c : ClassDecl );
|
||||
DTypedef( c : TypeDecl );
|
||||
}
|
||||
|
||||
typedef ModuleType = {
|
||||
var name : String;
|
||||
var params : {}; // TODO : not yet parsed
|
||||
var meta : Metadata;
|
||||
var isPrivate : Bool;
|
||||
}
|
||||
|
||||
typedef ClassDecl = {> ModuleType,
|
||||
var extend : Null<CType>;
|
||||
var implement : Array<CType>;
|
||||
var fields : Array<FieldDecl>;
|
||||
var isExtern : Bool;
|
||||
}
|
||||
|
||||
typedef TypeDecl = {> ModuleType,
|
||||
var t : CType;
|
||||
}
|
||||
|
||||
typedef FieldDecl = {
|
||||
var name : String;
|
||||
var meta : Metadata;
|
||||
var kind : FieldKind;
|
||||
var access : Array<FieldAccess>;
|
||||
}
|
||||
|
||||
enum abstract FieldAccess(UInt8) {
|
||||
var APublic;
|
||||
var APrivate;
|
||||
var AInline;
|
||||
var AOverride;
|
||||
var AStatic;
|
||||
var AMacro;
|
||||
}
|
||||
|
||||
enum abstract FieldPropertyAccess(UInt8) {
|
||||
var ADefault;
|
||||
var ANull;
|
||||
var AGet;
|
||||
var ASet;
|
||||
var ADynamic;
|
||||
var ANever;
|
||||
}
|
||||
|
||||
enum FieldKind {
|
||||
KFunction( f : FunctionDecl );
|
||||
KVar( v : VarDecl );
|
||||
}
|
||||
|
||||
@:structInit
|
||||
final class FunctionDecl {
|
||||
public var args : Array<Argument>;
|
||||
public var body : Expr;
|
||||
public var ret : Null<CType>;
|
||||
}
|
||||
|
||||
typedef VarDecl = {
|
||||
var get : Null<String>;
|
||||
var set : Null<String>;
|
||||
var expr : Null<Expr>;
|
||||
var type : Null<CType>;
|
||||
}
|
||||
|
||||
+119
-3
@@ -2,13 +2,13 @@ package hscript;
|
||||
|
||||
import hscript.utils.UnsafeReflect;
|
||||
|
||||
// TODO: EnumTools for scripted enums
|
||||
/**
|
||||
* Wrapper class for enums, both for real and scripted.
|
||||
* Use EnumTools and EnumValueTools for enum operations.
|
||||
*/
|
||||
@:structInit
|
||||
class HEnum implements IHScriptCustomBehaviour {
|
||||
private var enumValues(default, null) = {};
|
||||
var enumValues(default, null) = {};
|
||||
|
||||
public function setEnum(name:String, enumValue:Dynamic):Void {
|
||||
UnsafeReflect.setField(enumValues, name, enumValue);
|
||||
@@ -20,6 +20,10 @@ class HEnum implements IHScriptCustomBehaviour {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getEnumValues():Dynamic {
|
||||
return enumValues;
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
return getEnum(name);
|
||||
}
|
||||
@@ -57,10 +61,122 @@ class HEnumValue {
|
||||
if (args.length != other.args.length)
|
||||
return false;
|
||||
|
||||
for (i in 0...args.length) // TODO: allow deep comparison, like arrays
|
||||
for (i in 0...args.length)
|
||||
if (args[i] != other.args[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@:nullSafety
|
||||
class EnumTools {
|
||||
public static function getConstructors(e:Dynamic):Array<String> {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var henum:HEnum = cast e;
|
||||
return UnsafeReflect.fields(henum.getEnumValues());
|
||||
}
|
||||
return Type.getEnumConstructs(cast e);
|
||||
}
|
||||
|
||||
public static function createByName(e:Dynamic, constr:String, ?params:Array<Dynamic>):Dynamic {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var henum:HEnum = cast e;
|
||||
var constructor = henum.getEnum(constr);
|
||||
if(constructor == null)
|
||||
throw 'Constructor $constr not found in enum';
|
||||
if(Std.isOfType(constructor, HEnumValue))
|
||||
return constructor;
|
||||
if(Reflect.isFunction(constructor))
|
||||
return constructor(params == null ? [] : params);
|
||||
throw 'Invalid constructor type';
|
||||
}
|
||||
return Type.createEnum(cast e, constr, params);
|
||||
}
|
||||
|
||||
public static function createByIndex(e:Dynamic, index:Int, ?params:Array<Dynamic>):Dynamic {
|
||||
if(Std.isOfType(e, HEnum)) {
|
||||
var constructors = getConstructors(e);
|
||||
if(index < 0 || index >= constructors.length)
|
||||
throw 'Index $index out of bounds for enum';
|
||||
return createByName(e, constructors[index], params);
|
||||
}
|
||||
return Type.createEnumIndex(cast e, index, params);
|
||||
}
|
||||
}
|
||||
|
||||
@:nullSafety
|
||||
class EnumValueTools {
|
||||
public static function getType(e:Dynamic):Null<String> {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.enumName;
|
||||
}
|
||||
var en = Type.getEnum(e);
|
||||
if(en != null)
|
||||
return Type.getEnumName(en);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function getName(e:Dynamic):String {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.fieldName;
|
||||
}
|
||||
return Type.enumConstructor(e);
|
||||
}
|
||||
|
||||
public static function getParameters(e:Dynamic):Array<Dynamic> {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.args.copy();
|
||||
}
|
||||
return Type.enumParameters(e);
|
||||
}
|
||||
|
||||
public static function getIndex(e:Dynamic):Int {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
return hv.index;
|
||||
}
|
||||
return Type.enumIndex(e);
|
||||
}
|
||||
|
||||
public static function equals(a:Dynamic, b:Dynamic):Bool {
|
||||
if(Std.isOfType(a, HEnumValue) && Std.isOfType(b, HEnumValue)) {
|
||||
var hva:HEnumValue = cast a;
|
||||
var hvb:HEnumValue = cast b;
|
||||
return hva.compare(hvb);
|
||||
}
|
||||
return Type.enumEq(a, b);
|
||||
}
|
||||
|
||||
public static function match(e:Dynamic, pattern:Dynamic):Bool {
|
||||
if(Std.isOfType(e, HEnumValue)) {
|
||||
var hv:HEnumValue = cast e;
|
||||
if(Std.isOfType(pattern, HEnumValue)) {
|
||||
var hp:HEnumValue = cast pattern;
|
||||
if(hv.enumName != hp.enumName || hv.fieldName != hp.fieldName)
|
||||
return false;
|
||||
if(hp.args.length == 0)
|
||||
return true;
|
||||
if(hv.args.length != hp.args.length)
|
||||
return false;
|
||||
for(i in 0...hp.args.length) {
|
||||
var pa = hp.args[i];
|
||||
if(pa != null && hv.args[i] != pa)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if(Reflect.isObject(pattern)) {
|
||||
var patternName = UnsafeReflect.hasField(pattern, "name") ? UnsafeReflect.field(pattern, "name") : null;
|
||||
if(patternName != null && patternName != hv.fieldName)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return Type.enumEq(e, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
+112
-59
@@ -687,6 +687,10 @@ class Interp {
|
||||
return UnsafeReflect.getProperty(scriptObject, 'get_$id')();
|
||||
}
|
||||
}
|
||||
var cl = Type.resolveClass(id);
|
||||
if(cl != null) return cl;
|
||||
var en = Type.resolveEnum(id);
|
||||
if(en != null) return en;
|
||||
if (doException)
|
||||
error(EUnknownVariable(id));
|
||||
return null;
|
||||
@@ -845,70 +849,81 @@ class Interp {
|
||||
}
|
||||
return null;
|
||||
|
||||
case EEnum(en, _): // TODO: enum abstracts
|
||||
var enumThingy:HEnum = {};
|
||||
var enumName = en.name;
|
||||
var enumFields = en.fields;
|
||||
for (i => ef in enumFields) {
|
||||
var fieldName = ef.name;
|
||||
|
||||
if(ef.args.length < 1) {
|
||||
var enumValue:HEnumValue = {
|
||||
enumName: enumName,
|
||||
fieldName: fieldName,
|
||||
index: i,
|
||||
args: []
|
||||
}
|
||||
|
||||
enumThingy.setEnum(fieldName, enumValue);
|
||||
case EEnum(en, isAbstract):
|
||||
if(isAbstract) {
|
||||
var enumObj:Dynamic = {};
|
||||
var enumName = en.name;
|
||||
var enumFields = en.fields;
|
||||
for (i => ef in enumFields) {
|
||||
var fieldName = ef.name;
|
||||
var fieldValue = ef.value != null ? exprReturn(ef.value) : i;
|
||||
UnsafeReflect.setField(enumObj, fieldName, fieldValue);
|
||||
}
|
||||
else {
|
||||
var params = ef.args;
|
||||
var hasOpt = false, minParams = 0;
|
||||
for (p in params) {
|
||||
if (p.opt)
|
||||
hasOpt = true;
|
||||
else
|
||||
minParams++;
|
||||
}
|
||||
|
||||
var f = function(args:Array<Dynamic>):HEnumValue {
|
||||
if (((args == null) ? 0 : args.length) != params.length) {
|
||||
if (args.length < minParams) {
|
||||
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
||||
if (enumName != null)
|
||||
str += " for enum '" + enumName + "'";
|
||||
error(ECustom(str));
|
||||
}
|
||||
// make sure mandatory args are forced
|
||||
var args2 = [];
|
||||
var extraParams = args.length - minParams;
|
||||
var pos = 0;
|
||||
for (p in params)
|
||||
if (p.opt) {
|
||||
if (extraParams > 0) {
|
||||
args2.push(args[pos++]);
|
||||
extraParams--;
|
||||
} else
|
||||
args2.push(null);
|
||||
} else
|
||||
args2.push(args[pos++]);
|
||||
args = args2;
|
||||
}
|
||||
return {
|
||||
variables.set(enumName, enumObj);
|
||||
} else {
|
||||
var enumThingy:HEnum = {};
|
||||
var enumName = en.name;
|
||||
var enumFields = en.fields;
|
||||
for (i => ef in enumFields) {
|
||||
var fieldName = ef.name;
|
||||
|
||||
if(ef.args.length < 1) {
|
||||
var enumValue:HEnumValue = {
|
||||
enumName: enumName,
|
||||
fieldName: fieldName,
|
||||
index: i,
|
||||
args: args
|
||||
args: []
|
||||
}
|
||||
|
||||
enumThingy.setEnum(fieldName, enumValue);
|
||||
}
|
||||
else {
|
||||
var params = ef.args;
|
||||
var hasOpt = false, minParams = 0;
|
||||
for (p in params) {
|
||||
if (p.opt)
|
||||
hasOpt = true;
|
||||
else
|
||||
minParams++;
|
||||
}
|
||||
|
||||
var f = function(args:Array<Dynamic>):HEnumValue {
|
||||
if (((args == null) ? 0 : args.length) != params.length) {
|
||||
if (args.length < minParams) {
|
||||
var str = "Invalid number of parameters. Got " + args.length + ", required " + minParams;
|
||||
if (enumName != null)
|
||||
str += " for enum '" + enumName + "'";
|
||||
error(ECustom(str));
|
||||
}
|
||||
var args2 = [];
|
||||
var extraParams = args.length - minParams;
|
||||
var pos = 0;
|
||||
for (p in params)
|
||||
if (p.opt) {
|
||||
if (extraParams > 0) {
|
||||
args2.push(args[pos++]);
|
||||
extraParams--;
|
||||
} else
|
||||
args2.push(null);
|
||||
} else
|
||||
args2.push(args[pos++]);
|
||||
args = args2;
|
||||
}
|
||||
return {
|
||||
enumName: enumName,
|
||||
fieldName: fieldName,
|
||||
index: i,
|
||||
args: args
|
||||
};
|
||||
};
|
||||
};
|
||||
var f = Reflect.makeVarArgs(f);
|
||||
var f = Reflect.makeVarArgs(f);
|
||||
|
||||
enumThingy.setEnum(fieldName, f);
|
||||
enumThingy.setEnum(fieldName, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variables.set(en.name, enumThingy);
|
||||
variables.set(en.name, enumThingy);
|
||||
}
|
||||
case ERegex(e, f):
|
||||
return new EReg(e, f);
|
||||
case EConst(c):
|
||||
@@ -964,9 +979,33 @@ class Interp {
|
||||
restore(old);
|
||||
return v;
|
||||
case EField(e, f, s):
|
||||
var field:Null<Dynamic> = expr(e);
|
||||
if(s && field == null)
|
||||
return null;
|
||||
var field:Null<Dynamic>;
|
||||
try {
|
||||
field = expr(e);
|
||||
} catch(exc:Dynamic) {
|
||||
var path = getExprPath(e);
|
||||
if(path != null) {
|
||||
var fullPath = path + "." + f;
|
||||
var cl = Type.resolveClass(fullPath);
|
||||
if(cl != null) return cl;
|
||||
var en = Type.resolveEnum(fullPath);
|
||||
if(en != null) return en;
|
||||
if(s) return null;
|
||||
error(EUnknownVariable(path));
|
||||
}
|
||||
throw exc;
|
||||
}
|
||||
if(field == null) {
|
||||
var path = getExprPath(e);
|
||||
if(path != null) {
|
||||
var fullPath = path + "." + f;
|
||||
var cl = Type.resolveClass(fullPath);
|
||||
if(cl != null) return cl;
|
||||
var en = Type.resolveEnum(fullPath);
|
||||
if(en != null) return en;
|
||||
}
|
||||
if(s) return null;
|
||||
}
|
||||
return get(field, f);
|
||||
case EBinop(op, e1, e2):
|
||||
var fop = binops.get(op);
|
||||
@@ -1447,6 +1486,20 @@ class Interp {
|
||||
};
|
||||
}
|
||||
|
||||
function getExprPath(e:Expr):Null<String> {
|
||||
switch(Tools.expr(e)) {
|
||||
case EIdent(id):
|
||||
return id;
|
||||
case EField(e2, f, _):
|
||||
var parent = getExprPath(e2);
|
||||
if(parent != null)
|
||||
return parent + "." + f;
|
||||
return null;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function get(o:Dynamic, f:String):Dynamic {
|
||||
if (o == null)
|
||||
error(EInvalidAccess(f));
|
||||
|
||||
+31
-7
@@ -1117,38 +1117,62 @@ class Parser {
|
||||
push(tk);
|
||||
mk(EClass(name, fields, extend, interfaces, nextIsFinal, nextIsPrivate), p1);
|
||||
|
||||
case "enum": // TODO: enum abstract
|
||||
case "enum":
|
||||
var isAbstract = maybe(TId("abstract"));
|
||||
var name = getIdent();
|
||||
var underlyingType:CType = null;
|
||||
|
||||
if(isAbstract) {
|
||||
ensure(TPOpen);
|
||||
if(allowTypes) {
|
||||
underlyingType = parseType();
|
||||
ensure(TPClose);
|
||||
} else {
|
||||
var t = token();
|
||||
while(t != TPClose && t != TEof) {
|
||||
t = token();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ensure(TBrOpen);
|
||||
|
||||
// TODO: optimize this
|
||||
var fields:Array<EnumField> = [];
|
||||
var fieldName:String = '';
|
||||
var enumArgs:Array<Argument> = null;
|
||||
//var tk = token();
|
||||
var fieldValue:Expr = null;
|
||||
|
||||
while(!maybe(TBrClose)) {
|
||||
var tk = token();
|
||||
|
||||
switch(tk) {
|
||||
//case TBrClose:
|
||||
// break;
|
||||
case TSemicolon | TComma:
|
||||
if(fieldName.trim().length == 0) continue;
|
||||
|
||||
fields.push({
|
||||
name: fieldName,
|
||||
args: enumArgs == null ? [] : enumArgs
|
||||
args: enumArgs == null ? [] : enumArgs,
|
||||
value: fieldValue
|
||||
});
|
||||
fieldName = '';
|
||||
enumArgs = null;
|
||||
fieldValue = null;
|
||||
case TPOpen:
|
||||
if(isAbstract) {
|
||||
error(ECustom("Enum abstract fields cannot have parameters"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
if(enumArgs != null) {
|
||||
error(ECustom("Cannot have multiple argument lists in one enum constructor"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
enumArgs = parseFunctionArgs(true);
|
||||
case TOp("="):
|
||||
if(!isAbstract) {
|
||||
error(ECustom("Only enum abstract fields can have values"), tokenMin, tokenMax);
|
||||
break;
|
||||
}
|
||||
fieldValue = parseExpr();
|
||||
default:
|
||||
if(fieldName.trim().length != 0) {
|
||||
error(ECustom("Expected comma or semicolon"), tokenMin, tokenMax);
|
||||
@@ -1159,7 +1183,7 @@ class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
mk(EEnum({ name: name, fields: fields }, false), p1);
|
||||
mk(EEnum({ name: name, fields: fields, underlyingType: underlyingType }, isAbstract), p1);
|
||||
case "cast":
|
||||
var tk = token();
|
||||
var e:Expr = null;
|
||||
|
||||
+50
-26
@@ -148,34 +148,58 @@ class Printer {
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case EEnum(en, _): // TODO: enum abstracts
|
||||
add('enum ${en.name}');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.args.length > 0) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in e.args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(')');
|
||||
case EEnum(en, isAbstract):
|
||||
if(isAbstract) {
|
||||
add('enum abstract ${en.name}(');
|
||||
if(en.underlyingType != null)
|
||||
type(en.underlyingType);
|
||||
else
|
||||
add('Int');
|
||||
add(')');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
add(";\n");
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.value != null) {
|
||||
add(" = ");
|
||||
expr(e.value);
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
} else {
|
||||
add('enum ${en.name}');
|
||||
if(en.fields.length == 0) {
|
||||
add(' {}');
|
||||
return;
|
||||
}
|
||||
tabs += "\t";
|
||||
add(" {\n");
|
||||
for(e in en.fields) {
|
||||
add(tabs);
|
||||
add(e.name);
|
||||
if(e.args.length > 0) {
|
||||
add("(");
|
||||
var first = true;
|
||||
for( a in e.args ) {
|
||||
if( first ) first = false else add(", ");
|
||||
if( a.opt ) add("?");
|
||||
add(a.name);
|
||||
addType(a.t);
|
||||
}
|
||||
add(')');
|
||||
}
|
||||
add(";\n");
|
||||
}
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
}
|
||||
|
||||
tabs = tabs.substr(1);
|
||||
add("}");
|
||||
case ECast(e, t):
|
||||
var safe = t != null;
|
||||
add("cast ");
|
||||
|
||||
Reference in New Issue
Block a user