about summary refs log tree commit diff
path: root/src/libexpr/lexer.l
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/lexer.l')
-rw-r--r--src/libexpr/lexer.l41
1 files changed, 32 insertions, 9 deletions
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index d5a14f517acc..47f2bca1e699 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -3,6 +3,9 @@
 %option never-interactive
 
 
+%x STRING
+
+
 %{
 #include <string.h>
 #include <aterm2.h>
@@ -28,6 +31,9 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
     }
 }
 
+ATerm toATerm(const char * s);
+ATerm unescapeStr(const char * s);
+
 #define YY_USER_INIT initLoc(yylloc)
 #define YY_USER_ACTION adjustLoc(yylloc, yytext, yyleng);
 
@@ -36,7 +42,6 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
 
 ID          [a-zA-Z\_][a-zA-Z0-9\_\']*
 INT         [0-9]+
-STR         \"[^\n\"]*\"
 PATH        [a-zA-Z0-9\.\_\-\+]*(\/[a-zA-Z0-9\.\_\-\+]+)+
 URI         [a-zA-Z][a-zA-Z0-9\+\-\.]*\:[a-zA-Z0-9\%\/\?\:\@\&\=\+\$\,\-\_\.\!\~\*\']+
 
@@ -61,19 +66,27 @@ inherit     { return INHERIT; }
 \/\/        { return UPDATE; }
 \+\+        { return CONCAT; }
 
-{ID}        { yylval->t = ATmake("<str>", yytext); return ID; /* !!! alloc */ }
+{ID}        { yylval->t = toATerm(yytext); return ID; /* !!! alloc */ }
 {INT}       { int n = atoi(yytext); /* !!! overflow */
               yylval->t = ATmake("<int>", n);
               return INT;
             }
-{STR}       { int len = strlen(yytext);
-              yytext[len - 1] = 0;
-              yylval->t = ATmake("<str>", yytext + 1);
-              yytext[len - 1] = '\"';
-              return STR; /* !!! alloc */
+
+\"          { BEGIN(STRING); return '"'; }
+<STRING>([^\$\"\\]|\\.|\$[^\{\$])+ {
+/* Note: a dollar *is* allowed as-is in a string, as long as it's
+   not followed by a open brace.  This should probably be disallowed
+   eventually. */
+              yylval->t = unescapeStr(yytext); /* !!! alloc */ 
+              return STR;
             }
-{PATH}      { yylval->t = ATmake("<str>", yytext); return PATH; /* !!! alloc */ }
-{URI}       { yylval->t = ATmake("<str>", yytext); return URI; /* !!! alloc */ }
+<STRING>\$\{  { BEGIN(INITIAL); return DOLLAR_CURLY; }
+<STRING>\"  { BEGIN(INITIAL); return '"'; }
+<STRING>.   return yytext[0]; /* just in case: shouldn't be reached */
+
+
+{PATH}      { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ }
+{URI}       { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ }
 
 [ \t\n]+    /* eat up whitespace */
 \#[^\n]*    /* single-line comments */
@@ -83,3 +96,13 @@ inherit     { return INHERIT; }
 
 
 %%
+
+/* Horrible, disgusting hack: allow the parser to set the scanner
+   start condition back to STRING.  Necessary in interpolations like
+   "foo${expr}bar"; after the close brace we have to go back to the
+   STRING state. */
+void backToString(yyscan_t scanner)
+{
+    struct yyguts_t * yyg = (struct yyguts_t*) scanner;
+    BEGIN(STRING);
+}