зеркало из https://github.com/mozilla/pjs.git
Fixed adding setter to virtual inherited field.
This commit is contained in:
Родитель
5fb5604727
Коммит
7b8898dcf1
|
@ -1613,6 +1613,16 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasAttribute(const IdentifierList* identifiers, StringAtom &name)
|
||||||
|
{
|
||||||
|
while (identifiers) {
|
||||||
|
if (identifiers->name == name)
|
||||||
|
return true;
|
||||||
|
identifiers = identifiers->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JSType *ICodeGenerator::extractType(ExprNode *t)
|
JSType *ICodeGenerator::extractType(ExprNode *t)
|
||||||
{
|
{
|
||||||
JSType* type = &Any_Type;
|
JSType* type = &Any_Type;
|
||||||
|
@ -1799,7 +1809,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||||
if (isStatic)
|
if (isStatic)
|
||||||
thisClass->defineStatic(idExpr->name, type);
|
thisClass->defineStatic(idExpr->name, type);
|
||||||
else {
|
else {
|
||||||
thisClass->defineSlot(idExpr->name, type);
|
if (hasAttribute(vs->attributes, mContext->getWorld().identifiers["virtual"]))
|
||||||
|
thisClass->defineSlot(idExpr->name, type, JSSlot::kIsVirtual);
|
||||||
|
else
|
||||||
|
thisClass->defineSlot(idExpr->name, type);
|
||||||
if (v->initializer)
|
if (v->initializer)
|
||||||
needsInstanceInitializer = true;
|
needsInstanceInitializer = true;
|
||||||
}
|
}
|
||||||
|
@ -1823,12 +1836,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||||
thisClass->defineStatic(name, &Function_Type);
|
thisClass->defineStatic(name, &Function_Type);
|
||||||
else {
|
else {
|
||||||
switch (f->function.prefix) {
|
switch (f->function.prefix) {
|
||||||
// XXXX these dummy place holders for the getters/setters are leaking
|
|
||||||
case FunctionName::Get:
|
case FunctionName::Get:
|
||||||
thisClass->setGetter(name, new JSFunction(), extractType(f->function.resultType));
|
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||||
break;
|
break;
|
||||||
case FunctionName::Set:
|
case FunctionName::Set:
|
||||||
thisClass->setSetter(name, new JSFunction(), extractType(f->function.resultType));
|
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||||
break;
|
break;
|
||||||
case FunctionName::normal:
|
case FunctionName::normal:
|
||||||
thisClass->defineMethod(name, NULL);
|
thisClass->defineMethod(name, NULL);
|
||||||
|
|
|
@ -710,6 +710,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||||
ICodeModule *icm = target->getICode();
|
ICodeModule *icm = target->getICode();
|
||||||
ArgumentList *args = op4(call);
|
ArgumentList *args = op4(call);
|
||||||
|
|
||||||
|
// if all the parameters are positional
|
||||||
|
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||||
|
|
||||||
// the parameter count includes 'this' and any named rest parameter
|
// the parameter count includes 'this' and any named rest parameter
|
||||||
//
|
//
|
||||||
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
||||||
|
|
|
@ -171,6 +171,15 @@ static JSValue load(Context *cx, const JSValues &argv)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool goGeorge = false;
|
||||||
|
|
||||||
|
static JSValue george(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
goGeorge = !goGeorge;
|
||||||
|
|
||||||
|
return JSValue(new JSString(goGeorge ? "George is going" : "George is taking a break"));
|
||||||
|
}
|
||||||
|
|
||||||
#if 0 // need a XP version of this, rip off from Monkey?
|
#if 0 // need a XP version of this, rip off from Monkey?
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
static JSValue time(Context *cx, const JSValues &argv)
|
static JSValue time(Context *cx, const JSValues &argv)
|
||||||
|
@ -189,7 +198,7 @@ class Tracer : public Context::Listener {
|
||||||
typedef InstructionStream::difference_type InstructionOffset;
|
typedef InstructionStream::difference_type InstructionOffset;
|
||||||
void listen(Context* context, Context::Event event)
|
void listen(Context* context, Context::Event event)
|
||||||
{
|
{
|
||||||
if (event & Context::EV_STEP) {
|
if (goGeorge && (event & Context::EV_STEP)) {
|
||||||
ICodeModule *iCode = context->getICode();
|
ICodeModule *iCode = context->getICode();
|
||||||
JSValues ®isters = context->getRegisters();
|
JSValues ®isters = context->getRegisters();
|
||||||
InstructionIterator pc = context->getPC();
|
InstructionIterator pc = context->getPC();
|
||||||
|
@ -212,7 +221,7 @@ class Tracer : public Context::Listener {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//#define HAVE_GEORGE_TRACE_IT
|
#define HAVE_GEORGE_TRACE_IT
|
||||||
//#define TEST_XML_LOADER
|
//#define TEST_XML_LOADER
|
||||||
|
|
||||||
static void readEvalPrint(FILE *in, World &world)
|
static void readEvalPrint(FILE *in, World &world)
|
||||||
|
@ -225,6 +234,7 @@ static void readEvalPrint(FILE *in, World &world)
|
||||||
global.defineNativeFunction(world.identifiers["print"], print);
|
global.defineNativeFunction(world.identifiers["print"], print);
|
||||||
global.defineNativeFunction(world.identifiers["dump"], dump);
|
global.defineNativeFunction(world.identifiers["dump"], dump);
|
||||||
global.defineNativeFunction(world.identifiers["load"], load);
|
global.defineNativeFunction(world.identifiers["load"], load);
|
||||||
|
global.defineNativeFunction(world.identifiers["george"], george);
|
||||||
// global.defineNativeFunction(world.identifiers["time"], time);
|
// global.defineNativeFunction(world.identifiers["time"], time);
|
||||||
|
|
||||||
String buffer;
|
String buffer;
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace JSClasses {
|
||||||
|
|
||||||
|
|
||||||
struct JSSlot {
|
struct JSSlot {
|
||||||
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
typedef enum { kNoFlag = 0, kIsConstructor = 0x01, kIsVirtual = 0x02 } SlotFlags; // <-- readonly, enumerable etc
|
||||||
|
|
||||||
// a slot may have a getter or a setter or both, but NOT either if mActual
|
// a slot may have a getter or a setter or both, but NOT either if mActual
|
||||||
JSType* mType;
|
JSType* mType;
|
||||||
|
@ -65,6 +65,7 @@ namespace JSClasses {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
||||||
|
bool isVirtual() const { return (mFlags & kIsVirtual) != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
|
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
|
||||||
|
@ -104,9 +105,12 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
if (superClass) {
|
if (superClass) {
|
||||||
// inherit superclass methods
|
// inherit superclass methods
|
||||||
JSMethods::iterator end = superClass->mMethods.end();
|
mMethods = JSMethods(superClass->mMethods);
|
||||||
for (JSMethods::iterator i = superClass->mMethods.begin(); i != end; i++)
|
// and virtual fields
|
||||||
mMethods.push_back(*i);
|
JSSlots::iterator sEnd = superClass->mSlots.end();
|
||||||
|
for (JSSlots::iterator si = superClass->mSlots.begin(); si != sEnd; si++)
|
||||||
|
if (si->second.isVirtual())
|
||||||
|
mSlots[si->first] = si->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,14 +124,14 @@ namespace JSClasses {
|
||||||
return mScope;
|
return mScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JSSlot& defineSlot(const String& name, JSType* type, JSFunction* getter = 0, JSFunction* setter = 0)
|
const JSSlot& defineSlot(const String& name, JSType* type, JSSlot::SlotFlags flags = JSSlot::kNoFlag, JSFunction* getter = 0, JSFunction* setter = 0)
|
||||||
{
|
{
|
||||||
JSSlot& slot = mSlots[name];
|
JSSlot& slot = mSlots[name];
|
||||||
ASSERT(slot.mType == 0);
|
|
||||||
slot.mType = type;
|
slot.mType = type;
|
||||||
slot.mIndex = mSlotCount++; // starts at 0.
|
slot.mIndex = mSlotCount++; // starts at 0.
|
||||||
slot.mSetter = setter;
|
slot.mSetter = setter;
|
||||||
slot.mGetter = getter;
|
slot.mGetter = getter;
|
||||||
|
slot.mFlags = flags;
|
||||||
if (setter || getter)
|
if (setter || getter)
|
||||||
slot.mActual = false;
|
slot.mActual = false;
|
||||||
return slot;
|
return slot;
|
||||||
|
@ -137,11 +141,13 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
JSSlots::iterator slti = mSlots.find(name);
|
JSSlots::iterator slti = mSlots.find(name);
|
||||||
if (slti == mSlots.end())
|
if (slti == mSlots.end())
|
||||||
defineSlot(name, type, getter, 0);
|
defineSlot(name, type, JSSlot::kNoFlag, getter, 0);
|
||||||
else {
|
else {
|
||||||
ASSERT(!slti->second.mActual);
|
if (slti->second.mActual)
|
||||||
|
ASSERT(slti->second.isVirtual());
|
||||||
ASSERT(slti->second.mGetter == 0);
|
ASSERT(slti->second.mGetter == 0);
|
||||||
slti->second.mGetter = getter;
|
slti->second.mGetter = getter;
|
||||||
|
slti->second.mActual = false;
|
||||||
}
|
}
|
||||||
mHasGetters = true;
|
mHasGetters = true;
|
||||||
}
|
}
|
||||||
|
@ -150,11 +156,14 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
JSSlots::iterator slti = mSlots.find(name);
|
JSSlots::iterator slti = mSlots.find(name);
|
||||||
if (slti == mSlots.end())
|
if (slti == mSlots.end())
|
||||||
defineSlot(name, type, 0, setter);
|
defineSlot(name, type, JSSlot::kNoFlag, 0, setter);
|
||||||
else {
|
else {
|
||||||
ASSERT(!slti->second.mActual);
|
JSSlot &s = slti->second;
|
||||||
ASSERT(slti->second.mSetter == 0);
|
if (s.mActual)
|
||||||
slti->second.mSetter = setter;
|
ASSERT(s.isVirtual());
|
||||||
|
ASSERT(s.mSetter == 0);
|
||||||
|
s.mSetter = setter;
|
||||||
|
s.mActual = false;
|
||||||
}
|
}
|
||||||
mHasSetters = true;
|
mHasSetters = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1613,6 +1613,16 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasAttribute(const IdentifierList* identifiers, StringAtom &name)
|
||||||
|
{
|
||||||
|
while (identifiers) {
|
||||||
|
if (identifiers->name == name)
|
||||||
|
return true;
|
||||||
|
identifiers = identifiers->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
JSType *ICodeGenerator::extractType(ExprNode *t)
|
JSType *ICodeGenerator::extractType(ExprNode *t)
|
||||||
{
|
{
|
||||||
JSType* type = &Any_Type;
|
JSType* type = &Any_Type;
|
||||||
|
@ -1799,7 +1809,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||||
if (isStatic)
|
if (isStatic)
|
||||||
thisClass->defineStatic(idExpr->name, type);
|
thisClass->defineStatic(idExpr->name, type);
|
||||||
else {
|
else {
|
||||||
thisClass->defineSlot(idExpr->name, type);
|
if (hasAttribute(vs->attributes, mContext->getWorld().identifiers["virtual"]))
|
||||||
|
thisClass->defineSlot(idExpr->name, type, JSSlot::kIsVirtual);
|
||||||
|
else
|
||||||
|
thisClass->defineSlot(idExpr->name, type);
|
||||||
if (v->initializer)
|
if (v->initializer)
|
||||||
needsInstanceInitializer = true;
|
needsInstanceInitializer = true;
|
||||||
}
|
}
|
||||||
|
@ -1823,12 +1836,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||||
thisClass->defineStatic(name, &Function_Type);
|
thisClass->defineStatic(name, &Function_Type);
|
||||||
else {
|
else {
|
||||||
switch (f->function.prefix) {
|
switch (f->function.prefix) {
|
||||||
// XXXX these dummy place holders for the getters/setters are leaking
|
|
||||||
case FunctionName::Get:
|
case FunctionName::Get:
|
||||||
thisClass->setGetter(name, new JSFunction(), extractType(f->function.resultType));
|
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||||
break;
|
break;
|
||||||
case FunctionName::Set:
|
case FunctionName::Set:
|
||||||
thisClass->setSetter(name, new JSFunction(), extractType(f->function.resultType));
|
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||||
break;
|
break;
|
||||||
case FunctionName::normal:
|
case FunctionName::normal:
|
||||||
thisClass->defineMethod(name, NULL);
|
thisClass->defineMethod(name, NULL);
|
||||||
|
|
|
@ -710,6 +710,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||||
ICodeModule *icm = target->getICode();
|
ICodeModule *icm = target->getICode();
|
||||||
ArgumentList *args = op4(call);
|
ArgumentList *args = op4(call);
|
||||||
|
|
||||||
|
// if all the parameters are positional
|
||||||
|
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||||
|
|
||||||
// the parameter count includes 'this' and any named rest parameter
|
// the parameter count includes 'this' and any named rest parameter
|
||||||
//
|
//
|
||||||
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
uint32 pCount = icm->itsParameters->size() - 1; // we won't be passing 'this' via the arg list array
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace JSClasses {
|
||||||
|
|
||||||
|
|
||||||
struct JSSlot {
|
struct JSSlot {
|
||||||
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
|
typedef enum { kNoFlag = 0, kIsConstructor = 0x01, kIsVirtual = 0x02 } SlotFlags; // <-- readonly, enumerable etc
|
||||||
|
|
||||||
// a slot may have a getter or a setter or both, but NOT either if mActual
|
// a slot may have a getter or a setter or both, but NOT either if mActual
|
||||||
JSType* mType;
|
JSType* mType;
|
||||||
|
@ -65,6 +65,7 @@ namespace JSClasses {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
|
||||||
|
bool isVirtual() const { return (mFlags & kIsVirtual) != 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
|
typedef gc_map_allocator(JSSlot) gc_slot_allocator;
|
||||||
|
@ -104,9 +105,12 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
if (superClass) {
|
if (superClass) {
|
||||||
// inherit superclass methods
|
// inherit superclass methods
|
||||||
JSMethods::iterator end = superClass->mMethods.end();
|
mMethods = JSMethods(superClass->mMethods);
|
||||||
for (JSMethods::iterator i = superClass->mMethods.begin(); i != end; i++)
|
// and virtual fields
|
||||||
mMethods.push_back(*i);
|
JSSlots::iterator sEnd = superClass->mSlots.end();
|
||||||
|
for (JSSlots::iterator si = superClass->mSlots.begin(); si != sEnd; si++)
|
||||||
|
if (si->second.isVirtual())
|
||||||
|
mSlots[si->first] = si->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,14 +124,14 @@ namespace JSClasses {
|
||||||
return mScope;
|
return mScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JSSlot& defineSlot(const String& name, JSType* type, JSFunction* getter = 0, JSFunction* setter = 0)
|
const JSSlot& defineSlot(const String& name, JSType* type, JSSlot::SlotFlags flags = JSSlot::kNoFlag, JSFunction* getter = 0, JSFunction* setter = 0)
|
||||||
{
|
{
|
||||||
JSSlot& slot = mSlots[name];
|
JSSlot& slot = mSlots[name];
|
||||||
ASSERT(slot.mType == 0);
|
|
||||||
slot.mType = type;
|
slot.mType = type;
|
||||||
slot.mIndex = mSlotCount++; // starts at 0.
|
slot.mIndex = mSlotCount++; // starts at 0.
|
||||||
slot.mSetter = setter;
|
slot.mSetter = setter;
|
||||||
slot.mGetter = getter;
|
slot.mGetter = getter;
|
||||||
|
slot.mFlags = flags;
|
||||||
if (setter || getter)
|
if (setter || getter)
|
||||||
slot.mActual = false;
|
slot.mActual = false;
|
||||||
return slot;
|
return slot;
|
||||||
|
@ -137,11 +141,13 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
JSSlots::iterator slti = mSlots.find(name);
|
JSSlots::iterator slti = mSlots.find(name);
|
||||||
if (slti == mSlots.end())
|
if (slti == mSlots.end())
|
||||||
defineSlot(name, type, getter, 0);
|
defineSlot(name, type, JSSlot::kNoFlag, getter, 0);
|
||||||
else {
|
else {
|
||||||
ASSERT(!slti->second.mActual);
|
if (slti->second.mActual)
|
||||||
|
ASSERT(slti->second.isVirtual());
|
||||||
ASSERT(slti->second.mGetter == 0);
|
ASSERT(slti->second.mGetter == 0);
|
||||||
slti->second.mGetter = getter;
|
slti->second.mGetter = getter;
|
||||||
|
slti->second.mActual = false;
|
||||||
}
|
}
|
||||||
mHasGetters = true;
|
mHasGetters = true;
|
||||||
}
|
}
|
||||||
|
@ -150,11 +156,14 @@ namespace JSClasses {
|
||||||
{
|
{
|
||||||
JSSlots::iterator slti = mSlots.find(name);
|
JSSlots::iterator slti = mSlots.find(name);
|
||||||
if (slti == mSlots.end())
|
if (slti == mSlots.end())
|
||||||
defineSlot(name, type, 0, setter);
|
defineSlot(name, type, JSSlot::kNoFlag, 0, setter);
|
||||||
else {
|
else {
|
||||||
ASSERT(!slti->second.mActual);
|
JSSlot &s = slti->second;
|
||||||
ASSERT(slti->second.mSetter == 0);
|
if (s.mActual)
|
||||||
slti->second.mSetter = setter;
|
ASSERT(s.isVirtual());
|
||||||
|
ASSERT(s.mSetter == 0);
|
||||||
|
s.mSetter = setter;
|
||||||
|
s.mActual = false;
|
||||||
}
|
}
|
||||||
mHasSetters = true;
|
mHasSetters = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,6 +171,15 @@ static JSValue load(Context *cx, const JSValues &argv)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool goGeorge = false;
|
||||||
|
|
||||||
|
static JSValue george(Context *cx, const JSValues &argv)
|
||||||
|
{
|
||||||
|
goGeorge = !goGeorge;
|
||||||
|
|
||||||
|
return JSValue(new JSString(goGeorge ? "George is going" : "George is taking a break"));
|
||||||
|
}
|
||||||
|
|
||||||
#if 0 // need a XP version of this, rip off from Monkey?
|
#if 0 // need a XP version of this, rip off from Monkey?
|
||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
static JSValue time(Context *cx, const JSValues &argv)
|
static JSValue time(Context *cx, const JSValues &argv)
|
||||||
|
@ -189,7 +198,7 @@ class Tracer : public Context::Listener {
|
||||||
typedef InstructionStream::difference_type InstructionOffset;
|
typedef InstructionStream::difference_type InstructionOffset;
|
||||||
void listen(Context* context, Context::Event event)
|
void listen(Context* context, Context::Event event)
|
||||||
{
|
{
|
||||||
if (event & Context::EV_STEP) {
|
if (goGeorge && (event & Context::EV_STEP)) {
|
||||||
ICodeModule *iCode = context->getICode();
|
ICodeModule *iCode = context->getICode();
|
||||||
JSValues ®isters = context->getRegisters();
|
JSValues ®isters = context->getRegisters();
|
||||||
InstructionIterator pc = context->getPC();
|
InstructionIterator pc = context->getPC();
|
||||||
|
@ -212,7 +221,7 @@ class Tracer : public Context::Listener {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//#define HAVE_GEORGE_TRACE_IT
|
#define HAVE_GEORGE_TRACE_IT
|
||||||
//#define TEST_XML_LOADER
|
//#define TEST_XML_LOADER
|
||||||
|
|
||||||
static void readEvalPrint(FILE *in, World &world)
|
static void readEvalPrint(FILE *in, World &world)
|
||||||
|
@ -225,6 +234,7 @@ static void readEvalPrint(FILE *in, World &world)
|
||||||
global.defineNativeFunction(world.identifiers["print"], print);
|
global.defineNativeFunction(world.identifiers["print"], print);
|
||||||
global.defineNativeFunction(world.identifiers["dump"], dump);
|
global.defineNativeFunction(world.identifiers["dump"], dump);
|
||||||
global.defineNativeFunction(world.identifiers["load"], load);
|
global.defineNativeFunction(world.identifiers["load"], load);
|
||||||
|
global.defineNativeFunction(world.identifiers["george"], george);
|
||||||
// global.defineNativeFunction(world.identifiers["time"], time);
|
// global.defineNativeFunction(world.identifiers["time"], time);
|
||||||
|
|
||||||
String buffer;
|
String buffer;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче