git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@120 30ef5769-5b8d-40dd-aea6-55b5d6557bb3tags/rel_3_17_1_ga
@@ -255,10 +255,13 @@ see javassist.Dump. | |||
<h2>Changes</h2> | |||
<p>- version 3.0 | |||
<p>- version 3.0 beta 3 | |||
<ul> | |||
<li>CtClass.toClass() has been reimplemented. | |||
<li>CtClass.toClass() has been reimplemented. The behavior has been | |||
changed. | |||
<li>javassist.expr.NewArray has been implemented. It enables modifying | |||
an expression for array creation. | |||
</ul> | |||
<p>- version 3.0 beta in May 18th, 2004. |
@@ -511,6 +511,35 @@ public class Descriptor { | |||
return type; | |||
} | |||
/** | |||
* Computes the dimension of the array represented by the given | |||
* descriptor. For example, if the descriptor is <code>"[[I"</code>, | |||
* then this method returns 2. | |||
* | |||
* @param desc the descriptor. | |||
* @return 0 if the descriptor does not represent an array type. | |||
*/ | |||
public static int arrayDimension(String desc) { | |||
int dim = 0; | |||
while (desc.charAt(dim) == '[') | |||
++dim; | |||
return dim; | |||
} | |||
/** | |||
* Returns the descriptor of the type of the array component. | |||
* For example, if the given descriptor is | |||
* <code>"[[Ljava/lang/String;"</code> and the given dimension is 2, | |||
* then this method returns <code>"Ljava/lang/String;"</code>. | |||
* | |||
* @param desc the descriptor. | |||
* @param dim the array dimension. | |||
*/ | |||
public static String toArrayComponent(String desc, int dim) { | |||
return desc.substring(dim); | |||
} | |||
/** | |||
* Computes the data size specified by the given descriptor. | |||
* For example, if the descriptor is "D", this method returns 2. |
@@ -323,6 +323,7 @@ public class Javac { | |||
* parameters. $args represents an array of all the parameters. | |||
* It also makes $$ available as a parameter list of method call. | |||
* $0 can represent a local variable other than THIS (variable 0). | |||
* $class is also made available. | |||
* | |||
* <p>This must be called before calling <code>compileStmnt()</code> and | |||
* <code>compileExpr()</code>. The correct value of | |||
@@ -332,6 +333,8 @@ public class Javac { | |||
* @param varNo the register number of $0 (use0 is true) | |||
* or $1 (otherwise). | |||
* @param target the type of $0 (it can be null if use0 is false). | |||
* It is used as the name of the type represented | |||
* by $class. | |||
* @param isStatic true if the method in which the compiled bytecode | |||
* is embedded is static. | |||
*/ | |||
@@ -345,14 +348,17 @@ public class Javac { | |||
/** | |||
* Prepares to use cast $r, $w, $_, and $type. | |||
* $type is made to represent the specified return type. | |||
* It also enables to write a return statement with a return value | |||
* for void method. | |||
* | |||
* <p>If the return type is void, ($r) does nothing. | |||
* The type of $_ is java.lang.Object. | |||
* | |||
* @param type the return type. | |||
* @param useResultVar true if $_ is used. | |||
* @return -1 or the variable index assigned to $_. | |||
* @see #recordType(CtClass) | |||
*/ | |||
public int recordReturnType(CtClass type, boolean useResultVar) | |||
throws CompileError | |||
@@ -365,6 +371,8 @@ public class Javac { | |||
/** | |||
* Prepares to use $type. Note that recordReturnType() overwrites | |||
* the value of $type. | |||
* | |||
* @param t the type represented by $type. | |||
*/ | |||
public void recordType(CtClass t) { | |||
gen.recordType(t); |
@@ -458,7 +458,7 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
/** | |||
* Makes method parameters $0, $1, ..., $args, and $$ available. | |||
* Makes method parameters $0, $1, ..., $args, $$, and $class available. | |||
* $0 is equivalent to THIS if the method is not static. Otherwise, | |||
* if the method is static, then $0 is not available. | |||
*/ | |||
@@ -472,15 +472,20 @@ public class JvstCodeGen extends MemberCodeGen { | |||
} | |||
/** | |||
* Makes method parameters $0, $1, ..., $args, and $$ available. | |||
* Makes method parameters $0, $1, ..., $args, $$, and $class available. | |||
* $0 is available only if use0 is true. It might not be equivalent | |||
* to THIS. | |||
* | |||
* @paaram use0 true if $0 is used. | |||
* @param params the parameter types (the types of $1, $2, ..) | |||
* @param prefix it must be "$" (the first letter of $0, $1, ...) | |||
* @param paramVarName it must be "$args" | |||
* @param paramsName it must be "$$" | |||
* @param use0 true if $0 is used. | |||
* @param paramBase the register number of $0 (use0 is true) | |||
* or $1 (otherwise). | |||
* @param target the class of $0. If use0 is false, target | |||
* can be null. | |||
* can be null. The value of "target" is also used | |||
* as the name of the type represented by $class. | |||
* @param isStatic true if the method in which the compiled bytecode | |||
* is embedded is static. | |||
*/ | |||
@@ -499,7 +504,8 @@ public class JvstCodeGen extends MemberCodeGen { | |||
paramVarBase = paramBase; | |||
useParam0 = use0; | |||
param0Type = MemberResolver.jvmToJavaName(target); | |||
if (target != null) | |||
param0Type = MemberResolver.jvmToJavaName(target); | |||
inStaticMethod = isStatic; | |||
varNo = paramBase; |
@@ -108,44 +108,57 @@ public class ExprEditor { | |||
int pos = iterator.next(); | |||
int c = iterator.byteAt(pos); | |||
if (c == Opcode.INVOKESTATIC || c == Opcode.INVOKEINTERFACE | |||
|| c == Opcode.INVOKEVIRTUAL) { | |||
expr = new MethodCall(pos, iterator, clazz, minfo); | |||
edit((MethodCall)expr); | |||
} | |||
else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC | |||
|| c == Opcode.PUTFIELD || c == Opcode.PUTSTATIC) { | |||
expr = new FieldAccess(pos, iterator, clazz, minfo, c); | |||
edit((FieldAccess)expr); | |||
} | |||
else if (c == Opcode.NEW) { | |||
int index = iterator.u16bitAt(pos + 1); | |||
newList = new NewOp(newList, pos, | |||
cp.getClassInfo(index)); | |||
} | |||
else if (c == Opcode.INVOKESPECIAL) { | |||
if (newList != null && cp.isConstructor(newList.type, | |||
iterator.u16bitAt(pos + 1)) > 0) { | |||
expr = new NewExpr(pos, iterator, clazz, minfo, | |||
newList.type, newList.pos); | |||
edit((NewExpr)expr); | |||
newList = newList.next; | |||
} | |||
else { | |||
if (c < Opcode.GETSTATIC) // c < 178 | |||
/* skip */; | |||
else if (c < Opcode.NEWARRAY) { // c < 188 | |||
if (c == Opcode.INVOKESTATIC | |||
|| c == Opcode.INVOKEINTERFACE | |||
|| c == Opcode.INVOKEVIRTUAL) { | |||
expr = new MethodCall(pos, iterator, clazz, minfo); | |||
MethodCall mcall = (MethodCall)expr; | |||
if (!mcall.getMethodName().equals( | |||
edit((MethodCall)expr); | |||
} | |||
else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC | |||
|| c == Opcode.PUTFIELD | |||
|| c == Opcode.PUTSTATIC) { | |||
expr = new FieldAccess(pos, iterator, clazz, minfo, c); | |||
edit((FieldAccess)expr); | |||
} | |||
else if (c == Opcode.NEW) { | |||
int index = iterator.u16bitAt(pos + 1); | |||
newList = new NewOp(newList, pos, | |||
cp.getClassInfo(index)); | |||
} | |||
else if (c == Opcode.INVOKESPECIAL) { | |||
if (newList != null && cp.isConstructor(newList.type, | |||
iterator.u16bitAt(pos + 1)) > 0) { | |||
expr = new NewExpr(pos, iterator, clazz, minfo, | |||
newList.type, newList.pos); | |||
edit((NewExpr)expr); | |||
newList = newList.next; | |||
} | |||
else { | |||
expr = new MethodCall(pos, iterator, clazz, minfo); | |||
MethodCall mcall = (MethodCall)expr; | |||
if (!mcall.getMethodName().equals( | |||
MethodInfo.nameInit)) | |||
edit(mcall); | |||
edit(mcall); | |||
} | |||
} | |||
} | |||
else if (c == Opcode.INSTANCEOF) { | |||
expr = new Instanceof(pos, iterator, clazz, minfo); | |||
edit((Instanceof)expr); | |||
} | |||
else if (c == Opcode.CHECKCAST) { | |||
expr = new Cast(pos, iterator, clazz, minfo); | |||
edit((Cast)expr); | |||
else { // c >= 188 | |||
if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY | |||
|| c == Opcode.MULTIANEWARRAY) { | |||
expr = new NewArray(pos, iterator, clazz, minfo, c); | |||
edit((NewArray)expr); | |||
} | |||
else if (c == Opcode.INSTANCEOF) { | |||
expr = new Instanceof(pos, iterator, clazz, minfo); | |||
edit((Instanceof)expr); | |||
} | |||
else if (c == Opcode.CHECKCAST) { | |||
expr = new Cast(pos, iterator, clazz, minfo); | |||
edit((Cast)expr); | |||
} | |||
} | |||
if (expr != null && expr.edited()) { | |||
@@ -187,6 +200,15 @@ public class ExprEditor { | |||
*/ | |||
public void edit(NewExpr e) throws CannotCompileException {} | |||
/** | |||
* Edits an expression for array creation (overridable). | |||
* The default implementation performs nothing. | |||
* | |||
* @param a the <tt>new</tt> expression for creating an array. | |||
* @throws CannotCompileException | |||
*/ | |||
public void edit(NewArray a) throws CannotCompileException {} | |||
/** | |||
* Edits a method call (overridable). | |||
* The default implementation performs nothing. |
@@ -0,0 +1,281 @@ | |||
/* | |||
* Javassist, a Java-bytecode translator toolkit. | |||
* Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved. | |||
* | |||
* The contents of this file are subject to the Mozilla Public License Version | |||
* 1.1 (the "License"); you may not use this file except in compliance with | |||
* the License. Alternatively, the contents of this file may be used under | |||
* the terms of the GNU Lesser General Public License Version 2.1 or later. | |||
* | |||
* Software distributed under the License is distributed on an "AS IS" basis, | |||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||
* for the specific language governing rights and limitations under the | |||
* License. | |||
*/ | |||
package javassist.expr; | |||
import javassist.*; | |||
import javassist.bytecode.*; | |||
import javassist.compiler.*; | |||
import javassist.compiler.ast.ASTList; | |||
/** | |||
* Array creation. | |||
* | |||
* <p>This class does not provide methods for obtaining the initial | |||
* values of array elements. | |||
*/ | |||
public class NewArray extends Expr { | |||
int opcode; | |||
NewArray(int pos, CodeIterator i, CtClass declaring, MethodInfo m, | |||
int op) { | |||
super(pos, i, declaring, m); | |||
opcode = op; | |||
} | |||
/** | |||
* Returns the method or constructor containing the array creation | |||
* represented by this object. | |||
*/ | |||
public CtBehavior where() { return super.where(); } | |||
/** | |||
* Returns the line number of the source line containing the | |||
* array creation. | |||
* | |||
* @return -1 if this information is not available. | |||
*/ | |||
public int getLineNumber() { | |||
return super.getLineNumber(); | |||
} | |||
/** | |||
* Returns the source file containing the array creation. | |||
* | |||
* @return null if this information is not available. | |||
*/ | |||
public String getFileName() { | |||
return super.getFileName(); | |||
} | |||
/** | |||
* Returns the list of exceptions that the expression may throw. | |||
* This list includes both the exceptions that the try-catch statements | |||
* including the expression can catch and the exceptions that | |||
* the throws declaration allows the method to throw. | |||
*/ | |||
public CtClass[] mayThrow() { | |||
return super.mayThrow(); | |||
} | |||
/** | |||
* Returns the type of array components. If the created array is | |||
* a two-dimensional array of <tt>int</tt>, | |||
* the type returned by this method is | |||
* not <tt>int[]</tt> but <tt>int</tt>. | |||
*/ | |||
public CtClass getComponentType() throws NotFoundException { | |||
if (opcode == Opcode.NEWARRAY) { | |||
int atype = iterator.byteAt(currentPos + 1); | |||
return getPrimitiveType(atype); | |||
} | |||
else if (opcode == Opcode.ANEWARRAY | |||
|| opcode == Opcode.MULTIANEWARRAY) { | |||
int index = iterator.u16bitAt(currentPos + 1); | |||
String desc = getConstPool().getClassInfo(index); | |||
int dim = Descriptor.arrayDimension(desc); | |||
desc = Descriptor.toArrayComponent(desc, dim); | |||
return Descriptor.toCtClass(desc, thisClass.getClassPool()); | |||
} | |||
else | |||
throw new RuntimeException("bad opcode: " + opcode); | |||
} | |||
CtClass getPrimitiveType(int atype) { | |||
switch (atype) { | |||
case Opcode.T_BOOLEAN : | |||
return CtClass.booleanType; | |||
case Opcode.T_CHAR : | |||
return CtClass.charType; | |||
case Opcode.T_FLOAT : | |||
return CtClass.floatType; | |||
case Opcode.T_DOUBLE : | |||
return CtClass.doubleType; | |||
case Opcode.T_BYTE : | |||
return CtClass.byteType; | |||
case Opcode.T_SHORT : | |||
return CtClass.shortType; | |||
case Opcode.T_INT : | |||
return CtClass.intType; | |||
case Opcode.T_LONG : | |||
return CtClass.longType; | |||
default : | |||
throw new RuntimeException("bad atype: " + atype); | |||
} | |||
} | |||
/** | |||
* Returns the dimension of the created array. | |||
*/ | |||
public int getDimension() { | |||
if (opcode == Opcode.NEWARRAY) | |||
return 1; | |||
else if (opcode == Opcode.ANEWARRAY | |||
|| opcode == Opcode.MULTIANEWARRAY) { | |||
int index = iterator.u16bitAt(currentPos + 1); | |||
String desc = getConstPool().getClassInfo(index); | |||
return Descriptor.arrayDimension(desc) | |||
+ (opcode == Opcode.ANEWARRAY ? 1 : 0); | |||
} | |||
else | |||
throw new RuntimeException("bad opcode: " + opcode); | |||
} | |||
/** | |||
* Returns the number of dimensions of arrays to be created. | |||
* If the opcode is multianewarray, this method returns the second | |||
* operand. Otherwise, it returns 1. | |||
*/ | |||
public int getCreatedDimensions() { | |||
if (opcode == Opcode.MULTIANEWARRAY) | |||
return iterator.byteAt(currentPos + 3); | |||
else | |||
return 1; | |||
} | |||
/** | |||
* Replaces the array creation with the bytecode derived from | |||
* the given source text. | |||
* | |||
* <p>$0 is available even if the called method is static. | |||
* If the field access is writing, $_ is available but the value | |||
* of $_ is ignored. | |||
* | |||
* @param statement a Java statement. | |||
*/ | |||
public void replace(String statement) throws CannotCompileException { | |||
try { | |||
replace2(statement); | |||
} | |||
catch (CompileError e) { throw new CannotCompileException(e); } | |||
catch (NotFoundException e) { throw new CannotCompileException(e); } | |||
catch (BadBytecode e) { | |||
throw new CannotCompileException("broken method"); | |||
} | |||
} | |||
private void replace2(String statement) | |||
throws CompileError, NotFoundException, BadBytecode, | |||
CannotCompileException | |||
{ | |||
ConstPool constPool = getConstPool(); | |||
int pos = currentPos; | |||
CtClass retType; | |||
int codeLength; | |||
int index = 0; | |||
int dim = 1; | |||
String desc; | |||
if (opcode == Opcode.NEWARRAY) { | |||
index = iterator.byteAt(currentPos + 1); // atype | |||
CtPrimitiveType cpt = (CtPrimitiveType)getPrimitiveType(index); | |||
desc = "[" + cpt.getDescriptor(); | |||
codeLength = 2; | |||
} | |||
else if (opcode == Opcode.ANEWARRAY) { | |||
index = iterator.u16bitAt(pos + 1); | |||
desc = constPool.getClassInfo(index); | |||
if (desc.startsWith("[")) | |||
desc = "[" + desc; | |||
else | |||
desc = "[L" + desc + ";"; | |||
codeLength = 3; | |||
} | |||
else if (opcode == Opcode.MULTIANEWARRAY) { | |||
index = iterator.u16bitAt(currentPos + 1); | |||
desc = constPool.getClassInfo(index); | |||
dim = iterator.byteAt(currentPos + 3); | |||
codeLength = 4; | |||
} | |||
else | |||
throw new RuntimeException("bad opcode: " + opcode); | |||
retType = Descriptor.toCtClass(desc, thisClass.getClassPool()); | |||
Javac jc = new Javac(thisClass); | |||
CodeAttribute ca = iterator.get(); | |||
CtClass[] params = new CtClass[dim]; | |||
for (int i = 0; i < dim; ++i) | |||
params[i] = CtClass.intType; | |||
int paramVar = ca.getMaxLocals(); | |||
jc.recordParams(javaLangObject, params, | |||
true, paramVar, withinStatic()); | |||
/* Is $_ included in the source code? | |||
*/ | |||
checkResultValue(retType, statement); | |||
int retVar = jc.recordReturnType(retType, true); | |||
jc.recordProceed(new ProceedForArray(retType, opcode, index, dim)); | |||
Bytecode bytecode = jc.getBytecode(); | |||
storeStack(params, true, paramVar, bytecode); | |||
jc.recordLocalVariables(ca, pos); | |||
bytecode.addOpcode(ACONST_NULL); // initialize $_ | |||
bytecode.addAstore(retVar); | |||
jc.compileStmnt(statement); | |||
bytecode.addAload(retVar); | |||
replace0(pos, bytecode, codeLength); | |||
} | |||
/* <array type> $proceed(<dim> ..) | |||
*/ | |||
static class ProceedForArray implements ProceedHandler { | |||
CtClass arrayType; | |||
int opcode; | |||
int index, dimension; | |||
ProceedForArray(CtClass type, int op, int i, int dim) { | |||
arrayType = type; | |||
opcode = op; | |||
index = i; | |||
dimension = dim; | |||
} | |||
public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args) | |||
throws CompileError | |||
{ | |||
int num = gen.getMethodArgsLength(args); | |||
if (num != dimension) | |||
throw new CompileError(Javac.proceedName | |||
+ "() with a wrong number of parameters"); | |||
gen.atMethodArgs(args, new int[num], | |||
new int[num], new String[num]); | |||
bytecode.addOpcode(opcode); | |||
if (opcode == Opcode.ANEWARRAY) | |||
bytecode.addIndex(index); | |||
else if (opcode == Opcode.NEWARRAY) | |||
bytecode.add(index); | |||
else /* if (opcode == Opcode.MULTIANEWARRAY) */ { | |||
bytecode.addIndex(index); | |||
bytecode.add(dimension); | |||
bytecode.growStack(1 - dimension); | |||
} | |||
gen.setType(arrayType); | |||
} | |||
public void setReturnType(JvstTypeChecker c, ASTList args) | |||
throws CompileError | |||
{ | |||
c.setType(arrayType); | |||
} | |||
} | |||
} |
@@ -516,6 +516,7 @@ variable is available only in <code>insertAfter()</code> in | |||
<p>The value of <code>$class</code> is an <code>java.lang.Class</code> | |||
object representing the class in which the edited method is declared. | |||
This represents the type of <code>$0</code>. | |||
<h4>addCatch()</h4> | |||
@@ -613,10 +614,13 @@ the formal result type.</td> | |||
<tr> | |||
<td><code>$class</code></td> | |||
<td>A <code>java.lang.Class</code> object representing | |||
the class currently edited.</td> | |||
<td rowspan=2>A <code>java.lang.Class</code> object representing | |||
the class that declares the method<br> | |||
currently edited (the type of $0).</td> | |||
</tr> | |||
<tr><td> </td></tr> | |||
</table> | |||
</ul> | |||
@@ -795,8 +799,9 @@ The method <code>replace()</code> in | |||
source text representing the substitued statement or | |||
block for the field access. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have also special meaning: | |||
have special meaning: | |||
<ul><table border=0> | |||
<tr> | |||
@@ -875,7 +880,7 @@ is the type of the field. | |||
<h4>javassist.expr.NewExpr</h4> | |||
<p>A <code>NewExpr</code> object represents object creation | |||
with the <code>new</code> operator. | |||
with the <code>new</code> operator (not including array creation). | |||
The method <code>edit()</code> in <code>ExprEditor</code> | |||
receives this object if object creation is found. | |||
The method <code>replace()</code> in | |||
@@ -883,8 +888,9 @@ The method <code>replace()</code> in | |||
source text representing the substitued statement or | |||
block for the object creation. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have also special meaning: | |||
have special meaning: | |||
<ul><table border=0> | |||
@@ -919,16 +925,16 @@ The type of the created object. | |||
</td> | |||
</tr> | |||
<tr><td><code>$class</code>    </td> | |||
<td>A <code>java.lang.Class</code> object representing | |||
the class of the created object. | |||
</td></tr> | |||
<tr><td><code>$sig</code>    </td> | |||
<td>An array of <code>java.lang.Class</code> objects representing | |||
the formal parameter types.</td> | |||
</tr> | |||
<tr><td><code>$type</code>    </td> | |||
<td>A <code>java.lang.Class</code> object representing | |||
the class of the created object. | |||
</td></tr> | |||
<tr><td><code>$proceed</code>    </td> | |||
<td>The name of a virtual method executing the original | |||
object creation. | |||
@@ -942,6 +948,88 @@ object creation. | |||
<code>$args</code> and <code>$$</code> | |||
are also available. | |||
<h4>javassist.expr.NewArray</h4> | |||
<p>A <code>NewArray</code> object represents array creation | |||
with the <code>new</code> operator. | |||
The method <code>edit()</code> in <code>ExprEditor</code> | |||
receives this object if array creation is found. | |||
The method <code>replace()</code> in | |||
<code>NewArray</code> receives | |||
source text representing the substitued statement or | |||
block for the array creation. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have special meaning: | |||
<ul><table border=0> | |||
<tr> | |||
<td><code>$0</code></td> | |||
<td> | |||
<code>null</code>. | |||
</td> | |||
</tr> | |||
<tr> | |||
<td><code>$1</code>, <code>$2</code>, ...    </td> | |||
<td> | |||
The size of each dimension. | |||
</td> | |||
</tr> | |||
<tr> | |||
<td><code>$_</code></td> | |||
<td rowspan=2> | |||
The resulting value of the array creation. | |||
<br>A newly created array must be stored in this variable. | |||
</td> | |||
</tr> | |||
<tr><td> </td></tr> | |||
<tr> | |||
<td><code>$r</code></td> | |||
<td> | |||
The type of the created array. | |||
</td> | |||
</tr> | |||
<tr><td><code>$type</code>    </td> | |||
<td>A <code>java.lang.Class</code> object representing | |||
the class of the created array. | |||
</td></tr> | |||
<tr><td><code>$proceed</code>    </td> | |||
<td>The name of a virtual method executing the original | |||
array creation. | |||
.</td> | |||
</tr> | |||
</table> | |||
</ul> | |||
<p>The other identifiers such as <code>$w</code>, | |||
<code>$args</code> and <code>$$</code> | |||
are also available. | |||
<p>For example, if the array creation is the following expression, | |||
<ul><pre> | |||
String[][] s = new String[3][4]; | |||
</pre></ul> | |||
then the value of $1 and $2 are 3 and 4, respectively. $3 is not available. | |||
<p>If the array creation is the following expression, | |||
<ul><pre> | |||
String[][] s = new String[3][]; | |||
</pre></ul> | |||
then the value of $1 is 3 but $2 is not available. | |||
<h4>javassist.expr.Instanceof</h4> | |||
<p>A <code>Instanceof</code> object represents an <code>instanceof</code> | |||
@@ -953,8 +1041,9 @@ The method <code>replace()</code> in | |||
source text representing the substitued statement or | |||
block for the expression. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have also special meaning: | |||
have special meaning: | |||
<ul><table border=0> | |||
@@ -1028,8 +1117,9 @@ The method <code>replace()</code> in | |||
source text representing the substitued statement or | |||
block for the expression. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have also special meaning: | |||
have special meaning: | |||
<ul><table border=0> | |||
@@ -1103,8 +1193,9 @@ The method <code>insertBefore()</code> in | |||
<code>Handler</code> compiles the received | |||
source text and inserts it at the beginning of the <code>catch</code> clause. | |||
<p> | |||
In the source text, the identifiers starting with <code>$</code> | |||
have special meaning: | |||
have meaning: | |||
<ul><table border=0> | |||