literals.go

  1package common
  2
  3import (
  4	"strconv"
  5	"strings"
  6	"text/scanner"
  7
  8	"github.com/vektah/gqlgen/neelance/errors"
  9)
 10
 11type Literal interface {
 12	Value(vars map[string]interface{}) interface{}
 13	String() string
 14	Location() errors.Location
 15}
 16
 17type BasicLit struct {
 18	Type rune
 19	Text string
 20	Loc  errors.Location
 21}
 22
 23func (lit *BasicLit) Value(vars map[string]interface{}) interface{} {
 24	switch lit.Type {
 25	case scanner.Int:
 26		value, err := strconv.ParseInt(lit.Text, 10, 64)
 27		if err != nil {
 28			panic(err)
 29		}
 30		return int(value)
 31
 32	case scanner.Float:
 33		value, err := strconv.ParseFloat(lit.Text, 64)
 34		if err != nil {
 35			panic(err)
 36		}
 37		return value
 38
 39	case scanner.String:
 40		value, err := strconv.Unquote(lit.Text)
 41		if err != nil {
 42			panic(err)
 43		}
 44		return value
 45
 46	case scanner.Ident:
 47		switch lit.Text {
 48		case "true":
 49			return true
 50		case "false":
 51			return false
 52		default:
 53			return lit.Text
 54		}
 55
 56	default:
 57		panic("invalid literal")
 58	}
 59}
 60
 61func (lit *BasicLit) String() string {
 62	return lit.Text
 63}
 64
 65func (lit *BasicLit) Location() errors.Location {
 66	return lit.Loc
 67}
 68
 69type ListLit struct {
 70	Entries []Literal
 71	Loc     errors.Location
 72}
 73
 74func (lit *ListLit) Value(vars map[string]interface{}) interface{} {
 75	entries := make([]interface{}, len(lit.Entries))
 76	for i, entry := range lit.Entries {
 77		entries[i] = entry.Value(vars)
 78	}
 79	return entries
 80}
 81
 82func (lit *ListLit) String() string {
 83	entries := make([]string, len(lit.Entries))
 84	for i, entry := range lit.Entries {
 85		entries[i] = entry.String()
 86	}
 87	return "[" + strings.Join(entries, ", ") + "]"
 88}
 89
 90func (lit *ListLit) Location() errors.Location {
 91	return lit.Loc
 92}
 93
 94type ObjectLit struct {
 95	Fields []*ObjectLitField
 96	Loc    errors.Location
 97}
 98
 99type ObjectLitField struct {
100	Name  Ident
101	Value Literal
102}
103
104func (lit *ObjectLit) Value(vars map[string]interface{}) interface{} {
105	fields := make(map[string]interface{}, len(lit.Fields))
106	for _, f := range lit.Fields {
107		fields[f.Name.Name] = f.Value.Value(vars)
108	}
109	return fields
110}
111
112func (lit *ObjectLit) String() string {
113	entries := make([]string, 0, len(lit.Fields))
114	for _, f := range lit.Fields {
115		entries = append(entries, f.Name.Name+": "+f.Value.String())
116	}
117	return "{" + strings.Join(entries, ", ") + "}"
118}
119
120func (lit *ObjectLit) Location() errors.Location {
121	return lit.Loc
122}
123
124type NullLit struct {
125	Loc errors.Location
126}
127
128func (lit *NullLit) Value(vars map[string]interface{}) interface{} {
129	return nil
130}
131
132func (lit *NullLit) String() string {
133	return "null"
134}
135
136func (lit *NullLit) Location() errors.Location {
137	return lit.Loc
138}
139
140type Variable struct {
141	Name string
142	Loc  errors.Location
143}
144
145func (v Variable) Value(vars map[string]interface{}) interface{} {
146	return vars[v.Name]
147}
148
149func (v Variable) String() string {
150	return "$" + v.Name
151}
152
153func (v *Variable) Location() errors.Location {
154	return v.Loc
155}
156
157func ParseLiteral(l *Lexer, constOnly bool) Literal {
158	loc := l.Location()
159	switch l.Peek() {
160	case '$':
161		if constOnly {
162			l.SyntaxError("variable not allowed")
163			panic("unreachable")
164		}
165		l.ConsumeToken('$')
166		return &Variable{l.ConsumeIdent(), loc}
167
168	case scanner.Int, scanner.Float, scanner.String, scanner.Ident:
169		lit := l.ConsumeLiteral()
170		if lit.Type == scanner.Ident && lit.Text == "null" {
171			return &NullLit{loc}
172		}
173		lit.Loc = loc
174		return lit
175	case '-':
176		l.ConsumeToken('-')
177		lit := l.ConsumeLiteral()
178		lit.Text = "-" + lit.Text
179		lit.Loc = loc
180		return lit
181	case '[':
182		l.ConsumeToken('[')
183		var list []Literal
184		for l.Peek() != ']' {
185			list = append(list, ParseLiteral(l, constOnly))
186		}
187		l.ConsumeToken(']')
188		return &ListLit{list, loc}
189
190	case '{':
191		l.ConsumeToken('{')
192		var fields []*ObjectLitField
193		for l.Peek() != '}' {
194			name := l.ConsumeIdentWithLoc()
195			l.ConsumeToken(':')
196			value := ParseLiteral(l, constOnly)
197			fields = append(fields, &ObjectLitField{name, value})
198		}
199		l.ConsumeToken('}')
200		return &ObjectLit{fields, loc}
201
202	default:
203		l.SyntaxError("invalid value")
204		panic("unreachable")
205	}
206}