Commit a265bc69 authored by Raffaele Sandrini's avatar Raffaele Sandrini Committed by Raffaele Sandrini

add threading and assorted structures add an additional abstraction for

2006-09-27  Raffaele Sandrini  <rasa@gmx.ch>

	* vapi/glib-2.0.vala: add threading and assorted structures
	* vala/valamember.vala: add an additional abstraction for all members
	  of a class
	* vala/valalockstatement.vala, vala/valacodegenerator.vala,
	  vala/scanner.l, vala/valasemanticanalyzer.vala,
	  vala/valalockable.vala, vala/parser.y, vala/valacodevisitor.vala:
	  add lock feature to vala
	* vala/valamethod.vala, vala/valafield.vala, vala/valaconstant.vala,
	  vala/valasignal.vala, vala/valaproperty.vala: make those members
	  lockable
	* vala/valacodegenerator.vala: use member abstraction to simlify field
	  initialisation and destruction
	* vala/valacodegenerator.vala: introduce new C macros VALA_FREE_CHECKED
	  and VALA_FREE_UNCHECKED to make safe freeing code nicer
	* vala/vala.h: update and bring arraycreationexpression in order
	* vala/Makefile.am: update


svn path=/trunk/; revision=129
parent 8fe5d662
2006-09-27 Raffaele Sandrini <rasa@gmx.ch>
* vapi/glib-2.0.vala: add threading and assorted structures
* vala/valamember.vala: add an additional abstraction for all members
of a class
* vala/valalockstatement.vala, vala/valacodegenerator.vala,
vala/scanner.l, vala/valasemanticanalyzer.vala,
vala/valalockable.vala, vala/parser.y, vala/valacodevisitor.vala:
add lock feature to vala
* vala/valamethod.vala, vala/valafield.vala, vala/valaconstant.vala,
vala/valasignal.vala, vala/valaproperty.vala: make those members
lockable
* vala/valacodegenerator.vala: use member abstraction to simlify field
initialisation and destruction
* vala/valacodegenerator.vala: introduce new C macros VALA_FREE_CHECKED
and VALA_FREE_UNCHECKED to make safe freeing code nicer
* vala/vala.h: update and bring arraycreationexpression in order
* vala/Makefile.am: update
2006-09-27 Jürg Billeter <j@bitron.ch>
* vapi/glib-2.0.vala: add Process struct with spawn functions
......
......@@ -169,6 +169,15 @@ libvala_la_SOURCES = \
valalocalvariabledeclaration.c \
valalocalvariabledeclaration.h \
valalocalvariabledeclaration.vala \
valalockable.c \
valalockable.h \
valalockable.vala \
valalockstatement.c \
valalockstatement.h \
valalockstatement.vala \
valamember.c \
valamember.h \
valamember.vala \
valamemberaccess.c \
valamemberaccess.h \
valamemberaccess.vala \
......@@ -343,6 +352,9 @@ valainclude_HEADERS = \
valaliteral.h \
valaliteralexpression.h \
valalocalvariabledeclaration.h \
valalockable.h \
valamember.h \
valalockstatement.h \
valamemberaccess.h \
valamemberaccessibility.h \
valamemorymanager.h \
......
......@@ -170,6 +170,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
%token IN "in"
%token INTERFACE "interface"
%token IS "is"
%token LOCK "lock"
%token NAMESPACE "namespace"
%token NEW "new"
%token VALA_NULL "null"
......@@ -282,6 +283,7 @@ static void yyerror (YYLTYPE *locp, ValaParser *parser, const char *msg);
%type <statement> break_statement
%type <statement> continue_statement
%type <statement> return_statement
%type <statement> lock_statement
%type <namespace> namespace_declaration
%type <str> opt_name_specifier
%type <str> name_specifier
......@@ -1224,6 +1226,7 @@ embedded_statement
| selection_statement
| iteration_statement
| jump_statement
| lock_statement
;
block
......@@ -1686,6 +1689,16 @@ return_statement
}
;
lock_statement
: comment LOCK OPEN_PARENS expression CLOSE_PARENS embedded_statement
{
ValaSourceReference *src = src_com(@4, $1);
$$ = VALA_STATEMENT (vala_lock_statement_new ($4, $6, src));
g_object_unref (src);
g_object_unref ($4);
g_object_unref ($6);
}
namespace_declaration
: comment opt_attributes NAMESPACE IDENTIFIER
{
......
......@@ -171,6 +171,7 @@ literal ({integer_literal}|{real_literal}|{character_literal}|{string_literal
"virtual" { uploc; return VIRTUAL; }
"weak" { uploc; return WEAK; }
"while" { uploc; return WHILE; }
"lock" { uploc; return LOCK; }
{real_literal} { uploc; yylval->str = g_strdup (yytext); return REAL_LITERAL; }
{integer_literal} { uploc; yylval->str = g_strdup (yytext); return INTEGER_LITERAL; }
......
#include <vala/valaarraycreationexpression.h>
#include <vala/valaassignment.h>
#include <vala/valaattribute.h>
#include <vala/valabinaryexpression.h>
......@@ -36,6 +37,7 @@
#include <vala/valaliteral.h>
#include <vala/valaliteralexpression.h>
#include <vala/valalocalvariabledeclaration.h>
#include <vala/valalockstatement.h>
#include <vala/valamemberaccess.h>
#include <vala/valamethod.h>
#include <vala/valanamedargument.h>
......@@ -65,4 +67,3 @@
#include <vala/valaunaryexpression.h>
#include <vala/valavariabledeclarator.h>
#include <vala/valawhilestatement.h>
#include <vala/valaarraycreationexpression.h>
......@@ -37,6 +37,7 @@ public class Vala.CodeGenerator : CodeVisitor {
Symbol root_symbol;
Symbol current_symbol;
Symbol current_type_symbol;
Class current_class;
CCodeFragment header_begin;
CCodeFragment header_type_declaration;
......@@ -46,6 +47,8 @@ public class Vala.CodeGenerator : CodeVisitor {
CCodeFragment source_include_directives;
CCodeFragment source_type_member_declaration;
CCodeFragment source_type_member_definition;
CCodeFragment instance_init_fragment;
CCodeFragment instance_dispose_fragment;
CCodeStruct instance_struct;
CCodeStruct type_struct;
......@@ -78,6 +81,7 @@ public class Vala.CodeGenerator : CodeVisitor {
TypeReference double_type;
DataType list_type;
DataType slist_type;
TypeReference mutex_type;
public construct (bool manage_memory = true) {
memory_management = manage_memory;
......@@ -141,6 +145,9 @@ public class Vala.CodeGenerator : CodeVisitor {
list_type = (DataType) glib_ns.lookup ("List").node;
slist_type = (DataType) glib_ns.lookup ("SList").node;
mutex_type = new TypeReference ();
mutex_type.data_type = (DataType) glib_ns.lookup ("Mutex").node;
/* we're only interested in non-pkg source files */
var source_files = context.get_source_files ();
......@@ -216,6 +223,10 @@ public class Vala.CodeGenerator : CodeVisitor {
}
}
}
/* generate hardcoded "well-known" macros */
source_begin.append (new CCodeMacroReplacement ("VALA_FREE_CHECKED(o,f)", "((o) == NULL ? NULL : ((o) = (f (o), NULL)))"));
source_begin.append (new CCodeMacroReplacement ("VALA_FREE_UNCHECKED(o,f)", "((o) = (f (o), NULL))"));
}
private static ref string get_define_for_filename (string! filename) {
......@@ -298,12 +309,15 @@ public class Vala.CodeGenerator : CodeVisitor {
public override void visit_begin_class (Class! cl) {
current_symbol = cl.symbol;
current_type_symbol = cl.symbol;
current_class = cl;
instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ()));
instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
prop_enum = new CCodeEnum ();
prop_enum.add_value ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null)), null);
instance_init_fragment = new CCodeFragment ();
instance_dispose_fragment = new CCodeFragment ();
header_type_declaration.append (new CCodeNewline ());
......@@ -370,6 +384,7 @@ public class Vala.CodeGenerator : CodeVisitor {
source_type_member_definition.append (type_fun);
current_type_symbol = null;
current_class = null;
}
private void add_class_init_function (Class! cl) {
......@@ -579,24 +594,7 @@ public class Vala.CodeGenerator : CodeVisitor {
init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall)));
}
var fields = cl.get_fields ();
foreach (Field f in fields) {
if (f.initializer != null) {
ref CCodeExpression lhs = null;
if (f.instance) {
if (f.access == MemberAccessibility.PRIVATE) {
lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
} else {
lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
}
} /* else {
lhs = new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), f.get_cname ()));
} */
if (lhs != null) {
init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
}
}
}
init_block.add_statement (instance_init_fragment);
var init_sym = cl.symbol.lookup ("init");
if (init_sym != null) {
......@@ -626,21 +624,7 @@ public class Vala.CodeGenerator : CodeVisitor {
cblock.add_statement (cdecl);
var fields = cl.get_fields ();
foreach (Field f in fields) {
if (f.instance && f.type_reference.takes_ownership) {
var cself = new CCodeIdentifier ("self");
CCodeExpression cstruct = cself;
if (f.access == MemberAccessibility.PRIVATE) {
cstruct = new CCodeMemberAccess.pointer (cself, "priv");
}
var cfield = new CCodeMemberAccess.pointer (cstruct, f.get_cname ());
cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (cfield, f.type_reference)));
}
}
cblock.add_statement (instance_dispose_fragment);
cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
......@@ -880,6 +864,29 @@ public class Vala.CodeGenerator : CodeVisitor {
source_type_member_declaration.append (ctypedef);
}
}
public override void visit_member (Member! m) {
/* stuff meant for all lockable members */
if (m is Lockable && ((Lockable)m).get_lock_used ()) {
instance_priv_struct.add_field (mutex_type.get_cname (), get_symbol_lock_name (m.symbol));
instance_init_fragment.append (
new CCodeExpressionStatement (
new CCodeAssignment (
new CCodeMemberAccess.pointer (
new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
get_symbol_lock_name (m.symbol)),
new CCodeFunctionCall (new CCodeIdentifier (((Struct)mutex_type.data_type).default_construction_method.get_cname ())))));
var fc = new CCodeFunctionCall (new CCodeIdentifier ("VALA_FREE_CHECKED"));
fc.add_argument (
new CCodeMemberAccess.pointer (
new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"),
get_symbol_lock_name (m.symbol)));
fc.add_argument (new CCodeIdentifier (mutex_type.data_type.get_free_function ()));
instance_dispose_fragment.append (new CCodeExpressionStatement (fc));
}
}
public override void visit_constant (Constant! c) {
if (c.symbol.parent_symbol.node is DataType) {
......@@ -901,11 +908,17 @@ public class Vala.CodeGenerator : CodeVisitor {
}
public override void visit_field (Field! f) {
CCodeExpression lhs = null;
if (f.access != MemberAccessibility.PRIVATE) {
instance_struct.add_field (f.type_reference.get_cname (), f.get_cname ());
if (f.instance) {
lhs = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), f.get_cname ());
}
} else if (f.access == MemberAccessibility.PRIVATE) {
if (f.instance) {
instance_priv_struct.add_field (f.type_reference.get_cname (), f.get_cname ());
lhs = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), f.get_cname ());
} else {
if (f.symbol.parent_symbol.node is DataType) {
var t = (DataType) f.symbol.parent_symbol.node;
......@@ -920,6 +933,16 @@ public class Vala.CodeGenerator : CodeVisitor {
}
}
}
if (f.instance) {
if (f.initializer != null) {
instance_init_fragment.append (new CCodeExpressionStatement (new CCodeAssignment (lhs, (CCodeExpression) f.initializer.ccodenode)));
}
if (f.type_reference.takes_ownership) {
instance_dispose_fragment.append (new CCodeExpressionStatement (get_unref_expression (lhs, f.type_reference)));
}
}
}
public override void visit_begin_method (Method! m) {
......@@ -1899,6 +1922,44 @@ public class Vala.CodeGenerator : CodeVisitor {
}
}
private ref string get_symbol_lock_name (Symbol! sym) {
return "__lock_%s".printf (sym.name);
}
/**
* Visit operation called for lock statements.
*
* @param stmt a lock statement
*/
public override void visit_lock_statement (LockStatement! stmt) {
var cn = new CCodeFragment ();
CCodeExpression l = null;
CCodeFunctionCall fc;
var inner_node = ((MemberAccess)stmt.resource).inner;
if (inner_node == null) {
l = new CCodeIdentifier ("self");
} else if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
l = new CCodeFunctionCall (new CCodeIdentifier (((DataType) stmt.resource.symbol_reference.parent_symbol.node).get_upper_case_cname ()));
((CCodeFunctionCall) l).add_argument ((CCodeExpression)inner_node.ccodenode);
} else {
l = (CCodeExpression)inner_node.ccodenode;
}
l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference));
fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("lock").node).get_cname ()));
fc.add_argument (l);
cn.append (new CCodeExpressionStatement (fc));
cn.append (stmt.body.ccodenode);
fc = new CCodeFunctionCall (new CCodeIdentifier (((Method)mutex_type.data_type.symbol.lookup ("unlock").node).get_cname ()));
fc.add_argument (l);
cn.append (new CCodeExpressionStatement (fc));
stmt.ccodenode = cn;
}
/**
* Visit operations called for array creation expresions.
*
......
......@@ -170,6 +170,14 @@ public abstract class Vala.CodeVisitor {
*/
public virtual void visit_end_callback (Callback! cb) {
}
/**
* Visit operation called for Members.
*
* @param m a member
*/
public virtual void visit_member (Member! m) {
}
/**
* Visit operation called for constants.
......@@ -491,6 +499,14 @@ public abstract class Vala.CodeVisitor {
public virtual void visit_begin_return_statement (ReturnStatement! stmt) {
}
/**
* Visit operation called for lock statements before the body has been visited.
*
* @param stmt a lock statement
*/
public virtual void visit_lock_statement (LockStatement! stmt) {
}
/**
* Visit operation called at end of return statements.
*
......
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents a type member with a constant value.
*/
public class Vala.Constant : CodeNode {
public class Vala.Constant : Member, Lockable {
/**
* The symbol name of this constant.
*/
......@@ -50,6 +50,8 @@ public class Vala.Constant : CodeNode {
public MemberAccessibility access;
private string cname;
private bool lock_used = false;
/**
* Creates a new constant.
......@@ -68,12 +70,14 @@ public class Vala.Constant : CodeNode {
}
public override void accept (CodeVisitor! visitor) {
visitor.visit_member (this);
type_reference.accept (visitor);
if (initializer != null) {
initializer.accept (visitor);
}
visitor.visit_constant (this);
}
......@@ -94,4 +98,12 @@ public class Vala.Constant : CodeNode {
}
return cname;
}
public override bool get_lock_used () {
return lock_used;
}
public override void set_lock_used (bool used) {
lock_used = used;
}
}
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents a type or namespace field.
*/
public class Vala.Field : CodeNode, Invokable {
public class Vala.Field : Member, Invokable, Lockable {
/**
* The symbol name of this field.
*/
......@@ -65,6 +65,8 @@ public class Vala.Field : CodeNode, Invokable {
private string cname;
private bool _instance = true;
private bool lock_used = false;
/**
* Creates a new field.
*
......@@ -82,6 +84,8 @@ public class Vala.Field : CodeNode, Invokable {
}
public override void accept (CodeVisitor! visitor) {
visitor.visit_member (this);
type_reference.accept (visitor);
if (initializer != null) {
......@@ -158,4 +162,12 @@ public class Vala.Field : CodeNode, Invokable {
public override bool is_invokable () {
return (type_reference.data_type is Callback);
}
public override bool get_lock_used () {
return lock_used;
}
public override void set_lock_used (bool used) {
lock_used = used;
}
}
/* valalockable.vala
*
* Copyright (C) 2006 Raffaele Sandrini
*
* 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 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:
* Raffaele Sandrini <rasa@gmx.ch>
*/
/**
* Represents a lockable object.
*/
public interface Vala.Lockable {
/**
* Indicates a specific lockable object beeing actually locked somewhere.
*/
public abstract bool get_lock_used ();
/**
* Set this lockable object as beeing locked somewhere.
*/
public abstract void set_lock_used (bool used);
}
/* valalockstatement.vala
*
* Copyright (C) 2006 Raffaele Sandrini
*
* 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 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:
* Raffaele Sandrini <rasa@gmx.ch>
*/
using GLib;
/**
* Represents a lock statement e.g. "lock (a) { f(a) }".
*/
public class Vala.LockStatement : Statement {
/**
* Expression representing the resource to be locked.
*/
public Expression! resource { get; set construct; }
/**
* The statement during its execution the resource is locked.
*/
public Statement! body { get; set construct; }
public construct (Expression _resource, Statement _body, SourceReference source) {
resource = _resource;
body = _body;
source_reference = source;
}
public override void accept (CodeVisitor! visitor) {
resource.accept (visitor);
body.accept (visitor);
visitor.visit_lock_statement (this);
}
}
/* valamember.vala
*
* Copyright (C) 2006 Raffaele Sandrini
*
* 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 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:
* Raffaele Sandrini <rasa@gmx.ch>
*/
/**
* Represents a general class member.
*/
public class Vala.Member : CodeNode {
public override void accept (CodeVisitor! visitor) {
visitor.visit_member (this);
}
}
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents a type or namespace method.
*/
public class Vala.Method : CodeNode, Invokable {
public class Vala.Method : Member, Invokable {
/**
* The symbol name of this method.
*/
......
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents a property declaration in the source code.
*/
public class Vala.Property : CodeNode {
public class Vala.Property : Member, Lockable {
/**
* The property name.
*/
......@@ -71,6 +71,8 @@ public class Vala.Property : CodeNode {
*/
public bool interface_only { get; set; }
private bool lock_used = false;
/**
* Creates a new property.
*
......@@ -90,6 +92,7 @@ public class Vala.Property : CodeNode {
}
public override void accept (CodeVisitor! visitor) {
visitor.visit_member (this);
visitor.visit_begin_property (this);
type_reference.accept (visitor);
......@@ -151,4 +154,12 @@ public class Vala.Property : CodeNode {
}
}
}
public override bool get_lock_used () {
return lock_used;
}
public override void set_lock_used (bool used) {
lock_used = used;
}
}
......@@ -36,6 +36,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
Symbol current_symbol;
SourceFile current_source_file;
TypeReference current_return_type;
Class current_class;
List<weak NamespaceReference> current_using_directives;
......@@ -99,6 +100,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
public override void visit_begin_class (Class! cl) {
current_symbol = cl.symbol;
current_class = cl;
if (cl.base_class != null) {
current_source_file.add_symbol_dependency (cl.base_class.symbol, SourceFileDependencyType.HEADER_FULL);
......@@ -115,11 +117,21 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
public override void visit_begin_struct (Struct! st) {
current_symbol = st.symbol;
current_class = null;
}
public override void visit_end_struct (Struct! st) {
current_symbol = current_symbol.parent_symbol;
}
public override void visit_constant (Constant! c) {
if (!current_source_file.pkg) {
if (c.initializer == null) {
c.error = true;
Report.error (c.source_reference, "A const field requires a initializer to be provided");
}
}
}
public override void visit_field (Field! f) {
if (f.access != MemberAccessibility.PRIVATE) {
......@@ -548,6 +560,30 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
}
/**
* Visit operation called for lock statements.
*
* @param stmt a lock statement
*/
public override void visit_lock_statement (LockStatement! stmt) {
/* resource must be a member access and denote a Lockable */
if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference.node is Lockable)) {
stmt.error = true;
stmt.resource.error = true;
Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
return;
}
/* parent symbol must be the current class */
if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
stmt.error = true;
stmt.resource.error = true;
Report.error (stmt.resource.source_reference, "Only members of the current class are lockable");
}
((Lockable)stmt.resource.symbol_reference.node).set_lock_used (true);
}
public override void visit_begin_array_creation_expression (ArrayCreationExpression! expr) {
if (expr.initializer_list != null) {
expr.initializer_list.expected_type = expr.element_type.copy ();
......
......@@ -25,7 +25,7 @@ using GLib;
/**
* Represents an object signal. Signals enable objects to provide notifications.
*/
public class Vala.Signal : CodeNode, Invokable {
public class Vala.Signal : Member, Invokable,