diff --git a/doc/manual/expressions/language-values.xml b/doc/manual/expressions/language-values.xml
index c3514e58f..0bf6632d6 100644
--- a/doc/manual/expressions/language-values.xml
+++ b/doc/manual/expressions/language-values.xml
@@ -155,7 +155,14 @@ stdenv.mkDerivation {
expression that contained it. For instance, if a Nix expression in
/foo/bar/bla.nix refers to
../xyzzy/fnord.nix, the absolute path is
- /foo/xyzzy/fnord.nix.
+ /foo/xyzzy/fnord.nix.
+
+ If the first component of a path is a ~,
+ it is interpreted as if the rest of the path were relative to the
+ user's home directory. e.g. ~/foo would be
+ equivalent to /home/edolstra/foo for a user
+ whose home directory is /home/edolstra.
+
Booleans with values
true and
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 82520ee7a..705190900 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -80,6 +80,7 @@ static Expr * unescapeStr(SymbolTable & symbols, const char * s)
ID [a-zA-Z\_][a-zA-Z0-9\_\'\-]*
INT [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\.\_\-\+]+)*\>
URI [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
@@ -159,6 +160,7 @@ or { return OR_KW; }
. return yytext[0]; /* just in case: shouldn't be reached */
{PATH} { yylval->path = strdup(yytext); return PATH; }
+{HPATH} { 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 7d877cd67..f4648b902 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -268,7 +268,7 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%token ID ATTRPATH
%token STR IND_STR
%token INT
-%token PATH SPATH
+%token PATH HPATH SPATH
%token URI
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
%token DOLLAR_CURLY /* == ${ */
@@ -376,6 +376,14 @@ expr_simple
$$ = stripIndentation(CUR_POS, data->symbols, *$2);
}
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
+ | HPATH {
+ auto path = string{$1 + 1};
+ $$ = new ExprConcatStrings(CUR_POS, false, new vector{
+ new ExprPath("/"),
+ new ExprApp(new ExprVar(data->symbols.create("__getEnv")),
+ new ExprString(data->symbols.create("HOME"))),
+ new ExprString(data->symbols.create(path))});
+ }
| SPATH {
string path($1 + 1, strlen($1) - 2);
$$ = new ExprApp(CUR_POS,