carbon-core 0.1.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/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +38 -0
- data/.travis.yml +4 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +14 -0
- data/carbon.gemspec +30 -0
- data/lib/carbon.rb +54 -0
- data/lib/carbon/concrete.rb +43 -0
- data/lib/carbon/concrete/build.rb +63 -0
- data/lib/carbon/concrete/index.rb +324 -0
- data/lib/carbon/concrete/item.rb +37 -0
- data/lib/carbon/concrete/item/base.rb +153 -0
- data/lib/carbon/concrete/item/data.rb +22 -0
- data/lib/carbon/concrete/item/function.rb +97 -0
- data/lib/carbon/concrete/item/internal.rb +83 -0
- data/lib/carbon/concrete/item/struct.rb +65 -0
- data/lib/carbon/concrete/item/struct/element.rb +42 -0
- data/lib/carbon/concrete/item/trait.rb +72 -0
- data/lib/carbon/concrete/item/trait/expectation.rb +55 -0
- data/lib/carbon/concrete/request.rb +137 -0
- data/lib/carbon/concrete/type.rb +260 -0
- data/lib/carbon/concrete/type/function.rb +91 -0
- data/lib/carbon/concrete/type/generic.rb +118 -0
- data/lib/carbon/concrete/type/name.rb +147 -0
- data/lib/carbon/concrete/type/parse.rb +172 -0
- data/lib/carbon/concrete/type/part.rb +100 -0
- data/lib/carbon/core.rb +61 -0
- data/lib/carbon/core/int.rb +87 -0
- data/lib/carbon/core/integer.rb +109 -0
- data/lib/carbon/core/integer/cast.rb +83 -0
- data/lib/carbon/core/integer/math.rb +198 -0
- data/lib/carbon/core/integer/misc.rb +145 -0
- data/lib/carbon/core/integer/pole.rb +133 -0
- data/lib/carbon/core/integer/ship.rb +71 -0
- data/lib/carbon/core/integer/sign.rb +52 -0
- data/lib/carbon/core/integer/type.rb +42 -0
- data/lib/carbon/core/integer/zero.rb +52 -0
- data/lib/carbon/core/pointer.rb +54 -0
- data/lib/carbon/core/pointer/access.rb +123 -0
- data/lib/carbon/core/pointer/cast.rb +55 -0
- data/lib/carbon/core/pointer/math.rb +187 -0
- data/lib/carbon/core/pointer/memory.rb +85 -0
- data/lib/carbon/core/pointer/type.rb +23 -0
- data/lib/carbon/tacky.rb +21 -0
- data/lib/carbon/tacky/block.rb +96 -0
- data/lib/carbon/tacky/builder.rb +310 -0
- data/lib/carbon/tacky/context.rb +66 -0
- data/lib/carbon/tacky/function.rb +137 -0
- data/lib/carbon/tacky/instruction.rb +170 -0
- data/lib/carbon/tacky/parameter.rb +23 -0
- data/lib/carbon/tacky/reference.rb +23 -0
- data/lib/carbon/tacky/value.rb +40 -0
- data/lib/carbon/version.rb +9 -0
- metadata +186 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Carbon
|
5
|
+
module Concrete
|
6
|
+
class Type
|
7
|
+
# The function part of a type. This comes after the module that it is
|
8
|
+
# defined in, and contains three pieces of information: the name of the
|
9
|
+
# function, the generics associated with the function, and the parameters
|
10
|
+
# of the function.
|
11
|
+
#
|
12
|
+
# @todo TODO: add generic parameters.
|
13
|
+
# @note
|
14
|
+
# **This class is frozen upon initialization.** This means that any
|
15
|
+
# attempt to modify it will result in an error. In most cases, the
|
16
|
+
# attributes on this class will also be frozen, as well.
|
17
|
+
# @note
|
18
|
+
# This class does not include comparison methods; however, if they
|
19
|
+
# were to ever be needed, {#to_s} should be used for the basis of
|
20
|
+
# comparison.
|
21
|
+
class Function
|
22
|
+
# The name of the function. This is normally a bland string.
|
23
|
+
# Functions can have a variety of names to override default operations
|
24
|
+
# in the language; even more so than ruby.
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
# @example
|
28
|
+
# type = Carbon::Type("A.+(A, B)")
|
29
|
+
# func = type.name.function
|
30
|
+
# func.name # => "+"
|
31
|
+
# @return [::String] The name of the function.
|
32
|
+
attr_reader :name
|
33
|
+
|
34
|
+
# The parameters for the function. These are the arguments that are
|
35
|
+
# passed to the function when it's called. This is included in the
|
36
|
+
# definition for the name of the function to allow overloading.
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
# @example
|
40
|
+
# type = Carbon::Type("A.+(A, B)")
|
41
|
+
# func = type.name.function
|
42
|
+
# func.parameters
|
43
|
+
# # => [#<Carbon::Concrete::Type::Name A>,
|
44
|
+
# # #<Carbon::Concrete::Type::Name B>]
|
45
|
+
# @return [::Array<Type::Name>]
|
46
|
+
attr_reader :parameters
|
47
|
+
|
48
|
+
# Initialize the function.
|
49
|
+
#
|
50
|
+
# @see #name
|
51
|
+
# @see #params
|
52
|
+
# @param name [::String] The name of the function.
|
53
|
+
# @param params [::Array<Type::Name>] The parameters of the function.
|
54
|
+
# This is frozen before stored.
|
55
|
+
def initialize(name, params)
|
56
|
+
@name = name
|
57
|
+
@parameters = params
|
58
|
+
deep_freeze!
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a string representation of this function. In contrast to
|
62
|
+
# {#intern}, this includes generic information.
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
# @example
|
66
|
+
# func.name # => "+"
|
67
|
+
# func.parameters # => [#<Carbon::Concrete::Type::Name Test<T>>]
|
68
|
+
# func.to_s # => "+(Test<T>)"
|
69
|
+
# @return [::String]
|
70
|
+
def to_s
|
71
|
+
"#{@name}(#{@parameters.map(&:to_s).join(', ')})".freeze
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the interned version of this function. In contrast to
|
75
|
+
# {#to_s}, this does not include generic information.
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
# @note See {Item::Base#intern} For more information about interned
|
79
|
+
# names.
|
80
|
+
# @example
|
81
|
+
# func.name # => "+"
|
82
|
+
# func.parameters # => [#<Carbon::Concrete::Type::Name Test<T>>]
|
83
|
+
# func.intern # => "+(Test)"
|
84
|
+
# @return [::String]
|
85
|
+
def intern
|
86
|
+
"#{@name}(#{@parameters.map(&:intern).join(', ')})".freeze
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Carbon
|
5
|
+
module Concrete
|
6
|
+
class Type
|
7
|
+
# A generic part of a type. This is normally the `T` in
|
8
|
+
# `Carbon::Pointer<T>`. Generic portions can also have traits that
|
9
|
+
# the generic type must implement; this keeps track of that too.
|
10
|
+
# A complete example, containing traits, would look like this:
|
11
|
+
# `Carbon::Pointer<T: Carbon::Sized + Carbon::Numeric>`. The actual
|
12
|
+
# pointer type may not use those traits.
|
13
|
+
#
|
14
|
+
# @note
|
15
|
+
# **This class is frozen upon initialization.** This means that any
|
16
|
+
# attempt to modify it will result in an error. In most cases, the
|
17
|
+
# attributes on this class will also be frozen, as well.
|
18
|
+
class Generic
|
19
|
+
# The name of the generic. This is the generic type variable that is
|
20
|
+
# substituted in later for an actual value. This is normally a single
|
21
|
+
# character module name, but can be as complicated as needed.
|
22
|
+
#
|
23
|
+
# @api public
|
24
|
+
# @example
|
25
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
26
|
+
# type.generics.first.name # => #<Carbon::Concrete::Type T>
|
27
|
+
# @return [Type] The name.
|
28
|
+
attr_reader :name
|
29
|
+
|
30
|
+
# The implements of the generic. These are the traits that the generic
|
31
|
+
# parameter has to implement; this allows the generic code to make
|
32
|
+
# assumptions about the generic type (such as behavior or size) that
|
33
|
+
# would otherwise be impossible to make.
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
# @example
|
37
|
+
# name = "Carbon::Pointer<T: Carbon::Sized>"
|
38
|
+
# type = Carbon::Type(name)
|
39
|
+
# type.generics.first.implements
|
40
|
+
# # => Set[#<Carbon::Concrete::Type Carbon::Sized>]
|
41
|
+
# @return [Set<Type>] The traits the generic has to implement.
|
42
|
+
attr_reader :implements
|
43
|
+
|
44
|
+
# Initialize the generic part of the type.
|
45
|
+
#
|
46
|
+
# @see #name
|
47
|
+
# @see #implements
|
48
|
+
# @param name [Type] The name of the generic.
|
49
|
+
# @param implements [Set<Type>] The traits the generic must
|
50
|
+
# implement, if any.
|
51
|
+
def initialize(name, implements)
|
52
|
+
@name = name
|
53
|
+
@implements = Set.new(implements)
|
54
|
+
deep_freeze!
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns the correct generic. This is a weird function, but
|
58
|
+
# essentially, if the {#name}'s {Type#intern} is oen of the keys of
|
59
|
+
# the mapping, it returns the new generic; otherwise, it returns
|
60
|
+
# this object.
|
61
|
+
#
|
62
|
+
# @api public
|
63
|
+
# @example
|
64
|
+
# generic.to_s # => "T: Carbon::Sized"
|
65
|
+
# generic.is_a?(Generic) # => true
|
66
|
+
# other.to_s # => "Carbon::String"
|
67
|
+
# other.is_a?(Generic) # => true
|
68
|
+
# result = generic.sub("T" => other)
|
69
|
+
# result.to_s # => "Carbon::String: Carbon::Sized"
|
70
|
+
# @param mapping [{::String => Type::Generic}] The mapping.
|
71
|
+
# @return [Type::Generic] A different instance of the generic, if it's
|
72
|
+
# in the mapping.
|
73
|
+
# @return [self] otherwise.
|
74
|
+
def sub(mapping)
|
75
|
+
mapping.fetch(@name.intern, self)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Compares this generic instance to another generic instance. If the
|
79
|
+
# other generic instance _is_ this generic instance it returns true;
|
80
|
+
# otherwise, if the other value is a generic, and that generic's
|
81
|
+
# {#to_s} is equal to this one's, it returns true; otherwise, it
|
82
|
+
# returns false.
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
# @example
|
86
|
+
# type1 = Carbon::Type("Carbon::Pointer<T>")
|
87
|
+
# type2 = Carbon::Type("Carbon::List<T>")
|
88
|
+
# type1.generics == type2.generics # => true
|
89
|
+
# @param other [Type::Generic, ::Object] The object to compare.
|
90
|
+
# @return [::Boolean] True if the two are equivalent.
|
91
|
+
def ==(other)
|
92
|
+
equal?(other) ||
|
93
|
+
(other.is_a?(Type::Generic) && other.to_s == to_s)
|
94
|
+
end
|
95
|
+
|
96
|
+
alias_method :eql?, :==
|
97
|
+
|
98
|
+
# A string representation of the generic. If there are no implements,
|
99
|
+
# this is a direct call to {#name}'s {Type#to_s}; otherwise, this
|
100
|
+
# includes the name with a joined string of implements.
|
101
|
+
#
|
102
|
+
# @api public
|
103
|
+
# @example
|
104
|
+
# name = "Carbon::Pointer<T: Carbon::Sized>"
|
105
|
+
# type = Carbon::Type(name)
|
106
|
+
# type.generics.first.to_s # => "T: Carbon::Sized"
|
107
|
+
# @return [::String] The string representation.
|
108
|
+
def to_s
|
109
|
+
if @implements.any?
|
110
|
+
"#{@name}: #{@implements.map(&:to_s).join(' + ')}".freeze
|
111
|
+
else
|
112
|
+
@name.to_s
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Carbon
|
5
|
+
module Concrete
|
6
|
+
class Type
|
7
|
+
# The "name" of a type. This contains all of the physical information
|
8
|
+
# of a type. This mostly means the "parts" for the name, and the
|
9
|
+
# function information if it is included.
|
10
|
+
#
|
11
|
+
# @note
|
12
|
+
# **This class is frozen upon initialization.** This means that any
|
13
|
+
# attempt to modify it will result in an error. In most cases, the
|
14
|
+
# attributes on this class will also be frozen, as well.
|
15
|
+
class Name
|
16
|
+
include Enumerable
|
17
|
+
extend Forwardable
|
18
|
+
|
19
|
+
# The parts of the name. This is mainly the sections of the type
|
20
|
+
# name; for example, for `Carbon::Pointer`, the parts are `Carbon` and
|
21
|
+
# `Pointer`. Each part can contain generic information; however,
|
22
|
+
# by convention, only the last part is actually included for generic
|
23
|
+
# information.
|
24
|
+
#
|
25
|
+
# @api semipublic
|
26
|
+
# @example
|
27
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
28
|
+
# name = type.name
|
29
|
+
# name.parts
|
30
|
+
# # => [#<Carbon::Concrete::Type::Part Carbon>,
|
31
|
+
# # #<Carbon::Concrete::Type::Part Pointer>]
|
32
|
+
# @return [<Type::Part>] The parts.
|
33
|
+
attr_reader :parts
|
34
|
+
|
35
|
+
# The function information of a type. If no function information was
|
36
|
+
# included (i.e. the type is a module), then this is `nil`.
|
37
|
+
# Function information always includes a name and the parameters, if
|
38
|
+
# it is included.
|
39
|
+
#
|
40
|
+
# @api public
|
41
|
+
# @example
|
42
|
+
# full = "Carbon::Pointer<T>.+(Carbon::Pointer<T>, Carbon::Int32)"
|
43
|
+
# type = Carbon::Type(full)
|
44
|
+
# name = type.name
|
45
|
+
# name.function.to_s # => "+(Carbon::Pointer<T>, Carbon::Int32)"
|
46
|
+
# @return [Type::Function] The function information.
|
47
|
+
attr_reader :function
|
48
|
+
|
49
|
+
# @!method each
|
50
|
+
# Iterates over each part.
|
51
|
+
#
|
52
|
+
# @see #parts
|
53
|
+
# @api semipublic
|
54
|
+
# @example
|
55
|
+
# type.name.each { |part| puts part }
|
56
|
+
# @return [::Enumerable] An enumerable over the parts.
|
57
|
+
# @!method to_a
|
58
|
+
# Returns an array of the parts of the name.
|
59
|
+
#
|
60
|
+
# @see #parts
|
61
|
+
# @api semipublic
|
62
|
+
# @example
|
63
|
+
# type.name.to_a == type.name.parts # => true
|
64
|
+
# @return [<Type::Part>] The parts.
|
65
|
+
# @!method [](index)
|
66
|
+
# Returns a part at a specific index, or the parts over the given
|
67
|
+
# range.
|
68
|
+
#
|
69
|
+
# @see #parts
|
70
|
+
# @api semipublic
|
71
|
+
# @example
|
72
|
+
# type.name[0].to_s # => "Carbon"
|
73
|
+
# @param index [Numeric, Range<Numeric>]
|
74
|
+
# @return [Type::Part] The part.
|
75
|
+
# @return [<Type::Part>] The parts over the range.
|
76
|
+
# @!method first
|
77
|
+
# Returns the first part in the name.
|
78
|
+
#
|
79
|
+
# @see #parts
|
80
|
+
# @api semipublic
|
81
|
+
# @example
|
82
|
+
# type.name.first.to_s # => "Carbon"
|
83
|
+
# @return [Type::Part] The first part.
|
84
|
+
# @!method last
|
85
|
+
# Returns the last part in the name.
|
86
|
+
#
|
87
|
+
# @see #part
|
88
|
+
# @api semipublic
|
89
|
+
# @example
|
90
|
+
# type.name.last.to_s # => "Pointer<T>"
|
91
|
+
# @return [Type::Part] The last part.
|
92
|
+
delegate [:each, :to_a, :[], :first, :last] => :@parts
|
93
|
+
|
94
|
+
# Initialize the name with the given parts and function information.
|
95
|
+
# Freezes the class after completion.
|
96
|
+
#
|
97
|
+
# @param parts [<Type::Part>] The parts of the name.
|
98
|
+
# @param function [Type::Function?] The function part of the name, if
|
99
|
+
# it exists.
|
100
|
+
def initialize(parts, function)
|
101
|
+
@parts = parts.freeze
|
102
|
+
@function = function
|
103
|
+
|
104
|
+
to_s
|
105
|
+
intern
|
106
|
+
deep_freeze!
|
107
|
+
end
|
108
|
+
|
109
|
+
# A string representation of the name. Unlike {#intern}, this
|
110
|
+
# includes all generic information as well.
|
111
|
+
#
|
112
|
+
# @api public
|
113
|
+
# @example
|
114
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
115
|
+
# type.to_s # => "Carbon::Pointer<T>"
|
116
|
+
# @return [::String] The string representation.
|
117
|
+
def to_s
|
118
|
+
@_to_s ||=
|
119
|
+
if @function
|
120
|
+
"#{@parts.map(&:to_s).join('::')}.#{@function}"
|
121
|
+
else
|
122
|
+
@parts.map(&:to_s).join("::")
|
123
|
+
end.freeze
|
124
|
+
end
|
125
|
+
|
126
|
+
# An interned name of the type. Unlike {#to_s}, this doesn't include
|
127
|
+
# any generic information.
|
128
|
+
#
|
129
|
+
# @api public
|
130
|
+
# @example
|
131
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
132
|
+
# type.intern # => "Carbon::Pointer"
|
133
|
+
# @note See {Item::Base#intern} For more information about interned
|
134
|
+
# names.
|
135
|
+
# @return [::String] The interned name of the type.
|
136
|
+
def intern
|
137
|
+
@_intern ||=
|
138
|
+
if @function
|
139
|
+
"#{@parts.map(&:intern).join('::')}.#{@function.intern}"
|
140
|
+
else
|
141
|
+
@parts.map(&:intern).join("::")
|
142
|
+
end.freeze
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# rubocop:disable all
|
4
|
+
|
5
|
+
require "strscan"
|
6
|
+
|
7
|
+
module Carbon
|
8
|
+
module Concrete
|
9
|
+
class Type
|
10
|
+
# Parses a type. This starts by scanning the string, then parsing it.
|
11
|
+
# Each instance should result in a different parsed value; a single
|
12
|
+
# instance cannot be re-used for parsing something else. **Not for
|
13
|
+
# public consumption.**
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @private
|
17
|
+
class Parse
|
18
|
+
# Initialize the parser.
|
19
|
+
#
|
20
|
+
# @param scan [::String] The string to parse.
|
21
|
+
def initialize(scan)
|
22
|
+
@string = scan
|
23
|
+
@scanner = StringScanner.new(@string)
|
24
|
+
end
|
25
|
+
|
26
|
+
# The resulting value. This should be a name.
|
27
|
+
#
|
28
|
+
# @see #parse
|
29
|
+
# @return [Type::Name]
|
30
|
+
def value
|
31
|
+
@_value ||= parse
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def parse
|
37
|
+
@tokens = scan
|
38
|
+
name = parse_name
|
39
|
+
end
|
40
|
+
|
41
|
+
def scan
|
42
|
+
return to_enum(:scan) unless block_given?
|
43
|
+
|
44
|
+
until @scanner.eos?
|
45
|
+
single = scan_single
|
46
|
+
yield single if single
|
47
|
+
end
|
48
|
+
|
49
|
+
yield [:EOS]
|
50
|
+
end
|
51
|
+
|
52
|
+
def expect(*values)
|
53
|
+
token = @tokens.next
|
54
|
+
error(values, token[0]) unless values.include?(token[0])
|
55
|
+
token
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_name
|
59
|
+
parts = [parse_name_part]
|
60
|
+
func = nil
|
61
|
+
|
62
|
+
while @tokens.peek[0] == :"::"
|
63
|
+
expect :"::"
|
64
|
+
parts << parse_name_part
|
65
|
+
end
|
66
|
+
|
67
|
+
parts = [*parts[0..-2].map(&:strip), parts[-1]]
|
68
|
+
func = parse_function_name if @tokens.peek[0] == :"."
|
69
|
+
|
70
|
+
Name.new(parts, func)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_function_name
|
74
|
+
name = nil
|
75
|
+
params = []
|
76
|
+
expect :"."
|
77
|
+
name = case @tokens.peek[0]
|
78
|
+
when :< then expect(:<); "<"
|
79
|
+
when :> then expect(:>); ">"
|
80
|
+
when :+ then expect(:+); "+"
|
81
|
+
else expect(:FNAME)[1]
|
82
|
+
end
|
83
|
+
|
84
|
+
expect :"("
|
85
|
+
until @tokens.peek[0] == :")"
|
86
|
+
params << Type.new(parse_name)
|
87
|
+
break unless @tokens.peek[0] == :","
|
88
|
+
expect :","
|
89
|
+
end
|
90
|
+
expect :")"
|
91
|
+
|
92
|
+
Function.new(name, params)
|
93
|
+
end
|
94
|
+
|
95
|
+
def parse_name_part
|
96
|
+
part = expect(:MNAME)
|
97
|
+
generics = []
|
98
|
+
if @tokens.peek[0] == :<
|
99
|
+
expect :<
|
100
|
+
|
101
|
+
until @tokens.peek[0] == :>
|
102
|
+
generics << parse_generic
|
103
|
+
break unless @tokens.peek[0] == :","
|
104
|
+
expect :","
|
105
|
+
end
|
106
|
+
|
107
|
+
expect :>
|
108
|
+
end
|
109
|
+
|
110
|
+
Part.new(part[1], generics)
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_generic
|
114
|
+
name = Type.new(parse_name)
|
115
|
+
implements = []
|
116
|
+
if @tokens.peek[0] == :":"
|
117
|
+
expect :":"
|
118
|
+
implements << Type.new(parse_name)
|
119
|
+
while @tokens.peek[0] == :+
|
120
|
+
expect :+
|
121
|
+
implements << Type.new(parse_name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
Generic.new(name, implements)
|
126
|
+
end
|
127
|
+
|
128
|
+
FUNC_NAME = %r{
|
129
|
+
(
|
130
|
+
[a-z][A-Za-z0-9_-]*[!?=]?
|
131
|
+
| === | ==
|
132
|
+
| \<=\>
|
133
|
+
| << | >>
|
134
|
+
| <= | >=
|
135
|
+
| \-
|
136
|
+
| \* | \/
|
137
|
+
| % | & | \|
|
138
|
+
| \[\]
|
139
|
+
| \^
|
140
|
+
)
|
141
|
+
}x.freeze
|
142
|
+
|
143
|
+
def scan_single
|
144
|
+
case
|
145
|
+
when @scanner.scan(/[A-Z][A-Za-z0-9_-]*/)
|
146
|
+
[:MNAME, @scanner[0]]
|
147
|
+
when @scanner.scan(FUNC_NAME)
|
148
|
+
[:FNAME, @scanner[0]]
|
149
|
+
when @scanner.scan(/::/) then [:"::"]
|
150
|
+
when @scanner.scan(/</) then [:<]
|
151
|
+
when @scanner.scan(/>/) then [:>]
|
152
|
+
when @scanner.scan(/,/) then [:","]
|
153
|
+
when @scanner.scan(/:/) then [:":"]
|
154
|
+
when @scanner.scan(/\+/) then [:+]
|
155
|
+
when @scanner.scan(/\./) then [:"."]
|
156
|
+
when @scanner.scan(/\(/) then [:"("]
|
157
|
+
when @scanner.scan(/\)/) then [:")"]
|
158
|
+
when @scanner.scan(/\s+/)
|
159
|
+
else error([], @string[@scanner.pos])
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def error(expected, given)
|
164
|
+
fail ArgumentError,
|
165
|
+
"Unexpected #{given.inspect}, " \
|
166
|
+
"expected #{expected.map(&:inspect).join(', ')} " \
|
167
|
+
"(source #{@string})"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|