Merge pull request #5066 from Radvendii/master

add antiquotations to paths
This commit is contained in:
Eelco Dolstra 2021-09-01 12:55:04 +02:00 committed by GitHub
commit 7ee639f9db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 125 additions and 22 deletions

View file

@ -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`.

View file

@ -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;
} }

View file

@ -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);

View file

@ -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} { if (yytext[yyleng-1] == '/') <PATH_START>{PATH_SEG} {
throw ParseError("path '%s' has a trailing slash", yytext); POP_STATE();
PUSH_STATE(INPATH_SLASH);
yylval->path = strdup(yytext); yylval->path = strdup(yytext);
return PATH; return PATH;
} }
{HPATH} { if (yytext[yyleng-1] == '/')
throw ParseError("path '%s' has a trailing slash", yytext); <PATH_START>{HPATH_START} {
POP_STATE();
PUSH_STATE(INPATH_SLASH);
yylval->path = strdup(yytext); yylval->path = strdup(yytext);
return HPATH; 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");
}
{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; }

View file

@ -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); }

View 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"};
}