5
5
* you may not use this file except in compliance with the License.
6
6
* You may obtain a copy of the License at
7
7
*
8
- * https://www.apache.org/licenses/LICENSE-2.0
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
9
*
10
10
* Unless required by applicable law or agreed to in writing, software
11
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
- *
16
15
*/
17
16
18
17
package com.smeup.rpgparser.interpreter
19
18
19
+ import com.smeup.rpgparser.execution.Configuration
20
20
import com.smeup.rpgparser.execution.MainExecutionContext
21
21
import com.smeup.rpgparser.logging.ProgramUsageType
22
22
import com.smeup.rpgparser.parsing.ast.*
@@ -39,9 +39,13 @@ class RpgProgram(val cu: CompilationUnit, val name: String = "<UNNAMED RPG PROGR
39
39
40
40
private var systemInterface: SystemInterface ? = null
41
41
42
+ private val configuration: Configuration by lazy {
43
+ MainExecutionContext .getConfiguration()
44
+ }
45
+
42
46
private val interpreter: InternalInterpreter by lazy {
43
47
val interpreterCore = InternalInterpreter (this .systemInterface!! )
44
- MainExecutionContext .getConfiguration() .jarikoCallback.onInterpreterCreation(interpreterCore)
48
+ configuration .jarikoCallback.onInterpreterCreation(interpreterCore)
45
49
interpreterCore
46
50
}
47
51
@@ -82,102 +86,122 @@ class RpgProgram(val cu: CompilationUnit, val name: String = "<UNNAMED RPG PROGR
82
86
}
83
87
84
88
override fun execute (systemInterface : SystemInterface , params : LinkedHashMap <String , Value >): List <Value > {
85
- val expectedKeys = params().asSequence().map { it.name }.toSet()
89
+ val callback = configuration.jarikoCallback
90
+ val trace = JarikoTrace (JarikoTraceKind .RpgProgram , this .name)
91
+ return callback.traceBlock(trace) {
92
+ val expectedKeys = params().asSequence().map { it.name }.toSet()
86
93
87
- // Original params passed from the caller
88
- val callerParams = LinkedHashMap (params)
94
+ // Original params passed from the caller
95
+ val callerParams = LinkedHashMap (params)
89
96
90
- if (expectedKeys.size <= params.size) {
91
- require(params.keys.toSet() == params().asSequence().map { it.name }.toSet()) {
92
- " Expected params: ${params().asSequence().map { it.name }.joinToString(" , " )} "
93
- }
94
- } else {
95
- require(params().asSequence().map { it.name }.toSet().all { it in expectedKeys }) {
96
- " Expected params: ${params().asSequence().map { it.name }.joinToString(" , " )} "
97
- }
98
-
99
- // Set not passed params to NullValue
100
- params().forEach {
101
- if (it.name !in params.keys) {
102
- params[it.name] = NullValue
97
+ if (expectedKeys.size <= params.size) {
98
+ require(params.keys.toSet() == params().asSequence().map { it.name }.toSet()) {
99
+ " Expected params: ${params().asSequence().map { it.name }.joinToString(" , " )} "
100
+ }
101
+ } else {
102
+ require(params().asSequence().map { it.name }.toSet().all { it in expectedKeys }) {
103
+ " Expected params: ${params().asSequence().map { it.name }.joinToString(" , " )} "
103
104
}
104
- }
105
- }
106
- this .systemInterface = systemInterface
107
- val logSource = { LogSourceData .fromProgram(name) }
108
- logHandlers.renderLog(LazyLogEntry .produceStatement(logSource, " INTERPRETATION" , " START" ))
109
- val changedInitialValues: List <Value >
110
- val elapsed = measureNanoTime {
111
- interpreter.setInterpretationContext(object : InterpretationContext {
112
- private var iDataWrapUpChoice: DataWrapUpChoice ? = null
113
- override val currentProgramName: String
114
- get() = name
115
- override fun shouldReinitialize () = false
116
- override var dataWrapUpChoice: DataWrapUpChoice ?
117
- get() = iDataWrapUpChoice
118
- set(value) {
119
- iDataWrapUpChoice = value
120
- }
121
- })
122
105
123
- for (pv in params) {
124
- val expectedType = params().find { it.name == pv.key } !! .type
125
- val coercedValue = coerce(pv.value, expectedType)
126
- require(coercedValue.assignableTo(expectedType)) {
127
- " param ${pv.key} was expected to have type $expectedType . It has value: $coercedValue "
106
+ // Set not passed params to NullValue
107
+ params().forEach {
108
+ if (it.name !in params.keys) {
109
+ params[it.name] = NullValue
110
+ }
128
111
}
129
112
}
130
- if (! initialized) {
131
- initialized = true
132
-
133
- /* *
134
- * As the RPG program stack is managed outside of this method, it is up to the caller of this method
135
- * to ensure it is in the correct state, that is:
136
- * - `lastIndex` is this RpgProgram
137
- * - `lastIndex - 1` is the RpgProgram that calls this RpgProgram
138
- *
139
- * Note: If these two rules are not followed at this point, do not expect RpgPrograms to behave correctly.
140
- * that means something is wrong with `MainExecutionContext.getProgramStack()` push and pop logic.
141
- */
142
- val programStack = MainExecutionContext .getProgramStack()
143
- val caller = if (programStack.size > 1 ) {
144
- val parentProgramIndex = programStack.lastIndex - 1
145
- programStack[parentProgramIndex]
146
- } else {
147
- null
113
+ this .systemInterface = systemInterface
114
+ val logSource = { LogSourceData .fromProgram(name) }
115
+ logHandlers.renderLog(LazyLogEntry .produceStatement(logSource, " INTERPRETATION" , " START" ))
116
+ val changedInitialValues: List <Value >
117
+ val elapsed = measureNanoTime {
118
+ interpreter.setInterpretationContext(object : InterpretationContext {
119
+ private var iDataWrapUpChoice: DataWrapUpChoice ? = null
120
+ override val currentProgramName: String
121
+ get() = name
122
+
123
+ override fun shouldReinitialize () = false
124
+ override var dataWrapUpChoice: DataWrapUpChoice ?
125
+ get() = iDataWrapUpChoice
126
+ set(value) {
127
+ iDataWrapUpChoice = value
128
+ }
129
+ })
130
+
131
+ for (pv in params) {
132
+ val expectedType = params().find { it.name == pv.key }!! .type
133
+ val coercedValue = coerce(pv.value, expectedType)
134
+ require(coercedValue.assignableTo(expectedType)) {
135
+ " param ${pv.key} was expected to have type $expectedType . It has value: $coercedValue "
136
+ }
148
137
}
138
+ if (! initialized) {
139
+ initialized = true
140
+
141
+ /* *
142
+ * As the RPG program stack is managed outside of this method, it is up to the caller of this method
143
+ * to ensure it is in the correct state, that is:
144
+ * - `lastIndex` is this RpgProgram
145
+ * - `lastIndex - 1` is the RpgProgram that calls this RpgProgram
146
+ *
147
+ * Note: If these two rules are not followed at this point, do not expect RpgPrograms to behave correctly.
148
+ * that means something is wrong with `MainExecutionContext.getProgramStack()` push and pop logic.
149
+ */
150
+ val programStack = MainExecutionContext .getProgramStack()
151
+ val caller = if (programStack.size > 1 ) {
152
+ val parentProgramIndex = programStack.lastIndex - 1
153
+ programStack[parentProgramIndex]
154
+ } else {
155
+ null
156
+ }
149
157
150
- val activationGroupType = cu.activationGroupType()?.let {
151
- when {
152
- // When there is no caller use the default activation group
153
- it is CallerActivationGroup && caller == null ->
154
- NamedActivationGroup (MainExecutionContext .getConfiguration().defaultActivationGroupName)
155
- else -> it
158
+ val activationGroupType = cu.activationGroupType()?.let {
159
+ when {
160
+ // When there is no caller use the default activation group
161
+ it is CallerActivationGroup && caller == null ->
162
+ NamedActivationGroup (configuration.defaultActivationGroupName)
163
+
164
+ else -> it
165
+ }
166
+ } ? : when (caller) {
167
+ // for main program, which does not have a caller, activation group is fixed by config
168
+ null -> NamedActivationGroup (configuration.defaultActivationGroupName)
169
+ else -> CallerActivationGroup
156
170
}
157
- } ? : when (caller) {
158
- // for main program, which does not have a caller, activation group is fixed by config
159
- null -> NamedActivationGroup (MainExecutionContext .getConfiguration().defaultActivationGroupName)
160
- else -> CallerActivationGroup
161
- }
162
171
163
- activationGroup = ActivationGroup (activationGroupType, activationGroupType.assignedName(caller))
172
+ activationGroup = ActivationGroup (activationGroupType, activationGroupType.assignedName(caller))
173
+ }
174
+ configuration.jarikoCallback.onEnterPgm(
175
+ name,
176
+ interpreter.getGlobalSymbolTable()
177
+ )
178
+ // set reinitialization to false because symboltable cleaning currently is handled directly
179
+ // in internal interpreter before exit
180
+ // todo i don't know whether parameter reinitialization has still sense
181
+ interpreter.execute(this .cu, params, false , callerParams)
182
+ configuration.jarikoCallback.onExitPgm(
183
+ name,
184
+ interpreter.getGlobalSymbolTable(),
185
+ null
186
+ )
187
+ params.keys.forEach { params[it] = interpreter[it] }
188
+ changedInitialValues = params().map { interpreter[it.name] }
189
+ // here clear symbol table if needed
190
+ interpreter.doSomethingAfterExecution()
191
+ }.nanoseconds
192
+ if (MainExecutionContext .isLoggingEnabled) {
193
+ logHandlers.renderLog(LazyLogEntry .produceStatement(logSource, " INTERPRETATION" , " END" ))
194
+ logHandlers.renderLog(
195
+ LazyLogEntry .producePerformanceAndUpdateAnalytics(
196
+ logSource,
197
+ ProgramUsageType .Interpretation ,
198
+ " INTERPRETATION" ,
199
+ elapsed
200
+ )
201
+ )
164
202
}
165
- MainExecutionContext .getConfiguration().jarikoCallback.onEnterPgm(name, interpreter.getGlobalSymbolTable())
166
- // set reinitialization to false because symboltable cleaning currently is handled directly
167
- // in internal interpreter before exit
168
- // todo i don't know whether parameter reinitialization has still sense
169
- interpreter.execute(this .cu, params, false , callerParams)
170
- MainExecutionContext .getConfiguration().jarikoCallback.onExitPgm(name, interpreter.getGlobalSymbolTable(), null )
171
- params.keys.forEach { params[it] = interpreter[it] }
172
- changedInitialValues = params().map { interpreter[it.name] }
173
- // here clear symbol table if needed
174
- interpreter.doSomethingAfterExecution()
175
- }.nanoseconds
176
- if (MainExecutionContext .isLoggingEnabled) {
177
- logHandlers.renderLog(LazyLogEntry .produceStatement(logSource, " INTERPRETATION" , " END" ))
178
- logHandlers.renderLog(LazyLogEntry .producePerformanceAndUpdateAnalytics(logSource, ProgramUsageType .Interpretation , " INTERPRETATION" , elapsed))
203
+ changedInitialValues
179
204
}
180
- return changedInitialValues
181
205
}
182
206
183
207
override fun equals (other : Any? ) =
0 commit comments