Last active
January 3, 2016 07:19
-
-
Save nadako/8428429 to your computer and use it in GitHub Desktop.
Incomplete backport of @:enum abstracts from Haxe 3.1 to Haxe 3.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import haxe.macro.Context; | |
| import haxe.macro.Expr; | |
| import haxe.macro.Type; | |
| using haxe.macro.TypeTools; | |
| /** | |
| * Частичный бекпорт функциональности @:enum abstract из Haxe 3.1 | |
| * | |
| * @:enum abstract'ы - элегантная замена набору констант с проверкой значений на этапе компиляции. | |
| * | |
| * См. http://new.haxe.org/manual/types-abstract-enum.html для подробностей. | |
| * | |
| * Отличия от полноценного @:enum abstract из Haxe 3.1: | |
| * - вместо @:enum нужно писать @:build(EnumAbstract.build()) | |
| * - нужно писать static var вместо просто var (иначе до build-макроса дело даже не дойдет) | |
| * - не поддерживает типы параметров (но нам и не надо - нас вообще интересует тупо Int/String) | |
| * - не поддерживает дополнительные поля (нам и не надо, если что - сделаем) | |
| * - нельзя обращаться к константам без префикса класса (нет поддержки в компиляторе версии 3.0) | |
| * - нет проверки на полность при switch (нет поддержки в компиляторе версии 3.0) | |
| * | |
| * Когда перейдем на новый Haxe - это нужно будет выпилить и юзать встроенные @:enum абстракты. | |
| * | |
| * Пример использования: | |
| * | |
| * @:build(EnumAbstract.build()) | |
| * abstract BattleState(Int) | |
| * { | |
| * static var Start = 0; | |
| * static var Progress = 1; | |
| * static var End = 2; | |
| * } | |
| * | |
| */ | |
| class EnumAbstract | |
| { | |
| macro static public function build():Array<Field> | |
| { | |
| // получаем тип абстракта | |
| var a = switch(Context.getLocalClass().get().kind) | |
| { | |
| case KAbstractImpl(a): a; | |
| default: throw "EnumAbstract.build cannot be used on non-abstract"; | |
| }; | |
| var tA = a.get(); | |
| if (tA.params.length > 0) | |
| Context.error("EnumAbstract does not support type parameters", tA.pos); | |
| var ctA = TAbstract(a, []); | |
| // получаем рантайм-тип абстракта | |
| var tThis = tA.type; | |
| // итерируем по полям | |
| var fields = Context.getBuildFields(); | |
| for (field in fields) | |
| { | |
| switch(field.kind) | |
| { | |
| // для всех указанных переменных проверяем тип и делаем преобразование в нечто что можно юзать | |
| case FVar(t, e): | |
| if (e == null) | |
| Context.error("Value required", field.pos); | |
| if (t != null) | |
| Context.error("Type must be inferred", field.pos); | |
| var tE = Context.typeof(e); | |
| if (!Context.unify(tE, tThis)) | |
| Context.error('${tE.toString()} should be ${tThis.toString()}', e.pos); | |
| field.access = [APublic, AStatic, AInline]; | |
| field.kind = FVar(ctA.toComplexType(), macro untyped $e); | |
| default: | |
| } | |
| } | |
| return fields; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment