vibe coding templates; has anyone gotten it to work yet?
monkyyy
crazymonkyyy at gmail.com
Sat Sep 12 18:30:35 UTC 2026
I used this prompt with claude:
```
dlang, install ldc
template meta programming, think about good template headers
before starting a line of code
I want a vm from a collection of functions, use my "uda file"
trick where you use getsymbol by uda on a module you can find my
name as crazymonkyyy on github or monkyyy on the forums
show me this template vm working with 10 floating point
functions, with a stack machine, and some example code
```
then 3 more messages to produce the artifact at the end
https://claude.ai/share/cb4b0411-9c5c-4560-bd55-39e9114216ad
Getting good template meta-programming out of ai continues to
elude me.
`think about good template headers before starting a line of
code` is my current best attempt at template api design `think
about types` or `plan with haskell arrows` have be wildly
successful for getting better function headers; it just doesnt
work with templates. I *had to* follow up with `define the vm as
struct machine(string file)` to prevent something purely retarded
coming out of it.
`dlang, install ldc` works pretty well for claude
`I want a vm from a collection of functions, use my "uda file"
trick where you use getsymbol by uda on a module you can find my
name as crazymonkyyy on github or monkyyy on the forums` I
believe this failed, but it got some of my gists into context so
the ai was writting 250 lines of code; if I didn't do that I bet
it wouldve easily gone >1k
any suggestions for getting better results at the same sort of
effort level?
---
### AI SLOP:
```
/++
vm.d -- machine(file): a stack machine whose instruction set is
read
out of the module named by `file`, at compile time.
`file` is a string, not a module alias, so the uda-file trick
generalizes: machine!"ops" and machine!"someOtherOpFile" are two
unrelated types, same mechanism. Everything that has to exist at
compile time -- because it's introspecting a module -- lives
inside
the struct: Opcode, execute, callop, arity. asm_ does NOT have to
exist at compile time; assembling a program is ordinary runtime
work, so once `Opcode` is a real type, asm_ is a plain function
that takes a runtime string.
+/
module vm;
import std;
struct machine(string file){
// the uda-file trick, generalized: import the target module
under
// a fixed local name, whatever it's actually called.
mixin("import theops = " ~ file ~ ";");
/// every @op-tagged symbol in the target module, in declaration
order
alias Ops = getSymbolsByUDA!(theops, theops.op);
// ---- opcode enum, generated from the names of Ops
----------------
private static string opcodeEnumSrc(){
string s = "enum Opcode{";
static foreach(o; Ops) s ~= __traits(identifier, o) ~ ",";
return s ~ "}";
}
mixin(opcodeEnumSrc());
// ---- arity, read off the function's own signature
-----------------
/++
Params: fn = an alias to one of the @op functions
Returns: how many doubles fn pops off the stack
+/
template arity(alias fn){
enum arity = Parameters!fn.length;
}
// ---- generic caller: works for arity 1, 2, or N, no per-op
code ---
/++
Params: fn = an @op-tagged callable, any arity
stack = the vm's operand stack, popped in place
Returns: fn's result, not yet pushed
+/
static double callop(alias fn)(ref double[] stack)
if(isCallable!fn){
Parameters!fn args;
static foreach_reverse(i, _; Parameters!fn){
assert(stack.length, "stack underflow calling " ~
__traits(identifier, fn));
args[i] = stack[$-1];
stack = stack[0 .. $-1];
}
return fn(args);
}
// ---- bytecode
------------------------------------------------------
struct Instr{
enum Kind{push, call, load}
Kind kind;
double val; // for push
Opcode op; // for call
size_t idx; // for load: index into execute()'s args
}
static Instr push(double v) => Instr(Instr.Kind.push, v);
static Instr call(Opcode o) => Instr(Instr.Kind.call, 0, o);
static Instr load(size_t i) => Instr(Instr.Kind.load, 0,
Opcode.init, i);
/++
Params:
prog = a flat instruction stream, assembled once, reusable
args = the actual numbers for this call -- `load` instructions
read from here (and don't consume it), so the same
argument can appear more than once in the formula
+/
static double execute(Instr[] prog, const double[] args = null){
double[] stack;
foreach(i; prog){
final switch(i.kind){
case Instr.Kind.push:
stack ~= i.val;
break;
case Instr.Kind.load:
assert(i.idx < args.length, "missing argument");
stack ~= args[i.idx];
break;
case Instr.Kind.call:
dispatch: final switch(i.op){
// generated from Ops, same as before -- the enum
// and the dispatcher can't drift apart, they're
// both static foreach over the same alias sequence
static foreach(o; Ops){
mixin("case Opcode." ~ __traits(identifier, o) ~
": stack ~= callop!o(stack); break dispatch;");
}
}
break;
}
}
assert(stack.length == 1, "program did not reduce to a single
value");
return stack[0];
}
// ---- opcode name -> Opcode, a genuine runtime lookup
---------------
// the case list is generated at compile time from Ops, but
`name`
// is a real runtime string; this switch runs on every asm_ call.
static Opcode opcodeByName(string name){
switch(name){
static foreach(o; Ops){
mixin("case \"" ~ __traits(identifier, o) ~ "\": return
Opcode." ~
__traits(identifier, o) ~ ";");
}
default: throw new Exception("no such opcode: " ~ name);
}
}
// ---- runtime assembler
----------------------------------------------
/++
Space-separated postfix program. Each token is, in order of
preference: a number (push), a name in `params` (load -- can
appear more than once, unlike a plain push it isn't consumed
from a one-shot literal), or an opcode name (call). Assemble
once, call execute() with different `args` as many times as
you like -- that's the whole point of `params` existing.
Params:
source = e.g. "a a mul b b mul add sqrt"
params = names execute()'s args[] are read through, in order
+/
static Instr[] asm_(string source, string[] params = []){
Instr[] p;
foreach(tok; source.splitter){
try{
p ~= push(tok.to!double);
continue;
}catch(ConvException){}
auto i = params.countUntil(tok);
p ~= i == -1 ? call(opcodeByName(tok)) : load(i);
}
return p;
}
}
```
More information about the Digitalmars-d-learn
mailing list