summaryrefslogtreecommitdiff
path: root/src/flint.cr
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2022-09-04 15:55:10 +1200
committerMatthew Hall <hallmatthew314@gmail.com>2022-09-04 15:55:10 +1200
commit2fe381c9a1719718d4a4dfc662f07db47af7831f (patch)
tree9878717f235f686849e685599500394a461e9b0e /src/flint.cr
parent70dbbd733758b61317af37af1cbbec6aa4b6e2a5 (diff)
Big refactor + Program base class
Diffstat (limited to 'src/flint.cr')
-rw-r--r--src/flint.cr110
1 files changed, 60 insertions, 50 deletions
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