enolib 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/lib/enolib.rb +42 -0
- data/lib/enolib/constants.rb +16 -0
- data/lib/enolib/context.rb +220 -0
- data/lib/enolib/elements/element.rb +42 -0
- data/lib/enolib/elements/element_base.rb +141 -0
- data/lib/enolib/elements/empty.rb +9 -0
- data/lib/enolib/elements/field.rb +63 -0
- data/lib/enolib/elements/fieldset.rb +151 -0
- data/lib/enolib/elements/fieldset_entry.rb +15 -0
- data/lib/enolib/elements/list.rb +107 -0
- data/lib/enolib/elements/list_item.rb +13 -0
- data/lib/enolib/elements/missing/missing_element_base.rb +44 -0
- data/lib/enolib/elements/missing/missing_empty.rb +13 -0
- data/lib/enolib/elements/missing/missing_field.rb +13 -0
- data/lib/enolib/elements/missing/missing_fieldset.rb +29 -0
- data/lib/enolib/elements/missing/missing_fieldset_entry.rb +13 -0
- data/lib/enolib/elements/missing/missing_list.rb +33 -0
- data/lib/enolib/elements/missing/missing_section.rb +105 -0
- data/lib/enolib/elements/missing/missing_section_element.rb +53 -0
- data/lib/enolib/elements/missing/missing_value_element_base.rb +21 -0
- data/lib/enolib/elements/section.rb +560 -0
- data/lib/enolib/elements/section_element.rb +141 -0
- data/lib/enolib/elements/value_element_base.rb +79 -0
- data/lib/enolib/errors.rb +25 -0
- data/lib/enolib/errors/parsing.rb +136 -0
- data/lib/enolib/errors/selections.rb +83 -0
- data/lib/enolib/errors/validation.rb +146 -0
- data/lib/enolib/grammar_regexp.rb +103 -0
- data/lib/enolib/lookup.rb +235 -0
- data/lib/enolib/messages/de.rb +79 -0
- data/lib/enolib/messages/en.rb +79 -0
- data/lib/enolib/messages/es.rb +79 -0
- data/lib/enolib/parse.rb +9 -0
- data/lib/enolib/parser.rb +708 -0
- data/lib/enolib/register.rb +24 -0
- data/lib/enolib/reporters/html_reporter.rb +115 -0
- data/lib/enolib/reporters/reporter.rb +258 -0
- data/lib/enolib/reporters/terminal_reporter.rb +107 -0
- data/lib/enolib/reporters/text_reporter.rb +46 -0
- metadata +130 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# GENERATED ON 2019-04-10T13:57:55 - DO NOT EDIT MANUALLY
|
4
|
+
|
5
|
+
module Enolib
|
6
|
+
module Messages
|
7
|
+
module De
|
8
|
+
CONTENT_HEADER = 'Inhalt'
|
9
|
+
EXPECTED_EMPTY = 'Ein leeres Element wurde erwartet.'
|
10
|
+
EXPECTED_FIELD = 'Ein Feld wurde erwartet.'
|
11
|
+
EXPECTED_FIELDS = 'Nur Felder wurden erwartet.'
|
12
|
+
EXPECTED_FIELDSET = 'Ein Fieldset wurde erwartet.'
|
13
|
+
EXPECTED_FIELDSET_ENTRY = 'Ein Fieldset Eintrag wurde erwartet.'
|
14
|
+
EXPECTED_FIELDSETS = 'Nur Fieldsets wurden erwartet.'
|
15
|
+
EXPECTED_LIST = 'Eine Liste wurde erwartet.'
|
16
|
+
EXPECTED_LIST_ITEM = 'Ein Listen Eintrag wurde erwartet.'
|
17
|
+
EXPECTED_LISTS = 'Nur Listen wurden erwartet.'
|
18
|
+
EXPECTED_SECTION = 'Eine Sektion wurde erwartet.'
|
19
|
+
EXPECTED_SECTIONS = 'Nur Sektionen wurden erwartet.'
|
20
|
+
EXPECTED_SINGLE_ELEMENT = 'Nur ein einzelnes Element wurde erwartet.'
|
21
|
+
EXPECTED_SINGLE_EMPTY = 'Nur ein einzelnes leeres Element wurde erwartet.'
|
22
|
+
EXPECTED_SINGLE_FIELD = 'Nur ein einzelnes Feld wurde erwartet.'
|
23
|
+
EXPECTED_SINGLE_FIELDSET = 'Nur ein einzelnes Fieldset wurde erwartet.'
|
24
|
+
EXPECTED_SINGLE_FIELDSET_ENTRY = 'Nur ein einzelner Fieldset Eintrag wurde erwartet.'
|
25
|
+
EXPECTED_SINGLE_LIST = 'Nur eine einzelne Liste wurde erwartet.'
|
26
|
+
EXPECTED_SINGLE_SECTION = 'Nur eine einzelne Sektion wurde erwartet.'
|
27
|
+
GUTTER_HEADER = 'Zeile'
|
28
|
+
MISSING_COMMENT = 'Ein erforderlicher Kommentar zu diesem Feld fehlt.'
|
29
|
+
MISSING_ELEMENT = 'Ein einzelnes Element ist erforderlich - es kann einen beliebigen Schlüssel haben.'
|
30
|
+
MISSING_EMPTY = 'Ein einzelnes leeres Element ist erforderlich - es kann einen beliebigen Schlüssel haben.'
|
31
|
+
MISSING_FIELD = 'Ein einzelnes Feld ist erforderlich - es kann einen beliebigen Schlüssel haben.'
|
32
|
+
MISSING_FIELDSET = 'Ein einzelnes Fieldset ist erforderlich - es kann einen beliebigen Schlüssel haben.'
|
33
|
+
MISSING_FIELDSET_ENTRY = 'Ein einzelner Fieldset Eintrag ist erforderlich - er kann einen beliebigen Schlüssel haben.'
|
34
|
+
MISSING_LIST = 'Eine einzelne Liste ist erforderlich - sie kann einen beliebigen Schlüssel haben.'
|
35
|
+
MISSING_SECTION = 'Eine einzelne Sektion ist erforderlich - sie kann einen beliebigen Schlüssel haben.'
|
36
|
+
UNEXPECTED_ELEMENT = 'Dieses Element wurde nicht erwartet, prüfe ob es am richtigen Platz ist und dass der Schlüssel keine Tippfehler enthält.'
|
37
|
+
def self.comment_error(message) "Es gibt ein Problem mit dem Kommentar dieses Elements: #{message}" end
|
38
|
+
def self.cyclic_dependency(line, key) "In Zeile #{line} wird '#{key}' in sich selbst kopiert." end
|
39
|
+
def self.expected_empty_with_key(key) "Ein leeres Element mit dem Schlüssel '#{key}' wurde erwartet." end
|
40
|
+
def self.expected_field_with_key(key) "Ein Feld mit dem Schlüssel '#{key}' wurde erwartet." end
|
41
|
+
def self.expected_fields_with_key(key) "Nur Felder mit dem Schlüssel '#{key}' wurden erwartet." end
|
42
|
+
def self.expected_fieldset_with_key(key) "Ein Fieldset mit dem Schlüssel '#{key}' wurde erwartet." end
|
43
|
+
def self.expected_fieldsets_with_key(key) "Nur Fieldsets mit dem Schlüssel '#{key}' wurden erwartet." end
|
44
|
+
def self.expected_list_with_key(key) "Eine Liste mit dem Schlüssel '#{key}' wurde erwartet." end
|
45
|
+
def self.expected_lists_with_key(key) "Nur Listen mit dem Schlüssel '#{key}' wurden erwartet." end
|
46
|
+
def self.expected_section_with_key(key) "Eine Sektion mit dem Schlüssel '#{key}' wurde erwartet." end
|
47
|
+
def self.expected_sections_with_key(key) "Nur Sektionen mit dem Schlüssel '#{key}' wurden erwartet." end
|
48
|
+
def self.expected_single_element_with_key(key) "Nur ein einzelnes Element mit dem Schlüssel '#{key}' wurde erwartet." end
|
49
|
+
def self.expected_single_empty_with_key(key) "Nur ein einzelnes leeres Element mit dem Schlüssel '#{key}' wurde erwartet." end
|
50
|
+
def self.expected_single_field_with_key(key) "Nur ein einzelnes Feld mit dem Schlüssel '#{key}' wurde erwartet." end
|
51
|
+
def self.expected_single_fieldset_entry_with_key(key) "Nur ein einzelner Fieldset Eintrag mit dem Schlüssel '#{key}' wurde erwartet." end
|
52
|
+
def self.expected_single_fieldset_with_key(key) "Nur ein einzelnes Fieldset mit dem Schlüssel '#{key}' wurde erwartet." end
|
53
|
+
def self.expected_single_list_with_key(key) "Nur eine einzelne Liste mit dem Schlüssel '#{key}' wurde erwartet." end
|
54
|
+
def self.expected_single_section_with_key(key) "Nur eine einzelne Sektion mit dem Schlüssel '#{key}' wurde erwartet." end
|
55
|
+
def self.invalid_line(line) "Zeile #{line} folgt keinem spezifierten Muster." end
|
56
|
+
def self.key_error(message) "Es gibt ein Problem mit dem Schlüssel dieses Elements: #{message}" end
|
57
|
+
def self.missing_element_for_continuation(line) "Zeile #{line} enthält eine Zeilenfortsetzung ohne dass davor ein fortsetzbares Element begonnen wurde." end
|
58
|
+
def self.missing_element_with_key(key) "Das Element '#{key}' fehlt - falls es angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
59
|
+
def self.missing_empty_with_key(key) "Das leere Element '#{key}' fehlt - falls es angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
60
|
+
def self.missing_field_value(key) "Das Feld '#{key}' muss einen Wert enthalten." end
|
61
|
+
def self.missing_field_with_key(key) "Das Feld '#{key}' fehlt - falls es angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
62
|
+
def self.missing_fieldset_entry_value(key) "Der Fieldset Eintrag '#{key}' muss einen Wert enthalten." end
|
63
|
+
def self.missing_fieldset_entry_with_key(key) "Der Fieldset Eintrag '#{key}' fehlt - falls er angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
64
|
+
def self.missing_fieldset_for_fieldset_entry(line) "Zeile #{line} enthält einen Fieldset Eintrag ohne dass davor ein Fieldset begonnen wurde." end
|
65
|
+
def self.missing_fieldset_with_key(key) "Das Fieldset '#{key}' fehlt - falls es angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
66
|
+
def self.missing_list_for_list_item(line) "Zeile #{line} enthält einen Listeneintrag ohne dass davor ein eine Liste begonnen wurde." end
|
67
|
+
def self.missing_list_item_value(key) "Die Liste '#{key}' darf keine leeren Einträge enthalten." end
|
68
|
+
def self.missing_list_with_key(key) "Die Liste '#{key}' fehlt - falls sie angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
69
|
+
def self.missing_section_with_key(key) "Die Sektion '#{key}' fehlt - falls sie angegeben wurde eventuell nach Tippfehlern Ausschau halten und auch die Gross/Kleinschreibung beachten." end
|
70
|
+
def self.non_section_element_not_found(line, key) "In Zeile #{line} soll das Nicht-Sektions Element '#{key}' kopiert werden, es wurde aber nicht gefunden." end
|
71
|
+
def self.section_hierarchy_layer_skip(line) "Zeile #{line} beginnt eine Sektion die mehr als eine Ebene tiefer liegt als die aktuelle." end
|
72
|
+
def self.section_not_found(line, key) "In Zeile #{line} soll die Sektion '#{key}' kopiert werden, sie wurde aber nicht gefunden." end
|
73
|
+
def self.two_or_more_templates_found(key) "Es gibt mindestens zwei Elemente mit dem Schlüssel '#{key}' die hier zum kopieren in Frage kommen, es ist nicht klar welches kopiert werden soll." end
|
74
|
+
def self.unterminated_escaped_key(line) "In Zeile #{line} wird der Schlüssel eines Elements escaped, jedoch wird diese Escape Sequenz bis zum Ende der Zeile nicht mehr beendet." end
|
75
|
+
def self.unterminated_multiline_field(key, line) "Das Mehrzeilenfeld '#{key}' dass in Zeile #{line} beginnt wird bis zum Ende des Dokuments nicht mehr beendet." end
|
76
|
+
def self.value_error(message) "Es gibt ein Problem mit dem Wert dieses Elements: #{message}" end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# GENERATED ON 2019-04-10T13:57:55 - DO NOT EDIT MANUALLY
|
4
|
+
|
5
|
+
module Enolib
|
6
|
+
module Messages
|
7
|
+
module En
|
8
|
+
CONTENT_HEADER = 'Content'
|
9
|
+
EXPECTED_EMPTY = 'An empty element was expected.'
|
10
|
+
EXPECTED_FIELD = 'A field was expected.'
|
11
|
+
EXPECTED_FIELDS = 'Only fields were expected.'
|
12
|
+
EXPECTED_FIELDSET = 'A fieldset was expected.'
|
13
|
+
EXPECTED_FIELDSET_ENTRY = 'A fieldset entry was expected.'
|
14
|
+
EXPECTED_FIELDSETS = 'Only fieldsets were expected.'
|
15
|
+
EXPECTED_LIST = 'A list was expected.'
|
16
|
+
EXPECTED_LIST_ITEM = 'A list item was expected.'
|
17
|
+
EXPECTED_LISTS = 'Only lists were expected.'
|
18
|
+
EXPECTED_SECTION = 'A section was expected.'
|
19
|
+
EXPECTED_SECTIONS = 'Only sections were expected.'
|
20
|
+
EXPECTED_SINGLE_ELEMENT = 'Only a single element was expected.'
|
21
|
+
EXPECTED_SINGLE_EMPTY = 'Only a single empty element was expected.'
|
22
|
+
EXPECTED_SINGLE_FIELD = 'Only a single field was expected.'
|
23
|
+
EXPECTED_SINGLE_FIELDSET = 'Only a single fieldset was expected.'
|
24
|
+
EXPECTED_SINGLE_FIELDSET_ENTRY = 'Only a single fieldset entry was expected.'
|
25
|
+
EXPECTED_SINGLE_LIST = 'Only a single list was expected.'
|
26
|
+
EXPECTED_SINGLE_SECTION = 'Only a single section was expected.'
|
27
|
+
GUTTER_HEADER = 'Line'
|
28
|
+
MISSING_COMMENT = 'A required comment for this element is missing.'
|
29
|
+
MISSING_ELEMENT = 'A single element is required - it can have any key.'
|
30
|
+
MISSING_EMPTY = 'A single empty element is required - it can have any key.'
|
31
|
+
MISSING_FIELD = 'A single field is required - it can have any key.'
|
32
|
+
MISSING_FIELDSET = 'A single fieldset is required - it can have any key.'
|
33
|
+
MISSING_FIELDSET_ENTRY = 'A single fieldset entry is required - it can have any key.'
|
34
|
+
MISSING_LIST = 'A single list is required - it can have any key.'
|
35
|
+
MISSING_SECTION = 'A single section is required - it can have any key.'
|
36
|
+
UNEXPECTED_ELEMENT = 'This element was not expected, make sure it is at the right place in the document and that its key is not mis-typed.'
|
37
|
+
def self.comment_error(message) "There is a problem with the comment of this element: #{message}" end
|
38
|
+
def self.cyclic_dependency(line, key) "In line #{line} '#{key}' is copied into itself." end
|
39
|
+
def self.expected_empty_with_key(key) "An empty element with the key '#{key}' was expected." end
|
40
|
+
def self.expected_field_with_key(key) "A field with the key '#{key}' was expected." end
|
41
|
+
def self.expected_fields_with_key(key) "Only fields with the key '#{key}' were expected." end
|
42
|
+
def self.expected_fieldset_with_key(key) "A fieldset with the key '#{key}' was expected." end
|
43
|
+
def self.expected_fieldsets_with_key(key) "Only fieldsets with the key '#{key}' were expected." end
|
44
|
+
def self.expected_list_with_key(key) "A list with the key '#{key}' was expected." end
|
45
|
+
def self.expected_lists_with_key(key) "Only lists with the key '#{key}' were expected." end
|
46
|
+
def self.expected_section_with_key(key) "A section with the key '#{key}' was expected." end
|
47
|
+
def self.expected_sections_with_key(key) "Only sections with the key '#{key}' were expected." end
|
48
|
+
def self.expected_single_element_with_key(key) "Only a single element with the key '#{key}' was expected." end
|
49
|
+
def self.expected_single_empty_with_key(key) "Only a single empty element with the key '#{key}' was expected." end
|
50
|
+
def self.expected_single_field_with_key(key) "Only a single field with the key '#{key}' was expected." end
|
51
|
+
def self.expected_single_fieldset_entry_with_key(key) "Only a single fieldset entry with the key '#{key}' was expected." end
|
52
|
+
def self.expected_single_fieldset_with_key(key) "Only a single fieldset with the key '#{key}' was expected." end
|
53
|
+
def self.expected_single_list_with_key(key) "Only a single list with the key '#{key}' was expected." end
|
54
|
+
def self.expected_single_section_with_key(key) "Only a single section with the key '#{key}' was expected." end
|
55
|
+
def self.invalid_line(line) "Line #{line} does not follow any specified pattern." end
|
56
|
+
def self.key_error(message) "There is a problem with the key of this element: #{message}" end
|
57
|
+
def self.missing_element_for_continuation(line) "Line #{line} contains a line continuation without a continuable element being specified before." end
|
58
|
+
def self.missing_element_with_key(key) "The element '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
59
|
+
def self.missing_empty_with_key(key) "The empty element '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
60
|
+
def self.missing_field_value(key) "The field '#{key}' must contain a value." end
|
61
|
+
def self.missing_field_with_key(key) "The field '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
62
|
+
def self.missing_fieldset_entry_value(key) "The fieldset entry '#{key}' must contain a value." end
|
63
|
+
def self.missing_fieldset_entry_with_key(key) "The fieldset entry '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
64
|
+
def self.missing_fieldset_for_fieldset_entry(line) "Line #{line} contains a fieldset entry without a fieldset being specified before." end
|
65
|
+
def self.missing_fieldset_with_key(key) "The fieldset '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
66
|
+
def self.missing_list_for_list_item(line) "Line #{line} contains a list item without a list being specified before." end
|
67
|
+
def self.missing_list_item_value(key) "The list '#{key}' may not contain empty items." end
|
68
|
+
def self.missing_list_with_key(key) "The list '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
69
|
+
def self.missing_section_with_key(key) "The section '#{key}' is missing - in case it has been specified look for typos and also check for correct capitalization." end
|
70
|
+
def self.non_section_element_not_found(line, key) "In line #{line} the non-section element '#{key}' should be copied, but it was not found." end
|
71
|
+
def self.section_hierarchy_layer_skip(line) "Line #{line} starts a section that is more than one level deeper than the current one." end
|
72
|
+
def self.section_not_found(line, key) "In line #{line} the section '#{key}' should be copied, but it was not found." end
|
73
|
+
def self.two_or_more_templates_found(key) "There are at least two elements with the key '#{key}' that qualify for being copied here, it is not clear which to copy." end
|
74
|
+
def self.unterminated_escaped_key(line) "In line #{line} the key of an element is escaped, but the escape sequence is not terminated until the end of the line." end
|
75
|
+
def self.unterminated_multiline_field(key, line) "The multiline field '#{key}' starting in line #{line} is not terminated until the end of the document." end
|
76
|
+
def self.value_error(message) "There is a problem with the value of this element: #{message}" end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# GENERATED ON 2019-04-10T13:57:55 - DO NOT EDIT MANUALLY
|
4
|
+
|
5
|
+
module Enolib
|
6
|
+
module Messages
|
7
|
+
module Es
|
8
|
+
CONTENT_HEADER = 'Contenido'
|
9
|
+
EXPECTED_EMPTY = 'Se esperaba un elemento vacío.'
|
10
|
+
EXPECTED_FIELD = 'Se esperaba una casilla.'
|
11
|
+
EXPECTED_FIELDS = 'Solo se esperaban casillas.'
|
12
|
+
EXPECTED_FIELDSET = 'Se esperaba una collecíon de casillas.'
|
13
|
+
EXPECTED_FIELDSET_ENTRY = 'Se esperaba una casilla de collecíon.'
|
14
|
+
EXPECTED_FIELDSETS = 'Solo se esperaban colleciones de casillas.'
|
15
|
+
EXPECTED_LIST = 'Se esperaba una lista.'
|
16
|
+
EXPECTED_LIST_ITEM = 'Se esperaba una entrada de lista.'
|
17
|
+
EXPECTED_LISTS = 'Solo se esperaban listas.'
|
18
|
+
EXPECTED_SECTION = 'Se esperaba una sección.'
|
19
|
+
EXPECTED_SECTIONS = 'Solo se esperaban secciones.'
|
20
|
+
EXPECTED_SINGLE_ELEMENT = 'Solo se esperaba un único elemento.'
|
21
|
+
EXPECTED_SINGLE_EMPTY = 'Solo se esperaba un único elemento vacío.'
|
22
|
+
EXPECTED_SINGLE_FIELD = 'Solo se esperaba una sola casilla.'
|
23
|
+
EXPECTED_SINGLE_FIELDSET = 'Solo se esperaba una sola collecíon de casillas.'
|
24
|
+
EXPECTED_SINGLE_FIELDSET_ENTRY = 'Solo se esperaba una sola casilla de collecíon.'
|
25
|
+
EXPECTED_SINGLE_LIST = 'Solo se esperaba una sola lista.'
|
26
|
+
EXPECTED_SINGLE_SECTION = 'Solo se esperaba una sola sección.'
|
27
|
+
GUTTER_HEADER = 'Línea'
|
28
|
+
MISSING_COMMENT = 'Falta un comentario necesario para este elemento.'
|
29
|
+
MISSING_ELEMENT = 'Se requiere un único elemento - puede tener cualquier clave.'
|
30
|
+
MISSING_EMPTY = 'Se requiere un único elemento vacío - puede tener cualquier clave.'
|
31
|
+
MISSING_FIELD = 'Se requiere una sola casilla - puede tener cualquier clave.'
|
32
|
+
MISSING_FIELDSET = 'Se requiere una sola collecíon de casillas - puede tener cualquier clave.'
|
33
|
+
MISSING_FIELDSET_ENTRY = 'Se requiere una sola casilla de collecíon - puede tener cualquier clave.'
|
34
|
+
MISSING_LIST = 'Se requiere una sola lista - puede tener cualquier clave.'
|
35
|
+
MISSING_SECTION = 'Se requiere una sola sección - puede tener cualquier clave.'
|
36
|
+
UNEXPECTED_ELEMENT = 'Este elemento no se esperaba, averigua si es en el sitio correcto y que no contiene un error tipográfico la clave.'
|
37
|
+
def self.comment_error(message) "Hay un problema con el comentario de este elemento: #{message}" end
|
38
|
+
def self.cyclic_dependency(line, key) "En la línea #{line} '#{key}' se copia en sí mismo." end
|
39
|
+
def self.expected_empty_with_key(key) "Se esperaba un elemento vacío con la clave '#{key}'." end
|
40
|
+
def self.expected_field_with_key(key) "Se esperaba una casilla con la clave '#{key}'." end
|
41
|
+
def self.expected_fields_with_key(key) "Solo se esperaban casillas con la clave '#{key}'." end
|
42
|
+
def self.expected_fieldset_with_key(key) "Se esperaba una collecíon de casillas con la clave '#{key}'." end
|
43
|
+
def self.expected_fieldsets_with_key(key) "Solo se esperaban colleciones de casillas con la clave '#{key}'." end
|
44
|
+
def self.expected_list_with_key(key) "Se esperaba una lista con la clave '#{key}'." end
|
45
|
+
def self.expected_lists_with_key(key) "Solo se esperaban listas con la clave '#{key}'." end
|
46
|
+
def self.expected_section_with_key(key) "Se esperaba una sección con la clave '#{key}'." end
|
47
|
+
def self.expected_sections_with_key(key) "Solo se esperaban secciones con la clave '#{key}'." end
|
48
|
+
def self.expected_single_element_with_key(key) "Solo se esperaba un único elemento con la clave '#{key}'." end
|
49
|
+
def self.expected_single_empty_with_key(key) "Solo se esperaba un único elemento vacío con la clave '#{key}'." end
|
50
|
+
def self.expected_single_field_with_key(key) "Solo se esperaba una sola casilla con la clave '#{key}'." end
|
51
|
+
def self.expected_single_fieldset_entry_with_key(key) "Solo se esperaba una sola casilla de collecíon con la clave '#{key}'." end
|
52
|
+
def self.expected_single_fieldset_with_key(key) "Solo se esperaba una sola collecíon de casillas con la clave '#{key}'." end
|
53
|
+
def self.expected_single_list_with_key(key) "Solo se esperaba una sola lista con la clave '#{key}'." end
|
54
|
+
def self.expected_single_section_with_key(key) "Solo se esperaba una sola sección con la clave '#{key}'." end
|
55
|
+
def self.invalid_line(line) "Línea #{line} no sigue un patrón especificado." end
|
56
|
+
def self.key_error(message) "Hay un problema con la clave de este elemento: #{message}" end
|
57
|
+
def self.missing_element_for_continuation(line) "Línea #{line} contiene una continuacíon de línea sin un elemento que se puede continuar empezado antes." end
|
58
|
+
def self.missing_element_with_key(key) "Falta el elemento '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
59
|
+
def self.missing_empty_with_key(key) "Falta el elemento vacío '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
60
|
+
def self.missing_field_value(key) "La casilla '#{key}' debe contener un valor." end
|
61
|
+
def self.missing_field_with_key(key) "Falta la casilla '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
62
|
+
def self.missing_fieldset_entry_value(key) "La casilla de collecíon '#{key}' debe contener un valor." end
|
63
|
+
def self.missing_fieldset_entry_with_key(key) "Falta la casilla de collecíon '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
64
|
+
def self.missing_fieldset_for_fieldset_entry(line) "Línea #{line} contiene una casilla de collecíon sin una collecíon de casillas empezada antes." end
|
65
|
+
def self.missing_fieldset_with_key(key) "Falta la collecíon de casillas '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
66
|
+
def self.missing_list_for_list_item(line) "Línea #{line} contiene una entrada de lista sin una lista empezada antes." end
|
67
|
+
def self.missing_list_item_value(key) "La lista '#{key}' no debe contener entradas vacías." end
|
68
|
+
def self.missing_list_with_key(key) "Falta la lista '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
69
|
+
def self.missing_section_with_key(key) "Falta la sección '#{key}' - si se proporcionó, mira por errores ortográficos y también distingue entre mayúsculas y minúsculas." end
|
70
|
+
def self.non_section_element_not_found(line, key) "En la línea #{line} debe ser copiado el elemento no sección '#{key}', pero no se encontró." end
|
71
|
+
def self.section_hierarchy_layer_skip(line) "Línea #{line} inicia una sección que es más de un nivel más bajo el actual." end
|
72
|
+
def self.section_not_found(line, key) "En la línea #{line} debe ser copiado la sección '#{key}', pero no se encontró." end
|
73
|
+
def self.two_or_more_templates_found(key) "Hay como mínimo dos elementos con la clave '#{key}' que se clasifiquen para estar copiado, no está claro cual debe ser copiado." end
|
74
|
+
def self.unterminated_escaped_key(line) "En la línea #{line}, la clave de un elemento se escapa, pero esta secuencia de escape no termina hasta el final de la línea." end
|
75
|
+
def self.unterminated_multiline_field(key, line) "La casilla de múltiples líneas '#{key}' que comienza en la línea #{line} no termina hasta el final del documento." end
|
76
|
+
def self.value_error(message) "Hay un problema con el valor de este elemento: #{message}" end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/enolib/parse.rb
ADDED
@@ -0,0 +1,708 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Enolib
|
4
|
+
class Parser
|
5
|
+
def initialize(context)
|
6
|
+
@context = context
|
7
|
+
@depth = 0
|
8
|
+
@index = 0
|
9
|
+
@line = 0
|
10
|
+
@unresolved_non_section_elements = nil
|
11
|
+
@unresolved_sections = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
if @context.input.empty?
|
16
|
+
@context.line_count = 1
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
comments = nil
|
21
|
+
last_continuable_element = nil
|
22
|
+
last_non_section_element = nil
|
23
|
+
last_section = @context.document
|
24
|
+
|
25
|
+
while @index < @context.input.length
|
26
|
+
match = Grammar::REGEX.match(@context.input, @index)
|
27
|
+
|
28
|
+
unless match && match.begin(0) == @index
|
29
|
+
instruction = tokenize_error_context
|
30
|
+
raise Errors::Parsing.invalid_line(@context, instruction)
|
31
|
+
end
|
32
|
+
|
33
|
+
instruction = {
|
34
|
+
index: @index,
|
35
|
+
line: @line,
|
36
|
+
ranges: {
|
37
|
+
line: match.offset(0)
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
multiline_field = false
|
42
|
+
|
43
|
+
if match[Grammar::EMPTY_LINE_INDEX]
|
44
|
+
|
45
|
+
instruction[:type] = :empty_line
|
46
|
+
|
47
|
+
if comments
|
48
|
+
@context.meta.concat(comments)
|
49
|
+
comments = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
elsif match[Grammar::ELEMENT_OPERATOR_INDEX]
|
53
|
+
|
54
|
+
if comments
|
55
|
+
instruction[:comments] = comments
|
56
|
+
comments = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
instruction[:key] = match[Grammar::KEY_UNESCAPED_INDEX]
|
60
|
+
|
61
|
+
if instruction[:key]
|
62
|
+
instruction[:ranges][:element_operator] = match.offset(Grammar::ELEMENT_OPERATOR_INDEX)
|
63
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_UNESCAPED_INDEX)
|
64
|
+
else
|
65
|
+
instruction[:key] = match[Grammar::KEY_ESCAPED_INDEX]
|
66
|
+
instruction[:ranges][:element_operator] = match.offset(Grammar::ELEMENT_OPERATOR_INDEX)
|
67
|
+
instruction[:ranges][:escape_begin_operator] = match.offset(Grammar::KEY_ESCAPE_BEGIN_OPERATOR_INDEX)
|
68
|
+
instruction[:ranges][:escape_end_operator] = match.offset(Grammar::KEY_ESCAPE_END_OPERATOR_INDEX)
|
69
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_ESCAPED_INDEX)
|
70
|
+
end
|
71
|
+
|
72
|
+
value = match[Grammar::FIELD_VALUE_INDEX]
|
73
|
+
|
74
|
+
if value
|
75
|
+
instruction[:ranges][:value] = match.offset(Grammar::FIELD_VALUE_INDEX)
|
76
|
+
instruction[:type] = :field
|
77
|
+
instruction[:value] = value
|
78
|
+
else
|
79
|
+
instruction[:type] = :empty_element
|
80
|
+
end
|
81
|
+
|
82
|
+
instruction[:parent] = last_section
|
83
|
+
last_section[:elements].push(instruction)
|
84
|
+
last_continuable_element = instruction
|
85
|
+
last_non_section_element = instruction
|
86
|
+
|
87
|
+
elsif match[Grammar::LIST_ITEM_OPERATOR_INDEX]
|
88
|
+
|
89
|
+
if comments
|
90
|
+
instruction[:comments] = comments
|
91
|
+
comments = nil
|
92
|
+
end
|
93
|
+
|
94
|
+
instruction[:ranges][:item_operator] = match.offset(Grammar::LIST_ITEM_OPERATOR_INDEX)
|
95
|
+
instruction[:type] = :list_item
|
96
|
+
|
97
|
+
value = match[Grammar::LIST_ITEM_VALUE_INDEX]
|
98
|
+
|
99
|
+
if value
|
100
|
+
instruction[:ranges][:value] = match.offset(Grammar::LIST_ITEM_VALUE_INDEX)
|
101
|
+
instruction[:value] = value
|
102
|
+
end
|
103
|
+
|
104
|
+
if !last_non_section_element
|
105
|
+
instruction = tokenize_error_context
|
106
|
+
raise Errors::Parsing.missing_list_for_list_item(@context, instruction)
|
107
|
+
elsif last_non_section_element[:type] == :list
|
108
|
+
last_non_section_element[:items].push(instruction)
|
109
|
+
elsif last_non_section_element[:type] == :empty_element
|
110
|
+
last_non_section_element[:items] = [instruction]
|
111
|
+
last_non_section_element[:type] = :list
|
112
|
+
else
|
113
|
+
instruction = tokenize_error_context
|
114
|
+
raise Errors::Parsing.missing_list_for_list_item(@context, instruction)
|
115
|
+
end
|
116
|
+
|
117
|
+
instruction[:parent] = last_non_section_element
|
118
|
+
last_continuable_element = instruction
|
119
|
+
|
120
|
+
elsif match[Grammar::FIELDSET_ENTRY_OPERATOR_INDEX]
|
121
|
+
|
122
|
+
if comments
|
123
|
+
instruction[:comments] = comments
|
124
|
+
comments = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
instruction[:type] = :fieldset_entry
|
128
|
+
|
129
|
+
instruction[:key] = match[Grammar::KEY_UNESCAPED_INDEX]
|
130
|
+
|
131
|
+
if instruction[:key]
|
132
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_UNESCAPED_INDEX)
|
133
|
+
instruction[:ranges][:entry_operator] = match.offset(Grammar::FIELDSET_ENTRY_OPERATOR_INDEX)
|
134
|
+
else
|
135
|
+
instruction[:key] = match[Grammar::KEY_ESCAPED_INDEX]
|
136
|
+
instruction[:ranges][:entry_operator] = match.offset(Grammar::FIELDSET_ENTRY_OPERATOR_INDEX)
|
137
|
+
instruction[:ranges][:escape_begin_operator] = match.offset(Grammar::KEY_ESCAPE_BEGIN_OPERATOR_INDEX)
|
138
|
+
instruction[:ranges][:escape_end_operator] = match.offset(Grammar::KEY_ESCAPE_END_OPERATOR_INDEX)
|
139
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_ESCAPED_INDEX)
|
140
|
+
end
|
141
|
+
|
142
|
+
value = match[Grammar::FIELDSET_ENTRY_VALUE_INDEX]
|
143
|
+
|
144
|
+
if value
|
145
|
+
instruction[:ranges][:value] = match.offset(Grammar::FIELDSET_ENTRY_VALUE_INDEX)
|
146
|
+
instruction[:value] = value
|
147
|
+
end
|
148
|
+
|
149
|
+
if !last_non_section_element
|
150
|
+
instruction = tokenize_error_context
|
151
|
+
raise Errors::Parsing.missing_fieldset_for_fieldset_entry(@context, instruction)
|
152
|
+
elsif last_non_section_element[:type] == :fieldset
|
153
|
+
last_non_section_element[:entries].push(instruction)
|
154
|
+
elsif last_non_section_element[:type] == :empty_element
|
155
|
+
last_non_section_element[:entries] = [instruction]
|
156
|
+
last_non_section_element[:type] = :fieldset
|
157
|
+
else
|
158
|
+
instruction = tokenize_error_context
|
159
|
+
raise Errors::Parsing.missing_fieldset_for_fieldset_entry(@context, instruction)
|
160
|
+
end
|
161
|
+
|
162
|
+
instruction[:parent] = last_non_section_element
|
163
|
+
last_continuable_element = instruction
|
164
|
+
|
165
|
+
elsif match[Grammar::SPACED_LINE_CONTINUATION_OPERATOR_INDEX]
|
166
|
+
|
167
|
+
if !last_continuable_element
|
168
|
+
instruction = tokenize_error_context
|
169
|
+
raise Errors::Parsing.missing_element_for_continuation(@context, instruction)
|
170
|
+
end
|
171
|
+
|
172
|
+
instruction[:spaced] = true
|
173
|
+
instruction[:ranges][:spaced_line_continuation_operator] = match.offset(Grammar::SPACED_LINE_CONTINUATION_OPERATOR_INDEX)
|
174
|
+
instruction[:type] = :continuation
|
175
|
+
|
176
|
+
value = match[Grammar::SPACED_LINE_CONTINUATION_VALUE_INDEX]
|
177
|
+
|
178
|
+
if value
|
179
|
+
instruction[:ranges][:value] = match.offset(Grammar::SPACED_LINE_CONTINUATION_VALUE_INDEX)
|
180
|
+
instruction[:value] = value
|
181
|
+
end
|
182
|
+
|
183
|
+
if last_continuable_element.has_key?(:continuations)
|
184
|
+
last_continuable_element[:continuations].push(instruction)
|
185
|
+
else
|
186
|
+
if last_continuable_element[:type] == :empty_element
|
187
|
+
last_continuable_element[:type] = :field
|
188
|
+
end
|
189
|
+
|
190
|
+
last_continuable_element[:continuations] = [instruction]
|
191
|
+
end
|
192
|
+
|
193
|
+
if comments
|
194
|
+
@context.meta.concat(comments)
|
195
|
+
comments = nil
|
196
|
+
end
|
197
|
+
|
198
|
+
elsif match[Grammar::DIRECT_LINE_CONTINUATION_OPERATOR_INDEX]
|
199
|
+
|
200
|
+
if !last_continuable_element
|
201
|
+
instruction = tokenize_error_context
|
202
|
+
raise Errors::Parsing.missing_element_for_continuation(@context, instruction)
|
203
|
+
end
|
204
|
+
|
205
|
+
instruction[:ranges][:direct_line_continuation_operator] = match.offset(Grammar::DIRECT_LINE_CONTINUATION_OPERATOR_INDEX)
|
206
|
+
instruction[:type] = :continuation
|
207
|
+
|
208
|
+
value = match[Grammar::DIRECT_LINE_CONTINUATION_VALUE_INDEX]
|
209
|
+
|
210
|
+
if value
|
211
|
+
instruction[:ranges][:value] = match.offset(Grammar::DIRECT_LINE_CONTINUATION_VALUE_INDEX)
|
212
|
+
instruction[:value] = value
|
213
|
+
end
|
214
|
+
|
215
|
+
if last_continuable_element.has_key?(:continuations)
|
216
|
+
last_continuable_element[:continuations].push(instruction)
|
217
|
+
else
|
218
|
+
if last_continuable_element[:type] == :empty_element
|
219
|
+
last_continuable_element[:type] = :field
|
220
|
+
end
|
221
|
+
|
222
|
+
last_continuable_element[:continuations] = [instruction]
|
223
|
+
end
|
224
|
+
|
225
|
+
if comments
|
226
|
+
@context.meta.concat(comments)
|
227
|
+
comments = nil
|
228
|
+
end
|
229
|
+
|
230
|
+
elsif match[Grammar::SECTION_OPERATOR_INDEX]
|
231
|
+
|
232
|
+
if comments
|
233
|
+
instruction[:comments] = comments
|
234
|
+
comments = nil
|
235
|
+
end
|
236
|
+
|
237
|
+
instruction[:elements] = []
|
238
|
+
instruction[:ranges][:section_operator] = match.offset(Grammar::SECTION_OPERATOR_INDEX)
|
239
|
+
instruction[:type] = :section
|
240
|
+
|
241
|
+
new_depth = instruction[:ranges][:section_operator][1] - instruction[:ranges][:section_operator][0]
|
242
|
+
|
243
|
+
if new_depth == @depth + 1
|
244
|
+
instruction[:parent] = last_section
|
245
|
+
@depth = new_depth
|
246
|
+
elsif new_depth == @depth
|
247
|
+
instruction[:parent] = last_section[:parent]
|
248
|
+
elsif new_depth < @depth
|
249
|
+
while new_depth < @depth
|
250
|
+
last_section = last_section[:parent]
|
251
|
+
@depth -= 1
|
252
|
+
end
|
253
|
+
|
254
|
+
instruction[:parent] = last_section[:parent]
|
255
|
+
else
|
256
|
+
instruction = tokenize_error_context
|
257
|
+
raise Errors::Parsing.section_hierarchy_layer_skip(@context, instruction, last_section)
|
258
|
+
end
|
259
|
+
|
260
|
+
instruction[:parent][:elements].push(instruction)
|
261
|
+
last_section = instruction
|
262
|
+
|
263
|
+
instruction[:key] = match[Grammar::SECTION_KEY_UNESCAPED_INDEX]
|
264
|
+
|
265
|
+
if instruction[:key]
|
266
|
+
instruction[:ranges][:key] = match.offset(Grammar::SECTION_KEY_UNESCAPED_INDEX)
|
267
|
+
else
|
268
|
+
instruction[:key] = match[Grammar::SECTION_KEY_ESCAPED_INDEX]
|
269
|
+
instruction[:ranges][:escape_begin_operator] = match.offset(Grammar::SECTION_KEY_ESCAPE_BEGIN_OPERATOR_INDEX)
|
270
|
+
instruction[:ranges][:escape_end_operator] = match.offset(Grammar::SECTION_KEY_ESCAPE_END_OPERATOR_INDEX)
|
271
|
+
instruction[:ranges][:key] = match.offset(Grammar::SECTION_KEY_ESCAPED_INDEX)
|
272
|
+
end
|
273
|
+
|
274
|
+
template = match[Grammar::SECTION_TEMPLATE_INDEX]
|
275
|
+
|
276
|
+
if template
|
277
|
+
instruction[:ranges][:template] = match.offset(Grammar::SECTION_TEMPLATE_INDEX)
|
278
|
+
instruction[:template] = template
|
279
|
+
|
280
|
+
parent = instruction[:parent]
|
281
|
+
while parent[:type] != :document
|
282
|
+
parent[:deep_resolve] = true
|
283
|
+
parent = parent[:parent]
|
284
|
+
end
|
285
|
+
|
286
|
+
copy_operator_offset = match.offset(Grammar::SECTION_COPY_OPERATOR_INDEX)
|
287
|
+
|
288
|
+
if copy_operator_offset[1] - copy_operator_offset[0] == 2
|
289
|
+
instruction[:deep_copy] = true
|
290
|
+
instruction[:ranges][:deep_copy_operator] = copy_operator_offset
|
291
|
+
else
|
292
|
+
instruction[:ranges][:copy_operator] = copy_operator_offset
|
293
|
+
end
|
294
|
+
|
295
|
+
@unresolved_sections = {} unless @unresolved_sections
|
296
|
+
|
297
|
+
if @unresolved_sections.has_key?(template)
|
298
|
+
@unresolved_sections[template][:targets].push(instruction)
|
299
|
+
else
|
300
|
+
@unresolved_sections[template] = { targets: [instruction] }
|
301
|
+
end
|
302
|
+
|
303
|
+
instruction[:copy] = @unresolved_sections[template]
|
304
|
+
end
|
305
|
+
|
306
|
+
last_continuable_element = nil
|
307
|
+
last_non_section_element = nil
|
308
|
+
|
309
|
+
elsif match[Grammar::MULTILINE_FIELD_OPERATOR_INDEX]
|
310
|
+
|
311
|
+
if comments
|
312
|
+
instruction[:comments] = comments
|
313
|
+
comments = nil
|
314
|
+
end
|
315
|
+
|
316
|
+
operator = match[Grammar::MULTILINE_FIELD_OPERATOR_INDEX]
|
317
|
+
key = match[Grammar::MULTILINE_FIELD_KEY_INDEX]
|
318
|
+
|
319
|
+
instruction[:key] = key
|
320
|
+
instruction[:parent] = last_section
|
321
|
+
instruction[:ranges][:multiline_field_operator] = match.offset(Grammar::MULTILINE_FIELD_OPERATOR_INDEX)
|
322
|
+
instruction[:ranges][:key] = match.offset(Grammar::MULTILINE_FIELD_KEY_INDEX)
|
323
|
+
instruction[:type] = :multiline_field_begin
|
324
|
+
|
325
|
+
@index = match.end(0)
|
326
|
+
|
327
|
+
last_section[:elements].push(instruction)
|
328
|
+
last_continuable_element = nil
|
329
|
+
last_non_section_element = instruction
|
330
|
+
|
331
|
+
terminator_regex = /\n[^\S\n]*(#{operator})(?!-)[^\S\n]*(#{Regexp.escape(key)})[^\S\n]*(?=\n|$)/
|
332
|
+
terminator_match = terminator_regex.match(@context.input, @index)
|
333
|
+
|
334
|
+
@index += 1 # move past current char (\n) into next line
|
335
|
+
@line += 1
|
336
|
+
|
337
|
+
unless terminator_match
|
338
|
+
tokenize_error_context
|
339
|
+
raise Errors::Parsing.unterminated_multiline_field(@context, instruction)
|
340
|
+
end
|
341
|
+
|
342
|
+
end_of_multiline_field_index = terminator_match.begin(0)
|
343
|
+
|
344
|
+
if end_of_multiline_field_index != @index - 1
|
345
|
+
instruction[:lines] = []
|
346
|
+
|
347
|
+
loop do
|
348
|
+
end_of_line_index = @context.input.index("\n", @index)
|
349
|
+
|
350
|
+
if !end_of_line_index || end_of_line_index >= end_of_multiline_field_index
|
351
|
+
last_non_section_element[:lines].push(
|
352
|
+
line: @line,
|
353
|
+
ranges: {
|
354
|
+
line: [@index, end_of_multiline_field_index],
|
355
|
+
value: [@index, end_of_multiline_field_index]
|
356
|
+
},
|
357
|
+
type: :multiline_field_value
|
358
|
+
)
|
359
|
+
|
360
|
+
@index = end_of_multiline_field_index + 1
|
361
|
+
@line += 1
|
362
|
+
|
363
|
+
break
|
364
|
+
else
|
365
|
+
last_non_section_element[:lines].push(
|
366
|
+
line: @line,
|
367
|
+
ranges: {
|
368
|
+
line: [@index, end_of_line_index],
|
369
|
+
value: [@index, end_of_line_index]
|
370
|
+
},
|
371
|
+
type: :multiline_field_value
|
372
|
+
)
|
373
|
+
|
374
|
+
@index = end_of_line_index + 1
|
375
|
+
@line += 1
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
instruction = {
|
381
|
+
length: terminator_match.end(0),
|
382
|
+
line: @line,
|
383
|
+
ranges: {
|
384
|
+
key: terminator_match.offset(2),
|
385
|
+
line: [@index, terminator_match.end(0)],
|
386
|
+
multiline_field_operator: terminator_match.offset(1),
|
387
|
+
},
|
388
|
+
type: :multiline_field_end
|
389
|
+
}
|
390
|
+
|
391
|
+
last_non_section_element[:end] = instruction
|
392
|
+
last_non_section_element = nil
|
393
|
+
|
394
|
+
@index = terminator_match.end(0) + 1
|
395
|
+
@line += 1
|
396
|
+
|
397
|
+
multiline_field = true
|
398
|
+
|
399
|
+
elsif match[Grammar::COMMENT_OPERATOR_INDEX]
|
400
|
+
|
401
|
+
if comments
|
402
|
+
comments.push(instruction)
|
403
|
+
else
|
404
|
+
comments = [instruction]
|
405
|
+
end
|
406
|
+
|
407
|
+
instruction[:ranges][:comment_operator] = match.offset(Grammar::COMMENT_OPERATOR_INDEX)
|
408
|
+
instruction[:type] = :comment
|
409
|
+
|
410
|
+
comment = match[Grammar::COMMENT_VALUE_INDEX]
|
411
|
+
|
412
|
+
if comment
|
413
|
+
instruction[:comment] = comment
|
414
|
+
instruction[:ranges][:comment] = match.offset(Grammar::COMMENT_VALUE_INDEX)
|
415
|
+
end
|
416
|
+
|
417
|
+
elsif match[Grammar::COPY_OPERATOR_INDEX]
|
418
|
+
|
419
|
+
if comments
|
420
|
+
instruction[:comments] = comments
|
421
|
+
comments = nil
|
422
|
+
end
|
423
|
+
|
424
|
+
template = match[Grammar::TEMPLATE_INDEX]
|
425
|
+
|
426
|
+
instruction[:ranges][:copy_operator] = match.offset(Grammar::COPY_OPERATOR_INDEX)
|
427
|
+
instruction[:ranges][:template] = match.offset(Grammar::TEMPLATE_INDEX)
|
428
|
+
instruction[:template] = template
|
429
|
+
instruction[:type] = :empty_element
|
430
|
+
|
431
|
+
instruction[:key] = match[Grammar::KEY_UNESCAPED_INDEX]
|
432
|
+
|
433
|
+
if instruction[:key]
|
434
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_UNESCAPED_INDEX)
|
435
|
+
else
|
436
|
+
instruction[:key] = match[Grammar::KEY_ESCAPED_INDEX]
|
437
|
+
instruction[:ranges][:escape_begin_operator] = match.offset(Grammar::KEY_ESCAPE_BEGIN_OPERATOR_INDEX)
|
438
|
+
instruction[:ranges][:escape_end_operator] = match.offset(Grammar::KEY_ESCAPE_END_OPERATOR_INDEX)
|
439
|
+
instruction[:ranges][:key] = match.offset(Grammar::KEY_ESCAPED_INDEX)
|
440
|
+
end
|
441
|
+
|
442
|
+
instruction[:parent] = last_section
|
443
|
+
last_section[:elements].push(instruction)
|
444
|
+
last_continuable_element = nil
|
445
|
+
last_non_section_element = instruction
|
446
|
+
|
447
|
+
@unresolved_non_section_elements = {} unless @unresolved_non_section_elements
|
448
|
+
|
449
|
+
if @unresolved_non_section_elements.has_key?(template)
|
450
|
+
@unresolved_non_section_elements[template][:targets].push(instruction)
|
451
|
+
else
|
452
|
+
@unresolved_non_section_elements[template] = { targets: [instruction] }
|
453
|
+
end
|
454
|
+
|
455
|
+
instruction[:copy] = @unresolved_non_section_elements[template]
|
456
|
+
end
|
457
|
+
|
458
|
+
unless multiline_field
|
459
|
+
@index = match.end(0) + 1
|
460
|
+
@line += 1
|
461
|
+
end
|
462
|
+
end
|
463
|
+
|
464
|
+
if @context.input[-1] == "\n"
|
465
|
+
@context.line_count = @line + 1
|
466
|
+
else
|
467
|
+
@context.line_count = @line
|
468
|
+
end
|
469
|
+
|
470
|
+
@context.meta.concat(comments) if comments
|
471
|
+
|
472
|
+
resolve if @unresolved_non_section_elements || @unresolved_sections
|
473
|
+
end
|
474
|
+
|
475
|
+
private
|
476
|
+
|
477
|
+
def consolidate_non_section_elements(element, template)
|
478
|
+
if template.has_key?(:comments) && !element.has_key?(:comments)
|
479
|
+
element[:comments] = template[:comments]
|
480
|
+
end
|
481
|
+
|
482
|
+
case element[:type]
|
483
|
+
when :empty_element
|
484
|
+
case template[:type]
|
485
|
+
when :multiline_field_begin
|
486
|
+
element[:type] = :field
|
487
|
+
mirror(element, template)
|
488
|
+
when :field
|
489
|
+
element[:type] = :field
|
490
|
+
mirror(element, template)
|
491
|
+
when :fieldset
|
492
|
+
element[:type] = :fieldset
|
493
|
+
mirror(element, template)
|
494
|
+
when :list
|
495
|
+
element[:type] = :list
|
496
|
+
mirror(element, template)
|
497
|
+
end
|
498
|
+
when :fieldset
|
499
|
+
case template[:type]
|
500
|
+
when :fieldset
|
501
|
+
element[:extend] = template
|
502
|
+
when :field, :list, :multiline_field_begin
|
503
|
+
raise Errors::Parsing.missing_fieldset_for_fieldset_entry(@context, element[:entries].first)
|
504
|
+
end
|
505
|
+
when :list
|
506
|
+
case template[:type]
|
507
|
+
when :list
|
508
|
+
element[:extend] = template
|
509
|
+
when :field, :fieldset, :multiline_field_begin
|
510
|
+
raise Errors::Parsing.missing_list_for_list_item(@context, element[:items].first)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
def consolidate_sections(section, template, deep_merge)
|
516
|
+
if template.has_key?(:comments) && !section.has_key?(:comments)
|
517
|
+
section[:comments] = template[:comments]
|
518
|
+
end
|
519
|
+
|
520
|
+
if section[:elements].empty?
|
521
|
+
mirror(section, template)
|
522
|
+
else
|
523
|
+
# TODO: Handle possibility of two templates (one hardcoded in the document, one implicitly derived through deep merging)
|
524
|
+
# Possibly also elswhere (e.g. up there in the mirror branch?)
|
525
|
+
section[:extend] = template
|
526
|
+
|
527
|
+
return unless deep_merge
|
528
|
+
|
529
|
+
merge_map = {}
|
530
|
+
|
531
|
+
section[:elements].each do |section_element|
|
532
|
+
if section_element[:type] != :section || merge_map.has_key?(section_element[:key])
|
533
|
+
merge_map[section_element[:key]] = false # non-mergable (no section or multiple instructions with same key)
|
534
|
+
else
|
535
|
+
merge_map[section_element[:key]] = { section: section_element }
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
template[:elements].each do |section_element|
|
540
|
+
if merge_map.has_key?(section_element[:key])
|
541
|
+
merger = merge_map[section_element[:key]]
|
542
|
+
|
543
|
+
next unless merger
|
544
|
+
|
545
|
+
if section_element[:type] != :section || merger.has_key?(:template)
|
546
|
+
merge_map[section_element[:key]] = false # non-mergable (no section or multiple template instructions with same key)
|
547
|
+
else
|
548
|
+
merger[:template] = section_element
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
merge_map.each_value do |merger|
|
554
|
+
if merger && merger.has_key?(:template)
|
555
|
+
consolidate_sections(merger[:section], merger[:template], true)
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
def mirror(element, template)
|
562
|
+
if template.has_key?(:mirror)
|
563
|
+
element[:mirror] = template[:mirror]
|
564
|
+
else
|
565
|
+
element[:mirror] = template
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
def index(section)
|
570
|
+
section[:elements].each do |element|
|
571
|
+
if element[:type] == :section
|
572
|
+
index(element)
|
573
|
+
|
574
|
+
if @unresolved_sections &&
|
575
|
+
@unresolved_sections.has_key?(element[:key]) &&
|
576
|
+
element[:key] != element[:template]
|
577
|
+
copy_data = @unresolved_sections[element[:key]]
|
578
|
+
|
579
|
+
if copy_data.has_key?(:template)
|
580
|
+
raise Errors::Parsing.two_or_more_templates_found(@context, copy_data[:targets].first, copy_data[:template], element)
|
581
|
+
end
|
582
|
+
|
583
|
+
copy_data[:template] = element
|
584
|
+
end
|
585
|
+
elsif @unresolved_non_section_elements &&
|
586
|
+
@unresolved_non_section_elements.has_key?(element[:key]) &&
|
587
|
+
element[:key] != element[:template]
|
588
|
+
copy_data = @unresolved_non_section_elements[element[:key]]
|
589
|
+
|
590
|
+
if copy_data.has_key?(:template)
|
591
|
+
raise Errors::Parsing.two_or_more_templates_found(@context, copy_data[:targets].first, copy_data[:template], element)
|
592
|
+
end
|
593
|
+
|
594
|
+
copy_data[:template] = element
|
595
|
+
end
|
596
|
+
end
|
597
|
+
end
|
598
|
+
|
599
|
+
def resolve
|
600
|
+
index(@context.document)
|
601
|
+
|
602
|
+
if @unresolved_non_section_elements
|
603
|
+
@unresolved_non_section_elements.each_value do |copy|
|
604
|
+
unless copy.has_key?(:template)
|
605
|
+
raise Errors::Parsing.non_section_element_not_found(@context, copy[:targets].first)
|
606
|
+
end
|
607
|
+
|
608
|
+
copy[:targets].each do |target|
|
609
|
+
resolve_non_section_element(target) if target.has_key?(:copy)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
if @unresolved_sections
|
615
|
+
@unresolved_sections.each_value do |copy|
|
616
|
+
unless copy.has_key?(:template)
|
617
|
+
raise Errors::Parsing.section_not_found(@context, copy[:targets].first)
|
618
|
+
end
|
619
|
+
|
620
|
+
copy[:targets].each do |target|
|
621
|
+
resolve_section(target) if target.has_key?(:copy)
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
def resolve_non_section_element(element, previous_elements = [])
|
628
|
+
if previous_elements.include?(element)
|
629
|
+
raise Errors::Parsing.cyclic_dependency(@context, element, previous_elements)
|
630
|
+
end
|
631
|
+
|
632
|
+
template = element[:copy][:template]
|
633
|
+
|
634
|
+
if template.has_key?(:copy)
|
635
|
+
resolve_non_section_element(template, [*previous_elements, element])
|
636
|
+
end
|
637
|
+
|
638
|
+
consolidate_non_section_elements(element, template)
|
639
|
+
|
640
|
+
element.delete(:copy)
|
641
|
+
end
|
642
|
+
|
643
|
+
def resolve_section(section, previous_sections = [])
|
644
|
+
if previous_sections.include?(section)
|
645
|
+
raise Errors::Parsing.cyclic_dependency(@context, section, previous_sections)
|
646
|
+
end
|
647
|
+
|
648
|
+
if section.has_key?(:deep_resolve)
|
649
|
+
section[:elements].each do |section_element|
|
650
|
+
if section_element[:type] == :section &&
|
651
|
+
(section_element.has_key?(:copy) || section_element.has_key?(:deep_resolve))
|
652
|
+
resolve_section(section_element, [*previous_sections, section])
|
653
|
+
end
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
if section.has_key?(:copy)
|
658
|
+
template = section[:copy][:template]
|
659
|
+
|
660
|
+
if template.has_key?(:copy) || template.has_key?(:deep_resolve)
|
661
|
+
resolve_section(template, [*previous_sections, section])
|
662
|
+
end
|
663
|
+
|
664
|
+
consolidate_sections(section, template, section.has_key?(:deep_copy))
|
665
|
+
|
666
|
+
section.delete(:copy)
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
def tokenize_error_context
|
671
|
+
first_instruction = nil
|
672
|
+
|
673
|
+
loop do
|
674
|
+
end_of_line_index = @context.input.index("\n", @index)
|
675
|
+
|
676
|
+
if end_of_line_index
|
677
|
+
instruction = {
|
678
|
+
line: @line,
|
679
|
+
ranges: { line: [@index, end_of_line_index] }
|
680
|
+
}
|
681
|
+
|
682
|
+
@context.meta.push(instruction)
|
683
|
+
|
684
|
+
if first_instruction
|
685
|
+
instruction[:type] = :unparsed
|
686
|
+
else
|
687
|
+
first_instruction = instruction
|
688
|
+
end
|
689
|
+
|
690
|
+
@index = end_of_line_index + 1
|
691
|
+
@line += 1
|
692
|
+
else
|
693
|
+
instruction = {
|
694
|
+
line: @line,
|
695
|
+
ranges: { line: [@index, @context.input.length]}
|
696
|
+
}
|
697
|
+
|
698
|
+
instruction[:type] = :unparsed if first_instruction
|
699
|
+
|
700
|
+
@context.line_count = @line + 1
|
701
|
+
@context.meta.push(instruction)
|
702
|
+
|
703
|
+
return first_instruction || instruction
|
704
|
+
end
|
705
|
+
end
|
706
|
+
end
|
707
|
+
end
|
708
|
+
end
|