@@ -238,23 +238,105 @@ fn void Generator.emitStmt(Generator* gen, Stmt* s, u32 indent, bool newline) {
238238 break;
239239 case Assert:
240240 if (!gen.enable_asserts) break;
241+ gen.emitAssertStmt(cast<AssertStmt*>(s), indent);
242+ break;
243+ }
244+ }
241245
242- AssertStmt* a = cast<AssertStmt*>(s);
243- source_mgr.Location loc = gen.sm.locate(s.getLoc());
244- const char* funcname = gen.cur_function.asDecl().getFullName();
245-
246- out.add1('(');
247- Expr* inner = a.getInner();
248- gen.emitExpr(out, inner);
249- out.print(") || c2_assert(\"%s\", %d, \"%s\", \"", loc.filename, loc.line, funcname);
250- // encode expression as a string
251- string_buffer.Buf* str = string_buffer.create(128, false, 0);
252- inner.printLiteral(str);
253- out.encodeBytes(str.data(), str.size(), '"');
254- str.free();
255- out.add("\");\n");
246+ fn const char* get_type_format(Expr* e) {
247+ QualType qt = e.getType();
248+ QualType canon = qt.getCanonicalType();
249+ if (canon.isPointer() || canon.isFunction()) return "p";
250+ const Type* t = canon.getTypeOrNil();
251+ if (canon.isEnum()) {
252+ // output numeric value
253+ EnumType* et = (EnumType*)t;
254+ canon = et.getImplType();
255+ t = canon.getTypeOrNil();
256+ }
257+ const BuiltinType* bi = (BuiltinType*)t;
258+ switch (bi.getBaseKind()) {
259+ case Char:
260+ case Int8:
261+ case Int16:
262+ case Int32:
263+ return "d";
264+ case Int64:
265+ return "ld";
266+ case UInt8:
267+ case UInt16:
268+ case UInt32:
269+ return "u";
270+ case UInt64:
271+ return "lu";
272+ case Float32:
273+ case Float64:
274+ return "g";
275+ case Bool:
276+ return "d";
277+ case ISize: // not a base kind
278+ case USize: // not a base kind
279+ case Void:
256280 break;
257281 }
282+ return nil;
283+ }
284+
285+ // encode expression as a string
286+ fn void encode_expression(string_buffer.Buf* out, Expr* e) {
287+ char[128] tmp;
288+ string_buffer.Buf buf.init(tmp, elemsof(tmp), false, false, 0);
289+ e.printLiteral(&buf);
290+ const char* s = buf.data();
291+ for (const char* p = s;; p++) {
292+ if (!*p || *p == '%') {
293+ out.encodeBytes(s, (u32)(p - s), '"');
294+ if (!*p) break;
295+ if (*p == '%') out.add("%%");
296+ }
297+ }
298+ }
299+
300+ fn void Generator.emitAssertStmt(Generator* gen, AssertStmt* a, u32 indent) {
301+ string_buffer.Buf* out = gen.out;
302+ source_mgr.Location loc = gen.sm.locate(((Stmt*)a).getLoc());
303+ const char* funcname = gen.cur_function.asDecl().getFullName();
304+ Expr* inner = a.getInner();
305+ out.add1('(');
306+ gen.emitExpr(out, inner);
307+ out.print(") || c2_assert(\"%s\", %d, \"%s\", \"", loc.filename, loc.line, funcname);
308+ encode_expression(out, inner);
309+ if (inner.isComparison()) {
310+ BinaryOperator* b = (BinaryOperator*)inner;
311+ Expr* lhs = b.getLHS();
312+ Expr* rhs = b.getRHS();
313+ const char* fmt1 = lhs.isLiteral() ? nil : get_type_format(lhs);
314+ const char* fmt2 = rhs.isLiteral() ? nil : get_type_format(rhs);
315+ if (fmt1) {
316+ out.print(", ");
317+ encode_expression(out, lhs);
318+ out.print(": %%%s", fmt1);
319+ }
320+ if (fmt2) {
321+ out.print(", ");
322+ encode_expression(out, rhs);
323+ out.print(": %%%s", fmt2);
324+ }
325+ out.add1('"');
326+ if (fmt1) {
327+ out.add(", ");
328+ if (*fmt1 == 'p') out.add("(void*)");
329+ gen.emitExpr(out, lhs);
330+ }
331+ if (fmt2) {
332+ out.add(", ");
333+ if (*fmt2 == 'p') out.add("(void*)");
334+ gen.emitExpr(out, rhs);
335+ }
336+ } else {
337+ out.add1('"');
338+ }
339+ out.add(");\n");
258340}
259341
260342fn void emitAsmPart(string_buffer.Buf* out, bool multi_line, u32 indent) {
0 commit comments