mt-lang 0.3.16 → 0.3.20
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/docs/language-design.md +3 -4
- data/docs/language-manual.md +3 -3
- data/lib/milk_tea/base.rb +1 -1
- data/lib/milk_tea/core/{binding_types.rb → bindings.rb} +1 -1
- data/lib/milk_tea/core/c_backend/expressions.rb +34 -23
- data/lib/milk_tea/core/c_backend/feature_detection.rb +25 -45
- data/lib/milk_tea/core/c_backend/type_collectors.rb +18 -30
- data/lib/milk_tea/core/c_backend/type_declaration.rb +0 -6
- data/lib/milk_tea/core/c_backend.rb +63 -54
- data/lib/milk_tea/core/compile_time.rb +279 -74
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +1 -1
- data/lib/milk_tea/core/{compatibility_helpers.rb → intrinsics.rb} +9 -2
- data/lib/milk_tea/core/lexer.rb +55 -48
- data/lib/milk_tea/core/lowering/block.rb +9 -0
- data/lib/milk_tea/core/lowering/calls.rb +2 -0
- data/lib/milk_tea/core/lowering/declarations.rb +1 -1
- data/lib/milk_tea/core/lowering/functions.rb +11 -8
- data/lib/milk_tea/core/lowering/resolve.rb +10 -3
- data/lib/milk_tea/core/lowering/scans.rb +13 -18
- data/lib/milk_tea/core/lowering.rb +18 -18
- data/lib/milk_tea/core/module_binder.rb +9 -10
- data/lib/milk_tea/core/module_loader.rb +64 -57
- data/lib/milk_tea/core/module_path_resolver.rb +1 -4
- data/lib/milk_tea/core/parser/declarations.rb +43 -19
- data/lib/milk_tea/core/parser/expressions.rb +4 -7
- data/lib/milk_tea/core/parser/statements.rb +5 -5
- data/lib/milk_tea/core/parser.rb +43 -17
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +24 -31
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +20 -23
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +117 -85
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +19 -41
- data/lib/milk_tea/core/semantic_analyzer.rb +57 -38
- data/lib/milk_tea/core.rb +6 -2
- data/lib/milk_tea/dap/lldb_dap_backend.rb +153 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +1 -1
- data/lib/milk_tea/dap.rb +1 -1
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +6 -0
- data/lib/milk_tea/lsp.rb +1 -7
- data/lib/milk_tea/{bindings/cli.rb → tooling/bindgen_cli.rb} +1 -1
- data/lib/milk_tea/tooling/cli/commands/bindgen.rb +11 -0
- data/lib/milk_tea/tooling/cli/commands/build.rb +37 -0
- data/lib/milk_tea/tooling/cli/commands/cache.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/check.rb +116 -0
- data/lib/milk_tea/tooling/cli/commands/command_base.rb +8 -0
- data/lib/milk_tea/tooling/cli/commands/completions.rb +48 -0
- data/lib/milk_tea/tooling/cli/commands/dap.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/debug.rb +77 -0
- data/lib/milk_tea/tooling/cli/commands/deps.rb +17 -0
- data/lib/milk_tea/tooling/cli/commands/docs.rb +58 -0
- data/lib/milk_tea/tooling/cli/commands/emit_c.rb +64 -0
- data/lib/milk_tea/tooling/cli/commands/format.rb +199 -0
- data/lib/milk_tea/tooling/cli/commands/lex.rb +46 -0
- data/lib/milk_tea/tooling/cli/commands/lint.rb +248 -0
- data/lib/milk_tea/tooling/cli/commands/lower.rb +50 -0
- data/lib/milk_tea/tooling/cli/commands/lsp.rb +43 -0
- data/lib/milk_tea/tooling/cli/commands/new.rb +26 -0
- data/lib/milk_tea/tooling/cli/commands/parse.rb +51 -0
- data/lib/milk_tea/tooling/cli/commands/run.rb +99 -0
- data/lib/milk_tea/tooling/cli/commands/snapshot.rb +117 -0
- data/lib/milk_tea/tooling/cli/commands/test.rb +557 -0
- data/lib/milk_tea/tooling/cli/commands/toolchain.rb +16 -0
- data/lib/milk_tea/tooling/cli.rb +101 -1893
- data/lib/milk_tea/tooling.rb +1 -1
- metadata +29 -9
- data/lib/milk_tea/core/compile_time/const_eval.rb +0 -182
- data/lib/milk_tea/core/module_loader/errors.rb +0 -23
- data/lib/milk_tea/dap/backends/lldb_dap.rb +0 -156
- /data/lib/milk_tea/core/lowering/{async.rb → async/frame_builder.rb} +0 -0
|
@@ -1,6 +1,185 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "types/layout"
|
|
4
|
+
|
|
5
|
+
module MilkTea
|
|
6
|
+
module ConstEval
|
|
7
|
+
|
|
8
|
+
def self.evaluate(expression, resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
|
|
9
|
+
Evaluator.new(
|
|
10
|
+
resolve_identifier:,
|
|
11
|
+
resolve_member_access:,
|
|
12
|
+
resolve_type_ref:,
|
|
13
|
+
resolve_call:,
|
|
14
|
+
).evaluate(expression)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.equality_result(left, right)
|
|
18
|
+
return left == right if left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
19
|
+
return left == right if left.is_a?(String) && right.is_a?(String)
|
|
20
|
+
return left == right if boolean_value?(left) && boolean_value?(right)
|
|
21
|
+
return left == right if left.is_a?(Types::Base) && right.is_a?(Types::Base)
|
|
22
|
+
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.boolean_value?(value)
|
|
27
|
+
value == true || value == false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Evaluator
|
|
31
|
+
def initialize(resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
|
|
32
|
+
@resolve_identifier = resolve_identifier
|
|
33
|
+
@resolve_member_access = resolve_member_access
|
|
34
|
+
@resolve_type_ref = resolve_type_ref
|
|
35
|
+
@resolve_call = resolve_call
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def evaluate(expression)
|
|
39
|
+
case expression
|
|
40
|
+
when AST::ErrorExpr
|
|
41
|
+
nil
|
|
42
|
+
when AST::ExpressionList
|
|
43
|
+
expression.elements.filter_map { |element| evaluate(element) }
|
|
44
|
+
when AST::IntegerLiteral, AST::FloatLiteral, AST::BooleanLiteral
|
|
45
|
+
expression.value
|
|
46
|
+
when AST::StringLiteral
|
|
47
|
+
expression.value
|
|
48
|
+
when AST::Identifier
|
|
49
|
+
@resolve_identifier&.call(expression)
|
|
50
|
+
when AST::MemberAccess
|
|
51
|
+
@resolve_member_access&.call(expression)
|
|
52
|
+
when AST::Call
|
|
53
|
+
@resolve_call&.call(expression)
|
|
54
|
+
when AST::Specialization
|
|
55
|
+
@resolve_call&.call(expression)
|
|
56
|
+
when AST::SizeofExpr
|
|
57
|
+
type = resolve_layout_type(expression.type)
|
|
58
|
+
type && Layout.size_of(type)
|
|
59
|
+
when AST::AlignofExpr
|
|
60
|
+
type = resolve_layout_type(expression.type)
|
|
61
|
+
type && Layout.alignment_of(type)
|
|
62
|
+
when AST::OffsetofExpr
|
|
63
|
+
type = resolve_layout_type(expression.type)
|
|
64
|
+
if type
|
|
65
|
+
result = Layout.offset_of(type, expression.field)
|
|
66
|
+
return result if result
|
|
67
|
+
|
|
68
|
+
id_expr = AST::Identifier.new(name: expression.field)
|
|
69
|
+
value = @resolve_identifier&.call(id_expr)
|
|
70
|
+
if value.is_a?(Types::FieldHandle)
|
|
71
|
+
return Layout.offset_of(type, value.field_name)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
nil
|
|
75
|
+
when AST::UnaryOp
|
|
76
|
+
evaluate_unary(expression)
|
|
77
|
+
when AST::BinaryOp
|
|
78
|
+
evaluate_binary(expression)
|
|
79
|
+
when AST::IfExpr
|
|
80
|
+
condition = evaluate(expression.condition)
|
|
81
|
+
return unless ConstEval.boolean_value?(condition)
|
|
82
|
+
|
|
83
|
+
evaluate(condition ? expression.then_expression : expression.else_expression)
|
|
84
|
+
else
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def resolve_layout_type(type_ref)
|
|
90
|
+
return unless @resolve_type_ref
|
|
91
|
+
|
|
92
|
+
@resolve_type_ref.call(type_ref)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def evaluate_unary(expression)
|
|
96
|
+
operand = evaluate(expression.operand)
|
|
97
|
+
|
|
98
|
+
case expression.operator
|
|
99
|
+
when "+"
|
|
100
|
+
operand.is_a?(Numeric) ? operand : nil
|
|
101
|
+
when "-"
|
|
102
|
+
operand.is_a?(Numeric) ? -operand : nil
|
|
103
|
+
when "~"
|
|
104
|
+
operand.is_a?(Integer) ? ~operand : nil
|
|
105
|
+
when "not"
|
|
106
|
+
ConstEval.boolean_value?(operand) ? !operand : nil
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def evaluate_binary(expression)
|
|
111
|
+
left = evaluate(expression.left)
|
|
112
|
+
|
|
113
|
+
case expression.operator
|
|
114
|
+
when "and"
|
|
115
|
+
return unless ConstEval.boolean_value?(left)
|
|
116
|
+
return false if left == false
|
|
117
|
+
|
|
118
|
+
right = evaluate(expression.right)
|
|
119
|
+
return right if ConstEval.boolean_value?(right)
|
|
120
|
+
|
|
121
|
+
return nil
|
|
122
|
+
when "or"
|
|
123
|
+
return unless ConstEval.boolean_value?(left)
|
|
124
|
+
return true if left == true
|
|
125
|
+
|
|
126
|
+
right = evaluate(expression.right)
|
|
127
|
+
return right if ConstEval.boolean_value?(right)
|
|
128
|
+
|
|
129
|
+
return nil
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
right = evaluate(expression.right)
|
|
133
|
+
|
|
134
|
+
case expression.operator
|
|
135
|
+
when "=="
|
|
136
|
+
ConstEval.equality_result(left, right)
|
|
137
|
+
when "!="
|
|
138
|
+
result = ConstEval.equality_result(left, right)
|
|
139
|
+
result.nil? ? nil : !result
|
|
140
|
+
when "+"
|
|
141
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left + right : nil
|
|
142
|
+
when "-"
|
|
143
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left - right : nil
|
|
144
|
+
when "*"
|
|
145
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left * right : nil
|
|
146
|
+
when "/"
|
|
147
|
+
return unless left.is_a?(Numeric) && right.is_a?(Numeric)
|
|
148
|
+
raise CompileTime::Error, "division by zero" if zero_numeric?(right)
|
|
149
|
+
|
|
150
|
+
left / right
|
|
151
|
+
when "%"
|
|
152
|
+
return unless left.is_a?(Integer) && right.is_a?(Integer)
|
|
153
|
+
raise CompileTime::Error, "modulo by zero" if right.zero?
|
|
154
|
+
|
|
155
|
+
left % right
|
|
156
|
+
when "<<"
|
|
157
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? left << right : nil
|
|
158
|
+
when ">>"
|
|
159
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? left >> right : nil
|
|
160
|
+
when "&"
|
|
161
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? left & right : nil
|
|
162
|
+
when "|"
|
|
163
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? left | right : nil
|
|
164
|
+
when "^"
|
|
165
|
+
left.is_a?(Integer) && right.is_a?(Integer) ? left ^ right : nil
|
|
166
|
+
when "<"
|
|
167
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left < right : nil
|
|
168
|
+
when "<="
|
|
169
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left <= right : nil
|
|
170
|
+
when ">"
|
|
171
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left > right : nil
|
|
172
|
+
when ">="
|
|
173
|
+
left.is_a?(Numeric) && right.is_a?(Numeric) ? left >= right : nil
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def zero_numeric?(value)
|
|
178
|
+
(value.is_a?(Integer) && value.zero?) || (value.is_a?(Float) && value.zero?)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
4
183
|
|
|
5
184
|
module MilkTea
|
|
6
185
|
module CompileTime
|
|
@@ -73,75 +252,7 @@ module MilkTea
|
|
|
73
252
|
resolve_member_access: ->(ma_expr) {
|
|
74
253
|
@checker.evaluate_compile_time_const_value(ma_expr, scopes:)
|
|
75
254
|
},
|
|
76
|
-
resolve_call: ->(call_expr) {
|
|
77
|
-
if call_expr.callee.is_a?(AST::Identifier)
|
|
78
|
-
func = @checker.top_level_function(call_expr.callee.name)
|
|
79
|
-
if func&.ast&.respond_to?(:const) && func.ast.const
|
|
80
|
-
begin
|
|
81
|
-
initial_vars = {}
|
|
82
|
-
func.ast.params.each_with_index do |param, idx|
|
|
83
|
-
return nil if idx >= call_expr.arguments.length
|
|
84
|
-
|
|
85
|
-
arg_expr = call_expr.arguments[idx].value
|
|
86
|
-
arg_value = case arg_expr
|
|
87
|
-
when AST::Identifier
|
|
88
|
-
@variables[arg_expr.name] || @checker.evaluate_compile_time_const_value(arg_expr, scopes:)
|
|
89
|
-
else
|
|
90
|
-
CompileTime.evaluate(
|
|
91
|
-
arg_expr,
|
|
92
|
-
resolve_identifier: ->(id) { @variables[id.name] || @checker.evaluate_compile_time_const_value(id, scopes:) },
|
|
93
|
-
resolve_member_access: ->(ma) { @checker.evaluate_compile_time_const_value(ma, scopes:) },
|
|
94
|
-
resolve_type_ref: nil,
|
|
95
|
-
resolve_call: nil,
|
|
96
|
-
)
|
|
97
|
-
end
|
|
98
|
-
return nil unless arg_value
|
|
99
|
-
|
|
100
|
-
initial_vars[param.name] = arg_value
|
|
101
|
-
end
|
|
102
|
-
ctx = CompileTime::BlockContext.new(@checker, initial_variables: initial_vars)
|
|
103
|
-
next ctx.evaluate_block(func.ast.body, scopes:)
|
|
104
|
-
rescue CompileTime::ReturnValue => e
|
|
105
|
-
next e.value
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
types = if @checker.respond_to?(:types)
|
|
111
|
-
@checker.types
|
|
112
|
-
else
|
|
113
|
-
@checker.instance_variable_get(:@ctx).types
|
|
114
|
-
end
|
|
115
|
-
callee_name = if call_expr.callee.is_a?(AST::Specialization) && call_expr.callee.callee.respond_to?(:name)
|
|
116
|
-
call_expr.callee.callee.name
|
|
117
|
-
elsif call_expr.callee.respond_to?(:name)
|
|
118
|
-
call_expr.callee.name
|
|
119
|
-
end
|
|
120
|
-
if callee_name && (type = types[callee_name]) && type.is_a?(Types::Struct)
|
|
121
|
-
fields = {}
|
|
122
|
-
call_expr.arguments.each do |argument|
|
|
123
|
-
val = evaluate_expression(argument.value, scopes:)
|
|
124
|
-
return nil unless val
|
|
125
|
-
fields[argument.name] = val
|
|
126
|
-
end
|
|
127
|
-
next fields
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
if call_expr.callee.is_a?(AST::Specialization) && @checker.respond_to?(:resolve_type_expression)
|
|
131
|
-
resolved = @checker.resolve_type_expression(call_expr.callee)
|
|
132
|
-
if resolved && @checker.respond_to?(:array_type?) && @checker.array_type?(resolved)
|
|
133
|
-
values = []
|
|
134
|
-
call_expr.arguments.each do |argument|
|
|
135
|
-
val = evaluate_expression(argument.value, scopes:)
|
|
136
|
-
return nil unless val
|
|
137
|
-
values << val
|
|
138
|
-
end
|
|
139
|
-
next values
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
@checker.evaluate_compile_time_const_value(call_expr, scopes:)
|
|
144
|
-
},
|
|
255
|
+
resolve_call: ->(call_expr) { resolve_compile_time_call(call_expr, scopes:) },
|
|
145
256
|
)
|
|
146
257
|
end
|
|
147
258
|
end
|
|
@@ -256,13 +367,108 @@ module MilkTea
|
|
|
256
367
|
|
|
257
368
|
nil
|
|
258
369
|
end
|
|
370
|
+
|
|
371
|
+
def resolve_compile_time_call(call_expr, scopes:)
|
|
372
|
+
result = try_const_function_call(call_expr, scopes:)
|
|
373
|
+
return result if result
|
|
374
|
+
|
|
375
|
+
result = try_struct_constructor_call(call_expr, scopes:)
|
|
376
|
+
return result if result
|
|
377
|
+
|
|
378
|
+
result = try_array_constructor_call(call_expr, scopes:)
|
|
379
|
+
return result if result
|
|
380
|
+
|
|
381
|
+
@checker.evaluate_compile_time_const_value(call_expr, scopes:)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def try_const_function_call(call_expr, scopes:)
|
|
385
|
+
return unless call_expr.callee.is_a?(AST::Identifier)
|
|
386
|
+
|
|
387
|
+
func = @checker.top_level_function(call_expr.callee.name)
|
|
388
|
+
return unless func&.ast&.respond_to?(:const) && func.ast.const
|
|
389
|
+
|
|
390
|
+
begin
|
|
391
|
+
initial_vars = {}
|
|
392
|
+
func.ast.params.each_with_index do |param, idx|
|
|
393
|
+
return nil if idx >= call_expr.arguments.length
|
|
394
|
+
|
|
395
|
+
arg_expr = call_expr.arguments[idx].value
|
|
396
|
+
arg_value = case arg_expr
|
|
397
|
+
when AST::Identifier
|
|
398
|
+
@variables[arg_expr.name] || @checker.evaluate_compile_time_const_value(arg_expr, scopes:)
|
|
399
|
+
else
|
|
400
|
+
CompileTime.evaluate(
|
|
401
|
+
arg_expr,
|
|
402
|
+
resolve_identifier: ->(id) { @variables[id.name] || @checker.evaluate_compile_time_const_value(id, scopes:) },
|
|
403
|
+
resolve_member_access: ->(ma) { @checker.evaluate_compile_time_const_value(ma, scopes:) },
|
|
404
|
+
resolve_type_ref: nil,
|
|
405
|
+
resolve_call: nil,
|
|
406
|
+
)
|
|
407
|
+
end
|
|
408
|
+
return nil unless arg_value
|
|
409
|
+
|
|
410
|
+
initial_vars[param.name] = arg_value
|
|
411
|
+
end
|
|
412
|
+
ctx = BlockContext.new(@checker, initial_variables: initial_vars)
|
|
413
|
+
ctx.evaluate_block(func.ast.body, scopes:)
|
|
414
|
+
rescue ReturnValue => e
|
|
415
|
+
e.value
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def try_struct_constructor_call(call_expr, scopes:)
|
|
420
|
+
types = if @checker.respond_to?(:types)
|
|
421
|
+
@checker.types
|
|
422
|
+
else
|
|
423
|
+
@checker.instance_variable_get(:@ctx).types
|
|
424
|
+
end
|
|
425
|
+
callee_name = if call_expr.callee.is_a?(AST::Specialization) && call_expr.callee.callee.respond_to?(:name)
|
|
426
|
+
call_expr.callee.callee.name
|
|
427
|
+
elsif call_expr.callee.respond_to?(:name)
|
|
428
|
+
call_expr.callee.name
|
|
429
|
+
end
|
|
430
|
+
return unless callee_name
|
|
431
|
+
|
|
432
|
+
type = types[callee_name]
|
|
433
|
+
return unless type.is_a?(Types::Struct)
|
|
434
|
+
|
|
435
|
+
fields = {}
|
|
436
|
+
call_expr.arguments.each do |argument|
|
|
437
|
+
val = evaluate_expression(argument.value, scopes:)
|
|
438
|
+
return nil unless val
|
|
439
|
+
fields[argument.name] = val
|
|
440
|
+
end
|
|
441
|
+
fields
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def try_array_constructor_call(call_expr, scopes:)
|
|
445
|
+
return unless call_expr.callee.is_a?(AST::Specialization)
|
|
446
|
+
return unless @checker.respond_to?(:resolve_type_expression)
|
|
447
|
+
|
|
448
|
+
resolved = @checker.resolve_type_expression(call_expr.callee)
|
|
449
|
+
return unless resolved && @checker.respond_to?(:array_type?) && @checker.array_type?(resolved)
|
|
450
|
+
|
|
451
|
+
values = []
|
|
452
|
+
call_expr.arguments.each do |argument|
|
|
453
|
+
val = evaluate_expression(argument.value, scopes:)
|
|
454
|
+
return nil unless val
|
|
455
|
+
values << val
|
|
456
|
+
end
|
|
457
|
+
values
|
|
458
|
+
end
|
|
259
459
|
end
|
|
260
460
|
|
|
261
461
|
class Evaluator < ConstEval::Evaluator
|
|
262
462
|
|
|
263
463
|
def resolve_layout_type(type_ref)
|
|
264
|
-
|
|
265
|
-
|
|
464
|
+
result = begin
|
|
465
|
+
super
|
|
466
|
+
rescue SemanticError
|
|
467
|
+
nil
|
|
468
|
+
end
|
|
469
|
+
return result if result
|
|
470
|
+
return result if result
|
|
471
|
+
|
|
266
472
|
return unless type_ref.respond_to?(:name) && type_ref.name.parts.length >= 1
|
|
267
473
|
|
|
268
474
|
expression = ::MilkTea::AST.build_chain_from_parts(type_ref.name.parts)
|
|
@@ -276,7 +482,6 @@ module MilkTea
|
|
|
276
482
|
nil
|
|
277
483
|
end
|
|
278
484
|
|
|
279
|
-
|
|
280
485
|
end
|
|
281
486
|
|
|
282
487
|
def self.evaluate(expression, resolve_identifier:, resolve_member_access:, resolve_type_ref: nil, resolve_call: nil)
|
|
@@ -354,4 +559,4 @@ module MilkTea
|
|
|
354
559
|
end
|
|
355
560
|
end
|
|
356
561
|
end
|
|
357
|
-
end
|
|
562
|
+
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require_relative "types/predicates"
|
|
4
4
|
|
|
5
5
|
module MilkTea
|
|
6
|
-
module
|
|
6
|
+
module Intrinsics
|
|
7
7
|
include Types::Predicates
|
|
8
8
|
|
|
9
9
|
BUILTIN_CSTR = Types::Registry.primitive("cstr")
|
|
@@ -45,6 +45,13 @@ module MilkTea
|
|
|
45
45
|
"with" => :simd_lane_with,
|
|
46
46
|
}.freeze
|
|
47
47
|
|
|
48
|
+
SPECIALIZED_RECEIVERS = {
|
|
49
|
+
"str_buffer" => { predicate: :str_buffer_type?, kinds: STR_BUFFER_METHOD_KINDS },
|
|
50
|
+
"event" => { predicate: :event_type?, kinds: EVENT_METHOD_KINDS },
|
|
51
|
+
"atomic" => { predicate: :atomic_type?, kinds: ATOMIC_METHOD_KINDS },
|
|
52
|
+
"simd" => { predicate: :simd_type?, kinds: SIMD_METHOD_KINDS },
|
|
53
|
+
}.freeze
|
|
54
|
+
|
|
48
55
|
def type_ref_from_specialization(expression)
|
|
49
56
|
case expression.callee
|
|
50
57
|
when AST::Identifier
|
|
@@ -78,4 +85,4 @@ module MilkTea
|
|
|
78
85
|
expression.is_a?(AST::StringLiteral) && !expression.cstring && expected_type == BUILTIN_CSTR
|
|
79
86
|
end
|
|
80
87
|
end
|
|
81
|
-
end
|
|
88
|
+
end
|
data/lib/milk_tea/core/lexer.rb
CHANGED
|
@@ -106,6 +106,16 @@ module MilkTea
|
|
|
106
106
|
BIN_DIGIT_BYTE = Array.new(256) { |b| b.chr.match?(/[01_]/) }.freeze
|
|
107
107
|
SPACE_BYTE = " ".ord
|
|
108
108
|
|
|
109
|
+
include CharacterClasses
|
|
110
|
+
include Trivia
|
|
111
|
+
include Indentation
|
|
112
|
+
include Numbers
|
|
113
|
+
include Strings
|
|
114
|
+
include Heredocs
|
|
115
|
+
include FormatStrings
|
|
116
|
+
include Symbols
|
|
117
|
+
include Recovery
|
|
118
|
+
|
|
109
119
|
def self.lex(source, path: nil, mode: :syntax_only, recovery_errors: nil)
|
|
110
120
|
result = new(source, path: path, mode:, recovery_errors:).lex
|
|
111
121
|
mode == :with_trivia ? result.tokens : result
|
|
@@ -170,16 +180,6 @@ module MilkTea
|
|
|
170
180
|
@tokens
|
|
171
181
|
end
|
|
172
182
|
|
|
173
|
-
include CharacterClasses
|
|
174
|
-
include Trivia
|
|
175
|
-
include Indentation
|
|
176
|
-
include Numbers
|
|
177
|
-
include Strings
|
|
178
|
-
include Heredocs
|
|
179
|
-
include FormatStrings
|
|
180
|
-
include Symbols
|
|
181
|
-
include Recovery
|
|
182
|
-
|
|
183
183
|
def lex_line(lines, line_index, line, line_number, line_offset, has_newline:)
|
|
184
184
|
tab_index = line.index("\t")
|
|
185
185
|
if tab_index
|
|
@@ -279,43 +279,17 @@ module MilkTea
|
|
|
279
279
|
break
|
|
280
280
|
end
|
|
281
281
|
|
|
282
|
-
if char == "c"
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
raise error
|
|
282
|
+
if (char == "c" || char == "f")
|
|
283
|
+
result = dispatch_cf_prefix(char, line, index, line_number, line_offset, lines:, line_index:)
|
|
284
|
+
if result
|
|
285
|
+
if result[0] == :return
|
|
286
|
+
return result[1]
|
|
287
|
+
else
|
|
288
|
+
index = result[1]
|
|
289
|
+
next
|
|
290
|
+
end
|
|
292
291
|
end
|
|
293
292
|
end
|
|
294
|
-
if char == "c" && line[index + 1] == '"'
|
|
295
|
-
result = lex_string(lines, line_index, line, index, line_number, line_offset:, cstring: true)
|
|
296
|
-
return result.consumed_lines if result.consumed_lines > 1
|
|
297
|
-
|
|
298
|
-
index = result.next_index
|
|
299
|
-
next
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
if char == "f" && heredoc_start?(line, index, format: true)
|
|
303
|
-
return lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: false, format: true)
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
if char == "f" && line[index + 1] == "<" && line[index + 2] == "-" && identifier_start?(line[index + 3])
|
|
307
|
-
error = LexError.new("expected '<<-' for heredoc string; did you mean 'f<<-#{identifier_start_token(line, index + 3)}'?", line: line_number, column: index + 1, path: @path)
|
|
308
|
-
if @recovery_errors
|
|
309
|
-
@recovery_errors << error
|
|
310
|
-
else
|
|
311
|
-
raise error
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
if char == "f" && line[index + 1] == '"'
|
|
316
|
-
index = lex_format_string(line, index, line_number, line_offset:)
|
|
317
|
-
next
|
|
318
|
-
end
|
|
319
293
|
|
|
320
294
|
if char == "<" && heredoc_start?(line, index)
|
|
321
295
|
return lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: false)
|
|
@@ -371,8 +345,6 @@ module MilkTea
|
|
|
371
345
|
1
|
|
372
346
|
end
|
|
373
347
|
|
|
374
|
-
# ── newline emission ────────────────────────────────────────────
|
|
375
|
-
|
|
376
348
|
def emit_line_newline(line, line_number, line_offset, has_newline)
|
|
377
349
|
newline_start = line_offset + line.bytesize
|
|
378
350
|
newline_end = has_newline ? (newline_start + 1) : newline_start
|
|
@@ -393,7 +365,42 @@ module MilkTea
|
|
|
393
365
|
end
|
|
394
366
|
end
|
|
395
367
|
|
|
396
|
-
|
|
368
|
+
def dispatch_cf_prefix(char, line, index, line_number, line_offset, lines:, line_index:)
|
|
369
|
+
return nil unless char == "c" || char == "f"
|
|
370
|
+
|
|
371
|
+
is_c = char == "c"
|
|
372
|
+
is_f = char == "f"
|
|
373
|
+
|
|
374
|
+
if heredoc_start?(line, index, cstring: is_c, format: is_f)
|
|
375
|
+
n = lex_heredoc(lines, line_index, index, line_number, line_offset, cstring: is_c, format: is_f)
|
|
376
|
+
return [:return, n]
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
if line[index + 1] == "<" && line[index + 2] == "-" && identifier_start?(line[index + 3])
|
|
380
|
+
error = LexError.new("expected '<<-' for heredoc string; did you mean '#{char}<<-#{identifier_start_token(line, index + 3)}'?", line: line_number, column: index + 1, path: @path)
|
|
381
|
+
if @recovery_errors
|
|
382
|
+
@recovery_errors << error
|
|
383
|
+
else
|
|
384
|
+
raise error
|
|
385
|
+
end
|
|
386
|
+
return nil
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
if line[index + 1] == '"'
|
|
390
|
+
if is_c
|
|
391
|
+
string_result = lex_string(lines, line_index, line, index, line_number, line_offset:, cstring: true)
|
|
392
|
+
if string_result.consumed_lines > 1
|
|
393
|
+
return [:return, string_result.consumed_lines]
|
|
394
|
+
end
|
|
395
|
+
return [:next, string_result.next_index]
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
new_index = lex_format_string(line, index, line_number, line_offset:)
|
|
399
|
+
return [:next, new_index]
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
nil
|
|
403
|
+
end
|
|
397
404
|
|
|
398
405
|
def token(type, lexeme, literal, line, column, start_offset:, end_offset:)
|
|
399
406
|
Token.new(
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "expressions"
|
|
4
|
+
require_relative "loops"
|
|
5
|
+
require_relative "proc"
|
|
6
|
+
require_relative "resolve"
|
|
7
|
+
require_relative "utils"
|
|
8
|
+
require_relative "foreign_cstr"
|
|
9
|
+
require_relative "declarations"
|
|
10
|
+
require_relative "calls"
|
|
11
|
+
|
|
3
12
|
module MilkTea
|
|
4
13
|
module LowererBlock
|
|
5
14
|
def lower_block(statements, env:, active_defers:, return_type:, loop_flow:, allow_return: true)
|
|
@@ -78,7 +78,7 @@ module MilkTea
|
|
|
78
78
|
end
|
|
79
79
|
IR::AggregateLiteral.new(type:, fields:)
|
|
80
80
|
else
|
|
81
|
-
|
|
81
|
+
raise LoweringError.new("unsupported const value type #{const_value.class}", line: 0, column: 0, path: @ctx.current_analysis_path)
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "resolve"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
require_relative "block"
|
|
6
|
+
require_relative "async/normalization"
|
|
7
|
+
require_relative "async/lowering"
|
|
8
|
+
|
|
3
9
|
module MilkTea
|
|
4
10
|
module LowererFunctions
|
|
5
11
|
def lower_functions
|
|
6
12
|
lowered = []
|
|
13
|
+
cursor = 0
|
|
14
|
+
declarations = @ctx.ast.declarations
|
|
7
15
|
|
|
8
|
-
|
|
9
|
-
while changed
|
|
10
|
-
changed = false
|
|
11
|
-
|
|
16
|
+
while cursor < declarations.length
|
|
12
17
|
expanded_declarations.each do |decl|
|
|
13
18
|
case decl
|
|
14
19
|
when AST::FunctionDef
|
|
@@ -21,7 +26,6 @@ module MilkTea
|
|
|
21
26
|
|
|
22
27
|
lowered << lower_function_decl(instance)
|
|
23
28
|
@artifacts.lowered_function_linkage_names[linkage_name] = true
|
|
24
|
-
changed = true
|
|
25
29
|
end
|
|
26
30
|
else
|
|
27
31
|
linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name)
|
|
@@ -37,7 +41,6 @@ module MilkTea
|
|
|
37
41
|
@artifacts.lowered_function_linkage_names[entrypoint.linkage_name] = true
|
|
38
42
|
end
|
|
39
43
|
end
|
|
40
|
-
changed = true
|
|
41
44
|
end
|
|
42
45
|
when AST::ExtendingBlock
|
|
43
46
|
receiver_type = resolve_extending_receiver_type(@ctx.analysis, decl.type_name)
|
|
@@ -56,7 +59,6 @@ module MilkTea
|
|
|
56
59
|
|
|
57
60
|
lowered << lower_function_decl(instance, receiver_type:)
|
|
58
61
|
@artifacts.lowered_function_linkage_names[linkage_name] = true
|
|
59
|
-
changed = true
|
|
60
62
|
end
|
|
61
63
|
else
|
|
62
64
|
linkage_name = function_binding_c_name(binding, module_name: @ctx.module_name, receiver_type:)
|
|
@@ -64,11 +66,12 @@ module MilkTea
|
|
|
64
66
|
|
|
65
67
|
lowered << lower_function_decl(binding, receiver_type:)
|
|
66
68
|
@artifacts.lowered_function_linkage_names[linkage_name] = true
|
|
67
|
-
changed = true
|
|
68
69
|
end
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
end
|
|
73
|
+
|
|
74
|
+
cursor = declarations.length
|
|
72
75
|
end
|
|
73
76
|
|
|
74
77
|
lowered
|
|
@@ -1518,12 +1518,19 @@ module MilkTea
|
|
|
1518
1518
|
def resolve_type_argument_ref(type_ref, type_params:)
|
|
1519
1519
|
return resolve_type_ref(type_ref, type_params:) unless literal_type_argument_name_candidate?(type_ref)
|
|
1520
1520
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1521
|
+
result = try_resolve_type_ref(type_ref, type_params:)
|
|
1522
|
+
return result if result
|
|
1523
|
+
|
|
1523
1524
|
literal_type_argument = resolve_named_literal_type_argument(type_ref)
|
|
1524
1525
|
return literal_type_argument if literal_type_argument
|
|
1525
1526
|
|
|
1526
|
-
|
|
1527
|
+
resolve_type_ref(type_ref, type_params:)
|
|
1528
|
+
end
|
|
1529
|
+
|
|
1530
|
+
def try_resolve_type_ref(type_ref, type_params:)
|
|
1531
|
+
resolve_type_ref(type_ref, type_params:)
|
|
1532
|
+
rescue LoweringError
|
|
1533
|
+
nil
|
|
1527
1534
|
end
|
|
1528
1535
|
|
|
1529
1536
|
def literal_type_argument_name_candidate?(type_ref)
|