carbon-compiler 0.2.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 +7 -0
- data/.gitattributes +17 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +39 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +9 -0
- data/Vagrantfile +84 -0
- data/carbon-compiler.gemspec +28 -0
- data/lib/carbon/compiler.rb +20 -0
- data/lib/carbon/compiler/directive.rb +48 -0
- data/lib/carbon/compiler/directive/import.rb +17 -0
- data/lib/carbon/compiler/errors.rb +7 -0
- data/lib/carbon/compiler/location.rb +136 -0
- data/lib/carbon/compiler/metanostic.rb +123 -0
- data/lib/carbon/compiler/metanostic/defaults.rb +41 -0
- data/lib/carbon/compiler/metanostic/defaults.yml +138 -0
- data/lib/carbon/compiler/metanostic/diagnostic.rb +112 -0
- data/lib/carbon/compiler/metanostic/list.rb +109 -0
- data/lib/carbon/compiler/metanostic/mode.rb +162 -0
- data/lib/carbon/compiler/metanostic/state.rb +174 -0
- data/lib/carbon/compiler/metanostic/template.erb +11 -0
- data/lib/carbon/compiler/node.rb +18 -0
- data/lib/carbon/compiler/node/base.rb +213 -0
- data/lib/carbon/compiler/node/definition.rb +19 -0
- data/lib/carbon/compiler/node/definition/class.rb +24 -0
- data/lib/carbon/compiler/node/definition/class/element.rb +18 -0
- data/lib/carbon/compiler/node/definition/directive.rb +22 -0
- data/lib/carbon/compiler/node/definition/directive/function.rb +18 -0
- data/lib/carbon/compiler/node/definition/enum.rb +20 -0
- data/lib/carbon/compiler/node/definition/enum/element.rb +17 -0
- data/lib/carbon/compiler/node/definition/function.rb +44 -0
- data/lib/carbon/compiler/node/definition/function/body.rb +17 -0
- data/lib/carbon/compiler/node/definition/function/name.rb +18 -0
- data/lib/carbon/compiler/node/definition/function/parameter.rb +18 -0
- data/lib/carbon/compiler/node/definition/function/parameters.rb +17 -0
- data/lib/carbon/compiler/node/definition/module.rb +23 -0
- data/lib/carbon/compiler/node/definition/struct.rb +24 -0
- data/lib/carbon/compiler/node/definition/struct/element.rb +18 -0
- data/lib/carbon/compiler/node/etype.rb +66 -0
- data/lib/carbon/compiler/node/etype/option.rb +25 -0
- data/lib/carbon/compiler/node/etype/star.rb +13 -0
- data/lib/carbon/compiler/node/expression.rb +18 -0
- data/lib/carbon/compiler/node/expression/assignment.rb +22 -0
- data/lib/carbon/compiler/node/expression/call.rb +22 -0
- data/lib/carbon/compiler/node/expression/call/access.rb +24 -0
- data/lib/carbon/compiler/node/expression/call/attribute.rb +23 -0
- data/lib/carbon/compiler/node/expression/call/enum.rb +25 -0
- data/lib/carbon/compiler/node/expression/call/module.rb +24 -0
- data/lib/carbon/compiler/node/expression/call/parameters.rb +17 -0
- data/lib/carbon/compiler/node/expression/call/self.rb +17 -0
- data/lib/carbon/compiler/node/expression/call/unified.rb +27 -0
- data/lib/carbon/compiler/node/expression/literal.rb +83 -0
- data/lib/carbon/compiler/node/expression/operation.rb +20 -0
- data/lib/carbon/compiler/node/expression/operation/and.rb +20 -0
- data/lib/carbon/compiler/node/expression/operation/neq.rb +21 -0
- data/lib/carbon/compiler/node/expression/operation/normal.rb +20 -0
- data/lib/carbon/compiler/node/expression/operation/or.rb +20 -0
- data/lib/carbon/compiler/node/expression/unit.rb +16 -0
- data/lib/carbon/compiler/node/name.rb +27 -0
- data/lib/carbon/compiler/node/root.rb +23 -0
- data/lib/carbon/compiler/node/statement.rb +24 -0
- data/lib/carbon/compiler/node/statement/catch.rb +20 -0
- data/lib/carbon/compiler/node/statement/condition.rb +14 -0
- data/lib/carbon/compiler/node/statement/else.rb +17 -0
- data/lib/carbon/compiler/node/statement/elsif.rb +18 -0
- data/lib/carbon/compiler/node/statement/finally.rb +17 -0
- data/lib/carbon/compiler/node/statement/for.rb +18 -0
- data/lib/carbon/compiler/node/statement/if.rb +18 -0
- data/lib/carbon/compiler/node/statement/let.rb +18 -0
- data/lib/carbon/compiler/node/statement/match.rb +14 -0
- data/lib/carbon/compiler/node/statement/return.rb +17 -0
- data/lib/carbon/compiler/node/statement/try.rb +19 -0
- data/lib/carbon/compiler/node/statement/while.rb +19 -0
- data/lib/carbon/compiler/parser.rb +63 -0
- data/lib/carbon/compiler/parser/common.rb +79 -0
- data/lib/carbon/compiler/parser/expressions.rb +39 -0
- data/lib/carbon/compiler/parser/expressions/precedence.rb +134 -0
- data/lib/carbon/compiler/parser/expressions/primary.rb +120 -0
- data/lib/carbon/compiler/parser/firsts.rb +74 -0
- data/lib/carbon/compiler/parser/helpers.rb +61 -0
- data/lib/carbon/compiler/parser/root.rb +57 -0
- data/lib/carbon/compiler/parser/root/class.rb +34 -0
- data/lib/carbon/compiler/parser/root/directive.rb +87 -0
- data/lib/carbon/compiler/parser/root/enum.rb +45 -0
- data/lib/carbon/compiler/parser/root/function.rb +90 -0
- data/lib/carbon/compiler/parser/root/struct.rb +34 -0
- data/lib/carbon/compiler/parser/root/trait.rb +44 -0
- data/lib/carbon/compiler/parser/statements.rb +86 -0
- data/lib/carbon/compiler/parser/statements/if.rb +50 -0
- data/lib/carbon/compiler/parser/statements/match.rb +39 -0
- data/lib/carbon/compiler/parser/statements/try.rb +49 -0
- data/lib/carbon/compiler/project.rb +37 -0
- data/lib/carbon/compiler/project/file.rb +64 -0
- data/lib/carbon/compiler/scanner.rb +82 -0
- data/lib/carbon/compiler/scanner/main.rb +76 -0
- data/lib/carbon/compiler/scanner/token.rb +58 -0
- data/lib/carbon/compiler/version.rb +8 -0
- data/lib/carbon/compiler/visitor.rb +13 -0
- data/lib/carbon/compiler/visitor/base.rb +52 -0
- data/lib/carbon/compiler/visitor/generation.rb +45 -0
- data/lib/carbon/compiler/visitor/generation/asserts.rb +30 -0
- data/lib/carbon/compiler/visitor/generation/class.rb +93 -0
- data/lib/carbon/compiler/visitor/generation/context.rb +75 -0
- data/lib/carbon/compiler/visitor/generation/expressions.rb +82 -0
- data/lib/carbon/compiler/visitor/generation/expressions/assignment.rb +105 -0
- data/lib/carbon/compiler/visitor/generation/expressions/calls.rb +89 -0
- data/lib/carbon/compiler/visitor/generation/function.rb +68 -0
- data/lib/carbon/compiler/visitor/generation/statements.rb +131 -0
- data/lib/carbon/compiler/visitor/generation/struct.rb +115 -0
- data/lib/carbon/compiler/visitor/preparation.rb +86 -0
- data/lib/carbon/compiler/visitor/preparation/expressions.rb +26 -0
- data/lib/carbon/compiler/visitor/preparation/function.rb +55 -0
- data/lib/carbon/compiler/visitor/preparation/statements.rb +73 -0
- data/lib/carbon/compiler/visitor/preparation/struct.rb +37 -0
- data/program.ca +16 -0
- data/test.rb +21 -0
- 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,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
|