import toml; public{ import std.stdio : writeln; import std.file : read; import std.array; import std.string; import std.uni : isWhite, isAlpha, isAlphaNum; import std.ascii : isDigit; import std.conv : to; import std.algorithm; import std.sumtype : SumType; } import dopp_lexer : tokenize, isKeyword; import dopp_parser : parse; TOMLDocument toml_s; export enum TokenType{ Identifier, // todo split to Type - Function - Variable Keyword, Integer, Float, String, Symbol, Whitespace, // maybe todo add equals and other (=, >=, <=, ==) - needs or not ? Comment_Line, New_Line, Match_Any } export struct Token{ TokenType type; string lexeme; // for debug string toString(){ import std.format : format; //return "Token(type: %d, lexeme: %s)".format(type, lexeme); //return "Token = type: %d, lexeme: %s\n".format(type, lexeme); return "Token = type: %d, lexeme: %s\n".format(type, ( (TokenType.New_Line == type) ? `\n` : lexeme) ); } } // ./dopp -t == shortened for test (onto single .de -> .d module) // ./dopp -d "/test" -o "/test2" == input dir path + output dir path (default output dir = input dir) // ./dopp -f test.de -o test.d == input file name + output file name (default output file name = input file name [but .d instead .de] ) // ./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] ) bool is_valid_argv(ref string[] argv){ ulong num = argv.length; // uint64 if(num != 1 && num != 2 && num != 4){ return false; }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) if( (argv[0] == "-t") || (argv[0].length >= 4 && argv[0][$-3 .. $] == ".de") ){ return true; }else{ return false; } }else if(num == 2){ // two arguments = input file name/path or input dir path if(argv[0] != "-d" && argv[0] != "-f"){ return false; }else if(argv[0] == "-f"){ // must be file if(argv[1].length >= 4 && argv[1][$-3 .. $] == ".de"){ return true; }else{ return false; } }else{ // dir if(argv[1].length > 0){ return true; }else{ return false; } } }else{ // num == 4 string[] argv2 = argv[0 .. 2]; if( is_valid_argv(argv2) ){ // valid first 2 string[] argv4 = argv[2 .. $]; if( argv[2] != "-o" ){ // valid next - last 2 return false; }else if(argv[0] == "-f"){ // must be file if(argv[3].length >= 3 && argv[3][$-2 .. $] == ".d"){ return true; }else{ return false; } }else{ // dir if(argv[3].length > 0){ return true; }else{ return false; } } }else{ return false; } } } //alias Config_Value = SumType!(string, int, ubyte, bool); alias Config_Value = SumType!(string, ubyte, bool); Config_Value get_config_value(ref TOMLDocument toml_s, string key){ if(key == "indent_matter"){ ubyte default_indent_matter = 4; if(("indent_matter" in toml_s) != null){ if(toml_s[key].type == TOMLType.INTEGER){ ubyte indent_matter = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8) // todo add alias if(indent_matter > 0){ return Config_Value(indent_matter); } } } writeln("Warning: use default indent_matter = ", default_indent_matter); // todo add config key-value "no_warn" = false | true for silence return Config_Value(default_indent_matter); }else if(key == "indent_out"){ ubyte default_indent_out = 2; if(("indent_out" in toml_s) != null){ if(toml_s[key].type == TOMLType.INTEGER){ ubyte indent_out = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8) if(indent_out > 0){ return Config_Value(indent_out); } } } writeln("Warning: use default indent_out = ", default_indent_out); return Config_Value(default_indent_out); }else if(key == "indent_type"){ // 0 = whitespaces, 1 = tabs ubyte default_indent_type = 0; if(("indent_type" in toml_s) != null){ if(toml_s[key].type == TOMLType.INTEGER){ ubyte indent_type = cast(ubyte) toml_s[key].integer; // long (int64) -> ubyte (uint8) if(indent_type < 2){ // 0 | 1 return Config_Value(indent_type); } } } writeln("Warning: use default indent_type = ", default_indent_type); return Config_Value(default_indent_type); //}else{} } return Config_Value(0); } //void main(string[] argv){ int main(string[] argv){ toml_s = parseTOML(cast(string)read("dopp.toml")); /* writeln("indent_matter: ", toml_s["indent_matter"]); // 4 //writeln("xyz: ", toml_s["xyz"]); // Address boundary error || Segmentation fault (core dumped) writeln("indent_matter in: ", "indent_matter" in toml_s); // hex like 7F27C2992040 writeln("indent_matter is null: ", ("indent_matter" in toml_s) == null); // fasle writeln("indent_matter is TOMLType.INTEGER: ", (toml_s["indent_matter"].type == TOMLType.INTEGER)); // true writeln("xyz in: ", "xyz" in toml_s); // null writeln("xyz is null: ", ("xyz" in toml_s) == null); // true */ auto indent_type = get_config_value(toml_s, "indent_type"); //writeln("config: indent_type = ", indent_type); // 0 // todo add config key-value "no_warn" = false | true for silence auto indent_matter = get_config_value(toml_s, "indent_matter"); //writeln("config: indent_matter = ", indent_matter); // 4 auto indent_out = get_config_value(toml_s, "indent_out"); //writeln("config: indent_out = ", indent_out); // 2 /* int i = 0; foreach(string s; argv[1 .. $]){ writeln(s); i++; } writeln("i = ", i); */ string[] argv1 = argv[1 .. $]; // argv[0] always = program name ( ./dopp in my case in linux ) bool valid_argv = is_valid_argv(argv1); // writeln("valid_argv = ", valid_argv); // todo add config key-value "no_warn" = false | true for silence if(!valid_argv){ return 0; } //string source = `if (x > 0) { writeln("Positive"); }`; /+ string source = q"[ if (x > 0) { writeln("Pos`it`i've'"); } ]"; +/ //string str1 = "this is test"; // valid in dlang //string str1 = "this \"is\" test"; // valid in dlang //string str1 = "this `is` test"; // valid in dlang //string str1 = `this "is" test`; // valid in dlang // //string str1 = `this `is` test`; // not valid in dlang - but valid in my lexer-parser //string str1 = `this ` ~ "`is`" ~ ` test`; // valid in dlang // todo add to lexer r" .. "; // todo add to lexer multiline q"[ .. ]"; // todo add to lexer //string str1 = x"48 65 6C 6C 6F"; // valid in dlang - hex string // Hello //writeln(str1); //writeln("hey" ~ '\n' ~ "hello"); string source = q"[ auto y1 = "this is test"; auto y2 = "this \"is\" test"; auto y3 = `this "is" test`; // this is single line comment auto y4 = `this is test`; auto y5 = `this `is` test`; ]"; // " /+ string source = q"[ auto x = 5; auto x2 = 5_001; auto y1 = "this is test"; auto y2 = "this \"is\" test"; auto y3 = `this "is" test`; auto z = 1; ]"; // " +/ /+ string source = q"[ void main(){ auto x = 5; auto y = ptn x 1 = 1 5 = 5 * 2 9 = 9 * 3 _ = x * 4 } ]"; +/ auto tokens = tokenize(source, 0, 2); // indent_type = 0 = whitespace; indent_matter = 2 (whitespaces) writeln(tokens); auto result = parse(tokens); // indent_out = 2 (whitespaces in output-generated code) writeln(result); /+ void main(){ auto x = 5; if(x == 1){ y = 1; }else if(x == 5){ y = 5 * 2; // return x * 2; }else if(x == 9){ y = 9 * 3; // return x * 3; }else{ // other cases y = x * 4; } } +/ return 1; } unittest{ assert( is_valid_argv([]) == false ); assert( is_valid_argv([""]) == false ); assert( is_valid_argv(["-t"]) == true ); assert( is_valid_argv(["-d"]) == false ); assert( is_valid_argv(["-d", ""]) == false ); assert( is_valid_argv(["-d", "/test"]) == true ); assert( is_valid_argv(["-d", "/test", "-o", "/test2"]) == true ); assert( is_valid_argv(["test.de"]) == true ); assert( is_valid_argv(["-f", "test.de"]) == true ); assert( is_valid_argv(["-f", "test.de", "-o", "test.d"]) == true ); assert( is_valid_argv(["test.txt"]) == false ); assert( is_valid_argv(["-f", "test.txt"]) == false ); assert( is_valid_argv(["-f", "test.txt", "-o", "test.d"]) == false ); assert( is_valid_argv(["-f", "test.de", "-o", "test.txt"]) == false ); } // ./dopp -t == shortened for test (onto single .de -> .d module) // ./dopp -d "/test" -o "/test2" == input dir path + output dir path (default output dir = input dir) // ./dopp -f test.de -o test.d == input file name + output file name (default output file name = input file name [but .d instead .de] ) // ./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] )