emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/phps-mode ff28d3c: Fixed bug in incremental lex-analyze


From: Christian Johansson
Subject: [elpa] externals/phps-mode ff28d3c: Fixed bug in incremental lex-analyzer related to heredoc and nesting stack
Date: Thu, 11 Mar 2021 02:30:57 -0500 (EST)

branch: externals/phps-mode
commit ff28d3c3910233135b42a78c821f8f33e12a157d
Author: Christian Johansson <christian@cvj.se>
Commit: Christian Johansson <christian@cvj.se>

    Fixed bug in incremental lex-analyzer related to heredoc and nesting stack
---
 Makefile                             |   9 +-
 admin/phps-mode-automation-header.wy | 312 -----------------------------------
 admin/phps-mode-automation.el        | 117 ++++++-------
 phps-mode-lex-analyzer.el            |  38 ++++-
 phps-mode-lexer.el                   |  20 ++-
 phps-mode.el                         |   4 +-
 test/phps-mode-test-integration.el   | 153 ++---------------
 test/phps-mode-test-lexer.el         |  48 +++---
 8 files changed, 152 insertions(+), 549 deletions(-)

diff --git a/Makefile b/Makefile
index 2a6e1ee..9c1b246 100644
--- a/Makefile
+++ b/Makefile
@@ -2,15 +2,19 @@ EMACS = emacs
 ifdef emacs
        EMACS = $(emacs)
 endif
-EMACS_CMD := $(EMACS) -Q -batch -L . -L test/
+EMACS_CMD := $(EMACS) -Q -batch -L . -L test/ -L admin/
 
-EL  := admin/phps-mode-automation.el phps-mode-flymake.el 
phps-mode-lex-analyzer.el phps-mode-lexer.el phps-mode-macros.el 
phps-mode-syntax-table.el  phps-mode-parser-grammar-macro.el phps-mode.el 
phps-mode-test.el test/phps-mode-test-lex-analyzer.el 
test/phps-mode-test-integration.el test/phps-mode-test-lexer.el 
test/phps-mode-test-parser.el test/phps-mode-test-syntax-table.el
+EL  := admin/phps-mode-automation.el admin/phps-mode-automation-grammar.el 
phps-mode-flymake.el phps-mode-lex-analyzer.el phps-mode-lexer.el 
phps-mode-macros.el phps-mode-syntax-table.el  
phps-mode-parser-grammar-macro.el phps-mode.el phps-mode-test.el 
test/phps-mode-test-lex-analyzer.el test/phps-mode-test-integration.el 
test/phps-mode-test-lexer.el test/phps-mode-test-parser.el 
test/phps-mode-test-syntax-table.el
 ELC := $(EL:.el=.elc)
 
 .PHONY: clean
 clean:
        rm -f $(ELC)
 
+.PHONY: generate-parser
+generate-parser:
+       $(EMACS_CMD) -L ~/.emacs.d/emacs-parser-generator/ -l 
phps-mode-lexer.el -l admin/phps-mode-automation.el
+
 .PHONY: compile
 compile:
        $(EMACS_CMD) -f batch-byte-compile $(EL)
@@ -26,7 +30,6 @@ test-integration:
 test-lex-analyzer:
        $(EMACS_CMD) -l test/phps-mode-test-lex-analyzer.el
 
-
 .PHONY: test-lexer
 test-lexer:
        $(EMACS_CMD) -l test/phps-mode-test-lexer.el -f "phps-mode-test-lexer"
diff --git a/admin/phps-mode-automation-header.wy 
b/admin/phps-mode-automation-header.wy
deleted file mode 100644
index 17c4b33..0000000
--- a/admin/phps-mode-automation-header.wy
+++ /dev/null
@@ -1,312 +0,0 @@
-;;; phps.wy --- Semantic LALR grammar for PHP -*- lexical-binding: t -*-
-
-;; Copyright (C) 2018-2020  Free Software Foundation, Inc.
-
-;; This file is not part of GNU Emacs.
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, or (at
-;; your option) any later version.
-
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
-
-
-;;; Commentary:
-
-;; Run `(wisent-make-parsers)' or "C-c C-c" to generate grammar-file in Emacs 
Lisp.
-;;
-;; To debug (setq wisent-verbose-flag t) and check buffer *wisent-log*
-;;
-;; Based on the Zend PHP Parser YACC 
https://github.com/php/php-src/blob/master/Zend/zend_language_parser.y
-
-;; Create macros for all macros uses in original YACC, base macro structure on 
semantic-php-wy-macro.el
-
-;; Don't edit phps.wy because it's generated by phps-automation.el and 
phps-automation-header.wy
-
-;; Check semantic/wisent/grammar.el for macro definitions
-
-;; To force compile grammar use: (semantic-grammar-create-package t)
-
-
-;;; Code:
-
-%package phps-mode
-%provide phps-mode-wy
-
-%languagemode phps-mode
-
-%{
-  (setq max-specpdl-size 160000)
-}
-
-%use-macros phps-mode-parser-grammar-macro
-{
- ZEND_AST_CREATE
- ZEND_AST_CREATE_ASSIGN_OP
- ZEND_AST_CREATE_BINARY_OP
- ZEND_AST_CREATE_CAST
- ZEND_AST_CREATE_CLASS_CONST_OR_NAME
- ZEND_AST_CREATE_EX
- ZEND_AST_CREATE_LIST
- ZEND_AST_CREATE_ZVAL
- ZEND_AST_LIST_ADD
- ZEND_AST_LIST_RTRIM
- ZEND_LEX_TSTRING
- ZEND_NEGATE_NUM_STRING
- ZVAL_INTERNED_STR
-}
-
-%precedence T_THROW
-%precedence PREC_ARROW_FUNCTION
-%precedence T_INCLUDE T_INCLUDE_ONCE T_REQUIRE T_REQUIRE_ONCE
-%left T_LOGICAL_OR
-%left T_LOGICAL_XOR
-%left T_LOGICAL_AND
-%precedence T_PRINT
-%precedence T_YIELD
-%precedence T_DOUBLE_ARROW
-%precedence T_YIELD_FROM
-%precedence '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL 
T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL 
T_SR_EQUAL T_POW_EQUAL T_COALESCE_EQUAL
-%left '?' ':'
-%right T_COALESCE
-%left T_BOOLEAN_OR
-%left T_BOOLEAN_AND
-%left '|'
-%left '^'
-%left '&'
-%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL 
T_SPACESHIP
-%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
-%left '.'
-%left T_SL T_SR
-%left '+' '-'
-%left '*' '/' '%'
-%precedence '!'
-%precedence T_INSTANCEOF
-%precedence '~' T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST 
T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
-%right T_POW
-%precedence T_CLONE
-
-;; Resolve danging else conflict
-%precedence T_NOELSE
-%precedence T_ELSEIF
-%precedence T_ELSE
-
-%token <ast> T_LNUMBER   "integer number (T_LNUMBER)"
-%token <ast> T_DNUMBER   "floating-point number (T_DNUMBER)"
-%token <ast> T_STRING    "identifier (T_STRING)"
-%token <ast> T_VARIABLE  "variable (T_VARIABLE)"
-%token <ast> T_INLINE_HTML
-%token <ast> T_ENCAPSED_AND_WHITESPACE  "quoted-string and whitespace 
(T_ENCAPSED_AND_WHITESPACE)"
-%token <ast> T_CONSTANT_ENCAPSED_STRING "quoted-string 
(T_CONSTANT_ENCAPSED_STRING)"
-%token <ast> T_STRING_VARNAME "variable name (T_STRING_VARNAME)"
-%token <ast> T_NUM_STRING "number (T_NUM_STRING)"
-
-%type <punctuation>
-%token <punctuation> ADDITION "+"
-%token <punctuation> ASSIGN "="
-%token <punctuation> AT "@"
-%token <punctuation> BACKTICK "`"
-%token <punctuation> BITWISE_AND "&"
-%token <punctuation> BITWISE_OR "|"
-%token <punctuation> CLOSE_CURLY_BRACKET "]"
-%token <punctuation> CLOSE_PARENTHESIS ")"
-%token <punctuation> CLOSE_SQUARE_BRACKET "]"
-%token <punctuation> COLON ":"
-%token <punctuation> COMMA ","
-%token <punctuation> DOLLAR_SIGN "$"
-%token <punctuation> DOUBLE_QUOTE "\""
-%token <punctuation> DIVISION "/"
-%token <punctuation> DOT "."
-%token <punctuation> GREATER_THAN ">"
-%token <punctuation> LESSER_THAN "<"
-%token <punctuation> MODULO "%"
-%token <punctuation> MULTIPLICATION "*"
-%token <punctuation> NEGATION "!"
-%token <punctuation> OPEN_CURLY_BRACKET "{"
-%token <punctuation> OPEN_PARENTHESIS "("
-%token <punctuation> OPEN_SQUARE_BRACKET "["
-%token <punctuation> POW "^"
-%token <punctuation> QUESTION_MARK "?"
-%token <punctuation> SEMICOLON ";"
-%token <punctuation> SINGLE_QUOTE "'"
-%token <punctuation> SUBTRACTION "-"
-%token <punctuation> UNARY "~"
-
-%token END 0 "end of file"
-%token T_INCLUDE      "include (T_INCLUDE)"
-%token T_INCLUDE_ONCE "include_once (T_INCLUDE_ONCE)"
-%token T_EVAL         "eval (T_EVAL)"
-%token T_REQUIRE      "require (T_REQUIRE)"
-%token T_REQUIRE_ONCE "require_once (T_REQUIRE_ONCE)"
-%token T_LOGICAL_OR   "or (T_LOGICAL_OR)"
-%token T_LOGICAL_XOR  "xor (T_LOGICAL_XOR)"
-%token T_LOGICAL_AND  "and (T_LOGICAL_AND)"
-%token T_PRINT        "print (T_PRINT)"
-%token T_YIELD        "yield (T_YIELD)"
-%token T_YIELD_FROM   "yield from (T_YIELD_FROM)"
-%token T_PLUS_EQUAL   "+= (T_PLUS_EQUAL)"
-%token T_MINUS_EQUAL  "-= (T_MINUS_EQUAL)"
-%token T_MUL_EQUAL    "*= (T_MUL_EQUAL)"
-%token T_DIV_EQUAL    "/= (T_DIV_EQUAL)"
-%token T_CONCAT_EQUAL ".= (T_CONCAT_EQUAL)"
-%token T_MOD_EQUAL    "%= (T_MOD_EQUAL)"
-%token T_AND_EQUAL    "&= (T_AND_EQUAL)"
-%token T_OR_EQUAL     "|= (T_OR_EQUAL)"
-%token T_XOR_EQUAL    "^= (T_XOR_EQUAL)"
-%token T_SL_EQUAL     "<<= (T_SL_EQUAL)"
-%token T_SR_EQUAL     ">>= (T_SR_EQUAL)"
-%token T_COALESCE_EQUAL "??= (T_COALESCE_EQUAL)"
-%token T_BOOLEAN_OR   "|| (T_BOOLEAN_OR)"
-%token T_BOOLEAN_AND  "&& (T_BOOLEAN_AND)"
-%token T_IS_EQUAL     "== (T_IS_EQUAL)"
-%token T_IS_NOT_EQUAL "!= (T_IS_NOT_EQUAL)"
-%token T_IS_IDENTICAL "=== (T_IS_IDENTICAL)"
-%token T_IS_NOT_IDENTICAL "!== (T_IS_NOT_IDENTICAL)"
-%token T_IS_SMALLER_OR_EQUAL "<= (T_IS_SMALLER_OR_EQUAL)"
-%token T_IS_GREATER_OR_EQUAL ">= (T_IS_GREATER_OR_EQUAL)"
-%token T_SPACESHIP "<=> (T_SPACESHIP)"
-%token T_SL "<< (T_SL)"
-%token T_SR ">> (T_SR)"
-%token T_INSTANCEOF  "instanceof (T_INSTANCEOF)"
-%token T_INC "++ (T_INC)"
-%token T_DEC "-- (T_DEC)"
-%token T_INT_CAST    "(int) (T_INT_CAST)"
-%token T_DOUBLE_CAST "(double) (T_DOUBLE_CAST)"
-%token T_STRING_CAST "(string) (T_STRING_CAST)"
-%token T_ARRAY_CAST  "(array) (T_ARRAY_CAST)"
-%token T_OBJECT_CAST "(object) (T_OBJECT_CAST)"
-%token T_BOOL_CAST   "(bool) (T_BOOL_CAST)"
-%token T_UNSET_CAST  "(unset) (T_UNSET_CAST)"
-%token T_NEW       "new (T_NEW)"
-%token T_CLONE     "clone (T_CLONE)"
-%token T_EXIT      "exit (T_EXIT)"
-%token T_IF        "if (T_IF)"
-%token T_ELSEIF    "elseif (T_ELSEIF)"
-%token T_ELSE      "else (T_ELSE)"
-%token T_ENDIF     "endif (T_ENDIF)"
-%token T_ECHO       "echo (T_ECHO)"
-%token T_DO         "do (T_DO)"
-%token T_WHILE      "while (T_WHILE)"
-%token T_ENDWHILE   "endwhile (T_ENDWHILE)"
-%token T_FOR        "for (T_FOR)"
-%token T_ENDFOR     "endfor (T_ENDFOR)"
-%token T_FOREACH    "foreach (T_FOREACH)"
-%token T_ENDFOREACH "endforeach (T_ENDFOREACH)"
-%token T_DECLARE    "declare (T_DECLARE)"
-%token T_ENDDECLARE "enddeclare (T_ENDDECLARE)"
-%token T_AS         "as (T_AS)"
-%token T_SWITCH     "switch (T_SWITCH)"
-%token T_ENDSWITCH  "endswitch (T_ENDSWITCH)"
-%token T_CASE       "case (T_CASE)"
-%token T_DEFAULT    "default (T_DEFAULT)"
-%token T_BREAK      "break (T_BREAK)"
-%token T_CONTINUE   "continue (T_CONTINUE)"
-%token T_GOTO       "goto (T_GOTO)"
-%token T_FUNCTION   "function (T_FUNCTION)"
-%token T_FN         "fn (T_FN)"
-%token T_CONST      "const (T_CONST)"
-%token T_RETURN     "return (T_RETURN)"
-%token T_TRY        "try (T_TRY)"
-%token T_CATCH      "catch (T_CATCH)"
-%token T_FINALLY    "finally (T_FINALLY)"
-%token T_THROW      "throw (T_THROW)"
-%token T_USE        "use (T_USE)"
-%token T_INSTEADOF  "insteadof (T_INSTEADOF)"
-%token T_GLOBAL     "global (T_GLOBAL)"
-%token T_STATIC     "static (T_STATIC)"
-%token T_ABSTRACT   "abstract (T_ABSTRACT)"
-%token T_FINAL      "final (T_FINAL)"
-%token T_PRIVATE    "private (T_PRIVATE)"
-%token T_PROTECTED  "protected (T_PROTECTED)"
-%token T_PUBLIC     "public (T_PUBLIC)"
-%token T_VAR        "var (T_VAR)"
-%token T_UNSET      "unset (T_UNSET)"
-%token T_ISSET      "isset (T_ISSET)"
-%token T_EMPTY      "empty (T_EMPTY)"
-%token T_HALT_COMPILER "__halt_compiler (T_HALT_COMPILER)"
-%token T_CLASS      "class (T_CLASS)"
-%token T_TRAIT      "trait (T_TRAIT)"
-%token T_INTERFACE  "interface (T_INTERFACE)"
-%token T_EXTENDS    "extends (T_EXTENDS)"
-%token T_IMPLEMENTS "implements (T_IMPLEMENTS)"
-%token T_OBJECT_OPERATOR "-> (T_OBJECT_OPERATOR)"
-%token T_DOUBLE_ARROW    "=> (T_DOUBLE_ARROW)"
-%token T_LIST            "list (T_LIST)"
-%token T_ARRAY           "array (T_ARRAY)"
-%token T_CALLABLE        "callable (T_CALLABLE)"
-%token T_LINE            "__LINE__ (T_LINE)"
-%token T_FILE            "__FILE__ (T_FILE)"
-%token T_DIR             "__DIR__ (T_DIR)"
-%token T_CLASS_C         "__CLASS__ (T_CLASS_C)"
-%token T_TRAIT_C         "__TRAIT__ (T_TRAIT_C)"
-%token T_METHOD_C        "__METHOD__ (T_METHOD_C)"
-%token T_FUNC_C          "__FUNCTION__ (T_FUNC_C)"
-%token T_COMMENT         "comment (T_COMMENT)"
-%token T_DOC_COMMENT     "doc comment (T_DOC_COMMENT)"
-%token T_OPEN_TAG        "open tag (T_OPEN_TAG)"
-%token T_OPEN_TAG_WITH_ECHO "open tag with echo (T_OPEN_TAG_WITH_ECHO)"
-%token T_CLOSE_TAG       "close tag (T_CLOSE_TAG)"
-%token T_WHITESPACE      "whitespace (T_WHITESPACE)"
-%token T_START_HEREDOC   "heredoc start (T_START_HEREDOC)"
-%token T_END_HEREDOC     "heredoc end (T_END_HEREDOC)"
-%token T_DOLLAR_OPEN_CURLY_BRACES "${ (T_DOLLAR_OPEN_CURLY_BRACES)"
-%token T_CURLY_OPEN      "{$ (T_CURLY_OPEN)"
-%token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)"
-%token T_NAMESPACE       "namespace (T_NAMESPACE)"
-%token T_NS_C            "__NAMESPACE__ (T_NS_C)"
-%token T_NS_SEPARATOR    "\\ (T_NS_SEPARATOR)"
-%token T_ELLIPSIS        "... (T_ELLIPSIS)"
-%token T_COALESCE        "?? (T_COALESCE)"
-%token T_POW             "** (T_POW)"
-%token T_POW_EQUAL       "**= (T_POW_EQUAL)"
-%token T_BAD_CHARACTER   "invalid character (T_BAD_CHARACTER)"
-
-;; Token used to force a parse error from the lexer
-%token T_ERROR
-
-%type <ast> top_statement namespace_name name statement 
function_declaration_statement
-%type <ast> class_declaration_statement trait_declaration_statement
-%type <ast> interface_declaration_statement interface_extends_list
-%type <ast> group_use_declaration inline_use_declarations 
inline_use_declaration
-%type <ast> mixed_group_use_declaration use_declaration 
unprefixed_use_declaration
-%type <ast> unprefixed_use_declarations const_decl inner_statement
-%type <ast> expr optional_expr while_statement for_statement foreach_variable
-%type <ast> foreach_statement declare_statement finally_statement 
unset_variable variable
-%type <ast> extends_from parameter optional_type_without_static argument 
global_var
-%type <ast> static_var class_statement trait_adaptation trait_precedence 
trait_alias
-%type <ast> absolute_trait_method_reference trait_method_reference property 
echo_expr
-%type <ast> new_expr anonymous_class class_name class_name_reference 
simple_variable
-%type <ast> internal_functions_in_yacc
-%type <ast> exit_expr scalar backticks_expr lexical_var function_call 
member_name property_name
-%type <ast> variable_class_name dereferencable_scalar constant class_constant
-%type <ast> fully_dereferencable array_object_dereferencable
-%type <ast> callable_expr callable_variable static_member new_variable
-%type <ast> encaps_var encaps_var_offset isset_variables
-%type <ast> top_statement_list use_declarations const_list 
inner_statement_list if_stmt
-%type <ast> alt_if_stmt for_exprs switch_case_list global_var_list 
static_var_list
-%type <ast> echo_expr_list unset_variables catch_name_list catch_list 
optional_variable parameter_list class_statement_list
-%type <ast> implements_list case_list if_stmt_without_else
-%type <ast> non_empty_parameter_list argument_list non_empty_argument_list 
property_list
-%type <ast> class_const_list class_const_decl class_name_list 
trait_adaptations method_body non_empty_for_exprs
-%type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list 
lexical_vars
-%type <ast> lexical_var_list encaps_list
-%type <ast> array_pair non_empty_array_pair_list array_pair_list 
possible_array_pair
-%type <ast> isset_variable type return_type type_expr type_without_static
-%type <ast> identifier type_expr_without_static union_type_without_static
-%type <ast> inline_function union_type
-
-%type <num> returns_ref function fn is_reference is_variadic variable_modifiers
-%type <num> method_modifiers non_empty_member_modifiers member_modifier
-%type <num> class_modifiers class_modifier use_type backup_fn_flags
-
-%type <ptr> backup_lex_pos
-%type <str> backup_doc_comment
-
-%start start
\ No newline at end of file
diff --git a/admin/phps-mode-automation.el b/admin/phps-mode-automation.el
index d4ff671..39ce0ff 100644
--- a/admin/phps-mode-automation.el
+++ b/admin/phps-mode-automation.el
@@ -1,4 +1,4 @@
-;;; phps-automation --- Generate a Wisent Parser file -*- lexical-binding: t 
-*-
+;;; phps-mode-automation --- Generate a Wisent Parser file -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2018-2021  Free Software Foundation, Inc.
 
@@ -27,61 +27,66 @@
 
 ;;; Code:
 
-(let ((php-yacc-url 
"https://raw.githubusercontent.com/php/php-src/master/Zend/zend_language_parser.y";)
-      (php-yacc-file (expand-file-name "zend_language_parser.y"))
-      (wisent-destination (expand-file-name 
"../phps-mode-parser-grammar-raw.wy"))
-      (header (expand-file-name "phps-mode-automation-header.wy"))
-      (terminal-replacements (make-hash-table :test 'equal)))
-
-  (puthash "'+'" "ADDITION" terminal-replacements)
-  (puthash "'='" "ASSIGN" terminal-replacements)
-  (puthash "'@'" "AT" terminal-replacements)
-  (puthash "'`'" "BACKTICK" terminal-replacements)
-  (puthash "'&'" "BITWISE_AND" terminal-replacements)
-  (puthash "'|'" "BITWISE_OR" terminal-replacements)
-  (puthash "'}'" "CLOSE_CURLY_BRACKET" terminal-replacements)
-  (puthash "')'" "CLOSE_PARENTHESIS" terminal-replacements)
-  (puthash "']'" "CLOSE_SQUARE_BRACKET" terminal-replacements)
-  (puthash "':'" "COLON" terminal-replacements)
-  (puthash "','" "COMMA" terminal-replacements)
-  (puthash "'$'" "DOLLAR_SIGN" terminal-replacements)
-  (puthash "'\"'" "DOUBLE_QUOTE" terminal-replacements)
-  (puthash "'/'" "DIVISION" terminal-replacements)
-  (puthash "'.'" "DOT" terminal-replacements)
-  (puthash "'>'" "GREATER_THAN" terminal-replacements)
-  (puthash "'<'" "LESSER_THAN" terminal-replacements)
-  (puthash "'%'" "MODULO" terminal-replacements)
-  (puthash "'*'" "MULTIPLICATION" terminal-replacements)
-  (puthash "'!'" "NEGATION" terminal-replacements)
-  (puthash "'{'" "OPEN_CURLY_BRACKET" terminal-replacements)
-  (puthash "'('" "OPEN_PARENTHESIS" terminal-replacements)
-  (puthash "'['" "OPEN_SQUARE_BRACKET" terminal-replacements)
-  (puthash "'^'" "POW" terminal-replacements)
-  (puthash "'?'" "QUESTION_MARK" terminal-replacements)
-  (puthash "';'" "SEMICOLON" terminal-replacements)
-  (puthash "'''" "SINGLE_QUOTE" terminal-replacements)
-  (puthash "'-'" "SUBTRACTION" terminal-replacements)
-  (puthash "'~'" "UNARY" terminal-replacements)
-
-  ;; Download Yacc if not available
-  (unless (file-exists-p php-yacc-file)
-    (message "Downloading PHP Yacc grammar..")
-    (url-copy-file php-yacc-url php-yacc-file t t)
-    (message "Download completed"))
-
-  ;; Generate grammar
-  (message "Generating Wisent grammar..")
-  (if (fboundp 'emacs-wisent-grammar-converter--generate-grammar-from-filename)
-      (emacs-wisent-grammar-converter--generate-grammar-from-filename
-       php-yacc-file
-       wisent-destination
-       header
-       "phps-mode-parser--"
-       terminal-replacements)
-    (display-warning
-     'warning
-     "Missing emacs-wisent-grammar-converter!"))
-  (message "Automation completed"))
+(require 'phps-mode-automation-grammar)
+
+(when (fboundp 'parser-generator-lr-export-to-elisp)
+
+  (let ((php-yacc-url 
"https://raw.githubusercontent.com/php/php-src/php-8.0.0/Zend/zend_language_parser.y";)
+        (php-yacc-file (expand-file-name "zend_language_parser.y")))
+
+    ;; Download Yacc if not available
+    (unless (file-exists-p php-yacc-file)
+      (message "Downloading PHP 8.0 YACC grammar..")
+      (url-copy-file php-yacc-url php-yacc-file t t)
+      (message "Download of PHP 8.0 YACC grammar completed"))
+
+    ;; Prepare export
+    (when (fboundp 'parser-generator-set-grammar)
+      (parser-generator-set-grammar
+       `(
+         ,phps-mode-automation-grammar-non-terminals
+         ,phps-mode-automation-grammar-terminals
+         ,phps-mode-automation-grammar-productions
+         ,phps-mode-automation-grammar-start
+         )
+       ))
+    (when (fboundp 'parser-generator-set-look-ahead-number)
+      (parser-generator-set-look-ahead-number
+       phps-mode-automation-grammar-look-ahead-number))
+    (when (boundp 'parser-generator--e-identifier)
+      (setq
+       parser-generator--e-identifier
+       phps-mode-automation-grammar-e-identifier))
+    (when (boundp 'parser-generator--eof-identifier)
+      (setq
+       parser-generator--eof-identifier
+       phps-mode-automation-grammar-eof-identifier))
+    (when (boundp 'parser-generator-lex-analyzer--function)
+      (setq
+       parser-generator-lex-analyzer--function
+       phps-mode-automation-grammar-lex-analyzer-function))
+    (when (boundp 'parser-generator-lex-analyzer--get-function)
+      (setq
+       parser-generator-lex-analyzer--get-function
+       phps-mode-automation-grammar-lex-analyzer-get-function))
+    (when (boundp 'parser-generator-lr--precedence-attribute)
+      (setq
+       parser-generator-lr--precedence-attribute
+       phps-mode-automation-grammar-precendece-attribute))
+    (when (boundp 'parser-generator-lr--precedence-comparison-function)
+      (setq
+       parser-generator-lr--precedence-comparison-function
+       phps-mode-automation-grammar-precedence-comparison-function))
+    (when (fboundp 'parser-generator-process-grammar)
+      (parser-generator-process-grammar))
+    (when (fboundp 'parser-generator-lr-generate-parser-tables)
+      (parser-generator-lr-generate-parser-tables))
+
+    ;; Export
+    (let ((export (parser-generator-lr-export-to-elisp "phps-mode-parser")))
+      (message "export: %s" export))
+
+    (message "Automation completed")))
 
 (provide 'phps-mode-automation)
 ;;; phps-mode-automation.el ends here
diff --git a/phps-mode-lex-analyzer.el b/phps-mode-lex-analyzer.el
index ed66b6d..c340072 100644
--- a/phps-mode-lex-analyzer.el
+++ b/phps-mode-lex-analyzer.el
@@ -578,7 +578,11 @@
 (defun phps-mode-lex-analyzer--move-states (start diff)
   "Move lexer states after (or equal to) START with modification DIFF."
   (when phps-mode-lex-analyzer--states
-    (setq phps-mode-lex-analyzer--states 
(phps-mode-lex-analyzer--get-moved-states phps-mode-lex-analyzer--states start 
diff))))
+    (setq phps-mode-lex-analyzer--states
+          (phps-mode-lex-analyzer--get-moved-states
+           phps-mode-lex-analyzer--states
+           start
+           diff))))
 
 (defun phps-mode-lex-analyzer--get-moved-states (states start diff)
   "Return moved lexer STATES after (or equal to) START with modification DIFF."
@@ -591,16 +595,38 @@
         (let ((state-start (nth 0 state-object))
               (state-end (nth 1 state-object))
               (state-symbol (nth 2 state-object))
-              (state-stack (nth 3 state-object)))
+              (state-stack (nth 3 state-object))
+              (heredoc-label (nth 4 state-object))
+              (heredoc-label-stack (nth 5 state-object))
+              (nest-location-stack (nth 6 state-object)))
           (if (>= state-start start)
               (let ((new-state-start (+ state-start diff))
                     (new-state-end (+ state-end diff)))
-                (push (list new-state-start new-state-end state-symbol 
state-stack) new-states))
+                (push
+                 (list
+                  new-state-start
+                  new-state-end
+                  state-symbol
+                  state-stack
+                  heredoc-label
+                  heredoc-label-stack
+                  nest-location-stack)
+                 new-states))
             (if (> state-end start)
                 (let ((new-state-end (+ state-end diff)))
-                  (push (list state-start new-state-end state-symbol 
state-stack) new-states))
-              (push state-object new-states))))))
-
+                  (push
+                   (list
+                    state-start
+                    new-state-end
+                    state-symbol
+                    state-stack
+                    heredoc-label
+                    heredoc-label-stack
+                    nest-location-stack)
+                   new-states))
+              (push
+               state-object
+               new-states))))))
     new-states))
 
 (defun phps-mode-lex-analyzer--move-tokens (start diff)
diff --git a/phps-mode-lexer.el b/phps-mode-lexer.el
index 358d8b3..46bbc73 100644
--- a/phps-mode-lexer.el
+++ b/phps-mode-lexer.el
@@ -117,6 +117,9 @@
 (defvar-local phps-mode-lexer--generated-tokens nil
   "List of current generated tokens.")
 
+(defvar-local phps-mode-lexer--generated-new-tokens nil
+  "List of current newly generated tokens.")
+
 (defvar-local phps-mode-lexer--state nil
   "Current state of lexer.")
 
@@ -218,7 +221,7 @@
     "Entered nesting '%s'"
     opening))
   (push
-   opening
+   `(,opening ,(point))
    phps-mode-lexer--nest-location-stack))
 
 (defun phps-mode-lexer--handle-newline ()
@@ -240,16 +243,21 @@
     (when (and
            opening
            (or
-            (and (string= opening "{")
+            (and (string= (car opening) "{")
                  (not (string= closing "}")))
-            (and (string= opening "[")
+            (and (string= (car opening) "[")
                  (not (string= closing "]")))
-            (and (string= opening "(")
+            (and (string= (car opening) "(")
                  (not (string= closing ")")))))
       (signal
        'phps-lexer-error
        (list
-        (format "Bad nesting '%s' vs '%s' at %d'" opening closing (point))
+        (format
+         "Bad nesting '%s' started at '%s' vs '%s' at %d'"
+         (car opening)
+         (car (cdr opening))
+         closing
+         (point))
         (point))))
     (phps-mode-debug-message
      (message
@@ -271,6 +279,7 @@
 
   (semantic-lex-push-token (semantic-lex-token token start end))
   (push `(,token ,start . ,end) phps-mode-lexer--generated-tokens)
+  (push `(,token ,start . ,end) phps-mode-lexer--generated-new-tokens)
 
   (phps-mode-debug-message
    (message
@@ -461,6 +470,7 @@
 (defun phps-mode-lexer--re2c ()
   "Elisp port of original Zend re2c lexer."
 
+  (setq phps-mode-lexer--generated-new-tokens nil)
   (setq phps-mode-lexer--restart-flag nil)
   (let ((old-start (point)))
     (phps-mode-debug-message
diff --git a/phps-mode.el b/phps-mode.el
index cbab269..e401459 100644
--- a/phps-mode.el
+++ b/phps-mode.el
@@ -5,8 +5,8 @@
 ;; Author: Christian Johansson <christian@cvj.se>
 ;; Maintainer: Christian Johansson <christian@cvj.se>
 ;; Created: 3 Mar 2018
-;; Modified: 29 Jan 2021
-;; Version: 0.4.1
+;; Modified: 10 Mars 2021
+;; Version: 0.4.2
 ;; Keywords: tools, convenience
 ;; URL: https://github.com/cjohansson/emacs-phps-mode
 
diff --git a/test/phps-mode-test-integration.el 
b/test/phps-mode-test-integration.el
index 0a8e90e..214882f 100644
--- a/test/phps-mode-test-integration.el
+++ b/test/phps-mode-test-integration.el
@@ -169,155 +169,26 @@
    (goto-char 88)
    (delete-char 1))
 
-  )
-
-(defun phps-mode-test-integration--whitespace-modifications ()
-  "Test white-space modifications functions."
-
-  (phps-mode-test--with-buffer
-   "<?php\n$var = 'abc';\n\n$var2 = '123';\n"
-   "Add newline between two assignments and inspect moved tokens and states"
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-
-   ;; Initial state
-
-   ;; Tokens
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_VARIABLE 7 . 11) ("=" 12 . 13) 
(T_CONSTANT_ENCAPSED_STRING 14 . 19) (";" 19 . 20) (T_VARIABLE 22 . 27) ("=" 28 
. 29) (T_CONSTANT_ENCAPSED_STRING 30 . 35) (";" 35 . 36))))
-
-   ;; States
-   (should (equal phps-mode-lex-analyzer--states
-                  '((35 36 1 nil) (30 35 1 nil) (28 29 1 nil) (22 27 1 nil) 
(19 20 1 nil) (14 19 1 nil) (12 13 1 nil) (7 11 1 nil) (1 7 1 nil))))
-   
-   ;; Insert newline
-   (goto-char 21)
-   (newline)
-
-   ;; Final state
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-   (phps-mode-lex-analyzer--process-changes)
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-
-   ;; Tokens
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_VARIABLE 7 . 11) ("=" 12 . 13) 
(T_CONSTANT_ENCAPSED_STRING 14 . 19) (";" 19 . 20) (T_VARIABLE 23 . 28) ("=" 29 
. 30) (T_CONSTANT_ENCAPSED_STRING 31 . 36) (";" 36 . 37))))
-
-   ;; States
-   (should (equal phps-mode-lex-analyzer--states
-                  '((36 37 1 nil) (31 36 1 nil) (29 30 1 nil) (23 28 1 nil) 
(19 20 1 nil) (14 19 1 nil) (12 13 1 nil) (7 11 1 nil) (1 7 1 nil)))))
-
-  (phps-mode-test--with-buffer
-   "<?php\n$var = 'abc';\n\n$var2 = '123';\n"
-   "Delete backward char between two assignments and inspect moved tokens and 
states"
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-
-   ;; Initial state
-
-   ;; Tokens
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_VARIABLE 7 . 11) ("=" 12 . 13) 
(T_CONSTANT_ENCAPSED_STRING 14 . 19) (";" 19 . 20) (T_VARIABLE 22 . 27) ("=" 28 
. 29) (T_CONSTANT_ENCAPSED_STRING 30 . 35) (";" 35 . 36))))
-
-   ;; States
-   (should (equal phps-mode-lex-analyzer--states
-                  '((35 36 1 nil) (30 35 1 nil) (28 29 1 nil) (22 27 1 nil) 
(19 20 1 nil) (14 19 1 nil) (12 13 1 nil) (7 11 1 nil) (1 7 1 nil))))
-
-   ;; Insert newline
-   (goto-char 21)
-   (delete-char 1)
-
-   (phps-mode-lex-analyzer--process-changes)
-
-   ;; Final state
-   ;; (message "Modified buffer: '%s'" (buffer-substring-no-properties 
(point-min) (point-max)))
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-
-   ;; Tokens
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_VARIABLE 7 . 11) ("=" 12 . 13) 
(T_CONSTANT_ENCAPSED_STRING 14 . 19) (";" 19 . 20) (T_VARIABLE 21 . 26) ("=" 27 
. 28) (T_CONSTANT_ENCAPSED_STRING 29 . 34) (";" 34 . 35))))
-
-   ;; States
-   (should (equal phps-mode-lex-analyzer--states
-                  '((34 35 1 nil) (29 34 1 nil) (27 28 1 nil) (21 26 1 nil) 
(19 20 1 nil) (14 19 1 nil) (12 13 1 nil) (7 11 1 nil) (1 7 1 nil)))))
-
-  (phps-mode-test--with-buffer
-   "<?php\nif (true):\n    $var = 'abc';\n    $var2 = '123';\nendif;\n"
-   "Add newline inside if body after two assignments and inspect moved tokens 
and states"
-
-   ;; Initial state
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_IF 7 . 9) ("(" 10 . 11) (T_STRING 11 
. 15) (")" 15 . 16) (":" 16 . 17) (T_VARIABLE 22 . 26) ("=" 27 . 28) 
(T_CONSTANT_ENCAPSED_STRING 29 . 34) (";" 34 . 35) (T_VARIABLE 40 . 45) ("=" 46 
. 47) (T_CONSTANT_ENCAPSED_STRING 48 . 53) (";" 53 . 54) (T_ENDIF 55 . 60) (";" 
60 . 61))))
-
-   (should (equal phps-mode-lex-analyzer--states
-                  '((60 61 1 nil) (55 60 1 nil) (53 54 1 nil) (48 53 1 nil) 
(46 47 1 nil) (40 45 1 nil) (34 35 1 nil) (29 34 1 nil) (27 28 1 nil) (22 26 1 
nil) (16 17 1 nil) (15 16 1 nil) (11 15 1 nil) (10 11 1 nil) (7 9 1 nil) (1 7 1 
nil))))
-
-   ;; Insert newline and then indent
-   (goto-char 54)
-   (newline-and-indent)
-
-   (phps-mode-lex-analyzer--process-changes)
-
-   ;; Final state
-   ;; (message "Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "States: %s" phps-mode-lex-analyzer--states)
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_IF 7 . 9) ("(" 10 . 11) (T_STRING 11 
. 15) (")" 15 . 16) (":" 16 . 17) (T_VARIABLE 22 . 26) ("=" 27 . 28) 
(T_CONSTANT_ENCAPSED_STRING 29 . 34) (";" 34 . 35) (T_VARIABLE 40 . 45) ("=" 46 
. 47) (T_CONSTANT_ENCAPSED_STRING 48 . 53) (";" 53 . 54) (T_ENDIF 60 . 65) (";" 
65 . 66))))
-
-   (should (equal phps-mode-lex-analyzer--states
-                  '((65 66 1 nil) (60 65 1 nil) (53 54 1 nil) (48 53 1 nil) 
(46 47 1 nil) (40 45 1 nil) (34 35 1 nil) (29 34 1 nil) (27 28 1 nil) (22 26 1 
nil) (16 17 1 nil) (15 16 1 nil) (11 15 1 nil) (10 11 1 nil) (7 9 1 nil) (1 7 1 
nil)))))
-
-  (phps-mode-test--with-buffer
-   "<?php\nif (true):\n    $var = \"abc\nanother line here\nmore text 
here\";\n    $var2 = '123';\nendif;"
-   "Add test for inserting newlines inside token"
-
-   ;; (message "Before Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "Before States: %s" phps-mode-lex-analyzer--states)
-
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_IF 7 . 9) ("(" 10 . 11) (T_STRING 11 
. 15) (")" 15 . 16) (":" 16 . 17) (T_VARIABLE 22 . 26) ("=" 27 . 28) 
(T_CONSTANT_ENCAPSED_STRING 29 . 67) (";" 67 . 68) (T_VARIABLE 73 . 78) ("=" 79 
. 80) (T_CONSTANT_ENCAPSED_STRING 81 . 86) (";" 86 . 87) (T_ENDIF 88 . 93) (";" 
93 . 94))))
-   (should (equal phps-mode-lex-analyzer--states
-                  '((93 94 1 nil) (88 93 1 nil) (86 87 1 nil) (81 86 1 nil) 
(79 80 1 nil) (73 78 1 nil) (67 68 1 nil) (29 67 1 nil) (27 28 1 nil) (22 26 1 
nil) (16 17 1 nil) (15 16 1 nil) (11 15 1 nil) (10 11 1 nil) (7 9 1 nil) (1 7 1 
nil))))
-
-   ;; Insert newline and then indent
-   (goto-char 51)
-   (newline-and-indent)
-
-   (phps-mode-lex-analyzer--process-changes)
-
-   ;; (message "After Tokens %s" phps-mode-lex-analyzer--tokens)
-   ;; (message "After States: %s" phps-mode-lex-analyzer--states)
-   (should (equal phps-mode-lex-analyzer--tokens
-                  '((T_OPEN_TAG 1 . 7) (T_IF 7 . 9) ("(" 10 . 11) (T_STRING 11 
. 15) (")" 15 . 16) (":" 16 . 17) (T_VARIABLE 22 . 26) ("=" 27 . 28) 
(T_CONSTANT_ENCAPSED_STRING 29 . 76) (";" 76 . 77) (T_VARIABLE 82 . 87) ("=" 88 
. 89) (T_CONSTANT_ENCAPSED_STRING 90 . 95) (";" 95 . 96) (T_ENDIF 97 . 102) 
(";" 102 . 103))))
-   (should (equal phps-mode-lex-analyzer--states
-                  '((102 103 1 nil) (97 102 1 nil) (95 96 1 nil) (90 95 1 nil) 
(88 89 1 nil) (82 87 1 nil) (76 77 1 nil) (29 76 1 nil) (27 28 1 nil) (22 26 1 
nil) (16 17 1 nil) (15 16 1 nil) (11 15 1 nil) (10 11 1 nil) (7 9 1 nil) (1 7 1 
nil)))))
-
-  (phps-mode-test--with-buffer
-   "<?php\nfunction myFunctionA() {}\nfunction myFunctionB() {}\n"
-   "White-space changes in imenu function-oriented file"
-
-   (should (equal (phps-mode-lex-analyzer--get-imenu) '(("myFunctionA" . 16) 
("myFunctionB" . 42))))
-
-   (goto-char 32)
-   (newline-and-indent)
-
-   (phps-mode-lex-analyzer--process-changes)
+  (phps-mode-test--incremental-vs-intial-buffer
+   "<?php\n\nif (\n    true\n    && false\n) {\n    echo 'My long string 
here';\n    if (\nfalse\n        || true\n    ) {\n        echo 'Two lines 
of'\n            . 'strings here';\n    }\n}"
+   "Integration-test 15 white-space changes to see if nesting is maintained."
+   (goto-char 80)
+   (execute-kbd-macro (kbd "<tab>")))
 
-   (should (equal (phps-mode-lex-analyzer--get-imenu) '(("myFunctionA" . 16) 
("myFunctionB" . 43)))))
+  (phps-mode-test--incremental-vs-intial-buffer
+   "<?php\n\nif (\n    true\n    && false\n) {\n    echo 'My long string 
here';\n    if (\nfalse\n        || true\n    ) {\n        echo 'Two lines 
of'\n            . 'strings here';\n    }\n}"
+   "Integration-test 16 white-space changes to see if nesting is maintained."
+   (goto-char 80)
+   (execute-kbd-macro (kbd "<tab>"))
+   (goto-char 117)
+   (execute-kbd-macro (kbd "<return>")))
 
   )
 
 (defun phps-mode-test-integration ()
   "Run test for integration."
   ;; (setq debug-on-error t)
-  ;; (setq phps-mode-analyzer--process-on-indent-and-imenu t)
   (phps-mode-test-integration--incremental-vs-initial-buffers)
-  ;; (phps-mode-test-integration--whitespace-modifications)
   )
 
 (phps-mode-test-integration)
diff --git a/test/phps-mode-test-lexer.el b/test/phps-mode-test-lexer.el
index 8c6b635..2254bdc 100644
--- a/test/phps-mode-test-lexer.el
+++ b/test/phps-mode-test-lexer.el
@@ -604,53 +604,53 @@
 
   (should
    (equal
-    '((68 76 1 '(1))
-      (10 67 1 '(1))
-      (1 9 1 '(1)))
+    '((68 76 1 '(1) nil nil nil)
+      (10 67 1 '(1) nil nil nil)
+      (1 9 1 '(1) nil nil nil))
 
     (phps-mode-lex-analyzer--get-moved-states
-     '((66 74 1 '(1))
-       (8 65 1 '(1))
-       (1 7 1 '(1)))
+     '((66 74 1 '(1) nil nil nil)
+       (8 65 1 '(1) nil nil nil)
+       (1 7 1 '(1) nil nil nil))
      6
      2)))
 
   (should
    (equal
-    '((67 75 1 '(1))
-      (9 66 1 '(1))
-      (2 8 1 '(1)))
+    '((67 75 1 '(1) nil nil nil)
+      (9 66 1 '(1) nil nil nil)
+      (2 8 1 '(1) nil nil nil))
     
     (phps-mode-lex-analyzer--get-moved-states
-     '((66 74 1 '(1))
-       (8 65 1 '(1))
-       (1 7 1 '(1)))
+     '((66 74 1 '(1) nil nil nil)
+       (8 65 1 '(1) nil nil nil)
+       (1 7 1 '(1) nil nil nil))
      0
      1)))
 
   (should
    (equal
-    '((66 74 1 '(1))
-      (8 65 1 '(1))
-      (1 7 1 '(1)))
+    '((66 74 1 '(1) nil nil nil)
+      (8 65 1 '(1) nil nil nil)
+      (1 7 1 '(1) nil nil nil))
     
     (phps-mode-lex-analyzer--get-moved-states
-     '((66 74 1 '(1))
-       (8 65 1 '(1))
-       (1 7 1 '(1)))
+     '((66 74 1 '(1) nil nil nil)
+       (8 65 1 '(1) nil nil nil)
+       (1 7 1 '(1) nil nil nil))
      100
      1)))
 
   (should
    (equal
-    '((64 72 1 '(1))
-      (6 63 1 '(1))
-      (1 7 1 '(1)))
+    '((64 72 1 '(1) nil nil nil)
+      (6 63 1 '(1) nil nil nil)
+      (1 7 1 '(1) nil nil nil))
     
     (phps-mode-lex-analyzer--get-moved-states
-     '((66 74 1 '(1))
-       (8 65 1 '(1))
-       (3 9 1 '(1)))
+     '((66 74 1 '(1) nil nil nil)
+       (8 65 1 '(1) nil nil nil)
+       (3 9 1 '(1) nil nil nil))
      3
      -2))))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]