1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:47:34 +00:00

Shell: Add support for heredocs

Closes #4283.
Heredocs are implemented in a way that makes them feel more like a
string (and not a weird redirection, a la bash).
There are two tunables, whether the string is dedented (`<<-` vs `<<~`)
and whether it allows interpolation (quoted key vs not).
To the familiar people, this is how Ruby handles them, and I feel is the
most elegant heredoc syntax.
Unlike the oddjob that is bash, heredocs are treated exactly as normal
strings, and can be used _anywhere_ where a string can be used.
They are *required* to appear in the same order as used after a newline
is seen when parsing the sequence that the heredoc is used in.
For instance:
```sh
echo <<-doc1 <<-doc2 | blah blah
contents for doc1
doc1
contents for doc2
doc2
```
The typical nice errors are also implemented :^)
This commit is contained in:
Ali Mohammad Pur 2021-04-29 07:04:00 +04:30 committed by Andreas Kling
parent 7c8d39e002
commit 3048274f5e
7 changed files with 364 additions and 10 deletions

View file

@ -474,6 +474,7 @@ public:
ForLoop,
FunctionDeclaration,
Glob,
Heredoc,
HistoryEvent,
IfCond,
ImmediateExpression,
@ -1313,6 +1314,39 @@ private:
NonnullRefPtr<Node> m_right;
};
class Heredoc final : public Node {
public:
Heredoc(Position, String end, bool allow_interpolation, bool deindent);
virtual ~Heredoc();
virtual void visit(NodeVisitor& visitor) override { visitor.visit(this); }
const String& end() const { return m_end; }
bool allow_interpolation() const { return m_allows_interpolation; }
bool deindent() const { return m_deindent; }
const RefPtr<AST::Node>& contents() const { return m_contents; }
void set_contents(RefPtr<AST::Node> contents)
{
m_contents = move(contents);
if (m_contents->is_syntax_error())
set_is_syntax_error(m_contents->syntax_error_node());
else
clear_syntax_error();
}
private:
NODE(Heredoc);
virtual void dump(int level) const override;
virtual RefPtr<Value> run(RefPtr<Shell>) override;
virtual void highlight_in_editor(Line::Editor&, Shell&, HighlightMetadata = {}) override;
virtual HitTestResult hit_test_position(size_t) const override;
virtual RefPtr<Node> leftmost_trivial_literal() const override { return this; };
String m_end;
bool m_allows_interpolation { false };
bool m_deindent { false };
RefPtr<AST::Node> m_contents;
};
class StringLiteral final : public Node {
public:
StringLiteral(Position, String);