From 05f74f65e1abf0c76e28739f89127da3cc426e30 Mon Sep 17 00:00:00 2001 From: heinezen Date: Fri, 16 Oct 2020 18:30:54 +0200 Subject: [PATCH] parser: Read arbitrary member type arguments. --- nyan/ast.cpp | 75 ++++++++++++++++++++++++++++++++++++++------------- nyan/ast.h | 24 +++++++++++++++-- nyan/type.cpp | 19 +++---------- 3 files changed, 82 insertions(+), 36 deletions(-) diff --git a/nyan/ast.cpp b/nyan/ast.cpp index d109db7..d9d0aff 100644 --- a/nyan/ast.cpp +++ b/nyan/ast.cpp @@ -502,33 +502,30 @@ ASTMember::ASTMember(const Token &name, ASTMemberType::ASTMemberType() : does_exist{false}, - has_payload{false} {} + has_args{false} {} ASTMemberType::ASTMemberType(const Token &name, TokenStream &tokens) : does_exist{true}, - has_payload{false} { + has_args{false} { this->name = IDToken{name, tokens}; - // now there may follow a type payload, e.g. set(payloadtype) + // now there may follow type arguments, e.g. set(arg, key=val) auto token = tokens.next(); if (token->type == token_type::LPAREN) { - token = tokens.next(); - if (token->type == token_type::ID) { - this->payload = IDToken{*token, tokens}; - this->has_payload = true; - } - else { - throw ASTError("expected type identifier, but got", *token); - } - - token = tokens.next(); - - if (token->type != token_type::RPAREN) { - throw ASTError("expected closing parens, but encountered", *token); + comma_list( + token_type::RPAREN, + tokens, + [this] (const Token & /*token*/, TokenStream &stream) { + stream.reinsert_last(); + this->args.emplace_back(stream); + } + ); + if (this->args.size() > 0) { + this->has_args = true; } } else { tokens.reinsert_last(); @@ -541,6 +538,36 @@ bool ASTMemberType::exists() const { } +ASTMemberArgument::ASTMemberArgument(TokenStream &tokens) + : + has_key{false} { + auto token = tokens.next(); + if (token->type != token_type::ID) { + throw ASTError("expected argument value or key, but got", *token); + } + + auto next_token = tokens.next(); + // check if the argument is keyed + if (next_token->type == token_type::OPERATOR) { + if (unlikely(op_from_token(*next_token) != nyan_op::ASSIGN)) { + throw ASTError("expected argument keyed assignment, but got", *token); + } + + this->has_key = true; + this->key = IDToken(*token, tokens); + + token = tokens.next(); + if (unlikely(token->type != token_type::ID)) { + throw ASTError("expected argument value, but got", *token); + } + } else { + tokens.reinsert_last(); + } + + this->value = IDToken{*token, tokens}; +} + + ASTMemberValue::ASTMemberValue() : does_exist{false} {} @@ -719,12 +746,24 @@ void ASTMember::strb(std::ostringstream &builder, int indentlevel) const { void ASTMemberType::strb(std::ostringstream &builder, int /*indentlevel*/) const { builder << this->name.str(); - if (this->has_payload) { - builder << "(" << this->payload.str() << ")"; + if (this->has_args) { + builder << "("; + for (auto &arg : this->args) { + arg.strb(builder); + } + builder << ")"; } } +void ASTMemberArgument::strb(std::ostringstream &builder, int /*indentlevel*/) const { + if (this->has_key) { + builder << this->key.str() << "="; + } + + builder << this->value.str(); +} + void ASTMemberValue::strb(std::ostringstream &builder, int /*indentlevel*/) const { switch (this->container_type) { case container_t::SINGLE: diff --git a/nyan/ast.h b/nyan/ast.h index 5e85fb4..cbde529 100644 --- a/nyan/ast.h +++ b/nyan/ast.h @@ -47,6 +47,26 @@ class ASTBase { }; +/** + * AST representation of a member type argument declaration. + */ +class ASTMemberArgument : public ASTBase { + friend class ASTMemberType; + friend class Database; + friend class Type; + +public: + ASTMemberArgument(TokenStream &tokens); + + void strb(std::ostringstream &builder, int indentlevel=0) const override; + +protected: + bool has_key; + IDToken key; + IDToken value; +}; + + /** * AST representation of a member type declaration. */ @@ -65,8 +85,8 @@ class ASTMemberType : ASTBase { bool does_exist; IDToken name; - bool has_payload; - IDToken payload; + bool has_args; + std::vector args; }; diff --git a/nyan/type.cpp b/nyan/type.cpp index f9c40ea..faa34ba 100644 --- a/nyan/type.cpp +++ b/nyan/type.cpp @@ -27,26 +27,21 @@ Type::Type(const ASTMemberType &ast_type, // test if the type is primitive (int, float, text, ...) if (this->basic_type.is_fundamental()) { - if (ast_type.has_payload) { - throw ASTError{ - "fundamental type can't have a type payload", - ast_type.payload, false - }; - } return; } // container type like set(something) if (this->basic_type.is_container()) { - if (not ast_type.has_payload) { + if (not ast_type.has_args) { throw ASTError{ "container content type not specified", ast_type.name, false }; } + // TODO: Element type is more complex for dicts this->element_type = std::make_unique( - ast_type.payload, + ast_type.args.at(0).value, scope, ns, type_info @@ -56,14 +51,6 @@ Type::Type(const ASTMemberType &ast_type, // here, type must be a OBJECT. - // type is not builtin, but has a payload - if (ast_type.has_payload) { - throw ASTError{ - "you can't assign a target to an object type", - ast_type.payload, false - }; - } - this->basic_type = { primitive_t::OBJECT, container_t::SINGLE