Skip to content

Commit

Permalink
parser: Read arbitrary member type arguments.
Browse files Browse the repository at this point in the history
  • Loading branch information
heinezen committed Oct 16, 2020
1 parent e017655 commit 05f74f6
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 36 deletions.
75 changes: 57 additions & 18 deletions nyan/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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} {}
Expand Down Expand Up @@ -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:
Expand Down
24 changes: 22 additions & 2 deletions nyan/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -65,8 +85,8 @@ class ASTMemberType : ASTBase {
bool does_exist;
IDToken name;

bool has_payload;
IDToken payload;
bool has_args;
std::vector<ASTMemberArgument> args;
};


Expand Down
19 changes: 3 additions & 16 deletions nyan/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Type>(
ast_type.payload,
ast_type.args.at(0).value,
scope,
ns,
type_info
Expand All @@ -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
Expand Down

0 comments on commit 05f74f6

Please sign in to comment.