#include "daScript/misc/platform.h"
#include "daScript/simulate/runtime_string.h"
#include "daScript/simulate/aot_builtin_string.h"
#include "daScript/simulate/simulate.h"
#include "daScript/simulate/aot.h"
#include "daScript/simulate/debug_print.h"
#include "daScript/simulate/runtime_string_delete.h"
#include "daScript/simulate/simulate_nodes.h"
#include "daScript/simulate/sim_policy.h"
#include "misc/include_fmt.h"
namespace das
{
#if (!defined(DAS_ENABLE_EXCEPTIONS)) || (!DAS_ENABLE_EXCEPTIONS)
DAS_THREAD_LOCAL(jmp_buf *) g_throwBuf;
DAS_THREAD_LOCAL(string) g_throwMsg;
void das_throw(const char * msg) {
if ( *g_throwBuf ) {
*g_throwMsg = msg;
longjmp(**g_throwBuf,1);
} else {
DAS_FATAL_ERROR("unhanded das_throw, %s\n", msg);
}
}
void das_trycatch(callable tryBody, callable catchBody) {
DAS_ASSERTF(*g_throwBuf==nullptr, "das_trycatch without g_throwBuf");
jmp_buf ev;
*g_throwBuf = &ev;
if ( !setjmp(ev) ) {
tryBody();
} else {
*g_throwBuf = nullptr;
catchBody(g_throwMsg->c_str());
}
*g_throwBuf = nullptr;
}
#endif
template
__forceinline StringBuilderWriter & fmt_and_write_T ( StringBuilderWriter & writer, const char * fmt, TT value, Context * context, LineInfoArg * at ) {
char ffmt[64] = "{";
char buf[256];
char * head = ffmt + 1;
if ( fmt ) {
char * tail = ffmt + 61;
while ( head= sizeof(buf) ) {
context->throw_error_at(at, "fmt overflow, output truncated to %d characters", int(sizeof(buf)-1));
}
} catch ( const std::exception & e ) {
context->throw_error_at(at, "fmt error: %s", e.what());
}
#else
das_trycatch([&]{
auto result = fmt::format_to_n(buf, sizeof(buf)-1, fmt::runtime(ffmt), value);
auto len = result.size < sizeof(buf) ? result.size : sizeof(buf)-1;
buf[len] = 0;
writer.writeStr(buf, len);
if ( result.size >= sizeof(buf) ) {
context->throw_error_at(at, "fmt overflow, output truncated to %d characters", int(sizeof(buf)-1));
}
},[&](const char * e){
context->throw_error_at(at, "fmt error: %s", e);
});
#endif
return writer;
}
StringBuilderWriter & fmt_and_write_i8 ( StringBuilderWriter & writer, const char * fmt, int8_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_u8 ( StringBuilderWriter & writer, const char * fmt, uint8_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_i16 ( StringBuilderWriter & writer, const char * fmt, int16_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_u16 ( StringBuilderWriter & writer, const char * fmt, uint16_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_i32 ( StringBuilderWriter & writer, const char * fmt, int32_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_u32 ( StringBuilderWriter & writer, const char * fmt, uint32_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_i64 ( StringBuilderWriter & writer, const char * fmt, int64_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_u64 ( StringBuilderWriter & writer, const char * fmt, uint64_t value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_f ( StringBuilderWriter & writer, const char * fmt, float value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
StringBuilderWriter & fmt_and_write_d ( StringBuilderWriter & writer, const char * fmt, double value, Context * context, LineInfoArg * at ) {
return fmt_and_write_T(writer, fmt, value, context, at);
}
template
__forceinline char * fmt_T ( const char * fmt, TT value, Context * context, LineInfoArg * at ) {
char ffmt[64] = "{";
char buf[256];
char * head = ffmt + 1;
if ( fmt ) {
char * tail = ffmt + 61;
while ( head= sizeof(buf) ) {
context->throw_error_at(at, "fmt overflow, output truncated to %d characters", int(sizeof(buf)-1));
}
return context->allocateString(buf, uint32_t(len), at);
} catch (const std::exception & e) {
context->throw_error_at(at, "fmt error: %s", e.what());
return nullptr;
}
#else
char * return_value = nullptr;
das_trycatch([&]{
auto result = fmt::format_to_n(buf, sizeof(buf)-1, fmt::runtime(ffmt), value);
auto len = result.size < sizeof(buf) ? result.size : sizeof(buf)-1;
buf[len] = 0;
if ( result.size >= sizeof(buf) ) {
context->throw_error_at(at, "fmt overflow, output truncated to %d characters", int(sizeof(buf)-1));
}
return_value = context->allocateString(buf, uint32_t(len), at);
},[&](const char * e){
context->throw_error_at(at, "fmt error: %s", e);
});
return return_value;
#endif
}
char * fmt_i8 ( const char * fmt, int8_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_u8 ( const char * fmt, uint8_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_i16 ( const char * fmt, int16_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_u16 ( const char * fmt, uint16_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_i32 ( const char * fmt, int32_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_u32 ( const char * fmt, uint32_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_i64 ( const char * fmt, int64_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_u64 ( const char * fmt, uint64_t value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_f ( const char * fmt, float value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
char * fmt_d ( const char * fmt, double value, Context * context, LineInfoArg * at ) {
return fmt_T(fmt, value, context, at);
}
template
__forceinline char * das_lexical_cast_int_T ( TT x, bool hex, Context * __context__, LineInfoArg * at ) {
char buffer[128];
char * result;
if ( hex ) {
result = fmt::format_to(buffer,FMT_STRING("{:#x}"),x);
} else {
result = fmt::format_to(buffer,FMT_STRING("{}"),x);
}
*result = 0;
return __context__->allocateString(buffer,uint32_t(result-buffer),at);
}
char * das_lexical_cast_int_i8 ( int8_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_u8 ( uint8_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_i16 ( int16_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_u16 ( uint16_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_i32 ( int32_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_u32 ( uint32_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_i64 ( int64_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
char * das_lexical_cast_int_u64 ( uint64_t x, bool hex, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_int_T(x, hex, __context__, at);
}
template
__forceinline char * das_lexical_cast_fp_T ( TT x, Context * __context__, LineInfoArg * at ) {
char buffer[128];
auto result = fmt::format_to(buffer,FMT_STRING("{}"),x);
*result = 0;
return __context__->allocateString(buffer,uint32_t(result-buffer),at);
}
char * das_lexical_cast_fp_f ( float x, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_fp_T(x, __context__, at);
}
char * das_lexical_cast_fp_d ( double x, Context * __context__, LineInfoArg * at ) {
return das_lexical_cast_fp_T(x, __context__, at);
}
// string operations
vec4f SimPolicy_String::Add ( vec4f a, vec4f b, Context & context, LineInfo * at ) {
const char * sA = to_rts(a);
auto la = stringLength(context, sA);
const char * sB = to_rts(b);
auto lb = stringLength(context, sB);
uint32_t commonLength = la + lb;
if ( !commonLength ) {
return v_zero();
} else if ( char * sAB = (char * ) context.allocateString(nullptr, commonLength, at) ) {
memcpy ( sAB, sA, la );
memcpy ( sAB+la, sB, lb+1 );
context.stringHeap->recognize(sAB);
return cast::from(sAB);
} else {
context.throw_out_of_memory(true, commonLength, at);
return v_zero();
}
}
void SimPolicy_String::SetAdd ( char * a, vec4f b, Context & context, LineInfo * at ) {
char ** pA = (char **)a;
const char * sA = *pA ? *pA : rts_null;
auto la = stringLength(context, sA);
const char * sB = to_rts(b);
auto lb = stringLength(context, sB);
uint32_t commonLength = la + lb;
if ( !commonLength ) {
// *pA = nullptr; is unnecessary, because its already nullptr
return;
} else if ( char * sAB = (char * ) context.allocateString(nullptr, commonLength, at) ) {
memcpy ( sAB, sA, la );
memcpy ( sAB+la, sB, lb+1 );
*pA = sAB;
context.stringHeap->recognize(sAB);
} else {
context.throw_out_of_memory(true, commonLength, at);
}
}
// helper functions
DAS_API const char * rts_null = "";
static int hexChar ( char ch ) {
if ( ch>='a' && ch='A' && ch='0' && ch 12) | 0xE0);
result[1] = char(((ch >> 6) & 0x3F) | 0x80);
result[2] = char(((ch >> 0) & 0x3F) | 0x80);
result[3] = 0;
return true;
}
if (ch > 18) | 0xF0);
result[1] = char(((ch >> 12) & 0x3F) | 0x80);
result[2] = char(((ch >> 6) & 0x3F) | 0x80);
result[3] = char(((ch >> 0) & 0x3F) | 0x80);
result[4] = 0;
return true;
}
if (ch > 24) | 0xF8);
result[1] = char(((ch >> 18) & 0x3F) | 0x80);
result[2] = char(((ch >> 12) & 0x3F) | 0x80);
result[3] = char(((ch >> 6) & 0x3F) | 0x80);
result[4] = char(((ch >> 0) & 0x3F) | 0x80);
result[5] = 0;
return true;
}
if (ch > 30) | 0xFC);
result[1] = char(((ch >> 24) & 0x3F) | 0x80);
result[2] = char(((ch >> 18) & 0x3F) | 0x80);
result[3] = char(((ch >> 12) & 0x3F) | 0x80);
result[4] = char(((ch >> 6) & 0x3F) | 0x80);
result[5] = char(((ch >> 0) & 0x3F) | 0x80);
result[6] = 0;
return true;
}
result[0] = '?';
result[1] = 0;
return false;
}
string unescapeString ( const string & input, bool * error, bool ) {
if ( error ) *error = false;
const char* str = input.c_str();
const char* strEnd = str + input.length();
string result;
result.reserve(input.size());
for( ; str < strEnd; ++str ) {
if ( *str=='\\' ) {
++str;
if ( str == strEnd ) {
if ( error ) *error = true;
return result; // invalid escape sequence
}
switch ( *str ) {
case '"':
case '/':
case '\\': result += *str; break;
case 'b': result += '\b'; break;
case 'f': result += '\f'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
case 'v': result += '\v'; break;
case '\n': break; // skip LF
case '{': result += '{'; break;
case '}': result += '}'; break;
case '\r': if ( str+1!=strEnd && str[1]=='\n' ) str++; break; // skip CR LF or just CR
case 'x':
case 'u':
case 'U': {
int symbols = (*str == 'x') ? 2 : (*str == 'u') ? 4 : 8;
uint32_t charCode = 0;
int x = 0;
str++;
for (; x < symbols && str != strEnd; x++, str++) {
int h = hexChar(*str);
if (h < 0)
break;
charCode = charCode * 16 + h;
}
str--;
if (symbols == 2) { // \xNN
if (!x) {
if (error) *error = true;
}
else
result += char(charCode);
}
else if (x != symbols) { // \u \U requires exactly 4 or 8 hex symbols
if (error) *error = true;
}
else {
char buf[8];
if (!encodeUtf8Char(charCode, buf) && error)
*error = true;
result += buf;
}
}
break;
default: result += *str; if ( error ) *error = true; break; // invalid escape character
}
} else
result += *str;
}
return result;
}
string escapeString ( const string & input, bool das_escape ) {
const char* str = input.c_str();
const char* strEnd = str + input.length();
string result;
result.reserve(input.size());
for( ; str < strEnd; ++str ) {
auto ch = uint8_t(*str);
switch ( ch ) {
case '\"': result.append("\\\""); break;
case '\\': result.append("\\\\"); break;
case '\b': result.append("\\b"); break;
case '\v': result.append("\\v"); break;
case '\f': result.append("\\f"); break;
case '\n': result.append("\\n"); break;
case '\r': result.append("\\r"); break;
case '\t': result.append("\\t"); break;
case '{': if (das_escape) result.append("\\{"); else result.append("{"); break;
case '}': if (das_escape) result.append("\\}"); else result.append("}"); break;
default:
if ( ch >4]);
result.append(1,tohex[ch&15]);
} else {
result.append(1, ch);
}
break;
}
}
return result;
}
static string getFewLines ( const char* st, uint32_t stlen, int ROW, int COL, int /*LROW*/, int LCOL, int TAB ) {
TextWriter text;
int col=0, row=1;
auto it = st;
auto itend = st + stlen;
if ( ROW>1 ) {
while ( it!=itend && *it ) {
auto CH = *it++;
if ( CH=='\n' ) {
row++;
col=0;
if ( row==ROW ) break;
}
}
}
if ( row!=ROW ) return "";
auto beginOfLine = it;
for (;;) {
if (it == itend || *it == 0)
{
text