#include "daScript/misc/platform.h"
#include "daScript/simulate/runtime_string.h"
#include "daScript/simulate/simulate.h"
#include "daScript/simulate/hash.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"
namespace das
{
// 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.stringHeap->allocateString(nullptr, commonLength) ) {
memcpy ( sAB, sA, la );
memcpy ( sAB+la, sB, lb+1 );
context.stringHeap->recognize(sAB);
return cast::from(sAB);
} else {
context.throw_error_at(at, "can't add two strings, out of heap");
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.stringHeap->allocateString(nullptr, commonLength) ) {
memcpy ( sAB, sA, la );
memcpy ( sAB+la, sB, lb+1 );
*pA = sAB;
context.stringHeap->recognize(sAB);
} else {
context.throw_error_at(at, "can't add two strings, out of heap");
}
}
// helper functions
const char * rts_null = "";
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)+'0');
result.append(1,(ch&15)+'0');
} else {
result.append(1, ch);
}
break;
}
}
return result;
}
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 && it!=itend ) {
auto CH = *it++;
if ( CH=='\n' ) {
row++;
col=0;
if ( row==ROW ) break;
}
}
}
if ( row!=ROW ) return "";
auto beginOfLine = it;
for (;;) {
if (*it == 0 || it == itend)
{
text