diff --git a/src/codegen.inc.php b/src/codegen.inc.php index 441f567..bc8cb0d 100644 --- a/src/codegen.inc.php +++ b/src/codegen.inc.php @@ -96,6 +96,12 @@ function _add_twig_support(\Twig\Environment $twig) return $opts; } )); + $twig->addFunction(new \Twig\TwigFunction('buf2var', + function($name, $fname, $type, $buf, $tokens, $is_ptr) + { + return buf2var($name, $fname, $type, $buf, $tokens, $is_ptr); + } + )); $twig->addFilter(new \Twig\TwigFilter('go_type', function($type, $tokens) { @@ -122,7 +128,7 @@ function go_type(\mtgType $type, array $tokens = array()) if(array_key_exists("virtual", $tokens)) $str .= "I"; else - $str .= $vtype instanceof mtgMetaStruct ? "*" : ""; + $str .= $vtype instanceof \mtgMetaStruct ? "*" : ""; $str .= $native; @@ -152,3 +158,96 @@ function go_type(\mtgType $type, array $tokens = array()) throw new Exception("Unknown type '$type'"); } +function builtin_type_prefix(\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 buf2var($name, $fname, \mtgType $type, $buf, array $tokens = array(), $is_ptr = false) +{ + $str = ''; + + if($type instanceof \mtgBuiltinType) + { + $str .= _read_op($tokens, $buf.'.Read'.builtin_type_prefix($type).'(&'.$fname.', "'.$name.'")'); + } + else if($type instanceof \mtgMetaEnum) + { + $str .= _read_op($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 .= _read_op($tokens, "meta.ReadStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")"); + } + else if($type instanceof \mtgArrType) + { + $is_virtual = array_key_exists("virtual", $tokens); + $native_type = go_type($type->getValue(), $tokens); + $offset = "\n "; + $str .= "/*[]{$name}*/"; + $str .= $offset . _read_op($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 . buf2var("", "tmp_{$name}", $type->getValue(), $buf, $tokens, $is_virtual); + $str .= $offset . "{$fname} = append({$fname}, ".($need_new?"&":"")."tmp_{$name})"; + + $offset = "\n "; + $str .= $offset . "}"; + $str .= $offset . _read_op($tokens, "{$buf}.EndContainer()"); + $str .= "\n"; + } + else + throw new Exception("Unknown type '{$type}'"); + + return $str; +} + +function _read_op(array $tokens, $op) +{ + return "if err := $op; err != nil { return " . (array_key_exists("optional", $tokens) ? "/*optional*/nil" : "err"). " }"; +} diff --git a/tpl/macro.twig b/tpl/macro.twig index 9a23fc7..27e0754 100644 --- a/tpl/macro.twig +++ b/tpl/macro.twig @@ -150,7 +150,31 @@ fieldsMask meta.FieldsMask //@bitfields support {%- if o.parent ~%} if err := self.{{o.parent.name}}.ReadFields(reader); err != nil { return err } -{%- endif -%} +{%- endif ~%} + +{%- for f in o.fields ~%} + if _cont_size <= 0 { + return nil + } + + {%if has_token(o, 'bitfields') ~%} + if !use_mask { + {%- endif ~%} + + _cont_size-- + + {%if has_token(o, 'bitfields') ~%} + } + if !use_mask || (use_mask && self.HasValue({{loop.index0}})) { + {%- endif ~%} + + {{buf2var(f.name, 'self.' ~ f.name|ucfirst, f.type, 'reader', f.tokens, false)}} + + {%if has_token(o, 'bitfields') ~%} + } + {%- endif -%} + +{%- endfor -%} {% endmacro %}