From a20afd30c1eb5d65248160774226fcfaf5ced535 Mon Sep 17 00:00:00 2001 From: Anton Vasiliev <1695147@gmail.com> Date: Sun, 28 Sep 2025 12:16:05 +0100 Subject: [PATCH] #166 - Add support for single letter classes --- parser/zephir.lemon | 108 ++++++++++++++++++++++++- tests/classes/single-letter-class.phpt | 17 ++++ tests/classes/single_letter_class.phpt | 19 +++++ 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 tests/classes/single-letter-class.phpt create mode 100644 tests/classes/single_letter_class.phpt diff --git a/parser/zephir.lemon b/parser/zephir.lemon index 1d7ecd8d..1ec5c9d0 100644 --- a/parser/zephir.lemon +++ b/parser/zephir.lemon @@ -248,6 +248,14 @@ xx_interface_def(R) ::= INTERFACE IDENTIFIER(I) EXTENDS xx_implements_list(L) xx xx_ret_interface(&R, I, &B, &L, status->scanner_state); } +xx_interface_def(R) ::= INTERFACE CONSTANT(I) xx_interface_body(B) . { + xx_ret_interface(&R, I, &B, NULL, status->scanner_state); +} + +xx_interface_def(R) ::= INTERFACE CONSTANT(I) EXTENDS xx_implements_list(L) xx_interface_body(B) . { + xx_ret_interface(&R, I, &B, &L, status->scanner_state); +} + xx_class_def(R) ::= CLASS IDENTIFIER(I) xx_class_body(B) . { xx_ret_class(&R, I, &B, 0, 0, NULL, NULL, status->scanner_state); } @@ -256,6 +264,10 @@ xx_class_def(R) ::= CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) xx_class_body(B) . xx_ret_class(&R, I, &B, 0, 0, E, NULL, status->scanner_state); } +xx_class_def(R) ::= CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, NULL, status->scanner_state); +} + xx_class_def(R) ::= CLASS IDENTIFIER(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { xx_ret_class(&R, I, &B, 0, 0, NULL, &L, status->scanner_state); } @@ -264,6 +276,10 @@ xx_class_def(R) ::= CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) IMPLEMENTS xx_impl xx_ret_class(&R, I, &B, 0, 0, E, &L, status->scanner_state); } +xx_class_def(R) ::= CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, &L, status->scanner_state); +} + xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) xx_class_body(B) . { xx_ret_class(&R, I, &B, 1, 0, NULL, NULL, status->scanner_state); } @@ -272,6 +288,10 @@ xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) xx_class_ xx_ret_class(&R, I, &B, 1, 0, E, NULL, status->scanner_state); } +xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, NULL, status->scanner_state); +} + xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { xx_ret_class(&R, I, &B, 1, 0, NULL, &L, status->scanner_state); } @@ -280,6 +300,10 @@ xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) IMPLEMENT xx_ret_class(&R, I, &B, 1, 0, E, &L, status->scanner_state); } +xx_class_def(R) ::= ABSTRACT CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, &L, status->scanner_state); +} + xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) xx_class_body(B) . { xx_ret_class(&R, I, &B, 0, 1, NULL, NULL, status->scanner_state); } @@ -288,6 +312,10 @@ xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) xx_class_bod xx_ret_class(&R, I, &B, 0, 1, E, NULL, status->scanner_state); } +xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, NULL, status->scanner_state); +} + xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { xx_ret_class(&R, I, &B, 0, 1, NULL, &L, status->scanner_state); } @@ -296,7 +324,81 @@ xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) EXTENDS IDENTIFIER(E) IMPLEMENTS x xx_ret_class(&R, I, &B, 0, 1, E, &L, status->scanner_state); } -/* TODO: Add internall class */ +xx_class_def(R) ::= FINAL CLASS IDENTIFIER(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, NULL, NULL, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, NULL, &L, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= CLASS CONSTANT(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 0, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, NULL, NULL, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, NULL, &L, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= ABSTRACT CLASS CONSTANT(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 1, 0, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, NULL, NULL, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) EXTENDS CONSTANT(E) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, NULL, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, NULL, &L, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) EXTENDS IDENTIFIER(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, &L, status->scanner_state); +} + +xx_class_def(R) ::= FINAL CLASS CONSTANT(I) EXTENDS CONSTANT(E) IMPLEMENTS xx_implements_list(L) xx_class_body(B) . { + xx_ret_class(&R, I, &B, 0, 1, E, &L, status->scanner_state); +} xx_class_body(R) ::= BRACKET_OPEN BRACKET_CLOSE . { ZVAL_UNDEF(&R); @@ -318,6 +420,10 @@ xx_implements(R) ::= IDENTIFIER(I) . { xx_ret_literal(&R, XX_T_IDENTIFIER, I, status->scanner_state); } +xx_implements(R) ::= CONSTANT(I) . { + xx_ret_literal(&R, XX_T_IDENTIFIER, I, status->scanner_state); +} + xx_interface_body(R) ::= BRACKET_OPEN BRACKET_CLOSE . { ZVAL_UNDEF(&R); } diff --git a/tests/classes/single-letter-class.phpt b/tests/classes/single-letter-class.phpt new file mode 100644 index 00000000..559480fc --- /dev/null +++ b/tests/classes/single-letter-class.phpt @@ -0,0 +1,17 @@ +--TEST-- +Single-letter class name should be accepted (regression test) +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(1) "A" + diff --git a/tests/classes/single_letter_class.phpt b/tests/classes/single_letter_class.phpt new file mode 100644 index 00000000..b002b82e --- /dev/null +++ b/tests/classes/single_letter_class.phpt @@ -0,0 +1,19 @@ +--TEST-- +Single-letter class name should be parsed +--SKIPIF-- + +--FILE-- + +--EXPECT-- +string(5) "class" +string(1) "A" +