keith-packard / snek

Snek programming language for tiny systems
GNU General Public License v3.0
292 stars 30 forks source link

Would like input(), int(), and float() in Snek for Arduino UNO R3 #40

Closed mobluse closed 2 years ago

mobluse commented 2 years ago

Snek for Posix (e.g. Linux) has input(), float(), and int(). I would like these functions for Arduino UNO R3 also. I believe it would not add too much since these functions are used by the translation of the code in eeprom to bytecode in RAM anyway and by the REPL. It would AFAIK only be a matter of making them callable. If all do not fit in the flash ROM, I would want input() first, and then float(), since int() and float() could be written using the existing functions in Snek for Arduino UNO.

abs() exists in Snek for Posix and Arduino UNO. These functions are not currently documented on https://sneklang.org/doc/snek.html.

keith-packard commented 2 years ago

yeah, these would all be really useful. However, they just don't fit on this device along with the 512-byte boot loader. If you're willing to forego that and load snek using a dongle like the USBtinyISP, then you'd have enough space for all of these.

avrdude -c usbtiny -p ATMEGA328P -U flash:w:snek-uno-1.7.hex

snek-uno-1.7.zip

Thanks for finding a bug in the docs; I didn't realize abs was completely undocumented!

mobluse commented 2 years ago

I got an AVR Pocket Programmer by Sparkfun.com that works like a USBTiny and now I have input(), int(), and float(). I used avrdude as above, but otherwise followed this video for connection tips.

keith-packard commented 2 years ago

Awesome. I'll plan on creating new ports for the 328p devices which use all of the available ROM. If you've got other small functions that might be nice to have, I can look at adding a few more...

mobluse commented 2 years ago

I would also like exec() and eval(). I believe these would not be too big since e.g. exec() probably exists internally to interpret the file and in the REPL. These could be used if you want to write a calculator. If both exec() and eval() would not fit I prefer only exec(). In one case where I use exec() in a function in a MicroPython program I have to pass globals() as an argument. exec() is also something that distinguishes interpreted languages from compiled and would be a unique selling point for Snek versus C++ for Arduino UNO.

str() might also be useful to have, but you can use "%d"%a, "%g"%a, or "%s"%a as replacements, but that requires that you now what type a is.

Some functions to write and read data, e.g. strings, to eeprom. This could be used to log data. Of course, if you are not careful you risk overwriting your program, but that could also be an advantage. You could store log data in comments i.e. after #.

eeprom.write() doesn't work for this purpose now since you cannot control from a program what comes in on the console, unless you hack the serial port. You could add arguments to eeprom.write() to tell position and string. https://sneklang.org/doc/snek.html#_eeprom_write You would also need a eeprom.read() or eeprom.load() with position and count as arguments. Maybe you have some better ideas on how to use the EEPROM for logging to or editing the file.

keith-packard commented 2 years ago

I would also like exec() and eval(). I believe these would not be too big since e.g. exec() probably exists internally to interpret the file and in the REPL.

I've spent a couple of days looking at how hard this would be to support and it's not as easy as I would have expected; the key issue is that this requires suspending the parser after each top-level operation so that you can invoke it from exec or eval. To reduce the size of the system, the parser uses extensive global state, all of which would need to be encapsulated to allow effectively recursive use of it. This is fairly easy for CPython, which uses the C call stack for all of this state. Early experiments indicate that switching from global to local state (so you can have more than one parse instance running at a time), would increase the size of the executable by many hundreds of bytes. I'll keep these experiments around and see if I can think of a way to avoid the complexity required here. I agree it would be really nice to have, but it's gonna be a challenge.

str() might also be useful to have, but you can use "%d"%a, "%g"%a, or "%s"%a as replacements, but that requires that you now what type a is.

str() is functionally equivalent to "%s" (at least for snek), although I did discover a bug with %s output for lists/dicts/tuples that I'll have fixed. Adding str was pretty easy.

Some functions to write and read data, e.g. strings, to eeprom. This could be used to log data. Of course, if you are not careful you risk overwriting your program, but that could also be an advantage. You could store log data in comments i.e. after #.

That's an interesting idea -- one issue is that eeprom storage is very limited on the 328p, and storing two things there would require some kind of structured storage?

Maybe you have some better ideas on how to use the EEPROM for logging to or editing the file.

For editing the program, I'm still focused on using snekde or mu-editor from another machine.

mobluse commented 2 years ago

Is there a version with str() that I can test?

keith-packard commented 2 years ago

Not yet; I got side tracked, and then my back got wrecked by my dad's guest bed. I've got it sitting here on a branch with a pile of other changes. Until then, you can use '%s' % (val,) which is exactly the same