diff --git a/codon/parser/peg/grammar.peg b/codon/parser/peg/grammar.peg
index 92f22344..7d46c5ac 100644
--- a/codon/parser/peg/grammar.peg
+++ b/codon/parser/peg/grammar.peg
@@ -66,7 +66,7 @@ small_stmt <-
   / del_stmt
   / return_stmt &(SPACE / ';' / EOL)
   / raise_stmt &(SPACE / ';' / EOL)
-  / print_stmt 
+  / print_stmt
   / import_stmt
   / expressions &(_ ';' / _ EOL)  { return any(ast<ExprStmt>(LOC, ac_expr(V0))); }
   / NAME SPACE expressions {
@@ -331,7 +331,7 @@ param <-
 param_name <- <'**' / '*'>? _ NAME {
   return (!VS.tokens.empty() ? VS.token_to_string() : "") + ac<string>(V0);
 }
-generics <- '[' _ tlist(',', param) _ ']' { 
+generics <- '[' _ tlist(',', param) _ ']' {
   vector<Param> params;
   for (auto &p: VS) {
     auto v = ac<Param>(p);
@@ -339,7 +339,7 @@ generics <- '[' _ tlist(',', param) _ ']' {
     if (!v.type) v.type = ast<IdExpr>(LOC, "type");
     params.push_back(v);
   }
-  return params; 
+  return params;
 }
 decorators <- decorator+ {
   return VS.transform<ExprPtr>();
@@ -390,7 +390,7 @@ class_def <- 'class' SPACE NAME _ class_args? _ ':' _ suite {
   }
   for (auto &p: generics)
     args.push_back(p);
-  return ast<ClassStmt>(LOC, 
+  return ast<ClassStmt>(LOC,
     ac<string>(V0), move(args), suite, Attr(), vector<ExprPtr>{}, baseClasses
   );
 }
@@ -435,7 +435,7 @@ expression <-
   }
   / pipe { return ac_expr(V0); }
 # TODO: make it more pythonic
-lambdef <- 
+lambdef <-
   / 'lambda' SPACE list(',', NAME) _ ':' _ expression {
     return ast<LambdaExpr>(LOC,
       VS.transform<string>(0, VS.size() - 1), ac_expr(VS.back())
diff --git a/codon/util/toml++/toml_array.hpp b/codon/util/toml++/toml_array.hpp
index 7c61b806..25400cef 100644
--- a/codon/util/toml++/toml_array.hpp
+++ b/codon/util/toml++/toml_array.hpp
@@ -151,7 +151,7 @@ TOML_NAMESPACE_START
 	{
 		if (elements.empty())
 			return false;
-		
+
 		if (ntype == node_type::none)
 			ntype = elements[0]->type();
 
diff --git a/codon/util/toml++/toml_default_formatter.hpp b/codon/util/toml++/toml_default_formatter.hpp
index 54063aed..076b9ae9 100644
--- a/codon/util/toml++/toml_default_formatter.hpp
+++ b/codon/util/toml++/toml_default_formatter.hpp
@@ -218,7 +218,7 @@ TOML_NAMESPACE_END;
 				const char* lpDefaultChar,
 				int* lpUsedDefaultChar
 			);
- 
+
 			__declspec(dllimport)
 			int __stdcall MultiByteToWideChar(
 				unsigned int CodePage,
diff --git a/codon/util/toml++/toml_node.hpp b/codon/util/toml++/toml_node.hpp
index a7ace849..55880a80 100644
--- a/codon/util/toml++/toml_node.hpp
+++ b/codon/util/toml++/toml_node.hpp
@@ -19,7 +19,7 @@ TOML_NAMESPACE_START
 	node::node(const node& /*other*/) noexcept
 	{
 		// does not copy source information - this is not an error
-		// 
+		//
 		// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
 	}
 
@@ -35,7 +35,7 @@ TOML_NAMESPACE_START
 	node& node::operator= (const node& /*rhs*/) noexcept
 	{
 		// does not copy source information - this is not an error
-		// 
+		//
 		// see https://github.com/marzer/tomlplusplus/issues/49#issuecomment-665089577
 
 		source_ = {};
@@ -62,7 +62,7 @@ TOML_NAMESPACE_START
 	TOML_MEMBER_ATTR(const) bool node::is_time()			const noexcept { return false; }
 	TOML_MEMBER_ATTR(const) bool node::is_date_time()		const noexcept { return false; }
 	TOML_MEMBER_ATTR(const) bool node::is_array_of_tables()	const noexcept { return false; }
-	
+
 	TOML_MEMBER_ATTR(const) table* node::as_table()						noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) array* node::as_array()						noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) value<std::string>* node::as_string()		noexcept { return nullptr; }
@@ -72,7 +72,7 @@ TOML_NAMESPACE_START
 	TOML_MEMBER_ATTR(const) value<date>* node::as_date()				noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) value<time>* node::as_time()				noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) value<date_time>* node::as_date_time()		noexcept { return nullptr; }
-	
+
 	TOML_MEMBER_ATTR(const) const table* node::as_table()					const noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) const array* node::as_array()					const noexcept { return nullptr; }
 	TOML_MEMBER_ATTR(const) const value<std::string>* node::as_string()		const noexcept { return nullptr; }
diff --git a/codon/util/toml++/toml_parser.hpp b/codon/util/toml++/toml_parser.hpp
index e0f8a1d0..3bc5efd2 100644
--- a/codon/util/toml++/toml_parser.hpp
+++ b/codon/util/toml++/toml_parser.hpp
@@ -458,7 +458,7 @@ TOML_IMPL_NAMESPACE_START
 			std::vector<table*> implicit_tables;
 			std::vector<table*> dotted_key_tables;
 			std::vector<array*> table_arrays;
-			std::string recording_buffer; //for diagnostics 
+			std::string recording_buffer; //for diagnostics
 			bool recording = false, recording_whitespace = true;
 			std::string_view current_scope;
 			size_t nested_values = {};
@@ -920,7 +920,7 @@ TOML_IMPL_NAMESPACE_START
 							);
 
 						// handle surrogates in strings (1.0.0 and later)
-						if constexpr (TOML_LANG_AT_LEAST(1, 0, 0)) 
+						if constexpr (TOML_LANG_AT_LEAST(1, 0, 0))
 						{
 							if (is_unicode_surrogate(*cp))
 								set_error_and_return_default(
@@ -1083,7 +1083,7 @@ TOML_IMPL_NAMESPACE_START
 
 					set_error_and_return_default("encountered end-of-file"sv);
 				}
-					
+
 				// if the first three characters are all the same string delimiter then
 				// it's a multi-line string.
 				else if (first == second && first == third)
@@ -1514,7 +1514,7 @@ TOML_IMPL_NAMESPACE_START
 				return (fragments[0].value + fragments[1].value)
 					* pow(2.0, fragments[2].value * exponent_sign)
 					* sign;
-			
+
 				#else // !TOML_LANG_UNRELEASED
 
 				set_error_and_return_default(
@@ -1570,7 +1570,7 @@ TOML_IMPL_NAMESPACE_START
 				size_t length = {};
 				const utf8_codepoint* prev = {};
 				while (!is_eof() && !is_value_terminator(*cp))
-				{				
+				{
 					if (*cp == U'_')
 					{
 						if (!prev || !traits::is_digit(*prev))
@@ -1979,7 +1979,7 @@ TOML_IMPL_NAMESPACE_START
 					// detect the value type and parse accordingly,
 					// starting with value types that can be detected
 					// unambiguously from just one character.
-					
+
 					val = parse_value_known_prefixes();
 					return_if_error({});
 					if (val)
@@ -2492,7 +2492,7 @@ TOML_IMPL_NAMESPACE_START
 						set_error_and_return_default(
 							"expected bare key starting character or string delimiter, saw '"sv, to_sv(*cp), "'"sv
 						);
-						
+
 					// whitespace following the key segment
 					consume_leading_whitespace();
 
@@ -2583,7 +2583,7 @@ TOML_IMPL_NAMESPACE_START
 					// check for a premature closing ']'
 					if (*cp == U']')
 						set_error_and_return_default("tables with blank bare keys are explicitly prohibited"sv);
-				
+
 					// get the actual key
 					start_recording();
 					key = parse_key();
@@ -2672,7 +2672,7 @@ TOML_IMPL_NAMESPACE_START
 							).first->second->ref_cast<array>();
 						table_arrays.push_back(tab_arr);
 						tab_arr->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
-						
+
 						tab_arr->elements.emplace_back(new toml::table{});
 						tab_arr->elements.back()->source_ = { header_begin_pos, header_end_pos, reader.source_path() };
 						return &tab_arr->elements.back()->ref_cast<table>();
@@ -2803,7 +2803,7 @@ TOML_IMPL_NAMESPACE_START
 				assert_not_error();
 				assert_not_eof();
 				push_parse_scope("root table"sv);
-					
+
 				table* current_table = &root;
 
 				do
diff --git a/codon/util/toml++/toml_preprocessor.h b/codon/util/toml++/toml_preprocessor.h
index 09ecea45..2dabb87d 100644
--- a/codon/util/toml++/toml_preprocessor.h
+++ b/codon/util/toml++/toml_preprocessor.h
@@ -239,7 +239,7 @@
 //#====================================================================================================================
 
 #if TOML_ICC
-	
+
 	#define TOML_PUSH_WARNINGS \
 		__pragma(warning(push)) \
 		static_assert(true)
@@ -345,7 +345,7 @@
 #ifdef TOML_CONFIG_HEADER
 	#include TOML_CONFIG_HEADER
 #endif
- 
+
 #ifdef DOXYGEN
 	#define TOML_HEADER_ONLY 0
 	#define TOML_WINDOWS_COMPAT 1
@@ -803,9 +803,9 @@ TOML_ENABLE_WARNINGS;
 /// // global_header_that_includes_toml++.h
 /// #define TOML_HEADER_ONLY 0
 /// #include <toml.hpp>
-/// 
+///
 /// // some_code_file.cpp
-/// #define TOML_IMPLEMENTATION 
+/// #define TOML_IMPLEMENTATION
 /// #include "global_header_that_includes_toml++.h"
 /// \ecpp
 
diff --git a/codon/util/toml++/toml_table.hpp b/codon/util/toml++/toml_table.hpp
index bc1aa73c..1b846d82 100644
--- a/codon/util/toml++/toml_table.hpp
+++ b/codon/util/toml++/toml_table.hpp
@@ -142,7 +142,7 @@ TOML_NAMESPACE_START
 	{
 		if (map.empty())
 			return false;
-		
+
 		if (ntype == node_type::none)
 			ntype = map.cbegin()->second->type();
 
diff --git a/docs/sphinx/primer.rst b/docs/sphinx/primer.rst
index 13efa016..2c799946 100644
--- a/docs/sphinx/primer.rst
+++ b/docs/sphinx/primer.rst
@@ -811,12 +811,12 @@ You can also add methods to types:
 Type extensions
 ~~~~~~~~~~~~~~~
 
-Suppose you have a class that lacks a method or an operator that might be really useful. 
+Suppose you have a class that lacks a method or an operator that might be really useful.
 
-Codon provides an ``@extend`` annotation that allows programmers to add and modify 
-methods of various types at compile time, including built-in types like ``int`` or ``str``. 
-This actually allows much of the functionality of built-in types to be implemented in 
-Codon as type extensions in the standard library. 
+Codon provides an ``@extend`` annotation that allows programmers to add and modify
+methods of various types at compile time, including built-in types like ``int`` or ``str``.
+This actually allows much of the functionality of built-in types to be implemented in
+Codon as type extensions in the standard library.
 
 .. code:: python