#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<typename t1, typename t2>
|
|
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<typename T>
|
|
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<crank_elem> next;
|
|
pair<kstd::string_view,kstd::string_view> data;
|
|
};
|
|
|
|
struct crank_copy{
|
|
crank_ptr<crank_copy> next;
|
|
kstd::string_view data;
|
|
};
|
|
|
|
struct crank_native{
|
|
crank_ptr<crank_native> next;
|
|
pair<kstd::string_view,crank_macro> 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<crank_elem> elements;
|
|
crank_ptr<crank_copy> copies;
|
|
crank_ptr<crank_native> 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() && ptr<range.end();
|
|
}
|
|
|
|
bool any_elem_is_in_range(kstd::string_view range)
|
|
{
|
|
auto elems = &elements;
|
|
while(elems->ptr)
|
|
{
|
|
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);
|
|
};
|