summaryrefslogtreecommitdiff
path: root/Shell/Parser.cpp
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-09-13 15:54:33 +0430
committerAndreas Kling <kling@serenityos.org>2020-09-14 17:40:18 +0200
commitd1550ea64f0d2abf86b4bedd34ae7f7f71ccfc59 (patch)
treebad8f03044a3880923712b38e4261af8f9dbc326 /Shell/Parser.cpp
parent519aa2048ad9ca3f5d2a56906ff9feb3743bf746 (diff)
downloadserenity-d1550ea64f0d2abf86b4bedd34ae7f7f71ccfc59.zip
Shell: Add support for functions
This implementation does not have support for 'return' yet.
Diffstat (limited to 'Shell/Parser.cpp')
-rw-r--r--Shell/Parser.cpp89
1 files changed, 88 insertions, 1 deletions
diff --git a/Shell/Parser.cpp b/Shell/Parser.cpp
index 98ea06f5f7..3b101619e8 100644
--- a/Shell/Parser.cpp
+++ b/Shell/Parser.cpp
@@ -167,7 +167,10 @@ RefPtr<AST::Node> Parser::parse_sequence()
break;
}
- auto first = parse_or_logical_sequence();
+ auto first = parse_function_decl();
+
+ if (!first)
+ first = parse_or_logical_sequence();
if (!first)
return var_decls;
@@ -259,6 +262,90 @@ RefPtr<AST::Node> Parser::parse_variable_decls()
return create<AST::VariableDeclarations>(move(variables));
}
+RefPtr<AST::Node> Parser::parse_function_decl()
+{
+ auto rule_start = push_start();
+
+ auto restore = [&] {
+ m_offset = rule_start->offset;
+ return nullptr;
+ };
+
+ consume_while(is_whitespace);
+ auto offset_before_name = m_offset;
+ auto function_name = consume_while(is_word_character);
+ auto offset_after_name = m_offset;
+ if (function_name.is_empty())
+ return restore();
+
+ if (!expect('('))
+ return restore();
+
+ Vector<AST::FunctionDeclaration::NameWithPosition> arguments;
+ for (;;) {
+ consume_while(is_whitespace);
+
+ if (expect(')'))
+ break;
+
+ auto name_offset = m_offset;
+ auto arg_name = consume_while(is_word_character);
+ if (arg_name.is_empty()) {
+ // FIXME: Should this be a syntax error, or just return?
+ return restore();
+ }
+ arguments.append({ arg_name, { name_offset, m_offset } });
+ }
+
+ consume_while(is_whitespace);
+
+ {
+ RefPtr<AST::Node> syntax_error;
+ {
+ auto obrace_error_start = push_start();
+ syntax_error = create<AST::SyntaxError>("Expected an open brace '{' to start a function body");
+ }
+ if (!expect('{')) {
+ return create<AST::FunctionDeclaration>(
+ AST::FunctionDeclaration::NameWithPosition {
+ move(function_name),
+ { offset_before_name, offset_after_name } },
+ move(arguments),
+ move(syntax_error));
+ }
+ }
+
+ auto body = parse_toplevel();
+
+ {
+ RefPtr<AST::SyntaxError> syntax_error;
+ {
+ auto cbrace_error_start = push_start();
+ syntax_error = create<AST::SyntaxError>("Expected a close brace '}' to end a function body");
+ }
+ if (!expect('}')) {
+ if (body)
+ body->set_is_syntax_error(*syntax_error);
+ else
+ body = move(syntax_error);
+
+ return create<AST::FunctionDeclaration>(
+ AST::FunctionDeclaration::NameWithPosition {
+ move(function_name),
+ { offset_before_name, offset_after_name } },
+ move(arguments),
+ move(body));
+ }
+ }
+
+ return create<AST::FunctionDeclaration>(
+ AST::FunctionDeclaration::NameWithPosition {
+ move(function_name),
+ { offset_before_name, offset_after_name } },
+ move(arguments),
+ move(body));
+}
+
RefPtr<AST::Node> Parser::parse_or_logical_sequence()
{
consume_while(is_whitespace);