mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
245 lines
6.0 KiB
C
245 lines
6.0 KiB
C
// #target: macos-x64
|
|
|
|
/**
|
|
* @require Type.kindof == STRUCT
|
|
**/
|
|
module abc(<Type>);
|
|
import std::io;
|
|
import std::collections::list;
|
|
|
|
def TextTagList = List(<TextTag>);
|
|
|
|
fault TextError
|
|
{
|
|
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 TextError.UNTERMINATED_TAG?;
|
|
String name = tmpl[:end].trim();
|
|
if (name == "") return TextError.EMPTY_TAG?;
|
|
// Check that the tag exists in the data struct.
|
|
TextTag tag = {|
|
|
$foreach ($m : Type.membersof)
|
|
if (name == $m.nameof)
|
|
{
|
|
$switch ($m.typeid)
|
|
$case String.typeid:
|
|
return TextTag{
|
|
.kind = STRING,
|
|
.data = (String*)(data + $m.offsetof),
|
|
};
|
|
$default:
|
|
$if $defined(self.data.$eval($m.nameof).as_stream):
|
|
return TextTag{
|
|
.kind = TEMPLATE,
|
|
.template = self.data.$eval($m.nameof).as_stream(),
|
|
};
|
|
$endif
|
|
$endswitch
|
|
//return TextError.UNSUPPORTED_TAG?;
|
|
}
|
|
$endforeach
|
|
return TextError.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;
|
|
|
|
def Tmpl = TextTemplate(<Data>);
|
|
|
|
struct Data
|
|
{
|
|
String user;
|
|
String world;
|
|
bool ok;
|
|
}
|
|
|
|
|
|
|
|
def FooTmpl = TextTemplate(<Foo>);
|
|
def 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 i64 @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
|
|
%indirectarg1 = alloca %"any*", align 8
|
|
%error_var2 = alloca i64, align 8
|
|
%varargslots = alloca [1 x %"any*"], align 16
|
|
%indirectarg6 = 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)
|
|
%0 = load ptr, ptr @std.core.mem.allocator.thread_temp_allocator, align 8
|
|
%not = icmp eq ptr %0, null
|
|
br i1 %not, label %if.then, label %if.exit
|
|
|
|
if.then: ; preds = %entry
|
|
call void @std.core.mem.allocator.init_default_temp_allocators()
|
|
br label %if.exit
|
|
|
|
if.exit: ; preds = %if.then, %entry
|
|
%1 = load ptr, ptr @std.core.mem.allocator.thread_temp_allocator, align 8
|
|
%2 = insertvalue %"any*" undef, ptr %1, 0
|
|
%3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.std.core.mem.allocator.TempAllocator" to i64), 1
|
|
%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
|
|
store %"any*" %3, ptr %indirectarg1, align 8
|
|
%4 = 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 %indirectarg1)
|
|
%not_err = icmp eq i64 %4, 0
|
|
%5 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
|
br i1 %5, label %after_check, label %assign_optional
|
|
|
|
assign_optional: ; preds = %if.exit
|
|
store i64 %4, ptr %error_var, align 8
|
|
br label %guard_block
|
|
|
|
after_check: ; preds = %if.exit
|
|
br label %noerr_block
|
|
|
|
guard_block: ; preds = %assign_optional
|
|
%6 = load i64, ptr %error_var, align 8
|
|
ret i64 %6
|
|
|
|
noerr_block: ; preds = %after_check
|
|
%7 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft)
|
|
%not_err3 = icmp eq i64 %7, 0
|
|
%8 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
|
|
br i1 %8, label %after_check5, label %assign_optional4
|
|
|
|
assign_optional4: ; preds = %noerr_block
|
|
store i64 %7, ptr %error_var2, align 8
|
|
br label %panic_block
|
|
|
|
after_check5: ; preds = %noerr_block
|
|
br label %noerr_block7
|
|
|
|
panic_block: ; preds = %assign_optional4
|
|
%9 = insertvalue %"any*" undef, ptr %error_var2, 0
|
|
%10 = insertvalue %"any*" %9, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
|
|
store %"any*" %10, ptr %varargslots, align 16
|
|
%11 = insertvalue %"any*[]" undef, ptr %varargslots, 0
|
|
%"$$temp" = insertvalue %"any*[]" %11, i64 1, 1
|
|
store %"any*[]" %"$$temp", ptr %indirectarg6, align 8
|
|
call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 25
|
|
unreachable
|
|
|
|
noerr_block7: ; preds = %after_check5
|
|
ret i64 0
|
|
}
|