final XML ecmaToXml(Object object) { // See ECMA357 10.3 if (object == null || object == Undefined.instance) { throw ScriptRuntime.typeError("Cannot convert " + object + " to XML"); } if (object instanceof XML) return (XML) object; if (object instanceof XMLList) { XMLList list = (XMLList) object; if (list.getXML() != null) { return list.getXML(); } else { throw ScriptRuntime.typeError("Cannot convert list of >1 element to XML"); } } // TODO Technically we should fail on anything except a String, Number or Boolean // See ECMA357 10.3 // Extension: if object is a DOM node, use that to construct the XML // object. if (object instanceof Wrapper) { object = ((Wrapper) object).unwrap(); } if (object instanceof org.w3c.dom.Node) { org.w3c.dom.Node node = (org.w3c.dom.Node) object; return newXML(XmlNode.createElementFromNode(node)); } // Instead we just blindly cast to a String and let them convert anything. String s = ScriptRuntime.toString(object); // TODO Could this get any uglier? if (s.length() > 0 && s.charAt(0) == '<') { return parse(s); } else { return newXML(XmlNode.createText(options, s)); } }
private Object applyOrCall( boolean isApply, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { String methodName = isApply ? "apply" : "call"; if (!(thisObj instanceof XMLList) || ((XMLList) thisObj).targetProperty == null) throw ScriptRuntime.typeError1("msg.isnt.function", methodName); return ScriptRuntime.applyOrCall(isApply, cx, scope, thisObj, args); }
@Override void putXMLProperty(XMLName xmlName, Object value) { // Log("put property: " + name); // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } if (length() > 1) { throw ScriptRuntime.typeError("Assignment to lists with more than one item is not supported"); } else if (length() == 0) { // Secret sauce for super-expandos. // We set an element here, and then add ourselves to our target. if (targetObject != null && targetProperty != null && targetProperty.getLocalName() != null && targetProperty.getLocalName().length() > 0) { // Add an empty element with our targetProperty name and // then set it. XML xmlValue = newTextElementXML(null, targetProperty, null); addToList(xmlValue); if (xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } // Now add us to our parent XMLName name2 = XMLName.formProperty( targetProperty.getNamespace().getUri(), targetProperty.getLocalName()); targetObject.putXMLProperty(name2, this); replace(0, targetObject.getXML().getLastXmlChild()); } else { throw ScriptRuntime.typeError("Assignment to empty XMLList without targets not supported"); } } else if (xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } }
private static RuntimeException badXMLName(Object value) { String msg; if (value instanceof Number) { msg = "Can not construct XML name from number: "; } else if (value instanceof Boolean) { msg = "Can not construct XML name from boolean: "; } else if (value == Undefined.instance || value == null) { msg = "Can not construct XML name from "; } else { throw new IllegalArgumentException(value.toString()); } return ScriptRuntime.typeError(msg + ScriptRuntime.toString(value)); }
private String getStringProperty(Scriptable obj, String name, String defaultValue) { Object value = ScriptableObject.getProperty(obj, name); if (value != null && value != ScriptableObject.NOT_FOUND) { return ScriptRuntime.toString(value); } return defaultValue; }
private static int printSourceNumber(String source, int offset, StringBuffer sb) { double number = 0.0; char type = source.charAt(offset); ++offset; if (type == 'S') { if (sb != null) { number = source.charAt(offset); } ++offset; } else if (type == 'J' || type == 'D') { if (sb != null) { long lbits; lbits = (long) source.charAt(offset) << 48; lbits |= (long) source.charAt(offset + 1) << 32; lbits |= (long) source.charAt(offset + 2) << 16; lbits |= (long) source.charAt(offset + 3); if (type == 'J') { number = lbits; } else { number = Double.longBitsToDouble(lbits); } } offset += 4; } else { // Bad source throw new RuntimeException(); } if (sb != null) { sb.append(ScriptRuntime.numberToString(number, 10)); } return offset; }
XmlNode.QName toNodeQName(Context cx, Object namespaceValue, Object nameValue) { // This is duplication of constructQName(cx, namespaceValue, nameValue) // but for XMLName String localName; if (nameValue instanceof QName) { QName qname = (QName) nameValue; localName = qname.localName(); } else { localName = ScriptRuntime.toString(nameValue); } XmlNode.Namespace ns; if (namespaceValue == Undefined.instance) { if ("*".equals(localName)) { ns = null; } else { ns = getDefaultNamespace(cx).getDelegate(); } } else if (namespaceValue == null) { ns = null; } else if (namespaceValue instanceof Namespace) { ns = ((Namespace) namespaceValue).getDelegate(); } else { ns = this.namespacePrototype.constructNamespace(namespaceValue).getDelegate(); } if (localName != null && localName.equals("*")) localName = null; return XmlNode.QName.create(ns, localName); }
private XML parse(String frag) { try { return newXML( XmlNode.createElement( options, getDefaultNamespaceURI(Context.getCurrentContext()), frag)); } catch (SAXException e) { throw ScriptRuntime.typeError("Cannot parse XML: " + e.getMessage()); } }
/** * If value represents Uint32 index, make it available through ScriptRuntime.lastUint32Result(cx) * and return null. Otherwise return the same value as toXMLName(cx, value). */ XMLName toXMLNameOrIndex(Context cx, Object value) { XMLName result; if (value instanceof XMLName) { result = (XMLName) value; } else if (value instanceof String) { String str = (String) value; long test = ScriptRuntime.testUint32String(str); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); result = null; } else { result = toXMLNameFromString(cx, str); } } else if (value instanceof Number) { double d = ((Number) value).doubleValue(); long l = (long) d; if (l == d && 0 <= l && l <= 0xFFFFFFFFL) { ScriptRuntime.storeUint32Result(cx, l); result = null; } else { throw badXMLName(value); } } else if (value instanceof QName) { QName qname = (QName) value; String uri = qname.uri(); boolean number = false; result = null; if (uri != null && uri.length() == 0) { // Only in this case qname.toString() can resemble uint32 long test = ScriptRuntime.testUint32String(uri); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); number = true; } } if (!number) { result = XMLName.formProperty(uri, qname.localName()); } } else if (value instanceof Boolean || value == Undefined.instance || value == null) { throw badXMLName(value); } else { String str = ScriptRuntime.toString(value); long test = ScriptRuntime.testUint32String(str); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); result = null; } else { result = toXMLNameFromString(cx, str); } } return result; }
/* * Analog of match_glob() in jsstr.c */ private static void match_glob( GlobData mdata, Context cx, Scriptable scope, int count, RegExpImpl reImpl) { if (mdata.arrayobj == null) { Scriptable s = ScriptableObject.getTopLevelScope(scope); mdata.arrayobj = ScriptRuntime.newObject(cx, s, "Array", null); } SubString matchsub = reImpl.lastMatch; String matchstr = matchsub.toString(); mdata.arrayobj.put(count, mdata.arrayobj, matchstr); }
public Object action( Context cx, Scriptable scope, Scriptable thisObj, Object[] args, int actionType) { GlobData data = new GlobData(); data.mode = actionType; switch (actionType) { case RA_MATCH: { Object rval; data.optarg = 1; rval = matchOrReplace(cx, scope, thisObj, args, this, data, false); return data.arrayobj == null ? rval : data.arrayobj; } case RA_SEARCH: data.optarg = 1; return matchOrReplace(cx, scope, thisObj, args, this, data, false); case RA_REPLACE: { Object arg1 = args.length < 2 ? Undefined.instance : args[1]; String repstr = null; Function lambda = null; if (arg1 instanceof Function) { lambda = (Function) arg1; } else { repstr = ScriptRuntime.toString(arg1); } data.optarg = 2; data.lambda = lambda; data.repstr = repstr; data.dollar = repstr == null ? -1 : repstr.indexOf('$'); data.charBuf = null; data.leftIndex = 0; Object val = matchOrReplace(cx, scope, thisObj, args, this, data, true); SubString rc = this.rightContext; if (data.charBuf == null) { if (data.global || val == null || !val.equals(Boolean.TRUE)) { /* Didn't match even once. */ return data.str; } SubString lc = this.leftContext; replace_glob(data, cx, scope, this, lc.index, lc.length); } data.charBuf.append(rc.charArray, rc.index, rc.length); return data.charBuf.toString(); } default: throw Kit.codeBug(); } }
@Override boolean propertyIsEnumerable(Object name) { long index; if (name instanceof Integer) { index = ((Integer) name).intValue(); } else if (name instanceof Number) { double x = ((Number) name).doubleValue(); index = (long) x; if (index != x) { return false; } if (index == 0 && 1.0 / x < 0) { // Negative 0 return false; } } else { String s = ScriptRuntime.toString(name); index = ScriptRuntime.testUint32String(s); } return (0 <= index && index < length()); }
private Scriptable alloc(Context cx, Object[] args) { ScriptableObject obj = objArg(args, 0, ScriptableObject.class, true); int size = intArg(args, 1); Object typeObj = objArg(args, 2, Object.class, false); int type; if ((typeObj == null) || Undefined.instance.equals(typeObj)) { type = 2; } else { type = ScriptRuntime.toInt32(typeObj); } if (obj.getExternalArrayData() != null) { throw Utils.makeTypeError(cx, this, "object already has external array data"); } ExternalArrayData array; // Switch needs to match constants in smalloc.js switch (type) { case 1: array = new NativeInt8Array(size); break; case 2: array = new NativeUint8Array(size); break; case 3: array = new NativeInt16Array(size); break; case 4: array = new NativeUint16Array(size); break; case 5: array = new NativeInt32Array(size); break; case 6: array = new NativeUint32Array(size); break; case 7: array = new NativeFloat32Array(size); break; case 8: array = new NativeFloat64Array(size); break; case 9: array = new NativeUint8ClampedArray(size); break; default: throw Utils.makeError(cx, this, "Invalid array type"); } obj.setExternalArrayData(array); return obj; }
/* TODO: Can this can be replaced by ecmaToXml below? */ final XML newXMLFromJs(Object inputObject) { String frag; if (inputObject == null || inputObject == Undefined.instance) { frag = ""; } else if (inputObject instanceof XMLObjectImpl) { // todo: faster way for XMLObjects? frag = ((XMLObjectImpl) inputObject).toXMLString(); } else { frag = ScriptRuntime.toString(inputObject); } if (frag.trim().startsWith("<>")) { throw ScriptRuntime.typeError("Invalid use of XML object anonymous tags <></>."); } if (frag.indexOf("<") == -1) { // Solo text node return newXML(XmlNode.createText(options, frag)); } return parse(frag); }
final XMLList newXMLListFrom(Object inputObject) { XMLList rv = newXMLList(); if (inputObject == null || inputObject instanceof Undefined) { return rv; } else if (inputObject instanceof XML) { XML xml = (XML) inputObject; rv.getNodeList().add(xml); return rv; } else if (inputObject instanceof XMLList) { XMLList xmll = (XMLList) inputObject; rv.getNodeList().add(xmll.getNodeList()); return rv; } else { String frag = ScriptRuntime.toString(inputObject).trim(); if (!frag.startsWith("<>")) { frag = "<>" + frag + "</>"; } frag = "<fragment>" + frag.substring(2); if (!frag.endsWith("</>")) { throw ScriptRuntime.typeError("XML with anonymous tag missing end anonymous tag"); } frag = frag.substring(0, frag.length() - 3) + "</fragment>"; XML orgXML = newXMLFromJs(frag); // Now orphan the children and add them to our XMLList. XMLList children = orgXML.children(); for (int i = 0; i < children.getNodeList().length(); i++) { // Copy here is so that they'll be orphaned (parent() will be undefined) rv.getNodeList().add(((XML) children.item(i).copy())); } return rv; } }
/** {@inheritDoc} */ @Override public String getIdentifier(final Object entry) { // should be final but cannot be for sake of exception handling String identifier; if (entry instanceof Scriptable) { final Context cx = Context.enter(); try { final Object toString = ScriptableObject.getProperty((Scriptable) entry, "toString"); if (toString instanceof Function) { final Object toStringResult = ((Function) toString).call(cx, (Scriptable) entry, (Scriptable) entry, new Object[0]); identifier = ScriptRuntime.toString(toStringResult); } else if (toString != Scriptable.NOT_FOUND) { identifier = ScriptRuntime.toString(toString); } else if (entry instanceof BaseFunction) { final String functionName = ((BaseFunction) entry).getFunctionName(); identifier = functionName != null && functionName.length() != 0 ? functionName : entry.toString(); } else { identifier = entry.toString(); } } catch (final RhinoException ex) { LOGGER.debug( "Exception determining entry identifier via Rhino - falling back to simple toString", ex); identifier = entry.toString(); } finally { Context.exit(); } } else if (entry != null) { identifier = entry.toString(); } else { identifier = null; } return identifier; }
/** * Take an object from the scripting layer and convert it to an int. * * @param obj * @return int */ private int toInt(Object obj) { int result = 0; if (obj instanceof String) { result = Integer.parseInt((String) obj); } else if (obj instanceof Number) { result = ((Number) obj).intValue(); } else if (obj instanceof Scriptable) { Scriptable sobj = (Scriptable) obj; if (sobj.getClassName().equals("Number")) { result = (int) ScriptRuntime.toNumber(sobj); } } return result; }
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // This XMLList is being called as a Function. // Let's find the real Function object. if (targetProperty == null) throw ScriptRuntime.notFunctionError(this); String methodName = targetProperty.getLocalName(); boolean isApply = methodName.equals("apply"); if (isApply || methodName.equals("call")) return applyOrCall(isApply, cx, scope, thisObj, args); if (!(thisObj instanceof XMLObject)) { throw ScriptRuntime.typeError1("msg.incompat.call", methodName); } Object func = null; Scriptable sobj = thisObj; while (sobj instanceof XMLObject) { XMLObject xmlObject = (XMLObject) sobj; func = xmlObject.getFunctionProperty(cx, methodName); if (func != Scriptable.NOT_FOUND) { break; } sobj = xmlObject.getExtraMethodSource(cx); if (sobj != null) { thisObj = sobj; if (!(sobj instanceof XMLObject)) { func = ScriptableObject.getProperty(sobj, methodName); } } } if (!(func instanceof Callable)) { throw ScriptRuntime.notFunctionError(thisObj, func, methodName); } return ((Callable) func).call(cx, scope, thisObj, args); }
/* TODO: Too general; this should be split into overloaded methods. Is that possible? */ XmlNode.QName toNodeQName(Context cx, Object nameValue, boolean attribute) { if (nameValue instanceof XMLName) { return ((XMLName) nameValue).toQname(); } else if (nameValue instanceof QName) { QName qname = (QName) nameValue; return qname.getDelegate(); } else if (nameValue instanceof Boolean || nameValue instanceof Number || nameValue == Undefined.instance || nameValue == null) { throw badXMLName(nameValue); } else { String local = null; if (nameValue instanceof String) { local = (String) nameValue; } else { local = ScriptRuntime.toString(nameValue); } return toNodeQName(cx, local, attribute); } }
Namespace getDefaultNamespace(Context cx) { if (cx == null) { cx = Context.getCurrentContext(); if (cx == null) { return namespacePrototype; } } Object ns = ScriptRuntime.searchDefaultNamespace(cx); if (ns == null) { return namespacePrototype; } else { if (ns instanceof Namespace) { return (Namespace) ns; } else { // TODO Clarify or remove the following comment // Should not happen but for now it could // due to bad searchDefaultNamespace implementation. return namespacePrototype; } } }
/* TODO: Marked deprecated by original author */ XMLName toXMLName(Context cx, Object nameValue) { XMLName result; if (nameValue instanceof XMLName) { result = (XMLName) nameValue; } else if (nameValue instanceof QName) { QName qname = (QName) nameValue; result = XMLName.formProperty(qname.uri(), qname.localName()); } else if (nameValue instanceof String) { result = toXMLNameFromString(cx, (String) nameValue); } else if (nameValue instanceof Boolean || nameValue instanceof Number || nameValue == Undefined.instance || nameValue == null) { throw badXMLName(nameValue); } else { String name = ScriptRuntime.toString(nameValue); result = toXMLNameFromString(cx, name); } return result; }
/** @deprecated */ XMLName toAttributeName(Context cx, Object nameValue) { if (nameValue instanceof XMLName) { // TODO Will this always be an XMLName of type attribute name? return (XMLName) nameValue; } else if (nameValue instanceof QName) { return XMLName.create(((QName) nameValue).getDelegate(), true, false); } else if (nameValue instanceof Boolean || nameValue instanceof Number || nameValue == Undefined.instance || nameValue == null) { throw badXMLName(nameValue); } else { // TODO Not 100% sure that putting these in global namespace is the right thing to do String localName = null; if (nameValue instanceof String) { localName = (String) nameValue; } else { localName = ScriptRuntime.toString(nameValue); } if (localName != null && localName.equals("*")) localName = null; return XMLName.create( XmlNode.QName.create(XmlNode.Namespace.create(""), localName), true, false); } }
@Override public synchronized Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Transaction previousTransaction = Transaction.currentTransaction(); Transaction.startTransaction(); String filename = (String) args[0]; if (filename.startsWith(".")) filename = currentJslibPath + filename; filename = Pattern.compile("\\.\\./[^.]*/").matcher(filename).replaceAll("/"); filename = filename.replace("./", ""); InputStream inStream; ScriptableObject exportObject; String oldJsLibPath = currentJslibPath; try { File jslibFile = jslibFiles.get(filename); if (jslibFile == null && !filename.endsWith(".js")) { filename += ".js"; jslibFile = jslibFiles.get(filename); } if (jslibFile == null) throw ScriptRuntime.constructError("Error", "File not found " + filename); exportObject = exports.get(filename); Long lastTimeStamp = lastTimeStamps.get(filename); if (lastTimeStamp == null || lastTimeStamp < jslibFile.lastModified()) { lastTimeStamps.put(filename, jslibFile.lastModified()); inStream = new FileInputStream(jslibFile); exportObject = new NativeObject(); ScriptRuntime.setObjectProtoAndParent((ScriptableObject) exportObject, global); // setup the module scope ScriptableObject moduleScope = new NativeObject(); moduleScope.setParentScope(global); int lastSlash = filename.lastIndexOf('/'); currentJslibPath = lastSlash == -1 ? "" : filename.substring(0, lastSlash + 1); moduleScope.put("exports", moduleScope, exportObject); // memoize exports.put(filename, exportObject); // evaluate the script try { cx.evaluateString(moduleScope, IOUtils.toString(inStream, "UTF-8"), filename, 1, null); } catch (RuntimeException e) { // revert exports.remove(filename); jslibFiles.put(filename, jslibFile); throw e; } // re-retrieve it in case the library changed it exportObject = (ScriptableObject) moduleScope.get("exports", moduleScope); exports.put(filename, exportObject); if ("jsgi-app.js".equals(filename)) { // handle jackconfig.js, setting up the app if it is there global.put("app", global, exportObject.get("app", exportObject)); } // freeze it // exportObject.sealObject(); } Transaction.currentTransaction().commit(); } catch (IOException e) { throw ScriptRuntime.constructError("Error", e.getMessage()); } finally { currentJslibPath = oldJsLibPath; previousTransaction.enterTransaction(); } return exportObject; }
public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw ScriptRuntime.typeError1("msg.not.ctor", "XMLList"); }
/** Analog of C match_or_replace. */ private static Object matchOrReplace( Context cx, Scriptable scope, Scriptable thisObj, Object[] args, RegExpImpl reImpl, GlobData data, boolean forceFlat) { NativeRegExp re; String str = ScriptRuntime.toString(thisObj); data.str = str; Scriptable topScope = ScriptableObject.getTopLevelScope(scope); if (args.length == 0) { Object compiled = NativeRegExp.compileRE(cx, "", "", false); re = new NativeRegExp(topScope, compiled); } else if (args[0] instanceof NativeRegExp) { re = (NativeRegExp) args[0]; } else { String src = ScriptRuntime.toString(args[0]); String opt; if (data.optarg < args.length) { args[0] = src; opt = ScriptRuntime.toString(args[data.optarg]); } else { opt = null; } Object compiled = NativeRegExp.compileRE(cx, src, opt, forceFlat); re = new NativeRegExp(topScope, compiled); } data.regexp = re; data.global = (re.getFlags() & NativeRegExp.JSREG_GLOB) != 0; int[] indexp = {0}; Object result = null; if (data.mode == RA_SEARCH) { result = re.executeRegExp(cx, scope, reImpl, str, indexp, NativeRegExp.TEST); if (result != null && result.equals(Boolean.TRUE)) result = new Integer(reImpl.leftContext.length); else result = new Integer(-1); } else if (data.global) { re.lastIndex = 0; for (int count = 0; indexp[0] <= str.length(); count++) { result = re.executeRegExp(cx, scope, reImpl, str, indexp, NativeRegExp.TEST); if (result == null || !result.equals(Boolean.TRUE)) break; if (data.mode == RA_MATCH) { match_glob(data, cx, scope, count, reImpl); } else { if (data.mode != RA_REPLACE) Kit.codeBug(); SubString lastMatch = reImpl.lastMatch; int leftIndex = data.leftIndex; int leftlen = lastMatch.index - leftIndex; data.leftIndex = lastMatch.index + lastMatch.length; replace_glob(data, cx, scope, reImpl, leftIndex, leftlen); } if (reImpl.lastMatch.length == 0) { if (indexp[0] == str.length()) break; indexp[0]++; } } } else { result = re.executeRegExp( cx, scope, reImpl, str, indexp, ((data.mode == RA_REPLACE) ? NativeRegExp.TEST : NativeRegExp.MATCH)); } return result; }
/** * 对Scriptable对象转换成相应的Java对象 * * <p>如果对象类型是数组,按下标数组和关联数组两种情况分别转换为Array和Map; 否则转换为对应的Java对象,或者是一个包含此对象所有属性的Map * * @param scriptObj 需要转换的Scriptable对象 * @param context 上下文 * @return return 转换后的Java对象 */ @SuppressWarnings({"rawtypes", "unchecked"}) private static Object scriptableToJava(ScriptableObject scriptObj, Context context) throws IllegalAccessException, NoSuchFieldException { // Array & Arguments if (ScriptRuntime.isArrayObject(scriptObj)) { final Object[] arrayElements = (Object[]) context.getElements(scriptObj); // If scriptObj is a associative arry, arrayElements.length will // always 0 // So if scriptObj is empty or index array, return true, else return // false if (scriptObj.getIds().length == 0 || arrayElements.length == scriptObj.getIds().length) { for (int i = 0; i < arrayElements.length; i++) { arrayElements[i] = jsToJava(arrayElements[i], context); } return arrayElements; } else { final Object[] ids = scriptObj.getIds(); final HashMap map = new HashMap(); for (int i = 0; i < ids.length; i++) { final String key = ids[i].toString(); Object value = scriptObj.get(key, scriptObj); // if value is UniqueTag, means index is numeric, // should get its value by index if (value.getClass().equals(UniqueTag.class)) { value = scriptObj.get(Integer.parseInt(key), scriptObj); } map.put(ids[i], jsToJava(value, context)); } return map; } } else { final String jsClassName = scriptObj.getClassName(); // If jsClassName is 'Object', means scriptObj could't directly // convert to a normal java object, in this case we // return a map contains all properties in this scriptable object. if ("Object".equals(jsClassName)) { final Object[] ids = scriptObj.getIds(); final HashMap map = new HashMap(); for (int i = 0; i < ids.length; i++) { final String key = ids[i].toString(); final Object value = scriptObj.get(key, scriptObj); map.put(key, jsToJava(value, context)); } return map; } // If jsClassName is 'Funtion' & instanceof NativeFunction, // means scriptObj is a function defined in script, // in this case we return a String present source of this function else if ("Function".equals(jsClassName) && scriptObj instanceof NativeFunction) { final NativeFunction func = (NativeFunction) scriptObj; return Decompiler.decompile( func.getEncodedSource(), Decompiler.TO_SOURCE_FLAG, new UintMap()); } // Else, we can covert it to a desired java object by // Context.jsToJava() else { final Class clazz = (Class) ScriptRuntime.class.getDeclaredField(jsClassName + "Class").get(scriptObj); return Context.jsToJava(scriptObj, clazz); } } }
/* * Analog of replace_glob() in jsstr.c */ private static void replace_glob( GlobData rdata, Context cx, Scriptable scope, RegExpImpl reImpl, int leftIndex, int leftlen) { int replen; String lambdaStr; if (rdata.lambda != null) { // invoke lambda function with args lastMatch, $1, $2, ... $n, // leftContext.length, whole string. SubString[] parens = reImpl.parens; int parenCount = (parens == null) ? 0 : parens.length; Object[] args = new Object[parenCount + 3]; args[0] = reImpl.lastMatch.toString(); for (int i = 0; i < parenCount; i++) { SubString sub = parens[i]; if (sub != null) { args[i + 1] = sub.toString(); } else { args[i + 1] = Undefined.instance; } } args[parenCount + 1] = new Integer(reImpl.leftContext.length); args[parenCount + 2] = rdata.str; // This is a hack to prevent expose of reImpl data to // JS function which can run new regexps modifing // regexp that are used later by the engine. // TODO: redesign is necessary if (reImpl != ScriptRuntime.getRegExpProxy(cx)) Kit.codeBug(); RegExpImpl re2 = new RegExpImpl(); re2.multiline = reImpl.multiline; re2.input = reImpl.input; ScriptRuntime.setRegExpProxy(cx, re2); try { Scriptable parent = ScriptableObject.getTopLevelScope(scope); Object result = rdata.lambda.call(cx, parent, parent, args); lambdaStr = ScriptRuntime.toString(result); } finally { ScriptRuntime.setRegExpProxy(cx, reImpl); } replen = lambdaStr.length(); } else { lambdaStr = null; replen = rdata.repstr.length(); if (rdata.dollar >= 0) { int[] skip = new int[1]; int dp = rdata.dollar; do { SubString sub = interpretDollar(cx, reImpl, rdata.repstr, dp, skip); if (sub != null) { replen += sub.length - skip[0]; dp += skip[0]; } else { ++dp; } dp = rdata.repstr.indexOf('$', dp); } while (dp >= 0); } } int growth = leftlen + replen + reImpl.rightContext.length; StringBuffer charBuf = rdata.charBuf; if (charBuf == null) { charBuf = new StringBuffer(growth); rdata.charBuf = charBuf; } else { charBuf.ensureCapacity(rdata.charBuf.length() + growth); } charBuf.append(reImpl.leftContext.charArray, leftIndex, leftlen); if (rdata.lambda != null) { charBuf.append(lambdaStr); } else { do_replace(rdata, cx, reImpl); } }