aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorJJ2023-10-23 02:34:17 +0000
committerJJ2023-10-23 02:34:17 +0000
commitd5f89ba0e2fd0458f4e51e13233069583d5a89ac (patch)
tree658019acfbd5cec5c5944accb95d0fde618da050 /std
parent2d5d47c89d5b9df3535029f04cf1205e47276451 (diff)
std: broad updates; add ast, iterators, format, tests, logs
Diffstat (limited to 'std')
-rw-r--r--std/default/format.pk51
-rw-r--r--std/default/iterators.pk38
-rw-r--r--std/default/options.pk18
-rw-r--r--std/default/results.pk22
-rw-r--r--std/fundamental/ast.pk119
-rw-r--r--std/fundamental/logs.pk1
-rw-r--r--std/fundamental/tests.pk5
7 files changed, 236 insertions, 18 deletions
diff --git a/std/default/format.pk b/std/default/format.pk
new file mode 100644
index 0000000..c7d7ab8
--- /dev/null
+++ b/std/default/format.pk
@@ -0,0 +1,51 @@
+## std/format: Niceties around printing and debugging.
+## This module is imported by default.
+
+## The Display interface. Any type implementing `str` is printable.
+## Any type that is Display must also implement Debug.
+pub type Display = interface
+ str(Self): str
+ dbg(Self): str
+
+## The Debug interface. Broadly implemented for every type with magic,
+## types can (and should) override the generic implementations.
+pub type Debug = interface
+ 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.
+pub func dbg(params: varargs[Debug]) =
+ stdout.write(params.map(x => x.dbg).join(" "), "\n")
+
+## A dummy implementation of the Display interface for strings.
+pub func str(self: str): str = self
+## An implementation of the Debug interface for strings.
+pub func dbg(self: str): str = "\"" & self & "\""
+
+## An implementation of the Debug interface for all structs.
+## Uses the special `struct` typeclass.
+pub func dbg(self: struct): str =
+ "{" & self.fields.map(field => field.id & field.value.dbg) & "}"
+
+## An implementation of the Debug interface for all tuples.
+## Uses the special `tuple` typeclass.
+pub func dbg(self: tuple): str =
+ result &= "("
+ for i, field in self.fields.enumerate():
+ result &= field.id.map(id => id & " = ").get_or("")
+ if i != self.fields.len:
+ result &= ", "
+ result &= ")"
+
+## An implementation of the Debug interface for all arrays and lists.
+pub func dbg(self: Iter[Debug]): str =
+ "[" & self.map(x => x.str).join(", ") & "]"
+
+## The fmt macro. Builds a formatted string from its arguments.
+pub macro fmt(formatted: static[str], args: varargs[Display]) =
+ # if not formatted of String:
+ # macro_error("fmt must take a static string parameter!")
+ ...
diff --git a/std/default/iterators.pk b/std/default/iterators.pk
new file mode 100644
index 0000000..f97c61a
--- /dev/null
+++ b/std/default/iterators.pk
@@ -0,0 +1,38 @@
+## std/iterators: The Iter interface and associated functions.
+## This module is imported by default.
+
+## The Iter interface. Any type implementing `next()` is iterable.
+pub type Iter[T] = interface
+ next(mut Self): Option[T]
+
+# todo: useful functions for an iterator
+# https://doc.rust-lang.org/std/iter/trait.Iterator.html#provided-methods
+
+pub func advance_by[T](self: Iter[T], n: uint): Result[T, ...] =
+ for i in 0 .. n:
+ if self.next().is_none():
+ return Error(...)
+ Okay
+
+pub func get[T](self: Iter[T], at: uint): Option[T]
+ self.advance_by(at-1).ok?
+ self.next()
+
+# todo: implement iter[T](self: ...): Iter[T] funcs
+# todo: efficient functional methods
+
+## The Peek interface. Any type implementing Iter, `peek`, and `peek_nth` is peekable.
+pub type Peek[T] = interface
+ next(mut Self): Option[T]
+ peek(mut Self): Option[T]
+ peek_nth(mut Self, n: uint): Option[T]
+
+# todo: implement peek[T](self: Iter[T]): Peek[T]
+# todo: implement Peekable struct
+# https://github.com/LukeMathWalker/multipeek/blob/main/src/lib.rs
+
+## We don't want a Countable. It's not terribly useful.
+# pub type Countable[T] = interface
+# next(mut Self): Option[T]
+# len(Self): uint
+# get(Self, uint): Option[T]
diff --git a/std/default/options.pk b/std/default/options.pk
index f1bcac4..3aaea49 100644
--- a/std/default/options.pk
+++ b/std/default/options.pk
@@ -1,4 +1,4 @@
-## std/options
+## std/options: Optional types.
## This module is imported by default.
import std/format
@@ -47,20 +47,20 @@ pub func flatten[T](self: Option[Option[T]]): Option[T] = # todo: better name?
None
## Returns the inner value or a default.
-pub func or[T](self: Option[T], default: T): T =
+pub func get_or[T](self: Option[T], default: T): T =
if self of Some(x): x
else: default
## Directly accesses the inner value. Throws an exception if None.
-pub yeet func get[T](self: Option[T]): T =
+pub yeet func `!`[T](self: Option[T]): T =
if self of Some(x): x
else: raise Exception # todo: syntax??
-# todo: direct access, alias to get
-macro `!`[T](self: Option[T]): T
-# todo: indirect access, ??? do we propagate? is this useful? probably not
-macro `?`[T](self: Option[T]): T
-# todo: field access? useful? assignment?
-macro `.?`[T](self: Option[T])
+## Indirect access. Propagates None.
+pub macro `?`[T](self: Option[T]) =
+ quote:
+ match self
+ of Some(x): x
+ of None: return None
## Overloads the == operation for use on Options.
pub func `==`[T](a, b: Option[T]): bool =
diff --git a/std/default/results.pk b/std/default/results.pk
index 2ac47d0..187ece9 100644
--- a/std/default/results.pk
+++ b/std/default/results.pk
@@ -1,4 +1,4 @@
-## std/results
+## std/results: Result types.
## This module is imported by default.
import std/[options, format]
@@ -7,9 +7,11 @@ pub type Result[T, E] = union
Okay: T
Error: E
+# todo: determine the difference between interfaces and types
+# ErrorInterface? Errorable? Err?
pub type Error = interface
- func str(self: Self)
- func dbg(self: Self)
+ str(Self): str
+ dbg(Self): str
pub type Result[T] = Result[T, ref Error]
@@ -79,11 +81,11 @@ pub func transpose[T, E](self: Option[Result[T, E]], error: E): Result[Option[T]
Error(error)
## Returns the inner value or a default.
-pub func or[T, E](self: Result[T, E], default: T): T =
+pub func get_or[T, E](self: Result[T, E], default: T): T =
if self of Okay(x): x
else: default
## Directly accesses the inner value. Throws an exception if Error(e).
-pub yeet func get[T, E](self: Result[T, E]): T =
+pub yeet func `!`[T, E](self: Result[T, E]): T =
match self
of Okay(x): x
of Error(e): raise Exception(e) # todo: syntax??
@@ -92,10 +94,12 @@ pub yeet func get_err[T, E](self: Result[T, E]): E =
of Error(e): e
of Okay(x): raise Exception(x) # todo: syntax??
-# todo: direct access, alias to get
-macro `!`[T, E](self: Result[T, E]): T
-# todo: indirect access, propagates Err
-macro `?`[T, E](self: Result[T]): T
+## Indirect access. Propagates Error.
+macro `?`[T, E](self: Result[T, E]) =
+ quote:
+ match self
+ of Okay(x): x
+ of Error(e): return Error(e)
## Overloads the == operation for use on Results.
pub func `==`[T, E, F](a: Result[T, E], b: Result[T, F]): bool =
diff --git a/std/fundamental/ast.pk b/std/fundamental/ast.pk
new file mode 100644
index 0000000..25bdc02
--- /dev/null
+++ b/std/fundamental/ast.pk
@@ -0,0 +1,119 @@
+## std/ast: Exposes the AST for building and operating on with macros.
+
+pub type Ident = string
+pub type Number = int
+pub type Float = float
+pub type Char = char
+pub type String = str
+pub type Struct = list[struct[field: str, value: Expr]]
+pub type Tuple = list[struct[field: Option[string], value: Expr]]
+pub type List = list[Expr]
+
+pub type Let = struct
+ id: Pattern
+ kind: Option[Type]
+ value: ref Expr
+pub type Var = struct
+ id: Pattern
+ kind: Option[Type]
+ value: Option[ref Expr] # variable bindings can be delayed
+pub type Const = struct
+ id: Pattern
+ kind: Option[Type]
+ value = ref Expr
+pub type FuncDecl = struct
+ public: bool
+ effect: Option[str]
+ id: str
+ generics: list[struct[name: str, kind: Option[Type]]]
+ params: list[struct[name: str, kind: Type]]
+ kind: Type
+ body: list[Expr]
+pub type TypeDecl = struct
+ id: str
+ generics: list[str]
+ alias: Type
+pub type Import = struct
+ mod_from: Option[string]
+ imports: list[str]
+ alias: Option[str]
+pub type Module = struct
+ name: str
+ body: list[ref Expr]
+
+pub type Call = struct
+ id: str
+ params: list[Expr]
+pub type Cond = struct
+ branches: list[CondBranch]
+ else_body: Option[list[Expr]]
+pub type Try = struct
+ body: ref Expr
+ catches: list[struct[exceptions: list[str], body: list[Expr]]]
+ finally_body: Option[list[Expr]]
+pub type Match = struct
+ item: ref Expr
+ branches: list[MatchBranch]
+pub type Block = struct
+ id: Option[str]
+ body: list[Expr]
+pub type Static = struct
+ body: list[Expr]
+pub type For = struct
+ binding: Pattern
+ range: ref Expr
+ body: list[Expr]
+pub type While = struct
+ cond: ref Expr
+ body: list[Expr]
+pub type Loop = struct
+ body: list[Expr]
+
+# the first style of union. naming anonymous types.
+pub type Type = union
+ Void, Never,
+ Integer, Float, String,
+ Func: struct[from, to: ref Type] # todo: multiple parameters
+ Struct: list[struct[id: str, kind: Type]]
+ Tuple: list[struct[id: Option[str], kind: Type]]
+ Union: list[struct[id: str, kind: Type]]
+ Interface: struct # todo: generics
+ funcs: list[Signature]
+ for_type: Option[ref Type]
+ Array: struct[size: uint, kind: ref Type]
+ List: ref Type
+ Slice: ref Type # todo: plus ownership
+ Alias: str # todo: params?? huh?
+ Static: ref Type
+ Mutable: ref Type
+ Reference: ref Type
+pub type Signature = struct # todo: generics
+ id: str
+ effect: Option[str]
+ params: list[Type]
+ kind: Option[Type]
+pub type Pattern = union
+ Ident: str
+ Struct: struct[name: str, params: list[]]
+ Tuple: list[Pattern]
+ List
+pub type CondBranch = struct
+ cond: Expr
+ body: list[Expr]
+pub type MatchBranch = struct
+ pattern: Pattern
+ guard: Option[Expr]
+ body: Expr
+
+# the second style of union. A union of literal types, no names.
+pub type Expr = union
+ Ident, Number, Float, Char, String, Struct, Tuple, List,
+ Let, Var, Const, FuncDecl, TypeDecl, Import, Module,
+ Call, Cond, Try, Match, Block, Static, For, While, Loop,
+
+# todo: decide on a style of union
+
+# anonymous struct objects can be constructed with {}
+# anonymous tuple objects can be constructed with ()
+# anonymous list objects can be constructed with []
+# anonymous union *types* can be constructed with | (in parameters)
diff --git a/std/fundamental/logs.pk b/std/fundamental/logs.pk
new file mode 100644
index 0000000..7a0060f
--- /dev/null
+++ b/std/fundamental/logs.pk
@@ -0,0 +1 @@
+## std/logs: Utility macros and functions for logging.
diff --git a/std/fundamental/tests.pk b/std/fundamental/tests.pk
new file mode 100644
index 0000000..7eb00a8
--- /dev/null
+++ b/std/fundamental/tests.pk
@@ -0,0 +1,5 @@
+## std/tests: Utility macros and functions for testing.
+
+## A macro for runnable examples. Runs them on compilation.
+pub macro examples(body) =
+ ...