special-giggle 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 51b322e0b69121f5f57d8b7a514783d86dc33d06c7e81b59b33c36129f06741b
4
+ data.tar.gz: f74f42bb454c31cf959493f856904eb969fcc58aa19ab3fb0bb231c7d1883c3f
5
+ SHA512:
6
+ metadata.gz: 7064c01e544f59f15b46dd552ead4eba0a1b36b2a9dc854f1f57af40e98bbb20abc824d261411aa308bee06bf6ea740387141b61cbc6a130ca627e676a5e40fb
7
+ data.tar.gz: a08e189d09bf5d5f4b7f003fff659cc4229a7ca6f2461f668e9b0332a4b2e22b07971fb879e7607abf1b6dfbafe9bf66812da393f4530436826a3b89739d8e21
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ /pkg/
2
+ /tmp/
3
+
4
+ # Unit test
5
+ /test/*/*/*.s
6
+ /test/*/*/*.o
7
+ /test/*/*/*.bin
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ TODO
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in special-giggle.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ special-giggle (1.0.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ irb (1.0.0)
10
+ rake (10.5.0)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 2.0)
17
+ irb (~> 1.0)
18
+ rake (~> 10.0)
19
+ special-giggle!
20
+
21
+ BUNDLED WITH
22
+ 2.0.2
data/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # SpecialGiggle (Under Development)
2
+
3
+ Compiler for BX language, written fully in Ruby
4
+
5
+ ## Changelog
6
+
7
+ See [CHANGELOG.md](CHANGELOG.md) for more details
8
+
9
+ ## Specification
10
+
11
+ See [SPECIFICATION.md](SPECIFICATION.md) for details
12
+
13
+ ## Version Convention
14
+
15
+ - Patch 0.0.x: Implementation level changes, such as bugfixes
16
+ - Minor 0.x.0: Backwards compatible API changes, such as new functionality and feature
17
+ - Major x.0.0: Backwards incompatible API changes, such as changes that will break existing codes
18
+
19
+ ## Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'special-giggle'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ $ bundle
30
+
31
+ Or install it yourself as:
32
+
33
+ $ gem install special-giggle
34
+
35
+ ## Usage
36
+
37
+ ```ruby
38
+ require 'special-giggle'
39
+
40
+ SpecialGiggle.compile("file.bx", "file.bin")
41
+ ```
42
+
43
+ ## Development
44
+
45
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
46
+
47
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
48
+
49
+ ## Contributing
50
+
51
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kalari499/special-giggle.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ # Default
5
+ task :default => :spec
6
+
7
+ # Build
8
+ desc "Build special-giggle Gem"
9
+ task :build do
10
+ sh %{gem build special-giggle.gemspec}
11
+ end
12
+
13
+ # Unit test
14
+ Rake::TestTask.new(:test => [:test_good, :test_bad]) do |t|
15
+ t.description = "Unit testing: All tests"
16
+ end
17
+
18
+ Rake::TestTask.new(:test_good) do |t|
19
+ t.description = "Unit testing: Good programs"
20
+ t.test_files = ['test/good/unit.rb']
21
+ end
22
+
23
+ Rake::TestTask.new(:test_bad) do |t|
24
+ t.description = "Unit testing: Bad programs - Not implemented"
25
+ t.test_files = []
26
+ end
27
+
data/SPECIFICATION.md ADDED
@@ -0,0 +1,3 @@
1
+ ## BX Language Specification
2
+
3
+ TODO
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "special-giggle"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,27 @@
1
+ require 'special-giggle/lexer'
2
+ require 'special-giggle/parser'
3
+ require 'special-giggle/generator'
4
+
5
+ module SpecialGiggle
6
+ include Lexer
7
+ include Parser
8
+ include Generator
9
+
10
+ class GiggleError < StandardError; end
11
+
12
+ def self.to_asm(string)
13
+ tokens = Lexer.tokenize(string)
14
+ ast = Parser.parse(tokens)
15
+ code = Generator.generate(ast)
16
+ code
17
+ end
18
+
19
+ def self.compile(infile, outfile, tmpdir = "/tmp")
20
+ raise GiggleError, "Input file #{infile} does not found." unless File.exist?(infile)
21
+ file = File.basename(infile, ".*")
22
+ sfile, ofile = File.expand_path("#{file}.s", tmpdir), File.expand_path("#{file}.o", tmpdir)
23
+ File.write(sfile, to_asm(File.read(infile)))
24
+ system("as --64 -o #{ofile} #{sfile}") || (raise GiggleError, "Can't compile with as")
25
+ system("gcc -no-pie -o #{outfile} #{ofile}") || (raise GiggleError, "Can't link with gcc")
26
+ end
27
+ end
@@ -0,0 +1,143 @@
1
+ module Generator
2
+ class GeneratorError < StandardError; end
3
+
4
+ class Token
5
+ def initialize(type, src = nil, dst = nil)
6
+ @type, @src, @dst = type, src, dst
7
+ end
8
+
9
+ def need_imm?
10
+ end
11
+
12
+ def to_code
13
+ case @type
14
+ when :Print
15
+ [ "movq #{@src}, %rsi", "movq $__print_fmt, %rdi", "movq $0, %rax", "call printf" ]
16
+ when :Move
17
+ [ @src.is_a?(Integer) ? "movq $#{@src}, %r11" : "movq #{@src}, %r11", "movq %r11, #{@dst}" ]
18
+ when :Tilde
19
+ [ "movq #{@src}, %r11", "notq %r11", "movq %r11, #{@dst}" ]
20
+ when :Negative
21
+ [ "movq #{@src}, %r11", "negq %r11", "movq %r11, #{@dst}" ]
22
+ when :Plus
23
+ [ "movq #{@src[0]}, %r11", "movq %r11, #{@dst}", "movq #{@src[1]}, %r11", "addq %r11, #{@dst}"]
24
+ when :Minus
25
+ [ "movq #{@src[0]}, %r11", "movq %r11, #{@dst}", "movq #{@src[1]}, %r11", "subq %r11, #{@dst}"]
26
+ when :Asterisk
27
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "imulq %rcx", "movq %rax, #{@dst}" ]
28
+ when :Slash
29
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "cqo", "idivq %rcx", "movq %rax, #{@dst}" ]
30
+ when :Percent
31
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "cqo", "idivq %rcx", "movq %rdx, #{@dst}" ]
32
+ when :Bar
33
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "orq %rcx, %rax", "movq %rax, #{@dst}" ]
34
+ when :Ampersand
35
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "andq %rcx, %rax", "movq %rax, #{@dst}" ]
36
+ when :Caret
37
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "xorq %rcx, %rax", "movq %rax, #{@dst}" ]
38
+ when :LeftShift
39
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "salq %cl, %rax", "movq %rax, #{@dst}" ]
40
+ when :RightShift
41
+ [ "movq #{@src[0]}, %rax", "movq #{@src[1]}, %rcx", "sarq %cl, %rax", "movq %rax, #{@dst}" ]
42
+ end
43
+ end
44
+ end
45
+
46
+ BinaryOps = {
47
+ :Plus => 50,
48
+ :Minus => 50,
49
+ :Asterisk => 60,
50
+ :Slash => 60,
51
+ :Percent => 60,
52
+ :Bar => 10,
53
+ :Ampersand => 30,
54
+ :Caret => 20,
55
+ :LeftShift => 40,
56
+ :RightShift => 40,
57
+ }
58
+
59
+ UnaryOps = {
60
+ :Tilde => 70,
61
+ :Negative => 80,
62
+ }
63
+
64
+ Vars = Array.new
65
+
66
+ def self.var_temp
67
+ #var = "#{8 * Vars.length}(%rsp)"
68
+ var = "tmp_#{Vars.length}"
69
+ Vars << var unless Vars.include?(var)
70
+ var
71
+ end
72
+
73
+ def self.generate_expression(token)
74
+ if token.type == :Number
75
+ t = var_temp
76
+ [t, [Token.new(:Move, token.child[0], t)]]
77
+ elsif token.type == :Variable
78
+ [token.child[0], []]
79
+ elsif token.type == :Bracket
80
+ var, array = generate_expression(token.child[0])
81
+ t = var_temp
82
+ [t, [array, Token.new(:Move, var, t)]]
83
+ elsif UnaryOps.include?(token.type)
84
+ var, array = generate_expression(token.child[0])
85
+ t = var_temp
86
+ [t, [array, Token.new(token.type, var, t)]]
87
+ else
88
+ var1, array1 = generate_expression(token.child[0])
89
+ var2, array2 = generate_expression(token.child[1])
90
+ t = var_temp
91
+ [t, [array1, array2, Token.new(token.type, [var1, var2], t)]]
92
+ end
93
+ end
94
+
95
+ def self.generate_statement(token)
96
+ array = Array.new
97
+ if token.type == :Print
98
+ var, garray = generate_expression(token.child[0])
99
+ array << garray unless garray.empty?
100
+ array << Token.new(:Print, var)
101
+ elsif token.type == :Move
102
+ Vars << token.child[0].child[0] unless Vars.include?(token.child[0].child[0])
103
+ var, garray = generate_expression(token.child[1])
104
+ array << garray unless garray.empty?
105
+ array << Token.new(:Move, var, token.child[0].child[0])
106
+ end
107
+ array
108
+ end
109
+
110
+ def self.generate(token)
111
+ array = Array.new
112
+ token.child.each do |statement|
113
+ array << generate_statement(statement)
114
+ end
115
+
116
+ output = %{
117
+ .section .data
118
+ __print_fmt:
119
+ .string "%ld\\n"
120
+
121
+ .section .text
122
+ .globl main
123
+ main:
124
+ pushq %rbp
125
+ movq %rsp, %rbp
126
+ subq <VARIABLE>, %rsp
127
+
128
+ <CODE>
129
+ movq %rbp, %rsp
130
+ popq %rbp
131
+ movq $0, %rax
132
+ retq
133
+ }
134
+ text = ""
135
+ array.flatten.each { |ops| ops.to_code.each { |line| text += " " * 2 + line + "\n" } }
136
+
137
+ Vars.length.times do |i|
138
+ regex = "(?<![\\w])#{Vars[i]}(?![\\w])"
139
+ text.gsub!(/#{regex}/, i > 0 ? "#{8*i}(%rsp)" : "(%rsp)")
140
+ end
141
+ output.gsub('<VARIABLE>', "$#{Vars.length * 8}").gsub('<CODE>', text)
142
+ end
143
+ end
@@ -0,0 +1,62 @@
1
+ module Lexer
2
+ class LexerError < StandardError; end
3
+
4
+ class Token
5
+ attr_reader :string, :type
6
+
7
+ def initialize(string, type)
8
+ @string, @type = string, type
9
+ end
10
+ end
11
+
12
+ Patterns = {
13
+ :Blank => '[ \t\r]+',
14
+ :NewLine => '\n+',
15
+ :Print => 'print',
16
+ :Variable => '[A-Za-z_][A-Za-z0-9_]*',
17
+ :Number => '-?[0-9]+',
18
+ :Plus => '\+',
19
+ :Minus => '\-',
20
+ :Asterisk => '\*',
21
+ :Slash => '\/',
22
+ :Percent => '\%',
23
+ :Bar => '\|',
24
+ :Ampersand => '\&',
25
+ :Caret => '\^',
26
+ :Tilde => '\~',
27
+ :LeftShift => '<<',
28
+ :RightShift => '>>',
29
+ :Equal => '\=',
30
+ :LeftBracket => '\(',
31
+ :RightBracket => '\)',
32
+ :SemiColon => '\;',
33
+ }
34
+
35
+ def self.next_token(string, index)
36
+ Patterns.each do |type, pattern|
37
+ res = string.match(pattern, index)
38
+ next if res.nil?
39
+ return [res[0], type, res.end(0)] if res.begin(0) == index
40
+ end
41
+ [nil, nil, nil]
42
+ end
43
+
44
+ def self.tokenize(string)
45
+ tokens = Array.new
46
+ index, line, column = 0, 1, 1
47
+ while index < string.length
48
+ rstring, rtype, index = next_token(string, index)
49
+ case rtype
50
+ when nil
51
+ raise LexerError, "Unrecognized character in line #{line}, column #{column}"
52
+ when :Blank
53
+ next
54
+ when :NewLine
55
+ line, column = line + 1, 1
56
+ else
57
+ tokens << Token.new(rstring, rtype)
58
+ end
59
+ end
60
+ tokens
61
+ end
62
+ end
@@ -0,0 +1,72 @@
1
+ require_relative "lexer"
2
+ require_relative "parser"
3
+ require_relative "generator"
4
+
5
+ require "optparse"
6
+
7
+ def main
8
+ ARGV << "-h" if ARGV.empty?
9
+
10
+ options = Hash.new
11
+ OptionParser.new do |opts|
12
+ opts.banner = "Usage: ruby main.rb [options]"
13
+
14
+ opts.separator ""
15
+ opts.separator "Specific options:"
16
+
17
+ opts.on("-f FILE", "--file", String, "Input from file (required)") do |f|
18
+ options[:file] = f
19
+ end
20
+
21
+ opts.on("-t LANG", "--target", String, "Target language - C, Assembly (default C)") do |t|
22
+ options[:lang] = t
23
+ end
24
+
25
+ opts.on("-o FILE", "--output", String, "Output to file (default: stdout)") do |o|
26
+ options[:output] = o
27
+ end
28
+
29
+ opts.on_tail("-h", "--help","Show this message") do
30
+ puts opts
31
+ exit
32
+ end
33
+ end.parse!
34
+
35
+ abort("Missing input file. Abort.") if options[:file].nil?
36
+ abort("File not found. Abort.") unless File.file?(options[:file])
37
+
38
+ options[:lang] ||= "C"
39
+ lang = case options[:lang].downcase
40
+ when "c"
41
+ :C
42
+ when "assembly"
43
+ :S
44
+ else
45
+ abort("Language not supported. Abort.")
46
+ end
47
+
48
+ # Read program
49
+ program = File.read(options[:file])
50
+
51
+ # Lexing
52
+ lexer = Lexer.new
53
+ tokens = lexer.tokenize(program)
54
+
55
+ # Parsing
56
+ parser = Parser.new
57
+ ast = parser.parse(tokens)
58
+
59
+ # Code Generator
60
+ generator = Generator.new
61
+ code = generator.generate(ast, lang)
62
+
63
+ if options[:output]
64
+ File.write(options[:output], code)
65
+ else
66
+ puts code
67
+ end
68
+ end
69
+
70
+ if __FILE__ == $0
71
+ main
72
+ end
@@ -0,0 +1,85 @@
1
+ module Parser
2
+ class ParserError < StandardError; end
3
+
4
+ class Token
5
+ attr_reader :type, :child
6
+
7
+ def initialize(type, *args)
8
+ @type, @child = type, args
9
+ end
10
+ end
11
+
12
+ BinaryOps = {
13
+ :Plus => 50,
14
+ :Minus => 50,
15
+ :Asterisk => 60,
16
+ :Slash => 60,
17
+ :Percent => 60,
18
+ :Bar => 10,
19
+ :Ampersand => 30,
20
+ :Caret => 20,
21
+ :LeftShift => 40,
22
+ :RightShift => 40,
23
+ }
24
+
25
+ UnaryOps = {
26
+ :Tilde => 70,
27
+ :Minus => 80,
28
+ }
29
+
30
+ def self.parse_expression(tokens)
31
+ if tokens.length == 1 && tokens[0].type == :Variable
32
+ Token.new(:Variable, tokens[0].string)
33
+ elsif tokens.length == 1 && tokens[0].type == :Number
34
+ Token.new(:Number, tokens[0].string.to_i)
35
+ elsif tokens.length >= 3 && tokens[0].type == :LeftBracket && tokens[-1].type == :RightBracket
36
+ Token.new(:Bracket, parse_expression(tokens[1...-1]))
37
+ elsif tokens.length >= 2 && UnaryOps.include?(tokens[0].type)
38
+ if tokens[0].type == :Minus
39
+ Token.new(:Negative, parse_expression(tokens[1..-1]))
40
+ else
41
+ Token.new(tokens[0].type, parse_expression(tokens[1..-1]))
42
+ end
43
+ elsif tokens.length >= 3
44
+ head, precedence = nil, 100
45
+ (tokens.length-1).downto(0) do |index|
46
+ token = tokens[index]
47
+ next if index == 0 || index == tokens.length - 1 || !BinaryOps.include?(token.type)
48
+ next unless precedence.nil? || precedence > BinaryOps[token.type]
49
+ begin
50
+ head = Token.new(token.type, parse_expression(tokens[0..index-1]), parse_expression(tokens[index+1..-1]))
51
+ precedence = BinaryOps[token.type]
52
+ rescue ParserError
53
+ end
54
+ end
55
+ raise ParserError, "Syntax error in statement: #{tokens.map(&:string).join(' ')}" if head.nil?
56
+ head
57
+ else
58
+ raise ParserError, "Syntax error in statement: #{tokens.map(&:string).join(' ')}"
59
+ end
60
+ end
61
+
62
+ def self.parse_statement(tokens)
63
+ if tokens.length >= 1 && tokens[0].type == :Print
64
+ Token.new(:Print, parse_expression(tokens[1..-1]))
65
+ elsif tokens.length >= 2 && tokens[0].type == :Variable && tokens[1].type == :Equal
66
+ Token.new(:Move, Token.new(:Variable, tokens[0].string), parse_expression(tokens[2..-1]))
67
+ else
68
+ raise ParserError, "Syntax error in statement: #{tokens.map(&:string).join(' ')}"
69
+ end
70
+ end
71
+
72
+ def self.parse(tokens)
73
+ head = Token.new(:Program)
74
+ statement = Array.new
75
+ tokens.each do |token|
76
+ if token.type == :SemiColon
77
+ head.child << parse_statement(statement)
78
+ statement = Array.new
79
+ else
80
+ statement << token
81
+ end
82
+ end
83
+ head
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module SpecialGiggle
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "special-giggle/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "special-giggle"
7
+ spec.version = SpecialGiggle::VERSION
8
+ spec.authors = ["kalari499"]
9
+ spec.email = ["kalari499@gmail.com"]
10
+
11
+ spec.summary = "BX language compiler written in Ruby"
12
+ spec.homepage = "https://github.com/kalari499/special-giggle"
13
+ spec.license = "MIT"
14
+
15
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
16
+
17
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 2.0"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "irb", "~> 1.0"
27
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: special-giggle
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - kalari499
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: irb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ description:
56
+ email:
57
+ - kalari499@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - CHANGELOG.md
64
+ - Gemfile
65
+ - Gemfile.lock
66
+ - README.md
67
+ - Rakefile
68
+ - SPECIFICATION.md
69
+ - bin/console
70
+ - bin/setup
71
+ - lib/special-giggle.rb
72
+ - lib/special-giggle/generator.rb
73
+ - lib/special-giggle/lexer.rb
74
+ - lib/special-giggle/main.rb
75
+ - lib/special-giggle/parser.rb
76
+ - lib/special-giggle/version.rb
77
+ - special-giggle.gemspec
78
+ homepage: https://github.com/kalari499/special-giggle
79
+ licenses:
80
+ - MIT
81
+ metadata:
82
+ changelog_uri: https://github.com/kalari499/special-giggle/blob/master/CHANGELOG.md
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubygems_version: 3.0.6
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: BX language compiler written in Ruby
102
+ test_files: []