keep copies of parser inputs that are in-memory only

the parser modifies its inputs, which means that sharing them between
the error context reporting system and the parser itself can confuse the
reporting system. usually this led to early truncation of error context
reports which, while not dangerous, can be quite confusing.
This commit is contained in:
pennae 2024-01-29 06:19:23 +01:00
parent 686405ef41
commit d384ecd553
8 changed files with 20 additions and 7 deletions

View File

@ -2777,9 +2777,12 @@ Expr * EvalState::parseExprFromFile(const SourcePath & path, std::shared_ptr<Sta
Expr * EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv) Expr * EvalState::parseExprFromString(std::string s_, const SourcePath & basePath, std::shared_ptr<StaticEnv> & staticEnv)
{ {
auto s = make_ref<std::string>(std::move(s_)); // NOTE this method (and parseStdin) must take care to *fully copy* their input
s->append("\0\0", 2); // into their respective Pos::Origin until the parser stops overwriting its input
return parse(s->data(), s->size(), Pos::String{.source = s}, basePath, staticEnv); // data.
auto s = make_ref<std::string>(s_);
s_.append("\0\0", 2);
return parse(s_.data(), s_.size(), Pos::String{.source = s}, basePath, staticEnv);
} }
@ -2791,12 +2794,15 @@ Expr * EvalState::parseExprFromString(std::string s, const SourcePath & basePath
Expr * EvalState::parseStdin() Expr * EvalState::parseStdin()
{ {
// NOTE this method (and parseExprFromString) must take care to *fully copy* their
// input into their respective Pos::Origin until the parser stops overwriting its
// input data.
//Activity act(*logger, lvlTalkative, "parsing standard input"); //Activity act(*logger, lvlTalkative, "parsing standard input");
auto buffer = drainFD(0); auto buffer = drainFD(0);
// drainFD should have left some extra space for terminators // drainFD should have left some extra space for terminators
buffer.append("\0\0", 2); buffer.append("\0\0", 2);
auto s = make_ref<std::string>(std::move(buffer)); auto s = make_ref<std::string>(buffer);
return parse(s->data(), s->size(), Pos::Stdin{.source = s}, rootPath("."), staticBaseEnv); return parse(buffer.data(), buffer.size(), Pos::Stdin{.source = s}, rootPath("."), staticBaseEnv);
} }

View File

@ -3,3 +3,4 @@ error: attribute 'x' already defined at «stdin»:1:3
2| y = 456; 2| y = 456;
3| x = 789; 3| x = 789;
| ^ | ^
4| }

View File

@ -3,3 +3,4 @@ error: attribute 'x' already defined at «stdin»:9:5
9| x = 789; 9| x = 789;
10| inherit (as) x; 10| inherit (as) x;
| ^ | ^
11| };

View File

@ -3,3 +3,4 @@ error: attribute 'x' already defined at «stdin»:9:5
9| x = 789; 9| x = 789;
10| inherit (as) x; 10| inherit (as) x;
| ^ | ^
11| };

View File

@ -3,3 +3,4 @@ error: attribute 'services.ssh.port' already defined at «stdin»:2:3
2| services.ssh.port = 22; 2| services.ssh.port = 22;
3| services.ssh.port = 23; 3| services.ssh.port = 23;
| ^ | ^
4| }

View File

@ -3,3 +3,4 @@ error: attribute 'x' already defined at «stdin»:6:12
6| inherit x; 6| inherit x;
7| inherit x; 7| inherit x;
| ^ | ^
8| };

View File

@ -1,5 +1,6 @@
error: syntax error, unexpected ':', expecting '}' error: syntax error, unexpected ':', expecting '}'
at «stdin»:3:13: at «stdin»:3:13:
2| 2|
3| f = {x, y : 3| f = {x, y : ["baz" "bar" z "bat"]}: x + y;
| ^ | ^
4|

View File

@ -1,4 +1,5 @@
error: syntax error, unexpected invalid token, expecting end of file error: syntax error, unexpected invalid token, expecting end of file
at «stdin»:1:5: at «stdin»:1:5:
1| 123 1| 123 é 4
| ^ | ^
2|