diff options
| -rw-r--r-- | src/brainfuck/program.cr | 13 | ||||
| -rw-r--r-- | src/flint.cr | 110 | ||||
| -rw-r--r-- | src/program.cr | 13 | ||||
| -rw-r--r-- | src/thue/program.cr | 10 | ||||
| -rw-r--r-- | src/util.cr | 4 |
5 files changed, 93 insertions, 57 deletions
diff --git a/src/brainfuck/program.cr b/src/brainfuck/program.cr index 5b569df..4c3b41e 100644 --- a/src/brainfuck/program.cr +++ b/src/brainfuck/program.cr @@ -1,13 +1,18 @@ require "./parser.cr" +require "../program.cr" +require "../util.cr" -class Brainfuck::Program +struct Brainfuck::Program < Flint::Program @mem_size : Int32 - def initialize(@parser : Parser, mem_size : Int32?) - @mem_size = mem_size || DEFAULT_TAPE_SIZE + def initialize(source_io : IO, memory_size : Int32?) + super(source_io) + + @parser = Parser.new(source_io) + @mem_size = memory_size || DEFAULT_TAPE_SIZE end - def interpret + def interpret : Nil code = @parser.parse jumps = find_jumps(code) code_ptr = 0 diff --git a/src/flint.cr b/src/flint.cr index 20a9b54..a14e0c8 100644 --- a/src/flint.cr +++ b/src/flint.cr @@ -3,42 +3,49 @@ require "option_parser" require "./util.cr" +require "./program.cr" require "./brainfuck/*" require "./thue/*" module Flint VERSION = "0.1.1" + enum Language + Brainfuck + Thue + end + enum ExecutionMode Interpret Compile end + private def self.crash(message : String) + puts message + exit(1) + end + + private def self.crash(message : String, p : OptionParser) + puts message + puts p + exit(1) + end + + private def self.crash(message : String, ex_message : String?) + puts message + puts ex_message unless ex_message.nil? + exit(1) + end + def self.main execution_mode = ExecutionMode::Interpret - chosen_language = nil - memory_size = nil + language = nil source_file = nil read_stdin = false + language_options = Hash(Symbol, String).new parser = OptionParser.new do |parser| - parser.banner = "Basic usage: flint [LANGUAGE] [OPTIONS] [FILE]" - - parser.on("brainfuck", "select brainfuck as the language") do - chosen_language = :brainfuck - - parser.banner = "Usage: flint brainfuck [OPTIONS] [FILE]" - parser.on("-t CELLS", "--tape-size=CELLS", "specify the number of memory cells in the tape, defaults to 30,000") do |_cells| - memory_size = _cells.to_i - end - end - - parser.on("thue", "select Thue as the language") do - chosen_language = :thue - - parser.banner = "Usage: flint thue [OPTIONS] [FILE]" - # no thue-specific options yet - end + parser.banner = "Basic usage: flint [OPTIONS] [LANGUAGE] [FILE]" parser.on("-h", "--help", "show this help and exit") do puts parser @@ -51,55 +58,58 @@ module Flint parser.on("--stdin", "read source code from STDIN instead of a file") do read_stdin = true end + parser.on("-m CELLS", "--memory-size=CELLS", "specify the number of memory cells available, defaults vary depending on language") do |_cells| + language_options[:memory_size] = _cells + end parser.unknown_args do |_args| - source_file = _args[0]? + crash("ERROR: No language chosen", parser) if _args.size == 0 + crash("ERROR: No source file chosen", parser) if _args.size == 1 && !read_stdin + source_file = _args[1] unless read_stdin + language = case _args[0].downcase + when "brainfuck" then Language::Brainfuck + when "thue" then Language::Thue + else crash("ERROR: Unknown language specified: '#{_args[0]}'\nUser the '--supported-languages' flag to see whatlanguages are valid.", parser) + end end end parser.parse - source_io = read_stdin ? STDIN : source_file.try { |f| File.new(f) } - - if source_io.nil? - puts "ERROR: No source file chosen" - puts parser - exit(1) + # at this point, source_file and language are provably not nil + # the not_nil! method has to be used because the type-checker cannot deduce this + begin + source_io = read_stdin ? STDIN : File.new(source_file.not_nil!) + rescue File::NotFoundError + crash("ERROR: Could not load source file '#{source_file}'") end - case chosen_language - when :brainfuck - bf_parser = Brainfuck::Parser.new(source_io) - program = Brainfuck::Program.new(bf_parser, memory_size) - when :thue - thue_parser = Thue::Parser.new(source_io) - program = Thue::Program.new(thue_parser) - else - puts "ERROR: No language chosen" - puts parser - exit(1) - end + program = case language.not_nil! + in Language::Brainfuck + begin + m_str = language_options[:memory_size]? + m = m_str.try { |_m| _m.to_i} + rescue ArgumentError + crash("ERROR: Failed to parse the tape size value of '#{m_str}' as an integer", parser) + end + Brainfuck::Program.new(source_io, m) + in Language::Thue + Thue::Program.new(source_io) + end begin - p = program.not_nil! case execution_mode when ExecutionMode::Interpret - p.interpret + program.interpret when ExecutionMode::Compile - p.compile + program.compile end rescue ex : Util::ParserError - puts "Caught ParserError" - puts ex.message - exit(1) + crash("Caught ParserError", ex.message) rescue ex : Util::InterpreterError - puts "Error encountered while interpreting:" - puts ex.message - exit(1) + crash("Error encountered while interpreting:", ex.message) rescue ex : Util::CompilerError - puts "Failed to compile program:" - puts ex.message - exit(1) + crash("Failed to compile program:", ex.message) end end end diff --git a/src/program.cr b/src/program.cr new file mode 100644 index 0000000..9f92583 --- /dev/null +++ b/src/program.cr @@ -0,0 +1,13 @@ +require "./util.cr" + +abstract struct Flint::Program + def initialize(@source_io : IO) + end + + abstract def interpret : Nil + + def compile + raise Util::NoCompilerAvailableError.new("No compiler available for this language.") + end +end + diff --git a/src/thue/program.cr b/src/thue/program.cr index 96e1284..c9e5f2c 100644 --- a/src/thue/program.cr +++ b/src/thue/program.cr @@ -1,12 +1,16 @@ require "./thue.cr" require "./parser.cr" require "../util.cr" +require "../program.cr" -class Thue::Program - def initialize(@parser : Parser) +struct Thue::Program < Flint::Program + def initialize(source_io : IO) + super + + @parser = Parser.new(source_io) end - def interpret + def interpret : Nil rules, state = @parser.parse loop do diff --git a/src/util.cr b/src/util.cr index 8c5df5c..571a72e 100644 --- a/src/util.cr +++ b/src/util.cr @@ -1,4 +1,8 @@ module Util + alias OptionsBundle = { + memory_size: Int32? + } + class FlintError < Exception end |
