carbon-core 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|