Files
whetstone_DSL/editor/src/ast/Parser.h

172 lines
5.5 KiB
C++

#pragma once
#include "ASTNode.h"
#include "Module.h"
#include "Function.h"
#include "Variable.h"
#include "Parameter.h"
#include "Import.h"
#include "Statement.h"
#include "Expression.h"
#include "Type.h"
#include "Annotation.h"
#include "ClassDeclaration.h"
#include "GenericType.h"
#include "AsyncNodes.h"
#include "PreprocessorNodes.h"
#include "EnumNamespaceNodes.h"
#include <string>
#include <memory>
#include <vector>
#include <atomic>
#include <cstring>
#include <tree_sitter/api.h>
// Grammar language functions (defined in the grammar static libraries)
extern "C" {
const TSLanguage* tree_sitter_python();
const TSLanguage* tree_sitter_cpp();
const TSLanguage* tree_sitter_elisp();
const TSLanguage* tree_sitter_javascript();
const TSLanguage* tree_sitter_typescript();
const TSLanguage* tree_sitter_java();
const TSLanguage* tree_sitter_rust();
const TSLanguage* tree_sitter_go();
}
// Unique ID generator for AST nodes
class IdGenerator {
public:
static std::string next(const std::string& prefix = "node") {
static std::atomic<int> counter{0};
return prefix + "_" + std::to_string(counter.fetch_add(1));
}
};
// Diagnostic for parse errors
struct ParseDiagnostic {
int line;
int column;
std::string message;
std::string severity; // "error", "warning"
};
// Result type wrapping a module + diagnostics
struct ParseResult {
std::unique_ptr<Module> module;
std::vector<ParseDiagnostic> diagnostics;
bool hasErrors() const {
for (const auto& d : diagnostics) {
if (d.severity == "error") return true;
}
return false;
}
};
class TreeSitterParser {
private:
// ---------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------
static std::string nodeText(TSNode node, const std::string& source) {
uint32_t start = ts_node_start_byte(node);
uint32_t end = ts_node_end_byte(node);
if (start >= source.size() || end > source.size()) return "";
return source.substr(start, end - start);
}
static std::string nodeType(TSNode node) {
return ts_node_type(node);
}
static void applySpan(ASTNode* node, TSNode tsNode) {
if (!node || ts_node_is_null(tsNode)) return;
TSPoint start = ts_node_start_point(tsNode);
TSPoint end = ts_node_end_point(tsNode);
node->setSpan((int)start.row, (int)start.column, (int)end.row, (int)end.column);
}
static bool isNamed(TSNode node) {
return ts_node_is_named(node);
}
static TSNode childByFieldName(TSNode node, const char* field) {
return ts_node_child_by_field_name(node, field, (uint32_t)strlen(field));
}
// Walk all ERROR nodes in a tree and collect diagnostics
static void collectDiagnostics(TSNode node, const std::string& source,
std::vector<ParseDiagnostic>& diags) {
if (ts_node_is_null(node)) return;
std::string type = nodeType(node);
if (type == "ERROR" || ts_node_is_missing(node)) {
TSPoint start = ts_node_start_point(node);
ParseDiagnostic d;
d.line = (int)start.row + 1;
d.column = (int)start.column + 1;
d.severity = "error";
d.message = "Syntax error at line " + std::to_string(d.line) +
", column " + std::to_string(d.column);
diags.push_back(d);
}
uint32_t count = ts_node_child_count(node);
for (uint32_t i = 0; i < count; ++i) {
collectDiagnostics(ts_node_child(node, i), source, diags);
}
}
static TSNode findDescendantByType(TSNode node, const std::string& typeName) {
if (nodeType(node) == typeName) return node;
uint32_t count = ts_node_named_child_count(node);
for (uint32_t i = 0; i < count; ++i) {
TSNode child = ts_node_named_child(node, i);
TSNode found = findDescendantByType(child, typeName);
if (!ts_node_is_null(found)) return found;
}
return TSNode{};
}
static TSNode findDescendantByField(TSNode node, const std::string& fieldName) {
TSNode direct = childByFieldName(node, fieldName.c_str());
if (!ts_node_is_null(direct)) return direct;
uint32_t count = ts_node_named_child_count(node);
for (uint32_t i = 0; i < count; ++i) {
TSNode child = ts_node_named_child(node, i);
TSNode found = findDescendantByField(child, fieldName);
if (!ts_node_is_null(found)) return found;
}
return TSNode{};
}
static std::string trimPointerPrefix(const std::string& text) {
if (text.empty()) return text;
std::string out = text;
size_t pos = out.find('*');
if (pos != std::string::npos) {
out.erase(pos, 1);
}
return out;
}
// ---------------------------------------------------------------
public:
#include "ast/PythonParser.h"
#include "ast/CppParser.h"
#include "ast/ElispParser.h"
#include "ast/JavaScriptParser.h"
#include "ast/TypeScriptParser.h"
#include "ast/JavaParser.h"
#include "ast/RustParser.h"
#include "ast/GoParser.h"
private:
};
// Standalone parsers (not tree-sitter fragment includes)
#include "ast/KotlinParser.h"
#include "ast/CSharpParser.h"
#include "ast/FSharpParser.h"
#include "ast/CParser.h"
#include "ast/WatParser.h"
#include "ast/CommonLispParser.h"
#include "ast/SchemeParser.h"