Berry string.format() now automatically converts type according to format (#18890)

This commit is contained in:
s-hadinger 2023-06-16 20:38:53 +02:00 committed by GitHub
parent 28861821a6
commit 3fc932d38a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 178 additions and 57 deletions

View File

@ -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

View File

@ -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)

View 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

View File

@ -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);

View File

@ -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')