diff --git a/src/example.toml b/src/example.toml index edd1201..2191afa 100644 --- a/src/example.toml +++ b/src/example.toml @@ -1,31 +1,95 @@ -title = "TOML Example" -[owner] -name = """Tom Preston-Werner -test""" -othername = """Tom \"The killer\" or \"yo\" or -'you' Preston-Werner""" -date = 2010-04-23 -time = 21:30:00 -"lol".yo = "tesaat" +# Example TOML file with syntax errors -[[fruits]] +title = "My Config File" + +[author] +name = "John Doe" +email = "johndoe@example.com" + +[database] +name = "my_database" +username = "admin" +password = "password123" +" " = "lmao" +"" = "lmao" + +[server] +ip = "192.168.0.1" +port = 8080 + +[logging] +enabled = true +level = "info" + +[[fruit]] name = "apple" - -[fruits.physical] color = "red" -shape = "round" -[[fruits.varieties]] -name = "red delicious" - -[[fruits.varieties]] -name = "granny smith" - -[[fruits]] +[[fruit]] name = "banana" +color = "yellow" + + +[vegetables] +hello = "test" + +[vegetables.yeet] +carrot = "orange" +tomato = "red" +potato = "yellow" + +[[animal]] +name = "cat" +sound = "meow" +[[animal]] +name = "dog" +sound = "woof" + +[paths] +data = "/path/to/data" +logs = "/path/to/logs" + +[[servers]] +name = "server1" +ip = "192.168.0.10" +port = 8081 + +[[servers]] +name = "server2" +ip = "192.168.0.20" +port = 8082 + + +[arrays] +integers = [ 1, 2, 3 ] +colors = [ "red", "yellow", "green" ] +nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] +nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] +string_array = [ "all", 'strings', """are the same""", '''type''' ] + +# Mixed-type arrays are allowed +numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] +contributors = [ + "Foo Bar ", + { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } +] + +[fruie] +apple.color = "red" +apple.taste.sweet = true + +[fruie.apple.color] +test="oi" +[fruie.apple.taste] +test2="oi" + +[fruie.apple.texture] # you can add sub-tables +smooth = true +smooth = false + + +points = [ { x = 1, y = 2, z = 3 }, + { x = 7, y = 8, z = 9 }, + { x = 2, y = 4, z = 8 } ] -[[fruits.varieties]] -name = "plantain" -integers2.name = "Nail" -integers2 = {"oi"=5} diff --git a/src/lexer.py b/src/lexer.py index 09cd739..8f4ebcb 100644 --- a/src/lexer.py +++ b/src/lexer.py @@ -12,6 +12,7 @@ tokens = [ "BIN", "OCT", "FLOAT", # need to implement exponents check https://toml.io/en/ + "BOOL", "INF", "NAN", "COMMENT", @@ -38,7 +39,7 @@ def t_TIME(t): # needs number grouping (example : flt8 = 224_617.445_991_228) def t_FLOAT(t): - r"[+-]?\d+(\s*\.\s*\d+)?([eE][-+]?\d+)?" + r"[+-]?\d+(_\d+)*\s*\.\s*\d+(_\d+)*([eE][-+]?\d+(_\d+)*)?" #case where float appears on the left side with spaces in between if t.value.__contains__(' '): t.type = "ID" @@ -48,23 +49,23 @@ def t_FLOAT(t): # needs number grouping (example : int6 = 5_349_221) def t_INT(t): - r"[-+]?\d+" + r"[-+]?(\d+(_\d+)*)" return t # needs number grouping (example : hex3 = 0xdead_beef) def t_HEX(t): - r"0x[0-9a-fA-F]+" + r"0x[0-9a-fA-F]+(_[0-9a-fA-F]+)*" return t def t_BIN(t): - r"0b[01]+" + r"0b[01]+(_[01]+)*" return t def t_OCT(t): - r"0o[0-7]+" + r"0o[0-7]+(_[0-7]+)*" return t @@ -92,13 +93,14 @@ def t_ID(t): def t_MLSTR(t): - r"(\"\"\"(?:[^\"\\]|\\.)+\"\"\")|(\'\'\'(?:[^\'\\]|\\.)+\'\'\')" + r"(\"\"\"(?:[^\"\\]|\\.)*\"\"\")|(\'\'\'.*\'\'\')" + t.value = t.value.strip("\"'") return t # STR needs to be the first one to catch def t_STR(t): - r"(\"(?:[^\"\\]|\\.)+\")|(\'[^\']+\')" + r"(\"(?:[^\"\\]|\\.)*\")|(\'[^\']*\')" t.value = t.value.strip("\"'") return t diff --git a/src/parser.py b/src/parser.py index 5ebcb76..f695745 100644 --- a/src/parser.py +++ b/src/parser.py @@ -45,6 +45,7 @@ def p_table_simple(p): print("Cannot define the same table twice") p.parser.syntax_error = True p.parser.current_header = temp + p.parser.current_header_name = p[2] # isto ta errado @@ -68,6 +69,7 @@ def p_table_array(p): temp[headers[-1]].append({}) temp = temp[headers[-1]][-1] p.parser.current_header = temp + p.parser.current_header_name = p[3] def p_object(p): @@ -77,23 +79,30 @@ def p_object(p): if p.parser.syntax_error: return headers = p[1] + temp = p.parser.current_header + if isinstance(p[3],dict): for table in p.parser.current_tables: if p[1][0]==table[0]: print("Error, trying to redefine a table") return p.parser.current_inline_tables.append(p[1]) - else: + elif len(p[1])>1: for table in p.parser.current_inline_tables: if p[1][:len(table)]==table: print("Error, trying to redefine an inline table") return p.parser.current_tables.append(p[1]) - temp = p.parser.current_header for header in headers[:-1]: if header not in temp: temp[header] = {} temp = temp[header] + if not isinstance(temp,dict): + print("Error, cannot add {p[3]} to a {type(temp)} variable") + return + if headers[-1] in temp: + print(f"Error, cannot define {'.'.join(p.parser.current_header_name + p[1])} twice") + return temp[headers[-1]] = p[3] @@ -139,7 +148,12 @@ def p_dict_empty(p): def p_dictCont_multiple(p): """dictCont : dictCont ',' dictElem""" # checar se os dicts nao teem keys repetidas - p[0] = p[1].update(p[3]) + duplicate_list = [k for k in p[1] if k in p[3]] + for dup in duplicate_list: + print(f"Duplicate inline-table key {dup}") + if len(duplicate_list)==0: + p[1].update(p[3]) + p[0] = p[1] def p_dictCont_single(p): @@ -147,7 +161,7 @@ def p_dictCont_single(p): p[0] = p[1] -def p_dictElem_object(p): +def p_dictElem(p): """dictElem : key '=' value | key '=' array | key '=' dict""" @@ -177,6 +191,7 @@ def p_key_rest(p): | BIN | OCT | INF + | BOOL | NAN""" p[0] = [p[1]] @@ -239,6 +254,9 @@ def p_value_nan(p): """value : NAN""" p[0] = p[1] +def p_value_bool(p): + """value : BOOL""" + p[0] = bool(p[1]) def p_error(p): print(p) @@ -248,6 +266,7 @@ parser = yacc.yacc() parser.root_dict = dict() parser.current_header = parser.root_dict +parser.current_header_name = "" parser.syntax_error = False parser.current_inline_tables = [] parser.current_tables = []