629 lines
20 KiB
PHP
629 lines
20 KiB
PHP
|
<?php
|
||
|
|
||
|
require_once(dirname(__FILE__) . '/../../metagen.inc.php');
|
||
|
require_once(dirname(__FILE__) . '/go_tpl.inc.php');
|
||
|
|
||
|
class mtgGoCodegen extends mtgCodegen
|
||
|
{
|
||
|
function genUnit(mtgMetaInfoUnit $unit)
|
||
|
{
|
||
|
$obj = $unit->object;
|
||
|
if($obj instanceof mtgMetaRPC)
|
||
|
return $this->genRPC($obj);
|
||
|
if($obj instanceof mtgMetaEnum)
|
||
|
return $this->genEnum($obj);
|
||
|
else if($obj instanceof mtgMetaStruct)
|
||
|
return $this->genStruct($obj);
|
||
|
else
|
||
|
{
|
||
|
echo "WARN: skipping meta unit '{$obj->getId()}'\n";
|
||
|
return '';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function genEnum(mtgMetaEnum $struct)
|
||
|
{
|
||
|
$templater = new mtg_go_templater();
|
||
|
|
||
|
$repl = array();
|
||
|
$repl['%class%'] = $struct->getName();
|
||
|
$repl['%class_id%'] = $struct->getClassId();
|
||
|
|
||
|
$tpl = $templater->tpl_enum();
|
||
|
|
||
|
$this->fillEnumRepls($struct, $repl);
|
||
|
|
||
|
return mtg_fill_template($tpl, $repl);
|
||
|
}
|
||
|
|
||
|
function fillEnumRepls(mtgMetaEnum $enum, &$repl)
|
||
|
{
|
||
|
$repl['%values%'] = '';
|
||
|
$repl['%vnames_list%'] = '';
|
||
|
$repl['%values_list%'] = '';
|
||
|
|
||
|
$vnames = array();
|
||
|
$values = array();
|
||
|
$values_map = array();
|
||
|
$default_value = null;
|
||
|
$consts = array();
|
||
|
|
||
|
$enum_name = $enum->getName();
|
||
|
$map = array();
|
||
|
foreach($enum->getValues() as $vname => $value)
|
||
|
{
|
||
|
$map[$vname] = $value;
|
||
|
$vnames[] = "'$vname'";
|
||
|
$values[] = $value;
|
||
|
if(!$default_value)
|
||
|
$default_value = "$value; // $vname";
|
||
|
$consts[$value] = "{$enum->getName()}_{$vname} {$enum->getName()} = $value";
|
||
|
}
|
||
|
|
||
|
// must be sorted
|
||
|
sort($values, SORT_NUMERIC);
|
||
|
|
||
|
$repl['%vnames_list%'] = implode(',', $vnames);
|
||
|
$repl['%values_list%'] = implode(',', $values);
|
||
|
$repl['%values_map%'] = $this->genIntMap($map);
|
||
|
$repl['%default_enum_value%'] = $default_value;
|
||
|
$repl['%consts%'] = "\n " . implode("\n ", $consts) . "\n";
|
||
|
}
|
||
|
|
||
|
function preprocessField(mtgMetaStruct $struct, mtgMetaField $field) {}
|
||
|
|
||
|
function genRPC(mtgMetaRPC $rpc)
|
||
|
{
|
||
|
return $this->genRPCPacket($rpc->getReq()) .
|
||
|
$this->genRPCPacket($rpc->getRsp()) .
|
||
|
$this->genRPCReqResp($rpc);
|
||
|
}
|
||
|
|
||
|
function genRPCReqResp(mtgMetaRPC $rpc)
|
||
|
{
|
||
|
$templater = new mtg_go_templater();
|
||
|
|
||
|
$repl = array();
|
||
|
$repl['%code%'] = $rpc->getCode();
|
||
|
$repl['%rpc_name%'] = $rpc->getName();
|
||
|
$repl['%rpc_req_name%'] = $rpc->getReq()->getName();
|
||
|
$repl['%rpc_rsp_name%'] = $rpc->getRsp()->getName();
|
||
|
|
||
|
$tpl = $templater->tpl_rpc();
|
||
|
return mtg_fill_template($tpl, $repl);
|
||
|
}
|
||
|
|
||
|
function genRPCPacket(mtgMetaPacket $packet)
|
||
|
{
|
||
|
$templater = new mtg_go_templater();
|
||
|
|
||
|
$repl = array();
|
||
|
$repl['%type%'] = $packet->getName();
|
||
|
$repl['%code%'] = $packet->getNumericCode();
|
||
|
$repl['%class%'] = $packet->getName();
|
||
|
$repl['%class_id%'] = $packet->getClassId();
|
||
|
$repl['%parent_class%'] = '';
|
||
|
|
||
|
if(strpos($packet->getName(), '_RSP_') !== false)
|
||
|
$repl['%class_invert%'] = str_replace('_RSP_', '_REQ_', $packet->getName());
|
||
|
else
|
||
|
$repl['%class_invert%'] = str_replace('_REQ_', '_RSP_', $packet->getName());
|
||
|
|
||
|
$fields = $packet->getFields();
|
||
|
|
||
|
$tpl = $templater->tpl_packet();
|
||
|
|
||
|
$this->fillStructRepls($packet, $repl);
|
||
|
|
||
|
return mtg_fill_template($tpl, $repl);
|
||
|
}
|
||
|
|
||
|
function genStruct(mtgMetaStruct $struct)
|
||
|
{
|
||
|
$templater = new mtg_go_templater();
|
||
|
|
||
|
$repl = array();
|
||
|
$repl['%class%'] = $struct->getName();
|
||
|
$repl['%class_id%'] = $struct->getClassId();
|
||
|
$repl['%parent_class%'] = $struct->getParent() ? ''.$struct->getParent() : "";
|
||
|
|
||
|
$tpl = $templater->tpl_struct();
|
||
|
|
||
|
$this->fillStructRepls($struct, $repl);
|
||
|
|
||
|
$result = mtg_fill_template($tpl, $repl);
|
||
|
|
||
|
if($struct->hasToken('POD') && $struct->hasToken("id") && $struct->hasToken("table") && $struct->hasToken("owner"))
|
||
|
$result .= "\n" . str_replace(array_keys($repl), array_values($repl), $templater->tpl_collection_item());
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
function fillStructRepls(mtgMetaStruct $struct, &$repl)
|
||
|
{
|
||
|
foreach($struct->getFields() as $field)
|
||
|
$this->preprocessField($struct, $field);
|
||
|
|
||
|
$repl['%includes%'] = '';
|
||
|
$repl['%fields%'] = '';
|
||
|
$repl['%fields_names%'] = '[]string{';
|
||
|
$repl['%fields_props%'] = 'map[string]map[string]string{';
|
||
|
$repl['%fields_types%'] = 'map[string]string{';
|
||
|
$repl['%fields_reset%'] = '';
|
||
|
$repl['%read_buffer%'] = '';
|
||
|
$repl['%write_buffer%'] = '';
|
||
|
$repl['%total_top_fields%'] = sizeof($struct->getFields());
|
||
|
$repl['%ext_methods%'] = "";
|
||
|
$repl['%analytics_methods%'] = "";
|
||
|
|
||
|
$repl['%class_props%'] = 'map[string]string{' . $this->genStrMap($struct->getTokens()) . '}';
|
||
|
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
{
|
||
|
$repl['%read_buffer%'] .= "\n use_mask, mask, err := reader.TryReadMask()\n";
|
||
|
$repl['%read_buffer%'] .= "\n if err != nil {\n";
|
||
|
$repl['%read_buffer%'] .= "\n return err\n";
|
||
|
$repl['%read_buffer%'] .= "\n }\n";
|
||
|
$repl['%read_buffer%'] .= "\n self.fieldsMask = mask\n";
|
||
|
}
|
||
|
|
||
|
$parent = $struct->getParent();
|
||
|
$all_fields = mtg_get_all_fields($this->info, $struct);
|
||
|
|
||
|
foreach($all_fields as $field)
|
||
|
{
|
||
|
$name = $field->getName();
|
||
|
$repl['%fields_names%'] .= '"' . $name . '",';
|
||
|
$repl['%fields_props%'] .= '"' . $this->genFieldName($field) . '" : map[string]string{' . $this->genStrMap($field->getTokens()) . "},";
|
||
|
$field_type = $field->getType();
|
||
|
$repl['%fields_types%'] .= '"' . $name . '" : "' . $field_type . '",';
|
||
|
}
|
||
|
if($struct->hasToken('statist'))
|
||
|
{
|
||
|
$table_name = $struct->getToken('statist');
|
||
|
|
||
|
$repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Table() string {\n";
|
||
|
$repl['%analytics_methods%'] .= "\t return \"$table_name\"\n";
|
||
|
$repl['%analytics_methods%'] .= "}\n";
|
||
|
|
||
|
$repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Columns() []string {\n";
|
||
|
$repl['%analytics_methods%'] .= "\treturn []string{\n";
|
||
|
foreach($all_fields as $field)
|
||
|
{
|
||
|
if ($field->hasToken('statist_skip'))
|
||
|
continue;
|
||
|
|
||
|
$column_name = $field->hasToken('statist_alias') ? $field->getToken('statist_alias') : $field->getName();
|
||
|
|
||
|
$repl['%analytics_methods%'] .= "\t\t\"$column_name\",\n";
|
||
|
}
|
||
|
$repl['%analytics_methods%'] .= "\t}\n";
|
||
|
$repl['%analytics_methods%'] .= "}\n";
|
||
|
|
||
|
$repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Values() []interface{} {\n";
|
||
|
$repl['%analytics_methods%'] .= "\treturn []interface{}{\n";
|
||
|
foreach($all_fields as $field)
|
||
|
{
|
||
|
if ($field->hasToken('statist_skip'))
|
||
|
continue;
|
||
|
|
||
|
$repl['%analytics_methods%'] .= "\t\tself." . ucfirst($field->getName()) . ",\n";
|
||
|
}
|
||
|
$repl['%analytics_methods%'] .= "\t}\n";
|
||
|
$repl['%analytics_methods%'] .= "}\n";
|
||
|
}
|
||
|
|
||
|
$repl['%read_buffer%'] .= "\n _cont_size, err := reader.GetContainerSize()";
|
||
|
$repl['%read_buffer%'] .= "\n if err != nil {";
|
||
|
$repl['%read_buffer%'] .= "\n return err";
|
||
|
$repl['%read_buffer%'] .= "\n }";
|
||
|
|
||
|
$optional = 0;
|
||
|
foreach($struct->getFields() as $field)
|
||
|
{
|
||
|
if($field->hasToken('optional'))
|
||
|
$optional++;
|
||
|
}
|
||
|
$initial_fields_amount = count($struct->getFields()) - $optional;
|
||
|
$repl['%read_buffer%'] .= "\n if _cont_size < $initial_fields_amount {";
|
||
|
$repl['%read_buffer%'] .= "\n _cont_size = $initial_fields_amount";
|
||
|
$repl['%read_buffer%'] .= "\n }";
|
||
|
|
||
|
if($struct->hasToken('POD'))
|
||
|
{
|
||
|
$fields = $all_fields;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if($parent = $struct->getParent())
|
||
|
{
|
||
|
$repl['%read_buffer%'] .= "\n if err := self." . $parent . ".ReadFields(reader); err != nil { return err }";
|
||
|
$repl['%write_buffer%'] .= "\n if err := self." . $parent . ".WriteFields(writer); err != nil { return err }";
|
||
|
}
|
||
|
$fields = $struct->getFields();
|
||
|
}
|
||
|
|
||
|
$field_index = -1;
|
||
|
foreach($fields as $field)
|
||
|
{
|
||
|
++$field_index;
|
||
|
$options = $this->readFieldOptions($field);
|
||
|
|
||
|
$repl['%fields%'] .= "\n " . $this->genFieldDecl($field);
|
||
|
$repl['%fields_reset%'] .= "\n " . $this->genFieldReset($field);
|
||
|
$repl['%read_buffer%'] .= "\n if _cont_size <= 0 {";
|
||
|
$repl['%read_buffer%'] .= "\n return nil";
|
||
|
$repl['%read_buffer%'] .= "\n }";
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
$repl['%read_buffer%'] .= "\n if !use_mask {";
|
||
|
$repl['%read_buffer%'] .= "\n _cont_size--";
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
$repl['%read_buffer%'] .= "\n }";
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
$repl['%read_buffer%'] .= "\n if !use_mask || (use_mask && self.HasValue($field_index)) {";
|
||
|
$repl['%read_buffer%'] .= "\n " . $this->genBufRead($field->getName(), $options['fname'], $field->getType(), $options['buf'], $field->getTokens());
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
$repl['%read_buffer%'] .= "\n }";
|
||
|
$repl['%write_buffer%'] .= "\n " . $this->genBufWrite($field, "writer", $field->hasToken("virtual"));
|
||
|
}
|
||
|
|
||
|
$repl['%fields%'] = trim($repl['%fields%'], "\n ");
|
||
|
|
||
|
$repl['%fields_names%'] .= '}';
|
||
|
$repl['%fields_props%'] .= '}';
|
||
|
$repl['%fields_types%'] .= '}';
|
||
|
|
||
|
$repl['%import_from_mysql%'] = '';
|
||
|
$repl["%export_to_arr%"] = "";
|
||
|
if($struct->hasToken('POD') && $struct->hasToken("table"))
|
||
|
{
|
||
|
$ind = 0;
|
||
|
|
||
|
$repl['%import_from_mysql%'] .= "\n row := data.(".$struct->getName().")";
|
||
|
foreach($all_fields as $field)
|
||
|
{
|
||
|
$name = $this->genFieldName($field);
|
||
|
$repl['%import_from_mysql%'] .= sprintf("\n self.%s = row.%s", $name, $name);
|
||
|
$repl['%export_to_arr%'] .= sprintf("\n data[%d] = self.%s", $ind, $name);
|
||
|
$ind++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$repl["%table_name%"] = $struct->getToken("table");
|
||
|
$repl["%owner%"] = $struct->getToken("owner");
|
||
|
$repl["%id_field_name%"] = $struct->getToken("id");
|
||
|
$repl["%id_field%"] = ucfirst($struct->getToken("id"));
|
||
|
|
||
|
if($struct->hasToken("bitfields"))
|
||
|
{
|
||
|
$repl['%fields%'] .= "\nfieldsMask uint64\n";
|
||
|
|
||
|
$repl['%fields_reset%'] .= "\nself.fieldsMask = 0\n";
|
||
|
|
||
|
$repl['%ext_methods%'] .= "func(self *".$struct->getName().") HasValue(index uint64) bool {\n";
|
||
|
$repl['%ext_methods%'] .= " value := uint64(1 << index)\n";
|
||
|
$repl['%ext_methods%'] .= " return (self.fieldsMask & value) > 0\n";
|
||
|
$repl['%ext_methods%'] .= "}\n";
|
||
|
|
||
|
$repl['%ext_methods%'] .= "func(self *".$struct->getName().") SetFieldChanged(index uint64) {\n";
|
||
|
$repl['%ext_methods%'] .= " value := uint64(1 << index)\n";
|
||
|
$repl['%ext_methods%'] .= " self.fieldsMask |= value\n";
|
||
|
$repl['%ext_methods%'] .= "}\n";
|
||
|
|
||
|
$repl['%ext_methods%'] .= "func(self *".$struct->getName().") IsMaskFilled() bool {\n";
|
||
|
$repl['%ext_methods%'] .= " return self.fieldsMask > 0\n";
|
||
|
$repl['%ext_methods%'] .= "}\n";
|
||
|
|
||
|
$repl['%ext_methods%'] .= "func(self *".$struct->getName().") GetMask() uint64 {\n";
|
||
|
$repl['%ext_methods%'] .= " return self.fieldsMask\n";
|
||
|
$repl['%ext_methods%'] .= "}\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function readFieldOptions(mtgMetaField $field)
|
||
|
{
|
||
|
return array(
|
||
|
'fname' => 'self.'.ucfirst($field->getName()),
|
||
|
'buf' => "reader",
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function genReadBuiltinField($name, $fname, mtgType $type, $buf, array $tokens)
|
||
|
{
|
||
|
return $this->genRead($tokens, $buf.'.Read'.$this->genBuiltinTypePrefix($type).'(&'.$fname.', "'.$name.'")');
|
||
|
}
|
||
|
|
||
|
function genBufRead($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
|
||
|
{
|
||
|
$str = '';
|
||
|
|
||
|
if($type instanceof mtgBuiltinType)
|
||
|
{
|
||
|
$str .= $this->genReadBuiltinField($name, $fname, $type, $buf, $tokens);
|
||
|
}
|
||
|
else if($type instanceof mtgMetaEnum)
|
||
|
{
|
||
|
$str .= $this->genRead($tokens, "{$buf}.ReadI32((*int32)(&{$fname}), \"$name\")");
|
||
|
$str .= "\n if !{$fname}.IsValid() { return errors.Errorf(\"Bad enum value %d for $name\", $fname) }";
|
||
|
}
|
||
|
else if($type instanceof mtgMetaStruct)
|
||
|
{
|
||
|
if(array_key_exists('virtual', $tokens))
|
||
|
$str .= "if v, err := meta.ReadStructGeneric($buf, CreateById, \"{$name}\"); err != nil { return err } else { {$fname} = v.(I{$type}) }";
|
||
|
else
|
||
|
$str .= $this->genRead($tokens, "meta.ReadStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
|
||
|
}
|
||
|
else if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$is_virtual = array_key_exists("virtual", $tokens);
|
||
|
$native_type = $this->genNativeType($type->getValue(), $tokens);
|
||
|
$offset = "\n ";
|
||
|
$str .= "/*[]{$name}*/";
|
||
|
$str .= $offset . $this->genRead($tokens, "{$buf}.BeginContainer(\"$name\")");
|
||
|
//we don't want to propagate 'optionalness' below
|
||
|
unset($tokens['optional']);
|
||
|
$str .= $offset . "_{$name}_size, err := {$buf}.GetContainerSize()";
|
||
|
$str .= $offset . "if err != nil { return err }";
|
||
|
|
||
|
$need_new = !$is_virtual && $type->getValue() instanceof mtgMetaStruct;
|
||
|
|
||
|
$str .= $offset . "for ; _{$name}_size > 0; _{$name}_size-- {";
|
||
|
$offset = "\n ";
|
||
|
$str .= $offset . "var tmp_{$name} {$native_type}";
|
||
|
|
||
|
$str .= $offset . $this->genBufRead("", "tmp_{$name}", $type->getValue(), $buf, $tokens, $is_virtual);
|
||
|
$str .= $offset . "{$fname} = append({$fname}, ".($need_new?"&":"")."tmp_{$name})";
|
||
|
|
||
|
$offset = "\n ";
|
||
|
$str .= $offset . "}";
|
||
|
$str .= $offset . $this->genRead($tokens, "{$buf}.EndContainer()");
|
||
|
$str .= "\n";
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '{$type}'");
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genRead(array $tokens, $op)
|
||
|
{
|
||
|
return "if err := $op; err != nil { return " . (array_key_exists("optional", $tokens) ? "/*optional*/nil" : "err"). " }";
|
||
|
}
|
||
|
|
||
|
function genWrite($op)
|
||
|
{
|
||
|
return "if err := $op; err != nil { return err }";
|
||
|
}
|
||
|
|
||
|
function genBufWrite(mtgMetaField $field, $buf, $is_ptr = false)
|
||
|
{
|
||
|
return $this->genBufWriteEx($field->getName(), "self.".ucfirst($field->getName()), $field->getType(), $buf, $field->getTokens(), $is_ptr);
|
||
|
}
|
||
|
|
||
|
function genBufWriteEx($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false)
|
||
|
{
|
||
|
$str = '';
|
||
|
|
||
|
if($type instanceof mtgBuiltinType)
|
||
|
{
|
||
|
$str .= $this->genWrite("{$buf}.Write".$this->genBuiltinTypePrefix($type)."($fname, \"$name\")")."\n";
|
||
|
}
|
||
|
else if($type instanceof mtgMetaEnum)
|
||
|
{
|
||
|
$str .= $this->genWrite("{$buf}.WriteI32(int32($fname), \"$name\")");
|
||
|
}
|
||
|
else if($type instanceof mtgMetaStruct)
|
||
|
{
|
||
|
if(array_key_exists('virtual', $tokens))
|
||
|
$str .= $this->genWrite("meta.WriteStructGeneric($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
|
||
|
else
|
||
|
$str .= $this->genWrite("meta.WriteStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")");
|
||
|
}
|
||
|
else if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$is_virtual = array_key_exists("virtual", $tokens);
|
||
|
|
||
|
$str .= "{$buf}.BeginContainer(\"{$name}\")\n";
|
||
|
$str .= " for _, v := range({$fname}) {\n";
|
||
|
$str .= " ".$this->genBufWriteEx("", "v", $type->getValue(), $buf, $tokens, true)."\n";
|
||
|
$str .= " }\n";
|
||
|
$str .= " ".$this->genWrite("{$buf}.EndContainer()")."\n";
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '$type'");
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genFieldDecl(mtgMetaField $field)
|
||
|
{
|
||
|
return $this->genFieldName($field) . " " .
|
||
|
$this->genFieldNativeType($field) .
|
||
|
($field->getName()[0] != '_' ? " `json:\"{$field->getName()}\"`" : "")
|
||
|
;
|
||
|
}
|
||
|
|
||
|
function genFieldName(mtgMetaField $field)
|
||
|
{
|
||
|
return ucfirst($field->getName());
|
||
|
}
|
||
|
|
||
|
function genFieldReset(mtgMetaField $field)
|
||
|
{
|
||
|
$tokens = $field->getTokens();
|
||
|
|
||
|
$str = '';
|
||
|
$name = $this->genFieldName($field);
|
||
|
|
||
|
$type = $field->getType();
|
||
|
|
||
|
if($type instanceof mtgBuiltinType)
|
||
|
{
|
||
|
if($type->isNumeric())
|
||
|
{
|
||
|
//NOTE: numeric check is against str2num
|
||
|
if(array_key_exists('default', $tokens) && is_numeric($tokens['default']))
|
||
|
$str .= "self.$name = ".$tokens['default'];
|
||
|
else
|
||
|
$str .= " self.$name = 0";
|
||
|
}
|
||
|
else if($type->isString())
|
||
|
{
|
||
|
if(array_key_exists('default', $tokens))
|
||
|
$str .= "self.$name = ".$tokens['default'];
|
||
|
else
|
||
|
$str .= "self.$name = \"\"";
|
||
|
}
|
||
|
else if($type->isBool())
|
||
|
{
|
||
|
if(array_key_exists('default', $tokens))
|
||
|
$str .= "self.$name = ".$tokens['default'];
|
||
|
else
|
||
|
$str .= "self.$name = false";
|
||
|
}
|
||
|
else if($type->isBlob())
|
||
|
{
|
||
|
if(array_key_exists('default', $tokens))
|
||
|
$str .= "self.$name = ".$tokens['default'];
|
||
|
else
|
||
|
$str .= "self.$name = nil";
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '$type'");
|
||
|
}
|
||
|
else if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$str = "if self.$name == nil { \nself.$name = make(".$this->genFieldNativeType($field).",0) \n}\n ";
|
||
|
$str .= "self.$name = self.{$name}[0:0]";
|
||
|
}
|
||
|
else if($type instanceof mtgMetaEnum)
|
||
|
{
|
||
|
if(array_key_exists('default', $tokens))
|
||
|
$str = "self.$name = ".$this->genFieldNativeType($field)."_".trim($tokens['default'], '"');
|
||
|
else
|
||
|
$str = "self.$name = 0";
|
||
|
}
|
||
|
else if($type instanceof mtgMetaStruct)
|
||
|
{
|
||
|
$is_virtual = array_key_exists("virtual", $tokens);
|
||
|
if($is_virtual)
|
||
|
$str .= "self.$name = New".ltrim($this->genFieldNativeType($field),'I')."() ";
|
||
|
else
|
||
|
$str .= "self.$name.Reset()";
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '$type'");
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genFieldNativeType(mtgMetaField $field)
|
||
|
{
|
||
|
return $this->genNativeType($field->getType(), $field->getTokens());
|
||
|
}
|
||
|
|
||
|
function genNativeType(mtgType $type, array $tokens = array())
|
||
|
{
|
||
|
if($type instanceof mtgArrType)
|
||
|
{
|
||
|
$vtype = $type->getValue();
|
||
|
|
||
|
$native = $this->genNativePlainType($vtype);
|
||
|
|
||
|
$str = "[]";
|
||
|
if(array_key_exists("virtual", $tokens))
|
||
|
$str .= "I";
|
||
|
else
|
||
|
$str .= $vtype instanceof mtgMetaStruct ? "*" : "";
|
||
|
|
||
|
$str .= $native;
|
||
|
|
||
|
return $str;
|
||
|
}
|
||
|
else
|
||
|
return $this->genNativePlainType($type, $tokens);
|
||
|
}
|
||
|
|
||
|
function genBuiltinTypePrefix(mtgBuiltinType $type)
|
||
|
{
|
||
|
switch($type->getName())
|
||
|
{
|
||
|
case "string":
|
||
|
return "String";
|
||
|
case "bool":
|
||
|
return "Bool";
|
||
|
case "blob":
|
||
|
return "Blob";
|
||
|
case "float":
|
||
|
return "Float";
|
||
|
case "double":
|
||
|
return "Double";
|
||
|
case "uint64":
|
||
|
return "U64";
|
||
|
case "int64":
|
||
|
return "I64";
|
||
|
case "uint":
|
||
|
case "uint32":
|
||
|
return "U32";
|
||
|
case "uint16":
|
||
|
return "U16";
|
||
|
case "uint8":
|
||
|
return "U8";
|
||
|
case "int":
|
||
|
case "int32":
|
||
|
return "I32";
|
||
|
case "int16":
|
||
|
return "I16";
|
||
|
case "int8":
|
||
|
return "I8";
|
||
|
default:
|
||
|
throw new Exception("Unknown type '{$type}'");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function genNativePlainType(mtgType $type, array $tokens = array())
|
||
|
{
|
||
|
if($type instanceof mtgBuiltinType)
|
||
|
{
|
||
|
if($type->isFloat())
|
||
|
return "float32";
|
||
|
else if($type->isDouble())
|
||
|
return "float64";
|
||
|
else if($type->isBlob())
|
||
|
return "[]byte";
|
||
|
else
|
||
|
return $type->getName();
|
||
|
}
|
||
|
else if($type instanceof mtgMetaEnum)
|
||
|
return $type->getName();
|
||
|
else if($type instanceof mtgMetaStruct)
|
||
|
{
|
||
|
if(array_key_exists("virtual", $tokens))
|
||
|
return "I{$type->getName()}";
|
||
|
else
|
||
|
return $type->getName();
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '$type'");
|
||
|
}
|
||
|
|
||
|
function genStrMap(array $source)
|
||
|
{
|
||
|
$str = '';
|
||
|
foreach($source as $k => $v)
|
||
|
$str .= '"' . $k . '": "' . ($v ? str_replace('"', '\\"', $v) : "") . '",';
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function genIntMap(array $source)
|
||
|
{
|
||
|
$str = '';
|
||
|
foreach($source as $k => $v)
|
||
|
$str .= "\"$k\": {$v},";
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function offset($num = 1)
|
||
|
{
|
||
|
return str_repeat(" ", $num);
|
||
|
}
|
||
|
}
|