// benchmark_examples.zig - Benchmark pug example files // // Tests the same example files as the JS benchmark const std = @import("std"); const pug = @import("../pug.zig"); const Example = struct { name: []const u8, source: []const u8, }; // Example templates (matching JS pug examples that don't use includes/extends) const examples = [_]Example{ .{ .name = "attributes.pug", .source = \\div#id.left.container(class='user user-' + name) \\ h1.title= name \\ form \\ //- unbuffered comment :) \\ // An example of attributes. \\ input(type='text' name='user[name]' value=name) \\ input(checked, type='checkbox', name='user[blocked]') \\ input(type='submit', value='Update') , }, .{ .name = "code.pug", .source = \\- var title = "Things" \\ \\- \\ var subtitle = ["Really", "long", \\ "list", "of", \\ "words"] \\h1= title \\h2= subtitle.join(" ") \\ \\ul#users \\ each user, name in users \\ // expands to if (user.isA == 'ferret') \\ if user.isA == 'ferret' \\ li(class='user-' + name) #{name} is just a ferret \\ else \\ li(class='user-' + name) #{name} #{user.email} , }, .{ .name = "dynamicscript.pug", .source = \\html \\ head \\ title Dynamic Inline JavaScript \\ script. \\ var users = !{JSON.stringify(users).replace(/<\//g, "<\\/")} , }, .{ .name = "each.pug", .source = \\ul#users \\ each user, name in users \\ li(class='user-' + name) #{name} #{user.email} , }, .{ .name = "extend-layout.pug", .source = \\html \\ head \\ h1 My Site - #{title} \\ block scripts \\ script(src='/jquery.js') \\ body \\ block content \\ block foot \\ #footer \\ p some footer content , }, .{ .name = "form.pug", .source = \\form(method="post") \\ fieldset \\ legend General \\ p \\ label(for="user[name]") Username: \\ input(type="text", name="user[name]", value=user.name) \\ p \\ label(for="user[email]") Email: \\ input(type="text", name="user[email]", value=user.email) \\ .tip. \\ Enter a valid \\ email address \\ such as tj@vision-media.ca. \\ fieldset \\ legend Location \\ p \\ label(for="user[city]") City: \\ input(type="text", name="user[city]", value=user.city) \\ p \\ select(name="user[province]") \\ option(value="") -- Select Province -- \\ option(value="AB") Alberta \\ option(value="BC") British Columbia \\ option(value="SK") Saskatchewan \\ option(value="MB") Manitoba \\ option(value="ON") Ontario \\ option(value="QC") Quebec \\ p.buttons \\ input(type="submit", value="Save") , }, .{ .name = "layout.pug", .source = \\doctype html \\html(lang="en") \\ head \\ title Example \\ script. \\ if (foo) { \\ bar(); \\ } \\ body \\ h1 Pug - node template engine \\ #container , }, .{ .name = "pet.pug", .source = \\.pet \\ h2= pet.name \\ p #{pet.name} is #{pet.age} year(s) old. , }, .{ .name = "rss.pug", .source = \\doctype xml \\rss(version='2.0') \\channel \\ title RSS Title \\ description Some description here \\ link http://google.com \\ lastBuildDate Mon, 06 Sep 2010 00:01:00 +0000 \\ pubDate Mon, 06 Sep 2009 16:45:00 +0000 \\ \\ each item in items \\ item \\ title= item.title \\ description= item.description \\ link= item.link , }, .{ .name = "text.pug", .source = \\| An example of an \\a(href='#') inline \\| link. \\ \\form \\ label Username: \\ input(type='text', name='user[name]') \\ p \\ | Just an example of some text usage. \\ | You can have inline html, \\ | as well as \\ strong tags \\ | . \\ \\ | Interpolation is also supported. The \\ | username is currently "#{name}". \\ \\ label Email: \\ input(type='text', name='user[email]') \\ p \\ | Email is currently \\ em= email \\ | . , }, .{ .name = "whitespace.pug", .source = \\- var js = '' \\doctype html \\html \\ \\ head \\ title= "Some " + "JavaScript" \\ != js \\ \\ \\ \\ body , }, }; pub fn main() !void { const allocator = std.heap.page_allocator; std.debug.print("=== Zig Pugz Example Benchmark ===\n\n", .{}); var passed: usize = 0; var failed: usize = 0; var total_time_ns: u64 = 0; var html_outputs: [examples.len]?[]const u8 = undefined; for (&html_outputs) |*h| h.* = null; for (examples, 0..) |example, idx| { const iterations: usize = 100; var success = false; var time_ns: u64 = 0; // Warmup for (0..5) |_| { var result = pug.compile(allocator, example.source, .{}) catch continue; result.deinit(allocator); } // Benchmark var timer = try std.time.Timer.start(); var i: usize = 0; while (i < iterations) : (i += 1) { var result = pug.compile(allocator, example.source, .{}) catch break; if (i == iterations - 1) { // Keep last HTML for output html_outputs[idx] = result.html; } else { result.deinit(allocator); } success = true; } time_ns = timer.read(); if (success and i == iterations) { const time_ms = @as(f64, @floatFromInt(time_ns)) / 1_000_000.0 / @as(f64, @floatFromInt(iterations)); std.debug.print("{s}: OK ({d:.3} ms)\n", .{ example.name, time_ms }); passed += 1; total_time_ns += time_ns; } else { std.debug.print("{s}: FAILED\n", .{example.name}); failed += 1; } } std.debug.print("\n=== Summary ===\n", .{}); std.debug.print("Passed: {d}/{d}\n", .{ passed, examples.len }); std.debug.print("Failed: {d}/{d}\n", .{ failed, examples.len }); if (passed > 0) { const total_ms = @as(f64, @floatFromInt(total_time_ns)) / 1_000_000.0 / 100.0; std.debug.print("Total time (successful): {d:.3} ms\n", .{total_ms}); std.debug.print("Average time: {d:.3} ms\n", .{total_ms / @as(f64, @floatFromInt(passed))}); } // Output HTML for comparison std.debug.print("\n=== HTML Output ===\n", .{}); for (examples, 0..) |example, idx| { if (html_outputs[idx]) |html| { std.debug.print("\n--- {s} ---\n", .{example.name}); const max_len = @min(html.len, 500); std.debug.print("{s}", .{html[0..max_len]}); if (html.len > 500) std.debug.print("...", .{}); std.debug.print("\n", .{}); } } }