A Tcl like command language made for the Clinl kernel testing
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 

338 linhas
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);
};