[Feat] 实现 std.formater库,增加 std.io.printf函数
[Fix] 修复 evaluator中处理else if condVal类型错误的低级问题 [Feat] 为 String类型增加 insert, replace, erase函数
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -1037,12 +1037,15 @@ namespace Fig
|
||||
for (const auto &elif : ifSt->elifs)
|
||||
{
|
||||
ObjectPtr elifCondVal = eval(elif->condition, ctx);
|
||||
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);
|
||||
|
||||
178
src/Module/Library/std/formater/formater.fig
Normal file
178
src/Module/Library/std/formater/formater.fig
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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, {}},
|
||||
|
||||
Reference in New Issue
Block a user