]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
dova: Accept list, set, and map literals and tuples
authorJürg Billeter <j@bitron.ch>
Sat, 13 Mar 2010 19:43:56 +0000 (20:43 +0100)
committerJürg Billeter <j@bitron.ch>
Sat, 13 Mar 2010 19:45:47 +0000 (20:45 +0100)
12 files changed:
codegen/valaccodegenerator.vala
codegen/valaccodemodule.vala
vala/Makefile.am
vala/valacodenode.vala
vala/valacodevisitor.vala
vala/valaelementaccess.vala
vala/valalistliteral.vala [new file with mode: 0644]
vala/valamapliteral.vala [new file with mode: 0644]
vala/valaparser.vala
vala/valasemanticanalyzer.vala
vala/valasetliteral.vala [new file with mode: 0644]
vala/valatuple.vala

index 35dff33a62b110edd50bc83a09af82360b4edeb1..fd465d17cb483a87dcc6ae2b064f273293cd7887 100644 (file)
@@ -260,6 +260,22 @@ public class Vala.CCodeGenerator : CodeGenerator {
                head.visit_string_literal (expr);
        }
 
+       public override void visit_list_literal (ListLiteral expr) {
+               head.visit_list_literal (expr);
+       }
+
+       public override void visit_set_literal (SetLiteral expr) {
+               head.visit_set_literal (expr);
+       }
+
+       public override void visit_map_literal (MapLiteral expr) {
+               head.visit_map_literal (expr);
+       }
+
+       public override void visit_tuple (Tuple expr) {
+               head.visit_tuple (expr);
+       }
+
        public override void visit_null_literal (NullLiteral expr) {
                head.visit_null_literal (expr);
        }
index ebbc29863e6761de1457484ca84d4fff0319cbb0..939c49fc1bfdd311f51b1d82b75238c6f5d1bed3 100644 (file)
@@ -239,6 +239,22 @@ public abstract class Vala.CCodeModule {
                next.visit_string_literal (expr);
        }
 
+       public virtual void visit_list_literal (ListLiteral expr) {
+               next.visit_list_literal (expr);
+       }
+
+       public virtual void visit_set_literal (SetLiteral expr) {
+               next.visit_set_literal (expr);
+       }
+
+       public virtual void visit_map_literal (MapLiteral expr) {
+               next.visit_map_literal (expr);
+       }
+
+       public virtual void visit_tuple (Tuple expr) {
+               next.visit_tuple (expr);
+       }
+
        public virtual void visit_null_literal (NullLiteral expr) {
                next.visit_null_literal (expr);
        }
index 28a85ae39f4d1605fedaf50e2a9c29a397d888d5..72c2b88b3022a2124155cafdf2edacb1c1901225 100644 (file)
@@ -86,11 +86,13 @@ libvalacore_la_VALASOURCES = \
        valainterfacetype.vala \
        valainvalidtype.vala \
        valalambdaexpression.vala \
+       valalistliteral.vala \
        valaliteral.vala \
        valalocalvariable.vala \
        valalockable.vala \
        valalockstatement.vala \
        valaloop.vala \
+       valamapliteral.vala \
        valamarkupreader.vala \
        valamember.vala \
        valamemberaccess.vala \
@@ -121,6 +123,7 @@ libvalacore_la_VALASOURCES = \
        valascanner.vala \
        valascope.vala \
        valasemanticanalyzer.vala \
+       valasetliteral.vala \
        valasignal.vala \
        valasignaltype.vala \
        valasizeofexpression.vala \
index d42462396d38afee79a5b78b5f75dea47a81bbde..8f83cfd5066081d9e4f7c198e2dac053ed4c9738 100644 (file)
@@ -189,7 +189,7 @@ public abstract class Vala.CodeNode {
        public virtual void get_used_variables (Collection<LocalVariable> collection) {
        }
 
-       public string get_temp_name () {
+       public static string get_temp_name () {
                return "." + (++last_temp_nr).to_string ();
        }
 }
index 7744674d848c9d56df9a94b1bf50b2af4172fb63..f11a3ef43e5ec650746e1037ee0e7a7da6bcf68e 100644 (file)
@@ -476,6 +476,38 @@ public abstract class Vala.CodeVisitor {
        public virtual void visit_template (Template tmpl) {
        }
 
+       /**
+        * Visit operation called for list literals.
+        *
+        * @param lit a list literal
+        */
+       public virtual void visit_list_literal (ListLiteral lit) {
+       }
+
+       /**
+        * Visit operation called for set literals.
+        *
+        * @param lit a set literal
+        */
+       public virtual void visit_set_literal (SetLiteral lit) {
+       }
+
+       /**
+        * Visit operation called for map literals.
+        *
+        * @param lit a map literal
+        */
+       public virtual void visit_map_literal (MapLiteral lit) {
+       }
+
+       /**
+        * Visit operation called for tuples.
+        *
+        * @param tuple a tuple
+        */
+       public virtual void visit_tuple (Tuple tuple) {
+       }
+
        /**
         * Visit operation called for null literals.
         *
index 9cfe3c8d9455ef868f7cbb7a00ec784a126581b3..c96ee7a0345a46d7015e9bdd297f98f728818f64 100644 (file)
@@ -152,6 +152,40 @@ public class Vala.ElementAccess : Expression {
                        }
 
                        value_type = analyzer.unichar_type;
+               } else if (analyzer.context.profile == Profile.DOVA && container_type == analyzer.tuple_type.data_type) {
+                       if (get_indices ().size != 1) {
+                               error = true;
+                               Report.error (source_reference, "Element access with more than one dimension is not supported for tuples");
+                               return false;
+                       }
+                       var index = get_indices ().get (0) as IntegerLiteral;
+                       if (index == null) {
+                               error = true;
+                               Report.error (source_reference, "Element access with non-literal index is not supported for tuples");
+                               return false;
+                       }
+                       int i = index.value.to_int ();
+                       if (container.value_type.get_type_arguments ().size == 0) {
+                               error = true;
+                               Report.error (source_reference, "Element access is not supported for untyped tuples");
+                               return false;
+                       }
+                       if (i < 0 || i >= container.value_type.get_type_arguments ().size) {
+                               error = true;
+                               Report.error (source_reference, "Index out of range");
+                               return false;
+                       }
+
+                       value_type = container.value_type.get_type_arguments ().get (i);
+
+                       // replace element access by call to generic get method
+                       var ma = new MemberAccess (container, "get");
+                       ma.add_type_argument (value_type);
+                       var get_call = new MethodCall (ma);
+                       get_call.add_argument (index);
+                       get_call.target_type = this.target_type;
+                       parent_node.replace_expression (this, get_call);
+                       return get_call.check (analyzer);
                } else if (container is MemberAccess && container.symbol_reference is Signal) {
                        index_int_type_check = false;
 
diff --git a/vala/valalistliteral.vala b/vala/valalistliteral.vala
new file mode 100644 (file)
index 0000000..9dd6a4a
--- /dev/null
@@ -0,0 +1,113 @@
+/* valalistliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * 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:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+public class Vala.ListLiteral : Literal {
+       private List<Expression> expression_list = new ArrayList<Expression> ();
+
+       public DataType element_type { get; private set; }
+
+       public ListLiteral (SourceReference? source_reference = null) {
+               this.source_reference = source_reference;
+       }
+
+       public override void accept_children (CodeVisitor visitor) {
+               foreach (Expression expr in expression_list) {
+                       expr.accept (visitor);
+               }
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_list_literal (this);
+       }
+
+       public void add_expression (Expression expr) {
+               expression_list.add (expr);
+               expr.parent_node = this;
+       }
+
+       public List<Expression> get_expressions () {
+               return expression_list;
+       }
+
+       public override bool is_pure () {
+               return false;
+       }
+
+       public override void replace_expression (Expression old_node, Expression new_node) {
+               for (int i = 0; i < expression_list.size; i++) {
+                       if (expression_list[i] == old_node) {
+                               expression_list[i] = new_node;
+                       }
+               }
+       }
+
+       public override bool check (SemanticAnalyzer analyzer) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               // list literals are also allowed for constant arrays,
+               // however, they are currently handled by InitializerList
+               // therefore transform this expression if necessary
+               var array_type = target_type as ArrayType;
+               if (array_type != null && array_type.inline_allocated) {
+                       var initializer = new InitializerList (source_reference);
+                       initializer.target_type = target_type;
+                       foreach (var expr in expression_list) {
+                               initializer.append (expr);
+                       }
+
+                       analyzer.replaced_nodes.add (this);
+                       parent_node.replace_expression (this, initializer);
+                       return initializer.check (analyzer);
+               }
+
+               var list_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("List"));
+               list_type.value_owned = true;
+
+               bool fixed_element_type = false;
+               if (target_type != null && target_type.data_type == list_type.data_type && target_type.get_type_arguments ().size == 1) {
+                       element_type = target_type.get_type_arguments ().get (0).copy ();
+                       fixed_element_type = true;
+               }
+
+               foreach (var expr in expression_list) {
+                       if (fixed_element_type) {
+                               expr.target_type = element_type;
+                       }
+                       if (!expr.check (analyzer)) {
+                               return false;
+                       }
+                       if (element_type == null) {
+                               element_type = expr.value_type.copy ();
+                       }
+               }
+
+               element_type.value_owned = true;
+               list_type.add_type_argument (element_type);
+               value_type = list_type;
+
+               return !error;
+       }
+}
diff --git a/vala/valamapliteral.vala b/vala/valamapliteral.vala
new file mode 100644 (file)
index 0000000..bf50a78
--- /dev/null
@@ -0,0 +1,120 @@
+/* valamapliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * 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:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+public class Vala.MapLiteral : Literal {
+       private List<Expression> keys = new ArrayList<Expression> ();
+       private List<Expression> values = new ArrayList<Expression> ();
+
+       public DataType map_key_type { get; private set; }
+       public DataType map_value_type { get; private set; }
+
+       public MapLiteral (SourceReference? source_reference = null) {
+               this.source_reference = source_reference;
+       }
+
+       public override void accept_children (CodeVisitor visitor) {
+               for (int i = 0; i < keys.size; i++) {
+                       keys[i].accept (visitor);
+                       values[i].accept (visitor);
+               }
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_map_literal (this);
+       }
+
+       public void add_key (Expression expr) {
+               keys.add (expr);
+               expr.parent_node = this;
+       }
+
+       public void add_value (Expression expr) {
+               values.add (expr);
+               expr.parent_node = this;
+       }
+
+       public List<Expression> get_keys () {
+               return keys;
+       }
+
+       public List<Expression> get_values () {
+               return values;
+       }
+
+       public override bool is_pure () {
+               return false;
+       }
+
+       public override void replace_expression (Expression old_node, Expression new_node) {
+               for (int i = 0; i < keys.size; i++) {
+                       if (keys[i] == old_node) {
+                               keys[i] = new_node;
+                       }
+                       if (values[i] == old_node) {
+                               values[i] = new_node;
+                       }
+               }
+       }
+
+       public override bool check (SemanticAnalyzer analyzer) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               var map_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Map"));
+               map_type.value_owned = true;
+
+               bool fixed_element_type = false;
+               if (target_type != null && target_type.data_type == map_type.data_type && target_type.get_type_arguments ().size == 2) {
+                       map_key_type = target_type.get_type_arguments ().get (0).copy ();
+                       map_value_type = target_type.get_type_arguments ().get (1).copy ();
+                       fixed_element_type = true;
+               }
+
+               for (int i = 0; i < keys.size; i++) {
+                       if (fixed_element_type) {
+                               keys[i].target_type = map_key_type;
+                               values[i].target_type = map_value_type;
+                       }
+                       if (!keys[i].check (analyzer)) {
+                               return false;
+                       }
+                       if (!values[i].check (analyzer)) {
+                               return false;
+                       }
+                       if (map_key_type == null) {
+                               map_key_type = keys[i].value_type.copy ();
+                               map_value_type = values[i].value_type.copy ();
+                       }
+               }
+
+               map_key_type.value_owned = true;
+               map_value_type.value_owned = true;
+               map_type.add_type_argument (map_key_type);
+               map_type.add_type_argument (map_value_type);
+               value_type = map_type;
+
+               return !error;
+       }
+}
index 2f03484504d3fefb1c65db15b32efbe37526d55f..e92a4e8e52277d7c2f5f698f79c928664f82acc7 100644 (file)
@@ -551,11 +551,18 @@ public class Vala.Parser : CodeVisitor {
                        break;
                case TokenType.OPEN_BRACE:
                        if (context.profile == Profile.DOVA) {
-                               expr = parse_simple_name ();
+                               expr = parse_set_literal ();
                        } else {
                                expr = parse_initializer ();
                        }
                        break;
+               case TokenType.OPEN_BRACKET:
+                       if (context.profile == Profile.DOVA) {
+                               expr = parse_list_literal ();
+                       } else {
+                               expr = parse_simple_name ();
+                       }
+                       break;
                case TokenType.OPEN_PARENS:
                        expr = parse_tuple ();
                        break;
@@ -1526,6 +1533,32 @@ public class Vala.Parser : CodeVisitor {
                        variable_type = parse_type ();
                }
                do {
+                       if (variable_type == null && accept (TokenType.OPEN_PARENS)) {
+                               // tuple
+                               var begin = get_location ();
+
+                               string[] identifiers = {};
+                               do {
+                                       identifiers += parse_identifier ();
+                               } while (accept (TokenType.COMMA));
+                               expect (TokenType.CLOSE_PARENS);
+
+                               expect (TokenType.ASSIGN);
+                               var tuple = parse_expression ();
+                               var tuple_local = new LocalVariable (null, CodeNode.get_temp_name (), tuple, get_src (begin));
+                               block.add_statement (new DeclarationStatement (tuple_local, tuple_local.source_reference));
+
+                               for (int i = 0; i < identifiers.length; i++) {
+                                       var temp_access = new MemberAccess.simple (tuple_local.name, tuple_local.source_reference);
+                                       var ea = new ElementAccess (temp_access, tuple_local.source_reference);
+                                       ea.append_index (new IntegerLiteral (i.to_string ()));
+                                       var local = new LocalVariable (null, identifiers[i], ea, tuple_local.source_reference);
+                                       block.add_statement (new DeclarationStatement (local, local.source_reference));
+                               }
+
+                               continue;
+                       }
+
                        DataType type_copy = null;
                        if (variable_type != null) {
                                type_copy = variable_type.copy ();
@@ -2312,6 +2345,58 @@ public class Vala.Parser : CodeVisitor {
                return initializer;
        }
 
+       ListLiteral parse_list_literal () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.OPEN_BRACKET);
+               var initializer = new ListLiteral (get_src (begin));
+               if (current () != TokenType.CLOSE_BRACKET) {
+                       do {
+                               var init = parse_expression ();
+                               initializer.add_expression (init);
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_BRACKET);
+               return initializer;
+       }
+
+       Expression parse_set_literal () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.OPEN_BRACE);
+               var set = new SetLiteral (get_src (begin));
+               bool first = true;
+               if (current () != TokenType.CLOSE_BRACE) {
+                       do {
+                               var expr = parse_expression ();
+                               if (first && accept (TokenType.COLON)) {
+                                       // found colon after expression, it's a map
+                                       rollback (begin);
+                                       return parse_map_literal ();
+                               }
+                               first = false;
+                               set.add_expression (expr);
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_BRACE);
+               return set;
+       }
+
+       Expression parse_map_literal () throws ParseError {
+               var begin = get_location ();
+               expect (TokenType.OPEN_BRACE);
+               var map = new MapLiteral (get_src (begin));
+               if (current () != TokenType.CLOSE_BRACE) {
+                       do {
+                               var key = parse_expression ();
+                               map.add_key (key);
+                               expect (TokenType.COLON);
+                               var value = parse_expression ();
+                               map.add_value (value);
+                       } while (accept (TokenType.COMMA));
+               }
+               expect (TokenType.CLOSE_BRACE);
+               return map;
+       }
+
        Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
                var begin = get_location ();
                var access = parse_access_modifier ();
index 51b8906483f3518718531c94bbdc299d57312d5c..bafc2466d44bcba34660014547a1a97d17cc5f57 100644 (file)
@@ -136,6 +136,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public DataType garray_type;
        public DataType gvaluearray_type;
        public Class gerror_type;
+       public DataType list_type;
+       public DataType tuple_type;
 
        public int next_lambda_id = 0;
 
@@ -203,6 +205,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                        object_type = (Class) dova_ns.scope.lookup ("Object");
                        type_type = new ObjectType ((Class) dova_ns.scope.lookup ("Type"));
+                       list_type = new ObjectType ((Class) dova_ns.scope.lookup ("List"));
+                       tuple_type = new ObjectType ((Class) dova_ns.scope.lookup ("Tuple"));
                }
 
                current_symbol = root_symbol;
diff --git a/vala/valasetliteral.vala b/vala/valasetliteral.vala
new file mode 100644 (file)
index 0000000..4f490a5
--- /dev/null
@@ -0,0 +1,97 @@
+/* valasetliteral.vala
+ *
+ * Copyright (C) 2009  Jürg Billeter
+ *
+ * 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:
+ *     Jürg Billeter <j@bitron.ch>
+ */
+
+public class Vala.SetLiteral : Literal {
+       private List<Expression> expression_list = new ArrayList<Expression> ();
+
+       public DataType element_type { get; private set; }
+
+       public SetLiteral (SourceReference? source_reference = null) {
+               this.source_reference = source_reference;
+       }
+
+       public override void accept_children (CodeVisitor visitor) {
+               foreach (Expression expr in expression_list) {
+                       expr.accept (visitor);
+               }
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_set_literal (this);
+       }
+
+       public void add_expression (Expression expr) {
+               expression_list.add (expr);
+               expr.parent_node = this;
+       }
+
+       public List<Expression> get_expressions () {
+               return expression_list;
+       }
+
+       public override bool is_pure () {
+               return false;
+       }
+
+       public override void replace_expression (Expression old_node, Expression new_node) {
+               for (int i = 0; i < expression_list.size; i++) {
+                       if (expression_list[i] == old_node) {
+                               expression_list[i] = new_node;
+                       }
+               }
+       }
+
+       public override bool check (SemanticAnalyzer analyzer) {
+               if (checked) {
+                       return !error;
+               }
+
+               checked = true;
+
+               var set_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Set"));
+               set_type.value_owned = true;
+
+               bool fixed_element_type = false;
+               if (target_type != null && target_type.data_type == set_type.data_type && target_type.get_type_arguments ().size == 1) {
+                       element_type = target_type.get_type_arguments ().get (0).copy ();
+                       fixed_element_type = true;
+               }
+
+               foreach (var expr in expression_list) {
+                       if (fixed_element_type) {
+                               expr.target_type = element_type;
+                       }
+                       if (!expr.check (analyzer)) {
+                               return false;
+                       }
+                       if (element_type == null) {
+                               element_type = expr.value_type.copy ();
+                       }
+               }
+
+               element_type.value_owned = true;
+               set_type.add_type_argument (element_type);
+               value_type = set_type;
+
+               return !error;
+       }
+}
index b723d391de8e285e97b79eb58c56cd79bb875a22..a842ee6da20f9fb3f9d44a8e02bdb5005aee45d6 100644 (file)
@@ -32,6 +32,16 @@ public class Vala.Tuple : Expression {
                this.source_reference = source_reference;
        }
 
+       public override void accept_children (CodeVisitor visitor) {
+               foreach (Expression expr in expression_list) {
+                       expr.accept (visitor);
+               }
+       }
+
+       public override void accept (CodeVisitor visitor) {
+               visitor.visit_tuple (this);
+       }
+
        public void add_expression (Expression expr) {
                expression_list.add (expr);
        }
@@ -44,6 +54,14 @@ public class Vala.Tuple : Expression {
                return false;
        }
 
+       public override void replace_expression (Expression old_node, Expression new_node) {
+               for (int i = 0; i < expression_list.size; i++) {
+                       if (expression_list[i] == old_node) {
+                               expression_list[i] = new_node;
+                       }
+               }
+       }
+
        public override bool check (SemanticAnalyzer analyzer) {
                if (checked) {
                        return !error;
@@ -51,9 +69,22 @@ public class Vala.Tuple : Expression {
 
                checked = true;
 
-               Report.error (source_reference, "tuples are not supported");
-               error = true;
-               return false;
+               if (analyzer.context.profile != Profile.DOVA) {
+                       Report.error (source_reference, "tuples are not supported");
+                       error = true;
+                       return false;
+               }
+
+               value_type = new ObjectType ((Class) analyzer.context.root.scope.lookup ("Dova").scope.lookup ("Tuple"));
+               value_type.value_owned = true;
+
+               foreach (var expr in expression_list) {
+                       if (!expr.check (analyzer)) {
+                               return false;
+                       }
+                       value_type.add_type_argument (expr.value_type.copy ());
+               }
+
+               return !error;
        }
 }
-