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 }