1# git-gui simple class/object fake-alike
2# Copyright (C) 2007 Shawn Pearce
3
4proc class {class body} {
5 if {[namespace exists $class]} {
6 error "class $class already declared"
7 }
8 namespace eval $class {
9 variable __nextid 0
10 variable __sealed 0
11 variable __field_list {}
12 variable __field_array
13
14 proc cb {name args} {
15 upvar this this
16 set args [linsert $args 0 $name $this]
17 return [uplevel [list namespace code $args]]
18 }
19 }
20 namespace eval $class $body
21}
22
23proc field {name args} {
24 set class [uplevel {namespace current}]
25 variable ${class}::__sealed
26 variable ${class}::__field_array
27
28 switch [llength $args] {
29 0 { set new [list $name] }
30 1 { set new [list $name [lindex $args 0]] }
31 default { error "wrong # args: field name value?" }
32 }
33
34 if {$__sealed} {
35 error "class $class is sealed (cannot add new fields)"
36 }
37
38 if {[catch {set old $__field_array($name)}]} {
39 variable ${class}::__field_list
40 lappend __field_list $new
41 set __field_array($name) 1
42 } else {
43 error "field $name already declared"
44 }
45}
46
47proc constructor {name params body} {
48 set class [uplevel {namespace current}]
49 set ${class}::__sealed 1
50 variable ${class}::__field_list
51 set mbodyc {}
52
53 append mbodyc {set this } $class
54 append mbodyc {::__o[incr } $class {::__nextid]} \;
55 append mbodyc {namespace eval $this {}} \;
56
57 if {$__field_list ne {}} {
58 append mbodyc {upvar #0}
59 foreach n $__field_list {
60 set n [lindex $n 0]
61 append mbodyc { ${this}::} $n { } $n
62 regsub -all @$n\\M $body "\${this}::$n" body
63 }
64 append mbodyc \;
65 foreach n $__field_list {
66 if {[llength $n] == 2} {
67 append mbodyc \
68 {set } [lindex $n 0] { } [list [lindex $n 1]] \;
69 }
70 }
71 }
72 append mbodyc $body
73 namespace eval $class [list proc $name $params $mbodyc]
74}
75
76proc method {name params body {deleted {}} {del_body {}}} {
77 set class [uplevel {namespace current}]
78 set ${class}::__sealed 1
79 variable ${class}::__field_list
80 set params [linsert $params 0 this]
81 set mbodyc {}
82
83 switch $deleted {
84 {} {}
85 ifdeleted {
86 append mbodyc {if {![namespace exists $this]} }
87 append mbodyc \{ $del_body \; return \} \;
88 }
89 default {
90 error "wrong # args: method name args body (ifdeleted body)?"
91 }
92 }
93
94 set decl {}
95 foreach n $__field_list {
96 set n [lindex $n 0]
97 if {[regexp -- $n\\M $body]} {
98 if { [regexp -all -- $n\\M $body] == 1
99 && [regexp -all -- \\\$$n\\M $body] == 1} {
100 regsub -all \\\$$n\\M $body "\[set \${this}::$n\]" body
101 } else {
102 append decl { ${this}::} $n { } $n
103 regsub -all @$n\\M $body "\${this}::$n" body
104 }
105 }
106 }
107 if {$decl ne {}} {
108 append mbodyc {upvar #0} $decl \;
109 }
110 append mbodyc $body
111 namespace eval $class [list proc $name $params $mbodyc]
112}
113
114proc delete_this {{t {}}} {
115 if {$t eq {}} {
116 upvar this this
117 set t $this
118 }
119 if {[namespace exists $t]} {namespace delete $t}
120}
121
122proc make_toplevel {t w} {
123 upvar $t top $w pfx
124 if {[winfo ismapped .]} {
125 upvar this this
126 regsub -all {::} $this {__} w
127 set top .$w
128 set pfx $top
129 toplevel $top
130 } else {
131 set top .
132 set pfx {}
133 }
134}
135
136
137## auto_mkindex support for class/constructor/method
138##
139auto_mkindex_parser::command class {name body} {
140 variable parser
141 variable contextStack
142 set contextStack [linsert $contextStack 0 $name]
143 $parser eval [list _%@namespace eval $name] $body
144 set contextStack [lrange $contextStack 1 end]
145}
146auto_mkindex_parser::command constructor {name args} {
147 variable index
148 variable scriptFile
149 append index [list set auto_index([fullname $name])] \
150 [format { [list source [file join $dir %s]]} \
151 [file split $scriptFile]] "\n"
152}
153