summaryrefslogtreecommitdiff
path: root/tiger-compiler/src
diff options
context:
space:
mode:
Diffstat (limited to 'tiger-compiler/src')
-rw-r--r--tiger-compiler/src/assert/binder.cc12
-rw-r--r--tiger-compiler/src/assert/binder.hh22
-rw-r--r--tiger-compiler/src/assert/desugar-visitor.cc33
-rw-r--r--tiger-compiler/src/assert/desugar-visitor.hh42
-rw-r--r--tiger-compiler/src/assert/desugar-visitor.hxx39
-rw-r--r--tiger-compiler/src/assert/libassert.cc36
-rw-r--r--tiger-compiler/src/assert/libassert.hh79
-rw-r--r--tiger-compiler/src/assert/libassert.hxx45
-rw-r--r--tiger-compiler/src/assert/local.am17
-rw-r--r--tiger-compiler/src/assert/renamer.cc18
-rw-r--r--tiger-compiler/src/assert/renamer.hh30
-rw-r--r--tiger-compiler/src/assert/tasks.cc53
-rw-r--r--tiger-compiler/src/assert/tasks.hh59
-rw-r--r--tiger-compiler/src/assert/type-checker.cc21
-rw-r--r--tiger-compiler/src/assert/type-checker.hh30
-rw-r--r--tiger-compiler/src/ast/README.txt66
-rw-r--r--tiger-compiler/src/ast/all.hh51
-rw-r--r--tiger-compiler/src/ast/array-exp.cc31
-rw-r--r--tiger-compiler/src/ast/array-exp.hh60
-rw-r--r--tiger-compiler/src/ast/array-exp.hxx22
-rw-r--r--tiger-compiler/src/ast/array-ty.cc21
-rw-r--r--tiger-compiler/src/ast/array-ty.hh48
-rw-r--r--tiger-compiler/src/ast/array-ty.hxx16
-rw-r--r--tiger-compiler/src/ast/assert-exp.cc24
-rw-r--r--tiger-compiler/src/ast/assert-exp.hh42
-rw-r--r--tiger-compiler/src/ast/assert-exp.hxx14
-rw-r--r--tiger-compiler/src/ast/assert-visitor.hh51
-rw-r--r--tiger-compiler/src/ast/assert-visitor.hxx32
-rw-r--r--tiger-compiler/src/ast/assign-exp.cc26
-rw-r--r--tiger-compiler/src/ast/assign-exp.hh54
-rw-r--r--tiger-compiler/src/ast/assign-exp.hxx19
-rw-r--r--tiger-compiler/src/ast/ast-nodes.mk41
-rw-r--r--tiger-compiler/src/ast/ast.cc15
-rw-r--r--tiger-compiler/src/ast/ast.hh48
-rw-r--r--tiger-compiler/src/ast/ast.hxx18
-rw-r--r--tiger-compiler/src/ast/break-exp.cc18
-rw-r--r--tiger-compiler/src/ast/break-exp.hh49
-rw-r--r--tiger-compiler/src/ast/break-exp.hxx21
-rw-r--r--tiger-compiler/src/ast/call-exp.cc27
-rw-r--r--tiger-compiler/src/ast/call-exp.hh64
-rw-r--r--tiger-compiler/src/ast/call-exp.hxx25
-rw-r--r--tiger-compiler/src/ast/cast-exp.cc26
-rw-r--r--tiger-compiler/src/ast/cast-exp.hh62
-rw-r--r--tiger-compiler/src/ast/cast-exp.hxx19
-rw-r--r--tiger-compiler/src/ast/chunk-interface.hh25
-rw-r--r--tiger-compiler/src/ast/chunk-interface.hxx16
-rw-r--r--tiger-compiler/src/ast/chunk-list.cc58
-rw-r--r--tiger-compiler/src/ast/chunk-list.hh80
-rw-r--r--tiger-compiler/src/ast/chunk-list.hxx19
-rw-r--r--tiger-compiler/src/ast/chunk.hh139
-rw-r--r--tiger-compiler/src/ast/chunk.hxx118
-rw-r--r--tiger-compiler/src/ast/class-ty.cc22
-rw-r--r--tiger-compiler/src/ast/class-ty.hh55
-rw-r--r--tiger-compiler/src/ast/class-ty.hxx19
-rw-r--r--tiger-compiler/src/ast/dec.cc17
-rw-r--r--tiger-compiler/src/ast/dec.hh50
-rw-r--r--tiger-compiler/src/ast/dec.hxx15
-rw-r--r--tiger-compiler/src/ast/default-visitor.hh151
-rw-r--r--tiger-compiler/src/ast/default-visitor.hxx247
-rw-r--r--tiger-compiler/src/ast/dumper-dot.cc438
-rw-r--r--tiger-compiler/src/ast/dumper-dot.hh112
-rw-r--r--tiger-compiler/src/ast/dumper-dot.hxx214
-rw-r--r--tiger-compiler/src/ast/escapable.cc14
-rw-r--r--tiger-compiler/src/ast/escapable.hh30
-rw-r--r--tiger-compiler/src/ast/escapable.hxx16
-rw-r--r--tiger-compiler/src/ast/exp.cc16
-rw-r--r--tiger-compiler/src/ast/exp.hh43
-rw-r--r--tiger-compiler/src/ast/exp.hxx11
-rw-r--r--tiger-compiler/src/ast/field-init.cc22
-rw-r--r--tiger-compiler/src/ast/field-init.hh55
-rw-r--r--tiger-compiler/src/ast/field-init.hxx19
-rw-r--r--tiger-compiler/src/ast/field-var.cc22
-rw-r--r--tiger-compiler/src/ast/field-var.hh60
-rw-r--r--tiger-compiler/src/ast/field-var.hxx22
-rw-r--r--tiger-compiler/src/ast/field.cc22
-rw-r--r--tiger-compiler/src/ast/field.hh55
-rw-r--r--tiger-compiler/src/ast/field.hxx19
-rw-r--r--tiger-compiler/src/ast/for-exp.cc28
-rw-r--r--tiger-compiler/src/ast/for-exp.hh60
-rw-r--r--tiger-compiler/src/ast/for-exp.hxx22
-rw-r--r--tiger-compiler/src/ast/function-dec.cc33
-rw-r--r--tiger-compiler/src/ast/function-dec.hh72
-rw-r--r--tiger-compiler/src/ast/function-dec.hxx23
-rw-r--r--tiger-compiler/src/ast/fwd.hh80
-rw-r--r--tiger-compiler/src/ast/if-exp.cc31
-rw-r--r--tiger-compiler/src/ast/if-exp.hh71
-rw-r--r--tiger-compiler/src/ast/if-exp.hxx22
-rw-r--r--tiger-compiler/src/ast/int-exp.cc19
-rw-r--r--tiger-compiler/src/ast/int-exp.hh44
-rw-r--r--tiger-compiler/src/ast/int-exp.hxx15
-rw-r--r--tiger-compiler/src/ast/let-exp.cc26
-rw-r--r--tiger-compiler/src/ast/let-exp.hh55
-rw-r--r--tiger-compiler/src/ast/let-exp.hxx19
-rw-r--r--tiger-compiler/src/ast/libast.cc44
-rw-r--r--tiger-compiler/src/ast/libast.hh26
-rw-r--r--tiger-compiler/src/ast/local.am30
-rw-r--r--tiger-compiler/src/ast/location.hh14
-rw-r--r--tiger-compiler/src/ast/method-call-exp.cc24
-rw-r--r--tiger-compiler/src/ast/method-call-exp.hh70
-rw-r--r--tiger-compiler/src/ast/method-call-exp.hxx21
-rw-r--r--tiger-compiler/src/ast/method-dec.cc22
-rw-r--r--tiger-compiler/src/ast/method-dec.hh45
-rw-r--r--tiger-compiler/src/ast/method-dec.hxx11
-rw-r--r--tiger-compiler/src/ast/name-ty.cc19
-rw-r--r--tiger-compiler/src/ast/name-ty.hh56
-rw-r--r--tiger-compiler/src/ast/name-ty.hxx20
-rw-r--r--tiger-compiler/src/ast/nil-exp.cc19
-rw-r--r--tiger-compiler/src/ast/nil-exp.hh37
-rw-r--r--tiger-compiler/src/ast/nil-exp.hxx11
-rw-r--r--tiger-compiler/src/ast/non-assert-visitor.hh51
-rw-r--r--tiger-compiler/src/ast/non-assert-visitor.hxx34
-rw-r--r--tiger-compiler/src/ast/non-object-visitor.hh92
-rw-r--r--tiger-compiler/src/ast/non-object-visitor.hxx62
-rw-r--r--tiger-compiler/src/ast/object-exp.cc19
-rw-r--r--tiger-compiler/src/ast/object-exp.hh47
-rw-r--r--tiger-compiler/src/ast/object-exp.hxx16
-rw-r--r--tiger-compiler/src/ast/object-visitor.hh89
-rw-r--r--tiger-compiler/src/ast/object-visitor.hxx69
-rw-r--r--tiger-compiler/src/ast/op-exp.cc42
-rw-r--r--tiger-compiler/src/ast/op-exp.hh80
-rw-r--r--tiger-compiler/src/ast/op-exp.hxx21
-rw-r--r--tiger-compiler/src/ast/pretty-printer.cc419
-rw-r--r--tiger-compiler/src/ast/pretty-printer.hh96
-rw-r--r--tiger-compiler/src/ast/record-exp.cc30
-rw-r--r--tiger-compiler/src/ast/record-exp.hh57
-rw-r--r--tiger-compiler/src/ast/record-exp.hxx22
-rw-r--r--tiger-compiler/src/ast/record-ty.cc26
-rw-r--r--tiger-compiler/src/ast/record-ty.hh49
-rw-r--r--tiger-compiler/src/ast/record-ty.hxx16
-rw-r--r--tiger-compiler/src/ast/seq-exp.cc26
-rw-r--r--tiger-compiler/src/ast/seq-exp.hh47
-rw-r--r--tiger-compiler/src/ast/seq-exp.hxx16
-rw-r--r--tiger-compiler/src/ast/simple-var.cc19
-rw-r--r--tiger-compiler/src/ast/simple-var.hh56
-rw-r--r--tiger-compiler/src/ast/simple-var.hxx20
-rw-r--r--tiger-compiler/src/ast/string-exp.cc19
-rw-r--r--tiger-compiler/src/ast/string-exp.hh47
-rw-r--r--tiger-compiler/src/ast/string-exp.hxx16
-rw-r--r--tiger-compiler/src/ast/subscript-var.cc26
-rw-r--r--tiger-compiler/src/ast/subscript-var.hh54
-rw-r--r--tiger-compiler/src/ast/subscript-var.hxx19
-rw-r--r--tiger-compiler/src/ast/tasks.cc32
-rw-r--r--tiger-compiler/src/ast/tasks.hh24
-rw-r--r--tiger-compiler/src/ast/ty.cc17
-rw-r--r--tiger-compiler/src/ast/ty.hh39
-rw-r--r--tiger-compiler/src/ast/ty.hxx11
-rw-r--r--tiger-compiler/src/ast/typable.cc15
-rw-r--r--tiger-compiler/src/ast/typable.hh50
-rw-r--r--tiger-compiler/src/ast/typable.hxx24
-rw-r--r--tiger-compiler/src/ast/type-constructor.cc31
-rw-r--r--tiger-compiler/src/ast/type-constructor.hh38
-rw-r--r--tiger-compiler/src/ast/type-constructor.hxx23
-rw-r--r--tiger-compiler/src/ast/type-dec.cc22
-rw-r--r--tiger-compiler/src/ast/type-dec.hh51
-rw-r--r--tiger-compiler/src/ast/type-dec.hxx16
-rw-r--r--tiger-compiler/src/ast/var-dec.cc31
-rw-r--r--tiger-compiler/src/ast/var-dec.hh61
-rw-r--r--tiger-compiler/src/ast/var-dec.hxx19
-rw-r--r--tiger-compiler/src/ast/var.cc15
-rw-r--r--tiger-compiler/src/ast/var.hh26
-rw-r--r--tiger-compiler/src/ast/var.hxx11
-rw-r--r--tiger-compiler/src/ast/visitor.hh114
-rw-r--r--tiger-compiler/src/ast/visitor.hxx36
-rw-r--r--tiger-compiler/src/ast/while-exp.cc26
-rw-r--r--tiger-compiler/src/ast/while-exp.hh53
-rw-r--r--tiger-compiler/src/ast/while-exp.hxx19
-rw-r--r--tiger-compiler/src/astclone/cloner.cc311
-rw-r--r--tiger-compiler/src/astclone/cloner.hh102
-rw-r--r--tiger-compiler/src/astclone/cloner.hxx72
-rw-r--r--tiger-compiler/src/astclone/libastclone.hh42
-rw-r--r--tiger-compiler/src/astclone/libastclone.hxx40
-rw-r--r--tiger-compiler/src/astclone/local.am12
-rw-r--r--tiger-compiler/src/astclone/tasks.cc26
-rw-r--r--tiger-compiler/src/astclone/tasks.hh20
-rw-r--r--tiger-compiler/src/bind/binder.cc183
-rw-r--r--tiger-compiler/src/bind/binder.hh138
-rw-r--r--tiger-compiler/src/bind/binder.hxx124
-rw-r--r--tiger-compiler/src/bind/libbind.cc31
-rw-r--r--tiger-compiler/src/bind/libbind.hh29
-rw-r--r--tiger-compiler/src/bind/local.am17
-rw-r--r--tiger-compiler/src/bind/renamer.cc63
-rw-r--r--tiger-compiler/src/bind/renamer.hh62
-rw-r--r--tiger-compiler/src/bind/renamer.hxx24
-rw-r--r--tiger-compiler/src/bind/tasks.cc34
-rw-r--r--tiger-compiler/src/bind/tasks.hh42
-rw-r--r--tiger-compiler/src/callgraph/call-graph-visitor.cc56
-rw-r--r--tiger-compiler/src/callgraph/call-graph-visitor.hh38
-rw-r--r--tiger-compiler/src/callgraph/fundec-graph.hh76
-rw-r--r--tiger-compiler/src/callgraph/fundec-graph.hxx56
-rw-r--r--tiger-compiler/src/callgraph/libcallgraph.cc36
-rw-r--r--tiger-compiler/src/callgraph/libcallgraph.hh28
-rw-r--r--tiger-compiler/src/callgraph/local.am14
-rw-r--r--tiger-compiler/src/callgraph/parent-graph-visitor.cc42
-rw-r--r--tiger-compiler/src/callgraph/parent-graph-visitor.hh36
-rw-r--r--tiger-compiler/src/callgraph/tasks.cc52
-rw-r--r--tiger-compiler/src/callgraph/tasks.hh46
-rw-r--r--tiger-compiler/src/combine/binder.cc17
-rw-r--r--tiger-compiler/src/combine/binder.hh16
-rw-r--r--tiger-compiler/src/combine/libcombine.cc26
-rw-r--r--tiger-compiler/src/combine/libcombine.hh44
-rw-r--r--tiger-compiler/src/combine/local.am6
-rw-r--r--tiger-compiler/src/combine/tasks.cc74
-rw-r--r--tiger-compiler/src/combine/tasks.hh56
-rw-r--r--tiger-compiler/src/combine/type-checker.cc14
-rw-r--r--tiger-compiler/src/combine/type-checker.hh20
-rw-r--r--tiger-compiler/src/common.cc19
-rw-r--r--tiger-compiler/src/common.hh49
-rw-r--r--tiger-compiler/src/desugar/bounds-checking-visitor.cc31
-rw-r--r--tiger-compiler/src/desugar/bounds-checking-visitor.hh46
-rw-r--r--tiger-compiler/src/desugar/desugar-visitor.cc144
-rw-r--r--tiger-compiler/src/desugar/desugar-visitor.hh42
-rw-r--r--tiger-compiler/src/desugar/libdesugar.hh85
-rw-r--r--tiger-compiler/src/desugar/libdesugar.hxx95
-rw-r--r--tiger-compiler/src/desugar/local.am27
-rw-r--r--tiger-compiler/src/desugar/tasks.cc49
-rw-r--r--tiger-compiler/src/desugar/tasks.hh75
-rw-r--r--tiger-compiler/src/doc.hh23
-rw-r--r--tiger-compiler/src/escapes/escapes-visitor.cc31
-rw-r--r--tiger-compiler/src/escapes/escapes-visitor.hh75
-rw-r--r--tiger-compiler/src/escapes/libescapes.cc23
-rw-r--r--tiger-compiler/src/escapes/libescapes.hh23
-rw-r--r--tiger-compiler/src/escapes/local.am7
-rw-r--r--tiger-compiler/src/escapes/tasks.cc38
-rw-r--r--tiger-compiler/src/escapes/tasks.hh28
-rw-r--r--tiger-compiler/src/inlining/inliner.cc64
-rw-r--r--tiger-compiler/src/inlining/inliner.hh44
-rw-r--r--tiger-compiler/src/inlining/libinlining.cc54
-rw-r--r--tiger-compiler/src/inlining/libinlining.hh42
-rw-r--r--tiger-compiler/src/inlining/local.am8
-rw-r--r--tiger-compiler/src/inlining/pruner.cc34
-rw-r--r--tiger-compiler/src/inlining/pruner.hh42
-rw-r--r--tiger-compiler/src/inlining/tasks.cc31
-rw-r--r--tiger-compiler/src/inlining/tasks.hh36
-rw-r--r--tiger-compiler/src/llvmtranslate/escapes-collector.cc151
-rw-r--r--tiger-compiler/src/llvmtranslate/escapes-collector.hh13
-rw-r--r--tiger-compiler/src/llvmtranslate/fwd.hh31
-rwxr-xr-xtiger-compiler/src/llvmtranslate/generate-runtime.sh32
-rw-r--r--tiger-compiler/src/llvmtranslate/libllvmtranslate.cc47
-rw-r--r--tiger-compiler/src/llvmtranslate/libllvmtranslate.hh31
-rw-r--r--tiger-compiler/src/llvmtranslate/llvm-type-visitor.cc110
-rw-r--r--tiger-compiler/src/llvmtranslate/llvm-type-visitor.hh50
-rw-r--r--tiger-compiler/src/llvmtranslate/local.am39
-rw-r--r--tiger-compiler/src/llvmtranslate/tasks.cc64
-rw-r--r--tiger-compiler/src/llvmtranslate/tasks.hh34
-rw-r--r--tiger-compiler/src/llvmtranslate/tiger-runtime.c304
-rw-r--r--tiger-compiler/src/llvmtranslate/translator.cc737
-rw-r--r--tiger-compiler/src/llvmtranslate/translator.hh145
-rw-r--r--tiger-compiler/src/llvmtranslate/translator.hxx30
-rw-r--r--tiger-compiler/src/local.am75
-rw-r--r--tiger-compiler/src/object/binder.cc176
-rw-r--r--tiger-compiler/src/object/binder.hh98
-rw-r--r--tiger-compiler/src/object/desugar-visitor.cc1127
-rw-r--r--tiger-compiler/src/object/desugar-visitor.hh301
-rw-r--r--tiger-compiler/src/object/fwd.hh16
-rw-r--r--tiger-compiler/src/object/libobject.cc49
-rw-r--r--tiger-compiler/src/object/libobject.hh82
-rw-r--r--tiger-compiler/src/object/libobject.hxx48
-rw-r--r--tiger-compiler/src/object/local.am33
-rw-r--r--tiger-compiler/src/object/renamer.cc142
-rw-r--r--tiger-compiler/src/object/renamer.hh79
-rw-r--r--tiger-compiler/src/object/tasks.cc52
-rw-r--r--tiger-compiler/src/object/tasks.hh60
-rw-r--r--tiger-compiler/src/object/type-checker.cc405
-rw-r--r--tiger-compiler/src/object/type-checker.hh108
-rw-r--r--tiger-compiler/src/overload/binder.cc45
-rw-r--r--tiger-compiler/src/overload/binder.hh65
-rw-r--r--tiger-compiler/src/overload/liboverload.cc28
-rw-r--r--tiger-compiler/src/overload/liboverload.hh36
-rw-r--r--tiger-compiler/src/overload/local.am9
-rw-r--r--tiger-compiler/src/overload/over-table.hh63
-rw-r--r--tiger-compiler/src/overload/over-table.hxx64
-rw-r--r--tiger-compiler/src/overload/tasks.cc38
-rw-r--r--tiger-compiler/src/overload/tasks.hh29
-rw-r--r--tiger-compiler/src/overload/type-checker.cc21
-rw-r--r--tiger-compiler/src/overload/type-checker.hh37
-rw-r--r--tiger-compiler/src/parse/fwd.hh38
-rwxr-xr-xtiger-compiler/src/parse/generate-prelude.sh31
-rw-r--r--tiger-compiler/src/parse/libparse.cc137
-rw-r--r--tiger-compiler/src/parse/libparse.hh76
-rw-r--r--tiger-compiler/src/parse/local.am125
-rw-r--r--tiger-compiler/src/parse/metavar-map.hh48
-rw-r--r--tiger-compiler/src/parse/metavar-map.hxx69
-rw-r--r--tiger-compiler/src/parse/tasks.cc53
-rw-r--r--tiger-compiler/src/parse/tasks.hh51
-rw-r--r--tiger-compiler/src/parse/tiger-driver.cc215
-rw-r--r--tiger-compiler/src/parse/tiger-driver.hh110
-rw-r--r--tiger-compiler/src/parse/tiger-factory.hh144
-rw-r--r--tiger-compiler/src/parse/tiger-factory.hxx272
-rw-r--r--tiger-compiler/src/parse/tweast.cc87
-rw-r--r--tiger-compiler/src/parse/tweast.hh79
-rw-r--r--tiger-compiler/src/parse/tweast.hxx75
-rw-r--r--tiger-compiler/src/task/argument-task.cc29
-rw-r--r--tiger-compiler/src/task/argument-task.hh58
-rw-r--r--tiger-compiler/src/task/boolean-task.cc22
-rw-r--r--tiger-compiler/src/task/boolean-task.hh28
-rw-r--r--tiger-compiler/src/task/disjunctive-task.cc32
-rw-r--r--tiger-compiler/src/task/disjunctive-task.hh27
-rw-r--r--tiger-compiler/src/task/function-task.cc22
-rw-r--r--tiger-compiler/src/task/function-task.hh31
-rw-r--r--tiger-compiler/src/task/fwd.hh22
-rw-r--r--tiger-compiler/src/task/int-task.cc55
-rw-r--r--tiger-compiler/src/task/int-task.hh33
-rw-r--r--tiger-compiler/src/task/libtask.hh107
-rw-r--r--tiger-compiler/src/task/local.am15
-rw-r--r--tiger-compiler/src/task/multiple-string-task.cc21
-rw-r--r--tiger-compiler/src/task/multiple-string-task.hh34
-rw-r--r--tiger-compiler/src/task/simple-task.cc21
-rw-r--r--tiger-compiler/src/task/simple-task.hh34
-rw-r--r--tiger-compiler/src/task/string-task.cc22
-rw-r--r--tiger-compiler/src/task/string-task.hh28
-rw-r--r--tiger-compiler/src/task/task-register.cc353
-rw-r--r--tiger-compiler/src/task/task-register.hh118
-rw-r--r--tiger-compiler/src/task/task-register.hxx15
-rw-r--r--tiger-compiler/src/task/task.cc68
-rw-r--r--tiger-compiler/src/task/task.hh103
-rw-r--r--tiger-compiler/src/task/task.hxx24
-rw-r--r--tiger-compiler/src/task/tasks.cc28
-rw-r--r--tiger-compiler/src/task/tasks.hh23
-rw-r--r--tiger-compiler/src/tc.cc53
-rw-r--r--tiger-compiler/src/testsuite/libtestsuite.cc30
-rw-r--r--tiger-compiler/src/testsuite/libtestsuite.hh41
-rw-r--r--tiger-compiler/src/testsuite/local.am15
-rw-r--r--tiger-compiler/src/testsuite/tasks.cc49
-rw-r--r--tiger-compiler/src/testsuite/tasks.hh21
-rw-r--r--tiger-compiler/src/testsuite/tests-collector.cc19
-rw-r--r--tiger-compiler/src/testsuite/tests-collector.hh53
-rw-r--r--tiger-compiler/src/testsuite/tests-collector.hxx21
-rw-r--r--tiger-compiler/src/testsuite/testsuite-generator.cc143
-rw-r--r--tiger-compiler/src/testsuite/testsuite-generator.hh23
-rw-r--r--tiger-compiler/src/type/README.txt92
-rw-r--r--tiger-compiler/src/type/array.cc28
-rw-r--r--tiger-compiler/src/type/array.hh30
-rw-r--r--tiger-compiler/src/type/array.hxx18
-rw-r--r--tiger-compiler/src/type/attribute.cc16
-rw-r--r--tiger-compiler/src/type/attribute.hh44
-rw-r--r--tiger-compiler/src/type/attribute.hxx25
-rw-r--r--tiger-compiler/src/type/builtin-types.cc22
-rw-r--r--tiger-compiler/src/type/builtin-types.hh40
-rw-r--r--tiger-compiler/src/type/class.cc123
-rw-r--r--tiger-compiler/src/type/class.hh159
-rw-r--r--tiger-compiler/src/type/class.hxx88
-rw-r--r--tiger-compiler/src/type/default-visitor.hh65
-rw-r--r--tiger-compiler/src/type/default-visitor.hxx95
-rw-r--r--tiger-compiler/src/type/field.cc17
-rw-r--r--tiger-compiler/src/type/field.hh45
-rw-r--r--tiger-compiler/src/type/field.hxx16
-rw-r--r--tiger-compiler/src/type/function.cc38
-rw-r--r--tiger-compiler/src/type/function.hh59
-rw-r--r--tiger-compiler/src/type/function.hxx16
-rw-r--r--tiger-compiler/src/type/fwd.hh31
-rw-r--r--tiger-compiler/src/type/libtype.cc19
-rw-r--r--tiger-compiler/src/type/libtype.hh19
-rw-r--r--tiger-compiler/src/type/local.am29
-rw-r--r--tiger-compiler/src/type/method.cc48
-rw-r--r--tiger-compiler/src/type/method.hh90
-rw-r--r--tiger-compiler/src/type/method.hxx27
-rw-r--r--tiger-compiler/src/type/named.cc61
-rw-r--r--tiger-compiler/src/type/named.hh90
-rw-r--r--tiger-compiler/src/type/named.hxx28
-rw-r--r--tiger-compiler/src/type/nil.cc34
-rw-r--r--tiger-compiler/src/type/nil.hh47
-rw-r--r--tiger-compiler/src/type/pretty-printer.cc127
-rw-r--r--tiger-compiler/src/type/pretty-printer.hh67
-rw-r--r--tiger-compiler/src/type/record.cc52
-rw-r--r--tiger-compiler/src/type/record.hh69
-rw-r--r--tiger-compiler/src/type/record.hxx34
-rw-r--r--tiger-compiler/src/type/tasks.cc22
-rw-r--r--tiger-compiler/src/type/tasks.hh29
-rw-r--r--tiger-compiler/src/type/type-checker.cc639
-rw-r--r--tiger-compiler/src/type/type-checker.hh279
-rw-r--r--tiger-compiler/src/type/type-checker.hxx127
-rw-r--r--tiger-compiler/src/type/type.cc18
-rw-r--r--tiger-compiler/src/type/type.hh66
-rw-r--r--tiger-compiler/src/type/type.hxx37
-rw-r--r--tiger-compiler/src/type/types.hh18
-rw-r--r--tiger-compiler/src/type/visitor.hh57
-rw-r--r--tiger-compiler/src/type/visitor.hxx29
-rw-r--r--tiger-compiler/src/version.cc.in34
-rw-r--r--tiger-compiler/src/version.hh23
379 files changed, 22593 insertions, 0 deletions
diff --git a/tiger-compiler/src/assert/binder.cc b/tiger-compiler/src/assert/binder.cc
new file mode 100644
index 0000000..04008bc
--- /dev/null
+++ b/tiger-compiler/src/assert/binder.cc
@@ -0,0 +1,12 @@
+/**
+ ** \file assert/binder.cc
+ ** \brief Implementation of assert::Binder.
+ */
+
+#include <assert/binder.hh>
+
+namespace assert {
+
+ Binder::Binder() = default;
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/binder.hh b/tiger-compiler/src/assert/binder.hh
new file mode 100644
index 0000000..7ede6d7
--- /dev/null
+++ b/tiger-compiler/src/assert/binder.hh
@@ -0,0 +1,22 @@
+/**
+ ** \file assert/binder.hh
+ ** \brief Declaration of assert::Binder.
+ */
+
+#pragma once
+
+#include <bind/binder.hh>
+
+namespace assert {
+
+ class Binder
+ : public bind::Binder
+ {
+ public:
+ using super_class = bind::Binder;
+
+ // Build a Binder
+ Binder();
+ };
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/desugar-visitor.cc b/tiger-compiler/src/assert/desugar-visitor.cc
new file mode 100644
index 0000000..5f18a07
--- /dev/null
+++ b/tiger-compiler/src/assert/desugar-visitor.cc
@@ -0,0 +1,33 @@
+/**
+ ** \file assert/desugar-visitor.cc
+ ** \brief Implementation of assert::DesugarVisitor.
+ */
+
+#include <assert/desugar-visitor.hh>
+
+namespace assert
+{
+
+ DesugarVisitor::DesugarVisitor(const bool desugar_for_p,
+ const bool desugar_string_cmp_p)
+ : super_type(desugar_for_p, desugar_string_cmp_p)
+ {}
+
+ void DesugarVisitor::operator()(const ast::AssertExp& e)
+ {
+ // FIXME DONE: Some code was deleted here. (replace the AssertExp to a CallExp)
+ const ast::Location location = e.location_get();
+
+ const auto args = new ast::exps_type;
+
+ const std::string condition_text = get_formatted_assert_cond(e);
+ const std::string filename = get_formatted_location(e.location_get());
+
+ args->push_back(recurse(e.cond_get()));
+ args->push_back(new ast::StringExp(location, condition_text));
+ args->push_back(new ast::StringExp(location, filename));
+
+ result_ = new ast::CallExp(location, "assertion", args);
+ }
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/desugar-visitor.hh b/tiger-compiler/src/assert/desugar-visitor.hh
new file mode 100644
index 0000000..88d689e
--- /dev/null
+++ b/tiger-compiler/src/assert/desugar-visitor.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file assert/desugar-visitor.hh
+ ** \brief Declaration of assert::DesugarVisitor.
+ */
+
+#pragma once
+
+#include <ast/assert-visitor.hh>
+#include <desugar/desugar-visitor.hh>
+
+namespace assert {
+
+ class DesugarVisitor
+ : public desugar::DesugarVisitor
+ , public ast::AssertConstVisitor
+ {
+ public:
+ using super_type = desugar::DesugarVisitor;
+ using super_type::operator();
+
+ // Build a DesugarVisitor
+ DesugarVisitor(bool desugar_for_p, bool desugar_string_cmp_p);
+
+ // Desugar assertions
+ // \param e Node to visit
+ void operator()(const ast::AssertExp& e) override;
+
+ private:
+
+ // Retrieve the pretty-printed version of an assertion's condition as a
+ // string
+ // \param e Node to pretty-print.
+ inline std::string get_formatted_assert_cond(const ast::AssertExp& e);
+
+ // Retrieve the pretty-printed version of a Location as a string
+ // \param loc Location record to pretty-print
+ inline std::string get_formatted_location(const ast::Location& loc);
+ };
+
+} // namespace assert
+
+#include <assert/desugar-visitor.hxx>
diff --git a/tiger-compiler/src/assert/desugar-visitor.hxx b/tiger-compiler/src/assert/desugar-visitor.hxx
new file mode 100644
index 0000000..9e839c1
--- /dev/null
+++ b/tiger-compiler/src/assert/desugar-visitor.hxx
@@ -0,0 +1,39 @@
+/**
+ ** \file assert/desugar-visitor.hxx
+ ** \brief Implementation of assert::DesugarVisitor (inlined methods).
+ */
+
+#pragma once
+
+#include <assert/desugar-visitor.hh>
+
+#include <sstream>
+#include <string>
+
+#include <ast/pretty-printer.hh>
+
+namespace assert
+{
+
+ inline std::string
+ DesugarVisitor::get_formatted_assert_cond(const ast::AssertExp& e)
+ {
+ std::stringstream stream{};
+ ast::PrettyPrinter pretty_printer(stream);
+
+ pretty_printer(e.cond_get());
+
+ return stream.str();
+ }
+
+ inline std::string
+ DesugarVisitor::get_formatted_location(const ast::Location& loc)
+ {
+ std::stringstream stream{};
+
+ stream << loc;
+
+ return stream.str();
+ }
+
+}
diff --git a/tiger-compiler/src/assert/libassert.cc b/tiger-compiler/src/assert/libassert.cc
new file mode 100644
index 0000000..8114b74
--- /dev/null
+++ b/tiger-compiler/src/assert/libassert.cc
@@ -0,0 +1,36 @@
+/**
+ ** \file assert/libassert.cc
+ ** \brief Implementation of functions exported by the assert module.
+ */
+
+#include <assert/binder.hh>
+#include <assert/libassert.hh>
+#include <assert/renamer.hh>
+#include <assert/type-checker.hh>
+#include <misc/error.hh>
+
+namespace assert
+{
+
+ misc::error bind(ast::Ast& last)
+ {
+ Binder binder;
+ binder(last);
+ return binder.error_get();
+ }
+
+ misc::error types_check(ast::Ast& tree)
+ {
+ TypeChecker typer;
+ typer(tree);
+ return typer.error_get();
+ }
+
+ misc::error rename(ast::Ast& ast)
+ {
+ Renamer renamer;
+ renamer(ast);
+ return misc::error{};
+ }
+
+}
diff --git a/tiger-compiler/src/assert/libassert.hh b/tiger-compiler/src/assert/libassert.hh
new file mode 100644
index 0000000..aba01b1
--- /dev/null
+++ b/tiger-compiler/src/assert/libassert.hh
@@ -0,0 +1,79 @@
+/**
+ ** \file assert/libassert.hh
+ ** \brief Declare functions and variables exported by assert module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+
+namespace assert
+{
+ /*-------.
+ | Bind. |
+ `-------*/
+
+ /// \brief Bind the whole AST in place, return the error code
+ ///
+ /// \param last the ast you want to bind
+ ///
+ /// \return a misc::error that serve to indicate possible failure
+ misc::error bind(ast::Ast& last);
+
+ /*----------------.
+ | Compute types. |
+ `----------------*/
+
+ /** \brief Check types allowing assertions.
+
+ \param tree abstract syntax tree's root.
+
+ \return success of the type-checking. */
+ misc::error types_check(ast::Ast& tree);
+
+ /*---------.
+ | Rename. |
+ `---------*/
+
+ /// \brief Rename the whole ast in place
+ ///
+ /// \param ast the ast you want to rename
+ ///
+ /// \return a misc::error that serve to indicate possible failure
+ misc::error rename(ast::Ast& ast);
+
+ /*---------------------.
+ | Desugar assertions. |
+ `---------------------*/
+
+ /** \brief Remove assertions constructs from an AST.
+
+ \param tree abstract syntax tree's root, whose bindings
+ and types have been computed, and whose
+ identifiers are all unique.
+ \param class_names the names of the class types of the AST
+
+ \return the desugared, bound and type-checked AST. */
+ template <typename A>
+ A* desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p);
+
+ /** \brief Remove assertions constructs from an AST without recomputing
+ its bindings nor its types.
+
+ This function acts like assertions::assertions_desugar, but stops just
+ after the desugaring step (in fact, assertions::desugar is built
+ upon this function). It is meant to be used as a test of
+ DesugarVisitor (i.e., even if the desugared tree is badly bound
+ or typed, it can still be pretty-printed).
+
+ \param tree AST to desugar.
+ \param class_names the names of the class types of the AST
+
+ \return the desugared AST. */
+ template <typename A>
+ A* raw_desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p);
+
+}
+
+#include <assert/libassert.hxx>
diff --git a/tiger-compiler/src/assert/libassert.hxx b/tiger-compiler/src/assert/libassert.hxx
new file mode 100644
index 0000000..fcd2eb4
--- /dev/null
+++ b/tiger-compiler/src/assert/libassert.hxx
@@ -0,0 +1,45 @@
+/**
+ ** \file assert/libassert.hxx
+ ** \brief Implementation of functions exported by the assert module.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <assert/desugar-visitor.hh>
+#include <assert/libassert.hh>
+#include <misc/contract.hh>
+#include <misc/error.hh>
+
+namespace assert
+{
+
+ template <typename A> void bind_and_types_check(A& tree)
+ {
+ misc::error e;
+ e << ::assert::bind(tree);
+ e.ice_on_error_here();
+ e << ::assert::types_check(tree);
+ e.ice_on_error_here();
+ }
+
+ template <typename A>
+ A* raw_desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p)
+ {
+ DesugarVisitor desugar(desugar_for_p, desugar_string_cmp_p);
+ desugar(tree);
+ return dynamic_cast<A*>(desugar.result_get());
+ }
+
+ template <typename A>
+ A* desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p)
+ {
+ A* desugared = raw_desugar(tree, desugar_for_p, desugar_string_cmp_p);
+ assertion(desugared);
+ std::unique_ptr<A> desugared_ptr(desugared);
+ bind_and_types_check(*desugared_ptr);
+ return desugared_ptr.release();
+ }
+
+}
diff --git a/tiger-compiler/src/assert/local.am b/tiger-compiler/src/assert/local.am
new file mode 100644
index 0000000..18a8421
--- /dev/null
+++ b/tiger-compiler/src/assert/local.am
@@ -0,0 +1,17 @@
+## assert module
+
+src_libtc_la_SOURCES += \
+ %D%/libassert.hh \
+ %D%/libassert.cc \
+ %D%/libassert.hxx
+
+src_libtc_la_SOURCES += \
+ %D%/binder.hh %D%/binder.cc \
+ %D%/desugar-visitor.hh %D%/desugar-visitor.cc %D%/desugar-visitor.hxx \
+ %D%/type-checker.hh %D%/type-checker.cc \
+ %D%/renamer.hh %D%/renamer.cc
+
+
+## tasks
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/assert/renamer.cc b/tiger-compiler/src/assert/renamer.cc
new file mode 100644
index 0000000..7c63cfa
--- /dev/null
+++ b/tiger-compiler/src/assert/renamer.cc
@@ -0,0 +1,18 @@
+/**
+ ** \file assert/renamer.cc
+ ** \brief Implementation of assert::Renamer.
+ */
+
+#include <assert/renamer.hh>
+
+namespace assert
+{
+
+ Renamer::Renamer() = default;
+
+ void Renamer::operator()(ast::AssertExp& e)
+ {
+ ast::AssertVisitor::operator()(e);
+ }
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/renamer.hh b/tiger-compiler/src/assert/renamer.hh
new file mode 100644
index 0000000..6a5bd14
--- /dev/null
+++ b/tiger-compiler/src/assert/renamer.hh
@@ -0,0 +1,30 @@
+/**
+ ** \file assert/renamer.hh
+ ** \brief Declaration of assert::Renamer.
+ */
+
+#pragma once
+
+#include <ast/assert-visitor.hh>
+#include <bind/renamer.hh>
+
+namespace assert {
+
+ class Renamer
+ : public bind::Renamer
+ , public ast::AssertVisitor
+ {
+ public:
+ using super_type = ::bind::Renamer;
+ using super_type::operator();
+
+ // Build a renamer
+ Renamer();
+
+ // Visiting method for AssertExp nodes (redirects to
+ // `ast::AssertVisitor::operator()(ast::AssertExp&)`)
+ // \param e Node to visit
+ void operator()(ast::AssertExp& e) override;
+ };
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/tasks.cc b/tiger-compiler/src/assert/tasks.cc
new file mode 100644
index 0000000..3e43ecd
--- /dev/null
+++ b/tiger-compiler/src/assert/tasks.cc
@@ -0,0 +1,53 @@
+/**
+ ** \file assert/tasks.cc
+ ** \brief Assert module related tasks' implementation.
+ */
+
+#include <ast/tasks.hh>
+#include <astclone/libastclone.hh>
+#include <assert/libassert.hh>
+#include <common.hh>
+#include <desugar/tasks.hh>
+#include <escapes/tasks.hh>
+#include <llvmtranslate/tasks.hh>
+#define DEFINE_TASKS 1
+#include <assert/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace assert::tasks
+{
+ void parse() {}
+
+ void bind()
+ {
+ task_error() << ::assert::bind(*ast::tasks::the_program.get())
+ << &misc::error::exit_on_error;
+ }
+
+ void types_compute()
+ {
+ task_error() << ::assert::types_check(*ast::tasks::the_program.get())
+ << &misc::error::exit_on_error;
+ }
+
+ void rename()
+ {
+ task_error() << ::assert::rename(*ast::tasks::the_program.get())
+ << &misc::error::exit_on_error;
+ }
+
+ void desugar()
+ {
+ astclone::apply(::assert::desugar, ast::tasks::the_program,
+ desugar::tasks::desugar_for_p,
+ desugar::tasks::desugar_string_cmp_p);
+ }
+
+ void raw_desugar()
+ {
+ astclone::apply(::assert::raw_desugar, ast::tasks::the_program,
+ desugar::tasks::desugar_for_p,
+ desugar::tasks::desugar_string_cmp_p);
+ }
+
+} // namespace assert::tasks
diff --git a/tiger-compiler/src/assert/tasks.hh b/tiger-compiler/src/assert/tasks.hh
new file mode 100644
index 0000000..7f062de
--- /dev/null
+++ b/tiger-compiler/src/assert/tasks.hh
@@ -0,0 +1,59 @@
+/**
+ ** \file assert/tasks.hh
+ ** \brief Assert module related tasks.
+ */
+
+#pragma once
+
+#include <task/libtask.hh>
+
+// The tasks of the assert module
+namespace assert::tasks
+{
+ TASK_GROUP("Assert");
+
+ // Enable assert extensions.
+ BOOLEAN_TASK_DECLARE("assert",
+ "enable assert extensions",
+ enable_assert_extensions_p,
+ "");
+
+ // Parse the input file, allowing assertions.
+ TASK_DECLARE("assert-parse",
+ "parse a file, allowing assertions",
+ parse,
+ "assert parse");
+
+ // Bind the parsed file, allowing assertions.
+ TASK_DECLARE("assert-bindings-compute",
+ "bind the name uses to their definitions, allowing assertions",
+ bind,
+ "assert-parse");
+
+ // Check for type violation, allowing assertions.
+ TASK_DECLARE("assert-types-compute",
+ "check for type violations, allowing assertions",
+ types_compute,
+ "assert-bindings-compute");
+
+ // Perform a renaming, before desugaring assertions.
+ TASK_DECLARE("assert-rename",
+ "rename identifiers to unique names, allowing assertions",
+ rename,
+ "assert-bindings-compute");
+
+ // Remove syntactic sugar from the Ast.
+ TASK_DECLARE("assert-desugar",
+ "remove assertions constructs from the program",
+ desugar,
+ "assert-rename assert-types-compute");
+
+ // Remove syntactic sugar from the Ast without recomputing
+ // bindings nor types.
+ TASK_DECLARE("raw-assert-desugar",
+ "remove assertions constructs from the program "
+ "without recomputing bindings nor types",
+ raw_desugar,
+ "assert-rename assert-types-compute");
+
+} // namespace assert::tasks
diff --git a/tiger-compiler/src/assert/type-checker.cc b/tiger-compiler/src/assert/type-checker.cc
new file mode 100644
index 0000000..894ff6f
--- /dev/null
+++ b/tiger-compiler/src/assert/type-checker.cc
@@ -0,0 +1,21 @@
+/**
+ ** \file assert/type-checker.cc
+ ** \brief Implementation of assert::TypeChecker.
+ */
+
+#include <assert/type-checker.hh>
+
+namespace assert
+{
+
+ TypeChecker::TypeChecker() = default;
+
+ void TypeChecker::operator()(ast::AssertExp& e)
+ {
+ // FIXME DONE: Some code was deleted here. (implement method documentation)
+ check_type(e.cond_get(), "assertion", type::Int::instance());
+
+ type_default(e, &type::Void::instance());
+ }
+
+} // namespace assert
diff --git a/tiger-compiler/src/assert/type-checker.hh b/tiger-compiler/src/assert/type-checker.hh
new file mode 100644
index 0000000..e15e393
--- /dev/null
+++ b/tiger-compiler/src/assert/type-checker.hh
@@ -0,0 +1,30 @@
+/**
+ ** \file assert/type-checker.hh
+ ** \brief Declaration of assert::TypeChecker.
+ */
+
+#pragma once
+
+#include <ast/assert-visitor.hh>
+#include <type/type-checker.hh>
+
+namespace assert {
+
+ class TypeChecker
+ : public type::TypeChecker
+ , public ast::AssertVisitor
+ {
+ public:
+ using super_type = type::TypeChecker;
+ using super_type::operator();
+
+ // Build a TypeChecker
+ TypeChecker();
+
+ // Type an AssertExp node. All AssertExp must follow the typing table :
+ // cond_ : int | assert cond_ : void
+ // \param e Node to visit
+ void operator()(ast::AssertExp& e) override;
+ };
+
+} // assert
diff --git a/tiger-compiler/src/ast/README.txt b/tiger-compiler/src/ast/README.txt
new file mode 100644
index 0000000..4291b24
--- /dev/null
+++ b/tiger-compiler/src/ast/README.txt
@@ -0,0 +1,66 @@
+* README
+
+Tiger Abstract Syntax Tree nodes with their principal members.
+Incomplete classes are tagged with a `*'.
+
+/Ast/ (Location location)
+ /Dec/ (symbol name)
+ FunctionDec (VarChunk formals, NameTy result, Exp body)
+ MethodDec ()
+ TypeDec (Ty ty)
+ VarDec (NameTy type_name, Exp init)
+
+ /Exp/ ()
+ /Var/ ()
+ FieldVar (Var var, symbol name)
+ SimpleVar (symbol name)
+ SubscriptVar (Var var, Exp index)
+
+ ArrayExp (NameTy type_name, Exp size, Exp init)
+ AssertExp (Exp exp)
+ AssignExp (Var var, Exp exp)
+ BreakExp ()
+ CallExp (symbol name, exps_type args)
+ MethodCallExp (Var object)
+ CastExp (Exp exp, Ty ty)
+ ForExp (VarDec vardec, Exp hi, Exp body)
+ IfExp (Exp test, Exp thenclause, Exp elseclause)
+ IntExp (int value)
+ LetExp (ChunkList chunks, Exp body)
+ NilExp ()
+ ObjectExp (NameTy type_name)
+ OpExp (Exp left, Oper oper, Exp right)
+ RecordExp (NameTy type_name, fieldinits_type fields)
+ SeqExp (exps_type exps)
+ StringExp (string value)
+ WhileExp (Exp test, Exp body)
+
+ /Ty/ ()
+ ArrayTy (NameTy base_type)
+ ClassTy (NameTy super, ChunkList chunks)
+ NameTy (symbol name)
+ RecordTy (fields_type fields)
+
+ ChunkList (list_type chunks)
+
+ Field (symbol name, NameTy type_name)
+
+ FieldInit (symbol name, Exp init)
+
+
+Some of these classes also inherit from other classes.
+
+/Escapable/
+ VarDec (NameTy type_name, Exp init)
+
+/Typable/
+ /Dec/ (symbol name)
+ /Exp/ ()
+ /Ty/ ()
+
+/TypeConstructor/
+ /Ty/ ()
+ FunctionDec (VarChunk formals, NameTy result, Exp body)
+ NilExp ()
+ TypeDec (Ty ty)
+
diff --git a/tiger-compiler/src/ast/all.hh b/tiger-compiler/src/ast/all.hh
new file mode 100644
index 0000000..c55c3eb
--- /dev/null
+++ b/tiger-compiler/src/ast/all.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file ast/all.hh
+ ** \brief Include all the exported headers.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+
+#include <ast/chunk.hh>
+
+#include <ast/array-exp.hh>
+#include <ast/array-ty.hh>
+#include <ast/assert-exp.hh>
+#include <ast/assign-exp.hh>
+#include <ast/ast.hh>
+#include <ast/break-exp.hh>
+#include <ast/call-exp.hh>
+#include <ast/cast-exp.hh>
+#include <ast/chunk-list.hh>
+#include <ast/class-ty.hh>
+#include <ast/dec.hh>
+#include <ast/escapable.hh>
+#include <ast/exp.hh>
+#include <ast/field-init.hh>
+#include <ast/field-var.hh>
+#include <ast/field.hh>
+#include <ast/for-exp.hh>
+#include <ast/function-dec.hh>
+#include <ast/if-exp.hh>
+#include <ast/int-exp.hh>
+#include <ast/let-exp.hh>
+#include <ast/method-call-exp.hh>
+#include <ast/method-dec.hh>
+#include <ast/name-ty.hh>
+#include <ast/nil-exp.hh>
+#include <ast/object-exp.hh>
+#include <ast/op-exp.hh>
+#include <ast/record-exp.hh>
+#include <ast/record-ty.hh>
+#include <ast/seq-exp.hh>
+#include <ast/simple-var.hh>
+#include <ast/string-exp.hh>
+#include <ast/subscript-var.hh>
+#include <ast/ty.hh>
+#include <ast/typable.hh>
+#include <ast/type-constructor.hh>
+#include <ast/type-dec.hh>
+#include <ast/var-dec.hh>
+#include <ast/var.hh>
+#include <ast/while-exp.hh>
diff --git a/tiger-compiler/src/ast/array-exp.cc b/tiger-compiler/src/ast/array-exp.cc
new file mode 100644
index 0000000..8c0f241
--- /dev/null
+++ b/tiger-compiler/src/ast/array-exp.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file ast/array-exp.cc
+ ** \brief Implementation of ast::ArrayExp.
+ */
+
+#include <ast/array-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ ArrayExp::ArrayExp(const Location& location,
+ NameTy* type_name,
+ Exp* size,
+ Exp* init)
+ : Exp(location)
+ , type_name_(type_name)
+ , size_(size)
+ , init_(init)
+ {}
+
+ ArrayExp::~ArrayExp()
+ {
+ delete type_name_;
+ delete size_;
+ delete init_;
+ }
+
+ void ArrayExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void ArrayExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/array-exp.hh b/tiger-compiler/src/ast/array-exp.hh
new file mode 100644
index 0000000..ceab385
--- /dev/null
+++ b/tiger-compiler/src/ast/array-exp.hh
@@ -0,0 +1,60 @@
+/**
+ ** \file ast/array-exp.hh
+ ** \brief Declaration of ast::ArrayExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/name-ty.hh>
+
+namespace ast
+{
+ /// ArrayExp.
+ class ArrayExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an ArrayExp node.
+ ArrayExp(const Location& location, NameTy* type_name, Exp* size, Exp* init);
+ ArrayExp(const ArrayExp&) = delete;
+ ArrayExp& operator=(const ArrayExp&) = delete;
+ /// Destroy an ArrayExp node.
+ ~ArrayExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return identifier of the stored elements type.
+ const NameTy& type_name_get() const;
+ /// Return identifier of the stored elements type.
+ NameTy& type_name_get();
+ /// Return size of the array.
+ const Exp& size_get() const;
+ /// Return size of the array.
+ Exp& size_get();
+ /// Return initial value assigned to all elements of the array.
+ const Exp& init_get() const;
+ /// Return initial value assigned to all elements of the array.
+ Exp& init_get();
+ /** \} */
+
+ protected:
+ /// Identifier of the stored elements type.
+ NameTy* type_name_;
+ /// Size of the array.
+ Exp* size_;
+ /// Initial value assigned to all elements of the array.
+ Exp* init_;
+ };
+} // namespace ast
+#include <ast/array-exp.hxx>
diff --git a/tiger-compiler/src/ast/array-exp.hxx b/tiger-compiler/src/ast/array-exp.hxx
new file mode 100644
index 0000000..cab3e8b
--- /dev/null
+++ b/tiger-compiler/src/ast/array-exp.hxx
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/array-exp.hxx
+ ** \brief Inline methods of ast::ArrayExp.
+ */
+
+#pragma once
+
+#include <ast/array-exp.hh>
+
+namespace ast
+{
+
+ inline const NameTy& ArrayExp::type_name_get() const { return *type_name_; }
+ inline NameTy& ArrayExp::type_name_get() { return *type_name_; }
+
+ inline const Exp& ArrayExp::size_get() const { return *size_; }
+ inline Exp& ArrayExp::size_get() { return *size_; }
+
+ inline const Exp& ArrayExp::init_get() const { return *init_; }
+ inline Exp& ArrayExp::init_get() { return *init_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/array-ty.cc b/tiger-compiler/src/ast/array-ty.cc
new file mode 100644
index 0000000..d7af8b4
--- /dev/null
+++ b/tiger-compiler/src/ast/array-ty.cc
@@ -0,0 +1,21 @@
+/**
+ ** \file ast/array-ty.cc
+ ** \brief Implementation of ast::ArrayTy.
+ */
+
+#include <ast/array-ty.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ ArrayTy::ArrayTy(const Location& location, NameTy* base_type)
+ : Ty(location)
+ , base_type_(base_type)
+ {}
+
+ ArrayTy::~ArrayTy() { delete base_type_; }
+
+ void ArrayTy::accept(ConstVisitor& v) const { v(*this); }
+
+ void ArrayTy::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/array-ty.hh b/tiger-compiler/src/ast/array-ty.hh
new file mode 100644
index 0000000..73bb956
--- /dev/null
+++ b/tiger-compiler/src/ast/array-ty.hh
@@ -0,0 +1,48 @@
+/**
+ ** \file ast/array-ty.hh
+ ** \brief Declaration of ast::ArrayTy.
+ */
+
+#pragma once
+
+#include <ast/name-ty.hh>
+#include <ast/ty.hh>
+
+namespace ast
+{
+ /// ArrayTy.
+ class ArrayTy : public Ty
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an ArrayTy node.
+ ArrayTy(const Location& location, NameTy* base_type);
+ ArrayTy(const ArrayTy&) = delete;
+ ArrayTy& operator=(const ArrayTy&) = delete;
+ /// Destroy an ArrayTy node.
+ ~ArrayTy() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return name of the base type.
+ const NameTy& base_type_get() const;
+ /// Return name of the base type.
+ NameTy& base_type_get();
+ /** \} */
+
+ protected:
+ /// Name of the base type.
+ NameTy* base_type_;
+ };
+} // namespace ast
+#include <ast/array-ty.hxx>
diff --git a/tiger-compiler/src/ast/array-ty.hxx b/tiger-compiler/src/ast/array-ty.hxx
new file mode 100644
index 0000000..c679b1c
--- /dev/null
+++ b/tiger-compiler/src/ast/array-ty.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/array-ty.hxx
+ ** \brief Inline methods of ast::ArrayTy.
+ */
+
+#pragma once
+
+#include <ast/array-ty.hh>
+
+namespace ast
+{
+
+ inline const NameTy& ArrayTy::base_type_get() const { return *base_type_; }
+ inline NameTy& ArrayTy::base_type_get() { return *base_type_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/assert-exp.cc b/tiger-compiler/src/ast/assert-exp.cc
new file mode 100644
index 0000000..251f776
--- /dev/null
+++ b/tiger-compiler/src/ast/assert-exp.cc
@@ -0,0 +1,24 @@
+/**
+ ** \file ast/assert-exp.cc
+ ** \brief Implementation of ast::AssertExp.
+ */
+
+#include <ast/assert-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ AssertExp::AssertExp(const Location& location, Exp* condition)
+ : Exp(location)
+ , cond_{condition}
+ {}
+
+ AssertExp::~AssertExp()
+ {
+ delete cond_;
+ }
+
+ void AssertExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void AssertExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/assert-exp.hh b/tiger-compiler/src/ast/assert-exp.hh
new file mode 100644
index 0000000..6650ca4
--- /dev/null
+++ b/tiger-compiler/src/ast/assert-exp.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file ast/assert-exp.hh
+ ** \brief Declaration of ast::AssertExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ // AssertExp
+ class AssertExp : public Exp
+ {
+ public:
+ /// Construct an AssertExp node.
+ AssertExp(const Location& location, Exp* cond);
+ AssertExp(const AssertExp&) = delete;
+ AssertExp& operator=(const AssertExp&) = delete;
+
+ /// Destroy an AssertExp node.
+ ~AssertExp() override;
+
+
+ // Here are the visitor methods
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+
+ // Some basic getters
+ // Return the asserted condition in const form
+ const Exp& cond_get() const;
+ // Return the asserted condition
+ Exp& cond_get();
+
+ protected:
+ // The condition that the assertion will evaluate
+ Exp* cond_;
+ };
+} // namespace ast
+#include <ast/assert-exp.hxx>
diff --git a/tiger-compiler/src/ast/assert-exp.hxx b/tiger-compiler/src/ast/assert-exp.hxx
new file mode 100644
index 0000000..d5f8af8
--- /dev/null
+++ b/tiger-compiler/src/ast/assert-exp.hxx
@@ -0,0 +1,14 @@
+/**
+ ** \file ast/assert-exp.hxx
+ ** \brief Inline methods of ast::AssertExp.
+ */
+
+#pragma once
+
+#include <ast/assert-exp.hh>
+
+namespace ast
+{
+ inline const Exp& AssertExp::cond_get() const { return *cond_; }
+ inline Exp& AssertExp::cond_get() { return *cond_; }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/assert-visitor.hh b/tiger-compiler/src/ast/assert-visitor.hh
new file mode 100644
index 0000000..0488c1c
--- /dev/null
+++ b/tiger-compiler/src/ast/assert-visitor.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file ast/object-visitor.hh
+ ** \brief Provide default visits for assertion nodes.
+ */
+
+#pragma once
+
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ class GenAssertVisitor : virtual public GenVisitor<Const>
+ {
+ public:
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an object visitor.
+ GenAssertVisitor();
+ /// Destroy an object visitor.
+ virtual ~GenAssertVisitor();
+ /** \} */
+
+ /// \name Object-related visits.
+ /// \{
+ void operator()(const_t<AssertExp>& e) override;
+ /// \}
+ };
+
+ /// Shorthand for a const visitor.
+ using AssertConstVisitor = GenAssertVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using AssertVisitor = GenAssertVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ %template(AssertConstVisitor) GenAssertVisitor<misc::constify_traits>;
+ %template(AssertVisitor) GenAssertVisitor<misc::id_traits>;
+#endif
+
+} // namespace ast
+
+#include <ast/assert-visitor.hxx>
diff --git a/tiger-compiler/src/ast/assert-visitor.hxx b/tiger-compiler/src/ast/assert-visitor.hxx
new file mode 100644
index 0000000..c55bb43
--- /dev/null
+++ b/tiger-compiler/src/ast/assert-visitor.hxx
@@ -0,0 +1,32 @@
+/**
+ ** \file ast/assert-visitor.hxx
+ ** \brief Implementation for ast/assert-visitor.hh.
+ */
+
+#pragma once
+
+#include <ast/assert-exp.hh>
+#include <ast/assert-visitor.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ GenAssertVisitor<Const>::GenAssertVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenAssertVisitor<Const>::~GenAssertVisitor()
+ {}
+
+ /*-------------------------------.
+ | Assert-related visit method. |
+ `-------------------------------*/
+
+ template <template <typename> class Const>
+ void GenAssertVisitor<Const>::operator()(const_t<AssertExp>& e)
+ {
+ e.cond_get().accept(*this);
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/assign-exp.cc b/tiger-compiler/src/ast/assign-exp.cc
new file mode 100644
index 0000000..d61b5c2
--- /dev/null
+++ b/tiger-compiler/src/ast/assign-exp.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/assign-exp.cc
+ ** \brief Implementation of ast::AssignExp.
+ */
+
+#include <ast/assign-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ AssignExp::AssignExp(const Location& location, Var* var, Exp* exp)
+ : Exp(location)
+ , var_(var)
+ , exp_(exp)
+ {}
+
+ AssignExp::~AssignExp()
+ {
+ delete var_;
+ delete exp_;
+ }
+
+ void AssignExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void AssignExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/assign-exp.hh b/tiger-compiler/src/ast/assign-exp.hh
new file mode 100644
index 0000000..ca575ec
--- /dev/null
+++ b/tiger-compiler/src/ast/assign-exp.hh
@@ -0,0 +1,54 @@
+/**
+ ** \file ast/assign-exp.hh
+ ** \brief Declaration of ast::AssignExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/var.hh>
+
+namespace ast
+{
+ /// AssignExp.
+ class AssignExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an AssignExp node.
+ AssignExp(const Location& location, Var* var, Exp* exp);
+ AssignExp(const AssignExp&) = delete;
+ AssignExp& operator=(const AssignExp&) = delete;
+ /// Destroy an AssignExp node.
+ ~AssignExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return reference to the affected variable.
+ const Var& var_get() const;
+ /// Return reference to the affected variable.
+ Var& var_get();
+ /// Return assigned value.
+ const Exp& exp_get() const;
+ /// Return assigned value.
+ Exp& exp_get();
+ /** \} */
+
+ protected:
+ /// Reference to the affected variable.
+ Var* var_;
+ /// Assigned value.
+ Exp* exp_;
+ };
+} // namespace ast
+#include <ast/assign-exp.hxx>
diff --git a/tiger-compiler/src/ast/assign-exp.hxx b/tiger-compiler/src/ast/assign-exp.hxx
new file mode 100644
index 0000000..afd96ff
--- /dev/null
+++ b/tiger-compiler/src/ast/assign-exp.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/assign-exp.hxx
+ ** \brief Inline methods of ast::AssignExp.
+ */
+
+#pragma once
+
+#include <ast/assign-exp.hh>
+
+namespace ast
+{
+
+ inline const Var& AssignExp::var_get() const { return *var_; }
+ inline Var& AssignExp::var_get() { return *var_; }
+
+ inline const Exp& AssignExp::exp_get() const { return *exp_; }
+ inline Exp& AssignExp::exp_get() { return *exp_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/ast-nodes.mk b/tiger-compiler/src/ast/ast-nodes.mk
new file mode 100644
index 0000000..ab35724
--- /dev/null
+++ b/tiger-compiler/src/ast/ast-nodes.mk
@@ -0,0 +1,41 @@
+AST_NODES = \
+ src/ast/array-exp.hh src/ast/array-exp.hxx src/ast/array-exp.cc \
+ src/ast/array-ty.hh src/ast/array-ty.hxx src/ast/array-ty.cc \
+ src/ast/assert-exp.hh src/ast/assert-exp.hxx src/ast/assert-exp.cc \
+ src/ast/assign-exp.hh src/ast/assign-exp.hxx src/ast/assign-exp.cc \
+ src/ast/ast.hh src/ast/ast.hxx src/ast/ast.cc \
+ src/ast/break-exp.hh src/ast/break-exp.hxx src/ast/break-exp.cc \
+ src/ast/call-exp.hh src/ast/call-exp.hxx src/ast/call-exp.cc \
+ src/ast/cast-exp.hh src/ast/cast-exp.hxx src/ast/cast-exp.cc \
+ src/ast/chunk-list.hh src/ast/chunk-list.hxx src/ast/chunk-list.cc \
+ src/ast/class-ty.hh src/ast/class-ty.hxx src/ast/class-ty.cc \
+ src/ast/dec.hh src/ast/dec.hxx src/ast/dec.cc \
+ src/ast/escapable.hh src/ast/escapable.hxx src/ast/escapable.cc \
+ src/ast/exp.hh src/ast/exp.hxx src/ast/exp.cc \
+ src/ast/field.hh src/ast/field.hxx src/ast/field.cc \
+ src/ast/field-init.hh src/ast/field-init.hxx src/ast/field-init.cc \
+ src/ast/field-var.hh src/ast/field-var.hxx src/ast/field-var.cc \
+ src/ast/for-exp.hh src/ast/for-exp.hxx src/ast/for-exp.cc \
+ src/ast/function-dec.hh src/ast/function-dec.hxx src/ast/function-dec.cc \
+ src/ast/if-exp.hh src/ast/if-exp.hxx src/ast/if-exp.cc \
+ src/ast/int-exp.hh src/ast/int-exp.hxx src/ast/int-exp.cc \
+ src/ast/let-exp.hh src/ast/let-exp.hxx src/ast/let-exp.cc \
+ src/ast/method-call-exp.hh src/ast/method-call-exp.hxx src/ast/method-call-exp.cc \
+ src/ast/method-dec.hh src/ast/method-dec.hxx src/ast/method-dec.cc \
+ src/ast/name-ty.hh src/ast/name-ty.hxx src/ast/name-ty.cc \
+ src/ast/nil-exp.hh src/ast/nil-exp.hxx src/ast/nil-exp.cc \
+ src/ast/object-exp.hh src/ast/object-exp.hxx src/ast/object-exp.cc \
+ src/ast/op-exp.hh src/ast/op-exp.hxx src/ast/op-exp.cc \
+ src/ast/record-exp.hh src/ast/record-exp.hxx src/ast/record-exp.cc \
+ src/ast/record-ty.hh src/ast/record-ty.hxx src/ast/record-ty.cc \
+ src/ast/seq-exp.hh src/ast/seq-exp.hxx src/ast/seq-exp.cc \
+ src/ast/simple-var.hh src/ast/simple-var.hxx src/ast/simple-var.cc \
+ src/ast/string-exp.hh src/ast/string-exp.hxx src/ast/string-exp.cc \
+ src/ast/subscript-var.hh src/ast/subscript-var.hxx src/ast/subscript-var.cc \
+ src/ast/ty.hh src/ast/ty.hxx src/ast/ty.cc \
+ src/ast/typable.hh src/ast/typable.hxx src/ast/typable.cc \
+ src/ast/type-constructor.hh src/ast/type-constructor.hxx src/ast/type-constructor.cc \
+ src/ast/type-dec.hh src/ast/type-dec.hxx src/ast/type-dec.cc \
+ src/ast/var.hh src/ast/var.hxx src/ast/var.cc \
+ src/ast/var-dec.hh src/ast/var-dec.hxx src/ast/var-dec.cc \
+ src/ast/while-exp.hh src/ast/while-exp.hxx src/ast/while-exp.cc
diff --git a/tiger-compiler/src/ast/ast.cc b/tiger-compiler/src/ast/ast.cc
new file mode 100644
index 0000000..136262f
--- /dev/null
+++ b/tiger-compiler/src/ast/ast.cc
@@ -0,0 +1,15 @@
+/**
+ ** \file ast/ast.cc
+ ** \brief Implementation of ast::Ast.
+ */
+
+#include <ast/ast.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Ast::Ast(const Location& location)
+ : location_(location)
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/ast.hh b/tiger-compiler/src/ast/ast.hh
new file mode 100644
index 0000000..1c3037c
--- /dev/null
+++ b/tiger-compiler/src/ast/ast.hh
@@ -0,0 +1,48 @@
+/**
+ ** \file ast/ast.hh
+ ** \brief Declaration of ast::Ast.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <ast/location.hh>
+
+namespace ast
+{
+ /// Ast.
+ class Ast
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an Ast node.
+ explicit Ast(const Location& location);
+ Ast(const Ast&) = delete;
+ Ast& operator=(const Ast&) = delete;
+ /// Destroy an Ast node.
+ virtual ~Ast() = default;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ virtual void accept(ConstVisitor& v) const = 0;
+ /// Accept a non-const visitor \a v.
+ virtual void accept(Visitor& v) = 0;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return scanner position information.
+ const Location& location_get() const;
+ /// Set scanner position information.
+ void location_set(const Location&);
+ /** \} */
+
+ protected:
+ /// Scanner position information.
+ Location location_;
+ };
+} // namespace ast
+#include <ast/ast.hxx>
diff --git a/tiger-compiler/src/ast/ast.hxx b/tiger-compiler/src/ast/ast.hxx
new file mode 100644
index 0000000..963aaba
--- /dev/null
+++ b/tiger-compiler/src/ast/ast.hxx
@@ -0,0 +1,18 @@
+/**
+ ** \file ast/ast.hxx
+ ** \brief Inline methods of ast::Ast.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+
+namespace ast
+{
+ inline const Location& Ast::location_get() const { return location_; }
+ inline void Ast::location_set(const Location& location)
+ {
+ location_ = location;
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/break-exp.cc b/tiger-compiler/src/ast/break-exp.cc
new file mode 100644
index 0000000..3c76946
--- /dev/null
+++ b/tiger-compiler/src/ast/break-exp.cc
@@ -0,0 +1,18 @@
+/**
+ ** \file ast/break-exp.cc
+ ** \brief Implementation of ast::BreakExp.
+ */
+
+#include <ast/break-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ BreakExp::BreakExp(const Location& location)
+ : Exp(location)
+ {}
+
+ void BreakExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void BreakExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/break-exp.hh b/tiger-compiler/src/ast/break-exp.hh
new file mode 100644
index 0000000..25d89e8
--- /dev/null
+++ b/tiger-compiler/src/ast/break-exp.hh
@@ -0,0 +1,49 @@
+/**
+ ** \file ast/break-exp.hh
+ ** \brief Declaration of ast::BreakExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// BreakExp.
+ class BreakExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a BreakExp node.
+ explicit BreakExp(const Location& location);
+ BreakExp(const BreakExp&) = delete;
+ BreakExp& operator=(const BreakExp&) = delete;
+ /// Destroy a BreakExp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ // FIXME DONE: Some code was deleted here.
+ /// Return definition site.
+ const Exp* def_get() const;
+ Exp* def_get();
+ // FIXME DONE: Some code was deleted here.
+ /// Set definition site.
+ void def_set(Exp*);
+ /** \} */
+
+ protected:
+ /// The loop it breaks.
+ Exp* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/break-exp.hxx>
diff --git a/tiger-compiler/src/ast/break-exp.hxx b/tiger-compiler/src/ast/break-exp.hxx
new file mode 100644
index 0000000..604f754
--- /dev/null
+++ b/tiger-compiler/src/ast/break-exp.hxx
@@ -0,0 +1,21 @@
+/**
+ ** \file ast/break-exp.hxx
+ ** \brief Inline methods of ast::BreakExp.
+ */
+
+#pragma once
+
+#include <ast/break-exp.hh>
+
+// Hint: this needs to be done at TC-3.
+
+namespace ast
+{
+
+ // FIXME DONE: Some code was deleted here.
+ inline const Exp* BreakExp::def_get() const { return def_; }
+ inline Exp* BreakExp::def_get() { return def_; }
+ // FIXME DONE: Some code was deleted here.
+ inline void BreakExp::def_set(Exp* def) { def_ = def; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/call-exp.cc b/tiger-compiler/src/ast/call-exp.cc
new file mode 100644
index 0000000..546ab5f
--- /dev/null
+++ b/tiger-compiler/src/ast/call-exp.cc
@@ -0,0 +1,27 @@
+/**
+ ** \file ast/call-exp.cc
+ ** \brief Implementation of ast::CallExp.
+ */
+
+#include <ast/call-exp.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ CallExp::CallExp(const Location& location, misc::symbol name, exps_type* args)
+ : Exp(location)
+ , name_(name)
+ , args_(args)
+ {}
+
+ CallExp::~CallExp()
+ {
+ misc::deep_clear(*args_);
+ delete args_;
+ }
+
+ void CallExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void CallExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/call-exp.hh b/tiger-compiler/src/ast/call-exp.hh
new file mode 100644
index 0000000..a4b6c90
--- /dev/null
+++ b/tiger-compiler/src/ast/call-exp.hh
@@ -0,0 +1,64 @@
+/**
+ ** \file ast/call-exp.hh
+ ** \brief Declaration of ast::CallExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/function-dec.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// CallExp.
+ class CallExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a CallExp node.
+ CallExp(const Location& location, misc::symbol name, exps_type* args);
+ CallExp(const CallExp&) = delete;
+ CallExp& operator=(const CallExp&) = delete;
+ /// Destroy a CallExp node.
+ ~CallExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return identifier of the called function.
+ misc::symbol name_get() const;
+ /// Set identifier of the called function.
+ void name_set(misc::symbol);
+ /// Return list of arguments passed to the function.
+ const exps_type& args_get() const;
+ /// Return list of arguments passed to the function.
+ exps_type& args_get();
+ // FIXME DONE: Some code was deleted here.
+ /// Return definition site.
+ const FunctionDec* def_get() const;
+ FunctionDec* def_get();
+ // FIXME DONE: Some code was deleted here.
+ /// Set definition site.
+ void def_set(FunctionDec*);
+ /** \} */
+
+ protected:
+ /// Identifier of the called function.
+ misc::symbol name_;
+ /// List of arguments passed to the function.
+ exps_type* args_;
+ /// Definition site.
+ FunctionDec* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/call-exp.hxx>
diff --git a/tiger-compiler/src/ast/call-exp.hxx b/tiger-compiler/src/ast/call-exp.hxx
new file mode 100644
index 0000000..63b9c51
--- /dev/null
+++ b/tiger-compiler/src/ast/call-exp.hxx
@@ -0,0 +1,25 @@
+/**
+ ** \file ast/call-exp.hxx
+ ** \brief Inline methods of ast::CallExp.
+ */
+
+#pragma once
+
+#include <ast/call-exp.hh>
+
+namespace ast
+{
+
+ inline misc::symbol CallExp::name_get() const { return name_; }
+ inline void CallExp::name_set(misc::symbol name) { name_ = name; }
+
+ inline const exps_type& CallExp::args_get() const { return *args_; }
+ inline exps_type& CallExp::args_get() { return *args_; }
+
+ // FIXME DONE: Some code was deleted here.
+ inline const FunctionDec* CallExp::def_get() const { return def_; }
+ inline FunctionDec* CallExp::def_get() { return def_; }
+ // FIXME DONE: Some code was deleted here.
+ inline void CallExp::def_set(FunctionDec* def) { def_ = def; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/cast-exp.cc b/tiger-compiler/src/ast/cast-exp.cc
new file mode 100644
index 0000000..e40f8f0
--- /dev/null
+++ b/tiger-compiler/src/ast/cast-exp.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/cast-exp.cc
+ ** \brief Implementation of ast::CastExp.
+ */
+
+#include <ast/cast-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ CastExp::CastExp(const Location& location, Exp* exp, Ty* ty)
+ : Exp(location)
+ , exp_(exp)
+ , ty_(ty)
+ {}
+
+ CastExp::~CastExp()
+ {
+ delete exp_;
+ delete ty_;
+ }
+
+ void CastExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void CastExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/cast-exp.hh b/tiger-compiler/src/ast/cast-exp.hh
new file mode 100644
index 0000000..a73e7bb
--- /dev/null
+++ b/tiger-compiler/src/ast/cast-exp.hh
@@ -0,0 +1,62 @@
+/**
+ ** \file ast/cast-exp.hh
+ ** \brief Declaration of ast::CastExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/ty.hh>
+
+namespace ast
+{
+ /** \class ast::CastExp
+ ** \brief Cast the type of an expression to a given type.
+ **
+ ** This node is only used in the bounds checking transformation
+ ** (see desugar::bounds_checks_add). You don't need to worry
+ ** about it (nor about the `cast' keyword) if you don't implement
+ ** this option.
+ */
+
+ class CastExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a CastExp node.
+ CastExp(const Location& location, Exp* exp, Ty* ty);
+ CastExp(const CastExp&) = delete;
+ CastExp& operator=(const CastExp&) = delete;
+ /// Destroy a CastExp node.
+ ~CastExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the cast expression.
+ const Exp& exp_get() const;
+ /// Return the cast expression.
+ Exp& exp_get();
+ /// Return the target type.
+ const Ty& ty_get() const;
+ /// Return the target type.
+ Ty& ty_get();
+ /** \} */
+
+ protected:
+ /// The cast expression.
+ Exp* exp_;
+ /// The target type.
+ Ty* ty_;
+ };
+} // namespace ast
+#include <ast/cast-exp.hxx>
diff --git a/tiger-compiler/src/ast/cast-exp.hxx b/tiger-compiler/src/ast/cast-exp.hxx
new file mode 100644
index 0000000..4f248ad
--- /dev/null
+++ b/tiger-compiler/src/ast/cast-exp.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/cast-exp.hxx
+ ** \brief Inline methods of ast::CastExp.
+ */
+
+#pragma once
+
+#include <ast/cast-exp.hh>
+
+namespace ast
+{
+
+ inline const Exp& CastExp::exp_get() const { return *exp_; }
+ inline Exp& CastExp::exp_get() { return *exp_; }
+
+ inline const Ty& CastExp::ty_get() const { return *ty_; }
+ inline Ty& CastExp::ty_get() { return *ty_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/chunk-interface.hh b/tiger-compiler/src/ast/chunk-interface.hh
new file mode 100644
index 0000000..dcaad18
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk-interface.hh
@@ -0,0 +1,25 @@
+/**
+ ** \file ast/chunk-interface.hh
+ ** \brief Declare the interface for ChunkInterface class.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+
+namespace ast
+{
+ /// Declare ChunkInterface
+ class ChunkInterface : public Ast
+ {
+ /** \name Ctors and dtors.
+ ** \{ */
+ public:
+ /// Construct a ChunkInterface
+ explicit ChunkInterface(const Location& location);
+ /** \} */
+ };
+
+} // namespace ast
+
+#include <ast/chunk-interface.hxx>
diff --git a/tiger-compiler/src/ast/chunk-interface.hxx b/tiger-compiler/src/ast/chunk-interface.hxx
new file mode 100644
index 0000000..7824297
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk-interface.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/chunk-interface.hxx
+ ** \brief Inline methods for ast/chunk-interface.hh
+ */
+
+#pragma once
+
+#include <ast/chunk-interface.hh>
+
+namespace ast
+{
+ inline ChunkInterface::ChunkInterface(const Location& location)
+ : Ast(location)
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/chunk-list.cc b/tiger-compiler/src/ast/chunk-list.cc
new file mode 100644
index 0000000..6a530c4
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk-list.cc
@@ -0,0 +1,58 @@
+/**
+ ** \file ast/chunk-list.cc
+ ** \brief Implementation of ast::ChunkList.
+ */
+
+#include <ast/chunk-interface.hh>
+#include <ast/chunk-list.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ ChunkList::iterator ChunkList::begin() { return chunks_.begin(); }
+
+ ChunkList::iterator ChunkList::end() { return chunks_.end(); }
+
+ ChunkList::const_iterator ChunkList::begin() const { return chunks_.begin(); }
+
+ ChunkList::const_iterator ChunkList::end() const { return chunks_.end(); }
+
+ void ChunkList::push_front(ChunkInterface* d)
+ {
+ chunks_.emplace_front(d);
+ location_.begin = d->location_get().begin;
+ }
+
+ void ChunkList::emplace_back(ChunkInterface* d)
+ {
+ chunks_.emplace_back(d);
+ location_.end = d->location_get().end;
+ }
+
+ void ChunkList::splice_front(ChunkList& ds)
+ {
+ chunks_.splice(chunks_.begin(), ds.chunks_get());
+ }
+
+ void ChunkList::splice_back(ChunkList& ds)
+ {
+ chunks_.splice(chunks_.end(), ds.chunks_get());
+ }
+
+ ChunkList::ChunkList(const Location& location)
+ : Ast(location)
+ {}
+
+ ChunkList::ChunkList(const Location& location,
+ const ChunkList::list_type& chunks)
+ : Ast(location)
+ , chunks_(chunks)
+ {}
+
+ ChunkList::~ChunkList() { misc::deep_clear(chunks_); }
+
+ void ChunkList::accept(ConstVisitor& v) const { v(*this); }
+
+ void ChunkList::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/chunk-list.hh b/tiger-compiler/src/ast/chunk-list.hh
new file mode 100644
index 0000000..3674e27
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk-list.hh
@@ -0,0 +1,80 @@
+/**
+ ** \file ast/chunk-list.hh
+ ** \brief Declaration of ast::ChunkList.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+
+namespace ast
+{
+ /// ChunkList.
+ class ChunkList : public Ast
+ {
+ public:
+ using list_type = std::list<ChunkInterface*>;
+ /// Define value type
+ using value_type = list_type::value_type;
+ /// Define size type
+ using size_type = list_type::size_type;
+ /// Define reference to value type
+ using reference = list_type::reference;
+ /// Define const reference to value type
+ using const_reference = list_type::const_reference;
+ /// Define shorthand type for D-declations iterator.
+ using iterator = list_type::iterator;
+ /// Define shorthand type for D-declations const iterator.
+ using const_iterator = list_type::const_iterator;
+
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ /// Prepend \a d.
+ void push_front(ChunkInterface* d);
+ /// Append \a d.
+ void emplace_back(ChunkInterface* d);
+
+ /// Splice the content of \a ds in front of this list.
+ void splice_front(ChunkList& ds);
+ /// Splice the content of \a ds at the back this list.
+ void splice_back(ChunkList& ds);
+
+ /// Construct a ChunkList node.
+ ChunkList(const Location& location);
+
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a ChunkList node.
+ ChunkList(const Location& location, const ChunkList::list_type& chunks);
+ ChunkList(const ChunkList&) = delete;
+ ChunkList& operator=(const ChunkList&) = delete;
+ /// Destroy a ChunkList node.
+ ~ChunkList() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return declarations.
+ const ChunkList::list_type& chunks_get() const;
+ /// Return declarations.
+ ChunkList::list_type& chunks_get();
+ /** \} */
+
+ protected:
+ /// Declarations.
+ ChunkList::list_type chunks_;
+ };
+} // namespace ast
+#include <ast/chunk-list.hxx>
diff --git a/tiger-compiler/src/ast/chunk-list.hxx b/tiger-compiler/src/ast/chunk-list.hxx
new file mode 100644
index 0000000..6307760
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk-list.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/chunk-list.hxx
+ ** \brief Inline methods of ast::ChunkList.
+ */
+
+#pragma once
+
+#include <ast/chunk-list.hh>
+
+namespace ast
+{
+
+ inline const ChunkList::list_type& ChunkList::chunks_get() const
+ {
+ return chunks_;
+ }
+ inline ChunkList::list_type& ChunkList::chunks_get() { return chunks_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/chunk.hh b/tiger-compiler/src/ast/chunk.hh
new file mode 100644
index 0000000..8f59fb0
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk.hh
@@ -0,0 +1,139 @@
+/**
+ ** \file ast/chunk.hh
+ ** \brief Declaration of ast::Chunk.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <ast/chunk-interface.hh>
+
+namespace ast
+{
+ template <typename D>
+ /// Abstract a "list of D-declarations" node.
+ class Chunk : public ChunkInterface
+ {
+ /** \name Member types
+ ** \{ */
+ public:
+ /// Define shorthand type for list of D-declarations.
+ using Ds = std::vector<D*>;
+ /// Define value type
+ using value_type = typename Ds::value_type;
+ /// Define size type
+ using size_type = typename Ds::size_type;
+ /// Define reference to value type
+ using reference = typename Ds::reference;
+ /// Define const reference to value type
+ using const_reference = typename Ds::const_reference;
+ /// Define shorthand type for D-declations iterator.
+ using iterator = typename Ds::iterator;
+ /// Define shorthand type for D-declations const iterator.
+ using const_iterator = typename Ds::const_iterator;
+
+ /** \} */
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /** \brief Construct an Chunk node with a list of D-declarations.
+ ** \param location scanner position informations
+ ** \param decs list of D-declarations */
+ Chunk(const Location& location, Ds* decs);
+ explicit Chunk(const Location& location);
+
+ /** \brief Destroys an Chunk node.
+ **
+ ** Free list and its content. */
+ ~Chunk() override;
+
+ /** \} */
+
+ /** \name Visitors entry point.
+ ** \{ */
+ public:
+ /// Accept a const visitor \a v.
+ void accept(Visitor& v) override;
+
+ /// Accept a non-const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ public: /** \brief Access specified element
+ ** /param pos position of the element to return */
+ constexpr reference operator[](size_type pos);
+
+ /** \brief Access specified const element
+ ** /param pos position of the element to return */
+ constexpr const_reference operator[](size_type pos) const;
+
+ /// Access to list of D-declarations (read and write).
+ Ds& decs_get();
+
+ /// Access to list of D-declarations (read only).
+ const Ds& decs_get() const;
+
+ /** \} */
+
+ /** \name Iterators.
+ ** \{ */
+ public:
+ /// Return an iterator to the begging.
+ iterator begin();
+ /// Return a const iterator to the begging.
+ const_iterator begin() const;
+
+ /// Return an iterator to the end.
+ iterator end();
+ /// Return a const iterator to the end.
+ const_iterator end() const;
+
+ /** \} */
+
+ /** \name Capacity.
+ ** \} */
+ public:
+ /// Checks whether the container is empty.
+#ifdef SWIG
+ constexpr bool empty() const noexcept;
+#else /* SWIG */
+ [[nodiscard]] constexpr bool empty() const noexcept;
+#endif /* SWIG */
+ /** \name Modifiers.
+ ** \{ */
+ public:
+ /** \brief Erase the specified element from the container.
+ ** \param pos position of the element to remove. */
+ constexpr iterator erase(const_iterator pos);
+
+ /** \brief Erase the specified elements in range from the container.
+ ** \param first begin of the range
+ ** \param last end of the range */
+ constexpr iterator erase(const_iterator first, const_iterator last);
+
+ /** \brief Push \a d in front.
+ ** \param d declaration to push */
+ Chunk<D>& push_front(D& d);
+
+ /** \brief Push \a d in back.
+ ** \param d declaration to push */
+ Chunk<D>& emplace_back(D& d);
+
+ /** \} */
+
+ // SWIG 2 does not understand C++11 constructs, such as data
+ // member initializers.
+#ifndef SWIG
+ private:
+ Ds* decs_ = new Ds();
+#endif
+ };
+
+} // namespace ast
+
+#include <ast/chunk.hxx>
diff --git a/tiger-compiler/src/ast/chunk.hxx b/tiger-compiler/src/ast/chunk.hxx
new file mode 100644
index 0000000..a3c3ada
--- /dev/null
+++ b/tiger-compiler/src/ast/chunk.hxx
@@ -0,0 +1,118 @@
+/**
+ ** \file ast/chunk.hxx
+ ** \brief Implementation of ast::Chunk.
+ */
+
+#pragma once
+
+#include <ast/chunk.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ template <typename D>
+ Chunk<D>::Chunk(const Location& location, Ds* decs)
+ : ChunkInterface(location)
+ , decs_(decs)
+ {}
+
+ template <typename D>
+ Chunk<D>::Chunk(const Location& location)
+ : ChunkInterface(location)
+ {}
+
+ template <typename D> Chunk<D>::~Chunk()
+ {
+ misc::deep_clear(*decs_);
+ delete decs_;
+ }
+
+ template <typename D> inline void Chunk<D>::accept(Visitor& v) { v(*this); }
+
+ template <typename D> inline void Chunk<D>::accept(ConstVisitor& v) const
+ {
+ v(*this);
+ }
+
+ template <typename D>
+ inline constexpr typename Chunk<D>::reference
+ Chunk<D>::operator[](size_type pos)
+ {
+ return decs_->operator[](pos);
+ }
+
+ template <typename D>
+ inline constexpr typename Chunk<D>::const_reference
+ Chunk<D>::operator[](size_type pos) const
+ {
+ return decs_->operator[](pos);
+ }
+
+ template <typename D> inline typename Chunk<D>::Ds& Chunk<D>::decs_get()
+ {
+ return *decs_;
+ }
+
+ template <typename D>
+ inline const typename Chunk<D>::Ds& Chunk<D>::decs_get() const
+ {
+ return *decs_;
+ }
+
+ template <typename D> inline typename Chunk<D>::iterator Chunk<D>::begin()
+ {
+ return decs_->begin();
+ }
+
+ template <typename D>
+ inline typename Chunk<D>::const_iterator Chunk<D>::begin() const
+ {
+ return decs_->begin();
+ }
+
+ template <typename D> inline typename Chunk<D>::iterator Chunk<D>::end()
+ {
+ return decs_->end();
+ }
+
+ template <typename D>
+ inline typename Chunk<D>::const_iterator Chunk<D>::end() const
+ {
+ return decs_->end();
+ }
+
+ template <typename D> inline constexpr bool Chunk<D>::empty() const noexcept
+ {
+ return decs_->empty();
+ }
+
+ template <typename D>
+ inline constexpr typename Chunk<D>::iterator
+ Chunk<D>::erase(const_iterator pos)
+ {
+ return decs_->erase(pos);
+ }
+
+ template <typename D>
+ inline constexpr typename Chunk<D>::iterator
+ Chunk<D>::erase(const_iterator first, const_iterator last)
+ {
+ return decs_->erase(first, last);
+ }
+
+ template <typename D> Chunk<D>& Chunk<D>::push_front(D& d)
+ {
+ location_set(location_get() + d.location_get());
+ decs_->insert(decs_->begin(), &d);
+ return *this;
+ }
+
+ template <typename D> Chunk<D>& Chunk<D>::emplace_back(D& d)
+ {
+ location_set(location_get() + d.location_get());
+ decs_->emplace_back(&d);
+ return *this;
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/class-ty.cc b/tiger-compiler/src/ast/class-ty.cc
new file mode 100644
index 0000000..ca5e983
--- /dev/null
+++ b/tiger-compiler/src/ast/class-ty.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/class-ty.cc
+ ** \brief Implementation of ast::ClassTy.
+ */
+
+#include <ast/class-ty.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ ClassTy::ClassTy(const Location& location, NameTy* super, ChunkList* chunks)
+ : Ty(location)
+ , super_(super)
+ , chunks_(chunks)
+ {}
+
+ ClassTy::~ClassTy() { delete chunks_; }
+
+ void ClassTy::accept(ConstVisitor& v) const { v(*this); }
+
+ void ClassTy::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/class-ty.hh b/tiger-compiler/src/ast/class-ty.hh
new file mode 100644
index 0000000..0045685
--- /dev/null
+++ b/tiger-compiler/src/ast/class-ty.hh
@@ -0,0 +1,55 @@
+/**
+ ** \file ast/class-ty.hh
+ ** \brief Declaration of ast::ClassTy.
+ */
+
+#pragma once
+
+#include <ast/chunk-list.hh>
+#include <ast/name-ty.hh>
+#include <ast/ty.hh>
+
+namespace ast
+{
+ /// ClassTy.
+ class ClassTy : public Ty
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a ClassTy node.
+ ClassTy(const Location& location, NameTy* super, ChunkList* chunks);
+ ClassTy(const ClassTy&) = delete;
+ ClassTy& operator=(const ClassTy&) = delete;
+ /// Destroy a ClassTy node.
+ ~ClassTy() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return super class.
+ const NameTy& super_get() const;
+ /// Return super class.
+ NameTy& super_get();
+ /// Return list of declarations.
+ const ChunkList& chunks_get() const;
+ /// Return list of declarations.
+ ChunkList& chunks_get();
+ /** \} */
+
+ protected:
+ /// Super class.
+ NameTy* super_;
+ /// List of declarations.
+ ChunkList* chunks_;
+ };
+} // namespace ast
+#include <ast/class-ty.hxx>
diff --git a/tiger-compiler/src/ast/class-ty.hxx b/tiger-compiler/src/ast/class-ty.hxx
new file mode 100644
index 0000000..70c291b
--- /dev/null
+++ b/tiger-compiler/src/ast/class-ty.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/class-ty.hxx
+ ** \brief Inline methods of ast::ClassTy.
+ */
+
+#pragma once
+
+#include <ast/class-ty.hh>
+
+namespace ast
+{
+
+ inline const NameTy& ClassTy::super_get() const { return *super_; }
+ inline NameTy& ClassTy::super_get() { return *super_; }
+
+ inline const ChunkList& ClassTy::chunks_get() const { return *chunks_; }
+ inline ChunkList& ClassTy::chunks_get() { return *chunks_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/dec.cc b/tiger-compiler/src/ast/dec.cc
new file mode 100644
index 0000000..b19ed0b
--- /dev/null
+++ b/tiger-compiler/src/ast/dec.cc
@@ -0,0 +1,17 @@
+/**
+ ** \file ast/dec.cc
+ ** \brief Implementation of ast::Dec.
+ */
+
+#include <ast/dec.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Dec::Dec(const Location& location, misc::symbol name)
+ : Ast(location)
+ , Typable()
+ , name_(name)
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/dec.hh b/tiger-compiler/src/ast/dec.hh
new file mode 100644
index 0000000..f61489e
--- /dev/null
+++ b/tiger-compiler/src/ast/dec.hh
@@ -0,0 +1,50 @@
+/**
+ ** \file ast/dec.hh
+ ** \brief Declaration of ast::Dec.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/typable.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// Dec.
+ class Dec
+ : public Ast
+ , public Typable
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a Dec node.
+ Dec(const Location& location, misc::symbol name);
+ Dec(const Dec&) = delete;
+ Dec& operator=(const Dec&) = delete;
+ /// Destroy a Dec node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override = 0;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override = 0;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return name of the defined entity.
+ misc::symbol name_get() const;
+ /// Set name of the defined entity.
+ void name_set(misc::symbol);
+ /** \} */
+
+ protected:
+ /// Name of the defined entity.
+ misc::symbol name_;
+ };
+} // namespace ast
+#include <ast/dec.hxx>
diff --git a/tiger-compiler/src/ast/dec.hxx b/tiger-compiler/src/ast/dec.hxx
new file mode 100644
index 0000000..f3c12f5
--- /dev/null
+++ b/tiger-compiler/src/ast/dec.hxx
@@ -0,0 +1,15 @@
+/**
+ ** \file ast/dec.hxx
+ ** \brief Inline methods of ast::Dec.
+ */
+
+#pragma once
+
+#include <ast/dec.hh>
+
+namespace ast
+{
+ inline misc::symbol Dec::name_get() const { return name_; }
+ inline void Dec::name_set(misc::symbol name) { name_ = name; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/default-visitor.hh b/tiger-compiler/src/ast/default-visitor.hh
new file mode 100644
index 0000000..e4e2355
--- /dev/null
+++ b/tiger-compiler/src/ast/default-visitor.hh
@@ -0,0 +1,151 @@
+/**
+ ** \file ast/default-visitor.hh
+ ** \brief Traverse an Abstract Syntax Tree (w/o objects), doing nothing.
+ */
+
+#pragma once
+
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ /** \brief Just visit the whole Ast tree (except object-related nodes).
+
+ GenDefaultVisitor<CONSTNESS-SELECTOR> visits non-object-related
+ node of the the whole Ast tree, but does nothing else.
+
+ Beware, as there are no implementations visiting object-oriented
+ constructs (classes, objects, methods), hence this class is
+ abstract.
+
+ ast::GenDefaultVisitor inherits virtually from ast::GenVisitor
+ to allow diamond inheritance, e.g. so that a subclass of
+ ast::GenDefaultVisitor can also inherit missing object-related
+ implementations from another class (inheriting from
+ ast::GenVisitor).
+
+ \see ast::NonObjectVisitor for more information. */
+ template <template <typename> class Const>
+ class GenDefaultVisitor : public virtual GenVisitor<Const>
+ {
+ public:
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded \c operator() methods.
+ using super_type::operator();
+
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a default visitor.
+ GenDefaultVisitor();
+ /// Destroy a default visitor.
+ virtual ~GenDefaultVisitor();
+ /** \} */
+
+ /* We cannot simply use `using super_type::operator()' here,
+ otherwise the linker would complain about missing symbols for
+ these methods:
+
+ GenVisitor<id_traits>::operator()(ast::MethodDec&)
+ GenVisitor<id_traits>::operator()(ast::MethodCallExp&)
+
+ This behavior seems to come from the mix between diamond
+ inheritance and templates. We redefine the following operator
+ (delegating to GenVisitor's operator()) as a workaround. */
+ void operator()(const_t<Ast>& e) override;
+
+ /** \name Visit Variable related nodes.
+ ** \{ */
+ void operator()(const_t<SimpleVar>& e) override;
+ void operator()(const_t<FieldVar>& e) override;
+ void operator()(const_t<SubscriptVar>& e) override;
+ /** \} */
+
+ /** \name Visit Expression related nodes.
+ ** \{ */
+ void operator()(const_t<NilExp>& e) override;
+ void operator()(const_t<IntExp>& e) override;
+ void operator()(const_t<StringExp>& e) override;
+ void operator()(const_t<CallExp>& e) override;
+ void operator()(const_t<OpExp>& e) override;
+ void operator()(const_t<RecordExp>& e) override;
+ void operator()(const_t<SeqExp>& e) override;
+ void operator()(const_t<AssignExp>& e) override;
+ void operator()(const_t<IfExp>& e) override;
+ void operator()(const_t<WhileExp>& e) override;
+ void operator()(const_t<ForExp>& e) override;
+ void operator()(const_t<BreakExp>&) override;
+ void operator()(const_t<LetExp>& e) override;
+ void operator()(const_t<ArrayExp>& e) override;
+ void operator()(const_t<CastExp>& e) override;
+ void operator()(const_t<FieldInit>& e) override;
+ /** \} */
+
+ /** \name Visit Declaration related nodes.
+ **
+ ** Visiting declarations is simple, but there are many clauses.
+ ** This is because, in Tiger, the declarations are processed by
+ ** chunks (a chunk of Function declarations, then Var or Type,
+ ** then ...).
+ ** So we have to explain
+ ** \li How to visit a list of chunks;
+ ** \li how to visit chunks of function, var, or type declarations;
+ ** \li how to visit a single function, var, or type declaration.
+ ** \{ */
+
+ /// Visit a list of function, type and/or variables declarations.
+ void operator()(const_t<ChunkList>& e) override;
+
+ /// Visit a ChunkInterface chunks.
+ virtual void operator()(const_t<ChunkInterface>& e);
+
+ template <typename ChunkType>
+ /** \brief Visit a chunk (i.e., a list of Function, Var, and Type declarations).
+ **
+ ** It is exactly the same in the three cases, so the code is
+ ** factored via a template method. */
+ void chunk_visit(const_t<ChunkType>& e);
+
+ /// Visit Var declarations.
+ void operator()(const_t<VarChunk>& e) override;
+ void operator()(const_t<VarDec>& e) override;
+
+ /// Visit Function declarations.
+ void operator()(const_t<FunctionChunk>& e) override;
+ void operator()(const_t<FunctionDec>& e) override;
+
+ /// Visit Type declarations.
+ void operator()(const_t<TypeChunk>& e) override;
+ void operator()(const_t<TypeDec>& e) override;
+
+ /** \} */
+
+ /** \name Visit Type related nodes.
+ ** \{ */
+ void operator()(const_t<NameTy>& e) override;
+ void operator()(const_t<RecordTy>& e) override;
+ void operator()(const_t<ArrayTy>& e) override;
+ /** \} */
+
+ /** \name Visit Field related nodes. */
+ void operator()(const_t<Field>& e) override;
+ };
+
+ /// Shorthand for a const visitor.
+ using DefaultConstVisitor = GenDefaultVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using DefaultVisitor = GenDefaultVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ /// Shorthand for a const visitor.
+ %template(DefaultConstVisitor) GenDefaultVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ %template(DefaultVisitor) GenDefaultVisitor<misc::id_traits>;
+#endif
+} // namespace ast
+
+#include <ast/default-visitor.hxx>
diff --git a/tiger-compiler/src/ast/default-visitor.hxx b/tiger-compiler/src/ast/default-visitor.hxx
new file mode 100644
index 0000000..3d49e83
--- /dev/null
+++ b/tiger-compiler/src/ast/default-visitor.hxx
@@ -0,0 +1,247 @@
+/**
+ ** \file ast/default-visitor.hxx
+ ** \brief Implementation for ast/default-visitor.hh.
+ */
+
+#pragma once
+
+#include <ast/all.hh>
+#include <ast/default-visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ GenDefaultVisitor<Const>::GenDefaultVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenDefaultVisitor<Const>::~GenDefaultVisitor()
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Ast>& e)
+ {
+ super_type::operator()(e);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<SimpleVar>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<FieldVar>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.var_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<SubscriptVar>& e)
+ {
+ e.var_get().accept(*this);
+ e.index_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<NilExp>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<IntExp>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<StringExp>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<CallExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto arg : e.args_get())
+ arg->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<OpExp>& e)
+ {
+ e.left_get().accept(*this);
+ e.right_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<RecordExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.type_name_get().accept(*this);
+ for (auto field : e.fields_get())
+ field->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<SeqExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto exp : e.exps_get())
+ exp->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<AssignExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.var_get().accept(*this);
+ e.exp_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<IfExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.test_get().accept(*this);
+ e.thenclause_get().accept(*this);
+ e.elseclause_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<WhileExp>& e)
+ {
+ e.test_get().accept(*this);
+ e.body_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<ForExp>& e)
+ {
+ e.vardec_get().accept(*this);
+ e.hi_get().accept(*this);
+ e.body_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<BreakExp>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<LetExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.chunks_get().accept(*this);
+ e.body_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<ArrayExp>& e)
+ {
+ // FIXME: Some code was deleted here.
+ e.type_name_get().accept(*this);
+ e.size_get().accept(*this);
+ e.init_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<CastExp>& e)
+ {
+ e.exp_get().accept(*this);
+ e.ty_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<FieldInit>& e)
+ {
+ e.init_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<ChunkList>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto chunk : e.chunks_get())
+ chunk->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<ChunkInterface>& e)
+ {
+ e.accept(*this);
+ }
+
+ template <template <typename> class Const>
+ template <typename ChunkType>
+ inline void GenDefaultVisitor<Const>::chunk_visit(const_t<ChunkType>& e)
+ {
+ for (const auto dec : e)
+ dec->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<VarChunk>& e)
+ {
+ chunk_visit<VarChunk>(e);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<VarDec>& e)
+ {
+ // `type_name' might be omitted.
+ this->accept(e.type_name_get());
+ // `init' can be null in case of formal parameter.
+ this->accept(e.init_get());
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<FunctionChunk>& e)
+ {
+ chunk_visit<FunctionChunk>(e);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<FunctionDec>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.formals_get().accept(*this);
+ if (e.result_get() != nullptr)
+ e.result_get()->accept(*this);
+ if (e.body_get() != nullptr)
+ e.body_get()->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<TypeChunk>& e)
+ {
+ chunk_visit<TypeChunk>(e);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<TypeDec>& e)
+ {
+ e.ty_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<NameTy>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<RecordTy>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto field : e.fields_get())
+ field->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<ArrayTy>& e)
+ {
+ e.base_type_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Field>& e)
+ {
+ e.type_name_get().accept(*this);
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/dumper-dot.cc b/tiger-compiler/src/ast/dumper-dot.cc
new file mode 100644
index 0000000..aef9568
--- /dev/null
+++ b/tiger-compiler/src/ast/dumper-dot.cc
@@ -0,0 +1,438 @@
+/**
+ ** \file ast/dumper-dot.cc
+ ** \brief Implementation of ast::DumperDot.
+ */
+
+#include <ast/all.hh>
+#include <ast/dumper-dot.hh>
+#include <misc/indent.hh>
+#include <misc/symbol.hh>
+#include <type/pretty-printer.hh>
+
+namespace ast
+{
+ using namespace ast;
+
+ void DumperDot::dump(const std::string& field, const ast::Ast& e)
+ {
+ const std::string* old_parent_field = parent_field;
+ parent_field = &field;
+ e.accept(*this);
+ parent_field = old_parent_field;
+ }
+
+ void DumperDot::dump(const std::string& field, const ast::Ast* e)
+ {
+ if (!e)
+ return;
+ const std::string* old_parent_field = parent_field;
+ parent_field = &field;
+ e->accept(*this);
+ parent_field = old_parent_field;
+ }
+
+ DumperDot::DumperDot(std::ostream& ostr)
+ : ostr_(ostr)
+ {}
+
+ void DumperDot::dump_type(const ast::Typable& e)
+ {
+ // FIXME DONE: Some code was deleted here (Call node_html_field on a e.type_get() if exist).
+ if (e.type_get())
+ node_html_field("typable", *e.type_get());
+ }
+
+ void DumperDot::operator()(const ArrayExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "ArrayExp");
+ dump_type(e);
+ // FIXME DONE:Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"type_name", "size", "init"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("type_name", e.type_name_get());
+ dump("size", e.size_get());
+ dump("init", e.init_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const ArrayTy& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "ArrayTy");
+ dump_type(e);
+ node_html_ports({"base_type"});
+ footer_and_link(old_parent_id);
+ dump("base_type", e.base_type_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const AssignExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "AssignExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"exp", "var"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("base_type", e.exp_get());
+ dump("var", e.var_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const BreakExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "BreakExp");
+ dump_type(e);
+ node_html_ports({"def"});
+ footer_and_link(old_parent_id);
+ dump_def(e);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const CallExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "CallExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_field).
+ node_html_field("name", e.name_get());
+ node_html_ports();
+ // FIXME DONE: Some code was deleted here (node_html_port_list for each list).
+ node_html_port_list("args",e.args_get(), true);
+ node_html_one_port("def");
+ footer_and_link(old_parent_id);
+ dump_def(e);
+ // FIXME DONE: Some code was deleted here (dump_list).
+ dump_list("args",e.args_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const CastExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "CastExp");
+ dump_type(e);
+ node_html_ports({"exp", "ty"});
+ footer_and_link(old_parent_id);
+ dump("exp", e.exp_get());
+ dump("ty", e.ty_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const ClassTy& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "ClassTy");
+ dump_type(e);
+ node_html_ports({"super", "chunks"});
+ footer_and_link(old_parent_id);
+ dump("super", e.super_get());
+ dump("chunks", e.chunks_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const Field& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "Field");
+ node_html_field("name", e.name_get());
+ node_html_ports({"type_name"});
+ footer_and_link(old_parent_id);
+ dump("type_name", e.type_name_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const FieldInit& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "FieldInit");
+ node_html_field("name", e.name_get());
+ node_html_ports({"init"});
+ footer_and_link(old_parent_id);
+ dump("init", e.init_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const FieldVar& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "FieldVar");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_field).
+ node_html_field("name", e.name_get());
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"var"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("var",e.var_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const ForExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "ForExp");
+ dump_type(e);
+ node_html_ports({"vardec", "hi", "body"});
+ footer_and_link(old_parent_id);
+ dump("vardec", e.vardec_get());
+ dump("hi", e.hi_get());
+ dump("body", e.body_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const FunctionDec& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "FunctionDec");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"formals", "result", "body"});
+ footer_and_link(old_parent_id);
+ dump("formals", e.formals_get());
+ dump("result", e.result_get());
+ dump("body", e.body_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const IfExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "IfExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"test","then_clause","else_clause"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("test",e.test_get());
+ dump("then_clause",e.thenclause_get());
+ dump("else_clause", e.elseclause_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const IntExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "IntExp");
+ dump_type(e);
+ node_html_field("value", e.value_get());
+ footer_and_link(old_parent_id);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const LetExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "LetExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"chunk","body"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("chunk", e.chunks_get());
+ dump("body",e.body_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const MethodCallExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "MethodCallExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_field).
+ node_html_field("name", e.name_get());
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"object"});
+ // FIXME DONE: Some code was deleted here (node_html_port_list for each list).
+ node_html_port_list("args",e.args_get(), true);
+ node_html_one_port("def");
+ footer_and_link(old_parent_id);
+ dump_def(e);
+ // FIXME DONE: Some code was deleted here (dump and dump_list).
+ dump("object",e.object_get());
+ dump_list("args",e.args_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const MethodDec& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "MethodDec");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"formals", "result", "body"});
+ footer_and_link(old_parent_id);
+ dump("formals", e.formals_get());
+ dump("result", e.result_get());
+ dump("body", e.body_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const NameTy& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "NameTy");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"def"});
+ footer_and_link(old_parent_id);
+ dump_def(e);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const NilExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "NilExp");
+ dump_type(e);
+ footer_and_link(old_parent_id);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const ObjectExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "ObjectExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"type_name"});
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump).
+ dump("type_name", e.type_name_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const OpExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "OpExp");
+ dump_type(e);
+ node_html_field("oper", str(e.oper_get()), "'");
+ node_html_ports({"left", "right"});
+ footer_and_link(old_parent_id);
+ dump("left", e.left_get());
+ dump("right", e.right_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const RecordExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "RecordExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_ports with properties).
+ node_html_ports({"type_name"});
+ // FIXME DONE: Some code was deleted here (node_html_port_list for each list).
+ node_html_port_list("fields",e.fields_get());
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump and dump_list).
+ dump("type_name",e.type_name_get());
+ dump_list("fields",e.fields_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const RecordTy& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "RecordTy");
+ dump_type(e);
+ node_html_ports();
+ // FIXME DONE: Some code was deleted here (node_html_port_list for each list).
+ node_html_port_list("fields", e.fields_get());
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump_list).
+ dump_list("fields",e.fields_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const SeqExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "SeqExp");
+ dump_type(e);
+ node_html_ports();
+ // FIXME DONE: Some code was deleted here (node_html_port_list for each list).
+ node_html_port_list("exps", e.exps_get());
+ footer_and_link(old_parent_id);
+ // FIXME DONE: Some code was deleted here (dump_list).
+ dump_list("fields",e.exps_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const SimpleVar& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "SimpleVar");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"def"});
+ footer_and_link(old_parent_id);
+ dump_def(e);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const StringExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "StringExp");
+ dump_type(e);
+ // FIXME DONE: Some code was deleted here (node_html_field, use misc::escape).
+ // WTF ?????? Ce code est completement fait au pif je vous le dis :)
+ node_html_field("",misc::escape(e.value_get()));
+ footer_and_link(old_parent_id);
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const SubscriptVar& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "SubscriptVar");
+ dump_type(e);
+ node_html_ports({"var", "index"});
+ footer_and_link(old_parent_id);
+ dump("var", e.var_get());
+ dump("index", e.index_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const TypeDec& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "TypeDec");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"ty"});
+ footer_and_link(old_parent_id);
+ dump("ty", e.ty_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const VarDec& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "VarDec");
+ dump_type(e);
+ node_html_field("name", e.name_get());
+ node_html_ports({"type_name", "init"});
+ footer_and_link(old_parent_id);
+ dump("type_name", e.type_name_get());
+ dump("init", e.init_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const WhileExp& e)
+ {
+ unsigned long old_parent_id = node_html_header(e, "WhileExp");
+ dump_type(e);
+ node_html_ports({"test", "body"});
+ footer_and_link(old_parent_id);
+ dump("test", e.test_get());
+ dump("body", e.body_get());
+ parent_id = old_parent_id;
+ }
+
+ void DumperDot::operator()(const ast::AssertExp&)
+ {
+ // FIXME: Some code was deleted here.
+ }
+
+ void DumperDot::operator()(const ast::ChunkList& e)
+ {
+ dump_chunk<ast::ChunkList>(e, "ChunkList");
+ }
+
+ void DumperDot::operator()(const ast::FunctionChunk& e)
+ {
+ dump_chunk<ast::FunctionChunk>(e, "FunctionChunk");
+ }
+
+ void DumperDot::operator()(const ast::MethodChunk& e)
+ {
+ dump_chunk<ast::MethodChunk>(e, "MethodChunk");
+ }
+
+ void DumperDot::operator()(const ast::TypeChunk& e)
+ {
+ dump_chunk<ast::TypeChunk>(e, "TypeChunk");
+ }
+
+ void DumperDot::operator()(const ast::VarChunk& e)
+ {
+ dump_chunk<ast::VarChunk>(e, "VarChunk");
+ }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/dumper-dot.hh b/tiger-compiler/src/ast/dumper-dot.hh
new file mode 100644
index 0000000..a297f30
--- /dev/null
+++ b/tiger-compiler/src/ast/dumper-dot.hh
@@ -0,0 +1,112 @@
+
+/**
+ ** \file ast/dumper-dot.hh
+ ** \brief Declaration of ast::DumperDot.
+ */
+
+#pragma once
+
+#include <ast/default-visitor.hh>
+#include <misc/concepts.hh>
+#include <misc/escape.hh>
+
+namespace ast
+{
+ /// \brief Dump an Ast into dot format.
+ class DumperDot : public ast::DefaultConstVisitor
+ {
+ public:
+ using super_type = ast::DefaultConstVisitor;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a DumperDot.
+ DumperDot(std::ostream& ostr);
+
+ /// Destroy a DumperDot.
+ ~DumperDot() override = default;
+
+ // Visit methods.
+ public:
+ void operator()(const ast::ArrayExp&) override;
+ void operator()(const ast::ArrayTy&) override;
+ void operator()(const ast::AssignExp&) override;
+ void operator()(const ast::BreakExp&) override;
+ void operator()(const ast::CallExp&) override;
+ void operator()(const ast::CastExp&) override;
+ void operator()(const ast::ChunkList&) override;
+ void operator()(const ast::ClassTy&) override;
+ void operator()(const ast::Field&) override;
+ void operator()(const ast::FieldInit&) override;
+ void operator()(const ast::FieldVar&) override;
+ void operator()(const ast::ForExp&) override;
+ void operator()(const ast::FunctionDec&) override;
+ void operator()(const ast::IfExp&) override;
+ void operator()(const ast::IntExp&) override;
+ void operator()(const ast::LetExp&) override;
+ void operator()(const ast::MethodCallExp&) override;
+ void operator()(const ast::MethodDec&) override;
+ void operator()(const ast::NameTy&) override;
+ void operator()(const ast::NilExp&) override;
+ void operator()(const ast::ObjectExp&) override;
+ void operator()(const ast::OpExp&) override;
+ void operator()(const ast::RecordExp&) override;
+ void operator()(const ast::RecordTy&) override;
+ void operator()(const ast::SeqExp&) override;
+ void operator()(const ast::SimpleVar&) override;
+ void operator()(const ast::StringExp&) override;
+ void operator()(const ast::SubscriptVar&) override;
+ void operator()(const ast::TypeDec&) override;
+ void operator()(const ast::VarDec&) override;
+ void operator()(const ast::WhileExp&) override;
+ void operator()(const ast::FunctionChunk&) override;
+ void operator()(const ast::MethodChunk&) override;
+ void operator()(const ast::TypeChunk&) override;
+ void operator()(const ast::VarChunk&) override;
+ void operator()(const ast::AssertExp&) override;
+
+ protected:
+ void dump(const std::string& field, const ast::Ast& t);
+ void dump(const std::string& field, const ast::Ast* t);
+ template <typename Container>
+ requires misc::ConstIterable<Container>
+ void dump_list(const std::string& field, const Container& l);
+ template <typename T> void dump_def(const T& e) const;
+ void dump_type(const ast::Typable& e);
+ template <typename E> void dump_chunk(const E& e, const std::string& name);
+
+ void display_link(unsigned long old_parent_id) const;
+ void footer_and_link(unsigned long old_parent_id) const;
+
+ template <typename T>
+ unsigned long node_html_header(const T& e, const std::string& type);
+ template <typename T>
+ void node_html_field(const std::string& name,
+ const T& content,
+ const std::string& sep = "");
+ void node_html_one_port(const std::string& p);
+ void node_html_ports(const std::vector<std::string>& ports = {});
+ template <typename T>
+ void node_html_port_list(const std::string& name,
+ const T& list,
+ bool chunk = false);
+ void node_html_footer() const;
+
+ protected:
+ /// The stream to print on.
+ std::ostream& ostr_;
+
+ /// The parent id
+ unsigned long parent_id = -1;
+
+ /// Number of fields
+ unsigned long inner_fields = 0;
+
+ /// The parent field
+ const std::string* parent_field = nullptr;
+ };
+
+} // namespace ast
+
+#include <ast/dumper-dot.hxx>
diff --git a/tiger-compiler/src/ast/dumper-dot.hxx b/tiger-compiler/src/ast/dumper-dot.hxx
new file mode 100644
index 0000000..30a7b33
--- /dev/null
+++ b/tiger-compiler/src/ast/dumper-dot.hxx
@@ -0,0 +1,214 @@
+/**
+ ** \file ast/dumper-dot.hxx
+ ** \brief Implementation of ast::DumperDot.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <ast/dumper-dot.hh>
+#include <misc/indent.hh>
+
+namespace ast
+{
+
+ template <typename Container>
+ requires misc::ConstIterable<Container>
+ inline void DumperDot::dump_list(const std::string& field, const Container& l)
+ {
+ const std::string* old_parent_field = parent_field;
+ auto it = l.begin();
+ unsigned n = 0;
+ while (it != l.end())
+ {
+ std::ostringstream o;
+ o << field;
+ if (std::next(it) != l.end() || n > 0)
+ o << n++;
+ const std::string field_name = o.str();
+ parent_field = &field_name;
+ (*it++)->accept(*this);
+ }
+ parent_field = old_parent_field;
+ }
+
+ template <typename T> inline void DumperDot::dump_def(const T& e) const
+ {
+ const ast::Ast* d = nullptr;
+ // FIXME: Some code was deleted here (set d using definition of e).
+ (void)e;
+ if (!d)
+ return;
+ ostr_ << parent_id << ":def:s -> " << reinterpret_cast<std::uintptr_t>(d)
+ << ":nodename [constraint=false, style=dashed, color=\"dimgray\"]"
+ << misc::iendl;
+ }
+
+ inline void DumperDot::display_link(unsigned long old_parent_id) const
+ {
+ if (parent_field)
+ ostr_ << old_parent_id << ":" << *parent_field << ":s"
+ << " -> " << parent_id << ":nodename:n" << misc::iendl;
+ }
+
+ inline void DumperDot::footer_and_link(unsigned long old_parent_id) const
+ {
+ node_html_footer();
+ display_link(old_parent_id);
+ }
+
+ template <typename E>
+ inline void DumperDot::dump_chunk(const E& e, const std::string& name)
+ {
+ unsigned long old_parent_id = parent_id;
+ parent_id = reinterpret_cast<std::uintptr_t>(&e);
+ ostr_ << parent_id << " [label=<" << misc::incendl
+ << "<table cellborder='0' cellspacing='0'>" << misc::incendl << "<tr>"
+ << misc::incendl;
+ inner_fields = 0;
+ node_html_port_list(name, e, true);
+ ostr_ << misc::decendl << "</tr>" << misc::decendl << "</table>"
+ << misc::decendl << ">]" << misc::iendl;
+ display_link(old_parent_id);
+ dump_list("nodename", e);
+ parent_id = old_parent_id;
+ }
+
+ namespace
+ {
+ inline void node_html_begin_inner(std::ostream& ostr, bool list = false)
+ {
+ ostr << "<td cellpadding='0'>" << misc::incendl
+ << "<table border='0' cellborder='" << (list ? 0 : 1) << "'"
+ << " cellspacing='0' cellpadding='" << (list ? 0 : 2) << "'>"
+ << misc::incendl << "<tr>" << misc::incendl;
+ }
+
+ inline void node_html_end_inner(std::ostream& ostr)
+ {
+ ostr << misc::decendl << "</tr>" << misc::decendl << "</table>"
+ << misc::decendl << "</td>";
+ }
+
+ inline void node_html_separator(std::ostream& ostr)
+ {
+ node_html_end_inner(ostr);
+ ostr << misc::decendl << "</tr>" << misc::iendl << "<tr>"
+ << misc::incendl;
+ node_html_begin_inner(ostr);
+ }
+ inline void node_html_tr(std::ostream& ostr,
+ const std::string& port,
+ const std::string content)
+ {
+ ostr << "<td port='" << port << "'>" << content << "</td>";
+ }
+ inline bool ends_with(const std::string& value, const std::string& ending)
+ {
+ if (ending.size() > value.size())
+ return false;
+ return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+ }
+ inline std::string node_html_color(const std::string& type)
+ {
+ if (ends_with(type, "Dec"))
+ return "red1";
+ else if (ends_with(type, "Var"))
+ return "orange1";
+ else if (ends_with(type, "Ty"))
+ return "green3";
+ else if (ends_with(type, "Exp"))
+ return "blue2";
+ return "black";
+ }
+
+ template <typename T> std::string html_escape(const T& input)
+ {
+ std::ostringstream i;
+ i << input;
+ const std::string& str = i.str();
+ std::ostringstream o;
+ const std::string& specials = "&<>";
+ for (const auto& p : str)
+ if (p == '\\')
+ o << '\\' << '\\';
+ else if (specials.find(p) != std::string::npos)
+ o << "&#" << static_cast<int>(static_cast<unsigned char>(p)) << ";";
+ else
+ o << p;
+ return o.str();
+ }
+ } // namespace
+
+ template <typename T>
+ inline unsigned long DumperDot::node_html_header(const T& e,
+ const std::string& type)
+ {
+ unsigned long old_parent_id = parent_id;
+ parent_id = reinterpret_cast<std::uintptr_t>(&e);
+ ostr_ << parent_id << " [label=<" << misc::incendl
+ << "<table border='0' cellborder='0' cellspacing='0' cellpadding='0'"
+ << " color='" << node_html_color(type) << "'>" << misc::incendl
+ << "<tr>" << misc::incendl;
+ node_html_begin_inner(ostr_);
+ node_html_tr(ostr_, "nodename", type);
+ node_html_separator(ostr_);
+ inner_fields = 0;
+ return old_parent_id;
+ }
+ template <typename T>
+ inline void DumperDot::node_html_field(const std::string& name,
+ const T& content,
+ const std::string& sep)
+ {
+ std::ostringstream o;
+ o << name << ":&nbsp;" << sep << html_escape(content) << sep;
+ if (inner_fields++)
+ ostr_ << misc::iendl;
+ node_html_tr(ostr_, name, o.str());
+ }
+ inline void DumperDot::node_html_one_port(const std::string& p)
+ {
+ if (inner_fields++)
+ ostr_ << misc::iendl;
+ node_html_tr(ostr_, p, p);
+ }
+ inline void DumperDot::node_html_ports(const std::vector<std::string>& ports)
+ {
+ if (inner_fields)
+ node_html_separator(ostr_);
+ inner_fields = 0;
+ for (auto p : ports)
+ node_html_one_port(p);
+ }
+ template <typename T>
+ inline void DumperDot::node_html_port_list(const std::string& name,
+ const T& list,
+ bool chunk)
+ {
+ if (inner_fields++)
+ ostr_ << misc::iendl;
+ const std::string ref = chunk ? "nodename" : name;
+ node_html_begin_inner(ostr_, true);
+ long int size = std::distance(list.begin(), list.end());
+ ostr_ << "<td port='" << ref << "' colspan='" << (size ? size : 1) << "'>"
+ << name << "</td>";
+ if (size > 1)
+ {
+ ostr_ << misc::decendl << "</tr>" << misc::iendl << "<tr>"
+ << misc::incindent;
+ for (long int n = 0; n < size; n++)
+ ostr_ << misc::iendl << "<td port='" << ref << n << "'>" << n
+ << "</td>";
+ }
+ node_html_end_inner(ostr_);
+ }
+ inline void DumperDot::node_html_footer() const
+ {
+ if (!inner_fields)
+ ostr_ << "<td></td>";
+ node_html_end_inner(ostr_);
+ ostr_ << misc::decendl << "</tr>" << misc::decendl << "</table>"
+ << misc::decendl << ">]" << misc::iendl;
+ }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/escapable.cc b/tiger-compiler/src/ast/escapable.cc
new file mode 100644
index 0000000..9ca80e4
--- /dev/null
+++ b/tiger-compiler/src/ast/escapable.cc
@@ -0,0 +1,14 @@
+/**
+ ** \file ast/escapable.cc
+ ** \brief Implementation of ast::Escapable.
+ */
+
+#include <ast/escapable.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+ bool Escapable::escape_get() const { return escaping_; }
+ void Escapable::escape_set(bool escaped) { escaping_ = escaped; }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/escapable.hh b/tiger-compiler/src/ast/escapable.hh
new file mode 100644
index 0000000..b062114
--- /dev/null
+++ b/tiger-compiler/src/ast/escapable.hh
@@ -0,0 +1,30 @@
+/**
+ ** \file ast/escapable.hh
+ ** \brief Declaration of ast::Escapable.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+
+namespace ast
+{
+ /// Escapable.
+ class Escapable
+ {
+ // FIXME DONE: Some code was deleted here.
+ public:
+ // Returns whether the object is escaped
+ bool escape_get() const;
+ // Sets the escaped status of the object
+ void escape_set(bool escaped);
+ // Return definition site.
+ FunctionDec* def_get() const;
+ // Set definition site.
+ void def_set(FunctionDec*);
+ private:
+ bool escaping_ = true;
+ FunctionDec* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/escapable.hxx>
diff --git a/tiger-compiler/src/ast/escapable.hxx b/tiger-compiler/src/ast/escapable.hxx
new file mode 100644
index 0000000..00cb4bb
--- /dev/null
+++ b/tiger-compiler/src/ast/escapable.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/escapable.hxx
+ ** \brief Inline methods of ast::Escapable.
+ */
+
+#pragma once
+
+#include <ast/escapable.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+ inline FunctionDec* Escapable::def_get() const { return def_; }
+ inline void Escapable::def_set(FunctionDec* dec) { def_ = dec; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/exp.cc b/tiger-compiler/src/ast/exp.cc
new file mode 100644
index 0000000..1c3ce32
--- /dev/null
+++ b/tiger-compiler/src/ast/exp.cc
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/exp.cc
+ ** \brief Implementation of ast::Exp.
+ */
+
+#include <ast/exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Exp::Exp(const Location& location)
+ : Ast(location)
+ , Typable()
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/exp.hh b/tiger-compiler/src/ast/exp.hh
new file mode 100644
index 0000000..a4202c1
--- /dev/null
+++ b/tiger-compiler/src/ast/exp.hh
@@ -0,0 +1,43 @@
+/**
+ ** \file ast/exp.hh
+ ** \brief Declaration of ast::Exp.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/typable.hh>
+
+namespace ast
+{
+ /// Exp.
+ class Exp
+ : public Ast
+ , public Typable
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an Exp node.
+ explicit Exp(const Location& location);
+ Exp(const Exp&) = delete;
+ Exp& operator=(const Exp&) = delete;
+ /// Destroy an Exp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override = 0;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override = 0;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /** \} */
+
+ protected:
+ };
+} // namespace ast
+#include <ast/exp.hxx>
diff --git a/tiger-compiler/src/ast/exp.hxx b/tiger-compiler/src/ast/exp.hxx
new file mode 100644
index 0000000..49a8274
--- /dev/null
+++ b/tiger-compiler/src/ast/exp.hxx
@@ -0,0 +1,11 @@
+/**
+ ** \file ast/exp.hxx
+ ** \brief Inline methods of ast::Exp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{} // namespace ast
diff --git a/tiger-compiler/src/ast/field-init.cc b/tiger-compiler/src/ast/field-init.cc
new file mode 100644
index 0000000..54b5266
--- /dev/null
+++ b/tiger-compiler/src/ast/field-init.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/field-init.cc
+ ** \brief Implementation of ast::FieldInit.
+ */
+
+#include <ast/field-init.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ FieldInit::FieldInit(const Location& location, misc::symbol name, Exp* init)
+ : Ast(location)
+ , name_(name)
+ , init_(init)
+ {}
+
+ FieldInit::~FieldInit() { delete init_; }
+
+ void FieldInit::accept(ConstVisitor& v) const { v(*this); }
+
+ void FieldInit::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/field-init.hh b/tiger-compiler/src/ast/field-init.hh
new file mode 100644
index 0000000..9ea18b2
--- /dev/null
+++ b/tiger-compiler/src/ast/field-init.hh
@@ -0,0 +1,55 @@
+/**
+ ** \file ast/field-init.hh
+ ** \brief Declaration of ast::FieldInit.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/exp.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// FieldInit.
+ class FieldInit : public Ast
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a FieldInit node.
+ FieldInit(const Location& location, misc::symbol name, Exp* init);
+ FieldInit(const FieldInit&) = delete;
+ FieldInit& operator=(const FieldInit&) = delete;
+ /// Destroy a FieldInit node.
+ ~FieldInit() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return name of the field.
+ misc::symbol name_get() const;
+ /// Set name of the field.
+ void name_set(misc::symbol);
+ /// Return initial value of the field.
+ const Exp& init_get() const;
+ /// Return initial value of the field.
+ Exp& init_get();
+ /** \} */
+
+ protected:
+ /// Name of the field.
+ misc::symbol name_;
+ /// Initial value of the field.
+ Exp* init_;
+ };
+} // namespace ast
+#include <ast/field-init.hxx>
diff --git a/tiger-compiler/src/ast/field-init.hxx b/tiger-compiler/src/ast/field-init.hxx
new file mode 100644
index 0000000..1a895b7
--- /dev/null
+++ b/tiger-compiler/src/ast/field-init.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/field-init.hxx
+ ** \brief Inline methods of ast::FieldInit.
+ */
+
+#pragma once
+
+#include <ast/field-init.hh>
+
+namespace ast
+{
+
+ inline misc::symbol FieldInit::name_get() const { return name_; }
+ inline void FieldInit::name_set(misc::symbol name) { name_ = name; }
+
+ inline const Exp& FieldInit::init_get() const { return *init_; }
+ inline Exp& FieldInit::init_get() { return *init_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/field-var.cc b/tiger-compiler/src/ast/field-var.cc
new file mode 100644
index 0000000..7423fc1
--- /dev/null
+++ b/tiger-compiler/src/ast/field-var.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/field-var.cc
+ ** \brief Implementation of ast::FieldVar.
+ */
+
+#include <ast/field-var.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ FieldVar::FieldVar(const Location& location, Var* var, misc::symbol name)
+ : Var(location)
+ , var_(var)
+ , name_(name)
+ {}
+
+ FieldVar::~FieldVar() { delete var_; }
+
+ void FieldVar::accept(ConstVisitor& v) const { v(*this); }
+
+ void FieldVar::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/field-var.hh b/tiger-compiler/src/ast/field-var.hh
new file mode 100644
index 0000000..06c0b9a
--- /dev/null
+++ b/tiger-compiler/src/ast/field-var.hh
@@ -0,0 +1,60 @@
+/**
+ ** \file ast/field-var.hh
+ ** \brief Declaration of ast::FieldVar.
+ */
+
+#pragma once
+
+#include <ast/var.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// FieldVar.
+ class FieldVar : public Var
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a FieldVar node.
+ FieldVar(const Location& location, Var* var, misc::symbol name);
+ FieldVar(const FieldVar&) = delete;
+ FieldVar& operator=(const FieldVar&) = delete;
+ /// Destroy a FieldVar node.
+ ~FieldVar() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the record that holds the field.
+ const Var& var_get() const;
+ /// Return the record that holds the field.
+ Var& var_get();
+ /// Return the field's name.
+ misc::symbol name_get() const;
+ /// Set the field's name.
+ void name_set(misc::symbol);
+ /// Return handle the number of the field in the record that holds it.
+ int index_get() const;
+ /// Set handle the number of the field in the record that holds it.
+ void index_set(int);
+ /** \} */
+
+ protected:
+ /// The record that holds the field.
+ Var* var_;
+ /// The field's name.
+ misc::symbol name_;
+ /// Handle the number of the field in the record that holds it.
+ int index_ = -1;
+ };
+} // namespace ast
+#include <ast/field-var.hxx>
diff --git a/tiger-compiler/src/ast/field-var.hxx b/tiger-compiler/src/ast/field-var.hxx
new file mode 100644
index 0000000..cfadc89
--- /dev/null
+++ b/tiger-compiler/src/ast/field-var.hxx
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/field-var.hxx
+ ** \brief Inline methods of ast::FieldVar.
+ */
+
+#pragma once
+
+#include <ast/field-var.hh>
+
+namespace ast
+{
+
+ inline const Var& FieldVar::var_get() const { return *var_; }
+ inline Var& FieldVar::var_get() { return *var_; }
+
+ inline misc::symbol FieldVar::name_get() const { return name_; }
+ inline void FieldVar::name_set(misc::symbol name) { name_ = name; }
+
+ inline int FieldVar::index_get() const { return index_; }
+ inline void FieldVar::index_set(int index) { index_ = index; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/field.cc b/tiger-compiler/src/ast/field.cc
new file mode 100644
index 0000000..7265f24
--- /dev/null
+++ b/tiger-compiler/src/ast/field.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/field.cc
+ ** \brief Implementation of ast::Field.
+ */
+
+#include <ast/field.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Field::Field(const Location& location, misc::symbol name, NameTy* type_name)
+ : Ast(location)
+ , name_(name)
+ , type_name_(type_name)
+ {}
+
+ Field::~Field() { delete type_name_; }
+
+ void Field::accept(ConstVisitor& v) const { v(*this); }
+
+ void Field::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/field.hh b/tiger-compiler/src/ast/field.hh
new file mode 100644
index 0000000..cbb6352
--- /dev/null
+++ b/tiger-compiler/src/ast/field.hh
@@ -0,0 +1,55 @@
+/**
+ ** \file ast/field.hh
+ ** \brief Declaration of ast::Field.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/name-ty.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// Field.
+ class Field : public Ast
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a Field node.
+ Field(const Location& location, misc::symbol name, NameTy* type_name);
+ Field(const Field&) = delete;
+ Field& operator=(const Field&) = delete;
+ /// Destroy a Field node.
+ ~Field() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the field name.
+ misc::symbol name_get() const;
+ /// Set the field name.
+ void name_set(misc::symbol);
+ /// Return the field type name.
+ const NameTy& type_name_get() const;
+ /// Return the field type name.
+ NameTy& type_name_get();
+ /** \} */
+
+ protected:
+ /// The field name.
+ misc::symbol name_;
+ /// The field type name.
+ NameTy* type_name_;
+ };
+} // namespace ast
+#include <ast/field.hxx>
diff --git a/tiger-compiler/src/ast/field.hxx b/tiger-compiler/src/ast/field.hxx
new file mode 100644
index 0000000..0c7658c
--- /dev/null
+++ b/tiger-compiler/src/ast/field.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/field.hxx
+ ** \brief Inline methods of ast::Field.
+ */
+
+#pragma once
+
+#include <ast/field.hh>
+
+namespace ast
+{
+
+ inline misc::symbol Field::name_get() const { return name_; }
+ inline void Field::name_set(misc::symbol name) { name_ = name; }
+
+ inline const NameTy& Field::type_name_get() const { return *type_name_; }
+ inline NameTy& Field::type_name_get() { return *type_name_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/for-exp.cc b/tiger-compiler/src/ast/for-exp.cc
new file mode 100644
index 0000000..2ed51e1
--- /dev/null
+++ b/tiger-compiler/src/ast/for-exp.cc
@@ -0,0 +1,28 @@
+/**
+ ** \file ast/for-exp.cc
+ ** \brief Implementation of ast::ForExp.
+ */
+
+#include <ast/for-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ ForExp::ForExp(const Location& location, VarDec* vardec, Exp* hi, Exp* body)
+ : Exp(location)
+ , vardec_(vardec)
+ , hi_(hi)
+ , body_(body)
+ {}
+
+ ForExp::~ForExp()
+ {
+ delete vardec_;
+ delete hi_;
+ delete body_;
+ }
+
+ void ForExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void ForExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/for-exp.hh b/tiger-compiler/src/ast/for-exp.hh
new file mode 100644
index 0000000..b06a9be
--- /dev/null
+++ b/tiger-compiler/src/ast/for-exp.hh
@@ -0,0 +1,60 @@
+/**
+ ** \file ast/for-exp.hh
+ ** \brief Declaration of ast::ForExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/var-dec.hh>
+
+namespace ast
+{
+ /// ForExp.
+ class ForExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a ForExp node.
+ ForExp(const Location& location, VarDec* vardec, Exp* hi, Exp* body);
+ ForExp(const ForExp&) = delete;
+ ForExp& operator=(const ForExp&) = delete;
+ /// Destroy a ForExp node.
+ ~ForExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return implicit variable declaration.
+ const VarDec& vardec_get() const;
+ /// Return implicit variable declaration.
+ VarDec& vardec_get();
+ /// Return high bound of the loop.
+ const Exp& hi_get() const;
+ /// Return high bound of the loop.
+ Exp& hi_get();
+ /// Return instructions executed in the loop.
+ const Exp& body_get() const;
+ /// Return instructions executed in the loop.
+ Exp& body_get();
+ /** \} */
+
+ protected:
+ /// Implicit variable declaration.
+ VarDec* vardec_;
+ /// High bound of the loop.
+ Exp* hi_;
+ /// Instructions executed in the loop.
+ Exp* body_;
+ };
+} // namespace ast
+#include <ast/for-exp.hxx>
diff --git a/tiger-compiler/src/ast/for-exp.hxx b/tiger-compiler/src/ast/for-exp.hxx
new file mode 100644
index 0000000..c81d30f
--- /dev/null
+++ b/tiger-compiler/src/ast/for-exp.hxx
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/for-exp.hxx
+ ** \brief Inline methods of ast::ForExp.
+ */
+
+#pragma once
+
+#include <ast/for-exp.hh>
+
+namespace ast
+{
+
+ inline const VarDec& ForExp::vardec_get() const { return *vardec_; }
+ inline VarDec& ForExp::vardec_get() { return *vardec_; }
+
+ inline const Exp& ForExp::hi_get() const { return *hi_; }
+ inline Exp& ForExp::hi_get() { return *hi_; }
+
+ inline const Exp& ForExp::body_get() const { return *body_; }
+ inline Exp& ForExp::body_get() { return *body_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/function-dec.cc b/tiger-compiler/src/ast/function-dec.cc
new file mode 100644
index 0000000..c45ca0d
--- /dev/null
+++ b/tiger-compiler/src/ast/function-dec.cc
@@ -0,0 +1,33 @@
+/**
+ ** \file ast/function-dec.cc
+ ** \brief Implementation of ast::FunctionDec.
+ */
+
+#include <ast/function-dec.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ FunctionDec::FunctionDec(const Location& location,
+ misc::symbol name,
+ VarChunk* formals,
+ NameTy* result,
+ Exp* body)
+ : Dec(location, name)
+ , TypeConstructor()
+ , formals_(formals)
+ , result_(result)
+ , body_(body)
+ {}
+
+ FunctionDec::~FunctionDec()
+ {
+ delete formals_;
+ delete result_;
+ delete body_;
+ }
+
+ void FunctionDec::accept(ConstVisitor& v) const { v(*this); }
+
+ void FunctionDec::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/function-dec.hh b/tiger-compiler/src/ast/function-dec.hh
new file mode 100644
index 0000000..0a94e95
--- /dev/null
+++ b/tiger-compiler/src/ast/function-dec.hh
@@ -0,0 +1,72 @@
+/**
+ ** \file ast/function-dec.hh
+ ** \brief Declaration of ast::FunctionDec.
+ */
+
+#pragma once
+
+#include <ast/chunk.hh>
+#include <ast/dec.hh>
+#include <ast/exp.hh>
+#include <ast/name-ty.hh>
+#include <ast/type-constructor.hh>
+#include <ast/var-dec.hh>
+
+namespace ast
+{
+ /// FunctionDec.
+ class FunctionDec
+ : public Dec
+ , public TypeConstructor
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a FunctionDec node.
+ FunctionDec(const Location& location,
+ misc::symbol name,
+ VarChunk* formals,
+ NameTy* result,
+ Exp* body);
+ FunctionDec(const FunctionDec&) = delete;
+ FunctionDec& operator=(const FunctionDec&) = delete;
+ /// Destroy a FunctionDec node.
+ ~FunctionDec() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return formal arguments.
+ const VarChunk& formals_get() const;
+ /// Return formal arguments.
+ VarChunk& formals_get();
+ /// Return result type.
+ const NameTy* result_get() const;
+ /// Return result type.
+ NameTy* result_get();
+ /// Return instructions.
+ const Exp* body_get() const;
+ /// Return instructions.
+ Exp* body_get();
+ /// Set instructions.
+ void body_set(Exp*);
+ /** \} */
+
+ protected:
+ /// Formal arguments.
+ VarChunk* formals_;
+ /// Result type.
+ NameTy* result_;
+ /// Instructions.
+ Exp* body_;
+ };
+} // namespace ast
+#include <ast/function-dec.hxx>
diff --git a/tiger-compiler/src/ast/function-dec.hxx b/tiger-compiler/src/ast/function-dec.hxx
new file mode 100644
index 0000000..b9dda47
--- /dev/null
+++ b/tiger-compiler/src/ast/function-dec.hxx
@@ -0,0 +1,23 @@
+/**
+ ** \file ast/function-dec.hxx
+ ** \brief Inline methods of ast::FunctionDec.
+ */
+
+#pragma once
+
+#include <ast/function-dec.hh>
+
+namespace ast
+{
+
+ inline const VarChunk& FunctionDec::formals_get() const { return *formals_; }
+ inline VarChunk& FunctionDec::formals_get() { return *formals_; }
+
+ inline const NameTy* FunctionDec::result_get() const { return result_; }
+ inline NameTy* FunctionDec::result_get() { return result_; }
+
+ inline const Exp* FunctionDec::body_get() const { return body_; }
+ inline Exp* FunctionDec::body_get() { return body_; }
+ inline void FunctionDec::body_set(Exp* body) { body_ = body; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/fwd.hh b/tiger-compiler/src/ast/fwd.hh
new file mode 100644
index 0000000..3d2a611
--- /dev/null
+++ b/tiger-compiler/src/ast/fwd.hh
@@ -0,0 +1,80 @@
+/**
+ ** \file ast/fwd.hh
+ ** \brief Forward declarations of all AST classes
+ ** (needed by the visitors).
+ */
+
+#pragma once
+
+#include <list>
+#include <vector>
+#include <misc/fwd.hh>
+#include <misc/vector.hh>
+
+namespace ast
+{
+ class ArrayExp;
+ class ArrayTy;
+ class AssertExp;
+ class AssignExp;
+ class Ast;
+ class BreakExp;
+ class CallExp;
+ class CastExp;
+ class ChunkList;
+ class ClassTy;
+ class Dec;
+ class Escapable;
+ class Exp;
+ class Field;
+ class FieldInit;
+ class FieldVar;
+ class ForExp;
+ class FunctionDec;
+ class IfExp;
+ class IntExp;
+ class LetExp;
+ class MethodCallExp;
+ class MethodDec;
+ class NameTy;
+ class NilExp;
+ class ObjectExp;
+ class OpExp;
+ class RecordExp;
+ class RecordTy;
+ class SeqExp;
+ class SimpleVar;
+ class StringExp;
+ class SubscriptVar;
+ class Ty;
+ class Typable;
+ class TypeConstructor;
+ class TypeDec;
+ class Var;
+ class VarDec;
+ class WhileExp;
+
+ // From visitor.hh
+ template <template <typename> class Const> class GenVisitor;
+ using ConstVisitor = GenVisitor<misc::constify_traits>;
+ using Visitor = GenVisitor<misc::id_traits>;
+
+ // Collections of nodes.
+ using exps_type = std::vector<Exp*>;
+ using fieldinits_type = std::vector<FieldInit*>;
+ using fields_type = std::vector<Field*>;
+
+ // From chunk-interface.hh.
+ class ChunkInterface;
+
+ // From chunk-list.hh.
+ class ChunkList;
+
+ // From chunk.hh.
+ template <typename T> class Chunk;
+ using FunctionChunk = Chunk<FunctionDec>;
+ using MethodChunk = Chunk<MethodDec>;
+ using TypeChunk = Chunk<TypeDec>;
+ using VarChunk = Chunk<VarDec>;
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/if-exp.cc b/tiger-compiler/src/ast/if-exp.cc
new file mode 100644
index 0000000..ae1911f
--- /dev/null
+++ b/tiger-compiler/src/ast/if-exp.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file ast/if-exp.cc
+ ** \brief Implementation of ast::IfExp.
+ */
+
+#include <ast/if-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ IfExp::IfExp(const Location& location,
+ Exp* test,
+ Exp* thenclause,
+ Exp* elseclause)
+ : Exp(location)
+ , test_(test)
+ , thenclause_(thenclause)
+ , elseclause_(elseclause)
+ {}
+
+ IfExp::~IfExp()
+ {
+ delete test_;
+ delete thenclause_;
+ delete elseclause_;
+ }
+
+ void IfExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void IfExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/if-exp.hh b/tiger-compiler/src/ast/if-exp.hh
new file mode 100644
index 0000000..6b27452
--- /dev/null
+++ b/tiger-compiler/src/ast/if-exp.hh
@@ -0,0 +1,71 @@
+/**
+ ** \file ast/if-exp.hh
+ ** \brief Declaration of ast::IfExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/seq-exp.hh>
+
+namespace ast
+{
+ /// IfExp.
+ class IfExp : public Exp
+ {
+ public:
+ IfExp(const Location& location, Exp* test, Exp* thenclause)
+ : Exp(location)
+ , test_(test)
+ , thenclause_(thenclause)
+ , elseclause_(new SeqExp(location, new exps_type()))
+ {}
+
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an IfExp node.
+ IfExp(const Location& location,
+ Exp* test,
+ Exp* thenclause,
+ Exp* elseclause);
+ IfExp(const IfExp&) = delete;
+ IfExp& operator=(const IfExp&) = delete;
+ /// Destroy an IfExp node.
+ ~IfExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return condition.
+ const Exp& test_get() const;
+ /// Return condition.
+ Exp& test_get();
+ /// Return instructions executed if condition is true.
+ const Exp& thenclause_get() const;
+ /// Return instructions executed if condition is true.
+ Exp& thenclause_get();
+ /// Return instructions executed if condition is false.
+ const Exp& elseclause_get() const;
+ /// Return instructions executed if condition is false.
+ Exp& elseclause_get();
+ /** \} */
+
+ protected:
+ /// Condition.
+ Exp* test_;
+ /// Instructions executed if condition is true.
+ Exp* thenclause_;
+ /// Instructions executed if condition is false.
+ Exp* elseclause_;
+ };
+} // namespace ast
+#include <ast/if-exp.hxx>
diff --git a/tiger-compiler/src/ast/if-exp.hxx b/tiger-compiler/src/ast/if-exp.hxx
new file mode 100644
index 0000000..7b6cb07
--- /dev/null
+++ b/tiger-compiler/src/ast/if-exp.hxx
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/if-exp.hxx
+ ** \brief Inline methods of ast::IfExp.
+ */
+
+#pragma once
+
+#include <ast/if-exp.hh>
+
+namespace ast
+{
+
+ inline const Exp& IfExp::test_get() const { return *test_; }
+ inline Exp& IfExp::test_get() { return *test_; }
+
+ inline const Exp& IfExp::thenclause_get() const { return *thenclause_; }
+ inline Exp& IfExp::thenclause_get() { return *thenclause_; }
+
+ inline const Exp& IfExp::elseclause_get() const { return *elseclause_; }
+ inline Exp& IfExp::elseclause_get() { return *elseclause_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/int-exp.cc b/tiger-compiler/src/ast/int-exp.cc
new file mode 100644
index 0000000..e2fb992
--- /dev/null
+++ b/tiger-compiler/src/ast/int-exp.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/int-exp.cc
+ ** \brief Implementation of ast::IntExp.
+ */
+
+#include <ast/int-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ IntExp::IntExp(const Location& location, int value)
+ : Exp(location)
+ , value_(value)
+ {}
+
+ void IntExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void IntExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/int-exp.hh b/tiger-compiler/src/ast/int-exp.hh
new file mode 100644
index 0000000..a15bdf0
--- /dev/null
+++ b/tiger-compiler/src/ast/int-exp.hh
@@ -0,0 +1,44 @@
+/**
+ ** \file ast/int-exp.hh
+ ** \brief Declaration of ast::IntExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// IntExp.
+ class IntExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an IntExp node.
+ IntExp(const Location& location, int value);
+ IntExp(const IntExp&) = delete;
+ IntExp& operator=(const IntExp&) = delete;
+ /// Destroy an IntExp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return stored integer value.
+ int value_get() const;
+ /** \} */
+
+ protected:
+ /// Stored integer value.
+ int value_;
+ };
+} // namespace ast
+#include <ast/int-exp.hxx>
diff --git a/tiger-compiler/src/ast/int-exp.hxx b/tiger-compiler/src/ast/int-exp.hxx
new file mode 100644
index 0000000..0308ba7
--- /dev/null
+++ b/tiger-compiler/src/ast/int-exp.hxx
@@ -0,0 +1,15 @@
+/**
+ ** \file ast/int-exp.hxx
+ ** \brief Inline methods of ast::IntExp.
+ */
+
+#pragma once
+
+#include <ast/int-exp.hh>
+
+namespace ast
+{
+
+ inline int IntExp::value_get() const { return value_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/let-exp.cc b/tiger-compiler/src/ast/let-exp.cc
new file mode 100644
index 0000000..0ded46b
--- /dev/null
+++ b/tiger-compiler/src/ast/let-exp.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/let-exp.cc
+ ** \brief Implementation of ast::LetExp.
+ */
+
+#include <ast/let-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ LetExp::LetExp(const Location& location, ChunkList* chunks, Exp* body)
+ : Exp(location)
+ , chunks_(chunks)
+ , body_(body)
+ {}
+
+ LetExp::~LetExp()
+ {
+ delete chunks_;
+ delete body_;
+ }
+
+ void LetExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void LetExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/let-exp.hh b/tiger-compiler/src/ast/let-exp.hh
new file mode 100644
index 0000000..7955eeb
--- /dev/null
+++ b/tiger-compiler/src/ast/let-exp.hh
@@ -0,0 +1,55 @@
+/**
+ ** \file ast/let-exp.hh
+ ** \brief Declaration of ast::LetExp.
+ */
+
+#pragma once
+
+#include <ast/chunk-list.hh>
+#include <ast/exp.hh>
+#include <misc/contract.hh>
+
+namespace ast
+{
+ /// LetExp.
+ class LetExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a LetExp node.
+ LetExp(const Location& location, ChunkList* chunks, Exp* body);
+ LetExp(const LetExp&) = delete;
+ LetExp& operator=(const LetExp&) = delete;
+ /// Destroy a LetExp node.
+ ~LetExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return list of declarations.
+ const ChunkList& chunks_get() const;
+ /// Return list of declarations.
+ ChunkList& chunks_get();
+ /// Return list of instructions.
+ const Exp& body_get() const;
+ /// Return list of instructions.
+ Exp& body_get();
+ /** \} */
+
+ protected:
+ /// List of declarations.
+ ChunkList* chunks_;
+ /// List of instructions.
+ Exp* body_;
+ };
+} // namespace ast
+#include <ast/let-exp.hxx>
diff --git a/tiger-compiler/src/ast/let-exp.hxx b/tiger-compiler/src/ast/let-exp.hxx
new file mode 100644
index 0000000..9d6589c
--- /dev/null
+++ b/tiger-compiler/src/ast/let-exp.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/let-exp.hxx
+ ** \brief Inline methods of ast::LetExp.
+ */
+
+#pragma once
+
+#include <ast/let-exp.hh>
+
+namespace ast
+{
+
+ inline const ChunkList& LetExp::chunks_get() const { return *chunks_; }
+ inline ChunkList& LetExp::chunks_get() { return *chunks_; }
+
+ inline const Exp& LetExp::body_get() const { return *body_; }
+ inline Exp& LetExp::body_get() { return *body_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/libast.cc b/tiger-compiler/src/ast/libast.cc
new file mode 100644
index 0000000..0bebaa0
--- /dev/null
+++ b/tiger-compiler/src/ast/libast.cc
@@ -0,0 +1,44 @@
+/**
+ ** \file ast/libast.cc
+ ** \brief Public ast interface implementation.
+ */
+
+#include <fstream>
+
+#include <ast/dumper-dot.hh>
+#include <ast/libast.hh>
+#include <ast/pretty-printer.hh>
+
+// Define exported ast functions.
+namespace ast
+{
+ // Making the following variables const is more than merely
+ // stylistic. If they were not, Swig will create set/get for them,
+ // and there is no set (operator=), since it has a const member.
+
+ /// xalloc slot to enable escapes display in Ast display.
+ const misc::xalloc<bool> escapes_display;
+ /// xalloc slot to enable bindings display in Ast display.
+ const misc::xalloc<bool> bindings_display;
+
+ // Print the TREE on OSTR.
+ std::ostream& operator<<(std::ostream& ostr, const Ast& tree)
+ {
+ PrettyPrinter print(ostr);
+ print(tree);
+ return ostr;
+ }
+
+ /// Dump \a a on \a ostr.
+ std::ostream& dump_dot(const Ast& tree, std::ostream& ostr)
+ {
+ DumperDot dump_dot(ostr);
+ ostr << misc::resetindent << "digraph structs {" << misc::incendl;
+ ostr << "splines=line;" << misc::iendl;
+ ostr << "node [shape=plaintext]" << misc::iendl;
+ dump_dot(tree);
+ ostr << misc::decendl << "}" << misc::iendl;
+ return ostr;
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/libast.hh b/tiger-compiler/src/ast/libast.hh
new file mode 100644
index 0000000..121749d
--- /dev/null
+++ b/tiger-compiler/src/ast/libast.hh
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/libast.hh
+ ** \brief Public ast interface declaration.
+ */
+
+#pragma once
+
+#include <iosfwd>
+
+#include <misc/xalloc.hh>
+
+#include <ast/fwd.hh>
+
+/// Ast management.
+namespace ast
+{
+ extern const misc::xalloc<bool> escapes_display;
+ extern const misc::xalloc<bool> bindings_display;
+
+ /// Output \a a on \a ostr.
+ std::ostream& operator<<(std::ostream& ostr, const Ast& tree);
+
+ /// Dump \a a on \a ostr.
+ std::ostream& dump_dot(const Ast& tree, std::ostream& ostr);
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/local.am b/tiger-compiler/src/ast/local.am
new file mode 100644
index 0000000..1e520c5
--- /dev/null
+++ b/tiger-compiler/src/ast/local.am
@@ -0,0 +1,30 @@
+ast_basedir = src/ast/
+ast_srcdir = $(srcdir)/%D%
+# Don't use ast_srcdir in the include, otherwise Automake can't resolve it.
+include $(srcdir)/%D%/ast-nodes.mk
+
+
+src_libtc_la_SOURCES += \
+ %D%/location.hh \
+ %D%/all.hh \
+ %D%/chunk-interface.hh %D%/chunk-interface.hxx \
+ %D%/chunk.hh %D%/chunk.hxx \
+ %D%/fwd.hh \
+ %D%/visitor.hh \
+ $(AST_NODES) \
+ %D%/default-visitor.hh %D%/default-visitor.hxx \
+ %D%/dumper-dot.hh %D%/dumper-dot.hxx %D%/dumper-dot.cc \
+ %D%/non-object-visitor.hh %D%/non-object-visitor.hxx \
+ %D%/non-assert-visitor.hh %D%/non-assert-visitor.hxx \
+ %D%/object-visitor.hh %D%/object-visitor.hxx \
+ %D%/assert-visitor.hh %D%/assert-visitor.hxx \
+ %D%/pretty-printer.hh %D%/pretty-printer.cc \
+ %D%/visitor.hxx \
+ %D%/libast.hh %D%/libast.cc
+
+dist_noinst_DATA += %D%/README.txt
+
+check_PROGRAMS += %D%/test-ast
+%C%_test_ast_LDADD = src/libtc.la
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/ast/location.hh b/tiger-compiler/src/ast/location.hh
new file mode 100644
index 0000000..9e6e398
--- /dev/null
+++ b/tiger-compiler/src/ast/location.hh
@@ -0,0 +1,14 @@
+/**
+ ** \file ast/location.hh
+ ** \brief Definition of ast::Location.
+ */
+
+#pragma once
+
+#include <misc/symbol.hh>
+#include <parse/location.hh>
+
+namespace ast
+{
+ using Location = parse::location;
+}
diff --git a/tiger-compiler/src/ast/method-call-exp.cc b/tiger-compiler/src/ast/method-call-exp.cc
new file mode 100644
index 0000000..bdf1f41
--- /dev/null
+++ b/tiger-compiler/src/ast/method-call-exp.cc
@@ -0,0 +1,24 @@
+/**
+ ** \file ast/method-call-exp.cc
+ ** \brief Implementation of ast::MethodCallExp.
+ */
+
+#include <ast/method-call-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ MethodCallExp::MethodCallExp(const Location& location,
+ misc::symbol name,
+ exps_type* args,
+ Var* object)
+ : CallExp(location, name, args)
+ , object_(object)
+ {}
+
+ MethodCallExp::~MethodCallExp() { delete object_; }
+
+ void MethodCallExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void MethodCallExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/method-call-exp.hh b/tiger-compiler/src/ast/method-call-exp.hh
new file mode 100644
index 0000000..ef728d9
--- /dev/null
+++ b/tiger-compiler/src/ast/method-call-exp.hh
@@ -0,0 +1,70 @@
+/**
+ ** \file ast/method-call-exp.hh
+ ** \brief Declaration of ast::MethodCallExp.
+ */
+
+#pragma once
+
+#include <ast/call-exp.hh>
+#include <ast/method-dec.hh>
+#include <ast/var.hh>
+
+namespace ast
+{
+ /** \class ast::MethodCallExp
+ ** \brief Method call.
+ **
+ ** A method call is \em not a function call in the strict sense
+ ** of object-oriented programming. Inheritance is used as a
+ ** factoring tool here.
+ */
+
+ class MethodCallExp : public CallExp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a MethodCallExp node.
+ MethodCallExp(const Location& location,
+ misc::symbol name,
+ exps_type* args,
+ Var* object);
+ MethodCallExp(const MethodCallExp&) = delete;
+ MethodCallExp& operator=(const MethodCallExp&) = delete;
+ /// Destroy a MethodCallExp node.
+ ~MethodCallExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the object on which the method is called.
+ const Var& object_get() const;
+ /// Return the object on which the method is called.
+ Var& object_get();
+ // FIXME DONE: Some code was deleted here.
+ /// Return definition site.
+ const MethodDec* def_get() const;
+ MethodDec* def_get();
+
+ // FIXME DONE: Some code was deleted here.
+ /// Set definition site.
+ void def_set(MethodDec*);
+
+ /** \} */
+
+ protected:
+ /// The object on which the method is called.
+ Var* object_;
+ /// Definition site.
+ MethodDec* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/method-call-exp.hxx>
diff --git a/tiger-compiler/src/ast/method-call-exp.hxx b/tiger-compiler/src/ast/method-call-exp.hxx
new file mode 100644
index 0000000..fa49ca9
--- /dev/null
+++ b/tiger-compiler/src/ast/method-call-exp.hxx
@@ -0,0 +1,21 @@
+/**
+ ** \file ast/method-call-exp.hxx
+ ** \brief Inline methods of ast::MethodCallExp.
+ */
+
+#pragma once
+
+#include <ast/method-call-exp.hh>
+
+namespace ast
+{
+
+ inline const Var& MethodCallExp::object_get() const { return *object_; }
+ inline Var& MethodCallExp::object_get() { return *object_; }
+
+ // FIXME DONE: Some code was deleted here.
+ inline const MethodDec* MethodCallExp::def_get() const { return def_; }
+ inline MethodDec* MethodCallExp::def_get() { return def_; }
+ // FIXME DONE: Some code was deleted here.
+ inline void MethodCallExp::def_set(MethodDec* def) { def_ = def; }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/method-dec.cc b/tiger-compiler/src/ast/method-dec.cc
new file mode 100644
index 0000000..36f07d7
--- /dev/null
+++ b/tiger-compiler/src/ast/method-dec.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/method-dec.cc
+ ** \brief Implementation of ast::MethodDec.
+ */
+
+#include <ast/method-dec.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ MethodDec::MethodDec(const Location& location,
+ misc::symbol name,
+ VarChunk* formals,
+ NameTy* result,
+ Exp* body)
+ : FunctionDec(location, name, formals, result, body)
+ {}
+
+ void MethodDec::accept(ConstVisitor& v) const { v(*this); }
+
+ void MethodDec::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/method-dec.hh b/tiger-compiler/src/ast/method-dec.hh
new file mode 100644
index 0000000..d91cfd8
--- /dev/null
+++ b/tiger-compiler/src/ast/method-dec.hh
@@ -0,0 +1,45 @@
+/**
+ ** \file ast/method-dec.hh
+ ** \brief Declaration of ast::MethodDec.
+ */
+
+#pragma once
+
+#include <ast/function-dec.hh>
+
+namespace ast
+{
+ /** \class ast::MethodDec
+ ** \brief Method declaration.
+ **
+ ** A method declaration is \em not a function in the strict
+ ** sense of object-oriented programming. Inheritance is used
+ ** as a factoring tool here.
+ */
+
+ class MethodDec : public FunctionDec
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a MethodDec node.
+ MethodDec(const Location& location,
+ misc::symbol name,
+ VarChunk* formals,
+ NameTy* result,
+ Exp* body);
+ MethodDec(const MethodDec&) = delete;
+ MethodDec& operator=(const MethodDec&) = delete;
+ /// Destroy a MethodDec node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+ };
+} // namespace ast
+#include <ast/method-dec.hxx>
diff --git a/tiger-compiler/src/ast/method-dec.hxx b/tiger-compiler/src/ast/method-dec.hxx
new file mode 100644
index 0000000..2c75af3
--- /dev/null
+++ b/tiger-compiler/src/ast/method-dec.hxx
@@ -0,0 +1,11 @@
+/**
+ ** \file ast/method-dec.hxx
+ ** \brief Inline methods of ast::MethodDec.
+ */
+
+#pragma once
+
+#include <ast/method-dec.hh>
+
+namespace ast
+{} // namespace ast
diff --git a/tiger-compiler/src/ast/name-ty.cc b/tiger-compiler/src/ast/name-ty.cc
new file mode 100644
index 0000000..96610bb
--- /dev/null
+++ b/tiger-compiler/src/ast/name-ty.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/name-ty.cc
+ ** \brief Implementation of ast::NameTy.
+ */
+
+#include <ast/name-ty.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ NameTy::NameTy(const Location& location, misc::symbol name)
+ : Ty(location)
+ , name_(name)
+ {}
+
+ void NameTy::accept(ConstVisitor& v) const { v(*this); }
+
+ void NameTy::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/name-ty.hh b/tiger-compiler/src/ast/name-ty.hh
new file mode 100644
index 0000000..de08848
--- /dev/null
+++ b/tiger-compiler/src/ast/name-ty.hh
@@ -0,0 +1,56 @@
+/**
+ ** \file ast/name-ty.hh
+ ** \brief Declaration of ast::NameTy.
+ */
+
+#pragma once
+
+#include <ast/ty.hh>
+#include <ast/type-dec.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// NameTy.
+ class NameTy : public Ty
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a NameTy node.
+ NameTy(const Location& location, misc::symbol name);
+ NameTy(const NameTy&) = delete;
+ NameTy& operator=(const NameTy&) = delete;
+ /// Destroy a NameTy node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the name of the type.
+ misc::symbol name_get() const;
+ /// Set the name of the type.
+ void name_set(misc::symbol);
+ /// Return definition site.
+ const TypeDec* def_get() const;
+ /// Return definition site.
+ TypeDec* def_get();
+ /// Set definition site.
+ void def_set(TypeDec*);
+ /** \} */
+
+ protected:
+ /// The name of the type.
+ misc::symbol name_;
+ /// Definition site.
+ TypeDec* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/name-ty.hxx>
diff --git a/tiger-compiler/src/ast/name-ty.hxx b/tiger-compiler/src/ast/name-ty.hxx
new file mode 100644
index 0000000..d93b383
--- /dev/null
+++ b/tiger-compiler/src/ast/name-ty.hxx
@@ -0,0 +1,20 @@
+/**
+ ** \file ast/name-ty.hxx
+ ** \brief Inline methods of ast::NameTy.
+ */
+
+#pragma once
+
+#include <ast/name-ty.hh>
+
+namespace ast
+{
+
+ inline misc::symbol NameTy::name_get() const { return name_; }
+ inline void NameTy::name_set(misc::symbol name) { name_ = name; }
+
+ inline const TypeDec* NameTy::def_get() const { return def_; }
+ inline TypeDec* NameTy::def_get() { return def_; }
+ inline void NameTy::def_set(TypeDec* def) { def_ = def; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/nil-exp.cc b/tiger-compiler/src/ast/nil-exp.cc
new file mode 100644
index 0000000..f51c442
--- /dev/null
+++ b/tiger-compiler/src/ast/nil-exp.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/nil-exp.cc
+ ** \brief Implementation of ast::NilExp.
+ */
+
+#include <ast/nil-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ NilExp::NilExp(const Location& location)
+ : Exp(location)
+ , TypeConstructor()
+ {}
+
+ void NilExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void NilExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/nil-exp.hh b/tiger-compiler/src/ast/nil-exp.hh
new file mode 100644
index 0000000..c526b4b
--- /dev/null
+++ b/tiger-compiler/src/ast/nil-exp.hh
@@ -0,0 +1,37 @@
+/**
+ ** \file ast/nil-exp.hh
+ ** \brief Declaration of ast::NilExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/type-constructor.hh>
+
+namespace ast
+{
+ /// NilExp.
+ class NilExp
+ : public Exp
+ , public TypeConstructor
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a NilExp node.
+ explicit NilExp(const Location& location);
+ NilExp(const NilExp&) = delete;
+ NilExp& operator=(const NilExp&) = delete;
+ /// Destroy a NilExp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+ };
+} // namespace ast
+#include <ast/nil-exp.hxx>
diff --git a/tiger-compiler/src/ast/nil-exp.hxx b/tiger-compiler/src/ast/nil-exp.hxx
new file mode 100644
index 0000000..8d13ae6
--- /dev/null
+++ b/tiger-compiler/src/ast/nil-exp.hxx
@@ -0,0 +1,11 @@
+/**
+ ** \file ast/nil-exp.hxx
+ ** \brief Inline methods of ast::NilExp.
+ */
+
+#pragma once
+
+#include <ast/nil-exp.hh>
+
+namespace ast
+{} // namespace ast
diff --git a/tiger-compiler/src/ast/non-assert-visitor.hh b/tiger-compiler/src/ast/non-assert-visitor.hh
new file mode 100644
index 0000000..383768a
--- /dev/null
+++ b/tiger-compiler/src/ast/non-assert-visitor.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file ast/object-visitor.hh
+ ** \brief Provide default visits for assertion nodes.
+ */
+
+#pragma once
+
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ class GenNonAssertVisitor : virtual public GenVisitor<Const>
+ {
+ public:
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an object visitor.
+ GenNonAssertVisitor();
+ /// Destroy an object visitor.
+ virtual ~GenNonAssertVisitor();
+ /** \} */
+
+ /// \name Object-related visits.
+ /// \{
+ void operator()(const_t<AssertExp>& e) override;
+ /// \}
+ };
+
+ /// Shorthand for a const visitor.
+ using NonAssertConstVisitor = GenNonAssertVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using NonAssertVisitor = GenNonAssertVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ %template(AssertNonConstVisitor) GenNonAssertVisitor<misc::constify_traits>;
+ %template(AssertNonVisitor) GenNonAssertVisitor<misc::id_traits>;
+#endif
+
+} // namespace ast
+
+#include <ast/non-assert-visitor.hxx>
diff --git a/tiger-compiler/src/ast/non-assert-visitor.hxx b/tiger-compiler/src/ast/non-assert-visitor.hxx
new file mode 100644
index 0000000..dd0990d
--- /dev/null
+++ b/tiger-compiler/src/ast/non-assert-visitor.hxx
@@ -0,0 +1,34 @@
+/**
+ ** \file ast/assert-visitor.hxx
+ ** \brief Implementation for ast/assert-visitor.hh.
+ */
+
+#pragma once
+
+#include <ast/assert-exp.hh>
+#include <ast/assert-visitor.hh>
+#include <misc/contract.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ GenNonAssertVisitor<Const>::GenNonAssertVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenNonAssertVisitor<Const>::~GenNonAssertVisitor()
+ {}
+
+ /*-------------------------------.
+ | Assert-related visit method. |
+ `-------------------------------*/
+
+ template <template <typename> class Const>
+ void GenNonAssertVisitor<Const>::operator()(const_t<AssertExp>&)
+ {
+ // We must not be here (there should be no assert feature in plain Tiger).
+ unreachable();
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/non-object-visitor.hh b/tiger-compiler/src/ast/non-object-visitor.hh
new file mode 100644
index 0000000..c3fcf1a
--- /dev/null
+++ b/tiger-compiler/src/ast/non-object-visitor.hh
@@ -0,0 +1,92 @@
+/**
+ ** \file ast/non-object-visitor.hh
+ ** \brief Provide aborting visits for object-related nodes.
+ */
+
+#pragma once
+
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ /** GenNonObjectVisitor<CONSTNESS-SELECTOR> provides aborting visit
+ methods for object-related nodes. This class is meant to factor
+ the code visiting object-related nodes in visitors bound to
+ process AST \em without objects.
+
+ ast::GenNonObjectVisitor inherits virtually from ast::GenVisitor
+ to allow diamond inheritance, notably for a ``compatibility''
+ purpose with ast::GenDefaultVisitor.
+
+ For instance, type::TypeChecker, a visitor that checks the types
+ of an AST without objects, inherits from ast::DefaultVisitor to
+ factor default (``empty'') traversal implementations, and from
+ ast::NonObjectVisitor to get an aborting behavior for
+ object-related nodes.
+
+ \verbatim
+
+ /ast::Visitor/
+ ^
+ (virtual) | (virtual)
+ ,--------------+--------------.
+ | |
+ | |
+ /ast::DefaultVisitor/ /ast::NonObjectVisitor/
+ ^ ^
+ | |
+ `--------------+--------------'
+ |
+ |
+ type::TypeChecker
+
+ \endverbatim
+ */
+ template <template <typename> class Const>
+ class GenNonObjectVisitor : virtual public GenVisitor<Const>
+ {
+ public:
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a non-object visitor.
+ GenNonObjectVisitor();
+ /// Destroy a non-object visitor.
+ virtual ~GenNonObjectVisitor();
+ /** \} */
+
+ /// \name Object-related visits.
+ ///
+ /// The methods should not be used, since this visitor is for the
+ /// non-object flavor of the language.
+ /// \{
+ void operator()(const_t<ClassTy>& e) override;
+
+ void operator()(const_t<MethodChunk>& e) override;
+ void operator()(const_t<MethodDec>& e) override;
+
+ void operator()(const_t<MethodCallExp>& e) override;
+ void operator()(const_t<ObjectExp>& e) override;
+ /// \}
+ };
+
+ /// Shorthand for a const visitor.
+ using NonObjectConstVisitor = GenNonObjectVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using NonObjectVisitor = GenNonObjectVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ %template(NonObjectConstVisitor) GenNonObjectVisitor<misc::constify_traits>;
+ %template(NonObjectVisitor) GenNonObjectVisitor<misc::id_traits>;
+#endif
+} // namespace ast
+
+#include <ast/non-object-visitor.hxx>
diff --git a/tiger-compiler/src/ast/non-object-visitor.hxx b/tiger-compiler/src/ast/non-object-visitor.hxx
new file mode 100644
index 0000000..8d49932
--- /dev/null
+++ b/tiger-compiler/src/ast/non-object-visitor.hxx
@@ -0,0 +1,62 @@
+/**
+ ** \file ast/non-object-visitor.hxx
+ ** \brief Implementation for ast/non-object-visitor.hh.
+ */
+
+#pragma once
+
+#include <ast/all.hh>
+#include <ast/non-object-visitor.hh>
+#include <misc/contract.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ GenNonObjectVisitor<Const>::GenNonObjectVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenNonObjectVisitor<Const>::~GenNonObjectVisitor()
+ {}
+
+ /*-----------------------------------------.
+ | Object-related visit methods, disabled. |
+ `-----------------------------------------*/
+
+ template <template <typename> class Const>
+ void GenNonObjectVisitor<Const>::operator()(const_t<ClassTy>&)
+ {
+ // We must not be here (there should be no object feature in plain Tiger).
+ unreachable();
+ }
+
+ template <template <typename> class Const>
+ void GenNonObjectVisitor<Const>::operator()(const_t<MethodChunk>&)
+ {
+ // We must not be here (there should be no object feature in plain Tiger).
+ unreachable();
+ }
+
+ template <template <typename> class Const>
+ void GenNonObjectVisitor<Const>::operator()(const_t<MethodDec>&)
+ {
+ // We must not be here (there should be no object feature in plain Tiger).
+ unreachable();
+ }
+
+ template <template <typename> class Const>
+ void GenNonObjectVisitor<Const>::operator()(const_t<MethodCallExp>&)
+ {
+ // We must not be here (there should be no object feature in plain Tiger).
+ unreachable();
+ }
+
+ template <template <typename> class Const>
+ void GenNonObjectVisitor<Const>::operator()(const_t<ObjectExp>&)
+ {
+ // We must not be here (there should be no object feature in plain Tiger).
+ unreachable();
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/object-exp.cc b/tiger-compiler/src/ast/object-exp.cc
new file mode 100644
index 0000000..c2d5808
--- /dev/null
+++ b/tiger-compiler/src/ast/object-exp.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/object-exp.cc
+ ** \brief Implementation of ast::ObjectExp.
+ */
+
+#include <ast/object-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ ObjectExp::ObjectExp(const Location& location, NameTy* type_name)
+ : Exp(location)
+ , type_name_(type_name)
+ {}
+
+ void ObjectExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void ObjectExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/object-exp.hh b/tiger-compiler/src/ast/object-exp.hh
new file mode 100644
index 0000000..efab0a5
--- /dev/null
+++ b/tiger-compiler/src/ast/object-exp.hh
@@ -0,0 +1,47 @@
+/**
+ ** \file ast/object-exp.hh
+ ** \brief Declaration of ast::ObjectExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/name-ty.hh>
+
+namespace ast
+{
+ /// ObjectExp.
+ class ObjectExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an ObjectExp node.
+ ObjectExp(const Location& location, NameTy* type_name);
+ ObjectExp(const ObjectExp&) = delete;
+ ObjectExp& operator=(const ObjectExp&) = delete;
+ /// Destroy an ObjectExp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return name of the class from which the object is instantiated.
+ const NameTy& type_name_get() const;
+ /// Return name of the class from which the object is instantiated.
+ NameTy& type_name_get();
+ /** \} */
+
+ protected:
+ /// Name of the class from which the object is instantiated.
+ NameTy* type_name_;
+ };
+} // namespace ast
+#include <ast/object-exp.hxx>
diff --git a/tiger-compiler/src/ast/object-exp.hxx b/tiger-compiler/src/ast/object-exp.hxx
new file mode 100644
index 0000000..38fd5f6
--- /dev/null
+++ b/tiger-compiler/src/ast/object-exp.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/object-exp.hxx
+ ** \brief Inline methods of ast::ObjectExp.
+ */
+
+#pragma once
+
+#include <ast/object-exp.hh>
+
+namespace ast
+{
+
+ inline const NameTy& ObjectExp::type_name_get() const { return *type_name_; }
+ inline NameTy& ObjectExp::type_name_get() { return *type_name_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/object-visitor.hh b/tiger-compiler/src/ast/object-visitor.hh
new file mode 100644
index 0000000..b14c829
--- /dev/null
+++ b/tiger-compiler/src/ast/object-visitor.hh
@@ -0,0 +1,89 @@
+/**
+ ** \file ast/object-visitor.hh
+ ** \brief Provide default visits for object-related nodes.
+ */
+
+#pragma once
+
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ /** GenObjectVisitor<CONSTNESS-SELECTOR> provides default visit
+ methods for object-related nodes. This class is meant to factor
+ the code visiting object-related nodes.
+
+ ast::GenObjectVisitor inherits virtually from ast::GenVisitor
+ to allow diamond inheritance, notably for a ``compatibility''
+ purpose with ast::GenDefaultVisitor.
+
+ For instance, bind::Binder, a visitor that handles bindings for
+ an AST without objects, inherits from ast::DefaultVisitor to
+ factor default (``empty'') traversal implementations for
+ non-object-related nodes, and from ast::ObjectVisitor for
+ object-related nodes.
+
+ \verbatim
+
+ /ast::Visitor/
+ ^
+ (virtual) | (virtual)
+ ,--------------+--------------.
+ | |
+ | |
+ /ast::DefaultVisitor/ /ast::ObjectVisitor/
+ ^ ^
+ | |
+ `--------------+--------------'
+ |
+ |
+ bind::Binder
+
+ \endverbatim
+ */
+ template <template <typename> class Const>
+ class GenObjectVisitor : virtual public GenVisitor<Const>
+ {
+ public:
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an object visitor.
+ GenObjectVisitor();
+ /// Destroy an object visitor.
+ virtual ~GenObjectVisitor();
+ /** \} */
+
+ /// \name Object-related visits.
+ /// \{
+ void operator()(const_t<ClassTy>& e) override;
+
+ void operator()(const_t<MethodChunk>& e) override;
+ void operator()(const_t<MethodDec>& e) override;
+
+ void operator()(const_t<MethodCallExp>& e) override;
+ void operator()(const_t<ObjectExp>& e) override;
+ /// \}
+ };
+
+ /// Shorthand for a const visitor.
+ using ObjectConstVisitor = GenObjectVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using ObjectVisitor = GenObjectVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ %template(ObjectConstVisitor) GenObjectVisitor<misc::constify_traits>;
+ %template(ObjectVisitor) GenObjectVisitor<misc::id_traits>;
+#endif
+
+} // namespace ast
+
+#include <ast/object-visitor.hxx>
diff --git a/tiger-compiler/src/ast/object-visitor.hxx b/tiger-compiler/src/ast/object-visitor.hxx
new file mode 100644
index 0000000..c4eccbb
--- /dev/null
+++ b/tiger-compiler/src/ast/object-visitor.hxx
@@ -0,0 +1,69 @@
+/**
+ ** \file ast/object-visitor.hxx
+ ** \brief Implementation for ast/object-visitor.hh.
+ */
+
+#pragma once
+
+#include <ast/all.hh>
+#include <ast/object-visitor.hh>
+#include <misc/contract.hh>
+
+namespace ast
+{
+ template <template <typename> class Const>
+ GenObjectVisitor<Const>::GenObjectVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenObjectVisitor<Const>::~GenObjectVisitor()
+ {}
+
+ /*-------------------------------.
+ | Object-related visit methods. |
+ `-------------------------------*/
+
+ template <template <typename> class Const>
+ void GenObjectVisitor<Const>::operator()(const_t<ClassTy>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.chunks_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenObjectVisitor<Const>::operator()(const_t<MethodChunk>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (const auto dec : e)
+ dec->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenObjectVisitor<Const>::operator()(const_t<MethodDec>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.formals_get().accept(*this);
+ if (e.result_get() != nullptr)
+ e.result_get()->accept(*this);
+ if (e.body_get() != nullptr)
+ e.body_get()->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenObjectVisitor<Const>::operator()(const_t<MethodCallExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.object_get().accept(*this);
+ for (auto arg : e.args_get())
+ arg->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenObjectVisitor<Const>::operator()(const_t<ObjectExp>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.type_name_get().accept(*this);
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/op-exp.cc b/tiger-compiler/src/ast/op-exp.cc
new file mode 100644
index 0000000..6db4940
--- /dev/null
+++ b/tiger-compiler/src/ast/op-exp.cc
@@ -0,0 +1,42 @@
+/**
+ ** \file ast/op-exp.cc
+ ** \brief Implementation of ast::OpExp.
+ */
+
+#include <ast/op-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ OpExp::OpExp(const Location& location,
+ Exp* left,
+ OpExp::Oper oper,
+ Exp* right)
+ : Exp(location)
+ , left_(left)
+ , oper_(oper)
+ , right_(right)
+ {}
+
+ OpExp::~OpExp()
+ {
+ delete left_;
+ delete right_;
+ }
+
+ void OpExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void OpExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
+
+std::string str(ast::OpExp::Oper oper)
+{
+ static const std::unordered_map<ast::OpExp::Oper, std::string> op_str = {
+ {ast::OpExp::Oper::add, "+"}, {ast::OpExp::Oper::sub, "-"},
+ {ast::OpExp::Oper::mul, "*"}, {ast::OpExp::Oper::div, "/"},
+ {ast::OpExp::Oper::eq, "="}, {ast::OpExp::Oper::ne, "<>"},
+ {ast::OpExp::Oper::lt, "<"}, {ast::OpExp::Oper::le, "<="},
+ {ast::OpExp::Oper::gt, ">"}, {ast::OpExp::Oper::ge, ">="}};
+
+ return op_str.at(oper);
+}
diff --git a/tiger-compiler/src/ast/op-exp.hh b/tiger-compiler/src/ast/op-exp.hh
new file mode 100644
index 0000000..372650f
--- /dev/null
+++ b/tiger-compiler/src/ast/op-exp.hh
@@ -0,0 +1,80 @@
+/**
+ ** \file ast/op-exp.hh
+ ** \brief Declaration of ast::OpExp.
+ */
+
+#pragma once
+
+#include <unordered_map>
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// OpExp.
+ class OpExp : public Exp
+ {
+ public:
+ /// Operator qualifier.
+ enum class Oper
+ {
+ // Arithmetics.
+ /** \brief "+" */ add,
+ /** \brief "-" */ sub,
+ /** \brief "*" */ mul,
+ /** \brief "/" */ div,
+
+ // Comparison.
+ /** \brief "=" */ eq,
+ /** \brief "<>" */ ne,
+ /** \brief "<" */ lt,
+ /** \brief "<=" */ le,
+ /** \brief ">" */ gt,
+ /** \brief ">=" */ ge
+ };
+
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct an OpExp node.
+ OpExp(const Location& location, Exp* left, OpExp::Oper oper, Exp* right);
+ OpExp(const OpExp&) = delete;
+ OpExp& operator=(const OpExp&) = delete;
+ /// Destroy an OpExp node.
+ ~OpExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return left operand.
+ const Exp& left_get() const;
+ /// Return left operand.
+ Exp& left_get();
+ /// Return operator.
+ OpExp::Oper oper_get() const;
+ /// Return right operand.
+ const Exp& right_get() const;
+ /// Return right operand.
+ Exp& right_get();
+ /** \} */
+
+ protected:
+ /// Left operand.
+ Exp* left_;
+ /// Operator.
+ OpExp::Oper oper_;
+ /// Right operand.
+ Exp* right_;
+ };
+} // namespace ast
+
+// Return a representation of an operator.
+std::string str(ast::OpExp::Oper oper);
+#include <ast/op-exp.hxx>
diff --git a/tiger-compiler/src/ast/op-exp.hxx b/tiger-compiler/src/ast/op-exp.hxx
new file mode 100644
index 0000000..a665c3a
--- /dev/null
+++ b/tiger-compiler/src/ast/op-exp.hxx
@@ -0,0 +1,21 @@
+/**
+ ** \file ast/op-exp.hxx
+ ** \brief Inline methods of ast::OpExp.
+ */
+
+#pragma once
+
+#include <ast/op-exp.hh>
+
+namespace ast
+{
+
+ inline const Exp& OpExp::left_get() const { return *left_; }
+ inline Exp& OpExp::left_get() { return *left_; }
+
+ inline OpExp::Oper OpExp::oper_get() const { return oper_; }
+
+ inline const Exp& OpExp::right_get() const { return *right_; }
+ inline Exp& OpExp::right_get() { return *right_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/pretty-printer.cc b/tiger-compiler/src/ast/pretty-printer.cc
new file mode 100644
index 0000000..91dbc87
--- /dev/null
+++ b/tiger-compiler/src/ast/pretty-printer.cc
@@ -0,0 +1,419 @@
+/**
+ ** \file ast/pretty-printer.cc
+ ** \brief Implementation of ast::PrettyPrinter.
+ */
+
+#include <ast/all.hh>
+#include <ast/libast.hh>
+#include <ast/pretty-printer.hh>
+#include <misc/escape.hh>
+#include <misc/indent.hh>
+#include <misc/separator.hh>
+
+#include <type/class.hh>
+
+namespace ast
+{
+ // Anonymous namespace: these functions are private to this file.
+ namespace
+ {
+ /// Output \a e on \a ostr.
+ inline std::ostream& operator<<(std::ostream& ostr, const Escapable& e)
+ {
+ if (escapes_display(ostr)
+ // FIXME DONE: Some code was deleted here.
+ && e.escape_get())
+ ostr << "/* escaping */ ";
+
+ return ostr;
+ }
+
+ /// \brief Output \a e on \a ostr.
+ ///
+ /// Used to factor the output of the name declared,
+ /// and its possible additional attributes.
+ inline std::ostream& operator<<(std::ostream& ostr, const Dec& e)
+ {
+ ostr << e.name_get();
+ if (bindings_display(ostr))
+ ostr << " /* " << &e << " */";
+ return ostr;
+ }
+ } // namespace
+
+ PrettyPrinter::PrettyPrinter(std::ostream& ostr)
+ : ostr_(ostr)
+ {}
+
+ void PrettyPrinter::operator()(const SimpleVar& e)
+ {
+ ostr_ << e.name_get();
+ if (bindings_display(ostr_))
+ ostr_ << " /* " << e.def_get() << " */";
+ }
+
+ void PrettyPrinter::operator()(const FieldVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << e.var_get() << "." << e.name_get();
+ }
+
+ /* Foo[10]. */
+ void PrettyPrinter::operator()(const SubscriptVar& e)
+ {
+ ostr_ << e.var_get() << '[' << misc::incindent << e.index_get()
+ << misc::decindent << ']';
+ }
+
+ void PrettyPrinter::operator()(const CastExp& e)
+ {
+ ostr_ << "_cast(" << e.exp_get() << ", " << e.ty_get() << ')';
+ }
+
+ // FIXME DONE: Some code was deleted here.
+ void PrettyPrinter::operator()(const NilExp&) { ostr_ << "nil"; }
+ void PrettyPrinter::operator()(const IntExp& e) { ostr_ << e.value_get(); }
+ void PrettyPrinter::operator()(const StringExp& e)
+ {
+ ostr_ << "\"" << misc::escape(e.value_get()) << "\"";
+ }
+
+ void PrettyPrinter::operator()(const ObjectExp& e)
+ {
+ ostr_ << "new " << e.type_name_get();
+ if (bindings_display(ostr_))
+ ostr_ << " /* " << &e.type_name_get() << " */";
+ }
+
+ void PrettyPrinter::operator()(const CallExp& e)
+ {
+ ostr_ << e.name_get();
+ if (bindings_display(ostr_))
+ ostr_ << " /* " << e.def_get() << " */";
+ ostr_ << "(";
+ if (!e.args_get().empty())
+ {
+ ostr_ << misc::separate(e.args_get(), ", ");
+ }
+ ostr_ << ")";
+ }
+
+ void PrettyPrinter::operator()(const MethodCallExp& e)
+ {
+ ostr_ << e.object_get() << "." << e.name_get();
+ if (bindings_display(ostr_))
+ ostr_ << " /* " << e.def_get() << " */";
+ ostr_ << "(";
+ if (!e.args_get().empty())
+ {
+ ostr_ << misc::separate(e.args_get(), ", ");
+ }
+ ostr_ << ")";
+ }
+
+ void PrettyPrinter::operator()(const OpExp& e)
+ {
+ ostr_ << e.left_get() << " " << str(e.oper_get()) << " " << e.right_get();
+ }
+
+ void PrettyPrinter::operator()(const RecordExp& e)
+ {
+ ostr_ << e.type_name_get();
+
+ ostr_ << " { ";
+ if (!e.fields_get().empty())
+ {
+ ostr_ << misc::separate(e.fields_get(), ", ");
+ }
+ ostr_ << " }";
+ }
+
+ void PrettyPrinter::operator()(const RecordTy& e)
+ {
+ ostr_ << "{ ";
+ if (!e.fields_get().empty())
+ {
+ ostr_ << misc::separate(e.fields_get(), ", ");
+ }
+ ostr_ << " }";
+ }
+
+ void PrettyPrinter::operator()(const ArrayTy& e)
+ {
+ ostr_ << "array of " << e.base_type_get();
+ }
+
+ void PrettyPrinter::operator()(const ClassTy& e)
+ {
+ ostr_ << "class extends " << e.super_get() << "{" << misc::decendl;
+ if (!e.chunks_get().chunks_get().empty())
+ {
+ ostr_ << misc::separate(e.chunks_get(), "\n");
+ }
+ ostr_ << " }" << misc::decendl;
+ }
+
+ void PrettyPrinter::operator()(const Field& e)
+ {
+ ostr_ << e.name_get() << " : " << e.type_name_get();
+ }
+
+ void PrettyPrinter::operator()(const SeqExp& e)
+ {
+ if (e.exps_get().size() == 0)
+ ostr_ << "()";
+ else if (e.exps_get().size() == 1)
+ ostr_ << *e.exps_get().at(0);
+ else if (e.exps_get().size() > 1)
+ {
+ ostr_ << '(' << misc::incendl << *e.exps_get().at(0);
+ for (size_t i = 1; i < e.exps_get().size(); ++i)
+ {
+ ostr_ << ";" << misc::iendl << *e.exps_get().at(i);
+ }
+ ostr_ << misc::decendl << ")";
+ }
+ }
+
+ void PrettyPrinter::operator()(const AssignExp& e)
+ {
+ ostr_ << e.var_get() << " := " << e.exp_get();
+ }
+
+ void PrettyPrinter::operator()(const IfExp& e)
+ {
+ ostr_ << "(if " << e.test_get() << " then" << misc::incendl
+ << e.thenclause_get() << misc::decendl;
+ ostr_ << "else" << misc::incendl << e.elseclause_get() << ")"
+ << misc::decendl;
+ }
+
+ void PrettyPrinter::operator()(const WhileExp& e)
+ {
+ ostr_ << "(while ";
+ if (bindings_display(ostr_))
+ {
+ ostr_ << "/* " << &e << " /* ";
+ }
+ ostr_ << e.test_get() << " do" << misc::incendl << e.body_get() << ")"
+ << misc::decendl;
+ }
+
+ void PrettyPrinter::operator()(const ForExp& e)
+ {
+ ostr_ << "(for ";
+ if (bindings_display(ostr_))
+ {
+ ostr_ << "/* " << &e << " */ ";
+ }
+ ostr_ << e.vardec_get().name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &e.vardec_get() << " */";
+ }
+ ostr_ << " := " << *e.vardec_get().init_get() << " to " << e.hi_get()
+ << " do" << misc::incendl << e.body_get() << ")";
+ }
+
+ void PrettyPrinter::operator()(const BreakExp& e)
+ {
+ ostr_ << "break";
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << e.def_get() << " */";
+ }
+ }
+
+ void PrettyPrinter::operator()(const LetExp& e)
+ {
+ ostr_ << "let" << misc::incendl << e.chunks_get() << misc::decendl << "in"
+ << misc::incendl << e.body_get() << misc::decendl << "end";
+ }
+
+ void PrettyPrinter::operator()(const ArrayExp& e)
+ {
+ ostr_ << e.type_name_get() << "[" << e.size_get() << "] of "
+ << e.init_get();
+ }
+
+ void PrettyPrinter::operator()(const FieldInit& e)
+ {
+ ostr_ << e.name_get() << " = " << e.init_get();
+ }
+
+ void PrettyPrinter::operator()(const VarChunk& e)
+ {
+ for (auto dec : e.decs_get())
+ {
+ dec->accept(*this);
+ ostr_ << misc::iendl;
+ }
+ }
+
+ void PrettyPrinter::operator()(const VarDec& e)
+ {
+ ostr_ << "var " << static_cast<Escapable>(e) << e.name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &e << " */";
+ }
+ if (e.type_name_get() != nullptr)
+ ostr_ << " : " << *e.type_name_get();
+ if (e.init_get() != nullptr)
+ ostr_ << " := " << *e.init_get();
+ else
+ ostr_ << " := 0";
+ }
+
+ void PrettyPrinter::operator()(const TypeChunk& e)
+ {
+ for (auto dec : e.decs_get())
+ {
+ dec->accept(*this);
+ ostr_ << misc::iendl;
+ }
+ }
+
+ void PrettyPrinter::operator()(const TypeDec& e)
+ {
+ if (const auto c = dynamic_cast<const ClassTy*>(&e.ty_get()); c)
+ {
+ ostr_ << "class " << e.name_get();
+ if (bindings_display(ostr_))
+ ostr_ << " /* " << &e << " */";
+ ostr_ << " extends " << c->super_get()
+ << misc::iendl << "{" << misc::incendl;
+ if (!c->chunks_get().chunks_get().empty())
+ {
+ ostr_ << misc::separate(c->chunks_get(), "\n");
+ }
+ ostr_ << misc::decendl << "}";
+ }
+ else
+ {
+ ostr_ << "type " << e.name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &e << " */";
+ }
+ ostr_ << " = " << e.ty_get();
+ }
+ }
+
+ void PrettyPrinter::operator()(const NameTy& e)
+ {
+ ostr_ << e.name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << e.def_get() << " */";
+ }
+ }
+
+ void PrettyPrinter::operator()(const FunctionChunk& e)
+ {
+ for (auto dec : e.decs_get())
+ {
+ dec->accept(*this);
+ ostr_ << misc::iendl;
+ }
+ }
+
+ void PrettyPrinter::operator()(const FunctionDec& e)
+ {
+ if (e.body_get() == nullptr)
+ ostr_ << "primitive ";
+ else
+ ostr_ << "function ";
+ ostr_ << e.name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &e << " */";
+ }
+ ostr_ << "(";
+ auto decs = e.formals_get().decs_get();
+ if (!decs.empty())
+ {
+ ostr_ << static_cast<Escapable>(*decs.at(0)) << decs.at(0)->name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &decs.at(0) << " */";
+ }
+ ostr_ << " : " << *decs.at(0)->type_name_get();
+ for (size_t i = 1; i < decs.size(); ++i)
+ {
+ ostr_ << ", " << static_cast<Escapable>(*decs.at(i))
+ << decs.at(i)->name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &decs.at(i) << " */";
+ }
+ ostr_ << " : " << *decs.at(i)->type_name_get();
+ }
+ }
+ ostr_ << ")";
+ if (e.result_get() != nullptr)
+ {
+ ostr_ << " : " << *e.result_get();
+ }
+ if (e.body_get() != nullptr)
+ {
+ ostr_ << " =" << misc::incendl << *e.body_get() << misc::decindent;
+ }
+ ostr_ << misc::iendl;
+ }
+
+ void PrettyPrinter::operator()(const MethodChunk& e)
+ {
+ for (auto dec : e.decs_get())
+ {
+ dec->accept(*this);
+ ostr_ << misc::iendl;
+ }
+ }
+
+ void PrettyPrinter::operator()(const MethodDec& e)
+ {
+ ostr_ << "method " << e.name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &e << " */";
+ }
+ ostr_ << "(";
+ auto decs = e.formals_get().decs_get();
+ if (!decs.empty())
+ {
+ ostr_ << static_cast<Escapable>(*decs.at(0)) << decs.at(0)->name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &decs.at(0) << " */";
+ }
+ ostr_ << " : " << *decs.at(0)->type_name_get();
+ for (size_t i = 1; i < decs.size(); ++i)
+ {
+ ostr_ << ", " << static_cast<Escapable>(*decs.at(i))
+ << decs.at(i)->name_get();
+ if (bindings_display(ostr_))
+ {
+ ostr_ << " /* " << &decs.at(i) << " */";
+ }
+ ostr_ << " : " << *decs.at(i)->type_name_get();
+ }
+ }
+ ostr_ << ")";
+ if (e.result_get() != nullptr)
+ {
+ ostr_ << " : " << *e.result_get();
+ }
+ if (e.body_get() != nullptr)
+ {
+ ostr_ << " =" << misc::incendl << *e.body_get() << misc::decindent;
+ }
+ ostr_ << misc::iendl;
+ }
+
+ void PrettyPrinter::operator()(const AssertExp& e)
+ {
+ ostr_ << "assert " << e.cond_get();
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/pretty-printer.hh b/tiger-compiler/src/ast/pretty-printer.hh
new file mode 100644
index 0000000..7532331
--- /dev/null
+++ b/tiger-compiler/src/ast/pretty-printer.hh
@@ -0,0 +1,96 @@
+/**
+ ** \file ast/pretty-printer.hh
+ ** \brief Declaration of ast::PrettyPrinter.
+ */
+
+#pragma once
+
+#include <ast/assert-visitor.hh>
+#include <ast/default-visitor.hh>
+#include <ast/object-visitor.hh>
+
+namespace ast
+{
+ /// Visit an Ast and print the content of each node.
+ class PrettyPrinter
+ : virtual public DefaultConstVisitor
+ , virtual public ObjectConstVisitor
+ , virtual public AssertConstVisitor
+ {
+ public:
+ using super_type = DefaultConstVisitor;
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build to print on \a ostr.
+ PrettyPrinter(std::ostream& ostr);
+
+ /// Visit methods.
+ /// \{
+ void operator()(const SimpleVar& e) override;
+ void operator()(const FieldVar& e) override;
+ void operator()(const SubscriptVar& e) override;
+ void operator()(const CastExp& e) override;
+ // FIXME DONE: Some code was deleted here.
+ void operator()(const NilExp& e) override;
+ void operator()(const IntExp& e) override;
+ void operator()(const StringExp& e) override;
+ void operator()(const ObjectExp& e) override;
+ void operator()(const CallExp& e) override;
+ void operator()(const MethodCallExp& e) override;
+ void operator()(const OpExp& e) override;
+ void operator()(const RecordExp& e) override;
+ void operator()(const SeqExp& e) override;
+ void operator()(const AssignExp& e) override;
+ void operator()(const IfExp& e) override;
+ void operator()(const WhileExp& e) override;
+ void operator()(const ForExp& e) override;
+ void operator()(const BreakExp&) override;
+ void operator()(const LetExp& e) override;
+ void operator()(const ArrayExp& e) override;
+ void operator()(const FieldInit& e) override;
+ /// \}
+
+ /// Visit Var declarations.
+ void operator()(const VarChunk& e) override;
+ void operator()(const VarDec& e) override;
+
+ /// Visit Function declarations.
+ void operator()(const FunctionChunk& e) override;
+ void operator()(const FunctionDec& e) override;
+ void operator()(const MethodChunk& e) override;
+ void operator()(const MethodDec& e) override;
+
+ /// Visit Type declarations.
+ void operator()(const TypeChunk& e) override;
+ void operator()(const TypeDec& e) override;
+
+ /** \} */
+
+ /** \name Visit Type related nodes.
+ ** \{ */
+ void operator()(const NameTy& e) override;
+ void operator()(const RecordTy& e) override;
+ void operator()(const ArrayTy& e) override;
+ void operator()(const ClassTy& e) override;
+ /** \} */
+
+ /** \name Visit Field related nodes. */
+ void operator()(const Field& e) override;
+
+ /** \name Visit Assertion nodes. */
+ void operator()(const AssertExp& e) override;
+
+ private:
+ // Factor pretty-printing of RecordExp and RecordTy.
+ template <typename RecordClass> void print_record(const RecordClass& e);
+
+ // Whether we are in a ast::ClassTy.
+ bool within_classty_p_ = false;
+
+ protected:
+ /// The stream to print on.
+ std::ostream& ostr_;
+ };
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/record-exp.cc b/tiger-compiler/src/ast/record-exp.cc
new file mode 100644
index 0000000..6ca817a
--- /dev/null
+++ b/tiger-compiler/src/ast/record-exp.cc
@@ -0,0 +1,30 @@
+/**
+ ** \file ast/record-exp.cc
+ ** \brief Implementation of ast::RecordExp.
+ */
+
+#include <ast/record-exp.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ RecordExp::RecordExp(const Location& location,
+ NameTy* type_name,
+ fieldinits_type* fields)
+ : Exp(location)
+ , type_name_(type_name)
+ , fields_(fields)
+ {}
+
+ RecordExp::~RecordExp()
+ {
+ delete type_name_;
+ misc::deep_clear(*fields_);
+ delete fields_;
+ }
+
+ void RecordExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void RecordExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/record-exp.hh b/tiger-compiler/src/ast/record-exp.hh
new file mode 100644
index 0000000..f0ba79e
--- /dev/null
+++ b/tiger-compiler/src/ast/record-exp.hh
@@ -0,0 +1,57 @@
+/**
+ ** \file ast/record-exp.hh
+ ** \brief Declaration of ast::RecordExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/field-init.hh>
+#include <ast/name-ty.hh>
+
+namespace ast
+{
+ /// RecordExp.
+ class RecordExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a RecordExp node.
+ RecordExp(const Location& location,
+ NameTy* type_name,
+ fieldinits_type* fields);
+ RecordExp(const RecordExp&) = delete;
+ RecordExp& operator=(const RecordExp&) = delete;
+ /// Destroy a RecordExp node.
+ ~RecordExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return identifier of the record type.
+ const NameTy& type_name_get() const;
+ /// Return identifier of the record type.
+ NameTy& type_name_get();
+ /// Return list of field initializations.
+ const fieldinits_type& fields_get() const;
+ /// Return list of field initializations.
+ fieldinits_type& fields_get();
+ /** \} */
+
+ protected:
+ /// Identifier of the record type.
+ NameTy* type_name_;
+ /// List of field initializations.
+ fieldinits_type* fields_;
+ };
+} // namespace ast
+#include <ast/record-exp.hxx>
diff --git a/tiger-compiler/src/ast/record-exp.hxx b/tiger-compiler/src/ast/record-exp.hxx
new file mode 100644
index 0000000..ab92edd
--- /dev/null
+++ b/tiger-compiler/src/ast/record-exp.hxx
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/record-exp.hxx
+ ** \brief Inline methods of ast::RecordExp.
+ */
+
+#pragma once
+
+#include <ast/record-exp.hh>
+
+namespace ast
+{
+
+ inline const NameTy& RecordExp::type_name_get() const { return *type_name_; }
+ inline NameTy& RecordExp::type_name_get() { return *type_name_; }
+
+ inline const fieldinits_type& RecordExp::fields_get() const
+ {
+ return *fields_;
+ }
+ inline fieldinits_type& RecordExp::fields_get() { return *fields_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/record-ty.cc b/tiger-compiler/src/ast/record-ty.cc
new file mode 100644
index 0000000..5614e96
--- /dev/null
+++ b/tiger-compiler/src/ast/record-ty.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/record-ty.cc
+ ** \brief Implementation of ast::RecordTy.
+ */
+
+#include <ast/record-ty.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ RecordTy::RecordTy(const Location& location, fields_type* fields)
+ : Ty(location)
+ , fields_(fields)
+ {}
+
+ RecordTy::~RecordTy()
+ {
+ misc::deep_clear(*fields_);
+ delete fields_;
+ }
+
+ void RecordTy::accept(ConstVisitor& v) const { v(*this); }
+
+ void RecordTy::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/record-ty.hh b/tiger-compiler/src/ast/record-ty.hh
new file mode 100644
index 0000000..d2d1a46
--- /dev/null
+++ b/tiger-compiler/src/ast/record-ty.hh
@@ -0,0 +1,49 @@
+
+/**
+ ** \file ast/record-ty.hh
+ ** \brief Declaration of ast::RecordTy.
+ */
+
+#pragma once
+
+#include <ast/field.hh>
+#include <ast/ty.hh>
+
+namespace ast
+{
+ /// RecordTy.
+ class RecordTy : public Ty
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a RecordTy node.
+ RecordTy(const Location& location, fields_type* fields);
+ RecordTy(const RecordTy&) = delete;
+ RecordTy& operator=(const RecordTy&) = delete;
+ /// Destroy a RecordTy node.
+ ~RecordTy() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the field list.
+ const fields_type& fields_get() const;
+ /// Return the field list.
+ fields_type& fields_get();
+ /** \} */
+
+ protected:
+ /// The field list.
+ fields_type* fields_;
+ };
+} // namespace ast
+#include <ast/record-ty.hxx>
diff --git a/tiger-compiler/src/ast/record-ty.hxx b/tiger-compiler/src/ast/record-ty.hxx
new file mode 100644
index 0000000..6d1c91c
--- /dev/null
+++ b/tiger-compiler/src/ast/record-ty.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/record-ty.hxx
+ ** \brief Inline methods of ast::RecordTy.
+ */
+
+#pragma once
+
+#include <ast/record-ty.hh>
+
+namespace ast
+{
+
+ inline const fields_type& RecordTy::fields_get() const { return *fields_; }
+ inline fields_type& RecordTy::fields_get() { return *fields_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/seq-exp.cc b/tiger-compiler/src/ast/seq-exp.cc
new file mode 100644
index 0000000..af6bc6c
--- /dev/null
+++ b/tiger-compiler/src/ast/seq-exp.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/seq-exp.cc
+ ** \brief Implementation of ast::SeqExp.
+ */
+
+#include <ast/seq-exp.hh>
+#include <ast/visitor.hh>
+#include <misc/algorithm.hh>
+
+namespace ast
+{
+ SeqExp::SeqExp(const Location& location, exps_type* exps)
+ : Exp(location)
+ , exps_(exps)
+ {}
+
+ SeqExp::~SeqExp()
+ {
+ misc::deep_clear(*exps_);
+ delete exps_;
+ }
+
+ void SeqExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void SeqExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/seq-exp.hh b/tiger-compiler/src/ast/seq-exp.hh
new file mode 100644
index 0000000..882c11e
--- /dev/null
+++ b/tiger-compiler/src/ast/seq-exp.hh
@@ -0,0 +1,47 @@
+/**
+ ** \file ast/seq-exp.hh
+ ** \brief Declaration of ast::SeqExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// SeqExp.
+ class SeqExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a SeqExp node.
+ SeqExp(const Location& location, exps_type* exps);
+ SeqExp(const SeqExp&) = delete;
+ SeqExp& operator=(const SeqExp&) = delete;
+ /// Destroy a SeqExp node.
+ ~SeqExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return list of expressions.
+ const exps_type& exps_get() const;
+ /// Return list of expressions.
+ exps_type& exps_get();
+ /** \} */
+
+ protected:
+ /// List of expressions.
+ exps_type* exps_;
+ };
+} // namespace ast
+#include <ast/seq-exp.hxx>
diff --git a/tiger-compiler/src/ast/seq-exp.hxx b/tiger-compiler/src/ast/seq-exp.hxx
new file mode 100644
index 0000000..87e0488
--- /dev/null
+++ b/tiger-compiler/src/ast/seq-exp.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/seq-exp.hxx
+ ** \brief Inline methods of ast::SeqExp.
+ */
+
+#pragma once
+
+#include <ast/seq-exp.hh>
+
+namespace ast
+{
+
+ inline const exps_type& SeqExp::exps_get() const { return *exps_; }
+ inline exps_type& SeqExp::exps_get() { return *exps_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/simple-var.cc b/tiger-compiler/src/ast/simple-var.cc
new file mode 100644
index 0000000..74035e0
--- /dev/null
+++ b/tiger-compiler/src/ast/simple-var.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/simple-var.cc
+ ** \brief Implementation of ast::SimpleVar.
+ */
+
+#include <ast/simple-var.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ SimpleVar::SimpleVar(const Location& location, misc::symbol name)
+ : Var(location)
+ , name_(name)
+ {}
+
+ void SimpleVar::accept(ConstVisitor& v) const { v(*this); }
+
+ void SimpleVar::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/simple-var.hh b/tiger-compiler/src/ast/simple-var.hh
new file mode 100644
index 0000000..be47767
--- /dev/null
+++ b/tiger-compiler/src/ast/simple-var.hh
@@ -0,0 +1,56 @@
+/**
+ ** \file ast/simple-var.hh
+ ** \brief Declaration of ast::SimpleVar.
+ */
+
+#pragma once
+
+#include <ast/var-dec.hh>
+#include <ast/var.hh>
+#include <misc/symbol.hh>
+
+namespace ast
+{
+ /// SimpleVar.
+ class SimpleVar : public Var
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a SimpleVar node.
+ SimpleVar(const Location& location, misc::symbol name);
+ SimpleVar(const SimpleVar&) = delete;
+ SimpleVar& operator=(const SimpleVar&) = delete;
+ /// Destroy a SimpleVar node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return variable's name.
+ misc::symbol name_get() const;
+ /// Set variable's name.
+ void name_set(misc::symbol);
+ /// Return definition site.
+ const VarDec* def_get() const;
+ /// Return definition site.
+ VarDec* def_get();
+ /// Set definition site.
+ void def_set(VarDec*);
+ /** \} */
+
+ protected:
+ /// Variable's name.
+ misc::symbol name_;
+ /// Definition site.
+ VarDec* def_ = nullptr;
+ };
+} // namespace ast
+#include <ast/simple-var.hxx>
diff --git a/tiger-compiler/src/ast/simple-var.hxx b/tiger-compiler/src/ast/simple-var.hxx
new file mode 100644
index 0000000..e89b622
--- /dev/null
+++ b/tiger-compiler/src/ast/simple-var.hxx
@@ -0,0 +1,20 @@
+/**
+ ** \file ast/simple-var.hxx
+ ** \brief Inline methods of ast::SimpleVar.
+ */
+
+#pragma once
+
+#include <ast/simple-var.hh>
+
+namespace ast
+{
+
+ inline misc::symbol SimpleVar::name_get() const { return name_; }
+ inline void SimpleVar::name_set(misc::symbol name) { name_ = name; }
+
+ inline const VarDec* SimpleVar::def_get() const { return def_; }
+ inline VarDec* SimpleVar::def_get() { return def_; }
+ inline void SimpleVar::def_set(VarDec* def) { def_ = def; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/string-exp.cc b/tiger-compiler/src/ast/string-exp.cc
new file mode 100644
index 0000000..78ff00f
--- /dev/null
+++ b/tiger-compiler/src/ast/string-exp.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/string-exp.cc
+ ** \brief Implementation of ast::StringExp.
+ */
+
+#include <ast/string-exp.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ StringExp::StringExp(const Location& location, const std::string& value)
+ : Exp(location)
+ , value_(value)
+ {}
+
+ void StringExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void StringExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/string-exp.hh b/tiger-compiler/src/ast/string-exp.hh
new file mode 100644
index 0000000..c9fd4f0
--- /dev/null
+++ b/tiger-compiler/src/ast/string-exp.hh
@@ -0,0 +1,47 @@
+/**
+ ** \file ast/string-exp.hh
+ ** \brief Declaration of ast::StringExp.
+ */
+
+#pragma once
+
+#include <string>
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// StringExp.
+ class StringExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a StringExp node.
+ StringExp(const Location& location, const std::string& value);
+ StringExp(const StringExp&) = delete;
+ StringExp& operator=(const StringExp&) = delete;
+ /// Destroy a StringExp node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return stored string value.
+ const std::string& value_get() const;
+ /// Return stored string value.
+ std::string& value_get();
+ /** \} */
+
+ protected:
+ /// Stored string value.
+ std::string value_;
+ };
+} // namespace ast
+#include <ast/string-exp.hxx>
diff --git a/tiger-compiler/src/ast/string-exp.hxx b/tiger-compiler/src/ast/string-exp.hxx
new file mode 100644
index 0000000..2c8a429
--- /dev/null
+++ b/tiger-compiler/src/ast/string-exp.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/string-exp.hxx
+ ** \brief Inline methods of ast::StringExp.
+ */
+
+#pragma once
+
+#include <ast/string-exp.hh>
+
+namespace ast
+{
+
+ inline const std::string& StringExp::value_get() const { return value_; }
+ inline std::string& StringExp::value_get() { return value_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/subscript-var.cc b/tiger-compiler/src/ast/subscript-var.cc
new file mode 100644
index 0000000..8c2ab4e
--- /dev/null
+++ b/tiger-compiler/src/ast/subscript-var.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/subscript-var.cc
+ ** \brief Implementation of ast::SubscriptVar.
+ */
+
+#include <ast/subscript-var.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ SubscriptVar::SubscriptVar(const Location& location, Var* var, Exp* index)
+ : Var(location)
+ , var_(var)
+ , index_(index)
+ {}
+
+ SubscriptVar::~SubscriptVar()
+ {
+ delete var_;
+ delete index_;
+ }
+
+ void SubscriptVar::accept(ConstVisitor& v) const { v(*this); }
+
+ void SubscriptVar::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/subscript-var.hh b/tiger-compiler/src/ast/subscript-var.hh
new file mode 100644
index 0000000..d771391
--- /dev/null
+++ b/tiger-compiler/src/ast/subscript-var.hh
@@ -0,0 +1,54 @@
+/**
+ ** \file ast/subscript-var.hh
+ ** \brief Declaration of ast::SubscriptVar.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+#include <ast/var.hh>
+
+namespace ast
+{
+ /// SubscriptVar.
+ class SubscriptVar : public Var
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a SubscriptVar node.
+ SubscriptVar(const Location& location, Var* var, Exp* index);
+ SubscriptVar(const SubscriptVar&) = delete;
+ SubscriptVar& operator=(const SubscriptVar&) = delete;
+ /// Destroy a SubscriptVar node.
+ ~SubscriptVar() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the mother variable.
+ const Var& var_get() const;
+ /// Return the mother variable.
+ Var& var_get();
+ /// Return the offset expression.
+ const Exp& index_get() const;
+ /// Return the offset expression.
+ Exp& index_get();
+ /** \} */
+
+ protected:
+ /// The mother variable.
+ Var* var_;
+ /// The offset expression.
+ Exp* index_;
+ };
+} // namespace ast
+#include <ast/subscript-var.hxx>
diff --git a/tiger-compiler/src/ast/subscript-var.hxx b/tiger-compiler/src/ast/subscript-var.hxx
new file mode 100644
index 0000000..5523240
--- /dev/null
+++ b/tiger-compiler/src/ast/subscript-var.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/subscript-var.hxx
+ ** \brief Inline methods of ast::SubscriptVar.
+ */
+
+#pragma once
+
+#include <ast/subscript-var.hh>
+
+namespace ast
+{
+
+ inline const Var& SubscriptVar::var_get() const { return *var_; }
+ inline Var& SubscriptVar::var_get() { return *var_; }
+
+ inline const Exp& SubscriptVar::index_get() const { return *index_; }
+ inline Exp& SubscriptVar::index_get() { return *index_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/tasks.cc b/tiger-compiler/src/ast/tasks.cc
new file mode 100644
index 0000000..7ef95da
--- /dev/null
+++ b/tiger-compiler/src/ast/tasks.cc
@@ -0,0 +1,32 @@
+/**
+ ** \file ast/tasks.cc
+ ** \brief Ast Tasks implementation.
+ */
+
+#include <ast/libast.hh>
+#include <misc/contract.hh>
+#define DEFINE_TASKS 1
+#include <ast/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace ast::tasks
+{
+ // The abstract syntax tree.
+ std::unique_ptr<ast::ChunkList> the_program(nullptr);
+
+ void ast_display()
+ {
+ // `the_program' should have been set by the parse module by now.
+ precondition(the_program) << "Could not dump the AST, root is null";
+ std::cout << "/* == Abstract Syntax Tree. == */\n"
+ << *the_program << std::endl;
+ }
+
+ void ast_dump()
+ {
+ // `the_program' should have been set by the parse module by now.
+ precondition(the_program) << "Could not dump the AST, root is null";
+ ast::dump_dot(*the_program, std::cout);
+ }
+
+} // namespace ast::tasks
diff --git a/tiger-compiler/src/ast/tasks.hh b/tiger-compiler/src/ast/tasks.hh
new file mode 100644
index 0000000..490fc90
--- /dev/null
+++ b/tiger-compiler/src/ast/tasks.hh
@@ -0,0 +1,24 @@
+/**
+ ** \file ast/tasks.hh
+ ** \brief Ast module related tasks.
+ */
+
+#pragma once
+
+#include <ast/chunk-list.hh>
+#include <task/libtask.hh>
+
+namespace ast::tasks
+{
+ /// Global root node of abstract syntax tree.
+ extern std::unique_ptr<ast::ChunkList> the_program;
+
+ TASK_GROUP("2. Abstract Syntax Tree");
+
+ /// Display the abstract syntax tree.
+ TASK_DECLARE("A|ast-display", "display the AST", ast_display, "parse");
+
+ /// Display the abstract syntax tree using a dumper.
+ TASK_DECLARE("ast-dump", "dump the AST", ast_dump, "parse");
+
+} // namespace ast::tasks
diff --git a/tiger-compiler/src/ast/ty.cc b/tiger-compiler/src/ast/ty.cc
new file mode 100644
index 0000000..1b2f5d7
--- /dev/null
+++ b/tiger-compiler/src/ast/ty.cc
@@ -0,0 +1,17 @@
+/**
+ ** \file ast/ty.cc
+ ** \brief Implementation of ast::Ty.
+ */
+
+#include <ast/ty.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Ty::Ty(const Location& location)
+ : Ast(location)
+ , Typable()
+ , TypeConstructor()
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/ty.hh b/tiger-compiler/src/ast/ty.hh
new file mode 100644
index 0000000..847713b
--- /dev/null
+++ b/tiger-compiler/src/ast/ty.hh
@@ -0,0 +1,39 @@
+/**
+ ** \file ast/ty.hh
+ ** \brief Declaration of ast::Ty.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/typable.hh>
+#include <ast/type-constructor.hh>
+
+namespace ast
+{
+ /// Ty.
+ class Ty
+ : public Ast
+ , public Typable
+ , public TypeConstructor
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a Ty node.
+ explicit Ty(const Location& location);
+ Ty(const Ty&) = delete;
+ Ty& operator=(const Ty&) = delete;
+ /// Destroy a Ty node.
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override = 0;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override = 0;
+ /// \}
+ };
+} // namespace ast
+#include <ast/ty.hxx>
diff --git a/tiger-compiler/src/ast/ty.hxx b/tiger-compiler/src/ast/ty.hxx
new file mode 100644
index 0000000..8bce3c5
--- /dev/null
+++ b/tiger-compiler/src/ast/ty.hxx
@@ -0,0 +1,11 @@
+/**
+ ** \file ast/ty.hxx
+ ** \brief Inline methods of ast::Ty.
+ */
+
+#pragma once
+
+#include <ast/ty.hh>
+
+namespace ast
+{} // namespace ast
diff --git a/tiger-compiler/src/ast/typable.cc b/tiger-compiler/src/ast/typable.cc
new file mode 100644
index 0000000..889aa4b
--- /dev/null
+++ b/tiger-compiler/src/ast/typable.cc
@@ -0,0 +1,15 @@
+/**
+ ** \file ast/typable.cc
+ ** \brief Implementation of ast::Typable.
+ */
+
+#include <ast/typable.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+ Typable::Typable()
+ : type_(nullptr)
+ {}
+} // namespace ast
diff --git a/tiger-compiler/src/ast/typable.hh b/tiger-compiler/src/ast/typable.hh
new file mode 100644
index 0000000..50c004e
--- /dev/null
+++ b/tiger-compiler/src/ast/typable.hh
@@ -0,0 +1,50 @@
+/**
+ ** \file ast/typable.hh
+ ** \brief Declaration of ast::Typable.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <type/fwd.hh>
+
+namespace ast
+{
+ /** \class ast::Typable
+ ** \brief Hold a type information.
+ **
+ ** A Typable node holds a type information (type::Type) about
+ ** this node. This can be:
+ ** \li the type of the node itself, if it is a Exp or a Ty, or
+ ** \li the type of of the declared object, in case of a Dec.
+ */
+
+ class Typable
+ {
+ // FIXME DONE: Some code was deleted here.
+
+ public:
+ // Only need for basic constructor and destructor here
+ Typable();
+ virtual ~Typable() = default;
+
+ /* We prohibit copy and assignment as to avoid having
+ ** multiple Typable referencing the same Type which could
+ ** potentially mess up the TypeConstructor
+ */
+ Typable(const Typable&) = delete;
+ Typable& operator=(const Typable&) = delete;
+
+ // Basic getters/setters
+ void type_set(const type::Type*);
+ const type::Type* type_get() const;
+
+ // Making sure we can visit thoses "nodes"
+ virtual void accept(ConstVisitor& v) const = 0;
+ virtual void accept(Visitor& v) = 0;
+
+ private:
+ const type::Type* type_;
+ };
+} // namespace ast
+#include <ast/typable.hxx>
diff --git a/tiger-compiler/src/ast/typable.hxx b/tiger-compiler/src/ast/typable.hxx
new file mode 100644
index 0000000..3af401a
--- /dev/null
+++ b/tiger-compiler/src/ast/typable.hxx
@@ -0,0 +1,24 @@
+/**
+ ** \file ast/typable.hxx
+ ** \brief Inline methods of ast::Typable.
+ */
+
+#pragma once
+
+#include <ast/typable.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+
+ inline void Typable::type_set(const type::Type* typ)
+ {
+ // Explicitely casting it?
+ type_ = typ;
+ }
+
+ inline const type::Type* Typable::type_get() const
+ {
+ return type_;
+ }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/type-constructor.cc b/tiger-compiler/src/ast/type-constructor.cc
new file mode 100644
index 0000000..7786864
--- /dev/null
+++ b/tiger-compiler/src/ast/type-constructor.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file ast/type-constructor.cc
+ ** \brief Implementation of ast::TypeConstructor.
+ */
+
+#include <ast/type-constructor.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+ TypeConstructor::TypeConstructor()
+ : reference_(nullptr)
+ {}
+
+ TypeConstructor::~TypeConstructor()
+ {
+ // IF SOME MEMORY ERRORS HAPPENS, THIS IS THE CULPRIT
+ delete reference_;
+ }
+
+ void TypeConstructor::accept(ConstVisitor& v) const
+ {
+ v(this);
+ }
+
+ void TypeConstructor::accept(Visitor& v)
+ {
+ v(this);
+ }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/type-constructor.hh b/tiger-compiler/src/ast/type-constructor.hh
new file mode 100644
index 0000000..87f57d8
--- /dev/null
+++ b/tiger-compiler/src/ast/type-constructor.hh
@@ -0,0 +1,38 @@
+/**
+ ** \file ast/type-constructor.hh
+ ** \brief Declaration of ast::TypeConstructor.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <type/fwd.hh>
+
+namespace ast
+{
+ /** \class ast::TypeConstructor
+ ** \brief Create a new type.
+ */
+
+ class TypeConstructor
+ {
+ // FIXME DONE: Some code was deleted here.
+ public:
+ // Basic default constructor
+ // BUT we have a custom destructor this time (daring today aren't we?)
+ TypeConstructor();
+ ~TypeConstructor();
+
+ // Basic accessors
+ void created_type_set(const type::Type*);
+ const type::Type* created_type_get() const;
+
+ // Implementing the visitor so this can also be visited
+ void accept(ConstVisitor& v) const;
+ void accept(Visitor& v);
+
+ private:
+ const type::Type* reference_;
+ };
+} // namespace ast
+#include <ast/type-constructor.hxx>
diff --git a/tiger-compiler/src/ast/type-constructor.hxx b/tiger-compiler/src/ast/type-constructor.hxx
new file mode 100644
index 0000000..86933f3
--- /dev/null
+++ b/tiger-compiler/src/ast/type-constructor.hxx
@@ -0,0 +1,23 @@
+/**
+ ** \file ast/type-constructor.hxx
+ ** \brief Inline methods of ast::TypeConstructor.
+ */
+
+#pragma once
+
+#include <ast/type-constructor.hh>
+#include <type/types.hh>
+
+namespace ast
+{
+ // FIXME DONE: Some code was deleted here.
+ inline void TypeConstructor::created_type_set(const type::Type* typ)
+ {
+ reference_ = typ;
+ }
+
+ inline const type::Type* TypeConstructor::created_type_get() const
+ {
+ return reference_;
+ }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/type-dec.cc b/tiger-compiler/src/ast/type-dec.cc
new file mode 100644
index 0000000..336c42f
--- /dev/null
+++ b/tiger-compiler/src/ast/type-dec.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file ast/type-dec.cc
+ ** \brief Implementation of ast::TypeDec.
+ */
+
+#include <ast/type-dec.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ TypeDec::TypeDec(const Location& location, misc::symbol name, Ty* ty)
+ : Dec(location, name)
+ , TypeConstructor()
+ , ty_(ty)
+ {}
+
+ TypeDec::~TypeDec() { delete ty_; }
+
+ void TypeDec::accept(ConstVisitor& v) const { v(*this); }
+
+ void TypeDec::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/type-dec.hh b/tiger-compiler/src/ast/type-dec.hh
new file mode 100644
index 0000000..0e19926
--- /dev/null
+++ b/tiger-compiler/src/ast/type-dec.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file ast/type-dec.hh
+ ** \brief Declaration of ast::TypeDec.
+ */
+
+#pragma once
+
+#include <ast/dec.hh>
+#include <ast/ty.hh>
+#include <ast/type-constructor.hh>
+
+namespace ast
+{
+ /// TypeDec.
+ class TypeDec
+ : public Dec
+ , public TypeConstructor
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a TypeDec node.
+ TypeDec(const Location& location, misc::symbol name, Ty* ty);
+ TypeDec(const TypeDec&) = delete;
+ TypeDec& operator=(const TypeDec&) = delete;
+ /// Destroy a TypeDec node.
+ ~TypeDec() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return type definition.
+ const Ty& ty_get() const;
+ /// Return type definition.
+ Ty& ty_get();
+ /** \} */
+
+ protected:
+ /// Type definition.
+ Ty* ty_;
+ };
+} // namespace ast
+#include <ast/type-dec.hxx>
diff --git a/tiger-compiler/src/ast/type-dec.hxx b/tiger-compiler/src/ast/type-dec.hxx
new file mode 100644
index 0000000..69dc086
--- /dev/null
+++ b/tiger-compiler/src/ast/type-dec.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file ast/type-dec.hxx
+ ** \brief Inline methods of ast::TypeDec.
+ */
+
+#pragma once
+
+#include <ast/type-dec.hh>
+
+namespace ast
+{
+
+ inline const Ty& TypeDec::ty_get() const { return *ty_; }
+ inline Ty& TypeDec::ty_get() { return *ty_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/var-dec.cc b/tiger-compiler/src/ast/var-dec.cc
new file mode 100644
index 0000000..85e7eba
--- /dev/null
+++ b/tiger-compiler/src/ast/var-dec.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file ast/var-dec.cc
+ ** \brief Implementation of ast::VarDec.
+ */
+
+#include <ast/var-dec.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+
+ VarDec::VarDec(const Location& location,
+ misc::symbol name,
+ NameTy* type_name,
+ Exp* init)
+ : Dec(location, name)
+ , Escapable()
+ , type_name_(type_name)
+ , init_(init)
+ {}
+
+ VarDec::~VarDec()
+ {
+ delete type_name_;
+ delete init_;
+ }
+
+ void VarDec::accept(ConstVisitor& v) const { v(*this); }
+
+ void VarDec::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/var-dec.hh b/tiger-compiler/src/ast/var-dec.hh
new file mode 100644
index 0000000..fd15b7e
--- /dev/null
+++ b/tiger-compiler/src/ast/var-dec.hh
@@ -0,0 +1,61 @@
+/**
+ ** \file ast/var-dec.hh
+ ** \brief Declaration of ast::VarDec.
+ */
+
+#pragma once
+
+#include <ast/dec.hh>
+#include <ast/escapable.hh>
+#include <ast/exp.hh>
+#include <ast/name-ty.hh>
+
+namespace ast
+{
+ /// VarDec.
+ class VarDec
+ : public Dec
+ , public Escapable
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a VarDec node.
+ VarDec(const Location& location,
+ misc::symbol name,
+ NameTy* type_name,
+ Exp* init);
+ VarDec(const VarDec&) = delete;
+ VarDec& operator=(const VarDec&) = delete;
+ /// Destroy a VarDec node.
+ ~VarDec() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return optional type of the declared variable.
+ const NameTy* type_name_get() const;
+ /// Return optional type of the declared variable.
+ NameTy* type_name_get();
+ /// Return the initial value (expression) assigned to the variable.
+ const Exp* init_get() const;
+ /// Return the initial value (expression) assigned to the variable.
+ Exp* init_get();
+ /** \} */
+
+ protected:
+ /// Optional type of the declared variable.
+ NameTy* type_name_;
+ /// The initial value (expression) assigned to the variable.
+ Exp* init_;
+ };
+} // namespace ast
+#include <ast/var-dec.hxx>
diff --git a/tiger-compiler/src/ast/var-dec.hxx b/tiger-compiler/src/ast/var-dec.hxx
new file mode 100644
index 0000000..c96c3f4
--- /dev/null
+++ b/tiger-compiler/src/ast/var-dec.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/var-dec.hxx
+ ** \brief Inline methods of ast::VarDec.
+ */
+
+#pragma once
+
+#include <ast/var-dec.hh>
+
+namespace ast
+{
+
+ inline const NameTy* VarDec::type_name_get() const { return type_name_; }
+ inline NameTy* VarDec::type_name_get() { return type_name_; }
+
+ inline const Exp* VarDec::init_get() const { return init_; }
+ inline Exp* VarDec::init_get() { return init_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/var.cc b/tiger-compiler/src/ast/var.cc
new file mode 100644
index 0000000..6bea70c
--- /dev/null
+++ b/tiger-compiler/src/ast/var.cc
@@ -0,0 +1,15 @@
+/**
+ ** \file ast/var.cc
+ ** \brief Implementation of ast::Var.
+ */
+
+#include <ast/var.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ Var::Var(const Location& location)
+ : Exp(location)
+ {}
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/var.hh b/tiger-compiler/src/ast/var.hh
new file mode 100644
index 0000000..286e392
--- /dev/null
+++ b/tiger-compiler/src/ast/var.hh
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/var.hh
+ ** \brief Declaration of ast::Var.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// Var.
+ class Var : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a Var node.
+ explicit Var(const Location& location);
+ Var(const Var&) = delete;
+ Var& operator=(const Var&) = delete;
+ /// Destroy a Var node.
+ /** \} */
+ };
+} // namespace ast
+#include <ast/var.hxx>
diff --git a/tiger-compiler/src/ast/var.hxx b/tiger-compiler/src/ast/var.hxx
new file mode 100644
index 0000000..1f54528
--- /dev/null
+++ b/tiger-compiler/src/ast/var.hxx
@@ -0,0 +1,11 @@
+/**
+ ** \file ast/var.hxx
+ ** \brief Inline methods of ast::Var.
+ */
+
+#pragma once
+
+#include <ast/var.hh>
+
+namespace ast
+{} // namespace ast
diff --git a/tiger-compiler/src/ast/visitor.hh b/tiger-compiler/src/ast/visitor.hh
new file mode 100644
index 0000000..420db00
--- /dev/null
+++ b/tiger-compiler/src/ast/visitor.hh
@@ -0,0 +1,114 @@
+/**
+ ** \file ast/visitor.hh
+ ** \brief Definition of ast::Visitor.
+ */
+
+#pragma once
+
+#include <functional>
+#include <ast/fwd.hh>
+#include <misc/select-const.hh>
+
+namespace ast
+{
+ /** \brief Root class of all Ast visitors.
+ **
+ ** GenVisitor<CONSTIFY> is the root class of all Ast visitors. */
+ template <template <typename> class Const> class GenVisitor
+ {
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /// Destroy a GenVisitor.
+ virtual ~GenVisitor();
+ /** \} */
+
+ /// The entry point: visit \a e.
+ virtual void operator()(const_t<Ast>& e);
+ virtual void operator()(const_t<ArrayExp>&) = 0;
+ virtual void operator()(const_t<ArrayTy>&) = 0;
+ virtual void operator()(const_t<AssignExp>&) = 0;
+ virtual void operator()(const_t<BreakExp>&) = 0;
+ virtual void operator()(const_t<CallExp>&) = 0;
+ virtual void operator()(const_t<CastExp>&) = 0;
+ virtual void operator()(const_t<ChunkList>&) = 0;
+ virtual void operator()(const_t<ClassTy>&) = 0;
+ virtual void operator()(const_t<Field>&) = 0;
+ virtual void operator()(const_t<FieldInit>&) = 0;
+ virtual void operator()(const_t<FieldVar>&) = 0;
+ virtual void operator()(const_t<ForExp>&) = 0;
+ virtual void operator()(const_t<FunctionDec>&) = 0;
+ virtual void operator()(const_t<IfExp>&) = 0;
+ virtual void operator()(const_t<IntExp>&) = 0;
+ virtual void operator()(const_t<LetExp>&) = 0;
+ virtual void operator()(const_t<MethodCallExp>&) = 0;
+ virtual void operator()(const_t<MethodDec>&) = 0;
+ virtual void operator()(const_t<NameTy>&) = 0;
+ virtual void operator()(const_t<NilExp>&) = 0;
+ virtual void operator()(const_t<ObjectExp>&) = 0;
+ virtual void operator()(const_t<OpExp>&) = 0;
+ virtual void operator()(const_t<RecordExp>&) = 0;
+ virtual void operator()(const_t<RecordTy>&) = 0;
+ virtual void operator()(const_t<SeqExp>&) = 0;
+ virtual void operator()(const_t<SimpleVar>&) = 0;
+ virtual void operator()(const_t<StringExp>&) = 0;
+ virtual void operator()(const_t<SubscriptVar>&) = 0;
+ virtual void operator()(const_t<TypeDec>&) = 0;
+ virtual void operator()(const_t<VarDec>&) = 0;
+ virtual void operator()(const_t<WhileExp>&) = 0;
+
+ virtual void operator()(const_t<FunctionChunk>&) = 0;
+ virtual void operator()(const_t<MethodChunk>&) = 0;
+ virtual void operator()(const_t<TypeChunk>&) = 0;
+ virtual void operator()(const_t<VarChunk>&) = 0;
+
+ virtual void operator()(const_t<AssertExp>&) = 0;
+
+ /// Helper to visit nodes manipulated via a pointer.
+ template <class E> void operator()(E* e);
+
+ protected:
+ /** A convenient shortcut for recurring code like this:
+
+ \code
+ if (e)
+ e->accept(*this);
+ \endcode
+
+ However, the drawback of this approach is that it doesn't take
+ care of the constness, and any \a const violation will be
+ reported \em within the body of this method, not at its
+ corresponding call site.
+
+ We cannot use the misc/select_const.hh approach here, since
+ the compiler cannot resolve a function overloaded or
+ specialized on an associated type of a template. E.g., writing
+ \a accept like this:
+
+ \code
+ template <typename E>
+ void accept(const_t<E>* e);
+ \endcode
+
+ won't work directly. Of course, one can help the compiler,
+ providing it with \a E
+
+ \code
+ accept<ast::NameTy>(e.result_get());
+ \endcode
+
+ but this is painful. */
+ template <typename E> void accept(E* e);
+ };
+
+ /// Shorthand for a const visitor.
+ using ConstVisitor = GenVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using Visitor = GenVisitor<misc::id_traits>;
+
+} // namespace ast
+
+#include <ast/visitor.hxx>
diff --git a/tiger-compiler/src/ast/visitor.hxx b/tiger-compiler/src/ast/visitor.hxx
new file mode 100644
index 0000000..2765f80
--- /dev/null
+++ b/tiger-compiler/src/ast/visitor.hxx
@@ -0,0 +1,36 @@
+/**
+ ** \file ast/visitor.hxx
+ ** \brief Definition of ast::Visitor.
+ */
+
+#pragma once
+
+#include <ast/ast.hh>
+#include <ast/visitor.hh>
+
+namespace ast
+{
+ template <template <typename> class Const> GenVisitor<Const>::~GenVisitor() {}
+
+ template <template <typename> class Const>
+ void GenVisitor<Const>::operator()(const_t<ast::Ast>& e)
+ {
+ e.accept(*this);
+ }
+
+ template <template <typename> class Const>
+ template <class E>
+ void GenVisitor<Const>::operator()(E* e)
+ {
+ e->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ template <typename E>
+ void GenVisitor<Const>::accept(E* e)
+ {
+ if (e)
+ e->accept(*this);
+ }
+
+} // namespace ast
diff --git a/tiger-compiler/src/ast/while-exp.cc b/tiger-compiler/src/ast/while-exp.cc
new file mode 100644
index 0000000..3ffa5e1
--- /dev/null
+++ b/tiger-compiler/src/ast/while-exp.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file ast/while-exp.cc
+ ** \brief Implementation of ast::WhileExp.
+ */
+
+#include <ast/visitor.hh>
+#include <ast/while-exp.hh>
+
+namespace ast
+{
+ WhileExp::WhileExp(const Location& location, Exp* test, Exp* body)
+ : Exp(location)
+ , test_(test)
+ , body_(body)
+ {}
+
+ WhileExp::~WhileExp()
+ {
+ delete test_;
+ delete body_;
+ }
+
+ void WhileExp::accept(ConstVisitor& v) const { v(*this); }
+
+ void WhileExp::accept(Visitor& v) { v(*this); }
+} // namespace ast
diff --git a/tiger-compiler/src/ast/while-exp.hh b/tiger-compiler/src/ast/while-exp.hh
new file mode 100644
index 0000000..0f8a787
--- /dev/null
+++ b/tiger-compiler/src/ast/while-exp.hh
@@ -0,0 +1,53 @@
+/**
+ ** \file ast/while-exp.hh
+ ** \brief Declaration of ast::WhileExp.
+ */
+
+#pragma once
+
+#include <ast/exp.hh>
+
+namespace ast
+{
+ /// WhileExp.
+ class WhileExp : public Exp
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a WhileExp node.
+ WhileExp(const Location& location, Exp* test, Exp* body);
+ WhileExp(const WhileExp&) = delete;
+ WhileExp& operator=(const WhileExp&) = delete;
+ /// Destroy a WhileExp node.
+ ~WhileExp() override;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return exit condition of the loop.
+ const Exp& test_get() const;
+ /// Return exit condition of the loop.
+ Exp& test_get();
+ /// Return instructions executed in the loop.
+ const Exp& body_get() const;
+ /// Return instructions executed in the loop.
+ Exp& body_get();
+ /** \} */
+
+ protected:
+ /// Exit condition of the loop.
+ Exp* test_;
+ /// Instructions executed in the loop.
+ Exp* body_;
+ };
+} // namespace ast
+#include <ast/while-exp.hxx>
diff --git a/tiger-compiler/src/ast/while-exp.hxx b/tiger-compiler/src/ast/while-exp.hxx
new file mode 100644
index 0000000..d6b9195
--- /dev/null
+++ b/tiger-compiler/src/ast/while-exp.hxx
@@ -0,0 +1,19 @@
+/**
+ ** \file ast/while-exp.hxx
+ ** \brief Inline methods of ast::WhileExp.
+ */
+
+#pragma once
+
+#include <ast/while-exp.hh>
+
+namespace ast
+{
+
+ inline const Exp& WhileExp::test_get() const { return *test_; }
+ inline Exp& WhileExp::test_get() { return *test_; }
+
+ inline const Exp& WhileExp::body_get() const { return *body_; }
+ inline Exp& WhileExp::body_get() { return *body_; }
+
+} // namespace ast
diff --git a/tiger-compiler/src/astclone/cloner.cc b/tiger-compiler/src/astclone/cloner.cc
new file mode 100644
index 0000000..8e26fa7
--- /dev/null
+++ b/tiger-compiler/src/astclone/cloner.cc
@@ -0,0 +1,311 @@
+/**
+ ** \file astclone/cloner.cc
+ ** \brief Implementation of astclone::Cloner.
+ */
+
+#include <ast/all.hh>
+#include <astclone/cloner.hh>
+#include <misc/symbol.hh>
+
+namespace astclone
+{
+ using namespace ast;
+
+ Cloner::Cloner()
+ : result_(nullptr)
+ {}
+
+ Ast* Cloner::result_get() { return result_; }
+
+ void Cloner::operator()(const ast::ArrayExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& loc = e.location_get();
+ NameTy* type_name = recurse(e.type_name_get());
+ Exp* size = recurse(e.size_get());
+ Exp* init = recurse(e.init_get());
+ result_ = new ArrayExp(loc, type_name, size, init);
+ }
+
+ void Cloner::operator()(const ast::ArrayTy& e)
+ {
+ const Location& location = e.location_get();
+ NameTy* base_type = recurse(e.base_type_get());
+ result_ = new ArrayTy(location, base_type);
+ }
+
+ void Cloner::operator()(const ast::AssertExp& e)
+ {
+ const Location& location = e.location_get();
+ Exp* cond = recurse(e.cond_get());
+ result_ = new AssertExp(location, cond);
+ }
+
+ void Cloner::operator()(const ast::AssignExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ Var* variable = recurse(e.var_get());
+ Exp* value = recurse(e.exp_get());
+ result_ = new AssignExp(location, variable, value);
+ }
+
+ void Cloner::operator()(const ast::BreakExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ result_ = new BreakExp(location);
+ }
+
+ void Cloner::operator()(const ast::CallExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ // Apparently, we DO have a default copy constructor for symbols...
+ misc::symbol id = e.name_get();
+ exps_type* args = recurse_collection(e.args_get());
+ result_ = new CallExp(location, id, args);
+ }
+
+ void Cloner::operator()(const ast::CastExp& e)
+ {
+ const Location& location = e.location_get();
+ Exp* exp = recurse(e.exp_get());
+ Ty* ty = recurse(e.ty_get());
+ result_ = new CastExp(location, exp, ty);
+ }
+
+ void Cloner::operator()(const ast::ChunkList& e)
+ {
+ const Location& location = e.location_get();
+ ChunkList::list_type chunks = *recurse_collection(e.chunks_get());
+ result_ = new ChunkList(location, chunks);
+ }
+
+ void Cloner::operator()(const ast::ClassTy& e)
+ {
+ const Location& location = e.location_get();
+ NameTy* super = recurse(e.super_get());
+ ChunkList* chunks = recurse(e.chunks_get());
+ result_ = new ClassTy(location, super, chunks);
+ }
+
+ void Cloner::operator()(const ast::Field& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ NameTy* type_name = recurse(e.type_name_get());
+ result_ = new Field(location, name, type_name);
+ }
+
+ void Cloner::operator()(const ast::FieldInit& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ Exp* init = recurse(e.init_get());
+ result_ = new FieldInit(location, name, init);
+ }
+
+ void Cloner::operator()(const ast::FieldVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ Var* variable = recurse(e.var_get());
+ misc::symbol id = e.name_get();
+ result_ = new FieldVar(location, variable, id);
+ }
+
+ void Cloner::operator()(const ast::ForExp& e)
+ {
+ const Location& location = e.location_get();
+ VarDec* vardec = recurse(e.vardec_get());
+ Exp* hi = recurse(e.hi_get());
+ Exp* body = recurse(e.body_get());
+ result_ = new ForExp(location, vardec, hi, body);
+ }
+
+ void Cloner::operator()(const ast::FunctionDec& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ VarChunk* formals = recurse(e.formals_get());
+ NameTy* result = recurse(e.result_get());
+ Exp* body = recurse(e.body_get());
+ auto fundec = new FunctionDec(location, name, formals, result, body);
+ result_ = fundec;
+ }
+
+ void Cloner::operator()(const ast::IfExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ Exp* cond = recurse(e.test_get());
+ Exp* thenclause = recurse(e.thenclause_get());
+ Exp* elseclause = recurse(e.elseclause_get());
+ result_ = new IfExp(location, cond, thenclause, elseclause);
+ }
+
+ void Cloner::operator()(const ast::IntExp& e)
+ {
+ const Location& location = e.location_get();
+ int value = e.value_get();
+ result_ = new IntExp(location, value);
+ }
+
+ void Cloner::operator()(const ast::LetExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ Exp* body = recurse(e.body_get());
+ ChunkList* chunky = recurse(e.chunks_get());
+ result_ = new LetExp(location, chunky, body);
+ }
+
+ void Cloner::operator()(const ast::MethodCallExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ misc::symbol id = e.name_get();
+ exps_type* args = recurse_collection(e.args_get());
+ Var* variable = recurse(e.object_get());
+ result_ = new MethodCallExp(location, id, args, variable);
+ }
+
+ void Cloner::operator()(const ast::MethodDec& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ VarChunk* formals = recurse(e.formals_get());
+ NameTy* result = recurse(e.result_get());
+ Exp* body = recurse(e.body_get());
+ result_ = new MethodDec(location, name, formals, result, body);
+ }
+
+ void Cloner::operator()(const ast::NameTy& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ result_ = new NameTy(location, name);
+ }
+
+ void Cloner::operator()(const ast::NilExp& e)
+ {
+ const Location& location = e.location_get();
+ result_ = new NilExp(location);
+ }
+
+ void Cloner::operator()(const ast::ObjectExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ NameTy* name = recurse(e.type_name_get());
+ result_ = new ObjectExp(location, name);
+ }
+
+ void Cloner::operator()(const ast::OpExp& e)
+ {
+ const Location& location = e.location_get();
+ Exp* left = recurse(e.left_get());
+ OpExp::Oper oper = e.oper_get();
+ Exp* right = recurse(e.right_get());
+ result_ = new OpExp(location, left, oper, right);
+ }
+
+ void Cloner::operator()(const ast::RecordExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ NameTy* name = recurse(e.type_name_get());
+ fieldinits_type* fields = recurse_collection(e.fields_get());
+ result_ = new RecordExp(location, name, fields);
+ }
+
+ void Cloner::operator()(const ast::RecordTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ fields_type* fields = recurse_collection(e.fields_get());
+ result_ = new RecordTy(location, fields);
+ }
+
+ void Cloner::operator()(const ast::SeqExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ exps_type* types = recurse_collection(e.exps_get());
+ result_ = new SeqExp(location, types);
+ }
+
+ void Cloner::operator()(const ast::SimpleVar& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ result_ = new SimpleVar(location, name);
+ }
+
+ void Cloner::operator()(const ast::StringExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Location& location = e.location_get();
+ const std::string& txt = e.value_get();
+ result_ = new StringExp(location, txt);
+ }
+
+ void Cloner::operator()(const ast::SubscriptVar& e)
+ {
+ const Location& location = e.location_get();
+ Var* var = recurse(e.var_get());
+ Exp* index = recurse(e.index_get());
+ result_ = new SubscriptVar(location, var, index);
+ }
+
+ void Cloner::operator()(const ast::TypeDec& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ Ty* ty = recurse(e.ty_get());
+ result_ = new TypeDec(location, name, ty);
+ }
+
+ void Cloner::operator()(const ast::VarDec& e)
+ {
+ const Location& location = e.location_get();
+ misc::symbol name = e.name_get();
+ NameTy* type_name = recurse(e.type_name_get());
+ Exp* init = recurse(e.init_get());
+ // FIXME DONE: Some code was deleted here (Cloned node instantiation).
+ result_ = new VarDec(location, name, type_name, init);
+ }
+
+ void Cloner::operator()(const ast::WhileExp& e)
+ {
+ const Location& location = e.location_get();
+ Exp* test = recurse(e.test_get());
+ Exp* body = recurse(e.body_get());
+ result_ = new WhileExp(location, test, body);
+ }
+
+ void Cloner::operator()(const ast::FunctionChunk& e)
+ {
+ chunk_visit<ast::FunctionChunk>(e);
+ }
+
+ void Cloner::operator()(const ast::MethodChunk& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ chunk_visit<ast::MethodChunk>(e);
+ }
+
+ void Cloner::operator()(const ast::TypeChunk& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ chunk_visit<ast::TypeChunk>(e);
+ }
+
+ void Cloner::operator()(const ast::VarChunk& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ chunk_visit<ast::VarChunk>(e);
+ }
+
+} // namespace astclone
diff --git a/tiger-compiler/src/astclone/cloner.hh b/tiger-compiler/src/astclone/cloner.hh
new file mode 100644
index 0000000..f1405d1
--- /dev/null
+++ b/tiger-compiler/src/astclone/cloner.hh
@@ -0,0 +1,102 @@
+/**
+ ** \file astclone/cloner.hh
+ ** \brief Declaration of astclone::Cloner.
+ */
+
+#pragma once
+
+#include <ast/default-visitor.hh>
+
+namespace astclone
+{
+ /// \brief Duplicate an Ast.
+ class Cloner : public ast::DefaultConstVisitor
+ {
+ public:
+ using super_type = ast::DefaultConstVisitor;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a Cloner.
+ Cloner();
+
+ /// Destroy a Cloner.
+ ~Cloner() override = default;
+
+ // Return the cloned Ast.
+ ast::Ast* result_get();
+
+ template <typename T> T* recurse(const T& t);
+
+ template <typename T> T* recurse(const T* t);
+
+ /** \brief Clone a collection object.
+
+ Using overloading for this method is tempting, but it would
+ lead to the same prototype than the first \a recurse method.
+
+ A partial specialization for \a std::list<T> would work, but is
+ not allowed by C++ standard. As a consequence, we are stuck to
+ using different names.
+ */
+ template <typename CollectionType>
+ CollectionType* recurse_collection(const CollectionType& c);
+
+ // Visit methods.
+ public:
+ void operator()(const ast::ArrayExp&) override;
+ void operator()(const ast::ArrayTy&) override;
+ void operator()(const ast::AssertExp&) override;
+ void operator()(const ast::AssignExp&) override;
+ void operator()(const ast::BreakExp&) override;
+ void operator()(const ast::CallExp&) override;
+ void operator()(const ast::CastExp&) override;
+ void operator()(const ast::ChunkList&) override;
+ void operator()(const ast::ClassTy&) override;
+ void operator()(const ast::Field&) override;
+ void operator()(const ast::FieldInit&) override;
+ void operator()(const ast::FieldVar&) override;
+ void operator()(const ast::ForExp&) override;
+ void operator()(const ast::FunctionDec&) override;
+ void operator()(const ast::IfExp&) override;
+ void operator()(const ast::IntExp&) override;
+ void operator()(const ast::LetExp&) override;
+ void operator()(const ast::MethodCallExp&) override;
+ void operator()(const ast::MethodDec&) override;
+ void operator()(const ast::NameTy&) override;
+ void operator()(const ast::NilExp&) override;
+ void operator()(const ast::ObjectExp&) override;
+ void operator()(const ast::OpExp&) override;
+ void operator()(const ast::RecordExp&) override;
+ void operator()(const ast::RecordTy&) override;
+ void operator()(const ast::SeqExp&) override;
+ void operator()(const ast::SimpleVar&) override;
+ void operator()(const ast::StringExp&) override;
+ void operator()(const ast::SubscriptVar&) override;
+ void operator()(const ast::TypeDec&) override;
+ void operator()(const ast::VarDec&) override;
+ void operator()(const ast::WhileExp&) override;
+
+ template <typename ChunkType>
+ /** \brief Visit a chunk (i.e., a list of Function, Var, and Type declarations).
+ **
+ ** It is exactly the same in the three cases, so the code is
+ ** factored via a template method. */
+ void chunk_visit(const ChunkType& e);
+
+ // As we can't mix template and virtual methods, we have to
+ // duplicate these methods. That's too bad. :(
+ void operator()(const ast::FunctionChunk&) override;
+ void operator()(const ast::MethodChunk&) override;
+ void operator()(const ast::TypeChunk&) override;
+ void operator()(const ast::VarChunk&) override;
+
+ protected:
+ /// The cloned Ast.
+ ast::Ast* result_;
+ };
+
+} // namespace astclone
+
+#include <astclone/cloner.hxx>
diff --git a/tiger-compiler/src/astclone/cloner.hxx b/tiger-compiler/src/astclone/cloner.hxx
new file mode 100644
index 0000000..9e7d161
--- /dev/null
+++ b/tiger-compiler/src/astclone/cloner.hxx
@@ -0,0 +1,72 @@
+/**
+ ** \file astclone/cloner.hxx
+ ** \brief Template methods of astclone::Cloner.
+ */
+
+#pragma once
+
+#include <ast/libast.hh>
+#include <astclone/cloner.hh>
+
+namespace astclone
+{
+ using namespace ast;
+
+ template <typename T> T* Cloner::recurse(const T& t)
+ {
+ t.accept(*this);
+ T* res = dynamic_cast<T*>(result_);
+ assertion(res);
+ return res;
+ }
+
+ template <typename T> T* Cloner::recurse(const T* const t)
+ {
+ T* res = nullptr;
+ if (t)
+ {
+ t->accept(*this);
+ res = dynamic_cast<T*>(result_);
+ assertion(res);
+ }
+ return res;
+ }
+
+ template <typename CollectionType>
+ CollectionType* Cloner::recurse_collection(const CollectionType& c)
+ {
+ auto res = new CollectionType;
+
+ using elt_type = typename CollectionType::value_type;
+ for (const elt_type& e : c)
+ {
+ e->accept(*this);
+ auto elt = dynamic_cast<elt_type>(result_);
+ assertion(elt);
+ res->emplace_back(elt);
+ }
+
+ return res;
+ }
+
+ template <typename ChunkType> void Cloner::chunk_visit(const ChunkType& e)
+ {
+ const Location& location = e.location_get();
+
+ // The type of the list contained by this node.
+ using elt_type = typename ChunkType::Ds;
+ // The cloned list of declarations.
+ auto decs = new elt_type;
+
+ for (const typename elt_type::value_type& i : e)
+ {
+ i->accept(*this);
+ auto dec = dynamic_cast<typename elt_type::value_type>(result_);
+ assertion(dec);
+ decs->emplace_back(dec);
+ }
+ // The cloned ChunkInterface.
+ result_ = new ChunkType(location, decs);
+ }
+
+} // namespace astclone
diff --git a/tiger-compiler/src/astclone/libastclone.hh b/tiger-compiler/src/astclone/libastclone.hh
new file mode 100644
index 0000000..d62fea9
--- /dev/null
+++ b/tiger-compiler/src/astclone/libastclone.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file astclone/libastclone.hh
+ ** \brief Declare functions and variables exported by the Astclone module.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <ast/fwd.hh>
+
+/// Cloning an ast::Ast.
+namespace astclone
+{
+ /** \brief Make a deep copy of an AST.
+ ** \param tree abstract syntax tree's root.
+ ** \return the cloned AST. */
+ template <typename T> T* clone(const T& tree);
+
+ template <typename A> using applicable = auto(const A&) -> A*;
+
+ template <typename A>
+ using applicable_with_bools = auto(const A&, bool, bool) -> A*;
+
+ template <typename A, typename B>
+ using applicable_object = auto(const A&, const B&) -> A*;
+
+ /// Have the pure function \a f side effect on \a t.
+ template <typename A> void apply(applicable<A> f, std::unique_ptr<A>& t1);
+
+ template <typename A>
+ void apply(applicable_with_bools<A> f,
+ std::unique_ptr<A>& t1,
+ bool cond_1,
+ bool cond_2);
+
+ template <typename A, typename B>
+ void apply(applicable_object<A, B> f, std::unique_ptr<A>& t1, const B& t3);
+
+} // namespace astclone
+
+#include <astclone/libastclone.hxx>
diff --git a/tiger-compiler/src/astclone/libastclone.hxx b/tiger-compiler/src/astclone/libastclone.hxx
new file mode 100644
index 0000000..b6fe380
--- /dev/null
+++ b/tiger-compiler/src/astclone/libastclone.hxx
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <ast/exp.hh>
+#include <astclone/cloner.hh>
+#include <astclone/libastclone.hh>
+
+// Define exported clone functions.
+namespace astclone
+{
+ template <typename T> T* clone(const T& tree)
+ {
+ Cloner clone;
+ clone(tree);
+ return dynamic_cast<T*>(clone.result_get());
+ }
+
+ template <typename A> void apply(applicable<A> f, std::unique_ptr<A>& t1)
+ {
+ A* t2 = f(*t1);
+ t1.reset(t2);
+ }
+
+ template <typename A>
+ void apply(applicable_with_bools<A> f,
+ std::unique_ptr<A>& t1,
+ bool cond_1,
+ bool cond_2)
+ {
+ A* t2 = f(*t1, cond_1, cond_2);
+ t1.reset(t2);
+ }
+
+ template <typename A, typename B>
+ void apply(applicable_object<A, B> f, std::unique_ptr<A>& t1, B& t3)
+ {
+ A* t2 = f(*t1, t3);
+ t1.reset(t2);
+ }
+
+} // namespace astclone
diff --git a/tiger-compiler/src/astclone/local.am b/tiger-compiler/src/astclone/local.am
new file mode 100644
index 0000000..302667b
--- /dev/null
+++ b/tiger-compiler/src/astclone/local.am
@@ -0,0 +1,12 @@
+## astclone module.
+
+src_libtc_la_SOURCES += \
+ %D%/cloner.hh %D%/cloner.hxx %D%/cloner.cc \
+ %D%/libastclone.hh %D%/libastclone.hxx
+
+check_PROGRAMS += %D%/test-cloner
+%C%_test_cloner_LDADD = src/libtc.la
+%C%_test_cloner_CPPFLAGS = $(AM_CPPFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
+
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/astclone/tasks.cc b/tiger-compiler/src/astclone/tasks.cc
new file mode 100644
index 0000000..ae6d973
--- /dev/null
+++ b/tiger-compiler/src/astclone/tasks.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file astclone/tasks.cc
+ ** \brief Astclone module related tasks' implementation.
+ **/
+
+#include <ast/tasks.hh>
+
+#include <astclone/libastclone.hh>
+#define DEFINE_TASKS 1
+#include <astclone/tasks.hh>
+#undef DEFINE_TASKS
+
+#include <common.hh>
+
+namespace astclone::tasks
+{
+ void clone()
+ {
+ ast::ChunkList* ds = ::astclone::clone(*ast::tasks::the_program);
+ if (!ds)
+ task_error() << misc::error::error_type::failure << "Cloning Failed\n"
+ << &misc::error::exit;
+ ast::tasks::the_program.reset(ds);
+ }
+
+} // namespace astclone::tasks
diff --git a/tiger-compiler/src/astclone/tasks.hh b/tiger-compiler/src/astclone/tasks.hh
new file mode 100644
index 0000000..25b346b
--- /dev/null
+++ b/tiger-compiler/src/astclone/tasks.hh
@@ -0,0 +1,20 @@
+/**
+ ** \file astclone/tasks.hh
+ ** \brief Astclone module tasks.
+ */
+
+#pragma once
+
+#include <misc/fwd.hh>
+
+#include <task/libtask.hh>
+
+/// Tasks of the astclone module.
+namespace astclone::tasks
+{
+ TASK_GROUP("2.5 Cloning");
+
+ /// Clone ast::tasks::the_program, and replace it with its copy.
+ TASK_DECLARE("clone", "clone the Ast", clone, "parse");
+
+} // namespace astclone::tasks
diff --git a/tiger-compiler/src/bind/binder.cc b/tiger-compiler/src/bind/binder.cc
new file mode 100644
index 0000000..171e199
--- /dev/null
+++ b/tiger-compiler/src/bind/binder.cc
@@ -0,0 +1,183 @@
+/**
+ ** \file bind/binder.cc
+ ** \brief Implementation for bind/binder.hh.
+ */
+
+#include <ast/all.hh>
+#include <bind/binder.hh>
+
+#include <misc/contract.hh>
+
+namespace bind
+{
+ /*-----------------.
+ | Error handling. |
+ `-----------------*/
+
+ /// The error handler.
+ const misc::error& Binder::error_get() const { return error_; }
+
+ // FIXME DONE: Some code was deleted here.
+ void Binder::operator()(ast::SimpleVar& e)
+ {
+ ast::VarDec* init = scoped_map_var_.get(e.name_get());
+ if (init == nullptr)
+ {
+ err_undef(e.location_get(), e.name_get());
+ return;
+ }
+ e.def_set(init);
+ }
+
+ void Binder::operator()(ast::CallExp& e)
+ {
+ ast::FunctionDec* init = scoped_map_fun_.get(e.name_get());
+ if (init == nullptr)
+ {
+ err_undef(e.location_get(), e.name_get());
+ return;
+ }
+ e.def_set(init);
+ super_type::operator()(e);
+ }
+
+ void Binder::operator()(ast::NameTy& e)
+ {
+ misc::symbol test_string("string");
+ misc::symbol test_int("int");
+ if (e.name_get() == test_int || e.name_get() == test_string)
+ {
+ auto init = scoped_map_ty_.get(e.name_get());
+ e.def_set(init);
+ }
+ else
+ {
+ auto init = scoped_map_ty_.get(e.name_get());
+ if (init == nullptr)
+ {
+ err_type_undef(e.location_get(), e.name_get());
+ return;
+ }
+ e.def_set(init);
+ }
+ }
+
+ void Binder::operator()(ast::WhileExp& e)
+ {
+ bool actual = in_a_while_;
+ e.test_get().accept(*this);
+ loop_.emplace_back(&e);
+ in_a_while_ = true;
+ begin_scope();
+ e.body_get().accept(*this);
+ end_scope();
+ loop_.pop_back();
+ in_a_while_ = actual;
+ }
+
+ void Binder::operator()(ast::ForExp& e)
+ {
+ bool actual = in_a_while_;
+ begin_scope();
+ in_a_while_ = true;
+ e.vardec_get().accept(*this);
+ e.hi_get().accept(*this);
+ loop_.emplace_back(&e);
+ e.body_get().accept(*this);
+ end_scope();
+ loop_.pop_back();
+ in_a_while_ = actual;
+ }
+
+ void Binder::operator()(ast::BreakExp& e)
+ {
+ if (loop_.empty() || !in_a_while_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << e.location_get() << ": 'break' outside any loop\n";
+ }
+ else
+ {
+ e.def_set(loop_.back());
+ }
+ }
+
+ //Declaration of function
+
+ void Binder::operator()(ast::VarDec& e)
+ {
+ bool actual = in_a_while_;
+ scoped_map_var_.put(e.name_get(), &e);
+ in_a_while_ = false;
+ super_type::operator()(e);
+ in_a_while_ = actual;
+ }
+
+ void Binder::operator()(ast::FunctionChunk& e)
+ {
+ chunk_visit<ast::FunctionDec>(e);
+ }
+
+ void Binder::operator()(ast::TypeChunk& e)
+ {
+ chunk_visit<ast::TypeDec>(e);
+ }
+
+ template <class D> void Binder::chunk_visit(ast::Chunk<D>& e)
+ {
+ misc::scoped_map<const misc::symbol, D*> def = misc::scoped_map<const misc::symbol, D*>();
+ for (auto machala : e)
+ {
+ visit_dec_head<D>(*machala);
+ }
+ for (auto dec : e)
+ {
+ auto init = def.get(dec->name_get());
+ if (init == nullptr)
+ {
+ def.put(dec->name_get(), dec);
+ visit_dec_bod<D>(*dec);
+ }
+ else
+ {
+ err_ddec(dec->location_get(), init->location_get(), dec->name_get());
+ }
+ }
+ }
+
+ void Binder::operator()(ast::FunctionDec& e)
+ {
+ if (e.name_get() == "_main")
+ {
+ if (is_main_already_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << "Un deuxieme _main??????\n";
+ return;
+ }
+ is_main_already_ = true;
+ if (in_a_scope_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << "BRADDOCK, je vous préviens, attention ou vous mettez votre _main!!";
+ return;
+ }
+ }
+ scoped_map_fun_.put(e.name_get(), &e);
+ bool scope = in_a_scope_;
+ bool actual = in_a_while_;
+ in_a_while_ = false;
+ in_a_scope_ = true;
+ this->accept(e.result_get());
+ body_func(e);
+ in_a_while_ = actual;
+ in_a_scope_ = scope;
+ }
+
+ void Binder::operator()(ast::TypeDec& e)
+ {
+ scoped_map_ty_.put(e.name_get(), &e);
+ super_type::operator()(e);
+ }
+
+} // namespace bind
diff --git a/tiger-compiler/src/bind/binder.hh b/tiger-compiler/src/bind/binder.hh
new file mode 100644
index 0000000..f5a4ab3
--- /dev/null
+++ b/tiger-compiler/src/bind/binder.hh
@@ -0,0 +1,138 @@
+/**
+ ** \file bind/binder.hh
+ ** \brief Declaration of bind::Binder.
+ **/
+
+#pragma once
+
+#include <unordered_map>
+
+#include <ast/assert-visitor.hh>
+#include <ast/default-visitor.hh>
+#include <ast/object-visitor.hh>
+
+#include <misc/error.hh>
+#include <misc/fwd.hh>
+#include <misc/scoped-map.hh>
+
+namespace bind
+{
+ /** \brief Binding identifier uses to their definitions.
+ **
+ ** When the \c Binder finds a declaration (of a variable/formal, function,
+ ** or type), it keeps a pointer to it. When it finds a use, it binds it
+ ** to its definition, i.e., it annotates it with a pointer to the
+ ** declaration.
+ **
+ ** The \c Binder diagnoses identifier use errors (invalid multiple
+ ** definitions, unbound identifiers etc.).
+ **
+ ** Since identifier bindings depend on scopes, it needs an environment.
+ **
+ ** In the original Tiger by A. Appel, there are two namespaces: on
+ ** the one hand types, and on the other hand functions and variables.
+ ** Here, at EPITA, we will use three name spaces: we will allow
+ ** variables and functions with the same name.
+ **
+ ** Moreover, object constructs make use of two additional name
+ ** spaces: one for class attributes and one for methods (actually
+ ** these two name spaces only live within the scope of a class).
+ **
+ ** Note that this Binder is mainly doing nothing: it is just
+ ** interested in declarations and uses. To avoid writing
+ ** all the methods that `do nothing but walk', it derives
+ ** from \c ast::DefaultVisitor.
+ **/
+ class Binder
+ : public ast::DefaultVisitor
+ , public ast::ObjectVisitor
+ , public ast::AssertVisitor
+ {
+ public:
+ /// Super class type.
+ using super_type = ast::DefaultVisitor;
+ /// Import all the overloaded \c operator() methods.
+ using super_type::operator();
+
+ /// The error handler.
+ const misc::error& error_get() const;
+
+ // FIXME DONE: Some code was deleted here.
+
+ void operator()(ast::SimpleVar& e) override;
+ void operator()(ast::CallExp& e) override;
+ void operator()(ast::WhileExp& e) override;
+ void operator()(ast::ForExp& e) override;
+ void operator()(ast::BreakExp&) override;
+ void operator()(ast::NameTy& e) override;
+
+ // ---------------- //
+ // Visiting /Dec/. //
+ // ---------------- //
+
+ /// Visit Var declarations.
+ void operator()(ast::VarDec& e) override;
+
+ /// Visit Chunk
+ template <class D> void chunk_visit(ast::Chunk<D>& e);
+
+ /// Visit Function declarations.
+ void operator()(ast::FunctionChunk& e) override;
+ void operator()(ast::FunctionDec& e) override;
+ /// Visit Type declarations.
+ void operator()(ast::TypeChunk& e) override;
+ void operator()(ast::TypeDec& e) override;
+
+ Binder();
+
+
+ /// \name Type and Function declarations
+ /// \{
+
+ /// When traversing a function (or a type) we both have to bind
+ /// its body (i.e., we need to enter a new scope and push the
+ /// arguments in it), *and* we have to store the function's
+ /// declaration in the current scope (so that other functions can
+ /// call it).
+
+ /// We first introduce the function's name in the outer
+ /// environment so that the function can call itself recursively.
+ /// In the mean time, we also check for uniqueness. Then, as a
+ /// second step, we process the contents of all the functions
+ /// belonging to the current chunk.
+
+ // FIXME DONE: Some code was deleted here.
+ //function a effect sur les scoped map
+ void body_func(ast::FunctionDec& e);
+ void begin_scope();
+ void end_scope();
+ template <class D> void visit_dec_bod(D& e);
+ template <class D> void visit_dec_head(D& e);
+
+
+ //function that handles error
+ void err_undef(const ast::Location& loc, const misc::symbol& name);
+ void err_type_undef(const ast::Location& loc, const misc::symbol& name);
+ void err_ddec(const ast::Location& loc,
+ const ast::Location& first,
+ const misc::symbol& name);
+ void is_there__main(void);
+
+ protected:
+ /// Binding errors handler.
+ misc::error error_;
+
+ // FIXME DONE: Some code was deleted here (More members).
+ // J'ai copier pretty print en sah
+ template <typename Type> using t = typename Type::type;
+ misc::scoped_map<const misc::symbol, ast::VarDec*> scoped_map_var_;
+ misc::scoped_map<const misc::symbol, ast::TypeDec*> scoped_map_ty_;
+ misc::scoped_map<const misc::symbol, ast::FunctionDec*> scoped_map_fun_;
+ std::vector<ast::Exp*> loop_;
+ bool is_main_already_ = false;
+ bool in_a_while_ = false;
+ bool in_a_scope_ = false;
+ };
+} // namespace bind
+
+#include <bind/binder.hxx>
diff --git a/tiger-compiler/src/bind/binder.hxx b/tiger-compiler/src/bind/binder.hxx
new file mode 100644
index 0000000..0facad9
--- /dev/null
+++ b/tiger-compiler/src/bind/binder.hxx
@@ -0,0 +1,124 @@
+/**
+ ** \file bind/binder.hxx
+ ** \brief Inline methods of bind::Binder.
+ **/
+
+// FIXME DONE: Some code was deleted here.
+
+#pragma once
+
+#include <bind/binder.hh>
+
+namespace bind
+{
+ inline Binder::Binder()
+ {
+ scoped_map_fun_ = misc::scoped_map<const misc::symbol, ast::FunctionDec*>();
+ scoped_map_var_ = misc::scoped_map<const misc::symbol, ast::VarDec*>();
+ scoped_map_ty_ = misc::scoped_map<const misc::symbol, ast::TypeDec*>();
+ loop_ = std::vector<ast::Exp*>();
+ error_ = misc::error();
+ }
+
+ inline void Binder::body_func(ast::FunctionDec& e)
+ {
+ begin_scope();
+ bool tmp = in_a_scope_;
+ in_a_scope_ = true;
+ e.formals_get().accept(*this);
+ this->accept(e.body_get());
+ in_a_scope_ = tmp;
+ end_scope();
+ }
+
+ template <>
+ inline void Binder::visit_dec_head<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ if (e.name_get() == "_main")
+ {
+ if (is_main_already_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << "Un deuxieme _main??????\n";
+ return;
+ }
+ is_main_already_ = true;
+ if (in_a_scope_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << "BRADDOCK, je vous préviens, attention ou vous mettez votre _main!!";
+ return;
+ }
+ }
+ scoped_map_fun_.put(e.name_get(), &e);
+ }
+
+ template <>
+ inline void Binder::visit_dec_bod<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ bool actual = in_a_while_;
+ in_a_while_ = false;
+ this->accept(e.result_get());
+ body_func(e);
+ in_a_while_ = actual;
+ }
+
+ /// @brief visit header so the Ast can know this type exist
+ /// @param e an Dec of a funcrion or ast
+ template <>
+ inline void Binder::visit_dec_head<ast::TypeDec>(ast::TypeDec& e)
+ {
+ scoped_map_ty_.put(e.name_get(), &e);
+ }
+
+ template <>
+ inline void Binder::visit_dec_bod<ast::TypeDec>(ast::TypeDec& e)
+ {
+ super_type::operator()(e);
+ }
+
+ inline void Binder::begin_scope()
+ {
+ scoped_map_fun_.scope_begin();
+ scoped_map_ty_.scope_begin();
+ scoped_map_var_.scope_begin();
+ }
+
+ inline void Binder::end_scope()
+ {
+ scoped_map_fun_.scope_end();
+ scoped_map_ty_.scope_end();
+ scoped_map_var_.scope_end();
+ }
+
+ inline void Binder::err_undef(const ast::Location& loc, const misc::symbol& name)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << loc << ": undeclared variable: " << name << "\n";
+ }
+
+ inline void Binder::err_type_undef(const ast::Location& loc, const misc::symbol& name)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << loc << ": undeclared type: " << name << "\n";
+ }
+
+ inline void Binder::is_there__main()
+ {
+ if (!is_main_already_)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << "Bah bro il est ou ton _main??????\n";
+ }
+ }
+
+ inline void Binder::err_ddec(const ast::Location& loc,
+ const ast::Location& first,
+ const misc::symbol& name)
+ {
+ error_ << misc::error::error_type::bind;
+ error_ << loc << ": redefinition: " << name << "\n";
+ error_ << first << ": first definition\n";
+ }
+
+} // namespace bind \ No newline at end of file
diff --git a/tiger-compiler/src/bind/libbind.cc b/tiger-compiler/src/bind/libbind.cc
new file mode 100644
index 0000000..63dc4ee
--- /dev/null
+++ b/tiger-compiler/src/bind/libbind.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file bind/libbind.cc
+ ** \brief Define exported bind functions.
+ */
+
+
+// FIXME DONE: Some code was deleted here.
+
+#include <ast/ast.hh>
+#include <misc/error.hh>
+
+#include "renamer.hh"
+#include "binder.hh"
+
+namespace bind
+{
+ misc::error bind(ast::ChunkList* d)
+ {
+ Binder bdc = Binder();
+ bdc(d);
+ bdc.is_there__main();
+ return bdc.error_get();
+ }
+
+ misc::error rename(ast::Ast& tree)
+ {
+ Renamer renamer;
+ renamer(tree);
+ return misc::error{};
+ }
+}
diff --git a/tiger-compiler/src/bind/libbind.hh b/tiger-compiler/src/bind/libbind.hh
new file mode 100644
index 0000000..f4b8bb5
--- /dev/null
+++ b/tiger-compiler/src/bind/libbind.hh
@@ -0,0 +1,29 @@
+/**
+** \file bind/libbind.hh
+ ** \brief Interface of the bind module.
+ */
+
+// FIXME DONE: Some code was deleted here.
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+#include <bind/binder.hh>
+
+namespace bind
+{
+ /// \brief Bind the whole ast in place, return the error code
+ ///
+ /// \param last the ast you want to bind
+ ///
+ /// \return a misc::error that serve to indicate possible failure
+ misc::error bind(ast::ChunkList* d);
+
+ /// \brief Rename the whole ast in place
+ ///
+ /// \param ast the ast you want to rename
+ ///
+ /// \return a misc::error that serve to indicate possible failure
+ misc::error rename(ast::Ast& ast);
+} // namespace bind
diff --git a/tiger-compiler/src/bind/local.am b/tiger-compiler/src/bind/local.am
new file mode 100644
index 0000000..ae4d7b4
--- /dev/null
+++ b/tiger-compiler/src/bind/local.am
@@ -0,0 +1,17 @@
+## bind module.
+
+src_libtc_la_SOURCES += \
+ %D%/binder.hh %D%/binder.hxx %D%/binder.cc \
+ %D%/libbind.hh %D%/libbind.cc
+src_libtc_la_SOURCES += \
+ %D%/renamer.hh %D%/renamer.hxx %D%/renamer.cc
+
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
+
+## ------- ##
+## Tests. ##
+## ------- ##
+
+check_PROGRAMS += %D%/test-bind
+%C%_test_bind_LDADD = src/libtc.la
diff --git a/tiger-compiler/src/bind/renamer.cc b/tiger-compiler/src/bind/renamer.cc
new file mode 100644
index 0000000..1f13de0
--- /dev/null
+++ b/tiger-compiler/src/bind/renamer.cc
@@ -0,0 +1,63 @@
+/**
+ ** \file bind/renamer.cc
+ ** \brief Implementation of bind::Renamer.
+ */
+
+#include <bind/renamer.hh>
+
+namespace bind
+{
+ using namespace ast;
+
+ // FIXME DONE: Some code was deleted here.
+
+ void Renamer::operator()(ast::VarDec& e)
+ {
+ if (renames_.find(&e) != renames_.end())
+ super_type::operator()(e);
+ new_name_(&e);
+ e.name_set(renames_.at(&e));
+ super_type::operator()(e);
+ }
+ void Renamer::operator()(ast::TypeDec& e)
+ {
+ if (renames_.find(&e) != renames_.end())
+ super_type::operator()(e);
+ new_name_(&e);
+ e.name_set(renames_.at(&e));
+ super_type::operator()(e);
+ }
+ void Renamer::operator()(ast::FunctionDec& e)
+ {
+ if (e.body_get() == nullptr || e.name_get() == "_main"
+ || renames_.find(&e) != renames_.end())
+ {
+ super_type::operator()(e);
+ return;
+ }
+ new_name_(&e);
+ e.name_set(renames_.at(&e));
+ super_type::operator()(e);
+ }
+ void Renamer::operator()(ast::SimpleVar& e)
+ {
+ if (renames_.find(e.def_get()) != renames_.end())
+ e.name_set(renames_.at(e.def_get()));
+ }
+ void Renamer::operator()(ast::NameTy& e)
+ {
+ if (renames_.find(e.def_get()) != renames_.end())
+ e.name_set(renames_.at(e.def_get()));
+ }
+ void Renamer::operator()(ast::CallExp& e)
+ {
+ if (e.def_get() == nullptr || e.def_get()->body_get() == nullptr
+ || e.name_get() == "_main")
+ super_type::operator()(e);
+ else
+ {
+ e.name_set(renames_.at(e.def_get()));
+ super_type::operator()(e);
+ }
+ }
+} // namespace bind
diff --git a/tiger-compiler/src/bind/renamer.hh b/tiger-compiler/src/bind/renamer.hh
new file mode 100644
index 0000000..f4a1e82
--- /dev/null
+++ b/tiger-compiler/src/bind/renamer.hh
@@ -0,0 +1,62 @@
+/**
+ ** \file bind/renamer.hh
+ ** \brief Implementation of bind::Renamer.
+ */
+
+#pragma once
+
+#include <map>
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+
+namespace bind
+{
+ /// Perform identifier renaming within an AST (in place),
+ /// without support for objects.
+ class Renamer
+ : public ast::DefaultVisitor
+ , public ast::NonObjectVisitor
+ , public ast::NonAssertVisitor
+ {
+ public:
+ using super_type = ast::DefaultVisitor;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ // FIXME DONE: Some code was deleted here.
+
+ // Visit methods.
+ /// \brief Process a declaration body or a usage site.
+ ///
+ /// \a def is the definition site of \e (must be equal to
+ /// \a e if it is a Dec node).
+ template <class E, class Def> void visit(E& e, const Def* def);
+
+ /// \name Visiting definition sites.
+ /// \{
+ // FIXME DONE: Some code was deleted here.
+ void operator()(ast::VarDec& e) override;
+ void operator()(ast::TypeDec& e) override;
+ void operator()(ast::FunctionDec& e) override;
+ /// \}
+
+ /// \name Visiting usage sites.
+ /// \{
+ // FIXME DONE: Some code was deleted here.
+ void operator()(ast::SimpleVar& e) override;
+ void operator()(ast::NameTy& e) override;
+ void operator()(ast::CallExp& e) override;
+ /// \}
+
+ private:
+ // FIXME DONE: Some code was deleted here.
+ std::map<const ast::Dec*, misc::symbol> renames_;
+
+ void new_name_(const ast::Dec*);
+ };
+
+} // namespace bind
+
+#include <bind/renamer.hxx>
diff --git a/tiger-compiler/src/bind/renamer.hxx b/tiger-compiler/src/bind/renamer.hxx
new file mode 100644
index 0000000..f01b7c8
--- /dev/null
+++ b/tiger-compiler/src/bind/renamer.hxx
@@ -0,0 +1,24 @@
+/**
+ ** \file bind/renamer.hxx
+ ** \brief Template methods of bind::Renamer.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <bind/renamer.hh>
+
+namespace bind
+{
+ // FIXME DONE: Some code was deleted here.
+ inline void Renamer::new_name_(const ast::Dec* dec)
+ {
+ renames_.insert_or_assign(dec, misc::symbol::fresh(dec->name_get()));
+ }
+
+ template <class E, class Def> void Renamer::visit(E& e, const Def* def)
+ {
+ // FIXME DONE: Some code was deleted here.
+ operator()(e);
+ }
+} // namespace bind
diff --git a/tiger-compiler/src/bind/tasks.cc b/tiger-compiler/src/bind/tasks.cc
new file mode 100644
index 0000000..6492463
--- /dev/null
+++ b/tiger-compiler/src/bind/tasks.cc
@@ -0,0 +1,34 @@
+/**
+ ** \file bind/tasks.cc
+ ** \brief Bind module tasks implementation.
+ */
+
+// FIXME DONE: Some code was deleted here.
+#include <ast/libast.hh>
+#include <ast/tasks.hh>
+#include <bind/libbind.hh>
+#define DEFINE_TASKS 1
+#include <bind/tasks.hh>
+#undef DEFINE_TASKS
+#include <common.hh>
+
+namespace bind::tasks
+{
+
+ void bind() {
+ misc::error& program_error = task_error();
+ program_error << bind::bind(ast::tasks::the_program.get());
+ program_error.exit_on_error();
+ }
+
+ void display_bind() {
+ ast::bindings_display(std::cout) = true;
+ }
+
+ void rename() {
+ misc::error& program_error = task_error();
+ program_error << bind::rename(*ast::tasks::the_program);
+ program_error.exit_on_error();
+ }
+
+}
diff --git a/tiger-compiler/src/bind/tasks.hh b/tiger-compiler/src/bind/tasks.hh
new file mode 100644
index 0000000..5ad970d
--- /dev/null
+++ b/tiger-compiler/src/bind/tasks.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file bind/tasks.hh
+ ** \brief Bind module related tasks.
+ */
+
+// FIXME DONE: Some code was deleted here.
+#pragma once
+
+#include <task/libtask.hh>
+
+namespace bind::tasks
+{
+ TASK_GROUP("4. Binding");
+
+ // Binding tasks
+ DISJUNCTIVE_TASK_DECLARE("bound",
+ "default the binding to Tiger "
+ "(without objects nor overloading)",
+ "bindings-compute"
+ " combine-bindings-compute"
+ " object-bindings-compute"
+ " assert-bindings-compute");
+
+ TASK_DECLARE("b|bindings-compute",
+ "bind the name uses to their definitions",
+ bind,
+ "parse");
+
+ TASK_DECLARE("B|bindings-display",
+ "enable the bindings display in the next --ast-display "
+ "invocation. does not imply --bindings-compute",
+ display_bind,
+ "");
+
+ // Renaming tasks
+
+ TASK_DECLARE("rename",
+ "rename identifiers",
+ rename,
+ "bindings-compute");
+
+}
diff --git a/tiger-compiler/src/callgraph/call-graph-visitor.cc b/tiger-compiler/src/callgraph/call-graph-visitor.cc
new file mode 100644
index 0000000..6ad31c5
--- /dev/null
+++ b/tiger-compiler/src/callgraph/call-graph-visitor.cc
@@ -0,0 +1,56 @@
+/**
+ ** \file callgraph/call-graph-visitor.cc
+ ** \brief Implementation of callgraph::CallGraphVisitor.
+ **/
+
+#include <ast/call-exp.hh>
+#include <ast/function-dec.hh>
+#include <callgraph/call-graph-visitor.hh>
+
+namespace callgraph
+{
+ const CallGraph* CallGraphVisitor::create(const ast::Ast& tree)
+ {
+ // Create a new empty callgraph
+ callgraph_ = new CallGraph();
+
+ // Launch visitor.
+ tree.accept(*this);
+
+ // Return created callgraph.
+ return callgraph_;
+ }
+
+ CallGraph* CallGraphVisitor::create(ast::Ast& tree)
+ {
+ return const_cast<CallGraph*>(create(const_cast<const ast::Ast&>(tree)));
+ }
+
+ /*-----------.
+ | Visiting. |
+ `-----------*/
+
+ void CallGraphVisitor::operator()(const ast::CallExp& e)
+ {
+ // FIXME: Some code was deleted here (Link the Caller with the CallExp's declaration).
+ }
+
+ void CallGraphVisitor::operator()(const ast::FunctionChunk& e)
+ {
+ // First define the nodes for each defined function.
+ for (ast::FunctionDec* f : e)
+ callgraph_->fundec_add(f);
+ // Now bind callers and callees.
+ super_type::operator()(e);
+ }
+
+ void CallGraphVisitor::operator()(const ast::FunctionDec& e)
+ {
+ // Current function becomes temporarily the caller function.
+ ast::FunctionDec* save = caller;
+ caller = const_cast<ast::FunctionDec*>(&e);
+ super_type::operator()(e);
+ caller = save;
+ }
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/call-graph-visitor.hh b/tiger-compiler/src/callgraph/call-graph-visitor.hh
new file mode 100644
index 0000000..97d79b4
--- /dev/null
+++ b/tiger-compiler/src/callgraph/call-graph-visitor.hh
@@ -0,0 +1,38 @@
+/**
+ ** \file callgraph/call-graph-visitor.hh
+ ** \brief Definition of callgraph::CallGraphVisitor.
+ **/
+#pragma once
+
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <callgraph/fundec-graph.hh>
+
+namespace callgraph
+{
+ /// Computes the CallGraph.
+ class CallGraphVisitor
+ : protected ast::DefaultConstVisitor
+ , protected ast::NonObjectConstVisitor
+ , protected ast::NonAssertConstVisitor
+ {
+ public:
+ using super_type = ast::DefaultConstVisitor;
+ using super_type::operator();
+ const CallGraph* create(const ast::Ast& tree);
+ CallGraph* create(ast::Ast& tree);
+
+ protected:
+ void operator()(const ast::CallExp& e) override;
+ void operator()(const ast::FunctionChunk& e) override;
+ void operator()(const ast::FunctionDec& e) override;
+
+ protected:
+ /// Current function.
+ ast::FunctionDec* caller = nullptr;
+ /// Call graph.
+ CallGraph* callgraph_ = nullptr;
+ };
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/fundec-graph.hh b/tiger-compiler/src/callgraph/fundec-graph.hh
new file mode 100644
index 0000000..1addd0d
--- /dev/null
+++ b/tiger-compiler/src/callgraph/fundec-graph.hh
@@ -0,0 +1,76 @@
+/**
+ ** \file callgraph/fundec-graph.hh
+ ** \brief Declare and define fundec graph.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <boost/graph/adjacency_list.hpp>
+
+#include <ast/function-dec.hh>
+#include <misc/graph.hh>
+
+namespace callgraph
+{
+ /*--------------.
+ | FundecGraph. |
+ `--------------*/
+
+ class FundecGraph : public misc::directed_graph<ast::FunctionDec*>
+ {
+ public:
+ /// Add a vertex to the graph, and attach a function definition to it.
+ void fundec_add(ast::FunctionDec* f);
+ /// Create an edge between two vertices, identified by the
+ /// FunctionDec attached to each of them.
+ void fundec_link(ast::FunctionDec* fu, ast::FunctionDec* fv);
+
+ /// Retrieve the vertex handle corresponding to a FunctionDec.
+ vertex_descriptor hfundec_get(ast::FunctionDec* f) const;
+
+ // Search if FunctionDec 'searched' is 'start' or one of its parent.
+ ast::FunctionDec* hfundec_deep_get(ast::FunctionDec* start,
+ ast::FunctionDec* searched) const;
+
+ protected:
+ /// Print the label of vertex of a graph.
+ std::ostream& vertex_print(vertex_descriptor v,
+ std::ostream& ostr) const override;
+
+ using hfundecs_type = std::map<ast::FunctionDec*, vertex_descriptor>;
+
+ hfundecs_type hfundecs;
+ };
+
+ using CallGraph = FundecGraph;
+ using ParentGraph = FundecGraph;
+
+ /*------------.
+ | Iterators. |
+ `------------*/
+
+ /// Iterator on the vertices of a FundecGraph.
+ using fundecgraph_vertex_iter_type =
+ boost::graph_traits<FundecGraph>::vertex_iterator;
+ /// Iterator on the edges of a FundecGraph.
+ using fundecgraph_edge_iter_type =
+ boost::graph_traits<FundecGraph>::edge_iterator;
+ /// Iterator on the neighborhood of a vertex of a FundecGraph.
+ using fundecgraph_neighb_iter_type =
+ boost::graph_traits<FundecGraph>::adjacency_iterator;
+
+ /// \name Aliases.
+ /// \{
+ /// Iterator on the vertices of a CallGraph.
+ using callgraph_vertex_iter_type = fundecgraph_vertex_iter_type;
+ /// Iterator on the neighborhood of a vertex of a CallGraph.
+ using callgraph_neighb_iter_type = fundecgraph_neighb_iter_type;
+ /// Iterator on the neighborhood of a vertex of a ParentGraph.
+ using parentgraph_neighb_iter_type = fundecgraph_neighb_iter_type;
+ /// \}
+
+} // namespace callgraph
+
+#include <callgraph/fundec-graph.hxx>
diff --git a/tiger-compiler/src/callgraph/fundec-graph.hxx b/tiger-compiler/src/callgraph/fundec-graph.hxx
new file mode 100644
index 0000000..d5d863e
--- /dev/null
+++ b/tiger-compiler/src/callgraph/fundec-graph.hxx
@@ -0,0 +1,56 @@
+/**
+ ** \file callgraph/fundec-graph.hxx
+ ** \brief Inline methods for callgraph/fundec-graph.hh.
+ */
+
+#pragma once
+
+#include <callgraph/fundec-graph.hh>
+
+namespace callgraph
+{
+ inline void FundecGraph::fundec_add(ast::FunctionDec* f)
+ {
+ hfundecs[f] = this->vertex_add(f);
+ }
+
+ inline void FundecGraph::fundec_link(ast::FunctionDec* fu,
+ ast::FunctionDec* fv)
+ {
+ vertex_descriptor u = hfundecs[fu];
+ vertex_descriptor v = hfundecs[fv];
+ boost::add_edge(u, v, *this);
+ }
+
+ inline FundecGraph::vertex_descriptor
+ FundecGraph::hfundec_get(ast::FunctionDec* f) const
+ {
+ hfundecs_type::const_iterator i = hfundecs.find(f);
+ assertion(i != hfundecs.end());
+ return i->second;
+ }
+
+ inline ast::FunctionDec*
+ FundecGraph::hfundec_deep_get(ast::FunctionDec* start,
+ ast::FunctionDec* searched) const
+ {
+ if (start == searched)
+ return searched;
+
+ hfundecs_type::const_iterator i = hfundecs.find(start);
+ parentgraph_neighb_iter_type parent =
+ boost::adjacent_vertices(i->second, *this).first;
+
+ if ((*this)[*parent] == start)
+ return nullptr;
+
+ return hfundec_deep_get((*this)[*parent], searched);
+ }
+
+ inline std::ostream& FundecGraph::vertex_print(vertex_descriptor v,
+ std::ostream& ostr) const
+ {
+ return ostr << (*this)[v]->name_get();
+ }
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/libcallgraph.cc b/tiger-compiler/src/callgraph/libcallgraph.cc
new file mode 100644
index 0000000..be23b16
--- /dev/null
+++ b/tiger-compiler/src/callgraph/libcallgraph.cc
@@ -0,0 +1,36 @@
+/**
+ ** \file callgraph/libcallgraph.cc
+ ** \brief Define exported callgraph functions.
+ */
+
+#include <callgraph/call-graph-visitor.hh>
+#include <callgraph/libcallgraph.hh>
+#include <callgraph/parent-graph-visitor.hh>
+
+#include <misc/contract.hh>
+#include <misc/set.hh>
+
+namespace callgraph
+{
+
+ // Build the callgraph.
+ const CallGraph* callgraph_compute(const ast::Ast& tree)
+ {
+ CallGraphVisitor callgraph_visitor;
+ return callgraph_visitor.create(tree);
+ }
+
+ CallGraph* callgraph_compute(ast::Ast& tree)
+ {
+ CallGraphVisitor callgraph_visitor;
+ return callgraph_visitor.create(tree);
+ }
+
+ // Build the parentgraph.
+ ParentGraph* parentgraph_compute(ast::Ast& tree)
+ {
+ ParentGraphVisitor parentgraph_visitor;
+ return parentgraph_visitor.create(tree);
+ }
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/libcallgraph.hh b/tiger-compiler/src/callgraph/libcallgraph.hh
new file mode 100644
index 0000000..b928bac
--- /dev/null
+++ b/tiger-compiler/src/callgraph/libcallgraph.hh
@@ -0,0 +1,28 @@
+/**
+ ** \file callgraph/libcallgraph.hh
+ ** \brief Declare functions and variables exported by callgraph module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <callgraph/fundec-graph.hh>
+
+/// Computing static link related information.
+namespace callgraph
+{
+
+#ifdef SWIG
+ %newobject callgraph_compute;
+#endif
+ /// Build the callgraph.
+ const CallGraph* callgraph_compute(const ast::Ast& tree);
+ CallGraph* callgraph_compute(ast::Ast& tree);
+
+#ifdef SWIG
+ %newobject parentgraph_compute;
+#endif
+ /// Build the parentgraph.
+ ParentGraph* parentgraph_compute(ast::Ast& tree);
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/local.am b/tiger-compiler/src/callgraph/local.am
new file mode 100644
index 0000000..695075f
--- /dev/null
+++ b/tiger-compiler/src/callgraph/local.am
@@ -0,0 +1,14 @@
+## module callgraph.
+
+# Compiling.
+# Libcallgraph
+src_libtc_la_SOURCES += \
+ %D%/libcallgraph.hh %D%/libcallgraph.cc \
+ %D%/fundec-graph.hh %D%/fundec-graph.hxx \
+ %D%/call-graph-visitor.hh %D%/call-graph-visitor.cc \
+ %D%/parent-graph-visitor.hh %D%/parent-graph-visitor.cc
+
+src_libtc_la_LDFLAGS += $(BOOST_GRAPH_LDFLAGS)
+src_libtc_la_LIBADD += $(BOOST_GRAPH_LIBS)
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/callgraph/parent-graph-visitor.cc b/tiger-compiler/src/callgraph/parent-graph-visitor.cc
new file mode 100644
index 0000000..f99121d
--- /dev/null
+++ b/tiger-compiler/src/callgraph/parent-graph-visitor.cc
@@ -0,0 +1,42 @@
+/**
+ ** \file callgraph/parent-graph-visitor.cc
+ ** \brief Implementation for callgraph::ParentGraphVisitor.
+ **/
+
+#include <ast/function-dec.hh>
+#include <callgraph/parent-graph-visitor.hh>
+
+namespace callgraph
+{
+ ParentGraph* ParentGraphVisitor::create(ast::Ast& tree)
+ {
+ // Create a new empty parentgraph
+ parentgraph = new ParentGraph();
+
+ // Launch visitor.
+ tree.accept(*this);
+
+ // Return created parentgraph.
+ return parentgraph;
+ }
+
+ void ParentGraphVisitor::operator()(ast::FunctionChunk& e)
+ {
+ for (ast::FunctionDec* f : e)
+ {
+ parentgraph->fundec_add(f);
+ parentgraph->fundec_link(f, parent);
+ }
+ super_type::operator()(e);
+ }
+
+ void ParentGraphVisitor::operator()(ast::FunctionDec& e)
+ {
+ // Current function becomes temporarily the parent function.
+ ast::FunctionDec* tmp = parent;
+ parent = &e;
+ super_type::operator()(e);
+ parent = tmp;
+ }
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/parent-graph-visitor.hh b/tiger-compiler/src/callgraph/parent-graph-visitor.hh
new file mode 100644
index 0000000..be16987
--- /dev/null
+++ b/tiger-compiler/src/callgraph/parent-graph-visitor.hh
@@ -0,0 +1,36 @@
+/**
+ ** \file callgraph/parent-graph-visitor.hh
+ ** \brief Definition of callgraph::ParentGraphVisitor.
+ **/
+#pragma once
+
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <callgraph/fundec-graph.hh>
+
+namespace callgraph
+{
+ /// Compute the ParentGraph.
+ class ParentGraphVisitor
+ : public ast::DefaultVisitor
+ , public ast::NonObjectVisitor
+ , public ast::NonAssertVisitor
+ {
+ using super_type = ast::DefaultVisitor;
+ using super_type::operator();
+
+ public:
+ ParentGraph* create(ast::Ast& tree);
+
+ void operator()(ast::FunctionChunk& e) override;
+ void operator()(ast::FunctionDec& e) override;
+
+ protected:
+ /// Current function.
+ ast::FunctionDec* parent = nullptr;
+ /// Parent graph.
+ ParentGraph* parentgraph = nullptr;
+ };
+
+} // namespace callgraph
diff --git a/tiger-compiler/src/callgraph/tasks.cc b/tiger-compiler/src/callgraph/tasks.cc
new file mode 100644
index 0000000..e4d003b
--- /dev/null
+++ b/tiger-compiler/src/callgraph/tasks.cc
@@ -0,0 +1,52 @@
+/**
+ ** \file callgraph/tasks.cc
+ ** \brief Callgraph module related tasks' implementation.
+ */
+
+#include <ostream>
+
+#include <ast/libast.hh>
+#include <ast/tasks.hh>
+#define DEFINE_TASKS 1
+#include <callgraph/tasks.hh>
+#undef DEFINE_TASKS
+#include <callgraph/libcallgraph.hh>
+
+namespace callgraph::tasks
+{
+ /*------------.
+ | CallGraph. |
+ `------------*/
+
+ static std::unique_ptr<CallGraph> callgraph;
+
+ void callgraph_compute()
+ {
+ callgraph.reset(::callgraph::callgraph_compute(*ast::tasks::the_program));
+ }
+
+ void callgraph_dump()
+ {
+ precondition(callgraph.get());
+ callgraph->print("call");
+ }
+
+ /*--------------.
+ | ParentGraph. |
+ `--------------*/
+
+ static std::unique_ptr<ParentGraph> parentgraph;
+
+ void parentgraph_compute()
+ {
+ parentgraph.reset(
+ ::callgraph::parentgraph_compute(*ast::tasks::the_program));
+ }
+
+ void parentgraph_dump()
+ {
+ precondition(parentgraph.get());
+ parentgraph->print("parent");
+ }
+
+} // namespace callgraph::tasks
diff --git a/tiger-compiler/src/callgraph/tasks.hh b/tiger-compiler/src/callgraph/tasks.hh
new file mode 100644
index 0000000..e1fc584
--- /dev/null
+++ b/tiger-compiler/src/callgraph/tasks.hh
@@ -0,0 +1,46 @@
+/**
+ ** \file callgraph/tasks.hh
+ ** \brief Callgraph module related tasks.
+ */
+
+#pragma once
+
+#include <callgraph/fundec-graph.hh>
+#include <task/libtask.hh>
+
+/// The Tasks of the escapes module.
+namespace callgraph::tasks
+{
+ TASK_GROUP("3. Callgraph");
+
+ /*-------------.
+ | Call graph. |
+ `-------------*/
+
+ /// Build the call graph.
+ TASK_DECLARE("callgraph-compute",
+ "build the call graph",
+ callgraph_compute,
+ "bindings-compute");
+ /// Dump the callgraph.
+ TASK_DECLARE("callgraph-dump",
+ "dump the call graph",
+ callgraph_dump,
+ "callgraph-compute");
+
+ /*---------------.
+ | Parent graph. |
+ `---------------*/
+
+ /// Build the parent graph.
+ TASK_DECLARE("parentgraph-compute",
+ "build the parent graph",
+ parentgraph_compute,
+ "parse");
+ /// Dump the parentgraph.
+ TASK_DECLARE("parentgraph-dump",
+ "dump the parent graph",
+ parentgraph_dump,
+ "parentgraph-compute");
+
+} // namespace callgraph::tasks
diff --git a/tiger-compiler/src/combine/binder.cc b/tiger-compiler/src/combine/binder.cc
new file mode 100644
index 0000000..c5fc66e
--- /dev/null
+++ b/tiger-compiler/src/combine/binder.cc
@@ -0,0 +1,17 @@
+/**
+ ** \file combine/combine-binder.cc
+ ** \brief Implementation of combine::Binder.
+ */
+
+#include <ast/all.hh>
+#include <combine/binder.hh>
+
+namespace combine
+{
+ /*---------------.
+ | Visiting Dec. |
+ `---------------*/
+
+ // FIXME: Some code was deleted here.
+
+} // namespace combine
diff --git a/tiger-compiler/src/combine/binder.hh b/tiger-compiler/src/combine/binder.hh
new file mode 100644
index 0000000..1789b47
--- /dev/null
+++ b/tiger-compiler/src/combine/binder.hh
@@ -0,0 +1,16 @@
+/**
+ ** \file combine/binder.hh
+ ** \brief Declaration of combine::Binder.
+ **/
+
+#pragma once
+
+#include <object/binder.hh>
+#include <overload/binder.hh>
+
+namespace combine
+{
+ /// \brief Compute bindings with support for objects and overload.
+ // FIXME: Some code was deleted here (class Binder inheriting from object::Binder and overload::Binder).
+
+} // namespace combine
diff --git a/tiger-compiler/src/combine/libcombine.cc b/tiger-compiler/src/combine/libcombine.cc
new file mode 100644
index 0000000..29834de
--- /dev/null
+++ b/tiger-compiler/src/combine/libcombine.cc
@@ -0,0 +1,26 @@
+/**
+ ** \file combine/libcombine.cc
+ ** \brief Define exported combine functions.
+ */
+
+#include <combine/libcombine.hh>
+
+// FIXME: Some code was deleted here.
+
+namespace combine
+{
+ std::pair<overload::overfun_bindings_type, misc::error>
+ combine_bind(ast::Ast& tree, bool overloads_enabled)
+ {
+ // FIXME: Some code was deleted here.
+ }
+
+ misc::error
+ combine_types_check(ast::Ast& tree,
+ const overload::overfun_bindings_type& combine_bindings,
+ bool overloads_enabled)
+ {
+ // FIXME: Some code was deleted here.
+ }
+
+} // namespace combine
diff --git a/tiger-compiler/src/combine/libcombine.hh b/tiger-compiler/src/combine/libcombine.hh
new file mode 100644
index 0000000..66f3c4c
--- /dev/null
+++ b/tiger-compiler/src/combine/libcombine.hh
@@ -0,0 +1,44 @@
+/**
+ ** \file combine/libcombine.hh
+ ** \brief Declare functions and variables exported by combine module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+#include <overload/binder.hh>
+
+namespace combine
+{
+ /*-------.
+ | Bind. |
+ `-------*/
+
+ /** \brief Bind identifier uses to their definition, allowing
+ function overloading, and return a list of potential definition
+ sites for each function call.
+
+ \param tree AST to bind.
+
+ \return a pair whose first element is the potential function
+ bindings, and the second element the error status. */
+ std::pair<overload::overfun_bindings_type, misc::error>
+ combine_bind(ast::Ast& tree, bool overloads_enabled);
+
+ /*------------------------------.
+ | Compute types with overload. |
+ `------------------------------*/
+
+ /** \brief Check types allowing function overloading.
+
+ \param tree abstract syntax tree's root.
+ \param combine_bindings potential function bindings.
+
+ \return success of the type-checking. */
+ misc::error
+ combine_types_check(ast::Ast& tree,
+ const overload::overfun_bindings_type& combine_bindings,
+ bool overloads_enabled);
+
+} // namespace combine
diff --git a/tiger-compiler/src/combine/local.am b/tiger-compiler/src/combine/local.am
new file mode 100644
index 0000000..7fd348c
--- /dev/null
+++ b/tiger-compiler/src/combine/local.am
@@ -0,0 +1,6 @@
+src_libtc_la_SOURCES += \
+ %D%/libcombine.hh %D%/libcombine.cc \
+ %D%/binder.hh %D%/binder.cc \
+ %D%/type-checker.hh %D%/type-checker.cc
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/combine/tasks.cc b/tiger-compiler/src/combine/tasks.cc
new file mode 100644
index 0000000..48470ac
--- /dev/null
+++ b/tiger-compiler/src/combine/tasks.cc
@@ -0,0 +1,74 @@
+/**
+ ** \file combine/tasks.cc
+ ** \brief Combine module related tasks' implementation.
+ */
+
+#include <ast/tasks.hh>
+#include <bind/tasks.hh>
+#include <desugar/tasks.hh>
+#include <escapes/tasks.hh>
+#include <object/tasks.hh>
+
+#include <astclone/libastclone.hh>
+#include <desugar/libdesugar.hh>
+#include <inlining/libinlining.hh>
+
+#include <common.hh>
+
+#include <combine/libcombine.hh>
+#define DEFINE_TASKS 1
+#include <combine/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace combine::tasks
+{
+ std::unique_ptr<overload::overfun_bindings_type> the_overfun_bindings =
+ nullptr;
+
+ void combine_bindings_compute()
+ {
+ auto result =
+ ::combine::combine_bind(*ast::tasks::the_program, c_overload_p);
+ ::combine::tasks::the_overfun_bindings =
+ std::make_unique<overload::overfun_bindings_type>(
+ std::move(result.first));
+
+ task_error() << result.second << &misc::error::exit_on_error;
+ }
+
+ void combine_types_compute()
+ {
+ task_error() << ::combine::combine_types_check(
+ *ast::tasks::the_program, *::combine::tasks::the_overfun_bindings,
+ c_overload_p);
+ the_overfun_bindings.reset();
+ task_error().exit_on_error();
+ }
+
+ void combine_rename()
+ {
+ // FIXME: Some code was deleted here (Call appropriate renaming tasks).
+ }
+
+ void combine_desugar()
+ {
+ if (c_object_p)
+ ::object::tasks::object_desugar();
+
+ if (c_desugar_p)
+ ::desugar::tasks::desugar();
+
+ if (c_bounds_p)
+ astclone::apply(::desugar::bounds_checks_add, ast::tasks::the_program);
+
+ if (c_inline_p)
+ astclone::apply(::inlining::inline_expand, ast::tasks::the_program);
+
+ if (c_prune_p)
+ astclone::apply(::inlining::prune, ast::tasks::the_program);
+
+ if (c_escapes_p)
+ ::escapes::tasks::escapes_compute();
+ }
+
+} // namespace combine::tasks
diff --git a/tiger-compiler/src/combine/tasks.hh b/tiger-compiler/src/combine/tasks.hh
new file mode 100644
index 0000000..67cc169
--- /dev/null
+++ b/tiger-compiler/src/combine/tasks.hh
@@ -0,0 +1,56 @@
+/**
+ ** \file combine/tasks.hh
+ ** \brief Combine module related tasks.
+ */
+
+#pragma once
+
+#include <overload/binder.hh>
+#include <task/libtask.hh>
+
+namespace combine::tasks
+{
+ TASK_GROUP("Combine");
+
+ BOOLEAN_TASK_DECLARE("c-object", "combine objects", c_object_p, "object");
+ BOOLEAN_TASK_DECLARE("c-bounds", "combine bounds checking", c_bounds_p, "");
+ BOOLEAN_TASK_DECLARE("c-escapes", "combine escapes", c_escapes_p, "");
+ BOOLEAN_TASK_DECLARE("c-desugar",
+ "combine for and string comparison desugaring",
+ c_desugar_p,
+ "desugar-for desugar-string-cmp");
+ BOOLEAN_TASK_DECLARE("c-inline", "combine inlining", c_inline_p, "");
+ BOOLEAN_TASK_DECLARE("c-prune", "combine pruning", c_prune_p, "");
+ BOOLEAN_TASK_DECLARE("c-overload", "combine overloading", c_overload_p, "");
+
+ BOOLEAN_TASK_DECLARE(
+ "a|c-all",
+ "combine all compiler options",
+ c_all_p,
+ "c-object c-bounds c-escapes c-desugar c-inline c-prune c-overload");
+
+ TASK_DECLARE("combine-bindings-compute",
+ "bind the identifiers, "
+ "allowing various compiler options",
+ combine_bindings_compute,
+ "parse");
+
+ TASK_DECLARE("combine-types-compute",
+ "check for type violations, "
+ "allowing various compiler options",
+ combine_types_compute,
+ "combine-bindings-compute");
+
+ TASK_DECLARE("combine-rename",
+ "rename identifiers to unique names, "
+ "allowing various compiler options",
+ combine_rename,
+ "combine-types-compute");
+
+ TASK_DECLARE("c|combine-desugar",
+ "remove object and complex constructs from the program"
+ "allowing various compiler options",
+ combine_desugar,
+ "combine-rename");
+
+} // namespace combine::tasks
diff --git a/tiger-compiler/src/combine/type-checker.cc b/tiger-compiler/src/combine/type-checker.cc
new file mode 100644
index 0000000..67cbfbc
--- /dev/null
+++ b/tiger-compiler/src/combine/type-checker.cc
@@ -0,0 +1,14 @@
+/**
+ ** \file combine/type-checker.cc
+ ** \brief Implementation for combine/type-checker.hh.
+ */
+
+#include <ast/all.hh>
+#include <combine/type-checker.hh>
+#include <type/types.hh>
+
+namespace combine
+{
+ // FIXME: Some code was deleted here.
+
+} // namespace combine
diff --git a/tiger-compiler/src/combine/type-checker.hh b/tiger-compiler/src/combine/type-checker.hh
new file mode 100644
index 0000000..02370d2
--- /dev/null
+++ b/tiger-compiler/src/combine/type-checker.hh
@@ -0,0 +1,20 @@
+/**
+ ** \file combine/type-checker.hh
+ ** \brief Declaration of combine::TypeChecker.
+ */
+
+#pragma once
+
+#include <object/type-checker.hh>
+#include <overload/binder.hh>
+#include <overload/type-checker.hh>
+#include <type/class.hh>
+#include <type/types.hh>
+
+namespace combine
+{
+ /// Perform type checking, allowing objects, and compute
+ /// the bindings of the object's methods and fields.
+ // FIXME: Some code was deleted here (class TypeChecker inheriting from overload::TypeChecker and object::TypeChecker).
+
+} // namespace combine
diff --git a/tiger-compiler/src/common.cc b/tiger-compiler/src/common.cc
new file mode 100644
index 0000000..0375220
--- /dev/null
+++ b/tiger-compiler/src/common.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file common.cc
+ ** \brief Common definitions.
+ */
+
+#include <common.hh>
+
+// Sole argument: the file to process.
+const char* filename;
+
+// The current state of and error.
+misc::error& task_error()
+{
+ static misc::error task_error_;
+ return task_error_;
+}
+
+// Counting the time spent in the various tasks.
+misc::timer task_timer;
diff --git a/tiger-compiler/src/common.hh b/tiger-compiler/src/common.hh
new file mode 100644
index 0000000..ca647a9
--- /dev/null
+++ b/tiger-compiler/src/common.hh
@@ -0,0 +1,49 @@
+/**
+ ** \file src/common.hh
+ ** \brief Definitions common to the whole task system.
+ **
+ ** These variables are global. As such they should not be used
+ ** in the libraries, but only in the "imperative" subsystem: the
+ ** tasks.
+ */
+
+#pragma once
+
+#include <misc/error.hh>
+#include <misc/timer.hh>
+
+#ifdef SWIG
+// Warning 451: Setting a const char * variable may leak memory.
+%warnfilter(451) program_name;
+%warnfilter(451) program_version;
+%warnfilter(451) program_bug_address;
+%warnfilter(451) program_doc;
+%warnfilter(451) program_args_doc;
+%warnfilter(451) filename;
+#endif /* ! SWIG */
+
+/// \name Program identity.
+/// \{
+/// Name of this program.
+extern const char* program_name;
+
+/// Version string of this program.
+extern const char* program_version;
+
+/// Bug report address of this program.
+extern const char* program_bug_address;
+
+/// Describe program and accepted arguments.
+extern const char* program_doc;
+extern const char* program_args_doc;
+
+/// \}
+
+/// Timing the tasks.
+extern misc::timer task_timer;
+
+/// Sole argument: the file to process.
+extern const char* filename;
+
+/// The current state of error.
+extern misc::error& task_error();
diff --git a/tiger-compiler/src/desugar/bounds-checking-visitor.cc b/tiger-compiler/src/desugar/bounds-checking-visitor.cc
new file mode 100644
index 0000000..30f691e
--- /dev/null
+++ b/tiger-compiler/src/desugar/bounds-checking-visitor.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file desugar/bounds-checking-visitor.cc
+ ** \brief Implementation of desugar::BoundsCheckingVisitor.
+ */
+
+#include <ast/all.hh>
+#include <ast/libast.hh>
+#include <desugar/bounds-checking-visitor.hh>
+#include <misc/symbol.hh>
+#include <parse/libparse.hh>
+
+namespace desugar
+{
+ namespace
+ {
+ /// Return the name of the boxed type for \a s.
+ std::string box(misc::symbol s) { return "_box_" + s.get(); }
+
+ } // namespace
+
+ BoundsCheckingVisitor::BoundsCheckingVisitor()
+ : super_type()
+ {}
+
+ /*-----------------------.
+ | Array bounds checking. |
+ `-----------------------*/
+
+ // FIXME: Some code was deleted here.
+
+} // namespace desugar
diff --git a/tiger-compiler/src/desugar/bounds-checking-visitor.hh b/tiger-compiler/src/desugar/bounds-checking-visitor.hh
new file mode 100644
index 0000000..65e955d
--- /dev/null
+++ b/tiger-compiler/src/desugar/bounds-checking-visitor.hh
@@ -0,0 +1,46 @@
+/**
+ ** \file desugar/bounds-checking-visitor.hh
+ ** \brief Declaration of desugar::BoundsCheckingVisitor.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <astclone/cloner.hh>
+#include <parse/tweast.hh>
+
+namespace desugar
+{
+ /// \brief Add dynamic array bounds checks while duplicating an AST.
+ class BoundsCheckingVisitor : public astclone::Cloner
+ {
+ public:
+ /// Parent type.
+ using super_type = astclone::Cloner;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a BoundsCheckingVisitor.
+ BoundsCheckingVisitor();
+
+ /// \name Visit methods.
+ /// \{
+ // FIXME: Some code was deleted here.
+ /// \}
+
+ private:
+ /// The bounds checking runtime.
+ ///
+ /// Additional definitions to insert in the prelude.
+ static const std::string prelude;
+
+ // Symbols would be nicer, but maps of symbols are
+ // inconvenient since there is no default ctor.
+ using boxes_type = std::map<const type::Array*, std::string>;
+ /// Map from an array type to the corresponding `box' type name.
+ boxes_type boxes_;
+ };
+
+} // namespace desugar
diff --git a/tiger-compiler/src/desugar/desugar-visitor.cc b/tiger-compiler/src/desugar/desugar-visitor.cc
new file mode 100644
index 0000000..770cdf6
--- /dev/null
+++ b/tiger-compiler/src/desugar/desugar-visitor.cc
@@ -0,0 +1,144 @@
+/**
+ ** \file desugar/desugar-visitor.cc
+ ** \brief Implementation of desugar::DesugarVisitor.
+ */
+
+#include <ast/all.hh>
+#include <ast/libast.hh>
+#include <desugar/desugar-visitor.hh>
+#include <misc/algorithm.hh>
+#include <misc/symbol.hh>
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+
+namespace desugar
+{
+ DesugarVisitor::DesugarVisitor(bool desugar_for_p, bool desugar_string_cmp_p)
+ : super_type()
+ , desugar_for_p_(desugar_for_p)
+ , desugar_string_cmp_p_(desugar_string_cmp_p)
+ {}
+
+ /*-----------------------------.
+ | Desugar string comparisons. |
+ `-----------------------------*/
+ void DesugarVisitor::operator()(const ast::OpExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // Check to see that all of the elements to operate on are strings
+ if (dynamic_cast<const type::String*>(e.left_get().type_get()) == nullptr
+ || dynamic_cast<const type::String*>(e.right_get().type_get()) == nullptr)
+ {
+ return super_type::operator()(e);
+ }
+
+ const auto left = recurse(e.left_get());
+ const auto right = recurse(e.right_get());
+
+ misc::variant<ast::Exp*, ast::ChunkList*> res;
+
+ switch (e.oper_get())
+ {
+ case ast::OpExp::Oper::eq:
+ {
+ res = parse::parse(parse::Tweast() << "streq(" << left << ", " << right << ") = 0");
+ break;
+ }
+ case ast::OpExp::Oper::ne:
+ {
+ res = parse::parse(parse::Tweast() << "streq(" << left << ", " << right << ") <> 0");
+ break;
+ }
+ case ast::OpExp::Oper::lt:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") = -1");
+ break;
+ }
+ case ast::OpExp::Oper::le:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") <= 0");
+ break;
+ }
+ case ast::OpExp::Oper::gt:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") = 1");
+ break;
+ }
+ case ast::OpExp::Oper::ge:
+ {
+ res = parse::parse(parse::Tweast() << "strcmp(" << left << ", " << right << ") >= 0");
+ break;
+ }
+ default:
+ break;
+ }
+
+ ast::Exp* final = std::get<ast::Exp*>(res);
+ result_ = final;
+ }
+
+ /*----------------------.
+ | Desugar `for' loops. |
+ `----------------------*/
+
+ /*<<-
+ Desugar `for' loops as `while' loops:
+
+ for i := lo to hi do
+ body
+
+ is transformed as:
+
+ let
+ var _lo := lo
+ var _hi := hi
+ var i := _lo
+ in
+ if i <= _hi then
+ while 1 do
+ (
+ body;
+ if i = _hi then
+ break;
+ i := i + 1
+ )
+ end
+
+ Notice that:
+
+ - a `_hi' variable is introduced so that `hi' is evaluated only
+ once;
+
+ - a `_lo' variable is introduced to prevent `i' from being in the
+ scope of `_hi';
+
+ - a first test is performed before entering the loop, so that the
+ loop condition becomes `i < _hi' (instead of `i <= _hi'); this
+ is done to prevent overflows on INT_MAX.
+ ->>*/
+
+ void DesugarVisitor::operator()(const ast::ForExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ auto var_init = recurse(e.vardec_get().init_get());
+ auto lim = recurse(e.hi_get());
+ auto body = recurse(e.body_get());
+ auto iterator = e.vardec_get().name_get();
+ auto res = parse::parse(parse::Tweast() << "let "
+ "var _lo := " << var_init <<
+ " var _hi := " << lim <<
+ " var " << iterator << " := _lo "
+ "in "
+ "if " << iterator << " <= _hi then "
+ "while 1 do "
+ "( " << body << ";"
+ "if " << iterator << " = _hi then "
+ "break;"
+ << iterator << " := " << iterator << " + 1 "
+ ") "
+ "end");
+ ast::Exp* final = std::get<ast::Exp*>(res);
+ result_ = final;
+ }
+
+} // namespace desugar
diff --git a/tiger-compiler/src/desugar/desugar-visitor.hh b/tiger-compiler/src/desugar/desugar-visitor.hh
new file mode 100644
index 0000000..c6eee69
--- /dev/null
+++ b/tiger-compiler/src/desugar/desugar-visitor.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file desugar/desugar-visitor.hh
+ ** \brief Declaration of desugar::DesugarVisitor.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <astclone/cloner.hh>
+
+namespace desugar
+{
+ /// \brief Desugar some syntactic structures while duplicating an Ast.
+ class DesugarVisitor : public astclone::Cloner
+ {
+ public:
+ /// Superclass.
+ using super_type = astclone::Cloner;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a DesugarVisitor.
+ DesugarVisitor(bool desugar_for_p, bool desugar_string_cmp_p);
+
+ /// \name Visit methods.
+ /// \{
+ /// Desugar string comparisons.
+ void operator()(const ast::OpExp&) override;
+ /// Desugar `for' loops as `while' loops.
+ void operator()(const ast::ForExp&) override;
+ /// \}
+
+ private:
+ /// Desugar `for' loops?
+ bool desugar_for_p_;
+ /// Desugar string comparisons?
+ bool desugar_string_cmp_p_;
+ };
+
+} // namespace desugar
diff --git a/tiger-compiler/src/desugar/libdesugar.hh b/tiger-compiler/src/desugar/libdesugar.hh
new file mode 100644
index 0000000..d758ed2
--- /dev/null
+++ b/tiger-compiler/src/desugar/libdesugar.hh
@@ -0,0 +1,85 @@
+/**
+ ** \file desugar/libdesugar.hh
+ ** \brief Declare functions exported by the desugar module.
+ */
+
+#pragma once
+
+#include <misc/error.hh>
+
+/// Desugaring an ast::Ast.
+namespace desugar
+{
+ /*----------.
+ | Helpers. |
+ `----------*/
+
+ /// Recompute the bindings and the types of the AST \a tree.
+ ///
+ /// Raise an Internal Compiler Error on failure.
+ template <typename A> void bind_and_types_check(A& tree);
+
+ /*----------.
+ | Desugar. |
+ `----------*/
+
+ /** \brief Remove the syntactic sugar from an AST.
+
+ \param tree abstract syntax tree's root, whose bindings
+ and types have been computed, and whose
+ identifiers are all unique.
+ \param desugar_for_p desugar `for' loops.
+ \param desugar_string_cmp_p desugar string comparisons.
+
+ \return the desugared, bound and type-checked AST. */
+ template <typename A>
+ A* desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p);
+
+ /** \brief Remove the syntactic sugar from an AST without
+ recomputing its bindings nor its types.
+
+ This function acts like desugar::desugar, but stops just after
+ the desugaring step (in fact, desugar::desugar is built upon
+ this function). It is meant to be used as a test of
+ DesugarVisitor (i.e., even if the desugared tree is badly bound
+ or typed, it can still be pretty-printed).
+
+ \param tree AST to desugar.
+ \param desugar_for_p desugar `for' loops.
+ \param desugar_string_cmp_p desugar string comparisons.
+
+ \return the desugared AST. */
+ template <typename A>
+ A* raw_desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p);
+
+ /*-----------------------.
+ | Array bounds checking. |
+ `-----------------------*/
+
+ /** \brief Add runtime checks of array bounds.
+
+ \param tree abstract syntax tree's root, whose bindings and types
+ have been computed, and whose identifiers are all unique.
+
+ \return the AST with bounds checks, with bindings and type-checked. */
+
+ template <typename A> A* bounds_checks_add(const A& tree);
+
+ /** \brief Remove the syntactic sugar from an AST without
+ recomputing its bindings nor its types.
+
+ This function acts like desugar::bounds_checks_add, but stops
+ just after the tranformation step (in fact,
+ desugar::bounds_checks_add is built upon this function). It is
+ meant to be used as a test of BoundsCheckingVisitor (i.e., even
+ if the tree with bounds checks is badly bound or typed, it can
+ still be pretty-printed).
+
+ \param tree AST on which bounds checks are to be added
+
+ \return the AST with bounds checks. */
+ template <typename A> A* raw_bounds_checks_add(const A& tree);
+
+} // namespace desugar
+
+#include <desugar/libdesugar.hxx>
diff --git a/tiger-compiler/src/desugar/libdesugar.hxx b/tiger-compiler/src/desugar/libdesugar.hxx
new file mode 100644
index 0000000..191bd8d
--- /dev/null
+++ b/tiger-compiler/src/desugar/libdesugar.hxx
@@ -0,0 +1,95 @@
+#pragma once
+
+/**
+ ** \file desugar/libdesugar.hxx
+ ** \brief Functions exported by the desugar module.
+ */
+
+#include <memory>
+
+#include <ast/chunk-list.hh>
+#include <ast/exp.hh>
+#include <bind/libbind.hh>
+#include <desugar/bounds-checking-visitor.hh>
+#include <desugar/desugar-visitor.hh>
+#include <desugar/libdesugar.hh>
+#include <escapes/libescapes.hh>
+#include <overload/liboverload.hh>
+#include <type/libtype.hh>
+
+namespace desugar
+{
+ /*----------.
+ | Helpers. |
+ `----------*/
+
+ template <typename A> void bind_and_types_check(A& tree)
+ {
+ misc::error e;
+ // FIXME DONE: Some code was deleted here.
+ e << bind::bind(&tree);
+ e.ice_on_error_here();
+ e << type::types_check(tree);
+ e.ice_on_error_here();
+ }
+
+ // Explicit instantiation.
+ template void bind_and_types_check<ast::ChunkList>(ast::ChunkList&);
+
+ /*----------.
+ | Desugar. |
+ `----------*/
+
+ template <typename A>
+ A* raw_desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p)
+ {
+ // Desugar.
+ DesugarVisitor desugar(desugar_for_p, desugar_string_cmp_p);
+ desugar(tree);
+ return dynamic_cast<A*>(desugar.result_get());
+ }
+
+ template <typename A>
+ A* desugar(const A& tree, bool desugar_for_p, bool desugar_string_cmp_p)
+ {
+ // Desugar.
+ A* desugared = raw_desugar(tree, desugar_for_p, desugar_string_cmp_p);
+ assertion(desugared);
+ std::unique_ptr<A> desugared_ptr(desugared);
+ // Recompute the bindings and the types.
+ bind_and_types_check(*desugared_ptr);
+ return desugared_ptr.release();
+ }
+
+ /// Explicit instantiations.
+ template ast::ChunkList* raw_desugar(const ast::ChunkList&, bool, bool);
+ template ast::ChunkList* desugar(const ast::ChunkList&, bool, bool);
+
+ /*-----------------------.
+ | Array bounds checking. |
+ `-----------------------*/
+
+ template <typename A> A* raw_bounds_checks_add(const A& tree)
+ {
+ // Add array bounds checking code.
+ BoundsCheckingVisitor add_bounds_checks;
+ add_bounds_checks(tree);
+ return dynamic_cast<A*>(add_bounds_checks.result_get());
+ }
+
+ template <typename A> A* bounds_checks_add(const A& tree)
+ {
+ // Add bounds checks.
+ A* transformed = raw_bounds_checks_add(tree);
+ assertion(transformed);
+ std::unique_ptr<A> transformed_ptr(transformed);
+ // Recompute the bindings and the types.
+ bind_and_types_check(*transformed_ptr);
+ return transformed_ptr.release();
+ }
+
+ /// Explicit instantiations.
+ template ast::ChunkList* raw_bounds_checks_add(const ast::ChunkList&);
+ template ast::ChunkList* bounds_checks_add(const ast::ChunkList&);
+
+} // namespace desugar
diff --git a/tiger-compiler/src/desugar/local.am b/tiger-compiler/src/desugar/local.am
new file mode 100644
index 0000000..701d537
--- /dev/null
+++ b/tiger-compiler/src/desugar/local.am
@@ -0,0 +1,27 @@
+## desugar module.
+src_libtc_la_SOURCES += \
+ %D%/desugar-visitor.hh %D%/desugar-visitor.cc \
+ %D%/libdesugar.hh %D%/libdesugar.hxx
+
+check_PROGRAMS += \
+ %D%/test-string-cmp-desugar \
+ %D%/test-for-loops-desugar
+
+
+
+%C%_test_string_cmp_desugar_LDADD = src/libtc.la
+%C%_test_string_cmp_desugar_CPPFLAGS = $(AM_CPPFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
+
+%C%_test_for_loops_desugar_LDADD = src/libtc.la
+%C%_test_for_loops_desugar_CPPFLAGS = $(AM_CPPFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
+
+src_libtc_la_SOURCES += \
+ %D%/bounds-checking-visitor.hh %D%/bounds-checking-visitor.cc
+
+check_PROGRAMS += \
+ %D%/test-bounds-checking
+
+%C%_test_bounds_checking_LDADD = src/libtc.la
+%C%_test_bounds_checking_CPPFLAGS = $(AM_CPPFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/desugar/tasks.cc b/tiger-compiler/src/desugar/tasks.cc
new file mode 100644
index 0000000..0b83cb7
--- /dev/null
+++ b/tiger-compiler/src/desugar/tasks.cc
@@ -0,0 +1,49 @@
+/**
+ ** \file desugar/tasks.cc
+ ** \brief Desugar module related tasks' implementation.
+ **/
+
+#include <ast/tasks.hh>
+#include <astclone/libastclone.hh>
+#include <common.hh>
+#include <desugar/libdesugar.hh>
+#define DEFINE_TASKS 1
+#include <desugar/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace desugar::tasks
+{
+ /*-------------.
+ | Desugaring. |
+ `-------------*/
+
+ void desugar()
+ {
+ astclone::apply(::desugar::desugar, ast::tasks::the_program, desugar_for_p,
+ desugar_string_cmp_p);
+ /// Escape after desugaring if escape was done before
+ if (escapes::escaped)
+ escapes::escapes_compute(*ast::tasks::the_program);
+ }
+
+ void raw_desugar()
+ {
+ astclone::apply(::desugar::raw_desugar, ast::tasks::the_program,
+ desugar_for_p, desugar_string_cmp_p);
+ }
+
+ /*-----------------------.
+ | Array bounds checking. |
+ `-----------------------*/
+
+ void bounds_checks_add()
+ {
+ astclone::apply(::desugar::bounds_checks_add, ast::tasks::the_program);
+ }
+
+ void raw_bounds_checks_add()
+ {
+ astclone::apply(::desugar::raw_bounds_checks_add, ast::tasks::the_program);
+ }
+
+} // namespace desugar::tasks
diff --git a/tiger-compiler/src/desugar/tasks.hh b/tiger-compiler/src/desugar/tasks.hh
new file mode 100644
index 0000000..44a68e6
--- /dev/null
+++ b/tiger-compiler/src/desugar/tasks.hh
@@ -0,0 +1,75 @@
+/**
+ ** \file desugar/tasks.hh
+ ** \brief Desugar module tasks.
+ */
+
+#pragma once
+
+#include <config.h>
+#include <misc/fwd.hh>
+#include <task/libtask.hh>
+
+/// Tasks of the desugar module.
+namespace desugar::tasks
+{
+ TASK_GROUP("Desugaring and bounds-checking");
+
+ /*-------------.
+ | Desugaring. |
+ `-------------*/
+
+ /// Enable translation of `for' loops into `while' loops.
+ BOOLEAN_TASK_DECLARE("desugar-for", "desugar `for' loops", desugar_for_p, "");
+
+ /// Enable string comparison desugaring.
+ BOOLEAN_TASK_DECLARE("desugar-string-cmp",
+ "desugar string comparisons",
+ desugar_string_cmp_p,
+ "");
+
+ /// Default the removal of syntactic sugar from the AST to Tiger
+ /// (without overloading).
+ DISJUNCTIVE_TASK_DECLARE("desugared",
+ "Default the removal of syntactic sugar "
+ "from the AST to Tiger (without overloading)",
+ " assert-desugar"
+ " desugar");
+
+ /// Remove syntactic sugar from the Ast.
+ TASK_DECLARE("desugar", "desugar the AST", desugar, "types-compute rename");
+
+ /* FIXME: Careful with this options (and with
+ --raw-bounds-checks-add), as they leave the AST in a bad state
+ (without bindings nor types). For instance,
+
+ tc --raw-desugar -H will probably result in a SEGV.
+
+ since hir-compute wants a type-checked AST. */
+
+ /// Remove syntactic sugar from the AST without recomputing
+ /// bindings nor types.
+ TASK_DECLARE("raw-desugar",
+ "desugar the AST without recomputing "
+ "bindings nor types",
+ raw_desugar,
+ "typed rename");
+
+ /*-----------------------.
+ | Array bounds checking. |
+ `-----------------------*/
+
+ /// Enable emission of dynamic array bounds checking code.
+ TASK_DECLARE("bounds-checks-add",
+ "add dynamic bounds checks",
+ bounds_checks_add,
+ "types-compute rename");
+
+ /// Enable emission of dynamic array bounds checking code without
+ /// recomputing bindings nor types.
+ TASK_DECLARE("raw-bounds-checks-add",
+ "add bounds-checking to the AST without recomputing "
+ "bindings nor types",
+ raw_bounds_checks_add,
+ "typed rename");
+
+} // namespace desugar::tasks
diff --git a/tiger-compiler/src/doc.hh b/tiger-compiler/src/doc.hh
new file mode 100644
index 0000000..e629911
--- /dev/null
+++ b/tiger-compiler/src/doc.hh
@@ -0,0 +1,23 @@
+/**
+
+\mainpage
+
+These pages document the implementation of the EPITA Tiger Compiler
+Project (http://tiger.lrde.epita.fr).
+
+This very important project in the EPITA curriculum consists in the
+implementation of a Tiger compiler in C++. The Tiger language is
+described by Andrew Appel in his "Modern Compiler Implementation"
+books.
+
+Most of the material students need to implement their Tiger Project is
+to be found in the http://www.lrde.epita.fr/~tiger/ directory. In
+particular, reading http://www.lrde.epita.fr/~tiger/assignments.html
+is mandatory.
+
+The reader will find more information in various places listed on
+http://tiger.lrde.epita.fr/.
+
+*/
+
+Local Variables : mode : text End:
diff --git a/tiger-compiler/src/escapes/escapes-visitor.cc b/tiger-compiler/src/escapes/escapes-visitor.cc
new file mode 100644
index 0000000..f0fd5e2
--- /dev/null
+++ b/tiger-compiler/src/escapes/escapes-visitor.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file escapes/escapes-visitor.cc
+ ** \brief Implementation for escapes/escapes-visitor.hh.
+ */
+
+#include <ast/all.hh>
+#include <escapes/escapes-visitor.hh>
+#include <misc/contract.hh>
+
+namespace escapes
+{
+ // FIXME DONE: Some code was deleted here.
+
+ void EscapesVisitor::operator()(ast::SimpleVar& e)
+ {
+ if (depth_map_.at(e.def_get()) < current_depth_)
+ e.def_get()->escape_set(true);
+ }
+ void EscapesVisitor::operator()(ast::VarDec& e)
+ {
+ e.escape_set(false);
+ depth_map_.insert_or_assign(&e, current_depth_);
+ super_type::operator()(e);
+ }
+ void EscapesVisitor::operator()(ast::FunctionDec& e)
+ {
+ current_depth_++;
+ super_type::operator()(e);
+ current_depth_--;
+ }
+} // namespace escapes
diff --git a/tiger-compiler/src/escapes/escapes-visitor.hh b/tiger-compiler/src/escapes/escapes-visitor.hh
new file mode 100644
index 0000000..3b4023f
--- /dev/null
+++ b/tiger-compiler/src/escapes/escapes-visitor.hh
@@ -0,0 +1,75 @@
+/**
+ ** \file escapes/escapes-visitor.hh
+ ** \brief Compute the escapes.
+ **
+ ** Variables and formals of a function may escape, i.e., be accessed
+ ** by an inner function.
+ **
+ ** When the semantic analysis finds a declaration of variable or
+ ** formal FOO, it needs to know whether it escapes or not. This
+ ** requires an additional pass, before the semantic analysis, just to
+ ** spot the potential escapes of FOO.
+ **
+ ** In order to pass the result to the semantic analysis which walks
+ ** across the ast, the most natural and easy solution consists in
+ ** tagging the various VarDec and Field.
+ **
+ ** Now, how shall we compute the escapes?
+ ** The answer is obvious: we need to walk the ast, searching for variables
+ ** declared then accessed by an inner function.
+ **
+ ** If a variable is accessed from a nested function
+ **
+ ** 2è possibilité :
+ ** - Aucune n'échappe
+ ** - Echappe si accessed dans une fonction nestée
+ ** Attention
+ */
+
+#pragma once
+
+#include <map>
+
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+
+namespace escapes
+{
+ /** \brief Compute the escapes.
+ **
+ ** The EscapeVisitor is extremely similar to type::TypeChecker:
+ ** in its course of operation it must relate uses to
+ ** definitions. Therefore it will be run after the bind::Binder.
+ ** It also needs auxiliary information about the definitions (their
+ ** depth): a simple map suffices, since scoping issues were handled
+ ** by the bind::Binder.
+ **
+ ** Note that this EscapesVisitor is mainly doing nothing: it is just
+ ** interested in declaration and uses of variables/formals (and, of
+ ** course, function declaration...). It would be somewhat stupid to
+ ** write all the methods that `do nothing but walk'. This is why we
+ ** will inherit from the non const ast::DefaultVisitor.
+ **/
+ class EscapesVisitor
+ : public ast::DefaultVisitor
+ , public ast::NonObjectVisitor
+ , public ast::NonAssertVisitor
+ {
+ public:
+ /// Super class type.
+ using super_type = ast::DefaultVisitor;
+ /// Import all the overloaded visit methods.
+ using super_type::operator();
+
+ // FIXME DONE: Some code was deleted here.
+ void operator()(ast::SimpleVar& e) override;
+ void operator()(ast::VarDec& e) override;
+ void operator()(ast::FunctionDec& e) override;
+ protected:
+ std::map<ast::VarDec*, size_t> depth_map_;
+ private:
+ size_t current_depth_ = 0;
+ };
+
+} // namespace escapes
diff --git a/tiger-compiler/src/escapes/libescapes.cc b/tiger-compiler/src/escapes/libescapes.cc
new file mode 100644
index 0000000..6124d54
--- /dev/null
+++ b/tiger-compiler/src/escapes/libescapes.cc
@@ -0,0 +1,23 @@
+/**
+ ** \file escapes/libescapes.cc
+ ** \brief Define exported escapes functions.
+ */
+
+#include <escapes/escapes-visitor.hh>
+#include <escapes/libescapes.hh>
+
+namespace escapes
+{
+ /** Walk the tree, and set the escape flag of variables and arguments
+ if they do escape. */
+ void escapes_compute(ast::Ast& tree)
+ {
+ /// boolean to check if an escapes pass was done in desugar
+ escapes::escaped = true;
+ EscapesVisitor escapes_compute;
+ escapes_compute(tree);
+ }
+
+ bool escaped = false;
+
+} // namespace escapes
diff --git a/tiger-compiler/src/escapes/libescapes.hh b/tiger-compiler/src/escapes/libescapes.hh
new file mode 100644
index 0000000..2d3dd73
--- /dev/null
+++ b/tiger-compiler/src/escapes/libescapes.hh
@@ -0,0 +1,23 @@
+/**
+ ** \file escapes/libescapes.hh
+ ** \brief Declare functions and variables exported by escapes module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+
+/// Computing escape and static link related information.
+namespace escapes
+{
+ /// Compute the escaping variables.
+ void escapes_compute(ast::Ast& tree);
+
+ /// This boolean is used to know whether escape pass
+ /// was made
+ /// FIXME: this is a dirty fix it should be replaced with a
+ /// new implementation of tasks
+ extern bool escaped;
+
+} // namespace escapes
diff --git a/tiger-compiler/src/escapes/local.am b/tiger-compiler/src/escapes/local.am
new file mode 100644
index 0000000..ab6c63a
--- /dev/null
+++ b/tiger-compiler/src/escapes/local.am
@@ -0,0 +1,7 @@
+## escape module.
+
+src_libtc_la_SOURCES += \
+ %D%/libescapes.hh %D%/libescapes.cc \
+ %D%/escapes-visitor.hh %D%/escapes-visitor.cc
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/escapes/tasks.cc b/tiger-compiler/src/escapes/tasks.cc
new file mode 100644
index 0000000..42e6919
--- /dev/null
+++ b/tiger-compiler/src/escapes/tasks.cc
@@ -0,0 +1,38 @@
+/**
+ ** \file escapes/tasks.cc
+ ** \brief Escapes module related tasks' implementation.
+ */
+
+#include <ostream>
+
+#include <ast/libast.hh>
+#include <ast/tasks.hh>
+#include <escapes/libescapes.hh>
+#define DEFINE_TASKS 1
+#include <escapes/tasks.hh>
+#undef DEFINE_TASKS
+#include <misc/xalloc.hh>
+
+namespace escapes::tasks
+{
+
+ /*--------------------.
+ | Static Link tasks. |
+ `--------------------*/
+
+ void escapes_compute() { escapes::escapes_compute(*ast::tasks::the_program); }
+
+ /* WARNING. It is very tempting to use BOOLEAN_TASK_DECLARE with
+ these stream flags, since it factors out the need for the
+ following routines. Unfortunately when the Tasks are created,
+ not all the misc::xalloc are instantiated, so the registered
+ address of these flags is likely to change if there are other
+ xalloc in between. It is the index that is constant, not the
+ address of the pword.
+
+ Of course we could have Tasks dedicated to misc::xalloc, but
+ that's not nice. */
+
+ void escapes_display() { ast::escapes_display(std::cout) = true; }
+
+} // namespace escapes::tasks
diff --git a/tiger-compiler/src/escapes/tasks.hh b/tiger-compiler/src/escapes/tasks.hh
new file mode 100644
index 0000000..636c13f
--- /dev/null
+++ b/tiger-compiler/src/escapes/tasks.hh
@@ -0,0 +1,28 @@
+/**
+ ** \file escapes/tasks.hh
+ ** \brief Escapes module related tasks.
+ */
+
+#pragma once
+
+#include <task/libtask.hh>
+
+/// The Tasks of the escapes module.
+namespace escapes::tasks
+{
+ TASK_GROUP("3. Escapes");
+
+ /// Compute variables escaping.
+ TASK_DECLARE("e|escapes-compute",
+ "compute the escaping variables "
+ "and the functions requiring a static link",
+ escapes_compute,
+ "bound");
+
+ /// Display escaped variables.
+ TASK_DECLARE("E|escapes-display",
+ "enable escape display in the AST",
+ escapes_display,
+ "parse");
+
+} // namespace escapes::tasks
diff --git a/tiger-compiler/src/inlining/inliner.cc b/tiger-compiler/src/inlining/inliner.cc
new file mode 100644
index 0000000..85bbc88
--- /dev/null
+++ b/tiger-compiler/src/inlining/inliner.cc
@@ -0,0 +1,64 @@
+/**
+ ** \file inlining/inliner.cc
+ ** \brief Implementation of inlining::Inliner.
+ */
+
+#include <boost/graph/transitive_closure.hpp>
+
+#include <ranges>
+#include <callgraph/libcallgraph.hh>
+#include <inlining/inliner.hh>
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+
+namespace inlining
+{
+ using namespace ast;
+
+ Inliner::Inliner(const ast::Ast& tree)
+ : super_type()
+ , rec_funs_()
+ {
+ // Compute the transitive closure of the call graph to compute the
+ // set of recursive functions.
+ const callgraph::CallGraph* graph = callgraph::callgraph_compute(tree);
+ callgraph::CallGraph closure;
+ boost::transitive_closure(*graph, closure);
+
+ // Compute the parent graph to get nested functions.
+ const callgraph::ParentGraph* parentGraph =
+ callgraph::parentgraph_compute(const_cast<ast::Ast&>(tree));
+
+ // Re-attach properties to the vertices.
+ for (auto [i, i_end] = boost::vertices(closure); i != i_end; ++i)
+ closure[*i] = (*graph)[*i];
+ // Detect recursive functions.
+ for (auto [i, i_end] = boost::vertices(closure); i != i_end; ++i)
+ {
+ for (auto [j, j_end] = boost::adjacent_vertices(*i, closure);
+ j != j_end; ++j)
+ {
+ // Check all parent functions to detect cases like these :
+ // function a() =
+ // (
+ // let
+ // function b() = a()
+ // in
+ // end
+ // )
+ if (parentGraph->hfundec_deep_get(closure[*i], closure[*j]))
+ rec_funs_.insert(closure[*j]);
+ }
+ }
+ delete graph;
+ delete parentGraph;
+ }
+
+ const misc::set<const ast::FunctionDec*>& Inliner::rec_funs_get() const
+ {
+ return rec_funs_;
+ }
+
+ // FIXME: Some code was deleted here.
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/inliner.hh b/tiger-compiler/src/inlining/inliner.hh
new file mode 100644
index 0000000..fc2f71f
--- /dev/null
+++ b/tiger-compiler/src/inlining/inliner.hh
@@ -0,0 +1,44 @@
+/**
+ ** \file inlining/inliner.hh
+ ** \brief Declaration of inlining::Inliner.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <ast/function-dec.hh>
+#include <astclone/cloner.hh>
+#include <misc/scoped-map.hh>
+#include <misc/set.hh>
+
+namespace inlining
+{
+ /// Perform inline expansion of functions.
+ class Inliner : public astclone::Cloner
+ {
+ public:
+ using super_type = astclone::Cloner;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build an Inliner.
+ Inliner(const ast::Ast& tree);
+
+ /// \name Visit methods.
+ /// \{
+ // FIXME: Some code was deleted here.
+ /// \}
+
+ /// \name Getters.
+ /// \{
+ const misc::set<const ast::FunctionDec*>& rec_funs_get() const;
+ /// \}
+
+ private:
+ /// Recursive functions of the program.
+ misc::set<const ast::FunctionDec*> rec_funs_;
+ };
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/libinlining.cc b/tiger-compiler/src/inlining/libinlining.cc
new file mode 100644
index 0000000..3f6e6b9
--- /dev/null
+++ b/tiger-compiler/src/inlining/libinlining.cc
@@ -0,0 +1,54 @@
+/**
+ ** \file inlining/libinlining.cc
+ ** \brief Functions exported by the inlining module.
+ */
+
+#include <memory>
+
+#include <ast/exp.hh>
+#include <desugar/libdesugar.hh>
+#include <inlining/inliner.hh>
+#include <inlining/libinlining.hh>
+#include <inlining/pruner.hh>
+
+namespace inlining
+{
+ /*-----------.
+ | Inlining. |
+ `-----------*/
+
+ template <typename A> A* inline_expand(const A& tree)
+ {
+ // Inline.
+ Inliner inline_expand(tree);
+ inline_expand(tree);
+ A* inlined = dynamic_cast<A*>(inline_expand.result_get());
+ assertion(inlined);
+ std::unique_ptr<A> inlined_ptr(inlined);
+ // Recompute the bindings and the types.
+ desugar::bind_and_types_check(*inlined_ptr);
+ return inlined_ptr.release();
+ }
+
+ template ast::ChunkList* inline_expand(const ast::ChunkList&);
+
+ /*-------------------.
+ | Function pruning. |
+ `-------------------*/
+
+ template <typename A> A* prune(const A& tree)
+ {
+ // Prune unused functions.
+ Pruner prune;
+ prune(tree);
+ A* pruned = dynamic_cast<A*>(prune.result_get());
+ assertion(pruned);
+ std::unique_ptr<A> pruned_ptr(pruned);
+ // Recompute the bindings and the types.
+ desugar::bind_and_types_check(*pruned_ptr);
+ return pruned_ptr.release();
+ }
+
+ template ast::ChunkList* prune(const ast::ChunkList&);
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/libinlining.hh b/tiger-compiler/src/inlining/libinlining.hh
new file mode 100644
index 0000000..183349a
--- /dev/null
+++ b/tiger-compiler/src/inlining/libinlining.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file inlining/libinlining.hh
+ ** \brief Declare functions exported by the inlining module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+
+/// Inlining functions of an ast::Ast.
+namespace inlining
+{
+ /*-----------.
+ | Inlining. |
+ `-----------*/
+
+ /** Perform inline expansion of function bodies.
+
+ \param tree abstract syntax tree's root, whose bindings and types
+ have been computed. Each identifier must also be unique
+ within the AST to avoid name capture.
+
+ \return the AST where the bodies of non recursive functions have
+ been expanded (inlined), with bindings and type-checked.
+ */
+ template <typename A> A* inline_expand(const A& tree);
+
+ /*-------------------.
+ | Function pruning. |
+ `-------------------*/
+
+ /** Prune unused function from the AST.
+
+ \param tree abstract syntax tree's root, whose bindings and types
+ have been computed, and whose identifiers are all unique.
+
+ \return the AST whose unused functions have been removed, with
+ bindings and type-checked. */
+ template <typename A> A* prune(const A& tree);
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/local.am b/tiger-compiler/src/inlining/local.am
new file mode 100644
index 0000000..7a127bd
--- /dev/null
+++ b/tiger-compiler/src/inlining/local.am
@@ -0,0 +1,8 @@
+## inlining module.
+src_libtc_la_SOURCES += \
+ %D%/inliner.hh %D%/inliner.cc \
+ %D%/pruner.hh %D%/pruner.cc \
+ %D%/libinlining.hh %D%/libinlining.cc
+
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/inlining/pruner.cc b/tiger-compiler/src/inlining/pruner.cc
new file mode 100644
index 0000000..edb20eb
--- /dev/null
+++ b/tiger-compiler/src/inlining/pruner.cc
@@ -0,0 +1,34 @@
+/**
+ ** \file inlining/pruner.cc
+ ** \brief Implementation of inlining::Pruner.
+ */
+
+#include <inlining/pruner.hh>
+
+namespace inlining
+{
+ using namespace ast;
+
+ ast::FunctionChunk* Pruner::prune(ast::FunctionChunk& e)
+ {
+ while (true)
+ {
+ auto [remove_begin, remove_end] =
+ std::ranges::remove_if(e, [&](ast::FunctionDec* func_dec) {
+ if (!func_dec->body_get() || func_dec->name_get() == "_main")
+ return false;
+ else
+ return called_functions_[func_dec->name_get()] == 0;
+ });
+
+ if (remove_begin == remove_end)
+ break;
+ e.erase(remove_begin, remove_end);
+ }
+
+ return new FunctionChunk(e.location_get(), &e.decs_get());
+ }
+
+ // FIXME: Some code was deleted here.
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/pruner.hh b/tiger-compiler/src/inlining/pruner.hh
new file mode 100644
index 0000000..30a0609
--- /dev/null
+++ b/tiger-compiler/src/inlining/pruner.hh
@@ -0,0 +1,42 @@
+/**
+ ** \file inlining/pruner.hh
+ ** \brief Declaration of inlining::Pruner.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <astclone/cloner.hh>
+#include <misc/set.hh>
+
+namespace inlining
+{
+ /// Prune useless function declarations within an AST.
+ class Pruner : public astclone::Cloner
+ {
+ public:
+ using super_type = astclone::Cloner;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ using func_vect = std::vector<ast::FunctionDec*>;
+ using func_count = std::map<misc::symbol, int>;
+
+ /// \name Visit methods.
+ /// \{
+ // FIXME: Some code was deleted here.
+ /// \}
+
+ ast::FunctionChunk* prune(ast::FunctionChunk& e);
+
+ private:
+ // Keep track of current nested functions
+ std::vector<const ast::FunctionDec*> current_functions_;
+
+ // Associate function dec with the number of CallExp calling it
+ func_count called_functions_;
+ };
+
+} // namespace inlining
diff --git a/tiger-compiler/src/inlining/tasks.cc b/tiger-compiler/src/inlining/tasks.cc
new file mode 100644
index 0000000..f812d03
--- /dev/null
+++ b/tiger-compiler/src/inlining/tasks.cc
@@ -0,0 +1,31 @@
+/**
+ ** \file inlining/tasks.cc
+ ** \brief Inlining module related tasks' implementation.
+ **/
+
+#include <ast/tasks.hh>
+#include <astclone/libastclone.hh>
+#include <common.hh>
+#include <inlining/libinlining.hh>
+#define DEFINE_TASKS 1
+#include <inlining/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace inlining::tasks
+{
+ /*-----------.
+ | Inlining. |
+ `-----------*/
+
+ void inline_expand()
+ {
+ astclone::apply(::inlining::inline_expand, ast::tasks::the_program);
+ }
+
+ /*-------------------.
+ | Function pruning. |
+ `-------------------*/
+
+ void prune() { astclone::apply(::inlining::prune, ast::tasks::the_program); }
+
+} // namespace inlining::tasks
diff --git a/tiger-compiler/src/inlining/tasks.hh b/tiger-compiler/src/inlining/tasks.hh
new file mode 100644
index 0000000..6c190ed
--- /dev/null
+++ b/tiger-compiler/src/inlining/tasks.hh
@@ -0,0 +1,36 @@
+/**
+ ** \file inlining/tasks.hh
+ ** \brief Inlining module tasks.
+ */
+
+#pragma once
+
+#include <config.h>
+#include <misc/fwd.hh>
+#include <task/libtask.hh>
+
+namespace inlining::tasks
+{
+ TASK_GROUP("Inlining");
+
+ /*-----------.
+ | Inlining. |
+ `-----------*/
+
+ /// Expand the body of functions at the call sites.
+ TASK_DECLARE("inline",
+ "inline functions",
+ inline_expand,
+ "types-compute rename");
+
+ /*-------------------.
+ | Function pruning. |
+ `-------------------*/
+
+ /// Prune unused function definitions from the AST.
+ TASK_DECLARE("prune",
+ "prune unused functions",
+ prune,
+ "rename types-compute");
+
+} // namespace inlining::tasks
diff --git a/tiger-compiler/src/llvmtranslate/escapes-collector.cc b/tiger-compiler/src/llvmtranslate/escapes-collector.cc
new file mode 100644
index 0000000..4984805
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/escapes-collector.cc
@@ -0,0 +1,151 @@
+#include <ast/all.hh>
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <llvmtranslate/escapes-collector.hh>
+
+namespace llvmtranslate
+{
+ /// LLVM IR doesn't support static link and nested functions.
+ /// In order to translate those functions to LLVM IR, we use a technique
+ /// called Lambda Lifting, which consists in passing a pointer to
+ /// the escaped variables to the nested function using that variable.
+ ///
+ /// In order to do that, we need a visitor to collect these kind of
+ /// variables and associate them to each function.
+
+ class EscapesCollector
+ : public ast::DefaultConstVisitor
+ , public ast::NonObjectConstVisitor
+ , public ast::NonAssertConstVisitor
+ {
+ public:
+ /// Super class.
+ using super_type = ast::DefaultConstVisitor;
+ /// Import overloaded operator() methods.
+ using super_type::operator();
+
+ EscapesCollector()
+ : did_modify_{false}
+ , escaped_{}
+ {}
+
+ escaped_map_type& escaped_get() { return escaped_; }
+
+ void operator()(const ast::FunctionChunk& e) override
+ {
+ const bool saved_did_modify = did_modify_;
+
+ // Iterate on the chunk in order to iteratively collect all the callee
+ // functions' escaped variables.
+ did_modify_ = !e.empty();
+ while (did_modify_)
+ {
+ did_modify_ = false;
+ super_type::operator()(e);
+ }
+
+ did_modify_ = saved_did_modify;
+ }
+
+ void operator()(const ast::FunctionDec& e) override
+ {
+ // Keep track of the current function
+ // FIXME DONE: Some code was deleted here.
+ const auto function_type = \
+ dynamic_cast<const type::Function*>(&e.type_get()->actual());
+
+ precondition(function_type != nullptr);
+
+ // Last visited function
+ const type::Function* previous_scope = current_;
+
+ if (previous_scope == nullptr)
+ {
+ // Then we are at the first depth of the program, hence _main
+ main_function_ = function_type;
+ }
+
+ current_ = function_type;
+
+ if (!escaped_.contains(current_))
+ {
+ escaped_[current_] = misc::set<const ast::VarDec*>{};
+ }
+
+ super_type::operator()(e);
+
+ // Guess we only really need to go back one step before
+ current_ = previous_scope;
+ }
+
+ void operator()(const ast::CallExp& e) override
+ {
+ super_type::operator()(e);
+
+ // FIXME DONE: Some code was deleted here.
+ const auto escaped_reference = escaped_.find(current_);
+ precondition(escaped_reference != escaped_.end());
+ const auto escaped_state = escaped_reference->second;
+
+ const size_t before_size = escaped_state.size();
+
+ super_type::operator()(e.def_get());
+
+ // Check whether there are any newly collected escaped variables.
+ // If there are, mark the iteration as modified.
+ // FIXME DONE: Some code was deleted here.
+ const size_t after_size = escaped_state.size();
+
+ did_modify_ = before_size != after_size;
+ }
+
+ void operator()(const ast::SimpleVar& e) override
+ {
+ // Associate escaped variables declared in parent frames with their
+ // functions
+ // FIXME DONE: Some code was deleted here.
+ if (current_ == main_function_ || !e.def_get()->escape_get())
+ {
+ super_type::operator()(e);
+ return;
+ }
+
+ // Checking that the variable is escaped because not all variables are
+ auto attached_to = escaped_.find(current_);
+
+ // We have a function to attach this to
+ if (attached_to != escaped_.end()
+ && !attached_to->second.contains(e.def_get()))
+ {
+ attached_to->second.insert(e.def_get());
+ did_modify_ = true;
+ }
+
+ super_type::operator()(e);
+ }
+
+ private:
+ /// Whether any modification was done during the iteration.
+ bool did_modify_ = false;
+
+ /// Associate a set of variables with their function.
+ escaped_map_type escaped_;
+
+ /// Current visiting function.
+ // FIXME DONE: Some code was deleted here.
+ const type::Function* current_ = nullptr;
+
+ /// The reference to the main function
+ const type::Function* main_function_ = nullptr;
+ };
+
+ escaped_map_type collect_escapes(const ast::Ast& ast)
+ {
+ EscapesCollector collect;
+ collect(ast);
+
+ return std::move(collect.escaped_get());
+ }
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/escapes-collector.hh b/tiger-compiler/src/llvmtranslate/escapes-collector.hh
new file mode 100644
index 0000000..dab93c6
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/escapes-collector.hh
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <ast/fwd.hh>
+#include <llvmtranslate/fwd.hh>
+
+namespace llvmtranslate
+{
+
+ /// Collect all escapes for every function in the ast, and store it in a map.
+ /// This is used for Lambda Lifting.
+ escaped_map_type collect_escapes(const ast::Ast& ast);
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/fwd.hh b/tiger-compiler/src/llvmtranslate/fwd.hh
new file mode 100644
index 0000000..1eef45e
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/fwd.hh
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <map>
+
+#include <ast/fwd.hh>
+#include <misc/set.hh>
+#include <type/fwd.hh>
+
+namespace llvm
+{
+ // From llvm/IR/Module.h.
+ class Module;
+
+ // From llvm/IR/DerivedTypes.h
+ class StructType;
+
+ // From llvm/IR/Type.h
+ class Type;
+
+ // From llvm/IR/LLVMContext.h
+ class LLVMContext;
+
+} // namespace llvm
+
+namespace llvmtranslate
+{
+ using escaped_map_type =
+ std::map<const type::Function*, misc::set<const ast::VarDec*>>;
+ using frame_map_type = escaped_map_type;
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/generate-runtime.sh b/tiger-compiler/src/llvmtranslate/generate-runtime.sh
new file mode 100755
index 0000000..2e05445
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/generate-runtime.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+[ -z "$1" ] && echo "$0: Missing input file" && exit
+[ -z "$2" ] && echo "$0: Missing output file" && exit
+
+input=$1
+output=$2
+
+awk 'BEGIN {
+ print("#include <string>");
+ print("#include <llvmtranslate/libllvmtranslate.hh>");
+ print("");
+ print("namespace llvmtranslate");
+ print("{");
+ print("const char* runtime_string()");
+ print("{");
+ print(" return");
+ printf("R\"0("); # The zero here only serves as an identifier for the raw string, it does not changes the code behavior at all.
+ }
+ /^#(<<|>>)/ {
+ next;
+ }
+ {
+ print($0);
+ }
+ END {
+ print(")0\";");
+ print("}");
+ print("} // namespace llvmtranslate");
+ }' "$input" > "$output".tmp
+
+mv "$output".tmp "$output"
diff --git a/tiger-compiler/src/llvmtranslate/libllvmtranslate.cc b/tiger-compiler/src/llvmtranslate/libllvmtranslate.cc
new file mode 100644
index 0000000..b86b03a
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/libllvmtranslate.cc
@@ -0,0 +1,47 @@
+/**
+ ** \file llvmtranslate/libllvmtranslate.hh
+ ** \brief Public llvmtranslate module interface implementation.
+ **/
+
+#include <ast/default-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <common.hh> // program_name
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+#include <llvm/AsmParser/Parser.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Verifier.h>
+#include <llvm/Support/SourceMgr.h> // llvm::SMDiagnostic
+#include <llvmtranslate/escapes-collector.hh>
+#include <llvmtranslate/fwd.hh>
+#include <llvmtranslate/libllvmtranslate.hh>
+#include <llvmtranslate/translator.hh>
+
+#pragma GCC diagnostic pop
+
+namespace llvmtranslate
+{
+ std::pair<std::unique_ptr<llvm::LLVMContext>, std::unique_ptr<llvm::Module>>
+ translate(const ast::Ast& the_program)
+ {
+ auto ctx = std::make_unique<llvm::LLVMContext>();
+ auto module = std::make_unique<llvm::Module>(program_name, *ctx);
+
+ Translator translate{*module, collect_escapes(the_program)};
+ translate(the_program);
+
+ llvm::verifyModule(*module);
+
+ return {std::move(ctx), std::move(module)};
+ }
+
+ std::unique_ptr<llvm::Module> runtime_get(llvm::LLVMContext& ctx)
+ {
+ llvm::SMDiagnostic diag;
+ return llvm::parseAssemblyString(runtime_string(), diag, ctx);
+ }
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/libllvmtranslate.hh b/tiger-compiler/src/llvmtranslate/libllvmtranslate.hh
new file mode 100644
index 0000000..cf431e9
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/libllvmtranslate.hh
@@ -0,0 +1,31 @@
+/**
+ ** \file llvmtranslate/libllvmtranslate.hh
+ ** \brief Public llvmtranslate module interface declaration.
+ */
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <llvm/IR/LLVMContext.h>
+
+#include <ast/fwd.hh>
+#include <llvmtranslate/fwd.hh>
+
+/// Translation from ast::Ast to llvm::Value.
+namespace llvmtranslate
+{
+ /// Translate the file into a llvm::Module.
+ std::pair<std::unique_ptr<llvm::LLVMContext>, std::unique_ptr<llvm::Module>>
+ translate(const ast::Ast& the_program);
+
+ /// Load the runtime as a llvm::Module.
+ std::unique_ptr<llvm::Module> runtime_get(llvm::LLVMContext& ctx);
+
+ /// The LLVM runtime as a string, loaded from the generated file.
+ /// This function is implemented in $(build_dir)/src/llvmtranslate/runtime.cc
+ /// For more information take a look at `local.am`.
+ const char* runtime_string();
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/llvm-type-visitor.cc b/tiger-compiler/src/llvmtranslate/llvm-type-visitor.cc
new file mode 100644
index 0000000..a2130c9
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/llvm-type-visitor.cc
@@ -0,0 +1,110 @@
+/**
+ ** \file llvmtranslate/llvm-type-visitor.cc
+ ** \brief Implementation of llvmtranslator::LLVMTypeVisitor.
+ */
+
+#include <llvm/IR/DerivedTypes.h>
+
+#include <llvmtranslate/llvm-type-visitor.hh>
+#include <type/types.hh>
+
+namespace llvmtranslate
+{
+ LLVMTypeVisitor::LLVMTypeVisitor(llvm::LLVMContext& ctx)
+ : ctx_{ctx}
+ {}
+
+ llvm::Type* LLVMTypeVisitor::llvm_type_get() { return type_; }
+
+ llvm::Type* LLVMTypeVisitor::get_record_ltype(const type::Record* e)
+ {
+ return structs_[e];
+ }
+
+ llvm::Type* LLVMTypeVisitor::llvm_type(const type::Type& type)
+ {
+ operator()(type);
+ return type_;
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Nil& e)
+ {
+ if (auto record_type = e.record_type_get())
+ type_ = llvm_type(*record_type);
+ else
+ unreachable();
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Void&)
+ {
+ // FIXME DONE: Some code was deleted here (Void types can be interpreted as int or void type).
+ // Je cite : "a variable can hold a void value (that are represented using an integer in LLVM)"
+ // Mais du coup, je sais pas ce qui détermine quel type on lui donne.
+ // En attendant je mets void tout le temps jusqu'à ce qu'on trouve pourquoi on le mettrait à int
+ // Y a un monde où ça se gère au dessus (genre les vardecs et les assignexp ?)
+ // Source : Un YAKA qui dit que en gros on a le choix mais qu'il vaut mieux le représenter comme int
+ // Du coup pour le distinguer c'est un int sur 0 bits
+ type_ = llvm::Type::getIntNTy(ctx_,0);
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Int&)
+ {
+ type_ = llvm::Type::getInt32Ty(ctx_);
+ }
+
+ void LLVMTypeVisitor::operator()(const type::String&)
+ {
+ // Strings are pointers to characters in LLVM.
+ // FIXME DONE: Some code was deleted here.
+ // Bon vu qu'on a pas accès à la taille de la string on y va yolo.
+ // Du coup c'est un PointerType de Int8 (du coup 8 bits pour un char)
+ type_ = llvm::PointerType::get(llvm::Type::getInt8Ty(ctx_), 0);
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Named& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ llvm_type(e.actual());
+
+ const std::string reference_name = e.name_get().get();
+
+ if (const auto record_ref = dynamic_cast<const type::Record*>(&e.type_get()->actual());
+ record_ref != nullptr && structs_[record_ref]->getName() != reference_name)
+ {
+ structs_[record_ref]->setName(reference_name);
+ }
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Record& e)
+ {
+ // If the record was never translated, translate it
+ if (!structs_[&e])
+ {
+ // We need to create the struct in two passes to support recursive
+ // types, like 'type a = { next : a }
+ // So, first we create an empty struct
+ structs_[&e] = llvm::StructType::create(ctx_);
+ // Then set the body of the structure
+ std::vector<llvm::Type*> field_types;
+ field_types.reserve(e.fields_get().size());
+ // FIXME DONE: Some code was deleted here.
+ //Martial: Copy and convert the fields ig
+ for (const auto& field : e.fields_get())
+ {
+ super_type::operator()(field.type_get());
+ field_types.push_back(type_);
+ }
+ //Martial: Set the body with the converted types
+ structs_[&e]->setBody(std::move(field_types), false);
+ }
+ type_ = llvm::PointerType::getUnqual(structs_[&e]);
+ }
+
+ void LLVMTypeVisitor::operator()(const type::Array& e)
+ {
+ // Arrays are pointers to the array elements, like in C.
+ // FIXME DONE: Some code was deleted here.
+ llvm_type(*e.get_element_type());
+ type_ = llvm::PointerType::getUnqual(type_);
+ }
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/llvm-type-visitor.hh b/tiger-compiler/src/llvmtranslate/llvm-type-visitor.hh
new file mode 100644
index 0000000..d19ea9d
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/llvm-type-visitor.hh
@@ -0,0 +1,50 @@
+/**
+ ** \file llvmtranslate/llvm-type-visitor.hh
+ ** \brief Definition of llvmtranslator::LLVMTypeVisitor.
+ */
+
+#pragma once
+
+#include <llvm/IR/LLVMContext.h>
+
+#include <llvmtranslate/fwd.hh>
+#include <type/default-visitor.hh>
+
+namespace llvmtranslate
+{
+ /// Visit a Type and return the corresponding llvm::Type.
+ class LLVMTypeVisitor : public type::DefaultConstVisitor
+ {
+ public:
+ using super_type = type::DefaultConstVisitor;
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ LLVMTypeVisitor(llvm::LLVMContext& ctx);
+
+ llvm::Type* llvm_type_get();
+ llvm::Type* get_record_ltype(const type::Record* e);
+
+ /// Visit methods.
+ /// \{
+ void operator()(const type::Nil& e) override;
+ void operator()(const type::Void& e) override;
+ void operator()(const type::Int& e) override;
+ void operator()(const type::String& e) override;
+ void operator()(const type::Named& e) override;
+ void operator()(const type::Record& e) override;
+ void operator()(const type::Array& e) override;
+ /// \}
+
+ private:
+ /// The global context.
+ llvm::LLVMContext& ctx_;
+ /// The type of the last visited node.
+ llvm::Type* type_ = nullptr;
+ /// llvm::StructTypes for each type::Record
+ std::map<const type::Record*, llvm::StructType*> structs_;
+ /// Recurse and return the type_.
+ llvm::Type* llvm_type(const type::Type& type);
+ };
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/local.am b/tiger-compiler/src/llvmtranslate/local.am
new file mode 100644
index 0000000..d5a752b
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/local.am
@@ -0,0 +1,39 @@
+# Compile the LLVM Tiger runtime
+EXTRA_DIST += %D%/tiger-runtime.c
+CLEANFILES += %D%/runtime.ll
+%D%/runtime.ll: %D%/tiger-runtime.c
+ $(AM_V_CC)$(CLANG) -c -m32 -std=c99 -emit-llvm -S -o $@ $^
+
+LLVM_RUNTIME_GENERATION = %D%/generate-runtime.sh
+EXTRA_DIST += $(LLVM_RUNTIME_GENERATION)
+CLEANFILES += %D%/runtime.cc
+%D%/runtime.cc: %D%/runtime.ll
+ $(AM_V_GEN)$(srcdir)/$(LLVM_RUNTIME_GENERATION) $< $@
+
+## llvmtranslate module.
+src_libtc_la_SOURCES += \
+ %D%/escapes-collector.cc %D%/escapes-collector.hh \
+ %D%/translator.hh %D%/translator.hxx %D%/translator.cc \
+ %D%/libllvmtranslate.cc %D%/libllvmtranslate.hh \
+ %D%/llvm-type-visitor.cc %D%/llvm-type-visitor.hh \
+ %D%/fwd.hh
+
+nodist_src_libtc_la_SOURCES += %D%/runtime.cc
+
+## FIXME: Add SWIG support for this module
+
+## LLVM flags are found using `llvm-config`.
+
+if STATIC_LLVM
+EXTRA_LLVM_CONFIG_FLAGS = --link-static
+else
+EXTRA_LLVM_CONFIG_FLAGS =
+endif
+
+AM_CXXFLAGS += `$(LLVM_CONFIG) $(EXTRA_LLVM_CONFIG_FLAGS) --cppflags`
+src_libtc_la_LDFLAGS += \
+ `$(LLVM_CONFIG) $(EXTRA_LLVM_CONFIG_FLAGS) --ldflags` \
+ `$(LLVM_CONFIG) $(EXTRA_LLVM_CONFIG_FLAGS) --libs core linker asmparser irprinter` \
+ `$(LLVM_CONFIG) $(EXTRA_LLVM_CONFIG_FLAGS) --system-libs`
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/llvmtranslate/tasks.cc b/tiger-compiler/src/llvmtranslate/tasks.cc
new file mode 100644
index 0000000..09f865c
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/tasks.cc
@@ -0,0 +1,64 @@
+/**
+ ** \file llvmtranslate/tasks.cc
+ ** \brief LLVM Translate tasks.
+ */
+
+#include <memory>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+#include <llvm/Config/llvm-config.h> // LLVM_VERSION_*
+#include <llvm/IR/Module.h>
+#include <llvm/IR/PassManager.h>
+#include <llvm/IRPrinter/IRPrintingPasses.h>
+#include <llvm/Linker/Linker.h>
+#include <llvm/Support/raw_ostream.h> // llvm::outs()
+
+#pragma GCC diagnostic pop
+
+#include <ast/tasks.hh>
+#include <llvmtranslate/fwd.hh>
+#include <llvmtranslate/libllvmtranslate.hh>
+#define DEFINE_TASKS 1
+#include <llvmtranslate/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace llvmtranslate::tasks
+{
+ std::pair<std::unique_ptr<llvm::LLVMContext>, std::unique_ptr<llvm::Module>>
+ module = {nullptr, nullptr};
+
+ /// Translate the AST to LLVM IR.
+ void llvm_compute() { module = translate(*ast::tasks::the_program); }
+
+ /// Display the LLVM IR.
+ void llvm_display()
+ {
+ // If the runtime has to be displayed, get the runtime module,
+ // link it with the program module and print it.
+ if (llvm_runtime_display_p)
+ {
+ auto runtime = runtime_get(*module.first);
+#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 7
+ auto link =
+ llvm::Linker::LinkModules(module.second.get(), runtime.get());
+#else
+ auto link =
+ llvm::Linker::linkModules(*module.second, std::move(runtime));
+#endif
+ (void)link;
+ postcondition(!link); // Returns true on error
+ }
+
+ auto& out = llvm::outs();
+ llvm::PrintModulePass printer{out};
+#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 8
+ printer.run(*module.second);
+#else
+ llvm::ModuleAnalysisManager dummy_mam;
+ printer.run(*module.second, dummy_mam);
+#endif
+ }
+
+} // namespace llvmtranslate::tasks
diff --git a/tiger-compiler/src/llvmtranslate/tasks.hh b/tiger-compiler/src/llvmtranslate/tasks.hh
new file mode 100644
index 0000000..ade231a
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/tasks.hh
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <llvmtranslate/fwd.hh>
+#include <task/libtask.hh>
+
+namespace llvmtranslate::tasks
+{
+ /// The global translation module of ast;:tasks::the_program.
+ extern std::pair<std::unique_ptr<llvm::LLVMContext>,
+ std::unique_ptr<llvm::Module>>
+ module;
+
+ TASK_GROUP("5.5. Translation to LLVM Intermediate Representation");
+
+ /// Translate the AST to LLVM IR.
+ TASK_DECLARE("llvm-compute",
+ "translate to LLVM IR",
+ llvm_compute,
+ "typed desugar-for desugar-string-cmp desugar escapes-compute");
+
+ /// Activate displaying the runtime along with the LLVM IR.
+ BOOLEAN_TASK_DECLARE("llvm-runtime-display",
+ "enable runtime displaying"
+ "along with the LLVM IR",
+ llvm_runtime_display_p,
+ "");
+
+ /// Display the LLVM IR.
+ TASK_DECLARE("llvm-display",
+ "display the LLVM IR",
+ llvm_display,
+ "llvm-compute");
+
+} // namespace llvmtranslate::tasks
diff --git a/tiger-compiler/src/llvmtranslate/tiger-runtime.c b/tiger-compiler/src/llvmtranslate/tiger-runtime.c
new file mode 100644
index 0000000..f952e0f
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/tiger-runtime.c
@@ -0,0 +1,304 @@
+/**
+ \file llvm/tiger-runtime.c
+ \brief C Implementation of the Tiger runtime.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define EXIT_RUNTIME_FAILURE 120
+
+// FWD, declared by tc
+void tc_main(int);
+
+/** \name Internal functions (calls generated by the compiler only). */
+/** \{ */
+
+/** \brief Allocate an array and fill it with a default value.
+ \param size The size of the array.
+ \param elt The default element.
+
+ An element size is always the size of a word on 32-bit systems.
+*/
+int *tc_init_array(int size, int elt)
+{
+ int *arr = (int *)malloc(size * sizeof (elt));
+ for (size_t i = 0; i < size; ++i)
+ arr[i] = elt;
+ return arr;
+}
+/** \} */
+
+/** \name Miscellaneous */
+/** \{ */
+
+/** \brief Equivalent to operator! in C.
+ \param i The integer to be inversed.
+*/
+int tc_not(int i)
+{
+ return !i;
+}
+
+/** \brief Exit the program with the desired status.
+ \param status The status code.
+*/
+void tc_exit(int status)
+{
+ exit(status);
+}
+/** \} */
+
+/** \name Operations on strings. */
+/** \{ */
+
+// Small trick. Add a \0 after each char in the consts
+// This is filled in tc_main
+static char consts[512] = { 0 };
+
+/** \brief Get a string containing the character represented by the ascii value
+ * of \a i.
+ \param i The ascii value of the desired character.
+*/
+const char *tc_chr(int i)
+{
+ if (!(0 <= i && i <= 255))
+ {
+ fputs("chr: character out of range\n", stderr);
+ exit(EXIT_RUNTIME_FAILURE);
+ }
+ return consts + i * 2;
+}
+
+/** \brief Concatenate two strings.
+ \param a The first string.
+ \param b The second string.
+*/
+const char *tc_concat(const char *a, const char *b)
+{
+ size_t len_a = strlen(a);
+ size_t len_b = strlen(b);
+ if (len_a == 0)
+ return b;
+ else if (len_b == 0)
+ return a;
+ else
+ {
+ int i = 0;
+ int n = len_a + len_b;
+ char *t = (char *) malloc(n + 1);
+ for (i = 0; i < len_a; i++)
+ t[i] = a[i];
+ for (i = 0; i < len_b; i++)
+ t[i + len_a] = b[i];
+ t[n] = '\0';
+ return t;
+ }
+}
+
+/** \brief Get the ascii value of a character.
+ \param s The string representing the desired character to be converted.
+
+ Inverse of `tc_chr`.
+*/
+int tc_ord(const char *s)
+{
+ size_t len = strlen(s);
+ if (len == 0)
+ return -1;
+ else
+ return s[0];
+}
+
+/** \brief Get the size of a string.
+ \param s The string.
+*/
+int tc_size(const char *s)
+{
+ return strlen(s);
+}
+
+/** \brief Return a part of the string \a s.
+ \param s The source string
+ \param first The first character of the extraction (starting at 0)
+ \param n The number of characters to get.
+
+ \a first and \a n must be positive, and one shall not go beyond the size
+ of \a s. Otherwise, exit with runtime failure.
+*/
+const char *tc_substring(const char *s, int first, int n)
+{
+ size_t len = strlen(s);
+ if (!(0 <= first
+ && 0 <= n
+ && first + n <= len))
+ {
+ fputs("substring: arguments out of bounds\n", stderr);
+ exit(EXIT_RUNTIME_FAILURE);
+ }
+
+ if (n == 1)
+ return consts + s[first] * 2;
+ else
+ {
+ char *t = (char *) malloc(n + 1);
+ for (int i = 0; i < n; i++)
+ t[i] = s[first + i];
+ t[n] = '\0';
+ return t;
+ }
+}
+
+/** \brief Compare two strings.
+ \param lhs The first string.
+ \param rhs The second string.
+*/
+int tc_strcmp(const char *lhs, const char *rhs)
+{
+ return strcmp(lhs, rhs);
+}
+
+/** \brief Return a part of the string \a s.
+ \param s The source string
+ \param first The first character of the extraction (starting at 0)
+ \param n The number of characters to get.
+
+ \a first and \a n must be positive, and one shall not go beyond the size
+ of \a s. Otherwise, exit with runtime failure.
+*/
+int tc_streq(const char *lhs, const char *rhs)
+{
+ return strcmp(lhs, rhs) == 0;
+}
+/** \} */
+
+/** \name Input/Output. */
+/** \{ */
+
+/** \brief Get a character from the standard input.
+*/
+const char *tc_getchar()
+{
+ int i = getc(stdin);
+ if (i == EOF)
+ return "";
+ else
+ return consts + i * 2;
+}
+
+/** \brief Print a string on the standard output.
+ \param s The string to be printed.
+*/
+void tc_print(const char *s)
+{
+ printf("%s", s);
+}
+
+/** \brief Print a string on the standard error.
+ \param s The string to be printed.
+*/
+void tc_print_err(const char *s)
+{
+ fprintf(stderr, "%s", s);
+}
+
+/** \brief Print an int on the standard error.
+ \param i The int to be printed.
+*/
+void tc_print_int(int i)
+{
+ printf("%d", i);
+}
+
+/** \brief Flush the standard output.
+*/
+void tc_flush()
+{
+ fflush(stdout);
+}
+
+/** \} */
+
+/** \name Custom primitives. */
+/** \{ */
+
+/** \brief Terminate the program with an error if condition if false
+ \param condition Condition to assert, represented as a Tiger 32 bits integer
+ \param instruction_str The condition represented as a string, used for
+ pretty-printing. Can be NULL
+ \param filename File in which the assertion comes from. Can be NULL
+*/
+void tc_assertion(const int condition, const char* instruction_str,
+ const char* filename)
+{
+ if (condition)
+ {
+ return;
+ }
+
+ if (instruction_str == NULL)
+ {
+ instruction_str = "";
+ }
+
+ if (filename == NULL)
+ {
+ filename = "";
+ }
+
+ fprintf(stderr, "%s: %s assertion is false. aborting\n", filename,
+ instruction_str);
+ abort();
+}
+
+/**
+ * \brief Proceed to a fork syscall and return the resulting process id.
+ * \return the resulting pid for the parent, 0 for the child, or -1 if the
+ * process forking failed
+ */
+int tc_fork()
+ {
+ return fork();
+ }
+
+/**
+ * \brief Wait for the process specified by the provided id to end and return
+ * the resulting status code.
+ * \param pid a process, referenced by its identifier
+ * \return the process' status code
+ */
+int tc_wait_pid(int pid)
+ {
+ int status_code = -1;
+ waitpid(pid, &status_code, WUNTRACED | WCONTINUED);
+ return status_code;
+ }
+
+/**
+ * \brief Determine the exit code specified by a status code and return it.
+ * \param status_code any process status code
+ * \return the implied exit code
+ */
+int tc_get_exit_code(int status_code)
+ {
+ return WEXITSTATUS(status_code);
+ }
+
+/** \} */
+
+int main()
+{
+ // Fill the `consts` array with every character in the ascii table, followed
+ // by a null character.
+ for (int i = 0; i < 512; i += 2)
+ {
+ consts[i] = i / 2;
+ consts[i + 1] = 0;
+ }
+
+ tc_main(0);
+ return 0;
+}
diff --git a/tiger-compiler/src/llvmtranslate/translator.cc b/tiger-compiler/src/llvmtranslate/translator.cc
new file mode 100644
index 0000000..2c27db5
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/translator.cc
@@ -0,0 +1,737 @@
+/**
+ ** \file llvmtranslate/translator.cc
+ ** \brief Implementation of llvmtranslate::Translator
+ */
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+#include <llvm/Config/llvm-config.h> // LLVM_VERSION_*
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Verifier.h> // llvm::verifyFunction
+#include <llvm/Support/Casting.h>
+#include <llvm/TargetParser/Host.h> // llvm::sys
+#include <llvm/TargetParser/Triple.h>
+
+#pragma GCC diagnostic pop
+
+#include <ast/all.hh>
+#include <llvmtranslate/translator.hh>
+
+#include "llvm-type-visitor.hh"
+
+namespace llvmtranslate
+{
+ using namespace std::string_literals;
+
+ namespace
+ {
+ // Shorthands for integer type and pointer to integer type.
+ inline llvm::IntegerType* i32_t(llvm::LLVMContext& ctx)
+ {
+ return llvm::Type::getInt32Ty(ctx);
+ }
+
+ inline llvm::PointerType* i32p_t(llvm::LLVMContext& ctx)
+ {
+ return llvm::PointerType::get(llvm::Type::getInt32Ty(ctx), 0);
+ }
+
+ llvm::AllocaInst* create_alloca(llvm::Function* ll_function,
+ llvm::Type* ll_type,
+ const std::string& name)
+ {
+ // Create an IRBuilder starting at the beginning of the current entry
+ // block. LLVM treats allocas as local variables only if they occur at the
+ // beginning of a function.
+ llvm::IRBuilder<> tmp(&ll_function->getEntryBlock(),
+ ll_function->getEntryBlock().begin());
+ return tmp.CreateAlloca(ll_type, nullptr, name);
+ }
+
+ // Set default attributes to the functions
+ void set_default_attributes(llvm::Function& the_function,
+ const ast::FunctionDec& e)
+ {
+ the_function.addFnAttr(llvm::Attribute::NoUnwind); // No exceptions in TC
+ if (!e.body_get()) // Inline primitives
+ the_function.addFnAttr(llvm::Attribute::InlineHint);
+ }
+
+ std::string function_dec_name(const ast::FunctionDec& e)
+ {
+ // Rename "_main" to "tc_main"
+ if (e.name_get() == "_main")
+ return "tc_main";
+ // Prefix all the primitives with "tc_"
+ if (!e.body_get())
+ return "tc_" + e.name_get().get();
+ return e.name_get().get();
+ }
+ } // namespace
+
+ Translator::Translator(llvm::Module& module, escaped_map_type&& escaped)
+ : module_{module}
+ , ctx_{module_.getContext()}
+ , builder_{ctx_}
+ , escaped_{std::move(escaped)}
+ , type_visitor_{ctx_}
+ {
+ // The current process triple.
+ auto process_triple = llvm::Triple(llvm::sys::getProcessTriple());
+ // Set the 32-bit version of the triple.
+ module_.setTargetTriple(process_triple.get32BitArchVariant().str());
+ }
+
+ void Translator::operator()(const ast::Ast& e)
+ {
+ translate(e);
+ value_ = nullptr;
+ }
+
+ llvm::Value* Translator::translate(const ast::Ast& node)
+ {
+ node.accept(*this);
+ return value_;
+ }
+
+ llvm::Value* Translator::access_var(const ast::Var& e)
+ {
+ if (auto var_ast = dynamic_cast<const ast::SimpleVar*>(&e))
+ {
+ // FIXME DONE: Some code was deleted here.
+ // Chopper la VarDec
+ const ast::VarDec* dec = var_ast->def_get();
+ if (dec == nullptr)
+ {
+ // This is probably a binder error
+ unreachable();
+ }
+ // getFunction --> getValueSymbolTable --> lookup
+ auto all_vars = locals_[current_function_];
+ // Ou si c'est un argument, juste iterer sur les arguments jusqu'a trouver la bonne
+ return all_vars[dec];
+
+ }
+ else if (auto arr_ast = dynamic_cast<const ast::SubscriptVar*>(&e))
+ {
+ // FIXME DONE: Some code was deleted here.
+ // Here we have the case of an access in an array (var[index])
+ // Faire un call recursif sur la variable parent afin d'obtenir une reference
+ llvm::Value* mother_val = translate(arr_ast->var_get());
+
+ // Utiliser cette ref pour trouver le type associe
+ llvm::Type* mother_ty = llvm_type(*(arr_ast->var_get().type_get()));
+
+ // Creer une array ref afin de pouvoir stocker les indexs
+ // Ici, l'index en question est index_ de la variable e
+ llvm::Value* index_exp = translate(arr_ast->index_get());
+ //std::vector<llvm::Value*> =
+ const auto index = llvm::ArrayRef(index_exp);
+ // Et il n'y a plus qu'a cree tout ca en utilisant un llvm::IRBuilderBase::CreateGEP
+
+ return builder_.CreateGEP(mother_ty, mother_val, index, "subscriptptr_"s + "some_index");
+ }
+ else if (auto field_ast = dynamic_cast<const ast::FieldVar*>(&e))
+ {
+ const ast::Var* var = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ // Wait, isn't this going to recurse and create many instances of the thing?
+ // Or it is just a small piece of the path towards the full path to this var?
+ var = &(field_ast->var_get());
+
+ auto var_val = translate(*var);
+
+ const type::Record* record_type = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ record_type = dynamic_cast<const type::Record*>(&var->type_get()->actual());
+
+ if (record_type == nullptr)
+ {
+ // This could be a typing error (we do not have a var pointing to a record?)
+ unreachable();
+ }
+
+ misc::symbol field_name;
+ // FIXME DONE: Some code was deleted here.
+ field_name = field_ast->name_get();
+
+ int index = -1;
+ // FIXME DONE: Some code was deleted here (Get the index of the field).
+ index = record_type->field_index(field_name);
+
+ // The GEP instruction provides us with safe pointer arithmetics,
+ // usually used with records or arrays.
+ llvm::Type* record_ltype = nullptr;
+ // FIXME DONE: Some code was deleted here (Get record's corresponding LLVM type).
+ llvm_type(*record_type);
+ record_ltype = type_visitor_.get_record_ltype(record_type);
+
+ return builder_.CreateStructGEP(record_ltype, var_val, index,
+ "fieldptr_"s + field_name.get());
+ }
+ else
+ unreachable();
+ }
+
+ llvm::Value* Translator::init_array(llvm::Value* count_val,
+ llvm::Value* init_val)
+ {
+ // Cast everything so that it is conform to the signature of init_array
+ // int *init_array(int, int)
+
+ // We need to separate the pointers and the ints.
+ // LLVM requires a ptrtoint instruction for pointers
+ // and a bitcast for others.
+ auto init_val_cast = init_val->getType()->isPointerTy()
+ ? builder_.CreatePtrToInt(init_val, i32_t(ctx_), "init_array_ptrtoint")
+ : builder_.CreateBitCast(init_val, i32_t(ctx_), "init_array_bitcast");
+
+ // Create the init_array function:
+ // First, the arguments (int*, int, int)
+ std::vector<llvm::Type*> arg_type{i32_t(ctx_), init_val_cast->getType()};
+
+ // Then, create the FunctionType.
+ auto init_array_ltype =
+ llvm::FunctionType::get(i32p_t(ctx_), arg_type, false);
+
+ // Get the llvm::Function from the module related to the name and type
+ auto init_array_function =
+ module_.getOrInsertFunction("tc_init_array", init_array_ltype);
+
+ // Prepare the arguments.
+ std::vector<llvm::Value*> arg_vals{count_val, init_val_cast};
+
+ // Create the call.
+ auto init_array_call =
+ builder_.CreateCall(init_array_function, arg_vals, "init_array_call");
+
+ // Cast the result of the call in the desired type.
+ return builder_.CreateBitCast(init_array_call,
+ init_val->getType()->getPointerTo(),
+ "init_array_call_cast");
+ }
+
+ llvm::Type* Translator::llvm_type(const type::Type& type)
+ {
+ type_visitor_(type);
+ return type_visitor_.llvm_type_get();
+ }
+
+ llvm::FunctionType*
+ Translator::llvm_function_type(const type::Function& function_type)
+ {
+ // Prepare the arguments
+ std::vector<llvm::Type*> args_types;
+ // First, if there are any escaped vars, create ptr arguments for it
+ // (Lambda lifting)
+
+ if (auto escapes_it = escaped_.find(&function_type);
+ escapes_it != std::end(escaped_))
+ {
+ auto& escapes = escapes_it->second;
+ args_types.reserve(escapes.size()
+ + function_type.formals_get().fields_get().size());
+ for (const auto dec : escapes)
+ {
+ llvm::Type* var_ltype = nullptr;
+ // FIXME DONE: Some code was deleted here (Get the llvm type of the VarDec).
+ var_ltype = llvm_type(*dec->type_get());
+
+ args_types.emplace_back(llvm::PointerType::getUnqual(var_ltype));
+ }
+ }
+ else
+ args_types.reserve(function_type.formals_get().fields_get().size());
+
+ // Then, the actual arguments
+ for (const auto& field : function_type.formals_get())
+ args_types.emplace_back(llvm_type(field.type_get()));
+
+ llvm::Type* result_ltype = nullptr;
+ // FIXME DONE: Some code was deleted here (If the result is void typed, we assign llvm void type to result_ltype).
+ result_ltype = dynamic_cast<const type::Void*>(&function_type.result_get().actual()) != nullptr
+ ? llvm::Type::getVoidTy(ctx_)
+ : llvm_type(function_type.result_get());
+
+ return llvm::FunctionType::get(result_ltype, args_types, false);
+ }
+
+ void Translator::operator()(const ast::SimpleVar& e)
+ {
+ // Void var types are actually Ints represented by a 0
+ // FIXME DONE: Some code was deleted here.
+ value_ = access_var(e);
+ }
+
+ void Translator::operator()(const ast::FieldVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ value_ = access_var(e);
+ }
+
+ void Translator::operator()(const ast::SubscriptVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ value_ = access_var(e);
+ }
+
+ void Translator::operator()(const ast::NilExp& e)
+ {
+ // FIXME DONE: Some code was deleted here (Get the record_type of the Nil type, and create a null pointer).
+ const llvm::Type* pointer_type = llvm_type(*e.type_get());
+ value_ = llvm::ConstantPointerNull::get(pointer_type->getPointerTo());
+ }
+
+ void Translator::operator()(const ast::IntExp& e)
+ {
+ // FIXME DONE: Some code was deleted here (Integers in Tiger are all 32bit signed).
+ value_ = builder_.getInt32(e.value_get());
+ }
+
+ void Translator::operator()(const ast::StringExp& e)
+ {
+ // FIXME DONE: Some code was deleted here (Strings are translated as `i8*` values, like C's `char*`).
+ value_ = builder_.CreateGlobalStringPtr(e.value_get(), "str_exp");
+ }
+
+ void Translator::operator()(const ast::RecordExp& e)
+ {
+ // Get the record type
+ const type::Record* record_type = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ record_type = dynamic_cast<const type::Record*>(&e.type_get()->actual());
+
+ // Type the record and use get_record_ltype() to get its LLVM type
+ llvm_type(*record_type);
+ auto struct_ltype = type_visitor_.get_record_ltype(record_type);
+
+ // The size of the structure and cast it to int
+ auto sizeof_val = llvm::ConstantExpr::getSizeOf(struct_ltype);
+ sizeof_val = llvm::ConstantExpr::getTruncOrBitCast(sizeof_val, i32_t(ctx_));
+
+ // Generate the instruction calling Malloc
+ auto malloc_val = builder_.CreateMalloc(
+ i32_t(ctx_), struct_ltype, sizeof_val, nullptr, nullptr, "malloccall");
+
+ // Init the fields
+ // FIXME DONE: Some code was deleted here.
+ auto& fields = e.fields_get();
+
+ assertion(fields.size() == record_type->fields_get().size());
+
+ for (const auto field : fields)
+ {
+ const auto field_value = translate(field->init_get());
+ const auto field_index = record_type->field_index(field->name_get());
+
+ assertion(field_index >= 0);
+
+ const auto field_llvm_address = builder_.CreateStructGEP(
+ struct_ltype, malloc_val, field_index, "field_" + field->name_get().get()
+ );
+
+ value_ = builder_.CreateStore(field_value, field_llvm_address);
+ }
+
+ value_ = malloc_val;
+ }
+
+ void Translator::operator()(const ast::OpExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // The comparison instructions returns an i1, and we need an i32, since everything
+ // is an i32 in Tiger. Use a zero-extension to avoid this.
+ const auto left_operand = \
+ get_dereferenced(translate(e.left_get()), e.left_get().type_get());
+ const auto right_operand = \
+ get_dereferenced(translate(e.right_get()), e.right_get().type_get());
+
+ switch (e.oper_get())
+ {
+ case ast::OpExp::Oper::add:
+ value_ = builder_.CreateAdd(left_operand, right_operand, "op_add");
+ break;
+ case ast::OpExp::Oper::sub:
+ value_ = builder_.CreateSub(left_operand, right_operand, "op_sub");
+ break;
+ case ast::OpExp::Oper::mul:
+ value_ = builder_.CreateMul(left_operand, right_operand, "op_mul");
+ break;
+ case ast::OpExp::Oper::div:
+ value_ = builder_.CreateSDiv(left_operand, right_operand, "op_div");
+ break;
+ case ast::OpExp::Oper::eq:
+ value_ = builder_.CreateICmpEQ(left_operand, right_operand, "op_eq");
+ break;
+ case ast::OpExp::Oper::ne:
+ value_ = builder_.CreateICmpNE(left_operand, right_operand, "op_ne");
+ break;
+ case ast::OpExp::Oper::gt:
+ value_ = builder_.CreateICmpSGT(left_operand, right_operand, "op_gt");
+ break;
+ case ast::OpExp::Oper::ge:
+ value_ = builder_.CreateICmpSGE(left_operand, right_operand, "op_ge");
+ break;
+ case ast::OpExp::Oper::lt:
+ value_ = builder_.CreateICmpSLT(left_operand, right_operand, "op_lt");
+ break;
+ case ast::OpExp::Oper::le:
+ value_ = builder_.CreateICmpSLE(left_operand, right_operand, "op_le");
+ break;
+ }
+
+ value_ = builder_.CreateZExtOrTrunc(value_, i32_t(ctx_), "op_zext");
+ }
+
+ void Translator::operator()(const ast::SeqExp& e)
+ {
+ // An empty SeqExp is an empty expression, so we should return an int
+ // containing 0, since its type is void.
+ // FIXME DONE: Some code was deleted here.
+ if (e.exps_get().empty())
+ {
+ value_ = get_void_value();
+ return;
+ }
+
+ for (const auto& exp : e.exps_get())
+ {
+ translate(*exp);
+
+ if (dynamic_cast<const ast::Var*>(exp) != nullptr)
+ {
+ value_ = get_dereferenced(value_, exp->type_get());
+ }
+ }
+ }
+
+ void Translator::operator()(const ast::AssignExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ llvm::Value* value = \
+ get_dereferenced(translate(e.exp_get()), e.exp_get().type_get());
+ llvm::Value* variable = translate(e.var_get());
+
+ value_ = builder_.CreateStore(value, variable);
+ }
+
+ void Translator::operator()(const ast::IfExp& e)
+ {
+ // FIXME: Some code was deleted here (IfExps are handled in a similar way to Kaleidoscope (see LangImpl5.html)).
+ llvm::Value* cond = translate(e.test_get());
+
+ auto zero_val = llvm::ConstantInt::getSigned(cond->getType(), 0);
+
+ // The condition may not be correct we are checking that this is different than 0
+ cond = builder_.CreateICmpNE(cond, zero_val, "ifcond");
+
+ // We create the blocks
+ auto then_block = llvm::BasicBlock::Create(ctx_, "then_body", current_function_);
+ auto else_block = llvm::BasicBlock::Create(ctx_, "else_body", current_function_);
+ auto after_if = llvm::BasicBlock::Create(ctx_, "after_if", current_function_);
+
+ // Explicitely create the if statement
+ builder_.CreateCondBr(cond, then_block, else_block);
+
+ // We now tell the builder to insert newly added code to this block
+ builder_.SetInsertPoint(then_block);
+
+ llvm::Value* then_body = translate(e.thenclause_get());
+
+ // Create an unconditional jump to the end of the if statement
+ builder_.CreateBr(after_if);
+
+ // Very akward case where we have an if inside another if
+ // Apparently this is done to not disturb the PHI node
+ then_block = builder_.GetInsertBlock();
+
+ // We add the else block to the current function
+ // Function is private so we directly add the block to the function
+ // current_function_->getBasicBlockList().push_back(else_block);
+
+ // We are now adding stuff in the else block
+ builder_.SetInsertPoint(else_block);
+
+ llvm::Value* else_body = translate(e.elseclause_get());
+
+ builder_.CreateBr(after_if);
+
+ else_block = builder_.GetInsertBlock();
+
+ // Finally we add the remaining block, the one to be executer after the if
+ // current_function_->getBasicBlockList().push_back(after_if);
+
+ builder_.SetInsertPoint(after_if);
+
+ if (dynamic_cast<const type::Void*>(e.type_get()) == nullptr)
+ {
+ // And now for the star of the show: The PHI node
+ // This is a value that can take multiple values depending on the path
+ llvm::PHINode* phi = builder_.CreatePHI(llvm_type(*e.elseclause_get().type_get()), 2, "phinode");
+
+ phi->addIncoming(then_body, then_block);
+ phi->addIncoming(else_body, else_block);
+
+ value_ = phi;
+ }
+ }
+
+ void Translator::operator()(const ast::WhileExp& e)
+ {
+ // Bb containing the test and the branching
+ auto test_bb = llvm::BasicBlock::Create(ctx_, "test", current_function_);
+ auto body_bb = llvm::BasicBlock::Create(ctx_, "body", current_function_);
+ auto after_bb =
+ llvm::BasicBlock::Create(ctx_, "afterloop", current_function_);
+
+ // Save the after block for breaks
+ loop_end_[&e] = after_bb;
+
+ // Explicitly fall through from the current block
+ builder_.CreateBr(test_bb);
+
+ // Start inside the test BasicBlock
+ builder_.SetInsertPoint(test_bb);
+
+ auto cond_val = translate(e.test_get());
+ auto zero_val = llvm::ConstantInt::getSigned(cond_val->getType(), 0);
+ auto cmp_val = builder_.CreateICmpNE(cond_val, zero_val, "loopcond");
+
+ // Create the branching
+ builder_.CreateCondBr(cmp_val, body_bb, after_bb);
+
+ // Translate the body inside the body BasicBlock
+ builder_.SetInsertPoint(body_bb);
+ // Don't store the return value, is should be void.
+ translate(e.body_get());
+
+ // Go back to the Test BasicBlock
+ builder_.CreateBr(test_bb);
+
+ // Continue after the loop BasicBlock
+ builder_.SetInsertPoint(after_bb);
+ }
+
+ void Translator::operator()(const ast::BreakExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto while_node = dynamic_cast<const ast::WhileExp*>(e.def_get());
+
+ precondition(loop_end_.contains(while_node));
+
+ value_ = builder_.CreateBr(loop_end_.at(while_node));
+ }
+
+ void Translator::operator()(const ast::ArrayExp& e)
+ {
+ // Translate the number of elements,
+ // fill the array with the default value, then
+ // return the pointer to the allocated zone.
+ // FIXME DONE: Some code was deleted here (Use `init_array`).
+ llvm::Value* size = translate(e.size_get());
+ llvm::Value* init_value = translate(e.init_get());
+ value_ = init_array(size, init_value);
+ }
+
+ void Translator::operator()(const ast::CastExp& e)
+ {
+ auto exp_val = translate(e.exp_get());
+ llvm::Type* ltype = nullptr;
+ // FIXME DONE: Some code was deleted here (Destination llvm type).
+ ltype = llvm_type(*e.type_get());
+ value_ = builder_.CreateBitCast(exp_val, ltype, "cast_exp");
+ }
+
+ void Translator::operator()(const ast::FunctionChunk& e)
+ {
+ for (const auto& fdec : e)
+ visit_function_dec_header(*fdec);
+
+ for (const auto& fdec : e)
+ // There is nothing to translate for primitives.
+ if (fdec->body_get())
+ visit_function_dec_body(*fdec);
+ }
+
+ void Translator::visit_function_dec_header(const ast::FunctionDec& e)
+ {
+ bool is_main = e.name_get() == "_main";
+ bool is_primitive = e.body_get() == nullptr;
+ auto name = function_dec_name(e);
+
+ const type::Type* node_type = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ node_type = &e.type_get()->actual();
+
+ auto& function_type = static_cast<const type::Function&>(*node_type);
+ auto function_ltype = llvm_function_type(function_type);
+
+ // Main and primitives have External linkage.
+ // Other Tiger functions are treated as "static" functions in C.
+ auto linkage = is_main || is_primitive ? llvm::Function::ExternalLinkage
+ : llvm::Function::InternalLinkage;
+
+ auto the_function =
+ llvm::Function::Create(function_ltype, linkage, name, &module_);
+ set_default_attributes(*the_function, e);
+
+ auto& escaped = escaped_[&function_type];
+
+ // Name each argument of the function
+ for (auto arg_it = the_function->arg_begin();
+ arg_it != the_function->arg_end(); ++arg_it)
+ {
+ auto i = std::distance(the_function->arg_begin(), arg_it);
+ auto var = escaped.size() && static_cast<size_t>(i) < escaped.size()
+ ? *std::next(escaped_[&function_type].begin(), i)
+ : e.formals_get()[i - escaped.size()];
+
+ arg_it->setName(var->name_get().get());
+ }
+ }
+
+ void Translator::visit_function_dec_body(const ast::FunctionDec& e)
+ {
+ auto the_function = module_.getFunction(function_dec_name(e));
+
+ // Save the old function in case a nested function occurs.
+ auto old_insert_point = builder_.saveIP();
+ auto old_function = current_function_;
+ current_function_ = the_function;
+
+ // Create a new basic block to start the function.
+ auto bb = llvm::BasicBlock::Create(ctx_, "entry_"s + e.name_get().get(),
+ the_function);
+ builder_.SetInsertPoint(bb);
+
+ const type::Type* node_type = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ node_type = &e.type_get()->actual();
+
+ auto& function_type = static_cast<const type::Function&>(*node_type);
+ auto& escaped = escaped_[&function_type];
+ auto& formals = e.formals_get();
+
+ auto arg_it = the_function->arg_begin();
+
+ for (const auto var : escaped)
+ {
+ locals_[current_function_][var] = &*arg_it;
+ ++arg_it;
+ }
+
+ // FIXME DONE: Some code was deleted here (Create alloca instructions for each variable).
+ for (size_t i = 0; i < formals.decs_get().size(); i++)
+ {
+ const ast::VarDec* const parameter = formals.decs_get().at(i);
+ locals_[current_function_][parameter] = arg_it + i;
+ }
+
+ translate(*e.body_get());
+
+ // FIXME DONE: Some code was deleted here (Create a return instruction).
+ if (dynamic_cast<const type::Void*>(&function_type.result_get().actual()) != nullptr)
+ {
+ value_ = builder_.CreateRetVoid();
+ }
+ else
+ {
+ if (dynamic_cast<const ast::Var*>(e.body_get()) != nullptr)
+ {
+ value_ = get_dereferenced(value_, e.body_get()->type_get());
+ }
+
+ value_ = builder_.CreateRet(value_);
+ }
+
+ // Validate the generated code, checking for consistency.
+ llvm::verifyFunction(*the_function);
+
+ // Restore the context of the old function.
+ current_function_ = old_function;
+ builder_.restoreIP(old_insert_point);
+ }
+
+ void Translator::operator()(const ast::CallExp& e)
+ {
+ // Look up the name in the global module table.
+ // If it's a primitive, rename the call to tc_name.
+ //
+ // Then, add the escaped variables and the rest of the arguments to the
+ // list of arguments, and return the correct value.
+ // FIXME DONE: Some code was deleted here.
+ const auto function_type = dynamic_cast<const type::Function*>(e.def_get()->type_get());
+
+ precondition(function_type != nullptr);
+
+ std::string function_name = e.name_get().get();
+
+ if (e.def_get()->body_get() == nullptr)
+ {
+ // then the call references a primitive
+ function_name = "tc_" + function_name;
+ }
+
+ llvm::Function* function = module_.getFunction(function_name);
+ std::vector<llvm::Value*> args;
+ std::string twine = "call_" + e.name_get().get();
+
+ assertion(function != nullptr);
+
+ for (auto& var : escaped_[function_type])
+ {
+ args.push_back(translate(*var));
+ }
+
+ for (auto& parameter : e.args_get())
+ {
+ llvm::Value* variable = translate(*parameter);
+ llvm::Value* value = dynamic_cast<ast::Var*>(parameter) != nullptr
+ ? get_dereferenced(variable, parameter->type_get())
+ : variable;
+ args.push_back(value);
+ }
+
+ if (dynamic_cast<const type::Void*>(&function_type->result_get().actual()) != nullptr)
+ {
+ twine = "";
+ }
+
+ value_ = builder_.CreateCall(function, args, twine);
+ }
+
+ void Translator::operator()(const ast::VarDec& e)
+ {
+ // Void var types are actually Ints represented by a 0
+ // FIXME DONE: Some code was deleted here.
+ if (const auto existing_ref = declaration_in_current_scope(e))
+ {
+ value_ = existing_ref;
+ return;
+ }
+
+ llvm::Type* variable_type = llvm_type(*e.type_get());
+
+ llvm::Value* init_value = translate(*e.init_get());
+
+ llvm::Value* variable = create_alloca(current_function_, variable_type,
+ "var_" + e.name_get().get());
+
+ locals_[current_function_][&e] = variable;
+ value_ = builder_.CreateStore(init_value, variable);
+ }
+
+ llvm::Value* Translator::declaration_in_current_scope(const ast::VarDec& e) const
+ {
+ if (!locals_.contains(current_function_))
+ {
+ return nullptr;
+ }
+
+ const auto current_scope = locals_.at(current_function_);
+
+ return current_scope.contains(&e) ? current_scope.at(&e) : nullptr;
+ }
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/llvmtranslate/translator.hh b/tiger-compiler/src/llvmtranslate/translator.hh
new file mode 100644
index 0000000..3ddb625
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/translator.hh
@@ -0,0 +1,145 @@
+/**
+ ** \file llvmtranslate/translator.hh
+ ** \brief Declaration of llvmtranslate::Translator
+ */
+
+#pragma once
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Value.h>
+
+#pragma GCC diagnostic pop
+
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <llvmtranslate/fwd.hh>
+#include <llvmtranslate/llvm-type-visitor.hh>
+
+namespace llvmtranslate
+{
+ class Translator
+ : public ast::DefaultConstVisitor
+ , public ast::NonObjectConstVisitor
+ , public ast::NonAssertConstVisitor
+ {
+ public:
+ /// Super class.
+ using super_type = ast::DefaultConstVisitor;
+ /// Import overloaded operator() methods.
+ using super_type::operator();
+
+ Translator(llvm::Module& module, escaped_map_type&& escaped);
+
+ /// Run the translation.
+ void operator()(const ast::Ast& e) override;
+
+ /// \brief Run this visitor on \a node, and return its translation.
+ ///
+ /// It is also guaranteed that \a value_ is set to it.
+ /// More generally, this routine saves from direct calls to \a accept.
+ llvm::Value* translate(const ast::Ast& node);
+
+ /// \name Lvalues
+ /// \{
+ void operator()(const ast::SimpleVar& e) override;
+ void operator()(const ast::FieldVar& e) override;
+ void operator()(const ast::SubscriptVar& e) override;
+ /// \}
+
+ /// \name Expressions
+ /// \{
+ void operator()(const ast::NilExp&) override;
+ void operator()(const ast::IntExp& e) override;
+ void operator()(const ast::StringExp& e) override;
+ void operator()(const ast::RecordExp& e) override;
+ void operator()(const ast::CallExp& e) override;
+ void operator()(const ast::OpExp& e) override;
+ void operator()(const ast::SeqExp& e) override;
+ void operator()(const ast::AssignExp& e) override;
+ void operator()(const ast::IfExp& e) override;
+ void operator()(const ast::WhileExp& e) override;
+ void operator()(const ast::BreakExp&) override;
+ void operator()(const ast::ArrayExp& e) override;
+ void operator()(const ast::CastExp& e) override;
+ /// \}
+
+ /// \name Declarations
+ /// \{
+ void operator()(const ast::FunctionChunk& e) override;
+ void visit_function_dec_header(const ast::FunctionDec& e);
+ void visit_function_dec_body(const ast::FunctionDec& e);
+ void operator()(const ast::VarDec& e) override;
+
+ /**
+ * Check for the existence of a VarDec node within the current function
+ * scoped (locals_[current_function_]).
+ *
+ * If the node does exist within the scope, its LLVM reference is returned
+ * afterward. If not, nullptr is returned instead.
+ *
+ * @param e The node to look for
+ * @return The associated LLVM value if e does exist within the scope.
+ * nullptr otherwise
+ */
+ llvm::Value* declaration_in_current_scope(const ast::VarDec& e) const;
+
+ /// \}
+
+ protected:
+ /// The translation of the last visited node.
+ llvm::Value* value_ = nullptr;
+
+ /// The current function.
+ llvm::Function* current_function_ = nullptr;
+
+ /// The module containing the metadata and this file's AST.
+ llvm::Module& module_;
+
+ /// The global context of the translator.
+ llvm::LLVMContext& ctx_;
+
+ /// IR builder to simplify building nodes and instructions.
+ llvm::IRBuilder<> builder_;
+
+ /// Access for each "variable".
+ /// Since the AST doesn't contain the arguments added
+ /// for the lambda lifting, we need to identify them by their declaration.
+ std::map<const llvm::Function*, std::map<const ast::VarDec*, llvm::Value*>>
+ locals_;
+
+ /// For each loop, the basic block immediately after it.
+ std::map<const ast::WhileExp*, llvm::BasicBlock*> loop_end_;
+
+ /// Access every escaped variable for each function.
+ escaped_map_type escaped_;
+
+ /// The llvm type translator.
+ LLVMTypeVisitor type_visitor_;
+
+ /// Get a Tiger void value.
+ inline llvm::Value* get_void_value();
+
+ inline llvm::Value* get_dereferenced(llvm::Value* ptr, const type::Type* type);
+
+ private:
+ /// Get a LLVM access to a variable, usually to be loaded right after.
+ llvm::Value* access_var(const ast::Var& e);
+
+ /// Call the init_array function that allocates and initialize the array.
+ llvm::Value* init_array(llvm::Value* count_val, llvm::Value* init_val);
+
+ /// Get a llvm::Type from a type::Type using the type_visitor_.
+ llvm::Type* llvm_type(const type::Type& type);
+
+ /// Create a llvm function from a function type.
+ llvm::FunctionType* llvm_function_type(const type::Function& function_t);
+ };
+
+} // namespace llvmtranslate
+
+#include <llvmtranslate/translator.hxx>
diff --git a/tiger-compiler/src/llvmtranslate/translator.hxx b/tiger-compiler/src/llvmtranslate/translator.hxx
new file mode 100644
index 0000000..a509d4d
--- /dev/null
+++ b/tiger-compiler/src/llvmtranslate/translator.hxx
@@ -0,0 +1,30 @@
+/**
+ ** \file llvmtranslate/translator.hxx
+ ** \brief Inline methods for llvmtranslate::Translator.
+ */
+
+#pragma once
+
+#include <llvmtranslate/translator.hh>
+
+namespace llvmtranslate
+{
+
+ inline llvm::Value* Translator::get_void_value()
+ {
+ return builder_.getIntN(0, 0);
+ }
+
+ inline llvm::Value* Translator::get_dereferenced(llvm::Value* ptr,
+ const type::Type* type)
+ {
+ if (!ptr->getType()->isPointerTy())
+ {
+ return ptr;
+ }
+
+ return builder_.CreateLoad(llvm_type(*type), ptr, ptr->getName() + "_dereferenced");
+ }
+
+
+} // namespace llvmtranslate
diff --git a/tiger-compiler/src/local.am b/tiger-compiler/src/local.am
new file mode 100644
index 0000000..dfd658e
--- /dev/null
+++ b/tiger-compiler/src/local.am
@@ -0,0 +1,75 @@
+## ------------ ##
+## version.cc. ##
+## ------------ ##
+
+EXTRA_DIST += src/version.cc.in
+CLEANFILES += src/version.stamp
+src/version.stamp: $(top_srcdir)/ChangeLog $(srcdir)/src/version.cc.in
+ $(AM_V_GEN)rm -f src/version.tmp
+ $(AM_V_at)touch src/version.tmp
+# Be sure not to have `/' in Id. The embedded date may be
+# separated by `/' instead of `-', what sed dislikes.
+ $(AM_V_at)\
+ Id=`sed -n '/^\$$Id/{s,/,-,g;p;q;}' $(top_srcdir)/ChangeLog`; \
+ sed -e "s/@ID@/$$Id/" $(srcdir)/src/version.cc.in >src/version.cc.tmp
+ $(AM_V_at)$(top_srcdir)/build-aux/bin/move-if-change \
+ src/version.cc.tmp src/version.cc
+ $(AM_V_at)mv -f src/version.tmp src/version.stamp
+
+src/version.cc: src/version.stamp
+ $(AM_V_at)if test -f src/version.cc; then :; else \
+ rm -f src/version.stamp; \
+ $(MAKE) $(AM_MAKEFLAGS) src/version.stamp; \
+ fi
+
+
+## ------- ##
+## libtc. ##
+## ------- ##
+
+lib_LTLIBRARIES = src/libtc.la
+src_libtc_la_SOURCES = src/version.hh src/common.cc
+nodist_src_libtc_la_SOURCES = src/version.cc
+src_libtc_la_LDFLAGS = $(BOOST_PROGRAM_OPTIONS_LDFLAGS) -lreflex
+BUILT_SOURCES += $(nodist_src_libtc_la_SOURCES)
+CLEANFILES += $(nodist_src_libtc_la_SOURCES)
+src_libtc_la_LIBADD = \
+ $(top_builddir)/lib/misc/libmisc.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+
+## ---- ##
+## tc. ##
+## ---- ##
+
+bin_PROGRAMS = src/tc
+dist_src_tc_SOURCES = \
+ src/doc.hh \
+ $(TASKS) \
+ src/common.hh \
+ src/tc.cc
+
+src_tc_LDADD = src/libtc.la
+
+
+## --------- ##
+## Modules. ##
+## --------- ##
+
+TASKS =
+include src/task/local.am
+include src/ast/local.am
+include src/parse/local.am
+include src/astclone/local.am
+include src/bind/local.am
+include src/escapes/local.am
+include src/callgraph/local.am
+include src/type/local.am
+include src/object/local.am
+include src/overload/local.am
+include src/desugar/local.am
+include src/assert/local.am
+include src/testsuite/local.am
+include src/inlining/local.am
+include src/llvmtranslate/local.am
+include src/combine/local.am
diff --git a/tiger-compiler/src/object/binder.cc b/tiger-compiler/src/object/binder.cc
new file mode 100644
index 0000000..8220da5
--- /dev/null
+++ b/tiger-compiler/src/object/binder.cc
@@ -0,0 +1,176 @@
+/**
+ ** \file object/binder.cc
+ ** \brief Implementation of object::Binder.
+ */
+
+#include <ast/all.hh>
+#include <object/binder.hh>
+
+namespace object
+{
+ /*---------.
+ | Visits. |
+ `---------*/
+
+ /* Handle the case of `self'. If the variable is not named `self', handle it
+ like the normal `Binder'. If it is `self', it must be bound to a definiton
+ site, unless:
+ * it is inside a method,
+ * AND `self` is not overridden.
+ If those conditions are met, `self' is an implicitly defined instance of
+ the class.
+
+ Variable `self' will have a meaningful definition after the object
+ constructs have been desugared. */
+
+ void Binder::operator()(ast::SimpleVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ misc::symbol test_self("self");
+ if (e.name_get() == test_self && within_method_dec_ && !overrided_self_)
+ {
+ e.def_set(nullptr);
+ }
+ else
+ {
+ super_type::operator()(e);
+ }
+ }
+
+ // Handle the case of `Object'.
+ void Binder::operator()(ast::NameTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ misc::symbol test_obj("Object");
+ if (e.name_get() == test_obj)
+ {
+ e.def_set(nullptr);
+ }
+ else
+ {
+ super_type::operator()(e);
+ }
+ }
+
+ /*---------------.
+ | Visiting Exp. |
+ `---------------*/
+
+ void Binder::operator()(ast::ForExp& e)
+ {
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ super_type::operator()(e);
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ /*-------------------.
+ | Visiting ClassTy. |
+ `-------------------*/
+
+ void Binder::operator()(ast::ClassTy& e)
+ {
+ // FIXME DONE: Some code was deleted here (Scope begins).
+ begin_scope();
+ e.super_get().accept(*this);
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = true;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = false;
+ e.chunks_get().accept(*this);
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ // FIXME DONE: Some code was deleted here (Scope ends).
+ end_scope();
+ }
+
+ /*---------------.
+ | Visiting Dec. |
+ `---------------*/
+
+ void Binder::operator()(ast::VarDec& e)
+ {
+ if (within_class_ty_)
+ {
+ within_class_ty_ = false;
+ // Don't bind class attributes.
+ super_type::super_type::operator()(e);
+ within_class_ty_ = true;
+ }
+ else
+ {
+ // But still bind other variable declarations.
+ super_type::operator()(e);
+ if (e.name_get() == "self" && within_method_dec_)
+ overrided_self_ = true;
+ }
+ }
+
+ void Binder::operator()(ast::FunctionChunk& e)
+ {
+ chunk_visit<ast::FunctionDec>(e);
+ }
+
+ template <class D> void Binder::chunk_visit(ast::Chunk<D>& e)
+ {
+ // Shorthand.
+ using chunk_type = ast::Chunk<D>;
+ // FIXME: Some code was deleted here (Two passes: once on headers, then on bodies).
+ for (auto machala : e)
+ {
+ if (dynamic_cast<ast::MethodDec*>(machala))
+ {
+ scoped_map_fun_.put(machala->name_get(), machala);
+ }
+ }
+ super_type::operator()(e);
+ }
+
+ // This trampoline is needed, since `virtual' and `template' cannot
+ // be mixed.
+ template <>
+ void Binder::visit_dec_header<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ // FIXME DONE: Some code was deleted here (Call the super type).
+ super_type::operator()(e);
+ }
+
+ // Compute the bindings of this function's body.
+ template <> void Binder::visit_dec_body<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = false;
+ // FIXME DONE: Some code was deleted here (Call the super type).
+ super_type::operator()(e);
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ /* We can't bind methods definitions without types, so we don't
+ store them. Nonetheless, object::Binder must still recurse
+ through the children of ast::MethodChunk to bind other names.
+
+ Note that as we defer the binding of methods to the
+ type-checkimg, there is no need to visit method in two-pass (like
+ bind::Binder does for functions for instance). */
+ void Binder::operator()(ast::MethodDec& e)
+ {
+ // FIXME DONE: Some code was deleted here (Scope begins).
+ begin_scope();
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ bool saved_within_method_dec = within_method_dec_;
+ within_method_dec_ = true;
+ bool saved_overrided_self = overrided_self_;
+ overrided_self_ = false;
+ ast::DefaultVisitor::operator()(static_cast<ast::FunctionDec&>(e));
+ within_method_dec_ = saved_within_method_dec;
+ within_class_ty_ = saved_within_class_ty;
+ overrided_self_ = saved_overrided_self;
+ // FIXME DONE: Some code was deleted here (Scope ends).
+ end_scope();
+ }
+
+} // namespace object
diff --git a/tiger-compiler/src/object/binder.hh b/tiger-compiler/src/object/binder.hh
new file mode 100644
index 0000000..dad6b57
--- /dev/null
+++ b/tiger-compiler/src/object/binder.hh
@@ -0,0 +1,98 @@
+/**
+ ** \file object/binder.hh
+ ** \brief Declaration of object::Binder.
+ **/
+
+#pragma once
+
+#include <bind/binder.hh>
+
+namespace object
+{
+ /** \brief Computing bindings with support for objects.
+ **
+ ** Inheritance is declared virtual to enable diamond inheritance with
+ ** the combine::Binder (src/combine/binder.hh), inheriting from
+ ** overload::Binder and object::Binder, both inheriting from bind::Binder.
+ **/
+ class Binder : virtual public bind::Binder
+ {
+ public:
+ /// Super class type.
+ using super_type = ::bind::Binder;
+ /// Import all the overloaded operator() methods.
+ using super_type::operator();
+
+ /* The visiting methods. */
+ public:
+ // ---------------- //
+ // Visiting /Exp/. //
+ // ---------------- //
+
+ void operator()(ast::ForExp& e) override;
+
+ /// Visit a Variable instantiation.
+ void operator()(ast::SimpleVar& e) override;
+
+ // ---------------- //
+ // Visiting /Ty/. //
+ // ---------------- //
+
+ /// Visit a type name.
+ void operator()(ast::NameTy& e) override;
+
+ /// Visit a class definition.
+ void operator()(ast::ClassTy& e) override;
+
+ // ---------------- //
+ // Visiting /Dec/. //
+ // ---------------- //
+
+ /// Check a set of definitions: unique names, browse headers, then bodies.
+ template <class D> void chunk_visit(ast::Chunk<D>& e);
+
+ /// Check a Function declaration header.
+ template <class D> void visit_dec_header(D& e);
+
+ /// Check a Function declaration body.
+ template <class D> void visit_dec_body(D& e);
+
+ // Visit a variable declaration.
+ void operator()(ast::VarDec&) override;
+
+ /// Visit a chunk of Function declarations.
+ void operator()(ast::FunctionChunk&) override;
+
+ /// No longer used.
+ void operator()(ast::MethodDec&) override;
+
+ private:
+ /// Are we (immediately) within a class definition?
+ ///
+ /// This predicate is used to prevent the bindings of VarChunk that
+ /// are direct children of a ClassTy and which represent
+ /// attributes of that class definition; the binding of these
+ /// attributes is deferred to the type-checking phase (as for
+ /// records' fields). This predicate should be false within a
+ /// non-ClassTy node declaring variables, even if that node
+ /// belongs (indirectly) to the subtree of a ClassTy.
+ bool within_class_ty_ = false;
+
+ /// Are we (immediately) within a method definition?
+ ///
+ /// This predicate is used to determine whether `self' is a valid
+ /// variable. This is only the case for nodes that belong to the
+ /// subtree of a MethodDec node, except for FunctionDec and
+ /// ClassTy subtrees, which ``reset'' the context.
+ bool within_method_dec_ = false;
+
+ /// Is the implicit `self' formal of the current MethodDec overrided by an
+ /// other variable named `self' local to the current method?
+ ///
+ /// This predicate is used to determine whether a SimpleVar named `self`
+ /// should be bound to its potential definition or if it is bound to
+ /// nullptr, representing the current object.
+ bool overrided_self_ = false;
+ };
+
+} // namespace object
diff --git a/tiger-compiler/src/object/desugar-visitor.cc b/tiger-compiler/src/object/desugar-visitor.cc
new file mode 100644
index 0000000..db61a80
--- /dev/null
+++ b/tiger-compiler/src/object/desugar-visitor.cc
@@ -0,0 +1,1127 @@
+/**
+ ** \file object/desugar-visitor.cc
+ ** \brief Implementation of object::DesugarVisitor.
+ */
+
+#include <sstream>
+
+#include <algorithm>
+#include <ast/all.hh>
+#include <misc/contract.hh>
+#include <misc/set.hh>
+#include <misc/symbol.hh>
+#include <object/desugar-visitor.hh>
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+#include <type/class.hh>
+#include <type/function.hh>
+#include <type/record.hh>
+
+namespace object
+{
+ DesugarVisitor::DesugarVisitor(const class_names_type& names)
+ : class_names_(names)
+ {}
+
+ /*---------------------------.
+ | Handling names and types. |
+ `---------------------------*/
+
+ namespace
+ {
+ // Desugar prefixes.
+
+ // Prefix of every class id (label).
+ const char* class_id_prefix = "_id_";
+ // Prefix of every record holding the contents of a desugared class.
+ const char* class_contents_prefix = "_contents_";
+ // Prefix of every variant storing the possible dynamic type for
+ // a given static type.
+ const char* class_variant_prefix = "_variant_";
+ // Prefix of the fields in the variant.
+ const char* variant_field_prefix = "field_";
+ // Prefix of constructors.
+ const char* class_ctor_prefix = "_new_";
+ // Prefix of methods.
+ const char* method_prefix = "_method_";
+
+ // Useful routines.
+
+ // Try to get the class type of \a t. If \a t is not a class
+ // type, return a null pointer.
+ const type::Class* class_type_query(const ast::Typable& t)
+ {
+ // FIXME DONE: Some code was deleted here.
+ return dynamic_cast<const type::Class*>(&t.type_get()->actual());
+ }
+
+ // Like class_type_query, but ensure the type is actually a class.
+ const type::Class* class_type_get(const ast::Typable& t)
+ {
+ const type::Class* class_type = class_type_query(t);
+ postcondition(class_type);
+ return class_type;
+ }
+
+ } // namespace
+
+ /*------------------.
+ | Code generation. |
+ `------------------*/
+
+ std::string DesugarVisitor::type_symbol(const type::Type* type)
+ {
+ // FIXME DONE: Some code was deleted here (Check int, then string, then class name).
+ if (dynamic_cast<const type::Int*>(type))
+ {
+ return "int";
+ }
+ else if (dynamic_cast<const type::String*>(type))
+ {
+ return "string";
+ }
+ else if (const auto named = dynamic_cast<const type::Named*>(type))
+ {
+ return named->name_get().get();
+ }
+ else
+ {
+ throw std::invalid_argument("type was neither a builtin or named");
+ }
+ }
+
+ std::string DesugarVisitor::upcast_fun_name(const type::Class* from,
+ const type::Class* to)
+ {
+ std::stringstream s;
+ s << "_upcast_" << class_names_(from) << "_to_" << class_names_(to);
+ return s.str();
+ }
+
+ std::string DesugarVisitor::downcast_fun_name(const type::Class* from,
+ const type::Class* to)
+ {
+ std::stringstream s;
+ s << "_downcast_" << class_names_(from) << "_to_" << class_names_(to);
+ return s.str();
+ }
+
+ std::string DesugarVisitor::dispatch_fun_name(const type::Class* owner,
+ const type::Method* method)
+ {
+ std::stringstream s;
+ // If an extension is found, add it to the dispatch suffix.
+ if (dispatch_map_.find(method) != dispatch_map_.end())
+ s << "_dispatch_" << dispatch_map_[method] << "_" << class_names_(owner)
+ << "_" << method->name_get();
+ else
+ s << "_dispatch_" << class_names_(owner) << "_" << method->name_get();
+
+ return s.str();
+ }
+
+ void DesugarVisitor::adapt_type(ast::Exp*& source_exp,
+ const type::Class* source_type,
+ const type::Class* target_type)
+ {
+ // If the source type is different from the target type, (up)cast
+ // the source expression to the latter.
+ if (source_type && target_type && source_type != target_type)
+ source_exp = parse::parse(parse::Tweast()
+ << upcast_fun_name(source_type, target_type)
+ << " (" << source_exp << ")");
+ }
+
+ ast::Exp* DesugarVisitor::variant_exp(const type::Class* static_type,
+ const std::string& exact_type,
+ const field_inits_type& inits)
+ {
+ parse::Tweast input;
+ misc::symbol static_type_name = class_names_(static_type);
+ input << " " << class_variant_prefix << static_type_name
+ << " {"
+ " exact_type = "
+ << exact_type;
+ /* For each field of the variant, store the corresponding
+ initialization value if one was given, otherwise set the field
+ to `nil'. */
+ // Fields of the static type.
+ for (const type::Class* c = static_type; c; c = c->super_get())
+ // Don't generate slots for classes with no data.
+ if (c->has_data())
+ {
+ input << ",\n" << variant_field_prefix << class_names_(c) << " = ";
+ // These fields must have a value (we don't need to put an
+ // assertion here, misc::map::operator() already handles this.
+ std::string init = inits.operator()(c);
+ input << init;
+ }
+ // Potential fields of the dynamic type (from subclasses of the
+ // static type).
+ for (const type::Class* subclass : static_type->subclasses_get())
+ // Don't generate slots for classes with no data.
+ if (subclass->has_data())
+ {
+ input << ",\n"
+ << variant_field_prefix << class_names_(subclass) << " = ";
+ // These fields might be nil.
+ const auto i = inits.find(subclass);
+ if (i != inits.end())
+ input << i->second;
+ else
+ input << "nil";
+ }
+ input << " }\n";
+ return parse::parse(input);
+ }
+
+ // Syntactic sugar.
+ ast::Exp* DesugarVisitor::variant_exp(const type::Class* static_type,
+ const type::Class* dynamic_type,
+ const field_inits_type& inits)
+ {
+ std::string exact_type = class_id_prefix + class_names_(dynamic_type).get();
+ return variant_exp(static_type, exact_type, inits);
+ }
+
+ void DesugarVisitor::fill_variant_fields(const type::Class* class_type,
+ parse::Tweast* input)
+ {
+ // Don't generate slots for classes with no data.
+ if (class_type->has_data())
+ {
+ misc::symbol class_name = class_names_(class_type);
+ *input << ",\n"
+ << " " << variant_field_prefix << class_name << " : "
+ << " " << class_contents_prefix << class_name;
+ }
+ }
+
+ // Desugar a class type as a variant (record) type.
+ parse::Tweast* DesugarVisitor::variant_ty(const type::Class* class_type)
+ {
+ auto input = new parse::Tweast;
+ *input << " {"
+ << " exact_type : int";
+ // Actual data slots.
+ /* First, populate the variant with mandatory fields (always non
+ nil) starting with the type of the visited class, then super
+ classes. */
+ for (const type::Class* c = class_type; c; c = c->super_get())
+ fill_variant_fields(c, input);
+ /* Then add all subclasses types. These might be nil, according to
+ the exact type of the object. */
+ for (const type::Class* subclass : class_type->subclasses_get())
+ fill_variant_fields(subclass, input);
+ *input << " }\n";
+ return input;
+ }
+
+ void DesugarVisitor::fill_init_list(const type::Class* class_type,
+ field_inits_type& inits)
+ {
+ // Populate the initialization list with classes
+ // owning actual data only.
+ if (class_type->has_data())
+ {
+ std::string field_name = class_names_(class_type);
+ misc::put(inits, class_type,
+ std::string("source.") + variant_field_prefix + field_name);
+ }
+ }
+
+ parse::Tweast* DesugarVisitor::cast_function(const std::string& name,
+ const type::Class* source,
+ const type::Class* target,
+ const type::Class* exact_type)
+ {
+ auto input = new parse::Tweast;
+ *input << " function " << name << " (source : " << class_variant_prefix
+ << class_names_(source)
+ << ") :"
+ " "
+ << class_variant_prefix << class_names_(target) << " = ";
+
+ // Copy all fields from the source.
+ field_inits_type inits;
+ // First, fields from the class and its super classes...
+ for (const type::Class* c = source; c; c = c->super_get())
+ fill_init_list(c, inits);
+ // ...then, fields from the subclasses.
+ for (const type::Class* c : source->subclasses_get())
+ fill_init_list(c, inits);
+ *input << variant_exp(target, exact_type, inits) << "\n";
+ return input;
+ }
+
+ parse::Tweast* DesugarVisitor::upcast_function(const type::Class* source,
+ const type::Class* target)
+ {
+ return cast_function(upcast_fun_name(source, target), source, target,
+ source);
+ }
+
+ parse::Tweast* DesugarVisitor::downcast_function(const type::Class* source,
+ const type::Class* target)
+ {
+ return cast_function(downcast_fun_name(source, target), source, target,
+ target);
+ }
+
+ ast::Exp* DesugarVisitor::dispatch_switch(const type::Class* class_type,
+ const type::Method* method,
+ const ast::TypeChunk* typechunk,
+ const type::Method* dispatch_method)
+ {
+ parse::Tweast input;
+ misc::symbol method_name = method->name_get();
+ // If a recursive call is needed, dispatch_method will not be
+ // nullptr. It means that during the dispatch function
+ // declaration, formals of the mother method have been used
+ // (because of the use of dispatch_map_, we cannot use child's
+ // formals.
+ const ast::MethodDec* def;
+ // FIXME DONE: Some code was deleted here (Initialize def).
+ def = dispatch_method ? dispatch_method->def_get() : method->def_get();
+ const ast::VarChunk& formals = def->formals_get();
+
+ // Create a case for each method redefinition.
+ classes_type overridings;
+ for (const type::Class* c : class_type->subclasses_get())
+ if (std::ranges::any_of(*typechunk, [c](const ast::TypeDec* tmp) {
+ return class_type_query(*tmp) == c;
+ }))
+ overridings.emplace_back(c);
+
+ if (overridings.empty())
+ // No dispatch is needed; simply call the method.
+ input << method_call(class_names_(class_type), method_name, "self",
+ formals);
+ else
+ {
+ // Emit code for self.
+ bool first = true;
+ // Emit code for other types.
+ for (auto c : overridings)
+ {
+ if (!first)
+ input << " else ";
+ input << " if self.exact_type = " << class_id_prefix
+ << class_names_(c) << " then ";
+ // We search for the nearest implementation of our method.
+ const type::Class* nearest_c = c;
+ while (nearest_c && !(nearest_c->owned_meth_find(method_name)))
+ nearest_c = nearest_c->super_get();
+ input << method_call(
+ class_names_(nearest_c), method_name,
+ ((*class_type != *nearest_c)
+ ? downcast_fun_name(class_type, nearest_c) + " (self)"
+ : "self"),
+ formals);
+ first = false;
+ }
+ input << " else ";
+ // If this is a sub dispatch function, call the last dispatch
+ // method built so we don't need to write every single test
+ // for exact_type.
+ if (dispatch_method)
+ {
+ input << "_dispatch_";
+ if ((dispatch_map_[method] - 1) != 1)
+ input << (dispatch_map_[method] - 1) << "_";
+ input << class_names_(class_type) << "_" << method->name_get()
+ << " (self";
+ // Get the other arguments.
+ for (const ast::VarDec* arg : formals)
+ input << ", " << arg->name_get();
+ input << ")";
+ }
+ else
+ input << method_call(class_names_(class_type), method_name, "self",
+ formals);
+ }
+ input << '\n';
+ return parse::parse(input);
+ }
+
+ parse::Tweast* DesugarVisitor::method_call(misc::symbol class_name,
+ misc::symbol method_name,
+ const std::string& target,
+ const ast::VarChunk& formals)
+ {
+ auto input = new parse::Tweast;
+ *input << method_prefix << class_name << "_" << method_name << " (";
+
+ // Pass the target.
+ // FIXME DONE: Some code was deleted here.
+ *input << target;
+
+ // Pass other arguments.
+ // FIXME DONE: Some code was deleted here.
+ for (const auto var : formals)
+ {
+ // FIXME: Is potentially wrong
+ *input << ", " << *recurse(*var);
+ }
+
+ *input << ")";
+ return input;
+ }
+
+ /*------------------------.
+ | Visiting declarations. |
+ `------------------------*/
+
+ void DesugarVisitor::operator()(const ast::ChunkList& e)
+ {
+ const ast::Location& location = e.location_get();
+ // This is an inlined and specialized version of
+ // astclone::Cloner::recurse_collection. Maybe we could factor
+ // it, but it's not easy to see whether we could benefit from
+ // this. (Maybe a variant would be appropriate.)
+ ast::ChunkList::list_type contents;
+ for (const ast::ChunkInterface* d : e)
+ {
+ d->accept(*this);
+ // The result can be either an ast::ChunkInterface* or an ast::ChunkList*.
+ auto chunk = dynamic_cast<ast::ChunkInterface*>(result_);
+ if (chunk)
+ contents.emplace_back(chunk);
+ else
+ {
+ auto chunklist = dynamic_cast<ast::ChunkList*>(result_);
+ if (chunklist)
+ {
+ contents.splice(contents.end(), chunklist->chunks_get());
+ delete chunklist;
+ }
+ else
+ abort();
+ }
+ }
+ result_ = new ast::ChunkList(location, contents);
+ }
+
+ /*-----------------------------.
+ | Desugar class declarations. |
+ `-----------------------------*/
+
+ void DesugarVisitor::desugar_constructor(parse::Tweast& functions,
+ const type::Class* cls,
+ misc::symbol class_name)
+ {
+ functions << " function " << class_ctor_prefix << class_name
+ << "() : "
+ " "
+ << class_variant_prefix << class_name
+ << " = "
+ " let";
+ // Initialize each mandatory field of the variant (i.e.,
+ // the fields holding the attributes of the classes and
+ // its super classes).
+ for (const type::Class* c = cls; c; c = c->super_get())
+ if (c->has_data())
+ {
+ functions << " var contents_" << class_names_(c) << " := "
+ << " " << class_contents_prefix << class_names_(c) << " { ";
+
+ for (auto a = c->attrs_get().begin(); a != c->attrs_get().end(); a++)
+ {
+ if (a != c->attrs_get().begin())
+ functions << ", ";
+ const ast::VarDec* attr;
+ // FIXME DONE: Some code was deleted here (Initialize attr).
+ attr = a->def_get();
+ misc::symbol attr_name = attr->name_get();
+ // Partially clone the contents of the VarDec
+ // (cloning the whole VarDec would leak memory).
+
+ ast::Exp* attr_init = recurse(attr->init_get());
+ // Cast the initialization value if needed.
+ if (attr->init_get() && attr->type_name_get())
+ adapt_type(attr_init, class_type_query(*attr->init_get()),
+ class_type_query(*attr->type_name_get()));
+ functions << attr_name << " = " << attr_init;
+ }
+ functions << " } ";
+ }
+ functions << " in ";
+ // Create a list of initializations for each field of the
+ // variant being constructed.
+ field_inits_type inits;
+ for (const type::Class* c = cls; c; c = c->super_get())
+ if (c->has_data())
+ {
+ // FIXME DONE: Some code was deleted here.
+ std::string base = "contents_";
+ std::string name = class_names_(c);
+ misc::put(inits, c, base + name);
+ }
+ // Create the contents of the variant.
+ functions << variant_exp(cls, cls, inits) << " end\n";
+ }
+
+ void DesugarVisitor::desugar_method(parse::Tweast& functions,
+ const type::Method* method,
+ misc::symbol class_name)
+ {
+ functions << " function " << method_prefix << class_name << "_"
+ << method->name_get() << " (self : " << class_variant_prefix
+ << class_name;
+ // Get the other arguments.
+ const ast::MethodDec* def;
+ // FIXME DONE: Some code was deleted here (Initiliaze def).
+ def = method->def_get();
+ for (const ast::VarDec* arg : def->formals_get())
+ functions << ", " << arg->name_get() << " : "
+ << recurse(*arg->type_name_get());
+ functions << ")";
+ if (def->result_get())
+ functions << " : " << recurse(def->result_get());
+ ast::Exp* body = recurse(def->body_get());
+ // Cast the return value of the function if needed.
+ if (def->result_get())
+ adapt_type(body, class_type_query(*def->body_get()),
+ class_type_query(*def->result_get()));
+ functions << " = " << body << "\n";
+ }
+
+ void DesugarVisitor::dispatch_function(parse::Tweast& functions,
+ const ast::TypeChunk& e,
+ const type::Class* cls,
+ const type::Method* method,
+ misc::symbol class_name,
+ dispatch_list_type& sub_dispatches)
+ {
+ for (const type::Class* c = cls->super_get(); c; c = c->super_get())
+ {
+ // If this class is not defined in the current chunk, then
+ // the subdispatch method is not needed yet (since it can
+ // only be called after the declaration of the said class.
+ if (std::ranges::any_of(e, [c](const ast::TypeDec* t) {
+ return class_type_query(*t) == c;
+ }))
+ continue;
+
+ // Determine if the class c implements our method. If not,
+ // we do not need to write a sub dispatch method for it.
+ auto meth_it = std::ranges::find_if(
+ c->meths_get(), [method](const type::Method* meth) {
+ return meth->name_get() == method->name_get();
+ });
+
+ if (meth_it == c->meths_get().end())
+ continue;
+
+ const type::Method* parent_method = *meth_it;
+
+ // Since we're looping inside a chunk, we do not rebuild an
+ // already built sub dispatch method.
+ auto disp_it = sub_dispatches.emplace(c, parent_method);
+
+ if (!disp_it.second)
+ continue;
+
+ // Increments the dispatch counter.
+ if (dispatch_map_.find(parent_method) == dispatch_map_.end())
+ dispatch_map_[parent_method] = 2;
+ else
+ dispatch_map_[parent_method] = dispatch_map_[parent_method] + 1;
+
+ // Keep track of the added dispatch.
+ dispatch_added_ += parent_method;
+
+ // We build the subdispatch method.
+ functions << " function " << dispatch_fun_name(c, parent_method)
+ << " (self : " << class_variant_prefix << class_names_(c);
+ // Get the other arguments.
+ const ast::MethodDec* def;
+ // FIXME DONE: Some code was deleted here (Initialize def).
+ def = parent_method->def_get();
+ for (const ast::VarDec* arg : def->formals_get())
+ functions << ", " << arg->name_get() << " : "
+ << recurse(*arg->type_name_get());
+ functions << ")";
+ if (def->result_get())
+ functions << " : " << recurse(def->result_get());
+ functions << " = " << dispatch_switch(c, parent_method, &e, method);
+ }
+
+ functions << " function " << dispatch_fun_name(cls, method)
+ << " (self : " << class_variant_prefix << class_name;
+ // Get the other arguments.
+ const ast::MethodDec* def;
+ // FIXME DONE: Some code was deleted here (Initialize def).
+ def = method->def_get();
+ for (const ast::VarDec* arg : def->formals_get())
+ functions << ", " << arg->name_get() << " : "
+ << recurse(*arg->type_name_get());
+ functions << ")";
+ if (def->result_get() != nullptr)
+ functions << " : " << recurse(def->result_get());
+ functions << " = " << dispatch_switch(cls, method, &e);
+ }
+
+ void DesugarVisitor::handle_class(const ast::TypeChunk& e,
+ const type::Class* cls,
+ parse::Tweast& functions,
+ dispatch_list_type& sub_dispatches)
+ {
+ misc::symbol class_name = class_names_(cls);
+
+ /*---------------------------.
+ | Introduce a new class id. |
+ `---------------------------*/
+
+ class_ids_ << " var " << class_id_prefix << class_name
+ << " := " << cls->id_get() << "\n";
+
+ /*----------------------------------------------------.
+ | Create a record holding the actual class contents. |
+ `----------------------------------------------------*/
+
+ if (cls->has_data())
+ {
+ types_ << " type " << class_contents_prefix << class_name << " ="
+ << " { ";
+ // FIXME DONE: Some code was deleted here (Populate the record with attributes (names and types)).
+ const auto& attributes = cls->attrs_get();
+ const auto& first = attributes.begin();
+
+ for (auto attribute = first; attribute != attributes.end(); ++attribute)
+ {
+ if (attribute != first)
+ types_ << ", ";
+
+ types_ << attribute->name_get() << " : "
+ << type_symbol(&attribute->type_get());
+ }
+
+ types_ << " }\n";
+ }
+
+ /*--------------------------------------------------------------.
+ | Create a variant able to store any dynamic type corresponding |
+ | to this (static) class type. |
+ `--------------------------------------------------------------*/
+
+ types_ << " type " << class_variant_prefix << class_name << " ="
+ << variant_ty(cls);
+
+ /*-----------------------.
+ | Create a constructor. |
+ `-----------------------*/
+
+ desugar_constructor(functions, cls, class_name);
+
+ /*-------------------------------------------------------------.
+ | Create conversion routines from the class type to any of its |
+ | super types. |
+ `-------------------------------------------------------------*/
+
+ for (const type::Class* super_type = cls->super_get(); super_type;
+ super_type = super_type->super_get())
+ funs_tweast << upcast_function(cls, super_type);
+
+ /*-------------------------------------------------------------.
+ | Create conversion routines from the class type to any of its |
+ | subtypes. |
+ `-------------------------------------------------------------*/
+
+ for (const type::Class* subclass : cls->subclasses_get())
+ functions << downcast_function(cls, subclass);
+
+ for (const type::Method* m : cls->meths_get())
+ {
+ desugar_method(functions, m, class_name);
+ dispatch_function(functions, e, cls, m, class_name, sub_dispatches);
+ }
+ }
+
+ /* All type-related code is emitted into the top-level chunklist, so
+ that all classes are stored in the same typechunk, allowing them
+ to see their subclasses and be able to build a variant for each
+ of them. */
+ void DesugarVisitor::operator()(const ast::TypeChunk& e)
+ {
+ parse::Tweast functions;
+ // Is used to know what class/method pair we already have seen for the
+ // sub dispatch functions.
+ dispatch_list_type sub_dispatches;
+ for (const ast::TypeDec* t : e)
+ {
+ const type::Class* cls = nullptr;
+ // FIXME DONE: Some code was deleted here (Get the ty's class type).
+ cls = class_type_get(t->ty_get());
+
+ if (cls)
+ handle_class(e, cls, functions, sub_dispatches);
+ else
+ {
+ /* FIXME: In the rest of the visitor, the
+ simply-clone-this-node case is handled before the
+ desugar-this-node case. */
+ // Otherwise, clone the type declaration.
+ ast::TypeDec* typedec = recurse(*t);
+ assertion(typedec);
+ types_ << *typedec << '\n';
+ }
+ }
+
+ ast::ChunkList* funs_list = parse::parse(functions);
+ result_ = funs_list;
+ }
+
+ /*------------------------------------------------.
+ | Desugar class instantiations and object usage. |
+ `------------------------------------------------*/
+
+ void DesugarVisitor::operator()(const ast::VarDec& e)
+ {
+ /* We don't desugar everything using concrete syntax here, because
+ it would require a lot of additional manipulations, as we
+ cannot easily produce a single VarDec from a parsing. Also
+ working from VarChunk (with an `s') doesn't help much either, as
+ VarDec (with no `s') are also found in FunctionDec. */
+
+ // If this is not an object instantiation, delegate to the cloner.
+
+ const type::Class* class_type = class_type_query(e);
+ if (!class_type)
+ return super_type::operator()(e);
+
+ // Otherwise, handle the different cases.
+ const ast::Location& location = e.location_get();
+ ast::NameTy* type_name = nullptr;
+ ast::Exp* init = nullptr;
+ if (e.init_get())
+ {
+ // Object (variable) declaration.
+ if (e.type_name_get())
+ {
+ type_name = recurse(e.type_name_get());
+ init = recurse(e.init_get());
+ // If the dynamic type is non-nil and different from the
+ // static type, cast INIT to the latter.
+ // FIXME DONE: Some code was deleted here.
+ if (!init)
+ {
+ unreachable();
+ }
+
+ const type::Class* name_type = class_type_get(*type_name);
+ const type::Class* init_type = class_type_get(*init);
+ if (name_type != init_type)
+ {
+ adapt_type(init, name_type, init_type);
+ }
+ // Up to here
+ }
+ else
+ // No manifest type: simply clone the declaration as-is.
+ return super_type::operator()(e);
+ }
+ else
+ // Formal declaration.
+ type_name = recurse(e.type_name_get());
+
+ misc::symbol name = e.name_get();
+
+ result_ = new ast::VarDec(location, name, type_name, init);
+ postcondition(type_name || init);
+ }
+
+ // Desugar a class instantiation as a call to the desugared ctor routine.
+ void DesugarVisitor::operator()(const ast::ObjectExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const ast::Location location = e.location_get();
+
+ const std::string class_name = e.type_name_get().name_get();
+
+ const std::string call_name = class_ctor_prefix + class_name;
+ const auto args = new ast::exps_type;
+ result_ = new ast::CallExp(location, call_name, args);
+ }
+
+ void DesugarVisitor::operator()(const ast::IfExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ast::Exp* cond = recurse(e.test_get());
+ ast::Exp* then_clause = recurse(e.thenclause_get());
+ ast::Exp* else_clause = recurse(e.elseclause_get());
+ result_ = new ast::IfExp(e.location_get(), cond, then_clause, else_clause);
+ }
+
+ void DesugarVisitor::operator()(const ast::AssignExp& e)
+ {
+ // If this is not an object assignment, delegate to the cloner.
+ const type::Class* lhs_class_type;
+ // FIXME DONE: Some code was deleted here.
+ lhs_class_type = class_type_query(e.var_get());
+
+ if (!lhs_class_type)
+ return super_type::operator()(e);
+
+ // Duplicate the subtrees of E.
+ ast::Var* var = nullptr;
+ // FIXME DONE: Some code was deleted here (Recurse).
+ var = recurse(e.var_get());
+
+ ast::Exp* exp = nullptr;
+ // FIXME DONE: Some code was deleted here (Recurse).
+ exp = recurse(e.exp_get());
+
+ // If the RHS type is non-nil and different from the LHS type,
+ // cast EXP to the latter.
+ // FIXME DONE: Some code was deleted here.
+ const type::Class* rhs_class_type = class_type_get(*exp);
+ if (lhs_class_type != rhs_class_type)
+ {
+ adapt_type(exp, rhs_class_type, lhs_class_type);
+ }
+ // Up to here
+
+ ast::Exp* assignment =
+ parse::parse(parse::Tweast() << var << " := " << exp);
+ result_ = assignment;
+ }
+
+ ast::exps_type* DesugarVisitor::recurse_args(const ast::exps_type& actuals,
+ const type::Record& formals)
+ {
+ // For each argument, check the type of the actual argument
+ // against the formal one. If they are two different class types,
+ // convert the actual argument to the expected type.
+ auto args = new ast::exps_type;
+ ast::exps_type::const_iterator i;
+ type::Record::const_iterator j;
+ for (i = actuals.begin(), j = formals.begin();
+ i != actuals.end() && j != formals.end(); ++i, ++j)
+ {
+ // Clone the argument.
+ ast::Exp* arg = recurse(**i);
+
+ // In the case of a class, handle the case of a (non-nil) actual
+ // argument having a different type than the corresponding
+ // formal.
+ const type::Type* formal_type = &j->type_get().actual();
+ auto formal_class_type = dynamic_cast<const type::Class*>(formal_type);
+ // FIXME DONE: Some code was deleted here.
+ // How to check if this arg is non nil ?
+ // Checking if arg is not a nullptr ?
+ if (formal_class_type && arg)
+ {
+ const type::Type* arg_type = &((*i)->type_get()->actual());
+ auto arg_class_type = dynamic_cast<const type::Class*>(arg_type);
+ adapt_type(arg, arg_class_type, formal_class_type);
+ }
+ // Up to here
+ args->emplace_back(arg);
+ }
+ return args;
+ }
+
+ void DesugarVisitor::operator()(const ast::ArrayExp& e)
+ {
+ // We want to allow this:
+ // let
+ // class A {}
+ // class B extends A {}
+ // type arrtype = array of A
+ // var arr := arrtype[10] of new B
+ // in
+ // arr[0] := new B;
+ // arr[1] := new A
+ // end
+ // FIXME DONE: Some code was deleted here.
+
+ parse::Tweast input;
+ const type::Type* contener_type = &(e.type_name_get().type_get()->actual());
+ const type::Type* init_type = &(e.init_get().type_get()->actual());
+
+ auto contener_class_type = dynamic_cast<const type::Class*>(contener_type);
+ auto init_class_type = dynamic_cast<const type::Class*>(init_type);
+
+ ast::Exp* reced = recurse(e.init_get());
+ if (contener_class_type && init_class_type && reced)
+ {
+ adapt_type(reced, init_class_type, contener_class_type);
+ }
+
+ result_ = recurse(e);
+ }
+
+ void DesugarVisitor::operator()(const ast::RecordExp& e)
+ {
+ // We want to allow this:
+ // let
+ // class A {}
+ // class B extends A {}
+ // type rectype = { a : A }
+ // var rec := rectype { a = new B }
+ // in
+ // end
+ // FIXME DONE: Some code was deleted here.
+
+ const type::Type* rec_type = &(e.type_get()->actual());
+ auto actual_rec_type = dynamic_cast<const type::Record*>(rec_type);
+
+ if (actual_rec_type)
+ {
+ ast::fieldinits_type::const_iterator i;
+ type::Record::const_iterator j;
+ for (i = e.fields_get().begin(), j = actual_rec_type->fields_get().begin();
+ i != e.fields_get().end() && j != actual_rec_type->fields_get().end();
+ ++i, ++j)
+ {
+ const type::Type* given_type = &((*i)->init_get().type_get()->actual());
+ const type::Type* asked_type = &j->type_get().actual();
+ auto class_given = dynamic_cast<const type::Class*>(given_type);
+ auto class_asked = dynamic_cast<const type::Class*>(asked_type);
+
+ ast::Exp* reced = recurse((*i)->init_get());
+
+ if (class_given && class_asked && reced)
+ {
+ adapt_type(reced, class_given, class_asked);
+ }
+ }
+ }
+
+ // Maybe need to change this because we may need to create another
+ result_ = recurse(e);
+ }
+
+ void DesugarVisitor::operator()(const ast::CallExp& e)
+ {
+ const type::Function* function_type;
+ // FIXME DONE: Some code was deleted here.
+ const ast::FunctionDec* interm = e.def_get();
+ function_type = dynamic_cast<const type::Function*>(interm);
+
+ if (!interm)
+ {
+ unreachable();
+ }
+
+ const ast::Location& location = e.location_get();
+ // FIXME DONE: Some code was deleted here (Grab name).
+ misc::symbol name = e.name_get();
+
+ // FIXME DONE: Some code was deleted here (Actual arguments).
+ const ast::exps_type& arguments = e.args_get();
+
+ // (Types of) formal arguments.
+ const type::Record& formals = function_type->formals_get();
+ // Desugar the arguments and handle possible polymorphic assignments.
+ // FIXME DONE: Some code was deleted here.
+ ast::exps_type* final_args = recurse_args(arguments, formals);
+
+ // FIXME DONE: Some code was deleted here (Instantiate into result).
+ result_ = new ast::CallExp(location, name, final_args);
+ }
+
+ /*------------------------------------.
+ | Desugar accesses to class members. |
+ `------------------------------------*/
+
+ void DesugarVisitor::operator()(const ast::FieldVar& e)
+ {
+ // Check the type of the variable to see whether it is a class or
+ // a record.
+ const type::Class* class_type;
+ // FIXME DONE: Some code was deleted here.
+ class_type = class_type_query(e.var_get());
+
+ // If this is not a class, delegate to the cloner.
+ if (!class_type)
+ return super_type::operator()(e);
+
+ // FIXME DONE: Some code was deleted here (Grab name).
+ misc::symbol name = e.name_get();
+
+ // Otherwise, desugar this FieldVar as an access to an attribute.
+
+ // Look for the attribute within the class and its base classes.
+ const type::Class* owner = nullptr;
+ for (const type::Class* c = class_type; c; c = c->super_get())
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (c->attr_find(name))
+ {
+ owner = c;
+ break;
+ }
+ }
+ assertion(owner);
+
+ ast::Var* var;
+ // FIXME DONE: Some code was deleted here (Recurse).
+ var = recurse(e.var_get());
+
+ ast::Exp* attr_var =
+ parse::parse(parse::Tweast() << var << "." << variant_field_prefix
+ << class_names_(owner) << "."
+ // FIXME DONE ??: Some code was deleted here.
+ << name
+ );
+ result_ = attr_var;
+ }
+
+ void DesugarVisitor::operator()(const ast::LetExp& e)
+ {
+ // Save the current scope situation for dispatched methods
+ auto saved_dispatch_added_ = dispatch_added_;
+ dispatch_added_.clear();
+
+ super_type::operator()(e);
+
+ // After exiting the scope, remove unreachable dispatch methods
+ for (const auto* meth : dispatch_added_)
+ {
+ if (dispatch_map_[meth] == 2)
+ dispatch_map_.take(meth);
+ else
+ dispatch_map_[meth] -= 1;
+ }
+
+ // Resume the current scope
+ dispatch_added_ = saved_dispatch_added_;
+ }
+
+ void DesugarVisitor::operator()(const ast::MethodCallExp& e)
+ {
+ const type::Method* method_type;
+ // FIXME DONE: Some code was deleted here (Initialize method_type).
+ method_type = dynamic_cast<const type::Method*>(&e.def_get()->type_get()->actual());
+ // Maybe we need this ?
+ if (!method_type)
+ {
+ unreachable();
+ }
+
+ const type::Class* owner_type = method_type->owner_get();
+
+ const ast::Location& location = e.location_get();
+ std::string name = dispatch_fun_name(owner_type, method_type);
+
+ // FIXME DONE: Some code was deleted here (Fetch actual arguments).
+ // ???????????????????????????????????????????????????????????
+ const ast::exps_type actual_args = e.args_get();
+
+ // (Types of) formal arguments.
+ const type::Record& formals = method_type->formals_get();
+ // Desugar the arguments and handle possible polymorphic assignements.
+ ast::exps_type* args;
+ // FIXME DONE: Some code was deleted here (Initialize args).
+ args = recurse_args(actual_args, formals);
+
+ // Process the target of the method call, and convert it to the
+ // expected type if needed.
+ ast::Exp* object;
+ // FIXME DONE: Some code was deleted here (Recurse).
+ object = recurse(e.object_get());
+
+ // FIXME DONE: Some code was deleted here (Adapt type).
+ const type::Class* item_type = class_type_query(*object);
+ adapt_type(object, item_type, owner_type);
+ // Prepend the target to the actual arguments, as the desugared
+ // method expects to find it as its first arguments.
+ args->insert(args->begin(), object);
+
+ // Turn the method call into a function call to the desugared method.
+ // FIXME DONE: Some code was deleted here (Instanciate into result).
+ ast::Var* finial = dynamic_cast<ast::Var*>(object);
+ if (!finial)
+ {
+ unreachable();
+ }
+ result_ = new ast::MethodCallExp(location, name, args, finial);
+ }
+
+ /*--------------------------.
+ | New types and functions. |
+ `--------------------------*/
+
+ // Introduce a desugared builtin Object in the top-level function.
+ void DesugarVisitor::operator()(const ast::FunctionDec& e)
+ {
+ bool is_main;
+ // FIXME DONE: Some code was deleted here (Setup is_main).
+ is_main = e.name_get() == "_main";
+ if (is_main)
+ {
+ // Desugared data structures of the builtin Object.
+ types_ << " type " << class_variant_prefix
+ << "Object =" << variant_ty(&type::Class::object_instance());
+ // Object's class id.
+ class_ids_ << " var " << class_id_prefix
+ << "Object := "
+ " "
+ << type::Class::object_instance().id_get();
+ }
+
+ // Process E.
+ super_type::operator()(e);
+ if (is_main)
+ {
+ // Object's ctor.
+ funs_tweast << " function " << class_ctor_prefix
+ << "Object() :"
+ " "
+ << class_variant_prefix << "Object =";
+ // Initialize the variant (a single field is filled, the one
+ // corresponding to Object).
+ field_inits_type object_init;
+ misc::put(object_init, &type::Class::object_instance(),
+ std::string(class_contents_prefix) + "Object {}");
+ // Create the variant.
+ funs_tweast << variant_exp(&type::Class::object_instance(),
+ &type::Class::object_instance(),
+ object_init);
+
+ // Parse the built TWEASTs.
+ ast::ChunkList* types = parse::parse(types_);
+ ast::ChunkList* class_ids = parse::parse(class_ids_);
+ ast::ChunkList* funs = parse::parse(funs_tweast);
+ // Gather these declarations.
+ types->splice_back(*class_ids);
+ types->splice_back(*funs);
+ // Add them to the top of the program.
+ auto res = dynamic_cast<ast::FunctionDec*>(result_);
+ parse::Tweast input;
+ input << "let " << types << " in " << res->body_get() << " end";
+ res->body_set(parse::parse(input));
+ }
+
+ // Cast the return value of the function if needed.
+ if (e.body_get() && e.result_get())
+ {
+ const type::Class* body_type = class_type_query(*e.body_get());
+ const type::Class* result_type = class_type_query(*e.result_get());
+ if (body_type && result_type && body_type != result_type)
+ {
+ auto res = dynamic_cast<ast::FunctionDec*>(result_);
+ parse::Tweast input;
+ input << upcast_fun_name(body_type, result_type) << " ("
+ << res->body_get() << ")";
+ res->body_set(parse::parse(input));
+ }
+ }
+ }
+
+ void DesugarVisitor::operator()(const ast::NameTy& e)
+ {
+ // Check if E is the name of a class; if not, just clone it.
+ const type::Class* class_type = class_type_query(e);
+ if (!class_type)
+ return super_type::operator()(e);
+
+ // Otherwise, desugar the name of E.
+ const ast::Location& location = e.location_get();
+ result_ = new ast::NameTy(
+ location, class_variant_prefix + class_names_(class_type).get());
+ }
+
+} // namespace object
diff --git a/tiger-compiler/src/object/desugar-visitor.hh b/tiger-compiler/src/object/desugar-visitor.hh
new file mode 100644
index 0000000..3c2b455
--- /dev/null
+++ b/tiger-compiler/src/object/desugar-visitor.hh
@@ -0,0 +1,301 @@
+/**
+ ** \file object/desugar-visitor.hh
+ ** \brief Declaration of object::DesugarVisitor.
+ */
+
+#pragma once
+
+#include <astclone/cloner.hh>
+#include <object/fwd.hh>
+#include <parse/tweast.hh>
+
+namespace object
+{
+ /// \brief Desugar some object structures while duplicating an Ast.
+ class DesugarVisitor : public astclone::Cloner
+ {
+ public:
+ /// Superclass.
+ using super_type = astclone::Cloner;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a DesugarVisitor.
+ DesugarVisitor(const class_names_type& class_names);
+
+ /// Special version of the visit of a ChunkList allowing the
+ /// transformation of an ast::ChunkInterface to either a single ast::ChunkInterface or
+ /// to an ast::ChunkList.
+ void operator()(const ast::ChunkList& e) override;
+
+ /// \name Desugar class declarations.
+ /// \{
+
+ /// Desugar class declarations.
+ void operator()(const ast::TypeChunk& e) override;
+ /// Handle the builtin Object.
+ void operator()(const ast::FunctionDec& e) override;
+ /// Desugar class names.
+ void operator()(const ast::NameTy& e) override;
+
+ /// \}
+
+ /// \name Desugar class instantiations and object usage.
+ /// \{
+
+ /// Desugar polymorphic initializations.
+ void operator()(const ast::VarDec& e) override;
+ /// Desugar manifest objects.
+ void operator()(const ast::ObjectExp& e) override;
+ /// Desugar polymorphic branching.
+ void operator()(const ast::IfExp& e) override;
+ /// Desugar polymorphic assignments.
+ void operator()(const ast::AssignExp& e) override;
+ /// Desugar polymorphic insertion.
+ void operator()(const ast::ArrayExp& e) override;
+ void operator()(const ast::RecordExp& e) override;
+ /// Add object casts around arguments when needed.
+ void operator()(const ast::CallExp& e) override;
+
+ /// \}
+
+ /// \name Desugar accesses to class members.
+ /// \{
+
+ /// Desugar accesses to attributes.
+ void operator()(const ast::FieldVar& e) override;
+
+ /// Handle dynamic dispatch within scope.
+ void operator()(const ast::LetExp& e) override;
+
+ /// Desugar calls to methods.
+ void operator()(const ast::MethodCallExp& e) override;
+
+ /// \}
+
+ /// \brief Desugar actuals arguments in routine calls.
+ ///
+ /// \param actuals the actual arguments of the initial AST
+ /// \param formals the formal arguments of the routine
+ /// \return the desugared actual arguments
+ ast::exps_type* recurse_args(const ast::exps_type& actuals,
+ const type::Record& formals);
+
+ /// A list of classes (e.g., useful to represent a set of subclasses).
+ using classes_type = std::vector<const type::Class*>;
+
+ private:
+ /// \name Code generation.
+ /// \{
+
+ using pair_class_method =
+ std::pair<const type::Class*, const type::Method*>;
+ using dispatch_list_type = std::set<pair_class_method>;
+
+ /// \brief Desugar the constructor of the current class
+ ///
+ /// \param functions the tweast containing the constructor being desugared
+ /// \param cls the class whose constructor is being desugared
+ /// \param class_name the desugared version of the class name
+ void desugar_constructor(parse::Tweast& functions,
+ const type::Class* cls,
+ misc::symbol class_name);
+
+ /// \brief Desugar the current method.
+ ///
+ /// \param functions the tweast containing the method being desugared
+ /// \param method the methods being desugared
+ /// \param class_name the desugared version of the class name
+ void desugar_method(parse::Tweast& functions,
+ const type::Method* method,
+ misc::symbol class_name);
+
+ /// \brief Dispatch the method between the different classes.
+ ///
+ /// \param functions the tweast containing the dispatch
+ /// \param e the block of type being processed
+ /// \param cls the cls being desugared
+ /// \param method the method being dispatched
+ /// \param class_name the desugared version of the class name
+ /// \param sub_dispatches the processed classes/methods for dispatch
+ void dispatch_function(parse::Tweast& functions,
+ const ast::TypeChunk& e,
+ const type::Class* cls,
+ const type::Method* method,
+ misc::symbol class_name,
+ dispatch_list_type& sub_dispatches);
+
+ /// \brief Handle a class declaration.
+ ///
+ /// This is a declaration of a class: remove it and replace it with
+ ///
+ /// (1) a class type label (integer constant),
+ /// (2) new data structures:
+ /// - an actual structure holding the data of the class,
+ /// - a variant able to store any concrete type for this
+ /// class;
+ /// (3) new functions:
+ /// - a constructor,
+ /// - conversion routines used in polymorphic assignments (upcasts),
+ /// - conversion routines used in dynamic dispatch (downcasts),
+ /// - (desugared) methods,
+ /// - dispatch functions.
+ ///
+ /// We must take care of the order in which these declarations
+ /// are injected, since (1), (2) and (3) are declaration of
+ /// different kinds (variable, type and function respectively).
+ /// Mixing them would break the block of type declarations
+ /// (TypeChunk, or ``chunk'' of TypeDec's) being currently
+ /// visited. Thus we collect all class definitions from E,
+ /// replace them by new data structures ((2)) and inject the
+ /// rest of the new material *after* the TypeChunk ((1) and
+ /// (3)).
+ void handle_class(const ast::TypeChunk& e,
+ const type::Class* cls,
+ parse::Tweast& functions,
+ dispatch_list_type& sub_dispatches);
+
+ /// \brief Return the name of a type.
+ ///
+ /// \param type either a builtin type or a type::Named
+ /// \result the name of the type
+ std::string type_symbol(const type::Type* type);
+
+ /// Return the name of the upcast function between types \a from
+ /// and \a to.
+ std::string upcast_fun_name(const type::Class* from, const type::Class* to);
+ /// Return the name of the downcast function between types \a from
+ /// and \a to.
+ std::string downcast_fun_name(const type::Class* from,
+ const type::Class* to);
+
+ /// Return the name of the dispatch function for \a method,
+ /// defined in class \a owner.
+ std::string dispatch_fun_name(const type::Class* owner,
+ const type::Method* method);
+
+ /// Check if the type \a source_type of \a source_exp matches
+ /// \a target_type, and generate a type conversion wrapper if
+ /// needed.
+ void adapt_type(ast::Exp*& source_exp,
+ const type::Class* source_type,
+ const type::Class* target_type);
+
+ /// The type of a list of initializations for the field of a variant.
+ using field_inits_type = misc::map<const type::Class*, std::string>;
+
+ /// \brief Generate a variant expression.
+ ///
+ /// \param static_type the type of the class whose variant is built
+ /// \param exact_type the exact type of the data stored in the variant
+ /// \param inits the initalization value of the variant (must be
+ /// of type \a dynamic_type).
+ /// \return the generated variant expression
+ ast::Exp* variant_exp(const type::Class* static_type,
+ const std::string& exact_type,
+ const field_inits_type& inits);
+
+ /// Syntactic sugar for the previous routine.
+ ast::Exp* variant_exp(const type::Class* static_type,
+ const type::Class* dynamic_type,
+ const field_inits_type& inits);
+
+ /// \brief Populate a variant fields.
+ ///
+ /// \param class_type the type of the class used to populate the variant
+ /// \param input the tweast containing the variant being built
+ void fill_variant_fields(const type::Class* class_type,
+ parse::Tweast* input);
+
+ /// \brief Generate code for a variant type on a TWEAST.
+ ///
+ /// Contrary to object::DesugarVisitor::variant_exp, we
+ /// cannot directly generate an expression, since the client
+ /// TWEAST won't accept an ast::Ty* as a metavariable.
+ ///
+ /// \param class_type the type of the class whose variant is built
+ /// \return the TWEAST on which the code is generated
+ parse::Tweast* variant_ty(const type::Class* class_type);
+
+ /// \brief Populate an initialization list.
+ ///
+ /// \param class_type the type of the class used to populate the list
+ /// \param inits the initialization list
+ void fill_init_list(const type::Class* class_type, field_inits_type& inits);
+
+ /// \brief Generate a conversion routine.
+ ///
+ /// \param name the type of the generated function
+ /// \param source the type of the converted value
+ /// \param target the target type of the conversion
+ /// \param exact_type the exact type of the returned variant
+ /// \return the TWEAST on which the code is generated
+ parse::Tweast* cast_function(const std::string& name,
+ const type::Class* source,
+ const type::Class* target,
+ const type::Class* exact_type);
+
+ /// Syntactic sugar for object::DesugarVisitor::cast_function,
+ /// used to generate an upcast function.
+ parse::Tweast* upcast_function(const type::Class* source,
+ const type::Class* target);
+
+ /// Syntactic sugar for object::DesugarVisitor::cast_function,
+ /// used to generate a downcast function.
+ parse::Tweast* downcast_function(const type::Class* source,
+ const type::Class* target);
+
+ /// \brief Generate an expression looking like a switch
+ /// expression, to dispatch a method call. Do not generate code
+ /// for classes outside typechunk. If this function is used to create a sub
+ /// dispatch function, recursive call should be true, in order to call
+ /// the previous dispatch function if nothing matches.
+ ///
+ /// \param class_type the static type of the class owning the method
+ /// \param method the called method
+ /// \param typechunk the current chunk
+ /// \param dispatch_method the recursively called dispatch method
+ /// \return the generated expression
+ ast::Exp* dispatch_switch(const type::Class* class_type,
+ const type::Method* method,
+ const ast::TypeChunk* typechunk,
+ const type::Method* dispatch_method = nullptr);
+
+ /// \brief Generate a (static) call to a desugared method.
+ ///
+ /// \note The dynamic dispatch must have been performed before
+ /// using this generator.
+ ///
+ /// \param class_name the class where the method resides
+ /// \param method_name the name of the method
+ /// \param target the name of the target (object)
+ /// \param formals the actual arguments (other than the target)
+ /// \return the TWEAST on which the code is generated
+ parse::Tweast* method_call(misc::symbol class_name,
+ misc::symbol method_name,
+ const std::string& target,
+ const ast::VarChunk& formals);
+
+ /// \}
+
+ private:
+ /// The names of the classes defined in the program.
+ class_names_type class_names_;
+
+ /// TWEAST of desugared types.
+ parse::Tweast types_;
+ /// TWEAST of class ids.
+ parse::Tweast class_ids_;
+
+ /// TWEAST of upcast functions.
+ parse::Tweast funs_tweast;
+
+ /// Vector keeping track of added dispatch functions within a scope.
+ misc::vector<const type::Method*> dispatch_added_;
+
+ /// Map / counter giving the correct current dispatch extensions for a method
+ misc::map<const type::Method*, unsigned int> dispatch_map_;
+ };
+
+} // namespace object
diff --git a/tiger-compiler/src/object/fwd.hh b/tiger-compiler/src/object/fwd.hh
new file mode 100644
index 0000000..7b7d779
--- /dev/null
+++ b/tiger-compiler/src/object/fwd.hh
@@ -0,0 +1,16 @@
+/**
+ ** \file object/fwd.hh
+ ** \brief Forward declarations of using types.
+ */
+
+#pragma once
+
+#include <misc/map.hh>
+#include <misc/symbol.hh>
+#include <type/class.hh>
+
+namespace object
+{
+ /// Names associated to class types.
+ using class_names_type = misc::map<const type::Class*, misc::symbol>;
+} // namespace object
diff --git a/tiger-compiler/src/object/libobject.cc b/tiger-compiler/src/object/libobject.cc
new file mode 100644
index 0000000..b7c7f72
--- /dev/null
+++ b/tiger-compiler/src/object/libobject.cc
@@ -0,0 +1,49 @@
+/**
+ ** \file object/libobject.cc
+ ** \brief Define exported object functions.
+ */
+
+// FIXME DONE: Some code was deleted here.
+#include <object/libobject.hh>
+#include <object/binder.hh>
+#include <object/renamer.hh>
+#include <object/type-checker.hh>
+
+namespace object
+{
+ /*-------.
+ | Bind. |
+ `-------*/
+
+ // FIXME DONE: Some code was deleted here.
+ misc::error bind_obj(ast::ChunkList* d)
+ {
+ Binder bdc = Binder();
+ bdc(d);
+ return bdc.error_get();
+ }
+
+ /*----------------.
+ | Compute types. |
+ `----------------*/
+
+ misc::error types_check(ast::Ast& tree)
+ {
+ TypeChecker type;
+ type(tree);
+ return type.error_get();
+ }
+
+ /*---------.
+ | Rename. |
+ `---------*/
+
+ class_names_type* rename(ast::Ast& tree)
+ {
+ // Rename.
+ Renamer rename;
+ rename(tree);
+ return rename.class_names_get();
+ }
+
+} // namespace object
diff --git a/tiger-compiler/src/object/libobject.hh b/tiger-compiler/src/object/libobject.hh
new file mode 100644
index 0000000..d153ef4
--- /dev/null
+++ b/tiger-compiler/src/object/libobject.hh
@@ -0,0 +1,82 @@
+/**
+ ** \file object/libobject.hh
+ ** \brief Declare functions and variables exported by object module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+#include <object/fwd.hh>
+
+namespace object
+{
+ /*-------.
+ | Bind. |
+ `-------*/
+
+ // FIXME DONE: Some code was deleted here.
+ /// \brief Bind the whole ast_object in place, return the error code
+ ///
+ /// \param last the ast you want to bind
+ ///
+ /// \return a misc::error that serve to indicate possible failure
+ misc::error bind_obj(ast::ChunkList* last);
+
+ /*----------------.
+ | Compute types. |
+ `----------------*/
+
+ /** \brief Check types allowing objects.
+
+ \param tree abstract syntax tree's root.
+
+ \return success of the type-checking. */
+ misc::error types_check(ast::Ast& tree);
+
+ /*---------.
+ | Rename. |
+ `---------*/
+
+ /// Rename the variables of an AST so that they each have a unique
+ /// name, with support for objects.
+ ///
+ /// \param tree abstract syntax tree's root, whose bindings and types
+ /// have been computed.
+ /// \return a newly allocated dictionnary of class names
+ class_names_type* rename(ast::Ast& tree);
+
+ /*------------------.
+ | Desugar objects. |
+ `------------------*/
+
+ /** \brief Remove objects constructs from an AST.
+
+ \param tree abstract syntax tree's root, whose bindings
+ and types have been computed, and whose
+ identifiers are all unique.
+ \param class_names the names of the class types of the AST
+
+ \return the desugared, bound and type-checked AST. */
+ template <typename A>
+ A* desugar(const A& tree, const class_names_type& class_names);
+
+ /** \brief Remove objects constructs from an AST without recomputing
+ its bindings nor its types.
+
+ This function acts like object::object_desugar, but stops just
+ after the desugaring step (in fact, object::desugar is built
+ upon this function). It is meant to be used as a test of
+ DesugarVisitor (i.e., even if the desugared tree is badly bound
+ or typed, it can still be pretty-printed).
+
+ \param tree AST to desugar.
+ \param class_names the names of the class types of the AST
+
+ \return the desugared AST. */
+ template <typename A>
+ A* raw_desugar(const A& tree, const class_names_type& class_names);
+
+} // namespace object
+
+#include <object/libobject.hxx>
diff --git a/tiger-compiler/src/object/libobject.hxx b/tiger-compiler/src/object/libobject.hxx
new file mode 100644
index 0000000..7c75b08
--- /dev/null
+++ b/tiger-compiler/src/object/libobject.hxx
@@ -0,0 +1,48 @@
+#pragma once
+
+/**
+ ** \file object/libobject.hxx
+ ** \brief Functions exported by the object module.
+ */
+
+#include <memory>
+
+#include <desugar/libdesugar.hh>
+#include <object/desugar-visitor.hh>
+#include <object/fwd.hh>
+
+namespace object
+{
+
+ /*------------------.
+ | Desugar objects. |
+ `------------------*/
+
+ template <typename A>
+ A* raw_desugar(const A& tree, const class_names_type& class_names)
+ {
+ // Desugar.
+ ::object::DesugarVisitor desugar(class_names);
+ desugar(tree);
+ return dynamic_cast<A*>(desugar.result_get());
+ }
+
+ template <typename A>
+ A* desugar(const A& tree, const class_names_type& class_names)
+ {
+ // Desugar.
+ A* desugared = raw_desugar(tree, class_names);
+ assertion(desugared);
+ std::unique_ptr<A> desugared_ptr(desugared);
+ // Recompute the bindings and the types.
+ ::desugar::bind_and_types_check(*desugared_ptr);
+ return desugared_ptr.release();
+ }
+
+ /// Explicit instantiations.
+ template ast::ChunkList* raw_desugar(const ast::ChunkList&,
+ const class_names_type&);
+ template ast::ChunkList* desugar(const ast::ChunkList&,
+ const class_names_type&);
+
+} // namespace object
diff --git a/tiger-compiler/src/object/local.am b/tiger-compiler/src/object/local.am
new file mode 100644
index 0000000..3c1eda9
--- /dev/null
+++ b/tiger-compiler/src/object/local.am
@@ -0,0 +1,33 @@
+## object module.
+
+src_libtc_la_SOURCES += \
+ %D%/libobject.hh \
+ %D%/libobject.cc \
+ %D%/libobject.hxx \
+ %D%/fwd.hh
+
+src_libtc_la_SOURCES += %D%/binder.hh %D%/binder.cc
+
+src_libtc_la_SOURCES += %D%/type-checker.hh %D%/type-checker.cc \
+ %D%/renamer.hh %D%/renamer.cc
+
+src_libtc_la_SOURCES += %D%/desugar-visitor.hh %D%/desugar-visitor.cc
+
+
+# Tests.
+check_PROGRAMS += %D%/test-parse
+%C%_test_parse_LDADD = src/libtc.la
+
+check_PROGRAMS += %D%/test-bind
+%C%_test_bind_LDADD = src/libtc.la
+
+check_PROGRAMS += %D%/test-type
+%C%_test_type_LDADD = src/libtc.la
+
+# FIXME: Add a test for object::Renamer.
+
+check_PROGRAMS += %D%/test-desugar
+%C%_test_desugar_LDADD = src/libtc.la
+
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/object/renamer.cc b/tiger-compiler/src/object/renamer.cc
new file mode 100644
index 0000000..0abae10
--- /dev/null
+++ b/tiger-compiler/src/object/renamer.cc
@@ -0,0 +1,142 @@
+/**
+ ** \file object/renamer.cc
+ ** \brief Implementation of object::Renamer.
+ */
+
+#include <memory>
+
+#include <object/renamer.hh>
+
+namespace object
+{
+ using namespace ast;
+
+ Renamer::Renamer()
+ : super_type()
+ , class_names_(new class_names_type)
+ , within_class_ty_(false)
+ {
+ // Give a name to the built-in class Object.
+ misc::put(*class_names_, &type::Class::object_instance(), "Object");
+ }
+
+ /**
+ * Get the node's type as a class, if it references one
+ * @param ast Any typable node
+ * @return The node's referenced class type if there is one, nullptr if not
+ */
+ static inline const type::Class* get_referenced_class_type(const Typable& ast)
+ {
+ return dynamic_cast<const type::Class*>(&ast.type_get()->actual());
+ }
+
+ /*----------------------------.
+ | Visiting definition sites. |
+ `----------------------------*/
+
+ void Renamer::operator()(ast::VarDec& e)
+ {
+ if (within_class_ty_)
+ // Don't rename class attributes.
+ super_type::super_type::operator()(e);
+ else
+ // But still rename other variable declarations.
+ super_type::operator()(e);
+ }
+
+ void Renamer::operator()(ast::MethodChunk& e)
+ {
+ // FIXME DONE: Some code was deleted here (Just recurse on children nodes).
+ chunk_visit<MethodChunk>(e);
+ }
+
+ void Renamer::operator()(ast::MethodDec& e)
+ {
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ /* We can't call bind::Binder::visit directly, because this method
+ delegates the recursion task to DefaultVisitor, which doesn't
+ have a proper operator() for MethodDec. This visitor however
+ knows how to handle a FunctionDec; therefore we upcast the
+ MethodDec to a FunctionDec before visiting it. */
+ ast::FunctionDec& fundec = e;
+ visit(fundec, &fundec);
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ void Renamer::operator()(ast::TypeDec& e)
+ {
+ // Rename.
+ // FIXME DONE: Some code was deleted here.
+ if (class_names_->find(get_referenced_class_type(e)) == class_names_->end())
+ super_type::operator()(e);
+
+ // Collect the name of the classes.
+ // FIXME DONE: Some code was deleted here.
+ if (auto classtype = get_referenced_class_type(e))
+ {
+ class_names_->insert(std::make_pair(classtype, e.name_get()));
+ }
+ }
+
+ /*-----------------------.
+ | Visiting usage sites. |
+ `-----------------------*/
+
+ void Renamer::operator()(ast::MethodCallExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ super_type::operator()(e.object_get());
+ e.name_set(e.def_get()->name_get());
+ CallExp& upcast = e;
+ precondition(upcast.def_get() == nullptr);
+ super_type::operator()(upcast);
+ }
+
+ /*--------------------------------------.
+ | Visiting other object-related nodes. |
+ `--------------------------------------*/
+
+ void Renamer::operator()(ast::ClassTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = true;
+ if (e.super_get().name_get() != "Object")
+ e.super_get().name_set(e.super_get().def_get()->name_get());
+ super_type::operator()(e.chunks_get());
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ void Renamer::operator()(ast::ObjectExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (auto name = class_names_->find(get_referenced_class_type(e));
+ name != class_names_->end())
+ e.type_name_get().name_set(name->second);
+ else
+ {
+ this->accept(e.type_name_get().def_get());
+ e.type_name_get().name_set(e.type_name_get().def_get()->name_get());
+ class_names_->insert(
+ std::make_pair(get_referenced_class_type(e),
+ e.type_name_get().name_get()));
+ }
+ }
+
+ void Renamer::operator()(ast::LetExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ bool saved_within_class_ty = within_class_ty_;
+ within_class_ty_ = false;
+ super_type::operator()(e);
+ within_class_ty_ = saved_within_class_ty;
+ }
+
+ /*--------------.
+ | Class names. |
+ `--------------*/
+
+ class_names_type* Renamer::class_names_get() const { return class_names_; }
+
+} // namespace object
diff --git a/tiger-compiler/src/object/renamer.hh b/tiger-compiler/src/object/renamer.hh
new file mode 100644
index 0000000..6c62a86
--- /dev/null
+++ b/tiger-compiler/src/object/renamer.hh
@@ -0,0 +1,79 @@
+/**
+ ** \file object/renamer.hh
+ ** \brief Implementation of object::Renamer.
+ */
+
+#pragma once
+
+#include <map>
+
+#include <bind/renamer.hh>
+#include <object/fwd.hh>
+
+namespace object
+{
+ /// \brief Perform identifier renaming within an AST (in place),
+ /// with support for objects.
+ class Renamer : public bind::Renamer
+ {
+ public:
+ using super_type = ::bind::Renamer;
+
+ // Import overloaded virtual functions.
+ using super_type::operator();
+
+ /// Build a Renamer.
+ Renamer();
+
+ // Visit methods.
+ /// \name Visiting definition sites.
+ /// \{
+ /// This method is like bind::Binder's, but prevent the renaming
+ /// of attributes.
+ void operator()(ast::VarDec& e) override;
+ /// Rename methods.
+ void operator()(ast::MethodChunk& e) override;
+ /// Rename a method.
+ void operator()(ast::MethodDec& e) override;
+ /// In addition to performing the renaming, collect the name of
+ /// the classes.
+ void operator()(ast::TypeDec& e) override;
+ /// \}
+
+ /// \name Visiting usage sites.
+ /// \{
+ void operator()(ast::MethodCallExp& e) override;
+ /// \}
+
+ /// \name Visiting other object-related nodes.
+ ///
+ /// These methods should be part of an ObjectDefaultVisitor, but
+ /// our current design makes the implementation (and the use) of
+ /// such a visitor difficult.
+ /// \{
+ void operator()(ast::ClassTy& e) override;
+ void operator()(ast::ObjectExp& e) override;
+ /// \}
+
+ /// \name Visiting LetExp.
+ ///
+ /// In order to handle variable declarations that might be
+ /// situated in a ClassTy and yet do not qualify as attributes.
+ /// \{
+ void operator()(ast::LetExp& e) override;
+ /// \}
+
+ /// Class names.
+ /// \{
+ /// Get the class names.
+ class_names_type* class_names_get() const;
+
+ private:
+ /// Dictionnary mapping class types to their names.
+ class_names_type* class_names_;
+ /// Are we in a class definition?
+ bool within_class_ty_;
+ /// \}
+ };
+
+} // namespace object
diff --git a/tiger-compiler/src/object/tasks.cc b/tiger-compiler/src/object/tasks.cc
new file mode 100644
index 0000000..c4d0929
--- /dev/null
+++ b/tiger-compiler/src/object/tasks.cc
@@ -0,0 +1,52 @@
+/**
+ ** \file object/tasks.cc
+ ** \brief Object module related tasks' implementation.
+ */
+
+#include <memory>
+
+#include <ast/tasks.hh>
+#include <astclone/libastclone.hh>
+#include <common.hh>
+#include <object/libobject.hh>
+#define DEFINE_TASKS 1
+#include <object/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace object::tasks
+{
+ void object_parse() {}
+
+ // FIXME DONE: Some code was deleted here.
+ void object_bind()
+ {
+ task_error() << bind_obj(ast::tasks::the_program.get())
+ << &misc::error::exit_on_error;
+ }
+
+ void object_types_compute()
+ {
+ task_error() << ::object::types_check(*ast::tasks::the_program)
+ << &misc::error::exit_on_error;
+ }
+
+ static std::unique_ptr<class_names_type> class_names;
+
+ void object_rename()
+ {
+ class_names.reset(::object::rename(*ast::tasks::the_program));
+ }
+
+ void object_desugar()
+ {
+ astclone::apply(::object::desugar, ast::tasks::the_program,
+ *class_names.get());
+ }
+
+ void raw_object_desugar()
+ {
+ astclone::apply(::object::raw_desugar, ast::tasks::the_program,
+ *class_names.get());
+ }
+
+} // namespace object::tasks
diff --git a/tiger-compiler/src/object/tasks.hh b/tiger-compiler/src/object/tasks.hh
new file mode 100644
index 0000000..9a108f3
--- /dev/null
+++ b/tiger-compiler/src/object/tasks.hh
@@ -0,0 +1,60 @@
+/**
+ ** \file object/tasks.hh
+ ** \brief Object module related tasks.
+ */
+
+#pragma once
+
+#include <overload/binder.hh>
+#include <task/libtask.hh>
+
+namespace object::tasks
+{
+ TASK_GROUP("Object");
+
+ /// Enable object extensions.
+ BOOLEAN_TASK_DECLARE("o|object",
+ "enable object extensions",
+ enable_object_extensions_p,
+ "");
+
+ /// Parse the input file, allowing objects.
+ TASK_DECLARE("object-parse",
+ "parse a file, allowing objects",
+ object_parse,
+ "object parse");
+
+ // FIXME DONE: Some code was deleted here.
+ TASK_DECLARE("object-bindings-compute",
+ "bind the name uses to their definitions, allowing objects",
+ object_bind,
+ "object-parse");
+
+ /// Check for type violation, allowing objects.
+ TASK_DECLARE("object-types-compute",
+ "check for type violations, "
+ "allowing objects",
+ object_types_compute,
+ "object-bindings-compute");
+
+ /// Perform a renaming, before desugaring objects.
+ TASK_DECLARE("object-rename",
+ "rename identifiers to unique names, allowing objects",
+ object_rename,
+ "object-types-compute");
+
+ /// Remove syntactic sugar from the Ast.
+ TASK_DECLARE("object-desugar",
+ "remove object constructs from the program",
+ object_desugar,
+ "object-rename");
+
+ /// Remove syntactic sugar from the Ast without recomputing
+ /// bindings nor types.
+ TASK_DECLARE("raw-object-desugar",
+ "remove object constructs from the program "
+ "without recomputing bindings nor types",
+ raw_object_desugar,
+ "object-rename");
+
+} // namespace object::tasks
diff --git a/tiger-compiler/src/object/type-checker.cc b/tiger-compiler/src/object/type-checker.cc
new file mode 100644
index 0000000..76c4e88
--- /dev/null
+++ b/tiger-compiler/src/object/type-checker.cc
@@ -0,0 +1,405 @@
+/**
+ ** \file object/type-checker.cc
+ ** \brief Implementation for object/type-checker.hh.
+ */
+
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <boost/iterator/zip_iterator.hpp>
+
+#include <ast/all.hh>
+#include <object/type-checker.hh>
+#include <type/types.hh>
+
+namespace object
+{
+ TypeChecker::TypeChecker()
+ : super_type()
+ {
+ // Reset the subclasses of Object. This is required if several
+ // trees are processed during the compilation.
+ type::Class::object_instance().subclasses_clear();
+
+ // `self' variables are the only valid variables having a null
+ // declaration site. Use this property to tag them as read-only.
+ // FIXME DONE: Some code was deleted here.
+ var_read_only_.insert(nullptr);
+ }
+
+ /*--------------------------.
+ | The core of the visitor. |
+ `--------------------------*/
+
+ /*-----------------.
+ | Visiting /Var/. |
+ `-----------------*/
+
+ void TypeChecker::operator()(ast::SimpleVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (e.name_get() == "self")
+ type_default(e, current_);
+ else
+ super_type::operator()(e);
+ }
+
+ void TypeChecker::operator()(ast::FieldVar& e)
+ {
+ const type::Type* def_type = nullptr;
+ // FIXME DONE: Some code was deleted here (Grab type).
+ def_type = type(e.var_get());
+ auto class_type = dynamic_cast<const type::Class*>(&def_type->actual());
+
+ if (class_type)
+ {
+ // FIXME DONE: Some code was deleted here.
+ auto attr = class_type->attr_find(e.name_get());
+ if (attr == nullptr)
+ error(e, "No such attribute found");
+ else
+ type_default(e, attr->def_get()->type_get());
+ }
+ else
+ super_type::operator()(e);
+ }
+
+ /*----------------.
+ | Visiting /Ty/. |
+ `----------------*/
+
+ // Handle the case of `Object'.
+ void TypeChecker::operator()(ast::NameTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (e.name_get() == "Object")
+ {
+ type_default(e, &type::Class::object_instance());
+ }
+ else
+ super_type::operator()(e);
+ }
+
+ /*-----------------.
+ | Visiting /Exp/. |
+ `-----------------*/
+
+ void TypeChecker::operator()(ast::IfExp& e)
+ {
+ // We want to handle the following case
+ // let
+ // class A {}
+ // class B extends A { method print() = () }
+ // var a :=
+ // if 1 then
+ // new B
+ // else
+ // new A
+ // in
+ // a.print() /* error */
+ // end
+ // FIXME DONE: Some code was deleted here.
+ //Martial: Pré typage
+ super_type::operator()(e);
+ //Martial: Check mentionné au-dessus
+ if (auto then_class = dynamic_cast<type::Class*>(&e.thenclause_get());
+ then_class)
+ {
+ auto else_class = dynamic_cast<type::Class*>(&e.elseclause_get());
+ if (then_class->id_get() != else_class->id_get())
+ type_mismatch(e, "then clause", *e.thenclause_get().type_get(),
+ "else clause", *e.elseclause_get().type_get());
+ }
+ }
+
+ void TypeChecker::operator()(ast::OpExp& e)
+ {
+ // We want to only compare equal static object types.
+ // Otherwise, the desugarer emits wrong code on:
+ //
+ // let
+ // class A {}
+ // class B extends A {}
+ // var a := new A
+ // var b := new B
+ // in
+ // a = b
+ // end
+ // FIXME DONE: Some code was deleted here.
+ //Martial: Pré typage
+ super_type::operator()(e);
+ //Martial: Check mentionné au-dessus
+
+ const ast::OpExp::Oper operation_type = e.oper_get();
+ const auto a_class =
+ dynamic_cast<const type::Class*>(&e.left_get().type_get()->actual());
+ const auto b_class =
+ dynamic_cast<const type::Class*>(&e.right_get().type_get()->actual());
+
+ if (!a_class || !b_class || operation_type < ast::OpExp::Oper::eq
+ || operation_type > ast::OpExp::Oper::ne)
+ {
+ return;
+ }
+
+ if (a_class->id_get() != b_class->id_get())
+ {
+ type_mismatch(e, "left operand", *e.left_get().type_get(),
+ "right operand", *e.right_get().type_get());
+ }
+ }
+
+ void TypeChecker::operator()(ast::ObjectExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ type(e.type_name_get());
+ type_default(e, e.type_name_get().type_get());
+ }
+
+ void TypeChecker::operator()(ast::MethodCallExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ type(e.object_get());
+ for (ast::Exp* exp : e.args_get())
+ {
+ type(*exp);
+ }
+ const auto actual_params = e.args_get();
+
+ const auto obj =
+ dynamic_cast<const type::Class*>(&e.object_get().type_get()->actual());
+ assertion(obj != nullptr);
+ const auto meth = obj->meth_find(e.name_get());
+
+ if (!meth)
+ {
+ // std::string error_message = "method ";
+ error(e,
+ "method " + e.name_get().get()
+ + " does not exist within the "
+ "class");
+ type_default(e, &default_type);
+ return;
+ }
+
+ e.def_set(const_cast<ast::MethodDec*>(meth->def_get()));
+ const auto expected_params = e.def_get()->formals_get().decs_get();
+
+ if (actual_params.size() != expected_params.size())
+ {
+ error(e,
+ std::string(std::to_string(expected_params.size())
+ + " parameters expected but got "
+ + std::to_string(actual_params.size())));
+ }
+ else
+ {
+ std::for_each(
+ boost::make_zip_iterator(
+ boost::make_tuple(expected_params.begin(), actual_params.begin())),
+ boost::make_zip_iterator(
+ boost::make_tuple(expected_params.end(), actual_params.end())),
+ [this, &e](const boost::tuple<ast::VarDec*, ast::Exp*>& params) {
+ check_types(e, "expected", *params.get<0>(), "actual",
+ *params.get<1>());
+ });
+ }
+
+ type_default(e,
+ &dynamic_cast<const type::Method*>(e.def_get()->type_get())
+ ->result_get());
+ }
+
+ /*-----------------.
+ | Visiting /Dec/. |
+ `-----------------*/
+
+ /*--------------------.
+ | Visiting TypeChunk. |
+ `--------------------*/
+
+ void TypeChecker::operator()(ast::TypeChunk& e)
+ {
+ // Visit the header and the body of the typechunk, as in
+ // type::TypeChecker.
+ super_type::operator()(e);
+
+ // However, class members are not considered part of the body of
+ // their class here; they are processed separately to allow valid
+ // uses of the class from its members.
+ for (ast::TypeDec* typedec : e)
+ {
+ ast::Ty& ty = typedec->ty_get();
+ if (auto classty = dynamic_cast<ast::ClassTy*>(&ty))
+ visit_dec_members(*classty);
+ }
+ }
+
+ /*----------------------.
+ | Visiting MethodChunk. |
+ `----------------------*/
+
+ void TypeChecker::operator()(ast::MethodChunk& e)
+ {
+ precondition(within_class_body_p_);
+ within_class_body_p_ = false;
+
+ // Two passes: once on headers, then on bodies.
+ for (ast::MethodDec* m : e)
+ visit_dec_header(*m);
+ for (ast::MethodDec* m : e)
+ visit_dec_body(*m);
+
+ within_class_body_p_ = true;
+ }
+
+ // Store the type of this method.
+ void TypeChecker::visit_dec_header(ast::MethodDec& e)
+ {
+ assertion(current_);
+
+ // FIXME DONE: Some code was deleted here.
+ const type::Record* formals = type(e.formals_get());
+
+ const type::Type* return_type = e.result_get() != nullptr
+ ? type(*e.result_get())
+ : &type::Void::instance();
+
+ auto type =
+ std::make_unique<type::Method>(e.name_get(), current_, formals, *return_type, &e);
+
+ // Check for multiple definitions in the current class.
+ for (const type::Method* m : current_->meths_get())
+ if (m->name_get() == e.name_get())
+ return error(e, "method multiply defined", e.name_get());
+
+ // Check for signature conformance w.r.t. super class, if applicable.
+ const auto* super_meth_type =
+ dynamic_cast<const type::Method*>(current_->meth_type(e.name_get()));
+ // FIXME DONE: Some code was deleted here.
+ if (super_meth_type && !super_meth_type->compatible_with(*type.get()))
+ type_mismatch(e, "super class method signature", *super_meth_type,
+ "child class method signature", *type.get());
+ else
+ type_default(e, type.get());
+ current_->meth_add(type.release());
+ }
+
+ // Type check this method's body.
+ void TypeChecker::visit_dec_body(ast::MethodDec& e)
+ {
+ visit_routine_body<type::Method>(e);
+ }
+
+ /*---------------.
+ | Visit VarDec. |
+ `---------------*/
+
+ void TypeChecker::operator()(ast::VarDec& e)
+ {
+ // Signal that we are not directly inside a class' body, to avoid binding
+ // spurious members.
+ //
+ // For example:
+ // let
+ // class A =
+ // {
+ // var a := let var b := 0 in b end
+ // }
+ // var toto := new A
+ // in
+ // toto.a /* Valid */
+ // toto.b /* Invalid */
+ // end
+ bool saved_within_class_body = within_class_body_p_;
+ within_class_body_p_ = false;
+ super_type::operator()(e);
+ within_class_body_p_ = saved_within_class_body;
+
+ /* If we are directly inside a class declaration then E is an attribute:
+ record it into the CURRENT_ class. */
+ if (within_class_body_p_)
+ {
+ assertion(current_);
+
+ if (current_->attr_type(e.name_get()))
+ error(e, "attribute multiply defined", e.name_get());
+ else
+ current_->attr_add(&e);
+ }
+ }
+
+ /*-------------.
+ | Visit /Ty/. |
+ `-------------*/
+
+ // Don't handle members, as visit_dec_members is in charge of this task.
+ void TypeChecker::operator()(ast::ClassTy& e)
+ {
+ // FIXME DONE: Some code was deleted here (Create class).
+ /*
+ ** Moi sur le point de me faire chier dessus en code review parce que ma
+ ** variable est en français juste pour éviter le keyword `class'
+ */
+ auto classe = std::make_unique<type::Class>();
+
+ type_default(e, classe.get());
+
+ /* ------------------- *
+ * Superclass handling *
+ * ------------------- */
+
+ // FIXME DONE: Some code was deleted here (Set the type of the super class).
+
+ const type::Type* supertype;
+ if (e.super_get().def_get() == nullptr)
+ supertype = type(e.super_get());
+ else
+ supertype = type(e.super_get().def_get()->ty_get());
+
+ classe->super_set(dynamic_cast<const type::Class*>(&supertype->actual()));
+
+ // FIXME DONE: Some code was deleted here (Recursively update the list of subclasses of the super classes).
+ if (!classe->sound())
+ error(e, "infinite type inheritance recursion detected");
+
+ std::vector<const type::Class*> previous;
+ for (auto super = classe->super_get(); super != nullptr
+ && std::ranges::find(previous, super) == previous.end();
+ super = super->super_get())
+ {
+ super->subclass_add(classe.get());
+ previous.push_back(super);
+ }
+
+ /* à un moment je crois qu'il faut */
+ created_type_default(e, classe.release());
+ /* mais ça serait trop simple si je savais quand */
+ }
+
+ // Handle the members of a class.
+ void TypeChecker::visit_dec_members(ast::ClassTy& e)
+ {
+ assertion(!within_class_body_p_); // Should be false by the time we get here
+ const type::Type* type = nullptr;
+ // FIXME DONE: Some code was deleted here.
+ // là je crois faut get un type
+ type = e.type_get();
+
+ assertion(type);
+ auto class_type = dynamic_cast<const type::Class*>(type);
+ assertion(class_type);
+
+ type::Class* saved_class_type = current_;
+ within_class_body_p_ = true;
+ // Make the type writable, so that we can add references to the
+ // types of the members.
+ current_ = const_cast<type::Class*>(class_type);
+ e.chunks_get().accept(*this);
+
+ // Set back the status we had before we visited the members.
+ current_ = saved_class_type;
+ within_class_body_p_ = false;
+ }
+
+} // namespace object
diff --git a/tiger-compiler/src/object/type-checker.hh b/tiger-compiler/src/object/type-checker.hh
new file mode 100644
index 0000000..c965d25
--- /dev/null
+++ b/tiger-compiler/src/object/type-checker.hh
@@ -0,0 +1,108 @@
+/**
+ ** \file object/type-checker.hh
+ ** \brief Checking an ObjectTiger program in a Tiger program.
+ */
+
+#pragma once
+
+#include <type/class.hh>
+#include <type/type-checker.hh>
+#include <type/types.hh>
+
+namespace object
+{
+ /** \brief Perform type checking, allowing objects, and compute
+ ** the bindings of the object's methods and fields.
+ **
+ ** Inheritence is declared virtual to enable diamond inheritance with
+ ** the TypeChecker (src/combine/type-checker.hh), inheriting
+ ** from overload::TypeChecker and object::TypeChecker, both inheriting from
+ ** type::TypeChecker.
+ **/
+ class TypeChecker : virtual public type::TypeChecker
+ {
+ public:
+ /// Superclass.
+ using super_type = type::TypeChecker;
+ using super_type::operator();
+
+ /// Construction.
+ TypeChecker();
+
+ protected:
+ // ------------------------- //
+ // The core of the visitor. //
+ // ------------------------- //
+
+ // ---------------- //
+ // Visiting /Var/. //
+ // ---------------- //
+
+ void operator()(ast::FieldVar& e) override;
+ void operator()(ast::SimpleVar& e) override;
+
+ // --------------- //
+ // Visiting /Ty/. //
+ // --------------- //
+
+ void operator()(ast::NameTy& e) override;
+
+ // ---------------- //
+ // Visiting /Exp/. //
+ // ---------------- //
+
+ // Method exp.
+ void operator()(ast::IfExp& e) override;
+ void operator()(ast::OpExp& e) override;
+ void operator()(ast::ObjectExp& e) override;
+ void operator()(ast::MethodCallExp& e) override;
+
+ // ---------------- //
+ // Visiting /Dec/. //
+ // ---------------- //
+
+ /** Visit a chunk of type declarations.
+
+ This method is like type::TypeChecker's one, except that it
+ processes class declarations in three steps, instead of two
+ (visit the headers, then the bodies):
+
+ <ol>
+ <li>visit headers, as in type::TypeChecker;</li>
+ <li>visit bodies, which ignore all members of the class;</li>
+ <li>visit members, i.e., attributes and methods.</li>
+ </ol>
+
+ This way, a method of a class can use the type of this class
+ (e.g., return \a self), as that type has been created in the
+ second step, and the method is processed in the third. */
+ void operator()(ast::TypeChunk& e) override;
+
+ // Check a Method's declaration header.
+ void visit_dec_header(ast::MethodDec& e);
+ // Check a Method's declaration body.
+ void visit_dec_body(ast::MethodDec& e);
+
+ /// Visit a chunk of method declarations.
+ void operator()(ast::MethodChunk& e) override;
+
+ /// Visit a single Variable Declaration.
+ void operator()(ast::VarDec& e) override;
+
+ // --------------- //
+ // Visiting /Ty/. //
+ // --------------- //
+
+ // Visit a class definition \em without its members.
+ void operator()(ast::ClassTy& e) override;
+ // Visit the members of a class.
+ virtual void visit_dec_members(ast::ClassTy& e);
+
+ private:
+ /// Current visited class.
+ type::Class* current_ = nullptr;
+ /// Are we directly within an ast::ClassTy's body?
+ bool within_class_body_p_ = false;
+ };
+
+} // namespace object
diff --git a/tiger-compiler/src/overload/binder.cc b/tiger-compiler/src/overload/binder.cc
new file mode 100644
index 0000000..14610fe
--- /dev/null
+++ b/tiger-compiler/src/overload/binder.cc
@@ -0,0 +1,45 @@
+/**
+ ** \file overload/binder.cc
+ ** \brief Implementation of overload::Binder.
+ */
+
+#include <ast/all.hh>
+#include <overload/binder.hh>
+
+namespace overload
+{
+ overfun_bindings_type& Binder::overfun_bindings_get()
+ {
+ return overfun_bindings_;
+ }
+
+ /*---------.
+ | Scopes. |
+ `---------*/
+
+ // FIXME: Some code was deleted here.
+
+ /*-------------------.
+ | Visiting methods. |
+ `-------------------*/
+
+ // Same as Binder's, but do not set the definition site of E.
+ void Binder::operator()(ast::CallExp& e)
+ {
+ // FIXME: Some code was deleted here.
+ }
+
+ // Insert the prototype of the function in the environment.
+ void Binder::visit_dec_header(ast::FunctionDec& e)
+ {
+ // FIXME: Some code was deleted here (Checks for the _main case).
+ overfuns_.put(e.name_get(), e);
+ }
+
+ void Binder::operator()(ast::FunctionChunk& e)
+ {
+ // Two passes: once on headers, then on bodies.
+ // FIXME: Some code was deleted here.
+ }
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/binder.hh b/tiger-compiler/src/overload/binder.hh
new file mode 100644
index 0000000..607debb
--- /dev/null
+++ b/tiger-compiler/src/overload/binder.hh
@@ -0,0 +1,65 @@
+/**
+ ** \file overload/binder.hh
+ ** \brief Declaration of overload::Binder.
+ **/
+
+#pragma once
+
+#include <map>
+
+#include <bind/binder.hh>
+#include <overload/over-table.hh>
+
+namespace overload
+{
+ /// Type of the dictionary of potential function bindings.
+ using overfun_bindings_type = std::multimap<ast::CallExp*, ast::FunctionDec*>;
+
+ /** \brief Computing bindings with support for overloaded functions.
+ **
+ ** This visitor inherits from Binder, but redefines methods
+ ** dealing with function declarations and uses, to allow
+ ** overloading.
+ **
+ ** As overloading requires some knowledge of the type of the
+ ** arguments of a function, no real function binding is done here.
+ ** We store all potential function declarations (``homonyms'') for
+ ** each function call, and we'll let the overload::TypeChecker
+ ** decide later.
+ **
+ ** Inheritance is declared virtual to enable diamond inheritance with
+ ** the combine::Binder (src/combine/binder.hh), inheriting from
+ ** overload::Binder and object::Binder, both inheriting from bind::Binder.
+ **/
+ class Binder : virtual public bind::Binder
+ {
+ public:
+ /// Super class type.
+ using super_type = bind::Binder;
+ /// Import all the overloaded operator() methods.
+ using super_type::operator();
+
+ /* The visiting methods. */
+ /// Visit a function call.
+ void operator()(ast::CallExp& e) override;
+
+ /// Check a function declaration header.
+ void visit_dec_header(ast::FunctionDec& e);
+ /// Visit a chunk of function declarations.
+ void operator()(ast::FunctionChunk& e) override;
+
+ /// Return the function bindings.
+ overfun_bindings_type& overfun_bindings_get();
+
+ // FIXME: Some code was deleted here (Overload scope handling).
+ /** \} */
+
+ private:
+ using overtable_type = OverTable<ast::FunctionDec>;
+ /// The environment of (overloaded) functions.
+ overtable_type overfuns_;
+ /// The potential function bindings.
+ overfun_bindings_type overfun_bindings_;
+ };
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/liboverload.cc b/tiger-compiler/src/overload/liboverload.cc
new file mode 100644
index 0000000..7662300
--- /dev/null
+++ b/tiger-compiler/src/overload/liboverload.cc
@@ -0,0 +1,28 @@
+/**
+ ** \file overload/liboverload.cc
+ ** \brief Define exported type functions.
+ */
+
+#include <overload/binder.hh>
+#include <overload/liboverload.hh>
+#include <overload/type-checker.hh>
+
+namespace overload
+{
+ std::pair<overfun_bindings_type, misc::error> bind(ast::Ast& tree)
+ {
+ Binder bind;
+ bind(tree);
+ return std::pair(std::move(bind.overfun_bindings_get()),
+ std::move(bind.error_get()));
+ }
+
+ misc::error types_check(ast::Ast& tree,
+ const overfun_bindings_type& overfun_bindings)
+ {
+ TypeChecker type{overfun_bindings};
+ type(tree);
+ return type.error_get();
+ }
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/liboverload.hh b/tiger-compiler/src/overload/liboverload.hh
new file mode 100644
index 0000000..6c89862
--- /dev/null
+++ b/tiger-compiler/src/overload/liboverload.hh
@@ -0,0 +1,36 @@
+/**
+ ** \file overload/liboverload.hh
+ ** \brief Declare functions and variables exported by overload module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+#include <overload/binder.hh>
+
+/**
+ ** \brief Perform type checking, allowing function overloading.
+ */
+namespace overload
+{
+ /** \brief Bind identifier uses to their definition, allowing
+ function overloading, and return a list of potential definition
+ sites for each function call.
+
+ \param tree AST to bind.
+
+ \return a pair whose first element is the potential function
+ bindings, and the second element the error status. */
+ std::pair<overfun_bindings_type, misc::error> bind(ast::Ast& tree);
+
+ /** \brief Check types allowing function overloading.
+
+ \param tree abstract syntax tree's root.
+ \param overfun_bindings potential function bindings.
+
+ \return success of the type-checking. */
+ misc::error types_check(ast::Ast& tree,
+ const overfun_bindings_type& overfun_bindings);
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/local.am b/tiger-compiler/src/overload/local.am
new file mode 100644
index 0000000..022ce5f
--- /dev/null
+++ b/tiger-compiler/src/overload/local.am
@@ -0,0 +1,9 @@
+## overload module.
+
+src_libtc_la_SOURCES += \
+ %D%/over-table.hh %D%/over-table.hxx \
+ %D%/binder.hh %D%/binder.cc \
+ %D%/type-checker.hh %D%/type-checker.cc \
+ %D%/liboverload.hh %D%/liboverload.cc
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/overload/over-table.hh b/tiger-compiler/src/overload/over-table.hh
new file mode 100644
index 0000000..04ddb34
--- /dev/null
+++ b/tiger-compiler/src/overload/over-table.hh
@@ -0,0 +1,63 @@
+/**
+ ** \file overload/over-table.hh
+ ** \brief Checking/translating an OverTiger program in a Tiger program.
+ */
+
+#pragma once
+
+#include <map>
+#include <vector>
+
+namespace overload
+{
+ template <typename T> class OverTable
+ {
+ public:
+ using map_type = std::multimap<const misc::symbol, T*>;
+ using iterator = typename map_type::iterator;
+ using const_iterator = typename map_type::const_iterator;
+ using oversymtab_type = std::vector<map_type>;
+ using range_type = std::pair<const_iterator, const_iterator>;
+
+ /// Create a new over table.
+ OverTable();
+
+ /// \name Symbol handling
+ /// \{
+ /// Put \a key in the map and add the value to the associated container.
+ void put(misc::symbol key, T& value);
+
+ /// Return the range associated to the key.
+ ///
+ /// If the key is not found, the beginning and the end of the range are
+ /// equal.
+ range_type get(misc::symbol key);
+ /// \}
+
+ /// \name Scopes.
+ /// \{
+ /// \brief Open a new scope.
+ ///
+ /// All further type related declarations will be limited to this scope.
+ void scope_begin();
+
+ /// \brief Close the last scope.
+ ///
+ /// Forget everything (i.e. every type related informations) since the
+ /// latest scope_begin().
+ void scope_end();
+ /// \}
+
+ /// Print the table
+ std::ostream& dump(std::ostream& ostr) const;
+
+ protected:
+ oversymtab_type oversymtab_;
+ };
+
+ template <typename T>
+ std::ostream& operator<<(std::ostream& ostr, const OverTable<T>& tbl);
+
+} // namespace overload
+
+#include <overload/over-table.hxx>
diff --git a/tiger-compiler/src/overload/over-table.hxx b/tiger-compiler/src/overload/over-table.hxx
new file mode 100644
index 0000000..de8f98b
--- /dev/null
+++ b/tiger-compiler/src/overload/over-table.hxx
@@ -0,0 +1,64 @@
+/**
+ ** \file overload/over-table.hxx
+ ** \brief Inline methods and template implementations for overload/over-table.hh.
+ */
+
+#pragma once
+
+#include <ostream>
+#include <ranges>
+
+#include <overload/over-table.hh>
+
+namespace overload
+{
+ template <typename T> OverTable<T>::OverTable()
+ {
+ oversymtab_.emplace_back();
+ }
+
+ template <typename T> void OverTable<T>::put(misc::symbol key, T& value)
+ {
+ oversymtab_.back().emplace(key, &value);
+ }
+
+ template <typename T>
+ typename OverTable<T>::range_type OverTable<T>::get(misc::symbol key)
+ {
+ precondition(!oversymtab_.empty());
+ auto& map = oversymtab_.back();
+ return map.equal_range(key);
+ }
+
+ template <typename T> void OverTable<T>::scope_begin()
+ {
+ oversymtab_.emplace_back(oversymtab_.back());
+ }
+
+ template <typename T> void OverTable<T>::scope_end()
+ {
+ precondition(!oversymtab_.empty());
+ oversymtab_.pop_back();
+ }
+
+ template <typename T>
+ std::ostream& OverTable<T>::dump(std::ostream& ostr) const
+ {
+ ostr << "<overTable>\n";
+ for (const auto& m : oversymtab_ | std::views::reverse)
+ {
+ ostr << "<scope>\n";
+ for (const auto& im : m)
+ ostr << im.first << " : " << im->second.size() << '\n';
+ ostr << "</scope>\n";
+ }
+ return ostr << "</overTable>\n";
+ }
+
+ template <typename T>
+ std::ostream& operator<<(std::ostream& ostr, const OverTable<T>& tbl)
+ {
+ return tbl.dump(ostr);
+ }
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/tasks.cc b/tiger-compiler/src/overload/tasks.cc
new file mode 100644
index 0000000..9cfde5a
--- /dev/null
+++ b/tiger-compiler/src/overload/tasks.cc
@@ -0,0 +1,38 @@
+/**
+ ** \file overload/tasks.cc
+ ** \brief Overload module related tasks' implementation.
+ */
+
+#include <memory>
+
+#include <ast/tasks.hh>
+#include <common.hh>
+#include <overload/liboverload.hh>
+#define DEFINE_TASKS 1
+#include <overload/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace overload::tasks
+{
+ std::unique_ptr<overfun_bindings_type> the_overfun_bindings = nullptr;
+
+ void overfun_bindings_compute()
+ {
+ auto result = ::overload::bind(*ast::tasks::the_program);
+ ::overload::tasks::the_overfun_bindings =
+ std::make_unique<overfun_bindings_type>(std::move(result.first));
+
+ task_error() << result.second << &misc::error::exit_on_error;
+ }
+
+ void overfun_types_compute()
+ {
+ task_error() << ::overload::types_check(
+ *ast::tasks::the_program, *::overload::tasks::the_overfun_bindings);
+
+ // Force the unique_ptr to be freed.
+ the_overfun_bindings.reset();
+ task_error().exit_on_error();
+ }
+
+} // namespace overload::tasks
diff --git a/tiger-compiler/src/overload/tasks.hh b/tiger-compiler/src/overload/tasks.hh
new file mode 100644
index 0000000..31edad1
--- /dev/null
+++ b/tiger-compiler/src/overload/tasks.hh
@@ -0,0 +1,29 @@
+/**
+ ** \file overload/tasks.hh
+ ** \brief Overload module tasks.
+ */
+
+#pragma once
+
+#include <overload/binder.hh>
+#include <task/libtask.hh>
+
+namespace overload::tasks
+{
+ TASK_GROUP("4.5 Type checking with overloading");
+
+ /// Compute bindings, allowing function overloading.
+ TASK_DECLARE("overfun-bindings-compute",
+ "bind the identifiers, "
+ "allowing function overloading",
+ overfun_bindings_compute,
+ "parse");
+
+ /// Check for type violation, allowing function overloading.
+ TASK_DECLARE("O|overfun-types-compute",
+ "check for type violations, "
+ "allowing function overloading",
+ overfun_types_compute,
+ "overfun-bindings-compute");
+
+} // namespace overload::tasks
diff --git a/tiger-compiler/src/overload/type-checker.cc b/tiger-compiler/src/overload/type-checker.cc
new file mode 100644
index 0000000..1f32113
--- /dev/null
+++ b/tiger-compiler/src/overload/type-checker.cc
@@ -0,0 +1,21 @@
+/**
+ ** \file overload/type-checker.cc
+ ** \brief Implementation for overload/type-checker.hh.
+ */
+
+#include <algorithm>
+#include <sstream>
+
+#include <misc/indent.hh>
+#include <overload/type-checker.hh>
+#include <type/types.hh>
+
+namespace overload
+{
+ TypeChecker::TypeChecker(const overfun_bindings_type& overfun_bindings)
+ : overfun_bindings_{overfun_bindings}
+ {}
+
+ // FIXME: Some code was deleted here.
+
+} // namespace overload
diff --git a/tiger-compiler/src/overload/type-checker.hh b/tiger-compiler/src/overload/type-checker.hh
new file mode 100644
index 0000000..719db72
--- /dev/null
+++ b/tiger-compiler/src/overload/type-checker.hh
@@ -0,0 +1,37 @@
+/**
+ ** \file overload/type-checker.hh
+ ** \brief Checking/translating an OverTiger program in a Tiger program.
+ */
+
+#pragma once
+
+#include <overload/binder.hh>
+#include <type/type-checker.hh>
+#include <type/types.hh>
+
+namespace overload
+{
+ /** \brief Perform type checking, allowing function overload, and compute
+ ** the bindings of the functions.
+ **
+ ** Inheritance is declared virtual to enable diamond inheritance with
+ ** the combine::TypeChecker (src/combine/type-checker.hh), inheriting
+ ** from overload::TypeChecker and object::TypeChecker, both inheriting from
+ ** type::TypeChecker.
+ **/
+ class TypeChecker : virtual public type::TypeChecker
+ {
+ public:
+ /// Superclass.
+ using super_type = type::TypeChecker;
+ using super_type::operator();
+
+ TypeChecker(const overfun_bindings_type& overfun_bindings);
+ virtual ~TypeChecker() = default;
+
+ // FIXME: Some code was deleted here.
+ private:
+ const overfun_bindings_type& overfun_bindings_;
+ };
+
+} // namespace overload
diff --git a/tiger-compiler/src/parse/fwd.hh b/tiger-compiler/src/parse/fwd.hh
new file mode 100644
index 0000000..19ed898
--- /dev/null
+++ b/tiger-compiler/src/parse/fwd.hh
@@ -0,0 +1,38 @@
+/**
+ ** \file parse/fwd.hh
+ ** \brief Forward declarations for the parse module.
+ */
+
+#pragma once
+
+#include <misc/variant.hh>
+
+// From ast/.
+namespace ast
+{
+ class Exp;
+ class ChunkList;
+
+} // namespace ast
+
+namespace parse
+{
+ // From scantiger.hh.
+ class Lexer;
+
+ // From parsetiger.yy.
+ class parser;
+
+ // From location.hh.
+ class location;
+
+ // From tiger-driver.hh.
+ class TigerDriver;
+
+ // From tweast.hh
+ class Tweast;
+
+ /// Result of a parse: an Exp (*.tig) or a ChunkList (*.tih).
+ using ast_type = misc::variant<ast::Exp*, ast::ChunkList*>;
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/generate-prelude.sh b/tiger-compiler/src/parse/generate-prelude.sh
new file mode 100755
index 0000000..d81d28b
--- /dev/null
+++ b/tiger-compiler/src/parse/generate-prelude.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+
+[ -z "$1" ] && echo "$0: Missing input file" && exit
+[ -z "$2" ] && echo "$0: Missing output file" && exit
+
+input=$1
+output=$2
+
+awk 'BEGIN {
+ print("#include \"parse/tiger-driver.hh\"");
+ print("");
+ print("namespace parse");
+ print("{");
+ print(" const char* TigerDriver::prelude () const");
+ print(" {");
+ print(" return");
+ printf("R\"(");
+ }
+ /^#(<<|>>)/ {
+ next;
+ }
+ {
+ print($0);
+ }
+ END {
+ print(")\";");
+ print(" }");
+ print("} // namespace parse");
+ }' "$input" > "$output".tmp
+
+mv "$output".tmp "$output"
diff --git a/tiger-compiler/src/parse/libparse.cc b/tiger-compiler/src/parse/libparse.cc
new file mode 100644
index 0000000..7c963b6
--- /dev/null
+++ b/tiger-compiler/src/parse/libparse.cc
@@ -0,0 +1,137 @@
+/**
+ ** \file parse/libparse.cc
+ ** \brief Functions and variables exported by the parse module.
+ */
+
+#include <ast/chunk-interface.hh>
+#include <ast/chunk-list.hh>
+#include <misc/file-library.hh>
+#include <misc/indent.hh>
+#include <misc/symbol.hh>
+#include <parse/libparse.hh>
+#include <parse/location.hh>
+#include <parse/tasks.hh>
+#include <parse/tiger-driver.hh>
+#include <parse/tweast.hh>
+
+// Define exported parse functions.
+namespace parse
+{
+ ast::ChunkList* parse_prelude()
+ {
+ if (tasks::prelude.empty())
+ {
+ return nullptr;
+ }
+
+ TigerDriver td;
+
+ return std::get<ast::ChunkList*>(td.parse(td.prelude()));
+ }
+
+ // Parse a Tiger file, return the corresponding abstract syntax.
+ std::pair<ast::ChunkList*, misc::error> parse(const std::string& prelude,
+ const std::string& fname,
+ misc::file_library& library,
+ bool scan_trace_p,
+ bool parse_trace_p,
+ bool enable_object_extensions_p,
+ bool enable_assert_extensions_p)
+ {
+ // Current directory must be that of the file currently processed.
+ library.push_current_directory(misc::path(fname).parent_path());
+
+ TigerDriver td(library);
+ td.scan_trace(scan_trace_p).parse_trace(parse_trace_p);
+ td.enable_object_extensions(enable_object_extensions_p);
+ td.enable_assert_extensions(enable_assert_extensions_p);
+
+ ast::ChunkList* res = nullptr;
+
+ ast_type tree = td.parse_file(fname);
+
+ ast::Exp** exp = std::get_if<ast::Exp*>(&tree);
+ ast::ChunkList** chunks = std::get_if<ast::ChunkList*>(&tree);
+
+ // Try to parse the program as an expression, and check that the
+ // parsing did not fail in that case.
+ if (exp && *exp)
+ {
+ Tweast in;
+
+ if (!prelude.empty())
+ {
+ ast::ChunkList* prelude_chunks =
+ (prelude == "builtin"
+ ? std::get<ast::ChunkList*>(td.parse(td.prelude()))
+ : td.parse_import(prelude, location()));
+ if (prelude_chunks)
+ in << prelude_chunks;
+ }
+ in << "function _main() = (" << *exp << "; ())";
+ res = td.parse(in);
+ }
+ // Try to parse the program as a list of declarations, and check
+ // that the parsing did not fail in that case.
+ else if (chunks && *chunks)
+ {
+ // Try to parse the program as a list of declarations.
+ res = *chunks;
+ }
+ // Otherwise, the parsing failed, and an error will be returned as
+ // second member of the return value.
+
+ // Ensure that directory stack is not modified by parse.
+ library.pop_current_directory();
+
+ return std::pair(res, td.error_get());
+ }
+
+ ast_type parse(Tweast& input)
+ {
+ TigerDriver td;
+ td.enable_extensions();
+ td.enable_object_extensions();
+ ast_type res = td.parse(input);
+ if (td.error_get())
+ {
+ misc::error e;
+ e << "Failed to resolve Tweast:" << misc::incendl << input;
+ e << "Got: " << td.error_get();
+ e.ice_here();
+ }
+ return res;
+ }
+
+ ast::Exp* parse(const std::string& str, bool enable_object_extensions_p)
+ {
+ TigerDriver td;
+ td.enable_object_extensions(enable_object_extensions_p);
+ ast::Exp* res = td.parse(str);
+ td.error_get().ice_on_error_here();
+ return res;
+ }
+
+ ast::ChunkList* parse_unit(const std::string& str,
+ bool enable_object_extensions_p)
+ {
+ TigerDriver td;
+ td.enable_object_extensions(enable_object_extensions_p);
+ std::string rewrite = "function _main() = (" + str + "; ())";
+ ast::ChunkList* res = td.parse(rewrite);
+ td.error_get().ice_on_error_here();
+ return res;
+ }
+
+ // Parse a set of declarations.
+ ast::ChunkInterface* parse_chunks(Tweast& in)
+ {
+ ast::ChunkList* dl = parse(in);
+ assertion(dl->chunks_get().size() == 1);
+ ast::ChunkInterface* res = dl->chunks_get().front();
+ dl->chunks_get().pop_front();
+ delete dl;
+ return res;
+ }
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/libparse.hh b/tiger-compiler/src/parse/libparse.hh
new file mode 100644
index 0000000..7781bb6
--- /dev/null
+++ b/tiger-compiler/src/parse/libparse.hh
@@ -0,0 +1,76 @@
+/**
+ ** \file parse/libparse.hh
+ ** \brief Declare functions and variables exported by parse module.
+ */
+
+#pragma once
+
+#include <set>
+#include <string>
+#include <utility>
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+#include <misc/file-library.hh>
+#include <parse/fwd.hh>
+
+/// Parsing the input, delivering an ast::Ast.
+namespace parse
+{
+ /// \brief Parse a Tiger file, return the corresponding abstract syntax tree.
+ ///
+ /// \param prelude name of the prelude file.
+ /// \param fname path and name of the tiger file.
+ /// \param library library for managing search path.
+ /// \param scan_trace_p display information on scan step.
+ /// \param parse_trace_p display information on parse step.
+ /// \param enable_object_extensions_p enable object constructions
+ ///
+ /// \return a pair composed of a pointer to an abstract parse tree
+ /// (set to `nullptr' upon failure) and an error status.
+ /// This function is the only interface available between
+ /// the scanner/parser and the rest of the program.
+
+#ifdef SWIG
+ %newobject parse;
+#endif
+
+ /**
+ * \brief Parse the default prelude and return it.
+ * Return null if no-prelude is set.
+ * \return an AST representing the EPITA Tiger default prelude
+ */
+ ast::ChunkList* parse_prelude();
+
+ std::pair<ast::ChunkList*, misc::error>
+ parse(const std::string& prelude,
+ const std::string& fname,
+ misc::file_library& library,
+ bool scan_trace_p,
+ bool parse_trace_p,
+ bool enable_object_extensions_p = false,
+ bool enable_assert_extensions_p = false);
+
+ /// \brief Parse a Tweast.
+ ///
+ /// Extensions are enabled. Raises an exception on errors.
+ ast_type parse(Tweast& input);
+
+ /// Parse a std::string. Used for unit tests.
+ ast::Exp* parse(const std::string& str,
+ bool enable_object_extensions_p = false);
+
+ /// Parse a std::string. Used for unit tests.
+ /// The declaration of the _main function is automatically added.
+ ast::ChunkList* parse_unit(const std::string& str,
+ bool enable_object_extensions_p = false);
+
+ /// \brief Parse a set of declarations.
+ ///
+ /// Wrapper around parse::parse to return the single ast::ChunkInterface
+ /// to be found in the input (expected to contain ChunkList).
+ ///
+ /// Used by desugar::BoundsCheckingVisitor and object::ObjectDesugarVisitor.
+ ast::ChunkInterface* parse_chunks(Tweast& in);
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/local.am b/tiger-compiler/src/parse/local.am
new file mode 100644
index 0000000..1d80d2a
--- /dev/null
+++ b/tiger-compiler/src/parse/local.am
@@ -0,0 +1,125 @@
+## -------------------- ##
+## Scanner generation. ##
+## -------------------- ##
+
+# Definition of flags used by reflex
+REFLEX_HEADER = %D%/scantiger.hh
+REFLEX_FLAGS = -d --flex --header-file=$(REFLEX_HEADER)
+SOURCES_REFLEX = $(REFLEX_HEADER) %D%/scantiger.cc
+
+MAINTAINERCLEANFILES += %D%/scantiger.cc $(REFLEX_HEADER)
+EXTRA_DIST += %D%/scantiger.ll
+
+# Rule to generate all files with reflex
+%D%/scantiger.cc $(REFLEX_HEADER) : %D%/scantiger.ll
+ $(AM_V_GEN)mkdir -p $(@D)
+ $(AM_V_at)rm -f $@
+# Generate scantiger.cc and scantiger.hh
+ $(AM_V_at) $(REFLEX) $< -o %D%/scantiger.cc $(REFLEX_FLAGS)
+
+## ------------------- ##
+## Parser generation. ##
+## ------------------- ##
+BISONXX = $(top_builddir)/build-aux/bin/bison++
+BISONXX_IN = $(top_srcdir)/build-aux/bin/bison++.in
+BISONXXFLAGS = \
+ $(if $(V:0=),--verbose)
+AM_BISONFLAGS = \
+ --warnings=all,dangling-alias \
+ --report=all
+
+## Use this additional bison flag to display counterexamples in the tty.
+#AM_BISONFLAGS += --warnings=counterexamples
+
+# We do not use Automake features here.
+SOURCES_PARSETIGER_YY = \
+ %D%/location.hh \
+ %D%/parsetiger.cc \
+ %D%/parsetiger.hh
+BUILT_SOURCES += $(SOURCES_PARSETIGER_YY)
+
+# Ship %D%/stack.hh only if GLR is disabled, as Bison does not
+# generate this file for GLR parsers.
+dist-hook: dist-hook-parse
+dist-hook-parse:
+ @grep '%glr-parser' $(srcdir)/%D%/parsetiger.yy >/dev/null \
+ || cp -p $(srcdir)/%D%/stack.hh $(distdir)/src/parse/
+
+# Compile the parser and save cycles.
+# This code comes from "Handling Tools that Produce Many Outputs",
+# from the Automake documentation.
+EXTRA_DIST += \
+ %D%/parsetiger.stamp \
+ %D%/parsetiger.yy
+# The dependency is on bison++.in and not bison++, since bison++ is
+# regenerated at distribution time, and voids the time stamps (which
+# we don't want!).
+%D%/parsetiger.stamp: %D%/parsetiger.yy $(BISONXX_IN)
+ $(AM_V_GEN)mkdir -p $(@D)
+ $(AM_V_at)rm -f $@ $@.tmp
+ $(AM_V_at)echo '$@ rebuilt because of: $?' >$@.tmp
+ $(AM_V_at)$(MAKE) $(BISONXX)
+ $(AM_V_at)$(BISONXX) $(BISONXXFLAGS) \
+ -r $(srcdir)/src \
+ -- \
+ $< $(srcdir)/%D%/parsetiger.cc \
+ $(AM_BISONFLAGS) $(BISONFLAGS)
+ $(AM_V_at)mv -f $@.tmp $@
+
+## If Make does not know it will generate in the srcdir, then when
+## trying to compile from *.cc to *.lo, it will not apply VPATH
+## lookup, since it expects the file to be in builddir. So *here*,
+## make srcdir explicit.
+$(addprefix $(srcdir)/, $(SOURCES_PARSETIGER_YY)): %D%/parsetiger.stamp
+ $(AM_V_GEN)if test -f $@; then :; else \
+ rm -f $<; \
+ $(MAKE) $(AM_MAKEFLAGS) $<; \
+ fi
+
+# We tried several times to run make from ast/ to build location.hh.
+# Unfortunately, because of different, but equivalent, paths, BSD Make
+# was unable to build them. The following hook is here to address this.
+.PHONY: generate-parser
+generate-parser: $(SOURCES_PARSETIGER_YY)
+
+PARSE_PRELUDE_GENERATION = %D%/generate-prelude.sh
+EXTRA_DIST += $(PARSE_PRELUDE_GENERATION)
+CLEANFILES += %D%/prelude.cc
+%D%/prelude.cc: $(top_srcdir)/data/prelude.tih
+ $(AM_V_GEN)$(srcdir)/$(PARSE_PRELUDE_GENERATION) $< $@
+
+## ---------- ##
+## libparse. ##
+## ---------- ##
+
+src_libtc_la_SOURCES += \
+ $(SOURCES_REFLEX) \
+ $(SOURCES_PARSETIGER_YY) \
+ %D%/fwd.hh \
+ %D%/libparse.hh %D%/libparse.cc \
+ %D%/metavar-map.hh %D%/metavar-map.hxx \
+ %D%/tiger-driver.hh %D%/tiger-driver.cc \
+ %D%/tweast.hh %D%/tweast.cc %D%/tweast.hxx
+src_libtc_la_SOURCES += \
+ %D%/tiger-factory.hh %D%/tiger-factory.hxx
+
+FORMAT_IGNORE += $REFLEX_HEADER
+
+nodist_src_libtc_la_SOURCES += \
+ %D%/prelude.cc
+
+## ------- ##
+## Tests. ##
+## ------- ##
+
+check_PROGRAMS += \
+ %D%/test-parse \
+ %D%/test-tweast
+
+# Find the prelude.
+%C%_test_parse_CPPFLAGS = $(AM_CPPFLAGS) -DPKGDATADIR=\"$(pkgdatadir)\"
+%C%_test_parse_LDADD = src/libtc.la
+%C%_test_tweast_LDADD = src/libtc.la
+
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/parse/metavar-map.hh b/tiger-compiler/src/parse/metavar-map.hh
new file mode 100644
index 0000000..113db0f
--- /dev/null
+++ b/tiger-compiler/src/parse/metavar-map.hh
@@ -0,0 +1,48 @@
+/**
+ ** \file parse/metavar-map.hh
+ ** \brief Declaration of parse::MetavarMap.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <misc/map.hh>
+
+namespace parse
+{
+ /// A generic map of metavariables.
+ template <typename Data> class MetavarMap
+ {
+ public:
+ /// Build a map of metavariables of kind \a name.
+ MetavarMap(const std::string& name);
+ virtual ~MetavarMap();
+
+ /// Generate a (concrete syntax) Tiger statement for metavariable
+ /// number \a key (of kind \p Data).
+ std::string show(unsigned key) const;
+
+ /// Print the MetavarMap on \a ostr.
+ std::ostream& dump(std::ostream& ostr) const;
+
+ protected:
+ /// Append a metavariable to the map.
+ virtual std::string append_(unsigned& key, Data* data);
+ /// Extract a metavariable.
+ virtual Data* take_(unsigned key);
+
+ /// Name of the kind of variable.
+ const std::string name_;
+ /// Metavariables.
+ using map_type = misc::map<unsigned, Data*>;
+ map_type map_;
+ };
+
+ /// Output \a m onto \a ostr.
+ template <typename Data>
+ std::ostream& operator<<(std::ostream& ostr, const MetavarMap<Data>& m);
+
+} // namespace parse
+
+#include <parse/metavar-map.hxx>
diff --git a/tiger-compiler/src/parse/metavar-map.hxx b/tiger-compiler/src/parse/metavar-map.hxx
new file mode 100644
index 0000000..7dc2bbc
--- /dev/null
+++ b/tiger-compiler/src/parse/metavar-map.hxx
@@ -0,0 +1,69 @@
+/**
+ ** \file parse/metavar-map.hxx
+ ** \brief Implementation of parse::MetavarMap.
+ */
+
+#pragma once
+
+#include <sstream>
+#include <string>
+
+#include <misc/contract.hh>
+#include <misc/indent.hh>
+#include <parse/metavar-map.hh>
+
+namespace parse
+{
+ template <typename Data>
+ MetavarMap<Data>::MetavarMap(const std::string& name)
+ : name_(name)
+ , map_()
+ {}
+
+ template <typename Data> MetavarMap<Data>::~MetavarMap()
+ {
+ // At this point, every metavariable should have been taken from the map.
+ assertion(map_.empty()) << *this << "not empty, aborting.\n";
+ }
+
+ template <typename Data>
+ std::string MetavarMap<Data>::show(unsigned key) const
+ {
+ return '_' + name_ + '(' + std::to_string(key) + ')';
+ }
+
+ template <typename Data>
+ std::ostream& MetavarMap<Data>::dump(std::ostream& ostr) const
+ {
+ ostr << "MetavarMap<" << name_ << "> = [";
+
+ if (map_.empty())
+ return ostr << " ]" << misc::iendl;
+
+ ostr << misc::incindent;
+
+ for (const auto& [k, v] : map_)
+ ostr << misc::iendl << show(k) << " -> " << v;
+
+ return ostr << misc::decendl << "]" << misc::iendl;
+ }
+
+ template <typename Data>
+ std::string MetavarMap<Data>::append_(unsigned& count, Data* data)
+ {
+ map_[count] = data;
+ return show(count++);
+ }
+
+ template <typename Data> Data* MetavarMap<Data>::take_(unsigned key)
+ {
+ return map_.take(key);
+ }
+
+ template <typename Data>
+ std::ostream& operator<<(std::ostream& ostr, const MetavarMap<Data>& m)
+ {
+ return m.dump(ostr);
+ }
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/tasks.cc b/tiger-compiler/src/parse/tasks.cc
new file mode 100644
index 0000000..1423696
--- /dev/null
+++ b/tiger-compiler/src/parse/tasks.cc
@@ -0,0 +1,53 @@
+/**
+ ** \file parse/tasks.cc
+ ** \brief Parse module related tasks' implementation.
+ **/
+
+#include <cstdlib>
+#include <iostream>
+#include <memory>
+
+#include <assert/tasks.hh>
+#include <ast/tasks.hh>
+#include <common.hh>
+#include <misc/file-library.hh>
+#include <object/tasks.hh>
+#include <parse/libparse.hh>
+#define DEFINE_TASKS 1
+#include <parse/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace parse::tasks
+{
+ const char* tc_pkgdatadir = getenv("TC_PKGDATADIR");
+ misc::file_library l =
+ misc::file_library(tc_pkgdatadir ? tc_pkgdatadir : PKGDATADIR);
+
+ void no_prelude() { prelude = ""; }
+
+ void parse()
+ {
+ precondition(filename != nullptr);
+ bool scan_trace = scan_trace_p || getenv("SCAN");
+ bool parse_trace = parse_trace_p || getenv("PARSE");
+ std::pair<ast::ChunkList*, misc::error> result =
+ ::parse::parse(prelude, filename, l, scan_trace, parse_trace,
+ object::tasks::enable_object_extensions_p,
+ assert::tasks::enable_assert_extensions_p);
+
+ // If the parsing completely failed, stop.
+ task_error() << result.second;
+ if (!result.first)
+ task_error().exit();
+
+ // FIXME DONE: Some code was deleted here (Set `the_program' to the result of parsing).
+ ast::tasks::the_program = std::unique_ptr<ast::ChunkList>{result.first};
+ }
+
+ void library_display() { std::cout << l << '\n'; }
+
+ void library_append(const std::string& dir) { l.append_dir(dir); }
+
+ void library_prepend(const std::string& dir) { l.prepend_dir(dir); }
+
+} // namespace parse::tasks
diff --git a/tiger-compiler/src/parse/tasks.hh b/tiger-compiler/src/parse/tasks.hh
new file mode 100644
index 0000000..0ff37e1
--- /dev/null
+++ b/tiger-compiler/src/parse/tasks.hh
@@ -0,0 +1,51 @@
+/**
+ ** \file parse/tasks.hh
+ ** \brief Parse module tasks.
+ */
+
+#pragma once
+
+#include <misc/fwd.hh>
+#include <task/libtask.hh>
+
+/// Tasks of the parse module.
+namespace parse::tasks
+{
+ /// Global library for search path.
+ extern misc::file_library file_library;
+
+ TASK_GROUP("1. Parsing");
+
+ /// Enable scanner trace.
+ BOOLEAN_TASK_DECLARE("scan-trace", "trace the scanning", scan_trace_p, "");
+ /// Enable parser trace.
+ BOOLEAN_TASK_DECLARE("parse-trace", "trace the parse", parse_trace_p, "");
+ /// Prelude declarations.
+ STRING_TASK_DECLARE("prelude",
+ "builtin",
+ "name of the prelude. Defaults to \"builtin\" "
+ "denoting the builtin prelude",
+ prelude,
+ "");
+ /// Prelude declarations.
+ TASK_DECLARE("X|no-prelude", "don't include prelude", no_prelude, "");
+ /// Parse the input file, store the ast into ast::tasks::the_program.
+ TASK_DECLARE("parse", "parse a file", parse, "");
+
+ /// Display library search path.
+ TASK_DECLARE("library-display",
+ "display library search path",
+ library_display,
+ "");
+ /// Append directory DIR to the search path.
+ MULTIPLE_STRING_TASK_DECLARE("P|library-append",
+ "append directory DIR to the search path",
+ library_append,
+ "");
+ /// Prepend directory DIR to the search path.
+ MULTIPLE_STRING_TASK_DECLARE("p|library-prepend",
+ "prepend directory DIR to the search path",
+ library_prepend,
+ "");
+
+} // namespace parse::tasks
diff --git a/tiger-compiler/src/parse/tiger-driver.cc b/tiger-compiler/src/parse/tiger-driver.cc
new file mode 100644
index 0000000..d26d11d
--- /dev/null
+++ b/tiger-compiler/src/parse/tiger-driver.cc
@@ -0,0 +1,215 @@
+/**
+ ** \file parse/tiger-driver.cc
+ ** \brief Implementation of parse::TigerDriver.
+ */
+
+#include <cstdlib>
+#include <fstream>
+
+#include <parse/parsetiger.hh>
+#include <parse/scantiger.hh>
+#include <parse/tiger-driver.hh>
+
+namespace parse
+{
+ TigerDriver::TigerDriver(const misc::file_library& lib)
+ : library_(lib)
+ {}
+
+ // Yes, this is exactly the default dtor. But because it is defined
+ // here, in the *.cc file, instead of "= default" in the *.hh file,
+ // there is no need for all the members to be complete defined in
+ // the header. In particular, the scanner_ member acts as a Pimpl,
+ // so we really want the generation of the dtor to be delayed to
+ // here, not in the header.
+ TigerDriver::~TigerDriver() = default;
+
+ /// Set the scanner traces.
+ TigerDriver& TigerDriver::scan_trace(bool b)
+ {
+ scan_trace_p_ = b;
+ return *this;
+ }
+
+ /// Set the parser traces.
+ TigerDriver& TigerDriver::parse_trace(bool b)
+ {
+ parse_trace_p_ = b;
+ return *this;
+ }
+
+ /// Enable object extensions.
+ TigerDriver& TigerDriver::enable_object_extensions(bool b)
+ {
+ enable_object_extensions_p_ = b;
+ return *this;
+ }
+
+ /// Enable assert extensions.
+ TigerDriver& TigerDriver::enable_assert_extensions(bool b)
+ {
+ enable_assert_extensions_p_ = b;
+ return *this;
+ }
+
+ /// Enable syntax extensions.
+ TigerDriver& TigerDriver::enable_extensions(bool b)
+ {
+ enable_extensions_p_ = b;
+ return *this;
+ }
+
+ /// Parse a Tiger file or string.
+ ast_type TigerDriver::parse_()
+ {
+ std::string* fn = std::get_if<std::string>(&input_);
+
+ /* The (address of) the string behind the symbol FILENAME is
+ guaranteed to remain valid even after the symbol has been
+ destroyed, so we can safely pass `&filename.name_get()' to
+ `location_.initialize()'. As for other symbols, the
+ corresponding string will be deallocated at the end of the
+ program. */
+ misc::symbol filename(fn == nullptr ? ""
+ : *fn == "-" ? "standard input"
+ : *fn);
+ location_.initialize(&filename.get());
+
+ std::shared_ptr<std::istream> in;
+ if (fn == nullptr)
+ // Parse a Tweast.
+ in = (std::make_shared<std::stringstream>(
+ std::get<Tweast*>(input_)->input_get()));
+ else if (*fn == "-")
+ // Parse from the standard input.
+ in.reset(&std::cin, [](...) {});
+ else
+ {
+ // Parse from a file.
+ in = std::make_shared<std::ifstream>(*fn);
+ if (in->fail())
+ error_ << misc::error::error_type::failure << program_name
+ << ": cannot open `" << filename << "': " << strerror(errno)
+ << std::endl
+ << &misc::error::exit;
+ }
+
+ // FIXME DONE: Some code was deleted here (Initialize Lexer and enable scan traces).
+ Lexer lexer(*in);
+ lexer.set_debug(scan_trace_p_);
+
+ // FIXME DONE: Some code was deleted here (Initialize the parser and enable parse traces).
+ parser parser(*this, lexer);
+ parser.set_debug_level(parse_trace_p_);
+
+ // FIXME DONE: Some code was deleted here (Run the parser).
+ parser.parse();
+
+ ast_type res = ast_;
+ ast_ = static_cast<ast::Exp*>(nullptr);
+
+ return res;
+ }
+
+ /*---------------.
+ | Parse a file. |
+ `---------------*/
+
+ ast_type TigerDriver::parse_file(const misc::path& name)
+ {
+ if (parse_trace_p_)
+ std::cerr << "Parsing file: " << name << '\n';
+ input_ = name.string();
+ return parse_();
+ }
+
+ /*----------------.
+ | Parse a Tweast. |
+ `----------------*/
+
+ ast_type TigerDriver::parse_input(Tweast& s, bool extensions)
+ {
+ std::swap(extensions, enable_extensions_p_);
+ // Merge all aggregated Tweasts into a single one.
+ s.flatten();
+ if (parse_trace_p_)
+ std::cerr << "Parsing string: " << s.input_get() << '\n';
+ input_ = &s;
+ ast_type res = parse_();
+ std::swap(extensions, enable_extensions_p_);
+ return res;
+ }
+
+ ast_type TigerDriver::parse(Tweast& s) { return parse_input(s, true); }
+
+ /*-----------------.
+ | Parse a string. |
+ `-----------------*/
+
+ ast_type TigerDriver::parse(const std::string& s)
+ {
+ Tweast in(s);
+ return parse_input(in, false);
+ }
+
+ /*-----------------------.
+ | Parse a Tiger import. |
+ `-----------------------*/
+
+ ast::ChunkList* TigerDriver::parse_import(const std::string& name,
+ const location& loc)
+ {
+ // Try to find directory containing the file to import.
+ misc::path directory_path = library_.find_file(name);
+
+ if (directory_path.empty())
+ {
+ error_ << misc::error::error_type::failure << loc << ": " << name
+ << ": file not found.\n";
+ return nullptr;
+ }
+
+ // Complete path of file (directory + filename).
+ misc::path absolute_path =
+ directory_path / misc::path(misc::path(name).filename());
+
+ // Detect recursive inclusion.
+ if (open_files_.find(absolute_path) != open_files_.end())
+ {
+ error_ << misc::error::error_type::failure << loc << ": " << name
+ << ": recursive inclusion.\n"
+ << open_files_[absolute_path]
+ << ": initial inclusion was here.\n";
+ return nullptr;
+ }
+
+ library_.push_current_directory(directory_path);
+ open_files_[absolute_path] = loc;
+ // Save the inputs, and reset them.
+ input_type saved_input = input_;
+ location saved_location = location_;
+ // Parse the imported file.
+ ast::ChunkList* res = nullptr;
+ try
+ {
+ res = parse_file(absolute_path);
+ }
+ catch (const std::bad_variant_access& e)
+ {
+ error_ << misc::error::error_type::parse << absolute_path
+ << ": imported from " << loc
+ << ": syntax error, unexpected exp, expecting chunks.\n";
+ error_.exit();
+ }
+ // Set the inputs back to their original values.
+ input_ = saved_input;
+ location_ = saved_location;
+
+ open_files_.erase(absolute_path);
+ library_.pop_current_directory();
+ return res;
+ }
+
+ const misc::error& TigerDriver::error_get() const { return error_; }
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/tiger-driver.hh b/tiger-compiler/src/parse/tiger-driver.hh
new file mode 100644
index 0000000..266f8c2
--- /dev/null
+++ b/tiger-compiler/src/parse/tiger-driver.hh
@@ -0,0 +1,110 @@
+/**
+ ** \file parse/tiger-driver.hh
+ ** \brief Declaration of parse::TigerDriver.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <stack>
+
+#include <ast/fwd.hh>
+#include <common.hh>
+#include <misc/error.hh>
+#include <misc/file-library.hh>
+#include <parse/parsetiger.hh>
+#include <parse/tweast.hh>
+
+namespace parse
+{
+ /// Conduct the scanner and the parser.
+ class TigerDriver
+ {
+ public:
+ /// The parsed object is either a file, represented by the filename
+ /// or a Tweast.
+ using input_type = misc::variant<std::string, Tweast*>;
+
+ TigerDriver(const misc::file_library& lib = misc::file_library());
+ ~TigerDriver();
+
+ friend class parser;
+ /// Parse the Tiger file \a name.
+ ast_type parse_file(const misc::path& name);
+ /// Parse the Tweast \a s. Extensions are enabled.
+ ast_type parse(Tweast& s);
+ /// Parse the string \a s. Extensions are automatically disabled.
+ ast_type parse(const std::string& s);
+
+ /// Parse a Tiger prelude, return the list of chunk.
+ ast::ChunkList* parse_import(const std::string& name, const location& loc);
+
+ /// Return the error status of the parsing.
+ const misc::error& error_get() const;
+
+ /// The default prelude.
+ const char* prelude() const;
+
+ /// Set the scanner traces.
+ TigerDriver& scan_trace(bool b = true);
+
+ /// Set the parser traces.
+ TigerDriver& parse_trace(bool b = true);
+
+ /// Enable object extensions.
+ TigerDriver& enable_object_extensions(bool b = true);
+
+ /// Enable object extensions.
+ TigerDriver& enable_assert_extensions(bool b = true);
+
+ /// Enable syntax extensions.
+ TigerDriver& enable_extensions(bool b = true);
+
+ private:
+ /// \name Handling the scanner.
+ /// \{
+ /// Verbose scanning?
+ bool scan_trace_p_ = getenv("SCAN");
+
+ /// The list of open files, and the location of their request.
+ std::map<misc::path, location> open_files_;
+ /// \}
+
+ /// \name Running the parse.
+ /// \{
+ /// Parse a Tiger program, return the AST.
+ ast_type parse_();
+
+ /// Parse a Tweast. \a extensions temporarily enable or disable
+ /// extensions for the string parsing. This method is used to factor
+ /// code between parse(Tweast) and parse(const std::string))
+ ast_type parse_input(Tweast& input, bool extensions);
+
+ /// Parse a Tiger prelude \a f, return the list of chunk.
+ ast::ChunkList* parse_prelude(const std::string& f);
+
+ public:
+ /// The result of the parse.
+ ast_type ast_;
+ /// Parsing errors handler.
+ misc::error error_;
+ /// Verbose parsing?
+ bool parse_trace_p_ = getenv("PARSE");
+ /// \}
+
+ /// The location requesting the import.
+ location location_;
+ /// The source to parse.
+ input_type input_;
+ /// The file library for imports.
+ misc::file_library library_;
+ /// Allow object extensions?
+ bool enable_object_extensions_p_ = false;
+ /// Allow assert extensions?
+ bool enable_assert_extensions_p_ = false;
+ /// Allow language extensions (reserved identifiers, new keywords)?
+ bool enable_extensions_p_ = false;
+ };
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/tiger-factory.hh b/tiger-compiler/src/parse/tiger-factory.hh
new file mode 100644
index 0000000..9165bb6
--- /dev/null
+++ b/tiger-compiler/src/parse/tiger-factory.hh
@@ -0,0 +1,144 @@
+/**
+ ** \file parse/tiger-factory.hh
+ ** \brief Declaration of parse::TigerFactory.
+ */
+
+#pragma once
+
+#include <ast/all.hh>
+#include <ast/fwd.hh>
+#include <parse/location.hh>
+
+namespace parse
+{
+ ast::IntExp* make_IntExp(const location& location, int num);
+
+ ast::StringExp* make_StringExp(const location& location, std::string string);
+
+ ast::ObjectExp* make_ObjectExp(const location& location,
+ ast::NameTy* type_name);
+
+ ast::CallExp* make_CallExp(const location& location,
+ misc::symbol name,
+ ast::exps_type* args);
+
+ ast::MethodCallExp* make_MethodCallExp(const location& location,
+ misc::symbol name,
+ ast::exps_type* args,
+ ast::Var* object);
+
+ ast::RecordExp* make_RecordExp(const location& location,
+ ast::NameTy* type_name,
+ ast::fieldinits_type* fields);
+
+ ast::ArrayExp* make_ArrayExp(const location& location,
+ ast::NameTy* type_name,
+ ast::Exp* size,
+ ast::Exp* init);
+
+ ast::NilExp* make_NilExp(const location& location);
+
+ ast::SeqExp* make_SeqExp(const location& location, ast::exps_type* exps);
+
+ ast::AssignExp*
+ make_AssignExp(const location& location, ast::Var* var, ast::Exp* exp);
+
+ ast::IfExp* make_IfExp(const location& location,
+ ast::Exp* test,
+ ast::Exp* thenclause,
+ ast::Exp* elseclause);
+
+ ast::IfExp*
+ make_IfExp(const location& location, ast::Exp* test, ast::Exp* thenclause);
+
+ ast::WhileExp*
+ make_WhileExp(const location& location, ast::Exp* test, ast::Exp* body);
+
+ ast::ForExp* make_ForExp(const location& location,
+ ast::VarDec* vardec,
+ ast::Exp* hi,
+ ast::Exp* body);
+
+ ast::BreakExp* make_BreakExp(const location& location);
+
+ ast::LetExp*
+ make_LetExp(const location& location, ast::ChunkList* decs, ast::Exp* body);
+
+ ast::OpExp* make_OpExp(const location& location,
+ ast::Exp* left,
+ ast::OpExp::Oper oper,
+ ast::Exp* right);
+
+ ast::CastExp*
+ make_CastExp(const location& location, ast::Exp* exp, ast::Ty* ty);
+
+ ast::SimpleVar* make_SimpleVar(const location& location, misc::symbol name);
+
+ ast::FieldVar*
+ make_FieldVar(const location& location, ast::Var* var, misc::symbol name);
+
+ ast::SubscriptVar*
+ make_SubscriptVar(const location& location, ast::Var* var, ast::Exp* index);
+
+ /* Use expansion parameter pack to handle when we have one or empty arguments */
+ template <class... T> ast::exps_type* make_exps_type(T... exps);
+
+ ast::ChunkList* make_ChunkList(const location& location);
+
+ ast::TypeChunk* make_TypeChunk(const location& location);
+
+ ast::TypeDec*
+ make_TypeDec(const location& location, misc::symbol name, ast::Ty* ty);
+
+ ast::RecordTy* make_RecordTy(const location& location,
+ ast::fields_type* fields);
+
+ ast::ArrayTy* make_ArrayTy(const location& location, ast::NameTy* base_type);
+
+ template <class... T> ast::fields_type* make_fields_type(T... types);
+
+ ast::Field* make_Field(const location& location,
+ misc::symbol name,
+ ast::NameTy* type_name);
+
+ ast::NameTy* make_NameTy(const location& location, misc::symbol name);
+
+ template <class... T>
+ ast::fieldinits_type* make_fieldinits_type(T... inits_types);
+
+ ast::FieldInit*
+ make_FieldInit(const location& location, misc::symbol name, ast::Exp* init);
+
+ ast::ClassTy* make_ClassTy(const location& location,
+ ast::NameTy* super,
+ ast::ChunkList* decs);
+
+ ast::VarChunk* make_VarChunk(const location& location);
+
+ ast::VarDec* make_VarDec(const location& location,
+ misc::symbol name,
+ ast::NameTy* type_name,
+ ast::Exp* init);
+
+ ast::MethodChunk* make_MethodChunk(const location& location);
+
+ ast::MethodDec* make_MethodDec(const location& location,
+ misc::symbol name,
+ ast::VarChunk* formals,
+ ast::NameTy* result,
+ ast::Exp* body);
+
+ ast::FunctionDec* make_FunctionDec(const location& location,
+ misc::symbol name,
+ ast::VarChunk* formals,
+ ast::NameTy* result,
+ ast::Exp* body);
+
+ template <class... T> ast::FunctionChunk* make_FunctionChunk(T... args);
+
+ // For the custom tiger extension
+ ast::AssertExp* make_AssertExp(const location& location,
+ ast::Exp* condition);
+} // namespace parse
+
+#include <parse/tiger-factory.hxx>
diff --git a/tiger-compiler/src/parse/tiger-factory.hxx b/tiger-compiler/src/parse/tiger-factory.hxx
new file mode 100644
index 0000000..39d8531
--- /dev/null
+++ b/tiger-compiler/src/parse/tiger-factory.hxx
@@ -0,0 +1,272 @@
+#pragma once
+#include <parse/tiger-factory.hh>
+
+namespace parse
+{
+ inline ast::IntExp* make_IntExp(const location& location, int num)
+ {
+ return new ast::IntExp(location, num);
+ }
+
+ inline ast::StringExp* make_StringExp(const location& location,
+ std::string string)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of StringExp).
+ return new ast::StringExp(location, string);
+ }
+
+ inline ast::ObjectExp* make_ObjectExp(const location& location,
+ ast::NameTy* type_name)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of Object).
+ return new ast::ObjectExp(location, type_name);
+ }
+
+ inline ast::CallExp* make_CallExp(const location& location,
+ misc::symbol name,
+ ast::exps_type* args)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of CallExp).
+ return new ast::CallExp(location, name, args);
+ }
+
+ inline ast::MethodCallExp* make_MethodCallExp(const location& location,
+ misc::symbol name,
+ ast::exps_type* args,
+ ast::Var* object)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of MethodCallExp).
+ return new ast::MethodCallExp(location, name, args, object);
+ }
+
+ inline ast::RecordExp* make_RecordExp(const location& location,
+ ast::NameTy* type_name,
+ ast::fieldinits_type* fields)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of RecordExp).
+ return new ast::RecordExp(location, type_name, fields);
+ }
+
+ inline ast::ArrayExp* make_ArrayExp(const location& location,
+ ast::NameTy* type_name,
+ ast::Exp* size,
+ ast::Exp* init)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of ArrayExp).
+ return new ast::ArrayExp(location, type_name, size, init);
+ }
+
+ inline ast::NilExp* make_NilExp(const location& location)
+ {
+ return new ast::NilExp(location);
+ }
+
+ inline ast::SeqExp* make_SeqExp(const location& location,
+ ast::exps_type* exps)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of SeqExp).
+ return new ast::SeqExp(location, exps);
+ }
+
+ inline ast::AssignExp*
+ make_AssignExp(const location& location, ast::Var* var, ast::Exp* exp)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of AssignExp).
+ return new ast::AssignExp(location, var, exp);
+ }
+
+ inline ast::IfExp* make_IfExp(const location& location,
+ ast::Exp* test,
+ ast::Exp* thenclause,
+ ast::Exp* elseclause)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of IfExp).
+ return new ast::IfExp(location, test, thenclause, elseclause);
+ }
+
+ inline ast::IfExp*
+ make_IfExp(const location& location, ast::Exp* test, ast::Exp* thenclause)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of IfExp).
+ return new ast::IfExp(location, test, thenclause);
+ }
+
+ inline ast::WhileExp*
+ make_WhileExp(const location& location, ast::Exp* test, ast::Exp* body)
+ {
+ return new ast::WhileExp(location, test, body);
+ }
+
+ inline ast::ForExp* make_ForExp(const location& location,
+ ast::VarDec* vardec,
+ ast::Exp* hi,
+ ast::Exp* body)
+ {
+ return new ast::ForExp(location, vardec, hi, body);
+ }
+
+ inline ast::BreakExp* make_BreakExp(const location& location)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of BreakExp).
+ return new ast::BreakExp(location);
+ }
+
+ inline ast::LetExp*
+ make_LetExp(const location& location, ast::ChunkList* decs, ast::Exp* body)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of LetExp).
+ return new ast::LetExp(location, decs, body);
+ }
+
+ inline ast::OpExp* make_OpExp(const location& location,
+ ast::Exp* left,
+ ast::OpExp::Oper oper,
+ ast::Exp* right)
+ {
+ return new ast::OpExp(location, left, oper, right);
+ }
+
+ inline ast::CastExp*
+ make_CastExp(const location& location, ast::Exp* exp, ast::Ty* ty)
+ {
+ return new ast::CastExp(location, exp, ty);
+ }
+
+ inline ast::SimpleVar* make_SimpleVar(const location& location,
+ misc::symbol name)
+ {
+ return new ast::SimpleVar(location, name);
+ }
+
+ inline ast::FieldVar*
+ make_FieldVar(const location& location, ast::Var* var, misc::symbol name)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of FieldVar).
+ return new ast::FieldVar(location, var, name);
+ }
+
+ inline ast::SubscriptVar*
+ make_SubscriptVar(const location& location, ast::Var* var, ast::Exp* index)
+ {
+ return new ast::SubscriptVar(location, var, index);
+ }
+
+ /* Use expansion parameter pack to handle one or empty arguments */
+ template <class... T> inline ast::exps_type* make_exps_type(T... exps)
+ {
+ return new ast::exps_type{exps...};
+ }
+
+ inline ast::ChunkList* make_ChunkList(const location& location)
+ {
+ return new ast::ChunkList(location);
+ }
+
+ inline ast::TypeChunk* make_TypeChunk(const location& location)
+ {
+ return new ast::TypeChunk(location);
+ }
+
+ inline ast::TypeDec*
+ make_TypeDec(const location& location, misc::symbol name, ast::Ty* ty)
+ {
+ return new ast::TypeDec(location, name, ty);
+ }
+
+ inline ast::RecordTy* make_RecordTy(const location& location,
+ ast::fields_type* fields)
+ {
+ // FIXME DONE: Some code was deleted here (Constructor of RecordTy).
+ return new ast::RecordTy(location, fields);
+ }
+
+ inline ast::ArrayTy* make_ArrayTy(const location& location,
+ ast::NameTy* base_type)
+ {
+ return new ast::ArrayTy(location, base_type);
+ }
+
+ template <class... T> inline ast::fields_type* make_fields_type(T... types)
+ {
+ return new ast::fields_type{types...};
+ }
+
+ inline ast::Field* make_Field(const location& location,
+ misc::symbol name,
+ ast::NameTy* type_name)
+ {
+ return new ast::Field(location, name, type_name);
+ }
+
+ inline ast::NameTy* make_NameTy(const location& location, misc::symbol name)
+ {
+ return new ast::NameTy(location, name);
+ }
+
+ template <class... T>
+ inline ast::fieldinits_type* make_fieldinits_type(T... inits_types)
+ {
+ return new ast::fieldinits_type{inits_types...};
+ }
+
+ inline ast::FieldInit*
+ make_FieldInit(const location& location, misc::symbol name, ast::Exp* init)
+ {
+ return new ast::FieldInit(location, name, init);
+ }
+
+ inline ast::ClassTy* make_ClassTy(const location& location,
+ ast::NameTy* super,
+ ast::ChunkList* decs)
+ {
+ return new ast::ClassTy(location, super, decs);
+ }
+
+ inline ast::VarChunk* make_VarChunk(const location& location)
+ {
+ return new ast::VarChunk(location);
+ }
+
+ inline ast::VarDec* make_VarDec(const location& location,
+ misc::symbol name,
+ ast::NameTy* type_name,
+ ast::Exp* init)
+ {
+ return new ast::VarDec(location, name, type_name, init);
+ }
+
+ inline ast::MethodChunk* make_MethodChunk(const location& location)
+ {
+ return new ast::MethodChunk(location);
+ }
+
+ inline ast::MethodDec* make_MethodDec(const location& location,
+ misc::symbol name,
+ ast::VarChunk* formals,
+ ast::NameTy* result,
+ ast::Exp* body)
+ {
+ return new ast::MethodDec(location, name, formals, result, body);
+ }
+
+ inline ast::FunctionDec* make_FunctionDec(const location& location,
+ misc::symbol name,
+ ast::VarChunk* formals,
+ ast::NameTy* result,
+ ast::Exp* body)
+ {
+ return new ast::FunctionDec(location, name, formals, result, body);
+ }
+
+ template <class... T> inline ast::FunctionChunk* make_FunctionChunk(T... args)
+ {
+ return new ast::FunctionChunk(args...);
+ }
+
+ // For the custom tiger extension
+ inline ast::AssertExp* make_AssertExp(const location& location,
+ ast::Exp* condition)
+ {
+ return new ast::AssertExp(location, condition);
+ }
+} // namespace parse
diff --git a/tiger-compiler/src/parse/tweast.cc b/tiger-compiler/src/parse/tweast.cc
new file mode 100644
index 0000000..fbb21ac
--- /dev/null
+++ b/tiger-compiler/src/parse/tweast.cc
@@ -0,0 +1,87 @@
+/**
+ ** \file parse/tweast.cc
+ ** \brief Implementation of parse::Tweast.
+ */
+
+#include <sstream>
+
+#include <boost/algorithm/string/replace.hpp>
+
+#include <parse/tweast.hh>
+
+namespace parse
+{
+ unsigned Tweast::count_ = 0;
+
+ Tweast::Tweast()
+ : Tweast("")
+ {}
+
+ Tweast::Tweast(const std::string& str)
+ : MetavarMap<ast::Exp>::MetavarMap("exp")
+ , MetavarMap<ast::Var>::MetavarMap("lvalue")
+ , MetavarMap<ast::NameTy>::MetavarMap("namety")
+ , MetavarMap<ast::ChunkList>::MetavarMap("chunks")
+ , MetavarMap<Tweast>::MetavarMap("tweast")
+ , input_(str)
+ {}
+
+ void Tweast::flatten()
+ {
+ using tweasts_type = MetavarMap<Tweast>;
+ using tweasts_map_type = tweasts_type::map_type;
+
+ // Recursively flatten each Tweast metavariable.
+ for (const tweasts_map_type::value_type& t : tweasts_type::map_)
+ t.second->flatten();
+
+ // Grab each non-Tweast metavariable of Tweast metavariables, and
+ // renumber the metavariables.
+ for (const tweasts_map_type::value_type& t : tweasts_type::map_)
+ {
+ unsigned tweast_index = t.first;
+ Tweast& tweast = *t.second;
+
+ // Tweast input.
+ std::string tweast_input = tweast.input_get();
+ // Move metavariables to THIS and rename them.
+ move_metavars_<ast::Exp>(tweast, tweast_input);
+ move_metavars_<ast::Var>(tweast, tweast_input);
+ move_metavars_<ast::NameTy>(tweast, tweast_input);
+ move_metavars_<ast::ChunkList>(tweast, tweast_input);
+
+ // Replace the tweast metavariable reference with its input string.
+ std::string tweast_var = tweasts_type::show(tweast_index);
+ std::string input = input_.str();
+ boost::algorithm::replace_first(input, tweast_var, tweast_input);
+ input_.str(input);
+ }
+
+ // Delete aggregated Tweasts, and remove their associated
+ // metavariable from the map of Tweasts.
+ for (const tweasts_map_type::value_type& t : tweasts_type::map_)
+ delete t.second;
+ tweasts_type::map_.clear();
+ }
+
+ std::string Tweast::input_get() const { return input_.str(); }
+
+ std::ostream& Tweast::dump(std::ostream& ostr) const
+ {
+ ostr << "input = \"" << input_.str() << "\"" << misc::iendl;
+
+ MetavarMap<ast::Exp>::dump(ostr);
+ MetavarMap<ast::Var>::dump(ostr);
+ MetavarMap<ast::NameTy>::dump(ostr);
+ MetavarMap<ast::ChunkList>::dump(ostr);
+ MetavarMap<Tweast>::dump(ostr);
+
+ return ostr << misc::decendl;
+ }
+
+ std::ostream& operator<<(std::ostream& ostr, const Tweast& in)
+ {
+ return in.dump(ostr);
+ }
+
+} // namespace parse
diff --git a/tiger-compiler/src/parse/tweast.hh b/tiger-compiler/src/parse/tweast.hh
new file mode 100644
index 0000000..910f694
--- /dev/null
+++ b/tiger-compiler/src/parse/tweast.hh
@@ -0,0 +1,79 @@
+/**
+ ** \file parse/tweast.hh
+ ** \brief Declaration of parse::Tweast.
+ */
+
+#pragma once
+
+#include <iostream>
+#include <map>
+#include <sstream>
+
+#include <ast/fwd.hh>
+
+#include <misc/map.hh>
+#include <misc/symbol.hh>
+#include <parse/metavar-map.hh>
+
+namespace parse
+{
+ /// \brief TWEAST stands for ``Text With Embedded Abstract Syntax Trees''.
+ ///
+ /// Aggregate string to parse and tables of metavariables.
+ class Tweast
+ : public MetavarMap<ast::Exp>
+ , public MetavarMap<ast::Var>
+ , public MetavarMap<ast::NameTy>
+ , public MetavarMap<ast::ChunkList>
+ , public MetavarMap<parse::Tweast>
+ {
+ public:
+ Tweast();
+ Tweast(const std::string& str);
+
+ /// \brief Stream manipulator.
+ ///
+ /// Append Tiger expressions to the string to parse.
+ template <typename T> Tweast& operator<<(const T& t);
+
+ /// Metavariables manipulator.
+ template <typename T> T* take(unsigned s);
+
+ /// Move the contents of all aggregated Tweast metavariables into
+ /// the current Tweast.
+ void flatten();
+
+ /// Get the current input string.
+ std::string input_get() const;
+
+ /// Print the table
+ std::ostream& dump(std::ostream& ostr) const;
+
+ protected:
+ // Insert base class members in the current scope.
+ using MetavarMap<ast::Exp>::append_;
+ using MetavarMap<ast::Var>::append_;
+ using MetavarMap<ast::NameTy>::append_;
+ using MetavarMap<ast::ChunkList>::append_;
+ using MetavarMap<Tweast>::append_;
+
+ /// Fake append (default case, i.e. when \a data is not a metavariable).
+ template <typename T> T& append_(unsigned&, T& data) const;
+
+ template <typename T>
+ void move_metavars_(Tweast& tweast, std::string& input);
+
+ protected:
+ /// The next identifier suffix to create.
+ static unsigned count_;
+
+ /// The string to parse.
+ std::stringstream input_;
+ };
+
+ /// Display the content of the tweast.
+ std::ostream& operator<<(std::ostream& ostr, const Tweast& in);
+
+} // namespace parse
+
+#include <parse/tweast.hxx>
diff --git a/tiger-compiler/src/parse/tweast.hxx b/tiger-compiler/src/parse/tweast.hxx
new file mode 100644
index 0000000..3cb9592
--- /dev/null
+++ b/tiger-compiler/src/parse/tweast.hxx
@@ -0,0 +1,75 @@
+/**
+ ** \file parse/tweast.hxx
+ ** \brief implements inline methods of parse/tweast.hh
+ */
+
+#pragma once
+
+#include <algorithm>
+
+#include <boost/algorithm/string/replace.hpp>
+
+#include <misc/algorithm.hh>
+#include <misc/error.hh>
+#include <parse/tweast.hh>
+
+namespace parse
+{
+ template <typename T> T& Tweast::append_(unsigned&, T& data) const
+ {
+ return data;
+ }
+
+ template <typename T> Tweast& Tweast::operator<<(const T& t)
+ {
+ input_ << append_(count_, t);
+ return *this;
+ }
+
+ template <typename T> T* Tweast::take(unsigned s)
+ {
+ T* t = nullptr;
+ try
+ {
+ t = MetavarMap<T>::take_(s);
+ }
+ catch (const std::range_error& e)
+ {
+ // Print the contents of the Tweast before dying.
+ misc::error error;
+ error << e.what() << std::endl;
+ error << *this;
+ error.ice_here();
+ }
+ return t;
+ }
+
+ template <typename T>
+ void Tweast::move_metavars_(Tweast& tweast, std::string& input)
+ {
+ using metavars_type = MetavarMap<T>;
+ for (const typename metavars_type::map_type::value_type& var :
+ tweast.metavars_type::map_)
+ {
+ // Append the variable from VAR to the enclosing Tweast.
+ unsigned old_num = var.first;
+ // Warning, this is not thread-safe.
+ unsigned new_num = count_;
+ T* data = var.second;
+ metavars_type::map_[new_num] = data;
+ ++count_;
+
+ // Rename metavariables according to the numbering scheme
+ // within the input string.
+ std::string old_str = metavars_type::show(old_num);
+ std::string new_str = metavars_type::show(new_num);
+ // FIXME: This is inefficient, since the string is viewed
+ // each time a metavariable is processed. Better store
+ // each (old_num, new_num) pair in a map, and process
+ // the string in a single pass.
+ boost::algorithm::replace_first(input, old_str, new_str);
+ }
+ tweast.metavars_type::map_.clear();
+ }
+
+} // namespace parse
diff --git a/tiger-compiler/src/task/argument-task.cc b/tiger-compiler/src/task/argument-task.cc
new file mode 100644
index 0000000..82194f3
--- /dev/null
+++ b/tiger-compiler/src/task/argument-task.cc
@@ -0,0 +1,29 @@
+/**
+ ** \file task/argument-task.cc
+ ** \brief ArgumentTask class implementation.
+ */
+
+#include <task/argument-task.hh>
+#include <task/task-register.hh>
+
+namespace task
+{
+ ArgumentTask::ArgumentTask(const char* name,
+ const char* module_name,
+ const char* desc,
+ const char* argname,
+ std::string deps)
+ : Task(name, module_name, desc, deps)
+ , argname_(argname)
+ {
+ // Register this task.
+ TaskRegister::instance().register_task(*this);
+ }
+
+ const std::string& ArgumentTask::arg_get() const { return arg_; }
+
+ void ArgumentTask::arg_set(const std::string& arg) const { arg_ = arg; }
+
+ const char* ArgumentTask::argname_get() const { return argname_; }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/argument-task.hh b/tiger-compiler/src/task/argument-task.hh
new file mode 100644
index 0000000..775b084
--- /dev/null
+++ b/tiger-compiler/src/task/argument-task.hh
@@ -0,0 +1,58 @@
+/**
+ ** \file task/argument-task.hh
+ ** \brief Declare the task::ArgumentTask class.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <task/task.hh>
+
+namespace task
+{
+ /** \brief A `Task' expecting arguments prior to be executed.
+
+ This class embodies tasks which need an additional parameter for their
+ `execute()' method. Therefore a call to `arg_set()' must be made prior to
+ the `execute()' method, to set the value of this expected argument.
+ This class also automates the registering of its derived classes, as does its
+ sibling class `SimpleTask' for tasks without additional argument.
+ */
+ class ArgumentTask : public Task
+ {
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /// Construct and register an ArgumentTask.
+ ArgumentTask(const char* name,
+ const char* module_name,
+ const char* desc,
+ const char* argname,
+ std::string deps = "");
+
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ public:
+ /// Access to 'arg'.
+ const std::string& arg_get() const;
+
+ /// Access to `arg'.
+ virtual void arg_set(const std::string& arg) const;
+
+ /// Access to `argname'.
+ const char* argname_get() const;
+
+ /** \} */
+
+ protected:
+ /// ArgumentTask argument value.
+ mutable std::string arg_;
+
+ /// Argument name to be displayed when printing.
+ const char* argname_;
+ };
+
+} // namespace task
diff --git a/tiger-compiler/src/task/boolean-task.cc b/tiger-compiler/src/task/boolean-task.cc
new file mode 100644
index 0000000..9923082
--- /dev/null
+++ b/tiger-compiler/src/task/boolean-task.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file task/boolean-task.cc
+ ** \brief Implementation of task::BooleanTask.
+ **
+ */
+
+#include <task/boolean-task.hh>
+
+namespace task
+{
+ BooleanTask::BooleanTask(bool& flag,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : SimpleTask(name, module_name, desc, deps)
+ , flag_(flag)
+ {}
+
+ void BooleanTask::execute() const { flag_ = true; }
+
+} //namespace task
diff --git a/tiger-compiler/src/task/boolean-task.hh b/tiger-compiler/src/task/boolean-task.hh
new file mode 100644
index 0000000..88298b3
--- /dev/null
+++ b/tiger-compiler/src/task/boolean-task.hh
@@ -0,0 +1,28 @@
+/**
+ ** \file task/boolean-task.hh
+ ** \brief Declare the task::BooleanTask class.
+ **
+ */
+#pragma once
+
+#include <task/simple-task.hh>
+
+namespace task
+{
+ /// A simple Task that sets a Boolean variable to true.
+ class BooleanTask : public SimpleTask
+ {
+ public:
+ BooleanTask(bool& flag,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ void execute() const override;
+
+ private:
+ bool& flag_;
+ };
+
+} // namespace task
diff --git a/tiger-compiler/src/task/disjunctive-task.cc b/tiger-compiler/src/task/disjunctive-task.cc
new file mode 100644
index 0000000..07661bf
--- /dev/null
+++ b/tiger-compiler/src/task/disjunctive-task.cc
@@ -0,0 +1,32 @@
+/**
+ ** \file task/disjunctive-task.cc
+ ** \brief Implementation of task::DisjunctiveTask.
+ **
+ */
+
+#include <task/disjunctive-task.hh>
+
+namespace task
+{
+ DisjunctiveTask::DisjunctiveTask(const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : SimpleTask(name, module_name, desc, deps)
+ {}
+
+ void DisjunctiveTask::execute() const
+ {
+ // Nothing to do.
+ }
+
+ Task::deps_type
+ DisjunctiveTask::resolve_dependencies(tasks_list_type& active_tasks) const
+ {
+ if (!active_tasks.empty() || dependencies_.empty())
+ return Task::deps_type();
+ else
+ return Task::deps_type(1, *dependencies_.begin());
+ }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/disjunctive-task.hh b/tiger-compiler/src/task/disjunctive-task.hh
new file mode 100644
index 0000000..6cb52fc
--- /dev/null
+++ b/tiger-compiler/src/task/disjunctive-task.hh
@@ -0,0 +1,27 @@
+/**
+ ** \file task/disjunctive-task.hh
+ ** \brief Declare the DisjunctiveTask class.
+ **
+ */
+#pragma once
+
+#include <task/simple-task.hh>
+
+namespace task
+{
+ /// A Task that makes sure that AT LEAST one of its dependencies is
+ /// scheduled.
+ class DisjunctiveTask : public SimpleTask
+ {
+ public:
+ DisjunctiveTask(const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ void execute() const override;
+ deps_type
+ resolve_dependencies(tasks_list_type& active_tasks) const override;
+ };
+
+} //namespace task
diff --git a/tiger-compiler/src/task/function-task.cc b/tiger-compiler/src/task/function-task.cc
new file mode 100644
index 0000000..309a276
--- /dev/null
+++ b/tiger-compiler/src/task/function-task.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file task/function-task.cc
+ ** \brief Implementation of task::FunctionTask.
+ **
+ */
+
+#include <task/function-task.hh>
+
+namespace task
+{
+ FunctionTask::FunctionTask(callback_type& callback,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : SimpleTask(name, module_name, desc, deps)
+ , execute_(callback)
+ {}
+
+ void FunctionTask::execute() const { execute_(); }
+
+} //namespace task
diff --git a/tiger-compiler/src/task/function-task.hh b/tiger-compiler/src/task/function-task.hh
new file mode 100644
index 0000000..a08b285
--- /dev/null
+++ b/tiger-compiler/src/task/function-task.hh
@@ -0,0 +1,31 @@
+/**
+ ** \file task/function-task.hh
+ ** \brief Declare the task::FunctionTask class.
+ **
+ */
+#pragma once
+
+#include <task/simple-task.hh>
+
+namespace task
+{
+ /// A simple Task that invokes a callback function.
+ class FunctionTask : public SimpleTask
+ {
+ public:
+ using callback_type = auto() -> void;
+
+ FunctionTask(callback_type& callback,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ public:
+ void execute() const override;
+
+ private:
+ callback_type& execute_;
+ };
+
+} //namespace task
diff --git a/tiger-compiler/src/task/fwd.hh b/tiger-compiler/src/task/fwd.hh
new file mode 100644
index 0000000..620016f
--- /dev/null
+++ b/tiger-compiler/src/task/fwd.hh
@@ -0,0 +1,22 @@
+/**
+ ** \file task/fwd.hh
+ ** \brief Interface to the Task module.
+ **
+ */
+#pragma once
+
+namespace task
+{
+ // task.hh
+ class Task;
+
+ // argument-task.hh
+ class ArgumentTask;
+
+ // simple-task.hh
+ class SimpleTask;
+
+ // task-register.hh
+ class TaskRegister;
+
+} // namespace task
diff --git a/tiger-compiler/src/task/int-task.cc b/tiger-compiler/src/task/int-task.cc
new file mode 100644
index 0000000..bf26271
--- /dev/null
+++ b/tiger-compiler/src/task/int-task.cc
@@ -0,0 +1,55 @@
+/**
+ ** \file task/int-task.cc
+ ** \brief IntTask class implementation.
+ **
+ */
+
+#include <exception>
+#include <iostream>
+
+#include <common.hh>
+#include <task/int-task.hh>
+
+namespace task
+{
+ IntTask::IntTask(int& var,
+ int min,
+ int max,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : ArgumentTask(name, module_name, desc, "NUM", deps)
+ , var_(var)
+ , min_(min)
+ , max_(max)
+ {}
+
+ void IntTask::arg_set(const std::string& arg) const
+ {
+ arg_ = arg;
+
+ try
+ {
+ var_ = stol(arg);
+ }
+ catch (const std::invalid_argument& e)
+ {
+ std::cerr << program_name << ": expected an integer: " << arg << '\n';
+ throw;
+ }
+
+ if (!(min_ <= var_ && var_ <= max_))
+ {
+ std::cerr << program_name << ": invalid integer: " << var_ << '\n';
+
+ throw std::invalid_argument(std::string("invalid integer: ") + arg_);
+ }
+ }
+
+ void IntTask::execute() const
+ {
+ // Assignment done in arg_set.
+ }
+
+} //namespace task
diff --git a/tiger-compiler/src/task/int-task.hh b/tiger-compiler/src/task/int-task.hh
new file mode 100644
index 0000000..a45518d
--- /dev/null
+++ b/tiger-compiler/src/task/int-task.hh
@@ -0,0 +1,33 @@
+/**
+ ** \file task/int-task.hh
+ ** \brief Declare the IntTask class.
+ **
+ */
+#pragma once
+
+#include <task/argument-task.hh>
+
+namespace task
+{
+ /// A simple Task that sets an Int variable.
+ class IntTask : public ArgumentTask
+ {
+ public:
+ IntTask(int& var,
+ int min,
+ int max,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ void execute() const override;
+ void arg_set(const std::string& arg) const override;
+
+ private:
+ int& var_;
+ int min_;
+ int max_;
+ };
+
+} //namespace task
diff --git a/tiger-compiler/src/task/libtask.hh b/tiger-compiler/src/task/libtask.hh
new file mode 100644
index 0000000..518d377
--- /dev/null
+++ b/tiger-compiler/src/task/libtask.hh
@@ -0,0 +1,107 @@
+/**
+ ** \file task/libtask.hh
+ ** \brief Interface to the Task module.
+ **
+ */
+
+/* This file must not be protected against multiple inclusion,
+ because it might be read to define or declare the tasks. */
+
+#include <task/boolean-task.hh>
+#include <task/disjunctive-task.hh>
+#include <task/function-task.hh>
+#include <task/int-task.hh>
+#include <task/multiple-string-task.hh>
+#include <task/string-task.hh>
+
+/// Handling of Task.
+namespace task
+{} // namespace task
+
+/** A means to concatenate tokens with delayed evaluation. */
+#define CONCAT_(A, B) A##B
+#define CONCAT(A, B) CONCAT_(A, B)
+
+/** Make a "unique" token using the line number of invocation of this
+ macro.
+
+ Conflicts are possible, but unlikely: tasks declared at the same
+ line number, but in different files, are not a problem, since
+ anyway the tasks are static, and in different namespaces.
+
+ Just don't declare two tasks on the same line! */
+#define TASK_UNIQUE() CONCAT(task_, __LINE__)
+
+/*------------------------------.
+| Easy instantiation of Tasks. |
+`------------------------------*/
+
+#undef TASK_GROUP
+#undef TASK_DECLARE
+#undef BOOLEAN_TASK_DECLARE
+#undef INT_TASK_DECLARE
+#undef STRING_TASK_DECLARE
+#undef MULTIPLE_STRING_TASK_DECLARE
+#undef DISJUNCTIVE_TASK_DECLARE
+
+// Should we define the objects, or just declare them?
+#if DEFINE_TASKS
+
+/// Define the current Task group name.
+# define TASK_GROUP(Name) const char group_name[] = Name
+
+/// Instantiate a FunctionTask.
+# define TASK_DECLARE(Name, Help, Routine, Deps) \
+ extern void(Routine)(); \
+ static task::FunctionTask task_##Routine(Routine, group_name, Help, Name, \
+ Deps)
+
+/// Instantiate a BooleanTask.
+# define BOOLEAN_TASK_DECLARE(Name, Help, Flag, Deps) \
+ bool Flag; \
+ static task::BooleanTask task_##Flag(Flag, group_name, Help, Name, Deps)
+
+# define TASK_UNIQUE_NAME_(Line) task_##Line
+
+# define TASK_UNIQUE_NAME TASK_UNIQUE_NAME_(__LINE__)
+
+/// Instantiate an IntTask.
+# define INT_TASK_DECLARE(Name, Min, Max, Help, Flag, Deps) \
+ static task::IntTask TASK_UNIQUE()(Flag, Min, Max, group_name, Help, Name, \
+ Deps)
+
+/// Instantiate a StringTask.
+# define STRING_TASK_DECLARE(Name, Default, Help, Flag, Deps) \
+ std::string Flag = Default; \
+ static task::StringTask task_##Flag(Flag, group_name, Help, Name, Deps)
+
+/// Instanciate a MultipleStringTask
+# define MULTIPLE_STRING_TASK_DECLARE(Name, Help, Routine, Deps) \
+ extern task::MultipleStringTask::callback_type Routine; \
+ static task::MultipleStringTask task_##Routine(Routine, group_name, Help, \
+ Name, Deps)
+
+/// Instantiate a DisjunctiveTask.
+# define DISJUNCTIVE_TASK_DECLARE(Name, Help, Deps) \
+ static task::DisjunctiveTask task_##Routine(group_name, Help, Name, Deps)
+
+#else // !DEFINE_TASKS
+
+/// Define the current Task group name.
+# define TASK_GROUP(Name) extern const char* group_name
+/// Instantiate a FunctionTask.
+# define TASK_DECLARE(Name, Help, Routine, Deps) extern void(Routine)()
+/// Instantiate a BooleanTask.
+# define BOOLEAN_TASK_DECLARE(Name, Help, Flag, Deps) extern bool Flag;
+/// Instantiate an IntTask.
+# define INT_TASK_DECLARE(Name, Min, Max, Help, Flag, Deps)
+/// Instantiate a StringTask.
+# define STRING_TASK_DECLARE(Name, Default, Help, Flag, Deps) \
+ extern std::string Flag;
+/// Instantiate a MultipleStringTask.
+# define MULTIPLE_STRING_TASK_DECLARE(Name, Help, Routine, Deps) \
+ extern void(Routine)(std::string);
+/// Instantiate a DisjunctiveTask.
+# define DISJUNCTIVE_TASK_DECLARE(Name, Help, Deps)
+
+#endif // !DEFINE_TASKS
diff --git a/tiger-compiler/src/task/local.am b/tiger-compiler/src/task/local.am
new file mode 100644
index 0000000..a9bd6aa
--- /dev/null
+++ b/tiger-compiler/src/task/local.am
@@ -0,0 +1,15 @@
+## Task module.
+src_libtc_la_SOURCES += \
+ %D%/fwd.hh %D%/libtask.hh \
+ %D%/task.hh %D%/task.hxx %D%/task.cc \
+ %D%/boolean-task.hh %D%/boolean-task.cc \
+ %D%/function-task.hh %D%/function-task.cc \
+ %D%/int-task.hh %D%/int-task.cc \
+ %D%/string-task.hh %D%/string-task.cc \
+ %D%/multiple-string-task.hh %D%/multiple-string-task.cc \
+ %D%/disjunctive-task.hh %D%/disjunctive-task.cc \
+ %D%/task-register.hh %D%/task-register.cc %D%/task-register.hxx \
+ %D%/simple-task.hh %D%/simple-task.cc \
+ %D%/argument-task.hh %D%/argument-task.cc
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/task/multiple-string-task.cc b/tiger-compiler/src/task/multiple-string-task.cc
new file mode 100644
index 0000000..a789663
--- /dev/null
+++ b/tiger-compiler/src/task/multiple-string-task.cc
@@ -0,0 +1,21 @@
+/**
+ ** \file task/multiple-string-task.cc
+ ** \brief Implementation of task::MultipleStringTask.
+ */
+
+#include <task/multiple-string-task.hh>
+
+namespace task
+{
+ MultipleStringTask::MultipleStringTask(callback_type& cb,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : ArgumentTask(name, module_name, desc, "DIR", deps)
+ , execute_(cb)
+ {}
+
+ void MultipleStringTask::execute() const { execute_(arg_get()); }
+
+} //namespace task
diff --git a/tiger-compiler/src/task/multiple-string-task.hh b/tiger-compiler/src/task/multiple-string-task.hh
new file mode 100644
index 0000000..a770b3b
--- /dev/null
+++ b/tiger-compiler/src/task/multiple-string-task.hh
@@ -0,0 +1,34 @@
+/**
+ ** \file task/multiple-string-task.hh
+ ** \brief Declaration of task::MultipleStringTask.
+ **
+ */
+
+#pragma once
+
+#include <string>
+
+#include <task/argument-task.hh>
+
+namespace task
+{
+ /// A simple task that invokes callback function with string argument.
+ class MultipleStringTask : public ArgumentTask
+ {
+ public:
+ using callback_type = auto(const std::string&) -> void;
+
+ MultipleStringTask(callback_type& cb,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ public:
+ void execute() const override;
+
+ public:
+ callback_type& execute_;
+ };
+
+} // namespace task
diff --git a/tiger-compiler/src/task/simple-task.cc b/tiger-compiler/src/task/simple-task.cc
new file mode 100644
index 0000000..031a182
--- /dev/null
+++ b/tiger-compiler/src/task/simple-task.cc
@@ -0,0 +1,21 @@
+/**
+ ** \file task/simple-task.cc
+ ** \brief SimpleTask class implementation.
+ */
+
+#include <task/simple-task.hh>
+#include <task/task-register.hh>
+
+namespace task
+{
+ SimpleTask::SimpleTask(const char* name,
+ const char* module_name,
+ const char* desc,
+ std::string deps)
+ : Task(name, module_name, desc, deps)
+ {
+ // Register this task.
+ TaskRegister::instance().register_task(*this);
+ }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/simple-task.hh b/tiger-compiler/src/task/simple-task.hh
new file mode 100644
index 0000000..b44b8ea
--- /dev/null
+++ b/tiger-compiler/src/task/simple-task.hh
@@ -0,0 +1,34 @@
+/**
+ ** \file task/simple-task.hh
+ ** \brief Declare the task::SimpleTask class.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <task/task.hh>
+
+namespace task
+{
+ /** \brief A code factoring class for tasks without arguments.
+
+ The purpose of this class is to avoid duplicating the code which register a
+ task without arguments. The sibling class task::ArgumentTask does pretty much
+ the same (with extended functionnalities) for tasks with arguments.
+ */
+ class SimpleTask : public Task
+ {
+ /** \name Ctor. */
+ /** \{ */
+ public:
+ /// Construct and register a SimpleTask.
+ SimpleTask(const char* name,
+ const char* module_name,
+ const char* desc,
+ std::string deps = "");
+
+ /** \} */
+ };
+
+} // namespace task
diff --git a/tiger-compiler/src/task/string-task.cc b/tiger-compiler/src/task/string-task.cc
new file mode 100644
index 0000000..db7776c
--- /dev/null
+++ b/tiger-compiler/src/task/string-task.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file task/string-task.cc
+ ** \brief Implementation of task::StringTask.
+ **
+ */
+
+#include <task/string-task.hh>
+
+namespace task
+{
+ StringTask::StringTask(std::string& var,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps)
+ : ArgumentTask(name, module_name, desc, "STRING", deps)
+ , var_(var)
+ {}
+
+ void StringTask::execute() const { var_ = arg_get(); }
+
+} //namespace task
diff --git a/tiger-compiler/src/task/string-task.hh b/tiger-compiler/src/task/string-task.hh
new file mode 100644
index 0000000..9e06293
--- /dev/null
+++ b/tiger-compiler/src/task/string-task.hh
@@ -0,0 +1,28 @@
+/**
+ ** \file task/string-task.hh
+ ** \brief Declare the task::StringTask class.
+ **
+ */
+#pragma once
+
+#include <task/argument-task.hh>
+
+namespace task
+{
+ /// A simple Task that sets a String variable.
+ class StringTask : public ArgumentTask
+ {
+ public:
+ StringTask(std::string& var,
+ const char* module_name,
+ const char* desc,
+ const char* name,
+ std::string deps);
+
+ void execute() const override;
+
+ private:
+ std::string& var_;
+ };
+
+} //namespace task
diff --git a/tiger-compiler/src/task/task-register.cc b/tiger-compiler/src/task/task-register.cc
new file mode 100644
index 0000000..d449eed
--- /dev/null
+++ b/tiger-compiler/src/task/task-register.cc
@@ -0,0 +1,353 @@
+/**
+ ** \file task/task-register.cc
+ ** \brief Implementation of task::TaskRegister.
+ **
+ */
+
+#include <algorithm>
+#include <exception>
+#include <filesystem>
+#include <fstream>
+#include <map>
+
+#include <common.hh>
+#include <misc/algorithm.hh>
+#include <task/argument-task.hh>
+#include <task/disjunctive-task.hh>
+#include <task/simple-task.hh>
+#include <task/task-register.hh>
+
+namespace task
+{
+ // Singleton stuff
+ TaskRegister& TaskRegister::instance()
+ {
+ static TaskRegister instance_;
+ return instance_;
+ }
+
+ // Register this task.
+ void TaskRegister::register_task(const SimpleTask& task)
+ {
+ auto it = register_task_(task);
+ // The task was already registered.
+ if (it == modules_.end())
+ return;
+
+ // Callback when the option is parsed.
+ auto cb = [this, &task](bool f) {
+ if (f)
+ enable_task(task.name_get());
+ };
+
+ namespace po = boost::program_options;
+ auto v = po::bool_switch()->notifier(cb);
+
+ it->second.add_options()(task.fullname_get(), v, task.desc_get());
+ }
+
+ void TaskRegister::register_task(const ArgumentTask& task)
+ {
+ auto it = register_task_(task);
+ // The taks was already registered.
+ if (it == modules_.end())
+ return;
+
+ // Callback when the option is parsed.
+ auto cb = [this, &task](const std::string& arg) {
+ task.arg_set(arg);
+ enable_task(task.name_get());
+ };
+
+ namespace po = boost::program_options;
+ auto v = po::value<std::string>()
+ ->value_name(task.argname_get())
+ ->required()
+ ->notifier(cb);
+
+ it->second.add_options()(task.fullname_get(), v, task.desc_get());
+ }
+
+ // Internal task registration.
+ // Add the task to the list of tasks and return an iterrator to the module
+ // the option belongs to. The module is created if needed.
+ // In case something went wrong, the end of `modules_' is returned.
+ TaskRegister::indexed_module_type::iterator
+ TaskRegister::register_task_(const Task& task)
+ {
+ if (task_list_.find(task.name_get()) != task_list_.end())
+ {
+ task_error() << misc::error::error_type::failure << program_name
+ << ": TaskRegister::register_task(" << task.name_get()
+ << "): task name already registered.\n";
+ return modules_.end();
+ }
+ task_list_[task.name_get()] = &task;
+
+ // Short-hands.
+ namespace po = boost::program_options;
+ const std::string& module_name = task.module_name_get();
+ auto it = modules_.find(module_name);
+ if (it == modules_.end())
+ it = modules_.emplace(module_name, po::options_description(module_name))
+ .first;
+ // Return the iterator on the module the task belongs to.
+ return it;
+ }
+
+ // Request the execution of the task task_name.
+ void TaskRegister::enable_task(const std::string& task_name)
+ {
+ if (task_list_.find(task_name) == task_list_.end())
+ task_error() << misc::error::error_type::failure << program_name
+ << ": TaskRegister::enable_task(" << task_name
+ << "): this task has not been registered.\n";
+ else
+ {
+ const Task* task = task_list_.find(task_name)->second;
+ resolve_dependencies(*task);
+ // FIXME: for efficiency, resolve_dependency should be called once.
+ // FIXME: detect cycle.
+ task_order_.emplace_back(task);
+ }
+ }
+
+ // Return the number of tasks to execute.
+ int TaskRegister::nb_of_task_to_execute_get() { return task_order_.size(); }
+
+ // Resolve dependencies between tasks.
+ void TaskRegister::resolve_dependencies(const Task& task)
+ {
+ tasks_list_type enabled_tasks;
+
+ // Retrieved already active tasks.
+ for (const std::string& s : task.dependencies_get())
+ if (task_list_.find(s) == task_list_.end())
+ {
+ task_error() << misc::error::error_type::failure << program_name
+ << ": TaskRegister::resolve_dependencies(\""
+ << task.name_get() << "\"): unknown task: \"" << s << '"'
+ << std::endl;
+ }
+ else
+ {
+ const Task* task_dep = task_list_.find(s)->second;
+ if (misc::has(task_order_, task_dep))
+ enabled_tasks.emplace_back(task_dep);
+ }
+
+ // Ask the task which dependent tasks should be activated.
+ const Task::deps_type dep_tasks = task.resolve_dependencies(enabled_tasks);
+
+ // Activate them.
+ for (const std::string& s : dep_tasks)
+ {
+ if (task_list_.find(s) != task_list_.end())
+ if (!misc::has(task_order_, task_list_.find(s)->second))
+ enable_task(s);
+ }
+ }
+
+ // Check whether one of the options in os has the string_key s.
+ template <typename T>
+ static bool
+ is_parsed(const std::string& s,
+ const std::vector<boost::program_options::basic_option<T>>& os)
+ {
+ using option = boost::program_options::basic_option<T>;
+
+ return std::ranges::find_if(
+ os, [&s](const option& o) { return s == o.string_key; })
+ != end(os);
+ }
+
+ char* TaskRegister::parse_arg(int argc, char* argv[])
+ {
+ // Short-hand.
+ namespace po = boost::program_options;
+ std::string input_file;
+
+ // Create the category containing `help', `version' and `usage'.
+ po::options_description generic;
+ generic.add_options()("help,?", "Give this help list")(
+ "usage", "Give a short usage message")(
+ "version", "Print program version")("license", "Print program license");
+
+ // Positional parameter.
+ po::options_description hidden;
+ po::positional_options_description positional;
+ hidden.add_options()("input-file",
+ po::value<std::string>(&input_file)->required(),
+ "Input file");
+ positional.add("input-file", 1);
+
+ // Create the top-level category, with visible options.
+ po::options_description visible_desc(program_doc);
+
+ // Add each category to the top-level one.
+ for (const auto& i : modules_)
+ visible_desc.add(i.second);
+ visible_desc.add(generic);
+
+ // Sum of visible options and positional argument.
+ po::options_description all_opts = visible_desc;
+ all_opts.add(hidden);
+
+ // Give control to boost.
+ try
+ {
+ // Sadly we can't use `boost::program_options::variables_map'. By doing
+ // so, we would lose the chronological order of the tasks, which is
+ // capital for TC to work.
+ auto parsed = po::command_line_parser(argc, argv)
+ .options(all_opts)
+ .positional(positional)
+ .run();
+
+ // We don't want to fail if these options are present. So we take care
+ // of them right now.
+ if (is_parsed("help", parsed.options))
+ std::cout << visible_desc;
+ else if (is_parsed("version", parsed.options))
+ std::cout << program_version;
+ else if (is_parsed("usage", parsed.options))
+ std::cout << "tc [OPTIONS...] INPUT-FILE\n";
+ else if (is_parsed("license", parsed.options))
+ {
+ std::filesystem::path licenses("licenses");
+
+ if (!std::filesystem::exists(licenses))
+ {
+ std::cerr << program_name << ": cannot open licenses directory"
+ << ": No such file or directory\n";
+ }
+ else if (!std::filesystem::is_directory(licenses))
+ {
+ std::cerr << program_name << ": cannot open licenses directory"
+ << ": Not a directory\n";
+ }
+ else
+ {
+ using directory_iterator = std::filesystem::directory_iterator;
+ for (const auto& entry : directory_iterator(licenses))
+ {
+ const auto& path = entry.path();
+
+ if (!std::filesystem::is_regular_file(path)
+ || !path.has_extension()
+ || path.extension() != ".license")
+ continue;
+
+ std::ifstream license(path);
+ if (!license.is_open())
+ continue;
+
+ std::cout << "\n === " << path.stem().string()
+ << " license notice ===\n\n"
+ << license.rdbuf()
+ << "\n === " << path.stem().string()
+ << " license notice ===\n"
+ << std::endl;
+ }
+ }
+ }
+ else
+ {
+ // Replace the traditional calls to `vm.store()' and `vm.notify()'.
+ for (const auto& i : parsed.options)
+ {
+ auto option = parsed.description->find(i.string_key, false);
+
+ po::variable_value v;
+ option.semantic()->parse(v.value(), i.value, true);
+ option.semantic()->notify(v.value());
+ }
+
+ // If no input file is given, throw.
+ if (input_file.size() == 0)
+ throw po::error("no file name");
+ }
+ }
+ catch (const po::error& e)
+ {
+ std::cerr << program_name << ": " << e.what()
+ << "\ntc [OPTIONS...] INPUT-FILE\n"
+ "Try `tc --help' or `tc --usage' for more information.\n";
+ throw std::invalid_argument("command line parsing error");
+ }
+ catch (const std::invalid_argument& e)
+ {
+ throw;
+ }
+
+ char* input_file_ = nullptr;
+ if (!input_file.empty())
+ {
+ input_file_ = new char[input_file.size() + 1];
+ strcpy(input_file_, input_file.c_str());
+ }
+ return input_file_;
+ }
+
+ // Display registered Tasks.
+ std::ostream& TaskRegister::print_task_list(std::ostream& ostr)
+ {
+ ostr << "List of registered tasks:\n";
+ for (const tasks_by_name_type::value_type& i : task_list_)
+ ostr << "\t* " << i.first << '\n';
+ return ostr << std::endl;
+ }
+
+ // Dump task graph.
+ std::ostream& TaskRegister::print_task_graph(std::ostream& ostr)
+ {
+ ostr << "/* Task graph */\n"
+ << "digraph Tasks {\n"
+ << " node [shape=box, fontsize=14]\n"
+ // Preserve the order of the children.
+ << " graph [ordering=out]\n";
+
+ for (const tasks_by_name_type::value_type& i : task_list_)
+ {
+ const Task& task = *i.second;
+ if (dynamic_cast<const DisjunctiveTask*>(&task))
+ ostr << " \"" << task.name_get() << "\" [shape=diamond]\n";
+ ostr << " \"" << task.name_get() << "\"";
+ if (task.dependencies_get().size())
+ {
+ ostr << " -> {";
+ for (const std::string& s : task.dependencies_get())
+ ostr << " \"" << s << "\"";
+ ostr << " } ";
+ }
+ ostr << '\n';
+ }
+
+ return ostr << "}\n";
+ }
+
+ // Display registered Tasks execution order.
+ std::ostream& TaskRegister::print_task_order(std::ostream& ostr)
+ {
+ ostr << "List of Task Order:\n";
+ for (const Task* t : task_order_)
+ ostr << "\t* " << t->name_get() << std::endl;
+ return ostr << std::endl;
+ }
+
+ // Execute tasks, checking dependencies.
+ void TaskRegister::execute()
+ {
+ // FIXME: should be the only one to call resolve_dependency.
+ for (const Task* t : task_order_)
+ {
+ std::string pref(t->module_name_get());
+ if (!pref.empty())
+ pref = pref[0] + std::string(": ");
+ timer_.push(pref + t->name_get());
+ t->execute();
+ timer_.pop(pref + t->name_get());
+ }
+ }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/task-register.hh b/tiger-compiler/src/task/task-register.hh
new file mode 100644
index 0000000..6608e02
--- /dev/null
+++ b/tiger-compiler/src/task/task-register.hh
@@ -0,0 +1,118 @@
+/**
+ ** \file task/task-register.hh
+ ** \brief Declare the task::TaskRegister class.
+ **
+ */
+
+#pragma once
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <boost/program_options.hpp>
+
+#include <misc/timer.hh>
+#include <task/fwd.hh>
+
+namespace task
+{
+ /** \brief Register Tasks.
+
+ The purpose of the TaskRegister class is to collect tasks
+ and organize their execution using their dependencies (like 'make').
+ For modeling details, see Design Patterns: singleton.
+ */
+ class TaskRegister
+ {
+ // Make it non-copyable.
+ TaskRegister(const TaskRegister&) = delete;
+ TaskRegister& operator=(const TaskRegister&) = delete;
+
+ /// \name Ctor & dtor.
+ private:
+ /// Construct a TaskRegister.
+ TaskRegister() = default;
+
+ public:
+ /// Access to the unique TaskRegister.
+ static TaskRegister& instance();
+
+ /** \name Tasks registering.
+ ** \{ */
+ /// Register task \a task.
+ void register_task(const SimpleTask& task);
+ void register_task(const ArgumentTask& task);
+ /// Register the task \a task_name for execution.
+ void enable_task(const std::string& task_name);
+
+ /// Return the number of tasks to execute.
+ int nb_of_task_to_execute_get();
+ /** \} */
+
+ /// \name Task reordering.
+ private:
+ /** \brief Resolve dependencies between tasks.
+ **
+ ** Resolve dependencies on tasks registered for execution.
+ ** Make a depth first search of implicit tasks graph,
+ ** check cycles and build an ordered list of tasks. */
+ void resolve_dependencies(const Task& task);
+
+ public:
+ /** \brief Parse \a argv and determine which tasks to execute.
+ **
+ ** Use boost::program_options. */
+ char* parse_arg(int argc, char* argv[]);
+
+ /** \name Display TaskRegister content.
+ ** \{ */
+ /// Display registered Tasks.
+ std::ostream& print_task_list(std::ostream& ostr);
+ /// Display task graph.
+ std::ostream& print_task_graph(std::ostream& ostr);
+ /// Display registered Tasks execution order.
+ std::ostream& print_task_order(std::ostream& ostr);
+
+ /** \name Using registered Tasks.
+ ** \{ */
+ /// Execute tasks, checking dependencies.
+ void execute();
+ /** \} */
+
+ /** \name Time management.
+ ** \{ */
+ /// Access to the tasks timer.
+ const misc::timer& timer_get() const;
+ /** \} */
+
+ /// Ordered vector of tasks.
+ using tasks_list_type = std::vector<const Task*>;
+
+ private:
+ /// Associate a task name to a task.
+ using tasks_by_name_type = std::map<const std::string, Task const*>;
+ /// Associate a module name to a task module.
+ using indexed_module_type =
+ std::map<const std::string, boost::program_options::options_description>;
+
+ // Common code between the two overload of `register_task'.
+ indexed_module_type::iterator register_task_(const Task& task);
+
+ /// 'string to task' map.
+ tasks_by_name_type task_list_;
+
+ /// 'ordered for execution' tasks list.
+ tasks_list_type task_order_;
+
+ /// Tasks timer.
+ misc::timer timer_;
+
+ /// Task modules.
+ indexed_module_type modules_;
+ };
+
+} // namespace task
+
+#include <task/task-register.hxx>
diff --git a/tiger-compiler/src/task/task-register.hxx b/tiger-compiler/src/task/task-register.hxx
new file mode 100644
index 0000000..a72969a
--- /dev/null
+++ b/tiger-compiler/src/task/task-register.hxx
@@ -0,0 +1,15 @@
+/**
+ ** \file task/task-register.hxx
+ ** \brief Inline methods of task::TaskRegister.
+ **
+ */
+
+#pragma once
+
+#include <task/task-register.hh>
+
+namespace task
+{
+ inline const misc::timer& TaskRegister::timer_get() const { return timer_; }
+
+} // namespace task.
diff --git a/tiger-compiler/src/task/task.cc b/tiger-compiler/src/task/task.cc
new file mode 100644
index 0000000..c675ffa
--- /dev/null
+++ b/tiger-compiler/src/task/task.cc
@@ -0,0 +1,68 @@
+/**
+ ** \file task/task.cc
+ ** \brief Implementation of task::Task.
+ **
+ */
+
+#include <iostream>
+#include <iterator>
+
+#include <task/task.hh>
+
+namespace task
+{
+ Task::Task(const char* name,
+ const char* module_name,
+ const char* desc,
+ const std::string& deps)
+ : name_(normalize(name))
+ , fullname_(name_)
+ , module_name_(module_name)
+ , desc_(desc)
+ {
+ // Compute its dependencies.
+ std::string::size_type start = 0;
+ while (start < deps.size())
+ {
+ std::string::size_type end = deps.find(' ', start);
+ if (end > deps.size())
+ end = deps.size();
+ dependencies_.emplace_back(normalize(deps.substr(start, end - start)));
+ start = end + 1;
+ }
+
+ // See if it has a short option, such as "h|help".
+ if (name_.size() >= 2 && name_[1] == '|')
+ {
+ fullname_ += ',';
+ fullname_ += name_[0];
+ name_.erase(0, 2);
+ fullname_.erase(0, 2);
+ }
+ }
+
+ Task::deps_type Task::resolve_dependencies(tasks_list_type&) const
+ {
+ // By default, consider that all dependencies are required.
+ return dependencies_;
+ }
+
+ /// Display dependencies of this task.
+ void Task::print_dependencies() const
+ {
+ std::cout << "Dependencies for task " << name_ << ":\n";
+ for (const std::string& s : dependencies_)
+ std::cout << "\t" << s << '\n';
+ std::cout << std::flush;
+ }
+
+ std::string Task::normalize(const std::string& task_name)
+ {
+ std::string normalized_name;
+ std::ranges::replace_copy(
+ task_name, std::inserter(normalized_name, normalized_name.begin()), '_',
+ '-');
+ return normalized_name;
+ }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/task.hh b/tiger-compiler/src/task/task.hh
new file mode 100644
index 0000000..6081f1f
--- /dev/null
+++ b/tiger-compiler/src/task/task.hh
@@ -0,0 +1,103 @@
+/**
+ ** \file task/task.hh
+ ** \brief Declare the task::Task class.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include <task/task-register.hh>
+
+namespace task
+{
+ /** \brief A function bound to a command line option.
+
+ The purpose of the Task class is to abstract the execution of a module
+ and the tasks on which its execution depends. This is an implementation
+ of the Command Design Pattern.
+ */
+ class Task
+ {
+ /** \name Ctor & dtor. */
+ /** \{ */
+ public:
+ /** \brief Construct a Task.
+
+ \param name name of this task (used for long option)
+ \param module_name name of the module to which the task belongs.
+ \param desc description of this task
+ \param deps optional space separated list of task names
+ */
+ Task(const char* name,
+ const char* module_name,
+ const char* desc,
+ const std::string& deps = "");
+
+ /// Destroy this Task.
+ virtual ~Task() = default;
+ /** \}*/
+
+ /** \name Abstract methods.
+ ** \{ */
+ public:
+ /// Execute this task.
+ virtual void execute() const = 0;
+ /** \} */
+
+ using tasks_list_type = TaskRegister::tasks_list_type;
+
+ using deps_type = std::vector<std::string>;
+
+ virtual deps_type resolve_dependencies(tasks_list_type& active_tasks) const;
+
+ /** \name Accessors.
+ ** \{ */
+ public:
+ /** Access to 'name'.
+
+ 'const char*' is preferred to 'std::string' because TaskRegister
+ calls function requiring 'const char*'.
+ The use of 'std::string::c_str()' is so forbidden and a call to
+ 'strdup(std::string::c_str())' would imply dummy memory leaks. */
+ const char* name_get() const;
+
+ /// Access to 'module_name'.
+ const char* module_name_get() const;
+
+ /// Access to 'fullname'.
+ const char* fullname_get() const;
+
+ /// Access to 'desc'.
+ const char* desc_get() const;
+
+ /// Access to tasks dependencies.
+ const deps_type& dependencies_get() const;
+
+ /** \} */
+
+ public:
+ /// Display dependencies of this task .
+ void print_dependencies() const;
+
+ public:
+ /// Normalize the name of a task.
+ static std::string normalize(const std::string& task_name);
+
+ protected:
+ /// Task name.
+ std::string name_;
+ /// Task name plus short name.
+ std::string fullname_;
+ /// Module name to which the task belongs.
+ const char* module_name_;
+ /// A short description of this task (displayed in program usage).
+ const char* desc_;
+ /// Contains the name of the tasks on which this one depends.
+ deps_type dependencies_;
+ };
+
+} // namespace task
+
+#include <task/task.hxx>
diff --git a/tiger-compiler/src/task/task.hxx b/tiger-compiler/src/task/task.hxx
new file mode 100644
index 0000000..02fad0e
--- /dev/null
+++ b/tiger-compiler/src/task/task.hxx
@@ -0,0 +1,24 @@
+/**
+ ** \file task/task.hxx
+ ** \brief Inline methods for task/task.hh.
+ */
+#pragma once
+
+#include <task/task.hh>
+
+namespace task
+{
+ inline const char* Task::name_get() const { return name_.c_str(); }
+
+ inline const char* Task::module_name_get() const { return module_name_; }
+
+ inline const char* Task::fullname_get() const { return fullname_.c_str(); }
+
+ inline const char* Task::desc_get() const { return desc_; }
+
+ inline const Task::deps_type& Task::dependencies_get() const
+ {
+ return dependencies_;
+ }
+
+} // namespace task
diff --git a/tiger-compiler/src/task/tasks.cc b/tiger-compiler/src/task/tasks.cc
new file mode 100644
index 0000000..33eb35f
--- /dev/null
+++ b/tiger-compiler/src/task/tasks.cc
@@ -0,0 +1,28 @@
+/**
+ ** \file task/tasks.cc
+ ** \brief Task module related tasks.
+ */
+
+#include <iostream>
+
+#include <common.hh>
+#include <task/task-register.hh>
+#define DEFINE_TASKS 1
+#include <task/tasks.hh>
+#undef DEFINE_TASKS
+
+// Task module related tasks' implementation.
+namespace task::tasks
+{
+ void tasks_list() { TaskRegister::instance().print_task_list(std::cout); }
+
+ void tasks_graph() { TaskRegister::instance().print_task_graph(std::cout); }
+
+ void tasks_selection()
+ {
+ TaskRegister::instance().print_task_order(std::cout);
+ }
+
+ void time_report() { task_timer.dump_on_destruction(std::cerr); }
+
+} // namespace task::tasks
diff --git a/tiger-compiler/src/task/tasks.hh b/tiger-compiler/src/task/tasks.hh
new file mode 100644
index 0000000..b18943d
--- /dev/null
+++ b/tiger-compiler/src/task/tasks.hh
@@ -0,0 +1,23 @@
+/**
+ ** \file task/tasks.hh
+ ** \brief Task module related tasks.
+ */
+
+#pragma once
+
+#include <task/libtask.hh>
+
+namespace task::tasks
+{
+ TASK_GROUP("0. Tasks");
+
+ /// List all the existing tasks.
+ TASK_DECLARE("task-list", "list registered tasks", tasks_list, "");
+ /// Dump task graph.
+ TASK_DECLARE("task-graph", "show task graph", tasks_graph, "");
+ /// List the selected tasks in order.
+ TASK_DECLARE("task-selection", "list tasks to be run", tasks_selection, "");
+ /// Ask for a time report at the end of the execution.
+ TASK_DECLARE("time-report", "report execution times", time_report, "");
+
+} // namespace task::tasks
diff --git a/tiger-compiler/src/tc.cc b/tiger-compiler/src/tc.cc
new file mode 100644
index 0000000..0453714
--- /dev/null
+++ b/tiger-compiler/src/tc.cc
@@ -0,0 +1,53 @@
+/**
+ ** \file tc.cc
+ ** \brief The compiler driver.
+ */
+
+#include <cstdlib>
+#include <exception>
+#include <iostream>
+#include <stdexcept>
+#include <common.hh>
+
+#include <task/task-register.hh>
+
+int main(int argc, char** argv)
+{
+ program_name = argv[0];
+
+ try
+ {
+ task_timer.start();
+ task_timer.push("rest");
+
+ filename = task::TaskRegister::instance().parse_arg(argc, argv);
+ task_error().exit_on_error();
+
+ // If `help', `usage' or `version' is called, just exit.
+ if (filename == nullptr)
+ return 0;
+
+ if (task::TaskRegister::instance().nb_of_task_to_execute_get() == 0)
+ task::TaskRegister::instance().enable_task("parse");
+
+ task::TaskRegister::instance().execute();
+ task_timer << task::TaskRegister::instance().timer_get();
+ task_error().exit_on_error();
+ }
+
+ // Required to enable stack unwinding.
+ catch (const std::invalid_argument& e)
+ {
+ return 64;
+ }
+ catch (const std::runtime_error& e)
+ {
+ if (e.what() != std::string(""))
+ std::cerr << e.what() << '\n';
+ }
+ catch (const misc::error& e)
+ {
+ std::cerr << e;
+ return e.status_get_value();
+ }
+}
diff --git a/tiger-compiler/src/testsuite/libtestsuite.cc b/tiger-compiler/src/testsuite/libtestsuite.cc
new file mode 100644
index 0000000..86a5661
--- /dev/null
+++ b/tiger-compiler/src/testsuite/libtestsuite.cc
@@ -0,0 +1,30 @@
+/**
+ ** \file testsuite/libtestsuite.cc
+ ** \brief Functions exported by the testsuite module.
+ */
+
+#include <testsuite/libtestsuite.hh>
+
+#include <testsuite/tests-collector.hh>
+#include <testsuite/testsuite-generator.hh>
+
+namespace testsuite
+{
+
+ std::vector<const ast::FunctionDec*>
+ find_program_tests(const ast::ChunkList& program)
+ {
+ TestsCollector tests_collector;
+
+ tests_collector(program);
+
+ return tests_collector.tests_get();
+ }
+
+ ast::ChunkInterface*
+ create_testsuite_runtime(const std::vector<const ast::FunctionDec*>& tests)
+ {
+ return generate_testsuite_runtime(tests);
+ }
+
+} // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/libtestsuite.hh b/tiger-compiler/src/testsuite/libtestsuite.hh
new file mode 100644
index 0000000..2c42e04
--- /dev/null
+++ b/tiger-compiler/src/testsuite/libtestsuite.hh
@@ -0,0 +1,41 @@
+/**
+ ** \file testsuite/libtestsuite.hh
+ ** \brief Declare functions and variables exported by testsuite module.
+ */
+
+#pragma once
+
+#include <ast/function-dec.hh>
+
+namespace testsuite
+ {
+
+ /**
+ * Find all the tests functions of a program and return references to each of
+ * them.
+ *
+ * A function is considered a test function if it has the following
+ * properties :\n
+ * - It is located at the first level of a program file\n
+ * - Its name starts with test_*
+ *
+ * @param program the program to analyse
+ * @return a vector containing a reference to each test function
+ */
+ std::vector<const ast::FunctionDec*>
+ find_program_tests(const ast::ChunkList& program);
+
+ /**
+ * Create a testsuite runtime, which runs each function referenced in the
+ * vector.
+ *
+ * The return tree may then be appended to the main program AST list to be
+ * compiled along with the rest of this latter.
+ *
+ * @param tests the tests to run
+ * @return an AST tree describing the resulting testsuite runtime
+ */
+ ast::ChunkInterface*
+ create_testsuite_runtime(const std::vector<const ast::FunctionDec*>& tests);
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/local.am b/tiger-compiler/src/testsuite/local.am
new file mode 100644
index 0000000..0cd44bb
--- /dev/null
+++ b/tiger-compiler/src/testsuite/local.am
@@ -0,0 +1,15 @@
+## testsuite module
+
+src_libtc_la_SOURCES += \
+ %D%/libtestsuite.hh \
+ %D%/libtestsuite.cc
+
+src_libtc_la_SOURCES += \
+ %D%/tests-collector.hh %D%/tests-collector.cc \
+ %D%/testsuite-generator.hh %D%/testsuite-generator.cc
+
+
+## tasks
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
+
diff --git a/tiger-compiler/src/testsuite/tasks.cc b/tiger-compiler/src/testsuite/tasks.cc
new file mode 100644
index 0000000..c7f1164
--- /dev/null
+++ b/tiger-compiler/src/testsuite/tasks.cc
@@ -0,0 +1,49 @@
+/**
+ ** \file testsuite/tasks.hh
+ ** \brief Testsuite module related tasks' implementation.
+ */
+
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+#include <testsuite/libtestsuite.hh>
+
+#include <ast/tasks.hh>
+#include <parse/tasks.hh>
+#define DEFINE_TASKS 1
+#include <testsuite/tasks.hh>
+#undef DEFINE_TASKS
+
+namespace testsuite::tasks
+ {
+
+ void add_testsuite_runtime()
+ {
+ /**
+ * A testsuite being a series of function declaration, the prelude is
+ * not included by default. As such, we need to insert it on our own
+ * within the AST.
+ */
+ parse::Tweast new_program;
+
+ const auto prelude = parse::parse_prelude();
+ const auto current_program = ast::tasks::the_program.release();
+
+ const auto tests = find_program_tests(*current_program);
+
+ const auto testsuite_runtime = create_testsuite_runtime(tests);
+
+ current_program->emplace_back(testsuite_runtime);
+
+ if (prelude != nullptr)
+ {
+ new_program << prelude;
+ }
+
+ new_program << current_program;
+
+ const auto new_ast = parse::parse(new_program);
+
+ ast::tasks::the_program = std::unique_ptr<ast::ChunkList>{new_ast};
+ }
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/tasks.hh b/tiger-compiler/src/testsuite/tasks.hh
new file mode 100644
index 0000000..463e7e0
--- /dev/null
+++ b/tiger-compiler/src/testsuite/tasks.hh
@@ -0,0 +1,21 @@
+/**
+ ** \file testsuite/tasks.hh
+ ** \brief Testsuite module related tasks.
+ */
+
+#pragma once
+
+#include <task/libtask.hh>
+
+namespace testsuite::tasks
+ {
+
+ TASK_GROUP("Testsuite");
+
+ TASK_DECLARE("testsuite",
+ "run all declared test_* functions within a testsuite runtime "
+ "(preludes included automatically, _main must not be set)",
+ add_testsuite_runtime,
+ "parse");
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/tests-collector.cc b/tiger-compiler/src/testsuite/tests-collector.cc
new file mode 100644
index 0000000..b3365b2
--- /dev/null
+++ b/tiger-compiler/src/testsuite/tests-collector.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file testsuite/tests-collector.cc
+ ** \brief Implementation of testsuite::TestsCollector.
+ */
+
+#include <testsuite/tests-collector.hh>
+
+namespace testsuite
+ {
+
+ void TestsCollector::operator()(const ast::FunctionDec& e)
+ {
+ if (is_a_test_function(e))
+ {
+ tests_.push_back(&e);
+ }
+ }
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/tests-collector.hh b/tiger-compiler/src/testsuite/tests-collector.hh
new file mode 100644
index 0000000..d7e3ef1
--- /dev/null
+++ b/tiger-compiler/src/testsuite/tests-collector.hh
@@ -0,0 +1,53 @@
+/**
+ ** \file testsuite/tests-collector.hh
+ ** \brief Declaration of testsuite::TestsCollector.
+ */
+
+#pragma once
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+
+namespace testsuite
+ {
+
+ class TestsCollector
+ : public ast::DefaultConstVisitor
+ , public ast::NonObjectConstVisitor
+ , public ast::NonAssertConstVisitor
+ {
+
+ public:
+ using super_type = ast::DefaultConstVisitor;
+ using super_type::operator();
+
+ TestsCollector() = default;
+
+ /**
+ * Return all the functions recognized as test functions by the
+ * visitor.
+ *
+ * @return a vector of references to FunctionDec nodes that represents
+ * test functions
+ */
+ inline std::vector<const ast::FunctionDec*>& tests_get();
+
+ void operator()(const ast::FunctionDec& e) override;
+
+ protected:
+ // The tests identified by the visitor
+ std::vector<const ast::FunctionDec*> tests_;
+
+ /**
+ * Return whether the function declaration is identified as a test
+ * function.
+ * @param node an ast node
+ * @return true if the node references a valid test function, false
+ * otherwise
+ */
+ inline bool is_a_test_function(const ast::FunctionDec& node) ;
+ };
+
+ } // namespace testsuite
+
+#include <testsuite/tests-collector.hxx>
diff --git a/tiger-compiler/src/testsuite/tests-collector.hxx b/tiger-compiler/src/testsuite/tests-collector.hxx
new file mode 100644
index 0000000..9570dc1
--- /dev/null
+++ b/tiger-compiler/src/testsuite/tests-collector.hxx
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <testsuite/tests-collector.hh>
+
+namespace testsuite
+ {
+
+ inline std::vector<const ast::FunctionDec*>& TestsCollector::tests_get()
+ {
+ return tests_;
+ }
+
+ inline bool
+ TestsCollector::is_a_test_function(const ast::FunctionDec& node)
+ {
+ return node.name_get().get().starts_with("test_")
+ && node.formals_get().empty();
+ }
+
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/testsuite-generator.cc b/tiger-compiler/src/testsuite/testsuite-generator.cc
new file mode 100644
index 0000000..87ca479
--- /dev/null
+++ b/tiger-compiler/src/testsuite/testsuite-generator.cc
@@ -0,0 +1,143 @@
+/**
+ ** \file testsuite/testsuite-generator.cc
+ ** \brief Implementation of testsuite::TestsuiteGenerator.
+ */
+
+#include <testsuite/testsuite-generator.hh>
+
+#include <ast/function-dec.hh>
+#include <parse/libparse.hh>
+#include <parse/tweast.hh>
+
+namespace testsuite
+ {
+
+ /**
+ * Generate a function which calls the provided test with no arguments.
+ * @param definitions the testsuite definition
+ * @param test_reference the function to create a unit test for
+ * @return the new function's name
+ */
+ static std::string add_test_to_testsuite(
+ parse::Tweast& definitions,
+ const ast::FunctionDec* test_reference)
+ {
+ const std::string test_name = test_reference->name_get().get();
+ const std::string callback_name = "testsuite_" + test_name;
+
+ definitions << "function " + callback_name + "() = "
+ "let "
+ "var child_pid := -1 "
+ "var status_code := -1 "
+ "var exit_code := -1 "
+ "in "
+ "child_pid := fork(); "
+ "if (child_pid = -1) then ( "
+ "print_err(\"could not run child process. skipping test\"); "
+ "skipped := skipped + 1 "
+ ") "
+ "else if (child_pid = 0) then ( "
+ + test_name + "(); "
+ "exit(0) "
+ ") "
+ "else ( "
+ "status_code := wait_pid(child_pid); "
+
+ "if (status_code = 0) then ( "
+ "print(\" o \") "
+ ") "
+ "else ("
+ "print(\" x \") "
+ "); "
+
+ "print(\"" + test_name + " test \"); "
+ "if (status_code = 0) then ( "
+ "print(\"passed\"); "
+ "passed := passed + 1 "
+ ") "
+ "else ("
+ "print(\"failed with \"); "
+ "exit_code := get_exit_code(status_code); "
+ "if (status_code = 6) then "
+ "print(\"assertion failure\") "
+ "else if (status_code = 8) then "
+ "print(\"illegal instruction\") "
+ "else if (status_code = 11) then "
+ "print(\"segmentation fault\") "
+ "else if (exit_code = 120) then "
+ "print(\"runtime failure\") "
+ "else ( "
+ "print(\"other error code \"); "
+ "print_int(exit_code) "
+ "); "
+ "failed := failed + 1"
+ "); "
+ "print(\"\\n\"); "
+ "flush() "
+ ") "
+ "end ";
+
+ return callback_name;
+ }
+
+ /**
+ * Build the testsuite runtime, parse the result and return the AST.
+ * @param definitions the function declarations to add within the runtime
+ * @param names the names of the tests to run, once declared
+ * @return the resulting AST
+ */
+ static ast::ChunkInterface* build_testsuite(
+ const parse::Tweast& definitions,
+ const std::vector<std::string>& names)
+ {
+ parse::Tweast runtime;
+
+ runtime << "function _main() = let "
+ "var skipped := 0 "
+ "var passed := 0 "
+ "var failed := 0 ";
+
+ runtime << definitions.input_get();
+
+ runtime << " in "
+ "print(\"====================== Begin testing =====================\\n\\n\"); ";
+
+ for (const std::string& test : names)
+ {
+ runtime << test << "(); ";
+ }
+
+ runtime << "print(\"\\n=============== TC-RITERION testing result ===============\\n\"); "
+ "print(\" o Passed: \"); "
+ "print_int(passed); "
+ "print(\"\\n o Failed: \"); "
+ "print_int(failed); "
+ "if (skipped > 0) then ( "
+ "print(\"\\n o Skipped: \"); "
+ "print_int(skipped) "
+ "); "
+ "print(\"\\n==========================================================\\n\"); "
+ "flush() "
+ "end";
+
+ return parse::parse_chunks(runtime);
+ }
+
+ ast::ChunkInterface*
+ generate_testsuite_runtime(
+ const std::vector<const ast::FunctionDec*>& tests)
+ {
+ parse::Tweast declarations;
+ std::vector<std::string> test_names;
+
+ for (const auto test : tests)
+ {
+ const std::string test_name =
+ add_test_to_testsuite(declarations, test);
+ test_names.push_back(test_name);
+ }
+
+ return build_testsuite(declarations, test_names);
+ }
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/testsuite/testsuite-generator.hh b/tiger-compiler/src/testsuite/testsuite-generator.hh
new file mode 100644
index 0000000..c7d9424
--- /dev/null
+++ b/tiger-compiler/src/testsuite/testsuite-generator.hh
@@ -0,0 +1,23 @@
+/**
+ ** \file testsuite/testsuite-generator.hh
+ ** \brief Declaration of testsuite::TestsuiteGenerator.
+ */
+
+#pragma once
+
+#include <ast/chunk-interface.hh>
+
+namespace testsuite
+ {
+
+ /**
+ * Generate a new AST providing a _main function. This main function
+ * calls each provided function within the context of a testsuite runtime.
+ *
+ * @param tests a vector referencing every test to run within the testsuite
+ * @return a new AST which can be appened to the main program
+ */
+ ast::ChunkInterface*
+ generate_testsuite_runtime(const std::vector<const ast::FunctionDec*>& tests);
+
+ } // namespace testsuite
diff --git a/tiger-compiler/src/type/README.txt b/tiger-compiler/src/type/README.txt
new file mode 100644
index 0000000..12bc011
--- /dev/null
+++ b/tiger-compiler/src/type/README.txt
@@ -0,0 +1,92 @@
+* README
+
+Hierarchy of types for the Tiger language, with (most of) their
+interfaces.
+
+
+ostream& operator<<(ostream& ostr, const Type& t)
+bool operator==(const Type& lhs, const Type& rhs);
+bool operator!=(const Type& lhs, const Type& rhs);
+
+/Type/
+ virtual ~Type() {}
+ virtual const Type& actual() const;
+ virtual bool compatible_with(const Type& other) const;
+ virtual void accept(ConstVisitor& v) const;
+ virtual void accept(Visitor& v);
+
+ Nil
+ bool compatible_with(const Type& other) const override;
+ const Type* record_type_get() const;
+ void set_record_type(const Type& type) const;
+
+ Void
+
+ Int
+
+ String
+
+ Named(misc::symbol name, const Type* type)
+ const Type* type_get() const;
+ void type_set(const Type *type) const;
+ misc::symbol name_get() const;
+ void name_set(misc::symbol name);
+ const Type& actual() const override;
+ const bool sound() const;
+ bool compatible_with(const Type& other) const override;
+
+ Array(const Type& type)
+ const Type& type_get() const;
+
+ Record()
+ const Type* field_type(misc::symbol key) const;
+ int field_index(misc::symbol key) const;
+ const list<Field> fields_get() const;
+ void field_add(const Field& field);
+ void field_add(misc::symbol name, const Type& type);
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ Class(const Class* super = nullptr)
+ const Type* attr_type(misc::symbol key) const;
+ const Type* meth_type(misc::symbol key) const;
+ const attrs_type& attrs_get() const;
+ const meths_type& meths_get() const;
+ const Attribute* attr_find(misc::symbol key) const;
+ const Attribute* owner_attr_find(misc::symbol key) const;
+ const Method* owned_meth_find(misc::symbol key) const;
+ void attr_add(const Attribute& attr);
+ void attr_add(const VarDec* def);
+ void meth_add(const Method* method);
+ bool has_data() const;
+ unsigned id_get() const;
+ const Class* super_get() const;
+ void super_set(const Class* type);
+ const subclasses_type& subclasses_get() const;
+ void subclass_add(const Class* subclass) const;
+ void subclasses_clear() const;
+ const Class* common_root(const Class& other) const;
+ bool sound() const;
+ static const Class& object_instance();
+
+ Function(const Record* formals, const Type& result)
+
+ Method(misc::symbol name, const Class* owner, const Record* formals,
+ const Type& result, MethodDec* def)
+ misc::symbol name_get() const;
+ const Class* owner_get() const;
+ const Type& type_get() const;
+ const MethodDec* def_get() const;
+ MethodDec* def_get();
+ void name_set(misc::symbol name);
+ void def_set(MethodDec* def);
+
+Field(misc::symbol name, const Type& type)
+ misc::symbol name_get() const;
+ const Type& type_get() const;
+
+Attribute(const ast::VarDec* def)
+ misc::symbol name_get() const;
+ const Type& type_get() const;
+ const ast::VarDec* def_get() const;
+ void def_set(const ast::VarDec* def);
diff --git a/tiger-compiler/src/type/array.cc b/tiger-compiler/src/type/array.cc
new file mode 100644
index 0000000..1cf51ca
--- /dev/null
+++ b/tiger-compiler/src/type/array.cc
@@ -0,0 +1,28 @@
+/**
+ ** \file type/array.cc
+ ** \brief Implementation for type/array.hh.
+ */
+
+#include <type/array.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+
+ // FIXME DONE: Some code was deleted here.
+
+ Array::Array(const Type* const element_type)
+ : element_type_(element_type)
+ {}
+
+ void Array::accept(ConstVisitor& v) const
+ {
+ v(*this);
+ }
+
+ void Array::accept(Visitor& v)
+ {
+ v(*this);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/array.hh b/tiger-compiler/src/type/array.hh
new file mode 100644
index 0000000..417eeee
--- /dev/null
+++ b/tiger-compiler/src/type/array.hh
@@ -0,0 +1,30 @@
+/**
+ ** \file type/array.hh
+ ** \brief The class Array.
+ */
+#pragma once
+
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /// Array types.
+ class Array : public Type
+ {
+ // FIXME DONE: Some code was deleted here.
+ public:
+ Array(const Type* element_type);
+
+ void accept(ConstVisitor& v) const override;
+ void accept(Visitor& v) override;
+
+ inline const Type* get_element_type() const;
+
+ protected:
+ const Type* const element_type_;
+ };
+
+} // namespace type
+
+#include <type/array.hxx>
diff --git a/tiger-compiler/src/type/array.hxx b/tiger-compiler/src/type/array.hxx
new file mode 100644
index 0000000..1ed65da
--- /dev/null
+++ b/tiger-compiler/src/type/array.hxx
@@ -0,0 +1,18 @@
+/**
+ ** \file type/array.hxx
+ ** \brief Inline methods for type::Array.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/array.hh>
+
+namespace type
+{
+ // FIXME DONE: Some code was deleted here.
+ inline const Type* Array::get_element_type() const
+ {
+ return element_type_;
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/attribute.cc b/tiger-compiler/src/type/attribute.cc
new file mode 100644
index 0000000..bfbe537
--- /dev/null
+++ b/tiger-compiler/src/type/attribute.cc
@@ -0,0 +1,16 @@
+/**
+ ** \file type/attribute.cc
+ ** \brief Implementation for type/attribute.hh.
+ */
+
+#include <ostream>
+
+#include <type/attribute.hh>
+
+namespace type
+{
+ Attribute::Attribute(const ast::VarDec* def)
+ : def_(def)
+ {}
+
+} // namespace type
diff --git a/tiger-compiler/src/type/attribute.hh b/tiger-compiler/src/type/attribute.hh
new file mode 100644
index 0000000..d252da4
--- /dev/null
+++ b/tiger-compiler/src/type/attribute.hh
@@ -0,0 +1,44 @@
+/**
+ ** \file type/attribute.hh
+ ** \brief The class Attribute (of a class type).
+ */
+#pragma once
+
+#include <ast/var-dec.hh>
+
+namespace type
+{
+
+ /** \brief The base object for Class attributes.
+ **
+ ** Very much like Named, but it is *not* a Type. */
+ class Attribute
+ {
+ /** \name Constructor.
+ ** \{ */
+ public:
+ /** \brief Construct a Attribute.
+ ** \param def attribute's definition site.*/
+ explicit Attribute(const ast::VarDec* def);
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ public:
+ /// Return the attribute's name.
+ misc::symbol name_get() const;
+ /// Return the attribute's type.
+ const Type& type_get() const;
+ /// Return attribute's definition site.
+ const ast::VarDec* def_get() const;
+ /// Set the attribute's definition site.
+ void def_set(const ast::VarDec* def);
+ /** \} */
+
+ private:
+ const ast::VarDec* def_;
+ };
+
+} // namespace type
+
+#include <type/attribute.hxx>
diff --git a/tiger-compiler/src/type/attribute.hxx b/tiger-compiler/src/type/attribute.hxx
new file mode 100644
index 0000000..e59177d
--- /dev/null
+++ b/tiger-compiler/src/type/attribute.hxx
@@ -0,0 +1,25 @@
+/**
+ ** \file type/attribute.hxx
+ ** \brief Inline methods for type::Attribute.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+
+namespace type
+{
+ inline misc::symbol Attribute::name_get() const { return def_->name_get(); }
+
+ inline const Type& Attribute::type_get() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ precondition(def_->type_get() != nullptr);
+
+ return *def_->type_get();
+ }
+
+ inline const ast::VarDec* Attribute::def_get() const { return def_; }
+
+ inline void Attribute::def_set(const ast::VarDec* def) { def_ = def; }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/builtin-types.cc b/tiger-compiler/src/type/builtin-types.cc
new file mode 100644
index 0000000..7ea70ad
--- /dev/null
+++ b/tiger-compiler/src/type/builtin-types.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file type/builtin-types.cc
+ ** \brief Implementation for type/builtin-types.hh.
+ */
+
+#include <ostream>
+
+#include <type/builtin-types.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ // FIXME DONE: Some code was deleted here (Int, String, Void).
+ void Int::accept(ConstVisitor& v) const { v(instance()); }
+ void Int::accept(Visitor& v) { v(instance()); }
+
+ void Void::accept(ConstVisitor& v) const { v(instance()); }
+ void Void::accept(Visitor& v) { v(instance()); }
+
+ void String::accept(ConstVisitor& v) const { v(instance()); }
+ void String::accept(Visitor& v) { v(instance()); }
+} // namespace type
diff --git a/tiger-compiler/src/type/builtin-types.hh b/tiger-compiler/src/type/builtin-types.hh
new file mode 100644
index 0000000..40295eb
--- /dev/null
+++ b/tiger-compiler/src/type/builtin-types.hh
@@ -0,0 +1,40 @@
+/**
+ ** \file type/builtin-types.hh
+ ** \brief The classes Int, String, Void.
+ */
+#pragma once
+
+#include <misc/singleton.hh>
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ // FIXME DONE: Some code was deleted here (Other types : Int, String, Void).
+
+ class Int
+ : public Type
+ , public misc::Singleton<Int>
+ {
+ public:
+ void accept(ConstVisitor& v) const override;
+ void accept(Visitor& v) override;
+ };
+ class Void
+ : public Type
+ , public misc::Singleton<Void>
+ {
+ public:
+ void accept(ConstVisitor& v) const override;
+ void accept(Visitor& v) override;
+ };
+ class String
+ : public Type
+ , public misc::Singleton<String>
+ {
+ public:
+ void accept(ConstVisitor& v) const override;
+ void accept(Visitor& v) override;
+ };
+
+} // namespace type
diff --git a/tiger-compiler/src/type/class.cc b/tiger-compiler/src/type/class.cc
new file mode 100644
index 0000000..a1876d3
--- /dev/null
+++ b/tiger-compiler/src/type/class.cc
@@ -0,0 +1,123 @@
+/**
+ ** \file type/class.cc
+ ** \brief Implementation for type/class.hh.
+ */
+
+#include <ostream>
+
+#include <misc/algorithm.hh>
+#include <type/class.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ Class::Class(const Class* super)
+ : Type()
+ , id_(fresh_id())
+ , super_(super)
+ , subclasses_()
+ {}
+
+ void Class::accept(ConstVisitor& v) const { v(*this); }
+
+ void Class::accept(Visitor& v) { v(*this); }
+
+ const Type* Class::attr_type(misc::symbol key) const
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto& attribute = std::ranges::find_if(
+ attrs_,
+ [&key] (const misc::symbol& name) { return name == key; },
+ [] (const Attribute& attr) { return attr.name_get(); }
+ );
+
+ return attribute != attrs_.end() ? &attribute->type_get() : nullptr;
+ }
+
+ const Type* Class::meth_type(misc::symbol key) const
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto& method = std::ranges::find_if(
+ meths_,
+ [&key] (const misc::symbol& name) { return name == key; },
+ [] (const Method* const meth) { return meth->name_get(); }
+ );
+
+ return method != meths_.end() ? &(*method)->type_get() : nullptr;
+ }
+
+ // FIXME DONE: Some code was deleted here (Find common super class).
+ const Class* Class::common_root(const Class& other) const
+ {
+ // temporary note: i'm tired so maybe the algo sucks ass :c
+ if (*this == other)
+ {
+ return this;
+ }
+
+ std::vector<const Class*> super_classes;
+
+ for (auto this_sc = this; this_sc != nullptr; this_sc = this_sc->super_)
+ {
+ super_classes.push_back(this_sc);
+ }
+
+ for (auto other_sc = &other; other_sc != nullptr; other_sc = other_sc->super_)
+ {
+ if (auto matching = std::ranges::find(super_classes, other_sc);
+ matching != super_classes.end())
+ {
+ return *matching;
+ }
+ }
+
+ return nullptr;
+ }
+
+ // FIXME DONE: Some code was deleted here (Super class soundness test).
+ bool Class::sound() const
+ {
+ auto reference = this;
+ std::vector<const Class*> previous;
+
+ while (reference != nullptr)
+ {
+ if (std::ranges::find(previous, reference) != previous.end())
+ {
+ return false;
+ }
+
+ previous.push_back(reference);
+ reference = reference->super_;
+ }
+
+ return true;
+ }
+
+ // FIXME DONE: Some code was deleted here (Special implementation of "compatible_with" for Class).
+ bool Class::compatible_with(const Type& other) const
+ {
+ if (Type::compatible_with(other) || dynamic_cast<const Nil*>(&other))
+ {
+ return true;
+ }
+
+ const auto ptr = dynamic_cast<const Class*>(&other);
+
+ return ptr && common_root(*ptr);
+ }
+
+ const Class& Class::object_instance()
+ {
+ // FIXME DONE: Some code was deleted here.
+ static const Class object { nullptr };
+ return object;
+ }
+
+ unsigned Class::fresh_id()
+ {
+ static unsigned counter_ = 0;
+ return counter_++;
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/class.hh b/tiger-compiler/src/type/class.hh
new file mode 100644
index 0000000..37779e8
--- /dev/null
+++ b/tiger-compiler/src/type/class.hh
@@ -0,0 +1,159 @@
+/**
+ ** \file type/class.hh
+ ** \brief The class Class.
+ */
+#pragma once
+
+#include <vector>
+
+#include <misc/symbol.hh>
+#include <type/attribute.hh>
+#include <type/method.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /** \brief Class types.
+ **
+ ** List of Attributes and Methods. */
+ class Class : public Type
+ {
+ /** \name Constructor.
+ ** \{ */
+ public:
+ /** \brief Construct a Class.
+ **
+ ** \param super Super class. */
+ explicit Class(const Class* super = nullptr);
+ /** \} */
+
+ /// \name Visitors entry point.
+ /** \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /** \} */
+
+ /** \name Attribute and Method elementary manipulation.
+ ** \{ */
+ /// \brief Return the attribute type associated to \a key.
+ ///
+ /// The search is performed throughout the super classes.
+ const Type* attr_type(misc::symbol key) const;
+ /// \brief Return the method type associated to \a key.
+ ///
+ /// The search is performed throughout the super classes.
+ const Type* meth_type(misc::symbol key) const;
+ /** \} */
+
+ /** \name Internal Attribute list manipulators.
+ ** \{ */
+ /// List of Attribute's.
+ using attrs_type = std::vector<Attribute>;
+ /// List of Method's.
+ using meths_type = std::vector<const Method*>;
+ /// List of Subclasses's.
+ using subclasses_type = std::vector<const Class*>;
+
+ /// Return the list of stored Attributes (read only).
+ const attrs_type& attrs_get() const;
+ /// Return the list of stored Methods (read only).
+ const meths_type& meths_get() const;
+
+ /// \brief Find an attribute using its name, return `nullptr' if
+ /// not found.
+ ///
+ /// The search is performed throughout the super classes.
+ const Attribute* attr_find(misc::symbol key) const;
+ /// \brief Find a method using its name, return `nullptr' if
+ /// not found.
+ ///
+ /// The search is performed throughout the super classes.
+ const Method* meth_find(misc::symbol key) const;
+
+ /// \brief Find an owned attribute using its name, return
+ /// `nullptr' if not found.
+ ///
+ /// The search is restricted to the class.
+ const Attribute* owned_attr_find(misc::symbol key) const;
+
+ /// \brief Find an owned method using its name, return `nullptr'
+ /// if not found.
+ ///
+ /// The search is restricted to the class.
+ const Method* owned_meth_find(misc::symbol key) const;
+
+ /// Add an already existing Attribute to the list.
+ void attr_add(const Attribute& attr);
+ /// Create a Attribute then add it to the list.
+ void attr_add(const ast::VarDec* def);
+
+ /// Add an already existing Method to the list.
+ void meth_add(const Method* method);
+ /** \} */
+
+ /// Does this class have actual data (i.e., owned attributes)?
+ bool has_data() const;
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the unique identifier of the class.
+ unsigned id_get() const;
+
+ /// Return the type of the super class.
+ const Class* super_get() const;
+ /// Set the type of the super class.
+ void super_set(const Class* type);
+
+ /// Return (the transitive closure of) the list of subclasses.
+ const subclasses_type& subclasses_get() const;
+
+ /// \brief Add a class to the list of subclasses.
+ ///
+ /// Although this method alters \a this, it is const, since types
+ /// are mostly manipulated as const entities.
+ void subclass_add(const Class* subclass) const;
+
+ /// \brief Erase all the subclasses.
+ ///
+ /// This method is const for the same reason as
+ /// type::Class::subclass_add.
+ void subclasses_clear() const;
+ /** \} */
+
+ /** \name Type resolution.
+ ** \{ */
+ /** \brief Find the common super class. */
+ const Class* common_root(const Class& other) const;
+
+ /** \brief Check that the definition of this class is sound,
+ ** i.e. that there is no recursive inheritance. */
+ bool sound() const;
+ /** \} */
+
+ // FIXME DONE: Some code was deleted here (Inherited methods).
+ bool compatible_with(const Type& other) const override;
+
+ /// Return the unique instance of the class type `Object'.
+ static const Class& object_instance();
+
+ private:
+ /// Return a fresh identifier.
+ static unsigned fresh_id();
+
+ /// Class unique identifier
+ unsigned id_;
+ /// Super class.
+ const Class* super_;
+ /// Sub classes.
+ mutable subclasses_type subclasses_;
+ /// Attributes list.
+ attrs_type attrs_;
+ /// Methods list.
+ meths_type meths_;
+ };
+
+} // namespace type
+
+#include <type/class.hxx>
diff --git a/tiger-compiler/src/type/class.hxx b/tiger-compiler/src/type/class.hxx
new file mode 100644
index 0000000..0a41d17
--- /dev/null
+++ b/tiger-compiler/src/type/class.hxx
@@ -0,0 +1,88 @@
+/**
+ ** \file type/class.hxx
+ ** \brief Inline methods for type::Class.
+ */
+#pragma once
+
+#include <iostream>
+
+#include <misc/algorithm.hh>
+#include <type/class.hh>
+
+namespace type
+{
+ inline const Class::attrs_type& Class::attrs_get() const { return attrs_; }
+
+ inline const Attribute* Class::attr_find(misc::symbol key) const
+ {
+ for (const Class* cur = this; cur; cur = cur->super_get())
+ {
+ const Attribute* attr = cur->owned_attr_find(key);
+ if (attr)
+ return attr;
+ }
+ return nullptr;
+ }
+
+ inline const Method* Class::meth_find(misc::symbol key) const
+ {
+ for (const Class* cur = this; cur; cur = cur->super_get())
+ {
+ const Method* meth = cur->owned_meth_find(key);
+ if (meth)
+ return meth;
+ }
+ return nullptr;
+ }
+
+ inline const Attribute* Class::owned_attr_find(misc::symbol key) const
+ {
+ for (const Attribute& at : attrs_get())
+ if (at.name_get() == key)
+ return &at;
+ return nullptr;
+ }
+
+ inline const Method* Class::owned_meth_find(misc::symbol key) const
+ {
+ for (const Method* m : meths_get())
+ if (m->name_get() == key)
+ return m;
+ return nullptr;
+ }
+
+ inline void Class::attr_add(const Attribute& attr)
+ {
+ attrs_.emplace_back(attr);
+ }
+
+ inline void Class::attr_add(const ast::VarDec* def)
+ {
+ attrs_.emplace_back(def);
+ }
+
+ inline const Class::meths_type& Class::meths_get() const { return meths_; }
+
+ inline void Class::meth_add(const Method* meth) { meths_.emplace_back(meth); }
+
+ inline bool Class::has_data() const { return !attrs_.empty(); }
+
+ inline unsigned Class::id_get() const { return id_; }
+
+ inline const Class* Class::super_get() const { return super_; }
+
+ inline void Class::super_set(const Class* super) { super_ = super; }
+
+ inline const Class::subclasses_type& Class::subclasses_get() const
+ {
+ return subclasses_;
+ }
+
+ inline void Class::subclass_add(const Class* subclass) const
+ {
+ subclasses_.emplace_back(subclass);
+ }
+
+ inline void Class::subclasses_clear() const { subclasses_.clear(); }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/default-visitor.hh b/tiger-compiler/src/type/default-visitor.hh
new file mode 100644
index 0000000..dbcfc0c
--- /dev/null
+++ b/tiger-compiler/src/type/default-visitor.hh
@@ -0,0 +1,65 @@
+/**
+ ** \file type/default-visitor.hh
+ ** \brief Traverse a Type, doing nothing.
+ */
+
+#pragma once
+
+#include <type/visitor.hh>
+
+namespace type
+{
+ template <template <typename> class Const>
+ class GenDefaultVisitor : public GenVisitor<Const>
+ {
+ public:
+ /// Convenient abbreviation.
+ template <typename Type> using const_t = typename Const<Type>::type;
+
+ /// Super class type.
+ using super_type = GenVisitor<Const>;
+
+ // Import overloaded \c operator() methods.
+ using super_type::operator();
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a default visitor.
+ GenDefaultVisitor();
+ /// Destroy a default visitor.
+ virtual ~GenDefaultVisitor();
+ /** \} */
+
+ /** \name Visit basic types.
+ ** \{ */
+ void operator()(const_t<Nil>& e) override;
+ void operator()(const_t<Void>& e) override;
+ void operator()(const_t<Int>& e) override;
+ void operator()(const_t<String>& e) override;
+ /** \} */
+
+ /** \name Visit composed types.
+ ** \{ */
+ void operator()(const_t<Named>& e) override;
+ void operator()(const_t<Array>& e) override;
+ void operator()(const_t<Record>& e) override;
+ void operator()(const_t<Class>& e) override;
+ void operator()(const_t<Function>& e) override;
+ void operator()(const_t<Method>& e) override;
+ /** \} */
+ };
+
+ /// Shorthand for a const visitor.
+ using DefaultConstVisitor = GenDefaultVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using DefaultVisitor = GenDefaultVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ /// Shorthand for a const visitor.
+ %template(DefaultConstVisitor) GenDefaultVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ %template(DefaultVisitor) GenDefaultVisitor<misc::id_traits>;
+#endif
+} // namespace type
+
+#include <type/default-visitor.hxx>
diff --git a/tiger-compiler/src/type/default-visitor.hxx b/tiger-compiler/src/type/default-visitor.hxx
new file mode 100644
index 0000000..02cbd15
--- /dev/null
+++ b/tiger-compiler/src/type/default-visitor.hxx
@@ -0,0 +1,95 @@
+/**
+ ** \file type/default-visitor.hxx
+ ** \brief Implementation for type/default-visitor.hh.
+ */
+
+#pragma once
+
+#include <misc/algorithm.hh>
+#include <type/class.hh>
+#include <type/default-visitor.hh>
+#include <type/types.hh>
+
+namespace type
+{
+ template <template <typename> class Const>
+ GenDefaultVisitor<Const>::GenDefaultVisitor()
+ : GenVisitor<Const>()
+ {}
+
+ template <template <typename> class Const>
+ GenDefaultVisitor<Const>::~GenDefaultVisitor() = default;
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Nil>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Void>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Int>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<String>&)
+ {}
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Named>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.type_get()->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Array>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.get_element_type()->accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Record>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto field : e)
+ {
+ field.type_get().accept(*this);
+ }
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Class>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ for (auto attr : e.attrs_get())
+ {
+ attr.type_get().accept(*this);
+ }
+ for (auto meth : e.meths_get())
+ {
+ meth->accept(*this);
+ }
+ for (auto subclass : e.attrs_get())
+ {
+ subclass.type_get().accept(*this);
+ }
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Function>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ e.formals_get().accept(*this);
+ e.result_get().accept(*this);
+ }
+
+ template <template <typename> class Const>
+ void GenDefaultVisitor<Const>::operator()(const_t<Method>& e)
+ {
+ e.Function::accept(*this);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/field.cc b/tiger-compiler/src/type/field.cc
new file mode 100644
index 0000000..e7ec949
--- /dev/null
+++ b/tiger-compiler/src/type/field.cc
@@ -0,0 +1,17 @@
+/**
+ ** \file type/field.cc
+ ** \brief Implementation for type/field.hh.
+ */
+
+#include <ostream>
+
+#include <type/field.hh>
+
+namespace type
+{
+ Field::Field(misc::symbol name, const Type& type)
+ : name_(name)
+ , type_(type)
+ {}
+
+} // namespace type
diff --git a/tiger-compiler/src/type/field.hh b/tiger-compiler/src/type/field.hh
new file mode 100644
index 0000000..e1f5609
--- /dev/null
+++ b/tiger-compiler/src/type/field.hh
@@ -0,0 +1,45 @@
+/**
+ ** \file type/field.hh
+ ** \brief The class Field (of a record type).
+ */
+#pragma once
+
+#include <misc/symbol.hh>
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /** \brief The base type for Record fields.
+ **
+ ** Very much like Named, but it is *not* a Type. */
+ class Field
+ {
+ public:
+ /** \name Ctor & dtor.
+ ** \{ */
+ /** \brief Construct a Field.
+ ** \param name field's identifier.
+ ** \param type field's type. */
+ Field(misc::symbol name, const Type& type);
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the field's name.
+ misc::symbol name_get() const;
+ /// Return the field's type.
+ const Type& type_get() const;
+ /** \} */
+
+ protected:
+ /// Field's identifier.
+ misc::symbol name_;
+
+ /// Field's type.
+ const Type& type_;
+ };
+
+} // namespace type
+
+#include <type/field.hxx>
diff --git a/tiger-compiler/src/type/field.hxx b/tiger-compiler/src/type/field.hxx
new file mode 100644
index 0000000..b4d9630
--- /dev/null
+++ b/tiger-compiler/src/type/field.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file type/field.hxx
+ ** \brief Inline methods for type::Field.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/field.hh>
+
+namespace type
+{
+ inline misc::symbol Field::name_get() const { return name_; }
+
+ inline const Type& Field::type_get() const { return type_; }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/function.cc b/tiger-compiler/src/type/function.cc
new file mode 100644
index 0000000..91cef2c
--- /dev/null
+++ b/tiger-compiler/src/type/function.cc
@@ -0,0 +1,38 @@
+/**
+ ** \file type/function.cc
+ ** \brief Implementation for type/function.hh.
+ */
+
+#include <ostream>
+#include <ranges>
+
+#include <type/function.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ Function::Function(const Record* formals, const Type& result)
+ : result_(result)
+ {
+ precondition(formals);
+
+ formals_ = formals;
+ }
+
+ Function::~Function() { delete formals_; }
+
+ void Function::accept(ConstVisitor& v) const { v(*this); }
+
+ void Function::accept(Visitor& v) { v(*this); }
+
+ // FIXME DONE: Some code was deleted here.
+ bool Function::compatible_with(const Type& other) const
+ {
+ const auto other_function = dynamic_cast<const Function*>(&other);
+
+ return other_function != nullptr \
+ && other_function->formals_get().compatible_with(this->formals_get()) \
+ && other_function->result_get().compatible_with(this->result_get());
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/function.hh b/tiger-compiler/src/type/function.hh
new file mode 100644
index 0000000..2accb82
--- /dev/null
+++ b/tiger-compiler/src/type/function.hh
@@ -0,0 +1,59 @@
+/**
+ ** \file type/function.hh
+ ** \brief The class Function.
+ */
+#pragma once
+
+#include <type/fwd.hh>
+#include <type/record.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /** \brief Function types.
+ **
+ ** Encapsulate the signature of a function, i.e. the type structures
+ ** of both function's arguments and its result. */
+ class Function : public Type
+ {
+ public:
+ /** \brief Construct a Function.
+ **
+ ** \param formals type structures of formal arguments.
+ ** \param result type structure of what function returns. */
+ Function(const Record* formals, const Type& result);
+
+ /** \brief Destructor.
+ **/
+ ~Function() override;
+
+ /// \name Visitors entry point.
+ /** \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the type structures of the function's arguments.
+ const Record& formals_get() const;
+ /// Return the type structure of the function's result.
+ const Type& result_get() const;
+ /** \} */
+
+ // FIXME DONE: Some code was deleted here (Special implementation of "compatible_with" for Function).
+ bool compatible_with(const Type& other) const override;
+
+ protected:
+ /// Formals' types.
+ const Record* formals_;
+
+ /// Result's type.
+ const Type& result_;
+ };
+
+} // namespace type
+
+#include <type/function.hxx>
diff --git a/tiger-compiler/src/type/function.hxx b/tiger-compiler/src/type/function.hxx
new file mode 100644
index 0000000..1784650
--- /dev/null
+++ b/tiger-compiler/src/type/function.hxx
@@ -0,0 +1,16 @@
+/**
+ ** \file type/function.hxx
+ ** \brief Inline methods for type::Function.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/function.hh>
+
+namespace type
+{
+ inline const Record& Function::formals_get() const { return *formals_; }
+
+ inline const Type& Function::result_get() const { return result_; }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/fwd.hh b/tiger-compiler/src/type/fwd.hh
new file mode 100644
index 0000000..9fa9fca
--- /dev/null
+++ b/tiger-compiler/src/type/fwd.hh
@@ -0,0 +1,31 @@
+/**
+ ** \file type/fwd.hh
+ ** \brief Forward declarations for the type module.
+ */
+
+#pragma once
+
+#include <misc/fwd.hh>
+
+namespace type
+{
+ class Array;
+ class Attribute;
+ class Class;
+ class Field;
+ class Function;
+ class Int;
+ class Method;
+ class Named;
+ class Nil;
+ class Record;
+ class String;
+ class Type;
+ class Void;
+
+ // From visitor.hh
+ template <template <typename> class Const> class GenVisitor;
+ using ConstVisitor = GenVisitor<misc::constify_traits>;
+ using Visitor = GenVisitor<misc::id_traits>;
+
+} // namespace type
diff --git a/tiger-compiler/src/type/libtype.cc b/tiger-compiler/src/type/libtype.cc
new file mode 100644
index 0000000..50392d7
--- /dev/null
+++ b/tiger-compiler/src/type/libtype.cc
@@ -0,0 +1,19 @@
+/**
+ ** \file type/libtype.cc
+ ** \brief Define the function exported by type module.
+ */
+
+#include <ast/exp.hh>
+#include <type/libtype.hh>
+#include <type/type-checker.hh>
+
+namespace type
+{
+ misc::error types_check(ast::Ast& tree)
+ {
+ TypeChecker type;
+ type(tree);
+ return type.error_get();
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/libtype.hh b/tiger-compiler/src/type/libtype.hh
new file mode 100644
index 0000000..01fa60e
--- /dev/null
+++ b/tiger-compiler/src/type/libtype.hh
@@ -0,0 +1,19 @@
+/**
+ ** \file type/libtype.hh
+ ** \brief Declare the function exported by type module.
+ */
+
+#pragma once
+
+#include <ast/fwd.hh>
+#include <misc/error.hh>
+
+/// Type-checking an ast::Ast.
+namespace type
+{
+ /** \brief Check types in a (bound) AST.
+ ** \param tree abstract syntax tree's root.
+ ** \return synthesis of the errors possibly found. */
+ misc::error types_check(::ast::Ast& tree);
+
+} // namespace type
diff --git a/tiger-compiler/src/type/local.am b/tiger-compiler/src/type/local.am
new file mode 100644
index 0000000..e071bc1
--- /dev/null
+++ b/tiger-compiler/src/type/local.am
@@ -0,0 +1,29 @@
+## type module.
+EXTRA_DIST += %D%/README.txt
+
+src_libtc_la_SOURCES += \
+ %D%/fwd.hh %D%/types.hh \
+ %D%/array.hh %D%/array.cc %D%/array.hxx \
+ %D%/builtin-types.hh %D%/builtin-types.cc \
+ %D%/nil.hh %D%/nil.cc \
+ %D%/default-visitor.hh %D%/default-visitor.hxx \
+ %D%/field.hh %D%/field.cc %D%/field.hxx \
+ %D%/named.hh %D%/named.cc %D%/named.hxx \
+ %D%/pretty-printer.hh %D%/pretty-printer.cc \
+ %D%/record.hh %D%/record.cc %D%/record.hxx \
+ %D%/type.hh %D%/type.hxx %D%/type.cc \
+ %D%/type-checker.hh %D%/type-checker.hxx %D%/type-checker.cc \
+ %D%/libtype.hh %D%/libtype.cc \
+ %D%/visitor.hh %D%/visitor.hxx
+
+src_libtc_la_SOURCES += \
+ %D%/function.hh %D%/function.cc %D%/function.hxx
+src_libtc_la_SOURCES += \
+ %D%/attribute.hh %D%/attribute.cc %D%/attribute.hxx \
+ %D%/class.hh %D%/class.cc %D%/class.hxx \
+ %D%/method.hh %D%/method.cc %D%/method.hxx
+
+check_PROGRAMS += %D%/test-type
+%C%_test_type_LDADD = src/libtc.la
+
+TASKS += %D%/tasks.hh %D%/tasks.cc
diff --git a/tiger-compiler/src/type/method.cc b/tiger-compiler/src/type/method.cc
new file mode 100644
index 0000000..5726948
--- /dev/null
+++ b/tiger-compiler/src/type/method.cc
@@ -0,0 +1,48 @@
+/**
+ ** \file type/method.cc
+ ** \brief Implementation for type/method.hh.
+ */
+
+#include <iostream>
+
+#include <type/method.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ Method::Method(misc::symbol name,
+ const Class* owner,
+ const Record* formals,
+ const Type& result,
+ ast::MethodDec* def)
+ : Function(formals, result)
+ , name_(name)
+ , owner_(owner)
+ , def_(def)
+ {}
+
+ Method::Method(misc::symbol name,
+ const Record* formals,
+ const Type& result,
+ ast::MethodDec* def)
+ : Function(formals, result)
+ , name_(name)
+ , owner_(nullptr)
+ , def_(def)
+ {}
+
+ void Method::accept(ConstVisitor& v) const { v(*this); }
+
+ void Method::accept(Visitor& v) { v(*this); }
+
+ // FIXME DONE: Some code was deleted here.
+ bool Method::compatible_with(const Type& other) const
+ {
+ const auto other_method = dynamic_cast<const Method*>(&other);
+
+ return other_method != nullptr \
+ && other_method->formals_get().compatible_with(other) \
+ && other_method->result_get().compatible_with(other);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/method.hh b/tiger-compiler/src/type/method.hh
new file mode 100644
index 0000000..f9c3d8c
--- /dev/null
+++ b/tiger-compiler/src/type/method.hh
@@ -0,0 +1,90 @@
+/**
+ ** \file type/method.hh
+ ** \brief The class Method.
+ */
+#pragma once
+
+#include <ast/method-dec.hh>
+#include <type/function.hh>
+
+namespace type
+{
+ // Forward declaration.
+ class Class;
+
+ /** \brief Method types.
+ **
+ ** Encapsulate the signature of a method, i.e. the type structures
+ ** of both method's arguments and its result. */
+ class Method : public Function
+ {
+ /// A shortcut for the super type of this class.
+ using super_type = Function;
+
+ public:
+ /** \brief Construct a FunEntry.
+ **
+ ** \param name The method's identifier.
+ ** \param owner The type::Class owning this method.
+ ** \param formals The type structures of formal arguments.
+ ** \param result The type structure of what method returns.
+ ** \param def The method's definition site. */
+ Method(misc::symbol name,
+ const Class* owner,
+ const Record* formals,
+ const Type& result,
+ ast::MethodDec* def);
+
+ /** \brief Construct a FunEntry.
+ **
+ ** \param name The method's identifier.
+ ** \param formals The type structures of formal arguments.
+ ** \param result The type structure of what method returns.
+ ** \param def The method's definition site. */
+ Method(misc::symbol name,
+ const Record* formals,
+ const Type& result,
+ ast::MethodDec* def);
+
+ /// \name Visitors entry point.
+ /** \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the method's name.
+ misc::symbol name_get() const;
+ /// Return the method's owner (enclosing class).
+ const Class* owner_get() const;
+ /// Return the method's type.
+ const Type& type_get() const;
+ /// Return the method's definiton site.
+ const ast::MethodDec* def_get() const;
+ /// Return the method's definiton site.
+ ast::MethodDec* def_get();
+
+ /// Set the method's name.
+ void name_set(misc::symbol name);
+ /// set the method's definiton site.
+ void def_set(ast::MethodDec* def);
+ /** \} */
+
+ // FIXME DONE: Some code was deleted here (Special implementation of "compatible_with" for type::Method).
+ bool compatible_with(const Type& other) const override;
+
+ private:
+ /// Method's identifier.
+ misc::symbol name_;
+ /// The Class where this Method is defined.
+ const Class* owner_;
+ /// Method's definition site.
+ ast::MethodDec* def_;
+ };
+
+} // namespace type
+
+#include <type/method.hxx>
diff --git a/tiger-compiler/src/type/method.hxx b/tiger-compiler/src/type/method.hxx
new file mode 100644
index 0000000..d026252
--- /dev/null
+++ b/tiger-compiler/src/type/method.hxx
@@ -0,0 +1,27 @@
+/**
+ ** \file type/method.hxx
+ ** \brief Inline methods for type::Method.
+ */
+#pragma once
+
+namespace type
+{
+ inline misc::symbol Method::name_get() const { return name_; }
+
+ inline const Class* Method::owner_get() const { return owner_; }
+
+ inline const Type& Method::type_get() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ return *def_->type_get();
+ }
+
+ inline const ast::MethodDec* Method::def_get() const { return def_; }
+
+ inline ast::MethodDec* Method::def_get() { return def_; }
+
+ inline void Method::name_set(misc::symbol name) { name_ = name; }
+
+ inline void Method::def_set(ast::MethodDec* def) { def_ = def; }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/named.cc b/tiger-compiler/src/type/named.cc
new file mode 100644
index 0000000..ff092f6
--- /dev/null
+++ b/tiger-compiler/src/type/named.cc
@@ -0,0 +1,61 @@
+/**
+ ** \file type/named.cc
+ ** \brief Implementation for type/named.hh.
+ */
+
+#include <type/named.hh>
+#include <type/visitor.hh>
+#include <vector>
+
+namespace type
+{
+ Named::Named(misc::symbol name)
+ : name_(name)
+ , type_(nullptr)
+ {}
+
+ Named::Named(misc::symbol name, const Type* type)
+ : name_(name)
+ , type_(type)
+ {}
+
+ // Inherited functions
+ void Named::accept(ConstVisitor& v) const
+ {
+ // FIXME DONE: Some code was deleted here.
+ v(*this);
+ }
+
+ void Named::accept(Visitor& v)
+ {
+ // FIXME DONE: Some code was deleted here.
+ v(*this);
+ }
+
+ bool Named::sound() const
+ {
+ // FIXME DONE: Some code was deleted here (Sound).
+ auto reference = dynamic_cast<const Named*>(type_);
+ std::vector<const Named*> previous;
+
+ while (reference != nullptr)
+ {
+ if (std::ranges::find(previous, reference) != previous.end())
+ {
+ return false;
+ }
+
+ previous.push_back(reference);
+ reference = dynamic_cast<const Named*>(reference->type_get());
+ }
+
+ return true;
+ }
+
+ bool Named::compatible_with(const Type& other) const
+ {
+ // FIXME DONE: Some code was deleted here (Special implementation of "compatible_with" for Named).
+ return type_->compatible_with(other);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/named.hh b/tiger-compiler/src/type/named.hh
new file mode 100644
index 0000000..f8b914f
--- /dev/null
+++ b/tiger-compiler/src/type/named.hh
@@ -0,0 +1,90 @@
+/**
+ ** \file type/named.hh
+ ** \brief The class Named.
+ */
+#pragma once
+
+#include <misc/symbol.hh>
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /** \brief Named types.
+ **
+ ** Named types are used when new types are defined, i.e., in
+ ** \b Example: let type name_ = type_.
+ */
+ class Named : public Type
+ {
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /** \brief Construct a Named type.
+ ** \param name user defined type's identifier. */
+ explicit Named(misc::symbol name);
+ /** \brief Construct a Named type.
+ ** \param name user defined type's identifier.
+ ** \param type defined type's structure */
+ Named(misc::symbol name, const Type* type);
+ /** \} */
+
+ /// \name Visitors entry point.
+ /** \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /** \} */
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the user defined type's structure.
+ const Type* type_get() const;
+
+ /** \brief Set the defined type's structure.
+ **
+ ** This is the version which is used by TypeChecker which needs to
+ ** assign a value to the Named type. */
+ void type_set(const Type* type) const;
+
+ /// Return the name of this type.
+ misc::symbol name_get() const;
+
+ /// (Re)set the name of this type.
+ void name_set(misc::symbol name);
+ /** \} */
+
+ /** \name Type resolution.
+ ** \{ */
+ /// The type pointed to ultimately.
+ const Type& actual() const override;
+
+ /** \brief Whether the definition of this named type is sound,
+ ** i.e. that there is no recursive dependency. */
+ bool sound() const;
+ /** \} */
+
+ bool compatible_with(const Type& other) const override;
+
+ protected:
+ /// Name of the defined type.
+ misc::symbol name_;
+
+ /** \brief The Type pointed to.
+ **
+ ** "Mutable const" because most of the time types are handled as
+ ** const objects. But Named types are built in two steps: first
+ ** they are built without any value for \a type_ (by
+ ** TypeChecker::visit_dec_header <ast::TypeDec>), and then
+ ** they are completed (by TypeChecker::visit_dec_body <ast::TypeDec>).
+ ** Because the second step of the construction is actually seen
+ ** as a modification by the C++ type system, we have it accept
+ ** it thanks to mutable.
+ **/
+ mutable const Type* type_{};
+ };
+
+} // namespace type
+
+#include <type/named.hxx>
diff --git a/tiger-compiler/src/type/named.hxx b/tiger-compiler/src/type/named.hxx
new file mode 100644
index 0000000..1b84bb6
--- /dev/null
+++ b/tiger-compiler/src/type/named.hxx
@@ -0,0 +1,28 @@
+/**
+ ** \file type/named.hxx
+ ** \brief Inline methods for type::Named.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/named.hh>
+
+namespace type
+{
+ inline const Type* Named::type_get() const { return type_; }
+
+ inline void Named::type_set(const Type* type) const { type_ = type; }
+
+ inline misc::symbol Named::name_get() const { return name_; }
+
+ inline void Named::name_set(misc::symbol name) { name_ = name; }
+
+ inline const Type& Named::actual() const
+ {
+ // FIXME DONE: Some code was deleted here.
+ precondition(type_ != nullptr);
+
+ return type_->actual();
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/nil.cc b/tiger-compiler/src/type/nil.cc
new file mode 100644
index 0000000..d3c663c
--- /dev/null
+++ b/tiger-compiler/src/type/nil.cc
@@ -0,0 +1,34 @@
+/**
+ ** \file type/nil.cc
+ ** \brief Implementation for type/nil.hh.
+ */
+
+#include <ostream>
+
+#include <type/class.hh>
+#include <type/nil.hh>
+#include <type/record.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ /*------.
+ | Nil. |
+ `------*/
+
+ void Nil::accept(ConstVisitor& v) const { v(*this); }
+
+ void Nil::accept(Visitor& v) { v(*this); }
+
+ bool Nil::compatible_with(const Type& other) const
+ {
+ // FIXME DONE: Some code was deleted here
+ return dynamic_cast<const Record*>(&other.actual()) != nullptr
+ || dynamic_cast<const Class*>(&other.actual()) != nullptr;
+ }
+
+ const Type* Nil::record_type_get() const { return record_type_; }
+
+ void Nil::record_type_set(const Type& type) const { record_type_ = &type; }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/nil.hh b/tiger-compiler/src/type/nil.hh
new file mode 100644
index 0000000..4807ac0
--- /dev/null
+++ b/tiger-compiler/src/type/nil.hh
@@ -0,0 +1,47 @@
+/**
+ ** \file type/nil.hh
+ ** \brief The Nil type.
+ */
+#pragma once
+
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /*------.
+ | Nil. |
+ `------*/
+
+ class Record;
+
+ /// The builtin type of `nil'.
+ /// The Nil type is the type of a `nil` expression.
+ class Nil : public Type
+ {
+ public:
+ /// \name Visitors entry point.
+ /** \{ */
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /** \} */
+
+ bool compatible_with(const Type& other) const override;
+
+ /// Get the associated record type.
+ const Type* record_type_get() const;
+
+ /// Set the record type used with the nil.
+ void record_type_set(const Type& type) const;
+
+ private:
+ /// The actual record_type that it represents.
+ /// Nil types are either compatible with `type::Record` or `type::Class`.
+ /// record_type represents the actual type that the `nil` was meant to be
+ /// used with.
+ mutable const Type* record_type_ = nullptr;
+ };
+
+} // namespace type
diff --git a/tiger-compiler/src/type/pretty-printer.cc b/tiger-compiler/src/type/pretty-printer.cc
new file mode 100644
index 0000000..a6f4a99
--- /dev/null
+++ b/tiger-compiler/src/type/pretty-printer.cc
@@ -0,0 +1,127 @@
+/**
+ ** \file type/pretty-printer.cc
+ ** \brief Implementation for type/pretty-printer.hh.
+ */
+
+#include <type/libtype.hh>
+#include <type/pretty-printer.hh>
+#include <type/type.hh>
+#include <type/types.hh>
+
+namespace type
+{
+ namespace
+ {
+ template <typename Type>
+ std::ostream& print_type(std::ostream& ostr, const Type& type)
+ {
+ PrettyPrinter printer{ostr};
+ printer(type);
+ return ostr;
+ }
+
+ /// How many times did we go through operator()(const Named&)?
+ inline long int& indent(std::ostream& o)
+ {
+ // The slot to store the current indentation level.
+ static const int indent_index = std::ios::xalloc();
+ return o.iword(indent_index);
+ }
+
+ } // namespace
+
+ std::ostream& operator<<(std::ostream& ostr, const Attribute& e)
+ {
+ return print_type(ostr, e);
+ }
+
+ std::ostream& operator<<(std::ostream& ostr, const Field& e)
+ {
+ return print_type(ostr, e);
+ }
+
+ std::ostream& operator<<(std::ostream& ostr, const Type& e)
+ {
+ return print_type(ostr, e);
+ }
+
+ PrettyPrinter::PrettyPrinter(std::ostream& ostr)
+ : ostr_{ostr}
+ {}
+
+ void PrettyPrinter::operator()(const Nil& e)
+ {
+ ostr_ << "nil = ";
+ if (auto record_type = e.record_type_get())
+ ostr_ << *record_type;
+ else
+ ostr_ << "(null)";
+ }
+
+ void PrettyPrinter::operator()(const Void&) { ostr_ << "void"; }
+
+ void PrettyPrinter::operator()(const Int&)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "int";
+ }
+
+ void PrettyPrinter::operator()(const String&)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "string";
+ }
+
+ void PrettyPrinter::operator()(const Named& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (const misc::symbol& name = e.name_get();
+ name != "int" && name != "string")
+ ostr_ << name << ": ";
+
+ super_type::operator()(e);
+ }
+
+ void PrettyPrinter::operator()(const Array& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "array of ";
+ super_type::operator()(e);
+ }
+
+ void PrettyPrinter::operator()(const Record& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "record {" << misc::incendl;
+ super_type::operator()(e);
+ ostr_ << misc::decendl << "}";
+ }
+
+ void PrettyPrinter::operator()(const Class& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "class {" << misc::incendl;
+ super_type::operator()(e);
+ ostr_ << misc::decendl << "}";
+ }
+
+ void PrettyPrinter::operator()(const Function& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ ostr_ << "function (";
+ e.formals_get().accept(*this);
+ ostr_ << ") -> ";
+ e.result_get().accept(*this);
+ }
+
+ void PrettyPrinter::operator()(const Attribute& e)
+ {
+ ostr_ << e.name_get() << " : " << e.type_get();
+ }
+
+ void PrettyPrinter::operator()(const Field& e)
+ {
+ ostr_ << e.name_get() << " : " << e.type_get();
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/pretty-printer.hh b/tiger-compiler/src/type/pretty-printer.hh
new file mode 100644
index 0000000..786cfcf
--- /dev/null
+++ b/tiger-compiler/src/type/pretty-printer.hh
@@ -0,0 +1,67 @@
+/**
+ ** \file type/pretty-printer.hh
+ ** \brief Print the type hierarchy.
+ */
+
+#pragma once
+
+#include <ostream>
+
+#include <type/default-visitor.hh>
+#include <type/fwd.hh>
+
+namespace type
+{
+ class PrettyPrinter : public DefaultConstVisitor
+ {
+ public:
+ /// Super class type.
+ using super_type = DefaultConstVisitor;
+
+ // Import overloaded \c operator() methods.
+ using super_type::operator();
+
+ /** \name Ctor & dtor.
+ ** \{ */
+ /// Construct a pretty printer.
+ explicit PrettyPrinter(std::ostream& ostr);
+ /** \} */
+
+ /** \name Visit basic types.
+ ** \{ */
+ void operator()(const Nil& e) override;
+ void operator()(const Void& e) override;
+ void operator()(const Int& e) override;
+ void operator()(const String& e) override;
+ /** \} */
+
+ /** \name Visit composed types.
+ ** \{ */
+ void operator()(const Named& e) override;
+ void operator()(const Array& e) override;
+ void operator()(const Record& e) override;
+ void operator()(const Class& e) override;
+ void operator()(const Function& e) override;
+ /** \} */
+
+ /** \name Visit Non type types.
+ ** \{ */
+ void operator()(const Attribute& e);
+ void operator()(const Field& e);
+ /** \} */
+
+ private:
+ /// The stream to print on.
+ std::ostream& ostr_;
+ };
+
+ /// Overload redirection operator for Type.
+ std::ostream& operator<<(std::ostream& ostr, const Type& t);
+
+ /// Overload redirection operator for Attribute.
+ std::ostream& operator<<(std::ostream& ostr, const Attribute& obj);
+
+ /// Overload redirection operator for Field.
+ std::ostream& operator<<(std::ostream& ostr, const Field& obj);
+
+} // namespace type
diff --git a/tiger-compiler/src/type/record.cc b/tiger-compiler/src/type/record.cc
new file mode 100644
index 0000000..174e192
--- /dev/null
+++ b/tiger-compiler/src/type/record.cc
@@ -0,0 +1,52 @@
+/**
+ ** \file type/record.cc
+ ** \brief Implementation for type/record.hh.
+ */
+
+#include <algorithm>
+#include <ostream>
+
+#include <type/builtin-types.hh>
+#include <type/nil.hh>
+#include <type/record.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ void Record::accept(ConstVisitor& v) const { v(*this); }
+
+ void Record::accept(Visitor& v) { v(*this); }
+
+ // FIXME DONE: Some code was deleted here (Field manipulators).
+ const Type* Record::field_type(const misc::symbol key) const
+ {
+ const auto result = std::ranges::find_if(
+ fields_,
+ [&key] (const misc::symbol& name) { return name == key; },
+ [] (const Field& field) { return field.name_get(); }
+ );
+
+ return result != fields_.end() ? &result->type_get() : nullptr;
+ }
+
+ int Record::field_index(const misc::symbol key) const
+ {
+ const auto result = std::ranges::find_if(
+ fields_,
+ [&key] (const misc::symbol& name) { return name == key; },
+ [] (const Field& field) { return field.name_get(); }
+ );
+
+ return result != fields_.end() \
+ ? static_cast<int>(std::distance(fields_.begin(), result)) \
+ : -1;
+ }
+
+ // FIXME DONE: Some code was deleted here (Special implementation of "compatible_with" for Record).
+ bool Record::compatible_with(const Type& other) const
+ {
+ return Type::compatible_with(other) \
+ || dynamic_cast<const Nil*>(&other) != nullptr;
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/record.hh b/tiger-compiler/src/type/record.hh
new file mode 100644
index 0000000..d5a7d82
--- /dev/null
+++ b/tiger-compiler/src/type/record.hh
@@ -0,0 +1,69 @@
+/**
+ ** \file type/record.hh
+ ** \brief The class Record.
+ */
+#pragma once
+
+#include <vector>
+
+#include <misc/indent.hh>
+#include <misc/symbol.hh>
+#include <type/field.hh>
+#include <type/fwd.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ /** \brief Record types.
+ **
+ ** List of Field s. */
+ class Record : public Type
+ {
+ /// \name Visitors entry point.
+ /// \{ */
+ public:
+ /// Accept a const visitor \a v.
+ void accept(ConstVisitor& v) const override;
+ /// Accept a non-const visitor \a v.
+ void accept(Visitor& v) override;
+ /// \}
+
+ /** \name Field elementary manipulation.
+ ** \{ */
+ /// Return the type associated to \a key.
+ const Type* field_type(misc::symbol key) const;
+ /** \brief Return the index of the field associated to \a key.
+ **
+ ** The index of a field is its position in the list. */
+ int field_index(misc::symbol key) const;
+ /** \} */
+
+ /** \name Internal Field list manipulators.
+ ** \{ */
+ /// List of Field's.
+ using fields_type = std::vector<Field>;
+ /// Return the Field list stored in this (read only).
+ const fields_type& fields_get() const;
+
+ /// Add an already existing Field to the list.
+ void field_add(const Field& field);
+ /// Create a Field then add it to the list.
+ void field_add(misc::symbol name, const Type& type);
+
+ /// Iterators over Field's.
+ using const_iterator = fields_type::const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+ /** \} */
+
+ // FIXME DONE: Some code was deleted here (Inherited method).
+ bool compatible_with(const Type& other) const override;
+
+ protected:
+ /// Fields list.
+ fields_type fields_;
+ };
+
+} // namespace type
+
+#include <type/record.hxx>
diff --git a/tiger-compiler/src/type/record.hxx b/tiger-compiler/src/type/record.hxx
new file mode 100644
index 0000000..2907cb0
--- /dev/null
+++ b/tiger-compiler/src/type/record.hxx
@@ -0,0 +1,34 @@
+/**
+ ** \file type/record.hxx
+ ** \brief Inline methods for type::Record.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/record.hh>
+
+namespace type
+{
+ inline const Record::fields_type& Record::fields_get() const
+ {
+ return fields_;
+ }
+
+ inline void Record::field_add(const Field& field)
+ {
+ fields_.emplace_back(field);
+ }
+
+ inline void Record::field_add(misc::symbol name, const Type& type)
+ {
+ fields_.emplace_back(name, type);
+ }
+
+ inline Record::const_iterator Record::begin() const
+ {
+ return fields_.begin();
+ }
+
+ inline Record::const_iterator Record::end() const { return fields_.end(); }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/tasks.cc b/tiger-compiler/src/type/tasks.cc
new file mode 100644
index 0000000..261e015
--- /dev/null
+++ b/tiger-compiler/src/type/tasks.cc
@@ -0,0 +1,22 @@
+/**
+ ** \file type/tasks.cc
+ ** \brief Type module task implementations.
+ */
+
+#include <ast/tasks.hh>
+#include <common.hh>
+#include <type/libtype.hh>
+#define DEFINE_TASKS 1
+#include <type/tasks.hh>
+#undef DEFINE_TASKS
+
+// Type module related tasks' implementation.
+namespace type::tasks
+{
+ void types_check()
+ {
+ task_error() << ::type::types_check(*ast::tasks::the_program)
+ << &misc::error::exit_on_error;
+ }
+
+} // namespace type::tasks
diff --git a/tiger-compiler/src/type/tasks.hh b/tiger-compiler/src/type/tasks.hh
new file mode 100644
index 0000000..e6add54
--- /dev/null
+++ b/tiger-compiler/src/type/tasks.hh
@@ -0,0 +1,29 @@
+/**
+ ** \file type/tasks.hh
+ ** \brief Type module tasks.
+ */
+
+#pragma once
+
+#include <task/libtask.hh>
+
+namespace type::tasks
+{
+ TASK_GROUP("4. Type checking");
+
+ /// Default the type-checking to Tiger (without objects nor overloading).
+ DISJUNCTIVE_TASK_DECLARE("T|typed",
+ "default the type-checking to Tiger "
+ "(without objects nor overloading)",
+ "types-compute"
+ " combine-types-compute"
+ " object-types-compute"
+ " assert-types-compute");
+
+ /// Check for type violation.
+ TASK_DECLARE("types-compute",
+ "check for type violations",
+ types_check,
+ "bindings-compute");
+
+} // namespace type::tasks
diff --git a/tiger-compiler/src/type/type-checker.cc b/tiger-compiler/src/type/type-checker.cc
new file mode 100644
index 0000000..fcecc87
--- /dev/null
+++ b/tiger-compiler/src/type/type-checker.cc
@@ -0,0 +1,639 @@
+/**
+ ** \file type/type-checker.cc
+ ** \brief Implementation for type/type-checker.hh.
+ */
+
+#include <memory>
+#include <boost/iterator/zip_iterator.hpp>
+#include <misc/contract.hh>
+
+#include <ast/all.hh>
+#include <type/type-checker.hh>
+#include <type/types.hh>
+
+namespace type
+{
+ TypeChecker::TypeChecker()
+ : super_type()
+ , error_()
+ {}
+
+ const Type* TypeChecker::type(ast::Typable& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (e.type_get() == nullptr)
+ e.accept(*this);
+ return e.type_get();
+ }
+
+ const Record* TypeChecker::type(const ast::fields_type& e)
+ {
+ const auto res = new Record;
+ // FIXME DONE: Some code was deleted here.
+ for (const auto& var : e)
+ {
+ if (res->field_index(var->name_get()) != -1)
+ {
+ error(*var,
+ var->name_get().get()
+ + " attribute is already present in record");
+ }
+
+ res->field_add(var->name_get(), *type(var->type_name_get()));
+ }
+ return res;
+ }
+
+ const Record* TypeChecker::type(const ast::VarChunk& e)
+ {
+ const auto res = new Record;
+
+ for (const auto& var : e)
+ {
+ res->field_add(var->name_get(), *type(*var));
+ }
+
+ return res;
+ }
+
+ const misc::error& TypeChecker::error_get() const { return error_; }
+
+ /*-----------------.
+ | Error handling. |
+ `-----------------*/
+
+ void TypeChecker::error(const ast::Ast& ast, const std::string& msg)
+ {
+ error_ << misc::error::error_type::type << ast.location_get() << ": " << msg
+ << std::endl;
+ }
+
+ void TypeChecker::type_mismatch(const ast::Ast& ast,
+ const std::string& exp1,
+ const Type& type1,
+ const std::string& exp2,
+ const Type& type2)
+ {
+ error_ << misc::error::error_type::type << ast.location_get()
+ << ": type mismatch" << misc::incendl << exp1 << " type: " << type1
+ << misc::iendl << exp2 << " type: " << type2 << misc::decendl;
+ }
+
+ void TypeChecker::check_types(const ast::Ast& loc,
+ const std::string& exp1,
+ const Type& type1,
+ const std::string& exp2,
+ const Type& type2)
+ {
+ // FIXME DONE: Some code was deleted here (Check for type mismatch).
+ if (!type1.actual().compatible_with(type2.actual()))
+ type_mismatch(loc, exp1, type1, exp2, type2);
+
+ // If any of the type is Nil, set its `record_type_` to the other type.
+ if (!error_)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (auto nil = dynamic_cast<const Nil*>(&type1); nil != nullptr)
+ nil->record_type_set(type2);
+ else if (nil = dynamic_cast<const Nil*>(&type2); nil != nullptr)
+ nil->record_type_set(type1);
+ }
+ }
+
+ void TypeChecker::check_types(const ast::Ast& ast,
+ const std::string& exp1,
+ ast::Typable& type1,
+ const std::string& exp2,
+ ast::Typable& type2)
+ {
+ // Ensure evaluation order.
+ type(type1);
+ type(type2);
+ // FIXME DONE: Some code was deleted here (Check types).
+ check_types(ast, exp1, *type1.type_get(), exp2, *type2.type_get());
+ }
+
+ /*--------------------------.
+ | The core of the visitor. |
+ `--------------------------*/
+
+ /*-----------------.
+ | Visiting /Var/. |
+ `-----------------*/
+
+ void TypeChecker::operator()(ast::SimpleVar& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // It is assumed SimpleVar references a variable that has already been typed
+ precondition(e.def_get()->type_get() != nullptr);
+ type_default(e, e.def_get()->type_get());
+ }
+
+ // FIXME DONE: Some code was deleted here.
+
+ void TypeChecker::operator()(ast::FieldVar& e)
+ {
+ const auto record =
+ dynamic_cast<const Record*>(&type(e.var_get())->actual());
+
+ if (record == nullptr)
+ {
+ error(e.var_get(), "variable is not a record");
+ type_default(e, &default_type);
+ return;
+ }
+
+ const int index = record->field_index(e.name_get());
+
+ if (index < 0)
+ {
+ error(e,
+ e.name_get().get() + " attribute does not exist within record");
+ type_default(e, &default_type);
+ return;
+ }
+
+ const Type& type = record->fields_get().at(index).type_get();
+
+ type_default(e, &type);
+ }
+
+ void TypeChecker::operator()(ast::SubscriptVar& e)
+ {
+ check_type(e.index_get(), "array subscript value", Int::instance());
+
+ auto array = dynamic_cast<const Array*>(&type(e.var_get())->actual());
+ if (array == nullptr)
+ {
+ error(e, "index does not reference an array");
+ type_default(e, &default_type);
+ }
+ else
+ {
+ type_default(e, array->get_element_type());
+ }
+ }
+
+ /*-----------------.
+ | Visiting /Exp/. |
+ `-----------------*/
+
+ // Literals.
+ void TypeChecker::operator()(ast::NilExp& e)
+ {
+ auto nil_ptr = std::make_unique<Nil>();
+ type_default(e, nil_ptr.get());
+ created_type_default(e, nil_ptr.release());
+ }
+
+ void TypeChecker::operator()(ast::IntExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ type_default(e, &Int::instance());
+ }
+
+ void TypeChecker::operator()(ast::StringExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ type_default(e, &String::instance());
+ }
+
+ // Complex values.
+
+ void TypeChecker::operator()(ast::RecordExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+
+ const Type* named_record = type(e.type_name_get());
+ const auto record = dynamic_cast<const Record*>(&named_record->actual());
+
+ assertion(record != nullptr);
+
+ // everything must be typed first !
+ for (const auto field : e.fields_get())
+ {
+ type(field->init_get());
+ }
+
+ if (e.fields_get().size() != record->fields_get().size())
+ {
+ error(e, std::string("insufficient amount of arguments"));
+ }
+ else
+ {
+ auto record_fields = record->fields_get();
+ auto exp_fields = e.fields_get();
+
+ std::for_each(
+ boost::make_zip_iterator(
+ boost::make_tuple(record_fields.begin(), exp_fields.begin())),
+ boost::make_zip_iterator(
+ boost::make_tuple(record_fields.end(), exp_fields.end())),
+ [this](const boost::tuple<Field&, ast::FieldInit*>& params) {
+ const misc::symbol& expected_name = params.get<0>().name_get();
+ const Type& expected_type = params.get<0>().type_get();
+
+ const misc::symbol& actual_name = params.get<1>()->name_get();
+ const ast::Exp& actual_node = params.get<1>()->init_get();
+
+ if (expected_name != actual_name)
+ {
+ error(actual_node,
+ std::string("name mismatch: expected "
+ + expected_name.get() + " but got "
+ + actual_name.get()));
+ }
+
+ check_types(actual_node, expected_name.get() + " actual",
+ *actual_node.type_get(),
+ expected_name.get() + "expected", expected_type);
+ });
+ }
+
+ type_default(e, named_record);
+ }
+
+ void TypeChecker::operator()(ast::OpExp& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+
+ ast::OpExp::Oper oper = e.oper_get();
+ type(e.left_get());
+ type(e.right_get());
+
+ check_types(e, "left operand", *e.left_get().type_get(), "right operand",
+ *e.right_get().type_get());
+
+ if (const auto comparaison_type = &e.left_get().type_get()->actual();
+ (oper < ast::OpExp::Oper::eq || oper > ast::OpExp::Oper::ne)
+ && (dynamic_cast<const Int*>(comparaison_type) == nullptr
+ && dynamic_cast<const String*>(comparaison_type) == nullptr))
+ {
+ error_ << misc::error::error_type::type << e.location_get()
+ << ": type mismatch" << misc::incendl
+ << "order operations are only possible on int and string, not "
+ << *comparaison_type << misc::decendl;
+ }
+
+ type_default(e, &Int::instance());
+ }
+
+ // FIXME DONE: Some code was deleted here.
+
+ void TypeChecker::operator()(ast::ArrayExp& e)
+ {
+ // Typing order
+ type(e.type_name_get());
+ type(e.size_get());
+ type(e.init_get());
+
+ const Type* actual_type = e.type_name_get().type_get();
+ const auto array_type = dynamic_cast<const Array*>(&actual_type->actual());
+
+ if (array_type == nullptr)
+ {
+ error(e.type_name_get(), "type does not reference an array");
+ type_default(e, &default_type);
+ return;
+ }
+
+ check_type(e.size_get(), "array size", Int::instance());
+ check_types(e, "array element", *array_type->get_element_type(),
+ "initializer", *e.init_get().type_get());
+
+ type_default(e, actual_type);
+ }
+
+ void TypeChecker::operator()(ast::AssignExp& e)
+ {
+ check_types(e, "variable", e.var_get(), "value", e.exp_get());
+
+ if (auto svar = dynamic_cast<ast::SimpleVar*>(&e.var_get());
+ svar && var_read_only_.find(svar->def_get()) != var_read_only_.end())
+ error(e, "variable is read-only");
+
+ type_default(e, &Void::instance());
+ }
+
+ void TypeChecker::operator()(ast::BreakExp& e)
+ {
+ type_default(e, &Void::instance());
+ }
+
+ void TypeChecker::operator()(ast::CallExp& e)
+ {
+ for (ast::Exp* exp : e.args_get())
+ {
+ type(*exp);
+ }
+
+ const auto actual_params = e.args_get();
+ const auto expected_params = e.def_get()->formals_get().decs_get();
+
+ if (actual_params.size() != expected_params.size())
+ {
+ error(e,
+ std::string(std::to_string(expected_params.size())
+ + " parameters expected but got "
+ + std::to_string(actual_params.size())));
+ }
+ else
+ {
+ std::for_each(
+ boost::make_zip_iterator(
+ boost::make_tuple(expected_params.begin(), actual_params.begin())),
+ boost::make_zip_iterator(
+ boost::make_tuple(expected_params.end(), actual_params.end())),
+ [this, &e](const boost::tuple<ast::VarDec*, ast::Exp*>& params) {
+ check_types(e, "expected", *params.get<0>(), "actual",
+ *params.get<1>());
+ });
+ }
+
+ type_default(
+ e, &dynamic_cast<const Function*>(e.def_get()->type_get())->result_get());
+ }
+
+ void TypeChecker::operator()(ast::CastExp& e)
+ {
+ check_types(e, "target", e.ty_get(), "value", e.exp_get());
+
+ created_type_default(e, e.ty_get().type_get());
+ }
+
+ void TypeChecker::operator()(ast::ForExp& e)
+ {
+ check_types(e, "iterator", e.vardec_get(), "high bound", e.hi_get());
+
+ check_type(e.hi_get(), "high bound", Int::instance());
+
+ var_read_only_.insert(&e.vardec_get());
+
+ check_type(e.body_get(), "for body", Void::instance());
+
+ /* Break cannot be used in assignments */
+ const auto iterator_node =
+ dynamic_cast<const ast::IntExp*>(e.vardec_get().init_get());
+ const auto hi_node = dynamic_cast<const ast::IntExp*>(&e.hi_get());
+
+ if (iterator_node != nullptr && hi_node != nullptr
+ && iterator_node->value_get() > hi_node->value_get())
+ {
+ error(e.vardec_get(), "iterator initial value is higher than limit");
+ }
+
+ type_default(e, e.body_get().type_get());
+ }
+
+ void TypeChecker::operator()(ast::IfExp& e)
+ {
+ check_type(e.test_get(), "condition", Int::instance());
+
+ check_types(e, "then chunk return", e.thenclause_get(), "else chunk return",
+ e.elseclause_get());
+
+ type_default(e, e.elseclause_get().type_get());
+ }
+
+ void TypeChecker::operator()(ast::LetExp& e)
+ {
+ e.chunks_get().accept(*this);
+
+ type_default(e, type(e.body_get()));
+ }
+
+ void TypeChecker::operator()(ast::SeqExp& e)
+ {
+ if (e.exps_get().empty())
+ {
+ type_default(e, &Void::instance());
+ return;
+ }
+
+ for (ast::Exp* exp : e.exps_get())
+ {
+ type(*exp);
+ }
+
+ type_default(e, e.exps_get().back()->type_get());
+ }
+
+ void TypeChecker::operator()(ast::WhileExp& e)
+ {
+ check_type(e.test_get(), "condition", Int::instance());
+
+ check_type(e.body_get(), "while body", Void::instance());
+
+ type_default(e, e.body_get().type_get());
+ }
+
+ /*-----------------.
+ | Visiting /Dec/. |
+ `-----------------*/
+
+ /*------------------------.
+ | Visiting FunctionChunk. |
+ `------------------------*/
+
+ void TypeChecker::operator()(ast::FunctionChunk& e)
+ {
+ chunk_visit<ast::FunctionDec>(e);
+ }
+
+ void TypeChecker::operator()(ast::FunctionDec&)
+ {
+ // We must not be here.
+ unreachable();
+ }
+
+ // Store the type of this function.
+ template <>
+ void TypeChecker::visit_dec_header<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // Typing order
+ const Record* formals = type(e.formals_get());
+
+ const Type* return_type =
+ e.result_get() != nullptr ? type(*e.result_get()) : &Void::instance();
+
+ auto type = std::make_unique<Function>(formals, *return_type);
+
+ type_default(e, type.get());
+ created_type_default(e, type.release());
+ }
+
+ // Type check this function's body.
+ template <>
+ void TypeChecker::visit_dec_body<ast::FunctionDec>(ast::FunctionDec& e)
+ {
+ visit_routine_body<Function, ast::FunctionDec>(e);
+ }
+
+ /*---------------.
+ | Visit VarDec. |
+ `---------------*/
+
+ void TypeChecker::operator()(ast::VarDec& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Type* declared_type =
+ e.type_name_get() != nullptr ? type(*e.type_name_get()) : nullptr;
+
+ const Type* actual_type =
+ e.init_get() != nullptr ? type(*e.init_get()) : nullptr;
+
+ if (actual_type != nullptr && actual_type->actual() == Void::instance())
+ {
+ error(e, "VarDec type cannot be void");
+ actual_type = &default_type;
+ }
+
+ if (declared_type == nullptr)
+ {
+ if (actual_type != nullptr
+ && dynamic_cast<const Nil*>(&actual_type->actual()) != nullptr)
+ {
+ error(e, "Nil cannot be used with anonymous type declaration");
+ }
+
+ type_default(e, actual_type);
+ }
+ else
+ {
+ if (actual_type != nullptr)
+ check_types(e, "explicit variable declaration", *declared_type,
+ "init expression", *actual_type);
+
+ type_default(e, declared_type);
+ }
+ }
+
+ /*--------------------.
+ | Visiting TypeChunk. |
+ `--------------------*/
+
+ void TypeChecker::operator()(ast::TypeChunk& e)
+ {
+ chunk_visit<ast::TypeDec>(e);
+ }
+
+ void TypeChecker::operator()(ast::TypeDec&)
+ {
+ // We must not be here.
+ unreachable();
+ }
+
+ // Store this type.
+ template <> void TypeChecker::visit_dec_header<ast::TypeDec>(ast::TypeDec& e)
+ {
+ // We only process the head of the type declaration, to set its
+ // name in E. A declaration has no type in itself; here we store
+ // the type declared by E.
+ // FIXME DONE: Some code was deleted here.
+ if (e.type_get() != nullptr)
+ {
+ return;
+ }
+
+ auto type = std::make_unique<Named>(e.name_get());
+
+ type_default(e, type.get());
+ created_type_default(e, type.release());
+ }
+
+ // Bind the type body to its name.
+ template <> void TypeChecker::visit_dec_body<ast::TypeDec>(ast::TypeDec& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto named = dynamic_cast<const Named*>(e.type_get());
+
+ assertion(named != nullptr);
+
+ named->type_set(type(e.ty_get()));
+
+ if (!named->sound())
+ {
+ error(e, "infinite type reference recursion detected");
+ }
+ }
+
+ /*------------------.
+ | Visiting /Chunk/. |
+ `------------------*/
+
+ template <class D> void TypeChecker::chunk_visit(ast::Chunk<D>& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (auto var = dynamic_cast<ast::VarDec*>(e.decs_get().front());
+ var != nullptr)
+ {
+ type(*var);
+ return;
+ }
+
+ for (D* declaration : e)
+ {
+ visit_dec_header(*declaration);
+ }
+
+ for (D* declaration : e)
+ {
+ visit_dec_body(*declaration);
+ }
+
+ for (D* declaration : e)
+ {
+ if (const auto maybe_main =
+ dynamic_cast<ast::FunctionDec*>(declaration);
+ maybe_main != nullptr && maybe_main->name_get() == "_main")
+ type_main(maybe_main);
+ }
+ }
+
+ void TypeChecker::type_main(ast::FunctionDec* const e)
+ {
+ if (!e->formals_get().decs_get().empty())
+ {
+ error(*e, "_main function should have no arguments");
+ }
+
+ check_type(*e->body_get(), "_main return type", Void::instance());
+ }
+
+ /*-------------.
+ | Visit /Ty/. |
+ `-------------*/
+
+ void TypeChecker::operator()(ast::NameTy& e)
+ {
+ // FIXME DONE: Some code was deleted here (Recognize user defined types, and built-in types).
+ const Type* type = e.name_get() == "int" ? &Int::instance()
+ : e.name_get() == "string" ? &String::instance()
+ : this->type(*e.def_get());
+
+ auto named = std::make_unique<Named>(e.name_get(), type);
+
+ type_default(e, named.get());
+ created_type_default(e, named.release());
+ }
+
+ void TypeChecker::operator()(ast::RecordTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ std::unique_ptr<const Record> record(type(e.fields_get()));
+
+ type_default(e, record.get());
+ created_type_default(e, record.release());
+ }
+
+ void TypeChecker::operator()(ast::ArrayTy& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ auto array = std::make_unique<const Array>(type(e.base_type_get()));
+
+ type_default(e, array.get());
+ created_type_default(e, array.release());
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/type-checker.hh b/tiger-compiler/src/type/type-checker.hh
new file mode 100644
index 0000000..789a31f
--- /dev/null
+++ b/tiger-compiler/src/type/type-checker.hh
@@ -0,0 +1,279 @@
+/**
+ ** \file type/type-checker.hh
+ ** \brief Perform type checking and other semantical checks.
+ */
+
+#pragma once
+
+#include <cassert>
+#include <string>
+
+#include <ast/default-visitor.hh>
+#include <ast/non-assert-visitor.hh>
+#include <ast/non-object-visitor.hh>
+#include <misc/error.hh>
+#include <misc/set.hh>
+#include <type/fwd.hh>
+
+namespace type
+{
+ class TypeChecker
+ : public ast::DefaultVisitor
+ , public ast::NonObjectVisitor
+ , public ast::NonAssertVisitor
+ {
+ public:
+ using super_type = ast::DefaultVisitor;
+ using super_type::operator();
+
+ /// Construction.
+ TypeChecker();
+ /// The error handler.
+ const misc::error& error_get() const;
+
+ protected:
+ /// Run this visitor on \a e, and return its type.
+ ///
+ /// Note that it is also guaranteed that \a type_ is set to this type.
+ /// More generally, using \a type allows to avoid calling \a accept
+ /// directly.
+ const Type* type(ast::Typable& e);
+ const Record* type(const ast::fields_type& e);
+ const Record* type(const ast::VarChunk& e);
+
+ // ------------------ //
+ // Helping routines. //
+ // ------------------ //
+ protected:
+ /// \name Error handling.
+ /// \{
+
+ /// Report an error.
+ void error(const ast::Ast& ast, const std::string& msg);
+
+ /// Report an error.
+ ///
+ /// \param ast the node whose location is used in the error message
+ /// \param msg the error message
+ /// \param exp the culprit. It must support << output
+ template <typename T>
+ void error(const ast::Ast& ast, const std::string& msg, const T& exp);
+
+ /// Report an error, and recover from it.
+ ///
+ /// \param loc the node whose location is used in the error message
+ /// and whose type is set to nil as an attempt to
+ /// recover.
+ /// \param msg the error message
+ /// \param exp the culprit. It must support << output
+ template <typename T, typename U>
+ void error_and_recover(T& loc, const std::string& msg, const U& exp);
+
+ /// Report a type_mismatch between two entities.
+ /// \param ast the guilty node, used to report the location.
+ /// \param exp1 the string denoting the first exp.
+ /// \param type1 its type
+ /// \param exp2 similarly
+ /// \param type2 similarly
+ void type_mismatch(const ast::Ast& ast,
+ const std::string& exp1,
+ const Type& type1,
+ const std::string& exp2,
+ const Type& type2);
+ /// \}
+
+ /// \name Checking types.
+ /// \{
+
+ /// \brief Check the type of an Exp.
+ ///
+ /// \param e the expression/declaration to check
+ /// \param s the string to refer to \a e in error messages
+ /// (e.g., "index", "left operand" etc.).
+ /// \param t the expected type
+ ///
+ /// On failure, report the error, and set the type of \a e to \a t.
+ /// This should be used for `ast::Exp` and `ast::Dec` nodes.
+ template <typename NodeType>
+ void check_type(NodeType& e, const std::string& s, const Type& t);
+
+ /** \brief Check the type compatibility.
+ **
+ ** An error message is output if types are incompatible.
+ **
+ ** \param loc a node which location is used to report errors
+ ** \param exp1 the syntactic category of the first entity,
+ ** (used in error messages)
+ ** \param type1 the first type
+ ** \param exp2 same as above
+ ** \param type2 same as above
+ **/
+ void check_types(const ast::Ast& loc,
+ const std::string& exp1,
+ const Type& type1,
+ const std::string& exp2,
+ const Type& type2);
+ void check_types(const ast::Ast& loc,
+ const std::string& exp1,
+ ast::Typable& type1,
+ const std::string& exp2,
+ ast::Typable& type2);
+ /// \}
+
+ protected:
+ /// \name Setting types.
+ /// \{
+
+ /// Set the type of a node, if it isn't already set
+ /// (an existing type won't be overwritten).
+ ///
+ /// \param e the bound node
+ /// \param type the type
+ template <typename NodeType>
+ void type_default(NodeType& e, const type::Type* type);
+
+ /// Same as type_default, but for a created type.
+ template <typename NodeType>
+ void created_type_default(NodeType& e, const type::Type* type);
+
+ /// Set the type of a node (overwriting allowed).
+ ///
+ /// \param e the bound node
+ /// \param type the type
+ template <typename NodeType>
+ void type_set(NodeType& e, const type::Type* type);
+ /// \}
+
+ // ------------------------- //
+ // The core of the visitor. //
+ // ------------------------- //
+
+ // ---------------- //
+ // Visiting /Var/. //
+ // ---------------- //
+
+ void operator()(ast::SimpleVar& e) override;
+ // FIXME DONE: Some code was deleted here (Other Var nodes).
+ void operator()(ast::FieldVar& e) override;
+ void operator()(ast::SubscriptVar& e) override;
+
+ // ---------------- //
+ // Visiting /Exp/. //
+ // ---------------- //
+
+ // Literals.
+ void operator()(ast::NilExp&) override;
+ void operator()(ast::IntExp&) override;
+ void operator()(ast::StringExp&) override;
+
+ // Complex values.
+ void operator()(ast::RecordExp& e) override;
+ void operator()(ast::OpExp& e) override;
+ // FIXME DONE: Some code was deleted here (Other Exp nodes).
+ void operator()(ast::ArrayExp& e) override;
+ void operator()(ast::AssignExp& e) override;
+ void operator()(ast::BreakExp& e) override;
+ // I don't put MethodCallExp because it should be managed by CallExp
+ void operator()(ast::CallExp& e) override;
+ void operator()(ast::CastExp& e) override;
+ void operator()(ast::ForExp& e) override;
+ void operator()(ast::IfExp& e) override;
+ void operator()(ast::LetExp& e) override;
+ void operator()(ast::SeqExp& e) override;
+ void operator()(ast::WhileExp& e) override;
+
+ // ---------------- //
+ // Visiting /Dec/. //
+ // ---------------- //
+
+ /// \name Type and Function declarations.
+ /// \{
+
+ /// Be sure to read the documentation of
+ /// bind::Binder::chunk_visit.
+ ///
+ /// When type-checking a function (or a type) we need two
+ /// traversals: one to register the function's type (to enable
+ /// mutual recursions) and a second one to check the bodies.
+
+ /// This is why there are actually three methods: chunk_visit,
+ /// visit_dec_header, and visit_dec_body. It turns out that
+ /// chunk_visit can be written for both functions and types, but of
+ /// course, traversals of headers and bodies differ.
+
+ /// Check a set of definitions: unique names, browse headers, then
+ /// bodies.
+ template <class D> void chunk_visit(ast::Chunk<D>& e);
+
+ /// Check a Function or Type declaration header.
+ template <class D> void visit_dec_header(D& e);
+
+ /// Check a Function or Type declaration body.
+ template <class D> void visit_dec_body(D& e);
+
+ /// Generic type-checking of a routine's body.
+ template <typename Routine_Type, typename Routine_Node>
+ void visit_routine_body(Routine_Node& e);
+
+ /// Visit a chunk of function declarations.
+ void operator()(ast::FunctionChunk& e) override;
+ /// No longer used.
+ void operator()(ast::FunctionDec&) override;
+
+ /// Visit a chunk of type declarations.
+ void operator()(ast::TypeChunk& e) override;
+ /// No longer used.
+ void operator()(ast::TypeDec&) override;
+ /// \}
+
+ /// Visit a single Variable Declaration.
+ void operator()(ast::VarDec& e) override;
+
+ // --------------- //
+ // Visiting /Ty/. //
+ // --------------- //
+
+ void operator()(ast::NameTy& e) override;
+ void operator()(ast::RecordTy& e) override;
+ void operator()(ast::ArrayTy& e) override;
+
+ protected:
+ /// Error handler.
+ misc::error error_;
+ /// Set of for index variable definitions, which are read only.
+ misc::set<const ast::VarDec*> var_read_only_;
+
+ // ------------------- //
+ // Custom attributes. //
+ // ------------------- //
+
+ // Default type to use when a node is badly typed
+ const Type& default_type = Int::instance();
+
+ // ------------------- //
+ // Custom methods. //
+ // ------------------- //
+
+ /**
+ * @brief Check that the provided FunctionDec represents a valid main_
+ * function, typing-wise.
+ * @param e Node to check. It is assumed it represents a main_ function
+ */
+ void type_main(ast::FunctionDec* e);
+ };
+
+ /// Visit the lhs of an ast::FunctionDec.
+ template <>
+ void TypeChecker::visit_dec_header<ast::FunctionDec>(ast::FunctionDec& e);
+ /// Visit the rhs of an ast::FunctionDec.
+ template <>
+ void TypeChecker::visit_dec_body<ast::FunctionDec>(ast::FunctionDec& e);
+
+ /// Visit the lhs of an ast::TypeDec.
+ template <> void TypeChecker::visit_dec_header<ast::TypeDec>(ast::TypeDec& e);
+ /// Visit the rhs of an ast::TypeDec.
+ template <> void TypeChecker::visit_dec_body<ast::TypeDec>(ast::TypeDec& e);
+
+} // namespace type
+
+#include <type/type-checker.hxx>
diff --git a/tiger-compiler/src/type/type-checker.hxx b/tiger-compiler/src/type/type-checker.hxx
new file mode 100644
index 0000000..bcdf348
--- /dev/null
+++ b/tiger-compiler/src/type/type-checker.hxx
@@ -0,0 +1,127 @@
+/**
+ ** \file type/type-checker.hxx
+ ** \brief Inline methods of type::TypeChecker.
+ */
+
+#pragma once
+
+#include <ast/all.hh>
+#include <type/pretty-printer.hh>
+#include <type/type-checker.hh>
+#include <type/types.hh>
+
+namespace type
+{
+ namespace
+ {
+ const Nil nil_error_instance{};
+
+ }
+
+ /*----------------.
+ | Setting types. |
+ `----------------*/
+
+ template <typename NodeType>
+ void TypeChecker::type_default(NodeType& e, const type::Type* type)
+ {
+ // FIXME DONE: Some code was deleted here.
+ // We can check here to be sure that the type we use really is a native Tiger type
+ const auto casted = dynamic_cast<ast::Typable*>(&e);
+
+ assertion(casted != nullptr);
+
+ if (casted->type_get() != nullptr)
+ {
+ return;
+ }
+
+ type_set(e, type);
+ }
+
+ template <typename NodeType>
+ void TypeChecker::created_type_default(NodeType& e, const type::Type* type)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto casted = dynamic_cast<ast::TypeConstructor*>(&e);
+
+ assertion(casted != nullptr);
+
+ if (casted->created_type_get() != nullptr)
+ {
+ return;
+ }
+
+ casted->created_type_set(type);
+ }
+
+ template <typename NodeType>
+ void TypeChecker::type_set(NodeType& e, const type::Type* type)
+ {
+ // FIXME DONE: Some code was deleted here (Basically e.type_set(type)).
+ const auto casted = dynamic_cast<ast::Typable*>(&e);
+
+ assertion(casted != nullptr);
+
+ casted->type_set(type);
+ }
+
+ /*-----------------.
+ | Error handling. |
+ `-----------------*/
+
+ template <typename T>
+ void
+ TypeChecker::error(const ast::Ast& ast, const std::string& msg, const T& exp)
+ {
+ error_ << misc::error::error_type::type << ast.location_get() << ": " << msg
+ << ": " << exp << std::endl;
+ }
+
+ template <typename T, typename U>
+ void
+ TypeChecker::error_and_recover(T& loc, const std::string& msg, const U& exp)
+ {
+ error(loc, msg, exp);
+ loc.type_set(&nil_error_instance);
+ }
+
+ template <typename NodeType>
+ void TypeChecker::check_type(NodeType& e,
+ const std::string& s,
+ const Type& t)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const auto casted = dynamic_cast<ast::Typable*>(&e);
+
+ assertion(casted != nullptr);
+
+ if (type(*casted)->actual() == t)
+ return;
+
+ type_mismatch(e, s, *casted->type_get(), "expected", t);
+ }
+
+ /*------------.
+ | Functions. |
+ `------------*/
+
+ template <typename Routine_Type, typename Routine_Node>
+ void TypeChecker::visit_routine_body(Routine_Node& e)
+ {
+ // FIXME DONE: Some code was deleted here.
+ if (e.body_get() == nullptr)
+ return;
+ type(*e.body_get());
+ if (e.type_get())
+ {
+ auto rt = dynamic_cast<const Routine_Type*>(e.type_get());
+ check_types(e, "routine", rt->result_get(), "body", *e.body_get()->type_get());
+ }
+ else
+ {
+ created_type_default(e, e.body_get()->type_get());
+ }
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/type.cc b/tiger-compiler/src/type/type.cc
new file mode 100644
index 0000000..e0e448d
--- /dev/null
+++ b/tiger-compiler/src/type/type.cc
@@ -0,0 +1,18 @@
+/**
+ ** \file type/type.cc
+ ** \brief Implementation for type/type.hh.
+ */
+
+#include <ostream>
+
+#include <type/type.hh>
+
+namespace type
+{
+ const Type& Type::actual() const { return *this; }
+
+ bool Type::compatible_with(const Type& other) const { return *this == other; }
+
+ const misc::xalloc<bool> hide_actual_types;
+
+} // namespace type
diff --git a/tiger-compiler/src/type/type.hh b/tiger-compiler/src/type/type.hh
new file mode 100644
index 0000000..a5f9777
--- /dev/null
+++ b/tiger-compiler/src/type/type.hh
@@ -0,0 +1,66 @@
+/**
+ ** \file type/type.hh
+ ** \brief The class Type.
+ */
+#pragma once
+
+#include <misc/xalloc.hh>
+#include <type/fwd.hh>
+
+namespace type
+{
+ /// Abstract a type.
+ class Type
+ {
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /// Destroys a Type.
+ virtual ~Type() = default;
+ /** \} */
+
+ /// \name Visitors entry point.
+ /// \{ */
+ /// Accept a const visitor \a v.
+ virtual void accept(ConstVisitor& v) const = 0;
+ /// Accept a non-const visitor \a v.
+ virtual void accept(Visitor& v) = 0;
+ /// \}
+
+ /** \name Accessors.
+ ** \{ */
+ /// Return the actual type held by THIS.
+ virtual const Type& actual() const;
+ /** \} */
+
+ /** \brief Whether two types are "compatible".
+ **
+ ** I.e., whether "a = b", "a <> b", "a := b" are correctly typed
+ ** with a of type \a this, and b of type \a other).
+ **
+ ** By default two types are compatible (in the sense of "=" and "<>",
+ ** not w.r.t. an order) only when they are equal.
+ **
+ ** In the case of assignment, "rec := nil" is valid, but "nil := rec"
+ ** is not, which suggest that we should have a non commutative
+ ** assignment specific compatibility check. But since "nil := ..."
+ ** is incorrect syntactically, that is not needed.
+ */
+ virtual bool compatible_with(const Type& other) const;
+ };
+
+ /** \brief Compare two Type s.
+ **
+ ** Return true if \a a and \a b are equivalent Tiger Types. E.g.,
+ ** if \a a and \a b are different but point to the same type, then
+ ** return true. */
+ bool operator==(const Type& lhs, const Type& rhs);
+ /// !(a == b).
+ bool operator!=(const Type& lhs, const Type& rhs);
+
+ /// Hide actual types? (i.e., print only the surface type?)
+ extern const misc::xalloc<bool> hide_actual_types;
+
+} // namespace type
+
+#include <type/type.hxx>
diff --git a/tiger-compiler/src/type/type.hxx b/tiger-compiler/src/type/type.hxx
new file mode 100644
index 0000000..392c854
--- /dev/null
+++ b/tiger-compiler/src/type/type.hxx
@@ -0,0 +1,37 @@
+/**
+ ** \file type/type.hxx
+ ** \brief Inline methods for type::Type.
+ */
+#pragma once
+
+#include <misc/contract.hh>
+#include <type/type.hh>
+
+namespace type
+{
+ inline bool operator==(const Type& lhs, const Type& rhs)
+ {
+ // FIXME DONE: Some code was deleted here.
+ const Type* lhs_primal = &lhs.actual();
+ const Type* rhs_primal = &rhs.actual();
+
+ while (&rhs_primal->actual() != rhs_primal && rhs_primal != lhs_primal)
+ {
+ rhs_primal = &rhs_primal->actual();
+ }
+
+ while (&lhs_primal->actual() != lhs_primal && lhs_primal != rhs_primal)
+ {
+ lhs_primal = &lhs_primal->actual();
+ }
+
+ return lhs_primal == rhs_primal;
+ }
+
+ inline bool operator!=(const Type& lhs, const Type& rhs)
+ {
+ // FIXME DONE: Some code was deleted here.
+ return !(lhs == rhs);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/type/types.hh b/tiger-compiler/src/type/types.hh
new file mode 100644
index 0000000..b0d3771
--- /dev/null
+++ b/tiger-compiler/src/type/types.hh
@@ -0,0 +1,18 @@
+/**
+ ** \file type/types.hh
+ ** \brief Include all exported headers.
+ */
+
+#pragma once
+
+#include <type/array.hh>
+// FIXME: We should include "attribute.hh" and "class.hh" as well, but
+// currently that would break the compilation (because of recursive
+// dependencies). Investigate and fix this.
+#include <type/builtin-types.hh>
+#include <type/field.hh>
+#include <type/function.hh>
+#include <type/named.hh>
+#include <type/nil.hh>
+#include <type/record.hh>
+#include <type/type.hh>
diff --git a/tiger-compiler/src/type/visitor.hh b/tiger-compiler/src/type/visitor.hh
new file mode 100644
index 0000000..4e78ec0
--- /dev/null
+++ b/tiger-compiler/src/type/visitor.hh
@@ -0,0 +1,57 @@
+/**
+ ** \file type/visitor.hh
+ ** \brief Definition of type::Visitor.
+ */
+#pragma once
+
+#include <misc/select-const.hh>
+#include <type/fwd.hh>
+
+namespace type
+{
+ /** \brief Root class of all Type visitors.
+ **
+ ** GenVisitor<CONSTIFY> is the root class of all Type visitors. */
+ template <template <typename> class Const> class GenVisitor
+ {
+ /** \name Ctor & dtor.
+ ** \{ */
+ public:
+ /// Convenient abbreviation.
+ template <typename T> using const_t = typename Const<T>::type;
+
+ /// Destroy a GenVisitor.
+ virtual ~GenVisitor();
+ /** \} */
+
+ /// The entry point: visit \a e.
+ virtual void operator()(const_t<Type>& e);
+ virtual void operator()(const_t<Nil>&) = 0;
+ virtual void operator()(const_t<Void>&) = 0;
+ virtual void operator()(const_t<Int>&) = 0;
+ virtual void operator()(const_t<String>&) = 0;
+ virtual void operator()(const_t<Named>&) = 0;
+ virtual void operator()(const_t<Array>&) = 0;
+ virtual void operator()(const_t<Record>&) = 0;
+ virtual void operator()(const_t<Class>&) = 0;
+ virtual void operator()(const_t<Function>&) = 0;
+ virtual void operator()(const_t<Method>&) = 0;
+
+ /// Helper to visit nodes manipulated via a pointer.
+ template <class E> void operator()(E* e);
+ };
+
+ /// Shorthand for a const visitor.
+ using ConstVisitor = GenVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ using Visitor = GenVisitor<misc::id_traits>;
+
+#ifdef SWIG
+ /// Shorthand for a const visitor.
+ %template(GenConstVisitor) GenVisitor<misc::constify_traits>;
+ /// Shorthand for a non const visitor.
+ %template(GenVisitor) GenVisitor<misc::id_traits>;
+#endif
+} // namespace type
+
+#include <type/visitor.hxx>
diff --git a/tiger-compiler/src/type/visitor.hxx b/tiger-compiler/src/type/visitor.hxx
new file mode 100644
index 0000000..93a0f9b
--- /dev/null
+++ b/tiger-compiler/src/type/visitor.hxx
@@ -0,0 +1,29 @@
+/**
+ ** \file type/visitor.hxx
+ ** \brief Definition of type::Visitor.
+ */
+
+#pragma once
+
+#include <type/type.hh>
+#include <type/visitor.hh>
+
+namespace type
+{
+ template <template <typename> class Const>
+ GenVisitor<Const>::~GenVisitor() = default;
+
+ template <template <typename> class Const>
+ void GenVisitor<Const>::operator()(const_t<Type>& e)
+ {
+ e.accept(*this);
+ }
+
+ template <template <typename> class Const>
+ template <class E>
+ void GenVisitor<Const>::operator()(E* e)
+ {
+ e->accept(*this);
+ }
+
+} // namespace type
diff --git a/tiger-compiler/src/version.cc.in b/tiger-compiler/src/version.cc.in
new file mode 100644
index 0000000..24d699c
--- /dev/null
+++ b/tiger-compiler/src/version.cc.in
@@ -0,0 +1,34 @@
+/** -*- C++ -*-
+ ** \file version.cc
+ ** \brief Common definitions.
+ */
+
+#include <config.h>
+#include <authors.h>
+
+
+/*-------------------.
+| Program identity. |
+`-------------------*/
+
+/** Name of this program.
+
+Be sure to have something usable even before main is started,
+in case some ctor of a static object need to issue an error
+message. */
+const char *program_name = PACKAGE_NAME;
+
+// Version string of this program.
+const char *program_version =
+"tc (" PACKAGE_STRING ")\n"
+"@ID@\n"
+"\n"
+PACKAGE_SHORT_AUTHORS;
+
+// Bug report address of this program.
+const char *program_bug_address = PACKAGE_BUGREPORT;
+
+/// Describe program and accepted arguments.
+const char *program_doc =
+ "Tiger Compiler, Copyright (C) 2004-2021 LRDE.";
+const char *program_args_doc = "INPUT-FILE";
diff --git a/tiger-compiler/src/version.hh b/tiger-compiler/src/version.hh
new file mode 100644
index 0000000..c535db1
--- /dev/null
+++ b/tiger-compiler/src/version.hh
@@ -0,0 +1,23 @@
+/**
+ ** \file src/version.hh
+ ** \brief Version definitions.
+ */
+
+#pragma once
+
+/// \name Program identity.
+/// \{
+/// Name of this program.
+extern const char* program_name;
+
+/// Version string of this program.
+extern const char* program_version;
+
+/// Bug report address of this program.
+extern const char* program_bug_address;
+
+/// Describe program and accepted arguments.
+extern const char* program_doc;
+extern const char* program_args_doc;
+
+/// \}