(data []byte)
| 51 | } |
| 52 | |
| 53 | func newASTDecoder(data []byte) (*astDecoder, error) { |
| 54 | if len(data) < HeaderSize { |
| 55 | return nil, fmt.Errorf("data too short for header: %d bytes", len(data)) |
| 56 | } |
| 57 | version := data[HeaderOffsetMetadata+3] |
| 58 | if version != ProtocolVersion { |
| 59 | return nil, fmt.Errorf("unsupported protocol version %d (expected %d)", version, ProtocolVersion) |
| 60 | } |
| 61 | |
| 62 | strTable := readLE32(data, HeaderOffsetStringOffsets) |
| 63 | strData := readLE32(data, HeaderOffsetStringData) |
| 64 | extData := readLE32(data, HeaderOffsetExtendedData) |
| 65 | nodeOff := readLE32(data, HeaderOffsetNodes) |
| 66 | |
| 67 | dataLen := uint32(len(data)) |
| 68 | |
| 69 | // Validate that all offsets are within the buffer. |
| 70 | if strTable > dataLen || strData > dataLen || extData > dataLen || nodeOff > dataLen { |
| 71 | return nil, fmt.Errorf("invalid AST header offsets: offsets exceed data length (%d)", dataLen) |
| 72 | } |
| 73 | |
| 74 | // Validate monotonic non-decreasing order of regions. |
| 75 | if !(strTable <= strData && strData <= extData && extData <= nodeOff) { |
| 76 | return nil, fmt.Errorf("invalid AST header offsets: expected strTable <= strData <= extData <= nodeOff (got %d, %d, %d, %d)", strTable, strData, extData, nodeOff) |
| 77 | } |
| 78 | |
| 79 | d := &astDecoder{ |
| 80 | raw: data, |
| 81 | strTable: strTable, |
| 82 | strData: strData, |
| 83 | extData: extData, |
| 84 | nodeOff: nodeOff, |
| 85 | factory: ast.NewNodeFactory(ast.NodeFactoryHooks{}), |
| 86 | } |
| 87 | |
| 88 | d.nodeCount = (len(data) - int(d.nodeOff)) / NodeSize |
| 89 | |
| 90 | // Convert entire string data region to a single Go string upfront. |
| 91 | // Substringing a Go string shares the backing array, so subsequent |
| 92 | // getString calls produce substrings with zero allocations. |
| 93 | d.allStringData = string(data[d.strData:]) |
| 94 | |
| 95 | return d, nil |
| 96 | } |
| 97 | |
| 98 | // allocNodeSlice returns a zero-length slice with the given capacity, backed by |
| 99 | // the pre-allocated nodeArena. This avoids a heap allocation per NodeList. |
no test coverage detected