From aa3ce8fddce359ae3c0a43842e58cbd47f4a3f40 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Fri, 18 Oct 2024 16:13:40 +0200 Subject: [PATCH] docs, cleanup --- .../org/perlonjava/runtime/RuntimeCode.java | 102 ++++++-- .../runtime/RuntimeDataProvider.java | 97 +++++--- .../org/perlonjava/runtime/RuntimeGlob.java | 116 +++++++-- .../org/perlonjava/runtime/RuntimeHash.java | 234 ++++++++++++++++-- .../runtime/RuntimeScalarCache.java | 34 ++- .../runtime/RuntimeScalarReadOnly.java | 48 ++++ .../runtime/RuntimeTransliterate.java | 61 ++++- 7 files changed, 583 insertions(+), 109 deletions(-) diff --git a/src/main/java/org/perlonjava/runtime/RuntimeCode.java b/src/main/java/org/perlonjava/runtime/RuntimeCode.java index d8663a8c..dfd5aff6 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeCode.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeCode.java @@ -14,43 +14,73 @@ import java.util.HashMap; import java.util.List; +/** + * The RuntimeCode class represents a compiled code object in the runtime environment. + * It provides functionality to compile, store, and execute Perl subroutines and eval strings. + */ public class RuntimeCode implements RuntimeScalarReference { // Temporary storage for anonymous subroutines and eval string compiler context public static HashMap> anonSubs = new HashMap<>(); // temp storage for makeCodeObject() public static HashMap evalContext = new HashMap<>(); // storage for eval string compiler context + + // Method object representing the compiled subroutine public Method methodObject; - public Object codeObject; // apply() needs this + // Code object instance used during execution + public Object codeObject; + // Prototype of the subroutine public String prototype; + // Attributes associated with the subroutine public List attributes = new ArrayList<>(); + /** + * Constructs a RuntimeCode instance with the specified prototype and attributes. + * + * @param prototype the prototype of the subroutine + * @param attributes the attributes associated with the subroutine + */ public RuntimeCode(String prototype, List attributes) { this.prototype = prototype; this.attributes = attributes; } + /** + * Constructs a RuntimeCode instance with the specified method object and code object. + * + * @param methodObject the method object representing the compiled subroutine + * @param codeObject the code object instance used during execution + */ public RuntimeCode(Method methodObject, Object codeObject) { this.methodObject = methodObject; this.codeObject = codeObject; } + /** + * Constructs a RuntimeCode instance with the specified method object, code object, and prototype. + * + * @param methodObject the method object representing the compiled subroutine + * @param codeObject the code object instance used during execution + * @param prototype the prototype of the subroutine + */ public RuntimeCode(Method methodObject, Object codeObject, String prototype) { this.methodObject = methodObject; this.codeObject = codeObject; this.prototype = prototype; } - // Method to compile the text of eval string into a Class that - // represents an anonymous subroutine. - // - // After the Class returns to the caller, an instance of the Class - // will be populated with closure variables, and then - // makeCodeObject() will be called to transform the Class instance - // into a Perl CODE object - // + /** + * Compiles the text of an eval string into a Class that represents an anonymous subroutine. + * After the Class is returned to the caller, an instance of the Class will be populated + * with closure variables, and then makeCodeObject() will be called to transform the Class + * instance into a Perl CODE object. + * + * @param code the RuntimeScalar containing the eval string + * @param evalTag the tag used to retrieve the eval context + * @return the compiled Class representing the anonymous subroutine + * @throws Exception if an error occurs during compilation + */ public static Class evalStringHelper(RuntimeScalar code, String evalTag) throws Exception { - - // retrieve the eval context that was saved at program compile-time + // Retrieve the eval context that was saved at program compile-time EmitterContext ctx = RuntimeCode.evalContext.get(evalTag); ScopedSymbolTable symbolTable = ctx.symbolTable.clone(); @@ -87,7 +117,7 @@ public static Class evalStringHelper(RuntimeScalar code, String evalTag) thro true // use try-catch ); } catch (Exception e) { - // compilation error in eval-string + // Compilation error in eval-string // Set the global error variable "$@" using GlobalContext.setGlobalVariable(key, value) GlobalContext.getGlobalVariable("main::@").set(e.toString()); @@ -105,12 +135,15 @@ public static Class evalStringHelper(RuntimeScalar code, String evalTag) thro return generatedClass; } - // Factory method to create a CODE object (anonymous subroutine) - // - // This is called right after a new Class is compiled. - // - // codeObject is an instance of the new Class, with the closure variables in place. - // + /** + * Factory method to create a CODE object (anonymous subroutine). + * This is called right after a new Class is compiled. + * The codeObject is an instance of the new Class, with the closure variables in place. + * + * @param codeObject the instance of the compiled Class + * @return a RuntimeScalar representing the CODE object + * @throws Exception if an error occurs during method retrieval + */ public static RuntimeScalar makeCodeObject(Object codeObject) throws Exception { // Retrieve the class of the provided code object Class clazz = codeObject.getClass(); @@ -125,10 +158,15 @@ public static RuntimeScalar makeCodeObject(Object codeObject) throws Exception { return new RuntimeScalar(new RuntimeCode(mm, codeObject)); } - // Method to apply (execute) a subroutine reference + /** + * Method to apply (execute) a subroutine reference. + * Invokes the method associated with the code object, passing the RuntimeArray and RuntimeContextType as arguments. + * + * @param a the RuntimeArray containing the arguments for the subroutine + * @param callContext the context in which the subroutine is called + * @return the result of the subroutine execution as a RuntimeList + */ public RuntimeList apply(RuntimeArray a, int callContext) { - // Invoke the method associated with the code object, passing the RuntimeArray and RuntimeContextType as arguments - // This executes the subroutine and returns the result, which is expected to be a RuntimeList try { return (RuntimeList) this.methodObject.invoke(this.codeObject, a, callContext); } catch (Exception e) { @@ -136,19 +174,39 @@ public RuntimeList apply(RuntimeArray a, int callContext) { } } + /** + * Returns a string representation of the CODE reference. + * + * @return a string representing the CODE reference + */ public String toStringRef() { return "CODE(" + this.hashCode() + ")"; } + /** + * Returns an integer representation of the CODE reference. + * + * @return an integer representing the CODE reference + */ public int getIntRef() { return this.hashCode(); } + /** + * Returns a double representation of the CODE reference. + * + * @return a double representing the CODE reference + */ public double getDoubleRef() { return this.hashCode(); } + /** + * Returns a boolean representation of the CODE reference. + * + * @return true, indicating the presence of the CODE reference + */ public boolean getBooleanRef() { return true; } -} +} \ No newline at end of file diff --git a/src/main/java/org/perlonjava/runtime/RuntimeDataProvider.java b/src/main/java/org/perlonjava/runtime/RuntimeDataProvider.java index dab41904..362dc330 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeDataProvider.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeDataProvider.java @@ -3,126 +3,155 @@ import java.util.Iterator; /** - * RuntimeDataProvider interface defines methods for obtaining different types of runtime data. - * Classes implementing this interface should provide implementations for these methods. + * The RuntimeDataProvider interface defines methods for obtaining different types of runtime data. + * Classes implementing this interface should provide implementations for these methods to interact + * with various runtime data structures like arrays, lists, and scalars. */ public interface RuntimeDataProvider { /** * Retrieves a RuntimeArray of aliases instance. - * This is used to build the subroutine call parameter list `@_` + * This is used to build the subroutine call parameter list `@_`. * - * @return a RuntimeArray object. + * @return a RuntimeArray object representing the array of aliases */ RuntimeArray getArrayOfAlias(); /** - * Push the data into a RuntimeArray of aliases instance. - * This provides data to getArrayOfAlias() and to iterator() + * Pushes the data into a RuntimeArray of aliases instance. + * This provides data to getArrayOfAlias() and to iterator(). * - * @return a RuntimeArray object. + * @param arr the RuntimeArray to be set as the array of aliases + * @return the updated RuntimeArray object */ RuntimeArray setArrayOfAlias(RuntimeArray arr); /** * Retrieves a RuntimeList instance. - * This is always called at the end of a subroutine to transform the return value to RuntimeList + * This is always called at the end of a subroutine to transform the return value to RuntimeList. * - * @return a RuntimeList object. + * @return a RuntimeList object representing the list of elements */ RuntimeList getList(); /** * Retrieves a RuntimeScalar instance. * - * @return a RuntimeScalar object. + * @return a RuntimeScalar object representing the scalar value */ RuntimeScalar scalar(); + /** + * Retrieves the boolean value of the object. + * + * @return a boolean representing the truthiness of the object + */ boolean getBoolean(); + /** + * Retrieves the defined boolean value of the object. + * + * @return a boolean indicating whether the object is defined + */ boolean getDefinedBoolean(); /** - * Create a reference + * Creates a reference to the current object. + * + * @return a RuntimeScalar representing the reference */ RuntimeScalar createReference(); /** - * Add itself to a RuntimeArray. + * Adds itself to a RuntimeArray. * - * @param array The RuntimeArray object + * @param array the RuntimeArray object to which this entity will be added */ void addToArray(RuntimeArray array); /** - * Add itself to a RuntimeList. + * Adds itself to a RuntimeList. * - * @param list The RuntimeList object + * @param list the RuntimeList object to which this entity will be added */ void addToList(RuntimeList list); /** - * Count the number of RuntimeScalar elements. + * Counts the number of RuntimeScalar elements. + * + * @return the number of elements as an integer */ int countElements(); - // Get the total number of elements in all elements of the list as a RuntimeScalar + /** + * Gets the total number of elements in all elements of the list as a RuntimeScalar. + * + * @return a RuntimeScalar representing the count of elements + */ RuntimeScalar count(); /** - * Add itself to a RuntimeScalar. + * Adds itself to a RuntimeScalar. * - * @param scalar The RuntimeScalar object - * @return scalar + * @param scalar the RuntimeScalar object to which this entity will be added + * @return the updated RuntimeScalar object */ RuntimeScalar addToScalar(RuntimeScalar scalar); /** - * Set itself to a RuntimeList. + * Sets itself from a RuntimeList. * - * @param list The RuntimeList object - * @return list + * @param list the RuntimeList object from which this entity will be set + * @return the updated RuntimeArray object */ RuntimeArray setFromList(RuntimeList list); /** - * Retrives the result of keys() as a RuntimeArray instance. + * Retrieves the result of keys() as a RuntimeArray instance. * - * @return a RuntimeList object. + * @return a RuntimeArray object representing the keys */ RuntimeArray keys(); /** - * Retrives the result of values() as a RuntimeArray instance. + * Retrieves the result of values() as a RuntimeArray instance. * - * @return a RuntimeArray object. + * @return a RuntimeArray object representing the values */ RuntimeArray values(); /** - * Retrives the result of each() as a RuntimeList instance. + * Retrieves the result of each() as a RuntimeList instance. * - * @return a RuntimeList object. + * @return a RuntimeList object representing the key-value pairs */ RuntimeList each(); + /** + * Performs the chop operation on the object. + * + * @return a RuntimeScalar representing the result of the chop operation + */ RuntimeScalar chop(); + /** + * Performs the chomp operation on the object. + * + * @return a RuntimeScalar representing the result of the chomp operation + */ RuntimeScalar chomp(); /** - * Method to return an iterator. + * Returns an iterator over the elements of type RuntimeScalar. * - * @return a Iterator + * @return an Iterator for iterating over the elements */ Iterator iterator(); /** - * undefine the elements of the object + * Undefines the elements of the object. * - * @return the object. + * @return the object after undefining its elements */ RuntimeDataProvider undefine(); } - diff --git a/src/main/java/org/perlonjava/runtime/RuntimeGlob.java b/src/main/java/org/perlonjava/runtime/RuntimeGlob.java index 8d8a55a2..149d34ef 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeGlob.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeGlob.java @@ -5,9 +5,11 @@ /** * Represents a runtime typeglob in Perl. Typeglobs are special symbols that can represent * all types of Perl variables (scalars, arrays, hashes, subroutines, filehandles) with the same name. + * This class provides methods to manipulate and interact with typeglobs in the runtime environment. */ public class RuntimeGlob extends RuntimeBaseEntity implements RuntimeScalarReference { + // The name of the typeglob public String globName; /** @@ -20,7 +22,14 @@ public RuntimeGlob(String globName) { this.globName = globName; } - // Setters + /** + * Sets the value of the typeglob based on the type of the provided RuntimeScalar. + * Supports setting CODE and GLOB types, with special handling for IO objects. + * + * @param value The RuntimeScalar value to set. + * @return The set RuntimeScalar value. + * @throws IllegalStateException if the typeglob assignment is not implemented for the given type. + */ public RuntimeScalar set(RuntimeScalar value) { // System.out.println("glob set " + value.type); switch (value.type) { @@ -43,10 +52,20 @@ public RuntimeScalar set(RuntimeScalar value) { // return value; } + /** + * Counts the number of elements in the typeglob. + * + * @return The number of elements, which is always 1 for a typeglob. + */ public int countElements() { return 1; } + /** + * Returns a string representation of the typeglob. + * + * @return A string in the format "*globName". + */ public String toString() { return "*" + this.globName; } @@ -91,11 +110,20 @@ public boolean getBooleanRef() { return true; } + /** + * Returns a boolean indicating whether the typeglob is defined. + * + * @return Always true, as typeglobs are always considered defined. + */ public boolean getDefinedBoolean() { return true; } - // Get the scalar value of the Scalar + /** + * Gets the scalar value of the typeglob. + * + * @return A RuntimeScalar representing the typeglob. + */ public RuntimeScalar scalar() { RuntimeScalar ret = new RuntimeScalar(); ret.type = RuntimeScalarType.GLOB; @@ -103,11 +131,20 @@ public RuntimeScalar scalar() { return ret; } + /** + * Retrieves the boolean value of the typeglob. + * + * @return Always true, indicating the presence of the typeglob. + */ public boolean getBoolean() { return true; } - // Create a reference + /** + * Creates a reference to the typeglob. + * + * @return A RuntimeScalar representing the reference to the typeglob. + */ public RuntimeScalar createReference() { RuntimeScalar ret = new RuntimeScalar(); ret.type = RuntimeScalarType.GLOBREFERENCE; @@ -115,64 +152,117 @@ public RuntimeScalar createReference() { return ret; } - // Get the list value of the Scalar + /** + * Gets the list value of the typeglob. + * + * @return A RuntimeList containing the scalar representation of the typeglob. + */ public RuntimeList getList() { return new RuntimeList(this.scalar()); } - // Add itself to a RuntimeArray. + /** + * Adds itself to a RuntimeArray. + * + * @param array The RuntimeArray to which this typeglob will be added. + */ public void addToArray(RuntimeArray array) { array.push(this.scalar()); } /** - * Add itself to a RuntimeScalar. + * Adds itself to a RuntimeScalar. * - * @param scalar The RuntimeScalar object + * @param scalar The RuntimeScalar to which this typeglob will be added. + * @return The updated RuntimeScalar. */ public RuntimeScalar addToScalar(RuntimeScalar scalar) { return scalar.set(this); } + /** + * Sets itself from a RuntimeList. + * + * @param value The RuntimeList from which this typeglob will be set. + * @return The updated RuntimeArray. + */ public RuntimeArray setFromList(RuntimeList value) { return new RuntimeArray(this.set(value.scalar())); } - // keys() operator + /** + * The keys() operator for typeglobs. + * + * @return Throws an IllegalStateException as typeglobs do not support keys. + */ public RuntimeArray keys() { throw new IllegalStateException("Type of arg 1 to values must be hash or array"); } - // values() operator + /** + * The values() operator for typeglobs. + * + * @return Throws an IllegalStateException as typeglobs do not support values. + */ public RuntimeArray values() { throw new IllegalStateException("Type of arg 1 to values must be hash or array"); } + /** + * The each() operator for typeglobs. + * + * @return Throws an IllegalStateException as typeglobs do not support each. + */ public RuntimeList each() { throw new IllegalStateException("Type of arg 1 to each must be hash or array"); } + /** + * Performs the chop operation on the typeglob. + * + * @return Throws an IllegalStateException as chop is not implemented for typeglobs. + */ public RuntimeScalar chop() { throw new IllegalStateException("chop glob is not implemented"); } + /** + * Performs the chomp operation on the typeglob. + * + * @return Throws an IllegalStateException as chomp is not implemented for typeglobs. + */ public RuntimeScalar chomp() { throw new IllegalStateException("chomp glob is not implemented"); } - // Method to return an iterator + /** + * Returns an iterator over the elements of type RuntimeScalar. + * + * @return An Iterator for iterating over the elements. + */ public Iterator iterator() { return this.scalar().iterator(); } - // Get the Glob alias into an Array + /** + * Gets the Glob alias into an Array. + * + * @param arr The RuntimeArray to which the alias will be added. + * @return The updated RuntimeArray. + */ public RuntimeArray setArrayOfAlias(RuntimeArray arr) { arr.elements.add(this.scalar()); return arr; } + /** + * Undefines the elements of the typeglob. + * This method clears the CODE reference and invalidates the method resolution cache. + * + * @return The current RuntimeGlob instance after undefining its elements. + */ public RuntimeGlob undefine() { - // undefine CODE + // Undefine CODE GlobalContext.getGlobalCodeRef(this.globName).set(new RuntimeScalar()); // Invalidate the method resolution cache @@ -181,6 +271,4 @@ public RuntimeGlob undefine() { // XXX TODO undefine scalar, array, hash return this; } - } - diff --git a/src/main/java/org/perlonjava/runtime/RuntimeHash.java b/src/main/java/org/perlonjava/runtime/RuntimeHash.java index 479c70fa..72e0e2ac 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeHash.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeHash.java @@ -13,15 +13,25 @@ * any type of Perl scalar value. */ public class RuntimeHash extends RuntimeBaseEntity implements RuntimeScalarReference { + // Map to store the elements of the hash public Map elements; + // Iterator for traversing the hash elements Iterator hashIterator; - // Constructor + /** + * Constructor for RuntimeHash. + * Initializes an empty hash map to store elements. + */ public RuntimeHash() { this.elements = new HashMap<>(); } - // Create hash with the elements of a list + /** + * Creates a hash with the elements of a list. + * + * @param value The RuntimeDataProvider containing the elements to populate the hash. + * @return A new RuntimeHash populated with the elements from the list. + */ public static RuntimeHash createHash(RuntimeDataProvider value) { RuntimeHash result = new RuntimeHash(); Map resultHash = result.elements; @@ -34,16 +44,30 @@ public static RuntimeHash createHash(RuntimeDataProvider value) { return result; } - // Create hash reference with the elements of a list + /** + * Creates a hash reference with the elements of a list. + * + * @param value The RuntimeDataProvider containing the elements to populate the hash. + * @return A RuntimeScalar representing the hash reference. + */ public static RuntimeScalar createHashRef(RuntimeDataProvider value) { return createHash(value).createReference(); } + /** + * Counts the number of elements in the hash. + * + * @return The number of elements in the hash. + */ public int countElements() { return size(); } - // Add itself to a RuntimeArray. + /** + * Adds itself to a RuntimeArray. + * + * @param array The RuntimeArray to which this hash will be added. + */ public void addToArray(RuntimeArray array) { List elements = array.elements; for (Map.Entry entry : this.elements.entrySet()) { @@ -53,49 +77,82 @@ public void addToArray(RuntimeArray array) { } /** - * Add itself to a RuntimeScalar. + * Adds itself to a RuntimeScalar. * - * @param scalar The RuntimeScalar object + * @param scalar The RuntimeScalar to which this hash will be added. + * @return The updated RuntimeScalar. */ public RuntimeScalar addToScalar(RuntimeScalar scalar) { return scalar.set(this.scalar()); } - // Replace the whole hash with the elements of a list + /** + * Replaces the whole hash with the elements of a list. + * + * @param value The RuntimeList containing the elements to set in the hash. + * @return A RuntimeArray containing the updated hash. + */ public RuntimeArray setFromList(RuntimeList value) { RuntimeHash hash = createHash(value); this.elements = hash.elements; return new RuntimeArray(new RuntimeList(this)); } - // Add a key-value pair to the hash + /** + * Adds a key-value pair to the hash. + * + * @param key The key for the hash entry. + * @param value The value for the hash entry. + */ public void put(String key, RuntimeScalar value) { elements.put(key, value); } - // Get a value by key + /** + * Retrieves a value by key. + * + * @param key The key for the hash entry. + * @return The value associated with the key, or a proxy for lazy autovivification if the key does not exist. + */ public RuntimeScalar get(String key) { if (elements.containsKey(key)) { return elements.get(key); } - // lazy autovivification + // Lazy autovivification return new RuntimeHashProxy(this, key); } - // Get a value by key + /** + * Retrieves a value by key. + * + * @param keyScalar The RuntimeScalar representing the key for the hash entry. + * @return The value associated with the key, or a proxy for lazy autovivification if the key does not exist. + */ public RuntimeScalar get(RuntimeScalar keyScalar) { String key = keyScalar.toString(); if (elements.containsKey(key)) { return elements.get(key); } - // lazy autovivification + // Lazy autovivification return new RuntimeHashProxy(this, key); } + /** + * Checks if a key exists in the hash. + * + * @param key The RuntimeScalar representing the key to check. + * @return A RuntimeScalar indicating whether the key exists. + */ public RuntimeScalar exists(RuntimeScalar key) { return new RuntimeScalar(elements.containsKey(key.toString())); } + /** + * Deletes a key-value pair from the hash. + * + * @param key The RuntimeScalar representing the key to delete. + * @return The value associated with the deleted key, or an empty RuntimeScalar if the key did not exist. + */ public RuntimeScalar delete(RuntimeScalar key) { String k = key.toString(); if (elements.containsKey(k)) { @@ -104,7 +161,11 @@ public RuntimeScalar delete(RuntimeScalar key) { return new RuntimeScalar(); } - // Create a reference to the Hash + /** + * Creates a reference to the hash. + * + * @return A RuntimeScalar representing the hash reference. + */ public RuntimeScalar createReference() { RuntimeScalar result = new RuntimeScalar(); result.type = RuntimeScalarType.HASHREFERENCE; @@ -112,30 +173,57 @@ public RuntimeScalar createReference() { return result; } - // Get the size of the hash + /** + * Gets the size of the hash. + * + * @return The number of key-value pairs in the hash. + */ public int size() { return elements.size(); } + /** + * Retrieves the boolean value of the hash. + * + * @return True if the hash is not empty, false otherwise. + */ public boolean getBoolean() { return !elements.isEmpty(); } + /** + * Retrieves the defined boolean value of the hash. + * + * @return Always true, as hashes are always considered defined. + */ public boolean getDefinedBoolean() { return true; } - // Get the list value of the hash + /** + * Gets the list value of the hash. + * + * @return A RuntimeList containing the elements of the hash. + */ public RuntimeList getList() { return new RuntimeList(this); } - // Get the scalar value of the hash + /** + * Gets the scalar value of the hash. + * + * @return A RuntimeScalar representing the size of the hash. + */ public RuntimeScalar scalar() { return new RuntimeScalar(this.size()); } - // Slice the hash: @x{"a", "b"} + /** + * Slices the hash: @x{"a", "b"} + * + * @param value The RuntimeList containing the keys to slice. + * @return A RuntimeList containing the values associated with the specified keys. + */ public RuntimeList getSlice(RuntimeList value) { RuntimeList result = new RuntimeList(); List outElements = result.elements; @@ -146,6 +234,12 @@ public RuntimeList getSlice(RuntimeList value) { return result; } + /** + * Deletes a slice of the hash. + * + * @param value The RuntimeList containing the keys to delete. + * @return A RuntimeList containing the values associated with the deleted keys. + */ public RuntimeList deleteSlice(RuntimeList value) { RuntimeList result = new RuntimeList(); List outElements = result.elements; @@ -156,26 +250,39 @@ public RuntimeList deleteSlice(RuntimeList value) { return result; } - // keys() operator + /** + * The keys() operator for hashes. + * + * @return A RuntimeArray containing the keys of the hash. + */ public RuntimeArray keys() { RuntimeArray list = new RuntimeArray(); for (String key : elements.keySet()) { list.push(new RuntimeScalar(key)); } - hashIterator = null; // keys resets the iterator + hashIterator = null; // keys resets the iterator return list; } - // values() operator + /** + * The values() operator for hashes. + * + * @return A RuntimeArray containing the values of the hash. + */ public RuntimeArray values() { RuntimeArray list = new RuntimeArray(); for (RuntimeScalar value : elements.values()) { - list.push(value); // push an alias to the value + list.push(value); // push an alias to the value } - hashIterator = null; // values resets the iterator + hashIterator = null; // values resets the iterator return list; } + /** + * The each() operator for hashes. + * + * @return A RuntimeList containing the next key-value pair, or an empty list if the iterator is exhausted. + */ public RuntimeList each() { if (hashIterator == null) { hashIterator = iterator(); @@ -190,20 +297,38 @@ public RuntimeList each() { return new RuntimeList(); } + /** + * Performs the chop operation on the hash. + * + * @return A RuntimeScalar representing the result of the chop operation. + */ public RuntimeScalar chop() { return this.values().chop(); } + /** + * Performs the chomp operation on the hash. + * + * @return A RuntimeScalar representing the result of the chomp operation. + */ public RuntimeScalar chomp() { return this.values().chop(); } - // Method to return an iterator + /** + * Returns an iterator over the elements of type RuntimeScalar. + * + * @return An Iterator for iterating over the elements. + */ public Iterator iterator() { return new RuntimeHashIterator(); } - // Convert the hash to a string (for debugging purposes) + /** + * Converts the hash to a string (for debugging purposes). + * + * @return A string representation of the hash. + */ public String dump() { StringBuilder sb = new StringBuilder("{"); boolean first = true; @@ -218,28 +343,58 @@ public String dump() { return sb.toString(); } + /** + * Returns a string representation of the hash reference. + * + * @return A string in the format "HASH(hashCode)". + */ public String toStringRef() { return "HASH(" + this.hashCode() + ")"; } + /** + * Returns an integer representation of the hash reference. + * + * @return The hash code of this instance. + */ public int getIntRef() { return this.hashCode(); } + /** + * Returns a double representation of the hash reference. + * + * @return The hash code of this instance as a double. + */ public double getDoubleRef() { return this.hashCode(); } + /** + * Returns a boolean representation of the hash reference. + * + * @return Always true, indicating the presence of the hash reference. + */ public boolean getBooleanRef() { return true; } + /** + * Undefines the elements of the hash. + * This method clears all elements in the hash. + * + * @return The current RuntimeHash instance after undefining its elements. + */ public RuntimeHash undefine() { this.elements.clear(); return this; } - // Convert the hash to a string (for debugging purposes) + /** + * Converts the hash to a string (for debugging purposes). + * + * @return A string representation of the hash. + */ @Override public String toString() { StringBuilder sb = new StringBuilder(); @@ -249,7 +404,12 @@ public String toString() { return sb.toString(); } - // Get Hash aliases into an Array + /** + * Gets hash aliases into an array. + * + * @param arr The RuntimeArray to which the aliases will be added. + * @return The updated RuntimeArray. + */ public RuntimeArray setArrayOfAlias(RuntimeArray arr) { List arrElements = arr.elements; for (Map.Entry entry : this.elements.entrySet()) { @@ -259,22 +419,37 @@ public RuntimeArray setArrayOfAlias(RuntimeArray arr) { return arr; } - // Inner class implementing the Iterator interface + /** + * Inner class implementing the Iterator interface for iterating over hash elements. + */ private class RuntimeHashIterator implements Iterator { private final Iterator> entryIterator; private Map.Entry currentEntry; private boolean returnKey; + /** + * Constructs a RuntimeHashIterator for iterating over hash elements. + */ public RuntimeHashIterator() { this.entryIterator = elements.entrySet().iterator(); this.returnKey = true; } + /** + * Checks if there are more elements to iterate over. + * + * @return True if there are more elements, false otherwise. + */ @Override public boolean hasNext() { return (currentEntry != null && !returnKey) || entryIterator.hasNext(); } + /** + * Retrieves the next element in the iteration. + * + * @return The next RuntimeScalar element. + */ @Override public RuntimeScalar next() { if (returnKey) { @@ -287,6 +462,11 @@ public RuntimeScalar next() { } } + /** + * Remove operation is not supported for this iterator. + * + * @throws UnsupportedOperationException if called + */ @Override public void remove() { throw new UnsupportedOperationException("Remove not supported"); diff --git a/src/main/java/org/perlonjava/runtime/RuntimeScalarCache.java b/src/main/java/org/perlonjava/runtime/RuntimeScalarCache.java index d735ceac..883e91c9 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeScalarCache.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeScalarCache.java @@ -1,29 +1,54 @@ package org.perlonjava.runtime; +/** + * The RuntimeScalarCache class provides a caching mechanism for frequently used + * RuntimeScalar objects, such as small integers and common boolean values. + * This helps improve performance by reusing immutable scalar instances. + */ public class RuntimeScalarCache { + // Range of integers to cache static int minInt = -100; static int maxInt = 100; + // Array to store cached RuntimeScalarReadOnly objects for integers static RuntimeScalarReadOnly[] scalarInt = new RuntimeScalarReadOnly[maxInt - minInt + 1]; + // Cached RuntimeScalarReadOnly objects for common boolean and undefined values static RuntimeScalarReadOnly scalarTrue; static RuntimeScalarReadOnly scalarFalse; static RuntimeScalarReadOnly scalarUndef; static RuntimeScalarReadOnly scalarEmptyString; + // Static block to initialize the cache static { + // Cache integer values within the specified range for (int i = minInt; i <= maxInt; i++) { scalarInt[i - minInt] = new RuntimeScalarReadOnly(i); } + // Cache common boolean and undefined values scalarFalse = new RuntimeScalarReadOnly(false); scalarTrue = new RuntimeScalarReadOnly(true); scalarUndef = new RuntimeScalarReadOnly(); scalarEmptyString = new RuntimeScalarReadOnly(""); } + /** + * Retrieves a cached RuntimeScalar for the specified boolean value. + * + * @param b the boolean value + * @return the cached RuntimeScalar representing the boolean value + */ static RuntimeScalar getScalarBoolean(boolean b) { return b ? scalarTrue : scalarFalse; } + /** + * Retrieves a cached RuntimeScalar for the specified integer value. + * If the integer is within the cached range, a cached instance is returned; + * otherwise, a new RuntimeScalar is created. + * + * @param i the integer value + * @return the cached or newly created RuntimeScalar representing the integer value + */ public static RuntimeScalar getScalarInt(int i) { if (i >= minInt && i <= maxInt) { return scalarInt[i - minInt]; @@ -31,6 +56,14 @@ public static RuntimeScalar getScalarInt(int i) { return new RuntimeScalar(i); } + /** + * Retrieves a cached RuntimeScalar for the specified long integer value. + * If the long integer is within the cached range, a cached instance is returned; + * otherwise, a new RuntimeScalar is created. + * + * @param i the long integer value + * @return the cached or newly created RuntimeScalar representing the long integer value + */ static RuntimeScalar getScalarInt(long i) { if (i >= minInt && i <= maxInt) { return scalarInt[(int) i - minInt]; @@ -38,4 +71,3 @@ static RuntimeScalar getScalarInt(long i) { return new RuntimeScalar(i); } } - diff --git a/src/main/java/org/perlonjava/runtime/RuntimeScalarReadOnly.java b/src/main/java/org/perlonjava/runtime/RuntimeScalarReadOnly.java index abea4411..62d0fc51 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeScalarReadOnly.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeScalarReadOnly.java @@ -1,12 +1,20 @@ package org.perlonjava.runtime; +/** + * The RuntimeScalarReadOnly class represents an immutable scalar value in the runtime environment. + * It is used for caching and reusing common scalar values such as integers, booleans, and strings. + */ public class RuntimeScalarReadOnly extends RuntimeBaseProxy { + // Immutable fields representing the scalar value final boolean b; final int i; final String s; final double d; + /** + * Constructs a RuntimeScalarReadOnly representing an undefined value. + */ public RuntimeScalarReadOnly() { super(); this.b = false; @@ -17,6 +25,11 @@ public RuntimeScalarReadOnly() { this.type = RuntimeScalarType.UNDEF; } + /** + * Constructs a RuntimeScalarReadOnly representing an integer value. + * + * @param i the integer value + */ public RuntimeScalarReadOnly(int i) { super(); this.b = (i != 0); @@ -27,6 +40,11 @@ public RuntimeScalarReadOnly(int i) { this.type = RuntimeScalarType.INTEGER; } + /** + * Constructs a RuntimeScalarReadOnly representing a boolean value. + * + * @param b the boolean value + */ public RuntimeScalarReadOnly(boolean b) { super(); this.b = b; @@ -37,6 +55,11 @@ public RuntimeScalarReadOnly(boolean b) { this.type = RuntimeScalarType.INTEGER; } + /** + * Constructs a RuntimeScalarReadOnly representing a string value. + * + * @param s the string value + */ public RuntimeScalarReadOnly(String s) { super(); RuntimeScalar temp = new RuntimeScalar(s); @@ -48,26 +71,51 @@ public RuntimeScalarReadOnly(String s) { this.type = RuntimeScalarType.STRING; } + /** + * Throws an exception as this scalar is immutable and cannot be modified. + * + * @throws RuntimeException indicating that the constant item cannot be modified + */ @Override void vivify() { throw new RuntimeException("Can't modify constant item"); } + /** + * Retrieves the integer representation of the scalar. + * + * @return the integer value + */ @Override public int getInt() { return i; } + /** + * Retrieves the double representation of the scalar. + * + * @return the double value + */ @Override public double getDouble() { return d; } + /** + * Retrieves the string representation of the scalar. + * + * @return the string value + */ @Override public String toString() { return s; } + /** + * Retrieves the boolean representation of the scalar. + * + * @return the boolean value + */ @Override public boolean getBoolean() { return b; diff --git a/src/main/java/org/perlonjava/runtime/RuntimeTransliterate.java b/src/main/java/org/perlonjava/runtime/RuntimeTransliterate.java index e184ae03..42c3b4fc 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeTransliterate.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeTransliterate.java @@ -1,11 +1,13 @@ package org.perlonjava.runtime; /** - * RuntimeTransliterate class to implement Perl's tr// operator + * The RuntimeTransliterate class implements Perl's tr/// operator, which is used for character + * transliteration. It provides functionality to compile a transliteration pattern and apply it + * to a given string. */ public class RuntimeTransliterate { - + // Arrays and flags used for transliteration private char[] translationMap; private boolean[] usedChars; private boolean[] deleteChars; @@ -15,20 +17,26 @@ public class RuntimeTransliterate { private boolean returnOriginal; /** - * Creates a RuntimeTransliterate object from a pattern string with optional modifiers. + * Compiles a RuntimeTransliterate object from a pattern string with optional modifiers. * - * @param search The pattern string + * @param search The pattern string to search for * @param replace The replacement string - * @param modifiers Modifiers for the pattern - * @return A RuntimeTransliterate object. + * @param modifiers Modifiers for the pattern (e.g., complement, delete, squash) + * @return A compiled RuntimeTransliterate object */ public static RuntimeTransliterate compile(RuntimeScalar search, RuntimeScalar replace, RuntimeScalar modifiers) { - // TODO cache the compilation + // TODO: Cache the compilation RuntimeTransliterate transliterate = new RuntimeTransliterate(); transliterate.compileTransliteration(search.toString(), replace.toString(), modifiers.toString()); return transliterate; } + /** + * Applies the transliteration pattern to the given string. + * + * @param originalString The original string to be transliterated + * @return A new RuntimeScalar containing the transliterated string + */ public RuntimeScalar transliterate(RuntimeScalar originalString) { String input = originalString.toString(); StringBuilder result = new StringBuilder(); @@ -39,15 +47,12 @@ public RuntimeScalar transliterate(RuntimeScalar originalString) { if (deleteChars[ch]) { lastCharAdded = false; } else if (ch < 256 && usedChars[ch]) { - // System.out.println("used: " + ch); char mappedChar = translationMap[ch]; if (!squashDuplicates || result.length() == 0 || result.charAt(result.length() - 1) != mappedChar) { - // System.out.println("used append: " + ch); result.append(mappedChar); lastCharAdded = true; } } else { - // System.out.println("not used: " + ch); result.append(ch); lastCharAdded = false; } @@ -60,6 +65,13 @@ public RuntimeScalar transliterate(RuntimeScalar originalString) { return new RuntimeScalar(resultString); } + /** + * Compiles the transliteration pattern and replacement strings with the given modifiers. + * + * @param search The pattern string to search for + * @param replace The replacement string + * @param modifiers Modifiers for the pattern (e.g., complement, delete, squash) + */ public void compileTransliteration(String search, String replace, String modifiers) { complement = modifiers.contains("c"); deleteUnmatched = modifiers.contains("d"); @@ -85,6 +97,12 @@ public void compileTransliteration(String search, String replace, String modifie } } + /** + * Expands character ranges and escape sequences in the input string. + * + * @param input The input string containing ranges and escapes + * @return The expanded string + */ private String expandRangesAndEscapes(String input) { StringBuilder expanded = new StringBuilder(); for (int i = 0; i < input.length(); i++) { @@ -136,10 +154,24 @@ private String expandRangesAndEscapes(String input) { return expanded.toString(); } + /** + * Checks if a character is a hexadecimal digit. + * + * @param ch The character to check + * @return True if the character is a hexadecimal digit, false otherwise + */ private boolean isHexDigit(char ch) { return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'); } + /** + * Complements the translation map based on the search and replace strings. + * + * @param translationMap The translation map to populate + * @param usedChars The array indicating which characters are used + * @param search The search string + * @param replace The replacement string + */ private void complementTranslationMap(char[] translationMap, boolean[] usedChars, String search, String replace) { boolean[] complementSet = new boolean[256]; for (int i = 0; i < search.length(); i++) { @@ -165,6 +197,14 @@ private void complementTranslationMap(char[] translationMap, boolean[] usedChars } } + /** + * Populates the translation map based on the search and replace strings. + * + * @param translationMap The translation map to populate + * @param usedChars The array indicating which characters are used + * @param search The search string + * @param replace The replacement string + */ private void populateTranslationMap(char[] translationMap, boolean[] usedChars, String search, String replace) { int minLength = Math.min(search.length(), replace.length()); for (int i = 0; i < minLength; i++) { @@ -182,4 +222,3 @@ private void populateTranslationMap(char[] translationMap, boolean[] usedChars, } } } -