modl 0.0.2 → 0.3.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 +5 -5
- data/.gitignore +15 -0
- data/.idea/vcs.xml +6 -0
- data/.rspec +3 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +4 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/grammar_tests/1.modl +1 -0
- data/grammar_tests/2.modl +1 -0
- data/grammar_tests/3.modl +1 -0
- data/grammar_tests/a.modl +1 -0
- data/grammar_tests/b.modl +1 -0
- data/grammar_tests/base_tests.json +996 -0
- data/grammar_tests/c.modl +1 -0
- data/grammar_tests/demo_config.modl +9 -0
- data/grammar_tests/error_tests.json +70 -0
- data/grammar_tests/import_config.modl +9 -0
- data/grammar_tests/test_import_dir/nested_import1.txt +1 -0
- data/grammar_tests/test_import_dir/nested_import2.txt +1 -0
- data/grammar_tests/test_import_dir/nested_import3.txt +1 -0
- data/grammar_tests/test_import_dir/test_import.txt +9 -0
- data/lib/modl/interpreter.rb +10 -0
- data/lib/modl/parser/MODLLexer.interp +136 -0
- data/lib/modl/parser/MODLLexer.rb +324 -0
- data/lib/modl/parser/MODLLexer.tokens +41 -0
- data/lib/modl/parser/MODLParser.interp +95 -0
- data/lib/modl/parser/MODLParser.rb +2504 -0
- data/lib/modl/parser/MODLParser.tokens +41 -0
- data/lib/modl/parser/MODLParserBaseListener.rb +164 -0
- data/lib/modl/parser/MODLParserBaseVisitor.rb +107 -0
- data/lib/modl/parser/MODLParserListener.rb +151 -0
- data/lib/modl/parser/MODLParserVisitor.rb +56 -0
- data/lib/modl/parser/class_processor.rb +159 -0
- data/lib/modl/parser/evaluator.rb +164 -0
- data/lib/modl/parser/file_importer.rb +64 -0
- data/lib/modl/parser/global_parse_context.rb +249 -0
- data/lib/modl/parser/instruction_processor.rb +58 -0
- data/lib/modl/parser/interpreter.rb +38 -0
- data/lib/modl/parser/modl_class.rb +102 -0
- data/lib/modl/parser/modl_index.rb +30 -0
- data/lib/modl/parser/modl_keylist.rb +43 -0
- data/lib/modl/parser/modl_method.rb +132 -0
- data/lib/modl/parser/object_cache.rb +54 -0
- data/lib/modl/parser/parsed.rb +1410 -0
- data/lib/modl/parser/parser.rb +42 -0
- data/lib/modl/parser/ref_processor.rb +139 -0
- data/lib/modl/parser/substitutions.rb +67 -0
- data/lib/modl/parser/sutil.rb +78 -0
- data/lib/modl/parser/throwing_error_listener.rb +20 -0
- data/lib/modl/parser/version.rb +5 -0
- data/modl.gemspec +32 -0
- metadata +138 -11
- 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
|