diff --git a/src/core/TypeFromTokens.go b/src/core/TypeFromTokens.go index 35be112..842c816 100644 --- a/src/core/TypeFromTokens.go +++ b/src/core/TypeFromTokens.go @@ -68,6 +68,26 @@ func (env *Environment) TypeFromTokens(tokens token.List, file *fs.File) (types. return env.Pointer(typ), nil } + if len(tokens) >= 4 && tokens[0].Kind == token.ArrayStart && tokens[1].Kind == token.Number && tokens[2].Kind == token.ArrayEnd { + count, err := toNumber(tokens[1], file) + + if err != nil { + return nil, err + } + + if count <= 0 { + return nil, errors.New(InvalidNumber, file, tokens[1]) + } + + element, err := env.TypeFromTokens(tokens[3:], file) + + if err != nil { + return nil, err + } + + return env.Array(element, count), nil + } + if len(tokens) >= 2 && tokens[0].Kind == token.ArrayStart && tokens[1].Kind == token.ArrayEnd { typ, err := env.TypeFromTokens(tokens[2:], file) diff --git a/src/core/typeCache.go b/src/core/typeCache.go index 344e2cd..6022e79 100644 --- a/src/core/typeCache.go +++ b/src/core/typeCache.go @@ -8,11 +8,36 @@ import ( // typeCache contains reusable type objects. type typeCache struct { + arrayTypes sync.Map pointerTypes sync.Map resourceTypes sync.Map sliceTypes sync.Map } +// arrayKey identifies a static array type by element type and count. +type arrayKey struct { + typ types.Type + count int +} + +// Array returns the type that is a static array of the given type and count. +func (c *typeCache) Array(typ types.Type, count int) types.Type { + key := arrayKey{ + typ: typ, + count: count, + } + + existing, ok := c.arrayTypes.Load(key) + + if ok { + return existing.(types.Type) + } + + new := types.Array(typ, count) + existing, _ = c.arrayTypes.LoadOrStore(key, new) + return existing.(types.Type) +} + // Pointer returns the type that points to the given type. func (c *typeCache) Pointer(typ types.Type) types.Type { existing, ok := c.pointerTypes.Load(typ) diff --git a/src/types/Array.go b/src/types/Array.go new file mode 100644 index 0000000..fe27d6d --- /dev/null +++ b/src/types/Array.go @@ -0,0 +1,29 @@ +package types + +import ( + "fmt" + "strconv" +) + +// Array creates a new static array type. +func Array(element Type, count int) *Struct { + name := fmt.Sprintf("[%d]%s", count, element.Name()) + fields := make([]*Field, count) + elementSize := element.Size() + + for i := range fields { + fields[i] = &Field{ + Type: element, + Name: strconv.Itoa(i), + Index: uint64(i), + Offset: uint64(i * elementSize), + } + } + + return &Struct{ + Package: "", + UniqueName: name, + name: name, + Fields: fields, + } +} \ No newline at end of file diff --git a/src/types/Struct_test.go b/src/types/Struct_test.go index 9ed141c..8c14a43 100644 --- a/src/types/Struct_test.go +++ b/src/types/Struct_test.go @@ -32,4 +32,20 @@ func TestStruct(t *testing.T) { assert.Equal(t, point.FieldByName("x"), x) assert.Equal(t, point.FieldByName("y"), y) assert.Nil(t, point.FieldByName("invalid")) +} + +func TestArray(t *testing.T) { + array := types.Array(types.UInt8, 20) + assert.Equal(t, array.Name(), "[20]uint8") + assert.Equal(t, array.Size(), 20) + assert.Equal(t, len(array.Fields), 20) + assert.Equal(t, array.Fields[0].Offset, uint64(0)) + assert.Equal(t, array.Fields[19].Offset, uint64(19)) + + array = types.Array(types.Int64, 4) + assert.Equal(t, array.Name(), "[4]int64") + assert.Equal(t, array.Size(), 32) + assert.Equal(t, len(array.Fields), 4) + assert.Equal(t, array.Fields[0].Offset, uint64(0)) + assert.Equal(t, array.Fields[3].Offset, uint64(24)) } \ No newline at end of file