* Indented strings.

This commit is contained in:
Eelco Dolstra 2010-04-12 22:03:27 +00:00
parent a60317f20f
commit d4f0b0fc6c
7 changed files with 65 additions and 70 deletions

View file

@ -67,6 +67,7 @@ void run(Strings args)
doTest(state, "__add 1 2"); doTest(state, "__add 1 2");
doTest(state, "null"); doTest(state, "null");
doTest(state, "\"foo\""); doTest(state, "\"foo\"");
doTest(state, "''\n foo\n bar\n ''");
doTest(state, "let s = \"bar\"; in \"foo${s}\""); doTest(state, "let s = \"bar\"; in \"foo${s}\"");
doTest(state, "if true then 1 else 2"); doTest(state, "if true then 1 else 2");
doTest(state, "if false then 1 else 2"); doTest(state, "if false then 1 else 2");

View file

@ -367,6 +367,12 @@ bool EvalState::evalBool(Env & env, Expr * e)
} }
void Expr::eval(EvalState & state, Env & env, Value & v)
{
abort();
}
void ExprInt::eval(EvalState & state, Env & env, Value & v) void ExprInt::eval(EvalState & state, Env & env, Value & v)
{ {
mkInt(v, n); mkInt(v, n);

View file

@ -111,10 +111,11 @@ inherit { return INHERIT; }
\" { BEGIN(STRING); return '"'; } \" { BEGIN(STRING); return '"'; }
<STRING>([^\$\"\\]|\$[^\{\"]|\\.)+ { <STRING>([^\$\"\\]|\$[^\{\"]|\\.)+ {
/* !!! Not quite right: we want a follow restriction on "$", it /* !!! Not quite right: we want a follow restriction on
shouldn't be followed by a "{". Right now "$\"" will be consumed "$", it shouldn't be followed by a "{". Right now
as part of a string, rather than a "$" followed by the string "$\"" will be consumed as part of a string, rather
terminator. Disallow "$\"" for now. */ than a "$" followed by the string terminator.
Disallow "$\"" for now. */
yylval->e = unescapeStr(yytext); yylval->e = unescapeStr(yytext);
return STR; return STR;
} }
@ -124,25 +125,25 @@ inherit { return INHERIT; }
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; } \'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ { <IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
//yylval->t = makeIndStr(toATerm(yytext)); yylval->e = new ExprIndStr(yytext);
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\$ { <IND_STRING>\'\'\$ {
//yylval->t = makeIndStr(toATerm("$")); yylval->e = new ExprIndStr("$");
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\' { <IND_STRING>\'\'\' {
//yylval->t = makeIndStr(toATerm("''")); yylval->e = new ExprIndStr("''");
return IND_STR; return IND_STR;
} }
<IND_STRING>\'\'\\. { <IND_STRING>\'\'\\. {
//yylval->t = unescapeStr(yytext + 2); yylval->e = new ExprIndStr(yytext + 2);
return IND_STR; return IND_STR;
} }
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; } <IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; } <IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
<IND_STRING>\' { <IND_STRING>\' {
//yylval->t = makeIndStr(toATerm("'")); yylval->e = new ExprIndStr("'");
return IND_STR; return IND_STR;
} }
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */ <IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */

View file

@ -15,6 +15,11 @@ std::ostream & operator << (std::ostream & str, Expr & e)
} }
void Expr::show(std::ostream & str)
{
abort();
}
void ExprInt::show(std::ostream & str) void ExprInt::show(std::ostream & str)
{ {
str << n; str << n;
@ -152,20 +157,6 @@ ATerm bottomupRewrite(TermFun & f, ATerm e)
} }
Expr makeAttrs(const ATermMap & attrs)
{
ATermList bnds = ATempty;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i) {
Expr e;
ATerm pos;
if (!matchAttrRHS(i->value, e, pos))
abort(); /* can't happen */
bnds = ATinsert(bnds, makeBind(i->key, e, pos));
}
return makeAttrs(bnds);
}
static void varsBoundByPattern(ATermMap & map, Pattern pat) static void varsBoundByPattern(ATermMap & map, Pattern pat)
{ {
ATerm name; ATerm name;

View file

@ -35,11 +35,8 @@ struct EvalState;
struct Expr struct Expr
{ {
virtual void show(std::ostream & str) = 0; virtual void show(std::ostream & str);
virtual void eval(EvalState & state, Env & env, Value & v) virtual void eval(EvalState & state, Env & env, Value & v);
{
throw Error("not implemented");
}
}; };
std::ostream & operator << (std::ostream & str, Expr & e); std::ostream & operator << (std::ostream & str, Expr & e);
@ -62,6 +59,13 @@ struct ExprString : Expr
COMMON_METHODS COMMON_METHODS
}; };
/* Temporary class used during parsing of indented strings. */
struct ExprIndStr : Expr
{
string s;
ExprIndStr(const string & s) : s(s) { };
};
struct ExprPath : Expr struct ExprPath : Expr
{ {
string s; string s;
@ -206,10 +210,6 @@ struct TermFun
ATerm bottomupRewrite(TermFun & f, ATerm e); ATerm bottomupRewrite(TermFun & f, ATerm e);
/* Create an attribute set expression from an Attrs value. */
Expr makeAttrs(const ATermMap & attrs);
/* Check whether all variables are defined in the given expression. /* Check whether all variables are defined in the given expression.
Throw an exception if this isn't the case. */ Throw an exception if this isn't the case. */
void checkVarDefs(const ATermMap & def, Expr e); void checkVarDefs(const ATermMap & def, Expr e);

View file

@ -174,11 +174,12 @@ static void checkPatternVars(ATerm pos, Pattern pat)
ATermMap map; ATermMap map;
checkPatternVars(pos, map, pat); checkPatternVars(pos, map, pat);
} }
#endif
static Expr stripIndentation(ATermList es) static Expr * stripIndentation(vector<Expr *> & es)
{ {
if (es == ATempty) return makeStr(""); if (es.empty()) return new ExprString("");
/* 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
@ -186,9 +187,9 @@ static Expr stripIndentation(ATermList es)
bool atStartOfLine = true; /* = seen only whitespace in the current line */ bool atStartOfLine = true; /* = seen only whitespace in the current line */
unsigned int minIndent = 1000000; unsigned int minIndent = 1000000;
unsigned int curIndent = 0; unsigned int curIndent = 0;
ATerm e; foreach (vector<Expr *>::iterator, i, es) {
for (ATermIterator i(es); i; ++i) { ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
if (!matchIndStr(*i, e)) { if (!e) {
/* Anti-quotations end the current start-of-line whitespace. */ /* Anti-quotations end the current start-of-line whitespace. */
if (atStartOfLine) { if (atStartOfLine) {
atStartOfLine = false; atStartOfLine = false;
@ -196,12 +197,11 @@ static Expr stripIndentation(ATermList es)
} }
continue; continue;
} }
string s = aterm2String(e); for (unsigned int j = 0; j < e->s.size(); ++j) {
for (unsigned int j = 0; j < s.size(); ++j) {
if (atStartOfLine) { if (atStartOfLine) {
if (s[j] == ' ') if (e->s[j] == ' ')
curIndent++; curIndent++;
else if (s[j] == '\n') { else if (e->s[j] == '\n') {
/* Empty line, doesn't influence minimum /* Empty line, doesn't influence minimum
indentation. */ indentation. */
curIndent = 0; curIndent = 0;
@ -209,7 +209,7 @@ static Expr stripIndentation(ATermList es)
atStartOfLine = false; atStartOfLine = false;
if (curIndent < minIndent) minIndent = curIndent; if (curIndent < minIndent) minIndent = curIndent;
} }
} else if (s[j] == '\n') { } else if (e->s[j] == '\n') {
atStartOfLine = true; atStartOfLine = true;
curIndent = 0; curIndent = 0;
} }
@ -217,37 +217,37 @@ static Expr stripIndentation(ATermList es)
} }
/* Strip spaces from each line. */ /* Strip spaces from each line. */
ATermList es2 = ATempty; vector<Expr *> * es2 = new vector<Expr *>;
atStartOfLine = true; atStartOfLine = true;
unsigned int curDropped = 0; unsigned int curDropped = 0;
unsigned int n = ATgetLength(es); unsigned int n = es.size();
for (ATermIterator i(es); i; ++i, --n) { for (vector<Expr *>::iterator i = es.begin(); i != es.end(); ++i, --n) {
if (!matchIndStr(*i, e)) { ExprIndStr * e = dynamic_cast<ExprIndStr *>(*i);
if (!e) {
atStartOfLine = false; atStartOfLine = false;
curDropped = 0; curDropped = 0;
es2 = ATinsert(es2, *i); es2->push_back(*i);
continue; continue;
} }
string s = aterm2String(e);
string s2; string s2;
for (unsigned int j = 0; j < s.size(); ++j) { for (unsigned int j = 0; j < e->s.size(); ++j) {
if (atStartOfLine) { if (atStartOfLine) {
if (s[j] == ' ') { if (e->s[j] == ' ') {
if (curDropped++ >= minIndent) if (curDropped++ >= minIndent)
s2 += s[j]; s2 += e->s[j];
} }
else if (s[j] == '\n') { else if (e->s[j] == '\n') {
curDropped = 0; curDropped = 0;
s2 += s[j]; s2 += e->s[j];
} else { } else {
atStartOfLine = false; atStartOfLine = false;
curDropped = 0; curDropped = 0;
s2 += s[j]; s2 += e->s[j];
} }
} else { } else {
s2 += s[j]; s2 += e->s[j];
if (s[j] == '\n') atStartOfLine = true; if (e->s[j] == '\n') atStartOfLine = true;
} }
} }
@ -258,13 +258,12 @@ static Expr stripIndentation(ATermList es)
if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos) if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos)
s2 = string(s2, 0, p + 1); s2 = string(s2, 0, p + 1);
} }
es2 = ATinsert(es2, makeStr(s2)); es2->push_back(new ExprString(s2));
} }
return makeConcatStrings(ATreverse(es2)); return new ExprConcatStrings(es2);
} }
#endif
void backToString(yyscan_t scanner); void backToString(yyscan_t scanner);
@ -316,11 +315,10 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, ParseData * data, const char * err
%type <e> expr_app expr_select expr_simple %type <e> expr_app expr_select expr_simple
%type <list> expr_list %type <list> expr_list
%type <attrs> binds %type <attrs> binds
%type <ts> attrpath ind_string_parts
%type <formals> formals %type <formals> formals
%type <formal> formal %type <formal> formal
%type <ids> ids %type <ids> ids attrpath
%type <string_parts> string_parts %type <string_parts> string_parts ind_string_parts
%token <id> ID ATTRPATH %token <id> ID ATTRPATH
%token <e> STR IND_STR %token <e> STR IND_STR
%token <n> INT %token <n> INT
@ -411,11 +409,9 @@ expr_simple
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(ATreverse($2)); $$ = stripIndentation(*$2);
} }
*/
| PATH { $$ = new ExprPath(absPath($1, data->basePath)); } | PATH { $$ = new ExprPath(absPath($1, data->basePath)); }
| URI { $$ = new ExprString($1); } | URI { $$ = new ExprString($1); }
| '(' expr ')' { $$ = $2; } | '(' expr ')' { $$ = $2; }
@ -437,9 +433,9 @@ string_parts
; ;
ind_string_parts ind_string_parts
: ind_string_parts IND_STR { $$ = ATinsert($1, $2); } : ind_string_parts IND_STR { $$ = $1; $1->push_back($2); }
| ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = ATinsert($1, $3); } | ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = $1; $1->push_back($3); }
| { $$ = ATempty; } | { $$ = new vector<Expr *>; }
; ;
binds binds

View file

@ -42,7 +42,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
bool evalOnly, bool xmlOutput, Expr * e) bool evalOnly, bool xmlOutput, Expr * e)
{ {
if (parseOnly) if (parseOnly)
std::cout << format("%1%\n"); std::cout << format("%1%\n") % *e;
else else
foreach (Strings::const_iterator, i, attrPaths) { foreach (Strings::const_iterator, i, attrPaths) {
Value v; Value v;