Skip to content

Commit

Permalink
special syntax for Data subclasses
Browse files Browse the repository at this point in the history
allows declaring and typing variables, inject inherited methods OTTB
  • Loading branch information
HoneyryderChuck committed Oct 25, 2024
1 parent 36a3d5f commit 131ad1d
Show file tree
Hide file tree
Showing 4 changed files with 359 additions and 25 deletions.
9 changes: 8 additions & 1 deletion ext/rbs_extension/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@ VALUE parse_member_def(parserstate *state, bool instance_only, bool accept_overl

/**
* class_instance_name ::= {} <class_name>
* | {} Data `[` kwarg args `]`
* | {} class_name `[` type args <`]`>
*
* @param kind
Expand All @@ -1756,7 +1757,13 @@ void class_instance_name(parserstate *state, TypeNameKind kind, VALUE *name, VAL

*name = parse_type_name(state, kind, name_range);

if (state->next_token.type == pLBRACKET) {
if (CLASS_OF(*name) == RBS_TypeName && rb_funcall(*name, rb_intern("data?"), 0) == Qtrue) {
parser_advance_assert(state, pLPAREN);
args_range->start = state->current_token.range.start;
*args = parse_record_attributes(state);
parser_advance_assert(state, pRPAREN);
args_range->end = state->current_token.range.end;
} else if (state->next_token.type == pLBRACKET) {
parser_advance(state);
args_range->start = state->current_token.range.start;
parse_type_list(state, pRBRACKET, args);
Expand Down
314 changes: 314 additions & 0 deletions lib/rbs/ast/declarations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,320 @@ def to_json(state = _ = nil)
location: location
}.to_json(state)
end

def self.new(name: , args:, location:)

return super unless name.data?

superklass = super(name: name, args: [], location: location)

args.transform_values! do |(type, required)|
required ? type : Types::Optional.new(type: type, location: type.location)
end

# attribute readers
members = args.map do |k, type|
Members::AttrReader.new(
name: k,
type: type,
ivar_name: :"@#{type}",
kind: :instance,
location: location,
comment: nil,
annotations: nil
)
end

# initialize
members << Members::MethodDefinition.new(
name: :initialize,
kind: :instance,
location: location,
overloading: false,
comment: nil,
annotations: nil,
visibility: nil,
overloads: [
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: args.to_h { |k, type|
[
k,
# set param
Types::Function::Param.new(
name: nil,
type: type,
location: location
)
]
},
required_positionals: [],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::Bases::Void.new(location: location),
),
location: location,
block: nil,
),
annotations: []
),
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_positionals: args.map { |k, type|
# set param
Types::Function::Param.new(
name: k,
type: type,
location: location
)
},
required_keywords: [],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::Bases::Void.new(location: location),
),
location: location,
block: nil,
),
annotations: []
)
]
)

# members
members << Members::MethodDefinition.new(
name: :members,
kind: :instance,
location: location,
overloading: false,
comment: nil,
annotations: nil,
visibility: nil,
overloads: [
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: {},
required_positionals: [],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::ClassInstance.new(
name: BuiltinNames::Array,
args: [RBS::Types::ClassInstance.new(name: BuiltinNames::Symbol, args: [], location: location)],
location: location
),
),
location: location,
block: nil,
),
annotations: []
)
]
)

# deconstruct
members << Members::MethodDefinition.new(
name: :deconstruct,
kind: :instance,
location: location,
overloading: false,
comment: nil,
annotations: nil,
visibility: nil,
overloads: [
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: {},
required_positionals: [],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::Tuple.new(
types: args.values.map do |type|
RBS::Types::ClassInstance.new(name:type, args: [], location: location)
end,
location: location
),
),
location: location,
block: nil,
),
annotations: []
)
]
)

# deconstruct_keys
members << Members::MethodDefinition.new(
name: :deconstruct_keys,
kind: :instance,
location: location,
overloading: false,
comment: nil,
annotations: nil,
visibility: nil,
overloads: [
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: {},
required_positionals: [
Types::Function::Param.new(
name: nil,
type: RBS::Types::Bases::Nil.new(location: location),
location: location
)
],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::Record.new(
all_fields: args.to_h do |k, v|
[
k,
[
RBS::Types::ClassInstance.new(name: v, args: [], location: location),
true
]
]
end,
location: location
),
),
location: location,
block: nil,
),
annotations: []
),
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: {},
required_positionals: [
Types::Function::Param.new(
name: nil,
type: RBS::Types::ClassInstance.new(
name: BuiltinNames::Array,
location: location,
args: [
RBS::Types::ClassInstance.new(
name: BuiltinNames::Symbol,
args: [],
location: location
)
]
),
location: location
)
],
optional_keywords: {},
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::ClassInstance.new(
name: BuiltinNames::Hash,
location: location,
args: [
RBS::Types::ClassInstance.new(
name: BuiltinNames::Symbol,
args: [],
location: location
),
RBS::Types::ClassInstance.new(
name: RBS::Types::Bases::Any.new(location: location),
args: [],
location: location
)
]
),
),
location: location,
block: nil,
),
annotations: []
)
]
)

# with
members << Members::MethodDefinition.new(
name: :with,
kind: :instance,
location: location,
overloading: false,
comment: nil,
annotations: nil,
visibility: nil,
overloads: [
Members::MethodDefinition::Overload.new(
method_type: MethodType.new(
type_params: [],
type: Types::Function.new(
required_keywords: {},
required_positionals: [],
optional_keywords: args.to_h do |k, v|
[
k,
RBS::Types::Function::Param.new(
name: nil,
type: RBS::Types::ClassInstance.new(
name: v,
args: [],
location: location
),
location: location
)
]
end,
optional_positionals: [],
rest_keywords: nil,
rest_positionals: nil,
trailing_positionals: [],
return_type: RBS::Types::Bases::Instance.new(
location: location
),
),
location: location,
block: nil,
),
annotations: []
)
]
)

Class.new(
name: nil,
type_params: nil,
super_class: superklass,
annotations: nil,
comment: nil,
location: location,
members: members
)
end
end

include NestedDeclarationHelper
Expand Down
4 changes: 4 additions & 0 deletions lib/rbs/type_name.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ def alias?
kind == :alias
end

def data?
class? && namespace.empty? && name == :Data
end

def absolute!
self.class.new(namespace: namespace.absolute!, name: name)
end
Expand Down
Loading

0 comments on commit 131ad1d

Please sign in to comment.