github.com/ubuntu-core/snappy@v0.0.0-20210827154228-9e584df982bb/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 redistribute 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  )
    26  
    27  const (
    28  	opAND  = "AND"
    29  	opOR   = "OR"
    30  	opWITH = "WITH"
    31  )
    32  
    33  func isOperator(tok string) bool {
    34  	return tok == opAND || tok == opOR || tok == opWITH
    35  }
    36  
    37  type licenseID string
    38  
    39  func newLicenseID(s string) (licenseID, error) {
    40  	needle := s
    41  	for _, known := range allLicenses {
    42  		if needle == known {
    43  			return licenseID(s), nil
    44  		}
    45  	}
    46  	return "", fmt.Errorf("unknown license: %s", s)
    47  }
    48  
    49  type licenseExceptionID string
    50  
    51  func newLicenseExceptionID(s string) (licenseExceptionID, error) {
    52  	for _, known := range licenseExceptions {
    53  		if s == known {
    54  			return licenseExceptionID(s), nil
    55  		}
    56  	}
    57  	return "", fmt.Errorf("unknown license exception: %s", s)
    58  }
    59  
    60  type parser struct {
    61  	s *Scanner
    62  }
    63  
    64  func newParser(r io.Reader) *parser {
    65  	return &parser{s: NewScanner(r)}
    66  }
    67  
    68  func (p *parser) Validate() error {
    69  	return p.validate(0)
    70  }
    71  
    72  func (p *parser) validate(depth int) error {
    73  	last := ""
    74  
    75  	for p.s.Scan() {
    76  		tok := p.s.Text()
    77  
    78  		switch {
    79  		case tok == "(":
    80  			if last == opWITH {
    81  				return fmt.Errorf("%q not allowed after WITH", tok)
    82  			}
    83  			if err := p.validate(depth + 1); err != nil {
    84  				return err
    85  			}
    86  			if p.s.Text() != ")" {
    87  				return fmt.Errorf(`expected ")" got %q`, p.s.Text())
    88  			}
    89  		case tok == ")":
    90  			if depth == 0 {
    91  				return fmt.Errorf(`unexpected ")"`)
    92  			}
    93  			if last == "" {
    94  				return fmt.Errorf("empty expression")
    95  			}
    96  			return nil
    97  		case isOperator(tok):
    98  			if last == "" {
    99  				return fmt.Errorf("missing license before %s", tok)
   100  			}
   101  			if last == opAND || last == opOR {
   102  				return fmt.Errorf("expected license name, got %q", tok)
   103  			}
   104  			if tok == opWITH && last == "(" {
   105  				return fmt.Errorf("expected license name before %s", tok)
   106  			}
   107  			if last == opWITH {
   108  				return fmt.Errorf("expected exception name, got %q", tok)
   109  			}
   110  		default:
   111  			switch {
   112  			case last == opWITH:
   113  				if _, err := newLicenseExceptionID(tok); err != nil {
   114  					return err
   115  				}
   116  			case last == "", last == opAND, last == opOR:
   117  				if _, err := newLicenseID(tok); err != nil {
   118  					return err
   119  				}
   120  			default:
   121  				if _, err := newLicenseID(last); err == nil {
   122  					if _, err := newLicenseID(tok); err == nil {
   123  						return fmt.Errorf("missing AND or OR between %q and %q", last, tok)
   124  					}
   125  				}
   126  				return fmt.Errorf("unexpected string: %q", tok)
   127  			}
   128  
   129  		}
   130  		last = tok
   131  	}
   132  	if err := p.s.Err(); err != nil {
   133  		return err
   134  	}
   135  	if isOperator(last) {
   136  		return fmt.Errorf("missing license after %s", last)
   137  	}
   138  	if last == "" {
   139  		return fmt.Errorf("empty expression")
   140  	}
   141  
   142  	return nil
   143  }