using System.Reflection.Emit;
using System.Collections;
-namespace Mono.CSharp {
+namespace Mono.MonoBASIC {
/// <summary>
/// Represents a single method parameter
/// </summary>
- public class Parameter {
+ public class Parameter : Attributable {
+ ParameterBuilder builder;
+
[Flags]
public enum Modifier : byte {
- NONE = 0,
- REF = 1,
- OUT = 2,
- PARAMS = 4,
+ NONE = 0,
+ VAL = 0,
+ REF = 1,
+ OUT = 2,
+ PARAMS = 4,
+ // This is a flag which says that it's either REF or OUT.
+ ISBYREF = 8,
+ OPTIONAL = 16
}
- public readonly string TypeName;
- public readonly string Name;
+ public readonly Expression TypeName;
public readonly Modifier ModFlags;
- public Attributes OptAttributes;
+ public readonly string Name;
public Type parameter_type;
-
- public Parameter (string type, string name, Modifier mod, Attributes attrs)
+ public readonly Expression ParameterInitializer;
+ public readonly bool IsOptional;
+
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs)
+ : base (attrs)
{
Name = name;
ModFlags = mod;
TypeName = type;
- OptAttributes = attrs;
+ ParameterInitializer = null;
+ IsOptional = false;
}
- // <summary>
- // Resolve is used in method definitions
- // </summary>
- public bool Resolve (DeclSpace ds, Location l)
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi)
+ : base (attrs)
{
- parameter_type = RootContext.LookupType (ds, TypeName, false, l);
- return parameter_type != null;
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ ParameterInitializer = pi;
+ IsOptional = false;
+ }
+
+ public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
+ {
+ if (a.Type == TypeManager.marshal_as_attr_type) {
+ UnmanagedMarshal marshal = UnmanagedMarshal.DefineUnmanagedMarshal (a.UnmanagedType);
+ builder.SetMarshal (marshal);
+ } else
+ builder.SetCustomAttribute (cb);
}
+ public Parameter (Expression type, string name, Modifier mod, Attributes attrs, Expression pi, bool opt)
+ : base (attrs)
+ {
+ Name = name;
+ ModFlags = mod;
+ TypeName = type;
+ ParameterInitializer = pi;
+ IsOptional = opt;
+ }
+
+ public override AttributeTargets AttributeTargets {
+ get {
+ return AttributeTargets.Parameter;
+ }
+ }
+
// <summary>
- // ResolveAndDefine is used by delegate declarations, because
- // they happen during the initial tree resolution process
+ // Resolve is used in method definitions
// </summary>
- public bool ResolveAndDefine (DeclSpace ds)
+ public bool Resolve (DeclSpace ds, Location l)
{
- parameter_type = ds.FindType (TypeName);
+ parameter_type = ds.ResolveType (TypeName, false, l);
+
+ if (parameter_type == TypeManager.void_type){
+ Report.Error (1536, l, "`void' parameter is not permitted");
+ return false;
+ }
+
return parameter_type != null;
}
-
+
public Type ExternalType (DeclSpace ds, Location l)
{
- if ((ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
+ if ((ModFlags & Parameter.Modifier.ISBYREF) != 0){
string n = parameter_type.FullName + "&";
Type t = RootContext.LookupType (ds, n, false, l);
public ParameterAttributes Attributes {
get {
- switch (ModFlags){
+ int flags = ((int) ModFlags) & ~((int) Parameter.Modifier.ISBYREF);
+ switch ((Modifier) flags) {
case Modifier.NONE:
return ParameterAttributes.None;
case Modifier.REF:
return ParameterAttributes.None;
case Modifier.OUT:
return ParameterAttributes.Out;
+ case Modifier.OPTIONAL:
+ return ParameterAttributes.Optional;
case Modifier.PARAMS:
return 0;
}
return ExternalType (ds, loc).FullName;
}
+
+ public void DefineParameter (EmitContext ec, MethodBuilder mb, ConstructorBuilder cb, int index, Location loc)
+ {
+ if (mb == null)
+ builder = cb.DefineParameter (index, Attributes, Name);
+ else
+ builder = mb.DefineParameter (index, Attributes, Name);
+
+ if (ParameterInitializer != null) {
+ if (ParameterInitializer is MemberAccess) {
+ MemberAccess ma = ParameterInitializer as MemberAccess;
+
+ Expression const_ex = ma.Resolve(ec);
+ if (const_ex is EnumConstant)
+ builder.SetConstant (((EnumConstant) const_ex).Child.GetValue());
+ else
+ Report.Error(-1, "Internal error - Non supported argument type in optional parameter");
+ }
+ else
+ builder.SetConstant (((Constant) ParameterInitializer).GetValue());
+ }
+
+ if (OptAttributes != null)
+ OptAttributes.Emit (ec, this);
+ }
}
/// <summary>
ArrayParameter = array_parameter;
loc = l;
}
-
+
/// <summary>
/// This is used to reuse a set of empty parameters, because they
/// are common
/// </summary>
- public static Parameters GetEmptyReadOnlyParameters ()
+ public static Parameters EmptyReadOnlyParameters {
+ get {
+ if (empty_parameters == null)
+ empty_parameters = new Parameters (null, null, Location.Null);
+
+ return empty_parameters;
+ }
+ }
+
+ public bool HasOptional()
+ {
+ bool res = false;
+
+ foreach (Parameter p in FixedParameters)
+ {
+ if (p.IsOptional)
+ {
+ res = true;
+ break;
+ }
+ }
+ return (res);
+ }
+
+ /// <summary>
+ /// Returns the number of standard (i.e. non-optional) parameters
+ /// </summary>
+ public int CountStandardParams()
+ {
+ int res = 0;
+ if (FixedParameters == null)
+ return 0;
+
+ foreach (Parameter p in FixedParameters) {
+ if (!p.IsOptional)
+ res++;
+ }
+ return (res);
+ }
+
+ /// <summary>
+ /// Returns the number of optional parameters
+ /// </summary>
+ public int CountOptionalParams()
+ {
+ int res = 0;
+ if (FixedParameters == null)
+ return 0;
+
+ foreach (Parameter p in FixedParameters) {
+ if (p.IsOptional)
+ res++;
+ }
+ return (res);
+ }
+
+ public Expression GetDefaultValue (int i)
+ {
+ Parameter p = FixedParameters[i];
+ if (p.IsOptional)
+ return p.ParameterInitializer;
+ else
+ return null;
+ }
+
+ public void AppendParameter (Parameter p)
+ {
+ if (FixedParameters != null)
+ {
+ Parameter [] pa = new Parameter [FixedParameters.Length+1];
+ FixedParameters.CopyTo (pa, 0);
+ pa[FixedParameters.Length] = p;
+ FixedParameters = pa;
+ }
+ else
+ {
+ FixedParameters = new Parameter [1];
+ FixedParameters[0] = p;
+ }
+ }
+
+ public void PrependParameter (Parameter p)
+ {
+ Parameter [] pa = new Parameter [FixedParameters.Length+1];
+ FixedParameters.CopyTo (pa, 1);
+ pa[0] = p;
+ FixedParameters = pa;
+ }
+
+ public Parameters Copy (Location l)
{
- if (empty_parameters == null)
- empty_parameters = new Parameters (null, null, Location.Null);
+ Parameters p = new Parameters (null, null, l);
+ p.FixedParameters = new Parameter[this.FixedParameters.Length];
+ this.FixedParameters.CopyTo (p.FixedParameters, 0);
+
+ return (p);
- return empty_parameters;
}
public bool Empty {
//
}
- static void error100 (string name)
+ static void Error_DuplicateParameterName (string name)
{
Report.Error (
100, "The parameter name `" + name + "' is a duplicate");
for (j = i + 1; j < count; j++){
if (base_name != FixedParameters [j].Name)
continue;
- error100 (base_name);
+ Error_DuplicateParameterName (base_name);
return false;
}
if (base_name == array_par_name){
- error100 (base_name);
+ Error_DuplicateParameterName (base_name);
return false;
}
}
}
}
- if (failed)
- types = null;
-
if (extra > 0){
if (ArrayParameter.Resolve (ds, loc))
types [i] = ArrayParameter.ExternalType (ds, loc);
- else
- return false;
+ else
+ failed = true;
+ }
+
+ if (failed){
+ types = null;
+ return false;
}
return true;
foreach (Parameter p in FixedParameters){
Type t = null;
- if (p.ResolveAndDefine (ds))
+ if (p.Resolve (ds, loc))
t = p.ExternalType (ds, loc);
else
ok_flag = false;
}
if (extra > 0){
- if (ArrayParameter.ResolveAndDefine (ds))
+ if (ArrayParameter.Resolve (ds, loc))
types [i] = ArrayParameter.ExternalType (ds, loc);
else
ok_flag = false;
/// Note that the returned type will not contain any dereference in this
/// case (ie, you get "int" for a ref int instead of "int&"
/// </summary>
- public Type GetParameterInfo (DeclSpace ds, int idx, out bool is_out)
+ public Type GetParameterInfo (DeclSpace ds, int idx, out Parameter.Modifier mod)
{
- is_out = false;
+ mod = Parameter.Modifier.NONE;
if (!VerifyArgs ()){
FixedParameters = null;
return null;
if (types == null)
- if (ComputeParameterTypes (ds) == false){
- is_out = false;
+ if (ComputeParameterTypes (ds) == false)
return null;
- }
//
// If this is a request for the variable lenght arg.
//
int array_idx = (FixedParameters != null ? FixedParameters.Length : 0);
- if (idx == array_idx){
- is_out = false;
+ if (idx == array_idx)
return types [idx];
- }
//
// Otherwise, it is a fixed parameter
//
Parameter p = FixedParameters [idx];
- is_out = ((p.ModFlags & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0);
+ mod = p.ModFlags;
+
+ if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0)
+ mod |= Parameter.Modifier.ISBYREF;
return p.ParameterType;
}
// For now this is the only correc thing to do
return CallingConventions.Standard;
}
- }
-}
-
+ public void LabelParameters (EmitContext ec, MethodBase builder, Location loc)
+ {
+ //
+ // Define each type attribute (in/out/ref) and
+ // the argument names.
+ //
+ Parameter [] p = FixedParameters;
+ int i = 0;
+
+ MethodBuilder mb = null;
+ ConstructorBuilder cb = null;
+ if (builder is MethodBuilder)
+ mb = (MethodBuilder) builder;
+ else
+ cb = (ConstructorBuilder) builder;
+
+ if (p != null){
+ for (i = 0; i < p.Length; i++) {
+ p [i].DefineParameter (ec, mb, cb, i + 1, loc);
+ }
+ }
+
+ if (ArrayParameter != null) {
+ ParameterBuilder pb;
+ Parameter array_param = ArrayParameter;
+
+ if (mb == null)
+ pb = cb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
+ else
+ pb = mb.DefineParameter (i + 1, array_param.Attributes, array_param.Name);
+
+ CustomAttributeBuilder a = new CustomAttributeBuilder (TypeManager.cons_param_array_attribute, new object [0]);
+ pb.SetCustomAttribute (a);
+ }
+ }
+
+ }
+}