001package components.program;
002
003import components.queue.Queue;
004import components.sequence.Sequence;
005import components.simplereader.SimpleReader;
006import components.simplewriter.SimpleWriter;
007
008/**
009 * {@code ProgramKernel} enhanced with secondary methods.
010 */
011public interface Program extends ProgramKernel {
012
013    /**
014     * A constant, with value 4, holding the number of spaces added for each
015     * indentation level when pretty printing a {@code Program} object.
016     */
017    int INDENT_SIZE = 4;
018
019    /**
020     * BugsWorld virtual machine instructions and "byte codes".
021     */
022    enum Instruction {
023        /**
024         * Byte code = 0.
025         */
026        MOVE(0),
027
028        /**
029         * Byte code = 1.
030         */
031        TURNLEFT(1),
032
033        /**
034         * Byte code = 2.
035         */
036        TURNRIGHT(2),
037
038        /**
039         * Byte code = 3.
040         */
041        INFECT(3),
042
043        /**
044         * Byte code = 4.
045         */
046        SKIP(4),
047
048        /**
049         * Byte code = 5.
050         */
051        HALT(5),
052
053        /**
054         * Byte code = 6.
055         */
056        JUMP(6),
057
058        /**
059         * Byte code = 7.
060         */
061        JUMP_IF_NOT_NEXT_IS_EMPTY(7),
062
063        /**
064         * Byte code = 8.
065         */
066        JUMP_IF_NOT_NEXT_IS_NOT_EMPTY(8),
067
068        /**
069         * Byte code = 9.
070         */
071        JUMP_IF_NOT_NEXT_IS_WALL(9),
072
073        /**
074         * Byte code = 10.
075         */
076        JUMP_IF_NOT_NEXT_IS_NOT_WALL(10),
077
078        /**
079         * Byte code = 11.
080         */
081        JUMP_IF_NOT_NEXT_IS_FRIEND(11),
082
083        /**
084         * Byte code = 12.
085         */
086        JUMP_IF_NOT_NEXT_IS_NOT_FRIEND(12),
087
088        /**
089         * Byte code = 13.
090         */
091        JUMP_IF_NOT_NEXT_IS_ENEMY(13),
092
093        /**
094         * Byte code = 14.
095         */
096        JUMP_IF_NOT_NEXT_IS_NOT_ENEMY(14),
097
098        /**
099         * Byte code = 15.
100         */
101        JUMP_IF_NOT_RANDOM(15),
102
103        /**
104         * Byte code = 16.
105         */
106        JUMP_IF_NOT_TRUE(16);
107
108        /**
109         * Instruction byte code.
110         */
111        private final int blByteCode;
112
113        /**
114         * Constructor.
115         *
116         * @param code
117         *            the instruction byte code
118         */
119        Instruction(int code) {
120            this.blByteCode = code;
121        }
122
123        /**
124         * Returns the instruction byte code.
125         *
126         * @return the instruction byte code
127         */
128        public int byteCode() {
129            return this.blByteCode;
130        }
131
132    }
133
134    /**
135     * Pretty prints {@code this} to the given stream {@code out} using
136     * {@link #INDENT_SIZE INDENT_SIZE} spaces for each indentation level.
137     *
138     * @param out
139     *            the output stream
140     * @updates out.content
141     * @requires out.is_open
142     * @ensures <pre>
143     * out.content =
144     *   #out.content * [this pretty printed using INDENT_SIZE spaces for indentation]
145     * </pre>
146     */
147    void prettyPrint(SimpleWriter out);
148
149    /**
150     * Parses a BL program from {@code in} into {@code this}.
151     *
152     * @param in
153     *            the input stream
154     * @replaces this
155     * @updates in.content
156     * @requires in.is_open
157     * @ensures {@code
158     * if #in.content = [a program string]  and
159     *    [the last token of #in.content equals the name of the program supplied
160     *     near the beginning]  and
161     *    [the beginning name of each new instruction equals its ending name]  and
162     *    [none of the names of the new instructions equals the name of a primitive
163     *     instruction in the BL language or the name of any other new
164     *     instruction] then
165     *  this = [Program corresponding to program string #in.content]  and
166     *  in.content = <>
167     * else
168     *  [reports an appropriate error message to the console and terminates client]
169     * }
170     */
171    void parse(SimpleReader in);
172
173    /**
174     * Parses a BL program from {@code tokens} into {@code this}.
175     *
176     * @param tokens
177     *            the input tokens
178     * @replaces this
179     * @updates tokens
180     * @requires {@code [<Tokenizer.END_OF_INPUT> is a suffix of tokens]}
181     * @ensures {@code
182     * if #tokens = [a program string] * <Tokenizer.END_OF_INPUT>  and
183     *    [the penultimate token of #tokens equals the name of the program supplied
184     *     near the beginning]  and
185     *    [the beginning name of each new instruction equals its ending name]  and
186     *    [none of the names of the new instructions equals the name of a primitive
187     *     instruction in the BL language or the name of any other new
188     *     instruction] then
189     *  this = [Program corresponding to program string at start of #tokens]  and
190     *  tokens = <Tokenizer.END_OF_INPUT>
191     * else
192     *  [reports an appropriate error message to the console and terminates client]
193     * }
194     */
195    void parse(Queue<String> tokens);
196
197    /**
198     * Generates and returns the sequence of virtual machine instructions (
199     * "byte codes") corresponding to {@code this}.
200     *
201     * @return the compiled program
202     * @ensures <pre>
203     * if [all instructions called in this are either primitive or
204     *     defined in this.context]  and
205     *    [this does not include any calling cycles, i.e., recursion] then
206     *  generatedCode =
207     *   [the sequence of virtual machine "byte codes" corresponding to this]
208     * else
209     *  [reports an appropriate error message to the console and terminates client]
210     * </pre>
211     */
212    Sequence<Integer> generatedCode();
213
214}