A Tcl like command language made for the Clinl kernel testing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

338 lines
7.0 KiB

#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);
};