fixed! 2.01 has that bug fixed. rather nasty one in the keyhole optimizer
It is working: FloatingWrench.ino - Wokwi Arduino and ESP32 Simulator
The more I use wrench, the more I like it ![]()
Just posting here to share some love. Thank you for making Wrench available. After a (really long) search for a C-like script interpreter, I'm feeling at home with your project.
Will try it out as interpreter and then post back my feedback. Please keep up the good work. ![]()
I am super-anxious for feedback ![]()
I got stuck when trying to convert the Simon game to Wrench code: https://wokwi.com/projects/328451800839488084 ![]()
Adding debug messages was not enough to get further.
Hello Curt,
My apologies for the delay in replying. I'll gladly share feedback from the perspective of a first time user/adopter.
First, it took me 3 weeks to find your project on the internet. Was looking, listing and testing the most relevant different options: GitHub - radio3-network/operations: Place for research, docs, logs and things to help plan the next steps ahead but your project was difficult to find on the search engines. Only found it when searching here on the arduino forum for a slightly unrelated topic.
My recommendation: include keywords on the description of the github repository: GitHub - jingoro2112/wrench: practical embedded script interpreter such as "arduino", "interpreter", "compiler", "c-like", "esp32", "vm", "virtual machine" (and others you see best).
This because the github search algorithm isn't so effective, especially because there is a typo on your readme as "The wrench Virtual Machgine" and AIs get really confused with that. ![]()
The second thing is the example syntax, it is also needed to correct because
wr_run( w, outBytes ); // load and run the code! only compiles when you use wr_run( w, outBytes, outLen); // load and run the code!. This took me a while to figure out why the Hello World example was not compiling and might confuse other newbies like me.
And that's it. Your work is fantastic, it is being adopted as the default interpreter for B3OS.
I've written a special credits since your interpreter basically permits limitless expansion of features on ESP32 arduino to make it look&feel like a modern smartphone: B3OS/parser.cpp at main · radio3-network/B3OS · GitHub
Next challenge on the goal list is to make Wrench interact with LVGL 8.
The idea is that different apps (if/when desired) can create their own UI using the LVGL libraries already available on the system.
Perhaps I can ask for your help with this integration?
Many thanks! ![]()
Wow thanks! Yeah I have added some keywords to the github and am always looking for practical feedback. I've used this in two projects now and the only way to find those really corner-case issues is to actually test/use it.
I can't commit to anything but would love to help integrate as time allows, send me a me a DM or something and we can talk.
If you find any issues or deficiencies at all please let me know so I can correct them quickly.
Hi Curt - I want to say that you have done a fantastic job, and your program has great potential. Are you still working on it? I would love to see your project fly.
I have been playing around with it to see how far I can push it to integrate well with Arduino, and I have gotten a good step. Still, I am struggling with getting a solid way of integrating Arduino libraries, especially those that create an object (servo, etc.).
This is my list of challenges I have (some have already been mentioned):
- I am missing Class/Objects or functions in structs.
- I am missing a way to integrate a c++ object so that it can be created inside wrench.
- What about unsigned - Missing it for millis etc.
- missing char/byte
I am asking most of the above questions because I made a small code generator which generates wrappers for Arduino code (see below), and I am trying to extend it to libraries. To do so, the terminology needs to be pretty similar to not have to write a lot of manual "hacks". E.g. to use millis() correctly, I need to be sure that overflow works properly - which requires an unsigned long, and to use libraries with objects, I would need to write a lot of intermediary code to make sure it maps out correctly.
On the usability/feature side of things, I have the following:
- I would love an elegant way to concat strings: a = "sdfsdf" + "sdfsdf".
- Could you allow for a return to replace ";"? This would make it similar to javascript
- How do I pull out all the variables - e.g. debug prompt printing the global variables?
- How do I do a hot reload (keeping the variables but reloading the code)
Below is my experimental generated conversion of the basic Arduino functions (some not tested - had to be creative with the types here and there (char, unsigned long, string, etc.), so be critical about it):
void bbmin(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, min(argv[0].asFloat(), argv[1].asFloat()));
}
void bbmax(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, max(argv[0].asFloat(), argv[1].asFloat()));
}
void bbabs(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, abs(argv[0].asFloat()));
}
void bbconstrain(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
constrain(argv[0].asFloat(), argv[1].asFloat(), argv[2].asFloat());
}
void bbround(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, round(argv[0].asFloat()));
}
void bbradians(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, radians(argv[0].asFloat()));
}
void bbdegrees(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, degrees(argv[0].asFloat()));
}
void bbsq(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, sq(argv[0].asFloat()));
}
void bbsqrt(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, sqrt(argv[0].asFloat()));
}
void bbpow(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, pow(argv[0].asFloat(), argv[1].asFloat()));
}
void bbinterrupts(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
interrupts();
}
void bbnoInterrupts(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
noInterrupts();
}
void bbclockCyclesPerMicrosecond(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
clockCyclesPerMicrosecond();
}
void bbclockCyclesToMicroseconds(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, clockCyclesToMicroseconds(argv[0].asInt()));
}
void bbmicrosecondsToClockCycles(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, microsecondsToClockCycles(argv[0].asInt()));
}
void bb_NOP(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
_NOP();
}
void bbpinMode(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
pinMode(argv[0].asInt(), argv[1].asInt());
}
void bbdigitalWrite(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
digitalWrite(argv[0].asInt(), argv[1].asInt());
}
void bbdigitalRead(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, digitalRead(argv[0].asInt()));
}
void bbanalogRead(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, analogRead(argv[0].asInt()));
}
void bbanalogWrite(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
analogWrite(argv[0].asInt(), argv[1].asInt());
}
void bbmillis(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, millis());
}
void bbmicros(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, micros());
}
void bbdelay(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
delay(argv[0].asInt());
}
void bbdelayMicroseconds(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
delayMicroseconds(argv[0].asInt());
}
void bbpulseIn(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, pulseIn(argv[0].asInt(), argv[1].asInt(), argv[2].asInt()));
}
void bbpulseInLong(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
pulseInLong(argv[0].asInt(), argv[1].asInt());
}
void bbtone(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
tone(argv[0].asInt(), argv[1].asInt(), argv[2].asInt());
}
void bbnoTone(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
noTone(argv[0].asInt());
}
void bbrandom(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, random(argv[0].asInt(), argv[1].asInt()));
}
void bbrandomSeed(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
randomSeed(argv[0].asInt());
}
void bbmap(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, map(argv[0].asInt(), argv[1].asInt(), argv[2].asInt(), argv[3].asInt(), argv[4].asInt()));
}
void bbshiftIn(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeInt(&retVal, shiftIn(argv[0].asInt(), argv[1].asInt(), argv[2].asInt()));
}
void bbshiftOut(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
shiftOut(argv[0].asInt(), argv[1].asInt(), argv[2].asInt(), argv[3].asInt());
}
void bbcos(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, cos(argv[0].asFloat()));
}
void bbsin(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, sin(argv[0].asFloat()));
}
void bbtan(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
wr_makeFloat(&retVal, tan(argv[0].asFloat()));
}
void bbisAlpha(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isAlpha(argv[0].asInt());
}
void bbisAlphaNumeric(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isAlphaNumeric(argv[0].asInt());
}
void bbisAscii(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isAscii(argv[0].asInt());
}
void bbisControl(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isControl(argv[0].asInt());
}
void bbisDigit(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isDigit(argv[0].asInt());
}
void bbisGraph(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isGraph(argv[0].asInt());
}
void bbisHexadecimalDigit(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isHexadecimalDigit(argv[0].asInt());
}
void bbisLowerCase(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isLowerCase(argv[0].asInt());
}
void bbisPrintable(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isPrintable(argv[0].asInt());
}
void bbisPunct(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isPunct(argv[0].asInt());
}
void bbisSpace(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isSpace(argv[0].asInt());
}
void bbisUpperCase(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isUpperCase(argv[0].asInt());
}
void bbisWhitespace(WRState* w, const WRValue* argv, const int argn, WRValue& retVal, void* usr) {
isWhitespace(argv[0].asInt());
}
void registerBridge(WRState* w) {
String wrenchDefines = "";
wrenchDefines = wrenchDefines + "HIGH=" + HIGH + ";";
wrenchDefines = wrenchDefines + "LOW=" + LOW + ";";
wrenchDefines = wrenchDefines + "INPUT=" + INPUT + ";";
wrenchDefines = wrenchDefines + "OUTPUT=" + OUTPUT + ";";
wrenchDefines = wrenchDefines + "INPUT_PULLUP=" + INPUT_PULLUP + ";";
wrenchDefines = wrenchDefines + "PI=" + PI + ";";
wrenchDefines = wrenchDefines + "HALF_PI=" + HALF_PI + ";";
wrenchDefines = wrenchDefines + "TWO_PI=" + TWO_PI + ";";
wrenchDefines = wrenchDefines + "DEG_TO_RAD=" + DEG_TO_RAD + ";";
wrenchDefines = wrenchDefines + "RAD_TO_DEG=" + RAD_TO_DEG + ";";
wrenchDefines = wrenchDefines + "EULER=" + EULER + ";";
wrenchDefines = wrenchDefines + "LSBFIRST=" + LSBFIRST + ";";
wrenchDefines = wrenchDefines + "MSBFIRST=" + MSBFIRST + ";";
wrenchDefines = wrenchDefines + "CHANGE=" + CHANGE + ";";
wrenchDefines = wrenchDefines + "FALLING=" + FALLING + ";";
wrenchDefines = wrenchDefines + "RISING=" + RISING + ";";
wrenchDefines = wrenchDefines + "DEFAULT=" + DEFAULT + ";";
wrenchDefines = wrenchDefines + "EXTERNAL=" + EXTERNAL + ";";
wrenchDefines = wrenchDefines + "LED_BUILTIN=" + LED_BUILTIN + ";";
wr_registerFunction(w, "min", bbmin, 0);
wr_registerFunction(w, "max", bbmax, 0);
wr_registerFunction(w, "abs", bbabs, 0);
wr_registerFunction(w, "constrain", bbconstrain, 0);
wr_registerFunction(w, "round", bbround, 0);
wr_registerFunction(w, "radians", bbradians, 0);
wr_registerFunction(w, "degrees", bbdegrees, 0);
wr_registerFunction(w, "sq", bbsq, 0);
wr_registerFunction(w, "sqrt", bbsqrt, 0);
wr_registerFunction(w, "pow", bbpow, 0);
wr_registerFunction(w, "interrupts", bbinterrupts, 0);
wr_registerFunction(w, "noInterrupts", bbnoInterrupts, 0);
wr_registerFunction(w, "clockCyclesPerMicrosecond", bbclockCyclesPerMicrosecond, 0);
wr_registerFunction(w, "clockCyclesToMicroseconds", bbclockCyclesToMicroseconds, 0);
wr_registerFunction(w, "microsecondsToClockCycles", bbmicrosecondsToClockCycles, 0);
wr_registerFunction(w, "_NOP", bb_NOP, 0);
wr_registerFunction(w, "pinMode", bbpinMode, 0);
wr_registerFunction(w, "digitalWrite", bbdigitalWrite, 0);
wr_registerFunction(w, "digitalRead", bbdigitalRead, 0);
wr_registerFunction(w, "analogRead", bbanalogRead, 0);
wr_registerFunction(w, "analogWrite", bbanalogWrite, 0);
wr_registerFunction(w, "millis", bbmillis, 0);
wr_registerFunction(w, "micros", bbmicros, 0);
wr_registerFunction(w, "delay", bbdelay, 0);
wr_registerFunction(w, "delayMicroseconds", bbdelayMicroseconds, 0);
wr_registerFunction(w, "pulseIn", bbpulseIn, 0);
wr_registerFunction(w, "pulseInLong", bbpulseInLong, 0);
wr_registerFunction(w, "tone", bbtone, 0);
wr_registerFunction(w, "noTone", bbnoTone, 0);
wr_registerFunction(w, "random", bbrandom, 0);
wr_registerFunction(w, "randomSeed", bbrandomSeed, 0);
wr_registerFunction(w, "map", bbmap, 0);
wr_registerFunction(w, "shiftIn", bbshiftIn, 0);
wr_registerFunction(w, "shiftOut", bbshiftOut, 0);
wr_registerFunction(w, "cos", bbcos, 0);
wr_registerFunction(w, "sin", bbsin, 0);
wr_registerFunction(w, "tan", bbtan, 0);
wr_registerFunction(w, "isAlpha", bbisAlpha, 0);
wr_registerFunction(w, "isAlphaNumeric", bbisAlphaNumeric, 0);
wr_registerFunction(w, "isAscii", bbisAscii, 0);
wr_registerFunction(w, "isControl", bbisControl, 0);
wr_registerFunction(w, "isDigit", bbisDigit, 0);
wr_registerFunction(w, "isGraph", bbisGraph, 0);
wr_registerFunction(w, "isHexadecimalDigit", bbisHexadecimalDigit, 0);
wr_registerFunction(w, "isLowerCase", bbisLowerCase, 0);
wr_registerFunction(w, "isPrintable", bbisPrintable, 0);
wr_registerFunction(w, "isPunct", bbisPunct, 0);
wr_registerFunction(w, "isSpace", bbisSpace, 0);
wr_registerFunction(w, "isUpperCase", bbisUpperCase, 0);
wr_registerFunction(w, "isWhitespace", bbisWhitespace, 0);
}
Very much still developing it! Well sort of. I used it for a project or two, and whenever I need it for something I occasionally do a pass on the codebase, but mostly I just jump on any bugs the community finds.
So lets see if I can address your pain points..
1: So what is a member function? Its a function that:
- has a name qualified with it's container ie: container::function()
- has an implicit argument, a pointer to an instantiated container of its type ie: this
Thats pretty much it. In times of yore we did it in c like this:
struct SomeStruct { int a; };
SomeStruct_Function( SomeStruct* this, .... ) { this->a += 10; }
Mr. Stroustrup came along and made that process cleaner and more explicit.
So what's my point? I could add c++ like markup to wrench, but it would be syntactic sugar only, under the hood it would just do that c-thing. In a minimal scripting language...? That's a corner I chose not to paint, I mean have you seen Python? yikes.
But I see the argument. If the users beat a path to my door I can modify the parser to do it, but for now no thanks.
2- c++ in wrench? You have to be a bit more specific. It could be as simple as adding some extern "c" {} goodness, or it could be quite a bit more complicated. If you mean map a c++ object into wrench... geez I dunno that might be a bit outside the scope of what I wanted to accomplish. Gimee an example.
-
unsigned? yeah.. yeah... this is an argument I had with myself many times. MANY times. I ended up deciding to keep everything signed for convenience. The thing is if I add another type certain structures don't work, and I would have to expand the codebase almost everywhere and the point was to keep it small.
-
Kinda same as 3. If you really need this I would argue a strategic library function could get you there, just cast the argument to whatever it is you really need, the bits are all there

Okay so for feature requests..
concat strings: It already does this:
a = "alskdfjaslkdjf" "aslkjdflaksjd";
Same as c
I don't understand return replacing ';' now you're sounding like one of 'dem pythonic folk..
pulling out the variables.... okay this is something I'd have to add and it's about time. The variables are not stored by name, just by hash. This is done to keep the executable size to an absolute minimum. I need to add an "include symbols" option so the linker includes all the info required to do what you are asking, I'll add that to my todo list.
Hot reloading is not possible. okay not easy. not even hard.. it would be really really hard. You know how I said variables are stored by hash? That was only a half truth. The "hash" is actually just an offset generated at link time. so global variables are collected and assigned an offset, then whenever the linker encounters one it looks it up and plugs in the offset. Adding that table is something I can do (see above) but when the script loads it statically allocates exactly enough global space to fit its table. see the problem?
For hot reload to work the variables would have to be identical (number and order of) and there would be no way to enforce this.
Oh an functions are also statically allocated so that can't change.
Best I could do would be to add a "hot reloadable" option to the linker so that it could dump it's global variable table, and then on reload pull it in, since the information required to do that would normally not be included. It would be sort of a very abridged version of debug info and act something like...
The script would include a block that described global variable hash and offset, when the hot-reload happened the global data would be preserved on that basis.. then the new code would be loaded and instead of creating the global store with zeros, would try to find it's old value in that table. If it finds it, great it uses it. If not it sets it to zero, everything else just works... as long as I also preserve the dynamic store.
What do you want this for anyway?
Great to get a response from you - sorry that I did not see it until now. I did not realise that the Arduino forum did not send a notification - I have added notifications to this thread.
First of all, I am still using your code a lot. I love it!
I wrote a browser editor for it:
COMMENTS ON YOUR COMMENTS:
1: So, what is a member function? It's a function that...
Adding functions to structs would allow me to create "objects" that imitations objects from the c world.
2- c++ in wrench? You have to be a bit more specific. It could be as simple as adding some extern "c" {} goodness, or it could be quite a bit more complicated. If you mean map a c++ object into wrench... geez I dunno that might be a bit outside the scope of what I wanted to accomplish. Gimee an example.
Back to the basics: I want to find an elegant way to add Servos - and if you have functions in the structs - I can map out between a c object and a wrench "struct".
unsigned? yeah.. yeah... this is an argument I had with myself many times. MANY times. I ended up deciding to keep everything signed for convenience. The thing is if I add another type certain structures don't work, and I would have to expand the codebase almost everywhere and the point was to keep it small.
OK my primary concern is millis overflow timing. I have yet to test if this is a problem. Millis is unsigned and you using signed.... and also char/byte.
Kinda same as 3. If you really need this I would argue a strategic library function could get you there, just cast the argument to whatever it is you really need, the bits are all there
Hmm - I need to understand library functions and what you mean by this.
Okay so for feature requests..
concat strings: It already does this:
Hmm - I have to look into what you mean here.
I don't understand return replacing ';' now you're sounding like one of 'dem pythonic folk..
Nope I just know how hard it is for beginners to add ";" and if it would take two lines of code to add it to your script, it would save an endless amount of pain for beginners
Similarly adding "let/var" as variable definitions would allow javascript beginners to feel familiar with your syntax (small details - I know).
pulling out the variables.... okay this is something I'd have to add and it's about time. The variables are not stored by name, just by hash. This is done to keep the executable size to an absolute minimum. I need to add an "include symbols" option so the linker includes all the info required to do what you are asking, I'll add that to my todo list.
This is one thing I would really love! And after a few months of playing with Wrench the one feature I would really like to bother you about - the rest is just details/reflections/religion.
Hot reloading is not possible. okay not easy. not even hard.. it would be really really hard. You know how I said variables are stored by hash? That was only a half truth. The "hash" is actually just an offset generated at link time. so global variables are collected and assigned an offset, then whenever the linker encounters one it looks it up and plugs in the offset. Adding that table is something I can do (see above) but when the script loads it statically allocates exactly enough global space to fit its table. see the problem?
If the variables could be pulled out - I can always shoehorn them in again - in some way. It is only about the global variables ![]()
For hot reload to work the variables would have to be identical (number and order of) and there would be no way to enforce this.
Oh an functions are also statically allocated so that can't change.
Best I could do would be to add a "hot reloadable" option to the linker so that it could dump it's global variable table, and then on reload pull it in, since the information required to do that would normally not be included. It would be sort of a very abridged version of debug info and act something like...
Yes - precisely that is plenty enough.
The script would include a block that described global variable hash and offset, when the hot-reload happened the global data would be preserved on that basis.. then the new code would be loaded and instead of creating the global store with zeros, would try to find it's old value in that table. If it finds it, great it uses it. If not it sets it to zero, everything else just works... as long as I also preserve the dynamic store.
I really think that pulling out the variables would be enough - could I just add them after compile?
What do you want this for anyway?
I want to make a simple browser-based editor that can update code on Arduino (esp32) over usb and wifi. I could just use some open source javascript interpreter, but all in all I really really like how you have cut it down to the core... except for the few things I am nagging you about
The main dream is to do the following:
- Give a complete beginner a seamless experience of programming (no install - 100% browser). Here my love is for p5js (hence javascript), and thus, I am nudging you in the javascript syntax direction.
- Allow a complete beginner to also have a fundamental understanding of object-oriented programming and dot notation (hence the functions in struct)
2b. close one to one syntax with arduino and the libraries (hence the functions in struct) - Give a generic interface for scripting IOT.
- Create wifi-based instant code upload - therefore Wrench is attractive I am asking about hot-reload and extraction of global variables.
- Make as easy a transition from scripting to c as possible. Hence building it on top of Arduino so anybody can extend the library interface without having to go deep into "npm", "cmake" etc.
PS: I have been hacking away on Wrench for a while now, and I have yet to find any weird bugs/quirks - your syntax does what you say it does etc. Really impressive.
Actually a lot of this got implemented already, get latest!
In particular the global variable symbol table is now included in the code (it can be stripped out if you really want to save the space) and I added methods to get access to them, see the WrenchValue helper class.
A lot of little bugs (and a few big ones) have been fixed as well, the more wrench is actually used the better and tighter it gets, as long as users keep reporting back to me ![]()
I can add a variable declaration, "let" and "var" are both pretty harmless, I'll add them to the parser.
I think I might be able to parse something like this, and have it "work" with the existing VM (haha) :
struct SomeStruct
{
c = 10;
function SomeFunc()
{
println( c ); // 0 because it is local
println( this.c ); // 10! because "this" exists as an implicit variable
}
d = 20;
};
SomsStruct S = new SomeStruct;
S.SomeFunc();
I think I could do that..
