public class ANTLR extends Task {

    private CommandlineJava commandline = new CommandlineJava();

    /** the file to process */
    private File targetFile;

    /** where to output the result */
    private File outputDirectory;

    /** an optional super grammar file */
    private File superGrammar;

    /** optional flag to enable html output */
    private boolean html;

    /** optional flag to print out a diagnostic file */
    private boolean diagnostic;

    /** optional flag to add trace methods */
    private boolean trace;

    /** optional flag to add trace methods to the parser only */
    private boolean traceParser;

    /** optional flag to add trace methods to the lexer only */
    private boolean traceLexer;

    /** optional flag to add trace methods to the tree walker only */
    private boolean traceTreeWalker;

    /** working directory */
    private File workingdir = null;

    /** captures ANTLR's output */
    private ByteArrayOutputStream bos = new ByteArrayOutputStream();

    /** The debug attribute */
    private boolean debug;

    /** Instance of a utility class to use for file operations. */
    private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();

    /** Constructor for ANTLR task. */
    public ANTLR() {
        commandline.setVm(JavaEnvUtils.getJreExecutable("java"));
        commandline.setClassname("antlr.Tool");
    }

    /**
     * The grammar file to process.
     * @param target the gramer file
     */
    public void setTarget(File target) {
        log("Setting target to: " + target.toString(), Project.MSG_VERBOSE);
        this.targetFile = target;
    }

    /**
     * The directory to write the generated files to.
     * @param outputDirectory the output directory
     */
    public void setOutputdirectory(File outputDirectory) {
        log("Setting output directory to: " + outputDirectory.toString(), Project.MSG_VERBOSE);
        this.outputDirectory = outputDirectory;
    }

    /**
     * Sets an optional super grammar file.
     * Use setGlib(File superGrammar) instead.
     * @param superGrammar the super grammar filename
     * @deprecated  since ant 1.6
     */
    public void setGlib(String superGrammar) {
        String sg = null;
        if (Os.isFamily("dos")) {
            sg = superGrammar.replace('\\', '/');
        } else {
            sg = superGrammar;
        }
        setGlib(FILE_UTILS.resolveFile(getProject().getBaseDir(), sg));
    }
    /**
     * Sets an optional super grammar file
     * @param superGrammar the super grammar file
     * @since ant 1.6
     */
    public void setGlib(File superGrammar) {
        this.superGrammar = superGrammar;
    }
    /**
     * Sets a flag to enable ParseView debugging
     * @param enable a boolean value
     */
    public void setDebug(boolean enable) {
        this.debug = enable;
    }

    /**
     * If true, emit html
     * @param enable a boolean value
     */
    public void setHtml(boolean enable) {
        html = enable;
    }

    /**
     * Sets a flag to emit diagnostic text
     * @param enable a boolean value
     */
    public void setDiagnostic(boolean enable) {
        diagnostic = enable;
    }

    /**
     * If true, enables all tracing.
     * @param enable a boolean value
     */
    public void setTrace(boolean enable) {
        trace = enable;
    }

    /**
     * If true, enables parser tracing.
     * @param enable a boolean value
     */
    public void setTraceParser(boolean enable) {
        traceParser = enable;
    }

    /**
     * If true, enables lexer tracing.
     * @param enable a boolean value
     */
    public void setTraceLexer(boolean enable) {
        traceLexer = enable;
    }

    /**
     * Sets a flag to allow the user to enable tree walker tracing
     * @param enable a boolean value
     */
    public void setTraceTreeWalker(boolean enable) {
        traceTreeWalker = enable;
    }

    /**
     * @ant.attribute ignore="true"
     * @param s a boolean value
     */
    public void setFork(boolean s) {
    }

    /**
     * The working directory of the process
     * @param d the working directory
     */
    public void setDir(File d) {
        this.workingdir = d;
    }

    /**
     * Adds a classpath to be set
     * because a directory might be given for Antlr debug.
     * @return a path to be configured
     */
    public Path createClasspath() {
        return commandline.createClasspath(getProject()).createPath();
    }

    /**
     * Adds a new JVM argument.
     * @return  create a new JVM argument so that any argument can be passed to the JVM.
     * @see #setFork(boolean)
     */
    public Commandline.Argument createJvmarg() {
        return commandline.createVmArgument();
    }

    /**
     * Adds the jars or directories containing Antlr
     * this should make the forked JVM work without having to
     * specify it directly.
     * @throws BuildException on error
     */
    public void init() throws BuildException {
        addClasspathEntry("/antlr/ANTLRGrammarParseBehavior.class");
    }

    /**
     * Search for the given resource and add the directory or archive
     * that contains it to the classpath.
     *
     *
Doesn't work for archives in JDK 1.1 as the URL returned by
     * getResource doesn't contain the name of the archive.

     * @param resource the resource name to search for
     */
    protected void addClasspathEntry(String resource) {
        /*
         * pre Ant 1.6 this method used to call getClass().getResource
         * while Ant 1.6 will call ClassLoader.getResource().
         *
         * The difference is that Class.getResource expects a leading
         * slash for "absolute" resources and will strip it before
         * delegating to ClassLoader.getResource - so we now have to
         * emulate Class's behavior.
         */
        if (resource.startsWith("/")) {
            resource = resource.substring(1);
        } else {
            resource = "org/apache/tools/ant/taskdefs/optional/"
                + resource;
        }

        File f = LoaderUtils.getResourceSource(getClass().getClassLoader(),
                                               resource);
        if (f != null) {
            log("Found " + f.getAbsolutePath(), Project.MSG_DEBUG);
            createClasspath().setLocation(f);
        } else {
            log("Couldn\'t find " + resource, Project.MSG_VERBOSE);
        }
    }

    /**
     * Execute the task.
     * @throws BuildException on error
     */
    public void execute() throws BuildException {
        validateAttributes();

        File generatedFile = getGeneratedFile();
        boolean targetIsOutOfDate =
            targetFile.lastModified() > generatedFile.lastModified();
        boolean superGrammarIsOutOfDate  = superGrammar != null
                && (superGrammar.lastModified() > generatedFile.lastModified());
        if (targetIsOutOfDate || superGrammarIsOutOfDate) {
            if (targetIsOutOfDate) {
                log("Compiling " + targetFile + " as it is newer than "
                    + generatedFile, Project.MSG_VERBOSE);
            } else {
                log("Compiling " + targetFile + " as " + superGrammar
                    + " is newer than " + generatedFile, Project.MSG_VERBOSE);
            }
            populateAttributes();
            commandline.createArgument().setValue(targetFile.toString());

            log(commandline.describeCommand(), Project.MSG_VERBOSE);
            int err = run(commandline.getCommandline());
            if (err != 0) {
                throw new BuildException("ANTLR returned: " + err, getLocation());
            } else {
                String output = bos.toString();
                if (output.indexOf("error:") > -1) {
                    throw new BuildException("ANTLR signaled an error: "
                                             + output, getLocation());
                }
            }
        } else {
            log("Skipped grammar file. Generated file " + generatedFile
                + " is newer.", Project.MSG_VERBOSE);
        }
    }

    /**
     * A refactored method for populating all the command line arguments based
     * on the user-specified attributes.
     */
    private void populateAttributes() {
        commandline.createArgument().setValue("-o");
        commandline.createArgument().setValue(outputDirectory.toString());
        if (superGrammar != null) {
            commandline.createArgument().setValue("-glib");
            commandline.createArgument().setValue(superGrammar.toString());
        }
        if (html) {
            commandline.createArgument().setValue("-html");
        }
        if (diagnostic) {
            commandline.createArgument().setValue("-diagnostic");
        }
        if (trace) {
            commandline.createArgument().setValue("-trace");
        }
        if (traceParser) {
            commandline.createArgument().setValue("-traceParser");
        }
        if (traceLexer) {
            commandline.createArgument().setValue("-traceLexer");
        }
        if (traceTreeWalker) {
            if (is272()) {
                commandline.createArgument().setValue("-traceTreeParser");
            } else {
                commandline.createArgument().setValue("-traceTreeWalker");
            }
        }
        if (debug) {
            commandline.createArgument().setValue("-debug");
        }
    }

    private void validateAttributes() throws BuildException {
        if (targetFile == null || !targetFile.isFile()) {
            throw new BuildException("Invalid target: " + targetFile);
        }

        if (outputDirectory == null) {
            setOutputdirectory(new File(targetFile.getParent()));
        }
        if (!outputDirectory.isDirectory()) {
            throw new BuildException("Invalid output directory: " + outputDirectory);
        }
    }

    private File getGeneratedFile() throws BuildException {
        String generatedFileName = null;
        try {
            BufferedReader in = new BufferedReader(new FileReader(targetFile));
            String line;
            while ((line = in.readLine()) != null) {
                int extendsIndex = line.indexOf(" extends ");
                if (line.startsWith("class ") && extendsIndex > -1) {
                    generatedFileName = line.substring(
                        "class ".length(), extendsIndex).trim();
                    break;
                }
            }
            in.close();
        } catch (Exception e) {
            throw new BuildException("Unable to determine generated class", e);
        }
        if (generatedFileName == null) {
            throw new BuildException("Unable to determine generated class");
        }
        return new File(outputDirectory, generatedFileName
                        + (html ? ".html" : ".java"));
    }

    /** execute in a forked VM */
    private int run(String[] command) throws BuildException {
        PumpStreamHandler psh =
            new PumpStreamHandler(new LogOutputStream(this, Project.MSG_INFO),
                                  new TeeOutputStream(
                                                      new LogOutputStream(this,
                                                                          Project.MSG_WARN),
                                                      bos)
                                  );
        Execute exe = new Execute(psh, null);
        exe.setAntRun(getProject());
        if (workingdir != null) {
            exe.setWorkingDirectory(workingdir);
        }
        exe.setCommandline(command);
        try {
            return exe.execute();
        } catch (IOException e) {
            throw new BuildException(e, getLocation());
        } finally {
            FileUtils.close(bos);
        }
    }

    /**
     * Whether the antlr version is 2.7.2 (or higher).
     *
     * @return true if the version of Antlr present is 2.7.2 or later.
     * @since Ant 1.6
     */
    protected boolean is272() {
        AntClassLoader l = null;
        try {
            l = getProject().createClassLoader(commandline.getClasspath());
            l.loadClass("antlr.Version");
            return true;
        } catch (ClassNotFoundException e) {
            return false;
        } finally {
            if (l != null) {
                l.cleanup();

FUNC_DECL IF IF IF IF IF IF IF IF BINARY_OP CALL CALL IF LITERAL_ANCHOR CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR CALL LITERAL_ANCHOR CALL CALL LITERAL_ANCHOR LITERAL_ANCHOR

FUNC_DECL TRY IF VAR_DECL VAR_DECL PARAM CATCH RETURN CALL BINARY_OP CALL CALL THROW_RAISE CALL LITERAL_ANCHOR CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL CALL CALL CALL


org.gjt.sp.jedit.io.FileVFS

public class FileVFS extends VFS
{
	public static final String PERMISSIONS_PROPERTY = "FileVFS__perms";

	//{{{ FileVFS method
	public FileVFS()
	{
		super("file",READ_CAP | WRITE_CAP | DELETE_CAP
			| RENAME_CAP | MKDIR_CAP | LOW_LATENCY_CAP
			| ((OperatingSystem.isMacOS()
			|| OperatingSystem.isDOSDerived())
			? CASE_INSENSITIVE_CAP : 0),
			new String[] { EA_TYPE, EA_SIZE, EA_STATUS,
			EA_MODIFIED });
	} //}}}

	//{{{ getParentOfPath() method
	public String getParentOfPath(String path)
	{
		if(OperatingSystem.isDOSDerived())
		{
			if(path.length() == 2 && path.charAt(1) == ':')
				return FileRootsVFS.PROTOCOL + ":";
			else if(path.length() == 3 && path.endsWith(":\\"))
				return FileRootsVFS.PROTOCOL + ":";
			else if(path.startsWith("\\\\") && path.indexOf('\\',2) == -1)
				return path;
		}

		return super.getParentOfPath(path);
	} //}}}

	//{{{ constructPath() method
	public String constructPath(String parent, String path)
	{
		if(parent.endsWith(File.separator)
			|| parent.endsWith("/"))
			return parent + path;
		else
			return parent + File.separator + path;
	} //}}}

	//{{{ getFileSeparator() method
	public char getFileSeparator()
	{
		return File.separatorChar;
	} //}}}

	//{{{ save() method
	public boolean save(View view, Buffer buffer, String path)
	{
		if(OperatingSystem.isUnix())
		{
			int permissions = getPermissions(buffer.getPath());
			Log.log(Log.DEBUG,this,buffer.getPath() + " has permissions 0"
				+ Integer.toString(permissions,8));
			buffer.setIntegerProperty(PERMISSIONS_PROPERTY,permissions);
		}

		return super.save(view,buffer,path);
	} //}}}

	//{{{ insert() method
	public boolean insert(View view, Buffer buffer, String path)
	{
		File file = new File(path);

		//{{{ Check if file is valid
		if(!file.exists())
			return false;

		if(file.isDirectory())
		{
			VFSManager.error(view,file.getPath(),
				"ioerror.open-directory",null);
			return false;
		}

		if(!file.canRead())
		{
			VFSManager.error(view,file.getPath(),
				"ioerror.no-read",null);
			return false;
		} //}}}

		return super.insert(view,buffer,path);
	} //}}}

	//{{{ _canonPath() method
	/**
	 * Returns the canonical form if the specified path name. For example,
	 * <code>~</code> might be expanded to the user's home directory.
	 * @param session The session
	 * @param path The path
	 * @param comp The component that will parent error dialog boxes
	 * @exception IOException if an I/O error occurred
	 * @since jEdit 4.0pre2
	 */
	public String _canonPath(Object session, String path, Component comp)
		throws IOException
	{
		return MiscUtilities.canonPath(path);
	} //}}}

	//{{{ LocalDirectoryEntry class
	public static class LocalDirectoryEntry extends VFS.DirectoryEntry
	{
		// use system default short format
		public static DateFormat DATE_FORMAT
			= DateFormat.getInstance();

		public long modified;

		public LocalDirectoryEntry(File file)
		{
			super(file.getName(),file.getPath(),
				file.getPath(),file.isDirectory() ? DIRECTORY : FILE,file.length(),file.isHidden());
			this.modified = file.lastModified();
			this.canRead = file.canRead();
			this.canWrite = file.canWrite();
			this.symlinkPath = MiscUtilities.resolveSymlinks(path);
		}

		public String getExtendedAttribute(String name)
		{
			if(name.equals(EA_MODIFIED))
				return DATE_FORMAT.format(new Date(modified));
			else
				return super.getExtendedAttribute(name);
		}
	} //}}}

	//{{{ _listDirectory() method
	public VFS.DirectoryEntry[] _listDirectory(Object session, String path,
		Component comp)
	{
		//{{{ Windows work around
		/* On Windows, paths of the form X: list the last *working
		 * directory* on that drive. To list the root of the drive,
		 * you must use X:\.
		 *
		 * However, the VFS browser and friends strip off trailing
		 * path separators, for various reasons. So to work around
		 * that, we add a '\' to drive letter paths on Windows.
		 */
		if(OperatingSystem.isWindows())
		{
			if(path.length() == 2 && path.charAt(1) == ':')
				path = path.concat(File.separator);
		} //}}}

		File directory = new File(path);
		File[] list = directory.listFiles();
		if(list == null)
		{
			VFSManager.error(comp,path,"ioerror.directory-error-nomsg",null);
			return null;
		}

		VFS.DirectoryEntry[] list2 = new VFS.DirectoryEntry[list.length];
		for(int i = 0; i < list.length; i++)
			list2[i] = new LocalDirectoryEntry(list[i]);

		return list2;
	} //}}}

	//{{{ _getDirectoryEntry() method
	public DirectoryEntry _getDirectoryEntry(Object session, String path,
		Component comp)
	{
		if(path.equals("/") && OperatingSystem.isUnix())
		{
			return new VFS.DirectoryEntry(path,path,path,
				VFS.DirectoryEntry.DIRECTORY,0L,false);
		}

		File file = new File(path);
		if(!file.exists())
			return null;

		return new LocalDirectoryEntry(file);
	} //}}}

	//{{{ _delete() method
	public boolean _delete(Object session, String path, Component comp)
	{
		File file = new File(path);
		// do some platforms throw exceptions if the file does not exist
		// when we ask for the canonical path?
		String canonPath;
		try
		{
			canonPath = file.getCanonicalPath();
		}
		catch(IOException io)
		{
			canonPath = path;
		}

		boolean retVal = file.delete();
		if(retVal)
			VFSManager.sendVFSUpdate(this,canonPath,true);
		return retVal;
	} //}}}

	//{{{ _rename() method
	public boolean _rename(Object session, String from, String to,
		Component comp)
	{
		File _to = new File(to);

		String toCanonPath;
		try
		{
			toCanonPath = _to.getCanonicalPath();
		}
		catch(IOException io)
		{
			toCanonPath = to;
		}

		// this is needed because on OS X renaming to a non-existent
		// directory causes problems
		File parent = new File(_to.getParent());
		if(parent.exists())
		{
			if(!parent.isDirectory())
				return false;
		}
		else
		{
			parent.mkdirs();
			if(!parent.exists())
				return false;
		}

		File _from = new File(from);

		String fromCanonPath;
		try
		{
			fromCanonPath = _from.getCanonicalPath();
		}
		catch(IOException io)
		{
			fromCanonPath = from;
		}

		// Case-insensitive fs workaround
		if(!fromCanonPath.equalsIgnoreCase(toCanonPath))
			_to.delete();

		boolean retVal = _from.renameTo(_to);
		VFSManager.sendVFSUpdate(this,fromCanonPath,true);
		VFSManager.sendVFSUpdate(this,toCanonPath,true);
		return retVal;
	} //}}}

	//{{{ _mkdir() method
	public boolean _mkdir(Object session, String directory, Component comp)
	{
		String parent = getParentOfPath(directory);
		if(!new File(parent).exists())
		{
			if(!_mkdir(session,parent,comp))
				return false;
		}

		File file = new File(directory);

		boolean retVal = file.mkdir();
		String canonPath;
		try
		{
			canonPath = file.getCanonicalPath();
		}
		catch(IOException io)
		{
			canonPath = directory;
		}
		VFSManager.sendVFSUpdate(this,canonPath,true);
		return retVal;
	} //}}}

	//{{{ _backup() method
	public void _backup(Object session, String path, Component comp)
		throws IOException
	{
		// Fetch properties
		int backups = jEdit.getIntegerProperty("backups",1);

		if(backups == 0)
			return;

		String backupPrefix = jEdit.getProperty("backup.prefix");
		String backupSuffix = jEdit.getProperty("backup.suffix");

		String backupDirectory = jEdit.getProperty("backup.directory");

		int backupTimeDistance = jEdit.getIntegerProperty("backup.minTime",0);
		File file = new File(path);

		// Check for backup.directory, and create that
		// directory if it doesn't exist
		if(backupDirectory == null || backupDirectory.length() == 0)
			backupDirectory = file.getParent();
		else
		{
			backupDirectory = MiscUtilities.constructPath(
				System.getProperty("user.home"),backupDirectory);

			// Perhaps here we would want to guard with
			// a property for parallel backups or not.
			backupDirectory = MiscUtilities.concatPath(
				backupDirectory,file.getParent());

			File dir = new File(backupDirectory);

			if (!dir.exists())
				dir.mkdirs();
		}

		MiscUtilities.saveBackup(file,backups,backupPrefix,
			backupSuffix,backupDirectory,backupTimeDistance);
	} //}}}

	//{{{ _createInputStream() method
	public InputStream _createInputStream(Object session, String path,
		boolean ignoreErrors, Component comp) throws IOException
	{
		try
		{
			return new FileInputStream(path);
		}
		catch(IOException io)
		{
			if(ignoreErrors)
				return null;
			else
				throw io;
		}
	} //}}}

	//{{{ _createOutputStream() method
	public OutputStream _createOutputStream(Object session, String path,
		Component comp) throws IOException
	{
		return new FileOutputStream(path);
	} //}}}

	//{{{ _saveComplete() method
	public void _saveComplete(Object session, Buffer buffer, String path,
		Component comp)
	{
		int permissions = buffer.getIntegerProperty(PERMISSIONS_PROPERTY,0);
		setPermissions(path,permissions);
	} //}}}

	//{{{ Permission preservation code

	/** Code borrowed from j text editor (http://www.armedbear.org) */
	/** I made some changes to make it support suid, sgid and sticky files */

	//{{{ getPermissions() method
	/**
	 * Returns numeric permissions of a file. On non-Unix systems, always
	 * returns zero.
	 * @since jEdit 3.2pre9
	 */
	public static int getPermissions(String path)
	{
		int permissions = 0;

		if(jEdit.getBooleanProperty("chmodDisabled"))
			return permissions;

		if(OperatingSystem.isUnix())
		{
			String[] cmdarray = { "ls", "-ld", path };

			try
			{
				Process process = Runtime.getRuntime().exec(cmdarray);

				BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

				String output = reader.readLine();

				if(output != null)
				{
					String s = output.substring(1, 10);

					permissions = MiscUtilities
						.parsePermissions(s);
				}
			}

			// Feb 4 2000 5:30 PM
			// Catch Throwable here rather than Exception.
			// Kaffe's implementation of Runtime.exec throws java.lang.InternalError.
			catch (Throwable t)
			{
			}
		}

		return permissions;
	} //}}}

	//{{{ setPermissions() method
	/**
	 * Sets numeric permissions of a file. On non-Unix platforms,
	 * does nothing.
	 * @since jEdit 3.2pre9
	 */
	public static void setPermissions(String path, int permissions)
	{
		if(jEdit.getBooleanProperty("chmodDisabled"))
			return;

		if(permissions != 0)
		{
			if(OperatingSystem.isUnix())
			{
				String[] cmdarray = { "chmod", Integer.toString(permissions, 8), path };

				try
				{
					Process process = Runtime.getRuntime().exec(cmdarray);
					process.getInputStream().close();
					process.getOutputStream().close();
					process.getErrorStream().close();

FUNC_DECL RETURN IF PARAM PARAM PARAM CALL VAR_DECL CALL CALL BINARY_OP CALL CALL BINARY_OP CALL LITERAL_ANCHOR LITERAL_ANCHOR CALL

FUNC_DECL RETURN IF IF IF VAR_DECL PARAM PARAM PARAM CALL CALL RETURN CALL RETURN RETURN LITERAL_ANCHOR CALL LITERAL_ANCHOR CALL LITERAL_ANCHOR CALL LITERAL_ANCHOR LITERAL_ANCHOR CALL LITERAL_ANCHOR LITERAL_ANCHOR CALL

FUNC_DECL RETURN IF VAR_DECL IF PARAM PARAM PARAM CALL RETURN CALL BINARY_OP LITERAL_ANCHOR CALL RETURN CALL CALL CALL LITERAL_ANCHOR LITERAL_ANCHOR LITERAL_ANCHOR

FUNC_DECL RETURN IF VAR_DECL TRY VAR_DECL VAR_DECL PARAM PARAM PARAM CATCH CALL CALL ASSIGN CALL LITERAL_ANCHOR ASSIGN CALL

FUNC_DECL RETURN VAR_DECL IF TRY VAR_DECL VAR_DECL IF VAR_DECL TRY VAR_DECL VAR_DECL PARAM PARAM PARAM PARAM CALL CALL CALL CATCH CALL CATCH LITERAL_ANCHOR LITERAL_ANCHOR CALL CALL ASSIGN CALL IF IF CALL ASSIGN CALL ASSIGN CALL RETURN CALL CALL RETURN CALL CALL ASSIGN CALL LITERAL_ANCHOR LITERAL_ANCHOR

FUNC_DECL RETURN TRY VAR_DECL VAR_DECL VAR_DECL IF VAR_DECL PARAM PARAM PARAM CALL CATCH CALL LITERAL_ANCHOR ASSIGN CALL CALL IF CALL CALL ASSIGN CALL RETURN CALL LITERAL_ANCHOR

FUNC_DECL TRY PARAM PARAM PARAM PARAM CATCH RETURN IF CALL THROW_RAISE RETURN LITERAL_ANCHOR

FUNC_DECL VAR_DECL PARAM PARAM PARAM PARAM CALL CALL LITERAL_ANCHOR

FUNC_DECL IF IF PARAM PARAM BINARY_OP RETURN CALL IF LITERAL_ANCHOR LITERAL_ANCHOR CALL TRY VAR_DECL CATCH VAR_DECL CALL CALL CALL CALL CALL CALL CALL CALL LITERAL_ANCHOR CALL LITERAL_ANCHOR