Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.

Commit bd6ec90

Browse files
committed
feat: new class for runtime type checking
1 parent 8d8da21 commit bd6ec90

4 files changed

Lines changed: 193 additions & 0 deletions

File tree

‎CMakeLists.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_library(frontend STATIC
1919

2020
add_library(runtime STATIC
2121
${CMAKE_SOURCE_DIR}/src/runtime/interpreter.cpp
22+
${CMAKE_SOURCE_DIR}/src/runtime/type.cpp
2223
${CMAKE_SOURCE_DIR}/src/runtime/builtins.cpp
2324
${CMAKE_SOURCE_DIR}/src/runtime/builtin-modules/builtin_module_core.cpp
2425
${CMAKE_SOURCE_DIR}/src/runtime/builtin-modules/builtin_module_list.cpp

‎include/lbd/runtime/interpreter.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace runtime {
6464

6565
int arity;
6666
std::string name;
67+
// TODO: We can store signature of native-function here.
6768
Implementation implementation;
6869

6970
[[nodiscard]] std::string toString() const;

‎include/lbd/runtime/type.h‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pragma once
2+
3+
#include <lbd/runtime/interpreter.h>
4+
5+
/// These are runtime-types different from frontend::type.
6+
7+
namespace runtime::type {
8+
enum class TypeTag {
9+
Float,
10+
String,
11+
Closure,
12+
NativeFunction,
13+
List,
14+
Any
15+
};
16+
17+
TypeTag typeTagFromValue(const Value &value);
18+
19+
std::string typeTagToString(TypeTag tag);
20+
21+
struct Type {
22+
virtual ~Type() = default;
23+
24+
[[nodiscard]] virtual bool matches(const Value &value) const = 0;
25+
26+
[[nodiscard]] virtual std::string toString() const = 0;
27+
28+
[[nodiscard]] virtual bool isCallable() const;
29+
};
30+
31+
struct SimpleType final : Type {
32+
explicit SimpleType(TypeTag tag);
33+
34+
[[nodiscard]] bool matches(const Value &value) const override;
35+
36+
[[nodiscard]] std::string toString() const override;
37+
38+
[[nodiscard]] bool isCallable() const override;
39+
40+
private:
41+
TypeTag tag;
42+
};
43+
44+
struct ListType final : Type {
45+
explicit ListType(const std::shared_ptr<Type> &elementType);
46+
47+
[[nodiscard]] bool matches(const Value &value) const override;
48+
49+
[[nodiscard]] std::string toString() const override;
50+
51+
[[nodiscard]] bool isCallable() const override;
52+
53+
private:
54+
std::shared_ptr<Type> elementType;
55+
};
56+
57+
struct FunctionType final : Type {
58+
// TODO: Add support for variadic, maybe by adding a default parameter 'isVariadic'.
59+
explicit FunctionType(const std::vector<std::shared_ptr<Type> > &argumentTypes,
60+
const std::shared_ptr<Type> &returnType);
61+
62+
[[nodiscard]] bool matches(const Value &value) const override;
63+
64+
[[nodiscard]] std::string toString() const override;
65+
66+
[[nodiscard]] bool isCallable() const override;
67+
68+
[[nodiscard]] int arity() const;
69+
70+
private:
71+
std::vector<std::shared_ptr<Type> > argumentTypes;
72+
std::shared_ptr<Type> returnType;
73+
};
74+
}

‎src/runtime/type.cpp‎

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include <lbd/runtime/type.h>
2+
#include <lbd/error.h>
3+
4+
namespace runtime::type {
5+
inline TypeTag typeTagFromValue(const Value &value) {
6+
return std::visit([&]<typename T0>(T0 &&_) -> TypeTag {
7+
using T = std::decay_t<T0>;
8+
if constexpr (std::is_same_v<T, double>) {
9+
return TypeTag::Float;
10+
} else if constexpr (std::is_same_v<T, std::string>) {
11+
return TypeTag::String;
12+
} else if constexpr (std::is_same_v<T, Closure>) {
13+
return TypeTag::Closure;
14+
} else if constexpr (std::is_same_v<T, std::shared_ptr<NativeFunction> >) {
15+
return TypeTag::NativeFunction;
16+
} else if constexpr (std::is_same_v<T, std::shared_ptr<List> >) {
17+
return TypeTag::List;
18+
} else {
19+
return TypeTag::Any;
20+
}
21+
}, value);
22+
}
23+
24+
inline std::string typeTagToString(const TypeTag tag) {
25+
switch (tag) {
26+
case TypeTag::Float:
27+
return "Float";
28+
case TypeTag::String:
29+
return "String";
30+
case TypeTag::Closure:
31+
return "Closure";
32+
case TypeTag::NativeFunction:
33+
return "NativeFunction";
34+
case TypeTag::List:
35+
return "List";
36+
case TypeTag::Any:
37+
return "Any";
38+
default:
39+
STATIC_ASSERT(true, "unhandled type");
40+
return "UNKNOWN_TYPE"; // Unreachable
41+
}
42+
}
43+
44+
SimpleType::SimpleType(const TypeTag tag) : tag(tag) {
45+
}
46+
47+
bool SimpleType::matches(const Value &value) const {
48+
return tag == TypeTag::Any || tag == typeTagFromValue(value);
49+
}
50+
51+
std::string SimpleType::toString() const {
52+
return typeTagToString(tag);
53+
}
54+
55+
bool SimpleType::isCallable() const {
56+
return false;
57+
}
58+
59+
ListType::ListType(const std::shared_ptr<Type> &elementType) : elementType(elementType) {
60+
}
61+
62+
bool ListType::matches(const Value &value) const {
63+
if (typeTagFromValue(value) != TypeTag::Any) {
64+
return false;
65+
}
66+
auto &[elements] = *std::get<std::shared_ptr<List> >(value);
67+
return std::all_of(elements.begin(), elements.end(), [&](const auto &element) {
68+
return elementType->matches(element);
69+
});
70+
}
71+
72+
std::string ListType::toString() const {
73+
std::ostringstream outputStringStream;
74+
outputStringStream << "[" << elementType->toString() << "]";
75+
return outputStringStream.str();
76+
}
77+
78+
bool ListType::isCallable() const {
79+
return false;
80+
}
81+
82+
FunctionType::FunctionType(const std::vector<std::shared_ptr<Type> > &argumentTypes,
83+
const std::shared_ptr<Type> &returnType) : argumentTypes(argumentTypes),
84+
returnType(returnType) {
85+
}
86+
87+
bool FunctionType::matches(const Value &value) const {
88+
// TODO: Complete this.
89+
return false;
90+
}
91+
92+
std::string FunctionType::toString() const {
93+
std::ostringstream outputStringStream;
94+
for (auto &argumentType: argumentTypes) {
95+
if (argumentType->isCallable()) {
96+
outputStringStream << "(" << argumentType->toString() << ") ";
97+
} else {
98+
outputStringStream << argumentType->toString() << " ";
99+
}
100+
}
101+
if (returnType->isCallable()) {
102+
outputStringStream << "(" << returnType->toString() << ") ";
103+
} else {
104+
outputStringStream << returnType->toString() << " ";
105+
}
106+
return outputStringStream.str();
107+
}
108+
109+
bool FunctionType::isCallable() const {
110+
return true;
111+
}
112+
113+
int FunctionType::arity() const {
114+
// TODO: For variadic-functions return '-1'.
115+
return argumentTypes.size();
116+
}
117+
}

0 commit comments

Comments
 (0)