Rename libs/type -> libs/types, separate computed type tree from the AST type tree

This commit is contained in:
Nikita Lisitsa 2025-12-20 00:03:23 +03:00
parent 437123f6f4
commit 4175a86ae3
31 changed files with 335 additions and 216 deletions

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.30)
project(pslang CXX)
add_subdirectory(libs/type)
add_subdirectory(libs/types)
add_subdirectory(libs/ast)
add_subdirectory(libs/parser)
add_subdirectory(libs/jit)

View file

@ -3,4 +3,4 @@ file(GLOB_RECURSE PSLANG_AST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
add_library(pslang-ast STATIC ${PSLANG_AST_HEADERS} ${PSLANG_AST_SOURCES})
target_include_directories(pslang-ast PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(pslang-ast PUBLIC pslang-type)
target_link_libraries(pslang-ast PUBLIC pslang-types)

View file

@ -2,7 +2,7 @@
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/type/type.hpp>
#include <pslang/ast/type.hpp>
namespace pslang::ast
{
@ -10,7 +10,7 @@ namespace pslang::ast
struct cast_operation
{
expression_ptr expression;
type::type_ptr type;
type_ptr type;
ast::location location;
};

View file

@ -3,7 +3,7 @@
#include <pslang/ast/statement_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/type/type_fwd.hpp>
#include <pslang/ast/type_fwd.hpp>
#include <string>
#include <vector>
@ -16,13 +16,13 @@ namespace pslang::ast
struct argument
{
std::string name;
type::type_ptr type;
type_ptr type;
ast::location location;
};
std::string name;
std::vector<argument> arguments;
type::type_ptr return_type;
type_ptr return_type;
statement_list_ptr statements;
ast::location location;
};

View file

@ -7,7 +7,7 @@
#include <pslang/ast/function.hpp>
#include <pslang/ast/struct.hpp>
#include <pslang/ast/statement_fwd.hpp>
#include <pslang/type/type.hpp>
#include <pslang/ast/type.hpp>
#include <variant>
@ -18,7 +18,7 @@ namespace pslang::ast
{
value_category category;
std::string name;
type::type_ptr type;
type_ptr type;
expression_ptr initializer;
ast::location location;
};

View file

@ -1,7 +1,7 @@
#pragma once
#include <pslang/type/type_fwd.hpp>
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/type_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <string>
@ -13,7 +13,7 @@ namespace pslang::ast
struct field_definition
{
std::string name;
type::type_ptr type;
ast::type_ptr type;
ast::location location;
};

View file

@ -0,0 +1,49 @@
#pragma once
#include <pslang/types/unit.hpp>
#include <pslang/types/primitive.hpp>
#include <pslang/types/array.hpp>
#include <pslang/types/function.hpp>
#include <pslang/types/type_fwd.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/ast/type_fwd.hpp>
#include <variant>
namespace pslang::ast
{
struct array_type
{
type_ptr element_type;
std::uint64_t size;
};
struct function_type
{
std::vector<type_ptr> arguments;
type_ptr result;
};
struct type_identifier
{
std::string name;
ast::location location;
std::size_t level = 0;
};
using type_impl = std::variant<
types::unit_type,
types::primitive_type,
array_type,
function_type,
type_identifier
>;
struct type
: type_impl
{
using type_impl::type_impl;
};
}

View file

@ -0,0 +1,12 @@
#pragma once
#include <memory>
namespace pslang::ast
{
struct type;
using type_ptr = std::shared_ptr<type>;
}

View file

@ -1,5 +1,6 @@
#include <pslang/ast/print.hpp>
#include <pslang/type/print.hpp>
#include <pslang/types/print.hpp>
#include <pslang/types/type.hpp>
#include <iomanip>
@ -21,6 +22,56 @@ namespace pslang::ast
out << options.indent_string;
}
void print(std::ostream & out, type const & type, print_options const & options);
void print_impl(std::ostream & out, types::unit_type const &, print_options const &)
{
out << "unit";
}
void print_impl(std::ostream & out, types::primitive_type const & type, print_options const &)
{
types::print(out, type);
}
void print_impl(std::ostream & out, array_type const & type, print_options const & options)
{
print(out, *type.element_type, options);
out << "[" << type.size << "]";
}
void print_impl(std::ostream & out, function_type const & type, print_options const & options)
{
if (type.arguments.size() == 1)
{
print(out, *type.arguments.front(), options);
out << " -> ";
print(out, *type.result, options);
return;
}
out << '(';
bool first = true;
for (auto const & argument : type.arguments)
{
if (!first) out << ", ";
first = false;
print(out, *argument, options);
}
out << ") -> ";
print(out, *type.result, options);
}
void print_impl(std::ostream & out, type_identifier const & type, print_options const & options)
{
out << type.name;
}
void print(std::ostream & out, type const & type, print_options const & options)
{
std::visit([&](auto const & type){ print_impl(out, type, options); }, type);
}
void print_impl(std::ostream & out, bool_literal const & node, print_options const & options)
{
put_indent(out, options);
@ -117,7 +168,7 @@ namespace pslang::ast
{
put_indent(out, options);
out << "cast as ";
type::print(out, *node.type);
print(out, *node.type, options);
out << '\n';
print(out, node.expression, child(options));
}
@ -174,7 +225,7 @@ namespace pslang::ast
if (node.type)
{
out << ", type = ";
type::print(out, *node.type);
print(out, *node.type, options);
}
out << " }\n";
print(out, node.initializer, child(options));
@ -234,13 +285,13 @@ namespace pslang::ast
{
put_indent(out, options);
out << "function { name = \"" << node.name << "\", return type = ";
type::print(out, *node.return_type);
print(out, *node.return_type, options);
out << " }\n";
for (auto const & arg : node.arguments)
{
put_indent(out, child(options));
out << "argument { name = \"" << arg.name << "\", type = ";
type::print(out, *arg.type);
print(out, *arg.type, options);
out << " }\n";
}
put_indent(out, child(options));
@ -260,7 +311,7 @@ namespace pslang::ast
{
put_indent(out, options);
out << "field { name = \"" << node.name << "\", type = ";
type::print(out, *node.type);
print(out, *node.type, options);
out << " }\n";
}

View file

@ -57,29 +57,29 @@ namespace pslang::ast
std::vector<scope> scopes;
};
void resolve_identifiers(context & context, type::type & type);
void resolve_identifiers(context & context, type & type);
void resolve_identifiers(context & context, expression & expression);
void resolve_identifiers(context & context, statement_list const & statements);
void resolve_identifiers_impl(context &, type::unit_type const &)
void resolve_identifiers_impl(context &, types::unit_type const &)
{}
void resolve_identifiers_impl(context &, type::primitive_type const &)
void resolve_identifiers_impl(context &, types::primitive_type const &)
{}
void resolve_identifiers_impl(context & context, type::array_type const & array_type)
void resolve_identifiers_impl(context & context, array_type const & array_type)
{
resolve_identifiers(context, *array_type.element_type);
}
void resolve_identifiers_impl(context & context, type::function_type const & function_type)
void resolve_identifiers_impl(context & context, function_type const & function_type)
{
for (auto const & argument : function_type.arguments)
resolve_identifiers(context, *argument);
resolve_identifiers(context, *function_type.result);
}
void resolve_identifiers_impl(context & context, type::identifier & identifier)
void resolve_identifiers_impl(context & context, type_identifier & identifier)
{
for (auto it = context.scopes.rbegin(); it != context.scopes.rend(); ++it)
{
@ -94,7 +94,7 @@ namespace pslang::ast
throw parse_error("Identifier \"" + identifier.name + "\" not found", {});
}
void resolve_identifiers(context & context, type::type & type)
void resolve_identifiers(context & context, type & type)
{
return std::visit([&](auto & type){ return resolve_identifiers_impl(context, type); }, type);
}

View file

@ -21,7 +21,13 @@ namespace pslang::interpreter
struct struct_data
{
std::vector<ast::field_definition> fields;
struct field
{
std::string name;
types::type_ptr type;
};
std::vector<field> fields;
};
struct scope

View file

@ -3,11 +3,13 @@
#include <pslang/interpreter/context.hpp>
#include <pslang/interpreter/value.hpp>
#include <pslang/ast/expression_fwd.hpp>
#include <pslang/ast/type_fwd.hpp>
#include <pslang/types/type.hpp>
namespace pslang::interpreter
{
type::type resolve_type(context & context, type::type const & type);
types::type resolve_type(context & context, ast::type const & type);
value eval(context & context, ast::expression_ptr const & expression);

View file

@ -1,6 +1,6 @@
#pragma once
#include <pslang/type/type.hpp>
#include <pslang/types/type.hpp>
#include <pslang/ast/function.hpp>
#include <pslang/interpreter/value_fwd.hpp>
@ -60,20 +60,26 @@ namespace pslang::interpreter
struct array_value
{
// Can't infer type from elements in case of zero-sized array
type::type_ptr element_type;
types::type_ptr element_type;
std::vector<value_ptr> elements;
};
struct struct_value
{
type::type_ptr struct_type;
types::type_ptr struct_type;
std::unordered_map<std::string, value_ptr> fields;
};
struct function_value
{
std::vector<ast::function_definition::argument> arguments;
type::type_ptr return_type;
struct argument
{
std::string name;
types::type_ptr type;
};
std::vector<argument> arguments;
types::type_ptr return_type;
ast::statement_list_ptr statements;
};
@ -91,7 +97,7 @@ namespace pslang::interpreter
using value_impl::value_impl;
};
type::type type_of(value const & value);
types::type type_of(value const & value);
void print(std::ostream & out, value const & value);

View file

@ -1,5 +1,5 @@
#include <pslang/interpreter/context.hpp>
#include <pslang/type/print.hpp>
#include <pslang/types/print.hpp>
namespace pslang::interpreter
{
@ -20,7 +20,7 @@ namespace pslang::interpreter
out << variable.first << " = ";
print(out, variable.second.value);
out << " (";
type::print(out, type_of(variable.second.value));
types::print(out, type_of(variable.second.value));
out << ")\n";
}
}

View file

@ -2,7 +2,7 @@
#include <pslang/interpreter/exec.hpp>
#include <pslang/interpreter/value.hpp>
#include <pslang/ast/expression.hpp>
#include <pslang/type/print.hpp>
#include <pslang/types/print.hpp>
#include <sstream>
#include <optional>
@ -13,44 +13,36 @@ namespace pslang::interpreter
namespace
{
type::type resolve_type_impl(context &, type::unit_type const & type)
types::type resolve_type_impl(context &, types::unit_type const & type)
{
return type;
}
type::type resolve_type_impl(context &, type::primitive_type const & type)
types::type resolve_type_impl(context &, types::primitive_type const & type)
{
return type;
}
type::type resolve_type_impl(context & context, type::array_type const & type)
types::type resolve_type_impl(context & context, ast::array_type const & type)
{
return type::array_type{std::make_unique<type::type>(resolve_type(context, *type.element_type)), type.size};
return types::array_type{std::make_unique<types::type>(resolve_type(context, *type.element_type)), type.size};
}
type::type resolve_type_impl(context & context, type::function_type const & type)
types::type resolve_type_impl(context & context, ast::function_type const & type)
{
type::function_type result;
types::function_type result;
for (auto const & argument : type.arguments)
result.arguments.push_back(std::make_unique<type::type>(resolve_type(context, *argument)));
result.result = std::make_unique<type::type>(resolve_type(context, *type.result));
result.arguments.push_back(std::make_unique<types::type>(resolve_type(context, *argument)));
result.result = std::make_unique<types::type>(resolve_type(context, *type.result));
return result;
}
type::type resolve_type_impl(context & context, type::identifier const & type)
types::type resolve_type_impl(context & context, ast::type_identifier const & type)
{
for (auto it = context.scope_stack.rbegin(); it != context.scope_stack.rend(); ++it)
{
if (it->structs.count(type.name))
{
return type::identifier{std::string(it.base() - context.scope_stack.begin() - 1, '/') + type.name};
}
return types::named_type{type.name, type.level};
}
throw std::runtime_error("Type \"" + type.name + "\" is not defined");
}
type::type resolve_type_impl(context & context, type::type const & type)
types::type resolve_type_impl(context & context, ast::type const & type)
{
return std::visit([&](auto const & type){ return resolve_type_impl(context, type); }, type);
}
@ -166,7 +158,7 @@ namespace pslang::interpreter
{
std::ostringstream os;
os << "Cannot index into an array with an expression of type ";
type::print(os, type_of(index));
types::print(os, type_of(index));
throw std::runtime_error(os.str());
}
@ -223,7 +215,7 @@ namespace pslang::interpreter
os << "Cannot apply unary operator \"";
print(os, type);
os << "\" to a value of type ";
type::print(os, type_of(value));
types::print(os, type_of(value));
throw std::runtime_error(os.str());
}
@ -254,7 +246,7 @@ namespace pslang::interpreter
os << "Cannot apply unary operator \"";
print(os, type);
os << "\" to a value of type ";
type::print(os, type_of(primitive_value(arg1)));
types::print(os, type_of(primitive_value(arg1)));
throw std::runtime_error(os.str());
}
@ -370,9 +362,9 @@ namespace pslang::interpreter
os << "Cannot apply binary operator \"";
print(os, type);
os << "\" to values of type ";
type::print(os, type_of(primitive_value(arg1)));
types::print(os, type_of(primitive_value(arg1)));
os << " and ";
type::print(os, type_of(primitive_value(arg2)));
types::print(os, type_of(primitive_value(arg2)));
throw std::runtime_error(os.str());
}
@ -383,9 +375,9 @@ namespace pslang::interpreter
os << "Cannot apply binary operator \"";
print(os, type);
os << "\" to values of type ";
type::print(os, type_of(arg1));
types::print(os, type_of(arg1));
os << " and ";
type::print(os, type_of(arg2));
types::print(os, type_of(arg2));
throw std::runtime_error(os.str());
}
@ -404,15 +396,15 @@ namespace pslang::interpreter
auto type1 = type_of(arg1);
auto type2 = type_of(arg2);
if (!type::equal(type1, type2))
if (!types::equal(type1, type2))
{
std::ostringstream os;
os << "Cannot apply binary operator \"";
print(os, binary_operation.type);
os << "\" to values of type ";
type::print(os, type1);
types::print(os, type1);
os << " and ";
type::print(os, type2);
types::print(os, type2);
throw std::runtime_error(os.str());
}
@ -422,30 +414,30 @@ namespace pslang::interpreter
throw std::runtime_error("eval(binary_operation) for different argument types not implemented");
}
value cast_impl(unit_value const & value, type::type const & type)
value cast_impl(unit_value const & value, types::type const & type)
{
if (type::equal(type, type::unit_type{}))
if (types::equal(type, types::unit_type{}))
return value;
throw std::runtime_error("Cannot cast unit type to anything");
}
value cast_impl(array_value const & value, type::type const & type)
value cast_impl(array_value const & value, types::type const & type)
{
if (type::equal(type, type_of(value)))
if (types::equal(type, type_of(value)))
return value;
throw std::runtime_error("Cannot cast array type to anything");
}
template <typename T>
value cast_impl(primitive_value_base<T> const & value, type::unit_type const &)
value cast_impl(primitive_value_base<T> const & value, types::unit_type const &)
{
throw std::runtime_error("Cannot cast anything to unit type");
}
template <typename T, typename H>
value cast_impl(primitive_value_base<T> const & value, type::primitive_type_base<H> const & type)
value cast_impl(primitive_value_base<T> const & value, types::primitive_type_base<H> const & type)
{
if constexpr (std::is_same_v<T, H>)
{
@ -458,50 +450,50 @@ namespace pslang::interpreter
std::ostringstream os;
os << "Cannot cast value of type ";
type::print(os, type_of(primitive_value(value)));
types::print(os, type_of(primitive_value(value)));
os << " to type ";
type::print(os, type::primitive_type(type));
types::print(os, types::primitive_type(type));
throw std::runtime_error(os.str());
}
template <typename T>
value cast_impl(primitive_value_base<T> const & value, type::primitive_type const & type)
value cast_impl(primitive_value_base<T> const & value, types::primitive_type const & type)
{
return std::visit([&](auto const & type){ return cast_impl(value, type); }, type);
}
template <typename T>
value cast_impl(primitive_value_base<T> const &, type::array_type const &)
value cast_impl(primitive_value_base<T> const &, types::array_type const &)
{
throw std::runtime_error("Cannot cast anything to array type");
}
template <typename T>
value cast_impl(primitive_value_base<T> const &, type::function_type const &)
value cast_impl(primitive_value_base<T> const &, types::function_type const &)
{
throw std::runtime_error("Cannot cast anything to function type");
}
template <typename T>
value cast_impl(primitive_value_base<T> const & value, type::type const & type)
value cast_impl(primitive_value_base<T> const & value, types::type const & type)
{
return std::visit([&](auto const & type){ return cast_impl(value, type); }, type);
}
value cast_impl(primitive_value const & value, type::type const & type)
value cast_impl(primitive_value const & value, types::type const & type)
{
return std::visit([&](auto const & value){ return cast_impl(value, type); }, value);
}
value cast_impl(struct_value const & value, type::type const & type)
value cast_impl(struct_value const & value, types::type const & type)
{
if (type::equal(type, type::unit_type{}))
if (types::equal(type, types::unit_type{}))
return value;
throw std::runtime_error("Cannot cast struct type to anything");
}
value cast_impl(function_value const &, type::type const &)
value cast_impl(function_value const &, types::type const &)
{
throw std::runtime_error("Cannot cast function type to anything");
}
@ -509,7 +501,8 @@ namespace pslang::interpreter
value eval_impl(context & context, ast::cast_operation const & cast_operation)
{
auto arg = eval(context, cast_operation.expression);
return std::visit([&](auto const & value){ return cast_impl(value, *cast_operation.type); }, arg);
auto type = resolve_type(context, *cast_operation.type);
return std::visit([&](auto const & value){ return cast_impl(value, type); }, arg);
}
value eval_impl(context & context, ast::function_call const & function_call)
@ -537,13 +530,13 @@ namespace pslang::interpreter
for (std::size_t i = 0; i < args.size(); ++i)
{
auto actual_type = type_of(args[i]);
if (!type::equal(actual_type, *jt->second.fields[i].type))
if (!types::equal(actual_type, *jt->second.fields[i].type))
{
std::ostringstream os;
os << "Cannot create struct \"" << identifier->name << "\": field " << jt->second.fields[i].name << " expects type ";
type::print(os, *jt->second.fields[i].type);
types::print(os, *jt->second.fields[i].type);
os << " but actual type is ";
type::print(os, actual_type);
types::print(os, actual_type);
throw std::runtime_error(os.str());
}
@ -551,7 +544,7 @@ namespace pslang::interpreter
}
return struct_value{
.struct_type = std::make_unique<type::type>(resolve_type(context, type::identifier{identifier->name})),
.struct_type = std::make_unique<types::type>(types::named_type{.name = identifier->name, .level = identifier->level}),
.fields = std::move(fields),
};
}
@ -576,13 +569,13 @@ namespace pslang::interpreter
for (std::size_t i = 0; i < args.size(); ++i)
{
auto actual_type = type_of(args[i]);
if (!type::equal(actual_type, *fvalue->arguments[i].type))
if (!types::equal(actual_type, *fvalue->arguments[i].type))
{
std::ostringstream os;
os << "Cannot call function: argument #" << (i + 1) << " expects type ";
type::print(os, *fvalue->arguments[i].type);
types::print(os, *fvalue->arguments[i].type);
os << " but actual type is ";
type::print(os, actual_type);
types::print(os, actual_type);
throw std::runtime_error(os.str());
}
}
@ -598,13 +591,13 @@ namespace pslang::interpreter
exec(context, fvalue->statements);
auto actual_return_type = type_of(context.scope_stack.back().return_value);
if (!type::equal(actual_return_type, *expected_return_type))
if (!types::equal(actual_return_type, *expected_return_type))
{
std::ostringstream os;
os << "Error returning from function: expected return type is ";
type::print(os, *expected_return_type);
types::print(os, *expected_return_type);
os << " but actual type is ";
type::print(os, actual_return_type);
types::print(os, actual_return_type);
throw std::runtime_error(os.str());
}
@ -625,23 +618,23 @@ namespace pslang::interpreter
if (array.elements.empty())
throw std::runtime_error("Internal error: array ast node cannot have zero elements");
type::type_ptr element_type;
types::type_ptr element_type;
std::vector<value_ptr> elements;
for (std::size_t i = 0; i < array.elements.size(); ++i)
{
auto element = std::make_unique<value>(eval(context, array.elements[i]));
if (i == 0)
element_type = std::make_unique<type::type>(type_of(*element));
element_type = std::make_unique<types::type>(type_of(*element));
else
{
auto new_type = type_of(*element);
if (!type::equal(*element_type, new_type))
if (!types::equal(*element_type, new_type))
{
std::ostringstream os;
os << "Error forming array: inferred element type is ";
type::print(os, *element_type);
types::print(os, *element_type);
os << " but element #" << i << " type is ";
type::print(os, new_type);
types::print(os, new_type);
throw std::runtime_error(os.str());
}
}
@ -664,7 +657,7 @@ namespace pslang::interpreter
std::ostringstream os;
os << "Cannot index into a non-array of type ";
type::print(os, type_of(array));
types::print(os, type_of(array));
throw std::runtime_error(os.str());
}
@ -678,14 +671,14 @@ namespace pslang::interpreter
std::ostringstream os;
os << "Struct ";
type::print(os, type_of(object));
types::print(os, type_of(object));
os << " has no field named \"" << field_access.field_name << "\"";
throw std::runtime_error(os.str());
}
std::ostringstream os;
os << "Value of type ";
type::print(os, type_of(object));
types::print(os, type_of(object));
os << " is not a struct";
throw std::runtime_error(os.str());
}
@ -753,7 +746,7 @@ namespace pslang::interpreter
std::ostringstream os;
os << "Cannot index into a non-array of type ";
type::print(os, type_of(*array_ref));
types::print(os, type_of(*array_ref));
throw std::runtime_error(os.str());
}
@ -767,14 +760,14 @@ namespace pslang::interpreter
std::ostringstream os;
os << "Struct ";
type::print(os, type_of(*object_ref));
types::print(os, type_of(*object_ref));
os << " has no field named \"" << field_access.field_name << "\"";
throw std::runtime_error(os.str());
}
std::ostringstream os;
os << "Value of type ";
type::print(os, type_of(*object_ref));
types::print(os, type_of(*object_ref));
os << " is not a struct";
throw std::runtime_error(os.str());
}
@ -786,7 +779,7 @@ namespace pslang::interpreter
}
type::type resolve_type(context & context, type::type const & type)
types::type resolve_type(context & context, ast::type const & type)
{
return resolve_type_impl(context, type);
}

View file

@ -1,7 +1,7 @@
#include <pslang/interpreter/exec.hpp>
#include <pslang/interpreter/eval.hpp>
#include <pslang/ast/statement.hpp>
#include <pslang/type/print.hpp>
#include <pslang/types/print.hpp>
#include <stdexcept>
#include <sstream>
@ -43,13 +43,13 @@ namespace pslang::interpreter
auto ref = eval_ref(context, assignment.lhs);
auto existing_type = type_of(*ref);
if (!type::equal(existing_type, new_type))
if (!types::equal(existing_type, new_type))
{
std::ostringstream os;
os << "Cannot assign a value of type ";
type::print(os, new_type);
types::print(os, new_type);
os << " to a variable of type ";
type::print(os, existing_type);
types::print(os, existing_type);
throw std::runtime_error(os.str());
}
@ -67,13 +67,13 @@ namespace pslang::interpreter
{
auto expected_type = resolve_type(context, *variable_declaration.type);
auto actual_type = type_of(value);
if (!type::equal(expected_type, actual_type))
if (!types::equal(expected_type, actual_type))
{
std::ostringstream os;
os << "Cannot initialize a variable of type ";
type::print(os, expected_type);
types::print(os, expected_type);
os << " with an expression of type ";
type::print(os, actual_type);
types::print(os, actual_type);
throw std::runtime_error(os.str());
}
}
@ -105,11 +105,11 @@ namespace pslang::interpreter
{
auto value = eval(context, block.condition);
auto actual_type = type_of(value);
if (!type::equal(actual_type, type::primitive_type{type::bool_type{}}))
if (!types::equal(actual_type, types::primitive_type{types::bool_type{}}))
{
std::ostringstream os;
os << "Expected type bool, got type ";
type::print(os, actual_type);
types::print(os, actual_type);
os << " in if block condition";
throw std::runtime_error(os.str());
}
@ -133,11 +133,11 @@ namespace pslang::interpreter
{
auto value = eval(context, while_block.condition);
auto actual_type = type_of(value);
if (!type::equal(actual_type, type::primitive_type{type::bool_type{}}))
if (!types::equal(actual_type, types::primitive_type{types::bool_type{}}))
{
std::ostringstream os;
os << "Expected type bool, got type ";
type::print(os, actual_type);
types::print(os, actual_type);
os << " in while block condition";
throw std::runtime_error(os.str());
}
@ -162,8 +162,8 @@ namespace pslang::interpreter
function_value value;
for (auto const & argument : function_definition.arguments)
value.arguments.push_back({.name = argument.name, .type = std::make_unique<type::type>(resolve_type(context, *argument.type))});
value.return_type = std::make_unique<type::type>(resolve_type(context, *function_definition.return_type));
value.arguments.push_back({.name = argument.name, .type = std::make_unique<types::type>(resolve_type(context, *argument.type))});
value.return_type = std::make_unique<types::type>(resolve_type(context, *function_definition.return_type));
value.statements = function_definition.statements;
scope.variables[function_definition.name] = {.category = ast::value_category::constant, .value = std::move(value)};
@ -200,7 +200,7 @@ namespace pslang::interpreter
{
result.fields.push_back({
.name = field.name,
.type = std::make_unique<type::type>(resolve_type(context, *field.type)),
.type = std::make_unique<types::type>(resolve_type(context, *field.type)),
});
}
scope.structs[struct_definition.name] = std::move(result);

View file

@ -1,5 +1,5 @@
#include <pslang/interpreter/value.hpp>
#include <pslang/type/print.hpp>
#include <pslang/types/print.hpp>
#include <iomanip>
@ -9,42 +9,42 @@ namespace pslang::interpreter
namespace
{
type::type type_of_impl(unit_value const &)
types::type type_of_impl(unit_value const &)
{
return type::unit_type{};
return types::unit_type{};
}
template <typename T>
type::type type_of_impl(primitive_value_base<T> const &)
types::type type_of_impl(primitive_value_base<T> const &)
{
return type::primitive_type(type::primitive_type_base<T>{});
return types::primitive_type(types::primitive_type_base<T>{});
}
type::type type_of_impl(primitive_value const & value)
types::type type_of_impl(primitive_value const & value)
{
return std::visit([](auto const & value){ return type_of_impl(value); }, value);
}
type::type type_of_impl(array_value const & value)
types::type type_of_impl(array_value const & value)
{
return type::array_type{.element_type = value.element_type, .size = value.elements.size()};
return types::array_type{.element_type = value.element_type, .size = value.elements.size()};
}
type::type type_of_impl(struct_value const & value)
types::type type_of_impl(struct_value const & value)
{
return *value.struct_type;
}
type::type type_of_impl(function_value const & value)
types::type type_of_impl(function_value const & value)
{
type::function_type result;
types::function_type result;
for (auto const & argument : value.arguments)
result.arguments.push_back(argument.type);
result.result = value.return_type;
return result;
}
type::type type_of_impl(value const & value)
types::type type_of_impl(value const & value)
{
return std::visit([](auto const & value){ return type_of_impl(value); }, value);
}
@ -127,7 +127,7 @@ namespace pslang::interpreter
}
type::type type_of(value const & value)
types::type type_of(value const & value)
{
return type_of_impl(value);
}

View file

@ -20,9 +20,8 @@
%code requires {
#include <pslang/ast/statement.hpp>
#include <pslang/ast/location.hpp>
#include <pslang/parser/indented_statement.hpp>
#include <pslang/ast/statement.hpp>
namespace pslang::parser {
@ -149,13 +148,13 @@ template <typename T>
%type <std::vector<ast::function_definition::argument>> function_definition_argument_list
%type <std::vector<ast::function_definition::argument>> nonempty_function_definition_argument_list
%type <ast::function_definition::argument> function_definition_single_argument
%type <type::type_ptr> function_return_type
%type <ast::type_ptr> function_return_type
%type <ast::variable_declaration> variable_declaration
%type <ast::value_category> variable_keyword
%type <type::type> type_expression
%type <type::primitive_type> primitive_type
%type <std::vector<type::type_ptr>> function_paren_type_list
%type <std::vector<type::type_ptr>> two_or_more_type_list
%type <ast::type> type_expression
%type <types::primitive_type> primitive_type
%type <std::vector<ast::type_ptr>> function_paren_type_list
%type <std::vector<ast::type_ptr>> two_or_more_type_list
%type <ast::expression> expression
%type <ast::expression> postfix_expression
%type <ast::expression> base_expression
@ -192,7 +191,7 @@ statement
| return expression { $$ = ast::return_statement{std::make_unique<ast::expression>($2), @$}; }
| return { $$ = ast::return_statement{nullptr, @$}; }
| struct name colon { $$ = ast::struct_definition{$2, {}, @$}; }
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<type::type>($3), @$}; }
| name colon type_expression { $$ = ast::field_definition{$1, std::make_unique<ast::type>($3), @$}; }
;
function_definition_argument_list
@ -206,17 +205,17 @@ nonempty_function_definition_argument_list
;
function_definition_single_argument
: name colon type_expression { $$ = ast::function_definition::argument{$1, std::make_unique<type::type>($3), @$}; }
: name colon type_expression { $$ = ast::function_definition::argument{$1, std::make_unique<ast::type>($3), @$}; }
;
function_return_type
: arrow type_expression { $$ = std::make_unique<type::type>($2); }
| %empty { $$ = std::make_unique<type::type>(type::unit_type{}); }
: arrow type_expression { $$ = std::make_unique<ast::type>($2); }
| %empty { $$ = std::make_unique<ast::type>(types::unit_type{}); }
;
variable_declaration
: variable_keyword name assignment expression { $$ = ast::variable_declaration{$1, $2, nullptr, std::make_unique<ast::expression>($4), @$}; }
| variable_keyword name colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<type::type>($4), std::make_unique<ast::expression>($6), @$}; }
| variable_keyword name colon type_expression assignment expression { $$ = ast::variable_declaration{$1, $2, std::make_unique<ast::type>($4), std::make_unique<ast::expression>($6), @$}; }
;
variable_keyword
@ -226,37 +225,37 @@ variable_keyword
;
type_expression
: unit { $$ = type::type(type::unit_type{}); }
| primitive_type { $$ = type::type($1); }
| name { $$ = type::identifier{$1}; }
| type_expression lbracket lit_i32 rbracket { $$ = type::array_type{std::make_unique<type::type>($1), std::stoull($3)}; }
| type_expression arrow type_expression { std::vector<type::type_ptr> args; args.push_back(std::make_unique<type::type>($1)); $$ = type::function_type{std::move(args), std::make_unique<type::type>($3)}; }
| lparen function_paren_type_list rparen arrow type_expression { $$ = type::function_type{$2, std::make_unique<type::type>($5)}; }
: unit { $$ = types::unit_type{}; }
| primitive_type { $$ = ast::type($1); }
| name { $$ = ast::type_identifier{$1}; }
| type_expression lbracket lit_i32 rbracket { $$ = ast::array_type{std::make_unique<ast::type>($1), std::stoull($3)}; }
| type_expression arrow type_expression { std::vector<ast::type_ptr> args; args.push_back(std::make_unique<ast::type>($1)); $$ = ast::function_type{std::move(args), std::make_unique<ast::type>($3)}; }
| lparen function_paren_type_list rparen arrow type_expression { $$ = ast::function_type{$2, std::make_unique<ast::type>($5)}; }
| lparen type_expression rparen { $$ = $2; }
;
primitive_type
: bool { $$ = type::bool_type{}; }
| i8 { $$ = type::i8_type{}; }
| u8 { $$ = type::u8_type{}; }
| i16 { $$ = type::i16_type{}; }
| u16 { $$ = type::u16_type{}; }
| i32 { $$ = type::i32_type{}; }
| u32 { $$ = type::u32_type{}; }
| i64 { $$ = type::i64_type{}; }
| u64 { $$ = type::u64_type{}; }
| f32 { $$ = type::f32_type{}; }
| f64 { $$ = type::f64_type{}; }
: bool { $$ = types::bool_type{}; }
| i8 { $$ = types::i8_type{}; }
| u8 { $$ = types::u8_type{}; }
| i16 { $$ = types::i16_type{}; }
| u16 { $$ = types::u16_type{}; }
| i32 { $$ = types::i32_type{}; }
| u32 { $$ = types::u32_type{}; }
| i64 { $$ = types::i64_type{}; }
| u64 { $$ = types::u64_type{}; }
| f32 { $$ = types::f32_type{}; }
| f64 { $$ = types::f64_type{}; }
;
function_paren_type_list
: %empty { std::vector<type::type_ptr> tmp; $$ = std::move(tmp); }
: %empty { std::vector<ast::type_ptr> tmp; $$ = std::move(tmp); }
| two_or_more_type_list { $$ = $1; }
;
two_or_more_type_list
: type_expression comma type_expression { std::vector<type::type_ptr> tmp; tmp.push_back(std::make_unique<type::type>($1)); tmp.push_back(std::make_unique<type::type>($3)); $$ = std::move(tmp); }
| two_or_more_type_list comma type_expression { auto tmp = $1; tmp.push_back(std::make_unique<type::type>($3)); $$ = std::move(tmp); }
: type_expression comma type_expression { std::vector<ast::type_ptr> tmp; tmp.push_back(std::make_unique<ast::type>($1)); tmp.push_back(std::make_unique<ast::type>($3)); $$ = std::move(tmp); }
| two_or_more_type_list comma type_expression { auto tmp = $1; tmp.push_back(std::make_unique<ast::type>($3)); $$ = std::move(tmp); }
;
expression
@ -269,7 +268,7 @@ expression
| expression greater expression { $$ = ast::binary_operation{ast::binary_operation_type::greater, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| expression less_equals expression { $$ = ast::binary_operation{ast::binary_operation_type::less_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| expression greater_equals expression { $$ = ast::binary_operation{ast::binary_operation_type::greater_equals, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<type::type>($3), @$ }; }
| expression as type_expression { $$ = ast::cast_operation{ std::make_unique<ast::expression>($1), std::make_unique<ast::type>($3), @$ }; }
| minus expression %prec UMINUS { $$ = ast::unary_operation{ast::unary_operation_type::negation, std::make_unique<ast::expression>($2), @$ }; }
| expression plus expression { $$ = ast::binary_operation{ast::binary_operation_type::addition, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }
| expression minus expression { $$ = ast::binary_operation{ast::binary_operation_type::subtraction, std::make_unique<ast::expression>($1), std::make_unique<ast::expression>($3), @$ }; }

View file

@ -1,5 +0,0 @@
file(GLOB_RECURSE PSLANG_TYPE_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
file(GLOB_RECURSE PSLANG_TYPE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
add_library(pslang-type STATIC ${PSLANG_TYPE_HEADERS} ${PSLANG_TYPE_SOURCES})
target_include_directories(pslang-type PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")

View file

@ -1,29 +0,0 @@
#pragma once
#include <pslang/type/unit.hpp>
#include <pslang/type/primitive.hpp>
#include <pslang/type/array.hpp>
#include <pslang/type/function.hpp>
#include <pslang/type/identifier.hpp>
#include <pslang/type/type_fwd.hpp>
#include <variant>
namespace pslang::type
{
using type_impl = std::variant<
unit_type,
primitive_type,
array_type,
function_type,
identifier
>;
struct type
: type_impl
{
using type_impl::type_impl;
};
}

View file

@ -0,0 +1,5 @@
file(GLOB_RECURSE PSLANG_TYPES_HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp")
file(GLOB_RECURSE PSLANG_TYPES_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/source/*.cpp")
add_library(pslang-types STATIC ${PSLANG_TYPES_HEADERS} ${PSLANG_TYPES_SOURCES})
target_include_directories(pslang-types PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")

View file

@ -1,10 +1,10 @@
#pragma once
#include <pslang/type/type_fwd.hpp>
#include <pslang/types/type_fwd.hpp>
#include <cstdint>
namespace pslang::type
namespace pslang::types
{
struct array_type

View file

@ -1,10 +1,10 @@
#pragma once
#include <pslang/type/type_fwd.hpp>
#include <pslang/types/type_fwd.hpp>
#include <vector>
namespace pslang::type
namespace pslang::types
{
struct function_type

View file

@ -2,16 +2,16 @@
#include <string>
namespace pslang::type
namespace pslang::types
{
struct identifier
struct named_type
{
std::string name;
std::size_t level = 0;
std::size_t level;
};
inline bool operator == (identifier const & t1, identifier const & t2)
inline bool operator == (named_type const & t1, named_type const & t2)
{
return (t1.level == t2.level) && (t1.name == t2.name);
}

View file

@ -3,7 +3,7 @@
#include <variant>
#include <cstdint>
namespace pslang::type
namespace pslang::types
{
template <typename T>

View file

@ -1,10 +1,10 @@
#pragma once
#include <pslang/type/type_fwd.hpp>
#include <pslang/types/type_fwd.hpp>
#include <iostream>
namespace pslang::type
namespace pslang::types
{
void print(std::ostream & out, type const & type);

View file

@ -0,0 +1,29 @@
#pragma once
#include <pslang/types/unit.hpp>
#include <pslang/types/primitive.hpp>
#include <pslang/types/array.hpp>
#include <pslang/types/function.hpp>
#include <pslang/types/named.hpp>
#include <pslang/types/type_fwd.hpp>
#include <variant>
namespace pslang::types
{
using type_impl = std::variant<
unit_type,
primitive_type,
array_type,
function_type,
named_type
>;
struct type
: type_impl
{
using type_impl::type_impl;
};
}

View file

@ -2,7 +2,7 @@
#include <memory>
namespace pslang::type
namespace pslang::types
{
struct type;
@ -10,4 +10,5 @@ namespace pslang::type
using type_ptr = std::shared_ptr<type>;
bool equal(type const & t1, type const & t2);
}

View file

@ -1,6 +1,6 @@
#pragma once
namespace pslang::type
namespace pslang::types
{
struct unit_type

View file

@ -1,7 +1,7 @@
#include <pslang/type/print.hpp>
#include <pslang/type/type.hpp>
#include <pslang/types/print.hpp>
#include <pslang/types/type.hpp>
namespace pslang::type
namespace pslang::types
{
namespace
@ -100,7 +100,7 @@ namespace pslang::type
print(out, *type.result);
}
void print_impl(std::ostream & out, identifier const & type)
void print_impl(std::ostream & out, named_type const & type)
{
out << type.name;
}

View file

@ -1,6 +1,6 @@
#include <pslang/type/type.hpp>
#include <pslang/types/type.hpp>
namespace pslang::type
namespace pslang::types
{
bool equal(type const & t1, type const & t2)