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.

202 lines
4.5 KiB

5 years ago
  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. }