Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
617 lines (420 sloc) 15.2 KB
/*
Copyright (C) 2006-2011, Parrot Foundation.
$Id$
=head1 Lua abstract base class
=head2 Description
C<LuaAny> provides an abstract base class for some Lua types.
=head3 PMC Inheritance Summary
Class Parents
-----------------------------------------------
LuaBoolean LuaAny, Default
LuaFunction Sub, LuaAny, Default
LuaNil LuaAny, Default
LuaNumber LuaAny, Default
LuaString LuaAny, Default
LuaTable LuaAny, Default
LuaThread LuaAny, Default
LuaUserdata LuaAny, Default
=head3 PMC "Attribute" Summary
Class Metatable Environment Userdata
accessor get_metatable getfenv get_attr_str (getattribute)
mutator set_metatable setfenv set_attr_str (setattribute)
default value nil nil NULL
------------------------------------------------------------------
LuaBoolean nil - -
LuaFunction nil yes -
LuaNil nil - -
LuaNumber nil - -
LuaString yes (common) - -
LuaTable yes - -
LuaThread nil yes -
LuaUserdata yes yes yes
The metatable supports the OO mecanism.
=head3 Methods
=over 4
=cut
*/
#include "lua_private.h"
PMC *
_LuaAny_find_meth(PARROT_INTERP, PMC *obj, const char *name) {
PMC *meta = PMCNULL;
const INTVAL type = PMC_type(obj);
if (type == dynpmc_LuaTable) {
meta = _LuaTable_get_metatable(interp, obj);
}
else if (type == dynpmc_LuaUserdata) {
meta = _LuaUserdata_get_metatable(interp, obj);
}
else if (type == dynpmc_LuaString) {
meta = _LuaString_get_metatable(interp);
}
if (PMC_IS_NULL(meta))
return PMCNULL;
if (dynpmc_LuaTable != PMC_type(meta)) {
return meta;
}
else {
PMC *method;
PMC * const key = Parrot_pmc_new(interp, dynpmc_LuaString);
VTABLE_set_string_native(interp, key, Parrot_str_new_constant(interp, name));
method = VTABLE_get_pmc_keyed(interp, meta, key);
return (dynpmc_LuaNil != PMC_type(method)) ? method : PMCNULL;
}
}
pmclass LuaAny
abstract
dynpmc
group lua_group
hll lua {
/*
=item C<INTVAL get_bool()>
Returns C<true>.
=cut
*/
VTABLE INTVAL get_bool() {
return (INTVAL)1;
}
/*
=item C<FLOATVAL get_number()>
Throws an exception.
=cut
*/
VTABLE FLOATVAL get_number() {
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
return 0.0;
}
/*
=item C<void assign_pmc(PMC *value)>
=cut
*/
VTABLE void assign_pmc(PMC *value) {
const INTVAL type = PMC_type(value);
if (PMC_type(SELF) != type)
Parrot_pmc_reuse(INTERP, SELF, type, 0);
if (type != dynpmc_LuaNil)
SELF.set_pmc(value);
}
/*
=item C<PMC* get_pmc_keyed(PMC *key)>
Throws an exception.
=cut
*/
VTABLE PMC* get_pmc_keyed(PMC *key) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__index");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to index a %Ss value", SELF.name());
if (dynpmc_LuaFunction == PMC_type(meth)) {
PMC * retval = PMCNULL;
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, key, &retval);
if (PMC_IS_NULL(retval))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return retval;
}
else
return VTABLE_get_pmc_keyed(INTERP, meth, key);
}
/*
=item C<void set_pmc_keyed(PMC* key, PMC* value)>
Throws an exception.
=cut
*/
VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__newindex");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to index a %Ss value", SELF.name());
if (dynpmc_LuaFunction == PMC_type(meth)) {
Parrot_ext_call(INTERP, meth, "PiPP->", SELF, key, value);
}
else
VTABLE_set_pmc_keyed(INTERP, meth, key, value);
}
/*
=item C<PMC* neg(PMC *dest)>
=item C<void i_neg()>
Throws an exception.
=cut
*/
VTABLE PMC* neg(PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__unm");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "Pi->P", SELF, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
VTABLE void i_neg() {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__unm");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "Pi->P", SELF, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
/*
=item C<void set_bool(INTVAL value)>
Common implementation
=cut
*/
VTABLE void set_bool(INTVAL value) {
Parrot_pmc_reuse(INTERP, SELF, dynpmc_LuaBoolean, 0);
SELF.set_bool(value);
}
/*
=item C<INTVAL defined()>
Always returns true.
=cut
*/
VTABLE INTVAL defined() {
return (INTVAL)1;
}
/*
=item C<void* invoke(void* next)>
Throws an exception.
=cut
*/
VTABLE opcode_t* invoke(void *next) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__call");
PMC *call_sig;
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to call a %Ss value", SELF.name());
call_sig = Parrot_pcc_get_signature(INTERP, CURRENT_CONTEXT(INTERP));
VTABLE_unshift_pmc(INTERP, call_sig, SELF);
return VTABLE_invoke(INTERP, meth, next);
}
/*
=back
=head3 non-Vtable Methods
=over 4
=item C<void add(PMC *value, PMC *dest)>
=item C<void i_add(PMC *value)>
=item C<void subtract(PMC *value, PMC *dest)>
=item C<void i_substract (PMC *value)>
=item C<void multiply(PMC *value, PMC *dest)>
=item C<void i_multiply(PMC *value)>
=item C<void divide(PMC *value, PMC *dest)>
=item C<void i_divide(PMC *value)>
=item C<PMC* modulus(PMC *value, PMC *dest)>
=item C<void i_modulus(PMC *value)>
=item C<PMC* concatenate(PMC *value, PMC *dest)>
=item C<void i_concatenate(PMC *value)>
Throws an exception.
=cut
*/
MULTI PMC* add(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__add");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_add(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__add");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
MULTI PMC* subtract(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__sub");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_subtract(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__sub");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
MULTI PMC* multiply(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__mul");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_multiply(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__mul");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
MULTI PMC* divide(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__div");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_divide(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__div");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
MULTI PMC* modulus(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__mod");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_modulus(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__mod");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to perform arithmetic on a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
MULTI PMC* concatenate(DEFAULT value, PMC *dest) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__concat");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to concatenate a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &dest);
if (PMC_IS_NULL(dest))
return Parrot_pmc_new(INTERP, dynpmc_LuaNil);
return dest;
}
MULTI void i_concatenate(DEFAULT value) {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__concat");
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to concatenate a %Ss value", SELF.name());
Parrot_ext_call(INTERP, meth, "PiP->P", SELF, value, &SELF);
if (PMC_IS_NULL(SELF))
SELF = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
/*
=item C<INTVAL is_equal(PMC *value)>
=cut
*/
MULTI INTVAL is_equal(DEFAULT value) {
return (INTVAL)0;
}
/*
=item C<INTVAL cmp(PMC *value)>
Performs a multiple dispatch call for 'cmp'.
Without shortcut like in Default PMC.
=cut
*/
VTABLE INTVAL cmp(PMC *value) {
INTVAL retval;
Parrot_mmd_multi_dispatch_from_c_args(INTERP,
"cmp", "PP->I", SELF, value, &retval);
return retval;
}
MULTI INTVAL cmp(DEFAULT value) {
STRING * const self_name = SELF.name();
STRING * const val_name = VTABLE_name(INTERP, value);
if (Parrot_str_compare(INTERP, self_name, val_name) != 0)
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to compare %Ss with %Ss", self_name, val_name);
else
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to compare two %Ss values", self_name);
}
/*
=back
=head3 Specific Methods
=over 4
=item C<PMC *get_metatable()>
=cut
*/
METHOD PMC* get_metatable() {
PMC * const nil = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
RETURN(PMC *nil);
}
/*
=item C<PMC* len()>
=cut
*/
METHOD PMC* len() {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__len");
PMC *retval;
if (PMC_IS_NULL(meth))
Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_ILL_INHERIT,
"attempt to get length of a %Ss value", SELF.name());
retval = PMCNULL;
Parrot_ext_call(INTERP, meth, "Pi->P", SELF, &retval);
if (PMC_IS_NULL(retval))
retval = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
RETURN(PMC *retval);
}
/*
=item C<PMC* tonumber()>
Returns C<nil>.
=cut
*/
METHOD PMC* tonumber() {
PMC * const nil = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
RETURN(PMC *nil);
}
/*
=item C<PMC* tostring()>
Return a Lua C<string>.
Common implementation (use C<__tostring> or C<get_string>).
=cut
*/
METHOD PMC* tostring() {
PMC * const meth = _LuaAny_find_meth(INTERP, SELF, "__tostring");
PMC *retval;
if (!PMC_IS_NULL(meth)) {
retval = PMCNULL;
Parrot_ext_call(INTERP, meth, "Pi->P", SELF, &retval);
if (PMC_IS_NULL(retval))
retval = Parrot_pmc_new(INTERP, dynpmc_LuaNil);
}
else {
retval = Parrot_pmc_new(INTERP, dynpmc_LuaString);
VTABLE_set_string_native(INTERP, retval, SELF.get_string());
}
RETURN(PMC *retval);
}
}
/*
=back
=cut
*/
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4:
*/