{% 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(&$data = null, $assoc = false) { {{_self.fields_init(o)}} if(!is_null($data)) $this->import($data, $assoc); } function getClassId() { return self::CLASS_ID; } function import(&$data, $assoc = false, $root = true) { $IDX = -1; try { if(!is_array($data)) throw new Exception("Bad data: $data"); try { $IDX = 0; {{_self.import_fields(o)}} } catch(Exception $e) { if($IDX > -1) { $FIELDS = self::CLASS_FIELDS(); throw new Exception($e->getMessage() . " < {$FIELDS[$IDX]}"); } else throw $e; } if($root && $assoc && sizeof($data) > 0) throw new Exception("Junk fields: " . implode(',', array_keys($data))); } catch(Exception $e) { throw new Exception($e->getMessage() . " < ({{o.name}})"); } return $IDX; } function export($assoc = false, $virtual = false) { $data = array(); $this->fill($data, $assoc, $virtual); return $data; } function fill(&$data, $assoc = false, $virtual = false) { if($virtual) \metagen_php\array_set_value($data, $assoc, 'vclass__', $this->getClassId()); try { $__last_var = null; $__last_val = null; {{_self.export_fields(o)}} } catch(Exception $e) { throw new Exception("[{{o.name}}]\n->$__last_var\n" . serialize($__last_val) . "\n\t" . $e->getMessage()); } } } {% endmacro %} {% macro struct_fields(o) %} {%- for f in o.fields ~%} {{ _self.decl_struct_field(o, f) }} {%- endfor -%} {% endmacro %} {% macro decl_struct_field(o, f) ~%} /** @var {{f.type}}*/ {%- 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') -%} \metagen_php\val_{{f.type}}({{apply_value_filters(f.name, f.tokens, token(f, 'default')|default_value, false)}}) {%- 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, $assoc, false); {%- endif -%} {%- for f in o.fields ~%} {{data2value(f.name, f.type, '$data', '$this->', f.tokens)}} ++$IDX; {%- endfor -%} {% endmacro %} {% macro export_fields(o) %} {%- if o.parent -%} $__last_var = 'parent'; $__last_val = '<>'; parent::fill($data, $assoc, false); {%- endif -%} {%- for f in o.fields ~%} {{value2data(f.name, f.type, '$data', '$this->', 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 | first}}; 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 %}