Skip to content

Commit 18524e5

Browse files
committed
[Heavy] Add plugin system
1 parent b6e58ab commit 18524e5

File tree

10 files changed

+129
-26
lines changed

10 files changed

+129
-26
lines changed

heavy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ add_subdirectory(tools/heavy-scheme)
5353
add_subdirectory(test)
5454
add_subdirectory(unittests)
5555
add_subdirectory(include/nbdl_gen)
56+
add_subdirectory(plugins/HelloWorld)
5657

5758
add_subdirectory(cmake/modules)

heavy/cmake/modules/AddHeavy.cmake

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,29 @@ include(AddLLVM)
22
include(LLVMDistributionSupport)
33

44
function(add_heavy_library name)
5-
set(options "")
6-
set(one_value_args "")
7-
set(multi_value_args "")
8-
cmake_parse_arguments(ARG "${options}" "${one_value_args}"
9-
"${multi_value_args}" "${ARGN}")
10-
llvm_add_library(${name} ${ARG_UNPARSED_ARGUMENTS})
11-
get_target_export_arg(${name} Heavy export_arg UMBRELLA heavy-libraries)
12-
install(TARGETS ${name}
13-
COMPONENT ${name}
14-
${export_arg})
5+
set(options "")
6+
set(one_value_args "")
7+
set(multi_value_args "")
8+
cmake_parse_arguments(ARG "${options}" "${one_value_args}"
9+
"${multi_value_args}" "${ARGN}")
10+
llvm_add_library(${name} ${ARG_UNPARSED_ARGUMENTS})
11+
get_target_export_arg(${name} Heavy export_arg UMBRELLA heavy-libraries)
12+
install(TARGETS ${name}
13+
COMPONENT ${name}
14+
${export_arg})
1515

16-
add_llvm_install_targets(install-${name}
17-
DEPENDS ${name}
18-
COMPONENT ${name})
19-
set_property(GLOBAL APPEND PROPERTY HEAVY_EXPORTS ${name})
16+
add_llvm_install_targets(install-${name}
17+
DEPENDS ${name}
18+
COMPONENT ${name})
19+
set_property(GLOBAL APPEND PROPERTY HEAVY_EXPORTS ${name})
2020
endfunction(add_heavy_library)
2121

22-
# add_heavy_scheme_module
23-
# - Create a scheme module that is, by default, dynamically loaded.
24-
# - TODO Implement this.
25-
function(add_heavy_scheme_module name)
26-
set(options STATIC)
27-
set(one_value_args "")
28-
set(multi_value_args "")
29-
cmake_parse_arguments(ARG "${options}" "${one_value_args}"
30-
"${multi_value_args}")
31-
endfunction(add_heavy_scheme_module name)
22+
# Create a scheme module that is compiled as a dynamically loaded library.
23+
function(add_heavy_scheme_plugin name filename)
24+
set(options "")
25+
set(one_value_args "")
26+
set(multi_value_args)
27+
cmake_parse_arguments(ARG "${options}" "${one_value_args}"
28+
"${multi_value_args}")
29+
add_library(${name} MODULE ${filename})
30+
endfunction(add_heavy_scheme_plugin)

heavy/lib/Builtins.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "heavy/Value.h"
2020
#include "llvm/ADT/StringExtras.h"
2121
#include "llvm/Support/Casting.h"
22+
#include "llvm/Support/DynamicLibrary.h"
2223
#include "cassert"
2324
#include "memory"
2425

@@ -93,6 +94,8 @@ heavy::ExternFunction source_loc;
9394
heavy::ExternFunction source_loc_valid;
9495
heavy::ExternFunction dump_source_loc;
9596
heavy::ExternFunction make_syntactic_closure;
97+
heavy::ExternFunction load_plugin;
98+
heavy::ExternFunction load_builtin;
9699

97100
heavy::ExternFunction eval;
98101
heavy::ExternFunction op_eval;
@@ -1250,6 +1253,45 @@ void make_syntactic_closure(Context& C, ValueRefs Args) {
12501253
Value Result = C.CreateSyntaxClosure(Loc, Expr, Env);
12511254
C.Cont(Result);
12521255
}
1256+
1257+
// Dynamically load a native shared library.
1258+
void load_plugin(Context& C, ValueRefs Args) {
1259+
if (Args.size() != 1)
1260+
return C.RaiseError("invalid arity");
1261+
1262+
llvm::StringRef Filename = Args.front().getStringRef();
1263+
if (Filename.empty())
1264+
return C.RaiseError("expecting nonempty string-like object: {}",
1265+
Args.front());
1266+
1267+
std::string ErrMsg;
1268+
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename.data(),
1269+
&ErrMsg)) {
1270+
// TODO Make a "note" with Msg.
1271+
String* Msg = C.CreateString(ErrMsg);
1272+
return C.RaiseError("Failed to load plugin: {}\n{}", {Args.front(), Msg});
1273+
}
1274+
1275+
C.Cont();
1276+
}
1277+
1278+
// Dynamically load a Builtin from a heavy::ValueFn.
1279+
void load_builtin(Context& C, ValueRefs Args) {
1280+
if (Args.size() != 1)
1281+
return C.RaiseError("invalid arity");
1282+
1283+
llvm::StringRef FuncName = Args.front().getStringRef();
1284+
if (FuncName.empty())
1285+
return C.RaiseError("expecting nonempty string-like object: {}",
1286+
Args.front());
1287+
1288+
void* FuncVoidPtr
1289+
= llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(FuncName.data());
1290+
if (FuncVoidPtr == nullptr)
1291+
return C.RaiseError("unable to load builtin: {}", Args.front());
1292+
heavy::ValueFn Fn = reinterpret_cast<heavy::ValueFn>(FuncVoidPtr);
1293+
C.Cont(C.CreateBuiltin(Fn));
1294+
}
12531295
} // end of namespace heavy::builtins
12541296

12551297
// initialize the module for run-time independent of the compiler
@@ -1346,6 +1388,8 @@ void HEAVY_BASE_INIT(heavy::Context& Context) {
13461388
HEAVY_BASE_VAR(apply) = heavy::builtins::apply;
13471389
HEAVY_BASE_VAR(make_syntactic_closure)
13481390
= heavy::builtins::make_syntactic_closure;
1391+
HEAVY_BASE_VAR(load_plugin) = heavy::builtins::load_plugin;
1392+
HEAVY_BASE_VAR(load_builtin) = heavy::builtins::load_builtin;
13491393
}
13501394

13511395
// initializes the module and loads lookup information
@@ -1444,6 +1488,8 @@ void HEAVY_BASE_LOAD_MODULE(heavy::Context& Context) {
14441488
{"source-value?", HEAVY_BASE_VAR(is_source_value)},
14451489
{"apply", HEAVY_BASE_VAR(apply)},
14461490
{"make-syntactic-closure", HEAVY_BASE_VAR(make_syntactic_closure)},
1491+
{"load-plugin", HEAVY_BASE_VAR(load_plugin)},
1492+
{"load-builtin", HEAVY_BASE_VAR(load_builtin)},
14471493
});
14481494
}
14491495

heavy/lib/Context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,7 @@ void Context::IncludeModuleFile(heavy::SourceLocation Loc,
11231123
C.OpGen->SetTopLevelHandler(HEAVY_BASE_VAR(op_eval));
11241124
C.OpGen->VisitTopLevelSequence(Args[0]);
11251125
});
1126+
// Load and parse the file.
11261127
heavy::Value Parse = HEAVY_BASE_VAR(parse_source_file).get(C);
11271128
heavy::Value SourceVal = C.CreateSourceValue(Loc);
11281129
heavy::Value Filename = C.getCapture(0);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.13.4)
2+
add_heavy_scheme_plugin(heavyHelloWorld
3+
hello_world.cpp)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <heavy/Context.h>
2+
#include <heavy/Value.h>
3+
4+
extern "C" {
5+
void heavy_hello_world_compute_answer(heavy::Context& C, heavy::ValueRefs) {
6+
C.Cont(heavy::Int(42));
7+
}
8+
9+
void heavy_hello_world_my_write(heavy::Context& C, heavy::ValueRefs Args) {
10+
heavy::write(llvm::outs(), Args[0]);
11+
C.Cont();
12+
}
13+
}

heavy/test/Plugin/hello_world.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: clang++ -I %S/Inputs -fsyntax-only -Xclang -fheavy -Xclang -verify %s
2+
// expected-no-diagnostics
3+
4+
heavy_scheme {
5+
(import (heavy builtins)
6+
(heavy clang))
7+
8+
(load-plugin "libheavyHelloWorld.so")
9+
10+
(define compute-answer
11+
(load-builtin "heavy_hello_world_compute_answer"))
12+
13+
(define forty-two 'forty-two)
14+
15+
(write-lexer forty-two "static constexpr int forty_two = ")
16+
(write-lexer forty-two (number->string (compute-answer)))
17+
(write-lexer 0 ";")
18+
}
19+
20+
static_assert(forty_two == 42);
21+
int main() { }

heavy/test/Plugin/hello_world.scm

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: heavy-scheme %s | FileCheck %s
2+
(import (heavy builtins))
3+
4+
(load-plugin "libheavyHelloWorld.so")
5+
(define my-write
6+
(load-builtin "heavy_hello_world_my_write"))
7+
8+
(define compute-answer
9+
(load-builtin "heavy_hello_world_compute_answer"))
10+
11+
; CHECK: (hello world)
12+
(my-write '(hello world))
13+
14+
15+
; CHECK: 42
16+
(write (compute-answer))
17+
(newline)
18+

heavy/tools/heavy-scheme/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_llvm_executable(heavy-scheme heavy_main.cpp)
44
llvm_map_components_to_libnames(LLVM_LIBS core support)
55

66
target_link_libraries(heavy-scheme PRIVATE heavy ${LLVM_LIBS})
7+
set_target_properties(heavy-scheme PROPERTIES ENABLE_EXPORTS 1)
78

89
add_llvm_install_targets(install-heavy-scheme
910
DEPENDS heavy-scheme

heavy/tools/heavy-scheme/heavy_main.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ void SetModulePath(heavy::HeavyScheme& HeavyScheme) {
9191

9292
int main(int argc, char const** argv) {
9393
#if 0
94-
// TODO Provide interactive looping which requires support
95-
// in Parser/Lexer possibly. Also look at llvm::LineEditor.
94+
// TODO Provide interactive looping.
95+
// Also look at llvm::LineEditor.
9696
bool IsInteractive = llvm::sys::Process::StandardInIsUserInput();
9797
#endif
9898
llvm::InitLLVM LLVM_(argc, argv);

0 commit comments

Comments
 (0)