cleanup, requires, namespacing to actually get it to work

This commit is contained in:
Torsten Ruger 2014-04-14 21:52:16 +03:00
parent 5ad36bbd56
commit 2e6b90b12e
16 changed files with 379 additions and 299 deletions

10
Gemfile
View File

@ -1,10 +1,10 @@
source "http://rubygems.org" source "http://rubygems.org"
group :development do group :development do
gem "minitest", ">= 0" gem "minitest"
gem "rdoc", "~> 3.12" gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0" gem "bundler"
gem "jeweler", "~> 2.0.1" gem "jeweler"
gem "simplecov", ">= 0" gem "simplecov"
gem "roodi", "~> 2.1.0" gem "roodi"
end end

72
Gemfile.lock Normal file
View File

@ -0,0 +1,72 @@
GEM
remote: http://rubygems.org/
specs:
addressable (2.3.6)
builder (3.2.2)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
docile (1.1.3)
faraday (0.9.0)
multipart-post (>= 1.2, < 3)
git (1.2.6)
github_api (0.11.3)
addressable (~> 2.3)
descendants_tracker (~> 0.0.1)
faraday (~> 0.8, < 0.10)
hashie (>= 1.2)
multi_json (>= 1.7.5, < 2.0)
nokogiri (~> 1.6.0)
oauth2
hashie (2.1.1)
highline (1.6.21)
jeweler (2.0.1)
builder
bundler (>= 1.0)
git (>= 1.2.5)
github_api
highline (>= 1.6.15)
nokogiri (>= 1.5.10)
rake
rdoc
json (1.8.1)
jwt (0.1.11)
multi_json (>= 1.5)
mini_portile (0.5.3)
minitest (5.3.2)
multi_json (1.9.2)
multi_xml (0.5.5)
multipart-post (2.0.0)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
oauth2 (0.9.3)
faraday (>= 0.8, < 0.10)
jwt (~> 0.1.8)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (~> 1.2)
rack (1.5.2)
rake (10.2.2)
rdoc (3.12.2)
json (~> 1.4)
roodi (2.1.0)
ruby_parser
ruby_parser (3.5.0)
sexp_processor (~> 4.1)
sexp_processor (4.4.3)
simplecov (0.8.2)
docile (~> 1.1.0)
multi_json
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
thread_safe (0.3.3)
PLATFORMS
ruby
DEPENDENCIES
bundler
jeweler
minitest
rdoc (~> 3.12)
roodi
simplecov

View File

@ -1,4 +1,4 @@
class Asm::ARM::AddrTableObject class Asm::Arm::AddrTableObject
def initialize def initialize
@table = [] @table = []
@const = [] @const = []
@ -21,8 +21,8 @@ class Asm::ARM::AddrTableObject
@table.each do |pair| @table.each do |pair|
target_label, here_label = *pair target_label, here_label = *pair
here_label.assemble io, as here_label.assemble io, as
as.add_relocation io.tell, target_label, Asm::ARM::R_ARM_ABS32, as.add_relocation io.tell, target_label, Asm::Arm::R_ARM_ABS32,
Asm::ARM::Instruction::RelocHandler Asm::Arm::Instruction::RelocHandler
io.write_uint32 0 io.write_uint32 0
end end
@const.each do |pair| @const.each do |pair|

View File

@ -1,54 +1,54 @@
require_relative 'assembler' require 'asm/assembler'
module Asm module Asm
module Arm module Arm
# Relocation constants # Relocation constants
# Note that in this assembler, a relocation simply means any # Note that in this assembler, a relocation simply means any
# reference to a label that can only be determined at assembly time # reference to a label that can only be determined at assembly time
# or later (as in the normal meaning) # or later (as in the normal meaning)
R_ARM_PC24 = 0x01 R_ARM_PC24 = 0x01
R_ARM_ABS32 = 0x02 R_ARM_ABS32 = 0x02
# Unofficial (cant be used for extern relocations) # Unofficial (cant be used for extern relocations)
R_ARM_PC12 = 0xF0 R_ARM_PC12 = 0xF0
# TODO actually find the closest somehow # TODO actually find the closest somehow
def self.closest_addrtable(as) def self.closest_addrtable(as)
as.objects.find do |obj| as.objects.find do |obj|
obj.is_a?(Asm::ARM::AddrTableObject) obj.is_a?(Asm::Arm::AddrTableObject)
end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil)) end || (raise Asm::AssemblyError.new('could not find addrtable to use', nil))
end end
def self.write_resolved_relocation(io, addr, type) def self.write_resolved_relocation(io, addr, type)
case type case type
when R_ARM_PC24 when R_ARM_PC24
diff = addr - io.tell - 8 diff = addr - io.tell - 8
packed = [diff >> 2].pack('l') packed = [diff >> 2].pack('l')
io << packed[0,3] io << packed[0,3]
when R_ARM_ABS32 when R_ARM_ABS32
packed = [addr].pack('l') packed = [addr].pack('l')
io << packed io << packed
when R_ARM_PC12 when R_ARM_PC12
diff = addr - io.tell - 8 diff = addr - io.tell - 8
if (diff.abs > 2047) if (diff.abs > 2047)
raise Asm::AssemblyError.new('offset too large for R_ARM_PC12 relocation', raise Asm::AssemblyError.new('offset too large for R_ARM_PC12 relocation',
nil) nil)
end
val = diff.abs
sign = (diff>0)?1:0
curr = io.read_uint32
io.seek(-4, IO::SEEK_CUR)
io.write_uint32 (curr & ~0b00000000100000000000111111111111) |
val | (sign << 23)
else
raise 'unknown relocation type'
end end
val = diff.abs
sign = (diff>0)?1:0
curr = io.read_uint32
io.seek(-4, IO::SEEK_CUR)
io.write_uint32 (curr & ~0b00000000100000000000111111111111) |
val | (sign << 23)
else
raise 'unknown relocation type'
end end
end end
end end

View File

@ -3,7 +3,7 @@ module Asm
# ADDRESSING MODE 1 # ADDRESSING MODE 1
# Complete! # Complete!
class BuilderA class BuilderA
include Asm::ARM::InstructionTools include Asm::Arm::InstructionTools
def initialize def initialize
@cond = 0b1110 @cond = 0b1110

View File

@ -1,9 +1,11 @@
require "asm/parser"
module Asm module Asm
module Arm module Arm
# ADDRESSING MODE 2 # ADDRESSING MODE 2
# Implemented: immediate offset with offset=0 # Implemented: immediate offset with offset=0
class BuilderB class BuilderB
include Asm::ARM::InstructionTools include Asm::Arm::InstructionTools
def initialize def initialize
@cond = 0b1110 @cond = 0b1110
@ -96,15 +98,15 @@ module Asm
(pre_post_index << 12+4+4+1+1+1+1) | (i << 12+4+4+1+1+1+1+1) | (pre_post_index << 12+4+4+1+1+1+1) | (i << 12+4+4+1+1+1+1+1) |
(inst_class << 12+4+4+1+1+1+1+1+1) | (cond << 12+4+4+1+1+1+1+1+1+2) (inst_class << 12+4+4+1+1+1+1+1+1) | (cond << 12+4+4+1+1+1+1+1+1+2)
if (@use_addrtable_reloc) if (@use_addrtable_reloc)
closest_addrtable = Asm::ARM.closest_addrtable(as) closest_addrtable = Asm::Arm.closest_addrtable(as)
if (@addrtable_reloc_target.is_a?(Asm::Parser::LabelEquivAddrArgNode)) if (@addrtable_reloc_target.is_a?(Asm::Parser::LabelEquivAddrArgNode))
obj = ast_asm.object_for_label(@addrtable_reloc_target.label, inst) obj = ast_asm.object_for_label(@addrtable_reloc_target.label, inst)
ref_label = closest_addrtable.add_label(obj) ref_label = closest_addrtable.add_label(obj)
elsif (@addrtable_reloc_target.is_a?(Asm::Parser::NumEquivAddrArgNode)) elsif (@addrtable_reloc_target.is_a?(Asm::Parser::NumEquivAddrArgNode))
ref_label = closest_addrtable.add_const(@addrtable_reloc_target.value) ref_label = closest_addrtable.add_const(@addrtable_reloc_target.value)
end end
as.add_relocation io.tell, ref_label, Asm::ARM::R_ARM_PC12, as.add_relocation io.tell, ref_label, Asm::Arm::R_ARM_PC12,
Asm::ARM::Instruction::RelocHandler Asm::Arm::Instruction::RelocHandler
end end
io.write_uint32 val io.write_uint32 val
end end

View File

@ -2,11 +2,11 @@ module Asm
module Arm module Arm
# ADDRESSING MODE 4 # ADDRESSING MODE 4
class BuilderD class BuilderD
include Asm::ARM::InstructionTools include Asm::Arm::InstructionTools
def initialize def initialize
@cond = 0b1110 @cond = 0b1110
@inst_class = Asm::ARM::Instruction::OPC_STACK @inst_class = Asm::Arm::Instruction::OPC_STACK
@pre_post_index = 0 @pre_post_index = 0
@up_down = 0 @up_down = 0
@s = 0 @s = 0

View File

@ -1,5 +1,8 @@
require_relative 'arm_assembler' require 'asm/arm/arm_assembler'
require_relative 'parser' require 'asm/arm/instruction'
require 'asm/label_object'
require 'asm/parser'
require 'stream_reader'
require 'stringio' require 'stringio'
module Asm module Asm
@ -51,7 +54,7 @@ module Asm
end end
} }
@asm.add_object Asm::ARM::Instruction.new(node) @asm.add_object Asm::Arm::Instruction.new(node)
end end
%w(adc add and bic eor orr rsb rsc sbc sub %w(adc add and bic eor orr rsb rsc sbc sub

View File

@ -1,7 +1,13 @@
require "asm/arm/instruction_tools"
require "asm/arm/builder_a"
require "asm/arm/builder_b"
require "asm/arm/builder_d"
module Asm module Asm
module Arm module Arm
class Asm::ARM::Instruction
include Asm::ARM::InstructionTools class Instruction
include InstructionTools
COND_POSTFIXES = Regexp.union(%w(eq ne cs cc mi pl vs vc hi ls ge lt gt le al)).source COND_POSTFIXES = Regexp.union(%w(eq ne cs cc mi pl vs vc hi ls ge lt gt le al)).source
def initialize(node, ast_asm = nil) def initialize(node, ast_asm = nil)
@ -63,7 +69,7 @@ module Asm
:vs => 0b0110 :vs => 0b0110
} }
RelocHandler = Asm::ARM.method(:write_resolved_relocation) RelocHandler = Asm::Arm.method(:write_resolved_relocation)
def assemble(io, as) def assemble(io, as)
s = @s ? 1 : 0 s = @s ? 1 : 0
@ -123,7 +129,7 @@ module Asm
io << packed[0,3] io << packed[0,3]
elsif (arg.is_a?(Asm::LabelObject) or arg.is_a?(Asm::Parser::LabelRefArgNode)) elsif (arg.is_a?(Asm::LabelObject) or arg.is_a?(Asm::Parser::LabelRefArgNode))
arg = @ast_asm.object_for_label(arg.label, self) if arg.is_a?(Asm::Parser::LabelRefArgNode) arg = @ast_asm.object_for_label(arg.label, self) if arg.is_a?(Asm::Parser::LabelRefArgNode)
as.add_relocation(io.tell, arg, Asm::ARM::R_ARM_PC24, RelocHandler) as.add_relocation(io.tell, arg, Asm::Arm::R_ARM_PC24, RelocHandler)
io << "\x00\x00\x00" io << "\x00\x00\x00"
end end
io.write_uint8 OPCODES[opcode] | (COND_BITS[@cond] << 4) io.write_uint8 OPCODES[opcode] | (COND_BITS[@cond] << 4)

View File

@ -1,6 +1,6 @@
module Asm module Asm
module Arm module Arm
module Asm::ARM::InstructionTools module Asm::Arm::InstructionTools
def reg_ref(arg) def reg_ref(arg)
if (not arg.is_a?(Asm::Parser::RegisterArgNode)) if (not arg.is_a?(Asm::Parser::RegisterArgNode))
raise Asm::AssemblyError.new('argument must be a register', arg) raise Asm::AssemblyError.new('argument must be a register', arg)

View File

@ -39,8 +39,8 @@ module Asm
elsif (cmd.name == "asciz") elsif (cmd.name == "asciz")
str = eval(cmd.value) + "\x00" str = eval(cmd.value) + "\x00"
@asm.add_object Asm::DataObject.new(str) @asm.add_object Asm::DataObject.new(str)
elsif (defined?(Asm::ARM) and cmd.name == 'addrtable') elsif (defined?(Asm::Arm) and cmd.name == 'addrtable')
@asm.add_object Asm::ARM::AddrTableObject.new @asm.add_object Asm::Arm::AddrTableObject.new
else else
raise Asm::AssemblyError.new('unknown directive', cmd) raise Asm::AssemblyError.new('unknown directive', cmd)
end end

View File

@ -86,7 +86,7 @@ module Asm
case options.target case options.target
when :arm when :arm
require_relative 'arm_assembler.rb' require_relative 'arm_assembler.rb'
as_module = Asm::ARM as_module = Asm::Arm
as_target = Elf::Constants::TARGET_ARM as_target = Elf::Constants::TARGET_ARM
when :ttk91 when :ttk91
require_relative 'ttk91_assembler.rb' require_relative 'ttk91_assembler.rb'

View File

@ -1,6 +1,6 @@
require_relative 'str_scanner' require_relative 'str_scanner'
module AS module Asm
class ParseError < StandardError class ParseError < StandardError
def initialize(message, s) def initialize(message, s)
super(message) super(message)
@ -10,258 +10,259 @@ module AS
end end
attr_reader :line, :column attr_reader :line, :column
end end
end
class Asm::Parser class Parser
def initialize(str) def initialize(str)
scanner = Asm::Scanner.new(str) scanner = Asm::Scanner.new(str)
@ast = parse_toplevel scanner @ast = parse_toplevel scanner
end end
attr_reader :ast attr_reader :ast
def self.parse(str) def self.parse(str)
new(str).ast new(str).ast
end end
class Node class Node
def initialize(s = nil) def initialize(s = nil)
if (s) if (s)
@line = s.prev_line @line = s.prev_line
@column = s.prev_column @column = s.prev_column
else else
@line = 0 @line = 0
@column = 0 @column = 0
end
yield self if block_given?
end end
attr_reader :line, :column
yield self if block_given?
end end
attr_reader :line, :column
end
class ToplevelNode < Node class ToplevelNode < Node
attr_accessor :children attr_accessor :children
end
def parse_toplevel(s)
node = ToplevelNode.new(s)
node.children = []
while (not s.eos?)
node.children << parse(s)
end end
node def parse_toplevel(s)
end node = ToplevelNode.new(s)
node.children = []
def parse(s) while (not s.eos?)
s.scan /\s*/ node.children << parse(s)
node = nil
%w(comment directive label instruction).each { |em|
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('could not parse element', s) unless node
s.scan /\s*/
node
end
class CommentNode < Node; end
def parse_comment(s)
if (s.scan(/;.*?$/))
CommentNode.new(s)
end
end
class DirectiveNode < Node
attr_accessor :name, :value
end
def parse_directive(s)
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
DirectiveNode.new(s) { |n|
n.name = m[0]
n.value = m[1]
}
end
end
class LabelNode < Node
attr_accessor :name
end
def parse_label(s)
if (m = s.scan(/(\/*\w+):/))
LabelNode.new(s) { |n|
n.name = m[0]
}
end
end
class InstructionNode < Node
attr_accessor :opcode, :args
end
def parse_instruction(s)
if (m = s.scan(/(\w+)/))
node = InstructionNode.new(s) { |n|
n.opcode = m[0]
n.args = []
}
if (not s.scan(/\s*($|;)/))
loop {
arg = parse_arg(s)
node.args << arg
break if not s.scan(/\s*,/)
}
end end
node node
end end
end
class ArgNode < Node def parse(s)
end s.scan /\s*/
def parse_arg(s) node = nil
s.scan /\s*/ %w(comment directive label instruction).each { |em|
node = nil if (node = send('parse_'+em, s))
%w(reference register register_list num_literal label_ref).each { |em| break
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('expected argument but none found', s) unless node
if (node2 = parse_arg_op(s))
node2.argument = node
node = node2
end
s.scan /\s*/
node
end
def parse_arg_op(s)
s.scan /\s*/
node = nil
%w(shift math).each do |em|
if (node = send('parse_'+em, s))
break
end
end
s.scan /\s*/
node
end
class ShiftNode < Node
attr_accessor :type, :value, :argument
end
def parse_shift(s)
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
op = m[0].downcase
if (op == 'rrx' or arg = parse_arg(s))
ShiftNode.new(s) { |n|
n.type = m[0].downcase
n.value = arg
}
else
nil
end
end
end
class MathNode < Node
attr_accessor :left, :right, :op
alias_method :argument, :left
alias_method :argument=, :left=
end
def parse_math(s)
if (m = s.scan_str(/[\+\-]/))
if (arg1 = parse_arg(s))
MathNode.new(s) do |n|
n.right = arg1
n.op = m
end end
else
raise Asm::ParseError.new('expected right side for arithmetic op', s)
end
end
end
REGISTER_REGEXP = Regexp.union(*%w(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
rfp sl fp ip sp lr pc
))
class RegisterArgNode < ArgNode
attr_accessor :name
end
def parse_register(s)
if (m = s.scan_str(REGISTER_REGEXP))
RegisterArgNode.new(s) { |n|
n.name = m
} }
raise Asm::ParseError.new('could not parse element', s) unless node
s.scan /\s*/
node
end end
end
class RegisterListArgNode < ArgNode class CommentNode < Node; end
attr_accessor :registers def parse_comment(s)
end if (s.scan(/;.*?$/))
def parse_register_list(s) CommentNode.new(s)
if (m = s.scan(/\{/))
node = RegisterListArgNode.new(s) do |n|
n.registers = []
end end
loop do end
s.scan /\s*/
reg = parse_register(s) class DirectiveNode < Node
if (not reg) attr_accessor :name, :value
return nil end
def parse_directive(s)
if (m = s.scan(/\.(\w+)(?:(?!$)\s+(.+)\s*?$)?/))
DirectiveNode.new(s) { |n|
n.name = m[0]
n.value = m[1]
}
end
end
class LabelNode < Node
attr_accessor :name
end
def parse_label(s)
if (m = s.scan(/(\/*\w+):/))
LabelNode.new(s) { |n|
n.name = m[0]
}
end
end
class InstructionNode < Node
attr_accessor :opcode, :args
end
def parse_instruction(s)
if (m = s.scan(/(\w+)/))
node = InstructionNode.new(s) { |n|
n.opcode = m[0]
n.args = []
}
if (not s.scan(/\s*($|;)/))
loop {
arg = parse_arg(s)
node.args << arg
break if not s.scan(/\s*,/)
}
end end
s.scan /\s*,?/ node
end
end
node.registers << reg class ArgNode < Node
end
def parse_arg(s)
s.scan /\s*/
node = nil
%w(reference register register_list num_literal label_ref).each { |em|
if (node = send('parse_'+em, s))
break
end
}
raise Asm::ParseError.new('expected argument but none found', s) unless node
if (s.scan(/\}/)) if (node2 = parse_arg_op(s))
node2.argument = node
node = node2
end
s.scan /\s*/
node
end
def parse_arg_op(s)
s.scan /\s*/
node = nil
%w(shift math).each do |em|
if (node = send('parse_'+em, s))
break break
end end
end end
s.scan /\s*/
node node
end end
end
class NumLiteralArgNode < ArgNode class ShiftNode < Node
attr_accessor :value attr_accessor :type, :value, :argument
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
def parse_num_literal(s)
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
(m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n|
n.value = Integer(m[1])
}
end end
end def parse_shift(s)
if (m = s.scan(/(lsl|lsr|asr|ror|rrx)\s+/i))
class LabelRefArgNode < ArgNode op = m[0].downcase
attr_accessor :label, :label_object if (op == 'rrx' or arg = parse_arg(s))
end ShiftNode.new(s) { |n|
class LabelEquivAddrArgNode < LabelRefArgNode n.type = m[0].downcase
end n.value = arg
def parse_label_ref(s) }
if (m = s.scan(/(=?)(\/*\w+)/)) else
(m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n| nil
n.label = m[1] end
} end
end end
end
class ReferenceArgNode < ArgNode class MathNode < Node
attr_accessor :argument attr_accessor :left, :right, :op
end alias_method :argument, :left
def parse_reference(s) alias_method :argument=, :left=
if (m = s.scan(/\[/)) end
arg = parse_arg(s) def parse_math(s)
if (arg and s.scan(/\]/)) if (m = s.scan_str(/[\+\-]/))
ReferenceArgNode.new(s) do |n| if (arg1 = parse_arg(s))
n.argument = arg MathNode.new(s) do |n|
n.right = arg1
n.op = m
end
else
raise Asm::ParseError.new('expected right side for arithmetic op', s)
end
end
end
REGISTER_REGEXP = Regexp.union(*%w(r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12
r13 r14 r15 a1 a2 a3 a4 v1 v2 v3 v4 v5 v6
rfp sl fp ip sp lr pc
))
class RegisterArgNode < ArgNode
attr_accessor :name
end
def parse_register(s)
if (m = s.scan_str(REGISTER_REGEXP))
RegisterArgNode.new(s) { |n|
n.name = m
}
end
end
class RegisterListArgNode < ArgNode
attr_accessor :registers
end
def parse_register_list(s)
if (m = s.scan(/\{/))
node = RegisterListArgNode.new(s) do |n|
n.registers = []
end
loop do
s.scan /\s*/
reg = parse_register(s)
if (not reg)
return nil
end
s.scan /\s*,?/
node.registers << reg
if (s.scan(/\}/))
break
end
end
node
end
end
class NumLiteralArgNode < ArgNode
attr_accessor :value
end
class NumEquivAddrArgNode < NumLiteralArgNode
end
def parse_num_literal(s)
if (m = s.scan(/(=?)#(-?(?:0x)?[0-9A-Fa-f]+)/))
(m[0] == '=' ? NumEquivAddrArgNode : NumLiteralArgNode).new(s) { |n|
n.value = Integer(m[1])
}
end
end
class LabelRefArgNode < ArgNode
attr_accessor :label, :label_object
end
class LabelEquivAddrArgNode < LabelRefArgNode
end
def parse_label_ref(s)
if (m = s.scan(/(=?)(\/*\w+)/))
(m[0] == '=' ? LabelEquivAddrArgNode : LabelRefArgNode).new(s) { |n|
n.label = m[1]
}
end
end
class ReferenceArgNode < ArgNode
attr_accessor :argument
end
def parse_reference(s)
if (m = s.scan(/\[/))
arg = parse_arg(s)
if (arg and s.scan(/\]/))
ReferenceArgNode.new(s) do |n|
n.argument = arg
end
end end
end end
end end
end end
end end
if (__FILE__ == $0) if (__FILE__ == $0)

View File

@ -1,6 +1,6 @@
if (__FILE__ == $0) if (__FILE__ == $0)
gen = Asm::ARMCodeGenerator.new gen = Asm::ArmCodeGenerator.new
gen.instance_eval { gen.instance_eval {
mov r0, 5 mov r0, 5

View File

@ -8,7 +8,7 @@ end
SimpleCov.configure do SimpleCov.configure do
clean_filters clean_filters
load_adapter 'test_frameworks' load_profile 'test_frameworks'
end end
ENV["COVERAGE"] && SimpleCov.start do ENV["COVERAGE"] && SimpleCov.start do
@ -23,13 +23,9 @@ rescue Bundler::BundlerError => e
$stderr.puts "Run `bundle install` to install missing gems" $stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code exit e.status_code
end end
require 'minitest/unit' require "minitest/autorun"
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))
require 'crystal' require 'crystal'
class MiniTest::Unit::TestCase
end
MiniTest::Unit.autorun