carbon-compiler 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +17 -0
  3. data/.gitignore +10 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +39 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +9 -0
  12. data/Vagrantfile +84 -0
  13. data/carbon-compiler.gemspec +28 -0
  14. data/lib/carbon/compiler.rb +20 -0
  15. data/lib/carbon/compiler/directive.rb +48 -0
  16. data/lib/carbon/compiler/directive/import.rb +17 -0
  17. data/lib/carbon/compiler/errors.rb +7 -0
  18. data/lib/carbon/compiler/location.rb +136 -0
  19. data/lib/carbon/compiler/metanostic.rb +123 -0
  20. data/lib/carbon/compiler/metanostic/defaults.rb +41 -0
  21. data/lib/carbon/compiler/metanostic/defaults.yml +138 -0
  22. data/lib/carbon/compiler/metanostic/diagnostic.rb +112 -0
  23. data/lib/carbon/compiler/metanostic/list.rb +109 -0
  24. data/lib/carbon/compiler/metanostic/mode.rb +162 -0
  25. data/lib/carbon/compiler/metanostic/state.rb +174 -0
  26. data/lib/carbon/compiler/metanostic/template.erb +11 -0
  27. data/lib/carbon/compiler/node.rb +18 -0
  28. data/lib/carbon/compiler/node/base.rb +213 -0
  29. data/lib/carbon/compiler/node/definition.rb +19 -0
  30. data/lib/carbon/compiler/node/definition/class.rb +24 -0
  31. data/lib/carbon/compiler/node/definition/class/element.rb +18 -0
  32. data/lib/carbon/compiler/node/definition/directive.rb +22 -0
  33. data/lib/carbon/compiler/node/definition/directive/function.rb +18 -0
  34. data/lib/carbon/compiler/node/definition/enum.rb +20 -0
  35. data/lib/carbon/compiler/node/definition/enum/element.rb +17 -0
  36. data/lib/carbon/compiler/node/definition/function.rb +44 -0
  37. data/lib/carbon/compiler/node/definition/function/body.rb +17 -0
  38. data/lib/carbon/compiler/node/definition/function/name.rb +18 -0
  39. data/lib/carbon/compiler/node/definition/function/parameter.rb +18 -0
  40. data/lib/carbon/compiler/node/definition/function/parameters.rb +17 -0
  41. data/lib/carbon/compiler/node/definition/module.rb +23 -0
  42. data/lib/carbon/compiler/node/definition/struct.rb +24 -0
  43. data/lib/carbon/compiler/node/definition/struct/element.rb +18 -0
  44. data/lib/carbon/compiler/node/etype.rb +66 -0
  45. data/lib/carbon/compiler/node/etype/option.rb +25 -0
  46. data/lib/carbon/compiler/node/etype/star.rb +13 -0
  47. data/lib/carbon/compiler/node/expression.rb +18 -0
  48. data/lib/carbon/compiler/node/expression/assignment.rb +22 -0
  49. data/lib/carbon/compiler/node/expression/call.rb +22 -0
  50. data/lib/carbon/compiler/node/expression/call/access.rb +24 -0
  51. data/lib/carbon/compiler/node/expression/call/attribute.rb +23 -0
  52. data/lib/carbon/compiler/node/expression/call/enum.rb +25 -0
  53. data/lib/carbon/compiler/node/expression/call/module.rb +24 -0
  54. data/lib/carbon/compiler/node/expression/call/parameters.rb +17 -0
  55. data/lib/carbon/compiler/node/expression/call/self.rb +17 -0
  56. data/lib/carbon/compiler/node/expression/call/unified.rb +27 -0
  57. data/lib/carbon/compiler/node/expression/literal.rb +83 -0
  58. data/lib/carbon/compiler/node/expression/operation.rb +20 -0
  59. data/lib/carbon/compiler/node/expression/operation/and.rb +20 -0
  60. data/lib/carbon/compiler/node/expression/operation/neq.rb +21 -0
  61. data/lib/carbon/compiler/node/expression/operation/normal.rb +20 -0
  62. data/lib/carbon/compiler/node/expression/operation/or.rb +20 -0
  63. data/lib/carbon/compiler/node/expression/unit.rb +16 -0
  64. data/lib/carbon/compiler/node/name.rb +27 -0
  65. data/lib/carbon/compiler/node/root.rb +23 -0
  66. data/lib/carbon/compiler/node/statement.rb +24 -0
  67. data/lib/carbon/compiler/node/statement/catch.rb +20 -0
  68. data/lib/carbon/compiler/node/statement/condition.rb +14 -0
  69. data/lib/carbon/compiler/node/statement/else.rb +17 -0
  70. data/lib/carbon/compiler/node/statement/elsif.rb +18 -0
  71. data/lib/carbon/compiler/node/statement/finally.rb +17 -0
  72. data/lib/carbon/compiler/node/statement/for.rb +18 -0
  73. data/lib/carbon/compiler/node/statement/if.rb +18 -0
  74. data/lib/carbon/compiler/node/statement/let.rb +18 -0
  75. data/lib/carbon/compiler/node/statement/match.rb +14 -0
  76. data/lib/carbon/compiler/node/statement/return.rb +17 -0
  77. data/lib/carbon/compiler/node/statement/try.rb +19 -0
  78. data/lib/carbon/compiler/node/statement/while.rb +19 -0
  79. data/lib/carbon/compiler/parser.rb +63 -0
  80. data/lib/carbon/compiler/parser/common.rb +79 -0
  81. data/lib/carbon/compiler/parser/expressions.rb +39 -0
  82. data/lib/carbon/compiler/parser/expressions/precedence.rb +134 -0
  83. data/lib/carbon/compiler/parser/expressions/primary.rb +120 -0
  84. data/lib/carbon/compiler/parser/firsts.rb +74 -0
  85. data/lib/carbon/compiler/parser/helpers.rb +61 -0
  86. data/lib/carbon/compiler/parser/root.rb +57 -0
  87. data/lib/carbon/compiler/parser/root/class.rb +34 -0
  88. data/lib/carbon/compiler/parser/root/directive.rb +87 -0
  89. data/lib/carbon/compiler/parser/root/enum.rb +45 -0
  90. data/lib/carbon/compiler/parser/root/function.rb +90 -0
  91. data/lib/carbon/compiler/parser/root/struct.rb +34 -0
  92. data/lib/carbon/compiler/parser/root/trait.rb +44 -0
  93. data/lib/carbon/compiler/parser/statements.rb +86 -0
  94. data/lib/carbon/compiler/parser/statements/if.rb +50 -0
  95. data/lib/carbon/compiler/parser/statements/match.rb +39 -0
  96. data/lib/carbon/compiler/parser/statements/try.rb +49 -0
  97. data/lib/carbon/compiler/project.rb +37 -0
  98. data/lib/carbon/compiler/project/file.rb +64 -0
  99. data/lib/carbon/compiler/scanner.rb +82 -0
  100. data/lib/carbon/compiler/scanner/main.rb +76 -0
  101. data/lib/carbon/compiler/scanner/token.rb +58 -0
  102. data/lib/carbon/compiler/version.rb +8 -0
  103. data/lib/carbon/compiler/visitor.rb +13 -0
  104. data/lib/carbon/compiler/visitor/base.rb +52 -0
  105. data/lib/carbon/compiler/visitor/generation.rb +45 -0
  106. data/lib/carbon/compiler/visitor/generation/asserts.rb +30 -0
  107. data/lib/carbon/compiler/visitor/generation/class.rb +93 -0
  108. data/lib/carbon/compiler/visitor/generation/context.rb +75 -0
  109. data/lib/carbon/compiler/visitor/generation/expressions.rb +82 -0
  110. data/lib/carbon/compiler/visitor/generation/expressions/assignment.rb +105 -0
  111. data/lib/carbon/compiler/visitor/generation/expressions/calls.rb +89 -0
  112. data/lib/carbon/compiler/visitor/generation/function.rb +68 -0
  113. data/lib/carbon/compiler/visitor/generation/statements.rb +131 -0
  114. data/lib/carbon/compiler/visitor/generation/struct.rb +115 -0
  115. data/lib/carbon/compiler/visitor/preparation.rb +86 -0
  116. data/lib/carbon/compiler/visitor/preparation/expressions.rb +26 -0
  117. data/lib/carbon/compiler/visitor/preparation/function.rb +55 -0
  118. data/lib/carbon/compiler/visitor/preparation/statements.rb +73 -0
  119. data/lib/carbon/compiler/visitor/preparation/struct.rb +37 -0
  120. data/program.ca +16 -0
  121. data/test.rb +21 -0
  122. metadata +234 -0
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ class Parser
7
+ module Statements
8
+ # Parses a match statement.
9
+ module Match
10
+ protected
11
+
12
+ # TODO: Fix
13
+
14
+ def parse_statement_match
15
+ expect :match
16
+ expect :"("
17
+ source = parse_expression
18
+ expect :")"
19
+ expect :do
20
+ children = []
21
+ children << parse_match_element until peek? :end
22
+ expect :end
23
+
24
+ elements = Node.new(:statement_match_elements, children)
25
+ Node.new(:statement_match, [source, elements])
26
+ end
27
+
28
+ def parse_match_element
29
+ pattern = parse_expression
30
+ expect :"=>"
31
+ body = parse_statement
32
+
33
+ Node.new(:statement_match_element, [pattern, body])
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ class Parser
7
+ module Statements
8
+ # Parses a try statement.
9
+ module Try
10
+ protected
11
+
12
+ def parse_statement_try
13
+ expect :try
14
+ body = parse_statement
15
+ continued = parse_statement_try_continued
16
+
17
+ Node::Statement::Try.new([body, continued])
18
+ end
19
+
20
+ def parse_statement_try_continued
21
+ case peek.type
22
+ when :catch then parse_statement_try_catch
23
+ when :finally then parse_statement_try_finally
24
+ end
25
+ end
26
+
27
+ def parse_statement_try_catch
28
+ expect :catch
29
+ expect :"("
30
+ name = parse_name
31
+ expect :":"
32
+ type = parse_type
33
+ expect :")"
34
+ body = parse_statement
35
+ follow = parse_statement_try_continued
36
+
37
+ Node::Statement::Catch.new([name, type, body, follow])
38
+ end
39
+
40
+ def parse_statement_try_finally
41
+ expect :finally
42
+
43
+ Node::Statement::Finally.new([parse_statement])
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "carbon/compiler/project/file"
5
+ require "llvm/target"
6
+ require "llvm/execution_engine"
7
+
8
+ module Carbon
9
+ module Compiler
10
+ class Project
11
+ attr_reader :diagnostics
12
+ attr_reader :items
13
+ attr_reader :main
14
+
15
+ def initialize(files, root, libraries: [])
16
+ @root = Pathname.new(root).expand_path(Dir.pwd)
17
+ @files = files.map { |f| Project::File.new(f, @root, self) }
18
+ @diagnostics = Metanostic::List.new
19
+ @libraries = []
20
+ @files.each { |f| @diagnostics.files[f.short] = f }
21
+ end
22
+
23
+ def call
24
+ @index ||= begin
25
+ @index = Concrete::Index.new
26
+ @files.each { |f| f.call(@index, @diagnostics.clone) }
27
+ # load libraries...
28
+ @libraries.each do |library|
29
+ @index.link(Carbon::Concrete.load(::File.read(library, "rb")))
30
+ end
31
+ @index.link(Carbon::Core.index)
32
+ @index.finalize
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ class Project
7
+ class File
8
+ attr_reader :name
9
+ attr_reader :root
10
+ attr_reader :path
11
+ attr_reader :short
12
+ attr_reader :aliases
13
+
14
+ def initialize(path, root, project)
15
+ @root = Pathname.new(root)
16
+ @path = Pathname.new(path).expand_path(@root)
17
+ @short = @path.relative_path_from(@root)
18
+ @name = @short.sub_ext("").to_s
19
+ @project = project
20
+ @aliases = {}
21
+ end
22
+
23
+ def module
24
+ @module ||= begin
25
+ mname = @name
26
+ .gsub(/\A([a-z])/, &:upcase)
27
+ .gsub(/(\/|\\)([a-z])/) { |m| "::#{m[1].upcase}" }
28
+ .gsub(/_([a-z])/) { |m| m[1].upcase }
29
+ .gsub(/\/|\\/, "::")
30
+ Carbon::Type(mname)
31
+ end
32
+ end
33
+
34
+ attr_writer :module
35
+
36
+ def emit(*p)
37
+ @diagnostics.emit(*p)
38
+ end
39
+
40
+ def call(index, diagnostics)
41
+ @diagnostics = diagnostics
42
+ root = Visitor::Preparation.new(self, index).call(parser.root)
43
+ Visitor::Generation.new(self, index).call(root)
44
+ end
45
+
46
+ def parser
47
+ @parser ||= Compiler::Parser.new(scanner)
48
+ end
49
+
50
+ def scanner
51
+ @scanner ||= Compiler::Scanner.new(self)
52
+ end
53
+
54
+ def read
55
+ @_read ||= @path.read
56
+ end
57
+
58
+ def lines
59
+ @_lines ||= @path.each_line
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require "strscan"
4
+ require "carbon/compiler/scanner/main"
5
+ require "carbon/compiler/scanner/token"
6
+
7
+ module Carbon
8
+ module Compiler
9
+ # Scans over the file, taking a squence of characters and turning them into
10
+ # tokens.
11
+ class Scanner
12
+ include Main
13
+ include Enumerable
14
+
15
+ # The file that the scanner will run over.
16
+ #
17
+ # @return [Project::File]
18
+ attr_reader :file
19
+
20
+ # Initialize the scanner. Takes a file, which contains information about
21
+ # the file, and can read from the file.
22
+ #
23
+ # @param file [Project::File]
24
+ def initialize(file)
25
+ @file = file
26
+ @scanner = StringScanner.new(@file.read)
27
+ @line = 1
28
+ @last = 0
29
+ end
30
+
31
+ # Pretty inspect.
32
+ #
33
+ # @return [void]
34
+ def inspect
35
+ "#<#{self.class} #{@file.name}>"
36
+ end
37
+
38
+ # Yields each token to the block, if one is given. Returns an
39
+ # enumerator that enumerates over all generated tokens.
40
+ #
41
+ # @yield [token]
42
+ # @yieldparam token [Token]
43
+ # @return [Enumerator<Token>]
44
+ def each
45
+ return to_enum unless block_given?
46
+ until @scanner.eos?
47
+ token = scan
48
+ yield token if token.is_a?(Token)
49
+ end
50
+
51
+ yield Token.new(:EOF, "", location)
52
+ @scanner.reset
53
+ end
54
+
55
+ private
56
+
57
+ def match(string, name = :"#{string}")
58
+ if string.is_a?(::String)
59
+ string = /#{::Regexp.escape(string.to_s)}/
60
+ elsif string.is_a?(::Symbol)
61
+ string = /#{::Regexp.escape(string.to_s)}(?![\w])/
62
+ end
63
+
64
+ if @scanner.scan(string)
65
+ Token.new(name, @scanner[0], location(@scanner[0].length))
66
+ end
67
+ end
68
+
69
+ def location(length = 0)
70
+ lines = @line..@line
71
+ start = @scanner.charpos - @last
72
+ columns = (start - length)..start
73
+ Location.new(lines, columns, @file.short)
74
+ end
75
+
76
+ def error!
77
+ @file.emit("Syntax/Token/Unknown", location,
78
+ [@scanner.string[@scanner.charpos]])
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ class Scanner
7
+ # Performs the scanning.
8
+ module Main
9
+ protected
10
+
11
+ def scan
12
+ false ||
13
+ scan_keywords ||
14
+ scan_identifiers ||
15
+ scan_operators ||
16
+ scan_comment ||
17
+ scan_whitespace ||
18
+ error!
19
+ end
20
+
21
+ # rubocop:disable Metrics/CyclomaticComplexity
22
+ def scan_identifiers
23
+ false ||
24
+ match(/[a-z][A-Za-z0-9_-]*[!?=]?/, :IDENTIFIER) ||
25
+ match(/(0[xX][0-9a-fA-F]+)(_?[ui][0-9]+)?/, :NUMBER) ||
26
+ match(/(0|[1-9][0-9]*)(_?[ui][0-9]+)?/, :NUMBER) ||
27
+ match(/[A-Z][A-Za-z0-9_-]*/, :MNAME) ||
28
+ match(/"(([^"\\]|\\.)*)"/, :STRING) ||
29
+ false
30
+ end
31
+
32
+ KEYWORDS = %i(
33
+ finally return struct module catch elsif match trait while
34
+ self else enum for def end let try do if _
35
+ ).sort_by(&:size).reverse.freeze
36
+
37
+ def scan_keywords
38
+ KEYWORDS.find do |keyword|
39
+ m = match(/#{Regexp.escape(keyword)}(?![a-zA-Z0-9!?=_-])/, keyword)
40
+ return m if m
41
+ end || false
42
+ end
43
+
44
+ OPERATORS = %w(
45
+ === :: => == && || != << >> <= >= + - ~ ! * / % : ; & | [ ] ( ) { } <
46
+ > . , = ^ [] []=
47
+ ).sort_by(&:size).reverse.freeze
48
+
49
+ def scan_operators
50
+ OPERATORS.find do |operator|
51
+ m = match(operator)
52
+ return m if m
53
+ end || false
54
+ end
55
+
56
+ def scan_comment
57
+ if @scanner.scan(/\#.+?(\r\n|\r|\n)/)
58
+ @line += 1
59
+ @last = @scanner.charpos - 1
60
+ true
61
+ end
62
+ end
63
+
64
+ def scan_whitespace
65
+ if @scanner.scan(/\r\n|\r|\n/)
66
+ @line += 1
67
+ @last = @scanner.charpos - 1
68
+ true
69
+ elsif @scanner.scan(/[ \v\t\f]/)
70
+ true
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ class Scanner
7
+ # A token from the scanner.
8
+ class Token
9
+ # The type of the token. For any explicit matches (e.g. `"module"`),
10
+ # this is the exact match (e.g. `:module`). For any regular matches
11
+ # (e.g. an identifier), this is in all caps (e.g. `:IDENTIFIER`).
12
+ #
13
+ # @return [Symbol]
14
+ attr_reader :type
15
+ # The lexeme that this token is associated. This is what the token
16
+ # matched directly from the source.
17
+ #
18
+ # @return [String]
19
+ attr_reader :value
20
+ # The exact location the token was taken from. This only spans one
21
+ # line.
22
+ #
23
+ # @return [Location]
24
+ attr_reader :location
25
+
26
+ # Initialize the token. Freezes it after initializing.
27
+ #
28
+ # @param type [Symbol] The type. See {#type}.
29
+ # @param value [String] The value. See {#value}.
30
+ # @param location [Location] The location. See {#location}.
31
+ def initialize(type, value, location)
32
+ @type = type
33
+ @value = value
34
+ @location = location
35
+ @children = []
36
+ to_a
37
+ freeze
38
+ end
39
+
40
+ # Creates an array representation of this class. This is cached and
41
+ # frozen, since nothing about this class changes.
42
+ #
43
+ # @return [(Class, Symbol, String, Location)]
44
+ def to_a
45
+ @array ||= [self.class, @type, @value, @location].freeze
46
+ end
47
+
48
+ # Creates a numeric representation of this class for hashing.
49
+ #
50
+ # @see #to_a
51
+ # @return [Numeric]
52
+ def hash
53
+ to_a.hash
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ VERSION = "0.2.0".freeze
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "carbon/compiler/visitor/base"
5
+ require "carbon/compiler/visitor/generation"
6
+ require "carbon/compiler/visitor/preparation"
7
+
8
+ module Carbon
9
+ module Compiler
10
+ module Visitor
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Compiler
6
+ module Visitor
7
+ # A visitor base.
8
+ module Base
9
+ # The class methods.
10
+ module ClassMethods
11
+ def matches
12
+ @_matches ||= Concurrent::Hash.new
13
+ end
14
+
15
+ def on(nodes)
16
+ matches.merge!(nodes)
17
+ end
18
+ end
19
+
20
+ # The instance methods.
21
+ module InstanceMethods
22
+ def accept(node, *params)
23
+ visit(node, *params)
24
+ end
25
+
26
+ def visit(node, *params)
27
+ return unless node
28
+ begin
29
+ action = self.class.matches.fetch(node.class)
30
+ rescue KeyError
31
+ visit_missing(node, *params)
32
+ end
33
+ public_send(action, node, *params)
34
+ end
35
+
36
+ def visit_missing(node, *)
37
+ fail ArgumentError, "Cannot visit #{node.class}"
38
+ end
39
+
40
+ def visit_ignore(node)
41
+ node
42
+ end
43
+ end
44
+
45
+ def self.included(base)
46
+ base.include InstanceMethods
47
+ base.extend ClassMethods
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end