...

Source file src/github.com/emicklei/proto/enum.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  // Enum definition consists of a name and an enum body.
    31  type Enum struct {
    32  	Position scanner.Position
    33  	Comment  *Comment
    34  	Name     string
    35  	Elements []Visitee
    36  	Parent   Visitee
    37  }
    38  
    39  // Accept dispatches the call to the visitor.
    40  func (e *Enum) Accept(v Visitor) {
    41  	v.VisitEnum(e)
    42  }
    43  
    44  // Doc is part of Documented
    45  func (e *Enum) Doc() *Comment {
    46  	return e.Comment
    47  }
    48  
    49  // addElement is part of elementContainer
    50  func (e *Enum) addElement(v Visitee) {
    51  	v.parent(e)
    52  	e.Elements = append(e.Elements, v)
    53  }
    54  
    55  // elements is part of elementContainer
    56  func (e *Enum) elements() []Visitee {
    57  	return e.Elements
    58  }
    59  
    60  // takeLastComment is part of elementContainer
    61  // removes and returns the last element of the list if it is a Comment.
    62  func (e *Enum) takeLastComment(expectedOnLine int) (last *Comment) {
    63  	last, e.Elements = takeLastCommentIfEndsOnLine(e.Elements, expectedOnLine)
    64  	return
    65  }
    66  
    67  func (e *Enum) parse(p *Parser) error {
    68  	pos, tok, lit := p.next()
    69  	if tok != tIDENT {
    70  		if !isKeyword(tok) {
    71  			return p.unexpected(lit, "enum identifier", e)
    72  		}
    73  	}
    74  	e.Name = lit
    75  	consumeCommentFor(p, e)
    76  	_, tok, lit = p.next()
    77  	if tok != tLEFTCURLY {
    78  		return p.unexpected(lit, "enum opening {", e)
    79  	}
    80  	for {
    81  		pos, tok, lit = p.next()
    82  		switch tok {
    83  		case tCOMMENT:
    84  			if com := mergeOrReturnComment(e.elements(), lit, pos); com != nil { // not merged?
    85  				e.addElement(com)
    86  			}
    87  		case tOPTION:
    88  			v := new(Option)
    89  			v.Position = pos
    90  			v.Comment = e.takeLastComment(pos.Line)
    91  			err := v.parse(p)
    92  			if err != nil {
    93  				return err
    94  			}
    95  			e.addElement(v)
    96  		case tRIGHTCURLY, tEOF:
    97  			goto done
    98  		case tSEMICOLON:
    99  			maybeScanInlineComment(p, e)
   100  		case tRESERVED:
   101  			r := new(Reserved)
   102  			r.Position = pos
   103  			r.Comment = e.takeLastComment(pos.Line - 1)
   104  			if err := r.parse(p); err != nil {
   105  				return err
   106  			}
   107  			e.addElement(r)
   108  		default:
   109  			p.nextPut(pos, tok, lit)
   110  			f := new(EnumField)
   111  			f.Position = pos
   112  			f.Comment = e.takeLastComment(pos.Line - 1)
   113  			err := f.parse(p)
   114  			if err != nil {
   115  				return err
   116  			}
   117  			e.addElement(f)
   118  		}
   119  	}
   120  done:
   121  	if tok != tRIGHTCURLY {
   122  		return p.unexpected(lit, "enum closing }", e)
   123  	}
   124  	return nil
   125  }
   126  
   127  // parent is part of elementContainer
   128  func (e *Enum) parent(p Visitee) { e.Parent = p }
   129  
   130  // EnumField is part of the body of an Enum.
   131  type EnumField struct {
   132  	Position scanner.Position
   133  	Comment  *Comment
   134  	Name     string
   135  	Integer  int
   136  	// ValueOption is deprecated, use Elements instead
   137  	ValueOption   *Option
   138  	Elements      []Visitee // such as Option and Comment
   139  	InlineComment *Comment
   140  	Parent        Visitee
   141  }
   142  
   143  // elements is part of elementContainer
   144  func (f *EnumField) elements() []Visitee {
   145  	return f.Elements
   146  }
   147  
   148  // takeLastComment is part of elementContainer
   149  // removes and returns the last element of the list if it is a Comment.
   150  func (f *EnumField) takeLastComment(expectedOnLine int) (last *Comment) {
   151  	last, f.Elements = takeLastCommentIfEndsOnLine(f.Elements, expectedOnLine)
   152  	return
   153  }
   154  
   155  // Accept dispatches the call to the visitor.
   156  func (f *EnumField) Accept(v Visitor) {
   157  	v.VisitEnumField(f)
   158  }
   159  
   160  // inlineComment is part of commentInliner.
   161  func (f *EnumField) inlineComment(c *Comment) {
   162  	f.InlineComment = c
   163  }
   164  
   165  // Doc is part of Documented
   166  func (f *EnumField) Doc() *Comment {
   167  	return f.Comment
   168  }
   169  
   170  func (f *EnumField) parse(p *Parser) error {
   171  	_, tok, lit := p.nextIdentifier()
   172  	if tok != tIDENT {
   173  		if !isKeyword(tok) {
   174  			return p.unexpected(lit, "enum field identifier", f)
   175  		}
   176  	}
   177  	f.Name = lit
   178  	pos, tok, lit := p.next()
   179  	if tok != tEQUALS {
   180  		return p.unexpected(lit, "enum field =", f)
   181  	}
   182  	i, err := p.nextInteger()
   183  	if err != nil {
   184  		return p.unexpected(err.Error(), "enum field integer", f)
   185  	}
   186  	f.Integer = i
   187  	pos, tok, lit = p.next()
   188  	if tok == tLEFTSQUARE {
   189  		for {
   190  			o := new(Option)
   191  			o.Position = pos
   192  			o.IsEmbedded = true
   193  			err := o.parse(p)
   194  			if err != nil {
   195  				return err
   196  			}
   197  			// update deprecated field with the last option found
   198  			f.ValueOption = o
   199  			f.addElement(o)
   200  			pos, tok, lit = p.next()
   201  			if tok == tCOMMA {
   202  				continue
   203  			}
   204  			if tok == tRIGHTSQUARE {
   205  				break
   206  			}
   207  		}
   208  	}
   209  	if tSEMICOLON == tok {
   210  		p.nextPut(pos, tok, lit) // put back this token for scanning inline comment
   211  	}
   212  	return nil
   213  }
   214  
   215  // addElement is part of elementContainer
   216  func (f *EnumField) addElement(v Visitee) {
   217  	v.parent(f)
   218  	f.Elements = append(f.Elements, v)
   219  }
   220  
   221  func (f *EnumField) parent(v Visitee) { f.Parent = v }
   222  
   223  // IsDeprecated returns true if the option "deprecated" is set with value "true".
   224  func (f *EnumField) IsDeprecated() bool {
   225  	for _, each := range f.Elements {
   226  		if opt, ok := each.(*Option); ok {
   227  			if opt.Name == optionNameDeprecated {
   228  				return opt.Constant.Source == "true"
   229  			}
   230  		}
   231  	}
   232  	return false
   233  }
   234  

View as plain text