2 Types have a per-module namespace.
3 This is pre-populated with
4 int i8 i16 uint u8 u64 etc
10 Types can be added with:
17 name is optional, and can list (parameters) and /attributes
19 Types can be constructed with
21 name(args) parameterized type
24 (args:: args) procedure type
25 (args:: type) function type
27 I think that for pointer/array constructor, the decoration comes first.
29 is an array of 5 integers, so foo[5] is an int
31 is an owned pointer to bar, so "foo@" is a bar.
33 is an owner pointer to 5 integers while
35 is an array of 5 borrowed pointers to integers.
36 Having the result type at the end fits better with the function type.
38 then foo(1,2) returns a string.
41 The content of struct and record are a list of:
44 fieldname/attribute: type
47 indicate endianness - bigendian littleendian hostendian
50 protected by a given lock??
52 For enum, content is list of
54 where "= value" is optional
57 to assign a pointer, use foo = stuff
58 to update what the pointer points to, use foo^ = stuff
59 to get a reference to store in a pointer....
60 references are either borrowed or owned.
61 a name defined "type^" is a borrowed reference, a name defined
63 borrowed references may be taken of anything, but only remain defined
64 as long as the owner remains defined.
65 owned references can only be taken of ownable objects, and
68 There are various ways to own an object:
70 - ownership of a containing object.
71 - ownership provided by class method
73 non-type names (vars, constants) can be introduced with
75 const prefix: name = value; ...
76 func: name(args::type): statements
77 proc: name(args::result): statements
88 decide on data structure
89 different types can't really be handled by a big switch now,
90 I probably need and object with function pointers.
91 free_value(), vtype_compat(), val_init(),
92 dup_value(), value_cmp(), print_value(), parse_value()
94 parse_value only needed for args - str and num
96 print_value - only needed for print and code-dump
97 dup_value - needed until pointers can make sense
98 vtype_compat - needed for various things
99 value_cmp - needed until we have object behaviours
107 I think I need to disassociate the type from the storage.
108 So a 'value' is a parsed constant, but something new is needed for
109 the content of a variable.
110 Also, something new is needed for an intermediate lvalue such as an
111 index to an array or a field in a record. Ths is a type plus a pointer.
112 What about rvalues and the result of a calculation. I guess I store
113 that in a temp location, with a pointer...
115 I need to be clear what "interp_exec()" returns. Conceptually it
116 can be an object of any type, and for procedures it can be a tuple of
117 objects. It needs to identify a type and a value of that type.
118 The "value" might be a reference into a variable, or it might be
119 a copy from a calculation. Eventually the reference will have
120 ownership information
126 0/ when does 1/2 produce an integer? Only when explicitly expected.
127 1/ remove 'tail' from value
129 3/ Add a 'Vtyped' vtype and a 'type' pointer
130 4/ add an owership enum: borrowed, single
131 3/ add a 'void *valref' ??
132 4/ Convert num bool str label to Vtyped
134 No, this is awkward because propagate_types wants a 'type' and this intermediate
135 format has a enum+pointer. So make it just a pointer...
138 Vunknown - NULL pointer
139 Vnone - special value
142 A 'type' must be able to:
143 check is it can convert to some other type, reporting if it wants to
144 convert to another type. This requires visibility into other types.
145 print, compare, parse
146 add subtract multiply divide index
149 I currently have an enum of types that is used to test comparability
151 This needs to change .... I guess I need a struct type* What goes in it?
153 - scalar/record/struct/array/pointer/func/enum
156 Do I need forward declarations? Maybe I can just be lazy and
157 require everything to be declared eventually.
158 That isn't sufficient for:
159 - mutually recursive functions
160 - mutually recursive structures
162 What about unions ???
163 blend with enum: a tag with fields?
167 .Bool.true = a:char; b:char
170 I like "inheritance" but that doesn't allow the size of the whole to
172 I need a way to talk about which instance is active, even if the value
173 isn't stored. So Pascal-like variant records are good.
174 Maybe a struct could be declared as 'extensible' and other structs
175 could 'extend', and it literally makes it bigger
176 struct a extensible {x1:int}
177 struct b extends a {y1:int}
178 struct c extends a extensible {y2:int}
179 struct d extends c {z1:int}
181 now 'a' has room for x1, (y2 and z1) or y1
182 Which is used depends on context .. or by assertion on content.
183 So extensions can set values for existing fields
184 struct z extends a {x1=4; string c}
186 Syntax is a bit clumsy. Do I need "extensible"??
190 Are enums just a fancy way of doing 'const'?
192 const: a=1; b=2; c; d
193 which defines module-wide consts.
196 which defines consts foo.a foo.b foo.c
197 But I don't really like foo entering the val namespace.
198 If bar:foo, then bar.a could be true/false depending on value of bar.
199 bar.a! could set it?? bar.a=true?
202 How do we allocate new objects?
208 Maybe ^= assigns a borrowed reference, and @= assigns an owned reference.
210 allocating isn't really a top priority, so I should just focus on
215 I need a list of steps again:
217 - look up type by name and add syntax for
224 e.g. int[4] or foo@[3]
225 What is int[5][20] ?? it is an array of int[5], which is backwards.
226 So maybe I want [5][20]int ??
227 declares an array of that type/size
228 name : [] = [ 1,2,3 ]
229 declares an array of 3 numbers.
231 extracts an element from the array,
235 creates a slice, which can be stored in a var (borrowed ref) or
239 - new type class which has a size and member type
240 - new type access methods: index and size(?)
242 - new manifest values: [a,b,c] creates an array of whatever member type.
245 struct name : [[ name : type ]]
246 to define a new struct
248 - add syntax to extra a field from a struct
249 how is this type-checked if I don't know the type yet?
251 - add syntax for pointers
253 a:struct foo^ = new()
257 If I declare "struct foo ..." do I use "foo" or "struct foo" to ref the type?
259 So structs, records, enums, and classes must have distinct names.
261 When do I differentiate between compile-time constants and run-time values?
262 When declaring an array, do I require the size to be constant?
263 In a struct I do ... at time of declaration I calculate the size.
265 I do that too - and it is at run-time.
266 So during parsing, I need to describe the array with a member-type and executable size.
267 When that is evaluated, a type is created.
268 So we really need an executable which returns a type.
269 But ... we need to know the type when doing type analysis. So while variable size
270 is OK, the compiler needs to know what it is. Maybe the size needs to be a constant, as in
271 a names assiged with "size ::= 4*5". This gives the compiler some chance of comparing
272 types of array - and doing range checking on indexes.
274 We currently call var_init to set the type of a variable during type
275 analysis - which makes sense.
276 But for an array we don't have the final type until run-time. So we need an
278 So (for now) the size of an array is either a NUMBER or an IDENTIFIER which must be a
280 I need a point where the type is instantiated - where the variable is evaluated
281 and the size is set. I guess this happens when the 'struct var' is evaluated...
282 no, when a Declare binode is evaluated.
284 What happens if I have
285 a:[foo]number = thing
286 I guess the type analysis needs to afirm that thing has the correct type,
287 then a doesn't need to be initialized.
291 and 'a' hasn't been declared .... obviously an error.
294 For field access, I need to know the type of the variable.
295 But I can delay the look up until type analysis.
296 So a[4] is Index(a, 4) - a binode
297 a.foo is Field(a, "foo") - need a new exec type - Fieldname
298 a(args) is Call(a, args) - need a new Binode type - Tuple.
300 So I have to delay 'const' assessment to later too.
303 Where do type definition go?
304 I don't think they go with statements, they belong separately.
305 I don't want the full separation of a "type" section like Pascal
306 So they probably go at the top level, equivalent to "program" - and before.
307 They start with "struct" or "enum" or "record" etc.
309 So: what about constants? These are currently statements and so affect a scope in time.
310 But for declaring arrays in structs, or initial values of fields, we might want constants.
311 A constant could be within a struct, but only that it too limiting. I need module-wide
320 const { name ::= value ; name ::= value }
323 I'm in the middle of stage-1 on structures.
325 I need a type to parse the declaration into. It needs to be a linked list
326 of fields, each of which is a type, a name, and an initial value. i.e. a 'struct field'.
331 I want signed/unsigned/bitset integers (and probably floats).
332 These are different sizes, and I want to move 'type' out of 'value'
333 so I can have arrays of numbers that are *just* the densely packets numbers.
335 So there are two questions here: how will I handle values in oceani, and
336 what are the semantics of numbers in ocean.
338 I think I want bitops to requires bitsets and arith ops to require signed/unsigned.
339 But there is some overlap.
340 e.g. we use bitops to test if a number is a power of two
341 We sometimes use bitops to multiply, but that is probably best avoided.
344 Converting between the two can be done with simple assignment.
346 So + - * / % require/assume signed or unsigned
347 | & ~ << >> require/assume bitset
349 # accepts either and produces a bitset
351 Other issue is overflow/underflow checking.
352 Do we need another unsigned type - cyclic
354 i32 - signed integer in 32 bits
355 u32 - unsigned integer
356 c32 - unsigned with overflow permitted and ignored
359 int uint cint bset - whatever size.
361 i32 and u32 detect overflow/underflow and set to NaN - all 1's
362 If I want to allow overloading (such a NaN), I need a type that
363 declare no overloading. s32 and c32? Or annotations. !s32 !u32
365 So what about values in oceani? I want to separate out the type and not
368 - return of init, prepare, parse, dup
369 - passed to print, cmp, dup, free, to_int, to_float, to_mpq
370 - field in 'struct variable'
371 - field in 'struct lrval'
373 - intermediate left/right in interp
374 - field in array and struct field
375 - field in 'struct val' for manifest constants
378 variable gets a 'type' pointer and a union which can be a pointer
379 to the value, or the value itself (depending on size)
380 lrval get a type pointer as well, plus the union
385 Struct/array initialisers.
386 I like [a,b,c] rather than {a,b,c} because the latter can look like code.
387 But [] is also array indexing.
388 So an array initializer could look:
389 [ [1] = "hello", [5] = "there" ]
390 and that is confusingly similar to nested initialization
393 1/ use different outer. {} () <> << >>
394 < is possibly as it is not a prefix operator.
395 But nesting results in <<1,2>,<3,4>> which looks like << instead of < <
396 {} I already don't like
397 () is bad enough with function calls - it is best if it is grouping only.
398 though with function calls it is a list ...
399 << [1]="hello", [2]="there" >>... I don't really like that
405 2/ use different inner syntax.
406 [ .[1] = "hello", .[5] = "hello" ]
408 What about a newline-based syntax:
414 Nice, but doesn't actually help. Still need .[] because I want to allow
415 a one-line syntax too.
416 Maybe I just use {} after all.
418 a:[4]int = { [0]=2, [1]=3, [3]=1 }
419 Yes, I guess that is best.