...

Source file src/github.com/emicklei/proto/field.go

Documentation: github.com/emicklei/proto

     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  
    24  package proto
    25  
    26  import (
    27  	"text/scanner"
    28  )
    29  
    30  // Field is an abstract message field.
    31  type Field struct {
    32  	Position      scanner.Position
    33  	Comment       *Comment
    34  	Name          string
    35  	Type          string
    36  	Sequence      int
    37  	Options       []*Option
    38  	InlineComment *Comment
    39  	Parent        Visitee
    40  }
    41  
    42  // inlineComment is part of commentInliner.
    43  func (f *Field) inlineComment(c *Comment) {
    44  	f.InlineComment = c
    45  }
    46  
    47  // NormalField represents a field in a Message.
    48  type NormalField struct {
    49  	*Field
    50  	Repeated bool
    51  	Optional bool // proto2
    52  	Required bool // proto2
    53  }
    54  
    55  func newNormalField() *NormalField { return &NormalField{Field: new(Field)} }
    56  
    57  // Accept dispatches the call to the visitor.
    58  func (f *NormalField) Accept(v Visitor) {
    59  	v.VisitNormalField(f)
    60  }
    61  
    62  // Doc is part of Documented
    63  func (f *NormalField) Doc() *Comment {
    64  	return f.Comment
    65  }
    66  
    67  // parse expects:
    68  // [ "repeated" | "optional" ] type fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
    69  func (f *NormalField) parse(p *Parser) error {
    70  	for {
    71  		pos, tok, lit := p.nextTypeName()
    72  		switch tok {
    73  		case tCOMMENT:
    74  			c := newComment(pos, lit)
    75  			if f.InlineComment == nil {
    76  				f.InlineComment = c
    77  			} else {
    78  				f.InlineComment.Merge(c)
    79  			}
    80  		case tREPEATED:
    81  			f.Repeated = true
    82  			return f.parse(p)
    83  		case tOPTIONAL: // proto2
    84  			f.Optional = true
    85  			return f.parse(p)
    86  		case tIDENT:
    87  			f.Type = lit
    88  			return parseFieldAfterType(f.Field, p, f)
    89  		default:
    90  			goto done
    91  		}
    92  	}
    93  done:
    94  	return nil
    95  }
    96  
    97  // parseFieldAfterType expects:
    98  // fieldName "=" fieldNumber [ "[" fieldOptions "]" ] ";
    99  func parseFieldAfterType(f *Field, p *Parser, parent Visitee) error {
   100  	expectedToken := tIDENT
   101  	expected := "field identifier"
   102  
   103  	for {
   104  		pos, tok, lit := p.next()
   105  		if tok == tCOMMENT {
   106  			c := newComment(pos, lit)
   107  			if f.InlineComment == nil {
   108  				f.InlineComment = c
   109  			} else {
   110  				f.InlineComment.Merge(c)
   111  			}
   112  			continue
   113  		}
   114  		if tok != expectedToken {
   115  			// allow keyword as field name
   116  			if expectedToken == tIDENT && isKeyword(tok) {
   117  				// continue as identifier
   118  				tok = tIDENT
   119  			} else {
   120  				return p.unexpected(lit, expected, f)
   121  			}
   122  		}
   123  		// found expected token
   124  		if tok == tIDENT {
   125  			f.Name = lit
   126  			expectedToken = tEQUALS
   127  			expected = "field ="
   128  			continue
   129  		}
   130  		if tok == tEQUALS {
   131  			expectedToken = tNUMBER
   132  			expected = "field sequence number"
   133  			continue
   134  		}
   135  		if tok == tNUMBER {
   136  			// put it back so we can use the generic nextInteger
   137  			p.nextPut(pos, tok, lit)
   138  			i, err := p.nextInteger()
   139  			if err != nil {
   140  				return p.unexpected(lit, expected, f)
   141  			}
   142  			f.Sequence = i
   143  			break
   144  		}
   145  	}
   146  	consumeFieldComments(f, p)
   147  
   148  	// see if there are options
   149  	pos, tok, lit := p.next()
   150  	if tLEFTSQUARE != tok {
   151  		p.nextPut(pos, tok, lit)
   152  		return nil
   153  	}
   154  	// consume options
   155  	for {
   156  		o := new(Option)
   157  		o.Position = pos
   158  		o.IsEmbedded = true
   159  		o.parent(parent)
   160  		err := o.parse(p)
   161  		if err != nil {
   162  			return err
   163  		}
   164  		f.Options = append(f.Options, o)
   165  
   166  		pos, tok, lit = p.next()
   167  		if tRIGHTSQUARE == tok {
   168  			break
   169  		}
   170  		if tCOMMA != tok {
   171  			return p.unexpected(lit, "option ,", o)
   172  		}
   173  	}
   174  	return nil
   175  }
   176  
   177  func consumeFieldComments(f *Field, p *Parser) {
   178  	pos, tok, lit := p.next()
   179  	for tok == tCOMMENT {
   180  		c := newComment(pos, lit)
   181  		if f.InlineComment == nil {
   182  			f.InlineComment = c
   183  		} else {
   184  			f.InlineComment.Merge(c)
   185  		}
   186  		pos, tok, lit = p.next()
   187  	}
   188  	// no longer a comment, put it back
   189  	p.nextPut(pos, tok, lit)
   190  }
   191  
   192  // MapField represents a map entry in a message.
   193  type MapField struct {
   194  	*Field
   195  	KeyType string
   196  }
   197  
   198  func newMapField() *MapField { return &MapField{Field: new(Field)} }
   199  
   200  // Accept dispatches the call to the visitor.
   201  func (f *MapField) Accept(v Visitor) {
   202  	v.VisitMapField(f)
   203  }
   204  
   205  // Doc is part of Documented
   206  func (f *MapField) Doc() *Comment {
   207  	return f.Comment
   208  }
   209  
   210  // parse expects:
   211  // mapField = "map" "<" keyType "," type ">" mapName "=" fieldNumber [ "[" fieldOptions "]" ] ";"
   212  // keyType = "int32" | "int64" | "uint32" | "uint64" | "sint32" | "sint64" |
   213  //
   214  //	"fixed32" | "fixed64" | "sfixed32" | "sfixed64" | "bool" | "string"
   215  func (f *MapField) parse(p *Parser) error {
   216  	_, tok, lit := p.next()
   217  	if tLESS != tok {
   218  		return p.unexpected(lit, "map keyType <", f)
   219  	}
   220  	_, tok, lit = p.nextTypeName()
   221  	if tIDENT != tok {
   222  		return p.unexpected(lit, "map identifier", f)
   223  	}
   224  	f.KeyType = lit
   225  	_, tok, lit = p.next()
   226  	if tCOMMA != tok {
   227  		return p.unexpected(lit, "map type separator ,", f)
   228  	}
   229  	_, tok, lit = p.nextTypeName()
   230  	if tIDENT != tok {
   231  		return p.unexpected(lit, "map valueType identifier", f)
   232  	}
   233  	f.Type = lit
   234  	_, tok, lit = p.next()
   235  	if tGREATER != tok {
   236  		return p.unexpected(lit, "map valueType >", f)
   237  	}
   238  	return parseFieldAfterType(f.Field, p, f)
   239  }
   240  
   241  func (f *Field) parent(v Visitee) { f.Parent = v }
   242  
   243  const optionNameDeprecated = "deprecated"
   244  
   245  // IsDeprecated returns true if the option "deprecated" is set with value "true".
   246  func (f *Field) IsDeprecated() bool {
   247  	for _, each := range f.Options {
   248  		if each.Name == optionNameDeprecated {
   249  			return each.Constant.Source == "true"
   250  		}
   251  	}
   252  	return false
   253  }
   254  

View as plain text