mirror of
https://codeberg.org/ProgramSnail/lang.git
synced 2026-01-25 13:07:13 +00:00
bug fixes, tests passed, result modifier (!) added to function arguments and to types
This commit is contained in:
parent
4470454838
commit
3914ff7d8b
16 changed files with 418 additions and 62 deletions
|
|
@ -16,6 +16,7 @@ add_executable(lang src/main.cpp
|
||||||
src/expression_nodes.cpp
|
src/expression_nodes.cpp
|
||||||
src/basic_builders.cpp
|
src/basic_builders.cpp
|
||||||
src/type_builders.cpp
|
src/type_builders.cpp
|
||||||
|
src/doc_builders.cpp
|
||||||
src/expression_builders.cpp
|
src/expression_builders.cpp
|
||||||
src/statement_builders.cpp
|
src/statement_builders.cpp
|
||||||
include/tree_sitter_wrapper.hpp
|
include/tree_sitter_wrapper.hpp
|
||||||
|
|
|
||||||
2
deps/tree-sitter-lang
vendored
2
deps/tree-sitter-lang
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4a553f24fbd468755c103d64e1c3090dd4c2c7e0
|
Subproject commit b26c0544bf0dea60a421d4672c3f2997f445b5ff
|
||||||
|
|
@ -15,10 +15,18 @@ public:
|
||||||
|
|
||||||
SymbolDocs(const std::string &description) : description_(description) {}
|
SymbolDocs(const std::string &description) : description_(description) {}
|
||||||
|
|
||||||
template <typename T>
|
bool add_annotation_info(const std::string &annotation, std::string &&info) {
|
||||||
bool add_annotation_info(const std::string &annotation, T &&info) {
|
|
||||||
if (annotations_info_.count(annotation) == 0) {
|
if (annotations_info_.count(annotation) == 0) {
|
||||||
annotations_info_[annotation] = std::forward<T>(info);
|
annotations_info_[annotation] = std::move(info);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool add_annotation_info(const std::string &annotation,
|
||||||
|
const std::string &info) {
|
||||||
|
if (annotations_info_.count(annotation) == 0) {
|
||||||
|
annotations_info_[annotation] = info;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "basic_nodes.hpp"
|
#include "basic_nodes.hpp"
|
||||||
#include "tree_sitter_wrapper.hpp"
|
#include "tree_sitter_wrapper.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
@ -15,11 +16,6 @@ inline void print_position(std::ostream &out,
|
||||||
<< ']';
|
<< ']';
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void handle_general_error(const std::string &message) {
|
|
||||||
std::cerr << "\x1b[1;31mGeneral Error:\x1b[0m " << message << ".\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
handle_internal_error(const std::string &message, const std::string &place,
|
handle_internal_error(const std::string &message, const std::string &place,
|
||||||
std::optional<nodes::Node> node = std::nullopt) {
|
std::optional<nodes::Node> node = std::nullopt) {
|
||||||
|
|
|
||||||
|
|
@ -363,15 +363,16 @@ private:
|
||||||
|
|
||||||
class NameExpression : public Node {
|
class NameExpression : public Node {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
|
||||||
NameExpression(Node node, Identifier &&name)
|
NameExpression(Node node, Identifier &&name)
|
||||||
: Node(node), name_(std::forward<T>(name)) {}
|
: Node(node), name_(std::move(name)) {}
|
||||||
|
|
||||||
|
NameExpression(Node node, const Identifier &name) : Node(node), name_(name) {}
|
||||||
|
|
||||||
NameExpression(
|
NameExpression(
|
||||||
Node node, Identifier &&name,
|
Node node, Identifier &&name,
|
||||||
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
|
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
|
||||||
&&arguments,
|
&&arguments,
|
||||||
std::optional<const Type> &&prefix, bool is_point_call = false)
|
std::optional<TypeProxy> &&prefix, bool is_point_call = false)
|
||||||
: Node(node), name_(std::move(name)), arguments_(std::move(arguments)),
|
: Node(node), name_(std::move(name)), arguments_(std::move(arguments)),
|
||||||
prefix_(std::move(prefix)), is_point_call_(is_point_call) {}
|
prefix_(std::move(prefix)), is_point_call_(is_point_call) {}
|
||||||
|
|
||||||
|
|
@ -379,16 +380,16 @@ public:
|
||||||
|
|
||||||
const std::string *get_name() const { return name_.get(); }
|
const std::string *get_name() const { return name_.get(); }
|
||||||
|
|
||||||
std::optional<const Type *> get_prefix() {
|
std::optional<TypeProxy> get_prefix() {
|
||||||
if (prefix_.has_value()) {
|
if (prefix_.has_value()) {
|
||||||
return &prefix_.value();
|
return prefix_.value();
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<const Type *> get_prefix() const {
|
std::optional<const TypeProxy> get_prefix() const {
|
||||||
if (prefix_.has_value()) {
|
if (prefix_.has_value()) {
|
||||||
return &prefix_.value();
|
return prefix_.value();
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
@ -421,10 +422,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Identifier name_;
|
Identifier name_;
|
||||||
|
// universal function call syntax
|
||||||
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
|
std::vector<std::pair<std::optional<std::string>, ExpressionProxy>>
|
||||||
arguments_;
|
arguments_;
|
||||||
// universal function call syntax
|
std::optional<TypeProxy> prefix_;
|
||||||
std::optional<const Type> prefix_;
|
|
||||||
// for static methods
|
// for static methods
|
||||||
bool is_point_call_ = false; // x.f ... or f x ...
|
bool is_point_call_ = false; // x.f ... or f x ...
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -61,12 +61,15 @@ public:
|
||||||
std::vector<Identifier> &&arguments,
|
std::vector<Identifier> &&arguments,
|
||||||
std::vector<Modifier> &&reference_types,
|
std::vector<Modifier> &&reference_types,
|
||||||
std::vector<std::optional<TypeProxy>> &&types,
|
std::vector<std::optional<TypeProxy>> &&types,
|
||||||
|
std::vector<bool> &&optional_arguments,
|
||||||
|
std::vector<bool> &&result_arguments,
|
||||||
std::optional<ExpressionProxy> expression)
|
std::optional<ExpressionProxy> expression)
|
||||||
: Node(node), docs_(std::move(docs)),
|
: Node(node), docs_(std::move(docs)),
|
||||||
constraints_(std::move(constraints)), modifier_(modifier), name_(name),
|
constraints_(std::move(constraints)), modifier_(modifier), name_(name),
|
||||||
annotations_(std::move(annotations)), arguments_(std::move(arguments)),
|
annotations_(std::move(annotations)), arguments_(std::move(arguments)),
|
||||||
reference_types_(std::move(reference_types)), types_(std::move(types)),
|
reference_types_(std::move(reference_types)), types_(std::move(types)),
|
||||||
expression_(expression) {}
|
optional_arguments_(optional_arguments),
|
||||||
|
result_arguments_(result_arguments), expression_(expression) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SymbolDocs docs_;
|
SymbolDocs docs_;
|
||||||
|
|
@ -77,8 +80,9 @@ private:
|
||||||
std::vector<Identifier> arguments_;
|
std::vector<Identifier> arguments_;
|
||||||
std::vector<Modifier> reference_types_;
|
std::vector<Modifier> reference_types_;
|
||||||
std::vector<std::optional<TypeProxy>> types_;
|
std::vector<std::optional<TypeProxy>> types_;
|
||||||
|
std::vector<bool> optional_arguments_;
|
||||||
|
std::vector<bool> result_arguments_;
|
||||||
std::optional<ExpressionProxy> expression_;
|
std::optional<ExpressionProxy> expression_;
|
||||||
// std::vector<bool> optional_arguments_; // ??
|
|
||||||
}; // IN PROGRESS
|
}; // IN PROGRESS
|
||||||
|
|
||||||
class TypeDefinition : public Node {
|
class TypeDefinition : public Node {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// for clangd
|
#include "utils.hpp"
|
||||||
|
|
||||||
#include "tree_sitter/api.h"
|
#include "tree_sitter/api.h"
|
||||||
|
|
||||||
extern "C" const TSLanguage *tree_sitter_lang();
|
extern "C" const TSLanguage *tree_sitter_lang();
|
||||||
|
|
@ -16,21 +17,47 @@ public:
|
||||||
Node(const TSNode &node, const std::string *source)
|
Node(const TSNode &node, const std::string *source)
|
||||||
: node_(node), source_(source) {}
|
: node_(node), source_(source) {}
|
||||||
|
|
||||||
std::string get_type() const { return ts_node_type(node_); }
|
std::string get_type() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (get_type)");
|
||||||
|
}
|
||||||
|
return ts_node_type(node_);
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<size_t, size_t> get_start_point() const {
|
std::pair<size_t, size_t> get_start_point() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (get_start_point)");
|
||||||
|
}
|
||||||
|
|
||||||
TSPoint point = ts_node_start_point(node_);
|
TSPoint point = ts_node_start_point(node_);
|
||||||
return {point.row, point.column};
|
return {point.row, point.column};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<size_t, size_t> get_end_point() const {
|
std::pair<size_t, size_t> get_end_point() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (get_end_point)");
|
||||||
|
}
|
||||||
|
|
||||||
TSPoint point = ts_node_end_point(node_);
|
TSPoint point = ts_node_end_point(node_);
|
||||||
return {point.row, point.column};
|
return {point.row, point.column};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_as_sexpression() const { return ts_node_string(node_); }
|
std::string get_as_sexpression() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (get_as_sexpression)");
|
||||||
|
}
|
||||||
|
return ts_node_string(node_);
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_value() const { // from source
|
std::string get_value() const { // from source
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (get_value)");
|
||||||
|
}
|
||||||
size_t start = ts_node_start_byte(node_);
|
size_t start = ts_node_start_byte(node_);
|
||||||
size_t end = ts_node_end_byte(node_);
|
size_t end = ts_node_end_byte(node_);
|
||||||
return source_->substr(start, end - start);
|
return source_->substr(start, end - start);
|
||||||
|
|
@ -38,47 +65,107 @@ public:
|
||||||
|
|
||||||
bool is_null() const { return ts_node_is_null(node_); }
|
bool is_null() const { return ts_node_is_null(node_); }
|
||||||
|
|
||||||
bool is_named() const { return ts_node_is_named(node_); }
|
bool is_named() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (is_named)");
|
||||||
|
}
|
||||||
|
return ts_node_is_named(node_);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_missing() const { return ts_node_is_missing(node_); }
|
bool is_missing() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (is_missing)");
|
||||||
|
}
|
||||||
|
return ts_node_is_missing(node_);
|
||||||
|
}
|
||||||
|
|
||||||
bool is_extra() const { // comments, etc.
|
bool is_extra() const { // comments, etc.
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (is_extra)");
|
||||||
|
}
|
||||||
return ts_node_is_extra(node_);
|
return ts_node_is_extra(node_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_error() const { return ts_node_has_error(node_); }
|
bool has_error() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (has_error)");
|
||||||
|
}
|
||||||
|
return ts_node_has_error(node_);
|
||||||
|
}
|
||||||
|
|
||||||
Node nth_child(size_t n) const {
|
Node nth_child(size_t n) const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (nth_child)");
|
||||||
|
}
|
||||||
return Node(ts_node_child(node_, n), source_);
|
return Node(ts_node_child(node_, n), source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t child_count() const { return ts_node_child_count(node_); }
|
size_t child_count() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (child_count)");
|
||||||
|
}
|
||||||
|
return ts_node_child_count(node_);
|
||||||
|
}
|
||||||
|
|
||||||
Node nth_named_child(size_t n) const {
|
Node nth_named_child(size_t n) const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (nth_named_child)");
|
||||||
|
}
|
||||||
return Node(ts_node_named_child(node_, n), source_);
|
return Node(ts_node_named_child(node_, n), source_);
|
||||||
}
|
}
|
||||||
size_t named_child_count() const {
|
size_t named_child_count() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (named_child_count)");
|
||||||
|
}
|
||||||
return ts_node_named_child_count(node_);
|
return ts_node_named_child_count(node_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node child_by_field_name(const std::string &name) const {
|
Node child_by_field_name(const std::string &name) const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (child_by_field_name)");
|
||||||
|
}
|
||||||
return Node(ts_node_child_by_field_name(node_, name.c_str(), name.size()),
|
return Node(ts_node_child_by_field_name(node_, name.c_str(), name.size()),
|
||||||
source_);
|
source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node previous_sibling() const {
|
Node previous_sibling() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (previous_sibling)");
|
||||||
|
}
|
||||||
return Node(ts_node_prev_sibling(node_), source_);
|
return Node(ts_node_prev_sibling(node_), source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node previous_named_sibling() const {
|
Node previous_named_sibling() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (previous_named_sibling)");
|
||||||
|
}
|
||||||
return Node(ts_node_prev_named_sibling(node_), source_);
|
return Node(ts_node_prev_named_sibling(node_), source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node next_sibling() const {
|
Node next_sibling() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (next_sibling)");
|
||||||
|
}
|
||||||
return Node(ts_node_next_sibling(node_), source_);
|
return Node(ts_node_next_sibling(node_), source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node next_named_sibling() const {
|
Node next_named_sibling() const {
|
||||||
|
if (is_null()) {
|
||||||
|
error_handling::handle_general_error(
|
||||||
|
"Null parsing node method called (next_named_sibling)");
|
||||||
|
}
|
||||||
return Node(ts_node_next_named_sibling(node_), source_);
|
return Node(ts_node_next_named_sibling(node_), source_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,26 +34,28 @@ private:
|
||||||
class Type : public Node {
|
class Type : public Node {
|
||||||
public:
|
public:
|
||||||
Type(Node node, Identifier &&identifier, bool is_on_heap = false,
|
Type(Node node, Identifier &&identifier, bool is_on_heap = false,
|
||||||
bool is_optional = false)
|
bool is_optional = false, bool is_result = false)
|
||||||
: Node(node), name_(std::move(identifier)), is_on_heap_(is_on_heap),
|
: Node(node), name_(std::move(identifier)), is_on_heap_(is_on_heap),
|
||||||
is_optional_(is_optional) {}
|
is_optional_(is_optional), is_result_(is_result) {}
|
||||||
|
|
||||||
Type(Node node, const Identifier &identifier, bool is_on_heap = false,
|
Type(Node node, const Identifier &identifier, bool is_on_heap = false,
|
||||||
bool is_optional = false)
|
bool is_optional = false, bool is_result = false)
|
||||||
: Node(node), name_(identifier), is_on_heap_(is_on_heap),
|
: Node(node), name_(identifier), is_on_heap_(is_on_heap),
|
||||||
is_optional_(is_optional) {}
|
is_optional_(is_optional), is_result_(is_result) {}
|
||||||
|
|
||||||
Type(Node node, Identifier &&identifier, std::vector<TypeProxy> &¶meters,
|
Type(Node node, Identifier &&identifier, std::vector<TypeProxy> &¶meters,
|
||||||
bool is_on_heap = false, bool is_optional = false)
|
bool is_on_heap = false, bool is_optional = false,
|
||||||
|
bool is_result = false)
|
||||||
: Node(node), name_(std::move(identifier)),
|
: Node(node), name_(std::move(identifier)),
|
||||||
parameters_(std::move(parameters)), is_on_heap_(is_on_heap),
|
parameters_(std::move(parameters)), is_on_heap_(is_on_heap),
|
||||||
is_optional_(is_optional) {}
|
is_optional_(is_optional), is_result_(is_result) {}
|
||||||
|
|
||||||
Type(Node node, const Identifier &identifier,
|
Type(Node node, const Identifier &identifier,
|
||||||
std::vector<TypeProxy> &¶meters, bool is_on_heap = false,
|
std::vector<TypeProxy> &¶meters, bool is_on_heap = false,
|
||||||
bool is_optional = false)
|
bool is_optional = false, bool is_result = false)
|
||||||
: Node(node), name_(identifier), parameters_(std::move(parameters)),
|
: Node(node), name_(identifier), parameters_(std::move(parameters)),
|
||||||
is_on_heap_(is_on_heap), is_optional_(is_optional) {}
|
is_on_heap_(is_on_heap), is_optional_(is_optional),
|
||||||
|
is_result_(is_result) {}
|
||||||
|
|
||||||
std::string *get_name() { return name_.get(); }
|
std::string *get_name() { return name_.get(); }
|
||||||
|
|
||||||
|
|
@ -71,12 +73,15 @@ public:
|
||||||
|
|
||||||
bool is_optional() { return is_optional_; }
|
bool is_optional() { return is_optional_; }
|
||||||
|
|
||||||
|
bool is_result() { return is_result_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Identifier name_;
|
Identifier name_;
|
||||||
std::vector<TypeProxy> parameters_;
|
std::vector<TypeProxy> parameters_;
|
||||||
// or use allocator ??
|
// or use allocator ??
|
||||||
bool is_on_heap_ = false;
|
bool is_on_heap_ = false;
|
||||||
bool is_optional_ = false;
|
bool is_optional_ = false;
|
||||||
|
bool is_result_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeStorage {
|
class TypeStorage {
|
||||||
|
|
|
||||||
|
|
@ -1 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace error_handling {
|
||||||
|
|
||||||
|
inline void handle_general_error(const std::string &message) {
|
||||||
|
std::cerr << "\x1b[1;31mGeneral Error:\x1b[0m " << message << ".\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace error_handling
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -135,7 +135,7 @@ nodes::Literal build_bool_literal(parser::ParseTree::Node parser_node) {
|
||||||
literal == "true" ? true : false);
|
literal == "true" ? true : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes::Literal build_Unit_literal(parser::ParseTree::Node parser_node) {
|
nodes::Literal build_unit_literal(parser::ParseTree::Node parser_node) {
|
||||||
return nodes::Literal(build_node(parser_node), nodes::unit{});
|
return nodes::Literal(build_node(parser_node), nodes::unit{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +161,12 @@ nodes::Identifier build_identifier(parser::ParseTree::Node parser_node) {
|
||||||
return build_argument_name(parser_node);
|
return build_argument_name(parser_node);
|
||||||
case tokens::Type::ARGUMENT_TYPE_IDENTIFIER:
|
case tokens::Type::ARGUMENT_TYPE_IDENTIFIER:
|
||||||
return build_argument_type(parser_node);
|
return build_argument_type(parser_node);
|
||||||
// used as string
|
case tokens::Type::OPERATOR:
|
||||||
|
case tokens::Type::OPERATOR_TAIL1:
|
||||||
|
case tokens::Type::OPERATOR_TAIL2:
|
||||||
|
case tokens::Type::OPERATOR_TAIL3:
|
||||||
|
return build_operator(parser_node);
|
||||||
|
// [used as string]
|
||||||
// case tokens::Type::ANNOTATION_IDENTIFIER:
|
// case tokens::Type::ANNOTATION_IDENTIFIER:
|
||||||
// return build_annotation(parser_node);
|
// return build_annotation(parser_node);
|
||||||
default:
|
default:
|
||||||
|
|
@ -226,7 +231,7 @@ nodes::Identifier build_operator(parser::ParseTree::Node parser_node) {
|
||||||
identifier);
|
identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes::Identifier buildPlaceholder(parser::ParseTree::Node parser_node) {
|
nodes::Identifier build_placeholder(parser::ParseTree::Node parser_node) {
|
||||||
return nodes::Identifier(build_node(parser_node),
|
return nodes::Identifier(build_node(parser_node),
|
||||||
nodes::Identifier::PLACEHOLDER, "_");
|
nodes::Identifier::PLACEHOLDER, "_");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ nodes::SymbolDocs build_symbol_docs(
|
||||||
|
|
||||||
for (auto &annotation_parser_node : annotation_parser_nodes) {
|
for (auto &annotation_parser_node : annotation_parser_nodes) {
|
||||||
std::string annotation =
|
std::string annotation =
|
||||||
build_annotation(annotation_parser_node.nth_child(0));
|
build_annotation(annotation_parser_node.nth_named_child(0));
|
||||||
|
|
||||||
if (annotations.count(annotation) == 0) {
|
if (annotations.count(annotation) == 0) {
|
||||||
error_handling::handle_parsing_error(
|
error_handling::handle_parsing_error(
|
||||||
|
|
@ -45,7 +45,8 @@ nodes::SymbolDocs build_symbol_docs(
|
||||||
annotation_parser_node);
|
annotation_parser_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
docs.add_annotation_info(annotation, annotation_parser_node.nth_child(1));
|
docs.add_annotation_info(
|
||||||
|
annotation, annotation_parser_node.nth_named_child(1).get_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
return docs;
|
return docs;
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ build_expression(parser::ParseTree::Node parser_node,
|
||||||
build_name_expression(parser_node, expression_storage, type_storage)));
|
build_name_expression(parser_node, expression_storage, type_storage)));
|
||||||
case tokens::Type::ARGUMENT_NAME_IDENTIFIER:
|
case tokens::Type::ARGUMENT_NAME_IDENTIFIER:
|
||||||
case tokens::Type::SIMPLE_NAME_IDENTIFIER:
|
case tokens::Type::SIMPLE_NAME_IDENTIFIER:
|
||||||
|
case tokens::Type::PLACEHOLDER:
|
||||||
return expression_storage.add_expression(
|
return expression_storage.add_expression(
|
||||||
nodes::Expression(nodes::NameExpression(
|
nodes::Expression(nodes::NameExpression(
|
||||||
build_node(parser_node), build_identifier(parser_node))));
|
build_node(parser_node), build_identifier(parser_node))));
|
||||||
|
|
@ -501,13 +502,15 @@ nodes::Lambda build_lambda(parser::ParseTree::Node parser_node,
|
||||||
nodes::TypeStorage &type_storage) {
|
nodes::TypeStorage &type_storage) {
|
||||||
std::vector<nodes::Identifier> arguments;
|
std::vector<nodes::Identifier> arguments;
|
||||||
|
|
||||||
auto current_node = parser_node.nth_child(1); // next to '\\'
|
auto current_node =
|
||||||
|
parser_node.nth_child(1); // next to '\\', not null ('=>' should present)
|
||||||
|
|
||||||
while (current_node.is_named()) { // until _do_
|
while (current_node.is_named()) { // until _do_
|
||||||
arguments.emplace_back(build_identifier(parser_node));
|
arguments.emplace_back(build_identifier(current_node));
|
||||||
current_node = current_node.next_sibling();
|
current_node = current_node.next_sibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip '=>'
|
||||||
current_node = current_node.next_named_sibling();
|
current_node = current_node.next_named_sibling();
|
||||||
|
|
||||||
return nodes::Lambda(
|
return nodes::Lambda(
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
nodes::FunctionDefinition::STATIC;
|
nodes::FunctionDefinition::STATIC;
|
||||||
|
|
||||||
current_node = name_node.previous_sibling();
|
current_node = name_node.previous_sibling();
|
||||||
if (current_node.is_named()) {
|
if (!current_node.is_null() && current_node.is_named()) {
|
||||||
std::string modifier_str = current_node.get_value();
|
std::string modifier_str = current_node.get_value();
|
||||||
if (modifier_str == "%" || modifier_str == "let") {
|
if (modifier_str == "%" || modifier_str == "let") {
|
||||||
modifier = nodes::FunctionDefinition::LET;
|
modifier = nodes::FunctionDefinition::LET;
|
||||||
|
|
@ -231,6 +231,8 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
std::vector<std::optional<std::string>> argument_annotations;
|
std::vector<std::optional<std::string>> argument_annotations;
|
||||||
std::vector<nodes::Modifier> argument_reference_types;
|
std::vector<nodes::Modifier> argument_reference_types;
|
||||||
std::vector<nodes::Identifier> arguments;
|
std::vector<nodes::Identifier> arguments;
|
||||||
|
std::vector<bool> optional_arguments;
|
||||||
|
std::vector<bool> result_arguments;
|
||||||
|
|
||||||
std::vector<std::optional<std::string>> type_annotations;
|
std::vector<std::optional<std::string>> type_annotations;
|
||||||
std::vector<nodes::Modifier> type_reference_types;
|
std::vector<nodes::Modifier> type_reference_types;
|
||||||
|
|
@ -241,7 +243,7 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
current_node = name_node.next_named_sibling();
|
current_node = name_node.next_named_sibling();
|
||||||
|
|
||||||
bool at_least_one_argument_annotation_found = false;
|
bool at_least_one_argument_annotation_found = false;
|
||||||
bool at_least_one_argument_reference_type_found = false;
|
bool at_least_one_argument_modifier_found = false;
|
||||||
|
|
||||||
std::optional<std::string> last_annotation;
|
std::optional<std::string> last_annotation;
|
||||||
nodes::Modifier last_reference_type = nodes::Modifier::NONE;
|
nodes::Modifier last_reference_type = nodes::Modifier::NONE;
|
||||||
|
|
@ -258,14 +260,27 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
case tokens::Type::ARGUMENT_NAME_IDENTIFIER:
|
case tokens::Type::ARGUMENT_NAME_IDENTIFIER:
|
||||||
if (last_annotation.has_value()) {
|
if (last_annotation.has_value()) {
|
||||||
at_least_one_argument_annotation_found = true;
|
at_least_one_argument_annotation_found = true;
|
||||||
|
at_least_one_argument_modifier_found = true;
|
||||||
}
|
}
|
||||||
if (last_reference_type != nodes::Modifier::NONE) {
|
if (last_reference_type != nodes::Modifier::NONE) {
|
||||||
at_least_one_argument_reference_type_found = true;
|
at_least_one_argument_modifier_found = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
argument_annotations.push_back(last_annotation);
|
argument_annotations.push_back(last_annotation);
|
||||||
argument_reference_types.push_back(last_reference_type);
|
argument_reference_types.push_back(last_reference_type);
|
||||||
arguments.push_back(build_identifier(current_node));
|
arguments.push_back(build_identifier(current_node));
|
||||||
|
optional_arguments.push_back(!current_node.next_sibling().is_null() &&
|
||||||
|
current_node.next_sibling().is_named() &&
|
||||||
|
current_node.next_sibling().get_value() ==
|
||||||
|
"?");
|
||||||
|
result_arguments.push_back(!current_node.next_sibling().is_null() &&
|
||||||
|
current_node.next_sibling().is_named() &&
|
||||||
|
current_node.next_sibling().get_value() ==
|
||||||
|
"!");
|
||||||
|
if (optional_arguments.back() | result_arguments.back()) {
|
||||||
|
at_least_one_argument_modifier_found = true;
|
||||||
|
}
|
||||||
|
|
||||||
last_reference_type = nodes::Modifier::NONE;
|
last_reference_type = nodes::Modifier::NONE;
|
||||||
last_annotation = std::nullopt;
|
last_annotation = std::nullopt;
|
||||||
break;
|
break;
|
||||||
|
|
@ -293,23 +308,21 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
|
|
||||||
if (!at_least_one_argument_annotation_found) {
|
if (!at_least_one_argument_annotation_found) {
|
||||||
for (size_t i = 0; i < argument_annotations.size(); ++i) {
|
for (size_t i = 0; i < argument_annotations.size(); ++i) {
|
||||||
argument_annotations[i] = *arguments[i].get();
|
std::string argument_annotation = *arguments[i].get();
|
||||||
|
argument_annotations[i] =
|
||||||
|
argument_annotation.substr(1, argument_annotation.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (types.empty()) {
|
if (types.empty()) {
|
||||||
annotations = &argument_annotations;
|
annotations = &argument_annotations;
|
||||||
reference_types = &argument_reference_types;
|
reference_types = &argument_reference_types;
|
||||||
} else if (at_least_one_argument_annotation_found) {
|
} else if (at_least_one_argument_modifier_found) {
|
||||||
error_handling::handle_parsing_error(
|
error_handling::handle_parsing_error(
|
||||||
"It is impossible to use argument annotations when types explicitely "
|
"It is impossible to use argument modifiers (annotations, references, "
|
||||||
|
"optional markers, result markers) when types explicitely "
|
||||||
"defined. Use type annotations instead.",
|
"defined. Use type annotations instead.",
|
||||||
parser_node);
|
parser_node);
|
||||||
} else if (at_least_one_argument_reference_type_found) {
|
|
||||||
error_handling::handle_parsing_error(
|
|
||||||
"It is impossible to use argument reference types when types "
|
|
||||||
"explicitely defined. Use type reference types instead.",
|
|
||||||
parser_node);
|
|
||||||
} else {
|
} else {
|
||||||
annotations = &type_annotations;
|
annotations = &type_annotations;
|
||||||
reference_types = &type_reference_types;
|
reference_types = &type_reference_types;
|
||||||
|
|
@ -332,6 +345,7 @@ build_function_definition(parser::ParseTree::Node parser_node,
|
||||||
std::move(constraints), modifier, build_identifier(name_node),
|
std::move(constraints), modifier, build_identifier(name_node),
|
||||||
std::move(*annotations), std::move(arguments),
|
std::move(*annotations), std::move(arguments),
|
||||||
std::move(*reference_types), std::move(types),
|
std::move(*reference_types), std::move(types),
|
||||||
|
std::move(optional_arguments), std::move(result_arguments),
|
||||||
expression_node.has_value()
|
expression_node.has_value()
|
||||||
? build_expression(expression_node.value(), expression_storage,
|
? build_expression(expression_node.value(), expression_storage,
|
||||||
type_storage)
|
type_storage)
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,25 @@ nodes::TypeProxy build_type(parser::ParseTree::Node parse_node,
|
||||||
auto name_node = parse_node.child_by_field_name("name");
|
auto name_node = parse_node.child_by_field_name("name");
|
||||||
|
|
||||||
auto current_node = parse_node.nth_child(0);
|
auto current_node = parse_node.nth_child(0);
|
||||||
bool is_on_heap = !current_node.is_null() && current_node.get_value() == "^";
|
bool is_on_heap = (!current_node.is_null() && !current_node.is_named() &&
|
||||||
|
current_node.get_value() == "^");
|
||||||
|
|
||||||
current_node = name_node.next_sibling();
|
current_node = name_node.next_sibling();
|
||||||
bool is_optional = !current_node.is_null() && current_node.get_value() == "?";
|
bool is_optional = (!current_node.is_null() && !current_node.is_named() &&
|
||||||
|
current_node.get_value() == "?");
|
||||||
|
|
||||||
|
bool is_result = (!current_node.is_null() && !current_node.is_named() &&
|
||||||
|
current_node.get_value() == "!");
|
||||||
|
|
||||||
current_node = name_node.next_named_sibling();
|
current_node = name_node.next_named_sibling();
|
||||||
while (!current_node.is_null()) {
|
while (!current_node.is_null()) {
|
||||||
parameters.push_back(build_type(current_node, type_storage));
|
parameters.push_back(build_type(current_node, type_storage));
|
||||||
current_node = name_node.next_named_sibling();
|
current_node = current_node.next_named_sibling();
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_storage.add_type(
|
return type_storage.add_type(
|
||||||
nodes::Type(build_node(parse_node),
|
nodes::Type(build_node(parse_node), build_identifier(name_node),
|
||||||
tokens::string_to_type(name_node.get_type()) ==
|
std::move(parameters), is_on_heap, is_optional, is_result));
|
||||||
tokens::Type::ARGUMENT_TYPE_IDENTIFIER
|
|
||||||
? build_argument_type(name_node)
|
|
||||||
: build_simple_type(name_node),
|
|
||||||
std::move(parameters), is_on_heap, is_optional));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// '&'? annotation? type ('&' annotation? type)*
|
// '&'? annotation? type ('&' annotation? type)*
|
||||||
|
|
|
||||||
218
tests/test.langexp
Normal file
218
tests/test.langexp
Normal file
|
|
@ -0,0 +1,218 @@
|
||||||
|
#!/usr/bin/env lang
|
||||||
|
|
||||||
|
:: module; // import module to current namespace
|
||||||
|
|
||||||
|
:: _ = module; // import module to current namespace and use functions inside without namespace
|
||||||
|
|
||||||
|
:: module : func1 func2 func3;
|
||||||
|
:: module_namespace = module;
|
||||||
|
|
||||||
|
func = {
|
||||||
|
|
||||||
|
@ => {
|
||||||
|
%x := scan;
|
||||||
|
?? x == ''x'' => break;
|
||||||
|
};
|
||||||
|
|
||||||
|
@ i < 10 => {
|
||||||
|
inc i;
|
||||||
|
};
|
||||||
|
|
||||||
|
@ %x : 1..10 => {
|
||||||
|
print "Hello World!\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
?? abracadabbra < abracadabra_abracadabra || some_long_name == another_long_name
|
||||||
|
&&. abracadabra-abracadabra < long_long_long_long_name => io.print x
|
||||||
|
!! x < 0 => {
|
||||||
|
x += 1;
|
||||||
|
io.print y;
|
||||||
|
} !!=> return ();
|
||||||
|
}
|
||||||
|
|
||||||
|
: example of function with optional arguments (without type annotation)
|
||||||
|
: real type is 'A? 'A? -> 'A?
|
||||||
|
sum 'a? 'b? =
|
||||||
|
'a & 'b =: %a? & %b? => a + b
|
||||||
|
=: _ => null;
|
||||||
|
|
||||||
|
|
||||||
|
: example that shows that default annotations are argument names (without ')
|
||||||
|
@a is integer
|
||||||
|
@b also integer
|
||||||
|
sum 'a 'b = 'a + 'b;
|
||||||
|
|
||||||
|
: this function can be used to calculate Fibonacci sequence elements
|
||||||
|
: it is important is some algorithmic tasks
|
||||||
|
: also this is example of function constraint
|
||||||
|
@n is position in Fibonacci sequence
|
||||||
|
? 'n >= 0;
|
||||||
|
fib 'n : @n Int -> Int =
|
||||||
|
'n =: 0 | 1 => 1
|
||||||
|
=: _ => fib ('n - 1) + fib 'n;
|
||||||
|
|
||||||
|
func_2 = {
|
||||||
|
%variant := x;
|
||||||
|
|
||||||
|
%val | %err := f x;
|
||||||
|
|
||||||
|
%lambda1 := \'x 'y => 'x + 'y;
|
||||||
|
|
||||||
|
%lambda2 := \ => 3;
|
||||||
|
|
||||||
|
variant =: 1 | 2 => "a"
|
||||||
|
=: 3..10 => "b"
|
||||||
|
=: 45 | 55 | x ?? x > 100 => "c"
|
||||||
|
=: _ => "another variants";
|
||||||
|
|
||||||
|
// all var arrays are dynamic
|
||||||
|
$array := [[x y z]];
|
||||||
|
array.push a;
|
||||||
|
|
||||||
|
%x := maybe_something => do_something
|
||||||
|
:= _ => do_something_another;
|
||||||
|
|
||||||
|
%x := Task @name "do something" @duration 123.1;
|
||||||
|
|
||||||
|
// open optional: execute expression only if not null
|
||||||
|
%x? := maybe_something => do_something;
|
||||||
|
|
||||||
|
// open optional: return null to all outputs (all outputs should be optional values)
|
||||||
|
%x? := maybe_something;
|
||||||
|
|
||||||
|
// open optional: panic on null
|
||||||
|
%x! := maybe_something;
|
||||||
|
|
||||||
|
// open optional: return null to all outputs (all outputs should be optional values)
|
||||||
|
maybe_something?;
|
||||||
|
|
||||||
|
// open optional: panic on null
|
||||||
|
maybe_something!;
|
||||||
|
|
||||||
|
// open optional: if null then return default value (operator)
|
||||||
|
%x := maybe_something ?| value
|
||||||
|
|
||||||
|
%y := Fruit @apple ();
|
||||||
|
|
||||||
|
y =: Fruit @apple () => "apple"
|
||||||
|
=: Fruit @orange () => "orange"
|
||||||
|
=: Fruit @banana () => "banana";
|
||||||
|
|
||||||
|
%z := ( + ) 1 2;
|
||||||
|
|
||||||
|
// tuple access
|
||||||
|
%t := 1 & 2 & 3;
|
||||||
|
print t.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
: operator definition example
|
||||||
|
( - ) 'a 'b = 'a + neg 'b;
|
||||||
|
|
||||||
|
test.something = {
|
||||||
|
do_something a b c;
|
||||||
|
}
|
||||||
|
|
||||||
|
exec.something = {
|
||||||
|
do_something a b c;
|
||||||
|
}
|
||||||
|
|
||||||
|
example.something = {
|
||||||
|
do_something a b c;
|
||||||
|
}
|
||||||
|
|
||||||
|
Task = @name String
|
||||||
|
& @duration Float;
|
||||||
|
|
||||||
|
Fruit = @apple Unit
|
||||||
|
| @orange Unit
|
||||||
|
| @banana Unit;
|
||||||
|
|
||||||
|
: function that takes array reference argument
|
||||||
|
bubble_sort 'arr : <> Array['A] = {
|
||||||
|
swap_occured := true;
|
||||||
|
@ swap_occured => {
|
||||||
|
swap_occured = false;
|
||||||
|
@ %i : 0 .. 'arr.size => (?? 'arr[i] > 'arr[i + 1] => swap 'arr[i] 'arr[i + 1], swap_occured = true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
: bubble_sort with names instead of symbols
|
||||||
|
bubble_sort 'arr : ref Array['A] = {
|
||||||
|
var swap_occured := true;
|
||||||
|
for swap_occured do {
|
||||||
|
swap_occured = false;
|
||||||
|
for let i : 0 .. 'arr.size do (if 'arr[i] > 'arr[i + 1] do swap 'arr[i] 'arr[i + 1], swap_occured = true);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
: example of ^ and generics. ^ used to denote that this object allocated on heap
|
||||||
|
: object allocated by unique reference by default
|
||||||
|
^TreeNode 'Key 'Value =
|
||||||
|
& @key Key
|
||||||
|
& @value Value
|
||||||
|
& @left ^TreeNode['Key 'Value]
|
||||||
|
& @right ^TreeNode['Key 'Value];
|
||||||
|
|
||||||
|
TreeNode {
|
||||||
|
new = do_something; // static methods
|
||||||
|
|
||||||
|
$insert 'key = do_something; // const methods
|
||||||
|
|
||||||
|
%find 'key = do_something;
|
||||||
|
|
||||||
|
$delete 'key = do_something; // var methods
|
||||||
|
}
|
||||||
|
|
||||||
|
generic_type_name_expressions = {
|
||||||
|
$x := TreeNode[Int Int].new;
|
||||||
|
$y := std.Array[Int].new;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipes_example = {
|
||||||
|
expr |> func_1 a b |> func_2 c d |> print; // print (func_2 (func_1 expr a b) c d)
|
||||||
|
print <| func_1 a b <| func_2 c d <| expr; // print (func_1 a b (func_2 c d expr))
|
||||||
|
}
|
||||||
|
|
||||||
|
test_ref_access_precendence = {
|
||||||
|
%x := <> arr[123];
|
||||||
|
}
|
||||||
|
|
||||||
|
// by default constant arguments are used
|
||||||
|
|
||||||
|
: constant arguments example, type - 'A 'B
|
||||||
|
print_two 'a 'b = print 'a, print 'b;
|
||||||
|
|
||||||
|
: example of reference args and comma operator
|
||||||
|
swap 'a 'b : <> 'A <> 'A = %c := <- 'a, 'a := <- 'b, 'b := <- c;
|
||||||
|
|
||||||
|
: previous example with automatic type deduction
|
||||||
|
swap <> 'a <> 'b = %c := <- 'a, 'a := <- 'b, 'b := <- c;
|
||||||
|
|
||||||
|
: several outputs example
|
||||||
|
scan_three : -> String -> String -> String = scan & scan & scan;
|
||||||
|
|
||||||
|
: output by argument
|
||||||
|
scan_to_variable 'a : -> String = 'a := scan;
|
||||||
|
|
||||||
|
: consuming input example
|
||||||
|
move_construct_task 'name 'duration : <- String <- Float -> Task = Task @name 'name @duration 'duration;
|
||||||
|
|
||||||
|
: copy constructing, field annotations deduced
|
||||||
|
arg_deduction_example 'name 'duration : <- String <- Float -> Task = Task 'name 'duration;
|
||||||
|
|
||||||
|
: ord is fundamental typeclass
|
||||||
|
#Ord : #Eq {
|
||||||
|
$is_less_then : Ord -> Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
: function, that takes result argument
|
||||||
|
result_example 'a! = 'a =: _? => print "value inside"
|
||||||
|
=: _ => print "error inside";
|
||||||
|
|
||||||
|
: function, that returns result
|
||||||
|
parse_number : Unit! = {
|
||||||
|
%number_str := String.scan;
|
||||||
|
%number! := Int.parse number_str;
|
||||||
|
number.print;
|
||||||
|
bring ();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue