//==============================================================================
// BlockDef.java
//==============================================================================
package tribble.net.ftp.shell;
import java.io.PrintWriter;
import java.lang.Exception;
import java.lang.String;
import java.util.HashMap;
/*******************************************************************************
* FTP command begin/end block or func definition.
*
*
* @version API 1.1 $Revision: 1.10 $ $Date: 2010/07/12 22:29:52 $
* @since API 1.0, 2007-03-16
* @author David R. Tribble (david@tribble.com).
*
* Copyright ©2007-2010 by David R. Tribble, all rights reserved.
* Permission is granted to any person or entity except those designated by
* by the United States Department of State as a terrorist, or terrorist
* government or agency, to use and distribute this source code provided
* that the original copyright notice remains present and unaltered.
*
* @see CommandExec
* @see ExecFrame
*/
class BlockDef
implements CommandCodes
{
/** Revision information. */
static final String REV =
"@(#)tribble/net/ftp/shell/BlockDef.java API 1.1 $Revision: 1.10 $ $Date: 2010/07/12 22:29:52 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constants
//----------------------------------------
// Locally defined name types
private static final short NAMETYPE_VAR = 1;
private static final short NAMETYPE_LABEL = 2;
private static final short NAMETYPE_FUNC = 3;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Variables
/** Name of this block definition. */
String m_name;
/** Block type (begin/end, foreach, repeat). */
String m_type;
/** Outer block containing this block definition. */
BlockDef m_outer;
/** Parent command enclosing this block. */
CommandNode m_parent;
/** Source line number. */
int m_lineNo;
/** Scope nesting depth. */
int m_depth;
/** Commands (statements) in this block definition. */
private CommandNode m_cmds;
/** Local func definitions. */
private HashMap
m_funcs;
/** Local var definitions. */
private HashMap
m_vars;
/** Local statement label definitions. */
private HashMap
m_labels;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***************************************************************************
* Constructor.
*
* @param name
* Name of this block. Funcs have user-defined names, while begin/end block
* have names such as ".42".
*
* @param lineNo
* Source line number where the block is defined.
*
* @param outer
* Begin/end block or func containing this block. This is null for the
* outermost (file) scope, which has no outer scope.
*
* @param cmd
* Parent command containing this block. This is null for the outermost
* (file) scope, and for block commands having no controlling command.
*
* @since 1.7, 2007-08-02
*/
BlockDef(String name, int lineNo, BlockDef outer, CommandNode cmd)
{
// Initialize
m_name = name;
m_lineNo = lineNo;
m_outer = outer;
m_parent = cmd;
// Set up
if (outer != null)
m_depth = outer.m_depth+1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Methods
/***************************************************************************
* Establish the commands (statements) for this block definition.
*
* @param cmds
* First command (statement) defined within the begin/end block or func, or
* null if there are no commands.
*
* @since 1.1, 2007-03-16
*/
void setCmds(CommandNode cmds)
{
m_cmds = cmds;
}
/***************************************************************************
* Determine if this block definition is a func body.
*
* @since 1.2, 2007-03-21
*/
boolean isFunc()
{
// Examine the name of the block
return (m_type == CMD_FUNC);
}
/***************************************************************************
* Add a local func definition to this block definition.
*
* @param name
* Func name.
*
* @param cmd
* Command ({@link #CMD_FUNC CMD_FUNC}) containing the func definition.
*
* @return
* True if the func was added successfully, or false if it is already defined
* within this block definition.
*
* @since 1.1, 2007-03-16
*/
boolean addFuncDef(String name, CommandNode cmd)
{
// Add a func that is local to this block definition
if (m_funcs == null)
m_funcs = new HashMap();
if (m_funcs.get(name) != null)
return false;
m_funcs.put(name, cmd);
return true;
}
/***************************************************************************
* Retrieve a func definition within this block's scope.
*
* @param name
* Func name.
*
* @return
* The command node ({@link #CMD_FUNC CMD_FUNC}) containing the func
* definition, or null if no such func exists within the scope of this block
* definition.
*
* @since 1.1, 2007-03-16
*/
CommandNode findFuncDef(String name)
{
return findADef(name, NAMETYPE_FUNC);
}
/***************************************************************************
* Find the block containing a func definition.
*
* @param name
* Var name.
*
* @return
* The block definition containing the func definition ('func' command), or
* null if the func is not defined within the scope of this block or any of
* its outer blocks.
*
* @since 1.6, 2007-04-10
*/
BlockDef findFuncBlock(String name)
{
return findABlock(name, NAMETYPE_FUNC);
}
/***************************************************************************
* Add a local var definition to this block definition.
*
* @param name
* Var name.
*
* @param cmd
* Command ({@link #CMD_VAR CMD_VAR}) containing the var definition.
*
* @return
* True if the var was added successfully, or false if it is already defined
* within this block definition.
*
* @since 1.1, 2007-03-16
*/
boolean addVarDef(String name, CommandNode cmd)
{
// Add a var that is local to this block definition
if (m_vars == null)
m_vars = new HashMap();
if (m_vars.get(name) != null)
return false;
m_vars.put(name, cmd);
return true;
}
/***************************************************************************
* Retrieve a var definition within this block's scope.
*
* @param name
* Var name.
*
* @return
* The command node ({@link #CMD_VAR CMD_VAR}) containing the var definition,
* or null if no such var exists in the scope of this block definition.
*
* @since 1.1, 2007-03-16
*/
CommandNode findVarDef(String name)
{
return findADef(name, NAMETYPE_VAR);
}
/***************************************************************************
* Find the block containing a var definition.
*
* @param name
* Var name.
*
* @return
* The block definition containing the var definition ('var' command), or
* null if the var is not defined within the scope of this block or any of
* its outer blocks.
*
* @since 1.4, 2007-04-06
*/
BlockDef findVarBlock(String name)
{
return findABlock(name, NAMETYPE_VAR);
}
/***************************************************************************
* Add a local label definition to this block definition.
*
* @param name
* Label name.
*
* @param cmd
* Command ({@link #CMD_LABEL CMD_LABEL}) containing the statement label
* definition.
*
* @return
* True if the label was added successfully, or false if it is already
* defined within this block definition.
*
* @since 1.1, 2007-03-16
*/
boolean addLabelDef(String name, CommandNode cmd)
{
// Add a label that is local to this block definition
if (m_labels == null)
m_labels = new HashMap();
if (m_labels.get(name) != null)
return false;
m_labels.put(name, cmd);
return true;
}
/***************************************************************************
* Retrieve a local label definition in this block definition.
*
* @param name
* Label name.
*
* @return
* The command node ({@link #CMD_LABEL CMD_LABEL}) containing the statement
* label, or null if no such label exists in this block definition.
*
* @since 1.1, 2007-03-16
*/
CommandNode findLabelDef(String name)
{
return findADef(name, NAMETYPE_LABEL);
}
/***************************************************************************
* Find the block containing a label definition.
*
* @param name
* Label name.
*
* @return
* The block definition containing the label definition, or null if the label
* is not defined within the scope of this block or any of its outer blocks.
* Blocks outside func bodies are not searched.
*
* @since 1.5, 2007-04-09
*/
BlockDef findLabelBlock(String name)
{
return findABlock(name, NAMETYPE_LABEL);
}
/***************************************************************************
* Retrieve a var/label/func definition within this block's scope.
*
* @param name
* Var, label, or func name.
*
* @param type
* One of the {@link #NAMETYPE_VAR NAMETYPE_XXX} constants, specifying
* what kind of name name is.
*
* @return
* The command node containing the definition of the name, or null if it does
* not exist in the scope of this block. Labels are not searched for outside
* func bodies.
*
* @since 1.6, 2007-04-10
*/
private CommandNode findADef(String name, int type)
{
BlockDef scope;
// Search for the definition within this block's scope
for (scope = this; scope != null; scope = scope.m_outer)
{
HashMap list = null;
// Search the next block for the definition
switch (type)
{
case NAMETYPE_VAR: list = scope.m_vars; break;
case NAMETYPE_LABEL: list = scope.m_labels; break;
case NAMETYPE_FUNC: list = scope.m_funcs; break;
}
if (list != null)
{
CommandNode def;
def = list.get(name);
if (def != null)
return def;
}
// Expand the search to the next outer block,
// but do not search for labels outside a func block
if (type == NAMETYPE_LABEL && scope.isFunc())
break;
}
// The definition was not found
return null;
}
/***************************************************************************
* Find the block containing a var/label/func definition.
*
* @param name
* Var, label, or func name.
*
* @param type
* One of the {@link #NAMETYPE_VAR NAMETYPE_XXX} constants, specifying
* what kind of name name is.
*
* @return
* The block definition containing the definition of the name, or null if it
* is not defined within the scope of this block or any of its outer blocks.
* Labels are not searched for outside func bodies.
*
* @since 1.6, 2007-04-10
*/
private BlockDef findABlock(String name, int type)
{
BlockDef scope;
// Search for the definition within this block's scope
for (scope = this; scope != null; scope = scope.m_outer)
{
HashMap list = null;
// Search the next block for the definition
switch (type)
{
case NAMETYPE_VAR: list = scope.m_vars; break;
case NAMETYPE_LABEL: list = scope.m_labels; break;
case NAMETYPE_FUNC: list = scope.m_funcs; break;
}
// Search the next block for the definition
if (list != null && list.get(name) != null)
return scope;
// Expand the search to the next outer block,
// but do not search for labels outside a func block
if (type == NAMETYPE_LABEL && scope.isFunc())
break;
}
// The definition was not found
return null;
}
/***************************************************************************
* Release objects that are no longer needed by this block definition after a
* successful parse.
*
* @since 1.8, 2007-08-05
*/
void scrub()
{
m_funcs = null;
m_vars = null;
m_labels = null;
}
/***************************************************************************
* Pretty-print this block definition and its subordinate blocks.
*
* @since 1.9, 2007-08-07
*/
void printTree(PrintWriter out)
{
if (out != null)
printTree(out, "");
}
/***************************************************************************
* Pretty-print this block definition and its subordinate blocks.
*
* @since 1.9, 2007-08-07
*/
private void printTree(PrintWriter out, String indent)
{
CommandNode cmd;
// Print this block
print(out, indent);
// Print out this block's local definitions
for (cmd = m_cmds; cmd != null; cmd = cmd.m_next)
{
String type = null;
String name = null;
if (cmd.m_cmd == CMD_LABEL)
{
type = "label";
name = (String) cmd.m_args[0];
}
else if (cmd.m_cmd == CMD_VAR)
{
type = "var ";
name = (String) cmd.m_args[0];
}
else if (cmd.m_cmd == CMD_FUNC)
{
type = "func ";
name = (String) cmd.m_args[0];
}
if (type != null)
{
out.print(indent);
out.println(" " + type + " " + name + " @" + cmd.m_lineNo);
}
}
// Print this block's children (nested) blocks
for (cmd = m_cmds; cmd != null; cmd = cmd.m_next)
{
if (cmd.m_cmd == CMD_GOTO)
continue;
if (cmd.m_args == null)
continue;
for (int i = 0; i < cmd.m_args.length; i++)
{
if (cmd.m_args[i] instanceof BlockDef)
{
BlockDef sub;
sub = (BlockDef) cmd.m_args[i];
if (sub.m_lineNo > this.m_lineNo)
sub.printTree(out, indent + " ");
}
}
}
}
/***************************************************************************
* Pretty-print this block definition.
*
* @since 1.9, 2007-08-07
*/
private void print(PrintWriter out, String indent)
{
// Display the contents of this block definition
out.print(indent);
out.print(m_lineNo + ": {" + m_depth + "} \"" + m_name + "\" /"
+ m_type);
if (m_parent != null)
out.print(" : " + m_parent.m_cmd + " @" + m_parent.m_lineNo);
out.println();
}
}
// End BlockDef.java