diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c2616d13..30703f1f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development -## [10.0.0.0] - +## [10.0.0.1] +### Added +- Berry add module ``python_compat`` to be closer to Python syntax ## [Released] diff --git a/lib/libesp32/Berry/default/be_modtab.c b/lib/libesp32/Berry/default/be_modtab.c index 5d34177b7..3ce4cecd3 100644 --- a/lib/libesp32/Berry/default/be_modtab.c +++ b/lib/libesp32/Berry/default/be_modtab.c @@ -24,6 +24,7 @@ be_extern_native_module(introspect); be_extern_native_module(strict); /* Tasmota specific */ +be_extern_native_module(python_compat); be_extern_native_module(persist); be_extern_native_module(light); be_extern_native_module(gpio); @@ -80,6 +81,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #endif /* user-defined modules register start */ + &be_native_module(python_compat), &be_native_module(path), &be_native_module(persist), &be_native_module(gpio), diff --git a/lib/libesp32/Berry/default/be_python_compat.c b/lib/libesp32/Berry/default/be_python_compat.c new file mode 100644 index 000000000..d36f468fd --- /dev/null +++ b/lib/libesp32/Berry/default/be_python_compat.c @@ -0,0 +1,58 @@ +/******************************************************************** + * Berry python compatibility module + * + * `import python_compat` + *******************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: _anonymous_ +********************************************************************/ +be_local_closure(_anonymous_, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_string("global", 503252654, 6), + /* K1 */ be_nested_string("True", -841064955, 4), + /* K2 */ be_nested_string("False", -1753917960, 5), + /* K3 */ be_nested_string("None", 810547195, 4), + /* K4 */ be_nested_string("b", -418632219, 1), + }), + (be_nested_const_str("_anonymous_", 1957281476, 11)), + (be_nested_const_str("python_compat.be", -225667571, 16)), + ( &(const binstruction[10]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x50080200, // 0001 LDBOOL R2 1 0 + 0x90060202, // 0002 SETMBR R1 K1 R2 + 0x50080000, // 0003 LDBOOL R2 0 0 + 0x90060402, // 0004 SETMBR R1 K2 R2 + 0x4C080000, // 0005 LDNIL R2 + 0x90060602, // 0006 SETMBR R1 K3 R2 + 0x60080015, // 0007 GETGBL R2 G21 + 0x90060802, // 0008 SETMBR R1 K4 R2 + 0x80040000, // 0009 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified module: python_compat +********************************************************************/ +be_local_module(python_compat, + "python_compat", + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(_anonymous__closure) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(python_compat, NULL); +/********************************************************************/ diff --git a/lib/libesp32/Berry/src/be_parser.c b/lib/libesp32/Berry/src/be_parser.c index fcef0165a..fc7c06de5 100644 --- a/lib/libesp32/Berry/src/be_parser.c +++ b/lib/libesp32/Berry/src/be_parser.c @@ -877,6 +877,30 @@ static void primary_expr(bparser *parser, bexpdesc *e) } } +/* parse a single string literal as parameter */ +static void call_single_string_expr(bparser *parser, bexpdesc *e) +{ + bexpdesc arg; + bfuncinfo *finfo = parser->finfo; + int base; + + /* func 'string_literal' */ + check_var(parser, e); + if (e->type == ETMEMBER) { + push_error(parser, "method not allowed for string prefix"); + } + + base = be_code_nextreg(finfo, e); /* allocate a new base reg if not at top already */ + simple_expr(parser, &arg); + be_code_nextreg(finfo, &arg); /* move result to next reg */ + + be_code_call(finfo, base, 1); /* only one arg */ + if (e->type != ETREG) { + e->type = ETREG; + e->v.idx = base; + } +} + static void suffix_expr(bparser *parser, bexpdesc *e) { primary_expr(parser, e); @@ -891,6 +915,9 @@ static void suffix_expr(bparser *parser, bexpdesc *e) case OptLSB: /* '[' index */ index_expr(parser, e); break; + case TokenString: + call_single_string_expr(parser, e); /* " string literal */ + break; default: return; } diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 824ae114a..fa87de30e 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -990,6 +990,7 @@ //#define USE_WEBCAM // Add support for webcam #define USE_BERRY // Enable Berry scripting language + #define USE_BERRY_PYTHON_COMPAT // Enable by default `import python_compat` #define USE_BERRY_TIMEOUT 4000 // Timeout in ms, will raise an exception if running time exceeds this timeout #define USE_BERRY_PSRAM // Allocate Berry memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact // #define USE_BERRY_DEBUG // Compile Berry bytecode with line number information, makes exceptions easier to debug. Adds +8% of memory consumption for compiled code diff --git a/tasmota/xdrv_52_7_berry_embedded.ino b/tasmota/xdrv_52_7_berry_embedded.ino index afd9cb058..5450de6a9 100644 --- a/tasmota/xdrv_52_7_berry_embedded.ino +++ b/tasmota/xdrv_52_7_berry_embedded.ino @@ -26,65 +26,18 @@ \*********************************************************************************************/ const char berry_prog[] = - "import persist " - // create a 'ntv' module to allow functions to be registered in a safe namespace - // "ntv = module('ntv') " - // auto-import modules - // // import alias +#ifdef USE_BERRY_PYTHON_COMPAT + // enable python syntax compatibility mode + "import python_compat " +#endif + // persistance module + "import persist " + #ifdef USE_ENERGY_SENSOR "import energy " #endif - - // // Force gc and return allocated memory - // "def gc() " - // "import gc " - // "gc.collect() " - // "return gc.allocated() " - // // "end " - // // simple wrapper to load a file - // // prefixes '/' if needed, and simpler to use than `compile()` - // "def load(f) " - // "import string " - // "try " - // // check that the file ends with '.be' of '.bec' - // "var fl = string.split(f,'.') " - // "if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) " - // "raise \"file extension is not '.be' or '.bec'\" " - // "end " - // "var native = f[size(f)-1] == 'c' " - // // add prefix if needed - // "if f[0] != '/' f = '/' + f end " - // // load - works the same for .be and .bec - // "var c = compile(f,'file') " - // // save the compiled bytecode - // "if !native " - // "try " - // "self.save(f+'c', c) " - // "except .. as e " - // "self.log(string.format('BRY: could not save compiled file %s (%s)',f+'c',e)) " - // "end " - // "end " - // // call the compiled code - // "c() " - // "self.log(string.format(\"BRY: sucessfully loaded '%s'\",f)) " - // "except .. as e " - // "raise \"io_error\",string.format(\"Could not load file '%s'\",f) " - // "end " - - // "end " - - - // // Monkey patch `Driver` class - To be continued - // "class Driver2 : Driver " - // "def add_cmd(c, f) " - // "var tasmota = self.get_tasmota() " - // "tasmota.add_cmd(c, / cmd, idx, payload, payload_json -> f(self, cmd, idx, payload, payload_json)) " - // "end " - // "end " - // "Driver = Driver2 " - // Instantiate tasmota object "tasmota = Tasmota() " "def log(m,l) tasmota.log(m,l) end " @@ -97,29 +50,6 @@ const char berry_prog[] = #endif // USE_LVGL - // Wire class - // "class Wire : Wire_ntv " - // // read bytes as `bytes()` object - // "def read_bytes(addr,reg,size) " - // "self._begin_transmission(addr) " - // "self._write(reg) " - // "self._end_transmission(false) " - // "self._request_from(addr,size) " - // "var ret=bytes(size) " - // "while (self._available()) " - // "ret..self._read() " - // "end " - // "return ret " - // "end " - // // write bytes from `bytes` object - // "def write_bytes(addr,reg,b) " - // "self._begin_transmission(addr) " - // "self._write(reg) " - // "self._write(b) " - // "self._end_transmission() " - // "end " - // "end " - #ifdef USE_I2C "tasmota.wire1 = Wire(1) " "tasmota.wire2 = Wire(2) "