blob: 334650d8556223b6e55156bb38268ece7a0837dd [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package tests
import (
"encoding/binary"
"fmt"
"math"
"strings"
"mojo/public/go/system"
)
// inputParser parses validation tests input format as described in
// |mojo/public/cpp/bindings/tests/validation_test_input_parser.h|
type inputParser struct {
}
type dataItem struct {
Type string
Value string
}
type pointerPlaceholder struct {
Position int
Size int
}
func (p *inputParser) parseToDataItems(s string) []dataItem {
var items []dataItem
s = strings.TrimSpace(s)
for len(s) > 0 {
// Parsing data item type.
var itemType string
if s[0] == '[' {
closeBracket := strings.Index(s, "]")
if closeBracket == -1 {
panic("unmatched left [")
}
itemType = strings.TrimSpace(s[1:closeBracket])
s = strings.TrimSpace(s[closeBracket+1:])
} else {
itemType = "u1"
}
// Parsing data item value.
itemEnd := strings.IndexAny(s, "[ \t\n\r")
if itemEnd == -1 {
items = append(items, dataItem{itemType, strings.TrimSpace(s)})
s = ""
} else {
items = append(items, dataItem{itemType, strings.TrimSpace(s[:itemEnd])})
s = strings.TrimSpace(s[itemEnd:])
}
}
return items
}
// Parse parses a validation tests input string that has no comments.
// Panics if input has errors.
func (p *inputParser) Parse(s string) ([]byte, []system.Handle) {
var bytes []byte
var handles []system.Handle
var buf [8]byte
pointers := make(map[string]pointerPlaceholder)
for _, item := range p.parseToDataItems(s) {
switch item.Type {
case "u1":
var value uint8
fmt.Sscan(item.Value, &value)
bytes = append(bytes, byte(value))
case "u2":
var value uint16
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint16(buf[:2], value)
bytes = append(bytes, buf[:2]...)
case "u4":
var value uint32
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint32(buf[:4], value)
bytes = append(bytes, buf[:4]...)
case "u8":
var value uint64
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint64(buf[:8], value)
bytes = append(bytes, buf[:8]...)
case "s1":
var value int8
fmt.Sscan(item.Value, &value)
bytes = append(bytes, byte(value))
case "s2":
var value int16
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint16(buf[:2], uint16(value))
bytes = append(bytes, buf[:2]...)
case "s4":
var value int32
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint32(buf[:4], uint32(value))
bytes = append(bytes, buf[:4]...)
case "s8":
var value int64
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint64(buf[:8], uint64(value))
bytes = append(bytes, buf[:8]...)
case "b":
var value byte
for i := 0; i < 8; i++ {
value <<= 1
if item.Value[i] == '1' {
value++
}
}
bytes = append(bytes, value)
case "f":
var value float32
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint32(buf[:4], math.Float32bits(value))
bytes = append(bytes, buf[:4]...)
case "d":
var value float64
fmt.Sscan(item.Value, &value)
binary.LittleEndian.PutUint64(buf[:8], math.Float64bits(value))
bytes = append(bytes, buf[:8]...)
case "dist4":
pointers[item.Value] = pointerPlaceholder{len(bytes), 4}
bytes = append(bytes, buf[:4]...)
case "dist8":
pointers[item.Value] = pointerPlaceholder{len(bytes), 8}
bytes = append(bytes, buf[:8]...)
case "anchr":
placeholder := pointers[item.Value]
dist := len(bytes) - placeholder.Position
switch placeholder.Size {
case 4:
binary.LittleEndian.PutUint32(bytes[placeholder.Position:], uint32(dist))
case 8:
binary.LittleEndian.PutUint64(bytes[placeholder.Position:], uint64(dist))
}
delete(pointers, item.Value)
case "handles":
var value int
fmt.Sscan(item.Value, &value)
handles = make([]system.Handle, value)
for i, _ := range handles {
handles[i] = system.GetCore().AcquireNativeHandle(0)
}
default:
panic(fmt.Sprintf("unsupported item type: %v", item.Type))
}
}
if len(pointers) != 0 {
panic(fmt.Sprintf("unmatched pointers: %v", pointers))
}
return bytes, handles
}