1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
from dataclasses import dataclass
from functools import singledispatch
from typing import Dict, List
from .ast import ImplementationFile, FunctionDefinition, ExpressionStatement, FunctionCallExpression, \
VariableExpression, ConstantExpression, ReturnStatement, BasicType
@dataclass
class SsaResult:
data: List[str]
code: List[str]
@dataclass
class CompileContext:
next_data: int = 0
next_temp: int = 0
def build_ssa(file: ImplementationFile) -> str:
result = compile_to_ssa(file, CompileContext())
data = '\n'.join(result.data)
code = '\n'.join(result.code)
return data + '\n\n' + code
@singledispatch
def compile_to_ssa(target, context: CompileContext) -> SsaResult:
raise NotImplementedError('unannotated compile on ' + str(type(target)))
@compile_to_ssa.register
def _(target: ImplementationFile, context: CompileContext):
data = []
code = []
for target in target.contents:
result = compile_to_ssa(target, context)
data += result.data
code += result.code
return SsaResult(data, code)
@compile_to_ssa.register
def _(target: FunctionDefinition, context: CompileContext) -> SsaResult:
data = []
code = []
for statement in target.body:
result = compile_to_ssa(statement, context)
data += result.data
code += result.code
code = [' ' + instr for instr in code]
assert len(target.args) == 0
assert target.return_type == BasicType('int32')
code = [f"export function w ${target.name}() {{", "@start", *code, "}"]
return SsaResult(data, code)
@compile_to_ssa.register
def _(target: ExpressionStatement, context: CompileContext) -> SsaResult:
return compile_to_ssa(target.body, context)
@compile_to_ssa.register
def _(target: FunctionCallExpression, context: CompileContext) -> SsaResult:
assert isinstance(target.function, VariableExpression)
data = []
code = []
args = []
for i, expr in enumerate(target.arguments):
arg_dest = context.next_temp
result = compile_to_ssa(expr, context)
data += result.data
code += result.code
args += [f"l %t{arg_dest}"]
code += [f"call ${target.function.name}({','.join(args)}, ...)"]
return SsaResult(data, code)
@compile_to_ssa.register
def _(target: ConstantExpression, context: CompileContext) -> SsaResult:
if target.value.startswith('"'):
data_dest = context.next_data
context.next_data += 1
data = [f"data $data{data_dest} = {{ b {target.value}, b 0 }}"]
temp = context.next_temp
context.next_temp += 1
code = [f"%t{temp} =l copy $data{data_dest}"]
else:
assert not target.value.startswith('0b')
assert not target.value.startswith('0B')
assert not target.value.startswith('0o')
assert not target.value.startswith('0x')
assert not target.value.startswith('0X')
assert not target.value.startswith('0f')
assert not target.value.startswith('0F')
assert '.' not in target.value
assert not target.value.startswith("'")
data = []
temp = context.next_temp
context.next_temp += 1
code = [f"%t{temp} =w copy {target.value}"]
return SsaResult(data, code)
@compile_to_ssa.register
def _(target: ReturnStatement, context: CompileContext) -> SsaResult:
if target.body is None:
return SsaResult([], ['ret'])
ret_val_dest = context.next_temp
result = compile_to_ssa(target.body, context)
result.code.append(f"ret %t{ret_val_dest}")
return result
|