mirror of
https://github.com/arendst/Tasmota.git
synced 2025-04-25 15:27:17 +00:00
Berry string.format()
now automatically converts type according to format (#18890)
This commit is contained in:
parent
28861821a6
commit
3fc932d38a
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
31
lib/libesp32/berry/src/be_baselib.h
Normal file
31
lib/libesp32/berry/src/be_baselib.h
Normal file
@ -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
|
@ -12,6 +12,7 @@
|
||||
#include "be_module.h"
|
||||
#include "be_exec.h"
|
||||
#include "be_mem.h"
|
||||
#include "be_baselib.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
@ -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);
|
||||
|
@ -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) == '<instance: 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')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user