diff --git a/README.md b/README.md
index 55f5282b..e95088c4 100644
--- a/README.md
+++ b/README.md
@@ -18,8 +18,6 @@ There is a [book 📒](https://uberfoo.github.io/assets/docs/dwarf/introduction.
Check it out!
*Nota Bene*: This is a work in progress.
-The parser is pretty good, but not perfect, at recognizing the language.
-However, the errors that it reports aren't always useful.
I appreciate feedback.
Let me know if you love it, or hate it.
diff --git a/doc/book.toml b/doc/book.toml
index af655c29..579aab9f 100644
--- a/doc/book.toml
+++ b/doc/book.toml
@@ -49,4 +49,4 @@ command = "mdbook-mermaid"
[preprocessor.admonish]
command = "mdbook-admonish"
-assets_version = "2.0.2" # do not edit: managed by `mdbook-admonish install`
+assets_version = "3.0.1" # do not edit: managed by `mdbook-admonish install`
diff --git a/doc/mdbook-admonish.css b/doc/mdbook-admonish.css
index c3e9869e..a0a566ab 100644
--- a/doc/mdbook-admonish.css
+++ b/doc/mdbook-admonish.css
@@ -1,31 +1,18 @@
@charset "UTF-8";
:root {
- --md-admonition-icon--note:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--abstract:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--info:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--tip:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--success:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--question:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--warning:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--failure:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--danger:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--bug:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--example:
- url("data:image/svg+xml;charset=utf-8,");
- --md-admonition-icon--quote:
- url("data:image/svg+xml;charset=utf-8,");
- --md-details-icon:
- url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,");
+ --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,");
+ --md-details-icon: url("data:image/svg+xml;charset=utf-8,");
}
:is(.admonition) {
@@ -84,6 +71,8 @@ a.admonition-anchor-link::before {
padding-inline: 4.4rem 1.2rem;
font-weight: 700;
background-color: rgba(68, 138, 255, 0.1);
+ print-color-adjust: exact;
+ -webkit-print-color-adjust: exact;
display: flex;
}
:is(.admonition-title, summary.admonition-title) p {
@@ -99,6 +88,8 @@ html :is(.admonition-title, summary.admonition-title):last-child {
width: 2rem;
height: 2rem;
background-color: #448aff;
+ print-color-adjust: exact;
+ -webkit-print-color-adjust: exact;
mask-image: url('data:image/svg+xml;charset=utf-8,');
-webkit-mask-image: url('data:image/svg+xml;charset=utf-8,');
mask-repeat: no-repeat;
@@ -132,204 +123,204 @@ details[open].admonition > summary.admonition-title::after {
transform: rotate(90deg);
}
-:is(.admonition):is(.note) {
+:is(.admonition):is(.admonish-note) {
border-color: #448aff;
}
-:is(.note) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(68, 138, 255, 0.1);
}
-:is(.note) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #448aff;
- mask-image: var(--md-admonition-icon--note);
- -webkit-mask-image: var(--md-admonition-icon--note);
+ mask-image: var(--md-admonition-icon--admonish-note);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-note);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.abstract, .summary, .tldr) {
+:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) {
border-color: #00b0ff;
}
-:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 176, 255, 0.1);
}
-:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-abstract, .admonish-summary, .admonish-tldr) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b0ff;
- mask-image: var(--md-admonition-icon--abstract);
- -webkit-mask-image: var(--md-admonition-icon--abstract);
+ mask-image: var(--md-admonition-icon--admonish-abstract);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-abstract);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.info, .todo) {
+:is(.admonition):is(.admonish-info, .admonish-todo) {
border-color: #00b8d4;
}
-:is(.info, .todo) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 184, 212, 0.1);
}
-:is(.info, .todo) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00b8d4;
- mask-image: var(--md-admonition-icon--info);
- -webkit-mask-image: var(--md-admonition-icon--info);
+ mask-image: var(--md-admonition-icon--admonish-info);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-info);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.tip, .hint, .important) {
+:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) {
border-color: #00bfa5;
}
-:is(.tip, .hint, .important) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 191, 165, 0.1);
}
-:is(.tip, .hint, .important) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-tip, .admonish-hint, .admonish-important) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00bfa5;
- mask-image: var(--md-admonition-icon--tip);
- -webkit-mask-image: var(--md-admonition-icon--tip);
+ mask-image: var(--md-admonition-icon--admonish-tip);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-tip);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.success, .check, .done) {
+:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) {
border-color: #00c853;
}
-:is(.success, .check, .done) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(0, 200, 83, 0.1);
}
-:is(.success, .check, .done) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-success, .admonish-check, .admonish-done) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #00c853;
- mask-image: var(--md-admonition-icon--success);
- -webkit-mask-image: var(--md-admonition-icon--success);
+ mask-image: var(--md-admonition-icon--admonish-success);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-success);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.question, .help, .faq) {
+:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) {
border-color: #64dd17;
}
-:is(.question, .help, .faq) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(100, 221, 23, 0.1);
}
-:is(.question, .help, .faq) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-question, .admonish-help, .admonish-faq) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #64dd17;
- mask-image: var(--md-admonition-icon--question);
- -webkit-mask-image: var(--md-admonition-icon--question);
+ mask-image: var(--md-admonition-icon--admonish-question);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-question);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.warning, .caution, .attention) {
+:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) {
border-color: #ff9100;
}
-:is(.warning, .caution, .attention) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 145, 0, 0.1);
}
-:is(.warning, .caution, .attention) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-warning, .admonish-caution, .admonish-attention) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff9100;
- mask-image: var(--md-admonition-icon--warning);
- -webkit-mask-image: var(--md-admonition-icon--warning);
+ mask-image: var(--md-admonition-icon--admonish-warning);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-warning);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.failure, .fail, .missing) {
+:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) {
border-color: #ff5252;
}
-:is(.failure, .fail, .missing) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 82, 82, 0.1);
}
-:is(.failure, .fail, .missing) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-failure, .admonish-fail, .admonish-missing) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff5252;
- mask-image: var(--md-admonition-icon--failure);
- -webkit-mask-image: var(--md-admonition-icon--failure);
+ mask-image: var(--md-admonition-icon--admonish-failure);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-failure);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.danger, .error) {
+:is(.admonition):is(.admonish-danger, .admonish-error) {
border-color: #ff1744;
}
-:is(.danger, .error) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(255, 23, 68, 0.1);
}
-:is(.danger, .error) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #ff1744;
- mask-image: var(--md-admonition-icon--danger);
- -webkit-mask-image: var(--md-admonition-icon--danger);
+ mask-image: var(--md-admonition-icon--admonish-danger);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-danger);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.bug) {
+:is(.admonition):is(.admonish-bug) {
border-color: #f50057;
}
-:is(.bug) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(245, 0, 87, 0.1);
}
-:is(.bug) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #f50057;
- mask-image: var(--md-admonition-icon--bug);
- -webkit-mask-image: var(--md-admonition-icon--bug);
+ mask-image: var(--md-admonition-icon--admonish-bug);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-bug);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.example) {
+:is(.admonition):is(.admonish-example) {
border-color: #7c4dff;
}
-:is(.example) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(124, 77, 255, 0.1);
}
-:is(.example) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #7c4dff;
- mask-image: var(--md-admonition-icon--example);
- -webkit-mask-image: var(--md-admonition-icon--example);
+ mask-image: var(--md-admonition-icon--admonish-example);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-example);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
-webkit-mask-repeat: no-repeat;
}
-:is(.admonition):is(.quote, .cite) {
+:is(.admonition):is(.admonish-quote, .admonish-cite) {
border-color: #9e9e9e;
}
-:is(.quote, .cite) > :is(.admonition-title, summary.admonition-title) {
+:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) {
background-color: rgba(158, 158, 158, 0.1);
}
-:is(.quote, .cite) > :is(.admonition-title, summary.admonition-title)::before {
+:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before {
background-color: #9e9e9e;
- mask-image: var(--md-admonition-icon--quote);
- -webkit-mask-image: var(--md-admonition-icon--quote);
+ mask-image: var(--md-admonition-icon--admonish-quote);
+ -webkit-mask-image: var(--md-admonition-icon--admonish-quote);
mask-repeat: no-repeat;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
@@ -340,7 +331,8 @@ details[open].admonition > summary.admonition-title::after {
background-color: var(--sidebar-bg);
}
-.ayu :is(.admonition), .coal :is(.admonition) {
+.ayu :is(.admonition),
+.coal :is(.admonition) {
background-color: var(--theme-hover);
}
diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md
index 3b5712b0..81ddf421 100644
--- a/doc/src/SUMMARY.md
+++ b/doc/src/SUMMARY.md
@@ -16,8 +16,13 @@
- [Dwarf Language Reference]()
- [Items]()
+ - [Enumerations](./reference/enums.md)
+ - [Functions](./reference/functions.md)
+ - [Imports](./reference/imports.md)
+ - [Patterns](./reference/patterns.md)
+ - [Structs](./reference/structs.md)
- [Statements](./reference/statements.md)
- - [Expressions](./reference/expressions.md)
+ - [Expressions]()
- [Literal Expressions](./reference/expressions/literal.md)
- [Unary Expressions](./reference/expressions/unary.md)
- [Binary Expressions](./reference/expressions/binary.md)
diff --git a/doc/src/hacker/dwarf/generics.md b/doc/src/hacker/dwarf/generics.md
index 4d15cdc4..5aac4516 100644
--- a/doc/src/hacker/dwarf/generics.md
+++ b/doc/src/hacker/dwarf/generics.md
@@ -1,27 +1,27 @@
# Generic Types
-For those not in the know, generics are a type of polymorphism.
-They allow one to write code that works with many distinct types.
-This is facilitated by supplying a generic type in your generic code, e.g., a function or a struct.
-A concreted type is supplied at the usage site.
-During compilation, the generic type is replaced with the concrete type.
+Today we're going to talk about how generics are implemented in dwarf.
+Generics are a type of polymorphism, which is a way to have one chunk of code work with multiple types.
+In the generic code, the abstract type is specified by a single capital letter.
+When the code is compiled the abstract type is replaced with a concrete type.
+The concrete type is inferred from the call site.
-Here's a simple example:
+Below are examples of a generic function and a generic type, as well as a usage of each.
```dwarf
// This is a generic function.
// It takes a type T and returns a value of type T.
fn id(x: T) -> T {
- x
+ x + 42
}
// This is a generic type.
// It takes a type T and stores a value of type T.
- struct Box {
- value: T,
+ struct Box {
+ value: U,
}
- impl Box {
+ impl Box {
fn display(self) {
print("Box<{0}>\n".format(self.value));
}
@@ -29,55 +29,87 @@ fn id(x: T) -> T {
fn main() {
// Here we call the generic function with an int.
- let x = id(42);
+ let x = id(54);
print("{0}\n".format(x));
+ chacha::assert(x == 96);
// And here with a float.
- let y = id(9.6);
+ let y = id("Hello World, the answer is ");
print("{0}\n".format(y));
+ chacha::assert(y == "Hello World, the answer is 42");
- // Here we create a Box that stores an int.
- let z = Box{value: "Hello, World!"};
- print("{0}\n".format(z));
+ // Here we create a Box that stores a float.
+ let z = Box{ value: 0.42 };
z.display();
+ chacha::assert(chacha::typeof(z.value) == "float");
- // Let's box a list.
- let α = Box{value: [1, 2, 3]};
- print("{0}\n".format(α));
+ // Let's box a list now.
+ let α = Box{ value: [1, 2, 3] };
α.display();
+ chacha::assert(chacha::typeof(α.value) == "[int]");
+
+ // Let's try something interesting...
+ let β = Box{ value: id("") };
+ β.display();
+ chacha::assert(chacha::typeof(β.value) == "string");
+ chacha::assert(β.value == "42");
}
```
+In the examples above notice that the generic labels, `T` and `U`, are used in the function and type definitions.
+The code in the `main` function uses the generic function and type with no label to be seen.
+That is because concrete types are used in the non-generic, non-definition code.
+
## Requirements
So what does it take to make this happen in dwarf?
Well, like everything else, there's a parser piece, an extruder piece, and an interpreter piece.
+The {{i: parser}} reads the input and looks for generic annotations where appropriate.
+The {{i: extruder}} takes the output of the parser and builds the AST, substituting the generic placeholder with a concrete type.
+The {{i: interpreter}} then takes the AST and evaluates it.
+
### Parser
-### Extruder
+We won't discuss how the parser works, which is covered in the [parser](../arch/parser.md) section.
+Instead we'll look at the parser output.
+But first!
+
+#### Where are generics allowed?
-### Interpreter
-## {{i: Grace}} {{i: AST}} Model
+
+
+
+### Extruder
+
+#### {{i: Grace}} {{i: AST}} Model
Below is an approximation of (a part of) the model that is used to generate (a part of) the dwarf abstract syntax tree ([AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree)).
-The points worth reflecting upon are that `Type` is a generalization over all of the dwarf types.
-Also, `Struct` and `Field` both have relationships to `Type`. separate from `R1`.
+The diagram is UML-ish, and says that **Type** is a supertype, and everything connected by an **R1** label is it's subtype.
+**Field** has two relationships, **R3** and **R4**, to **Struct** and **Type** respectively.
+These relationships are backed by "referential attributes" whose purpose is to store the relationship data.
+In the case of **Field**, **struct** formalizes **R3** and **type** formalizes **R4**.
+
+The points worth reflecting upon are that **Type** is a generalization over all of the dwarf types.
+Also, **Field** and **Generic** both have relationships to **Type**. separate from **R1**.
```mermaid
classDiagram
Type <|-- Generic : R1
Type <|-- Integer : R1
Type <|-- Struct : R1
- Type <|-- Etc : R1
+ Type <|-- Etcetera : R1
Generic --> "0..1" Type : R2
Struct "1" <-- "0..*" Field : R3
Field --> Type : R4
+ class Type
+ <> Type
+
class Generic {
- place_holder: String
- type: Option~R2_Type~
+ label: String
+ *type: Option~R2_Type~
}
class Struct {
@@ -86,11 +118,51 @@ classDiagram
class Field {
name: String
- struct: R3_Struct
- type: R4_Type
+ *struct: R3_Struct
+ *type: R4_Type
}
```
+There is a real model that is much more extensive that is used to generate the AST code.
+Below is the generated code for the actual **Type**, called `ValueType` in the code.
+
+```rust
+pub enum ValueType {
+ Char(Uuid),
+ Empty(Uuid),
+ Enumeration(Uuid),
+ Function(Uuid),
+ Future(Uuid),
+ Generic(Uuid),
+ Import(Uuid),
+ Lambda(Uuid),
+ List(Uuid),
+ ObjectStore(Uuid),
+ Plugin(Uuid),
+ Range(Uuid),
+ Struct(Uuid),
+ Task(Uuid),
+ Ty(Uuid),
+ Unknown(Uuid),
+}
+```
+
+The `Ty` variant is actually imported from yet another, fundamental, model.
+It's definition is below, ond contains what one might expect, given what is missing from above.
+These are the fundamental modeling types, whereas above are the dwarf types.
+
+```rust
+pub enum Ty {
+ Boolean(Uuid),
+ External(Uuid),
+ Float(Uuid),
+ Integer(Uuid),
+ Object(Uuid),
+ String(Uuid),
+ Uuid(Uuid),
+}
+```
+
```dwarf
let definition = "
struct Box {
@@ -104,3 +176,5 @@ print(ast);
```
Mention something about assuming the type of a field expression, and then having to use that to check type.
+
+### Interpreter
\ No newline at end of file
diff --git a/doc/src/reference/enums.md b/doc/src/reference/enums.md
new file mode 100644
index 00000000..1a188139
--- /dev/null
+++ b/doc/src/reference/enums.md
@@ -0,0 +1 @@
+# Enumerations
diff --git a/doc/src/reference/functions.md b/doc/src/reference/functions.md
new file mode 100644
index 00000000..0c5faf50
--- /dev/null
+++ b/doc/src/reference/functions.md
@@ -0,0 +1 @@
+# Functions
diff --git a/doc/src/reference/imports.md b/doc/src/reference/imports.md
new file mode 100644
index 00000000..767a95a5
--- /dev/null
+++ b/doc/src/reference/imports.md
@@ -0,0 +1 @@
+# Imports
diff --git a/doc/src/reference/patterns.md b/doc/src/reference/patterns.md
new file mode 100644
index 00000000..3c9daa33
--- /dev/null
+++ b/doc/src/reference/patterns.md
@@ -0,0 +1 @@
+# Patterns
diff --git a/doc/src/reference/structs.md b/doc/src/reference/structs.md
new file mode 100644
index 00000000..c88ba870
--- /dev/null
+++ b/doc/src/reference/structs.md
@@ -0,0 +1 @@
+# Structs
diff --git a/doc/src/tutorials/mandelbrot/complex.md b/doc/src/tutorials/mandelbrot/complex.md
index 53af1cdd..a1781f97 100644
--- a/doc/src/tutorials/mandelbrot/complex.md
+++ b/doc/src/tutorials/mandelbrot/complex.md
@@ -5,7 +5,7 @@ One element is the real part of the number, and the other is the imaginary part.
The real part is plotted along the x-axis, and the imaginary part is plotted along the y-axis.
Addition and subtraction are defined as you would expect: perform the operation on the real and imaginary parts independently, e.g.: \\((a, m) + (b, n) = (a + b, m + n)\\).
-To multiply two complex numbers, one must refer back to multiplying two binomials: \\((a + bi)(c + di) = ac + adi + bci + bdi^2\\).
+To multiply two complex numbers, one must refer back to multiplying two binomials: \\((a + bi)(c + di) = bdi^2 + bci + adi + ac = bci + adi + ac - bd\\).
But don't get caught up in the math — it's not on the test.
## Defining the Type
@@ -54,6 +54,8 @@ The last two lines are functions provided by the runtime {{i: ChaCha}}.
Having a type is a good start.
We can now create Complex numbers
+### Addition
+
Addition is fairly straightforward:
```dwarf
@@ -73,6 +75,7 @@ impl Complex {
This is an *impl* block.
Functions that belong to the *struct* go into the *impl* block.
+### Squared
Similarly, the square function is not too bad:
@@ -90,6 +93,7 @@ impl Complex {
}
```
+### A Shortcut
Earlier I said that you know if you are in the set if you don't go to infinity and beyond.
We don't have that much time, and there's a shortcut.
While we are iterating, we can just check the absolute value of the complex number.
@@ -117,6 +121,8 @@ There is something worth noting in the last function.
We are returning a *float*, but there is no *return* statement.
Just like in Rust, the last expression in a *block* is the the value of the block.
+### Zero
+
We'll need to be able to create the Complex number "0".
We can do that with a *{{i: static method}}*.
Static methods are functions that belong to the type, rather than an instance of the type.
diff --git a/src/chacha/interpreter/pvt.rs b/src/chacha/interpreter/pvt.rs
index de443f18..4521e2eb 100644
--- a/src/chacha/interpreter/pvt.rs
+++ b/src/chacha/interpreter/pvt.rs
@@ -207,7 +207,7 @@ impl<'a> PrintableValueType<'a> {
let list = s_read!(lu_dog).exhume_list(list).unwrap();
let list = s_read!(list);
let ty = list.r36_value_type(&s_read!(lu_dog))[0].clone();
- write!(f, "{}", PrintableValueType(false, ty, context))
+ write!(f, "[{}]", PrintableValueType(false, ty, context))
}
ValueTypeEnum::XPlugin(ref plugin) => {
let plugin = s_read!(lu_dog).exhume_x_plugin(plugin).unwrap();
diff --git a/src/chacha/value.rs b/src/chacha/value.rs
index 810f3d6f..e28c5d84 100644
--- a/src/chacha/value.rs
+++ b/src/chacha/value.rs
@@ -453,14 +453,16 @@ impl Value {
unreachable!()
}
Value::Vector { ty, inner: _ } => {
- let ty = match &s_read!(ty).subtype {
- ValueTypeEnum::XFuture(id) => {
- let ty = lu_dog.exhume_x_future(id).unwrap();
- let ty = s_read!(ty);
- ty.r2_value_type(lu_dog)[0].clone()
- }
- _ => ty.clone(),
- };
+ // 🚧 This code was here and I don't know why. I think it must
+ // have been a copy/paste error. I commented it out on 12/11/2023.
+ // let ty = match &s_read!(ty).subtype {
+ // ValueTypeEnum::XFuture(id) => {
+ // let ty = lu_dog.exhume_x_future(id).unwrap();
+ // let ty = s_read!(ty);
+ // ty.r2_value_type(lu_dog)[0].clone()
+ // }
+ // _ => ty.clone(),
+ // };
for vt in lu_dog.iter_value_type() {
if let ValueTypeEnum::List(id) = s_read!(vt).subtype {
let list = lu_dog.exhume_list(&id).unwrap();
@@ -1142,7 +1144,9 @@ impl std::ops::Add for Value {
(Value::String(a), Value::Float(b)) => Value::String(a.to_owned() + &b.to_string()),
(Value::Integer(a), Value::Integer(b)) => Value::Integer(a + b),
// (Value::Integer(a), Value::String(b)) => Value::String(a.to_string() + &b),
- // (Value::String(a), Value::Integer(b)) => Value::String(a + &b.to_string()),
+ (Value::String(a), Value::Integer(b)) => {
+ Value::String(a.to_owned() + b.to_string().as_str())
+ }
(Value::String(a), Value::String(b)) => Value::String(a.to_owned() + b),
(Value::Char(a), Value::Char(b)) => Value::String(a.to_string() + &b.to_string()),
(Value::Char(a), Value::String(b)) => Value::String(a.to_string() + &b),
diff --git a/src/dwarf.rs b/src/dwarf.rs
index 8b94a8a7..02341602 100644
--- a/src/dwarf.rs
+++ b/src/dwarf.rs
@@ -305,50 +305,6 @@ impl Type {
}
}
-// impl From<(&Type, &mut LuDogStore, &SarzakStore)> for ValueType {
-// fn from((type_, store, model): (&Type, &mut LuDogStore, &SarzakStore)) -> Self {
-// match type_ {
-// Type::Boolean => {
-// let ty = Ty::new_boolean();
-// ValueType::new_ty(&ty, store)
-// }
-// Type::Empty => ValueType::new_empty(),
-// Type::Float => {
-// let ty = Ty::new_float();
-// ValueType::new_ty(&ty, store)
-// }
-// Type::Integer => {
-// let ty = Ty::new_integer();
-// ValueType::new_ty(&ty, store)
-// }
-// Type::Option(type_) => {
-// let ty = (&**type_, &store, &model).into();
-// let option = WoogOption::new_none(&ty, store);
-// ValueType::new_woog_option(&option, store)
-// }
-// Type::Self_(type_) => panic!("Self is deprecated."),
-// Type::String => {
-// let ty = Ty::new_s_string();
-// ValueType::new_ty(&ty, store)
-// }
-// Type::UserType(type_) => {
-// let name = if let Token::Object(name) = &**type_ {
-// name
-// } else {
-// panic!("Expected UserType to be Token::Object.")
-// };
-// let obj_id = model.exhume_object_id_by_name(&name).unwrap();
-// let ty = model.exhume_ty(obj_id).unwrap();
-// ValueType::new_ty(&ty, store)
-// }
-// Type::Uuid => {
-// let ty = Ty::new_s_uuid();
-// ValueType::new_ty(&ty, store)
-// }
-// }
-// }
-// }
-
#[derive(Clone, Debug, PartialEq)]
pub enum Statement {
Empty,
diff --git a/tests/harness/types/generics/workout.ore b/tests/harness/types/generics/workout.ore
new file mode 100644
index 00000000..4e27ff89
--- /dev/null
+++ b/tests/harness/types/generics/workout.ore
@@ -0,0 +1,45 @@
+// This is a generic function.
+// It takes a type T and returns a value of type T.
+fn id(x: T) -> T {
+ x + 42
+}
+
+// This is a generic type.
+// It takes a type T and stores a value of type T.
+ struct Box {
+ value: T,
+ }
+
+ impl Box {
+ fn display(self) {
+ print("Box<{0}>\n".format(self.value));
+ }
+ }
+
+fn main() {
+ // Here we call the generic function with an int.
+ let x = id(54);
+ print("{0}\n".format(x));
+ chacha::assert(x == 96);
+
+ // And here with a float.
+ let y = id("Hello World, the answer is ");
+ print("{0}\n".format(y));
+ chacha::assert(y == "Hello World, the answer is 42");
+
+ // Here we create a Box that stores a float.
+ let z = Box{ value: 0.42 };
+ z.display();
+ chacha::assert(chacha::typeof(z.value) == "float");
+
+ // Let's box a list now.
+ let α = Box{ value: [1, 2, 3] };
+ α.display();
+ chacha::assert(chacha::typeof(α.value) == "[int]");
+
+ // Let's try something interesting...
+ let β = Box{ value: id("") };
+ β.display();
+ chacha::assert(chacha::typeof(β.value) == "string");
+ chacha::assert(β.value == "42");
+}
\ No newline at end of file