Skip to content

Commit 7f706b4

Browse files
committed
[Heavy] Add string-ref; Improve utf8 support for string procs
1 parent 09def94 commit 7f706b4

File tree

6 files changed

+97
-16
lines changed

6 files changed

+97
-16
lines changed

heavy/include/heavy/Builtins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ void InitParseSourceFile(heavy::Context& C, ParseSourceFileFn Fn) {
8888
namespace heavy::detail {
8989
// Declare utility functions for iterating UTF-8 characters.
9090
class Utf8View {
91-
llvm::StringRef Range;
9291
public:
92+
llvm::StringRef Range;
9393
Utf8View(llvm::StringRef StrView)
9494
: Range(StrView)
9595
{ }

heavy/include/heavy/Context.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,14 @@ class Context : public ContinuationStack<Context>,
342342
Pair* CreatePair(Value V1) {
343343
return new (*this) Pair(V1, CreateEmpty());
344344
}
345+
Pair* CreatePair(Value V1, Value V2, Pair* SourcePair) {
346+
heavy::SourceLocation Loc = SourcePair->getSourceLocation();
347+
// Try to preserve source locations.
348+
if (Loc.isValid())
349+
return CreatePairWithSource(V1, V2, Loc);
350+
else
351+
return CreatePair(V1, V2);
352+
}
345353
PairWithSource* CreatePairWithSource(Value V1, Value V2,
346354
SourceLocation Loc) {
347355
return new (*this) PairWithSource(V1, V2, Loc);

heavy/include/heavy/base.sld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
raise
6060
string-append
6161
string-copy
62+
string-ref
6263
string-length
6364
values
6465
with-exception-handler

heavy/lib/Builtins.cpp

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ heavy::ExternFunction newline;
7474
heavy::ExternFunction string_append;
7575
heavy::ExternFunction string_copy;
7676
heavy::ExternFunction string_length;
77+
heavy::ExternFunction string_ref;
7778
heavy::ExternFunction number_to_string;
7879
heavy::ExternFunction eq;
7980
heavy::ExternFunction equal;
@@ -518,10 +519,43 @@ void string_append(Context& C, ValueRefs Args) {
518519
void string_length(Context& C, ValueRefs Args) {
519520
if (Args.size() != 1 || !isa<String, Symbol>(Args[0]))
520521
return C.RaiseError("expecting string-like object");
521-
int Size = static_cast<int>(Args[0].getStringRef().size());
522+
523+
auto Utf8View = detail::Utf8View(Args[0].getStringRef());
524+
525+
int Size = 0;
526+
while (Utf8View.drop_front())
527+
++Size;
528+
522529
return C.Cont(Int(Size));
523530
}
524531

532+
void string_ref(Context& C, ValueRefs Args) {
533+
size_t K = 0;
534+
if (Args.size() != 2)
535+
return C.RaiseError("invalid arity");
536+
if (!isa<String, Symbol>(Args[0]))
537+
return C.RaiseError("expecting string-like object");
538+
if (Args.size() == 2) {
539+
if (isa<Int>(Args[1]) && cast<Int>(Args[1]) >= 0)
540+
K = static_cast<size_t>(cast<Int>(Args[1]));
541+
else
542+
return C.RaiseError("expecting positive integer");
543+
}
544+
545+
auto Utf8View = detail::Utf8View(Args[0].getStringRef());
546+
547+
Value V;
548+
for (size_t I = 0; I <= K; ++I) {
549+
V = Utf8View.drop_front();
550+
if (!V) {
551+
return C.RaiseError("invalid index for string: {0} {1}",
552+
{Args[1], Args[0]});
553+
}
554+
}
555+
556+
return C.Cont(V);
557+
}
558+
525559
void string_copy(Context& C, ValueRefs Args) {
526560
if (Args.size() > 3)
527561
return C.RaiseError("invalid arity");
@@ -532,20 +566,31 @@ void string_copy(Context& C, ValueRefs Args) {
532566
size_t EndPos = ~size_t(0); // npos
533567

534568
if (Args.size() >= 2) {
535-
if (isa<Int>(Args[1]))
569+
if (isa<Int>(Args[1]) && cast<Int>(Args[1]) >= 0)
536570
StartPos = static_cast<size_t>(cast<Int>(Args[1]));
537571
else
538-
return C.RaiseError("expecting integer");
572+
return C.RaiseError("expecting positive integer");
539573
}
540574
if (Args.size() == 3) {
541-
if (isa<Int>(Args[2]))
575+
if (isa<Int>(Args[2]) && cast<Int>(Args[2]) >= 0)
542576
EndPos = static_cast<size_t>(cast<Int>(Args[2]));
543577
else
544-
return C.RaiseError("expecting integer");
578+
return C.RaiseError("expecting positive integer");
579+
}
580+
581+
auto View = detail::Utf8View(Args[0].getStringRef());
582+
size_t I = 0;
583+
for (; I < StartPos; ++I)
584+
View.drop_front();
585+
auto Back = View;
586+
llvm::StringRef ViewStr = View.Range;
587+
if (EndPos != ~size_t(0)) {
588+
for (; I < EndPos; ++I)
589+
Back.drop_front();
590+
ViewStr = ViewStr.drop_back(Back.Range.size());
545591
}
546592

547-
llvm::StringRef Substr = Args[0].getStringRef().slice(StartPos, EndPos);
548-
return C.Cont(C.CreateString(Substr));
593+
return C.Cont(C.CreateString(ViewStr));
549594
}
550595

551596
void number_to_string(Context& C, ValueRefs Args) {
@@ -742,7 +787,7 @@ Value append_rec(Context& C, Value List, Value Cdr) {
742787
return Cdr;
743788
if (Pair* P = dyn_cast<Pair>(List)) {
744789
if (Value V = append_rec(C, P->Cdr, Cdr))
745-
return C.CreatePair(P->Car, V);
790+
return C.CreatePair(P->Car, V, P);
746791
}
747792
return Value();
748793
};
@@ -1201,6 +1246,7 @@ void HEAVY_BASE_INIT(heavy::Context& Context) {
12011246
HEAVY_BASE_VAR(string_append) = heavy::builtins::string_append;
12021247
HEAVY_BASE_VAR(string_copy) = heavy::builtins::string_copy;
12031248
HEAVY_BASE_VAR(string_length) = heavy::builtins::string_length;
1249+
HEAVY_BASE_VAR(string_ref) = heavy::builtins::string_ref;
12041250
HEAVY_BASE_VAR(number_to_string) = heavy::builtins::number_to_string;
12051251
HEAVY_BASE_VAR(eq) = heavy::builtins::eqv;
12061252
HEAVY_BASE_VAR(equal) = heavy::builtins::equal;
@@ -1295,6 +1341,7 @@ void HEAVY_BASE_LOAD_MODULE(heavy::Context& Context) {
12951341
{"string-append", HEAVY_BASE_VAR(string_append)},
12961342
{"string-copy", HEAVY_BASE_VAR(string_copy)},
12971343
{"string-length", HEAVY_BASE_VAR(string_length)},
1344+
{"string-ref", HEAVY_BASE_VAR(string_ref)},
12981345
{"number->string", HEAVY_BASE_VAR(number_to_string)},
12991346
{"eq?", HEAVY_BASE_VAR(eq)},
13001347
{"equal?", HEAVY_BASE_VAR(equal)},

heavy/lib/Context.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,11 +1480,7 @@ class LiteralRebuilder : public ValueVisitor<LiteralRebuilder, Value> {
14801480
Value Cdr = Visit(P->Cdr);
14811481
if (Car == P->Car && Cdr == P->Cdr)
14821482
return P;
1483-
heavy::SourceLocation Loc = P->getSourceLocation();
1484-
if (Loc.isValid())
1485-
return Context.CreatePairWithSource(Car, Cdr, Loc);
1486-
else
1487-
return Context.CreatePair(Car, Cdr);
1483+
return Context.CreatePair(Car, Cdr, P);
14881484
}
14891485

14901486
Value VisitVector(Vector* V) {

heavy/test/Evaluate/string.scm

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
(string? ())))
1010
(newline)
1111

12-
; CHECK-NEXT: (0 1 3 3 13)
12+
; CHECK-NEXT: (0 1 3 3 13 1 3 9)
1313
(write (list (string-length "")
1414
(string-length "f")
1515
(string-length "foo")
1616
(string-length 'foo)
17-
(string-length "Hello, world!")))
17+
(string-length "Hello, world!")
18+
(string-length "λ")
19+
(string-length "ΣλΣ")
20+
(string-length "ΣλΣfooΣλΣ")))
1821
(newline)
1922

2023
; CHECK-NEXT: ""
@@ -29,6 +32,9 @@
2932
; CHECK-NEXT: "Hello, world!"
3033
(write (string-append 'Hello ", world" '!))(newline)
3134

35+
; CHECK-NEXT: "λΣλΣbarΣλΣfooΣλΣ"
36+
(write (string-append "λ" "ΣλΣ" "bar" "ΣλΣfooΣλΣ"))(newline)
37+
3238
; CHECK-NEXT: "Hello, world!"
3339
(write (string-copy "Hello, world!"))(newline)
3440

@@ -59,6 +65,29 @@
5965
; CHECK-NEXT: ""
6066
(write (string-copy "Hello, world!" 13 5))(newline)
6167

68+
; CHECK-NEXT: #\Σ
69+
(write (string-ref "ΣλΣfooΣλΣ" 0))(newline)
70+
71+
; CHECK-NEXT: #\λ
72+
(write (string-ref "ΣλΣfooΣλΣ" 1))(newline)
73+
74+
; CHECK-NEXT: #\f
75+
(write (string-ref "ΣλΣfooΣλΣ" 3))(newline)
76+
77+
; CHECK: "λ"
78+
(write (string-copy "λ"))(newline)
79+
; CHECK: "ΣλΣ"
80+
(write (string-copy "ΣλΣ"))(newline)
81+
; CHECK: "ΣλΣfooΣλΣ"
82+
(write (string-copy "ΣλΣfooΣλΣ"))(newline)
83+
84+
; CHECK: ""
85+
(write (string-copy "λ" 1))(newline)
86+
; CHECK: "λΣ"
87+
(write (string-copy "ΣλΣ" 1))(newline)
88+
; CHECK: "fooΣ"
89+
(write (string-copy "ΣλΣfooΣλΣ" 3 7))(newline)
90+
6291
; CHECK-NEXT: "0"
6392
(write (number->string 0))(newline)
6493

0 commit comments

Comments
 (0)