update test file
This commit is contained in:
parent
6be3662226
commit
117f8e878e
|
|
@ -0,0 +1,99 @@
|
|||
cmake_minimum_required(VERSION 4.0)
|
||||
|
||||
project(test_ast)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
message(STATUS "CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}")
|
||||
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
|
||||
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if (DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
message(STATUS ">>> CMAKE_TOOLCHAIN_FILE: ${CMAKE_TOOLCHAIN_FILE}")
|
||||
endif()
|
||||
if (DEFINED VCPKG_TARGET_TRIPLET)
|
||||
message(STATUS ">>> VCPKG_TARGET_TRIPLET: ${VCPKG_TARGET_TRIPLET}")
|
||||
endif()
|
||||
|
||||
# 设置默认构建类型
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE
|
||||
"Release"
|
||||
CACHE STRING "Build type" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
|
||||
"MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# MinGW/MSYS2 静态链接
|
||||
if(MINGW)
|
||||
add_link_options(-static -static-libgcc -static-libstdc++)
|
||||
elseif(UNIX AND NOT APPLE) # Linux 静态链接
|
||||
add_link_options(-static-libgcc -static-libstdc++)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib" ".dll.a")
|
||||
else()
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
|
||||
endif()
|
||||
|
||||
find_package(glaze CONFIG REQUIRED)
|
||||
find_package(spdlog CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
find_package(Taskflow REQUIRED)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
find_package(unofficial-tree-sitter CONFIG REQUIRED)
|
||||
set(TREESITTER_TARGET unofficial::tree-sitter::tree-sitter)
|
||||
else()
|
||||
# find_package(PkgConfig REQUIRED)
|
||||
# pkg_check_modules(TREESITTER tree-sitter)
|
||||
find_library(TREESITTER_LIBRARY tree-sitter) # use ${TREESITTER_LIBRARY}
|
||||
set(TREESITTER_TARGET ${TREESITTER_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(NOT TARGET spdlog::spdlog_header_only)
|
||||
message(WARNING "spdlog header-only target not found, using shared library")
|
||||
endif()
|
||||
if(NOT TARGET fmt::fmt-header-only)
|
||||
message(WARNING "fmt header-only target not found, using shared library")
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(SOURCES
|
||||
./test.cpp
|
||||
./debug_printer.cpp
|
||||
../../src/language/ast/deserializer.cpp
|
||||
../../src/language/ast/detail.cpp
|
||||
../../src/language/ast/tree_sitter_utils.cpp
|
||||
../../src/utils/string.cpp
|
||||
../../src/tree-sitter/parser.c)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE src)
|
||||
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE SPDLOG_HEADER_ONLY
|
||||
FMT_HEADER_ONLY)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
glaze::glaze
|
||||
Taskflow::Taskflow
|
||||
spdlog::spdlog_header_only
|
||||
fmt::fmt-header-only
|
||||
${TREESITTER_TARGET} # 使用变量,避免条件判断
|
||||
$<$<PLATFORM_ID:Linux>:Threads::Threads> # 使用生成器表达式
|
||||
)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||
-Wall -Wextra -Wpedantic
|
||||
$<$<CONFIG:Debug>:-g -O0>
|
||||
$<$<CONFIG:Release>:-O3>
|
||||
)
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,100 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "../../src/language/ast/types.hpp"
|
||||
#include "../../src/language/ast/deserializer.hpp"
|
||||
|
||||
namespace lsp::language::ast
|
||||
{
|
||||
class DebugPrinter : public ASTVisitor
|
||||
{
|
||||
public:
|
||||
explicit DebugPrinter(std::ostream& os = std::cout, int indent_size = 2) :
|
||||
os_(os), indent_size_(indent_size), current_indent_(0) {}
|
||||
|
||||
void Print(const ASTNode* node);
|
||||
void PrintStatements(const std::vector<StatementPtr>& statements);
|
||||
void PrintParseResult(const ParseResult& result);
|
||||
|
||||
void VisitUnitDefinition(UnitDefinition& node) override;
|
||||
void VisitClassDefinition(ClassDefinition& node) override;
|
||||
void VisitClassMember(ClassMember& node) override;
|
||||
void VisitMethodDeclaration(MethodDeclaration& node) override;
|
||||
void VisitPropertyDeclaration(PropertyDeclaration& node) override;
|
||||
void VisitExternalMethodDefinition(ExternalMethodDefinition& node) override;
|
||||
void VisitIdentifier(Identifier& node) override;
|
||||
void VisitLiteral(Literal& node) override;
|
||||
void VisitBinaryExpression(BinaryExpression& node) override;
|
||||
void VisitComparisonExpression(ComparisonExpression& node) override;
|
||||
void VisitUnaryExpression(UnaryExpression& node) override;
|
||||
void VisitTernaryExpression(TernaryExpression& node) override;
|
||||
void VisitCallExpression(CallExpression& node) override;
|
||||
void VisitAttributeExpression(AttributeExpression& node) override;
|
||||
void VisitSubscriptExpression(SubscriptExpression& node) override;
|
||||
void VisitArrayExpression(ArrayExpression& node) override;
|
||||
void VisitAnonymousFunctionExpression(AnonymousFunctionExpression& node) override;
|
||||
void VisitPrefixIncrementExpression(PrefixIncrementExpression& node) override;
|
||||
void VisitPrefixDecrementExpression(PrefixDecrementExpression& node) override;
|
||||
void VisitPostfixIncrementExpression(PostfixIncrementExpression& node) override;
|
||||
void VisitPostfixDecrementExpression(PostfixDecrementExpression& node) override;
|
||||
void VisitFunctionPointerExpression(FunctionPointerExpression& node) override;
|
||||
void VisitAssignmentExpression(AssignmentExpression& node) override;
|
||||
void VisitExpressionStatement(ExpressionStatement& node) override;
|
||||
void VisitVarStatement(VarStatement& node) override;
|
||||
void VisitStaticStatement(StaticStatement& node) override;
|
||||
void VisitGlobalStatement(GlobalStatement& node) override;
|
||||
void VisitConstStatement(ConstStatement& node) override;
|
||||
void VisitAssignmentStatement(AssignmentStatement& node) override;
|
||||
void VisitBlockStatement(BlockStatement& node) override;
|
||||
void VisitIfStatement(IfStatement& node) override;
|
||||
void VisitForInStatement(ForInStatement& node) override;
|
||||
void VisitForToStatement(ForToStatement& node) override;
|
||||
void VisitWhileStatement(WhileStatement& node) override;
|
||||
void VisitRepeatStatement(RepeatStatement& node) override;
|
||||
void VisitCaseStatement(CaseStatement& node) override;
|
||||
void VisitTryStatement(TryStatement& node) override;
|
||||
void VisitBreakStatement(BreakStatement& node) override;
|
||||
void VisitContinueStatement(ContinueStatement& node) override;
|
||||
void VisitReturnStatement(ReturnStatement& node) override;
|
||||
void VisitUsesStatement(UsesStatement& node) override;
|
||||
void VisitFunctionDefinition(FunctionDefinition& node) override;
|
||||
void VisitFunctionDeclaration(FunctionDeclaration& node) override;
|
||||
void VisitVarDeclaration(VarDeclaration& node) override;
|
||||
void VisitStaticDeclaration(StaticDeclaration& node) override;
|
||||
void VisitGlobalDeclaration(GlobalDeclaration& node) override;
|
||||
void VisitFieldDeclaration(FieldDeclaration& node) override;
|
||||
void VisitUnpackPattern(UnpackPattern& node) override;
|
||||
void VisitTSSQLExpression(TSSQLExpression& node) override;
|
||||
|
||||
private:
|
||||
std::ostream& os_;
|
||||
int indent_size_;
|
||||
int current_indent_;
|
||||
|
||||
void IncreaseIndent() { current_indent_ += indent_size_; }
|
||||
void DecreaseIndent() { current_indent_ -= indent_size_; }
|
||||
void PrintIndent();
|
||||
std::string GetIndent() const;
|
||||
|
||||
void PrintLocation(const Location& loc);
|
||||
void PrintNodeHeader(const std::string& type_name, const Location& loc);
|
||||
void PrintExpression(const Expression* expr);
|
||||
void PrintSignature(const Signature& sig);
|
||||
void PrintParameter(const Parameter& param);
|
||||
void PrintLeftHandSide(const LeftHandSide& lhs);
|
||||
void PrintOperator(BinaryOperator op);
|
||||
void PrintOperator(UnaryOperator op);
|
||||
void PrintOperator(AssignmentOperator op);
|
||||
void PrintLiteralKind(LiteralKind kind);
|
||||
void PrintAccessModifier(AccessModifier modifier);
|
||||
void PrintMethodModifier(MethodModifier modifier);
|
||||
void PrintReferenceModifier(ReferenceModifier modifier);
|
||||
void PrintError(const ParseError& error);
|
||||
};
|
||||
|
||||
std::string DebugString(const ASTNode* node);
|
||||
std::string DebugString(const ParseResult& result);
|
||||
void DebugPrint(const ASTNode* node);
|
||||
void DebugPrint(const ParseResult& result);
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <tree_sitter/api.h>
|
||||
}
|
||||
|
||||
extern "C" const TSLanguage* tree_sitter_tsf(void);
|
||||
|
||||
#include "../../src/language/ast/deserializer.hpp"
|
||||
#include "./debug_printer.hpp"
|
||||
|
||||
using namespace lsp::language::ast;
|
||||
|
||||
// ==================== 文件读取 ====================
|
||||
|
||||
std::string ReadFile(const std::string& filepath)
|
||||
{
|
||||
std::ifstream file(filepath);
|
||||
if (!file.is_open())
|
||||
{
|
||||
throw std::runtime_error("Cannot open file: " + filepath);
|
||||
}
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << file.rdbuf();
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
// ==================== Tree-Sitter 解析 ====================
|
||||
|
||||
class TreeSitterParser
|
||||
{
|
||||
public:
|
||||
TreeSitterParser()
|
||||
{
|
||||
parser_ = ts_parser_new();
|
||||
if (!parser_)
|
||||
{
|
||||
throw std::runtime_error("Failed to create parser");
|
||||
}
|
||||
|
||||
// 设置语言
|
||||
if (!ts_parser_set_language(parser_, tree_sitter_tsf()))
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
throw std::runtime_error("Failed to set language");
|
||||
}
|
||||
}
|
||||
|
||||
~TreeSitterParser()
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
}
|
||||
if (parser_)
|
||||
{
|
||||
ts_parser_delete(parser_);
|
||||
}
|
||||
}
|
||||
|
||||
TSTree* Parse(const std::string& source)
|
||||
{
|
||||
if (tree_)
|
||||
{
|
||||
ts_tree_delete(tree_);
|
||||
tree_ = nullptr;
|
||||
}
|
||||
|
||||
tree_ = ts_parser_parse_string(
|
||||
parser_,
|
||||
nullptr,
|
||||
source.c_str(),
|
||||
source.length());
|
||||
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse source");
|
||||
}
|
||||
|
||||
return tree_;
|
||||
}
|
||||
|
||||
TSNode GetRootNode()
|
||||
{
|
||||
if (!tree_)
|
||||
{
|
||||
throw std::runtime_error("No tree available");
|
||||
}
|
||||
return ts_tree_root_node(tree_);
|
||||
}
|
||||
|
||||
private:
|
||||
TSParser* parser_ = nullptr;
|
||||
TSTree* tree_ = nullptr;
|
||||
};
|
||||
|
||||
// ==================== 主程序 ====================
|
||||
|
||||
void PrintUsage(const char* program_name)
|
||||
{
|
||||
std::cout << "Usage: " << program_name << " <file_path> [options]\n";
|
||||
std::cout << "\nOptions:\n";
|
||||
std::cout << " -v, --verbose Print verbose output\n";
|
||||
std::cout << " -i, --incremental Test incremental parsing\n";
|
||||
std::cout << " -h, --help Show this help message\n";
|
||||
std::cout << "\nExample:\n";
|
||||
std::cout << " " << program_name << " test.tsf\n";
|
||||
std::cout << " " << program_name << " test.tsf -v -s\n";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
PrintUsage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string filepath;
|
||||
bool verbose = false;
|
||||
bool test_incremental = false;
|
||||
|
||||
// 解析命令行参数
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::string arg = argv[i];
|
||||
if (arg == "-h" || arg == "--help")
|
||||
{
|
||||
PrintUsage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
else if (arg == "-v" || arg == "--verbose")
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
else if (arg == "-i" || arg == "--incremental")
|
||||
{
|
||||
test_incremental = true;
|
||||
}
|
||||
else if (filepath.empty())
|
||||
{
|
||||
filepath = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown argument: " << arg << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 读取文件
|
||||
std::cout << "Reading file: " << filepath << "\n";
|
||||
std::string source = ReadFile(filepath);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
std::cout << "File size: " << source.length() << " bytes\n";
|
||||
std::cout << "----------------------------------------\n";
|
||||
std::cout << source << "\n";
|
||||
std::cout << "----------------------------------------\n\n";
|
||||
}
|
||||
|
||||
// 创建 Tree-Sitter 解析器
|
||||
std::cout << "Parsing with Tree-Sitter...\n";
|
||||
TreeSitterParser ts_parser;
|
||||
TSTree* tree = ts_parser.Parse(source);
|
||||
TSNode root = ts_parser.GetRootNode();
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
std::cout << "Root node type: " << ts_node_type(root) << "\n";
|
||||
std::cout << "Root node child count: " << ts_node_child_count(root) << "\n\n";
|
||||
}
|
||||
|
||||
// 创建 AST 反序列化器
|
||||
Deserializer deserializer;
|
||||
|
||||
ParseResult result;
|
||||
|
||||
if (test_incremental)
|
||||
{
|
||||
std::cout << "Using incremental parsing...\n";
|
||||
auto inc_result = deserializer.ParseIncremental(root, source);
|
||||
result = std::move(inc_result.result);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Using full parsing...\n";
|
||||
result = deserializer.Parse(root, source);
|
||||
}
|
||||
|
||||
// 打印解析结果
|
||||
std::cout << "\n";
|
||||
DebugPrint(result);
|
||||
|
||||
// 打印摘要
|
||||
std::cout << "\n========================================\n";
|
||||
std::cout << "Summary:\n";
|
||||
std::cout << " File: " << filepath << "\n";
|
||||
std::cout << " Size: " << source.length() << " bytes\n";
|
||||
std::cout << " AST Nodes: " << result.statements.size() << "\n";
|
||||
std::cout << " Errors: " << result.errors.size() << "\n";
|
||||
|
||||
if (result.HasErrors())
|
||||
{
|
||||
std::cout << " Status: FAILED (with errors)\n";
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << " Status: SUCCESS\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
var d, e: boolean;
|
||||
global c, d;
|
||||
static e, f;
|
||||
const a: boolean = false;
|
||||
|
||||
var a, b: boolean := true;
|
||||
static d := "abc";
|
||||
global c := 123456;
|
||||
// e := f1();
|
||||
|
||||
// function f1(a: string; b: boolean = true): integer;
|
||||
// begin
|
||||
// end;
|
||||
|
||||
// function f2(a, b, c);overload;
|
||||
// begin
|
||||
// end;
|
||||
|
||||
// var d := 1;
|
||||
// c := false;
|
||||
// f := fa();
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include <iostream>
|
||||
#include <vector>
|
||||
#include "../src/protocol/protocol.hpp"
|
||||
#include "../src/protocol/transform/facade.hpp"
|
||||
#include "../../src/protocol/protocol.hpp"
|
||||
#include "../../src/protocol/transform/facade.hpp"
|
||||
|
||||
using namespace lsp::protocol;
|
||||
using namespace lsp;
|
||||
|
|
@ -12,7 +12,8 @@ void print_json(const string& name, const T& obj)
|
|||
if (auto result = glz::write_json(obj); result)
|
||||
{
|
||||
std::cout << name << " = " << *result << std::endl;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: " << result.error() << "\n";
|
||||
}
|
||||
|
|
@ -39,10 +40,10 @@ void test_basic_conversion()
|
|||
RequestMessage restored = transform::As<RequestMessage>(any);
|
||||
std::cout << "Restored method: " << restored.method << std::endl;
|
||||
std::cout << "id = ";
|
||||
std::visit([](const auto& value)
|
||||
{
|
||||
std::visit([](const auto& value) {
|
||||
std::cout << value;
|
||||
}, restored.id);
|
||||
},
|
||||
restored.id);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
|
|
@ -78,10 +79,10 @@ void test_json_string()
|
|||
std::cout << "jsonrpc = " << request.jsonrpc << std::endl;
|
||||
std::cout << "method = " << request.method << std::endl;
|
||||
std::cout << "id = ";
|
||||
std::visit([](const auto& value)
|
||||
{
|
||||
std::visit([](const auto& value) {
|
||||
std::cout << value;
|
||||
}, request.id);
|
||||
},
|
||||
request.id);
|
||||
std::cout << std::endl;
|
||||
|
||||
auto result = glz::write_json(request.params);
|
||||
|
|
@ -100,8 +101,7 @@ void test_json_string()
|
|||
void test_basic_types()
|
||||
{
|
||||
std::cout << "\n=== Test basic_types.hpp ===" << std::endl;
|
||||
Range range =
|
||||
{
|
||||
Range range = {
|
||||
.start = { 1, 3 },
|
||||
.end = { 2, 4 }
|
||||
};
|
||||
|
|
@ -117,25 +117,21 @@ void test_basic_types()
|
|||
ate.newText = "text_edit";
|
||||
ate.annotationId = "id";
|
||||
|
||||
Location location =
|
||||
{
|
||||
Location location = {
|
||||
.uri = "location_uri",
|
||||
.range = { .start = { 1, 3 }, .end = { 2, 4 } }
|
||||
};
|
||||
|
||||
Command command1 =
|
||||
{
|
||||
Command command1 = {
|
||||
.title = "command_title",
|
||||
.command = "command_command",
|
||||
};
|
||||
Command command2 =
|
||||
{
|
||||
Command command2 = {
|
||||
.title = "command_title",
|
||||
.command = "command_command",
|
||||
.arguments = "any_string"
|
||||
};
|
||||
Command command3 =
|
||||
{
|
||||
Command command3 = {
|
||||
.title = "command_title",
|
||||
.command = "command_command",
|
||||
.arguments = 123
|
||||
|
|
@ -155,15 +151,13 @@ void test_basic_types()
|
|||
{ "data", array_val },
|
||||
{ "metadata", nullptr }
|
||||
};
|
||||
Command command4 =
|
||||
{
|
||||
Command command4 = {
|
||||
.title = "command_title",
|
||||
.command = "command_command",
|
||||
.arguments = object
|
||||
};
|
||||
|
||||
MarkdownClientCapabilities mkcp =
|
||||
{
|
||||
MarkdownClientCapabilities mkcp = {
|
||||
.parser = "parse",
|
||||
.allowedTags = std::vector<string>{ "h1", "h2", "p", "code", "pre" }
|
||||
};
|
||||
|
|
@ -238,21 +232,25 @@ void test_RequestMessage_serialize()
|
|||
RequestMessage request;
|
||||
auto error = glz::read_json(request, json);
|
||||
|
||||
if (error) {
|
||||
if (error)
|
||||
{
|
||||
std::cerr << "Failed to parse JSON: " << glz::format_error(error, json) << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "jsonrpc: " << request.jsonrpc << std::endl;
|
||||
std::cout << "method: " << request.method << std::endl;
|
||||
std::visit([](const auto& id)
|
||||
{
|
||||
std::visit([](const auto& id) {
|
||||
using T = std::decay_t<decltype(id)>;
|
||||
if constexpr (std::is_same_v<T, lsp::protocol::string>) {
|
||||
if constexpr (std::is_same_v<T, lsp::protocol::string>)
|
||||
{
|
||||
std::cout << "ID (string): " << id << std::endl;
|
||||
} else if constexpr (std::is_same_v<T, lsp::protocol::integer>) {
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, lsp::protocol::integer>)
|
||||
{
|
||||
std::cout << "ID (integer): " << id << std::endl;
|
||||
}
|
||||
}, request.id);
|
||||
},
|
||||
request.id);
|
||||
|
||||
auto completionParams = transform::As<CompletionParams>(request.params.value());
|
||||
std::cout << "URI: " << completionParams.textDocument.uri << std::endl;
|
||||
|
|
@ -277,7 +275,7 @@ void test_message()
|
|||
result.serverInfo.version = "1.0.0";
|
||||
TextDocumentSyncOptions opts;
|
||||
opts.openClose = true;
|
||||
opts.change = TextDocumentSyncKind::kIncremental;
|
||||
opts.change = TextDocumentSyncKind::Incremental;
|
||||
result.capabilities.textDocumentSync = opts;
|
||||
|
||||
CompletionParams comparams;
|
||||
|
|
@ -285,7 +283,7 @@ void test_message()
|
|||
comparams.position.character = 12;
|
||||
comparams.position.line = 22;
|
||||
comparams.context = CompletionContext{
|
||||
.triggerKind = CompletionTriggerKind::kInvoked,
|
||||
.triggerKind = CompletionTriggerKind::Invoked,
|
||||
.triggerCharacter = std::nullopt
|
||||
};
|
||||
RequestMessage rm;
|
||||
|
|
@ -24,173 +24,227 @@ using LSPAnyVariant = std::variant<
|
|||
string,
|
||||
decimal, // 放在前面,优先匹配数字
|
||||
boolean,
|
||||
std::nullptr_t
|
||||
>;
|
||||
std::nullptr_t>;
|
||||
|
||||
struct LSPAny {
|
||||
struct LSPAny
|
||||
{
|
||||
LSPAnyVariant value;
|
||||
|
||||
// 默认构造函数
|
||||
LSPAny() : value(nullptr) {}
|
||||
LSPAny() :
|
||||
value(nullptr) {}
|
||||
|
||||
// 拷贝和移动构造函数
|
||||
LSPAny(const LSPAny& other) : value(other.value) {}
|
||||
LSPAny(LSPAny&& other) noexcept : value(std::move(other.value)) {}
|
||||
LSPAny(const LSPAny& other) :
|
||||
value(other.value) {}
|
||||
LSPAny(LSPAny&& other) noexcept :
|
||||
value(std::move(other.value)) {}
|
||||
|
||||
// 针对每种支持的类型的构造函数
|
||||
LSPAny(const std::map<string, LSPAny>& val) : value(val) {}
|
||||
LSPAny(std::map<string, LSPAny>&& val) : value(std::move(val)) {}
|
||||
LSPAny(const std::map<string, LSPAny>& val) :
|
||||
value(val) {}
|
||||
LSPAny(std::map<string, LSPAny>&& val) :
|
||||
value(std::move(val)) {}
|
||||
|
||||
LSPAny(const std::vector<LSPAny>& val) : value(val) {}
|
||||
LSPAny(std::vector<LSPAny>&& val) : value(std::move(val)) {}
|
||||
LSPAny(const std::vector<LSPAny>& val) :
|
||||
value(val) {}
|
||||
LSPAny(std::vector<LSPAny>&& val) :
|
||||
value(std::move(val)) {}
|
||||
|
||||
LSPAny(const string& val) : value(val) {}
|
||||
LSPAny(string&& val) : value(std::move(val)) {}
|
||||
LSPAny(const char* val) : value(string(val)) {}
|
||||
LSPAny(const string& val) :
|
||||
value(val) {}
|
||||
LSPAny(string&& val) :
|
||||
value(std::move(val)) {}
|
||||
LSPAny(const char* val) :
|
||||
value(string(val)) {}
|
||||
|
||||
// 所有数字类型都转换为 decimal
|
||||
LSPAny(int val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(long val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(long long val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned int val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned long val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned long long val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(float val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(double val) : value(val) {}
|
||||
LSPAny(long double val) : value(static_cast<decimal>(val)) {}
|
||||
LSPAny(int val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(long val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(long long val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned int val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned long val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(unsigned long long val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(float val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
LSPAny(double val) :
|
||||
value(val) {}
|
||||
LSPAny(long double val) :
|
||||
value(static_cast<decimal>(val)) {}
|
||||
|
||||
LSPAny(boolean val) : value(val) {}
|
||||
LSPAny(std::nullptr_t) : value(nullptr) {}
|
||||
LSPAny(boolean val) :
|
||||
value(val) {}
|
||||
LSPAny(std::nullptr_t) :
|
||||
value(nullptr) {}
|
||||
|
||||
// 赋值操作符
|
||||
LSPAny& operator=(const LSPAny& other) {
|
||||
LSPAny& operator=(const LSPAny& other)
|
||||
{
|
||||
value = other.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(LSPAny&& other) noexcept {
|
||||
LSPAny& operator=(LSPAny&& other) noexcept
|
||||
{
|
||||
value = std::move(other.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 针对每种支持的类型的赋值操作符
|
||||
LSPAny& operator=(const std::map<string, LSPAny>& val) {
|
||||
LSPAny& operator=(const std::map<string, LSPAny>& val)
|
||||
{
|
||||
value = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(std::map<string, LSPAny>&& val) {
|
||||
LSPAny& operator=(std::map<string, LSPAny>&& val)
|
||||
{
|
||||
value = std::move(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(const std::vector<LSPAny>& val) {
|
||||
LSPAny& operator=(const std::vector<LSPAny>& val)
|
||||
{
|
||||
value = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(std::vector<LSPAny>&& val) {
|
||||
LSPAny& operator=(std::vector<LSPAny>&& val)
|
||||
{
|
||||
value = std::move(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(const string& val) {
|
||||
LSPAny& operator=(const string& val)
|
||||
{
|
||||
value = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(string&& val) {
|
||||
LSPAny& operator=(string&& val)
|
||||
{
|
||||
value = std::move(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(const char* val) {
|
||||
LSPAny& operator=(const char* val)
|
||||
{
|
||||
value = string(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 所有数字类型都转换为 decimal
|
||||
LSPAny& operator=(int val) {
|
||||
LSPAny& operator=(int val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(long val) {
|
||||
LSPAny& operator=(long val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(long long val) {
|
||||
LSPAny& operator=(long long val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(unsigned int val) {
|
||||
LSPAny& operator=(unsigned int val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(unsigned long val) {
|
||||
LSPAny& operator=(unsigned long val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(unsigned long long val) {
|
||||
LSPAny& operator=(unsigned long long val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(float val) {
|
||||
LSPAny& operator=(float val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(double val) {
|
||||
LSPAny& operator=(double val)
|
||||
{
|
||||
value = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(long double val) {
|
||||
LSPAny& operator=(long double val)
|
||||
{
|
||||
value = static_cast<decimal>(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(boolean val) {
|
||||
LSPAny& operator=(boolean val)
|
||||
{
|
||||
value = val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LSPAny& operator=(std::nullptr_t) {
|
||||
LSPAny& operator=(std::nullptr_t)
|
||||
{
|
||||
value = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 类型检查辅助函数
|
||||
template<typename T>
|
||||
bool is() const { return std::holds_alternative<T>(value); }
|
||||
bool is() const
|
||||
{
|
||||
return std::holds_alternative<T>(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& get() { return std::get<T>(value); }
|
||||
T& get()
|
||||
{
|
||||
return std::get<T>(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T& get() const { return std::get<T>(value); }
|
||||
const T& get() const
|
||||
{
|
||||
return std::get<T>(value);
|
||||
}
|
||||
|
||||
// 访问操作符
|
||||
template<typename Visitor>
|
||||
auto visit(Visitor&& visitor) const {
|
||||
auto visit(Visitor&& visitor) const
|
||||
{
|
||||
return std::visit(std::forward<Visitor>(visitor), value);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
auto visit(Visitor&& visitor) {
|
||||
auto visit(Visitor&& visitor)
|
||||
{
|
||||
return std::visit(std::forward<Visitor>(visitor), value);
|
||||
}
|
||||
};
|
||||
|
||||
// glaze 自动支持 std::variant,无需额外配置
|
||||
namespace glz {
|
||||
namespace glz
|
||||
{
|
||||
template<>
|
||||
struct meta<LSPAny> {
|
||||
struct meta<LSPAny>
|
||||
{
|
||||
using T = LSPAny;
|
||||
static constexpr auto value = &T::value;
|
||||
};
|
||||
|
|
@ -199,68 +253,83 @@ namespace glz {
|
|||
// ===== 简单清晰的转换模板 =====
|
||||
|
||||
// 转换工具类
|
||||
struct LSPConvert {
|
||||
struct LSPConvert
|
||||
{
|
||||
// === 基本类型的转换(优先级最高) ===
|
||||
|
||||
// boolean
|
||||
static LSPAny ToLSPAny(boolean value) {
|
||||
static LSPAny ToLSPAny(boolean value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
// 整数类型
|
||||
static LSPAny ToLSPAny(int value) {
|
||||
static LSPAny ToLSPAny(int value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(long value) {
|
||||
static LSPAny ToLSPAny(long value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(long long value) {
|
||||
static LSPAny ToLSPAny(long long value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(unsigned int value) {
|
||||
static LSPAny ToLSPAny(unsigned int value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(unsigned long value) {
|
||||
static LSPAny ToLSPAny(unsigned long value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(unsigned long long value) {
|
||||
static LSPAny ToLSPAny(unsigned long long value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
// 浮点类型
|
||||
static LSPAny ToLSPAny(float value) {
|
||||
static LSPAny ToLSPAny(float value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(double value) {
|
||||
static LSPAny ToLSPAny(double value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(long double value) {
|
||||
static LSPAny ToLSPAny(long double value)
|
||||
{
|
||||
return LSPAny(value);
|
||||
}
|
||||
|
||||
// string
|
||||
static LSPAny ToLSPAny(const string& str) {
|
||||
static LSPAny ToLSPAny(const string& str)
|
||||
{
|
||||
return LSPAny(str);
|
||||
}
|
||||
|
||||
static LSPAny ToLSPAny(const char* str) {
|
||||
static LSPAny ToLSPAny(const char* str)
|
||||
{
|
||||
return LSPAny(str);
|
||||
}
|
||||
|
||||
// nullptr
|
||||
static LSPAny ToLSPAny(std::nullptr_t) {
|
||||
static LSPAny ToLSPAny(std::nullptr_t)
|
||||
{
|
||||
return LSPAny(nullptr);
|
||||
}
|
||||
|
||||
// LSPAny 自身
|
||||
static LSPAny ToLSPAny(const LSPAny& any) {
|
||||
static LSPAny ToLSPAny(const LSPAny& any)
|
||||
{
|
||||
return any;
|
||||
}
|
||||
|
||||
|
|
@ -268,10 +337,12 @@ struct LSPConvert {
|
|||
|
||||
// vector
|
||||
template<typename T>
|
||||
static LSPAny ToLSPAny(const std::vector<T>& vec) {
|
||||
static LSPAny ToLSPAny(const std::vector<T>& vec)
|
||||
{
|
||||
LSPArray arr;
|
||||
arr.reserve(vec.size());
|
||||
for (const auto& item : vec) {
|
||||
for (const auto& item : vec)
|
||||
{
|
||||
arr.push_back(ToLSPAny(item));
|
||||
}
|
||||
return LSPAny(std::move(arr));
|
||||
|
|
@ -279,9 +350,11 @@ struct LSPConvert {
|
|||
|
||||
// map
|
||||
template<typename T>
|
||||
static LSPAny ToLSPAny(const std::map<string, T>& map) {
|
||||
static LSPAny ToLSPAny(const std::map<string, T>& map)
|
||||
{
|
||||
LSPObject obj;
|
||||
for (const auto& [key, value] : map) {
|
||||
for (const auto& [key, value] : map)
|
||||
{
|
||||
obj[key] = ToLSPAny(value);
|
||||
}
|
||||
return LSPAny(std::move(obj));
|
||||
|
|
@ -289,8 +362,10 @@ struct LSPConvert {
|
|||
|
||||
// optional
|
||||
template<typename T>
|
||||
static LSPAny ToLSPAny(const std::optional<T>& opt) {
|
||||
if (opt.has_value()) {
|
||||
static LSPAny ToLSPAny(const std::optional<T>& opt)
|
||||
{
|
||||
if (opt.has_value())
|
||||
{
|
||||
return ToLSPAny(*opt);
|
||||
}
|
||||
return LSPAny(nullptr);
|
||||
|
|
@ -304,19 +379,22 @@ struct LSPConvert {
|
|||
!std::is_same<T, const char*>::value &&
|
||||
!std::is_same<T, std::nullptr_t>::value &&
|
||||
!std::is_same<T, LSPAny>::value,
|
||||
LSPAny
|
||||
>::type ToLSPAny(const T& obj) {
|
||||
LSPAny>::type
|
||||
ToLSPAny(const T& obj)
|
||||
{
|
||||
// 序列化为 JSON 字符串
|
||||
std::string json;
|
||||
auto ec = glz::write_json(obj, json);
|
||||
if (ec) {
|
||||
if (ec)
|
||||
{
|
||||
throw std::runtime_error("Failed to serialize to JSON");
|
||||
}
|
||||
|
||||
// 直接解析为 LSPAny
|
||||
LSPAny result;
|
||||
ec = glz::read_json(result, json);
|
||||
if (ec) {
|
||||
if (ec)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse JSON to LSPAny");
|
||||
}
|
||||
|
||||
|
|
@ -326,8 +404,10 @@ struct LSPConvert {
|
|||
// === LSPAny 到基本类型的转换 ===
|
||||
|
||||
// boolean
|
||||
static boolean BoolFromLSPAny(const LSPAny& any) {
|
||||
if (!any.is<boolean>()) {
|
||||
static boolean BoolFromLSPAny(const LSPAny& any)
|
||||
{
|
||||
if (!any.is<boolean>())
|
||||
{
|
||||
throw std::runtime_error("LSPAny is not a boolean");
|
||||
}
|
||||
return any.get<boolean>();
|
||||
|
|
@ -336,16 +416,20 @@ struct LSPConvert {
|
|||
// 数字类型
|
||||
template<typename T>
|
||||
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
|
||||
NumberFromLSPAny(const LSPAny& any) {
|
||||
if (!any.is<decimal>()) {
|
||||
NumberFromLSPAny(const LSPAny& any)
|
||||
{
|
||||
if (!any.is<decimal>())
|
||||
{
|
||||
throw std::runtime_error("LSPAny is not a number");
|
||||
}
|
||||
return static_cast<T>(any.get<decimal>());
|
||||
}
|
||||
|
||||
// string
|
||||
static string StringFromLSPAny(const LSPAny& any) {
|
||||
if (!any.is<string>()) {
|
||||
static string StringFromLSPAny(const LSPAny& any)
|
||||
{
|
||||
if (!any.is<string>())
|
||||
{
|
||||
throw std::runtime_error("LSPAny is not a string");
|
||||
}
|
||||
return any.get<string>();
|
||||
|
|
@ -355,15 +439,18 @@ struct LSPConvert {
|
|||
|
||||
// vector
|
||||
template<typename T>
|
||||
static std::vector<T> VectorFromLSPAny(const LSPAny& any) {
|
||||
if (!any.is<LSPArray>()) {
|
||||
static std::vector<T> VectorFromLSPAny(const LSPAny& any)
|
||||
{
|
||||
if (!any.is<LSPArray>())
|
||||
{
|
||||
throw std::runtime_error("LSPAny is not an array");
|
||||
}
|
||||
|
||||
const auto& arr = any.get<LSPArray>();
|
||||
std::vector<T> result;
|
||||
result.reserve(arr.size());
|
||||
for (const auto& item : arr) {
|
||||
for (const auto& item : arr)
|
||||
{
|
||||
result.push_back(FromLSPAny<T>(item));
|
||||
}
|
||||
return result;
|
||||
|
|
@ -371,8 +458,10 @@ struct LSPConvert {
|
|||
|
||||
// optional
|
||||
template<typename T>
|
||||
static std::optional<T> OptionalFromLSPAny(const LSPAny& any) {
|
||||
if (any.is<std::nullptr_t>()) {
|
||||
static std::optional<T> OptionalFromLSPAny(const LSPAny& any)
|
||||
{
|
||||
if (any.is<std::nullptr_t>())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return FromLSPAny<T>(any);
|
||||
|
|
@ -380,7 +469,8 @@ struct LSPConvert {
|
|||
|
||||
// === LSPAny 到 Struct 的转换 ===
|
||||
template<typename T>
|
||||
static T FromLSPAny(const LSPAny& any) {
|
||||
static T FromLSPAny(const LSPAny& any)
|
||||
{
|
||||
return FromLSPAnyImpl<T>(any);
|
||||
}
|
||||
|
||||
|
|
@ -388,24 +478,28 @@ private:
|
|||
// 内部实现,使用重载来处理不同类型
|
||||
|
||||
// boolean
|
||||
static boolean FromLSPAnyImpl(const LSPAny& any, boolean*) {
|
||||
static boolean FromLSPAnyImpl(const LSPAny& any, boolean*)
|
||||
{
|
||||
return BoolFromLSPAny(any);
|
||||
}
|
||||
|
||||
// string
|
||||
static string FromLSPAnyImpl(const LSPAny& any, string*) {
|
||||
static string FromLSPAnyImpl(const LSPAny& any, string*)
|
||||
{
|
||||
return StringFromLSPAny(any);
|
||||
}
|
||||
|
||||
// 数字类型
|
||||
template<typename T>
|
||||
static typename std::enable_if<std::is_arithmetic<T>::value && !std::is_same<T, boolean>::value, T>::type
|
||||
FromLSPAnyImpl(const LSPAny& any, T*) {
|
||||
FromLSPAnyImpl(const LSPAny& any, T*)
|
||||
{
|
||||
return NumberFromLSPAny<T>(any);
|
||||
}
|
||||
|
||||
// LSPAny 自身
|
||||
static LSPAny FromLSPAnyImpl(const LSPAny& any, LSPAny*) {
|
||||
static LSPAny FromLSPAnyImpl(const LSPAny& any, LSPAny*)
|
||||
{
|
||||
return any;
|
||||
}
|
||||
|
||||
|
|
@ -415,19 +509,22 @@ private:
|
|||
!std::is_arithmetic<T>::value &&
|
||||
!std::is_same<T, string>::value &&
|
||||
!std::is_same<T, LSPAny>::value,
|
||||
T
|
||||
>::type FromLSPAnyImpl(const LSPAny& any, T*) {
|
||||
T>::type
|
||||
FromLSPAnyImpl(const LSPAny& any, T*)
|
||||
{
|
||||
// 序列化 LSPAny 为 JSON
|
||||
std::string json;
|
||||
auto ec = glz::write_json(any.value, json);
|
||||
if (ec) {
|
||||
if (ec)
|
||||
{
|
||||
throw std::runtime_error("Failed to serialize LSPAny to JSON");
|
||||
}
|
||||
|
||||
// 解析 JSON 到目标类型
|
||||
T result;
|
||||
ec = glz::read_json(result, json);
|
||||
if (ec) {
|
||||
if (ec)
|
||||
{
|
||||
throw std::runtime_error("Failed to parse JSON to target type");
|
||||
}
|
||||
|
||||
|
|
@ -436,7 +533,8 @@ private:
|
|||
|
||||
// 通过指针类型来分派
|
||||
template<typename T>
|
||||
static T FromLSPAnyImpl(const LSPAny& any) {
|
||||
static T FromLSPAnyImpl(const LSPAny& any)
|
||||
{
|
||||
return FromLSPAnyImpl(any, static_cast<T*>(nullptr));
|
||||
}
|
||||
};
|
||||
|
|
@ -461,17 +559,20 @@ inline LSPAny ToLSPAny(const LSPAny& any) { return LSPConvert::ToLSPAny(any); }
|
|||
|
||||
// 容器类型的便利函数
|
||||
template<typename T>
|
||||
LSPAny ToLSPAny(const std::vector<T>& vec) {
|
||||
LSPAny ToLSPAny(const std::vector<T>& vec)
|
||||
{
|
||||
return LSPConvert::ToLSPAny(vec);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LSPAny ToLSPAny(const std::map<string, T>& map) {
|
||||
LSPAny ToLSPAny(const std::map<string, T>& map)
|
||||
{
|
||||
return LSPConvert::ToLSPAny(map);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LSPAny ToLSPAny(const std::optional<T>& opt) {
|
||||
LSPAny ToLSPAny(const std::optional<T>& opt)
|
||||
{
|
||||
return LSPConvert::ToLSPAny(opt);
|
||||
}
|
||||
|
||||
|
|
@ -483,46 +584,54 @@ typename std::enable_if<
|
|||
!std::is_same<T, const char*>::value &&
|
||||
!std::is_same<T, std::nullptr_t>::value &&
|
||||
!std::is_same<T, LSPAny>::value,
|
||||
LSPAny
|
||||
>::type ToLSPAny(const T& value) {
|
||||
LSPAny>::type
|
||||
ToLSPAny(const T& value)
|
||||
{
|
||||
return LSPConvert::ToLSPAny(value);
|
||||
}
|
||||
|
||||
// FromLSPAny 便利函数
|
||||
template<typename T>
|
||||
T FromLSPAny(const LSPAny& any) {
|
||||
T FromLSPAny(const LSPAny& any)
|
||||
{
|
||||
return LSPConvert::FromLSPAny<T>(any);
|
||||
}
|
||||
|
||||
// ===== 测试代码 =====
|
||||
|
||||
// 测试用的结构体
|
||||
struct Message {
|
||||
struct Message
|
||||
{
|
||||
string jsonrpc = "2.0";
|
||||
string method;
|
||||
int id = 0;
|
||||
};
|
||||
|
||||
struct Position {
|
||||
struct Position
|
||||
{
|
||||
int line;
|
||||
int character;
|
||||
};
|
||||
|
||||
struct Range {
|
||||
struct Range
|
||||
{
|
||||
Position start;
|
||||
Position end;
|
||||
};
|
||||
|
||||
struct TextDocumentIdentifier {
|
||||
struct TextDocumentIdentifier
|
||||
{
|
||||
string uri;
|
||||
};
|
||||
|
||||
struct TextDocumentPositionParams {
|
||||
struct TextDocumentPositionParams
|
||||
{
|
||||
TextDocumentIdentifier textDocument;
|
||||
Position position;
|
||||
};
|
||||
|
||||
struct CompletionItem {
|
||||
struct CompletionItem
|
||||
{
|
||||
string label;
|
||||
std::optional<int> kind;
|
||||
std::optional<string> detail;
|
||||
|
|
@ -536,70 +645,90 @@ struct CompletionItem {
|
|||
|
||||
// 为测试结构体提供 glaze 元数据
|
||||
template<>
|
||||
struct glz::meta<Message> {
|
||||
struct glz::meta<Message>
|
||||
{
|
||||
using T = Message;
|
||||
static constexpr auto value = object(
|
||||
"jsonrpc", &T::jsonrpc,
|
||||
"method", &T::method,
|
||||
"id", &T::id
|
||||
);
|
||||
"jsonrpc",
|
||||
&T::jsonrpc,
|
||||
"method",
|
||||
&T::method,
|
||||
"id",
|
||||
&T::id);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct glz::meta<Position> {
|
||||
struct glz::meta<Position>
|
||||
{
|
||||
using T = Position;
|
||||
static constexpr auto value = object(
|
||||
"line", &T::line,
|
||||
"character", &T::character
|
||||
);
|
||||
"line",
|
||||
&T::line,
|
||||
"character",
|
||||
&T::character);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct glz::meta<Range> {
|
||||
struct glz::meta<Range>
|
||||
{
|
||||
using T = Range;
|
||||
static constexpr auto value = object(
|
||||
"start", &T::start,
|
||||
"end", &T::end
|
||||
);
|
||||
"start",
|
||||
&T::start,
|
||||
"end",
|
||||
&T::end);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct glz::meta<TextDocumentIdentifier> {
|
||||
struct glz::meta<TextDocumentIdentifier>
|
||||
{
|
||||
using T = TextDocumentIdentifier;
|
||||
static constexpr auto value = object(
|
||||
"uri", &T::uri
|
||||
);
|
||||
"uri",
|
||||
&T::uri);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct glz::meta<TextDocumentPositionParams> {
|
||||
struct glz::meta<TextDocumentPositionParams>
|
||||
{
|
||||
using T = TextDocumentPositionParams;
|
||||
static constexpr auto value = object(
|
||||
"textDocument", &T::textDocument,
|
||||
"position", &T::position
|
||||
);
|
||||
"textDocument",
|
||||
&T::textDocument,
|
||||
"position",
|
||||
&T::position);
|
||||
};
|
||||
|
||||
template<>
|
||||
struct glz::meta<CompletionItem> {
|
||||
struct glz::meta<CompletionItem>
|
||||
{
|
||||
using T = CompletionItem;
|
||||
static constexpr auto value = object(
|
||||
"label", &T::label,
|
||||
"kind", &T::kind,
|
||||
"detail", &T::detail,
|
||||
"documentation", &T::documentation,
|
||||
"deprecated", &T::deprecated,
|
||||
"preselect", &T::preselect,
|
||||
"sortText", &T::sortText,
|
||||
"filterText", &T::filterText,
|
||||
"insertText", &T::insertText
|
||||
);
|
||||
"label",
|
||||
&T::label,
|
||||
"kind",
|
||||
&T::kind,
|
||||
"detail",
|
||||
&T::detail,
|
||||
"documentation",
|
||||
&T::documentation,
|
||||
"deprecated",
|
||||
&T::deprecated,
|
||||
"preselect",
|
||||
&T::preselect,
|
||||
"sortText",
|
||||
&T::sortText,
|
||||
"filterText",
|
||||
&T::filterText,
|
||||
"insertText",
|
||||
&T::insertText);
|
||||
};
|
||||
|
||||
// 测试函数
|
||||
#include <iostream>
|
||||
|
||||
void test_basic_conversion() {
|
||||
void test_basic_conversion()
|
||||
{
|
||||
std::cout << "=== Testing Basic Conversion ===" << std::endl;
|
||||
|
||||
// 测试 struct 转换
|
||||
|
|
@ -621,7 +750,8 @@ void test_basic_conversion() {
|
|||
std::cout << "Restored id: " << restored.id << std::endl;
|
||||
}
|
||||
|
||||
void test_vector_conversion() {
|
||||
void test_vector_conversion()
|
||||
{
|
||||
std::cout << "\n=== Testing Vector Conversion ===" << std::endl;
|
||||
|
||||
std::vector<Position> positions = {
|
||||
|
|
@ -642,7 +772,8 @@ void test_vector_conversion() {
|
|||
std::cout << "Restored " << restored.size() << " positions" << std::endl;
|
||||
}
|
||||
|
||||
void test_optional_conversion() {
|
||||
void test_optional_conversion()
|
||||
{
|
||||
std::cout << "\n=== Testing Optional Conversion ===" << std::endl;
|
||||
|
||||
CompletionItem item;
|
||||
|
|
@ -663,7 +794,8 @@ void test_optional_conversion() {
|
|||
std::cout << "Empty optional as JSON: " << json << std::endl;
|
||||
}
|
||||
|
||||
void test_mixed_usage() {
|
||||
void test_mixed_usage()
|
||||
{
|
||||
std::cout << "\n=== Testing Mixed Usage ===" << std::endl;
|
||||
|
||||
// 创建复杂对象
|
||||
|
|
@ -683,7 +815,8 @@ void test_mixed_usage() {
|
|||
std::cout << "Complex object: " << json << std::endl;
|
||||
|
||||
// 提取值
|
||||
if (root.is<LSPObject>()) {
|
||||
if (root.is<LSPObject>())
|
||||
{
|
||||
auto& root_obj = root.get<LSPObject>();
|
||||
|
||||
Message msg = FromLSPAny<Message>(root_obj["message"]);
|
||||
|
|
@ -694,15 +827,19 @@ void test_mixed_usage() {
|
|||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
test_basic_conversion();
|
||||
test_vector_conversion();
|
||||
test_optional_conversion();
|
||||
test_mixed_usage();
|
||||
|
||||
std::cout << "\nAll tests completed!" << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cout << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,41 +1 @@
|
|||
function MyFunc(a: string; b: array of string);
|
||||
begin
|
||||
end
|
||||
function MyFunc(a: string; b: array of string);overload;
|
||||
begin
|
||||
end;
|
||||
|
||||
// type ImageDimensions = class
|
||||
// property Width read width_;
|
||||
// property Width : array of string index 2 read width_;
|
||||
// end;
|
||||
|
||||
// <?tslx>
|
||||
// <div class="element-data-container">
|
||||
// <?tsl
|
||||
// rpt_data_bar(data[i],canAudit);
|
||||
// ?>
|
||||
// <div class="diff-section <?= isDiffed?'diff-section-diffed':''?>" id="eid-<?=tempid?>">
|
||||
// <div class="diff-left span5">
|
||||
// <?tsl
|
||||
// try
|
||||
// rpt_show_data(other_data_i);
|
||||
// except
|
||||
// dolog("diffrepot_erData","数据解析展示出错:"$data[i]["NAME"]);
|
||||
// dolog("diffrepot_erData",tostn(data[i]["DATA_ID"]));
|
||||
// end;
|
||||
|
||||
// ?>
|
||||
// </div>
|
||||
|
||||
// <div class="diff-right span5">
|
||||
// <?tsl rpt_show_data(data[i]); ?>
|
||||
// </div>
|
||||
// <div class="span2">
|
||||
// <?=class(IDS_LiveReport).rpt_data_comments(data[i]['comment'])?>
|
||||
// </div>
|
||||
// <div class="clear"></div>
|
||||
// </div>
|
||||
// </div><!--end element-data-container -->
|
||||
// <?tsl
|
||||
|
||||
data := `r | data;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ ROOT_DIRS=(
|
|||
"/mnt/d/code/tinysoft/OfficeXml-dev/generator"
|
||||
"/mnt/d/code/tinysoft/tsoffice/"
|
||||
"/mnt/d/code/tinysoft/pdfconverter"
|
||||
"/mnt/c/Programs/Tinysoft/TSLGen2/funcext/other"
|
||||
"/mnt/c/Programs/Tinysoft/TSLGen2/funcext/tsword"
|
||||
"/mnt/c/Programs/Tinysoft/TSLGen2/funcext/word2arr"
|
||||
# "/mnt/d/code/tinysoft/PdfConverter"
|
||||
# 可以添加更多目录
|
||||
# "/path/to/third/directory"
|
||||
|
|
|
|||
|
|
@ -58,9 +58,10 @@ module.exports = grammar({
|
|||
word: ($) => $.identifier,
|
||||
|
||||
conflicts: ($) => [
|
||||
[$._left_hand_side, $.primary_expression],
|
||||
[$.tssql_select_expression, $._table_or_subquery],
|
||||
[$._left_hand_side, $._primary_expression],
|
||||
[$._tssql_select_expression, $._table_or_subquery],
|
||||
[$.tslx_close_tag, $.tslx_expression_tag],
|
||||
[$._assignable_expression, $.array_element],
|
||||
],
|
||||
|
||||
inline: ($) => [$._statement],
|
||||
|
|
@ -86,22 +87,22 @@ module.exports = grammar({
|
|||
$.break_statement,
|
||||
$.continue_statement,
|
||||
$.return_statement,
|
||||
$.inherited_statement,
|
||||
// $.inherited_statement,
|
||||
),
|
||||
|
||||
_compound_statement: ($) =>
|
||||
choice(
|
||||
$.if_statement,
|
||||
$.for_statement,
|
||||
$._for_statement,
|
||||
$.while_statement,
|
||||
$.repeat_statement,
|
||||
$.case_statement,
|
||||
$.try_statement,
|
||||
|
||||
$.anonymous_function_statement,
|
||||
// $.function_declaration_statement,
|
||||
$.function_declaration_statement,
|
||||
$.function_definition_statement,
|
||||
$.function_definition_statement_with_overload,
|
||||
$.function_definition_with_overload_statement,
|
||||
$.class_definition_statement,
|
||||
$.external_method_statement,
|
||||
|
||||
|
|
@ -109,11 +110,14 @@ module.exports = grammar({
|
|||
$._tslx_template_statement,
|
||||
),
|
||||
|
||||
var_statement: ($) => seq($.var_declaration, kSemicolon),
|
||||
var_statement: ($) =>
|
||||
seq(field("declaration", $.var_declaration), kSemicolon),
|
||||
|
||||
static_statement: ($) => seq($.static_declaration, kSemicolon),
|
||||
static_statement: ($) =>
|
||||
seq(field("declaration", $.static_declaration), kSemicolon),
|
||||
|
||||
global_statement: ($) => seq($.global_declaration, kSemicolon),
|
||||
global_statement: ($) =>
|
||||
seq(field("declaration", $.global_declaration), kSemicolon),
|
||||
|
||||
const_statement: ($) =>
|
||||
seq(
|
||||
|
|
@ -126,13 +130,16 @@ module.exports = grammar({
|
|||
),
|
||||
|
||||
var_declaration: ($) =>
|
||||
seq(kw("var"), $._variable_declaration, optional($._type_clause)),
|
||||
seq(kw("var"), $._variable_declaration, optional($._type_clause), optional($._initial_value)),
|
||||
|
||||
static_declaration: ($) =>
|
||||
seq(kw("static"), $._variable_declaration, optional($._type_clause)),
|
||||
seq(kw("static"), $._variable_declaration, optional($._type_clause), optional($._initial_value)),
|
||||
|
||||
global_declaration: ($) =>
|
||||
seq(kw("global"), $._variable_declaration, optional($._type_clause)),
|
||||
seq(kw("global"), $._variable_declaration, optional($._type_clause), optional($._initial_value)),
|
||||
|
||||
_initial_value: ($) =>
|
||||
seq(":=", field("initial_value", $._right_hand_side)),
|
||||
|
||||
_variable_declaration: ($) => sep1(field("name", $.identifier), ","),
|
||||
|
||||
|
|
@ -165,73 +172,43 @@ module.exports = grammar({
|
|||
continue_statement: (_) => seq(kw("continue"), kSemicolon),
|
||||
|
||||
return_statement: ($) =>
|
||||
seq(kw("return"), optional($.expression), kSemicolon),
|
||||
seq(kw("return"), field("value", optional($.expression)), kSemicolon),
|
||||
|
||||
inherited_statement: ($) => seq($.inherited_expression, kSemicolon),
|
||||
// inherited_statement: ($) => seq($._inherited_expression, kSemicolon),
|
||||
|
||||
_built_in_expression: ($) =>
|
||||
choice($.echo_expression, $.raise_expression, $.new_expression),
|
||||
choice($.echo_expression, $.raise_expression, $.new_expression, $.inherited_expression),
|
||||
|
||||
echo_expression: ($) =>
|
||||
prec.left(1, seq(kw("echo"), sep1($.expression, ","))),
|
||||
prec.left(1, seq(kw("echo"), sep1(field("argument", $.expression), ","))),
|
||||
|
||||
raise_expression: ($) => seq(kw("raise"), $.expression),
|
||||
raise_expression: ($) => seq(kw("raise"), field("exception", $.expression)),
|
||||
|
||||
inherited_expression: ($) => seq(kw("inherited"), optional($.expression)),
|
||||
inherited_expression: ($) => prec.left(0, seq(kw("inherited"), field("class", optional($.expression)))),
|
||||
|
||||
new_expression: ($) => seq(kw("new"), $.expression),
|
||||
new_expression: ($) => seq(kw("new"), field("class", $.expression)),
|
||||
|
||||
expression_statement: ($) =>
|
||||
seq(choice($.expression, $.tssql_dml_expression), kSemicolon),
|
||||
seq(choice($.expression, $._tssql_dml_expression), kSemicolon),
|
||||
|
||||
expression: ($) =>
|
||||
choice(
|
||||
$.operator_expression,
|
||||
$.tssql_select_expression,
|
||||
$.primary_expression,
|
||||
$._operator_expression,
|
||||
$._tssql_select_expression,
|
||||
$._primary_expression,
|
||||
$._built_in_expression,
|
||||
),
|
||||
|
||||
operator_expression: ($) =>
|
||||
_operator_expression: ($) =>
|
||||
choice(
|
||||
$.expr_expression,
|
||||
|
||||
$.ternary_expression,
|
||||
|
||||
$.logical_or_expression,
|
||||
$.logical_and_expression,
|
||||
$.logical_not_expression,
|
||||
|
||||
$.comparison_expression,
|
||||
|
||||
$.bitwise_or_expression,
|
||||
$.bitwise_and_expression,
|
||||
$.bitwise_xor_expression,
|
||||
$.bitwise_not_expression,
|
||||
$.shift_expression,
|
||||
|
||||
$.addition_expression,
|
||||
$.multiplication_expression,
|
||||
$.power_expression,
|
||||
$.logarithm_expression,
|
||||
|
||||
$.matrix_multiplication_expression,
|
||||
$.matrix_power_expression,
|
||||
$.matrix_concatenation_expression,
|
||||
$.matrix_transpose_expression,
|
||||
$.range_expression,
|
||||
|
||||
$.set_operation_expression,
|
||||
|
||||
$.concatenation_expression,
|
||||
|
||||
$.unary_plus_expression,
|
||||
$.unary_minus_expression,
|
||||
$.binary_expression,
|
||||
$.unary_expression,
|
||||
$.prefix_increment_expression,
|
||||
$.prefix_decrement_expression,
|
||||
$.postfix_increment_expression,
|
||||
$.postfix_decrement_expression,
|
||||
$.derivative_expression,
|
||||
$.function_pointer_expression,
|
||||
),
|
||||
|
||||
|
|
@ -295,7 +272,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
_with_assignment_expression: ($) =>
|
||||
_assignable_expression: ($) =>
|
||||
choice(
|
||||
$.expression,
|
||||
$.assignment_expression,
|
||||
|
|
@ -308,51 +285,45 @@ module.exports = grammar({
|
|||
seq(
|
||||
field("condition", $.expression),
|
||||
"?",
|
||||
optional(field("consequence", $._with_assignment_expression)),
|
||||
optional(field("consequence", $._assignable_expression)),
|
||||
":",
|
||||
field("alternative", $._with_assignment_expression),
|
||||
field("alternative", $._assignable_expression),
|
||||
),
|
||||
),
|
||||
|
||||
logical_or_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalOr,
|
||||
seq(
|
||||
field("left", $.expression),
|
||||
field("operator", choice(kw("or"), ".||", "||")),
|
||||
field("right", $.expression),
|
||||
),
|
||||
binary_expression: ($) =>
|
||||
choice(
|
||||
$._logical_or_expression,
|
||||
$._logical_and_expression,
|
||||
|
||||
$._bitwise_or_expression,
|
||||
$._bitwise_and_expression,
|
||||
$._bitwise_xor_expression,
|
||||
$._shift_expression,
|
||||
|
||||
$._addition_expression,
|
||||
$._multiplication_expression,
|
||||
$._power_expression,
|
||||
$._logarithm_expression,
|
||||
|
||||
$._matrix_multiplication_expression,
|
||||
$._matrix_power_expression,
|
||||
$._matrix_concatenation_expression,
|
||||
$._range_expression,
|
||||
|
||||
$._comparison_expression,
|
||||
|
||||
$._set_operation_expression,
|
||||
|
||||
$._concatenation_expression,
|
||||
),
|
||||
|
||||
logical_and_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalAnd,
|
||||
seq(
|
||||
field("left", $.expression),
|
||||
field("operator", choice(kw("and"), ".&&", "&&")),
|
||||
field("right", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
logical_not_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalNot,
|
||||
seq(
|
||||
field("operator", choice(kw("not"), ".!!")),
|
||||
field("argument", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
comparison_expression: ($) =>
|
||||
_comparison_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kComparsion,
|
||||
seq(
|
||||
$.expression,
|
||||
repeat1(
|
||||
seq(
|
||||
field(
|
||||
"operators",
|
||||
choice(
|
||||
field("left", $.expression),
|
||||
field("operator", choice(
|
||||
"=",
|
||||
"<>",
|
||||
">",
|
||||
|
|
@ -370,13 +341,40 @@ module.exports = grammar({
|
|||
kw("like"),
|
||||
),
|
||||
),
|
||||
$.expression,
|
||||
),
|
||||
),
|
||||
field("right", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
bitwise_or_expression: ($) =>
|
||||
_logical_or_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalOr,
|
||||
seq(
|
||||
field("left", $.expression),
|
||||
field("operator", choice(kw("or"), ".||", "||")),
|
||||
field("right", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
_logical_and_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalAnd,
|
||||
seq(
|
||||
field("left", $.expression),
|
||||
field("operator", choice(kw("and"), ".&&", "&&")),
|
||||
field("right", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
_logical_not_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogicalNot,
|
||||
seq(
|
||||
field("operator", choice(kw("not"), ".!!")),
|
||||
field("argument", $.expression),
|
||||
),
|
||||
),
|
||||
|
||||
_bitwise_or_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kBitwiseOr,
|
||||
seq(
|
||||
|
|
@ -386,7 +384,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
bitwise_and_expression: ($) =>
|
||||
_bitwise_and_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kBitwiseAnd,
|
||||
seq(
|
||||
|
|
@ -396,7 +394,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
bitwise_xor_expression: ($) =>
|
||||
_bitwise_xor_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kBitwiseXor,
|
||||
seq(
|
||||
|
|
@ -406,13 +404,13 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
bitwise_not_expression: ($) =>
|
||||
_bitwise_not_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kBitwiseNot,
|
||||
seq(field("operator", ".!"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
shift_expression: ($) =>
|
||||
_shift_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kShift,
|
||||
seq(
|
||||
|
|
@ -422,7 +420,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
addition_expression: ($) =>
|
||||
_addition_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kAddSub,
|
||||
seq(
|
||||
|
|
@ -432,7 +430,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
multiplication_expression: ($) =>
|
||||
_multiplication_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kTimes,
|
||||
seq(
|
||||
|
|
@ -442,7 +440,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
power_expression: ($) =>
|
||||
_power_expression: ($) =>
|
||||
prec.right(
|
||||
kPrec.kPower,
|
||||
seq(
|
||||
|
|
@ -452,7 +450,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
logarithm_expression: ($) =>
|
||||
_logarithm_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kLogarithm,
|
||||
seq(
|
||||
|
|
@ -462,7 +460,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
matrix_multiplication_expression: ($) =>
|
||||
_matrix_multiplication_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kMatrixTimes,
|
||||
seq(
|
||||
|
|
@ -472,7 +470,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
matrix_power_expression: ($) =>
|
||||
_matrix_power_expression: ($) =>
|
||||
prec.right(
|
||||
kPrec.kMatrixPower,
|
||||
seq(
|
||||
|
|
@ -482,7 +480,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
matrix_concatenation_expression: ($) =>
|
||||
_matrix_concatenation_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kMatrixConcat,
|
||||
seq(
|
||||
|
|
@ -492,7 +490,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
range_expression: ($) =>
|
||||
_range_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kRange,
|
||||
seq(
|
||||
|
|
@ -502,13 +500,13 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
matrix_transpose_expression: ($) =>
|
||||
_matrix_transpose_expression: ($) =>
|
||||
prec(
|
||||
kPrec.kMatrixTranspose,
|
||||
seq(field("operator", "`"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
set_operation_expression: ($) =>
|
||||
_set_operation_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kSet,
|
||||
seq(
|
||||
|
|
@ -527,7 +525,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
concatenation_expression: ($) =>
|
||||
_concatenation_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kConcat,
|
||||
seq(
|
||||
|
|
@ -537,18 +535,37 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
unary_plus_expression: ($) =>
|
||||
unary_expression: ($) =>
|
||||
choice(
|
||||
$._unary_plus_expression,
|
||||
$._unary_minus_expression,
|
||||
$._derivative_expression,
|
||||
|
||||
$._logical_not_expression,
|
||||
|
||||
$._bitwise_not_expression,
|
||||
|
||||
$._matrix_transpose_expression,
|
||||
),
|
||||
|
||||
_unary_plus_expression: ($) =>
|
||||
prec(
|
||||
kPrec.kSigned,
|
||||
seq(field("operator", "+"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
unary_minus_expression: ($) =>
|
||||
_unary_minus_expression: ($) =>
|
||||
prec(
|
||||
kPrec.kSigned,
|
||||
seq(field("operator", "-"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
_derivative_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kDerivative,
|
||||
seq(field("operator", "!"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
prefix_increment_expression: ($) =>
|
||||
prec.right(
|
||||
kPrec.kPrefix,
|
||||
|
|
@ -573,12 +590,6 @@ module.exports = grammar({
|
|||
seq(field("argument", $.expression), field("operator", "--")),
|
||||
),
|
||||
|
||||
derivative_expression: ($) =>
|
||||
prec.left(
|
||||
kPrec.kDerivative,
|
||||
seq(field("operator", "!"), field("argument", $.expression)),
|
||||
),
|
||||
|
||||
function_pointer_expression: ($) =>
|
||||
prec(
|
||||
kPrec.kFunctionPointer,
|
||||
|
|
@ -591,7 +602,7 @@ module.exports = grammar({
|
|||
$._parameter_signature,
|
||||
field("return_type", optional($._type_clause)),
|
||||
optional(kSemicolon),
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
),
|
||||
|
||||
unpack_pattern: ($) => prec.dynamic(1, seq("[", $._unpack_vars, "]")),
|
||||
|
|
@ -604,10 +615,7 @@ module.exports = grammar({
|
|||
|
||||
_left_hand_side: ($) =>
|
||||
choice(
|
||||
$._assignable_identifier,
|
||||
$.var_declaration,
|
||||
$.static_declaration,
|
||||
$.global_declaration,
|
||||
$._identifier_like,
|
||||
$.attribute,
|
||||
$.subscript,
|
||||
$.unpack_pattern,
|
||||
|
|
@ -620,7 +628,7 @@ module.exports = grammar({
|
|||
$.augmented_assignment_expression,
|
||||
),
|
||||
|
||||
tssql_select_expression: ($) =>
|
||||
_tssql_select_expression: ($) =>
|
||||
choice(
|
||||
$.select_expression,
|
||||
$.sselect_expression,
|
||||
|
|
@ -628,7 +636,7 @@ module.exports = grammar({
|
|||
$.mselect_expression,
|
||||
),
|
||||
|
||||
tssql_dml_expression: ($) =>
|
||||
_tssql_dml_expression: ($) =>
|
||||
choice($.update_expression, $.delete_expression, $.insert_expression),
|
||||
|
||||
select_expression: ($) => seq(kw("select"), $._select_clause),
|
||||
|
|
@ -673,7 +681,7 @@ module.exports = grammar({
|
|||
|
||||
update_assignment: ($) =>
|
||||
seq(
|
||||
field("column", $.primary_expression),
|
||||
field("column", $._primary_expression),
|
||||
"=",
|
||||
field("value", $.expression),
|
||||
),
|
||||
|
|
@ -799,16 +807,16 @@ module.exports = grammar({
|
|||
")",
|
||||
),
|
||||
|
||||
primary_expression: ($) =>
|
||||
_primary_expression: ($) =>
|
||||
choice(
|
||||
$.attribute,
|
||||
$.subscript,
|
||||
$.parenthesized_expression,
|
||||
$.call,
|
||||
$.array,
|
||||
$._literal,
|
||||
$._assignable_identifier,
|
||||
$._reserved_keyword,
|
||||
$.literal,
|
||||
$.reserved_keyword,
|
||||
$._parenthesized_expression,
|
||||
$._identifier_like,
|
||||
|
||||
$.sql_field,
|
||||
),
|
||||
|
|
@ -816,12 +824,12 @@ module.exports = grammar({
|
|||
// identifier: _ => /[a-zA-Z_][a-zA-Z0-9_]*/,
|
||||
identifier: (_) => token(prec(kPrec.kIdentifier, /[a-zA-Z_][a-zA-Z0-9_]*/)),
|
||||
|
||||
_literal: ($) =>
|
||||
literal: ($) =>
|
||||
choice($.number, $.string, $.boolean, $.nil, $.infinity, $.ellipsis),
|
||||
|
||||
_assignable_identifier: ($) => choice($.identifier, $.type, $.do),
|
||||
_identifier_like: ($) => choice($.identifier, $.type, $.do),
|
||||
|
||||
_reserved_keyword: ($) => choice($.class, $.in),
|
||||
reserved_keyword: ($) => choice($.class, $.in),
|
||||
|
||||
type: (_) => kw("type"),
|
||||
class: (_) => kw("class"),
|
||||
|
|
@ -890,9 +898,9 @@ module.exports = grammar({
|
|||
prec(
|
||||
kPrec.kCall,
|
||||
seq(
|
||||
field("function", $.primary_expression),
|
||||
field("function", $._primary_expression),
|
||||
"(",
|
||||
field("arguments", optional($.argument_list)),
|
||||
optional(sep1(field("argument", $.argument), ",")),
|
||||
")",
|
||||
),
|
||||
),
|
||||
|
|
@ -901,7 +909,7 @@ module.exports = grammar({
|
|||
prec(
|
||||
kPrec.kAttribute,
|
||||
seq(
|
||||
field("object", choice($.primary_expression)),
|
||||
field("object", choice($._primary_expression)),
|
||||
".",
|
||||
field("attribute", $.identifier),
|
||||
),
|
||||
|
|
@ -913,7 +921,7 @@ module.exports = grammar({
|
|||
prec(
|
||||
kPrec.kSubscript,
|
||||
seq(
|
||||
field("value", $.primary_expression),
|
||||
field("value", $._primary_expression),
|
||||
"[",
|
||||
field("subscript", $._index_spec),
|
||||
"]",
|
||||
|
|
@ -921,8 +929,7 @@ module.exports = grammar({
|
|||
),
|
||||
),
|
||||
|
||||
parenthesized_expression: ($) =>
|
||||
seq("(", $._with_assignment_expression, ")"),
|
||||
_parenthesized_expression: ($) => seq("(", optional($._assignable_expression), ")"),
|
||||
|
||||
array: ($) =>
|
||||
prec(
|
||||
|
|
@ -930,15 +937,18 @@ module.exports = grammar({
|
|||
seq(kw("array"), "(", optional($._array_elements), ")"),
|
||||
),
|
||||
|
||||
argument_list: ($) => sep1($.argument, ","),
|
||||
|
||||
argument: ($) =>
|
||||
choice(
|
||||
$.expression,
|
||||
seq(field("name", $.identifier), ":", field("value", $.expression)),
|
||||
"*",
|
||||
$.named_argument,
|
||||
// $.spread_argument
|
||||
),
|
||||
|
||||
named_argument: ($) =>
|
||||
seq(field("name", $.identifier), ":", field("value", $.expression)),
|
||||
|
||||
// spread_argument: (_) => "*",
|
||||
|
||||
_index_spec: ($) => choice($._multi_index, $._single_index),
|
||||
|
||||
_multi_index: ($) => seq($._index_item, repeat1(seq(",", $._index_item))),
|
||||
|
|
@ -969,9 +979,9 @@ module.exports = grammar({
|
|||
|
||||
key_value_pair: ($) =>
|
||||
seq(
|
||||
field("key", $.expression),
|
||||
field("key", choice($.expression)),
|
||||
":",
|
||||
field("value", choice($.expression, $.parenthesized_array)),
|
||||
field("value", choice($.parenthesized_array, $.expression)),
|
||||
),
|
||||
|
||||
parenthesized_array: ($) =>
|
||||
|
|
@ -979,12 +989,7 @@ module.exports = grammar({
|
|||
1,
|
||||
seq(
|
||||
"(",
|
||||
choice(
|
||||
seq($.key_value_pair, ",", sep1($.key_value_pair, ",")),
|
||||
$.key_value_pair,
|
||||
seq($.expression, ",", sep1($.expression, ",")),
|
||||
$.expression,
|
||||
),
|
||||
sep1($.array_element, ","),
|
||||
optional(","),
|
||||
")",
|
||||
),
|
||||
|
|
@ -1001,15 +1006,15 @@ module.exports = grammar({
|
|||
kPrec.kIf,
|
||||
seq(
|
||||
$.if_clause,
|
||||
repeat(field("alternative", $.else_if_clause)),
|
||||
optional(field("alternative", $.else_clause)),
|
||||
repeat($.else_if_clause),
|
||||
optional($.else_clause),
|
||||
),
|
||||
),
|
||||
|
||||
if_clause: ($) =>
|
||||
seq(
|
||||
kw("if"),
|
||||
field("condition", $._with_assignment_expression),
|
||||
field("condition", $._assignable_expression),
|
||||
kw("then"),
|
||||
field("consequence", $._statement_suite),
|
||||
),
|
||||
|
|
@ -1020,7 +1025,7 @@ module.exports = grammar({
|
|||
seq(
|
||||
kw("else"),
|
||||
kw("if"),
|
||||
field("condition", $._with_assignment_expression),
|
||||
field("condition", $._assignable_expression),
|
||||
kw("then"),
|
||||
field("consequence", $._statement_suite),
|
||||
),
|
||||
|
|
@ -1030,13 +1035,13 @@ module.exports = grammar({
|
|||
seq(kw("else"), field("consequence", $._statement_suite)),
|
||||
|
||||
_statement_suite: ($) =>
|
||||
choice(seq($.block_statement, optional(kSemicolon)), $.single_suite),
|
||||
choice(seq($.block_suite, optional(kSemicolon)), $.single_suite),
|
||||
|
||||
single_suite: ($) => $._statement,
|
||||
|
||||
block_statement: ($) => seq(kw("begin"), repeat($._statement), kw("end")),
|
||||
block_suite: ($) => seq(kw("begin"), repeat($._statement), kw("end")),
|
||||
|
||||
for_statement: ($) => choice($.for_in_statement, $.for_to_statement),
|
||||
_for_statement: ($) => choice($.for_in_statement, $.for_to_statement),
|
||||
|
||||
for_in_statement: ($) =>
|
||||
seq(
|
||||
|
|
@ -1091,13 +1096,9 @@ module.exports = grammar({
|
|||
),
|
||||
|
||||
case_branch: ($) =>
|
||||
seq(
|
||||
$.case_values,
|
||||
":",
|
||||
field("consequence", $._statement_suite),
|
||||
),
|
||||
seq($._case_values, ":", field("consequence", $._statement_suite)),
|
||||
|
||||
case_values: ($) => sep1(field("value", $.expression), ","),
|
||||
_case_values: ($) => sep1(field("value", $.expression), ","),
|
||||
|
||||
case_else: ($) => seq(kw("else"), field("consequence", $._statement_suite)),
|
||||
|
||||
|
|
@ -1114,14 +1115,14 @@ module.exports = grammar({
|
|||
anonymous_function_statement: ($) =>
|
||||
seq($.anonymous_function_expression, optional(kSemicolon)),
|
||||
|
||||
// function_declaration_statement: ($) =>
|
||||
// seq(
|
||||
// kw("function"),
|
||||
// field("name", $.identifier),
|
||||
// $._parameter_signature,
|
||||
// optional(field("return_type", $._type_clause)),
|
||||
// kSemicolon,
|
||||
// ),
|
||||
function_declaration_statement: ($) =>
|
||||
seq(
|
||||
kw("function"),
|
||||
field("name", $.identifier),
|
||||
$._parameter_signature,
|
||||
optional(field("return_type", $._type_clause)),
|
||||
kSemicolon,
|
||||
),
|
||||
|
||||
function_definition_statement: ($) =>
|
||||
seq(
|
||||
|
|
@ -1130,11 +1131,11 @@ module.exports = grammar({
|
|||
$._parameter_signature,
|
||||
field("return_type", optional($._type_clause)),
|
||||
optional(kSemicolon),
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
function_definition_statement_with_overload: ($) =>
|
||||
function_definition_with_overload_statement: ($) =>
|
||||
seq(
|
||||
kw("function"),
|
||||
field("name", $.identifier),
|
||||
|
|
@ -1143,20 +1144,20 @@ module.exports = grammar({
|
|||
kSemicolon,
|
||||
kw("overload"),
|
||||
kSemicolon,
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
_parameter_signature: ($) =>
|
||||
seq("(", optional(field("parameters", $.parameter_list)), ")"),
|
||||
seq("(", optional(field("parameters", $.parameters)), ")"),
|
||||
|
||||
parameter_list: ($) => sep1($.parameter, kSemicolon),
|
||||
parameters: ($) => sep1(field("parameter", $.parameter), kSemicolon),
|
||||
|
||||
parameter: ($) =>
|
||||
seq(
|
||||
optional(choice(kw("var"), kw("out"))),
|
||||
sep1(field("name", $.identifier), ","),
|
||||
optional(field("type", $._type_clause)),
|
||||
optional($._type_clause),
|
||||
optional(seq("=", field("default", $.expression))),
|
||||
),
|
||||
|
||||
|
|
@ -1184,9 +1185,10 @@ module.exports = grammar({
|
|||
class_member: ($) =>
|
||||
choice(
|
||||
field("access_modifier", $.access_modifier),
|
||||
field("reference_modifier", $.reference_modifier),
|
||||
choice(
|
||||
$.variable_declaration,
|
||||
$.method_declaration,
|
||||
$._method_declaration,
|
||||
$.property_declaration,
|
||||
),
|
||||
$.uses_statement,
|
||||
|
|
@ -1198,7 +1200,7 @@ module.exports = grammar({
|
|||
variable_declaration: ($) =>
|
||||
seq(
|
||||
optional($._reference_tag),
|
||||
field("variables", $.member_variable),
|
||||
field("variable", $.member_variable),
|
||||
kSemicolon,
|
||||
),
|
||||
|
||||
|
|
@ -1207,13 +1209,15 @@ module.exports = grammar({
|
|||
|
||||
reference_modifier: (_) => choice(kw("weakref"), kw("autoref")),
|
||||
|
||||
member_variable: ($) =>
|
||||
choice($.static_declaration, $.nostatic_declaration),
|
||||
member_variable: ($) => choice($.static_member_variable, $.field_member_variable),
|
||||
|
||||
nostatic_declaration: ($) =>
|
||||
seq($._variable_declaration, optional($._type_clause)),
|
||||
static_member_variable: ($) =>
|
||||
seq(kw("static"), $._variable_declaration, optional($._type_clause), optional(seq("=", field("initial_value", $._right_hand_side)))),
|
||||
|
||||
method_declaration: ($) =>
|
||||
field_member_variable: ($) =>
|
||||
seq($._variable_declaration, optional($._type_clause), optional(seq("=", field("initial_value", $._right_hand_side)))),
|
||||
|
||||
_method_declaration: ($) =>
|
||||
choice(
|
||||
$.method_declaration_only,
|
||||
$.method_with_modifier,
|
||||
|
|
@ -1239,7 +1243,7 @@ module.exports = grammar({
|
|||
kSemicolon,
|
||||
field("modifier", $.method_modifier),
|
||||
kSemicolon,
|
||||
optional(seq(field("body", $.block_statement), optional(kSemicolon))),
|
||||
optional(seq(field("body", $.block_suite), optional(kSemicolon))),
|
||||
),
|
||||
|
||||
method_with_implementation: ($) =>
|
||||
|
|
@ -1250,13 +1254,13 @@ module.exports = grammar({
|
|||
$._parameter_signature,
|
||||
optional(field("return_type", $._type_clause)),
|
||||
optional(kSemicolon),
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
method_name: ($) =>
|
||||
choice(
|
||||
$._assignable_identifier,
|
||||
$._identifier_like,
|
||||
// $.identifier,
|
||||
$.operator_overload,
|
||||
),
|
||||
|
|
@ -1279,35 +1283,35 @@ module.exports = grammar({
|
|||
kSemicolon,
|
||||
),
|
||||
|
||||
_property_index: ($) => seq(kw("index"), choice($.number, $.string)),
|
||||
_property_index: ($) => seq(kw("index"), field("index", choice($.number, $.string))),
|
||||
|
||||
property_accessors: ($) =>
|
||||
choice(
|
||||
$.read_only_accessor,
|
||||
$.write_only_accessor,
|
||||
$.read_write_accessor,
|
||||
$.write_read_accessor,
|
||||
$._read_only_accessor,
|
||||
$._write_only_accessor,
|
||||
$._read_write_accessor,
|
||||
$._write_read_accessor,
|
||||
),
|
||||
|
||||
read_only_accessor: ($) => seq(kw("read"), $.identifier),
|
||||
_read_only_accessor: ($) => seq(kw("read"), field("read", $.identifier)),
|
||||
|
||||
write_only_accessor: ($) => seq(kw("write"), $.identifier),
|
||||
_write_only_accessor: ($) => seq(kw("write"), field("write", $.identifier)),
|
||||
|
||||
read_write_accessor: ($) =>
|
||||
seq(kw("read"), $.identifier, kw("write"), $.identifier),
|
||||
_read_write_accessor: ($) =>
|
||||
seq(kw("read"), field("read", $.identifier), kw("write"), field("write", $.identifier)),
|
||||
|
||||
write_read_accessor: ($) =>
|
||||
seq(kw("write"), $.identifier, kw("read"), $.identifier),
|
||||
_write_read_accessor: ($) =>
|
||||
seq(kw("write"), field("write", $.identifier), kw("read"), field("read", $.identifier)),
|
||||
|
||||
// 类外方法实现
|
||||
external_method_statement: ($) =>
|
||||
choice($.modifier_method, $.operator_method, $.normal_method),
|
||||
choice($._modifier_method, $._operator_method, $._normal_method),
|
||||
|
||||
matrix_iteration_statement: ($) =>
|
||||
seq(
|
||||
field("target", $.expression),
|
||||
"::",
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
|
|
@ -1364,7 +1368,7 @@ module.exports = grammar({
|
|||
html_comment: (_) =>
|
||||
token(seq("<!--", repeat(choice(/[^-]/, /-[^-]/, /--[^>]/)), "-->")),
|
||||
|
||||
modifier_method: ($) =>
|
||||
_modifier_method: ($) =>
|
||||
seq(
|
||||
kw("function"),
|
||||
$._qualified_method_name,
|
||||
|
|
@ -1373,14 +1377,14 @@ module.exports = grammar({
|
|||
kSemicolon,
|
||||
field("modifier", $.method_modifier),
|
||||
kSemicolon,
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
operator_method: ($) =>
|
||||
_operator_method: ($) =>
|
||||
choice($._operator_method, $._operator_method_with_modifier),
|
||||
|
||||
normal_method: ($) =>
|
||||
_normal_method: ($) =>
|
||||
seq(
|
||||
optional($.class),
|
||||
kw("function"),
|
||||
|
|
@ -1388,7 +1392,7 @@ module.exports = grammar({
|
|||
$._parameter_signature,
|
||||
optional(field("return_type", $._type_clause)),
|
||||
optional(kSemicolon),
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
|
|
@ -1402,7 +1406,7 @@ module.exports = grammar({
|
|||
$._parameter_signature,
|
||||
optional(field("return_type", $._type_clause)),
|
||||
optional(kSemicolon),
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
|
|
@ -1418,7 +1422,7 @@ module.exports = grammar({
|
|||
kSemicolon,
|
||||
field("modifier", $.method_modifier),
|
||||
kSemicolon,
|
||||
field("body", $.block_statement),
|
||||
field("body", $.block_suite),
|
||||
optional(kSemicolon),
|
||||
),
|
||||
|
||||
|
|
@ -1444,16 +1448,16 @@ module.exports = grammar({
|
|||
),
|
||||
|
||||
interface_section: ($) =>
|
||||
seq(kw("interface"), optional(repeat($._statement))),
|
||||
seq(kw("interface"), repeat($._statement)),
|
||||
|
||||
implementation_section: ($) =>
|
||||
seq(kw("implementation"), optional(repeat($._statement))),
|
||||
seq(kw("implementation"), repeat($._statement)),
|
||||
|
||||
initialization_section: ($) =>
|
||||
seq(kw("initialization"), optional(repeat($._statement))),
|
||||
seq(kw("initialization"), repeat($._statement)),
|
||||
|
||||
finalization_section: ($) =>
|
||||
seq(kw("finalization"), optional(repeat($._statement))),
|
||||
seq(kw("finalization"), repeat($._statement)),
|
||||
|
||||
uses_statement: ($) =>
|
||||
seq(kw("uses"), sep1(field("module", $.identifier), ","), kSemicolon),
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue