mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-05-06 22:18:28 +00:00
243 lines
5.0 KiB
Go
243 lines
5.0 KiB
Go
//Copyright 2013 GoGraphviz Authors
|
|
//
|
|
//Licensed under the Apache License, Version 2.0 (the "License");
|
|
//you may not use this file except in compliance with the License.
|
|
//You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
//Unless required by applicable law or agreed to in writing, software
|
|
//distributed under the License is distributed on an "AS IS" BASIS,
|
|
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
//See the License for the specific language governing permissions and
|
|
//limitations under the License.
|
|
|
|
package token
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Token struct {
|
|
Type Type
|
|
Lit []byte
|
|
}
|
|
|
|
func NewToken(typ Type, lit []byte) *Token {
|
|
return &Token{typ, lit}
|
|
}
|
|
|
|
func (this *Token) Equals(that *Token) bool {
|
|
if this == nil || that == nil {
|
|
return this == that
|
|
}
|
|
|
|
if this.Type != that.Type {
|
|
return false
|
|
}
|
|
|
|
return bytes.Equal(this.Lit, that.Lit)
|
|
}
|
|
|
|
func (this *Token) String() string {
|
|
str := ""
|
|
if this.Type == EOF {
|
|
str += "\"$\""
|
|
} else {
|
|
str += "\"" + string(this.Lit) + "\""
|
|
}
|
|
str += "(" + strconv.Itoa(int(this.Type)) + ")"
|
|
return str
|
|
}
|
|
|
|
type Type int
|
|
|
|
const (
|
|
ILLEGAL Type = iota - 1
|
|
EOF
|
|
)
|
|
|
|
func (T Type) String() string {
|
|
return strconv.Itoa(int(T))
|
|
}
|
|
|
|
// Position describes an arbitrary source position
|
|
// including the file, line, and column location.
|
|
// A Position is valid if the line number is > 0.
|
|
//
|
|
type Position struct {
|
|
Offset int // offset, starting at 0
|
|
Line int // line number, starting at 1
|
|
Column int // column number, starting at 1 (character count)
|
|
}
|
|
|
|
// IsValid returns true if the position is valid.
|
|
func (pos *Position) IsValid() bool { return pos.Line > 0 }
|
|
|
|
// String returns a string in one of several forms:
|
|
//
|
|
// file:line:column valid position with file name
|
|
// line:column valid position without file name
|
|
// file invalid position with file name
|
|
// - invalid position without file name
|
|
//
|
|
func (pos Position) String() string {
|
|
s := ""
|
|
if pos.IsValid() {
|
|
s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
|
|
}
|
|
if s == "" {
|
|
s = "-"
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (T *Token) IntValue() (int64, error) {
|
|
return strconv.ParseInt(string(T.Lit), 10, 64)
|
|
}
|
|
|
|
func (T *Token) UintValue() (uint64, error) {
|
|
return strconv.ParseUint(string(T.Lit), 10, 64)
|
|
}
|
|
|
|
func (T *Token) SDTVal() string {
|
|
sdt := string(T.Lit)
|
|
rex, err := regexp.Compile("\\$[0-9]+")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
idx := rex.FindAllStringIndex(sdt, -1)
|
|
res := ""
|
|
if len(idx) <= 0 {
|
|
res = sdt
|
|
} else {
|
|
for i, loc := range idx {
|
|
if loc[0] > 0 {
|
|
if i > 0 {
|
|
res += sdt[idx[i-1][1]:loc[0]]
|
|
} else {
|
|
res += sdt[0:loc[0]]
|
|
}
|
|
}
|
|
res += "X["
|
|
res += sdt[loc[0]+1 : loc[1]]
|
|
res += "]"
|
|
}
|
|
if idx[len(idx)-1][1] < len(sdt) {
|
|
res += sdt[idx[len(idx)-1][1]:]
|
|
}
|
|
}
|
|
return strings.TrimSpace(res[2 : len(res)-2])
|
|
}
|
|
|
|
//*********** Tokenmap
|
|
|
|
type TokenMap struct {
|
|
tokenMap []string
|
|
stringMap map[string]Type
|
|
}
|
|
|
|
func NewMap() *TokenMap {
|
|
tm := &TokenMap{make([]string, 0, 10), make(map[string]Type)}
|
|
tm.AddToken("$")
|
|
tm.AddToken("ε")
|
|
return tm
|
|
}
|
|
|
|
func (this *TokenMap) AddToken(str string) {
|
|
if _, exists := this.stringMap[str]; exists {
|
|
return
|
|
}
|
|
this.stringMap[str] = Type(len(this.tokenMap))
|
|
this.tokenMap = append(this.tokenMap, str)
|
|
}
|
|
|
|
func NewMapFromFile(file string) (*TokenMap, error) {
|
|
src, err := ioutil.ReadFile(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewMapFromString(string(src)), nil
|
|
}
|
|
|
|
func NewMapFromStrings(input []string) *TokenMap {
|
|
tm := NewMap()
|
|
for _, s := range input {
|
|
tm.AddToken(s)
|
|
}
|
|
return tm
|
|
}
|
|
|
|
func NewMapFromString(input string) *TokenMap {
|
|
tokens := strings.Fields(input)
|
|
return NewMapFromStrings(tokens)
|
|
}
|
|
|
|
func (this *TokenMap) Type(key string) Type {
|
|
tok, ok := this.stringMap[key]
|
|
if !ok {
|
|
return ILLEGAL
|
|
}
|
|
return tok
|
|
}
|
|
|
|
func (this *TokenMap) TokenString(typ Type) string {
|
|
tok := int(typ)
|
|
if tok < 0 || tok >= len(this.tokenMap) {
|
|
return "illegal " + strconv.Itoa(tok)
|
|
}
|
|
return this.tokenMap[tok]
|
|
}
|
|
|
|
func (this *TokenMap) String() string {
|
|
res := ""
|
|
for str, tok := range this.stringMap {
|
|
res += str + " : " + strconv.Itoa(int(tok)) + "\n"
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (this *TokenMap) Strings() []string {
|
|
return this.tokenMap[1:]
|
|
}
|
|
|
|
func (this *TokenMap) Equals(that *TokenMap) bool {
|
|
if this == nil || that == nil {
|
|
return false
|
|
}
|
|
|
|
if len(this.stringMap) != len(that.stringMap) ||
|
|
len(this.tokenMap) != len(that.tokenMap) {
|
|
return false
|
|
}
|
|
|
|
for str, tok := range this.stringMap {
|
|
if tok1, ok := that.stringMap[str]; !ok || tok1 != tok {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (this *TokenMap) Tokens() []*Token {
|
|
res := make([]*Token, 0, len(this.stringMap))
|
|
for typ, str := range this.tokenMap {
|
|
res = append(res, &Token{Type(typ), []byte(str)})
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (this *TokenMap) WriteFile(file string) error {
|
|
out := ""
|
|
for i := 1; i < len(this.tokenMap); i++ {
|
|
out += this.TokenString(Type(i)) + "\n"
|
|
}
|
|
return ioutil.WriteFile(file, []byte(out), 0644)
|
|
}
|