jade-lang 0.8.0 → 0.10.0
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/CHANGELOG.md +439 -2
- data/docs/interop.md +18 -1
- data/docs/stdlib.md +3 -1
- data/docs/syntax.md +96 -0
- data/lib/jade/api.rb +9 -0
- data/lib/jade/ast.rb +37 -1
- data/lib/jade/cli/eject.rb +132 -0
- data/lib/jade/cli.rb +2 -0
- data/lib/jade/codegen/boundary/specialized/list.rb +11 -7
- data/lib/jade/codegen/boundary/specialized/maybe.rb +2 -2
- data/lib/jade/codegen/boundary/specialized/record.rb +19 -4
- data/lib/jade/codegen/boundary/specialized/scalar.rb +2 -2
- data/lib/jade/codegen/boundary/specialized.rb +13 -5
- data/lib/jade/codegen/boundary.rb +12 -2
- data/lib/jade/codegen/context.rb +17 -0
- data/lib/jade/codegen/error.rb +1 -0
- data/lib/jade/codegen/function_call.rb +23 -7
- data/lib/jade/codegen/function_declaration.rb +25 -13
- data/lib/jade/codegen/helpers.rb +27 -4
- data/lib/jade/codegen/implementation.rb +2 -2
- data/lib/jade/codegen/inline.rb +1 -1
- data/lib/jade/codegen/inlines.rb +6 -1
- data/lib/jade/codegen/names.rb +31 -0
- data/lib/jade/codegen/pattern/constructor.rb +2 -2
- data/lib/jade/codegen/transforms/fold_shape.rb +1 -1
- data/lib/jade/codegen.rb +76 -15
- data/lib/jade/compiler.rb +2 -0
- data/lib/jade/entry.rb +1 -1
- data/lib/jade/error.rb +5 -0
- data/lib/jade/extensions.rb +70 -0
- data/lib/jade/formatter/calls.rb +68 -11
- data/lib/jade/formatter/collections.rb +4 -4
- data/lib/jade/formatter/declarations.rb +13 -15
- data/lib/jade/formatter/helper.rb +20 -0
- data/lib/jade/formatter/infix_application.rb +19 -4
- data/lib/jade/formatter/lambda.rb +24 -12
- data/lib/jade/formatter/pattern.rb +3 -0
- data/lib/jade/frontend/desugaring/placeholder.rb +40 -17
- data/lib/jade/frontend/desugaring.rb +29 -9
- data/lib/jade/frontend/fixity_fixer.rb +6 -4
- data/lib/jade/frontend/forward_declaration/error/alias_expansion.rb +23 -0
- data/lib/jade/frontend/forward_declaration/error/duplicate_constructor_name.rb +45 -0
- data/lib/jade/frontend/forward_declaration/error/duplicate_type_name.rb +42 -0
- data/lib/jade/frontend/forward_declaration/error.rb +3 -0
- data/lib/jade/frontend/forward_declaration/helper.rb +58 -0
- data/lib/jade/frontend/forward_declaration/import_declaration.rb +4 -0
- data/lib/jade/frontend/forward_declaration/interface_declaration.rb +6 -0
- data/lib/jade/frontend/forward_declaration/module.rb +4 -0
- data/lib/jade/frontend/forward_declaration/struct_declaration.rb +10 -1
- data/lib/jade/frontend/forward_declaration/type_alias_declaration.rb +37 -0
- data/lib/jade/frontend/forward_declaration/type_declaration.rb +10 -1
- data/lib/jade/frontend/forward_declaration.rb +2 -0
- data/lib/jade/frontend/pattern_analysis/exhaustiveness.rb +47 -43
- data/lib/jade/frontend/pattern_analysis/matrix.rb +28 -219
- data/lib/jade/frontend/pattern_analysis/pattern.rb +132 -0
- data/lib/jade/frontend/pattern_analysis/redundancy.rb +24 -0
- data/lib/jade/frontend/pattern_analysis/signature.rb +220 -0
- data/lib/jade/frontend/pattern_analysis/usefulness.rb +72 -0
- data/lib/jade/frontend/pattern_analysis/witnesses.rb +73 -0
- data/lib/jade/frontend/pattern_analysis.rb +5 -38
- data/lib/jade/frontend/semantic_analysis/body.rb +29 -1
- data/lib/jade/frontend/semantic_analysis/error/duplicate_implementation.rb +39 -0
- data/lib/jade/frontend/semantic_analysis/error/implementation_on_alias.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error/no_base_case.rb +45 -0
- data/lib/jade/frontend/semantic_analysis/error/placeholder_not_allowed.rb +15 -3
- data/lib/jade/frontend/semantic_analysis/error/recursive_type_alias.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error.rb +4 -0
- data/lib/jade/frontend/semantic_analysis/helper.rb +41 -0
- data/lib/jade/frontend/semantic_analysis/implementation.rb +13 -10
- data/lib/jade/frontend/semantic_analysis/inhabitedness.rb +90 -0
- data/lib/jade/frontend/semantic_analysis/interop_import_declaration.rb +28 -16
- data/lib/jade/frontend/semantic_analysis/keyed_call.rb +21 -5
- data/lib/jade/frontend/semantic_analysis/pattern_range.rb +16 -0
- data/lib/jade/frontend/semantic_analysis/struct_declaration.rb +1 -0
- data/lib/jade/frontend/semantic_analysis/type_alias_declaration/cycle_detection.rb +95 -0
- data/lib/jade/frontend/semantic_analysis/type_alias_declaration.rb +48 -0
- data/lib/jade/frontend/semantic_analysis/type_declaration.rb +1 -0
- data/lib/jade/frontend/semantic_analysis.rb +5 -0
- data/lib/jade/frontend/type_checking/canonicalize.rb +1 -0
- data/lib/jade/frontend/type_checking/cascade.rb +90 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/encodable.rb +10 -0
- data/lib/jade/frontend/type_checking/constraints/deriving.rb +5 -4
- data/lib/jade/frontend/type_checking/constraints.rb +18 -3
- data/lib/jade/frontend/type_checking/error/display.rb +49 -0
- data/lib/jade/frontend/type_checking/error/division_by_zero.rb +31 -0
- data/lib/jade/frontend/type_checking/error/empty_range_pattern.rb +25 -0
- data/lib/jade/frontend/type_checking/error/function_body_type_mismatch.rb +4 -3
- data/lib/jade/frontend/type_checking/error/function_call_type_mismatch.rb +108 -5
- data/lib/jade/frontend/type_checking/error/if_branch_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/if_branches_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/if_condition_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/implementation_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/list_item_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/missing_patterns.rb +20 -4
- data/lib/jade/frontend/type_checking/error/pattern_type_mismatch.rb +7 -1
- data/lib/jade/frontend/type_checking/error/range_pattern_type.rb +29 -0
- data/lib/jade/frontend/type_checking/error/record_access_type_mismatch.rb +2 -2
- data/lib/jade/frontend/type_checking/error/recursive_derivation.rb +25 -0
- data/lib/jade/frontend/type_checking/error/type_mismatch.rb +10 -2
- data/lib/jade/frontend/type_checking/error/unreachable_branch.rb +22 -0
- data/lib/jade/frontend/type_checking/error.rb +6 -0
- data/lib/jade/frontend/type_checking/inference/assign.rb +1 -1
- data/lib/jade/frontend/type_checking/inference/case_of.rb +21 -4
- data/lib/jade/frontend/type_checking/inference/division.rb +50 -0
- data/lib/jade/frontend/type_checking/inference/function_call.rb +47 -2
- data/lib/jade/frontend/type_checking/inference/lambda.rb +1 -1
- data/lib/jade/frontend/type_checking/inference/pattern.rb +35 -0
- data/lib/jade/frontend/type_checking/inference/type_alias_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference.rb +2 -0
- data/lib/jade/frontend/type_checking/loader.rb +11 -0
- data/lib/jade/frontend/type_checking/port_resolution.rb +26 -8
- data/lib/jade/frontend/type_checking/substitution.rb +2 -2
- data/lib/jade/frontend/type_checking.rb +3 -1
- data/lib/jade/frontend/usage_analysis.rb +5 -1
- data/lib/jade/interop/boundary.rb +64 -24
- data/lib/jade/interop/error.rb +35 -7
- data/lib/jade/interop/lowering.rb +8 -2
- data/lib/jade/lsp/converters.rb +83 -2
- data/lib/jade/lsp/handlers.rb +122 -25
- data/lib/jade/lsp/snippets.rb +12 -0
- data/lib/jade/lsp/state.rb +11 -4
- data/lib/jade/module_loader/build.rb +36 -0
- data/lib/jade/module_loader.rb +1 -0
- data/lib/jade/parsing/combinators.rb +78 -2
- data/lib/jade/parsing/error.rb +43 -6
- data/lib/jade/parsing/type.rb +5 -3
- data/lib/jade/parsing.rb +140 -26
- data/lib/jade/runtime.rb +32 -13
- data/lib/jade/source.rb +6 -2
- data/lib/jade/stdlib/basics.rb +22 -3
- data/lib/jade/stdlib/char.rb +2 -0
- data/lib/jade/stdlib/clock.rb +6 -2
- data/lib/jade/stdlib/decimal.rb +51 -14
- data/lib/jade/stdlib/intrinsics.rb +59 -6
- data/lib/jade/stdlib/list.rb +37 -1
- data/lib/jade/stdlib/number.rb +47 -0
- data/lib/jade/stdlib/range.rb +211 -0
- data/lib/jade/stdlib.rb +11 -4
- data/lib/jade/symbol/alias.rb +11 -0
- data/lib/jade/symbol/parser.rb +1 -1
- data/lib/jade/symbol.rb +13 -1
- data/lib/jade/task.rb +74 -56
- data/lib/jade/type/anonymous_record.rb +11 -2
- data/lib/jade/type/application.rb +11 -2
- data/lib/jade/type/base.rb +26 -0
- data/lib/jade/type/function.rb +11 -2
- data/lib/jade/type.rb +36 -10
- data/lib/jade/version.rb +1 -1
- data/lib/jade.rb +1 -0
- metadata +35 -3
- data/lib/jade/frontend/type_checking/constraints/deriving/assignable.rb +0 -170
|
@@ -5,12 +5,45 @@ require 'jade/codegen/inlines'
|
|
|
5
5
|
module Jade
|
|
6
6
|
module Stdlib
|
|
7
7
|
module Intrinsics
|
|
8
|
+
# A running app wants the implementations these files carry and not
|
|
9
|
+
# the declarations, which are what read type annotations.
|
|
10
|
+
def self.runtime_only!
|
|
11
|
+
@runtime_only = true
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.declaring!
|
|
15
|
+
@runtime_only = false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.runtime_only?
|
|
19
|
+
@runtime_only ||= false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# A second load of the same file would otherwise store every symbol
|
|
23
|
+
# twice.
|
|
24
|
+
def self.extended(base)
|
|
25
|
+
base.instance_variable_set(:@symbols, nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.reload_for_declarations(files)
|
|
29
|
+
return unless runtime_only?
|
|
30
|
+
|
|
31
|
+
declaring!
|
|
32
|
+
files.each { load "#{__dir__}/#{it}.rb" }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def runtime_only?
|
|
36
|
+
Intrinsics.runtime_only?
|
|
37
|
+
end
|
|
38
|
+
|
|
8
39
|
def generate_entry(registry)
|
|
9
40
|
@entry = entry
|
|
10
41
|
.then { load_env(it, registry) }
|
|
11
42
|
end
|
|
12
43
|
|
|
13
44
|
def variant(name, of:, args: [])
|
|
45
|
+
return if runtime_only?
|
|
46
|
+
|
|
14
47
|
parent = @symbols
|
|
15
48
|
&.find { it.is_a?(Symbol::Union) && it.name == of.to_s }
|
|
16
49
|
|
|
@@ -44,12 +77,14 @@ module Jade
|
|
|
44
77
|
end
|
|
45
78
|
|
|
46
79
|
def union(name, *type_params, constructor: false)
|
|
80
|
+
return if runtime_only?
|
|
81
|
+
|
|
47
82
|
union_symbol = Symbol
|
|
48
83
|
.union(name.to_s, type_params.map { Symbol.var(it, nil) }, [], nil)
|
|
49
84
|
.with(module_name:)
|
|
50
85
|
.tap { store(it) }
|
|
51
86
|
|
|
52
|
-
|
|
87
|
+
if constructor
|
|
53
88
|
Symbol.constructor(
|
|
54
89
|
name.to_s,
|
|
55
90
|
type_params.map { Symbol.var(it, nil) },
|
|
@@ -67,6 +102,8 @@ module Jade
|
|
|
67
102
|
codegen = body || "Jade::Runtime.intr('#{qualified_fn_name}')"
|
|
68
103
|
impl = runtime_impl(qualified_fn_name, params.size, block, body)
|
|
69
104
|
|
|
105
|
+
return Runtime.register(qualified_fn_name, &impl) if runtime_only?
|
|
106
|
+
|
|
70
107
|
Symbol
|
|
71
108
|
.stdlib_function(
|
|
72
109
|
name.to_s,
|
|
@@ -118,6 +155,8 @@ module Jade
|
|
|
118
155
|
end
|
|
119
156
|
|
|
120
157
|
def interface(name, type_param, functions, default: {})
|
|
158
|
+
return if runtime_only?
|
|
159
|
+
|
|
121
160
|
functions
|
|
122
161
|
.map { |k, v| Symbol.parse(v).then { to_interface_function(name, k, it) }.with(module_name:) }
|
|
123
162
|
.then { Symbol.interface(name, Symbol.parse(type_param), it, default, nil) }
|
|
@@ -144,6 +183,8 @@ module Jade
|
|
|
144
183
|
end
|
|
145
184
|
|
|
146
185
|
def implementation(interface_name, type, functions)
|
|
186
|
+
return register_native_impls(interface_name, type, functions) if runtime_only?
|
|
187
|
+
|
|
147
188
|
interface = imports
|
|
148
189
|
.map(&:symbols)
|
|
149
190
|
.then { [symbols, *it] }
|
|
@@ -168,11 +209,17 @@ module Jade
|
|
|
168
209
|
)
|
|
169
210
|
.then { store(it) }
|
|
170
211
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
212
|
+
register_native_impls(interface_name, type, functions)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Dispatch on a native Ruby class is the only part of an
|
|
216
|
+
# implementation a running app can use.
|
|
217
|
+
def register_native_impls(interface_name, type, functions)
|
|
218
|
+
return unless (ruby_classes = @native_types&.[](type))
|
|
219
|
+
|
|
220
|
+
qualified_iface = "#{interface_to_ref(interface_name).module_name}.#{interface_name}"
|
|
221
|
+
qualified_fns = functions.transform_values { "#{module_name}.#{it}" }
|
|
222
|
+
ruby_classes.each { Runtime.register_impl(qualified_iface, it, qualified_fns) }
|
|
176
223
|
end
|
|
177
224
|
|
|
178
225
|
# Accepts both bare/qualified names ('Int', 'Basics.Int') and full type
|
|
@@ -198,6 +245,8 @@ module Jade
|
|
|
198
245
|
end
|
|
199
246
|
|
|
200
247
|
def import(module_name)
|
|
248
|
+
return if runtime_only?
|
|
249
|
+
|
|
201
250
|
@imports = imports + [module_name]
|
|
202
251
|
end
|
|
203
252
|
|
|
@@ -206,6 +255,8 @@ module Jade
|
|
|
206
255
|
end
|
|
207
256
|
|
|
208
257
|
def default_importing(imports)
|
|
258
|
+
return if runtime_only?
|
|
259
|
+
|
|
209
260
|
@default_imports = if imports == :*
|
|
210
261
|
exposes
|
|
211
262
|
else
|
|
@@ -244,6 +295,8 @@ module Jade
|
|
|
244
295
|
@symbols.concat << symbol
|
|
245
296
|
end
|
|
246
297
|
|
|
298
|
+
|
|
299
|
+
|
|
247
300
|
def module_name
|
|
248
301
|
"#{self.name.split('::').last}"
|
|
249
302
|
end
|
data/lib/jade/stdlib/list.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Jade
|
|
|
12
12
|
|
|
13
13
|
function(:singleton, { element: 'a' }, 'List(a)')
|
|
14
14
|
function(:repeat, { element: 'a', times: 'Int' }, 'List(a)')
|
|
15
|
-
function(:range, { begin_: 'Int', end_: 'Int' }, 'List(
|
|
15
|
+
function(:range, { begin_: 'Int', end_: 'Int' }, 'List(Int)')
|
|
16
16
|
function(:"empty?", { list: 'List(a)' }, 'Bool')
|
|
17
17
|
function(:head, { list: 'List(a)' }, 'Maybe(a)')
|
|
18
18
|
function(:tail, { list: 'List(a)' }, 'List(a)')
|
|
@@ -170,6 +170,42 @@ module Jade
|
|
|
170
170
|
),
|
|
171
171
|
)
|
|
172
172
|
|
|
173
|
+
function(
|
|
174
|
+
:sum,
|
|
175
|
+
{ list: 'List(a)' },
|
|
176
|
+
'a',
|
|
177
|
+
constraints: [['Basics.Numeric', 'a']],
|
|
178
|
+
body: Symbol::DerivedFunction.new(
|
|
179
|
+
params: ['list'],
|
|
180
|
+
body: [:call,
|
|
181
|
+
[:stdlib_fn, 'List.fold'],
|
|
182
|
+
[
|
|
183
|
+
[:var, 'list'],
|
|
184
|
+
[:call, [:impl_arg, 0, 'from_int'], [0]],
|
|
185
|
+
[:impl_arg, 0, '(+)'],
|
|
186
|
+
],
|
|
187
|
+
],
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
function(
|
|
192
|
+
:product,
|
|
193
|
+
{ list: 'List(a)' },
|
|
194
|
+
'a',
|
|
195
|
+
constraints: [['Basics.Numeric', 'a']],
|
|
196
|
+
body: Symbol::DerivedFunction.new(
|
|
197
|
+
params: ['list'],
|
|
198
|
+
body: [:call,
|
|
199
|
+
[:stdlib_fn, 'List.fold'],
|
|
200
|
+
[
|
|
201
|
+
[:var, 'list'],
|
|
202
|
+
[:call, [:impl_arg, 0, 'from_int'], [1]],
|
|
203
|
+
[:impl_arg, 0, '(*)'],
|
|
204
|
+
],
|
|
205
|
+
],
|
|
206
|
+
),
|
|
207
|
+
)
|
|
208
|
+
|
|
173
209
|
function(
|
|
174
210
|
'maximum_with',
|
|
175
211
|
{ list: 'List(a)', cmp: 'a, a -> Ordering' },
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'jade/stdlib/intrinsics'
|
|
2
|
+
|
|
3
|
+
module Jade
|
|
4
|
+
module Stdlib
|
|
5
|
+
# `non_zero` cannot live in Basics beside the `NonZero` type it builds,
|
|
6
|
+
# because its `Maybe` comes from a module that needs Basics first.
|
|
7
|
+
module Number
|
|
8
|
+
extend Intrinsics
|
|
9
|
+
|
|
10
|
+
import Basics
|
|
11
|
+
|
|
12
|
+
# What counts as zero is the type's business, so this dispatches
|
|
13
|
+
# rather than asking Ruby whether the value is `0`.
|
|
14
|
+
function(
|
|
15
|
+
:non_zero,
|
|
16
|
+
{ n: 'a' },
|
|
17
|
+
'Maybe(NonZero(a))',
|
|
18
|
+
constraints: [['Basics.Numeric', 'a'], ['Basics.Eq', 'a']],
|
|
19
|
+
body: Symbol::DerivedFunction.new(
|
|
20
|
+
params: ['n'],
|
|
21
|
+
body: [:call,
|
|
22
|
+
[:stdlib_fn, 'Number.checked'],
|
|
23
|
+
[
|
|
24
|
+
[:var, 'n'],
|
|
25
|
+
[:call, [:impl_arg, 0, 'from_int'], [0]],
|
|
26
|
+
[:impl_arg, 1, '(==)'],
|
|
27
|
+
]],
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# For anyone implementing `Numeric` themselves: the divisor arrives
|
|
32
|
+
# wrapped and the arithmetic needs it bare.
|
|
33
|
+
function(:unwrap, { n: 'NonZero(a)' }, 'a')
|
|
34
|
+
|
|
35
|
+
function(
|
|
36
|
+
:checked,
|
|
37
|
+
{ n: 'a', zero: 'a', eq: 'a, a -> Bool' },
|
|
38
|
+
'Maybe(NonZero(a))',
|
|
39
|
+
private: true,
|
|
40
|
+
) do |n, zero, eq|
|
|
41
|
+
eq.call(n, zero) ? Jade::Maybe::Nothing[] : Jade::Maybe::Just[n]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
default_importing(['non_zero'])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'jade/stdlib/compiled'
|
|
2
|
+
|
|
3
|
+
module Jade
|
|
4
|
+
module Stdlib
|
|
5
|
+
module Range
|
|
6
|
+
extend self
|
|
7
|
+
extend Compiled
|
|
8
|
+
|
|
9
|
+
def uri
|
|
10
|
+
'range.jd'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def imports
|
|
14
|
+
[Basics, Maybe, Tuple]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# `..` desugars to `Range.between`, so the module has to be in scope
|
|
18
|
+
# wherever the operator is legal, which is everywhere.
|
|
19
|
+
def default_imports
|
|
20
|
+
[Symbol.type_ref('Range', 'Range')]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def code
|
|
24
|
+
<<~JADE
|
|
25
|
+
module Range exposing (
|
|
26
|
+
Range,
|
|
27
|
+
all,
|
|
28
|
+
between,
|
|
29
|
+
bounded?,
|
|
30
|
+
clamp,
|
|
31
|
+
contains?,
|
|
32
|
+
empty,
|
|
33
|
+
empty?,
|
|
34
|
+
from,
|
|
35
|
+
intersect,
|
|
36
|
+
lower,
|
|
37
|
+
overlaps?,
|
|
38
|
+
to,
|
|
39
|
+
upper,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
type Range(a)
|
|
43
|
+
= Empty
|
|
44
|
+
| Between(a, a)
|
|
45
|
+
| From(a)
|
|
46
|
+
| To(a)
|
|
47
|
+
| All
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def empty -> Range(a)
|
|
51
|
+
Empty
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def all -> Range(a)
|
|
56
|
+
All
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def from(low: a) -> Range(a)
|
|
61
|
+
From(low)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def to(high: a) -> Range(a)
|
|
66
|
+
To(high)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def between(low: a, high: a) -> Range(a)
|
|
71
|
+
if low <= high then
|
|
72
|
+
Between(low, high)
|
|
73
|
+
else
|
|
74
|
+
Empty
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def contains?(range: Range(a), value: a) -> Bool
|
|
80
|
+
case range
|
|
81
|
+
in Empty then False
|
|
82
|
+
in Between(low, high) then low <= value && value <= high
|
|
83
|
+
in From(low) then low <= value
|
|
84
|
+
in To(high) then value <= high
|
|
85
|
+
in All then True
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def empty?(range: Range(a)) -> Bool
|
|
91
|
+
case range
|
|
92
|
+
in Empty then True
|
|
93
|
+
in Between(low, high) then high < low
|
|
94
|
+
in From(_) then False
|
|
95
|
+
in To(_) then False
|
|
96
|
+
in All then False
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def bounded?(range: Range(a)) -> Bool
|
|
102
|
+
case range
|
|
103
|
+
in Empty then True
|
|
104
|
+
in Between(_, _) then True
|
|
105
|
+
in From(_) then False
|
|
106
|
+
in To(_) then False
|
|
107
|
+
in All then False
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def lower(range: Range(a)) -> Maybe(a)
|
|
113
|
+
case range
|
|
114
|
+
in Empty then Nothing
|
|
115
|
+
in Between(low, _) then Just(low)
|
|
116
|
+
in From(low) then Just(low)
|
|
117
|
+
in To(_) then Nothing
|
|
118
|
+
in All then Nothing
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def upper(range: Range(a)) -> Maybe(a)
|
|
124
|
+
case range
|
|
125
|
+
in Empty then Nothing
|
|
126
|
+
in Between(_, high) then Just(high)
|
|
127
|
+
in From(_) then Nothing
|
|
128
|
+
in To(high) then Just(high)
|
|
129
|
+
in All then Nothing
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def intersect(left: Range(a), right: Range(a)) -> Range(a)
|
|
135
|
+
if empty?(left) || empty?(right) then
|
|
136
|
+
Empty
|
|
137
|
+
else
|
|
138
|
+
rebuild(
|
|
139
|
+
highest(lower(left), lower(right)),
|
|
140
|
+
lowest(upper(left), upper(right)),
|
|
141
|
+
)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def overlaps?(left: Range(a), right: Range(a)) -> Bool
|
|
147
|
+
intersect(left, right)
|
|
148
|
+
|> empty?
|
|
149
|
+
|> not
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def clamp(range: Range(a), value: a) -> Maybe(a)
|
|
154
|
+
if empty?(range) then
|
|
155
|
+
Nothing
|
|
156
|
+
else
|
|
157
|
+
value
|
|
158
|
+
|> at_least(lower(range))
|
|
159
|
+
|> at_most(upper(range))
|
|
160
|
+
|> Just
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def rebuild(low: Maybe(a), high: Maybe(a)) -> Range(a)
|
|
166
|
+
case (low, high)
|
|
167
|
+
in (Nothing, Nothing) then All
|
|
168
|
+
in (Just(l), Nothing) then From(l)
|
|
169
|
+
in (Nothing, Just(h)) then To(h)
|
|
170
|
+
in (Just(l), Just(h)) then between(l, h)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def highest(left: Maybe(a), right: Maybe(a)) -> Maybe(a)
|
|
176
|
+
case (left, right)
|
|
177
|
+
in (Nothing, _) then right
|
|
178
|
+
in (_, Nothing) then left
|
|
179
|
+
in (Just(l), Just(r)) then if l <= r then Just(r) else Just(l) end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def lowest(left: Maybe(a), right: Maybe(a)) -> Maybe(a)
|
|
185
|
+
case (left, right)
|
|
186
|
+
in (Nothing, _) then right
|
|
187
|
+
in (_, Nothing) then left
|
|
188
|
+
in (Just(l), Just(r)) then if l <= r then Just(l) else Just(r) end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def at_least(value: a, bound: Maybe(a)) -> a
|
|
194
|
+
case bound
|
|
195
|
+
in Nothing then value
|
|
196
|
+
in Just(low) then if value <= low then low else value end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def at_most(value: a, bound: Maybe(a)) -> a
|
|
202
|
+
case bound
|
|
203
|
+
in Nothing then value
|
|
204
|
+
in Just(high) then if high <= value then high else value end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
JADE
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
data/lib/jade/stdlib.rb
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
require 'set'
|
|
2
|
+
require 'jade/stdlib/intrinsics'
|
|
3
|
+
|
|
4
|
+
# A runtime-only load skipped the declarations; the compiler needs them.
|
|
5
|
+
Jade::Stdlib::Intrinsics.reload_for_declarations(Jade::Runtime::STDLIB)
|
|
6
|
+
|
|
2
7
|
require 'jade/stdlib/basics'
|
|
3
8
|
require 'jade/stdlib/maybe'
|
|
4
9
|
require 'jade/stdlib/tuple'
|
|
5
10
|
require 'jade/stdlib/list'
|
|
6
11
|
require 'jade/stdlib/char'
|
|
12
|
+
require 'jade/stdlib/number'
|
|
7
13
|
require 'jade/stdlib/string'
|
|
8
14
|
require 'jade/stdlib/result'
|
|
9
15
|
require 'jade/stdlib/task'
|
|
@@ -16,6 +22,7 @@ require 'jade/stdlib/bytes'
|
|
|
16
22
|
require 'jade/stdlib/calendar'
|
|
17
23
|
require 'jade/stdlib/clock'
|
|
18
24
|
require 'jade/stdlib/decimal'
|
|
25
|
+
require 'jade/stdlib/range'
|
|
19
26
|
require 'jade/stdlib/show'
|
|
20
27
|
require 'jade/stdlib/debug'
|
|
21
28
|
|
|
@@ -24,21 +31,21 @@ module Jade
|
|
|
24
31
|
extend self
|
|
25
32
|
|
|
26
33
|
INTRINSICS = %w[
|
|
27
|
-
Basics String List Tuple Char Task
|
|
34
|
+
Basics Number String List Tuple Char Task
|
|
28
35
|
Decode Encode
|
|
29
36
|
Bytes
|
|
30
37
|
Dict Set
|
|
31
38
|
Show Debug
|
|
32
39
|
].freeze
|
|
33
|
-
COMPILED = %w[Maybe Result Decode.Params Calendar Clock Decimal].freeze
|
|
40
|
+
COMPILED = %w[Maybe Result Decode.Params Calendar Clock Decimal Range].freeze
|
|
34
41
|
TOPLEVELS = (INTRINSICS + COMPILED).map { it.split('.', 2).first }.to_set.freeze
|
|
35
42
|
STDLIBS = [
|
|
36
|
-
Stdlib::Basics, Stdlib::Maybe, Stdlib::Tuple, Stdlib::List, Stdlib::Char,
|
|
43
|
+
Stdlib::Basics, Stdlib::Maybe, Stdlib::Number, Stdlib::Tuple, Stdlib::List, Stdlib::Char,
|
|
37
44
|
Stdlib::String, Stdlib::Result, Stdlib::Task,
|
|
38
45
|
Stdlib::Dict, Stdlib::Set,
|
|
39
46
|
Stdlib::Decode, Stdlib::Decode::Params, Stdlib::Encode,
|
|
40
47
|
Stdlib::Bytes,
|
|
41
|
-
Stdlib::Calendar, Stdlib::Clock, Stdlib::Decimal, Stdlib::Show, Stdlib::Debug,
|
|
48
|
+
Stdlib::Calendar, Stdlib::Clock, Stdlib::Decimal, Stdlib::Range, Stdlib::Show, Stdlib::Debug,
|
|
42
49
|
]
|
|
43
50
|
# Loaded into the registry but not auto-imported into user modules.
|
|
44
51
|
EXTENSIONS = [
|
data/lib/jade/symbol/parser.rb
CHANGED
data/lib/jade/symbol.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'jade/symbol/base'
|
|
2
|
-
require 'jade/symbol/parser'
|
|
3
2
|
|
|
4
3
|
require 'jade/symbol/anonymous_record'
|
|
5
4
|
require 'jade/symbol/constructor'
|
|
@@ -16,6 +15,7 @@ require 'jade/symbol/record_type'
|
|
|
16
15
|
require 'jade/symbol/stdlib_function'
|
|
17
16
|
require 'jade/symbol/stdlib_implementation'
|
|
18
17
|
require 'jade/symbol/struct'
|
|
18
|
+
require 'jade/symbol/alias'
|
|
19
19
|
require 'jade/symbol/type_application'
|
|
20
20
|
require 'jade/symbol/partial_application'
|
|
21
21
|
require 'jade/symbol/type_ref'
|
|
@@ -122,6 +122,14 @@ module Jade
|
|
|
122
122
|
Struct[nil, name, type_params, nil, span]
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
def predeclared_alias(name, type_params, span)
|
|
126
|
+
Alias[nil, name, type_params, nil, span]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def alias(name, type_params, body, span)
|
|
130
|
+
Alias[nil, name, type_params, body, span]
|
|
131
|
+
end
|
|
132
|
+
|
|
125
133
|
def interface(name, type_var, functions, default, span)
|
|
126
134
|
Interface[nil, name, type_var, functions, default, span]
|
|
127
135
|
end
|
|
@@ -153,7 +161,11 @@ module Jade
|
|
|
153
161
|
]
|
|
154
162
|
end
|
|
155
163
|
|
|
164
|
+
# The parser is the compiler's, and a running app never reads a type
|
|
165
|
+
# annotation, so it loads here rather than with the symbol classes.
|
|
156
166
|
def parse(annotation)
|
|
167
|
+
require_relative 'symbol/parser'
|
|
168
|
+
|
|
157
169
|
Lexer
|
|
158
170
|
.tokenize(Source.new(uri: nil, text: annotation))
|
|
159
171
|
.then { Parser.parse(it) }
|