Semantic Versioning Parser for voc
This commit is contained in:
commit
052d41505e
7 changed files with 510 additions and 0 deletions
168
src/SemVer.Mod
Normal file
168
src/SemVer.Mod
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
MODULE SemVer;
|
||||
|
||||
IMPORT Out;
|
||||
|
||||
TYPE
|
||||
StringIdentifier = ARRAY 256 OF CHAR;
|
||||
Version* = RECORD
|
||||
Major*, Minor*, Patch*: INTEGER;
|
||||
PreRelease*, Build*: StringIdentifier;
|
||||
END;
|
||||
|
||||
PROCEDURE IsDigit(ch: CHAR): BOOLEAN;
|
||||
BEGIN
|
||||
RETURN (ch >= '0') & (ch <= '9');
|
||||
END IsDigit;
|
||||
|
||||
PROCEDURE HasLeadingZero(s: ARRAY OF CHAR; i: INTEGER): BOOLEAN;
|
||||
BEGIN
|
||||
RETURN (s[i] = '0') & IsDigit(s[i + 1]);
|
||||
END HasLeadingZero;
|
||||
|
||||
PROCEDURE ParseInt(s: ARRAY OF CHAR; VAR i, n: INTEGER; VAR ok: BOOLEAN);
|
||||
VAR digit: INTEGER;
|
||||
BEGIN
|
||||
n := 0;
|
||||
IF ~IsDigit(s[i]) THEN ok := FALSE; RETURN END;
|
||||
|
||||
WHILE (i < LEN(s)) & IsDigit(s[i]) DO
|
||||
digit := ORD(s[i]) - ORD('0');
|
||||
n := n * 10 + digit;
|
||||
INC(i);
|
||||
END;
|
||||
ok := TRUE;
|
||||
END ParseInt;
|
||||
|
||||
PROCEDURE IsIdentChar(ch: CHAR): BOOLEAN;
|
||||
BEGIN
|
||||
RETURN ((ch >= '0') & (ch <= '9')) OR
|
||||
((ch >= 'A') & (ch <= 'Z')) OR
|
||||
((ch >= 'a') & (ch <= 'z')) OR
|
||||
(ch = '-');
|
||||
END IsIdentChar;
|
||||
|
||||
PROCEDURE ParseIdentifiers(
|
||||
s: ARRAY OF CHAR;
|
||||
VAR i: INTEGER;
|
||||
VAR dest: StringIdentifier;
|
||||
checkLeadingZero: BOOLEAN;
|
||||
VAR ok: BOOLEAN);
|
||||
VAR
|
||||
j, segLen: INTEGER;
|
||||
ch: CHAR;
|
||||
isNumeric, hasLeadingZero: BOOLEAN;
|
||||
BEGIN
|
||||
j := 0; ok := FALSE;
|
||||
|
||||
(* Require at least one character *)
|
||||
IF (s[i] = '.') OR (s[i] = '+') OR (s[i] = 0X) THEN RETURN END;
|
||||
|
||||
LOOP
|
||||
segLen := 0;
|
||||
isNumeric := TRUE;
|
||||
hasLeadingZero := FALSE;
|
||||
|
||||
(* Empty identifier is invalid *)
|
||||
IF (s[i] = '.') OR (s[i] = '+') OR (s[i] = 0X) THEN RETURN END;
|
||||
|
||||
WHILE (s[i] # '.') & (s[i] # '+') & (s[i] # 0X) DO
|
||||
ch := s[i];
|
||||
|
||||
IF ~IsIdentChar(ch) THEN RETURN END;
|
||||
|
||||
(* Check for leading-zero numeric identifiers *)
|
||||
IF checkLeadingZero THEN
|
||||
IF segLen = 0 THEN
|
||||
IF ch = '0' THEN hasLeadingZero := TRUE END;
|
||||
ELSE
|
||||
IF hasLeadingZero & IsDigit(ch) THEN RETURN END;
|
||||
END;
|
||||
IF ~IsDigit(ch) THEN isNumeric := FALSE END;
|
||||
END;
|
||||
|
||||
IF j >= LEN(dest) - 1 THEN RETURN END;
|
||||
dest[j] := ch; INC(i); INC(j); INC(segLen);
|
||||
END;
|
||||
|
||||
(* Add dot if needed *)
|
||||
IF s[i] = '.' THEN
|
||||
IF j >= LEN(dest) - 1 THEN RETURN END;
|
||||
dest[j] := '.'; INC(i); INC(j);
|
||||
ELSE
|
||||
EXIT;
|
||||
END;
|
||||
END;
|
||||
|
||||
dest[j] := 0X;
|
||||
ok := TRUE;
|
||||
END ParseIdentifiers;
|
||||
|
||||
PROCEDURE ParsePreRelease(
|
||||
s: ARRAY OF CHAR;
|
||||
VAR i: INTEGER;
|
||||
VAR PreRelease: StringIdentifier;
|
||||
VAR ok: BOOLEAN);
|
||||
BEGIN
|
||||
IF s[i] # '-' THEN ok := FALSE; RETURN END;
|
||||
INC(i);
|
||||
ParseIdentifiers(s, i, PreRelease, TRUE (* checkLeadingZero *), ok);
|
||||
END ParsePreRelease;
|
||||
|
||||
PROCEDURE ParseBuild(
|
||||
s: ARRAY OF CHAR;
|
||||
VAR i: INTEGER;
|
||||
VAR Build: StringIdentifier;
|
||||
VAR ok: BOOLEAN);
|
||||
BEGIN
|
||||
IF s[i] # '+' THEN ok := FALSE; RETURN END;
|
||||
INC(i);
|
||||
ParseIdentifiers(s, i, Build, FALSE (* checkLeadingZero *), ok);
|
||||
END ParseBuild;
|
||||
|
||||
|
||||
PROCEDURE Parse*(s: ARRAY OF CHAR; VAR v: Version; VAR finalok: BOOLEAN);
|
||||
VAR
|
||||
i: INTEGER;
|
||||
ok: BOOLEAN;
|
||||
BEGIN
|
||||
(* Make sure it's clean *)
|
||||
v.Major := 0;
|
||||
v.Minor := 0;
|
||||
v.Patch := 0;
|
||||
v.PreRelease[0] := 0X;
|
||||
v.Build[0] := 0X;
|
||||
|
||||
ok := FALSE;
|
||||
finalok := FALSE;
|
||||
i := 0;
|
||||
|
||||
(* Major *)
|
||||
IF HasLeadingZero(s, i) THEN RETURN END;
|
||||
ParseInt(s, i, v.Major, ok); IF ~ok THEN RETURN END;
|
||||
IF s[i] # '.' THEN RETURN END; INC(i);
|
||||
|
||||
(* Minor *)
|
||||
IF HasLeadingZero(s, i) THEN RETURN END;
|
||||
ParseInt(s, i, v.Minor, ok); IF ~ok THEN RETURN END;
|
||||
IF s[i] # '.' THEN RETURN END; INC(i);
|
||||
|
||||
(* Patch *)
|
||||
IF HasLeadingZero(s, i) THEN RETURN END;
|
||||
ParseInt(s, i, v.Patch, ok); IF ~ok THEN RETURN END;
|
||||
|
||||
(* PreRelease, if exists *)
|
||||
IF s[i] = '-' THEN
|
||||
ParsePreRelease(s, i, v.PreRelease, ok)
|
||||
END;
|
||||
|
||||
(* Build, if exists *)
|
||||
IF s[i] = '+' THEN
|
||||
ParseBuild(s, i, v.Build, ok)
|
||||
END;
|
||||
|
||||
(* Must end cleanly *)
|
||||
IF s[i] # 0X THEN ok := FALSE; RETURN END;
|
||||
|
||||
finalok := TRUE;
|
||||
END Parse;
|
||||
END SemVer.
|
||||
Loading…
Add table
Add a link
Reference in a new issue