YARP resync (#8059)

This commit is contained in:
Jemma Issroff 2023-07-12 12:46:38 -04:00 committed by GitHub
parent 47cb789332
commit a02f5eb56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
Notes: git 2023-07-12 16:46:58 +00:00
Merged-By: jemmaissroff
5 changed files with 140 additions and 25 deletions

View File

@ -4427,7 +4427,7 @@ module YARP
end end
end end
# Represents a parentesized expression # Represents a parenthesized expression
# #
# (10 + 34) # (10 + 34)
# ^^^^^^^^^ # ^^^^^^^^^

View File

@ -426,9 +426,14 @@ class ErrorsTest < Test::Unit::TestCase
expected = DefNode( expected = DefNode(
Location(), Location(),
nil, nil,
ParametersNode([], [], [], nil, [], nil, nil), ParametersNode([
RequiredParameterNode(:A),
RequiredParameterNode(:@a),
RequiredParameterNode(:$A),
RequiredParameterNode(:@@a),
], [], [], nil, [], nil, nil),
nil, nil,
[], [:A, :@a, :$A, :@@a],
Location(), Location(),
nil, nil,
Location(), Location(),

View File

@ -0,0 +1,101 @@
# frozen_string_literal: true
require "yarp_test_helper"
if RUBY_PLATFORM =~ /linux/
#
# examine a yarp dll or static archive for expected external symbols.
# these tests only work on a linux system right now.
#
class LibrarySymbolsTest < Test::Unit::TestCase
def setup
super
@librubyparser_a = File.expand_path(File.join(__dir__, "..", "build", "librubyparser.a"))
@librubyparser_so = File.expand_path(File.join(__dir__, "..", "build", "librubyparser.so"))
@yarp_so = File.expand_path(File.join(__dir__, "..", "lib", "yarp.so"))
end
# objdump runner and helpers
def objdump(path)
assert_path_exist(path)
%x(objdump --section=.text --syms #{path}).split("\n")
end
def global_objdump_symbols(path)
objdump(path).select { |line| line[17] == "g" }
end
def hidden_global_objdump_symbols(path)
global_objdump_symbols(path).select { |line| line =~ / \.hidden / }
end
def visible_global_objdump_symbols(path)
global_objdump_symbols(path).reject { |line| line =~ / \.hidden / }
end
# nm runner and helpers
def nm(path)
assert_path_exist(path)
%x(nm #{path}).split("\n")
end
def global_nm_symbols(path)
nm(path).select { |line| line[17] == "T" }
end
def local_nm_symbols(path)
nm(path).select { |line| line[17] == "t" }
end
# dig the symbol name out of each line. works for both `objdump` and `nm` output.
def names(symbol_lines)
symbol_lines.map { |line| line.split(/\s+/).last }
end
#
# static archive - librubyparser.a
#
def test_librubyparser_a_contains_nothing_globally_visible
omit("librubyparser.a is not built") unless File.exist?(@librubyparser_a)
assert_empty(names(visible_global_objdump_symbols(@librubyparser_a)))
end
def test_librubyparser_a_contains_hidden_yp_symbols
omit("librubyparser.a is not built") unless File.exist?(@librubyparser_a)
names(hidden_global_objdump_symbols(@librubyparser_a)).tap do |symbols|
assert_includes(symbols, "yp_parse")
assert_includes(symbols, "yp_version")
end
end
#
# shared object - librubyparser.so
#
def test_librubyparser_so_exports_only_the_necessary_functions
omit("librubyparser.so is not built") unless File.exist?(@librubyparser_so)
names(global_nm_symbols(@librubyparser_so)).tap do |symbols|
assert_includes(symbols, "yp_parse")
assert_includes(symbols, "yp_version")
end
names(local_nm_symbols(@librubyparser_so)).tap do |symbols|
assert_includes(symbols, "yp_encoding_shift_jis_isupper_char")
end
# TODO: someone who uses this library needs to finish this test
end
#
# shared object - yarp.so
#
def test_yarp_so_exports_only_the_C_extension_init_function
omit("yarp.so is not built") unless File.exist?(@yarp_so)
names(global_nm_symbols(@yarp_so)).tap do |symbols|
assert_equal(["Init_yarp"], symbols)
end
end
end
end

View File

@ -12,11 +12,9 @@
#include <string.h> #include <string.h>
// YP_EXPORTED_FUNCTION // YP_EXPORTED_FUNCTION
#if defined(YP_STATIC) #if defined(_WIN32)
# define YP_EXPORTED_FUNCTION
#elif defined(_WIN32)
# define YP_EXPORTED_FUNCTION __declspec(dllexport) extern # define YP_EXPORTED_FUNCTION __declspec(dllexport) extern
#else #elif defined(YP_EXPORT_SYMBOLS)
# ifndef YP_EXPORTED_FUNCTION # ifndef YP_EXPORTED_FUNCTION
# ifndef RUBY_FUNC_EXPORTED # ifndef RUBY_FUNC_EXPORTED
# define YP_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern # define YP_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern
@ -24,6 +22,8 @@
# define YP_EXPORTED_FUNCTION RUBY_FUNC_EXPORTED # define YP_EXPORTED_FUNCTION RUBY_FUNC_EXPORTED
# endif # endif
# endif # endif
#else
# define YP_EXPORTED_FUNCTION
#endif #endif
// YP_ATTRIBUTE_UNUSED // YP_ATTRIBUTE_UNUSED

View File

@ -3412,7 +3412,6 @@ yp_required_destructured_parameter_node_closing_set(yp_required_destructured_par
// Allocate a new RequiredParameterNode node. // Allocate a new RequiredParameterNode node.
static yp_required_parameter_node_t * static yp_required_parameter_node_t *
yp_required_parameter_node_create(yp_parser_t *parser, const yp_token_t *token) { yp_required_parameter_node_create(yp_parser_t *parser, const yp_token_t *token) {
assert(token->type == YP_TOKEN_MISSING || token->type == YP_TOKEN_IDENTIFIER);
yp_required_parameter_node_t *node = YP_ALLOC_NODE(parser, yp_required_parameter_node_t); yp_required_parameter_node_t *node = YP_ALLOC_NODE(parser, yp_required_parameter_node_t);
*node = (yp_required_parameter_node_t) { *node = (yp_required_parameter_node_t) {
@ -8244,8 +8243,27 @@ parse_parameters(
} }
break; break;
} }
case YP_TOKEN_IDENTIFIER: { case YP_TOKEN_CLASS_VARIABLE:
case YP_TOKEN_IDENTIFIER:
case YP_TOKEN_CONSTANT:
case YP_TOKEN_INSTANCE_VARIABLE:
case YP_TOKEN_GLOBAL_VARIABLE: {
parser_lex(parser); parser_lex(parser);
switch (parser->previous.type) {
case YP_TOKEN_CONSTANT:
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant");
break;
case YP_TOKEN_INSTANCE_VARIABLE:
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable");
break;
case YP_TOKEN_GLOBAL_VARIABLE:
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable");
break;
case YP_TOKEN_CLASS_VARIABLE:
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable");
break;
default: break;
}
if (parser->current.type == YP_TOKEN_EQUAL) { if (parser->current.type == YP_TOKEN_EQUAL) {
update_parameter_state(parser, &parser->current, &order); update_parameter_state(parser, &parser->current, &order);
@ -8387,22 +8405,6 @@ parse_parameters(
yp_parameters_node_keyword_rest_set(params, param); yp_parameters_node_keyword_rest_set(params, param);
break; break;
} }
case YP_TOKEN_CONSTANT:
parser_lex(parser);
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant");
break;
case YP_TOKEN_INSTANCE_VARIABLE:
parser_lex(parser);
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable");
break;
case YP_TOKEN_GLOBAL_VARIABLE:
parser_lex(parser);
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable");
break;
case YP_TOKEN_CLASS_VARIABLE:
parser_lex(parser);
yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable");
break;
default: default:
if (parser->previous.type == YP_TOKEN_COMMA) { if (parser->previous.type == YP_TOKEN_COMMA) {
if (allows_trailing_comma) { if (allows_trailing_comma) {
@ -8427,6 +8429,13 @@ parse_parameters(
} while (looping && accept(parser, YP_TOKEN_COMMA)); } while (looping && accept(parser, YP_TOKEN_COMMA));
yp_do_loop_stack_pop(parser); yp_do_loop_stack_pop(parser);
// If we don't have any parameters, return `NULL` instead of an empty `ParametersNode`.
if (params->base.location.start == params->base.location.end) {
yp_node_destroy(parser, (yp_node_t *) params);
return NULL;
}
return params; return params;
} }