#pragma once #include "memory_pool.hpp" #include "string_view.hpp" class crank_context; kstd::string_view identity(kstd::string_view args, crank_context& ctx); kstd::string_view set(kstd::string_view args, crank_context& ctx); bool istokenok(int m); bool islinearspace(int m); kstd::string_view skip_whitespace(kstd::string_view code); kstd::string_view skip_linearspace(kstd::string_view code); template struct pair{ pair(t1 f, t2 s) : first{f} , second{s} {} t1 first; t2 second; }; struct crank_macro{ kstd::string_view(*execute)(kstd::string_view, crank_context&); crank_macro() { execute=identity; } crank_macro(kstd::string_view(*f)(kstd::string_view, crank_context&)) { execute=f; } kstd::string_view operator()(kstd::string_view args, crank_context* ctx) { return execute(args, *ctx); } }; struct crank_elem; template struct crank_ptr{ T* ptr=nullptr; memory_pool* memory=nullptr; crank_ptr(T* _ptr, memory_pool* _memory) : ptr{_ptr} , memory{_memory} {} crank_ptr(){} crank_ptr(crank_ptr&) = delete; crank_ptr(crank_ptr&& oth) { auto tmp = oth.ptr; oth.ptr=ptr; ptr=tmp; auto tmpm = oth.memory; oth.memory=memory; memory=tmpm; } void operator=(crank_ptr&& oth) { auto tmp = oth.ptr; oth.ptr=ptr; ptr=tmp; auto tmpm = oth.memory; oth.memory=memory; memory=tmpm; } ~crank_ptr() { if(ptr&&memory) { memory->desallocate(ptr); } } }; struct crank_elem{ crank_ptr next; pair data; }; struct crank_copy{ crank_ptr next; kstd::string_view data; }; struct crank_native{ crank_ptr next; pair data; }; kstd::string_view skip_whitespace(kstd::string_view code); kstd::string_view extract_subcommand(kstd::string_view code); kstd::string_view extract_array(kstd::string_view code); kstd::string_view extract_token(kstd::string_view code); kstd::string_view extract_command(kstd::string_view code); kstd::string_view extract_string(kstd::string_view code); class crank_context{ memory_pool memory; crank_ptr elements; crank_ptr copies; crank_ptr natives; public: kstd::string_view copy(kstd::string_view src) { char* ptr = (char*)memory.allocate(src.size()); if(ptr) { crank_copy* cpy = (crank_copy*)memory.allocate(sizeof(crank_copy)); if(cpy) { new(cpy) crank_copy{.next=std::move(copies), .data=kstd::string_view(ptr,src.size())}; copies = std::move(crank_ptr{cpy, &memory}); memcpy(ptr,src.begin(),src.size()); return copies.ptr->data; } else { memory.desallocate(ptr); return kstd::string_view(); } } return kstd::string_view(); } kstd::string_view copy_replace(kstd::string_view src) { size_t new_len=src.size(); auto m = src.begin(); while(m!=src.end()) { if(!istokenok(*m)) { m++; } else { auto token = extract_token(kstd::string_view(m,src.end())); if(token[0]=='$') { new_len-=token.size(); new_len+=get_symbol(kstd::string_view(token.begin()+1,token.end())).size(); } m+=token.size(); } } char* ptr = (char*)memory.allocate(new_len); if(ptr) { crank_copy* cpy = (crank_copy*)memory.allocate(sizeof(crank_copy)); if(cpy) { new(cpy) crank_copy{.next=std::move(copies), .data=kstd::string_view(ptr,new_len)}; copies = std::move(crank_ptr{cpy, &memory}); auto dest = kstd::string_view(ptr,new_len); auto src_it = src.begin(); auto dest_it = dest.begin(); while(src_it!=src.end() && dest_it!=dest.end()) { if(!istokenok(*src_it)) { *dest_it = *src_it; dest_it++; src_it++; } else { auto token = extract_token(kstd::string_view(src_it,src.end())); if(token[0]=='$') { auto resolved = get_symbol(kstd::string_view(token.begin()+1,token.end())); memcpy(dest_it,resolved.begin(),resolved.size()); src_it+=token.size(); dest_it+=resolved.size(); } else { memcpy(dest_it,token.begin(),token.size()); src_it+=token.size(); dest_it+=token.size(); } } } return copies.ptr->data; } else { memory.desallocate(ptr); return kstd::string_view(); } } return kstd::string_view(); } kstd::string_view store(kstd::string_view key, kstd::string_view value) { crank_elem* elem = (crank_elem*)memory.allocate(sizeof(crank_elem)); if(elem) { new(elem) crank_elem{.next=std::move(elements), .data=pair(key, value)}; elements = std::move(crank_ptr{elem, &memory}); return value; } return kstd::string_view(); } kstd::string_view add_native(kstd::string_view key, crank_macro value) { crank_native* native = (crank_native*)memory.allocate(sizeof(crank_native)); if(native) { new(native) crank_native{.next=std::move(natives), .data=pair(key, value)}; natives = std::move(crank_ptr{native, &memory}); return key; } return kstd::string_view(); } bool string_is_in_range(kstd::string_view range, char* ptr) { return ptr>=range.begin() && ptrptr) { if( string_is_in_range(range, elems->ptr->data.first.begin()) || string_is_in_range(range, elems->ptr->data.second.begin()) ) { return true; } elems = &(elems->ptr->next); } return false; } kstd::string_view get_symbol(kstd::string_view key) { auto elems = &elements; while(elems->ptr) { if( elems->ptr->data.first == key ) { return elems->ptr->data.second; } elems = &(elems->ptr->next); } return kstd::string_view(); } crank_macro& get_native(kstd::string_view key) { auto elems = &natives; while(elems->ptr) { if( elems->ptr->data.first == key ) { return elems->ptr->data.second; } elems = &(elems->ptr->next); } static const char* id = "identity"; return get_native(kstd::string_view((char*)id,8)); } void collect() { auto elems = &elements; while(elems->ptr) { auto elems_after = &(elems->ptr->next); while(elems_after->ptr) { if( elems->ptr->data.first == elems_after->ptr->data.first ) { *elems_after = std::move(elems_after->ptr->next); } else { elems_after = &(elems_after->ptr->next); } } elems = &(elems->ptr->next); } auto cps = &copies; while(cps->ptr) { if( ! any_elem_is_in_range(cps->ptr->data) ) { memory.desallocate(cps->ptr->data.begin()); *cps=std::move(cps->ptr->next); } else { cps = &(cps->ptr->next); } } } crank_context() { static const char* str_set = "set"; add_native(kstd::string_view((char*)str_set,3), set); static const char* str_identity = "identity"; add_native(kstd::string_view((char*)str_identity,8), identity); } kstd::string_view execute_command(kstd::string_view code); kstd::string_view eval(kstd::string_view); kstd::string_view eval_no_copy(kstd::string_view); };