A toy language built for the Pebble smartwatch
Go to file
Sage Vaillancourt b222df047d Only run tests if 'make' succeeded 2021-07-12 20:10:45 -04:00
resources/images Got results-as-operands working 2020-05-06 04:33:24 +01:00
src Only run tests if 'make' succeeded 2021-07-12 20:10:45 -04:00
.gitignore Converted to package.json format 2020-08-02 21:18:24 +01:00
README.md Update README for recent changes. Remove aliases. 2020-08-09 23:37:28 +01:00
package.json Bump version number 2020-08-02 21:54:21 +01:00
wscript Initial Commit 2020-05-06 04:33:24 +01:00

README.md

PebbLisp

A very basic LISP implementation with an interpreter and editor written for the Pebble.

Download the Android app 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.

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 0 0)

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) 0)

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 0 0)) (pw win 0)

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