lojix/interpreter/src/main/com/thesett/aima/logic/fol/interpreter/ResolutionInterpreter.java
public void interpreterLoop() throws IOException
    {
        // Display the welcome message.
        printIntroduction();

        // Initialize the JLine console.
        consoleReader = initializeCommandLineReader();

        // Used to buffer input, and only feed it to the parser when a PERIOD is encountered.
        TokenBuffer tokenBuffer = new TokenBuffer();

        // Used to hold the currently buffered lines of input, for the purpose of presenting this back to the user
        // in the event of a syntax or other error in the input.
        ArrayList<String> inputLines = new ArrayList<String>();

        // Used to count the number of lines entered.
        int lineNo = 0;

        while (true)
        {
            String line = null;

            try
            {
                line = consoleReader.readLine(mode.prompt);
                inputLines.add(line);

                // JLine returns null if CTRL-D is pressed. Exit program mode back to query mode, or exit the
                // interpreter completely from query mode.
                if ((line == null) && ((mode == Mode.Query) || (mode == Mode.QueryMultiLine)))
                {
                    /*log.fine("CTRL-D in query mode, exiting.");*/

                    System.out.println();

                    break;
                }
                else if ((line == null) && ((mode == Mode.Program) || (mode == Mode.ProgramMultiLine)))
                {
                    /*log.fine("CTRL-D in program mode, returning to query mode.");*/

                    System.out.println();
                    mode = Mode.Query;

                    continue;
                }

                // Check the input to see if a system directive was input. This is only allowed in query mode, and is
                // handled differently to normal queries.
                if (mode == Mode.Query)
                {
                    Source<Token> tokenSource =
                        new OffsettingTokenSource(TokenSource.getTokenSourceForString(line), lineNo);
                    parser.setTokenSource(tokenSource);

                    PrologParser.Directive directive = parser.peekAndConsumeDirective();

                    if (directive != null)
                    {
                        switch (directive)
                        {
                        case Trace:

                            /*log.fine("Got trace directive.");*/
                            break;

                        case Info:

                            /*log.fine("Got info directive.");*/
                            break;

                        case User:

                            /*log.fine("Got user directive, entering program mode.");*/
                            mode = Mode.Program;
                            break;
                        }

                        inputLines.clear();

                        continue;
                    }
                }

                // For normal queries, the query functor '?-' begins every statement, this is not passed back from
                // JLine even though it is used as the command prompt.
                if (mode == Mode.Query)
                {
                    line = QUERY_PROMPT + line;
                    inputLines.set(inputLines.size() - 1, line);
                }

                // Buffer input tokens until EOL is reached, of the input is terminated with a PERIOD.
                Source<Token> tokenSource =
                    new OffsettingTokenSource(TokenSource.getTokenSourceForString(line), lineNo);
                Token nextToken;

                while (true)
                {
                    nextToken = tokenSource.poll();

                    if (nextToken == null)
                    {
                        break;
                    }

                    if (nextToken.kind == PrologParserConstants.PERIOD)
                    {
                        /*log.fine("Token was PERIOD.");*/
                        mode = (mode == Mode.QueryMultiLine) ? Mode.Query : mode;
                        mode = (mode == Mode.ProgramMultiLine) ? Mode.Program : mode;

                        tokenBuffer.offer(nextToken);

                        break;
                    }
                    else if (nextToken.kind == PrologParserConstants.EOF)
                    {
                        /*log.fine("Token was EOF.");*/
                        mode = (mode == Mode.Query) ? Mode.QueryMultiLine : mode;
                        mode = (mode == Mode.Program) ? Mode.ProgramMultiLine : mode;

                        lineNo++;

                        break;
                    }

                    tokenBuffer.offer(nextToken);
                }

                // Evaluate the current token buffer, whenever the input is terminated with a PERIOD.
                if ((nextToken != null) && (nextToken.kind == PrologParserConstants.PERIOD))
                {
                    parser.setTokenSource(tokenBuffer);

                    // Parse the next clause.
                    Sentence<Clause> nextParsing = parser.parse();

                    /*log.fine(nextParsing.toString());*/
                    evaluate(nextParsing);

                    inputLines.clear();
                }
            }
            catch (SourceCodeException e)
            {
                SourceCodePosition sourceCodePosition = e.getSourceCodePosition().asZeroOffsetPosition();
                int startLine = sourceCodePosition.getStartLine();
                int endLine = sourceCodePosition.getEndLine();
                int startColumn = sourceCodePosition.getStartColumn();
                int endColumn = sourceCodePosition.getEndColumn();

                System.out.println("[(" + startLine + ", " + startColumn + "), (" + endLine + ", " + endColumn + ")]");

                for (int i = 0; i < inputLines.size(); i++)
                {
                    String errorLine = inputLines.get(i);
                    System.out.println(errorLine);

                    // Check if the line has the error somewhere in it, and mark the part of it that contains the error.
                    int pos = 0;

                    if (i == startLine)
                    {
                        for (; pos < startColumn; pos++)
                        {
                            System.out.print(" ");
                        }
                    }

                    if (i == endLine)
                    {
                        for (; pos <= endColumn; pos++)
                        {
                            System.out.print("^");
                        }

                        System.out.println();
                    }

                    if ((i > startLine) && (i < endLine))
                    {
                        for (; pos < errorLine.length(); pos++)
                        {
                            System.out.print("^");
                        }

                        System.out.println();
                    }
                }

                System.out.println();
                System.out.println(e.getMessage());
                System.out.println();

                inputLines.clear();
                tokenBuffer.clear();
            }
        }
    }
public void interpreterLoop() throws IOException
    {
        // Display the welcome message.
        printIntroduction();

        // Initialize the JLine console.
        consoleReader = initializeCommandLineReader();

        // Used to buffer input, and only feed it to the parser when a PERIOD is encountered.
        TokenBuffer tokenBuffer = new TokenBuffer();

        // Used to hold the currently buffered lines of input, for the purpose of presenting this back to the user
        // in the event of a syntax or other error in the input.
        ArrayList<String> inputLines = new ArrayList<String>();

        // Used to count the number of lines entered.
        int lineNo = 0;

        while (true)
        {
            String line = null;

            try
            {
                line = consoleReader.readLine(mode.prompt);
                inputLines.add(line);

                // JLine returns null if CTRL-D is pressed. Exit program mode back to query mode, or exit the
                // interpreter completely from query mode.
                if ((line == null) && ((mode == Mode.Query) || (mode == Mode.QueryMultiLine)))
                {
                    /*log.fine("CTRL-D in query mode, exiting.");*/

                    System.out.println();

                    break;
                }
                else if ((line == null) && ((mode == Mode.Program) || (mode == Mode.ProgramMultiLine)))
                {
                    /*log.fine("CTRL-D in program mode, returning to query mode.");*/

                    System.out.println();
                    mode = Mode.Query;

                    continue;
                }

                // Check the input to see if a system directive was input. This is only allowed in query mode, and is
                // handled differently to normal queries.
                if (mode == Mode.Query)
                {
                    Source<Token> tokenSource =
                        new OffsettingTokenSource(TokenSource.getTokenSourceForString(line), lineNo);
                    parser.setTokenSource(tokenSource);

                    PrologParser.Directive directive = parser.peekAndConsumeDirective();

                    if (directive != null)
                    {
                        switch (directive)
                        {
                        case Trace:

                            /*log.fine("Got trace directive.");*/
                            break;

                        case Info:

                            /*log.fine("Got info directive.");*/
                            break;

                        case User:

                            /*log.fine("Got user directive, entering program mode.");*/
                            mode = Mode.Program;
                            break;
                        }

                        inputLines.clear();

                        continue;
                    }
                }

                // For normal queries, the query functor '?-' begins every statement, this is not passed back from
                // JLine even though it is used as the command prompt.
                if (mode == Mode.Query)
                {
                    line = QUERY_PROMPT + line;
                    inputLines.set(inputLines.size() - 1, line);
                }

                // Buffer input tokens until EOL is reached, of the input is terminated with a PERIOD.
                Source<Token> tokenSource =
                    new OffsettingTokenSource(TokenSource.getTokenSourceForString(line), lineNo);
                Token nextToken;

                while (true)
                {
                    nextToken = tokenSource.poll();

                    if (nextToken == null)
                    {
                        break;
                    }

                    if (nextToken.kind == PrologParserConstants.PERIOD)
                    {
                        /*log.fine("Token was PERIOD.");*/
                        mode = (mode == Mode.QueryMultiLine) ? Mode.Query : mode;
                        mode = (mode == Mode.ProgramMultiLine) ? Mode.Program : mode;

                        tokenBuffer.offer(nextToken);

                        break;
                    }
                    else if (nextToken.kind == PrologParserConstants.EOF)
                    {
                        /*log.fine("Token was EOF.");*/
                        mode = (mode == Mode.Query) ? Mode.QueryMultiLine : mode;
                        mode = (mode == Mode.Program) ? Mode.ProgramMultiLine : mode;

                        lineNo++;

                        break;
                    }

                    tokenBuffer.offer(nextToken);
                }

                // Evaluate the current token buffer, whenever the input is terminated with a PERIOD.
                if ((nextToken != null) && (nextToken.kind == PrologParserConstants.PERIOD))
                {
                    parser.setTokenSource(tokenBuffer);

                    // Parse the next clause.
                    Sentence<Clause> nextParsing = parser.parse();

                    /*log.fine(nextParsing.toString());*/
                    evaluate(nextParsing);

                    inputLines.clear();
                }
            }
            catch (SourceCodeException e)
            {
                SourceCodePosition sourceCodePosition = e.getSourceCodePosition().asZeroOffsetPosition();
                int startLine = sourceCodePosition.getStartLine();
                int endLine = sourceCodePosition.getEndLine();
                int startColumn = sourceCodePosition.getStartColumn();
                int endColumn = sourceCodePosition.getEndColumn();

                System.out.println("[(" + startLine + ", " + startColumn + "), (" + endLine + ", " + endColumn + ")]");

                for (int i = 0; i < inputLines.size(); i++)
                {
                    String errorLine = inputLines.get(i);
                    System.out.println(errorLine);

                    // Check if the line has the error somewhere in it, and mark the part of it that contains the error.
                    int pos = 0;

                    if (i == startLine)
                    {
                        for (; pos < startColumn; pos++)
                        {
                            System.out.print(" ");
                        }
                    }

                    if (i == endLine)
                    {
                        for (; pos <= endColumn; pos++)
                        {
                            System.out.print("^");
                        }

                        System.out.println();
                    }

                    if ((i > startLine) && (i < endLine))
                    {
                        for (; pos < errorLine.length(); pos++)
                        {
                            System.out.print("^");
                        }

                        System.out.println();
                    }
                }

                System.out.println();
                System.out.println(e.getMessage());
                System.out.println();

                inputLines.clear();
                tokenBuffer.clear();
            }
        }
    }
Implements the top-level interpreter loop. This will parse and evaluate sentences until it encounters an CTRL-D
in query mode, at which point the interpreter will terminate.

@throws SourceCodeException If malformed code is encountered.
@throws IOException         If an IO error is encountered whilst reading the source code.