lojix/wam_prolog/src/main/com/thesett/aima/logic/fol/wam/compiler/InstructionCompiler.java
private void compileClause(Clause clause, WAMCompiledPredicate compiledPredicate, boolean isFirst, boolean isLast,
        boolean multipleClauses, int clauseNumber) throws SourceCodeException
    {
        // Used to build up the compiled clause in.
        WAMCompiledClause result = new WAMCompiledClause(compiledPredicate);

        // Check if the clause to compile is a fact (no body).
        boolean isFact = clause.getBody() == null;

        // Check if the clause to compile is a chain rule, (one called body).
        boolean isChainRule = (clause.getBody() != null) && (clause.getBody().length == 1);

        // Used to keep track of registers as they are seen during compilation. The first time a variable is seen,
        // a variable is written onto the heap, subsequent times its value. The first time a functor is seen,
        // its structure is written onto the heap, subsequent times it is compared with.
        seenRegisters = new TreeSet<Integer>();

        // This is used to keep track of the next temporary register available to allocate.
        lastAllocatedTempReg = findMaxArgumentsInClause(clause);

        // This is used to keep track of the number of permanent variables.
        numPermanentVars = 0;

        // This is used to keep track of the allocation slot for the cut level variable, when needed. -1 means it is
        // not needed, so it is initialized to this.
        cutLevelVarSlot = -1;

        // These are used to generate pre and post instructions for the clause, for example, for the creation and
        // clean-up of stack frames.
        SizeableList<WAMInstruction> preFixInstructions = new SizeableLinkedList<WAMInstruction>();
        SizeableList<WAMInstruction> postFixInstructions = new SizeableLinkedList<WAMInstruction>();

        // Find all the free non-anonymous variables in the clause.
        Set<Variable> freeVars = TermUtils.findFreeNonAnonymousVariables(clause);
        Collection<Integer> freeVarNames = new TreeSet<Integer>();

        for (Variable var : freeVars)
        {
            freeVarNames.add(var.getName());
        }

        // Allocate permanent variables for a program clause. Program clauses only use permanent variables when really
        // needed to preserve variables across calls.
        allocatePermanentProgramRegisters(clause);

        // Gather information about the counts and positions of occurrence of variables and constants within the clause.
        gatherPositionAndOccurrenceInfo(clause);

        // Labels the entry point to each choice point.
        FunctorName fn = interner.getFunctorFunctorName(clause.getHead());
        WAMLabel entryLabel = new WAMLabel(fn, clauseNumber);

        // Label for the entry point to the next choice point, to backtrack to.
        WAMLabel retryLabel = new WAMLabel(fn, clauseNumber + 1);

        // Create choice point instructions for the clause, depending on its position within the containing predicate.
        // The choice point instructions are only created when a predicate is built from multiple clauses, as otherwise
        // there are no choices to be made.
        if (isFirst && !isLast && multipleClauses)
        {
            // try me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TryMeElse,
                    retryLabel));
        }
        else if (!isFirst && !isLast && multipleClauses)
        {
            // retry me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.RetryMeElse,
                    retryLabel));
        }
        else if (isLast && multipleClauses)
        {
            // trust me.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TrustMe));
        }

        // Generate the prefix code for the clause.
        // Rules may chain multiple, so require stack frames to preserve registers across calls.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        // Chain rules only make one call, so also do not need a stack frame.
        if (!(isFact || isChainRule))
        {
            // Allocate a stack frame at the start of the clause.
            /*log.fine("ALLOCATE " + numPermanentVars);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Allocate));
        }

        // Deep cuts require the current choice point to be kept in a permanent variable, so that it can be recovered
        // once deeper choice points or environments have been reached.
        if (cutLevelVarSlot >= 0)
        {
            /*log.fine("GET_LEVEL "+ cutLevelVarSlot);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.GetLevel,
                    (byte) cutLevelVarSlot));
        }

        result.addInstructions(preFixInstructions);

        // Compile the clause head.
        Functor expression = clause.getHead();

        SizeableLinkedList<WAMInstruction> instructions = compileHead(expression);
        result.addInstructions(expression, instructions);

        // Compile all of the conjunctive parts of the body of the clause, if there are any.
        if (!isFact)
        {
            Functor[] expressions = clause.getBody();

            for (int i = 0; i < expressions.length; i++)
            {
                expression = expressions[i];

                boolean isLastBody = i == (expressions.length - 1);
                boolean isFirstBody = i == 0;

                Integer permVarsRemaining =
                    (Integer) symbolTable.get(expression.getSymbolKey(), SymbolTableKeys.SYMKEY_PERM_VARS_REMAINING);

                // Select a non-default built-in implementation to compile the functor with, if it is a built-in.
                BuiltIn builtIn;

                if (expression instanceof BuiltIn)
                {
                    builtIn = (BuiltIn) expression;
                }
                else
                {
                    builtIn = this;
                }

                // The 'isFirstBody' parameter is only set to true, when this is the first functor of a rule.
                instructions = builtIn.compileBodyArguments(expression, i == 0, fn, i);
                result.addInstructions(expression, instructions);

                // Call the body. The number of permanent variables remaining is specified for environment trimming.
                instructions =
                    builtIn.compileBodyCall(expression, isFirstBody, isLastBody, isChainRule, permVarsRemaining);
                result.addInstructions(expression, instructions);
            }
        }

        // Generate the postfix code for the clause. Rules may chain, so require stack frames.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        if (isFact)
        {
            /*log.fine("PROCEED");*/
            postFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Proceed));
        }

        result.addInstructions(postFixInstructions);
    }
private void compileClause(Clause clause, WAMCompiledPredicate compiledPredicate, boolean isFirst, boolean isLast,
        boolean multipleClauses, int clauseNumber) throws SourceCodeException
    {
        // Used to build up the compiled clause in.
        WAMCompiledClause result = new WAMCompiledClause(compiledPredicate);

        // Check if the clause to compile is a fact (no body).
        boolean isFact = clause.getBody() == null;

        // Check if the clause to compile is a chain rule, (one called body).
        boolean isChainRule = (clause.getBody() != null) && (clause.getBody().length == 1);

        // Used to keep track of registers as they are seen during compilation. The first time a variable is seen,
        // a variable is written onto the heap, subsequent times its value. The first time a functor is seen,
        // its structure is written onto the heap, subsequent times it is compared with.
        seenRegisters = new TreeSet<Integer>();

        // This is used to keep track of the next temporary register available to allocate.
        lastAllocatedTempReg = findMaxArgumentsInClause(clause);

        // This is used to keep track of the number of permanent variables.
        numPermanentVars = 0;

        // This is used to keep track of the allocation slot for the cut level variable, when needed. -1 means it is
        // not needed, so it is initialized to this.
        cutLevelVarSlot = -1;

        // These are used to generate pre and post instructions for the clause, for example, for the creation and
        // clean-up of stack frames.
        SizeableList<WAMInstruction> preFixInstructions = new SizeableLinkedList<WAMInstruction>();
        SizeableList<WAMInstruction> postFixInstructions = new SizeableLinkedList<WAMInstruction>();

        // Find all the free non-anonymous variables in the clause.
        Set<Variable> freeVars = TermUtils.findFreeNonAnonymousVariables(clause);
        Collection<Integer> freeVarNames = new TreeSet<Integer>();

        for (Variable var : freeVars)
        {
            freeVarNames.add(var.getName());
        }

        // Allocate permanent variables for a program clause. Program clauses only use permanent variables when really
        // needed to preserve variables across calls.
        allocatePermanentProgramRegisters(clause);

        // Gather information about the counts and positions of occurrence of variables and constants within the clause.
        gatherPositionAndOccurrenceInfo(clause);

        // Labels the entry point to each choice point.
        FunctorName fn = interner.getFunctorFunctorName(clause.getHead());
        WAMLabel entryLabel = new WAMLabel(fn, clauseNumber);

        // Label for the entry point to the next choice point, to backtrack to.
        WAMLabel retryLabel = new WAMLabel(fn, clauseNumber + 1);

        // Create choice point instructions for the clause, depending on its position within the containing predicate.
        // The choice point instructions are only created when a predicate is built from multiple clauses, as otherwise
        // there are no choices to be made.
        if (isFirst && !isLast && multipleClauses)
        {
            // try me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TryMeElse,
                    retryLabel));
        }
        else if (!isFirst && !isLast && multipleClauses)
        {
            // retry me else.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.RetryMeElse,
                    retryLabel));
        }
        else if (isLast && multipleClauses)
        {
            // trust me.
            preFixInstructions.add(new WAMInstruction(entryLabel, WAMInstruction.WAMInstructionSet.TrustMe));
        }

        // Generate the prefix code for the clause.
        // Rules may chain multiple, so require stack frames to preserve registers across calls.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        // Chain rules only make one call, so also do not need a stack frame.
        if (!(isFact || isChainRule))
        {
            // Allocate a stack frame at the start of the clause.
            /*log.fine("ALLOCATE " + numPermanentVars);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Allocate));
        }

        // Deep cuts require the current choice point to be kept in a permanent variable, so that it can be recovered
        // once deeper choice points or environments have been reached.
        if (cutLevelVarSlot >= 0)
        {
            /*log.fine("GET_LEVEL "+ cutLevelVarSlot);*/
            preFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.GetLevel,
                    (byte) cutLevelVarSlot));
        }

        result.addInstructions(preFixInstructions);

        // Compile the clause head.
        Functor expression = clause.getHead();

        SizeableLinkedList<WAMInstruction> instructions = compileHead(expression);
        result.addInstructions(expression, instructions);

        // Compile all of the conjunctive parts of the body of the clause, if there are any.
        if (!isFact)
        {
            Functor[] expressions = clause.getBody();

            for (int i = 0; i < expressions.length; i++)
            {
                expression = expressions[i];

                boolean isLastBody = i == (expressions.length - 1);
                boolean isFirstBody = i == 0;

                Integer permVarsRemaining =
                    (Integer) symbolTable.get(expression.getSymbolKey(), SymbolTableKeys.SYMKEY_PERM_VARS_REMAINING);

                // Select a non-default built-in implementation to compile the functor with, if it is a built-in.
                BuiltIn builtIn;

                if (expression instanceof BuiltIn)
                {
                    builtIn = (BuiltIn) expression;
                }
                else
                {
                    builtIn = this;
                }

                // The 'isFirstBody' parameter is only set to true, when this is the first functor of a rule.
                instructions = builtIn.compileBodyArguments(expression, i == 0, fn, i);
                result.addInstructions(expression, instructions);

                // Call the body. The number of permanent variables remaining is specified for environment trimming.
                instructions =
                    builtIn.compileBodyCall(expression, isFirstBody, isLastBody, isChainRule, permVarsRemaining);
                result.addInstructions(expression, instructions);
            }
        }

        // Generate the postfix code for the clause. Rules may chain, so require stack frames.
        // Facts are always leafs so can use the global continuation point register to return from calls.
        if (isFact)
        {
            /*log.fine("PROCEED");*/
            postFixInstructions.add(new WAMInstruction(WAMInstruction.WAMInstructionSet.Proceed));
        }

        result.addInstructions(postFixInstructions);
    }
private void compileClause ( Clause clause , WAMCompiledPredicate compiledPredicate , boolean isFirst , boolean isLast , boolean multipleClauses , int clauseNumber ) throws SourceCodeException { // Used to build up the compiled clause in. WAMCompiledClause result = new WAMCompiledClause ( compiledPredicate ) ; // Check if the clause to compile is a fact (no body). boolean isFact = clause . getBody ( ) == null ; // Check if the clause to compile is a chain rule, (one called body). boolean isChainRule = ( clause . getBody ( ) != null ) && ( clause . getBody ( ) . length == 1 ) ; // Used to keep track of registers as they are seen during compilation. The first time a variable is seen, // a variable is written onto the heap, subsequent times its value. The first time a functor is seen, // its structure is written onto the heap, subsequent times it is compared with. seenRegisters = new TreeSet < Integer > ( ) ; // This is used to keep track of the next temporary register available to allocate. lastAllocatedTempReg = findMaxArgumentsInClause ( clause ) ; // This is used to keep track of the number of permanent variables. numPermanentVars = 0 ; // This is used to keep track of the allocation slot for the cut level variable, when needed. -1 means it is // not needed, so it is initialized to this. cutLevelVarSlot = - 1 ; // These are used to generate pre and post instructions for the clause, for example, for the creation and // clean-up of stack frames. SizeableList < WAMInstruction > preFixInstructions = new SizeableLinkedList < WAMInstruction > ( ) ; SizeableList < WAMInstruction > postFixInstructions = new SizeableLinkedList < WAMInstruction > ( ) ; // Find all the free non-anonymous variables in the clause. Set < Variable > freeVars = TermUtils . findFreeNonAnonymousVariables ( clause ) ; Collection < Integer > freeVarNames = new TreeSet < Integer > ( ) ; for ( Variable var : freeVars ) { freeVarNames . add ( var . getName ( ) ) ; } // Allocate permanent variables for a program clause. Program clauses only use permanent variables when really // needed to preserve variables across calls. allocatePermanentProgramRegisters ( clause ) ; // Gather information about the counts and positions of occurrence of variables and constants within the clause. gatherPositionAndOccurrenceInfo ( clause ) ; // Labels the entry point to each choice point. FunctorName fn = interner . getFunctorFunctorName ( clause . getHead ( ) ) ; WAMLabel entryLabel = new WAMLabel ( fn , clauseNumber ) ; // Label for the entry point to the next choice point, to backtrack to. WAMLabel retryLabel = new WAMLabel ( fn , clauseNumber + 1 ) ; // Create choice point instructions for the clause, depending on its position within the containing predicate. // The choice point instructions are only created when a predicate is built from multiple clauses, as otherwise // there are no choices to be made. if ( isFirst && ! isLast && multipleClauses ) { // try me else. preFixInstructions . add ( new WAMInstruction ( entryLabel , WAMInstruction . WAMInstructionSet . TryMeElse , retryLabel ) ) ; } else if ( ! isFirst && ! isLast && multipleClauses ) { // retry me else. preFixInstructions . add ( new WAMInstruction ( entryLabel , WAMInstruction . WAMInstructionSet . RetryMeElse , retryLabel ) ) ; } else if ( isLast && multipleClauses ) { // trust me. preFixInstructions . add ( new WAMInstruction ( entryLabel , WAMInstruction . WAMInstructionSet . TrustMe ) ) ; } // Generate the prefix code for the clause. // Rules may chain multiple, so require stack frames to preserve registers across calls. // Facts are always leafs so can use the global continuation point register to return from calls. // Chain rules only make one call, so also do not need a stack frame. if ( ! ( isFact || isChainRule ) ) { // Allocate a stack frame at the start of the clause. /*log.fine("ALLOCATE " + numPermanentVars);*/ preFixInstructions . add ( new WAMInstruction ( WAMInstruction . WAMInstructionSet . Allocate ) ) ; } // Deep cuts require the current choice point to be kept in a permanent variable, so that it can be recovered // once deeper choice points or environments have been reached. if ( cutLevelVarSlot >= 0 ) { /*log.fine("GET_LEVEL "+ cutLevelVarSlot);*/ preFixInstructions . add ( new WAMInstruction ( WAMInstruction . WAMInstructionSet . GetLevel , ( byte ) cutLevelVarSlot ) ) ; } result . addInstructions ( preFixInstructions ) ; // Compile the clause head. Functor expression = clause . getHead ( ) ; SizeableLinkedList < WAMInstruction > instructions = compileHead ( expression ) ; result . addInstructions ( expression , instructions ) ; // Compile all of the conjunctive parts of the body of the clause, if there are any. if ( ! isFact ) { Functor [ ] expressions = clause . getBody ( ) ; for ( int i = 0 ; i < expressions . length ; i ++ ) { expression = expressions [ i ] ; boolean isLastBody = i == ( expressions . length - 1 ) ; boolean isFirstBody = i == 0 ; Integer permVarsRemaining = ( Integer ) symbolTable . get ( expression . getSymbolKey ( ) , SymbolTableKeys . SYMKEY_PERM_VARS_REMAINING ) ; // Select a non-default built-in implementation to compile the functor with, if it is a built-in. BuiltIn builtIn ; if ( expression instanceof BuiltIn ) { builtIn = ( BuiltIn ) expression ; } else { builtIn = this ; } // The 'isFirstBody' parameter is only set to true, when this is the first functor of a rule. instructions = builtIn . compileBodyArguments ( expression , i == 0 , fn , i ) ; result . addInstructions ( expression , instructions ) ; // Call the body. The number of permanent variables remaining is specified for environment trimming. instructions = builtIn . compileBodyCall ( expression , isFirstBody , isLastBody , isChainRule , permVarsRemaining ) ; result . addInstructions ( expression , instructions ) ; } } // Generate the postfix code for the clause. Rules may chain, so require stack frames. // Facts are always leafs so can use the global continuation point register to return from calls. if ( isFact ) { /*log.fine("PROCEED");*/ postFixInstructions . add ( new WAMInstruction ( WAMInstruction . WAMInstructionSet . Proceed ) ) ; } result . addInstructions ( postFixInstructions ) ; }
Compiles a program clause, and adds its instructions to a compiled predicate.

@param  clause            The source clause to compile.
@param  compiledPredicate The predicate to add instructions to.
@param  isFirst           <tt>true</tt> iff the clause is the first in the predicate.
@param  isLast            <tt>true</tt> iff the clause is the last in the predicate.
@param  multipleClauses   <tt>true</tt> iff the predicate contains >1 clause.
@param  clauseNumber      The position of the clause within the predicate.

@throws SourceCodeException If there is an error in the source code preventing its compilation.
Compiles a program clause and adds its instructions to a compiled predicate .