diff --git a/CHANGELOG.md b/CHANGELOG.md index 89398a06c..03c019944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - Matter add controller's Vendor Name to logs and UI - Matter redesigned UI - Matter add support for Contact Sensor +- Berry `string.format()` now automatically converts type according to format ### Breaking Changed diff --git a/lib/libesp32/berry/src/be_baselib.c b/lib/libesp32/berry/src/be_baselib.c index 592d74a53..ba366c12b 100644 --- a/lib/libesp32/berry/src/be_baselib.c +++ b/lib/libesp32/berry/src/be_baselib.c @@ -18,7 +18,7 @@ #define READLINE_STEP 100 -static int l_assert(bvm *vm) +int be_baselib_assert(bvm *vm) { int argc = be_top(vm); /* assertion fails when there is no argument @@ -33,7 +33,7 @@ static int l_assert(bvm *vm) be_return_nil(vm); } -static int l_print(bvm *vm) +int be_baselib_print(bvm *vm) { int i, argc = be_top(vm); for (i = 1; i <= argc; ++i) { @@ -68,7 +68,7 @@ static int m_readline(bvm *vm) be_return(vm); } -static int l_input(bvm *vm) +int be_baselib_input(bvm *vm) { if (be_top(vm) && be_isstring(vm, 1)) { /* echo prompt */ be_writestring(be_tostring(vm, 1)); @@ -118,7 +118,7 @@ static bbool obj2int(bvm *vm, bvalue *var, bint *val) return bfalse; } -static int l_super(bvm *vm) +int be_baselib_super(bvm *vm) { int argc = be_top(vm); @@ -197,7 +197,7 @@ static int l_super(bvm *vm) be_return_nil(vm); } -static int l_type(bvm *vm) +int be_baselib_type(bvm *vm) { if (be_top(vm)) { be_pushstring(vm, be_typename(vm, 1)); @@ -206,7 +206,7 @@ static int l_type(bvm *vm) be_return_nil(vm); } -static int l_classname(bvm *vm) +int be_baselib_classname(bvm *vm) { if (be_top(vm)) { const char *t = be_classname(vm, 1); @@ -218,7 +218,7 @@ static int l_classname(bvm *vm) be_return_nil(vm); } -static int l_classof(bvm *vm) +int be_baselib_classof(bvm *vm) { if (be_top(vm) && be_classof(vm, 1)) { be_return(vm); @@ -226,7 +226,7 @@ static int l_classof(bvm *vm) be_return_nil(vm); } -static int l_number(bvm *vm) +int be_baselib_number(bvm *vm) { if (be_top(vm)) { if (be_isstring(vm, 1)) { @@ -240,7 +240,7 @@ static int l_number(bvm *vm) be_return_nil(vm); } -static int l_int(bvm *vm) +int be_baselib_int(bvm *vm) { if (be_top(vm)) { if (be_isstring(vm, 1)) { @@ -272,7 +272,7 @@ static int l_int(bvm *vm) be_return_nil(vm); } -static int l_real(bvm *vm) +int be_baselib_real(bvm *vm) { if (be_top(vm)) { if (be_isstring(vm, 1)) { @@ -296,7 +296,7 @@ static int check_method(bvm *vm, const char *attr) be_isinstance(vm, 1) && be_getmethod(vm, 1, attr); } -static int l_iterator(bvm *vm) +int be_baselib_iterator(bvm *vm) { if (be_top(vm) && be_isfunction(vm, 1)) { be_return(vm); /* return the argument[0]::function */ @@ -357,7 +357,7 @@ static int l_call(bvm *vm) be_return_nil(vm); } -static int l_str(bvm *vm) +int be_baselib_str(bvm *vm) { if (be_top(vm)) { be_tostring(vm, 1); @@ -378,7 +378,7 @@ static int l_bool(bvm *vm) } -static int l_size(bvm *vm) +int be_baselib_size(bvm *vm) { if (be_top(vm) && be_isstring(vm, 1)) { be_pushint(vm, be_strlen(vm, 1)); @@ -393,7 +393,7 @@ static int l_size(bvm *vm) be_return_nil(vm); } -static int l_module(bvm *vm) +int be_baselib_module(bvm *vm) { int argc = be_top(vm); be_newmodule(vm); @@ -436,7 +436,7 @@ static int m_compile_file(bvm *vm) } #endif -static int l_compile(bvm *vm) +int be_baselib_compile(bvm *vm) { #if BE_USE_SCRIPT_COMPILER if (be_top(vm) && be_isstring(vm, 1)) { @@ -467,12 +467,12 @@ static int _issubv(bvm *vm, bbool (*filter)(bvm*, int)) be_return(vm); } -static int l_issubclass(bvm *vm) +int be_baselib_issubclass(bvm *vm) { return _issubv(vm, be_isclass); } -static int l_isinstance(bvm *vm) +int be_baselib_isinstance(bvm *vm) { return _issubv(vm, be_isinstance); } @@ -480,23 +480,23 @@ static int l_isinstance(bvm *vm) #if !BE_USE_PRECOMPILED_OBJECT void be_load_baselib(bvm *vm) { - be_regfunc(vm, "assert", l_assert); - be_regfunc(vm, "print", l_print); - be_regfunc(vm, "input", l_input); - be_regfunc(vm, "super", l_super); - be_regfunc(vm, "type", l_type); - be_regfunc(vm, "classname", l_classname); - be_regfunc(vm, "classof", l_classof); - be_regfunc(vm, "number", l_number); - be_regfunc(vm, "str", l_str); - be_regfunc(vm, "int", l_int); - be_regfunc(vm, "real", l_real); - be_regfunc(vm, "module", l_module); - be_regfunc(vm, "size", l_size); - be_regfunc(vm, "compile", l_compile); - be_regfunc(vm, "issubclass", l_issubclass); - be_regfunc(vm, "isinstance", l_isinstance); - be_regfunc(vm, "__iterator__", l_iterator); + be_regfunc(vm, "assert", be_baselib_assert); + be_regfunc(vm, "print", be_baselib_print); + be_regfunc(vm, "input", be_baselib_input); + be_regfunc(vm, "super", be_baselib_super); + be_regfunc(vm, "type", be_baselib_type); + be_regfunc(vm, "classname", be_baselib_classname); + be_regfunc(vm, "classof", be_baselib_classof); + be_regfunc(vm, "number", be_baselib_number); + be_regfunc(vm, "str", be_baselib_str); + be_regfunc(vm, "int", be_baselib_int); + be_regfunc(vm, "real", be_baselib_real); + be_regfunc(vm, "module", be_baselib_module); + be_regfunc(vm, "size", be_baselib_size); + be_regfunc(vm, "compile", be_baselib_compile); + be_regfunc(vm, "issubclass", be_baselib_issubclass); + be_regfunc(vm, "isinstance", be_baselib_isinstance); + be_regfunc(vm, "__iterator__", be_baselib_iterator); } /* call must be added later to respect order of builtins */ @@ -513,23 +513,23 @@ extern const bclass be_class_bytes; extern int be_nfunc_open(bvm *vm); /* @const_object_info_begin vartab m_builtin (scope: local) { - assert, func(l_assert) - print, func(l_print) - input, func(l_input) - super, func(l_super) - type, func(l_type) - classname, func(l_classname) - classof, func(l_classof) - number, func(l_number) - str, func(l_str) - int, func(l_int) - real, func(l_real) - module, func(l_module) - size, func(l_size) - compile, func(l_compile) - issubclass, func(l_issubclass) - isinstance, func(l_isinstance) - __iterator__, func(l_iterator) + assert, func(be_baselib_assert) + print, func(be_baselib_print) + input, func(be_baselib_input) + super, func(be_baselib_super) + type, func(be_baselib_type) + classname, func(be_baselib_classname) + classof, func(be_baselib_classof) + number, func(be_baselib_number) + str, func(be_baselib_str) + int, func(be_baselib_int) + real, func(be_baselib_real) + module, func(be_baselib_module) + size, func(be_baselib_size) + compile, func(be_baselib_compile) + issubclass, func(be_baselib_issubclass) + isinstance, func(be_baselib_isinstance) + __iterator__, func(be_baselib_iterator) open, func(be_nfunc_open) list, class(be_class_list) map, class(be_class_map) diff --git a/lib/libesp32/berry/src/be_baselib.h b/lib/libesp32/berry/src/be_baselib.h new file mode 100644 index 000000000..582b0871b --- /dev/null +++ b/lib/libesp32/berry/src/be_baselib.h @@ -0,0 +1,31 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#ifndef __BE_BASELIB_H +#define __BE_BASELIB_H + +#include "be_object.h" + +int be_baselib_assert(bvm *vm); +int be_baselib_print(bvm *vm); +int be_baselib_input(bvm *vm); +int be_baselib_super(bvm *vm); +int be_baselib_type(bvm *vm); +int be_baselib_classname(bvm *vm); +int be_baselib_classof(bvm *vm); +int be_baselib_number(bvm *vm); +int be_baselib_str(bvm *vm); +int be_baselib_int(bvm *vm); +int be_baselib_real(bvm *vm); +int be_baselib_module(bvm *vm); +int be_baselib_size(bvm *vm); +int be_baselib_compile(bvm *vm); +int be_baselib_issubclass(bvm *vm); +int be_baselib_isinstance(bvm *vm); +int be_baselib_iterator(bvm *vm); + +#endif diff --git a/lib/libesp32/berry/src/be_strlib.c b/lib/libesp32/berry/src/be_strlib.c index 2c5424634..4172876e6 100644 --- a/lib/libesp32/berry/src/be_strlib.c +++ b/lib/libesp32/berry/src/be_strlib.c @@ -12,6 +12,7 @@ #include "be_module.h" #include "be_exec.h" #include "be_mem.h" +#include "be_baselib.h" #include #include #include @@ -556,6 +557,48 @@ static void mode_fixlen(char *mode, const char *lenmode) mode[l + lm] = '\0'; } +static bbool convert_to_int(bvm *vm, int index, bint *val) +{ + bbool converted = bfalse; + if (val == NULL) { return bfalse; } + if (be_isint(vm, index)) { + *val = be_toint(vm, index); + converted = btrue; + } else { + be_pushntvfunction(vm, be_baselib_int); + be_pushvalue(vm, index); + be_call(vm, 1); + be_pop(vm, 1); + if (be_isint(vm, -1)) { + *val = be_toint(vm, -1); + converted = btrue; + } + be_pop(vm, 1); + } + return converted; +} + +static bbool convert_to_real(bvm *vm, int index, breal *val) +{ + bbool converted = bfalse; + if (val == NULL) { return bfalse; } + if (be_isnumber(vm, index)) { + *val = be_toreal(vm, index); + converted = btrue; + } else { + be_pushntvfunction(vm, be_baselib_real); + be_pushvalue(vm, index); + be_call(vm, 1); + be_pop(vm, 1); + if (be_isnumber(vm, -1)) { + *val = be_toreal(vm, -1); + converted = btrue; + } + be_pop(vm, 1); + } + return converted; +} + static int str_format(bvm *vm) { int top = be_top(vm); @@ -585,25 +628,34 @@ static int str_format(bvm *vm) break; case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': - if (be_isint(vm, index)) { + { + bint val; + if (convert_to_int(vm, index, &val)) { mode_fixlen(mode, BE_INT_FMTLEN); - sprintf(buf, mode, be_toint(vm, index)); + sprintf(buf, mode, val); } be_pushstring(vm, buf); break; + } case 'e': case 'E': case 'f': case 'g': case 'G': - if (be_isnumber(vm, index)) { - sprintf(buf, mode, be_toreal(vm, index)); + { + breal val; + if (convert_to_real(vm, index, &val)) { + sprintf(buf, mode, val); } be_pushstring(vm, buf); break; + } case 'c': - if (be_isint(vm, index)) { - sprintf(buf, "%c", (int)be_toint(vm, index)); + { + bint val; + if (convert_to_int(vm, index, &val)) { + sprintf(buf, "%c", (int)val); } be_pushstring(vm, buf); break; + } case 's': { const char *s = be_tostring(vm, index); int len = be_strlen(vm, index); diff --git a/lib/libesp32/berry/tests/string.be b/lib/libesp32/berry/tests/string.be index e7d91e8dd..072e5faa7 100644 --- a/lib/libesp32/berry/tests/string.be +++ b/lib/libesp32/berry/tests/string.be @@ -110,3 +110,40 @@ s = "a"# "b" # zz "c" assert(s == 'abc') + +# string.format with automatic conversion +import string + +assert(string.format("%i", 3) == '3') +assert(string.format("%i", "3") == '3') +assert(string.format("%i", "03") == '3') +assert(string.format("%i", nil) == '') + +class A def toint() return 42 end end +a=A() +class B end +b=B() + +assert(string.format("%i", a) == '42') +assert(string.format("%i", b) == '') + +assert(string.format("%i", nil) == '') +assert(string.format("%i", true) == '1') +assert(string.format("%i", false) == '0') + +assert(string.format("%c", a) == '*') + +assert(string.format("%f", 3.5) == '3.500000') +assert(string.format("%f", 3) == '3.000000') +assert(string.format("%.1f", 3) == '3.0') +assert(string.format("%.1f", nil) == '') +assert(string.format("%.1f", true) == '') +assert(string.format("%.1f", false) == '') +assert(string.format("%.1f", a) == '') + +assert(string.format("%s", a) == '') +assert(string.format("%s", 0) == '0') +assert(string.format("%s", nil) == 'nil') +assert(string.format("%s", true) == 'true') +assert(string.format("%s", false) == 'false') +