* Indented strings.
This commit is contained in:
parent
a60317f20f
commit
d4f0b0fc6c
7 changed files with 65 additions and 70 deletions
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue