diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /tiger-compiler/tcsh | |
Diffstat (limited to 'tiger-compiler/tcsh')
42 files changed, 5514 insertions, 0 deletions
diff --git a/tiger-compiler/tcsh/Makefile.am b/tiger-compiler/tcsh/Makefile.am new file mode 100644 index 0000000..2c2c1f9 --- /dev/null +++ b/tiger-compiler/tcsh/Makefile.am @@ -0,0 +1,5 @@ +SUBDIRS = python + +EXTRA_DIST = README-deps.txt generate-swig-mk src + +check_SCRIPTS = run diff --git a/tiger-compiler/tcsh/README-deps.txt b/tiger-compiler/tcsh/README-deps.txt new file mode 100644 index 0000000..8e3fa60 --- /dev/null +++ b/tiger-compiler/tcsh/README-deps.txt @@ -0,0 +1,49 @@ +* Handling dependencies of SWIG-generated files. -*- outline -*- + + +** The problem with non-Automade dependencies + +Sometimes, the dependencies computed by swig in tcsh/python/.deps and +tcsh/ruby/.deps are void because of some changes in the build +environment (e.g., SWIG has been installed somewhere else since the +last build, and dependencies on SWIG's .swg files are no longer +valid). Hence SWIG wrappers won't build, because of unmet +dependencies. + +_build % make -C tcsh/ruby +make: Entering directory `/home/levill_r/src/tc/_build/tcsh/ruby' +make: *** No rule to make target `/home/levill_r/local/share/swig/1.3.29/swig.swg', needed by `tiger_misc-wrap.cc'. Stop. +make: Leaving directory `/home/levill_r/src/tc/_build/tcsh/ruby' + +In the previous example, I (Roland) wasn't able to build TCSH/Ruby +because I had updated from SWIG 1.3.29 (installed locally) to 1.3.31 +(provided by Debian). + +** Solution + +Our approach is to provide a target to reset the dependencies (i.e., +to set them to the initial state set by `configure'). `make +deps-reset' provides that service, erasing dependencies generated by +swig. + +_build % make -C tcsh/ruby deps-reset +make: Entering directory `/home/levill_r/src/tc/_build/tcsh/ruby' +make: Leaving directory `/home/levill_r/src/tc/_build/tcsh/ruby' + +The build can then proceed. + +_build % make -C tcsh/ruby +make: Entering directory `/home/levill_r/src/tc/_build/tcsh/ruby' +if /usr/bin/swig -c++ -ruby -I../../../lib -I../../../src -MD -MF ".deps/tiger_misc-wrap.Tcc" -o tiger_misc-wrap.cc ../../../lib/misc/tiger_misc.i; \ + then \ + mv -f ".deps/tiger_misc-wrap.Tcc" ".deps/tiger_misc-wrap.Pcc"; \ + else \ + rm -f ".deps/tiger_misc-wrap.Tcc"; exit 1; \ + fi + +[...] + + +Note: I don't know whether Automake is smart enough to handle this +problem gracefully with the dependencies it already handles. If so, +please tell us! diff --git a/tiger-compiler/tcsh/generate-swig-mk b/tiger-compiler/tcsh/generate-swig-mk new file mode 100755 index 0000000..200d98b --- /dev/null +++ b/tiger-compiler/tcsh/generate-swig-mk @@ -0,0 +1,101 @@ +#! /bin/sh + +if test $# -ne 2; then + echo "Usage: $0 python filename" >&2 + exit 1 +fi + +if test "x$1" != xpython; then + echo "$0: first argument must be \`python'" + exit 1 +fi + +if test -z "$top_srcdir"; then + echo "$0: top_srcdir undefined" >&2 + exit 1 +fi + +lang=$1 + +# Connect stdout to the output file. +exec >$2 + +cat <<EOF +## Generated by $0. Do not edit by hand! + +AM_LDFLAGS = -avoid-version -module -shared +AM_LIBADD = \$(top_builddir)/src/libtc.la +tcdir = \$(top_srcdir) + +CLEANFILES = + +# The list of dependencies generated as a side-effect of running swig. +SWIG_GENERATED_DEPS = + +EOF +case $lang in + python) echo "nodist_python_PYTHON =" ;; +esac + +# Compile swig modules. +case $lang in + python) mod_dir=pyexec ;; +esac +for src in $(find $top_srcdir/tcsh/src -name '*.i' | + sed -e 's:'"$top_srcdir"':$(tcdir):') +do + base=$(basename $src ".i") + module=$(echo $base | sed -e 's/tiger_//') + modulepath=$(dirname $src) + dest=$base-wrap.cc + case $lang in + python) + ltmodule=_tiger_$module + cleanfiles="$dest $base.py $base.pyc" + ;; + esac + # No $< and $@ here because NetBSD make does not like it. Two + # rules, because two outputs from a single input does not fit Make's + # model. See automake.info "Multiple Outputs". + cat <<EOF + +## Module: $module. +${mod_dir}_LTLIBRARIES += $ltmodule.la +nodist_${ltmodule}_la_SOURCES = $dest +${ltmodule}_la_LIBADD = \$(AM_LIBADD) +CLEANFILES += $cleanfiles +$dest: $src + \$(AM_V_GEN)if \$(SWIG) \$(AM_SWIGFLAGS) \$(SWIGFLAGS) -MD -MF "\$(DEPDIR)/$base-wrap.Tcc" -o $dest $src; \\ + then \\ + mv -f "\$(DEPDIR)/$base-wrap.Tcc" "\$(DEPDIR)/$base-wrap.Pcc"; \\ + else \\ + rm -f "\$(DEPDIR)/$base-wrap.Tcc"; exit 1; \\ + fi + +@AMDEP_TRUE@@am__include@ @am__quote@./\$(DEPDIR)/$base-wrap.Pcc@am__quote@ + +@AMDEP_TRUE@ SWIG_GENERATED_DEPS += ./\$(DEPDIR)/$base-wrap.Pcc + +EOF + case $lang in + python) cat <<EOF +nodist_python_PYTHON += $base.py +$base.py: $src + \$(AM_V_GEN)\$(MAKE) \$(AM_MAKEFLAGS) $dest +EOF + ;; + esac +done +cat <<EOF + + +# Target \`deps-reset' re-initializes the dependencies generated as a +# side-effect of running swig. +.PHONY: deps-reset +deps-reset: + @list='\$(SWIG_GENERATED_DEPS)'; for d in \$\$list; do \\ + echo '# dummy' > \$\$d; \\ + done + + +EOF diff --git a/tiger-compiler/tcsh/python/Makefile.am b/tiger-compiler/tcsh/python/Makefile.am new file mode 100644 index 0000000..442b582 --- /dev/null +++ b/tiger-compiler/tcsh/python/Makefile.am @@ -0,0 +1,60 @@ +## ------------------------ ## +## Included sub makefiles. ## +## ------------------------ ## + +include $(top_srcdir)/tcsh/run.mk + +pyexec_LTLIBRARIES = + +# Build a Swig wrapper for each module. +$(srcdir)/swig.mk: $(top_srcdir)/tcsh/generate-swig-mk + $(AM_V_GEN)top_srcdir="$(top_srcdir)" $< python $@.tmp + $(AM_V_at)mv -f $@.tmp $@ + $(AM_V_at)chmod -w $@ +include $(srcdir)/swig.mk + +AM_CPPFLAGS = \ + -I$(top_srcdir)/lib -I$(top_srcdir)/src -I$(top_builddir)/src \ + -I$(top_srcdir)/tcsh/src \ + $(BOOST_CPPFLAGS) \ + -I$(PYTHONINC) +AM_SWIGFLAGS = -c++ -python -py3 -I$(top_srcdir)/lib -I$(top_srcdir)/src + +# Tiger Compiler module loader. +python_PYTHON = tc.py +# Tiger interpreter. +python_PYTHON += ti.py + + + +## --------- ## +## Testing. ## +## --------- ## + +EXTRA_DIST = $(TESTS) +EXTRA_DIST += $(srcdir)/tests/ipynbtest.py + +TESTS_ENVIRONMENT = \ + top_srcdir="$(top_srcdir)" top_builddir="$(top_builddir)" +# Ensure `run' is rebuilt before the tests are run. +$(TESTS): $(srcdir)/run.stamp +# The dependency is on `run.in' and not `run', since `run' is +# regenerated at distribution time, and voids the time stamps (which +# we don't want!). +EXTRA_DIST += $(srcdir)/run.stamp +$(srcdir)/run.stamp: $(RUN_IN) + $(AM_V_GEN)rm -f $@ $@.tmp + $(AM_V_at)touch $@.tmp + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) $(RUN) + $(AM_V_at)mv -f $@.tmp $@ + +TESTS = +TESTS += tcsh-llvm.test + +LOG_COMPILER = $(srcdir)/../run +TESTS += tests/tc.ipynb tests/ti.ipynb tests/misc.ipynb tests/common.ipynb \ + tests/parse.ipynb tests/object.ipynb +TESTS += tests/ast.ipynb +TESTS += tests/bind.ipynb tests/escapes.ipynb +TESTS += tests/type.ipynb tests/astclone.ipynb tests/desugar.ipynb +TESTS += tests/combine.ipynb diff --git a/tiger-compiler/tcsh/python/tc.py b/tiger-compiler/tcsh/python/tc.py new file mode 100644 index 0000000..095e79c --- /dev/null +++ b/tiger-compiler/tcsh/python/tc.py @@ -0,0 +1,97 @@ +# Tiger Compiler module loader. + +import importlib + +from enum import Enum +from typing import List, Literal + + +class BackendType(Enum): + llvm: Literal["llvm"] = "llvm" + mips: Literal["mips"] = "mips" + + +def try_import(prefix: str, modules: List[str]): + for mod in modules: + mod_name = prefix + mod + try: + globals()[mod] = importlib.import_module(mod_name) + except: + pass + + +# Query tc for a module. +def has(module_name: str) -> bool: + return module_name in globals() + + +try_import( + "tiger_", + [ + "misc", + "common", + "parse", + "object", + "ast", + "bind", + "escapes", + "type", + "combine", + "astclone", + "desugar", + "overload", + "llvmtranslate", + ], +) + +# Shortcuts +Cout = common.cvar.Cout +Cerr = common.cvar.Cerr +Ofstream = common.Ofstream + +# Load IPython specific support if we can. +try: + # Load only if we are running IPython. + from IPython import get_ipython + from IPython.core.magic import Magics, magics_class, cell_magic + import os + import sys + import tempfile + + import ti + + @magics_class + class TigerMagics(Magics): + @cell_magic + def tiger(self, line, cell): + if not line: + print(self.__doc__, file=sys.stderr) + return + backend = BackendType("mips") + line = line.split() + if len(line) == 2 and line[1] in [e.value for e in BackendType]: + backend = BackendType(line[1]) + elif len(line) > 1: + print(self.__doc__, file=sys.stderr) + return + with tempfile.NamedTemporaryFile(dir=".", suffix=".tig") as t: + t.write(cell.encode("utf-8")) + t.flush() + executor = ti.TiExecutor(t.name, exit_on_error=False, backend=backend) + executor.backend_get() + self.shell.user_ns[line[0]] = executor.data + + TigerMagics.__doc__ = ( + "%%tiger variable_name [backend]\n" + "variable_name is the name of the finale variable\n" + "backend is optional and must be in [{}]".format( + ", ".join((e.value for e in BackendType)) + ) + ) + + ip = get_ipython() + if ip: + ip.register_magics(TigerMagics) + +except (ImportError, NameError) as e: + pass diff --git a/tiger-compiler/tcsh/python/tcsh-hir.test b/tiger-compiler/tcsh/python/tcsh-hir.test new file mode 100755 index 0000000..b341457 --- /dev/null +++ b/tiger-compiler/tcsh/python/tcsh-hir.test @@ -0,0 +1,8 @@ +#! /bin/sh + +set -e + +testsdir=$top_srcdir/tests +run=$top_builddir/tcsh/run + +$run $srcdir/ti.py -b hir $testsdir/good/fact.tig diff --git a/tiger-compiler/tcsh/python/tcsh-llvm.test b/tiger-compiler/tcsh/python/tcsh-llvm.test new file mode 100755 index 0000000..bb72672 --- /dev/null +++ b/tiger-compiler/tcsh/python/tcsh-llvm.test @@ -0,0 +1,8 @@ +#! /bin/sh + +set -e + +testsdir=$top_srcdir/tests +run=$top_builddir/tcsh/run + +$run $srcdir/ti.py -b llvm $testsdir/good/fact.tig diff --git a/tiger-compiler/tcsh/python/tests/ast.ipynb b/tiger-compiler/tcsh/python/tests/ast.ipynb new file mode 100644 index 0000000..51f06ee --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/ast.ipynb @@ -0,0 +1,394 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and Ast" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"ast\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_ast\n", + "tiger_ast == tc.ast" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Ast Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['ArrayExp',\n", + " 'ArrayTy',\n", + " 'AssignExp',\n", + " 'Ast',\n", + " 'AstConstVisitor',\n", + " 'AstVisitor',\n", + " 'BreakExp',\n", + " 'CallExp',\n", + " 'CallbackVisitor',\n", + " 'CallbackVisitor_Argument',\n", + " 'CastExp',\n", + " 'ChunkInterface',\n", + " 'ChunkList',\n", + " 'ClassTy',\n", + " 'Dec',\n", + " 'Exp',\n", + " 'Field',\n", + " 'FieldInit',\n", + " 'FieldVar',\n", + " 'ForExp',\n", + " 'FunctionChunk',\n", + " 'FunctionDec',\n", + " 'IfExp',\n", + " 'IntExp',\n", + " 'LetExp',\n", + " 'MethodCallExp',\n", + " 'MethodChunk',\n", + " 'MethodDec',\n", + " 'NameTy',\n", + " 'NilExp',\n", + " 'ObjectExp',\n", + " 'OpExp',\n", + " 'RecordExp',\n", + " 'RecordTy',\n", + " 'SeqExp',\n", + " 'SimpleVar',\n", + " 'StringExp',\n", + " 'SubscriptVar',\n", + " 'SwigPyIterator',\n", + " 'Ty',\n", + " 'TypeChunk',\n", + " 'TypeDec',\n", + " 'Var',\n", + " 'VarChunk',\n", + " 'VarDec',\n", + " 'WhileExp']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def ignore(e):\n", + " if e.startswith(\"_\") or not e[0] == e[0].upper():\n", + " return False\n", + " return e not in (\"Escapable\", \"Typable\", \"TypeConstructor\")\n", + "list(filter(ignore, dir(tc.ast)))" + ] + }, + { + "cell_type": "markdown", + "id": "c2ffa10b", + "metadata": {}, + "source": [ + "# Tiger Magics and AST" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "eecfc7a6", + "metadata": {}, + "outputs": [], + "source": [ + "%%tiger executor\n", + "let\n", + " var b := 5\n", + "in\n", + " print_int(b)\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2d1e6475", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "ast = executor.ast\n", + "print(type(ast))" + ] + }, + { + "cell_type": "markdown", + "id": "89fbcdc9", + "metadata": {}, + "source": [ + "# Parse Ast\n", + "We use this to only parse the ast and don't run code after TC2, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).parse()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "0276768a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "primitive print(string : string)\n", + "primitive print_err(string : string)\n", + "primitive print_int(int : int)\n", + "primitive flush()\n", + "primitive getchar() : string\n", + "primitive ord(string : string) : int\n", + "primitive chr(code : int) : string\n", + "primitive size(string : string) : int\n", + "primitive streq(s1 : string, s2 : string) : int\n", + "primitive strcmp(s1 : string, s2 : string) : int\n", + "primitive substring(string : string, start : int, length : int) : string\n", + "primitive concat(fst : string, snd : string) : string\n", + "primitive not(boolean : int) : int\n", + "primitive exit(status : int)\n", + "function _main() =\n", + " (\n", + " let\n", + " var b := 5\n", + " in\n", + " print_int(b)\n", + " end;\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "print(ast)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e9856080", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.FunctionChunk'>\n", + "<class 'tiger_ast.FunctionDec'>\n", + "\n", + "function _main() =\n", + " (\n", + " let\n", + " var b := 5\n", + " in\n", + " print_int(b)\n", + " end;\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "main_chunk = ast[1]\n", + "print(type(main_chunk))\n", + "main_function = main_chunk[0]\n", + "print(type(main_function))\n", + "print(str(main_function))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "51de4ce3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.SeqExp'>\n", + "<class 'tiger_ast.LetExp'>\n", + "let\n", + " var b := 5\n", + "in\n", + " print_int(b)\n", + "end\n" + ] + } + ], + "source": [ + "main_body = main_function.body_get()\n", + "print(type(main_body))\n", + "let = main_body.exps_get()[0]\n", + "print(type(let))\n", + "print(let)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "1428a492", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.VarChunk'>\n", + "<class 'tiger_ast.VarDec'>\n", + "\n", + "var b := 5\n", + "b -> 5\n" + ] + } + ], + "source": [ + "var_chk = let.chunks_get()[0]\n", + "print(type(var_chk))\n", + "var_b = var_chk[0]\n", + "print(type(var_b))\n", + "print(var_b)\n", + "print(\"{} -> {}\".format(var_b.name_get(), var_b.init_get()))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "d9796c32", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.CallExp'>\n", + "print_int(b)\n", + "<class 'tiger_ast.SimpleVar'>\n", + "b\n" + ] + } + ], + "source": [ + "print_call = let.body_get()\n", + "print(type(print_call))\n", + "print(print_call)\n", + "print_arg = print_call.args_get()[0]\n", + "print(type(print_arg))\n", + "print(print_arg)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/astclone.ipynb b/tiger-compiler/tcsh/python/tests/astclone.ipynb new file mode 100644 index 0000000..924260b --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/astclone.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b8caa27f", + "metadata": {}, + "source": [ + "# Import Tiger and AstClone" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"astclone\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_astclone\n", + "tiger_astclone == tc.astclone" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Ast Clone Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['clone']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.astclone)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Clone Ast\n", + "We use this to only parse the ast and don't run code after TC4, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).type()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "29d68680", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n", + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "cloned_ast = tc.astclone.clone(ast)\n", + "print(ast == cloned_ast)\n", + "print(str(ast) == str(cloned_ast))\n", + "print(type(cloned_ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5f1cb3e7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "primitive print(string : string)\n", + "primitive print_err(string : string)\n", + "primitive print_int(int : int)\n", + "primitive flush()\n", + "primitive getchar() : string\n", + "primitive ord(string : string) : int\n", + "primitive chr(code : int) : string\n", + "primitive size(string : string) : int\n", + "primitive streq(s1 : string, s2 : string) : int\n", + "primitive strcmp(s1 : string, s2 : string) : int\n", + "primitive substring(string : string, start : int, length : int) : string\n", + "primitive concat(fst : string, snd : string) : string\n", + "primitive not(boolean : int) : int\n", + "primitive exit(status : int)\n", + "function _main() =\n", + " (\n", + " let\n", + " var b := 5\n", + " in\n", + " print_int(b)\n", + " end;\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "print(cloned_ast)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/bind.ipynb b/tiger-compiler/tcsh/python/tests/bind.ipynb new file mode 100644 index 0000000..f2ceafe --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/bind.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and bind" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"bind\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_bind\n", + "tiger_bind == tc.bind" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Bind Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['bind', 'rename']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.bind)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Bind Ast\n", + "We use this to only parse the ast and don't run code after TC3, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).bind()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "703bb878", + "metadata": {}, + "outputs": [], + "source": [ + "# all variables are identical to ast.ipynb \n", + "main_chunk = ast[1]\n", + "main_function = main_chunk[0]\n", + "main_body = main_function.body_get()\n", + "let = main_body.exps_get()[0]\n", + "var_chk = let.chunks_get()[0]\n", + "var_b = var_chk[0]\n", + "print_call = let.body_get()\n", + "print_arg = print_call.args_get()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "991c55bf", + "metadata": {}, + "outputs": [], + "source": [ + "def find_builtin(ast: tc.ast.ChunkList, name: str):\n", + " key = tc.misc.symbol(name)\n", + " for fns in ast[0]:\n", + " if fns.name_get() == key:\n", + " return fns\n", + " return None" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "a0fc3d00", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.FunctionDec'> \n", + "primitive print_int(int : int)\n", + "True\n", + "True\n", + "False\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "ref_print_int = print_call.def_get()\n", + "print(type(ref_print_int), str(ref_print_int))\n", + "\n", + "builtin_print_int = find_builtin(ast, \"print_int\")\n", + "builtin_print = find_builtin(ast, \"print\")\n", + "\n", + "print(ref_print_int == builtin_print_int)\n", + "print(builtin_print_int == ref_print_int)\n", + "print(ref_print_int == builtin_print)\n", + "print(builtin_print == ref_print_int)\n", + "\n", + "print(print_arg.def_get() == var_b)" + ] + }, + { + "cell_type": "markdown", + "id": "3c997fb0", + "metadata": {}, + "source": [ + "# Bind Rename" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "ff0b5358", + "metadata": {}, + "outputs": [], + "source": [ + "tc.bind.rename(ast)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fcccea94", + "metadata": {}, + "outputs": [], + "source": [ + "# all variables are identical to ast.ipynb \n", + "main_chunk = ast[1]\n", + "main_function = main_chunk[0]\n", + "main_body = main_function.body_get()\n", + "let = main_body.exps_get()[0]\n", + "var_chk = let.chunks_get()[0]\n", + "var_b = var_chk[0]\n", + "print_call = let.body_get()\n", + "print_arg = print_call.args_get()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "1ba1374c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "False\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "ref_print_int = print_call.def_get()\n", + "builtin_print_int = find_builtin(ast, \"print_int\")\n", + "builtin_print = find_builtin(ast, \"print\")\n", + "\n", + "print(ref_print_int == builtin_print_int)\n", + "print(builtin_print_int == ref_print_int)\n", + "print(ref_print_int == builtin_print)\n", + "print(builtin_print == ref_print_int)\n", + "\n", + "print(print_arg.def_get() == var_b)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/combine.ipynb b/tiger-compiler/tcsh/python/tests/combine.ipynb new file mode 100644 index 0000000..c97c28a --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/combine.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b8caa27f", + "metadata": {}, + "source": [ + "# Import Tiger and combine" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"combine\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_combine\n", + "tiger_combine == tc.combine" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Combine Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['combine_bind', 'combine_types_check']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.combine)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Combine Ast\n", + "We use this to only parse the ast and don't run code after TC4, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).type()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "29d68680", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tuple'>\n" + ] + } + ], + "source": [ + "pair = tc.combine.combine_bind(ast, True)\n", + "print(type(pair))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "46abfec6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<Swig Object of type 'overload::overfun_bindings_type *' at 0x7fb2c1d50810> <class 'tiger_misc.error'>\n", + "\n" + ] + } + ], + "source": [ + "overfun_bindings_get, error = pair\n", + "print(repr(overfun_bindings_get), type(error))\n", + "print(error)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e8f0ee43", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "error = tc.combine.combine_types_check(ast, overfun_bindings_get, True)\n", + "print(error)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/common.ipynb b/tiger-compiler/tcsh/python/tests/common.ipynb new file mode 100644 index 0000000..a2ee8ac --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/common.ipynb @@ -0,0 +1,154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and Common" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"common\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_common\n", + "tiger_common == tc.common" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Common Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Ofstream', 'cvar', 'get_cerr', 'get_cout']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\"), dir(tc.common)))" + ] + }, + { + "cell_type": "markdown", + "id": "c2ffa10b", + "metadata": {}, + "source": [ + "# Common Ofstrem" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<Swig Object of type 'std::ostream *' at 0x7f812c0f0750>\n" + ] + } + ], + "source": [ + "import os\n", + "import tempfile\n", + "\n", + "# Create file\n", + "f = tempfile.NamedTemporaryFile(delete=False)\n", + "f.write(b\"let in end\")\n", + "f.close()\n", + "\n", + "# Open a C++ ostream\n", + "ostream = tc.common.Ofstream(f.name)\n", + "print(ostream.to())\n", + "\n", + "# Delete file\n", + "os.unlink(f.name)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/desugar.ipynb b/tiger-compiler/tcsh/python/tests/desugar.ipynb new file mode 100644 index 0000000..3e6417f --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/desugar.ipynb @@ -0,0 +1,343 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b8caa27f", + "metadata": {}, + "source": [ + "# Import Tiger and Desugar" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"desugar\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_desugar\n", + "tiger_desugar == tc.desugar" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Desugar Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['desugar', 'raw_desugar']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.desugar)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Desugar Ast\n", + "We use this to only parse the ast and don't run code after TC4, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"for i := 1 to 10 do (i; ())\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).type()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d0e05897", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "primitive print(string : string)\n", + "primitive print_err(string : string)\n", + "primitive print_int(int : int)\n", + "primitive flush()\n", + "primitive getchar() : string\n", + "primitive ord(string : string) : int\n", + "primitive chr(code : int) : string\n", + "primitive size(string : string) : int\n", + "primitive streq(s1 : string, s2 : string) : int\n", + "primitive strcmp(s1 : string, s2 : string) : int\n", + "primitive substring(string : string, start : int, length : int) : string\n", + "primitive concat(fst : string, snd : string) : string\n", + "primitive not(boolean : int) : int\n", + "primitive exit(status : int)\n", + "function _main() =\n", + " (\n", + " (for i := 1 to 10 do\n", + " (\n", + " i;\n", + " ()\n", + " ));\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "print(ast)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "29d68680", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function tiger_desugar.raw_desugar(tree: 'Ast', desugar_for: 'bool' = False, desugar_string_cmp: 'bool' = False) -> 'ast::Ast *'>" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.desugar.raw_desugar" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "04a11b99", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "primitive print(string : string)\n", + "primitive print_err(string : string)\n", + "primitive print_int(int : int)\n", + "primitive flush()\n", + "primitive getchar() : string\n", + "primitive ord(string : string) : int\n", + "primitive chr(code : int) : string\n", + "primitive size(string : string) : int\n", + "primitive streq(s1 : string, s2 : string) : int\n", + "primitive strcmp(s1 : string, s2 : string) : int\n", + "primitive substring(string : string, start : int, length : int) : string\n", + "primitive concat(fst : string, snd : string) : string\n", + "primitive not(boolean : int) : int\n", + "primitive exit(status : int)\n", + "function _main() =\n", + " (\n", + " let\n", + " var _lo := 1\n", + " var _hi := 10\n", + " var i := _lo\n", + " in\n", + " (if (_lo <= _hi)\n", + " then (while 1 do\n", + " (\n", + " (\n", + " i;\n", + " ()\n", + " );\n", + " (if (i = _hi)\n", + " then break\n", + " else ());\n", + " (i := (i + 1))\n", + " ))\n", + " else ())\n", + " end;\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "ast_raw = tc.desugar.raw_desugar(ast, True, True)\n", + "print(ast_raw)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "da86985d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function tiger_desugar.desugar(tree: 'Ast', desugar_for: 'bool' = False, desugar_string_cmp: 'bool' = False) -> 'ast::Ast *'>" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.desugar.desugar" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "86f1bcc7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "primitive print(string : string)\n", + "primitive print_err(string : string)\n", + "primitive print_int(int : int)\n", + "primitive flush()\n", + "primitive getchar() : string\n", + "primitive ord(string : string) : int\n", + "primitive chr(code : int) : string\n", + "primitive size(string : string) : int\n", + "primitive streq(s1 : string, s2 : string) : int\n", + "primitive strcmp(s1 : string, s2 : string) : int\n", + "primitive substring(string : string, start : int, length : int) : string\n", + "primitive concat(fst : string, snd : string) : string\n", + "primitive not(boolean : int) : int\n", + "primitive exit(status : int)\n", + "function _main() =\n", + " (\n", + " let\n", + " var _lo := 1\n", + " var _hi := 10\n", + " var i := _lo\n", + " in\n", + " (if (_lo <= _hi)\n", + " then (while 1 do\n", + " (\n", + " (\n", + " i;\n", + " ()\n", + " );\n", + " (if (i = _hi)\n", + " then break\n", + " else ());\n", + " (i := (i + 1))\n", + " ))\n", + " else ())\n", + " end;\n", + " ()\n", + " )\n" + ] + } + ], + "source": [ + "ast = tc.desugar.desugar(ast, True, True)\n", + "print(ast)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/escapes.ipynb b/tiger-compiler/tcsh/python/tests/escapes.ipynb new file mode 100644 index 0000000..ed914fb --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/escapes.ipynb @@ -0,0 +1,194 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and escapes" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"escapes\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_escapes\n", + "tiger_escapes == tc.escapes" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Escapes Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function tiger_escapes.escapes_compute(tree: 'ast::Ast &') -> 'void'>" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.escapes.escapes_compute" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Escape\n", + "We use this to only parse and bind the ast and don't run code after TC3, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).bind()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "371349e8", + "metadata": {}, + "outputs": [], + "source": [ + "tc.escapes.escapes_compute(ast)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "703bb878", + "metadata": {}, + "outputs": [], + "source": [ + "# all variables are identical to ast.ipynb \n", + "main_chunk = ast[1]\n", + "main_function = main_chunk[0]\n", + "main_body = main_function.body_get()\n", + "let = main_body.exps_get()[0]\n", + "var_chk = let.chunks_get()[0]\n", + "var_b = var_chk[0]\n", + "print_call = let.body_get()\n", + "print_arg = print_call.args_get()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "c7ed8db8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n" + ] + } + ], + "source": [ + "print(var_b.escape_get())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/ipynbtest.py b/tiger-compiler/tcsh/python/tests/ipynbtest.py new file mode 100755 index 0000000..1b7798a --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/ipynbtest.py @@ -0,0 +1,279 @@ +#!/usr/bin/env python3 +""" +simple example script for running and testing notebooks. + +Usage: `ipnbdoctest.py foo.ipynb [bar.ipynb [...]]` + +Each cell is submitted to the kernel, and the outputs are compared +with those stored in the notebook. +""" + +# Derived from https://gist.github.com/minrk/2620735 +# Derived from https://gitlab.lrde.epita.fr/spot/spot/-/raw/next/tests/python/ipnbdoctest.py + +from __future__ import print_function + +import os +import sys +import time +import base64 +import re +import pprint +import random +from difflib import unified_diff as diff + +from collections import defaultdict +try: + from queue import Empty +except ImportError: + print('Python 3.x is needed to run this script.') + sys.exit(77) + +import importlib.util +try: + importlib.util.find_spec('IPython') +except: + print('IPython is needed to run this script.') + sys.exit(77) + +try: + from jupyter_client import KernelManager +except ImportError: + try: + from IPython.kernel import KernelManager + except ImportError: + try: + from IPython.zmq.blockingkernelmanager \ + import BlockingKernelManager as KernelManager + except: + print('IPython is needed to run this script.') + sys.exit(77) + +# Until Debian Stable ships IPython >3.0, we stick to the v3 format. +try: + from nbformat import v4 as nbformat +except ImportError: + from IPython.nbformat import v4 as nbformat + + +def canonicalize(s): + """sanitize a string for comparison. + + fix universal newlines, strip trailing newlines, and normalize likely + random values (memory addresses and UUIDs) + """ + if not isinstance(s, str): + return s + + # normalize newline: + s = s.replace('\r\n', '\n') + + # ignore trailing newlines (but not space) + s = s.rstrip('\n') + + # remove hex addresses: + s = re.sub(r'at 0x[a-f0-9]+', 'at 0xadd7e5500000', s) + + # remove backend lists in documentations/errors: + s = re.sub(r'\[((lir|hir|llvm|mips|ia32), ?)*(lir|hir|llvm|mips|ia32)\]', + '[]', s) + + return s + + +def canonical_dict(data): + """Neutralize gratuitous differences in a Jupyter dictionary.""" + + if 'text' in data: + data['text'] = canonicalize(data['text']) + + if 'data' in data: + d = data['data'] + if "text/html" in d and "text/plain" in d: + del d["text/plain"] + for k in d: + d[k] = canonicalize(d[k]) + + if ('ename' in data and + data['ename'] == 'SystemExit' and data['evalue'] == '77'): + # sys.exit(77) is used to Skip the test. + sys.exit(77) + + if 'ename' in data and data['ename'] == 'CalledProcessError': + # CalledProcessError message has a final dot in Python 3.6 + data['evalue'] = re.sub(r"(' returned non-zero exit status \d+)\.", + r'\1', data['evalue']) + + for e in ('transient', 'execution_count', 'traceback'): + if e in data: + del data[e] + return data + + +def compare_outputs(ref, test): + """Check that two lists of outputs are equivalent and report the result.""" + + cref = list(map(canonical_dict, ref)) + ctest = list(map(canonical_dict, test)) + + ok = True + + if len(cref) != len(ctest): + print("output length mismatch (expected {}, got {})" + .format(len(cref), len(ctest))) + ok = False + # There can be several outputs. For instance wnen the cell both + # prints a result (goes to "stdout") and displays an automaton + # (goes to "data"). + exp = pprint.pformat(cref, width=132) + eff = pprint.pformat(ctest, width=132) + if exp[:-1] != '\n': + exp += '\n' + if eff[:-1] != '\n': + eff += '\n' + if exp == eff: + return ok + else: + print(''.join(diff(exp.splitlines(1), eff.splitlines(1), + fromfile='expected', tofile='effective'))) + return False + + +def _wait_for_ready_backport(kc): + """Backport BlockingKernelClient.wait_for_ready from IPython 3""" + # Wait for kernel info reply on shell channel + kc.kernel_info() + while True: + msg = kc.get_shell_msg(block=True, timeout=30) + if msg['msg_type'] == 'kernel_info_reply': + break + # Flush IOPub channel + while True: + try: + msg = kc.get_iopub_msg(block=True, timeout=1) + except Empty: + break + + +def run_cell(kc, cell): + kc.execute(cell.source) + outs = [] + + while True: + try: + msg = kc.get_iopub_msg(timeout=1) + except Empty: + if not kc.is_alive(): + raise RuntimeError("Kernel died") + continue + + msg_type = msg['msg_type'] + content = msg['content'] + + if msg_type == 'status' and content['execution_state'] == 'idle': + break + if msg_type in ('status', 'pyin', 'execute_input', + 'comm_open', 'comm_msg'): + continue + if msg_type == 'stream': + if 'Widget' in content['text']: + continue + # If the last stream had the same name, then outputs are + # appended. + if outs: + last = outs[-1] + if last['output_type'] == 'stream' and \ + last['name'] == content['name']: + last['text'] += content['text'] + continue + elif msg_type == 'clear_output': + outs = [] + continue + + content['output_type'] = msg_type + outs.append(content) + # Flush shell channel + while True: + try: + kc.get_shell_msg(timeout=0.1) + except Empty: + if not kc.is_alive(): + raise RuntimeError("Kernel died") + break + return outs + + +def test_notebook(ipynb): + with open(ipynb, encoding='utf-8') as f: + nb = nbformat.reads_json(f.read()) + km = KernelManager() + # Do not save the history to disk, as it can yield spurious lock errors. + # See https://github.com/ipython/ipython/issues/2845 + km.start_kernel(extra_arguments=['--HistoryManager.hist_file=:memory:', + '--quiet']) + + kc = km.client() + kc.start_channels() + + try: + kc.wait_for_ready(timeout=30) + except AttributeError: + _wait_for_ready_backport(kc) + + successes = 0 + failures = 0 + errors = 0 + for i, cell in enumerate(nb.cells): + if cell.cell_type == 'markdown' and cell.source.startswith("#"): + title = re.sub(r'^#+ ?', '', cell.source.splitlines()[0]) + if cell.cell_type != 'code' or cell.source.startswith('#DONTCHECK'): + continue + try: + outs = run_cell(kc, cell) + except Exception as e: + print("failed to run cell:", repr(e)) + print(cell.input) + errors += 1 + continue + + failed = not compare_outputs(cell.outputs, outs) + print("{: <30} {: >2}: ".format(title, i), end="") + if failed: + print("FAIL") + failures += 1 + else: + print("OK") + successes += 1 + + print("tested notebook %s" % ipynb) + print(" %3i cells successfully replicated" % successes) + if failures: + print(" %3i cells mismatched output" % failures) + if errors: + print(" %3i cells failed to complete" % errors) + kc.stop_channels() + km.shutdown_kernel() + del km + if failures or errors: + sys.exit(1) + + +if __name__ == '__main__': + for ipynb in sys.argv[1:]: + tries=3 + while tries: + print("testing %s" % ipynb) + try: + test_notebook(ipynb) + break + except RuntimeError as e: + # If the Kernel dies, try again. It seems we have spurious + # failures when multiple instances of jupyter start in parallel. + if 'Kernel died' in str(e): + tries -= 1 + if tries: + s = random.randint(1, 5) + print("trying again in", s, "seconds...") + time.sleep(s) + else: + raise e diff --git a/tiger-compiler/tcsh/python/tests/llvmtranslate.ipynb b/tiger-compiler/tcsh/python/tests/llvmtranslate.ipynb new file mode 100644 index 0000000..1e84c8f --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/llvmtranslate.ipynb @@ -0,0 +1,220 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b8caa27f", + "metadata": {}, + "source": [ + "# Import Tiger and LLVMTranslate" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"llvmtranslate\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_llvmtranslate\n", + "tiger_llvmtranslate == tc.llvmtranslate" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# LLVMTranslate Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['translate']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.llvmtranslate)))" + ] + }, + { + "cell_type": "markdown", + "id": "39d05040", + "metadata": {}, + "source": [ + "# Tiger Magics and LLVMTranslate" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b210db83", + "metadata": {}, + "outputs": [], + "source": [ + "%%tiger executor llvm\n", + "let\n", + " var b := 5\n", + "in\n", + " print_int(b)\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cd732dc4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "; ModuleID = 'LRDE Tiger Compiler'\n", + "source_filename = \"LRDE Tiger Compiler\"\n" + ] + } + ], + "source": [ + "llvm = executor.llvm\n", + "print(*llvm.splitlines()[0:2], sep=\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "defafcde", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n" + ] + } + ], + "source": [ + "print(executor.result)" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# LLVMTranslate example\n", + "In Tiger Magics it run translate and then run clang (see tcsh/python/ti.py)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).desugar()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "29d68680", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "; ModuleID = 'LRDE Tiger Compiler'\n", + "source_filename = \"LRDE Tiger Compiler\"\n" + ] + } + ], + "source": [ + "llvm = tc.llvmtranslate.translate(ast)\n", + "print(*llvm.splitlines()[0:2], sep=\"\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/misc.ipynb b/tiger-compiler/tcsh/python/tests/misc.ipynb new file mode 100644 index 0000000..8fb12a2 --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/misc.ipynb @@ -0,0 +1,358 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and Misc" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"misc\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_misc\n", + "tiger_misc == tc.misc" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Misc Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['error', 'file_library', 'symbol', 'symbol_fresh', 'timer']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\"), dir(tc.misc)))" + ] + }, + { + "cell_type": "markdown", + "id": "c2ffa10b", + "metadata": {}, + "source": [ + "# Misc error" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 SUCCESS\n", + "1 FAILURE\n", + "2 SCAN\n", + "3 PARSE\n", + "4 BIND\n", + "5 TYPE\n" + ] + } + ], + "source": [ + "errors_messages = tc.misc.error.error_type_message()\n", + "for i in range(6):\n", + " print(i, errors_messages[i])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "bf7ee0ae", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "print(tc.misc.error.error_type_success)\n", + "print(tc.misc.error.error_type_failure)\n", + "print(tc.misc.error.error_type_scan)\n", + "print(tc.misc.error.error_type_parse)\n", + "print(tc.misc.error.error_type_bind)\n", + "print(tc.misc.error.error_type_type)" + ] + }, + { + "cell_type": "markdown", + "id": "aa79fa38", + "metadata": {}, + "source": [ + "# Misc symbol" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "082ad376", + "metadata": {}, + "outputs": [], + "source": [ + "hello = tc.misc.symbol(\"Hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "88a477ec", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_misc.symbol'>\n" + ] + } + ], + "source": [ + "print(type(hello))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "315f56d1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "str(hello)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "9614378d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hello == \"Hello\"" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "14621e65", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hello == tc.misc.symbol(\"Hello\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "dccec330", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hello != tc.misc.symbol(\"world\")" + ] + }, + { + "cell_type": "markdown", + "id": "a8236c03", + "metadata": {}, + "source": [ + "# Misc timer" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "2f35c4c7", + "metadata": {}, + "outputs": [], + "source": [ + "my_timer = tc.misc.timer()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "70f7b6e0", + "metadata": {}, + "outputs": [], + "source": [ + "my_timer.start()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "8510ce33", + "metadata": {}, + "outputs": [], + "source": [ + "my_timer.push('test')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "8eeb355b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Execution times (seconds)\n", + "\n", + "Cumulated times (seconds)\n", + " test : -0.79 ( -79%) -0.13 ( -13%) -1.43526e+07 (-1.44e+09%) \n", + "\n", + " TOTAL (seconds) : 0 user, 0 system, 0 wall\n" + ] + } + ], + "source": [ + "#DONTCHECK\n", + "my_timer.dump()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/object.ipynb b/tiger-compiler/tcsh/python/tests/object.ipynb new file mode 100644 index 0000000..69563e5 --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/object.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and Object" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"object\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_object\n", + "tiger_object == tc.object" + ] + }, + { + "cell_type": "markdown", + "id": "c2ffa10b", + "metadata": {}, + "source": [ + "# Object functions" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "37f1bbb8", + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Callable\n", + "def function_annotations(fn: Callable) -> str:\n", + " ann = fn.__annotations__\n", + " ret = ann.get(\"return\")\n", + " args = \", \".join((\"{}: '{}'\".format(a, ann[a]) for a in ann if a != \"return\"))\n", + " name = fn.__module__ + '.' + fn.__qualname__\n", + " return \"<function {name}({args}) -> '{ret}'>\".format(name=name, args=args, ret=ret)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<function tiger_object.bind(tree: 'Ast') -> 'misc::error'>\n" + ] + } + ], + "source": [ + "if tc.has(\"bind\"): # Wait TC3\n", + " print(function_annotations(tc.object.bind))\n", + "else:\n", + " def bind(tree: 'ast::Ast &') -> 'misc::error':\n", + " pass\n", + " bind.__module__ = \"tiger_object\"\n", + " print(function_annotations(bind))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "bfba3cc3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<function tiger_object.types_check(tree: 'Ast') -> 'misc::error'>\n" + ] + } + ], + "source": [ + "if tc.has(\"type\"): # Wait TC4\n", + " print(function_annotations(tc.object.types_check))\n", + "else:\n", + " def types_check(tree: 'ast::Ast &') -> 'misc::error':\n", + " pass\n", + " types_check.__module__ = \"tiger_object\"\n", + " print(function_annotations(types_check))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "bd48ce57", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<function tiger_object.rename(tree: 'Ast') -> 'object::class_names_type *'>\n" + ] + } + ], + "source": [ + "if tc.has(\"desugar\"): # Wait TC4\n", + " print(function_annotations(tc.object.rename))\n", + "else:\n", + " def rename(tree: 'ast::Ast &') -> 'object::class_names_type *':\n", + " pass\n", + " rename.__module__ = \"tiger_object\"\n", + " print(function_annotations(rename))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/overload.ipynb b/tiger-compiler/tcsh/python/tests/overload.ipynb new file mode 100644 index 0000000..170ab9c --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/overload.ipynb @@ -0,0 +1,207 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b8caa27f", + "metadata": {}, + "source": [ + "# Import Tiger and Overload" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"overload\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_overload\n", + "tiger_overload == tc.overload" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Overload Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['bind', 'types_check']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.overload)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Overload Ast\n", + "We use this to only parse the ast and don't run code after TC4, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).type()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "29d68680", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tuple'>\n" + ] + } + ], + "source": [ + "pair = tc.overload.bind(ast)\n", + "print(type(pair))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "46abfec6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'SwigPyObject'> <class 'tiger_misc.error'>\n", + "\n" + ] + } + ], + "source": [ + "overfun_bindings_get, error = pair\n", + "print(type(overfun_bindings_get), type(error))\n", + "print(error)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e8f0ee43", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "error = tc.overload.types_check(ast, overfun_bindings_get)\n", + "print(error)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/parse.ipynb b/tiger-compiler/tcsh/python/tests/parse.ipynb new file mode 100644 index 0000000..e899bc4 --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/parse.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3f7f66b6", + "metadata": {}, + "source": [ + "# Import Tiger and Parse" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"parse\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_parse\n", + "tiger_parse == tc.parse" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Parse Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['MetavarChunkList',\n", + " 'MetavarMap',\n", + " 'MetavarNameTy',\n", + " 'MetavarVar',\n", + " 'TigerParser',\n", + " 'YY_NULLPTR',\n", + " 'location',\n", + " 'parse',\n", + " 'parse_chunks',\n", + " 'parse_unit',\n", + " 'position']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.endswith(\"Tweast\") and not e.startswith(\"tiger\"), dir(tc.parse)))" + ] + }, + { + "cell_type": "markdown", + "id": "c2ffa10b", + "metadata": {}, + "source": [ + "# Parse parse" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "\n", + "if tc.has(\"misc\"):\n", + " with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let in end\")\n", + " f.seek(0)\n", + " ast = tc.parse.parse(\"builtin\", f.name, tc.misc.file_library())\n", + " # do not use ast before tc2" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/tc.ipynb b/tiger-compiler/tcsh/python/tests/tc.ipynb new file mode 100644 index 0000000..58cfa3f --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/tc.ipynb @@ -0,0 +1,252 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "cefa08c9", + "metadata": {}, + "source": [ + "# Import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "989c2dff", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "markdown", + "id": "37e62513", + "metadata": {}, + "source": [ + "# Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "38583076", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "%%tiger variable_name [backend]\n", + "variable_name is the name of the finale variable\n", + "backend is optional and must be in [llvm, hir, lir, mips, ia32]\n" + ] + } + ], + "source": [ + "print(tc.TigerMagics.__doc__)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "0e93343f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "UsageError: %%tiger is a cell magic, but the cell body is empty.\n" + ] + } + ], + "source": [ + "%%tiger" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d2d30487", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "UsageError: %%tiger is a cell magic, but the cell body is empty.\n" + ] + } + ], + "source": [ + "%%tiger execution" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c5ce6c25", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "%%tiger variable_name [backend]\n", + "variable_name is the name of the finale variable\n", + "backend is optional and must be in [llvm, hir, lir, mips, ia32]\n" + ] + } + ], + "source": [ + "%%tiger\n", + "let in end" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "05856612", + "metadata": {}, + "outputs": [], + "source": [ + "%%tiger execution\n", + "let in end" + ] + }, + { + "cell_type": "markdown", + "id": "326e35de", + "metadata": {}, + "source": [ + "# tc Variables and Functions" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "97e995a8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<Swig Object of type 'std::ostream *' at 0x7fd40876a430>" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.Cout" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "ad4ebd05", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<Swig Object of type 'std::ostream *' at 0x7fd40876a610>" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.Cerr" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6790e6ee", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<enum 'BackendType'>" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.BackendType" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "34ebeb8c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function tc.has(module_name: str) -> bool>" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "fc67329d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"common\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/ti.ipynb b/tiger-compiler/tcsh/python/tests/ti.ipynb new file mode 100644 index 0000000..dfa5399 --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/ti.ipynb @@ -0,0 +1,186 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7415e928", + "metadata": {}, + "source": [ + "The ti module is used to easily perform all the steps in the tc module and in the command line." + ] + }, + { + "cell_type": "markdown", + "id": "cefa08c9", + "metadata": {}, + "source": [ + "# Import ti" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "989c2dff", + "metadata": {}, + "outputs": [], + "source": [ + "import ti" + ] + }, + { + "cell_type": "markdown", + "id": "37e62513", + "metadata": {}, + "source": [ + "# ti Process File" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d293f4f2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function ti.process_file(filename: 'str', backend: 'tc.BackendType' = <BackendType.mips: 'mips'>, **kwargs) -> 'None'>" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ti.process_file" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "fefa7505", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello World!\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b'let in print(\"Hello World!\\n\") end')\n", + " f.seek(0)\n", + " \n", + " if not ti.tc.has(\"llvmtranslate\"): # Simulate result before TCL\n", + " print(\"Hello World!\")\n", + " else:\n", + " ti.process_file(f.name, 'llvm')" + ] + }, + { + "cell_type": "markdown", + "id": "3a6c23a4", + "metadata": {}, + "source": [ + "# ti TiExecutor" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bd177f77", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "<function ti.TiExecutor.__init__(self, filename: 'str', backend: 'tc.BackendType' = <BackendType.mips: 'mips'>, exit_on_error: 'bool' = True, get_result: 'bool' = False, rename: 'bool' = True, desugar: 'bool' = True, object_enabled: 'bool' = True, debug: 'bool' = False)>" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ti.TiExecutor.__init__" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "64c47c73", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ast: None\n", + "error: None\n", + "fragments: None\n", + "lir_fragments: None\n", + "llvm: None\n", + "result: None\n", + "target: None\n", + "tempmap: None\n", + "\n", + "Hello World!\n", + "\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " # Create File\n", + " f.write(b'let in print(\"Hello World!\\n\") end')\n", + " f.seek(0)\n", + " \n", + " # Create Executor\n", + " \n", + " if ti.tc.has(\"llvmtranslate\"):\n", + " e = ti.TiExecutor(f.name, backend=\"llvm\", rename=False, desugar=False, exit_on_error=False, get_result=True)\n", + " else:\n", + " e = ti.TiExecutor(f.name, rename=False, desugar=False, exit_on_error=False, get_result=True)\n", + " \n", + " # All data are empty before execution\n", + " print(e.data)\n", + " e.backend_exec()\n", + " \n", + " if not ti.tc.has(\"llvmtranslate\"): # Simulate result before TCL\n", + " e.data.result = \"Hello World!\\n\"\n", + " \n", + " # Result is stored when get_result=True\n", + " print(e.data.result)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/tests/type.ipynb b/tiger-compiler/tcsh/python/tests/type.ipynb new file mode 100644 index 0000000..5daab36 --- /dev/null +++ b/tiger-compiler/tcsh/python/tests/type.ipynb @@ -0,0 +1,228 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "81a0b85e", + "metadata": {}, + "source": [ + "# Import Tiger and type" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9cb3bce5", + "metadata": {}, + "outputs": [], + "source": [ + "import tc" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "be38c5fe", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tc.has(\"type\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "9fe09a20", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import tiger_type\n", + "tiger_type == tc.type" + ] + }, + { + "cell_type": "markdown", + "id": "3b3a7285", + "metadata": {}, + "source": [ + "# Type Library" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2be2f25d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Array',\n", + " 'Class',\n", + " 'Class_object_instance',\n", + " 'Field',\n", + " 'Function',\n", + " 'Int',\n", + " 'Method',\n", + " 'Named',\n", + " 'Nil',\n", + " 'Record',\n", + " 'String',\n", + " 'Type',\n", + " 'Void',\n", + " 'cvar',\n", + " 'hide_actual_types',\n", + " 'types_check']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(filter(lambda e: not e.startswith(\"_\") and not e.startswith(\"tiger\"), dir(tc.type)))" + ] + }, + { + "cell_type": "markdown", + "id": "35825bf6", + "metadata": {}, + "source": [ + "# Type Ast\n", + "We use this to only parse the ast and don't run code after TC4, but use Tiger Magics" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "0ee4cd72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_ast.ChunkList'>\n" + ] + } + ], + "source": [ + "import tempfile\n", + "\n", + "with tempfile.NamedTemporaryFile() as f:\n", + " f.write(b\"let var b := 5 in print_int(b) end\")\n", + " f.seek(0)\n", + " ast = tc.ti.TiExecutor(f.name).type()\n", + "print(type(ast))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "703bb878", + "metadata": {}, + "outputs": [], + "source": [ + "# all variables are identical to ast.ipynb \n", + "main_chunk = ast[1]\n", + "main_function = main_chunk[0]\n", + "main_body = main_function.body_get()\n", + "let = main_body.exps_get()[0]\n", + "var_chk = let.chunks_get()[0]\n", + "var_b = var_chk[0]\n", + "print_call = let.body_get()\n", + "print_arg = print_call.args_get()[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "40ad7839", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "<class 'tiger_type.Int'>\n", + "int\n" + ] + } + ], + "source": [ + "print(type(var_b.type_get()))\n", + "print(str(var_b.type_get()))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "be462b0c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "main_function: \n", + "{\n", + "} -> void\n", + "main_body: void\n", + "let: void\n", + "var_b: int\n", + "print_call: void\n", + "print_arg: int\n" + ] + } + ], + "source": [ + "for e in (\"main_function\", \"main_body\", \"let\", \"var_b\", \"print_call\", \"print_arg\"):\n", + " if hasattr(globals()[e], \"type_get\"):\n", + " print(e, globals()[e].type_get(), sep=\": \")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tiger-compiler/tcsh/python/ti.py b/tiger-compiler/tcsh/python/ti.py new file mode 100755 index 0000000..a7df479 --- /dev/null +++ b/tiger-compiler/tcsh/python/ti.py @@ -0,0 +1,356 @@ +#! /usr/bin/env python3 + +# Tiger interpreter. + +# Execute a Tiger program, using the Tiger Compiler through +# TCSH/Python and a supporting back-end environment (HAVM, Nolimips, +# or an IA-32 environment). +# +# This script needs a complete, dynamically-compiled Tiger compiler +# (with all its modules) to work. The Tree back-end needs a `havm' +# binary to be available in the PATH; the MIPS back-end, a `nolimips' +# binary; and the IA-32 back-end, an IA-32 execution environment. + +from __future__ import annotations +from collections.abc import Callable +from typing import List, Optional, Tuple, TypeVar, Union + +import optparse +import tempfile +import subprocess + +import os +import sys +import re + +import tc + + +# Subclass to redefine error method (for exit code to be 1). +class TiOptionParser(optparse.OptionParser): + def error(self, msg: str) -> None: + self.print_usage(sys.stderr) + self.exit(1, "%s: error: %s\n" % (self.get_prog_name(), msg)) + + +T = TypeVar("T") + + +def wrap_step( + modules: List[str] = [], + require: Optional[str] = None, + backend: Optional[tc.BackendType] = None, +) -> Callable[[Callable[[TiExecutor], T]], Callable[[TiExecutor], Optional[T]]]: + """ + Decorator for steps of TiExecutor, execute the require step if needed + """ + + def check_wrap_step( + f: Callable[[TiExecutor], T] + ) -> Callable[[TiExecutor], Optional[T]]: + def new_f(self: TiExecutor) -> Optional[T]: + if self.debug: + print(f"CALL {f.__name__} [{self.backend}]") + if backend and self.backend != backend: + self.backend = backend + if hasattr(self, "__step"): + delattr(self, "__step") + self._rm_asm() + self._rm_llvm() + self.data = TiExecutor.TiExecution() + if require and not hasattr(self, require): + raise RuntimeError(require + " step must exist") + if self.data.error: + return None + hasstep = hasattr(self, "__step") + if require and (not hasstep or hasstep and not self.__step == require): + getattr(self, require)() + if self.data.error: + return None + for mod in modules: + if not tc.has(mod): + msg = f"Module {mod} is not available to execute {f.__name__} step\nCheck your install of tc" + self.data.error = (-1, msg) + print(msg, file=sys.stderr) + if self.exit_on_error: + sys.exit(1) + return None + if self.debug: + print(f"ENTER {f.__name__} [{self.backend}]") + res = f(self) + if self.debug: + print(f"EXIT {f.__name__} [{self.backend}]") + self.__step = f.__name__ + return res + + new_f.__doc__ = f"Ast {f.__name__} step" + if require: + new_f.__doc__ += f"\nRequire {require} step, execute it otherwise" + if modules and len(modules): + new_f.__doc__ += "\nRequire {} tc modules".format(", ".join(modules)) + new_f.__name__ = f.__name__ + return new_f + + return check_wrap_step + + +class TiExecutor: + class TiExecution: + ast: Optional[tc.ast.ChunkList] = None + error: Optional[Tuple[int, str]] = None + fragments: Optional[tc.tree.Fragments] = None + lir_fragments: Optional[tc.assem.Fragments] = None + target: Optional[Union[tc.target.Ia32Target, tc.target.MipsTarget]] = None + tempmap: Optional[tc.temp.TempMap] = None + result: Optional[str] = None + llvm: Optional[str] = None + + def __str__(self) -> str: + res = "" + + def truncate(msg: str) -> str: + return msg if not msg or len(msg) < 100 else msg[:100] + "..." + + for e in dir(self): + if not e.startswith("_"): + res += e + ": " + truncate(repr(getattr(self, e))) + "\n" + return res + + def __init__( + self, + filename: str, + backend: tc.BackendType = tc.BackendType.mips, + exit_on_error: bool = True, + get_result: bool = False, + rename: bool = True, + desugar: bool = True, + object_enabled: bool = True, + debug: bool = False, + ): + self.filename = filename + self.backend = tc.BackendType(backend) + self.exit_on_error = exit_on_error + self.get = get_result + self.rename_enabled = rename + self.desugar_enabled = desugar + self.object_enabled = object_enabled + self.debug = debug + self.data = TiExecutor.TiExecution() + + def error_message(self) -> str: + if not self.data.error: + return "" + status, message = self.data.error + statusMessage = tc.misc.error.error_type_message()[status] + if re.match(r"(.*/)?tmp\w{8}\.tig$", self.filename): + if message.startswith(self.filename + ":"): + message = message.replace(self.filename + ":", "") + message = " " + message + else: + message = "\n" + message + return str(status) + " " + statusMessage + ":" + message + + def throw_error(self, e: Exception) -> None: + self.__step = "error" + self.data.error = e.args + status, message = e.args + if self.exit_on_error: + print(message, file=sys.stderr) + sys.exit(status) + else: + print(self.error_message(), end="", file=sys.stderr) + + def _rm_attribute_file(self, arg: str) -> None: + if hasattr(self, arg): + os.unlink(getattr(self, arg)) + delattr(self, arg) + + def _rm_attribute_dir(self, arg: str) -> None: + if hasattr(self, arg): + os.rmdir(getattr(self, arg)) + delattr(self, arg) + + def _rm_attribute_temp(self, arg: str) -> None: + if hasattr(self, arg): + os.unlink(getattr(self, arg).name) + delattr(self, arg) + + def _run_cmd(self, *cmd: str) -> Optional[str]: + if self.get: + proc = subprocess.run(cmd, capture_output=True) + self.data.result = proc.stdout.decode("utf-8") + else: + os.system(" ".join(cmd)) + self.data.result = None + return self.data.result + + @wrap_step(["misc", "parse"]) + def parse(self) -> Optional[tc.ast.ChunkList]: + lib = tc.misc.file_library() + try: + self.data.ast = tc.parse.parse("builtin", self.filename, lib) + except Exception as e: + return self.throw_error(e) + return self.data.ast + + @wrap_step(["bind"], "parse") + def bind(self) -> Optional[tc.ast.ChunkList]: + try: + if self.object_enabled and tc.has("object"): + tc.object.bind(self.data.ast).exit_on_error() + else: + tc.bind.bind(self.data.ast).exit_on_error() + except Exception as e: + return self.throw_error(e) + return self.data.ast + + @wrap_step([], "bind") + def rename(self) -> Optional[tc.ast.ChunkList]: + if ( + self.rename_enabled + and tc.has("bind") + and not self.object_enabled + and not tc.has("object") + ): + tc.bind.rename(self.data.ast) + return self.data.ast + + @wrap_step(["type"], "rename") + def type(self) -> Optional[tc.ast.ChunkList]: + try: + if self.object_enabled and tc.has("object"): + tc.object.types_check(self.data.ast).exit_on_error() + else: + tc.type.types_check(self.data.ast).exit_on_error() + except Exception as e: + return self.throw_error(e) + return self.data.ast + + @wrap_step([], "type") + def object_desugar(self) -> Optional[tc.ast.ChunkList]: + if self.object_enabled and tc.has("object"): + class_names = tc.object.rename(self.data.ast) + self.data.ast = tc.object.desugar(self.data.ast, class_names) + return self.data.ast + + @wrap_step([], "object_desugar") + def desugar(self) -> Optional[tc.ast.ChunkList]: + if self.desugar_enabled and tc.has("desugar"): + self.data.ast = tc.desugar.desugar(self.data.ast, True, True) + return self.data.ast + + @wrap_step(["llvmtranslate"], "desugar") + def llvm_file(self) -> str: + self.data.llvm = tc.llvmtranslate.translate(self.data.ast) + + self._rm_llvm() + self.llvm_temp_dir = tempfile.mkdtemp() + # Dump assembly code output into a temporary file. + self.llvm_output = os.path.join(self.llvm_temp_dir, "llvm.ll") + with open(self.llvm_output, "w") as f: + f.write(str(self.data.llvm)) + return self.llvm_output + + def _rm_llvm(self) -> None: + self._rm_attribute_file("llvm_output") + self._rm_attribute_file("llvm_binary") + self._rm_attribute_dir("llvm_temp_dir") + + @wrap_step([], "llvm_file") + def llvm_bin(self) -> str: + self._rm_attribute_file("llvm_binary") + self.llvm_binary = os.path.join(self.llvm_temp_dir, "bin") + os.system(f"clang -m32 {self.llvm_output} -o {self.llvm_binary}") + return self.llvm_binary + + @wrap_step([], "llvm_bin", tc.BackendType.llvm) + def llvm(self) -> Optional[str]: + self._run_cmd(self.llvm_binary) + self._rm_llvm() + return self.data.result + + def frontend_run(self) -> None: + """Run parse, bind and type depending of TC step""" + self.parse() + + self.bind() + self.rename() + self.type() + self.object_desugar() + self.desugar() + return None + + def backend_exec(self) -> Optional[str]: + """execute backends: llvm, hir, lir, mips and ia32""" + self.frontend_run() + if self.backend == tc.BackendType.llvm: + return self.llvm() + return None + + def backend_run(self) -> None: + self.get = False + self.backend_exec() + + def backend_get(self) -> Optional[str]: + self.get = True + return self.backend_exec() + + +def process_file( + filename: str, backend: tc.BackendType = tc.BackendType.mips, **kwargs +) -> None: + executor = TiExecutor(filename, backend=backend, **kwargs) + executor.backend_run() + + +if __name__ == "__main__": + # Parser creation. + parser = TiOptionParser( + """%prog [options] file.tig + Execute a Tiger program, using a given back-end.""" + ) + parser.add_option( + "-b", + "--back-end", + metavar="BACKEND", + dest="backend", + default=tc.BackendType.mips, + help="use BACKEND as back-end. Can be either " + f"`{tc.BackendType.llvm.value}' (LLVM), " + f"`{tc.BackendType.mips.value}' (MIPS assembly language) " + "[default: %default]", + ) + parser.add_option( + "-d", + "--debug", + action="store_true", + dest="debug", + default=False, + help="print debug call trace", + ) + + # Options parsing. + (options, args) = parser.parse_args() + + # Invalid argument. + me = os.path.basename(sys.argv[0]) + error = False + if len(args) != 1: + print(f"{me}: not enough arguments") + error = True + + if options.backend not in [e.value for e in tc.BackendType]: + print(f"{me}: select a valid backend") + error = True + + if error: + parser.print_help() + sys.exit(1) + + # Get filename from arguments. + filename = args[-1] + process_file(filename, **vars(options)) + +# Local Variables: +# mode: python +# End: diff --git a/tiger-compiler/tcsh/run.in b/tiger-compiler/tcsh/run.in new file mode 100755 index 0000000..1a12070 --- /dev/null +++ b/tiger-compiler/tcsh/run.in @@ -0,0 +1,53 @@ +#! /bin/sh +# Copyright (C) 2003, 2004, 2006, 2013 Laboratoire d'Informatique de +# Paris 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), +# Université Pierre et Marie Curie. +# +# This file is part of Spot, a model checking library. +# +# Spot is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Spot is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +# License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Spot; see the file COPYING. If not, write to the Free +# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + + +# If we are running from make check (srcdir is set) and VERBOSE is +# unset, be quiet. +test -n "$srcdir" && test -z "$VERBOSE" && exec >/dev/null 2>&1 + +# Darwin needs some help in figuring out where non-installed libtool +# libraries are (on this platform libtool encodes the expected final +# path of dependent libraries in each library). +modpath='.libs:@abs_top_builddir@/src/.libs' + +# `@abs_builddir@/python' and `@abs_srcdir@/python' are for the *.py +# files, and `@abs_builddir@/python/.libs' for the *.so files. We +# used to rely on a module called `ltihooks' to teach the `import' +# statement how to load a Libtool library, but it started to cause +# issues with Python 2.6. +pypath='@abs_builddir@/python:@abs_builddir@/python/.libs:@abs_srcdir@/python':"$PYTHONPATH" + +case $1 in + export) + # use export to get variables + echo "PYTHONPATH='$pypath' DYLD_LIBRARY_PATH='$modpath'";; + *.py) + PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath exec @PYTHON@ "$@";; + *.test) + exec sh -x "$@";; + *.ipynb) + PYTHONPATH=$pypath DYLD_LIBRARY_PATH=$modpath exec @abs_srcdir@/python/tests/ipynbtest.py "$@";; + *) + echo "Unknown extension" >&2 + exit 2;; +esac diff --git a/tiger-compiler/tcsh/run.mk b/tiger-compiler/tcsh/run.mk new file mode 100644 index 0000000..bfc00e9 --- /dev/null +++ b/tiger-compiler/tcsh/run.mk @@ -0,0 +1,6 @@ +# A test/script wrapper. + +RUN = $(top_builddir)/tcsh/run +RUN_IN = $(top_srcdir)/tcsh/run.in +$(RUN): $(RUN_IN) + cd $(top_builddir)/tcsh && $(MAKE) $(AM_MAKEFLAGS) run diff --git a/tiger-compiler/tcsh/src/helper.hh b/tiger-compiler/tcsh/src/helper.hh new file mode 100644 index 0000000..cdbf760 --- /dev/null +++ b/tiger-compiler/tcsh/src/helper.hh @@ -0,0 +1,16 @@ +#ifndef SWIG_HELPER_H +#define SWIG_HELPER_H + +#define STCONVERT(TYPE, TYPENAME) \ +void operator()(const TYPE & e) override \ +{ \ + result = SWIG_NewPointerObj(SWIG_as_voidptr(&e), SWIGTYPE_ ## TYPENAME, 0); \ +} + +#define IFTYPECONVERT(TYPE, TYPENAME) \ +if (const TYPE* d = dynamic_cast<const TYPE*>(&e); d != nullptr) \ +{ \ + result = SWIG_NewPointerObj(SWIG_as_voidptr(&e), SWIGTYPE_ ## TYPENAME, 0); \ +} + +#endif /* ! SWIG_HELPER_H */ diff --git a/tiger-compiler/tcsh/src/swig_real_type.hh b/tiger-compiler/tcsh/src/swig_real_type.hh new file mode 100644 index 0000000..9420bf9 --- /dev/null +++ b/tiger-compiler/tcsh/src/swig_real_type.hh @@ -0,0 +1,67 @@ +#ifndef SWIG_REAL_TYPE_HH +#define SWIG_REAL_TYPE_HH + +#include "helper.hh" + +namespace { + using namespace ast; + class SwigAstTypeVisitor : public ConstVisitor + { + public: + PyObject *result; + SwigAstTypeVisitor() : GenVisitor<misc::constify_traits>() {} + ~SwigAstTypeVisitor() {} + +#define STHELPER(TYPE) STCONVERT(TYPE, p_ast__ ## TYPE) + STHELPER(ArrayExp) + STHELPER(ArrayTy) + STHELPER(AssignExp) + STHELPER(Ast) + STHELPER(BreakExp) + STHELPER(CallExp) + STHELPER(CastExp) + STHELPER(ChunkList) + STHELPER(ClassTy) + STHELPER(Field) + STHELPER(FieldInit) + STHELPER(FieldVar) + STHELPER(ForExp) + STHELPER(FunctionDec) + STHELPER(IfExp) + STHELPER(IntExp) + STHELPER(LetExp) + STHELPER(MethodCallExp) + STHELPER(MethodDec) + STHELPER(NameTy) + STHELPER(NilExp) + STHELPER(ObjectExp) + STHELPER(OpExp) + STHELPER(RecordExp) + STHELPER(RecordTy) + STHELPER(SeqExp) + STHELPER(SimpleVar) + STHELPER(StringExp) + STHELPER(SubscriptVar) + STHELPER(TypeDec) + STHELPER(VarDec) + STHELPER(WhileExp) +#undef STHELPER + +#define STCHUNKHELPER(TYPE) \ + STCONVERT(TYPE ## Chunk, p_ast__ChunkT_ast__ ## TYPE ## Dec_t) + STCHUNKHELPER(Function) + STCHUNKHELPER(Method) + STCHUNKHELPER(Type) + STCHUNKHELPER(Var) +#undef STCHUNKHELPER + }; +} // namespace + +PyObject *get_swig_real_ast_type(const ast::Ast& e) +{ + SwigAstTypeVisitor stv; + e.accept(stv); + return stv.result; +} + +#endif /* ! SWIG_REAL_TYPE_HH */ diff --git a/tiger-compiler/tcsh/src/tiger_ast.i b/tiger-compiler/tcsh/src/tiger_ast.i new file mode 100644 index 0000000..685100f --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_ast.i @@ -0,0 +1,312 @@ +// -*- C++ -*- + +%module tiger_ast + +%include "std_string.i" +%include "std_vector.i" +%include "std_list.i" +%include "std_except.i" + +%{ + #include "helper.hh" + #include <sstream> + #include <fstream> + #include <ast/visitor.hh> + #include <ast/object-visitor.hh> + #include <ast/default-visitor.hh> + #include <ast/all.hh> + #include <ast/libast.hh> + #include <common.hh> +%} + +%typemap(ret) ast::Ast* { + $result = get_swig_real_ast_type(*$1); +} +%apply ast::Ast* { ast::ChunkInterface*, ast::Exp*, ast::Dec*, ast::Ty*, ast::Var* } +%apply ast::Ast* { ast::Ast&, ast::ChunkInterface&, ast::Exp&, ast::Dec&, ast::Ty&, ast::Var& } + +%include "common.hh" +%include "ast/fwd.hh" + +%include "ast/location.hh" + +%include "ast/ast.hh" + +%extend ast::Ast +{ + std::string __str__() const + { + std::ostringstream o; + o << *$self; + return o.str(); + } + bool operator==(const ast::Ast& o) const + { + return $self == &o; + } +} + +%extend ast::OpExp { + %pythoncode %{ + def oper_str_get(self) -> "std::string": + return _tiger_ast.str(self.oper_get()) + + @staticmethod + def oper_names(): + return { getattr(_tiger_ast, t): t[len("OpExp_Oper_"):] for t in dir(_tiger_ast) if t.startswith("OpExp_Oper_") } + + def oper_name_get(self) -> "std::string": + return OpExp.oper_names()[self.oper_get()] + %} +} + +%extend ast::Typable +{ + %pythoncode %{ + def type_get(self) -> "type::Type const *": + import tiger_type + return tiger_type._get_swig_real_type_type(_tiger_ast.Typable_type_get(self)) + %} +} + +// Visitors. +%include "ast/visitor.hh" +%template(AstConstVisitor) ast::GenVisitor<misc::constify_traits>; +%template(AstVisitor) ast::GenVisitor<misc::id_traits>; +%warnfilter(401); + +%{ +#include "swig_real_type.hh" +%} + +%define HELPER(TYPE, SUPER_TYPE) + void operator()(const ast::##TYPE & e) override + { + CallbackVisitor_Argument arg{++id_, #TYPE, &e}; + auto obj = make_argument_dict(arg); + call_callback(parent_obj_, obj); + + auto save_arg = parent_arg_; + auto save_obj = parent_obj_; + parent_arg_ = arg; + parent_obj_ = obj; + SUPER_TYPE##::operator()(e); + parent_arg_ = save_arg; + parent_obj_ = save_obj; + } +%enddef + +%warnfilter(451) CallbackVisitor_Argument::name; +%inline +{ + ast::Ast* ast_upcast(ast::ChunkList* a) + { + return static_cast<ast::Ast *>(a); + } + +#ifdef SWIGPYTHON + + struct CallbackVisitor_Argument + { + int id{}; + const char* name{}; + const ast::Ast* ast{}; + }; + + class CallbackVisitor + : public ast::DefaultConstVisitor + , public ast::ObjectConstVisitor + { + public: + using super_type = ast::DefaultVisitor; + + CallbackVisitor(PyObject* pyfunc) + : GenVisitor<misc::constify_traits>() + { + Py_XINCREF(pyfunc); + this->callback_ = pyfunc; + } + ~CallbackVisitor() {} + + PyObject* make_argument_dict(const CallbackVisitor_Argument& a) + { + std::ostringstream o; + if (a.ast) o << *a.ast; + std::string name(a.name); + std::string dec_name; + if (auto dec = dynamic_cast<const ast::Dec*>(a.ast)) + dec_name = std::string(dec->name_get()); + auto s = o.str(); + PyObject *obj = get_swig_real_ast_type(*a.ast); + return Py_BuildValue("{s:i,s:s,s:s,s:s,s:O}", + "id", a.id, + "name", name.c_str(), + "string", s.c_str(), + "dec", dec_name.c_str(), + "ast", obj); + } + + PyObject* call_callback(PyObject* from, PyObject* to) const + { + auto arglist = Py_BuildValue("(OO)", from ? from : Py_None, to ? to : Py_None); + auto result = PyObject_CallObject(this->callback_, arglist); + Py_DECREF(arglist); + return result; + } + + HELPER(ArrayExp, ast::DefaultConstVisitor) + HELPER(ArrayTy, ast::DefaultConstVisitor) + HELPER(AssignExp, ast::DefaultConstVisitor) + HELPER(Ast, ast::DefaultConstVisitor) + HELPER(BreakExp, ast::DefaultConstVisitor) + HELPER(CallExp, ast::DefaultConstVisitor) + HELPER(CastExp, ast::DefaultConstVisitor) + HELPER(ChunkList, ast::DefaultConstVisitor) + HELPER(Field, ast::DefaultConstVisitor) + HELPER(FieldInit, ast::DefaultConstVisitor) + HELPER(FieldVar, ast::DefaultConstVisitor) + HELPER(ForExp, ast::DefaultConstVisitor) + HELPER(FunctionChunk, ast::DefaultConstVisitor) + HELPER(FunctionDec, ast::DefaultConstVisitor) + HELPER(IfExp, ast::DefaultConstVisitor) + HELPER(IntExp, ast::DefaultConstVisitor) + HELPER(LetExp, ast::DefaultConstVisitor) + HELPER(NameTy, ast::DefaultConstVisitor) + HELPER(NilExp, ast::DefaultConstVisitor) + HELPER(OpExp, ast::DefaultConstVisitor) + HELPER(RecordExp, ast::DefaultConstVisitor) + HELPER(RecordTy, ast::DefaultConstVisitor) + HELPER(SeqExp, ast::DefaultConstVisitor) + HELPER(SimpleVar, ast::DefaultConstVisitor) + HELPER(StringExp, ast::DefaultConstVisitor) + HELPER(SubscriptVar, ast::DefaultConstVisitor) + HELPER(TypeChunk, ast::DefaultConstVisitor) + HELPER(TypeDec, ast::DefaultConstVisitor) + HELPER(VarChunk, ast::DefaultConstVisitor) + HELPER(VarDec, ast::DefaultConstVisitor) + HELPER(WhileExp, ast::DefaultConstVisitor) + + HELPER(ClassTy, ast::ObjectConstVisitor) + HELPER(MethodChunk, ast::ObjectConstVisitor) + HELPER(MethodCallExp, ast::ObjectConstVisitor) + HELPER(MethodDec, ast::ObjectConstVisitor) + HELPER(ObjectExp, ast::ObjectConstVisitor) + + private: + PyObject* callback_{}; + + int id_{}; + CallbackVisitor_Argument parent_arg_{}; + PyObject* parent_obj_{}; + }; + + ast::ConstVisitor* get_callback_visitor(PyObject* pyfunc) + { + if (!PyCallable_Check(pyfunc)) { + PyErr_SetString(PyExc_TypeError, "Need a callable object!"); + return NULL; + } + + return new CallbackVisitor(pyfunc); + } + +#endif +} + +// Types. +%include "ast/escapable.hh" +%include "ast/typable.hh" +%include "ast/type-constructor.hh" + +%include "ast/field.hh" +%include "ast/field-init.hh" + +// Exps. +%include "ast/exp.hh" +%include "ast/array-exp.hh" +%include "ast/assign-exp.hh" +%include "ast/break-exp.hh" +%include "ast/call-exp.hh" +%include "ast/cast-exp.hh" +%include "ast/for-exp.hh" +%include "ast/if-exp.hh" +%include "ast/int-exp.hh" +%include "ast/let-exp.hh" +%include "ast/method-call-exp.hh" +%include "ast/nil-exp.hh" +%include "ast/object-exp.hh" +%include "ast/op-exp.hh" +%include "ast/record-exp.hh" +%include "ast/seq-exp.hh" +%include "ast/string-exp.hh" +%include "ast/while-exp.hh" + +// Vars. +%include "ast/var.hh" +%include "ast/simple-var.hh" +%include "ast/field-var.hh" +%include "ast/subscript-var.hh" + +// Tys. +%include "ast/ty.hh" +%include "ast/name-ty.hh" +%include "ast/record-ty.hh" +%include "ast/array-ty.hh" +%include "ast/class-ty.hh" + +// ChunkInterface. +%ignore ast::Chunk::operator[]; +%include "ast/chunk-interface.hh" +%include "ast/dec.hh" +%include "ast/function-dec.hh" +%include "ast/method-dec.hh" +%include "ast/var-dec.hh" +%include "ast/type-dec.hh" +%include "ast/chunk-list.hh" +%include "ast/chunk.hh" + +%extend ast::Chunk +{ + int __len__() + { + return std::distance((*$self).begin(), (*$self).end()); + } + + D* __getitem__(int pos) throw(std::out_of_range) + { + int size = std::distance((*$self).begin(), (*$self).end()); + if (pos >= size || pos < -size) + throw std::out_of_range("trying to access chunk item"); + auto front = (*$self).begin(); + std::advance(front, pos >= 0 ? pos : size + pos); + return *front; + } +} + +%template(FunctionChunk) ast::Chunk<ast::FunctionDec>; +%template(MethodChunk) ast::Chunk<ast::MethodDec>; +%template(TypeChunk) ast::Chunk<ast::TypeDec>; +%template(VarChunk) ast::Chunk<ast::VarDec>; +%template(exps_type)std::vector<ast::Exp*>; +%template(fieldinits_type) std::vector<ast::FieldInit*>; +%template(fields_type) std::vector<ast::Field*>; + +%extend ast::ChunkList +{ + int __len__() + { + return std::distance((*$self).begin(), (*$self).end()); + } + + ast::ChunkInterface* __getitem__(int pos) + { + int size = std::distance((*$self).begin(), (*$self).end()); + if (pos >= size || pos < -size) + throw std::out_of_range("trying to access chunk item"); + auto front = (*$self).begin(); + std::advance(front, pos >= 0 ? pos : size + pos); + return *front; + } +} + +%include "ast/libast.hh" diff --git a/tiger-compiler/tcsh/src/tiger_astclone.i b/tiger-compiler/tcsh/src/tiger_astclone.i new file mode 100644 index 0000000..ca8438a --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_astclone.i @@ -0,0 +1,17 @@ +// -*- C++ -*- + +%module tiger_astclone + +%import "tiger_ast.i" + +%{ + #include <astclone/libastclone.hh> + #include "swig_real_type.hh" +%} +%inline +{ + ast::Ast* clone(const ast::Ast& tree) + { + return astclone::clone<ast::Ast>(tree); + } +} diff --git a/tiger-compiler/tcsh/src/tiger_bind.i b/tiger-compiler/tcsh/src/tiger_bind.i new file mode 100644 index 0000000..00034cf --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_bind.i @@ -0,0 +1,13 @@ +// -*- C++ -*- + +%module tiger_bind + +%import "tiger_misc.i" + +%include "std_string.i" + +%{ + #include <bind/libbind.hh> +%} + +%include "bind/libbind.hh" diff --git a/tiger-compiler/tcsh/src/tiger_callgraph.i b/tiger-compiler/tcsh/src/tiger_callgraph.i new file mode 100644 index 0000000..429c451 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_callgraph.i @@ -0,0 +1,18 @@ +// -*- C++ -*- + +%module tiger_callgraph + +%include "std_string.i" + +%{ + #include <callgraph/fundec-graph.hh> + #include <callgraph/libcallgraph.hh> +%} + +namespace callgraph +{ + class FundecGraph; + using CallGraph = FundecGraph; +} + +%include "callgraph/libcallgraph.hh" diff --git a/tiger-compiler/tcsh/src/tiger_combine.i b/tiger-compiler/tcsh/src/tiger_combine.i new file mode 100644 index 0000000..5ac5278 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_combine.i @@ -0,0 +1,14 @@ +// -*- C++ -*- + +%module tiger_combine + +%include "std_pair.i" + +%{ + #include <combine/libcombine.hh> + using namespace combine; +%} + +%template() std::pair<overload::overfun_bindings_type, misc::error>; + +%include "combine/libcombine.hh" diff --git a/tiger-compiler/tcsh/src/tiger_common.i b/tiger-compiler/tcsh/src/tiger_common.i new file mode 100644 index 0000000..ff43652 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_common.i @@ -0,0 +1,73 @@ +// -*- C++ -*- + +%module tiger_common + +%include std_string.i + +%{ + #include <fstream> + #include <sstream> + #include <iostream> + #include <cassert> + #include <string> + #include <misc/timer.hh> +%} + +// Warning 454: Setting a pointer/reference variable may leak memory. +%warnfilter(454) Cout; +%warnfilter(454) Cerr; +%warnfilter(454) Clog; + +// Ofstream. +%inline %{ + struct Ofstream + { + Ofstream (const std::string& filename) : closed_ (false) + { + stream_ = new std::ofstream (filename.c_str ()); + } + + ~Ofstream () + { + if (!closed_) + close (); + } + + std::ostream& + to () + { + assert (stream_); + return *stream_; + } + + void + close () + { + assert (stream_); + stream_->close (); + delete stream_; + closed_ = true; + } + + std::ofstream* stream_; + bool closed_; + }; + + std::ostream& + get_cout() + { + return std::cout; + } + + std::ostream& + get_cerr() + { + return std::cerr; + } + + std::ostream* Cout = &std::cout; + std::ostream* Cerr = &std::cerr; + std::ostream* Clog = &std::clog; + + misc::timer timer; +%} diff --git a/tiger-compiler/tcsh/src/tiger_desugar.i b/tiger-compiler/tcsh/src/tiger_desugar.i new file mode 100644 index 0000000..94f6b82 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_desugar.i @@ -0,0 +1,30 @@ +// -*- C++ -*- + +%module tiger_desugar + +%import "tiger_ast.i" + +%{ + #include <desugar/libdesugar.hh> + #include <ast/all.hh> + #include "swig_real_type.hh" +%} + +%rename(desugar) ast_desugar; +%rename(raw_desugar) ast_raw_desugar; + +%inline { +ast::Ast* ast_desugar(const ast::Ast& tree, + bool desugar_for = false, + bool desugar_string_cmp = false) +{ + return desugar::desugar<ast::Ast>(tree, desugar_for, desugar_string_cmp); +} +ast::Ast* ast_raw_desugar(const ast::Ast& tree, + bool desugar_for = false, + bool desugar_string_cmp = false) +{ + return desugar::raw_desugar<ast::Ast>(tree, desugar_for, desugar_string_cmp); +} +} + diff --git a/tiger-compiler/tcsh/src/tiger_escapes.i b/tiger-compiler/tcsh/src/tiger_escapes.i new file mode 100644 index 0000000..b176790 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_escapes.i @@ -0,0 +1,11 @@ +// -*- C++ -*- + +%module tiger_escapes + +%include "std_string.i" + +%{ + #include <escapes/libescapes.hh> +%} + +%include "escapes/libescapes.hh" diff --git a/tiger-compiler/tcsh/src/tiger_llvmtranslate.i b/tiger-compiler/tcsh/src/tiger_llvmtranslate.i new file mode 100644 index 0000000..70fade9 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_llvmtranslate.i @@ -0,0 +1,39 @@ +// -*- C++ -*- + +%module tiger_llvmtranslate + +%include "std_string.i" + +%{ + #include <llvmtranslate/libllvmtranslate.hh> + #include <llvmtranslate/tasks.hh> + #include <llvm/IR/IRPrintingPasses.h> + #include <llvm/Linker/Linker.h> + #include <llvm/IR/Module.h> +%} + +%inline +{ + std::string translate(const ast::Ast& tree) + { + auto module = llvmtranslate::translate(tree); + auto runtime = llvmtranslate::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 + postcondition(!link); // Returns true on error + + std::string str; + llvm::raw_string_ostream out(str); + 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 + return out.str(); + } +} diff --git a/tiger-compiler/tcsh/src/tiger_misc.i b/tiger-compiler/tcsh/src/tiger_misc.i new file mode 100644 index 0000000..7e1470f --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_misc.i @@ -0,0 +1,73 @@ +// -*- C++ -*- + +%module tiger_misc + +%include "std_string.i" + +%{ + #include <sstream> + + #include <misc/file-library.hh> + #include <misc/symbol.hh> + #include <misc/error.hh> + // The need for this using directive seems to be a SWIG bug. It is + // needed by the _wrap_error___lshift____SWIG_5 in the C++ wrapper + // generated by swig (tiger_bind-wrap.cc). + using misc::error; + + #include <misc/timer.hh> +%} + +%exception { + try { + $function + } catch (const misc::error& e) + { + std::ostringstream o; + o << e; + PyObject *err = Py_BuildValue("is", e.status_get_value(), o.str().c_str()); + PyErr_SetObject(PyExc_RuntimeError, err); + SWIG_fail; + } +} + +%include "misc/file-library.hh" + +// Save some warnings from SWIG. +%ignore misc::error::operator=; +%ignore misc::error::operator bool; + +// SWIG has trouble wrapping some of misc::error's operator<<'s; ignore them. +%ignore misc::error::operator<<; + +%include "misc/error.hh" + +// Wrap misc::error::operator<<. +%extend misc::error +{ + std::string __str__() const + { + std::ostringstream o; + o << *$self; + return o.str(); + } + + %pythoncode %{ + @staticmethod + def error_type_message() -> dict[int, str]: + return { getattr(_tiger_misc, t): t[len("error_error_type_"):].upper() for t in dir(_tiger_misc) if t.startswith("error_error_type_") } + %} +} + +%ignore misc::symbol::operator=; +%ignore misc::symbol::operator<<; +%include "misc/symbol.hh" +%extend misc::symbol +{ + std::string __str__() const + { + return ($self)->get(); + } +} + +%include "misc/timer.hh" diff --git a/tiger-compiler/tcsh/src/tiger_object.i b/tiger-compiler/tcsh/src/tiger_object.i new file mode 100644 index 0000000..cd81eec --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_object.i @@ -0,0 +1,32 @@ +// -*- C++ -*- + +%module tiger_object + +%import "tiger_ast.i" + +%{ + #include <object/libobject.hh> + #include <ast/all.hh> + #include "swig_real_type.hh" +%} + +%import "tiger_misc.i" + +%rename(desugar) object_desugar; +%rename(raw_desugar) object_raw_desugar; + +%inline { +ast::Ast* object_desugar(const ast::Ast& tree, + const object::class_names_type& class_names) +{ + return object::desugar<ast::Ast>(tree, class_names); +} +ast::Ast* object_raw_desugar(const ast::Ast& tree, + const object::class_names_type& class_names) +{ + return object::raw_desugar<ast::Ast>(tree, class_names); +} +} + +%include "object/fwd.hh" +%include "object/libobject.hh" diff --git a/tiger-compiler/tcsh/src/tiger_overload.i b/tiger-compiler/tcsh/src/tiger_overload.i new file mode 100644 index 0000000..7a9090c --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_overload.i @@ -0,0 +1,14 @@ +// -*- C++ -*- + +%module tiger_overload + +%include "std_pair.i" + +%{ + #include <overload/liboverload.hh> + using namespace overload; +%} + +%template() std::pair<overfun_bindings_type, misc::error>; + +%include "overload/liboverload.hh" diff --git a/tiger-compiler/tcsh/src/tiger_parse.i b/tiger-compiler/tcsh/src/tiger_parse.i new file mode 100644 index 0000000..1d62bd8 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_parse.i @@ -0,0 +1,102 @@ +// -*- C++ -*- + +%module tiger_parse + +%include "std_string.i" +%include "std_pair.i" + +%{ + #include <sstream> + #include <misc/error.hh> + #include <parse/location.hh> + #include <parse/tiger-driver.hh> + #include <parse/libparse.hh> +%} + +%import "tiger_misc.i" + +%include "parse/fwd.hh" + +// Explicit instantiation of MetavarMap's. +%include "parse/metavar-map.hh" +%template(MetavarMap) parse::MetavarMap<ast::Exp>; +%template(MetavarVar) parse::MetavarMap<ast::Var>; +%template(MetavarNameTy) parse::MetavarMap<ast::NameTy>; +%template(MetavarChunkList) parse::MetavarMap<ast::ChunkList>; +%template(MetavarTweast) parse::MetavarMap<parse::Tweast>; + +/*------------------. +| parse::position. | +`------------------*/ + +// Replace parse::position's ctor and ignore parse::position::initialize, +// as Python is unable to parse the literal `1u' used as default value +// of two of their arguments. +%extend parse::position +{ + // External ctor. For more information, see + // http://www.nabble.com/Java---adding-code-to-a-constructor-td20210601.html + position (const std::string* f = nullptr, + unsigned int l = 1, unsigned int c = 1) + { + return new parse::position(f, l, c); + } +} +%ignore parse::position::position; +%ignore parse::position::initialize; +%extend parse::position +{ + std::string + __str__ () const + { + std::ostringstream o; + o << *$self; + return o.str (); + } +} + +/*------------------. +| parse::location. | +`------------------*/ + +// Ignore parse::location::initialize, as Python is unable to +// parse the literal `1u' used as default value of two of its +// arguments. +%ignore parse::location::initialize; +%include "parse/location.hh" +%extend parse::location +{ + std::string + __str__ () const + { + std::ostringstream o; + o << *$self; + return o.str (); + } +} + +/*-----------. +| libparse. | +`-----------*/ + +%import "parse/tweast.hh" +%include "parse/tiger-driver.hh" +%inline +{ + namespace parse + { + // Parse a Tiger file, return the corresponding abstract syntax. + ast::ChunkList* + parse (const std::string& prelude, const std::string& fname, + misc::file_library& library) + { + std::pair<ast::ChunkList*, misc::error> res = + parse (prelude, fname, library, false, false, true); + res.second.exit_on_error(); + return res.first; + } + } + +} + +%include "parse/libparse.hh" diff --git a/tiger-compiler/tcsh/src/tiger_type.i b/tiger-compiler/tcsh/src/tiger_type.i new file mode 100644 index 0000000..5679873 --- /dev/null +++ b/tiger-compiler/tcsh/src/tiger_type.i @@ -0,0 +1,91 @@ +// -*- C++ -*- + +%module tiger_type + +%include "std_string.i" + +%include "misc/singleton.hh" + +%{ + #include "helper.hh" + #include <type/libtype.hh> + #include <misc/singleton.hh> + + #include <type/fwd.hh> + #include <type/type.hh> + #include <type/array.hh> + #include <type/builtin-types.hh> + #include <type/class.hh> + #include <type/field.hh> + #include <type/function.hh> + #include <type/method.hh> + #include <type/named.hh> + #include <type/nil.hh> + #include <type/record.hh> + + #include <type/visitor.hh> + #include <type/pretty-printer.hh> +%} + +%typemap(ret) type::Type* { + $result = _get_swig_real_type_type(*$1); +} + +%warnfilter(401); + +%include "type/fwd.hh" +%include "type/type.hh" + +%extend type::Type +{ + std::string __str__() const + { + std::ostringstream o; + o << *$self; + return o.str(); + } +} +%{ +namespace { + using namespace type; + class SwigTypeVisitor : public ConstVisitor + { + public: + PyObject *result; + +#define STHELPER(TYPE) STCONVERT(TYPE, p_type__ ## TYPE) + STHELPER(Array) + STHELPER(Class) + STHELPER(Function) + STHELPER(Int) + STHELPER(Method) + STHELPER(Named) + STHELPER(Nil) + STHELPER(Record) + STHELPER(String) + STHELPER(Void) +#undef STHELPER + }; +} // namespace +%} +%inline %{ +PyObject *_get_swig_real_type_type(const type::Type& e) +{ + SwigTypeVisitor stv; + e.accept(stv); + return stv.result; +} +%} + + +%include "type/array.hh" +%include "type/builtin-types.hh" +%include "type/class.hh" +%include "type/field.hh" +%include "type/function.hh" +%include "type/method.hh" +%include "type/named.hh" +%include "type/nil.hh" +%include "type/record.hh" + +%include "type/libtype.hh" |
