aboutsummaryrefslogtreecommitdiff
path: root/docs/book/EXAMPLES.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/book/EXAMPLES.html')
-rw-r--r--docs/book/EXAMPLES.html964
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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 -&gt; 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 =&gt; 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 =&gt; 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 = "\"" &amp; self &amp; "\""
+
+## 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) =&gt; key &amp; ":" &amp; 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) =&gt;
+ key.map(x =&gt; x &amp; ":").get_or("") &amp; 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 =&gt; 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 &amp;= quote(`parts` &amp; str(`arg`) &amp;) # fixme
+ res &amp;= 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&lt;T&gt; 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 &amp; 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 &gt; 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 &gt; 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 &lt;= 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 &lt;= 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 &lt; 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 &amp;=(a: mut str, b: str) =
+ a.push(b)
+
+## The concatenation operator. Consumes two strings.
+pub func &amp;(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
+ &lt;(a: Self, b: Self): bool
+
+## A blanket implementation of a corresponding greater-than function.
+## Note to self: do NOT inline!
+pub func &gt;[T: Compare](a: T, b: T): bool =
+ b &lt; 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 `&lt;` nor `==` are guaranteed to hold, as classes
+## are implicitly implementable.
+pub type Ord = class
+ &lt;(a: Self, b: Self): bool
+ ==(a: Self, b: Self): bool
+
+## A blanket implementation of a corresponding less-than-or-equal function.
+pub func &lt;=[T: Ord](a: T, b: T): bool =
+ a &lt; b or a == b
+
+## A blanket implementation of a corresponding greater-than-or-equal function.
+pub func &gt;=[T: Ord](a: T, b: T): bool =
+ a &gt; 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 &lt; 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 &lt; 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 &lt; 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 &lt;= 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>