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.
 

203 lines
4.5 KiB

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