mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
233 lines
5.9 KiB
Plaintext
233 lines
5.9 KiB
Plaintext
// #target: macos-x64
|
|
|
|
<* @require Type.kindof == STRUCT *>
|
|
module abc{Type};
|
|
import std::io;
|
|
import std::collections::list;
|
|
|
|
alias TextTagList = List{TextTag};
|
|
|
|
faultdef UNTERMINATED_TAG, EMPTY_TAG, MISSING_TAG, UNSUPPORTED_TAG;
|
|
|
|
enum TextTagKind: char
|
|
{
|
|
STRING,
|
|
TEMPLATE,
|
|
}
|
|
|
|
struct TextTemplate
|
|
{
|
|
Allocator allocator;
|
|
String template;
|
|
TextTag[] tags;
|
|
Type data;
|
|
}
|
|
|
|
struct TextTag
|
|
{
|
|
usz start;
|
|
usz end;
|
|
TextTagKind kind;
|
|
union {
|
|
String* data;
|
|
TextTemplate* template;
|
|
}
|
|
}
|
|
|
|
<*
|
|
@require self.tags.len == 0 "template already initialized"
|
|
@require tag_start != tag_end
|
|
*>
|
|
fn void? TextTemplate.init(&self, String template, String tag_start = "{{", String tag_end = "}}", Allocator using = allocator::heap())
|
|
{
|
|
TextTagList tags;
|
|
String tmpl = template;
|
|
uptr data = (uptr)&self.data;
|
|
while (true)
|
|
{
|
|
usz? start = tmpl.index_of(tag_start);
|
|
if (catch start) break;
|
|
tmpl = tmpl[start + tag_start.len..];
|
|
|
|
usz? end = tmpl.index_of(tag_end);
|
|
if (catch end) return UNTERMINATED_TAG?;
|
|
String name = tmpl[:end].trim();
|
|
if (name == "") return EMPTY_TAG?;
|
|
// Check that the tag exists in the data struct.
|
|
|
|
TextTag tag @noinit;
|
|
do OUTER:
|
|
{
|
|
$foreach $m : Type.membersof:
|
|
if (name == $m.nameof)
|
|
{
|
|
$switch $m.typeid:
|
|
$case String.typeid:
|
|
tag = {
|
|
.kind = STRING,
|
|
.data = (String*)(data + $m.offsetof),
|
|
};
|
|
break OUTER;
|
|
$default:
|
|
$if $defined($m.get(self.data).as_stream):
|
|
tag = {
|
|
.kind = TEMPLATE,
|
|
.template = self.data.$eval($m.nameof).as_stream(),
|
|
};
|
|
break;
|
|
$endif
|
|
$endswitch
|
|
//return UNSUPPORTED_TAG?;
|
|
}
|
|
$endforeach
|
|
return MISSING_TAG?;
|
|
};
|
|
tmpl = tmpl[end + tag_end.len..];
|
|
|
|
tag.start = start;
|
|
tag.end = start + tag_start.len + end + tag_end.len;
|
|
tags.push(tag);
|
|
}
|
|
|
|
*self = { .allocator = using, .template = template, .tags = tags.array_view() };
|
|
}
|
|
|
|
fn void? TextTemplate.free(&self)
|
|
{
|
|
allocator::free(self.allocator, self.tags);
|
|
*self = {};
|
|
}
|
|
|
|
fn usz? TextTemplate.write_to(&self, OutStream writer)
|
|
{
|
|
usz n;
|
|
usz pos;
|
|
foreach (tag : self.tags)
|
|
{
|
|
n += writer.write(self.template[pos:tag.start])!;
|
|
pos += tag.end;
|
|
n += tag.write(writer)!;
|
|
}
|
|
n += writer.write(self.template[pos..])!;
|
|
return n;
|
|
}
|
|
|
|
fn usz? TextTag.write(&self, OutStream writer)
|
|
{
|
|
switch (self.kind)
|
|
{
|
|
case STRING:
|
|
return writer.write(*self.data);
|
|
case TEMPLATE:
|
|
return self.template.write_to(writer);
|
|
}
|
|
}
|
|
|
|
module text_test;
|
|
import abc;
|
|
import std::io;
|
|
|
|
alias Tmpl = TextTemplate{Data};
|
|
|
|
struct Data
|
|
{
|
|
String user;
|
|
String world;
|
|
bool ok;
|
|
}
|
|
|
|
|
|
|
|
alias FooTmpl = TextTemplate{Foo};
|
|
alias BarTmpl = TextTemplate{Bar};
|
|
|
|
struct Foo
|
|
{
|
|
String foo;
|
|
BarTmpl* bar;
|
|
}
|
|
|
|
struct Bar
|
|
{
|
|
String bar;
|
|
}
|
|
|
|
fn void main()
|
|
{
|
|
|
|
String foo_tmpl = "<<{{foo}} | {{bar}}>>";
|
|
FooTmpl ft;
|
|
ft.init(foo_tmpl, using: allocator::temp())!!;
|
|
defer ft.free()!!;
|
|
|
|
|
|
}
|
|
|
|
/* #expect: text_test.ll
|
|
|
|
define void @text_test.main() #0 {
|
|
entry:
|
|
%foo_tmpl = alloca %"char[]", align 8
|
|
%ft = alloca %TextTemplate, align 8
|
|
%error_var = alloca i64, align 8
|
|
%indirectarg = alloca %"char[]", align 8
|
|
%varargslots = alloca [1 x %any], align 16
|
|
%indirectarg1 = alloca %"any[]", align 8
|
|
%error_var2 = alloca i64, align 8
|
|
%varargslots7 = alloca [1 x %any], align 16
|
|
%indirectarg9 = alloca %"any[]", align 8
|
|
store %"char[]" { ptr @.str, i64 21 }, ptr %foo_tmpl, align 8
|
|
call void @llvm.memset.p0.i64(ptr align 8 %ft, i8 0, i64 72, i1 false)
|
|
%lo = load ptr, ptr %foo_tmpl, align 8
|
|
%ptradd = getelementptr inbounds i8, ptr %foo_tmpl, i64 8
|
|
%hi = load i64, ptr %ptradd, align 8
|
|
store %"char[]" { ptr @.str.2, i64 2 }, ptr %indirectarg, align 8
|
|
%0 = call i64 @"abc$text_test.Foo$.TextTemplate.init"(ptr %ft, ptr %lo, i64 %hi, ptr @.str.1, i64 2, ptr byval(%"char[]") align 8 %indirectarg, ptr byval(%any) align 8 @std.core.mem.allocator.current_temp)
|
|
%not_err = icmp eq i64 %0, 0
|
|
%1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
|
br i1 %1, label %after_check, label %assign_optional
|
|
|
|
assign_optional: ; preds = %entry
|
|
store i64 %0, ptr %error_var, align 8
|
|
br label %panic_block
|
|
|
|
after_check: ; preds = %entry
|
|
br label %noerr_block
|
|
|
|
panic_block: ; preds = %assign_optional
|
|
%2 = insertvalue %any undef, ptr %error_var, 0
|
|
%3 = insertvalue %any %2, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
|
|
store %any %3, ptr %varargslots, align 16
|
|
%4 = insertvalue %"any[]" undef, ptr %varargslots, 0
|
|
%"$$temp" = insertvalue %"any[]" %4, i64 1, 1
|
|
store %"any[]" %"$$temp", ptr %indirectarg1, align 8
|
|
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 25, ptr @.func, i64 4, i32 159, ptr byval(%"any[]") align 8 %indirectarg1) #3
|
|
unreachable
|
|
|
|
noerr_block: ; preds = %after_check
|
|
%5 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft)
|
|
%not_err3 = icmp eq i64 %5, 0
|
|
%6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
|
|
br i1 %6, label %after_check5, label %assign_optional4
|
|
|
|
assign_optional4: ; preds = %noerr_block
|
|
store i64 %5, ptr %error_var2, align 8
|
|
br label %panic_block6
|
|
|
|
after_check5: ; preds = %noerr_block
|
|
br label %noerr_block10
|
|
|
|
panic_block6: ; preds = %assign_optional4
|
|
%7 = insertvalue %any undef, ptr %error_var2, 0
|
|
%8 = insertvalue %any %7, i64 ptrtoint (ptr @"$ct.fault" to i64), 1
|
|
store %any %8, ptr %varargslots7, align 16
|
|
%9 = insertvalue %"any[]" undef, ptr %varargslots7, 0
|
|
%"$$temp8" = insertvalue %"any[]" %9, i64 1, 1
|
|
store %"any[]" %"$$temp8", ptr %indirectarg9, align 8
|
|
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 25, ptr @.func, i64 4, i32 160, ptr byval(%"any[]") align 8 %indirectarg9) #3
|
|
unreachable
|
|
|
|
noerr_block10: ; preds = %after_check5
|
|
ret void
|
|
}
|