150 lines
3.1 KiB
Go
150 lines
3.1 KiB
Go
// Copyright 2015-2017 Jean Niklas L'orange. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package edn
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// RawMessage is a raw encoded, but valid, EDN value. It implements Marshaler
|
|
// and Unmarshaler and can be used to delay EDN decoding or precompute an EDN
|
|
// encoding.
|
|
type RawMessage []byte
|
|
|
|
// MarshalEDN returns m as the EDN encoding of m.
|
|
func (m RawMessage) MarshalEDN() ([]byte, error) {
|
|
if m == nil {
|
|
return []byte("nil"), nil
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// UnmarshalEDN sets *m to a copy of data.
|
|
func (m *RawMessage) UnmarshalEDN(data []byte) error {
|
|
if m == nil {
|
|
return errors.New("edn.RawMessage: UnmarshalEDN on nil pointer")
|
|
}
|
|
*m = append((*m)[0:0], data...)
|
|
return nil
|
|
}
|
|
|
|
// A Keyword is an EDN keyword without : prepended in front.
|
|
type Keyword string
|
|
|
|
func (k Keyword) String() string {
|
|
return fmt.Sprintf(":%s", string(k))
|
|
}
|
|
|
|
func (k Keyword) MarshalEDN() ([]byte, error) {
|
|
return []byte(k.String()), nil
|
|
}
|
|
|
|
// A Symbol is an EDN symbol.
|
|
type Symbol string
|
|
|
|
func (s Symbol) String() string {
|
|
return string(s)
|
|
}
|
|
|
|
func (s Symbol) MarshalEDN() ([]byte, error) {
|
|
return []byte(s), nil
|
|
}
|
|
|
|
// A Tag is a tagged value. The Tagname represents the name of the tag, and the
|
|
// Value is the value of the element.
|
|
type Tag struct {
|
|
Tagname string
|
|
Value interface{}
|
|
}
|
|
|
|
func (t Tag) String() string {
|
|
return fmt.Sprintf("#%s %v", t.Tagname, t.Value)
|
|
}
|
|
|
|
func (t Tag) MarshalEDN() ([]byte, error) {
|
|
str := []byte(fmt.Sprintf(`#%s `, t.Tagname))
|
|
b, err := Marshal(t.Value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return append(str, b...), nil
|
|
}
|
|
|
|
func (t *Tag) UnmarshalEDN(bs []byte) error {
|
|
// read actual tag, using the lexer.
|
|
var lex lexer
|
|
lex.reset()
|
|
buf := bufio.NewReader(bytes.NewBuffer(bs))
|
|
start := 0
|
|
endTag := 0
|
|
tag:
|
|
for {
|
|
r, rlen, err := buf.ReadRune()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
ls := lex.state(r)
|
|
switch ls {
|
|
case lexIgnore:
|
|
start += rlen
|
|
endTag += rlen
|
|
case lexError:
|
|
return lex.err
|
|
case lexEndPrev:
|
|
break tag
|
|
case lexEnd: // unexpected, assuming tag which is not ending with lexEnd
|
|
return errUnexpected
|
|
case lexCont:
|
|
endTag += rlen
|
|
}
|
|
}
|
|
t.Tagname = string(bs[start+1 : endTag])
|
|
return Unmarshal(bs[endTag:], &t.Value)
|
|
}
|
|
|
|
// A Rune type is a wrapper for a rune. It can be used to encode runes as
|
|
// characters instead of int32 values.
|
|
type Rune rune
|
|
|
|
func (r Rune) MarshalEDN() ([]byte, error) {
|
|
buf := bytes.NewBuffer(make([]byte, 0, 10))
|
|
encodeRune(buf, rune(r))
|
|
return buf.Bytes(), nil
|
|
}
|
|
|
|
func encodeRune(buf *bytes.Buffer, r rune) {
|
|
const hex = "0123456789abcdef"
|
|
if !isWhitespace(r) {
|
|
buf.WriteByte('\\')
|
|
buf.WriteRune(r)
|
|
} else {
|
|
switch r {
|
|
case '\b':
|
|
buf.WriteString(`\backspace`)
|
|
case '\f':
|
|
buf.WriteString(`\formfeed`)
|
|
case '\n':
|
|
buf.WriteString(`\newline`)
|
|
case '\r':
|
|
buf.WriteString(`\return`)
|
|
case '\t':
|
|
buf.WriteString(`\tab`)
|
|
case ' ':
|
|
buf.WriteString(`\space`)
|
|
default:
|
|
buf.WriteByte('\\')
|
|
buf.WriteByte('u')
|
|
buf.WriteByte(hex[r>>12&0xF])
|
|
buf.WriteByte(hex[r>>8&0xF])
|
|
buf.WriteByte(hex[r>>4&0xF])
|
|
buf.WriteByte(hex[r&0xF])
|
|
}
|
|
}
|
|
}
|