Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3c412ed

Browse files
committed
Version pragma.
1 parent 52d9f89 commit 3c412ed

27 files changed

+902
-66
lines changed

docs/layout-of-source-files.rst

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,36 @@
22
Layout of a Solidity Source File
33
********************************
44

5-
Source files can contain an arbitrary number of contract definitions and include directives.
5+
Source files can contain an arbitrary number of contract definitions, include directives
6+
and pragma directives.
7+
8+
.. index:: ! pragma, version
9+
10+
Version Pragma
11+
==============
12+
13+
Source files can (and should) be annotated with a so-called version pragma to reject
14+
being compiled with future compiler versions that might introduce incompatible
15+
changes. We try to keep such changes at an absolute minimum and especially
16+
introduce changes in a way that changes in semantics will also require changes
17+
in the syntax, but this is of course not always possible. Because of that, it is always
18+
a good idea to read through the changelog at least for releases that contain
19+
breaking changes, those releases will always have versions of the form
20+
``0.x.0`` or ``x.0.0``.
21+
22+
The version pragma is used as follows::
23+
24+
pragma solidity ^0.4.0;
25+
26+
Such a source file will not compile with a compiler earlier than version 0.4.0
27+
and it will also not work on a compiler starting form version 0.5.0 (this
28+
second condition is added by using ``^``). The idea behind this is that
29+
there will be no breaking changes until version ``0.5.0``, so we can always
30+
be sure that our code will compile the way we intended it to. We do not fix
31+
the exact version of the compiler, so that bugfix releases are still possible.
32+
33+
It is possible to specify much more complex rules for the compiler version,
34+
the expression follows those used by npm.
635

736
.. index:: source file, ! import
837

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
/*
2+
This file is part of cpp-ethereum.
3+
4+
cpp-ethereum 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+
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @author Christian <[email protected]>
19+
* @date 2016
20+
* Utilities to handle semantic versioning.
21+
*/
22+
23+
#include <libsolidity/analysis/SemVerHandler.h>
24+
#include <functional>
25+
26+
using namespace std;
27+
using namespace dev;
28+
using namespace dev::solidity;
29+
30+
SemVerVersion::SemVerVersion(string const& _versionString)
31+
{
32+
auto i = _versionString.begin();
33+
auto end = _versionString.end();
34+
35+
for (unsigned level = 0; level < 3; ++level)
36+
{
37+
unsigned v = 0;
38+
for (; i != end && '0' <= *i && *i <= '9'; ++i)
39+
v = v * 10 + (*i - '0');
40+
numbers[level] = v;
41+
if (level < 2)
42+
{
43+
if (i == end || *i != '.')
44+
throw SemVerError();
45+
else
46+
++i;
47+
}
48+
}
49+
if (i != end && *i == '-')
50+
{
51+
auto prereleaseStart = ++i;
52+
while (i != end && *i != '+') ++i;
53+
prerelease = string(prereleaseStart, i);
54+
}
55+
if (i != end && *i == '+')
56+
{
57+
auto buildStart = ++i;
58+
while (i != end) ++i;
59+
build = string(buildStart, i);
60+
}
61+
if (i != end)
62+
throw SemVerError();
63+
}
64+
65+
bool SemVerMatchExpression::MatchComponent::matches(SemVerVersion const& _version) const
66+
{
67+
if (prefix == Token::BitNot)
68+
{
69+
MatchComponent comp = *this;
70+
71+
comp.prefix = Token::GreaterThanOrEqual;
72+
if (!comp.matches(_version))
73+
return false;
74+
75+
if (levelsPresent >= 2)
76+
comp.levelsPresent = 2;
77+
else
78+
comp.levelsPresent = 1;
79+
comp.prefix = Token::LessThanOrEqual;
80+
return comp.matches(_version);
81+
}
82+
else if (prefix == Token::BitXor)
83+
{
84+
MatchComponent comp = *this;
85+
86+
comp.prefix = Token::GreaterThanOrEqual;
87+
if (!comp.matches(_version))
88+
return false;
89+
90+
if (comp.version.numbers[0] == 0)
91+
comp.levelsPresent = 2;
92+
else
93+
comp.levelsPresent = 1;
94+
comp.prefix = Token::LessThanOrEqual;
95+
return comp.matches(_version);
96+
}
97+
else
98+
{
99+
int cmp = 0;
100+
bool didCompare = false;
101+
for (unsigned i = 0; i < levelsPresent && cmp == 0; i++)
102+
if (version.numbers[i] != unsigned(-1))
103+
{
104+
didCompare = true;
105+
cmp = _version.numbers[i] - version.numbers[i];
106+
}
107+
if (cmp == 0 && !_version.prerelease.empty() && didCompare)
108+
cmp = -1;
109+
if (prefix == Token::Assign)
110+
return cmp == 0;
111+
else if (prefix == Token::LessThan)
112+
return cmp < 0;
113+
else if (prefix == Token::LessThanOrEqual)
114+
return cmp <= 0;
115+
else if (prefix == Token::GreaterThan)
116+
return cmp > 0;
117+
else if (prefix == Token::GreaterThanOrEqual)
118+
return cmp >= 0;
119+
else
120+
solAssert(false, "Invalid SemVer expression");
121+
return false;
122+
}
123+
}
124+
125+
bool SemVerMatchExpression::Conjunction::matches(SemVerVersion const& _version) const
126+
{
127+
for (auto const& component: components)
128+
if (!component.matches(_version))
129+
return false;
130+
return true;
131+
}
132+
133+
bool SemVerMatchExpression::matches(SemVerVersion const& _version) const
134+
{
135+
if (!isValid())
136+
return false;
137+
for (auto const& range: m_disjunction)
138+
if (range.matches(_version))
139+
return true;
140+
return false;
141+
}
142+
143+
SemVerMatchExpression SemVerMatchExpressionParser::parse()
144+
{
145+
reset();
146+
147+
try
148+
{
149+
while (true)
150+
{
151+
parseMatchExpression();
152+
if (m_pos >= m_tokens.size())
153+
break;
154+
if (currentToken() != Token::Or)
155+
throw SemVerError();
156+
nextToken();
157+
}
158+
}
159+
catch (SemVerError const&)
160+
{
161+
reset();
162+
}
163+
164+
return m_expression;
165+
}
166+
167+
168+
void SemVerMatchExpressionParser::reset()
169+
{
170+
m_expression = SemVerMatchExpression();
171+
m_pos = 0;
172+
m_posInside = 0;
173+
}
174+
175+
void SemVerMatchExpressionParser::parseMatchExpression()
176+
{
177+
// component - component (range)
178+
// or component component* (conjunction)
179+
180+
SemVerMatchExpression::Conjunction range;
181+
range.components.push_back(parseMatchComponent());
182+
if (currentToken() == Token::Sub)
183+
{
184+
range.components[0].prefix = Token::GreaterThanOrEqual;
185+
nextToken();
186+
range.components.push_back(parseMatchComponent());
187+
range.components[1].prefix = Token::LessThanOrEqual;
188+
}
189+
else
190+
while (currentToken() != Token::Or && currentToken() != Token::Illegal)
191+
range.components.push_back(parseMatchComponent());
192+
m_expression.m_disjunction.push_back(range);
193+
}
194+
195+
SemVerMatchExpression::MatchComponent SemVerMatchExpressionParser::parseMatchComponent()
196+
{
197+
SemVerMatchExpression::MatchComponent component;
198+
Token::Value token = currentToken();
199+
if (
200+
token == Token::BitXor ||
201+
token == Token::BitNot ||
202+
token == Token::LessThan ||
203+
token == Token::LessThanOrEqual||
204+
token == Token::GreaterThan ||
205+
token == Token::GreaterThanOrEqual ||
206+
token == Token::Assign
207+
)
208+
{
209+
component.prefix = token;
210+
nextToken();
211+
}
212+
else
213+
component.prefix = Token::Assign;
214+
215+
component.levelsPresent = 0;
216+
while (component.levelsPresent < 3)
217+
{
218+
component.version.numbers[component.levelsPresent] = parseVersionPart();
219+
component.levelsPresent++;
220+
if (currentChar() == '.')
221+
nextChar();
222+
else
223+
break;
224+
}
225+
// TODO we do not support pre and build version qualifiers for now in match expressions
226+
// (but we do support them in the actual versions)
227+
return component;
228+
}
229+
230+
unsigned SemVerMatchExpressionParser::parseVersionPart()
231+
{
232+
auto startPos = m_pos;
233+
char c = currentChar();
234+
nextChar();
235+
if (c == 'x' || c == 'X' || c == '*')
236+
return unsigned(-1);
237+
else if (c == '0')
238+
return 0;
239+
else if ('1' <= c && c <= '9')
240+
{
241+
unsigned v = c - '0';
242+
// If we skip to the next token, the current number is terminated.
243+
while (m_pos == startPos && '0' <= currentChar() && currentChar() <= '9')
244+
{
245+
c = currentChar();
246+
if (v * 10 < v || v * 10 + (c - '0') < v * 10)
247+
throw SemVerError();
248+
v = v * 10 + c - '0';
249+
nextChar();
250+
}
251+
return v;
252+
}
253+
else
254+
throw SemVerError();
255+
}
256+
257+
char SemVerMatchExpressionParser::currentChar() const
258+
{
259+
if (m_pos >= m_literals.size())
260+
return char(-1);
261+
if (m_posInside >= m_literals[m_pos].size())
262+
return char(-1);
263+
return m_literals[m_pos][m_posInside];
264+
}
265+
266+
char SemVerMatchExpressionParser::nextChar()
267+
{
268+
if (m_pos < m_literals.size())
269+
{
270+
if (m_posInside + 1 >= m_literals[m_pos].size())
271+
nextToken();
272+
else
273+
++m_posInside;
274+
}
275+
return currentChar();
276+
}
277+
278+
Token::Value SemVerMatchExpressionParser::currentToken() const
279+
{
280+
if (m_pos < m_tokens.size())
281+
return m_tokens[m_pos];
282+
else
283+
return Token::Illegal;
284+
}
285+
286+
void SemVerMatchExpressionParser::nextToken()
287+
{
288+
++m_pos;
289+
m_posInside = 0;
290+
}

0 commit comments

Comments
 (0)