1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module Environment
9
10 module Tracer
11
12 class Event
13 attr_reader :label
14 attr_reader :klass
15 attr_reader :loc
16 attr_reader :msg
17
18
19 def initialize(label, klass, loc, msg)
20 ASSERT.kind_of label, ::String
21 ASSERT.kind_of klass, ::Class
22 ASSERT.kind_of loc, LOC::Entry
23 ASSERT.kind_of msg, ::String
24
25 @label = label
26 @klass = klass
27 @loc = loc
28 @msg = msg
29 end
30
31
32 def to_s
33 format("%s:#%d:[%s] %s: %s",
34 self.loc.file_name,
35 self.loc.line_num + 1,
36 label,
37 Tracer.class_to_string(klass),
38 self.msg
39 )
40 end
41 end
42
43
44
45 module_function
46
47 def make_event(label, klass, loc, msg)
48 ASSERT.kind_of label, ::String
49 ASSERT.kind_of klass, ::Class
50 ASSERT.kind_of loc, LOC::Entry
51 ASSERT.kind_of msg, ::String
52
53 Event.new(label.freeze, klass, loc, msg.freeze).freeze
54 end
55
56
57 def trace(pref, eval_depth, label, klass, loc, msg)
58 ASSERT.kind_of pref, E::Preference
59 ASSERT.kind_of eval_depth, ::Integer
60 ASSERT.kind_of label, ::String
61 ASSERT.kind_of klass, ::Class
62 ASSERT.kind_of loc, LOC::Entry
63 ASSERT.kind_of msg, ::String
64 ASSERT.assert block_given?
65
66 if pref.trace_mode?
67 STDERR.printf "%s[%s] %s: %s\n",
68 '| ' * eval_depth,
69 label,
70 Tracer.class_to_string(klass),
71 msg
72 end
73
74 object = yield Tracer.make_event(label, klass, loc, msg)
75
76 if pref.trace_mode?
77 STDERR.printf "%s--> %s: %s\n",
78 '| ' * eval_depth,
79 Tracer.class_to_string(object.class),
80 object.to_s
81 end
82
83 object
84 end
85
86
87 def trace_single(pref, eval_depth, label, klass, loc, msg)
88 ASSERT.kind_of pref, E::Preference
89 ASSERT.kind_of eval_depth, ::Integer
90 ASSERT.kind_of label, ::String
91 ASSERT.kind_of klass, ::Class
92 ASSERT.kind_of loc, LOC::Entry
93 ASSERT.kind_of msg, ::String
94
95 if pref.trace_mode?
96 STDERR.printf "%s[%s] %s: %s",
97 '| ' * eval_depth,
98 label,
99 Tracer.class_to_string(klass),
100 msg
101 end
102
103 object = yield Tracer.make_event(label, klass, loc, msg)
104
105 if pref.trace_mode?
106 STDERR.printf " --> %s: %s\n",
107 Tracer.class_to_string(object.class),
108 object.to_s
109 end
110
111 object
112 end
113
114
115 def class_to_string(klass)
116 ASSERT.kind_of klass, ::Class
117
118 class_name, *fully_qualified_module_names = klass.to_s.split(/::/)
119
120 s = if fully_qualified_module_names.empty?
121 class_name
122 else
123 *module_names, fq_class_name = fully_qualified_module_names
124
125 format("%s (%s)",
126 fq_class_name,
127 Tracer.abbreviate(module_names).join('::')
128 )
129 end
130
131 ASSERT.kind_of s, ::String
132 end
133
134
135 ABBREVIATABLE_MODULE_NAMES = [
136 # Lexical
137 [['Lexical'], 'L'],
138 [['Lexical', 'Lexer'], 'LL'],
139
140 # ConcreteSyntax
141 [['ConcreteSyntax'], 'CS'],
142 [['ConcreteSyntax', 'Module'], 'CSM'],
143 [['ConcreteSyntax', 'Module', 'Declaration'], 'CSMD'],
144 [['ConcreteSyntax', 'Module', 'Expression'], 'CSME'],
145 [['ConcreteSyntax', 'Module', 'Pattern'], 'CSMP'],
146 [['ConcreteSyntax', 'Core'], 'CSC'],
147 [['ConcreteSyntax', 'Core', 'Declaration'], 'CSCD'],
148 [['ConcreteSyntax', 'Core', 'Expression'], 'CSCE'],
149 [['ConcreteSyntax', 'Core', 'Expression', 'Unary'], 'CSCEU'],
150 [['ConcreteSyntax', 'Core', 'Expression', 'Unary', 'Atom'],
151 'CSCEUA'],
152 [['ConcreteSyntax', 'Core', 'Expression', 'Binary'], 'CSCEB'],
153 [['ConcreteSyntax', 'Core', 'Expression', 'Nary'], 'CSCEN'],
154 [['ConcreteSyntax', 'Core', 'Pattern'], 'CSCP'],
155
156 # AbstractSyntax
157 [['AbstractSyntax'], 'AS'],
158 [['AbstractSyntax', 'Core'], 'ASC'],
159 [['AbstractSyntax', 'Core', 'Declaration'], 'ASCD'],
160 [['AbstractSyntax', 'Core', 'Expression'], 'ASCE'],
161 [['AbstractSyntax', 'Core', 'Expression', 'Unary'], 'ASCEU'],
162 [['AbstractSyntax', 'Core', 'Expression', 'Unary', 'Atom'],
163 'ASCEUA'],
164 [['AbstractSyntax', 'Core', 'Expression', 'Binary'], 'ASCEB'],
165 [['AbstractSyntax', 'Core', 'Expression', 'Nary'], 'ASCEN'],
166
167 # Value
168 [['Value'], 'V'],
169 [['Value', 'Core'], 'VC'],
170 [['Value', 'Core', 'Atom'], 'VCA'],
171 [['Value', 'Core', 'Atom', 'Number'], 'VCAN'],
172 [['Value', 'Core', 'Product'], 'VCP'],
173 [['Value', 'Core', 'Union'], 'VCU'],
174 [['Value', 'Core', 'Morph'], 'VCM'],
175
176 # Environment
177 [['Environment'], 'E']
178 ].sort { |(xs, _), (ys, _)| ys.size <=> xs.size } # For longest-match
179
180 def abbreviate(names)
181 ASSERT.kind_of names, ::Array
182
183 ABBREVIATABLE_MODULE_NAMES.each { |prefix_names, abbreviated_name|
184 prefix_length = prefix_names.length
185
186 if names.take(prefix_length) == prefix_names
187 break [abbreviated_name] + names.drop(prefix_length)
188 else
189 names
190 end
191 }
192 end
193
194 end # Umu::Environment::Tracer
195
196 end # Umu::Environment
197
198 end # Umu