Fixes and enhancements to get class references, constructors and scripts
working from .xml input. git-svn-id: svn://10.0.0.236/trunk@85189 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -41,8 +41,8 @@ namespace JavaScript {
|
||||
void
|
||||
JSException::toString8 (string8 &rval)
|
||||
{
|
||||
rval = *exception_types[mType] + " Exception: " +
|
||||
*exception_msgs[mID];
|
||||
rval = string8(exception_types[mType]) + " Exception: " +
|
||||
string8(exception_msgs[mID]);
|
||||
if (mSource.size() != 0)
|
||||
rval += " in " + mSource;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace JavaScript {
|
||||
class JSException {
|
||||
public:
|
||||
JSException (ExceptionID ID, string8_citer pos = 0,
|
||||
string8 source = 0, ExceptionType type = etUnknown)
|
||||
string8 source = "", ExceptionType type = etUnknown)
|
||||
: mID(ID), mType(type), mPos(pos), mSource(source) {}
|
||||
ExceptionID mID;
|
||||
ExceptionType mType;
|
||||
@@ -100,7 +100,7 @@ namespace JavaScript {
|
||||
class JSParseException : public JSException {
|
||||
public:
|
||||
JSParseException (ExceptionID ID, string8_citer pos = 0,
|
||||
string8 source = 0) :
|
||||
string8 source = "") :
|
||||
JSException(ID, pos, source, etParser) {}
|
||||
/*
|
||||
private:
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace ICodeASM {
|
||||
throw JSParseException (eidExpectArgList);
|
||||
|
||||
tl = seekTokenStart (tl.begin + 1, end);
|
||||
StringFormatter s_fmt;
|
||||
while (tl.estimate == teString || tl.estimate == teAlpha) {
|
||||
string *argName = 0;
|
||||
|
||||
@@ -143,6 +144,15 @@ namespace ICodeASM {
|
||||
sap = &(mCx->getWorld().identifiers[argName->c_str()]);
|
||||
delete argName;
|
||||
}
|
||||
else {
|
||||
/* if an argument name was not specified, use the position
|
||||
* to build a default name.
|
||||
*/
|
||||
s_fmt << (uint32)al->size();
|
||||
sap = &(mCx->getWorld().identifiers[s_fmt.getString()]);
|
||||
s_fmt.clear();
|
||||
|
||||
}
|
||||
VM::Argument arg = VM::Argument (tr, sap);
|
||||
|
||||
al->push_back(arg);
|
||||
@@ -176,7 +186,7 @@ namespace ICodeASM {
|
||||
|
||||
for (int i = 0; keyword_exprNodeKinds[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_exprNodeKinds[i], keyword_exprNodeKinds[i] +
|
||||
strlen (keyword_exprNodeKinds[i]) + 1) == 0) {
|
||||
strlen (keyword_exprNodeKinds[i])) == 0) {
|
||||
*rval = exprNodeOps[i];
|
||||
delete str;
|
||||
return end;
|
||||
@@ -220,11 +230,28 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
string8_citer
|
||||
ICodeParser::parseJSClassOperand (string8_citer /*begin*/,
|
||||
string8_citer end, string ** /*rval*/)
|
||||
ICodeParser::parseJSClassOperand (string8_citer begin,
|
||||
string8_citer end, JSTypes::JSType **rval)
|
||||
{
|
||||
NOT_REACHED ("JSClasses are hard, lets go shopping.");
|
||||
TokenLocation tl = seekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw JSParseException (eidExpectString);
|
||||
|
||||
string8 *str;
|
||||
end = lexString8 (tl.begin, end, &str);
|
||||
StringAtom &typename_atom = mCx->getWorld().identifiers[str->c_str()];
|
||||
delete str;
|
||||
JSTypes::JSValue jsv =
|
||||
mCx->getGlobalObject()->getVariable(typename_atom);
|
||||
if (jsv.isType())
|
||||
*rval = jsv.type;
|
||||
else
|
||||
*rval = &(JSTypes::Any_Type);
|
||||
|
||||
return end;
|
||||
// NOT_REACHED ("JSClasses are hard, lets go shopping.");
|
||||
// return end;
|
||||
}
|
||||
|
||||
string8_citer
|
||||
@@ -287,7 +314,7 @@ namespace ICodeASM {
|
||||
begin = lexAlpha (tl.begin, end, &str);
|
||||
|
||||
if (cmp_nocase(*str, keyword_offset, keyword_offset +
|
||||
strlen(keyword_offset) + 1) == 0) {
|
||||
strlen(keyword_offset)) == 0) {
|
||||
delete str;
|
||||
/* got the "Offset" keyword, treat next thing as a jump offset
|
||||
* expressed as "Offset +/-N" */
|
||||
@@ -391,7 +418,7 @@ namespace ICodeASM {
|
||||
CASE_TYPE(Bool, bool, static_cast);
|
||||
CASE_TYPE(Double, double, static_cast);
|
||||
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSClass, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSClass, JSTypes::JSType *, reinterpret_cast);
|
||||
CASE_TYPE(JSString, JSTypes::JSString *, reinterpret_cast);
|
||||
CASE_TYPE(JSFunction, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSType, JSTypes::JSType *, reinterpret_cast);
|
||||
@@ -491,7 +518,7 @@ namespace ICodeASM {
|
||||
for (uint i = 0; i < icodemap_size; ++i)
|
||||
if (cmp_nocase(icode_str, &icodemap[i].name[0],
|
||||
&icodemap[i].name[0] +
|
||||
strlen(icodemap[i].name) + 1) == 0)
|
||||
strlen(icodemap[i].name)) == 0)
|
||||
/* if match found, parse it's operands */
|
||||
return parseInstruction (i, firstTokenEnd, end);
|
||||
/* otherwise, choke on it */
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace ICodeASM {
|
||||
string8 **rval);
|
||||
string8_citer
|
||||
parseJSClassOperand (string8_citer begin, string8_citer end,
|
||||
string8 **rval);
|
||||
JSTypes::JSType **rval);
|
||||
string8_citer
|
||||
parseJSStringOperand (string8_citer begin, string8_citer end,
|
||||
JSTypes::JSString **rval);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "icodegenerator.h"
|
||||
#include "interpreter.h"
|
||||
#include "xmlparser.h"
|
||||
#include "exception.h"
|
||||
#include "icodeasm.h"
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -2552,8 +2553,10 @@ Formatter& operator<<(Formatter &f, string &s)
|
||||
}
|
||||
|
||||
|
||||
void ICodeGenerator::readICode(const char *fileName)
|
||||
ICodeModule *ICodeGenerator::readICode(const char *fileName)
|
||||
{
|
||||
ICodeModule *result = NULL;
|
||||
|
||||
XMLParser xp(fileName);
|
||||
XMLNode *top = xp.parseDocument();
|
||||
stdOut << *top;
|
||||
@@ -2582,12 +2585,13 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
|
||||
mContext->getGlobalObject()->defineVariable(className, &Type_Type, JSValue(thisClass));
|
||||
|
||||
bool hasDefaultConstructor = false;
|
||||
// bool hasDefaultConstructor = false;
|
||||
XMLNodeList &elements = node->children();
|
||||
for (XMLNodeList::const_iterator j = elements.begin(); j != elements.end(); j++) {
|
||||
XMLNode *element = *j;
|
||||
bool isConstructor = (element->name().compare(widenCString("constructor")) == 0);
|
||||
|
||||
if (element->name().compare(widenCString("method")) == 0) {
|
||||
if (isConstructor || (element->name().compare(widenCString("method")) == 0)) {
|
||||
String methodName, resultTypeName;
|
||||
element->getValue(widenCString("name"), methodName);
|
||||
element->getValue(widenCString("type"), resultTypeName);
|
||||
@@ -2631,7 +2635,12 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
resultType,
|
||||
NotABanana); /* exception register */
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
if (isConstructor) {
|
||||
thisClass->defineConstructor(methodName);
|
||||
scg.setStatic(thisClass, mContext->getWorld().identifiers[methodName], scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2651,7 +2660,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
}
|
||||
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg.complete(&Void_Type)));
|
||||
|
||||
/*
|
||||
if (!hasDefaultConstructor) {
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList(0);
|
||||
@@ -2665,6 +2674,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
thisClass->defineConstructor(className);
|
||||
scg.setStatic(thisClass, mContext->getWorld().identifiers[className], scg.newFunction(icg.complete(&Void_Type)));
|
||||
}
|
||||
*/
|
||||
thisClass->complete();
|
||||
|
||||
if (scg.getICode()->size()) {
|
||||
@@ -2676,7 +2686,24 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
else {
|
||||
if (node->name().compare(widenCString("script")) == 0) {
|
||||
// build an icode module and execute it
|
||||
String &body = node->body();
|
||||
if (body.length()) {
|
||||
std::string str(body.length(), char());
|
||||
std::transform(body.begin(), body.end(), str.begin(), narrow);
|
||||
ICodeParser icp(mContext);
|
||||
|
||||
stdOut << "(script) Calling ICodeParser with :\n" << str << "\n";
|
||||
|
||||
icp.parseSourceFromString(str);
|
||||
|
||||
result = new ICodeModule(icp.mInstructions,
|
||||
NULL, /* VariableList *variables */
|
||||
NULL, /* ParameterList *parameters */
|
||||
icp.mMaxRegister,
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
&Void_Type,
|
||||
NotABanana); /* exception register */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node->name().compare(widenCString("instance")) == 0) {
|
||||
@@ -2691,7 +2718,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace ICG {
|
||||
}
|
||||
|
||||
ICodeModule *complete(JSType *resultType);
|
||||
void readICode(const char *fileName);
|
||||
ICodeModule *readICode(const char *fileName);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
JSType *getParameterType(FunctionDefinition &function, int index);
|
||||
|
||||
@@ -162,10 +162,10 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
||||
return icm;
|
||||
}
|
||||
|
||||
void Context::loadClass(const char *fileName)
|
||||
ICodeModule* Context::loadClass(const char *fileName)
|
||||
{
|
||||
ICodeGenerator icg(this);
|
||||
icg.readICode(fileName); // loads it into the global object
|
||||
return icg.readICode(fileName); // loads it into the global object
|
||||
}
|
||||
|
||||
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
|
||||
@@ -604,96 +604,99 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
else {
|
||||
ICodeModule *icm = target->getICode();
|
||||
ArgumentList *args = op3(call);
|
||||
ArgumentList *callArgs = NULL;
|
||||
|
||||
// if all the parameters are positional
|
||||
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||
if (icm->itsParameters) {
|
||||
|
||||
// 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
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
ArgumentList *callArgs = new ArgumentList(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
// if all the parameters are positional
|
||||
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
// 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
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
callArgs = new ArgumentList(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
|
||||
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->data();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->size(), end);
|
||||
int index = -1;
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->data();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->size(), end);
|
||||
int index = -1;
|
||||
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
index = (int)d;
|
||||
index -= icm->itsParameters->mPositionalCount;
|
||||
}
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
index = (int)d;
|
||||
index -= icm->itsParameters->mPositionalCount;
|
||||
}
|
||||
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else {
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else {
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
}
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
else {
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call), mICode, mCurrentClosure);
|
||||
mICode = icm;
|
||||
mActivation = new Activation(mICode->itsMaxRegister, mActivation, target->getThis(), callArgs);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Interpreter {
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
void loadClass(const char *fileName);
|
||||
ICodeModule* loadClass(const char *fileName);
|
||||
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op);
|
||||
|
||||
@@ -142,14 +142,16 @@ namespace Interpreter {
|
||||
// copy caller's parameter list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
*dest++ = thisArg;
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list->begin(),
|
||||
end = list->end(); src != end; ++src, ++dest) {
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
if (list) {
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list->begin(),
|
||||
end = list->end(); src != end; ++src, ++dest) {
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,9 @@ static JSValue loadxml(Context *cx, const JSValues &argv)
|
||||
JSString& fileName = *val.string;
|
||||
std::string str(fileName.length(), char());
|
||||
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
|
||||
cx->loadClass(str.c_str());
|
||||
ICodeModule *icm = cx->loadClass(str.c_str());
|
||||
if (icm)
|
||||
result = JSValue(new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ namespace JavaScript {
|
||||
void
|
||||
JSException::toString8 (string8 &rval)
|
||||
{
|
||||
rval = *exception_types[mType] + " Exception: " +
|
||||
*exception_msgs[mID];
|
||||
rval = string8(exception_types[mType]) + " Exception: " +
|
||||
string8(exception_msgs[mID]);
|
||||
if (mSource.size() != 0)
|
||||
rval += " in " + mSource;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace JavaScript {
|
||||
class JSException {
|
||||
public:
|
||||
JSException (ExceptionID ID, string8_citer pos = 0,
|
||||
string8 source = 0, ExceptionType type = etUnknown)
|
||||
string8 source = "", ExceptionType type = etUnknown)
|
||||
: mID(ID), mType(type), mPos(pos), mSource(source) {}
|
||||
ExceptionID mID;
|
||||
ExceptionType mType;
|
||||
@@ -100,7 +100,7 @@ namespace JavaScript {
|
||||
class JSParseException : public JSException {
|
||||
public:
|
||||
JSParseException (ExceptionID ID, string8_citer pos = 0,
|
||||
string8 source = 0) :
|
||||
string8 source = "") :
|
||||
JSException(ID, pos, source, etParser) {}
|
||||
/*
|
||||
private:
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace ICodeASM {
|
||||
throw JSParseException (eidExpectArgList);
|
||||
|
||||
tl = seekTokenStart (tl.begin + 1, end);
|
||||
StringFormatter s_fmt;
|
||||
while (tl.estimate == teString || tl.estimate == teAlpha) {
|
||||
string *argName = 0;
|
||||
|
||||
@@ -143,6 +144,15 @@ namespace ICodeASM {
|
||||
sap = &(mCx->getWorld().identifiers[argName->c_str()]);
|
||||
delete argName;
|
||||
}
|
||||
else {
|
||||
/* if an argument name was not specified, use the position
|
||||
* to build a default name.
|
||||
*/
|
||||
s_fmt << (uint32)al->size();
|
||||
sap = &(mCx->getWorld().identifiers[s_fmt.getString()]);
|
||||
s_fmt.clear();
|
||||
|
||||
}
|
||||
VM::Argument arg = VM::Argument (tr, sap);
|
||||
|
||||
al->push_back(arg);
|
||||
@@ -176,7 +186,7 @@ namespace ICodeASM {
|
||||
|
||||
for (int i = 0; keyword_exprNodeKinds[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_exprNodeKinds[i], keyword_exprNodeKinds[i] +
|
||||
strlen (keyword_exprNodeKinds[i]) + 1) == 0) {
|
||||
strlen (keyword_exprNodeKinds[i])) == 0) {
|
||||
*rval = exprNodeOps[i];
|
||||
delete str;
|
||||
return end;
|
||||
@@ -220,11 +230,28 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
string8_citer
|
||||
ICodeParser::parseJSClassOperand (string8_citer /*begin*/,
|
||||
string8_citer end, string ** /*rval*/)
|
||||
ICodeParser::parseJSClassOperand (string8_citer begin,
|
||||
string8_citer end, JSTypes::JSType **rval)
|
||||
{
|
||||
NOT_REACHED ("JSClasses are hard, lets go shopping.");
|
||||
TokenLocation tl = seekTokenStart (begin, end);
|
||||
|
||||
if (tl.estimate != teString)
|
||||
throw JSParseException (eidExpectString);
|
||||
|
||||
string8 *str;
|
||||
end = lexString8 (tl.begin, end, &str);
|
||||
StringAtom &typename_atom = mCx->getWorld().identifiers[str->c_str()];
|
||||
delete str;
|
||||
JSTypes::JSValue jsv =
|
||||
mCx->getGlobalObject()->getVariable(typename_atom);
|
||||
if (jsv.isType())
|
||||
*rval = jsv.type;
|
||||
else
|
||||
*rval = &(JSTypes::Any_Type);
|
||||
|
||||
return end;
|
||||
// NOT_REACHED ("JSClasses are hard, lets go shopping.");
|
||||
// return end;
|
||||
}
|
||||
|
||||
string8_citer
|
||||
@@ -287,7 +314,7 @@ namespace ICodeASM {
|
||||
begin = lexAlpha (tl.begin, end, &str);
|
||||
|
||||
if (cmp_nocase(*str, keyword_offset, keyword_offset +
|
||||
strlen(keyword_offset) + 1) == 0) {
|
||||
strlen(keyword_offset)) == 0) {
|
||||
delete str;
|
||||
/* got the "Offset" keyword, treat next thing as a jump offset
|
||||
* expressed as "Offset +/-N" */
|
||||
@@ -391,7 +418,7 @@ namespace ICodeASM {
|
||||
CASE_TYPE(Bool, bool, static_cast);
|
||||
CASE_TYPE(Double, double, static_cast);
|
||||
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSClass, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSClass, JSTypes::JSType *, reinterpret_cast);
|
||||
CASE_TYPE(JSString, JSTypes::JSString *, reinterpret_cast);
|
||||
CASE_TYPE(JSFunction, string *, reinterpret_cast);
|
||||
CASE_TYPE(JSType, JSTypes::JSType *, reinterpret_cast);
|
||||
@@ -491,7 +518,7 @@ namespace ICodeASM {
|
||||
for (uint i = 0; i < icodemap_size; ++i)
|
||||
if (cmp_nocase(icode_str, &icodemap[i].name[0],
|
||||
&icodemap[i].name[0] +
|
||||
strlen(icodemap[i].name) + 1) == 0)
|
||||
strlen(icodemap[i].name)) == 0)
|
||||
/* if match found, parse it's operands */
|
||||
return parseInstruction (i, firstTokenEnd, end);
|
||||
/* otherwise, choke on it */
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace ICodeASM {
|
||||
string8 **rval);
|
||||
string8_citer
|
||||
parseJSClassOperand (string8_citer begin, string8_citer end,
|
||||
string8 **rval);
|
||||
JSTypes::JSType **rval);
|
||||
string8_citer
|
||||
parseJSStringOperand (string8_citer begin, string8_citer end,
|
||||
JSTypes::JSString **rval);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "icodegenerator.h"
|
||||
#include "interpreter.h"
|
||||
#include "xmlparser.h"
|
||||
#include "exception.h"
|
||||
#include "icodeasm.h"
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -2552,8 +2553,10 @@ Formatter& operator<<(Formatter &f, string &s)
|
||||
}
|
||||
|
||||
|
||||
void ICodeGenerator::readICode(const char *fileName)
|
||||
ICodeModule *ICodeGenerator::readICode(const char *fileName)
|
||||
{
|
||||
ICodeModule *result = NULL;
|
||||
|
||||
XMLParser xp(fileName);
|
||||
XMLNode *top = xp.parseDocument();
|
||||
stdOut << *top;
|
||||
@@ -2582,12 +2585,13 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
|
||||
mContext->getGlobalObject()->defineVariable(className, &Type_Type, JSValue(thisClass));
|
||||
|
||||
bool hasDefaultConstructor = false;
|
||||
// bool hasDefaultConstructor = false;
|
||||
XMLNodeList &elements = node->children();
|
||||
for (XMLNodeList::const_iterator j = elements.begin(); j != elements.end(); j++) {
|
||||
XMLNode *element = *j;
|
||||
bool isConstructor = (element->name().compare(widenCString("constructor")) == 0);
|
||||
|
||||
if (element->name().compare(widenCString("method")) == 0) {
|
||||
if (isConstructor || (element->name().compare(widenCString("method")) == 0)) {
|
||||
String methodName, resultTypeName;
|
||||
element->getValue(widenCString("name"), methodName);
|
||||
element->getValue(widenCString("type"), resultTypeName);
|
||||
@@ -2631,7 +2635,12 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
resultType,
|
||||
NotABanana); /* exception register */
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
if (isConstructor) {
|
||||
thisClass->defineConstructor(methodName);
|
||||
scg.setStatic(thisClass, mContext->getWorld().identifiers[methodName], scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
thisClass->defineMethod(methodName, new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -2651,7 +2660,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
}
|
||||
scg.setStatic(thisClass, mInitName, scg.newFunction(ccg.complete(&Void_Type)));
|
||||
|
||||
/*
|
||||
if (!hasDefaultConstructor) {
|
||||
TypedRegister thisValue = TypedRegister(0, thisClass);
|
||||
ArgumentList *args = new ArgumentList(0);
|
||||
@@ -2665,6 +2674,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
thisClass->defineConstructor(className);
|
||||
scg.setStatic(thisClass, mContext->getWorld().identifiers[className], scg.newFunction(icg.complete(&Void_Type)));
|
||||
}
|
||||
*/
|
||||
thisClass->complete();
|
||||
|
||||
if (scg.getICode()->size()) {
|
||||
@@ -2676,7 +2686,24 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
else {
|
||||
if (node->name().compare(widenCString("script")) == 0) {
|
||||
// build an icode module and execute it
|
||||
String &body = node->body();
|
||||
if (body.length()) {
|
||||
std::string str(body.length(), char());
|
||||
std::transform(body.begin(), body.end(), str.begin(), narrow);
|
||||
ICodeParser icp(mContext);
|
||||
|
||||
stdOut << "(script) Calling ICodeParser with :\n" << str << "\n";
|
||||
|
||||
icp.parseSourceFromString(str);
|
||||
|
||||
result = new ICodeModule(icp.mInstructions,
|
||||
NULL, /* VariableList *variables */
|
||||
NULL, /* ParameterList *parameters */
|
||||
icp.mMaxRegister,
|
||||
NULL, /* InstructionMap *instructionMap */
|
||||
&Void_Type,
|
||||
NotABanana); /* exception register */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (node->name().compare(widenCString("instance")) == 0) {
|
||||
@@ -2691,7 +2718,7 @@ void ICodeGenerator::readICode(const char *fileName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace ICG {
|
||||
}
|
||||
|
||||
ICodeModule *complete(JSType *resultType);
|
||||
void readICode(const char *fileName);
|
||||
ICodeModule *readICode(const char *fileName);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
JSType *getParameterType(FunctionDefinition &function, int index);
|
||||
|
||||
@@ -162,10 +162,10 @@ ICodeModule* Context::genCode(StmtNode *p, const String &fileName)
|
||||
return icm;
|
||||
}
|
||||
|
||||
void Context::loadClass(const char *fileName)
|
||||
ICodeModule* Context::loadClass(const char *fileName)
|
||||
{
|
||||
ICodeGenerator icg(this);
|
||||
icg.readICode(fileName); // loads it into the global object
|
||||
return icg.readICode(fileName); // loads it into the global object
|
||||
}
|
||||
|
||||
JSValues& Context::getRegisters() { return mActivation->mRegisters; }
|
||||
@@ -604,96 +604,99 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
else {
|
||||
ICodeModule *icm = target->getICode();
|
||||
ArgumentList *args = op3(call);
|
||||
ArgumentList *callArgs = NULL;
|
||||
|
||||
// if all the parameters are positional
|
||||
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||
if (icm->itsParameters) {
|
||||
|
||||
// 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
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
ArgumentList *callArgs = new ArgumentList(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
// if all the parameters are positional
|
||||
// if (icm->itsParameters->mPositionalCount == icm->itsParameters->size())
|
||||
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
// 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
|
||||
// callArgs will be the actual args passed to the target, put into correct register order.
|
||||
// It has room for the rest parameter.
|
||||
callArgs = new ArgumentList(pCount, Argument(TypedRegister(NotARegister, &Null_Type), NULL));
|
||||
|
||||
// don't want to count the rest parameter while processing the others
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::NoRestParameter) pCount--;
|
||||
|
||||
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
uint32 i;
|
||||
JSArray *restArg = NULL;
|
||||
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
// first match all named arguments with their intended target locations
|
||||
for (i = 0; i < args->size(); i++) {
|
||||
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
const StringAtom *argName = (*args)[i].second;
|
||||
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->data();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->size(), end);
|
||||
int index = -1;
|
||||
TypedRegister parameter = icm->itsParameters->findVariable(*argName);
|
||||
if (parameter.first == NotARegister) {
|
||||
// arg name doesn't match any parameter name, it's a candidate
|
||||
// for the rest parameter (if there is one)
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::NoRestParameter)
|
||||
throw new JSException("Named argument doesn't match parameter name in call with no rest parameter");
|
||||
else {
|
||||
if (icm->itsParameters->mRestParameter != ParameterList::HasUnnamedRestParameter) {
|
||||
// if the name is a numeric literal >= 0, use it as an array index
|
||||
// otherwise just set the named property.
|
||||
const char16 *c = argName->data();
|
||||
const char16 *end;
|
||||
double d = stringToDouble(c, c + argName->size(), end);
|
||||
int index = -1;
|
||||
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
index = (int)d;
|
||||
index -= icm->itsParameters->mPositionalCount;
|
||||
}
|
||||
if ((d != d) || (d < 0) || (d != (int)d)) { // a non-numeric or negative value
|
||||
if (icm->itsParameters->mRestParameter == ParameterList::HasRestParameterBeforeBar)
|
||||
throw new JSException("Non-numeric or negative argument name for positional rest parameter");
|
||||
}
|
||||
else { // shift the index value down by the number of positional parameters
|
||||
index = (int)d;
|
||||
index -= icm->itsParameters->mPositionalCount;
|
||||
}
|
||||
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match
|
||||
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else {
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
if (restArg == NULL) {
|
||||
// allocate the rest argument and then subvert the register being used for the
|
||||
// argument under consideration to hold the newly created rest argument.
|
||||
restArg = new JSArray();
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
(*registers)[argument.first] = restArg;
|
||||
// The callArgs for the rest parameter position gets loaded from that slot
|
||||
(*callArgs)[pCount] = Argument(TypedRegister(argument.first, &Array_Type), NULL);
|
||||
}
|
||||
else {
|
||||
if (index == -1)
|
||||
restArg->setProperty(*argName, (*registers)[argument.first]);
|
||||
else
|
||||
(*restArg)[uint32(index)] = (*registers)[argument.first];
|
||||
}
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
// else just throw it away
|
||||
}
|
||||
else {
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint32 targetIndex = parameter.first - 1; // this is the register number we're targetting
|
||||
TypedRegister targetParameter = (*callArgs)[targetIndex].first;
|
||||
if (targetParameter.first != NotARegister) // uh oh, some other argument wants this parameter
|
||||
throw new JSException("Two (or more) arguments have the same name");
|
||||
(*callArgs)[targetIndex] = (*args)[i];
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// make sure that all non-optional parameters have values
|
||||
for (i = 0; i < pCount; i++) {
|
||||
TypedRegister parameter = (*callArgs)[i].first;
|
||||
if (parameter.first == NotARegister) { // doesn't have an assigned argument
|
||||
if (!icm->itsParameters->isOptional(i + 1)) // and parameter (allowing for 'this') doesn't have an optional value
|
||||
throw new JSException("No argument supplied for non-optional parameter");
|
||||
}
|
||||
}
|
||||
|
||||
mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call), mICode, mCurrentClosure);
|
||||
mICode = icm;
|
||||
mActivation = new Activation(mICode->itsMaxRegister, mActivation, target->getThis(), callArgs);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Interpreter {
|
||||
ICodeModule* genCode(StmtNode *p, const String &fileName);
|
||||
JSValue readEvalFile(FILE* in, const String& fileName);
|
||||
|
||||
void loadClass(const char *fileName);
|
||||
ICodeModule* loadClass(const char *fileName);
|
||||
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op);
|
||||
|
||||
@@ -142,14 +142,16 @@ namespace Interpreter {
|
||||
// copy caller's parameter list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
*dest++ = thisArg;
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list->begin(),
|
||||
end = list->end(); src != end; ++src, ++dest) {
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
if (list) {
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (ArgumentList::const_iterator src = list->begin(),
|
||||
end = list->end(); src != end; ++src, ++dest) {
|
||||
Register r = (*src).first.first;
|
||||
if (r != NotARegister)
|
||||
*dest = params[r];
|
||||
else
|
||||
*dest = JSValue(JSValue::uninitialized_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,9 @@ static JSValue loadxml(Context *cx, const JSValues &argv)
|
||||
JSString& fileName = *val.string;
|
||||
std::string str(fileName.length(), char());
|
||||
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
|
||||
cx->loadClass(str.c_str());
|
||||
ICodeModule *icm = cx->loadClass(str.c_str());
|
||||
if (icm)
|
||||
result = JSValue(new JSFunction(icm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user