Merge pull request #5066 from Radvendii/master
add antiquotations to paths
This commit is contained in:
commit
7ee639f9db
7 changed files with 125 additions and 22 deletions
|
@ -139,6 +139,13 @@ Nix has the following basic data types:
|
||||||
environment variable `NIX_PATH` will be searched for the given file
|
environment variable `NIX_PATH` will be searched for the given file
|
||||||
or directory name.
|
or directory name.
|
||||||
|
|
||||||
|
Antiquotation is supported in any paths except those in angle brackets.
|
||||||
|
`./${foo}-${bar}.nix` is a more convenient way of writing
|
||||||
|
`./. + "/" + foo + "-" + bar + ".nix"` or `./. + "/${foo}-${bar}.nix"`. At
|
||||||
|
least one slash must appear *before* any antiquotations for this to be
|
||||||
|
recognized as a path. `a.${foo}/b.${bar}` is a syntactically valid division
|
||||||
|
operation. `./a.${foo}/b.${bar}` is a path.
|
||||||
|
|
||||||
- *Booleans* with values `true` and `false`.
|
- *Booleans* with values `true` and `false`.
|
||||||
|
|
||||||
- The null value, denoted as `null`.
|
- The null value, denoted as `null`.
|
||||||
|
|
|
@ -1576,7 +1576,6 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
and none of the strings are allowed to have contexts. */
|
and none of the strings are allowed to have contexts. */
|
||||||
if (first) {
|
if (first) {
|
||||||
firstType = vTmp.type();
|
firstType = vTmp.type();
|
||||||
first = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstType == nInt) {
|
if (firstType == nInt) {
|
||||||
|
@ -1597,7 +1596,12 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
||||||
} else
|
} else
|
||||||
throwEvalError(pos, "cannot add %1% to a float", showType(vTmp));
|
throwEvalError(pos, "cannot add %1% to a float", showType(vTmp));
|
||||||
} else
|
} else
|
||||||
s << state.coerceToString(pos, vTmp, context, false, firstType == nString);
|
/* skip canonization of first path, which would only be not
|
||||||
|
canonized in the first place if it's coming from a ./${foo} type
|
||||||
|
path */
|
||||||
|
s << state.coerceToString(pos, vTmp, context, false, firstType == nString, !first);
|
||||||
|
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstType == nInt)
|
if (firstType == nInt)
|
||||||
|
@ -1786,7 +1790,7 @@ std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
|
||||||
}
|
}
|
||||||
|
|
||||||
string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore, bool copyToStore)
|
bool coerceMore, bool copyToStore, bool canonicalizePath)
|
||||||
{
|
{
|
||||||
forceValue(v, pos);
|
forceValue(v, pos);
|
||||||
|
|
||||||
|
@ -1798,7 +1802,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v.type() == nPath) {
|
if (v.type() == nPath) {
|
||||||
Path path(canonPath(v.path));
|
Path path(canonicalizePath ? canonPath(v.path) : v.path);
|
||||||
return copyToStore ? copyPathToStore(context, path) : path;
|
return copyToStore ? copyPathToStore(context, path) : path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,8 @@ public:
|
||||||
booleans and lists to a string. If `copyToStore' is set,
|
booleans and lists to a string. If `copyToStore' is set,
|
||||||
referenced paths are copied to the Nix store as a side effect. */
|
referenced paths are copied to the Nix store as a side effect. */
|
||||||
string coerceToString(const Pos & pos, Value & v, PathSet & context,
|
string coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
bool coerceMore = false, bool copyToStore = true);
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
|
bool canonicalizePath = true);
|
||||||
|
|
||||||
string copyPathToStore(PathSet & context, const Path & path);
|
string copyPathToStore(PathSet & context, const Path & path);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
%s DEFAULT
|
%s DEFAULT
|
||||||
%x STRING
|
%x STRING
|
||||||
%x IND_STRING
|
%x IND_STRING
|
||||||
|
%x INPATH
|
||||||
|
%x INPATH_SLASH
|
||||||
|
%x PATH_START
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
@ -97,9 +100,12 @@ ANY .|\n
|
||||||
ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
|
ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
|
||||||
INT [0-9]+
|
INT [0-9]+
|
||||||
FLOAT (([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?
|
FLOAT (([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?
|
||||||
PATH [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+\/?
|
PATH_CHAR [a-zA-Z0-9\.\_\-\+]
|
||||||
HPATH \~(\/[a-zA-Z0-9\.\_\-\+]+)+\/?
|
PATH {PATH_CHAR}*(\/{PATH_CHAR}+)+\/?
|
||||||
SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
|
PATH_SEG {PATH_CHAR}*\/
|
||||||
|
HPATH \~(\/{PATH_CHAR}+)+\/?
|
||||||
|
HPATH_START \~\/
|
||||||
|
SPATH \<{PATH_CHAR}+(\/{PATH_CHAR}+)*\>
|
||||||
URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
|
URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,17 +206,73 @@ or { return OR_KW; }
|
||||||
return IND_STR;
|
return IND_STR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{PATH_SEG}\$\{ |
|
||||||
|
{HPATH_START}\$\{ {
|
||||||
|
PUSH_STATE(PATH_START);
|
||||||
|
yyless(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
<PATH_START>{PATH_SEG} {
|
||||||
|
POP_STATE();
|
||||||
|
PUSH_STATE(INPATH_SLASH);
|
||||||
|
yylval->path = strdup(yytext);
|
||||||
|
return PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
<PATH_START>{HPATH_START} {
|
||||||
|
POP_STATE();
|
||||||
|
PUSH_STATE(INPATH_SLASH);
|
||||||
|
yylval->path = strdup(yytext);
|
||||||
|
return HPATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
{PATH} {
|
||||||
|
if (yytext[yyleng-1] == '/')
|
||||||
|
PUSH_STATE(INPATH_SLASH);
|
||||||
|
else
|
||||||
|
PUSH_STATE(INPATH);
|
||||||
|
yylval->path = strdup(yytext);
|
||||||
|
return PATH;
|
||||||
|
}
|
||||||
|
{HPATH} {
|
||||||
|
if (yytext[yyleng-1] == '/')
|
||||||
|
PUSH_STATE(INPATH_SLASH);
|
||||||
|
else
|
||||||
|
PUSH_STATE(INPATH);
|
||||||
|
yylval->path = strdup(yytext);
|
||||||
|
return HPATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
<INPATH,INPATH_SLASH>\$\{ {
|
||||||
|
POP_STATE();
|
||||||
|
PUSH_STATE(INPATH);
|
||||||
|
PUSH_STATE(DEFAULT);
|
||||||
|
return DOLLAR_CURLY;
|
||||||
|
}
|
||||||
|
<INPATH,INPATH_SLASH>{PATH}|{PATH_SEG}|{PATH_CHAR}+ {
|
||||||
|
POP_STATE();
|
||||||
|
if (yytext[yyleng-1] == '/')
|
||||||
|
PUSH_STATE(INPATH_SLASH);
|
||||||
|
else
|
||||||
|
PUSH_STATE(INPATH);
|
||||||
|
yylval->e = new ExprString(data->symbols.create(string(yytext)));
|
||||||
|
return STR;
|
||||||
|
}
|
||||||
|
<INPATH>{ANY} |
|
||||||
|
<INPATH><<EOF>> {
|
||||||
|
/* if we encounter a non-path character we inform the parser that the path has
|
||||||
|
ended with a PATH_END token and re-parse this character in the default
|
||||||
|
context (it may be ')', ';', or something of that sort) */
|
||||||
|
POP_STATE();
|
||||||
|
yyless(0);
|
||||||
|
return PATH_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
<INPATH_SLASH>{ANY} |
|
||||||
|
<INPATH_SLASH><<EOF>> {
|
||||||
|
throw ParseError("path has a trailing slash");
|
||||||
|
}
|
||||||
|
|
||||||
{PATH} { if (yytext[yyleng-1] == '/')
|
|
||||||
throw ParseError("path '%s' has a trailing slash", yytext);
|
|
||||||
yylval->path = strdup(yytext);
|
|
||||||
return PATH;
|
|
||||||
}
|
|
||||||
{HPATH} { if (yytext[yyleng-1] == '/')
|
|
||||||
throw ParseError("path '%s' has a trailing slash", yytext);
|
|
||||||
yylval->path = strdup(yytext);
|
|
||||||
return HPATH;
|
|
||||||
}
|
|
||||||
{SPATH} { yylval->path = strdup(yytext); return SPATH; }
|
{SPATH} { yylval->path = strdup(yytext); return SPATH; }
|
||||||
{URI} { yylval->uri = strdup(yytext); return URI; }
|
{URI} { yylval->uri = strdup(yytext); return URI; }
|
||||||
|
|
||||||
|
|
|
@ -290,13 +290,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
|
||||||
%type <formal> formal
|
%type <formal> formal
|
||||||
%type <attrNames> attrs attrpath
|
%type <attrNames> attrs attrpath
|
||||||
%type <string_parts> string_parts_interpolated ind_string_parts
|
%type <string_parts> string_parts_interpolated ind_string_parts
|
||||||
%type <e> string_parts string_attr
|
%type <e> path_start string_parts string_attr
|
||||||
%type <id> attr
|
%type <id> attr
|
||||||
%token <id> ID ATTRPATH
|
%token <id> ID ATTRPATH
|
||||||
%token <e> STR IND_STR
|
%token <e> STR IND_STR
|
||||||
%token <n> INT
|
%token <n> INT
|
||||||
%token <nf> FLOAT
|
%token <nf> FLOAT
|
||||||
%token <path> PATH HPATH SPATH
|
%token <path> PATH HPATH SPATH PATH_END
|
||||||
%token <uri> URI
|
%token <uri> URI
|
||||||
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
|
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
|
||||||
%token DOLLAR_CURLY /* == ${ */
|
%token DOLLAR_CURLY /* == ${ */
|
||||||
|
@ -405,8 +405,11 @@ expr_simple
|
||||||
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
|
||||||
$$ = stripIndentation(CUR_POS, data->symbols, *$2);
|
$$ = stripIndentation(CUR_POS, data->symbols, *$2);
|
||||||
}
|
}
|
||||||
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
|
| path_start PATH_END { $$ = $1; }
|
||||||
| HPATH { $$ = new ExprPath(getHome() + string{$1 + 1}); }
|
| path_start string_parts_interpolated PATH_END {
|
||||||
|
$2->insert($2->begin(), $1);
|
||||||
|
$$ = new ExprConcatStrings(CUR_POS, false, $2);
|
||||||
|
}
|
||||||
| SPATH {
|
| SPATH {
|
||||||
string path($1 + 1, strlen($1) - 2);
|
string path($1 + 1, strlen($1) - 2);
|
||||||
$$ = new ExprApp(CUR_POS,
|
$$ = new ExprApp(CUR_POS,
|
||||||
|
@ -452,6 +455,20 @@ string_parts_interpolated
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
path_start
|
||||||
|
: PATH {
|
||||||
|
Path path(absPath($1, data->basePath));
|
||||||
|
/* add back in the trailing '/' to the first segment */
|
||||||
|
if ($1[strlen($1)-1] == '/' && strlen($1) > 1)
|
||||||
|
path += "/";
|
||||||
|
$$ = new ExprPath(path);
|
||||||
|
}
|
||||||
|
| HPATH {
|
||||||
|
Path path(getHome() + string($1 + 1));
|
||||||
|
$$ = new ExprPath(path);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
ind_string_parts
|
ind_string_parts
|
||||||
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
|
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
|
||||||
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
|
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }
|
||||||
|
|
12
tests/lang/eval-okay-path-antiquotation.nix
Normal file
12
tests/lang/eval-okay-path-antiquotation.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
let
|
||||||
|
foo = "foo";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
simple = ./${foo};
|
||||||
|
surrounded = ./a-${foo}-b;
|
||||||
|
absolute = /${foo};
|
||||||
|
expr = ./${foo + "/bar"};
|
||||||
|
home = ~/${foo};
|
||||||
|
notfirst = ./bar/${foo};
|
||||||
|
slashes = /${foo}/${"bar"};
|
||||||
|
}
|
Loading…
Reference in a new issue