feat(Parser): Introduce AST toString and basic parser structure
Signed-off-by: erick-alcachofa <erick@artichoke.dev> This commit introduces the foundational structure for the parser and Abstract Syntax Tree (AST). It includes a new `Parser.hpp` header that outlines the primary parsing functions for top-level declarations like `modules`, `structs`, `enums`, and `functions`. It also adds a `toString` function for the AST to aid in debugging and visualization. The commit also updates the `Expected.hpp` utility by adding new error codes like `ecUnexpectedToken`, `ecExpectedSemicolon`, `ecImportInsideModule`, and `ecUnimplemented` to provide more granular and descriptive parsing errors. The `Tokenizer` has been updated to use these new, more specific exceptions.
This commit is contained in:
parent
583b20230d
commit
552cda58e7
@ -28,4 +28,6 @@ namespace arti::lang::ast {
|
|||||||
return std::make_unique<typename Node::element_type>();
|
return std::make_unique<typename Node::element_type>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string toString(const AST &tree, std::size_t padding = 0);
|
||||||
|
|
||||||
} // namespace arti::lang::ast
|
} // namespace arti::lang::ast
|
||||||
|
|||||||
@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <artichoke/Parser/AST/AST.hpp>
|
||||||
|
#include <artichoke/Tokenizer/Tokenizer.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang {
|
||||||
|
|
||||||
|
struct Parser {
|
||||||
|
Parser(std::string source) noexcept;
|
||||||
|
|
||||||
|
Parser(std::string unitName, std::string source) noexcept;
|
||||||
|
|
||||||
|
Parser(Parser &&) noexcept;
|
||||||
|
Parser &operator=(Parser &&) noexcept;
|
||||||
|
|
||||||
|
Parser(const Parser &) noexcept = delete;
|
||||||
|
Parser &operator=(const Parser &) noexcept = delete;
|
||||||
|
|
||||||
|
Expected<ast::AST> parse();
|
||||||
|
|
||||||
|
Expected<ast::Optional<ast::TopLevelDeclNode>>
|
||||||
|
parseTopLevelDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::ImportDeclNode>
|
||||||
|
parseImportDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::AliasDeclNode>
|
||||||
|
parseAliasDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::ModuleDeclNode>
|
||||||
|
parseModuleDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::StructDeclNode>
|
||||||
|
parseStructDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::EnumDeclNode>
|
||||||
|
parseEnumDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::GenericParamNode>>
|
||||||
|
parseGenericParamsList();
|
||||||
|
|
||||||
|
Expected<ast::GenericParamNode>
|
||||||
|
parseGenericParam();
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::StructMemberNode>>
|
||||||
|
parseStructMembersList();
|
||||||
|
|
||||||
|
Expected<ast::StructMemberNode>
|
||||||
|
parseStructMember();
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::EnumMemberNode>>
|
||||||
|
parseEnumMembersList();
|
||||||
|
|
||||||
|
Expected<ast::EnumMemberNode>
|
||||||
|
parseEnumMember();
|
||||||
|
|
||||||
|
Expected<ast::FunctionDeclNode>
|
||||||
|
parseFunctionDeclaration();
|
||||||
|
|
||||||
|
Expected<ast::NamespacedIdentifierNode>
|
||||||
|
parseNamespacedIdentifier();
|
||||||
|
|
||||||
|
Expected<ast::TypeNode>
|
||||||
|
parseType();
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::TypeQualifier>>
|
||||||
|
parseTypeQualifiers();
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::TypeNode>>
|
||||||
|
parseGenericArgumentsList();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string unitName;
|
||||||
|
std::string sourceCode;
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@ -17,6 +17,10 @@ namespace arti::lang {
|
|||||||
ecInvalidCharacter,
|
ecInvalidCharacter,
|
||||||
ecInvalidIndex,
|
ecInvalidIndex,
|
||||||
ecInvalidComment,
|
ecInvalidComment,
|
||||||
|
ecUnexpectedToken,
|
||||||
|
ecExpectedSemicolon,
|
||||||
|
ecImportInsideModule,
|
||||||
|
ecUnimplemented,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Exception {
|
struct Exception {
|
||||||
@ -71,6 +75,24 @@ namespace arti::lang {
|
|||||||
else if constexpr (code == ecInvalidComment) {
|
else if constexpr (code == ecInvalidComment) {
|
||||||
return "Invalid comment found, missing '*/' end of comment";
|
return "Invalid comment found, missing '*/' end of comment";
|
||||||
}
|
}
|
||||||
|
else if constexpr (code == ecUnexpectedToken) {
|
||||||
|
return std::format(
|
||||||
|
"Found unexpected token '{}', expected {}",
|
||||||
|
std::forward<Args>(args)...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if constexpr (code == ecExpectedSemicolon) {
|
||||||
|
return std::format(
|
||||||
|
"Expected ';', got '{}'",
|
||||||
|
std::forward<Args>(args)...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if constexpr (code == ecImportInsideModule) {
|
||||||
|
return "Cannot use import statements inside a module declaration";
|
||||||
|
}
|
||||||
|
else if constexpr (code == ecUnimplemented) {
|
||||||
|
return "Unimplemented";
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
|||||||
1742
lib/src/Parser/AST/AST.cpp
Normal file
1742
lib/src/Parser/AST/AST.cpp
Normal file
File diff suppressed because it is too large
Load Diff
755
lib/src/Parser/Declarations.cpp
Normal file
755
lib/src/Parser/Declarations.cpp
Normal file
@ -0,0 +1,755 @@
|
|||||||
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang {
|
||||||
|
|
||||||
|
Expected<ast::Optional<ast::TopLevelDeclNode>>
|
||||||
|
Parser::parseTopLevelDeclaration() {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
bool exportable = false;
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::kwExport) {
|
||||||
|
exportable = true;
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::kwImport) {
|
||||||
|
if (exportable) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"exportable declaration, ie. Struct, Enum, Function, Module"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node = parseImportDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwUsing) {
|
||||||
|
if (exportable) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"exportable declaration, ie. Struct, Enum, Function, Module"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node = parseAliasDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwModule) {
|
||||||
|
auto node = parseModuleDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
(*node)->isExported = exportable;
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwStruct) {
|
||||||
|
auto node = parseStructDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
(*node)->isExported = exportable;
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwEnum) {
|
||||||
|
auto node = parseEnumDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
(*node)->isExported = exportable;
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value == TokenV::kwFn) {
|
||||||
|
auto node = parseFunctionDeclaration();
|
||||||
|
|
||||||
|
if (! node) {
|
||||||
|
return Unexpected<>{ std::move(node).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
(*node)->isExported = exportable;
|
||||||
|
|
||||||
|
return ast::TopLevelDeclNode{ std::move(node).value() };
|
||||||
|
}
|
||||||
|
else if (peekToken->value != TokenV::tkEOF) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"top level declaration"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::ImportDeclNode> Parser::parseImportDeclaration() {
|
||||||
|
auto node = ast::MakeNode<ast::ImportDeclNode>();
|
||||||
|
node->importAll = false;
|
||||||
|
|
||||||
|
auto kw = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! kw) {
|
||||||
|
return Unexpected<>{ std::move(kw).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location.line = kw->line;
|
||||||
|
node->location.column = kw->column;
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto target = parseNamespacedIdentifier();
|
||||||
|
|
||||||
|
if (! target) {
|
||||||
|
return Unexpected<>{ std::move(target).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->importTarget = std::move(target).value();
|
||||||
|
|
||||||
|
auto peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value == TokenV::opAccess) {
|
||||||
|
auto peekStar = tokenizer.peek(1);
|
||||||
|
|
||||||
|
if (! peekStar) {
|
||||||
|
return Unexpected<>{ std::move(peekStar).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekStar->value != TokenV::opStar) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekStar->line,
|
||||||
|
peekStar->column,
|
||||||
|
toString(*peekStar),
|
||||||
|
"identifier or '*'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
node->importAll = true;
|
||||||
|
std::ignore = tokenizer.consume(2);
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value != TokenV::opSemicolon) {
|
||||||
|
return langException<ExceptCode::ecExpectedSemicolon>(
|
||||||
|
peekNext->line,
|
||||||
|
peekNext->column,
|
||||||
|
toString(*peekNext)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::AliasDeclNode> Parser::parseAliasDeclaration() {
|
||||||
|
auto node = ast::MakeNode<ast::AliasDeclNode>();
|
||||||
|
|
||||||
|
auto kw = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! kw) {
|
||||||
|
return Unexpected<>{ std::move(kw).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location.line = kw->line;
|
||||||
|
node->location.column = kw->column;
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto aliased = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! aliased) {
|
||||||
|
return Unexpected<>{ std::move(aliased).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliased->value != TokenV::tkIdentifier) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
aliased->line,
|
||||||
|
aliased->column,
|
||||||
|
toString(*aliased),
|
||||||
|
"identifier"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
node->alias = aliased->strValue;
|
||||||
|
|
||||||
|
auto eq = tokenizer.peekExpect(0, TokenV::opAssign);
|
||||||
|
|
||||||
|
if (! eq) {
|
||||||
|
return Unexpected{ std::move(eq).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto type = parseType();
|
||||||
|
|
||||||
|
if (! type) {
|
||||||
|
return Unexpected{ std::move(type).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->target = std::move(type).value();
|
||||||
|
|
||||||
|
auto semicolon = tokenizer.peekExpect(0, TokenV::opSemicolon);
|
||||||
|
|
||||||
|
if (! semicolon) {
|
||||||
|
return Unexpected{ std::move(semicolon).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::ModuleDeclNode> Parser::parseModuleDeclaration() {
|
||||||
|
auto node = ast::MakeNode<ast::ModuleDeclNode>();
|
||||||
|
|
||||||
|
auto kw = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! kw) {
|
||||||
|
return Unexpected<>{ std::move(kw).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location.line = kw->line;
|
||||||
|
node->location.column = kw->column;
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto moduleName = parseNamespacedIdentifier();
|
||||||
|
|
||||||
|
if (! moduleName) {
|
||||||
|
return Unexpected<>{ std::move(moduleName).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->name = std::move(moduleName).value();
|
||||||
|
|
||||||
|
auto lsquirly = tokenizer.peekExpect(0, TokenV::opLSquirly);
|
||||||
|
|
||||||
|
if (! lsquirly) {
|
||||||
|
return Unexpected{ std::move(lsquirly).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
bool keepParsing = true;
|
||||||
|
auto decl = ast::Optional<ast::TopLevelDeclNode>{};
|
||||||
|
|
||||||
|
while (keepParsing) {
|
||||||
|
auto idecl = parseTopLevelDeclaration();
|
||||||
|
|
||||||
|
if (! idecl) {
|
||||||
|
return Unexpected<>{ std::move(idecl).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
decl = std::move(idecl).value();
|
||||||
|
|
||||||
|
if (! decl.has_value()) {
|
||||||
|
keepParsing = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (std::holds_alternative<ast::ModuleDeclNode>(*decl)) {
|
||||||
|
node->childModules.push_back(
|
||||||
|
std::get<ast::ModuleDeclNode>(std::move(*decl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<ast::StructDeclNode>(*decl)) {
|
||||||
|
node->innerDeclarations.push_back(
|
||||||
|
std::get<ast::StructDeclNode>(std::move(*decl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<ast::EnumDeclNode>(*decl)) {
|
||||||
|
node->innerDeclarations.push_back(
|
||||||
|
std::get<ast::EnumDeclNode>(std::move(*decl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<ast::FunctionDeclNode>(*decl)) {
|
||||||
|
node->innerDeclarations.push_back(
|
||||||
|
std::get<ast::FunctionDeclNode>(std::move(*decl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<ast::AliasDeclNode>(*decl)) {
|
||||||
|
node->aliasDeclarations.push_back(
|
||||||
|
std::get<ast::AliasDeclNode>(std::move(*decl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<ast::ImportDeclNode>(*decl)) {
|
||||||
|
auto importDecl = std::get<ast::ImportDeclNode>(std::move(*decl));
|
||||||
|
|
||||||
|
return langException<ExceptCode::ecImportInsideModule>(
|
||||||
|
importDecl->location.line,
|
||||||
|
importDecl->location.column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rsquirly = tokenizer.peekExpect(0, TokenV::opRSquirly);
|
||||||
|
|
||||||
|
if (! rsquirly) {
|
||||||
|
return Unexpected{ std::move(rsquirly).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::StructDeclNode> Parser::parseStructDeclaration() {
|
||||||
|
auto node = ast::MakeNode<ast::StructDeclNode>();
|
||||||
|
|
||||||
|
auto kw = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! kw) {
|
||||||
|
return Unexpected<>{ std::move(kw).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location.line = kw->line;
|
||||||
|
node->location.column = kw->column;
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto name = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! name) {
|
||||||
|
return Unexpected<>{ std::move(name).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name->value != TokenV::tkIdentifier) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
name->line,
|
||||||
|
name->column,
|
||||||
|
toString(*name),
|
||||||
|
"identifier"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
node->name = name->strValue;
|
||||||
|
|
||||||
|
auto peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value == TokenV::opLt) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto generics = parseGenericParamsList();
|
||||||
|
|
||||||
|
if (! generics) {
|
||||||
|
return Unexpected<>{ std::move(generics).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->genericParams = std::move(*generics);
|
||||||
|
|
||||||
|
if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) {
|
||||||
|
return Unexpected{ std::move(closeG).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value != TokenV::opLSquirly) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekNext->line,
|
||||||
|
peekNext->column,
|
||||||
|
toString(*peekNext),
|
||||||
|
"'{'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto members = parseStructMembersList();
|
||||||
|
|
||||||
|
if (! members) {
|
||||||
|
return Unexpected<>{ std::move(members).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->structMembers = std::move(members).value();
|
||||||
|
|
||||||
|
if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) {
|
||||||
|
return Unexpected{ std::move(closeS).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::EnumDeclNode> Parser::parseEnumDeclaration() {
|
||||||
|
auto node = ast::MakeNode<ast::EnumDeclNode>();
|
||||||
|
|
||||||
|
auto kw = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! kw) {
|
||||||
|
return Unexpected<>{ std::move(kw).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->location.line = kw->line;
|
||||||
|
node->location.column = kw->column;
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto name = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! name) {
|
||||||
|
return Unexpected<>{ std::move(name).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name->value != TokenV::tkIdentifier) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
name->line,
|
||||||
|
name->column,
|
||||||
|
toString(*name),
|
||||||
|
"identifier"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
node->name = name->strValue;
|
||||||
|
|
||||||
|
auto peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value == TokenV::opLt) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto generics = parseGenericParamsList();
|
||||||
|
|
||||||
|
if (! generics) {
|
||||||
|
return Unexpected<>{ std::move(generics).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->genericParams = std::move(*generics);
|
||||||
|
|
||||||
|
if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) {
|
||||||
|
return Unexpected{ std::move(closeG).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value != TokenV::opLSquirly) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekNext->line,
|
||||||
|
peekNext->column,
|
||||||
|
toString(*peekNext),
|
||||||
|
"'{'"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto members = parseEnumMembersList();
|
||||||
|
|
||||||
|
if (! members) {
|
||||||
|
return Unexpected<>{ std::move(members).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->enumMembers = std::move(members).value();
|
||||||
|
|
||||||
|
if (auto closeS = tokenizer.peekExpect(0, TokenV::opRSquirly); ! closeS) {
|
||||||
|
return Unexpected{ std::move(closeS).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::GenericParamNode>>
|
||||||
|
Parser::parseGenericParamsList() {
|
||||||
|
auto paramsList = ast::Vector<ast::GenericParamNode>{};
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekToken->value != TokenV::opGt) {
|
||||||
|
auto param = parseGenericParam();
|
||||||
|
|
||||||
|
if (! param) {
|
||||||
|
return Unexpected{ std::move(param).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
paramsList.push_back(std::move(param).value());
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::GenericParamNode> Parser::parseGenericParam() {
|
||||||
|
auto node = ast::MakeNode<ast::GenericParamNode>();
|
||||||
|
|
||||||
|
if (auto kwTypename = tokenizer.peekExpect(0, TokenV::kwTypename);
|
||||||
|
! kwTypename) {
|
||||||
|
return Unexpected{ std::move(kwTypename).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = { .line = kwTypename->line,
|
||||||
|
.column = kwTypename->column };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) {
|
||||||
|
return Unexpected{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->name = ident->strValue;
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto sc = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! sc) {
|
||||||
|
return Unexpected{ std::move(sc).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->value == TokenV::opComma) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
}
|
||||||
|
else if (sc->value != TokenV::opGt) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
sc->line,
|
||||||
|
sc->column,
|
||||||
|
toString(*sc),
|
||||||
|
"'}' or ','"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::StructMemberNode>>
|
||||||
|
Parser::parseStructMembersList() {
|
||||||
|
auto membersList = ast::Vector<ast::StructMemberNode>{};
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekToken->value != TokenV::opRSquirly) {
|
||||||
|
auto member = parseStructMember();
|
||||||
|
|
||||||
|
if (! member) {
|
||||||
|
return Unexpected{ std::move(member).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
membersList.push_back(std::move(member).value());
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return membersList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::StructMemberNode> Parser::parseStructMember() {
|
||||||
|
auto node = ast::MakeNode<ast::StructMemberNode>();
|
||||||
|
|
||||||
|
if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) {
|
||||||
|
return Unexpected{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = { .line = ident->line, .column = ident->column };
|
||||||
|
|
||||||
|
node->name = ident->strValue;
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
if (auto colon = tokenizer.peekExpect(0, TokenV::opColon); ! colon) {
|
||||||
|
return Unexpected{ std::move(colon).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto type = parseType();
|
||||||
|
|
||||||
|
if (! type) {
|
||||||
|
return Unexpected{ std::move(type).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->type = std::move(type).value();
|
||||||
|
|
||||||
|
auto sc = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! sc) {
|
||||||
|
return Unexpected{ std::move(sc).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->value == TokenV::opComma) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
}
|
||||||
|
else if (sc->value != TokenV::opRSquirly) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
sc->line,
|
||||||
|
sc->column,
|
||||||
|
toString(*sc),
|
||||||
|
"'}' or ','"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::EnumMemberNode>> Parser::parseEnumMembersList() {
|
||||||
|
auto membersList = ast::Vector<ast::EnumMemberNode>{};
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekToken->value != TokenV::opRSquirly) {
|
||||||
|
auto member = parseEnumMember();
|
||||||
|
|
||||||
|
if (! member) {
|
||||||
|
return Unexpected{ std::move(member).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
membersList.push_back(std::move(member).value());
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return membersList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::EnumMemberNode> Parser::parseEnumMember() {
|
||||||
|
auto node = ast::MakeNode<ast::EnumMemberNode>();
|
||||||
|
|
||||||
|
if (auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier); ! ident) {
|
||||||
|
return Unexpected{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = { .line = ident->line, .column = ident->column };
|
||||||
|
|
||||||
|
node->name = ident->strValue;
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto sc = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! sc) {
|
||||||
|
return Unexpected{ std::move(sc).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->value == TokenV::opLParen) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto type = parseType();
|
||||||
|
|
||||||
|
if (! type) {
|
||||||
|
return Unexpected{ std::move(type).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->type = std::move(type).value();
|
||||||
|
|
||||||
|
if (auto closeP = tokenizer.peekExpect(0, TokenV::opRParen); ! closeP) {
|
||||||
|
return Unexpected{ std::move(closeP).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
sc = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! sc) {
|
||||||
|
return Unexpected{ std::move(sc).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc->value == TokenV::opComma) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
}
|
||||||
|
else if (sc->value != TokenV::opRSquirly) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
sc->line,
|
||||||
|
sc->column,
|
||||||
|
toString(*sc),
|
||||||
|
"'}' or ','"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::FunctionDeclNode> Parser::parseFunctionDeclaration() {
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return langException<ExceptCode::ecUnimplemented>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arti::lang
|
||||||
0
lib/src/Parser/Expressions.cpp
Normal file
0
lib/src/Parser/Expressions.cpp
Normal file
0
lib/src/Parser/Literals.cpp
Normal file
0
lib/src/Parser/Literals.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang {
|
||||||
|
|
||||||
|
Parser::Parser(std::string source) noexcept
|
||||||
|
: unitName{}
|
||||||
|
, sourceCode{ source }
|
||||||
|
, tokenizer{ source } { }
|
||||||
|
|
||||||
|
Parser::Parser(std::string unitName, std::string source) noexcept
|
||||||
|
: unitName{ unitName }
|
||||||
|
, sourceCode{ source }
|
||||||
|
, tokenizer{ source } { }
|
||||||
|
|
||||||
|
Expected<ast::AST> Parser::parse() {
|
||||||
|
auto unit = ast::MakeNode<ast::AST>();
|
||||||
|
auto tlDecl = ast::Optional<ast::TopLevelDeclNode>{};
|
||||||
|
bool keepParsing = true;
|
||||||
|
|
||||||
|
unit->unitName = this->unitName;
|
||||||
|
|
||||||
|
while (keepParsing) {
|
||||||
|
if (auto ok = parseTopLevelDeclaration(); ok) {
|
||||||
|
tlDecl = std::move(ok).value();
|
||||||
|
|
||||||
|
if (! tlDecl.has_value()) {
|
||||||
|
keepParsing = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unit->declarations.push_back(std::move(tlDecl).value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Unexpected<>{ std::move(ok).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eof = tokenizer.peekExpect(0, TokenV::tkEOF);
|
||||||
|
|
||||||
|
if (! eof) {
|
||||||
|
return Unexpected<>{ std::move(eof).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arti::lang
|
||||||
0
lib/src/Parser/Statements.cpp
Normal file
0
lib/src/Parser/Statements.cpp
Normal file
299
lib/src/Parser/Types.cpp
Normal file
299
lib/src/Parser/Types.cpp
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#include <artichoke/Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace arti::lang {
|
||||||
|
|
||||||
|
Expected<ast::NamespacedIdentifierNode> Parser::parseNamespacedIdentifier() {
|
||||||
|
auto node = ast::MakeNode<ast::NamespacedIdentifierNode>();
|
||||||
|
|
||||||
|
auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier);
|
||||||
|
|
||||||
|
if (! ident) {
|
||||||
|
return Unexpected<>{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = { .line = ident->line, .column = ident->column };
|
||||||
|
|
||||||
|
node->identParts.emplace_back(ident->strValue);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekNext->value == TokenV::opAccess) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
ident = tokenizer.peekExpect(0, TokenV::tkIdentifier);
|
||||||
|
|
||||||
|
if (! ident) {
|
||||||
|
return Unexpected<>{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->identParts.emplace_back(ident->strValue);
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::TypeNode> Parser::parseType() {
|
||||||
|
auto node = ast::MakeNode<ast::TypeNode>();
|
||||||
|
|
||||||
|
if (auto peekNext = tokenizer.peek(); ! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node->location = { .line = peekNext->line, .column = peekNext->column };
|
||||||
|
|
||||||
|
if (peekNext->value != TokenV::tkIdentifier) {
|
||||||
|
auto qualifiers = parseTypeQualifiers();
|
||||||
|
|
||||||
|
if (! qualifiers) {
|
||||||
|
return Unexpected<>{ std::move(qualifiers).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
node->qualifiers = std::move(qualifiers).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto identType = parseNamespacedIdentifier();
|
||||||
|
|
||||||
|
if (! identType) {
|
||||||
|
return Unexpected<>{ std::move(identType).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
auto currentNode = ast::TypeExpressionNode{};
|
||||||
|
|
||||||
|
currentNode = ast::MakeNode<ast::IdentifierTypeNode>();
|
||||||
|
|
||||||
|
std::get<ast::IdentifierTypeNode>(currentNode)->location =
|
||||||
|
(*identType)->location;
|
||||||
|
|
||||||
|
std::get<ast::IdentifierTypeNode>(currentNode)->typeName =
|
||||||
|
std::move(identType).value();
|
||||||
|
|
||||||
|
auto peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value == TokenV::opLt) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto args = parseGenericArgumentsList();
|
||||||
|
|
||||||
|
if (! args) {
|
||||||
|
return Unexpected<>{ std::move(args).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) {
|
||||||
|
return Unexpected<>{ std::move(closeG).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto newNode = ast::MakeNode<ast::GenericTypeNode>();
|
||||||
|
|
||||||
|
newNode->location = std::visit(
|
||||||
|
[](const auto &node) { return node->location; },
|
||||||
|
currentNode
|
||||||
|
);
|
||||||
|
|
||||||
|
newNode->baseType = std::move(currentNode);
|
||||||
|
newNode->genericArgs = std::move(args).value();
|
||||||
|
currentNode = std::move(newNode);
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekNext->value == TokenV::opAccess) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto ident = tokenizer.peekExpect(0, TokenV::tkIdentifier);
|
||||||
|
|
||||||
|
if (! ident) {
|
||||||
|
return Unexpected<>{ std::move(ident).error() };
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto newNode = ast::MakeNode<ast::NamespacedTypeNode>();
|
||||||
|
|
||||||
|
newNode->location = std::visit(
|
||||||
|
[](const auto &node) { return node->location; },
|
||||||
|
currentNode
|
||||||
|
);
|
||||||
|
|
||||||
|
newNode->typeName = ident->strValue;
|
||||||
|
newNode->baseType = std::move(currentNode);
|
||||||
|
currentNode = std::move(newNode);
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekNext->value == TokenV::opLt) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto args = parseGenericArgumentsList();
|
||||||
|
|
||||||
|
if (! args) {
|
||||||
|
return Unexpected<>{ std::move(args).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto closeG = tokenizer.peekExpect(0, TokenV::opGt); ! closeG) {
|
||||||
|
return Unexpected<>{ std::move(closeG).error() };
|
||||||
|
}
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
auto newNode = ast::MakeNode<ast::GenericTypeNode>();
|
||||||
|
|
||||||
|
newNode->location = std::visit(
|
||||||
|
[](const auto &node) { return node->location; },
|
||||||
|
currentNode
|
||||||
|
);
|
||||||
|
|
||||||
|
newNode->baseType = std::move(currentNode);
|
||||||
|
newNode->genericArgs = std::move(args).value();
|
||||||
|
currentNode = std::move(newNode);
|
||||||
|
|
||||||
|
peekNext = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekNext) {
|
||||||
|
return Unexpected<>{ std::move(peekNext).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node->baseType = std::move(currentNode);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::TypeQualifier>> Parser::parseTypeQualifiers() {
|
||||||
|
auto qualifs = ast::Vector<ast::TypeQualifier>{};
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { None, AfterOptional, AfterMutable } state = None;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
switch (peekToken->value) {
|
||||||
|
using enum TokenV;
|
||||||
|
|
||||||
|
case opStar:
|
||||||
|
qualifs.push_back(ast::TypeQualifier::Pointer);
|
||||||
|
state = None;
|
||||||
|
break;
|
||||||
|
case opMut:
|
||||||
|
if (state == AfterMutable) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"non mutable type qualifier, i.e. any of ( *, ?, [] )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
qualifs.push_back(ast::TypeQualifier::Mutable);
|
||||||
|
state = AfterMutable;
|
||||||
|
break;
|
||||||
|
case opOpt:
|
||||||
|
if (state == AfterOptional) {
|
||||||
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
|
peekToken->line,
|
||||||
|
peekToken->column,
|
||||||
|
toString(*peekToken),
|
||||||
|
"non optional type qualifier, i.e. any of ( *, $, [] )"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
qualifs.push_back(ast::TypeQualifier::Optional);
|
||||||
|
state = AfterOptional;
|
||||||
|
break;
|
||||||
|
case opLBracket:
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekToken = tokenizer.peekExpect(0, opRBracket);
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
qualifs.push_back(ast::TypeQualifier::Slice);
|
||||||
|
state = None;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return qualifs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected<>{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return qualifs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<ast::Vector<ast::TypeNode>> Parser::parseGenericArgumentsList() {
|
||||||
|
auto args = ast::Vector<ast::TypeNode>{};
|
||||||
|
|
||||||
|
auto peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
while (peekToken->value != TokenV::opGt) {
|
||||||
|
auto type = parseType();
|
||||||
|
|
||||||
|
if (! type) {
|
||||||
|
return Unexpected<>{ std::move(type).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push_back(std::move(type).value());
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (peekToken->value == TokenV::opComma) {
|
||||||
|
std::ignore = tokenizer.consume();
|
||||||
|
|
||||||
|
peekToken = tokenizer.peek();
|
||||||
|
|
||||||
|
if (! peekToken) {
|
||||||
|
return Unexpected{ std::move(peekToken).error() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace arti::lang
|
||||||
@ -112,16 +112,12 @@ namespace arti::lang {
|
|||||||
auto tokenAt = tokensBuffer.at(n);
|
auto tokenAt = tokensBuffer.at(n);
|
||||||
|
|
||||||
if (tokenAt.value != tokenType) {
|
if (tokenAt.value != tokenType) {
|
||||||
return Unexpected<> {
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
Exception{
|
tokenAt.line,
|
||||||
.line = tokenAt.line,
|
tokenAt.column,
|
||||||
.column = tokenAt.column,
|
toString(tokenAt),
|
||||||
.message = std::format(
|
toString(tokenType)
|
||||||
"Expected token of type {}, got {}",
|
);
|
||||||
toString(tokenType), toString(tokenAt)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokenAt;
|
return tokenAt;
|
||||||
@ -147,16 +143,12 @@ namespace arti::lang {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token->value != tokenType) {
|
if (token->value != tokenType) {
|
||||||
return Unexpected<> {
|
return langException<ExceptCode::ecUnexpectedToken>(
|
||||||
Exception{
|
token->line,
|
||||||
.line = token->line,
|
token->column,
|
||||||
.column = token->column,
|
toString(*token),
|
||||||
.message = std::format(
|
toString(tokenType)
|
||||||
"Expected token of type {}, got {}",
|
);
|
||||||
toString(tokenType), toString(*token)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return *token;
|
return *token;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user