Custom label level types can be useful to make sure that the xyz.init and xyz.end macros like sb.init and sb.end match. For example:
// '#block' must be ended with a '#endblock', otherwise the compiler will complain.
// This makes sure that 'sb.init' must be ended with a 'sb.end'.
// Create a string builder.
macro sb.init
#block !!sb.block
memory _sb.array_ sizeof(ptr) in
memory _sb.ptr_ sizeof(ptr) in
_sb.array_ _sb.ptr_ string-builder.init
endmacro
// Dump the contents to a stream and deallocate the string builder.
macro sb.end // file-desc: stream-to-dump
let stream in
// Dump the generated string.
_sb.array_ _sb.ptr_ string-builder.to-array stream fputs
// Deallocate the string builder object.
_sb.array_ @64 mfree drop
end
end end
#endblock !!sb.block
endmacro
// This is fine.
sb.init
"hello, world!\n" sb.add-str
STDOUT sb.end
// This is not fine, `sb.end` ends `if`.
sb.init
x 2 > if
STDOUT sb.end
end
Custom label level types can be useful to make sure that the
xyz.init
andxyz.end
macros likesb.init
andsb.end
match. For example: