Skip to content

Commit 87fcd7c

Browse files
authored
Merge pull request #4856 from kinke/ldc2-conf-dir
ldc2.conf: Implement ~= concatenating operator [2]
2 parents 880d514 + ae83835 commit 87fcd7c

File tree

6 files changed

+160
-84
lines changed

6 files changed

+160
-84
lines changed

driver/config.d

+79-36
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,25 @@ class ScalarSetting : Setting
6666

6767
class ArraySetting : Setting
6868
{
69-
this(string name, string[] vals)
69+
this(string name, string[] vals, bool isAppending)
7070
{
7171
super(name, Type.array);
7272
_vals = vals;
73+
_isAppending = isAppending;
7374
}
7475

7576
@property const(string)[] vals() const
7677
{
7778
return _vals;
7879
}
7980

81+
@property bool isAppending() const
82+
{
83+
return _isAppending;
84+
}
85+
8086
private string[] _vals;
87+
private bool _isAppending;
8188
}
8289

8390
class GroupSetting : Setting
@@ -133,7 +140,7 @@ EBNF grammar.
133140
It is a subset of the libconfig grammar (http://www.hyperrealm.com/libconfig).
134141
135142
config = { ows , setting } , ows ;
136-
setting = (name | string) , (":" | "=") , value , [";" | ","] ;
143+
setting = (name | string) , (":" | "=" | "~=") , value , [";" | ","] ;
137144
name = alpha , { alpha | digit | "_" | "-" } ;
138145
value = string | array | group ;
139146
array = "[" , ows ,
@@ -172,6 +179,7 @@ enum Token
172179
{
173180
name,
174181
assign, // ':' or '='
182+
appendAssign, // '~='
175183
str,
176184
lbrace, // '{'
177185
rbrace, // '}'
@@ -187,17 +195,18 @@ string humanReadableToken(in Token tok)
187195
{
188196
final switch(tok)
189197
{
190-
case Token.name: return `"name"`;
191-
case Token.assign: return `':' or '='`;
192-
case Token.str: return `"string"`;
193-
case Token.lbrace: return `'{'`;
194-
case Token.rbrace: return `'}'`;
195-
case Token.lbracket: return `'['`;
196-
case Token.rbracket: return `']'`;
197-
case Token.semicolon: return `';'`;
198-
case Token.comma: return `','`;
199-
case Token.unknown: return `"unknown token"`;
200-
case Token.eof: return `"end of file"`;
198+
case Token.name: return `"name"`;
199+
case Token.assign: return `':' or '='`;
200+
case Token.appendAssign: return `'~='`;
201+
case Token.str: return `"string"`;
202+
case Token.lbrace: return `'{'`;
203+
case Token.rbrace: return `'}'`;
204+
case Token.lbracket: return `'['`;
205+
case Token.rbracket: return `']'`;
206+
case Token.semicolon: return `';'`;
207+
case Token.comma: return `','`;
208+
case Token.unknown: return `"unknown token"`;
209+
case Token.eof: return `"end of file"`;
201210
}
202211
}
203212

@@ -226,11 +235,14 @@ struct Parser
226235

227236
void error(in string msg)
228237
{
229-
enum fmt = "Error while reading config file: %.*s\nline %d: %.*s";
230-
char[1024] buf;
231-
auto len = snprintf(buf.ptr, buf.length, fmt, cast(int) filename.length,
232-
filename.ptr, lineNum, cast(int) msg.length, msg.ptr);
233-
throw new Exception(buf[0 .. len].idup);
238+
error(msg, lineNum);
239+
}
240+
241+
void error(in string msg, int lineNum)
242+
{
243+
char[20] buf = void;
244+
auto len = snprintf(buf.ptr, buf.length, "line %d: ", lineNum);
245+
throw new Exception((cast(string) buf[0 .. len]) ~ msg);
234246
}
235247

236248
char getChar()
@@ -275,6 +287,19 @@ struct Parser
275287
return getTok(outStr);
276288
}
277289

290+
if (lastChar == '~')
291+
{
292+
lastChar = getChar();
293+
if (lastChar != '=')
294+
{
295+
outStr = "~";
296+
return Token.unknown;
297+
}
298+
299+
lastChar = getChar();
300+
return Token.appendAssign;
301+
}
302+
278303
if (isalpha(lastChar))
279304
{
280305
string name;
@@ -410,17 +435,6 @@ struct Parser
410435
". Got " ~ humanReadableToken(tok) ~ s ~ " instead.");
411436
}
412437

413-
string accept(in Token expected)
414-
{
415-
string s;
416-
immutable tok = getTok(s);
417-
if (tok != expected)
418-
{
419-
unexpectedTokenError(tok, expected, s);
420-
}
421-
return s;
422-
}
423-
424438
Setting[] parseConfig()
425439
{
426440
Setting[] res;
@@ -450,11 +464,29 @@ struct Parser
450464
assert(false);
451465
}
452466

453-
accept(Token.assign);
467+
string s;
468+
t = getTok(s);
469+
if (t != Token.assign && t != Token.appendAssign)
470+
{
471+
auto msg = "Expected either"
472+
~ " token " ~ humanReadableToken(Token.assign)
473+
~ " or token " ~ humanReadableToken(Token.appendAssign)
474+
~ " but got: " ~ humanReadableToken(t)
475+
~ ' ' ~ (s.length ? '(' ~ s ~ ')' : s);
476+
error(msg);
477+
}
478+
// This is off by +1 if `t` is followed by \n
479+
const assignLineNum = lineNum;
454480

455-
Setting res = parseValue(name);
481+
Setting res = parseValue(name, t);
482+
if (t == Token.appendAssign)
483+
{
484+
if (res.type == Setting.Type.scalar)
485+
error(humanReadableToken(t) ~ " is not supported with scalar values", assignLineNum);
486+
if (res.type == Setting.Type.group)
487+
error(humanReadableToken(t) ~ " is not supported with groups", assignLineNum);
488+
}
456489

457-
string s;
458490
t = getTok(s);
459491
if (t != Token.semicolon && t != Token.comma)
460492
{
@@ -464,8 +496,10 @@ struct Parser
464496
return res;
465497
}
466498

467-
Setting parseValue(string name)
499+
Setting parseValue(string name, Token tAssign = Token.assign)
468500
{
501+
assert(tAssign == Token.assign || tAssign == Token.appendAssign);
502+
469503
string s;
470504
auto t = getTok(s);
471505
if (t == Token.str)
@@ -474,6 +508,7 @@ struct Parser
474508
}
475509
else if (t == Token.lbracket)
476510
{
511+
const isAppending = tAssign == Token.appendAssign;
477512
string[] arrVal;
478513
while (1)
479514
{
@@ -485,7 +520,7 @@ struct Parser
485520
arrVal ~= s;
486521
break;
487522
case Token.rbracket:
488-
return new ArraySetting(name, arrVal);
523+
return new ArraySetting(name, arrVal, isAppending);
489524
default:
490525
unexpectedTokenError(t, Token.str, s);
491526
assert(false);
@@ -498,7 +533,7 @@ struct Parser
498533
case Token.comma:
499534
break;
500535
case Token.rbracket:
501-
return new ArraySetting(name, arrVal);
536+
return new ArraySetting(name, arrVal, isAppending);
502537
default:
503538
unexpectedTokenError(t, Token.comma, s);
504539
assert(false);
@@ -578,6 +613,8 @@ group-1_2: {};
578613
scalar = "abc";
579614
// comment
580615
Array_1-2 = [ "a" ];
616+
617+
AppArray ~= [ "x" ]; // appending array
581618
};
582619
`;
583620

@@ -591,7 +628,7 @@ group-1_2: {};
591628
assert(settings[1].name == "86(_64)?-.*linux\\.?");
592629
assert(settings[1].type == Setting.Type.group);
593630
auto group2 = cast(GroupSetting) settings[1];
594-
assert(group2.children.length == 2);
631+
assert(group2.children.length == 3);
595632

596633
assert(group2.children[0].name == "scalar");
597634
assert(group2.children[0].type == Setting.Type.scalar);
@@ -600,4 +637,10 @@ group-1_2: {};
600637
assert(group2.children[1].name == "Array_1-2");
601638
assert(group2.children[1].type == Setting.Type.array);
602639
assert((cast(ArraySetting) group2.children[1]).vals == [ "a" ]);
640+
assert((cast(ArraySetting) group2.children[1]).isAppending == false);
641+
642+
assert(group2.children[2].name == "AppArray");
643+
assert(group2.children[2].type == Setting.Type.array);
644+
assert((cast(ArraySetting) group2.children[2]).vals == [ "x" ]);
645+
assert((cast(ArraySetting) group2.children[2]).isAppending == true);
603646
}

driver/configfile.d

+42-41
Original file line numberDiff line numberDiff line change
@@ -14,44 +14,53 @@ module driver.configfile;
1414

1515
import dmd.globals;
1616
import dmd.root.array;
17+
import dmd.root.string : toDString, toCString, toCStringThen;
1718
import driver.config;
1819
import core.stdc.stdio;
19-
import core.stdc.string;
2020

2121

2222
string normalizeSlashes(const(char)* binDir)
2323
{
24-
immutable len = strlen(binDir);
25-
auto res = binDir[0 .. len].dup;
24+
auto res = binDir.toDString.dup;
2625
foreach (ref c; res)
2726
{
2827
if (c == '\\') c = '/';
2928
}
3029
return cast(string)res; // assumeUnique
3130
}
3231

33-
T findSetting(T)(GroupSetting[] sections, Setting.Type type, string name)
32+
const(string)[] findArraySetting(GroupSetting[] sections, string name)
3433
{
35-
// lexically later sections dominate earlier ones
36-
foreach_reverse (section; sections)
34+
const(string)[] result = null;
35+
foreach (section; sections)
3736
{
3837
foreach (c; section.children)
3938
{
40-
if (c.type == type && c.name == name)
41-
return cast(T) c;
39+
if (c.type == Setting.Type.array && c.name == name)
40+
{
41+
auto as = cast(ArraySetting) c;
42+
if (as.isAppending)
43+
result ~= as.vals;
44+
else
45+
result = as.vals;
46+
}
4247
}
4348
}
44-
return null;
45-
}
46-
47-
ArraySetting findArraySetting(GroupSetting[] sections, string name)
48-
{
49-
return findSetting!ArraySetting(sections, Setting.Type.array, name);
49+
return result;
5050
}
5151

52-
ScalarSetting findScalarSetting(GroupSetting[] sections, string name)
52+
string findScalarSetting(GroupSetting[] sections, string name)
5353
{
54-
return findSetting!ScalarSetting(sections, Setting.Type.scalar, name);
54+
string result = null;
55+
foreach (section; sections)
56+
{
57+
foreach (c; section.children)
58+
{
59+
if (c.type == Setting.Type.scalar && c.name == name)
60+
result = (cast(ScalarSetting) c).val;
61+
}
62+
}
63+
return result;
5564
}
5665

5766
string replace(string str, string pattern, string replacement)
@@ -133,12 +142,10 @@ private:
133142
Array!(const(char)*) _libDirs;
134143
const(char)* rpathcstr;
135144

136-
static bool sectionMatches(const(char)* section, const(char)* triple);
145+
static bool sectionMatches(const(char)* section, const(char)* triple) nothrow;
137146

138147
bool readConfig(const(char)* cfPath, const(char)* triple, const(char)* binDir)
139148
{
140-
switches.setDim(0);
141-
postSwitches.setDim(0);
142149
const cfgPaths = CfgPaths(cfPath, binDir);
143150

144151
try
@@ -147,55 +154,49 @@ private:
147154
foreach (s; parseConfigFile(cfPath))
148155
{
149156
if (s.type == Setting.Type.group &&
150-
(s.name == "default" || sectionMatches((s.name ~ '\0').ptr, triple)))
157+
(s.name == "default" || s.name.toCStringThen!(name => sectionMatches(name.ptr, triple))))
151158
{
152159
sections ~= cast(GroupSetting) s;
153160
}
154161
}
155162

156163
if (sections.length == 0)
157164
{
158-
const dTriple = triple[0 .. strlen(triple)];
159-
const dCfPath = cfPath[0 .. strlen(cfPath)];
160-
throw new Exception("No matching section for triple '" ~ cast(string) dTriple
161-
~ "' in " ~ cast(string) dCfPath);
165+
throw new Exception("No matching section for triple '" ~ cast(string) triple.toDString
166+
~ "'");
162167
}
163168

164-
auto switches = findArraySetting(sections, "switches");
165-
auto postSwitches = findArraySetting(sections, "post-switches");
166-
if (!switches && !postSwitches)
167-
{
168-
const dCfPath = cfPath[0 .. strlen(cfPath)];
169-
throw new Exception("Could not look up switches in " ~ cast(string) dCfPath);
170-
}
169+
const switches = findArraySetting(sections, "switches");
170+
const postSwitches = findArraySetting(sections, "post-switches");
171+
if (switches.length + postSwitches.length == 0)
172+
throw new Exception("Could not look up switches");
171173

172-
void applyArray(ref Array!(const(char)*) output, ArraySetting input)
174+
void applyArray(ref Array!(const(char)*) output, const(string)[] input)
173175
{
174-
if (!input)
175-
return;
176+
output.setDim(0);
176177

177-
output.reserve(input.vals.length);
178-
foreach (sw; input.vals)
178+
output.reserve(input.length);
179+
foreach (sw; input)
179180
{
180-
const finalSwitch = sw.replacePlaceholders(cfgPaths) ~ '\0';
181+
const finalSwitch = sw.replacePlaceholders(cfgPaths).toCString;
181182
output.push(finalSwitch.ptr);
182183
}
183184
}
184185

185186
applyArray(this.switches, switches);
186187
applyArray(this.postSwitches, postSwitches);
187188

188-
auto libDirs = findArraySetting(sections, "lib-dirs");
189+
const libDirs = findArraySetting(sections, "lib-dirs");
189190
applyArray(_libDirs, libDirs);
190191

191-
if (auto rpath = findScalarSetting(sections, "rpath"))
192-
this.rpathcstr = (rpath.val.replacePlaceholders(cfgPaths) ~ '\0').ptr;
192+
const rpath = findScalarSetting(sections, "rpath");
193+
this.rpathcstr = rpath.length == 0 ? null : rpath.replacePlaceholders(cfgPaths).toCString.ptr;
193194

194195
return true;
195196
}
196197
catch (Exception ex)
197198
{
198-
fprintf(stderr, "Error: %.*s\n", cast(int) ex.msg.length, ex.msg.ptr);
199+
fprintf(stderr, "Error while reading config file: %s\n%.*s\n", cfPath, cast(int) ex.msg.length, ex.msg.ptr);
199200
return false;
200201
}
201202
}

tests/driver/config_append_assign.d

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %ldc -o- -v -conf=%S/inputs/appending_assign.conf %s 2>&1
2+
3+
module object;
4+
5+
version(Section1_1)
6+
static assert(false);
7+
version(Section1_2) {}
8+
else static assert(false);
9+
10+
version(Section2) {}
11+
else static assert(false);

0 commit comments

Comments
 (0)