[vala/staging] Add CodeTransformer and an implementation stub, CCodeTransformer



commit 7c6e22800698ca74808fbbb8af76068069d093c3
Author: Luca Bruno <lucabru src gnome org>
Date:   Sun Aug 7 12:22:15 2011 +0200

    Add CodeTransformer and an implementation stub, CCodeTransformer

 codegen/Makefile.am               |   1 +
 codegen/valaccodetransformer.vala |  71 +++++
 compiler/valacompiler.vala        |   7 +
 vala/Makefile.am                  |   1 +
 vala/valacodebuilder.vala         |  17 +-
 vala/valacodetransformer.vala     | 552 ++++++++++++++++++++++++++++++++++++++
 vala/valasemanticanalyzer.vala    |  16 --
 7 files changed, 647 insertions(+), 18 deletions(-)
---
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index 036652ef3..0d94dd737 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -35,6 +35,7 @@ libvalaccodegen_la_VALASOURCES = \
        valaccodemethodcallmodule.vala \
        valaccodemethodmodule.vala \
        valaccodestructmodule.vala \
+       valaccodetransformer.vala \
        valaclassregisterfunction.vala \
        valactype.vala \
        valaenumregisterfunction.vala \
diff --git a/codegen/valaccodetransformer.vala b/codegen/valaccodetransformer.vala
new file mode 100644
index 000000000..3599fc3c8
--- /dev/null
+++ b/codegen/valaccodetransformer.vala
@@ -0,0 +1,71 @@
+/* valaccodetransformer.vala
+ *
+ * Copyright (C) 2012  Luca Bruno
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library 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
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Luca Bruno <lucabru src gnome org>
+ */
+
+/**
+ * Code visitor for simplyfing the code tree for the C codegen.
+ */
+public class Vala.CCodeTransformer : CodeTransformer {
+       public override void visit_constant (Constant c) {
+               c.active = true;
+               c.accept_children (this);
+       }
+
+       public override void visit_method (Method m) {
+               if (m.body == null) {
+                       return;
+               }
+
+               m.accept_children (this);
+       }
+
+       public override void visit_creation_method (CreationMethod m) {
+               if (m.body == null) {
+                       return;
+               }
+
+               m.accept_children (this);
+       }
+
+       public override void visit_block (Block b) {
+               b.accept_children (this);
+
+               foreach (LocalVariable local in b.get_local_variables ()) {
+                       local.active = false;
+               }
+               foreach (Constant constant in b.get_local_constants ()) {
+                       constant.active = false;
+               }
+       }
+
+       public override void visit_local_variable (LocalVariable local) {
+               local.active = true;
+               local.accept_children (this);
+       }
+
+       public override void visit_expression (Expression expr) {
+               if (expr in context.analyzer.replaced_nodes) {
+                       return;
+               }
+
+               base.visit_expression (expr);
+       }
+}
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index 7394e45da..96d1ba3ab 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -403,6 +403,13 @@ class Vala.Compiler {
                        }
                }
 
+               var transformer = new CCodeTransformer ();
+               transformer.transform (context);
+
+               if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 
0)) {
+                       return quit ();
+               }
+
                if (dump_tree != null) {
                        var code_writer = new CodeWriter (CodeWriterType.DUMP);
                        code_writer.write_file (context, dump_tree);
diff --git a/vala/Makefile.am b/vala/Makefile.am
index c4b8bce46..d341e7659 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -52,6 +52,7 @@ libvala_la_VALASOURCES = \
        valacodecontext.vala \
        valacodegenerator.vala \
        valacodenode.vala \
+       valacodetransformer.vala \
        valacodevisitor.vala \
        valacodewriter.vala \
        valacomment.vala \
diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala
index 17e5a913d..cedac79f1 100644
--- a/vala/valacodebuilder.vala
+++ b/vala/valacodebuilder.vala
@@ -99,6 +99,16 @@ public class Vala.CodeBuilder {
                statement_stack.add (stmt);
        }
 
+       public void open_loop () {
+               statement_stack.add (current_block);
+               var parent_block = current_block;
+
+               current_block = new Block (source_reference);
+
+               var stmt = new Loop (current_block, source_reference);
+               parent_block.add_statement (stmt);
+       }
+
        public void open_while (Expression condition) {
                statement_stack.add (current_block);
                var parent_block = current_block;
@@ -233,9 +243,8 @@ public class Vala.CodeBuilder {
                add_statement (new ContinueStatement (source_reference));
        }
 
-       public string add_temp_declaration (DataType? type, Expression? initializer = null, bool floating = 
false) {
+       public string add_temp_declaration (DataType? type, Expression? initializer = null) {
                var local = new LocalVariable (type, CodeNode.get_temp_name (), initializer, 
source_reference);
-               // FIXME: use create_temp_access behavior
                var stmt = new DeclarationStatement (local, source_reference);
                insert_block.insert_before (insert_statement, stmt);
                check_nodes.insert (0, stmt);
@@ -256,6 +265,10 @@ public class Vala.CodeBuilder {
                return new Parser().parse_expression_string (str, source_reference);
        }
 
+       public void statements (string str) {
+               new Parser().parse_statements_string (str, current_block, source_reference);
+       }
+
        // only qualified types, will slightly simplify the work of SymbolResolver
        public static Symbol? symbol_from_string (string symbol_string, Symbol? parent_symbol = null) {
                Symbol sym = parent_symbol != null ? parent_symbol : CodeContext.get().root;
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
new file mode 100644
index 000000000..66ab12c41
--- /dev/null
+++ b/vala/valacodetransformer.vala
@@ -0,0 +1,552 @@
+/* valacodetransformer.vala
+ *
+ * Copyright (C) 2011  Luca Bruno
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library 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
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Luca Bruno <lucabru src gnome org>
+ */
+
+/**
+ * Code visitor for transforming the code tree.
+ */
+public class Vala.CodeTransformer : CodeVisitor {
+       public weak CodeContext context { get; private set; }
+
+       public CodeBuilder b { get; private set; }
+
+       ArrayList<CodeBuilder> builder_stack = new ArrayList<CodeBuilder> ();
+       Map<weak CodeBuilder, void*> builder_data = new HashMap<weak CodeBuilder, void*> ();
+       Map<string, CodeNode> wrapper_cache;
+
+       // Keep tracks of generated and visited stuff to avoid cycles
+       Set<CodeNode> unit_generated = new HashSet<CodeNode> ();
+       Set<weak CodeNode> visited = new HashSet<weak CodeNode> ();
+
+       public void push_builder (CodeBuilder builder) {
+               builder_stack.add (b);
+               b = builder;
+       }
+
+       public void pop_builder () {
+               b = builder_stack.remove_at (builder_stack.size - 1);
+       }
+
+       class ReplaceStatementData {
+               public Statement stmt;
+               public Block parent_block;
+       }
+
+       public void begin_replace_statement (Statement stmt) {
+               push_builder (new CodeBuilder (context, stmt, stmt.source_reference));
+
+               var data = new ReplaceStatementData ();
+               data.stmt = stmt;
+               data.parent_block = context.analyzer.get_current_block (stmt);
+               builder_data.set (b, (void*) (owned) data);
+       }
+
+       public void end_replace_statement () {
+               var data = (ReplaceStatementData) builder_data.get (b);
+               builder_data.remove (b);
+
+               context.analyzer.replaced_nodes.add (data.stmt);
+               data.parent_block.replace_statement (data.stmt, new EmptyStatement 
(data.stmt.source_reference));
+
+               b.check (this);
+               pop_builder ();
+       }
+
+       class ReplaceExpressionData {
+               public Expression expr;
+               public CodeNode parent_node;
+       }
+
+       public void begin_replace_expression (owned Expression expr) {
+               push_builder (new CodeBuilder (context, expr.parent_statement, expr.source_reference));
+
+               var data = new ReplaceExpressionData ();
+               data.expr = expr;
+               data.parent_node = expr.parent_node;
+               builder_data.set (b, (void*) (owned) data);
+       }
+
+       public void end_replace_expression (Expression? replacement) {
+               var data = (ReplaceExpressionData) builder_data.get (b);
+               builder_data.remove (b);
+
+               if (replacement != null) {
+                       context.analyzer.replaced_nodes.add (data.expr);
+                       data.parent_node.replace_expression (data.expr, replacement);
+                       b.check (this);
+               }
+               pop_builder ();
+               if (replacement != null) {
+                       check (replacement);
+               }
+       }
+
+       /**
+        * Transform the code tree for the specified code context.
+        *
+        * @param context a code context
+        */
+       public void transform (CodeContext context) {
+               this.context = context;
+
+               /* we're only interested in non-pkg source files */
+               var source_files = context.get_source_files ();
+               foreach (SourceFile file in source_files) {
+                       /* clear wrapper cache for every file */
+                       wrapper_cache = new HashMap<string, CodeNode> (str_hash, str_equal);
+                       file.accept (this);
+               }
+
+               this.context = null;
+       }
+
+       public static DataType? copy_type (DataType? type, bool? value_owned = null, bool? nullable = null) {
+               if (type == null) {
+                       return null;
+               }
+
+               var ret = type.copy ();
+               if (value_owned != null) {
+                       ret.value_owned = value_owned;
+               }
+               if (nullable != null) {
+                       ret.nullable = nullable;
+               }
+               return ret;
+       }
+
+       // Create an access to a temporary variable, with proper reference transfer if needed to avoid 
unnecessary copies
+       public Expression return_temp_access (string local, DataType value_type, DataType? target_type, 
DataType? formal_target_type = null) {
+               Expression temp_access = new MemberAccess.simple (local, b.source_reference);
+
+               var target_owned = target_type != null && target_type.value_owned;
+               if (target_owned && value_type.is_disposable ()) {
+                       temp_access = new ReferenceTransferExpression (temp_access, b.source_reference);
+                       temp_access.target_type = target_type != null ? target_type.copy () : value_type.copy 
();
+                       temp_access.target_type.value_owned = true;
+                       temp_access.formal_target_type = copy_type (formal_target_type);
+               } else {
+                       temp_access.target_type = copy_type (target_type);
+               }
+
+               return temp_access;
+       }
+
+       public bool get_cached_wrapper (string key, out CodeNode node) {
+               node = wrapper_cache.get (key);
+               return node != null;
+       }
+
+       public void add_cached_wrapper (string key, CodeNode node) {
+               wrapper_cache.set (key, node);
+       }
+
+       public string temp_func_cname () {
+               return "_vala_func_"+CodeNode.get_temp_name ().substring (1);
+       }
+
+       public bool wrapper_method (DataType return_type, string? cache_key, out Method m, Symbol? parent = 
null) {
+               CodeNode n = null;
+               if (cache_key != null && get_cached_wrapper (cache_key, out n)) {
+                       m = (Method) n;
+                       return true;
+               }
+               m = new Method (temp_func_cname (), return_type, b.source_reference);
+               (parent == null ? context.root : parent).add_method (m);
+               m.access = SymbolAccessibility.PRIVATE;
+               add_cached_wrapper (cache_key, m);
+               return false;
+       }
+
+       public Symbol symbol_from_string (string s) {
+               return CodeBuilder.symbol_from_string (s);
+       }
+
+       public DataType data_type (string s, bool value_owned = true, bool nullable = false) {
+               return CodeBuilder.data_type (s, value_owned, nullable);
+       }
+
+       public Expression expression (string str) {
+               return b.expression (str);
+       }
+
+       public void statements (string str) {
+               b.statements (str);
+       }
+
+       public void check (CodeNode node) {
+               node.accept (context.resolver);
+               if (!node.check (context)) {
+                       return;
+               }
+               node.accept (this);
+       }
+
+       public bool is_visited (CodeNode node) {
+               var file = node.source_reference.file;
+               return file.file_type == SourceFileType.SOURCE || (context.header_filename != null && 
file.file_type == SourceFileType.FAST);
+       }
+
+       public void accept_external (CodeNode node) {
+               if (node.source_reference != null) {
+                       if (!is_visited (node) && !unit_generated.contains (node)) {
+                               unit_generated.add (node);
+                               check (node);
+                       }
+               }
+       }
+
+       public bool always_true (Expression condition) {
+               var literal = condition as BooleanLiteral;
+               return (literal != null && literal.value);
+       }
+
+       public bool always_false (Expression condition) {
+               var literal = condition as BooleanLiteral;
+               return (literal != null && !literal.value);
+       }
+
+       public override void visit_addressof_expression (Vala.AddressofExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_array_creation_expression (Vala.ArrayCreationExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_assignment (Vala.Assignment a) {
+               a.accept_children (this);
+       }
+
+       public override void visit_base_access (Vala.BaseAccess expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_binary_expression (Vala.BinaryExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_block (Vala.Block b) {
+               b.accept_children (this);
+       }
+
+       public override void visit_boolean_literal (Vala.BooleanLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_break_statement (Vala.BreakStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_cast_expression (Vala.CastExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_catch_clause (Vala.CatchClause clause) {
+               clause.accept_children (this);
+       }
+
+       public override void visit_character_literal (Vala.CharacterLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_class (Vala.Class cl) {
+               cl.accept_children (this);
+       }
+
+       public override void visit_conditional_expression (Vala.ConditionalExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_constant (Vala.Constant c) {
+               c.accept_children (this);
+       }
+
+       public override void visit_constructor (Vala.Constructor c) {
+               c.accept_children (this);
+       }
+
+       public override void visit_continue_statement (Vala.ContinueStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_creation_method (Vala.CreationMethod m) {
+               m.accept_children (this);
+       }
+
+       public override void visit_data_type (Vala.DataType type) {
+               type.accept_children (this);
+       }
+
+       public override void visit_declaration_statement (Vala.DeclarationStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_delegate (Vala.Delegate d) {
+               d.accept_children (this);
+       }
+
+       public override void visit_delete_statement (Vala.DeleteStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_destructor (Vala.Destructor d) {
+               d.accept_children (this);
+       }
+
+       public override void visit_do_statement (Vala.DoStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_element_access (Vala.ElementAccess expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_empty_statement (Vala.EmptyStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_end_full_expression (Vala.Expression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_enum (Vala.Enum en) {
+               en.accept_children (this);
+       }
+
+       public override void visit_enum_value (Vala.EnumValue ev) {
+               ev.accept_children (this);
+       }
+
+       public override void visit_error_code (Vala.ErrorCode ecode) {
+               ecode.accept_children (this);
+       }
+
+       public override void visit_error_domain (Vala.ErrorDomain edomain) {
+               edomain.accept_children (this);
+       }
+
+       public override void visit_expression (Vala.Expression expr) {
+               if (expr in visited) {
+                       return;
+               }
+               visited.add (expr);
+
+               expr.accept_children (this);
+       }
+
+       public override void visit_expression_statement (Vala.ExpressionStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_field (Vala.Field f) {
+               f.accept_children (this);
+       }
+
+       public override void visit_for_statement (Vala.ForStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_foreach_statement (Vala.ForeachStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_formal_parameter (Vala.Parameter p) {
+               p.accept_children (this);
+       }
+
+       public override void visit_if_statement (Vala.IfStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_initializer_list (Vala.InitializerList list) {
+               list.accept_children (this);
+       }
+
+       public override void visit_integer_literal (Vala.IntegerLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_interface (Vala.Interface iface) {
+               iface.accept_children (this);
+       }
+
+       public override void visit_lambda_expression (Vala.LambdaExpression expr) {
+               if (expr in visited) {
+                       return;
+               }
+               visited.add (expr);
+
+               expr.accept_children (this);
+       }
+
+       public override void visit_local_variable (Vala.LocalVariable local) {
+               local.accept_children (this);
+       }
+
+       public override void visit_lock_statement (Vala.LockStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_loop (Vala.Loop stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_member_access (Vala.MemberAccess expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_method (Vala.Method m) {
+               m.accept_children (this);
+       }
+
+       public override void visit_method_call (Vala.MethodCall expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_named_argument (Vala.NamedArgument expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_namespace (Vala.Namespace ns) {
+               ns.accept_children (this);
+       }
+
+       public override void visit_null_literal (Vala.NullLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_object_creation_expression (Vala.ObjectCreationExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_pointer_indirection (Vala.PointerIndirection expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_postfix_expression (Vala.PostfixExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_property (Vala.Property prop) {
+               prop.accept_children (this);
+       }
+
+       public override void visit_property_accessor (Vala.PropertyAccessor acc) {
+               acc.accept_children (this);
+       }
+
+       public override void visit_real_literal (Vala.RealLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_reference_transfer_expression (Vala.ReferenceTransferExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_regex_literal (Vala.RegexLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_return_statement (Vala.ReturnStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_signal (Vala.Signal sig) {
+               sig.accept_children (this);
+       }
+
+       public override void visit_sizeof_expression (Vala.SizeofExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_slice_expression (Vala.SliceExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_source_file (Vala.SourceFile source_file) {
+               source_file.accept_children (this);
+       }
+
+       public override void visit_string_literal (Vala.StringLiteral lit) {
+               lit.accept_children (this);
+       }
+
+       public override void visit_struct (Vala.Struct st) {
+               st.accept_children (this);
+       }
+
+       public override void visit_switch_label (Vala.SwitchLabel label) {
+               label.accept_children (this);
+       }
+
+       public override void visit_switch_section (Vala.SwitchSection section) {
+               section.accept_children (this);
+       }
+
+       public override void visit_switch_statement (Vala.SwitchStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_template (Vala.Template tmpl) {
+               tmpl.accept_children (this);
+       }
+
+       public override void visit_throw_statement (Vala.ThrowStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_try_statement (Vala.TryStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_tuple (Vala.Tuple tuple) {
+               tuple.accept_children (this);
+       }
+
+       public override void visit_type_check (Vala.TypeCheck expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_type_parameter (Vala.TypeParameter p) {
+               p.accept_children (this);
+       }
+
+       public override void visit_typeof_expression (Vala.TypeofExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_unary_expression (Vala.UnaryExpression expr) {
+               expr.accept_children (this);
+       }
+
+       public override void visit_unlock_statement (Vala.UnlockStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_while_statement (Vala.WhileStatement stmt) {
+               stmt.accept_children (this);
+       }
+
+       public override void visit_yield_statement (Vala.YieldStatement y) {
+               y.accept_children (this);
+       }
+}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 1f4df2cb8..03281b499 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -943,22 +943,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                return false;
        }
 
-       // Create an access to a temporary variable, with proper reference transfer if needed
-       public static Expression create_temp_access (LocalVariable local, DataType? target_type) {
-               Expression temp_access = new MemberAccess.simple (local.name, local.source_reference);
-
-               var target_owned = target_type != null && target_type.value_owned;
-               if (target_owned && local.variable_type.is_disposable ()) {
-                       temp_access = new ReferenceTransferExpression (temp_access, local.source_reference);
-                       temp_access.target_type = target_type != null ? target_type.copy () : 
local.variable_type.copy ();
-                       temp_access.target_type.value_owned = true;
-               } else {
-                       temp_access.target_type = target_type != null ? target_type.copy () : null;
-               }
-
-               return temp_access;
-       }
-
        public void visit_member_initializer (MemberInitializer init, DataType type) {
                init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
                if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {


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