mt-lang 0.3.39 → 0.3.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/ast.rb +2 -2
- data/lib/milk_tea/core/bindings/attribute_binding.rb +1 -6
- data/lib/milk_tea/core/bindings/module_binding.rb +1 -1
- data/lib/milk_tea/core/intrinsics.rb +23 -1
- data/lib/milk_tea/core/lowering/functions.rb +3 -0
- data/lib/milk_tea/core/lowering/resolve.rb +4 -65
- data/lib/milk_tea/core/lowering/utils.rb +0 -17
- data/lib/milk_tea/core/lowering.rb +1 -2
- data/lib/milk_tea/core/module_binder.rb +4 -15
- data/lib/milk_tea/core/module_loader.rb +41 -8
- data/lib/milk_tea/core/parser/declarations.rb +24 -17
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +2 -111
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1 -2
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +26 -17
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +26 -42
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +0 -59
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +0 -2
- data/lib/milk_tea/core/types/predicates.rb +57 -0
- data/lib/milk_tea/core/types/registry.rb +14 -2
- data/lib/milk_tea/core/types.rb +0 -4
- data/lib/milk_tea/lsp/server/code_actions.rb +13 -7
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +56 -12
- data/lib/milk_tea/lsp/server/text_documents.rb +18 -2
- data/lib/milk_tea/lsp/workspace/caches.rb +28 -1
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +31 -0
- data/lib/milk_tea/lsp/workspace/store.rb +7 -1
- data/lib/milk_tea/lsp/workspace.rb +6 -0
- data/lib/milk_tea/tooling/formatter.rb +2 -3
- data/lib/milk_tea/tooling/linter/fix_engine.rb +46 -0
- data/lib/milk_tea/tooling/linter/rules.rb +32 -0
- data/lib/milk_tea/tooling/linter.rb +4 -0
- data/lib/milk_tea/tooling.rb +0 -1
- metadata +2 -3
- data/lib/milk_tea/tooling/cst_formatter.rb +0 -13
|
@@ -202,28 +202,72 @@ module MilkTea
|
|
|
202
202
|
end.join("\n")
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
+
# Declaration-prefix regex. Unlike the old form, it also covers the
|
|
206
|
+
# `const function` compound, async/foreign/external/editable/static
|
|
207
|
+
# modifiers, and `attribute` declarations. `static_assert` is not
|
|
208
|
+
# matched: `static` requires whitespace before the keyword, and a bare
|
|
209
|
+
# module-level statement cannot be a declaration.
|
|
210
|
+
SURFACE_DECL_LINE = %r{\A(?:(?:public|foreign|external|async|editable|static|const)\s+)*(?:function|struct|union|enum|flags|variant|interface|event|type|const|var|extending|opaque|attribute)\b}
|
|
211
|
+
|
|
212
|
+
# A bare `name: Type` line. Only struct/union fields (and continuation
|
|
213
|
+
# parameter lines) take this shape; local declarations use `let`/`var`,
|
|
214
|
+
# named arguments use `=`, and match-arm labels start with a keyword or
|
|
215
|
+
# pattern. Requires a type-like token after the colon so `_:` arm labels
|
|
216
|
+
# are not treated as surface.
|
|
217
|
+
SURFACE_FIELD_LINE = /\A[A-Za-z_][A-Za-z0-9_]*\s*:\s*[A-Za-z_\[\]]/
|
|
218
|
+
|
|
219
|
+
# Over-approximation of the module's externally-observable surface. It
|
|
220
|
+
# must never MISS a surface change (a miss leaves shared-cache analyses
|
|
221
|
+
# of dependents stale); false positives only trigger a harmless
|
|
222
|
+
# re-analysis. In addition to declaration lines it captures:
|
|
223
|
+
# - `@[...]` attributes (packed/align/deprecated change layout/docs)
|
|
224
|
+
# - multi-line declaration headers, so parameter/signature edits on
|
|
225
|
+
# continuation lines are detected
|
|
226
|
+
# - struct/union field lines (`name: Type`)
|
|
205
227
|
def dependency_export_surface_fingerprint(content)
|
|
206
|
-
content.to_s.
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
lines = content.to_s.lines.map(&:strip)
|
|
229
|
+
surface = []
|
|
230
|
+
i = 0
|
|
231
|
+
while i < lines.length
|
|
232
|
+
line = lines[i]
|
|
233
|
+
if line.empty? || line.start_with?('#')
|
|
234
|
+
i += 1
|
|
235
|
+
next
|
|
236
|
+
end
|
|
209
237
|
|
|
210
|
-
if
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
238
|
+
if line.start_with?('@[') || line.match?(SURFACE_DECL_LINE) || line.match?(SURFACE_FIELD_LINE)
|
|
239
|
+
surface << line
|
|
240
|
+
# Multi-line header: absorb continuation lines until the
|
|
241
|
+
# terminating ':' so edits inside the header are surfaced too.
|
|
242
|
+
unless line.end_with?(':')
|
|
243
|
+
i += 1
|
|
244
|
+
while i < lines.length
|
|
245
|
+
cont = lines[i]
|
|
246
|
+
break if cont.empty?
|
|
247
|
+
surface << cont
|
|
248
|
+
i += 1
|
|
249
|
+
break if cont.end_with?(':')
|
|
250
|
+
end
|
|
251
|
+
next
|
|
252
|
+
end
|
|
216
253
|
end
|
|
217
|
-
|
|
254
|
+
i += 1
|
|
255
|
+
end
|
|
256
|
+
surface.join("\n")
|
|
218
257
|
end
|
|
219
258
|
|
|
220
259
|
def dependency_refresh_required_for_edit?(changed_uri, previous_content, current_content)
|
|
221
260
|
return false if previous_content == current_content
|
|
222
261
|
return true if dependency_import_fingerprint(previous_content) != dependency_import_fingerprint(current_content)
|
|
223
262
|
|
|
224
|
-
|
|
225
|
-
|
|
263
|
+
# Keep the open-document dependency index fresh (related_open_document_uris
|
|
264
|
+
# updates it as a side effect) so dependent tracking stays accurate.
|
|
265
|
+
@workspace.related_open_document_uris(changed_uri)
|
|
226
266
|
|
|
267
|
+
# A surface edit can invalidate shared-cache analyses of NON-open
|
|
268
|
+
# dependents (their cached entries are recomputed against this module
|
|
269
|
+
# on their next pull), so clearing must not be gated on there being
|
|
270
|
+
# open dependents to refresh.
|
|
227
271
|
dependency_export_surface_fingerprint(previous_content) != dependency_export_surface_fingerprint(current_content)
|
|
228
272
|
end
|
|
229
273
|
|
|
@@ -43,7 +43,12 @@ module MilkTea
|
|
|
43
43
|
invalidate_document_caches(uri)
|
|
44
44
|
current_content = @workspace.get_content(uri)
|
|
45
45
|
refresh_open_document_dependency_state(uri, previous_content: previous_content, current_content: current_content)
|
|
46
|
-
|
|
46
|
+
# This server is always pull-based (diagnosticProvider), so the
|
|
47
|
+
# client's textDocument/diagnostic request asks for the full tier.
|
|
48
|
+
# Scheduling a lighter tier here computes in the worker and then
|
|
49
|
+
# duplicates the full lint on the request thread; keep the tiers
|
|
50
|
+
# aligned so the pull can serve the worker's result.
|
|
51
|
+
schedule_diagnostics(uri, lint_tier: :full) unless @workspace.background_document?(uri)
|
|
47
52
|
nil
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -65,12 +70,23 @@ module MilkTea
|
|
|
65
70
|
|
|
66
71
|
def handle_did_close(params)
|
|
67
72
|
uri = params['textDocument']['uri']
|
|
73
|
+
previous_content = @workspace.get_content(uri)
|
|
68
74
|
cancel_diagnostics(uri)
|
|
69
75
|
@workspace.close_document(uri)
|
|
70
76
|
invalidate_document_caches(uri)
|
|
71
77
|
@diagnostic_report_cache.delete(uri)
|
|
72
78
|
@workspace_diagnostic_cache.delete(uri)
|
|
73
|
-
|
|
79
|
+
# Once closed, the buffer is no longer authoritative. If it differed
|
|
80
|
+
# from disk, module analyses computed against it (for dependents and
|
|
81
|
+
# the file itself) are stale; drop the whole shared cache. Closing is
|
|
82
|
+
# a rare per-file event, so an unconditional clear is cheap and safe.
|
|
83
|
+
disk_content = begin
|
|
84
|
+
path = uri_to_path(uri)
|
|
85
|
+
path && File.file?(path) ? File.read(path) : nil
|
|
86
|
+
rescue StandardError
|
|
87
|
+
nil
|
|
88
|
+
end
|
|
89
|
+
clear_shared_module_cache if previous_content != disk_content
|
|
74
90
|
unless defined?(@pull_diagnostics_active) && @pull_diagnostics_active
|
|
75
91
|
@protocol.write_notification('textDocument/publishDiagnostics', {
|
|
76
92
|
uri: uri,
|
|
@@ -99,14 +99,41 @@ module MilkTea
|
|
|
99
99
|
|
|
100
100
|
lock_wait_start = total_start ? monotonic_time : nil
|
|
101
101
|
if @facts_state_mutex.try_lock
|
|
102
|
+
# No analysis is in flight; computing here is fine (cold paths,
|
|
103
|
+
# tests). It does not block on other work.
|
|
102
104
|
begin
|
|
103
105
|
compute_snapshot.call
|
|
104
106
|
ensure
|
|
105
107
|
@facts_state_mutex.unlock
|
|
106
108
|
end
|
|
107
109
|
elsif allow_last_good_fallback && last_good_snapshot
|
|
108
|
-
|
|
110
|
+
# Facts exist from a prior pass; never block on the in-flight one.
|
|
109
111
|
snapshot = last_good_snapshot
|
|
112
|
+
cache_state = 'last_good'
|
|
113
|
+
elsif allow_last_good_fallback
|
|
114
|
+
# No facts yet and a background analysis is computing this document.
|
|
115
|
+
# Wait briefly (bounded) for it so the request usually returns fresh
|
|
116
|
+
# facts instead of a lexical fallback — without duplicating the work
|
|
117
|
+
# (we never run analysis here) or blocking indefinitely. Beyond the
|
|
118
|
+
# budget, serve nil and let the handler fall back.
|
|
119
|
+
deadline = monotonic_time + (IN_FLIGHT_FACTS_WAIT_MS / 1000.0)
|
|
120
|
+
acquired = false
|
|
121
|
+
while monotonic_time < deadline
|
|
122
|
+
if @facts_state_mutex.try_lock
|
|
123
|
+
acquired = true
|
|
124
|
+
break
|
|
125
|
+
end
|
|
126
|
+
sleep 0.02
|
|
127
|
+
end
|
|
128
|
+
if acquired
|
|
129
|
+
begin
|
|
130
|
+
compute_snapshot.call
|
|
131
|
+
ensure
|
|
132
|
+
@facts_state_mutex.unlock
|
|
133
|
+
end
|
|
134
|
+
else
|
|
135
|
+
cache_state = 'nil'
|
|
136
|
+
end
|
|
110
137
|
else
|
|
111
138
|
@facts_state_mutex.synchronize do
|
|
112
139
|
lock_wait_ms = elapsed_ms(lock_wait_start) if lock_wait_start
|
|
@@ -107,6 +107,37 @@ module MilkTea
|
|
|
107
107
|
@full_reverse_index_built = false
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
# Drop all cached module analyses (and the per-uri snapshots derived from
|
|
111
|
+
# them) when an analysis input that was captured in those analyses is no
|
|
112
|
+
# longer authoritative — e.g. a closed document whose buffer differed from
|
|
113
|
+
# disk. Kept rare: closing a file is infrequent, so a wholesale clear is
|
|
114
|
+
# safer than reasoning about which dependents could have observed the
|
|
115
|
+
# closed buffer. Open documents keep their last-known-good snapshots so
|
|
116
|
+
# they keep serving rich features while re-analysis lands.
|
|
117
|
+
def clear_shared_module_cache
|
|
118
|
+
@facts_state_mutex.synchronize do
|
|
119
|
+
@facts_cache_mutex.synchronize do
|
|
120
|
+
all_open = @document_state_mutex.synchronize { @open_documents.keys }
|
|
121
|
+
preserved_facts = all_open.each_with_object({}) do |open_uri, preserved|
|
|
122
|
+
facts = @last_good_facts_cache[open_uri]
|
|
123
|
+
preserved[open_uri] = facts if facts
|
|
124
|
+
end
|
|
125
|
+
preserved_snapshots = all_open.each_with_object({}) do |open_uri, preserved|
|
|
126
|
+
snapshot = @last_good_tooling_snapshot_cache[open_uri]
|
|
127
|
+
preserved[open_uri] = snapshot if snapshot
|
|
128
|
+
end
|
|
129
|
+
@shared_module_cache.clear
|
|
130
|
+
@facts_cache.clear
|
|
131
|
+
@tooling_snapshot_cache.clear
|
|
132
|
+
@diagnostics_cache.clear
|
|
133
|
+
@last_good_facts_cache.clear
|
|
134
|
+
@last_good_tooling_snapshot_cache.clear
|
|
135
|
+
preserved_snapshots.each { |open_uri, snapshot| @last_good_tooling_snapshot_cache[open_uri] = snapshot }
|
|
136
|
+
preserved_facts.each { |open_uri, facts| @last_good_facts_cache[open_uri] = facts }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
110
141
|
def update_dependency_index(uri, facts)
|
|
111
142
|
imported_module_names = if facts
|
|
112
143
|
facts.imports.each_value.filter_map(&:name).to_set
|
|
@@ -72,7 +72,13 @@ module MilkTea
|
|
|
72
72
|
invalidate_cache(uri)
|
|
73
73
|
enqueue_definition_warmup(uri) unless background_document?(uri)
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
# The shared module cache is intentionally NOT cleared here. Imported
|
|
76
|
+
# module analyses only become stale when this file's dependency surface
|
|
77
|
+
# (imports or exported declarations) changes; a body-only edit leaves
|
|
78
|
+
# them valid. handle_did_change detects surface changes via
|
|
79
|
+
# dependency_refresh_required_for_edit? and clears the cache through
|
|
80
|
+
# refresh_import_dependent_caches. Clearing it on every keystroke forced
|
|
81
|
+
# a full re-analysis of every transitive module per edit.
|
|
76
82
|
dependent_uris = @facts_cache_mutex.synchronize do
|
|
77
83
|
all_open = @document_state_mutex.synchronize { @open_documents.keys }
|
|
78
84
|
dependent_open_document_uris_for(uri, all_open)
|
|
@@ -22,6 +22,12 @@ module MilkTea
|
|
|
22
22
|
DOCUMENT_SOURCES = %w[active-editor visible-editor background-document].freeze
|
|
23
23
|
PERF_LOG_THRESHOLD_MS = 1000
|
|
24
24
|
|
|
25
|
+
# How long a request thread waits (when no facts are available yet) for an
|
|
26
|
+
# in-flight background analysis to finish before falling back to lexical/
|
|
27
|
+
# nil results. Bounds the main-loop stall while usually returning fresh
|
|
28
|
+
# facts; request threads never run the analysis themselves in this window.
|
|
29
|
+
IN_FLIGHT_FACTS_WAIT_MS = Integer(ENV.fetch('MILK_TEA_LSP_FACTS_WAIT_MS', '500'))
|
|
30
|
+
|
|
25
31
|
# Token types that introduce a named definition, in order of precedence.
|
|
26
32
|
#
|
|
27
33
|
# NOTE: this list is intentionally minimal. Multi-keyword prefixes such as
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "../core"
|
|
4
|
-
require_relative "cst_formatter"
|
|
5
4
|
|
|
6
5
|
module MilkTea
|
|
7
6
|
class FormatterError < StandardError; end
|
|
@@ -49,12 +48,12 @@ module MilkTea
|
|
|
49
48
|
|
|
50
49
|
def self.preserve_format(source, path:, profile: nil)
|
|
51
50
|
cst = profile_phase(profile, "format.cst") { build_cst(source, path:) }
|
|
52
|
-
profile_phase(profile, "format.cst_fmt") {
|
|
51
|
+
profile_phase(profile, "format.cst_fmt") { cst.reconstruct }
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
def self.tidy_format(source, path:, max_line_length: DEFAULT_MAX_LINE_LENGTH, profile: nil)
|
|
56
55
|
cst = profile_phase(profile, "format.cst") { build_cst(source, path:) }
|
|
57
|
-
normalized = profile_phase(profile, "format.normalize") {
|
|
56
|
+
normalized = profile_phase(profile, "format.normalize") { cst.reconstruct_normalized }
|
|
58
57
|
wrapped = profile_phase(profile, "format.wrap") { wrap_long_argument_lists(normalized, max_line_length:, path:) }
|
|
59
58
|
profile_phase(profile, "format.blank_lines") { normalize_blank_lines(wrapped, path:) }
|
|
60
59
|
end
|
|
@@ -17,6 +17,7 @@ module MilkTea
|
|
|
17
17
|
when "redundant-else" then redundant_else_edits(lines, warning)
|
|
18
18
|
when "redundant-return" then redundant_return_edits(lines, warning)
|
|
19
19
|
when "redundant-type-annotation" then redundant_type_annotation_edits(lines, warning)
|
|
20
|
+
when "prefer-inline-methods" then prefer_inline_methods_edits(lines, warning)
|
|
20
21
|
when "unused-import" then unused_import_edits(lines, warning)
|
|
21
22
|
when "trailing-list-comma" then trailing_list_comma_edits(lines, warning)
|
|
22
23
|
else []
|
|
@@ -152,6 +153,51 @@ module MilkTea
|
|
|
152
153
|
[FixEdit.new(start_line: line_idx, start_char: 0, end_line: line_idx + 1, end_char: 0, new_text: "")]
|
|
153
154
|
end
|
|
154
155
|
|
|
156
|
+
# Moves the methods of an `extending X:` block inline into the matching
|
|
157
|
+
# `struct X:` declaration. Only rewrites when the struct immediately
|
|
158
|
+
# precedes the extending block (blank lines allowed between them); other
|
|
159
|
+
# layouts are left alone since the move would be non-local.
|
|
160
|
+
def self.prefer_inline_methods_edits(lines, warning)
|
|
161
|
+
name = warning.symbol_name
|
|
162
|
+
return [] unless name && warning.line
|
|
163
|
+
|
|
164
|
+
struct_idx = lines.index { |l| l.match?(/\A\s*struct\s+#{Regexp.escape(name)}\b/) }
|
|
165
|
+
return [] unless struct_idx
|
|
166
|
+
|
|
167
|
+
last_member_idx = nil
|
|
168
|
+
((struct_idx + 1)...lines.length).each do |i|
|
|
169
|
+
l = lines[i]
|
|
170
|
+
break if !l.chomp.empty? && !l.start_with?(" ", "\t")
|
|
171
|
+
|
|
172
|
+
last_member_idx = i unless l.chomp.empty?
|
|
173
|
+
end
|
|
174
|
+
return [] unless last_member_idx
|
|
175
|
+
|
|
176
|
+
ext_start_idx = warning.line - 1
|
|
177
|
+
return [] unless last_member_idx < ext_start_idx
|
|
178
|
+
|
|
179
|
+
ext_end_idx = ext_start_idx
|
|
180
|
+
((ext_start_idx + 1)...lines.length).each do |i|
|
|
181
|
+
l = lines[i]
|
|
182
|
+
break if !l.chomp.empty? && !l.start_with?(" ", "\t")
|
|
183
|
+
|
|
184
|
+
ext_end_idx = i unless l.chomp.empty?
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
method_lines = lines[(ext_start_idx + 1)..ext_end_idx].to_a
|
|
188
|
+
method_lines.shift while method_lines.first && method_lines.first.chomp.empty?
|
|
189
|
+
method_lines.pop while method_lines.last && method_lines.last.chomp.empty?
|
|
190
|
+
return [] if method_lines.empty?
|
|
191
|
+
|
|
192
|
+
between = lines[(last_member_idx + 1)...ext_start_idx]
|
|
193
|
+
return [] unless between.all? { |l| l.chomp.empty? }
|
|
194
|
+
|
|
195
|
+
method_text = method_lines.join
|
|
196
|
+
new_text = "#{lines[last_member_idx].chomp}\n\n#{method_text}"
|
|
197
|
+
|
|
198
|
+
[FixEdit.new(start_line: last_member_idx, start_char: 0, end_line: ext_end_idx + 1, end_char: 0, new_text: new_text)]
|
|
199
|
+
end
|
|
200
|
+
|
|
155
201
|
def self.unused_import_edits(lines, warning)
|
|
156
202
|
return [] unless warning.line
|
|
157
203
|
|
|
@@ -586,6 +586,38 @@ module MilkTea
|
|
|
586
586
|
def lvalue_expression?(expression)
|
|
587
587
|
expression.is_a?(AST::Identifier) || expression.is_a?(AST::MemberAccess) || expression.is_a?(AST::IndexAccess)
|
|
588
588
|
end
|
|
589
|
+
# ── prefer-inline-methods ──────────────────────────────────────────────
|
|
590
|
+
# Flag `extending X:` blocks whose receiver struct is declared in the same
|
|
591
|
+
# file, suggesting the methods be written inline inside the struct body
|
|
592
|
+
# (which desugars to the identical `extending` block).
|
|
593
|
+
|
|
594
|
+
def emit_prefer_inline_methods_warnings(source_file)
|
|
595
|
+
struct_names = source_file.declarations.filter_map { |decl| decl.name if decl.is_a?(AST::StructDecl) }.to_set
|
|
596
|
+
return if struct_names.empty?
|
|
597
|
+
|
|
598
|
+
source_file.declarations.each do |declaration|
|
|
599
|
+
next unless declaration.is_a?(AST::ExtendingBlock)
|
|
600
|
+
next if declaration.inline
|
|
601
|
+
|
|
602
|
+
parts = declaration.type_name.name.parts
|
|
603
|
+
next unless parts.length == 1
|
|
604
|
+
next if declaration.type_name.arguments.any?
|
|
605
|
+
|
|
606
|
+
name = parts.first
|
|
607
|
+
next unless struct_names.include?(name)
|
|
608
|
+
|
|
609
|
+
@warnings << Warning.new(
|
|
610
|
+
path: @path,
|
|
611
|
+
line: declaration.line,
|
|
612
|
+
column: declaration.column,
|
|
613
|
+
length: name.length,
|
|
614
|
+
code: "prefer-inline-methods",
|
|
615
|
+
message: "methods on '#{name}' can be written inline inside the struct declaration",
|
|
616
|
+
severity: :hint,
|
|
617
|
+
symbol_name: name,
|
|
618
|
+
)
|
|
619
|
+
end
|
|
620
|
+
end
|
|
589
621
|
end
|
|
590
622
|
end
|
|
591
623
|
end
|
|
@@ -35,6 +35,7 @@ module MilkTea
|
|
|
35
35
|
owning-release-double
|
|
36
36
|
prefer-conditional-expression
|
|
37
37
|
prefer-inline-if
|
|
38
|
+
prefer-inline-methods
|
|
38
39
|
prefer-is-variant
|
|
39
40
|
prefer-let
|
|
40
41
|
prefer-let-else
|
|
@@ -69,6 +70,7 @@ module MilkTea
|
|
|
69
70
|
redundant-ignored-match-binding
|
|
70
71
|
prefer-let-else
|
|
71
72
|
prefer-var-else
|
|
73
|
+
prefer-inline-methods
|
|
72
74
|
redundant-bool-compare
|
|
73
75
|
redundant-cast
|
|
74
76
|
redundant-else
|
|
@@ -95,6 +97,7 @@ module MilkTea
|
|
|
95
97
|
"redundant-type-annotation" => "Remove redundant type annotation",
|
|
96
98
|
"prefer-let-else" => "Rewrite as let-else",
|
|
97
99
|
"prefer-var-else" => "Rewrite as var-else",
|
|
100
|
+
"prefer-inline-methods" => "Inline methods into struct",
|
|
98
101
|
"trailing-list-comma" => "Remove trailing list comma",
|
|
99
102
|
}.freeze
|
|
100
103
|
EVENT_STACK_SNAPSHOT_WARNING_THRESHOLD = 128
|
|
@@ -771,6 +774,7 @@ module MilkTea
|
|
|
771
774
|
profile_phase("rule.doc_tag") { emit_doc_tag_warnings(ast) } if full_tier?
|
|
772
775
|
profile_phase("rule.event_capacity") { emit_event_capacity_warnings(ast) }
|
|
773
776
|
profile_phase("rule.trailing_list_comma") { emit_trailing_list_comma_warnings(ast) }
|
|
777
|
+
profile_phase("rule.prefer_inline_methods") { emit_prefer_inline_methods_warnings(ast) }
|
|
774
778
|
profile_phase("rule.line_too_long") { emit_line_too_long_warnings }
|
|
775
779
|
@warnings
|
|
776
780
|
end
|
data/lib/milk_tea/tooling.rb
CHANGED
|
@@ -11,7 +11,6 @@ require_relative "tooling/sexpr_dumper"
|
|
|
11
11
|
require_relative "tooling/sexpr_parser"
|
|
12
12
|
require_relative "tooling/build"
|
|
13
13
|
require_relative "tooling/run"
|
|
14
|
-
require_relative "tooling/cst_formatter"
|
|
15
14
|
require_relative "tooling/error_formatter"
|
|
16
15
|
require_relative "tooling/formatter"
|
|
17
16
|
require_relative "tooling/linter"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mt-lang
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.41
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Long (Teefan) Tran
|
|
@@ -385,7 +385,6 @@ files:
|
|
|
385
385
|
- lib/milk_tea/tooling/cli/commands/snapshot.rb
|
|
386
386
|
- lib/milk_tea/tooling/cli/commands/test.rb
|
|
387
387
|
- lib/milk_tea/tooling/cli/commands/toolchain.rb
|
|
388
|
-
- lib/milk_tea/tooling/cst_formatter.rb
|
|
389
388
|
- lib/milk_tea/tooling/debug_info_formatter.rb
|
|
390
389
|
- lib/milk_tea/tooling/debug_map.rb
|
|
391
390
|
- lib/milk_tea/tooling/docs_app.rb
|
|
@@ -626,7 +625,7 @@ metadata:
|
|
|
626
625
|
homepage_uri: https://teefan.github.io/mt-lang/
|
|
627
626
|
source_code_uri: https://github.com/teefan/mt-lang
|
|
628
627
|
post_install_message: |
|
|
629
|
-
Milk Tea 0.3.
|
|
628
|
+
Milk Tea 0.3.41 installed!
|
|
630
629
|
|
|
631
630
|
System requirements:
|
|
632
631
|
- A C compiler (gcc or clang) must be available on PATH
|