2022-05-27 06:18:17 +00:00
|
|
|
#include "comdel_parser.h"
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
#include "poly.h"
|
2022-05-27 06:18:17 +00:00
|
|
|
#include "tokens_type.h"
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
ComdelParser::ComdelParser(std::vector<Token> tokens)
|
2022-05-27 06:18:17 +00:00
|
|
|
: tokens(std::move(tokens)), position(0) {}
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
// Tries to consume a token, returns an error otherwise.
|
|
|
|
// Unlike the regular consume() call this should be used
|
|
|
|
// when a missing token means a syntax error.
|
|
|
|
#define RETURN_IF_NOT_TOKEN(tokenType) \
|
|
|
|
do { \
|
|
|
|
if (!consume(tokenType)) { \
|
|
|
|
return unexpected(); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
// Checks if the current token matches the argument.
|
|
|
|
// Otherwise, adds the token to the list of expected tokens (used in
|
|
|
|
// error message).
|
2022-05-27 06:18:17 +00:00
|
|
|
bool ComdelParser::check(TokenType tokenType) {
|
|
|
|
if (current().type == tokenType)
|
2022-03-29 19:31:45 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
expectedTokens.insert(tokenType);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Token &ComdelParser::current() {
|
|
|
|
return tokens[position];
|
|
|
|
}
|
|
|
|
|
|
|
|
// attempts to consume a token and returns whether it's successful
|
|
|
|
bool ComdelParser::consume(TokenType tokenType) {
|
|
|
|
bool exists = check(tokenType);
|
|
|
|
if (exists) {
|
|
|
|
bump();
|
|
|
|
}
|
|
|
|
return exists;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ATLAS_ASSERT_FAIL(x) \
|
|
|
|
do{}while(0)
|
|
|
|
|
|
|
|
void ComdelParser::bump() {
|
2022-06-05 17:02:44 +00:00
|
|
|
if (tokens[position].type != TokenType::END_OF_FILE) {
|
|
|
|
++position;
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-06-05 17:02:44 +00:00
|
|
|
ATLAS_ASSERT_FAIL("Internal parser error, called bump after EOF");
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
expectedTokens.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates an "unexpected token" error that also
|
|
|
|
// includes a list of valid alternatives based on the contents
|
|
|
|
// of the expectedTokens vector
|
|
|
|
//
|
|
|
|
// e.g. "expected one of: ',', ')', found 'c'"
|
|
|
|
// when parsing "func(a, b c);"
|
|
|
|
PError ComdelParser::unexpected() {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "Found: `" << current().text << "`. ";
|
|
|
|
|
|
|
|
ss << "Expected";
|
|
|
|
if (expectedTokens.size() > 1) {
|
|
|
|
ss << " one of: ";
|
|
|
|
} else {
|
|
|
|
ss << ": ";
|
|
|
|
}
|
|
|
|
uint token_counter = 0;
|
2022-05-27 06:18:17 +00:00
|
|
|
for (auto &type: expectedTokens) {
|
2022-03-29 19:31:45 +00:00
|
|
|
if (type == TokenType::IDENTIFIER ||
|
|
|
|
type == TokenType::NUMBER ||
|
|
|
|
type == TokenType::STRING ||
|
|
|
|
type == TokenType::COLOR) {
|
|
|
|
ss << tokenTypeToString(type);
|
|
|
|
} else {
|
|
|
|
ss << "`" << tokenTypeToString(type) << "`";
|
|
|
|
}
|
|
|
|
++token_counter;
|
|
|
|
if (token_counter < expectedTokens.size())
|
|
|
|
ss << ", ";
|
|
|
|
else
|
2022-05-27 06:18:17 +00:00
|
|
|
ss << ".";
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
return {{current().span, ss.str()}};
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parses a list of 'nodes' separated by 'separator'. Parsed nodes
|
|
|
|
// are returned in a vector. A list can be empty which will give
|
|
|
|
// an empty vector.
|
|
|
|
//
|
|
|
|
// The list is enclosed in 'openDelim' and 'closeDelim'.
|
|
|
|
//
|
|
|
|
// 'openDelim' and 'separator' are optional (could be nullopt).
|
|
|
|
//
|
2022-04-08 18:17:58 +00:00
|
|
|
// 'closeDelim' is mandatory, and it will be consumed.
|
2022-03-29 19:31:45 +00:00
|
|
|
//
|
2022-05-27 06:18:17 +00:00
|
|
|
// Function 'parse_f' should only parseLibrary a single node of type T.
|
2022-03-29 19:31:45 +00:00
|
|
|
//
|
2022-04-08 18:17:58 +00:00
|
|
|
// Parameter allowTrailing==true means that the list should end with
|
|
|
|
// 'separator' and otherwise the list should end with 'node'. This
|
2022-03-29 19:31:45 +00:00
|
|
|
// parameter is false in every call-site!
|
2022-05-27 06:18:17 +00:00
|
|
|
template<typename T>
|
|
|
|
PResult<std::vector<T>>
|
2022-03-29 19:31:45 +00:00
|
|
|
ComdelParser::parseList(std::optional<TokenType> openDelim,
|
|
|
|
TokenType closeDelim,
|
|
|
|
std::optional<TokenType> separator,
|
|
|
|
bool allowTrailing,
|
2022-05-27 06:18:17 +00:00
|
|
|
const std::function<PResult<T>()> &parse_f) {
|
2022-03-29 19:31:45 +00:00
|
|
|
std::vector<T> vec;
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (openDelim) {
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(*openDelim);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
while (true) {
|
|
|
|
if (consume(closeDelim)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!first && separator) {
|
|
|
|
RETURN_IF_NOT_TOKEN(*separator);
|
|
|
|
if (allowTrailing && consume(closeDelim)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
first = false;
|
|
|
|
auto item = parse_f();
|
|
|
|
RETURN_IF_ERR(item);
|
|
|
|
vec.push_back(*item);
|
|
|
|
}
|
|
|
|
|
2022-04-05 21:48:07 +00:00
|
|
|
return vec;
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2022-05-01 16:13:01 +00:00
|
|
|
void ComdelParser::skipUntilNextKeyword() {
|
|
|
|
int depth = 0;
|
|
|
|
bool enteredBlock = false;
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (true) {
|
|
|
|
if (is_keyword(current().type) && (!enteredBlock || (enteredBlock && depth == 0))) {
|
2022-05-01 16:13:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::LBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
enteredBlock = true;
|
|
|
|
depth++;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::RBRACE)) {
|
|
|
|
if (depth == 0) {
|
2022-05-01 16:13:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
depth--;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
bump();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
const std::vector<SourceError> &ComdelParser::getErrors() {
|
2022-03-29 19:31:45 +00:00
|
|
|
return errors;
|
|
|
|
}
|
|
|
|
|
|
|
|
Span &ComdelParser::getPreviousSpan() {
|
|
|
|
static Span span;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (position == 0) {
|
2022-03-29 19:31:45 +00:00
|
|
|
return span;
|
|
|
|
} else {
|
|
|
|
return tokens[position].span;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// See comment for Spanner
|
2022-05-27 06:18:17 +00:00
|
|
|
Spanner ComdelParser::getSpanner() {
|
|
|
|
return {current().span, getPreviousSpan()};
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// utility for reading strings
|
|
|
|
#define ASSIGN_OR_SET_ERR(var, presult) \
|
|
|
|
do { \
|
|
|
|
auto&& assign_or_return_if_err_temp_ = (presult); \
|
|
|
|
if (!assign_or_return_if_err_temp_) { \
|
|
|
|
err = PError(assign_or_return_if_err_temp_.error()); \
|
|
|
|
} else { \
|
2022-05-27 06:18:17 +00:00
|
|
|
(var) = *assign_or_return_if_err_temp_; \
|
2022-03-29 19:31:45 +00:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// utility for reading strings
|
|
|
|
#define APPEND_OR_SET_ERR(var, presult) \
|
|
|
|
do { \
|
|
|
|
auto&& assign_or_return_if_err_temp_ = (presult); \
|
|
|
|
if (!assign_or_return_if_err_temp_) { \
|
|
|
|
err = PError(assign_or_return_if_err_temp_.error()); \
|
|
|
|
} else { \
|
2022-05-27 06:18:17 +00:00
|
|
|
(var).push_back(*assign_or_return_if_err_temp_); \
|
2022-03-29 19:31:45 +00:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
// utility for reading strings
|
|
|
|
#define APPEND_OR_RETURN_IF_ERR(var, presult) \
|
|
|
|
do { \
|
|
|
|
auto&& assign_or_return_if_err_temp_ = (presult); \
|
|
|
|
if (!assign_or_return_if_err_temp_) { \
|
|
|
|
return PError(assign_or_return_if_err_temp_.error()); \
|
|
|
|
} else { \
|
2022-05-27 06:18:17 +00:00
|
|
|
(var).push_back(*assign_or_return_if_err_temp_); \
|
2022-03-29 19:31:45 +00:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* F U N C T I O N S O F R E C U R S I V E D E S C E N T P A R S E R
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
std::optional<LibraryNode> ComdelParser::parseLibrary() {
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
LibraryNode library{};
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::END_OF_FILE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_NAME)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-03-29 21:08:55 +00:00
|
|
|
ASSIGN_OR_SET_ERR(library.name, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_HEADER)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
|
|
|
ASSIGN_OR_SET_ERR(library.header, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_COMPONENT_HEADER)) {
|
2022-05-15 23:02:34 +00:00
|
|
|
bump();
|
|
|
|
ASSIGN_OR_SET_ERR(library.componentHeader, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_DIRECTORY)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
|
|
|
ASSIGN_OR_SET_ERR(library.componentDirectory, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_INFO)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
|
|
|
ASSIGN_OR_SET_ERR(library.libraryInfo, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_ADDRESS)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
APPEND_OR_SET_ERR(library.addressSpaces, parseAddress());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_COMPONENT)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
APPEND_OR_SET_ERR(library.components, parseComponent());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_BUS)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
APPEND_OR_SET_ERR(library.buses, parseBus());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_CONNECTION)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
APPEND_OR_SET_ERR(library.connections, parseConnection());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_MESSAGES)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-05-27 06:18:17 +00:00
|
|
|
ASSIGN_OR_SET_ERR(library.messages, parseList<PropertyNode>(TokenType::LBRACE,
|
|
|
|
TokenType::RBRACE,
|
|
|
|
std::nullopt,
|
|
|
|
false,
|
2022-06-12 14:02:24 +00:00
|
|
|
[this] { return parseProperty(TokenType::STRING);
|
2022-05-27 06:18:17 +00:00
|
|
|
}
|
|
|
|
));
|
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
skipUntilNextKeyword();
|
|
|
|
bump();
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
|
|
|
err = unexpected();
|
2022-05-01 16:13:01 +00:00
|
|
|
bump();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-03-29 19:31:45 +00:00
|
|
|
errors.push_back(err.error());
|
2022-05-01 16:13:01 +00:00
|
|
|
skipUntilNextKeyword();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!errors.empty())
|
2022-03-29 19:31:45 +00:00
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
return spanner(library);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* StringNode := "\"" + CONTENT + "\""
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<StringNode> ComdelParser::parseString() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
if (check(TokenType::STRING)) {
|
|
|
|
StringNode node;
|
|
|
|
node.value = current().text;
|
|
|
|
node.span = current().span;
|
|
|
|
bump();
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-06-12 14:02:24 +00:00
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* ColorNode := #RRGGBB[AA]
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
PResult<ColorNode> ComdelParser::parseColor() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
if (check(TokenType::COLOR)) {
|
|
|
|
ColorNode node{current().text};
|
|
|
|
node.span = current().span;
|
|
|
|
bump();
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* IdentifierNode := IDENTIFIER
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<IdentifierNode> ComdelParser::parseIdentifier() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
|
|
|
IdentifierNode node;
|
|
|
|
node.value = current().text;
|
|
|
|
node.span = current().span;
|
|
|
|
bump();
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* NumberNode := ('0x' | '0b'){0,1}[0-9]*
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<NumberNode> ComdelParser::parseNumber() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
if (check(TokenType::NUMBER)) {
|
|
|
|
NumberNode node{current().text};
|
|
|
|
node.span = current().span;
|
|
|
|
bump();
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* CountNode := "@size (" + NumberNode + "," + NumberNode + ")"
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<CountNode> ComdelParser::parseCount() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_COUNT);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
auto first = parseNumber();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!first.has_value()) {
|
2022-03-29 19:31:45 +00:00
|
|
|
return PError(first.error());
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
auto second = parseNumber();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!second.has_value()) {
|
2022-03-29 19:31:45 +00:00
|
|
|
return PError(second.error());
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
return spanner(CountNode{first.value(), second.value()});
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* PropertyNode := key: value;
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<PropertyNode> ComdelParser::parseProperty(std::optional<TokenType> valueType = std::nullopt) {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
IdentifierNode key;
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(key, parseIdentifier());
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COLON);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (valueType.has_value()) {
|
|
|
|
if (valueType == TokenType::BOOL_TYPE) {
|
|
|
|
if (!(check(TokenType::TRUE) || check(TokenType::FALSE))) {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (!check(*valueType)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
}
|
2022-03-31 21:20:41 +00:00
|
|
|
ValueNode value;
|
2022-03-29 21:08:55 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::SEMICOLON);
|
|
|
|
|
|
|
|
PropertyNode node;
|
|
|
|
node.key = key;
|
|
|
|
node.value = value;
|
|
|
|
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-04-08 18:17:58 +00:00
|
|
|
* AddressSpaceNode := "@address" + IDENTIFIER "(" + NUMBER + "," + NUMBER + ")"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<AddressSpaceNode> ComdelParser::parseAddress() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
AddressSpaceNode addressSpace{};
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_ADDRESS);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(addressSpace.name, parseIdentifier());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(addressSpace.start, parseNumber());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(addressSpace.end, parseNumber());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
return spanner(addressSpace);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* ComponentNode := "@component" + IDENTIFIER + ("processor" | "memory") { COMPONENT_BLOCK }
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<ComponentNode> ComdelParser::parseComponent() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
|
2022-03-29 21:49:32 +00:00
|
|
|
ComponentNode component{};
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_COMPONENT);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(component.name, parseIdentifier());
|
2022-05-15 21:55:03 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(component.type, parseComponentType());
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_INSTANCE_NAME)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-05-30 23:05:08 +00:00
|
|
|
ASSIGN_OR_SET_ERR(component.instanceName, parseIdentifier());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_TOOLTIP)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(component.tooltip, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_SOURCE)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(component.source, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_COUNT)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(component.count, parseCount());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_DISPLAY)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(component.display, parseDisplay());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_PIN)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(component.pins, parsePin());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_ATTRIBUTE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(component.attributes, parseAttribute());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_RULE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(component.rules, parseRule());
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(component);
|
|
|
|
}
|
|
|
|
|
2022-04-24 20:21:45 +00:00
|
|
|
PResult<EnumNode<ComponentNode::ComponentType>> ComdelParser::parseComponentType() {
|
|
|
|
EnumNode<ComponentNode::ComponentType> type;
|
|
|
|
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::CT_PROCESSOR)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
bump();
|
|
|
|
type = EnumNode(ComponentNode::PROCESSOR);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::CT_MEMORY)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
bump();
|
|
|
|
type = EnumNode(ComponentNode::MEMORY);
|
|
|
|
} else {
|
|
|
|
type = EnumNode(ComponentNode::OTHER);
|
|
|
|
}
|
|
|
|
return spanner(type);
|
|
|
|
}
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* DisplayNode := "@display {" + (DISPLAY_ITEM)* + "}"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<DisplayNode> ComdelParser::parseDisplay() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:08:55 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_DISPLAY);
|
2022-03-29 21:49:32 +00:00
|
|
|
DisplayNode display;
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<DisplayItemNode> item;
|
2022-03-29 19:31:45 +00:00
|
|
|
item = parseDisplayItem();
|
|
|
|
RETURN_IF_ERR(item);
|
|
|
|
display.items.push_back(*item);
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
return spanner(display);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* DisplayItemNode := "TYPE {(KEY + ":" + VALUE + ";")*}
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<DisplayItemNode> ComdelParser::parseDisplayItem() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
DisplayItemNode displayItem;
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(displayItem.type, parseIdentifier());
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
PResult<PropertyNode> item{parseProperty()};
|
|
|
|
RETURN_IF_ERR(item);
|
|
|
|
displayItem.values.push_back(*item);
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
return spanner(displayItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* BusNode := "@bus " + NAME + TYPE + "{" + POPUP + "}"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<BusNode> ComdelParser::parseBus() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
BusNode bus;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_BUS);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(bus.name, parseIdentifier());
|
2022-05-27 06:18:17 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(bus.type, parseBusType());
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_TOOLTIP)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-05-30 23:05:08 +00:00
|
|
|
ASSIGN_OR_SET_ERR(bus.tooltip, parseString());
|
|
|
|
} else if (check(TokenType::KW_INSTANCE_NAME)) {
|
|
|
|
bump();
|
|
|
|
ASSIGN_OR_SET_ERR(bus.instanceName, parseIdentifier());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_COUNT)) {
|
2022-05-30 23:05:08 +00:00
|
|
|
ASSIGN_OR_SET_ERR(bus.count, parseCount());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_DISPLAY)) {
|
2022-05-30 23:05:08 +00:00
|
|
|
ASSIGN_OR_SET_ERR(bus.display, parseDisplay());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_WIRES)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-05-30 23:05:08 +00:00
|
|
|
if(consume(TokenType::LBRACE)) {
|
|
|
|
while (check(TokenType::IDENTIFIER)) {
|
|
|
|
APPEND_OR_RETURN_IF_ERR(bus.wires, parseWire());
|
2022-03-29 21:08:55 +00:00
|
|
|
|
2022-05-30 23:05:08 +00:00
|
|
|
if (check(TokenType::COMMA)) {
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-30 23:05:08 +00:00
|
|
|
} else {
|
|
|
|
err = unexpected();
|
|
|
|
}
|
|
|
|
if(!consume(TokenType::RBRACE)) {
|
|
|
|
err = unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(bus);
|
|
|
|
}
|
|
|
|
|
2022-04-24 20:21:45 +00:00
|
|
|
PResult<EnumNode<BusNode::BusType>> ComdelParser::parseBusType() {
|
|
|
|
PResult<EnumNode<BusNode::BusType>> type;
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
auto tokenType = parseIdentifier();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (tokenType.value().value == "automatic") {
|
2022-04-24 20:21:45 +00:00
|
|
|
type = EnumNode(BusNode::AUTOMATIC);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (tokenType.value().value == "regular") {
|
2022-04-24 20:21:45 +00:00
|
|
|
type = EnumNode(BusNode::REGULAR);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (tokenType.value().value == "singleAutomatic") {
|
2022-05-08 12:50:56 +00:00
|
|
|
type = EnumNode(BusNode::SINGLE_AUTOMATIC);
|
2022-04-24 20:21:45 +00:00
|
|
|
} else {
|
2022-05-08 12:50:56 +00:00
|
|
|
type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"});
|
2022-04-24 20:21:45 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-05-08 12:50:56 +00:00
|
|
|
type = PError(SourceError{current().span, "expected 'automatic', 'singleAutomatic' or 'regular'"});
|
2022-04-24 20:21:45 +00:00
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-04-24 20:21:45 +00:00
|
|
|
* WireNode := NAME(<SIZE>){0,1} TYPE [hidden | terminated_with (#number | null)])*
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<WireNode> ComdelParser::parseWire() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
WireNode wire;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(wire.name, parseIdentifier());
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::LT)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LT);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(wire.size, parseNumber());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::GT);
|
|
|
|
} else {
|
|
|
|
wire.size.value = 1;
|
|
|
|
}
|
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
// default
|
2022-04-24 20:21:45 +00:00
|
|
|
wire.type = EnumNode(WireNode::WIRE);
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::WIRE_DEFAULT)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
wire.type = EnumNode(WireNode::WIRE);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::WIRE_AND)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
wire.type = EnumNode(WireNode::WIRED_AND);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::WIRE_OR)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
wire.type = EnumNode(WireNode::WIRED_OR);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::R_WIRE)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
wire.type = EnumNode(WireNode::R_WIRE);
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (true) {
|
|
|
|
if (check(TokenType::HIDDEN)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
bump();
|
|
|
|
wire.hidden = true;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::TERMINATE_WITH)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
bump();
|
|
|
|
wire.hasTerminateWith = true;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::NIL)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
bump();
|
|
|
|
wire.terminateWith = ValueNode::ofNull();
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NUMBER)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
auto number = parseNumber();
|
|
|
|
wire.terminateWith = ValueNode::ofInt(number->value);
|
|
|
|
} else {
|
|
|
|
auto token = current();
|
|
|
|
return PError(SourceError{token.span, "unexpected token"});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return spanner(wire);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* PinNode := "@pin" NAME TYPE "{"
|
2022-03-29 19:31:45 +00:00
|
|
|
"@tooltip" MESSAGE
|
|
|
|
"@connection" TYPE "(" MESSAGE ")"
|
2022-03-29 21:49:32 +00:00
|
|
|
DisplayNode
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<PinNode> ComdelParser::parsePin() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_PIN);
|
2022-03-29 21:49:32 +00:00
|
|
|
PinNode pin{};
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(pin.name, parseIdentifier());
|
2022-03-29 21:08:55 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::PIN_IN)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
pin.type = EnumNode(PinNode::IN);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::PIN_OUT)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
pin.type = EnumNode(PinNode::OUT);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::PIN_IN_OUT)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-04-24 20:21:45 +00:00
|
|
|
pin.type = EnumNode(PinNode::IN_OUT);
|
2022-03-29 21:08:55 +00:00
|
|
|
} else {
|
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-03-29 21:08:55 +00:00
|
|
|
if (check(TokenType::KW_TOOLTIP)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(pin.tooltip, parseString());
|
2022-03-29 21:08:55 +00:00
|
|
|
} else if (check(TokenType::KW_DISPLAY)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(pin.display, parseDisplay());
|
2022-03-29 21:08:55 +00:00
|
|
|
} else if (check(TokenType::KW_CONNECTION)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(pin.connection, parsePinConnection());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_WIRES)) {
|
2022-04-09 12:10:40 +00:00
|
|
|
bump();
|
2022-05-27 06:18:17 +00:00
|
|
|
auto wires = parseList<ValueNode>(TokenType::LBRACE,
|
|
|
|
TokenType::RBRACE,
|
|
|
|
TokenType::COMMA,
|
|
|
|
false,
|
2022-04-09 12:10:40 +00:00
|
|
|
[this] { return parseConnectionWire(); });
|
|
|
|
RETURN_IF_ERR(wires);
|
|
|
|
pin.wires = *wires;
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(pin);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* PinConnectionNode := "@connection " + ("check_only" | "automatically") + "(" + MESSAGE + ")"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<PinConnectionNode> ComdelParser::parsePinConnection() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
PinConnectionNode connection{};
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
|
|
|
|
|
2022-04-24 20:21:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.type, parseConnectionType());
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.message, parseString());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
return spanner(connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
PResult<EnumNode<PinConnectionNode::ConnectionType>> ComdelParser::parseConnectionType() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
|
|
|
|
EnumNode<PinConnectionNode::ConnectionType> type;
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
auto identifier = parseIdentifier();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (identifier.value().value == "required") {
|
2022-05-08 12:50:56 +00:00
|
|
|
type = EnumNode(PinConnectionNode::REQUIRED);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (identifier.value().value == "optional") {
|
2022-05-08 12:50:56 +00:00
|
|
|
type = EnumNode(PinConnectionNode::OPTIONAL);
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-05-08 12:50:56 +00:00
|
|
|
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-05-08 12:50:56 +00:00
|
|
|
return PError(SourceError{current().span, "expected connection type 'required' or 'optional'"});
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2022-04-24 20:21:45 +00:00
|
|
|
return spanner(type);
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-29 21:49:32 +00:00
|
|
|
* AttributeNode := "@attribute " + NAME + TYPE ("default" + VALUE){0,1} ("{" POPUP "}"){0,1}
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<AttributeNode> ComdelParser::parseAttribute() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
AttributeNode attribute;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(attribute.name, parseIdentifier());
|
|
|
|
} else {
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::INT_TYPE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.type = ValueNode::INT;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::STRING_TYPE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.type = ValueNode::STRING;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::BOOL_TYPE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.type = ValueNode::BOOL;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::WIRE_TYPE)) {
|
2022-04-05 21:48:07 +00:00
|
|
|
attribute.type = ValueNode::WIRE;
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
bump();
|
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::DEFAULT);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (attribute.type == ValueNode::BOOL) {
|
|
|
|
if (check(TokenType::TRUE)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofBool(true);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::FALSE)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofBool(false);
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (attribute.type == ValueNode::INT) {
|
|
|
|
if (check(TokenType::NUMBER)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto number = parseNumber();
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofInt(number->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (attribute.type == ValueNode::STRING) {
|
|
|
|
if (check(TokenType::STRING)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto string = parseString();
|
2022-04-05 21:48:07 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofString(string->asString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (attribute.type == ValueNode::IDENTIFIER) {
|
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto identifier = parseIdentifier();
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofIdentifier(identifier->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (attribute.type == ValueNode::MEMORY) {
|
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-05-15 21:55:03 +00:00
|
|
|
auto identifier = parseIdentifier();
|
|
|
|
attribute.defaultValue = ValueNode::ofMemory(identifier->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NIL)) {
|
2022-05-15 21:55:03 +00:00
|
|
|
bump();
|
|
|
|
attribute.defaultValue = ValueNode::ofMemory(std::nullopt);
|
|
|
|
} else {
|
|
|
|
return unexpected();
|
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (attribute.type == ValueNode::WIRE) {
|
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-04-05 21:48:07 +00:00
|
|
|
auto identifier = parseIdentifier();
|
|
|
|
attribute.defaultValue = ValueNode::ofWire(identifier->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NIL)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-05-15 21:55:03 +00:00
|
|
|
attribute.defaultValue = ValueNode::ofWire(std::nullopt);
|
2022-04-08 20:46:47 +00:00
|
|
|
} else {
|
2022-04-05 21:48:07 +00:00
|
|
|
return unexpected();
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::LBRACE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
2022-03-31 21:20:41 +00:00
|
|
|
PopupNode popup;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!check(TokenType::KW_POPUP)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(popup, parsePopup());
|
2022-03-31 21:20:41 +00:00
|
|
|
attribute.popup = std::optional<PopupNode>(popup);
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return spanner(attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* Enumeration
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
PResult<EnumerationNode> ComdelParser::parseEnumeration() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
StringNode key;
|
2022-03-29 21:08:55 +00:00
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(key, parseString());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::EQUALS);
|
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
ValueNode value;
|
2022-03-29 21:08:55 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(value, parseValue());
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
EnumerationNode node;
|
|
|
|
node.key = key;
|
|
|
|
node.value = value;
|
|
|
|
|
|
|
|
return spanner(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-31 21:20:41 +00:00
|
|
|
* PopupNode := "@popup " + ("automatic" | "on_demand") { POPUP BODY }
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<PopupNode> ComdelParser::parsePopup() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-31 21:20:41 +00:00
|
|
|
PopupNode popup;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_POPUP);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
auto identifier = parseIdentifier();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (identifier.value().value == "automatic") {
|
2022-04-24 20:21:45 +00:00
|
|
|
popup.type = EnumNode(PopupNode::AUTOMATIC);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (identifier.value().value == "on_demand") {
|
2022-04-24 20:21:45 +00:00
|
|
|
popup.type = EnumNode(PopupNode::ON_DEMAND);
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
|
|
|
return PError(SourceError{current().span, "expected type 'automatic', 'on_demand'"});
|
|
|
|
}
|
|
|
|
} else {
|
2022-04-24 20:21:45 +00:00
|
|
|
popup.type = EnumNode(PopupNode::ON_DEMAND);
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_TITLE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(popup.title, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_TEXT)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(popup.text, parseString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_RULE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(popup.rules, parseRule());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_ENUMERATED)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
|
|
|
popup.enumerated = true;
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(popup.enumeration,
|
2022-05-27 06:18:17 +00:00
|
|
|
parseList<EnumerationNode>(
|
|
|
|
TokenType::LBRACE,
|
2022-03-29 21:08:55 +00:00
|
|
|
TokenType::RBRACE,
|
2022-05-27 06:18:17 +00:00
|
|
|
TokenType::COMMA,
|
2022-03-29 21:08:55 +00:00
|
|
|
true,
|
2022-05-27 06:18:17 +00:00
|
|
|
[this] { return parseEnumeration(); }
|
|
|
|
)
|
2022-03-29 21:08:55 +00:00
|
|
|
);
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(popup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-05-08 12:50:56 +00:00
|
|
|
* ConnectionNode := "@connection (" + COMPONENT + "." + PIN + "," + BUS [ + "," + COMPONENT2 + "." + "PIN2"] + ") {" + CONNECTION + "}"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-29 21:49:32 +00:00
|
|
|
PResult<ConnectionNode> ComdelParser::parseConnection() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-29 21:49:32 +00:00
|
|
|
ConnectionNode connection;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
2022-04-09 17:44:02 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.first.component, parseIdentifier());
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::DOT);
|
2022-04-09 17:44:02 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier());
|
2022-04-09 17:44:02 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::COMMA)) {
|
2022-04-09 17:44:02 +00:00
|
|
|
auto conn = ConnectionComponentNode{};
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(conn.component, parseIdentifier());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::DOT);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(conn.pin, parseIdentifier());
|
|
|
|
connection.second = conn;
|
|
|
|
}
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-04-09 17:44:02 +00:00
|
|
|
int wireCount = 0;
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-03-29 21:08:55 +00:00
|
|
|
if (check(TokenType::KW_ATTRIBUTE)) {
|
|
|
|
APPEND_OR_RETURN_IF_ERR(connection.attributes, parseAttribute());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_WIRES)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
bump();
|
2022-04-09 17:44:02 +00:00
|
|
|
auto wires = parseList<ValueNode>(TokenType::LBRACE, TokenType::RBRACE, TokenType::COMMA, false,
|
2022-05-27 06:18:17 +00:00
|
|
|
[this] { return parseConnectionWire(); });
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_ERR(wires);
|
2022-05-27 06:18:17 +00:00
|
|
|
if (wireCount == 0) {
|
2022-04-09 17:44:02 +00:00
|
|
|
connection.firstWires = *wires;
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (wireCount == 1 && connection.second.has_value()) {
|
2022-04-09 17:44:02 +00:00
|
|
|
connection.secondWires = *wires;
|
|
|
|
} else {
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
wireCount++;
|
2022-03-29 19:31:45 +00:00
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(connection);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
2022-03-31 21:20:41 +00:00
|
|
|
* RuleNode := "@rule {" + if-else statements + "}"
|
2022-03-29 19:31:45 +00:00
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<RuleNode> ComdelParser::parseRule() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-31 21:20:41 +00:00
|
|
|
RuleNode rule;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_RULE);
|
|
|
|
|
2022-03-29 19:31:45 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
APPEND_OR_RETURN_IF_ERR(rule.statements, parseIfStatement());
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::RBRACE)) {
|
2022-03-29 21:08:55 +00:00
|
|
|
break;
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::ELSE);
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(rule);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* IfStatement := "if(!function(params...)) { error(MESSAGE) | warning(MESSAGE) }
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-04-08 18:17:58 +00:00
|
|
|
PResult<IfStatementNode> ComdelParser::parseIfStatement() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-04-08 18:17:58 +00:00
|
|
|
IfStatementNode ifStatement;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-29 21:08:55 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::IF);
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::NOT)) {
|
2022-03-29 19:31:45 +00:00
|
|
|
ifStatement.condition.negated = true;
|
|
|
|
bump();
|
|
|
|
} else {
|
|
|
|
ifStatement.condition.negated = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.functionName, parseIdentifier());
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(ifStatement.condition.params, parseList<ValueNode>(TokenType::LPAREN,
|
|
|
|
TokenType::RPAREN,
|
|
|
|
TokenType::COMMA,
|
|
|
|
false,
|
|
|
|
[this] { return parseValue(); }
|
|
|
|
));
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::ERROR)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
ifStatement.action.type = EnumNode(ActionNode::ERROR);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::WARNING)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
ifStatement.action.type = EnumNode(ActionNode::WARNING);
|
2022-03-29 21:08:55 +00:00
|
|
|
} else {
|
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
2022-03-29 21:08:55 +00:00
|
|
|
bump();
|
2022-03-29 19:31:45 +00:00
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(ifStatement.action.message, parseString());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
|
|
|
|
return spanner(ifStatement);
|
|
|
|
}
|
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<ValueNode> ComdelParser::parseValue() {
|
2022-03-29 19:31:45 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-03-31 21:20:41 +00:00
|
|
|
ValueNode value;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::IDENTIFIER)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
value = ValueNode::ofIdentifier(parseIdentifier()->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::STRING)) {
|
2022-04-05 21:48:07 +00:00
|
|
|
value = ValueNode::ofString(parseString()->asString());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NUMBER)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
value = ValueNode::ofInt(parseNumber()->value);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::TRUE)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-03-31 21:20:41 +00:00
|
|
|
value = ValueNode::ofBool(true);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::FALSE)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-03-31 21:20:41 +00:00
|
|
|
value = ValueNode::ofBool(false);
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NIL)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
|
|
|
value = ValueNode::ofNull();
|
2022-06-12 14:02:24 +00:00
|
|
|
} else if(check(TokenType::COLOR)) {
|
|
|
|
value = ValueNode::ofColor(parseColor()->color);
|
2022-03-29 21:08:55 +00:00
|
|
|
} else {
|
|
|
|
return unexpected();
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2022-04-12 21:37:05 +00:00
|
|
|
return spanner(value);
|
2022-03-29 19:31:45 +00:00
|
|
|
}
|
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
std::optional<SchemaNode> ComdelParser::parseSchema() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
SchemaNode schema{};
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_SOURCE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
bump();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::STRING)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
auto source = parseString();
|
|
|
|
schema.source = *source;
|
|
|
|
} else {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `@source`");
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
} else {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `@source`");
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!check(TokenType::KW_SCHEMA)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `@schema`");
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
bump();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!check(TokenType::LBRACE)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `{`");
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
bump();
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_INSTANCE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
APPEND_OR_SET_ERR(schema.instances, parseInstance());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_CONNECTION)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
APPEND_OR_SET_ERR(schema.connections, parseConnectionInstance());
|
|
|
|
} else {
|
|
|
|
err = unexpected();
|
2022-05-01 16:13:01 +00:00
|
|
|
bump();
|
2022-03-31 21:20:41 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-03-31 21:20:41 +00:00
|
|
|
errors.push_back(err.error());
|
2022-05-01 16:13:01 +00:00
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-07 16:28:31 +00:00
|
|
|
errors.emplace_back(current().span, "expected `}` reached EOF");
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
2022-03-31 21:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!check(TokenType::RBRACE)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `}`");
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
} else {
|
|
|
|
bump();
|
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!check(TokenType::END_OF_FILE)) {
|
2022-04-24 20:21:45 +00:00
|
|
|
errors.emplace_back(current().span, "expected `EOF`");
|
2022-03-31 21:20:41 +00:00
|
|
|
}
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!errors.empty())
|
2022-03-31 21:20:41 +00:00
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
return spanner(schema);
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
*
|
|
|
|
* CountNode := "@position (" + NumberNode + "," + NumberNode + ")"
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
2022-05-27 06:18:17 +00:00
|
|
|
PResult<CountNode> ComdelParser::parsePosition() {
|
2022-03-31 21:20:41 +00:00
|
|
|
auto spanner = getSpanner();
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_POSITION);
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
|
|
|
auto first = parseNumber();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!first.has_value()) {
|
2022-03-31 21:20:41 +00:00
|
|
|
return PError(first.error());
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
auto second = parseNumber();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!second.has_value()) {
|
2022-03-31 21:20:41 +00:00
|
|
|
return PError(second.error());
|
|
|
|
}
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
return spanner(CountNode{first.value(), second.value()});
|
|
|
|
}
|
|
|
|
|
|
|
|
PResult<InstanceNode> ComdelParser::parseInstance() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_INSTANCE);
|
|
|
|
|
|
|
|
InstanceNode instance;
|
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(instance.name, parseIdentifier());
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(instance.component, parseIdentifier());
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_POSITION)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
ASSIGN_OR_SET_ERR(instance.position, parsePosition());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_ATTRIBUTE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(instance.attributes, parseInstanceAttribute());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::KW_SIZE)) {
|
2022-03-31 21:20:41 +00:00
|
|
|
bump();
|
|
|
|
auto number = parseNumber();
|
|
|
|
RETURN_IF_ERR(number);
|
|
|
|
instance.size = *number;
|
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-08 12:50:56 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-31 21:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
return spanner(instance);
|
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<InstanceAttributeNode> ComdelParser::parseInstanceAttribute() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_ATTRIBUTE);
|
|
|
|
InstanceAttributeNode attribute;
|
|
|
|
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(attribute.name, parseIdentifier());
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(attribute.value, parseValue());
|
|
|
|
|
|
|
|
return spanner(attribute);
|
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
PResult<ConnectionInstanceNode> ComdelParser::parseConnectionInstance() {
|
|
|
|
auto spanner = getSpanner();
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::KW_CONNECTION);
|
|
|
|
|
|
|
|
ConnectionInstanceNode connection;
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LPAREN);
|
2022-04-09 17:44:02 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.first.instance, parseIdentifier());
|
2022-03-31 21:20:41 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::DOT);
|
2022-04-09 17:44:02 +00:00
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.first.pin, parseIdentifier());
|
2022-03-31 21:20:41 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::COMMA);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(connection.bus, parseIdentifier());
|
2022-04-09 17:44:02 +00:00
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::COMMA)) {
|
2022-04-09 17:44:02 +00:00
|
|
|
bump();
|
|
|
|
ConnectionComponentInstance second;
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(second.instance, parseIdentifier());
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::DOT);
|
|
|
|
ASSIGN_OR_RETURN_IF_ERR(second.pin, parseIdentifier());
|
|
|
|
connection.second = second;
|
|
|
|
}
|
|
|
|
|
2022-03-31 21:20:41 +00:00
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RPAREN);
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::LBRACE);
|
|
|
|
|
2022-05-27 06:18:17 +00:00
|
|
|
while (!check(TokenType::RBRACE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
PResult<poly<AstNode>> err;
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::KW_ATTRIBUTE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
APPEND_OR_SET_ERR(connection.attributes, parseInstanceAttribute());
|
2022-03-31 21:20:41 +00:00
|
|
|
} else {
|
2022-05-01 16:13:01 +00:00
|
|
|
err = unexpected();
|
2022-05-07 16:28:31 +00:00
|
|
|
bump();
|
2022-05-01 16:13:01 +00:00
|
|
|
}
|
2022-05-27 06:18:17 +00:00
|
|
|
if (!err.has_value()) {
|
2022-05-01 16:13:01 +00:00
|
|
|
errors.push_back(err.error());
|
|
|
|
skipUntilNextKeyword();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::END_OF_FILE)) {
|
2022-05-01 16:13:01 +00:00
|
|
|
return PError({Span(spanner.lo), "Reached EOF"});
|
|
|
|
}
|
2022-03-31 21:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_IF_NOT_TOKEN(TokenType::RBRACE);
|
|
|
|
|
|
|
|
return spanner(connection);
|
|
|
|
}
|
2022-03-29 19:31:45 +00:00
|
|
|
|
2022-04-08 20:46:47 +00:00
|
|
|
PResult<ValueNode> ComdelParser::parseConnectionWire() {
|
2022-05-08 12:50:56 +00:00
|
|
|
auto spanner = getSpanner();
|
2022-05-27 06:18:17 +00:00
|
|
|
if (check(TokenType::NUMBER)) {
|
2022-05-08 12:50:56 +00:00
|
|
|
return spanner(ValueNode::ofInt(parseNumber()->value));
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::NIL)) {
|
2022-04-08 20:46:47 +00:00
|
|
|
bump();
|
2022-05-08 12:50:56 +00:00
|
|
|
return spanner(ValueNode::ofNull());
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::STRING)) {
|
2022-06-05 17:02:44 +00:00
|
|
|
return spanner(ValueNode::ofString(parseString()->asString()));
|
2022-05-27 06:18:17 +00:00
|
|
|
} else if (check(TokenType::IDENTIFIER)) {
|
2022-05-08 12:50:56 +00:00
|
|
|
return spanner(ValueNode::ofIdentifier(parseIdentifier()->value));
|
2022-04-08 20:46:47 +00:00
|
|
|
} else {
|
|
|
|
return unexpected();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|