* Optimise string constants by putting them in the symbol table.

This commit is contained in:
Eelco Dolstra 2010-10-23 21:11:59 +00:00
parent 8ac06726b9
commit b2ba62170c
4 changed files with 55 additions and 39 deletions

View file

@ -249,6 +249,14 @@ void mkString(Value & v, const string & s, const PathSet & context)
} }
void mkString(Value & v, const Symbol & s)
{
v.type = tString;
v.string.s = ((string) s).c_str();
v.string.context = 0;
}
void mkPath(Value & v, const char * s) void mkPath(Value & v, const char * s)
{ {
clearValue(v); clearValue(v);
@ -429,7 +437,7 @@ void ExprInt::eval(EvalState & state, Env & env, Value & v)
void ExprString::eval(EvalState & state, Env & env, Value & v) void ExprString::eval(EvalState & state, Env & env, Value & v)
{ {
mkString(v, s.c_str()); mkString(v, s);
} }

View file

@ -46,7 +46,7 @@ static void adjustLoc(YYLTYPE * loc, const char * s, size_t len)
} }
static Expr * unescapeStr(const char * s) static Expr * unescapeStr(SymbolTable & symbols, const char * s)
{ {
string t; string t;
char c; char c;
@ -66,7 +66,7 @@ static Expr * unescapeStr(const char * s)
} }
else t += c; else t += c;
} }
return new ExprString(t); return new ExprString(symbols.create(t));
} }
@ -119,7 +119,7 @@ inherit { return INHERIT; }
"$\"" will be consumed as part of a string, rather "$\"" will be consumed as part of a string, rather
than a "$" followed by the string terminator. than a "$" followed by the string terminator.
Disallow "$\"" for now. */ Disallow "$\"" for now. */
yylval->e = unescapeStr(yytext); yylval->e = unescapeStr(data->symbols, yytext);
return STR; return STR;
} }
<STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } <STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
@ -140,7 +140,7 @@ inherit { return INHERIT; }
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\\. { <IND_STRING>\'\'\\. {
yylval->e = unescapeStr(yytext + 2); yylval->e = unescapeStr(data->symbols, yytext + 2);
return IND_STR; return IND_STR;
} }
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } <IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }

View file

@ -65,8 +65,8 @@ struct ExprInt : Expr
struct ExprString : Expr struct ExprString : Expr
{ {
string s; Symbol s;
ExprString(const string & s) : s(s) { }; ExprString(const Symbol & s) : s(s) { };
COMMON_METHODS COMMON_METHODS
}; };

View file

@ -7,19 +7,44 @@
%parse-param { yyscan_t scanner } %parse-param { yyscan_t scanner }
%parse-param { ParseData * data } %parse-param { ParseData * data }
%lex-param { yyscan_t scanner } %lex-param { yyscan_t scanner }
%lex-param { ParseData * data }
%code requires {
%{
/* Newer versions of Bison copy the declarations below to #ifndef BISON_HEADER
parser-tab.hh, which sucks bigtime since lexer.l doesn't want that #define BISON_HEADER
stuff. So allow it to be excluded. */
#ifndef BISON_HEADER_HACK
#define BISON_HEADER_HACK
#include "util.hh" #include "util.hh"
#include "nixexpr.hh" #include "nixexpr.hh"
namespace nix {
struct ParseData
{
SymbolTable & symbols;
Expr * result;
Path basePath;
Path path;
string error;
Symbol sLetBody;
ParseData(SymbolTable & symbols)
: symbols(symbols)
, sLetBody(symbols.create("<let-body>"))
{ };
};
}
#define YY_DECL int yylex \
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParseData * data)
#endif
}
%{
#include "parser-tab.hh" #include "parser-tab.hh"
#include "lexer-tab.hh" #include "lexer-tab.hh"
#define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4 #define YYSTYPE YYSTYPE // workaround a bug in Bison 2.4
@ -28,27 +53,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
YY_DECL;
using namespace nix; using namespace nix;
namespace nix { namespace nix {
struct ParseData
{
SymbolTable & symbols;
Expr * result;
Path basePath;
Path path;
string error;
Symbol sLetBody;
ParseData(SymbolTable & symbols)
: symbols(symbols)
, sLetBody(symbols.create("<let-body>"))
{ };
};
static string showAttrPath(const vector<Symbol> & attrPath) static string showAttrPath(const vector<Symbol> & attrPath)
{ {
@ -113,9 +124,9 @@ static void addFormal(const Pos & pos, Formals * formals, const Formal & formal)
} }
static Expr * stripIndentation(vector<Expr *> & es) static Expr * stripIndentation(SymbolTable & symbols, vector<Expr *> & es)
{ {
if (es.empty()) return new ExprString(""); if (es.empty()) return new ExprString(symbols.create(""));
/* Figure out the minimum indentation. Note that by design /* Figure out the minimum indentation. Note that by design
whitespace-only final lines are not taken into account. (So whitespace-only final lines are not taken into account. (So
@ -195,7 +206,7 @@ static Expr * stripIndentation(vector<Expr *> & es)
s2 = string(s2, 0, p + 1); s2 = string(s2, 0, p + 1);
} }
es2->push_back(new ExprString(s2)); es2->push_back(new ExprString(symbols.create(s2)));
} }
return new ExprConcatStrings(es2); return new ExprConcatStrings(es2);
@ -224,9 +235,6 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
} }
#endif
%} %}
%union { %union {
@ -337,15 +345,15 @@ expr_simple
| INT { $$ = new ExprInt($1); } | INT { $$ = new ExprInt($1); }
| '"' string_parts '"' { | '"' string_parts '"' {
/* For efficiency, and to simplify parse trees a bit. */ /* For efficiency, and to simplify parse trees a bit. */
if ($2->empty()) $$ = new ExprString(""); if ($2->empty()) $$ = new ExprString(data->symbols.create(""));
else if ($2->size() == 1) $$ = $2->front(); else if ($2->size() == 1) $$ = $2->front();
else $$ = new ExprConcatStrings($2); else $$ = new ExprConcatStrings($2);
} }
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE { | IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(*$2); $$ = stripIndentation(data->symbols, *$2);
} }
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); } | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
| URI { $$ = new ExprString($1); } | URI { $$ = new ExprString(data->symbols.create($1)); }
| '(' expr ')' { $$ = $2; } | '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared /* Let expressions `let {..., body = ...}' are just desugared
into `(rec {..., body = ...}).body'. */ into `(rec {..., body = ...}).body'. */