1// Copyright (c) 2017 Ernest Micklei 2// 3// MIT License 4// 5// Permission is hereby granted, free of charge, to any person obtaining 6// a copy of this software and associated documentation files (the 7// "Software"), to deal in the Software without restriction, including 8// without limitation the rights to use, copy, modify, merge, publish, 9// distribute, sublicense, and/or sell copies of the Software, and to 10// permit persons to whom the Software is furnished to do so, subject to 11// the following conditions: 12// 13// The above copyright notice and this permission notice shall be 14// included in all copies or substantial portions of the Software. 15// 16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24package proto 25 26import ( 27 "fmt" 28 "strconv" 29 "text/scanner" 30) 31 32// Field is an abstract message field. 33type Field struct { 34 Position scanner.Position 35 Comment *Comment 36 Name string 37 Type string 38 Sequence int 39 Options []*Option 40 InlineComment *Comment 41} 42 43// inlineComment is part of commentInliner. 44func (f *Field) inlineComment(c *Comment) { 45 f.InlineComment = c 46} 47 48// NormalField represents a field in a Message. 49type NormalField struct { 50 *Field 51 Repeated bool 52 Optional bool // proto2 53 Required bool // proto2 54} 55 56func newNormalField() *NormalField { return &NormalField{Field: new(Field)} } 57 58// Accept dispatches the call to the visitor. 59func (f *NormalField) Accept(v Visitor) { 60 v.VisitNormalField(f) 61} 62 63// Doc is part of Documented 64func (f *NormalField) Doc() *Comment { 65 return f.Comment 66} 67 68// columns returns printable source tokens 69func (f *NormalField) columns() (cols []aligned) { 70 if f.Repeated { 71 cols = append(cols, leftAligned("repeated ")) 72 } else { 73 cols = append(cols, alignedEmpty) 74 } 75 if f.Optional { 76 cols = append(cols, leftAligned("optional ")) 77 } else { 78 cols = append(cols, alignedEmpty) 79 } 80 cols = append(cols, rightAligned(f.Type), alignedSpace, leftAligned(f.Name), alignedEquals, rightAligned(strconv.Itoa(f.Sequence))) 81 if len(f.Options) > 0 { 82 cols = append(cols, leftAligned(" [")) 83 for i, each := range f.Options { 84 if i > 0 { 85 cols = append(cols, alignedComma) 86 } 87 cols = append(cols, each.keyValuePair(true)...) 88 } 89 cols = append(cols, leftAligned("]")) 90 } 91 cols = append(cols, alignedSemicolon) 92 if f.InlineComment != nil { 93 cols = append(cols, f.InlineComment.alignedInlinePrefix(), notAligned(f.InlineComment.Message())) 94 } 95 return 96} 97 98// parse expects: 99// [ "repeated" | "optional" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";" 100func (f *NormalField) parse(p *Parser) error { 101 for { 102 _, tok, lit := p.nextIdentifier() 103 switch tok { 104 case tREPEATED: 105 f.Repeated = true 106 return f.parse(p) 107 case tOPTIONAL: // proto2 108 f.Optional = true 109 return f.parse(p) 110 case tIDENT: 111 f.Type = lit 112 return parseFieldAfterType(f.Field, p) 113 default: 114 goto done 115 } 116 } 117done: 118 return nil 119} 120 121// parseFieldAfterType expects: 122// fieldName "=" fieldNumber [ "[" fieldOptions "]" ] "; 123func parseFieldAfterType(f *Field, p *Parser) error { 124 pos, tok, lit := p.next() 125 if tok != tIDENT { 126 if !isKeyword(tok) { 127 return p.unexpected(lit, "field identifier", f) 128 } 129 } 130 f.Name = lit 131 pos, tok, lit = p.next() 132 if tok != tEQUALS { 133 return p.unexpected(lit, "field =", f) 134 } 135 i, err := p.nextInteger() 136 if err != nil { 137 return p.unexpected(lit, "field sequence number", f) 138 } 139 f.Sequence = i 140 // see if there are options 141 pos, tok, lit = p.next() 142 if tLEFTSQUARE != tok { 143 return nil 144 } 145 // consume options 146 for { 147 o := new(Option) 148 o.Position = pos 149 o.IsEmbedded = true 150 err := o.parse(p) 151 if err != nil { 152 return err 153 } 154 f.Options = append(f.Options, o) 155 156 pos, tok, lit = p.next() 157 if tRIGHTSQUARE == tok { 158 break 159 } 160 if tCOMMA != tok { 161 return p.unexpected(lit, "option ,", o) 162 } 163 } 164 return nil 165} 166 167func (n *NormalField) String() string { return fmt.Sprintf("<field %s=%d>", n.Name, n.Sequence) } 168 169// MapField represents a map entry in a message. 170type MapField struct { 171 *Field 172 KeyType string 173} 174 175func newMapField() *MapField { return &MapField{Field: new(Field)} } 176 177// Accept dispatches the call to the visitor. 178func (f *MapField) Accept(v Visitor) { 179 v.VisitMapField(f) 180} 181 182// columns returns printable source tokens 183func (f *MapField) columns() (cols []aligned) { 184 cols = append(cols, 185 notAligned("map <"), 186 rightAligned(f.KeyType), 187 notAligned(","), 188 leftAligned(f.Type), 189 notAligned("> "), 190 rightAligned(f.Name), 191 alignedEquals, 192 rightAligned(strconv.Itoa(f.Sequence))) 193 if len(f.Options) > 0 { 194 cols = append(cols, leftAligned(" [")) 195 for i, each := range f.Options { 196 if i > 0 { 197 cols = append(cols, alignedComma) 198 } 199 cols = append(cols, each.keyValuePair(true)...) 200 } 201 cols = append(cols, leftAligned("]")) 202 } 203 cols = append(cols, alignedSemicolon) 204 if f.InlineComment != nil { 205 cols = append(cols, f.InlineComment.alignedInlinePrefix(), notAligned(f.InlineComment.Message())) 206 } 207 return 208} 209 210// parse expects: 211// mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber [ "[" fieldOptions "]" ] ";" 212// keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" | 213// "fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string" 214func (f *MapField) parse(p *Parser) error { 215 _, tok, lit := p.next() 216 if tLESS != tok { 217 return p.unexpected(lit, "map keyType <", f) 218 } 219 _, tok, lit = p.next() 220 if tIDENT != tok { 221 return p.unexpected(lit, "map identifier", f) 222 } 223 f.KeyType = lit 224 _, tok, lit = p.next() 225 if tCOMMA != tok { 226 return p.unexpected(lit, "map type separator ,", f) 227 } 228 _, tok, lit = p.nextIdentifier() 229 if tIDENT != tok { 230 return p.unexpected(lit, "map valueType identifier", f) 231 } 232 f.Type = lit 233 _, tok, lit = p.next() 234 if tGREATER != tok { 235 return p.unexpected(lit, "map valueType >", f) 236 } 237 return parseFieldAfterType(f.Field, p) 238} 239