blob: ae7094b27774b75e059e89f4ce9b5e5f3f0f6890 [file] [log] [blame]
{{/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/}}
{{Include "common.tmpl"}}
{{/*
-------------------------------------------------------------------------------
Emits the fully qualified name (prefixed with the package) of the specified
type or variable.
-------------------------------------------------------------------------------
*/}}
{{define "Go.QualifiedName"}}{{Global "module"}}{{$.Name}}{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the go type for the provided AST type or expression.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Type"}}
{{if not (IsType $)}}{{Template "Go.Type" (TypeOf $)}}
{{else if IsAny $}}interface{}
{{else if IsPseudonym $}}{{Template "Go.QualifiedName" $}}
{{else if IsStaticArray $}}{{Template "Go.QualifiedName" $}}
{{else if IsMap $}}{{Template "Go.QualifiedName" $}}
{{else if IsClass $}}{{Template "Go.QualifiedName" $}}
{{else if IsEnum $}}{{Template "Go.QualifiedName" $}}
{{else if IsPointer $}}{{Template "Go.QualifiedName" $}}
{{else if IsSlice $}}{{Template "Go.QualifiedName" $}}
{{else if IsReference $}}(*{{Template "Go.Type" $.To}})
{{else if IsBool $}}bool
{{else if IsInt $}}int64
{{else if IsUint $}}uint64
{{else if IsChar $}}byte
{{else if IsU8 $}}uint8
{{else if IsS8 $}}int8
{{else if IsU16 $}}uint16
{{else if IsS16 $}}int16
{{else if IsF32 $}}float32
{{else if IsU32 $}}uint32
{{else if IsS32 $}}int32
{{else if IsF64 $}}float64
{{else if IsU64 $}}uint64
{{else if IsS64 $}}int64
{{else if IsString $}}string
{{else if IsVoid $}}void
{{else}}{{Error "macro Type called with unsupported type: %s" $.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the go default value for the provided AST type.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Null"}}
{{AssertType $ "Type"}}
{{ if IsPointer $}}{{Template "Go.Type" $}}{}
{{else if IsReference $}}{{Template "Go.Type" $}}(nil)
{{else if IsBool $}}false
{{else if IsInt $}}int(0)
{{else if IsUint $}}uint(0)
{{else if IsS8 $}}int8(0)
{{else if IsU8 $}}uint8(0)
{{else if IsS16 $}}int16(0)
{{else if IsU16 $}}uint16(0)
{{else if IsS32 $}}int32(0)
{{else if IsU32 $}}uint32(0)
{{else if IsF32 $}}float32(0)
{{else if IsS64 $}}int64(0)
{{else if IsU64 $}}uint64(0)
{{else if IsF64 $}}float64(0)
{{else if IsString $}}""
{{else if IsPseudonym $}}{{Template "Go.Type" $}}({{Template "Go.Null" $.To}})
{{else}}{{Error "macro Type called with unsupported type: %s" $.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to decode the specified type and variable name.
ErrHandler can control what should happen if there's a decode error. By
default ErrHandler is set to "return err".
-------------------------------------------------------------------------------
*/}}
{{define "Go.Decode"}}
{{AssertType $.Type "Type" }}
{{AssertType $.Name "string" }}
{{AssertType $.ErrHandler "string" "nil"}}
{{ if not $.ErrHandler}}{{Template "Go.Decode" "Type" $.Type "Name" $.Name "ErrHandler" "return err"}}
{{else if IsStaticArray $.Type}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsMap $.Type}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsClass $.Type}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsPointer $.Type}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsPseudonym $.Type}}
{{$ty := $.Type.To}}
{{ if IsStaticArray $ty}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsMap $ty}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsClass $ty}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsPointer $ty}}if err := d.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else}}{{Template "Go.DecodePOD" "Type" $ty "Name" $.Name "ErrHandler" $.ErrHandler "Cast" $.Type}}
{{end}}
{{else}}{{Template "Go.DecodePOD" "Type" $.Type "Name" $.Name "ErrHandler" $.ErrHandler}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to decode the specified Plain-Old-Data type and variable name.
ErrHandler can control what should happen if there's a decode error. By
default ErrHandler is set to "return err".
Cast can be used to cast the value type before assigment to Name.
-------------------------------------------------------------------------------
*/}}
{{define "Go.DecodePOD_cast"}}{{if $}}{{Template "Go.Type" $}}(ϟv){{else}}ϟv{{end}}{{end}}
{{define "Go.DecodePOD"}}
{{AssertType $.Type "Type" }}
{{AssertType $.Name "string" }}
{{AssertType $.ErrHandler "string" "nil"}}
{{AssertType $.Cast "Type" "nil"}}
{{$v := Macro "Go.DecodePOD_cast" $.Cast}}
{{$int_size := "ϟs.Architecture.IntegerSize*8"}}
{{ if IsEnum $.Type}}if ϟv, err := d.Uint32(); err == nil { {{$.Name}} = {{$.Type.Name}}(ϟv) } else { {{$.ErrHandler}} }
{{else if IsBool $.Type}}if ϟv, err := d.Bool(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsChar $.Type}}if ϟv, err := d.Uint8(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsU8 $.Type}}if ϟv, err := d.Uint8(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsS8 $.Type}}if ϟv, err := d.Int8(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsU16 $.Type}}if ϟv, err := d.Uint16(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsS16 $.Type}}if ϟv, err := d.Int16(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsF32 $.Type}}if ϟv, err := d.Float32(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsU32 $.Type}}if ϟv, err := d.Uint32(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsS32 $.Type}}if ϟv, err := d.Int32(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsF64 $.Type}}if ϟv, err := d.Float64(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsU64 $.Type}}if ϟv, err := d.Uint64(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsS64 $.Type}}if ϟv, err := d.Int64(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsString $.Type}}if ϟv, err := d.String(); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsInt $.Type}}if ϟv, err := binary.ReadInt(d, {{$int_size}}); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsUint $.Type}}if ϟv, err := binary.ReadUint(d, {{$int_size}}); err == nil { {{$.Name}} = {{$v}} } else { {{$.ErrHandler}} }
{{else if IsVoid $.Type}}
{{else}}{{Error "macro Go.DecodePOD '%v' called with unsupported type: %v" $.Name $.Type.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to encode the specified type and variable name.
ErrHandler can control what should happen if there's a encode error. By
default ErrHandler is set to "return err".
-------------------------------------------------------------------------------
*/}}
{{define "Go.Encode"}}
{{AssertType $.Type "Type" }}
{{AssertType $.Name "string" }}
{{AssertType $.ErrHandler "string" "nil"}}
{{$ty := $.Type | Underlying}}
{{$int_size := "ϟs.Architecture.IntegerSize*8"}}
{{ if not $.ErrHandler}}{{Template "Go.Decode" "Type" $.Type "Name" $.Name "ErrHandler" "return err"}}
{{else if IsStaticArray $ty}}if err := e.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsMap $ty}}if err := e.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsClass $ty}}if err := e.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsPointer $ty}}if err := e.Value(&{{$.Name}}); err != nil { {{$.ErrHandler}} }
{{else if IsEnum $ty}}if err := e.Uint32(uint32({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsBool $ty}}if err := e.Bool(bool({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsChar $ty}}if err := e.Uint8(uint8({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsU8 $ty}}if err := e.Uint8(uint8({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsS8 $ty}}if err := e.Int8(int8({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsU16 $ty}}if err := e.Uint16(uint16({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsS16 $ty}}if err := e.Int16(int16({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsF32 $ty}}if err := e.Float32(float32({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsU32 $ty}}if err := e.Uint32(uint32({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsS32 $ty}}if err := e.Int32(int32({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsF64 $ty}}if err := e.Float64(float64({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsU64 $ty}}if err := e.Uint64(uint64({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsS64 $ty}}if err := e.Int64(int64({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsString $ty}}if err := e.String(string({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsInt $ty}}if err := binary.WriteInt(e, {{$int_size}}, int64({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsUint $ty}}if err := binary.WriteUint(e, {{$int_size}}, uint64({{$.Name}})); err != nil { {{$.ErrHandler}} }
{{else if IsVoid $ty}}
{{else}}{{Error "macro Go.Encode '%v' called with unsupported type: %v" $.Name $.Type.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Transforms the given string or identifier into a format used for a public Go
type or field. Example:
this_is_go_public -> ThisIsGoPublic
-------------------------------------------------------------------------------
*/}}
{{define "Go.Public"}}
{{AssertType $ "string"}}
{{$ | SplitOn "_" | Title}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Transforms the given string or identifier into a format used for a private Go
type or field. Example:
this_is_go_private -> thisIsGoPrivate
-------------------------------------------------------------------------------
*/}}
{{define "Go.Private"}}
{{AssertType $ "string"}}
{{$ | SplitOn "_" | Title | Join | Untitle}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the expression to lookup the given parameter.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Parameter"}}{{AssertType $ "Parameter"}}{{Template "Go.Public" $.Name}}{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the name of the specified command's structure.
-------------------------------------------------------------------------------
*/}}
{{define "Go.CmdName"}}
{{AssertType $ "Function"}}
{{Macro "CmdName" $ | Title}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to simulate the given command.
-------------------------------------------------------------------------------
*/}}
{{define "Go.CommandLogic"}}
{{AssertType $ "Function"}}
ϟa.observations.ApplyReadss.Memory[memory.ApplicationPool])
{{Template "Go.Block" $.Block}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits all the statements in the given block
-------------------------------------------------------------------------------
*/}}
{{define "Go.Block"}}
{{ForEach $.Statements "Go.Statement" | JoinWith "\n"}}
{{/* Assign each local variable of the block to a blank identifier, in case it hasn't been used. */}}
{{if $locals := ForEach $.Statements "Go.LocalNames"}}
{{ForEach $locals "Go.Blank" | JoinWith ", "}} = {{$locals | JoinWith ", "}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to execute the given statement.
If the global "Go.Statement.Override" is specified then this the macro with
the specified name is called, otherwise the macro delegates to
"Go.Statement.Default".
-------------------------------------------------------------------------------
*/}}
{{define "Go.Statement"}}
{{if $override := Global "Go.Statement.Override"}}
{{Template $override $}}
{{else}}
{{Template "Go.Statement.Default" $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to execute the given statement.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Statement.Default"}}
{{ if IsDeclareLocal $}}{{$.Local.Name}} := {{Template "Go.Read" $.Local.Value}} {{Template "Go.TypeComment" (TypeOf $.Local)}}
{{else if IsAssert $}}
{{else if IsAssign $}}{{Template "Go.Assign" "LHS" $.LHS "Operator" $.Operator "RHS" $.RHS}}
{{else if IsArrayAssign $}}{{Template "Go.ArrayAssign" $}}
{{else if IsMapAssign $}}{{Template "Go.MapAssign" $}}
{{else if IsSliceAssign $}}{{Template "Go.SliceAssign" $}}
{{else if IsCopy $}}{{Error "Copy statement found outside of a Fence"}}
{{else if IsReturn $}}{{Template "Go.Assign" "LHS" $.Function.Return "Operator" "=" "RHS" $.Value}}
{{else if IsIteration $}}{{Template "Go.Iteration" $}}
{{else if IsCall $}}{{Template "Go.Call" $}}
{{else if IsRead $}}{{Template "Go.Read" $.Slice}}.OnReada, ϟs, ϟd, ϟl, ϟb)
{{else if IsWrite $}}{{Template "Go.Read" $.Slice}}.OnWritea, ϟs, ϟd, ϟl, ϟb)
{{else if IsFence $}}{{Template "Go.Fence" $}}
{{else if IsBranch $}}{{Template "Go.Branch" $}}
{{else if IsSwitch $}}{{Template "Go.Switch" $}}
{{else}}{{Error "unsupported statement %T: %v" $ $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to execute an iteration statement
-------------------------------------------------------------------------------
*/}}
{{define "Go.Range"}}
{{AssertType $.Name "string"}}
{{AssertType $.Range "BinaryOp"}}
for {{$.Name}} := {{Template "Go.Type" $.Range.RHS}}({{Template "Go.Read" $.Range.LHS}}); {{$.Name}} < {{Template "Go.Read" $.Range.RHS}}; {{$.Name}}++
{{end}}
{{define "Go.Iteration"}}
{{AssertType $ "Iteration"}}
{{ if IsBinaryOp $.Iterable}}
{{Template "Go.Range" "Name" $.Iterator.Name "Range" $.Iterable}} {
{{Template "Go.Block" $.Block}}
}
{{else}}
for _, {{$.Iterator.Name}} := range {{Template "Go.Read" $.Iterable}}.Range() {
{{Template "Go.Block" $.Block}}
}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to execute a call statement
-------------------------------------------------------------------------------
*/}}
{{define "Go.Call"}}
{{AssertType $ "Call"}}
{{$args := ForEach $.Arguments "Go.Read" | JoinWith ", "}}
{{if $.Target.Object}}
{{Template "Go.Read" $.Target.Object}}.{{$.Target.Function.Name}}({{$args}})
{{else}}
externsa, ϟs, ϟd, ϟl, ϟb}.{{$.Target.Function.Name}}({{$args}})
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to execute a fence statement
-------------------------------------------------------------------------------
*/}}
{{define "Go.Fence"}}
{{AssertType $ "Fence"}}
ϟa.observations.ApplyWritess.Memory[memory.ApplicationPool])
{{if not (IsNil $.Statement)}}
{{if IsCopy $.Statement}} {{/* Copies are only allowed in fences */}}
{{Template "Go.Read" $.Statement.Dst}}.Copy({{Template "Go.Read" $.Statement.Src}}, ϟa, ϟs, ϟd, ϟl, ϟb)
{{else}}
{{Template "Go.Statement" $.Statement}}
{{end}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to execute a branch statement
-------------------------------------------------------------------------------
*/}}
{{define "Go.Branch"}}
{{AssertType $ "Branch"}}
if {{Template "Go.Read" $.Condition}} {
{{Template "Go.Block" $.True}}
{{if len $.False.Statements}}
} else {
{{Template "Go.Block" $.False}}
{{end}}
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to execute a switch statement
-------------------------------------------------------------------------------
*/}}
{{define "Go.Switch"}}
{{AssertType $ "Switch"}}
switch {{Template "Go.Read" $.Value}} {
{{range $c := $.Cases}}
case {{range $i, $cond := $c.Conditions}}§
{{if $i}}, {{end}}{{Template "Go.Read" $cond}}§
{{end}}:
{{Template "Go.Block" $c.Block}}
{{end}}
default:
v := {{Template "Go.Read" $.Value}}
return fmt.Errorf("Missing switch case handler for value %T %v", v, v)
}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to assign the RHS to the LHS
-------------------------------------------------------------------------------
*/}}
{{define "Go.Assign"}}
{{if IsIgnore $.LHS}}
{{if ne $.Operator "="}}{{Error "Compound assignments to '_' are not supported (%s)" $.Operator}}{{end}}
_ = {{Template "Go.Read" $.RHS}}
{{else}}
{{Template "Go.Read" $.LHS}} {{$.Operator}} {{Template "Go.Read" $.RHS}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to assign a value to a static-array index
-------------------------------------------------------------------------------
*/}}
{{define "Go.ArrayAssign"}}
{{AssertType $ "ArrayAssign"}}
{{Template "Go.Read" $.To.Array}}.Elements[{{Template "Go.Read" $.To.Index}}] {{$.Operator}} {{Template "Go.Read" $.Value}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to assign a value to a map index
-------------------------------------------------------------------------------
*/}}
{{define "Go.MapAssign"}}
{{AssertType $ "MapAssign"}}
{{if eq $.Operator "="}}
{{if IsNull $.Value}}
delete({{Template "Go.Read" $.To.Map}}, {{Template "Go.Read" $.To.Index}})
{{else}}
{{Template "Go.Read" $.To.Map}}[{{Template "Go.Read" $.To.Index}}] = {{Template "Go.Read" $.Value}}
{{end}}
{{else}}
{{Error "Unsupported MapAssign operator %s" $.Operator}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to assign a value to a slice index
-------------------------------------------------------------------------------
*/}}
{{define "Go.SliceAssign"}}
{{AssertType $ "SliceAssign"}}
{{if ne $.Operator "="}}{{Error "Compound assignments to pointers are not supported (%s)" $.Operator}}{{end}}
{{Template "Go.Read" $.To.Slice}}.Index({{Template "Go.Read" $.To.Index}}, ϟs).Write({{Template "Go.Read" $.Value}}, ϟa, ϟs, ϟd, ϟl, ϟb)
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to read the value of the specified expression.
If the global "Go.Read.Override" is specified then this the macro with the
specified name is called, otherwise the macro delegates to "Go.Read.Default".
-------------------------------------------------------------------------------
*/}}
{{define "Go.Read"}}
{{if $override := Global "Go.Read.Override"}}
{{Template $override $}}
{{else}}
{{Template "Go.Read.Default" $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to read a slice or pointer, with special handling for
inferred expressions.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Memory.Read"}}
{{if Global "Go.InferredExpression"}}
{{/*
If the expression is inferred, then it is the output of a command.
When building a replay, Read with ϟb would replace the output memory with
observed memory which is undesirable, so instead just map the memory and
perform regular (non-replay-builder) read logic.
*/}}
MapMemorya, ϟs, ϟd, ϟl, ϟb).Reada, ϟs, ϟd, ϟl, nil)
{{else}}
Reada, ϟs, ϟd, ϟl, ϟb)
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the Go logic to execute the given statement.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Read.Default"}}
{{ if IsBoolValue $}}{{$}}
{{else if IsNumericValue $}}{{Template "Go.Type" $}}({{$}})
{{else if IsUnaryOp $}}{{$.Operator}}({{Template "Go.Read" $.Expression}})
{{else if IsStringValue $}}{{printf "%q" $}}
{{else if IsEnumEntry $}}{{$.Owner.Name}}_{{$.Name}}
{{else if IsLocal $}}{{$.Name}}
{{else if IsBitTest $}}(({{Template "Go.Read" $.Bits}}) & ({{Template "Go.Read" $.Bitfield}}) != 0)
{{else if IsBinaryOp $}}({{Template "Go.Read" $.LHS}}) {{$.Operator}} ({{Template "Go.Read" $.RHS}})
{{else if IsCast $}}{{Template "Go.Cast" $}}
{{else if IsCall $}}{{Template "Go.Call" $}}
{{else if IsUnknown $}}{{Global "Go.InferredExpression" "1"}}{{Template "Go.Read" $.Inferred}}{{Global "Go.InferredExpression" ""}}
{{else if IsObserved $}}{{Template "Go.ReadParameter" $.Parameter}}
{{else if IsMember $}}{{Template "Go.Read" $.Object}}.{{Template "Go.Public" $.Field.Name}}
{{else if IsGlobal $}}ϟc.{{Title $.Name}}
{{else if IsParameter $}}{{Template "Go.ReadParameter" $}}
{{else if IsMapIndex $}}{{Template "Go.Read" $.Map}}.Get({{Template "Go.Read" $.Index}})
{{else if IsMapContains $}}{{Template "Go.Read" $.Map}}.Contains({{Template "Go.Read" $.Key}})
{{else if IsLength $}}{{Template "Go.Type" $.Type}}({{Template "Go.ReadLength" "Type" (TypeOf $.Object) "Value" $.Object}})
{{else if IsNull $}}{{Template "Go.Null" $.Type}}
{{else if IsNew $}}new {{Template "Go.Type" $.Type}}
{{else if IsSliceIndex $}}{{Template "Go.Read" $.Slice }}.Index({{Template "Go.Read" $.Index}}, ϟs).{{Macro "Go.Memory.Read"}}
{{else if IsSliceRange $}}{{Template "Go.Read" $.Slice }}.Slice({{Template "Go.Read" $.Range.LHS}}, {{Template "Go.Read" $.Range.RHS}}, ϟs)
{{else if IsPointerRange $}}{{Template "Go.Read" $.Pointer}}.Slice({{Template "Go.Read" $.Range.LHS}}, {{Template "Go.Read" $.Range.RHS}}, ϟs)
{{else if IsClone $}}{{Template "Go.Read" $.Slice }}.Clonea, ϟs, ϟd, ϟl, ϟb)
{{else if IsMake $}}Make{{Template "Go.Type" $.Type}}({{Template "Go.Read" $.Size}}, ϟs)
{{else if IsSelect $}}{{Template "Go.Select" $}}
{{else if IsArrayInitializer $}}{{Template "Go.ArrayInitializer" $}}
{{else if IsClassInitializer $}}{{Template "Go.ClassInitializer" $}}
{{else if IsCreate $}}{{Template "Go.Create" $}}
{{else}}{{Error "macro Go.Read called with unsupported type: %T" $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to cast a value to another type.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Cast"}}
{{AssertType $ "Cast"}}
{{$src_ty := $.Object | TypeOf | Underlying | Unpack}}
{{$dst_ty := $.Type | Underlying}}
{{$src := Macro "Go.Read" $.Object}}
{{/* T* -> number */}}{{if and (IsPointer $src_ty) (IsNumericType $dst_ty)}}
{{Template "Go.Type" $.Type}}({{$src}}.Address)
{{/* A[] -> B[] */}}{{else if and (IsSlice $src_ty) (IsSlice $dst_ty)}}
As{{Template "Go.Type" $.Type}}({{$src}}, ϟs)
{{/* T[] -> T* */}}{{else if and (IsSlice $src_ty) (IsPointer $dst_ty)}}
{{Template "Go.Type" $.Type}}({{$src}}.Index(0, ϟs))
{{/* char* -> string */}}{{else if and (IsPointer $src_ty) (IsString $dst_ty)}}
strings.TrimRight(string({{$src}}.StringSlices, ϟd, ϟl).{{Macro "Go.Memory.Read"}}), "\x00")
{{/* char[] -> string */}}{{else if and (IsSlice $src_ty) (IsString $dst_ty)}}
string({{$src}}.{{Macro "Go.Memory.Read"}})
{{/* string[] -> char[] */}}{{else if and (IsString $src_ty) (IsSlice $dst_ty)}}
Make{{Template "Go.Type" $.Type}}FromString({{$src}}, ϟs)
{{else}}
{{Template "Go.Type" $.Type}}({{$src}})
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to read the value of the specified expression.
-------------------------------------------------------------------------------
*/}}
{{define "Go.ReadParameter"}}
{{AssertType $ "Parameter"}}
ϟa.{{Template "Go.Public" $.Name}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to perform a select experssion.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Select"}}
{{AssertType $ "Select"}}
func() (result {{Template "Go.Type" $}}) {
switch {{Template "Go.Read" $.Value}} {
{{range $c := $.Choices}}
case {{range $i, $cond := $c.Conditions}}§
{{if $i}}, {{end}}{{Template "Go.Read" $cond}}§
{{end}}:
return {{Template "Go.Read" $c.Expression}}
{{end}}
default:
// TODO: better unmatched handling
panic(fmt.Errorf("Unmatched switch(%v) in atom %T", {{Template "Go.Read" $.Value}}, ϟa))
return result
}
}()
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to initialize a new instance of an array.
-------------------------------------------------------------------------------
*/}}
{{define "Go.ArrayInitializer"}}
{{AssertType $ "ArrayInitializer"}}
{{$a := $.Array | Underlying | Unpack}}
{{Template "Go.Type" $}}{ Elements: [{{$a.Size}}]{{Template "Go.Type" $a.ValueType}}{ {{ForEach $.Values "Go.Read" | JoinWith ", "}} } }
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to initialize a new instance of a class.
-------------------------------------------------------------------------------
*/}}
{{define "Go.ClassInitializer"}}
{{AssertType $ "ClassInitializer"}}
func(){{Template "Go.Type" $}}{
s := {{Template "Go.Type" $}}{}
s.Init()
{{range $f := $.Fields}}
s.{{$f.Field.Name}} = {{Template "Go.Read" $f.Value}}
{{end}}
return s
}()
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to return a pointer to a new instance of a class.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Create"}}
{{AssertType $ "Create"}}
func(){{Template "Go.Type" $}}{
s := &{{Template "Go.Type" (Unpack $.Type).To}}{}
s.Init()
{{range $f := $.Initializer.Fields}}
s.{{$f.Field.Name}} = {{Template "Go.Read" $f.Value}}
{{end}}
return s
}()
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a comment displaying the specified type.
-------------------------------------------------------------------------------
*/}}
{{define "Go.TypeComment"}}
{{AssertType $ "Type"}}
// {{$.Name}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the logic to read the length of the specified expression by
Value and Type.
-------------------------------------------------------------------------------
*/}}
{{define "Go.ReadLength"}}
{{AssertType $.Type "Type"}}
{{$ty := Unpack $.Type}}
{{ if IsPseudonym $ty}}{{Template "Go.ReadLength" "Type" $ty.To "Value" $.Value}}
{{else if IsSlice $ty}}{{Template "Go.Read" $.Value}}.Count
{{else if IsString $ty}}len({{Template "Go.Read" $.Value}})
{{else if IsMap $ty}}len({{Template "Go.Read" $.Value}})
{{else }}{{Error "macro Go.ReadLength called with unsupported type: %v" $.Type}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
If the given statement is a local variable declaration, return its name.
-------------------------------------------------------------------------------
*/}}
{{define "Go.LocalNames"}}
{{if IsDeclareLocal $}}{{$.Local.Name}}
{{else if IsFence $}}{{Template "Go.LocalNames" $.Statement}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a Go blank identifier, _.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Blank"}}_{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the size in bytes of the specified type as a uint64
-------------------------------------------------------------------------------
*/}}
{{define "Go.SizeOf"}}
{{AssertType $ "Type"}}
{{ if IsPseudonym $}}{{Template "Go.SizeOf" $.To}}
{{else if IsVoid $}}uint64(1)
{{else if IsBool $}}uint64(1)
{{else if IsChar $}}uint64(1)
{{else if IsU8 $}}uint64(1)
{{else if IsS8 $}}uint64(1)
{{else if IsU16 $}}uint64(2)
{{else if IsS16 $}}uint64(2)
{{else if IsF32 $}}uint64(4)
{{else if IsU32 $}}uint64(4)
{{else if IsS32 $}}uint64(4)
{{else if IsF64 $}}uint64(8)
{{else if IsU64 $}}uint64(8)
{{else if IsS64 $}}uint64(8)
{{else if IsEnum $}}uint64(4)
{{else if IsString $}}uint64s.Architecture.PointerSize)
{{else if IsPointer $}}uint64s.Architecture.PointerSize)
{{else if IsInt $}}uint64s.Architecture.IntegerSize)
{{else if IsUint $}}uint64s.Architecture.IntegerSize)
{{else if IsStaticArray $}}{{Template "Go.SizeOf" $.ValueType}}*{{$.Size}}
{{else if IsClass $}}func() uint64 { panic("Sizeof class is not yet implemented") }()
{{else }}{{Error "macro Go.SizeOf called with unsupported type: %v" $}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Returns the replay builder Value holding the specified variable.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Replay.Value"}}
{{AssertType $.Type "Type"}}
{{AssertType $.Name "string"}}
{{if (GetAnnotation $.Type "replay_custom_value")}}{{$.Name}}.valueb, ϟa, ϟs)
{{else if IsBool $.Type}}value.Bool({{$.Name}})
{{else if IsS8 $.Type}}value.S8({{$.Name}})
{{else if IsU8 $.Type}}value.U8({{$.Name}})
{{else if IsS16 $.Type}}value.S16({{$.Name}})
{{else if IsU16 $.Type}}value.U16({{$.Name}})
{{else if IsF32 $.Type}}value.F32({{$.Name}})
{{else if IsU32 $.Type}}value.U32({{$.Name}})
{{else if IsS32 $.Type}}value.S32({{$.Name}})
{{else if IsF64 $.Type}}value.F64({{$.Name}})
{{else if IsU64 $.Type}}value.U64({{$.Name}})
{{else if IsS64 $.Type}}value.S64({{$.Name}})
{{else if IsInt $.Type}}value.S64({{$.Name}})
{{else if IsUint $.Type}}value.U64({{$.Name}})
{{else if IsString $.Type}}ϟb.String({{$.Name}})
{{else if IsPointer $.Type}}{{$.Name}}.value()
{{else if IsEnum $.Type}}value.U32({{$.Name}})
{{else if IsStaticArray $.Type}}{{$.Name}}.valueb, ϟa, ϟs)
{{else if IsPseudonym $.Type}}{{$.Name}}.valueb, ϟa, ϟs)
{{else if IsClass $.Type}}{{$.Name}}.valueb, ϟa, ϟs)
{{else }}{{Error "macro Go.Replay.Value '%v' called with unsupported type: %s" $.Name $.Type.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits the replay builder type for the given command return type.
-------------------------------------------------------------------------------
*/}}
{{define "Go.Replay.Type"}}
{{AssertType $ "Type"}}
{{ if IsPseudonym $}}{{Template "Go.Replay.Type" $.To}}
{{else if IsEnum $}}protocol.TypeUint32
{{else if IsBool $}}protocol.TypeBool
{{else if IsInt $}}protocol.TypeInt64
{{else if IsUint $}}protocol.TypeUint64
{{else if IsS8 $}}protocol.TypeInt8
{{else if IsU8 $}}protocol.TypeUint8
{{else if IsS16 $}}protocol.TypeInt16
{{else if IsU16 $}}protocol.TypeUint16
{{else if IsS32 $}}protocol.TypeInt32
{{else if IsU32 $}}protocol.TypeUint32
{{else if IsF32 $}}protocol.TypeFloat
{{else if IsS64 $}}protocol.TypeInt64
{{else if IsU64 $}}protocol.TypeUint64
{{else if IsF64 $}}protocol.TypeDouble
{{else if IsVoid $}}protocol.TypeVoid
{{else if IsString $}}protocol.TypeVolatilePointer
{{else if IsPointer $}}protocol.TypeVolatilePointer {{/* TODO: Might be absolute... */}}
{{else}}{{Error "macro Go.Replay.Type called with unsupported type: %s" $.Name}}
{{end}}
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a comment stating that the file is automatically generated.
-------------------------------------------------------------------------------
*/}}
{{define "Go.GeneratedHeader"}}
{{Copyright "generated" "apic"}}¶
package {{$}};
{{end}}
{{/*
-------------------------------------------------------------------------------
Emits a comment block containing the specified text.
-------------------------------------------------------------------------------
*/}}
{{define "Go.CommentHeader"}}
{{AssertType $ "string"}} {{/* The comment block body text */}}
////////////////////////////////////////////////////////////////////////////////
// {{.}}
////////////////////////////////////////////////////////////////////////////////
{{end}}