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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
SLUL specification
==================
Copyright © 2026 Samuel Lidén Borell <samuel@kodafritt.se>
SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later
1. Introduction
===============
1.1. Rationale
--------------
The SLUL language is meant to be:
* Trustworthy from a user point of view; code should always have the minimum
necessary privileges and it should be memory safe without any loopholes.
* As free as possible from recurring maintenance burdens; in particular,
changes in dependencies should not necessite additional tasks for the
dependent modules (such as rebuilds or code adaptations).
* Have a low threshold for use; it should not require a large runtime
(technical threshold) or learning lots of new concepts or terminology
(knowledge threshold).
This document defines the SLUL programming language and its execution
environment.
1.2. Organisation of the Document
---------------------------------
This document is structured in these parts:
1. This introduction
2. A high-level architecture overview
3. Language Syntax and Semantics
4. Module System
5. Runtime Library
6. Subsets and Extensions
7. Binary Interface
Cross-references are given in parentheses, for example (1.2) would refer to
this section.
1.3. Definitions
----------------
* Application
* Execute
* Giveme
* Giveme Section
* I/O
* Library
* Module
* Runtime Loader
* Top-Level
2. Architecture Overview
========================
2.1. Modules
------------
A module is the highest unit for organising software. It can contain a number
of top-level definitions (3.2; 3.3) such as classes. A module can either be
an application module (2.1.1) or a library module (2.1.2).
2.1.1. Application Modules
--------------------------
An application module must define at least one class that is a service (x.x.x).
Each service provides one or more entry points (x.x.x) for the application.
A such entry point can be called upon some environment-defined event, such as
when the application is started, (in graphical applications) when a button
is pressed, (in web applications) when a page is loaded, for example.
Service classes may contain one `giveme` section (x.x.x) for dependency
injection of, for example, I/O or parameters provided by the runtime.
2.1.2. Library Modules
----------------------
A library module defines a interface that may be used from other modules
(applications and as well as other libraries). An interface contains a set of
exported classes and functions, that are defined in the interface file (x.x.x)
of the library.
Libraries can (and should) be versioned (x.x.x), and definitions may be tied
to a specific versions. Versions and their definitions are immutable once
released. From the definitions contained in given version, a so called
"API hash" can be computed (x.x.x).
2.2. The Parts Needed to Load an Application
--------------------------------------------
The following parts are necessary to load an application:
* The application module (2.1.1).
* Any library modules (2.1.2) needed by the program.
* The runtime loader, which loads the main program as well as the library
modules. The runtime loader also processes the `giveme`
section (x.x.x) of each service class.
2.2. Source Files in a Module
-----------------------------
A SLUL module consists of the following files:
* The module source code (`.slul` files, except `interface.slul`)
* For library modules, the interface definition file (`interface.slul`)
* For library modules, an API index file (`api.index`)
* A list of dependencies (`deps.index` file)
* Optionally, a list of all `.slul` and `.index` files.
Here is an example list of files in an application module:
deps.index
SomeCommand.slul
Here is an example list of files in a library module:
deps.index
api.index
sources.index
interface.slul
SomeThing.slul
Section (11.1) contains a list of restrictions on filenames.
2.3. Interface Directories
--------------------------
In order to use a module as a dependency, it must have been copied into an
interface directory with the filename corresponding to the module name, plus
the `.slul` file extension.
For interfaces contained unversioned definitions, the filename must instead
have the format `modulename-apihash.slul`, where the API hash (x.x.x) is
computed over all unversioned definitions with the preceeding version set to
the last defined version (if any).
The compiler looks for interfaces in the following order. Not all directories
are applicable to all operating systems or environments:
* Interface directories specified with compiler command-line options (10.1).
* Per-user interface directories (x.x.x).
* Local interface directories (x.x.x).
* System interface directories (x.x.x).
3. Language Syntax
==================
3.1. Valid Lexical Tokens
-------------------------
TODO
3.2. Anatomy of a Module Source File
------------------------------------
A module source file whose filename begins with an uppercase letter is a
source is a class file. The contents in a class file is considered to be part
of a class (x.x.x) with the same name as the file, minus the directories and
file extension.
A module source file whose filename begins with a lowercase letter is called
a utility file. In a utility file, definitions do not belong to any class.
A class file may contain the following top-level definitions, in the following
order:
1. A service type definition (3.4.1) or a class definition qualifier (3.4.7.1)
2. A `giveme` section (3.4.2)
3. Any number of fields (3.4.3)
4. Any number of constructors (3.4.4)
5. Any number of functions (3.4.5)
Top-level definitions may not be indented.
3.3. Anatomy of an Interface File
---------------------------------
A library module must have an interface file, that describes the exported
definitions. Exported definitions are made available to be used by other
modules.
TODO require interface files to begin with `library <modulename>`?
An interface file may contain the following top-level definitions, in the
following order:
1. Optionally a `usetype` section (3.4.6)
2. Any number of constants (3.4.3.1)
3. Any number of class definitions (3.4.7)
The classes may in turn contain the following top-level definitions, again
in the following order:
1. Any number of fields (3.4.3)
2. Any number of constructors (3.4.4)
3. Any number of functions (3.4.5)
Note that unlike module source files, interface files do not contain `end`
keywords, since top-level definitions automatically end where the next
top-level definition begins.
Top-level definitions may not be indented.
3.4. Top-Level Definitions
--------------------------
3.4.1. Service Type Definitions
3.4.2. `giveme` Sections
3.4.3. Field Definitions
3.4.3.1. Constant Definitions
3.4.4. Constructor Definitions
3.4.5. Function Definitions
3.4.6. `usetype` Sections
when an interface requests a type in `usetype` then any module, that
depends on the interface, must also depend on the module that defines the type.
3.4.7. Class Definitions
3.4.7.1. Class Definition Qualifiers
3.5. Identifier References
--------------------------
There are two types of identifiers: types, which start with an uppercase letter
and function/data identifiers, which start with a lowercase letter.
Identifiers can be defined and referenced in any order, except for local
variables which have to be defined before use (x.x.x).
Identifiers can only be defined once, and may not "shadow" another identifier
in an outer scope. However, identifiers can exist with the same name if they
are in different scopes that are not visible in either of the other scope.
Each module has it's own namespace (x.x.x), and depending on a module only
makes identifiers in the requested version visible, and they only become
visible in the module/interface that requested them (x.x.x). See also `usetype`
(3.4.6).
3.6. Type References
--------------------
TODO Examples of type references
Int
List Int
Int i
List Int l
Map String Int m
Map String List Int ml
List Map String Int lm
GenericType1 (GenericType2 Int) String g
TODO problems:
* Make visual separation clearer between the type and what follows
after it.
- use double spaces?
Int i
List Int l
Map String Int m
Map String List Int ml
List Map String Int lm
GenericType1 (GenericType2 Int) String g
- use alignment?
Int i
List Int l
Map String Int m
Map String List Int ml
List Map String Int lm
GenericType1 (GenericType2 Int) String g
- use parentheses? but perhaps harder to parse?
(Int) i
(List Int) l
(Map String Int) m
(Map String List Int) ml
(List Map String Int) lm
(GenericType1 (GenericType2 Int) String) g
- use a terminator character/sequence?
Int: i
List Int: l
Map String Int: m
Map String List Int: ml
List Map String Int: lm
GenericType1 (GenericType2 Int) String: g
- use brackets/parantheses around the variable identifier?
Int [i]
List Int [l]
Map String Int [m]
Map String List Int [ml]
List Map String Int [lm]
GenericType1 (GenericType2 Int) String [g]
- allow writing generic types together(!):
Int i
ListInt l
MapStringInt m
MapStringListInt ml
ListMapStringInt lm
GenericType1(GenericType2Int)String g
- Use [] or <> like other proglangs (but should there be a comma?)?
Int i
List<Int> l
Map<String,Int> m
Map<String,List<Int>> ml
List<Map<String Int> lm
GenericType1<GenericType2<Int>,String> g
- Use [] between the base type and the type parameters?
(see `notes/combined_list_and_array.txt`).
And use concrete maps? (see next section)
Int i
List[]Int l
MapOfString[]Int m
MapOfString[]List[]Int ml
List[]MapOfString[]Int lm
GenericType1[](GenericType2[]Int)[]String g
* How to call methods of objects of the parameter type?
- Add a possibility to require a specific type.
- Can it be done without a vtable? Maybe pass some info along with the
generic this/object parameters?
- Or don't do that at all, and have StringMap, IntMap, etc.
(which could have a more efficient encoding/lookup).
- But `StringMap Int` is "mixed endian".
- `MapOfString Int` ?
- `MapFromString Int` ?
- `MapFromStringTo Int` ?
- `MapStringTo Int` ?
- `FromStringTo Int` ?
- `LookupWithString Int` ?
- `LookupFromString Int` ?
- Or, even reverse the order? `Int StringMap`
- `Map_String Int` ?
- `LookupS`, `LookupI`
- Or avoid the problem:
- `NameMap`, `NumberMap`, `CustomMap`
- `NameLookup`, `NumberLookup`, `CustomLookup`
- there could also be `AsciiCaseInsensLookup` for example.
(but there are many combinations!)
- Or have "simple objects" that cannot have outgoing pointers,
and have a unique representation of each value, and hence only need
length in order to compare them?
* TODO
3.7. Function Code
------------------
* TODO
4. Module System
================
* TODO
- describe the module system
- describe interface files
- describe API hash computation
* TODO language semantics section (section 5?)
* TODO
5. Semantic Checks and Program Behaviour
========================================
* TODO
6. Runtime Library
==================
* TODO
7. Subsets and Extensions
=========================
* TODO
- how to "invoke" a subset or extension in a module
- the bootstrapping subset
- extensions (which ones should be extensions, and which ones should be
built-in?)
- int64?
- integer wrap-around?
- floating point (different formats, could be several extensions)
- vector?
8. Repositories
===============
x.x.x. Local Repositories
-------------------------
TODO /usr/share/slul-interfaces, /usr/local, ~/.local, %COMMONFILES%, ...
9. Binary Interface
===================
* TODO
- general considerations / rationale
- common definitions
- SYS-V based interface
- Win32/64 based interface?
- WASI based interface?
10. Compiler Command-Line Syntax
===============================
TODO
11. Details
===========
11.1. Restrictions on Filenames
-------------------------------
The purpose of these rules is to support a wide variety of file systems.
Filenames are case-sensitive and must use only English letters a-z (uppercase
and lowercase), digits 0-9 and underscores "_", followed by a dot "." and a
lowercase file extension.
The first character in a filename must always be a letter (not a digit,
dot or underscore).
Each file or directory must have a filename that is case-insensitive distinct
from all other filenames.
No files may have any of the following names, case-insensitive, before the
file extension:
* `aux`
* `com` followed by a digit 0-9
* `con`
* `lpt` followed by a digit 0-9
* `lst`
* `nul`
* `prn`
The total length of a filename, including directory names and a 1 character
separator after each directory, may not exceed 100 characters.
11.2. API hash computation
--------------------------
TODO
|