This commit is contained in:
ProgramSnail 2023-03-31 12:10:12 +03:00
parent 582ad5668e
commit 0d62ae0814
29 changed files with 99479 additions and 1166 deletions

View file

@ -8,10 +8,18 @@ find_package(Catch2 2 REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
include_directories(include)
include(tree_sitter/api.h)
include_directories(include
tree-sitter/lib/src
tree-sitter/lib/include)
# add_executable(interpreter_tests tests/tests.cpp)
# target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)
# add_executable(lang_interpreter src/main.cpp)
add_executable(lang_interpreter src/main.cpp
src/visitor.cpp
src/build_visitor.cpp
src/print_visitor.cpp
src/parser.c
include/parser.h
tree-sitter/lib/src/lib.c)

View file

@ -526,6 +526,7 @@ struct AnnotatedType : public Node {
};
using TypeParameter = std::variant<
std::unique_ptr<TypeExpression>,
std::unique_ptr<ParametrizedType>,
std::unique_ptr<Expression>>;

View file

@ -5,6 +5,7 @@
// for clangd
#include "tree_sitter/api.h"
extern "C" const TSLanguage* tree_sitter_LANG();
namespace parser {
@ -12,31 +13,76 @@ class ParseTree {
public:
class Node {
public:
std::string GetType();
std::pair<size_t, size_t> GetStartPoint();
std::pair<size_t, size_t> GetEndPoint();
std::string GetAsSExpression();
Node() = default;
Node(const TSNode &node, const std::string* source) : node_(node), source_(source) {}
std::string GetValue(); // from source
std::string GetType() {
return ts_node_type(node_);
}
bool IsNull();
bool IsNamed();
bool IsMissing();
bool IsExtra(); // comments, etc.
bool HasError();
std::pair<size_t, size_t> GetStartPoint() {
TSPoint point = ts_node_start_point(node_);
return {point.row, point.column};
}
Node NthChild(size_t n);
size_t ChildCount();
std::pair<size_t, size_t> GetEndPoint() {
TSPoint point = ts_node_end_point(node_);
return {point.row, point.column};
}
Node NthNamedChild(size_t n);
size_t NamedChildCount();
std::string GetAsSExpression() {
return ts_node_string(node_);
}
Node ChildByFieldName(const std::string& name);
std::string GetValue() { // from source
size_t start = ts_node_start_byte(node_);
size_t end = ts_node_end_byte(node_);
return source_->substr(start, end - start); // TODO check
}
bool IsNull() {
return ts_node_is_null(node_);
}
bool IsNamed() {
return ts_node_is_named(node_);
}
bool IsMissing() {
return ts_node_is_missing(node_);
}
bool IsExtra() { // comments, etc.
return ts_node_is_extra(node_);
}
bool HasError() {
return ts_node_has_error(node_);
}
Node NthChild(size_t n) {
return Node(ts_node_child(node_, n), source_);
}
size_t ChildCount() {
return ts_node_child_count(node_);
}
Node NthNamedChild(size_t n) {
return Node(ts_node_named_child(node_, n), source_);
}
size_t NamedChildCount() {
return ts_node_named_child_count(node_);
}
Node ChildByFieldName(const std::string& name) {
return Node(ts_node_child_by_field_name(node_, name.c_str(), name.size()), source_);
}
// ?? use field id instaed of name ??
// ?? node equality check needed ??
private:
TSNode node_;
const std::string* source_ = nullptr;
};
class Cursor { // ?? needed ??
public:
@ -54,12 +100,24 @@ public:
TSTreeCursor cursor_;
};
ParseTree(const std::string& input);
ParseTree(const std::string& source) : source_(source) {
TSParser* parser = ts_parser_new();
ts_parser_set_language(parser, tree_sitter_LANG());
tree_ = ts_parser_parse_string(
parser,
NULL,
source_.c_str(),
source_.size());
}
Node GetRoot() const {
return Node(ts_tree_root_node(tree_), &source_);
}
Node GetRoot() const;
private:
TSTree* tree_;
std::string source; // for token value extraction
std::string source_; // for token value extraction
};
} // namespace parser

224
include/parser.h Normal file
View file

@ -0,0 +1,224 @@
#ifndef TREE_SITTER_PARSER_H_
#define TREE_SITTER_PARSER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#define ts_builtin_sym_error ((TSSymbol)-1)
#define ts_builtin_sym_end 0
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
typedef uint16_t TSStateId;
#ifndef TREE_SITTER_API_H_
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
#endif
typedef struct {
TSFieldId field_id;
uint8_t child_index;
bool inherited;
} TSFieldMapEntry;
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
typedef struct {
bool visible;
bool named;
bool supertype;
} TSSymbolMetadata;
typedef struct TSLexer TSLexer;
struct TSLexer {
int32_t lookahead;
TSSymbol result_symbol;
void (*advance)(TSLexer *, bool);
void (*mark_end)(TSLexer *);
uint32_t (*get_column)(TSLexer *);
bool (*is_at_included_range_start)(const TSLexer *);
bool (*eof)(const TSLexer *);
};
typedef enum {
TSParseActionTypeShift,
TSParseActionTypeReduce,
TSParseActionTypeAccept,
TSParseActionTypeRecover,
} TSParseActionType;
typedef union {
struct {
uint8_t type;
TSStateId state;
bool extra;
bool repetition;
} shift;
struct {
uint8_t type;
uint8_t child_count;
TSSymbol symbol;
int16_t dynamic_precedence;
uint16_t production_id;
} reduce;
uint8_t type;
} TSParseAction;
typedef struct {
uint16_t lex_state;
uint16_t external_lex_state;
} TSLexMode;
typedef union {
TSParseAction action;
struct {
uint8_t count;
bool reusable;
} entry;
} TSParseActionEntry;
struct TSLanguage {
uint32_t version;
uint32_t symbol_count;
uint32_t alias_count;
uint32_t token_count;
uint32_t external_token_count;
uint32_t state_count;
uint32_t large_state_count;
uint32_t production_id_count;
uint32_t field_count;
uint16_t max_alias_sequence_length;
const uint16_t *parse_table;
const uint16_t *small_parse_table;
const uint32_t *small_parse_table_map;
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
const uint16_t *alias_map;
const TSSymbol *alias_sequences;
const TSLexMode *lex_modes;
bool (*lex_fn)(TSLexer *, TSStateId);
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
TSSymbol keyword_capture_token;
struct {
const bool *states;
const TSSymbol *symbol_map;
void *(*create)(void);
void (*destroy)(void *);
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
unsigned (*serialize)(void *, char *);
void (*deserialize)(void *, const char *, unsigned);
} external_scanner;
const TSStateId *primary_state_ids;
};
/*
* Lexer Macros
*/
#define START_LEXER() \
bool result = false; \
bool skip = false; \
bool eof = false; \
int32_t lookahead; \
goto start; \
next_state: \
lexer->advance(lexer, skip); \
start: \
skip = false; \
lookahead = lexer->lookahead;
#define ADVANCE(state_value) \
{ \
state = state_value; \
goto next_state; \
}
#define SKIP(state_value) \
{ \
skip = true; \
state = state_value; \
goto next_state; \
}
#define ACCEPT_TOKEN(symbol_value) \
result = true; \
lexer->result_symbol = symbol_value; \
lexer->mark_end(lexer);
#define END_STATE() return result;
/*
* Parse Table Macros
*/
#define SMALL_STATE(id) id - LARGE_STATE_COUNT
#define STATE(id) id
#define ACTIONS(id) id
#define SHIFT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value \
} \
}}
#define SHIFT_REPEAT(state_value) \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.state = state_value, \
.repetition = true \
} \
}}
#define SHIFT_EXTRA() \
{{ \
.shift = { \
.type = TSParseActionTypeShift, \
.extra = true \
} \
}}
#define REDUCE(symbol_val, child_count_val, ...) \
{{ \
.reduce = { \
.type = TSParseActionTypeReduce, \
.symbol = symbol_val, \
.child_count = child_count_val, \
__VA_ARGS__ \
}, \
}}
#define RECOVER() \
{{ \
.type = TSParseActionTypeRecover \
}}
#define ACCEPT_INPUT() \
{{ \
.type = TSParseActionTypeAccept \
}}
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_PARSER_H_

View file

@ -1,8 +1,10 @@
#include <iostream>
#include <memory>
// forclangd
#include "../include/build_visitor.hpp"
#include "../include/parse_token_types.hpp"
#include <bits/utility.h>
#include <memory>
namespace interpreter {
@ -77,6 +79,7 @@ void BuildVisitor::Visit(Namespace* node) {
auto current_node_ = parse_node.ChildByFieldName("name");
auto current_node_type = current_node_.GetType();
if (current_node_type == parser::tokens::DefinedAnnotatedName) {
std::string name_modifier = parse_node.NthChild(1).GetValue(); // TODO
if (name_modifier == "const") {
@ -254,10 +257,11 @@ void BuildVisitor::Visit(TypeclassDefinition* node) {
size_t child_count = parse_node.NamedChildCount();
if (child_count > 1) {
node->requirements.resize(child_count - 1, std::make_unique<FunctionDeclaration>());
node->requirements.resize(child_count - 1);
for (size_t i = 0; i < child_count - 1; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
node->requirements[i] = std::make_unique<FunctionDeclaration>();
Visit(node->requirements[i].get());
}
}
@ -463,12 +467,23 @@ void BuildVisitor::Visit(DefinitionParameter* node) {
size_t child_count = parse_node.NamedChildCount();
if (child_count > 1) {
node->typeclasses.resize(child_count - 1, std::make_unique<ParametrizedTypeclass>());
node->typeclasses.resize(child_count - 1);
for (size_t i = 0; i < child_count - 1; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
std::string current_node_type = current_node_.GetType();
node->typeclasses[i] = std::make_unique<ParametrizedTypeclass>();
if (current_node_type == parser::tokens::TypeclassExpression) { // optimize ??
node->typeclasses[i]->typeclass_expression = std::make_unique<TypeclassExpression>();
Visit(node->typeclasses[i]->typeclass_expression.get());
} else if (current_node_type == parser::tokens::ParametrizedTypeclass) {
Visit(node->typeclasses[i].get());
// choose between typeclass_expression and parametrized_typeclass
} else {
// error
}
}
}
@ -483,12 +498,23 @@ void BuildVisitor::Visit(DefinitionArgument* node) {
size_t child_count = parse_node.NamedChildCount();
if (child_count > 1) {
node->types.resize(child_count - 1, std::make_unique<ParametrizedType>());
node->types.resize(child_count - 1);
for (size_t i = 0; i < child_count - 1; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
std::string current_node_type = current_node_.GetType();
node->types[i] = std::make_unique<ParametrizedType>();
if (current_node_type == parser::tokens::TypeExpression) { // optimize ??
node->types[i]->type_expression = std::make_unique<TypeExpression>();
Visit(node->types[i]->type_expression.get());
} else if (current_node_type == parser::tokens::ParametrizedType) {
Visit(node->types[i].get());
// choose between type_expression and parametrized_type
} else {
// error
}
}
}
@ -1079,10 +1105,11 @@ void BuildVisitor::Visit(TupleName* node) {
size_t names_count = parse_node.NamedChildCount();
node->names.resize(names_count, std::make_unique<AnnotatedName>());
node->names.resize(names_count);
for (size_t i = 0; i < names_count; ++i) {
current_node_ = parse_node.NthNamedChild(i);
node->names[i] = std::make_unique<AnnotatedName>();
Visit(node->names[i].get());
}
@ -1094,10 +1121,11 @@ void BuildVisitor::Visit(VariantName* node) {
size_t names_count = parse_node.NamedChildCount();
node->names.resize(names_count, std::make_unique<AnnotatedName>());
node->names.resize(names_count);
for (size_t i = 0; i < names_count; ++i) {
current_node_ = parse_node.NthNamedChild(i);
node->names[i] =std::make_unique<AnnotatedName>();
Visit(node->names[i].get());
}
@ -1109,7 +1137,7 @@ void BuildVisitor::Visit(AnnotatedName* node) {
node->name = parse_node.ChildByFieldName("name").GetValue();
if (parse_node.ChildCount() > 1) {
if (parse_node.NamedChildCount() > 1) {
current_node_ = parse_node.ChildByFieldName("type");
node->type = std::make_unique<ParametrizedType>();
Visit(node->type.value().get());
@ -1144,27 +1172,27 @@ void BuildVisitor::Visit(AnyName& node) {
// Type
void BuildVisitor::Visit(TypeConstructor* node) {
auto parse_node = current_node_;
current_node_ = parse_node.ChildByFieldName("type");
node->type = std::make_unique<ParametrizedType>();
Visit(node->type.get());
size_t parameter_count = (parse_node.NamedChildCount() - 1) / 2;
node->parameters.resize(parameter_count);
for (size_t i = 0; i < parameter_count * 2; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
if (i % 2 == 0) {
node->parameters[i / 2].first = current_node_.GetValue();
} else {
Visit(node->parameters[i / 2].second);
}
}
current_node_ = parse_node;
// auto parse_node = current_node_;
//
// current_node_ = parse_node.ChildByFieldName("type");
// node->type = std::make_unique<ParametrizedType>();
// Visit(node->type.get());
//
// size_t parameter_count = (parse_node.NamedChildCount() - 1) / 2;
//
// node->parameters.resize(parameter_count);
//
// for (size_t i = 0; i < parameter_count * 2; ++i) {
// current_node_ = parse_node.NthNamedChild(i + 1);
//
// if (i % 2 == 0) {
// node->parameters[i / 2].first = current_node_.GetValue();
// } else {
// Visit(node->parameters[i / 2].second);
// }
// }
//
// current_node_ = parse_node;
}
void BuildVisitor::Visit(TupleType* node) {
@ -1245,11 +1273,23 @@ void BuildVisitor::Visit(AnnotatedType* node) {
size_t child_count = parse_node.NamedChildCount();
if (child_count > 1) {
node->annotations.resize(child_count - 1, std::make_unique<ParametrizedTypeclass>());
node->annotations.resize(child_count - 1);
for (size_t i = 0; i < child_count - 1; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
std::string current_node_type = current_node_.GetType();
node->annotations[i] = std::make_unique<ParametrizedTypeclass>();
if (current_node_type == parser::tokens::TypeclassExpression) { // optimize ??
node->annotations[i]->typeclass_expression = std::make_unique<TypeclassExpression>();
Visit(node->annotations[i]->typeclass_expression.get());
} else if (current_node_type == parser::tokens::ParametrizedTypeclass) {
Visit(node->annotations[i].get());
} else {
// error
}
}
}
@ -1296,7 +1336,7 @@ void BuildVisitor::Visit(TypeExpression* node) {
current_node_ = parse_node;
}
void BuildVisitor::Visit(AnyType& node) {
void BuildVisitor::Visit(AnyType& node) { // Or ScopedAnyType
auto parse_node = current_node_;
current_node_ = parse_node.NthNamedChild(0);
@ -1349,7 +1389,10 @@ void BuildVisitor::Visit(TypeParameter& node) {
std::string current_node_type = current_node_.GetType();
if (current_node_type == parser::tokens::ParametrizedType) { // optimize ??
if (current_node_type == parser::tokens::TypeExpression) { // optimize ??
node = std::make_unique<TypeExpression>();
Visit(std::get<std::unique_ptr<TypeExpression>>(node).get());
} else if (current_node_type == parser::tokens::ParametrizedType) {
node = std::make_unique<ParametrizedType>();
Visit(std::get<std::unique_ptr<ParametrizedType>>(node).get());
} else if (current_node_type == parser::tokens::Expression) {
@ -1374,11 +1417,23 @@ void BuildVisitor::Visit(AnnotatedTypeclass* node) {
size_t child_count = parse_node.NamedChildCount();
if (child_count > 1) {
node->annotations.resize(child_count - 1, std::make_unique<ParametrizedTypeclass>());
node->annotations.resize(child_count - 1);
for (size_t i = 0; i < child_count - 1; ++i) {
current_node_ = parse_node.NthNamedChild(i + 1);
std::string current_node_type = current_node_.GetType();
node->annotations[i] = std::make_unique<ParametrizedTypeclass>();
if (current_node_type == parser::tokens::TypeclassExpression) { // optimize ??
node->annotations[i]->typeclass_expression = std::make_unique<TypeclassExpression>();
Visit(node->annotations[i]->typeclass_expression.get());
} else if (current_node_type == parser::tokens::ParametrizedTypeclass) {
Visit(node->annotations[i].get());
} else {
// error
}
}
}

40
src/main.cpp Normal file
View file

@ -0,0 +1,40 @@
#include <fstream>
#include <iostream>
#include <sstream>
// for clangd
#include "../include/parse_tree.hpp"
#include "../include/interpreter_tree.hpp"
#include "../include/build_visitor.hpp"
#include "../include/print_visitor.hpp"
int main(int argc, char** argv) { // TODO, only test version
if (argc < 2 || argc > 2) {
std::cout << "Wrong argument count (provide one argument - source file)\n";
return 0;
}
std::string filename = argv[1];
std::ifstream in;
in.open(filename); // TODO handle errors
std::stringstream source_stream;
source_stream << in.rdbuf();
in.close();
std::string source = source_stream.str();
parser::ParseTree parse_tree(source);
std::unique_ptr<interpreter::tokens::SourceFile> source_file =
std::make_unique<interpreter::tokens::SourceFile>();
interpreter::BuildVisitor build_visitor(parse_tree);
interpreter::PrintVisitor print_visitor(std::cout);
build_visitor.VisitSourceFile(source_file.get());
//print_visitor.VisitSourceFile(source_file.get());
}

View file

@ -1,12 +0,0 @@
// for clangd
#include "../include/node.hpp"
#include "../include/visitor.hpp"
namespace interpreter {
/*void Node::Accept(Visitor* visitor) {
visitor->Visit(this);
}*/
} // namespace interpreter

98452
src/parser.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,7 @@ void PrintVisitor::Visit(Node* node) {
// Sources -----------------
void PrintVisitor::Visit(SourceFile* node) {
out_ << "<SourceFile>\n\n";
out_ << "(SourceFile\n\n";
for (auto& statement : node->statements) {
if (std::holds_alternative<Partition>(statement)) {
Visit(&std::get<Partition>(statement));
@ -19,21 +19,21 @@ void PrintVisitor::Visit(SourceFile* node) {
// error
}
}
out_ << "\n<SourceFile/>";
out_ << "\nSourceFile)\n";
}
void PrintVisitor::Visit(Sources* node) {
out_ << "<Sources>\n\n";
out_ << "(Sources\n\n";
for (auto& statement : node->statements) {
Visitor::Visit(statement);
}
out_ << "\n</Sources>";
out_ << "\n)\n";
}
// Namespaces, partittions -----------------
void PrintVisitor::Visit(Partition* node) {
out_ << "<Partition> ";
out_ << "(Partition ";
switch (node->type) {
case Partition::Test:
out_ << "TEST";
@ -56,11 +56,11 @@ void PrintVisitor::Visit(Partition* node) {
}
out_ << " {\n";
Visit(node->scope.get());
out_ << "} </Partition>\n";
out_ << "} )\n";
}
void PrintVisitor::Visit(Namespace* node) {
out_ << "<Namespace> ";
out_ << "(Namespace ";
if (std::holds_alternative<std::unique_ptr<DefinedAnnotatedName>>(node->name)) {
if (node->is_const) {
out_ << "const ";
@ -75,13 +75,13 @@ void PrintVisitor::Visit(Namespace* node) {
}
out_ << "{\n";
Visit(node->scope.get());
out_ << "} </Namespace>\n";
out_ << "} )\n";
}
// Definitions -----------------
void PrintVisitor::Visit(ImportStatement* node) {
out_ << "<Import> \"" << node->module_name << "\" ";
out_ << "(Import \"" << node->module_name << "\" ";
if (node->symbols.size() > 0) {
out_ << '\n';
}
@ -89,35 +89,35 @@ void PrintVisitor::Visit(ImportStatement* node) {
Visitor::Visit(symbol);
out_ << '\n';
}
out_ << "</Import>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(UsageDefinition* node) {
out_ << "<Usage> ";
out_ << "(Usage ";
Visit(&node->name);
out_ << " = ";
Visit(node->import_statement.get());
out_ << "</Usage>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(AliasDefinition* node) {
out_ << "<Alias> ";
out_ << "(Alias ";
Visit(node->type.get());
out_ << " = ";
Visit(node->value.get());
out_ << "</Alias>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(VariableDefinition* node) {
out_ << "<Variable> " << (node->is_const ? "const" : "var") << ' ';
out_ << "(Variable " << (node->is_const ? "const" : "var") << ' ';
Visit(&node->name);
out_ << " = ";
Visitor::Visit(node->value);
out_ << "</Variable>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(FunctionDeclaration* node) {
out_ << "<FunctionDeclaration> ";
out_ << "(FunctionDeclaration ";
Visit(&node->name);
out_ << "\n";
for (auto& parameter : node->parameters) {
@ -127,35 +127,35 @@ void PrintVisitor::Visit(FunctionDeclaration* node) {
for (auto& argument_type : node->argument_types) {
Visitor::Visit(argument_type);
}
out_ << "</FunctionDeclaration>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(FunctionDefinition* node) {
out_ << "<Function> ";
out_ << "(Function ";
Visit(node->name.get());
out_ << " = ";
Visitor::Visit(node->value);
out_ << "</Function>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(AliasTypeDefinition* node) {
out_ << "<AliasType> ";
out_ << "(AliasType ";
Visit(node->type.get());
out_ << " = ";
Visit(node->value.get());
out_ << "</AliasType>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(TypeDefinition* node) {
out_ << "<Type> ";
out_ << "(Type ";
Visit(node->type.get());
out_ << " = ";
Visitor::Visit(node->value);
out_ << "</Type>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(TypeclassDefinition* node) {
out_ << "<Typeclass> ";
out_ << "(Typeclass ";
Visit(node->typeclass.get());
if (node->requirements.size() > 0) {
out_ << " : \n";
@ -164,13 +164,13 @@ void PrintVisitor::Visit(TypeclassDefinition* node) {
out_ << "& ";
Visit(requirement.get());
}
out_ << "</Typeclass>\n";
out_ << ")\n";
}
// Definition parts
void PrintVisitor::Visit(DefinedName* node) {
out_ << "<DefinedName> ";
out_ << "(DefinedName ";
Visit(&node->name);
if (node->parameters.size() > 0) {
out_ << "\n";
@ -184,11 +184,11 @@ void PrintVisitor::Visit(DefinedName* node) {
for (auto& argument : node->arguments) {
Visit(argument.get());
}
out_ << "</DefinedName>\n";
out_ << ")";
}
void PrintVisitor::Visit(DefinedAnnotatedName* node) {
out_ << "<DefinedAnnotatedName> ";
out_ << "(DefinedAnnotatedName ";
Visit(&node->name);
out_ << " : ";
if (std::holds_alternative<std::unique_ptr<DefinedType>>(node->type)) {
@ -198,11 +198,11 @@ void PrintVisitor::Visit(DefinedAnnotatedName* node) {
} else {
// no annotation
}
out_ << " </DefinedAnnotatedName>";
out_ << " )";
}
void PrintVisitor::Visit(DefinedType* node) {
out_ << "<DefinedType> ";
out_ << "(DefinedType ";
Visit(node->type.get());
if (node->parameters.size() > 0) {
out_ << "\n";
@ -216,11 +216,11 @@ void PrintVisitor::Visit(DefinedType* node) {
for (auto& argument : node->arguments) {
Visit(argument.get());
}
out_ << "</DefinedType>\n";
out_ << ")";
}
void PrintVisitor::Visit(DefinedTypeclass* node) {
out_ << "<DefinedTypeclass> ";
out_ << "(DefinedTypeclass ";
Visit(node->typeclass.get());
if (node->parameters.size() > 0) {
out_ << "\n";
@ -234,33 +234,33 @@ void PrintVisitor::Visit(DefinedTypeclass* node) {
for (auto& argument : node->arguments) {
Visit(argument.get());
}
out_ << "</DefinedTypeclass>\n";
out_ << ")";
}
void PrintVisitor::Visit(DefinitionParameter* node) {
out_ << "<DefinitionParameter> " << (node->typeclasses.size() > 0 ? "(" : "");
out_ << "(DefinitionParameter " << (node->typeclasses.size() > 0 ? "(" : "");
Visit(&node->type);
out_ << ' ';
for (auto& typeclass : node->typeclasses) {
Visit(typeclass.get());
}
out_ << "</DefinitionParamater>\n";
out_ << ")";
}
void PrintVisitor::Visit(DefinitionArgument* node) {
out_ << "<DefinitionArgument> " << (node->types.size() > 0 ? "(" : "");
out_ << "(DefinitionArgument " << (node->types.size() > 0 ? "(" : "");
Visit(&node->name);
out_ << ' ';
for (auto& type : node->types) {
Visit(type.get());
}
out_ << "</DefinitionArgument>\n";
out_ << ")";
}
// Flow control -----------------
void PrintVisitor::Visit(MatchCase* node) {
out_ << "<MatchCase> | ";
out_ << "(MatchCase | ";
Visitor::Visit(node->value);
if (node->condition.has_value()) {
out_ << " ? ";
@ -270,21 +270,21 @@ void PrintVisitor::Visit(MatchCase* node) {
out_ << " -> ";
Visitor::Visit(node->statement.value());
}
out_ << "</MatchCase>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(Match* node) {
out_ << "<Match> ";
out_ << "(Match ";
Visitor::Visit(node->value);
out_ << " with\n";
for (auto& match_case : node->matches) {
Visit(&match_case);
}
out_ << "</Match>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(Condition* node) {
out_ << "<If> ";
out_ << "(If ";
Visitor::Visit(node->conditions[0]);
out_ << " then\n";
Visitor::Visit(node->statements[0]);
@ -301,63 +301,63 @@ void PrintVisitor::Visit(Condition* node) {
Visitor::Visit(node->statements[node->conditions.size()]);
out_ << '\n';
}
out_ << "</If>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(DoWhileLoop* node) {
out_ << "<DoWhile>\n";
out_ << "(DoWhile\n";
Visitor::Visit(node->statement);
out_ << "\nwhile\n";
Visitor::Visit(node->condition);
out_ << "\n</DoWhile>\n";
out_ << "\n)\n";
}
void PrintVisitor::Visit(WhileLoop* node) {
out_ << "<While>\n";
out_ << "(While\n";
Visitor::Visit(node->statement);
out_ << "\ndo\n";
Visitor::Visit(node->condition);
out_ << "\n</While>\n";
out_ << "\n)\n";
}
void PrintVisitor::Visit(ForLoop* node) {
out_ << "<For>\n";
out_ << "(For\n";
Visitor::Visit(node->variable);
out_ << "\nin\n";
Visitor::Visit(node->interval);
out_ << "\ndo\n";
Visitor::Visit(node->statement);
out_ << "</For>\n";
out_ << ")\n";
}
void PrintVisitor::Visit(LoopLoop* node) {
out_ << "<Loop>\n";
out_ << "(Loop\n";
Visitor::Visit(node->statement);
out_ << "<\n/Loop>\n";
out_ << "\nLoop)\n";
}
// Statements, expressions, blocks, etc. -----------------
void PrintVisitor::Visit(Block* node) {
out_ << "<Block> {\n";
out_ << "(Block {\n";
for (auto& statement : node->statements) {
Visitor::Visit(statement);
}
out_ << "} </Block>\n";
out_ << "} )\n";
}
void PrintVisitor::Visit(ScopedStatement* node) {
out_ << "<Scoped> ( ";
out_ << "(Scoped ( ";
Visitor::Visit(node->statement);
out_ << " ) </Scoped>";
out_ << " ) )\n";
}
void PrintVisitor::Visit(LoopControlExpression& node) { // enum
switch (node) {
case LoopControlExpression::Break:
out_ << "<Break/>\n";
out_ << "(Break/>\n";
break;
case LoopControlExpression::Continue:
out_ << "<Continue/>\n";
out_ << "(Continue/>\n";
break;
}
}
@ -365,66 +365,66 @@ void PrintVisitor::Visit(LoopControlExpression& node) { // enum
// Operators
void PrintVisitor::Visit(BinaryOperatorExpression* node) {
out_ << "<BinaryOperator> ";
out_ << "(BinaryOperator ";
Visitor::Visit(node->left_expression);
out_ << ' ';
Visit(&node->operator_name);
out_ << ' ';
Visitor::Visit(node->right_expression);
out_ << " </BinaryOperator>";
out_ << " )";
}
void PrintVisitor::Visit(UnaryOperatorExpression* node) {
out_ << "<UnaryOperator> ";
out_ << "(UnaryOperator ";
Visit(&node->operator_name);
out_ << ' ';
Visitor::Visit(node->expression);
out_ << " </UnaryOperator>";
out_ << " )";
}
// Simple Expressions
void PrintVisitor::Visit(FunctionCallExpression* node) {
out_ << "<FunctionCall> ";
out_ << "(FunctionCall ";
Visit(node->name.get());
out_ << ' ';
for (auto& argument : node->arguments) {
Visitor::Visit(argument);
out_ << ' ';
}
out_ << "</FunctionCall>";
out_ << ")\n";
}
void PrintVisitor::Visit(TupleExpression* node) {
out_ << "<TupleExpression> ";
out_ << "(TupleExpression ";
out_ << ' ';
for (auto& expression : node->expressions) {
out_ << "& ";
Visitor::Visit(expression);
}
out_ << " </TupleExpression>";
out_ << " )\n";
}
void PrintVisitor::Visit(VariantExpression* node) {
out_ << "<VariantExpression> ";
out_ << "(VariantExpression ";
out_ << ' ';
for (auto& expression : node->expressions) {
out_ << "& ";
Visitor::Visit(expression);
}
out_ << " </VariantExpression>";
out_ << " )\n";
}
void PrintVisitor::Visit(ReturnExpression* node) {
out_ << "<Return> ";
out_ << "(Return ";
Visitor::Visit(node->expression);
out_ << " </Return>";
out_ << " )\n";
}
// Lambda
void PrintVisitor::Visit(LambdaFunction* node) {
out_ << "<LambdaFunction> \\ ";
out_ << "(LambdaFunction \\ ";
for (auto& parameter : node->parameters) {
Visit(parameter.get());
}
@ -436,73 +436,73 @@ void PrintVisitor::Visit(LambdaFunction* node) {
}
out_ << " -> ";
Visitor::Visit(node->expression);
out_ << " </LambdaFunction>";
out_ << " )\n";
}
// Name
void PrintVisitor::Visit(NameSuperExpression* node) {
out_ << "<NameSuperExpression> ";
out_ << "(NameSuperExpression ";
for (auto& variable_namespace : node->namespaces) {
Visitor::Visit(variable_namespace);
out_ << '.';
}
for (int i = 0; i < node->expressions.size(); ++i) {
for (size_t i = 0; i < node->expressions.size(); ++i) {
Visitor::Visit(node->expressions[i]);
if (i + 1 < node->expressions.size()) {
out_ << '.';
}
}
out_ << "</NameSupperExpression>\n";
out_ << ")";
}
void PrintVisitor::Visit(NameExpression* node) {
out_ << "<NameExpression> ";
out_ << "(NameExpression ";
for (auto& variable_namespace : node->namespaces) {
Visitor::Visit(variable_namespace);
out_ << '.';
}
for (int i = 0; i < node->names.size(); ++i) {
for (size_t i = 0; i < node->names.size(); ++i) {
Visit(&node->names[i]);
if (i + 1 < node->names.size()) {
out_ << '.';
}
}
out_ << "</NameExpression>\n";
out_ << ")";
}
void PrintVisitor::Visit(TupleName* node) {
out_ << "<TupleName> ";
out_ << "(TupleName ";
for (auto& name : node->names) {
out_ << '&';
Visit(name.get());
}
out_ << "</TupleName>\n";
out_ << ")";
}
void PrintVisitor::Visit(VariantName* node) {
out_ << "<VariantName> ";
out_ << "(VariantName ";
for (auto& name : node->names) {
out_ << '|';
Visit(name.get());
}
out_ << "</VariantName>\n";
out_ << ")";
}
void PrintVisitor::Visit(AnnotatedName* node) {
out_ << "<AnnotatedName> ";
out_ << "(AnnotatedName ";
Visit(&node->name);
if (node->type.has_value()) {
out_ << " : ";
Visit(node->type.value().get());
}
out_ << " </AnnotatedName>";
out_ << " )";
}
// Type
void PrintVisitor::Visit(TypeConstructor* node) {
out_ << "<TypeConstructor> ";
out_ << "(TypeConstructor ";
Visit(node->type.get());
out_ << '\n';
for (auto& parameter : node->parameters) {
@ -511,13 +511,13 @@ void PrintVisitor::Visit(TypeConstructor* node) {
Visitor::Visit(parameter.second);
out_ << '\n';
}
out_ << "</TypeConstructor>\n";
out_ << ")";
}
void PrintVisitor::Visit(TupleType* node) {
out_ << "<TupleType> ";
out_ << "(TupleType ";
if (node->type.has_value()) {
Visit(&node->type.value()); // optional
Visit(&node->type.value());
}
out_ << ' ';
for (auto& entity : node->entities) {
@ -528,11 +528,11 @@ void PrintVisitor::Visit(TupleType* node) {
}
Visitor::Visit(entity.second);
}
out_ << "</TupleType>";
out_ << ")";
}
void PrintVisitor::Visit(VariantType* node) {
out_ << "<VariantType> ";
out_ << "(VariantType ";
if (node->type.has_value()) {
Visit(&node->type.value());
}
@ -547,11 +547,11 @@ void PrintVisitor::Visit(VariantType* node) {
// error
}
}
out_ << "</VariantType>";
out_ << ")";
}
void PrintVisitor::Visit(AnnotatedType* node) {
out_ << "<AnnotatedType> ";
out_ << "(AnnotatedType ";
Visit(node->type_expression.get());
if (node->annotations.size() > 0) {
out_ << " :";
@ -560,33 +560,33 @@ void PrintVisitor::Visit(AnnotatedType* node) {
out_ << " ";
Visit(annotation.get());
}
out_ << "</AnnotatedType>";
out_ << ")";
}
void PrintVisitor::Visit(ParametrizedType* node) {
out_ << "<ParametrizedType> ";
out_ << "(ParametrizedType ";
Visit(node->type_expression.get());
for (auto& paramater : node->parameters) {
out_ << ' ';
Visitor::Visit(paramater);
}
out_ << " </ParamtrizedType>";
out_ << " )";
}
void PrintVisitor::Visit(TypeExpression* node) {
out_ << "<TypeExpression> ";
out_ << "(TypeExpression ";
for (auto& type_namespace : node->namespaces) {
Visitor::Visit(type_namespace);
out_ << '.';
}
Visit(&node->type);
out_ << " </TypeExpression>";
out_ << " )";
}
// Typeclass
void PrintVisitor::Visit(AnnotatedTypeclass* node) {
out_ << "<AnnotatedTypeclass> ";
out_ << "(AnnotatedTypeclass ";
Visit(node->typeclass_expression.get());
if (node->annotations.size() > 0) {
out_ << " :";
@ -595,49 +595,49 @@ void PrintVisitor::Visit(AnnotatedTypeclass* node) {
out_ << " ";
Visit(annotation.get());
}
out_ << "</AnnotatedTypeclass>";
out_ << ")";
}
void PrintVisitor::Visit(ParametrizedTypeclass* node) {
out_ << "<ParametrizedTypeclass> ";
out_ << "(ParametrizedTypeclass ";
Visit(node->typeclass_expression.get());
for (auto& paramater : node->parameters) {
out_ << ' ';
Visitor::Visit(paramater);
}
out_ << " </ParamtrizedTypeclass>";
out_ << " )";
}
void PrintVisitor::Visit(TypeclassExpression* node) {
out_ << "<TypeclassExpression> ";
out_ << "(TypeclassExpression ";
for (auto& typeclass_namespace : node->namespaces) {
Visitor::Visit(typeclass_namespace);
out_ << '.';
}
Visit(&node->typeclass);
out_ << " </TypeclassExpression>";
out_ << " )";
}
// Identifiers, constants, etc. -----------------
void PrintVisitor::Visit(AnyIdentifier* node) { // std::string
out_ << "<Identifier " << *node << " />";
out_ << "(Identifier " << *node << " )";
}
void PrintVisitor::Visit(FloatNumberLiteral* node) {
out_ << "<Identifier " << node->value << " />";
out_ << "(FloatNumber " << node->value << " )";
}
void PrintVisitor::Visit(NumberLiteral* node) {
out_ << "<Number " << node->value << " />";
out_ << "(Number " << node->value << " )";
}
void PrintVisitor::Visit(StringLiteral* node) {
out_ << "<String " << node->value << " />";
out_ << "(String " << node->value << " )";
}
void PrintVisitor::Visit(CharLiteral* node) {
out_ << "<Char " << node->value << " />";
out_ << "(Char " << node->value << " )";
}
} // namespace interpreter

View file

@ -265,7 +265,7 @@ void Visitor::Visit(AnyName& node) {
// Type
void Visitor::Visit(AnyType& node) {
void Visitor::Visit(AnyType& node) { // Or ScopedAnyType
switch (node.index()) {
case 0:
Visit(std::get<std::unique_ptr<ParametrizedType>>(node).get());
@ -301,9 +301,12 @@ void Visitor::Visit(TypeSubExpression& node) {
void Visitor::Visit(TypeParameter& node) {
switch (node.index()) {
case 0:
Visit(std::get<std::unique_ptr<ParametrizedType>>(node).get());
Visit(std::get<std::unique_ptr<TypeExpression>>(node).get());
break;
case 1:
Visit(std::get<std::unique_ptr<ParametrizedType>>(node).get());
break;
case 2:
Visit(*std::get<std::unique_ptr<Expression>>(node).get());
break;
default:

29
tests/arrays.lang Normal file
View file

@ -0,0 +1,29 @@
decl test_arrays : Unit -> Unit
def test_arrays = {
var arr1 = [1, 2, 3]
const arr2 = [] // empty array ??
var arr3 = [] : Int.5 // TODO: decide ??
const arr4= ['a'..'z']
const n = 100;
var @arr5 = @[] : @Int.n // unique pointer (??)
var @@arr6 = @@[] : @@Int.n // shared pointer (??)
var @@arr6_pointer = @@arr6
const elem1 = arr1.1
var elem2 = arr1.1
const *ref1 = *arr1.1 // reference <-> unmanaged pointer (??)
var *ref2 = *arr1.1
; *arr1.1 = 123
; ref1 = arr1.2 // set value
; *ref1 = *ref2 // set reference
// ?? references, that can't change ??
// ?? array access, array mutable access, array get reference to elem ??
// ?? arrays as basic type ??
// ?? custom allocators ??
}
// ????????????????????

69
tests/classes.lang Normal file
View file

@ -0,0 +1,69 @@
// ?? value - parametric classes ??
// struct fields/etc. accessible from everywere
// class fields/etc. accessible only from namespace of class or class instance (from "methods")
// points at the beginning of constructor name - amount of needed constructor prefixes ?
// ?? how to make class compositons ??
struct Fruit =
| Apple
| Orange
| Banana
struct Optional 'A =
| Some & 'A
| None
struct (Result : #Move) 'A 'B =
| & 'A
| Error & 'B
// struct (Complex : #Value) =
// & Float(0.0)
// & Float(0.0)
//
// struct Task =
// & name("Task") : String
// & duration(0.0) : Float
class Employee =
& name : String
& role :
( | Director
& importance : Float
& share : Float
| Manager
& productivity :
( Productivity
| .Low
| .Average
| .High
& duration : Float
& sleep_on_work :
(SleepOnWork
| ..Yes
| ..No
))
& salary : Int
| Programmer
& skills : Float
& current_task : Optional Task
& salary : Int)
class Bag =
&
( | Apple
| Orange
| Banana)
& bag_type :
( | Small
| Medium
& weight_kg : Int
& weight_g : Int
& weight_g : Int
| Big)
& other_things : Array Something

View file

@ -0,0 +1,43 @@
namespace Employee {
decl gen_employee : Unit -> Employee
def gen_employee = {
; a = b + c
return
$Employee
& name = "John"
& role =
($Manager
& name = "John"
& productivity =
($Productivity.High
& duration = 10.3
& sleep_on_work = ($Productivity.SleepOnWork.No))
& salary = 123)
}
}
/*
class Employee =
& name : String
& role :
( | Director
& importance : Float
& share : Float
| Manager
& productivity :
( Productivity
| .Low
| .Average
| .High
& duration : Float
& sleep_on_work :
(SleepOnWork
| ..Yes
| ..No
))
& salary : Int
| Programmer
& skills : Float
& current_task : Optional Task
& salary : Int)
*/

44
tests/flow_control.lang Normal file
View file

@ -0,0 +1,44 @@
decl flow_control_test : Unit -> Unit
def flow_control_test = {
// if && || a < b
// || a == b
// && b < c
// && c > 10
if ((a < b) || (a == b)) && (b < c)
then IO.print x
elif x < 0
then {
; ++x
; IO.print y
} else {
return {}
}
while (a > 0) && (!array.is_empty)
do {
; --a
; array.pop
}
while x < 10 do
x += x + 3
for i in 0..y do {
; IO.print i
}
for & i & j
in (& 0..y & 0..k)
do { // TODO: decide ??? does it work (like auto zip) ???
; IO.print 1
; IO.print 2
; IO.print 128
}
loop {
; ++y
if y > 100 then
break
}
}

70
tests/functions.lang Normal file
View file

@ -0,0 +1,70 @@
// "decl" is not required, but useful in module interface
decl sum ('A : #Add) : 'A -> 'A -> 'A
def sum : a b = a + b
decl fib : Int -> Int
def fib : n =
match n with
| 0 | 1 -> 1
| _ -> fib (n - 1) + fib n
decl fact : Int -> Int
def fact : n =
match n with
| 0 -> 1
| n -> n * fact (n - 1)
decl find_prefix_hashes ('H : (#AccHash Char)) : String -> Array 'H
def find_prefix_hashes ('H : (#AccHash Char)) : str = {
var hashes = (Array 'H).new (str.size + 1)
; hashes.0 = 'H.of str.0
for i in 1..hashes.size do {
; hashes.i = hashes.(i - 1).clone
; hashes.i.append str.i
}
return hashes
}
// ?? other default constructor symbol (instead of placeholder _), etc. ??
// seporate first and last iteration of loop ?
// previous and next iterations ?
decl find_substring : String -> String -> Array Index
def find_substring : str substr = {
alias Hash = AccHash Char
var result = (Array Index).empty
const str_hashes = find_prefix_hashes Hash str
const substr_hash = Hash.of substr
for i in 0..(str_hashes.size - substr.size) do {
const part_hash = Hash.diff str_hashes.(i + substr.size) str_hashes.i
if part_hash == substr_hash then {
; result.push i
}
}
return result
}
decl is_empty : Unit -> Bool
def is_empty =
return 0
decl do_something : Unit -> Unit
def do_something =
IO.print "Hello World!"
decl mul : Int -> Int -> Int
def mul : x y = x * y
decl mul_10 : Int -> Int
def mul_10 = mul 10 // or argument can be used
// ?? is partial application feature needed ??

18
tests/import.lang Normal file
View file

@ -0,0 +1,18 @@
import "module"
import "module" : func
import "module" :
func1
func2
func3
func4
func5
use ModuleNamespace = import "module"
use PartOfModuleNamespace =
import "module" :
func1
func2
func3
// ?? use ":" once again ??

15
tests/lambdas.lang Normal file
View file

@ -0,0 +1,15 @@
decl test_lambdas : Unit -> Unit
def test_lambdas = {
const lambda1 = \x -> x * x
// const lambda2 = \(x : #Hash) -> x.hash // ??
const lambda3 = \x y -> x + y
// TODO: type LambdaType = Int -> Int // ?? type keyword ??
// const typed_lambda = \x -> x + 1
const lambda4 = \x -> {
; IO.print x
const y = x + x
return y
}
}

15
tests/match.lang Normal file
View file

@ -0,0 +1,15 @@
def fruit_cost : fruit = {
return (match fruit with
| $Banana -> 11
| $Apple | $Orange -> 7)
}
def amount_to_string : x is_zero_separated = {
const ans = match x with
| 0 ? is_zero_separated -> "Zero"
| 0 | 1 | 2 | 3 | 4 -> "Few"
| x ? (5..9).contains x -> "Several"
| x ? (10..19).contains x -> "Pack"
| _ -> "Lots"
return ans
}

9
tests/memory.lang Normal file
View file

@ -0,0 +1,9 @@
struct StructWithRef =
& @Int._ // unique pointer to any-sized array (default size is zero ??)
decl test_memory : Unit -> Unit
def test_memory = {
const @unique_ref1 <- @5 // move unique reference
var @unique_ref2 <- @(Array.of 1 2 3)
// ?? reference to constant value ??
}

20
tests/namespaces.lang Normal file
View file

@ -0,0 +1,20 @@
namespace Namespace {
decl something : Unit
}
namespace Array 'A {
decl something : Unit
// "static methods" of Array 'a class
}
namespace Array ('A : #Copy) {
decl something : Unit
// "static methods" of Array 'a with "copyable" 'a
}
namespace var a : Array ('A : #Copy) {
decl something : Unit
// "methods" of Array 'a (a as array instance) with "copyable" 'a
}
// ?? what to do with const/public/... methods ??

View file

@ -0,0 +1,5 @@
class (FixedArray : #Ord) 'A : (a : Int) =
& size(a) : Int // ?? const ??
& @[] : @'A.a
// ?? not shure about array definition ??

38
tests/partitions.lang Normal file
View file

@ -0,0 +1,38 @@
// partition DOC { // or .doc.lang filename
// // ...
// }
// ?? separated doc ??
partition TEST { // or .test.lang filename
decl something : Unit
}
partition INTERFACE { // or .interface.lang filename
decl something : Unit
}
partition CORE { // or .core.lang filename
decl something : Unit
}
partition LIB { // or .lib.lang filename
decl something : Unit
}
partition MODULE { // or .module.lang filename
decl something : Unit
}
// maybe another name for partition
partition EXE { // or .exe.lang filename
decl something : Unit
}
// partition CONFIG { // or .config.lang filename
// decl something : Unit
// }
// ?? config is one of the partitions ??
// ?? maybe more ??

12
tests/tuples.lang Normal file
View file

@ -0,0 +1,12 @@
decl test_tuples : Unit -> Unit
def test_tuples = {
var tuple1 = & "a" & 2 & "hello"
const & t1 & t2 & t3 = f x
; tuple1.0 = "b"
}
// ??????????????????????????

7
tests/type_casting.lang Normal file
View file

@ -0,0 +1,7 @@
decl test_type_casting : Unit -> Unit
def test_type_casting = {
var x = y.as Int
var k = (f y x).as Float
}
// type casting is can be done by generic method "as"

36
tests/typeclasses.lang Normal file
View file

@ -0,0 +1,36 @@
typeclass #Copy =
& copy : #Copy -> #Copy
typeclass (#Ord : #Eq) =
& ( < ) : #Ord -> #Ord -> Bool
& ( > ) : #Ord -> #Ord -> Bool
& ( <= ) : #Ord -> #Ord -> Bool
& ( >= ) : #Ord -> #Ord -> Bool
typeclass (#D : #A #B #C) 'A 'B =
& do_something : Unit -> (& 'A & 'B)
typeclass #E 'A =
& do_something : Unit -> 'A
namespace const ord : #Ord {
def ( <= ) : a b = (a < b) || (a == b)
def ( > ) : a b = !(a <= b)
def ( >= ) : a b = !(a < b)
}
// === ?? dependent types ?? ===
//
// typeclass #F : (a : Int) (b : Int) =
// & do_something Int -> Int
//
// namespace (f : #F a b c) {
// require do_sometihng a = b
// }
//
// ===
// ?? operators over functions (without arguments, like "def <= = < || ==;") ??
// ?? define operators like OCaml ??
// ?? denote moved type ??
// ?? "trait" VS "typeclass" ??

14
tests/types.lang Normal file
View file

@ -0,0 +1,14 @@
alias T1 = Int;
type (T2 : #A #B #C);
// Define file level abstract type
T2 =
| Int
| Float
| Complex;
// Compile module (functions, types, ...) for T2 = Int, Float, Complex
// ?? file level <-> module level ??

22
tests/variants.lang Normal file
View file

@ -0,0 +1,22 @@
decl test_variants : Unit -> Unit
def test_variants = {
var variant1 = | 'a' | 2 | "hello"
var | val | err = f x // optional types for each
; val -> "something" // open variant as value in expr
; val -!> "nothing" // open variant as None in expr
; ?err // open variant as value, or return None (if possible), operator
match variant1 with
| 'a' -> "something"
| 2 -> "something"
| "hello" -> "something"
| a -> "Something"
| String.of str -> "something"
| Int.of i -> "someting"
| 11 -> "nothing"
}
// ???????????????????????

1
tree-sitter Submodule

@ -0,0 +1 @@
Subproject commit 1b1c3974f789a9bfaa31f493e6eaa212f13bdfb9

View file

@ -1,983 +0,0 @@
#ifndef TREE_SITTER_API_H_
#define TREE_SITTER_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
/****************************/
/* Section - ABI Versioning */
/****************************/
/**
* The latest ABI version that is supported by the current version of the
* library. When Languages are generated by the Tree-sitter CLI, they are
* assigned an ABI version number that corresponds to the current CLI version.
* The Tree-sitter library is generally backwards-compatible with languages
* generated using older CLI versions, but is not forwards-compatible.
*/
#define TREE_SITTER_LANGUAGE_VERSION 14
/**
* The earliest ABI version that is supported by the current version of the
* library.
*/
#define TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION 13
/*******************/
/* Section - Types */
/*******************/
typedef uint16_t TSSymbol;
typedef uint16_t TSFieldId;
typedef struct TSLanguage TSLanguage;
typedef struct TSParser TSParser;
typedef struct TSTree TSTree;
typedef struct TSQuery TSQuery;
typedef struct TSQueryCursor TSQueryCursor;
typedef enum {
TSInputEncodingUTF8,
TSInputEncodingUTF16,
} TSInputEncoding;
typedef enum {
TSSymbolTypeRegular,
TSSymbolTypeAnonymous,
TSSymbolTypeAuxiliary,
} TSSymbolType;
typedef struct {
uint32_t row;
uint32_t column;
} TSPoint;
typedef struct {
TSPoint start_point;
TSPoint end_point;
uint32_t start_byte;
uint32_t end_byte;
} TSRange;
typedef struct {
void *payload;
const char *(*read)(void *payload, uint32_t byte_index, TSPoint position, uint32_t *bytes_read);
TSInputEncoding encoding;
} TSInput;
typedef enum {
TSLogTypeParse,
TSLogTypeLex,
} TSLogType;
typedef struct {
void *payload;
void (*log)(void *payload, TSLogType, const char *);
} TSLogger;
typedef struct {
uint32_t start_byte;
uint32_t old_end_byte;
uint32_t new_end_byte;
TSPoint start_point;
TSPoint old_end_point;
TSPoint new_end_point;
} TSInputEdit;
typedef struct {
uint32_t context[4];
const void *id;
const TSTree *tree;
} TSNode;
typedef struct {
const void *tree;
const void *id;
uint32_t context[2];
} TSTreeCursor;
typedef struct {
TSNode node;
uint32_t index;
} TSQueryCapture;
typedef enum {
TSQuantifierZero = 0, // must match the array initialization value
TSQuantifierZeroOrOne,
TSQuantifierZeroOrMore,
TSQuantifierOne,
TSQuantifierOneOrMore,
} TSQuantifier;
typedef struct {
uint32_t id;
uint16_t pattern_index;
uint16_t capture_count;
const TSQueryCapture *captures;
} TSQueryMatch;
typedef enum {
TSQueryPredicateStepTypeDone,
TSQueryPredicateStepTypeCapture,
TSQueryPredicateStepTypeString,
} TSQueryPredicateStepType;
typedef struct {
TSQueryPredicateStepType type;
uint32_t value_id;
} TSQueryPredicateStep;
typedef enum {
TSQueryErrorNone = 0,
TSQueryErrorSyntax,
TSQueryErrorNodeType,
TSQueryErrorField,
TSQueryErrorCapture,
TSQueryErrorStructure,
TSQueryErrorLanguage,
} TSQueryError;
/********************/
/* Section - Parser */
/********************/
/**
* Create a new parser.
*/
TSParser *ts_parser_new(void);
/**
* Delete the parser, freeing all of the memory that it used.
*/
void ts_parser_delete(TSParser *parser);
/**
* Set the language that the parser should use for parsing.
*
* Returns a boolean indicating whether or not the language was successfully
* assigned. True means assignment succeeded. False means there was a version
* mismatch: the language was generated with an incompatible version of the
* Tree-sitter CLI. Check the language's version using `ts_language_version`
* and compare it to this library's `TREE_SITTER_LANGUAGE_VERSION` and
* `TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION` constants.
*/
bool ts_parser_set_language(TSParser *self, const TSLanguage *language);
/**
* Get the parser's current language.
*/
const TSLanguage *ts_parser_language(const TSParser *self);
/**
* Set the ranges of text that the parser should include when parsing.
*
* By default, the parser will always include entire documents. This function
* allows you to parse only a *portion* of a document but still return a syntax
* tree whose ranges match up with the document as a whole. You can also pass
* multiple disjoint ranges.
*
* The second and third parameters specify the location and length of an array
* of ranges. The parser does *not* take ownership of these ranges; it copies
* the data, so it doesn't matter how these ranges are allocated.
*
* If `length` is zero, then the entire document will be parsed. Otherwise,
* the given ranges must be ordered from earliest to latest in the document,
* and they must not overlap. That is, the following must hold for all
* `i` < `length - 1`: ranges[i].end_byte <= ranges[i + 1].start_byte
*
* If this requirement is not satisfied, the operation will fail, the ranges
* will not be assigned, and this function will return `false`. On success,
* this function returns `true`
*/
bool ts_parser_set_included_ranges(
TSParser *self,
const TSRange *ranges,
uint32_t length
);
/**
* Get the ranges of text that the parser will include when parsing.
*
* The returned pointer is owned by the parser. The caller should not free it
* or write to it. The length of the array will be written to the given
* `length` pointer.
*/
const TSRange *ts_parser_included_ranges(
const TSParser *self,
uint32_t *length
);
/**
* Use the parser to parse some source code and create a syntax tree.
*
* If you are parsing this document for the first time, pass `NULL` for the
* `old_tree` parameter. Otherwise, if you have already parsed an earlier
* version of this document and the document has since been edited, pass the
* previous syntax tree so that the unchanged parts of it can be reused.
* This will save time and memory. For this to work correctly, you must have
* already edited the old syntax tree using the `ts_tree_edit` function in a
* way that exactly matches the source code changes.
*
* The `TSInput` parameter lets you specify how to read the text. It has the
* following three fields:
* 1. `read`: A function to retrieve a chunk of text at a given byte offset
* and (row, column) position. The function should return a pointer to the
* text and write its length to the `bytes_read` pointer. The parser does
* not take ownership of this buffer; it just borrows it until it has
* finished reading it. The function should write a zero value to the
* `bytes_read` pointer to indicate the end of the document.
* 2. `payload`: An arbitrary pointer that will be passed to each invocation
* of the `read` function.
* 3. `encoding`: An indication of how the text is encoded. Either
* `TSInputEncodingUTF8` or `TSInputEncodingUTF16`.
*
* This function returns a syntax tree on success, and `NULL` on failure. There
* are three possible reasons for failure:
* 1. The parser does not have a language assigned. Check for this using the
`ts_parser_language` function.
* 2. Parsing was cancelled due to a timeout that was set by an earlier call to
* the `ts_parser_set_timeout_micros` function. You can resume parsing from
* where the parser left out by calling `ts_parser_parse` again with the
* same arguments. Or you can start parsing from scratch by first calling
* `ts_parser_reset`.
* 3. Parsing was cancelled using a cancellation flag that was set by an
* earlier call to `ts_parser_set_cancellation_flag`. You can resume parsing
* from where the parser left out by calling `ts_parser_parse` again with
* the same arguments.
*/
TSTree *ts_parser_parse(
TSParser *self,
const TSTree *old_tree,
TSInput input
);
/**
* Use the parser to parse some source code stored in one contiguous buffer.
* The first two parameters are the same as in the `ts_parser_parse` function
* above. The second two parameters indicate the location of the buffer and its
* length in bytes.
*/
TSTree *ts_parser_parse_string(
TSParser *self,
const TSTree *old_tree,
const char *string,
uint32_t length
);
/**
* Use the parser to parse some source code stored in one contiguous buffer with
* a given encoding. The first four parameters work the same as in the
* `ts_parser_parse_string` method above. The final parameter indicates whether
* the text is encoded as UTF8 or UTF16.
*/
TSTree *ts_parser_parse_string_encoding(
TSParser *self,
const TSTree *old_tree,
const char *string,
uint32_t length,
TSInputEncoding encoding
);
/**
* Instruct the parser to start the next parse from the beginning.
*
* If the parser previously failed because of a timeout or a cancellation, then
* by default, it will resume where it left off on the next call to
* `ts_parser_parse` or other parsing functions. If you don't want to resume,
* and instead intend to use this parser to parse some other document, you must
* call `ts_parser_reset` first.
*/
void ts_parser_reset(TSParser *self);
/**
* Set the maximum duration in microseconds that parsing should be allowed to
* take before halting.
*
* If parsing takes longer than this, it will halt early, returning NULL.
* See `ts_parser_parse` for more information.
*/
void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout);
/**
* Get the duration in microseconds that parsing is allowed to take.
*/
uint64_t ts_parser_timeout_micros(const TSParser *self);
/**
* Set the parser's current cancellation flag pointer.
*
* If a non-null pointer is assigned, then the parser will periodically read
* from this pointer during parsing. If it reads a non-zero value, it will
* halt early, returning NULL. See `ts_parser_parse` for more information.
*/
void ts_parser_set_cancellation_flag(TSParser *self, const size_t *flag);
/**
* Get the parser's current cancellation flag pointer.
*/
const size_t *ts_parser_cancellation_flag(const TSParser *self);
/**
* Set the logger that a parser should use during parsing.
*
* The parser does not take ownership over the logger payload. If a logger was
* previously assigned, the caller is responsible for releasing any memory
* owned by the previous logger.
*/
void ts_parser_set_logger(TSParser *self, TSLogger logger);
/**
* Get the parser's current logger.
*/
TSLogger ts_parser_logger(const TSParser *self);
/**
* Set the file descriptor to which the parser should write debugging graphs
* during parsing. The graphs are formatted in the DOT language. You may want
* to pipe these graphs directly to a `dot(1)` process in order to generate
* SVG output. You can turn off this logging by passing a negative number.
*/
void ts_parser_print_dot_graphs(TSParser *self, int file);
/******************/
/* Section - Tree */
/******************/
/**
* Create a shallow copy of the syntax tree. This is very fast.
*
* You need to copy a syntax tree in order to use it on more than one thread at
* a time, as syntax trees are not thread safe.
*/
TSTree *ts_tree_copy(const TSTree *self);
/**
* Delete the syntax tree, freeing all of the memory that it used.
*/
void ts_tree_delete(TSTree *self);
/**
* Get the root node of the syntax tree.
*/
TSNode ts_tree_root_node(const TSTree *self);
/**
* Get the root node of the syntax tree, but with its position
* shifted forward by the given offset.
*/
TSNode ts_tree_root_node_with_offset(
const TSTree *self,
uint32_t offset_bytes,
TSPoint offset_point
);
/**
* Get the language that was used to parse the syntax tree.
*/
const TSLanguage *ts_tree_language(const TSTree *);
/**
* Get the array of included ranges that was used to parse the syntax tree.
*
* The returned pointer must be freed by the caller.
*/
TSRange *ts_tree_included_ranges(const TSTree *, uint32_t *length);
/**
* Edit the syntax tree to keep it in sync with source code that has been
* edited.
*
* You must describe the edit both in terms of byte offsets and in terms of
* (row, column) coordinates.
*/
void ts_tree_edit(TSTree *self, const TSInputEdit *edit);
/**
* Compare an old edited syntax tree to a new syntax tree representing the same
* document, returning an array of ranges whose syntactic structure has changed.
*
* For this to work correctly, the old syntax tree must have been edited such
* that its ranges match up to the new tree. Generally, you'll want to call
* this function right after calling one of the `ts_parser_parse` functions.
* You need to pass the old tree that was passed to parse, as well as the new
* tree that was returned from that function.
*
* The returned array is allocated using `malloc` and the caller is responsible
* for freeing it using `free`. The length of the array will be written to the
* given `length` pointer.
*/
TSRange *ts_tree_get_changed_ranges(
const TSTree *old_tree,
const TSTree *new_tree,
uint32_t *length
);
/**
* Write a DOT graph describing the syntax tree to the given file.
*/
void ts_tree_print_dot_graph(const TSTree *, int file_descriptor);
/******************/
/* Section - Node */
/******************/
/**
* Get the node's type as a null-terminated string.
*/
const char *ts_node_type(TSNode);
/**
* Get the node's type as a numerical id.
*/
TSSymbol ts_node_symbol(TSNode);
/**
* Get the node's start byte.
*/
uint32_t ts_node_start_byte(TSNode);
/**
* Get the node's start position in terms of rows and columns.
*/
TSPoint ts_node_start_point(TSNode);
/**
* Get the node's end byte.
*/
uint32_t ts_node_end_byte(TSNode);
/**
* Get the node's end position in terms of rows and columns.
*/
TSPoint ts_node_end_point(TSNode);
/**
* Get an S-expression representing the node as a string.
*
* This string is allocated with `malloc` and the caller is responsible for
* freeing it using `free`.
*/
char *ts_node_string(TSNode);
/**
* Check if the node is null. Functions like `ts_node_child` and
* `ts_node_next_sibling` will return a null node to indicate that no such node
* was found.
*/
bool ts_node_is_null(TSNode);
/**
* Check if the node is *named*. Named nodes correspond to named rules in the
* grammar, whereas *anonymous* nodes correspond to string literals in the
* grammar.
*/
bool ts_node_is_named(TSNode);
/**
* Check if the node is *missing*. Missing nodes are inserted by the parser in
* order to recover from certain kinds of syntax errors.
*/
bool ts_node_is_missing(TSNode);
/**
* Check if the node is *extra*. Extra nodes represent things like comments,
* which are not required the grammar, but can appear anywhere.
*/
bool ts_node_is_extra(TSNode);
/**
* Check if a syntax node has been edited.
*/
bool ts_node_has_changes(TSNode);
/**
* Check if the node is a syntax error or contains any syntax errors.
*/
bool ts_node_has_error(TSNode);
/**
* Get the node's immediate parent.
*/
TSNode ts_node_parent(TSNode);
/**
* Get the node's child at the given index, where zero represents the first
* child.
*/
TSNode ts_node_child(TSNode, uint32_t);
/**
* Get the field name for node's child at the given index, where zero represents
* the first child. Returns NULL, if no field is found.
*/
const char *ts_node_field_name_for_child(TSNode, uint32_t);
/**
* Get the node's number of children.
*/
uint32_t ts_node_child_count(TSNode);
/**
* Get the node's *named* child at the given index.
*
* See also `ts_node_is_named`.
*/
TSNode ts_node_named_child(TSNode, uint32_t);
/**
* Get the node's number of *named* children.
*
* See also `ts_node_is_named`.
*/
uint32_t ts_node_named_child_count(TSNode);
/**
* Get the node's child with the given field name.
*/
TSNode ts_node_child_by_field_name(
TSNode self,
const char *field_name,
uint32_t field_name_length
);
/**
* Get the node's child with the given numerical field id.
*
* You can convert a field name to an id using the
* `ts_language_field_id_for_name` function.
*/
TSNode ts_node_child_by_field_id(TSNode, TSFieldId);
/**
* Get the node's next / previous sibling.
*/
TSNode ts_node_next_sibling(TSNode);
TSNode ts_node_prev_sibling(TSNode);
/**
* Get the node's next / previous *named* sibling.
*/
TSNode ts_node_next_named_sibling(TSNode);
TSNode ts_node_prev_named_sibling(TSNode);
/**
* Get the node's first child that extends beyond the given byte offset.
*/
TSNode ts_node_first_child_for_byte(TSNode, uint32_t);
/**
* Get the node's first named child that extends beyond the given byte offset.
*/
TSNode ts_node_first_named_child_for_byte(TSNode, uint32_t);
/**
* Get the smallest node within this node that spans the given range of bytes
* or (row, column) positions.
*/
TSNode ts_node_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
TSNode ts_node_descendant_for_point_range(TSNode, TSPoint, TSPoint);
/**
* Get the smallest named node within this node that spans the given range of
* bytes or (row, column) positions.
*/
TSNode ts_node_named_descendant_for_byte_range(TSNode, uint32_t, uint32_t);
TSNode ts_node_named_descendant_for_point_range(TSNode, TSPoint, TSPoint);
/**
* Edit the node to keep it in-sync with source code that has been edited.
*
* This function is only rarely needed. When you edit a syntax tree with the
* `ts_tree_edit` function, all of the nodes that you retrieve from the tree
* afterward will already reflect the edit. You only need to use `ts_node_edit`
* when you have a `TSNode` instance that you want to keep and continue to use
* after an edit.
*/
void ts_node_edit(TSNode *, const TSInputEdit *);
/**
* Check if two nodes are identical.
*/
bool ts_node_eq(TSNode, TSNode);
/************************/
/* Section - TreeCursor */
/************************/
/**
* Create a new tree cursor starting from the given node.
*
* A tree cursor allows you to walk a syntax tree more efficiently than is
* possible using the `TSNode` functions. It is a mutable object that is always
* on a certain syntax node, and can be moved imperatively to different nodes.
*/
TSTreeCursor ts_tree_cursor_new(TSNode);
/**
* Delete a tree cursor, freeing all of the memory that it used.
*/
void ts_tree_cursor_delete(TSTreeCursor *);
/**
* Re-initialize a tree cursor to start at a different node.
*/
void ts_tree_cursor_reset(TSTreeCursor *, TSNode);
/**
* Get the tree cursor's current node.
*/
TSNode ts_tree_cursor_current_node(const TSTreeCursor *);
/**
* Get the field name of the tree cursor's current node.
*
* This returns `NULL` if the current node doesn't have a field.
* See also `ts_node_child_by_field_name`.
*/
const char *ts_tree_cursor_current_field_name(const TSTreeCursor *);
/**
* Get the field id of the tree cursor's current node.
*
* This returns zero if the current node doesn't have a field.
* See also `ts_node_child_by_field_id`, `ts_language_field_id_for_name`.
*/
TSFieldId ts_tree_cursor_current_field_id(const TSTreeCursor *);
/**
* Move the cursor to the parent of its current node.
*
* This returns `true` if the cursor successfully moved, and returns `false`
* if there was no parent node (the cursor was already on the root node).
*/
bool ts_tree_cursor_goto_parent(TSTreeCursor *);
/**
* Move the cursor to the next sibling of its current node.
*
* This returns `true` if the cursor successfully moved, and returns `false`
* if there was no next sibling node.
*/
bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *);
/**
* Move the cursor to the first child of its current node.
*
* This returns `true` if the cursor successfully moved, and returns `false`
* if there were no children.
*/
bool ts_tree_cursor_goto_first_child(TSTreeCursor *);
/**
* Move the cursor to the first child of its current node that extends beyond
* the given byte offset or point.
*
* This returns the index of the child node if one was found, and returns -1
* if no such child was found.
*/
int64_t ts_tree_cursor_goto_first_child_for_byte(TSTreeCursor *, uint32_t);
int64_t ts_tree_cursor_goto_first_child_for_point(TSTreeCursor *, TSPoint);
TSTreeCursor ts_tree_cursor_copy(const TSTreeCursor *);
/*******************/
/* Section - Query */
/*******************/
/**
* Create a new query from a string containing one or more S-expression
* patterns. The query is associated with a particular language, and can
* only be run on syntax nodes parsed with that language.
*
* If all of the given patterns are valid, this returns a `TSQuery`.
* If a pattern is invalid, this returns `NULL`, and provides two pieces
* of information about the problem:
* 1. The byte offset of the error is written to the `error_offset` parameter.
* 2. The type of error is written to the `error_type` parameter.
*/
TSQuery *ts_query_new(
const TSLanguage *language,
const char *source,
uint32_t source_len,
uint32_t *error_offset,
TSQueryError *error_type
);
/**
* Delete a query, freeing all of the memory that it used.
*/
void ts_query_delete(TSQuery *);
/**
* Get the number of patterns, captures, or string literals in the query.
*/
uint32_t ts_query_pattern_count(const TSQuery *);
uint32_t ts_query_capture_count(const TSQuery *);
uint32_t ts_query_string_count(const TSQuery *);
/**
* Get the byte offset where the given pattern starts in the query's source.
*
* This can be useful when combining queries by concatenating their source
* code strings.
*/
uint32_t ts_query_start_byte_for_pattern(const TSQuery *, uint32_t);
/**
* Get all of the predicates for the given pattern in the query.
*
* The predicates are represented as a single array of steps. There are three
* types of steps in this array, which correspond to the three legal values for
* the `type` field:
* - `TSQueryPredicateStepTypeCapture` - Steps with this type represent names
* of captures. Their `value_id` can be used with the
* `ts_query_capture_name_for_id` function to obtain the name of the capture.
* - `TSQueryPredicateStepTypeString` - Steps with this type represent literal
* strings. Their `value_id` can be used with the
* `ts_query_string_value_for_id` function to obtain their string value.
* - `TSQueryPredicateStepTypeDone` - Steps with this type are *sentinels*
* that represent the end of an individual predicate. If a pattern has two
* predicates, then there will be two steps with this `type` in the array.
*/
const TSQueryPredicateStep *ts_query_predicates_for_pattern(
const TSQuery *self,
uint32_t pattern_index,
uint32_t *length
);
/*
* Check if the given pattern in the query has a single root node.
*/
bool ts_query_is_pattern_rooted(const TSQuery *self, uint32_t pattern_index);
/*
* Check if the given pattern in the query is 'non local'.
*
* A non-local pattern has multiple root nodes and can match within a
* repeating sequence of nodes, as specified by the grammar. Non-local
* patterns disable certain optimizations that would otherwise be possible
* when executing a query on a specific range of a syntax tree.
*/
bool ts_query_is_pattern_non_local(const TSQuery *self, uint32_t pattern_index);
/*
* Check if a given pattern is guaranteed to match once a given step is reached.
* The step is specified by its byte offset in the query's source code.
*/
bool ts_query_is_pattern_guaranteed_at_step(const TSQuery *self, uint32_t byte_offset);
/**
* Get the name and length of one of the query's captures, or one of the
* query's string literals. Each capture and string is associated with a
* numeric id based on the order that it appeared in the query's source.
*/
const char *ts_query_capture_name_for_id(
const TSQuery *,
uint32_t id,
uint32_t *length
);
/**
* Get the quantifier of the query's captures. Each capture is * associated
* with a numeric id based on the order that it appeared in the query's source.
*/
TSQuantifier ts_query_capture_quantifier_for_id(
const TSQuery *,
uint32_t pattern_id,
uint32_t capture_id
);
const char *ts_query_string_value_for_id(
const TSQuery *,
uint32_t id,
uint32_t *length
);
/**
* Disable a certain capture within a query.
*
* This prevents the capture from being returned in matches, and also avoids
* any resource usage associated with recording the capture. Currently, there
* is no way to undo this.
*/
void ts_query_disable_capture(TSQuery *, const char *, uint32_t);
/**
* Disable a certain pattern within a query.
*
* This prevents the pattern from matching and removes most of the overhead
* associated with the pattern. Currently, there is no way to undo this.
*/
void ts_query_disable_pattern(TSQuery *, uint32_t);
/**
* Create a new cursor for executing a given query.
*
* The cursor stores the state that is needed to iteratively search
* for matches. To use the query cursor, first call `ts_query_cursor_exec`
* to start running a given query on a given syntax node. Then, there are
* two options for consuming the results of the query:
* 1. Repeatedly call `ts_query_cursor_next_match` to iterate over all of the
* *matches* in the order that they were found. Each match contains the
* index of the pattern that matched, and an array of captures. Because
* multiple patterns can match the same set of nodes, one match may contain
* captures that appear *before* some of the captures from a previous match.
* 2. Repeatedly call `ts_query_cursor_next_capture` to iterate over all of the
* individual *captures* in the order that they appear. This is useful if
* don't care about which pattern matched, and just want a single ordered
* sequence of captures.
*
* If you don't care about consuming all of the results, you can stop calling
* `ts_query_cursor_next_match` or `ts_query_cursor_next_capture` at any point.
* You can then start executing another query on another node by calling
* `ts_query_cursor_exec` again.
*/
TSQueryCursor *ts_query_cursor_new(void);
/**
* Delete a query cursor, freeing all of the memory that it used.
*/
void ts_query_cursor_delete(TSQueryCursor *);
/**
* Start running a given query on a given node.
*/
void ts_query_cursor_exec(TSQueryCursor *, const TSQuery *, TSNode);
/**
* Manage the maximum number of in-progress matches allowed by this query
* cursor.
*
* Query cursors have an optional maximum capacity for storing lists of
* in-progress captures. If this capacity is exceeded, then the
* earliest-starting match will silently be dropped to make room for further
* matches. This maximum capacity is optional by default, query cursors allow
* any number of pending matches, dynamically allocating new space for them as
* needed as the query is executed.
*/
bool ts_query_cursor_did_exceed_match_limit(const TSQueryCursor *);
uint32_t ts_query_cursor_match_limit(const TSQueryCursor *);
void ts_query_cursor_set_match_limit(TSQueryCursor *, uint32_t);
/**
* Set the range of bytes or (row, column) positions in which the query
* will be executed.
*/
void ts_query_cursor_set_byte_range(TSQueryCursor *, uint32_t, uint32_t);
void ts_query_cursor_set_point_range(TSQueryCursor *, TSPoint, TSPoint);
/**
* Advance to the next match of the currently running query.
*
* If there is a match, write it to `*match` and return `true`.
* Otherwise, return `false`.
*/
bool ts_query_cursor_next_match(TSQueryCursor *, TSQueryMatch *match);
void ts_query_cursor_remove_match(TSQueryCursor *, uint32_t id);
/**
* Advance to the next capture of the currently running query.
*
* If there is a capture, write its match to `*match` and its index within
* the matche's capture list to `*capture_index`. Otherwise, return `false`.
*/
bool ts_query_cursor_next_capture(
TSQueryCursor *,
TSQueryMatch *match,
uint32_t *capture_index
);
/**********************/
/* Section - Language */
/**********************/
/**
* Get the number of distinct node types in the language.
*/
uint32_t ts_language_symbol_count(const TSLanguage *);
/**
* Get a node type string for the given numerical id.
*/
const char *ts_language_symbol_name(const TSLanguage *, TSSymbol);
/**
* Get the numerical id for the given node type string.
*/
TSSymbol ts_language_symbol_for_name(
const TSLanguage *self,
const char *string,
uint32_t length,
bool is_named
);
/**
* Get the number of distinct field names in the language.
*/
uint32_t ts_language_field_count(const TSLanguage *);
/**
* Get the field name string for the given numerical id.
*/
const char *ts_language_field_name_for_id(const TSLanguage *, TSFieldId);
/**
* Get the numerical id for the given field name string.
*/
TSFieldId ts_language_field_id_for_name(const TSLanguage *, const char *, uint32_t);
/**
* Check whether the given node type id belongs to named nodes, anonymous nodes,
* or a hidden nodes.
*
* See also `ts_node_is_named`. Hidden nodes are never returned from the API.
*/
TSSymbolType ts_language_symbol_type(const TSLanguage *, TSSymbol);
/**
* Get the ABI version number for this language. This version number is used
* to ensure that languages were generated by a compatible version of
* Tree-sitter.
*
* See also `ts_parser_set_language`.
*/
uint32_t ts_language_version(const TSLanguage *);
/**********************************/
/* Section - Global Configuration */
/**********************************/
/**
* Set the allocation functions used by the library.
*
* By default, Tree-sitter uses the standard libc allocation functions,
* but aborts the process when an allocation fails. This function lets
* you supply alternative allocation functions at runtime.
*
* If you pass `NULL` for any parameter, Tree-sitter will switch back to
* its default implementation of that function.
*
* If you call this function after the library has already been used, then
* you must ensure that either:
* 1. All the existing objects have been freed.
* 2. The new allocator shares its state with the old one, so it is capable
* of freeing memory that was allocated by the old allocator.
*/
void ts_set_allocator(
void *(*new_malloc)(size_t),
void *(*new_calloc)(size_t, size_t),
void *(*new_realloc)(void *, size_t),
void (*new_free)(void *)
);
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_API_H_