1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 3 of the License, or
7 	(at your option) any later version.
8 
9 	solidity is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /**
19  * @author Christian <chris@ethereum.org>
20  * @date 2016
21  * Utilities to handle semantic versioning.
22  */
23 
24 #pragma once
25 
26 #include <liblangutil/Token.h>
27 #include <libsolutil/Assertions.h>
28 
29 #include <string>
30 #include <optional>
31 #include <utility>
32 #include <vector>
33 
34 namespace solidity::langutil
35 {
36 
37 class SemVerError: public util::Exception
38 {
39 };
40 
41 #undef major
42 #undef minor
43 
44 struct SemVerVersion
45 {
46 	unsigned numbers[3];
47 	std::string prerelease;
48 	std::string build;
49 
majorSemVerVersion50 	unsigned major() const { return numbers[0]; }
minorSemVerVersion51 	unsigned minor() const { return numbers[1]; }
patchSemVerVersion52 	unsigned patch() const { return numbers[2]; }
53 
isPrereleaseSemVerVersion54 	bool isPrerelease() const { return !prerelease.empty(); }
55 
56 	explicit SemVerVersion(std::string const& _versionString = "0.0.0");
57 };
58 
59 struct SemVerMatchExpression
60 {
61 	bool matches(SemVerVersion const& _version) const;
62 
isValidSemVerMatchExpression63 	bool isValid() const { return !m_disjunction.empty(); }
64 
65 	struct MatchComponent
66 	{
67 		/// Prefix from < > <= >= ~ ^
68 		Token prefix = Token::Illegal;
69 		/// Version, where unsigned(-1) in major, minor or patch denotes '*', 'x' or 'X'
70 		SemVerVersion version;
71 		/// Whether we have 1, 1.2 or 1.2.4
72 		unsigned levelsPresent = 1;
73 		bool matches(SemVerVersion const& _version) const;
74 	};
75 
76 	struct Conjunction
77 	{
78 		std::vector<MatchComponent> components;
79 		bool matches(SemVerVersion const& _version) const;
80 	};
81 
82 	std::vector<Conjunction> m_disjunction;
83 };
84 
85 class SemVerMatchExpressionParser
86 {
87 public:
88 	SemVerMatchExpressionParser(std::vector<Token> _tokens, std::vector<std::string> _literals);
89 
90 	/// Returns an expression if it was parseable, or nothing otherwise.
91 	std::optional<SemVerMatchExpression> parse();
92 
93 private:
94 	void reset();
95 
96 	void parseMatchExpression();
97 	SemVerMatchExpression::MatchComponent parseMatchComponent();
98 	unsigned parseVersionPart();
99 
100 	char currentChar() const;
101 	char nextChar();
102 	Token currentToken() const;
103 	void nextToken();
104 
105 	std::vector<Token> m_tokens;
106 	std::vector<std::string> m_literals;
107 
108 	unsigned m_pos = 0;
109 	unsigned m_posInside = 0;
110 
111 	SemVerMatchExpression m_expression;
112 };
113 
114 }
115