[Feat] 实现 std.formater库,增加 std.io.printf函数

[Fix] 修复 evaluator中处理else if condVal类型错误的低级问题
[Feat] 为 String类型增加 insert, replace, erase函数
This commit is contained in:
2025-12-29 18:27:39 +08:00
parent cd106fc513
commit 2a455a0487
6 changed files with 335 additions and 14 deletions

View File

@@ -115,7 +115,7 @@ namespace Fig
}
i += cplen;
++ cnt;
++cnt;
}
return ch;
@@ -138,8 +138,71 @@ namespace Fig
if (cnt == index)
{
*this = FString(substr(0, i)) + src +
FString(substr(i + cplen));
*this = FString(substr(0, i)) + src + FString(substr(i + cplen));
}
i += cplen;
++cnt;
}
}
void realErase(size_t index, size_t n)
{
size_t cnt = 0;
size_t eraseStart = 0;
size_t eraseCplens = 0;
for (size_t i = 0; i < size();)
{
uint8_t cplen = 1;
if ((at(i) & 0xf8) == 0xf0)
cplen = 4;
else if ((at(i) & 0xf0) == 0xe0)
cplen = 3;
else if ((at(i) & 0xe0) == 0xc0)
cplen = 2;
if (i + cplen > size())
cplen = 1;
i += cplen;
++cnt;
if (cnt == index)
{
eraseStart = i;
}
if (cnt < index + n)
{
eraseCplens += cplen;
}
}
erase(eraseStart, eraseCplens);
}
void realInsert(size_t index, const FString &src)
{
if (index == length())
{
for (auto &c : src)
{
push_back(c);
}
return;
}
size_t cnt = 0;
for (size_t i = 0; i < size();)
{
uint8_t cplen = 1;
if ((at(i) & 0xf8) == 0xf0)
cplen = 4;
else if ((at(i) & 0xf0) == 0xe0)
cplen = 3;
else if ((at(i) & 0xe0) == 0xc0)
cplen = 2;
if (i + cplen > size())
cplen = 1;
if (cnt == index)
{
insert(i, src);
}
i += cplen;

View File

@@ -1037,12 +1037,15 @@ namespace Fig
for (const auto &elif : ifSt->elifs)
{
ObjectPtr elifCondVal = eval(elif->condition, ctx);
throw EvaluatorError(
u8"TypeError",
std::format(
"Condition must be boolean, but got '{}'",
condVal->getTypeInfo().toString().toBasicString()),
ifSt->condition);
if (elifCondVal->getTypeInfo() != ValueType::Bool)
{
throw EvaluatorError(
u8"TypeError",
std::format(
"Condition must be boolean, but got '{}'",
condVal->getTypeInfo().toString().toBasicString()),
ifSt->condition);
}
if (elifCondVal->as<ValueType::BoolClass>())
{
return evalBlockStatement(elif->body, ctx);

View File

@@ -0,0 +1,178 @@
/*
Official Module `std.formater`
Library/std/formater/formater.fig
*/
import std.value; // `type` function and string_from
public func format(objects ...) -> Any
{
if objects.length() < 1
{
return null;
}
var fmt := objects[0];
if value.type(fmt) != "String"
{
return null;
}
var result := "";
var argIndex := 1;
var i := 0;
var length := fmt.length();
while (i < length)
{
var char := fmt[i];
if char == "{"
{
if (i + 1 >= length)
{
return null;
}
var nextChar = fmt[i + 1];
if nextChar == "{"
{
result += "{";
i += 2;
continue;
}
var endIndex := -1;
for var j = i + 1; j < length; j += 1
{
if fmt[j] == "}"
{
endIndex = j;
break;
}
}
if endIndex == -1
{
return null;
}
if argIndex >= objects.length()
{
return null;
}
result += value.string_from(objects[argIndex]);
argIndex += 1;
i = endIndex + 1;
}
else if char == "}"
{
if i + 1 < length && fmt[i + 1] == "}"
{
result += "}";
i += 2;
continue;
}
return null;
}
else
{
result += char;
i += 1;
}
}
return result;
}
public func formatByListArgs(objects) -> Any
{
if value.type(objects) != "List"
{
return null;
}
if objects.length() < 1
{
return null;
}
var fmt := objects[0];
if value.type(fmt) != "String"
{
return null;
}
var result := "";
var argIndex := 1;
var i := 0;
var length := fmt.length();
while (i < length)
{
var char := fmt[i];
if char == "{"
{
if (i + 1 >= length)
{
return null;
}
var nextChar = fmt[i + 1];
if nextChar == "{"
{
result += "{";
i += 2;
continue;
}
var endIndex := -1;
for var j = i + 1; j < length; j += 1
{
if fmt[j] == "}"
{
endIndex = j;
break;
}
}
if endIndex == -1
{
return null;
}
if argIndex >= objects.length()
{
return null;
}
result += value.string_from(objects[argIndex]);
argIndex += 1;
i = endIndex + 1;
}
else if char == "}"
{
if i + 1 < length && fmt[i + 1] == "}"
{
result += "}";
i += 2;
continue;
}
return null;
}
else
{
result += char;
i += 1;
}
}
return result;
}

View File

@@ -6,6 +6,8 @@
import _builtins;
import noSpace; // sub module `no space print`
import std.formater; // format
// outputs
public func print(objects...) -> Int
@@ -37,6 +39,11 @@ public func println(objects...) -> Int
return length + 1;
}
public func printf(objects...) -> Any
{
__fstdout_print(formater.formatByListArgs(objects));
}
// inputs
public func read() -> String

View File

@@ -151,7 +151,7 @@ namespace Fig
}},
{u8"__fvalue_string_from", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
ObjectPtr val = args[0];
return std::make_shared<Object>(val->toString());
return std::make_shared<Object>(val->toStringIO());
}},
/* math start */
{u8"__fmath_acos", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {

View File

@@ -78,7 +78,76 @@ namespace Fig
const FString &str = as<ValueType::StringClass>();
return std::make_shared<Object>(static_cast<ValueType::IntClass>(str.length()));
}},
{u8"replace", [this](std::vector<ObjectPtr> args) -> ObjectPtr {
if (args.size() != 2)
throw RuntimeError(FString(
std::format("`replace` expects 2 arguments, {} got", args.size())));
FString &str = as<ValueType::StringClass>();
ObjectPtr arg1 = args[0];
ObjectPtr arg2 = args[1];
if (!arg1->is<ValueType::IntClass>())
{
throw RuntimeError(FString(
"`replace` arg 1 expects type Int"));
}
if (!arg2->is<ValueType::StringClass>())
{
throw RuntimeError(FString(
"`replace` arg 2 expects type String"));
}
str.realReplace(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::StringClass>());
return Object::getNullInstance();
}},
{u8"erase", [this](std::vector<ObjectPtr> args) -> ObjectPtr {
if (args.size() != 2)
throw RuntimeError(FString(
std::format("`erase` expects 2 arguments, {} got", args.size())));
FString &str = as<ValueType::StringClass>();
ObjectPtr arg1 = args[0];
ObjectPtr arg2 = args[1];
if (!arg1->is<ValueType::IntClass>())
{
throw RuntimeError(FString(
"`erase` arg 1 expects type Int"));
}
if (!arg2->is<ValueType::IntClass>())
{
throw RuntimeError(FString(
"`erase` arg 2 expects type Int"));
}
ValueType::IntClass index = arg1->as<ValueType::IntClass>();
ValueType::IntClass n = arg2->as<ValueType::IntClass>();
if (index < 0 || n < 0)
{
throw RuntimeError(FString("`erase`: index and n must greater or equal to 0"));
}
if (index + n > str.length())
{
throw RuntimeError(FString("`erase`: length is not long enough to erase"));
}
str.realErase(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::IntClass>());
return Object::getNullInstance();
}},
{u8"insert", [this](std::vector<ObjectPtr> args) -> ObjectPtr {
if (args.size() != 2)
throw RuntimeError(FString(
std::format("`insert` expects 2 arguments, {} got", args.size())));
FString &str = as<ValueType::StringClass>();
ObjectPtr arg1 = args[0];
ObjectPtr arg2 = args[1];
if (!arg1->is<ValueType::IntClass>())
{
throw RuntimeError(FString(
"`insert` arg 1 expects type Int"));
}
if (!arg2->is<ValueType::StringClass>())
{
throw RuntimeError(FString(
"`insert` arg 2 expects type String"));
}
str.realInsert(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::StringClass>());
return Object::getNullInstance();
}},
}},
{ValueType::Function, {}},
{ValueType::StructType, {}},
@@ -136,15 +205,16 @@ namespace Fig
map.contains(index));
}},
}},
{ValueType::Module, {}}
};
{ValueType::Module, {}}};
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
{ValueType::Null, {}},
{ValueType::Int, {}},
{ValueType::Double, {}},
{ValueType::String, {
{u8"length", 0},
{u8"replace", 2},
{u8"erase", 2},
{u8"insert", 2},
}},
{ValueType::Function, {}},
{ValueType::StructType, {}},