This source file includes following definitions.
- potion_closure_new
- potion_closure_code
- potion_closure_string
- potion_closure_arity
- potion_closure_minargs
- potion_sig_arity
- potion_sig_minargs
- potion_sig_at
- potion_sig_name_at
- potion_no_call
- potion_add_metaclass
- potion_type_new
- potion_type_new2
- potion_type_call_is
- potion_obj_get_call
- potion_type_callset_is
- potion_obj_get_callset
- potion_type_constructor_is
- potion_class
- potion_class_find
- potion_class_type
- potion_ivars
- potion_obj_find_ivar
- potion_obj_get
- potion_obj_set
- potion_proto_method
- potion_getter_method
- potion_def_method
- potion_lookup
- potion_bind
- potion_message
- potion_obj_add
- potion_obj_sub
- potion_obj_mult
- potion_obj_div
- potion_obj_rem
- potion_obj_bitn
- potion_obj_bitl
- potion_obj_bitr
- potion_ref
- potion_ref_string
- potion_object_string
- potion_object_forward
- potion_object_send
- potion_object_new
- potion_object_size
- potion_get_metaclass
- potion_lobby_self
- potion_lobby_string
- potion_lobby_kind
- potion_lobby_can
- potion_lobby_print
- potion_lobby_say
- potion_init_class_reference
- potion_define_global
- potion_about
- potion_exit
- potion_object_init
- potion_lobby_init
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include "p2.h"
#include "internal.h"
#include "khash.h"
#include "table.h"
#include "asm.h"
PN potion_closure_new(Potion *P, PN_F meth, PN sig, PN_SIZE extra) {
PN_SIZE i; PN cr;
vPN(Closure) c = PN_ALLOC_N(PN_TCLOSURE, struct PNClosure, extra * sizeof(PN));
c->method = meth;
if (PN_IS_TUPLE(sig) && PN_TUPLE_LEN(sig) > 0) {
c->sig = sig;
c->arity = potion_sig_arity(P, sig);
c->minargs = potion_sig_minargs(P, sig);
} else {
c->sig = PN_NIL;
c->arity = 0;
c->minargs = 0;
}
c->extra = extra;
for (i = 0; i < c->extra; i++)
c->data[i] = PN_NIL;
cr = (PN)c;
return cr;
}
PN potion_closure_code(Potion *P, PN cl, PN self) {
if (PN_CLOSURE(self)->extra > 0 && PN_IS_PROTO(PN_CLOSURE(self)->data[0]))
return PN_CLOSURE(self)->data[0];
return PN_NIL;
}
PN potion_closure_string(Potion *P, PN cl, PN self, PN maxlen) {
#ifdef P2
# define FUNCNAME "sub"
#else
# define FUNCNAME "function"
#endif
PN out = potion_byte_str(P, FUNCNAME);
if (PN_CLOSURE(self)->name)
pn_printf(P, out, " %s", PN_STR_PTR(PN_CLOSURE(self)->name));
pn_printf(P, out, "(");
potion_bytes_obj_string(P, out, potion_sig_string(P,cl,PN_CLOSURE(self)->sig));
pn_printf(P, out, ")");
return PN_STR_B(out);
}
PN potion_closure_arity(Potion *P, PN cl, PN self) {
return PN_NUM(PN_CLOSURE(self)->arity);
}
PN potion_closure_minargs(Potion *P, PN cl, PN self) {
return PN_NUM(PN_CLOSURE(self)->minargs);
}
int potion_sig_arity(Potion *P, PN sig) {
if (PN_IS_TUPLE(sig)) {
int count = 0;
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd(sig);
if (t->len != 0) {
PN_SIZE i;
for (i = 0; i < t->len; i++) {
PN v = (PN)t->set[i];
if (PN_IS_STR(v)) count++;
if (PN_IS_NUM(v) && v == PN_NUM(':') && PN_IS_STR((PN)t->set[i+1])) count--;
}
}
return count;
}
else if (sig == PN_NIL)
return 0;
else {
potion_fatal("Invalid signature type for sig_arity");
return 0;
}
}
int potion_sig_minargs(Potion *P, PN sig) {
if (PN_IS_TUPLE(sig)) {
int count = 0;
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd(sig);
if (t->len != 0) {
PN_SIZE i;
for (i = 0; i < t->len; i++) {
PN v = (PN)t->set[i];
if (PN_IS_STR(v)) count++;
if (PN_IS_NUM(v) && v == PN_NUM('|')) break;
if (PN_IS_NUM(v) && v == PN_NUM(':')) { count--; break; }
}
}
return count;
}
else if (sig == PN_NIL)
return 0;
else {
potion_fatal("wrong sig type for sig_minargs");
return 0;
}
}
PN potion_sig_at(Potion *P, PN sig, int index) {
PN result = PN_NIL;
if (PN_IS_TUPLE(sig)) {
int count = -1;
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd(sig);
if (t->len > 0) {
PN_SIZE i;
for (i = 0; i < t->len; i++) {
PN v = (PN)t->set[i];
if (PN_IS_STR(v)) count++;
if (PN_IS_NUM(v) && v == PN_NUM(':') && PN_IS_STR((PN)t->set[i+1])) count--;
if (count == index) {
result = potion_tuple_new(P, v);
if (i+1 < t->len && PN_IS_NUM((PN)t->set[i+1])) {
PN typ = (PN)t->set[i+1];
result = potion_tuple_push(P, result, typ);
if (i+2 < t->len && typ == PN_NUM(':'))
result = potion_tuple_push(P, result, (PN)t->set[i+2]);
}
return result;
}
}
}
return result;
}
else if (sig == PN_NIL)
return result;
else {
potion_fatal("wrong sig type for sig_at");
return 0;
}
}
PN potion_sig_name_at(Potion *P, PN sig, int index) {
if (PN_IS_TUPLE(sig)) {
int count = -1;
struct PNTuple * volatile t = (struct PNTuple *)potion_fwd(sig);
if (t->len > 0) {
PN_SIZE i;
for (i = 0; i < t->len; i++) {
PN v = (PN)t->set[i];
if (PN_IS_STR(v)) count++;
if (PN_IS_NUM(v) && v == PN_NUM(':') && PN_IS_STR((PN)t->set[i+1])) count--;
if (count == index)
return v;
}
}
return 0;
}
else if (sig == PN_NIL)
return 0;
else {
potion_fatal("wrong sig type for sig_at");
return 0;
}
}
PN potion_no_call(Potion *P, PN cl, PN self) {
return self;
}
void potion_add_metaclass(Potion *P, vPN(Vtable) vt) {
struct PNVtable *meta = vt->meta = PN_CALLOC_N(PN_TVTABLE, struct PNVtable, 0);
meta->type = PN_FLEX_SIZE(P->vts) + PN_TNIL;
PN_FLEX_NEEDS(1, P->vts, PN_TFLEX, PNFlex, TYPE_BATCH_SIZE);
PN_FLEX_SIZE(P->vts)++;
meta->name = PN_NIL;
meta->parent = PN_TVTABLE;
meta->methods = (struct PNTable *)potion_table_empty(P);
meta->ctor = PN_FUNC(potion_no_call, 0);
PN_VTABLE(meta->type) = (PN)meta;
meta->meta = PN_NIL;
PN_TOUCH(P->vts);
}
PN potion_type_new(Potion *P, PNType t, PN self) {
vPN(Vtable) vt = PN_CALLOC_N(PN_TVTABLE, struct PNVtable, 0);
vt->type = t;
vt->name = PN_NIL;
vt->parent = self ? ((struct PNVtable *)self)->type : 0;
vt->methods = (struct PNTable *)potion_table_empty(P);
vt->ctor = PN_FUNC(potion_no_call, 0);
PN_VTABLE(t) = (PN)vt;
potion_add_metaclass(P, vt);
return (PN)vt;
}
PN potion_type_new2(Potion *P, PNType t, PN self, PN name) {
vPN(Vtable) vt = (vPN(Vtable))potion_type_new(P, t, self);
vt->name = name;
return (PN)vt;
}
void potion_type_call_is(PN vt, PN cl) {
((struct PNVtable *)vt)->call = cl;
}
PN potion_obj_get_call(Potion *P, PN obj) {
PN cl = ((struct PNVtable *)PN_VTABLE(PN_TYPE(obj)))->call;
if (cl == PN_NIL) cl = P->call;
return cl;
}
void potion_type_callset_is(PN vt, PN cl) {
((struct PNVtable *)vt)->callset = cl;
}
PN potion_obj_get_callset(Potion *P, PN obj) {
PN cl = ((struct PNVtable *)PN_VTABLE(PN_TYPE(obj)))->callset;
if (cl == PN_NIL) cl = P->callset;
return cl;
}
void potion_type_constructor_is(PN vt, PN cl) {
((struct PNVtable *)vt)->ctor = cl;
}
PN potion_class(Potion *P, PN cl, PN self, PN ivars) {
PN parent = ((!self || self == P->lobby) ? PN_VTABLE(PN_TOBJECT) : self);
PN pvars = ((struct PNVtable *)parent)->ivars;
PNType t = PN_FLEX_SIZE(P->vts) + PN_TNIL;
PN_FLEX_NEEDS(1, P->vts, PN_TFLEX, PNFlex, TYPE_BATCH_SIZE);
PN_FLEX_SIZE(P->vts)++;
self = potion_type_new(P, t, parent);
if (PN_IS_TUPLE(pvars)) {
if (!PN_IS_TUPLE(ivars)) ivars = PN_TUP0();
PN_TUPLE_EACH(pvars, i, v, {PN_PUT(ivars, v);});
}
if (PN_IS_TUPLE(ivars))
potion_ivars(P, PN_NIL, self, ivars);
if (!PN_IS_CLOSURE(cl))
cl = ((struct PNVtable *)parent)->ctor;
((struct PNVtable *)self)->ctor = cl;
PN_TOUCH(P->vts);
return self;
}
PN potion_class_find(Potion *P, PN name) {
int i;
for (i=0; i < PN_FLEX_SIZE(P->vts); i++) {
vPN(Vtable) vt = (struct PNVtable *)PN_FLEX_AT(P->vts, i);
if (vt && vt->name == name)
return (PN)vt;
}
return PN_NIL;
}
PNType potion_class_type(Potion *P, PN class) {
struct PNVtable *vt = (struct PNVtable *)potion_fwd(class);
return vt->type;
}
PN potion_ivars(Potion *P, PN cl, PN self, PN ivars) {
struct PNVtable *vt = (struct PNVtable *)self;
#ifdef POTION_JIT_TARGET
PNAsm * volatile asmb = potion_asm_new(P);
P->target.ivars(P, ivars, &asmb);
vt->ivfunc = (PN_IVAR_FUNC)PN_ALLOC_FUNC(asmb->len);
PN_MEMCPY_N(vt->ivfunc, asmb->ptr, u8, asmb->len);
#endif
vt->ivlen = PN_TUPLE_LEN(ivars);
vt->ivars = ivars;
return self;
}
static inline long potion_obj_find_ivar(Potion *P, PN self, PN ivar) {
PNType t = PN_TYPE(self);
vPN(Vtable) vt = (struct PNVtable *)PN_VTABLE(t);
if (vt->ivfunc != NULL)
return vt->ivfunc(PN_UNIQ(ivar));
if (t > PN_TUSER) {
PN ivars = ((struct PNVtable *)PN_VTABLE(t))->ivars;
if (ivars != PN_NIL) {
PN found = potion_tuple_bsearch(P, 0, ivars, ivar);
return found == PN_FALSE ? -1 : found;
}
}
return -1;
}
PN potion_obj_get(Potion *P, PN cl, PN self, PN ivar) {
long i = potion_obj_find_ivar(P, self, ivar);
if (i >= 0)
return ((struct PNObject *)self)->ivars[i];
return PN_NIL;
}
PN potion_obj_set(Potion *P, PN cl, PN self, PN ivar, PN value) {
long i = potion_obj_find_ivar(P, self, ivar);
if (i >= 0) {
((struct PNObject *)self)->ivars[i] = value;
PN_TOUCH(self);
}
return value;
}
PN potion_proto_method(Potion *P, PN cl, PN self, PN args) {
return potion_vm(P, PN_CLOSURE(cl)->data[0], P->lobby, args, 0, NULL);
}
PN potion_getter_method(Potion *P, PN cl, PN self) {
return PN_CLOSURE(cl)->data[0];
}
PN potion_def_method(Potion *P, PN closure, PN self, PN key, PN method) {
int ret;
PN cl;
vPN(Vtable) vt = (struct PNVtable *)self;
unsigned k = kh_put(PN, vt->methods, key, &ret);
PN_QUICK_FWD(struct PNTable *, vt->methods);
PN_TOUCH(vt->methods);
if (!PN_IS_CLOSURE(method)) {
if (PN_IS_PROTO(method)) {
cl = potion_closure_new(P, (PN_F)potion_proto_method, PN_PROTO(method)->sig, 1);
PN_PROTO(method)->name = key;
}
else
cl = potion_closure_new(P, (PN_F)potion_getter_method, PN_NIL, 1);
PN_CLOSURE(cl)->data[0] = method;
PN_CLOSURE(cl)->name = key;
method = cl;
}
else
PN_CLOSURE(method)->name = key;
kh_val(PN, vt->methods, k) = method;
PN_TOUCH(self);
#ifdef JIT_MCACHE
if (P->target.mcache != NULL) {
PNAsm * volatile asmb = potion_asm_new(P);
P->target.mcache(P, vt, &asmb);
if (asmb->len <= 4096) {
if (vt->mcache == NULL)
vt->mcache = PN_ALLOC_FUNC(4096);
PN_MEMCPY_N(vt->mcache, asmb->ptr, u8, asmb->len);
} else if (vt->mcache != NULL) {
potion_munmap(vt->mcache, 4096);
vt->mcache = NULL;
}
}
#endif
return method;
}
PN potion_lookup(Potion *P, PN closure, PN self, PN key) {
vPN(Vtable) vt = (struct PNVtable *)self;
#ifdef JIT_MCACHE
if (vt->mcache != NULL)
return vt->mcache(PN_UNIQ(key));
#endif
unsigned k = kh_get(PN, vt->methods, key);
if (k != kh_end(vt->methods)) return kh_val(PN, vt->methods, k);
return PN_NIL;
}
PN potion_bind(Potion *P, PN rcv, PN msg) {
PN closure = PN_NIL;
PN vt = PN_NIL;
PNType t = PN_TYPE(rcv);
if (!PN_TYPECHECK(t)) return PN_NIL;
if (t == PN_TVTABLE && !PN_IS_METACLASS(rcv)) {
vt = (PN)((struct PNVtable *)rcv)->meta;
} else {
vt = PN_VTABLE(t);
}
while (1) {
closure = ((msg == PN_lookup) && (t == PN_TVTABLE))
? potion_lookup(P, 0, vt, msg)
: potion_send(vt, PN_lookup, msg);
if (closure || !((struct PNVtable *)vt)->parent) break;
vt = PN_VTABLE(((struct PNVtable *)vt)->parent);
}
return closure;
}
PN potion_message(Potion *P, PN rcv, PN msg) {
PN cl = potion_bind(P, rcv, msg);
if (PN_IS_CLOSURE(cl) && PN_CLOSURE(cl)->sig == PN_NIL)
return PN_CLOSURE(cl)->method(P, cl, rcv, PN_NIL);
return cl;
}
PN potion_obj_add(Potion *P, PN a, PN b) {
return potion_send(a, PN_add, b);
}
PN potion_obj_sub(Potion *P, PN a, PN b) {
return potion_send(a, PN_sub, b);
}
PN potion_obj_mult(Potion *P, PN a, PN b) {
return potion_send(a, PN_mult, b);
}
PN potion_obj_div(Potion *P, PN a, PN b) {
return potion_send(a, PN_div, b);
}
PN potion_obj_rem(Potion *P, PN a, PN b) {
return potion_send(a, PN_rem, b);
}
PN potion_obj_bitn(Potion *P, PN a) {
return potion_send(a, PN_bitn);
}
PN potion_obj_bitl(Potion *P, PN a, PN b) {
return potion_send(a, PN_bitl, b);
}
PN potion_obj_bitr(Potion *P, PN a, PN b) {
return potion_send(a, PN_bitr, b);
}
PN potion_ref(Potion *P, PN data) {
if (PN_IS_REF(data)) return data;
vPN(WeakRef) ref = PN_ALLOC(PN_TWEAK, struct PNWeakRef);
ref->data = data;
return (PN)ref;
}
PN potion_ref_string(Potion *P, PN cl, PN self, PN len) {
return potion_str(P, "<ref>");
}
PN potion_object_string(Potion *P, PN cl, vPN(Object) self) {
struct PNVtable *vt = (struct PNVtable *)PN_VTABLE(self->vt);
if (vt->name != PN_NIL) {
PN str = potion_byte_str2(P, NULL, 0);
pn_printf(P, str, "<%s %lx>", PN_STR_PTR(vt->name), (PN)self);
return potion_send(str, PN_string);
}
return potion_str(P, "<object>");
}
PN potion_object_forward(Potion *P, PN cl, PN self, PN method) {
printf("#<object>");
return PN_NIL;
}
PN potion_object_send(Potion *P, PN cl, PN self, PN method) {
return potion_send(self, method);
}
PN potion_object_new(Potion *P, PN cl, PN self) {
vPN(Vtable) vt = (struct PNVtable *)self;
if (PN_IS_METACLASS(vt))
return PN_NIL;
if (vt->type == PN_TVTABLE)
return PN_NIL;
return (PN)PN_ALLOC_N(vt->type, struct PNObject,
potion_type_size(P, (struct PNObject *)self) - sizeof(struct PNObject) + vt->ivlen * sizeof(PN));
}
PN potion_object_size(Potion *P, PN cl, PN self) {
vPN(Object) obj = (struct PNObject *)self;
return sizeof(struct PNObject) + (((struct PNVtable *)PN_VTABLE(obj->vt))->ivlen * sizeof(PN));
}
PN potion_get_metaclass(Potion *P, PN cl, vPN(Vtable) self) {
return (PN)self->meta;
}
static PN potion_lobby_self(Potion *P, PN cl, PN self) {
return self;
}
PN potion_lobby_string(Potion *P, PN cl, PN self) {
PN str = ((struct PNVtable *)self)->name;
return (void *)str != PN_NIL ? str :
PN_IS_METACLASS(self) ? potion_str(P, "<metaclass>") : potion_str(P, "<class>");
}
PN potion_lobby_kind(Potion *P, PN cl, PN self) {
PNType t = PN_TYPE(self);
if (!PN_TYPECHECK(t)) return PN_NIL;
return PN_VTABLE(t);
}
PN potion_lobby_can(Potion *P, PN cl, PN self, PN method) {
return potion_bind(P, self, method) ? PN_TRUE : PN_FALSE;
}
PN potion_lobby_print(Potion *P, PN cl, PN self) {
return potion_send(potion_send(self, PN_string), PN_print);
}
PN potion_lobby_say(Potion *P, PN cl, PN self) {
potion_send(potion_send(self, PN_string), PN_print);
printf("\n");
return PN_NIL;
}
static void potion_init_class_reference(Potion *P, PN name, PN vt) {
potion_send(P->lobby, PN_def, name, vt);
((struct PNVtable *)vt)->name = name;
char meta_str[strlen("<metaclass: >") + PN_STR_LEN(name) + 1];
sprintf(meta_str, "<metaclass: %s>", PN_STR_PTR(name));
((struct PNVtable *)vt)->meta->name = potion_str(P, meta_str);
}
void potion_define_global(Potion *P, PN name, PN val) {
if (PN_TYPE(val) == PN_TVTABLE && !PN_IS_METACLASS(val)) {
potion_init_class_reference(P, name, val);
} else {
potion_send(P->lobby, PN_def, name, val);
}
}
PN potion_about(Potion *P, PN cl, PN self) {
PN about = potion_table_empty(P);
potion_table_put(P, PN_NIL, about, potion_str(P, "_why"),
potion_str(P, "“I love _why, but learning Ruby from him is like trying to learn to pole vault "
"by having Salvador Dali punch you in the face.” - Steven Frank"));
potion_table_put(P, PN_NIL, about, potion_str(P, "minimalism"),
potion_str(P, "“The sad thing about ‘minimalism’ is that it has a name.” "
"- Steve Dekorte"));
potion_table_put(P, PN_NIL, about, potion_str(P, "stage fright"),
potion_str(P, "“Recently no move on Potion. I git pull everyday.” "
"- matz"));
potion_table_put(P, PN_NIL, about, potion_str(P, "terms of use"),
potion_str(P, "“Setting up my new anarchist bulletin board so that during registration, if you accept "
"the terms and conditions, you are banned forever.” - Dr. Casey Hall"));
potion_table_put(P, PN_NIL, about, potion_str(P, "help"),
potion_str(P, "`man which` - Evan Weaver"));
potion_table_put(P, PN_NIL, about, potion_str(P, "ts"),
potion_str(P, "“pigeon%” - Guy Decoux (1955 - 2008)"));
potion_table_put(P, PN_NIL, about, potion_str(P, "summary"),
potion_str(P, "“I smell as how a leprechaun looks.” - Alana Post"));
return about;
}
PN potion_exit(Potion *P, PN cl, PN self) {
potion_destroy(P);
exit(0);
}
void potion_object_init(Potion *P) {
PN clo_vt = PN_VTABLE(PN_TCLOSURE);
PN ref_vt = PN_VTABLE(PN_TWEAK);
PN obj_vt = PN_VTABLE(PN_TOBJECT);
potion_method(clo_vt, "code", potion_closure_code, 0);
potion_method(clo_vt, "string", potion_closure_string, 0);
potion_method(clo_vt, "arity", potion_closure_arity, 0);
potion_method(clo_vt, "minargs", potion_closure_minargs, 0);
potion_method(ref_vt, "string", potion_ref_string, 0);
potion_method(obj_vt, "forward", potion_object_forward, 0);
potion_method(obj_vt, "send", potion_object_send, 0);
potion_method(obj_vt, "string", potion_object_string, 0);
potion_method(obj_vt, "size", potion_object_size, 0);
}
# ifdef P2
# define LOBBY_NAME "P2"
# define NUMBER_NAME "Int"
# define STRING_NAME "Str"
# else
# define LOBBY_NAME "Lobby"
# define NUMBER_NAME "Number"
# define STRING_NAME "String"
# endif
void potion_lobby_init(Potion *P) {
potion_init_class_reference(P, potion_str(P, LOBBY_NAME), P->lobby);
potion_init_class_reference(P, potion_str(P, "Mixin"), PN_VTABLE(PN_TVTABLE));
potion_init_class_reference(P, potion_str(P, "Object"), PN_VTABLE(PN_TOBJECT));
potion_init_class_reference(P, potion_str(P, NILKIND_NAME), PN_VTABLE(PN_TNIL));
potion_init_class_reference(P, potion_str(P, NUMBER_NAME), PN_VTABLE(PN_TNUMBER));
potion_init_class_reference(P, potion_str(P, "Boolean"), PN_VTABLE(PN_TBOOLEAN));
potion_init_class_reference(P, potion_str(P, STRING_NAME), PN_VTABLE(PN_TSTRING));
potion_init_class_reference(P, potion_str(P, "Table"), PN_VTABLE(PN_TTABLE));
potion_init_class_reference(P, potion_str(P, "Function"), PN_VTABLE(PN_TCLOSURE));
potion_init_class_reference(P, potion_str(P, "Tuple"), PN_VTABLE(PN_TTUPLE));
potion_init_class_reference(P, potion_str(P, "File"), PN_VTABLE(PN_TFILE));
potion_init_class_reference(P, potion_str(P, "Potion"), PN_VTABLE(PN_TSTATE));
potion_init_class_reference(P, potion_str(P, "Source"), PN_VTABLE(PN_TSOURCE));
potion_init_class_reference(P, potion_str(P, "Bytes"), PN_VTABLE(PN_TBYTES));
potion_init_class_reference(P, potion_str(P, "Compiled"), PN_VTABLE(PN_TPROTO));
potion_init_class_reference(P, potion_str(P, "Ref"), PN_VTABLE(PN_TWEAK));
potion_init_class_reference(P, potion_str(P, "Lick"), PN_VTABLE(PN_TLICK));
potion_init_class_reference(P, potion_str(P, "Error"), PN_VTABLE(PN_TERROR));
potion_init_class_reference(P, potion_str(P, "Continuation"), PN_VTABLE(PN_TCONT));
potion_init_class_reference(P, potion_str(P, "Num"), PN_VTABLE(PN_TDECIMAL));
P->call = P->callset = PN_FUNC(potion_no_call, 0);
PN mixin_vt = PN_VTABLE(PN_TVTABLE);
potion_type_call_is(mixin_vt, PN_FUNC(potion_object_new, 0));
potion_method(mixin_vt, "meta", potion_get_metaclass, 0);
potion_method(P->lobby, "about", potion_about, 0);
#ifndef DISABLE_CALLCC
potion_method(P->lobby, "here", potion_callcc, 0);
#endif
potion_method(P->lobby, "exit", potion_exit, 0);
potion_method(P->lobby, "kind", potion_lobby_kind, 0);
potion_method(P->lobby, "srand", potion_srand, "seed=N");
potion_method(P->lobby, "rand", potion_rand, 0);
potion_method(P->lobby, "self", potion_lobby_self, 0);
potion_method(P->lobby, "string", potion_lobby_string, 0);
potion_method(P->lobby, "can", potion_lobby_can, "method=S");
potion_method(P->lobby, "print", potion_lobby_print, 0);
potion_method(P->lobby, "say", potion_lobby_say, 0);
}