[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/PushoN/daScript/master/src/simulate/runtime_string.cpp [Back]  [Original]

#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 

Web Proxy Viewer  |  New URL  |  Original Page