summaryrefslogtreecommitdiff
path: root/docs/chapter22/README.md
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-21 14:18:23 -0700
committerCliff Click <cliffc@acm.org>2025-07-03 09:50:14 -0700
commit018379b0cf4e286ceacb1e39f34dd80f770e381e (patch)
treed88eae2d5e2d9609f271ec78fb60aaf08c5aaee5 /docs/chapter22/README.md
parent49534ffa88fedb3a4ebc42094e9edb27d456e6d6 (diff)
downloadSimple-linear-chapter22.tar.gz
Simple-linear-chapter22.zip
Chapter 22: A Hello, World!linear-chapter22
Co-authored-by: godalming123 <68993177+godalming123@users.noreply.github.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Diffstat (limited to 'docs/chapter22/README.md')
-rw-r--r--docs/chapter22/README.md194
1 files changed, 194 insertions, 0 deletions
diff --git a/docs/chapter22/README.md b/docs/chapter22/README.md
new file mode 100644
index 00000000..563a245f
--- /dev/null
+++ b/docs/chapter22/README.md
@@ -0,0 +1,194 @@
+# Chapter 22: A Hello, World!
+
+It's high time for strings and printing! In this chapter we look at what it
+takes to make a basic string - not really a full fledged String class, that
+will wait for another chapter.
+
+```java
+sys.io.p("Hello, World!");
+```
+
+Yeah! A 1-liner `Hello, World`! This example can be found in
+`examples/A_helloWorld.smp`.
+
+
+Let's break it down.
+
+- `sys`: is Just A Variable Name. Like other variables, it is looked up in the
+ current scope... which looks completely empty. Every Simple program now starts
+ with the `sys` variable in-scope. `sys` itself a normal `struct`
+ and is defined in `src/main/smp/sys.smp`.
+- `sys.io.p`: lookup the `io` field in `sys` struct, which yields the `sys.io`
+ struct; then a lookup of `p` (short for "print") in the `sys.io` struct.
+ This returns a function.
+- `p("Hello, World!")`: call the function just loaded from the `p` field, with
+ `"Hello, World!"` as a string argument.
+- `"Hello, World!"`: New syntax that yields a constant array of `u8` (chars).
+ The array is otherwise a normal range-checked array, with a leading `#`
+ length field. The array backing data eventually ends up in the *constant
+ pool*, and from there in an ELF file's RODATA section.
+
+
+ You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter22) in a linear Git revision history on the [linear](https://github.com/SeaOfNodes/Simple/tree/linear) branch and [compare](https://github.com/SeaOfNodes/Simple/compare/linear-chapter21...linear-chapter22) it to the previous chapter.
+
+
+## Nested Types and Static Fields
+
+Simple now supports nested types - this is a name-space only change, so no new
+semantics - just the ability to nest type definitions.
+
+```java
+struct Outer {
+ struct Inner {
+ int in;
+ int pi = 3.14;
+ };
+ int out;
+};
+```
+
+Any final field set in the declaration (as opposed to the constructor) is
+automatically a "static" field - it is final for all instances, and does not
+need to be stored in each instances. Instead one copy is kept in a global
+space (not really a *class* object yet) and loaded from there.
+
+In this example:
+- Instances of the `Outer` struct have a single `int` field `out`.
+- Instances of the `Inner` struct have a single `int` field `in`.
+- There exists a `Outer.Inner.pi` field in a global space with value `3.14`.
+
+The `sys` struct is another example, with nested `libc` and `io` structs at
+least. All the fields in these structs are all final, hence static.
+
+
+
+## FFI and I/O Calls
+
+We can now call external / FFI functions, and they are declared like any other
+variable except being assigned "C". Here is the binding for the libc `write`
+call:
+
+`{ i32 fd, i32 buf, i32 len -> i32 } write = "C";`
+
+Any final variable assigned as "C" will be considered defined externally. The
+syntax of this might change slightly to avoid ambiguity with assign the same
+"C" string.
+
+There is no linker support for getting the correct signature or namespace; the
+name `write` has to be unique when linking.
+
+
+## Auto-Import and the "sys." namespace
+
+The `sys` struct includes `libc` bindings, and any default library code
+including e.g. printing support and collections. As of this chapter it
+includes minimal libc bindings and an easy print:
+
+```java
+// top-level default import
+struct sys {
+ // libc bindings
+ /** https://www.man7.org/linux/man-pages/man2/<libc call>.2.html */
+ struct libc {
+ // fd buf len -> len
+ { i32 i64 i32 -> i32 } write = "C";
+ // addr len prot flags fd off -> void*
+ { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C";
+ // mmap flags
+ i32 PROT_EXEC = 4;
+ i32 PROT_READ = 1;
+ i32 PROT_WRITE= 2;
+ i32 PROT_NONE = 0;
+ i32 MAP_PRIVATE = 2;
+ i32 MAP_ANON = 32;
+ };
+ struct io {
+ val p = { u8[~] str ->
+ i64 ptr = str; // cast array base to i64
+ i32 len = str#; // cast length to signed
+ return sys.libc.write(1,ptr,len);
+ };
+ };
+};
+```
+
+The `sys` import itself is Just Another `struct` like any other struct; it has
+fields and assignments and types declared internally. Note that these
+assignments are all final and in the struct declaration, hence these are all
+*static* fields.
+
+
+## Casting a Pointer to an `i64`
+
+You can now cast a pointer to an i64, although not the other way around.
+`i64 ptr = str; // cast array base to i64`
+
+For arrays, this cast is to the array *base* skipping the `#` length field, and
+is suitable for passing to external "C" calls. For structs, this is just the
+struct base. This is used to pass a length-checked Simple array to the libc
+`write` call in the above `sys.io.p` function.
+
+
+## Arrays of Constants and Constant Arrays
+
+The Simple type system now supports the notion of a "constant array" - an array
+of fixed constants, stored in the ELF file in the RODATA section. Currently we
+only support strings at the parser level: `"Hello, World!"` makes a `u8[13]`
+array containing 13 ASCII bytes; like all arrays it has a length and will be
+range-checked at some point.
+
+A constant version of a non-constant array can be assigned using the `u8[~]`
+syntax.
+
+```java
+// Make a mutable array of ints
+int N=4;
+i32[] is = new i32[N];
+// Mutate the array
+for( int i=0; i<N; i++ )
+ is[i] = i*i;
+// Function "sum" can read but not write the array
+val sum = { i32[~] nums -> // Notice the [~] signature marking nums as immutable
+ int sum = 0;
+ for( int i=0; i<nums#; i++ )
+ sum += nums[i];
+ return sum;
+};
+return sum(is);
+```
+
+Note that this affects the deep contents of the array and not the array
+variable itself.
+
+## Quote Characters
+
+The form ``` `0` ``` makes a `u8` value with the ASCII character `0`.
+
+## Continuous Improvement
+
+In the rush to get executable code from
+[Chapters 19](https://github.com/SeaOfNodes/Simple/tree/linear-chapter19),
+[Chapters 20](https://github.com/SeaOfNodes/Simple/tree/linear-chapter20), and
+[Chapters 21](https://github.com/SeaOfNodes/Simple/tree/linear-chapter21), we
+wrote a lot of code in a hurry. That also means we wrote a lot of bugs (sad
+face), and will be paying the price for a few chapters. In this chapter we
+also found and fixed a number of bugs, here's a sample:
+
+- x86 encoding bugs:
+- - `imul` with immediate forms and `setXX` had incorrect `REX` forms.
+- - x86 `div` was taking `RAX,RDX` as the second *input* register; they are already
+ hardwired as the *first* input register.
+- - Many x86 ops that kill `flags` did not state so in the port.
+- - Short forms for some x86 ops (e.g. using the `inc` vs `add+1`)
+- Global Code Motion `ScheduleLate` missed visiting values only visible around
+ loop backedges; also was adding extra dependence edges between loads and
+ stores with different aliasing.
+- Inlining would reset the **idepth** (as expected) but then use the existing
+ `CallNode` and `FunNode` that are *folding* but not yet peep'd away - leading
+ to incorrect **idepth** calculations.
+
+Many more bugs got fixed, but this sample should give an idea of the continuous
+improvements going on. These happen because we have finally reached a point
+where we can aggressive test again - we are writing Real (Simple) Code (tm) and
+running it... and crashing on these bugs. Compilers are big, complex, beasties
+and some amount of bugs and bug fixing is to be expected.