Files
CHORUS/vendor/github.com/ipld/go-ipld-prime/schema/dsl/parse.go
anthonyrawlins 9bdcbe0447 Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes:
- Added BACKBEAT SDK integration for P2P operation timing
- Implemented beat-aware status tracking for distributed operations
- Added Docker secrets support for secure license management
- Resolved KACHING license validation via HTTPS/TLS
- Updated docker-compose configuration for clean stack deployment
- Disabled rollback policies to prevent deployment failures
- Added license credential storage (CHORUS-DEV-MULTI-001)

Technical improvements:
- BACKBEAT P2P operation tracking with phase management
- Enhanced configuration system with file-based secrets
- Improved error handling for license validation
- Clean separation of KACHING and CHORUS deployment stacks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-06 07:56:26 +10:00

735 lines
16 KiB
Go

package schemadsl
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
dmt "github.com/ipld/go-ipld-prime/schema/dmt"
)
var globalTrue = true
// TODO: fuzz testing
func ParseBytes(src []byte) (*dmt.Schema, error) {
return Parse("", bytes.NewReader(src))
}
func ParseFile(path string) (*dmt.Schema, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return Parse(path, f)
}
func Parse(name string, r io.Reader) (*dmt.Schema, error) {
p := &parser{
path: name,
br: bufio.NewReader(r),
line: 1,
col: 1,
}
sch := &dmt.Schema{}
sch.Types.Values = make(map[string]dmt.TypeDefn)
for {
tok, err := p.consumeToken()
if err == io.EOF {
break
}
switch tok {
case "type":
name, err := p.consumeName()
if err != nil {
return nil, err
}
defn, err := p.typeDefn()
if err != nil {
return nil, err
}
mapAppend(&sch.Types, name, defn)
case "advanced":
return nil, p.errf("TODO: advanced")
default:
return nil, p.errf("unexpected token: %q", tok)
}
}
return sch, nil
}
func mapAppend(mapPtr, k, v interface{}) {
// TODO: delete with generics
// TODO: error on dupes
mval := reflect.ValueOf(mapPtr).Elem()
kval := reflect.ValueOf(k)
vval := reflect.ValueOf(v)
keys := mval.FieldByName("Keys")
keys.Set(reflect.Append(keys, kval))
values := mval.FieldByName("Values")
if values.IsNil() {
values.Set(reflect.MakeMap(values.Type()))
}
values.SetMapIndex(kval, vval)
}
type parser struct {
path string
br *bufio.Reader
peekedToken string
line, col int
}
func (p *parser) forwardError(err error) error {
var prefix string
if p.path != "" {
prefix = p.path + ":"
}
return fmt.Errorf("%s%d:%d: %s", prefix, p.line, p.col, err)
}
func (p *parser) errf(format string, args ...interface{}) error {
return p.forwardError(fmt.Errorf(format, args...))
}
func (p *parser) consumeToken() (string, error) {
if tok := p.peekedToken; tok != "" {
p.peekedToken = ""
return tok, nil
}
for {
// TODO: use runes for better unicode support
b, err := p.br.ReadByte()
if err == io.EOF {
return "", err // TODO: ErrUnexpectedEOF?
}
if err != nil {
return "", p.forwardError(err)
}
p.col++
switch b {
case ' ', '\t', '\r': // skip whitespace
continue
case '\n': // skip newline
// TODO: should we require a newline after each type def, struct field, etc?
p.line++
p.col = 1
continue
case '"': // quoted string
quoted, err := p.br.ReadString('"')
if err != nil {
return "", p.forwardError(err)
}
return "\"" + quoted, nil
case '{', '}', '[', ']', '(', ')', ':', '&': // simple token
return string(b), nil
case '#': // comment
_, err := p.br.ReadString('\n')
if err != nil {
return "", p.forwardError(err)
}
// tokenize the newline
if err := p.br.UnreadByte(); err != nil {
panic(err) // should never happen
}
continue
default: // string token or name
var sb strings.Builder
sb.WriteByte(b)
for {
b, err := p.br.ReadByte()
if err == io.EOF {
// Token ends at the end of the whole input.
return sb.String(), nil
}
if err != nil {
return "", p.forwardError(err)
}
// TODO: should probably allow unicode letters and numbers, like Go?
switch {
case b >= 'a' && b <= 'z', b >= 'A' && b <= 'Z':
case b >= '0' && b <= '9':
case b == '_':
default:
if err := p.br.UnreadByte(); err != nil {
panic(err) // should never happen
}
return sb.String(), nil
}
sb.WriteByte(b)
}
}
}
}
func (p *parser) consumePeeked() {
if p.peekedToken == "" {
panic("consumePeeked requires a peeked token to be present")
}
p.peekedToken = ""
}
func (p *parser) peekToken() (string, error) {
if tok := p.peekedToken; tok != "" {
return tok, nil
}
tok, err := p.consumeToken()
if err != nil {
if err == io.EOF {
// peekToken is often used when a token is optional.
// If we hit io.EOF, that's not an error.
// TODO: consider making peekToken just not return an error?
return "", nil
}
return "", err
}
p.peekedToken = tok
return tok, nil
}
func (p *parser) consumeName() (string, error) {
tok, err := p.consumeToken()
if err != nil {
return "", err
}
switch tok {
case "\"", "{", "}", "[", "]", "(", ")", ":":
return "", p.errf("expected a name, got %q", tok)
}
if tok[0] == '"' {
return "", p.errf("expected a name, got string %s", tok)
}
return tok, nil
}
func (p *parser) consumeString() (string, error) {
tok, err := p.consumeToken()
if err != nil {
return "", err
}
if tok[0] != '"' {
return "", p.errf("expected a string, got %q", tok)
}
// Unquote, too.
return tok[1 : len(tok)-1], nil
}
func (p *parser) consumeStringMap() (map[string]string, error) {
result := map[string]string{}
loop:
for {
tok, err := p.peekToken()
if err != nil {
return result, err
}
switch tok {
case "{":
p.consumePeeked()
case "}":
p.consumePeeked()
break loop
default:
key, err := p.consumeName()
if err != nil {
return result, err
}
value, err := p.consumeString()
if err != nil {
return result, err
}
result[key] = value
}
}
return result, nil
}
func (p *parser) consumeRequired(tok string) error {
got, err := p.consumeToken()
if err != nil {
return err
}
if got != tok {
return p.errf("expected %q, got %q", tok, got)
}
return nil
}
func (p *parser) typeDefn() (dmt.TypeDefn, error) {
var defn dmt.TypeDefn
kind, err := p.consumeToken()
if err != nil {
return defn, err
}
switch kind {
case "struct":
if err := p.consumeRequired("{"); err != nil {
return defn, err
}
defn.TypeDefnStruct, err = p.typeStruct()
case "union":
if err := p.consumeRequired("{"); err != nil {
return defn, err
}
defn.TypeDefnUnion, err = p.typeUnion()
case "enum":
if err := p.consumeRequired("{"); err != nil {
return defn, err
}
defn.TypeDefnEnum, err = p.typeEnum()
case "bool":
defn.TypeDefnBool = &dmt.TypeDefnBool{}
case "bytes":
defn.TypeDefnBytes = &dmt.TypeDefnBytes{}
case "float":
defn.TypeDefnFloat = &dmt.TypeDefnFloat{}
case "int":
defn.TypeDefnInt = &dmt.TypeDefnInt{}
case "link":
defn.TypeDefnLink = &dmt.TypeDefnLink{}
case "any":
defn.TypeDefnAny = &dmt.TypeDefnAny{}
case "&":
target, err := p.consumeName()
if err != nil {
return defn, err
}
defn.TypeDefnLink = &dmt.TypeDefnLink{ExpectedType: &target}
case "string":
defn.TypeDefnString = &dmt.TypeDefnString{}
case "{":
defn.TypeDefnMap, err = p.typeMap()
case "[":
defn.TypeDefnList, err = p.typeList()
case "=":
from, err := p.consumeName()
if err != nil {
return defn, err
}
defn.TypeDefnCopy = &dmt.TypeDefnCopy{FromType: from}
default:
err = p.errf("unknown type keyword: %q", kind)
}
return defn, err
}
func (p *parser) typeStruct() (*dmt.TypeDefnStruct, error) {
repr := &dmt.StructRepresentation_Map{}
repr.Fields = &dmt.Map__FieldName__StructRepresentation_Map_FieldDetails{}
defn := &dmt.TypeDefnStruct{}
for {
tok, err := p.consumeToken()
if err != nil {
return nil, err
}
if tok == "}" {
break
}
name := tok
var field dmt.StructField
loop:
for {
tok, err := p.peekToken()
if err != nil {
return nil, err
}
switch tok {
case "optional":
if field.Optional != nil {
return nil, p.errf("multiple optional keywords")
}
field.Optional = &globalTrue
p.consumePeeked()
case "nullable":
if field.Nullable != nil {
return nil, p.errf("multiple nullable keywords")
}
field.Nullable = &globalTrue
p.consumePeeked()
default:
var err error
field.Type, err = p.typeNameOrInlineDefn()
if err != nil {
return nil, err
}
break loop
}
}
tok, err = p.peekToken()
if err != nil {
return nil, err
}
if tok == "(" {
details := dmt.StructRepresentation_Map_FieldDetails{}
p.consumePeeked()
parenLoop:
for {
tok, err = p.consumeToken()
if err != nil {
return nil, err
}
switch tok {
case ")":
break parenLoop
case "rename":
str, err := p.consumeString()
if err != nil {
return nil, err
}
details.Rename = &str
case "implicit":
scalar, err := p.consumeToken()
if err != nil {
return nil, err
}
var anyScalar dmt.AnyScalar
switch {
case scalar[0] == '"': // string
s, err := strconv.Unquote(scalar)
if err != nil {
return nil, p.forwardError(err)
}
anyScalar.String = &s
case scalar == "true", scalar == "false": // bool
t := scalar == "true"
anyScalar.Bool = &t
case scalar[0] >= '0' && scalar[0] <= '0':
n, err := strconv.Atoi(scalar)
if err != nil {
return nil, p.forwardError(err)
}
anyScalar.Int = &n
default:
return nil, p.errf("unsupported implicit scalar: %s", scalar)
}
details.Implicit = &anyScalar
}
}
mapAppend(repr.Fields, name, details)
}
mapAppend(&defn.Fields, name, field)
}
reprName := "map" // default repr
if tok, err := p.peekToken(); err == nil && tok == "representation" {
p.consumePeeked()
name, err := p.consumeName()
if err != nil {
return nil, err
}
reprName = name
}
if reprName != "map" && len(repr.Fields.Keys) > 0 {
return nil, p.errf("rename and implicit are only supported for struct map representations")
}
switch reprName {
case "map":
if len(repr.Fields.Keys) == 0 {
// Fields is optional; omit it if empty.
repr.Fields = nil
}
defn.Representation.StructRepresentation_Map = repr
return defn, nil
case "tuple":
defn.Representation.StructRepresentation_Tuple = &dmt.StructRepresentation_Tuple{}
return defn, nil
// TODO: support custom fieldorder
case "stringjoin":
optMap, err := p.consumeStringMap()
if err != nil {
return nil, err
}
join, hasJoin := optMap["join"]
if !hasJoin {
return nil, p.errf("no join value provided for stringjoin repr")
}
defn.Representation.StructRepresentation_Stringjoin = &dmt.StructRepresentation_Stringjoin{
Join: join,
}
return defn, nil
default:
return nil, p.errf("unknown struct repr: %q", reprName)
}
}
func (p *parser) typeNameOrInlineDefn() (dmt.TypeNameOrInlineDefn, error) {
var typ dmt.TypeNameOrInlineDefn
tok, err := p.consumeToken()
if err != nil {
return typ, err
}
switch tok {
case "&":
expectedName, err := p.consumeName()
if err != nil {
return typ, err
}
typ.InlineDefn = &dmt.InlineDefn{TypeDefnLink: &dmt.TypeDefnLink{ExpectedType: &expectedName}}
case "[":
tlist, err := p.typeList()
if err != nil {
return typ, err
}
typ.InlineDefn = &dmt.InlineDefn{TypeDefnList: tlist}
case "{":
tmap, err := p.typeMap()
if err != nil {
return typ, err
}
typ.InlineDefn = &dmt.InlineDefn{TypeDefnMap: tmap}
default:
typ.TypeName = &tok
}
return typ, nil
}
func (p *parser) typeList() (*dmt.TypeDefnList, error) {
defn := &dmt.TypeDefnList{}
tok, err := p.peekToken()
if err != nil {
return nil, err
}
if tok == "nullable" {
defn.ValueNullable = &globalTrue
p.consumePeeked()
}
defn.ValueType, err = p.typeNameOrInlineDefn()
if err != nil {
return nil, err
}
if err := p.consumeRequired("]"); err != nil {
return defn, err
}
// TODO: repr
return defn, nil
}
func (p *parser) typeMap() (*dmt.TypeDefnMap, error) {
defn := &dmt.TypeDefnMap{}
var err error
defn.KeyType, err = p.consumeName()
if err != nil {
return nil, err
}
if err := p.consumeRequired(":"); err != nil {
return defn, err
}
tok, err := p.peekToken()
if err != nil {
return nil, err
}
if tok == "nullable" {
defn.ValueNullable = &globalTrue
p.consumePeeked()
}
defn.ValueType, err = p.typeNameOrInlineDefn()
if err != nil {
return nil, err
}
if err := p.consumeRequired("}"); err != nil {
return defn, err
}
return defn, nil
}
func (p *parser) typeUnion() (*dmt.TypeDefnUnion, error) {
defn := &dmt.TypeDefnUnion{}
var reprKeys []string
for {
tok, err := p.consumeToken()
if err != nil {
return nil, err
}
if tok == "}" {
break
}
if tok != "|" {
return nil, p.errf("expected %q or %q, got %q", "}", "|", tok)
}
var member dmt.UnionMember
nameOrInline, err := p.typeNameOrInlineDefn()
if err != nil {
return nil, err
}
if nameOrInline.TypeName != nil {
member.TypeName = nameOrInline.TypeName
} else {
if nameOrInline.InlineDefn.TypeDefnLink != nil {
member.UnionMemberInlineDefn = &dmt.UnionMemberInlineDefn{TypeDefnLink: nameOrInline.InlineDefn.TypeDefnLink}
} else {
return nil, p.errf("expected a name or inline link, got neither")
}
}
defn.Members = append(defn.Members, member)
key, err := p.consumeToken()
if err != nil {
return nil, err
}
reprKeys = append(reprKeys, key)
}
if err := p.consumeRequired("representation"); err != nil {
return nil, err
}
reprName, err := p.consumeName()
if err != nil {
return nil, err
}
switch reprName {
case "keyed":
repr := &dmt.UnionRepresentation_Keyed{}
for i, keyStr := range reprKeys {
key, err := strconv.Unquote(keyStr)
if err != nil {
return nil, p.forwardError(err)
}
mapAppend(repr, key, defn.Members[i])
}
defn.Representation.UnionRepresentation_Keyed = repr
case "kinded":
repr := &dmt.UnionRepresentation_Kinded{}
// TODO: verify keys are valid kinds? enum should do it for us?
for i, key := range reprKeys {
mapAppend(repr, key, defn.Members[i])
}
defn.Representation.UnionRepresentation_Kinded = repr
case "stringprefix":
repr := &dmt.UnionRepresentation_StringPrefix{
Prefixes: dmt.Map__String__TypeName{
Values: map[string]string{},
},
}
for i, key := range reprKeys {
// unquote prefix string
if len(key) < 2 || key[0] != '"' || key[len(key)-1] != '"' {
return nil, p.errf("invalid stringprefix %q", key)
}
key = key[1 : len(key)-1]
// add prefix to prefixes map
repr.Prefixes.Keys = append(repr.Prefixes.Keys, key)
repr.Prefixes.Values[key] = *defn.Members[i].TypeName
}
defn.Representation.UnionRepresentation_StringPrefix = repr
default:
return nil, p.errf("TODO: union repr %q", reprName)
}
return defn, nil
}
func (p *parser) typeEnum() (*dmt.TypeDefnEnum, error) {
defn := &dmt.TypeDefnEnum{}
var reprKeys []string
for {
tok, err := p.consumeToken()
if err != nil {
return nil, err
}
if tok == "}" {
break
}
if tok != "|" {
return nil, p.errf("expected %q or %q, got %q", "}", "|", tok)
}
name, err := p.consumeToken()
if err != nil {
return nil, err
}
defn.Members = append(defn.Members, name)
if tok, err := p.peekToken(); err == nil && tok == "(" {
p.consumePeeked()
key, err := p.consumeToken()
if err != nil {
return nil, err
}
reprKeys = append(reprKeys, key)
if err := p.consumeRequired(")"); err != nil {
return defn, err
}
} else {
reprKeys = append(reprKeys, "")
}
}
reprName := "string" // default repr
if tok, err := p.peekToken(); err == nil && tok == "representation" {
p.consumePeeked()
name, err := p.consumeName()
if err != nil {
return nil, err
}
reprName = name
}
switch reprName {
case "string":
repr := &dmt.EnumRepresentation_String{}
for i, key := range reprKeys {
if key == "" {
continue // no key; defaults to the name
}
if key[0] != '"' {
return nil, p.errf("enum string representation used with non-string key: %s", key)
}
unquoted, err := strconv.Unquote(key)
if err != nil {
return nil, p.forwardError(err)
}
mapAppend(repr, defn.Members[i], unquoted)
}
defn.Representation.EnumRepresentation_String = repr
case "int":
repr := &dmt.EnumRepresentation_Int{}
for i, key := range reprKeys {
if key[0] != '"' {
return nil, p.errf("enum int representation used with non-string key: %s", key)
}
unquoted, err := strconv.Unquote(key)
if err != nil {
return nil, p.forwardError(err)
}
parsed, err := strconv.Atoi(unquoted)
if err != nil {
return nil, p.forwardError(err)
}
mapAppend(repr, defn.Members[i], parsed)
}
defn.Representation.EnumRepresentation_Int = repr
default:
return nil, p.errf("unknown enum repr: %q", reprName)
}
return defn, nil
}