151 lines
6.2 KiB
Markdown
151 lines
6.2 KiB
Markdown
# PebbLisp
|
|
A very basic LISP implementation with an interpreter and editor written for the Pebble.
|
|
|
|
[Download the Android app](https://gitlab.com/sagev9000/pebblispandroid/-/wikis/Downloads) to easily type up and send scripts to your Pebble.
|
|
|
|
# Writing in PebbLisp
|
|
PebbLisp includes several built-ins functionalities.
|
|
|
|
## Def
|
|
`def` stores a given object into the environment with the given symbol. The general form is:
|
|
|
|
`(def symbol object)`
|
|
|
|
As an example, to store a long greeting message into the short symbol `g`:
|
|
|
|
`(def g "Hello, how are you today?")`
|
|
|
|
`g` will then evaluate to `"Hello, how are you today"`.
|
|
|
|
> Remember that defining an object with the same symbol as an object that already exists is possible, but deletes the original object from the environment!
|
|
|
|
## If
|
|
`if` checks a given condition. If the condition evaluates to true, the first given expression is returned. If false, the second expression is returned. The general format is:
|
|
|
|
`(if condition expr1 expr2)`
|
|
|
|
The condition will typically be involve a comparison operator. For example:
|
|
|
|
`(if (< 5 10) "Yee" "haw")`
|
|
|
|
Would return `"Yee"`, as `(< 5 10)` aka `5 < 10` evaluates to true.
|
|
|
|
## Fn
|
|
`fn` creates a lambda with a (theoretically) arbitrary number of arguments to be evaluated on call. The general form is:
|
|
|
|
`(fn (arg-list) (lambda-body))`
|
|
|
|
A lambda will commonly be stored under a `def` symbol, for example:
|
|
|
|
`(def sq (fn (a) (* a a)))`
|
|
|
|
Defines a simple lambda to square a given number. Calling it is as simple as `(sq 5)`, which returns `25`.
|
|
|
|
Lambdas can also be applied anonymously, as in `((fn (a) (* a a)) 5)`, which also returns `25`, but this is most useful when using something like `map`. For example:
|
|
|
|
`(map (fn (a) (* a a)) (1 2 3 5 8 13 21 34))`
|
|
|
|
Uses an anonymous lambda to square each element in the list. This is particularly useful on a low-memory device like the Pebble, where it may be useful to avoid storing the named lambda object in the environment.
|
|
|
|
Lambdas may also have no arguments:
|
|
|
|
`(fn () 9001)`
|
|
|
|
## Cat
|
|
`cat` returns its arguments concatenated as strings. It has the same general form as arithmetic operators
|
|
|
|
`(cat expr1 expr2 ...)`
|
|
|
|
For example, combining numbers and strings:
|
|
|
|
`(cat "There are " 5 " cats")`
|
|
|
|
Would return `There are 5 cats`.
|
|
|
|
A `cat` operation is applied implicitly when using `+` with strings, but this may result in confusing behavior when combined with number objects, due to the left-associativity of operators. For example, `(+ 5 10 " cats")` results in `15 cats` but `(+ "Cats: " 5 10)` results in `Cats: 510`.
|
|
|
|
## Map
|
|
`map` applies a given lambda to each element in a given list and returns a list composed of each result. The general form of a `map` expression is
|
|
|
|
`(map lambda (input-list))`
|
|
|
|
For example, using a `sq` lambda:
|
|
|
|
`(map sq (1 2 3 4 5 6 7 8 9 10)`
|
|
|
|
Would return `( 1 4 9 16 25 36 49 64 81 100 )`, with each element being the square of the corresponding element in the input list.
|
|
|
|
## Fil
|
|
`fil` returns a filtered list, based on a given list and a given condition. Partial function support in PebbLisp is nowhere near comprehensive, but `fil` operates on the bare notion that currently exists. The general form of a `fil` expression is
|
|
|
|
`(fil (partial-condition) (candidate-list))`
|
|
|
|
Each element in the candidate list is compared against the partial condition. If the comparison returns true, it is added to the returned list. For example
|
|
|
|
`(fil (< 100) (20 150 30 200))`
|
|
|
|
would return `( 150 200 )`, as no other elements fit the condition `(< 100 n)`.
|
|
|
|
# Pebble-Specific Functions
|
|
There are several functions to access features of the Pebble itself.
|
|
Note that due to some over-simplicity of function-handling, all of the following functions expect to receive two arguments, regardless of how many they actually use.
|
|
|
|
## Checking the Time
|
|
There are several functions for fetching invidual elements of the current time
|
|
- `sec` the current seconds (0-59)
|
|
- `mnt` the current minutes (0-59)
|
|
- `hr` the current hour (0-23)
|
|
- `hrt` the current hour (1-12)
|
|
|
|
For example
|
|
|
|
`(mnt)`
|
|
|
|
would return 16, if called at 5:16
|
|
|
|
## Vibrating
|
|
`vibe` calls the vibration engine to start, following a given pattern. The pattern should be a list, composed of alternating on/off durations, in milliseconds. For example
|
|
|
|
`(vibe (100 200 200 400 200 800))`
|
|
|
|
would cause a sort of *Bz. Bzz. Bzzzz. Bzzzzzzzz.* pattern.
|
|
|
|
## Window Manipulation
|
|
Basic Window and TextLayer manipulations are enabled in PebbLisp.
|
|
|
|
`cw` creates a blank window that can be manipulated by other functions. Note that `cw` does not itself display the window.
|
|
|
|
`pw` is the function responsible for pushing a window onto the stack. For example
|
|
|
|
`(def win (cw)) (pw win)`
|
|
|
|
Creates and pushes to the screen a blank white window. Note that windows can be exited by tapping the back button. Getting something useful to display requires the use of a TextLayer.
|
|
|
|
`atl` adds a text layer to the given window, and displays the given object as text. For example
|
|
|
|
`(def tl (atl win "Hello"))`
|
|
|
|
Adds a TextLayer to `ww` with the text "Hello", where `ww` is a Window created with `cw`. It also stores a reference to the TextLayer in `tl`, for later updates.
|
|
|
|
`utl` changes the text in a given TextLayer. For example
|
|
|
|
`(utl tl "Good-bye")`
|
|
|
|
changes the text in `tl` to "Good-bye", where `tl` is an existing TextLayer.
|
|
|
|
## Subscribing
|
|
`sub` allows for a given lambda to be repeatedly called at a given time interval. More testing is needed, but it is possible that this lambda needs to be defined beforehand, instead of directly passed to `sub`. The lambda will likely fail if it requires arguments.
|
|
|
|
The first argument is the lambda to be called, and the second is an optional argument selecting the frequency of the repetition. If the second argument is any number 1-6, it will repeat every second, minute, hour, day, month, or year, respectively. If the argument is anything else, it will default to repeating every minute.
|
|
|
|
Subscribing currently has little use outside of window manipulation, as it's effects are hard to view outside of that environment. As an example
|
|
|
|
`(sub upwin 1)`
|
|
|
|
would request that `upwin` be run every second, where `upwin` is a lambda that does not rely on arguments.
|
|
|
|
# TODO
|
|
- Better script calling
|
|
- Even more pebble functions
|
|
- Maybe hard-code more built-in functions to ease up on memory use
|