blob: ac901f63a9219c1d859ec88f37c7dbca2b90f98b [file]
#!/bin/bash
# The single source of truth for reserved words, categorized by PHP documentation
# Taken from https://www.php.net/manual/en/reserved.keywords.php
PHP_RESERVED_KEYWORDS=(
"abstract" "and" "array" "as" "break" "callable" "case" "catch"
"class" "clone" "const" "continue" "declare" "default" "die" "do"
"echo" "else" "elseif" "empty" "enddeclare" "endfor" "endforeach"
"endif" "endswitch" "endwhile" "eval" "exit" "extends" "final"
"finally" "fn" "for" "foreach" "function" "global" "goto" "if"
"implements" "include" "include_once" "instanceof" "insteadof"
"interface" "isset" "list" "match" "namespace" "new" "or" "parent"
"print" "private" "protected" "public" "readonly" "require"
"require_once" "return" "self" "static" "switch" "throw" "trait"
"try" "unset" "use" "var" "while" "xor" "yield"
)
# Taken from https://www.php.net/manual/en/reserved.other-reserved-words.php
PHP_OTHER_RESERVED_WORDS=(
"parent" "self" "int" "float" "bool" "string" "true" "false" "null"
"void" "iterable" "object" "mixed" "never" "array" "callable"
)
# Derived lists:
# RESERVED_WORDS is the union of keywords and soft reserved words.
RESERVED_WORDS=($(echo "${PHP_RESERVED_KEYWORDS[@]}" "${PHP_OTHER_RESERVED_WORDS[@]}" | tr ' ' '\n' | sort -u))
# This is for backwards compatibility. New PHP_RESERVED_KEYWORDS should be added
# here to prevent unnecessary breaking changes, as constants do not need the PB prefix.
# @TODO: allow ALL names for constants except for "class"
VALID_CONSTANT_NAMES=(
"bool" "false" "float" "int" "iterable" "mixed" "never" "null"
"object" "parent" "readonly" "self" "string" "true" "void"
)
VALID_CONSTANT_NAMES=($(echo "${VALID_CONSTANT_NAMES[@]}" | tr ' ' '\n' | sort -u))
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
format_columns() {
local per_line=$1
local indent=$2
shift 2
local words=("$@")
local num_words=${#words[@]}
# Default to original behavior of quoting the word.
local item_fmt="${ITEM_FMT:-\"%s\"}"
if [[ -z "$ITEM_FMT" ]]; then
item_fmt="\"%s\""
fi
# Compute max width per column to match Google C++/C formatting
local col_widths=()
local c=0
while (( c < per_line )); do
local max_w=0
local k=$c
while (( k < num_words )); do
local w="${words[k]}"
local s
printf -v s "$item_fmt" "$w"
if (( k < num_words - 1 )); then
s+=","
fi
if (( ${#s} > max_w )); then
max_w=${#s}
fi
k=$((k + per_line))
done
col_widths+=($((max_w + 1)))
c=$((c + 1))
done
local i=0
while (( i < num_words )); do
local line="$indent"
local j=0
while (( j < per_line && i < num_words )); do
local w="${words[i]}"
local s
printf -v s "$item_fmt" "$w"
if (( i < num_words - 1 )); then
s+=","
fi
if (( j < per_line - 1 && i < num_words - 1 )); then
local cw="${col_widths[j]}"
printf -v padded "%-${cw}s" "$s"
line+="$padded"
else
line+="$s"
fi
i=$((i + 1))
j=$((j + 1))
done
echo "${line%" "}"
done
}
update_file() {
local path="$1"
local label="$2"
local new_content="$3"
local begin="// BEGIN $label"
local end="// END $label"
local full_path="$REPO_ROOT/$path"
if [[ ! -f "$full_path" ]]; then
echo "Skipping $path (not found)"
return
fi
# Extract indentation of the first line of content
local indent=$(echo "$new_content" | head -n 1 | grep -o '^[[:space:]]*')
local temp_file=$(mktemp)
# Use perl to replace the block, writing to a temporary file
BEGIN_MARKER="$begin" END_MARKER="$end" NEW_CONTENT="$new_content" INDENT="$indent" \
perl -0777 -pe 's{^[ \t]*\Q$ENV{BEGIN_MARKER}\E.*?^[ \t]*\Q$ENV{END_MARKER}\E}{$ENV{INDENT}$ENV{BEGIN_MARKER}\n$ENV{NEW_CONTENT}\n$ENV{INDENT}$ENV{END_MARKER}}sm' "$full_path" > "$temp_file"
# Move the temporary file to the original file's path
mv "$temp_file" "$full_path"
echo "Updated $path"
}
generate_names_cc() {
local lines=()
lines+=("// @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY")
lines+=("const char* const kReservedNames[] = {")
local col_lines=()
while IFS= read -r line; do
col_lines+=("$line")
done < <(format_columns 5 " " "${RESERVED_WORDS[@]}")
for l in "${col_lines[@]}"; do lines+=("$l"); done
lines[${#lines[@]}-1]+="};"
lines+=("const int kReservedNamesSize = ${#RESERVED_WORDS[@]};")
printf "%s\n" "${lines[@]}"
}
generate_names_c() {
local lines=()
lines+=("// @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY")
lines+=("const char* const kReservedNames[] = {")
local decorated=()
for w in "${RESERVED_WORDS[@]}"; do
decorated+=("\"$w\"")
done
decorated+=("NULL")
local col_lines=()
while IFS= read -r line; do
col_lines+=("$line")
done < <(ITEM_FMT="%s" format_columns 4 " " "${decorated[@]}")
for l in "${col_lines[@]}"; do lines+=("$l"); done
lines[${#lines[@]}-1]+="};"
printf "%s\n" "${lines[@]}"
}
generate_php_generator_cc() {
local lines=()
lines+=("// @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY")
lines+=("constexpr absl::string_view kValidConstantNames[] = {")
local col_lines=()
while IFS= read -r line; do
col_lines+=("$line")
done < <(format_columns 5 " " "${VALID_CONSTANT_NAMES[@]}")
for l in "${col_lines[@]}"; do lines+=("$l"); done
lines[${#lines[@]}-1]+="};"
lines+=("const int kValidConstantNamesSize = ${#VALID_CONSTANT_NAMES[@]};")
printf "%s\n" "${lines[@]}"
}
generate_proto_messages() {
local upper=$1
echo "// @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY"
for w in "${RESERVED_WORDS[@]}"; do
local name="$w"
if [[ "$upper" == "true" ]]; then name=$(echo "$w" | tr '[:lower:]' '[:upper:]'); fi
echo "message $name {}"
done
}
generate_proto_enums() {
local upper=$1
echo "// @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY"
local i=1
for w in "${RESERVED_WORDS[@]}"; do
local name="$w"
if [[ "$upper" == "true" ]]; then name=$(echo "$w" | tr '[:lower:]' '[:upper:]'); fi
echo "enum $name {"
echo " ZERO$i = 0;"
echo "}"
i=$((i + 1))
done
}
generate_proto_enum_values() {
local upper=$1
echo " // @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY"
local i=0
for w in "${RESERVED_WORDS[@]}"; do
local name="$w"
if [[ "$upper" == "true" ]]; then name=$(echo "$w" | tr '[:lower:]' '[:upper:]'); fi
echo " $name = $i;"
i=$((i + 1))
done
}
generate_test_cases() {
echo " // @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY"
# Lower messages
for w in "${RESERVED_WORDS[@]}"; do
echo " \$m = new \\Lower\\PB$w();"
done
echo ""
# Upper messages
for w in "${RESERVED_WORDS[@]}"; do
local upper=$(echo "$w" | tr '[:lower:]' '[:upper:]')
echo " \$m = new \\Upper\\PB$upper();"
done
echo ""
# Lower enums
for w in "${RESERVED_WORDS[@]}"; do
echo " \$m = new \\Lower_enum\\PB$w();"
done
echo ""
# Upper enums
for w in "${RESERVED_WORDS[@]}"; do
local upper=$(echo "$w" | tr '[:lower:]' '[:upper:]')
echo " \$m = new \\Upper_enum\\PB$upper();"
done
echo ""
# Lower enum values
for w in "${RESERVED_WORDS[@]}"; do
local prefix="PB"
for v in "${VALID_CONSTANT_NAMES[@]}"; do
if [[ "$w" == "$v" ]]; then prefix=""; break; fi
done
echo " \$m = \\Lower_enum_value\\NotAllowed::${prefix}${w};"
done
echo ""
# Upper enum values
for w in "${RESERVED_WORDS[@]}"; do
local prefix="PB"
for v in "${VALID_CONSTANT_NAMES[@]}"; do
if [[ "$w" == "$v" ]]; then prefix=""; break; fi
done
local upper=$(echo "$w" | tr '[:lower:]' '[:upper:]')
echo " \$m = \\Upper_enum_value\\NotAllowed::${prefix}${upper};"
done
}
generate_gpbutil_reserved_words() {
echo " // @see php/update_reserved_words.sh - DO NOT MODIFY THIS LIST MANUALLY"
echo " \$reserved_words = array("
ITEM_FMT="\"%s\"=>0" format_columns 3 " " "${RESERVED_WORDS[@]}"
echo " );"
}
update_file "src/google/protobuf/compiler/php/names.cc" "RESERVED NAMES" "$(generate_names_cc)"
update_file "php/ext/google/protobuf/names.c" "RESERVED NAMES" "$(generate_names_c)"
update_file "src/google/protobuf/compiler/php/php_generator.cc" "VALID CONSTANT NAMES" "$(generate_php_generator_cc)"
update_file "php/tests/proto/test_reserved_message_lower.proto" "RESERVED NAMES" "$(generate_proto_messages false)"
update_file "php/tests/proto/test_reserved_message_upper.proto" "RESERVED NAMES" "$(generate_proto_messages true)"
update_file "php/tests/proto/test_reserved_enum_lower.proto" "RESERVED NAMES" "$(generate_proto_enums false)"
update_file "php/tests/proto/test_reserved_enum_upper.proto" "RESERVED NAMES" "$(generate_proto_enums true)"
update_file "php/tests/proto/test_reserved_enum_value_lower.proto" "RESERVED NAMES" "$(generate_proto_enum_values false)"
update_file "php/tests/proto/test_reserved_enum_value_upper.proto" "RESERVED NAMES" "$(generate_proto_enum_values true)"
update_file "php/tests/GeneratedClassTest.php" "RESERVED NAMES" "$(generate_test_cases)"
update_file "php/src/Google/Protobuf/Internal/GPBUtil.php" "RESERVED WORDS" "$(generate_gpbutil_reserved_words)"