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