Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add class/module alias declaration #1219

Merged
merged 9 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ext/rbs_extension/constants.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ VALUE RBS_AST_Declarations_Module;
VALUE RBS_AST_Declarations_Module_Self;
VALUE RBS_AST_Declarations_Class;
VALUE RBS_AST_Declarations_Class_Super;
VALUE RBS_AST_Declarations_ModuleAlias;
VALUE RBS_AST_Declarations_ClassAlias;

VALUE RBS_AST_Members;
VALUE RBS_AST_Members_Alias;
Expand Down Expand Up @@ -88,6 +90,8 @@ void rbs__init_constants(void) {
RBS_AST_Declarations_Module_Self = rb_const_get(RBS_AST_Declarations_Module, rb_intern("Self"));
RBS_AST_Declarations_Class = rb_const_get(RBS_AST_Declarations, rb_intern("Class"));
RBS_AST_Declarations_Class_Super = rb_const_get(RBS_AST_Declarations_Class, rb_intern("Super"));
RBS_AST_Declarations_ClassAlias = rb_const_get(RBS_AST_Declarations, rb_intern("ClassAlias"));
RBS_AST_Declarations_ModuleAlias = rb_const_get(RBS_AST_Declarations, rb_intern("ModuleAlias"));

RBS_AST_Members = rb_const_get(RBS_AST, rb_intern("Members"));
RBS_AST_Members_Alias = rb_const_get(RBS_AST_Members, rb_intern("Alias"));
Expand Down
2 changes: 2 additions & 0 deletions ext/rbs_extension/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ extern VALUE RBS_AST_Declarations_Global;
extern VALUE RBS_AST_Declarations_Interface;
extern VALUE RBS_AST_Declarations_Module_Self;
extern VALUE RBS_AST_Declarations_Module;
extern VALUE RBS_AST_Declarations_ModuleAlias;
extern VALUE RBS_AST_Declarations_ClassAlias;

extern VALUE RBS_AST_Members;
extern VALUE RBS_AST_Members_Alias;
Expand Down
113 changes: 86 additions & 27 deletions ext/rbs_extension/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,7 +1034,6 @@ VALUE parse_type(parserstate *state) {

type_param ::= tUIDENT (module_type_params == false)
*/

VALUE parse_type_params(parserstate *state, range *rg, bool module_type_params) {
VALUE params = rb_ary_new();

Expand Down Expand Up @@ -2267,29 +2266,20 @@ VALUE parse_module_members(parserstate *state) {
}

/*
module_decl ::= {`module`} module_name module_type_params module_members <kEND>
| {`module`} module_name module_type_params `:` module_self_types module_members <kEND>
module_decl ::= {module_name} module_type_params module_members <kEND>
| {module_name} module_name module_type_params `:` module_self_types module_members <kEND>
*/
VALUE parse_module_decl(parserstate *state, position comment_pos, VALUE annotations) {
VALUE parse_module_decl0(parserstate *state, range keyword_range, VALUE module_name, range name_range, VALUE comment, VALUE annotations) {
range decl_range;
range keyword_range;
range name_range;
range end_range;
range type_params_range;
range colon_range;
range self_types_range;

parser_push_typevar_table(state, true);

position start = state->current_token.range.start;
comment_pos = nonnull_pos_or(comment_pos, start);
VALUE comment = get_comment(state, comment_pos.line);
decl_range.start = keyword_range.start;

keyword_range = state->current_token.range;
decl_range.start = state->current_token.range.start;

parser_advance(state);
VALUE module_name = parse_type_name(state, CLASS_NAME, &name_range);
VALUE type_params = parse_type_params(state, &type_params_range, true);
VALUE self_types = rb_ary_new();

Expand Down Expand Up @@ -2332,6 +2322,46 @@ VALUE parse_module_decl(parserstate *state, position comment_pos, VALUE annotati
);
}

/*
module_decl ::= {`module`} module_name `=` old_module_name <kEND>
| {`module`} module_name module_decl0 <kEND>

*/
VALUE parse_module_decl(parserstate *state, position comment_pos, VALUE annotations) {
range keyword_range = state->current_token.range;
range module_name_range;

comment_pos = nonnull_pos_or(comment_pos, state->current_token.range.start);
VALUE comment = get_comment(state, comment_pos.line);

parser_advance(state);
VALUE module_name = parse_type_name(state, CLASS_NAME, &module_name_range);

if (state->next_token.type == pEQ) {
range eq_range = state->next_token.range;
parser_advance(state);
parser_advance(state);

range old_name_range;
VALUE old_name = parse_type_name(state, CLASS_NAME, &old_name_range);

range decl_range;
decl_range.start = keyword_range.start;
decl_range.end = old_name_range.end;

VALUE location = rbs_new_location(state->buffer, decl_range);
rbs_loc *loc = rbs_check_location(location);
rbs_loc_add_required_child(loc, rb_intern("keyword"), keyword_range);
rbs_loc_add_required_child(loc, rb_intern("new_name"), module_name_range);
rbs_loc_add_required_child(loc, rb_intern("eq"), eq_range);
rbs_loc_add_optional_child(loc, rb_intern("old_name"), old_name_range);

return rbs_ast_decl_module_alias(module_name, old_name, location, comment);
} else {
return parse_module_decl0(state, keyword_range, module_name, module_name_range, comment, annotations);
}
}

/*
class_decl_super ::= {} `<` <class_instance_name>
| {<>}
Expand Down Expand Up @@ -2368,35 +2398,25 @@ VALUE parse_class_decl_super(parserstate *state, range *lt_range) {
}

/*
class_decl ::= {`class`} class_name type_params class_decl_super class_members <`end`>
class_decl ::= {class_name} type_params class_decl_super class_members <`end`>
*/
VALUE parse_class_decl(parserstate *state, position comment_pos, VALUE annotations) {
VALUE parse_class_decl0(parserstate *state, range keyword_range, VALUE name, range name_range, VALUE comment, VALUE annotations) {
range decl_range;
range keyword_range;
range name_range;
range end_range;
range type_params_range;
range lt_range;

VALUE name;
VALUE type_params;
VALUE super;
VALUE members;
VALUE comment;
VALUE location;

rbs_loc *loc;

parser_push_typevar_table(state, true);

decl_range.start = state->current_token.range.start;
keyword_range = state->current_token.range;
decl_range.start = keyword_range.start;

comment_pos = nonnull_pos_or(comment_pos, decl_range.start);
comment = get_comment(state, comment_pos.line);

parser_advance(state);
name = parse_type_name(state, CLASS_NAME, &name_range);
type_params = parse_type_params(state, &type_params_range, true);
super = parse_class_decl_super(state, &lt_range);
members = parse_module_members(state);
Expand Down Expand Up @@ -2426,6 +2446,45 @@ VALUE parse_class_decl(parserstate *state, position comment_pos, VALUE annotatio
);
}

/*
class_decl ::= {`class`} class_name `=` <class_name>
| {`class`} class_name <class_decl0>
*/
VALUE parse_class_decl(parserstate *state, position comment_pos, VALUE annotations) {
range keyword_range = state->current_token.range;
range class_name_range;

comment_pos = nonnull_pos_or(comment_pos, state->current_token.range.start);
VALUE comment = get_comment(state, comment_pos.line);

parser_advance(state);
VALUE class_name = parse_type_name(state, CLASS_NAME, &class_name_range);

if (state->next_token.type == pEQ) {
range eq_range = state->next_token.range;
parser_advance(state);
parser_advance(state);

range old_name_range;
VALUE old_name = parse_type_name(state, CLASS_NAME, &old_name_range);

range decl_range;
decl_range.start = keyword_range.start;
decl_range.end = old_name_range.end;

VALUE location = rbs_new_location(state->buffer, decl_range);
rbs_loc *loc = rbs_check_location(location);
rbs_loc_add_required_child(loc, rb_intern("keyword"), keyword_range);
rbs_loc_add_required_child(loc, rb_intern("new_name"), class_name_range);
rbs_loc_add_required_child(loc, rb_intern("eq"), eq_range);
rbs_loc_add_optional_child(loc, rb_intern("old_name"), old_name_range);

return rbs_ast_decl_class_alias(class_name, old_name, location, comment);
} else {
return parse_class_decl0(state, keyword_range, class_name, class_name_range, comment, annotations);
}
}

/*
nested_decl ::= {<const_decl>}
| {<class_decl>}
Expand Down
28 changes: 28 additions & 0 deletions ext/rbs_extension/ruby_objs.c
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,34 @@ VALUE rbs_ast_decl_module(VALUE name, VALUE type_params, VALUE self_types, VALUE
);
}

VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) {
VALUE args = rb_hash_new();
rb_hash_aset(args, ID2SYM(rb_intern("new_name")), new_name);
rb_hash_aset(args, ID2SYM(rb_intern("old_name")), old_name);
rb_hash_aset(args, ID2SYM(rb_intern("location")), location);
rb_hash_aset(args, ID2SYM(rb_intern("comment")), comment);

return CLASS_NEW_INSTANCE(
RBS_AST_Declarations_ClassAlias,
1,
&args
);
}

VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment) {
VALUE args = rb_hash_new();
rb_hash_aset(args, ID2SYM(rb_intern("new_name")), new_name);
rb_hash_aset(args, ID2SYM(rb_intern("old_name")), old_name);
rb_hash_aset(args, ID2SYM(rb_intern("location")), location);
rb_hash_aset(args, ID2SYM(rb_intern("comment")), comment);

return CLASS_NEW_INSTANCE(
RBS_AST_Declarations_ModuleAlias,
1,
&args
);
}

VALUE rbs_ast_members_method_definition_overload(VALUE annotations, VALUE method_type) {
VALUE args = rb_hash_new();
rb_hash_aset(args, ID2SYM(rb_intern("annotations")), annotations);
Expand Down
2 changes: 2 additions & 0 deletions ext/rbs_extension/ruby_objs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ VALUE rbs_ast_decl_global(VALUE name, VALUE type, VALUE location, VALUE comment)
VALUE rbs_ast_decl_interface(VALUE name, VALUE type_params, VALUE members, VALUE annotations, VALUE location, VALUE comment);
VALUE rbs_ast_decl_module_self(VALUE name, VALUE args, VALUE location);
VALUE rbs_ast_decl_module(VALUE name, VALUE type_params, VALUE self_types, VALUE members, VALUE annotations, VALUE location, VALUE comment);
VALUE rbs_ast_decl_module_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment);
VALUE rbs_ast_decl_class_alias(VALUE new_name, VALUE old_name, VALUE location, VALUE comment);
VALUE rbs_ast_members_alias(VALUE new_name, VALUE old_name, VALUE kind, VALUE annotations, VALUE location, VALUE comment);
VALUE rbs_ast_members_attribute(VALUE klass, VALUE name, VALUE type, VALUE ivar_name, VALUE kind, VALUE annotations, VALUE location, VALUE comment, VALUE visibility);
VALUE rbs_ast_members_method_definition(VALUE name, VALUE kind, VALUE overloads, VALUE annotations, VALUE location, VALUE comment, VALUE overloading, VALUE visibility);
Expand Down
47 changes: 47 additions & 0 deletions lib/rbs/ast/declarations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,53 @@ def to_json(state = _ = nil)
}.to_json(state)
end
end

class AliasDecl < Base
attr_reader :new_name, :old_name, :location, :comment

def initialize(new_name:, old_name:, location:, comment:)
@new_name = new_name
@old_name = old_name
@location = location
@comment = comment
end

def ==(other)
other.is_a?(self.class) &&
other.new_name == new_name &&
other.old_name == old_name
end

alias eql? ==

def hash
self.class.hash ^ new_name.hash ^ old_name.hash
end
end

class ClassAlias < AliasDecl
def to_json(state = _ = nil)
{
declaration: :class_alias,
new_name: new_name,
old_name: old_name,
location: location,
comment: comment
}.to_json(state)
end
end

class ModuleAlias < AliasDecl
def to_json(state = _ = nil)
{
declaration: :module_alias,
new_name: new_name,
old_name: old_name,
location: location,
comment: comment
}.to_json(state)
end
end
end
end
end
5 changes: 5 additions & 0 deletions lib/rbs/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,11 @@ def run_validate(args, options)
end
end

env.class_alias_decls.each do |name, entry|
stdout.puts "Validating class/module alias definition: `#{name}`..."
validator.validate_class_alias(entry: entry)
end

env.interface_decls.each do |name, decl|
stdout.puts "Validating interface: `#{name}`..."
builder.build_interface(name).each_type do |type|
Expand Down
4 changes: 4 additions & 0 deletions lib/rbs/definition_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ def define_instance(definition, type_name, subst)
end

def build_instance(type_name)
type_name = env.normalize_module_name(type_name)

try_cache(type_name, cache: instance_cache) do
entry = env.class_decls[type_name] or raise "Unknown name for build_instance: #{type_name}"
ensure_namespace!(type_name.namespace, location: entry.decls[0].decl.location)
Expand Down Expand Up @@ -276,6 +278,8 @@ def build_singleton0(type_name)
end

def build_singleton(type_name)
type_name = env.normalize_module_name(type_name)

try_cache type_name, cache: singleton_cache do
entry = env.class_decls[type_name] or raise "Unknown name for build_singleton: #{type_name}"
ensure_namespace!(type_name.namespace, location: entry.decls[0].decl.location)
Expand Down
Loading