transpiler 0.1.0__py3-none-any.whl

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.
transpiler/__init__.py ADDED
File without changes
File without changes
@@ -0,0 +1,121 @@
1
+ from transpiler.ir.nodes import *
2
+ from transpiler.ir.types import *
3
+
4
+ class CBackend:
5
+ def __init__(self):
6
+ self.indent_level = 0
7
+
8
+ def generate(self, program: Program) -> str:
9
+ lines = [
10
+ '#include "runtime/c/transpiler_runtime.h"',
11
+ ""
12
+ ]
13
+
14
+ for struct in program.structs:
15
+ lines.append(f"typedef struct {struct.name} {struct.name};")
16
+ if program.structs: lines.append("")
17
+
18
+ for struct in program.structs:
19
+ lines.append(self._generate_struct(struct))
20
+
21
+ for function in program.functions:
22
+ lines.append(self._generate_function(function))
23
+
24
+ return "\n".join(lines)
25
+
26
+ def _generate_struct(self, node: Struct) -> str:
27
+ lines = [f"struct {node.name} {{"]
28
+ self.indent_level += 1
29
+ for name, typ in node.fields:
30
+ lines.append(self._indent(f"{self._type_to_str(typ)} {name};"))
31
+ self.indent_level -= 1
32
+ lines.append("};\n")
33
+ return "\n".join(lines)
34
+
35
+ def _generate_function(self, node: Function) -> str:
36
+ params = []
37
+ for p in node.params:
38
+ params.append(f"{self._type_to_str(p.type)} {p.name}")
39
+
40
+ ret_type = self._type_to_str(node.return_type)
41
+
42
+ lines = [f"{ret_type} {node.name}({', '.join(params)}) {{"]
43
+ self.indent_level += 1
44
+ body_str = self._generate_block(node.body)
45
+ if body_str:
46
+ lines.append(body_str)
47
+ self.indent_level -= 1
48
+ lines.append("}\n")
49
+ return "\n".join(lines)
50
+
51
+ def _generate_block(self, node: Block) -> str:
52
+ lines = []
53
+ for stmt in node.statements:
54
+ stmt_str = self._generate_stmt(stmt)
55
+ if stmt_str:
56
+ lines.append(self._indent(stmt_str))
57
+ return "\n".join(lines)
58
+
59
+ def _generate_stmt(self, node: Stmt) -> str:
60
+ if isinstance(node, Return):
61
+ if node.value:
62
+ return f"return {self._generate_expr(node.value)};"
63
+ return "return;"
64
+ elif isinstance(node, Let):
65
+ return f"{self._type_to_str(node.type)} {node.name} = {self._generate_expr(node.value)};"
66
+ elif isinstance(node, Assign):
67
+ return f"{self._generate_expr(node.target)} = {self._generate_expr(node.value)};"
68
+ elif isinstance(node, ExprStmt):
69
+ return f"{self._generate_expr(node.expr)};"
70
+ elif isinstance(node, If):
71
+ res = f"if ({self._generate_expr(node.condition)}) {{\n"
72
+ self.indent_level += 1
73
+ res += self._generate_block(node.then_block)
74
+ self.indent_level -= 1
75
+ res += f"\n{self._indent('}')}"
76
+ if node.else_block:
77
+ res += " else {\n"
78
+ self.indent_level += 1
79
+ res += self._generate_block(node.else_block)
80
+ self.indent_level -= 1
81
+ res += f"\n{self._indent('}')}"
82
+ return res.strip()
83
+ elif isinstance(node, While):
84
+ res = f"while ({self._generate_expr(node.condition)}) {{\n"
85
+ self.indent_level += 1
86
+ res += self._generate_block(node.body)
87
+ self.indent_level -= 1
88
+ res += f"\n{self._indent('}')}"
89
+ return res.strip()
90
+ return ""
91
+
92
+ def _generate_expr(self, node: Expr) -> str:
93
+ if isinstance(node, IntLiteral): return str(node.value)
94
+ elif isinstance(node, FloatLiteral): return str(node.value)
95
+ elif isinstance(node, BoolLiteral): return "true" if node.value else "false"
96
+ elif isinstance(node, StringLiteral): return f'"{node.value}"'
97
+ elif isinstance(node, NullLiteral): return "NULL"
98
+ elif isinstance(node, Var): return node.name
99
+ elif isinstance(node, Binary):
100
+ return f"({self._generate_expr(node.left)} {node.op.value} {self._generate_expr(node.right)})"
101
+ elif isinstance(node, Call):
102
+ func = self._generate_expr(node.function)
103
+ if func == "print":
104
+ func = "print_int"
105
+ args = [self._generate_expr(arg) for arg in node.args]
106
+ return f"{func}({', '.join(args)})"
107
+ elif isinstance(node, FieldAccess):
108
+ return f"{self._generate_expr(node.object)}.{node.field}"
109
+ return ""
110
+
111
+ def _type_to_str(self, t: Type) -> str:
112
+ if t.kind == TypeKind.INT: return "int"
113
+ elif t.kind == TypeKind.FLOAT: return "double"
114
+ elif t.kind == TypeKind.BOOL: return "bool"
115
+ elif t.kind == TypeKind.STRING: return "char*"
116
+ elif t.kind == TypeKind.VOID: return "void"
117
+ elif t.kind == TypeKind.STRUCT: return f"struct {t.name}"
118
+ return "void*"
119
+
120
+ def _indent(self, line: str) -> str:
121
+ return " " * self.indent_level + line
File without changes
@@ -0,0 +1,120 @@
1
+ from transpiler.ir.nodes import *
2
+ from transpiler.ir.types import *
3
+
4
+ class GoBackend:
5
+ def __init__(self):
6
+ self.indent_level = 0
7
+
8
+ def generate(self, program: Program) -> str:
9
+ lines = [
10
+ "package main",
11
+ "",
12
+ 'import "fmt"',
13
+ ""
14
+ ]
15
+
16
+ for struct in program.structs:
17
+ lines.append(self._generate_struct(struct))
18
+ for function in program.functions:
19
+ lines.append(self._generate_function(function))
20
+
21
+ return "\n".join(lines)
22
+
23
+ def _generate_struct(self, node: Struct) -> str:
24
+ lines = [f"type {node.name} struct {{"]
25
+ self.indent_level += 1
26
+ for name, typ in node.fields:
27
+ # Capitalize field names to export them in Go
28
+ go_name = name.capitalize()
29
+ lines.append(self._indent(f"{go_name} {self._type_to_str(typ)}"))
30
+ self.indent_level -= 1
31
+ lines.append("}\n")
32
+ return "\n".join(lines)
33
+
34
+ def _generate_function(self, node: Function) -> str:
35
+ params = []
36
+ for p in node.params:
37
+ params.append(f"{p.name} {self._type_to_str(p.type)}")
38
+
39
+ ret_type = self._type_to_str(node.return_type)
40
+ ret_str = f" {ret_type}" if ret_type and ret_type not in ("void", "interface{}") else ""
41
+
42
+ lines = [f"func {node.name}({', '.join(params)}){ret_str} {{"]
43
+ self.indent_level += 1
44
+ body_str = self._generate_block(node.body)
45
+ if body_str:
46
+ lines.append(body_str)
47
+ self.indent_level -= 1
48
+ lines.append("}\n")
49
+ return "\n".join(lines)
50
+
51
+ def _generate_block(self, node: Block) -> str:
52
+ lines = []
53
+ for stmt in node.statements:
54
+ stmt_str = self._generate_stmt(stmt)
55
+ if stmt_str:
56
+ lines.append(self._indent(stmt_str))
57
+ return "\n".join(lines)
58
+
59
+ def _generate_stmt(self, node: Stmt) -> str:
60
+ if isinstance(node, Return):
61
+ if node.value:
62
+ return f"return {self._generate_expr(node.value)}"
63
+ return "return"
64
+ elif isinstance(node, Let):
65
+ return f"var {node.name} {self._type_to_str(node.type)} = {self._generate_expr(node.value)}"
66
+ elif isinstance(node, Assign):
67
+ return f"{self._generate_expr(node.target)} = {self._generate_expr(node.value)}"
68
+ elif isinstance(node, ExprStmt):
69
+ return self._generate_expr(node.expr)
70
+ elif isinstance(node, If):
71
+ res = f"if {self._generate_expr(node.condition)} {{\n"
72
+ self.indent_level += 1
73
+ res += self._generate_block(node.then_block)
74
+ self.indent_level -= 1
75
+ res += f"\n{self._indent('}')}"
76
+ if node.else_block:
77
+ res += " else {\n"
78
+ self.indent_level += 1
79
+ res += self._generate_block(node.else_block)
80
+ self.indent_level -= 1
81
+ res += f"\n{self._indent('}')}"
82
+ return res.strip()
83
+ elif isinstance(node, While):
84
+ res = f"for {self._generate_expr(node.condition)} {{\n"
85
+ self.indent_level += 1
86
+ res += self._generate_block(node.body)
87
+ self.indent_level -= 1
88
+ res += f"\n{self._indent('}')}"
89
+ return res.strip()
90
+ return ""
91
+
92
+ def _generate_expr(self, node: Expr) -> str:
93
+ if isinstance(node, IntLiteral): return str(node.value)
94
+ elif isinstance(node, FloatLiteral): return str(node.value)
95
+ elif isinstance(node, BoolLiteral): return "true" if node.value else "false"
96
+ elif isinstance(node, StringLiteral): return f'"{node.value}"'
97
+ elif isinstance(node, NullLiteral): return "nil"
98
+ elif isinstance(node, Var): return node.name
99
+ elif isinstance(node, Binary):
100
+ return f"({self._generate_expr(node.left)} {node.op.value} {self._generate_expr(node.right)})"
101
+ elif isinstance(node, Call):
102
+ func = self._generate_expr(node.function)
103
+ if func == "print":
104
+ func = "fmt.Println"
105
+ args = [self._generate_expr(arg) for arg in node.args]
106
+ return f"{func}({', '.join(args)})"
107
+ elif isinstance(node, FieldAccess):
108
+ return f"{self._generate_expr(node.object)}.{node.field.capitalize()}"
109
+ return ""
110
+
111
+ def _type_to_str(self, t: Type) -> str:
112
+ if t.kind == TypeKind.INT: return "int"
113
+ elif t.kind == TypeKind.FLOAT: return "float64"
114
+ elif t.kind == TypeKind.BOOL: return "bool"
115
+ elif t.kind == TypeKind.STRING: return "string"
116
+ elif t.kind == TypeKind.VOID: return "void"
117
+ return "interface{}"
118
+
119
+ def _indent(self, line: str) -> str:
120
+ return "\t" * self.indent_level + line
File without changes
@@ -0,0 +1,112 @@
1
+ from transpiler.ir.nodes import *
2
+ from transpiler.ir.types import *
3
+
4
+ class JavaBackend:
5
+ def __init__(self):
6
+ self.indent_level = 0
7
+
8
+ def generate(self, program: Program) -> str:
9
+ lines = [
10
+ "public class Main {",
11
+ ""
12
+ ]
13
+ self.indent_level += 1
14
+
15
+ for function in program.functions:
16
+ lines.append(self._generate_function(function))
17
+
18
+ self.indent_level -= 1
19
+ lines.append("}\n")
20
+ return "\n".join(lines)
21
+
22
+ def _generate_function(self, node: Function) -> str:
23
+ params = []
24
+ for p in node.params:
25
+ params.append(f"{self._type_to_str(p.type)} {p.name}")
26
+
27
+ ret_type = self._type_to_str(node.return_type)
28
+
29
+ if node.name == "main":
30
+ lines = [self._indent(f"public static void main(String[] args) {{")]
31
+ else:
32
+ lines = [self._indent(f"public static {ret_type} {node.name}({', '.join(params)}) {{")]
33
+
34
+ self.indent_level += 1
35
+ body_str = self._generate_block(node.body)
36
+ if body_str:
37
+ lines.append(body_str)
38
+ self.indent_level -= 1
39
+ lines.append(self._indent("}\n"))
40
+ return "\n".join(lines)
41
+
42
+ def _generate_block(self, node: Block) -> str:
43
+ lines = []
44
+ for stmt in node.statements:
45
+ stmt_str = self._generate_stmt(stmt)
46
+ if stmt_str:
47
+ lines.append(self._indent(stmt_str))
48
+ return "\n".join(lines)
49
+
50
+ def _generate_stmt(self, node: Stmt) -> str:
51
+ if isinstance(node, Return):
52
+ if node.value:
53
+ return f"return {self._generate_expr(node.value)};"
54
+ return "return;"
55
+ elif isinstance(node, Let):
56
+ return f"{self._type_to_str(node.type)} {node.name} = {self._generate_expr(node.value)};"
57
+ elif isinstance(node, Assign):
58
+ return f"{self._generate_expr(node.target)} = {self._generate_expr(node.value)};"
59
+ elif isinstance(node, ExprStmt):
60
+ return f"{self._generate_expr(node.expr)};"
61
+ elif isinstance(node, If):
62
+ res = f"if ({self._generate_expr(node.condition)}) {{\n"
63
+ self.indent_level += 1
64
+ res += self._generate_block(node.then_block)
65
+ self.indent_level -= 1
66
+ res += f"\n{self._indent('}')}"
67
+ if node.else_block:
68
+ res += " else {\n"
69
+ self.indent_level += 1
70
+ res += self._generate_block(node.else_block)
71
+ self.indent_level -= 1
72
+ res += f"\n{self._indent('}')}"
73
+ return res.strip()
74
+ elif isinstance(node, While):
75
+ res = f"while ({self._generate_expr(node.condition)}) {{\n"
76
+ self.indent_level += 1
77
+ res += self._generate_block(node.body)
78
+ self.indent_level -= 1
79
+ res += f"\n{self._indent('}')}"
80
+ return res.strip()
81
+ return ""
82
+
83
+ def _generate_expr(self, node: Expr) -> str:
84
+ if isinstance(node, IntLiteral): return str(node.value)
85
+ elif isinstance(node, FloatLiteral): return str(node.value)
86
+ elif isinstance(node, BoolLiteral): return "true" if node.value else "false"
87
+ elif isinstance(node, StringLiteral): return f'"{node.value}"'
88
+ elif isinstance(node, NullLiteral): return "null"
89
+ elif isinstance(node, Var): return node.name
90
+ elif isinstance(node, Binary):
91
+ return f"({self._generate_expr(node.left)} {node.op.value} {self._generate_expr(node.right)})"
92
+ elif isinstance(node, Call):
93
+ func = self._generate_expr(node.function)
94
+ if func == "print":
95
+ func = "System.out.println"
96
+ args = [self._generate_expr(arg) for arg in node.args]
97
+ return f"{func}({', '.join(args)})"
98
+ elif isinstance(node, FieldAccess):
99
+ return f"{self._generate_expr(node.object)}.{node.field}"
100
+ return ""
101
+
102
+ def _type_to_str(self, t: Type) -> str:
103
+ if t.kind == TypeKind.INT: return "int"
104
+ elif t.kind == TypeKind.FLOAT: return "double"
105
+ elif t.kind == TypeKind.BOOL: return "boolean"
106
+ elif t.kind == TypeKind.STRING: return "String"
107
+ elif t.kind == TypeKind.VOID: return "void"
108
+ elif t.kind == TypeKind.STRUCT: return t.name
109
+ return "Object"
110
+
111
+ def _indent(self, line: str) -> str:
112
+ return " " * self.indent_level + line
File without changes
@@ -0,0 +1,108 @@
1
+ from transpiler.ir.nodes import *
2
+ from transpiler.ir.types import *
3
+
4
+ class JSBackend:
5
+ def __init__(self):
6
+ self.indent_level = 0
7
+
8
+ def generate(self, program: Program) -> str:
9
+ lines = []
10
+ for struct in program.structs:
11
+ lines.append(self._generate_struct(struct))
12
+ for function in program.functions:
13
+ lines.append(self._generate_function(function))
14
+ return "\n".join(lines)
15
+
16
+ def _generate_struct(self, node: Struct) -> str:
17
+ lines = [f"class {node.name} {{"]
18
+ self.indent_level += 1
19
+
20
+ if node.fields:
21
+ params = [name for name, _ in node.fields]
22
+ lines.append(self._indent(f"constructor({', '.join(params)}) {{"))
23
+ self.indent_level += 1
24
+ for name in params:
25
+ lines.append(self._indent(f"this.{name} = {name};"))
26
+ self.indent_level -= 1
27
+ lines.append(self._indent("}"))
28
+
29
+ self.indent_level -= 1
30
+ lines.append("}\n")
31
+ return "\n".join(lines)
32
+
33
+ def _generate_function(self, node: Function) -> str:
34
+ params = [p.name for p in node.params]
35
+ lines = [f"function {node.name}({', '.join(params)}) {{"]
36
+ self.indent_level += 1
37
+ body_str = self._generate_block(node.body)
38
+ if body_str:
39
+ lines.append(body_str)
40
+ self.indent_level -= 1
41
+ lines.append("}\n")
42
+ return "\n".join(lines)
43
+
44
+ def _generate_block(self, node: Block) -> str:
45
+ lines = []
46
+ for stmt in node.statements:
47
+ stmt_str = self._generate_stmt(stmt)
48
+ if stmt_str:
49
+ lines.append(self._indent(stmt_str))
50
+ return "\n".join(lines)
51
+
52
+ def _generate_stmt(self, node: Stmt) -> str:
53
+ if isinstance(node, Return):
54
+ if node.value:
55
+ return f"return {self._generate_expr(node.value)};"
56
+ return "return;"
57
+ elif isinstance(node, Let):
58
+ return f"let {node.name} = {self._generate_expr(node.value)};"
59
+ elif isinstance(node, Assign):
60
+ return f"{self._generate_expr(node.target)} = {self._generate_expr(node.value)};"
61
+ elif isinstance(node, ExprStmt):
62
+ return f"{self._generate_expr(node.expr)};"
63
+ elif isinstance(node, If):
64
+ res = f"if ({self._generate_expr(node.condition)}) {{\n"
65
+ self.indent_level += 1
66
+ res += self._generate_block(node.then_block)
67
+ self.indent_level -= 1
68
+ res += f"\n{self._indent('}')}"
69
+ if node.else_block:
70
+ res += " else {\n"
71
+ self.indent_level += 1
72
+ res += self._generate_block(node.else_block)
73
+ self.indent_level -= 1
74
+ res += f"\n{self._indent('}')}"
75
+ return res.strip()
76
+ elif isinstance(node, While):
77
+ res = f"while ({self._generate_expr(node.condition)}) {{\n"
78
+ self.indent_level += 1
79
+ res += self._generate_block(node.body)
80
+ self.indent_level -= 1
81
+ res += f"\n{self._indent('}')}"
82
+ return res.strip()
83
+ return ""
84
+
85
+ def _generate_expr(self, node: Expr) -> str:
86
+ if isinstance(node, IntLiteral): return str(node.value)
87
+ elif isinstance(node, FloatLiteral): return str(node.value)
88
+ elif isinstance(node, BoolLiteral): return "true" if node.value else "false"
89
+ elif isinstance(node, StringLiteral): return f'"{node.value}"'
90
+ elif isinstance(node, NullLiteral): return "null"
91
+ elif isinstance(node, Var): return node.name
92
+ elif isinstance(node, Binary):
93
+ op = node.op.value
94
+ if node.op == BinOp.EQ: op = "==="
95
+ if node.op == BinOp.NEQ: op = "!=="
96
+ return f"({self._generate_expr(node.left)} {op} {self._generate_expr(node.right)})"
97
+ elif isinstance(node, Call):
98
+ func = self._generate_expr(node.function)
99
+ if func == "print":
100
+ func = "console.log"
101
+ args = [self._generate_expr(arg) for arg in node.args]
102
+ return f"{func}({', '.join(args)})"
103
+ elif isinstance(node, FieldAccess):
104
+ return f"{self._generate_expr(node.object)}.{node.field}"
105
+ return ""
106
+
107
+ def _indent(self, line: str) -> str:
108
+ return " " * self.indent_level + line
File without changes
@@ -0,0 +1,109 @@
1
+ from transpiler.ir.nodes import *
2
+ from transpiler.ir.types import *
3
+
4
+ class PythonBackend:
5
+ def __init__(self):
6
+ self.indent_level = 0
7
+
8
+ def generate(self, program: Program) -> str:
9
+ lines = []
10
+ for struct in program.structs:
11
+ lines.append(self._generate_struct(struct))
12
+ for function in program.functions:
13
+ lines.append(self._generate_function(function))
14
+ return "\n".join(lines)
15
+
16
+ def _generate_struct(self, node: Struct) -> str:
17
+ lines = [f"class {node.name}:"]
18
+ self.indent_level += 1
19
+ if not node.fields:
20
+ lines.append(self._indent("pass"))
21
+ else:
22
+ for name, typ in node.fields:
23
+ lines.append(self._indent(f"{name}: {self._type_to_str(typ)}"))
24
+ self.indent_level -= 1
25
+ return "\n".join(lines) + "\n"
26
+
27
+ def _generate_function(self, node: Function) -> str:
28
+ params = []
29
+ for p in node.params:
30
+ ptype = self._type_to_str(p.type)
31
+ params.append(f"{p.name}: {ptype}" if ptype else p.name)
32
+
33
+ ret_type = self._type_to_str(node.return_type)
34
+ ret_str = f" -> {ret_type}" if ret_type and ret_type != "Any" else ""
35
+
36
+ lines = [f"def {node.name}({', '.join(params)}){ret_str}:"]
37
+ self.indent_level += 1
38
+ body_str = self._generate_block(node.body)
39
+ if not body_str.strip():
40
+ lines.append(self._indent("pass"))
41
+ else:
42
+ lines.append(body_str)
43
+ self.indent_level -= 1
44
+ return "\n".join(lines) + "\n"
45
+
46
+ def _generate_block(self, node: Block) -> str:
47
+ lines = []
48
+ for stmt in node.statements:
49
+ stmt_str = self._generate_stmt(stmt)
50
+ if stmt_str:
51
+ lines.append(self._indent(stmt_str))
52
+ return "\n".join(lines)
53
+
54
+ def _generate_stmt(self, node: Stmt) -> str:
55
+ if isinstance(node, Return):
56
+ if node.value:
57
+ return f"return {self._generate_expr(node.value)}"
58
+ return "return"
59
+ elif isinstance(node, Let):
60
+ return f"{node.name}: {self._type_to_str(node.type)} = {self._generate_expr(node.value)}"
61
+ elif isinstance(node, Assign):
62
+ return f"{self._generate_expr(node.target)} = {self._generate_expr(node.value)}"
63
+ elif isinstance(node, ExprStmt):
64
+ return self._generate_expr(node.expr)
65
+ elif isinstance(node, If):
66
+ res = f"if {self._generate_expr(node.condition)}:\n"
67
+ self.indent_level += 1
68
+ res += self._generate_block(node.then_block)
69
+ self.indent_level -= 1
70
+ if node.else_block:
71
+ res += f"\n{self._indent('else:')}\n"
72
+ self.indent_level += 1
73
+ res += self._generate_block(node.else_block)
74
+ self.indent_level -= 1
75
+ return res.strip()
76
+ elif isinstance(node, While):
77
+ res = f"while {self._generate_expr(node.condition)}:\n"
78
+ self.indent_level += 1
79
+ res += self._generate_block(node.body)
80
+ self.indent_level -= 1
81
+ return res.strip()
82
+ return ""
83
+
84
+ def _generate_expr(self, node: Expr) -> str:
85
+ if isinstance(node, IntLiteral): return str(node.value)
86
+ elif isinstance(node, FloatLiteral): return str(node.value)
87
+ elif isinstance(node, BoolLiteral): return "True" if node.value else "False"
88
+ elif isinstance(node, StringLiteral): return f'"{node.value}"'
89
+ elif isinstance(node, NullLiteral): return "None"
90
+ elif isinstance(node, Var): return node.name
91
+ elif isinstance(node, Binary):
92
+ return f"({self._generate_expr(node.left)} {node.op.value} {self._generate_expr(node.right)})"
93
+ elif isinstance(node, Call):
94
+ func = self._generate_expr(node.function)
95
+ args = [self._generate_expr(arg) for arg in node.args]
96
+ return f"{func}({', '.join(args)})"
97
+ elif isinstance(node, FieldAccess):
98
+ return f"{self._generate_expr(node.object)}.{node.field}"
99
+ return ""
100
+
101
+ def _type_to_str(self, t: Type) -> str:
102
+ if t.kind == TypeKind.INT: return "int"
103
+ elif t.kind == TypeKind.FLOAT: return "float"
104
+ elif t.kind == TypeKind.BOOL: return "bool"
105
+ elif t.kind == TypeKind.STRING: return "str"
106
+ return "Any"
107
+
108
+ def _indent(self, line: str) -> str:
109
+ return " " * self.indent_level + line