All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bloodshura.sparkium.brainfxck.BrainfuckInterpreter Maven / Gradle / Ivy

The newest version!
package com.github.bloodshura.sparkium.brainfxck;

import com.github.bloodshura.ignitium.activity.logging.Logger;
import com.github.bloodshura.ignitium.activity.logging.XLogger;
import com.github.bloodshura.ignitium.activity.scanning.Scanner;
import com.github.bloodshura.ignitium.activity.scanning.XScanner;
import com.github.bloodshura.ignitium.charset.TextBuilder;
import com.github.bloodshura.ignitium.collection.store.impl.XQueue;
import com.github.bloodshura.ignitium.resource.Resource;
import com.github.bloodshura.sparkium.brainfxck.action.ActionSet;
import com.github.bloodshura.sparkium.brainfxck.action.impl.DefaultAction;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;

/**
 * This class is responsible for interpreting Brainfuck code, executing them, and maintaining the necessary resources, like the {@link BrainfuckMemory} instance, the output logger, the input scanner, etc.
 */
public class BrainfuckInterpreter {
	private final ActionSet actionSet;
	private final XQueue buffer;
	private Logger logger;
	private final BrainfuckMemory memory;
	private Scanner scanner;

	/**
	 * Constructs a new instance of the Brainfuck interpreter, using the default {@link ActionSet} and {@link BrainfuckMemory}.
	 * 

Note that, this interpreter automatically creates a console logger and console scanner. * * @see #BrainfuckInterpreter(ActionSet, BrainfuckMemory) */ public BrainfuckInterpreter() { this(new ActionSet(new DefaultAction()), new BrainfuckMemory()); } /** * Constructs a new instance of the Brainfuck interpreter, using the specified {@link ActionSet} and the default {@link BrainfuckMemory}. *

Note that, this interpreter automatically creates a console logger and console scanner. * * @param actionSet The {@link ActionSet} to be used * @see #BrainfuckInterpreter(ActionSet, BrainfuckMemory) */ public BrainfuckInterpreter(@Nonnull ActionSet actionSet) { this(actionSet, new BrainfuckMemory()); } /** * Constructs a new instance of the Brainfuck interpreter, using the default {@link ActionSet} and the specified {@link BrainfuckMemory}. *

Note that, this interpreter automatically creates a console logger and console scanner. * * @param memory The {@link BrainfuckMemory} to be used * @see #BrainfuckInterpreter(ActionSet, BrainfuckMemory) */ public BrainfuckInterpreter(@Nonnull BrainfuckMemory memory) { this(new ActionSet(new DefaultAction()), memory); } /** * Constructs a new instance of the Brainfuck interpreter, using the specified {@link ActionSet} and {@link BrainfuckMemory}. *

Note that, this interpreter automatically creates a console logger and console scanner. * * @param actionSet The {@link ActionSet} to be used * @param memory The {@link BrainfuckMemory} to be used * @see #setLogger(Logger) * @see #setScanner(Scanner) */ public BrainfuckInterpreter(@Nonnull ActionSet actionSet, @Nonnull BrainfuckMemory memory) { this.actionSet = actionSet; this.buffer = new XQueue<>(); this.memory = memory; setLogger(null); setScanner(null); } /** * Returns the unmodifiable {@link ActionSet} used by this interpreter. * * @return The action set */ @Nonnull public ActionSet getActionSet() { return actionSet; } /** * Returns the logger used by this interpreter, where code execution output goes. * * @return The output logger * @see #setLogger(Logger) */ @Nonnull public Logger getLogger() { return logger; } /** * Returns the instance responsible for memory management of the Brainfuck code ran by this interpreter. * * @return The memory manager */ @Nonnull public BrainfuckMemory getMemory() { return memory; } /** * Returns the scanner used by this interpreter, where code execution input comes from. * * @return The input scanner * @see #setScanner(Scanner) */ @Nonnull public Scanner getScanner() { return scanner; } /** * Interprets the Brainfuck code passed by parammeter. * * @param input The Brainfuck code * @throws IOException If an I/O exception occurs when interpreting the code; for example, I/O fails on the logger and/or scanner */ public void interpret(@Nonnull CharSequence input) throws IOException { BrainfuckContext context = new BrainfuckContext(this); input = removeComments(input); for (int i = 0; !Thread.interrupted() && i < input.length(); i++) { context.setCurrentIndex(i); context.interpret(input.charAt(i)); if (context.getCurrentIndex() != i) { i = context.getCurrentIndex() - 1; } } } /** * Interprets the resource passed by parammeter, passing it to a String and then calling the method {@link #interpret(CharSequence)}. * * @param resource The code resource * @throws IOException If an I/O exception occurs when trying to read String from the resource parammeter * @throws IOException If an I/O exception occurs when interpreting the code; for example, I/O fails on the logger and/or scanner * @see #interpret(CharSequence) */ public void interpret(@Nonnull Resource resource) throws IOException { interpret(resource.readString()); } /** * A convenient method to read an unique character from the input scanner. *

In this default implementation, it's used the {@link Scanner} specified on this interpreter; therefore, depending the input source, it will only be processed after a line feed is inserted. *

Because of those cases, an internal buffer is maintained, where all the characters are stored into and, on each call to this method, a single character is polled. * * @return The character read */ public char readChar() { if (!buffer.isEmpty()) { return buffer.poll(); } String line = getScanner().scan(); for (int i = 1; i < line.length(); i++) { buffer.push(line.charAt(i)); } return line.charAt(0); } /** * Changes the logger used by this interpreter. *

If the logger parameter is null, it will be assigned {@link XLogger#DEFAULT}. * * @param logger The output logger */ public void setLogger(@Nullable Logger logger) { this.logger = logger != null ? logger : XLogger.DEFAULT; } /** * Changes the scanner used by this interpreter. *

If the scanner parameter is null, it will be assigned {@link XScanner#DEFAULT}. * * @param scanner The input scanner */ public void setScanner(@Nullable Scanner scanner) { this.scanner = scanner != null ? scanner : XScanner.DEFAULT; } /** * Removes all comments present in the specified Brainfuck code. *

Comments start with a single quote ('), and end with a line feed (\n). * * @param The CharSequence class type * @param sequence The Brainfuck code, as a character sequence * @return The stripped Brainfuck code, without comments */ @Nonnull public static E removeComments(@Nonnull E sequence) { TextBuilder builder = new TextBuilder(); boolean removing = false; for (int i = 0; i < sequence.length(); i++) { char ch = sequence.charAt(i); if (ch == '\'') { removing = true; } else if (ch == '\n') { removing = false; } else if (!removing) { builder.append(ch); } } return (E) builder.get(sequence.getClass()); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy