A Tcl like command language made for the Clinl kernel testing
Não pode escolher mais do que 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.

202 linhas
4.5 KiB

há 6 anos
  1. #include "crank.h"
  2. kstd::string_view crank_context::eval(kstd::string_view code)
  3. {
  4. auto ret = eval_no_copy(copy(code));
  5. return ret;
  6. }
  7. kstd::string_view identity(kstd::string_view args, crank_context& ctx)
  8. {
  9. return args;
  10. }
  11. kstd::string_view set(kstd::string_view args, crank_context& ctx)
  12. {
  13. args = skip_whitespace(args);
  14. auto key = extract_token(args);
  15. auto value = skip_linearspace(kstd::string_view(args.begin()+key.size(),args.end()));
  16. return ctx.store(key,value);
  17. }
  18. bool istokenok(int m)
  19. {
  20. return (
  21. isalpha(m)
  22. || isdigit(m)
  23. || m=='$'
  24. || m=='-'
  25. || m=='_'
  26. );
  27. }
  28. bool islinearspace(int m)
  29. {
  30. return (
  31. m==' '
  32. || m=='\t'
  33. );
  34. }
  35. kstd::string_view skip_whitespace(kstd::string_view code)
  36. {
  37. auto m = code.begin();
  38. while(m<code.end() && isspace(*m))
  39. {
  40. m++;
  41. }
  42. return kstd::string_view(m,code.end());
  43. }
  44. kstd::string_view skip_linearspace(kstd::string_view code)
  45. {
  46. auto m = code.begin();
  47. while(m<code.end() && islinearspace(*m))
  48. {
  49. m++;
  50. }
  51. return kstd::string_view(m,code.end());
  52. }
  53. template<char bound>
  54. kstd::string_view extract_bounded(kstd::string_view code)
  55. {
  56. auto m = code.begin();
  57. while(m<code.end() && *m!=bound)
  58. {
  59. if(*m=='"')
  60. {
  61. m++;
  62. m+=extract_string(kstd::string_view(m,code.end())).size();
  63. m++;
  64. }
  65. else if(*m=='{')
  66. {
  67. m++;
  68. m+=extract_array(kstd::string_view(m,code.end())).size();
  69. m++;
  70. }
  71. else if(*m=='[')
  72. {
  73. m++;
  74. m+=extract_subcommand(kstd::string_view(m,code.end())).size();
  75. m++;
  76. }
  77. else if(istokenok(*m))
  78. {
  79. m+=extract_token(kstd::string_view(m,code.end())).size();
  80. }
  81. else
  82. {
  83. m = skip_whitespace(kstd::string_view(m,code.end())).begin();
  84. }
  85. }
  86. return kstd::string_view(code.begin(), m);
  87. }
  88. kstd::string_view extract_command(kstd::string_view code)
  89. {
  90. code = skip_whitespace(code);
  91. return extract_bounded<'\n'>(code);
  92. }
  93. kstd::string_view extract_subcommand(kstd::string_view code)
  94. {
  95. return extract_bounded<']'>(code);
  96. }
  97. kstd::string_view extract_string(kstd::string_view code)
  98. {
  99. auto m = code.begin();
  100. while(m<code.end() && *m!='"')
  101. {
  102. m+=(*m!='\\')?1:2;
  103. }
  104. return kstd::string_view(code.begin(), m);
  105. }
  106. kstd::string_view extract_token(kstd::string_view code)
  107. {
  108. auto m = code.begin();
  109. while(m<code.end() && istokenok(*m))
  110. {
  111. m++;
  112. }
  113. return kstd::string_view(code.begin(), m);
  114. }
  115. kstd::string_view extract_array(kstd::string_view code)
  116. {
  117. return extract_bounded<'}'>(code);
  118. }
  119. kstd::string_view crank_context::execute_command(kstd::string_view code)
  120. {
  121. code = copy_replace(code);
  122. auto token = extract_token(code);
  123. auto symbol = get_symbol(token);
  124. auto args = skip_linearspace(kstd::string_view(code.begin()+token.size(),code.end()));
  125. if(symbol.size())
  126. {
  127. if(symbol[0]=='@')
  128. {
  129. symbol = skip_linearspace(kstd::string_view(symbol.begin()+1, symbol.end()));
  130. while(istokenok(args[0]))
  131. {
  132. auto argname = extract_token(symbol);
  133. symbol = skip_linearspace(kstd::string_view(symbol.begin()+argname.size(), symbol.end()));
  134. auto argvalue = kstd::string_view();
  135. if(args[0]=='{')
  136. {
  137. argvalue=extract_array(kstd::string_view(args.begin()+1, args.end()));
  138. args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
  139. }
  140. else if(args[0]=='[')
  141. {
  142. argvalue=crank_context::execute_command(extract_subcommand(kstd::string_view(args.begin()+1, args.end())));
  143. args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
  144. }
  145. else if(args[0]=='"')
  146. {
  147. argvalue=extract_string(kstd::string_view(args.begin()+1, args.end()));
  148. args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size()+2, args.end()));
  149. }
  150. else
  151. {
  152. argvalue=extract_token(kstd::string_view(args.begin()+1, args.end()));
  153. args = skip_linearspace(kstd::string_view(args.begin()+argvalue.size(), args.end()));
  154. }
  155. store(argname,argvalue);
  156. }
  157. symbol = extract_array(symbol);
  158. auto command = extract_command(symbol);
  159. auto ret = kstd::string_view();
  160. while(command.size())
  161. {
  162. ret = execute_command(command);
  163. symbol = kstd::string_view(symbol.begin()+command.size(),symbol.end());
  164. command = extract_command(symbol);
  165. }
  166. return ret;
  167. }
  168. else
  169. {
  170. return symbol;
  171. }
  172. }
  173. else
  174. {
  175. return get_native(token)(args,this);
  176. }
  177. }
  178. kstd::string_view crank_context::eval_no_copy(kstd::string_view code)
  179. {
  180. auto command = extract_command(code);
  181. auto ret = kstd::string_view();;
  182. while(command.size())
  183. {
  184. ret = execute_command(command);
  185. code = kstd::string_view(code.begin()+command.size(),code.end());
  186. command = extract_command(code);
  187. }
  188. return ret;
  189. }