Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region --- License ---
2
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
3
 * See license.txt for license info
4
 */
5
#endregion
6
 
7
using System;
8
using System.Collections.Generic;
9
using System.Text;
10
using System.Text.RegularExpressions;
11
 
12
namespace Bind.Structures
13
{
14
    public class Function : Delegate, IEquatable<Function>, IComparable<Function>
15
    {
16
        #region Static Members
17
 
18
        internal static FunctionCollection Wrappers;
19
 
20
        static bool loaded;
21
 
22
        #region internal static void Initialize()
23
 
24
        internal static void Initialize()
25
        {
26
            if (!loaded)
27
            {
28
                Wrappers = new FunctionCollection();
29
                loaded = true;
30
            }
31
        }
32
 
33
        #endregion
34
 
35
        #endregion
36
 
37
        #region Fields
38
 
39
        Delegate wrapped_delegate;
40
        int index;
41
 
42
        #endregion
43
 
44
        #region --- Constructors ---
45
 
46
        public Function(Delegate d)
47
            : base(d)
48
        {
49
            Name = d.Name;
50
            Body = new FunctionBody();
51
            WrappedDelegate = d;
52
        }
53
 
54
        public Function(Function f)
55
            : this(f.WrappedDelegate)
56
        {
57
            Parameters = new ParameterCollection(f.Parameters);
58
            ReturnType = new Type(f.ReturnType);
59
            Body.AddRange(f.Body);
60
        }
61
 
62
        #endregion
63
 
64
        #region public Delegate WrappedDelegate
65
 
66
        public Delegate WrappedDelegate
67
        {
68
            get { return wrapped_delegate; }
69
            set { wrapped_delegate = value; }
70
        }
71
 
72
        #endregion
73
 
74
        #region public void TurnVoidPointersToIntPtr()
75
 
76
        public void TurnVoidPointersToIntPtr()
77
        {
78
            foreach (Parameter p in Parameters)
79
            {
80
                if (p.Pointer != 0 && p.CurrentType == "void")
81
                {
82
                    p.CurrentType = "IntPtr";
83
                    p.Pointer = 0;
84
                }
85
            }
86
        }
87
 
88
        #endregion
89
 
90
        #region public override bool Unsafe
91
 
92
        public override bool Unsafe
93
        {
94
            get
95
            {
96
                if ((Settings.Compatibility & Settings.Legacy.NoPublicUnsafeFunctions) != Settings.Legacy.None)
97
                    return false;
98
 
99
                return base.Unsafe;
100
            }
101
        }
102
 
103
        #endregion
104
 
105
        #region public FunctionBody Body
106
 
107
        FunctionBody _body;
108
 
109
        public FunctionBody Body
110
        {
111
            get { return _body; }
112
            set { _body = value; }
113
        }
114
 
115
        #endregion
116
 
117
        #region public string TrimmedName
118
 
119
        public string TrimmedName;
120
 
121
        #endregion
122
 
123
        #region public override string Name
124
 
125
        /// <summary>
126
        /// Gets or sets the name of the opengl function.
127
        /// If no Tao compatibility is set, set TrimmedName to Name, after removing
128
        /// [u][bsifd][v].
129
        /// </summary>
130
        public override string Name
131
        {
132
            get { return base.Name; }
133
            set
134
            {
135
                base.Name = value;
136
 
137
                if ((Settings.Compatibility & Settings.Legacy.NoTrimFunctionEnding) != Settings.Legacy.None)
138
                {
139
                    // If we don't need compatibility with Tao,
140
                    // remove the Extension and the overload information from the name
141
                    // (Extension == "ARB", "EXT", etc, overload == [u][bsidf][v])
142
                    // TODO: Use some regex's here, to reduce clutter.
143
                    TrimmedName = value;
144
                }
145
                else
146
                {
147
                    TrimmedName = Utilities.StripGL2Extension(value);
148
 
149
                    Match m = endingsNotToTrim.Match(TrimmedName);
150
                    if ((m.Index + m.Length) != TrimmedName.Length)
151
                    {
152
                        // Some endings should not be trimmed, for example: 'b' from Attrib
153
 
154
                        m = endings.Match(TrimmedName);
155
 
156
                        if (m.Length > 0 && m.Index + m.Length == TrimmedName.Length)
157
                        {
158
                            // Only trim endings, not internal matches.
159
                            if (m.Value[m.Length - 1] == 'v' && endingsAddV.IsMatch(Name) &&
160
                                !Name.StartsWith("Get") && !Name.StartsWith("MatrixIndex"))
161
                            {
162
                                // Only trim ending 'v' when there is a number
163
                                TrimmedName = TrimmedName.Substring(0, m.Index) + "v";
164
                            }
165
                            else
166
                            {
167
                                if (!TrimmedName.EndsWith("xedv"))
168
                                    TrimmedName = TrimmedName.Substring(0, m.Index);
169
                                else
170
                                    TrimmedName = TrimmedName.Substring(0, m.Index + 1);
171
                            }
172
                        }
173
                    }
174
                }
175
            }
176
        }
177
 
178
        #endregion
179
 
180
        #region public override string ToString()
181
 
182
        public override string ToString()
183
        {
184
            StringBuilder sb = new StringBuilder();
185
 
186
            sb.Append(Unsafe ? "unsafe " : "");
187
            sb.Append(ReturnType);
188
            sb.Append(" ");
189
            if ((Settings.Compatibility & Settings.Legacy.NoTrimFunctionEnding) != Settings.Legacy.None)
190
            {
191
                sb.Append(Settings.FunctionPrefix);
192
            }
193
            sb.Append(!String.IsNullOrEmpty(TrimmedName) ? TrimmedName : Name);
194
 
195
            if (Parameters.HasGenericParameters)
196
            {
197
                sb.Append("<");
198
                foreach (Parameter p in Parameters)
199
                {
200
                    if (p.Generic)
201
                    {
202
                        sb.Append(p.CurrentType);
203
                        sb.Append(",");
204
                    }
205
                }
206
                sb.Remove(sb.Length - 1, 1);
207
                sb.Append(">");
208
            }
209
            sb.AppendLine(Parameters.ToString(false));
210
            if (Parameters.HasGenericParameters)
211
            {
212
                foreach (Parameter p in Parameters)
213
                {
214
                    if (p.Generic)
215
                        sb.AppendLine(String.Format("    where {0} : struct", p.CurrentType));
216
                }
217
 
218
            }
219
 
220
            if (Body.Count > 0)
221
            {
222
                sb.Append(Body.ToString());
223
            }
224
 
225
            return sb.ToString();
226
        }
227
 
228
        #endregion
229
 
230
        #region IEquatable<Function> Members
231
 
232
        public bool Equals(Function other)
233
        {
234
            return
235
                !String.IsNullOrEmpty(TrimmedName) && !String.IsNullOrEmpty(other.TrimmedName) &&
236
                TrimmedName == other.TrimmedName &&
237
                Parameters.ToString(true) == other.Parameters.ToString(true);
238
        }
239
 
240
        #endregion
241
 
242
        #region public void WrapParameters(List<Function> wrappers)
243
 
244
        public void WrapParameters(List<Function> wrappers)
245
        {
246
            Function f;
247
 
248
            if (Parameters.HasPointerParameters)
249
            {
250
                Function _this = new Function(this);
251
                // Array overloads
252
                foreach (Parameter p in _this.Parameters)
253
                {
254
                    if (p.WrapperType == WrapperTypes.ArrayParameter && p.ElementCount != 1)
255
                    {
256
                        p.Reference = false;
257
                        p.Array++;
258
                        p.Pointer--;
259
                    }
260
                }
261
                f = new Function(_this);
262
                f.CreateBody(false);
263
                wrappers.Add(f);
264
                new Function(f).WrapVoidPointers(wrappers);
265
 
266
                _this = new Function(this);
267
                // Reference overloads
268
                foreach (Parameter p in _this.Parameters)
269
                {
270
                    if (p.WrapperType == WrapperTypes.ArrayParameter)
271
                    {
272
                        p.Reference = true;
273
                        p.Array--;
274
                        p.Pointer--;
275
                    }
276
                }
277
                f = new Function(_this);
278
                f.CreateBody(false);
279
                wrappers.Add(f);
280
                new Function(f).WrapVoidPointers(wrappers);
281
 
282
                _this = this;
283
                // Pointer overloads
284
                // Should be last to work around Intellisense bug, where
285
                // array overloads are not reported if there is a pointer overload.
286
                foreach (Parameter p in _this.Parameters)
287
                {
288
                    if (p.WrapperType == WrapperTypes.ArrayParameter)
289
                    {
290
                        p.Reference = false;
291
                        //p.Array--;
292
                        //p.Pointer++;
293
                    }
294
                }
295
                f = new Function(_this);
296
                f.CreateBody(false);
297
                wrappers.Add(f);
298
                new Function(f).WrapVoidPointers(wrappers);
299
            }
300
            else
301
            {
302
                f = new Function(this);
303
                f.CreateBody(false);
304
                wrappers.Add(f);
305
            }
306
        }
307
 
308
        #endregion
309
 
310
        #region public void WrapVoidPointers(List<Function> wrappers)
311
 
312
        public void WrapVoidPointers(List<Function> wrappers)
313
        {
314
            if (index >= 0 && index < Parameters.Count)
315
            {
316
                if (Parameters[index].WrapperType == WrapperTypes.GenericParameter)
317
                {
318
                    // Recurse to the last parameter
319
                    ++index;
320
                    WrapVoidPointers(wrappers);
321
                    --index;
322
 
323
                    // On stack rewind, create generic wrappers
324
                    Parameters[index].Reference = true;
325
                    Parameters[index].Array = 0;
326
                    Parameters[index].Pointer = 0;
327
                    Parameters[index].Generic = true;
328
                    Parameters[index].CurrentType = "T" + index.ToString();
329
                    Parameters[index].Flow = FlowDirection.Undefined;
330
                    Parameters.Rebuild = true;
331
                    CreateBody(false);
332
                    wrappers.Add(new Function(this));
333
 
334
                    Parameters[index].Reference = false;
335
                    Parameters[index].Array = 1;
336
                    Parameters[index].Pointer = 0;
337
                    Parameters[index].Generic = true;
338
                    Parameters[index].CurrentType = "T" + index.ToString();
339
                    Parameters[index].Flow = FlowDirection.Undefined;
340
                    Parameters.Rebuild = true;
341
                    CreateBody(false);
342
                    wrappers.Add(new Function(this));
343
 
344
                    Parameters[index].Reference = false;
345
                    Parameters[index].Array = 2;
346
                    Parameters[index].Pointer = 0;
347
                    Parameters[index].Generic = true;
348
                    Parameters[index].CurrentType = "T" + index.ToString();
349
                    Parameters[index].Flow = FlowDirection.Undefined;
350
                    Parameters.Rebuild = true;
351
                    CreateBody(false);
352
                    wrappers.Add(new Function(this));
353
 
354
                    Parameters[index].Reference = false;
355
                    Parameters[index].Array = 3;
356
                    Parameters[index].Pointer = 0;
357
                    Parameters[index].Generic = true;
358
                    Parameters[index].CurrentType = "T" + index.ToString();
359
                    Parameters[index].Flow = FlowDirection.Undefined;
360
                    Parameters.Rebuild = true;
361
                    CreateBody(false);
362
                    wrappers.Add(new Function(this));
363
                }
364
                else
365
                {
366
                    // Recurse to the last parameter
367
                    ++index;
368
                    WrapVoidPointers(wrappers);
369
                    --index;
370
                }
371
            }
372
        }
373
 
374
        #endregion
375
 
376
        #region public void WrapReturnType()
377
 
378
        public void WrapReturnType()
379
        {
380
            switch (ReturnType.WrapperType)
381
            {
382
                case WrapperTypes.StringReturnType:
383
                    ReturnType.QualifiedType = "String";
384
                    break;
385
            }
386
        }
387
 
388
        #endregion
389
 
390
        #region public void CreateBody(bool wantCLSCompliance)
391
 
392
        readonly static List<string> handle_statements = new List<string>();
393
        readonly static List<string> handle_release_statements = new List<string>();
394
        readonly static List<string> fixed_statements = new List<string>();
395
        readonly static List<string> assign_statements = new List<string>();
396
 
397
        // For example, if parameter foo has indirection level = 1, then it
398
        // is consumed as 'foo*' in the fixed_statements and the call string.
399
        string[] indirection_levels = new string[] { "", "*", "**", "***", "****" };
400
 
401
        public void CreateBody(bool wantCLSCompliance)
402
        {
403
            Function f = new Function(this);
404
 
405
            f.Body.Clear();
406
            handle_statements.Clear();
407
            handle_release_statements.Clear();
408
            fixed_statements.Clear();
409
            assign_statements.Clear();
410
 
411
            // Obtain pointers by pinning the parameters
412
            foreach (Parameter p in f.Parameters)
413
            {
414
                if (p.NeedsPin)
415
                {
416
                    if (p.WrapperType == WrapperTypes.GenericParameter)
417
                    {
418
                        // Use GCHandle to obtain pointer to generic parameters and 'fixed' for arrays.
419
                        // This is because fixed can only take the address of fields, not managed objects.
420
                        handle_statements.Add(String.Format(
421
                            "{0} {1}_ptr = {0}.Alloc({1}, GCHandleType.Pinned);",
422
                            "GCHandle", p.Name));
423
 
424
                        handle_release_statements.Add(String.Format("{0}_ptr.Free();", p.Name));
425
 
426
                        // Due to the GCHandle-style pinning (which boxes value types), we need to assign the modified
427
                        // value back to the reference parameter (but only if it has an out or in/out flow direction).
428
                        if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
429
                        {
430
                            assign_statements.Add(String.Format(
431
                                "{0} = ({1}){0}_ptr.Target;",
432
                                p.Name, p.QualifiedType));
433
                        }
434
 
435
                        // Note! The following line modifies f.Parameters, *not* this.Parameters
436
                        p.Name = "(IntPtr)" + p.Name + "_ptr.AddrOfPinnedObject()";
437
                    }
438
                    else if (p.WrapperType == WrapperTypes.PointerParameter ||
439
                        p.WrapperType == WrapperTypes.ArrayParameter ||
440
                        p.WrapperType == WrapperTypes.ReferenceParameter)
441
                    {
442
                        // A fixed statement is issued for all non-generic pointers, arrays and references.
443
                        fixed_statements.Add(String.Format(
444
                            "fixed ({0}{3} {1} = {2})",
445
                            wantCLSCompliance && !p.CLSCompliant ? p.GetCLSCompliantType() : p.QualifiedType,
446
                            p.Name + "_ptr",
447
                            p.Array > 0 ? p.Name : "&" + p.Name,
448
                            indirection_levels[p.IndirectionLevel]));
449
 
450
                        if (p.Name == "pixels_ptr")
451
                            System.Diagnostics.Debugger.Break();
452
 
453
                        // Arrays are not value types, so we don't need to do anything for them.
454
                        // Pointers are passed directly by value, so we don't need to assign them back either (they don't change).
455
                        if ((p.Flow == FlowDirection.Out || p.Flow == FlowDirection.Undefined) && p.Reference)
456
                        {
457
                            assign_statements.Add(String.Format("{0} = *{0}_ptr;", p.Name));
458
                        }
459
 
460
                        p.Name = p.Name + "_ptr";
461
                    }
462
                    else
463
                    {
464
                        throw new ApplicationException("Unknown parameter type");
465
                    }
466
                }
467
            }
468
 
469
            // Automatic OpenGL error checking.
470
            // See OpenTK.Graphics.ErrorHelper for more information.
471
            // Make sure that no error checking is added to the GetError function,
472
            // as that would cause infinite recursion!
473
            if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
474
            {
475
                if (f.TrimmedName != "GetError")
476
                {
477
                    f.Body.Add("#if DEBUG");
478
                    f.Body.Add("using (new ErrorHelper(GraphicsContext.CurrentContext))");
479
                    f.Body.Add("{");
480
                    if (f.TrimmedName == "Begin")
481
                        f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = false;");
482
                    f.Body.Add("#endif");
483
                }
484
            }
485
 
486
            if (!f.Unsafe && fixed_statements.Count > 0)
487
            {
488
                f.Body.Add("unsafe");
489
                f.Body.Add("{");
490
                f.Body.Indent();
491
            }
492
 
493
            if (fixed_statements.Count > 0)
494
            {
495
                f.Body.AddRange(fixed_statements);
496
                f.Body.Add("{");
497
                f.Body.Indent();
498
            }
499
 
500
            if (handle_statements.Count > 0)
501
            {
502
                f.Body.AddRange(handle_statements);
503
                f.Body.Add("try");
504
                f.Body.Add("{");
505
                f.Body.Indent();
506
            }
507
 
508
            // Hack: When creating untyped enum wrappers, it is possible that the wrapper uses an "All"
509
            // enum, while the delegate uses a specific enum (e.g. "TextureUnit"). For this reason, we need
510
            // to modify the parameters before generating the call string.
511
            // Note: We cannot generate a callstring using WrappedDelegate directly, as its parameters will
512
            // typically be different than the parameters of the wrapper. We need to modify the parameters
513
            // of the wrapper directly.
514
            if ((Settings.Compatibility & Settings.Legacy.KeepUntypedEnums) != 0)
515
            {
516
                int parameter_index = -1; // Used for comparing wrapper parameters with delegate parameters
517
                foreach (Parameter p in f.Parameters)
518
                {
519
                    parameter_index++;
520
                    if (p.IsEnum && p.QualifiedType != f.WrappedDelegate.Parameters[parameter_index].QualifiedType)
521
                    {
522
                        p.QualifiedType = f.WrappedDelegate.Parameters[parameter_index].QualifiedType;
523
                    }
524
                }
525
            }
526
 
527
            if (assign_statements.Count > 0)
528
            {
529
                // Call function
530
                string method_call = f.CallString();
531
                if (f.ReturnType.CurrentType.ToLower().Contains("void"))
532
                    f.Body.Add(String.Format("{0};", method_call));
533
                else if (ReturnType.CurrentType.ToLower().Contains("string"))
534
                    f.Body.Add(String.Format("{0} {1} = null; unsafe {{ {1} = new string((sbyte*){2}); }}",
535
                        ReturnType.QualifiedType, "retval", method_call));
536
                else
537
                    f.Body.Add(String.Format("{0} {1} = {2};", f.ReturnType.QualifiedType, "retval", method_call));
538
 
539
                // Assign out parameters
540
                f.Body.AddRange(assign_statements);
541
 
542
                // Return
543
                if (!f.ReturnType.CurrentType.ToLower().Contains("void"))
544
                {
545
                    f.Body.Add("return retval;");
546
                }
547
            }
548
            else
549
            {
550
                // Call function and return
551
                if (f.ReturnType.CurrentType.ToLower().Contains("void"))
552
                    f.Body.Add(String.Format("{0};", f.CallString()));
553
                else if (ReturnType.CurrentType.ToLower().Contains("string"))
554
                    f.Body.Add(String.Format("unsafe {{ return new string((sbyte*){0}); }}",
555
                        f.CallString()));
556
                else
557
                    f.Body.Add(String.Format("return {0};", f.CallString()));
558
            }
559
 
560
 
561
            // Free all allocated GCHandles
562
            if (handle_statements.Count > 0)
563
            {
564
                f.Body.Unindent();
565
                f.Body.Add("}");
566
                f.Body.Add("finally");
567
                f.Body.Add("{");
568
                f.Body.Indent();
569
 
570
                f.Body.AddRange(handle_release_statements);
571
 
572
                f.Body.Unindent();
573
                f.Body.Add("}");
574
            }
575
 
576
            if (!f.Unsafe && fixed_statements.Count > 0)
577
            {
578
                f.Body.Unindent();
579
                f.Body.Add("}");
580
            }
581
 
582
            if (fixed_statements.Count > 0)
583
            {
584
                f.Body.Unindent();
585
                f.Body.Add("}");
586
            }
587
 
588
            if ((Settings.Compatibility & Settings.Legacy.NoDebugHelpers) == 0)
589
            {
590
                if (f.TrimmedName != "GetError")
591
                {
592
                    f.Body.Add("#if DEBUG");
593
                    if (f.TrimmedName == "End")
594
                        f.Body.Add("GraphicsContext.CurrentContext.ErrorChecking = true;");
595
                    f.Body.Add("}");
596
                    f.Body.Add("#endif");
597
                }
598
            }
599
 
600
            Body = f.Body;
601
        }
602
 
603
        #endregion
604
 
605
        #region IComparable<Function> Members
606
 
607
        public int CompareTo(Function other)
608
        {
609
            int ret = Name.CompareTo(other.Name);
610
            if (ret == 0)
611
                ret = Parameters.CompareTo(other.Parameters);
612
            if (ret == 0)
613
                ret = ReturnType.CompareTo(other.ReturnType);
614
            return ret;
615
        }
616
 
617
        #endregion
618
    }
619
 
620
    #region class FunctionBody : List<string>
621
 
622
    public class FunctionBody : List<string>
623
    {
624
        public FunctionBody()
625
        {
626
        }
627
 
628
        public FunctionBody(FunctionBody fb)
629
        {
630
            foreach (string s in fb)
631
            {
632
                Add(s);
633
            }
634
        }
635
 
636
        private string indent = "";
637
 
638
        public void Indent()
639
        {
640
            indent += "    ";
641
        }
642
 
643
        public void Unindent()
644
        {
645
            if (indent.Length >= 4)
646
                indent = indent.Substring(4);
647
        }
648
 
649
        new public void Add(string s)
650
        {
651
            base.Add(indent + s);
652
        }
653
 
654
        new public void AddRange(IEnumerable<string> collection)
655
        {
656
            foreach (string t in collection)
657
            {
658
                Add(t);
659
            }
660
        }
661
 
662
        public override string ToString()
663
        {
664
            if (Count == 0)
665
                return String.Empty;
666
 
667
            StringBuilder sb = new StringBuilder(Count);
668
 
669
            sb.AppendLine("{");
670
            foreach (string s in this)
671
            {
672
                sb.AppendLine("    " + s);
673
            }
674
            sb.Append("}");
675
 
676
            return sb.ToString();
677
        }
678
    }
679
 
680
    #endregion
681
 
682
    #region class FunctionCollection : SortedDictionary<string, List<Function>>
683
 
684
    class FunctionCollection : SortedDictionary<string, List<Function>>
685
    {
686
        Regex unsignedFunctions = new Regex(@".+(u[dfisb]v?)", RegexOptions.Compiled);
687
 
688
        public void Add(Function f)
689
        {
690
            if (!ContainsKey(f.Extension))
691
            {
692
                Add(f.Extension, new List<Function>());
693
                this[f.Extension].Add(f);
694
            }
695
            else
696
            {
697
                this[f.Extension].Add(f);
698
            }
699
        }
700
 
701
        public void AddRange(IEnumerable<Function> functions)
702
        {
703
            foreach (Function f in functions)
704
            {
705
                Add(f);
706
            }
707
        }
708
 
709
        /// <summary>
710
        /// Adds the function to the collection, if a function with the same name and parameters doesn't already exist.
711
        /// </summary>
712
        /// <param name="f">The Function to add.</param>
713
        public void AddChecked(Function f)
714
        {
715
            if (Function.Wrappers.ContainsKey(f.Extension))
716
            {
717
                int index = Function.Wrappers[f.Extension].IndexOf(f);
718
                if (index == -1)
719
                {
720
                    Function.Wrappers.Add(f);
721
                }
722
                else
723
                {
724
                    Function existing = Function.Wrappers[f.Extension][index];
725
                    if ((existing.Parameters.HasUnsignedParameters && !unsignedFunctions.IsMatch(existing.Name) && unsignedFunctions.IsMatch(f.Name)) ||
726
                        (!existing.Parameters.HasUnsignedParameters && unsignedFunctions.IsMatch(existing.Name) && !unsignedFunctions.IsMatch(f.Name)))
727
                    {
728
                        Function.Wrappers[f.Extension].RemoveAt(index);
729
                        Function.Wrappers[f.Extension].Add(f);
730
                    }
731
                }
732
            }
733
            else
734
            {
735
                Function.Wrappers.Add(f);
736
            }
737
        }
738
    }
739
 
740
    #endregion
741
}