/* * Created by PyramIDE. * User: フランスのトトロ aka (David RENÉ) * Date: 07/06/2016 * Time: 23:15 * © Calexium */ read yaml_type.anubis read tools/streams.anubis read tools/string.anubis read system/string.anubis type YAML_Parser_Info: yaml_p_info(Int parent_indent, Int context_indent, Int level). type YAML_Parser_Node_Info: none, unquoted, in_single_quote, in_double_quote. type YAML_Parser_String_State: none, unquoted, in_single_quote, in_double_quote. type YAML_Parser_Context_Info: none, line, block_start, block. type YAML_Parser_Node: map(List(YAML_Key_Value) kvl), list(List(YAML_Value) vl), value(YAML_Value v). define Maybe(YAML_Parser_Node) _read_node ( Stream s, YAML_Parser_Info p_info, YAML_Parser_Node_Info node_info, List(Word8) so_far ). define Bool eol(Stream s, Word8 c) = if c = 10 then true // LF else if c = 13 then // CR if read_byte(s) is // for CR LF { failure then true, success(next_char) then if next_char = 10 then true else unput_byte(next_char, s); true } else false. define One skip_to_next_line ( Stream s )= if read_byte(s) is { failure then unique, success(c) then if eol(s, c) then unique else skip_to_next_line(s) }. define One skip_spaces ( Stream s )= if read_byte(s) is { failure then unique, success(c) then if c = ' ' then skip_spaces(s) else unput_byte(c, s); unique }. define One skip_to_next_node ( Stream s )= if read_byte(s) is { failure then unique, success(c) then if eol(s, c) then skip_to_next_node(s) else if c = ' ' then skip_to_next_node(s) else if c = '#' then //skip_spaces(s); skip_to_next_line(s); skip_to_next_node(s) else unput_byte(c, s); unique }. define List(Word8) trim_right ( List(Word8) char_list, Word8 token )= if char_list is { [ ] then [ ], [h . t] then if h = token then trim_right(t, token) else char_list }. define String trim_right ( String str, Word8 token )= implode(reverse(trim_right(reverse(explode(str)), token))). define Maybe(YAML_Value) extract_yaml_string ( String str, Stream s, YAML_Parser_String_State ss, List(Word8) so_far )= if read_byte(s) is { failure then success(string(var(implode(reverse(so_far))))), success(c) then if ss is { none then if c = '\"' then extract_yaml_string(str, s, in_double_quote, so_far) else if c = '\'' then extract_yaml_string(str, s, in_single_quote, so_far) else extract_yaml_string(str, s, unquoted, so_far), unquoted then success(string(var(str))), in_single_quote then if read_byte(s) is { failure then if c = '\'' then success(string(var(implode(reverse(so_far))))) else failure, success(nc) then unput_byte(nc, s); extract_yaml_string(str, s, in_single_quote, [c . so_far]) }, in_double_quote then if read_byte(s) is { failure then if c = '\"' then success(string(var(implode(reverse(so_far))))) else failure, success(nc) then unput_byte(nc, s); extract_yaml_string(str, s, in_double_quote, [c . so_far]) }, } }. // should be of type Maybe(YAML_Value) define YAML_Value get_yaml_value ( String str )= with str = trim_token(str, ' '), if str = "yes" then bool(var(true)) else if str = "no" then bool(var(false)) else if str = "true" then bool(var(true)) else if str = "false" then bool(var(false)) else if decimal_scan(str) is { failure then if extract_yaml_string(str, make_stream(str), none, []) is { failure then null, success(v) then v } success(integer) then int(var(integer)) }. define Maybe(List(YAML_Key_Value)) read_block_maps ( Stream s, YAML_Parser_Info p_info, Int block_indent, List(YAML_Key_Value) so_far )= since p_info is yaml_p_info(parent_indent, context_indent, level), skip_spaces(s); skip_to_next_node(s); with current_indent = current_column(s), //println("reading block map entries"); //println("current_indent: " + current_indent); //println("block_indent: " + block_indent); if current_indent = block_indent then if _read_node(s, yaml_p_info(block_indent, current_indent, level), none, []) is { failure then success([]), success(node_type) then if node_type is { map(yaml_kvl) then if yaml_kvl is { [ ] then failure, [h . _] then read_block_maps(s, p_info, block_indent, [ h . so_far ]), } list(yaml_lv) then success(so_far), value(yaml_value) then success(so_far) } } else success(so_far). define Maybe(List(YAML_Value)) read_block_list ( Stream s, YAML_Parser_Info p_info, Int block_indent, List(YAML_Value) so_far )= since p_info is yaml_p_info(parent_indent, context_indent, level), skip_spaces(s); skip_to_next_node(s); with current_indent = current_column(s), //println("current_indent: " + current_indent); //println("block_indent: " + block_indent); if current_indent = block_indent then if _read_node(s, yaml_p_info(block_indent, current_indent, level), none, []) is { failure then success([]), success(node_type) then if node_type is { map(yaml_kvl) then failure, list(yaml_lv) then if yaml_lv is { [ ] then failure, [h . _] then read_block_list(s, p_info, block_indent, [ h . so_far ]), } value(yaml_value) then failure } } else success(so_far). define Maybe(YAML_Value) read_value ( Stream s, YAML_Parser_Info p_info, YAML_Parser_Context_Info ctx_info, List(Word8) so_far )= since p_info is yaml_p_info(parent_indent, context_indent, level), //skip_spaces(s); with current_indent = current_column(s), if read_byte(s) is { failure then success(null), success(c) then if eol(s, c) then // \n if ctx_info is { none then read_value(s, p_info, block_start, so_far), line then with value_str = implode(reverse(so_far)), success(get_yaml_value(value_str)), block_start then read_value(s, p_info, block_start, so_far), block then read_value(s, p_info, block, so_far) } else if ctx_info is { none then read_value(s, p_info, line, [c . so_far]), line then //println(implode(reverse([c . so_far]))); if c = '#' then skip_to_next_line(s); success(get_yaml_value(implode(reverse(so_far)))) else read_value(s, p_info, line, [c . so_far]), block_start then // println("block_start"); unput_byte(c, s); skip_to_next_node(s); with current_indent = current_column(s), // TODO : this return "null" if list character "- " is on the same column as the key first character (it should not) if current_indent =< parent_indent then success(null) else read_value(s, yaml_p_info(parent_indent, current_indent, level + 1), block, so_far), block then unput_byte(c, s); //println("block level " + level); skip_to_next_node(s); with current_indent = current_column(s), if _read_node(s, yaml_p_info(current_indent, current_indent, level), none, []) is { failure then success(null), success(node_type) then if node_type is { map(yaml_kvl) then //println("map node"); if read_block_maps(s, p_info, current_indent, yaml_kvl) is { failure then success(map(var(reverse(yaml_kvl)))), success(list_kv) then success(map(var(reverse(list_kv)))) } list(yaml_lv) then //println("list node"); if read_block_list(s, p_info, current_indent, yaml_lv) is { failure then success(list(var(yaml_lv))), success(list_v) then success(list(var(reverse(list_v)))) } value(yaml_value) then //println("value node"); success(yaml_value) } } } }. define Maybe(List(YAML_Value)) read_values ( Word8 c, Stream s, YAML_Parser_Info p_info, List(YAML_Value) so_far )= if c = '-' then if read_byte(s) is { failure then success(reverse(so_far)), success(next_char) then if next_char = ' ' then skip_spaces(s); //println("found a list"); since p_info is yaml_p_info(parent_indent, context_indent, level), with current_indent = current_column(s), if (current_indent-1) =< parent_indent then success(so_far) else if read_value(s, yaml_p_info((current_indent-1), current_indent, level), block, []) is { failure then success(so_far), success(v) then if read_byte(s) is { failure then success([v . so_far]), success(next_next_char) then read_values(next_next_char, s, p_info, [v . so_far]) } } else unput_byte(next_char, s); unput_byte(c, s); success(so_far), } else unput_byte(c, s); success(so_far). define Maybe(YAML_Parser_Node) get_key_node ( Stream s, YAML_Parser_Info p_info, List(Word8) so_far )= if read_byte(s) is { failure then with key_name = implode(reverse(so_far)), success(map([key_value(key_name, var(null))])), success(next_char) then if eol(s, next_char) then // \n unput_byte(next_char, s); with key_name = implode(reverse(so_far)), //println("key found [LF] \n name: " + key_name); skip_spaces(s); with value = read_value(s, p_info, none, []), if value is { failure then failure, success(v) then success(map([key_value(key_name, var(v))])) } else if next_char = ' ' then with key_name = implode(reverse(so_far)), //println("key found [ ]\n name: " + key_name); skip_spaces(s); with value = read_value(s, p_info, none, []), if value is { failure then failure, success(v) then success(map([key_value(key_name, var(v))])) } else failure //_read_node(s, p_info, unquoted, [next_char . [c . so_far]]) }. define Maybe(YAML_Parser_Node) _read_node ( Stream s, YAML_Parser_Info p_info, YAML_Parser_Node_Info node_info, List(Word8) so_far )= if read_byte(s) is { failure then failure, success(c) then if node_info is { none then if c = '-' then if read_values(c, s, p_info, []) is { failure then failure, success(lv) then success(list(lv)) } else if c = '\"' then _read_node(s, p_info, in_double_quote, so_far) else if c = '\'' then _read_node(s, p_info, in_single_quote, so_far) else _read_node(s, p_info, unquoted, [ c . so_far ]), unquoted then if c = ':' then get_key_node(s, p_info, so_far) else if eol(s, c) then with str = implode(reverse(so_far)), //println("value (str): " + str); success(value(get_yaml_value(str))) else if c = '#' then with str = implode(reverse(so_far)), skip_to_next_line(s); success(value(get_yaml_value(str))) else //println("" + implode(reverse(so_far))); _read_node(s, p_info, unquoted, [ c . so_far ]), in_single_quote then todo, in_double_quote then todo // _read_node(s, p_info, in_double_quote, [ c . so_far ]) } }. public define Maybe(YAML_Document) get_yaml_document_content ( Stream s, YAML_Document doc )= //skip all blanks of begin of line skip_spaces(s); with indent = current_column(s), if read_byte(s) is { failure then //println("skipping blank line"); //get_yaml_document_content(s, doc), //blank line success(doc) success(c) then //check for comment if eol(s, c) then get_yaml_document_content(s, doc) else if c = '#' then //println("skipping comment ["+line+"]"); skip_to_next_line(s); get_yaml_document_content(s, doc) //check for entry of the map else unput_byte(c, s); //println("map entry indent["+indent+"]");//["+line+"]"); with mb_node = _read_node(s, yaml_p_info(indent, indent, 0), none, /*make_stream(line)*/[]), if mb_node is { failure then println("Can't parse YAML node at column " + current_column(s) + " line " + current_line(s)); get_yaml_document_content(s, doc), success(node_type) then since doc is yaml_document(nodes), if node_type is { map(yaml_kv) then nodes <- [map(var(yaml_kv)) . *nodes]; get_yaml_document_content(s, yaml_document(nodes)) list(yaml_lv) then nodes <- [list(var(yaml_lv)) . *nodes]; get_yaml_document_content(s, yaml_document(nodes)) value(yaml_value) then //println("Value found on root"); failure } } }. //read_byte public define Maybe(YAML_Document) get_yaml_document ( Stream s, )= if read_line(s) is { failure then failure, success(line) then if start_with(line, "---") then println("Start parsing YAML document"); get_yaml_document_content(s, yaml_document(var([]))) else get_yaml_document(s) }. public define YAML parse_YAML_file ( Stream s, Var(List(YAML_Document)) docs )= if get_yaml_document(s) is { failure then yaml(var(reverse(*docs))), success(doc) then docs <- [doc . *docs]; parse_YAML_file(s, docs) }. public define YAML parse_YAML_file ( Stream s )= if read_line(s) is { failure then yaml(var([])), success(line) then if start_with(line, "%YAML 1.1") then println("%YAML 1.1 file"); parse_YAML_file(s, var([])) else yaml(var([])) }.