update: misc
This commit is contained in:
parent
175c30b199
commit
9bde4370a6
1 changed files with 10 additions and 83 deletions
93
todo.md
93
todo.md
|
|
@ -130,88 +130,15 @@ ___
|
||||||
- Loops com forloop
|
- Loops com forloop
|
||||||
- Tudo testado
|
- Tudo testado
|
||||||
|
|
||||||
4 -Filtros
|
|
||||||
|
|
||||||
|
- Renderer básico — variáveis simples {{ nome }} (já quase pronto acima)
|
||||||
|
- Filtros em variáveis — {{ nome|upper }}, {{ idade|add:5 }}
|
||||||
|
- Escaping automático — tudo escapa por default, {{ valor|safe }} não escapa
|
||||||
|
- Tags básicas — {% if %}, {% for %}, {% block %}
|
||||||
|
- Extends / include
|
||||||
|
- Autoescape on/off
|
||||||
|
|
||||||
|
- Adicionar suporte a argumentos nos filtros (já quase pronto — parsear name:arg)
|
||||||
|
- Implementar tags básicas (if/for) usando a árvore do parser
|
||||||
|
- Autoescape completo (escape só em .string, e tratar .safe se quiser)
|
||||||
na verdade o pushScope não tava não, a versão final que vc me mandou depois que se inspirou no tokamak foi essa:
|
- Blocos e extends (usando a árvore para coletar blocos e renderizar base)
|
||||||
```
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const Value = union(enum) {
|
|
||||||
null,
|
|
||||||
bool: bool,
|
|
||||||
int: i64,
|
|
||||||
float: f64,
|
|
||||||
string: []const u8,
|
|
||||||
list: []const Value,
|
|
||||||
dict: std.StringHashMapUnmanaged(Value),
|
|
||||||
|
|
||||||
pub fn deinit(self: Value) void {
|
|
||||||
_ = self; // nada — a arena libera tudo
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Context = struct {
|
|
||||||
arena: std.heap.ArenaAllocator,
|
|
||||||
map: std.StringHashMapUnmanaged(Value),
|
|
||||||
|
|
||||||
pub fn init(child_allocator: std.mem.Allocator) Context {
|
|
||||||
const arena = std.heap.ArenaAllocator.init(child_allocator);
|
|
||||||
return .{
|
|
||||||
.arena = arena,
|
|
||||||
.map = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn allocator(self: *Context) std.mem.Allocator {
|
|
||||||
return self.arena.allocator();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Context) void {
|
|
||||||
self.arena.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(self: *Context, key: []const u8, value: Value) !void {
|
|
||||||
const gop = try self.map.getOrPut(self.allocator(), key);
|
|
||||||
if (gop.found_existing) {
|
|
||||||
// opcional: deinit value antigo se necessário
|
|
||||||
// mas como arena libera tudo, não precisa
|
|
||||||
} else {
|
|
||||||
gop.key_ptr.* = try self.allocator().dupe(u8, key);
|
|
||||||
}
|
|
||||||
gop.value_ptr.* = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(self: *const Context, key: []const u8) ?Value {
|
|
||||||
return self.map.get(key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
```
|
|
||||||
ao colocar isso ordered_dict: []struct { key: []const u8, val: Value }, vc ferrou em todos os switches de Value que agora tem que prever o que fazer com orderdered_dict
|
|
||||||
|
|
||||||
Conclusão sobre o getA melhor abordagem, considerando Zig, é:
|
|
||||||
Manter o get(comptime T: type, key) — é seguro, performático, e em uso real fica natural
|
|
||||||
|
|
||||||
```zig
|
|
||||||
const idade: i64 = ctx.get("idade") orelse 0;
|
|
||||||
const nome: []const u8 = ctx.get("nome") orelse "Desconhecido";
|
|
||||||
```
|
|
||||||
|
|
||||||
É verboso no teste, mas em código real é claro e seguro.Ou podemos fazer uma versão com optional:
|
|
||||||
|
|
||||||
```zig
|
|
||||||
pub fn get(self: *const Context, comptime T: type, key: []const u8) ?T {
|
|
||||||
const value = self.map.get(key) orelse return null;
|
|
||||||
return value.as(T) catch null;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Aí fica:
|
|
||||||
|
|
||||||
```zig
|
|
||||||
const idade = ctx.get(i64, "idade") orelse 0;
|
|
||||||
```
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue