diff options
| author | Cliff Click <cliffc@acm.org> | 2026-10-08 16:52:27 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-10-08 16:52:27 -0700 |
| commit | 7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9 (patch) | |
| tree | bda5cb52577488cb61544c671afa5080297d0381 /chapter25/module.md | |
| parent | 87a75c83b75480e65147a4d425fddd14a05df4d9 (diff) | |
| download | Simple-main.tar.gz Simple-main.zip | |
Support putting static data into ELF constant poolmain
Mostly fcn inits in <clinit>
Diffstat (limited to 'chapter25/module.md')
| -rw-r--r-- | chapter25/module.md | 279 |
1 files changed, 0 insertions, 279 deletions
diff --git a/chapter25/module.md b/chapter25/module.md deleted file mode 100644 index 4cd801e7..00000000 --- a/chapter25/module.md +++ /dev/null @@ -1,279 +0,0 @@ - -# Modules for Simple - -English | [日本語](module.ja.md) - -Goals: -- 1-liner valid program (for easy tutorial/newbie starts) -- - Compile and run with minimal effort -- Separate compilation and namespaces; external libs -- - Compile to ELF or other linkable/executable format -- Easy private fields & classes -- Output files are compatible with existing .o/.exe/lib/dll infrastructure -- No `#include` or `import` files -- Structure / file system heirarchy per module -- - Perhaps many files make a module -- - easy namespaces within a module -- - Nested names in parent file or nested file -- Class initializers guarenteed: -- - execute exactly once -- - lazily on first touch -- - complete on or before first instances are made -- - - (an exception is allowed for a golden instance in `<clinit>`) - - ---- -### Goal: Valid 1-liner, minimal effort - -This makes a module and a class `hello` out of the current working directory -name. Compiling without more arguments also links and executes. - -File: `hello.smp` -``` -sys.io.p("Hello World!"); -``` - -Compile and run: -``` -> smp hello.smp -Hello World! -``` - -Module and class name is `hello` extracted from file name, compiled in memory -and `exec'd`. No files made, this is strictly a run and gun mode. - - ---- -### Goal: separate compilation - -Name a build directory target during compilation to get `.o` files. -The build target directory structure will match the source, and -can be placed anywhere. - -As before, since no module name is mentioned on the compile line, `Pet` becomes -both the module and a class. - -File: Pet.smp -``` -// Class initializer <clinit> is any code outside a struct declaration -// and is guaranteed to run-once on first touch. - -// static fields listed here: -int default_leggies = 4; - -// A default (no argument) <init> is code inside struct with same name as the -// file; this is the same behavior as field initializers for Java, although -// any code is allowed, not just expressions. - -struct Pet { - str name; - int leggies = default_leggies; -} - -float yet_another_static_field; -``` - -Compile to `Pet.o` in the `build/` directory: -``` -> smp Pet.smp -o build/ -> ls build -Pet.o -``` - - ---- -### Goal: nested namespaces - -This makes a module and class `Pet` based on the file name in `myRepo`. It -also makes a nested class `Pet.Vet`. These are used from a different module -`Owner`. - - -Directory: `~/myRepo/` -``` -~/myRepo/ - Pet.smp - build/ - -~/otherRepo/ - Owner.smp -``` - -File: `myRepo/Pet.smp` -``` -int default_leggies = 4; - -struct Pet { - str name; - int leggies = default_leggies; -} - -// Nested class Vet inside of file Pet -struct Vet { - str name; - str address; - long credit_card_num; -} -``` - -File: `otherRepo/Owner.smp` -``` -Pet dog = Pet{name="Fido"}; -Pet snake = Pet{name="slither", leggies = 0; }; -Pet.Vet vet = Pet.Vet{name="Linda"; address="101 Main St"; credit_card_num=1234}; - -sys.io.p("I took "+dog.name+" to "+vet.name+"\n"); -``` - -Compile to `Pet.o` in the `build/` directory; since the compile line does not -mention some other module root, `Pet` must be the module (and is also a class). -Since `Pet` is the module, `Vet` is a class within the module `Pet`. - -``` -> smp Pet.smp -o build/ -> ls build -Pet.o -``` - -The code for both `Pet` and `Pet.Vet` are in the same `Pet.o` file. - -Compile and run `Owner.smp`, specifying the `Pet` repo to satisfy the free -variables `Pet` and `Pet.Vet`. - -``` -> smp Owner.smp -lib ~/myRepo/build -I took Fido to Linda -``` - ---- -### Goal: nested namespace in a nested file - -Same as the last example but with nested files: - -``` -~/myRepo - Pet.smp - Pet/ - Vet.smp - build/ - Pet.o - Pet/ - Vet.o - -~/otherRepo - Owner.smp -``` - - -File: Pet.smp -``` -int default_leggies = 4; - -struct Pet { - str name; - int leggies = default_leggies; -} -``` - -File: Pet/Vet.smp -``` -// Nested class Vet inside of directory Pet -struct Vet { - str name; - str address; - long credit_card_num; -} -``` - -Compile and run `Owner.smp`: -``` -> smp Owner.smp -lib ~/myRepo/build -I took Fido to Linda -``` - - ---- -### Goal: Class Initializers are Lazy - -``` -Parent.smp -Parent/ - ChildA.smp - ChildB.smp -``` - -File: `Parent.smp` -``` -sys.io.p("In Parent <clinit>"); -sys.io.p(ChildB.str); -``` - -File: `ChildA.smp` -``` -// <clinit> for ChildA -sys.io.p("In ChildA <clinit>"); -str str = "A"; -``` - -File: `ChildB.smp` -``` -// <clinit> for ChildB -sys.io.p("In ChildB <clinit>"); -str str = "B"; -``` - -Compile and run: -``` -> smp Parent.smp -In Parent <clinit> -In ChildB <clinit> -B - -``` - -### Goal: Easy private fields - -Leading underscore makes field or class private. - -### Goal: similar to C compiler driver syntax - -``` -Simple --cpu x86_64_v2 --abi Win64 --norun -o lib/lib/sys_x86_64_v2_win64.o src/main/smp/sys.smp -``` - -Module not mentioned, so top-level file is module: `sys` -Module directory not mentioned, so is prefix of file name `src/main/smp`. -Build dir not mentioned, so is prefix of output file: `lib/` -Output file is default `smp.o`, here renamed. - - - -One <clinit> can refer to another, and will be executed as first touched. -Parents must be touched before children by design. -However a child A can refer to a child B. -Touching Parent.B means -- Parent is touched first, and begins <clinit> -- Anything it touches, gets recursively <clinit> including e.g. A or B -- Parent completes. -- Nothing in a <clinit> can refer to another *module*. -- Static functions *can* refer to another module, but then can be executed... - -Goal: deterministic <clinit> within a module. - History: plenty of times I've had complex <clinit> orders, and then discovered - some referred static-final-fields are not yet init'd when child uses. - SubGoal: deterministic <clinit> *order*, Parent before Child, etc. - Issue: mid-Parent <clinit>, refers to Child, so Child <clinit> before Parent completes. - SubAnswer: Since parent first, and "parent knows child", this is OK. - SubIssue: this does not work across modules; one module is not a parent of another - Issue: Parent fcns called during <clinit> can non-determistic init child. - "fcn = { -> rand ? A.fld : B.fld }" - Answer?: Parent <clinit> *may not* direct or indirect refer to a child. - Example: `B b = new B; // Illegal ref to child in Parent.<clinit>` - Example: `B? b = fcn(); fcn = { -> rand ? null : new B; } // Illegal call to fcn referring to B inside Parent <clinit>` - Example: `B? b; fcn = { -> new B; } // OK, no B.<clinit> during Parent.<clinit>` - -Goal: external linkage also enjoys the 1-shot init feature. - Answer?: extern call to 'Foo.foo()' first checks Foo.<clinit> - has run, before calling `Foo.foo()`. Optional: Caller is - modified to bypass <clinit> check after success. -
\ No newline at end of file |
