ulisp-picocalc/ulisp-extensions.ino

197 lines
4.1 KiB
C++

/*
User Extensions
*/
// Utility functions
uint8_t
dec_to_bcd(uint8_t n)
{
uint8_t bcd = 0;
uint8_t tens = n / 10;
bcd = tens << 4;
tens *= 10;
bcd += (n - tens) & 0x0f;
return bcd;
}
uint8_t
bcd_to_dec(uint8_t n)
{
return ((n>>4) * 10) + (n&0x0f);
}
// Definitions
object *
fn_now(object *args, object *env)
{
(void) env;
static unsigned long Offset;
unsigned long now = millis()/1000;
int nargs = listlength(args);
// Set time
if (nargs == 3) {
Offset = (unsigned long)((checkinteger(first(args))*60 \
+ checkinteger(second(args)))*60 \
+ checkinteger(third(args)) - now);
} else if (nargs > 0) {
error2(PSTR("wrong number of arguments"));
}
// Return time
unsigned long secs = Offset + now;
object *seconds = number(secs%60);
object *minutes = number((secs/60)%60);
object *hours = number((secs/3600)%24);
return cons(hours, cons(minutes, cons(seconds, NULL)));
}
void
hyperprint(object *form, int lm, pfun_t pfun)
{
if (atom(form)) {
if (isbuiltin(form, NOTHING)) {
printsymbol(form, pfun);
} else {
printobject(form, pfun);
}
} else if (quoted(form)) {
pfun('\'');
hyperprint(car(cdr(form)), lm + 1, pfun);
} else {
lm = lm + PPINDENT;
bool fits = (subwidth(form, PPWIDTH - lm - PPINDENT) >= 0);
int special = 0, extra = 0; bool separate = true;
object *arg = car(form);
if (symbolp(arg) && builtinp(arg->name)) {
uint8_t minmax = getminmax(builtin(arg->name));
if (minmax == 0327 || minmax == 0313) {
special = 2; // defun, setq, setf, defvar
} else if (minmax == 0317 || minmax == 0017 ||
minmax == 0117 || minmax == 0123) {
special = 1;
}
}
while (form != NULL) {
if (atom(form)) {
pfstring(PSTR(" . "), pfun);
printobject(form, pfun);
pfun(')');
return;
} else if (separate) {
pfun('(');
separate = false;
} else if (special) {
pfun(' ');
special--;
} else if (fits) {
pfun(' ');
} else {
pln(pfun);
indent(lm, ' ', pfun);
}
hyperprint(car(form), lm+extra, pfun);
form = cdr(form);
}
pfun(')');
}
}
object *
fn_sym_def(object *args, object *env)
{
(void) env;
object *obj = first(args);
pfun_t pfun = pstreamfun(cdr(args));
#if defined(gfxsupport)
if (pfun == gfxwrite) ppwidth = GFXPPWIDTH;
#endif
object *pair = findvalue(obj, env);
object *var = car(pair);
object *val = cdr(pair);
pln(pfun);
if (consp(val) && symbolp(car(val)) && builtin(car(val)->name) == LAMBDA) {
hyperprint(cons(bsymbol(DEFUN), cons(var, cdr(val))), 0, pfun);
} else {
hyperprint(cons(bsymbol(DEFVAR), cons(var, cons(quote(val), NULL))), 0, pfun);
}
pln(pfun);
ppwidth = PPWIDTH;
return bsymbol(NOTHING);
}
object *
fn_lambdap(object *arg, object *env)
{
(void) env;
if (consp(arg)) {
arg = car(arg);
}
if (builtin(arg->name) == LAMBDA) {
return tee;
}
return nil;
}
// Symbol names
const char stringlambdap[] PROGMEM = "lambdap";
const char stringnow[] PROGMEM = "now";
const char string_sym_def[] PROGMEM = "symbol-def";
// Documentation strings
const char doclambdap[] PROGMEM = "(lambdap x)"
"Returns t if the form passed in is a lambda.";
const char docnow[] PROGMEM = "(now [hh mm ss])\n"
"Sets the current time, or with no arguments returns the current time\n"
"as a list of three integers (hh mm ss).";
const char docpform[] PROGMEM = "(pform form str)\n"
"Print a form to a stream in a manner suitable for writing to storage.";
const char doc_sym_def[] PROGMEM = "(symbol-def symbol [str])\n"
"Prints the definition of a symbol (variable or function) defined in\n"
"ulisp using the pretty printer."
"If str is specified it prints to the specified stream.\n"
"It returns no value.";
// Symbol lookup table
const tbl_entry_t lookup_table2[] PROGMEM = {
{ stringlambdap, fn_lambdap, 0211, doclambdap },
{ stringnow, fn_now, 0203, docnow },
{ string_sym_def, fn_sym_def, 0212, doc_sym_def },
};
// Table cross-reference functions
tbl_entry_t *tables[] = {lookup_table, lookup_table2};
const unsigned int tablesizes[] = { arraysize(lookup_table), arraysize(lookup_table2) };
const tbl_entry_t *
table(int n)
{
return tables[n];
}
unsigned int
tablesize(int n)
{
return tablesizes[n];
}