dopp.d 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. import toml;
  2. public{
  3. import std.stdio : writeln;
  4. import std.file : read;
  5. import std.array; // .array.idup + other
  6. import std.string;
  7. import std.uni : isWhite, isAlpha, isAlphaNum;
  8. import std.ascii : isDigit;
  9. import std.conv : to;
  10. import std.algorithm;
  11. import std.sumtype : SumType;
  12. import std.range : repeat;
  13. }
  14. import dopp_lexer : tokenize, isKeyword;
  15. import dopp_parser : parse;
  16. TOMLDocument toml_s;
  17. export enum TokenType{
  18. Identifier, // todo split to Type - Function - Variable
  19. Keyword,
  20. Integer,
  21. Float,
  22. String,
  23. Symbol,
  24. Whitespace, // maybe todo add equals and other (=, >=, <=, ==) - needs or not ?
  25. Round_Bracket,
  26. Comment_Line,
  27. New_Line,
  28. Indent_Incr,
  29. Indent_Decr,
  30. Match_Any
  31. }
  32. export struct Token{
  33. TokenType type;
  34. string lexeme;
  35. // for debug
  36. string toString(){
  37. import std.format : format;
  38. import std.string : replace;
  39. //return "Token(type: %d, lexeme: %s)".format(type, lexeme);
  40. //return "Token = type: %d, lexeme: %s\n".format(type, lexeme);
  41. return "Token = type: %d, lexeme: %s\n".format(type,
  42. ( (type == TokenType.New_Line) ?
  43. `\n` :
  44. ( (type == TokenType.Indent_Incr) || (type == TokenType.Indent_Decr) ) ?
  45. lexeme.replace("\n", "\\n") : lexeme ) );
  46. }
  47. }
  48. // ./dopp -t == shortened for test (onto single .de -> .d module)
  49. // ./dopp -d "/test" -o "/test2" == input dir path + output dir path (default output dir = input dir)
  50. // ./dopp -f test.de -o test.d == input file name + output file name (default output file name = input file name [but .d instead .de] )
  51. // ./dopp -f "/test/test.de" -o "/result/test.d" == input file path + output file path (default output file name and path = input file name and path [but .d instead .de] )
  52. bool is_valid_argv(ref string[] argv){
  53. ulong num = argv.length; // uint64
  54. if(num != 1 && num != 2 && num != 4){
  55. return false;
  56. }else if(num == 1){ // one argument only (just filename or /path/filename) == shortened ./dopp -f test.de = ./dopp test.de; or -t == shortened for test (onto single .de -> .d module)
  57. if( (argv[0] == "-t") || (argv[0].length >= 4 && argv[0][$-3 .. $] == ".de") ){
  58. return true;
  59. }else{
  60. return false;
  61. }
  62. }else if(num == 2){ // two arguments = input file name/path or input dir path
  63. if(argv[0] != "-d" && argv[0] != "-f"){
  64. return false;
  65. }else if(argv[0] == "-f"){ // must be file
  66. if(argv[1].length >= 4 && argv[1][$-3 .. $] == ".de"){
  67. return true;
  68. }else{
  69. return false;
  70. }
  71. }else{ // dir
  72. if(argv[1].length > 0){
  73. return true;
  74. }else{
  75. return false;
  76. }
  77. }
  78. }else{ // num == 4
  79. string[] argv2 = argv[0 .. 2];
  80. if( is_valid_argv(argv2) ){ // valid first 2
  81. string[] argv4 = argv[2 .. $];
  82. if( argv[2] != "-o" ){ // valid next - last 2
  83. return false;
  84. }else if(argv[0] == "-f"){ // must be file
  85. if(argv[3].length >= 3 && argv[3][$-2 .. $] == ".d"){
  86. return true;
  87. }else{
  88. return false;
  89. }
  90. }else{ // dir
  91. if(argv[3].length > 0){
  92. return true;
  93. }else{
  94. return false;
  95. }
  96. }
  97. }else{
  98. return false;
  99. }
  100. }
  101. }
  102. //alias Config_Value = SumType!(string, int, ubyte, bool);
  103. alias Config_Value = SumType!(string, ubyte, bool);
  104. Config_Value get_config_value(ref TOMLDocument toml_s, string key){
  105. if(key == "indent_matter"){
  106. ubyte default_indent_matter = 4;
  107. if(("indent_matter" in toml_s) != null){
  108. if(toml_s[key].type == TOMLType.INTEGER){
  109. ubyte indent_matter = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8) // todo add alias
  110. if(indent_matter > 0){
  111. return Config_Value(indent_matter);
  112. }
  113. }
  114. }
  115. writeln("Warning: use default indent_matter = ", default_indent_matter); // todo add config key-value "no_warn" = false | true for silence
  116. return Config_Value(default_indent_matter);
  117. }else if(key == "indent_out"){
  118. ubyte default_indent_out = 2;
  119. if(("indent_out" in toml_s) != null){
  120. if(toml_s[key].type == TOMLType.INTEGER){
  121. ubyte indent_out = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8)
  122. if(indent_out > 0){
  123. return Config_Value(indent_out);
  124. }
  125. }
  126. }
  127. writeln("Warning: use default indent_out = ", default_indent_out);
  128. return Config_Value(default_indent_out);
  129. }else if(key == "indent_type"){ // 0 = whitespaces, 1 = tabs
  130. ubyte default_indent_type = 0;
  131. if(("indent_type" in toml_s) != null){
  132. if(toml_s[key].type == TOMLType.INTEGER){
  133. ubyte indent_type = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8)
  134. if(indent_type < 2){ // 0 | 1
  135. return Config_Value(indent_type);
  136. }
  137. }
  138. }
  139. writeln("Warning: use default indent_type = ", default_indent_type);
  140. return Config_Value(default_indent_type);
  141. //}else{}
  142. }
  143. return Config_Value(0);
  144. }
  145. //void main(string[] argv){
  146. int main(string[] argv){
  147. toml_s = parseTOML(cast(string)read("dopp.toml"));
  148. /*
  149. writeln("indent_matter: ", toml_s["indent_matter"]); // 4
  150. //writeln("xyz: ", toml_s["xyz"]); // Address boundary error || Segmentation fault (core dumped)
  151. writeln("indent_matter in: ", "indent_matter" in toml_s); // hex like 7F27C2992040
  152. writeln("indent_matter is null: ", ("indent_matter" in toml_s) == null); // fasle
  153. writeln("indent_matter is TOMLType.INTEGER: ", (toml_s["indent_matter"].type == TOMLType.INTEGER)); // true
  154. writeln("xyz in: ", "xyz" in toml_s); // null
  155. writeln("xyz is null: ", ("xyz" in toml_s) == null); // true
  156. */
  157. auto indent_type = get_config_value(toml_s, "indent_type");
  158. //writeln("config: indent_type = ", indent_type); // 0 // todo add config key-value "no_warn" = false | true for silence
  159. auto indent_matter = get_config_value(toml_s, "indent_matter");
  160. //writeln("config: indent_matter = ", indent_matter); // 4
  161. auto indent_out = get_config_value(toml_s, "indent_out");
  162. //writeln("config: indent_out = ", indent_out); // 2
  163. /*
  164. int i = 0;
  165. foreach(string s; argv[1 .. $]){
  166. writeln(s);
  167. i++;
  168. }
  169. writeln("i = ", i);
  170. */
  171. string[] argv1 = argv[1 .. $]; // argv[0] always = program name ( ./dopp in my case in linux )
  172. bool valid_argv = is_valid_argv(argv1);
  173. // writeln("valid_argv = ", valid_argv); // todo add config key-value "no_warn" = false | true for silence
  174. if(!valid_argv){
  175. return 1;
  176. }
  177. //string source = `if (x > 0) { writeln("Positive"); }`;
  178. /+
  179. string source = q"[
  180. if (x > 0) {
  181. writeln("Pos`it`i've'");
  182. }
  183. ]";
  184. +/
  185. //string str1 = "this is test"; // valid in dlang
  186. //string str1 = "this \"is\" test"; // valid in dlang
  187. //string str1 = "this `is` test"; // valid in dlang
  188. //string str1 = `this "is" test`; // valid in dlang
  189. // //string str1 = `this `is` test`; // not valid in dlang - but valid in my lexer-parser
  190. //string str1 = `this ` ~ "`is`" ~ ` test`; // valid in dlang
  191. // todo add to lexer r" .. ";
  192. // todo add to lexer multiline q"[ .. ]";
  193. // todo add to lexer //string str1 = x"48 65 6C 6C 6F"; // valid in dlang - hex string // Hello
  194. //writeln(str1);
  195. //writeln("hey" ~ '\n' ~ "hello");
  196. string source = q"[
  197. auto y1 = "this is test";
  198. if(true)
  199. auto y2 = "this \"is\" test";
  200. else
  201. auto y3 = `this "is" test`; // this is single line comment
  202. auto y4 = `this is test`;
  203. auto y5 = `this `is` test`;
  204. ]"; // "
  205. /+
  206. string source = q"[
  207. auto x = 5;
  208. auto x2 = 5_001;
  209. auto y1 = "this is test";
  210. auto y2 = "this \"is\" test";
  211. auto y3 = `this "is" test`;
  212. auto z = 1;
  213. ]"; // "
  214. +/
  215. /+
  216. string source = q"[
  217. void main(){
  218. auto x = 5;
  219. auto y = ptn x
  220. 1 = 1
  221. 5 = 5 * 2
  222. 9 = 9 * 3
  223. _ = x * 4
  224. }
  225. ]";
  226. +/
  227. auto tokens = tokenize(source, 0, 2, 2); // indent_type = 0 = whitespace; indent_matter = 2 (whitespaces); indent_out = 2 (whitespaces in output-generated code)
  228. writeln(tokens);
  229. auto result = parse(tokens);
  230. writeln(result);
  231. /+
  232. void main(){
  233. auto x = 5;
  234. if(x == 1){
  235. y = 1;
  236. }else if(x == 5){
  237. y = 5 * 2; // return x * 2;
  238. }else if(x == 9){
  239. y = 9 * 3; // return x * 3;
  240. }else{ // other cases
  241. y = x * 4;
  242. }
  243. }
  244. +/
  245. return 0;
  246. }
  247. unittest{
  248. assert( is_valid_argv([]) == false );
  249. assert( is_valid_argv([""]) == false );
  250. assert( is_valid_argv(["-t"]) == true );
  251. assert( is_valid_argv(["-d"]) == false );
  252. assert( is_valid_argv(["-d", ""]) == false );
  253. assert( is_valid_argv(["-d", "/test"]) == true );
  254. assert( is_valid_argv(["-d", "/test", "-o", "/test2"]) == true );
  255. assert( is_valid_argv(["test.de"]) == true );
  256. assert( is_valid_argv(["-f", "test.de"]) == true );
  257. assert( is_valid_argv(["-f", "test.de", "-o", "test.d"]) == true );
  258. assert( is_valid_argv(["test.txt"]) == false );
  259. assert( is_valid_argv(["-f", "test.txt"]) == false );
  260. assert( is_valid_argv(["-f", "test.txt", "-o", "test.d"]) == false );
  261. assert( is_valid_argv(["-f", "test.de", "-o", "test.txt"]) == false );
  262. }
  263. // ./dopp -t == shortened for test (onto single .de -> .d module)
  264. // ./dopp -d "/test" -o "/test2" == input dir path + output dir path (default output dir = input dir)
  265. // ./dopp -f test.de -o test.d == input file name + output file name (default output file name = input file name [but .d instead .de] )
  266. // ./dopp -f "/test/test.de" -o "/result/test.d" == input file path + output file path (default output file name and path = input file name and path [but .d instead .de] )