github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/spdx/parser.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribuLicenseidte it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package spdx
    21  
    22  import (
    23  	"fmt"
    24  	"io"
    25  	"strings"
    26  )
    27  
    28  const (
    29  	opUNSET = ""
    30  	opAND   = "AND"
    31  	opOR    = "OR"
    32  	opWITH  = "WITH"
    33  )
    34  
    35  func isOperator(tok string) bool {
    36  	return tok == opAND || tok == opOR || tok == opWITH
    37  }
    38  
    39  type licenseID string
    40  
    41  func newLicenseID(s string) (licenseID, error) {
    42  	needle := s
    43  	if strings.HasSuffix(s, "+") {
    44  		needle = s[:len(s)-1]
    45  	}
    46  	for _, known := range allLicenses {
    47  		if needle == known {
    48  			return licenseID(s), nil
    49  		}
    50  	}
    51  	return "", fmt.Errorf("unknown license: %s", s)
    52  }
    53  
    54  type licenseExceptionID string
    55  
    56  func newLicenseExceptionID(s string) (licenseExceptionID, error) {
    57  	for _, known := range licenseExceptions {
    58  		if s == known {
    59  			return licenseExceptionID(s), nil
    60  		}
    61  	}
    62  	return "", fmt.Errorf("unknown license exception: %s", s)
    63  }
    64  
    65  type parser struct {
    66  	s *Scanner
    67  }
    68  
    69  func newParser(r io.Reader) *parser {
    70  	return &parser{s: NewScanner(r)}
    71  }
    72  
    73  func (p *parser) Validate() error {
    74  	return p.validate(0)
    75  }
    76  
    77  func (p *parser) advance(id string) error {
    78  	if p.s.Text() != id {
    79  		return fmt.Errorf("expected %q got %q", id, p.s.Text())
    80  	}
    81  	return nil
    82  }
    83  
    84  func (p *parser) validate(depth int) error {
    85  	last := ""
    86  
    87  	for p.s.Scan() {
    88  		tok := p.s.Text()
    89  
    90  		switch {
    91  		case tok == "(":
    92  			if last == opWITH {
    93  				return fmt.Errorf("%q not allowed after WITH", tok)
    94  			}
    95  			if err := p.validate(depth + 1); err != nil {
    96  				return err
    97  			}
    98  			if p.s.Text() != ")" {
    99  				return fmt.Errorf(`expected ")" got %q`, p.s.Text())
   100  			}
   101  		case tok == ")":
   102  			if depth == 0 {
   103  				return fmt.Errorf(`unexpected ")"`)
   104  			}
   105  			if last == "" {
   106  				return fmt.Errorf("empty expression")
   107  			}
   108  			return nil
   109  		case isOperator(tok):
   110  			if last == "" {
   111  				return fmt.Errorf("missing license before %s", tok)
   112  			}
   113  			if last == opAND || last == opOR {
   114  				return fmt.Errorf("expected license name, got %q", tok)
   115  			}
   116  			if tok == opWITH && last == "(" {
   117  				return fmt.Errorf("expected license name before %s", tok)
   118  			}
   119  			if last == opWITH {
   120  				return fmt.Errorf("expected exception name, got %q", tok)
   121  			}
   122  		default:
   123  			switch {
   124  			case last == opWITH:
   125  				if _, err := newLicenseExceptionID(tok); err != nil {
   126  					return err
   127  				}
   128  			case last == "", last == opAND, last == opOR:
   129  				if _, err := newLicenseID(tok); err != nil {
   130  					return err
   131  				}
   132  			default:
   133  				if _, err := newLicenseID(last); err == nil {
   134  					if _, err := newLicenseID(tok); err == nil {
   135  						return fmt.Errorf("missing AND or OR between %q and %q", last, tok)
   136  					}
   137  				}
   138  				return fmt.Errorf("unexpected string: %q", tok)
   139  			}
   140  
   141  		}
   142  		last = tok
   143  	}
   144  	if err := p.s.Err(); err != nil {
   145  		return err
   146  	}
   147  	if isOperator(last) {
   148  		return fmt.Errorf("missing license after %s", last)
   149  	}
   150  	if last == "" {
   151  		return fmt.Errorf("empty expression")
   152  	}
   153  
   154  	return nil
   155  }