[Feat] 实现 std.formater库,增加 std.io.printf函数
[Fix] 修复 evaluator中处理else if condVal类型错误的低级问题 [Feat] 为 String类型增加 insert, replace, erase函数
This commit is contained in:
@@ -115,7 +115,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
i += cplen;
|
i += cplen;
|
||||||
++ cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
@@ -138,8 +138,71 @@ namespace Fig
|
|||||||
|
|
||||||
if (cnt == index)
|
if (cnt == index)
|
||||||
{
|
{
|
||||||
*this = FString(substr(0, i)) + src +
|
*this = FString(substr(0, i)) + src + FString(substr(i + cplen));
|
||||||
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;
|
i += cplen;
|
||||||
|
|||||||
@@ -1037,12 +1037,15 @@ namespace Fig
|
|||||||
for (const auto &elif : ifSt->elifs)
|
for (const auto &elif : ifSt->elifs)
|
||||||
{
|
{
|
||||||
ObjectPtr elifCondVal = eval(elif->condition, ctx);
|
ObjectPtr elifCondVal = eval(elif->condition, ctx);
|
||||||
throw EvaluatorError(
|
if (elifCondVal->getTypeInfo() != ValueType::Bool)
|
||||||
u8"TypeError",
|
{
|
||||||
std::format(
|
throw EvaluatorError(
|
||||||
"Condition must be boolean, but got '{}'",
|
u8"TypeError",
|
||||||
condVal->getTypeInfo().toString().toBasicString()),
|
std::format(
|
||||||
ifSt->condition);
|
"Condition must be boolean, but got '{}'",
|
||||||
|
condVal->getTypeInfo().toString().toBasicString()),
|
||||||
|
ifSt->condition);
|
||||||
|
}
|
||||||
if (elifCondVal->as<ValueType::BoolClass>())
|
if (elifCondVal->as<ValueType::BoolClass>())
|
||||||
{
|
{
|
||||||
return evalBlockStatement(elif->body, ctx);
|
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 _builtins;
|
||||||
import noSpace; // sub module `no space print`
|
import noSpace; // sub module `no space print`
|
||||||
|
|
||||||
|
import std.formater; // format
|
||||||
|
|
||||||
// outputs
|
// outputs
|
||||||
|
|
||||||
public func print(objects...) -> Int
|
public func print(objects...) -> Int
|
||||||
@@ -37,6 +39,11 @@ public func println(objects...) -> Int
|
|||||||
return length + 1;
|
return length + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func printf(objects...) -> Any
|
||||||
|
{
|
||||||
|
__fstdout_print(formater.formatByListArgs(objects));
|
||||||
|
}
|
||||||
|
|
||||||
// inputs
|
// inputs
|
||||||
|
|
||||||
public func read() -> String
|
public func read() -> String
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ namespace Fig
|
|||||||
}},
|
}},
|
||||||
{u8"__fvalue_string_from", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
{u8"__fvalue_string_from", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||||
ObjectPtr val = args[0];
|
ObjectPtr val = args[0];
|
||||||
return std::make_shared<Object>(val->toString());
|
return std::make_shared<Object>(val->toStringIO());
|
||||||
}},
|
}},
|
||||||
/* math start */
|
/* math start */
|
||||||
{u8"__fmath_acos", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
{u8"__fmath_acos", [](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||||
|
|||||||
@@ -78,7 +78,76 @@ namespace Fig
|
|||||||
const FString &str = as<ValueType::StringClass>();
|
const FString &str = as<ValueType::StringClass>();
|
||||||
return std::make_shared<Object>(static_cast<ValueType::IntClass>(str.length()));
|
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::Function, {}},
|
||||||
{ValueType::StructType, {}},
|
{ValueType::StructType, {}},
|
||||||
@@ -136,15 +205,16 @@ namespace Fig
|
|||||||
map.contains(index));
|
map.contains(index));
|
||||||
}},
|
}},
|
||||||
}},
|
}},
|
||||||
{ValueType::Module, {}}
|
{ValueType::Module, {}}};
|
||||||
};
|
|
||||||
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
|
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
|
||||||
{ValueType::Null, {}},
|
{ValueType::Null, {}},
|
||||||
{ValueType::Int, {}},
|
{ValueType::Int, {}},
|
||||||
{ValueType::Double, {}},
|
{ValueType::Double, {}},
|
||||||
{ValueType::String, {
|
{ValueType::String, {
|
||||||
{u8"length", 0},
|
{u8"length", 0},
|
||||||
|
{u8"replace", 2},
|
||||||
|
{u8"erase", 2},
|
||||||
|
{u8"insert", 2},
|
||||||
}},
|
}},
|
||||||
{ValueType::Function, {}},
|
{ValueType::Function, {}},
|
||||||
{ValueType::StructType, {}},
|
{ValueType::StructType, {}},
|
||||||
|
|||||||
Reference in New Issue
Block a user