blob: c70902dd3cd06fb7edecfb2c59cb17262740a4d6 [file]
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// Minimal parser support for compiler unit tests.
//
// The Bison grammar (thrifty.yy) references a set of functions and globals that
// are normally provided by src/thrift/main.cc. The compiler unit tests build
// does not compile main.cc (it would conflict with the Catch2 main), but some
// tests still need to parse .thrift files.
//
// This file provides lightweight implementations sufficient for unit tests.
#include "thrift/globals.h"
#include "thrift/main.h"
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <string>
#include <vector>
// Provided by compiler/cpp/tests/thrift_test_globals.cc (not declared in public headers)
extern std::string g_curdir;
extern std::string g_curpath;
extern std::vector<std::string> g_incl_searchpath;
// Error reporting used by the parser.
void yyerror(const char* fmt, ...) {
std::fprintf(stderr, "[ERROR:%s:%d] ", g_curpath.c_str(), yylineno);
va_list args;
va_start(args, fmt);
std::vfprintf(stderr, fmt, args);
va_end(args);
std::fprintf(stderr, "\n");
throw std::runtime_error("thrift parser error");
}
// Simplified helpers referenced by the grammar.
std::string program_name(std::string filename) {
filename.erase(std::remove(filename.begin(), filename.end(), '\\'), filename.end());
std::string::size_type slash = filename.rfind('/');
if (slash != std::string::npos) {
filename = filename.substr(slash + 1);
}
std::string::size_type dot = filename.rfind('.');
if (dot != std::string::npos) {
filename = filename.substr(0, dot);
}
return filename;
}
std::string directory_name(std::string filename) {
std::replace(filename.begin(), filename.end(), '\\', '/');
std::string::size_type slash = filename.rfind('/');
if (slash == std::string::npos) {
return ".";
}
return filename.substr(0, slash);
}
std::string include_file(std::string filename) {
// Unit tests only parse fixtures without includes. Provide a best-effort
// resolution to satisfy the linker and any unexpected includes.
if (!filename.empty() && (filename[0] == '/' || filename.find(":/") != std::string::npos)) {
return filename;
}
// Search current dir first.
if (!g_curdir.empty()) {
return g_curdir + "/" + filename;
}
return filename;
}
void clear_doctext() {
if (g_doctext != nullptr) {
std::free(g_doctext);
g_doctext = nullptr;
}
}
char* clean_up_doctext(char* doctext) {
// Keep behavior minimal for unit tests.
return doctext;
}
void declare_valid_program_doctext() {
if ((g_program_doctext_candidate != nullptr) && (g_program_doctext_status == STILL_CANDIDATE)) {
g_program_doctext_status = ABSOLUTELY_SURE;
} else {
g_program_doctext_status = NO_PROGRAM_DOCTEXT;
}
}
void validate_simple_identifier(const char* identifier) {
if (identifier == nullptr) {
return;
}
const std::string name(identifier);
if (name.find('.') != std::string::npos) {
yyerror("Identifier %s can't have a dot.", identifier);
}
}
void validate_const_type(t_const* /*c*/) {
// Not needed for current unit tests.
}
void validate_field_value(t_field* /*field*/, t_const_value* /*cv*/) {
// Not needed for current unit tests.
}
bool validate_throws(t_struct* /*throws*/) {
return true;
}
void check_for_list_of_bytes(t_type* /*list_elem_type*/) {
// Not needed for current unit tests.
}
void emit_byte_type_warning() {
// Not needed for current unit tests.
}
void error_unsupported_namespace_decl(const char* old_form, const char* new_form) {
// Treat as fatal in unit tests.
if (new_form == nullptr) {
yyerror("Unsupported declaration '%s_namespace'", old_form);
} else {
yyerror("Unsupported declaration '%s'", old_form);
}
}