Skip to content

Commit 1575310

Browse files
committed
[Heavy] Fix Clang environment loading; Fix source-loc
1 parent 6ddaa68 commit 1575310

File tree

7 files changed

+123
-65
lines changed

7 files changed

+123
-65
lines changed

clang/lib/Parse/ParseDeclHeavy.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ clang::SourceLocation getSourceLocation(heavy::FullSourceLocation Loc) {
4545
.getLocWithOffset(Loc.getOffset());
4646
}
4747

48-
void LoadParentEnv(heavy::HeavyScheme& HS, void* Handle) {
48+
heavy::Environment* LoadEnv(heavy::HeavyScheme& HS, void* Handle) {
4949
DeclContext* DC = reinterpret_cast<DeclContext*>(Handle);
50-
if (!DC->isTranslationUnit()) {
51-
HS.LoadEmbeddedEnv(DC->getParent(), LoadParentEnv);
52-
}
50+
// Here, nullptr represents the default, root environment.
51+
void* ParentHandle = !DC->isTranslationUnit() ? DC->getParent()
52+
: nullptr;
53+
54+
return HS.LoadEmbeddedEnv(ParentHandle, LoadEnv);
5355
}
5456

5557
// It is complicated to keep the TokenBuffer alive
@@ -154,17 +156,26 @@ bool Parser::ParseHeavyScheme() {
154156
};
155157

156158
auto expr_eval = [&](heavy::Context& C, heavy::ValueRefs Args) {
157-
if (Args.size() != 1) {
158-
C.RaiseError("invalid arity to function", C.getCallee());
159-
return;
159+
heavy::SourceLocation Loc;
160+
heavy::Value Input;
161+
if (Args.size() == 2) {
162+
// Accept any value that may have a source location.
163+
Loc = Args[0].getSourceLocation();
164+
Input = Args[1];
165+
} else if (Args.size() == 1) {
166+
Input = Args[0];
167+
} else {
168+
return C.RaiseError("invalid arity");
160169
}
161-
if (!isa<heavy::String, heavy::Symbol>(Args[0])) {
170+
if (!isa<heavy::String, heavy::Symbol>(Input)) {
162171
C.RaiseError("expecting string or identifier", C.getCallee());
163172
return;
164173
}
165-
llvm::StringRef Source = Args[0].getStringRef();
166-
heavy::SourceLocation Loc = Args[0].getSourceLocation();
167-
if (!Loc.isValid()) Loc = C.getLoc();
174+
llvm::StringRef Source = Input.getStringRef();
175+
if (!Loc.isValid())
176+
Loc = Input.getSourceLocation();
177+
if (!Loc.isValid())
178+
Loc = C.getLoc();
168179

169180
// Prepare to revert Parser.
170181
TentativeParsingAction ParseReverter(P);
@@ -258,9 +269,11 @@ bool Parser::ParseHeavyScheme() {
258269
ClangLoc, RequestedFilename->getView(),
259270
false, nullptr, nullptr, nullptr, nullptr, nullptr,
260271
nullptr, nullptr, nullptr);
261-
if (!File)
262-
return C.RaiseError("error opening file",
263-
heavy::Value(RequestedFilename));
272+
if (!File) {
273+
heavy::String* ErrMsg = C.CreateString("error opening file: ",
274+
RequestedFilename->getStringRef());
275+
return C.RaiseError(ErrMsg, heavy::Value(RequestedFilename));
276+
}
264277
// Determine if file is a system file... as if!
265278
SrcMgr::CharacteristicKind FileChar =
266279
this->PP.getHeaderSearchInfo()
@@ -308,10 +321,6 @@ bool Parser::ParseHeavyScheme() {
308321

309322
PP.InitEmbeddedLexer(LexerInitFn);
310323

311-
// Load the environment for the current DeclContext
312-
DeclContext* DC = getActions().CurContext;
313-
HeavyScheme->LoadEmbeddedEnv(DC, LoadParentEnv);
314-
315324
bool HasError = false;
316325
auto ErrorHandler = [&](llvm::StringRef Err,
317326
heavy::FullSourceLocation EmbeddedLoc) {
@@ -356,10 +365,13 @@ bool Parser::ParseHeavyScheme() {
356365
C.Cont();
357366
}));
358367

368+
// Get the nested environment for the current DeclContext.
369+
DeclContext* DC = getActions().CurContext;
370+
heavy::Environment* Env = HeavyScheme->LoadEmbeddedEnv(DC, LoadEnv);
371+
359372
heavy::TokenKind Terminator = heavy::tok::r_brace;
360-
HeavyScheme->ProcessTopLevelCommands(SchemeLexer,
361-
ErrorHandler,
362-
Terminator);
373+
HeavyScheme->ProcessTopLevelCommands(SchemeLexer, heavy::base::eval,
374+
ErrorHandler, Env, Terminator);
363375

364376
// Return control to C++ Lexer
365377
PP.FinishEmbeddedLexer(SchemeLexer.GetByteOffset());

heavy/include/heavy/HeavyScheme.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ using ModuleLoadNamesFn = void(heavy::Context&);
3232
using ValueRefs = llvm::MutableArrayRef<heavy::Value>;
3333
using ValueFnTy = void (Context&, ValueRefs);
3434

35+
namespace base {
36+
void eval(Context& C, ValueRefs Args);
37+
}
38+
3539
// HeavyScheme - Opaque wrapper for heavy::Context and common operations
3640
// needed for embedding scheme
3741
class HeavyScheme {
@@ -92,8 +96,9 @@ class HeavyScheme {
9296
// LoadParent is called, and then the new environment is
9397
// created to shadow whatever environment is loaded in
9498
// Context at that point.
95-
void LoadEmbeddedEnv(void* Handle,
96-
llvm::function_ref<void(HeavyScheme&, void*)> LoadParent);
99+
using LoadEnvFnTy = heavy::Environment*(HeavyScheme&, void*);
100+
heavy::Environment* LoadEmbeddedEnv(void* Handle,
101+
llvm::function_ref<LoadEnvFnTy> LoadParent);
97102

98103
using ErrorHandlerFn = void(llvm::StringRef,
99104
heavy::FullSourceLocation const&);
@@ -106,12 +111,10 @@ class HeavyScheme {
106111
// (ie a heavy::tok::r_paren can terminate without effecting
107112
// the parsing of lists that are delimited by parens)
108113
// - ExprHandler defaults to `base::eval`
109-
void ProcessTopLevelCommands(heavy::Lexer& Lexer,
110-
llvm::function_ref<ErrorHandlerFn> ErrorHandler,
111-
heavy::tok Terminator);
112114
void ProcessTopLevelCommands(heavy::Lexer& Lexer,
113115
llvm::function_ref<ValueFnTy> ExprHandler,
114116
llvm::function_ref<ErrorHandlerFn> ErrorHandler,
117+
heavy::Environment* Env = nullptr,
115118
heavy::tok Terminator = heavy::tok::eof);
116119
// ProcessTopLevelCommands
117120
// - Filename overload requires calling InitSourceFileStorage.

heavy/lib/Builtins.cpp

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ heavy::ExternBuiltinSyntax lambda;
4141
heavy::ExternBuiltinSyntax quasiquote;
4242
heavy::ExternBuiltinSyntax quote;
4343
heavy::ExternBuiltinSyntax set;
44-
heavy::ExternBuiltinSyntax source_loc;
4544

4645

4746
heavy::ExternFunction add;
@@ -71,6 +70,7 @@ heavy::ExternFunction raise;
7170
heavy::ExternFunction error;
7271
heavy::ExternFunction dynamic_wind;
7372
heavy::ExternFunction load_module;
73+
heavy::ExternFunction source_loc;
7474

7575
heavy::ExternFunction eval;
7676
heavy::ExternFunction op_eval;
@@ -322,17 +322,10 @@ void parse_source_file(Context& C, ValueRefs Args) {
322322
C.RaiseError("parse-source-file is undefined");
323323
}
324324

325-
mlir::Value source_loc(OpGen& OG, Pair* P) {
326-
// Convert an unevaluated value into a SourceValue.
327-
// (or rather the operation to do this).
328-
Pair* P2 = dyn_cast<Pair>(P->Cdr);
329-
if (!P2 || !isa<Empty>(P2->Cdr)) {
330-
return OG.SetError("single argument required", P);
331-
}
332-
// Defer creating a SourceValue until evaluation.
333-
heavy::SourceLocation Loc = P2->Car.getSourceLocation();
334-
auto SourceLocOp = OG.create<heavy::SourceLocOp>(Loc);
335-
return SourceLocOp.getResult();
325+
void source_loc(Context& C, ValueRefs Args) {
326+
if (Args.size() != 1)
327+
return C.RaiseError("expecting single argument");
328+
C.Cont(C.CreateSourceValue(Args[0].getSourceLocation()));
336329
}
337330

338331
} // end of namespace heavy::base

heavy/lib/HeavyScheme.cpp

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ namespace heavy {
2626

2727
HeavyScheme::HeavyScheme(std::unique_ptr<heavy::Context> C)
2828
: ContextPtr(std::move(C)),
29-
EnvPtr(std::make_unique<heavy::Environment>(*ContextPtr)),
3029
SourceManagerPtr(std::make_unique<heavy::SourceManager>()),
3130
SourceFileStoragePtr(nullptr, [](SourceFileStorage*) { })
3231
{
33-
ContextPtr->setEnvironment(EnvPtr.get());
32+
// Create and store the default environment.
33+
ContextPtr->EmbeddedEnvs[nullptr] =
34+
std::make_unique<heavy::Environment>(*ContextPtr);
3435
}
3536

3637
HeavyScheme::HeavyScheme()
@@ -53,44 +54,32 @@ heavy::Lexer HeavyScheme::createEmbeddedLexer(uintptr_t ExternalRawLoc,
5354
return Lexer(File, BufferPos);
5455
}
5556

56-
void HeavyScheme::LoadEmbeddedEnv(void* Handle,
57-
llvm::function_ref<void(HeavyScheme&, void*)> LoadParent) {
58-
auto& Context = getContext();
59-
auto& EmbeddedEnvs = Context.EmbeddedEnvs; // TODO store EmbeddedEnvs in HeavyScheme
57+
heavy::Environment* HeavyScheme::LoadEmbeddedEnv(void* Handle,
58+
llvm::function_ref<heavy::Environment*(HeavyScheme&, void*)> LoadParent) {
59+
auto& EmbeddedEnvs = getContext().EmbeddedEnvs;
6060
auto itr = EmbeddedEnvs.find(Handle);
61-
if (itr != EmbeddedEnvs.end()) {
62-
Context.EnvStack = itr->second.get();
63-
return;
64-
}
61+
if (itr != EmbeddedEnvs.end())
62+
return itr->second.get();
6563

66-
LoadParent(*this, Handle);
67-
Environment* Parent = cast<Environment>(Context.getEnvironment());
68-
auto& Env = Context.EmbeddedEnvs[Handle] =
64+
assert(Handle != nullptr && "HeavyScheme should have root environment");
65+
Environment* Parent = LoadParent(*this, Handle);
66+
auto& EnvPtr = EmbeddedEnvs[Handle] =
6967
std::make_unique<Environment>(Parent);
70-
Context.setEnvironment(Env.get());
71-
return;
72-
}
73-
74-
void HeavyScheme::ProcessTopLevelCommands(
75-
heavy::Lexer& Lexer,
76-
llvm::function_ref<ErrorHandlerFn> ErrorHandler,
77-
heavy::tok Terminator) {
78-
return ProcessTopLevelCommands(Lexer, base::eval, ErrorHandler,
79-
Terminator);
68+
return EnvPtr.get();
8069
}
8170

8271
void HeavyScheme::ProcessTopLevelCommands(
8372
heavy::Lexer& Lexer,
8473
llvm::function_ref<ValueFnTy> ExprHandler,
8574
llvm::function_ref<ErrorHandlerFn> ErrorHandler,
75+
heavy::Environment* Env,
8676
heavy::tok Terminator) {
87-
// This should be the only entry point so that Env is captured and
88-
// participates in garbage collection.
89-
heavy::Environment* Env = EnvPtr.get();
9077
auto& Context = getContext();
9178
auto& SM = getSourceManager();
9279
auto ParserPtr = std::make_unique<Parser>(Lexer, Context);
9380
Parser& Parser = *ParserPtr;
81+
if (Env == nullptr)
82+
Env = Context.EmbeddedEnvs[nullptr].get();
9483

9584
auto HandleErrorFn = [&](heavy::Context& Context, ValueRefs Args) {
9685
heavy::FullSourceLocation FullLoc = SM.getFullSourceLocation(

heavy/lib/SourceFileStorage.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ void HeavyScheme::ProcessTopLevelCommands(llvm::StringRef Filename,
5757
return;
5858
}
5959
heavy::Lexer Lexer(FileResult.get());
60-
ProcessTopLevelCommands(Lexer, ExprHandler, ErrorHandler, tok::eof);
60+
ProcessTopLevelCommands(Lexer, ExprHandler, ErrorHandler,
61+
/*Environment=*/nullptr, tok::eof);
6162
}
6263

6364
// This overload provides the default file system

heavy/test/Clang/Inputs/my/lib.sld

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
(import (heavy base))
2+
3+
(define-library (my lib)
4+
(import (heavy base))
5+
(import (heavy clang))
6+
(begin
7+
(define (lol-trait name)
8+
(define loc (source-loc name))
9+
(write-lexer loc 'struct)
10+
(write-lexer loc
11+
(string-append
12+
name
13+
" { static constexpr bool is_"
14+
name
15+
" = true; };")))
16+
(define (is-empty cpp-typename)
17+
(expr-eval
18+
(source-loc cpp-typename)
19+
(string-append "std::is_empty_v<"
20+
cpp-typename
21+
">")))
22+
(write "end of my lib init")
23+
(newline))
24+
(export is-empty lol-trait)
25+
)
26+
(write "end of my lib module")
27+
(newline)

heavy/test/Clang/import.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: clang++ -I %S/Inputs -fsyntax-only -Xclang -fheavy -Xclang -verify %s
2+
3+
#include <type_traits>
4+
5+
namespace foo {
6+
// expected-error@+6{{expected unqualified-id}}
7+
heavy_scheme {
8+
(import (my lib))
9+
(import (heavy base))
10+
11+
(lol-trait 'woof)
12+
(lol-trait 'my-trait)
13+
(define hello-foo "hello foo!")
14+
(write hello-foo)
15+
}
16+
}
17+
18+
static_assert(std::is_empty_v<foo::woof>);
19+
20+
namespace bar {
21+
heavy_scheme {
22+
; // FIXME Should we have separate scopes in different namespaces?
23+
(import (heavy base))
24+
(write hello-foo)
25+
(import (my lib)) ; FIXME
26+
(if (is-empty 'foo::woof)
27+
(lol-trait 'bark)
28+
(raise-error "expecting empty woof"))
29+
}
30+
}
31+
32+
static_assert(std::is_empty_v<bar::bark>);
33+
static_assert(bar::bark::is_bark);

0 commit comments

Comments
 (0)