Commit c86c5d85 authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

replace Invokable interface by DelegateType, MethodType, and SignalType

2007-12-14  Juerg Billeter  <j@bitron.ch>

	* vala/Makefile.am, vala/valadatatype.vala, vala/valadelegatetype.vala,
	  vala/valafield.vala, vala/valaformalparameter.vala,
	  vala/valainterfacewriter.vala, vala/valainvokable.vala,
	  vala/valamemorymanager.vala, vala/valamethod.vala,
	  vala/valamethodtype.vala, vala/valasemanticanalyzer.vala,
	  vala/valasignal.vala, vala/valasignaltype.vala,
	  vala/valasymbolresolver.vala, vala/valavariabledeclarator.vala,
	  gobject/valaccodegenerator.vala,
	  gobject/valaccodegeneratorinvocationexpression.vala: replace Invokable
	  interface by DelegateType, MethodType, and SignalType classes

svn path=/trunk/; revision=768
parent 10727f6e
2007-12-14 Jürg Billeter <j@bitron.ch>
* vala/Makefile.am, vala/valadatatype.vala, vala/valadelegatetype.vala,
vala/valafield.vala, vala/valaformalparameter.vala,
vala/valainterfacewriter.vala, vala/valainvokable.vala,
vala/valamemorymanager.vala, vala/valamethod.vala,
vala/valamethodtype.vala, vala/valasemanticanalyzer.vala,
vala/valasignal.vala, vala/valasignaltype.vala,
vala/valasymbolresolver.vala, vala/valavariabledeclarator.vala,
gobject/valaccodegenerator.vala,
gobject/valaccodegeneratorinvocationexpression.vala: replace Invokable
interface by DelegateType, MethodType, and SignalType classes
2007-12-14 Jürg Billeter <j@bitron.ch>
* gobject/valaccodegeneratorinvocationexpression.vala: fix exception
......
......@@ -1771,7 +1771,7 @@ public class Vala.CCodeGenerator : CodeGenerator {
var local_vars = b.get_local_variables ();
foreach (VariableDeclarator decl in local_vars) {
if (decl.active && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
if (decl.active && decl.type_reference.data_type != null && decl.type_reference.data_type.is_reference_type () && decl.type_reference.takes_ownership) {
found = true;
var ma = new MemberAccess.simple (decl.name);
ma.symbol_reference = decl;
......
......@@ -41,15 +41,13 @@ public class Vala.CCodeGenerator {
var ma = (MemberAccess) expr.call;
if (expr.call.symbol_reference is Invokable) {
var i = (Invokable) expr.call.symbol_reference;
params = i.get_parameters ();
if (i is Method) {
m = (Method) i;
} else if (i is Signal) {
ccall = (CCodeFunctionCall) expr.call.ccodenode;
}
var itype = expr.call.static_type;
params = itype.get_parameters ();
if (itype is MethodType) {
m = ((MethodType) itype).method_symbol;
} else if (itype is SignalType) {
ccall = (CCodeFunctionCall) expr.call.ccodenode;
}
if (m is ArrayResizeMethod) {
......
......@@ -46,6 +46,7 @@ libvalacore_la_VALASOURCES = \
valacreationmethod.vala \
valadatatype.vala \
valadeclarationstatement.vala \
valadelegatetype.vala \
valadestructor.vala \
valadostatement.vala \
valaelementaccess.vala \
......@@ -65,7 +66,6 @@ libvalacore_la_VALASOURCES = \
valainterface.vala \
valainterfacewriter.vala \
valainvocationexpression.vala \
valainvokable.vala \
valalambdaexpression.vala \
valaliteral.vala \
valaliteralexpression.vala \
......@@ -77,6 +77,7 @@ libvalacore_la_VALASOURCES = \
valamemberinitializer.vala \
valamemorymanager.vala \
valamethod.vala \
valamethodtype.vala \
valanamedargument.vala \
valanamespace.vala \
valanamespacereference.vala \
......@@ -99,6 +100,7 @@ libvalacore_la_VALASOURCES = \
valascope.vala \
valasemanticanalyzer.vala \
valasignal.vala \
valasignaltype.vala \
valasizeofexpression.vala \
valasourcefile.vala \
valasourcefilecycle.vala \
......
......@@ -121,7 +121,7 @@ public class Vala.DataType : CodeNode {
*
* @return the type string to be used in C code
*/
public string get_cname (bool var_type = false, bool const_type = false) {
public virtual string get_cname (bool var_type = false, bool const_type = false) {
if (data_type == null && type_parameter == null) {
if (var_type) {
return "gpointer";
......@@ -176,21 +176,44 @@ public class Vala.DataType : CodeNode {
return "const %s%s".printf (t.get_cname (), ptr);
}
/**
* Returns a user-readable name of the type corresponding to this type
* reference.
*
* @return display name
*/
public string! to_string () {
public override string! to_string () {
string s;
if (data_type != null) {
return data_type.get_full_name ();
s = data_type.get_full_name ();
} else if (type_parameter != null) {
return type_parameter.name;
s = type_parameter.name;
} else {
return "null";
s = "null";
}
var type_args = get_type_arguments ();
if (!(data_type is Array) && type_args.size > 0) {
s += "<";
bool first = true;
foreach (DataType type_arg in type_args) {
if (!first) {
s += ",";
} else {
first = false;
}
if (!type_arg.takes_ownership) {
s += "weak ";
}
if (type_arg.data_type != null) {
s += type_arg.data_type.get_full_name ();
} else {
s += type_arg.type_parameter.name;
}
}
s += ">";
}
if (non_null) {
s += "!";
}
return s;
}
/**
......@@ -307,4 +330,31 @@ public class Vala.DataType : CodeNode {
}
}
}
/**
* Returns whether instances of this type are invokable.
*
* @return true if invokable, false otherwise
*/
public virtual bool is_invokable () {
return false;
}
/**
* Returns the return type of this invokable.
*
* @return return type
*/
public virtual DataType get_return_type () {
return null;
}
/**
* Returns copy of the list of invocation parameters.
*
* @return parameter list
*/
public virtual Collection<FormalParameter> get_parameters () {
return null;
}
}
/* valadelegatetype.vala
*
* Copyright (C) 2007 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>
*/
using GLib;
using Gee;
/**
* The type of an instance of a delegate.
*/
public class Vala.DelegateType : DataType {
public Callback delegate_symbol { get; set; }
public DelegateType (construct Callback delegate_symbol) {
}
public override bool is_invokable () {
return true;
}
public override DataType get_return_type () {
return delegate_symbol.return_type;
}
public override Collection<FormalParameter> get_parameters () {
return delegate_symbol.get_parameters ();
}
public override string! to_string () {
return delegate_symbol.get_full_name ();
}
public override DataType! copy () {
return new DelegateType (delegate_symbol);
}
public override string get_cname (bool var_type = false, bool const_type = false) {
return delegate_symbol.get_cname (const_type);
}
}
......@@ -26,7 +26,7 @@ using Gee;
/**
* Represents a type or namespace field.
*/
public class Vala.Field : Member, Invokable, Lockable {
public class Vala.Field : Member, Lockable {
/**
* The data type of this field.
*/
......@@ -151,28 +151,6 @@ public class Vala.Field : Member, Invokable, Lockable {
}
}
public Collection<FormalParameter> get_parameters () {
if (!is_invokable ()) {
return null;
}
var cb = (Callback) type_reference.data_type;
return cb.get_parameters ();
}
public DataType get_return_type () {
if (!is_invokable ()) {
return null;
}
var cb = (Callback) type_reference.data_type;
return cb.return_type;
}
public bool is_invokable () {
return (type_reference.data_type is Callback);
}
public bool get_lock_used () {
return lock_used;
}
......
......@@ -27,7 +27,7 @@ using Gee;
/**
* Represents a formal parameter in method and callback signatures.
*/
public class Vala.FormalParameter : Symbol, Invokable {
public class Vala.FormalParameter : Symbol {
/**
* The parameter type.
*/
......@@ -106,28 +106,6 @@ public class Vala.FormalParameter : Symbol, Invokable {
}
}
public Collection<FormalParameter> get_parameters () {
if (!is_invokable ()) {
return null;
}
var cb = (Callback) type_reference.data_type;
return cb.get_parameters ();
}
public DataType get_return_type () {
if (!is_invokable ()) {
return null;
}
var cb = (Callback) type_reference.data_type;
return cb.return_type;
}
public bool is_invokable () {
return (type_reference.data_type is Callback);
}
public override void replace_type (DataType! old_type, DataType! new_type) {
if (type_reference == old_type) {
type_reference = new_type;
......
......@@ -660,36 +660,7 @@ public class Vala.InterfaceWriter : CodeVisitor {
}
private void write_type (DataType! type) {
if (type.data_type != null) {
write_string (type.data_type.get_full_name ());
} else {
write_string (type.type_parameter.name);
}
var type_args = type.get_type_arguments ();
if (!(type.data_type is Array) && type_args.size > 0) {
write_string ("<");
bool first = true;
foreach (DataType type_arg in type_args) {
if (!first) {
write_string (",");
} else {
first = false;
}
if (!type_arg.takes_ownership) {
write_string ("weak ");
}
if (type_arg.data_type != null) {
write_string (type_arg.data_type.get_full_name ());
} else {
write_string (type_arg.type_parameter.name);
}
}
write_string (">");
}
if (type.non_null) {
write_string ("!");
}
write_string (type.to_string ());
}
private void write_string (string! s) {
......
......@@ -205,8 +205,8 @@ public class Vala.MemoryManager : CodeVisitor {
public override void visit_invocation_expression (InvocationExpression! expr) {
expr.accept_children (this);
var msym = (Invokable) expr.call.symbol_reference;
Collection<FormalParameter> params = msym.get_parameters ();
var mtype = expr.call.static_type;
Collection<FormalParameter> params = mtype.get_parameters ();
Iterator<FormalParameter> params_it = params.iterator ();
foreach (Expression arg in expr.get_argument_list ()) {
......@@ -220,7 +220,7 @@ public class Vala.MemoryManager : CodeVisitor {
if (is_ref && param.type_reference.type_parameter != null) {
if (expr.call is MemberAccess) {
var ma = (MemberAccess) expr.call;
var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference, expr);
var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, ma.symbol_reference, param.type_reference, expr);
if (param_type != null) {
is_ref = param_type.takes_ownership;
}
......@@ -244,11 +244,11 @@ public class Vala.MemoryManager : CodeVisitor {
public override void visit_object_creation_expression (ObjectCreationExpression! expr) {
expr.accept_children (this);
if (!(expr.symbol_reference is Invokable)) {
if (!(expr.symbol_reference is Method)) {
return;
}
var msym = (Invokable) expr.symbol_reference;
var msym = (Method) expr.symbol_reference;
Collection<FormalParameter> params = msym.get_parameters ();
Iterator<FormalParameter> params_it = params.iterator ();
......
......@@ -27,7 +27,7 @@ using Gee;
/**
* Represents a type or namespace method.
*/
public class Vala.Method : Member, Invokable {
public class Vala.Method : Member {
public const string DEFAULT_SENTINEL = "NULL";
/**
......@@ -202,14 +202,6 @@ public class Vala.Method : Member, Invokable {
public Collection<FormalParameter> get_parameters () {
return new ReadOnlyCollection<FormalParameter> (parameters);
}
public DataType get_return_type () {
return return_type;
}
public bool is_invokable () {
return true;
}
public override void accept (CodeVisitor! visitor) {
visitor.visit_method (this);
......
/* valainvokable.vala
/* valamethodtype.vala
*
* Copyright (C) 2006-2007 Jürg Billeter
* Copyright (C) 2007 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
......@@ -24,27 +24,23 @@ using GLib;
using Gee;
/**
* Represents a possibly invokable code object.
* The type of a method referencea.
*/
public interface Vala.Invokable : Symbol {
/**
* Returns whether this code object is invokable.
*
* @return true if invokable, false otherwise
*/
public abstract bool is_invokable ();
/**
* Returns the return type of this invokable.
*
* @return return type
*/
public abstract DataType get_return_type ();
/**
* Returns copy of the list of invocation parameters.
*
* @return parameter list
*/
public abstract Collection<FormalParameter> get_parameters ();
public class Vala.MethodType : DataType {
public Method method_symbol { get; set; }
public MethodType (construct Method method_symbol) {
}
public override bool is_invokable () {
return true;
}
public override DataType get_return_type () {
return method_symbol.return_type;
}
public override Collection<FormalParameter> get_parameters () {
return method_symbol.get_parameters ();
}
}
......@@ -1219,6 +1219,10 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
return decl.type_reference;
} else if (sym is EnumValue) {
return new ValueType ((Typesymbol) sym.parent_symbol);
} else if (sym is Method) {
return new MethodType ((Method) sym);
} else if (sym is Signal) {
return new SignalType ((Signal) sym);
}
return null;
}
......@@ -1437,6 +1441,10 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
private bool is_type_compatible (DataType! expression_type, DataType! expected_type) {
if (expected_type is DelegateType && expression_type is DelegateType) {
return ((DelegateType) expected_type).delegate_symbol == ((DelegateType) expression_type).delegate_symbol;
}
/* only null is compatible to null */
if (expected_type.data_type == null && expected_type.type_parameter == null) {
return (expression_type.data_type == null && expected_type.type_parameter == null);
......@@ -1527,25 +1535,18 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
}
var msym = expr.call.symbol_reference;
var mtype = expr.call.static_type;
if (msym == null) {
/* if no symbol found, skip this check */
if (mtype == null) {
/* if no type found, skip this check */
expr.error = true;
return;
}
Collection<FormalParameter> params;
if (msym is Invokable) {
var m = (Invokable) msym;
if (m.is_invokable ()) {
params = m.get_parameters ();
} else {
expr.error = true;
Report.error (expr.source_reference, "invocation not supported in this context");
return;
}
if (mtype.is_invokable ()) {
params = mtype.get_parameters ();
} else {
expr.error = true;
Report.error (expr.source_reference, "invocation not supported in this context");
......@@ -1573,57 +1574,54 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
DataType ret_type;
if (msym is Invokable) {
var m = (Invokable) msym;
ret_type = m.get_return_type ();
params = m.get_parameters ();
ret_type = mtype.get_return_type ();
params = mtype.get_parameters ();
if (ret_type.data_type == null && ret_type.type_parameter == null) {
// void return type
if (!(expr.parent_node is ExpressionStatement)) {
expr.error = true;
Report.error (expr.source_reference, "invocation of void method not allowed as expression");
return;
}
if (ret_type.data_type == null && ret_type.type_parameter == null) {
// void return type
if (!(expr.parent_node is ExpressionStatement)) {
expr.error = true;
Report.error (expr.source_reference, "invocation of void method not allowed as expression");
return;
}
}
// resolve generic return values
if (ret_type.type_parameter != null) {
if (!(expr.call is MemberAccess)) {
Report.error (((CodeNode) m).source_reference, "internal error: unsupported generic return value");
expr.error = true;
return;
}
var ma = (MemberAccess) expr.call;
if (ma.inner == null) {
// TODO resolve generic return values within the type hierarchy if possible
Report.error (expr.source_reference, "internal error: resolving generic return values within type hierarchy not supported yet");
expr.error = true;
// resolve generic return values
if (ret_type.type_parameter != null) {
if (!(expr.call is MemberAccess)) {
Report.error (expr.source_reference, "internal error: unsupported generic return value");
expr.error = true;
return;
}
var ma = (MemberAccess) expr.call;
if (ma.inner == null) {
// TODO resolve generic return values within the type hierarchy if possible
Report.error (expr.source_reference, "internal error: resolving generic return values within type hierarchy not supported yet");
expr.error = true;
return;
} else {
ret_type = get_actual_type (ma.inner.static_type, ma.symbol_reference, ret_type, expr);
if (ret_type == null) {
return;
} else {
ret_type = get_actual_type (ma.inner.static_type, msym, ret_type, expr);
if (ret_type == null) {
return;
}
}
}
}
if (msym is Method) {
var m = (Method) msym;
if (mtype is MethodType) {
var m = ((MethodType) mtype).method_symbol;
expr.tree_can_fail = expr.can_fail = (m.get_error_domains ().size > 0);
}
expr.static_type = ret_type;
check_arguments (expr, msym, params, expr.get_argument_list ());
check_arguments (expr, mtype, params, expr.get_argument_list ());
}
private bool check_arguments (Expression! expr, Symbol! msym, Collection<FormalParameter> params, Collection<Expression> args) {
private bool check_arguments (Expression! expr, DataType! mtype, Collection<FormalParameter> params, Collection<Expression> args) {
Expression prev_arg = null;
Iterator<Expression> arg_it = args.iterator ();
bool diag = (msym.get_attribute ("Diagnostics") != null);
bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
bool ellipsis = false;
int i = 0;
......@@ -1641,7 +1639,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
if (!arg_it.next ()) {
if (param.default_expression == null) {
expr.error = true;
Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.size));
Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
return false;
}
} else {
......@@ -1652,7 +1650,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
return false;
} else if (arg.static_type == null) {
// disallow untyped arguments except for type inference of callbacks
if (!(param.type_reference.data_type is Callback) || !(arg.symbol_reference is Method)) {
if (!(param.type_reference is DelegateType) || !(arg.symbol_reference is Method)) {
expr.error = true;
Report.error (expr.source_reference, "Invalid type for argument %d".printf (i + 1));
return false;
......@@ -1689,7 +1687,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
} else if (!ellipsis && arg_it.next ()) {
expr.error = true;
Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.size));
Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
return false;
}
......@@ -1996,7 +1994,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
if (expr.symbol_reference is Method) {
var m = (Method) expr.symbol_reference;
check_arguments (expr, m, m.get_parameters (), expr.get_argument_list ());
check_arguments (expr, new MethodType (m), m.get_parameters (), expr.get_argument_list ());
expr.tree_can_fail = expr.can_fail = (m.get_error_domains ().size > 0);
} else if (type is Enum) {
......@@ -2564,7 +2562,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
}
public override void visit_lambda_expression (LambdaExpression! l) {
if (l.expected_type == null || !(l.expected_type.data_type is Callback)) {
if (!(l.expected_type is DelegateType)) {
l.error = true;
Report.error (l.source_reference, "lambda expression not allowed in this context");
return;
......@@ -2578,7 +2576,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
in_instance_method = is_in_constructor ();
}
var cb = (Callback) l.expected_type.data_type;
var cb = (Callback) ((DelegateType) l.expected_type).delegate_symbol;
l.method = new Method (get_lambda_name (), cb.return_type);
l.method.instance = cb.instance && in_instance_method;
l.method.owner = current_symbol.scope;
......@@ -2659,8 +2657,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
if (ma.symbol_reference is Signal) {
var sig = (Signal) ma.symbol_reference;
a.right.expected_type = new DataType ();
a.right.expected_type.data_type = sig.get_callback ();
a.right.expected_type = new DelegateType (sig.get_callback ());
} else {
a.right.expected_type = ma.static_type;
}
......
......@@ -26,7 +26,7 @@ using Gee;
/**
* Represents an object signal. Signals enable objects to provide notifications.
*/
public class Vala.Signal : Member, Invokable, Lockable {
public class Vala.Signal : Member, Lockable {
/**
* The return type of handlers of this signal.
*/
......@@ -76,15 +76,7 @@ public class Vala.Signal : Member, Invokable, Lockable {
public Collection<FormalParameter> get_parameters () {
return new ReadOnlyCollection<FormalParameter> (parameters);
}
public DataType get_return_type () {
return return_type;
}
public bool is_invokable () {
return true;
}
/**
* Returns generated callback to be used for signal handlers.
*
......
/* valasignaltype.vala
*
* Copyright (C) 2007 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>
*/
using GLib;
using Gee;
/**
* The type of a signal referencea.
*/
public class Vala.SignalType : DataType {
public Signal signal_symbol { get; set; }
public SignalType (construct Signal signal_symbol) {
}
public override bool is_invokable () {
return true;</