{% macro decl_units(meta) %} {%- for u in meta.getunits ~%} {%- if u.object is instanceof('\\mtgMetaStruct') -%} {{ _self.decl_struct(u.object) }} {%- elseif u.object is instanceof('\\mtgMetaEnum') -%} {{ _self.decl_enum(u.object) }} {%- endif ~%} {%- endfor ~%} {% endmacro %} {% macro decl_struct(o) %} class {{o.name}} {{o.parent ? 'extends ' ~ o.parent.name}} { const CLASS_ID = {{o.classid}}; {{ _self.struct_fields(o) }} static function CLASS_PROPS() { static $props = {{o.tokens|var_export}}; return $props; } static function CLASS_FIELDS() { static $flds = null; if($flds === null) $flds = {{_self.fields_names(o)}}; return $flds; } static function CLASS_FIELDS_TYPES() { static $flds = null; if($flds === null) $flds = {{_self.fields_types(o)}}; return $flds; } static function CLASS_FIELDS_PROPS() { static $flds = null; if($flds === null) $flds = {{_self.fields_props(o)}}; return $flds; } function __construct() { {{_self.fields_init(o)}} } function getClassId() { return self::CLASS_ID; } function import(array &$data, bool $assoc = false) { if($assoc) { self::normalize($data, $normalized); $this->_import($normalized, true); } else $this->_import($data, true); } function _import(array &$data, $root = true) : int { if(!is_array($data)) throw new Exception("Bad data: $data"); if($root) reset($data); $IDX = 0; try { {{_self.import_fields(o)}} } catch(Exception $e) { $FIELDS = self::CLASS_FIELDS(); throw new Exception($e->getMessage() . " < {$FIELDS[$IDX]} < ({{o.name}})"); } return $IDX; } function export(bool $assoc = false, bool $virtual = false) : array { $data = array(); $this->_export($data, $assoc, $virtual); return $data; } function _export(array &$data, bool $assoc = false, $virtual = false) { if($virtual) $data[] = $this->getClassId(); {{_self.export_fields(o)}} } static function normalize(array &$data, array &$mapped, bool $check_junk = true, bool $root = true) : int { $IDX = -1; try { $IDX = 0; {%- if o.parent ~%} $IDX = parent::normalize($data, $mapped, $check_junk, false); {%- endif ~%} {%- for f in o.fields ~%} {{data_normalize(f.name, f.type, '$data', '$mapped', f.tokens)}} ++$IDX; {%- endfor ~%} } catch(Exception $e) { $FIELDS = self::CLASS_FIELDS(); throw new Exception($e->getMessage() . " < {$FIELDS[$IDX]} < ({{o.name}})"); } if($root && $check_junk && sizeof($data) > 0) throw new Exception("Junk fields: " . implode(',', array_keys($data))); return $IDX; } } {% endmacro %} {% macro struct_fields(o) %} {%- for f in o.fields ~%} {{ _self.decl_struct_field(o, f) }} {%- endfor -%} {% endmacro %} {% macro decl_struct_field(o, f) ~%} {%- if f.type is instanceof('\\mtgMetaStruct') ~%} /** @var {{f.type}}|null*/ {%- endif -%} {%- if f.type is instanceof('\\mtgBuiltinType') and f.type.isstring ~%} public ${{f.name}} = ''; {%- elseif f.type is instanceof('\\mtgArrType') ~%} public ${{f.name}} = []; {%- else ~%} public ${{f.name}}; {%- endif -%} {% endmacro %} {% macro fields_names(o) %} {%- if o.parent -%} array_merge(parent::CLASS_FIELDS(), {%- endif -%} [ {%- for f in o.fields -%} '{{f.name}}' {{not loop.last ? ','}} {%- endfor -%} ] {%- if o.parent -%} ) {%- endif -%} {% endmacro %} {% macro fields_types(o) %} {%- if o.parent -%} array_merge(parent::CLASS_FIELDS_TYPES(), {%- endif -%} [ {%- for f in o.fields -%} '{{f.name}}' => '{{f.type}}' {{not loop.last ? ','}} {%- endfor -%} ] {%- if o.parent -%} ) {%- endif -%} {% endmacro %} {% macro fields_props(o) %} {%- if o.parent -%} array_merge(parent::CLASS_FIELDS_PROPS(), {%- endif -%} [ {%- for f in o.fields -%} '{{f.name}}' => {{f.tokens|var_export}} {{not loop.last ? ','}} {%- endfor -%} ] {%- if o.parent -%} ) {%- endif -%} {% endmacro %} {% macro field_init_value(o, f) %} {%- if f.type is instanceof('\\mtgMetaStruct') ~%} {%- if has_token(f, 'default') and token(f, 'default') == 'null' -%} null {%- else -%} new {{f.type}}() {%- endif -%} {%- elseif f.type is instanceof('\\mtgMetaEnum') ~%} {%- if has_token(f, 'default') -%} {{f.type}}::{{token(f, 'default')|replace({'"' : ''})|default_value}} {%- else -%} {{f.type}}::DEFAULT_VALUE {%- endif -%} {%- elseif f.type is instanceof('\\mtgArrType') ~%} [] {%- elseif f.type is instanceof('\\mtgBuiltinType') ~%} {%- if has_token(f, 'default') -%} {{token(f, 'default')|default_value}} {%- elseif f.type.isstring -%} '' {%- else -%} 0 {%- endif -%} {%- else -%} {{Error("Uknown type: " ~ f.type)}} {%- endif -%} {% endmacro %} {% macro field_init(o, f) %} $this->{{f.name}} = {{_self.field_init_value(o, f)}}; {% endmacro %} {% macro fields_init(o) %} {%- if o.parent -%} parent::__construct(); {%- endif -%} {%- for f in o.fields ~%} {{_self.field_init(o, f)}} {%- endfor -%} {% endmacro %} {% macro import_fields(o) %} {%- if o.parent -%} $IDX = parent::_import($data, false); {%- endif -%} {%- for f in o.fields ~%} {{data2value('$this->'~f.name, f.type, '$data', f.tokens)}} ++$IDX; {%- endfor -%} {% endmacro %} {% macro export_fields(o) %} {%- if o.parent -%} parent::_export($data, $assoc, false); {%- endif -%} {%- for f in o.fields ~%} {{value2data('$this->'~f.name, f.name, f.type, '$data', f.tokens)}} {%- endfor -%} {% endmacro %} {% macro decl_enum(o) %} class {{o.name}} { const CLASS_ID = {{o.classid}}; {{ _self.enum_values(o) }} const DEFAULT_VALUE = {{o.values|length > 0 ? o.values | first : 0}}; function getClassId() { return self::CLASS_ID; } static function isValueValid($value) { $values_list = self::getValuesList(); return in_array($value, self::$values_list_); } static private $values_map_; static function getValueByName($name) { if(!self::$values_map_) { self::$values_map_ = array( {{ _self.enum_values_map(o) }} ); } if(!isset(self::$values_map_[$name])) throw new Exception("Value with name '$name' isn't defined in enum {{o.name}}. Accepted: " . implode(',', self::getNamesList())); return self::$values_map_[$name]; } static private $names_map_; static function getNameByValue($value) { if(!self::$names_map_) { self::$names_map_ = array( {{ _self.enum_names_map(o) }} ); } if(!isset(self::$names_map_[$value])) throw new Exception("Value $value isn't defined in enum {{o.name}}. Accepted: " . implode(',', self::getValuesList())); return self::$names_map_[$value]; } // throws exception if $value is not valid numeric enum value static function checkValidity($value) { if(!is_numeric($value)) throw new Exception("Numeric expected but got $value"); if(!self::isValueValid($value)) throw new Exception("Numeric value '$value' isn't value from enum {{o.name}}. Accepted numerics are " . implode(',', self::getValuesList()) . " but better to use one of names instead: " . implode(',', self::getNamesList())); } static private $values_list_; static function getValuesList() { if(!self::$values_list_) { self::$values_list_ = array( {{ _self.enum_values_list(o) }} ); } return self::$values_list_; } static private $names_list_; static function getNamesList() { if(!self::$names_list_) { self::$names_list_ = array( {{ _self.enum_names_list(o) }} ); } return self::$names_list_; } } {% endmacro %} {% macro enum_values(o) %} {%- for n,v in o.values ~%} const {{n}} = {{v}}; {%- endfor ~%} {% endmacro %} {% macro enum_values_map(o) %} {%- for n,v in o.values ~%} '{{n}}' => {{v}}, {%- endfor ~%} {% endmacro %} {% macro enum_names_map(o) %} {%- for n,v in o.values ~%} {{v}} => '{{n}}', {%- endfor ~%} {% endmacro %} {% macro enum_values_list(o) %} {%- for v in o.values ~%} {{v}}, {%- endfor ~%} {% endmacro %} {% macro enum_names_list(o) %} {%- for n,v in o.values ~%} '{{n}}', {%- endfor ~%} {% endmacro %} {% macro class_map(meta) %} {%- for u in meta.getunits ~%} case {{u.object.classid}} : return "{{u.object.name}}"; {%- endfor ~%} {% endmacro %}