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.
 

203 linhas
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;
}