blob: ee127af23b6afbac60352228d0b1470e07f2f712 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/shell/parser/parser.h"
#include "src/developer/shell/parser/ast.h"
#include "src/developer/shell/parser/combinators.h"
#include "src/developer/shell/parser/text_match.h"
namespace shell::parser {
namespace {
ParseResultStream Whitespace(ParseResultStream prefixes);
// Create a parser that runs a sequence of parsers consecutively, with optional whitespace parsed
// between each parser.
fit::function<ParseResultStream(ParseResultStream)> WSSeq(
fit::function<ParseResultStream(ParseResultStream)> first) {
return Seq(Maybe(Whitespace), std::move(first), Maybe(Whitespace));
}
template <typename... Args>
fit::function<ParseResultStream(ParseResultStream)> WSSeq(
fit::function<ParseResultStream(ParseResultStream)> first, Args... args) {
return Seq(Maybe(Whitespace), std::move(first), WSSeq(std::move(args)...));
}
ParseResultStream IdentifierCharacter(ParseResultStream prefixes);
// Parse a keyword.
fit::function<ParseResultStream(ParseResultStream)> KW(const std::string& keyword) {
return Seq(Token(keyword), Not(IdentifierCharacter));
}
// Token Rules -------------------------------------------------------------------------------------
ParseResultStream IdentifierCharacter(ParseResultStream prefixes) {
return CharGroup("identifier character", "a-zA-Z0-9_")(std::move(prefixes));
}
ParseResultStream Whitespace(ParseResultStream prefixes) {
return NT<ast::Whitespace>(OnePlus(
Alt(AnyChar("space", " \n\r\t"), Seq(Token("#"), ZeroPlus(AnyCharBut("non-newline", "\n")),
Token("\n")))))(std::move(prefixes));
}
ParseResultStream Digit(ParseResultStream prefixes) {
return CharGroup("digit", "0-9")(std::move(prefixes));
}
ParseResultStream HexDigit(ParseResultStream prefixes) {
return CharGroup("hex digit", "a-fA-F0-9")(std::move(prefixes));
}
ParseResultStream UnescapedIdentifier(ParseResultStream prefixes);
fit::function<ParseResultStream(ParseResultStream)> Thingy(int min) {
if (min > 0) {
return Seq(IdentifierCharacter, Thingy(min - 1));
} else {
return [](ParseResultStream prefixes) { return Maybe(Thingy(1))(std::move(prefixes)); };
}
}
ParseResultStream UnescapedIdentifier(ParseResultStream prefixes) {
return Token(OnePlus(IdentifierCharacter))(std::move(prefixes));
}
// Grammar Rules -----------------------------------------------------------------------------------
// Parses an identifier
// myVariable
ParseResultStream Identifier(ParseResultStream prefixes) {
return NT<ast::Identifier>(Seq(Not(Digit), UnescapedIdentifier))(std::move(prefixes));
}
// Parses an unadorned decimal Integer
// 0
// 12345
// 12_345
ParseResultStream DecimalInteger(ParseResultStream prefixes) {
return Alt(Seq(Token("0"), Not(Digit)),
Seq(Not(Token("0")), Token(OnePlus(Digit)),
ZeroPlus(Seq(Token("_"), Token(OnePlus(Digit))))))(std::move(prefixes));
}
// Parses a hexadecimal integer marked by '0x'
// 0x1234abcd
// 0x12_abcd
ParseResultStream HexInteger(ParseResultStream prefixes) {
return Seq(Token("0x"),
Seq(Token(OnePlus(HexDigit)), ZeroPlus(Seq(Token("_"), Token(OnePlus(HexDigit))))))(
std::move(prefixes));
}
// Parses an integer.
// 0
// 12345
// 12_345
// 0x1234abcd
// 0x12_abcd
ParseResultStream Integer(ParseResultStream prefixes) {
// TODO: Binary integers, once we ask the FIDL team about them.
return NT<ast::Integer>(Alt(HexInteger, DecimalInteger))(std::move(prefixes));
}
// Parses an expression. This is effectively unimplemented right now.
ParseResultStream Expression(ParseResultStream prefixes) {
// Unimplemented
return NT<ast::Expression>(Integer)(std::move(prefixes));
}
// Parses a variable declaration:
// var foo = 4.5
ParseResultStream VariableDecl(ParseResultStream prefixes) {
return NT<ast::VariableDecl>(
WSSeq(Alt(KW("var"), KW("const")), Identifier, Token("="), Expression))(std::move(prefixes));
}
// Parses the body of a program, but doesn't create an AST node. This is useful for parsing blocks
// where we might want to include the braces in the node's children.
ParseResultStream ProgramContent(ParseResultStream prefixes) {
/* Eventual full version of this rule is:
return Alt(WSSeq(VariableDecl, Maybe(WSSeq(AnyChar(";&", "; or &"), ProgramMeta))),
WSSeq(FunctionDecl, Program),
WSSeq(Expression, Maybe(WSSeq(AnyChar(";&", "; or &"), ProgramMeta))),
Empty)(prefixes);
*/
return Alt(WSSeq(VariableDecl, Maybe(WSSeq(AnyChar("; or &", ";&"), ProgramContent))),
Empty)(std::move(prefixes));
}
} // namespace
std::shared_ptr<ast::Node> Parse(std::string_view text) {
return NT<ast::Program>(Seq(ProgramContent, EOS))(text).Next().node();
}
} // namespace shell::parser