From: Jürg Billeter Date: Sat, 13 Mar 2010 19:43:56 +0000 (+0100) Subject: dova: Accept list, set, and map literals and tuples X-Git-Tag: 0.8.0~195 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=84b6b23be9a93fc1d17b2b8a9f5134e0f3054ccc;p=thirdparty%2Fvala.git dova: Accept list, set, and map literals and tuples --- diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala index 35dff33a6..fd465d17c 100644 --- a/codegen/valaccodegenerator.vala +++ b/codegen/valaccodegenerator.vala @@ -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); } diff --git a/codegen/valaccodemodule.vala b/codegen/valaccodemodule.vala index ebbc29863..939c49fc1 100644 --- a/codegen/valaccodemodule.vala +++ b/codegen/valaccodemodule.vala @@ -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); } diff --git a/vala/Makefile.am b/vala/Makefile.am index 28a85ae39..72c2b88b3 100644 --- a/vala/Makefile.am +++ b/vala/Makefile.am @@ -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 \ diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala index d42462396..8f83cfd50 100644 --- a/vala/valacodenode.vala +++ b/vala/valacodenode.vala @@ -189,7 +189,7 @@ public abstract class Vala.CodeNode { public virtual void get_used_variables (Collection collection) { } - public string get_temp_name () { + public static string get_temp_name () { return "." + (++last_temp_nr).to_string (); } } diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala index 7744674d8..f11a3ef43 100644 --- a/vala/valacodevisitor.vala +++ b/vala/valacodevisitor.vala @@ -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. * diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala index 9cfe3c8d9..c96ee7a03 100644 --- a/vala/valaelementaccess.vala +++ b/vala/valaelementaccess.vala @@ -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 index 000000000..9dd6a4ab2 --- /dev/null +++ b/vala/valalistliteral.vala @@ -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 + */ + +public class Vala.ListLiteral : Literal { + private List expression_list = new ArrayList (); + + 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 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 index 000000000..bf50a78ec --- /dev/null +++ b/vala/valamapliteral.vala @@ -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 + */ + +public class Vala.MapLiteral : Literal { + private List keys = new ArrayList (); + private List values = new ArrayList (); + + 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 get_keys () { + return keys; + } + + public List 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; + } +} diff --git a/vala/valaparser.vala b/vala/valaparser.vala index 2f0348450..e92a4e8e5 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -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? attrs) throws ParseError { var begin = get_location (); var access = parse_access_modifier (); diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala index 51b890648..bafc2466d 100644 --- a/vala/valasemanticanalyzer.vala +++ b/vala/valasemanticanalyzer.vala @@ -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 index 000000000..4f490a581 --- /dev/null +++ b/vala/valasetliteral.vala @@ -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 + */ + +public class Vala.SetLiteral : Literal { + private List expression_list = new ArrayList (); + + 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 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; + } +} diff --git a/vala/valatuple.vala b/vala/valatuple.vala index b723d391d..a842ee6da 100644 --- a/vala/valatuple.vala +++ b/vala/valatuple.vala @@ -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; } } -