Skip to content

Commit 293a43c

Browse files
authored
Merge pull request #30 from vitekkor/#25-add-comments-to-code
#25 add comments to code
2 parents e574df7 + 44b5a12 commit 293a43c

File tree

14 files changed

+260
-29
lines changed

14 files changed

+260
-29
lines changed

codeGenerator/src/generators/generator.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939

4040
# noinspection PyUnresolvedReferences,PyTypeChecker,PyArgumentList
4141
class Generator:
42-
# TODO document
42+
4343
def __init__(self, language=None, options=None, logger=None):
4444
assert language is not None, "You must specify the language"
4545
self.language = language
@@ -56,7 +56,6 @@ def __init__(self, language=None, options=None, logger=None):
5656

5757
# This flag is used for Java lambdas where local variables references
5858
# must be final.
59-
# FIXME: may affect
6059
self._inside_java_lambda = False
6160
self._inside_func_body = False
6261

@@ -177,6 +176,12 @@ def generate_main_func(self) -> ast.FunctionDeclaration:
177176
params=[args])
178177

179178
def generate_loop_expr(self, already_in_main: list):
179+
"""
180+
Generate a new loop. One of the three is for, while, do-while.
181+
Iterations can be either using a variable or iterating through a collection.
182+
:param already_in_main: a list of declarations that already exist in the parent block
183+
:return: ast.LoopExpr
184+
"""
180185
res = []
181186
iterable_types = self._get_iterable_types()
182187
random_type_to_iterate = ut.randomUtil.choice(iterable_types)
@@ -285,6 +290,10 @@ def generate_loop_expr(self, already_in_main: list):
285290
return res
286291

287292
def _get_iterable_types(self) -> list[tp.Type]:
293+
"""
294+
Returns a list of iterable types that includes built-in types, user-defined types, and primitive data types
295+
:return: a list of iterable types
296+
"""
288297
builtin_types: list[tp.Type] = [
289298
x for x in self.get_types() if hasattr(x, 'type_args')
290299
]
@@ -2715,49 +2724,60 @@ def _gen_func_body(self, ret_type: tp.Type):
27152724
ast.Block([expr])
27162725
else:
27172726
exprs, decls = self._gen_side_effects()
2718-
if ut.randomUtil.bool():
2727+
if ut.randomUtil.bool(
2728+
): # probabilistic choice whether to generate a cycle in the body of this function
27192729
loop_expr = self.generate_loop_expr(decls)
2730+
2731+
# Get all variable declarations in current context, excluding parameter declarations
27202732
decls_in_context = {
27212733
k: v
27222734
for k, v in self.context.get_vars(
27232735
self.namespace, only_current=True).items()
27242736
if not isinstance(v, ast.ParameterDeclaration)
27252737
}
2738+
# Get all variable declarations in func body, including those declared in loop_expr and decls
27262739
decls_in_body = [
27272740
expr for expr in exprs
27282741
if isinstance(expr, ast.VariableDeclaration)
27292742
] + decls + [
27302743
_var for _var in loop_expr
27312744
if isinstance(_var, ast.VariableDeclaration)
27322745
]
2746+
2747+
# Get all variable declarations in loop
27332748
decls_in_loop = [
27342749
_var for _var in [
27352750
_var for _var in loop_expr
27362751
if isinstance(_var, ast.LoopExpr)
27372752
][0].body.body if isinstance(_var, ast.VariableDeclaration)
27382753
]
27392754

2755+
# Get all variable declarations in loop context (i.e., variables defined in a parent loop)
27402756
decls_in_loop_context = {
27412757
decl.name: decl
27422758
for decl, namespace in self.context._namespaces.items()
27432759
if isinstance(decl, ast.VariableDeclaration)
27442760
and namespace[:-1] == self.namespace
27452761
and namespace[-1].__contains__('loop')
27462762
}
2763+
2764+
# Get all variable declarations in loop context that are not already in decls_in_body or decls_in_loop
27472765
decls_in_loop_to_add = {
27482766
k: decl
27492767
for k, decl in decls_in_loop_context.items()
27502768
if decl not in decls_in_loop and decl not in decls_in_body
27512769
}
27522770
decls_in_context.update(decls_in_loop_to_add)
2771+
# Get all variable declarations in decls_in_context that are not already in decls_in_body
27532772
decls_to_add = {
27542773
k: v
27552774
for k, v in decls_in_context.items()
27562775
if v not in decls_in_body
27572776
}
2758-
print()
2777+
# Add new variables to decls
27592778
for var in decls_to_add.values():
27602779
decls.append(var)
2780+
# Create a new Block with updated declarations and expressions
27612781
body = ast.Block(decls + exprs + loop_expr + [expr])
27622782
else:
27632783
body = ast.Block(decls + exprs + [expr])

codeGenerator/src/ir/ast.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,10 @@ def is_equal(self, other):
13991399
class LoopExpr(Expr):
14001400

14011401
def __init__(self, body: Node):
1402+
"""
1403+
Definition of base class for loop expressions
1404+
:param body: loop body
1405+
"""
14021406
self.body = body
14031407

14041408

@@ -1407,6 +1411,11 @@ class ForExpr(LoopExpr):
14071411
class IterableExpr(Expr):
14081412

14091413
def __init__(self, array: ArrayExpr, variable: Variable):
1414+
"""
1415+
Defines IterableExpr. Ex. i in ArrayList<String>()
1416+
:param variable: variable to iterate through range
1417+
:param array: array expr
1418+
"""
14101419
self.arrayExpr = array
14111420
self.parameter = variable
14121421

@@ -1420,6 +1429,12 @@ class RangeExpr(Expr):
14201429

14211430
def __init__(self, variable: Variable, left_bound: Node,
14221431
right_bound: Node):
1432+
"""
1433+
Defines RangeExpression. Ex. 1..10
1434+
:param variable: variable to iterate through range
1435+
:param left_bound: left bound of range
1436+
:param right_bound: right bound of range
1437+
"""
14231438
self.parameter = variable
14241439
self.left_bound = left_bound
14251440
self.right_bound = right_bound
@@ -1433,6 +1448,11 @@ def children(self):
14331448
return [self.parameter, self.left_bound, self.right_bound]
14341449

14351450
def __init__(self, body: Node, loop_expr: IterableExpr | RangeExpr):
1451+
"""
1452+
Definition of For loop
1453+
:param body: loop body
1454+
:param loop_expr: iteration expr
1455+
"""
14361456
super(ForExpr, self).__init__(body)
14371457
self.loop_expr = loop_expr
14381458

@@ -1450,11 +1470,19 @@ def __str__(self):
14501470
class WhileExprBase(LoopExpr):
14511471

14521472
def __init__(self, body: Node, condition: Expr):
1473+
"""
1474+
Definition of base class for loop expressions
1475+
:param body: loop body
1476+
:param condition: exit condition of the loop
1477+
"""
14531478
super(WhileExprBase, self).__init__(body)
14541479
self.condition = condition
14551480

14561481

14571482
class WhileExpr(WhileExprBase):
1483+
"""
1484+
Class definition for a while loop
1485+
"""
14581486

14591487
def __str__(self):
14601488
return "while ({})\n{}".format(str(self.condition), str(self.body))
@@ -1464,6 +1492,9 @@ def children(self):
14641492

14651493

14661494
class DoWhileExpr(WhileExprBase):
1495+
"""
1496+
Class definition for a do-while loop
1497+
"""
14671498

14681499
def __str__(self):
14691500
return "do\n{}\nwhile ({})".format(str(self.body), str(self.condition))
@@ -1475,6 +1506,11 @@ def children(self):
14751506
class ClassCast(Node):
14761507

14771508
def __init__(self, expr: Node, cast_type):
1509+
"""
1510+
Class cast expr
1511+
:param expr: expression to cast
1512+
:param cast_type: cast type
1513+
"""
14781514
self.expr = expr
14791515
self.cast_type = cast_type
14801516

codeGenerator/src/translators/java.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,14 +1296,20 @@ def visit_loop(self, node: ast.Node):
12961296
old_ident = self.ident
12971297
self.ident += 2
12981298
body = node.body
1299+
# Find the loop expression (e.g. the condition for a while loop)
1300+
# by filtering out the body from the children of the node.
12991301
loop_expr = [child for child in node.children() if child != body][0]
13001302
children_res = self._visit_loop_body(body)
1303+
# If the loop expression is a function call, visit the function call and pop its result off the stack.
1304+
# Otherwise, visit the loop expression.
13011305
if isinstance(loop_expr, ast.FunctionCall):
13021306
loop_expr.accept(self)
13031307
loop_expr_res = self.pop_children_res([loop_expr])[0]
13041308
else:
13051309
loop_expr_res = self._visit_loop_expr(loop_expr)
13061310
children_res = [loop_expr_res, children_res]
1311+
1312+
# Determine the type of loop node and format the result string accordingly.
13071313
if isinstance(node, ast.ForExpr):
13081314
res = "{}for ({})\n{}".format(" " * old_ident, children_res[0],
13091315
children_res[1])
@@ -1326,18 +1332,21 @@ def _visit_loop_expr(self, node):
13261332
for c in children:
13271333
c.accept(self)
13281334
children_res = self.pop_children_res(children)
1335+
# If the node is an IterableExpr, create a string representation of the for-loop expression
13291336
if isinstance(node, ast.ForExpr.IterableExpr):
13301337
res = "{type} {var}: {array}".format(type=self.get_type_name(
13311338
node.arrayExpr.array_type.type_args[0]),
13321339
var=str(children_res[0]),
13331340
array=str(children_res[1]))
1341+
# If the node is a RangeExpr, create a string representation of the range for-loop expression
13341342
elif isinstance(node, ast.ForExpr.RangeExpr):
13351343
var = str(children_res[0])
13361344
start = str(children_res[1])
13371345
end = str(children_res[2])
13381346
res = "{} = {}; {} <= {}; {}++".format(
13391347
_handle_range_expression(var, children[1]), start, var, end,
13401348
var)
1349+
# If the node is a ComparisonExpr, visit the binary operation and get the result
13411350
elif isinstance(node, ast.ComparisonExpr):
13421351
self.visit_binary_op(node)
13431352
res = self.pop_children_res([node])[0]

codeGenerator/src/translators/kotlin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,12 +657,14 @@ def visit_assign(self, node):
657657
def visit_loop(self, node: ast.Node):
658658
old_ident = self.ident
659659
self.ident += 2
660+
# we should cast integers inside loop body to avoid incorrect code
660661
prev = self._cast_integers
661662
self._cast_integers = True
662663
children = node.children()
663664
for c in children:
664665
c.accept(self)
665666
children_res = self.pop_children_res(children)
667+
# Construct a string representation of the loop based on its type
666668
if isinstance(node, ast.ForExpr):
667669
res = "{}for ({})\n{}".format(" " * old_ident,
668670
children_res[0][self.ident:],

testOracle/src/main/kotlin/com/vitekkor/perffect/ResultsComaparator.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import kotlinx.serialization.json.Json
1212
import java.io.File
1313
import kotlin.system.exitProcess
1414

15+
/**
16+
* Compare the execution times of Java and Kotlin programs.
17+
* Reads the necessary files from the file system, compiles the programs, measures their execution times,
18+
* and outputs the results to the console.
19+
*/
1520
fun main() {
1621
val seed = -8497514709130667753
1722
val kotlinCompiler = KotlinJVMCompiler()

testOracle/src/main/kotlin/com/vitekkor/perffect/TestOracle.kt

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ suspend fun main() {
6363
TestOracle().run()
6464
}
6565

66+
/**
67+
* A class that represents the test oracle.
68+
*/
6669
class TestOracle {
6770
private val log = logger {}
6871

@@ -78,15 +81,19 @@ class TestOracle {
7881
javaCompiler.cleanUp()
7982
try {
8083
log.info("$SEED $seed")
84+
// Generate Kotlin program and measure generation time. Timeout 2 minutes.
8185
val (kotlin, kotlinGenerationTime) = withTimeoutOrNull(Duration.ofMinutes(2).toKotlinDuration()) {
8286
measureTimedValue { client.generateKotlin(seed) }
8387
}.also { if (it == null) log.warn { "$KOTLIN_PROGRAM timeout exceeded" } } ?: continue
88+
// Save stat
8489
kotlinStat.totalNumberOfPrograms++
8590
kotlinStat.averageGenerationTimeMs += kotlinGenerationTime.inWholeMilliseconds
8691

92+
// Generate Java program and measure generation time. Timeout 2 minutes.
8793
val (java, javaGenerationTime) = withTimeoutOrNull(Duration.ofMinutes(2).toKotlinDuration()) {
8894
measureTimedValue { client.generateJava(seed) }
8995
}.also { if (it == null) log.warn { "$JAVA_PROGRAM timeout exceeded" } } ?: continue
96+
// Save stat
9097
javaStat.totalNumberOfPrograms++
9198
javaStat.averageGenerationTimeMs += javaGenerationTime.inWholeMilliseconds
9299

@@ -107,6 +114,7 @@ class TestOracle {
107114
val javaProject = java.toProject(Language.JAVA)
108115
log.info("$JAVA_PROGRAM generated code: ${java.text}")
109116

117+
// Compile and measure time
110118
val (kotlinCompileStatus, kotlinCompileTime) =
111119
kotlinCompiler.tryToCompileWithStatusAndExecutionTime(kotlinProject)
112120
log.info("$KOTLIN_PROGRAM compileStatus: $kotlinCompileStatus; compileTime: $kotlinCompileTime")
@@ -131,6 +139,7 @@ class TestOracle {
131139
continue
132140
}
133141

142+
//
134143
val javaRepeatCount = chooseNumberOfExecutions(javaCompiler, java)
135144
val kotlinRepeatCount = chooseNumberOfExecutions(kotlinCompiler, kotlin)
136145

@@ -170,6 +179,12 @@ class TestOracle {
170179
}
171180
}
172181

182+
/**
183+
* Chooses the number of executions based on the given program and compiler.
184+
* @param compiler the compiler for the program
185+
* @param program the program for which to choose the number of executions
186+
* @return the chosen number of executions
187+
*/
173188
private fun chooseNumberOfExecutions(compiler: BaseCompiler, program: Server.Program): Long {
174189
if (program.language == Language.KOTLIN.name.lowercase()) {
175190
var repeatCount = 10L
@@ -182,10 +197,10 @@ class TestOracle {
182197
if (executionTime.first.contains("Exception")) {
183198
break
184199
}
185-
repeatCount *= 10L
200+
repeatCount *= 10L // increase repeat count until program execution time less than 1s
186201
} while (executionTime.second < 1000 && repeatCount > 0L)
187202
repeatCount /= 10L
188-
if (repeatCount < 0L) repeatCount = 9000000000000000000L
203+
if (repeatCount < 0L) repeatCount = 9000000000000000000L // overflow handling
189204
log.info("$KOTLIN_PROGRAM execution time over 1s with $repeatCount. Program text: $project")
190205
compiler.cleanUp()
191206
return repeatCount
@@ -201,17 +216,22 @@ class TestOracle {
201216
if (executionTime.first.contains("Exception")) {
202217
break
203218
}
204-
repeatCount *= 10L
219+
repeatCount *= 10L // increase repeat count until program execution time less than 1s
205220
} while (executionTime.second < 1000 && repeatCount > 0L)
206221
repeatCount /= 10L
207-
if (repeatCount < 0L) repeatCount = 9000000000000000000L
222+
if (repeatCount < 0L) repeatCount = 9000000000000000000L // overflow handling
208223
log.info("$JAVA_PROGRAM execution time over 1s with $repeatCount. Program text: $project")
209224
compiler.cleanUp()
210225
return repeatCount
211226
}
212227
throw UnsupportedOperationException("Support only Java and Kotlin")
213228
}
214229

230+
/**
231+
* Compares the execution times of Java and Kotlin programs based on the given measurement result.
232+
* If there is a performance degradation, saves the results to a directory.
233+
* @param measurementResult the measurement result containing the execution times of the programs
234+
*/
215235
private suspend fun compareExecutionTimes(measurementResult: MeasurementResult) {
216236
val percentage = measurementResult.kotlin.time / measurementResult.java.time
217237
if (percentage > CompilerArgs.percentageDelta) {
@@ -225,6 +245,7 @@ class TestOracle {
225245
CompilerArgs.pathToResultsDir + "/${measurementResult.seed}"
226246
)
227247
withContext(Dispatchers.IO) {
248+
// Save meta data about the test results
228249
File(CompilerArgs.pathToResultsDir + "/${measurementResult.seed}", "meta.json").bufferedWriter().use {
229250
it.write(Json.encodeToString(measurementResult))
230251
}

0 commit comments

Comments
 (0)