Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 79 additions & 36 deletions source/external/ldc/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,25 @@ class ScalarSetting : Setting

class ArraySetting : Setting
{
this(string name, string[] vals)
this(string name, string[] vals, bool isAppending)
{
super(name, Type.array);
_vals = vals;
_isAppending = isAppending;
}

@property const(string)[] vals() const
{
return _vals;
}

@property bool isAppending() const
{
return _isAppending;
}

private string[] _vals;
private bool _isAppending;
}

class GroupSetting : Setting
Expand Down Expand Up @@ -125,7 +132,7 @@ EBNF grammar.
It is a subset of the libconfig grammar (http://www.hyperrealm.com/libconfig).

config = { ows , setting } , ows ;
setting = (name | string) , (":" | "=") , value , [";" | ","] ;
setting = (name | string) , (":" | "=" | "~=") , value , [";" | ","] ;
name = alpha , { alpha | digit | "_" | "-" } ;
value = string | array | group ;
array = "[" , ows ,
Expand Down Expand Up @@ -164,6 +171,7 @@ enum Token
{
name,
assign, // ':' or '='
appendAssign, // '~='
str,
lbrace, // '{'
rbrace, // '}'
Expand All @@ -179,17 +187,18 @@ string humanReadableToken(in Token tok)
{
final switch(tok)
{
case Token.name: return `"name"`;
case Token.assign: return `':' or '='`;
case Token.str: return `"string"`;
case Token.lbrace: return `'{'`;
case Token.rbrace: return `'}'`;
case Token.lbracket: return `'['`;
case Token.rbracket: return `']'`;
case Token.semicolon: return `';'`;
case Token.comma: return `','`;
case Token.unknown: return `"unknown token"`;
case Token.eof: return `"end of file"`;
case Token.name: return `"name"`;
case Token.assign: return `':' or '='`;
case Token.appendAssign: return `'~='`;
case Token.str: return `"string"`;
case Token.lbrace: return `'{'`;
case Token.rbrace: return `'}'`;
case Token.lbracket: return `'['`;
case Token.rbracket: return `']'`;
case Token.semicolon: return `';'`;
case Token.comma: return `','`;
case Token.unknown: return `"unknown token"`;
case Token.eof: return `"end of file"`;
}
}

Expand Down Expand Up @@ -218,11 +227,14 @@ struct Parser

void error(in string msg)
{
enum fmt = "Error while reading config file: %.*s\nline %d: %.*s";
char[1024] buf;
auto len = snprintf(buf.ptr, buf.length, fmt, cast(int) filename.length,
filename.ptr, lineNum, cast(int) msg.length, msg.ptr);
throw new Exception(buf[0 .. len].idup);
error(msg, lineNum);
}

void error(in string msg, int lineNum)
{
char[20] buf = void;
auto len = snprintf(buf.ptr, buf.length, "line %d: ", lineNum);
throw new Exception((cast(string) buf[0 .. len]) ~ msg);
}

char getChar()
Expand Down Expand Up @@ -267,6 +279,19 @@ struct Parser
return getTok(outStr);
}

if (lastChar == '~')
{
lastChar = getChar();
if (lastChar != '=')
{
outStr = "~";
return Token.unknown;
}

lastChar = getChar();
return Token.appendAssign;
}

if (isalpha(lastChar))
{
string name;
Expand Down Expand Up @@ -402,17 +427,6 @@ struct Parser
". Got " ~ humanReadableToken(tok) ~ s ~ " instead.");
}

string accept(in Token expected)
{
string s;
immutable tok = getTok(s);
if (tok != expected)
{
unexpectedTokenError(tok, expected, s);
}
return s;
}

Setting[] parseConfig()
{
Setting[] res;
Expand Down Expand Up @@ -442,11 +456,29 @@ struct Parser
assert(false);
}

accept(Token.assign);
string s;
t = getTok(s);
if (t != Token.assign && t != Token.appendAssign)
{
auto msg = "Expected either"
~ " token " ~ humanReadableToken(Token.assign)
~ " or token " ~ humanReadableToken(Token.appendAssign)
~ " but got: " ~ humanReadableToken(t)
~ ' ' ~ (s.length ? '(' ~ s ~ ')' : s);
error(msg);
}
// This is off by +1 if `t` is followed by \n
const assignLineNum = lineNum;

Setting res = parseValue(name);
Setting res = parseValue(name, t);
if (t == Token.appendAssign)
{
if (res.type == Setting.Type.scalar)
error(humanReadableToken(t) ~ " is not supported with scalar values", assignLineNum);
if (res.type == Setting.Type.group)
error(humanReadableToken(t) ~ " is not supported with groups", assignLineNum);
}

string s;
t = getTok(s);
if (t != Token.semicolon && t != Token.comma)
{
Expand All @@ -456,8 +488,10 @@ struct Parser
return res;
}

Setting parseValue(string name)
Setting parseValue(string name, Token tAssign = Token.assign)
{
assert(tAssign == Token.assign || tAssign == Token.appendAssign);

string s;
auto t = getTok(s);
if (t == Token.str)
Expand All @@ -466,6 +500,7 @@ struct Parser
}
else if (t == Token.lbracket)
{
const isAppending = tAssign == Token.appendAssign;
string[] arrVal;
while (1)
{
Expand All @@ -477,7 +512,7 @@ struct Parser
arrVal ~= s;
break;
case Token.rbracket:
return new ArraySetting(name, arrVal);
return new ArraySetting(name, arrVal, isAppending);
default:
unexpectedTokenError(t, Token.str, s);
assert(false);
Expand All @@ -490,7 +525,7 @@ struct Parser
case Token.comma:
break;
case Token.rbracket:
return new ArraySetting(name, arrVal);
return new ArraySetting(name, arrVal, isAppending);
default:
unexpectedTokenError(t, Token.comma, s);
assert(false);
Expand Down Expand Up @@ -570,6 +605,8 @@ group-1_2: {};
scalar = "abc";
// comment
Array_1-2 = [ "a" ];

AppArray ~= [ "x" ]; // appending array
};
`;

Expand All @@ -583,7 +620,7 @@ group-1_2: {};
assert(settings[1].name == "86(_64)?-.*linux\\.?");
assert(settings[1].type == Setting.Type.group);
auto group2 = cast(GroupSetting) settings[1];
assert(group2.children.length == 2);
assert(group2.children.length == 3);

assert(group2.children[0].name == "scalar");
assert(group2.children[0].type == Setting.Type.scalar);
Expand All @@ -592,4 +629,10 @@ group-1_2: {};
assert(group2.children[1].name == "Array_1-2");
assert(group2.children[1].type == Setting.Type.array);
assert((cast(ArraySetting) group2.children[1]).vals == [ "a" ]);
assert((cast(ArraySetting) group2.children[1]).isAppending == false);

assert(group2.children[2].name == "AppArray");
assert(group2.children[2].type == Setting.Type.array);
assert((cast(ArraySetting) group2.children[2]).vals == [ "x" ]);
assert((cast(ArraySetting) group2.children[2]).isAppending == true);
}
47 changes: 39 additions & 8 deletions source/served/utils/stdlib_detect.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module served.utils.stdlib_detect;

import std.algorithm : countUntil, splitter, startsWith;
import std.array : appender, replace;
import std.array : Appender, appender, replace;
import std.ascii : isWhite;
import std.conv : to;
import std.experimental.logger : trace, warning;
Expand Down Expand Up @@ -359,9 +359,39 @@ bool parseDmdConfImports(R)(R confPath, scope const(char)[] confDirPath, out str

bool parseLdcConfImports(string confPath, scope const(char)[] binDirPath, out string[] paths)
{
import external.ldc.config;
Appender!(string[]) ret;
scope(exit) paths = ret.data;

auto ret = appender!(string[]);
import std.algorithm;
import std.array;
import std.file;

if (confPath.isDir)
{
auto configFiles = confPath.dirEntries(SpanMode.shallow)
.filter!`a.isFile`
.map!`a.name`
// FIXME this should be numeric sort
.array
.sort;

import std.conv;
trace("the config files are: ", text(configFiles));

foreach (file; configFiles)
parseLdcConfImportsSingleFile(file, binDirPath, ret);
}
else
parseLdcConfImportsSingleFile(confPath, binDirPath, ret);

if (!ret.data.length)
warning("failed to find phobos/druntime paths in ldc conf ", confPath, " - going to continue looking elsewhere...");
return ret.data.length > 0;
}

void parseLdcConfImportsSingleFile(string confPath, scope const(char)[] binDirPath, ref Appender!(string[]) ret)
{
import external.ldc.config;

binDirPath = binDirPath.replace('\\', '/');

Expand All @@ -388,18 +418,19 @@ bool parseLdcConfImports(string confPath, scope const(char)[] binDirPath, out st
}

trace("test ldc conf ", confPath);
Setting[] settings;
try
settings = parseConfigFile(confPath);
catch (Exception e)
throw new Exception("Could not read ldc2 config file: " ~ confPath ~ ": " ~ e.msg);

foreach (s; parseConfigFile(confPath))
{
if (s.type == Setting.Type.group && s.name == "default")
{
parseSection(cast(GroupSetting) s);
}
}

paths = ret.data;
if (!ret.data.length)
warning("failed to find phobos/druntime paths in ldc conf ", confPath, " - going to continue looking elsewhere...");
return ret.data.length > 0;
}

deprecated string[] parseDflagsImports(scope const(char)[] options, bool windows)
Expand Down
Loading