Browse Source

initial commit

master
Ludovic 'Archivist' Lagouardette 5 years ago
parent
commit
4d486f3d19
10 changed files with 14877 additions and 1 deletions
  1. +3
    -1
      README.md
  2. +68
    -0
      arena.hpp
  3. +136
    -0
      buffer.hpp
  4. +14020
    -0
      catch.hpp
  5. +37
    -0
      container.hpp
  6. +203
    -0
      crank.cpp
  7. +319
    -0
      crank.h
  8. +46
    -0
      main.cpp
  9. +39
    -0
      memory_pool.hpp
  10. +6
    -0
      string_view.hpp

+ 3
- 1
README.md View File

@ -1,3 +1,5 @@
# Crank
A Tcl like command language made for the Clinl kernel testing
A Tcl like command language made for the Clinl kernel testing
Build it just by building crank.cpp and main.cpp together in a C++17 compiler and you are done.

+ 68
- 0
arena.hpp View File

@ -0,0 +1,68 @@
#pragma once
#include "buffer.hpp"
#include "stdlib.h"
#include "string.h"
class arena{
ksdk::buffer<char> data;
size_t last;
size_t count;
public:
arena()
:last(0)
,count(0)
,data(ksdk::buffer<char>(nullptr,(size_t)0))
{}
arena(size_t sz)
:last(0)
,count(0)
,data(ksdk::buffer<char>(nullptr,(size_t)0))
{
if(sz!=0)
{
auto v=malloc(sz);
if(v!=nullptr)
{
data=ksdk::buffer<char>((char*)v,sz);
}
}
}
arena(char* pos,size_t sz)
:last(0)
,count(0)
,data(ksdk::buffer<char>(pos,(size_t)sz))
{
}
void* allocate(size_t sz)
{
auto ret=data.begin()+last;
if(ret<data.end())
{
count++;
last+=sz;
return ret;
}
else
{
return nullptr;
}
}
bool desallocate(void* ptr)
{
if(ptr>=data.begin() && ptr<data.end())
{
count--;
if(count==0)
{
memset(data.begin(),data.size(),0);
last=0;
}
return true;
}
return false;
}
};

+ 136
- 0
buffer.hpp View File

@ -0,0 +1,136 @@
#pragma once
#include <stddef.h>
#include "container.hpp"
namespace __internals{
template<typename T>
T& ref(T& n)
{
return n;
}
template<class T>
struct r_op_iterator
{
r_op_iterator(T* in):it(in){}
T* it;
auto operator++()
{
return it--;
}
auto operator++(int)
{
return --it;
}
auto operator--()
{
return it--;
}
auto operator--(int)
{
return --it;
}
T& operator*()
{
return *it;
}
T& operator[](const size_t idx)
{
return *(it-idx);
}
auto operator==(const r_op_iterator& rhs)
{
return it==rhs.it;
}
auto operator!=(const r_op_iterator& rhs)
{
return it!=rhs.it;
}
auto operator<=(const r_op_iterator& rhs)
{
return (rhs.it<=it);
}
auto operator>=(const r_op_iterator& rhs)
{
return (rhs.it>=it);
}
auto operator<(const r_op_iterator& rhs)
{
return (rhs.it<it);
}
auto operator>(const r_op_iterator& rhs)
{
return (rhs.it>it);
}
};
}
namespace ksdk{
template<typename T>
class buffer : public typed_container<T>
{
protected:
T* _buffer;
size_t _size;
public:
constexpr buffer(T* b, T* e)
:_buffer(b)
,_size(e-b)
{
}
constexpr buffer()
:_buffer(nullptr)
,_size(0)
{
}
constexpr buffer(T* b, size_t sz)
:_buffer(b)
,_size(sz)
{
}
size_t size()
{
return _size;
}
T* begin()
{
return _buffer;
}
T* end()
{
return _buffer+_size;
}
__internals::r_op_iterator<T> rbegin()
{
return __internals::r_op_iterator<T>(_buffer-1+_size);
}
__internals::r_op_iterator<T> rend()
{
return __internals::r_op_iterator<T>(_buffer-1);
}
T& operator[](size_t idx)
{
return _buffer[idx];
}
bool operator==(buffer<T> oth)
{
if(size()!=oth.size())
return false;
for(size_t i=0; i<size(); i++)
if(_buffer[i]!=oth[i])
return false;
return true;
}
};
}

+ 14020
- 0
catch.hpp
File diff suppressed because it is too large
View File


+ 37
- 0
container.hpp View File

@ -0,0 +1,37 @@
#pragma once
#include <stddef.h>
namespace __internals{
/* Enable_if implementation */
template<bool b, class T = void>
struct enable_if{};
template<class T>
struct enable_if<true,T>{
typedef T type;
};
/* Enable_if helper implementation */
template<bool b, class T = void>
using enable_if_t = typename enable_if<b,T>::type;
/* static_assert implementaion for comparing integers */
template<bool b, typename t = enable_if_t<b>>
class check{
};
}
namespace ksdk{
class container
{
public:
size_t size();
};
template<class T>
class typed_container : public container
{
};
}

+ 203
- 0
crank.cpp View File

@ -0,0 +1,203 @@
#include "crank.h"
kstd::string_view crank_context::eval(kstd::string_view code)
{
auto ret = eval_no_copy(copy(code));
return ret;
}
kstd::string_view identity(kstd::string_view args, crank_context& ctx)
{
return args;
}
kstd::string_view set(kstd::string_view args, crank_context& ctx)
{
args = skip_whitespace(args);
auto key = extract_token(args);
auto value = skip_linearspace(kstd::string_view(args.begin()+key.size(),args.end()));
return ctx.store(key,value);
}
bool istokenok(int m)
{
return (
isalpha(m)
|| isdigit(m)
|| m=='$'
|| m=='-'
|| m=='_'
);
}
bool islinearspace(int m)
{
return (
m==' '
|| m=='\t'
);
}
kstd::string_view skip_whitespace(kstd::string_view code)
{
auto m = code.begin();
while(m<code.end() && isspace(*m))
{
m++;
}
return kstd::string_view(m,code.end());
}
kstd::string_view skip_linearspace(kstd::string_view code)
{
auto m = code.begin();
while(m<code.end() && islinearspace(*m))
{
m++;
}
return kstd::string_view(m,code.end());
}
template<char bound>
kstd::string_view extract_bounded(kstd::string_view code)
{
auto m = code.begin();
while(m<code.end() && *m!=bound)
{
if(*m=='"')
{
m++;
m+=extract_string(kstd::string_view(m,code.end())).size();
m++;
}
else if(*m=='{')
{
m++;
m+=extract_array(kstd::string_view(m,code.end())).size();
m++;
}
else if(*m=='[')
{
m++;
m+=extract_subcommand(kstd::string_view(m,code.end())).size();
m++;
}
else if(istokenok(*m))
{
m+=extract_token(kstd::string_view(m,code.end())).size();
}
else
{
m = skip_whitespace(kstd::string_view(m,code.end())).begin();
}
}
return kstd::string_view(code.begin(), m);
}
kstd::string_view extract_command(kstd::string_view code)
{
code = skip_whitespace(code);
return extract_bounded<'\n'>(code);
}
kstd::string_view extract_subcommand(kstd::string_view code)
{
return extract_bounded<']'>(code);
}
kstd::string_view extract_string(kstd::string_view code)
{
auto m = code.begin();
while(m<code.end() && *m!='"')
{
m+=(*m!='\\')?1:2;
}
return kstd::string_view(code.begin(), m);
}
kstd::string_view extract_token(kstd::string_view code)
{
auto m = code.begin();
while(m<code.end() && istokenok(*m))
{
m++;
}
return kstd::string_view(code.begin(), m);
}
kstd::string_view extract_array(kstd::string_view code)
{
return extract_bounded<'}'>(code);
}
kstd::string_view crank_context::execute_command(kstd::string_view code)
{
code = copy_replace(code);
auto token = extract_token(code);
auto symbol = get_symbol(token);
auto args = skip_linearspace(kstd::string_view(code.begin()+token.size(),code.end()));
if(symbol.size())
{
if(symbol[0]=='@')
{
symbol = skip_linearspace(kstd::string_view(symbol.begin()+1, symbol.end()));
while(istokenok(args[0]))
{
auto argname = extract_token(symbol);
symbol = skip_linearspace(kstd::string_view(symbol.begin()+argname.size(), symbol.end()));
auto argvalue = kstd::string_view();
if(args[0]=='{')
{
argvalue=extract_array(kstd::string_view(args.begin()+1, args.end()));
args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
}
else if(args[0]=='[')
{
argvalue=crank_context::execute_command(extract_subcommand(kstd::string_view(args.begin()+1, args.end())));
args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
}
else if(args[0]=='"')
{
argvalue=extract_string(kstd::string_view(args.begin()+1, args.end()));
args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
}
else
{
argvalue=extract_token(kstd::string_view(args.begin()+1, args.end()));
args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size(), args.end()));
}
store(argname,argvalue);
}
symbol = extract_array(symbol);
auto command = extract_command(symbol);
auto ret = kstd::string_view();
while(command.size())
{
ret = execute_command(command);
symbol = kstd::string_view(symbol.begin()+command.size(),symbol.end());
command = extract_command(symbol);
}
return ret;
}
else
{
return symbol;
}
}
else
{
return get_native(token)(args,this);
}
}
kstd::string_view crank_context::eval_no_copy(kstd::string_view code)
{
auto command = extract_command(code);
auto ret = kstd::string_view();;
while(command.size())
{
ret = execute_command(command);
code = kstd::string_view(code.begin()+command.size(),code.end());
command = extract_command(code);
}
return ret;
}

+ 319
- 0
crank.h View File

@ -0,0 +1,319 @@
#pragma once
#include "memory_pool.hpp"
#include "string_view.hpp"
#include "2CL.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,src.size())};
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 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);
};

+ 46
- 0
main.cpp View File

@ -0,0 +1,46 @@
/*#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
#include "catch.hpp"
*/
#include "crank.h"
#include <iostream>
#include <string>
kstd::string_view set2(kstd::string_view args, crank_context& ctx)
{
args = skip_whitespace(args);
auto key = extract_token(args);
auto value = skip_linearspace(kstd::string_view(args.begin()+key.size(),args.end()));
for(auto c : value)
std::cout<<c;
std::cout<<" out:"<<value.size()<<std::endl;
return ctx.store(key,value);
}
int main()
{
const char* set2text = "set2";
std::string get="";
crank_context ctx;
ctx.add_native(kstd::string_view((char*)set2text,4), set2);
while((std::getline(std::cin,get)).good())
{
auto ret = ctx.eval(kstd::string_view(get.data(), get.size()));
for(auto c : ret)
std::cout<<c;
std::cout<<" out:"<<ret.size()<<std::endl;
}
}
/*
TEST_CASE("crank")
{
crank_context ctx;
static const char* setter_code = "set sample \"Hello world\"";
kstd::string_view setter_c{(char*)setter_code, 24};
ctx.eval_no_copy(setter_c);
static const char* getter_code = "$sample";
kstd::string_view getter_c{(char*)getter_code, 7};
ctx.eval_no_copy(getter_c);
}*/

+ 39
- 0
memory_pool.hpp View File

@ -0,0 +1,39 @@
#pragma once
#include "arena.hpp"
#include <array>
class memory_pool{
std::array<arena,256> _pool;
public:
memory_pool()
: _pool()
{
_pool.fill(arena());
for(auto& a : _pool)
a = arena(4096);
}
memory_pool(memory_pool&) = delete;
memory_pool(memory_pool&&) = delete;
void* allocate(size_t sz)
{
for(auto& a : _pool)
{
void* ptr = a.allocate(sz);
if(ptr!=nullptr)
return ptr;
}
return nullptr;
}
void desallocate(void* ptr)
{
for(auto& a : _pool)
{
bool success = a.desallocate(ptr);
if(success)
return;
}
}
};

+ 6
- 0
string_view.hpp View File

@ -0,0 +1,6 @@
#pragma once
#include "buffer.hpp"
namespace kstd{
using string_view = ksdk::buffer<char>;
}

Loading…
Cancel
Save