Skip to content

Commit

Permalink
add antiquotations to paths
Browse files Browse the repository at this point in the history
  • Loading branch information
Radvendii committed Jul 29, 2021
1 parent da55210 commit a6ca81d
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 12 deletions.
12 changes: 8 additions & 4 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1580,7 +1580,6 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
and none of the strings are allowed to have contexts. */
if (first) {
firstType = vTmp.type();
first = false;
}

if (firstType == nInt) {
Expand All @@ -1601,7 +1600,12 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
} else
throwEvalError(pos, "cannot add %1% to a float", showType(vTmp));
} 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)
Expand Down Expand Up @@ -1790,7 +1794,7 @@ std::optional<string> EvalState::tryAttrsToString(const Pos & pos, Value & v,
}

string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore, bool copyToStore)
bool coerceMore, bool copyToStore, bool canonizePath)
{
forceValue(v, pos);

Expand All @@ -1802,7 +1806,7 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
}

if (v.type() == nPath) {
Path path(canonPath(v.path));
Path path(canonizePath ? canonPath(v.path) : v.path);
return copyToStore ? copyPathToStore(context, path) : path;
}

Expand Down
3 changes: 2 additions & 1 deletion src/libexpr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ public:
booleans and lists to a string. If `copyToStore' is set,
referenced paths are copied to the Nix store as a side effect. */
string coerceToString(const Pos & pos, Value & v, PathSet & context,
bool coerceMore = false, bool copyToStore = true);
bool coerceMore = false, bool copyToStore = true,
bool canonizePath = true);

string copyPathToStore(PathSet & context, const Path & path);

Expand Down
59 changes: 54 additions & 5 deletions src/libexpr/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
%s DEFAULT
%x STRING
%x IND_STRING
%x INPATH
%x INPATH_SLASH
%x PATH_START


%{
Expand Down Expand Up @@ -98,6 +101,7 @@ ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
INT [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_SEG [a-zA-Z0-9\.\_\-\+]*\/
HPATH \~(\/[a-zA-Z0-9\.\_\-\+]+)+\/?
SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
Expand Down Expand Up @@ -200,12 +204,57 @@ or { return OR_KW; }
return IND_STR;
}

{PATH_SEG}\$\{ {
PUSH_STATE(PATH_START);
yyless(0);
}

<PATH_START>{PATH_SEG} {
PUSH_STATE(INPATH_SLASH);
yylval->path = strdup(yytext);
return PATH;
}

{PATH} {
if (yytext[yyleng-1] == '/')
PUSH_STATE(INPATH_SLASH);
else
PUSH_STATE(INPATH);
yylval->path = strdup(yytext);
return PATH;
}
<INPATH,INPATH_SLASH>\$\{ {
POP_STATE();
PUSH_STATE(INPATH);
PUSH_STATE(DEFAULT);
return DOLLAR_CURLY;
}
<INPATH,INPATH_SLASH>{PATH}|{PATH_SEG} {
POP_STATE();
if (yytext[yyleng-1] == '/')
PUSH_STATE(INPATH_SLASH);
else
PUSH_STATE(INPATH);
// none of the escaped characters can actually show up in this string
// TODO: figure out what to use more directly than unescapeStr()
yylval->e = unescapeStr(data->symbols, yytext, yyleng);
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);
Expand Down
12 changes: 10 additions & 2 deletions src/libexpr/parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%token <e> STR IND_STR
%token <n> INT
%token <nf> FLOAT
%token <path> PATH HPATH SPATH
%token <path> PATH HPATH SPATH PATH_END
%token <uri> URI
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
%token DOLLAR_CURLY /* == ${ */
Expand Down Expand Up @@ -405,7 +405,15 @@ expr_simple
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(CUR_POS, data->symbols, *$2);
}
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
| PATH PATH_END { $$ = new ExprPath(absPath($1, data->basePath)); }
| PATH string_parts_interpolated PATH_END {
Path startPath = absPath($1, data->basePath);
/* add back in the trailing '/' to the first segment */
if ($1[strlen($1)-1] == '/')
startPath += "/";
$2->insert($2->begin(), new ExprPath(startPath));
$$ = new ExprConcatStrings(CUR_POS, false, $2);
}
| HPATH { $$ = new ExprPath(getHome() + string{$1 + 1}); }
| SPATH {
string path($1 + 1, strlen($1) - 2);
Expand Down

0 comments on commit a6ca81d

Please sign in to comment.