import "../std/plugin.zc" include fn bf_transpile(body: char*, api: ZApi*) { let out = api.out; fputs(f"""{{ static unsigned char tape[30000] = {{0}}; unsigned char *ptr = tape; """, out); let idx = 0; while (body[idx] != 0) { let ch = body[idx]; match ch { '>' => fputs(" ++ptr;\n", out), '<' => fputs(" --ptr;\n", out), '+' => fputs(" ++*ptr;\n", out), '-' => fputs(" --*ptr;\n", out), '.' => fputs(" putchar(*ptr);\n", out), ',' => fputs(" *ptr = getchar();\n", out), '[' => fputs(f" while (*ptr) {{ \n", out), ']' => fputs(f" }} \n", out), _ => (void)0 } idx = idx + 1; } fputs(f"}} \n", out); } fn bf_hover(body: char*, line: int, col: int) -> char* { let p = body; let r = 0; let c = 0; // We don't skip newlines here to keep coordinate sync with ZLS while (p[0] != 0) { if (r == line && c == col) { match (int)p[0] { '>' => return "**:ptr++**: Increment the data pointer.", '<' => return "**:ptr--**: Decrement the data pointer.", '+' => return "**(*ptr)++**: Increment the byte at the data pointer.", '-' => return "**(*ptr)--**: Decrement the byte at the data pointer.", '.' => return "**:putchar**: Output the byte at the data pointer.", ',' => return "**:getchar**: Accept one byte of input, storing its value in the byte at the data pointer.", '[' => return "**:while(*ptr)**: If the byte at the data pointer is zero, jump forward to the command after the corresponding `]` command.", ']' => return "**:end-while**: If the byte at the data pointer is nonzero, jump back to the command after the corresponding `[` command.", _ => return NULL } } if (p[0] == 10) { r++; c = 0; } else { c++; } p = &p[1]; } return NULL; } let bf_plugin = ZPlugin { name: "brainfuck", handler: bf_transpile, hover_handler: bf_hover }; @export fn z_plugin_init() -> ZPlugin* { return &bf_plugin; }