From b4a584ac51b0eaef0d1029362e17a397335842f4 Mon Sep 17 00:00:00 2001 From: Josh Ring Date: Fri, 13 Sep 2024 11:27:05 +0100 Subject: [PATCH] General content update (#35) - Updated favicon to remove circle, enlarge text, C is blue, 3 is purple - Updated landing page for the docs to try to convey a bit more of the project's goals and visually pop - Updated arrays to add multi-dimensional fixed arrays, placed near the bottom as not key, but still helpful - Updated optionals page to add linking to the advanced optionals page and introduce the content on each page - Updated types page to improve the Enum, Optional and Result and some other minor things --- .astro/types.d.ts | 115 ++++---- public/ico.svg | 88 +++++- src/content/docs/guide/index.mdx | 49 ++-- src/content/docs/references/docs/arrays.md | 58 +++- src/content/docs/references/docs/examples.md | 4 + src/content/docs/references/docs/generics.md | 10 +- src/content/docs/references/docs/optionals.md | 9 +- src/content/docs/references/docs/types.md | 250 ++++++++++-------- .../getting-started/firstproject.md | 63 ----- 9 files changed, 386 insertions(+), 260 deletions(-) delete mode 100644 src/content/docs/references/getting-started/firstproject.md diff --git a/.astro/types.d.ts b/.astro/types.d.ts index bd646ea..1411f7b 100644 --- a/.astro/types.d.ts +++ b/.astro/types.d.ts @@ -190,378 +190,371 @@ declare module 'astro:content' { slug: "guide/basic-types-and-values"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "guide/index.mdx": { id: "guide/index.mdx"; slug: "guide"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; "guide/my-first-hello-world.md": { id: "guide/my-first-hello-world.md"; slug: "guide/my-first-hello-world"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "guide/my-first-project.md": { id: "guide/my-first-project.md"; slug: "guide/my-first-project"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/build-system/commands.md": { id: "references/build-system/commands.md"; slug: "references/build-system/commands"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/build-system/index.md": { id: "references/build-system/index.md"; slug: "references/build-system"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/build-system/project.md": { id: "references/build-system/project.md"; slug: "references/build-system/project"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/development/changes.md": { id: "references/development/changes.md"; slug: "references/development/changes"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/development/index.md": { id: "references/development/index.md"; slug: "references/development"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/development/rejectedideas.md": { id: "references/development/rejectedideas.md"; slug: "references/development/rejectedideas"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/anyinterfaces.md": { id: "references/docs/anyinterfaces.md"; slug: "references/docs/anyinterfaces"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/arrays.md": { id: "references/docs/arrays.md"; slug: "references/docs/arrays"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/asm.md": { id: "references/docs/asm.md"; slug: "references/docs/asm"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/attributes.md": { id: "references/docs/attributes.md"; slug: "references/docs/attributes"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/builtins.md": { id: "references/docs/builtins.md"; slug: "references/docs/builtins"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/changesfromc.md": { id: "references/docs/changesfromc.md"; slug: "references/docs/changesfromc"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/cinterop.md": { id: "references/docs/cinterop.md"; slug: "references/docs/cinterop"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/comments.md": { id: "references/docs/comments.md"; slug: "references/docs/comments"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/compare.md": { id: "references/docs/compare.md"; slug: "references/docs/compare"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/compiletime.md": { id: "references/docs/compiletime.md"; slug: "references/docs/compiletime"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/contracts.md": { id: "references/docs/contracts.md"; slug: "references/docs/contracts"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/conversion.md": { id: "references/docs/conversion.md"; slug: "references/docs/conversion"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/defer.md": { id: "references/docs/defer.md"; slug: "references/docs/defer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/define.md": { id: "references/docs/define.md"; slug: "references/docs/define"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/examples.md": { id: "references/docs/examples.md"; slug: "references/docs/examples"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/expressions.md": { id: "references/docs/expressions.md"; slug: "references/docs/expressions"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/faq.md": { id: "references/docs/faq.md"; slug: "references/docs/faq"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/functions.md": { id: "references/docs/functions.md"; slug: "references/docs/functions"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/generics.md": { id: "references/docs/generics.md"; slug: "references/docs/generics"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/libraries.md": { id: "references/docs/libraries.md"; slug: "references/docs/libraries"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/macros.md": { id: "references/docs/macros.md"; slug: "references/docs/macros"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/modules.md": { id: "references/docs/modules.md"; slug: "references/docs/modules"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/naming.md": { id: "references/docs/naming.md"; slug: "references/docs/naming"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/operators.md": { id: "references/docs/operators.md"; slug: "references/docs/operators"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/optionals.md": { id: "references/docs/optionals.md"; slug: "references/docs/optionals"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/optionals_advanced.md": { id: "references/docs/optionals_advanced.md"; slug: "references/docs/optionals_advanced"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/precedence.md": { id: "references/docs/precedence.md"; slug: "references/docs/precedence"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/reflection.md": { id: "references/docs/reflection.md"; slug: "references/docs/reflection"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/sample.md": { id: "references/docs/sample.md"; slug: "references/docs/sample"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/specification.md": { id: "references/docs/specification.md"; slug: "references/docs/specification"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/standard_library.md": { id: "references/docs/standard_library.md"; slug: "references/docs/standard_library"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/statements.md": { id: "references/docs/statements.md"; slug: "references/docs/statements"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/stdlib_refcard.md": { id: "references/docs/stdlib_refcard.md"; slug: "references/docs/stdlib_refcard"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/syntax.md": { id: "references/docs/syntax.md"; slug: "references/docs/syntax"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/types.md": { id: "references/docs/types.md"; slug: "references/docs/types"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/undefinedbehaviour.md": { id: "references/docs/undefinedbehaviour.md"; slug: "references/docs/undefinedbehaviour"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/variables.md": { id: "references/docs/variables.md"; slug: "references/docs/variables"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/docs/vectors.md": { id: "references/docs/vectors.md"; slug: "references/docs/vectors"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/getting-started/allfeatures.md": { id: "references/getting-started/allfeatures.md"; slug: "references/getting-started/allfeatures"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> -} & { render(): Render[".md"] }; -"references/getting-started/firstproject.md": { - id: "references/getting-started/firstproject.md"; - slug: "references/getting-started/firstproject"; - body: string; - collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/getting-started/prebuilt-binaries.md": { id: "references/getting-started/prebuilt-binaries.md"; slug: "references/getting-started/prebuilt-binaries"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/getting-started/primer.md": { id: "references/getting-started/primer.md"; slug: "references/getting-started/primer"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/getting-started/setup.md": { id: "references/getting-started/setup.md"; slug: "references/getting-started/setup"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".md"] }; "references/index.mdx": { id: "references/index.mdx"; slug: "references"; body: string; collection: "docs"; - data: InferEntrySchema<"docs"> + data: any } & { render(): Render[".mdx"] }; }; @@ -573,5 +566,5 @@ declare module 'astro:content' { type AnyEntryMap = ContentEntryMap & DataEntryMap; - type ContentConfig = typeof import("../src/content/config.js"); + type ContentConfig = never; } diff --git a/public/ico.svg b/public/ico.svg index 13cdd08..eb440b3 100644 --- a/public/ico.svg +++ b/public/ico.svg @@ -1,5 +1,83 @@ - - - - - + + diff --git a/src/content/docs/guide/index.mdx b/src/content/docs/guide/index.mdx index 53bd8b0..38327c5 100644 --- a/src/content/docs/guide/index.mdx +++ b/src/content/docs/guide/index.mdx @@ -5,25 +5,40 @@ sidebar: order: 1 --- -Hello, the C3 Guide is a guide to the C3 Programming Language. It is a work in progress, and will be continually updated. - ## What is C3? -C3 is a system programming language based on C. It is an evolution of C enabling the same paradigms and -retaining the same syntax as far as possible. +C3 is an evolution of C and a systems programming language, featuring: + +### 🦺 Ergonomics **and** Safety +- Optionals to safely and quickly handle errors and null. +- Defer to clean up resources. +- Slices and foreach for safe iteration. +- Contracts in comments, to add constraints to your code. + +### ⚑ Performance **by** default +- Write SIMD vectors to program the hardware directly. +- Access to different memory allocators to fine tune performance. +- Zero overhead errors. +- Fast compilation times. +- LLVM backend for industrial strength optimisations. +- Easy to use inline assembly. + +### πŸ”‹Batteries **included** standard library +- Dynamic containers and strings. +- Cross-platform abstractions for ease of use. +- Access to the native platform when you need it. -## Features +### πŸ”§ Leverage **existing** C or C++ libraries +- Full C ABI compatibility. +- C3 can link C code, C can link C3 code. -- Full C ABI compatibility -- Module system -- Generic modules -- Design by contract -- Zero overhead errors -- Semantic macro system -- First-class SIMD vector types -- Struct subtyping -- Safe array access using slices -- Easy to use inline assembly -- Cross-platform standard library which includes dynamic containers and strings -- LLVM backend +### πŸ“¦ Modules **are** the future +- Modules namespace code. +- Modules make encapsulation simple with explicit control. +- Interfaces define shared behaviour to write robust libraries. +- Generic modules make extending code easier. +- Simple struct composition and reuse with struct subtyping. +### πŸŽ“ Macros **without** a PhD +- Macros can be similar to normal functions. +- Or write code that understands the types in your code. diff --git a/src/content/docs/references/docs/arrays.md b/src/content/docs/references/docs/arrays.md index ea7559a..309c6dc 100644 --- a/src/content/docs/references/docs/arrays.md +++ b/src/content/docs/references/docs/arrays.md @@ -8,7 +8,7 @@ sidebar: Arrays have a central role in programming. C3 offers built-in arrays, slices and [vectors](/references/docs/vectors/). The standard library enhances this further with dynamically sized arrays and other collections. -## Fixed arrays +## Fixed size 1D arrays These are declared as `[]`, e.g. `int[4]`. Fixed arrays are treated as values and will be copied if given as parameter. Unlike C, the number is part of its type. Taking a pointer to a fixed array will create a pointer to a fixed array, e.g. `int[4]*`. @@ -33,6 +33,7 @@ When you want to initialize a fixed array without specifying the size, use the [ int[3] a = { 1, 2, 3 }; int[*] b = { 4, 5, 6 }; // Type inferred to be int[3] ``` + ## Slice The final type is the slice `[]` e.g. `int[]`. A slice is a view into either a fixed or variable array. Internally it is represented as a struct containing a pointer and a size. Both fixed and variable arrays may be converted into slices, and slices may be implicitly converted to pointers. @@ -281,3 +282,58 @@ fn void test() } ``` +## Fixed size multi-dimensional arrays + +To declare two dimensional fixed arrays as `[, ] arr`, like `int[4][2] arr`. Below you can see how this compares to C: +```c +// C +// Uses: name[][] +int array_in_c[4][2] = { + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, +}; + +// C3 +// Uses: [][] +// C3 declares the dimensions, inner-most to outer-most +int[4][2] array = { + {1, 2, 3, 4}, + {5, 6, 7, 8}, +}; + +// To match C we must invert the order of the dimensions +int[2][4] array = { + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, +}; + +// C3 also supports Irregular arrays, for example: +int[][4] array = { + { 1 }, + { 2, 3 }, + { 4, 5, 6 }, + { 7, 8, 9, 10 }, +}; +``` + +:::note +Accessing the multi-dimensional fixed array has inverted array index order to when the array was declared. +```c3 +// Uses: [][] +int[2][4] array = { + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, +}; + +// Access fixed array using: array[][] +int value = array[3][1]; // 8 +``` +::: + + diff --git a/src/content/docs/references/docs/examples.md b/src/content/docs/references/docs/examples.md index 2518086..86c8530 100644 --- a/src/content/docs/references/docs/examples.md +++ b/src/content/docs/references/docs/examples.md @@ -565,7 +565,11 @@ macro long @fib(long $n) const long FIB19 = @fib(19); // Same as const long FIB19 = 4181; ``` +:::note +C3 macros are designed to provide a replacement for C preprocessor macros. They extend such macros by providing compile time evaluation using constant folding, which offers an IDE friendly, limited, compile time execution. +However, if you are doing more complex compile time code generation it is recommended to use `$exec` and related techniques to generate code in external scripts instead. +::: Read more about compile time execution [here](/references/docs/compiletime). #### Generic modules diff --git a/src/content/docs/references/docs/generics.md b/src/content/docs/references/docs/generics.md index cd18c62..29a4350 100644 --- a/src/content/docs/references/docs/generics.md +++ b/src/content/docs/references/docs/generics.md @@ -9,14 +9,14 @@ Generic modules are parameterized modules that allow functionality for arbitrary For generic modules, the generic parameters follows the module name: -``` +```c3 // TypeA, TypeB, TypeC are generic parameters. module vector(); ``` Code inside a generic module may use the generic parameters as if they were well-defined symbols: -``` +```c3 module foo_test(); struct Foo @@ -32,7 +32,7 @@ fn Type2 test(Type2 b, Foo *foo) Including a generic module works as usual: -``` +```c3 import foo_test; def FooFloat = Foo(); @@ -51,7 +51,7 @@ foo_test::test()(1.0, &g); Just like for macros, optional constraints may be added to improve compile errors: -``` +```c3 /** * @require $assignable(1, TypeB) && $assignable(1, TypeC) * @require $assignable((TypeB)1, TypeA) && $assignable((TypeC)1, TypeA) @@ -61,7 +61,7 @@ module vector(); /* .. code * ../ ``` -``` +```c3 def testFunction = vector::testFunc(); // This would give the error diff --git a/src/content/docs/references/docs/optionals.md b/src/content/docs/references/docs/optionals.md index f39bb9c..8cf0f22 100644 --- a/src/content/docs/references/docs/optionals.md +++ b/src/content/docs/references/docs/optionals.md @@ -5,6 +5,12 @@ sidebar: order: 114 --- +In this section we will go over the *essential* information about Optionals and safe methods for working with them, for example + [`if (catch optional_value)`](#checking-if-an-optional-is-empty) + and the [Rethrow operator `!`](#using-the-rethrow-operator--to-unwrap-an-optional-value). + +In the [advanced section](../optionals_advanced/) there are other *nice to have* features. Like an alternative to safely unwrap a result from an Optionals using [`if (try optional_value)`](../optionals_advanced/#run-code-if-the-optional-has-a-result) and an unsafe method to [force unwrap `!!`](../optionals_advanced/#force-unwrapping-expressions) a result from an Optional, return [default values for optionals `??`](../optionals_advanced/#return-a-default-value-if-optional-is-empty) if they are empty and other more specialised concepts. + ## What is an Optional? Optionals are a safer alternative to returning `-1` or `null` from @@ -30,8 +36,7 @@ int! b = IoError.FILE_NOT_FOUND?; Unwrapping an Optional is safe because it checks it has a result present before trying to use it. -After unwrapping a variable is a non-Optional, and behaves -like a normal variable. +After unwrapping, the variable then behaves like a normal variable, a non-Optional. ::: ## Checking if an Optional is empty diff --git a/src/content/docs/references/docs/types.md b/src/content/docs/references/docs/types.md index 9e73f02..42b1645 100644 --- a/src/content/docs/references/docs/types.md +++ b/src/content/docs/references/docs/types.md @@ -150,7 +150,7 @@ It is possible to type a floating point by adding a suffix: |------------|---------:| | bf16 | bfloat16 | | f16 | float16 | -| f32 *or f* | float | +| f32 *or* f | float | | f64 | double | | f128 | float128 | @@ -315,125 +315,181 @@ Distinct types is a kind of type alias which creates a new type that has the sam but is - as the name suggests - distinct from it. It cannot implicitly convert into the other type using the syntax `distict = ` - distinct MyId = int; - fn void* get_by_id(MyId id) { ... } +```c3 +distinct MyId = int; +fn void* get_by_id(MyId id) { ... } - fn void test(MyId id) - { - void* val = get_by_id(id); // Ok - void* val2 = get_by_id(1); // Literals convert implicitly - int a = 1; - // void* val3 = get_by_id(a); // ERROR expected a MyId - void* val4 = get_by_id((MyId)a); // Works - // a = id; // ERROR can't assign 'MyId' to 'int' - } +fn void test(MyId id) +{ + void* val = get_by_id(id); // Ok + void* val2 = get_by_id(1); // Literals convert implicitly + int a = 1; + // void* val3 = get_by_id(a); // ERROR expected a MyId + void* val4 = get_by_id((MyId)a); // Works + // a = id; // ERROR can't assign 'MyId' to 'int' +} +``` #### Inline distinct Using `inline` in the `distinct` declaration allows a distinct type to implicitly convert to its underlying type: - distinct Abc = int; - distinct Bcd = inline int; +```c3 +distinct Abc = int; +distinct Bcd = inline int; - fn void test() - { - Abc a = 1; - Bcd b = 1; +fn void test() +{ + Abc a = 1; + Bcd b = 1; - // int i = a; Error: Abc cannot be implicitly converted to 'int' - int i = b; // This is valid + // int i = a; Error: Abc cannot be implicitly converted to 'int' + int i = b; // This is valid - // However, 'inline' does not allow implicit conversion from - // the inline type to the distinct type: - // a = i; Error: Can't implicitly convert 'int' to 'Abc' - // b = i; Error: Can't implicitly convert 'int' to 'Bcd' - } + // However, 'inline' does not allow implicit conversion from + // the inline type to the distinct type: + // a = i; Error: Can't implicitly convert 'int' to 'Abc' + // b = i; Error: Can't implicitly convert 'int' to 'Bcd' +} +``` ### Generic types +```c3 +import generic_list; // Contains the generic MyList - import generic_list; // Contains the generic MyList +struct Foo { + int x; +} - struct Foo { int x; } +// βœ… def for each type used with a generic module. +def IntMyList = MyList(); +MyListFoo working_example; - // Using def - usually recommended: - def IntMyList = MyList(); - IntMyList abc; +// ❌ An inline type definition will give an error. +// It is only allowed in a type definition or macro. +MyList failing_example = MyList(); +``` +Read more about [generic types](/references/docs/generics). - // Inline type definition - MyList bcd = MyList(); +## Enum -Read more about generic types on [the page about generics](/references/docs/generics). +Enum or enumerated types use the following syntax: +```c3 +enum State : int +{ + WAITING, + RUNNING, + TERMINATED +} -## Enum +// Access enum values via: +State current_state = State.WAITING; +``` +The access requires referencing the `enum`'s name as `State.WAITING` because +an enum like `State` is a separate namespace by default, just like C++'s class `enum`. -Enum (enumerated) types use the following syntax: - enum State : int - { - PENDING, - RUNNING, - TERMINATED - } +### Enum associated values -Enum constants are namespaces by default, just like C++'s class enums. So accessing the enums above would for example use `State.PENDING` rather than `PENDING`. +It is possible to associate each enum value with one or more a static values. +```c3 +enum State : int (String description) +{ + WAITING = "waiting", + RUNNING = "running", + TERMINATED = "ended", +} -### Enum type inference +fn void main() +{ + State process = State.RUNNING; + io::printfn("%s", process.description); +} +``` +Multiple static values can be associated with an enum value, for example: +```c3 +struct Position +{ + int x; + int y; +} -When an enum is used in where the type can be inferred, like in case-clauses or in variable assignment, it is allowed to drop the enum name: +enum State : int (String desc, bool active, Position pos) +{ + WAITING = { "waiting", false, { 1, 2} }, + RUNNING = { "running", true, {12,22} }, + TERMINATED = { "ended", false, { 0, 0} }, +} - State foo = PENDING; // State.PENDING is inferred. - switch (foo) +fn void main() +{ + State process = State.RUNNING; + if (process.active) { - case RUNNING: // State.RUNNING is inferred - ... - default: - ... + io::printfn("Process is: %s", process.desc); + io::printfn("Position x: %d", process.pos.x); } +} +``` - fn void test(State s) { ... } - - ... - - test(RUNNING); // State.RUNNING is inferred +### Enum type inference +When an `enum` is used where the type can be inferred, like in switch case-clauses or in variable assignment, the enum name is not required: +```c3 +State process = WAITING; // State.WAITING is inferred. +switch (process) +{ + case RUNNING: // State.RUNNING is inferred + io::printfn("Position x: %d", process.pos.x); + default: + io::printfn("Process is: %s", process.desc); +} -In the case that it collides with a global in the same scope, it needs the qualifier: +fn void test(State s) { ... } - module test; +test(RUNNING); // State.RUNNING is inferred +``` - fn void testState(State s) { ... } +If the `enum` without it's name matches with a global in the same scope, it needs the enum name to be added as a qualifier, for example: +```c3 +module test; - const State RUNNING = State.TERMINATED; // Don't do this! +// Global variable +// ❌ Don't do this! +const State RUNNING = State.TERMINATED; - ... +test(RUNNING); // Ambiguous +test(test::RUNNING); // Uses global variable. +test(State.RUNNING); // Uses enum constant. +``` - test(RUNNING); // Ambiguous - test(test::RUNNING); // Uses global. - test(State.RUNNING); // Uses enum constant. +## Optional Type +An [Optional type](../optionals/) is created by taking a type and appending `!`. +An Optional type behaves like a tagged union, containing either the +result or an Excuse of type [fault](#optional-excuses-are-of-type-fault). -### Enum associated values +```c3 +int! i; +i = 5; // Assigning a real value to i. +i = IOResult.IO_ERROR?; // Assigning an optional result to i. +``` -It is possible to associate each enum value with a static value. +Only variables, expressions and function returns may be Optionals. +Function and macro parameters in their definitions may not be optionals. - enum State : int (String state_desc, bool active) - { - PENDING = { "pending start", false }, - RUNNING = { "running", true }, - TERMINATED = { "ended", false } - } +```c3 +fn Foo*! getFoo() { /* ... */ } // βœ… Ok! +int! x = 0; // βœ… Ok! +fn void processFoo(Foo*! f) { /* ... */ } // ❌ fn paramater +``` - ... - - State s = get_state(); +Read more about the Optional types on the page about [Optionals and error handling](/references/docs/optionals). - io::printfn("Currently the process is %s", s.state_desc); - if (s.active) do_something(); -## Faults +### Optional Excuses are of type Fault -`fault` defines a set of optional result values, that are similar to enums, but are used for -optional returns. +When an [Optional](../optionals/) does not contain a result, it is empty, and has an Excuse, which is of type `fault`. ```c3 fault IOResult @@ -448,35 +504,17 @@ fault MapResult } ``` -Like the typeid, the constants are pointer sized and each value is globally unique, even when -compared to other faults. For example the underlying value of `MapResult.NOT_FOUND` is guaranteed -to be different from `IOResult.IO_ERROR`. This is true even if they are separately compiled. - -A fault may be stored as a normal value, but is also unique in that it may be passed -as the optional result value using the `!` suffix operator. - - -## Optional Result Types - -An *optional result type* is created by taking a type and appending `!`. -An optional result type is a tagged union containing either the *expected result* or *an optional result value* -(which is a fault). - -```c3 -int! i; -i = 5; // Assigning a real value to i. -i = IOResult.IO_ERROR?; // Assigning an optional result to i. -``` - -Only variables and return variables may be optionals. Function and macro parameters may not be optionals. +Like the [typeid type](#the-typeid-type), the constants are pointer sized +and each value is globally unique. For example the underlying value of +`MapResult.NOT_FOUND` is guaranteed to be different from `IOResult.IO_ERROR`. +This is true even if they are separately compiled. -```c3 -fn Foo*! getFoo() { /* ... */ } // Ok! -fn void processFoo(Foo*! f) { /* ... */ } // Error -int! x = 0; // Ok! -``` +:::note +The values assigned to a fault may vary each time a program is compiled. +::: -Read more about the optional types on the page about [optionals and error handling](/references/docs/optionals). +A fault may be stored as a normal value, but is also unique so that it may be passed +in an Optional as a function return value using the [rethrow `!` operator](../optionals/#using-the-rethrow-operator--to-unwrap-an-optional-value). ## Struct types diff --git a/src/content/docs/references/getting-started/firstproject.md b/src/content/docs/references/getting-started/firstproject.md deleted file mode 100644 index aec20a1..0000000 --- a/src/content/docs/references/getting-started/firstproject.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Your First Project -description: Your first project with C3 -sidebar: - order: 4 ---- - -Starting out with C3, you probably want to get a feel for the language, without using the integrated build system. - -Open a text editor and enter the following in a file you call `hello_world.c3`: - -``` -module hello_world; -import std::io; - -fn int main(String[] argv) -{ - io::printn("Hello World!"); - return 0; -} -``` - -Now in the terminal type: - -``` -$ c3c compile hello_world.c3 -$ ./hello_world -Hello World -$ -``` - -## A real project - -Once you go beyond simple files, you want to create a real project. Do so by entering `c3c init hello_world`. - -You will get the following structure: - - -``` -$ c3c init hello_world -$ tree . -. -└── hello_world - β”œβ”€β”€ project.json - β”œβ”€β”€ LICENSE - β”œβ”€β”€ README.md - β”œβ”€β”€ build - β”œβ”€β”€ docs - β”œβ”€β”€ lib - β”œβ”€β”€ resources - β”œβ”€β”€ src - β”‚ └── main.c3 - └── test -``` - -Enter main.c3 and write the same code as above, then anywhere in the project structure: - -``` -$ c3c run -Hello World -$ -``` -