aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval.cc12
-rw-r--r--src/libexpr/eval.hh3
-rw-r--r--src/libexpr/lexer.l88
-rw-r--r--src/libexpr/parser.y25
4 files changed, 106 insertions, 22 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 419b377ba..a8bfa7711 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -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) {
@@ -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)
@@ -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);
@@ -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;
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 47db8b2ba..ad6fb7ff4 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -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);
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 27975dc9e..8ad6a1957 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -9,6 +9,9 @@
%s DEFAULT
%x 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\_\'\-]*
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\.\_\-\+]+)+\/?
-HPATH \~(\/[a-zA-Z0-9\.\_\-\+]+)+\/?
-SPATH \<[a-zA-Z0-9\.\_\-\+]+(\/[a-zA-Z0-9\.\_\-\+]+)*\>
+PATH_CHAR [a-zA-Z0-9\.\_\-\+]
+PATH {PATH_CHAR}*(\/{PATH_CHAR}+)+\/?
+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\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
@@ -200,17 +206,73 @@ or { return OR_KW; }
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; }
{URI} { yylval->uri = strdup(yytext); return URI; }
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index f948dde47..796e87cc1 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -290,13 +290,13 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%type <formal> formal
%type <attrNames> attrs attrpath
%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
%token <id> ID ATTRPATH
%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 /* == ${ */
@@ -405,8 +405,11 @@ expr_simple
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(CUR_POS, data->symbols, *$2);
}
- | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
- | HPATH { $$ = new ExprPath(getHome() + string{$1 + 1}); }
+ | path_start PATH_END { $$ = $1; }
+ | path_start string_parts_interpolated PATH_END {
+ $2->insert($2->begin(), $1);
+ $$ = new ExprConcatStrings(CUR_POS, false, $2);
+ }
| SPATH {
string path($1 + 1, strlen($1) - 2);
$$ = 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] == '/')
+ path += "/";
+ $$ = new ExprPath(path);
+ }
+ | HPATH {
+ Path path(getHome() + string($1 + 1));
+ $$ = new ExprPath(path);
+ }
+ ;
+
ind_string_parts
: ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
| ind_string_parts DOLLAR_CURLY expr '}' { $$ = $1; $1->push_back($3); }