diff options
author | JJ | 2024-05-20 22:38:13 +0000 |
---|---|---|
committer | JJ | 2024-05-20 23:06:12 +0000 |
commit | f2c5b00c13c698414e82b77f076447337e9cbac0 (patch) | |
tree | 1e5e0c63d8034b5d79943973ea2169c6b5a408c8 /docs/book/EXAMPLES.html | |
parent | 9bbf69870ff0e857156ae2cfa36915cb21f90938 (diff) |
Diffstat (limited to 'docs/book/EXAMPLES.html')
-rw-r--r-- | docs/book/EXAMPLES.html | 964 |
1 files changed, 964 insertions, 0 deletions
diff --git a/docs/book/EXAMPLES.html b/docs/book/EXAMPLES.html new file mode 100644 index 0000000..ee37878 --- /dev/null +++ b/docs/book/EXAMPLES.html @@ -0,0 +1,964 @@ +<!DOCTYPE HTML> +<html lang="en" class="light" dir="ltr"> + <head> + <!-- Book generated using mdBook --> + <meta charset="UTF-8"> + <title>Examples - The Puck Programming Language</title> + + + <!-- Custom HTML head --> + + <meta name="description" content=""> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="theme-color" content="#ffffff"> + + <link rel="icon" href="favicon.svg"> + <link rel="shortcut icon" href="favicon.png"> + <link rel="stylesheet" href="css/variables.css"> + <link rel="stylesheet" href="css/general.css"> + <link rel="stylesheet" href="css/chrome.css"> + <link rel="stylesheet" href="css/print.css" media="print"> + + <!-- Fonts --> + <link rel="stylesheet" href="FontAwesome/css/font-awesome.css"> + <link rel="stylesheet" href="fonts/fonts.css"> + + <!-- Highlight.js Stylesheets --> + <link rel="stylesheet" href="highlight.css"> + <link rel="stylesheet" href="tomorrow-night.css"> + <link rel="stylesheet" href="ayu-highlight.css"> + + <!-- Custom theme stylesheets --> + + </head> + <body class="sidebar-visible no-js"> + <div id="body-container"> + <!-- Provide site root to javascript --> + <script> + var path_to_root = ""; + var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light"; + </script> + + <!-- Work around some values being stored in localStorage wrapped in quotes --> + <script> + try { + var theme = localStorage.getItem('mdbook-theme'); + var sidebar = localStorage.getItem('mdbook-sidebar'); + + if (theme.startsWith('"') && theme.endsWith('"')) { + localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); + } + + if (sidebar.startsWith('"') && sidebar.endsWith('"')) { + localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); + } + } catch (e) { } + </script> + + <!-- Set the theme before any content is loaded, prevents flash --> + <script> + var theme; + try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } + if (theme === null || theme === undefined) { theme = default_theme; } + var html = document.querySelector('html'); + html.classList.remove('light') + html.classList.add(theme); + var body = document.querySelector('body'); + body.classList.remove('no-js') + body.classList.add('js'); + </script> + + <input type="checkbox" id="sidebar-toggle-anchor" class="hidden"> + + <!-- Hide / unhide sidebar before it is displayed --> + <script> + var body = document.querySelector('body'); + var sidebar = null; + var sidebar_toggle = document.getElementById("sidebar-toggle-anchor"); + if (document.body.clientWidth >= 1080) { + try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } + sidebar = sidebar || 'visible'; + } else { + sidebar = 'hidden'; + } + sidebar_toggle.checked = sidebar === 'visible'; + body.classList.remove('sidebar-visible'); + body.classList.add("sidebar-" + sidebar); + </script> + + <nav id="sidebar" class="sidebar" aria-label="Table of contents"> + <div class="sidebar-scrollbox"> + <ol class="chapter"><li class="chapter-item expanded affix "><a href="../index.html">The Puck Programming Language</a></li><li class="chapter-item expanded "><a href="OVERVIEW.html"><strong aria-hidden="true">1.</strong> Basic Usage</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">1.1.</strong> Variables and Comments</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.2.</strong> Functions and Indentation</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.3.</strong> Uniform Function Call Syntax</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.4.</strong> Basic Types</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.5.</strong> Conditionals and Pattern Matching</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.6.</strong> Error Handling</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.7.</strong> Blocks and Loops</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.8.</strong> Module System</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.9.</strong> Compile-time Programming</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.10.</strong> Async System and Threading</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.11.</strong> Memory Management</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.12.</strong> Types System</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.13.</strong> Structs and Tuples</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.14.</strong> Unions and Enums</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">1.15.</strong> Classes</div></li></ol></li><li class="chapter-item expanded "><a href="SYNTAX.html"><strong aria-hidden="true">2.</strong> Syntax</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">2.1.</strong> Call Syntax</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">2.2.</strong> Indentation Rules</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">2.3.</strong> Expression Rules</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">2.4.</strong> Reserved Keywords</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">2.5.</strong> A Formal Grammar</div></li></ol></li><li class="chapter-item expanded "><a href="TYPES.html"><strong aria-hidden="true">3.</strong> Type System</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">3.1.</strong> Basic Types</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">3.2.</strong> Parameter Types</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">3.3.</strong> Reference Types</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">3.4.</strong> Abstract Types</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">3.5.</strong> Advanced Types</div></li></ol></li><li class="chapter-item expanded "><a href="MODULES.html"><strong aria-hidden="true">4.</strong> Module System</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">4.1.</strong> What are modules?</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.2.</strong> Using modules</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.3.</strong> Implicit modules</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.4.</strong> Defining interfaces [todo]</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">4.5.</strong> Defining an external API [todo]</div></li></ol></li><li class="chapter-item expanded "><a href="MEMORY_MANAGEMENT.html"><strong aria-hidden="true">5.</strong> Memory Management [todo]</a></li><li class="chapter-item expanded "><a href="METAPROGRAMMING.html"><strong aria-hidden="true">6.</strong> Metaprogramming</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">6.1.</strong> Scope</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">6.2.</strong> Usage</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">6.3.</strong> Quoting [todo]</div></li></ol></li><li class="chapter-item expanded "><a href="ERRORS.html"><strong aria-hidden="true">7.</strong> Error Handling</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">7.1.</strong> Errors as monads</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">7.2.</strong> Errors as checked exceptions</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">7.3.</strong> Errors as effects [todo]</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">7.4.</strong> Unrecoverable Exceptions</div></li></ol></li><li class="chapter-item expanded "><a href="ASYNC.html"><strong aria-hidden="true">8.</strong> Async System</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">8.1.</strong> Effects System [todo]</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">8.2.</strong> Threading [todo]</div></li></ol></li><li class="chapter-item expanded "><a href="INTEROP.html"><strong aria-hidden="true">9.</strong> Language Interop [draft]</a></li><li><ol class="section"><li class="chapter-item expanded "><div><strong aria-hidden="true">9.1.</strong> Rust</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">9.2.</strong> Swift, Nim</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">9.3.</strong> Java, Kotlin</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">9.4.</strong> Python, Racket, C</div></li></ol></li><li class="chapter-item expanded "><div><strong aria-hidden="true">10.</strong> Effects System [draft]</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">11.</strong> Refinement Types [draft]</div></li><li class="chapter-item expanded "><div><strong aria-hidden="true">12.</strong> Dependent Types [draft]</div></li><li class="chapter-item expanded "><a href="EXAMPLES.html" class="active"><strong aria-hidden="true">13.</strong> Examples</a></li></ol> + </div> + <div id="sidebar-resize-handle" class="sidebar-resize-handle"> + <div class="sidebar-resize-indicator"></div> + </div> + </nav> + + <!-- Track and set sidebar scroll position --> + <script> + var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox'); + sidebarScrollbox.addEventListener('click', function(e) { + if (e.target.tagName === 'A') { + sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop); + } + }, { passive: true }); + var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll'); + sessionStorage.removeItem('sidebar-scroll'); + if (sidebarScrollTop) { + // preserve sidebar scroll position when navigating via links within sidebar + sidebarScrollbox.scrollTop = sidebarScrollTop; + } else { + // scroll sidebar to current active section when navigating via "next/previous chapter" buttons + var activeSection = document.querySelector('#sidebar .active'); + if (activeSection) { + activeSection.scrollIntoView({ block: 'center' }); + } + } + </script> + + <div id="page-wrapper" class="page-wrapper"> + + <div class="page"> + <div id="menu-bar-hover-placeholder"></div> + <div id="menu-bar" class="menu-bar sticky"> + <div class="left-buttons"> + <label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar"> + <i class="fa fa-bars"></i> + </label> + <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list"> + <i class="fa fa-paint-brush"></i> + </button> + <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu"> + <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li> + <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li> + <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li> + <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li> + <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li> + </ul> + <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar"> + <i class="fa fa-search"></i> + </button> + </div> + + <h1 class="menu-title">The Puck Programming Language</h1> + + <div class="right-buttons"> + <a href="print.html" title="Print this book" aria-label="Print this book"> + <i id="print-button" class="fa fa-print"></i> + </a> + + </div> + </div> + + <div id="search-wrapper" class="hidden"> + <form id="searchbar-outer" class="searchbar-outer"> + <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header"> + </form> + <div id="searchresults-outer" class="searchresults-outer hidden"> + <div id="searchresults-header" class="searchresults-header"></div> + <ul id="searchresults"> + </ul> + </div> + </div> + + <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> + <script> + document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); + document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); + Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) { + link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); + }); + </script> + + <div id="content" class="content"> + <main> + <h1 id="example-programs"><a class="header" href="#example-programs">Example Programs</a></h1> +<p>These are taken directly from the (work-in-progress) stdlib.</p> +<h2 id="stdoptions"><a class="header" href="#stdoptions">std.options</a></h2> +<pre><code class="language-puck">## std.options: Optional types. +## This module is imported by default. + +use std.format + +## The `Option` type. +## A type that represents either the presence or absence of a value. +pub type Option[T] = union + Some(T) + None + +## Syntactic sugar for optional type declarations. +pub macro ?(T: type) = + quote Option[`T`] + +## Directly accesses the inner value. Throws an exception if None. +pub func ![T](self: T?): T = + if self of Some(x) then x + else raise "empty" + +## Indirect access. Propagates `None`. +pub macro ?[T](self: Option[T]) = + quote + match `self` + of Some(x) then x + of None then return None + +## Checks if a type is present within an `Option` type. +pub func is_some[T](self: T?): bool = + self of Some(_) +## Checks if a type is not present within an `Option` type. +pub func is_none[T](self: T?): bool = + self of None + +## Converts an `Option[T]` to a `Result[T, E]` given a user-provided error. +pub func err[T, E](self: T?, error: E): Result[T, E] = + if self of Some(x) then + Okay(x) + else + Error(error) + +## Applies a function to `T`, if it exists. +pub func map[T, U](self: T?, fn: T -> U): U? = + if self of Some(x) then + Some(fn(x)) + else + None +## Converts `T` to a `None`, if `fn` returns false and it exists. +pub func filter[T](self: T?, fn: T -> bool): T? = + if self of Some(x) and fn(x) then + Some(x) + else + None + +## Applies a function to T, if it exists. Equivalent to `self.map(fn).flatten`. +pub func flatmap[T, U](self: T?, fn: T -> U?): U? = + if self of Some(x) then + fn(x) + else + None +## Converts from Option[Option[T]] to Option[T]. +pub func flatten[T](self: T??): T? = + if self of Some(Some(x)) then + Some(x) + else + None + +## Returns the inner value or a default. +pub func get_or[T](self: T?, default: T): T = + if self of Some(x) then x + else default + +## Overloads the `==` operation for use on Options. +pub func ==[T](a, b: T?): bool = + if (a, b) of (Some(x), Some(y)) then + x == y + else + false + +## Overloads the `str()` function for use on Options. +pub func str[T: Display](self: T?): str = + if self of Some(x) then + "Some({})".fmt(x.str) + else + "None" + +# references: +# https://nim-lang.github.io/Nim/options.html +# https://doc.rust-lang.org/std/option/enum.Option.html +</code></pre> +<h2 id="stdresults"><a class="header" href="#stdresults">std.results</a></h2> +<pre><code class="language-puck">## std.results: Result types. +## This module is imported by default. + +use std.[options, format] + +## The Result type. Represents either success or failure. +pub type Result[T, E] = union + Okay(T) + Error(E) + +## The Err class. Useful for dynamically dispatching errors. +pub type Err = class + str(Self): str + dbg(Self): str + +## A `Result` type that uses dynamically dispatched errors. +## The `Error` may be any type implementing `Err`. +pub type Result[T] = Result[T, ref Err] +## A `Result` type that only checks for success. +## Does not contain a value. +# pub type Success[E] = Result[void, E] +## A `Result` type that only checks for success. +## Does not contain a value. Dynamically dispatched. +# pub type Success = Result[void] + +## Syntactic sugar for dynamic result type declarations. +pub macro !(T: type) = + quote Result[`T`] + +## Indirect access. Propagates `Error`. +pub macro ?[T, E](self: Result[T, E]) = + quote + match `self` + of Okay(x) then x + of Error(e) then return Error(e) + +## Checks if a `Result` type was successful. +pub func is_ok[T, E](self: Result[T, E]): bool = + self of Okay(_) +## Checks if a `Result` type was not successful. +pub func is_err[T, E](self: Result[T, E]): bool = + self of Error(_) + +## Converts from a `Result[T, E]` to an `Option[T]`. +pub func ok[T, E](self: Result[T, E]): T? = + if self of Okay(x) then + Some(x) + else + None +## Converts from a `Result[T, E]` to an `Option[E]`. +pub func err[T, E](self: Result[T, E]): E? = + if self of Error(x) then + Some(x) + else + None + +## Applies a function to `T`, if self is `Okay`. +pub func map[T, E, U](self: Result[T, E], fn: T -> U): Result[U, E] = + match self + of Okay(x) then + Okay(fn(x)) + of Error(e) then + Error(e) +## Applies a function to `E`, if self is `Error`. +pub func map_err[T, E, F](self: Result[T, E], fn: E -> F): Result[T, F] = + match self + of Error(e) then + Error(fn(e)) + of Okay(x) then + Okay(x) + +## Applies a function to `T`, if it exists. Equivalent to `self.map(fn).flatten`. +pub func flatmap[T, E, U](self: Result[T, E], fn: T -> Result[U, E]): Result[U, E] = + match self + of Okay(x) then + fn(x) + of Error(e) then + Error(e) +## Converts from a `Result[Result[T, E], E]` to a `Result[T, E]`. +pub func flatten[T, E](self: Result[Result[T, E], E]): Result[T, E] = + match self + of Okay(Okay(x)) then + Okay(x) + of Okay(Error(e)), Error(e) then + Error(e) + +## Transposes a `Result[Option[T], E]` to an `Option[Result[T, E]]`. +pub func transpose[T, E](self: Result[T?, E]): Result[T, E]? = + match self + of Okay(Some(x)) then + Some(Okay(x)) + of Okay(None), Error(_) then + None +## Transposes an `Option[Result[T, E]]` to a `Result[Option[T], E]`. Takes a default error. +pub func transpose[T, E](self: Result[T, E]?, error: E): Result[T?, E] = + match self + of Some(Okay(x)) then Okay(Some(x)) + of Some(Error(e)) then Error(e) + of None then Error(error) + +## Returns the inner value or a default. +pub func get_or[T, E](self: Result[T, E], default: T): T = + if self of Okay(x) then x + else default + +## Directly accesses the inner value. Throws an exception if `Error`. +pub func ![T, E](self: Result[T, E]): T = + match self + of Okay(x) then x + of Error(e) then raise e +## Directly accesses the inner error. Throws an exception of type T if `Okay`. +pub func get_err[T, E](self: Result[T, E]): E = + match self + of Error(e) then e + of Okay(x) then raise x + +## Overloads the `==` operation for use on Results. +pub func ==[T, E, F](a: Result[T, E], b: Result[T, F]): bool = + if (a, b) of (Okay(x), Okay(y)) then + x == y + else + false + +## Overloads the `str()` function for use on Results. +pub func str[T: Display, E: Display](self: Result[T, E]): str = + match self + of Some(x) then + "Okay({})".fmt(x.str) + of Error(e) then + "Error({})".fmt(e.str) + +# references: +# https://doc.rust-lang.org/std/result/enum.Result.html +# https://github.com/arnetheduck/nim-results +# https://github.com/codex-storage/questionable +</code></pre> +<h2 id="stdformat"><a class="header" href="#stdformat">std.format</a></h2> +<pre><code class="language-puck">## std.format: Niceties around printing and debugging. +## This module is imported by default. + +## The Display class. Any type implementing `str` is printable. +## Any type that is Display must necessarily also implement Debug. +pub type Display = class + str(Self): str + dbg(Self): str + +## The Debug class. Broadly implemented for every type with compiler magic. +## Types can (and should) override the generic implementations. +pub type Debug = class + dbg(Self): str + +## Prints all of its arguments to the command line. +pub func print(params: varargs[Display]) = + stdout.write(params.map(x => x.str).join(" "), "\n") + +## Prints all of its arguments to the command line, in Debug form. +## +## Note: this function is special! It does not count as a side effect. +## This breaks effect tracking, of course: but `dbg` is for debugging. +## It will produce a warning in code compiled for release. +@[pure] +pub func dbg(params: varargs[Debug]) = + stdout.write(params.map(x => x.dbg).join(" "), "\n") + +## A dummy implementation of the Display class for strings. +pub func str(self: str): str = self +## An implementation of the Debug class for strings. +pub func dbg(self: str): str = "\"" & self & "\"" + +## An implementation of the Debug class for all structs. +## Uses the special `struct` typeclass. +pub func dbg[T: Debug](self: struct[T]): str = + "{{}}".fmt(self.fields.map((key, val) => key & ":" & val.dbg)) + +## An implementation of the Debug class for all tuples. +## Uses the special `tuple` typeclass. +pub func dbg[T: Debug](self: tuple[T]): str = + "({})".fmt(self.fields.map((key, val) => + key.map(x => x & ":").get_or("") & val.dbg).join(", ")) + +## An implementation of the Debug class for all arrays and lists. +pub func dbg[T: Debug](self: Iter[T]): str = + "[{}]".fmt(self.map(x => x.dbg).join(", ")) + +## The fmt macro. Builds a formatted string from its arguments. +pub macro fmt(self: const str, args: varargs[Display]): str = + let parts = self.split("{}") + if parts.len != args.len + 1 then + macro_error("wrong number of arguments") + use std.ast + var res = parts.get(0)! + for i, arg in args do + res &= quote(`parts` & str(`arg`) &) # fixme + res &= parts.last()! + res +</code></pre> +<h2 id="stddebug"><a class="header" href="#stddebug">std.debug</a></h2> +<pre><code class="language-puck">## std.debug: Useful functions for debugging. +## This module is imported by default. + +## The `assert` macro checks that a provided assertation is true, +## and panics and dumps information if it is not. +## Asserts remain in release builds. If not desired, see `dbg_assert` +pub macro assert(cond: bool) = + quote + if not `cond` then + panic "assertation failed!\n {}".fmt(dbg(`cond`)) + +## The `dbg_assert` function provides an assert that is compiled out in release builds. +## This is useful for debugging performance-critical code. +pub macro dbg_assert(cond: bool) = + quote + when debug then # fixme: where is this constant coming from? + assert `cond` + +## The `discard` function consumes an object of any type. +## Useful for throwing away the result of a computation. +pub func discard[T](self: T) = + return + +## The `panic` function prints a message to `stderr` and quits. +pub func panic(message: str): never = + stderr.write(message, "\n") + std.os.exit(1) + +## The special ... syntax is used to mark unimplemented parts of code. +## Such code will compile, but panic upon being called at runtime. +## It is usable almost anywhere, including in type declarations, thanks to compiler magic. +@[magic] +pub func ...: never = + panic("unimplemented") +</code></pre> +<h2 id="stdlists"><a class="header" href="#stdlists">std.lists</a></h2> +<pre><code class="language-puck">## std.lists: Dynamic arrays. +## This module is imported by default. + +## The fundamental list type. Heap-allocated. +## Equivalent to Vec<T> in other languages. +@[opaque] # opaque on a struct tells us raw field access breaks invariants. +pub type list[T] = struct + data: ptr T + capacity: uint + length: uint + +## A transparent, common alias for a list of bytes. +pub type bytes = list[byte] + +## Initialize and return an empty list with inner type T. +pub func init[T]: list[T] = + { data = nil, capacity = 0, length = 0 } # fixme: nil!!!!! + +## Gets the length of a list. +@[inline] # idk what to do with attributes +pub func len[T](self: lent list[T]): uint = + self.length + +pub func empty[T](self: lent list[T]): bool = + self.length == 0 + +## Gets the internal capacity of a list. +func cap[T](self: lent list[T]): uint = + self.capacity + +## Expands the capacity of a list. +@[safe] +func grow[T](self: mut list[T]) = + self.capacity = max(self.length + 1, self.capacity * 2) + self.data = self.data.realloc(self.capacity * sizeof(T)) + +## Pushes a new element to the end of a list. +@[safe] +pub func push[T](self: mut list[T], val: T) = + if self.capacity == self.length then self.grow() + self.data.set(val, offset = self.length) + self.length += 1 + +## Takes ownership of and pushes all the values of a list into another list. +pub func push[T](self: mut list[T], values: list[T]) = + for val in values do + self.push(val) + +## Removes & returns an element from the end of a list, if it exists. +@[safe] +pub func pop[T](self: mut list[T]): T? = + if self.length == 0 then + None + else + self.length -= 1 + Some(self.data.get(offset = self.length)) + +## Returns a reference to an element of a list, if in range. +@[safe] +pub func get[T](self: lent list[T], i: uint): lent T? = + if i > self.length then + None + else # fixme: interior mutability + Some(lent self.data.get(offset = i)) +## Returns a mutable reference to an element of a list, if in range. +@[safe] +pub func get[T](self: mut list[T], i: uint): mut T? = + if i > self.length then + None + else # fixme: interior mutability + Some(mut self.data.get(offset = i)) + +## Sets the element of a list to a value. +@[safe] +pub func set[T](self: mut list[T], i: uint, val: T) = + assert i <= self.length, "index out of bounds" + Okay(self.data.set(offset = i, val)) + +## Inserts a value at a location and shifts elements of the list accordingly. +@[safe] +pub func insert[T](self: mut list[T], i: uint, val: T) = + assert i <= self.length, "index out of bounds" + if self.capacity == self.length then self.grow() + self.data.offset(i).copy(self.data.offset(i + 1), self.length - i) + self.data.set(i, val) + self.length += 1 +## Inserts a list of values at a location and shifts elements of the list accordingly. +pub func insert[T](self: mut list[T], i: uint, vals: list[T]) = + for val in vals.rev: # inserting backwards avoids counting + self.insert(val, i) + +## Removes a value at a location and shifts elements of the list accordingly. +@[safe] +pub func remove[T](self: mut list[T], i: uint): T? = + if index < self.length then None + else + self.length -= 1 + let res = self.data.get(i) + self.data.offset(i + 1).copy(self.data.offset(i), self.length - i) + res + +## Gets the last element of a list, if it exists. +pub func last[T](self: lent list[T]): lent T? = + self.get(self.len - 1) +## Gets the last element of a list mutably, if it exists. +pub func last[T](self: mut list[T]): mut T? = + self.get(self.len - 1) + +# reference: https://doc.rust-lang.org/nomicon/vec/vec.html +</code></pre> +<h2 id="stdstrings"><a class="header" href="#stdstrings">std.strings</a></h2> +<pre><code class="language-puck">## std.strings: The standard implementation of strings. +## This module is imported by default. + +## A primitive string type. +## +## We do not want methods defined on `list[byte]` to carry over, +## so we define `str` as a newtype. +@[opaque] +pub type str = struct + data: list[byte] + +## Initialize and return an empty string. +pub func init: str = { data = [] } + +## Gets the length of a string. +## This is an O(n) operation, due to UTF-8 encoding. +pub func len(self: lent str): uint = + var res: uint + for _ in self do + res += 1 + res + +## Pushes a character to the end of a mutable string. +pub func push(self: mut str, val: char) = + self.data.push(val.byte) # todo: obsolete by from/to conversion?? + +## Pushes an owned string to the end of a mutable string. +pub func push(self: mut str, val: str) = + self.data.push(val.bytes) # todo: obsolete by from/to conversion?? + +## Removes and returns the last character of a string, if it exists. +## +## SAFETY: We return early upon an empty string. +## And decrement by one char for a non-empty string. +@[safe] +pub func pop(self: mut str): char? = + let char = self.chars.rev.next? + self.data.set_len(self.len - char.len) # this is normally unsafe. + Some(char) + +## Returns the character at the provided index, if it exists. +pub func get(self: str, i: uint): char? = + ... + +## Sets the character at the provided index, if it exists. +## As strings are packed, this may call str.grow and reallocate. +## oh fuck we have to insert + remove anyway +pub func set(self: mut str, i: uint, val: char) = + ... + +## Inserts a character at an arbitrary position within a string. +## Panics on failure. (todo: can we do better?) +pub func insert(self: mut str, i: uint, val: char) = + ... + +## Removes and returns a character at an arbitrary position within a string. +## Panics on failure. (todo: can we do better?) +pub func remove(self: mut str, i: uint): char? = + ... + +## Syntactic sugar for string appending. +pub func &=(a: mut str, b: str) = + a.push(b) + +## The concatenation operator. Consumes two strings. +pub func &(a: str, b: str): str = + a.push(b) + a + +## Conversion from a string to a list of bytes. Zero-cost. +pub func to(self: str): list[byte] = self.data +## Conversion from a str to a list[char]. Reallocates. +pub func to(self: str): list[char] = + var res: list[char] + for char in self do res.push(char) + res +## Conversion from a char to an array of bytes. Zero-cost. +@[safe] # possibly unsafe?? depends on repr of arrays +pub func to(self: char): array[byte, 4] = + self.cast[array[byte, 4]] + +# reference: https://doc.rust-lang.org/std/string/struct.String.html +</code></pre> +<h2 id="stdcompare"><a class="header" href="#stdcompare">std.compare</a></h2> +<pre><code class="language-puck">## std.compare: Classes for comparable types. + +## The Eq class. For types with some notion of equivalence. +pub type Eq = class + ==(Self, Self): bool + +## A blanket implementation of a corresponding not-equal function. +pub !=[T: Eq](a: T, b: T): bool = + not(a == b) + +## The Compare class. For a type comparable with itself. +pub type Compare = class + <(a: Self, b: Self): bool + +## A blanket implementation of a corresponding greater-than function. +## Note to self: do NOT inline! +pub func >[T: Compare](a: T, b: T): bool = + b < a + +## The Ord class. For types with some notion of equivalence and comparision. +## +## Note: This is *not* a mathematical notion of an order! +## No invariants on `<` nor `==` are guaranteed to hold, as classes +## are implicitly implementable. +pub type Ord = class + <(a: Self, b: Self): bool + ==(a: Self, b: Self): bool + +## A blanket implementation of a corresponding less-than-or-equal function. +pub func <=[T: Ord](a: T, b: T): bool = + a < b or a == b + +## A blanket implementation of a corresponding greater-than-or-equal function. +pub func >=[T: Ord](a: T, b: T): bool = + a > b or a == b + +# reference: https://doc.rust-lang.org/std/cmp +</code></pre> +<h2 id="stdconvert"><a class="header" href="#stdconvert">std.convert</a></h2> +<pre><code class="language-puck">## std.convert: Classes for type coersion and conversion. +## This module is imported by default. + +## The Coerce class is used for type conversion that will not fail. +## Its associated methods, `from` and `into`, are used internally +## by the compiler for implicit type conversion (coersion). +pub type Coerce[T] = class + to(Self): T + # from(T): Self + +## The `from` function is automatically implemented for all types that +## implement `to`: that is, all types T that are convertable to U. +pub func from[T: Coerce[U], U](self: U): T = + to(self) + +## The Convert class is used for type conversion that may fail. +# We'll see what this breaks. +pub type Convert[T, E] = class + to(Self): Result[T, E] +</code></pre> +<h2 id="stdranges"><a class="header" href="#stdranges">std.ranges</a></h2> +<pre><code class="language-puck">## std.ranges: Ranges of integers and other things. For iteration. +## This module is imported by default. + +type Range[T] = struct + start: T + end: T + +type RangeIncl[T] = struct + start: T + end: T + done: bool + +## Exclusive ranges. Useful for iteration. +## Includes `from`, does not include `to`. +pub func ..(from: int, to: int): Range[int] = { from, to } + +## Inclusive ranges. Useful for ranges. +## Includes `from` and `to`. +pub func ..=(from: int, to: int): RangeIncl[int] = { from, to, done = false } + +# todo: implement for all types that can increment or smth idk +pub func next[T: int](self: mut Range[T]): T? = + if self.start < self.end then + self.start += 1 + Some(self.start - 1) + else + None + +# todo: We don't need a mutable Range here to peek. +# How does this interact with classes? +pub func peek[T: int](self: mut Range[T]): T? = + self.peek_nth(0) + +pub func peek_nth[T: int](self: mut Range[T], i: uint): T? = + let res = self.start + i + if res < self.end then + Some(res) + else + None + +pub func next[T: int](self: mut RangeIncl[T]): T? = + if self.done then + None + elif self.start < self.end then + let res = self.start + self.start += 1 + Some(res) + elif self.start == self.end then + self.done = true + Some(self.start) + else + self.done = true + None + +pub func peek[T: int](self: mut RangeIncl[T]): T? = + self.peek_nth(0) + +pub func peek_nth[T: int](self: mut RangeIncl[T], i: uint): T? = + let res = self.start + i + if res <= self.end + then Some(res) + else None +</code></pre> +<h2 id="stdast"><a class="header" href="#stdast">std.ast</a></h2> +<pre><code class="language-puck">## std.ast: Exposes the AST for building and operating on with macros. + +## The `Expr` type represents the abstract syntax tree of Puck itself. +## It notably lacks type information. It is also not necessarily syntactically +## correct-by-construction: Cond, Try, and Match expressions must have at least +## one branch in their branches (yet this is not expressible here). +pub type Expr = union + # Terms + Ident(str) + Number(int) + Float(float) + Char(char) + String(str) + Struct(list[(field: str, value: Expr)]) # {...} + Tuple(list[(field: str?, value: Expr)]) # (...) + List(list[Expr]) # [...] + # Bindings + Let(id: Pattern, kind: Type?, value: ref Expr) + Var(id: Pattern, kind: Type?, value: ref[Expr]?) + Constant(public: bool, id: Pattern, kind: Type?, value: ref Expr) + FuncDecl( + public: bool, + id: str, + generics: list[(id: str, kind: Type?)], + params: list[(id: str, kind: Type)], + kind: Type?, + body: list[Expr]) + MacroDecl( + public: bool, + id: str, + generics: list[(id: str, kind: Type?)], + params: list[(id: str, kind: Type?)], + kind: Type?, + body: list[Expr]) + TypeDecl( + public: bool, + id: str, + generics: list[str], + body: Type) + Module( + public: bool, + id: str, + generics: list[str], # always empty for now + body: list[Expr]) + Use(modules: list[(path: str, alias: str?)]) + # Control Flow + Call(id: str, params: list[Expr]) + Cond( + branches: list[(cond: Expr, body: list[Expr])], + else_body: list[Expr]) + Try( + try_body: list[Expr], + catches: list[(exceptions: list[str], body: list[Expr])], + finally_body: list[Expr]) # todo: throw this out + Match( + item: ref Expr, + branches: list[(pattern: Pattern, guard: Expr?, body: list[Expr])]) + Block(id: str?, body: list[Expr]) + Static(body: list[Expr]) + For(binding: Pattern, range: ref Expr, body: list[Expr]) + While(cond: ref Expr, body: list[Expr]) + Loop(body: list[Expr]) + Attribute(on: ref Expr) + Quote(body: ref Expr) + Unquote(body: ref Expr) + +pub type Type = ref union + Never + Int(size: uint) + Dec(size: uint) + Float(size: uint) + Func(from: list[Type], to: Type) + Struct(list[(id: str, kind: Type)]) + Tuple(list[(id: str?, kind: Type)]) + Union(list[(id: str, kind: Type)]) + Class(list[(id: str, from: list[Type], to: Type?)]) + Array(size: uint, kind: Type) + List(Type) + Slice(Type) # todo: plus ownership + Alias(str) # todo: params?? huh? + Const(Type) + Lent(Type) + Mut(Type) + Ref(Type) + Refc(Type) + Ptr(Type) + +pub type Pattern = union + Ident(str) + Number(int), Float(float), Char(char), String(str) + Struct(name: str, params: list[Pattern]) + Tuple(list[Pattern]) + List(list[Pattern]) + +@[magic] +pub func quote(body): Expr +</code></pre> + + </main> + + <nav class="nav-wrapper" aria-label="Page navigation"> + <!-- Mobile navigation buttons --> + <a rel="prev" href="INTEROP.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> + <i class="fa fa-angle-left"></i> + </a> + + + <div style="clear: both"></div> + </nav> + </div> + </div> + + <nav class="nav-wide-wrapper" aria-label="Page navigation"> + <a rel="prev" href="INTEROP.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> + <i class="fa fa-angle-left"></i> + </a> + + </nav> + + </div> + + + + + <script> + window.playground_copyable = true; + </script> + + + <script src="elasticlunr.min.js"></script> + <script src="mark.min.js"></script> + <script src="searcher.js"></script> + + <script src="clipboard.min.js"></script> + <script src="highlight.js"></script> + <script src="book.js"></script> + + <!-- Custom JS scripts --> + + + </div> + </body> +</html> |