-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNOTES.si
112 lines (74 loc) · 4.39 KB
/
NOTES.si
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# Need to propagate constants and compute as much as possible.
# Want to be able to solve:
insert :: proc(map: *Map(%K, %V), key: K, val: V) { ... }
# OR
# Maybe instead, we allow full compile-time type procedures that can be specialized:
[[ specialization(key_type) ]] map_key_type :: proc(%T: type): type { ... }
[[ specialization(value_type) ]] map_value_type :: proc(%T: type): type { ... }
insert :: proc(map: *%T, key: key_type(T), val: value_type(T)) { ... }
# Could that even work since specializations can't be polymorphic?
# Another option is allowing constants to be defined in structs:
Map_Type :: struct(%K, %V) {
key_type :: K;
val_type :: V;
...
}
insert :: proc(map: *%T, key: T.key_type, val: T.val_type) { ... }
# At that point, I feel like there isn't much difference between structs and modules...
# The second two options provide more utility as far as allowing types to "relay" other types
# without the need for them to appear in a parameter list. Example:
Range_Iter :: struct {
value_type :: s64;
start: value_type,
end: value_type,
step: value_type,
}
proc iter_value :: proc(iter: *T): T.value_type { ... }
# =============================================================================================
# We still haven't tackled the issue where certain situations really should have
# declaration order dependency. For "global" (i.e. outside of a procedure) declarations,
# order shouldn't really matter as long as we make sure there aren't missing symbols or
# dependency cycles, but procedure-local variables and all parameters (?) should be ordered.
# For example, the following currently passes analysis:
foo :: proc() {
x := y;
y := 0;
}
# While you could argue that this is valid in a way, it's better to think about code in a
# procedure as having some sort of flow (i.e. linear execution plus well-defined control
# flow structures). So this should be caught as an error. I think we had to do the same sort
# of look-behind thing in the bJou compiler...
# As for parameters, I initially thought that they should be ordered as well, but I'm not so
# sure. There isn't really any understood "execution" w.r.t. argument/parameter binding.
# In a lot of ways, it's not too dissimilar to a handful of global declarations in a scope.
# Their "initialization" just happens to come from somewhere else.
# So, I'm not sure why the following should be disallowed (except maybe just for the sake of
# simplicity, which is certainly a valid concern):
casting_identity :: proc(%T: type = typeof(arg), arg: %arg_type): T { return cast(T, arg); }
casting_identity(123); # does nothing
casting_identity(u64, 123); # actually casts to a different type
# I'm not sure what the use cases for allowing this would be...
# Plus this all hinges on two things:
#
# 1. We actually implement default param values, which remains to be seen...
# 2. Default param values can be positioned before non-default. That wasn't really the plan anyways, so
# this may all be a non-issue.
# =============================================================================================
# Another TODO: We need to check types for dependency cycles differently than the way we check declarations.
# For example, the following should not compile, because it is recursive without any indirection and
# thus has infinite size:
List :: struct(%value_type: type) {
value: value_type;
next: List(value_type);
}
# This should compile (note the addition of pointer indirection on `next`):
List :: struct(%value_type: type) {
value: value_type;
next: *List(value_type);
}
# =============================================================================================
# Should we even have non-polymorphic varags? Why not just pass everything in a slice?
takes_ints :: proc(args: [s64]) { ... }
takes_ints([ 1, 2, 3 ]);
# =============================================================================================
# TODO: Check for control-flow paths that don't return in a returning proc.