diff options
| -rw-r--r-- | Specification.md | 465 | ||||
| -rw-r--r-- | bootstrap/Makefile | 2 |
2 files changed, 466 insertions, 1 deletions
diff --git a/Specification.md b/Specification.md new file mode 100644 index 0000000..6eb095f --- /dev/null +++ b/Specification.md @@ -0,0 +1,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 diff --git a/bootstrap/Makefile b/bootstrap/Makefile index 25c437e..1daf304 100644 --- a/bootstrap/Makefile +++ b/bootstrap/Makefile @@ -216,7 +216,7 @@ clang-analyze: clang --analyze $(CLANG_ANALYZE_FLAGS) $(C_SOURCES) $(TEST_C_SOURCES) longlines: if grep -nE '^.{80,}' $(C_SOURCES) $(C_HEADERS) $(TEST_C_SOURCES) \ - $(srcdir)/Makefile; then \ + $(srcdir)/Makefile $(srcdir)/../Specification.md; then \ echo "error: Too long lines detected. Maximum is 80 characters" ;\ false ;\ else \ |
