modl 0.0.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +15 -0
  3. data/.idea/vcs.xml +6 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +5 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +4 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +9 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +52 -0
  12. data/Rakefile +6 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/grammar_tests/1.modl +1 -0
  16. data/grammar_tests/2.modl +1 -0
  17. data/grammar_tests/3.modl +1 -0
  18. data/grammar_tests/a.modl +1 -0
  19. data/grammar_tests/b.modl +1 -0
  20. data/grammar_tests/base_tests.json +996 -0
  21. data/grammar_tests/c.modl +1 -0
  22. data/grammar_tests/demo_config.modl +9 -0
  23. data/grammar_tests/error_tests.json +70 -0
  24. data/grammar_tests/import_config.modl +9 -0
  25. data/grammar_tests/test_import_dir/nested_import1.txt +1 -0
  26. data/grammar_tests/test_import_dir/nested_import2.txt +1 -0
  27. data/grammar_tests/test_import_dir/nested_import3.txt +1 -0
  28. data/grammar_tests/test_import_dir/test_import.txt +9 -0
  29. data/lib/modl/interpreter.rb +10 -0
  30. data/lib/modl/parser/MODLLexer.interp +136 -0
  31. data/lib/modl/parser/MODLLexer.rb +324 -0
  32. data/lib/modl/parser/MODLLexer.tokens +41 -0
  33. data/lib/modl/parser/MODLParser.interp +95 -0
  34. data/lib/modl/parser/MODLParser.rb +2504 -0
  35. data/lib/modl/parser/MODLParser.tokens +41 -0
  36. data/lib/modl/parser/MODLParserBaseListener.rb +164 -0
  37. data/lib/modl/parser/MODLParserBaseVisitor.rb +107 -0
  38. data/lib/modl/parser/MODLParserListener.rb +151 -0
  39. data/lib/modl/parser/MODLParserVisitor.rb +56 -0
  40. data/lib/modl/parser/class_processor.rb +159 -0
  41. data/lib/modl/parser/evaluator.rb +164 -0
  42. data/lib/modl/parser/file_importer.rb +64 -0
  43. data/lib/modl/parser/global_parse_context.rb +249 -0
  44. data/lib/modl/parser/instruction_processor.rb +58 -0
  45. data/lib/modl/parser/interpreter.rb +38 -0
  46. data/lib/modl/parser/modl_class.rb +102 -0
  47. data/lib/modl/parser/modl_index.rb +30 -0
  48. data/lib/modl/parser/modl_keylist.rb +43 -0
  49. data/lib/modl/parser/modl_method.rb +132 -0
  50. data/lib/modl/parser/object_cache.rb +54 -0
  51. data/lib/modl/parser/parsed.rb +1410 -0
  52. data/lib/modl/parser/parser.rb +42 -0
  53. data/lib/modl/parser/ref_processor.rb +139 -0
  54. data/lib/modl/parser/substitutions.rb +67 -0
  55. data/lib/modl/parser/sutil.rb +78 -0
  56. data/lib/modl/parser/throwing_error_listener.rb +20 -0
  57. data/lib/modl/parser/version.rb +5 -0
  58. data/modl.gemspec +32 -0
  59. metadata +138 -11
  60. data/lib/modl.rb +0 -5
@@ -0,0 +1,41 @@
1
+ WS=1
2
+ NULL=2
3
+ TRUE=3
4
+ FALSE=4
5
+ COLON=5
6
+ EQUALS=6
7
+ STRUCT_SEP=7
8
+ ARR_SEP=8
9
+ LBRAC=9
10
+ RBRAC=10
11
+ LSBRAC=11
12
+ RSBRAC=12
13
+ NUMBER=13
14
+ COMMENT=14
15
+ STRING=15
16
+ HASH_PREFIX=16
17
+ QUOTED=17
18
+ GRAVED=18
19
+ LCBRAC=19
20
+ CWS=20
21
+ QMARK=21
22
+ FSLASH=22
23
+ GTHAN=23
24
+ LTHAN=24
25
+ ASTERISK=25
26
+ AMP=26
27
+ PIPE=27
28
+ EXCLAM=28
29
+ CCOMMENT=29
30
+ RCBRAC=30
31
+ ','=8
32
+ '{'=19
33
+ '?'=21
34
+ '/'=22
35
+ '>'=23
36
+ '<'=24
37
+ '*'=25
38
+ '&'=26
39
+ '|'=27
40
+ '!'=28
41
+ '}'=30
@@ -0,0 +1,164 @@
1
+ # Generated from MODLParser.g4 by ANTLR 4.7.2
2
+ require 'antlr4/runtime'
3
+
4
+ module Modl::Parser
5
+
6
+ class MODLParserBaseListener < MODLParserListener
7
+ def enterModl(ctx)
8
+ end
9
+
10
+ def exitModl(ctx)
11
+ end
12
+
13
+ def enterModl_structure(ctx)
14
+ end
15
+
16
+ def exitModl_structure(ctx)
17
+ end
18
+
19
+ def enterModl_map(ctx)
20
+ end
21
+
22
+ def exitModl_map(ctx)
23
+ end
24
+
25
+ def enterModl_array(ctx)
26
+ end
27
+
28
+ def exitModl_array(ctx)
29
+ end
30
+
31
+ def enterModl_nb_array(ctx)
32
+ end
33
+
34
+ def exitModl_nb_array(ctx)
35
+ end
36
+
37
+ def enterModl_pair(ctx)
38
+ end
39
+
40
+ def exitModl_pair(ctx)
41
+ end
42
+
43
+ def enterModl_value_item(ctx)
44
+ end
45
+
46
+ def exitModl_value_item(ctx)
47
+ end
48
+
49
+ def enterModl_top_level_conditional(ctx)
50
+ end
51
+
52
+ def exitModl_top_level_conditional(ctx)
53
+ end
54
+
55
+ def enterModl_top_level_conditional_return(ctx)
56
+ end
57
+
58
+ def exitModl_top_level_conditional_return(ctx)
59
+ end
60
+
61
+ def enterModl_map_conditional(ctx)
62
+ end
63
+
64
+ def exitModl_map_conditional(ctx)
65
+ end
66
+
67
+ def enterModl_map_conditional_return(ctx)
68
+ end
69
+
70
+ def exitModl_map_conditional_return(ctx)
71
+ end
72
+
73
+ def enterModl_map_item(ctx)
74
+ end
75
+
76
+ def exitModl_map_item(ctx)
77
+ end
78
+
79
+ def enterModl_array_conditional(ctx)
80
+ end
81
+
82
+ def exitModl_array_conditional(ctx)
83
+ end
84
+
85
+ def enterModl_array_conditional_return(ctx)
86
+ end
87
+
88
+ def exitModl_array_conditional_return(ctx)
89
+ end
90
+
91
+ def enterModl_array_item(ctx)
92
+ end
93
+
94
+ def exitModl_array_item(ctx)
95
+ end
96
+
97
+ def enterModl_value_conditional(ctx)
98
+ end
99
+
100
+ def exitModl_value_conditional(ctx)
101
+ end
102
+
103
+ def enterModl_value_conditional_return(ctx)
104
+ end
105
+
106
+ def exitModl_value_conditional_return(ctx)
107
+ end
108
+
109
+ def enterModl_condition_test(ctx)
110
+ end
111
+
112
+ def exitModl_condition_test(ctx)
113
+ end
114
+
115
+ def enterModl_operator(ctx)
116
+ end
117
+
118
+ def exitModl_operator(ctx)
119
+ end
120
+
121
+ def enterModl_condition(ctx)
122
+ end
123
+
124
+ def exitModl_condition(ctx)
125
+ end
126
+
127
+ def enterModl_condition_group(ctx)
128
+ end
129
+
130
+ def exitModl_condition_group(ctx)
131
+ end
132
+
133
+ def enterModl_value(ctx)
134
+ end
135
+
136
+ def exitModl_value(ctx)
137
+ end
138
+
139
+ def enterModl_array_value_item(ctx)
140
+ end
141
+
142
+ def exitModl_array_value_item(ctx)
143
+ end
144
+
145
+ def enterModl_primitive(ctx)
146
+ end
147
+
148
+ def exitModl_primitive(ctx)
149
+ end
150
+
151
+ def enter_every_rule(ctx)
152
+ end
153
+
154
+ def exit_every_rule(ctx)
155
+ end
156
+
157
+ def visit_terminal(node)
158
+ end
159
+
160
+ def visit_error_node(node)
161
+ end
162
+
163
+ end
164
+ end
@@ -0,0 +1,107 @@
1
+ # Generated from MODLParser.g4 by ANTLR 4.7.2
2
+
3
+ require 'antlr4/runtime'
4
+
5
+
6
+ module Modl::Parser
7
+
8
+ class MODLParserBaseVisitor < Antlr4::Runtime::AbstractParseTreeVisitor
9
+ def visitModl( ctx)
10
+ return visit_children(ctx)
11
+ end
12
+
13
+ def visitModl_structure( ctx)
14
+ return visit_children(ctx)
15
+ end
16
+
17
+ def visitModl_map( ctx)
18
+ return visit_children(ctx)
19
+ end
20
+
21
+ def visitModl_array( ctx)
22
+ return visit_children(ctx)
23
+ end
24
+
25
+ def visitModl_nb_array( ctx)
26
+ return visit_children(ctx)
27
+ end
28
+
29
+ def visitModl_pair( ctx)
30
+ return visit_children(ctx)
31
+ end
32
+
33
+ def visitModl_value_item( ctx)
34
+ return visit_children(ctx)
35
+ end
36
+
37
+ def visitModl_top_level_conditional( ctx)
38
+ return visit_children(ctx)
39
+ end
40
+
41
+ def visitModl_top_level_conditional_return( ctx)
42
+ return visit_children(ctx)
43
+ end
44
+
45
+ def visitModl_map_conditional( ctx)
46
+ return visit_children(ctx)
47
+ end
48
+
49
+ def visitModl_map_conditional_return( ctx)
50
+ return visit_children(ctx)
51
+ end
52
+
53
+ def visitModl_map_item( ctx)
54
+ return visit_children(ctx)
55
+ end
56
+
57
+ def visitModl_array_conditional( ctx)
58
+ return visit_children(ctx)
59
+ end
60
+
61
+ def visitModl_array_conditional_return( ctx)
62
+ return visit_children(ctx)
63
+ end
64
+
65
+ def visitModl_array_item( ctx)
66
+ return visit_children(ctx)
67
+ end
68
+
69
+ def visitModl_value_conditional( ctx)
70
+ return visit_children(ctx)
71
+ end
72
+
73
+ def visitModl_value_conditional_return( ctx)
74
+ return visit_children(ctx)
75
+ end
76
+
77
+ def visitModl_condition_test( ctx)
78
+ return visit_children(ctx)
79
+ end
80
+
81
+ def visitModl_operator( ctx)
82
+ return visit_children(ctx)
83
+ end
84
+
85
+ def visitModl_condition( ctx)
86
+ return visit_children(ctx)
87
+ end
88
+
89
+ def visitModl_condition_group( ctx)
90
+ return visit_children(ctx)
91
+ end
92
+
93
+ def visitModl_value( ctx)
94
+ return visit_children(ctx)
95
+ end
96
+
97
+ def visitModl_array_value_item( ctx)
98
+ return visit_children(ctx)
99
+ end
100
+
101
+ def visitModl_primitive( ctx)
102
+ return visit_children(ctx)
103
+ end
104
+
105
+
106
+ end
107
+ end
@@ -0,0 +1,151 @@
1
+ # Generated from MODLParser.g4 by ANTLR 4.7.2
2
+ module Modl::Parser
3
+ require 'antlr4/runtime'
4
+
5
+ class MODLParserListener < Antlr4::Runtime::ParseTreeListener
6
+ def enterModl(ctx)
7
+ end
8
+
9
+ def exitModl(ctx)
10
+ end
11
+
12
+ def enterModl_structure(ctx)
13
+ end
14
+
15
+ def exitModl_structure(ctx)
16
+ end
17
+
18
+ def enterModl_map(ctx)
19
+ end
20
+
21
+ def exitModl_map(ctx)
22
+ end
23
+
24
+ def enterModl_array(ctx)
25
+ end
26
+
27
+ def exitModl_array(ctx)
28
+ end
29
+
30
+ def enterModl_nb_array(ctx)
31
+ end
32
+
33
+ def exitModl_nb_array(ctx)
34
+ end
35
+
36
+ def enterModl_pair(ctx)
37
+ end
38
+
39
+ def exitModl_pair(ctx)
40
+ end
41
+
42
+ def enterModl_value_item(ctx)
43
+ end
44
+
45
+ def exitModl_value_item(ctx)
46
+ end
47
+
48
+ def enterModl_top_level_conditional(ctx)
49
+ end
50
+
51
+ def exitModl_top_level_conditional(ctx)
52
+ end
53
+
54
+ def enterModl_top_level_conditional_return(ctx)
55
+ end
56
+
57
+ def exitModl_top_level_conditional_return(ctx)
58
+ end
59
+
60
+ def enterModl_map_conditional(ctx)
61
+ end
62
+
63
+ def exitModl_map_conditional(ctx)
64
+ end
65
+
66
+ def enterModl_map_conditional_return(ctx)
67
+ end
68
+
69
+ def exitModl_map_conditional_return(ctx)
70
+ end
71
+
72
+ def enterModl_map_item(ctx)
73
+ end
74
+
75
+ def exitModl_map_item(ctx)
76
+ end
77
+
78
+ def enterModl_array_conditional(ctx)
79
+ end
80
+
81
+ def exitModl_array_conditional(ctx)
82
+ end
83
+
84
+ def enterModl_array_conditional_return(ctx)
85
+ end
86
+
87
+ def exitModl_array_conditional_return(ctx)
88
+ end
89
+
90
+ def enterModl_array_item(ctx)
91
+ end
92
+
93
+ def exitModl_array_item(ctx)
94
+ end
95
+
96
+ def enterModl_value_conditional(ctx)
97
+ end
98
+
99
+ def exitModl_value_conditional(ctx)
100
+ end
101
+
102
+ def enterModl_value_conditional_return(ctx)
103
+ end
104
+
105
+ def exitModl_value_conditional_return(ctx)
106
+ end
107
+
108
+ def enterModl_condition_test(ctx)
109
+ end
110
+
111
+ def exitModl_condition_test(ctx)
112
+ end
113
+
114
+ def enterModl_operator(ctx)
115
+ end
116
+
117
+ def exitModl_operator(ctx)
118
+ end
119
+
120
+ def enterModl_condition(ctx)
121
+ end
122
+
123
+ def exitModl_condition(ctx)
124
+ end
125
+
126
+ def enterModl_condition_group(ctx)
127
+ end
128
+
129
+ def exitModl_condition_group(ctx)
130
+ end
131
+
132
+ def enterModl_value(ctx)
133
+ end
134
+
135
+ def exitModl_value(ctx)
136
+ end
137
+
138
+ def enterModl_array_value_item(ctx)
139
+ end
140
+
141
+ def exitModl_array_value_item(ctx)
142
+ end
143
+
144
+ def enterModl_primitive(ctx)
145
+ end
146
+
147
+ def exitModl_primitive(ctx)
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,56 @@
1
+ # Generated from MODLParser.g4 by ANTLR 4.7.2
2
+ require 'antlr4/runtime'
3
+
4
+ module Modl::Parser
5
+
6
+ class MODLParserVisitor < Antlr4::Runtime::ParseTreeVisitor
7
+ def visitModl(ctx)
8
+ end
9
+ def visitModl_structure(ctx)
10
+ end
11
+ def visitModl_map(ctx)
12
+ end
13
+ def visitModl_array(ctx)
14
+ end
15
+ def visitModl_nb_array(ctx)
16
+ end
17
+ def visitModl_pair(ctx)
18
+ end
19
+ def visitModl_value_item(ctx)
20
+ end
21
+ def visitModl_top_level_conditional(ctx)
22
+ end
23
+ def visitModl_top_level_conditional_return(ctx)
24
+ end
25
+ def visitModl_map_conditional(ctx)
26
+ end
27
+ def visitModl_map_conditional_return(ctx)
28
+ end
29
+ def visitModl_map_item(ctx)
30
+ end
31
+ def visitModl_array_conditional(ctx)
32
+ end
33
+ def visitModl_array_conditional_return(ctx)
34
+ end
35
+ def visitModl_array_item(ctx)
36
+ end
37
+ def visitModl_value_conditional(ctx)
38
+ end
39
+ def visitModl_value_conditional_return(ctx)
40
+ end
41
+ def visitModl_condition_test(ctx)
42
+ end
43
+ def visitModl_operator(ctx)
44
+ end
45
+ def visitModl_condition(ctx)
46
+ end
47
+ def visitModl_condition_group(ctx)
48
+ end
49
+ def visitModl_value(ctx)
50
+ end
51
+ def visitModl_array_value_item(ctx)
52
+ end
53
+ def visitModl_primitive(ctx)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,159 @@
1
+ module Modl
2
+ module Parser
3
+ # This class handles the conversion of objects that refer to classes into instances of those classes.
4
+ # It works recursively since class usage can be nested.
5
+ class ClassProcessor
6
+ # How deep can the class structure be?
7
+ MAX_RECURSION_DEPTH = 20
8
+ # global is a GlobalParseContext and obj is the extracted Array or Hash from Modl::Parser::Parsed.extract_json
9
+ def self.process(global, obj)
10
+ # Process each object in the array or just process the object if its a hash.
11
+ # Any other object is ignored.
12
+ raise StandardError, 'parameter "global" should be a GlobalParseContext' unless global.is_a?(GlobalParseContext)
13
+
14
+ if obj.is_a? Array
15
+ obj.each do |o|
16
+ process_obj global, o if o.is_a? Hash
17
+ end
18
+ elsif obj.is_a? Hash
19
+ process_obj global, obj
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # Process the contents of the supplied hash obj
26
+ def self.process_obj(global, obj)
27
+ obj.keys.each do |k|
28
+ value = obj[k]
29
+ # Does the key refer to a class that we have parsed or loaded?
30
+ clazz = global.classs(k)
31
+ if clazz
32
+ # Yes so convert this value to an instance of that class
33
+ new_k, new_v = process_class global, k, value
34
+ # Replace the existing object with the new class instance and a new key
35
+ obj.delete k
36
+ obj[new_k] = new_v
37
+ end
38
+ # Recurse into the value in case it has contents that also refer to classes.
39
+ process global, value
40
+ end
41
+ end
42
+
43
+ # Convert the supplied object val into an instance of the class with key k
44
+ def self.process_class(global, k, v)
45
+ clazz = global.classs(k)
46
+ new_value = transform_to_class(clazz, global, v)
47
+
48
+ if v.is_a?(Array)
49
+ new_value = v if new_value.empty?
50
+ else
51
+ # Check the top class and do some type-specific processing
52
+ tc = top_class(clazz, global)
53
+ if tc == 'str'
54
+ new_value = v.to_s
55
+ elsif tc == 'num' && !v.is_a?(Numeric)
56
+ raise InterpreterError, 'Superclass of "' + clazz.id + '" is num - cannot assign String value "' + v.to_s + '"'
57
+ elsif tc == 'map'
58
+ if v.is_a? Hash
59
+ # Bring down values from the superclass hierarchy
60
+ new_value = copy_from_superclasses(clazz, global, new_value, v)
61
+ else
62
+ new_value[k] = v
63
+ end
64
+ else
65
+ new_value = v
66
+ end
67
+ end
68
+
69
+ process_nested_classes(global, new_value)
70
+ [clazz.name_or_id, new_value]
71
+ end
72
+
73
+ # Bring down values from the superclass hierarchy
74
+ def self.copy_from_superclasses(clazz, global, new_value, v)
75
+ new_value = v.merge(new_value)
76
+ depth = 0
77
+ loop do
78
+ clazz = global.classs(clazz.superclass)
79
+ break if clazz.nil? || depth > MAX_RECURSION_DEPTH
80
+
81
+ clazz.merge_content(new_value)
82
+ depth += 1
83
+ end
84
+ new_value
85
+ end
86
+
87
+ # Transfer the keys from val to the new_value object.
88
+ def self.copy_keys_to_new_value(new_value, val)
89
+ val.each do |value|
90
+ next unless value&.is_a?(Hash)
91
+
92
+ new_value.merge!(value)
93
+ end
94
+ end
95
+
96
+ # If the new_value has nested class references then process those recursively as well.
97
+ def self.process_nested_classes(global, new_value)
98
+ return unless new_value.is_a? Hash
99
+
100
+ new_value.keys.each do |nk|
101
+ clazz = global.classs(nk)
102
+ nv = new_value[nk]
103
+ next unless clazz # skip it if it doesn't refer to a class
104
+
105
+ if !nv.nil? && !nv.is_a?(String) && !nv.is_a?(Numeric)
106
+ new_k, new_v = process_class global, nk, nv
107
+ else
108
+ new_k = clazz.name_or_id
109
+ new_v = nv
110
+ end
111
+
112
+ # Replace the value for this key if we've changed anything.
113
+ if new_value[new_k] != new_v
114
+ new_value.delete nk
115
+ new_value[new_k] = new_v
116
+ end
117
+ end
118
+ end
119
+
120
+ # Process the *assign lists ('keylist' in this code) and any extra pairs defined by the class.
121
+ # The id, name, and superclass can be ignored here.
122
+ def self.transform_to_class(clazz, global, v)
123
+ new_value = {} # the replacement for val after conversion to a class instance
124
+
125
+ # Process the key list if we found one otherwise raise an error
126
+ # Slightly different processing for hashes and arrays
127
+ if v.is_a? Hash
128
+ keys = clazz.keylist_of_length(v.length)
129
+ lam = ->(i) {v[v.keys[i]]}
130
+ elsif v.is_a? Array
131
+ keys = clazz.keylist_of_length(v.length)
132
+ lam = ->(i) {v[i]}
133
+ end
134
+
135
+ keys&.each_index do |i|
136
+ new_value[keys[i]] = lam.call(i)
137
+ end
138
+
139
+ new_value.keys do |nk|
140
+ process_obj global, new_value[nk]
141
+ end
142
+
143
+ clazz.merge_content(new_value)
144
+ end
145
+
146
+ # Get the top level class for the supplied class
147
+ def self.top_class(clazz, global, depth = 0)
148
+ # Check for self-referential classes that cause infinite recursion
149
+ return if depth > MAX_RECURSION_DEPTH
150
+
151
+ superclass = clazz.superclass
152
+ c = global.classs(superclass)
153
+ return top_class(c, global, depth + 1) if c
154
+
155
+ superclass
156
+ end
157
+ end
158
+ end
159
+ end