Skip to content

Commit 8c858e0

Browse files
committed
[Heavy] Fix hygiene for define init syntax
1 parent 928d089 commit 8c858e0

File tree

7 files changed

+56
-15
lines changed

7 files changed

+56
-15
lines changed

heavy/include/heavy/OpGen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ class OpGen : public ValueVisitor<OpGen, mlir::Value> {
128128
// in LookupEnv.
129129
SyntaxClosure* CurSyntaxClosure = nullptr;
130130

131+
struct SyntaxClosureScope;
132+
131133
// Err - The stored error to indicate that the compiler is in an error state.
132134
// (Use CheckError())
133135
Value Err = nullptr;

heavy/include/heavy/base.sld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
define-syntax
3535
if
3636
lambda
37+
case-lambda
3738
quasiquote
3839
quote
3940
set!

heavy/lib/Builtins.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,14 @@ mlir::Value syntax_fn(OpGen& OG, Pair* P) {
193193

194194
mlir::Value lambda(OpGen& OG, Pair* P) {
195195
Pair* P2 = dyn_cast<Pair>(P->Cdr);
196+
if (!P2)
197+
return OG.SetError("invalid lambda syntax", P);
196198
Value Formals = P2->Car;
197199
Pair* Body = dyn_cast<Pair>(P2->Cdr);
198200

201+
if (!Body)
202+
return OG.SetError("lambda syntax requires body");
203+
199204
return OG.createLambda(Formals, Body, P->getSourceLocation());
200205
}
201206

heavy/lib/OpEval.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,13 @@ class OpEvalImpl {
503503
}
504504

505505
BlockItrTy Visit(SetOp Op) {
506-
heavy::Binding* B = cast<heavy::Binding>(getBindingOrValue(Op.getBinding()));
506+
Value RawValue = getBindingOrValue(Op.getBinding());
507+
heavy::Binding* B = dyn_cast<heavy::Binding>(RawValue);
508+
if (!B) {
509+
Context.RaiseError("invalid set operand: {}", RawValue);
510+
return BlockItrTy();
511+
}
512+
507513
heavy::Value RHS = getValue(Op.getInput());
508514
B->setValue(RHS);
509515
return next(Op);

heavy/lib/OpGen.cpp

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@
3030
#include <memory>
3131

3232
using namespace heavy;
33+
34+
struct OpGen::SyntaxClosureScope {
35+
OpGen& O;
36+
SyntaxClosure* PrevSC;
37+
38+
SyntaxClosureScope(OpGen& O, SyntaxClosure* SC)
39+
: O(O),
40+
PrevSC(O.CurSyntaxClosure)
41+
{
42+
O.CurSyntaxClosure = SC;
43+
}
44+
45+
~SyntaxClosureScope() {
46+
O.CurSyntaxClosure = PrevSC;
47+
}
48+
};
49+
3350
// LambdaScope - RAII object that pushes an operation that is
3451
// FunctionLike to the scope stack along with a
3552
// BindingScope where we can insert stack local
@@ -884,6 +901,11 @@ bool OpGen::WalkDefineInits(Value Env, IdSet& LocalIds) {
884901
// Insert the binding initializer.
885902
auto Undef = cast<heavy::Undefined>(B->getValue());
886903
Value DefineArgs = Undef.getTracer();
904+
// SC may be nullptr.
905+
auto* SC = dyn_cast<SyntaxClosure>(Undef.getTracer());
906+
SyntaxClosureScope SCScope(*this, SC);
907+
if (SC)
908+
DefineArgs = SC->Node;
887909
mlir::Value Init = VisitDefineArgs(DefineArgs);
888910
mlir::Value BVal = LocalizeValue(BindingTable.lookup(B), B);
889911
SourceLocation Loc = DefineArgs.getSourceLocation();
@@ -918,14 +940,17 @@ mlir::Value OpGen::createBinding(Binding *B, mlir::Value Init) {
918940
return BVal;
919941
}
920942

921-
mlir::Value OpGen::createDefine(Value Id, Value DefineArgs,
922-
Value OrigCall) {
943+
mlir::Value OpGen::createDefine(Value Id, Value DefineArgs, Value OrigCall) {
923944
if (isTopLevel()) return createTopLevelDefine(Id, DefineArgs, OrigCall);
924945
if (!IsLocalDefineAllowed) return SetError("unexpected define", OrigCall);
925-
// Create the binding with a lazy init.
926-
// (Include everything after the define
927-
// keyword to visit it later because it could
928-
// be a terse lambda syntax.)
946+
// Create the binding with an undefined object that secretly holds
947+
// its syntax in the current environment.
948+
Value Env;
949+
950+
if (CurSyntaxClosure)
951+
DefineArgs = Context.CreateSyntaxClosure(DefineArgs.getSourceLocation(),
952+
DefineArgs,
953+
CurSyntaxClosure->Env);
929954
Binding* B = Context.CreateBinding(Id, Undefined(DefineArgs));
930955
// Push to the local environment.
931956
Context.PushLocalBinding(B);
@@ -1145,11 +1170,8 @@ mlir::Value OpGen::VisitExternName(ExternName* EN) {
11451170
}
11461171

11471172
mlir::Value OpGen::VisitSyntaxClosure(SyntaxClosure* SC) {
1148-
SyntaxClosure* PrevSC = CurSyntaxClosure;
1149-
CurSyntaxClosure = SC;
1173+
SyntaxClosureScope SCScope(*this, SC);
11501174
mlir::Value Result = Visit(SC->Node);
1151-
CurSyntaxClosure = PrevSC;
1152-
11531175
return Result;
11541176
}
11551177

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@
2121

2222
(define-syntax create-op-literal
2323
(syntax-rules ()
24-
((create-op-literal (Arg) X)
24+
((create-op-literal (EmptyThunk) X)
2525
((lambda (Arg)
26+
; Test hygiene of define initializer.
27+
(define (MakeAttr Z)
28+
(value-attr Z))
29+
; Trigger compiling define initializers with a syntactic closure.
30+
(EmptyThunk)
2631
(create-op "heavy.literal"
2732
(attributes
28-
`("info", (value-attr Arg))))) X))))
33+
`("info", (MakeAttr Arg))))) X))))
2934

3035
(write "end of init")
3136
(newline)

heavy/test/Evaluate/load-module.scm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
; CHECK-NEXT: "end of init"
66
(import (my lib))
77
(import (only (heavy builtins)
8-
write newline))
8+
write newline lambda))
99

1010
; CHECK: "hello module!"
1111
; CHECK-NEXT: 5
@@ -16,5 +16,5 @@
1616
(hello-module-syntax "woof!")
1717

1818
; CHECK: #op{"heavy.literal"() {info = #heavy<"42">}
19-
(write (create-op-literal (SomeArg) 42))
19+
(write (create-op-literal ((lambda () #f)) 42))
2020
(newline)

0 commit comments

Comments
 (0)