Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/examples/enum.wtx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

type E = enum {
val_1,
val_2,
}

let main = func() i32 {
type E2 = enum {
foo,
bar
}
}
106 changes: 66 additions & 40 deletions src/frontend/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Winter {
boolNode,
caseNode,
callNode,
enumNode,
exprNode,
forNode,
funcNode,
Expand All @@ -32,18 +33,63 @@ namespace Winter {
returnNode,
strLitNode,
switchNode,
typeNode,
varNode,

error
};
} // namespace Winter

template <>
struct std::formatter<Winter::NodeType> {
constexpr auto parse(std::format_parse_context& ctx) {
auto it = ctx.begin();
if (it != ctx.end() && *it != '}') {
throw std::format_error("Invalid format specifier for NodeType");
}
return it;
}

auto format(Winter::NodeType node, std::format_context& ctx) const {
switch (node) {
case Winter::NodeType::aliasNode: return std::format_to(ctx.out(), "aliasNode");
case Winter::NodeType::typeAlias: return std::format_to(ctx.out(), "typeAlias");
case Winter::NodeType::funcAlias: return std::format_to(ctx.out(), "funcAlias");
case Winter::NodeType::argNode: return std::format_to(ctx.out(), "argNode");
case Winter::NodeType::bodyNode: return std::format_to(ctx.out(), "bodyNode");
case Winter::NodeType::boolNode: return std::format_to(ctx.out(), "boolNode");
case Winter::NodeType::caseNode: return std::format_to(ctx.out(), "caseNode");
case Winter::NodeType::callNode: return std::format_to(ctx.out(), "callNode");
case Winter::NodeType::enumNode: return std::format_to(ctx.out(), "enumNode");
case Winter::NodeType::exprNode: return std::format_to(ctx.out(), "exprNode");
case Winter::NodeType::funcNode: return std::format_to(ctx.out(), "funcNode");
case Winter::NodeType::forNode: return std::format_to(ctx.out(), "forNode");
case Winter::NodeType::identNode: return std::format_to(ctx.out(), "identNode");
case Winter::NodeType::ifNode: return std::format_to(ctx.out(), "ifNode");
case Winter::NodeType::modNode: return std::format_to(ctx.out(), "modNode");
case Winter::NodeType::letNode: return std::format_to(ctx.out(), "letNode");
case Winter::NodeType::numlitNode: return std::format_to(ctx.out(), "numlitNode");
case Winter::NodeType::paramNode: return std::format_to(ctx.out(), "paramNode");
case Winter::NodeType::returnNode: return std::format_to(ctx.out(), "returnNode");
case Winter::NodeType::strLitNode: return std::format_to(ctx.out(), "strLitNode");
case Winter::NodeType::switchNode: return std::format_to(ctx.out(), "switchNode");
case Winter::NodeType::typeNode: return std::format_to(ctx.out(), "typeNode");
case Winter::NodeType::varNode: return std::format_to(ctx.out(), "varNode");
case Winter::NodeType::error: return std::format_to(ctx.out(), "error");
}
return std::format_to(ctx.out(), "");
}
};

namespace Winter {
struct aliasNode;
struct typeAlias;
struct funcAlias;
struct argNode;
struct boolNode;
struct bodyNode;
struct caseNode;
struct enumNode;
struct exprNode;
struct forNode;
struct funcNode;
Expand All @@ -57,6 +103,7 @@ namespace Winter {
struct returnNode;
struct strLitNode;
struct switchNode;
struct typeNode;
struct varNode;

struct TOMBSTONE {
Expand Down Expand Up @@ -90,6 +137,7 @@ namespace Winter {
bodyNode,
boolNode,
caseNode,
enumNode,
exprNode,
forNode,
funcCallNode,
Expand All @@ -103,6 +151,7 @@ namespace Winter {
returnNode,
strLitNode,
switchNode,
typeNode,
varNode,
TOMBSTONE>;

Expand Down Expand Up @@ -178,6 +227,14 @@ namespace Winter {
}
};

struct enumNode {
int count;

[[nodiscard]] std::string display() const {
return std::format("EnumNode[ count:{} ]", count);
}
};

struct exprNode {
int childCount;
std::optional<TokenType> op;
Expand Down Expand Up @@ -285,7 +342,15 @@ namespace Winter {

[[nodiscard]] std::string display() const {
return std::format(
"SwitchNode[ ident:{}, cases:{}, defaultCase:{}]", ident, caseCount, defaultCase);
"SwitchNode[ ident:{}, cases:{}, defaultCase:{} ]", ident, caseCount, defaultCase);
}
};

struct typeNode {
NodeType child;

[[nodiscard]] std::string display() const {
return std::format("typeNode[ child:{} ]", child);
}
};

Expand All @@ -304,43 +369,4 @@ namespace Winter {

} // namespace Winter

template <>
struct std::formatter<Winter::NodeType> {
constexpr auto parse(std::format_parse_context& ctx) {
auto it = ctx.begin();
if (it != ctx.end() && *it != '}') {
throw std::format_error("Invalid format specifier for NodeType");
}
return it;
}

auto format(Winter::NodeType node, std::format_context& ctx) const {
switch (node) {
case Winter::NodeType::aliasNode: return std::format_to(ctx.out(), "aliasNode");
case Winter::NodeType::typeAlias: return std::format_to(ctx.out(), "typeAlias");
case Winter::NodeType::funcAlias: return std::format_to(ctx.out(), "funcAlias");
case Winter::NodeType::argNode: return std::format_to(ctx.out(), "argNode");
case Winter::NodeType::bodyNode: return std::format_to(ctx.out(), "bodyNode");
case Winter::NodeType::boolNode: return std::format_to(ctx.out(), "boolNode");
case Winter::NodeType::caseNode: return std::format_to(ctx.out(), "caseNode");
case Winter::NodeType::callNode: return std::format_to(ctx.out(), "callNode");
case Winter::NodeType::exprNode: return std::format_to(ctx.out(), "exprNode");
case Winter::NodeType::funcNode: return std::format_to(ctx.out(), "funcNode");
case Winter::NodeType::forNode: return std::format_to(ctx.out(), "forNode");
case Winter::NodeType::identNode: return std::format_to(ctx.out(), "identNode");
case Winter::NodeType::ifNode: return std::format_to(ctx.out(), "ifNode");
case Winter::NodeType::modNode: return std::format_to(ctx.out(), "modNode");
case Winter::NodeType::letNode: return std::format_to(ctx.out(), "letNode");
case Winter::NodeType::numlitNode: return std::format_to(ctx.out(), "numlitNode");
case Winter::NodeType::paramNode: return std::format_to(ctx.out(), "paramNode");
case Winter::NodeType::returnNode: return std::format_to(ctx.out(), "returnNode");
case Winter::NodeType::strLitNode: return std::format_to(ctx.out(), "strLitNode");
case Winter::NodeType::switchNode: return std::format_to(ctx.out(), "switchNode");
case Winter::NodeType::varNode: return std::format_to(ctx.out(), "varNode");
case Winter::NodeType::error: return std::format_to(ctx.out(), "error");
}
return std::format_to(ctx.out(), "");
}
};

#endif // WINTER_AST_H
3 changes: 3 additions & 0 deletions src/frontend/lexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ namespace Winter {
kw_case,
kw_class,
kw_default,
kw_enum,
kw_else,
kw_fallthrough,
kw_false,
Expand Down Expand Up @@ -111,6 +112,7 @@ namespace Winter {
{"case"sv, TokenType::kw_case},
{"class"sv, TokenType::kw_class},
{"default"sv, TokenType::kw_default},
{"enum"sv, TokenType::kw_enum},
{"else"sv, TokenType::kw_else},
{"fallthrough"sv, TokenType::kw_fallthrough},
{"false"sv, TokenType::kw_false},
Expand Down Expand Up @@ -194,6 +196,7 @@ struct std::formatter<Winter::TokenType> {
case Winter::TokenType::kw_case: return std::format_to(ctx.out(), "kw_case");
case Winter::TokenType::kw_class: return std::format_to(ctx.out(), "kw_class");
case Winter::TokenType::kw_default: return std::format_to(ctx.out(), "kw_default");
case Winter::TokenType::kw_enum: return std::format_to(ctx.out(), "kw_enum");
case Winter::TokenType::kw_else: return std::format_to(ctx.out(), "kw_else");
case Winter::TokenType::kw_fallthrough:
return std::format_to(ctx.out(), "kw_fallthrough");
Expand Down
115 changes: 80 additions & 35 deletions src/frontend/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,45 +118,41 @@ namespace Winter {

std::vector<Node> children = {};
while (!check(TokenType::rbrace)) {
Node_Result maybe_return =
std::unexpected(Error(ErrType::Parser, "Token not known in body"));

if (check(TokenType::kw_return)) {
Node_Result maybe_return = parseReturn();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseReturn();

} else if (check(TokenType::ident)) {
Node_Result maybe_return = parseCallOrVariable();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseCallOrVariable();

} else if (check(TokenType::kw_if)) {
Node_Result maybe_return = parseIf();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseIf();

} else if (check(TokenType::kw_let)) {
Node_Result maybe_return = parseLet(false);
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
consume(); // consume ';'
continue;

} else if (check(TokenType::kw_for)) {
Node_Result maybe_return = parseFor();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseFor();

} else if (check(TokenType::kw_const)) {
Node_Result maybe_return = parseConst();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseConst();

} else if (check(TokenType::kw_switch)) {
Node_Result maybe_return = parseSwitch();
if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
maybe_return = parseSwitch();

} else {
return std::unexpected(Error(ErrType::Parser, "Token not known in body"));
} else if (check(TokenType::kw_type)) {
maybe_return = parseType();
consume(); // consume final rbrace
}

if (!maybe_return.has_value()) { return std::unexpected(maybe_return.error()); }
children.push_back(maybe_return.value());
}

consume(); // consume '}'
Expand Down Expand Up @@ -220,6 +216,29 @@ namespace Winter {
}
}

[[nodiscard]] Node_Result Parser::parseEnum() noexcept {
if (!check({TokenType::kw_enum})) {
return std::unexpected(Error(ErrType::Parser, "Unexpected token: expected kw_enum"));
}

if (!consume({TokenType::lbrace})) {
return std::unexpected(Error(ErrType::Parser, "Unexpected token: expected lbrace"));
}
consume();

std::vector<Node> idents = {};
while (!check(TokenType::rbrace)) {
std::string ident = current.toString(&L);
idents.push_back(Node(NodeType::identNode, identNode(ident)));
consume();

if (check(TokenType::comma)) { consume(); }
if (!check(TokenType::ident)) { break; }
}

return Node(NodeType::enumNode, enumNode(static_cast<int>(idents.size())), idents);
}

[[nodiscard]] Node_Result Parser::parseExpr(std::size_t min_bp) noexcept {
Node lhs = Node::tombstone();
switch (current.type) {
Expand Down Expand Up @@ -622,6 +641,34 @@ namespace Winter {
cases);
}

[[nodiscard]] Node_Result Parser::parseType() noexcept {
if (!check(TokenType::kw_type)) {
return std::unexpected(Error(ErrType::Parser, "Unexpected token: expected kw_type"));
}
consume();

const std::string name = current.toString(&L);
if (!consume({TokenType::op_equal})) {
return std::unexpected(Error(ErrType::Parser, "Unexpected token: No type body found"));
}
consume();

Node_Result body = Node::tombstone();
NodeType childType;

switch (current.type) {
case TokenType::kw_enum:
body = parseEnum();
childType = NodeType::enumNode;
break;
default: return std::unexpected(Error(ErrType::Parser, "Unexpected type found"));
}

if (!body.has_value()) { return std::unexpected(body.error()); }

return Node(NodeType::typeNode, typeNode(childType), {body.value()});
}

[[nodiscard]] Node_Result Parser::parseVariable() noexcept {
return std::unexpected(Error(ErrType::NotImplemented, "parseVariable"));
}
Expand All @@ -631,26 +678,24 @@ namespace Winter {

consume(); // start
while (!check(TokenType::eof)) {
Node_Result expected = std::unexpected(
Error(ErrType::Parser, "Unexpected token found. Expected top-level keyword"));

if (current.type == TokenType::kw_let) {
Node_Result expected = parseLet(false);
if (!expected.has_value()) { return std::unexpected(expected.error()); }
code.push_back(expected.value());
expected = parseLet(false);
} else if (current.type == TokenType::kw_mod) {
Node_Result expected = parseMod();
if (!expected.has_value()) { return std::unexpected(expected.error()); }
code.push_back(expected.value());
expected = parseMod();
} else if (current.type == TokenType::kw_const) {
Node_Result expected = parseConst();
if (!expected.has_value()) { return std::unexpected(expected.error()); }
code.push_back(expected.value());
expected = parseConst();
} else if (current.type == TokenType::kw_alias) {
Node_Result expected = parseAlias();
if (!expected.has_value()) { return std::unexpected(expected.error()); }
code.push_back(expected.value());
} else {
return std::unexpected(
Error(ErrType::Parser, "Unexpected token found. Expected top-level keyword"));
expected = parseAlias();
} else if (current.type == TokenType::kw_type) {
expected = parseType();
consume();
}

if (!expected.has_value()) { return std::unexpected(expected.error()); }
code.push_back(expected.value());
}

return code;
Expand Down
2 changes: 2 additions & 0 deletions src/frontend/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ namespace Winter {
[[nodiscard]] Node_Result parseCallOrVariable() noexcept;
[[nodiscard]] Node_Result parseCase() noexcept;
[[nodiscard]] Node_Result parseConst() noexcept;
[[nodiscard]] Node_Result parseEnum() noexcept;
[[nodiscard]] Node_Result parseExpr(std::size_t) noexcept;
[[nodiscard]] Node_Result parseFor() noexcept;
[[nodiscard]] Node_Result parseFunc() noexcept;
Expand All @@ -68,6 +69,7 @@ namespace Winter {
[[nodiscard]] Node_Result parseReturn() noexcept;
[[nodiscard]] Node_Result parseStrLit() noexcept;
[[nodiscard]] Node_Result parseSwitch() noexcept;
[[nodiscard]] Node_Result parseType() noexcept;
[[nodiscard]] Node_Result parseVariable() noexcept;

[[nodiscard]] std::expected<std::vector<Node>, Error> operator()();
Expand Down
Loading
Loading