diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 62ff3680b..9fb3b7bf2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,83 +1,83 @@ -name: Tests - -on: [push, pull_request] - -jobs: - lexer: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup Python - uses: actions/setup-python@v2 - - - name: Install requirements - run: pip install -r requirements.txt - - - name: Run tests - run: | - cd src - make clean - make - make test TAG=lexer - - parser: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup Python - uses: actions/setup-python@v2 - - - name: Install requirements - run: pip install -r requirements.txt - - - name: Run tests - run: | - cd src - make clean - make - make test TAG=parser - - semantic: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup Python - uses: actions/setup-python@v2 - - - name: Install requirements - run: pip install -r requirements.txt - - - name: Run tests - run: | - cd src - make clean - make - make test TAG=semantic - - codegen: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Setup Python - uses: actions/setup-python@v2 - - - name: Install requirements - run: pip install -r requirements.txt - - - name: Install spim - run: sudo apt-get install spim - - - name: Run tests - run: | - cd src - make clean - make - make test TAG=codegen +name: Tests + +on: [push, pull_request] + +jobs: + lexer: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=lexer + + parser: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=parser + + semantic: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=semantic + + codegen: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Setup Python + uses: actions/setup-python@v2 + + - name: Install requirements + run: pip install -r requirements.txt + + - name: Install spim + run: sudo apt-get install spim + + - name: Run tests + run: | + cd src + make clean + make + make test TAG=codegen diff --git a/.gitignore b/.gitignore index 4acafde18..fe260740f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,410 +1,417 @@ -# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig - -# Created by https://www.gitignore.io/api/visualstudiocode,linux,latex,python -# Edit at https://www.gitignore.io/?templates=visualstudiocode,linux,latex,python - -### LaTeX ### -## Core latex/pdflatex auxiliary files: -*.aux -*.lof -*.log -*.lot -*.fls -*.out -*.toc -*.fmt -*.fot -*.cb -*.cb2 -.*.lb - -## Intermediate documents: -*.dvi -*.xdv -*-converted-to.* -# these rules might exclude image files for figures etc. -# *.ps -# *.eps -# *.pdf - -## Generated if empty string is given at "Please type another file name for output:" -.pdf - -## Bibliography auxiliary files (bibtex/biblatex/biber): -*.bbl -*.bcf -*.blg -*-blx.aux -*-blx.bib -*.run.xml - -## Build tool auxiliary files: -*.fdb_latexmk -*.synctex -*.synctex(busy) -*.synctex.gz -*.synctex.gz(busy) -*.pdfsync - -## Build tool directories for auxiliary files -# latexrun -latex.out/ - -## Auxiliary and intermediate files from other packages: -# algorithms -*.alg -*.loa - -# achemso -acs-*.bib - -# amsthm -*.thm - -# beamer -*.nav -*.pre -*.snm -*.vrb - -# changes -*.soc - -# comment -*.cut - -# cprotect -*.cpt - -# elsarticle (documentclass of Elsevier journals) -*.spl - -# endnotes -*.ent - -# fixme -*.lox - -# feynmf/feynmp -*.mf -*.mp -*.t[1-9] -*.t[1-9][0-9] -*.tfm - -#(r)(e)ledmac/(r)(e)ledpar -*.end -*.?end -*.[1-9] -*.[1-9][0-9] -*.[1-9][0-9][0-9] -*.[1-9]R -*.[1-9][0-9]R -*.[1-9][0-9][0-9]R -*.eledsec[1-9] -*.eledsec[1-9]R -*.eledsec[1-9][0-9] -*.eledsec[1-9][0-9]R -*.eledsec[1-9][0-9][0-9] -*.eledsec[1-9][0-9][0-9]R - -# glossaries -*.acn -*.acr -*.glg -*.glo -*.gls -*.glsdefs - -# uncomment this for glossaries-extra (will ignore makeindex's style files!) -# *.ist - -# gnuplottex -*-gnuplottex-* - -# gregoriotex -*.gaux -*.gtex - -# htlatex -*.4ct -*.4tc -*.idv -*.lg -*.trc -*.xref - -# hyperref -*.brf - -# knitr -*-concordance.tex -# TODO Comment the next line if you want to keep your tikz graphics files -*.tikz -*-tikzDictionary - -# listings -*.lol - -# luatexja-ruby -*.ltjruby - -# makeidx -*.idx -*.ilg -*.ind - -# minitoc -*.maf -*.mlf -*.mlt -*.mtc[0-9]* -*.slf[0-9]* -*.slt[0-9]* -*.stc[0-9]* - -# minted -_minted* -*.pyg - -# morewrites -*.mw - -# nomencl -*.nlg -*.nlo -*.nls - -# pax -*.pax - -# pdfpcnotes -*.pdfpc - -# sagetex -*.sagetex.sage -*.sagetex.py -*.sagetex.scmd - -# scrwfile -*.wrt - -# sympy -*.sout -*.sympy -sympy-plots-for-*.tex/ - -# pdfcomment -*.upa -*.upb - -# pythontex -*.pytxcode -pythontex-files-*/ - -# tcolorbox -*.listing - -# thmtools -*.loe - -# TikZ & PGF -*.dpth -*.md5 -*.auxlock - -# todonotes -*.tdo - -# vhistory -*.hst -*.ver - -# easy-todo -*.lod - -# xcolor -*.xcp - -# xmpincl -*.xmpi - -# xindy -*.xdy - -# xypic precompiled matrices -*.xyc - -# endfloat -*.ttt -*.fff - -# Latexian -TSWLatexianTemp* - -## Editors: -# WinEdt -*.bak -*.sav - -# Texpad -.texpadtmp - -# LyX -*.lyx~ - -# Kile -*.backup - -# KBibTeX -*~[0-9]* - -# auto folder when using emacs and auctex -./auto/* -*.el - -# expex forward references with \gathertags -*-tags.tex - -# standalone packages -*.sta - -### LaTeX Patch ### -# glossaries -*.glstex - -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# celery beat schedule file -celerybeat-schedule - -# SageMath parsed files -*.sage.py - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -# End of https://www.gitignore.io/api/visualstudiocode,linux,latex,python - -# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) - +# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig + +# Created by https://www.gitignore.io/api/visualstudiocode,linux,latex,python +# Edit at https://www.gitignore.io/?templates=visualstudiocode,linux,latex,python + +### LaTeX ### +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps +# *.pdf + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## User defined files: +*_log.txt + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# comment +*.cut + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs + +# uncomment this for glossaries-extra (will ignore makeindex's style files!) +# *.ist + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Comment the next line if you want to keep your tikz graphics files +*.tikz +*-tikzDictionary + +# listings +*.lol + +# luatexja-ruby +*.ltjruby + +# makeidx +*.idx +*.ilg +*.ind + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# tcolorbox +*.listing + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# todonotes +*.tdo + +# vhistory +*.hst +*.ver + +# easy-todo +*.lod + +# xcolor +*.xcp + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices +*.xyc + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# LyX +*.lyx~ + +# Kile +*.backup + +# KBibTeX +*~[0-9]* + +# auto folder when using emacs and auctex +./auto/* +*.el + +# expex forward references with \gathertags +*-tags.tex + +# standalone packages +*.sta + +### LaTeX Patch ### +# glossaries +*.glstex + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# lib named project folders +!src/cool2/lib +!src/cool2/cool/lib + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history + +# End of https://www.gitignore.io/api/visualstudiocode,linux,latex,python + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..4c5c0ce57 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Archivo actual", + "type": "python", + "request": "launch", + "program": "src/cool_cmp/main.py", + "args": ["src/testing.cl", "src/testing.mips", "-m"], + // "args": ["src/testing.cl", "src/testing.mips", "-icil", "-c"], + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ed4759fc2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "python.testing.cwd": "./src", + "python.testing.pytestArgs": [ + "../" + ], + "python.testing.unittestEnabled": false, + "python.testing.nosetestsEnabled": false, + "python.testing.pytestEnabled": true, + "python.linting.mypyEnabled": true, + "python.linting.enabled": true, + "python.linting.pylintEnabled": false, + "python.analysis.extraPaths": ["./src/cool_cmp/"] +} \ No newline at end of file diff --git a/LICENSE b/LICENSE index 718bd210a..7f19c2d8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2021 School of Math and Computer Science, University of Havana - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2021 School of Math and Computer Science, University of Havana + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Readme.md b/Readme.md index a47d48b9e..0e33ddb08 100644 --- a/Readme.md +++ b/Readme.md @@ -1,172 +1,172 @@ -# COOL: Proyecto de Compilación - -> Proyecto base para el compilador de 4to año en Ciencia de la Computación. - -## Generalidades - -La evaluación de la asignatura Complementos de Compilación, inscrita en el programa del 4to año de la Licenciatura en Ciencia de la Computación de la Facultad de Matemática y Computación de la -Universidad de La Habana, consiste este curso en la implementación de un compilador completamente -funcional para el lenguaje _COOL_. - -_COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. - -## Cómo comenzar (o terminar) - -El proyecto de Compilación será recogido y evaluado **únicamente** a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. A continuación le damos las instrucciones mínimas necesarias para ello: - -### 1. Si no lo han hecho ya, regístrense en [Github](https://github.com) todos los miembros del equipo (es gratis). - -![](img/img1.png) - -### 2. Haga click en el botón **Fork** para hacer una copia del proyecto en el perfil de Github de uno de los miembros. - -Opcionalmente pueden [crear una organización](https://github.com/organizations/new) y copiar el proyecto en el perfil de la misma. - -![](img/img2.png) - -### 3. Una vez hecho esto, tendrá un nuevo repositorio en `github/`. - -Revise que el repositorio de su equipo está en su perfil. -En este ejemplo se ha copiado a la cuenta de `github.com/apiad`. - -Debe indicar bajo el nombre del repositorio: `"forked from matcom/cool-compiler-2021"`. - -![](img/img3.png) - -### 4. Clone este proyecto en un repositorio local. - -Busque la URL de su proyecto en la interfaz web de Github. - -Asegúrese de clonar **su copia** y no el proyecto original en `matcom/cool-compiler-2021`. - -![](img/img4.png) - -```bash -$ git clone git@github.com:/cool-compiler-2021.git -``` - -> Donde `` es posiblemente el nombre de su equipo o del miembro donde se hizo el _fork_. - -A partir de este punto debe tener un proyecto `cool-compiler-2021` local. -El siguiente paso depende de si usted ya tiene su código versionado con `git` o no. - -### 5.A. Si tiene su proyecto en git (y no quiere perder la historia): - -#### 5.1. Mezcle hacia el nuevo respositorio su repositorio anterior: - -```bash -$ cd cool-compiler-2021 -$ git pull --allow-unrelated-histories master -``` - -#### 5.2. Organice su proyecto, código fuente y documentación, de acuerdo a las instrucciones de este documento, y vuelva a hacer `commit`. - -```bash -$ mv src/ -$ git add . -$ git commit -a -m "Mezclado con el proyecto base" -``` - -#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. - -```bash -$ git push origin master -``` - -### 5.B Si aún no tiene su proyecto en git (o no le importa la historia): - -#### 5.1. Simplemente copie el código de su proyecto en la carpeta correspondiente `src` y haga su primer commit. - -```bash -$ mv src/ -$ git commit -a -m "Hello Git!" -``` - -#### 5.2. A partir de este punto asegúrese de hacer `commit` de forma regular para mantener su repositorio actualizado. - -Si necesita saber más sobre `git`, todo lo imprescindible está en [esta guía](doc/github-git-cheat-sheet.pdf). - -#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. - -```bash -$ git push origin master -``` - -## Entregas - -En este proyecto se realizarán entregas parciales a lo largo del curso. Para realizar una entrega, siga los siguientes pasos. - -### 1. Cree un pull request al proyecto original desde su copia. - -![](img/img5.png) - -### 2. Asegúrese de tener la siguiente configuración antes de hacer click en **Create pull request**. - -- **base repository**: `matcom/cool-compiler-2021` (repositorio original) - - **branch**: `master` -- **head repository**: `/cool-compiler-2021` (repositorio propio) - - **branch**: `master` (o la que corresponda) - -> Asegúrese que se indica **Able to merge**. De lo contrario, existen cambios en el repositorio original que usted no tiene, y debe actualizarlos. - -> **NOTA**: Asegúrese que el _pull request_ se hace a la rama `master`. - -![](img/img6.png) - -### 3. Introduzca un título y descripción adecuados, y haga click en **Create pull request**. - -![](img/img7.png) - -### 4. Espere mientras se ejecutan las pruebas. - -Verá la indicación **Some checks haven't completed yet**. - -![](img/img8.png) - -Es posible que tenga que actualizar los cambios que se hayan hecho en el repositorio original, por ejemplo, si se han agregado nuevos tests. En este caso obtendrá el siguiente mensaje: - -> **This branch is out-of-date with base branch** - -Haga click en **Update branch** y siga las instrucciones. -### 5. Verifique que no hubo errores en las pruebas. - -Si ve el mensaje **(All | Some) checks have failed**, significa que su código no pasó las pruebas. - -![](img/img9.png) - -Para ver los resultados de las pruebas haga click en el link **Details**. - -![](img/img10.png) - - -### 6. Arregle los errores y repita el paso 5 hasta que todas las pruebas pasen. - -Para cualquier modificación que haga a su proyecto, haga _commit_ y _push_ para **su repositorio personal** y automáticamente se actualizará el estado del _pull request_ y se volverán a ejecutar las pruebas. **No es necesario** abrir un _pull request_ nuevo por cada entrega, sino actualizar el anterior. - -> **Por favor asegúrese de mantener un solo _pull request_ activo por equipo**. En caso de abrir uno nuevo, cerrar el anterior. - -## Sobre la implementación - -Ponga todo su código e instrucciones necesarias en la carpeta `src`. Más información en [`src/Readme.md`](src/Readme.md). - -## Sobre la documentación - -Usted debe presentar un reporte escrito documentando el proceso de construcción de su compilador y los detalles más importantes de su funcionamiento. Más información en [`doc/Readme.md`](doc/Readme.md). - -## Sobre los equipos de desarrollo - -Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. - -## Sobre los casos de prueba - -La carpeta `tests` contiene todos los casos de prueba que son obligatorios de pasar para que su proyecto tenga derecho a ser evaluado. - -Estos tests se ejecutan automáticamente cada vez que hace un _pull request_ al repositorio `matcom/cool-compiler-2021`. Solo aquellos proyectos que pasen todas las pruebas con éxito serán evaluados. - -Para ejecutar las pruebas localmente, debe tener instalado `Python 3.7`, `pip` y `make` (normalmente viene con Linux). Ejecute: - -```bash -$ pip install -r requirements.txt -$ cd src -$ make test -``` +# COOL: Proyecto de Compilación + +> Proyecto base para el compilador de 4to año en Ciencia de la Computación. + +## Generalidades + +La evaluación de la asignatura Complementos de Compilación, inscrita en el programa del 4to año de la Licenciatura en Ciencia de la Computación de la Facultad de Matemática y Computación de la +Universidad de La Habana, consiste este curso en la implementación de un compilador completamente +funcional para el lenguaje _COOL_. + +_COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. + +## Cómo comenzar (o terminar) + +El proyecto de Compilación será recogido y evaluado **únicamente** a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. A continuación le damos las instrucciones mínimas necesarias para ello: + +### 1. Si no lo han hecho ya, regístrense en [Github](https://github.com) todos los miembros del equipo (es gratis). + +![](img/img1.png) + +### 2. Haga click en el botón **Fork** para hacer una copia del proyecto en el perfil de Github de uno de los miembros. + +Opcionalmente pueden [crear una organización](https://github.com/organizations/new) y copiar el proyecto en el perfil de la misma. + +![](img/img2.png) + +### 3. Una vez hecho esto, tendrá un nuevo repositorio en `github/`. + +Revise que el repositorio de su equipo está en su perfil. +En este ejemplo se ha copiado a la cuenta de `github.com/apiad`. + +Debe indicar bajo el nombre del repositorio: `"forked from matcom/cool-compiler-2021"`. + +![](img/img3.png) + +### 4. Clone este proyecto en un repositorio local. + +Busque la URL de su proyecto en la interfaz web de Github. + +Asegúrese de clonar **su copia** y no el proyecto original en `matcom/cool-compiler-2021`. + +![](img/img4.png) + +```bash +$ git clone git@github.com:/cool-compiler-2021.git +``` + +> Donde `` es posiblemente el nombre de su equipo o del miembro donde se hizo el _fork_. + +A partir de este punto debe tener un proyecto `cool-compiler-2021` local. +El siguiente paso depende de si usted ya tiene su código versionado con `git` o no. + +### 5.A. Si tiene su proyecto en git (y no quiere perder la historia): + +#### 5.1. Mezcle hacia el nuevo respositorio su repositorio anterior: + +```bash +$ cd cool-compiler-2021 +$ git pull --allow-unrelated-histories master +``` + +#### 5.2. Organice su proyecto, código fuente y documentación, de acuerdo a las instrucciones de este documento, y vuelva a hacer `commit`. + +```bash +$ mv src/ +$ git add . +$ git commit -a -m "Mezclado con el proyecto base" +``` + +#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. + +```bash +$ git push origin master +``` + +### 5.B Si aún no tiene su proyecto en git (o no le importa la historia): + +#### 5.1. Simplemente copie el código de su proyecto en la carpeta correspondiente `src` y haga su primer commit. + +```bash +$ mv src/ +$ git commit -a -m "Hello Git!" +``` + +#### 5.2. A partir de este punto asegúrese de hacer `commit` de forma regular para mantener su repositorio actualizado. + +Si necesita saber más sobre `git`, todo lo imprescindible está en [esta guía](doc/github-git-cheat-sheet.pdf). + +#### 5.3. A partir de este punto puede hacer `push` cada vez que tenga cambios que subir. + +```bash +$ git push origin master +``` + +## Entregas + +En este proyecto se realizarán entregas parciales a lo largo del curso. Para realizar una entrega, siga los siguientes pasos. + +### 1. Cree un pull request al proyecto original desde su copia. + +![](img/img5.png) + +### 2. Asegúrese de tener la siguiente configuración antes de hacer click en **Create pull request**. + +- **base repository**: `matcom/cool-compiler-2021` (repositorio original) + - **branch**: `master` +- **head repository**: `/cool-compiler-2021` (repositorio propio) + - **branch**: `master` (o la que corresponda) + +> Asegúrese que se indica **Able to merge**. De lo contrario, existen cambios en el repositorio original que usted no tiene, y debe actualizarlos. + +> **NOTA**: Asegúrese que el _pull request_ se hace a la rama `master`. + +![](img/img6.png) + +### 3. Introduzca un título y descripción adecuados, y haga click en **Create pull request**. + +![](img/img7.png) + +### 4. Espere mientras se ejecutan las pruebas. + +Verá la indicación **Some checks haven't completed yet**. + +![](img/img8.png) + +Es posible que tenga que actualizar los cambios que se hayan hecho en el repositorio original, por ejemplo, si se han agregado nuevos tests. En este caso obtendrá el siguiente mensaje: + +> **This branch is out-of-date with base branch** + +Haga click en **Update branch** y siga las instrucciones. +### 5. Verifique que no hubo errores en las pruebas. + +Si ve el mensaje **(All | Some) checks have failed**, significa que su código no pasó las pruebas. + +![](img/img9.png) + +Para ver los resultados de las pruebas haga click en el link **Details**. + +![](img/img10.png) + + +### 6. Arregle los errores y repita el paso 5 hasta que todas las pruebas pasen. + +Para cualquier modificación que haga a su proyecto, haga _commit_ y _push_ para **su repositorio personal** y automáticamente se actualizará el estado del _pull request_ y se volverán a ejecutar las pruebas. **No es necesario** abrir un _pull request_ nuevo por cada entrega, sino actualizar el anterior. + +> **Por favor asegúrese de mantener un solo _pull request_ activo por equipo**. En caso de abrir uno nuevo, cerrar el anterior. + +## Sobre la implementación + +Ponga todo su código e instrucciones necesarias en la carpeta `src`. Más información en [`src/Readme.md`](src/Readme.md). + +## Sobre la documentación + +Usted debe presentar un reporte escrito documentando el proceso de construcción de su compilador y los detalles más importantes de su funcionamiento. Más información en [`doc/Readme.md`](doc/Readme.md). + +## Sobre los equipos de desarrollo + +Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. + +## Sobre los casos de prueba + +La carpeta `tests` contiene todos los casos de prueba que son obligatorios de pasar para que su proyecto tenga derecho a ser evaluado. + +Estos tests se ejecutan automáticamente cada vez que hace un _pull request_ al repositorio `matcom/cool-compiler-2021`. Solo aquellos proyectos que pasen todas las pruebas con éxito serán evaluados. + +Para ejecutar las pruebas localmente, debe tener instalado `Python 3.7`, `pip` y `make` (normalmente viene con Linux). Ejecute: + +```bash +$ pip install -r requirements.txt +$ cd src +$ make test +``` diff --git a/doc/Manual de CIL.md b/doc/Manual de CIL.md new file mode 100644 index 000000000..edc23f342 --- /dev/null +++ b/doc/Manual de CIL.md @@ -0,0 +1,497 @@ +# MANUAL DE CIL + +## RESTRICCIONES + +- Los tipos son identificadores que comienzan con mayúscula +- Las variables son todas minúsculas + +## INSTRUCCIONES + +### Tipos + +Sección destinada a la definción de los tipos. + +Se inicializa la sección de tipos con : + +```python +.TYPES +``` + +y se agrega una nueva definición de tipo según sea necesario de la siguiente manera : + +``` python +.TYPES + +type { + # PARENT (ONLY ONE) + parent: + + # ATTRIBUTES + attribute + ... + ... + ... + + # METHODS + method : + ... + ... + ... +} +``` + +Aqui vemos el ejemplo del tipo Main: + +``` python +.TYPES + +type Main { + parent: IO + + attribute a + attribute b + + method __init: __init_Main_type + method __init_a_at_Main: __init_a_at_Main + method __init_b_at_Main: __init_b_at_Main + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method main: function_main_at_Main +} +``` + +### Datos + +Sección destinada a la definción de los datos estáticos del programa. + +Se inicializa la sección de datos con : + +``` python +.DATA +``` + +y se agrega una nueva definición de dato según sea necesario de la siguiente manera : + +``` python +.DATA + + # CADENAS CONSTANTES + = + ... + ... + ... +``` + +Aqui vemos el ejemplo de la cadena constante "Hola Mundo": + +``` python +.DATA + +string_hola_mundo = "Hola Mundo" +``` + +### Código + +Sección destinada a la definción de las funciones del programa. Tiene que existir una función llamada main la cual es el punto de entrada al programa. + +Se inicializa la sección de código con : + +``` python +.CODE +``` + +y se agrega una nueva definición de código según sea necesario de la siguiente manera : + +``` python +.CODE + + # FUNCIONES + function { + # PARAMETERS + PARAM + ... + ... + ... + + # LOCAL VARIABLES + LOCAL + ... + ... + ... + + # CODE + + ... + ... + ... + + # RETURN + RETURN + } +``` + +Aquí vemos el ejemplo de la función main: + +``` python + +.CODE +function function_main_at_Main { + PARAM self + + LOCAL local_main_at_Main_internal_0 + LOCAL local_main_at_Main_internal_1 + + local_main_at_Main_internal_0 = LOAD data_0 + ARG self + ARG local_main_at_Main_internal_0 + local_main_at_Main_internal_1 = CALL function_out_string_at_IO + + RETURN local_main_at_Main_internal_1 +} +``` + +### KeyWords + +* ABORT + >Indica que se debe abortar la ejecución del programa + + ```python + # Ejemplo + ABORT + ``` + +* ALLOCATE + > Reserva memoria para un objeto de tipo b y devuelve la dirección en a + + ```python + # Ejemplo + a = ALLOCATE b + ``` + +* ARG + > Indica que el próximo llamado a **CALL** acepta el argumento siguiente al comando + + ```python + # Ejemplo + ARG self + CALL __init_Main_type + ``` + +* ARRAY + > Crea un arreglo de objetos de tipo b de tamaño length devolviendo la dirección de este en a + + ```python + # Ejemplo + a = ARRAY b length + ``` + +* CALL + >Indica que la siguiente expresion es una llamada a una función + + ```python + # Ejemplo + ARG self + CALL __init_Main_type + ``` + +* CONCAT + > Devuelve la concatenación de los strings b y c en a + + ```python + # Ejemplo + a = CONCAT b c + ``` + +* COPY + >Copia superficialmente el objeto b en a + + ```python + # Ejemplo + a = COPY b + ``` + +* OBJEQUAL + >Indica si los objetos a y b son iguales guardando el resultado en c + + ```python + # Ejemplo + c = OBJEQUAL a b + ``` + +* EQUAL + >Indica si a y b son iguales guardando el resultado en c + + ```python + # Ejemplo + c = EQUAL a b + ``` + +* FATHER + >Devuelve el padre del tipo del siguente objeto a + + ```python + # Ejemplo + father = FATHER a + ``` + +* GETATTR + > Obtiene el valor del atributo c del objeto b en a + + ```python + # Ejemplo + a = GETATTR b c + ``` + +* GETINDEX + > Obtiene el valor objeto del índice c del arreglo b en a + + ```python + # Ejemplo + a = GETINDEX b c + ``` + +* GOTO + > Salto incondicional a label + + ```python + # Ejemplo + GOTO label + ``` + +* IFGOTO + > Si a es verdadero realiza un salto a label + + ```python + # Ejemplo + IF a GOTO label + ``` + +* LABEL + >Define una etiqueta en el programa + + ```python + # Ejemplo + LABEL label_0 + ``` + + >Etiquetas son utilizadas para definir un punto de entrada a una parte del código tanto para ciclos como para anotaciones. + +* LENGTH + >Devuelve la longitud del string b en a + + ```python + # Ejemplo + a = LENGTH b + ``` + +* LOAD + >Carga el dato de la sección .DATA data_0 en a + + ```python + # Ejemplo + a = LOAD data_0 + ``` + +* LOCAL + > Define una variable local llamada a + + ```python + # Ejemplo + LOCAL a + ``` + +* NOT + > Devuelve la negación de b en a + + ```python + # Ejemplo + a = NOT b + ``` + +* PARAM + > Indica que la función acepta el parámetro self, vinculando el valor pasado en los argumentos con dicho nombre + + ```python + # Ejemplo + PARAM self + ``` + +* PRINT + > Imprime el string a + + ```python + # Ejemplo + PRINT a + ``` +* PRINTINT + > Imprime el entero a + + ```python + # Ejemplo + PRINTINT a + ``` + +* READ + > Lee de consola un string guardándolo en a + + ```python + # Ejemplo + a = READ + ``` + +* READINT + > Lee un entero de consola guardándolo en a + + ```python + # Ejemplo + a = READINT + ``` + +* RETURN + > Indica que la función retorna a + + ```python + # Ejemplo + RETURN a + ``` + +* SETATTR + > Asigna a al atributo c del objeto b + + ```python + # Ejemplo + SETATTR b c a + ``` + +* SETINDEX + > Asigna el objeto c al índice b del arreglo a + + ```python + # Ejemplo + SETINDEX a b c + ``` + +* SUBSTRING + > Devuelve la subcadena de de b a partir del índice c de tamaño length en a + + ```python + # Ejemplo + a = SUBSTRING b c length + ``` + + En caso de ser inválida la operación el programa se detiene + +* TYPEOF + >Devuelve el tipo dinámico de b en a + + ```python + # Ejemplo + a = TYPEOF b + ``` + +* VCALL + > Devuelve en a el resultado de llamar el método c en el tipo b + + ```python + # Ejemplo + a = VCALL b c + ``` + +* VOID + >Devuelve null en a + + ```python + # Ejemplo + a = VOID + ``` + + >Para indicar que una variable no tiene un valor. + +### Operadores + +* **\+** + >Suma de dos variables + + ```python + # Ejemplo + a = b + c + ``` + +* **\-** + >Resta de dos variables + + ```python + # Ejemplo + a = b - c + ``` + +* **\*** + >Multiplicación de dos variables + + ```python + # Ejemplo + a = b * c + ``` + +* **/** + >División de dos variables + + ```python + # Ejemplo + a = b / c + ``` + +* **<** + >En a si b es menor que c + + ```python + # Ejemplo + a = b < c + ``` + +* **\>** + >En a si b es mayor que c + + ```python + # Ejemplo + a = b > c + ``` + +### Asignaciones + +* **=** + >Asignación de un variable a otra variable + + ```python + # Ejemplo + a = b + ``` + +### Funciones + +* function + >Definición de una función + + ```python + # Ejemplo + function main + { + PARAM self + LOCAL local_internal_0 + local_internal_0 = READINT + PRINT local_internal_0 + local_internal_0 = local_internal_0 + 1 + RETURN local_internal_0 + } + ``` + + >Para definir una función se utiliza la palabra reservada function y se le asigna un nombre. + > + >Seguido se define una lista de parámetros y una lista de variables locales. + > + >Finalmente se define el cuerpo de la función. diff --git a/doc/Manual de CIL.pdf b/doc/Manual de CIL.pdf new file mode 100644 index 000000000..7c231b9b2 Binary files /dev/null and b/doc/Manual de CIL.pdf differ diff --git a/doc/Readme.md b/doc/Readme.md index 3b2569f5c..fbf5265ca 100644 --- a/doc/Readme.md +++ b/doc/Readme.md @@ -1,33 +1,33 @@ -# Documentación - -## Readme - -Modifique el contenido de este documento para documentar de forma clara y concisa los siguientes aspectos: - -- Cómo ejecutar (y compilar si es necesario) su compilador. -- Requisitos adicionales, dependencias, configuración, etc. -- Opciones adicionales que tenga su compilador. - -## Sobre los Equipos de Desarrollo - -Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. El proyecto de Compilación será recogido y evaluado únicamente a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. - -**⚠️ NOTA**: Debe completar el archivo `team.yml` con los datos correctos de cada miembro de su equipo. - -## Sobre los Materiales a Entregar - -Para la evaluación del proyecto Ud. debe entregar un informe en formato PDF (`report.pdf`) en esta carpeta, que resuma de manera organizada y comprensible la arquitectura e implementación de su compilador. -El documento no tiene límite de extensión. -En él explicará en más detalle su solución a los problemas que, durante la implementación de cada una de las fases del proceso de compilación, hayan requerido de Ud. especial atención. - -## Estructura del reporte - -Usted es libre de estructurar su reporte escrito como más conveniente le parezca. A continuación le sugerimos algunas secciones que no deberían faltar, aunque puede mezclar, renombrar y organizarlas de la manera que mejor le parezca: - -- **Uso del compilador**: detalles sobre las opciones de líneas de comando, si tiene opciones adicionales (e.j., `--ast` genera un AST en JSON, etc.). Básicamente lo mismo que pondrá en este Readme. -- **Arquitectura del compilador**: una explicación general de la arquitectura, en cuántos módulos se divide el proyecto, cuantas fases tiene, qué tipo de gramática se utiliza, y en general, como se organiza el proyecto. Una buena imagen siempre ayuda. -- **Problemas técnicos**: detalles sobre cualquier problema teórico o técnico interesante que haya necesitado resolver de forma particular. - -## Sobre la Fecha de Entrega - -Se realizarán recogidas parciales del proyecto a lo largo del curso. En el Canal de Telegram se anunciará la fecha y requisitos de cada entrega. +# Documentación + +## Readme + +Modifique el contenido de este documento para documentar de forma clara y concisa los siguientes aspectos: + +- Cómo ejecutar (y compilar si es necesario) su compilador. +- Requisitos adicionales, dependencias, configuración, etc. +- Opciones adicionales que tenga su compilador. + +## Sobre los Equipos de Desarrollo + +Para desarrollar el compilador del lenguaje COOL se trabajará en equipos de 2 o 3 integrantes. El proyecto de Compilación será recogido y evaluado únicamente a través de Github. Es imprescindible tener una cuenta de Github para cada participante, y que su proyecto esté correctamente hosteado en esta plataforma. + +**⚠️ NOTA**: Debe completar el archivo `team.yml` con los datos correctos de cada miembro de su equipo. + +## Sobre los Materiales a Entregar + +Para la evaluación del proyecto Ud. debe entregar un informe en formato PDF (`report.pdf`) en esta carpeta, que resuma de manera organizada y comprensible la arquitectura e implementación de su compilador. +El documento no tiene límite de extensión. +En él explicará en más detalle su solución a los problemas que, durante la implementación de cada una de las fases del proceso de compilación, hayan requerido de Ud. especial atención. + +## Estructura del reporte + +Usted es libre de estructurar su reporte escrito como más conveniente le parezca. A continuación le sugerimos algunas secciones que no deberían faltar, aunque puede mezclar, renombrar y organizarlas de la manera que mejor le parezca: + +- **Uso del compilador**: detalles sobre las opciones de líneas de comando, si tiene opciones adicionales (e.j., `--ast` genera un AST en JSON, etc.). Básicamente lo mismo que pondrá en este Readme. +- **Arquitectura del compilador**: una explicación general de la arquitectura, en cuántos módulos se divide el proyecto, cuantas fases tiene, qué tipo de gramática se utiliza, y en general, como se organiza el proyecto. Una buena imagen siempre ayuda. +- **Problemas técnicos**: detalles sobre cualquier problema teórico o técnico interesante que haya necesitado resolver de forma particular. + +## Sobre la Fecha de Entrega + +Se realizarán recogidas parciales del proyecto a lo largo del curso. En el Canal de Telegram se anunciará la fecha y requisitos de cada entrega. diff --git a/doc/images/herencia.png b/doc/images/herencia.png new file mode 100644 index 000000000..90c42633c Binary files /dev/null and b/doc/images/herencia.png differ diff --git a/doc/images/pipeline.png b/doc/images/pipeline.png new file mode 100644 index 000000000..a648597a9 Binary files /dev/null and b/doc/images/pipeline.png differ diff --git a/doc/images/stack.jpg b/doc/images/stack.jpg new file mode 100644 index 000000000..8b640fcbb Binary files /dev/null and b/doc/images/stack.jpg differ diff --git a/doc/report.md b/doc/report.md new file mode 100644 index 000000000..d59b54c7e --- /dev/null +++ b/doc/report.md @@ -0,0 +1,265 @@ +# Informe + +El objetivo principal de la aplicación es contruir un compilador que convierta un programa de COOL en un programa funcionalmente equivalente en MIPS. Se mostrará su uso y se describirá la arquitectura y procesos relacionados con su contrucción y funcionamiento. + +## ¿Cómo Instalarlo? + +### Clonar el repositorio + +``` bash +git clone https://github.com/WataLuisoDalmauCompiler/cool-compiler-2021.git +cd cool-compiler-2021 +``` + +### Instalar requerimientos + +``` bash +pip install -r requirements.txt +``` + +## ¿Cómo usar el compilador? + +### Uso básico + +Para el uso del compilador es necesario correr el archivo `src/coolc.sh`. Este compilará el programa COOL que se le dió como entrada y guardará el programa MIPS en la misma localización con extensión _.mips_. + +``` bash + ./src/coolc.sh +``` + +### Uso avanzado + +El compilador hecho presenta otras funcionalidades a las cuales se puede acceder si se llama al programa +`src/cool_cmp/main.py` mediante diferentes flags que se le pasan como argumentos: + +- `-m`: Guarda el programa compilado a MIPS en el archivo de salida dado con extensión `.mips` +- `-c`: Guarda el programa generado de CIL en el archivo de salida dado con extensión `.cil` +- `-i`: Guarda el progama de COOL con los AutoType resueltos en el archivo de salida dado con extensión `.infer.cil` +- `-icil`: Interpreta el AST de CIL generado por el programa de entrada +- `-icool`: Interpreta el AST de Cool generado por el programa de entrada + +Por ejemplo el siguiente programa interpreta y guarda el código CIL generado +> $python3 src/cool_cmp/main.py src/testing.cl src/testing.cil -icil -c + +También posee otras funcionalidades previstas para el desarrollador del compilador: + +- `-ucp`: Actualiza el parser serializado de Cool +- `-ucl`: Actualiza el lexer serializado de Cool + +### Uso para el desarrollador + +Para probar un programa específico de COOL, se dejó una configuración por defecto para debuguear en el Visual Studio Code. Esta tiene como entrada el archivo testing.cl. + +Para probar el código generado por el compilador debe escribir la entrada en el archivo input.txt, la salida esperada en el archivo expected\_output.txt y ejecutar el siguiente comando: + +``` bash +./src/test_mips.sh +``` + +## Arquitectura + +### Estructura + +El compilador se divide en varios módulos entre los más destacados están: + +- cmp: + - Clases bases de la API de Gramática + - Implementación del patrón visitor + - Clases bases para herramientas de análisis semántico + - Nodos bases de AST de Cool y CIL +- cmp_tools: + - Implementación de lexer + - Implementación de parsers +- cool: + - Gramática, parser, lexer, AST de Cool + - Implementación de los visitors del compilador. +- cil: + - AST y visitors de CIL +- mips: + - AST y visitors de MIPS +- pipes: + - Contiene la definición de los Pipe y Pipeline usados para modelar el flujo del compilador + - Contiene los pipelines del compilador necesarios para realizar las distintas tareas realizables por este + +### Flujo de trabajo + +La dinámica de flujo de trabajo del compilador se ve representada por Pipe y Pipeline, las cuales permiten una gran flexibilidad y desacomplamiento a la hora de agregar pasos a un proceso. Un Pipe es la representación de una tarea en concreto, mientras que un Pipeline es la agrupación de varias tareas realizadas una tras otra, que también es posible verla como una sola. El estado de la tarea es mantenido en un diccionario que es pasado de tarea en tarea como argumento para así poder usar los resultados obtenidos en otros pasos previos. + +![images/pipeline.png](images/pipeline.png) + +Gracias a esto es posible crear y tener diferentes flujos de trabajo para usarlos fácilmente. Por ejemplo en el proyecto se tienen varios flujos de trabajo listos para su uso: + +- `generate_cil_pipeline`: Genera el código CIL correspondiente al programa COOL que se dió de entrada. +- `generate_cool_pipeline`: Reconstruye el programa COOL de entrada con los tipos inferidos sustituidos +- `interprete_cool_pipeline`: Interpreta el programa COOL en Python. +- `generate_mips_pipeline`: Genera el código MIPS de un programa de COOL. + +### Errores + +Detectar y mostrar los errores son un paso crucial en cualquier aplicación que permite al usuario ahorrar mucho tiempo al proveerle una descripción lo más precisa posible de este. El estado principal de la aplicación posee una lista, la cuál contiene todos los errores incurridos por etapas anteriores. Al final de la ejecución los errores son escritos en la salida estándar del programa. + +En la implementación de los flujos, generalmente se ignora realizar una fase si existe algún error previo, por esto se asume en las explicaciones que siempre se llega a ellas sin errores previos. + +### Fases + +El compilador se divide en dos fases principales: + +- Fase de análisis: Empieza leyendo el código fuente (COOL) y termina en la construcción de un AST que represente el código de entrada, verificando la correctitud de este . +- Fase de síntesis: Empieza recibiendo el AST de COOL , creando otro de código intermedio CIL y termina con la generación de código MIPS. + +### Fase de análisis + +En la fase de análisis se contemplan las siguientes etapas: + +1. Lectura del programa +2. Tokenización del programa +3. Análisis sintáctico +4. Análisis semántico +5. Acción correspondiente a la entrada (Interpretar COOL, continuar hacia la siguiente fase) + +#### Tokenización + +Este proceso es el encargado de convertir el texto plano de un programa de COOL en una lista de tokens para poder trabajar con ellas en próximas etapas. + +Siguiendo el flujo de trabajo propuesto, esta etapa se realiza usando el pipe `lexer_pipeline` en la cual se lee el texto y se tokeniza usando el módulo `ply` y se añade la lista de tokens resultante al flujo. + +En este paso también se ignoran los comentarios en la salida de los tokens ya que estos no son necesarios para los análisis sintáctico y semántico. Un problema que se pudo apreciar en esta etapa es que los comentarios anidados no pueden ser eliminados con expresiones regulares ya que estas fallan al identificar este tipo de estructuras, para resolver este problema se utilizó un algoritmo basado en paréntesis balanceados en el que solamente los tokens comprendidos con profundidad 0 pasan a la lista final. + +#### Análisis sintáctico + +Este proceso es el encargado de convertir los tokens del programa en un árbol de sintaxis abstracta, en caso de que estos coincidan con la gramática del lenguaje. + +El pipeline encargado de esta etapa es `syntax_pipeline` el cual evalúa el parser con los tokens dados y añade al flujo la derivación de extrema derecha de los tokens que luego será evaluada y convertida en un AST por la gramátca atributada. + +##### Gramática + +La gramática propuesta para COOL se encuentra en `cool/grammar/cool_grammar.py`. Esta es una gramática atributada la cual al ser evaluada devuelve el AST correspondiente al programa de entrada de COOL. + +##### Parser + +El parser es contruido en base a la gramática previamente definida el cual consiste en un parser LALR1. Debido a que su construcción dinámica incurre en un consumo de tiempo relativamente alto, este se encuentra serializado para un mejor rendimiento del inicio del programa. + +#### Análisis semántico + +Este proceso es el encargado de verificar la correcta semántica del programa de COOL. Se aplica fuertemente el patrón visitor, pasando por diferentes etapas las cuales van construyendo diferentes estructuras y analizando el contenido del AST para verificar su correctitud. + +El pipeline encargado de esta etapa es `semantic_pipeline`. + +##### Construcción del Contexto + +El contexto de un programa de COOL se puede definir como una colección de los tipos que están definidos en el programa. Estos tipos tiene otras informaciones como son los atributos, métodos y padre. La construcción del contexto pasa por tres etapas: + +1. Construcción del contexto inicial (Contexto que posee la información de las clases básicas Ej: Object, Int). + + - Para la construcción del contexto inicial se creó un esqueleto conteniendo las definiciones de las clases bases con sus respectivos métodos (ver `cool/lib/std.cl`). Este esqueleto es analizado por la infraestructura existente y devuelve el contexto inicial. Se prefirió esta aproximación ya que permite obtener el contexto de forma natural sin tener que recurrir a tenerlo fijado dentro del código. + +2. Recolección de tipos y construcción del árbol de dependencias. + - La recolección de tipos constituye el paso en el que se agregan los tipos definidos al contexto del programa. En esta etapa se comprueba que no existan ciclos en la relación padre entre los tipos. + +3. Construcción de tipos. + - Finalmente se agrega la información restante a los tipos como son los métodos y atributos que los conforman. + +##### Comprobación de tipos y construcción del ámbito + +Una vez se tiene el contexto contruido es necesario verificar las demás reglas semánticas de COOL. + +En esta etapa: + +- Se anotan los nodos que contienen tipos con las expresiones correspondientes. +- Se construye el ámbito (Scope) del programa. +- Se comprueban las reglas semánticas de COOL. + +Para realizar el chequeo de tipos de un programa de COOL es necesario conocer el tipo estático de las expresiones, esto se realiza con un recorrido del AST de COOL en post-orden anotando el tipo de las expresiones de manera bottom-up para comprobar la correctitud de las operaciones entre estas. En el mismo recorrido se va construyendo el Scope que verifica la correctitud en el uso de variables. También se verifican las demás reglas semánticas como por ejemplo las relacionadas con la sobreescritura de métodos. + +##### Inferencia de tipos + +El proyecto soporta inferencia de tipos mediante la anotación del tipo con el nombre especial de AUTO\_TYPE. + +El algoritmo propuesto para la inferencia de los tipos AUTO\_TYPE se basa en la idea de ir descartando los tipos que no pueden ser, basándose en las operaciones realizadas sobre los AUTO\_TYPE y las operaciones válidas sobre los posibles tipos. Estas operaciones pueden ser asignación, operaciones aritméticas y despachado de métodos. Luego que se tiene toda la información necesaria, se comprueba que no haya incoherencias en los posibles tipos resultantes (Ej: métodos con igual nombre y parámetros en clases no relacionadas) y se sustituye en los nodos del AST, el AUTO\_TYPE, por el tipo más adecuado según su posición (Ej: por los argumentos el más abstracto o por el tipo de retorno, el más concreto). + +La primera parte del algoritmo consiste en reunir toda la información sobre las operaciones que actúan sobre los AUTO\_TYPE, esto se hace de manera automática y natural en el chequeo de tipos mediante la llamada a los métodos _conforms\_to_, _get\_attribute_ y _get\_method_ de la clase AutoType y _operation\_defined_ de Operator. Estos métodos son llamados en el recorrido TypeChecker para comprobar que las operaciones a realizar sobre los tipos cumplen las reglas semánticas. El algoritmo se aprovecha de esto y elimina en esta etapa los tipos que no satisfacen las operaciones (Vea semantic.type.AutoType y semantic.operations.Operator.operation_defined). + +La segunda parte consiste en verificar la validez de los posibles tipos. Definimos a un AUTO\_TYPE como válido si el grafo de sus posibles tipos (tomando la relación A padre de B) es unilateralmente conexo y no vacío. Esta definición se debe a que en caso de no ser unilateralmente conexo, significaría que habría dos subherencias disjuntas que podrían ocupar el lugar del AUTO\_TYPE y en este caso no se podría decidir entre una de estas. Por otra parte en el caso de ser vacío significaría que no hay posibles tipos que satisfagan las operaciones realizadas sobre el AUTO\_TYPE. Una vez comprobada la validez del AUTO\_TYPE se pone a los nodos el tipo correspondiente a su posición ya sea el más abstracto o concreto. Esta segunda parte se realiza en el recorrido AutoResolver. + +Ejemplos de caso válido (Izquierda) y no válido (Derecha): + +![images/herencia.png](images/herencia.png) + +#### Fin del análisis semántico + +Al final del análisis semántico se sabe que el programa es correcto o no y se tiene un AST de este listo para ser procesado según haga falta. + +##### Interpretar COOL + +Este árbol es posible interpretarlo y para esto se creó el visitor RunVisitor que ejecuta los nodos sobre Python. Esto es útil a la hora de verificar la correctitud del código sin tener que compilarlo y aumentar las probabilidades de que el error no se produzca en una etapa posterior. + +### Fase de síntesis + +En esta fase: + +- Se construye un AST de CIL dado el AST de COOL anterior +- Se genera un AST de MIPS dado el AST de CIL construido. +- Se escribe el programa representado en el AST de MIPS en el archivo deseado. + +#### AST COOL a AST CIL + +Esta conversión se realiza mediante una visita al AST de COOL con el COOLToCILVisitor. El objetivo principal de esta parte es desenrollar las expresiones anidadas e implementar algunos funcionalidades de COOL en este nivel sin tener que hacerlo en MIPS disminuyendo la carga de trabajo en la parte de generación. + +Para una mejor explicación sobre el lenguaje CIL referirse a `Manual de CIL.md`. + +En esta fase: + +- Se recopilan todos los string literales en la aplicación en la sección de datos +- Se crean las funciones estáticas para cada método en CIL + +Entre los problemas principales resueltos en CIL se encuentran: + +- Inicialización de Tipos + - Para cada atributo se genera una función de inicialización + - Para cada tipo se genera una función de inicialización +- Lógica del case of + - Se generan las instrucciones necesarias esta instrucción +- Despachado de objetos por valor + - Se despacha en dependencia del tipo anotado en el nodo. Si es un tipo por valor se despacha estáticamente en otro caso dinámicamente. + +#### AST CIL a AST MIPS + +Esta conversión se realiza mediante una visita al AST de CIL con el CILToMIPSVisitor. En esta visita se genera un AST MIPS que representa un programa equivalente al de CIL. + +Para representar un programa de CIL en MIPS se tuvieron ciertos convenios a la hora del uso de la pila para pasar argumentos a las funciones, sobre dónde se guardarán los valores de las variables locales necesarias para que el código se ejecute correctamente y la representación de tipos y de objetos en memoria. + +- Convenio de llamado de funciones + - Los argumentos de las funciones se añaden en el orden de definición + - Las variables locales se guardan luego de los parámetros + - Se actualiza el frame pointer con el valor actual del stack pointer + - Se salvan los registros viejos de frame pointer y de return address + - Al final de la función se restauran los valores de frame pointer y de return address y se quitan de la pila los argumentos y variables locales + +![images/stack.jpg](images/stack.jpg) + +- Representación de tipos + - Se representan en el siguiente orden: Dirección del padre, Tamaño de instancia del objeto, Dirección al nombre del objeto, Direcciones a los métodos correspondientes. + - Ejemplo: + +```asm +# Representación de Object MIPS +Object: .word 0, 4, data_0, __init_Object_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object +``` + +- Representación de objetos + - Por referencia: + - Se crea un espacio de memoria en el heap del tamaño deseado + - Se guarda primero el tipo al que pertenece y el espacio restante corresponde a los atributos por orden de definición + - Ej: \[Obj, attr1, attr2, ...\] + - Por valor: + - El valor es el mismo representado + +En este nivel se efectuaron las implementaciones de las funciones básicas provistas por Cool, estas funciones son abort, copy, type_name, las operaciones de IO y las operaciones con String. + +### Manejo de String + +En el caso de los String estos se trataron como una mezcla de referencia y valor, al ser el String un objeto por referencia y su valor no cabe en un solo word estos se representan en memoria como una tupla de Dirección de tipo, Dirección a String. Al realizar cualquier operación sobre una cadena el resultado devuelve una nueva cadena dejando la anterior sin cambios. Esto facilita en gran medida el trabajo con estas, aunque no hace un manejo eficiente de los recursos. + +### Despachado dinámico + +Gracias a que la representación de los objetos en memoria tienen el tipo al que pertenecen y los tipos poseen la dirección a los métodos que implementan se tiene toda la información necesaria para el despachado dinámico. diff --git a/doc/report.pdf b/doc/report.pdf new file mode 100644 index 000000000..6cb0a4ef9 Binary files /dev/null and b/doc/report.pdf differ diff --git a/doc/team.yml b/doc/team.yml index c16162532..b16415109 100644 --- a/doc/team.yml +++ b/doc/team.yml @@ -1,10 +1,10 @@ -members: - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX - - name: Nombre Apellido1 Apellido2 - github: github_id - group: CXXX +members: + - name: Damián O´Hallorans Toledo + github: NazDia + group: C412 + - name: Luis Ernesto Ibarra Vázquez + github: luisoibarra + group: C411 + - name: Luis Enrique Dalmau Coopat + github: LukeDalmau + group: C411 diff --git a/makefile b/makefile new file mode 100644 index 000000000..cd83fb352 --- /dev/null +++ b/makefile @@ -0,0 +1,12 @@ +.PHONY: clean + +main: + # Compiling the compiler :) + +clean: + rm -rf build/* + rm -rf ../tests/*/*.mips + +test: + pytest ../tests -v --tb=short -m=${TAG} + diff --git a/requirements.txt b/requirements.txt index 9eb0cad1a..62bc6037a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,6 @@ -pytest -pytest-ordering +ipython==8.0.1 +nbformat==5.0.4 +plac==1.1.3 +ply==3.11 +pydot==1.4.1 +pytest==7.0.1 diff --git a/src/Readme.md b/src/Readme.md index 1200371b5..cdca282ec 100644 --- a/src/Readme.md +++ b/src/Readme.md @@ -1,78 +1,78 @@ -# COOL: Proyecto de Compilación - -La evaluación de la asignatura Complementos de Compilación, inscrita en el programa del 4to año de la Licenciatura en Ciencia de la Computación de la Facultad de Matemática y Computación de la -Universidad de La Habana, consiste este curso en la implementación de un compilador completamente -funcional para el lenguaje _COOL_. - -_COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. - -### Sobre el Lenguaje COOL - -Ud. podrá encontrar la especificación formal del lenguaje COOL en el documento _"COOL Language Reference Manual"_, que se distribuye junto con el presente texto. - -## Código Fuente - -### Compilando su proyecto - -Si es necesario compilar su proyecto, incluya todas las instrucciones necesarias en un archivo [`/src/makefile`](/src/makefile). -Durante la evaluación su proyecto se compilará ejecutando la siguiente secuencia: - -```bash -$ cd source -$ make clean -$ make -``` - -### Ejecutando su proyecto - -Incluya en un archivo [`/src/coolc.sh`](/src/coolc.sh) todas las instrucciones que hacen falta para lanzar su compilador. Recibirá como entrada un archivo con extensión `.cl` y debe generar como salida un archivo `.mips` cuyo nombre será el mismo que la entrada. - -Para lanzar el compilador, se ejecutará la siguiente instrucción: - -```bash -$ cd source -$ ./coolc.sh -``` - -### Sobre el Compilador de COOL - -El compilador de COOL se ejecutará como se ha definido anteriormente. -En caso de que no ocurran errores durante la operación del compilador, **coolc.sh** deberá terminar con código de salida 0, generar (o sobrescribir si ya existe) en la misma carpeta del archivo **.cl** procesado, y con el mismo nombre que éste, un archivo con extension **.mips** que pueda ser ejecutado con **spim**. Además, reportar a la salida estándar solamente lo siguiente: - - - - -En caso de que ocurran errores durante la operación del compilador, **coolc.sh** deberá terminar con código -de salida (exit code) 1 y reportar a la salida estándar (standard output stream) lo que sigue... - - - - _1 - ... - _n - -... donde `_i` tiene el siguiente formato: - - (,) - : - -Los campos `` y `` indican la ubicación del error en el fichero **.cl** procesado. En caso -de que la naturaleza del error sea tal que no pueda asociárselo a una línea y columna en el archivo de -código fuente, el valor de dichos campos debe ser 0. - -El campo `` será alguno entre: - -- `CompilerError`: se reporta al detectar alguna anomalía con la entrada del compilador. Por ejemplo, si el fichero a compilar no existe. -- `LexicographicError`: errores detectados por el lexer. -- `SyntacticError`: errores detectados por el parser. -- `NameError`: se reporta al referenciar un `identificador` en un ámbito en el que no es visible. -- `TypeError`: se reporta al detectar un problema de tipos. Incluye: - - incompatibilidad de tipos entre `rvalue` y `lvalue`, - - operación no definida entre objetos de ciertos tipos, y - - tipo referenciado pero no definido. -- `AttributeError`: se reporta cuando un atributo o método se referencia pero no está definido. -- `SemanticError`: cualquier otro error semántico. - -### Sobre la Implementación del Compilador de COOL - -El compilador debe estar implementado en `python`. Usted debe utilizar una herramienta generadora de analizadores -lexicográficos y sintácticos. Puede utilizar la que sea de su preferencia. +# COOL: Proyecto de Compilación + +La evaluación de la asignatura Complementos de Compilación, inscrita en el programa del 4to año de la Licenciatura en Ciencia de la Computación de la Facultad de Matemática y Computación de la +Universidad de La Habana, consiste este curso en la implementación de un compilador completamente +funcional para el lenguaje _COOL_. + +_COOL (Classroom Object-Oriented Language)_ es un pequeño lenguaje que puede ser implementado con un esfuerzo razonable en un semestre del curso. Aun así, _COOL_ mantiene muchas de las características de los lenguajes de programación modernos, incluyendo orientación a objetos, tipado estático y manejo automático de memoria. + +### Sobre el Lenguaje COOL + +Ud. podrá encontrar la especificación formal del lenguaje COOL en el documento _"COOL Language Reference Manual"_, que se distribuye junto con el presente texto. + +## Código Fuente + +### Compilando su proyecto + +Si es necesario compilar su proyecto, incluya todas las instrucciones necesarias en un archivo [`/src/makefile`](/src/makefile). +Durante la evaluación su proyecto se compilará ejecutando la siguiente secuencia: + +```bash +$ cd source +$ make clean +$ make +``` + +### Ejecutando su proyecto + +Incluya en un archivo [`/src/coolc.sh`](/src/coolc.sh) todas las instrucciones que hacen falta para lanzar su compilador. Recibirá como entrada un archivo con extensión `.cl` y debe generar como salida un archivo `.mips` cuyo nombre será el mismo que la entrada. + +Para lanzar el compilador, se ejecutará la siguiente instrucción: + +```bash +$ cd source +$ ./coolc.sh +``` + +### Sobre el Compilador de COOL + +El compilador de COOL se ejecutará como se ha definido anteriormente. +En caso de que no ocurran errores durante la operación del compilador, **coolc.sh** deberá terminar con código de salida 0, generar (o sobrescribir si ya existe) en la misma carpeta del archivo **.cl** procesado, y con el mismo nombre que éste, un archivo con extension **.mips** que pueda ser ejecutado con **spim**. Además, reportar a la salida estándar solamente lo siguiente: + + + + +En caso de que ocurran errores durante la operación del compilador, **coolc.sh** deberá terminar con código +de salida (exit code) 1 y reportar a la salida estándar (standard output stream) lo que sigue... + + + + _1 + ... + _n + +... donde `_i` tiene el siguiente formato: + + (,) - : + +Los campos `` y `` indican la ubicación del error en el fichero **.cl** procesado. En caso +de que la naturaleza del error sea tal que no pueda asociárselo a una línea y columna en el archivo de +código fuente, el valor de dichos campos debe ser 0. + +El campo `` será alguno entre: + +- `CompilerError`: se reporta al detectar alguna anomalía con la entrada del compilador. Por ejemplo, si el fichero a compilar no existe. +- `LexicographicError`: errores detectados por el lexer. +- `SyntacticError`: errores detectados por el parser. +- `NameError`: se reporta al referenciar un `identificador` en un ámbito en el que no es visible. +- `TypeError`: se reporta al detectar un problema de tipos. Incluye: + - incompatibilidad de tipos entre `rvalue` y `lvalue`, + - operación no definida entre objetos de ciertos tipos, y + - tipo referenciado pero no definido. +- `AttributeError`: se reporta cuando un atributo o método se referencia pero no está definido. +- `SemanticError`: cualquier otro error semántico. + +### Sobre la Implementación del Compilador de COOL + +El compilador debe estar implementado en `python`. Usted debe utilizar una herramienta generadora de analizadores +lexicográficos y sintácticos. Puede utilizar la que sea de su preferencia. diff --git a/src/cool_cmp/__init__.py b/src/cool_cmp/__init__.py new file mode 100644 index 000000000..912fcd4be --- /dev/null +++ b/src/cool_cmp/__init__.py @@ -0,0 +1,5 @@ +import sys +import os +base_dir = os.path.dirname(__file__) +# sys.path.append(os.path.join(base_dir, "..")) +sys.path.append(base_dir) \ No newline at end of file diff --git a/src/cool_cmp/cil/__init__.py b/src/cool_cmp/cil/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cil/ast/cil_ast.py b/src/cool_cmp/cil/ast/cil_ast.py new file mode 100644 index 000000000..1859625c2 --- /dev/null +++ b/src/cool_cmp/cil/ast/cil_ast.py @@ -0,0 +1,122 @@ +from cmp.cil import * + +################################################################################ +# META INSTRUCTIONS + +class IntAbortNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class IntTypeNameNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class BoolAbortNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class BoolTypeNameNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + + +class ObjectAbortNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class ObjectCopyNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class ObjectTypeNameNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class StringLengthNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class StringConcatNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class StringSubstringNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class IOOutStringNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class IOOutIntNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class IOInStringNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class IOInIntNode(InstructionNode): + def __init__(self,row,column,comment=None): + super().__init__(row,column,comment) + +class InitInstance(InstructionNode): + def __init__(self, source, instance_type, row, column, comment=None)-> None: + super().__init__(row, column, comment) + self.source = source + self.instance_type = instance_type + + +################################################################################ + + +################################################################################ +# OTHER INSTRUCTIONS + +class GetFatherNode(InstructionNode): + def __init__(self, dest, variable,row, column, comment=None)-> None: + super().__init__(row, column, comment) + self.dest = dest + self.variable = variable + + +class VoidNode(InstructionNode): + def __init__(self, dest, row, column, comment=None)-> None: + super().__init__(row, column, comment) + self.dest = dest + +################################################################################ + + +################################################################################ +# ARITHMETIC INSTRUCTIONS + +class UnaryArithmeticNode(InstructionNode): + def __init__(self, dest, value, row, column, comment=None)-> None: + super().__init__(row, column, comment) + self.dest = dest + self.value = value + +class NotNode(UnaryArithmeticNode): + pass + +class EqualNode(ArithmeticNode): + pass + + +class GreaterNode(ArithmeticNode): + pass + + +class LesserNode(ArithmeticNode): + pass + +class ObjEqualNode(ArithmeticNode): + def __init__(self, dest, left, right, row=None, column=None, comment=None, value_compare=None) -> None: + super().__init__(dest, left, right, row, column, comment=comment) + if value_compare is None: + raise ValueError("value_compare must be initialized to True or False") + self.value_compare = value_compare + +################################################################################ + diff --git a/src/cool_cmp/cil/errors/errors.py b/src/cool_cmp/cil/errors/errors.py new file mode 100644 index 000000000..f046e7dbe --- /dev/null +++ b/src/cool_cmp/cil/errors/errors.py @@ -0,0 +1,11 @@ +from error.errors import RunError + +ZERO_DIVISION = "Divison by 0 not defined." + +class AbortError(RunError): + ERROR_TYPE = "AbortError" + def __init__(self, type_name): + self.typex = type_name + + def __str__(self): + return f"" diff --git a/src/cool_cmp/cil/visitors/cil_visitor.py b/src/cool_cmp/cil/visitors/cil_visitor.py new file mode 100644 index 000000000..c2d4ef12a --- /dev/null +++ b/src/cool_cmp/cil/visitors/cil_visitor.py @@ -0,0 +1,1665 @@ +import cil.ast.cil_ast as cil +from cool.ast.cool_ast import * +import cmp.visitor as visitor +from cmp.semantic import VariableInfo +from semantic.context import Context +from cil.errors.errors import RunError, ZERO_DIVISION, AbortError +from semantic.type import SelfType +from math import floor + +class CILPrintVisitor(): + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(cil.ProgramNode) + def visit(self, node): + dottypes = '\n'.join(self.visit(t) for t in node.dottypes) + dotdata = '\n'.join(self.visit(t) for t in node.dotdata) + dotcode = '\n'.join(self.visit(t) for t in node.dotcode) + + return f'.TYPES\n{dottypes}\n\n.DATA\n{dotdata}\n\n.CODE\n{dotcode}' + + @visitor.when(cil.DataNode) + def visit(self, node): + return f"{node.name} = {node.value}" + + @visitor.when(cil.TypeNode) + def visit(self, node): + attributes = '\n\t'.join(f'attribute {x}' for x in node.attributes) + methods = '\n\t'.join(f'method {x}: {y}' for x,y in node.methods) + + return f'type {node.name} {{\n\tparent: {node.parent}\n\t{attributes}\n\n\t{methods}\n}}' + + @visitor.when(cil.FunctionNode) + def visit(self, node): + params = '\n\t'.join(self.visit(x) for x in node.params) + localvars = '\n\t'.join(self.visit(x) for x in node.localvars) + instructions = '\n\t'.join(self.visit(x) for x in node.instructions) + + return f'function {node.name} {{\n\t{params}\n\n\t{localvars}\n\n\t{instructions}\n}}' + + @visitor.when(cil.ParamNode) + def visit(self, node): + return f'PARAM {node.name}' + + @visitor.when(cil.LocalNode) + def visit(self, node): + return f'LOCAL {node.name}' + + @visitor.when(cil.AssignNode) + def visit(self, node): + return f'{node.dest} = {node.source}' + + @visitor.when(cil.PlusNode) + def visit(self, node): + return f'{node.dest} = {node.left} + {node.right}' + + @visitor.when(cil.MinusNode) + def visit(self, node): + return f'{node.dest} = {node.left} - {node.right}' + + @visitor.when(cil.StarNode) + def visit(self, node): + return f'{node.dest} = {node.left} * {node.right}' + + @visitor.when(cil.DivNode) + def visit(self, node): + return f'{node.dest} = {node.left} / {node.right}' + + @visitor.when(cil.AllocateNode) + def visit(self, node): + return f'{node.dest} = ALLOCATE {node.type}' + + @visitor.when(cil.TypeOfNode) + def visit(self, node): + return f'{node.dest} = TYPEOF {node.obj}' + + @visitor.when(cil.TypeNameNode) + def visit(self, node): + return f'{node.dest} = TYPENAME {node.type}' + + @visitor.when(cil.StaticCallNode) + def visit(self, node): + return f'{node.dest} = CALL {node.function}' + + @visitor.when(cil.DynamicCallNode) + def visit(self, node): + return f'{node.dest} = VCALL {node.type} {node.method}' + + @visitor.when(cil.GetAttribNode) + def visit(self, node): + return f'{node.dest} = GETATTR {node.source} {node.attr}' + + @visitor.when(cil.SetAttribNode) + def visit(self, node:cil.SetAttribNode): + return f'SETATTR {node.source} {node.attr} {node.value}' + + @visitor.when(cil.ArgNode) + def visit(self, node): + return f'ARG {node.name}' + + @visitor.when(cil.CommentNode) + def visit(self, node): + return f'# {node.msg}' + + @visitor.when(cil.ReturnNode) + def visit(self, node): + return f'RETURN {node.value if node.value is not None else ""}' + + @visitor.when(cil.AbortNode) + def visit(self, node): + return f'ABORT' + + @visitor.when(cil.CopyNode) + def visit(self, node): + return f'{node.result} = COPY {node.instance}' + + @visitor.when(cil.LengthNode) + def visit(self, node): + return f'{node.dest} = LENGTH {node.string_var}' + + @visitor.when(cil.ConcatNode) + def visit(self, node): + return f'{node.dest} = CONCAT {node.string1} {node.string2}' + + @visitor.when(cil.SubstringNode) + def visit(self, node): + return f'{node.dest} = SUBSTRING {node.string} {node.index} {node.length}' + + @visitor.when(cil.PrintNode) + def visit(self, node): + return f'PRINT {node.str_addr}' + + @visitor.when(cil.PrintIntNode) + def visit(self, node): + return f'PRINTINT {node.int_addr}' + + @visitor.when(cil.ReadNode) + def visit(self, node): + return f'{node.dest} = READ' + + @visitor.when(cil.ReadIntNode) + def visit(self, node): + return f'{node.dest} = READINT' + + @visitor.when(cil.LoadNode) + def visit(self, node:cil.LoadNode): + return f'{node.dest} = LOAD {node.msg}' + + @visitor.when(cil.LabelNode) + def visit(self, node:cil.LabelNode): + return f'LABEL {node.label}' + + @visitor.when(cil.GotoIfNode) + def visit(self, node:cil.GotoIfNode): + return f'IF {node.condition_value} GOTO {node.label}' + + @visitor.when(cil.GotoNode) + def visit(self, node:cil.GotoNode): + return f'GOTO {node.label}' + + @visitor.when(cil.NotNode) + def visit(self, node:cil.NotNode): + return f'{node.dest} = NOT {node.value}' + + @visitor.when(cil.EqualNode) + def visit(self, node:cil.EqualNode): + return f'{node.dest} = EQUAL {node.left} {node.right}' + + @visitor.when(cil.ObjEqualNode) + def visit(self, node:cil.ObjEqualNode): + return f'{node.dest} = OBJEQUAL {node.left} {node.right}' + + @visitor.when(cil.GreaterNode) + def visit(self, node:cil.GreaterNode): + return f'{node.dest} = {node.left} > {node.right}' + + @visitor.when(cil.LesserNode) + def visit(self, node:cil.LesserNode): + return f'{node.dest} = {node.left} < {node.right}' + + @visitor.when(cil.VoidNode) + def visit(self, node:cil.VoidNode): + return f'{node.dest} = VOID' + + @visitor.when(cil.GetFatherNode) + def visit(self, node:cil.GetFatherNode): + return f'{node.dest} = FATHER {node.variable}' + + @visitor.when(cil.ArrayNode) + def visit(self, node:cil.ArrayNode): + return f'{node.dest} = ARRAY {node.type} {node.length}' + + @visitor.when(cil.SetIndexNode) + def visit(self, node:cil.SetIndexNode): + return f'SETINDEX {node.source} {node.index} {node.value}' + + @visitor.when(cil.GetIndexNode) + def visit(self, node:cil.GetIndexNode): + return f'{node.dest} = GETINDEX {node.source} {node.index}' + + @visitor.when(cil.InitInstance) + def visit(self, node:cil.InitInstance): + return "" + + +class CILRunnerVisitor(): + + def __init__(self) -> None: + self.data = {} + self.types = {} + self.function = {} + self.errors = [] + + def jump_to(self, label): + return ("jump",label) + + def return_value(self, value): + return ("return", value) + + def next_instruction(self): + return ("next", None) + + def get_type(self, typex) -> cil.TypeNode: + if isinstance(typex, cil.TypeNode): + return typex + + if isinstance(typex, dict): + return typex["__type"] + try: + if isinstance(typex, cil.TypeNode): + return typex + return self.types[typex] + except KeyError: + self.raise_error("Type {0} isn't defined", typex) + + def get_dynamic_type(self, type_name, caller_fun_scope): + if type_name[0].isupper(): # Type Name + typex = self.get_type(type_name) + else: # Type variable + typex = self.get_type(caller_fun_scope[type_name]) + return typex + + def raise_error(self, message, *args): + raise RunError(message, *args) + + def create_type_instance(self, name): + typex = self.get_type(name) + return { + "__type": typex, + "__is_type": True, + } + + def get_value(self, source, function_scope): + value = None + try: + value = int(source) + except ValueError: + if source in function_scope: + value = function_scope[source] + elif source in self.types: + value = self.create_type_instance(source) + else: + self.raise_error("Variable {0} doesn't exist", source) + return value + + def set_value(self, dest, value, function_scope): + if dest not in function_scope: + self.raise_error("Variable {0} isn't defined", dest) + function_scope[dest] = value + + def get_value_str(self, source, function_scope, error=None): + value = self.get_value(source, function_scope) + if not isinstance(value, str): + if not error: + error = f"String expected at {source}" + self.raise_error(error) + return value + + def get_value_int(self, source, function_scope, error=None): + value = self.get_value(source, function_scope) + if not isinstance(value, int): + if not error: + error = f"Int expected at {source}" + self.raise_error(error) + return value + + def binary_node(self, node, function_scope, func): + left = self.get_value(node.left, function_scope) + right = self.get_value(node.right, function_scope) + value = func(left, right) + self.set_value(node.dest, value, function_scope) + return self.next_instruction() + + def string_cleaner(self, string): + semi = string[1:-1] + temp = [] + escape = False + for ch in semi: + if ch == '\\' and not escape: + escape = True + elif ch == 'n' and escape: + temp.append('\n') + escape = False + elif ch == 't' and escape: + temp.append('\t') + escape = False + elif ch == 'b' and escape: + temp.append('\b') + escape = False + elif ch == 'f' and escape: + temp.append('\f') + escape = False + elif escape: + temp.append(ch) + escape = False + else: + temp.append(ch) + + return ''.join(temp) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(cil.ProgramNode) + def visit(self, node:cil.ProgramNode): + for t in node.dottypes + [cil.TypeNode("__Array", None, "__Array", row = -1, column=-1, comment="Array type generated in for running")]: + self.visit(t) + for t in node.dotdata: + self.visit(t) + for t in node.dotcode: + self.visit(t) + try: + result = self.visit(cil.StaticCallNode("main", "result", row=-1, column=-1), [], {"result":None}) + return result + except RunError as er: + # er.text = er.text[10:] + self.errors.append(er) + return None + + @visitor.when(cil.DataNode) + def visit(self, node:cil.DataNode): + if node.name in self.data: + self.raise_error("Data {0} already defined") + self.data[node.name] = self.string_cleaner(node.value) + + @visitor.when(cil.TypeNode) + def visit(self, node:cil.TypeNode): + if node.name in self.types: + self.raise_error("Type {0} already defined", node.name) + self.types[node.name] = node + + @visitor.when(cil.TypeNameNode) + def visit(self, node:cil.TypeNameNode, args: list, caller_fun_scope: dict): + typex = self.get_dynamic_type(node.type, caller_fun_scope) + if typex.name_data not in self.data: + self.raise_error(f"Data {typex.name_data} not defined") + value = self.data[typex.name_data] + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.FunctionNode) + def visit(self, node): + self.function[node.name] = node + + @visitor.when(cil.StaticCallNode) + def visit(self, node:cil.StaticCallNode, args: list, caller_fun_scope: dict): + try: + func_node = self.function[node.function] + except KeyError: + self.raise_error("Function {0} doesn't exist", node.function) + + fun_scope = {} + label_dict = {} + current_args = [] + if len(args) != len(func_node.params): + self.raise_error("Argument amount {0} doesn't match with params amount {1} at {2}", len(args), len(func_node.params), node.function) + + for p in func_node.params: + self.visit(p, args, fun_scope) + + for i,label_node in [(i,x) for i,x in enumerate(func_node.instructions) if isinstance(x, cil.LabelNode)]: + if label_node.label in label_dict: + self.raise_error("Repeated label {0} at {1}", label_node.name, node.function) + label_dict[label_node.label] = i + + for local in func_node.localvars: + self.visit(local, current_args, fun_scope) + + i = 0 + while i < len(func_node.instructions): + instr = func_node.instructions[i] + action,action_info = self.visit(instr, current_args, fun_scope) + i+=1 + if action == "jump": + try: + i = label_dict[action_info] + except KeyError: + self.raise_error("Missing label {0} at function {1}", action_info, node.function) + if action == "return": + if isinstance(instr, cil.ReturnNode): + self.set_value(node.dest, action_info, caller_fun_scope) + return self.return_value(action_info) + else: # A Function call + self.set_value(instr.dest, action_info, fun_scope) + self.raise_error("Missing return at {0}", node.function) + + @visitor.when(cil.DynamicCallNode) + def visit(self, node, args: list, caller_fun_scope: dict): + # typex = args[0]['__type'] + typex = self.get_dynamic_type(node.type, caller_fun_scope) + try: + func_name = next(static_name for name, static_name in typex.methods if name == node.method) + except StopIteration: + self.raise_error("Type {0} doesn't contains method {1}", node.type, node.method) + return self.visit(cil.StaticCallNode(func_name, node.dest, row=node.row, column=node.column, comment=node.comment), args, caller_fun_scope) + + @visitor.when(cil.ParamNode) + def visit(self, node:cil.ParamNode, args: list, caller_fun_scope: dict): + if node.name in caller_fun_scope: + self.raise_error("Parameter {0} already defined", node.name) + value = args.pop(0) # Removes argument from caller's list + caller_fun_scope[node.name] = value + return self.next_instruction() + + @visitor.when(cil.LocalNode) + def visit(self, node:cil.LocalNode, args: list, caller_fun_scope: dict): + if node.name in caller_fun_scope: + self.raise_error("Variable {0} already defined", node.name) + caller_fun_scope[node.name] = None + return self.next_instruction() + + @visitor.when(cil.AssignNode) + def visit(self, node:cil.AssignNode, args: list, caller_fun_scope: dict): + value = self.get_value(node.source, caller_fun_scope) + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.PlusNode) + def visit(self, node, args: list, caller_fun_scope: dict): + return self.binary_node(node, caller_fun_scope, lambda x,y: x+y) + + @visitor.when(cil.MinusNode) + def visit(self, node, args: list, caller_fun_scope: dict): + return self.binary_node(node, caller_fun_scope, lambda x,y: x-y) + + @visitor.when(cil.StarNode) + def visit(self, node, args: list, caller_fun_scope: dict): + return self.binary_node(node, caller_fun_scope, lambda x,y: x*y) + + @visitor.when(cil.DivNode) + def visit(self, node, args: list, caller_fun_scope: dict): + try: + return self.binary_node(node, caller_fun_scope, lambda x,y: floor(x/y)) + except ZeroDivisionError: + self.raise_error(ZERO_DIVISION) + + @visitor.when(cil.AllocateNode) + def visit(self, node, args: list, caller_fun_scope: dict): + typex = self.get_dynamic_type(node.type, caller_fun_scope) + + value = self.create_type_instance(typex.name) + value["__is_type"] = False + for attr in typex.attributes: + value[attr] = None + + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.GetFatherNode) + def visit(self, node:cil.GetFatherNode, args: list, caller_fun_scope: dict): + typex = self.get_dynamic_type(node.variable, caller_fun_scope) + if typex.parent == None: + value = None + else: + value = self.create_type_instance(typex.parent) + + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.ArrayNode) + def visit(self, node:cil.ArrayNode, args: list, caller_fun_scope: dict): + array_type = self.get_dynamic_type(node.type, caller_fun_scope) + length = self.get_value_int(node.length, caller_fun_scope) + value = { + "__type": self.get_type("__Array"), + "length": length, + "items": [None for _ in range(length)] + } + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.SetIndexNode) + def visit(self, node:cil.SetIndexNode, args: list, caller_fun_scope: dict): + value = self.get_value(node.value, caller_fun_scope) + array = self.get_value(node.source, caller_fun_scope) + index = self.get_value_int(node.index, caller_fun_scope) + try: + array["items"][index] = value + except IndexError: + self.raise_error(f"Index {node.index} Out Of Range at {node.source}") + return self.next_instruction() + + @visitor.when(cil.GetIndexNode) + def visit(self, node:cil.GetIndexNode, args: list, caller_fun_scope: dict): + array = self.get_value(node.source, caller_fun_scope) + index = self.get_value_int(node.index, caller_fun_scope) + try: + value = array["items"][index] + self.set_value(node.dest, value, caller_fun_scope) + except IndexError: + self.raise_error(f"Index {node.index} Out Of Range at {node.source}") + + return self.next_instruction() + + @visitor.when(cil.TypeOfNode) + def visit(self, node, args: list, caller_fun_scope: dict): + # value = node.obj + # while isinstance(value, str): + value = self.get_value(node.obj, caller_fun_scope) + if isinstance(value, bool): + self.set_value(node.dest, self.create_type_instance("Bool"), caller_fun_scope) + elif isinstance(value, int): + self.set_value(node.dest, self.create_type_instance("Int"), caller_fun_scope) + elif isinstance(value, str): + self.set_value(node.dest, self.create_type_instance("String"), caller_fun_scope) + else: + self.set_value(node.dest, self.create_type_instance(value["__type"].name), caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.GetAttribNode) + def visit(self, node, args: list, caller_fun_scope: dict): + obj_value = self.get_value(node.source, caller_fun_scope) + if not obj_value: + obj_value = self.get_value(node.source, caller_fun_scope) + try: + value = obj_value[node.attr] + except KeyError: + self.raise_error("Attribute {0} not found at object {1}", node.attr, node.source) + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.SetAttribNode) + def visit(self, node:cil.SetAttribNode, args: list, caller_fun_scope: dict): + obj_value = self.get_value(node.source, caller_fun_scope) + if node.attr not in obj_value: + self.raise_error("Attribute {0} not found at object {1}", node.attr, node.source) + obj_value[node.attr] = self.get_value(node.value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.ArgNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = self.get_value(node.name, caller_fun_scope) + args.append(value) + return self.next_instruction() + + @visitor.when(cil.CommentNode) + def visit(self, node, args: list, caller_fun_scope: dict): + return self.next_instruction() + + @visitor.when(cil.ReturnNode) + def visit(self, node, args: list, caller_fun_scope: dict): + if node.value is not None: + value = self.get_value(node.value, caller_fun_scope) + else: + value = None + return self.return_value(value) + + @visitor.when(cil.AbortNode) + def visit(self, node, args: list, caller_fun_scope: dict): + try: + typex = caller_fun_scope['self']['__type'].name + except: + analisis = caller_fun_scope['self'] + if isinstance(analisis, str): + typex = 'String' + elif isinstance(analisis, bool): + typex = 'Bool' + elif isinstance(analisis, int): + typex = 'Int' + + raise AbortError(typex) + + @visitor.when(cil.CopyNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = self.get_value(node.instance, caller_fun_scope) + if not isinstance(value, (str, int)): + value = value.copy() + self.set_value(node.result, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.LengthNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = self.get_value_str(node.string_var, caller_fun_scope, "LENGTH operation undefined with non String type") + self.set_value(node.dest, len(value), caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.ConcatNode) + def visit(self, node, args: list, caller_fun_scope: dict): + error = "CONCAT operation undefined with non String type" + value1 = self.get_value_str(node.string1, caller_fun_scope, error) + value2 = self.get_value_str(node.string2, caller_fun_scope, error) + self.set_value(node.dest, value1 + value2, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.SubstringNode) + def visit(self, node, args: list, caller_fun_scope: dict): + error1 = "SUBSTRING operation undefined with non String type" + error2 = "SUBSTRING operation undefined with non Int index" + error3 = "SUBSTRING operation undefined with non Int length" + value1 = self.get_value_str(node.string, caller_fun_scope, error1) + value2 = self.get_value_int(node.index, caller_fun_scope, error2) + value3 = self.get_value_int(node.length, caller_fun_scope, error3) + if value2 > len(value1): + self.raise_error("SUBSTRING Out of range index") + if value3 < 0: + self.raise_error("SUBSTRING Negative length") + if value2 + value3 > len(value1): + self.raise_error("SUBSTRING Length too long for operation") + self.set_value(node.dest, value1[value2:value2+value3], caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.PrintNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = self.get_value_str(node.str_addr, caller_fun_scope, "PRINT operation undefined with non String type") + print(value, end="") + return self.next_instruction() + + @visitor.when(cil.PrintIntNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = self.get_value_int(node.int_addr, caller_fun_scope, "PRINTINT operation undefined with non Int type") + print(value, end="") + return self.next_instruction() + + @visitor.when(cil.ReadNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = input() + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.ReadIntNode) + def visit(self, node, args: list, caller_fun_scope: dict): + value = input() + try: + value = int(value) + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + except ValueError: + raise RunError(f"Readed value {value} isn't an integer") + + @visitor.when(cil.LoadNode) + def visit(self, node:cil.LoadNode, args: list, caller_fun_scope: dict): + try: + value = self.data[node.msg] + except KeyError: + self.raise_error("Data {0} isn't defined", node.msg) + self.set_value(node.dest, value, caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.LabelNode) + def visit(self, node:cil.LabelNode, args: list, caller_fun_scope: dict): + return self.next_instruction() + + @visitor.when(cil.GotoIfNode) + def visit(self, node:cil.GotoIfNode, args: list, caller_fun_scope: dict): + value = self.get_value(node.condition_value, caller_fun_scope) + jump = True + if isinstance(value, int): + jump = value != 0 + if value is None: + jump = False + if jump: + return self.jump_to(node.label) + return self.next_instruction() + + @visitor.when(cil.GotoNode) + def visit(self, node:cil.GotoNode, args: list, caller_fun_scope: dict): + return self.jump_to(node.label) + + @visitor.when(cil.NotNode) + def visit(self, node:cil.NotNode, args: list, caller_fun_scope: dict): + value = self.get_value(node.value, caller_fun_scope) + self.set_value(node.dest, not bool(value), caller_fun_scope) + return self.next_instruction() + + @visitor.when(cil.EqualNode) + def visit(self, node:cil.EqualNode, args: list, caller_fun_scope: dict): + def equal(x,y): + if isinstance(x, int) and isinstance(y, int): + return x == y + if isinstance(x, str) and isinstance(y, str): + if len(x) == len(y) and len(x) == 0: + return True + if len(x) == 1 and len(y) == 1: + return x == y + self.raise_error("Only character comparation available") + + if all(not isinstance(z, (int,str)) for z in [x,y]): + cmp1 = None + cmp2 = None + if x is not None: + if x["__is_type"]: + cmp1 = x["__type"].name + else: + cmp = x + # self.raise_error("Equal operation cant operate") + if y is not None: + if y["__is_type"]: + cmp2 = y["__type"].name + else: + cmp = y + # self.raise_error("Equal operation cant operate") + return cmp1 == cmp2 + else: + self.raise_error("OPERATION must have both argument ") + return self.binary_node(node, caller_fun_scope, equal) + + @visitor.when(cil.ObjEqualNode) + def visit(self, node:cil.ObjEqualNode, args: list, caller_fun_scope: dict): + def equal(x,y): + if isinstance(x, int) and isinstance(y, int): + return x == y + if isinstance(x, str) and isinstance(y, str): + return x == y + + if all(not isinstance(z, (int,str)) for z in [x,y]): + cmp1 = None + cmp2 = None + if x is not None: + if x["__is_type"]: + cmp1 = x["__type"].name + else: + cmp1 = id(x) # Compare by ref + if y is not None: + if y["__is_type"]: + cmp2 = y["__type"].name + else: + cmp2 = id(y) # Compare by ref + return cmp1 == cmp2 + else: + self.raise_error("OPERATION must have both argument ") + return self.binary_node(node, caller_fun_scope, equal) + + @visitor.when(cil.GreaterNode) + def visit(self, node:cil.GreaterNode, args: list, caller_fun_scope: dict): + return self.binary_node(node, caller_fun_scope, lambda x,y: x>y) + + @visitor.when(cil.LesserNode) + def visit(self, node:cil.LesserNode, args: list, caller_fun_scope: dict): + return self.binary_node(node, caller_fun_scope, lambda x,y: x 0: + self.dotcode.remove(funcs[0]) + + function_node = cil.FunctionNode(function_name, [], [], [], [],row,column,comment) + self.dotcode.append(function_node) + return function_node + + def get_function(self, function_name): + funcs = [x for x in self.dotcode if isinstance(x, cil.FunctionNode) and x.name == function_name] + return funcs[0] + + def register_type(self, name, parent=None, row=None, column=None, comment=None): + if parent: + for t in self.dottypes: + if t.name == name and ((t.parent and parent.name != t.parent.name) or not t.parent): + t.parent = [x for x in self.dottypes if x.name == parent.name][0] + return t + + parent = parent.name + + if len([x for x in self.dottypes if x.name == name]) == 0: + type_name_data_node = self.register_data('"'+name+'"', row, column, comment) + if name == "Int": # Assign Type name node address for non reference type + self.int_name_data = type_name_data_node + elif name == "Bool": + self.bool_name_data = type_name_data_node + type_node = cil.TypeNode(name, parent, type_name_data_node.name, row, column, comment) + self.dottypes.append(type_node) + return type_node + + else: + return self.get_dottype(name) + + def get_dottype(self, name): + return [x for x in self.dottypes if x.name == name][0] + + def register_data(self, value, row, column, comment=None): + vname = f'data_{len(self.dotdata)}' + data_node = cil.DataNode(vname, value, row, column, comment) + self.dotdata.append(data_node) + return data_node + + def create_entry_function(self, row, column, comment=None): + self.current_function = self.register_function('main', row, column, comment) + instance = self.define_internal_local(row, column, comment) + result = self.define_internal_local(row, column, comment) + main_method_name = self.to_function_name('main', 'Main') + main_type = self.context.get_type("Main") + main_node = InstantiateNode(("Main",0,0),0,0) + instance = self.visit(main_node, main_type.class_node.scope) + self.register_instruction(cil.ArgNode(instance, row, column)) + self.register_instruction(cil.StaticCallNode(main_method_name, result, row, column, comment)) + self.register_instruction(cil.ReturnNode("0", row, column, comment)) + self.current_function = None + + def create_type_distance_function(self, row, column, comment=None): + self.current_function = self.register_function('type_distance', row, column, comment) + type1 = "type1" + type2 = "type2" + self.params.append(cil.ParamNode(type1, row, column, comment)) + self.params.append(cil.ParamNode(type2, row, column, comment)) + + start_label = self.define_label(row, column, comment) + end_label = self.define_label(row, column, comment) + fail_label = self.define_label(row, column, comment) + + index = self.define_internal_local(row, column, comment) + equal = self.define_internal_local(row, column, comment) + equal_void = self.define_internal_local(row, column, comment) + void = self.define_internal_local(row, column, comment) + self.register_instruction(cil.VoidNode(void, row, column, comment)) + self.register_instruction(cil.AssignNode(index, "0", row, column, comment)) + + self.register_instruction(start_label) + self.register_instruction(cil.EqualNode(equal, type1, type2, row, column, comment)) + self.register_instruction(cil.GotoIfNode(equal, end_label.label, row, column, comment)) + self.register_instruction(cil.GetFatherNode(type1, type1, row, column, comment)) + self.register_instruction(cil.EqualNode(equal_void, type1, void, row, column, comment)) + self.register_instruction(cil.GotoIfNode(equal_void, fail_label.label, row, column, comment)) + self.register_instruction(cil.PlusNode(index, index, "1", row, column, comment)) + self.register_instruction(cil.GotoNode(start_label.label, row, column, comment)) + + self.register_instruction(fail_label) + self.register_instruction(cil.AssignNode(index, "-1", row, column, comment)) + self.register_instruction(end_label) + self.register_instruction(cil.ReturnNode(index, row, column, comment)) + + self.current_function = None + + def create_empty_methods(self, typex, dottype, row, column, comment=None): + """ + Creates all methods and init methods except the main init method + """ + if typex.parent: + self.create_empty_methods(typex.parent, dottype, row, column, comment) + + for attr in typex.attributes: + dottype.attributes.append(attr.name) + new_function = self.register_function(self.to_init_attr_function_name(attr.name, typex.name), row, column, f"Init {attr.name} at {typex.name}") + dottype.methods.append((new_function.name, new_function.name)) + + for m in typex.methods: + name = self.to_function_name(m.name, typex.name) + self.register_function(name, row, column, comment) + temp = [(x, y) for (x, y) in dottype.methods if x == m.name] + if len(temp) > 0: + dottype.methods[dottype.methods.index(temp[0])] = (m.name, name) + + elif len([x for (_, x) in dottype.methods if x == name]) == 0: + dottype.methods.append((m.name, name)) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope): + ###################################################### + # node.declarations -> [ ClassDeclarationNode ... ] + ###################################################### + + self.create_entry_function(node.row,node.column,"Program Node") + self.create_type_distance_function(node.row,node.column,"Program Node") + + for type_name, typex in self.context.types.items(): # Register all types + if type_name not in ["Error", "Void"]: + self.register_type(type_name,parent=None ,row=node.row, column=node.column, comment="Program Node") + + for type_name, typex in self.context.types.items(): # Assign parents to types + if type_name not in ["Error", "Void"]: + self.register_type(type_name, typex.parent, + node.row, node.column, "Program Node") + + self.abort_data = self.register_data('"Abort called from class "', node.row, node.column, "Register abort message") + self.endline_data = self.register_data('"\\n"', node.row, node.column, "Endline message") + + for type_name, typex in self.context.types.items(): # Create methods + if type_name not in ["Error", "Void"]: + this_type = next(x for x in self.dottypes if x.name == type_name) + self.create_empty_methods(typex, this_type, node.row, node.column, "Program Node") + + for type_name, typex in self.context.types.items(): + if type_name in self.context.special_types and type_name not in ["Error", "Void"]: + self.visit(typex.class_node, typex.class_node.scope) + + for declaration, child_scope in zip(node.declarations, scope.children): + self.visit(declaration, child_scope) + + return cil.ProgramNode(self.dottypes, self.dotdata, self.dotcode, node.row, node.column) + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + #################################################################### + # node.id -> str + # node.parent -> str + # node.features -> [ FuncDeclarationNode/AttrDeclarationNode ... ] + #################################################################### + + self.current_type = self.context.get_type(node.id) + + type_node = self.get_dottype(self.current_type.name) + + # Register class init function + self.current_function = init_function = self.register_function(self.to_init_type_function_name(self.current_type.name), node.row, node.column, "Class Declaration Node") + type_node.methods.insert(0, ("__init", init_function.name)) + self.params.append(cil.ParamNode('self', node.row, node.column, "Class Declaration Node")) + + # if self.current_type.parent and self.current_type.parent.name not in ["String", "Int", "Bool"]: + # self.register_instruction(cil.ArgNode('self', node.row, node.column, "Calling father init function")) + # self.register_instruction(cil.StaticCallNode(self.to_init_type_function_name(self.current_type.parent.name), "self", node.row, node.column)) + + self.register_instruction(cil.InitInstance('self', type_node.name, node.row, node.column, "Class Declaration Node")) + + for attr in self.current_type.attributes: + # Initializing attribute's init functions + init_attr_function = self.get_function(self.to_init_attr_function_name(attr.name, type_node.name)) + self.current_function = init_attr_function + self.visit(attr.node, attr.node.scope) + + for attr,typex in self.current_type.all_attributes(): + init_attr_function = self.get_function(self.to_init_attr_function_name(attr.name, typex.name)) + + # Calling function in type init function + self.current_function = init_function + dest = self.define_internal_local(row=attr.node.row, column=attr.node.column, comment="Attribute value destination") + self.register_instruction(cil.ArgNode('self',node.row, node.column, "arg node")) + self.register_instruction(cil.StaticCallNode(init_attr_function.name, dest, node.row, node.column, "Initialize arg function")) + + self.register_instruction(cil.ReturnNode('self',node.row, node.column, "return node")) # Returning created instance + + + # Initialize methods + func_declarations = (f for f in node.features if isinstance(f, FuncDeclarationNode)) + for feature in func_declarations: + self.current_function = self.get_function(self.to_function_name(feature.id,self.current_type.name)) + self.visit(feature, feature.scope) + + self.current_type = None + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + ############################### + # node.id -> str + # node.params -> [ (str, str) ... ] + # node.type -> str + # node.body -> [ ExpressionNode ... ] + ############################### + + self.current_method = self.current_type.get_method(node.id, len(node.params)) + + # Your code here!!! (Handle PARAMS) + self.params.append(cil.ParamNode('self', node.row, node.column, "Func Declaration Node")) + for param in self.current_method.param_names: + self.params.append(cil.ParamNode(param, node.row, node.column, "Func Declaration Node")) + + value = self.visit(node.body, scope) + + # Your code here!!! (Handle RETURN) + self.register_instruction(cil.ReturnNode(value, node.row, node.column, "Func Declaration Node")) + self.current_method = None + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + self.params.append(cil.ParamNode('self', node.row, node.column, "Attr Declaration Node")) + result = self.visit(node.expr, scope) + attr_offset = self.current_type.get_attribute_index(node.id, self.current_type) + self.register_instruction(cil.SetAttribNode("self", node.id, result, attr_offset, node.row, node.column, "Attr Declaration Node")) + self.register_instruction(cil.ReturnNode(value= None, row= node.row, column= node.column, comment="Attr Declaration Node")) + return result + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope): + ############################### + # node.id -> str + # node.type -> str + # node.expr -> ExpressionNode + ############################### + # Your code here!!! + local = scope.find_variable(node.id) + cil_local = self.register_local(local, node.row, node.column, "Var Declaration Node") + value = self.visit(node.expr,scope) + self.register_instruction(cil.AssignNode(cil_local,value,node.row,node.column,"Var Declaration Node")) + return cil_local + + @visitor.when(AssignNode) + def visit(self, node, scope): + ############################### + # node.id -> str + # node.expr -> ExpressionNode + ############################### + local = scope.find_variable(node.id) + value = self.visit(node.expr,scope) + if hasattr(local,'cil_name'): + self.register_instruction(cil.AssignNode(local.cil_name,value,node.row,node.column, "Assign Node")) + return local.cil_name + else: + if any(x for x in self.params if x.name == local.name): + self.register_instruction(cil.AssignNode(local.name, value, node.row,node.column, "Assign Node")) # Param + return local.name + else: + attr_offset = self.current_type.get_attribute_index(local.name, self.current_type) + self.register_instruction(cil.SetAttribNode('self',local.name, value, attr_offset, node.row, node.column, "Assign Node")) + # value = self.define_internal_local() # Attr + # self.register_instruction(cil.GetAttribNode('self',local.name,value)) + return value # or self ? + + @visitor.when(CallNode) + def visit(self, node:CallNode, scope): + ############################### + # node.obj -> AtomicNode + # node.id -> str + # node.args -> [ ExpressionNode ... ] + ############################### + + obj_value = self.visit(node.obj,scope) + + # Calling static method with no by reference type + if node.obj.type.name in ["Int", "Bool"] and not node.at: + node.at = node.obj.type + + args = [] + if node.at: + method = node.at.get_method(node.id, len(node.args)) + else: + method = node.obj.type.get_method(node.id, len(node.args)) + + for arg_node in node.args: + value = self.visit(arg_node,scope) + args.append(value) + + result = self.define_internal_local(node.row, node.column, comment=f"Result value of function {node.id}") + + self.register_instruction(cil.ArgNode(obj_value, node.row, node.column, "Call Node")) # self + for arg,value in zip(method.param_names,args): + self.register_instruction(cil.ArgNode(value, node.row, node.column, "Call Node")) + + defining_type = None + if node.at: + if isinstance(node.at, SelfType): + defining_type = node.at.defining_type + self.register_instruction(cil.DynamicCallNode(node.at.name, node.id, result, defining_type, node.row, node.column, "Call Node")) + else: + type_node = next(x for x in self.dottypes if x.name == node.at.name) + cil_name = next(cil_name for cool_name, cil_name in type_node.methods if cool_name == node.id) + self.register_instruction(cil.StaticCallNode(cil_name, result, node.row, node.column, "Call Node")) + else: + # if isinstance(node.obj.type, SelfType): + # defining_type = node.obj.type.defining_type + # self.register_instruction(cil.DynamicCallNode(node.obj.type.name,node.id,result, defining_type)) + # else: + # type_node = next(x for x in self.dottypes if x.name == node.obj.type.name) + # cil_name = next(cil_name for cool_name, cil_name in type_node.methods if cool_name == node.id) + # self.register_instruction(cil.StaticCallNode(cil_name, result)) + + if isinstance(node.obj.type, SelfType): + defining_type = node.obj.type.defining_type + else: + defining_type = node.obj.type + + type_var = self.define_internal_local(node.row, node.column, "Call Node") + + self.register_instruction(cil.TypeOfNode(obj_value, type_var, node.row, node.column, "Call Node")) + + self.register_instruction(cil.DynamicCallNode(type_var, node.id, result, defining_type, node.row, node.column, "Call Node")) + + return result + + @visitor.when(LetNode) + def visit(self, node:LetNode, scope): + current_scope = node.scope + for param in node.params: + current_scope = current_scope.children[0] + self.visit(param, current_scope) + current_scope = current_scope.children[-1] + result = self.visit(node.expr, current_scope) + return result + + @visitor.when(CheckNode) + def visit(self, node:CheckNode, scope, check_value): + scope = node.scope + local = scope.find_variable(node.id) + cil_local = self.register_local(local, node.row, node.column, "Check Node") + self.register_instruction(cil.AssignNode(cil_local, check_value, node.row, node.column, "Check Node")) + result = self.visit(node.expr, scope) + return result + + @visitor.when(CaseNode) + def visit(self, node: CaseNode, scope): + + abort_label = self.define_label( node.row, node.column, "Case Node abort label") + + value = self.visit(node.expr, scope) + final_result = self.define_internal_local(node.row, node.column, "Case Node local final result") + + type_value = self.define_internal_local(node.row, node.column, "Case Node local type_value") + + + isVoid = self.define_internal_local(node.row, node.column, "Case Node local isVoid") + self.register_instruction(cil.VoidNode(isVoid, node.row, node.column, "Case Node void isVoid")) + self.register_instruction(cil.EqualNode(isVoid,value,isVoid, node.row, node.column, "Case Node equal isVoid value isVoid")) + self.register_instruction(cil.GotoIfNode(isVoid, abort_label.label, node.row, node.column, "Case Node gotoif isVoid abort_label")) + + + self.register_instruction(cil.TypeOfNode(value, type_value, node.row, node.column, "Case Node typeof value")) + checks = len(node.params) + + array_types = self.define_internal_local(node.row, node.column , "Case Node array types") + self.register_instruction(cil.ArrayNode(array_types, "Object", checks, node.row, node.column, "Case Node array declaration")) # Type Object because at the end all are Objects + + for i,param in enumerate(node.params): + self.register_instruction(cil.SetIndexNode(array_types, str(i), param.type.name, node.row, node.column, f"Case Node array setindex {i}")) + + index = self.define_internal_local( node.row, node.column, "Case Node local index") + minim_index = self.define_internal_local( node.row, node.column, "Case Node local minim index") + minim = self.define_internal_local(node.row, node.column, "Case Node local minim") + distance = self.define_internal_local( node.row, node.column, "Case Node local distance") + current_type = self.define_internal_local( node.row, node.column, "Case Node local current type") + self.register_instruction(cil.AssignNode(index, "-1", node.row, node.column, "Case Node assign index -1")) + self.register_instruction(cil.AssignNode(minim, "-2", node.row, node.column, "Case Node assign minim -2")) + + start_label = self.define_label(node.row, node.column, "Case Node start label") + minim_label = self.define_label( node.row, node.column, "Case Node minim label") + end_label = self.define_label( node.row, node.column, "Case Node end label") + + stop_for = self.define_internal_local( node.row, node.column, "Case Node local stop_for") + not_valid_distance = self.define_internal_local( node.row, node.column, "Case Node local not_valid_distance") + minim_cond = self.define_internal_local( node.row, node.column, "Case Node local minim_cond") + + self.register_instruction(start_label) + self.register_instruction(cil.PlusNode(index, index, "1", node.row, node.column, "Case Node plus index 1")) + self.register_instruction(cil.EqualNode(stop_for, index, str(checks), node.row, node.column, "Case Node equal stop_for index checks")) + self.register_instruction(cil.GotoIfNode(stop_for, end_label.label, node.row, node.column, "Case Node gotoif stop_for end_label")) + + + self.register_instruction(cil.GetIndexNode(array_types, index, current_type, node.row, node.column, "Case Node get_index array_types index")) + + self.register_instruction(cil.ArgNode(type_value, node.row, node.column, "Case Node arg type_value")) + self.register_instruction(cil.ArgNode(current_type, node.row, node.column, "Case Node arg current_type")) + self.register_instruction(cil.StaticCallNode("type_distance", distance, node.row, node.column, "Case Node static_call type_distance")) + + self.register_instruction(cil.EqualNode(not_valid_distance, distance, "-1", node.row, node.column, "Case Node equal not_valid_distance distance -1")) + self.register_instruction(cil.GotoIfNode(not_valid_distance, start_label.label, node.row, node.column, "Case Node gotoif not_valid_distance start_label")) + + self.register_instruction(cil.EqualNode(minim_cond, minim, "-2", node.row, node.column, "Case Node equal minim_cond minim -2")) + self.register_instruction(cil.GotoIfNode(minim_cond, minim_label.label, node.row, node.column, "Case Node gotoif minim_cond minim_label")) + self.register_instruction(cil.GreaterNode(minim_cond, minim, distance, node.row, node.column, "Case Node greater minim_cond minim distance")) + self.register_instruction(cil.GotoIfNode(minim_cond, minim_label.label, node.row, node.column, "Case Node gotoif minim_cond minim_label")) + self.register_instruction(cil.GotoNode(start_label.label, node.row, node.column, "Case Node goto start_label")) + + self.register_instruction(minim_label) + self.register_instruction(cil.AssignNode(minim, distance, node.row, node.column, "Case Node assign minim distance")) + self.register_instruction(cil.AssignNode(minim_index, index, node.row, node.column, "Case Node assign minim_index index")) + + self.register_instruction(cil.GotoNode(start_label.label, node.row, node.column, "Case Node goto start_label")) + self.register_instruction(end_label) + + self.register_instruction(cil.EqualNode(minim_cond, minim, "-2", node.row, node.column, "Case Node equal minim_cond minim -2")) + self.register_instruction(cil.GotoIfNode(minim_cond, abort_label.label, node.row, node.column, "Case Node gotoif minim_cond abort_label")) + + self.register_instruction(cil.GetIndexNode(array_types, minim_index, current_type, node.row, node.column, "Case Node get_index array_types minim_index")) + + final_label = self.define_label( node.row, node.column, "Case Node final_label") + not_equal_types = self.define_internal_local( node.row, node.column, "Case Node local not_equal_types") + end_labels = [self.define_label(node.row, node.column,f"Case Node end_label {i}") for i in node.params] + for lbl, param, child_scope in zip(end_labels, node.params, node.scope.children): + self.register_instruction(cil.EqualNode(not_equal_types, param.type.name, current_type, node.row, node.column, "Case Node equal not_equal_types param.type.name current_type")) + self.register_instruction(cil.NotNode(not_equal_types, not_equal_types, node.row, node.column, "Case Node not not_equal_types not_equal_types")) + self.register_instruction(cil.GotoIfNode(not_equal_types, lbl.label, node.row, node.column, "Case Node gotoif not_equal_types lbl.label")) + + result = self.visit(param, child_scope, value) + self.register_instruction(cil.AssignNode(final_result, result, node.row, node.column, "Case Node assign final_result result")) + + self.register_instruction(cil.GotoNode(final_label.label, node.row, node.column, "Case Node goto final_label")) + self.register_instruction(lbl) + + self.register_instruction(abort_label) + self.register_instruction(cil.AbortNode(node.row, node.column, "Case Node abort")) + self.register_instruction(final_label) + + return final_result + + @visitor.when(IsVoidNode) + def visit(self, node:IsVoidNode, scope): + result = self.define_internal_local( node.row, node.column, "Is Void Node") + value = self.visit(node.member, scope) + if node.member.type.name in ["Int", "Bool"]: + self.register_instruction(cil.AssignNode(result, 0, node.row, node.col, comment="Non object always not void")) + else: + void_value = self.define_internal_local( node.row, node.column, "Is Void Node") + self.register_instruction(cil.VoidNode(void_value, node.row, node.column, "Is Void Node")) + self.register_instruction(cil.ObjEqualNode(result, value, void_value, node.row, node.column, "Is Void Node", value_compare=False)) + return result + + @visitor.when(ConditionalNode) + def visit(self, node:ConditionalNode, scope): + + result = self.define_internal_local( node.row, node.column, "Conditional Node") + condition_value = self.visit(node.condition, scope) + then_label = self.define_label( node.row, node.column, "Conditional Node") + end_label = self.define_label( node.row, node.column, "Conditional Node") + + self.register_instruction(cil.GotoIfNode(condition_value, then_label.label, node.row, node.column, "Conditional Node")) + + else_value = self.visit(node.else_expr, scope) + self.register_instruction(cil.AssignNode(result, else_value, node.row, node.column, "Conditional Node")) + self.register_instruction(cil.GotoNode(end_label.label, node.row, node.column, "Conditional Node")) + + self.register_instruction(then_label) + then_value = self.visit(node.then_expr,scope) + self.register_instruction(cil.AssignNode(result, then_value, node.row, node.column, "Conditional Node")) + + self.register_instruction(end_label) + return result + + @visitor.when(BlockNode) + def visit(self, node:BlockNode, scope): + scope = node.scope + result = self.define_internal_local( node.row, node.column, "Block Node") + for expr in node.expr_list: + result = self.visit(expr, scope) + return result + + @visitor.when(WhileNode) + def visit(self, node:WhileNode, scope): + result = self.visit(VoidNode(None), scope) + start_label = self.define_label( node.row, node.column, "While Node") + loop_label = self.define_label( node.row, node.column, "While Node") + end_label = self.define_label( node.row, node.column, "While Node") + + self.register_instruction(start_label) + condition_result = self.visit(node.condition, scope) + + self.register_instruction(cil.GotoIfNode(condition_result, loop_label.label, node.row, node.column, "While Node")) + self.register_instruction(cil.GotoNode(end_label.label, node.row, node.column, "While Node")) + + self.register_instruction(loop_label) + self.visit(node.expr, scope) + + self.register_instruction(cil.GotoNode(start_label.label, node.row, node.column, "While Node")) + self.register_instruction(end_label) + + return result + + @visitor.when(NotNode) + def visit(self, node, scope): + result = self.define_internal_local( node.row, node.column, "Not Node") + value = self.visit(node.member, scope) + self.register_instruction(cil.NotNode(result, value, node.row, node.column, "Not Node")) + return result + + @visitor.when(RoofNode) + def visit(self, node:RoofNode, scope): + result = self.define_internal_local( node.row, node.column, "Roof Node") + value = self.visit(node.member, scope) + self.register_instruction(cil.MinusNode(result, "0", value, node.row, node.column, "Roof Node")) + return result + + @visitor.when(EqualNode) + def visit(self, node:EqualNode, scope): + result = self.define_internal_local( node.row, node.column, "Equal Node") + + value1 = self.visit(node.left, scope) + value2 = self.visit(node.right, scope) + + value_types = ["Int", "Bool"] + value_compare = node.left.type.name in value_types and node.right.type.name in value_types + + self.register_instruction(cil.ObjEqualNode(result, value1, value2, node.row, node.column, "Equal Node", value_compare=value_compare)) + + return result + + @visitor.when(GreaterNode) + def visit(self, node:GreaterNode, scope): + result = self.define_internal_local( node.row, node.column, "Greater Node") + + value1 = self.visit(node.left, scope) + value2 = self.visit(node.right, scope) + + self.register_instruction(cil.GreaterNode(result, value1, value2, node.row, node.column, "Greater Node")) + + return result + + @visitor.when(GreaterEqualNode) + def visit(self, node, scope): + result = self.define_internal_local( node.row, node.column, "GreaterEqual Node") + + value1 = self.visit(node.left, scope) + value2 = self.visit(node.right, scope) + + self.register_instruction(cil.LesserNode(result, value1, value2, node.row, node.column, "GreaterEqual Node")) + self.register_instruction(cil.NotNode(result, result, node.row, node.column, "GreaterEqual Node")) + + return result + + @visitor.when(LesserNode) + def visit(self, node, scope): + result = self.define_internal_local( node.row, node.column, "Lesser Node") + + value1 = self.visit(node.left, scope) + value2 = self.visit(node.right, scope) + + self.register_instruction(cil.LesserNode(result, value1, value2, node.row, node.column, "Lesser Node")) + + return result + + @visitor.when(LesserEqualNode) + def visit(self, node, scope): + result = self.define_internal_local( node.row, node.column, "LesserEqual Node") + + value1 = self.visit(node.left, scope) + value2 = self.visit(node.right, scope) + + self.register_instruction(cil.GreaterNode(result, value1, value2, node.row, node.column, "LesserEqual Node")) + self.register_instruction(cil.NotNode(result, result, node.row, node.column, "LesserEqual Node")) + + return result + + @visitor.when(VoidNode) + def visit(self, node, scope): + result = self.define_internal_local( node.row, node.column, "Void Node") + self.register_instruction(cil.VoidNode(result, node.row, node.column, "Void Node")) + return result + + @visitor.when(BoolNode) + def visit(self, node, scope): + ############################### + # node.lex -> str + ############################### + return "0" if node.lex.lower() == "false" else "1" + + @visitor.when(ConstantNumNode) + def visit(self, node, scope): + ############################### + # node.lex -> str + ############################### + + return node.lex + + @visitor.when(VariableNode) + def visit(self, node, scope): + ############################### + # node.lex -> str + ############################### + + # Your code here!!! + try: + return scope.find_variable(node.lex).cil_name # is a Local Variable + except AttributeError: + if any(x for x in self.params if x.name == node.lex): + return node.lex # Param + else: + attr_offset = self.current_type.get_attribute_index(node.lex, self.current_type) + value = self.define_internal_local( node.row,node.column,"Variable Node") # Attr + self.register_instruction(cil.GetAttribNode('self',node.lex, value, attr_offset, node.row, node.column, "Variable Node")) + return value + + @visitor.when(InstantiateNode) + def visit(self, node, scope): + ############################### + # node.lex -> str + ############################### + + # Your code here!!! + instance = self.define_internal_local( node.row, node.column, "Instantiate Node") + instance_typex = self.context.get_type(node.lex, current_type = self.current_type) + if instance_typex.name == "Void": + self.register_instruction(cil.VoidNode(instance, node.row, node.column, "Instantiate Node")) + elif instance_typex.name == "SELF_TYPE": + dynamic_type = self.define_internal_local( node.row, node.column, "Instantiate Node") + self.register_instruction(cil.TypeOfNode("self", dynamic_type, node.row, node.column, "Instantiate Node")) + self.register_instruction(cil.AllocateNode(dynamic_type, instance, node.row, node.column, "Instantiate Node")) + self.register_instruction(cil.ArgNode(instance, node.row, node.column, "Instantiate Node")) + self.register_instruction(cil.DynamicCallNode(dynamic_type, "__init", instance, instance_typex.defining_type, node.row, node.column, "Instantiate Node")) + else: + self.register_instruction(cil.AllocateNode(instance_typex.name, instance, node.row, node.column, "Instantiate Node")) + self.register_instruction(cil.ArgNode(instance, node.row, node.column, "Instantiate Node")) + self.register_instruction(cil.StaticCallNode(self.to_init_type_function_name(instance_typex.name), instance, node.row, node.column, "Instantiate Node")) + return instance + + @visitor.when(PlusNode) + def visit(self, node, scope): + ############################### + # node.left -> ExpressionNode + # node.right -> ExpressionNode + ############################### + + # Your code here!!! + left = self.visit(node.left,scope) + right = self.visit(node.right,scope) + + value = self.define_internal_local( node.row, node.column, "Plus Node") + self.register_instruction(cil.PlusNode(value,left,right,node.row,node.column,"Plus Node")) + return value + + @visitor.when(MinusNode) + def visit(self, node, scope): + ############################### + # node.left -> ExpressionNode + # node.right -> ExpressionNode + ############################### + + # Your code here!!! + left = self.visit(node.left,scope) + right = self.visit(node.right,scope) + + value = self.define_internal_local( node.row, node.column, "Minus Node") + self.register_instruction(cil.MinusNode(value,left,right,node.row,node.column,"Minus Node")) + return value + + @visitor.when(StarNode) + def visit(self, node, scope): + ############################### + # node.left -> ExpressionNode + # node.right -> ExpressionNode + ############################### + + # Your code here!!! + left = self.visit(node.left,scope) + right = self.visit(node.right,scope) + + value = self.define_internal_local( node.row, node.column, "Star Node") + self.register_instruction(cil.StarNode(value,left,right,node.row,node.column,"Star Node")) + return value + + @visitor.when(DivNode) + def visit(self, node, scope): + ############################### + # node.left -> ExpressionNode + # node.right -> ExpressionNode + ############################### + + # Your code here!!! + left = self.visit(node.left,scope) + right = self.visit(node.right,scope) + + value = self.define_internal_local( node.row, node.column, "Div Node") + self.register_instruction(cil.DivNode(value,left,right,node.row,node.column,"Div Node")) + return value + + @visitor.when(StringNode) + def visit(self, node, scope): + value = self.register_data(node.lex, node.row, node.column, "String Node") + result = self.define_internal_local( node.row, node.column, "String Node") + self.register_instruction(cil.LoadNode(result, value.name, node.row, node.column, "String Node")) + return result + + @visitor.when(SpecialNode) + def visit(self, node, scope=None): + return self.visit(node.cil_node_type(row=node.row, column=node.column), scope) + + + + # META INSTRUCTIONS ONLY USED IN CODE + # TRANSLATION THAT DOESN'T BELONG TO CIL'S + # INSTRUCTION SET + + @visitor.when(cil.ObjectCopyNode) + def visit(self, node, scope=None): + instance = self.params[0] + result = self.define_internal_local( node.row, node.column, "Object Copy Node") + self.register_instruction(cil.CopyNode(instance.name, result, node.row, node.column, "Object Copy Node")) + return result + + @visitor.when(cil.ObjectAbortNode) + def visit(self, node:cil.ObjectAbortNode, scope=None): + # Abort called from class {self.typex}\n + instance = self.params[0] + type_var = self.define_internal_local(node.row, node.column, "Dynamic type for abort dispatch") + type_name = self.define_internal_local(node.row, node.column, "Type name address") + + self.register_instruction(cil.TypeOfNode(instance.name, type_var, node.row, node.column, "Assign object type")) + self.register_instruction(cil.TypeNameNode(type_var, type_name, node.row, node.column, "Get type name")) + + self._add_print_abort_instructions(type_name, node.row, node.column, "Abort Object") + return "0" + + @visitor.when(cil.ObjectTypeNameNode) + def visit(self, node, scope=None): + instance = self.params[0] + result = self.define_internal_local(row=node.row, column=node.column, comment=node.comment) + self.register_instruction(cil.TypeOfNode(instance.name, result, node.row, node.column, "Object Type Name Node")) + self.register_instruction(cil.TypeNameNode(result, result, node.row, node.column, "Object Type Name Node")) + return result + + @visitor.when(cil.IntAbortNode) + def visit(self, node:cil.IntAbortNode, scope=None): + type_name = self.define_internal_local(node.row, node.column, "Type name address") + + self.register_instruction(cil.LoadNode(type_name, self.int_name_data.name, node.row, node.column)) + + self._add_print_abort_instructions(type_name, node.row, node.column, "Abort Int") + return "0" + + @visitor.when(cil.IntTypeNameNode) + def visit(self, node:cil.IntTypeNameNode, scope=None): + type_name = self.define_internal_local(node.row, node.column, "Type name address") + self.register_instruction(cil.LoadNode(type_name, self.int_name_data.name, node.row, node.column)) + return type_name + + @visitor.when(cil.BoolAbortNode) + def visit(self, node:cil.BoolAbortNode, scope=None): + type_name = self.define_internal_local(node.row, node.column, "Type name address") + + self.register_instruction(cil.LoadNode(type_name, self.bool_name_data.name, node.row, node.column)) + + self._add_print_abort_instructions(type_name, node.row, node.column, "Abort Bool") + return "0" + + @visitor.when(cil.BoolTypeNameNode) + def visit(self, node:cil.BoolTypeNameNode, scope=None): + type_name = self.define_internal_local(node.row, node.column, "Type name address") + self.register_instruction(cil.LoadNode(type_name, self.bool_name_data.name, node.row, node.column)) + return type_name + + @visitor.when(cil.StringConcatNode) + def visit(self, node, scope=None): + string1 = self.params[0] + string2 = self.params[1] + result = self.define_internal_local( node.row, node.column, "String Concat Node") + self.register_instruction(cil.ConcatNode(result, string1.name, string2.name, node.row, node.column, "String Concat Node")) + return result + + @visitor.when(cil.StringLengthNode) + def visit(self, node, scope=None): + string = self.params[0] + result = self.define_internal_local( node.row, node.column, "String Length Node") + self.register_instruction(cil.LengthNode(result, string.name, node.row, node.column, "String Length Node")) + return result + + @visitor.when(cil.StringSubstringNode) + def visit(self, node, scope=None): + string = self.params[0] + index = self.params[1] + length = self.params[2] + result = self.define_internal_local( node.row, node.column, "String Substring Node") + self.register_instruction(cil.SubstringNode(result, string.name, index.name, length.name, node.row, node.column,"String Substring Node")) + return result + + @visitor.when(cil.IOInStringNode) + def visit(self, node, scope=None): + result = self.define_internal_local( node.row, node.column, "IO In String Node") + self.register_instruction(cil.ReadNode(result, node.row, node.column, "IO In String Node")) + return result + + @visitor.when(cil.IOInIntNode) + def visit(self, node, scope=None): + result = self.define_internal_local( node.row, node.column, "IO In Int Node") + self.register_instruction(cil.ReadIntNode(result, node.row, node.column, "IO In Int Node")) + return result + + @visitor.when(cil.IOOutIntNode) + def visit(self, node, scope=None): + integer = self.params[1] + self.register_instruction(cil.PrintIntNode(integer.name, node.row, node.column, "IO Out Int Node")) + return self.params[0].name + + @visitor.when(cil.IOOutStringNode) + def visit(self, node, scope=None): + string = self.params[1] + self.register_instruction(cil.PrintNode(string.name, node.row, node.column, "IO Out String Node")) + return self.params[0].name + + # ====================================================================== diff --git a/src/cool_cmp/cmp/__init__.py b/src/cool_cmp/cmp/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cmp/ast.py b/src/cool_cmp/cmp/ast.py new file mode 100644 index 000000000..792908349 --- /dev/null +++ b/src/cool_cmp/cmp/ast.py @@ -0,0 +1,78 @@ +import cmp.visitor as visitor + +class Node: + def evaluate(self): + raise NotImplementedError() + +class AtomicNode(Node): + def __init__(self, lex): + self.lex = lex + +class UnaryNode(Node): + def __init__(self, node): + self.node = node + + def evaluate(self): + value = self.node.evaluate() + return self.operate(value) + + @staticmethod + def operate(value): + raise NotImplementedError() + +class BinaryNode(Node): + def __init__(self, left, right): + self.left = left + self.right = right + + def evaluate(self): + lvalue = self.left.evaluate() + rvalue = self.right.evaluate() + return self.operate(lvalue, rvalue) + + @staticmethod + def operate(lvalue, rvalue): + raise NotImplementedError() + +class TernaryNode(Node): + def __init__(self, left, middle, right): + self.left = left + self.right = right + self.middle = middle + + def evaluate(self): + lvalue = self.left.evaluate() + mvalue = self.middle.evaluate() + rvalue = self.right.evaluate() + return self.operate(lvalue, mvalue, rvalue) + + @staticmethod + def operate(lvalue, mvalue, rvalue): + raise NotImplementedError() + +def get_printer(AtomicNode=AtomicNode, UnaryNode=UnaryNode, BinaryNode=BinaryNode, ): + + class PrintVisitor(object): + @visitor.on('node') + def visit(self, node, tabs): + pass + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__}' + child = self.visit(node.node, tabs + 1) + return f'{ans}\n{child}' + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__} ' + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f'{ans}\n{left}\n{right}' + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__ {node.__class__.__name__}: {node.lex}' + + printer = PrintVisitor() + return (lambda ast: printer.visit(ast)) \ No newline at end of file diff --git a/src/cool_cmp/cmp/automata.py b/src/cool_cmp/cmp/automata.py new file mode 100644 index 000000000..07522ae8a --- /dev/null +++ b/src/cool_cmp/cmp/automata.py @@ -0,0 +1,210 @@ +try: + import pydot +except: + pass + +class State: + def __init__(self, state, final=False, formatter=None, shape='circle'): + self.state = state + self.final = final + self.transitions = {} + self.epsilon_transitions = set() + self.tag = None + self.formatter = formatter + self.shape = shape + + # The method name is set this way from compatibility issues. + def set_formatter(self, value, attr='formatter', visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + self.__setattr__(attr, value) + for destinations in self.transitions.values(): + for node in destinations: + node.set_formatter(value, attr, visited) + for node in self.epsilon_transitions: + node.set_formatter(value, attr, visited) + return self + + def has_transition(self, symbol): + return symbol in self.transitions + + def add_transition(self, symbol, state): + try: + self.transitions[symbol].append(state) + except: + self.transitions[symbol] = [state] + return self + + def add_epsilon_transition(self, state): + self.epsilon_transitions.add(state) + return self + + def recognize(self, string): + states = self.epsilon_closure + for symbol in string: + states = self.move_by_state(symbol, *states) + states = self.epsilon_closure_by_state(*states) + return any(s.final for s in states) + + def to_deterministic(self, formatter=None): + closure = self.epsilon_closure + start = State(tuple(closure), any(s.final for s in closure), formatter) + + closures = [ closure ] + states = [ start ] + pending = [ start ] + + while pending: + state = pending.pop() + symbols = { symbol for s in state.state for symbol in s.transitions } + + for symbol in symbols: + move = self.move_by_state(symbol, *state.state) + closure = self.epsilon_closure_by_state(*move) + + if closure not in closures: + new_state = State(tuple(closure), any(s.final for s in closure), formatter) + closures.append(closure) + states.append(new_state) + pending.append(new_state) + else: + index = closures.index(closure) + new_state = states[index] + + state.add_transition(symbol, new_state) + + return start + + @staticmethod + def from_nfa(nfa, get_states=False): + states = [] + for n in range(nfa.states): + state = State(n, n in nfa.finals) + states.append(state) + + for (origin, symbol), destinations in nfa.map.items(): + origin = states[origin] + origin[symbol] = [ states[d] for d in destinations ] + + if get_states: + return states[nfa.start], states + return states[nfa.start] + + @staticmethod + def move_by_state(symbol, *states): + return { s for state in states if state.has_transition(symbol) for s in state[symbol]} + + @staticmethod + def epsilon_closure_by_state(*states): + closure = { state for state in states } + + l = 0 + while l != len(closure): + l = len(closure) + tmp = [s for s in closure] + for s in tmp: + for epsilon_state in s.epsilon_transitions: + closure.add(epsilon_state) + return closure + + @property + def epsilon_closure(self): + return self.epsilon_closure_by_state(self) + + @property + def name(self): + try: + return f'{self.idx}\n' + self.formatter(self.state) + except AttributeError: + return self.formatter(self.state) + + def get(self, symbol): + target = self.transitions[symbol] + assert len(target) == 1 + return target[0] + + def __getitem__(self, symbol): + if symbol == '': + return self.epsilon_transitions + try: + return self.transitions[symbol] + except KeyError: + return None + + def __setitem__(self, symbol, value): + if symbol == '': + self.epsilon_transitions = value + else: + self.transitions[symbol] = value + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.state) + + def __hash__(self): + return hash(self.state) + + def __iter__(self): + yield from self._visit() + + def _visit(self, visited=None): + if visited is None: + visited = set() + elif self in visited: + return + + visited.add(self) + yield self + + for destinations in self.transitions.values(): + for node in destinations: + yield from node._visit(visited) + for node in self.epsilon_transitions: + yield from node._visit(visited) + + def graph(self,rankdir_conf='LR'): + G = pydot.Dot(rankdir=rankdir_conf, margin=0.1) + G.add_node(pydot.Node('start', shape='plaintext', label='', width=0, height=0)) + + visited = set() + def visit(start): + ids = id(start) + if ids not in visited: + visited.add(ids) + G.add_node(pydot.Node(ids, label=start.name, shape=self.shape, style='bold' if start.final else '')) + for tran, destinations in start.transitions.items(): + for end in destinations: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label=tran, labeldistance=2)) + for end in start.epsilon_transitions: + visit(end) + G.add_edge(pydot.Edge(ids, id(end), label='ε', labeldistance=2)) + + visit(self) + G.add_edge(pydot.Edge('start', id(self), label='', style='dashed')) + + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode('utf8') + except: + pass + + def write_to(self, fname): + return self.graph().write_svg(fname) + +def multiline_formatter(state): + return '\n'.join(str(item) for item in state) + +def lr0_formatter(state): + try: + return '\n'.join(str(item) for item in state) + except TypeError: + return str(state) \ No newline at end of file diff --git a/src/cool_cmp/cmp/cil.py b/src/cool_cmp/cmp/cil.py new file mode 100644 index 000000000..8bc4abbeb --- /dev/null +++ b/src/cool_cmp/cmp/cil.py @@ -0,0 +1,254 @@ +from typing import Optional +import cmp.visitor as visitor + + +class Node: + def __init__(self,row,column,comment=None) -> None: + self.row = row + self.column = column + self.comment = comment + +class ProgramNode(Node): + def __init__(self, dottypes, dotdata, dotcode, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dottypes = dottypes + self.dotdata = dotdata + self.dotcode = dotcode + +class TypeNode(Node): + def __init__(self, name, parent, name_data, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = name + self.parent = parent + self.name_data = name_data + self.attributes = [] + self.methods = [] + + def __str__(self): + return self.name + +class DataNode(Node): + def __init__(self, vname, value, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = vname + self.value = value + +class FunctionNode(Node): + def __init__(self, fname, params, localvars, instructions, labels, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = fname + self.params = params + self.localvars = localvars + self.instructions = instructions + self.labels = labels + + @property + def return_instruction(self) -> 'Optional[ReturnNode]': + if self.instructions: + return self.instructions[-1] if isinstance(self.instructions[-1], ReturnNode) else None + return None + +class ParamNode(Node): + def __init__(self, name, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = name + +class LocalNode(Node): + def __init__(self, name,row ,column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = name + +class InstructionNode(Node): + def __init__(self, row, column, comment=None) -> None: + super().__init__(row,column,comment) + +class AssignNode(InstructionNode): + def __init__(self, dest, source, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.source = source + +class ArithmeticNode(InstructionNode): + def __init__(self, dest, left, right, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.left = left + self.right = right + +class PlusNode(ArithmeticNode): + pass + + +class MinusNode(ArithmeticNode): + pass + + +class StarNode(ArithmeticNode): + pass + + +class DivNode(ArithmeticNode): + pass + + +class GetAttribNode(InstructionNode): + def __init__(self, source, attr, dest, attribute_index, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.source = source + self.attr = attr + self.dest = dest + self.attribute_index = attribute_index + +class SetAttribNode(InstructionNode): + def __init__(self, source, attr, value, attribute_index, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.source = source + self.attr = attr + self.value = value + self.attribute_index = attribute_index + +class GetIndexNode(InstructionNode): + def __init__(self, source, index, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.source = source + self.index = index + self.dest = dest + +class SetIndexNode(InstructionNode): + def __init__(self, source, index, value, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.source = source + self.index = index + self.value = value + +class AllocateNode(InstructionNode): + def __init__(self, itype, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.type = itype + self.dest = dest + +class ArrayNode(InstructionNode): + def __init__(self, dest, type, length, row, column,comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.type = type + self.length = length + +class TypeOfNode(InstructionNode): + def __init__(self, obj, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.obj = obj + self.dest = dest + +class TypeNameNode(InstructionNode): + def __init__(self, typex, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.type = typex + self.dest = dest + +class LabelNode(InstructionNode): + def __init__(self, label, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.label = label + +class GotoNode(InstructionNode): + def __init__(self, label,row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.label = label + +class GotoIfNode(InstructionNode): + def __init__(self, condition_value, label, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.condition_value = condition_value + self.label = label + +class StaticCallNode(InstructionNode): + def __init__(self, function, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.function = function + self.dest = dest + +class DynamicCallNode(InstructionNode): + def __init__(self, xtype, method, dest, base_type=None, row=None, column=None, comment=None) -> None: + super().__init__(row,column,comment) + self.type = xtype + self.method = method + self.dest = dest + self.base_type = base_type # Needed for SELF_TYPE handling. Is the Type where the SELF_TYPE was defined + +class ArgNode(InstructionNode): + def __init__(self, name, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.name = name + +class ReturnNode(InstructionNode): + def __init__(self, value=None, row=None, column=None, comment=None) -> None: + super().__init__(row,column,comment) + self.value = value + +class LoadNode(InstructionNode): + def __init__(self, dest, msg, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.msg = msg + +class LengthNode(InstructionNode): + def __init__(self, dest, string_var, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.string_var = string_var + + +class ConcatNode(InstructionNode): + def __init__(self, dest, string1, string2, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.string1 = string1 + self.string2 = string2 + +class PrefixNode(InstructionNode): + def __init__(self, row, column, comment=None) -> None: + super().__init__(row,column,comment) + +class SubstringNode(InstructionNode): + def __init__(self, dest, string, index, length, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + self.string = string + self.index = index + self.length = length + +class ReadNode(InstructionNode): + def __init__(self, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + +class ReadIntNode(InstructionNode): + def __init__(self, dest, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.dest = dest + +class PrintNode(InstructionNode): + def __init__(self, str_addr, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.str_addr = str_addr + +class PrintIntNode(InstructionNode): + def __init__(self, int_addr, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.int_addr = int_addr + +class AbortNode(InstructionNode): + def __init__(self, row, column, comment=None) -> None: + super().__init__(row,column,comment) + +class CopyNode(InstructionNode): + def __init__(self, instance, result, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.instance = instance + self.result = result + +class CommentNode(InstructionNode): + def __init__(self, msg, row, column, comment=None) -> None: + super().__init__(row,column,comment) + self.msg = msg diff --git a/src/cool_cmp/cmp/evaluation.py b/src/cool_cmp/cmp/evaluation.py new file mode 100644 index 000000000..d49eaae8c --- /dev/null +++ b/src/cool_cmp/cmp/evaluation.py @@ -0,0 +1,33 @@ +from cmp.pycompiler import EOF +from cmp.tools.parsing import ShiftReduceParser + +def evaluate_reverse_parse(right_parse, operations, tokens): + if not right_parse or not operations or not tokens: + return + + right_parse = iter(right_parse) + tokens = iter(tokens) + stack = [] + for operation in operations: + if operation == ShiftReduceParser.SHIFT: + token = next(tokens) + stack.append(token.lex) + elif operation == ShiftReduceParser.REDUCE: + production = next(right_parse) + head, body = production + attributes = production.attributes + assert all(rule is None for rule in attributes[1:]), 'There must be only synteticed attributes.' + rule = attributes[0] + + if len(body): + synteticed = [None] + stack[-len(body):] + value = rule(None, synteticed) + stack[-len(body):] = [value] + else: + stack.append(rule(None, None)) + else: + raise Exception('Invalid action!!!') + + assert len(stack) == 1 + assert isinstance(next(tokens).token_type, EOF) + return stack[0] \ No newline at end of file diff --git a/src/cool_cmp/cmp/languages.py b/src/cool_cmp/cmp/languages.py new file mode 100644 index 000000000..a1dfc78e6 --- /dev/null +++ b/src/cool_cmp/cmp/languages.py @@ -0,0 +1,228 @@ +from cmp.pycompiler import Sentence, Production +from cmp.utils import ContainerSet, Token, UnknownToken +from cmp.tools.parsing import build_parsing_table, metodo_predictivo_no_recursivo + +class BasicXCool: + def __init__(self, G): + self.G = G + self.fixed_tokens = { lex: Token(lex, G[lex]) for lex in '+ - * / ( )'.split() } + + @property + def firsts(self): + G = self.G + return { + G['+']: ContainerSet(G['+'] , contains_epsilon=False), + G['-']: ContainerSet(G['-'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['/']: ContainerSet(G['/'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['num']: ContainerSet(G['num'] , contains_epsilon=False), + G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), + G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), + Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), + Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False), + G['F']: ContainerSet(G['-'], G.EOF, G['*'], G['/'], G[')'], G['+'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G[')'], G['-'], G.EOF, G['+'] , contains_epsilon=False) + } + + @property + def table(self): + G = self.G + return { + ( G['E'], G['num'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['X'], G['+'], ): [ Production(G['X'], Sentence(G['+'], G['T'], G['X'])), ], + ( G['X'], G['-'], ): [ Production(G['X'], Sentence(G['-'], G['T'], G['X'])), ], + ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], + ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], + ( G['T'], G['num'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['Y'], G['*'], ): [ Production(G['Y'], Sentence(G['*'], G['F'], G['Y'])), ], + ( G['Y'], G['/'], ): [ Production(G['Y'], Sentence(G['/'], G['F'], G['Y'])), ], + ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['-'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['+'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['F'], G['num'], ): [ Production(G['F'], Sentence(G['num'])), ], + ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['('], G['E'], G[')'])), ] + } + + @property + def tokenizer(self): + G = self.G + fixed_tokens = self.fixed_tokens + + def tokenize_text(text): + tokens = [] + for item in text.split(): + try: + float(item) + token = Token(item, G['num']) + except ValueError: + try: + token = fixed_tokens[item] + except: + token = UnknownToken(item) + tokens.append(token) + eof = Token('$', G.EOF) + tokens.append(eof) + return tokens + + return tokenize_text + +class PowXCool: + def __init__(self, G): + self.G = G + + @property + def firsts(self): + G = self.G + return { + G['+']: ContainerSet(G['+'] , contains_epsilon=False), + G['-']: ContainerSet(G['-'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['/']: ContainerSet(G['/'] , contains_epsilon=False), + G['^']: ContainerSet(G['^'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['num']: ContainerSet(G['num'] , contains_epsilon=False), + G['E']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G['num'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['-'], G['+'] , contains_epsilon=True), + G['Y']: ContainerSet(G['/'], G['*'] , contains_epsilon=True), + G['Z']: ContainerSet(G['^'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['+'], G['T'], G['X']): ContainerSet(G['+'] , contains_epsilon=False), + Sentence(G['-'], G['T'], G['X']): ContainerSet(G['-'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['*'], G['F'], G['Y']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['/'], G['F'], G['Y']): ContainerSet(G['/'] , contains_epsilon=False), + Sentence(G['A'], G['Z']): ContainerSet(G['num'], G['('] , contains_epsilon=False), + Sentence(G['^'], G['F']): ContainerSet(G['^'] , contains_epsilon=False), + Sentence(G['num']): ContainerSet(G['num'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['F']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['A']: ContainerSet(G['-'], G['*'], G['/'], G['^'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G['-'], G[')'], G.EOF, G['+'] , contains_epsilon=False), + G['Z']: ContainerSet(G['-'], G['*'], G['/'], G[')'], G.EOF, G['+'] , contains_epsilon=False) + } + +class Regex: + def __init__(self, G): + self.G = G + + @property + def firsts(self): + G = self.G + return { + G['|']: ContainerSet(G['|'] , contains_epsilon=False), + G['*']: ContainerSet(G['*'] , contains_epsilon=False), + G['(']: ContainerSet(G['('] , contains_epsilon=False), + G[')']: ContainerSet(G[')'] , contains_epsilon=False), + G['symbol']: ContainerSet(G['symbol'] , contains_epsilon=False), + G['ε']: ContainerSet(G['ε'] , contains_epsilon=False), + G['E']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['T']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['F']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G['ε'], G['symbol'], G['('] , contains_epsilon=False), + G['X']: ContainerSet(G['|'] , contains_epsilon=True), + G['Y']: ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=True), + G['Z']: ContainerSet(G['*'] , contains_epsilon=True), + Sentence(G['T'], G['X']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['|'], G['E']): ContainerSet(G['|'] , contains_epsilon=False), + G.Epsilon: ContainerSet( contains_epsilon=True), + Sentence(G['F'], G['Y']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['T']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['A'], G['Z']): ContainerSet(G['symbol'], G['ε'], G['('] , contains_epsilon=False), + Sentence(G['*']): ContainerSet(G['*'] , contains_epsilon=False), + Sentence(G['symbol']): ContainerSet(G['symbol'] , contains_epsilon=False), + Sentence(G['ε']): ContainerSet(G['ε'] , contains_epsilon=False), + Sentence(G['('], G['E'], G[')']): ContainerSet(G['('] , contains_epsilon=False) + } + + @property + def follows(self): + G = self.G + return { + G['E']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['T']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), + G['F']: ContainerSet(G[')'], G.EOF, G['symbol'], G['|'], G['ε'], G['('] , contains_epsilon=False), + G['A']: ContainerSet(G.EOF, G['|'], G['*'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False), + G['X']: ContainerSet(G[')'], G.EOF , contains_epsilon=False), + G['Y']: ContainerSet(G[')'], G.EOF, G['|'] , contains_epsilon=False), + G['Z']: ContainerSet(G.EOF, G['|'], G['('], G[')'], G['symbol'], G['ε'] , contains_epsilon=False) + } + + @property + def table(self): + G = self.G + return { + ( G['E'], G['symbol'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['ε'], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['E'], G['('], ): [ Production(G['E'], Sentence(G['T'], G['X'])), ], + ( G['X'], G['|'], ): [ Production(G['X'], Sentence(G['|'], G['E'])), ], + ( G['X'], G[')'], ): [ Production(G['X'], G.Epsilon), ], + ( G['X'], G.EOF, ): [ Production(G['X'], G.Epsilon), ], + ( G['T'], G['symbol'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['ε'], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['T'], G['('], ): [ Production(G['T'], Sentence(G['F'], G['Y'])), ], + ( G['Y'], G['symbol'], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G['ε'], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G['('], ): [ Production(G['Y'], Sentence(G['T'])), ], + ( G['Y'], G[')'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G.EOF, ): [ Production(G['Y'], G.Epsilon), ], + ( G['Y'], G['|'], ): [ Production(G['Y'], G.Epsilon), ], + ( G['F'], G['symbol'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['F'], G['ε'], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['F'], G['('], ): [ Production(G['F'], Sentence(G['A'], G['Z'])), ], + ( G['Z'], G['*'], ): [ Production(G['Z'], Sentence(G['*'])), ], + ( G['Z'], G.EOF, ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['|'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['('], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G[')'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['symbol'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['Z'], G['ε'], ): [ Production(G['Z'], G.Epsilon), ], + ( G['A'], G['symbol'], ): [ Production(G['A'], Sentence(G['symbol'])), ], + ( G['A'], G['ε'], ): [ Production(G['A'], Sentence(G['ε'])), ], + ( G['A'], G['('], ): [ Production(G['A'], Sentence(G['('], G['E'], G[')'])), ] + } + + @property + def parser(self): + firsts = self.firsts + follows = self.follows + M = build_parsing_table(self.G, firsts, follows) + parser = metodo_predictivo_no_recursivo(self.G, M) + return parser \ No newline at end of file diff --git a/src/cool_cmp/cmp/nbpackage.py b/src/cool_cmp/cmp/nbpackage.py new file mode 100644 index 000000000..5458e63b9 --- /dev/null +++ b/src/cool_cmp/cmp/nbpackage.py @@ -0,0 +1,87 @@ +import io, os, sys, types + +from IPython import get_ipython +from nbformat import read +from IPython.core.interactiveshell import InteractiveShell + +def find_notebook(fullname, path=None): + """find a notebook, given its fully qualified name and an optional path + + This turns "foo.bar" into "foo/bar.ipynb" + and tries turning "Foo_Bar" into "Foo Bar" if Foo_Bar + does not exist. + """ + name = fullname.rsplit('.', 1)[-1] + if not path: + path = [''] + for d in path: + nb_path = os.path.join(d, name + ".ipynb") + if os.path.isfile(nb_path): + return nb_path + # let import Notebook_Name find "Notebook Name.ipynb" + nb_path = nb_path.replace("_", " ") + if os.path.isfile(nb_path): + return nb_path + +class NotebookLoader(object): + """Module Loader for Jupyter Notebooks""" + def __init__(self, path=None): + self.shell = InteractiveShell.instance() + self.path = path + + def load_module(self, fullname): + """import a notebook as a module""" + path = find_notebook(fullname, self.path) + + print ("importing Jupyter notebook from %s" % path) + + # load the notebook object + with io.open(path, 'r', encoding='utf-8') as f: + nb = read(f, 4) + + + # create the module and add it to sys.modules + # if name in sys.modules: + # return sys.modules[name] + mod = types.ModuleType(fullname) + mod.__file__ = path + mod.__loader__ = self + mod.__dict__['get_ipython'] = get_ipython + sys.modules[fullname] = mod + + # extra work to ensure that magics that would affect the user_ns + # actually affect the notebook module's ns + save_user_ns = self.shell.user_ns + self.shell.user_ns = mod.__dict__ + + try: + for cell in nb.cells: + if cell.cell_type == 'code': + # transform the input to executable Python + code = self.shell.input_transformer_manager.transform_cell(cell.source) + # run the code in themodule + exec(code, mod.__dict__) + finally: + self.shell.user_ns = save_user_ns + return mod + +class NotebookFinder(object): + """Module finder that locates Jupyter Notebooks""" + def __init__(self): + self.loaders = {} + + def find_module(self, fullname, path=None): + nb_path = find_notebook(fullname, path) + if not nb_path: + return + + key = path + if path: + # lists aren't hashable + key = os.path.sep.join(path) + + if key not in self.loaders: + self.loaders[key] = NotebookLoader(path) + return self.loaders[key] + +sys.meta_path.append(NotebookFinder()) \ No newline at end of file diff --git a/src/cool_cmp/cmp/pycompiler.py b/src/cool_cmp/cmp/pycompiler.py new file mode 100644 index 000000000..fa0a71df9 --- /dev/null +++ b/src/cool_cmp/cmp/pycompiler.py @@ -0,0 +1,532 @@ +import json + +class Symbol(object): + + def __init__(self, name, grammar): + self.Name = name + self.Grammar = grammar + + def __str__(self): + return self.Name + + def __repr__(self): + return repr(self.Name) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(self, other) + + raise TypeError(other) + + def __or__(self, other): + + if isinstance(other, (Sentence)): + return SentenceList(Sentence(self), other) + + raise TypeError(other) + + @property + def IsEpsilon(self): + return False + + def __len__(self): + return 1 + + def __hash__(self): + return hash(self.Name) + + def __eq__(self,value): + return isinstance(value,Symbol) and value.Name == self.Name + +class NonTerminal(Symbol): + + + def __init__(self, name, grammar): + super().__init__(name, grammar) + self.productions = [] + + + def __imod__(self, other): + + if isinstance(other, (Sentence)): + p = Production(self, other) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, tuple): + assert len(other) > 1 + + if len(other) == 2: + other += (None,) * len(other[0]) + + assert len(other) == len(other[0]) + 2, "Debe definirse una, y solo una, regla por cada símbolo de la producción" + # assert len(other) == 2, "Tiene que ser una Tupla de 2 elementos (sentence, attribute)" + + if isinstance(other[0], Symbol) or isinstance(other[0], Sentence): + p = AttributeProduction(self, other[0], other[1:]) + else: + raise Exception("") + + self.Grammar.Add_Production(p) + return self + + if isinstance(other, Symbol): + p = Production(self, Sentence(other)) + self.Grammar.Add_Production(p) + return self + + if isinstance(other, SentenceList): + + for s in other: + p = Production(self, s) + self.Grammar.Add_Production(p) + + return self + + raise TypeError(other) + + @property + def IsTerminal(self): + return False + + @property + def IsNonTerminal(self): + return True + + @property + def IsEpsilon(self): + return False + +class Terminal(Symbol): + + def __init__(self, name, grammar): + super().__init__(name, grammar) + + @property + def IsTerminal(self): + return True + + @property + def IsNonTerminal(self): + return False + + @property + def IsEpsilon(self): + return False + +class EOF(Terminal): + + def __init__(self, Grammar): + super().__init__('$', Grammar) + +class Sentence(object): + + def __init__(self, *args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + + def __len__(self): + return len(self._symbols) + + def __add__(self, other): + if isinstance(other, Symbol): + return Sentence(*(self._symbols + (other,))) + + if isinstance(other, Sentence): + return Sentence(*(self._symbols + other._symbols)) + + raise TypeError(other) + + def __or__(self, other): + if isinstance(other, Sentence): + return SentenceList(self, other) + + if isinstance(other, Symbol): + return SentenceList(self, Sentence(other)) + + raise TypeError(other) + + def __repr__(self): + return str(self) + + def __str__(self): + return ("%s " * len(self._symbols) % tuple(self._symbols)).strip() + + def __iter__(self): + return iter(self._symbols) + + def __getitem__(self, index): + return self._symbols[index] + + def __eq__(self, other): + return self._symbols == other._symbols + + def __hash__(self): + return self.hash + + @property + def IsEpsilon(self): + return False + +class SentenceFromIter(Sentence): + def __init__(self,args): + self._symbols = tuple(x for x in args if not x.IsEpsilon) + self.hash = hash(self._symbols) + +class SentenceList(object): + + def __init__(self, *args): + self._sentences = list(args) + + def Add(self, symbol): + if not symbol and (symbol is None or not symbol.IsEpsilon): + raise ValueError(symbol) + + self._sentences.append(symbol) + + def __iter__(self): + return iter(self._sentences) + + def __or__(self, other): + if isinstance(other, Sentence): + self.Add(other) + return self + + if isinstance(other, Symbol): + return self | Sentence(other) + + +class Epsilon(Terminal, Sentence): + + def __init__(self, grammar): + super().__init__('epsilon', grammar) + + + def __str__(self): + return "e" + + def __repr__(self): + return 'epsilon' + + def __iter__(self): + yield from () + + def __len__(self): + return 0 + + def __add__(self, other): + return other + + def __eq__(self, other): + return isinstance(other, (Epsilon,)) + + def __hash__(self): + return hash("") + + @property + def IsEpsilon(self): + return True + +class Production(object): + + def __init__(self, nonTerminal, sentence): + + self.Left = nonTerminal + self.Right = sentence + + def __str__(self): + + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + def __eq__(self, other): + return isinstance(other, Production) and self.Left == other.Left and self.Right == other.Right + + def __hash__(self): + return hash((self.Left, self.Right)) + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + +class AttributeProduction(Production): + + def __init__(self, nonTerminal, sentence, attributes): + if not isinstance(sentence, Sentence) and isinstance(sentence, Symbol): + sentence = Sentence(sentence) + super(AttributeProduction, self).__init__(nonTerminal, sentence) + + self.attributes = attributes + + def __str__(self): + return '%s := %s' % (self.Left, self.Right) + + def __repr__(self): + return '%s -> %s' % (self.Left, self.Right) + + def __iter__(self): + yield self.Left + yield self.Right + + + @property + def IsEpsilon(self): + return self.Right.IsEpsilon + + # sintetizar en ingles??????, pending aggrement + def syntetice(self): + pass + +class Grammar(): + + def __init__(self): + + self.Productions = [] + self.nonTerminals = [] + self.terminals = [] + self.startSymbol = None + # production type + self.pType = None + self.Epsilon = Epsilon(self) + self.EOF = EOF(self) + + self.symbDict = { '$': self.EOF } + + def NonTerminal(self, name, startSymbol = False): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = NonTerminal(name,self) + + if startSymbol: + + if self.startSymbol is None: + self.startSymbol = term + else: + raise Exception("Cannot define more than one start symbol.") + + self.nonTerminals.append(term) + self.symbDict[name] = term + return term + + def NonTerminals(self, names): + + ans = tuple((self.NonTerminal(x) for x in names.strip().split())) + + return ans + + + def Add_Production(self, production): + + if len(self.Productions) == 0: + self.pType = type(production) + + assert type(production) == self.pType, "The Productions most be of only 1 type." + + production.Left.productions.append(production) + self.Productions.append(production) + + + def Terminal(self, name): + + name = name.strip() + if not name: + raise Exception("Empty name") + + term = Terminal(name, self) + self.terminals.append(term) + self.symbDict[name] = term + return term + + def Terminals(self, names): + + ans = tuple((self.Terminal(x) for x in names.strip().split())) + + return ans + + + def __str__(self): + + mul = '%s, ' + + ans = 'Non-Terminals:\n\t' + + if self.nonTerminals: + nonterminals = mul * (len(self.nonTerminals)-1) + '%s\n' + + ans += nonterminals % tuple(self.nonTerminals) + else: + ans += '\n' + + ans += 'Terminals:\n\t' + + if self.terminals: + terminals = mul * (len(self.terminals)-1) + '%s\n' + + ans += terminals % tuple(self.terminals) + else: + ans += '\n' + + ans += 'Productions:\n\t' + + ans += str(self.Productions) + + return ans + + def __getitem__(self, name): + try: + return self.symbDict[name] + except KeyError: + return None + + @property + def to_json(self): + + productions = [] + + for p in self.Productions: + head = p.Left.Name + + body = [] + + for s in p.Right: + body.append(s.Name) + + productions.append({'Head':head, 'Body':body}) + + d={'NonTerminals':[symb.Name for symb in self.nonTerminals], 'Terminals': [symb.Name for symb in self.terminals],\ + 'Productions':productions} + + # [{'Head':p.Left.Name, "Body": [s.Name for s in p.Right]} for p in self.Productions] + return json.dumps(d) + + @staticmethod + def from_json(data): + data = json.loads(data) + + G = Grammar() + dic = {'epsilon':G.Epsilon} + + for term in data['Terminals']: + dic[term] = G.Terminal(term) + + for noTerm in data['NonTerminals']: + dic[noTerm] = G.NonTerminal(noTerm) + + for p in data['Productions']: + head = p['Head'] + dic[head] %= Sentence(*[dic[term] for term in p['Body']]) + + return G + + def copy(self): + G = Grammar() + G.Productions = self.Productions.copy() + G.nonTerminals = self.nonTerminals.copy() + G.terminals = self.terminals.copy() + G.pType = self.pType + G.startSymbol = self.startSymbol + G.Epsilon = self.Epsilon + G.EOF = self.EOF + G.symbDict = self.symbDict.copy() + + return G + + @property + def IsAugmentedGrammar(self): + augmented = 0 + for left, right in self.Productions: + if self.startSymbol == left: + augmented += 1 + if augmented <= 1: + return True + else: + return False + + def AugmentedGrammar(self, force=False): + if not self.IsAugmentedGrammar or force: + + G = self.copy() + # S, self.startSymbol, SS = self.startSymbol, None, self.NonTerminal('S\'', True) + S = G.startSymbol + G.startSymbol = None + SS = G.NonTerminal('S\'', True) + if G.pType is AttributeProduction: + SS %= S + G.Epsilon, lambda x : x + else: + SS %= S + G.Epsilon + + return G + else: + return self.copy() + #endchange + +class Item: + + def __init__(self, production, pos, lookaheads=[]): + self.production = production + self.pos = pos + self.lookaheads = frozenset(look for look in lookaheads) + + def __str__(self): + s = str(self.production.Left) + " -> " + if len(self.production.Right) > 0: + for i,c in enumerate(self.production.Right): + if i == self.pos: + s += "." + s += str(self.production.Right[i]) + ' ' + if self.pos == len(self.production.Right): + s += "." + else: + s += "." + s += ", " + str(self.lookaheads)[10:-1] + return s + + def __repr__(self): + return str(self) + + + def __eq__(self, other): + return ( + (self.pos == other.pos) and + (self.production == other.production) and + (set(self.lookaheads) == set(other.lookaheads)) + ) + + def __hash__(self): + return hash((self.production,self.pos,self.lookaheads)) + + def __getitem__(self,pos): + return self.production.Right[pos] + + @property + def IsReduceItem(self): + return len(self.production.Right) == self.pos + + @property + def NextSymbol(self): + if self.pos < len(self.production.Right): + return self.production.Right[self.pos] + else: + return None + + def NextItem(self): + if self.pos < len(self.production.Right): + return Item(self.production,self.pos+1,self.lookaheads) + else: + return None + + def Preview(self, skip=1): + unseen = self.production.Right[self.pos+skip:] + return [ unseen + (lookahead,) for lookahead in self.lookaheads ] + + def Center(self): + return Item(self.production, self.pos) \ No newline at end of file diff --git a/src/cool_cmp/cmp/semantic.py b/src/cool_cmp/cmp/semantic.py new file mode 100644 index 000000000..f92ea87e5 --- /dev/null +++ b/src/cool_cmp/cmp/semantic.py @@ -0,0 +1,227 @@ +import itertools as itt +from collections import OrderedDict + + +class SemanticError(Exception): + @property + def text(self): + return self.args[0] + +class Attribute: + def __init__(self, name, typex): + self.name = name + self.type = typex + + def __str__(self): + return f'[attrib] {self.name} : {self.type.name};' + + def __repr__(self): + return str(self) + +class Method: + def __init__(self, name, param_names, params_types, return_type): + self.name = name + self.param_names = param_names + self.param_types = params_types + self.return_type = return_type + + def __str__(self): + params = ', '.join(f'{n}:{t.name}' for n,t in zip(self.param_names, self.param_types)) + return f'[method] {self.name}({params}): {self.return_type.name};' + + def __eq__(self, other): + return other.name == self.name and \ + other.return_type == self.return_type and \ + other.param_types == self.param_types + +class Type: + def __init__(self, name:str): + self.name = name + self.attributes = [] + self.methods = [] + self.parent = None + + def set_parent(self, parent): + if self.parent is not None: + raise SemanticError(f'Parent type is already set for {self.name}.') + self.parent = parent + + def get_attribute(self, name:str): + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') + try: + return self.parent.get_attribute(name) + except SemanticError: + raise SemanticError(f'Attribute "{name}" is not defined in {self.name}.') + + def define_attribute(self, name:str, typex): + try: + self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + raise SemanticError(f'Attribute "{name}" is already defined in {self.name}.') + + def get_method(self, name:str): + try: + return next(method for method in self.methods if method.name == name) + except StopIteration: + if self.parent is None: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + try: + return self.parent.get_method(name) + except SemanticError: + raise SemanticError(f'Method "{name}" is not defined in {self.name}.') + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if name in (method.name for method in self.methods): + raise SemanticError(f'Method "{name}" already defined in {self.name}') + + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def all_attributes(self, clean=True): + plain = OrderedDict() if self.parent is None or self.parent == self else self.parent.all_attributes(False) + for attr in self.attributes: + plain[attr.name] = (attr, self) + return plain.values() if clean else plain + + def all_methods(self, clean=True): + return self._all_methods(clean, set()) + + def _all_methods(self, clean:bool, visited_types:set): + if self.parent is None or self.parent == self or self in visited_types: + plain = OrderedDict() + else: + visited_types.add(self) + plain = self.parent._all_methods(False, visited_types) + for method in self.methods: + plain[method.name] = (method, self) + return plain.values() if clean else plain + + def conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.conforms_to(other) + + def bypass(self): + return False + + def __str__(self): + output = f'type {self.name}' + parent = '' if self.parent is None else f' : {self.parent.name}' + output += parent + output += ' {' + output += '\n\t' if self.attributes or self.methods else '' + output += '\n\t'.join(str(x) for x in self.attributes) + output += '\n\t' if self.attributes else '' + output += '\n\t'.join(str(x) for x in self.methods) + output += '\n' if self.methods else '' + output += '}\n' + return output + + def __repr__(self): + return str(self) + +class ErrorType(Type): + def __init__(self): + Type.__init__(self, '') + + def conforms_to(self, other): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + +class VoidType(Type): + def __init__(self): + Type.__init__(self, '') + + def conforms_to(self, other): + raise Exception('Invalid type: void type.') + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, VoidType) + +class IntType(Type): + def __init__(self): + Type.__init__(self, 'int') + + def __eq__(self, other): + return other.name == self.name or isinstance(other, IntType) + +class Context: + def __init__(self): + self.types = {} + + def create_type(self, name:str): + if name in self.types: + raise SemanticError(f'Type with the same name ({name}) already in context.') + typex = self.types[name] = Type(name) + return typex + + def get_type(self, name:str): + try: + return self.types[name] + except KeyError: + raise SemanticError(f'Type "{name}" is not defined.') + + def __str__(self): + return '{\n\t' + '\n\t'.join(y for x in self.types.values() for y in str(x).split('\n')) + '\n}' + + def __repr__(self): + return str(self) + +class VariableInfo: + def __init__(self, name, vtype): + self.name = name + self.type = vtype + + def __str__(self): + return str(self.name) + " -> " + str(self.type) + + def __repr__(self): + return str(self) + +class Scope: + def __init__(self, parent=None): + self.locals = [] + self.parent = parent + self.children = [] + self.index = 0 if parent is None else len(parent) + + def __len__(self): + return len(self.locals) + + def create_child(self): + child = type(self)(self) + self.children.append(child) + return child + + def define_variable(self, vname, vtype): + info = VariableInfo(vname, vtype) + self.locals.append(info) + return info + + def find_variable(self, vname, index=None): + locals = self.locals if index is None else itt.islice(self.locals, index) + try: + return next(x for x in locals if x.name == vname) + except StopIteration: + return self.parent.find_variable(vname, self.index) if not self.parent is None else None + + def is_defined(self, vname): + return self.find_variable(vname) is not None + + def is_local(self, vname): + return any(True for x in self.locals if x.name == vname) diff --git a/src/cool_cmp/cmp/tools/__init__.py b/src/cool_cmp/cmp/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cmp/tools/automata.py b/src/cool_cmp/cmp/tools/automata.py new file mode 100644 index 000000000..2ad7b848a --- /dev/null +++ b/src/cool_cmp/cmp/tools/automata.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJzNWN1um0gUvucp6BWwRSjx1SrSrBRt4iR20rRJW9VCCI1hbE+LgTBDGjvKY+1r7DPtmR9gjIm3q+5KexPDzPn9zjdnDuGIEW4xVOF8SawHtMIMc15ZZ2hKNudVVVTWNcJZZm0QZTRnHOcJsQiiObeWKCO5tUIfNyVRojka44wRa4o+VjWxPiOcbyyMtrS0OEckr9ekwhz2tUBZIl6XGbFYEwGvNieWTddlUXG73KQFt8hTQkpuX8k16QckSsyYtaiKtZ2sy6DmNGON1u9FzjHNSXUPmSUZCNrvxqegk5KFHcc0pzyOXUayhQ/pcML8Bc0hbJ9DCIxyWuRM7FQcHXmgZgvRQIki9WMsgpT82ywpW4i76sFr1tcYcu0cNMuPRYLndYarDai0woYget6ePL8sisre2jS3masi8F5AFlbdU3/u+bdiy1AKKCdr5srobQCAACwP7q3vQPqcVHHseL5zlT/ijKZ2UmQZSYSeXSxsZd4Riv1QwtMonEfott3rgg9wmrpzbz+rIKUswVXqOo6nKkBKRrMijw3DRjFkyDpiuSCT7gXSxS5FRLCKN7ZdEV5X+xqhFIxCx4lASjPqzNBwdXTLCpcrGY+M5AJJDgZnBXfB2reUVsi5vnP8Na6WNEdHwbFI+kLkH+dFSlwl/048OpIYjs9WuCTIKTNgJSdPsJLhOcmQ4/jfacpX6MhfEbpcCb55uqyZT3VZG/bs1JQi588/HJsu4Ans2AROnU3FznAoWRNEQqskIxAT32TwOi+yVJrJWleKt8oiFE0EJCKyx0LiVnp/xcn475yMDzrRVkm6bKyei8fMH2u8qPoFRskuhEZeh31fq8W+PaYd6DqsFLMVSZVzTZsL3SQqUlYxe1zGHROGCKbI4gVJRYBdQgFeUpLI4td88avgvGabVJZdS7Wks/GpC23J+4m+pI/Jtbtx4TTUxCeeKJR87jcEuQjs8Uy9JRzZ345kdaGN9FQ8mbTRh76RzUko7URCA179QVeap6JBQYLBP8qs7SBJXVUkb3urhGhdPBJtZbMGUkkQgFbqzc4LPtQsQtNeZNYw33N2UDVUfqLwKOoYM20ZA/dox5Z9s0YiFTBkmdNtkwyvaL7s1LQt3QnsRCYlZdTRX8hMlaiEJFE9wUzLZKkOo3f2LBGJVMc1L9aYF3lTnA7dG3UpdbePFBDeUtSq7SC2jYyzcovSBrR+171FMsGboC5TsOnewpsO+sYyr4kkK1hd7UcpwpuhkMngWBcceHpCz3vLwMbvK5oReybcb9EsKItShjBwHxm5Dd1W26Y0F8L+gERTp4uGk0+qQE/ymrxQ3W4W4LIkuXrXqZuji/vLkyeRyBc45kWcLnAHgsg+Qc+QVYZeRyrs8pD0i8BTFtAUHclfFksqoM+uBKoT1t25hTADvQkKRRVn6ucVLIXGfNdWNwpIDG5Qj3NbX44N9uWBPG48g/iXCssEoKI5zJBq57KBeqK2L0WaS3fiNW8/nOylUpk05bnslUu9i5tLeSrQJKB5Sp4ayUs0CQtB+PYc2Em4hXj8uVxt+m/ejTFwGbx580YOXTunpFNEIiHLvkdyoTuRE5H8tk0PHLxH4moRqfv3ftJx670kk84bx3UOTHXxsY9HJpmAGekxOoa/I4SP9dT7NoWFGuFR+z6yesMnyPZmlCQ8BT0R+vMYHowZ4mVPeTSoPGqUR7vKSZj5MMihUAVYceFHBSeeR5HqWOmTfy+tuyHsw7IvFPTNA+LqKZL+WjzvT3YK9wVBBd6CJTU49qpj7urx3f4iz3gtT0wHYAfdSBTxuX5p6wJ3pDsRpfIzb7dEQPEEdHLMD5Tq6H9dqhbXFnlzltL4HfsDY7m5p7FV0BqFNq+mtqADDkYHHIz2HPw7tWua2PHg6ap7FfupCg2ehzr6T9CvjUJ03nqIHcZp+Kv9jLKvBXwfiY92gaSY8mHkqSlbxcqse+d3V8JUwPJJwnqOytIdunA0PWqBwJ1Ia/bK0FKr8VigcI1cdxYyMeSJyVKoztRnyrsiV/O1XDwXOEyEZ3caplEgvhhgbIPrm9NHIppyKsSmgfhIYj0LcuvaM2rxKZxEzQWjo/H6NREyyIhVYRveySTvhMlP7ZgfSQwlbvEa5u813eouYk4QU2Sg7v7CmLszMIgpC6KYBmtSwSeVcUf2b89hqSF7ElR9VQ9YUXPFdCo5/0PRddlP4XusqEs1fYnVlVj9ER6Ji1aHv/LUN8USpmoEA4Ten8MX3jd4mKLE6kb/nRN/COaDhbDsq505dtojE5Nj17PuptRv/y3CuXslw3tUDlT1NSRj/3oXY5Pwj9HOfxPmaBpeA+P7NBZ7X9GVHm/UnNZejbOQ+uPdgWb/hlRC6Ktlf0AhHUyAap4G7cdknxfg5KGNYro31PaC7iYeNQddef4Hf+Y/eNZffhu9yA=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cool_cmp/cmp/tools/evaluation.py b/src/cool_cmp/cmp/tools/evaluation.py new file mode 100644 index 000000000..591a58f13 --- /dev/null +++ b/src/cool_cmp/cmp/tools/evaluation.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJxdUMFuwjAMvecrfGy3qoLrJN86YGViCO2GECrF1SLSpErcqf37OUWwsZPtZ/v5+TXetVC3Xd6NtWs7bciDbjvnGV4/FmqJmsmrE1oaWFnUQdvAla1JFbhxltQaDVm1QLJ9S75iUmdqgL4r00tx7CofKGmyMn1RoBuwjqEB56ekFAw8ce+tggaXSZMqKCWWEge8kSQnaWSRQ0EVAok2K1iZ5uwuZI88dpSJWmlfyWB4EJF03p37mrWzkSXT9ou8/HU+xgHCImrbZAZ/5xSMf6q8Yvb61DMFBYz74vCUrBOTPs/l5OV/vZ8d8N8J+U5e1tkOtIVFYrJ5PBn92OVv4ZN8q21lInR78LLXBx2giBBLjtO/hgYByASaZld4miy7b+0QV/k7NRyxLY6yGDO5swVhi54X0+bEj9vkknF6P3H3azXZFEekGWlmh7u1150HxkmQSP0BhJm25Q=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cool_cmp/cmp/tools/parsing.py b/src/cool_cmp/cmp/tools/parsing.py new file mode 100644 index 000000000..34d472eb7 --- /dev/null +++ b/src/cool_cmp/cmp/tools/parsing.py @@ -0,0 +1,16 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVVtr2zAUfvevEH2yqWfa14AeypKGlXlNL5SCMUZO5FTMlhRZbpZu++87ujiOm3QwGJRU56pzvu8cuVKiQUxTpYWoW8QaKZRGrK3ZkgaVMS4bmXSaDcbPgmvCOFUPVAcrWqGlaGSnaVGLJamLiqlWh/a3jUktX0g0CVCFnSZAEltlgKb4MFMYBUirHbiiBZbJl3YmW1YLHiD6Y0mldoZrUrc0QKxCC6OYJi3VBXWeJgMFszFUQqE5YhxJI6EUV9k8N6dp0skV0TRMIyNCIi40SpOlK6Xtk9kwVCpKvsOpT3t8oaK6UxxNR0C4VsO5a/zn7wDN8KPqoHBTV2nqmieAecM49GPrzcp8DEcZOW/tvLngj+MAnR/ht31hNUUzY5/1UNkkty7JQolVt9RMcJsDPePb5CuttDlLON+z9YsVrgCvZ4uXpwQ6B5W0qoGPXntUCEI3+ORUxNJaZ7/wNHkhalV4Nm569dWR2iNcjREWdS22AHHssB6P2GaEObXSX7DcnMJyk82TVhOlH3ZNKep3DvNkdnv9PxG/xxuPuIlmcbszCSjvGqoMEjJygMPAtjvYjm9DD86A7iBDu8udsKcN8pWYZjJm3nLI3oHxA7rcQxCCx/llDHfSKHKRQNVdv0pV6ZVQXFV+sErjkPuB2I0ltuxYvSokUS3j60KTsqZ7cmPP9pjkCo5OH8B+9xSTk7g/Y9LDvoBjj7oJoCagyhb5ZDTuafYc0zwhUlK+Ckn0fvCdHWfEwGr6hgynOx8uMTvlogd6Tt0z5ujwJg9ZaiFrqBYrUUhFVwxafRUFF4Wiyw4wfBWAXooNYx5Ef3aIWcHCyQY8xYAnNJTCRwAZt4lvkB0qTODRa+cdxdhR4FNLa5xT/BHrUCc42CbDrZ38J5zZnYvHWwmWpsEX8O8NZ0ZyC2kW396+xk+JFNK9SQRvs6bJ/bu/hi0ar5BRYkwm+2EGyV7aT3D/OUAHXwRkKjjHl8E7rVSM6/BsppRQCboq4csJPSZJcuaXxXNpgApGocNwLHCarWOSZxd+ee3bYGZJEb6mYU15uHDTHH26jO1f1Ff11A+V98hY7m9+21tOjNs/1u2lt/1sNsEfuhaMXQ=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +deprecated_metodo_predictivo_no_recursivo = metodo_predictivo_no_recursivo +def metodo_predictivo_no_recursivo(G, M=None, firsts=None, follows=None): + parser = deprecated_metodo_predictivo_no_recursivo(G, M, firsts, follows) + def updated(tokens): + return parser([t.token_type for t in tokens]) + return updated + +exec(zlib.decompress(base64.b64decode('eJx9U8GO2jAQvfMVZi9JtCFarqiuVLUsRUilWranCEUmGcBaY0e2s3TV7b/X9iQhpaiXxJ4Zv3nzZqYUzBiyOfK9fYKqKeE70wb0bEQ2X5ePzzQKv2hEnuZffnye0wj/zrBe0Wi9cocK9qQouOS2KGIDYp8u0lfQO2WAPjJhIHFoxDuyBV10xy6i/XdmVlquJP31uzMclFWDa7FruKiK2rHk8lBYthMQJy2JWz7/KhDQjBsg35RdnmoBJ5AWqrnWSvfPi5IJ0dVwTg9gC+OFKXRQZliMZeULzR+27lw22ihNH9xRNbZuLM29WdWgma/F4P185ALIs27AA3gECzTg5JOpDyBCqRd2BFbRc46gwcz3fwk2qzWXNg4v0+jDZDJ5f3efj1HavZptE3wXhyRpj5tIZQmXQ6EDF4KQ/4QnA+ddkCojn3ZKW6dulmV36NdgGy2dsNI3kSBuatmBDvLkV9hdZW27MTSMGjK6qJexugZZxZcITBsEuKd5D+lTBti2I/d06m8grtPgBP83D4ZgImxq53ZJ0BxS7lT1Rp0pWPZKE/N22inhRdbgGmagin1MgtmQdFarOkYQ4pYPtB3aHcmA0RV5PSUkLES/Gq2wvaa9LoGfj9jeVmG9mo1uUbrJKOxu5mzabi7s2lABEsfRRU6HI4HK+Tb7wbteJ8fJQIwx6aUPCdI1uCbt1s5/llB7dxwt5SsTvGqLGY/HUTL6AyImjec='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) + +exec(zlib.decompress(base64.b64decode('eJyFVltP4zoQfu+v8D41OcfHWl6RLJ0KekEgqLg+dKtiGrf1ktiR7RS6iP9+ZuykSYE9ywOKLzPzzTffjLuypiDLomSVV7kjqiiN9eTEaC+UlvZG+t6queKNyR0rhXVKr5urS1OUlZeLlbLOO9osc7MUedxsHZQ7PFa5tI31mZdFL5MrIl9LobMkozo97pEdz9ilfPU3u+LJ5D2iVmRHlCOXRktiLNHGkx07c7C+lbZQWuRgRaz0ldWzeY/c824KSdojKzAbEqVJxqZWbpV8STASeeZfQE40HYINuWdVmQkvk2dYCeckQMbY92wZ3buFLJ3Kje41wTGjpLQmo9/pfYpRcYGBdwy/qqVXRrt5yBpDW+lcMkAsOX97j0DD/QHCWwETJ1J7aTEJ4u0OdyG/fLaCPIG3pSw9OZe7obXGhkM84vfcxcTbJDKWG/MsNlJkLm0AvwXArx1sFBbGUTR/TkMGr/QZAeVMwV2XpO8RfG5cZYE3e5QMYt0mh7T/NYAwV/zWVrJHXjZQeHKFCK/4SOQO9oj4VKc2/0lIRjDQgQRpdBSSBh+TJi+xT6YldJIGjGvjTQ1wSqNEOYqI/qycXzxLq2UewSD8usKdMxRbNEP5YemDdf8xbj6SAu6SJ4lF3qpMZijVx0/OH/s9MuDQB7+kRl6jugPzaVtvtO3qnvNpm1k47SKT4PdDDSKotG04UXlTCC+adrvxwBctqhyaHThfQGw4BnEFsp4qlWeLi+ujRW1ndDLu8JJLWDPnha0BdgWdcn5E+2MrikLYPS2iWheo3gwI0PxwVoBv2JyN2fBqND/UQdiD0zP+23iz7yB/wwOHZ9BrrbR5NKcoE98hfWbmKUq0y5kHNQHFPBCTtHcnKUXVwtmWzzxE2vA3f2zfGxlvUZsXfAudUgbV3vHN7GJey3eK5RwzX48m9/eY6XZSuaDrQxwXAQcha75X7AQU2xVSjYegDlCI6+CG4CBSGhusnQ7kBdCsEc2X8+FD7HUdu7b6Hy7gb8tEWWI7rsP6joksW3grtFNYlmTKLkUh6QuyysC6lVjyhexaeds/PDM3G7Xy1xKqL6dwAopd5iBLAmqN6+TTDVQuynoRdV07XHjxlMvkIQz/MX9gYzZoRFqrN2nStfzrlqjLrOgpFlrqqpAWOQshQ4Ee2FbaJ+PkcWmV9omi/R++D//0D0/67KdROnHeJq9xvqKbU1S6lyle6gdyT5nKXrmqo4VYsYCShyP83E+P2jwWOAySMxfZwBaJ26SE16TtobgHd0t2IVeeHzZbbQKpLKxcK4clfGAiPhGJpLFHKexdnVOcimlUSBhMjfG+G7pvT3P4W9fT4PZ6eHp3MqRl7bfjdvrh5wEJnXPK1qDWKMC04SfkNwUuur8T/hz7ZnI2uqXrr1I6NMR2rc2wI/7FIqhlIf3GZLX89rdHFIgKEqkH6nloZGBnhO/MaHY+5/yS9oOS/4nFw4P41WxAw69ytfTfvn2DoRqtLnv/ATLgLos='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cool_cmp/cmp/tools/regex.py b/src/cool_cmp/cmp/tools/regex.py new file mode 100644 index 000000000..d272ad86c --- /dev/null +++ b/src/cool_cmp/cmp/tools/regex.py @@ -0,0 +1,3 @@ +import zlib, base64 +exec(zlib.decompress(base64.b64decode('eJytVsFu2zgQvesreFhDVE0IdY8BCNTZtVRg2yyaOKgdwxAYiYrZSKRK0qnttp+1v7HftCQlWbLWTXPYgwzyzXDem9Fw5FyKEqRlFRKlASsrITWYalGy9EpkFF0yTuTeLW/blZe3Z6p9KsqKFVS2R2NJypLIzkULUaiQbE1IoknjBv+IpujKPC2epIVQW0l7gOAp0ZQTzQTv4JJxVrLDAN1yu+U5SbRIspwEQ376RIqtO9QKbRCaVEQqOvS3IOMPrXNJtchEUkmasVSzJ5FwkUiabo3Xk+gObzUrVHtoLh4p975gk6uXFkQpMKsUKwS3NYRdjYMLD2Q0PyqCiha5BYGkeis5+AKVNrjCE5Sb11EovHq9RloSrphNSeFvPwJP4l74hvBmX96L4sV8CttlWNDdGfI3R/LJgBy+Riq4mBgNKe4YGwm/1y/WaTh2kGV7a+Oy1JR2I7JakaiotIKsMNqvwLBNGg/vI+6FbwhvbS84uq53f8FXuHBI/pzXNdjAz7vGR642Wde0/zf5yVUYiogi3LF6NrCkD3RnLoLpPnagEmq60yhG6pFVydcNM++yIql5oXNZ823wau2BOMbfdheuZ+EOxavdOsiFBDvA+Mr/7iP/lXmgeQLz/PO3v/7hAetwMA7AUljlLAdDGkB4Bg4hU24LXYLAZKQZ31Kz1nLvoM84jlcHIwTQXUorDf6k+5mUQjbWWtnBKPOV6zF/HRiL68miDrEJSVVRnsHPxnLc1Af933wUh7O/osDYmgJvXLnut6zIkod6bjl9MY7bnQdmOA6vBJ9TWVoq6M985CrngTmK0BQt0BLdnTop6M9BBKZgAZbgzjeuFfqAbtAlIujWuPb8voNXAIIA1DkBU1jLOcLz8QIVpLzPCNggdaFWb9bIMNBTcGLqtRjhajzr49dwYweEPRM4u0m8Hg19L+tjchjhaLx8IdXS6OqjUdQyTSzT8lmmaISn47sXMt2N8Ic++tERBc7wDMd0hEkfTWEjzRhu+wbZM9yMZ+PLoa5jk8RejAct4r3Hz38QYBw0A+Ha3sVm3iaJ+XbpJHHzFrlb+t9LGZmuqKfAJzeM7SJ0vtj9un0zGQTHn8Ja2xGBzitoGVNzOVpGe0lPIzcp9gIaqlQ82LnhxkZwdnKdpXwulQ0ezqT6yJmhVB+yFxu/hxu7mOPTTzXMkcPf4Xl4/IRZYIG7PwDwnUUe8dn/DXARdMk/ev8C0IsPHg=='))) +# Created by pyminifier (https://github.com/liftoff/pyminifier) diff --git a/src/cool_cmp/cmp/utils.py b/src/cool_cmp/cmp/utils.py new file mode 100644 index 000000000..62fed781a --- /dev/null +++ b/src/cool_cmp/cmp/utils.py @@ -0,0 +1,219 @@ +from .pycompiler import Production, Sentence, Symbol, EOF, Epsilon + +class ContainerSet: + def __init__(self, *values, contains_epsilon=False): + self.set = set(values) + self.contains_epsilon = contains_epsilon + + def add(self, value): + n = len(self.set) + self.set.add(value) + return n != len(self.set) + + def extend(self, values): + change = False + for value in values: + change |= self.add(value) + return change + + def set_epsilon(self, value=True): + last = self.contains_epsilon + self.contains_epsilon = value + return last != self.contains_epsilon + + def update(self, other): + n = len(self.set) + self.set.update(other.set) + return n != len(self.set) + + def epsilon_update(self, other): + return self.set_epsilon(self.contains_epsilon | other.contains_epsilon) + + def hard_update(self, other): + return self.update(other) | self.epsilon_update(other) + + def find_match(self, match): + for item in self.set: + if item == match: + return item + return None + + def __len__(self): + return len(self.set) + int(self.contains_epsilon) + + def __str__(self): + return '%s-%s' % (str(self.set), self.contains_epsilon) + + def __repr__(self): + return str(self) + + def __iter__(self): + return iter(self.set) + + def __nonzero__(self): + return len(self) > 0 + + def __eq__(self, other): + if isinstance(other, set): + return self.set == other + return isinstance(other, ContainerSet) and self.set == other.set and self.contains_epsilon == other.contains_epsilon + + +def inspect(item, grammar_name='G', mapper=None): + try: + return mapper[item] + except (TypeError, KeyError ): + if isinstance(item, dict): + items = ',\n '.join(f'{inspect(key, grammar_name, mapper)}: {inspect(value, grammar_name, mapper)}' for key, value in item.items() ) + return f'{{\n {items} \n}}' + elif isinstance(item, ContainerSet): + args = f'{ ", ".join(inspect(x, grammar_name, mapper) for x in item.set) } ,' if item.set else '' + return f'ContainerSet({args} contains_epsilon={item.contains_epsilon})' + elif isinstance(item, EOF): + return f'{grammar_name}.EOF' + elif isinstance(item, Epsilon): + return f'{grammar_name}.Epsilon' + elif isinstance(item, Symbol): + return f"G['{item.Name}']" + elif isinstance(item, Sentence): + items = ', '.join(inspect(s, grammar_name, mapper) for s in item._symbols) + return f'Sentence({items})' + elif isinstance(item, Production): + left = inspect(item.Left, grammar_name, mapper) + right = inspect(item.Right, grammar_name, mapper) + return f'Production({left}, {right})' + elif isinstance(item, tuple) or isinstance(item, list): + ctor = ('(', ')') if isinstance(item, tuple) else ('[',']') + return f'{ctor[0]} {("%s, " * len(item)) % tuple(inspect(x, grammar_name, mapper) for x in item)}{ctor[1]}' + else: + raise ValueError(f'Invalid: {item}') + +def pprint(item, header=""): + if header: + print(header) + + if isinstance(item, dict): + for key, value in item.items(): + print(f'{key} ---> {value}') + elif isinstance(item, list): + print('[') + for x in item: + print(f' {repr(x)}') + print(']') + else: + print(item) + +class Token: + """ + Basic token class. + + Parameters + ---------- + lex : str + Token's lexeme. + token_type : Enum + Token's type. + """ + + def __init__(self, lex, token_type): + self.lex = lex + self.token_type = token_type + + def __str__(self): + return f'{self.token_type}: {self.lex}' + + def __repr__(self): + return str(self) + + @property + def is_valid(self): + return True + +class UnknownToken(Token): + def __init__(self, lex): + Token.__init__(self, lex, None) + + def transform_to(self, token_type): + return Token(self.lex, token_type) + + @property + def is_valid(self): + return False + +def tokenizer(G, fixed_tokens): + def decorate(func): + def tokenize_text(text): + tokens = [] + for lex in text.split(): + try: + token = fixed_tokens[lex] + except KeyError: + token = UnknownToken(lex) + try: + token = func(token) + except TypeError: + pass + tokens.append(token) + tokens.append(Token('$', G.EOF)) + return tokens + + if hasattr(func, '__call__'): + return tokenize_text + elif isinstance(func, str): + return tokenize_text(func) + else: + raise TypeError('Argument must be "str" or a callable object.') + return decorate + +class DisjointSet: + def __init__(self, *items): + self.nodes = { x: DisjointNode(x) for x in items } + + def merge(self, items): + items = (self.nodes[x] for x in items) + try: + head, *others = items + for other in others: + head.merge(other) + except ValueError: + pass + + @property + def representatives(self): + return { n.representative for n in self.nodes.values() } + + @property + def groups(self): + return [[n for n in self.nodes.values() if n.representative == r] for r in self.representatives] + + def __len__(self): + return len(self.representatives) + + def __getitem__(self, item): + return self.nodes[item] + + def __str__(self): + return str(self.groups) + + def __repr__(self): + return str(self) + +class DisjointNode: + def __init__(self, value): + self.value = value + self.parent = self + + @property + def representative(self): + if self.parent != self: + self.parent = self.parent.representative + return self.parent + + def merge(self, other): + other.representative.parent = self.representative + + def __str__(self): + return str(self.value) + + def __repr__(self): + return str(self) \ No newline at end of file diff --git a/src/cool_cmp/cmp/visitor.py b/src/cool_cmp/cmp/visitor.py new file mode 100644 index 000000000..500298bcd --- /dev/null +++ b/src/cool_cmp/cmp/visitor.py @@ -0,0 +1,80 @@ +# The MIT License (MIT) +# +# Copyright (c) 2013 Curtis Schlak +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import inspect + +__all__ = ['on', 'when'] + +def on(param_name): + def f(fn): + dispatcher = Dispatcher(param_name, fn) + return dispatcher + return f + + +def when(param_type): + def f(fn): + frame = inspect.currentframe().f_back + func_name = fn.func_name if 'func_name' in dir(fn) else fn.__name__ + dispatcher = frame.f_locals[func_name] + if not isinstance(dispatcher, Dispatcher): + dispatcher = dispatcher.dispatcher + dispatcher.add_target(param_type, fn) + def ff(*args, **kw): + return dispatcher(*args, **kw) + ff.dispatcher = dispatcher + return ff + return f + + +class Dispatcher(object): + def __init__(self, param_name, fn): + frame = inspect.currentframe().f_back.f_back + top_level = frame.f_locals == frame.f_globals + self.param_index = self.__argspec(fn).args.index(param_name) + self.param_name = param_name + self.targets = {} + + def __call__(self, *args, **kw): + typ = args[self.param_index].__class__ + d = self.targets.get(typ) + if d is not None: + return d(*args, **kw) + else: + issub = issubclass + t = self.targets + ks = t.keys() + ans = [t[k](*args, **kw) for k in ks if issub(typ, k)] + if len(ans) == 1: + return ans.pop() + return ans + + def add_target(self, typ, target): + self.targets[typ] = target + + @staticmethod + def __argspec(fn): + # Support for Python 3 type hints requires inspect.getfullargspec + if hasattr(inspect, 'getfullargspec'): + return inspect.getfullargspec(fn) + else: + return inspect.getargspec(fn) diff --git a/src/cool_cmp/cmp_tools/__init__.py b/src/cool_cmp/cmp_tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cmp_tools/grammar/grammar_fixer.py b/src/cool_cmp/cmp_tools/grammar/grammar_fixer.py new file mode 100644 index 000000000..076ee232b --- /dev/null +++ b/src/cool_cmp/cmp_tools/grammar/grammar_fixer.py @@ -0,0 +1,401 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal, SentenceFromIter) +from cmp_tools.utils.trie import TrieNode, Trie +from cmp_tools.utils.algorithms import permutation # FIX + +# GRAMMAR FIXER UTILS +def change_grammar_from_productions(gramm:Grammar,new_productions): + """ + Empty all non terminal and grammar productions\n + and add all productions in new_productions to gramm + """ + for x in gramm.nonTerminals: + x.productions = [] + + gramm.Productions = [] + + for x in new_productions: + gramm.Add_Production(x) + + return gramm + +def generate_name(G:Grammar,idx,prefix = 'N'): + new_key = prefix+'_' + cur_idx = idx + while f'{new_key}{cur_idx}' in G.symbDict.keys(): + cur_idx+=1 + return f'{new_key}{cur_idx}',cur_idx+1 + +def remove_unnecessary_symbols(gramm:Grammar,unnecesary): + new_prod = [] + + for prod in gramm.Productions: + if not prod.Left in unnecesary: + r_unne = [x for x in prod.Right if x in unnecesary] + if not r_unne: + new_prod.append(prod) + + for x in unnecesary: + try: + gramm.nonTerminals.remove(x) + except ValueError: + gramm.terminals.remove(x) + gramm.symbDict.__delitem__(x.Name) + + change_grammar_from_productions(gramm,new_prod) + +def build_reach(gramm:Grammar, symbol): + """ + Return a set with the symbols that reach symbol + """ + reach = set() + reach.add(symbol) + last_len = 0 + while last_len != len(reach): + last_len = len(reach) + for x in gramm.Productions: + if any([y for y in x.Right if y in reach]): + reach.add(x.Left) + return reach + +def fix_grammar(G,errors): + """ + Check if G is LL1 and fix it if possible\n + Removes the immediate left recursion and the common prefixes\n + return the new grammar fixed if possible\n + else return None + """ + if not G: + return None + # Your code goes here + new_errors = [] + + G = fix_common_prefix(G) + G = fix_left_recursion(G,new_errors) + G = fix_unnecesary_prod(G) + + errors.extend(new_errors) + if new_errors: + return None + return G + + +# LEFT RECURSION +# Esta implementado solamente la inmediata una sola vez Probar algo como E -> EE o algo por el estilo +def fix_left_recursion(grammar:Grammar, errors): + ''' + Fix immediate left recursion of grammar\n + return a fixed copy of grammar + ''' + new_grammar = grammar.copy() + new_grammar.Productions = [] + + for n_ter in grammar.nonTerminals: + for prod in n_ter.productions: + if not prod.Right.IsEpsilon and prod.Right[0] == prod.Left: + fix_non_terminal_left_recursion(n_ter,new_grammar, errors) + break + else: + new_grammar.Productions.extend(n_ter.productions) + + return new_grammar + +def fix_non_terminal_left_recursion(non_terminal:NonTerminal, grammar, errors): + ''' + Fix immediate left recursion non_terminal in grammar\n + ''' + new_name,idx = generate_name(grammar,0,non_terminal.Name) + new_non_terminal = grammar.NonTerminal(new_name) + + left_prod = non_terminal.productions + non_terminal.productions = [] + new_prod_new_n_ter = set() + new_prod_old_n_ter = set() + + for prod in left_prod: + if not prod.Right.IsEpsilon and prod.Right[0] == non_terminal: + if len(prod.Right) > 1: + sentence = [x for x in prod.Right[1:]] + sentence.append(new_non_terminal) + new_prod_new_n_ter.add(Production(new_non_terminal,SentenceFromIter(sentence))) + else: + sentence = [x for x in prod.Right] + sentence.append(new_non_terminal) + new_prod_new_n_ter.add(Production(new_non_terminal,grammar.Epsilon)) + new_prod_old_n_ter.add(Production(non_terminal,SentenceFromIter(sentence))) + + for prod in new_prod_new_n_ter: + grammar.Add_Production(prod) + + if not new_prod_old_n_ter: + errors.append(f'All productions of {non_terminal} begins with {non_terminal}, no string can be parsed by a left parse') + + for prod in new_prod_old_n_ter: + grammar.Add_Production(prod) + + +# CLEANING GRAMMAR +def fix_unnecesary_prod(grammar:Grammar): + grammar = fix_e_productions(grammar) + grammar = fix_useless_symbols(grammar) + return grammar + + +# COMMON PREFIX +def fix_common_prefix(grammar:Grammar): + """ + returns a copy of grammar without common prefixes + """ + G = grammar.copy() + G.Productions = [] + + for non_terminal in grammar.nonTerminals: + trie = Trie() + epsilon = False + for x in non_terminal.productions: + if not x.Right.IsEpsilon: + trie.add(x.Right) + else: + epsilon = True + non_terminal.productions = [] + if epsilon: + G.Add_Production(Production(x.Left,G.Epsilon)) + for node in trie.top.sons: + execute_node(trie.top.sons[node],non_terminal,[],G,0) + return G + +def execute_node(node:TrieNode,left,right:list,grammar:Grammar,idx): + """ + Fills productions with the new grammar productions\n + left: left part of the production\n + right: right part of the production in a list\n + productions: all the productions of the grammar without common prefixes\n + idx: index of the generated name + """ + right.append(node.value) + if len(node.sons) > 1 or (len(node.sons) == 1 and node.terminal): + name,idx = generate_name(grammar,idx,left.Name) + new_prod = grammar.NonTerminal(name) + right.append(new_prod) + grammar.Add_Production(Production(left,SentenceFromIter(right))) + left = new_prod + if node.terminal: + grammar.Add_Production(Production(left,grammar.Epsilon)) + for x in node.sons: + right = [] + execute_node(node.sons[x],left,right,grammar,idx) + elif len(node.sons) == 1: + for key in node.sons: + execute_node(node.sons[key],left,right,grammar,idx) + break + else: + grammar.Add_Production(Production(left,SentenceFromIter(right))) + + +# e-PRODUCTIONS +def remove_e_productions(G): + """ + returns a grammar with all epsilon productions eliminated\n + and a set with the Non Terminal that reached epsilon productions\n + return G,n_t_epsilon + """ + + n_t_epsilon = set() + new_productions = [] + # Removes all epsilon transitions from the non terminals + for x in G.Productions: + if x.Right.IsEpsilon: + n_t_epsilon.add(x.Left) + x.Left.productions.remove(x) + else: + new_productions.append(x) + + change = 0 + while change != len(n_t_epsilon): + change = len(n_t_epsilon) + for prod in G.Productions: + if len([x for x in prod.Right if x in n_t_epsilon]) == len(prod.Right): # All x in right is on n_t_epsilon + n_t_epsilon.add(prod.Left) + + G.Productions = new_productions + + return G,n_t_epsilon + +def add_new_productions(prod,new_productions,n_t_epsilon): + """ + Add to new_productions the corresponding productions from\n + permutate prod with the non_terminals in n_t_epsilon \n + Ex: A->BCB,n_t_eps={B}\n + add to new_productions {A->BCB, A->CB, A->BC, A->C} + """ + had_epsilon = [False]*len(prod.Right) + cant_epsilon = 0 + + for i,x in enumerate(prod.Right): + if x in n_t_epsilon: + had_epsilon[i] = True + cant_epsilon += 1 + + for perm in permutation(cant_epsilon,2): + new_prod_right = [] + perm_idx = 0 + for i,x in enumerate(had_epsilon): + if not x: + new_prod_right.append(prod.Right[i]) + elif perm[perm_idx]: + new_prod_right.append(prod.Right[i]) + perm_idx = perm_idx+1 if x else perm_idx + if new_prod_right: + new_productions.add(Production(prod.Left,SentenceFromIter(new_prod_right))) + if cant_epsilon == 0: + new_productions.add(Production(prod.Left,prod.Right)) + +def fix_e_productions(gramm:Grammar): + """ + Returns a grammar without epsilon transitions.\n + if gramm recognize epsilon then an augmented grammar\n + is return with an epsilon transition on the start symbol + """ + G = gramm + + G,n_t_epsilon = remove_e_productions(G) + + if G.startSymbol in n_t_epsilon: + G = G.AugmentedGrammar(force=True) + G.Add_Production(Production(G.startSymbol,G.Epsilon)) + else: + G = G.copy() + + new_productions = set() + + for prod in gramm.Productions: + add_new_productions(prod,new_productions,n_t_epsilon) + + for x in gramm.nonTerminals: + x.productions = [] + + for prod in new_productions: + G.Add_Production(prod) + + return G + + +# NON DERIVE TERMINAL +def update_derivation(production,derivation,left_derivation = True): + symbol,sentence = production.Left,production.Right + derive = [] + derive.append(production) + if not symbol in derivation: + if sentence.IsEpsilon: + derive.extend(derivation[symbol.Grammar.Epsilon]) + elif not left_derivation: + sentence = [ sentence[i] for i in range(len(sentence)-1,-1,-1) ] # sentence.reverse() + for x in sentence: + derive.extend(derivation[x]) + derivation[symbol] = derive + +def fix_non_derive_terminal(gramm:Grammar,return_derivations = False,left_derivation = True): + """ + Remove from gramm the non terminals A that dont satisfy:\n + A->*w where w in {G.T}* + return grammar + return grammar,derivation + """ + gramm = gramm.copy() + + derivation = { x:[Production(x,Sentence(x)),] for x in gramm.terminals } + derivation[gramm.Epsilon] = [Production(gramm.Epsilon,Sentence(gramm.Epsilon)),] + derive_something = set(gramm.terminals) + productions = set(gramm.Productions) + + change = -1 + while change != len(derive_something): + change = len(derive_something) + to_remove = [] + for x in productions: + if not any([y for y in x.Right if not y in derive_something]): # if y ->* w with w in T* + derive_something.add(x.Left) + update_derivation(x,derivation,left_derivation) + to_remove.append(x) + for x in to_remove: productions.remove(x) + + remove_unnecessary_symbols(gramm,[x for x in gramm.nonTerminals if x not in derive_something]) + + if return_derivations: + return gramm,derivation + return gramm + + +# UNREACHABLE SYMBOLS +def fix_unreachable_symbols(gramm:Grammar): + gramm = gramm.copy() + + pending = [gramm.startSymbol] + reachable = set(pending) + while pending: + symb = pending.pop() + for prod in symb.productions: + for r in prod.Right: + if not r in reachable: + reachable.add(r) + if isinstance(r,NonTerminal): + pending.append(r) + + remove_unnecessary_symbols(gramm,[x for x in gramm.nonTerminals + gramm.terminals if x not in reachable]) + + return gramm + + +# USELESS SYMBOLS +def fix_useless_symbols(gramm:Grammar): + """ + fix the non derive on terminal, non_terminals\n + and the unreachable symbols from the start symbol + """ + gramm = fix_unit_productions(gramm) + + gramm = fix_non_derive_terminal(gramm) + + gramm = fix_unreachable_symbols(gramm) + + return gramm + + +# UNIT PRODUCTIONS +def get_unit_tuples(unit_productions): + change = -1 + tuples = set([(x.Left,x.Right[0]) for x in unit_productions]) + while change != len(tuples): + change = len(tuples) + to_add = set() + for t in tuples: + for q in [x for x in tuples if t[1] == x[0]]: + to_add.add((t[0],q[1])) + tuples.update(to_add) + return tuples + + +def fix_unit_productions(gramm:Grammar): + """ + returns an equivalent grammar without productions of the form:\n + A -> B + """ + gramm = gramm.copy() + + unit_productions = {x for x in gramm.Productions if len(x.Right) == 1 and x.Right[0].IsNonTerminal} + + new_productions = set() + + for x in gramm.Productions: + if not x in unit_productions: + new_productions.add(x) + + pending = get_unit_tuples(unit_productions) + + while pending: + l,r = pending.pop() + for prod in r.productions: + if not prod in unit_productions: + new_productions.add(Production(l,prod.Right)) + + return change_grammar_from_productions(gramm,new_productions) diff --git a/src/cool_cmp/cmp_tools/grammar/grammar_parser.py b/src/cool_cmp/cmp_tools/grammar/grammar_parser.py new file mode 100644 index 000000000..c68e7720b --- /dev/null +++ b/src/cool_cmp/cmp_tools/grammar/grammar_parser.py @@ -0,0 +1,174 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal) +from cmp.ast import Node, AtomicNode, BinaryNode, TernaryNode +from cmp.utils import Token + +G_parser = Grammar() +Q = G_parser.NonTerminal('Q', True) +non_terminals = G_parser.NonTerminals('L S X Z E K T N M') +L, S, X, Z, E, K, T, N, M = non_terminals +non_terminals = { x.Name:x for x in non_terminals } +non_terminals[Q.Name] = Q + +terminals = G_parser.Terminals('pipe sym der end comma') +pipe, sym, der, end, comma = terminals +terminals = { x.Name:x for x in terminals } +terminals['eof'] = G_parser.EOF + +symbols = non_terminals.copy() +symbols.update(terminals) + +class GramConcatLines(BinaryNode): + @staticmethod + def operate(lvalue, rvalue): + return lvalue + '\n' + rvalue + +class GramNewProdNode(TernaryNode): + @staticmethod + def operate(lvalue, mvalue, rvalue): + return lvalue + ' > ' + mvalue + rvalue + +class GramConcatProdNode(BinaryNode): + @staticmethod + def operate(lvalue, rvalue): + return ' | ' + lvalue + rvalue + +class GramConcatNode(BinaryNode): + @staticmethod + def operate(lvalue, rvalue): + if rvalue == '': + return lvalue + return lvalue + ' ' + rvalue + +class SymbolNode(AtomicNode): + def evaluate(self): + return self.lex + + +############################ BEGIN PRODUCTIONS ############################ +# ======================================================================= # +Q %= E + end + T, lambda h,s: GramConcatLines(s[1],s[3]) +T %= E + end + T, lambda h,s: GramConcatLines(s[1],s[3]) +T %= G_parser.Epsilon, lambda h,s: SymbolNode('') +E %= sym + der + L, lambda h,s: s[3], None, None, lambda h,s: SymbolNode(s[1]) +L %= S + X, lambda h,s: GramNewProdNode(h[0],s[1],s[2]) +X %= pipe + S + X, lambda h,s: GramConcatProdNode(s[2],s[3]), None, None, lambda h,s: h[0] +X %= G_parser.Epsilon, lambda h,s: SymbolNode('') +S %= sym + K, lambda h,s: GramConcatNode(SymbolNode(s[1]),s[2]) +K %= sym + K, lambda h,s: GramConcatNode(SymbolNode(s[1]),s[2]) +K %= G_parser.Epsilon, lambda h,s: SymbolNode('') +# ======================================================================= # +############################# END PRODUCTIONS ############################# + +from cmp_tools.parser.parser_ll1 import ParserLL1 +from cmp_tools.grammar.grammar_tokens import get_lexer_from_text,nonzero_digits,digits,min_letters,cap_letters,separator,regex_char_separator + +# Grammar of the parser of Grammars +gram_parser = ParserLL1(G_parser) + +expand = '~' + +# Lexer of Grammar of the parser of Grammars +terms = f'sym{separator}[{min_letters}{cap_letters}_][_{min_letters}{cap_letters}{digits}]*{regex_char_separator}pipe{separator}\\|{regex_char_separator}end{separator};{regex_char_separator}der@{expand}{regex_char_separator}space{separator} *{regex_char_separator}comma{separator},{regex_char_separator}' +gram_lexer = None #get_lexer_from_text(terms,[]) ############################## + +def fix_gram_text(gram_text,errors): + gram_text = gram_text.replace('\n','') + + new_errors = [] + tokens = get_grammar_tokens(gram_text,new_errors) + if new_errors: + errors.append('Error getting the grammar tokens') + errors.extend(new_errors) + + new_errors = [] + gramm = gram_parser.evaluate(tokens,new_errors) + if new_errors: + errors.append('Error evaluating the grammar definition') + errors.extend(new_errors) + + return gramm + +def get_grammar_from_text(gramm_text, errors): + """ + returns a Grammar form gramm_text\n + gramm_text: is the grammar written by the user\n + NonTerminal_i ~ Production1_1 | ... | Production1_N;\n + ... + NonTerminal_j ~ ProductionQ_1 | ... | ProductionZ_P;\n + """ + gramm_text = fix_gram_text(gramm_text,errors) + if not gramm_text: + return None + + G = Grammar() + dic_sym = {} + + gramm = gramm_text.split('\n') + index = 0 + + distinguish = '' + symbols = set() + non_terminals = set() + for s in gramm: + if s: + s = s.split(' > ') + if not distinguish: + distinguish = s[0] + non_terminals.add(s[0]) + symbols.add(s[0]) + for ps in s[1].split(' | '): + for q in ps.split(' '): + symbols.add(q) + terminals = symbols.difference(non_terminals) + non_terminals.remove(distinguish) + S = G.NonTerminal(distinguish,True) + dic_sym[distinguish] = S + non_ter = ' '.join(non_terminals) + non_ter = G.NonTerminals(non_ter) + for x in non_ter: + dic_sym[x.Name] = x + ter = ' '.join(terminals) + ter = G.Terminals(ter) + for x in ter: + dic_sym[x.Name] = x + + dic_sym.update({"epsilon":G.Epsilon, "$":G.EOF}) + + s = gramm[index] + index+=1 + while s != "": + s = s.split(" > ") + q = s[1].split(" | ") + for prod in q: + p = prod.split(" ") + try: + temp = dic_sym[p[0]] + except KeyError: + errors.append(f'{p[0]} is not defined in the terminals or in the non_terminals') + break + for ter in p[1:]: + try: + temp += dic_sym[ter] + except KeyError: + errors.append(f'{ter} is not defined in the terminals or in the non_terminals') + break + try: + dic_sym[s[0]] %= temp + except TypeError: + errors.append(f'A Non Terminal cant be left part of a production: {s}') + break + s = gramm[index] + index+=1 + return G + +def get_grammar_tokens(gram_def,errors:list): + tokens = [] + for x in gram_lexer(gram_def): + if x.token_type != 'space': + try: + tok = Token(x.lex,symbols[x.token_type]) + tokens.append(tok) + except KeyError: + errors.append(f'Unknown Token({x.lex},{x.token_type}) in gram_def') + return tokens diff --git a/src/cool_cmp/cmp_tools/grammar/grammar_tokens.py b/src/cool_cmp/cmp_tools/grammar/grammar_tokens.py new file mode 100644 index 000000000..92649b232 --- /dev/null +++ b/src/cool_cmp/cmp_tools/grammar/grammar_tokens.py @@ -0,0 +1,141 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal) +from cmp.ast import Node, AtomicNode, BinaryNode, TernaryNode +from cmp.utils import Token +from cmp_tools.lexer.lexer import Lexer,nonzero_digits,digits,min_letters,cap_letters +from cmp_tools.lexer.regex import fixed_tokens, EPSILON, regex_automaton + + +digits_letters = f'{digits}{min_letters}{cap_letters}' +others = f',.^;:<>=-_!^&~/' +separator = '@' +regex_char_separator = '\n' +regex_separator = f'{regex_char_separator}*' + +# Lexer that recognise the token defined by the user +lex_token = Lexer([ #################################################### + # ('term',f'[{digits_letters}]*'), + # ('regex_ex',f'{separator}[ \\\\\\[\\]\\+\\?\\*\\(\\)\\|\\{EPSILON}{digits_letters}{others}]*'), + # ('regex_sep',regex_separator), +],'eof') + +# num@12w09djqdk\nlet@[asdcsac] ==> num - regex(12w09djqdk) let - regex([asdcasac]) + +def get_lexer_from_text(text,errors:list): + """ + Returns a Lexer that recognise tokens of the form @\\n@\\n...@\\n\n + where term is the name of the terminal and regex is the regular expression of term\n + the order in text is the same that the order of the lexer table + """ + tokens = lex_token(text) + lexer_table = [] + tok_iter = iter(tokens) + new_errors = [] + while True: + try: + terminal = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if terminal.token_type == 'eof': + break + + if not terminal.token_type == 'term': + new_errors.append(f'Expected: {terminal.lex}.token_type == term, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + try: + regex = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if not regex.token_type == 'regex_ex': + new_errors.append(f'Expected: {regex.lex}.token_type == regex_ex, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + try: + sep = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if not (sep.token_type == 'regex_sep' or sep.token_type == 'eof'): + new_errors.append(f'Expected: {sep.lex}.token_type == regex_sep or eof, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + lexer_table.append((terminal.lex,regex.lex[1:])) + + if sep.token_type == 'eof': + break + + for x in new_errors: + errors.append(x) + try: + next(tok_iter) + errors.append('tokens left to parse') + return None + except StopIteration: + if new_errors: + return None + return Lexer(lexer_table,'eof') + +def get_lexer_dict_from_text(text,errors:list): + """ + Returns a dictionary that recognise tokens of the form @\\n@\\n...@\\n\n + where term is the name of the terminal and regex is the regular expression of term\n + """ + tokens = lex_token(text) + lexer_table = {} + tok_iter = iter(tokens) + new_errors = [] + while True: + try: + terminal = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if terminal.token_type == 'eof': + break + + if not terminal.token_type == 'term': + new_errors.append(f'Expected: {terminal.lex}.token_type == term, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + try: + regex = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if not regex.token_type == 'regex_ex': + new_errors.append(f'Expected: {regex.lex}.token_type == regex_ex, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + try: + sep = next(tok_iter) + except StopIteration: + new_errors.append(f'Expected: token') + break + + if not (sep.token_type == 'regex_sep' or sep.token_type == 'eof'): + new_errors.append(f'Expected: {sep.lex}.token_type == regex_sep or eof, Recieve: {terminal.lex}.token_type == {terminal.token_type}') + break + + lexer_table[terminal.lex] = regex_automaton(regex.lex[1:]) + + if sep.token_type == 'eof': + break + + for x in new_errors: + errors.append(x) + try: + next(tok_iter) + errors.append('tokens left to parse') + return None + except StopIteration: + if new_errors: + return None + return lexer_table diff --git a/src/cool_cmp/cmp_tools/grammar/grammar_util.py b/src/cool_cmp/cmp_tools/grammar/grammar_util.py new file mode 100644 index 000000000..a6e59f739 --- /dev/null +++ b/src/cool_cmp/cmp_tools/grammar/grammar_util.py @@ -0,0 +1,21 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal) +from cmp_tools.grammar.grammar_parser import expand + + +def grammar_to_text(G:Grammar): + gram = '' + for n in G.nonTerminals: + gram += n.Name + f' {expand} ' + for p in n.productions: + if p.Right.IsEpsilon: + gram += ' epsilon ' + else: + for s in p.Right: + gram += f' {s.Name} ' + gram += ' | ' + gram = gram[:len(gram)-2] + gram += ';\n' + + return gram + \ No newline at end of file diff --git a/src/cool_cmp/cmp_tools/lang/language.py b/src/cool_cmp/cmp_tools/lang/language.py new file mode 100644 index 000000000..3b5af81c3 --- /dev/null +++ b/src/cool_cmp/cmp_tools/lang/language.py @@ -0,0 +1,64 @@ +from cmp.utils import Token +class Language(): + + parser = None + + grammar = None + + lexer = None + + def __init__(self, grammar,lexer,token_parse_dict={}): + self.grammar = grammar + self.lexer = lexer + self.token_parse = token_parse_dict + + def _fix_tokens(self,tokens,errors): + """ + If there are a token_type named 'space' this are discarted from the parsing tokens\n + also transform lexer tokens to grammar tokens + """ + fix_tokens = [] + for x in tokens: + if x.token_type != 'space': + try: + if x.token_type in self.token_parse: + tok = Token(self.token_parse[x.token_type](x.lex),x.token_type) + else: + tok = Token(x.lex,x.token_type) + fix_tokens.append(tok) + except KeyError: + errors.append(f'The grammar does not recognize the token {x}') + return fix_tokens + + def __call__(self, text, errors, tokens=None): + """ + returns a tuple of the parse and the tokens of the text + """ + + if tokens is None: + tokens = self.get_tokens(text, errors) + + parse_errors = [] + parse = self.parser(tokens,parse_errors) + + for x in parse_errors: + errors.append(x) + + if parse_errors: + return [],tokens + + return parse,tokens + + def get_tokens(self, text, errors): + """ + Return the text tokens + """ + tokens = self.lexer(text) + return tokens + + def find_conflict(self): + return self.parser.find_conflict() + + def evaluate(self, text, errors:list,return_ast = False): + tokens = self._fix_tokens(self.lexer(text),errors) + return self.parser.evaluate(tokens,errors,return_ast) diff --git a/src/cool_cmp/cmp_tools/lang/language_ll1.py b/src/cool_cmp/cmp_tools/lang/language_ll1.py new file mode 100644 index 000000000..842d40b0a --- /dev/null +++ b/src/cool_cmp/cmp_tools/lang/language_ll1.py @@ -0,0 +1,62 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal, SentenceFromIter) +from cmp.utils import ContainerSet, inspect, pprint, Token +from cmp_tools.grammar.grammar_tokens import get_lexer_from_text +from cmp_tools.grammar.grammar_parser import get_grammar_from_text +from cmp_tools.lexer.lexer import digits,min_letters,cap_letters +from cmp_tools.parser.parser_ll1 import ParserLL1 +from cmp_tools.grammar.grammar_fixer import fix_grammar +from cmp_tools.lang.language import Language +class LanguageLL1(Language): + + def __init__(self, grammar,lexer): + super().__init__(grammar,lexer) + self.parser = ParserLL1(self.grammar) + + @property + def get_firsts(self): + return self.parser.get_firsts + + @property + def get_follows(self): + return self.parser.get_follows + + @property + def get_predictive_table(self): + return self.parser.get_parser_table + + def get_derivation_tree(self,parse): + return self.parser.get_derivation_tree(parse) + +def build_LL1(tokens_def, grammar_def, errors:list): + """ + token_def:\n + The definition of the non terminal symbols of the grammar\n + (the name must be equal to the non terminals written in grammar_def)\n + token_def --> same format than text in get_lexer function\n + token_def can be an instance of Lexer in case of already have it\n + grammar_def:\n + The definition by the user of the grammar in this format:\n + Production1;Production2;...ProductionN;\n + A production can be: T ~ A bc |r3 | epsilon\n + grammar_def can be an instance of Grammar in case of already have it\n + return None if the grammar is not LL1\n + return the LanguageLL1 defined in grammar_def \n + """ + new_errors = [] + lex_gram = get_lexer_from_text(tokens_def,new_errors) if isinstance(tokens_def,str) else tokens_def + Gramm = get_grammar_from_text(grammar_def,new_errors) if isinstance(grammar_def,str) else grammar_def + # Gramm = fix_grammar(Gramm,errors) + + if not Gramm or not lex_gram: + for x in new_errors: + errors.append(x) + return None + ll1 = LanguageLL1(Gramm,lex_gram) + for x in ll1.parser.errors: + new_errors.append(x) + for x in new_errors: + errors.append(x) + # if new_errors: + # return None + return ll1 diff --git a/src/cool_cmp/cmp_tools/lang/language_lr.py b/src/cool_cmp/cmp_tools/lang/language_lr.py new file mode 100644 index 000000000..f7cda24e4 --- /dev/null +++ b/src/cool_cmp/cmp_tools/lang/language_lr.py @@ -0,0 +1,53 @@ +from cmp_tools.parser.parser_lr import LR0Parser,LR1Parser,SLR1Parser,LALR1Parser +from cmp_tools.grammar.grammar_parser import get_grammar_from_text +from cmp_tools.grammar.grammar_tokens import get_lexer_from_text +from cmp_tools.lang.language import Language + +def return_lr_parser(G,parser): + parser = parser.lower() + if parser == 'lr0': + lr = LR0Parser(G) + elif parser == 'lalr1': + lr = LALR1Parser(G) + elif parser == 'slr1': + lr = SLR1Parser(G) + elif parser == 'lr1': + lr = LR1Parser(G) + else: + lr = None + return lr + +def build_LR(tok_def,gram_def,lr:str,errors): + """ + gram_def: grammar definition or an instance of Grammar\n + tok_def: tokens deefinition or an instance of Lexer\n + lr: type of lr parser, can be ['lalr1', 'lr1', 'lr0', 'slr1']\n + return a LanguageLR\n + return None in case of errors + """ + new_errors = [] + + lex_gram = get_lexer_from_text(tok_def,new_errors) if isinstance(tok_def,str) else tok_def + Gramm = get_grammar_from_text(gram_def,new_errors) if isinstance(gram_def,str) else gram_def + + for x in new_errors: + errors.append(x) + if lex_gram and Gramm: + lr = return_lr_parser(Gramm,lr) + if not lr: + errors.append(f'{lr} is not a valid LR type of parser, try [lalr1, lr1, lr0, slr1]') + return None + if lr.errors: + errors.extend(lr.errors) + # return None + return LanguageLR(Gramm,lex_gram,lr) + return None + +class LanguageLR(Language): + + def __init__(self, grammar, lexer, parser_lr,token_parse_dict={}): + super().__init__(grammar,lexer,token_parse_dict) + self.parser = parser_lr + + def get_derivation_tree(self,parse): + return self.parser.get_derivation_tree(parse,False) diff --git a/src/cool_cmp/cmp_tools/lang/language_regular.py b/src/cool_cmp/cmp_tools/lang/language_regular.py new file mode 100644 index 000000000..35b9d85f1 --- /dev/null +++ b/src/cool_cmp/cmp_tools/lang/language_regular.py @@ -0,0 +1,397 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceFromIter, SentenceList, Symbol, + Terminal) +from cmp.utils import ContainerSet, Token, inspect, pprint +from cmp_tools.grammar.grammar_parser import get_grammar_from_text +from cmp_tools.grammar.grammar_tokens import get_lexer_dict_from_text,get_lexer_from_text +from cmp_tools.lang.language_lr import LanguageLR,return_lr_parser +from cmp_tools.lexer.lexer import cap_letters, digits, min_letters +from cmp_tools.lexer.regex import EPSILON, regex_automaton +from cmp_tools.utils.automaton import * + +def copy_automaton(base_automaton): + """ + Returns a tuple of base_automaton properties\n + start, states, finals, transitions + """ + start = base_automaton.start + dif = base_automaton.states + finals = base_automaton.finals.copy() + + transitions = {} + for x in base_automaton.transitions: + for y in base_automaton.transitions[x]: + transitions[x,y] = base_automaton.transitions[x][y] + + return start,dif,finals,transitions + +def join(raw_automaton,raw_automaton_join,state1,state2): + """ + raw_automaton, raw_automaton_join: tuples of copy_automatons\n + state1, state2: states of raw_automaton\n + insert raw_automaton_join in raw_automaton between state1 and state2\n + ______ ______ + (state1)--[symb in transitions[start of join automaton]]-->raw_automaton_join--e-->(state2) + """ + start, dif, finals, transitions = raw_automaton + j_start, j_dif, j_finals, j_transitions = raw_automaton_join + + for symb in [s for x,s in j_transitions if x == j_start]: + try: + transitions[state1,symb].append(j_transitions[j_start,symb][0] + dif) + except KeyError: + transitions[state1,symb] = [j_transitions[j_start,symb][0] + dif] + + for f in j_finals: + transitions[f+dif,''] = [state2] + + for state,symb in j_transitions: + transitions[state + dif,symb] = [j_transitions[state,symb][0] + dif] + + return start,dif+j_dif,finals,transitions + +def join_automaton(base_automaton,lex_dic): ################ convertir los States de lex_dic en DFA + """ + base_automaton: automaton from grammar, (deterministic) + lex_dic: dictionary that maps the terminals to the automaton that recognize it + """ + + start, dif, finals, transitions = copy_automaton(base_automaton) + fixed_transitions = transitions.copy() + transitions = {} + raw = start, dif, finals, transitions + cached_automaton = {} + + for state,terminal in fixed_transitions: + try: + au = cur_start, cur_states, cur_finals, cur_transitions = cached_automaton[terminal] + except KeyError: + automaton = lex_dic[terminal] + au = cur_start, cur_states, cur_finals, cur_transitions = copy_automaton(automaton) + cached_automaton[terminal] = au + + raw = join(raw,au,state,fixed_transitions[state,terminal][0]) + + nfa = NFA(raw[1],raw[2],raw[3],raw[0]) + dfa = nfa_to_dfa(nfa) + mini = automata_minimization(dfa) + + return mini + +def build_automaton_from_grammar(tok_def,gram_def,errors,lexer=None,grammar=None): + """ + Return the NFA if the grammar is regular + else return None + """ + new_errors = [] + + lex = get_lexer_from_text(tok_def,errors) if not lexer else lexer + G = get_grammar_from_text(gram_def,errors) if not grammar else grammar + + if G == None or lex == None: + errors.append('Invalid grammar or token definition') + return None + + if not check_grammar_regular(G, errors): + errors.append('Invalid Regular Grammar') + return None + + symb_num = {} + transitions = {} + itr1 = iter(range(len(G.nonTerminals))) + for x in G.nonTerminals: + symb_num[x] = next(itr1) + + start = symb_num[G.startSymbol] + finals = [len(G.nonTerminals)] + + distinguish_on_epsilon = any([x for x in G.startSymbol.productions if x.IsEpsilon]) + if distinguish_on_epsilon: finals.append(start) + + for prod in G.Productions: + left = symb_num[prod.Left] + len_right = len(prod.Right) + first_symbol = prod.Right[0] + if len_right == 2: + try: + transitions[left,first_symbol.Name].add(symb_num[prod.Right[1]]) + except KeyError: + transitions[left,first_symbol.Name] = {symb_num[prod.Right[1]]} + elif len_right == 1: + try: + transitions[left,first_symbol.Name].add(finals[0]) + except KeyError: + transitions[left,first_symbol.Name] = {finals[0]} + + nfa = NFA(len(G.nonTerminals)+1,finals,transitions,start) + dfa = nfa_to_dfa(nfa) + mini = automata_minimization(dfa) + + return mini # join_automaton(mini,lex.regexs) ############################################## + +def check_grammar_regular(G:Grammar,errors): + """ + return True if the Grammar G is regular + """ + new_errors = [] + for prod in G.Productions: + left = prod.Left + right = prod.Right + if right.IsEpsilon : + if left != G.startSymbol: + new_errors.append(f'Invalid Production for Regular Grammar: {prod}; the only left part that can have an epsilon on right part is the distiguish state') + continue + if len(right) > 2: + new_errors.append(f'Invalid Production for Regular Grammar: {prod}; the lenght of right part must be at most 2 and is {len(right)}') + else: + if not right[0].IsTerminal: + new_errors.append(f'Invalid Production for Regular Grammar: {prod}; the first symbol on a right part must be a terminal') + if len(right) == 2: + if right[1].IsTerminal: + new_errors.append(f'Invalid Production for Regular Grammar: {prod}; the second symbol on a right part must be a non terminal') + errors.extend(new_errors) + return not bool(new_errors) + +# REGULAR GRAMMAR TO REGEX + +def eliminate_state(tupled_automaton,s): + start,states,finals,transitions = tupled_automaton + + assert s != start,"you cant eliminate the start state" + + start = start if start < s else start - 1 + try: + finals.remove(s) + except: + pass + finals = { x for x in map(lambda x: x if x < s else x-1,finals)} + + exit_s = [] + enter_s = [] + other = [] + new_transitions = {} + cycle = '' + + for x in transitions.items(): # cycles in s dont go anywhere just 'activate' cycle variable + (state,value),regex = x + if state == s: + if value == s: + cycle = f'({regex})*' + continue + exit_s.append(x) + elif value == s: + enter_s.append(x) + else: + other.append(x) + + for (state0, value0),regex0 in enter_s: + for (state1, value1),regex1 in exit_s: + third = first(lambda x: x[0][0] == state0 and x[0][1] == value1,other) + if third: + other.remove(third) + transition = f"{third[1]}|" if third else "" + state = state0 if state0 < s else state0 - 1 + value = value1 if value1 < s else value1 - 1 + new_transitions[state,value] = f"({transition}{regex0}{cycle}{regex1})" + + for (state0, value0),regex0 in other: + state0 = state0 if state0 < s else state0 - 1 + value0 = value0 if value0 < s else value0 - 1 + if [x for (state,value), regex in new_transitions.items() if state == state0 and value == value0]: + print("WTF!!") + new_transitions[state0,value0] = regex0 + + return start,states-1,finals,new_transitions + +def eliminate_all_non_start_non_finals(tupled_automaton): + """ + return a tuple of start,states,finals,transitions of the automaton from eliminate all the \n + non start and the non finals states + """ + start,states,finals,transitions = tupled_automaton + change = True + while change: + change = False + for s in range(states): + if not s in finals and s != start: + change = True + tupled_automaton = start,states,finals,transitions = eliminate_state(tupled_automaton,s) + break + return tupled_automaton + +def eliminate_all_non_start_non_t(tupled_automaton,t): + """ + return a tuple of start,states,finals,transitions of the automaton from eliminate all the \n + non start and the non t states + """ + start,states,finals,transitions = tupled_automaton + change = True + while change: + change = False + for s in range(states): + if s != t and s != start: + change = True + tupled_automaton = start,states,finals,transitions = eliminate_state(tupled_automaton,s) + t = t if s > t else t-1 + break + return tupled_automaton + +def get_key(start,end,transitions): + # key = first(lambda x: x[0][0] == start and x[1] == end,transitions.items()) + try: + key = transitions[start,end] + except KeyError: + key = '' + return key#[0][1] if key else '' + +def get_regex_from_reduced_automaton(tupled_automaton): + """ + tupled_automaton: an automaton with de form:\n + (A)--regex->(A)<-regex_left regex_right->(B)<-regex--(B)\n + or\n + (AB)--regex->(AB)\n + where A is start and B is final\n + """ + start,states,finals,transitions = tupled_automaton + if states == 2: + other = 0 if start == 1 else 1 + A = get_key(start,start,transitions) + B = get_key(start,other,transitions) + C = get_key(other,other,transitions) + D = get_key(other,start,transitions) + if not B: + return '' + if A and C and D: + return f"({A}|{B}{C}*{D})*{B}{C}*" + if A and D: + return f"({A}|{B}{D})*{B}" + if A and C: + return f"{A}*{B}{C}*" + if A: + return f"{A}*{B}" + if C and D: + return f"({B}{C}*{D})*{B}{C}*" + if C: + return f"{B}{C}*" + if D: + return f"({B}{D})*{B}" + return f"{B}" + if states == 1: + assert start in finals, "start is not a final state" + A = get_key(start,start,transitions) + if A: + return f"{A}*" + else: + return '' + assert False, "Wrong number of states in the tupled automaton" + +def regex_from_clean_automaton(tupled_automaton,s): + """ + tupled_automaton: an automaton with only finals states and the start state + s: final state to find regex + return the regex from eliminate all the states except the start state and the s state + """ + tupled_automaton = eliminate_all_non_start_non_t(tupled_automaton,s) + + return get_regex_from_reduced_automaton(tupled_automaton) + +def convert_to_regex_automaton(tupled_automaton): + """ + join al the transitions from state x to state y in one equivalent regex\n + example:\n + (A)-a,b,c->(B) => (A)-a|b|c->(B) + """ + start,states,finals,transitions = tupled_automaton + + temp_dic = {} + for (state,symbol),values in transitions.items(): + for value in values: + try: + regex = temp_dic[state,value] + regex = regex[:len(regex)-1] + f"|{symbol})" + except KeyError: + regex = f'({symbol})' + temp_dic[state,value] = regex + + transitions = temp_dic + + return start,states,finals,transitions + +def build_regex_from_grammar(tok_def,gram_def,errors:list,lexer=None,grammar=None,automaton=None): + """ + return the regex and the automaton from tok_def and gram_def or from lexer and grammar if automaton is not given\n + else return the regex of the automaton given + """ + new_errors = [] + + if not automaton: + automaton = build_automaton_from_grammar(tok_def,gram_def,new_errors,lexer,grammar) + if not automaton: + errors.extend(new_errors) + return None + + tupled_automaton = copy_automaton(automaton) + tupled_automaton = convert_to_regex_automaton(tupled_automaton) + tupled_automaton = start,states,finals,transitions = eliminate_all_non_start_non_finals(tupled_automaton) + iter_finals = finals.copy() + regex = [] + for s in iter_finals: + new_transitions = transitions.copy() + new_finals = finals.copy() + automaton = start,states,new_finals,new_transitions + new_regex = regex_from_clean_automaton(automaton,s) + regex.append(new_regex) + + if new_errors: + errors.extend(new_errors) + + regex = '|'.join(regex) + + tupl = regex_automaton(regex,return_regex=True) + return tupl[1] + + + +def build_Lan_Reg(tok_def,gram_def,errors): + """ + gram_def: grammar definition or an instance of Grammar\n + tok_def: tokens deefinition or an instance of Lexer\n + return a LanguageRegular\n + return None in case of errors + """ + lexer = get_lexer_from_text(tok_def,errors) if isinstance(tok_def,str) else tok_def + grammar = get_grammar_from_text(gram_def,errors) if isinstance(gram_def,str) else gram_def + + if not grammar or not lexer: + errors.append('Invalid grammar or token definition') + return None + + if not check_grammar_regular(grammar,errors): + errors.append('Invalid Regular Grammar') + return None + + return LanguageRegular(grammar,lexer) + +class LanguageRegular(LanguageLR): + + grammar_regex = None + + grammar_automaton = None + + def __init__(self, grammar, lexer): + super().__init__(grammar,lexer,None) + + def grammar_to_regex(self,errors): + self.grammar_regex = self.grammar_regex if self.grammar_regex else build_regex_from_grammar('','',errors,self.lexer,self.grammar,self.grammar_to_automaton(errors)) + return self.grammar_regex + + def grammar_to_automaton(self,errors): + self.grammar_automaton = self.grammar_automaton if self.grammar_automaton else build_automaton_from_grammar('','',errors,self.lexer,self.grammar) + return self.grammar_automaton + + def __call__(self, string,errors): + automaton = self.grammar_to_automaton(errors) + if automaton: + return automaton.recognize(string),None + return None,None + diff --git a/src/cool_cmp/cmp_tools/lexer/lexer.py b/src/cool_cmp/cmp_tools/lexer/lexer.py new file mode 100644 index 000000000..9f825d22e --- /dev/null +++ b/src/cool_cmp/cmp_tools/lexer/lexer.py @@ -0,0 +1,116 @@ + +from cmp.utils import Token +from cmp.automata import State +from cmp_tools.lexer.regex import regex_automaton + +class DetailToken(Token): + def __init__(self, lex,token_type): + super().__init__(lex,token_type) + self.row = lex[1] + self.column = lex[2] + +class Lexer: + def __init__(self, table, eof): + self.eof = eof + self.regexs = self._build_regexs(table) + self.automaton = self._build_automaton() + self.table = { x:y for x,y in table} + + def _build_regexs(self, table): + regexs = {} + for n, (token_type, regex) in enumerate(table): + # Your code here!!! + # - Remember to tag the final states with the token_type and priority. + # - .tag might be useful for that purpose ;-) + auto = regex_automaton(regex) + auto, states = State.from_nfa(auto,True) + for st in states: + if st.final: + st.tag = (n,token_type) + regexs[token_type] = auto + return regexs + + def _build_automaton(self): + start = State('start') + # Your code here!!! + for x in self.regexs: + start.add_epsilon_transition(self.regexs[x]) + return start.to_deterministic() + + def _walk(self, string): + state = self.automaton + final = state if state.final else None + final_lex = lex = '' + + for symbol in string: + # Your code here!!! + if state.has_transition(symbol): + state = state[symbol][0] + if state.final: + final = state + final_lex = lex + # else: + # final = None + else: + final_lex = lex + break + lex += symbol + else: + final_lex = lex + + return final, final_lex + + def _tokenize(self, text): + + while text: + stop_state, lex = self._walk(text) + + if stop_state and len(lex)>0: + st_min = min([st.tag for st in [ final for final in stop_state.state if final.final]]) + yield lex,st_min[1] + else: + if len(lex) == 0: + lex = text[0] + yield lex,'UNKNOWN' + + text = text[len(lex):] + + yield '$', self.eof + + def __call__(self, text): + return [ Token(lex, ttype) for lex, ttype in self._tokenize(text) ] + +class DetailLexer(Lexer): + + def _tokenize(self, text): + row,column = 0,0 + while text: + stop_state, lex = self._walk(text) + + rows_in_lex = len([x for x in lex if x == '\n']) + row += rows_in_lex + if rows_in_lex: + column = len(lex.split('\n')[-1]) + else: + column += len(lex) + + if stop_state and len(lex)>0: + st_min = min([st.tag for st in [ final for final in stop_state.state if final.final]]) + yield (lex,row,column),st_min[1] + else: + if len(lex) == 0: + lex = text[0] + yield (lex,row,column),'UNKNOWN' + + text = text[len(lex):] + + yield ('$',row,column), self.eof + + def __call__(self, text): + return [ DetailToken(lex, ttype) for lex, ttype in self._tokenize(text) ] + + +nonzero_digits = '[123456789]' +min_letters = '[abcdefghijklmnopqrstuvwxyz]' +cap_letters = '[ABCDEFGHIJKLMNOPQRSTUVWXYZ]' +digits = f'({nonzero_digits}|0)' diff --git a/src/cool_cmp/cmp_tools/lexer/regex.py b/src/cool_cmp/cmp_tools/lexer/regex.py new file mode 100644 index 000000000..b4ed38395 --- /dev/null +++ b/src/cool_cmp/cmp_tools/lexer/regex.py @@ -0,0 +1,147 @@ +from cmp.ast import Node, AtomicNode, UnaryNode, BinaryNode +from cmp.utils import Token +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal) +from cmp_tools.utils.automaton import * +from cmp_tools.parser.parser_ll1 import ParserLL1 + + +G = Grammar() + +EPSILON = 'ε' + +E = G.NonTerminal('E', True) +T, F, A, X, Y, Z, R, Q = G.NonTerminals('T F A X Y Z R Q') +pipe, star, opar, cpar, symbol, epsilon, plus, qtn, obra, cbra = G.Terminals(f'| * ( ) symbol {EPSILON} + ? [ ]') + +# Your code here!!! +E %= T + X, lambda h,s: s[2], None,lambda h,s: s[1] + +X %= pipe + T + X, lambda h,s: UnionNode(h[0],s[3]), None, None,lambda h,s: s[2] +X %= G.Epsilon, lambda h,s: h[0] + +T %= A + Y, lambda h,s: s[2], None,lambda h,s: s[1] + +Y %= A + Y, lambda h,s: ConcatNode(h[0],s[2]), None,lambda h,s: s[1] +Y %= G.Epsilon, lambda h,s: h[0] + +A %= Z + F, lambda h,s: s[2] ,None ,lambda h,s: s[1] + +F %= star + F, lambda h,s: s[2], None, lambda h,s: ClosureNode(h[0]) +F %= plus + F, lambda h,s: s[2],None,lambda h,s: PlusNode(h[0]) +F %= qtn + F, lambda h,s: s[2], None, lambda h,s: QuestionNode(h[0]) +F %= G.Epsilon, lambda h,s: h[0] + +R %= A + Q, lambda h,s: s[2], None,lambda h,s: s[1] + +Q %= A + Q, lambda h,s: UnionNode(h[0],s[2]), None, lambda h,s: s[1] +Q %= G.Epsilon, lambda h,s: h[0] + +Z %= symbol, lambda h,s: SymbolNode(s[1]), None +Z %= opar + E + cpar, lambda h,s: s[2], None, None, None +Z %= obra + R + cbra, lambda h,s: s[2], None, None, None +Z %= epsilon, lambda h,s: EpsilonNode(s[1]), None + + +regex_parser = ParserLL1(G) + +class EpsilonNode(AtomicNode): + def evaluate(self): + automata = NFA(1,{0},{},0) + return '',automata + +class SymbolNode(AtomicNode): + def evaluate(self): + s = self.lex + # Your code here!!! + automata = NFA(2,{1},{(0,s):[1]},0) + return f'{s}',automata + +class ClosureNode(UnaryNode): + @staticmethod + def operate(value): + # Your code here!!! + return f'({value[0]})*',automata_closure(value[1]) + +class UnionNode(BinaryNode): + @staticmethod + def operate(lvalue, rvalue): + # Your code here!!! + return f'({lvalue[0]}|{rvalue[0]})',automata_union(lvalue[1],rvalue[1]) + +class ConcatNode(BinaryNode): + @staticmethod + def operate(lvalue, rvalue): + # Your code here!!! + return f'{lvalue[0]}{rvalue[0]}',automata_concatenation(lvalue[1],rvalue[1]) + +class PlusNode(UnaryNode): + @staticmethod + def operate(value): + # Your code here!!! + return f'({value[0]})+',automata_concatenation(value[1],automata_closure(value[1])) + +class QuestionNode(UnaryNode): + @staticmethod + def operate(value): + # Your code here!!! + epsilon = NFA(1,{0},{},0) + return f'({value[0]})?',automata_union(value[1],epsilon) + +fixed_tokens = { + '*' : Token('*' , star), + '(' : Token('(' , opar), + ')' : Token(')' , cpar), + '|' : Token('|' , pipe), + '?' : Token('?' , qtn), + '+' : Token('+' , plus), + '[' : Token('[' , obra), + ']' : Token(']' , cbra), + EPSILON : Token(EPSILON , epsilon), + } + +def regex_tokenizer(text, G, skip_whitespaces=True): + tokens = [] + # > fixed_tokens = ??? + # Your code here!!! + + skip = False + for i, char in enumerate(text): + + if skip: + skip = False + continue + + if skip_whitespaces and char.isspace(): + continue + # Your code here!!! + if char == '\\': + try: + tokens.append(Token(text[i+1],symbol)) + except IndexError: + tokens.append(Token('\\',symbol)) + skip = True + continue + + try: + tokens.append(fixed_tokens[char]) + except KeyError: + tokens.append(Token(char,symbol)) + + tokens.append(Token('$', G.EOF)) + return tokens + +def regex_automaton(regex,skip_whitespces=False,return_regex = False): + """ + returns the minimal dfa that recognize regex + """ + tokens = regex_tokenizer(regex,G,skip_whitespces) + errors = [] + regex,nfa = regex_parser.evaluate(tokens,errors) + if nfa: + dfa = nfa_to_dfa(nfa) + mini = automata_minimization(dfa) + if return_regex: + return mini,regex + return mini + return None \ No newline at end of file diff --git a/src/cool_cmp/cmp_tools/parser/__init__.py b/src/cool_cmp/cmp_tools/parser/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cmp_tools/parser/parser.py b/src/cool_cmp/cmp_tools/parser/parser.py new file mode 100644 index 000000000..30aff9581 --- /dev/null +++ b/src/cool_cmp/cmp_tools/parser/parser.py @@ -0,0 +1,44 @@ +from cmp.automata import State +class Parser(): + + def __call__(self,tokens,errors): + raise NotImplementedError() + + def find_conflit(self): + ''' + return a list of conflicts + ''' + raise NotImplementedError() + + def evaluate(self,tokens,errors,return_ast=False): + raise NotImplementedError() + + def get_derivation_tree(self,parse_list, left_to_right=True): + if not left_to_right: parse_list.reverse() + + node = State(parse_list[0].Left) + self.build_tree(node,[0],parse_list,left_to_right) + return node.graph('TD') + + def build_tree(self,current_node, index, parse_list, left_to_right): + + new_nodes = [] + if parse_list[index[0]].Right: + for x in parse_list[index[0]].Right: + new_nodes.append(State(x)) + else: + new_nodes.append(State(parse_list[index[0]].Right)) + + if not left_to_right: new_nodes.reverse() + + for x in new_nodes: + current_node.add_transition('',x) + if x.state.IsNonTerminal: + index[0] += 1 + self.build_tree(x,index,parse_list,left_to_right) + + if not left_to_right: + try: + current_node.transitions[''].reverse() + except: + pass diff --git a/src/cool_cmp/cmp_tools/parser/parser_ll1.py b/src/cool_cmp/cmp_tools/parser/parser_ll1.py new file mode 100644 index 000000000..ad02b7ff9 --- /dev/null +++ b/src/cool_cmp/cmp_tools/parser/parser_ll1.py @@ -0,0 +1,332 @@ +from cmp.pycompiler import (EOF, Epsilon, Grammar, NonTerminal, Production, + Sentence, SentenceList, Symbol, Terminal) +from cmp.utils import ContainerSet, inspect, pprint, Token +from cmp_tools.utils.first_follow import compute_firsts, compute_follows, compute_local_first +from cmp_tools.parser.parser import Parser +from cmp_tools.grammar.grammar_fixer import fix_non_derive_terminal, build_reach + +class ParserLL1(Parser): + + grammar = None + + firsts = None + + follows = None + + parse_table = None + + parser = None + + errors = [] + + eval_errors = [] + + def __init__(self, G:Grammar): + """ + When created check for grammar errors in errors + """ + self.grammar = G + + @property + def get_follows(self): + if self.follows is None: + self.firsts = self.get_firsts + self.follows = compute_follows(self.grammar,self.firsts) + return self.follows + + @property + def get_firsts(self): + if self.firsts is None: + self.firsts = compute_firsts(self.grammar) + return self.firsts + + @property + def get_parser_table(self): + if self.parse_table is None: + self.parse_table = self.build_parsing_table() + return self.parse_table + + def __call__(self,tokens,errors): + if not self.parser: + self.parser = self.metodo_predictivo_no_recursivo() + return self.parser(tokens,errors) + + def build_parsing_table(self): + # init parsing table + M = {} + + G = self.grammar + firsts = self.get_firsts + follows = self.get_follows + + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + + ################################################### + # working with symbols on First(alpha) ... + ################################################### + # # + for t in firsts[alpha]: + try: + a = M[X,t] + if type(a) == type(list()): + self.errors.append(\ + f'Grammar Ambiguity: M[{X},{t}] = {a}, and also must be M[{X},{t}] = {alpha}') + if not alpha in a: + a.append(alpha) + elif a != alpha: + self.errors.append(\ + f'Grammar Ambiguity: M[{X},{t}] = {a}, and also must be M[{X},{t}] = {alpha}') + M[X,t] = [a,alpha] + except KeyError: + M[X,t] = alpha + ################################################### + + ################################################### + # working with epsilon... + ################################################### + # # + if firsts[alpha].contains_epsilon: + for t in follows[X]: + try: + a = M[X,t] + if a != alpha: + self.errors.append(\ + f'Grammar Ambiguity: M[{X},{t}] = {a}, and also must be M[{X},{t}] = {alpha}') + if type(a) == type(list()): + a.append(alpha) + else: + M[X,t] = [a,alpha] + except KeyError: + M[X,t] = alpha + ################################################### + + # parsing table is ready!!! + return M + + def return_prod(self, left,right): + for i,x in enumerate(left.productions,0): + if x.Right == right: + return left.productions[i]; + return None + + def metodo_predictivo_no_recursivo(self): + + G = self.grammar + M = self.get_parser_table + firsts = self.get_firsts + follows = self.get_follows + + # parser construction... + def parser(tokens, parser_errors:list): + + ################################################### + # tokens ends with $ (G.EOF) + ################################################### + # init: + stack = [G.EOF,G.startSymbol] + + cursor = 0 + output = [] + ################################################### + + # parsing tokens... + # print((top, a)) + + ################################################### + # # + while cursor < len(tokens): + top = stack.pop() + a = tokens[cursor] + prod = None + if top.IsTerminal: + if a.token_type == top: + cursor+=1 + continue + else: + parser_errors.append(f'Expected: {top}, Recieve: {a.token_type}') + break + try: + prod = M[top,a.token_type] + except KeyError: + parser_errors.append(f'M[{top},{a.token_type}] generate nothing: expected {[ x[1] for x in M if x[0] == top ]}') + break + + if a.token_type in firsts[prod]: + rev = prod[::-1] + for t in rev: + stack.append(t) + output.append(self.return_prod(top,prod)) + + elif prod.IsEpsilon and a.token_type in follows[top]: + output.append(self.return_prod(top,prod)) + else: + parser_errors.append(f'{a.token_type} Not in follows[{top}]') + break + + ################################################### + + # left parse is ready!!! + return output + + # parser is ready!!! + return parser + + def _evaluate(self, production, left_parse, tokens, inherited_value=None): + head, body = production + attributes = production.attributes + + # Insert your code here ... + # > synteticed = ... + synteticed = [None for _ in attributes] + # > inherited = ... + inherited = [None]*(len(body)+1) + # Anything to do with inherited_value? + inherited[0] = inherited_value + + for i, symbol in enumerate(body, 1): + if symbol.IsTerminal: + if not inherited[i] is None: + self.eval_errors.append(f'Terminals cant have inherited values. Terminal:{symbol}; Inherited:{inherited[i]}') + break + # Insert your code here ... + try: + synteticed[i] = next(tokens).lex # como es un terminal se sintetiza como el mismo + except StopIteration: + self.eval_errors.append(f'tokens stopped the iteration') + break + else: + try: + next_production = next(left_parse) + except StopIteration: + self.eval_errors.append(f'left_parse stopped the iteration') + break + if not symbol == next_production.Left: + self.eval_errors.append(f'{symbol} doesnt match with {next_production.Left}. Cant expand {symbol}') + break + # Insert your code here ... + if attributes[i]: + inherited[i] = attributes[i](inherited, synteticed) + synteticed[i] = self._evaluate(next_production, left_parse, tokens, inherited[i]) + + # Insert your code here ... + if attributes[0]: + synteticed[0] = attributes[0](inherited, synteticed) + # > return ... + return synteticed[0] + + def evaluate_parse(self, left_parse, tokens): + self.eval_errors.clear() + if not left_parse or not tokens: + self.eval_errors.append('Empty tokens or Empty left_parse') + return None + + left_parse = iter(left_parse) + tokens = iter(tokens) + result = self._evaluate(next(left_parse), left_parse, tokens) + + if not isinstance(next(tokens).token_type, EOF): + self.eval_errors.append('Last parsed token doesnt match with EOF') + return None + return result + + def evaluate(self,tokens,errors:list): + """ + If no errors then returns the evaluated tokens\n + else fills errors with errors returning None + """ + parser = self.metodo_predictivo_no_recursivo() + new_errors = [] + left_parse = parser(tokens,new_errors) + if not new_errors: + ast = self.evaluate_parse(left_parse, tokens) + if self.eval_errors: + for x in self.eval_errors: + errors.append(x) + return None + return ast.evaluate() + else: + for x in new_errors: + errors.append(x) + return None + + def find_conflict(self): + table = self.get_parser_table + conflicts = [] + for x in table: + if type(table[x]) == type([1,2]): + grammar,derive = fix_non_derive_terminal(self.grammar,True) + visited = set([grammar.startSymbol,]) + conflict = self._find_conflict(build_reach(self.grammar,x[0]), grammar.startSymbol,x,derive,visited,[]) + conflicts.append(conflict) + return conflicts + + def _find_conflict(self, reach, current, searching, derive, visited, productions): + """ + si X in reach => X puede alcanzar a searching + derive[X] producciones para hacer X una oracion + searching llave de la tabla que da problemas + productions producciones que va llevando + """ + if current == searching[0]: + return self._generate_conflict_error(searching,productions,derive) + + for x in current.productions: + new_productions = productions.copy() + new_productions.append(x) + for y in x.Right: + if y in reach: + if y not in visited: + visited.add(y) + conflict = self._find_conflict(reach,y,searching,derive,visited,new_productions) + if conflict: + return conflict + visited.remove(y) + new_productions.extend(derive[y]) + + return '' + + def _generate_conflict_error(self,searching,productions,derive): + string = self._generate_conflict_string(productions,derive) + aux = ' | '.join([str(x) for x in self.get_parser_table[searching]]) + conflict = f'The prefix "{string}{searching[1].Name}" generate the parse {productions}, that can be continued by these productions {searching[0]} -> {aux}' + return conflict + + def _generate_conflict_string(self,productions,derive): + + stack = [self.grammar.startSymbol] + cursor = 0 + output = [] + string = [] + + while cursor < len(productions): + top = stack.pop() + + if top.IsTerminal: + if not top.IsEpsilon: + string.append(top) + cursor += 1 + continue + + prod = productions[cursor] + + if prod.Right: + rev = prod.Right[::-1] + for t in rev: + stack.append(t) + else: + stack.append(self.grammar.Epsilon) + cursor += 1 + + stack.reverse() + for x in stack: + if x.IsTerminal: + string.append(x) + + output = '' + for x in string: + output += x.Name + ' ' + + return output diff --git a/src/cool_cmp/cmp_tools/parser/parser_lr.py b/src/cool_cmp/cmp_tools/parser/parser_lr.py new file mode 100644 index 000000000..8bd35b6d4 --- /dev/null +++ b/src/cool_cmp/cmp_tools/parser/parser_lr.py @@ -0,0 +1,696 @@ +from cmp.automata import State, lr0_formatter, multiline_formatter +from cmp.pycompiler import (EOF, Epsilon, Grammar, Item, NonTerminal, + Production, Sentence, SentenceFromIter, + SentenceList, Symbol, Terminal) +from cmp_tools.utils.first_follow import (compute_firsts, compute_follows, compute_local_first) +from cmp.utils import ContainerSet, DisjointNode, DisjointSet, Token +from cmp_tools.parser.parser import Parser +from cmp_tools.grammar.grammar_fixer import fix_non_derive_terminal +from cmp_tools.utils.automaton import state_transpose +from cool.errors.errors import SyntacticCoolError, SYNTACTIC_ERROR + +###################### LR0 and SLR1 ########################### +def get_state(visited,pending,item): + if not item in visited.keys(): + new_state = State(item,True) + pending.append(item) + visited[item] = new_state + return new_state + return visited[item] + +def build_LR0_automaton(G:Grammar): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0) + + automaton = State(start_item, True) + + pending = [ start_item ] + visited = { start_item: automaton } + + while pending: + current_item = pending.pop() + if current_item.IsReduceItem: + continue + + current_state = visited[current_item] + next_symbol = current_item.NextSymbol + next_item = current_item.NextItem() + + #- $(X --> a.cB) ---c---> (X --> ac.B) con c in V_T + #- $(X --> a.YB) ---Y---> (X --> aY.B) con Y in V_N + next_state = get_state(visited,pending,next_item) + current_state.add_transition(next_symbol.Name,next_state) + + if next_symbol in G.nonTerminals: + sym_productions = G.symbDict[next_symbol.Name].productions + #- $(X --> a.YB) ---e---> (Y --> .Z) con Y in V_N + for pr in [Item(x,0) for x in sym_productions]: + trans_state = get_state(visited,pending,pr) + current_state.add_epsilon_transition(trans_state) + + return automaton.to_deterministic(lr0_formatter) + +class ShiftReduceParser(Parser): + SHIFT = 'SHIFT' + REDUCE = 'REDUCE' + OK = 'OK' + lr_type = None + errors = None + automaton = None + grammar = None + error_states = None # self.error_states[key] is the set of posibles values + eval_errors = [] + + + state_dict = {} # state_dic[key] = State with idx==key + + def __init__(self, G, automaton_builder, verbose=False): + self.grammar = G + self.verbose = verbose + self.action = {} + self.goto = {} + self.errors = [] + self.error_states = {} + G = G.AugmentedGrammar(True) + self.automaton = automaton_builder(G) + self._build_parsing_table(G) + + def _build_parsing_table(self, G): + raise NotImplementedError() + + def __call__(self, tokens, errors,finding_conflict = False): + stack = [ 0 ] + cursor = 0 + output = [] + tokens = [x for x in tokens] + while True and cursor < len(tokens): + state = stack[-1] + lookahead = tokens[cursor] + if self.verbose: print(stack, '<---||--->', tokens[cursor:]) + + # Your code here!!! (Detect error) + try: + action = self.action[state, lookahead.token_type] + if isinstance(action,tuple): + action, tag = action + else: + return None if not finding_conflict else (state,lookahead,output) + except KeyError: + # errors.append(f'Invalid transition ({state},{lookahead}) doesnt exist expected {[ x[1] for x in self.action if x[0] == state ]}') + posibles = [x for x in self.action if x[0] == state ] + arg = f"{lookahead.lex[0]}" if lookahead.is_eof else lookahead.lex[0] + errors.append(SyntacticCoolError(SYNTACTIC_ERROR, arg, token=lookahead)) + # errors.append(f"Invalid transition near '{lookahead.lex[0]}'. Expected: {', '.join([ str(x[1]) for x in posibles ])}. Line:{lookahead.lex[1] + 1} Column:{lookahead.lex[2] + 1}") + if len(posibles) == 1 and not lookahead.is_eof: + tokens.insert(cursor + 1, Token((str(posibles[0][1]), lookahead.lex[1], lookahead.lex[2]), posibles[0][1])) + cursor += 1 + continue + return None if not finding_conflict else (state,lookahead,output) + + if action == self.SHIFT: + # Your code here!!! (Shift case) + stack.append(lookahead.token_type) + stack.append(tag) + cursor+=1 + elif action == self.REDUCE: + # Your code here!!! (Reduce case) + for i in range(len(tag.Right)): + stack.pop() + top = stack.pop() + if top != tag.Right[-(i+1)]: + errors.append(f"Productions reduce doesnt match: {top} != {tag.Right[-(i+1)]}") + + index = self.goto[stack[-1],tag.Left] + stack.append(tag.Left) + stack.append(index) + output.append(tag) + elif action == self.OK: + # Your code here!!! (OK case) + return output if not finding_conflict else (state,lookahead,output) + # Your code here!!! (Invalid case) + else: + errors.append(f"Invalid case: {action}") + return None if not finding_conflict else (state,lookahead,output) + + if cursor == len(tokens): + errors.append('EOF token missing') + + else: + errors.append('No valid derivation tree can be built with the given tokens') + + def _register(self, table, key, value): + if key in table: + key_value = table[key] + if type(key_value) == type(set()): + if value not in key_value: + self.errors.append(f'Shift-Reduce or Reduce-Reduce conflict: {key} already on table with values {table[key]} cannot register with value {value}') + key_value.add(value) + if key in self.error_states: + self.error_states[key].add(key) + else: + self.error_states[key] = set([value,key_value]) + elif key_value != value: + self.errors.append(f'Shift-Reduce or Reduce-Reduce conflict: {key} already on table with value {table[key]} cannot register with value {value}') + table[key] = set([value, key_value]) + if key in self.error_states: + self.error_states[key].add(key) + else: + self.error_states[key] = set([value,key_value]) + else: + table[key] = value + + def _evaluate(self, production, right_parse, tokens, inherited_value=None): + head, body = production + attributes = production.attributes + body = list(body) + body.reverse() + # Insert your code here ... + # > synteticed = ... + synteticed = [None for _ in attributes] + # > inherited = ... + inherited = [None]*(len(body)+1) + # Anything to do with inherited_value? + inherited[0] = inherited_value + + for i, symbol in zip(range(len(body),0,-1),body) : + if symbol.IsTerminal: + if not inherited[i] is None: + self.eval_errors.append(f'Terminals cant have inherited values. Terminal:{symbol}; Inherited:{inherited[i]}') + break + # Insert your code here ... + try: + synteticed[i] = next(tokens).lex # como es un terminal se sintetiza como el mismo + except StopIteration: + self.eval_errors.append(f'tokens stopped the iteration') + break + else: + try: + next_production = next(right_parse) + except StopIteration: + self.eval_errors.append(f'right_parse stopped the iteration') + break + if not symbol == next_production.Left: + self.eval_errors.append(f'{symbol} doesnt match with {next_production.Left}. Cant expand {symbol}') + break + # Insert your code here ... + if attributes[i]: + inherited[i] = attributes[i](inherited, synteticed) + synteticed[i] = self._evaluate(next_production, right_parse, tokens, inherited[i]) + + # Insert your code here ... + if attributes[0]: + synteticed[0] = attributes[0](inherited, synteticed) + # > return ... + return synteticed[0] + + def evaluate_parse(self, right_parse, tokens): + self.eval_errors.clear() + if not right_parse or not tokens: + self.eval_errors.append('Empty tokens or Empty right_parse') + return None + + right_parse = iter(right_parse) + end = tokens[-1] + tokens = tokens[:len(tokens)-1] + tokens.reverse() + tokens.append(end) + tokens = iter(tokens) + result = self._evaluate(next(right_parse), right_parse, tokens) + + if not isinstance(next(tokens).token_type, EOF): + self.eval_errors.append('Last parsed token doesnt match with EOF') + return None + return result + + def evaluate(self,tokens,errors:list,return_ast=False,parsed_tokens=None): + """ + If no errors then returns the evaluated tokens\n + else fills errors with errors returning None + """ + parser = self.__call__ + new_errors = [] + if parsed_tokens is None: + right_parse = parser(tokens,new_errors) + else: + right_parse = parsed_tokens + if not new_errors: + right_parse.reverse() + ast = self.evaluate_parse(right_parse, tokens) + if self.eval_errors: + for x in self.eval_errors: + errors.append(x) + return None + if return_ast: + return ast + return ast.evaluate() + else: + for x in new_errors: + errors.append(x) + return None + + def find_conflict(self): + conflicts = [] + automaton_reverse,state_dict = state_transpose(self.automaton) + for key,value in self.action.items(): + if type(value) == type(set()): + conflict_productions = [x[1] for x in value if isinstance(x[1],Production)] + for production in conflict_productions: + conflict_state = state_dict[key[0]][0] + conflict_item = find_conflict_item(conflict_state,production) + stack = [(conflict_state,conflict_item)] + + sentence = [ y for y in production.Right ] + sentence.reverse() + current_state = conflict_state + current_item = conflict_item + for y in sentence: + current_item = Item(current_item.production,current_item.pos-1,current_item.lookaheads) + current_state = go_back(current_state,y,current_item,state_dict) + stack.append((current_state,current_item)) + stack.reverse() + + initial_item = find_initial_item(self.automaton) + path = [(self.automaton,initial_item,False)] + visited = {(initial_item,self.automaton.idx)} + find_path_to(stack[0][0],stack[0][1],self.automaton,initial_item,path,visited) # una lista de tuplas que es (estado en que estoy,item en el que estoy) + + terminals = items_to_terminals(path[:len(path)-1],stack) + conflicts.append(self._generate_error(value,terminals,[x[1] for x in path] + [x[1] for x in stack[1:]],key[0],key[1])) + break + + return conflicts + + def _generate_error(self,conflict,terminals,items,state,lookahead): + string = ' '.join(x.Name for x in terminals) + return f'The string "{string}" is generated by the items {items}, stopping in state {state}, the conflict is because the automaton can do the following actions {conflict} looking at terminal "{lookahead}"' + +class LR0Parser(ShiftReduceParser): + + def __init__(self,G,verbose=False): + super().__init__(G,build_LR0_automaton,verbose) + self.lr_type = 'lr0' + + def _build_parsing_table(self,G): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + automaton = self.automaton + for i, node in enumerate(automaton): + if self.verbose: print(i, '\t', '\n\t '.join(str(x) for x in node.state), '\n') + node.idx = i + + for node in automaton: + idx = node.idx + for state in node.state: + item = state.state + # Your code here!!! + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + item = state.state + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action,(idx,G.EOF),(self.OK,None)) + else: + for c in G.terminals + [G.EOF]: + self._register(self.action, (idx,c),(self.REDUCE,item.production)) + else: + next_sym = item.NextSymbol + try: + next_state = node[next_sym.Name][0] + if next_sym.IsNonTerminal: + self._register(self.goto,(idx,next_sym),next_state.idx) + else: + self._register(self.action,(idx,next_sym),(self.SHIFT,next_state.idx)) + except KeyError: + self.errors.append(f'Node: {node} without transition with symbol {next_sym}') + return None + +class SLR1Parser(ShiftReduceParser): + + def __init__(self,G,verbose=False): + super().__init__(G,build_LR0_automaton,verbose) + self.lr_type = 'slr1' + + def _build_parsing_table(self,G): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + firsts = compute_firsts(G) + follows = compute_follows(G, firsts) + + automaton = self.automaton + for i, node in enumerate(automaton): + if self.verbose: print(i, '\t', '\n\t '.join(str(x) for x in node.state), '\n') + node.idx = i + + for node in automaton: + idx = node.idx + for state in node.state: + item = state.state + # Your code here!!! + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + item = state.state + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action,(idx,G.EOF),(self.OK,None)) + else: + for c in follows[item.production.Left]: + self._register(self.action, (idx,c),(self.REDUCE,item.production)) + else: + next_sym = item.NextSymbol + try: + next_state = node[next_sym.Name][0] + if next_sym.IsNonTerminal: + self._register(self.goto,(idx,next_sym),next_state.idx) + else: + self._register(self.action,(idx,next_sym),(self.SHIFT,next_state.idx)) + except KeyError: + self.errors.append(f'Node: {node} without transition with symbol {next_sym}') + return None + + +###################### LR1 ########################### +def expand(item, firsts): + next_symbol = item.NextSymbol + if next_symbol is None or not next_symbol.IsNonTerminal: + return [] + + lookaheads = ContainerSet() # lookahead = que yo quiero ver cuando vaya a reducir + # Your code here!!! (Compute lookahead for child items) + + for prev in item.Preview(): + lookaheads.update(compute_local_first(firsts,prev)) + + assert not lookaheads.contains_epsilon + + # Your code here!!! (Build and return child items) + return [ Item(x,0,lookaheads) for x in next_symbol.productions] + +def compress(items): + centers = {} + + for item in items: + center = item.Center() + try: + lookaheads = centers[center] + except KeyError: + centers[center] = lookaheads = set() + lookaheads.update(item.lookaheads) + + return { Item(x.production, x.pos, set(lookahead)) for x, lookahead in centers.items() } + +def closure_lr1(items, firsts): + closure = ContainerSet(*items) + + changed = True + while changed: + changed = False + + new_items = ContainerSet() + # Your code here!!! + for x in closure: + new_items.extend(expand(x,firsts)) + + changed = closure.update(new_items) + + return compress(closure) + +def goto_lr1(items, symbol, firsts=None, just_kernel=False): + assert just_kernel or firsts is not None, '`firsts` must be provided if `just_kernel=False`' + items = frozenset(item.NextItem() for item in items if item.NextSymbol == symbol) + return items if just_kernel else closure_lr1(items, firsts) + +def build_LR1_automaton(G): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + firsts = compute_firsts(G) + firsts[G.EOF] = ContainerSet(G.EOF) + + start_production = G.startSymbol.productions[0] + start_item = Item(start_production, 0, lookaheads=(G.EOF,)) + start = frozenset([start_item]) + + closure = closure_lr1(start, firsts) + automaton = State(frozenset(closure), True) + + pending = [ start ] + visited = { start: automaton } + + while pending: + current = pending.pop() + current_state = visited[current] + + for symbol in G.terminals + G.nonTerminals: + # Your code here!!! (Get/Build `next_state`) + next_state_key = goto_lr1(current_state.state,symbol,just_kernel=True) + # next_state_key = frozenset([i.NextItem() for i in current_state.state if i.NextSymbol == symbol]) + if not next_state_key: + continue + try: + next_state = visited[next_state_key] + except KeyError: + next_state_items = goto_lr1(current_state.state,symbol,firsts) + next_state = State(frozenset(next_state_items),True) + pending.append(next_state_key) + visited[next_state_key] = next_state + current_state.add_transition(symbol.Name, next_state) + + + automaton.set_formatter(multiline_formatter) + return automaton + +class LR1Parser(ShiftReduceParser): + + def __init__(self,G,verbose=False): + super().__init__(G,build_LR1_automaton,verbose) + self.lr_type = 'lr1' + + def _build_parsing_table(self,G): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + automaton = self.automaton + for i, node in enumerate(automaton): + if self.verbose: print(i, '\t', '\n\t '.join(str(x) for x in node.state), '\n') + node.idx = i + + for node in automaton: + idx = node.idx + for item in node.state: + # Your code here!!! + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action,(idx,G.EOF),(self.OK,None)) + else: + for c in item.lookaheads: + self._register(self.action, (idx,c),(self.REDUCE,item.production)) + else: + next_sym = item.NextSymbol + try: + next_state = node[next_sym.Name][0] + if next_sym.IsNonTerminal: + self._register(self.goto,(idx,next_sym),next_state.idx) + else: + self._register(self.action,(idx,next_sym),(self.SHIFT,next_state.idx)) + except KeyError: + self.errors.append(f'Node: {node} without transition with symbol {next_sym}') + return None + + +###################### LALR1 ########################### +def center_of(items): + return { item.Center() for item in items } + +def build_automaton_from_ds(initial:State, ds:DisjointSet): + for g in ds.groups: + r = g[0].representative.value + old_transitions = r.transitions + r.transitions = {} + for x in old_transitions: + node = None + for y in ds.groups: + if center_of(y[0].representative.value.state) == center_of(old_transitions[x][0].state): + node = y + break + assert node, 'group not found' + r.add_transition(x, node[0].representative.value) + end = [x for x in ds.groups if x[0].representative.value == initial][0] + return end[0].representative.value + +def from_lr1_to_lalr(lr1_automaton:State): + pending = [s for s in lr1_automaton] + ds = DisjointSet(*pending) + while pending: + to_merge = [] + pivot = center_of(pending[0].state) + for i,x in enumerate(pending): + if center_of(x.state) == pivot: + to_merge.append(x) + pending[i] = None + pending = [x for x in pending if x] + ds.merge(to_merge) + + for g in ds.groups: + r = g[0].representative + for x in [x for x in g if r != x]: + for prod in r.value.state: + for prod2 in x.value.state: + if prod.Center() == prod2.Center(): + new_lookahead = {x for x in prod.lookaheads} + new_lookahead.update({x for x in prod2.lookaheads}) + prod.lookaheads = frozenset(new_lookahead) + return build_automaton_from_ds(lr1_automaton,ds) + +def build_LALR1_automaton(G): + return from_lr1_to_lalr(build_LR1_automaton(G)) + +class LALR1Parser(ShiftReduceParser): + + def __init__(self,G,verbose=False): + super().__init__(G,build_LALR1_automaton,verbose) + self.lr_type = 'lalr1' + + def _build_parsing_table(self,G): + assert len(G.startSymbol.productions) == 1, 'Grammar must be augmented' + + automaton = self.automaton + for i, node in enumerate(automaton): + if self.verbose: print(i, '\t', '\n\t '.join(str(x) for x in node.state), '\n') + node.idx = i + + for node in automaton: + idx = node.idx + for item in node.state: + # Your code here!!! + # - Fill `self.Action` and `self.Goto` according to `item`) + # - Feel free to use `self._register(...)`) + if item.IsReduceItem: + if item.production.Left == G.startSymbol: + self._register(self.action,(idx,G.EOF),(self.OK,None)) + else: + for c in item.lookaheads: + self._register(self.action, (idx,c),(self.REDUCE,item.production)) + else: + next_sym = item.NextSymbol + try: + next_state = node[next_sym.Name][0] + if next_sym.IsNonTerminal: + self._register(self.goto,(idx,next_sym),next_state.idx) + else: + self._register(self.action,(idx,next_sym),(self.SHIFT,next_state.idx)) + except KeyError: + self.errors.append(f'Node: {node} without transition with symbol {next_sym}') + return None + + +############## Conflict Utils ####################### +def go_back(state_to_transpose, symbol,expected_item,transpose_state_dic): + """ + return a state that enter to state_to_transpose with symbol `symbol` + """ + candidates = transpose_state_dic[state_to_transpose.idx][1][symbol.Name] + candidates = [x for x in candidates if any([y for y in x.state if y.state == expected_item])] + return transpose_state_dic[candidates[0].idx][0] + +def find_path_to(goal_state,goal_item,current_state,current_item,path,item_checked): + """ + path: a list of tuple (item's state, item) that represent th items taken to reach current state + item_checked: a set of tuple (item, item's state.idx) that saves the visited items + return in path the items needed to reach the goal_item in goal_state from current_item in current_state + """ + if goal_state == current_state and goal_item == current_item: + return True + if current_item.IsReduceItem: + return False + + spanned_items = span_item(current_state,current_item) + + path.append((current_state[current_item[current_item.pos].Name][0],current_item.NextItem(),True if current_item[current_item.pos].IsNonTerminal else False)) + if not (path[-1][1],path[-1][0].idx) in item_checked: + item_checked.add((path[-1][1],path[-1][0].idx)) + if find_path_to(goal_state,goal_item,path[-1][0],path[-1][1],path,item_checked): + return True + path.pop() + + for next_item in spanned_items: + path.append((current_state,next_item,False)) + if not (path[-1][1],path[-1][0].idx) in item_checked: + item_checked.add((next_item,current_state.idx)) + if find_path_to(goal_state,goal_item,path[-1][0],path[-1][1],path,item_checked): + return True + path.pop() + return False + +def items_to_terminals(first_path, second_path): + """ + concat the terminals of first_path an the sentence of second_path + """ + terminals = [] + for i,(state,item,skipped) in enumerate(first_path): + if not item.IsReduceItem: + if i != 0 and skipped: # before skiped: + last_state,last_item,skipped = first_path[i-1] + spanned_items = span_item(last_state,last_item) + for next_item in spanned_items: + next_terminals = item_sentence(last_state,next_item) + if next_terminals: + terminals += next_terminals + break + if item[item.pos].IsTerminal: + terminals.append(item[item.pos]) + + for state,item in second_path: + if not item.IsReduceItem: + if item[item.pos].IsTerminal: + terminals.append(item[item.pos]) + else: + spanned_items = span_item(state,item) + terminals += item_sentence(state,spanned_items[0]) + return terminals + +def find_initial_item(initial_state): + for in_state in initial_state.state: + item = in_state.state + if len(item.production.Right) == 1 and item.production.Right[0].IsNonTerminal \ + and "'" in item.production.Left.Name: + return item + +def find_conflict_item(state,production): + for in_state in state.state: + if isinstance(in_state,Item): + if in_state.production == production: + return in_state + else: + item = in_state.state + if item.production == production: + return item + +def span_item(state,item): + return [x.state for x in state.state if x.state.production.Left == item[item.pos] and x.state.pos == 0] + # Tambien incluir los lookahead en la condicion? + +def item_sentence(state,item): + path = [] + _item_sentence(state,item,set(),path) + return path + +def _item_sentence(state:State,item,visited,path): + + if item.IsReduceItem: + return True + + next_symb = item.NextSymbol + if isinstance(next_symb,NonTerminal): + if not (state.idx,next_symb) in visited: + visited.add((state.idx,next_symb)) + for next_item in span_item(state,item): + if _item_sentence(state,next_item,visited,path): + if _item_sentence(state[next_symb.Name][0],item.NextItem(),visited,path): + return True + else: + path.append(next_symb) + if _item_sentence(state[next_symb.Name][0],item.NextItem(),visited,path): + return True + path.pop() \ No newline at end of file diff --git a/src/cool_cmp/cmp_tools/shortcut.py b/src/cool_cmp/cmp_tools/shortcut.py new file mode 100644 index 000000000..5cde6e1f1 --- /dev/null +++ b/src/cool_cmp/cmp_tools/shortcut.py @@ -0,0 +1,12 @@ +from cmp_tools.lang.language_ll1 import build_LL1 +from cmp_tools.lang.language_lr import build_LR +from cmp_tools.lang.language_regular import build_Lan_Reg +from cmp_tools.grammar.grammar_fixer import fix_common_prefix,fix_e_productions,fix_left_recursion,fix_useless_symbols +from cmp_tools.grammar.grammar_util import grammar_to_text +from cmp_tools.grammar.grammar_parser import get_grammar_from_text +from cmp_tools.utils.first_follow import compute_firsts, compute_follows + +def build_LR_2(lr_type): + def build(tok_def,gram_def,error): + return build_LR(tok_def,gram_def,lr_type,error) + return build \ No newline at end of file diff --git a/src/cool_cmp/cmp_tools/utils/algorithms.py b/src/cool_cmp/cmp_tools/utils/algorithms.py new file mode 100644 index 000000000..a1e7bce34 --- /dev/null +++ b/src/cool_cmp/cmp_tools/utils/algorithms.py @@ -0,0 +1,21 @@ + +def permutation(n,k): + """ + returns an iter from all permutations in n places of k elements\n + Ex: n = 2, k = 2\n + returns [0,0],[0,1],[1,1],[1,0] + """ + perm = [None]*n + if n == 0: + return [] + for t in inner_permutation(perm,0,k,n): + yield t + +def inner_permutation(perm,i,k,n): + for p in range(k): + perm[i] = p + if i < n-1: + for t in inner_permutation(perm,i+1,k,n): + yield t + else: + yield tuple(perm) diff --git a/src/cool_cmp/cmp_tools/utils/automaton.py b/src/cool_cmp/cmp_tools/utils/automaton.py new file mode 100644 index 000000000..a145cafd6 --- /dev/null +++ b/src/cool_cmp/cmp_tools/utils/automaton.py @@ -0,0 +1,463 @@ +from cmp.utils import ContainerSet +from cmp.utils import DisjointSet +from cmp.automata import State +import pydot + +def state_transpose(initial_state:State): + """ + returns the state equivalent to initial_state on the transpose graph and a dictionary mapping idx to new states transposed + """ + state_dict = {} # state_dict[key] = (original_state,copy_of_original_state_with_transposed_transitions) + idx = 0 + for x in initial_state: + new_state = State(x.state,x.final,x.formatter,x.shape) + if not hasattr(x,'idx'): + x.idx = idx + idx+=1 + new_state.idx = x.idx + state_dict[x.idx] = (x,new_state) + + for x in initial_state: + for key,states in x.transitions.items(): + for state in states: + state_dict[state.idx][1].add_transition(key,state_dict[x.idx][1]) + + return state_dict[initial_state.idx][1],state_dict + +class NFA: + def __init__(self, states, finals, transitions, start=0): + self.states = states + self.start = start + self.finals = set(finals) + self.map = transitions + self.vocabulary = set() + self.transitions = { state: {} for state in range(states) } + + for (origin, symbol), destinations in transitions.items(): + assert hasattr(destinations, '__iter__'), 'Invalid collection of states' + self.transitions[origin][symbol] = destinations + self.vocabulary.add(symbol) + + self.vocabulary.discard('') + + def epsilon_transitions(self, state): + assert state in self.transitions, 'Invalid state' + try: + return self.transitions[state][''] + except KeyError: + return () + + def graph(self): + G = pydot.Dot(rankdir='LR', margin=0.1) + G.add_node(pydot.Node('start', shape='plaintext', label='', width=0, height=0)) + + for (start, tran), destinations in self.map.items(): + tran = 'ε' if tran == '' else tran + G.add_node(pydot.Node(start, shape='circle', style='bold' if start in self.finals else '')) + for end in destinations: + G.add_node(pydot.Node(end, shape='circle', style='bold' if end in self.finals else '')) + G.add_edge(pydot.Edge(start, end, label=tran, labeldistance=2)) + + G.add_edge(pydot.Edge('start', self.start, label='', style='dashed')) + # G = 'Graph Drawed' + return G + + def _repr_svg_(self): + try: + return self.graph().create_svg().decode('utf8') + except: + pass + +class DFA(NFA): + + def __init__(self, states, finals, transitions, start=0): + assert all(isinstance(value, int) for value in transitions.values()) + assert all(len(symbol) > 0 for origin, symbol in transitions) + + transitions = { key: [value] for key, value in transitions.items() } + NFA.__init__(self, states, finals, transitions, start) + self.current = start + + def _move(self, symbol): + # Your code here + try: + self.current = self.transitions[self.current][symbol][0] + return True + except: # Ver el error q da + return False + + def _reset(self): + self.current = self.start + + def recognize(self, string): + # Your code here + self._reset() + for i in range(0,len(string)): + if not self._move(string[i]): + return False + return self.current in self.finals + +def goto(automaton:NFA, states, symbol): + # Devuelve los estados en los cuales existe una transicion desde alguno de los estados de states mediante + # symbol + moves = set() + for state in states: + # Your code here + try: + for i in automaton.transitions[state][symbol]: + moves.add(i) + except: + pass + return moves + +def epsilon_closure(automaton, states): + pending = [ s for s in states ] # equivalente a list(states) pero me gusta así :p + closure = { s for s in states } # equivalente a set(states) pero me gusta así :p + analiced = [False]*automaton.states + + while pending: + state = pending.pop() + # Your code here + try: + for i in automaton.transitions[state]['']: + if not analiced[i]: + closure.add(i) + pending.append(i) + except KeyError: # Ver el error q da + pass + analiced[state] = True + return ContainerSet(*closure) + +def first(cond, itera): + for x in iter(itera): + if cond(x): + return x + return None + +def nfa_to_dfa(automaton): + transitions = {} + + start = epsilon_closure(automaton, [automaton.start]) + start.id = 0 + start.is_final = any(s in automaton.finals for s in start) + states = [ start ] + pending = [ start ] + ids = 1 + while pending: + state = pending.pop() + + for symbol in automaton.vocabulary: + # Your code here + # ... + new_state = epsilon_closure(automaton,goto(automaton, state, symbol)) + + if len(new_state) == 0: # no genera nada + continue + + try: + transitions[state.id, symbol] + assert False, 'Invalid DFA!!!' + except KeyError: + # Your code here + if new_state in states: + transitions[state.id, symbol] = first(lambda x: x.set == new_state.set,states).id + continue + + new_state.id = ids + ids += 1 + new_state.is_final = any(s in automaton.finals for s in new_state) + transitions[state.id, symbol] = new_state.id + + pending.append(new_state) # agregar id al new_state + states.append(new_state) + + finals = [ state.id for state in states if state.is_final ] + dfa = DFA(len(states), finals, transitions) + return dfa + +def automata_union(a1, a2): + transitions = {} + + start = 0 + d1 = 1 + d2 = a1.states + d1 + final = a2.states + d2 + + for (origin, symbol), destinations in a1.map.items(): + ## Relocate a1 transitions ... + # Your code here + transitions[origin + d1,symbol] = [t for t in map(lambda x: x+d1,destinations)] + + + for (origin, symbol), destinations in a2.map.items(): + ## Relocate a2 transitions ... + # Your code here + transitions[origin + d2,symbol] = [t for t in map(lambda x: x+d2,destinations)] + + ## Add transitions from start state ... + # Your code here + transitions[start,''] = [a1.start + d1, a2.start + d2] # epsilon transitions to initials of a1 and a2 + + ## Add transitions to final state ... + # Your code here + for f1 in a1.finals: + try: + transitions[f1 + d1,''].append(final) + except KeyError: + transitions[f1 + d1,''] = [final] + + for f2 in a2.finals: + try: + transitions[f2 + d2,''].append(final) + except KeyError: + transitions[f2 + d2,''] = [final] + + states = a1.states + a2.states + 2 + finals = { final } + + return NFA(states, finals, transitions, start) + +def automata_concatenation(a1, a2): + transitions = {} + + start = 0 + d1 = 0 + d2 = a1.states + d1 + final = a2.states + d2 + + for (origin, symbol), destinations in a1.map.items(): + ## Relocate a1 transitions ... + # Your code here + transitions[origin + d1, symbol] = [t for t in map(lambda x: x+d1,destinations)] + + for (origin, symbol), destinations in a2.map.items(): + ## Relocate a2 transitions ... + # Your code here + transitions[origin + d2, symbol] = [t for t in map(lambda x: x+d2,destinations)] + + + ## Add transitions to final state ... + # Your code here + for f1 in a1.finals: + try: + transitions[f1 + d1,''].append(a2.start + d2) + except KeyError: + transitions[f1 + d1,''] = [a2.start + d2] + + for f2 in a2.finals: + try: + transitions[f2 + d2,''].append(a2.start + d2) + except KeyError: + transitions[f2 + d2,''] = [final] + states = a1.states + a2.states + 1 + finals = { final } + + return NFA(states, finals, transitions, start) + +def automata_closure(a1): + transitions = {} + + start = 0 + d1 = 1 + final = a1.states + d1 + + for (origin, symbol), destinations in a1.map.items(): + ## Relocate automaton transitions ... + # Your code here + transitions[origin + d1,symbol] = [t for t in map(lambda x: x+d1,destinations)] + + ## Add transitions from start state ... + # Your code here + transitions[start,''] = [a1.start + d1, final] + + ## Add transitions to final state and to start state ... + # Your code here + for f1 in a1.finals: + try: + transitions[f1 + d1,''].append(a1.start + d1) + transitions[f1 + d1,''].append(final) + except: + transitions[f1 + d1,''] = [a1.start + d1] + transitions[f1 + d1,''].append(final) + + + states = a1.states + 2 + finals = { final } + + return NFA(states, finals, transitions, start) + +def distinguish_states(group, automaton, partition): + split = {} + vocabulary = tuple(automaton.vocabulary) + for member1 in group: + # Your code here + # mira a ver a que grupo pertenece + for group_representative in split.keys(): + # chequea el vocabulario + for symbol in vocabulary: + err1, err2 = False, False + try: + m1 = automaton.transitions[partition[group_representative].value][symbol][0] + except KeyError: + err1 = True + try: + m2 = automaton.transitions[member1.value][symbol][0] + except KeyError: + err2 = True + + if err1 and err2: + continue + elif (not err1 and err2) or (err1 and not err2): + break + + if partition[m1].representative != partition[m2].representative: + break + else: + # matcheo todo el vocabulario + split[group_representative].append(member1.value) + break + else: + # no pertenece a ninguno por lo tanto creo uno nuevo + split[member1.value] = [member1.value] + return [group for group in split.values()] + +def state_minimization(automaton): + partition = DisjointSet(*range(automaton.states)) + + ## partition = { NON-FINALS | FINALS } + # Your code here + partition.merge([ x for x in automaton.finals]) + + non_finals = [nf for nf in filter(lambda x: not x in automaton.finals,range(automaton.states))] + partition.merge(non_finals) + + while True: + new_partition = DisjointSet(*range(automaton.states)) + + ## Split each group if needed (use distinguish_states(group, automaton, partition)) + # Your code here + for gr in partition.groups: + for gr in distinguish_states(gr,automaton,partition) : + new_partition.merge(gr) + + if len(new_partition) == len(partition): + break + + partition = new_partition + + return partition + +def automata_minimization(automaton): + partition = state_minimization(automaton) + + states = [s for s in partition.representatives] + transitions = {} + + for i, state in enumerate(states): + # Your code here + origin = state.value + for symbol, destinations in automaton.transitions[origin].items(): + # Your code here + transition = states.index(partition[destinations[0]].representative) + + try: + transitions[i,symbol] + assert False + except KeyError: + # Your code here + transitions[i,symbol] = transition + + # Your code here + finals = set() + for gr in partition.groups: + for i in gr: + if i.value in automaton.finals: + finals.add(states.index(i.representative)) + start = states.index(partition[automaton.start].representative) + + return DFA(len(states), finals, transitions, start) + +def automata_full_determined(a1): + transitions = {} + + if a1.states * len(a1.vocabulary) == len(a1.map.items()): + for (origin, symbol), destinations in a1.map.items(): + # Your code here + transitions[origin,symbol] = [t for t in destinations] + + return NFA(a1.states,a1.finals,transitions,a1.start) + + + start = 0 + # final = a1.states + end = a1.states #final + 1 + + for (origin, symbol), destinations in a1.map.items(): + # Your code here + transitions[origin,symbol] = [t for t in destinations] + + + for i in range(end): + for x in a1.vocabulary: + try: + transitions[i,x] + except KeyError: + transitions[i,x] = [end] + + for v in a1.vocabulary: + try: + transitions[end,v].append(end) + except KeyError: + transitions[end,v] = [end] + + states = a1.states + 1 + finals = set(a1.finals) + + return NFA(states, finals, transitions, start) + +def automata_complement(a1): + a1 = automata_full_determined(a1) + transitions = {} + + start = a1.start + final = a1.states # a1.states estado epsilon + + for (origin, symbol), destinations in a1.map.items(): + # Your code here + transitions[origin,symbol] = [t for t in destinations] + + for x in filter(lambda x: not x in a1.finals, range(a1.states)): + transitions[x,''] = [final] + + states = a1.states + 1 + finals = { final } + + return NFA(states, finals, transitions, start) + +def automata_intersection(a1,a2): + return automata_complement(automata_union(automata_complement(a1),automata_complement(a2))) + +def automata_difference(a1,a2): + return automata_intersection(a1,automata_complement(a2)) + +def automata_reverse(a1): + transitions = {} + + start = a1.states + final = a1.start + + for (origin, symbol), destinations in a1.map.items(): + ## Relocate automaton transitions ... + # Your code here + for x in destinations: + try: + transitions[x,symbol].append(origin) + except KeyError: + transitions[x,symbol] = [origin] + + transitions[start,''] = [x for x in a1.finals] + + states = a1.states + 1 + finals = { final } + + return NFA(states, finals, transitions, start) diff --git a/src/cool_cmp/cmp_tools/utils/first_follow.py b/src/cool_cmp/cmp_tools/utils/first_follow.py new file mode 100644 index 000000000..df7f96a96 --- /dev/null +++ b/src/cool_cmp/cmp_tools/utils/first_follow.py @@ -0,0 +1,108 @@ +from cmp.utils import ContainerSet + +def compute_local_first(firsts, alpha): + first_alpha = ContainerSet() + try: + alpha_is_epsilon = alpha.IsEpsilon + except: + alpha_is_epsilon = False + ################################################### + # alpha == epsilon ? First(alpha) = { epsilon } + ################################################### + # # + if alpha_is_epsilon: + first_alpha.set_epsilon() + return first_alpha + ################################################### + ################################################### + # alpha = X1 ... XN + # First(X1) subconjunto First(alpha) + # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) + # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) + ################################################### + # # + change = False + for i in alpha: + if not firsts[i].contains_epsilon: + # epsilon pertenece a First(X1)...First(Xi) ? First(Xi+1) subconjunto de First(X) y First(alpha) + change = True + for j in firsts[i]: + first_alpha.add(j) + if change: + break + if not change: + # epsilon pertenece a First(X1)...First(XN) ? epsilon pertence a First(X) y al First(alpha) + first_alpha.set_epsilon() + ################################################### + # First(alpha) + return first_alpha + + +def compute_firsts(G): + + firsts = {} + change = True + # init First(Vt) + for terminal in G.terminals: + firsts[terminal] = ContainerSet(terminal) + # init First(Vn) + for nonterminal in G.nonTerminals: + firsts[nonterminal] = ContainerSet() + while change: + change = False + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + # get current First(X) + first_X = firsts[X] + # init First(alpha) + try: + first_alpha = firsts[alpha] + except KeyError: + first_alpha = firsts[alpha] = ContainerSet() + # CurrentFirst(alpha)??? + local_first = compute_local_first(firsts, alpha) + # update First(X) and First(alpha) from CurrentFirst(alpha) + change |= first_alpha.hard_update(local_first) + change |= first_X.hard_update(local_first) + # First(Vt) + First(Vt) + First(RightSides) + return firsts + +def compute_follows(G,firsts): + + follows = { } + change = True + local_firsts = { } + # init Follow(Vn) + for nonterminal in G.nonTerminals: + follows[nonterminal] = ContainerSet() + follows[G.startSymbol] = ContainerSet(G.EOF) + while change: + change = False + # P: X -> alpha + for production in G.Productions: + X = production.Left + alpha = production.Right + follow_X = follows[X] + ################################################### + # X -> zeta Y beta + # First(beta) - { epsilon } subset of Follow(Y) + # beta ->* epsilon or X -> zeta Y ? Follow(X) subset of Follow(Y) + ################################################### + # # + j = 0 + alpha2 = {} + for i in alpha: + alpha2[j] = i + j+=1 + for i in alpha2.keys(): + y = alpha2[i] + if y.IsNonTerminal: + local_firsts = compute_local_first(firsts,alpha[i+1:]) + change |= follows[y].update(local_firsts) + if local_firsts.contains_epsilon: + change |= follows[y].update(follow_X) + ################################################### + # Follow(Vn) + return follows \ No newline at end of file diff --git a/src/cool_cmp/cmp_tools/utils/trie.py b/src/cool_cmp/cmp_tools/utils/trie.py new file mode 100644 index 000000000..4fb056398 --- /dev/null +++ b/src/cool_cmp/cmp_tools/utils/trie.py @@ -0,0 +1,63 @@ +class TrieNode(): + + sons = None + value = None + terminal = None + + def __init__(self,value,terminal = False,sons = []): + self.value = value + self.sons = {} + self.terminal = terminal + for x in sons: + self.add_son(x) + + def add_son(self,item): + assert isinstance(item,TrieNode), "item must be a TrieNode" + self.sons[item.value] = item + + def find_son(self,son_value): + return self.sons[son_value] + + def __iter__(self): + yield self + for x in self.sons: + for y in self.sons[x]: + yield y + + def __str__(self): + rep = f'{self.value}[' + for x in self.sons: + rep += f'{self.sons[x]},' + rep += ']\n' + return rep + +class Trie: + top = None + + def __init__(self): + self.top = TrieNode('^') + + def LCP(self, item): + current = self.top + idx = 0 + for x in item: + try: + current = current.find_son(x) + idx += 1 + except KeyError: + break + return current,idx + + def add(self,item): + where_to,from_this = self.LCP(item) + for x in item[from_this:]: + new = TrieNode(x) + where_to.add_son(new) + where_to = new + where_to.terminal = True + + def __str__(self): + return str(self.top) + + def __iter__(self): + return self.top.__iter__() \ No newline at end of file diff --git a/src/cool_cmp/cool/__init__.py b/src/cool_cmp/cool/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/cool/ast/cool_ast.py b/src/cool_cmp/cool/ast/cool_ast.py new file mode 100644 index 000000000..ba45eb990 --- /dev/null +++ b/src/cool_cmp/cool/ast/cool_ast.py @@ -0,0 +1,276 @@ + +class Node: + def __init__(self,row=None,column=None): + self.row = row + self.column = column + +class ProgramNode(Node): + def __init__(self, declarations,row=None,column=None): + super().__init__(row,column) + self.declarations = declarations + + def __iter__(self): + for x in self.declarations: + yield from x + +class DeclarationNode(Node): + pass + +class ExpressionNode(Node): + pass + +class ClassDeclarationNode(DeclarationNode): + def __init__(self, idx, features, parent=None,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.parent = parent[0] if parent else 'Object' + self.parent_row = parent[1] if parent else -1 + self.parent_column = parent[2] if parent else -1 + self.features = features + + def __iter__(self): + yield self + for x in self.features: + yield from x + +class FuncDeclarationNode(DeclarationNode): + def __init__(self, idx, params, return_type, body,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.params = params + self.type = return_type[0] + self.type_row = return_type[1] + self.type_column = return_type[2] + self.body = body + + def __iter__(self): + yield self + yield from self.params + yield from self.body + +class AttrDeclarationNode(DeclarationNode): + def __init__(self, idx, typex, expr=None,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.type = typex + self.expr = expr + + def __iter__(self): + yield self + if self.expr: + yield from self.expr + +class ParamNode(DeclarationNode): + def __init__(self, idx, typex, row=None,column=None): + super().__init__(row,column) + self.id = idx + self.type = typex + + def __iter__(self): + yield self + +class SpecialNode(ExpressionNode): + def __init__(self, func,row=None,column=None, cil_node_type=None): + super().__init__(row,column) + self.func = func + self.cil_node_type = cil_node_type + + def __iter__(self): + yield self + +class VarDeclarationNode(ExpressionNode): + def __init__(self, idx, typex, expr,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.type = typex + self.expr = expr + + def __iter__(self): + yield self + if self.expr: + yield from self.expr + +class AssignNode(ExpressionNode): + def __init__(self, idx, expr,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.expr = expr + + def __iter__(self): + yield self + if self.expr: + yield from self.expr + +class CallNode(ExpressionNode): + def __init__(self, obj, idx, args,at_type,row=None,column=None): + super().__init__(row,column) + self.obj = obj + self.id = idx + self.args = args + self.at = at_type + + def __iter__(self): + yield from self.obj + for x in self.args: + yield from x + yield self + +class BlockNode(ExpressionNode): + def __init__(self, expr_list,row=None,column=None): + super().__init__(row,column) + self.expr_list = expr_list + + def __iter__(self): + yield self + for x in self.expr_list: + yield from x + +class ConditionalNode(ExpressionNode): + def __init__(self, condition,then_expr,else_expr,row=None,column=None): + super().__init__(row,column) + self.condition = condition + self.then_expr = then_expr + self.else_expr = else_expr + + def get_return_type(self,current_type): + else_type = self.else_expr.type + then_type = self.then_expr.type + return else_type.join(then_type,current_type) + + def __iter__(self): + yield self + for x in [self.condition,self.then_expr,self.else_expr]: + yield from x + +class CheckNode(ExpressionNode): + def __init__(self, idx, typex, expr,row=None,column=None): + super().__init__(row,column) + self.id = idx + self.type = typex + self.expr = expr + + def __iter__(self): + yield self + yield from self.expr + +class LetNode(ExpressionNode): + def __init__(self, dec_var_list, expr,row=None,column=None): + super().__init__(row,column) + self.params = dec_var_list + self.expr = expr + + def __iter__(self): + yield self + for x in self.params: + yield from x + + +class CaseNode(ExpressionNode): + def __init__(self, expr, check_list,row=None,column=None): + super().__init__(row,column) + self.expr = expr + self.params = check_list + + def __iter__(self): + yield self + yield from expr + for x in self.params: + yield from x + +class WhileNode(ExpressionNode): + def __init__(self, condition, expr,row=None,column=None): + super().__init__(row,column) + self.condition = condition + self.expr = expr + + def __iter__(self): + yield self + yield from expr + for x in self.params: + yield from x + +class AtomicNode(ExpressionNode): + def __init__(self, lex,row=None,column=None): + super().__init__(row,column) + self.lex = lex + + def __iter__(self): + yield self + +class UnaryNode(ExpressionNode): + def __init__(self, member,row=None,column=None): + super().__init__(row,column) + self.member = member + + def __iter__(self): + yield self + yield self.member + +class BinaryNode(ExpressionNode): + def __init__(self, left, right,row=None,column=None): + super().__init__(row,column) + self.left = left + self.right = right + + def __iter__(self): + yield self + yield self.left + yield self.right + +class StringNode(AtomicNode): + pass + +class BoolNode(AtomicNode): + pass + +class ConstantNumNode(AtomicNode): + pass + +class VoidNode(AtomicNode): + pass + +class VariableNode(AtomicNode): + pass + +class InstantiateNode(AtomicNode): + + def __init__(self, type, row=None,column=None): + super().__init__(type[0], row, column) + self.type_row = type[1] + self.type_column = type[2] + +class NotNode(UnaryNode): + pass + +class RoofNode(UnaryNode): + pass + +class IsVoidNode(UnaryNode): + pass + +class PlusNode(BinaryNode): + pass + +class MinusNode(BinaryNode): + pass + +class StarNode(BinaryNode): + pass + +class DivNode(BinaryNode): + pass + +class EqualNode(BinaryNode): + pass + +class GreaterNode(BinaryNode): + pass + +class GreaterEqualNode(BinaryNode): + pass + +class LesserNode(BinaryNode): + pass + +class LesserEqualNode(BinaryNode): + pass \ No newline at end of file diff --git a/src/cool_cmp/cool/errors/errors.py b/src/cool_cmp/cool/errors/errors.py new file mode 100644 index 000000000..84b31220b --- /dev/null +++ b/src/cool_cmp/cool/errors/errors.py @@ -0,0 +1,98 @@ +from error.errors import PositionError + +STRING_TOO_LONG = "String too long. Max length is 1024 chars, have {0} chars" + +SYNTACTIC_ERROR = 'at or near {0}' +REDEFINITION_BASIC_CLASS = 'Redefinition of basic class {0}.' +METHOD_REDEFINED_WRONG_SIGNATURE_PARAM = 'In redefined method {0}, parameter type {1} is different from original type {2}.' +METHOD_REDEFINED_WRONG_SIGNATURE_RETURN = "In redefined method {0}, return type {1} is different from original return type {2}." +METHOD_REDEFINED_WRONG_PARAM_AMOUNT = "Incompatible number of formal parameters in redefined method {0}." +SELF_IS_READONLY = 'Variable "self" is read-only.' +ASSIGN_SELF = "Cannot assign to 'self'." +LET_BOUND_SELF = "'self' cannot be bound in a 'let' expression." +PARAM_NAME_SELF = "'self' cannot be the name of a formal parameter." +ATTRIBUTE_NAME_SELF = "'self' cannot be the name of an attribute." +ATTRIBUTE_NOT_DEFINED = 'Attribute "{0}" is not defined in class "{1}".' +ATTRIBUTE_ALREADY_DEFINED = 'Attribute {0} is multiply defined in class.' +ATTRIBUTE_ALREADY_DEFINED_IN_PARENT = 'Attribute {0} is an attribute of an inherited class.' +LOCAL_ALREADY_DEFINED = 'Variable "{0}" is already defined in method "{1}".' +INCOMPATIBLE_TYPES = "Inferred type {0} of initialization of {1} does not conform to identifier's declared type {2}." +UNDEFINED_CLASS_CASE_BRANCH = 'Class {0} of case branch is undefined.' +UNDEFINED_PARAM_TYPE = "Class {0} of formal parameter {1} is undefined." +UNDEFINED_RETURN_TYPE = "Undefined return type {0} in method {1}." +UNDEFINED_NEW_TYPE = "'new' used with undefined class {0}." +ATTRIBUTE_INCOMPATIBLE_TYPES = 'Inferred type {2} of initialization of attribute {0} does not conform to declared type {1}.' +METHOD_INCOMPATIBLE_RETURN_TYPE = "Inferred return type {2} of method {0} does not conform to declared return type {1}." +VARIABLE_NOT_DEFINED = 'Undeclared identifier {0}.' +INVALID_UNARY_OPERATION = "Argument of '{0}' has type {1} instead of {2}." +INVALID_BINARY_OPERATION = 'non-{1} arguments: {1} {0} {2}' +NOT_BOOLEAN_CONDITION = "Predicate of 'if' does not have type Bool." +WHILE_NOT_BOOLEAN_CONDITION = "Loop condition does not have type Bool." +CIRCULAR_DEPENDENCY = 'Class {0}, or an ancestor of {0}, is involved in an inheritance cycle.' +VOID_TYPE_CONFORMS = "Void is not a valid type." +NO_OPERATION_DEFINDED = "No operations defined with operator {0} and types {1}." +MULTIPLE_OPERATION_DEFINED = "Multiple operations defined with operator {0} and types {1}." +CASE_NO_BRANCH_SELECTED = "No branch can be selected. Type {0} is not conformed by any of the branches." +NO_BOOL_CONDITION = "The condition value type is not Bool." +DISPATCH_VOID = "Can't dispatch a Void value." +DISPATCH_UNDEFINED_METHOD = "Dispatch to undefined method {0}." +DISPATCH_METHOD_WRONG_ARGS = "Method {0} called with wrong number of arguments." +STATIC_DISPATCH_INCOMPATIBLE_TYPES = "Expression type {0} does not conform to declared static dispatch type {1}." +INCOMPATIBLE_PARAMS_TYPES = "In call of method {0}, type {1} of parameter {2} does not conform to declared type {3}." +METHOD_NOT_DEFINED = "Method '{0}' is not defined{1} in '{2}' with {3} params." +METHOD_ALREADY_DEFINED = "Method {0} is multiply defined." +METHOD_REPEATED_ARGS_NAME = "Formal parameter {0} is multiply defined." +ATTRIBUTE_TYPE_UNDEFINED = "Class {0} of attribute {1} is undefined." +NO_ENTRY_POINT = "The program must define a 'main' method with no parameters in the 'Main' class" +NO_MAIN_TYPE = "The program must define a 'Main' type" +INVALID_EQUAL_BASIC_TYPE_OPERATION = "Illegal comparison with a basic type." +CASE_TYPES_REPEATED = "Duplicate branch {0} in case statement." +ZERO_DIVISION = "Divison by 0 not defined." +SUBSTR_OUT_RANGE = "Index out of range in substr, word:'{0}' substr begin:{1} substr length:{2}." +ATTRIBUTE_CANT_INFER = "No attribute '{0}' in inferred types." +METHOD_CANT_INFER = "No method '{0}' with {1} params in inferred types." +TYPE_NOT_DEFINED = "Type '{0}' is not defined." +LET_BOUND_TYPE_NOT_DEFINED = "Class {0} of let-bound identifier {1} is undefined." +TYPE_ALREADY_DEFINED = "Classes may not be redefined" +TYPE_CANT_INFER = "Cant infer type in given context." +TYPE_CANT_BE_INHERITED = "Class {0} cannot inherit class {1}." +UNDEFINED_INHERITED_TYPE = "Class {0} inherits from an undefined class {1}." +NO_COMMON_TYPE = "No common types between {0} and {1}" +READ_IS_NOT_INT = "Invalid type: {0} is not an Int" + +class LexerCoolError(PositionError): + """ + Error class for lexical errors + """ + + FORMAT = "({}, {}) - {}: {}" + + ERROR_TYPE = "LexicographicError" + +class SemanticError(PositionError): + """ + Error class for semantic errors + """ + + FORMAT = "({}, {}) - {}: {}" + ERROR_TYPE = "SemanticError" + +class SyntacticCoolError(PositionError): + """ + Error class for syntactic errors + """ + + ERROR_TYPE = "SyntacticError" + +class NameCoolError(SemanticError): + ERROR_TYPE = "NameError" + +class TypeCoolError(SemanticError): + ERROR_TYPE = "TypeError" + +class AttributeCoolError(SemanticError): + ERROR_TYPE = "AttributeError" + +class InferError(SemanticError): + ERROR_TYPE = "InferenceError" + diff --git a/src/cool_cmp/cool/grammar/comment_grammar.py b/src/cool_cmp/cool/grammar/comment_grammar.py new file mode 100644 index 000000000..6df5ca67c --- /dev/null +++ b/src/cool_cmp/cool/grammar/comment_grammar.py @@ -0,0 +1,18 @@ +from cmp.pycompiler import Grammar, NonTerminal, Terminal +from cool.ast.cool_ast import * + +C = Grammar() + +# non-terminals +text = C.NonTerminal('', startSymbol=True) +chunk = C.NonTerminal('') + +# Terminals +delimiter_open,delimiter_close, plain_text = C.Terminals('(* *) text') + +# productions +text %= chunk + delimiter_open + text + delimiter_close + text, lambda h,s: s[1] + s[5] +text %= chunk, lambda h,s: s[1] +chunk %= plain_text + chunk, lambda h,s: s[1][0] + s[2] +chunk %= C.Epsilon, lambda h,s: '' + diff --git a/src/cool_cmp/cool/grammar/cool_grammar.py b/src/cool_cmp/cool/grammar/cool_grammar.py new file mode 100644 index 000000000..2eda67024 --- /dev/null +++ b/src/cool_cmp/cool/grammar/cool_grammar.py @@ -0,0 +1,145 @@ +from cmp.pycompiler import Grammar, NonTerminal, Terminal +from cool.ast.cool_ast import * + +G = Grammar() + +# non-terminals +program = G.NonTerminal('', startSymbol=True) +class_list, def_class = G.NonTerminals(' ') +feature_list, def_attr, def_func, feature = G.NonTerminals(' ') +param_list, param, expr_list = G.NonTerminals(' ') +expr, boolean, compare, arith, term, factor, negate, atom = \ + G.NonTerminals(' ') +func_call, arg_list, dispatch = G.NonTerminals(' ') +def_var, def_var_list = G.NonTerminals(' ') +case_check, case_check_list = G.NonTerminals(' ') +param_list_not_empty, arg_list_not_empty = G.NonTerminals(' ') + +# Terminals + +ifx,then,elsex,if_r,whilex,loop,loop_r = G.Terminals('if then else fi while loop pool') +ocur,ccur,colon,semi,comma, dot = G.Terminals('{ } : ; , .') +opar,cpar,plus,minus,div,star,notx,roof = G.Terminals('( ) + - / * not ~') +less,less_eq,greater,greater_eq,equal = G.Terminals('< <= > >= =') +let,inx,case,of,case_r,arrow,assign = G.Terminals('let in case of esac => <-') +true,false,num,string = G.Terminals('true false num string') +classx, inherits, new, isvoid = G.Terminals('class inherits new isvoid') +idx,typex,at = G.Terminals('id type @') # 'at' is @ +comment_open, comment_close = G.Terminals('(* *)') + +# productions +program %= class_list, lambda h,s: ProgramNode(s[1],row=0,column=0) + +# ??? +class_list %= def_class, lambda h,s: [s[1]] +class_list %= def_class + class_list, lambda h,s: [s[1]] + s[2] + +# ??? +def_class %= classx + typex + ocur + feature_list + ccur + semi, lambda h,s: ClassDeclarationNode(s[2][0],s[4],row=s[1][1] ,column=s[1][2]) +def_class %= classx + typex + inherits + typex + ocur + feature_list + ccur + semi, lambda h,s: ClassDeclarationNode(s[2][0],s[6],s[4],row=s[1][1] ,column=s[1][2]) + +def_class %= classx + typex + ocur + ccur + semi, lambda h,s: ClassDeclarationNode(s[2][0],[],row=s[1][1] ,column=s[1][2]) +def_class %= classx + typex + inherits + typex + ocur + ccur + semi, lambda h,s: ClassDeclarationNode(s[2][0],[],s[4],row=s[1][1] ,column=s[1][2]) + +# ??? +feature_list %= feature + semi, lambda h,s: [s[1]] +feature_list %= feature + semi + feature_list, lambda h,s: [s[1]] + s[3] + +# ??? +feature %= def_attr, lambda h,s: s[1] +feature %= def_func, lambda h,s: s[1] + +# ??? +def_attr %= idx + colon + typex, lambda h,s: AttrDeclarationNode(s[1][0],s[3][0],row=s[1][1] ,column=s[1][2]) +def_attr %= idx + colon + typex + assign + expr, lambda h,s: AttrDeclarationNode(s[1][0],s[3][0],s[5],row=s[1][1] ,column=s[1][2]) + +# ??? +def_func %= idx + opar + param_list + cpar + colon + typex + ocur + expr + ccur, lambda h,s: FuncDeclarationNode(s[1][0],s[3],s[6],s[8],row=s[1][1] ,column=s[1][2]) + +param_list %= G.Epsilon, lambda h,s: [ ] +param_list %= param_list_not_empty, lambda h,s: s[1] +param_list_not_empty %= param, lambda h,s: [ s[1] ] +param_list_not_empty %= param_list_not_empty + comma + param, lambda h,s: s[1] + [ s[3] ] + +# ??? +param %= idx + colon + typex, lambda h,s: ParamNode(s[1][0],s[3][0],row=s[1][1],column = s[1][2]) + +def_var %= idx + colon + typex + assign + expr, lambda h,s: VarDeclarationNode(s[1][0],s[3][0],s[5],row=s[1][1] ,column=s[1][2]) +def_var %= idx + colon + typex, lambda h,s: VarDeclarationNode(s[1][0],s[3][0],None,row=s[1][1] ,column=s[1][2]) + +def_var_list %= def_var, lambda h,s: [ s[1] ] +def_var_list %= def_var_list + comma + def_var, lambda h,s: s[1] + [ s[3] ] + +case_check %= idx + colon + typex + arrow + expr + semi, lambda h,s: CheckNode(s[1][0],s[3][0],s[5],row=s[1][1] ,column=s[1][2]) + +case_check_list %= case_check, lambda h,s: [ s[1] ] +case_check_list %= case_check + case_check_list, lambda h,s: [ s[1] ] + s[2] + + +# ??? +expr %= idx + assign + expr, lambda h,s: AssignNode(s[1][0],s[3],row=s[1][1] ,column=s[1][2]) +# expr %= idx + colon + typex + assign + expr, lambda h,s: VarDeclarationNode(s[1][0],s[3][0],s[5],row=s[1][1] ,column=s[1][2]) +expr %= boolean, lambda h,s: s[1] +expr %= ocur + expr_list + ccur, lambda h,s: BlockNode(s[2],row=s[1][1] ,column=s[1][2]) +expr %= let + def_var_list + inx + expr, lambda h,s: LetNode(s[2],s[4],row=s[1][1] ,column=s[1][2]) +expr %= case + expr + of + case_check_list + case_r, lambda h,s: CaseNode(s[2],s[4],row=s[1][1] ,column=s[1][2]) +expr %= whilex + expr + loop + expr + loop_r, lambda h,s: WhileNode(s[2],s[4],row=s[1][1] ,column=s[1][2]) + +# ??? +expr_list %= expr + semi, lambda h,s: [ s[1] ] +expr_list %= expr + semi + expr_list, lambda h,s: [ s[1] ] + s[3] + +# ??? +boolean %= notx + boolean, lambda h,s: NotNode(s[2],s[1][1],s[1][2]) +boolean %= compare, lambda h,s: s[1] + +# ??? +compare %= arith + equal + boolean , lambda h,s: EqualNode(s[1],s[3],s[2][1],s[2][2]) +compare %= arith + less + boolean , lambda h,s: LesserNode(s[1],s[3],s[2][1],s[2][2]) +compare %= arith + less_eq + boolean , lambda h,s: LesserEqualNode(s[1],s[3],s[2][1],s[2][2]) +compare %= arith + greater + boolean , lambda h,s: GreaterNode(s[1],s[3],s[2][1],s[2][2]) +compare %= arith + greater_eq + boolean, lambda h,s: GreaterEqualNode(s[1],s[3],s[2][1],s[2][2]) +compare %= arith, lambda h,s: s[1] + +# ??? +arith %= arith + plus + term, lambda h,s: PlusNode(s[1],s[3],row=s[2][1] ,column=s[2][2]) +arith %= arith + minus + term, lambda h,s: MinusNode(s[1],s[3],row=s[2][1] ,column=s[2][2]) +arith %= term, lambda h,s: s[1] + +# ??? +term %= term + star + factor, lambda h,s: StarNode(s[1],s[3],row=s[2][1] ,column=s[2][2]) +term %= term + div + factor, lambda h,s: DivNode(s[1],s[3],row=s[2][1] ,column=s[2][2]) +term %= factor, lambda h,s: s[1] + +# ??? +factor %= isvoid + negate, lambda h,s: IsVoidNode(s[2],row=s[1][1] ,column=s[1][2]) +factor %= negate, lambda h,s: s[1] + +# +negate %= roof + negate, lambda h,s: RoofNode(s[2],row=s[1][1] ,column=s[1][2]) +negate %= dispatch, lambda h,s: s[1] + +# +dispatch %= dispatch + at + typex + dot + func_call, lambda h,s: CallNode(s[1],s[5][1],s[5][2],s[3][0],row=s[5][3] ,column=s[5][4]) +dispatch %= dispatch + dot + func_call, lambda h,s: CallNode(s[1],s[3][1],s[3][2],None,row=s[3][3] ,column=s[3][4]) +dispatch %= atom, lambda h,s: s[1] + +# ??? +atom %= num, lambda h,s: ConstantNumNode(s[1][0],row=s[1][1] ,column=s[1][2]) +atom %= string, lambda h,s: StringNode(s[1][0],row=s[1][1] ,column=s[1][2]) +atom %= true, lambda h,s: BoolNode(s[1][0],row=s[1][1] ,column=s[1][2]) +atom %= false, lambda h,s: BoolNode(s[1][0],row=s[1][1] ,column=s[1][2]) +atom %= idx, lambda h,s: VariableNode(s[1][0],row=s[1][1] ,column=s[1][2]) +atom %= new + typex, lambda h,s: InstantiateNode(s[2],row=s[1][1] ,column=s[1][2]) +atom %= func_call, lambda h,s: CallNode(s[1][0],s[1][1],s[1][2],None,row=s[1][3] ,column=s[1][4]) +# atom %= at + typex + dot + func_call, lambda h,s: CallNode(s[4][0],s[4][1],s[4][2],s[2][0],row=s[4][3] ,column=s[4][4]) +atom %= opar + expr + cpar, lambda h,s: s[2] +atom %= ifx + expr + then + expr + elsex + expr + if_r, lambda h,s: ConditionalNode(s[2],s[4],s[6],row=s[1][1] ,column=s[1][2]) + +# ??? +func_call %= idx + opar + arg_list + cpar, lambda h,s: (VariableNode('self',s[1][1],s[1][2]),s[1][0],s[3],s[1][1],s[1][2]) + +arg_list %= G.Epsilon, lambda h,s: [ ] +arg_list %= arg_list_not_empty, lambda h,s: s[1] +arg_list_not_empty %= expr, lambda h,s: [ s[1] ] +arg_list_not_empty %= arg_list_not_empty + comma + expr, lambda h,s: s[1] + [ s[3] ] diff --git a/src/cool_cmp/cool/lexer/comment_lexer.obj b/src/cool_cmp/cool/lexer/comment_lexer.obj new file mode 100644 index 000000000..4223c828a Binary files /dev/null and b/src/cool_cmp/cool/lexer/comment_lexer.obj differ diff --git a/src/cool_cmp/cool/lexer/comment_lexer.py b/src/cool_cmp/cool/lexer/comment_lexer.py new file mode 100644 index 000000000..58508093d --- /dev/null +++ b/src/cool_cmp/cool/lexer/comment_lexer.py @@ -0,0 +1,28 @@ +from cool.lexer.cool_lexer import Lexer, save_lexer, load_lexer, lower_case,upper_case,numbers +from cool.grammar.comment_grammar import delimiter_close,delimiter_open,plain_text,C + +text = f'[{lower_case}{upper_case}_{numbers}\n\r\b\f\t\v"~`\'!,:;<@=> \\[\\]\\*/-\\+.\\?\\(\\)\\\\#$%^&\\|'+'{}'+']*' +tex = text.replace('\\(\\)','').replace('\\*','') + +tex3 = f'[(\\*+(\\()*)(\\(+(\\))*)\\)+]' # ( \\(\\* | \\*\\) )^C +tex3 = tex + f'|{tex3}' +tex1 = '\\(\\*' +tex2 = '\\*\\)' + +comment_tokens_def = [ + (plain_text, tex3), + (delimiter_open, tex1), + (delimiter_close, tex2), + ] + +# comment_lexer = Lexer(comment_tokens_def,C.EOF) + +import os +base_dir = os.path.dirname(__file__) +comment_lexer_path = os.path.join(base_dir, 'comment_lexer.obj') +# comment_lexer = save_lexer(comment_tokens_def,comment_lexer_path,C) +comment_lexer = None +try: + comment_lexer = load_lexer(comment_lexer_path) +except Exception as e: + print(e) \ No newline at end of file diff --git a/src/cool_cmp/cool/lexer/cool_lexer.obj b/src/cool_cmp/cool/lexer/cool_lexer.obj new file mode 100644 index 000000000..f0c60d55e Binary files /dev/null and b/src/cool_cmp/cool/lexer/cool_lexer.obj differ diff --git a/src/cool_cmp/cool/lexer/cool_lexer.py b/src/cool_cmp/cool/lexer/cool_lexer.py new file mode 100644 index 000000000..f60dcab9f --- /dev/null +++ b/src/cool_cmp/cool/lexer/cool_lexer.py @@ -0,0 +1,54 @@ +from cool.grammar.cool_grammar import * +from cool.lexer.utils import * + +# Keyword are case in sensitive except for true and false that the first letter must be lower case +keywords = [ + (ifx, '[iI][fF]'), (if_r, '[fF][iI]'), (then, '[tT][hH][eE][nN]'), + (elsex, '[eE][lL][sS][eE]'), (isvoid, '[iI][sS][vV][oO][iI][dD]'), + (new, '[nN][eE][wW]'), (whilex, '[wW][hH][iI][lL][eE]'), + (loop, '[lL][oO][oO][pP]'), (loop_r, '[pP][oO][oO][lL]'), + (classx, '[cC][lL][aA][sS][sS]'), (let, '[lL][eE][tT]'), + (inx, '[iI][nN]'), (case, '[cC][aA][sS][eE]'), (of, '[oO][fF]'), + (case_r, '[eE][sS][aA][cC]'), (inherits, '[iI][nN][hH][eE][rR][iI][tT][sS]'), + (true, 't[rR][uU][eE]'), (false, 'f[aA][lL][sS][eE]') + ] + +operators = [ + (dot, '.'),(plus, '\\+'),(minus, '-'),(div, '/'), + (star, '\\*'),(notx, 'not'),(roof, '~'),(less, '<'), + (less_eq, '<='),(greater, '>'),(greater_eq, '>='), + (equal, '='),(assign, '<-'),(arrow, '=>'),(at, '@'), + ] + +signs = [ + (opar, '\\('),(cpar, '\\)'),(ocur, '{'),(ccur ,'}'), + (colon, ':'),(semi, ';'),(comma,','), + ] + +lower_case = 'qwertyuiopasdfghjklzxcvbnm' +upper_case = 'QWERTYUIOPASDFGHJKLZXCVBNM' +numbers = '1234567890' +text = f'[{lower_case}{upper_case}_{numbers}~`\'!,:;<@=>≤”“ \\[\\]\\*/-\\+.\\?\\(\\)\\\\#$%^&\\|'+'{}'+']*' + +ignore = [('space',f'[ \n\r\b\f\t\v]+|(--({text}|")*\n)')] + +other = [ + (comment_open, "\\(\\*"), + (comment_close, "\\*\\)"), + (idx, f'[{lower_case}][{lower_case}{upper_case}_{numbers}]*'), + (typex, f'[{upper_case}][{lower_case}{upper_case}_{numbers}]*'), + (num, f'[123456789][{numbers}]*(.[{numbers}]+)?|0'), + (string, f'"{text}"') + ] +cool_tokens_def = keywords+operators+signs+other+ignore +# cool_lexer = Lexer(cool_token_def,G.EOF) + +import os +base_dir = os.path.dirname(__file__) +cool_lexer_path = os.path.join(base_dir, 'cool_lexer.obj') +# cool_lexer = save_lexer(cool_tokens_def,cool_lexer_path,G) +cool_lexer = None +try: + cool_lexer = load_lexer(cool_lexer_path) +except Exception as e: + print(e) \ No newline at end of file diff --git a/src/cool_cmp/cool/lexer/ply_cool_lexer.py b/src/cool_cmp/cool/lexer/ply_cool_lexer.py new file mode 100644 index 000000000..14527f5d8 --- /dev/null +++ b/src/cool_cmp/cool/lexer/ply_cool_lexer.py @@ -0,0 +1,376 @@ +from typing import List, Tuple + +from error.error_tracker import ErrorTracker +from cool.errors.errors import LexerCoolError +from cool.grammar import cool_grammar as cool_G +import ply.lex as lex + +class Lex(): + def __init__(self, lex): + self.lex = lex + + def set_type(self, new): + self.type = new + + def set_row(self, new): + self.row = new + + def set_column(self, new): + self.column = new + + def __str__(self): + return self.lex + + def __getitem__(self, i): + if i == 0: + return self.lex + + elif i == 1: + return self.row + + elif i == 2: + return self.column + + elif i == 3: + return self.type + +class PlyCoolToken(lex.LexToken): + + def __init__(self, lex:str, typex, line:int, column:int, is_eof=False): + self.set_lex(lex) + self.set_type(typex) + self.set_position(line, column) + self.__is_eof = is_eof + + @property + def is_eof(self): + return self.__is_eof + + def set_lex(self, lex:str): + self.lex = Lex(lex) + self.value = Lex(lex) + + def set_type(self, typex:str): + self.lex.set_type(typex) + self.value.set_type(typex) + self.type = typex + self.token_type = typex + self.typex = typex + + def set_position(self, line:int, column:int): + self.lex.set_row(line) + self.value.set_row(line) + self.lex.set_column(column) + self.value.set_column(column) + self.lineno = line + self.line = line + self.column = column + self.lexpos = column + + def get_lex(self)->str: + return self.lex + + def get_type(self)->str: + return self.typex + + def get_position(self)->Tuple[int,int]: + return (self.line, self.column) + + def __str__(self): + return f"{self.lex}:{self.type} Line {self.line} Column{self.column}" + + def __repr__(self): + return str(self) + +class PlyLexer(): + + @staticmethod + def find_column(input, token): + line_start = input.rfind('\n', 0, token.lexpos) + 1 + return (token.lexpos - line_start) + 1 + + def __init__(self): + self.error_tracker = ErrorTracker() # Error tracker implementation + + reserved = { + 'if' : 'IF', + 'then' : 'THEN', + 'fi' : 'FI', + 'else' : 'ELSE', + 'case' : 'CASE', + 'of' : 'OF', + 'esac' : 'ESAC', + 'class' : 'CLASS', + 'inherits' : 'INHERITS', + 'let' : 'LET', + 'in' : 'IN', + 'while' : 'WHILE', + 'loop' : 'LOOP', + 'pool' : 'POOL', + 'new' : 'NEW', + 'isvoid' : 'ISVOID', + 'not' : 'NOT', + 'true' : 'TRUE', + 'false' : 'FALSE' + } + + tokens = ( + 'OBJECTID', + 'TYPEID', + 'NUMBER', + 'PLUS', + 'MINUS', + 'STAR', + 'DIV', + 'EQ', + 'LEQ', + 'LESS', + 'NEG', + 'OPAR', + 'CPAR', + 'OCUR', + 'CCUR', + 'ASSIGN', + 'SEMI', + 'COLON', + 'SIGNALER', + 'ARROBA', + 'STRING', + 'COMMENT', + 'DOT', + 'COMMA' + ) + tuple(reserved[x] for x in reserved.keys()) + + + self.terminals = { + 'IF' : cool_G.ifx, + 'THEN' : cool_G.then, + 'ELSE' : cool_G.elsex, + 'FI' : cool_G.if_r, + 'WHILE' : cool_G.whilex, + 'LOOP' : cool_G.loop, + 'POOL' : cool_G.loop_r, + 'OCUR' : cool_G.ocur, + 'CCUR' : cool_G.ccur, + 'COLON' : cool_G.colon, + 'SEMI' : cool_G.semi, + 'COMMA' : cool_G.comma, + 'DOT' : cool_G.dot, + 'OPAR' : cool_G.opar, + 'CPAR' : cool_G.cpar, + 'PLUS' : cool_G.plus, + 'MINUS' : cool_G.minus, + 'DIV' : cool_G.div, + 'STAR' : cool_G.star, + 'NOT' : cool_G.notx, + 'NEG' : cool_G.roof, + 'LESS' : cool_G.less, + 'LEQ' : cool_G.less_eq, + # 'GREAT' : cool_G.greater, + # 'GEQ' : cool_G.greater_eq, + 'EQ' : cool_G.equal, + 'LET' : cool_G.let, + 'IN' : cool_G.inx, + 'CASE' : cool_G.case, + 'OF' : cool_G.of, + 'ESAC' : cool_G.case_r, + 'SIGNALER' : cool_G.arrow, + 'ASSIGN' : cool_G.assign, + 'TRUE' : cool_G.true, + 'FALSE' : cool_G.false, + 'NUMBER' : cool_G.num, + 'STRING' : cool_G.string, + 'CLASS' : cool_G.classx, + 'INHERITS' : cool_G.inherits, + 'NEW' : cool_G.new, + 'ISVOID' : cool_G.isvoid, + 'OBJECTID' : cool_G.idx, + 'TYPEID' : cool_G.typex, + 'ARROBA' : cool_G.at, + 'COMMENT' : cool_G.comment_open, + 'COMMENT' : cool_G.comment_close} + + # def t_COMMENTMULTI(t): + # r'\(\*(.|\n)*?\*\)' + # t.lexer.lineno += t.value.count("\n") + + # def t_COMMENTMULTIUNFINISHED(t): + # r'\(\*(.|\n)*' + # t.lexer.lineno += t.value.count("\n") + # msg = 'EOF in comment' + # self.add_error(LexerCoolError(msg, token = PlyCoolToken(t.value, t.type, t.lexer.lineno - 1, t.lexer.lexpos - 1))) + + def t_STRING(t): + r'"([^\r\n"\\]|(\\\n)|(\\.)){0,1024}"' + t.lexer.lineno += t.value.count("\n") + null_ch = 'String contains null character' + for i in range(len(t.value)): + if t.value[i] == '\x00': + pos = t.lexer.lexpos - (len(t.value) - i) + line = t.lexer.lineno - t.value[:i].count("\n") + self.add_error(LexerCoolError(null_ch, token = PlyCoolToken(t.value, t.type, line, pos))) + return t + + def t_STRINGUNFINISHED(t): + r'"([^\r\n"\\]|(\\\n)|(\\.)){0,1024}\n' + t.lexer.lineno += t.value.count("\n") + null_ch = 'String contains null character' + for i in range(len(t.value)): + if t.value[i] == '\x00': + pos = t.lexer.lexpos - (len(t.value) - i) + line = t.lexer.lineno - t.value[:i].count("\n") + self.add_error(LexerCoolError(null_ch, token = PlyCoolToken(t.value, t.type, line, pos))) + msg = 'Unterminated string constant' + self.add_error(LexerCoolError(msg, token = PlyCoolToken(t.value, t.type, t.lexer.lineno - 1, t.lexer.lexpos - 1))) + + def t_STRINGUNFINISHEDEOF(t): + r'"([^\r\n"\\]|(\\\n)|(\\.)){0,1024}' + t.lexer.lineno += t.value.count("\n") + null_ch = 'String contains null character' + for i in range(len(t.value)): + if t.value[i] == '\x00': + pos = t.lexer.lexpos - (len(t.value) - i) + line = t.lexer.lineno - t.value[:i].count("\n") + self.add_error(LexerCoolError(null_ch, token = PlyCoolToken(t.value, t.type, line, pos))) + msg = 'EOF in string constant' + self.add_error(LexerCoolError(msg, token = PlyCoolToken(t.value, t.type, t.lexer.lineno, t.lexer.lexpos))) + + def t_NUMBER(t): + r'\d+' + try: + int(t.value) + except ValueError: + msg = "Integer value too large %d", t.value + self.add_error(LexerCoolError(msg, token = PlyCoolToken(t.value, t.type, t.lineno, t.lexpos))) + t.value = 'Invalid' + return t + + def t_OBJECTID(t): + r'[a-z][a-zA-Z0-9_]*' + low = t.value.lower() + t.type = reserved.get(low,'OBJECTID') + return t + + def t_TYPEID(t): + r'[A-Z][a-zA-Z0-9_]*' + low = t.value.lower() + if low == 'true': + t.type = 'TYPEID' + + elif low == 'false': + t.type = 'TYPEID' + + else: + t.type = reserved.get(low, 'TYPEID') + + return t + + def t_COMMENTSINGLE(t): + r'(--.*)' + + + t_PLUS = r'\+' + t_MINUS = r'-' + t_STAR = r'\*' + t_DIV = r'/' + t_OPAR = r'\(' + t_CPAR = r'\)' + t_OCUR = r'\{' + t_CCUR = r'\}' + t_EQ = r'=' + t_ASSIGN = r'<-' + t_LEQ = r'<=' + t_LESS = r'<' + t_NEG = r'~' + t_SEMI = r';' + t_COLON = r':' + t_SIGNALER = r'=>' + t_ARROBA = r'@' + t_DOT = r'\.' + t_COMMA = r',' + + t_ignore = " \t" + + def t_newline(t): + r'\n+' + t.lexer.lineno += t.value.count("\n") + + def t_error(t): + msg = f'ERROR "{t.value[0]}"' + self.add_error(LexerCoolError(msg, token = PlyCoolToken(t.value[0], t.type, t.lineno, t.lexpos))) + t.lexer.skip(1) + + self.lexer = lex.lex() + + def __call__(self, program_string:str): + self.error_tracker = ErrorTracker() + count = 0 + lines = 0 + passes = 0 + semi_clean_string = [] + for i in range(len(program_string)): + if passes > 0: + passes -= 1 + elif program_string[i] == '(' and i + 1 < len(program_string) and program_string[i + 1] == '*': + count += 1 + semi_clean_string.append(' ') + semi_clean_string.append(' ') + if i + 2 < len(program_string) and program_string[i + 2] == ')': + semi_clean_string.append(' ') + passes = 2 + + else: + passes = 1 + + elif program_string[i] == '*' and i + 1 < len(program_string) and program_string[i + 1] == ')' and count > 0: + count -= 1 + semi_clean_string.append(' ') + semi_clean_string.append(' ') + passes = 1 + + elif count > 0 and program_string[i] != '\n': + semi_clean_string.append(' ') + + elif program_string[i] == '\n': + semi_clean_string.append(program_string[i]) + lines += 1 + + else: + semi_clean_string.append(program_string[i]) + + clean = ''.join(semi_clean_string) + # print(clean) + # print(len(clean)) + # print(len(program_string)) + self.lexer.input(clean) + result = [] + base_line = -1 + while True: + tok = self.lexer.token() + # if base_line < 0: + # base_line = tok.lineno - 1 + + if not tok: + break + result.append(PlyCoolToken(tok.value, tok.type, tok.lineno, self.find_column(program_string, tok))) + + if count > 0: + self.add_error(LexerCoolError('EOF in comment', token = PlyCoolToken('', '', lines + 1, len(program_string)))) + + for error in self.error_tracker.get_errors(): + error.token.set_position(error.token.lineno, self.find_column(program_string, error.token)) + + for token in result: + token.set_type(self.terminals[token.token_type]) + + result.append(PlyCoolToken('EOF', cool_G.G.EOF, lines + 1, len(program_string), True)) + result[-1].set_position(result[-1].line, self.find_column(program_string, result[-1])) + + return result + + def add_error(self, error:LexerCoolError): + self.error_tracker.add_error(error) + + def get_errors(self)->List[LexerCoolError]: + errors = self.error_tracker.get_errors() + return errors diff --git a/src/cool_cmp/cool/lexer/utils.py b/src/cool_cmp/cool/lexer/utils.py new file mode 100644 index 000000000..2993e7f0c --- /dev/null +++ b/src/cool_cmp/cool/lexer/utils.py @@ -0,0 +1,19 @@ +from cmp_tools.lexer.lexer import DetailLexer as Lexer +import pickle + +def save_lexer(table,path,G): + with open(path,'wb') as f: + attributes = [] + for prod in G.Productions: + attributes.append(prod.attributes) + prod.__delattr__('attributes') + lexer = Lexer(table,G.EOF) + pickle.dump(lexer,f,pickle.HIGHEST_PROTOCOL) + for prod,attr in zip(G.Productions,attributes): + prod.attributes = attr + return lexer + +def load_lexer(path): + with open(path,'rb') as f: + lexer = pickle.load(f) + return lexer diff --git a/src/cool_cmp/cool/lib/std.cl b/src/cool_cmp/cool/lib/std.cl new file mode 100644 index 000000000..e2756418a --- /dev/null +++ b/src/cool_cmp/cool/lib/std.cl @@ -0,0 +1,57 @@ +-- Standar Cool Library +-- Some methods changed when building the ast to provide a python implementation for it +class Object { + abort() : Object{ + self + }; + + type_name() : String { + "Object" + }; + + copy() : SELF_TYPE { + self + }; +}; + +class String inherits Object { + + length() : Int { 0 }; + concat(s : String) : String { s }; + substr(i : Int, l : Int) : String { "string" }; +}; + +class IO inherits Object { + out_string(x : String) : SELF_TYPE { self }; + out_int(x : Int) : SELF_TYPE { self }; + in_string() : String { "string" }; + in_int() : Int { 0 }; +}; + +class Int inherits Object { + abort() : Object{ + let io:IO <- new IO in { + io.out_string("Abort called from class Int") + @Object.abort(); + } + }; + + type_name() : String { + "Int" + }; +}; + +class Bool inherits Object { + abort() : Object{ + let io:IO <- new IO in { + io.out_string("Abort called from class Bool") + @Object.abort(); + } + }; + + type_name() : String { + "Bool" + }; + }; + +class Void { }; \ No newline at end of file diff --git a/src/cool_cmp/cool/parser/comment_parser.obj b/src/cool_cmp/cool/parser/comment_parser.obj new file mode 100644 index 000000000..7ee11f469 Binary files /dev/null and b/src/cool_cmp/cool/parser/comment_parser.obj differ diff --git a/src/cool_cmp/cool/parser/comment_parser.py b/src/cool_cmp/cool/parser/comment_parser.py new file mode 100644 index 000000000..1ab9c988f --- /dev/null +++ b/src/cool_cmp/cool/parser/comment_parser.py @@ -0,0 +1,13 @@ +from cool.grammar.comment_grammar import C +from cool.parser.utils import load_parser, save_parser + +import os +base_dir = os.path.dirname(__file__) +comment_parser_path = os.path.join(base_dir, 'comment_parser.obj') +# comment_parser = save_parser(comment_parser_path,C) +# print('Errors',comment_parser.errors) +comment_parser = None +try: + comment_parser = load_parser(comment_parser_path,C) +except Exception as e: + print(e) \ No newline at end of file diff --git a/src/cool_cmp/cool/parser/cool_parser.obj b/src/cool_cmp/cool/parser/cool_parser.obj new file mode 100644 index 000000000..c2a2d54c0 Binary files /dev/null and b/src/cool_cmp/cool/parser/cool_parser.obj differ diff --git a/src/cool_cmp/cool/parser/cool_parser.py b/src/cool_cmp/cool/parser/cool_parser.py new file mode 100644 index 000000000..07aeca598 --- /dev/null +++ b/src/cool_cmp/cool/parser/cool_parser.py @@ -0,0 +1,13 @@ +from cool.grammar.cool_grammar import G +from cool.parser.utils import load_parser, save_parser + +import os +base_dir = os.path.dirname(__file__) +cool_parser_path = os.path.join(base_dir, 'cool_parser.obj') +# cool_parser = save_parser(cool_parser_path,G) +# print('Errors',cool_parser.errors) +cool_parser = None +try: + cool_parser = load_parser(cool_parser_path,G) +except Exception as e: + print(e) \ No newline at end of file diff --git a/src/cool_cmp/cool/parser/utils.py b/src/cool_cmp/cool/parser/utils.py new file mode 100644 index 000000000..8b97d20a7 --- /dev/null +++ b/src/cool_cmp/cool/parser/utils.py @@ -0,0 +1,25 @@ +from cmp.pycompiler import Production +from cmp_tools.lang.language_lr import LanguageLR,LR1Parser,LALR1Parser +import pickle + +def save_parser(path,G): + pType = G.pType + G.pType = Production + attributes = [] + for prod in G.Productions: + attributes.append(prod.attributes) + prod.__delattr__('attributes') + parser = LALR1Parser(G) + with open(path,'wb') as f: + pickle.dump(parser,f,pickle.HIGHEST_PROTOCOL) + for prod,attr in zip(parser.grammar.Productions,attributes): + prod.attributes = attr + G.pType = pType + return parser + +def load_parser(path,G): + with open(path,'rb') as f: + parser = pickle.load(f) + for prod,prod2 in zip(parser.grammar.Productions,G.Productions): + prod.attributes = prod2.attributes + return parser diff --git a/src/cool_cmp/cool/semantic/atomic.py b/src/cool_cmp/cool/semantic/atomic.py new file mode 100644 index 000000000..1e3611cfb --- /dev/null +++ b/src/cool_cmp/cool/semantic/atomic.py @@ -0,0 +1,50 @@ +class ClassInstance: + def __init__(self,typex, context, operator, errors,**kwargs): + self.type = typex + self.context = context + self.operator = operator + self.errors = errors + self.scope = typex.class_node.scope.instance_copy(typex,context,operator,errors) + self.scope.set_variable_value('self',self) + if 'value' in kwargs: + self.value = kwargs['value'] + + def __eq__(self, other): + if self.type.name == "Void" and other.type.name == "Void": + return True + else: + return super().__eq__(other) + + def __hash__(self): + if self.type.name == "Void": + return 0 + else: + return super().__hash__() + + def copy(self): + if hasattr(self,'value'): + instance = ClassInstance(self.type,self.context,self.operator,self.errors,value=self.value) + else: + instance = ClassInstance(self.type,self.context,self.operator,self.errors) + instance.scope = self.scope.copy() + return instance + + def shallow_copy(self): + if hasattr(self,'value'): + instance = ClassInstance(self.type,self.context,self.operator,self.errors,value=self.value) + else: + instance = ClassInstance(self.type,self.context,self.operator,self.errors) + instance.scope.locals = [] + for var_info in self.scope.locals: + var = instance.scope.define_variable(var_info.name,var_info.type) + if hasattr(var_info,'value'): + if hasattr(var_info.value,'value'): + var.value = ClassInstance(var_info.value.type,var_info.value.context,var_info.value.operator,var_info.value.errors,value=var_info.value.value) + else: + var.value = var_info.value + return instance + + def __str__(self): + if hasattr(self,'value'): + return f'{self.value}: {self.type.name}' + return f'{self.type.name} instance' \ No newline at end of file diff --git a/src/cool_cmp/cool/semantic/operations.py b/src/cool_cmp/cool/semantic/operations.py new file mode 100644 index 000000000..b4aa1237f --- /dev/null +++ b/src/cool_cmp/cool/semantic/operations.py @@ -0,0 +1,192 @@ +from error.errors import RunError +from cool.errors.errors import SemanticError, NO_OPERATION_DEFINDED, MULTIPLE_OPERATION_DEFINED, ZERO_DIVISION +from cool.ast.cool_ast import * +from semantic.type import * +from cool.semantic.atomic import * + +class Operator: + + def __init__(self,context,errors): + object_type = context.get_type('Object') + int_type = context.get_type('Int') + string_type = context.get_type('String') + bool_type = context.get_type('Bool') + void_type = context.get_type('Void') + self.operations = OperationDict({ + ('~',(int_type,)):(lambda x: ClassInstance(int_type,context,self,errors,value=-x.value),int_type), + ('-',(int_type,int_type)):(lambda x,y: ClassInstance(int_type,context,self,errors,value=x.value - y.value),int_type), + ('+',(int_type,int_type)):(lambda x,y: ClassInstance(int_type,context,self,errors,value=x.value + y.value),int_type), + ('*',(int_type,int_type)):(lambda x,y: ClassInstance(int_type,context,self,errors,value=x.value * y.value),int_type), + ('/',(int_type,int_type)):(lambda x,y: ClassInstance(int_type,context,self,errors,value=x.value // y.value),int_type), + ('<' ,(int_type,int_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value < y.value),bool_type), + ('>' ,(int_type,int_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value > y.value),bool_type), + ('<=',(int_type,int_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value <= y.value),bool_type), + ('>=',(int_type,int_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value >= y.value),bool_type), + ( '=',(int_type,int_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value == y.value),bool_type), + + ('<' ,(string_type,string_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value < y.value),bool_type), + ('>' ,(string_type,string_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value > y.value),bool_type), + ('<=',(string_type,string_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value <= y.value),bool_type), + ('>=',(string_type,string_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value >= y.value),bool_type), + ( '=',(string_type,string_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value == y.value),bool_type), + + ('not',(bool_type,)):(lambda x: ClassInstance(bool_type,context,self,errors,value=not x.value),bool_type), + ( '=',(bool_type,bool_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.value == y.value),bool_type), + + ('isvoid',(object_type,)):(lambda x: ClassInstance(bool_type,context,self,errors,value=x.type == void_type),bool_type), + + ( '=',(object_type,object_type)):(lambda x,y: ClassInstance(bool_type,context,self,errors,value=x.scope.get_variable_value('self') == y.scope.get_variable_value('self')),bool_type), + }) + self.operator = { + PlusNode:'+', + MinusNode:'-', + DivNode:'/', + StarNode:'*', + NotNode:'not', + GreaterEqualNode:'>=', + GreaterNode:'>', + LesserEqualNode:'<=', + LesserNode:'<', + EqualNode:'=', + RoofNode:'~', + IsVoidNode:'isvoid', + } + + def register_operation(self,operator,function,return_type,*types): + self.operations[operator,types] = (function,return_type) + + def get_operator(self,node): + return self.operator.get(type(node),None) + + def operation_defined(self,node, *types): + operator = self.get_operator(node) + if operator: + return (operator,types) in self.operations + return False + + def type_of_operation(self,node,*types): + operator = self.get_operator(node) + if operator: + try: + value = self.operations[(operator,types)] + except KeyError: + return ErrorType() + return value[1] + return ErrorType() + + def operate(self,operator,*values): + types = tuple(value.type for value in values) + try: + return self.operations[operator,types][0](*values) + except KeyError as exc: + raise RunError(exc.args[0]) + except ZeroDivisionError as exc: + raise RunError(ZERO_DIVISION) + + def __str__(self): + return str(self.operations) + +class OperationDict: + def __init__(self, default:"(operator,*types)->(func_operator,return_type)"={}): + self.operations = default + + def get_valid_operators_of(self, operator): + valid_operators_types = [args for op,args in self.operations if op == operator] + return valid_operators_types + + def get(self,key,default=None): + operator, types = key + types = list(types) + auto_type_index = [i for i,x in enumerate(types) if isinstance(x, AutoType)] + if not auto_type_index: + try: + return self[key] + except KeyError: + return default + + possible_operations_types = [oper_types for oper,oper_types in self.operations if oper == operator and len(oper_types) == len(types)] + for i in [i for i in range(len(types)) if i not in auto_type_index]: + possible_operations_types = [x for x in possible_operations_types if x[i] == types[i]] + + combinations = dict() + for i, possibles in [(i, types[i].possibles) for i in auto_type_index]: + no_possibles = [] + for possible in possibles: + if any(x for x in possible_operations_types if x[i] == possible): + value = combinations.get(i,[]) + value.append(possible) + combinations[i] = value + else: + no_possibles.append(possible) + for to_remove in no_possibles: + types[i].remove_possible(to_remove) + + if len(combinations) != len(auto_type_index): + raise KeyError("No operation can satisfy the current types") + + results = [] + import cool.visitors.utils as ut + for possible_types in ut.set_permutation(*[combinations[i] for i in auto_type_index]): + type_key = [x for x in types] + for j,i in enumerate(auto_type_index): + type_key[i] = possible_types[j] + type_key = tuple(type_key) + try: + result = self[operator,type_key] + results.append(result) + except KeyError: + for j,i in enumerate(auto_type_index): + types[i].remove_possible(possible_types[j]) + + if len(results) != 1: + raise KeyError("Result must have a cardinality of 1") + return results[0] + + def get_covariant(self,key): + operator,types = key + possible_op = [] + + for op,op_types in self.operations: + if operator == op and len(types) == len(op_types): + for op_type,key_type in zip(op_types,types): + if not (op_type in key_type.get_parents() or op_type == key_type): + break + else: + possible_op.append((op,op_types)) + + if len(possible_op) > 1: + raise KeyError(MULTIPLE_OPERATION_DEFINED.format(operator,types)) + if len(possible_op) == 0: + raise KeyError(NO_OPERATION_DEFINDED.format(operator, types)) + + return self.operations[possible_op[0]] + + def __getitem__(self,key): + operator,types = key + if operator == "=" and len(types) == 2: # Special Equal Restriction + if any(isinstance(types[0], x) for x in [BoolType, IntType, StringType] ) and types[0] != types[1]: + raise KeyError() + try: + return self.operations[key] + except KeyError: + if any(x for x in key[1] if isinstance(x,AutoType)): + result = self.get(key) + return result + raise KeyError(NO_OPERATION_DEFINDED.format(operator, types)) + return self.get_covariant(key) + except TypeError: # Unhashable error + raise KeyError(NO_OPERATION_DEFINDED.format(operator, types)) + + def __contains__(self,key): + try: + self[key] + return True + except KeyError: + return False + + def __setitem__(self,key,value): + op,types = key + self.operations[key] = value + + def __str__(self): + return "\n".join([f"{op} : {', '.join([typex.name for typex in types])} --> {ret_type.name}" for (op, types),(func, ret_type) in self.operations.items()]) \ No newline at end of file diff --git a/src/cool_cmp/cool/visitors/utils.py b/src/cool_cmp/cool/visitors/utils.py new file mode 100644 index 000000000..27054a1fb --- /dev/null +++ b/src/cool_cmp/cool/visitors/utils.py @@ -0,0 +1,83 @@ +def build_graph_list(type_list): + graph = { x:[x.parent,] for x in type_list } + for x in graph: + if graph[x][0] is None or graph[x][0] not in type_list: + graph[x] = [] + return graph + +def reverse_graph(graph): + graph = { x:y.copy() for x,y in graph.items() } + reverse = { x:[] for x in graph } + for x,y in graph.items(): + for z in y: + reverse_list = reverse.get(z, []) + if x not in reverse_list: + reverse_list.append(x) + reverse[z] = reverse_list + return reverse + +def build_graph_dict(context_types): + graph = { y:[y.parent,] for x,y in context_types.items() } + for x in graph: + if graph[x][0] is None: + graph[x] = [] + return graph + + +def dfs(graph, node=None): + d = dict() + f = dict() + time = [0] + if node: + d[node] = time[0]; time[0]+=1 + _dfs(graph, node, d, f, time) + f[node] = time[0]; time[0]+=1 + else: + for node in graph: + if node not in d: + d[node] = time[0]; time[0]+=1 + _dfs(graph, node, d, f, time) + f[node] = time[0]; time[0]+=1 + return d,f + +def _dfs(graph, node, d, f, time): + for adj in graph[node]: + if adj not in d: + d[adj] = time[0]; time[0]+=1 + _dfs(graph,adj,d,f,time) + f[adj] = time[0]; time[0]+=1 + +def any_cycles(graph, return_sort=False): + d,f,time,stack,cycles = { x:0 for x in graph },{ x:0 for x in graph },[1], [], [] + for x in graph: + if not d[x]: + d[x] = time[0]; time[0]+=1 + topological_order(graph,x,d,f,time,stack,cycles) + f[x] = time[0]; time[0]+=1 + stack.append(x) + if return_sort: + stack.reverse() + return cycles, stack + return cycles + + +def topological_order(graph,node,d,f,time,stack,cycles): + + for adj in graph[node]: + if not d[adj]: + d[adj] = time[0]; time[0]+=1 + topological_order(graph,adj,d,f,time,stack,cycles) + f[adj] = time[0]; time[0]+=1 + stack.append(adj) + elif not f[adj]: + cycles.append((node,adj)) + +def set_permutation(*iterables): + if len(iterables) == 1: + for x in iterables[0]: + yield [x] + else: + permutations = [x for x in set_permutation(*iterables[1:])] + for value in iterables[0]: + for permutation in permutations: + yield [value] + permutation \ No newline at end of file diff --git a/src/cool_cmp/cool/visitors/visitors.py b/src/cool_cmp/cool/visitors/visitors.py new file mode 100644 index 000000000..c0ab5ecb6 --- /dev/null +++ b/src/cool_cmp/cool/visitors/visitors.py @@ -0,0 +1,1173 @@ +import cmp.visitor as visitor +from cool.ast.cool_ast import * +from semantic.type import Type,ErrorType,StringType,IntType,IOType,BoolType,ObjectType,SelfType,VoidType,AutoType +from semantic.context import Context +from cool.semantic.atomic import ClassInstance +from cool.errors.errors import * +import cool.visitors.utils as ut +from cool.semantic.operations import Operator + +class ReconstructVisitor: + def __init__(self, context, operator): + self.context = context + self.operator = operator + self.tab = " " + + def add_line(self, line, depth): + return self.tab*depth + line + "\n" + + def preappend_depth_if_needed(self, text, depth): + if text[-1] != "\n": + return self.tab*depth + text + "\n" + return text + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node, depth=0): + program = "" + for decl in node.declarations: + program += self.visit(decl, depth) + program += self.add_line("\n", depth) + + return program + + @visitor.when(ClassDeclarationNode) + def visit(self, node, depth=0): + father = f" inherits {node.parent}" if node.parent != "Object" else "" + class_decl = self.add_line(f"class {node.id}" + father, depth) + class_decl += self.add_line("{", depth) + for feature in node.features: + class_decl += self.visit(feature, depth + 1) + class_decl += self.add_line("}", depth) + return class_decl + + @visitor.when(AttrDeclarationNode) + def visit(self, node, depth=0): + attr_decl = f"{node.id}:{node.type.name}" + if node.expr and node.expr.type.name != "Void" and node.expr.column != None: + attr_decl += " <- " + attr_decl += self.visit(node.expr, depth + 1) + attr_decl += ";" + return self.add_line(attr_decl, depth) + + @visitor.when(FuncDeclarationNode) + def visit(self, node, depth=0): + func_decl = f"{node.id}(" + func_decl += ", ".join([self.visit(x, depth + 1) for x in node.params]) + func_decl += f"): {node.type.name}" + func_decl = self.add_line(func_decl, depth) + func_decl += self.add_line("{", depth) + func_decl += self.preappend_depth_if_needed(self.visit(node.body, depth+1), depth + 1) + func_decl += self.add_line("};", depth) + return func_decl + + @visitor.when(ParamNode) + def visit(self, node, depth=0): + return f"{node.id}:{node.type.name}" + + @visitor.when(VarDeclarationNode) + def visit(self, node, depth=0): + decl = self.add_line(f"{node.id}:{node.type.name} <- ", depth) + decl += self.preappend_depth_if_needed(self.visit(node.expr, depth + 1), depth + 1) + return decl + + @visitor.when(AssignNode) + def visit(self, node, depth=0): + assign = self.add_line(f"{node.id} <- ", depth) + assign += self.preappend_depth_if_needed(self.visit(node.expr, depth + 1), depth + 1) + return assign + + @visitor.when(CallNode) + def visit(self, node, depth=0): + obj = self.visit(node.obj, depth) + obj = self.preappend_depth_if_needed(obj, depth) + if node.at: + obj += self.add_line(f"@{node.at.name}.{node.id}(", depth) # remove the \n + else: + obj += self.add_line(f".{node.id}(", depth) # remove the \n + + for arg in [self.visit(x, depth + 1) for x in node.args]: + if arg[-1] == "\n": + arg = arg[:len(arg)-1] + ",\n" + else: + arg = self.add_line(arg + ",", depth + 1) + obj += arg + if node.args: + obj = obj[:len(obj)-2] + "\n" + obj += self.add_line(")", depth) + return obj + + @visitor.when(BlockNode) + def visit(self, node, depth=0): + block = self.add_line("{", depth) + + for expr in node.expr_list: + expr = self.visit(expr, depth + 1) + if expr[-1] == "\n": + expr = expr[:len(expr)-1] + ";\n" + else: + expr = self.add_line(expr + ";", depth + 1) + block += expr + + block += self.add_line("}", depth) + return block + + @visitor.when(ConditionalNode) + def visit(self, node, depth=0): + condition = self.add_line("if", depth) + condition += self.preappend_depth_if_needed(self.visit(node.condition,depth + 1), depth + 1) + condition += self.add_line("then", depth) + condition += self.preappend_depth_if_needed(self.visit(node.then_expr, depth + 1), depth + 1) + condition += self.add_line("else", depth) + condition += self.preappend_depth_if_needed(self.visit(node.else_expr, depth + 1), depth + 1) + condition += self.add_line("fi", depth) + return condition + + @visitor.when(LetNode) + def visit(self, node, depth=0): + let = self.add_line("let", depth) + for arg in [self.visit(arg, depth + 1) for arg in node.params]: + if arg[-1] == "\n": + arg = arg[:len(arg)-1] + ",\n" + else: + arg = self.preappend_depth_if_needed(arg + ",", depth + 1) + let += arg + if node.params: + let = let[:len(let)-2] + "\n" + + + let += self.add_line("in", depth) + expr = self.preappend_depth_if_needed(self.visit(node.expr, depth + 1), depth + 1) + return let + expr + + @visitor.when(CaseNode) + def visit(self, node, depth=0): + case = self.add_line("case", depth) + case += self.preappend_depth_if_needed(self.visit(node.expr, depth + 1), depth + 1) + case += self.add_line("of", depth) + for check in [self.visit(x, depth + 1) for x in node.params]: + check = self.preappend_depth_if_needed(check, depth + 1) + case += check + case += self.add_line("esac", depth) + return case + + @visitor.when(CheckNode) + def visit(self, node, depth=0): + check = self.add_line(f"{node.id}:{node.type.name} =>", depth) + expr = self.visit(node.expr, depth + 1) + expr = self.preappend_depth_if_needed(expr, depth + 1) + check += expr[:len(expr)-1] + ";\n" + return check + + @visitor.when(WhileNode) + def visit(self, node, depth=0): + code = self.add_line("while", depth) + code += self.preappend_depth_if_needed(self.visit(node.condition, depth + 1), depth + 1) + code += self.add_line("loop", depth) + code += self.preappend_depth_if_needed(self.visit(node.expr, depth + 1), depth + 1) + code += self.add_line("pool", depth) + return code + + @visitor.when(UnaryNode) + def visit(self, node, depth=0): + operator = self.operator.get_operator(node) + " " + operator += self.visit(node.member, depth + 1) + return operator + + @visitor.when(BinaryNode) + def visit(self, node, depth=0): + operator = "(" + operator += self.visit(node.left, depth + 1) + operator += " " + self.operator.get_operator(node) + " " + operator += self.visit(node.right, depth + 1) + operator += ")" + return operator + + @visitor.when(VariableNode) + def visit(self, node, depth=0): + return node.lex + + @visitor.when(ConstantNumNode) + def visit(self, node, depth=0): + return node.lex + + @visitor.when(BoolNode) + def visit(self, node, depth=0): + return node.lex + + @visitor.when(StringNode) + def visit(self, node, depth=0): + return node.lex + + @visitor.when(VoidNode) + def visit(self, node, depth=0): + return "void" + + @visitor.when(InstantiateNode) + def visit(self, node, depth=0): + return "new " + node.lex + +class FormatVisitor(object): + + @visitor.on('node') + def visit(self, node, tabs): + pass + + def get_type_name(self, node): + try: + return node.type.name + except AttributeError: + return node.type + + @visitor.when(ProgramNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ProgramNode [ ... ]' + statements = '\n'.join(self.visit(child, tabs + 1) for child in node.declarations) + return f'{ans}\n{statements}' + + @visitor.when(ClassDeclarationNode) + def visit(self, node, tabs=0): + parent = '' if node.parent is None else f": {node.parent}" + ans = '\t' * tabs + f'\\__ClassDeclarationNode: class {node.id} {parent} {{ ... }}' + features = '\n'.join(self.visit(child, tabs + 1) for child in node.features) + return f'{ans}\n{features}' + + @visitor.when(AttrDeclarationNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__AttrDeclarationNode: {node.id} : {self.get_type_name(node)}' + return f'{ans}' + + @visitor.when(VarDeclarationNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__VarDeclarationNode: let {node.id} : {self.get_type_name(node)} = ' + expr = self.visit(node.expr, tabs + 1) + return f'{ans}\n{expr}' + + @visitor.when(AssignNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__AssignNode: let {node.id} <- ' + expr = self.visit(node.expr, tabs + 1) + return f'{ans}\n{expr}' + + @visitor.when(FuncDeclarationNode) + def visit(self, node, tabs=0): + params = ', '.join([self.visit(x) for x in node.params]) + ans = '\t' * tabs + f'\\__FuncDeclarationNode: {node.id}({params}) : {self.get_type_name(node)} {{ }};' + body = self.visit(node.body, tabs + 1) + return f'{ans}\n{body}' + + @visitor.when(BinaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__ {node.__class__.__name__} ' + left = self.visit(node.left, tabs + 1) + right = self.visit(node.right, tabs + 1) + return f'{ans}\n{left}\n{right}' + + @visitor.when(UnaryNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f'\\__{node.__class__.__name__} ' + member = self.visit(node.member, tabs + 1) + return f'{ans}\n{member}' + + @visitor.when(AtomicNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__{node.__class__.__name__}: {node.lex}' + + @visitor.when(BlockNode) + def visit(self,node,tabs=0): + ans = '\t' * tabs + f'\\__ BlockNode: {{ }}' + expr_list = [ self.visit(x,tabs+1) for x in node.expr_list ] + return ans + "\n" + '\n'.join(expr_list) + + @visitor.when(CallNode) + def visit(self, node, tabs=0): + obj = self.visit(node.obj, tabs + 1) + ans = '\t' * tabs + f'\\__CallNode: .{node.id}(, ..., )' + args = '\n'.join(self.visit(arg, tabs + 1) for arg in node.args) + return f'{ans}\n{obj}\n{args}' + + @visitor.when(InstantiateNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f'\\__ InstantiateNode: new {node.lex}' + + @visitor.when(ParamNode) + def visit(self, node, tabs=0): + return '\t' * tabs + f"{node.id} : {self.get_type_name(node)}" + + @visitor.when(CaseNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f"\\__CaseNode: case of esac" + expr = self.visit(node.expr, tabs + 1) + checks = "\n".join(self.visit(check, tabs + 1) for check in node.params) + return f"{ans}\n{expr}\n{checks}" + + @visitor.when(CheckNode) + def visit(self, node, tabs=0): + ans = "\t" * tabs + f"\\__CheckNode: {node.id}:{self.get_type_name(node)} => " + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{expr}" + + @visitor.when(LetNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f"\\__LetNode: let in " + decls = "\n".join(self.visit(decl, tabs + 1) for decl in node.params) + expr = self.visit(node.expr, tabs + 1) + return f"{ans}\n{decls}\n{expr}" + + @visitor.when(ConditionalNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f"\\__ConditionalNode: if then else fi" + cond = self.visit(node.condition, tabs + 1) + then = self.visit(node.then_expr, tabs + 1) + elsex = self.visit(node.else_expr, tabs + 1) + return f"{ans}\n{cond}\n{then}\n{elsex}" + + @visitor.when(WhileNode) + def visit(self, node, tabs=0): + ans = '\t' * tabs + f"\\__WhileNode: while loop pool" + cond = self.visit(node.condition, tabs + 1) + body = self.visit(node.expr, tabs + 1) + return f"{ans}\n{cond}\n{body}" + + +class TypeCollector(object): + def __init__(self, errors=[], context=None): + self.context = context + self.errors = errors + + def add_semantic_error(self, error:SemanticError, row:int, column:int): + error.set_position(row, column) + self.errors.append(error) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + if not self.context: + self.context = Context({ + 'Object':ObjectType, + 'String':StringType, + 'Bool':BoolType, + 'Int':IntType, + 'IO':IOType, + 'Void':VoidType, + 'Error':ErrorType, + }) + + for class_decl in node.declarations: + if class_decl.id in self.context.special_types: + typex = self.context.get_type(class_decl.id) + typex.class_node = class_decl + if typex.name != "Object": + typex.parent = self.context.get_type(class_decl.parent) if class_decl.parent is not None else None + self.add_semantic_error(SemanticError(REDEFINITION_BASIC_CLASS, class_decl.id), class_decl.row, class_decl.column) + else: + try: + typex = self.context.create_type(class_decl.id) + typex.class_node = class_decl + except SemanticError as er: + self.add_semantic_error(er, class_decl.row, class_decl.column) + + for class_decl in node.declarations: + if not class_decl.id in self.context.special_types: + try: + curr_type = self.context.get_type(class_decl.id) + except SemanticError as er: + self.add_semantic_error(er, class_decl.row, class_decl.column) + if class_decl.parent: + try: + parent_type = self.context.get_type(class_decl.parent) + except SemanticError as er: + er = TypeCoolError(UNDEFINED_INHERITED_TYPE, class_decl.id, class_decl.parent) + self.add_semantic_error(er, class_decl.parent_row, class_decl.parent_column) + try: + if not curr_type.parent: + curr_type.set_parent(parent_type) + except SemanticError as er: + self.add_semantic_error(er, class_decl.row, class_decl.column) + + cycles = ut.any_cycles(ut.build_graph_dict(self.context.types)) + + for type1,type2 in cycles: + error = SemanticError(CIRCULAR_DEPENDENCY, type1.name) + self.add_semantic_error(error, type1.class_node.row, type1.class_node.column) + +class TypeBuilder: + def __init__(self, context, errors=[]): + self.context = context + self.current_type = None + self.errors = errors + + def add_semantic_error(self, error:SemanticError, row:int, column:int): + error.set_position(row, column) + self.errors.append(error) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + for decl in node.declarations: + self.visit(decl) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + for child in node.features: + self.visit(child) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + if node.id == 'self': + er = SemanticError(ATTRIBUTE_NAME_SELF) + node.type = ErrorType() + self.add_semantic_error(er, node.row, node.column) + return + try: + node.type = self.context.get_type(node.type, current_type = self.current_type) + except SemanticError as er: + er = TypeCoolError(ATTRIBUTE_TYPE_UNDEFINED, node.type, node.id) + node.type = ErrorType() + self.add_semantic_error(er, node.row, node.column) + try: + attribute = self.current_type.define_attribute(node.id,node.type) + attribute.node = node + except SemanticError as er: + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + for i,x in enumerate(node.params): + if x.id == 'self': + er = SemanticError(PARAM_NAME_SELF) + self.add_semantic_error(er, x.row, x.column) + try: + x.type = self.context.get_type(x.type, current_type = self.current_type) + except SemanticError as er: + er = TypeCoolError(UNDEFINED_PARAM_TYPE, x.type, x.id) + x.type = ErrorType() + self.add_semantic_error(er, x.row, x.column) + if x.id in [n.id for n in node.params[:i]]: + er = SemanticError(METHOD_REPEATED_ARGS_NAME, x.id) + self.add_semantic_error(er, x.row, x.column) + try: + node.type = self.context.get_type(node.type, current_type = self.current_type) + except SemanticError as er: + er = TypeCoolError(UNDEFINED_RETURN_TYPE, node.type, node.id) + node.type = ErrorType() + self.add_semantic_error(er, node.type_row, node.type_column) + try: + method = self.current_type.define_method(node.id,[x.id for x in node.params],[x.type for x in node.params],node.type) + method.node = node + except SemanticError as er: + self.add_semantic_error(er, node.row, node.column) + +class TypeChecker: + """ + Checks if the operations between types are correct. + Build the program scope. + Nodes are tagged with their type. + """ + def __init__(self, context:Context, errors=[]): + self.context = context + self.current_type = None + self.current_method = None + self.errors = errors + self.operator = Operator(context,errors) + + def complete_initial_types(self): + complete_types = ['Object','String','IO', 'Int', 'Bool'] + for cmp_type in complete_types: + self.context.get_type(cmp_type).complete() + + def add_semantic_error(self, error:SemanticError, row:int, column:int): + error.set_position(row, column) + self.errors.append(error) + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node, scope=None): + scope = scope + + for declaration in node.declarations: + self.visit(declaration, scope) + + if 'Main' in self.context.types: + MainType = self.context.get_type('Main') + try: + main_method = MainType.get_method('main',0, only_local = True) + except SemanticError as er: + self.errors.append(SemanticError(NO_ENTRY_POINT)) + else: + self.errors.append(SemanticError(NO_MAIN_TYPE)) + + self.complete_initial_types() + + return scope,self.operator + + @visitor.when(ClassDeclarationNode) + def visit(self, node, scope): + self.current_type = self.context.get_type(node.id) + node.scope = scope.create_child(self.current_type) + node.scope.define_variable('self',self.current_type) + node.features.sort(key=lambda x: x.__class__.__name__) # Attributes first, Stable sort + for feature in node.features: + self.visit(feature,node.scope) + + @visitor.when(AttrDeclarationNode) + def visit(self, node, scope): + if not node.expr: + if node.type.name != "AUTO_TYPE": + node.expr = node.type.default + node.expr.type = node.type # if type is void then is not assigned in the visit else the type is overridden + else: + return # No default expr can be assing at this moment + + scope.define_variable(node.id,node.type) + + a_scope = scope.create_child() + self.visit(node.expr,a_scope) + + node.scope = a_scope + + if not node.expr.type.conforms_to(node.type,self.current_type): + self.add_semantic_error(TypeCoolError(ATTRIBUTE_INCOMPATIBLE_TYPES, node.id, node.type.name, node.expr.type.name),node.expr.row,node.expr.column) + + @visitor.when(FuncDeclarationNode) + def visit(self, node, scope): + methods = [] + current_method = self.current_type.get_method(node.id,len(node.params)) + if self.current_type.parent: + methods = self.current_type.parent.all_methods() + methods = [x for x,typex in methods if x.name == node.id] + methods = [x for x in methods if x != current_method] + if methods: + for method in methods: + if len(method.param_names) == len(node.params): + for i,(x,y) in [(i,(x,y)) for i,(x,y) in enumerate(zip(method.param_types, current_method.param_types)) if x != y]: + err = SemanticError(METHOD_REDEFINED_WRONG_SIGNATURE_PARAM,method.name, y.name, x.name) + self.add_semantic_error(err, node.params[i].row, node.params[i].column) + else: + err = SemanticError(METHOD_REDEFINED_WRONG_PARAM_AMOUNT, node.id) + self.add_semantic_error(err, node.row, node.column) + if method.return_type != current_method.return_type: + err = SemanticError(METHOD_REDEFINED_WRONG_SIGNATURE_RETURN, method.name, current_method.return_type.name, method.return_type.name) + self.add_semantic_error(err, node.type_row, node.type_column) + + + f_scope = scope.create_child() + node.scope = f_scope + + for param in node.params: + self.visit(param,f_scope) + + self.current_method = self.current_type.get_method(node.id,len(node.params)) + self.visit(node.body,f_scope) + + if not isinstance(node.type,VoidType) and not node.body.type.conforms_to(node.type,self.current_type): + err = TypeCoolError(METHOD_INCOMPATIBLE_RETURN_TYPE, node.id, node.type.name, node.body.type.name) + self.add_semantic_error(err, node.row, node.column) + + @visitor.when(ParamNode) + def visit(self, node, scope): + scope.define_variable(node.id,node.type) + + @visitor.when(VarDeclarationNode) + def visit(self, node, scope, let_variable=False): + if node.id == 'self': + if let_variable: + err = SemanticError(LET_BOUND_SELF) + else: + err = SemanticError(SELF_IS_READONLY) + self.add_semantic_error(err, node.row, node.column) + + try: + node.type = self.context.get_type(node.type, current_type = self.current_type) + except SemanticError as er: + if let_variable: + er = TypeCoolError(LET_BOUND_TYPE_NOT_DEFINED, node.type, node.id) + node.type = ErrorType() + self.add_semantic_error(er, node.row, node.column) + if not node.expr and node.type.name != "AUTO_TYPE": + node.expr = node.type.default + node.expr.type = node.type # if type is void then is not assigned in the visit else the type is overridden + + if scope.is_local(node.id): + er = SemanticError(LOCAL_ALREADY_DEFINED, node.id, self.current_method.name) + self.add_semantic_error(er, node.row, node.column) + else: + scope.define_variable(node.id,node.type) + + if not node.expr and node.type.name == "AUTO_TYPE": + return # No default expr can be assing at this moment + + self.visit(node.expr,scope) + + if not node.expr.type.conforms_to(node.type,self.current_type): + er = TypeCoolError(INCOMPATIBLE_TYPES, node.expr.type.name, node.id, node.type.name) + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(AssignNode) + def visit(self, node, scope): + if node.id == 'self': + er = SemanticError(ASSIGN_SELF) + self.add_semantic_error(er, node.row, node.column) + + self.visit(node.expr,scope) + + if not scope.is_defined(node.id): + er = NameCoolError(VARIABLE_NOT_DEFINED, node.id) + self.add_semantic_error(er, node.row, node.column) + + node.type = node.expr.type + + if not node.expr.type.conforms_to(node.type,self.current_type): + er = TypeCoolError(INCOMPATIBLE_TYPES, node.expr.type.name, node.id, node.type.name) + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(CallNode) + def visit(self, node, scope): + # obj,id,args + self.visit(node.obj,scope) + for arg in node.args: + self.visit(arg,scope) + + try: + if node.at: + node.at = self.context.get_type(node.at) + if not node.obj.type.conforms_to(node.at,self.current_type): + er = TypeCoolError(STATIC_DISPATCH_INCOMPATIBLE_TYPES, node.obj.type.name, node.at.name) + self.add_semantic_error(er, node.obj.row, node.obj.column) + dispatch_type = node.at + else: + dispatch_type = node.obj.type + try: + method = dispatch_type.get_method(node.id,len(node.args),self.current_type) + not_conform = [(x,y.type,name) for x,y,name in zip(method.param_types,node.args,method.param_names) if not y.type.conforms_to(x,self.current_type)] + for x,y,name in not_conform: + er = TypeCoolError(INCOMPATIBLE_PARAMS_TYPES, method.name, y.name, name, x.name) + self.add_semantic_error(er, node.row, node.column) + node.type = method.return_type if method.return_type.name != "SELF_TYPE" else node.obj.type + except SemanticError as er: + if not any(meth for meth, typex in dispatch_type.all_methods() if meth.name == node.id): + raise AttributeCoolError(DISPATCH_UNDEFINED_METHOD, node.id) + else: + raise SemanticError(DISPATCH_METHOD_WRONG_ARGS, node.id) + + except SemanticError as er: + node.type = ErrorType() + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(BlockNode) + def visit(self, node:BlockNode, scope): + + node.scope = scope.create_child() + + for expr in node.expr_list: + self.visit(expr,node.scope) + + node.type = node.expr_list[-1].type + + @visitor.when(ConditionalNode) + def visit(self, node:ConditionalNode, scope): + self.visit(node.condition,scope) + self.visit(node.then_expr,scope) + self.visit(node.else_expr,scope) + + if node.condition.type != self.context.get_type('Bool') and not node.condition.type is ErrorType: + er = TypeCoolError(NOT_BOOLEAN_CONDITION) + self.add_semantic_error(er, node.row, node.column) + try: + node.type = node.get_return_type(self.current_type) + except InferError as er: + node.type = self.context.get_type("Error") + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(LetNode) + def visit(self, node: LetNode, scope): + let_scope = scope.create_child() + node.scope = let_scope + curr_scope = let_scope + for var_node in node.params: + attr_scope = curr_scope.create_child() + self.visit(var_node,attr_scope,True) + curr_scope = attr_scope + body_scope = curr_scope.create_child() + self.visit(node.expr,body_scope) + node.type = node.expr.type + + @visitor.when(WhileNode) + def visit(self, node:WhileNode, scope): + node.type = self.context.get_type('Object') + self.visit(node.condition,scope) + if node.condition.type != self.context.get_type('Bool'): + er = TypeCoolError(WHILE_NOT_BOOLEAN_CONDITION) + self.add_semantic_error(er, node.row, node.column) + self.visit(node.expr,scope) + + @visitor.when(CheckNode) + def visit(self, node:CheckNode, scope): + if node.id == 'self': + er = SemanticError(SELF_IS_READONLY) + self.add_semantic_error(er, node.row, node.column) + + try: + node.type = self.context.get_type(node.type, current_type = self.current_type) + except SemanticError: + er = TypeCoolError(UNDEFINED_CLASS_CASE_BRANCH, node.type) + self.add_semantic_error(er, node.row, node.column) + node.type = ErrorType() + + node.scope = scope.create_child() + node.scope.define_variable(node.id,node.type) + + self.visit(node.expr,node.scope) + + # if not node.expr.type.conforms_to(node.type,self.current_type): + # self.errors.append(INCOMPATIBLE_TYPES.format(node.expr.type.name,node.type.name) + f' Line:{node.row} Column:{node.column}') + + @visitor.when(CaseNode) + def visit(self, node:CaseNode, scope): + self.visit(node.expr,scope) + + node.scope = scope = scope.create_child() + + types = [] + param_types = [] + for i,param in enumerate(node.params): + self.visit(param,scope) + # if not (node.expr.type.conforms_to(param.type,self.current_type) or param.type.conforms_to(node.expr.type,self.current_type)): + # self.errors.append(f"Incompatible types {param.type.name} with {node.expr.type.name}" + f' Line:{node.row} Column:{node.column}') + if any(x for x in param_types if x == param.type): + er = SemanticError(CASE_TYPES_REPEATED, param.type.name) + self.add_semantic_error(er, param.row, param.column) + else: + param_types.append(param.type) + types.append((i,param.expr.type)) + + static_type = types[0][1] + for i,join in types[1:]: + static_type = static_type.join(join,self.current_type) + node.type = static_type + + @visitor.when(UnaryNode) + def visit(self, node, scope): + self.visit(node.member,scope) + + if not self.operator.operation_defined(node,node.member.type): + node.type = ErrorType() + node_operator = self.operator.get_operator(node) + correct_types = self.operator.operations.get_valid_operators_of(node_operator) + unary_correct_types = [x for x in correct_types if len(x) == 1] + if len(unary_correct_types) == 0: + correct_type_name = "No Type" + else: + correct_type_name = " or ".join([x[0].name for x in unary_correct_types]) + + er = TypeCoolError(INVALID_UNARY_OPERATION, node_operator, node.member.type.name, correct_type_name) + if not isinstance(node.member.type, ErrorType): + self.add_semantic_error(er, node.row, node.column) + else: + node.type = self.operator.type_of_operation(node,node.member.type) + + @visitor.when(BinaryNode) + def visit(self, node, scope): + self.visit(node.left,scope) + self.visit(node.right,scope) + + if not self.operator.operation_defined(node,node.left.type,node.right.type): + node.type = ErrorType() + operator = self.operator.get_operator(node) + if operator == self.operator.get_operator(EqualNode(None, None)): + er_message = INVALID_EQUAL_BASIC_TYPE_OPERATION + er_args = () + else: + er_message = INVALID_BINARY_OPERATION + er_args = (operator, node.left.type.name,node.right.type.name) + er = TypeCoolError(er_message, *er_args) + self.add_semantic_error(er, node.row, node.column) + else: + node.type = self.operator.type_of_operation(node,node.left.type,node.right.type) + + @visitor.when(ConstantNumNode) + def visit(self, node, scope): + node.type = self.context.get_type("Int") + + @visitor.when(BoolNode) + def visit(self, node, scope): + node.type = self.context.get_type("Bool") + + @visitor.when(StringNode) + def visit(self, node:StringNode, scope): + node.type = self.context.get_type("String") + if len(node.lex) > 1024: + er = LexerCoolError(STRING_TOO_LONG, len(node.lex)) + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(VoidNode) + def visit(self, node, scope): + pass + + @visitor.when(VariableNode) + def visit(self, node, scope): + if scope.is_defined(node.lex): + var = scope.find_variable(node.lex) + node.type = var.type + else: + node.type = ErrorType() + er = NameCoolError(VARIABLE_NOT_DEFINED, node.lex) + self.add_semantic_error(er, node.row, node.column) + + @visitor.when(InstantiateNode) + def visit(self, node, scope): + try: + node.type = self.context.get_type(node.lex, current_type = self.current_type) + except SemanticError as er: + er = TypeCoolError(UNDEFINED_NEW_TYPE, node.lex) + node.type = ErrorType() + self.add_semantic_error(er, node.type_row, node.type_column) + +class AutoResolver: + + def __init__(self, context:Context, errors=[]): + self.context = context + self.errors = errors + + def add_semantic_error(self, error:SemanticError, row:int, column:int): + error.set_position(row, column) + self.errors.append(error) + + def change_auto_to_concrete_type(self, node, node_type_name="type", less_concrete=False): + typex = getattr(node, node_type_name) + if typex.name == "AUTO_TYPE": + try: + if less_concrete: + setattr(node, node_type_name, typex.get_lower(self.current_type)) + else: + setattr(node, node_type_name, typex.get_higher(self.current_type)) + except InferError as er: + self.add_semantic_error(er, node.row, node.column) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node): + for declaration in node.declarations: + self.visit(declaration) + + @visitor.when(ClassDeclarationNode) + def visit(self, node): + self.current_type = self.context.get_type(node.id) + for feature in node.features: + self.visit(feature) + + @visitor.when(AttrDeclarationNode) + def visit(self, node): + self.change_auto_to_concrete_type(node) + if not node.expr: + node.expr = node.type.default + node.expr.type = node.type + self.visit(node.expr) + + @visitor.when(FuncDeclarationNode) + def visit(self, node): + self.change_auto_to_concrete_type(node) + for param in node.params: + self.visit(param) + + self.visit(node.body) + + @visitor.when(ParamNode) + def visit(self, node): + self.change_auto_to_concrete_type(node, less_concrete=True) + + @visitor.when(VarDeclarationNode) + def visit(self, node): + self.change_auto_to_concrete_type(node) + if not node.expr: + node.expr = node.type.default + node.expr.type = node.type + self.visit(node.expr) + + @visitor.when(AssignNode) + def visit(self, node): + self.visit(node.expr) + + @visitor.when(CallNode) + def visit(self, node): + self.visit(node.obj) + + for arg in node.args: + self.visit(arg) + + if node.at: + pass + + @visitor.when(BlockNode) + def visit(self, node:BlockNode): + for expr in node.expr_list: + self.visit(expr) + + @visitor.when(ConditionalNode) + def visit(self, node:ConditionalNode): + self.visit(node.condition) + self.visit(node.then_expr) + self.visit(node.else_expr) + + @visitor.when(LetNode) + def visit(self, node: LetNode): + for var_node in node.params: + self.visit(var_node) + self.visit(node.expr) + + @visitor.when(WhileNode) + def visit(self, node:WhileNode): + self.visit(node.condition) + self.visit(node.expr) + + @visitor.when(CheckNode) + def visit(self, node:CheckNode): + self.visit(node.expr) + + @visitor.when(CaseNode) + def visit(self, node:CaseNode): + self.visit(node.expr) + + for i,param in enumerate(node.params): + self.visit(param) + + @visitor.when(UnaryNode) + def visit(self, node): + self.visit(node.member) + + @visitor.when(BinaryNode) + def visit(self, node): + self.visit(node.left) + self.visit(node.right) + + @visitor.when(ConstantNumNode) + def visit(self, node): + pass + + @visitor.when(BoolNode) + def visit(self, node): + pass + + @visitor.when(StringNode) + def visit(self, node:StringNode): + pass + + @visitor.when(VoidNode) + def visit(self, node): + pass + + @visitor.when(VariableNode) + def visit(self, node): + pass + + @visitor.when(InstantiateNode) + def visit(self, node): + pass + + +class RunVisitor: + + def __init__(self, context:Context, scope, operator, errors=[]): + self.context = context + self.scope = scope + self.errors = errors + self.operator = operator + + @visitor.on('node') + def visit(self, node, scope): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode, scope=None): + for decl in node.declarations: + if decl.id == 'Main': + for method in [x.node for x,y in self.context.get_type('Main').all_methods()]: + if method.id == 'main': + main_type = self.context.get_type(decl.id) + main_instance = ClassInstance(main_type,self.context,self.operator,self.errors) + # method_scope = method.scope.copy() + # method_scope.set_variable_value('self',main_instance) + # method_scope.set_parent(main_instance.scope) + try: + value = self.visit(method.body,main_instance.scope) + except RunError as err: + self.errors.append(err) + return None + return value + + @visitor.when(VarDeclarationNode) + def visit(self, node:VarDeclarationNode, scope): + current_value = self.visit(node.expr,scope) + scope.define_variable(node.id,node.type) + scope.set_variable_value(node.id,current_value) + return current_value + + @visitor.when(AssignNode) + def visit(self, node:AssignNode, scope): + value = self.visit(node.expr,scope) + scope.set_variable_value(node.id,value) + return value + + @visitor.when(CallNode) + def visit(self, node:CallNode, scope): + value = self.visit(node.obj,scope) + if value.type.name == "Void": + raise RunError(DISPATCH_VOID + f" Line:{node.row} Column:{node.column}") + args = [self.visit(x,scope) for x in node.args] + if node.at: + method = node.at.get_method(node.id,len(node.args)) + else: + method = value.type.get_method(node.id,len(node.args)) + func_scope = method.node.scope.copy() + func_scope.set_parent(value.scope) + for arg,name in zip(args,method.param_names): + func_scope.set_variable_value(name,arg) + # func_scope.set_variable_value('self',value) + value = self.visit(method.node.body,func_scope) + return value + + @visitor.when(SpecialNode) + def visit(self, node:SpecialNode, scope): + try: + return node.func(scope,self.context,self.operator,self.errors) + except RunError as cexc: + raise RunError(cexc.text + f" Line:{node.row} Column:{node.column}") + + @visitor.when(BlockNode) + def visit(self, node:BlockNode, scope): + body_scope = scope.create_child() + values = [self.visit(x,body_scope) for x in node.expr_list] + return values[-1] + + @visitor.when(ConditionalNode) + def visit(self, node:ConditionalNode, scope): + condition = self.visit(node.condition,scope) + if condition.value is True: + return self.visit(node.then_expr,scope) + if condition.value is False: + return self.visit(node.else_expr,scope) + raise RunError(NO_BOOL_CONDITION + f" Line:{node.row} Column:{node.column}") # This connot happend BUT you never know + + @visitor.when(LetNode) + def visit(self, node:LetNode, scope): + let_scope = scope.create_child() + for var_decl in node.params: + value = self.visit(var_decl.expr,let_scope) + if not let_scope.is_local(var_decl.id): + let_scope.define_variable(var_decl.id,var_decl.type) + let_scope.set_variable_value(var_decl.id,value) + value = self.visit(node.expr,let_scope) + return value + + @visitor.when(WhileNode) + def visit(self, node:WhileNode, scope): + while self.visit(node.condition,scope).value == True: + self.visit(node.expr,scope) + typex = self.context.get_type('Void') + return ClassInstance(typex,self.context,self.operator,self.errors,value=None) + + @visitor.when(CheckNode) + def visit(self, node:CheckNode, scope,**kwargs): + node_scope = scope.create_child() + value = kwargs['value'] + node_scope.define_variable(node.id,value.type) + node_scope.set_variable_value(node.id,value) + return self.visit(node.expr,node_scope) + + @visitor.when(CaseNode) + def visit(self, node:CaseNode, scope): + value = self.visit(node.expr,scope) + + if value.type.name == "Void": + raise RunError(VOID_TYPE_CONFORMS + f" Line: {node.row} Column: {node.column}") + + try: + greaters = (x for x in [(i,x.type) for i,x in enumerate(node.params)] if value.type.conforms_to(x[1],value.type)) + least_pos,least = next(greaters) + for i,other in greaters: + least_pos,least = (least_pos,least) if least.conforms_to(other,least) else (i,other) + except StopIteration: + raise RunError(CASE_NO_BRANCH_SELECTED.format(value.type.name) + f" Line: {node.row} Column: {node.column}") + + return self.visit(node.params[least_pos],scope,value=value) + + @visitor.when(UnaryNode) + def visit(self, node, scope): + operator = self.operator.get_operator(node) + value = None + member_value = self.visit(node.member,scope) + try: + value = self.operator.operate(operator,member_value) + except RunError as err: + raise RunError(err.text + f' Line:{node.row} Column:{node.column}') + return value + + @visitor.when(BinaryNode) + def visit(self, node, scope): + operator = self.operator.get_operator(node) + value = None + left_value = self.visit(node.left,scope) + right_value = self.visit(node.right,scope) + try: + value = self.operator.operate(operator,left_value,right_value) + except RunError as err: + raise RunError(err.text + f' Line:{node.row} Column:{node.column}') + return value + + @visitor.when(ConstantNumNode) + def visit(self, node:ConstantNumNode, scope): + typex = self.context.get_type('Int') + return ClassInstance(typex,self.context,self.operator,self.errors,value=int(node.lex)) + + @visitor.when(BoolNode) + def visit(self, node, scope): + typex = self.context.get_type("Bool") + if node.lex[0]=='t': # true + return ClassInstance(typex,self.context,self.operator,self.errors,value=True) + return ClassInstance(typex,self.context,self.operator,self.errors,value=False) + + @visitor.when(StringNode) + def visit(self, node, scope): + typex = self.context.get_type('String') + string_without_delimitators = node.lex[1:len(node.lex)-1] + return ClassInstance(typex,self.context,self.operator,self.errors,value=string_without_delimitators) + + @visitor.when(VoidNode) + def visit(self, node, scope): + typex = self.context.get_type('Void') + return ClassInstance(typex,self.context,self.operator,self.errors,value=None) + + @visitor.when(VariableNode) + def visit(self, node:VariableNode, scope): + try: + value = scope.get_variable_value(node.lex) + except TypeError as exc: # Variable not assign yet searching in Attr + try: + attr = [x.type for x in scope.locals if x.name == 'self'][0].get_attribute(node.lex) + value = self.visit(attr.node.expr, scope) + except SemanticError as er: # Attr not found + er.set_position(node.row, node.column) + self.errors.append(er) + return value + + @visitor.when(InstantiateNode) + def visit(self, node:InstantiateNode, scope): + typex = self.context.get_type(node.lex,scope.find_variable('self').type) + return ClassInstance(typex,self.context,self.operator,self.errors) + \ No newline at end of file diff --git a/src/cool_cmp/error/__init__.py b/src/cool_cmp/error/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/error/error_tracker.py b/src/cool_cmp/error/error_tracker.py new file mode 100644 index 000000000..9ba787616 --- /dev/null +++ b/src/cool_cmp/error/error_tracker.py @@ -0,0 +1,25 @@ +from typing import List +from error.errors import CoolError, PositionError + +class LexerCoolError(PositionError): + """ + Error class for lexical errors + """ + + FORMAT = "({}, {}) - {}: {}" + + ERROR_TYPE = "LexicographicError" + +class ErrorTracker(): + """ + Basic Error tracking system + """ + + def __init__(self): + self.__errors = [] + + def add_error(self, error:CoolError): + self.__errors.append(error) + + def get_errors(self)->List[CoolError]: + return self.__errors \ No newline at end of file diff --git a/src/cool_cmp/error/errors.py b/src/cool_cmp/error/errors.py new file mode 100644 index 000000000..46a3700c3 --- /dev/null +++ b/src/cool_cmp/error/errors.py @@ -0,0 +1,73 @@ + +class CoolError(Exception): + """ + Base Cool Error + """ + + @property + def text(self): + return str(self) + + ERROR_TYPE = "CoolError" + + FORMAT = "{}: {}" + + def __init__(self, msg:str, *args): + self.error = msg + self.args = args + + def print_error(self): + print(str(self)) + + def __str__(self): + return CoolError.FORMAT.format(self.ERROR_TYPE, self.error.format(*self.args)) + + def __repr__(self): + return str(self) + +class PositionError(CoolError): + """ + Error class for positional errors + """ + + FORMAT = "({}, {}) - {}: ERROR {}" + + def __init__(self, error_message:str, *args, **kwargs): + """ + kwargs: + token: The token where the error is + row: Row error + column: Column error + lex: Representation of the error + """ + super().__init__(error_message, *args) + self.__row = kwargs.get("row") + self.__column = kwargs.get("column") + self.lex = kwargs.get("lex") + if "token" in kwargs: + self.__row = kwargs["token"].lex[1] + self.__column = kwargs["token"].lex[2] + self.lex = kwargs["token"].lex[0] + self.token = kwargs["token"] + else: + self.token = None + + @property + def row(self): + return self.__row if self.token == None else self.token.line + + @property + def column(self): + return self.__column if self.token == None else self.token.column + + def set_position(self, row:int, column:int): + self.__row = row + self.__column = column + + def __str__(self): + if self.row == None or self.column == None: + return super().__str__() + return self.FORMAT.format(self.row,self.column, self.ERROR_TYPE, self.error.format(*self.args)) + +class RunError(CoolError): + ERROR_TYPE = "RunError" diff --git a/src/cool_cmp/main.py b/src/cool_cmp/main.py new file mode 100644 index 000000000..ac53bb421 --- /dev/null +++ b/src/cool_cmp/main.py @@ -0,0 +1,104 @@ +# import os, sys +# base_dir = os.path.dirname(__file__) +# sys.path.append(os.path.join(base_dir, "..")) + +from cil.errors.errors import AbortError +from pipes.pipelines import cool_pipeline, generate_cool_pipeline, interprete_cil_pipeline,\ + interprete_cool_pipeline, generate_cil_pipeline, generate_mips_pipeline +from cool.grammar.cool_grammar import G +from cool.parser.cool_parser import save_parser,cool_parser_path, cool_parser +from cool.lexer.cool_lexer import save_lexer,cool_lexer_path, cool_tokens_def +from cool.grammar.comment_grammar import C +from cool.parser.comment_parser import comment_parser_path, comment_parser +from cool.lexer.comment_lexer import comment_lexer_path, comment_tokens_def +import plac + +# plac annotation (description, type of arg [option, flag, positional], abrev, type, choices) +def main( + program_dir:("Path to cool program", "positional"), + output_dir:("Path for the compiled mips", "positional"), + out_infer:("Creates a file containing the inferred types", 'flag', 'i'), + out_cil:("Creates a file containing the generated CIL code", 'flag', 'c'), + out_mips:("Creates a file containing the generated MIPS code", 'flag', 'm'), + run_cil:("Run interpreter on the generated CIL code", 'flag', 'icil'), + run_cool:("Run interpreter on the COOL code", 'flag', 'icool'), + verbose:("Print more info", 'flag', 'v'), + update_cool_parser:("Update pickled cool parser", 'flag', 'ucp'), + update_cool_lexer:("Update pickled cool lexer", 'flag', 'ucl'), + update_comment_parser:("Update pickled comment parser", 'flag', 'ump'), + update_comment_lexer:("Update pickled comment lexer", 'flag', 'uml')): + """ + Manage cool interpreter and run programs + """ + change = False + if update_cool_parser: + obj = save_parser(cool_parser_path,G) + print('Errors',obj.errors) + print("Parser updated") + change |= True + + if update_cool_lexer: + obj = save_lexer(cool_tokens_def,cool_lexer_path,G) + print("Lexer updated") + change |= True + + if update_comment_parser: + obj = save_parser(comment_parser_path,C) + print('Errors',obj.errors) + print("Comment Parser updated") + change |= True + + if update_comment_lexer: + obj = save_lexer(comment_tokens_def,comment_lexer_path,C) + print("Comment Lexer updated") + change |= True + + if change: + print("Parsers and Lexers updated") + exit() + + if program_dir == None: + print("If no update flag is provided 'program_dir' is required") + exit(1) + + with open(program_dir) as file: + file_content = file.read() + + if run_cool: + result = interprete_cool_pipeline(file_content, verbose=verbose) + elif out_infer: + result = generate_cool_pipeline(file_content, verbose=verbose) + elif run_cil: + result = interprete_cil_pipeline(file_content, verbose=verbose) + elif out_cil: + result = generate_cil_pipeline(file_content, verbose=verbose) + elif out_mips: + result = generate_mips_pipeline(file_content, verbose=verbose) + else: + result = cool_pipeline(file_content,verbose=verbose) + ast, g_errors, parse, tokens, context, scope, operator, value, reconstr, cil_text, cil_value, mips_text = [result.get(x, None) for x in ["ast", "errors", "text_parse", "text_tokens", "context", "scope", "operator", "value", "reconstructed_text", "cil_text", "cil_value", "mips_text"]] + + if reconstr and out_infer: + with open(output_dir + ".infer.cl", "w") as file: + file.write(reconstr) + + if cil_text and out_cil: + with open(output_dir + ".cil", "w") as file: + file.write(cil_text) + + if mips_text and out_mips: + out_dir = program_dir + ".mips" + if output_dir: + out_dir = output_dir + with open(out_dir, "w") as file: + file.write(mips_text) + + if [x for x in g_errors if not isinstance(x, AbortError)]: + for err in g_errors: + print(err) + exit(1) + # if hasattr(value, "value"): + # print("Value:",value.value) + +if __name__ == "__main__": + plac.call(main) \ No newline at end of file diff --git a/src/cool_cmp/mips/__init__.py b/src/cool_cmp/mips/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/mips/ast/mips_ast.py b/src/cool_cmp/mips/ast/mips_ast.py new file mode 100644 index 000000000..729d9f4f6 --- /dev/null +++ b/src/cool_cmp/mips/ast/mips_ast.py @@ -0,0 +1,252 @@ +import enum + +class Node: + def __init__(self,row=None,column=None,comment=None): + self.row = row + self.column = column + self.comment = comment + +class ProgramNode(Node): + def __init__(self, comment=None): + super().__init__(row=-1, column=-1, comment=comment) + self.instructions = [] + self.data = [] + +class DataNode(Node): + def __init__(self, name, type, values, row=None, column=None, comment=None): + """ + values: Value List. Must be a LIST + """ + super().__init__(row=row, column=column, comment=comment) + self.name = name + self.type = type + self.values = values + +class ASCIIZNode(DataNode): + def __init__(self, name, string, row=None, column=None, comment=None): + super().__init__(name, MipsTypes.asciiz, [string], row=row, column=column, comment=comment) + +class ArithmeticNode(Node): + pass + +class BinaryArithmeticNode(ArithmeticNode): + def __init__(self, result, first_arg, second_arg, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.result = result + self.first_arg = first_arg + self.second_arg = second_arg + +class AddNode(BinaryArithmeticNode): + pass + +class SubstractNode(BinaryArithmeticNode): + pass + +class AddImmediateNode(BinaryArithmeticNode): + pass + +class AddUnsignedNode(BinaryArithmeticNode): + pass + +class SubstractUnsignedNode(BinaryArithmeticNode): + pass + +class AddImmediateUnsignedNode(BinaryArithmeticNode): + pass + +class MultiplyNoOverflowNode(BinaryArithmeticNode): + pass + +class AndNode(BinaryArithmeticNode): + pass + +class OrNode(BinaryArithmeticNode): + pass + +class NorNode(BinaryArithmeticNode): + pass + +class XorNode(BinaryArithmeticNode): + pass + +class AndImmediateNode(BinaryArithmeticNode): + pass + +class OrImmediateNode(BinaryArithmeticNode): + pass + +class ShiftLeftNode(BinaryArithmeticNode): + pass + +class ShiftRightNode(BinaryArithmeticNode): + pass + +class SetLessThanNode(BinaryArithmeticNode): + pass + +class SetLessOrEqualThanNode(BinaryArithmeticNode): + pass + +class SetLessThanImmediateNode(BinaryArithmeticNode): + pass + +class SetGreaterOrEqualThanNode(BinaryArithmeticNode): + pass + +class SetGreaterThanNode(BinaryArithmeticNode): + pass + +class SetEqualToNode(BinaryArithmeticNode): + pass + +class SetNotEqualToNode(BinaryArithmeticNode): + pass + +class OperationOverflowNode(ArithmeticNode): + def __init__(self, first_arg, second_arg, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.first_arg = first_arg + self.second_arg = second_arg + +class MultiplyOverflowNode(OperationOverflowNode): + pass + +class DivideOverflowNode(OperationOverflowNode): + pass + +class InstructionNode(Node): + pass + +class CommentNode(InstructionNode): + def __init__(self, msg ,row=None, column=None, comment=None): + super().__init__(row=row, column=column) + self.msg = msg + +class LoadWordNode(InstructionNode): + def __init__(self, dest, offset, base_source_dir, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + self.offset = offset + self.base_source_dir = base_source_dir + +class LoadByteNode(InstructionNode): + def __init__(self, dest, offset, base_source_dir, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + self.offset = offset + self.base_source_dir = base_source_dir + +class StoreWordNode(InstructionNode): + def __init__(self, source, offset, base_dest_dir, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.source = source + self.offset = offset + self.base_dest_dir = base_dest_dir + +class StoreByteNode(InstructionNode): + def __init__(self, source, offset, base_dest_dir, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.source = source + self.offset = offset + self.base_dest_dir = base_dest_dir + +class LoadAddressNode(InstructionNode): + def __init__(self, dest, label, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + self.label = label + +class LoadImmediateNode(InstructionNode): + def __init__(self, dest, value, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + self.value = value + +class MoveFromHiNode(InstructionNode): + def __init__(self, dest, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + +class MoveFromLoNode(InstructionNode): + def __init__(self, dest, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + +class MoveNode(InstructionNode): + def __init__(self, dest, source, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.dest = dest + self.source = source + +class BranchNode(InstructionNode): + def __init__(self, first_arg, second_arg, address, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.first_arg = first_arg + self.second_arg = second_arg + self.address = address + +class BranchEqualNode(BranchNode): + pass + +class BranchNotEqualNode(BranchNode): + pass + +class BranchGreaterNode(BranchNode): + pass + +class BranchGreaterEqualNode(BranchNode): + pass + +class BranchLessEqualNode(BranchNode): + pass + +class BranchLessNode(BranchNode): + pass + +class JumpNode(InstructionNode): + def __init__(self, address, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.address = address + +class JumpRegisterNode(InstructionNode): + def __init__(self, register, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.register = register + +class JumpAndLinkNode(InstructionNode): + def __init__(self, address, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + self.address = address + +class LabelNode(InstructionNode): + def __init__(self, label, row=None, column=None, comment=None, isFunc=False): + super().__init__(row=row, column=column, comment=comment) + self.label = label + self.isFunc = isFunc + +class SyscallNode(InstructionNode): + def __init__(self, row=None, column=None, comment=None): + super().__init__(row=row, column=column, comment=comment) + +class MipsTypes(): + ascii = '.ascii' + asciiz = '.asciiz' + byte = '.byte' + halfword = '.halfword' + word = '.word' + space = '.space' + +# class PrintIntNode(InstructionNode): +# pass + +# class PrintStringNode(InstructionNode): +# pass + +# class ReadIntNode(InstructionNode): +# pass + +# class ReadStringNode(InstructionNode): +# pass + +# class ExitNode(InstructionNode): +# pass diff --git a/src/cool_cmp/mips/error/errors.py b/src/cool_cmp/mips/error/errors.py new file mode 100644 index 000000000..5f4f111f0 --- /dev/null +++ b/src/cool_cmp/mips/error/errors.py @@ -0,0 +1,20 @@ +INVALID_REGISTER_ARGUMENTS = "Register {0} is in range {1} and {2}, given {3}" +INVALID_CIL_META_INSTRUCTION = "Trying to translate a cil meta instruction" + +class MipsError(Exception): + ERROR_TEMPLATE = "" + + def __str__(self) -> str: + return self.ERROR_TEMPLATE.format(*self.args) + +class RegisterInvalidArgError(MipsError): + ERROR_TEMPLATE = INVALID_REGISTER_ARGUMENTS + def __init__(self, name, inf, sup, current) -> None: + self.name = name + self.inf = inf + self.sup = sup + self.current = current + super().__init__(name, inf, sup, current) + +class MetaCILInvalidError(MipsError): + ERROR_TEMPLATE = INVALID_CIL_META_INSTRUCTION \ No newline at end of file diff --git a/src/cool_cmp/mips/registers.py b/src/cool_cmp/mips/registers.py new file mode 100644 index 000000000..8ce40ab27 --- /dev/null +++ b/src/cool_cmp/mips/registers.py @@ -0,0 +1,58 @@ +from mips.error.errors import RegisterInvalidArgError + +class Reg: + """ + Provides names for MIPS registers + + Example: + ```python + v0 = Reg.v(0) # v0 = "$v0" + v0 = Reg.v(2) # Raises a RegisterInvalidArgError + ``` + """ + @staticmethod + def __ranged_register(name, inf, sup, arg): + if arg < inf or arg > sup: + raise RegisterInvalidArgError(name,inf,sup,arg) + return f"${name}{arg}" + + @staticmethod + def __register(name): + return f"${name}" + + @staticmethod + def raw(arg:int): + return Reg.__ranged_register("",0,31,arg) + + @staticmethod + def zero(): + return Reg.__register("zero") + + @staticmethod + def v(arg:int): + return Reg.__ranged_register("v",0,1,arg) + + @staticmethod + def a(arg:int): + return Reg.__ranged_register("a",0,3,arg) + + @staticmethod + def t(arg:int): + return Reg.__ranged_register("t",0,9,arg) + + @staticmethod + def s(arg:int): + return Reg.__ranged_register("s",0,7,arg) + + @staticmethod + def ra(): + return Reg.__register("ra") + + @staticmethod + def fp(): + return Reg.__register("fp") + + @staticmethod + def sp(): + return Reg.__register("sp") + \ No newline at end of file diff --git a/src/cool_cmp/mips/visitors/mips_visitors.py b/src/cool_cmp/mips/visitors/mips_visitors.py new file mode 100644 index 000000000..dfcf29fb9 --- /dev/null +++ b/src/cool_cmp/mips/visitors/mips_visitors.py @@ -0,0 +1,1199 @@ +from typing import List +from mips.ast.mips_ast import * +import cmp.visitor as visitor +import cil.ast.cil_ast as cil +from mips.error.errors import MetaCILInvalidError +from mips.registers import Reg + +class MIPSPrintVisitor(): + + def __init__(self) -> None: + self.lines = [] + self.prefix=" " + + def add_comments(self, node:Node , tabulated=False): + if node.comment: + if isinstance(node.comment, str): + if tabulated: + self.add_line(self.prefix + "# " + node.comment) + else: + self.add_line(f"# {node.comment}") + else: + for comment in node.comment: + if tabulated: + self.add_line(self.prefix + "# " + comment) + else: + self.add_line(f"# {comment}") + + def add_line(self, line=""): + self.lines.append(line) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(ProgramNode) + def visit(self, node:ProgramNode): + self.add_comments(node) + self.add_line(".text ") + for n in node.instructions: + self.add_comments(n, tabulated=True) + instr = self.visit(n) + self.add_line(instr) + self.add_line(".data ") + for n in node.data: + self.add_comments(n) + instr = self.visit(n) + self.add_line(instr) + return '\n'.join(self.lines) + + @visitor.when(DataNode) + def visit(self, node:DataNode): + return f"{node.name}: {node.type} {', '.join([str(x) for x in node.values])}" + + @visitor.when(CommentNode) + def visit(self, node:CommentNode): + return f"# {node.msg}" + + @visitor.when(AddNode) + def visit(self, node:AddNode): + return self.prefix + f"add {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SubstractNode) + def visit(self, node:SubstractNode): + return self.prefix + f"sub {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(AddImmediateNode) + def visit(self, node:AddImmediateNode): + return self.prefix + f"addi {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(AddUnsignedNode) + def visit(self, node:AddUnsignedNode): + return self.prefix + f"addu {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SubstractUnsignedNode) + def visit(self, node:SubstractUnsignedNode): + return self.prefix + f"subu {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(AddImmediateUnsignedNode) + def visit(self, node:AddImmediateUnsignedNode): + return self.prefix + f"addiu {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(MultiplyNoOverflowNode) + def visit(self, node:MultiplyNoOverflowNode): + return self.prefix + f"mul {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(AndNode) + def visit(self, node:AndNode): + return self.prefix + f"and {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(OrNode) + def visit(self, node:OrNode): + return self.prefix + f"or {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(NorNode) + def visit(self, node:NorNode): + return self.prefix + f"nor {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(XorNode) + def visit(self, node: XorNode): + return self.prefix + f"xor {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(AndImmediateNode) + def visit(self, node:AndImmediateNode): + return self.prefix + f"andi {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(OrImmediateNode) + def visit(self, node:OrImmediateNode): + return self.prefix + f"ori {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(ShiftLeftNode) + def visit(self, node:ShiftLeftNode): + return self.prefix + f"sll {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(ShiftRightNode) + def visit(self, node:ShiftLeftNode): + return self.prefix + f"srl {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(MultiplyOverflowNode) + def visit(self, node:MultiplyOverflowNode): + return self.prefix + f"mult {node.first_arg}, {node.second_arg}" + + @visitor.when(DivideOverflowNode) + def visit(self, node:DivideOverflowNode): + return self.prefix + f"div {node.first_arg}, {node.second_arg}" + + @visitor.when(LoadWordNode) + def visit(self, node:LoadWordNode): + return self.prefix + f"lw {node.dest}, {node.offset}({node.base_source_dir})" + + @visitor.when(LoadByteNode) + def visit(self, node:LoadByteNode): + return self.prefix + f"lb {node.dest}, {node.offset}({node.base_source_dir})" + + @visitor.when(StoreWordNode) + def visit(self, node:StoreWordNode): + return self.prefix + f"sw {node.source}, {node.offset}({node.base_dest_dir})" + + @visitor.when(StoreByteNode) + def visit(self, node:StoreByteNode): + return self.prefix + f"sb {node.source}, {node.offset}({node.base_dest_dir})" + + @visitor.when(LoadAddressNode) + def visit(self, node:LoadAddressNode): + return self.prefix + f"la {node.dest}, {node.label}" + + @visitor.when(LoadImmediateNode) + def visit(self, node:LoadImmediateNode): + return self.prefix + f"li {node.dest}, {node.value}" + + @visitor.when(MoveFromHiNode) + def visit(self, node:MoveFromHiNode): + return self.prefix + f"mfhi {node.dest}" + + @visitor.when(MoveFromLoNode) + def visit(self, node:MoveFromLoNode): + return self.prefix + f"mflo {node.dest}" + + @visitor.when(MoveNode) + def visit(self, node:MoveNode): + return self.prefix + f"move {node.dest}, {node.source}" + + @visitor.when(BranchEqualNode) + def visit(self, node:BranchEqualNode): + return self.prefix + f"beq {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(BranchNotEqualNode) + def visit(self, node:BranchNotEqualNode): + return self.prefix + f"bne {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(BranchGreaterNode) + def visit(self, node:BranchGreaterNode): + return self.prefix + f"bgt {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(BranchGreaterEqualNode) + def visit(self, node:BranchGreaterEqualNode): + return self.prefix + f"bge {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(BranchLessNode) + def visit(self, node:BranchLessNode): + return self.prefix + f"blt {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(BranchLessEqualNode) + def visit(self, node:BranchLessEqualNode): + return self.prefix + f"ble {node.first_arg}, {node.second_arg}, {node.address}" + + @visitor.when(SetLessThanNode) + def visit(self, node:SetLessThanNode): + return self.prefix + f"slt {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetLessOrEqualThanNode) + def visit(self, node:SetLessOrEqualThanNode): + return self.prefix + f"sle {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetLessThanImmediateNode) + def visit(self, node:SetLessThanNode): + return self.prefix + f"slti {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetGreaterThanNode) + def visit(self, node:SetGreaterThanNode): + return self.prefix + f"sgt {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetGreaterOrEqualThanNode) + def visit(self, node:SetGreaterOrEqualThanNode): + return self.prefix + f"sge {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetEqualToNode) + def visit(self, node:SetEqualToNode): + return self.prefix + f"seq {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(SetNotEqualToNode) + def visit(self, node:SetNotEqualToNode): + return self.prefix + f"sne {node.result}, {node.first_arg}, {node.second_arg}" + + @visitor.when(JumpNode) + def visit(self, node:JumpNode): + return self.prefix + f"j {node.address}" + + @visitor.when(JumpRegisterNode) + def visit(self, node:JumpRegisterNode): + return self.prefix + f"jr {node.register}" + + @visitor.when(JumpAndLinkNode) + def visit(self, node:JumpAndLinkNode): + return self.prefix + f"jal {node.address}" + + @visitor.when(SyscallNode) + def visit(self, node:SyscallNode): + return self.prefix + f"syscall" + + @visitor.when(LabelNode) + def visit(self, node:LabelNode): + if node.isFunc: + return f"\n{node.label}:" + return self.prefix + f"{node.label}:" + + + +class CILToMIPSVisitor(): + + WORD_SIZE = 4 + TO_METHODS_OFFSET = 12 # 4 Father, 4 Instance Size, 4 Type Name address, METHODS + TYPE_NAME_OFFSET = 8 # 4 Father, 4 Instance Size, Type Name address + MAX_STRING_LENGTH = 1024 # Max amount reserved when a read system call is made + STRING_EMPTY = None # Stores the data address for the "" string + + def __init__(self, errors=[]) -> None: + self.errors = errors + self.program_node = None + self.current_function = None + self.method_dict_name = {} # Maps Type and COOL Method name to CIL function name + self.local_variable_offset = {} # Maps CIL local variable frame pointer offset + self.type_method_dict_list = {} # Maps Type name to list of tuple(COOL Name, CIL Name) + + def _push(self, registers: List[str],row=None,column = None, comment= None): + """ + Push the registers in order into the stack + """ + self._allocate_stack_space(4*len(registers), row, column, comment) + for i,reg in enumerate(registers): + self.add_instruction(StoreWordNode(reg, i*4, Reg.sp(), row=row, column=column, comment=comment)) + + def _pop(self, registers: List[str],row=None,column = None, comment= None): + """ + Pop the registers in order from the stack + """ + for i,reg in enumerate(registers): + self.add_instruction(LoadWordNode( + reg, i*4, Reg.sp(), row, column, comment)) + self._deallocate_stack_space(4*len(registers), row, column, comment) + + def _allocate_stack_space(self, bytes_amount: int, row=None, column=None, comment=None): + self.add_instruction(AddImmediateNode(Reg.sp(), Reg.sp(), -bytes_amount, row, column, comment)) + + def _deallocate_stack_space(self, bytes_amount: int, row=None, column=None, comment=None): + self.add_instruction(AddImmediateNode(Reg.sp(), Reg.sp(), bytes_amount, row, column, comment)) + + def _load_local_variable(self, dest, name, row=None, column=None, comment=None): + try: + value = int(name) + self.add_instruction(LoadImmediateNode(dest, name, row, column, comment)) + except ValueError: + self.add_instruction(LoadWordNode(dest, self.local_variable_offset[name], Reg.fp(),row,column,comment)) # Stack address for local variable + + def _load_type_variable(self, dest, name, row=None, column=None, comment=None): + """ + Store into dest the type address of name. + + name can be a type name or can be an address to a type address + + name = IO + + local = IO + name = local + """ + if isinstance(name, cil.TypeNode): + name = name.name + if name[0].isupper(): + self.add_instruction(LoadAddressNode(dest, name,row,column,comment)) + else: + self._load_local_variable(dest, name, row, column, comment) + + def _store_local_variable(self, source, name_or_value, row=None, column=None, comment=None): + try: + # Int literal + int_value = int(name_or_value) + self.add_instruction(AddImmediateNode(source, Reg.zero(), int_value, row, column, comment)) + except ValueError: + # Variable + self.add_instruction(StoreWordNode(source, self.local_variable_offset[name_or_value], Reg.fp(),row,column,comment)) # Stores allocated memory address in destination variable + + def _call_with_register(self, register, row=None, column=None, comment=None): + self.add_instruction(JumpRegisterNode(register, row, column, comment)) + + def _add_abort_instructions(self, row=None, column=None, comment=None): + """ + Add the abort instructions + """ + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.zero(), 10,row,column,comment)) # 10 System call code for abort + self.add_instruction(SyscallNode(row, column, comment)) + + def _add_copy_string_cycle(self, label_prefix, length_reg, string_source, string_dest, temp_reg, add_null=True, row=None, column=None, comment=None): + """ + Adds the instructions required to copy the string in string_source to string_dest + using temp_reg to store the individual char values. The length to copy is stored in length_reg. + """ + + start_loop = label_prefix + "_start_copy" + end_loop = label_prefix + "_end_copy" + self.add_instruction(LabelNode(start_loop, row, column, comment)) + self.add_instruction(BranchLessEqualNode(length_reg, Reg.zero(), end_loop,row,column,comment)) # if length <= 0 then end loop, missing null + + self.add_instruction(LoadByteNode(temp_reg, 0, string_source,row,column,comment)) # t3 = char to copy + self.add_instruction(StoreByteNode(temp_reg, 0, string_dest,row,column,comment)) # copy char to corresponding address position + self.add_instruction(AddImmediateNode(string_source, string_source, 1,row,column,comment)) # Next original string address + self.add_instruction(AddImmediateNode(string_dest, string_dest, 1,row,column,comment)) # Next copy string address + + self.add_instruction(AddImmediateNode( + length_reg, length_reg, -1, row, column, comment)) # Decrease amount + self.add_instruction(JumpNode(start_loop, row, column, comment)) + + self.add_instruction(LabelNode(end_loop, row, column, comment)) + + if add_null: + self.add_instruction(StoreByteNode( + Reg.zero(), 0, string_dest, row, column, comment)) # Final null character + + def _add_create_string_instance(self, temp_reg, string_address, row=None, column=None, comment=None): + """ + Returns in $v0 the new instance of String,Address. + Uses $a0, $v0 + """ + self.add_instruction(LoadAddressNode(temp_reg, "String", row, column, "Type address into $a0")) # Type address into $a0 + self.add_instruction(LoadImmediateNode(Reg.a(0), self.WORD_SIZE * 2, row, column, "If String the is type and address")) # If String the is type and address + self._allocate_heap_space(Reg.a(0), row, column) + + self.add_instruction(StoreWordNode(temp_reg, 0, Reg.v(0), row, column, "Store String Type")) # Store String Type + self.add_instruction(StoreWordNode(string_address, self.WORD_SIZE, Reg.v(0), row, column, "Store String Address")) # Store String Address + + + def _add_copy_function(self,row=None, column = None, comment=None): + """ + Function that copies the instance passed in $a0 and returns the copy address + in $v0 + """ + + self.add_instruction( + LabelNode("__copy", row, column, comment, True)) + + self.add_instruction(MoveNode(Reg.t(0), Reg.a(0),row,column,comment)) # t0 = object address + self.add_instruction(LoadWordNode(Reg.t(1), 0, Reg.t(0),row,column,comment)) # t1 = instance type dir + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.t(1),row,column,comment)) # a0 = instance size + self._allocate_heap_space(Reg.a(0),row,column,comment) # v0 = allocated space + + start_label_name = "__start_copy_loop" + end_label_name = "__end_copy_loop" + + self.add_instruction(MoveNode(Reg.t(1), Reg.a(0),row,column,comment)) # t1 = instance size + # t1 = bytes amount = instance size / 4 + self.add_instruction(ShiftRightNode( + Reg.t(1), Reg.t(1), 2, row, column, comment)) + # t3 = new object memory address + self.add_instruction( + MoveNode(Reg.t(3), Reg.v(0), row, column, comment)) + + self.add_instruction(LabelNode(start_label_name,row,column,comment)) + self.add_instruction(BranchLessEqualNode(Reg.t(1), Reg.zero(), end_label_name,row,column,comment)) # End cycle condition + + # Get value from original object + self.add_instruction(LoadWordNode( + Reg.t(2), 0, Reg.t(0), row, column, comment)) + self.add_instruction(StoreWordNode(Reg.t(2), 0, Reg.t(3),row,column,comment)) # Set value copied value into the new object + self.add_instruction(AddImmediateNode(Reg.t(0), Reg.t(0), 4,row,column,comment)) # Next position old object + self.add_instruction(AddImmediateNode(Reg.t(3), Reg.t(3), 4,row,column,comment)) # Next position new object + self.add_instruction(AddImmediateNode(Reg.t(1), Reg.t(1), -1,row,column,comment)) # Copy amount -= 1 + + self.add_instruction(JumpNode(start_label_name,row,column,comment)) + self.add_instruction(LabelNode(end_label_name, row, column, comment)) + + # In v0 is the new object address + self.add_instruction(JumpRegisterNode(Reg.ra(), row, column, comment)) + + def _add_length_function(self,row=None, column = None, comment=None): + """ + Function that returns in $v0 the length of the string passed in $a0 + """ + self.add_instruction( + LabelNode("__string_length", row, column, comment, True)) + + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.a(0), row, column, "Actual String address")) # Actual String address + + self.add_instruction(LoadImmediateNode(Reg.v(0), 0, row, column, "v0 = current length")) # v0 = current length + start_loop = "__string_length_start_loop" + end_loop = "__string_length_end_loop" + self.add_instruction(LabelNode(start_loop, row, column, comment)) + self.add_instruction(LoadByteNode(Reg.t(0), 0, Reg.a(0),row,column,comment)) # Load current char + + self.add_instruction(BranchEqualNode(Reg.t(0), Reg.zero(), end_loop,row,column,comment)) # Is null char? end + + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.v(0), 1,row,column,comment)) # Increment length + self.add_instruction(AddImmediateNode(Reg.a(0), Reg.a(0), 1,row,column,comment)) # Next char + + self.add_instruction(JumpNode(start_loop,row,column,comment)) + self.add_instruction(LabelNode(end_loop,row,column,comment)) + + # In v0 is the string length + self.add_instruction(JumpRegisterNode(Reg.ra(), row, column, comment)) + + def _add_substring_function(self, row=None, column = None, comment=None): + """ + Returns in $v0 the result of the substring of $a0 starting in index $a1 with length $a2 + """ + + self.add_instruction( + LabelNode("__string_substring", row, column, comment, True)) + + saved_register = [Reg.a(0), Reg.a(1), Reg.a(2), Reg.ra()] + self._push(saved_register, row, column, "Save arguments") # Save arguments + self.add_instruction(JumpAndLinkNode("__string_length",row,column,"$v0 = length of string")) + # $v0 = length of string + self._pop(saved_register,row,column,"Restore arguments") # Restore arguments + + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.a(0), row, column, "Actual String address")) # Actual String address + + abort_label = "__string_substring_abort" + + # If index >= length(string) then abort + self.add_instruction(BranchGreaterEqualNode(Reg.a(1), Reg.v(0), abort_label,row,column, "If index >= length(string) then abort")) + + self.add_instruction(AddNode(Reg.t(0), Reg.a(1), Reg.a(2),row,column, "t0 = index + length")) # t0 = index + length + # If index + length >= length(string) then abort + self.add_instruction(BranchGreaterNode(Reg.t(0), Reg.v(0), abort_label,row,column, "If index + length >= length(string) then abort")) + + # If 0 < 0 then abort + self.add_instruction(BranchLessNode(Reg.a(2), Reg.zero(), abort_label,row,column, "If 0 < 0 then abort")) + + # Here the operation can be safetly made + self.add_instruction(MoveNode(Reg.t(1), Reg.a(0),row,column, "Saving the string address")) # Saving the string address + + self.add_instruction(AddImmediateNode(Reg.a(0), Reg.a(2), 1,row,column, "a0 = length + 1. Extra space for null character")) # a0 = length + 1. Extra space for null character + self._allocate_heap_space(Reg.a(0),row,column,comment) + # v0 = new String address + + self.add_instruction(MoveNode(Reg.t(2), Reg.v(0),row,column, "Saving the new string address")) # Saving the new string address + self.add_instruction(AddImmediateNode(Reg.a(0), Reg.a(0), -1,row,column, "Removing the last null space from copy")) # Removing the last null space from copy + + self.add_instruction(AddNode(Reg.t(1), Reg.t(1), Reg.a(1),row,column, "Advance index positions in original string")) # Advance index positions in original string + + self._add_copy_string_cycle("__string_substring", Reg.a(0), Reg.t(1), Reg.t(2), Reg.t(3),row,column,comment) + + self.add_instruction(MoveNode(Reg.v(1), Reg.v(0), comment="Saving String Address")) + self._add_create_string_instance(Reg.t(0), Reg.v(1)) + + self.add_instruction(JumpRegisterNode(Reg.ra(),row,column, "Return the address of the new String")) + + self.add_instruction(LabelNode(abort_label,row,column,comment)) + self._add_abort_instructions( row, column, comment) + + def _add_type_name_function(self,row=None, column = None, comment=None): + """ + Returns in $v0 the string address of the type given in $a0 + """ + + self.add_instruction( + LabelNode("__type_name", row, column, comment, True)) + # $t0 = type name address + self.add_instruction(LoadWordNode(Reg.t(0), self.TYPE_NAME_OFFSET, Reg.a(0), row, column, "$t0 = type name address")) + + self._add_create_string_instance(Reg.t(1), Reg.t(0)) + + # Return the address of the String + self.add_instruction(JumpRegisterNode(Reg.ra(), row, column, "Return the address of the String")) + + def _add_concat_function(self,row=None, column = None, comment=None): + """ + Returns in $v0 the concatenation of the strings given in $a0 and $a1 + """ + + self.add_instruction(LabelNode("__concat", row, column, comment, True)) + + saved_register = [Reg.a(0), Reg.a(1), Reg.ra()] + self._push(saved_register,row,column,comment) # Save arguments + self.add_instruction(JumpAndLinkNode("__string_length",row,column,comment)) + # $v0 = length of string1 + self._pop(saved_register,row,column,comment) # Restore arguments + + self.add_instruction(MoveNode(Reg.t(1), Reg.a(0),row,column,comment)) # t1 = string1 + self.add_instruction(MoveNode(Reg.a(0), Reg.a(1),row,column,comment)) # Passing arguments to __string_length + # Swap ended a0,a1 = a1,a0 + self.add_instruction( + MoveNode(Reg.a(1), Reg.t(1), row, column, comment)) + + # t0 = length of string1 + self.add_instruction( + MoveNode(Reg.t(0), Reg.v(0), row, column, comment)) + + saved_register = [Reg.a(0), Reg.a(1), Reg.t(0), Reg.ra()] + self._push(saved_register,row,column,comment) # Save arguments + self.add_instruction(JumpAndLinkNode("__string_length",row,column,comment)) + # $v0 = length of string2 + self._pop(saved_register, row, column, comment ) # Restore arguments + + # Returning the arguments to the correct order + self.add_instruction(MoveNode(Reg.t(1), Reg.a(0),row,column,comment)) # t1 = string2 + self.add_instruction(MoveNode(Reg.a(0), Reg.a(1),row,column,comment)) + self.add_instruction(MoveNode(Reg.a(1), Reg.t(1),row,column,comment)) # Swap ended a1,a0 = a1,a0 + + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.a(0))) # Actual String address + self.add_instruction(LoadWordNode(Reg.a(1), self.WORD_SIZE, Reg.a(1))) # Actual String address + + self.add_instruction(MoveNode(Reg.t(1), Reg.a(0),row,column,comment)) # t1 = string1, saving arg + + self.add_instruction(AddNode(Reg.t(2), Reg.v(0), Reg.t(0),row,column,comment)) # t2 = length of the concatenated string without null + self.add_instruction(AddImmediateNode(Reg.a(0), Reg.t(2), 1,row,column,comment)) # a0 = length of the concatenated string with null + self.add_instruction(MoveNode(Reg.t(2), Reg.v(0),row,column,comment)) # t2 = length of string2 + + # Allocates the necessary space + self._allocate_heap_space(Reg.a(0), row, column, comment) + # New string address in $v0 + + self.add_instruction(MoveNode(Reg.v(1), Reg.v( + 0), row, column, "Save string address")) # Save string address + + # Copy the string1 from a0 to v0 without the null character. Also increments the v0 address + # up to the next character. + self._add_copy_string_cycle("__concat_string1_copy", Reg.t(0), Reg.t(1), Reg.v(1), Reg.t(3), add_null=False,row=row,column=column,comment=comment) + self._add_copy_string_cycle("__concat_string2_copy", Reg.t(2), Reg.a(1), Reg.v(1), Reg.t(3), add_null=True, row=row,column= column,comment= comment) + + self.add_instruction(MoveNode(Reg.v(1), Reg.v( + 0), row, column, "Save string address")) # Save string address + + self._add_create_string_instance(Reg.t(0), Reg.v(1)) + + self.add_instruction(JumpRegisterNode(Reg.ra(), row, column, "Returns the concatenated string instance in v0")) + + def _add_remove_final_char(self, row=None, column=None, comment=None): + """ + Updates the string passed in $a0 by removing the last char of the string. + String must be non empty, else undefined behavior. Uses t0 and t1 + """ + + self.add_instruction( + LabelNode("__remove_last_char", row, column, comment, True)) + + #t0 = string addr + self.add_instruction(LoadWordNode(Reg.t(0), self.WORD_SIZE, Reg.a(0), row, column, "Actual String address")) # Actual String address + start_loop = "__remove_last_char_start" + end_loop = "__remove_last_char_end" + return_label = "__remove_last_char_return" + + self.add_instruction(LoadByteNode(Reg.t(1), 0, Reg.t(0), comment="Get current char")) + self.add_instruction(BranchEqualNode(Reg.t(1), Reg.zero(), return_label, comment="if char is null then return")) + + self.add_instruction(LabelNode(start_loop, comment="Initial loop")) + self.add_instruction(LoadByteNode(Reg.t(1), 0, Reg.t(0), comment="Get current char")) + self.add_instruction(BranchEqualNode(Reg.t(1), Reg.zero(), end_loop, comment="if char is null then break")) + self.add_instruction(AddImmediateNode(Reg.t(0), Reg.t(0), 1, comment="Increment address")) + self.add_instruction(JumpNode(start_loop)) + + self.add_instruction(LabelNode(end_loop, comment="End loop, removing last char")) + self.add_instruction(AddImmediateNode(Reg.t(0), Reg.t(0), -1, comment="Back one char to last one")) + self.add_instruction(StoreByteNode(Reg.zero(), 0, Reg.t(0), comment="Store null character")) + + self.add_instruction(LabelNode(return_label, comment="Return, removing last char")) + self.add_instruction(JumpRegisterNode(Reg.ra())) + + def _add_string_equal_function(self, row=None, column=None, comment=None): + """ + Returns in v0 if the strings given in a0 and a1 are equal + """ + + self.add_instruction( + LabelNode("__string_equal", row, column, comment, True)) + + start_compare_loop = "__string_equal_start_loop" + end_compare_loop = "__string_equal_end_loop" + + self.add_instruction(LoadWordNode(Reg.t(0), self.WORD_SIZE, Reg.a(0), row, column, "Actual String address")) # Actual String address + self.add_instruction(LoadWordNode(Reg.t(1), self.WORD_SIZE, Reg.a(1), row, column, "Actual String address")) # Actual String address + + self.add_instruction(LabelNode(start_compare_loop)) + self.add_instruction(LoadByteNode(Reg.t(2), 0, Reg.t(0), comment="Load string1 char")) + self.add_instruction(LoadByteNode(Reg.t(3), 0, Reg.t(1), comment="Load string2 char")) + self.add_instruction(SetEqualToNode(Reg.t(4), Reg.t(2), Reg.t(3), comment="Equal chars?")) + self.add_instruction(BranchEqualNode(Reg.t(4), Reg.zero(), end_compare_loop, comment="If not equal then")) # If not equal then + + # Chars are equal to null? => End + self.add_instruction(BranchEqualNode(Reg.t(2), Reg.zero(), end_compare_loop, comment="Both strings ended")) + + # Next char + self.add_instruction(AddImmediateNode(Reg.t(0), Reg.t(0), 1, comment="Next char")) + self.add_instruction(AddImmediateNode(Reg.t(1), Reg.t(1), 1, comment="Next char")) + + self.add_instruction(JumpNode(start_compare_loop)) + + self.add_instruction(LabelNode(end_compare_loop)) + self.add_instruction(MoveNode(Reg.v(0), Reg.t(4), comment="Assign return value")) + self.add_instruction(JumpRegisterNode(Reg.ra())) + + def _add_obj_equal_function(self, row=None, column=None, comment=None): + """ + Returns in v0 if the objects given in a0 and a1 are equal + """ + self.add_instruction( + LabelNode("__object_equal", row, column, comment, True)) + + obj_cmp_false_section = "__object_equal_false_section" + obj_end_cmp_label = "__object_equal_end" + + self.add_instruction(SetEqualToNode(Reg.v(0), Reg.a(0), Reg.a(1), comment="Compare obj by address")) + self.add_instruction(BranchNotEqualNode(Reg.v(0), Reg.zero(), obj_end_cmp_label, comment="Equal Address or Value obj are equal")) + + # Here a0 != a1 + + self.add_instruction(SetEqualToNode(Reg.t(0), Reg.zero(), Reg.a(0), comment="Check if first obj is null")) + self.add_instruction(BranchNotEqualNode(Reg.t(0), Reg.zero(), obj_cmp_false_section, comment="Set v0 to False and return")) + + self.add_instruction(SetEqualToNode(Reg.t(0), Reg.zero(), Reg.a(1), comment="Check if second obj is null")) + self.add_instruction(BranchNotEqualNode(Reg.t(0), Reg.zero(), obj_cmp_false_section, comment="Set v0 to False and return")) + + + self.add_instruction(MoveNode(Reg.t(0), Reg.a(0), comment="t0 = left object")) + self.add_instruction(MoveNode(Reg.t(1), Reg.a(1), comment="t1 = right object")) + + + + self.add_instruction(LoadWordNode(Reg.t(0), 0, Reg.t(0), comment="t0=left objType")) + self.add_instruction(LoadWordNode(Reg.t(1), 0, Reg.t(1), comment="t1=right objType")) + + self._load_type_variable(Reg.t(2), "String", comment="Loading String type address for comparison") + + self.add_instruction(SetEqualToNode(Reg.t(0), Reg.t(0), Reg.t(2), comment="t0 = left type == String")) + self.add_instruction(SetEqualToNode(Reg.t(1), Reg.t(1), Reg.t(2), comment="t1 = right type == String")) + self.add_instruction(AndNode(Reg.t(0), Reg.t(0), Reg.t(1), comment="Both types are equal to String")) + + self.add_instruction(BranchEqualNode(Reg.t(0), Reg.zero(), obj_cmp_false_section, comment="If not equal return 0")) + + self._push([Reg.ra(), Reg.a(0), Reg.a(1)]) + self.add_instruction(JumpAndLinkNode("__string_equal")) + # In $v0 if equal or not + self._pop([Reg.ra(), Reg.a(0), Reg.a(1)]) + + self.add_instruction(JumpNode(obj_end_cmp_label, comment="Go to end")) + self.add_instruction(LabelNode(obj_cmp_false_section, comment="Do Obj cmp")) + + self.add_instruction(MoveNode(Reg.v(0), Reg.zero(), comment="Not equal objects")) + + self.add_instruction(LabelNode(obj_end_cmp_label, comment="End cmp")) + + self.add_instruction(JumpRegisterNode(Reg.ra())) + + def _add_get_ra_function(self,row=None,column=None,comment=None): + """ + Adds a function that returns in $v0 2 instructions after the caller instruction + """ + self.add_instruction(LabelNode("__get_ra", row, column, comment, True)) + self.add_instruction(MoveNode(Reg.v(0), Reg.ra(),row,column,comment)) + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.v(0), 2*self.WORD_SIZE,row,column,comment)) + self.add_instruction(JumpRegisterNode(Reg.ra(),row,column,comment)) + + def _load_value(self, dest1, value1,row=None,column=None,comment=None): + """ + Returns in register `dest1` the value of `value1` + """ + try: + value = int(value1) + self.add_instruction(LoadImmediateNode( + dest1, value, row, column, comment)) + except ValueError: + try: + self._load_local_variable(dest1, value1,row,column,comment) + except KeyError: + self._load_type_variable(dest1, value1, row, column, comment) + + def _binary_operation(self, node: cil.ArithmeticNode, instruction_type, reg1, reg2, temp_reg, row=None, column=None, comment=None): + self._load_value(reg1, node.left,row,column,comment) + self._load_value(reg2, node.right,row,column,comment) + self.add_instruction(instruction_type(temp_reg, reg1, reg2, row, column, comment)) + self._store_local_variable(temp_reg, node.dest,row,column,comment) + + def _allocate_heap_space(self, reg_with_amount,row=None,column=None,comment=None): + """ + Stores in `a0` the `reg_with_amount` and makes a system call + to reserve space. The reserve space address will be in `v0` + """ + if reg_with_amount != Reg.a(0): + self.add_instruction(MoveNode(Reg.a(0), reg_with_amount,row,column,comment)) # Saves in $a0 the bytes size for current type + self.add_instruction(LoadImmediateNode(Reg.v(0), 9,row,column,comment)) # Reserve space arg + self.add_instruction(SyscallNode(row,column,comment)) # Returns in $v0 the allocated memory + + def _attribute_index_to_offset(self, index): + """ + Returns the offset for the given attribute's index in the object memory space + """ + return self.WORD_SIZE + index * self.WORD_SIZE # Object Type address first and then the attributes + + def _get_array_index(self, dest_reg, aux_reg, index, row=None, column=None, comment=None): + """ + Returns in `dest_reg` the actual offset for `index` in an array, `aux_reg` is used + for computing this value. + """ + try: + offset = int(index) * self.WORD_SIZE + self._load_value(dest_reg, offset, row, column, + comment) # Offset in dest_reg + except ValueError: + self._load_value(aux_reg, index, row, column, comment) + self.add_instruction(LoadImmediateNode(dest_reg, self.WORD_SIZE,row,column,comment)) + self.add_instruction(MultiplyNoOverflowNode(dest_reg, dest_reg, aux_reg,row,column,comment)) # Offset in dest_reg + + + def add_instruction(self, instr:Node): + self.program_node.instructions.append(instr) + + def add_data(self, data: DataNode): + self.program_node.data.append(data) + + @visitor.on('node') + def visit(self, node): + pass + + @visitor.when(cil.ProgramNode) + def visit(self, node:cil.ProgramNode): + + for type_node in node.dottypes: + self.type_method_dict_list[type_node.name] = type_node.methods.copy() + for method,static_method in type_node.methods: + self.method_dict_name[type_node.name, method] = static_method + + program = ProgramNode("Genereted MIPS") + self.program_node = program + + for data in node.dotdata: # Register data nodes + self.visit(data) + self.visit(cil.DataNode("__empty_string", '""', 0, 0, "Register empty string data")) # Register empty string data + self.STRING_EMPTY = self.program_node.data[-1].name + + self._add_get_ra_function(node.row,node.column,node.comment) + self._add_copy_function(node.row,node.column,node.comment) + self._add_length_function( node.row,node.column,node.comment) + self._add_substring_function( node.row,node.column,node.comment) + self._add_type_name_function( node.row,node.column,node.comment) + self._add_concat_function( node.row,node.column,node.comment) + self._add_string_equal_function(node.row,node.column, "String Equal Function") + self._add_obj_equal_function(node.row,node.column, "Object Equal Function") + self._add_remove_final_char(node.row, node.column, "Remove Final Char") + + for function in node.dotcode: + self.current_function = function + self.visit(function) + + self.current_function = None + + for typex in node.dottypes: + self.visit(typex) + + return program + + @visitor.when(cil.FunctionNode) + def visit(self, node:cil.FunctionNode): + + self.local_variable_offset = {} + + self.add_instruction( + LabelNode(node.name, node.row, node.column, node.comment, True)) + allocated_space = len(node.localvars) * self.WORD_SIZE # When a function is called the stack already contains all the params + self._allocate_stack_space( + allocated_space,node.row, node.column, node.comment) + offset = 0 + + for local in node.localvars + node.params[::-1]: # Params in reverse order + self.local_variable_offset[local.name] = offset + offset += self.WORD_SIZE + + self.add_instruction(MoveNode(Reg.t(0), Reg.sp(),node.row, node.column,node.comment)) # Temporary save fp + saved_registers = [Reg.ra(), Reg.fp()] # + [Reg.s(i) for i in range(8)] + self._push(saved_registers, node.row, node.column, node.comment) + # Set fp to value that matches with the offsets + self.add_instruction(MoveNode(Reg.fp(), Reg.t( + 0), node.row, node.column, node.comment)) + + for instr in node.instructions: + self.visit(instr) + + self._pop(saved_registers, node.row, node.column, node.comment) + self._deallocate_stack_space(allocated_space + len(node.params) * self.WORD_SIZE, + node.row, node.column, node.comment) # Deallocate also the params + self.add_instruction(JumpRegisterNode( + Reg.ra(), node.row, node.column, node.comment)) + + @visitor.when(cil.CommentNode) + def visit(self, node:cil.CommentNode): + self.add_instruction(CommentNode(node.msg, node.row, node.column, node.comment)) + + @visitor.when(cil.ReturnNode) + def visit(self, node:cil.ReturnNode): + if node.value: + self._load_value(Reg.v(0), node.value, node.row, + node.column, node.comment) + + @visitor.when(cil.AllocateNode) + def visit(self, node:cil.AllocateNode): + self.add_instruction(CommentNode("Allocate", node.row, node.column, node.comment)) + if node.type in ["Int", "Bool"]: + + self._store_local_variable(Reg.zero(), node.dest, node.row, node.column, node.comment) # Default value for Int and Bool is 0 + return + + if node.type[0].isupper(): # Is a Type name + self.add_instruction(LoadAddressNode(Reg.a( + 0), node.type, node.row, node.column, node.comment)) # Type address into $a0 + else: + self._load_local_variable(Reg.a(0), node.type, node.row, node.column, node.comment) + if node.type == "String": + self.add_instruction(LoadImmediateNode(Reg.a(0), self.WORD_SIZE * 2, node.row, node.column, node.comment)) # If String the is type and address + else: + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.a(0), node.row, node.column, node.comment)) # Saves in $a0 the bytes size for current type + self._allocate_heap_space(Reg.a(0), node.row, node.column) + self._store_local_variable(Reg.v(0), node.dest, node.row, node.column) + + @visitor.when(cil.AbortNode) + def visit(self, node:cil.AbortNode): + self._add_abort_instructions( node.row, node.column, node.comment) + + @visitor.when(cil.StaticCallNode) + def visit(self, node:cil.StaticCallNode): + self.add_instruction(JumpAndLinkNode(node.function,node.row, node.column, node.comment)) # Jumps to label + self._store_local_variable( + Reg.v(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.DynamicCallNode) + def visit(self, node:cil.DynamicCallNode): + type_name = None + if node.type[0].isupper(): # Is a Type name + type_name = node.type + elif node.base_type: # Is a variable name or SELF_TYPE + type_name = node.base_type.name + + self._load_type_variable( + Reg.t(0), node.type, node.row, node.column, node.comment) # t0 = TypeAddress + # Override of methods leave the new method in the same position as the overriden method + offset = next(offset * self.WORD_SIZE + self.TO_METHODS_OFFSET for offset, (cool_method,cil_method) in enumerate(self.type_method_dict_list[type_name]) if cool_method == node.method) + self.add_instruction(LoadWordNode(Reg.t(0), offset, Reg.t(0),node.row, node.column, node.comment)) # t0 = method direction + self.add_instruction(JumpAndLinkNode("__get_ra",node.row, node.column, node.comment)) + self.add_instruction(MoveNode(Reg.ra(), Reg.v(0),node.row, node.column, node.comment)) + self.add_instruction(JumpRegisterNode(Reg.t(0),node.row, node.column, node.comment)) + self._store_local_variable(Reg.v(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.DataNode) + def visit(self, node:cil.DataNode): + self.add_data(ASCIIZNode(node.name, node.value)) + + @visitor.when(cil.TypeNode) + def visit(self, node:cil.TypeNode): + name = f"{node.name}" + data_type = MipsTypes.word + + # Father address + values = [node.parent if node.parent is not None else 0] # If no parent VOID + + # Allocate attribute amount plus type address + values.append((len(node.attributes)+1)*self.WORD_SIZE) + + # Type name address + values.append(node.name_data) + + # Methods + values.extend([x[1] for x in node.methods]) + + data_node = DataNode(name, data_type, values, + node.row, node.column, node.comment) + + self.add_data(data_node) + + return data_node + + @visitor.when(cil.ArgNode) + def visit(self, node:cil.ArgNode): + self._load_value(Reg.t(0), node.name, node.row, + node.column, node.comment) + self._push([Reg.t(0)], node.row, node.column, node.comment) + + @visitor.when(cil.AssignNode) + def visit(self, node:cil.AssignNode): + self._load_value(Reg.t(0), node.source,node.row, node.column, node.comment) + self._store_local_variable( + Reg.t(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.DivNode) + def visit(self, node:cil.DivNode): + self._load_value(Reg.t(0), node.left,node.row, node.column, node.comment) + self._load_value(Reg.t(1), node.right,node.row, node.column, node.comment) + self.add_instruction(DivideOverflowNode( + Reg.t(0), Reg.t(1), node.row, node.column, node.comment)) + self.add_instruction(MoveFromLoNode(Reg.t(0), node.row, node.column, "Getting quotient")) + self._store_local_variable( + Reg.t(0), node.dest, node.row, node.column, "Stores the quotient") # Stores the quotient + + @visitor.when(cil.StarNode) + def visit(self, node:cil.StarNode): + self._binary_operation(node, MultiplyNoOverflowNode, Reg.t( + 0), Reg.t(1), Reg.t(2), node.row, node.column, node.comment) + + @visitor.when(cil.MinusNode) + def visit(self, node:cil.MinusNode): + self._binary_operation(node, SubstractNode, Reg.t(0), Reg.t(1), Reg.t(2),node.row, node.column, node.comment) + + @visitor.when(cil.PlusNode) + def visit(self, node:cil.PlusNode): + self._binary_operation(node, AddNode, Reg.t(0), Reg.t( + 1), Reg.t(2), node.row, node.column, node.comment) + + @visitor.when(cil.ObjEqualNode) + def visit(self, node:cil.ObjEqualNode): + if node.value_compare: + self._binary_operation(node, SetEqualToNode, Reg.t(0), Reg.t(1), Reg.t(2),node.row, node.column, node.comment) + else: + self._load_local_variable(Reg.a(0), node.left, node.row, node.column, "a0 = left object") + self._load_local_variable(Reg.a(1), node.right, node.row, node.column, "a1 = right object") + self._push([Reg.ra()]) + self.add_instruction(JumpAndLinkNode("__object_equal")) + self._pop([Reg.ra()]) + self._store_local_variable(Reg.v(0), node.dest, comment="Saving equal result") + + @visitor.when(cil.EqualNode) + def visit(self, node:cil.EqualNode): + self._binary_operation(node, SetEqualToNode, Reg.t(0), Reg.t(1), Reg.t(2),node.row, node.column, node.comment) + + @visitor.when(cil.GreaterNode) + def visit(self, node:cil.GreaterNode): + self._binary_operation(node, SetGreaterThanNode, Reg.t(0), Reg.t(1), Reg.t(2),node.row, node.column, node.comment) + + @visitor.when(cil.LesserNode) + def visit(self, node:cil.LesserNode): + self._binary_operation(node, SetLessThanNode, Reg.t(0), Reg.t(1), Reg.t(2),node.row, node.column, node.comment) + + @visitor.when(cil.NotNode) + def visit(self, node:cil.NotNode): + self._load_value(Reg.t(0), node.value,node.row, node.column, node.comment) + self.add_instruction(SetEqualToNode(Reg.t(0),Reg.t(0),Reg.zero(),node.row, node.column, node.comment)) + #self.add_instruction(XorNode(Reg.t(0), Reg.t(0),1,node.row, node.column, node.comment)) # Not equivalent for 0 and 1 + self._store_local_variable(Reg.t(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.TypeOfNode) + def visit(self, node:cil.TypeOfNode): + self._load_local_variable(Reg.t(0), node.obj,node.row, node.column, node.comment) + self.add_instruction(LoadWordNode(Reg.t(0), 0, Reg.t(0),node.row, node.column, node.comment)) # First word in instance is type address + self._store_local_variable( + Reg.t(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.ParamNode) + def visit(self, node:cil.ParamNode): + pass # Function Node already do this work + + @visitor.when(cil.ArrayNode) + def visit(self, node:cil.ArrayNode): + # Calculating Length + self._get_array_index(Reg.a(0), Reg.t( + 0), node.length, node.row, node.column, node.comment) + # $a0 = Array Length + + self._allocate_heap_space(Reg.a(0),node.row, node.column, node.comment) # Allocated address in $v0 + self._store_local_variable( + Reg.v(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.GetIndexNode) + def visit(self, node:cil.GetIndexNode): + # Calculating Offset + self._get_array_index(Reg.t(2), Reg.t(0), node.index,node.row, node.column, node.comment) # Offset in t2 + + self._load_value(Reg.t(1), node.source,node.row, node.column, node.comment) # Load array direction into t1 + + self.add_instruction(AddNode(Reg.t(1), Reg.t(1), Reg.t(2),node.row, node.column, node.comment)) # t1 is at the index position + + self.add_instruction(LoadWordNode(Reg.t(2), 0, Reg.t(1),node.row, node.column, node.comment)) + self._store_local_variable( + Reg.t(2), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.SetIndexNode) + def visit(self, node:cil.SetIndexNode): + # Calculating Offset + self._get_array_index(Reg.t(2), Reg.t(0), node.index,node.row, node.column, node.comment) # Offset in t2 + + self._load_value(Reg.t(3), node.value,node.row, node.column, node.comment) # Set value in t3 + + self._load_value(Reg.t(1), node.source,node.row, node.column, node.comment) # Array address in t1 + + self.add_instruction(AddNode(Reg.t(1), Reg.t(1), Reg.t(2),node.row, node.column, node.comment)) # t1 is at the index position + + self.add_instruction(StoreWordNode( + Reg.t(3), 0, Reg.t(1), node.row, node.column, node.comment)) + + @visitor.when(cil.CopyNode) + def visit(self, node:cil.CopyNode): + self._load_value(Reg.a(0), node.instance,node.row, node.column, node.comment) # t0 = instance + # Function Node already saves all register information + self.add_instruction(JumpAndLinkNode("__copy",node.row, node.column, node.comment)) + self._store_local_variable( + Reg.v(0), node.result, node.row, node.column, node.comment) + + @visitor.when(cil.LengthNode) + def visit(self, node:cil.LengthNode): + self._load_value(Reg.a(0), node.string_var,node.row, node.column, node.comment) # a0 = instance + # Function Node already saves all register information + self.add_instruction(JumpAndLinkNode("__string_length",node.row, node.column, node.comment)) + self._store_local_variable(Reg.v(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.SubstringNode) + def visit(self, node:cil.SubstringNode): + self._load_value(Reg.a(0), node.string,node.row, node.column, node.comment) + self._load_value(Reg.a(1), node.index,node.row, node.column, node.comment) + self._load_value(Reg.a(2), node.length,node.row, node.column, node.comment) + # Function Node already saves all register information + self.add_instruction(JumpAndLinkNode("__string_substring",node.row, node.column, node.comment)) + self._store_local_variable( + Reg.v(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.TypeNameNode) + def visit(self, node:cil.TypeNameNode): + self._load_type_variable(Reg.a(0), node.type,node.row, node.column, node.comment) + # Function Node already saves all register information + self.add_instruction(JumpAndLinkNode("__type_name",node.row, node.column, node.comment)) + self._store_local_variable(Reg.v(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.ConcatNode) + def visit(self, node:cil.ConcatNode): + self._load_local_variable(Reg.a(0), node.string1,node.row, node.column, node.comment) + self._load_local_variable(Reg.a(1), node.string2,node.row, node.column, node.comment) + + # Function Node already saves all register information + self.add_instruction(JumpAndLinkNode("__concat",node.row, node.column, node.comment)) + + self._store_local_variable( + Reg.v(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.VoidNode) + def visit(self, node:cil.VoidNode): + self._store_local_variable(Reg.zero(), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.GotoNode) + def visit(self, node:cil.GotoNode): + self.add_instruction( + JumpNode(node.label, node.row, node.column, node.comment)) + + @visitor.when(cil.LabelNode) + def visit(self, node:cil.LabelNode): + self.add_instruction( + LabelNode(node.label,node.row, node.column, node.comment)) + + @visitor.when(cil.GetFatherNode) + def visit(self, node:cil.GetFatherNode): + self._load_type_variable(Reg.t(0), node.variable,node.row, node.column, node.comment) # t0 = Type Address + self.add_instruction(LoadWordNode(Reg.t(0), 0, Reg.t(0),node.row, node.column, node.comment)) # t0 = t0[0] -> FatherAddress + self._store_local_variable( + Reg.t(0), node.dest, node.row, node.column, node.comment) + + @visitor.when(cil.PrintNode) + def visit(self, node:cil.PrintNode): + self._load_value(Reg.a(0), node.str_addr, node.row, node.column, node.comment) + self.add_instruction(LoadWordNode(Reg.a(0), self.WORD_SIZE, Reg.a(0), node.row, node.column, "Getting the String address")) # Getting the String address + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.zero(), 4, node.row, node.column, "4 System call code for print string")) # 4 System call code for print string + self.add_instruction(SyscallNode()) + + + @visitor.when(cil.PrintIntNode) + def visit(self, node:cil.PrintIntNode): + self._load_value(Reg.a(0), node.int_addr,node.row, node.column, node.comment) + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.zero(), 1,node.row, node.column, node.comment)) # 1 System call code for print int + self.add_instruction(SyscallNode(node.row, node.column, node.comment)) + + + + @visitor.when(cil.ReadNode) + def visit(self, node:cil.ReadNode): + self.add_instruction(LoadImmediateNode(Reg.a(1), self.MAX_STRING_LENGTH, node.row, node.column, "a1 = Allocated length Save the length in a1")) # a1 = Allocated length Save the length in a1 + self._allocate_heap_space(Reg.a(1), node.row, node.column, "Allocates 1024 bytes and return the address un v0") # Allocates 1024 bytes and return the address un v0 + self.add_instruction(MoveNode(Reg.a(0), Reg.v(0), node.row, node.column, "a0 = v0 Save the address in a0")) # a0 = v0 Save the address in a0 + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.zero(), 8, node.row, node.column, "8 System call code for read string")) # 8 System call code for read string + self.add_instruction(SyscallNode(node.row, node.column, "Fills the address in a0 with the string")) # Fills the address in a0 with the string + self.add_instruction(MoveNode(Reg.a(1), Reg.a(0), node.row, node.column, "a1 = a0 Save the address in a1")) # a1 = a0 Save the address in a1 + self._add_create_string_instance(Reg.t(0), Reg.a(1)) # Create String, Address instance + + self.add_instruction(MoveNode(Reg.a(0), Reg.v(0), node.row, node.column, "a0 = v0 Get the string instance address")) # a0 = v0 Get the string instance address + self._push([Reg.ra()]) + self.add_instruction(JumpAndLinkNode("__remove_last_char", comment="Remove last char")) + self._pop([Reg.ra()]) + + self._store_local_variable(Reg.v(0), node.dest, node.row, node.column, "Save the address in the final destination") # Save the address in the final destination + + @visitor.when(cil.ReadIntNode) + def visit(self, node:cil.ReadIntNode): + self.add_instruction(AddImmediateNode(Reg.v(0), Reg.zero(), 5,node.row, node.column, node.comment)) # 5 System call code for read int + self.add_instruction(SyscallNode(node.row, node.column, node.comment)) # Returns the read integer in v0 + self._store_local_variable(Reg.v(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.InitInstance) + def visit(self, node:cil.InitInstance): + self._load_local_variable(Reg.t(0), node.source) # Load object address in t0 + self._load_type_variable(Reg.t(1), node.instance_type) # Load type in t1 + self.add_instruction(StoreWordNode(Reg.t(1), 0, Reg.t(0))) # Assing type to first position in object address + if node.instance_type == "String": + self.add_instruction(LoadAddressNode(Reg.t(1), self.STRING_EMPTY)) # Init String with empty value + self.add_instruction(StoreWordNode(Reg.t(1), self.WORD_SIZE, Reg.t(0))) # Save empty string address in value slot for String + + + @visitor.when(cil.LoadNode) + def visit(self, node:cil.LoadNode): + self.add_instruction(LoadAddressNode(Reg.t(0), node.msg, node.row, node.column, node.comment)) + + self._add_create_string_instance(Reg.t(1), Reg.t(0)) # Create String instance + + self._store_local_variable(Reg.v(0), node.dest, node.row, node.column, "Save string instance") + + @visitor.when(cil.ObjectCopyNode) + def visit(self, node:cil.ObjectCopyNode): + raise MetaCILInvalidError() + + @visitor.when(cil.ObjectAbortNode) + def visit(self, node:cil.ObjectAbortNode): + raise MetaCILInvalidError() + + @visitor.when(cil.ObjectTypeNameNode) + def visit(self, node:cil.ObjectTypeNameNode): + raise MetaCILInvalidError() + + @visitor.when(cil.StringConcatNode) + def visit(self, node:cil.IOInIntNode): + raise MetaCILInvalidError() + + @visitor.when(cil.StringLengthNode) + def visit(self, node:cil.StringLengthNode): + raise MetaCILInvalidError() + + @visitor.when(cil.StringSubstringNode) + def visit(self, node:cil.StringSubstringNode): + raise MetaCILInvalidError() + + @visitor.when(cil.IOInIntNode) + def visit(self, node:cil.IOInIntNode): + raise MetaCILInvalidError() + + @visitor.when(cil.IOInStringNode) + def visit(self, node:cil.IOInStringNode): + raise MetaCILInvalidError() + + @visitor.when(cil.IOOutIntNode) + def visit(self, node:cil.IOOutIntNode): + raise MetaCILInvalidError() + + @visitor.when(cil.IOOutStringNode) + def visit(self, node:cil.IOOutStringNode): + raise MetaCILInvalidError() + + + @visitor.when(cil.GetAttribNode) + def visit(self, node:cil.GetAttribNode): + self._load_value(Reg.t(0), node.source,node.row, node.column, node.comment) # Load the object address + # Get the attribute offset + attr_offset = self._attribute_index_to_offset(node.attribute_index) + # Fetch the attribute value + self.add_instruction(LoadWordNode(Reg.t(0), attr_offset, Reg.t(0),node.row, node.column, node.comment)) + # Assign attribute value + self._store_local_variable(Reg.t(0), node.dest,node.row, node.column, node.comment) + + @visitor.when(cil.SetAttribNode) + def visit(self, node:cil.SetAttribNode): + self._load_value(Reg.t(0), node.source,node.row, node.column, node.comment) # Load the object address + # Get the attribute offset + attr_offset = self._attribute_index_to_offset(node.attribute_index) + # Load the value to be setted into t1 + self._load_value(Reg.t(1), node.value,node.row, node.column, node.comment) + # Save the attribute value + self.add_instruction(StoreWordNode(Reg.t(1), attr_offset, Reg.t(0),node.row, node.column, node.comment)) + + + @visitor.when(cil.GotoIfNode) + def visit(self, node:cil.GotoIfNode): + self._load_value(Reg.t(0), node.condition_value,node.row, node.column, node.comment) # Load condition value + self.add_instruction(BranchNotEqualNode(Reg.t(0), Reg.zero( + ), node.label, node.row, node.column, node.comment)) # Not 0 is True. If not zero jump to label diff --git a/src/cool_cmp/pipes/__init__.py b/src/cool_cmp/pipes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/pipes/pipeline.py b/src/cool_cmp/pipes/pipeline.py new file mode 100644 index 000000000..973426399 --- /dev/null +++ b/src/cool_cmp/pipes/pipeline.py @@ -0,0 +1,38 @@ +class Pipe: + def __init__(self, pipe_func, pipe_check=None): + """ + pipe_func: callable that recieve a dictionary and return a dictionary + pipe_check: callable that recieve a dictionary and return if the pipe can be executed + """ + self.func = pipe_func + if pipe_check: + self.check = pipe_check + else: + self.check = lambda x: True + + def __call__(self, *args, **kwargs): + return self.func(*args, **kwargs) + + def can_execute(self, dictionary): + return self.check(dictionary) + +class Pipeline(Pipe): + + def __init__(self, *pipes): + super().__init__(self.__call__) + self.pipes = [pipe for pipe in pipes] + + def __call__(self, *args, **kwargs): + start_pipe = self.pipes[0] + + result = start_pipe(*args, **kwargs) + + for pipe in self.pipes[1:]: + if pipe.can_execute(result): + result = pipe(result) + else: + break + + return result + + \ No newline at end of file diff --git a/src/cool_cmp/pipes/pipelines.py b/src/cool_cmp/pipes/pipelines.py new file mode 100644 index 000000000..52aa18048 --- /dev/null +++ b/src/cool_cmp/pipes/pipelines.py @@ -0,0 +1,96 @@ +from pipes.pipes import * +from pipes.pipeline import Pipeline, Pipe + +lexer_pipeline = Pipeline(start_pipe, + sub_tab_for_spaces_pipe, + ply_lexer_pipe + # change_escaped_lines, + # remove_comments_pipe, + # tokenize_text_pipe, + # string_escape_pipe, + ) + +# lexer_pipeline = Pipeline(start_pipe, # Temporary lexer for testing semantics +# change_escaped_lines, +# tokenize_text_pipe, +# remove_comment_tokens_pipe, +# string_escape_pipe, +# ) + +# lexer_pipeline = Pipeline(start_pipe, +# change_escaped_lines, +# remove_comments_pipe, +# tokenize_text_pipe, +# string_escape_pipe, +# ) + +syntax_pipeline = Pipeline(parse_text_pipe, + ) + +pre_semantic_pipeline = Pipeline(ast_pipe, + void_as_type_pipe, + type_collector_pipe, + build_types_pipe, + check_types_pipe, + auto_resolver_pipe, + ) + + +def get_std(): + import os + std_dir = os.path.join(os.path.dirname(__file__), "..", "cool", "lib", "std.cl") + with open(std_dir, "r") as f: + std = f.read() + return std + +def get_std_context(): + std_pipeline = Pipeline(lexer_pipeline, + syntax_pipeline, + pre_semantic_pipeline) + + std_result = std_pipeline(get_std()) + return std_result['context'] + +def add_std_pipe(result:dict): + std_context = get_std_context() + result['context'] = std_context + return result + +add_std_pipe = Pipe(add_std_pipe) + + +semantic_pipeline = Pipeline(add_std_pipe, + pre_semantic_pipeline, + ) + +execution_pipe = Pipe(run_program_pipe) + +base_cool_pipeline = Pipeline(lexer_pipeline, + syntax_pipeline, + semantic_pipeline,) + +generate_cil_pipeline = Pipeline(base_cool_pipeline, + cool_to_cil_pipe, + cil_ast_to_text_pipe) + +interprete_cil_pipeline = Pipeline(generate_cil_pipeline, + run_cil_pipe) + +basic_mips_pipeline = Pipeline(cil_to_mips_pipe) + +generate_mips_pipeline = Pipeline(base_cool_pipeline, + cool_to_cil_pipe, + basic_mips_pipeline, + mips_ast_to_text_pipe) + +generate_cool_pipeline = Pipeline(base_cool_pipeline, + reconstruct_pipe) + +interprete_cool_pipeline = Pipeline(generate_cool_pipeline, + execution_pipe) + +cool_pipeline = Pipeline(base_cool_pipeline, + cool_to_cil_pipe, + cil_ast_to_text_pipe, + basic_mips_pipeline, + mips_ast_to_text_pipe) \ No newline at end of file diff --git a/src/cool_cmp/pipes/pipes.py b/src/cool_cmp/pipes/pipes.py new file mode 100644 index 000000000..01adc453c --- /dev/null +++ b/src/cool_cmp/pipes/pipes.py @@ -0,0 +1,509 @@ + +from cool.lexer.cool_lexer import cool_lexer +from cool.lexer.ply_cool_lexer import PlyLexer +from cool.lexer.comment_lexer import comment_lexer +from cmp_tools.lang.language_lr import LanguageLR +from cool.parser.cool_parser import cool_parser +from cool.parser.comment_parser import comment_parser +from cool.visitors.visitors import * +from cool.grammar.cool_grammar import G, comment_open, comment_close +from cool.grammar.comment_grammar import C +from semantic.scope import Scope +from pipes.utils import pprint_tokens, print_errors +from pipes.pipeline import Pipe +from cil.visitors.cil_visitor import CILPrintVisitor, CILRunnerVisitor, COOLToCILVisitor +from mips.visitors.mips_visitors import CILToMIPSVisitor, MIPSPrintVisitor + +ply_lexer = PlyLexer() + +def start_pipe(text, verbose = False): + """ + Start the pipeline + """ + result = { + "text": text, + "verbose": verbose, + "errors": [], + } + return result + +start_pipe = Pipe(start_pipe) + +def change_escaped_lines(result:dict, escape_regex="\\\ *?\n"): + import re + text, _ = re.subn(escape_regex, "", result['text']) + result["text"] = text + return result + +change_escaped_lines = Pipe(change_escaped_lines) + +def remove_comments_pipe(result:dict, comment_grammar=C, comment_lexer=comment_lexer, comment_parser=comment_parser): + """ + Remove the commented lines from the text + """ + text = result["text"] + + lang = LanguageLR(comment_grammar, comment_lexer, comment_parser) + errors = [] + parse, tokens = lang(text, errors) + if not errors: + text = comment_parser.evaluate(tokens, errors, True) + + if result.get("verbose",False): + if errors: + print_errors("Removing Comments Errors", errors) + if len(text) != len(result["text"]): + print("=========== Text Comments Removed ===============") + print(text) + else: + print("=========== No Comments Removed ===============") + + result["errors"].extend(errors) + result["text"] = text + + return result + +remove_comments_pipe = Pipe(remove_comments_pipe) + +def remove_comment_tokens_pipe(result:dict): + """ + Remove all tokens between (* *) and their respective errors if any + """ + tokens = result["text_tokens"] + errors = result["errors"] + new_tokens = [] + new_errors = [] + deep = 0 + start_comment_position, end_comment_position = None, None + for tok in tokens: + if tok.token_type == comment_open: + deep+=1 + start_comment_position = (tok.lex[1], tok.lex[2]) + elif tok.token_type == comment_close: + deep-=1 + if deep == 0: + end_comment_position = (tok.lex[1], tok.lex[2]) + # Removing errors related to comments + errors = [x for x in errors if not (start_comment_position <= (x.row, x.column) <= end_comment_position)] + elif not deep: + new_tokens.append(tok) + + if result.get("verbose",False): + if errors: + print_errors("Nested Comment Elimination Errors", errors) + + result["errors"] = errors + result["errors"].extend(new_errors) + + result.update({ + "text_tokens": new_tokens + }) + return result + +remove_comment_tokens_pipe = Pipe(remove_comment_tokens_pipe) + +def tokenize_text_pipe(result:dict, language_grammar=G, language_lexer=cool_lexer, language_parser=cool_parser): + """ + Tokenize the text + """ + text = result['text'] + + lang = LanguageLR(language_grammar, language_lexer, language_parser) + + errors = [] + tokens = lang.get_tokens(text, errors) + + result.update({ + "parser": language_parser, + "lexer": language_lexer, + "language": lang, + "text_tokens": tokens, + }) + + if result.get("verbose",False): + if errors: + print_errors("Lexer Errors", errors) + print('================== TOKENS =====================') + pprint_tokens(tokens) + + result["errors"].extend(errors) + + return result + +tokenize_text_pipe = Pipe(tokenize_text_pipe) + +def sub_tab_for_spaces_pipe(result:dict): + """ + Change the \\t for ' ' + """ + import re + text = re.sub("\t"," ", result['text']) + result['text'] = text + return result + +sub_tab_for_spaces_pipe = Pipe(sub_tab_for_spaces_pipe) + +def ply_lexer_pipe(result:dict, language_grammar=G, language_lexer=ply_lexer, language_parser=cool_parser): + """ + Tokenize with ply + """ + text = result["text"] + + lang = LanguageLR(language_grammar, language_lexer, language_parser) + + errors = [] + tokens = lang.get_tokens(text, errors) + + errors = language_lexer.get_errors() + + result.update({ + "parser" : language_parser, + "lexer" : language_lexer, + "language" : lang, + "text_tokens" : tokens + }) + + if result.get("verbose", False): + if errors: + print_errors("Lexer Errors", errors) + + print('================== TOKENS =====================') + pprint_tokens(tokens) + + result["errors"].extend(errors) + + return result + +ply_lexer_pipe = Pipe(ply_lexer_pipe) + +def parse_text_pipe(result:dict, language_grammar=G, language_lexer=PlyLexer(), language_parser=cool_parser): + """ + Parse the text + """ + text = result['text'] + tokens = result.get('text_tokens') + + errors = [] + if len(tokens) == 1: + tokens[0].set_position(0,0) # EOF token must be at 0,0 + + lang = result.get('language', LanguageLR(language_grammar, language_lexer, language_parser)) + + parse, tokens = lang(text, errors, tokens) + + + if result.get("verbose",False): + if errors: + print_errors("Parsing Text Errors", errors) + if not 'text_tokens' in result: + print('================== TOKENS =====================') + pprint_tokens(tokens) + print('=================== PARSE =====================') + print('\n'.join(repr(x) for x in parse)) + + result.update({ + "text_parse": parse, + "language": lang, + "text_tokens": tokens, + "parser":language_parser + }) + + result["errors"].extend(errors) + + return result + +parse_text_pipe = Pipe(parse_text_pipe) + +def ast_pipe(result:dict): + """ + Add the initial ast + """ + parser = result["parser"] + tokens = result["text_tokens"] + text_parsed = result.get("text_parse", None) + + errors = [] + if text_parsed or tokens: + ast = parser.evaluate(tokens,errors,True,text_parsed) + result["ast"] = ast + + if result.get("verbose", False): + if errors: + print_errors("Building AST Errors", errors) + print('==================== AST ======================') + formatter = FormatVisitor() + tree = formatter.visit(ast) + print(tree) + + result["errors"].extend(errors) + + return result + +ast_pipe = Pipe(ast_pipe, lambda x: not x["errors"]) + +def type_collector_pipe(result:dict, collector=TypeCollector): + """ + Collects the types in the program. + """ + ast = result.get("ast", None) + if not ast: + return result + + errors = [] + collector = collector(errors, result.get("context", None)) + collector.visit(ast) + context = collector.context + + result["context"] = context + + if result.get("verbose", False): + if errors: + print_errors("Collecting Types Errors", errors) + print('============== COLLECTED TYPES ===============') + print(context) + + result["errors"].extend(errors) + + return result + +type_collector_pipe = Pipe(type_collector_pipe) + +def build_types_pipe(result:dict, builder=TypeBuilder): + """ + Build the types in context + """ + ast = result.get("ast", None) + context = result.get("context",None) + if not ast or not context: + return result + + errors = [] + builder = builder(context, errors) + builder.visit(ast) + + if result.get("verbose", False): + if errors: + print_errors("Building Types Errors", errors) + print('=============== BUILT TYPES ================') + print(context) + + result["errors"].extend(errors) + + return result + +build_types_pipe = Pipe(build_types_pipe) + +def check_types_pipe(result:dict, checker=TypeChecker): + """ + Build the scope and check for types to be ok + """ + + ast = result.get("ast", None) + context = result.get("context",None) + if not ast or not context: + return result + + errors = [] + checker = checker(context, errors) + scope, operator = checker.visit(ast, Scope()) + + result["scope"] = scope + result["operator"] = operator + + if result.get("verbose", False): + if errors: + print_errors("Checking Types Errors", errors) + print("=========== Checked Types Info =============") + print("Scope:") + print(scope) + print("Operator:") + print(operator) + + result["errors"].extend(errors) + + return result + +check_types_pipe = Pipe(check_types_pipe) + +def run_program_pipe(result:dict, runner=RunVisitor): + """ + Run ast and store the result + """ + ast = result.get("ast",None) + context = result.get("context",None) + scope = result.get("scope",None) + operator = result.get("operator",None) + errors = result.get("errors", None) + if any(x == None for x in [ast, context, scope, operator]) or errors: + return result + + errors = [] + runner = runner(context,scope,operator,errors) + value = runner.visit(ast) + + result["value"] = value + + if result.get("verbose", False): + if errors: + print_errors("Running Program Errors", errors) + print('=============== PROGRAM RAN ===============') + print('Returned Value:') + print(value) + + result["errors"].extend(errors) + + return result + +run_program_pipe = Pipe(run_program_pipe, lambda x: not x["errors"]) + +def reconstruct_pipe(result:dict, reconstructer=ReconstructVisitor): + ast = result.get("ast",None) + context = result.get("context",None) + operation = result.get("operator",None) + if any(x == None for x in [ast, context, operation]): + return result + + reconstructer = reconstructer(context, operation) + reconstructed_text = reconstructer.visit(ast) + if result.get("verbose", False): + print("============== Reconstructed Text ===============") + print(reconstructed_text) + result['reconstructed_text'] = reconstructed_text + return result + +reconstruct_pipe = Pipe(reconstruct_pipe) + +def void_as_type_pipe(result:dict): + + tokens = result.get("text_tokens",None) + if not tokens: + return result + + result["errors"].extend([f"Void cant appear explicitly. Line:{x.lex[1]} Column:{x.lex[2]}" for x in tokens if x.token_type.Name == "type" and x.lex[0] == "Void"]) + return result + +void_as_type_pipe = Pipe(void_as_type_pipe) + +def auto_resolver_pipe(result:dict, auto_resolver=AutoResolver): + ast = result.get("ast",None) + context = result.get("context",None) + if any(x == None for x in [ast, context]): + return result + + errors = [] + resolver = auto_resolver(context, errors) + resolver.visit(ast) + + if result.get("verbose", False): + if errors: + print_errors("Auto Resolver Errors", errors) + + result["errors"].extend(errors) + + return result + +auto_resolver_pipe = Pipe(auto_resolver_pipe) + +def string_escape_pipe(result:dict): + tokens = result["text_tokens"] + import re + for tok_str in [x for x in tokens if x.token_type.Name == "string"]: + text = re.sub(r"\\n","\n",tok_str.lex[0]) + text = re.sub(r"\\b","\b",text) + text = re.sub(r"\\t","\t",text) + text = re.sub(r"\\f","\f",text) + tok_str.lex = (text, tok_str.lex[1], tok_str.lex[2]) + return result + +string_escape_pipe = Pipe(string_escape_pipe) + +def cool_to_cil_pipe(result: dict, cool_to_cil=COOLToCILVisitor): + context = result.get("context",None) + scope = result.get("scope", None) + ast = result.get("ast", None) + if any(x == None for x in [context, ast, scope]): + return result + + if result.get("errors"): + return result + + errors = [] + cool_to_cil_visitor = cool_to_cil(context, errors) + + cil_ast = cool_to_cil_visitor.visit(ast, scope) + + result['cil_ast'] = cil_ast + + if result.get("verbose", False): + if errors: + print_errors("COOL to CIL Errors", errors) + + result["errors"].extend(errors) + + return result + +cool_to_cil_pipe = Pipe(cool_to_cil_pipe) + +def cil_ast_to_text_pipe(result: dict, formatter=CILPrintVisitor): + ast = result.get("cil_ast",None) + if any(x == None for x in [ast]): + return result + + formatter = formatter() + cil_text = formatter.visit(ast) + if result.get("verbose", False): + print("============== CIL Text ===============") + print(cil_text) + result['cil_text'] = cil_text + return result + +cil_ast_to_text_pipe = Pipe(cil_ast_to_text_pipe) + +def run_cil_pipe(result: dict, runner= CILRunnerVisitor): + ast = result.get("cil_ast",None) + if ast is None: + return result + + runner = runner() + value = runner.visit(ast) + result["errors"].extend(runner.errors) + if result.get("verbose", False): + print("============== CIL Result ===============") + print(value) + print_errors("============ CIL Run Error =============", runner.errors) + result['cil_value'] = value + return result + +run_cil_pipe = Pipe(run_cil_pipe) + +def cil_to_mips_pipe(result: dict, cil_to_mips=CILToMIPSVisitor): + ast = result.get("cil_ast",None) + if ast is None: + return result + + converter = cil_to_mips() + value = converter.visit(ast) + result["errors"].extend(converter.errors) + if result.get("verbose", False): + print("============== CIL to MIPS Result ===============") + print(value) + print_errors("============ CIL to MIPS Error =============", converter.errors) + result['mips_ast'] = value + return result + +cil_to_mips_pipe = Pipe(cil_to_mips_pipe) + +def mips_ast_to_text_pipe(result: dict, formatter=MIPSPrintVisitor): + ast = result.get("mips_ast",None) + if any(x == None for x in [ast]): + return result + + formatter = formatter() + mips_text = formatter.visit(ast) + if result.get("verbose", False): + print("============== MIPS Text ===============") + print(mips_text) + result['mips_text'] = mips_text + return result + +mips_ast_to_text_pipe = Pipe(mips_ast_to_text_pipe) diff --git a/src/cool_cmp/pipes/utils.py b/src/cool_cmp/pipes/utils.py new file mode 100644 index 000000000..55e75d1d9 --- /dev/null +++ b/src/cool_cmp/pipes/utils.py @@ -0,0 +1,19 @@ +from cool.lexer.cool_lexer import ocur, ccur, semi + +def pprint_tokens(tokens): + indent = 0 + pending = [] + for token in tokens: + pending.append(token) + if token.token_type in { ocur, ccur, semi }: + if token.token_type == ccur: + indent -= 1 + print(' '*indent + ' '.join(str(t.token_type) for t in pending)) + pending.clear() + if token.token_type == ocur: + indent += 1 + print(' '.join([str(t.token_type) for t in pending])) + +def print_errors(header:str, errors): + print(f"=========== {header} ===============") + print(*[f"- {error}\n" for error in errors]) \ No newline at end of file diff --git a/src/cool_cmp/semantic/__init__.py b/src/cool_cmp/semantic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cool_cmp/semantic/context.py b/src/cool_cmp/semantic/context.py new file mode 100644 index 000000000..dd65a9c95 --- /dev/null +++ b/src/cool_cmp/semantic/context.py @@ -0,0 +1,31 @@ +from cmp.semantic import Context as DeprecatedContext +from semantic.type import Type, SelfType, AutoType +from cool.errors.errors import SemanticError, TYPE_NOT_DEFINED, TYPE_ALREADY_DEFINED + +class Context(DeprecatedContext): + + def __init__(self, special_types:dict): + super().__init__() + self.special_types = special_types + for name in self.special_types: + self.types[name] = self.special_types[name]() + + def get_type(self, name:str,self_type=None,current_type=None): + if name == 'SELF_TYPE': + if self_type: + name = self_type.name + else: + return SelfType(current_type) + # raise TypeError('Wrong argument combination: name is "SELF_TYPE" and no self_type given') + elif name == 'AUTO_TYPE': + return AutoType(self) + try: + return self.types[name] + except KeyError: + raise SemanticError(TYPE_NOT_DEFINED, name) + + def create_type(self, name:str): + if name in self.types: + raise SemanticError(TYPE_ALREADY_DEFINED, name) + typex = self.types[name] = Type(name) + return typex \ No newline at end of file diff --git a/src/cool_cmp/semantic/scope.py b/src/cool_cmp/semantic/scope.py new file mode 100644 index 000000000..0eee1339f --- /dev/null +++ b/src/cool_cmp/semantic/scope.py @@ -0,0 +1,96 @@ +from cmp.semantic import Scope as DeprecatedScope +from cool.errors.errors import SemanticError +from cool.visitors.visitors import RunVisitor +class Scope(DeprecatedScope): + + def __init__(self, parent=None, typex=None): + super().__init__(parent) + self.type = typex + + def set_parent(self, parent): + self.parent = parent + self.index = len(parent.locals) + + def set_variable_value(self,name:str,value): + variable = self.find_variable(name) + variable.value = value + + def find_variable(self, vname, index=None): + var = super().find_variable(vname, index) + if var: return var + try: + if self.type: + attribute = self.type.get_attribute(vname) + return attribute + return None + except SemanticError: + return None + + def create_child(self, typex=None): + child = super().create_child() + child.type = self.type if not typex else typex + return child + + def get_variable_value(self,name:str): + variable = self.find_variable(name) + if hasattr(variable,'value'): + return variable.value + else: + raise TypeError(f"Value of variable {name} is not assigned") + + def instance_copy(self,typex,context,operator,errors): + scope = Scope(self.parent, self.type) + scope.index = self.index + scope.define_variable('self',typex) + attributes = typex.all_attributes() + run = RunVisitor(context,scope,operator,errors) + for var,attr_typex in attributes: + if var.type.name == 'SELF_TYPE': + scope.define_variable(var.name,typex) + else: + scope.define_variable(var.name,var.type) + for var,attr_typex in attributes: + default_node = var.node.expr + value = run.visit(default_node,scope) + scope.set_variable_value(var.name,value) + scope.children = self.children.copy() + return scope + + def copy(self): + copy_self = Scope(self.parent, self.type) + copy_self.index = self.index + copy_self.children = self.children.copy() + + for var_info in self.locals: + var = copy_self.define_variable(var_info.name,var_info.type) + if hasattr(var_info,'value'): + var.value = var_info.value.copy() + + return copy_self + + def _depth(self) -> int: + if self.parent == None: + return 0 + else: + return self.parent._depth() + 1 + + def __str__(self): + tab = " " + base = tab*self._depth() + value = base + "Scope: Index->%d\n" % self.index + + base += tab + + if self.locals: + value += base + "Local Variables \n" + for x in self.locals: + value += base + tab + x.name + ":" + x.type.name + "\n" + + if self.children: + value += base + "Childrens \n" + + for x in self.children: + value += str(x) + + return value + \ No newline at end of file diff --git a/src/cool_cmp/semantic/type.py b/src/cool_cmp/semantic/type.py new file mode 100644 index 000000000..47935754d --- /dev/null +++ b/src/cool_cmp/semantic/type.py @@ -0,0 +1,446 @@ +from cmp.semantic import Attribute, Method +from cmp.semantic import Type as DeprecatedType +from cmp.semantic import SemanticError as DeprecatedSemanticError +from cool.ast.cool_ast import VoidNode,ConstantNumNode,StringNode,BoolNode,SpecialNode,InstantiateNode +import cil.ast.cil_ast as cil +from cool.semantic.atomic import ClassInstance +from error.errors import CoolError, RunError +from cool.errors.errors import SemanticError, TypeCoolError, InferError, \ + VOID_TYPE_CONFORMS, METHOD_NOT_DEFINED, METHOD_ALREADY_DEFINED, \ + SUBSTR_OUT_RANGE, ATTRIBUTE_NOT_DEFINED, ATTRIBUTE_ALREADY_DEFINED, \ + ATTRIBUTE_CANT_INFER, METHOD_CANT_INFER, TYPE_CANT_INFER, TYPE_CANT_BE_INHERITED, \ + NO_COMMON_TYPE, READ_IS_NOT_INT, ATTRIBUTE_ALREADY_DEFINED_IN_PARENT +import cool.visitors.utils as ut + +class Type(DeprecatedType): + + def add_special_method(self,func,method_name,method_args, cil_node_type): + f = self.get_method(method_name,method_args) + old_type = f.node.body.type + f.node.body = SpecialNode(func,f.node.row,f.node.column, cil_node_type) + f.node.body.type = old_type + + def set_parent(self,parent): + try: + DeprecatedType.set_parent(self,parent) + if not parent.can_have_children: + self.parent = None + raise SemanticError(TYPE_CANT_BE_INHERITED, self.name, parent.name) + except DeprecatedSemanticError as er: + raise SemanticError(er.text) + + def __hash__(self): + return hash(self.name) + + def __eq__(self,other): + return isinstance(other, type(self)) and other.name==self.name + + def get_method(self,name:str,args:int,current_type = None, only_local = False): + self = self if not isinstance(self,SelfType) or not current_type else current_type + try: + return next(method for method in self.methods if method.name == name and len(method.param_names)==args) + except StopIteration: + if self.parent is None or self.parent == self: + raise SemanticError(METHOD_NOT_DEFINED,name, "", self.name, args) + try: + if not only_local: + return self.parent.get_method(name,args) + raise SemanticError() + except SemanticError: + raise SemanticError(METHOD_NOT_DEFINED, name, "" if not only_local else " locally", self.name, args) + + def define_method(self, name:str, param_names:list, param_types:list, return_type): + if (name,len(param_names)) in ((method.name,len(method.param_names)) for method in self.methods): + raise SemanticError(METHOD_ALREADY_DEFINED, name) + method = Method(name, param_names, param_types, return_type) + self.methods.append(method) + return method + + def get_parents(self): + if self.parent: + parents = self.parent.get_parents() + return [self.parent] + parents + else: + return [] + + def get_attribute(self, name:str): + return self._get_attribute(name, set()) + + def _get_attribute(self, name:str, visited_types:set): + if self in visited_types: + raise SemanticError(ATTRIBUTE_NOT_DEFINED, name, self.name) + try: + return next(attr for attr in self.attributes if attr.name == name) + except StopIteration: + if self.parent is None or self.parent == self: + raise SemanticError(ATTRIBUTE_NOT_DEFINED, name, self.name) + try: + visited_types.add(self) + return self.parent._get_attribute(name, visited_types) + except SemanticError: + raise SemanticError(ATTRIBUTE_NOT_DEFINED, name, self.name) + + def define_attribute(self, name:str, typex): + try: + attribute = self.get_attribute(name) + except SemanticError: + attribute = Attribute(name, typex) + self.attributes.append(attribute) + return attribute + else: + if attribute in self.attributes: + raise SemanticError(ATTRIBUTE_ALREADY_DEFINED, name) + else: + raise SemanticError(ATTRIBUTE_ALREADY_DEFINED_IN_PARENT, name) + + def conforms_to(self,other,current_type): + self_type = self if not isinstance(self,SelfType) else current_type + other_type = other if not isinstance(other,SelfType) else current_type + if isinstance(other,AutoType): + new_types = [] + for x in self_type.get_parents() + [self_type]: + if x in other_type.possibles: + new_types.append(x) + other.update_possibles(new_types) + return bool(new_types) + return self_type.__conforms_to(other_type) + + def __conforms_to(self, other): + return other.bypass() or self == other or self.parent is not None and self.parent.__conforms_to(other) + + def join(self,other,current_type): + self = self if not isinstance(self,SelfType) else current_type + other = other if not isinstance(other,SelfType) else current_type + + self = self if not isinstance(self,AutoType) else self.get_lower(current_type) + other = other if not isinstance(other,AutoType) else other.get_lower(current_type) + + self_parents = self.get_parents() + other_parents = other.get_parents() + other_types = [other] + other_parents + self_types = [self] + self_parents + for common in self_types: + if common in other_types: + return common + if isinstance(self, ErrorType) or isinstance(other, ErrorType): + return ErrorType() + raise TypeCoolError(NO_COMMON_TYPE, self.name, other.name) + + def get_attribute_index(self, attribute_name, current_type): + self = self if not isinstance(self,SelfType) else current_type + for i,(x,_) in enumerate(self.all_attributes()): + if x.name == attribute_name: + return i + raise CoolError(f"Attribute {attribute_name} defined at type {self.name}") + + @property + def can_have_children(self): + return True + + @property + def default(self): + return InstantiateNode(("Void", -1, -1), -1, -1) + +class ObjectType(Type): + def __init__(self): + Type.__init__(self, 'Object') + self.parent = None + + def complete(self): + self.add_special_method(self.abort,'abort',0, cil.ObjectAbortNode) + self.add_special_method(self.copy,'copy',0, cil.ObjectCopyNode) + self.add_special_method(self.type_name,'type_name',0, cil.ObjectTypeNameNode) + + def set_parent(self,parent): + pass + + @staticmethod + def abort(scope,context,operator,errors,**kwargs): + raise RunError('Cool Program Aborted') + + @staticmethod + def type_name(scope,context,operator,errors,**kwargs): + this_type = scope.get_variable_value('self').type + string = context.get_type('String') + return ClassInstance(string,context,operator,errors,value=this_type.name) + + @staticmethod + def copy(scope,context,operator,errors,**kwargs): + value = scope.get_variable_value('self') + return value.shallow_copy() + +class SelfType(Type): + + def __init__(self, defining_type): + self.defining_type = defining_type + Type.__init__(self, 'SELF_TYPE') + + @property + def can_have_children(self): + return False + +class IntType(Type): + def __init__(self): + Type.__init__(self, 'Int') + + def complete(self): + self.add_special_method(self.abort,'abort',0, cil.IntAbortNode) + self.add_special_method(self.type_name,'type_name',0, cil.IntTypeNameNode) + + def set_parent(self,parent): + pass + + @staticmethod + def abort(scope,context,operator,errors,**kwargs): + raise RunError('Cool Program Aborted from Int') + + @staticmethod + def type_name(scope,context,operator,errors,**kwargs): + string = context.get_type('String') + return ClassInstance(string,context,operator,errors,value="Int") + + @property + def can_have_children(self): + return False + + @property + def default(self): + return ConstantNumNode('0') + +class BoolType(Type): + def __init__(self): + Type.__init__(self, 'Bool') + + def complete(self): + self.add_special_method(self.abort,'abort',0, cil.BoolAbortNode) + self.add_special_method(self.type_name,'type_name',0, cil.BoolTypeNameNode) + + def set_parent(self,parent): + pass + + @staticmethod + def abort(scope,context,operator,errors,**kwargs): + raise RunError('Cool Program Aborted from Bool') + + @staticmethod + def type_name(scope,context,operator,errors,**kwargs): + string = context.get_type('String') + return ClassInstance(string,context,operator,errors,value="Bool") + + + @property + def can_have_children(self): + return False + + @property + def default(self): + return BoolNode('false') + +class StringType(Type): + def __init__(self): + Type.__init__(self, 'String') + + def complete(self): + self.add_special_method(self.length,'length',0, cil.StringLengthNode) + self.add_special_method(self.concat,'concat',1, cil.StringConcatNode) + self.add_special_method(self.substr,'substr',2, cil.StringSubstringNode) + + @staticmethod + def length(scope,context,operator,errors,**kwargs): + value = scope.get_variable_value('self').value + int_type = context.get_type('Int') + return ClassInstance(int_type,context,operator,errors,value=len(value)) + + @staticmethod + def concat(scope,context,operator,errors,**kwargs): + value = scope.get_variable_value('self').value + concat = scope.get_variable_value('s').value + typex = context.get_type('String') + return ClassInstance(typex,context,operator,errors,value=value + concat) + + @staticmethod + def substr(scope,context,operator,errors,**kwargs): + value = scope.get_variable_value('self').value + i = scope.get_variable_value('i').value + l = scope.get_variable_value('l').value + typex = context.get_type('String') + value_sliced = value[i:i+l] + if len(value) < l-i or l < 0: + raise RunError(SUBSTR_OUT_RANGE,value,i,l) + return ClassInstance(typex,context,operator,errors,value=value_sliced) + + @property + def can_have_children(self): + return False + + @property + def default(self): + return StringNode('""') + +class VoidType(Type): + + def __init__(self): + Type.__init__(self, 'Void') + + def conforms_to(self, other, current_type): + return True + + def bypass(self): + return True + +class ErrorType(Type): + def __init__(self): + Type.__init__(self, 'Error') + + def conforms_to(self, other, current_type): + return True + + def bypass(self): + return True + + def __eq__(self, other): + return isinstance(other, Type) + + def __hash__(self): + return super().__hash__() + +class IOType(Type): + def __init__(self): + Type.__init__(self, 'IO') + + def complete(self): + self.add_special_method(self.out_string,'out_string',1, cil.IOOutStringNode) + self.add_special_method(self.out_int,'out_int',1, cil.IOOutIntNode) + self.add_special_method(self.in_string,'in_string',0, cil.IOInStringNode) + self.add_special_method(self.in_int,'in_int',0, cil.IOInIntNode) + + @staticmethod + def out_string(scope,context,operator,errors,**kwargs): + out = scope.get_variable_value('x').value + print(out, end="") + typex = context.get_type('IO') + return scope.get_variable_value('self') + + @staticmethod + def out_int(scope,context,operator,errors,**kwargs): + out = scope.get_variable_value('x').value + print(out, end="") + typex = context.get_type('IO') + return scope.get_variable_value('self') + + @staticmethod + def in_string(scope,context,operator,errors,**kwargs): + value = input() + typex = context.get_type('String') + return ClassInstance(typex,context,operator,errors,value=value) + + @staticmethod + def in_int(scope,context,operator,errors,**kwargs): + value = input() + import re + m = re.search(" *([1234567890]+)[^1234567890\n]*\n?", value) + typex = context.get_type('Int') + try: + if m: + return ClassInstance(typex,context,operator,errors,value=int(m.group(1))) + else: + raise ValueError() + except ValueError: + raise RunError(READ_IS_NOT_INT, value) + +class AutoType(Type): + def __init__(self,context): + Type.__init__(self, 'AUTO_TYPE') + self.parent = None + self.context = context + self.possibles = [ x for x in context.types.values() if all([not isinstance(x, ErrorType), not isinstance(x, VoidType)])] + self.equals = [self,] + + def update_possibles(self, new_possibles): + for x in self.equals: + x.possibles = new_possibles + + def get_attribute(self,name): + self.update_possibles([x for x in self.possibles if any(attr for attr,typex in x.all_attributes() if attr.name==name)]) + if not self.possibles: + raise InferError(ATTRIBUTE_CANT_INFER, name) + return self.possibles[-1].get_attribute(name) + + def get_method(self,name,args,current_type = None): + self.update_possibles([x for x in self.possibles if any(meth for meth,typex in x.all_methods() if (meth.name==name and len(meth.param_names) == args))]) + if not self.possibles: + raise InferError(METHOD_CANT_INFER, name, args) + return self.possibles[-1].get_method(name,args) + + def conforms_to(self,other,current_type): + self_type = self if not isinstance(self,SelfType) else current_type + other_type = other if not isinstance(other,SelfType) else current_type + if isinstance(other,AutoType): + new_possibles = [] + for p_type in self.possibles: + if p_type in other_type.possibles: + new_possibles.append(p_type) + + self.add_to_equals(other) + + self.update_possibles(new_possibles) + + return bool(new_possibles) + else: + self.update_possibles([x for x in self.possibles if other_type.conforms_to(x,current_type)]) + return bool(self.possibles) + + def is_valid(self,current_type): + """ + Return True if the graph of the possible types is unilaterally connected + """ + if not self.possibles: return False + graph = ut.reverse_graph(ut.build_graph_list(self.possibles)) + _, topo_sort = ut.any_cycles(graph, True) + current = topo_sort[0] + d, f = ut.dfs(graph, current) + if len(d) == len(graph): + return True + return False + + def add_to_equals(self,other): + if not id(other) in [id(x) for x in self.equals]: + for x in self.possibles: + if not x in other.possibles: + self.possibles.remove(x) + for eq in other.equals: + self.equals.append(eq) + eq.equals = self.equals + eq.possibles = self.possibles + + def remove_possible(self, typex): + self.possibles.remove(typex) + self.update_possibles(self.possibles) + + def get_higher(self, current_type): + valid = self.is_valid(current_type) + if not valid: raise InferError(TYPE_CANT_INFER) + graph = ut.reverse_graph(ut.build_graph_list(self.possibles)) + _, topo_sort = ut.any_cycles(graph, True) + + current = topo_sort[0] + while len(graph[current]) == 1: + current = graph[current][0] + + return current + + def get_lower(self,current_type): + ## Lower implementation using graphs + valid = self.is_valid(current_type) + if not valid: raise InferError(TYPE_CANT_INFER) + graph = ut.reverse_graph(ut.build_graph_list(self.possibles)) + _, topo_sort = ut.any_cycles(graph, True) + + current = topo_sort[0] + return current + ## Lower implementation using join operator + # possibles = [x for x in self.possibles if not isinstance(x, ErrorType)] + # lesser = possibles[0] + # for x in possibles: + # lesser = x.join(lesser,current_type) + # return lesser diff --git a/src/coolc.sh b/src/coolc.sh index 3088de4f9..166301d48 100755 --- a/src/coolc.sh +++ b/src/coolc.sh @@ -2,10 +2,14 @@ INPUT_FILE=$1 OUTPUT_FILE=${INPUT_FILE:0: -2}mips +BASEDIR=$(dirname "$0") +PROGRAM=$BASEDIR/cool_cmp/main.py # Si su compilador no lo hace ya, aquí puede imprimir la información de contacto -echo "LINEA_CON_NOMBRE_Y_VERSION_DEL_COMPILADOR" # TODO: Recuerde cambiar estas -echo "Copyright (c) 2019: Nombre1, Nombre2, Nombre3" # TODO: líneas a los valores correctos +echo "WLD CoolCompiler v0.0" +echo "Copyright (c) 2019: Luis Ernesto, Damián, Luis Enrique" # Llamar al compilador -echo "Compiling $INPUT_FILE into $OUTPUT_FILE" +# echo "Compiling $INPUT_FILE into $OUTPUT_FILE" + +python3 $PROGRAM $INPUT_FILE $OUTPUT_FILE -m \ No newline at end of file diff --git a/src/expected_output.txt b/src/expected_output.txt new file mode 100644 index 000000000..3408320b2 --- /dev/null +++ b/src/expected_output.txt @@ -0,0 +1,7 @@ +title: The Top 100 CD_ROMs +author: Ulanoff +periodical: PC Magazine +- dynamic type was Article - +title: Compilers, Principles, Techniques, and Tools +author: Aho, Sethi, and Ullman +- dynamic type was Book - diff --git a/src/input.txt b/src/input.txt new file mode 100644 index 000000000..8e1b64142 --- /dev/null +++ b/src/input.txt @@ -0,0 +1 @@ +anitalabalatina diff --git a/src/makefile b/src/makefile index 30df993f5..cd83fb352 100644 --- a/src/makefile +++ b/src/makefile @@ -1,12 +1,12 @@ -.PHONY: clean - -main: - # Compiling the compiler :) - -clean: - rm -rf build/* - rm -rf ../tests/*/*.mips - -test: - pytest ../tests -v --tb=short -m=${TAG} - +.PHONY: clean + +main: + # Compiling the compiler :) + +clean: + rm -rf build/* + rm -rf ../tests/*/*.mips + +test: + pytest ../tests -v --tb=short -m=${TAG} + diff --git a/src/output.txt b/src/output.txt new file mode 100644 index 000000000..49566c1bf --- /dev/null +++ b/src/output.txt @@ -0,0 +1,12 @@ +SPIM Version 8.0 of January 8, 2010 +Copyright 1990-2010, James R. Larus. +All Rights Reserved. +See the file README for a full copyright notice. +Loaded: /usr/lib/spim/exceptions.s +title: The Top 100 CD_ROMs +author: Ulanoff +periodical: PC Magazine +- dynamic type was Article - +title: Compilers, Principles, Techniques, and Tools +author: Aho, Sethi, and Ullman +- dynamic type was Book - diff --git a/src/test_mips.sh b/src/test_mips.sh new file mode 100644 index 000000000..52c44c513 --- /dev/null +++ b/src/test_mips.sh @@ -0,0 +1,14 @@ +BASEDIR=$(dirname "$0") +INPUT=$BASEDIR/input.txt +OUTPUT=$BASEDIR/output.txt +EXPECTED_OUTPUT=$BASEDIR/expected_output.txt +FILE=$BASEDIR/testing.mips + +$BASEDIR/coolc.sh $BASEDIR/testing.cl +spim -file $FILE < $INPUT > $OUTPUT +if cmp -b -i 0:178 $EXPECTED_OUTPUT $OUTPUT +then + echo "Test Passed" +else + echo "Test Failed" +fi diff --git a/src/testing.cl b/src/testing.cl new file mode 100644 index 000000000..d39f86bbe --- /dev/null +++ b/src/testing.cl @@ -0,0 +1,132 @@ +-- example of static and dynamic type differing for a dispatch + +Class Book inherits IO { + title : String; + author : String; + + initBook(title_p : String, author_p : String) : Book { + { + title <- title_p; + author <- author_p; + self; + } + }; + + print() : Book { + { + out_string("title: ").out_string(title).out_string("\n"); + out_string("author: ").out_string(author).out_string("\n"); + self; + } + }; +}; + +Class Article inherits Book { + per_title : String; + + initArticle(title_p : String, author_p : String, + per_title_p : String) : Article { + { + initBook(title_p, author_p); + per_title <- per_title_p; + self; + } + }; + + print() : Book { + { + self@Book.print(); + out_string("periodical: ").out_string(per_title).out_string("\n"); + self; + } + }; +}; + +Class BookList inherits IO { + (* Since abort "returns" type Object, we have to add + an expression of type Bool here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + isNil() : Bool { { abort(); true; } }; + + cons(hd : Book) : Cons { + (let new_cell : Cons <- new Cons in + new_cell.init(hd,self) + ) + }; + + (* Since abort "returns" type Object, we have to add + an expression of type Book here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + car() : Book { { abort(); new Book; } }; + + (* Since abort "returns" type Object, we have to add + an expression of type BookList here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + cdr() : BookList { { abort(); new BookList; } }; + + print_list() : Object { abort() }; +}; + +Class Cons inherits BookList { + xcar : Book; -- We keep the car and cdr in attributes. + xcdr : BookList; -- Because methods and features must have different names, + -- we use xcar and xcdr for the attributes and reserve + -- car and cdr for the features. + + isNil() : Bool { false }; + + init(hd : Book, tl : BookList) : Cons { + { + xcar <- hd; + xcdr <- tl; + self; + } + }; + + car() : Book { xcar }; + + cdr() : BookList { xcdr }; + + print_list() : Object { + { + case xcar.print() of + dummy : Book => out_string("- dynamic type was Book -\n"); + dummy : Article => out_string("- dynamic type was Article -\n"); + esac; + xcdr.print_list(); + } + }; +}; + +Class Nil inherits BookList { + isNil() : Bool { true }; + + print_list() : Object { true }; +}; + + +Class Main { + + books : BookList; + + main() : Object { + (let a_book : Book <- + (new Book).initBook("Compilers, Principles, Techniques, and Tools", + "Aho, Sethi, and Ullman") + in + (let an_article : Article <- + (new Article).initArticle("The Top 100 CD_ROMs", + "Ulanoff", + "PC Magazine") + in + { + books <- (new Nil).cons(a_book).cons(an_article); + books.print_list(); + } + ) -- end let an_article + ) -- end let a_book + }; +}; diff --git a/src/testing.cl.cil b/src/testing.cl.cil new file mode 100644 index 000000000..787765124 --- /dev/null +++ b/src/testing.cl.cil @@ -0,0 +1,1026 @@ +.TYPES +type Object { + parent: None + + + method __init: __init_Object_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object +} +type String { + parent: Object + + + method __init: __init_String_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method length: function_length_at_String + method concat: function_concat_at_String + method substr: function_substr_at_String +} +type Bool { + parent: Object + + + method __init: __init_Bool_type + method abort: function_abort_at_Bool + method type_name: function_type_name_at_Bool + method copy: function_copy_at_Object +} +type Int { + parent: Object + + + method __init: __init_Int_type + method abort: function_abort_at_Int + method type_name: function_type_name_at_Int + method copy: function_copy_at_Object +} +type IO { + parent: Object + + + method __init: __init_IO_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO +} +type Foo { + parent: Bazz + attribute h + attribute g + attribute i + attribute a + attribute b + + method __init: __init_Foo_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method __init_h_at_Bazz: __init_h_at_Bazz + method __init_g_at_Bazz: __init_g_at_Bazz + method __init_i_at_Bazz: __init_i_at_Bazz + method printh: function_printh_at_Bazz + method doh: function_doh_at_Foo + method __init_a_at_Foo: __init_a_at_Foo + method __init_b_at_Foo: __init_b_at_Foo +} +type Bar { + parent: Razz + attribute h + attribute g + attribute i + attribute a + attribute b + attribute e + attribute f + attribute c + attribute d + + method __init: __init_Bar_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method __init_h_at_Bazz: __init_h_at_Bazz + method __init_g_at_Bazz: __init_g_at_Bazz + method __init_i_at_Bazz: __init_i_at_Bazz + method printh: function_printh_at_Bazz + method doh: function_doh_at_Foo + method __init_a_at_Foo: __init_a_at_Foo + method __init_b_at_Foo: __init_b_at_Foo + method __init_e_at_Razz: __init_e_at_Razz + method __init_f_at_Razz: __init_f_at_Razz + method __init_c_at_Bar: __init_c_at_Bar + method __init_d_at_Bar: __init_d_at_Bar +} +type Razz { + parent: Foo + attribute h + attribute g + attribute i + attribute a + attribute b + attribute e + attribute f + + method __init: __init_Razz_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method __init_h_at_Bazz: __init_h_at_Bazz + method __init_g_at_Bazz: __init_g_at_Bazz + method __init_i_at_Bazz: __init_i_at_Bazz + method printh: function_printh_at_Bazz + method doh: function_doh_at_Foo + method __init_a_at_Foo: __init_a_at_Foo + method __init_b_at_Foo: __init_b_at_Foo + method __init_e_at_Razz: __init_e_at_Razz + method __init_f_at_Razz: __init_f_at_Razz +} +type Bazz { + parent: IO + attribute h + attribute g + attribute i + + method __init: __init_Bazz_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method out_string: function_out_string_at_IO + method out_int: function_out_int_at_IO + method in_string: function_in_string_at_IO + method in_int: function_in_int_at_IO + method __init_h_at_Bazz: __init_h_at_Bazz + method __init_g_at_Bazz: __init_g_at_Bazz + method __init_i_at_Bazz: __init_i_at_Bazz + method printh: function_printh_at_Bazz + method doh: function_doh_at_Bazz +} +type Main { + parent: Object + attribute a + attribute b + attribute c + attribute d + + method __init: __init_Main_type + method abort: function_abort_at_Object + method type_name: function_type_name_at_Object + method copy: function_copy_at_Object + method __init_a_at_Main: __init_a_at_Main + method __init_b_at_Main: __init_b_at_Main + method __init_c_at_Main: __init_c_at_Main + method __init_d_at_Main: __init_d_at_Main + method main: function_main_at_Main +} + +.DATA +data_0 = "Object" +data_1 = "String" +data_2 = "Bool" +data_3 = "Int" +data_4 = "IO" +data_5 = "Foo" +data_6 = "Bar" +data_7 = "Razz" +data_8 = "Bazz" +data_9 = "Main" +data_10 = "Abort called from class " +data_11 = "\n" +data_12 = "do nothing" + +.CODE +function main { + + + LOCAL local_n_internal_0 + LOCAL local_n_internal_1 + LOCAL local_n_internal_2 + + local_n_internal_2 = ALLOCATE Main + ARG local_n_internal_2 + local_n_internal_2 = CALL __init_Main_type + ARG local_n_internal_2 + local_n_internal_1 = CALL function_main_at_Main + RETURN 0 +} +function type_distance { + PARAM type1 + PARAM type2 + + LOCAL local_distance_internal_0 + LOCAL local_distance_internal_1 + LOCAL local_distance_internal_2 + LOCAL local_distance_internal_3 + + local_distance_internal_3 = VOID + local_distance_internal_0 = 0 + LABEL distance_label_0 + local_distance_internal_1 = EQUAL type1 type2 + IF local_distance_internal_1 GOTO distance_label_1 + type1 = FATHER type1 + local_distance_internal_2 = EQUAL type1 local_distance_internal_3 + IF local_distance_internal_2 GOTO distance_label_2 + local_distance_internal_0 = local_distance_internal_0 + 1 + GOTO distance_label_0 + LABEL distance_label_2 + local_distance_internal_0 = -1 + LABEL distance_label_1 + RETURN local_distance_internal_0 +} +function function_length_at_String { + PARAM self + + LOCAL local_length_at_String_internal_0 + + local_length_at_String_internal_0 = LENGTH self + RETURN local_length_at_String_internal_0 +} +function function_concat_at_String { + PARAM self + PARAM s + + LOCAL local_concat_at_String_internal_0 + + local_concat_at_String_internal_0 = CONCAT self s + RETURN local_concat_at_String_internal_0 +} +function function_substr_at_String { + PARAM self + PARAM i + PARAM l + + LOCAL local_substr_at_String_internal_0 + + local_substr_at_String_internal_0 = SUBSTRING self i l + RETURN local_substr_at_String_internal_0 +} +function function_abort_at_Bool { + PARAM self + + LOCAL local_abort_at_Bool_internal_0 + LOCAL local_abort_at_Bool_internal_1 + LOCAL local_abort_at_Bool_internal_2 + LOCAL local_abort_at_Bool_internal_3 + LOCAL local_abort_at_Bool_internal_4 + + local_abort_at_Bool_internal_0 = LOAD data_2 + local_abort_at_Bool_internal_1 = LOAD data_10 + local_abort_at_Bool_internal_2 = LOAD data_11 + local_abort_at_Bool_internal_3 = CONCAT local_abort_at_Bool_internal_1 local_abort_at_Bool_internal_0 + local_abort_at_Bool_internal_4 = CONCAT local_abort_at_Bool_internal_3 local_abort_at_Bool_internal_2 + PRINT local_abort_at_Bool_internal_4 + ABORT + RETURN 0 +} +function function_type_name_at_Bool { + PARAM self + + LOCAL local_type_name_at_Bool_internal_0 + + local_type_name_at_Bool_internal_0 = LOAD data_2 + RETURN local_type_name_at_Bool_internal_0 +} +function function_abort_at_Int { + PARAM self + + LOCAL local_abort_at_Int_internal_0 + LOCAL local_abort_at_Int_internal_1 + LOCAL local_abort_at_Int_internal_2 + LOCAL local_abort_at_Int_internal_3 + LOCAL local_abort_at_Int_internal_4 + + local_abort_at_Int_internal_0 = LOAD data_3 + local_abort_at_Int_internal_1 = LOAD data_10 + local_abort_at_Int_internal_2 = LOAD data_11 + local_abort_at_Int_internal_3 = CONCAT local_abort_at_Int_internal_1 local_abort_at_Int_internal_0 + local_abort_at_Int_internal_4 = CONCAT local_abort_at_Int_internal_3 local_abort_at_Int_internal_2 + PRINT local_abort_at_Int_internal_4 + ABORT + RETURN 0 +} +function function_type_name_at_Int { + PARAM self + + LOCAL local_type_name_at_Int_internal_0 + + local_type_name_at_Int_internal_0 = LOAD data_3 + RETURN local_type_name_at_Int_internal_0 +} +function __init_c_at_Bar { + PARAM self + + LOCAL local__init_c_at_Bar_internal_0 + LOCAL local__init_c_at_Bar_internal_1 + + ARG self + local__init_c_at_Bar_internal_1 = TYPEOF self + local__init_c_at_Bar_internal_0 = VCALL local__init_c_at_Bar_internal_1 doh + SETATTR self c local__init_c_at_Bar_internal_0 + RETURN +} +function __init_d_at_Bar { + PARAM self + + LOCAL local__init_d_at_Bar_internal_0 + LOCAL local__init_d_at_Bar_internal_1 + + ARG self + local__init_d_at_Bar_internal_1 = TYPEOF self + local__init_d_at_Bar_internal_0 = VCALL local__init_d_at_Bar_internal_1 printh + SETATTR self d local__init_d_at_Bar_internal_0 + RETURN +} +function __init_a_at_Foo { + PARAM self + + LOCAL local__init_a_at_Foo_internal_0 + LOCAL local__init_a_at_Foo_internal_1 + LOCAL local__init_a_at_Foo_internal_2 + LOCAL local__init_a_at_Foo_internal_3 + LOCAL local__init_a_at_Foo_internal_4 + LOCAL local__init_a_at_Foo_internal_5 + LOCAL local__init_a_at_Foo_internal_6 + LOCAL local__init_a_at_Foo_internal_7 + LOCAL local__init_a_at_Foo_internal_8 + LOCAL local__init_a_at_Foo_internal_9 + LOCAL local__init_a_at_Foo_internal_10 + LOCAL local__init_a_at_Foo_internal_11 + LOCAL local__init_a_at_Foo_internal_12 + LOCAL local__init_a_at_Foo_n_13 + LOCAL local__init_a_at_Foo_internal_14 + LOCAL local__init_a_at_Foo_n_15 + LOCAL local__init_a_at_Foo_internal_16 + LOCAL local__init_a_at_Foo_n_17 + + local__init_a_at_Foo_internal_2 = VOID + local__init_a_at_Foo_internal_2 = EQUAL self local__init_a_at_Foo_internal_2 + IF local__init_a_at_Foo_internal_2 GOTO _init_a_at_Foo_label_0 + local__init_a_at_Foo_internal_1 = TYPEOF self + local__init_a_at_Foo_internal_3 = ARRAY Object 3 + SETINDEX local__init_a_at_Foo_internal_3 0 Razz + SETINDEX local__init_a_at_Foo_internal_3 1 Foo + SETINDEX local__init_a_at_Foo_internal_3 2 Bar + local__init_a_at_Foo_internal_4 = -1 + local__init_a_at_Foo_internal_6 = -2 + LABEL _init_a_at_Foo_label_1 + local__init_a_at_Foo_internal_4 = local__init_a_at_Foo_internal_4 + 1 + local__init_a_at_Foo_internal_9 = EQUAL local__init_a_at_Foo_internal_4 3 + IF local__init_a_at_Foo_internal_9 GOTO _init_a_at_Foo_label_3 + local__init_a_at_Foo_internal_8 = GETINDEX local__init_a_at_Foo_internal_3 local__init_a_at_Foo_internal_4 + ARG local__init_a_at_Foo_internal_1 + ARG local__init_a_at_Foo_internal_8 + local__init_a_at_Foo_internal_7 = CALL type_distance + local__init_a_at_Foo_internal_10 = EQUAL local__init_a_at_Foo_internal_7 -1 + IF local__init_a_at_Foo_internal_10 GOTO _init_a_at_Foo_label_1 + local__init_a_at_Foo_internal_11 = EQUAL local__init_a_at_Foo_internal_6 -2 + IF local__init_a_at_Foo_internal_11 GOTO _init_a_at_Foo_label_2 + local__init_a_at_Foo_internal_11 = local__init_a_at_Foo_internal_6 > local__init_a_at_Foo_internal_7 + IF local__init_a_at_Foo_internal_11 GOTO _init_a_at_Foo_label_2 + GOTO _init_a_at_Foo_label_1 + LABEL _init_a_at_Foo_label_2 + local__init_a_at_Foo_internal_6 = local__init_a_at_Foo_internal_7 + local__init_a_at_Foo_internal_5 = local__init_a_at_Foo_internal_4 + GOTO _init_a_at_Foo_label_1 + LABEL _init_a_at_Foo_label_3 + local__init_a_at_Foo_internal_11 = EQUAL local__init_a_at_Foo_internal_6 -2 + IF local__init_a_at_Foo_internal_11 GOTO _init_a_at_Foo_label_0 + local__init_a_at_Foo_internal_8 = GETINDEX local__init_a_at_Foo_internal_3 local__init_a_at_Foo_internal_5 + local__init_a_at_Foo_internal_12 = EQUAL Razz local__init_a_at_Foo_internal_8 + local__init_a_at_Foo_internal_12 = NOT local__init_a_at_Foo_internal_12 + IF local__init_a_at_Foo_internal_12 GOTO _init_a_at_Foo_label_5 + local__init_a_at_Foo_n_13 = self + local__init_a_at_Foo_internal_14 = ALLOCATE Bar + ARG local__init_a_at_Foo_internal_14 + local__init_a_at_Foo_internal_14 = CALL __init_Bar_type + local__init_a_at_Foo_internal_0 = local__init_a_at_Foo_internal_14 + GOTO _init_a_at_Foo_label_4 + LABEL _init_a_at_Foo_label_5 + local__init_a_at_Foo_internal_12 = EQUAL Foo local__init_a_at_Foo_internal_8 + local__init_a_at_Foo_internal_12 = NOT local__init_a_at_Foo_internal_12 + IF local__init_a_at_Foo_internal_12 GOTO _init_a_at_Foo_label_6 + local__init_a_at_Foo_n_15 = self + local__init_a_at_Foo_internal_16 = ALLOCATE Razz + ARG local__init_a_at_Foo_internal_16 + local__init_a_at_Foo_internal_16 = CALL __init_Razz_type + local__init_a_at_Foo_internal_0 = local__init_a_at_Foo_internal_16 + GOTO _init_a_at_Foo_label_4 + LABEL _init_a_at_Foo_label_6 + local__init_a_at_Foo_internal_12 = EQUAL Bar local__init_a_at_Foo_internal_8 + local__init_a_at_Foo_internal_12 = NOT local__init_a_at_Foo_internal_12 + IF local__init_a_at_Foo_internal_12 GOTO _init_a_at_Foo_label_7 + local__init_a_at_Foo_n_17 = self + local__init_a_at_Foo_internal_0 = local__init_a_at_Foo_n_17 + GOTO _init_a_at_Foo_label_4 + LABEL _init_a_at_Foo_label_7 + LABEL _init_a_at_Foo_label_0 + ABORT + LABEL _init_a_at_Foo_label_4 + SETATTR self a local__init_a_at_Foo_internal_0 + RETURN +} +function __init_b_at_Foo { + PARAM self + + LOCAL local__init_b_at_Foo_internal_0 + LOCAL local__init_b_at_Foo_internal_1 + LOCAL local__init_b_at_Foo_internal_2 + LOCAL local__init_b_at_Foo_internal_3 + LOCAL local__init_b_at_Foo_internal_4 + LOCAL local__init_b_at_Foo_internal_5 + LOCAL local__init_b_at_Foo_internal_6 + LOCAL local__init_b_at_Foo_internal_7 + LOCAL local__init_b_at_Foo_internal_8 + LOCAL local__init_b_at_Foo_internal_9 + LOCAL local__init_b_at_Foo_internal_10 + LOCAL local__init_b_at_Foo_internal_11 + LOCAL local__init_b_at_Foo_internal_12 + + local__init_b_at_Foo_internal_0 = GETATTR self a + ARG local__init_b_at_Foo_internal_0 + local__init_b_at_Foo_internal_2 = TYPEOF local__init_b_at_Foo_internal_0 + local__init_b_at_Foo_internal_1 = VCALL local__init_b_at_Foo_internal_2 doh + local__init_b_at_Foo_internal_3 = GETATTR self g + ARG local__init_b_at_Foo_internal_3 + local__init_b_at_Foo_internal_5 = TYPEOF local__init_b_at_Foo_internal_3 + local__init_b_at_Foo_internal_4 = VCALL local__init_b_at_Foo_internal_5 doh + local__init_b_at_Foo_internal_6 = local__init_b_at_Foo_internal_1 + local__init_b_at_Foo_internal_4 + ARG self + local__init_b_at_Foo_internal_8 = TYPEOF self + local__init_b_at_Foo_internal_7 = VCALL local__init_b_at_Foo_internal_8 doh + local__init_b_at_Foo_internal_9 = local__init_b_at_Foo_internal_6 + local__init_b_at_Foo_internal_7 + ARG self + local__init_b_at_Foo_internal_11 = TYPEOF self + local__init_b_at_Foo_internal_10 = VCALL local__init_b_at_Foo_internal_11 printh + local__init_b_at_Foo_internal_12 = local__init_b_at_Foo_internal_9 + local__init_b_at_Foo_internal_10 + SETATTR self b local__init_b_at_Foo_internal_12 + RETURN +} +function function_doh_at_Foo { + PARAM self + + LOCAL local_doh_at_Foo_i_0 + LOCAL local_doh_at_Foo_internal_1 + LOCAL local_doh_at_Foo_internal_2 + LOCAL local_doh_at_Foo_internal_3 + LOCAL local_doh_at_Foo_internal_4 + + local_doh_at_Foo_internal_1 = GETATTR self h + local_doh_at_Foo_i_0 = local_doh_at_Foo_internal_1 + local_doh_at_Foo_internal_3 = GETATTR self h + local_doh_at_Foo_internal_4 = local_doh_at_Foo_internal_3 + 2 + SETATTR self h local_doh_at_Foo_internal_4 + RETURN local_doh_at_Foo_i_0 +} +function __init_e_at_Razz { + PARAM self + + LOCAL local__init_e_at_Razz_internal_0 + LOCAL local__init_e_at_Razz_internal_1 + LOCAL local__init_e_at_Razz_internal_2 + LOCAL local__init_e_at_Razz_internal_3 + LOCAL local__init_e_at_Razz_internal_4 + LOCAL local__init_e_at_Razz_internal_5 + LOCAL local__init_e_at_Razz_internal_6 + LOCAL local__init_e_at_Razz_internal_7 + LOCAL local__init_e_at_Razz_internal_8 + LOCAL local__init_e_at_Razz_internal_9 + LOCAL local__init_e_at_Razz_internal_10 + LOCAL local__init_e_at_Razz_internal_11 + LOCAL local__init_e_at_Razz_internal_12 + LOCAL local__init_e_at_Razz_n_13 + LOCAL local__init_e_at_Razz_internal_14 + LOCAL local__init_e_at_Razz_n_15 + + local__init_e_at_Razz_internal_2 = VOID + local__init_e_at_Razz_internal_2 = EQUAL self local__init_e_at_Razz_internal_2 + IF local__init_e_at_Razz_internal_2 GOTO _init_e_at_Razz_label_0 + local__init_e_at_Razz_internal_1 = TYPEOF self + local__init_e_at_Razz_internal_3 = ARRAY Object 2 + SETINDEX local__init_e_at_Razz_internal_3 0 Razz + SETINDEX local__init_e_at_Razz_internal_3 1 Bar + local__init_e_at_Razz_internal_4 = -1 + local__init_e_at_Razz_internal_6 = -2 + LABEL _init_e_at_Razz_label_1 + local__init_e_at_Razz_internal_4 = local__init_e_at_Razz_internal_4 + 1 + local__init_e_at_Razz_internal_9 = EQUAL local__init_e_at_Razz_internal_4 2 + IF local__init_e_at_Razz_internal_9 GOTO _init_e_at_Razz_label_3 + local__init_e_at_Razz_internal_8 = GETINDEX local__init_e_at_Razz_internal_3 local__init_e_at_Razz_internal_4 + ARG local__init_e_at_Razz_internal_1 + ARG local__init_e_at_Razz_internal_8 + local__init_e_at_Razz_internal_7 = CALL type_distance + local__init_e_at_Razz_internal_10 = EQUAL local__init_e_at_Razz_internal_7 -1 + IF local__init_e_at_Razz_internal_10 GOTO _init_e_at_Razz_label_1 + local__init_e_at_Razz_internal_11 = EQUAL local__init_e_at_Razz_internal_6 -2 + IF local__init_e_at_Razz_internal_11 GOTO _init_e_at_Razz_label_2 + local__init_e_at_Razz_internal_11 = local__init_e_at_Razz_internal_6 > local__init_e_at_Razz_internal_7 + IF local__init_e_at_Razz_internal_11 GOTO _init_e_at_Razz_label_2 + GOTO _init_e_at_Razz_label_1 + LABEL _init_e_at_Razz_label_2 + local__init_e_at_Razz_internal_6 = local__init_e_at_Razz_internal_7 + local__init_e_at_Razz_internal_5 = local__init_e_at_Razz_internal_4 + GOTO _init_e_at_Razz_label_1 + LABEL _init_e_at_Razz_label_3 + local__init_e_at_Razz_internal_11 = EQUAL local__init_e_at_Razz_internal_6 -2 + IF local__init_e_at_Razz_internal_11 GOTO _init_e_at_Razz_label_0 + local__init_e_at_Razz_internal_8 = GETINDEX local__init_e_at_Razz_internal_3 local__init_e_at_Razz_internal_5 + local__init_e_at_Razz_internal_12 = EQUAL Razz local__init_e_at_Razz_internal_8 + local__init_e_at_Razz_internal_12 = NOT local__init_e_at_Razz_internal_12 + IF local__init_e_at_Razz_internal_12 GOTO _init_e_at_Razz_label_5 + local__init_e_at_Razz_n_13 = self + local__init_e_at_Razz_internal_14 = ALLOCATE Bar + ARG local__init_e_at_Razz_internal_14 + local__init_e_at_Razz_internal_14 = CALL __init_Bar_type + local__init_e_at_Razz_internal_0 = local__init_e_at_Razz_internal_14 + GOTO _init_e_at_Razz_label_4 + LABEL _init_e_at_Razz_label_5 + local__init_e_at_Razz_internal_12 = EQUAL Bar local__init_e_at_Razz_internal_8 + local__init_e_at_Razz_internal_12 = NOT local__init_e_at_Razz_internal_12 + IF local__init_e_at_Razz_internal_12 GOTO _init_e_at_Razz_label_6 + local__init_e_at_Razz_n_15 = self + local__init_e_at_Razz_internal_0 = local__init_e_at_Razz_n_15 + GOTO _init_e_at_Razz_label_4 + LABEL _init_e_at_Razz_label_6 + LABEL _init_e_at_Razz_label_0 + ABORT + LABEL _init_e_at_Razz_label_4 + SETATTR self e local__init_e_at_Razz_internal_0 + RETURN +} +function __init_f_at_Razz { + PARAM self + + LOCAL local__init_f_at_Razz_internal_0 + LOCAL local__init_f_at_Razz_internal_1 + LOCAL local__init_f_at_Razz_internal_2 + LOCAL local__init_f_at_Razz_internal_3 + LOCAL local__init_f_at_Razz_internal_4 + LOCAL local__init_f_at_Razz_internal_5 + LOCAL local__init_f_at_Razz_internal_6 + LOCAL local__init_f_at_Razz_internal_7 + LOCAL local__init_f_at_Razz_internal_8 + LOCAL local__init_f_at_Razz_internal_9 + LOCAL local__init_f_at_Razz_internal_10 + LOCAL local__init_f_at_Razz_internal_11 + LOCAL local__init_f_at_Razz_internal_12 + LOCAL local__init_f_at_Razz_internal_13 + LOCAL local__init_f_at_Razz_internal_14 + LOCAL local__init_f_at_Razz_internal_15 + + local__init_f_at_Razz_internal_0 = GETATTR self a + ARG local__init_f_at_Razz_internal_0 + local__init_f_at_Razz_internal_1 = CALL function_doh_at_Bazz + local__init_f_at_Razz_internal_2 = GETATTR self g + ARG local__init_f_at_Razz_internal_2 + local__init_f_at_Razz_internal_4 = TYPEOF local__init_f_at_Razz_internal_2 + local__init_f_at_Razz_internal_3 = VCALL local__init_f_at_Razz_internal_4 doh + local__init_f_at_Razz_internal_5 = local__init_f_at_Razz_internal_1 + local__init_f_at_Razz_internal_3 + local__init_f_at_Razz_internal_6 = GETATTR self e + ARG local__init_f_at_Razz_internal_6 + local__init_f_at_Razz_internal_8 = TYPEOF local__init_f_at_Razz_internal_6 + local__init_f_at_Razz_internal_7 = VCALL local__init_f_at_Razz_internal_8 doh + local__init_f_at_Razz_internal_9 = local__init_f_at_Razz_internal_5 + local__init_f_at_Razz_internal_7 + ARG self + local__init_f_at_Razz_internal_11 = TYPEOF self + local__init_f_at_Razz_internal_10 = VCALL local__init_f_at_Razz_internal_11 doh + local__init_f_at_Razz_internal_12 = local__init_f_at_Razz_internal_9 + local__init_f_at_Razz_internal_10 + ARG self + local__init_f_at_Razz_internal_14 = TYPEOF self + local__init_f_at_Razz_internal_13 = VCALL local__init_f_at_Razz_internal_14 printh + local__init_f_at_Razz_internal_15 = local__init_f_at_Razz_internal_12 + local__init_f_at_Razz_internal_13 + SETATTR self f local__init_f_at_Razz_internal_15 + RETURN +} +function function_out_string_at_IO { + PARAM self + PARAM x + + + + PRINT x + RETURN self +} +function function_out_int_at_IO { + PARAM self + PARAM x + + + + PRINTINT x + RETURN self +} +function function_in_string_at_IO { + PARAM self + + LOCAL local_in_string_at_IO_internal_0 + + local_in_string_at_IO_internal_0 = READ + RETURN local_in_string_at_IO_internal_0 +} +function function_in_int_at_IO { + PARAM self + + LOCAL local_in_int_at_IO_internal_0 + + local_in_int_at_IO_internal_0 = READINT + RETURN local_in_int_at_IO_internal_0 +} +function __init_h_at_Bazz { + PARAM self + + + + SETATTR self h 1 + RETURN +} +function __init_g_at_Bazz { + PARAM self + + LOCAL local__init_g_at_Bazz_internal_0 + LOCAL local__init_g_at_Bazz_internal_1 + LOCAL local__init_g_at_Bazz_internal_2 + LOCAL local__init_g_at_Bazz_internal_3 + LOCAL local__init_g_at_Bazz_internal_4 + LOCAL local__init_g_at_Bazz_internal_5 + LOCAL local__init_g_at_Bazz_internal_6 + LOCAL local__init_g_at_Bazz_internal_7 + LOCAL local__init_g_at_Bazz_internal_8 + LOCAL local__init_g_at_Bazz_internal_9 + LOCAL local__init_g_at_Bazz_internal_10 + LOCAL local__init_g_at_Bazz_internal_11 + LOCAL local__init_g_at_Bazz_internal_12 + LOCAL local__init_g_at_Bazz_n_13 + LOCAL local__init_g_at_Bazz_internal_14 + LOCAL local__init_g_at_Bazz_n_15 + LOCAL local__init_g_at_Bazz_internal_16 + LOCAL local__init_g_at_Bazz_n_17 + LOCAL local__init_g_at_Bazz_internal_18 + LOCAL local__init_g_at_Bazz_n_19 + + local__init_g_at_Bazz_internal_2 = VOID + local__init_g_at_Bazz_internal_2 = EQUAL self local__init_g_at_Bazz_internal_2 + IF local__init_g_at_Bazz_internal_2 GOTO _init_g_at_Bazz_label_0 + local__init_g_at_Bazz_internal_1 = TYPEOF self + local__init_g_at_Bazz_internal_3 = ARRAY Object 4 + SETINDEX local__init_g_at_Bazz_internal_3 0 Bazz + SETINDEX local__init_g_at_Bazz_internal_3 1 Razz + SETINDEX local__init_g_at_Bazz_internal_3 2 Foo + SETINDEX local__init_g_at_Bazz_internal_3 3 Bar + local__init_g_at_Bazz_internal_4 = -1 + local__init_g_at_Bazz_internal_6 = -2 + LABEL _init_g_at_Bazz_label_1 + local__init_g_at_Bazz_internal_4 = local__init_g_at_Bazz_internal_4 + 1 + local__init_g_at_Bazz_internal_9 = EQUAL local__init_g_at_Bazz_internal_4 4 + IF local__init_g_at_Bazz_internal_9 GOTO _init_g_at_Bazz_label_3 + local__init_g_at_Bazz_internal_8 = GETINDEX local__init_g_at_Bazz_internal_3 local__init_g_at_Bazz_internal_4 + ARG local__init_g_at_Bazz_internal_1 + ARG local__init_g_at_Bazz_internal_8 + local__init_g_at_Bazz_internal_7 = CALL type_distance + local__init_g_at_Bazz_internal_10 = EQUAL local__init_g_at_Bazz_internal_7 -1 + IF local__init_g_at_Bazz_internal_10 GOTO _init_g_at_Bazz_label_1 + local__init_g_at_Bazz_internal_11 = EQUAL local__init_g_at_Bazz_internal_6 -2 + IF local__init_g_at_Bazz_internal_11 GOTO _init_g_at_Bazz_label_2 + local__init_g_at_Bazz_internal_11 = local__init_g_at_Bazz_internal_6 > local__init_g_at_Bazz_internal_7 + IF local__init_g_at_Bazz_internal_11 GOTO _init_g_at_Bazz_label_2 + GOTO _init_g_at_Bazz_label_1 + LABEL _init_g_at_Bazz_label_2 + local__init_g_at_Bazz_internal_6 = local__init_g_at_Bazz_internal_7 + local__init_g_at_Bazz_internal_5 = local__init_g_at_Bazz_internal_4 + GOTO _init_g_at_Bazz_label_1 + LABEL _init_g_at_Bazz_label_3 + local__init_g_at_Bazz_internal_11 = EQUAL local__init_g_at_Bazz_internal_6 -2 + IF local__init_g_at_Bazz_internal_11 GOTO _init_g_at_Bazz_label_0 + local__init_g_at_Bazz_internal_8 = GETINDEX local__init_g_at_Bazz_internal_3 local__init_g_at_Bazz_internal_5 + local__init_g_at_Bazz_internal_12 = EQUAL Bazz local__init_g_at_Bazz_internal_8 + local__init_g_at_Bazz_internal_12 = NOT local__init_g_at_Bazz_internal_12 + IF local__init_g_at_Bazz_internal_12 GOTO _init_g_at_Bazz_label_5 + local__init_g_at_Bazz_n_13 = self + local__init_g_at_Bazz_internal_14 = ALLOCATE Foo + ARG local__init_g_at_Bazz_internal_14 + local__init_g_at_Bazz_internal_14 = CALL __init_Foo_type + local__init_g_at_Bazz_internal_0 = local__init_g_at_Bazz_internal_14 + GOTO _init_g_at_Bazz_label_4 + LABEL _init_g_at_Bazz_label_5 + local__init_g_at_Bazz_internal_12 = EQUAL Razz local__init_g_at_Bazz_internal_8 + local__init_g_at_Bazz_internal_12 = NOT local__init_g_at_Bazz_internal_12 + IF local__init_g_at_Bazz_internal_12 GOTO _init_g_at_Bazz_label_6 + local__init_g_at_Bazz_n_15 = self + local__init_g_at_Bazz_internal_16 = ALLOCATE Bar + ARG local__init_g_at_Bazz_internal_16 + local__init_g_at_Bazz_internal_16 = CALL __init_Bar_type + local__init_g_at_Bazz_internal_0 = local__init_g_at_Bazz_internal_16 + GOTO _init_g_at_Bazz_label_4 + LABEL _init_g_at_Bazz_label_6 + local__init_g_at_Bazz_internal_12 = EQUAL Foo local__init_g_at_Bazz_internal_8 + local__init_g_at_Bazz_internal_12 = NOT local__init_g_at_Bazz_internal_12 + IF local__init_g_at_Bazz_internal_12 GOTO _init_g_at_Bazz_label_7 + local__init_g_at_Bazz_n_17 = self + local__init_g_at_Bazz_internal_18 = ALLOCATE Razz + ARG local__init_g_at_Bazz_internal_18 + local__init_g_at_Bazz_internal_18 = CALL __init_Razz_type + local__init_g_at_Bazz_internal_0 = local__init_g_at_Bazz_internal_18 + GOTO _init_g_at_Bazz_label_4 + LABEL _init_g_at_Bazz_label_7 + local__init_g_at_Bazz_internal_12 = EQUAL Bar local__init_g_at_Bazz_internal_8 + local__init_g_at_Bazz_internal_12 = NOT local__init_g_at_Bazz_internal_12 + IF local__init_g_at_Bazz_internal_12 GOTO _init_g_at_Bazz_label_8 + local__init_g_at_Bazz_n_19 = self + local__init_g_at_Bazz_internal_0 = local__init_g_at_Bazz_n_19 + GOTO _init_g_at_Bazz_label_4 + LABEL _init_g_at_Bazz_label_8 + LABEL _init_g_at_Bazz_label_0 + ABORT + LABEL _init_g_at_Bazz_label_4 + SETATTR self g local__init_g_at_Bazz_internal_0 + RETURN +} +function __init_i_at_Bazz { + PARAM self + + LOCAL local__init_i_at_Bazz_internal_0 + LOCAL local__init_i_at_Bazz_internal_1 + + ARG self + local__init_i_at_Bazz_internal_1 = TYPEOF self + local__init_i_at_Bazz_internal_0 = VCALL local__init_i_at_Bazz_internal_1 printh + SETATTR self i local__init_i_at_Bazz_internal_0 + RETURN +} +function function_printh_at_Bazz { + PARAM self + + LOCAL local_printh_at_Bazz_internal_0 + LOCAL local_printh_at_Bazz_internal_1 + LOCAL local_printh_at_Bazz_internal_2 + LOCAL local_printh_at_Bazz_internal_3 + + local_printh_at_Bazz_internal_1 = GETATTR self h + ARG self + ARG local_printh_at_Bazz_internal_1 + local_printh_at_Bazz_internal_3 = TYPEOF self + local_printh_at_Bazz_internal_2 = VCALL local_printh_at_Bazz_internal_3 out_int + RETURN 0 +} +function function_doh_at_Bazz { + PARAM self + + LOCAL local_doh_at_Bazz_i_0 + LOCAL local_doh_at_Bazz_internal_1 + LOCAL local_doh_at_Bazz_internal_2 + LOCAL local_doh_at_Bazz_internal_3 + LOCAL local_doh_at_Bazz_internal_4 + + local_doh_at_Bazz_internal_1 = GETATTR self h + local_doh_at_Bazz_i_0 = local_doh_at_Bazz_internal_1 + local_doh_at_Bazz_internal_3 = GETATTR self h + local_doh_at_Bazz_internal_4 = local_doh_at_Bazz_internal_3 + 1 + SETATTR self h local_doh_at_Bazz_internal_4 + RETURN local_doh_at_Bazz_i_0 +} +function function_abort_at_Object { + PARAM self + + LOCAL local_abort_at_Object_internal_0 + LOCAL local_abort_at_Object_internal_1 + LOCAL local_abort_at_Object_internal_2 + LOCAL local_abort_at_Object_internal_3 + LOCAL local_abort_at_Object_internal_4 + LOCAL local_abort_at_Object_internal_5 + + local_abort_at_Object_internal_0 = TYPEOF self + local_abort_at_Object_internal_1 = TYPENAME local_abort_at_Object_internal_0 + local_abort_at_Object_internal_2 = LOAD data_10 + local_abort_at_Object_internal_3 = LOAD data_11 + local_abort_at_Object_internal_4 = CONCAT local_abort_at_Object_internal_2 local_abort_at_Object_internal_1 + local_abort_at_Object_internal_5 = CONCAT local_abort_at_Object_internal_4 local_abort_at_Object_internal_3 + PRINT local_abort_at_Object_internal_5 + ABORT + RETURN 0 +} +function function_type_name_at_Object { + PARAM self + + LOCAL local_type_name_at_Object_internal_0 + + local_type_name_at_Object_internal_0 = TYPEOF self + local_type_name_at_Object_internal_0 = TYPENAME local_type_name_at_Object_internal_0 + RETURN local_type_name_at_Object_internal_0 +} +function function_copy_at_Object { + PARAM self + + LOCAL local_copy_at_Object_internal_0 + + local_copy_at_Object_internal_0 = COPY self + RETURN local_copy_at_Object_internal_0 +} +function __init_a_at_Main { + PARAM self + + LOCAL local__init_a_at_Main_internal_0 + + local__init_a_at_Main_internal_0 = ALLOCATE Bazz + ARG local__init_a_at_Main_internal_0 + local__init_a_at_Main_internal_0 = CALL __init_Bazz_type + SETATTR self a local__init_a_at_Main_internal_0 + RETURN +} +function __init_b_at_Main { + PARAM self + + LOCAL local__init_b_at_Main_internal_0 + + local__init_b_at_Main_internal_0 = ALLOCATE Foo + ARG local__init_b_at_Main_internal_0 + local__init_b_at_Main_internal_0 = CALL __init_Foo_type + SETATTR self b local__init_b_at_Main_internal_0 + RETURN +} +function __init_c_at_Main { + PARAM self + + LOCAL local__init_c_at_Main_internal_0 + + local__init_c_at_Main_internal_0 = ALLOCATE Razz + ARG local__init_c_at_Main_internal_0 + local__init_c_at_Main_internal_0 = CALL __init_Razz_type + SETATTR self c local__init_c_at_Main_internal_0 + RETURN +} +function __init_d_at_Main { + PARAM self + + LOCAL local__init_d_at_Main_internal_0 + + local__init_d_at_Main_internal_0 = ALLOCATE Bar + ARG local__init_d_at_Main_internal_0 + local__init_d_at_Main_internal_0 = CALL __init_Bar_type + SETATTR self d local__init_d_at_Main_internal_0 + RETURN +} +function function_main_at_Main { + PARAM self + + LOCAL local_main_at_Main_internal_0 + + local_main_at_Main_internal_0 = LOAD data_12 + RETURN local_main_at_Main_internal_0 +} +function __init_Object_type { + PARAM self + + + + + RETURN self +} +function __init_String_type { + PARAM self + + + + + RETURN self +} +function __init_Bool_type { + PARAM self + + + + + RETURN self +} +function __init_Int_type { + PARAM self + + + + + RETURN self +} +function __init_IO_type { + PARAM self + + + + + RETURN self +} +function __init_Foo_type { + PARAM self + + LOCAL local__init_Foo_type_internal_0 + LOCAL local__init_Foo_type_internal_1 + LOCAL local__init_Foo_type_internal_2 + LOCAL local__init_Foo_type_internal_3 + LOCAL local__init_Foo_type_internal_4 + + + ARG self + local__init_Foo_type_internal_0 = CALL __init_h_at_Bazz + ARG self + local__init_Foo_type_internal_1 = CALL __init_g_at_Bazz + ARG self + local__init_Foo_type_internal_2 = CALL __init_i_at_Bazz + ARG self + local__init_Foo_type_internal_3 = CALL __init_a_at_Foo + ARG self + local__init_Foo_type_internal_4 = CALL __init_b_at_Foo + RETURN self +} +function __init_Bar_type { + PARAM self + + LOCAL local__init_Bar_type_internal_0 + LOCAL local__init_Bar_type_internal_1 + LOCAL local__init_Bar_type_internal_2 + LOCAL local__init_Bar_type_internal_3 + LOCAL local__init_Bar_type_internal_4 + LOCAL local__init_Bar_type_internal_5 + LOCAL local__init_Bar_type_internal_6 + LOCAL local__init_Bar_type_internal_7 + LOCAL local__init_Bar_type_internal_8 + + + ARG self + local__init_Bar_type_internal_0 = CALL __init_h_at_Bazz + ARG self + local__init_Bar_type_internal_1 = CALL __init_g_at_Bazz + ARG self + local__init_Bar_type_internal_2 = CALL __init_i_at_Bazz + ARG self + local__init_Bar_type_internal_3 = CALL __init_a_at_Foo + ARG self + local__init_Bar_type_internal_4 = CALL __init_b_at_Foo + ARG self + local__init_Bar_type_internal_5 = CALL __init_e_at_Razz + ARG self + local__init_Bar_type_internal_6 = CALL __init_f_at_Razz + ARG self + local__init_Bar_type_internal_7 = CALL __init_c_at_Bar + ARG self + local__init_Bar_type_internal_8 = CALL __init_d_at_Bar + RETURN self +} +function __init_Razz_type { + PARAM self + + LOCAL local__init_Razz_type_internal_0 + LOCAL local__init_Razz_type_internal_1 + LOCAL local__init_Razz_type_internal_2 + LOCAL local__init_Razz_type_internal_3 + LOCAL local__init_Razz_type_internal_4 + LOCAL local__init_Razz_type_internal_5 + LOCAL local__init_Razz_type_internal_6 + + + ARG self + local__init_Razz_type_internal_0 = CALL __init_h_at_Bazz + ARG self + local__init_Razz_type_internal_1 = CALL __init_g_at_Bazz + ARG self + local__init_Razz_type_internal_2 = CALL __init_i_at_Bazz + ARG self + local__init_Razz_type_internal_3 = CALL __init_a_at_Foo + ARG self + local__init_Razz_type_internal_4 = CALL __init_b_at_Foo + ARG self + local__init_Razz_type_internal_5 = CALL __init_e_at_Razz + ARG self + local__init_Razz_type_internal_6 = CALL __init_f_at_Razz + RETURN self +} +function __init_Bazz_type { + PARAM self + + LOCAL local__init_Bazz_type_internal_0 + LOCAL local__init_Bazz_type_internal_1 + LOCAL local__init_Bazz_type_internal_2 + + + ARG self + local__init_Bazz_type_internal_0 = CALL __init_h_at_Bazz + ARG self + local__init_Bazz_type_internal_1 = CALL __init_g_at_Bazz + ARG self + local__init_Bazz_type_internal_2 = CALL __init_i_at_Bazz + RETURN self +} +function __init_Main_type { + PARAM self + + LOCAL local__init_Main_type_internal_0 + LOCAL local__init_Main_type_internal_1 + LOCAL local__init_Main_type_internal_2 + LOCAL local__init_Main_type_internal_3 + + + ARG self + local__init_Main_type_internal_0 = CALL __init_a_at_Main + ARG self + local__init_Main_type_internal_1 = CALL __init_b_at_Main + ARG self + local__init_Main_type_internal_2 = CALL __init_c_at_Main + ARG self + local__init_Main_type_internal_3 = CALL __init_d_at_Main + RETURN self +} \ No newline at end of file diff --git a/src/testing.cl.infer.cl b/src/testing.cl.infer.cl new file mode 100644 index 000000000..85a5e0173 --- /dev/null +++ b/src/testing.cl.infer.cl @@ -0,0 +1,37 @@ +class A inherits IO +{ + p(): Int + { + 0 + }; +} + + +class Main inherits A +{ + msg:String <- "Hello World"; + p(): Int + { + 1 + }; + main(): Int + { + let + x0:Int <- + 0, + x1:Int <- + 1, + x2:Int <- + let + x1:Int <- + 2, + x2:Int <- + (x1 + 1) + in + ((x0 + x1) + x2) + in + (x1 + x2) + }; +} + + diff --git a/src/testing.mips b/src/testing.mips new file mode 100644 index 000000000..e2c2985e6 --- /dev/null +++ b/src/testing.mips @@ -0,0 +1,3655 @@ +# Genereted MIPS +.text + +__get_ra: + move $v0, $ra + addi $v0, $v0, 8 + jr $ra + +__copy: + move $t0, $a0 + lw $t1, 0($t0) + lw $a0, 4($t1) + li $v0, 9 + syscall + move $t1, $a0 + srl $t1, $t1, 2 + move $t3, $v0 + __start_copy_loop: + ble $t1, $zero, __end_copy_loop + lw $t2, 0($t0) + sw $t2, 0($t3) + addi $t0, $t0, 4 + addi $t3, $t3, 4 + addi $t1, $t1, -1 + j __start_copy_loop + __end_copy_loop: + jr $ra + +__string_length: + # Actual String address + lw $a0, 4($a0) + # v0 = current length + li $v0, 0 + __string_length_start_loop: + lb $t0, 0($a0) + beq $t0, $zero, __string_length_end_loop + addi $v0, $v0, 1 + addi $a0, $a0, 1 + j __string_length_start_loop + __string_length_end_loop: + jr $ra + +__string_substring: + # Save arguments + addi $sp, $sp, -16 + # Save arguments + sw $a0, 0($sp) + # Save arguments + sw $a1, 4($sp) + # Save arguments + sw $a2, 8($sp) + # Save arguments + sw $ra, 12($sp) + # $v0 = length of string + jal __string_length + # Restore arguments + lw $a0, 0($sp) + # Restore arguments + lw $a1, 4($sp) + # Restore arguments + lw $a2, 8($sp) + # Restore arguments + lw $ra, 12($sp) + # Restore arguments + addi $sp, $sp, 16 + # Actual String address + lw $a0, 4($a0) + # If index >= length(string) then abort + bge $a1, $v0, __string_substring_abort + # t0 = index + length + add $t0, $a1, $a2 + # If index + length >= length(string) then abort + bgt $t0, $v0, __string_substring_abort + # If 0 < 0 then abort + blt $a2, $zero, __string_substring_abort + # Saving the string address + move $t1, $a0 + # a0 = length + 1. Extra space for null character + addi $a0, $a2, 1 + li $v0, 9 + syscall + # Saving the new string address + move $t2, $v0 + # Removing the last null space from copy + addi $a0, $a0, -1 + # Advance index positions in original string + add $t1, $t1, $a1 + __string_substring_start_copy: + ble $a0, $zero, __string_substring_end_copy + lb $t3, 0($t1) + sb $t3, 0($t2) + addi $t1, $t1, 1 + addi $t2, $t2, 1 + addi $a0, $a0, -1 + j __string_substring_start_copy + __string_substring_end_copy: + # Saving String Address + move $v1, $v0 + # Type address into $a0 + la $t0, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t0, 0($v0) + # Store String Address + sw $v1, 4($v0) + # Return the address of the new String + jr $ra + __string_substring_abort: + addi $v0, $zero, 10 + syscall + +__type_name: + # $t0 = type name address + lw $t0, 8($a0) + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Return the address of the String + jr $ra + +__concat: + addi $sp, $sp, -12 + sw $a0, 0($sp) + sw $a1, 4($sp) + sw $ra, 8($sp) + jal __string_length + lw $a0, 0($sp) + lw $a1, 4($sp) + lw $ra, 8($sp) + addi $sp, $sp, 12 + move $t1, $a0 + move $a0, $a1 + move $a1, $t1 + move $t0, $v0 + addi $sp, $sp, -16 + sw $a0, 0($sp) + sw $a1, 4($sp) + sw $t0, 8($sp) + sw $ra, 12($sp) + jal __string_length + lw $a0, 0($sp) + lw $a1, 4($sp) + lw $t0, 8($sp) + lw $ra, 12($sp) + addi $sp, $sp, 16 + move $t1, $a0 + move $a0, $a1 + move $a1, $t1 + lw $a0, 4($a0) + lw $a1, 4($a1) + move $t1, $a0 + add $t2, $v0, $t0 + addi $a0, $t2, 1 + move $t2, $v0 + li $v0, 9 + syscall + # Save string address + move $v1, $v0 + __concat_string1_copy_start_copy: + ble $t0, $zero, __concat_string1_copy_end_copy + lb $t3, 0($t1) + sb $t3, 0($v1) + addi $t1, $t1, 1 + addi $v1, $v1, 1 + addi $t0, $t0, -1 + j __concat_string1_copy_start_copy + __concat_string1_copy_end_copy: + __concat_string2_copy_start_copy: + ble $t2, $zero, __concat_string2_copy_end_copy + lb $t3, 0($a1) + sb $t3, 0($v1) + addi $a1, $a1, 1 + addi $v1, $v1, 1 + addi $t2, $t2, -1 + j __concat_string2_copy_start_copy + __concat_string2_copy_end_copy: + sb $zero, 0($v1) + # Save string address + move $v1, $v0 + # Type address into $a0 + la $t0, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t0, 0($v0) + # Store String Address + sw $v1, 4($v0) + # Returns the concatenated string instance in v0 + jr $ra + # String Equal Function + +__string_equal: + # Actual String address + lw $t0, 4($a0) + # Actual String address + lw $t1, 4($a1) + __string_equal_start_loop: + # Load string1 char + lb $t2, 0($t0) + # Load string2 char + lb $t3, 0($t1) + # Equal chars? + seq $t4, $t2, $t3 + # If not equal then + beq $t4, $zero, __string_equal_end_loop + # Both strings ended + beq $t2, $zero, __string_equal_end_loop + # Next char + addi $t0, $t0, 1 + # Next char + addi $t1, $t1, 1 + j __string_equal_start_loop + __string_equal_end_loop: + # Assign return value + move $v0, $t4 + jr $ra + # Object Equal Function + +__object_equal: + # Compare obj by address + seq $v0, $a0, $a1 + # Equal Address or Value obj are equal + bne $v0, $zero, __object_equal_end + # Check if first obj is null + seq $t0, $zero, $a0 + # Set v0 to False and return + bne $t0, $zero, __object_equal_false_section + # Check if second obj is null + seq $t0, $zero, $a1 + # Set v0 to False and return + bne $t0, $zero, __object_equal_false_section + # t0 = left object + move $t0, $a0 + # t1 = right object + move $t1, $a1 + # t0=left objType + lw $t0, 0($t0) + # t1=right objType + lw $t1, 0($t1) + # Loading String type address for comparison + la $t2, String + # t0 = left type == String + seq $t0, $t0, $t2 + # t1 = right type == String + seq $t1, $t1, $t2 + # Both types are equal to String + and $t0, $t0, $t1 + # If not equal return 0 + beq $t0, $zero, __object_equal_false_section + addi $sp, $sp, -12 + sw $ra, 0($sp) + sw $a0, 4($sp) + sw $a1, 8($sp) + jal __string_equal + lw $ra, 0($sp) + lw $a0, 4($sp) + lw $a1, 8($sp) + addi $sp, $sp, 12 + # Go to end + j __object_equal_end + # Do Obj cmp + __object_equal_false_section: + # Not equal objects + move $v0, $zero + # End cmp + __object_equal_end: + jr $ra + # Remove Final Char + +__remove_last_char: + # Actual String address + lw $t0, 4($a0) + # Get current char + lb $t1, 0($t0) + # if char is null then return + beq $t1, $zero, __remove_last_char_return + # Initial loop + __remove_last_char_start: + # Get current char + lb $t1, 0($t0) + # if char is null then break + beq $t1, $zero, __remove_last_char_end + # Increment address + addi $t0, $t0, 1 + j __remove_last_char_start + # End loop, removing last char + __remove_last_char_end: + # Back one char to last one + addi $t0, $t0, -1 + # Store null character + sb $zero, 0($t0) + # Return, removing last char + __remove_last_char_return: + jr $ra + # Program Node + +main: + # Program Node + addi $sp, $sp, -12 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 +# Allocate + # Instantiate Node + la $a0, Main + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 8($fp) + # Instantiate Node + lw $t0, 8($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Main_type + # Instantiate Node + sw $v0, 8($fp) + lw $t0, 8($fp) + addi $sp, $sp, -4 + sw $t0, 0($sp) + # Program Node + jal function_main_at_Main + # Program Node + sw $v0, 4($fp) + # Program Node + li $v0, 0 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 12 + # Program Node + jr $ra + # Program Node + +type_distance: + # Program Node + addi $sp, $sp, -16 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Program Node + sw $zero, 12($fp) + # Program Node + li $t0, 0 + # Program Node + sw $t0, 0($fp) + # Program Node + distance_label_0: + # Program Node + lw $t0, 20($fp) + # Program Node + lw $t1, 16($fp) + # Program Node + seq $t2, $t0, $t1 + # Program Node + sw $t2, 4($fp) + # Program Node + lw $t0, 4($fp) + # Program Node + bne $t0, $zero, distance_label_1 + # Program Node + lw $t0, 20($fp) + # Program Node + lw $t0, 0($t0) + # Program Node + sw $t0, 20($fp) + # Program Node + lw $t0, 20($fp) + # Program Node + lw $t1, 12($fp) + # Program Node + seq $t2, $t0, $t1 + # Program Node + sw $t2, 8($fp) + # Program Node + lw $t0, 8($fp) + # Program Node + bne $t0, $zero, distance_label_2 + # Program Node + lw $t0, 0($fp) + # Program Node + li $t1, 1 + # Program Node + add $t2, $t0, $t1 + # Program Node + sw $t2, 0($fp) + # Program Node + j distance_label_0 + # Program Node + distance_label_2: + # Program Node + li $t0, -1 + # Program Node + sw $t0, 0($fp) + # Program Node + distance_label_1: + # Program Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 24 + # Program Node + jr $ra + # Program Node + +function_length_at_String: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # String Length Node + lw $a0, 4($fp) + # String Length Node + jal __string_length + # String Length Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_concat_at_String: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # String Concat Node + lw $a0, 8($fp) + # String Concat Node + lw $a1, 4($fp) + # String Concat Node + jal __concat + # String Concat Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 12 + # Program Node + jr $ra + # Program Node + +function_substr_at_String: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # String Substring Node + lw $a0, 12($fp) + # String Substring Node + lw $a1, 8($fp) + # String Substring Node + lw $a2, 4($fp) + # String Substring Node + jal __string_substring + # String Substring Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 16 + # Program Node + jr $ra + # Program Node + +function_abort_at_Bool: + # Program Node + addi $sp, $sp, -20 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + la $t0, data_2 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + la $t0, data_11 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 4($fp) + la $t0, data_12 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 8($fp) + # Final abort message + lw $a0, 4($fp) + # Final abort message + lw $a1, 0($fp) + # Final abort message + jal __concat + # Final abort message + sw $v0, 12($fp) + # Final Final abort message + lw $a0, 12($fp) + # Final Final abort message + lw $a1, 8($fp) + # Final Final abort message + jal __concat + # Final Final abort message + sw $v0, 16($fp) + # Print abort info + lw $a0, 16($fp) + # Getting the String address + lw $a0, 4($a0) + # 4 System call code for print string + addi $v0, $zero, 4 + syscall + # Abort Bool + addi $v0, $zero, 10 + # Abort Bool + syscall + # Func Declaration Node + li $v0, 0 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 24 + # Program Node + jr $ra + # Program Node + +function_type_name_at_Bool: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + la $t0, data_2 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_abort_at_Int: + # Program Node + addi $sp, $sp, -20 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + la $t0, data_3 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + la $t0, data_11 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 4($fp) + la $t0, data_12 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 8($fp) + # Final abort message + lw $a0, 4($fp) + # Final abort message + lw $a1, 0($fp) + # Final abort message + jal __concat + # Final abort message + sw $v0, 12($fp) + # Final Final abort message + lw $a0, 12($fp) + # Final Final abort message + lw $a1, 8($fp) + # Final Final abort message + jal __concat + # Final Final abort message + sw $v0, 16($fp) + # Print abort info + lw $a0, 16($fp) + # Getting the String address + lw $a0, 4($a0) + # 4 System call code for print string + addi $v0, $zero, 4 + syscall + # Abort Int + addi $v0, $zero, 10 + # Abort Int + syscall + # Func Declaration Node + li $v0, 0 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 24 + # Program Node + jr $ra + # Program Node + +function_type_name_at_Int: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + la $t0, data_3 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Init title at Book + +__init_title_at_Book: + # Init title at Book + addi $sp, $sp, -4 + # Init title at Book + move $t0, $sp + # Init title at Book + addi $sp, $sp, -8 + # Init title at Book + sw $ra, 0($sp) + # Init title at Book + sw $fp, 4($sp) + # Init title at Book + move $fp, $t0 + # String Node + la $t0, data_13 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 4($t0) + # Init title at Book + lw $ra, 0($sp) + # Init title at Book + lw $fp, 4($sp) + # Init title at Book + addi $sp, $sp, 8 + # Init title at Book + addi $sp, $sp, 8 + # Init title at Book + jr $ra + # Init author at Book + +__init_author_at_Book: + # Init author at Book + addi $sp, $sp, -4 + # Init author at Book + move $t0, $sp + # Init author at Book + addi $sp, $sp, -8 + # Init author at Book + sw $ra, 0($sp) + # Init author at Book + sw $fp, 4($sp) + # Init author at Book + move $fp, $t0 + # String Node + la $t0, data_14 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 8($t0) + # Init author at Book + lw $ra, 0($sp) + # Init author at Book + lw $fp, 4($sp) + # Init author at Book + addi $sp, $sp, 8 + # Init author at Book + addi $sp, $sp, 8 + # Init author at Book + jr $ra + # Program Node + +function_initBook_at_Book: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Assign Node + lw $t0, 12($fp) + # Assign Node + lw $t1, 8($fp) + # Assign Node + sw $t1, 4($t0) + # Assign Node + lw $t0, 12($fp) + # Assign Node + lw $t1, 4($fp) + # Assign Node + sw $t1, 8($t0) + # Func Declaration Node + lw $v0, 12($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 16 + # Program Node + jr $ra + # Program Node + +function_print_at_Book: + # Program Node + addi $sp, $sp, -76 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # String Node + la $t0, data_15 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 4($fp) + # Call Node + lw $t0, 76($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 4($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 76($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 12($fp) + # Call Node + lw $t0, 12($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 8($fp) + # Variable Node + lw $t0, 76($fp) + # Variable Node + lw $t0, 4($t0) + # Variable Node + sw $t0, 16($fp) + # Call Node + lw $t0, 8($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 16($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 24($fp) + # Call Node + lw $t0, 24($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 20($fp) + # String Node + la $t0, data_16 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 28($fp) + # Call Node + lw $t0, 20($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 28($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 20($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 36($fp) + # Call Node + lw $t0, 36($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 32($fp) + # String Node + la $t0, data_17 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 40($fp) + # Call Node + lw $t0, 76($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 40($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 76($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 48($fp) + # Call Node + lw $t0, 48($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 44($fp) + # Variable Node + lw $t0, 76($fp) + # Variable Node + lw $t0, 8($t0) + # Variable Node + sw $t0, 52($fp) + # Call Node + lw $t0, 44($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 52($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 44($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 60($fp) + # Call Node + lw $t0, 60($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 56($fp) + # String Node + la $t0, data_18 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 64($fp) + # Call Node + lw $t0, 56($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 64($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 56($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 72($fp) + # Call Node + lw $t0, 72($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 68($fp) + # Func Declaration Node + lw $v0, 76($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 80 + # Program Node + jr $ra + # Init per_title at Article + +__init_per_title_at_Article: + # Init per_title at Article + addi $sp, $sp, -4 + # Init per_title at Article + move $t0, $sp + # Init per_title at Article + addi $sp, $sp, -8 + # Init per_title at Article + sw $ra, 0($sp) + # Init per_title at Article + sw $fp, 4($sp) + # Init per_title at Article + move $fp, $t0 + # String Node + la $t0, data_19 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 12($t0) + # Init per_title at Article + lw $ra, 0($sp) + # Init per_title at Article + lw $fp, 4($sp) + # Init per_title at Article + addi $sp, $sp, 8 + # Init per_title at Article + addi $sp, $sp, 8 + # Init per_title at Article + jr $ra + # Program Node + +function_initArticle_at_Article: + # Program Node + addi $sp, $sp, -12 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 24($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 20($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 16($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 24($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 8($fp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 52($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 4($fp) + # Assign Node + lw $t0, 24($fp) + # Assign Node + lw $t1, 12($fp) + # Assign Node + sw $t1, 12($t0) + # Func Declaration Node + lw $v0, 24($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 28 + # Program Node + jr $ra + # Program Node + +function_print_at_Article: + # Program Node + addi $sp, $sp, -44 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 44($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + jal function_print_at_Book + # Call Node + sw $v0, 4($fp) + # String Node + la $t0, data_20 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 8($fp) + # Call Node + lw $t0, 44($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 8($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 44($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 16($fp) + # Call Node + lw $t0, 16($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 12($fp) + # Variable Node + lw $t0, 44($fp) + # Variable Node + lw $t0, 12($t0) + # Variable Node + sw $t0, 20($fp) + # Call Node + lw $t0, 12($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 20($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 12($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 28($fp) + # Call Node + lw $t0, 28($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 24($fp) + # String Node + la $t0, data_21 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 32($fp) + # Call Node + lw $t0, 24($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 32($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 24($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 40($fp) + # Call Node + lw $t0, 40($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 36($fp) + # Func Declaration Node + lw $v0, 44($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 48 + # Program Node + jr $ra + # Init xcar at Cons + +__init_xcar_at_Cons: + # Init xcar at Cons + addi $sp, $sp, -4 + # Init xcar at Cons + move $t0, $sp + # Init xcar at Cons + addi $sp, $sp, -8 + # Init xcar at Cons + sw $ra, 0($sp) + # Init xcar at Cons + sw $fp, 4($sp) + # Init xcar at Cons + move $fp, $t0 + # Instantiate Node + sw $zero, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 4($t0) + # Init xcar at Cons + lw $ra, 0($sp) + # Init xcar at Cons + lw $fp, 4($sp) + # Init xcar at Cons + addi $sp, $sp, 8 + # Init xcar at Cons + addi $sp, $sp, 8 + # Init xcar at Cons + jr $ra + # Init xcdr at Cons + +__init_xcdr_at_Cons: + # Init xcdr at Cons + addi $sp, $sp, -4 + # Init xcdr at Cons + move $t0, $sp + # Init xcdr at Cons + addi $sp, $sp, -8 + # Init xcdr at Cons + sw $ra, 0($sp) + # Init xcdr at Cons + sw $fp, 4($sp) + # Init xcdr at Cons + move $fp, $t0 + # Instantiate Node + sw $zero, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 8($t0) + # Init xcdr at Cons + lw $ra, 0($sp) + # Init xcdr at Cons + lw $fp, 4($sp) + # Init xcdr at Cons + addi $sp, $sp, 8 + # Init xcdr at Cons + addi $sp, $sp, 8 + # Init xcdr at Cons + jr $ra + # Program Node + +function_isNil_at_Cons: + # Program Node + addi $sp, $sp, 0 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Func Declaration Node + li $v0, 0 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 4 + # Program Node + jr $ra + # Program Node + +function_init_at_Cons: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Assign Node + lw $t0, 12($fp) + # Assign Node + lw $t1, 8($fp) + # Assign Node + sw $t1, 4($t0) + # Assign Node + lw $t0, 12($fp) + # Assign Node + lw $t1, 4($fp) + # Assign Node + sw $t1, 8($t0) + # Func Declaration Node + lw $v0, 12($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 16 + # Program Node + jr $ra + # Program Node + +function_car_at_Cons: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Variable Node + lw $t0, 4($fp) + # Variable Node + lw $t0, 4($t0) + # Variable Node + sw $t0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_cdr_at_Cons: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Variable Node + lw $t0, 4($fp) + # Variable Node + lw $t0, 8($t0) + # Variable Node + sw $t0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_print_list_at_Cons: + # Program Node + addi $sp, $sp, -112 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Variable Node + lw $t0, 112($fp) + # Variable Node + lw $t0, 4($t0) + # Variable Node + sw $t0, 4($fp) + # Call Node + lw $t0, 4($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 4($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 12($fp) + # Call Node + lw $t0, 12($fp) + # Call Node + lw $t0, 56($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 8($fp) + # Case Node void isVoid + sw $zero, 24($fp) + # Case Node equal isVoid value isVoid + lw $t0, 8($fp) + # Case Node equal isVoid value isVoid + lw $t1, 24($fp) + # Case Node equal isVoid value isVoid + seq $t2, $t0, $t1 + # Case Node equal isVoid value isVoid + sw $t2, 24($fp) + # Case Node gotoif isVoid abort_label + lw $t0, 24($fp) + # Case Node gotoif isVoid abort_label + bne $t0, $zero, print_list_at_Cons_label_0 + # Case Node typeof value + lw $t0, 8($fp) + # Case Node typeof value + lw $t0, 0($t0) + # Case Node typeof value + sw $t0, 20($fp) + # Case Node array declaration + li $a0, 8 + # Case Node array declaration + li $v0, 9 + # Case Node array declaration + syscall + # Case Node array declaration + sw $v0, 28($fp) + # Case Node array setindex 0 + li $t2, 0 + # Case Node array setindex 0 + la $t3, Book + # Case Node array setindex 0 + lw $t1, 28($fp) + # Case Node array setindex 0 + add $t1, $t1, $t2 + # Case Node array setindex 0 + sw $t3, 0($t1) + # Case Node array setindex 1 + li $t2, 4 + # Case Node array setindex 1 + la $t3, Article + # Case Node array setindex 1 + lw $t1, 28($fp) + # Case Node array setindex 1 + add $t1, $t1, $t2 + # Case Node array setindex 1 + sw $t3, 0($t1) + # Case Node assign index -1 + li $t0, -1 + # Case Node assign index -1 + sw $t0, 32($fp) + # Case Node assign minim -2 + li $t0, -2 + # Case Node assign minim -2 + sw $t0, 40($fp) + # Case Node start label + print_list_at_Cons_label_1: + # Case Node plus index 1 + lw $t0, 32($fp) + # Case Node plus index 1 + li $t1, 1 + # Case Node plus index 1 + add $t2, $t0, $t1 + # Case Node plus index 1 + sw $t2, 32($fp) + # Case Node equal stop_for index checks + lw $t0, 32($fp) + # Case Node equal stop_for index checks + li $t1, 2 + # Case Node equal stop_for index checks + seq $t2, $t0, $t1 + # Case Node equal stop_for index checks + sw $t2, 52($fp) + # Case Node gotoif stop_for end_label + lw $t0, 52($fp) + # Case Node gotoif stop_for end_label + bne $t0, $zero, print_list_at_Cons_label_3 + # Case Node get_index array_types index + lw $t0, 32($fp) + # Case Node get_index array_types index + li $t2, 4 + # Case Node get_index array_types index + mul $t2, $t2, $t0 + # Case Node get_index array_types index + lw $t1, 28($fp) + # Case Node get_index array_types index + add $t1, $t1, $t2 + # Case Node get_index array_types index + lw $t2, 0($t1) + # Case Node get_index array_types index + sw $t2, 48($fp) + # Case Node arg type_value + lw $t0, 20($fp) + # Case Node arg type_value + addi $sp, $sp, -4 + # Case Node arg type_value + sw $t0, 0($sp) + # Case Node arg current_type + lw $t0, 48($fp) + # Case Node arg current_type + addi $sp, $sp, -4 + # Case Node arg current_type + sw $t0, 0($sp) + # Case Node static_call type_distance + jal type_distance + # Case Node static_call type_distance + sw $v0, 44($fp) + # Case Node equal not_valid_distance distance -1 + lw $t0, 44($fp) + # Case Node equal not_valid_distance distance -1 + li $t1, -1 + # Case Node equal not_valid_distance distance -1 + seq $t2, $t0, $t1 + # Case Node equal not_valid_distance distance -1 + sw $t2, 56($fp) + # Case Node gotoif not_valid_distance start_label + lw $t0, 56($fp) + # Case Node gotoif not_valid_distance start_label + bne $t0, $zero, print_list_at_Cons_label_1 + # Case Node equal minim_cond minim -2 + lw $t0, 40($fp) + # Case Node equal minim_cond minim -2 + li $t1, -2 + # Case Node equal minim_cond minim -2 + seq $t2, $t0, $t1 + # Case Node equal minim_cond minim -2 + sw $t2, 60($fp) + # Case Node gotoif minim_cond minim_label + lw $t0, 60($fp) + # Case Node gotoif minim_cond minim_label + bne $t0, $zero, print_list_at_Cons_label_2 + # Case Node greater minim_cond minim distance + lw $t0, 40($fp) + # Case Node greater minim_cond minim distance + lw $t1, 44($fp) + # Case Node greater minim_cond minim distance + sgt $t2, $t0, $t1 + # Case Node greater minim_cond minim distance + sw $t2, 60($fp) + # Case Node gotoif minim_cond minim_label + lw $t0, 60($fp) + # Case Node gotoif minim_cond minim_label + bne $t0, $zero, print_list_at_Cons_label_2 + # Case Node goto start_label + j print_list_at_Cons_label_1 + # Case Node minim label + print_list_at_Cons_label_2: + # Case Node assign minim distance + lw $t0, 44($fp) + # Case Node assign minim distance + sw $t0, 40($fp) + # Case Node assign minim_index index + lw $t0, 32($fp) + # Case Node assign minim_index index + sw $t0, 36($fp) + # Case Node goto start_label + j print_list_at_Cons_label_1 + # Case Node end label + print_list_at_Cons_label_3: + # Case Node equal minim_cond minim -2 + lw $t0, 40($fp) + # Case Node equal minim_cond minim -2 + li $t1, -2 + # Case Node equal minim_cond minim -2 + seq $t2, $t0, $t1 + # Case Node equal minim_cond minim -2 + sw $t2, 60($fp) + # Case Node gotoif minim_cond abort_label + lw $t0, 60($fp) + # Case Node gotoif minim_cond abort_label + bne $t0, $zero, print_list_at_Cons_label_0 + # Case Node get_index array_types minim_index + lw $t0, 36($fp) + # Case Node get_index array_types minim_index + li $t2, 4 + # Case Node get_index array_types minim_index + mul $t2, $t2, $t0 + # Case Node get_index array_types minim_index + lw $t1, 28($fp) + # Case Node get_index array_types minim_index + add $t1, $t1, $t2 + # Case Node get_index array_types minim_index + lw $t2, 0($t1) + # Case Node get_index array_types minim_index + sw $t2, 48($fp) + # Case Node equal not_equal_types param.type.name current_type + la $t0, Book + # Case Node equal not_equal_types param.type.name current_type + lw $t1, 48($fp) + # Case Node equal not_equal_types param.type.name current_type + seq $t2, $t0, $t1 + # Case Node equal not_equal_types param.type.name current_type + sw $t2, 64($fp) + # Case Node not not_equal_types not_equal_types + lw $t0, 64($fp) + # Case Node not not_equal_types not_equal_types + seq $t0, $t0, $zero + # Case Node not not_equal_types not_equal_types + sw $t0, 64($fp) + # Case Node gotoif not_equal_types lbl.label + lw $t0, 64($fp) + # Case Node gotoif not_equal_types lbl.label + bne $t0, $zero, print_list_at_Cons_label_5 + # Check Node + lw $t0, 8($fp) + # Check Node + sw $t0, 68($fp) + # String Node + la $t0, data_22 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 72($fp) + # Call Node + lw $t0, 112($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 72($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 112($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 80($fp) + # Call Node + lw $t0, 80($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 76($fp) + # Case Node assign final_result result + lw $t0, 76($fp) + # Case Node assign final_result result + sw $t0, 16($fp) + # Case Node goto final_label + j print_list_at_Cons_label_4 + # Case Node end_label + print_list_at_Cons_label_5: + # Case Node equal not_equal_types param.type.name current_type + la $t0, Article + # Case Node equal not_equal_types param.type.name current_type + lw $t1, 48($fp) + # Case Node equal not_equal_types param.type.name current_type + seq $t2, $t0, $t1 + # Case Node equal not_equal_types param.type.name current_type + sw $t2, 64($fp) + # Case Node not not_equal_types not_equal_types + lw $t0, 64($fp) + # Case Node not not_equal_types not_equal_types + seq $t0, $t0, $zero + # Case Node not not_equal_types not_equal_types + sw $t0, 64($fp) + # Case Node gotoif not_equal_types lbl.label + lw $t0, 64($fp) + # Case Node gotoif not_equal_types lbl.label + bne $t0, $zero, print_list_at_Cons_label_6 + # Check Node + lw $t0, 8($fp) + # Check Node + sw $t0, 84($fp) + # String Node + la $t0, data_23 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 88($fp) + # Call Node + lw $t0, 112($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 88($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 112($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 96($fp) + # Call Node + lw $t0, 96($fp) + # Call Node + lw $t0, 28($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 92($fp) + # Case Node assign final_result result + lw $t0, 92($fp) + # Case Node assign final_result result + sw $t0, 16($fp) + # Case Node goto final_label + j print_list_at_Cons_label_4 + # Case Node end_label + print_list_at_Cons_label_6: + # Case Node abort label + print_list_at_Cons_label_0: + # Case Node abort + addi $v0, $zero, 10 + # Case Node abort + syscall + # Case Node final_label + print_list_at_Cons_label_4: + # Variable Node + lw $t0, 112($fp) + # Variable Node + lw $t0, 8($t0) + # Variable Node + sw $t0, 100($fp) + # Call Node + lw $t0, 100($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 100($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 108($fp) + # Call Node + lw $t0, 108($fp) + # Call Node + lw $t0, 60($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 104($fp) + # Func Declaration Node + lw $v0, 104($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 116 + # Program Node + jr $ra + # Program Node + +function_out_string_at_IO: + # Program Node + addi $sp, $sp, 0 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # IO Out String Node + lw $a0, 0($fp) + # Getting the String address + lw $a0, 4($a0) + # 4 System call code for print string + addi $v0, $zero, 4 + syscall + # Func Declaration Node + lw $v0, 4($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_out_int_at_IO: + # Program Node + addi $sp, $sp, 0 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # IO Out Int Node + lw $a0, 0($fp) + # IO Out Int Node + addi $v0, $zero, 1 + # IO Out Int Node + syscall + # Func Declaration Node + lw $v0, 4($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_in_string_at_IO: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # a1 = Allocated length Save the length in a1 + li $a1, 1024 + # Allocates 1024 bytes and return the address un v0 + move $a0, $a1 + # Allocates 1024 bytes and return the address un v0 + li $v0, 9 + # Allocates 1024 bytes and return the address un v0 + syscall + # a0 = v0 Save the address in a0 + move $a0, $v0 + # 8 System call code for read string + addi $v0, $zero, 8 + # Fills the address in a0 with the string + syscall + # a1 = a0 Save the address in a1 + move $a1, $a0 + # Type address into $a0 + la $t0, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t0, 0($v0) + # Store String Address + sw $a1, 4($v0) + # a0 = v0 Get the string instance address + move $a0, $v0 + addi $sp, $sp, -4 + sw $ra, 0($sp) + # Remove last char + jal __remove_last_char + lw $ra, 0($sp) + addi $sp, $sp, 4 + # Save the address in the final destination + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_in_int_at_IO: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # IO In Int Node + addi $v0, $zero, 5 + # IO In Int Node + syscall + # IO In Int Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_isNil_at_BookList: + # Program Node + addi $sp, $sp, -12 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 12($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 12($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 8($fp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 16($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 4($fp) + # Func Declaration Node + li $v0, 1 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 16 + # Program Node + jr $ra + # Program Node + +function_cons_at_BookList: + # Program Node + addi $sp, $sp, -16 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 +# Allocate + # Instantiate Node + la $a0, Cons + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 4($fp) + # Instantiate Node + lw $t0, 4($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Cons_type + # Instantiate Node + sw $v0, 4($fp) + # Var Declaration Node + lw $t0, 4($fp) + # Var Declaration Node + sw $t0, 0($fp) + # Call Node + lw $t0, 0($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 16($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 20($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 0($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 12($fp) + # Call Node + lw $t0, 12($fp) + # Call Node + lw $t0, 72($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 8($fp) + # Func Declaration Node + lw $v0, 8($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 24 + # Program Node + jr $ra + # Program Node + +function_car_at_BookList: + # Program Node + addi $sp, $sp, -16 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 16($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 16($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 8($fp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 16($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 4($fp) +# Allocate + # Instantiate Node + la $a0, Book + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 12($fp) + # Instantiate Node + lw $t0, 12($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Book_type + # Instantiate Node + sw $v0, 12($fp) + # Func Declaration Node + lw $v0, 12($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 20 + # Program Node + jr $ra + # Program Node + +function_cdr_at_BookList: + # Program Node + addi $sp, $sp, -16 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 16($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 16($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 8($fp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 16($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 4($fp) +# Allocate + # Instantiate Node + la $a0, BookList + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 12($fp) + # Instantiate Node + lw $t0, 12($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_BookList_type + # Instantiate Node + sw $v0, 12($fp) + # Func Declaration Node + lw $v0, 12($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 20 + # Program Node + jr $ra + # Program Node + +function_print_list_at_BookList: + # Program Node + addi $sp, $sp, -8 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Call Node + lw $t0, 8($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 8($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 4($fp) + # Call Node + lw $t0, 4($fp) + # Call Node + lw $t0, 16($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 12 + # Program Node + jr $ra + # Program Node + +function_isNil_at_Nil: + # Program Node + addi $sp, $sp, 0 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Func Declaration Node + li $v0, 1 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 4 + # Program Node + jr $ra + # Program Node + +function_print_list_at_Nil: + # Program Node + addi $sp, $sp, 0 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Func Declaration Node + li $v0, 1 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 4 + # Program Node + jr $ra + # Program Node + +function_abort_at_Object: + # Program Node + addi $sp, $sp, -24 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Assign object type + lw $t0, 24($fp) + # Assign object type + lw $t0, 0($t0) + # Assign object type + sw $t0, 0($fp) + # Get type name + lw $a0, 0($fp) + # Get type name + jal __type_name + # Get type name + sw $v0, 4($fp) + la $t0, data_11 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 8($fp) + la $t0, data_12 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 12($fp) + # Final abort message + lw $a0, 8($fp) + # Final abort message + lw $a1, 4($fp) + # Final abort message + jal __concat + # Final abort message + sw $v0, 16($fp) + # Final Final abort message + lw $a0, 16($fp) + # Final Final abort message + lw $a1, 12($fp) + # Final Final abort message + jal __concat + # Final Final abort message + sw $v0, 20($fp) + # Print abort info + lw $a0, 20($fp) + # Getting the String address + lw $a0, 4($a0) + # 4 System call code for print string + addi $v0, $zero, 4 + syscall + # Abort Object + addi $v0, $zero, 10 + # Abort Object + syscall + # Func Declaration Node + li $v0, 0 + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 28 + # Program Node + jr $ra + # Program Node + +function_type_name_at_Object: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Object Type Name Node + lw $t0, 4($fp) + # Object Type Name Node + lw $t0, 0($t0) + # Object Type Name Node + sw $t0, 0($fp) + # Object Type Name Node + lw $a0, 0($fp) + # Object Type Name Node + jal __type_name + # Object Type Name Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Program Node + +function_copy_at_Object: + # Program Node + addi $sp, $sp, -4 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 + # Object Copy Node + lw $a0, 4($fp) + # Object Copy Node + jal __copy + # Object Copy Node + sw $v0, 0($fp) + # Func Declaration Node + lw $v0, 0($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 8 + # Program Node + jr $ra + # Init books at Main + +__init_books_at_Main: + # Init books at Main + addi $sp, $sp, -4 + # Init books at Main + move $t0, $sp + # Init books at Main + addi $sp, $sp, -8 + # Init books at Main + sw $ra, 0($sp) + # Init books at Main + sw $fp, 4($sp) + # Init books at Main + move $fp, $t0 + # Instantiate Node + sw $zero, 0($fp) + # Attr Declaration Node + lw $t0, 4($fp) + # Attr Declaration Node + lw $t1, 0($fp) + # Attr Declaration Node + sw $t1, 4($t0) + # Init books at Main + lw $ra, 0($sp) + # Init books at Main + lw $fp, 4($sp) + # Init books at Main + addi $sp, $sp, 8 + # Init books at Main + addi $sp, $sp, 8 + # Init books at Main + jr $ra + # Program Node + +function_main_at_Main: + # Program Node + addi $sp, $sp, -88 + # Program Node + move $t0, $sp + # Program Node + addi $sp, $sp, -8 + # Program Node + sw $ra, 0($sp) + # Program Node + sw $fp, 4($sp) + # Program Node + move $fp, $t0 +# Allocate + # Instantiate Node + la $a0, Book + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 4($fp) + # Instantiate Node + lw $t0, 4($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Book_type + # Instantiate Node + sw $v0, 4($fp) + # String Node + la $t0, data_24 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 8($fp) + # String Node + la $t0, data_25 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 12($fp) + # Call Node + lw $t0, 4($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 8($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 12($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 4($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 20($fp) + # Call Node + lw $t0, 20($fp) + # Call Node + lw $t0, 52($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 16($fp) + # Var Declaration Node + lw $t0, 16($fp) + # Var Declaration Node + sw $t0, 0($fp) +# Allocate + # Instantiate Node + la $a0, Article + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 28($fp) + # Instantiate Node + lw $t0, 28($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Article_type + # Instantiate Node + sw $v0, 28($fp) + # String Node + la $t0, data_26 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 32($fp) + # String Node + la $t0, data_27 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 36($fp) + # String Node + la $t0, data_28 + # Type address into $a0 + la $t1, String + # If String the is type and address + li $a0, 8 + li $v0, 9 + syscall + # Store String Type + sw $t1, 0($v0) + # Store String Address + sw $t0, 4($v0) + # Save string instance + sw $v0, 40($fp) + # Call Node + lw $t0, 28($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 32($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 36($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 40($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 28($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 48($fp) + # Call Node + lw $t0, 48($fp) + # Call Node + lw $t0, 64($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 44($fp) + # Var Declaration Node + lw $t0, 44($fp) + # Var Declaration Node + sw $t0, 24($fp) +# Allocate + # Instantiate Node + la $a0, Nil + # Instantiate Node + lw $a0, 4($a0) + li $v0, 9 + syscall + sw $v0, 56($fp) + # Instantiate Node + lw $t0, 56($fp) + # Instantiate Node + addi $sp, $sp, -4 + # Instantiate Node + sw $t0, 0($sp) + # Instantiate Node + jal __init_Nil_type + # Instantiate Node + sw $v0, 56($fp) + # Call Node + lw $t0, 56($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 0($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 56($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 64($fp) + # Call Node + lw $t0, 64($fp) + # Call Node + lw $t0, 48($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 60($fp) + # Call Node + lw $t0, 60($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 24($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 60($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 72($fp) + # Call Node + lw $t0, 72($fp) + # Call Node + lw $t0, 48($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 68($fp) + # Assign Node + lw $t0, 88($fp) + # Assign Node + lw $t1, 68($fp) + # Assign Node + sw $t1, 4($t0) + # Variable Node + lw $t0, 88($fp) + # Variable Node + lw $t0, 4($t0) + # Variable Node + sw $t0, 76($fp) + # Call Node + lw $t0, 76($fp) + # Call Node + addi $sp, $sp, -4 + # Call Node + sw $t0, 0($sp) + # Call Node + lw $t0, 76($fp) + # Call Node + lw $t0, 0($t0) + # Call Node + sw $t0, 84($fp) + # Call Node + lw $t0, 84($fp) + # Call Node + lw $t0, 60($t0) + # Call Node + jal __get_ra + # Call Node + move $ra, $v0 + # Call Node + jr $t0 + # Call Node + sw $v0, 80($fp) + # Func Declaration Node + lw $v0, 80($fp) + # Program Node + lw $ra, 0($sp) + # Program Node + lw $fp, 4($sp) + # Program Node + addi $sp, $sp, 8 + # Program Node + addi $sp, $sp, 92 + # Program Node + jr $ra + # Class Declaration Node + +__init_Object_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, Object + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_String_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, String + sw $t1, 0($t0) + la $t1, __empty_string + sw $t1, 4($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Bool_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, Bool + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Int_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, Int + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_IO_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, IO + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Book_type: + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 8($fp) + la $t1, Book + sw $t1, 0($t0) + # arg node + lw $t0, 8($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_title_at_Book + # Initialize arg function + sw $v0, 0($fp) + # arg node + lw $t0, 8($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_author_at_Book + # Initialize arg function + sw $v0, 4($fp) + # return node + lw $v0, 8($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 12 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Article_type: + # Class Declaration Node + addi $sp, $sp, -12 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 12($fp) + la $t1, Article + sw $t1, 0($t0) + # arg node + lw $t0, 12($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_title_at_Book + # Initialize arg function + sw $v0, 0($fp) + # arg node + lw $t0, 12($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_author_at_Book + # Initialize arg function + sw $v0, 4($fp) + # arg node + lw $t0, 12($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_per_title_at_Article + # Initialize arg function + sw $v0, 8($fp) + # return node + lw $v0, 12($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 16 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_BookList_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, BookList + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Cons_type: + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 8($fp) + la $t1, Cons + sw $t1, 0($t0) + # arg node + lw $t0, 8($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_xcar_at_Cons + # Initialize arg function + sw $v0, 0($fp) + # arg node + lw $t0, 8($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_xcdr_at_Cons + # Initialize arg function + sw $v0, 4($fp) + # return node + lw $v0, 8($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 12 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Nil_type: + # Class Declaration Node + addi $sp, $sp, 0 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 0($fp) + la $t1, Nil + sw $t1, 0($t0) + # return node + lw $v0, 0($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 4 + # Class Declaration Node + jr $ra + # Class Declaration Node + +__init_Main_type: + # Class Declaration Node + addi $sp, $sp, -4 + # Class Declaration Node + move $t0, $sp + # Class Declaration Node + addi $sp, $sp, -8 + # Class Declaration Node + sw $ra, 0($sp) + # Class Declaration Node + sw $fp, 4($sp) + # Class Declaration Node + move $fp, $t0 + lw $t0, 4($fp) + la $t1, Main + sw $t1, 0($t0) + # arg node + lw $t0, 4($fp) + # arg node + addi $sp, $sp, -4 + # arg node + sw $t0, 0($sp) + # Initialize arg function + jal __init_books_at_Main + # Initialize arg function + sw $v0, 0($fp) + # return node + lw $v0, 4($fp) + # Class Declaration Node + lw $ra, 0($sp) + # Class Declaration Node + lw $fp, 4($sp) + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + addi $sp, $sp, 8 + # Class Declaration Node + jr $ra +.data +data_0: .asciiz "Object" +data_1: .asciiz "String" +data_2: .asciiz "Bool" +data_3: .asciiz "Int" +data_4: .asciiz "IO" +data_5: .asciiz "Book" +data_6: .asciiz "Article" +data_7: .asciiz "BookList" +data_8: .asciiz "Cons" +data_9: .asciiz "Nil" +data_10: .asciiz "Main" +data_11: .asciiz "Abort called from class " +data_12: .asciiz "\n" +data_13: .asciiz "" +data_14: .asciiz "" +data_15: .asciiz "title: " +data_16: .asciiz "\n" +data_17: .asciiz "author: " +data_18: .asciiz "\n" +data_19: .asciiz "" +data_20: .asciiz "periodical: " +data_21: .asciiz "\n" +data_22: .asciiz "- dynamic type was Book -\n" +data_23: .asciiz "- dynamic type was Article -\n" +data_24: .asciiz "Compilers, Principles, Techniques, and Tools" +data_25: .asciiz "Aho, Sethi, and Ullman" +data_26: .asciiz "The Top 100 CD_ROMs" +data_27: .asciiz "Ulanoff" +data_28: .asciiz "PC Magazine" +__empty_string: .asciiz "" +# Program Node +Object: .word 0, 4, data_0, __init_Object_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object +# Program Node +String: .word Object, 4, data_1, __init_String_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_length_at_String, function_concat_at_String, function_substr_at_String +# Program Node +Bool: .word Object, 4, data_2, __init_Bool_type, function_abort_at_Bool, function_type_name_at_Bool, function_copy_at_Object +# Program Node +Int: .word Object, 4, data_3, __init_Int_type, function_abort_at_Int, function_type_name_at_Int, function_copy_at_Object +# Program Node +IO: .word Object, 4, data_4, __init_IO_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO +# Program Node +Book: .word IO, 12, data_5, __init_Book_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO, __init_title_at_Book, __init_author_at_Book, function_initBook_at_Book, function_print_at_Book +# Program Node +Article: .word Book, 16, data_6, __init_Article_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO, __init_title_at_Book, __init_author_at_Book, function_initBook_at_Book, function_print_at_Article, __init_per_title_at_Article, function_initArticle_at_Article +# Program Node +BookList: .word IO, 4, data_7, __init_BookList_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO, function_isNil_at_BookList, function_cons_at_BookList, function_car_at_BookList, function_cdr_at_BookList, function_print_list_at_BookList +# Program Node +Cons: .word BookList, 12, data_8, __init_Cons_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO, function_isNil_at_Cons, function_cons_at_BookList, function_car_at_Cons, function_cdr_at_Cons, function_print_list_at_Cons, __init_xcar_at_Cons, __init_xcdr_at_Cons, function_init_at_Cons +# Program Node +Nil: .word BookList, 4, data_9, __init_Nil_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, function_out_string_at_IO, function_out_int_at_IO, function_in_string_at_IO, function_in_int_at_IO, function_isNil_at_Nil, function_cons_at_BookList, function_car_at_BookList, function_cdr_at_BookList, function_print_list_at_Nil +# Program Node +Main: .word Object, 8, data_10, __init_Main_type, function_abort_at_Object, function_type_name_at_Object, function_copy_at_Object, __init_books_at_Main, function_main_at_Main \ No newline at end of file diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 000000000..4a3587927 --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,2 @@ +*.cil +*.mips \ No newline at end of file diff --git a/tests/codegen/arith.cl b/tests/codegen/arith.cl index af5951cf7..0d9f5dd33 100755 --- a/tests/codegen/arith.cl +++ b/tests/codegen/arith.cl @@ -1,430 +1,430 @@ -(* - * A contribution from Anne Sheets (sheets@cory) - * - * Tests the arithmetic operations and various other things - *) - -class A { - - var : Int <- 0; - - value() : Int { var }; - - set_var(num : Int) : A{ - { - var <- num; - self; - } - }; - - method1(num : Int) : A { -- same - self - }; - - method2(num1 : Int, num2 : Int) : A { -- plus - (let x : Int in - { - x <- num1 + num2; - (new B).set_var(x); - } - ) - }; - - method3(num : Int) : A { -- negate - (let x : Int in - { - x <- ~num; - (new C).set_var(x); - } - ) - }; - - method4(num1 : Int, num2 : Int) : A { -- diff - if num2 < num1 then - (let x : Int in - { - x <- num1 - num2; - (new D).set_var(x); - } - ) - else - (let x : Int in - { - x <- num2 - num1; - (new D).set_var(x); - } - ) - fi - }; - - method5(num : Int) : A { -- factorial - (let x : Int <- 1 in - { - (let y : Int <- 1 in - while y <= num loop - { - x <- x * y; - y <- y + 1; - } - pool - ); - (new E).set_var(x); - } - ) - }; - -}; - -class B inherits A { -- B is a number squared - - method5(num : Int) : A { -- square - (let x : Int in - { - x <- num * num; - (new E).set_var(x); - } - ) - }; - -}; - -class C inherits B { - - method6(num : Int) : A { -- negate - (let x : Int in - { - x <- ~num; - (new A).set_var(x); - } - ) - }; - - method5(num : Int) : A { -- cube - (let x : Int in - { - x <- num * num * num; - (new E).set_var(x); - } - ) - }; - -}; - -class D inherits B { - - method7(num : Int) : Bool { -- divisible by 3 - (let x : Int <- num in - if x < 0 then method7(~x) else - if 0 = x then true else - if 1 = x then false else - if 2 = x then false else - method7(x - 3) - fi fi fi fi - ) - }; - -}; - -class E inherits D { - - method6(num : Int) : A { -- division - (let x : Int in - { - x <- num / 8; - (new A).set_var(x); - } - ) - }; - -}; - -(* The following code is from atoi.cl in ~cs164/examples *) - -(* - The class A2I provides integer-to-string and string-to-integer -conversion routines. To use these routines, either inherit them -in the class where needed, have a dummy variable bound to -something of type A2I, or simpl write (new A2I).method(argument). -*) - - -(* - c2i Converts a 1-character string to an integer. Aborts - if the string is not "0" through "9" -*) -class A2I { - - c2i(char : String) : Int { - if char = "0" then 0 else - if char = "1" then 1 else - if char = "2" then 2 else - if char = "3" then 3 else - if char = "4" then 4 else - if char = "5" then 5 else - if char = "6" then 6 else - if char = "7" then 7 else - if char = "8" then 8 else - if char = "9" then 9 else - { abort(); 0; } (* the 0 is needed to satisfy the - typchecker *) - fi fi fi fi fi fi fi fi fi fi - }; - -(* - i2c is the inverse of c2i. -*) - i2c(i : Int) : String { - if i = 0 then "0" else - if i = 1 then "1" else - if i = 2 then "2" else - if i = 3 then "3" else - if i = 4 then "4" else - if i = 5 then "5" else - if i = 6 then "6" else - if i = 7 then "7" else - if i = 8 then "8" else - if i = 9 then "9" else - { abort(); ""; } -- the "" is needed to satisfy the typchecker - fi fi fi fi fi fi fi fi fi fi - }; - -(* - a2i converts an ASCII string into an integer. The empty string -is converted to 0. Signed and unsigned strings are handled. The -method aborts if the string does not represent an integer. Very -long strings of digits produce strange answers because of arithmetic -overflow. - -*) - a2i(s : String) : Int { - if s.length() = 0 then 0 else - if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else - if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else - a2i_aux(s) - fi fi fi - }; - -(* a2i_aux converts the usigned portion of the string. As a - programming example, this method is written iteratively. *) - - - a2i_aux(s : String) : Int { - (let int : Int <- 0 in - { - (let j : Int <- s.length() in - (let i : Int <- 0 in - while i < j loop - { - int <- int * 10 + c2i(s.substr(i,1)); - i <- i + 1; - } - pool - ) - ); - int; - } - ) - }; - -(* i2a converts an integer to a string. Positive and negative - numbers are handled correctly. *) - - i2a(i : Int) : String { - if i = 0 then "0" else - if 0 < i then i2a_aux(i) else - "-".concat(i2a_aux(i * ~1)) - fi fi - }; - -(* i2a_aux is an example using recursion. *) - - i2a_aux(i : Int) : String { - if i = 0 then "" else - (let next : Int <- i / 10 in - i2a_aux(next).concat(i2c(i - next * 10)) - ) - fi - }; - -}; - -class Main inherits IO { - - char : String; - avar : A; - a_var : A; - flag : Bool <- true; - - - menu() : String { - { - out_string("\n\tTo add a number to "); - print(avar); - out_string("...enter a:\n"); - out_string("\tTo negate "); - print(avar); - out_string("...enter b:\n"); - out_string("\tTo find the difference between "); - print(avar); - out_string("and another number...enter c:\n"); - out_string("\tTo find the factorial of "); - print(avar); - out_string("...enter d:\n"); - out_string("\tTo square "); - print(avar); - out_string("...enter e:\n"); - out_string("\tTo cube "); - print(avar); - out_string("...enter f:\n"); - out_string("\tTo find out if "); - print(avar); - out_string("is a multiple of 3...enter g:\n"); - out_string("\tTo divide "); - print(avar); - out_string("by 8...enter h:\n"); - out_string("\tTo get a new number...enter j:\n"); - out_string("\tTo quit...enter q:\n\n"); - in_string(); - } - }; - - prompt() : String { - { - out_string("\n"); - out_string("Please enter a number... "); - in_string(); - } - }; - - get_int() : Int { - { - (let z : A2I <- new A2I in - (let s : String <- prompt() in - z.a2i(s) - ) - ); - } - }; - - is_even(num : Int) : Bool { - (let x : Int <- num in - if x < 0 then is_even(~x) else - if 0 = x then true else - if 1 = x then false else - is_even(x - 2) - fi fi fi - ) - }; - - class_type(var : A) : IO { - case var of - a : A => out_string("Class type is now A\n"); - b : B => out_string("Class type is now B\n"); - c : C => out_string("Class type is now C\n"); - d : D => out_string("Class type is now D\n"); - e : E => out_string("Class type is now E\n"); - o : Object => out_string("Oooops\n"); - esac - }; - - print(var : A) : IO { - (let z : A2I <- new A2I in - { - out_string(z.i2a(var.value())); - out_string(" "); - } - ) - }; - - main() : Object { - { - avar <- (new A); - while flag loop - { - -- avar <- (new A).set_var(get_int()); - out_string("number "); - print(avar); - if is_even(avar.value()) then - out_string("is even!\n") - else - out_string("is odd!\n") - fi; - -- print(avar); -- prints out answer - class_type(avar); - char <- menu(); - if char = "a" then -- add - { - a_var <- (new A).set_var(get_int()); - avar <- (new B).method2(avar.value(), a_var.value()); - } else - if char = "b" then -- negate - case avar of - c : C => avar <- c.method6(c.value()); - a : A => avar <- a.method3(a.value()); - o : Object => { - out_string("Oooops\n"); - abort(); 0; - }; - esac else - if char = "c" then -- diff - { - a_var <- (new A).set_var(get_int()); - avar <- (new D).method4(avar.value(), a_var.value()); - } else - if char = "d" then avar <- (new C)@A.method5(avar.value()) else - -- factorial - if char = "e" then avar <- (new C)@B.method5(avar.value()) else - -- square - if char = "f" then avar <- (new C)@C.method5(avar.value()) else - -- cube - if char = "g" then -- multiple of 3? - if ((new D).method7(avar.value())) - then -- avar <- (new A).method1(avar.value()) - { - out_string("number "); - print(avar); - out_string("is divisible by 3.\n"); - } - else -- avar <- (new A).set_var(0) - { - out_string("number "); - print(avar); - out_string("is not divisible by 3.\n"); - } - fi else - if char = "h" then - (let x : A in - { - x <- (new E).method6(avar.value()); - (let r : Int <- (avar.value() - (x.value() * 8)) in - { - out_string("number "); - print(avar); - out_string("is equal to "); - print(x); - out_string("times 8 with a remainder of "); - (let a : A2I <- new A2I in - { - out_string(a.i2a(r)); - out_string("\n"); - } - ); -- end let a: - } - ); -- end let r: - avar <- x; - } - ) -- end let x: - else - if char = "j" then avar <- (new A) - else - if char = "q" then flag <- false - else - avar <- (new A).method1(avar.value()) -- divide/8 - fi fi fi fi fi fi fi fi fi fi; - } - pool; - } - }; - -}; - +(* + * A contribution from Anne Sheets (sheets@cory) + * + * Tests the arithmetic operations and various other things + *) + +class A { + + var : Int <- 0; + + value() : Int { var }; + + set_var(num : Int) : A{ + { + var <- num; + self; + } + }; + + method1(num : Int) : A { -- same + self + }; + + method2(num1 : Int, num2 : Int) : A { -- plus + (let x : Int in + { + x <- num1 + num2; + (new B).set_var(x); + } + ) + }; + + method3(num : Int) : A { -- negate + (let x : Int in + { + x <- ~num; + (new C).set_var(x); + } + ) + }; + + method4(num1 : Int, num2 : Int) : A { -- diff + if num2 < num1 then + (let x : Int in + { + x <- num1 - num2; + (new D).set_var(x); + } + ) + else + (let x : Int in + { + x <- num2 - num1; + (new D).set_var(x); + } + ) + fi + }; + + method5(num : Int) : A { -- factorial + (let x : Int <- 1 in + { + (let y : Int <- 1 in + while y <= num loop + { + x <- x * y; + y <- y + 1; + } + pool + ); + (new E).set_var(x); + } + ) + }; + +}; + +class B inherits A { -- B is a number squared + + method5(num : Int) : A { -- square + (let x : Int in + { + x <- num * num; + (new E).set_var(x); + } + ) + }; + +}; + +class C inherits B { + + method6(num : Int) : A { -- negate + (let x : Int in + { + x <- ~num; + (new A).set_var(x); + } + ) + }; + + method5(num : Int) : A { -- cube + (let x : Int in + { + x <- num * num * num; + (new E).set_var(x); + } + ) + }; + +}; + +class D inherits B { + + method7(num : Int) : Bool { -- divisible by 3 + (let x : Int <- num in + if x < 0 then method7(~x) else + if 0 = x then true else + if 1 = x then false else + if 2 = x then false else + method7(x - 3) + fi fi fi fi + ) + }; + +}; + +class E inherits D { + + method6(num : Int) : A { -- division + (let x : Int in + { + x <- num / 8; + (new A).set_var(x); + } + ) + }; + +}; + +(* The following code is from atoi.cl in ~cs164/examples *) + +(* + The class A2I provides integer-to-string and string-to-integer +conversion routines. To use these routines, either inherit them +in the class where needed, have a dummy variable bound to +something of type A2I, or simpl write (new A2I).method(argument). +*) + + +(* + c2i Converts a 1-character string to an integer. Aborts + if the string is not "0" through "9" +*) +class A2I { + + c2i(char : String) : Int { + if char = "0" then 0 else + if char = "1" then 1 else + if char = "2" then 2 else + if char = "3" then 3 else + if char = "4" then 4 else + if char = "5" then 5 else + if char = "6" then 6 else + if char = "7" then 7 else + if char = "8" then 8 else + if char = "9" then 9 else + { abort(); 0; } (* the 0 is needed to satisfy the + typchecker *) + fi fi fi fi fi fi fi fi fi fi + }; + +(* + i2c is the inverse of c2i. +*) + i2c(i : Int) : String { + if i = 0 then "0" else + if i = 1 then "1" else + if i = 2 then "2" else + if i = 3 then "3" else + if i = 4 then "4" else + if i = 5 then "5" else + if i = 6 then "6" else + if i = 7 then "7" else + if i = 8 then "8" else + if i = 9 then "9" else + { abort(); ""; } -- the "" is needed to satisfy the typchecker + fi fi fi fi fi fi fi fi fi fi + }; + +(* + a2i converts an ASCII string into an integer. The empty string +is converted to 0. Signed and unsigned strings are handled. The +method aborts if the string does not represent an integer. Very +long strings of digits produce strange answers because of arithmetic +overflow. + +*) + a2i(s : String) : Int { + if s.length() = 0 then 0 else + if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else + if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else + a2i_aux(s) + fi fi fi + }; + +(* a2i_aux converts the usigned portion of the string. As a + programming example, this method is written iteratively. *) + + + a2i_aux(s : String) : Int { + (let int : Int <- 0 in + { + (let j : Int <- s.length() in + (let i : Int <- 0 in + while i < j loop + { + int <- int * 10 + c2i(s.substr(i,1)); + i <- i + 1; + } + pool + ) + ); + int; + } + ) + }; + +(* i2a converts an integer to a string. Positive and negative + numbers are handled correctly. *) + + i2a(i : Int) : String { + if i = 0 then "0" else + if 0 < i then i2a_aux(i) else + "-".concat(i2a_aux(i * ~1)) + fi fi + }; + +(* i2a_aux is an example using recursion. *) + + i2a_aux(i : Int) : String { + if i = 0 then "" else + (let next : Int <- i / 10 in + i2a_aux(next).concat(i2c(i - next * 10)) + ) + fi + }; + +}; + +class Main inherits IO { + + char : String; + avar : A; + a_var : A; + flag : Bool <- true; + + + menu() : String { + { + out_string("\n\tTo add a number to "); + print(avar); + out_string("...enter a:\n"); + out_string("\tTo negate "); + print(avar); + out_string("...enter b:\n"); + out_string("\tTo find the difference between "); + print(avar); + out_string("and another number...enter c:\n"); + out_string("\tTo find the factorial of "); + print(avar); + out_string("...enter d:\n"); + out_string("\tTo square "); + print(avar); + out_string("...enter e:\n"); + out_string("\tTo cube "); + print(avar); + out_string("...enter f:\n"); + out_string("\tTo find out if "); + print(avar); + out_string("is a multiple of 3...enter g:\n"); + out_string("\tTo divide "); + print(avar); + out_string("by 8...enter h:\n"); + out_string("\tTo get a new number...enter j:\n"); + out_string("\tTo quit...enter q:\n\n"); + in_string(); + } + }; + + prompt() : String { + { + out_string("\n"); + out_string("Please enter a number... "); + in_string(); + } + }; + + get_int() : Int { + { + (let z : A2I <- new A2I in + (let s : String <- prompt() in + z.a2i(s) + ) + ); + } + }; + + is_even(num : Int) : Bool { + (let x : Int <- num in + if x < 0 then is_even(~x) else + if 0 = x then true else + if 1 = x then false else + is_even(x - 2) + fi fi fi + ) + }; + + class_type(var : A) : IO { + case var of + a : A => out_string("Class type is now A\n"); + b : B => out_string("Class type is now B\n"); + c : C => out_string("Class type is now C\n"); + d : D => out_string("Class type is now D\n"); + e : E => out_string("Class type is now E\n"); + o : Object => out_string("Oooops\n"); + esac + }; + + print(var : A) : IO { + (let z : A2I <- new A2I in + { + out_string(z.i2a(var.value())); + out_string(" "); + } + ) + }; + + main() : Object { + { + avar <- (new A); + while flag loop + { + -- avar <- (new A).set_var(get_int()); + out_string("number "); + print(avar); + if is_even(avar.value()) then + out_string("is even!\n") + else + out_string("is odd!\n") + fi; + -- print(avar); -- prints out answer + class_type(avar); + char <- menu(); + if char = "a" then -- add + { + a_var <- (new A).set_var(get_int()); + avar <- (new B).method2(avar.value(), a_var.value()); + } else + if char = "b" then -- negate + case avar of + c : C => avar <- c.method6(c.value()); + a : A => avar <- a.method3(a.value()); + o : Object => { + out_string("Oooops\n"); + abort(); 0; + }; + esac else + if char = "c" then -- diff + { + a_var <- (new A).set_var(get_int()); + avar <- (new D).method4(avar.value(), a_var.value()); + } else + if char = "d" then avar <- (new C)@A.method5(avar.value()) else + -- factorial + if char = "e" then avar <- (new C)@B.method5(avar.value()) else + -- square + if char = "f" then avar <- (new C)@C.method5(avar.value()) else + -- cube + if char = "g" then -- multiple of 3? + if ((new D).method7(avar.value())) + then -- avar <- (new A).method1(avar.value()) + { + out_string("number "); + print(avar); + out_string("is divisible by 3.\n"); + } + else -- avar <- (new A).set_var(0) + { + out_string("number "); + print(avar); + out_string("is not divisible by 3.\n"); + } + fi else + if char = "h" then + (let x : A in + { + x <- (new E).method6(avar.value()); + (let r : Int <- (avar.value() - (x.value() * 8)) in + { + out_string("number "); + print(avar); + out_string("is equal to "); + print(x); + out_string("times 8 with a remainder of "); + (let a : A2I <- new A2I in + { + out_string(a.i2a(r)); + out_string("\n"); + } + ); -- end let a: + } + ); -- end let r: + avar <- x; + } + ) -- end let x: + else + if char = "j" then avar <- (new A) + else + if char = "q" then flag <- false + else + avar <- (new A).method1(avar.value()) -- divide/8 + fi fi fi fi fi fi fi fi fi fi; + } + pool; + } + }; + +}; + diff --git a/tests/codegen/book_list.cl b/tests/codegen/book_list.cl index 025ea1695..d39f86bbe 100755 --- a/tests/codegen/book_list.cl +++ b/tests/codegen/book_list.cl @@ -1,132 +1,132 @@ --- example of static and dynamic type differing for a dispatch - -Class Book inherits IO { - title : String; - author : String; - - initBook(title_p : String, author_p : String) : Book { - { - title <- title_p; - author <- author_p; - self; - } - }; - - print() : Book { - { - out_string("title: ").out_string(title).out_string("\n"); - out_string("author: ").out_string(author).out_string("\n"); - self; - } - }; -}; - -Class Article inherits Book { - per_title : String; - - initArticle(title_p : String, author_p : String, - per_title_p : String) : Article { - { - initBook(title_p, author_p); - per_title <- per_title_p; - self; - } - }; - - print() : Book { - { - self@Book.print(); - out_string("periodical: ").out_string(per_title).out_string("\n"); - self; - } - }; -}; - -Class BookList inherits IO { - (* Since abort "returns" type Object, we have to add - an expression of type Bool here to satisfy the typechecker. - This code is unreachable, since abort() halts the program. - *) - isNil() : Bool { { abort(); true; } }; - - cons(hd : Book) : Cons { - (let new_cell : Cons <- new Cons in - new_cell.init(hd,self) - ) - }; - - (* Since abort "returns" type Object, we have to add - an expression of type Book here to satisfy the typechecker. - This code is unreachable, since abort() halts the program. - *) - car() : Book { { abort(); new Book; } }; - - (* Since abort "returns" type Object, we have to add - an expression of type BookList here to satisfy the typechecker. - This code is unreachable, since abort() halts the program. - *) - cdr() : BookList { { abort(); new BookList; } }; - - print_list() : Object { abort() }; -}; - -Class Cons inherits BookList { - xcar : Book; -- We keep the car and cdr in attributes. - xcdr : BookList; -- Because methods and features must have different names, - -- we use xcar and xcdr for the attributes and reserve - -- car and cdr for the features. - - isNil() : Bool { false }; - - init(hd : Book, tl : BookList) : Cons { - { - xcar <- hd; - xcdr <- tl; - self; - } - }; - - car() : Book { xcar }; - - cdr() : BookList { xcdr }; - - print_list() : Object { - { - case xcar.print() of - dummy : Book => out_string("- dynamic type was Book -\n"); - dummy : Article => out_string("- dynamic type was Article -\n"); - esac; - xcdr.print_list(); - } - }; -}; - -Class Nil inherits BookList { - isNil() : Bool { true }; - - print_list() : Object { true }; -}; - - -Class Main { - - books : BookList; - - main() : Object { - (let a_book : Book <- - (new Book).initBook("Compilers, Principles, Techniques, and Tools", - "Aho, Sethi, and Ullman") - in - (let an_article : Article <- - (new Article).initArticle("The Top 100 CD_ROMs", - "Ulanoff", - "PC Magazine") - in - { - books <- (new Nil).cons(a_book).cons(an_article); - books.print_list(); - } - ) -- end let an_article - ) -- end let a_book - }; -}; +-- example of static and dynamic type differing for a dispatch + +Class Book inherits IO { + title : String; + author : String; + + initBook(title_p : String, author_p : String) : Book { + { + title <- title_p; + author <- author_p; + self; + } + }; + + print() : Book { + { + out_string("title: ").out_string(title).out_string("\n"); + out_string("author: ").out_string(author).out_string("\n"); + self; + } + }; +}; + +Class Article inherits Book { + per_title : String; + + initArticle(title_p : String, author_p : String, + per_title_p : String) : Article { + { + initBook(title_p, author_p); + per_title <- per_title_p; + self; + } + }; + + print() : Book { + { + self@Book.print(); + out_string("periodical: ").out_string(per_title).out_string("\n"); + self; + } + }; +}; + +Class BookList inherits IO { + (* Since abort "returns" type Object, we have to add + an expression of type Bool here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + isNil() : Bool { { abort(); true; } }; + + cons(hd : Book) : Cons { + (let new_cell : Cons <- new Cons in + new_cell.init(hd,self) + ) + }; + + (* Since abort "returns" type Object, we have to add + an expression of type Book here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + car() : Book { { abort(); new Book; } }; + + (* Since abort "returns" type Object, we have to add + an expression of type BookList here to satisfy the typechecker. + This code is unreachable, since abort() halts the program. + *) + cdr() : BookList { { abort(); new BookList; } }; + + print_list() : Object { abort() }; +}; + +Class Cons inherits BookList { + xcar : Book; -- We keep the car and cdr in attributes. + xcdr : BookList; -- Because methods and features must have different names, + -- we use xcar and xcdr for the attributes and reserve + -- car and cdr for the features. + + isNil() : Bool { false }; + + init(hd : Book, tl : BookList) : Cons { + { + xcar <- hd; + xcdr <- tl; + self; + } + }; + + car() : Book { xcar }; + + cdr() : BookList { xcdr }; + + print_list() : Object { + { + case xcar.print() of + dummy : Book => out_string("- dynamic type was Book -\n"); + dummy : Article => out_string("- dynamic type was Article -\n"); + esac; + xcdr.print_list(); + } + }; +}; + +Class Nil inherits BookList { + isNil() : Bool { true }; + + print_list() : Object { true }; +}; + + +Class Main { + + books : BookList; + + main() : Object { + (let a_book : Book <- + (new Book).initBook("Compilers, Principles, Techniques, and Tools", + "Aho, Sethi, and Ullman") + in + (let an_article : Article <- + (new Article).initArticle("The Top 100 CD_ROMs", + "Ulanoff", + "PC Magazine") + in + { + books <- (new Nil).cons(a_book).cons(an_article); + books.print_list(); + } + ) -- end let an_article + ) -- end let a_book + }; +}; diff --git a/tests/codegen/cells.cl b/tests/codegen/cells.cl index 9fd6741bb..bcd891498 100755 --- a/tests/codegen/cells.cl +++ b/tests/codegen/cells.cl @@ -1,97 +1,97 @@ -(* models one-dimensional cellular automaton on a circle of finite radius - arrays are faked as Strings, - X's respresent live cells, dots represent dead cells, - no error checking is done *) -class CellularAutomaton inherits IO { - population_map : String; - - init(map : String) : CellularAutomaton { - { - population_map <- map; - self; - } - }; - - print() : CellularAutomaton { - { - out_string(population_map.concat("\n")); - self; - } - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - population_map.substr(position, 1) - }; - - cell_left_neighbor(position : Int) : String { - if position = 0 then - cell(num_cells() - 1) - else - cell(position - 1) - fi - }; - - cell_right_neighbor(position : Int) : String { - if position = num_cells() - 1 then - cell(0) - else - cell(position + 1) - fi - }; - - (* a cell will live if exactly 1 of itself and it's immediate - neighbors are alive *) - cell_at_next_evolution(position : Int) : String { - if (if cell(position) = "X" then 1 else 0 fi - + if cell_left_neighbor(position) = "X" then 1 else 0 fi - + if cell_right_neighbor(position) = "X" then 1 else 0 fi - = 1) - then - "X" - else - "." - fi - }; - - evolve() : CellularAutomaton { - (let position : Int in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; -}; - -class Main { - cells : CellularAutomaton; - - main() : Main { - { - cells <- (new CellularAutomaton).init(" X "); - cells.print(); - (let countdown : Int <- 20 in - while 0 < countdown loop - { - cells.evolve(); - cells.print(); - countdown <- countdown - 1; - } - pool - ); - self; - } - }; -}; +(* models one-dimensional cellular automaton on a circle of finite radius + arrays are faked as Strings, + X's respresent live cells, dots represent dead cells, + no error checking is done *) +class CellularAutomaton inherits IO { + population_map : String; + + init(map : String) : CellularAutomaton { + { + population_map <- map; + self; + } + }; + + print() : CellularAutomaton { + { + out_string(population_map.concat("\n")); + self; + } + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + population_map.substr(position, 1) + }; + + cell_left_neighbor(position : Int) : String { + if position = 0 then + cell(num_cells() - 1) + else + cell(position - 1) + fi + }; + + cell_right_neighbor(position : Int) : String { + if position = num_cells() - 1 then + cell(0) + else + cell(position + 1) + fi + }; + + (* a cell will live if exactly 1 of itself and it's immediate + neighbors are alive *) + cell_at_next_evolution(position : Int) : String { + if (if cell(position) = "X" then 1 else 0 fi + + if cell_left_neighbor(position) = "X" then 1 else 0 fi + + if cell_right_neighbor(position) = "X" then 1 else 0 fi + = 1) + then + "X" + else + "." + fi + }; + + evolve() : CellularAutomaton { + (let position : Int in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; +}; + +class Main { + cells : CellularAutomaton; + + main() : Main { + { + cells <- (new CellularAutomaton).init(" X "); + cells.print(); + (let countdown : Int <- 20 in + while 0 < countdown loop + { + cells.evolve(); + cells.print(); + countdown <- countdown - 1; + } + pool + ); + self; + } + }; +}; diff --git a/tests/codegen/complex.cl b/tests/codegen/complex.cl index 0b7aa44e9..9edb6151d 100755 --- a/tests/codegen/complex.cl +++ b/tests/codegen/complex.cl @@ -1,52 +1,52 @@ -class Main inherits IO { - main() : IO { - (let c : Complex <- (new Complex).init(1, 1) in - if c.reflect_X().reflect_Y() = c.reflect_0() - then out_string("=)\n") - else out_string("=(\n") - fi - ) - }; -}; - -class Complex inherits IO { - x : Int; - y : Int; - - init(a : Int, b : Int) : Complex { - { - x = a; - y = b; - self; - } - }; - - print() : Object { - if y = 0 - then out_int(x) - else out_int(x).out_string("+").out_int(y).out_string("I") - fi - }; - - reflect_0() : Complex { - { - x = ~x; - y = ~y; - self; - } - }; - - reflect_X() : Complex { - { - y = ~y; - self; - } - }; - - reflect_Y() : Complex { - { - x = ~x; - self; - } - }; -}; +class Main inherits IO { + main() : IO { + (let c : Complex <- (new Complex).init(1, 1) in + if c.reflect_X().reflect_Y() = c.reflect_0() + then out_string("=)\n") + else out_string("=(\n") + fi + ) + }; +}; + +class Complex inherits IO { + x : Int; + y : Int; + + init(a : Int, b : Int) : Complex { + { + x = a; + y = b; + self; + } + }; + + print() : Object { + if y = 0 + then out_int(x) + else out_int(x).out_string("+").out_int(y).out_string("I") + fi + }; + + reflect_0() : Complex { + { + x = ~x; + y = ~y; + self; + } + }; + + reflect_X() : Complex { + { + y = ~y; + self; + } + }; + + reflect_Y() : Complex { + { + x = ~x; + self; + } + }; +}; diff --git a/tests/codegen/fib.cl b/tests/codegen/fib.cl index 08ceaede8..ced8cee48 100644 --- a/tests/codegen/fib.cl +++ b/tests/codegen/fib.cl @@ -1,29 +1,29 @@ -class Main inherits IO { - -- the class has features. Only methods in this case. - main(): Object { - { - out_string("Enter n to find nth fibonacci number!\n"); - out_int(fib(in_int())); - out_string("\n"); - } - }; - - fib(i : Int) : Int { -- list of formals. And the return type of the method. - let a : Int <- 1, - b : Int <- 0, - c : Int <- 0 - in - { - while (not (i = 0)) loop -- expressions are nested. - { - c <- a + b; - i <- i - 1; - b <- a; - a <- c; - } - pool; - c; - } - }; - -}; +class Main inherits IO { + -- the class has features. Only methods in this case. + main(): Object { + { + out_string("Enter n to find nth fibonacci number!\n"); + out_int(fib(in_int())); + out_string("\n"); + } + }; + + fib(i : Int) : Int { -- list of formals. And the return type of the method. + let a : Int <- 1, + b : Int <- 0, + c : Int <- 0 + in + { + while (not (i = 0)) loop -- expressions are nested. + { + c <- a + b; + i <- i - 1; + b <- a; + a <- c; + } + pool; + c; + } + }; + +}; diff --git a/tests/codegen/fib_input.txt b/tests/codegen/fib_input.txt index f599e28b8..d43401489 100644 --- a/tests/codegen/fib_input.txt +++ b/tests/codegen/fib_input.txt @@ -1 +1 @@ -10 +10 diff --git a/tests/codegen/graph.cl b/tests/codegen/graph.cl index 8e511358c..59e29bbf4 100755 --- a/tests/codegen/graph.cl +++ b/tests/codegen/graph.cl @@ -1,381 +1,381 @@ -(* - * Cool program reading descriptions of weighted directed graphs - * from stdin. It builds up a graph objects with a list of vertices - * and a list of edges. Every vertice has a list of outgoing edges. - * - * INPUT FORMAT - * Every line has the form vertice successor* - * Where vertice is an int, and successor is vertice,weight - * - * An empty line or EOF terminates the input. - * - * The list of vertices and the edge list is printed out by the Main - * class. - * - * TEST - * Once compiled, the file g1.graph can be fed to the program. - * The output should look like this: - -nautilus.CS.Berkeley.EDU 53# spim -file graph.s (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - b : Int <- a.doh() + g.doh() + doh() + printh(); - - doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; - -}; - -class Bar inherits Razz { - - c : Int <- doh(); - - d : Object <- printh(); -}; - - -class Razz inherits Foo { - - e : Bar <- case self of - n : Razz => (new Bar); - n : Bar => n; - esac; - - f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); - -}; - -class Bazz inherits IO { - - h : Int <- 1; - - g : Foo <- case self of - n : Bazz => (new Foo); - n : Razz => (new Bar); - n : Foo => (new Razz); - n : Bar => n; - esac; - - i : Object <- printh(); - - printh() : Int { { out_int(h); 0; } }; - - doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; -}; - -(* scary . . . *) -class Main { - a : Bazz <- new Bazz; - b : Foo <- new Foo; - c : Razz <- new Razz; - d : Bar <- new Bar; - - main(): String { "do nothing" }; - -}; - - - - - +(* hairy . . .*) + +class Foo inherits Bazz { + a : Razz <- case self of + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + b : Int <- a.doh() + g.doh() + doh() + printh(); + + doh() : Int { (let i : Int <- h in { h <- h + 2; i; } ) }; + +}; + +class Bar inherits Razz { + + c : Int <- doh(); + + d : Object <- printh(); +}; + + +class Razz inherits Foo { + + e : Bar <- case self of + n : Razz => (new Bar); + n : Bar => n; + esac; + + f : Int <- a@Bazz.doh() + g.doh() + e.doh() + doh() + printh(); + +}; + +class Bazz inherits IO { + + h : Int <- 1; + + g : Foo <- case self of + n : Bazz => (new Foo); + n : Razz => (new Bar); + n : Foo => (new Razz); + n : Bar => n; + esac; + + i : Object <- printh(); + + printh() : Int { { out_int(h); 0; } }; + + doh() : Int { (let i: Int <- h in { h <- h + 1; i; } ) }; +}; + +(* scary . . . *) +class Main { + a : Bazz <- new Bazz; + b : Foo <- new Foo; + c : Razz <- new Razz; + d : Bar <- new Bar; + + main(): String { "do nothing" }; + +}; + + + + + diff --git a/tests/codegen/hello_world.cl b/tests/codegen/hello_world.cl index 0c818f908..b0a180a2e 100755 --- a/tests/codegen/hello_world.cl +++ b/tests/codegen/hello_world.cl @@ -1,5 +1,5 @@ -class Main inherits IO { - main(): IO { - out_string("Hello, World.\n") - }; -}; +class Main inherits IO { + main(): IO { + out_string("Hello, World.\n") + }; +}; diff --git a/tests/codegen/io.cl b/tests/codegen/io.cl index 7f0de869e..42ee6854e 100755 --- a/tests/codegen/io.cl +++ b/tests/codegen/io.cl @@ -1,103 +1,103 @@ -(* - * The IO class is predefined and has 4 methods: - * - * out_string(s : String) : SELF_TYPE - * out_int(i : Int) : SELF_TYPE - * in_string() : String - * in_int() : Int - * - * The out operations print their argument to the terminal. The - * in_string method reads an entire line from the terminal and returns a - * string not containing the new line. The in_int method also reads - * an entire line from the terminal and returns the integer - * corresponding to the first non blank word on the line. If that - * word is not an integer, it returns 0. - * - * - * Because our language is object oriented, we need an object of type - * IO in order to call any of these methods. - * - * There are basically two ways of getting access to IO in a class C. - * - * 1) Define C to Inherit from IO. This way the IO methods become - * methods of C, and they can be called using the abbreviated - * dispatch, i.e. - * - * class C inherits IO is - * ... - * out_string("Hello world\n") - * ... - * end; - * - * 2) If your class C does not directly or indirectly inherit from - * IO, the best way to access IO is through an initialized - * attribute of type IO. - * - * class C inherits Foo is - * io : IO <- new IO; - * ... - * io.out_string("Hello world\n"); - * ... - * end; - * - * Approach 1) is most often used, in particular when you need IO - * functions in the Main class. - * - *) - - -class A { - - -- Let's assume that we don't want A to not inherit from IO. - - io : IO <- new IO; - - out_a() : Object { io.out_string("A: Hello world\n") }; - -}; - - -class B inherits A { - - -- B does not have to an extra attribute, since it inherits io from A. - - out_b() : Object { io.out_string("B: Hello world\n") }; - -}; - - -class C inherits IO { - - -- Now the IO methods are part of C. - - out_c() : Object { out_string("C: Hello world\n") }; - - -- Note that out_string(...) is just a shorthand for self.out_string(...) - -}; - - -class D inherits C { - - -- Inherits IO methods from C. - - out_d() : Object { out_string("D: Hello world\n") }; - -}; - - -class Main inherits IO { - - -- Same case as class C. - - main() : Object { - { - (new A).out_a(); - (new B).out_b(); - (new C).out_c(); - (new D).out_d(); - out_string("Done.\n"); - } - }; - -}; +(* + * The IO class is predefined and has 4 methods: + * + * out_string(s : String) : SELF_TYPE + * out_int(i : Int) : SELF_TYPE + * in_string() : String + * in_int() : Int + * + * The out operations print their argument to the terminal. The + * in_string method reads an entire line from the terminal and returns a + * string not containing the new line. The in_int method also reads + * an entire line from the terminal and returns the integer + * corresponding to the first non blank word on the line. If that + * word is not an integer, it returns 0. + * + * + * Because our language is object oriented, we need an object of type + * IO in order to call any of these methods. + * + * There are basically two ways of getting access to IO in a class C. + * + * 1) Define C to Inherit from IO. This way the IO methods become + * methods of C, and they can be called using the abbreviated + * dispatch, i.e. + * + * class C inherits IO is + * ... + * out_string("Hello world\n") + * ... + * end; + * + * 2) If your class C does not directly or indirectly inherit from + * IO, the best way to access IO is through an initialized + * attribute of type IO. + * + * class C inherits Foo is + * io : IO <- new IO; + * ... + * io.out_string("Hello world\n"); + * ... + * end; + * + * Approach 1) is most often used, in particular when you need IO + * functions in the Main class. + * + *) + + +class A { + + -- Let's assume that we don't want A to not inherit from IO. + + io : IO <- new IO; + + out_a() : Object { io.out_string("A: Hello world\n") }; + +}; + + +class B inherits A { + + -- B does not have to an extra attribute, since it inherits io from A. + + out_b() : Object { io.out_string("B: Hello world\n") }; + +}; + + +class C inherits IO { + + -- Now the IO methods are part of C. + + out_c() : Object { out_string("C: Hello world\n") }; + + -- Note that out_string(...) is just a shorthand for self.out_string(...) + +}; + + +class D inherits C { + + -- Inherits IO methods from C. + + out_d() : Object { out_string("D: Hello world\n") }; + +}; + + +class Main inherits IO { + + -- Same case as class C. + + main() : Object { + { + (new A).out_a(); + (new B).out_b(); + (new C).out_c(); + (new D).out_d(); + out_string("Done.\n"); + } + }; + +}; diff --git a/tests/codegen/life.cl b/tests/codegen/life.cl index b83d97957..7d7a41fdb 100755 --- a/tests/codegen/life.cl +++ b/tests/codegen/life.cl @@ -1,436 +1,436 @@ -(* The Game of Life - Tendo Kayiira, Summer '95 - With code taken from /private/cool/class/examples/cells.cl - - This introduction was taken off the internet. It gives a brief - description of the Game Of Life. It also gives the rules by which - this particular game follows. - - Introduction - - John Conway's Game of Life is a mathematical amusement, but it - is also much more: an insight into how a system of simple - cellualar automata can create complex, odd, and often aesthetically - pleasing patterns. It is played on a cartesian grid of cells - which are either 'on' or 'off' The game gets it's name from the - similarity between the behaviour of these cells and the behaviour - of living organisms. - - The Rules - - The playfield is a cartesian grid of arbitrary size. Each cell in - this grid can be in an 'on' state or an 'off' state. On each 'turn' - (called a generation,) the state of each cell changes simultaneously - depending on it's state and the state of all cells adjacent to it. - - For 'on' cells, - If the cell has 0 or 1 neighbours which are 'on', the cell turns - 'off'. ('dies of loneliness') - If the cell has 2 or 3 neighbours which are 'on', the cell stays - 'on'. (nothing happens to that cell) - If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', - the cell turns 'off'. ('dies of overcrowding') - - For 'off' cells, - If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which - are 'on', the cell stays 'off'. (nothing happens to that cell) - If the cell has 3 neighbours which are 'on', the cell turns - 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) - - Repeat for as many generations as desired. - - *) - - -class Board inherits IO { - - rows : Int; - columns : Int; - board_size : Int; - - size_of_board(initial : String) : Int { - initial.length() - }; - - board_init(start : String) : Board { - (let size :Int <- size_of_board(start) in - { - if size = 15 then - { - rows <- 3; - columns <- 5; - board_size <- size; - } - else if size = 16 then - { - rows <- 4; - columns <- 4; - board_size <- size; - } - else if size = 20 then - { - rows <- 4; - columns <- 5; - board_size <- size; - } - else if size = 21 then - { - rows <- 3; - columns <- 7; - board_size <- size; - } - else if size = 25 then - { - rows <- 5; - columns <- 5; - board_size <- size; - } - else if size = 28 then - { - rows <- 7; - columns <- 4; - board_size <- size; - } - else -- If none of the above fit, then just give - { -- the configuration of the most common board - rows <- 5; - columns <- 5; - board_size <- size; - } - fi fi fi fi fi fi; - self; - } - ) - }; - -}; - - - -class CellularAutomaton inherits Board { - population_map : String; - - init(map : String) : CellularAutomaton { - { - population_map <- map; - board_init(map); - self; - } - }; - - - - - print() : CellularAutomaton { - - (let i : Int <- 0 in - (let num : Int <- board_size in - { - out_string("\n"); - while i < num loop - { - out_string(population_map.substr(i,columns)); - out_string("\n"); - i <- i + columns; - } - pool; - out_string("\n"); - self; - } - ) ) - }; - - num_cells() : Int { - population_map.length() - }; - - cell(position : Int) : String { - if board_size - 1 < position then - " " - else - population_map.substr(position, 1) - fi - }; - - north(position : Int): String { - if (position - columns) < 0 then - " " - else - cell(position - columns) - fi - }; - - south(position : Int): String { - if board_size < (position + columns) then - " " - else - cell(position + columns) - fi - }; - - east(position : Int): String { - if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - cell(position + 1) - fi - }; - - west(position : Int): String { - if position = 0 then - " " - else - if ((position / columns) * columns) = position then - " " - else - cell(position - 1) - fi fi - }; - - northwest(position : Int): String { - if (position - columns) < 0 then - " " - else if ((position / columns) * columns) = position then - " " - else - north(position - 1) - fi fi - }; - - northeast(position : Int): String { - if (position - columns) < 0 then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - north(position + 1) - fi fi - }; - - southeast(position : Int): String { - if board_size < (position + columns) then - " " - else if (((position + 1) /columns ) * columns) = (position + 1) then - " " - else - south(position + 1) - fi fi - }; - - southwest(position : Int): String { - if board_size < (position + columns) then - " " - else if ((position / columns) * columns) = position then - " " - else - south(position - 1) - fi fi - }; - - neighbors(position: Int): Int { - { - if north(position) = "X" then 1 else 0 fi - + if south(position) = "X" then 1 else 0 fi - + if east(position) = "X" then 1 else 0 fi - + if west(position) = "X" then 1 else 0 fi - + if northeast(position) = "X" then 1 else 0 fi - + if northwest(position) = "X" then 1 else 0 fi - + if southeast(position) = "X" then 1 else 0 fi - + if southwest(position) = "X" then 1 else 0 fi; - } - }; - - -(* A cell will live if 2 or 3 of it's neighbors are alive. It dies - otherwise. A cell is born if only 3 of it's neighbors are alive. *) - - cell_at_next_evolution(position : Int) : String { - - if neighbors(position) = 3 then - "X" - else - if neighbors(position) = 2 then - if cell(position) = "X" then - "X" - else - "-" - fi - else - "-" - fi fi - }; - - - evolve() : CellularAutomaton { - (let position : Int <- 0 in - (let num : Int <- num_cells() in - (let temp : String in - { - while position < num loop - { - temp <- temp.concat(cell_at_next_evolution(position)); - position <- position + 1; - } - pool; - population_map <- temp; - self; - } - ) ) ) - }; - -(* This is where the background pattern is detremined by the user. More - patterns can be added as long as whoever adds keeps the board either - 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) - option(): String { - { - (let num : Int in - { - out_string("\nPlease chose a number:\n"); - out_string("\t1: A cross\n"); - out_string("\t2: A slash from the upper left to lower right\n"); - out_string("\t3: A slash from the upper right to lower left\n"); - out_string("\t4: An X\n"); - out_string("\t5: A greater than sign \n"); - out_string("\t6: A less than sign\n"); - out_string("\t7: Two greater than signs\n"); - out_string("\t8: Two less than signs\n"); - out_string("\t9: A 'V'\n"); - out_string("\t10: An inverse 'V'\n"); - out_string("\t11: Numbers 9 and 10 combined\n"); - out_string("\t12: A full grid\n"); - out_string("\t13: A 'T'\n"); - out_string("\t14: A plus '+'\n"); - out_string("\t15: A 'W'\n"); - out_string("\t16: An 'M'\n"); - out_string("\t17: An 'E'\n"); - out_string("\t18: A '3'\n"); - out_string("\t19: An 'O'\n"); - out_string("\t20: An '8'\n"); - out_string("\t21: An 'S'\n"); - out_string("Your choice => "); - num <- in_int(); - out_string("\n"); - if num = 1 then - " XX XXXX XXXX XX " - else if num = 2 then - " X X X X X " - else if num = 3 then - "X X X X X" - else if num = 4 then - "X X X X X X X X X" - else if num = 5 then - "X X X X X " - else if num = 6 then - " X X X X X" - else if num = 7 then - "X X X XX X " - else if num = 8 then - " X XX X X X " - else if num = 9 then - "X X X X X " - else if num = 10 then - " X X X X X" - else if num = 11 then - "X X X X X X X X" - else if num = 12 then - "XXXXXXXXXXXXXXXXXXXXXXXXX" - else if num = 13 then - "XXXXX X X X X " - else if num = 14 then - " X X XXXXX X X " - else if num = 15 then - "X X X X X X X " - else if num = 16 then - " X X X X X X X" - else if num = 17 then - "XXXXX X XXXXX X XXXX" - else if num = 18 then - "XXX X X X X XXXX " - else if num = 19 then - " XX X XX X XX " - else if num = 20 then - " XX X XX X XX X XX X XX " - else if num = 21 then - " XXXX X XX X XXXX " - else - " " - fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; - } - ); - } - }; - - - - - prompt() : Bool { - { - (let ans : String in - { - out_string("Would you like to continue with the next generation? \n"); - out_string("Please use lowercase y or n for your answer [y]: "); - ans <- in_string(); - out_string("\n"); - if ans = "n" then - false - else - true - fi; - } - ); - } - }; - - - prompt2() : Bool { - (let ans : String in - { - out_string("\n\n"); - out_string("Would you like to choose a background pattern? \n"); - out_string("Please use lowercase y or n for your answer [n]: "); - ans <- in_string(); - if ans = "y" then - true - else - false - fi; - } - ) - }; - - -}; - -class Main inherits CellularAutomaton { - cells : CellularAutomaton; - - main() : Main { - { - (let continue : Bool in - (let choice : String in - { - out_string("Welcome to the Game of Life.\n"); - out_string("There are many initial states to choose from. \n"); - while prompt2() loop - { - continue <- true; - choice <- option(); - cells <- (new CellularAutomaton).init(choice); - cells.print(); - while continue loop - if prompt() then - { - cells.evolve(); - cells.print(); - } - else - continue <- false - fi - pool; - } - pool; - self; - } ) ); } - }; -}; - +(* The Game of Life + Tendo Kayiira, Summer '95 + With code taken from /private/cool/class/examples/cells.cl + + This introduction was taken off the internet. It gives a brief + description of the Game Of Life. It also gives the rules by which + this particular game follows. + + Introduction + + John Conway's Game of Life is a mathematical amusement, but it + is also much more: an insight into how a system of simple + cellualar automata can create complex, odd, and often aesthetically + pleasing patterns. It is played on a cartesian grid of cells + which are either 'on' or 'off' The game gets it's name from the + similarity between the behaviour of these cells and the behaviour + of living organisms. + + The Rules + + The playfield is a cartesian grid of arbitrary size. Each cell in + this grid can be in an 'on' state or an 'off' state. On each 'turn' + (called a generation,) the state of each cell changes simultaneously + depending on it's state and the state of all cells adjacent to it. + + For 'on' cells, + If the cell has 0 or 1 neighbours which are 'on', the cell turns + 'off'. ('dies of loneliness') + If the cell has 2 or 3 neighbours which are 'on', the cell stays + 'on'. (nothing happens to that cell) + If the cell has 4, 5, 6, 7, 8, or 9 neighbours which are 'on', + the cell turns 'off'. ('dies of overcrowding') + + For 'off' cells, + If the cell has 0, 1, 2, 4, 5, 6, 7, 8, or 9 neighbours which + are 'on', the cell stays 'off'. (nothing happens to that cell) + If the cell has 3 neighbours which are 'on', the cell turns + 'on'. (3 neighbouring 'alive' cells 'give birth' to a fourth.) + + Repeat for as many generations as desired. + + *) + + +class Board inherits IO { + + rows : Int; + columns : Int; + board_size : Int; + + size_of_board(initial : String) : Int { + initial.length() + }; + + board_init(start : String) : Board { + (let size :Int <- size_of_board(start) in + { + if size = 15 then + { + rows <- 3; + columns <- 5; + board_size <- size; + } + else if size = 16 then + { + rows <- 4; + columns <- 4; + board_size <- size; + } + else if size = 20 then + { + rows <- 4; + columns <- 5; + board_size <- size; + } + else if size = 21 then + { + rows <- 3; + columns <- 7; + board_size <- size; + } + else if size = 25 then + { + rows <- 5; + columns <- 5; + board_size <- size; + } + else if size = 28 then + { + rows <- 7; + columns <- 4; + board_size <- size; + } + else -- If none of the above fit, then just give + { -- the configuration of the most common board + rows <- 5; + columns <- 5; + board_size <- size; + } + fi fi fi fi fi fi; + self; + } + ) + }; + +}; + + + +class CellularAutomaton inherits Board { + population_map : String; + + init(map : String) : CellularAutomaton { + { + population_map <- map; + board_init(map); + self; + } + }; + + + + + print() : CellularAutomaton { + + (let i : Int <- 0 in + (let num : Int <- board_size in + { + out_string("\n"); + while i < num loop + { + out_string(population_map.substr(i,columns)); + out_string("\n"); + i <- i + columns; + } + pool; + out_string("\n"); + self; + } + ) ) + }; + + num_cells() : Int { + population_map.length() + }; + + cell(position : Int) : String { + if board_size - 1 < position then + " " + else + population_map.substr(position, 1) + fi + }; + + north(position : Int): String { + if (position - columns) < 0 then + " " + else + cell(position - columns) + fi + }; + + south(position : Int): String { + if board_size < (position + columns) then + " " + else + cell(position + columns) + fi + }; + + east(position : Int): String { + if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + cell(position + 1) + fi + }; + + west(position : Int): String { + if position = 0 then + " " + else + if ((position / columns) * columns) = position then + " " + else + cell(position - 1) + fi fi + }; + + northwest(position : Int): String { + if (position - columns) < 0 then + " " + else if ((position / columns) * columns) = position then + " " + else + north(position - 1) + fi fi + }; + + northeast(position : Int): String { + if (position - columns) < 0 then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + north(position + 1) + fi fi + }; + + southeast(position : Int): String { + if board_size < (position + columns) then + " " + else if (((position + 1) /columns ) * columns) = (position + 1) then + " " + else + south(position + 1) + fi fi + }; + + southwest(position : Int): String { + if board_size < (position + columns) then + " " + else if ((position / columns) * columns) = position then + " " + else + south(position - 1) + fi fi + }; + + neighbors(position: Int): Int { + { + if north(position) = "X" then 1 else 0 fi + + if south(position) = "X" then 1 else 0 fi + + if east(position) = "X" then 1 else 0 fi + + if west(position) = "X" then 1 else 0 fi + + if northeast(position) = "X" then 1 else 0 fi + + if northwest(position) = "X" then 1 else 0 fi + + if southeast(position) = "X" then 1 else 0 fi + + if southwest(position) = "X" then 1 else 0 fi; + } + }; + + +(* A cell will live if 2 or 3 of it's neighbors are alive. It dies + otherwise. A cell is born if only 3 of it's neighbors are alive. *) + + cell_at_next_evolution(position : Int) : String { + + if neighbors(position) = 3 then + "X" + else + if neighbors(position) = 2 then + if cell(position) = "X" then + "X" + else + "-" + fi + else + "-" + fi fi + }; + + + evolve() : CellularAutomaton { + (let position : Int <- 0 in + (let num : Int <- num_cells() in + (let temp : String in + { + while position < num loop + { + temp <- temp.concat(cell_at_next_evolution(position)); + position <- position + 1; + } + pool; + population_map <- temp; + self; + } + ) ) ) + }; + +(* This is where the background pattern is detremined by the user. More + patterns can be added as long as whoever adds keeps the board either + 3x5, 4x5, 5x5, 3x7, 7x4, 4x4 with the row first then column. *) + option(): String { + { + (let num : Int in + { + out_string("\nPlease chose a number:\n"); + out_string("\t1: A cross\n"); + out_string("\t2: A slash from the upper left to lower right\n"); + out_string("\t3: A slash from the upper right to lower left\n"); + out_string("\t4: An X\n"); + out_string("\t5: A greater than sign \n"); + out_string("\t6: A less than sign\n"); + out_string("\t7: Two greater than signs\n"); + out_string("\t8: Two less than signs\n"); + out_string("\t9: A 'V'\n"); + out_string("\t10: An inverse 'V'\n"); + out_string("\t11: Numbers 9 and 10 combined\n"); + out_string("\t12: A full grid\n"); + out_string("\t13: A 'T'\n"); + out_string("\t14: A plus '+'\n"); + out_string("\t15: A 'W'\n"); + out_string("\t16: An 'M'\n"); + out_string("\t17: An 'E'\n"); + out_string("\t18: A '3'\n"); + out_string("\t19: An 'O'\n"); + out_string("\t20: An '8'\n"); + out_string("\t21: An 'S'\n"); + out_string("Your choice => "); + num <- in_int(); + out_string("\n"); + if num = 1 then + " XX XXXX XXXX XX " + else if num = 2 then + " X X X X X " + else if num = 3 then + "X X X X X" + else if num = 4 then + "X X X X X X X X X" + else if num = 5 then + "X X X X X " + else if num = 6 then + " X X X X X" + else if num = 7 then + "X X X XX X " + else if num = 8 then + " X XX X X X " + else if num = 9 then + "X X X X X " + else if num = 10 then + " X X X X X" + else if num = 11 then + "X X X X X X X X" + else if num = 12 then + "XXXXXXXXXXXXXXXXXXXXXXXXX" + else if num = 13 then + "XXXXX X X X X " + else if num = 14 then + " X X XXXXX X X " + else if num = 15 then + "X X X X X X X " + else if num = 16 then + " X X X X X X X" + else if num = 17 then + "XXXXX X XXXXX X XXXX" + else if num = 18 then + "XXX X X X X XXXX " + else if num = 19 then + " XX X XX X XX " + else if num = 20 then + " XX X XX X XX X XX X XX " + else if num = 21 then + " XXXX X XX X XXXX " + else + " " + fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi fi; + } + ); + } + }; + + + + + prompt() : Bool { + { + (let ans : String in + { + out_string("Would you like to continue with the next generation? \n"); + out_string("Please use lowercase y or n for your answer [y]: "); + ans <- in_string(); + out_string("\n"); + if ans = "n" then + false + else + true + fi; + } + ); + } + }; + + + prompt2() : Bool { + (let ans : String in + { + out_string("\n\n"); + out_string("Would you like to choose a background pattern? \n"); + out_string("Please use lowercase y or n for your answer [n]: "); + ans <- in_string(); + if ans = "y" then + true + else + false + fi; + } + ) + }; + + +}; + +class Main inherits CellularAutomaton { + cells : CellularAutomaton; + + main() : Main { + { + (let continue : Bool in + (let choice : String in + { + out_string("Welcome to the Game of Life.\n"); + out_string("There are many initial states to choose from. \n"); + while prompt2() loop + { + continue <- true; + choice <- option(); + cells <- (new CellularAutomaton).init(choice); + cells.print(); + while continue loop + if prompt() then + { + cells.evolve(); + cells.print(); + } + else + continue <- false + fi + pool; + } + pool; + self; + } ) ); } + }; +}; + diff --git a/tests/codegen/new_complex.cl b/tests/codegen/new_complex.cl index a4fe714ce..ad7035b56 100755 --- a/tests/codegen/new_complex.cl +++ b/tests/codegen/new_complex.cl @@ -1,79 +1,79 @@ -class Main inherits IO { - main() : IO { - (let c : Complex <- (new Complex).init(1, 1) in - { - -- trivially equal (see CoolAid) - if c.reflect_X() = c.reflect_0() - then out_string("=)\n") - else out_string("=(\n") - fi; - -- equal - if c.reflect_X().reflect_Y().equal(c.reflect_0()) - then out_string("=)\n") - else out_string("=(\n") - fi; - } - ) - }; -}; - -class Complex inherits IO { - x : Int; - y : Int; - - init(a : Int, b : Int) : Complex { - { - x = a; - y = b; - self; - } - }; - - print() : Object { - if y = 0 - then out_int(x) - else out_int(x).out_string("+").out_int(y).out_string("I") - fi - }; - - reflect_0() : Complex { - { - x = ~x; - y = ~y; - self; - } - }; - - reflect_X() : Complex { - { - y = ~y; - self; - } - }; - - reflect_Y() : Complex { - { - x = ~x; - self; - } - }; - - equal(d : Complex) : Bool { - if x = d.x_value() - then - if y = d.y_value() - then true - else false - fi - else false - fi - }; - - x_value() : Int { - x - }; - - y_value() : Int { - y - }; -}; +class Main inherits IO { + main() : IO { + (let c : Complex <- (new Complex).init(1, 1) in + { + -- trivially equal (see CoolAid) + if c.reflect_X() = c.reflect_0() + then out_string("=)\n") + else out_string("=(\n") + fi; + -- equal + if c.reflect_X().reflect_Y().equal(c.reflect_0()) + then out_string("=)\n") + else out_string("=(\n") + fi; + } + ) + }; +}; + +class Complex inherits IO { + x : Int; + y : Int; + + init(a : Int, b : Int) : Complex { + { + x = a; + y = b; + self; + } + }; + + print() : Object { + if y = 0 + then out_int(x) + else out_int(x).out_string("+").out_int(y).out_string("I") + fi + }; + + reflect_0() : Complex { + { + x = ~x; + y = ~y; + self; + } + }; + + reflect_X() : Complex { + { + y = ~y; + self; + } + }; + + reflect_Y() : Complex { + { + x = ~x; + self; + } + }; + + equal(d : Complex) : Bool { + if x = d.x_value() + then + if y = d.y_value() + then true + else false + fi + else false + fi + }; + + x_value() : Int { + x + }; + + y_value() : Int { + y + }; +}; diff --git a/tests/codegen/palindrome.cl b/tests/codegen/palindrome.cl index 7f24789f9..6acbeb731 100755 --- a/tests/codegen/palindrome.cl +++ b/tests/codegen/palindrome.cl @@ -1,25 +1,25 @@ -class Main inherits IO { - pal(s : String) : Bool { - if s.length() = 0 - then true - else if s.length() = 1 - then true - else if s.substr(0, 1) = s.substr(s.length() - 1, 1) - then pal(s.substr(1, s.length() -2)) - else false - fi fi fi - }; - - i : Int; - - main() : IO { - { - i <- ~1; - out_string("enter a string\n"); - if pal(in_string()) - then out_string("that was a palindrome\n") - else out_string("that was not a palindrome\n") - fi; - } - }; -}; +class Main inherits IO { + pal(s : String) : Bool { + if s.length() = 0 + then true + else if s.length() = 1 + then true + else if s.substr(0, 1) = s.substr(s.length() - 1, 1) + then pal(s.substr(1, s.length() -2)) + else false + fi fi fi + }; + + i : Int; + + main() : IO { + { + i <- ~1; + out_string("enter a string\n"); + if pal(in_string()) + then out_string("that was a palindrome\n") + else out_string("that was not a palindrome\n") + fi; + } + }; +}; diff --git a/tests/codegen_test.py b/tests/codegen_test.py index 48df768ff..a426ff6bd 100644 --- a/tests/codegen_test.py +++ b/tests/codegen_test.py @@ -10,8 +10,11 @@ # @pytest.mark.semantic @pytest.mark.codegen @pytest.mark.ok -@pytest.mark.run(order=4) +@pytest.mark.run(order=6) @pytest.mark.parametrize("cool_file", tests) def test_codegen(compiler_path, cool_file): compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ - tests_dir + cool_file[:-3] + '_output.txt') \ No newline at end of file + tests_dir + cool_file[:-3] + '_output.txt', timeout=10) + +# if __name__ == "__main__": +# pytest.main(["-m", "codegen"]) \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index 1f44eeb72..3dd3fe6cd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,4 +3,11 @@ @pytest.fixture def compiler_path(): - return os.path.abspath('./coolc.sh') \ No newline at end of file + curr = os.path.dirname(__file__) + return os.path.join(curr, "..", "src", "coolc.sh") + # return os.path.abspath('./coolc.sh') + +@pytest.fixture +def main_path(): + curr = os.path.dirname(__file__) + return os.path.join(curr, "..", "src", "cool_cmp", "main.py") \ No newline at end of file diff --git a/tests/icil_test.py b/tests/icil_test.py new file mode 100644 index 000000000..711664de5 --- /dev/null +++ b/tests/icil_test.py @@ -0,0 +1,24 @@ + +import pytest + +import os +from utils import compare_outputs_icil + +tests_dir = __file__.rpartition('/')[0] + '/initial_gen/' +tests_dir2 = __file__.rpartition('/')[0] + '/codegen/' +tests1 = [(file, tests_dir) for file in os.listdir(tests_dir) if file.endswith('.cl')] +tests2 = [(file, tests_dir2) for file in os.listdir(tests_dir2) if file.endswith('.cl')] + +tests = tests1 + tests2 + +@pytest.mark.icil +@pytest.mark.ok +@pytest.mark.run(order=4) +@pytest.mark.parametrize("cool_files", tests) +def test_icil(main_path, cool_files): + cool_file, tests_dir = cool_files + compare_outputs_icil(main_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt') + +# if __name__ == "__main__": +# pytest.main(["-m", "icil"]) \ No newline at end of file diff --git a/tests/initial_gen/ackermann.cl b/tests/initial_gen/ackermann.cl new file mode 100644 index 000000000..da3b46119 --- /dev/null +++ b/tests/initial_gen/ackermann.cl @@ -0,0 +1,16 @@ +class Main inherits IO { + ack(m: Int, n: Int) : Int { + if m = 0 then + n + 1 + else if n = 0 then + ack(m-1, 1) + else + ack(m-1, ack(m, n-1)) + fi + fi + }; + + main() : IO { + out_int(ack(2,3)) + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/ackermann_input.txt b/tests/initial_gen/ackermann_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/ackermann_output.txt b/tests/initial_gen/ackermann_output.txt new file mode 100644 index 000000000..f11c82a4c --- /dev/null +++ b/tests/initial_gen/ackermann_output.txt @@ -0,0 +1 @@ +9 \ No newline at end of file diff --git a/tests/initial_gen/case_of.cl b/tests/initial_gen/case_of.cl new file mode 100644 index 000000000..10f845a74 --- /dev/null +++ b/tests/initial_gen/case_of.cl @@ -0,0 +1,14 @@ +class A{ +}; + +class B inherits A { +}; + +class Main inherits IO { + main() : AUTO_TYPE { + out_int(case new B of + a: A => 1; + b: B => 2; + esac) + }; +}; diff --git a/tests/initial_gen/case_of_input.txt b/tests/initial_gen/case_of_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/case_of_output.txt b/tests/initial_gen/case_of_output.txt new file mode 100644 index 000000000..d8263ee98 --- /dev/null +++ b/tests/initial_gen/case_of_output.txt @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/tests/initial_gen/concat.cl b/tests/initial_gen/concat.cl new file mode 100644 index 000000000..1c78120f3 --- /dev/null +++ b/tests/initial_gen/concat.cl @@ -0,0 +1,7 @@ +class Main inherits IO +{ + main(): AUTO_TYPE + { + out_string("Hello ".concat("World!")) + }; +}; diff --git a/tests/initial_gen/concat_input.txt b/tests/initial_gen/concat_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/concat_output.txt b/tests/initial_gen/concat_output.txt new file mode 100644 index 000000000..c57eff55e --- /dev/null +++ b/tests/initial_gen/concat_output.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/tests/initial_gen/copy.cl b/tests/initial_gen/copy.cl new file mode 100644 index 000000000..1787c4d80 --- /dev/null +++ b/tests/initial_gen/copy.cl @@ -0,0 +1,24 @@ +class Main inherits IO { + + a:Int <- 0; + + get_a() : Int { + a + }; + + add_a() : AUTO_TYPE { + a <- a+1 + }; + + main() : AUTO_TYPE { + { + a <- 1; + let b:Main <- copy() in { + out_int(b.get_a()); + b.add_a(); + out_int(b.get_a()); + out_int(a); + }; + } + }; +}; diff --git a/tests/initial_gen/copy_input.txt b/tests/initial_gen/copy_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/copy_output.txt b/tests/initial_gen/copy_output.txt new file mode 100644 index 000000000..5a396e28e --- /dev/null +++ b/tests/initial_gen/copy_output.txt @@ -0,0 +1 @@ +121 \ No newline at end of file diff --git a/tests/initial_gen/equal.cl b/tests/initial_gen/equal.cl new file mode 100644 index 000000000..3b0151975 --- /dev/null +++ b/tests/initial_gen/equal.cl @@ -0,0 +1,26 @@ +class Main inherits IO { + main() : AUTO_TYPE { + if "Hello" = "Hello" then + if "0" = "1" then + out_string("Mal1") + else if 5 = 4 then + out_string("Mal2") + else if 1 = 1 then + if new Object = new Object then + out_string("Mal") + else if self = self then + out_string("Bien") + else + out_string("Mal") + fi + fi + else + out_string("Mal3") + fi + fi + fi + else + out_string("Mal4") + fi + }; +}; diff --git a/tests/initial_gen/equal_input.txt b/tests/initial_gen/equal_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/equal_output.txt b/tests/initial_gen/equal_output.txt new file mode 100644 index 000000000..7d843c7a3 --- /dev/null +++ b/tests/initial_gen/equal_output.txt @@ -0,0 +1 @@ +Bien \ No newline at end of file diff --git a/tests/initial_gen/length.cl b/tests/initial_gen/length.cl new file mode 100644 index 000000000..84176f30c --- /dev/null +++ b/tests/initial_gen/length.cl @@ -0,0 +1,6 @@ +class Main inherits IO { + msg: String <- "Hello"; + main() : AUTO_TYPE { + out_int(msg.length()) + }; +}; diff --git a/tests/initial_gen/length_input.txt b/tests/initial_gen/length_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/length_output.txt b/tests/initial_gen/length_output.txt new file mode 100644 index 000000000..7813681f5 --- /dev/null +++ b/tests/initial_gen/length_output.txt @@ -0,0 +1 @@ +5 \ No newline at end of file diff --git a/tests/initial_gen/print_arg_int.cl b/tests/initial_gen/print_arg_int.cl new file mode 100644 index 000000000..69800c9bd --- /dev/null +++ b/tests/initial_gen/print_arg_int.cl @@ -0,0 +1,8 @@ +class Main inherits IO { + arg: Int <- 1; + main() : IO { + { + out_int(arg); + } + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/print_arg_int_input.txt b/tests/initial_gen/print_arg_int_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/print_arg_int_output.txt b/tests/initial_gen/print_arg_int_output.txt new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/tests/initial_gen/print_arg_int_output.txt @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/tests/initial_gen/print_arg_string.cl b/tests/initial_gen/print_arg_string.cl new file mode 100644 index 000000000..18403a798 --- /dev/null +++ b/tests/initial_gen/print_arg_string.cl @@ -0,0 +1,8 @@ +class Main inherits IO { + arg: String <- "Hello World!"; + main() : IO { + { + out_string(arg); + } + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/print_arg_string_input.txt b/tests/initial_gen/print_arg_string_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/print_arg_string_output.txt b/tests/initial_gen/print_arg_string_output.txt new file mode 100644 index 000000000..c57eff55e --- /dev/null +++ b/tests/initial_gen/print_arg_string_output.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/tests/initial_gen/print_int.cl b/tests/initial_gen/print_int.cl new file mode 100644 index 000000000..4c61009cb --- /dev/null +++ b/tests/initial_gen/print_int.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : IO { + out_int(2022) + }; +}; diff --git a/tests/initial_gen/print_int_input.txt b/tests/initial_gen/print_int_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/print_int_output.txt b/tests/initial_gen/print_int_output.txt new file mode 100644 index 000000000..a7d594744 --- /dev/null +++ b/tests/initial_gen/print_int_output.txt @@ -0,0 +1 @@ +2022 \ No newline at end of file diff --git a/tests/initial_gen/print_string.cl b/tests/initial_gen/print_string.cl new file mode 100644 index 000000000..3d8f0714b --- /dev/null +++ b/tests/initial_gen/print_string.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : IO { + out_string("Hello World!") + }; +}; diff --git a/tests/initial_gen/print_string_input.txt b/tests/initial_gen/print_string_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/print_string_output.txt b/tests/initial_gen/print_string_output.txt new file mode 100644 index 000000000..c57eff55e --- /dev/null +++ b/tests/initial_gen/print_string_output.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/tests/initial_gen/self_type.cl b/tests/initial_gen/self_type.cl new file mode 100644 index 000000000..6efc1e5d7 --- /dev/null +++ b/tests/initial_gen/self_type.cl @@ -0,0 +1,32 @@ +class A +{ + get(): SELF_TYPE + { + self + }; + get2(): SELF_TYPE + { + new SELF_TYPE + }; +}; + + +class B inherits A +{ + +}; + + +class Main inherits IO +{ + main(): AUTO_TYPE + { + { + let b:B <- + new B in + out_string(b.get().type_name().concat(b.get2().type_name().concat(b.type_name()))); + } + }; +}; + + diff --git a/tests/initial_gen/self_type_input.txt b/tests/initial_gen/self_type_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/self_type_output.txt b/tests/initial_gen/self_type_output.txt new file mode 100644 index 000000000..f6d5afa37 --- /dev/null +++ b/tests/initial_gen/self_type_output.txt @@ -0,0 +1 @@ +BBB \ No newline at end of file diff --git a/tests/initial_gen/simple_conditional.cl b/tests/initial_gen/simple_conditional.cl new file mode 100644 index 000000000..56c29235b --- /dev/null +++ b/tests/initial_gen/simple_conditional.cl @@ -0,0 +1,8 @@ +class Main inherits IO { + main() : IO { + { + if false then out_int(0) else out_int(1) fi; + if true then out_int(0) else out_int(1) fi; + } + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/simple_conditional_input.txt b/tests/initial_gen/simple_conditional_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/simple_conditional_output.txt b/tests/initial_gen/simple_conditional_output.txt new file mode 100644 index 000000000..9a037142a --- /dev/null +++ b/tests/initial_gen/simple_conditional_output.txt @@ -0,0 +1 @@ +10 \ No newline at end of file diff --git a/tests/initial_gen/simple_input_int.cl b/tests/initial_gen/simple_input_int.cl new file mode 100644 index 000000000..20be946ed --- /dev/null +++ b/tests/initial_gen/simple_input_int.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : IO { + let x: Int <- in_int() in out_int(x) + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/simple_input_int_input.txt b/tests/initial_gen/simple_input_int_input.txt new file mode 100644 index 000000000..1b79f38e2 --- /dev/null +++ b/tests/initial_gen/simple_input_int_input.txt @@ -0,0 +1 @@ +500 diff --git a/tests/initial_gen/simple_input_int_output.txt b/tests/initial_gen/simple_input_int_output.txt new file mode 100644 index 000000000..eb1f49486 --- /dev/null +++ b/tests/initial_gen/simple_input_int_output.txt @@ -0,0 +1 @@ +500 \ No newline at end of file diff --git a/tests/initial_gen/simple_input_string.cl b/tests/initial_gen/simple_input_string.cl new file mode 100644 index 000000000..e290e5153 --- /dev/null +++ b/tests/initial_gen/simple_input_string.cl @@ -0,0 +1,5 @@ +class Main inherits IO { + main() : IO { + let x: String <- in_string() in out_string(x) + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/simple_input_string_input.txt b/tests/initial_gen/simple_input_string_input.txt new file mode 100644 index 000000000..980a0d5f1 --- /dev/null +++ b/tests/initial_gen/simple_input_string_input.txt @@ -0,0 +1 @@ +Hello World! diff --git a/tests/initial_gen/simple_input_string_output.txt b/tests/initial_gen/simple_input_string_output.txt new file mode 100644 index 000000000..c57eff55e --- /dev/null +++ b/tests/initial_gen/simple_input_string_output.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/tests/initial_gen/simple_isvoid.cl b/tests/initial_gen/simple_isvoid.cl new file mode 100644 index 000000000..1a3c2b653 --- /dev/null +++ b/tests/initial_gen/simple_isvoid.cl @@ -0,0 +1,11 @@ +class Main inherits IO { + a : IO; + main() : AUTO_TYPE { + let b: Bool <- isvoid a in + if b then + out_string("True") + else + out_string("False") + fi + }; +}; diff --git a/tests/initial_gen/simple_isvoid_input.txt b/tests/initial_gen/simple_isvoid_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/simple_isvoid_output.txt b/tests/initial_gen/simple_isvoid_output.txt new file mode 100644 index 000000000..4791ed555 --- /dev/null +++ b/tests/initial_gen/simple_isvoid_output.txt @@ -0,0 +1 @@ +True \ No newline at end of file diff --git a/tests/initial_gen/substring.cl b/tests/initial_gen/substring.cl new file mode 100644 index 000000000..ca584d643 --- /dev/null +++ b/tests/initial_gen/substring.cl @@ -0,0 +1,8 @@ +class Main inherits IO +{ + main(): AUTO_TYPE + { + let s:String <- "0123456789" + in out_string(s.substr(3,4)) + }; +}; diff --git a/tests/initial_gen/substring_input.txt b/tests/initial_gen/substring_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/substring_output.txt b/tests/initial_gen/substring_output.txt new file mode 100644 index 000000000..4cab17e44 --- /dev/null +++ b/tests/initial_gen/substring_output.txt @@ -0,0 +1 @@ +3456 \ No newline at end of file diff --git a/tests/initial_gen/type_name.cl b/tests/initial_gen/type_name.cl new file mode 100644 index 000000000..8944f50bc --- /dev/null +++ b/tests/initial_gen/type_name.cl @@ -0,0 +1,7 @@ +class Main inherits IO +{ + main(): AUTO_TYPE + { + out_string(type_name()) + }; +}; diff --git a/tests/initial_gen/type_name_input.txt b/tests/initial_gen/type_name_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/type_name_output.txt b/tests/initial_gen/type_name_output.txt new file mode 100644 index 000000000..1c9bf4968 --- /dev/null +++ b/tests/initial_gen/type_name_output.txt @@ -0,0 +1 @@ +Main \ No newline at end of file diff --git a/tests/initial_gen/value_dispatch.cl b/tests/initial_gen/value_dispatch.cl new file mode 100644 index 000000000..d610b3c91 --- /dev/null +++ b/tests/initial_gen/value_dispatch.cl @@ -0,0 +1,10 @@ +class Main inherits IO { + main() : AUTO_TYPE { + { + out_string(1.type_name()); + out_string(false.type_name()); + out_string(true.type_name()); + true.abort(); + } + }; +}; diff --git a/tests/initial_gen/value_dispatch_input.txt b/tests/initial_gen/value_dispatch_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/value_dispatch_output.txt b/tests/initial_gen/value_dispatch_output.txt new file mode 100644 index 000000000..2892b3949 --- /dev/null +++ b/tests/initial_gen/value_dispatch_output.txt @@ -0,0 +1 @@ +IntBoolBoolAbort called from class Bool diff --git a/tests/initial_gen/while_loop.cl b/tests/initial_gen/while_loop.cl new file mode 100644 index 000000000..bd0afec93 --- /dev/null +++ b/tests/initial_gen/while_loop.cl @@ -0,0 +1,9 @@ +class Main inherits IO { + a: Int <- 10; + main() : AUTO_TYPE { + while not a <= 0 loop { + a <- a - 1; + out_int(a); + } pool + }; +}; \ No newline at end of file diff --git a/tests/initial_gen/while_loop_input.txt b/tests/initial_gen/while_loop_input.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/initial_gen/while_loop_output.txt b/tests/initial_gen/while_loop_output.txt new file mode 100644 index 000000000..919c15914 --- /dev/null +++ b/tests/initial_gen/while_loop_output.txt @@ -0,0 +1 @@ +9876543210 \ No newline at end of file diff --git a/tests/initial_gen_test.py b/tests/initial_gen_test.py new file mode 100644 index 000000000..52c0cdd1b --- /dev/null +++ b/tests/initial_gen_test.py @@ -0,0 +1,19 @@ + +import pytest + +import os +from utils import compare_outputs + +tests_dir = __file__.rpartition('/')[0] + '/initial_gen/' +tests = [(file) for file in os.listdir(tests_dir) if file.endswith('.cl')] + +@pytest.mark.initialgen +@pytest.mark.ok +@pytest.mark.run(order=5) +@pytest.mark.parametrize("cool_file", tests) +def test_initial_gen(compiler_path, cool_file): + compare_outputs(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_input.txt',\ + tests_dir + cool_file[:-3] + '_output.txt', timeout=2) + +# if __name__ == "__main__": +# pytest.main(["-m", "initialgen"]) \ No newline at end of file diff --git a/tests/lexer/comment1.cl b/tests/lexer/comment1.cl index 69533f23c..1b63af3c7 100644 --- a/tests/lexer/comment1.cl +++ b/tests/lexer/comment1.cl @@ -1,55 +1,55 @@ ---Any characters between two dashes “--” and the next newline ---(or EOF, if there is no next newline) are treated as comments - -(*(*(* -Comments may also be written by enclosing -text in (∗ . . . ∗). The latter form of comment may be nested. -Comments cannot cross file boundaries. -*)*)*) - -class Error() { - - (* There was once a comment, - that was quite long. - But, the reader soon discovered that - the comment was indeed longer than - previously assumed. Now, the reader - was in a real dilemma; is the comment - ever gonna end? If I stop reading, will - it end? - He started imagining all sorts of things. - He thought about heisenberg's cat and how - how that relates to the end of the sentence. - He thought to himself "I'm gonna stop reading". - "If I keep reading this comment, I'm gonna know - the fate of this sentence; That will be disastorous." - He knew that such a comment was gonna extend to - another file. It was too awesome to be contained in - a single file. And he would have kept reading too... - if only... - cool wasn't a super-duper-fab-awesomest language; - but cool is that language; - "This comment shall go not cross this file" said cool. - Alas! The reader could read no more. - There was once a comment, - that was quite long. - But, the reader soon discovered that - the comment was indeed longer than - previously assumed. Now, the reader - was in a real dilemma; is the comment - ever gonna end? If I stop reading, will - it end? - He started imagining all sorts of things. - He thought about heisenberg's cat and how - how that relates to the end of the sentence. - He thought to himself "I'm gonna stop reading". - "If I keep reading this comment, I'm gonna know - the fate of this sentence; That will be disastorous." - He knew that such a comment was gonna extend to - another file. It was too awesome to be contained in - a single file. And he would have kept reading too... - if only... - cool wasn't a super-duper-fab-awesomest language; - but cool is that language; - "This comment shall go not cross this file" said cool. +--Any characters between two dashes “--” and the next newline +--(or EOF, if there is no next newline) are treated as comments + +(*(*(* +Comments may also be written by enclosing +text in (∗ . . . ∗). The latter form of comment may be nested. +Comments cannot cross file boundaries. +*)*)*) + +class Error() { + + (* There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. + Alas! The reader could read no more. + There was once a comment, + that was quite long. + But, the reader soon discovered that + the comment was indeed longer than + previously assumed. Now, the reader + was in a real dilemma; is the comment + ever gonna end? If I stop reading, will + it end? + He started imagining all sorts of things. + He thought about heisenberg's cat and how + how that relates to the end of the sentence. + He thought to himself "I'm gonna stop reading". + "If I keep reading this comment, I'm gonna know + the fate of this sentence; That will be disastorous." + He knew that such a comment was gonna extend to + another file. It was too awesome to be contained in + a single file. And he would have kept reading too... + if only... + cool wasn't a super-duper-fab-awesomest language; + but cool is that language; + "This comment shall go not cross this file" said cool. Alas! The reader could read no more. \ No newline at end of file diff --git a/tests/lexer/comment1_error.txt b/tests/lexer/comment1_error.txt index 9fd7b8d67..710483ee9 100644 --- a/tests/lexer/comment1_error.txt +++ b/tests/lexer/comment1_error.txt @@ -1 +1 @@ -(55, 46) - LexicographicError: EOF in comment +(55, 46) - LexicographicError: EOF in comment diff --git a/tests/lexer/iis1.cl b/tests/lexer/iis1.cl index 12cb52beb..ca6b68ac3 100644 --- a/tests/lexer/iis1.cl +++ b/tests/lexer/iis1.cl @@ -1,111 +1,111 @@ -(* Integers, Identifiers, and Special Notation *) - -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ -5! = 120, 2 + 2 = 5 or E = mc2; p + 1 @ p = 1: for x in range(len(b)) -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) -class Class if then else fi testing Testing ~007agent_bond james_007B0N3SS___ -loop pool while tRuE or noT faLsE let in case of ESAC - -(* -#3 INT_CONST 0007 -#3 INT_CONST 123 -#3 '+' -#3 INT_CONST 1 -#3 '-' -#3 INT_CONST 1 -#3 '+' -#3 INT_CONST 90 -#3 '-' -#3 INT_CONST 09 -#3 '+' -#3 INT_CONST 11113 -#3 '-' -#3 INT_CONST 4 -#3 OBJECTID r -#3 '*' -#3 OBJECTID a -#3 '*' -#3 OBJECTID self -#3 '*' -#3 OBJECTID c -#3 '+' -#3 '+' -#4 INT_CONST 5 -#4 ERROR "!" -#4 '=' -#4 INT_CONST 120 -#4 ',' -#4 INT_CONST 2 -#4 '+' -#4 INT_CONST 2 -#4 '=' -#4 INT_CONST 5 -#4 OBJECTID or -#4 TYPEID E -#4 '=' -#4 OBJECTID mc2 -#4 ';' -#4 OBJECTID p -#4 '+' -#4 INT_CONST 1 -#4 '@' -#4 OBJECTID p -#4 '=' -#4 INT_CONST 1 -#4 ':' -#4 OBJECTID for -#4 OBJECTID x -#4 IN -#4 OBJECTID range -#4 '(' -#4 OBJECTID len -#4 '(' -#4 OBJECTID b -#4 ')' -#4 ')' -#5 NEW -#5 '/' -#5 ASSIGN -#5 '<' -#5 LE -#5 DARROW -#5 '{' -#5 '(' -#5 TYPEID Int -#5 ':' -#5 TYPEID Objet -#5 ',' -#5 TYPEID Bool -#5 ';' -#5 TYPEID String -#5 '.' -#5 OBJECTID string -#5 TYPEID SELF_TYPE -#5 ISVOID -#5 '}' -#5 ')' -#6 CLASS -#6 CLASS -#6 IF -#6 THEN -#6 ELSE -#6 FI -#6 OBJECTID testing -#6 TYPEID Testing -#6 '~' -#6 INT_CONST 007 -#6 OBJECTID agent_bond -#6 OBJECTID james_007B0N3SS___ -#7 LOOP -#7 POOL -#7 WHILE -#7 BOOL_CONST true -#7 OBJECTID or -#7 NOT -#7 BOOL_CONST false -#7 LET -#7 IN -#7 CASE -#7 OF -#7 ESAC +(* Integers, Identifiers, and Special Notation *) + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +5! = 120, 2 + 2 = 5 or E = mc2; p + 1 @ p = 1: for x in range(len(b)) +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +class Class if then else fi testing Testing ~007agent_bond james_007B0N3SS___ +loop pool while tRuE or noT faLsE let in case of ESAC + +(* +#3 INT_CONST 0007 +#3 INT_CONST 123 +#3 '+' +#3 INT_CONST 1 +#3 '-' +#3 INT_CONST 1 +#3 '+' +#3 INT_CONST 90 +#3 '-' +#3 INT_CONST 09 +#3 '+' +#3 INT_CONST 11113 +#3 '-' +#3 INT_CONST 4 +#3 OBJECTID r +#3 '*' +#3 OBJECTID a +#3 '*' +#3 OBJECTID self +#3 '*' +#3 OBJECTID c +#3 '+' +#3 '+' +#4 INT_CONST 5 +#4 ERROR "!" +#4 '=' +#4 INT_CONST 120 +#4 ',' +#4 INT_CONST 2 +#4 '+' +#4 INT_CONST 2 +#4 '=' +#4 INT_CONST 5 +#4 OBJECTID or +#4 TYPEID E +#4 '=' +#4 OBJECTID mc2 +#4 ';' +#4 OBJECTID p +#4 '+' +#4 INT_CONST 1 +#4 '@' +#4 OBJECTID p +#4 '=' +#4 INT_CONST 1 +#4 ':' +#4 OBJECTID for +#4 OBJECTID x +#4 IN +#4 OBJECTID range +#4 '(' +#4 OBJECTID len +#4 '(' +#4 OBJECTID b +#4 ')' +#4 ')' +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#6 CLASS +#6 CLASS +#6 IF +#6 THEN +#6 ELSE +#6 FI +#6 OBJECTID testing +#6 TYPEID Testing +#6 '~' +#6 INT_CONST 007 +#6 OBJECTID agent_bond +#6 OBJECTID james_007B0N3SS___ +#7 LOOP +#7 POOL +#7 WHILE +#7 BOOL_CONST true +#7 OBJECTID or +#7 NOT +#7 BOOL_CONST false +#7 LET +#7 IN +#7 CASE +#7 OF +#7 ESAC *) \ No newline at end of file diff --git a/tests/lexer/iis1_error.txt b/tests/lexer/iis1_error.txt index 9e6d66cac..12f62f1ba 100644 --- a/tests/lexer/iis1_error.txt +++ b/tests/lexer/iis1_error.txt @@ -1 +1 @@ -(4, 2) - LexicographicError: ERROR "!" +(4, 2) - LexicographicError: ERROR "!" diff --git a/tests/lexer/iis2.cl b/tests/lexer/iis2.cl index 9b25715d4..d42552494 100644 --- a/tests/lexer/iis2.cl +++ b/tests/lexer/iis2.cl @@ -1,120 +1,120 @@ -(* Integers, Identifiers, and Special Notation *) - -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ -class Class if then else fi testing Testing ~007agent_bond james_007bones___ - - -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) -loop pool while tRuE or noT faLsE let in case of ESAC - -factorial(5) = 120, 2 + 2 = 5? or E = mc2; p + 1 resto p = 1: (@ for x in range(len(b))) - -(* -#3 INT_CONST 0007 -#3 INT_CONST 123 -#3 '+' -#3 INT_CONST 1 -#3 '-' -#3 INT_CONST 1 -#3 '+' -#3 INT_CONST 90 -#3 '-' -#3 INT_CONST 09 -#3 '+' -#3 INT_CONST 11113 -#3 '-' -#3 INT_CONST 4 -#3 OBJECTID r -#3 '*' -#3 OBJECTID a -#3 '*' -#3 OBJECTID self -#3 '*' -#3 OBJECTID c -#3 '+' -#3 '+' -#4 CLASS -#4 CLASS -#4 IF -#4 THEN -#4 ELSE -#4 FI -#4 OBJECTID testing -#4 TYPEID Testing -#4 '~' -#4 INT_CONST 007 -#4 OBJECTID agent_bond -#4 OBJECTID james_007bones___ -#7 NEW -#7 '/' -#7 ASSIGN -#7 '<' -#7 LE -#7 DARROW -#7 '{' -#7 '(' -#7 TYPEID Int -#7 ':' -#7 TYPEID Objet -#7 ',' -#7 TYPEID Bool -#7 ';' -#7 TYPEID String -#7 '.' -#7 OBJECTID string -#7 TYPEID SELF_TYPE -#7 ISVOID -#7 '}' -#7 ')' -#8 LOOP -#8 POOL -#8 WHILE -#8 BOOL_CONST true -#8 OBJECTID or -#8 NOT -#8 BOOL_CONST false -#8 LET -#8 IN -#8 CASE -#8 OF -#8 ESAC -#10 OBJECTID factorial -#10 '(' -#10 INT_CONST 5 -#10 ')' -#10 '=' -#10 INT_CONST 120 -#10 ',' -#10 INT_CONST 2 -#10 '+' -#10 INT_CONST 2 -#10 '=' -#10 INT_CONST 5 -#10 ERROR "?" -#10 OBJECTID or -#10 TYPEID E -#10 '=' -#10 OBJECTID mc2 -#10 ';' -#10 OBJECTID p -#10 '+' -#10 INT_CONST 1 -#10 OBJECTID resto -#10 OBJECTID p -#10 '=' -#10 INT_CONST 1 -#10 ':' -#10 '(' -#10 '@' -#10 OBJECTID for -#10 OBJECTID x -#10 IN -#10 OBJECTID range -#10 '(' -#10 OBJECTID len -#10 '(' -#10 OBJECTID b -#10 ')' -#10 ')' -#10 ')' +(* Integers, Identifiers, and Special Notation *) + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +loop pool while tRuE or noT faLsE let in case of ESAC + +factorial(5) = 120, 2 + 2 = 5? or E = mc2; p + 1 resto p = 1: (@ for x in range(len(b))) + +(* +#3 INT_CONST 0007 +#3 INT_CONST 123 +#3 '+' +#3 INT_CONST 1 +#3 '-' +#3 INT_CONST 1 +#3 '+' +#3 INT_CONST 90 +#3 '-' +#3 INT_CONST 09 +#3 '+' +#3 INT_CONST 11113 +#3 '-' +#3 INT_CONST 4 +#3 OBJECTID r +#3 '*' +#3 OBJECTID a +#3 '*' +#3 OBJECTID self +#3 '*' +#3 OBJECTID c +#3 '+' +#3 '+' +#4 CLASS +#4 CLASS +#4 IF +#4 THEN +#4 ELSE +#4 FI +#4 OBJECTID testing +#4 TYPEID Testing +#4 '~' +#4 INT_CONST 007 +#4 OBJECTID agent_bond +#4 OBJECTID james_007bones___ +#7 NEW +#7 '/' +#7 ASSIGN +#7 '<' +#7 LE +#7 DARROW +#7 '{' +#7 '(' +#7 TYPEID Int +#7 ':' +#7 TYPEID Objet +#7 ',' +#7 TYPEID Bool +#7 ';' +#7 TYPEID String +#7 '.' +#7 OBJECTID string +#7 TYPEID SELF_TYPE +#7 ISVOID +#7 '}' +#7 ')' +#8 LOOP +#8 POOL +#8 WHILE +#8 BOOL_CONST true +#8 OBJECTID or +#8 NOT +#8 BOOL_CONST false +#8 LET +#8 IN +#8 CASE +#8 OF +#8 ESAC +#10 OBJECTID factorial +#10 '(' +#10 INT_CONST 5 +#10 ')' +#10 '=' +#10 INT_CONST 120 +#10 ',' +#10 INT_CONST 2 +#10 '+' +#10 INT_CONST 2 +#10 '=' +#10 INT_CONST 5 +#10 ERROR "?" +#10 OBJECTID or +#10 TYPEID E +#10 '=' +#10 OBJECTID mc2 +#10 ';' +#10 OBJECTID p +#10 '+' +#10 INT_CONST 1 +#10 OBJECTID resto +#10 OBJECTID p +#10 '=' +#10 INT_CONST 1 +#10 ':' +#10 '(' +#10 '@' +#10 OBJECTID for +#10 OBJECTID x +#10 IN +#10 OBJECTID range +#10 '(' +#10 OBJECTID len +#10 '(' +#10 OBJECTID b +#10 ')' +#10 ')' +#10 ')' *) \ No newline at end of file diff --git a/tests/lexer/iis2_error.txt b/tests/lexer/iis2_error.txt index 922391a9d..988d0286e 100644 --- a/tests/lexer/iis2_error.txt +++ b/tests/lexer/iis2_error.txt @@ -1 +1 @@ -(10, 30) - LexicographicError: ERROR "?" +(10, 30) - LexicographicError: ERROR "?" diff --git a/tests/lexer/iis3.cl b/tests/lexer/iis3.cl index 0b965ddea..dcd85f960 100644 --- a/tests/lexer/iis3.cl +++ b/tests/lexer/iis3.cl @@ -1,121 +1,121 @@ -(* Integers, Identifiers, and Special Notation *) - -factorial(5) = 120, 2 + 2 = 5 or E = mc^2; p + 1 @ p = 1: z for x in range(len(b))) - -loop pool while tRuE or noT faLsE let in case of ESAC - -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) - - -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ -class Class if then else fi testing Testing ~007agent_bond james_007bones___ - -(* -#3 OBJECTID factorial -#3 '(' -#3 INT_CONST 5 -#3 ')' -#3 '=' -#3 INT_CONST 120 -#3 ',' -#3 INT_CONST 2 -#3 '+' -#3 INT_CONST 2 -#3 '=' -#3 INT_CONST 5 -#3 OBJECTID or -#3 TYPEID E -#3 '=' -#3 OBJECTID mc -#3 ERROR "^" -#3 INT_CONST 2 -#3 ';' -#3 OBJECTID p -#3 '+' -#3 INT_CONST 1 -#3 '@' -#3 OBJECTID p -#3 '=' -#3 INT_CONST 1 -#3 ':' -#3 OBJECTID z -#3 OBJECTID for -#3 OBJECTID x -#3 IN -#3 OBJECTID range -#3 '(' -#3 OBJECTID len -#3 '(' -#3 OBJECTID b -#3 ')' -#3 ')' -#3 ')' -#5 LOOP -#5 POOL -#5 WHILE -#5 BOOL_CONST true -#5 OBJECTID or -#5 NOT -#5 BOOL_CONST false -#5 LET -#5 IN -#5 CASE -#5 OF -#5 ESAC -#7 NEW -#7 '/' -#7 ASSIGN -#7 '<' -#7 LE -#7 DARROW -#7 '{' -#7 '(' -#7 TYPEID Int -#7 ':' -#7 TYPEID Objet -#7 ',' -#7 TYPEID Bool -#7 ';' -#7 TYPEID String -#7 '.' -#7 OBJECTID string -#7 TYPEID SELF_TYPE -#7 ISVOID -#7 '}' -#7 ')' -#10 INT_CONST 0007 -#10 INT_CONST 123 -#10 '+' -#10 INT_CONST 1 -#10 '-' -#10 INT_CONST 1 -#10 '+' -#10 INT_CONST 90 -#10 '-' -#10 INT_CONST 09 -#10 '+' -#10 INT_CONST 11113 -#10 '-' -#10 INT_CONST 4 -#10 OBJECTID r -#10 '*' -#10 OBJECTID a -#10 '*' -#10 OBJECTID self -#10 '*' -#10 OBJECTID c -#10 '+' -#10 '+' -#11 CLASS -#11 CLASS -#11 IF -#11 THEN -#11 ELSE -#11 FI -#11 OBJECTID testing -#11 TYPEID Testing -#11 '~' -#11 INT_CONST 007 -#11 OBJECTID agent_bond -#11 OBJECTID james_007bones___ +(* Integers, Identifiers, and Special Notation *) + +factorial(5) = 120, 2 + 2 = 5 or E = mc^2; p + 1 @ p = 1: z for x in range(len(b))) + +loop pool while tRuE or noT faLsE let in case of ESAC + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) + + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +(* +#3 OBJECTID factorial +#3 '(' +#3 INT_CONST 5 +#3 ')' +#3 '=' +#3 INT_CONST 120 +#3 ',' +#3 INT_CONST 2 +#3 '+' +#3 INT_CONST 2 +#3 '=' +#3 INT_CONST 5 +#3 OBJECTID or +#3 TYPEID E +#3 '=' +#3 OBJECTID mc +#3 ERROR "^" +#3 INT_CONST 2 +#3 ';' +#3 OBJECTID p +#3 '+' +#3 INT_CONST 1 +#3 '@' +#3 OBJECTID p +#3 '=' +#3 INT_CONST 1 +#3 ':' +#3 OBJECTID z +#3 OBJECTID for +#3 OBJECTID x +#3 IN +#3 OBJECTID range +#3 '(' +#3 OBJECTID len +#3 '(' +#3 OBJECTID b +#3 ')' +#3 ')' +#3 ')' +#5 LOOP +#5 POOL +#5 WHILE +#5 BOOL_CONST true +#5 OBJECTID or +#5 NOT +#5 BOOL_CONST false +#5 LET +#5 IN +#5 CASE +#5 OF +#5 ESAC +#7 NEW +#7 '/' +#7 ASSIGN +#7 '<' +#7 LE +#7 DARROW +#7 '{' +#7 '(' +#7 TYPEID Int +#7 ':' +#7 TYPEID Objet +#7 ',' +#7 TYPEID Bool +#7 ';' +#7 TYPEID String +#7 '.' +#7 OBJECTID string +#7 TYPEID SELF_TYPE +#7 ISVOID +#7 '}' +#7 ')' +#10 INT_CONST 0007 +#10 INT_CONST 123 +#10 '+' +#10 INT_CONST 1 +#10 '-' +#10 INT_CONST 1 +#10 '+' +#10 INT_CONST 90 +#10 '-' +#10 INT_CONST 09 +#10 '+' +#10 INT_CONST 11113 +#10 '-' +#10 INT_CONST 4 +#10 OBJECTID r +#10 '*' +#10 OBJECTID a +#10 '*' +#10 OBJECTID self +#10 '*' +#10 OBJECTID c +#10 '+' +#10 '+' +#11 CLASS +#11 CLASS +#11 IF +#11 THEN +#11 ELSE +#11 FI +#11 OBJECTID testing +#11 TYPEID Testing +#11 '~' +#11 INT_CONST 007 +#11 OBJECTID agent_bond +#11 OBJECTID james_007bones___ *) \ No newline at end of file diff --git a/tests/lexer/iis3_error.txt b/tests/lexer/iis3_error.txt index b001b6a71..3abc2b556 100644 --- a/tests/lexer/iis3_error.txt +++ b/tests/lexer/iis3_error.txt @@ -1 +1 @@ -(3, 40) - LexicographicError: ERROR "^" +(3, 40) - LexicographicError: ERROR "^" diff --git a/tests/lexer/iis4.cl b/tests/lexer/iis4.cl index 9e7a9cb62..5357ab734 100644 --- a/tests/lexer/iis4.cl +++ b/tests/lexer/iis4.cl @@ -1,120 +1,120 @@ -(* Integers, Identifiers, and Special Notation *) - -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ - -factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 % p = 1: @.@ for x in range(len(b))~ - - -loop pool while tRuE or noT faLsE let in case of ESAC -class Class if then else fi testing Testing ~007agent_bond james_007bones___ - -(* -#3 NEW -#3 '/' -#3 ASSIGN -#3 '<' -#3 LE -#3 DARROW -#3 '{' -#3 '(' -#3 TYPEID Int -#3 ':' -#3 TYPEID Objet -#3 ',' -#3 TYPEID Bool -#3 ';' -#3 TYPEID String -#3 '.' -#3 OBJECTID string -#3 TYPEID SELF_TYPE -#3 ISVOID -#3 '}' -#3 ')' -#4 INT_CONST 0007 -#4 INT_CONST 123 -#4 '+' -#4 INT_CONST 1 -#4 '-' -#4 INT_CONST 1 -#4 '+' -#4 INT_CONST 90 -#4 '-' -#4 INT_CONST 09 -#4 '+' -#4 INT_CONST 11113 -#4 '-' -#4 INT_CONST 4 -#4 OBJECTID r -#4 '*' -#4 OBJECTID a -#4 '*' -#4 OBJECTID self -#4 '*' -#4 OBJECTID c -#4 '+' -#4 '+' -#6 OBJECTID factorial -#6 '(' -#6 INT_CONST 5 -#6 ')' -#6 '=' -#6 INT_CONST 120 -#6 ',' -#6 INT_CONST 2 -#6 '+' -#6 INT_CONST 2 -#6 '=' -#6 INT_CONST 5 -#6 OBJECTID or -#6 TYPEID E -#6 '=' -#6 OBJECTID mc2 -#6 ';' -#6 OBJECTID p -#6 '+' -#6 INT_CONST 1 -#6 ERROR "%" -#6 OBJECTID p -#6 '=' -#6 INT_CONST 1 -#6 ':' -#6 '@' -#6 '.' -#6 '@' -#6 OBJECTID for -#6 OBJECTID x -#6 IN -#6 OBJECTID range -#6 '(' -#6 OBJECTID len -#6 '(' -#6 OBJECTID b -#6 ')' -#6 ')' -#6 '~' -#9 LOOP -#9 POOL -#9 WHILE -#9 BOOL_CONST true -#9 OBJECTID or -#9 NOT -#9 BOOL_CONST false -#9 LET -#9 IN -#9 CASE -#9 OF -#9 ESAC -#10 CLASS -#10 CLASS -#10 IF -#10 THEN -#10 ELSE -#10 FI -#10 OBJECTID testing -#10 TYPEID Testing -#10 '~' -#10 INT_CONST 007 -#10 OBJECTID agent_bond -#10 OBJECTID james_007bones___ +(* Integers, Identifiers, and Special Notation *) + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 % p = 1: @.@ for x in range(len(b))~ + + +loop pool while tRuE or noT faLsE let in case of ESAC +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +(* +#3 NEW +#3 '/' +#3 ASSIGN +#3 '<' +#3 LE +#3 DARROW +#3 '{' +#3 '(' +#3 TYPEID Int +#3 ':' +#3 TYPEID Objet +#3 ',' +#3 TYPEID Bool +#3 ';' +#3 TYPEID String +#3 '.' +#3 OBJECTID string +#3 TYPEID SELF_TYPE +#3 ISVOID +#3 '}' +#3 ')' +#4 INT_CONST 0007 +#4 INT_CONST 123 +#4 '+' +#4 INT_CONST 1 +#4 '-' +#4 INT_CONST 1 +#4 '+' +#4 INT_CONST 90 +#4 '-' +#4 INT_CONST 09 +#4 '+' +#4 INT_CONST 11113 +#4 '-' +#4 INT_CONST 4 +#4 OBJECTID r +#4 '*' +#4 OBJECTID a +#4 '*' +#4 OBJECTID self +#4 '*' +#4 OBJECTID c +#4 '+' +#4 '+' +#6 OBJECTID factorial +#6 '(' +#6 INT_CONST 5 +#6 ')' +#6 '=' +#6 INT_CONST 120 +#6 ',' +#6 INT_CONST 2 +#6 '+' +#6 INT_CONST 2 +#6 '=' +#6 INT_CONST 5 +#6 OBJECTID or +#6 TYPEID E +#6 '=' +#6 OBJECTID mc2 +#6 ';' +#6 OBJECTID p +#6 '+' +#6 INT_CONST 1 +#6 ERROR "%" +#6 OBJECTID p +#6 '=' +#6 INT_CONST 1 +#6 ':' +#6 '@' +#6 '.' +#6 '@' +#6 OBJECTID for +#6 OBJECTID x +#6 IN +#6 OBJECTID range +#6 '(' +#6 OBJECTID len +#6 '(' +#6 OBJECTID b +#6 ')' +#6 ')' +#6 '~' +#9 LOOP +#9 POOL +#9 WHILE +#9 BOOL_CONST true +#9 OBJECTID or +#9 NOT +#9 BOOL_CONST false +#9 LET +#9 IN +#9 CASE +#9 OF +#9 ESAC +#10 CLASS +#10 CLASS +#10 IF +#10 THEN +#10 ELSE +#10 FI +#10 OBJECTID testing +#10 TYPEID Testing +#10 '~' +#10 INT_CONST 007 +#10 OBJECTID agent_bond +#10 OBJECTID james_007bones___ *) \ No newline at end of file diff --git a/tests/lexer/iis4_error.txt b/tests/lexer/iis4_error.txt index f24076a8c..aab8f39c1 100644 --- a/tests/lexer/iis4_error.txt +++ b/tests/lexer/iis4_error.txt @@ -1 +1 @@ -(6, 49) - LexicographicError: ERROR "!" +(6, 49) - LexicographicError: ERROR "!" diff --git a/tests/lexer/iis5.cl b/tests/lexer/iis5.cl index d146c0547..f602488b9 100644 --- a/tests/lexer/iis5.cl +++ b/tests/lexer/iis5.cl @@ -1,121 +1,121 @@ -(* Integers, Identifiers, and Special Notation *) - - -loop pool while tRuE or noT faLsE let in case of ESAC -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) -class Class if then else fi testing Testing ~007agent_bond james_007bones___ - -factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: [@.@ for x in range(len(b))] - -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ - -(* -#4 LOOP -#4 POOL -#4 WHILE -#4 BOOL_CONST true -#4 OBJECTID or -#4 NOT -#4 BOOL_CONST false -#4 LET -#4 IN -#4 CASE -#4 OF -#4 ESAC -#5 NEW -#5 '/' -#5 ASSIGN -#5 '<' -#5 LE -#5 DARROW -#5 '{' -#5 '(' -#5 TYPEID Int -#5 ':' -#5 TYPEID Objet -#5 ',' -#5 TYPEID Bool -#5 ';' -#5 TYPEID String -#5 '.' -#5 OBJECTID string -#5 TYPEID SELF_TYPE -#5 ISVOID -#5 '}' -#5 ')' -#6 CLASS -#6 CLASS -#6 IF -#6 THEN -#6 ELSE -#6 FI -#6 OBJECTID testing -#6 TYPEID Testing -#6 '~' -#6 INT_CONST 007 -#6 OBJECTID agent_bond -#6 OBJECTID james_007bones___ -#8 OBJECTID factorial -#8 '(' -#8 INT_CONST 5 -#8 ')' -#8 '=' -#8 INT_CONST 120 -#8 ',' -#8 INT_CONST 2 -#8 '+' -#8 INT_CONST 2 -#8 '=' -#8 INT_CONST 5 -#8 OBJECTID or -#8 TYPEID E -#8 '=' -#8 OBJECTID mc2 -#8 ';' -#8 OBJECTID p -#8 '+' -#8 INT_CONST 1 -#8 OBJECTID resto -#8 OBJECTID p -#8 '=' -#8 INT_CONST 1 -#8 ':' -#8 ERROR "[" -#8 '@' -#8 '.' -#8 '@' -#8 OBJECTID for -#8 OBJECTID x -#8 IN -#8 OBJECTID range -#8 '(' -#8 OBJECTID len -#8 '(' -#8 OBJECTID b -#8 ')' -#8 ')' -#8 ERROR "]" -#10 INT_CONST 0007 -#10 INT_CONST 123 -#10 '+' -#10 INT_CONST 1 -#10 '-' -#10 INT_CONST 1 -#10 '+' -#10 INT_CONST 90 -#10 '-' -#10 INT_CONST 09 -#10 '+' -#10 INT_CONST 11113 -#10 '-' -#10 INT_CONST 4 -#10 OBJECTID r -#10 '*' -#10 OBJECTID a -#10 '*' -#10 OBJECTID self -#10 '*' -#10 OBJECTID c -#10 '+' -#10 '+' -*) +(* Integers, Identifiers, and Special Notation *) + + +loop pool while tRuE or noT faLsE let in case of ESAC +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) +class Class if then else fi testing Testing ~007agent_bond james_007bones___ + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: [@.@ for x in range(len(b))] + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ + +(* +#4 LOOP +#4 POOL +#4 WHILE +#4 BOOL_CONST true +#4 OBJECTID or +#4 NOT +#4 BOOL_CONST false +#4 LET +#4 IN +#4 CASE +#4 OF +#4 ESAC +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#6 CLASS +#6 CLASS +#6 IF +#6 THEN +#6 ELSE +#6 FI +#6 OBJECTID testing +#6 TYPEID Testing +#6 '~' +#6 INT_CONST 007 +#6 OBJECTID agent_bond +#6 OBJECTID james_007bones___ +#8 OBJECTID factorial +#8 '(' +#8 INT_CONST 5 +#8 ')' +#8 '=' +#8 INT_CONST 120 +#8 ',' +#8 INT_CONST 2 +#8 '+' +#8 INT_CONST 2 +#8 '=' +#8 INT_CONST 5 +#8 OBJECTID or +#8 TYPEID E +#8 '=' +#8 OBJECTID mc2 +#8 ';' +#8 OBJECTID p +#8 '+' +#8 INT_CONST 1 +#8 OBJECTID resto +#8 OBJECTID p +#8 '=' +#8 INT_CONST 1 +#8 ':' +#8 ERROR "[" +#8 '@' +#8 '.' +#8 '@' +#8 OBJECTID for +#8 OBJECTID x +#8 IN +#8 OBJECTID range +#8 '(' +#8 OBJECTID len +#8 '(' +#8 OBJECTID b +#8 ')' +#8 ')' +#8 ERROR "]" +#10 INT_CONST 0007 +#10 INT_CONST 123 +#10 '+' +#10 INT_CONST 1 +#10 '-' +#10 INT_CONST 1 +#10 '+' +#10 INT_CONST 90 +#10 '-' +#10 INT_CONST 09 +#10 '+' +#10 INT_CONST 11113 +#10 '-' +#10 INT_CONST 4 +#10 OBJECTID r +#10 '*' +#10 OBJECTID a +#10 '*' +#10 OBJECTID self +#10 '*' +#10 OBJECTID c +#10 '+' +#10 '+' +*) diff --git a/tests/lexer/iis5_error.txt b/tests/lexer/iis5_error.txt index b3dbadcb6..9d6e1a738 100644 --- a/tests/lexer/iis5_error.txt +++ b/tests/lexer/iis5_error.txt @@ -1,2 +1,2 @@ -(8, 62) - LexicographicError: ERROR "[" -(8, 89) - LexicographicError: ERROR "]" +(8, 62) - LexicographicError: ERROR "[" +(8, 89) - LexicographicError: ERROR "]" diff --git a/tests/lexer/iis6.cl b/tests/lexer/iis6.cl index 1042f132b..ba93b19d9 100644 --- a/tests/lexer/iis6.cl +++ b/tests/lexer/iis6.cl @@ -1,125 +1,125 @@ -(* Integers, Identifiers, and Special Notation *) - -factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: {@.@ for x in range(len(b))} - -new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) - - -class Class if then else fi testing Testing ~007agent_bond _james_007bones___ - - - -0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ -loop pool while tRuE or noT faLsE let in case of ESAC - -(* -#3 OBJECTID factorial -#3 '(' -#3 INT_CONST 5 -#3 ')' -#3 '=' -#3 INT_CONST 120 -#3 ',' -#3 INT_CONST 2 -#3 '+' -#3 INT_CONST 2 -#3 '=' -#3 INT_CONST 5 -#3 OBJECTID or -#3 TYPEID E -#3 '=' -#3 OBJECTID mc2 -#3 ';' -#3 OBJECTID p -#3 '+' -#3 INT_CONST 1 -#3 OBJECTID resto -#3 OBJECTID p -#3 '=' -#3 INT_CONST 1 -#3 ':' -#3 '{' -#3 '@' -#3 '.' -#3 '@' -#3 OBJECTID for -#3 OBJECTID x -#3 IN -#3 OBJECTID range -#3 '(' -#3 OBJECTID len -#3 '(' -#3 OBJECTID b -#3 ')' -#3 ')' -#3 '}' -#5 NEW -#5 '/' -#5 ASSIGN -#5 '<' -#5 LE -#5 DARROW -#5 '{' -#5 '(' -#5 TYPEID Int -#5 ':' -#5 TYPEID Objet -#5 ',' -#5 TYPEID Bool -#5 ';' -#5 TYPEID String -#5 '.' -#5 OBJECTID string -#5 TYPEID SELF_TYPE -#5 ISVOID -#5 '}' -#5 ')' -#8 CLASS -#8 CLASS -#8 IF -#8 THEN -#8 ELSE -#8 FI -#8 OBJECTID testing -#8 TYPEID Testing -#8 '~' -#8 INT_CONST 007 -#8 OBJECTID agent_bond -#8 ERROR "_" -#8 OBJECTID james_007bones___ -#12 INT_CONST 0007 -#12 INT_CONST 123 -#12 '+' -#12 INT_CONST 1 -#12 '-' -#12 INT_CONST 1 -#12 '+' -#12 INT_CONST 90 -#12 '-' -#12 INT_CONST 09 -#12 '+' -#12 INT_CONST 11113 -#12 '-' -#12 INT_CONST 4 -#12 OBJECTID r -#12 '*' -#12 OBJECTID a -#12 '*' -#12 OBJECTID self -#12 '*' -#12 OBJECTID c -#12 '+' -#12 '+' -#13 LOOP -#13 POOL -#13 WHILE -#13 BOOL_CONST true -#13 OBJECTID or -#13 NOT -#13 BOOL_CONST false -#13 LET -#13 IN -#13 CASE -#13 OF -#13 ESAC +(* Integers, Identifiers, and Special Notation *) + +factorial(5) = 120, 2 + 2 = 5 or E = mc2; p + 1 resto p = 1: {@.@ for x in range(len(b))} + +new / <- <<==> {( Int: Objet, Bool; String.string SELF_TYPE isvoid }) + + +class Class if then else fi testing Testing ~007agent_bond _james_007bones___ + + + +0007 123 +1 -1 +90 -09 +11113 -4r *a *self* c++ +loop pool while tRuE or noT faLsE let in case of ESAC + +(* +#3 OBJECTID factorial +#3 '(' +#3 INT_CONST 5 +#3 ')' +#3 '=' +#3 INT_CONST 120 +#3 ',' +#3 INT_CONST 2 +#3 '+' +#3 INT_CONST 2 +#3 '=' +#3 INT_CONST 5 +#3 OBJECTID or +#3 TYPEID E +#3 '=' +#3 OBJECTID mc2 +#3 ';' +#3 OBJECTID p +#3 '+' +#3 INT_CONST 1 +#3 OBJECTID resto +#3 OBJECTID p +#3 '=' +#3 INT_CONST 1 +#3 ':' +#3 '{' +#3 '@' +#3 '.' +#3 '@' +#3 OBJECTID for +#3 OBJECTID x +#3 IN +#3 OBJECTID range +#3 '(' +#3 OBJECTID len +#3 '(' +#3 OBJECTID b +#3 ')' +#3 ')' +#3 '}' +#5 NEW +#5 '/' +#5 ASSIGN +#5 '<' +#5 LE +#5 DARROW +#5 '{' +#5 '(' +#5 TYPEID Int +#5 ':' +#5 TYPEID Objet +#5 ',' +#5 TYPEID Bool +#5 ';' +#5 TYPEID String +#5 '.' +#5 OBJECTID string +#5 TYPEID SELF_TYPE +#5 ISVOID +#5 '}' +#5 ')' +#8 CLASS +#8 CLASS +#8 IF +#8 THEN +#8 ELSE +#8 FI +#8 OBJECTID testing +#8 TYPEID Testing +#8 '~' +#8 INT_CONST 007 +#8 OBJECTID agent_bond +#8 ERROR "_" +#8 OBJECTID james_007bones___ +#12 INT_CONST 0007 +#12 INT_CONST 123 +#12 '+' +#12 INT_CONST 1 +#12 '-' +#12 INT_CONST 1 +#12 '+' +#12 INT_CONST 90 +#12 '-' +#12 INT_CONST 09 +#12 '+' +#12 INT_CONST 11113 +#12 '-' +#12 INT_CONST 4 +#12 OBJECTID r +#12 '*' +#12 OBJECTID a +#12 '*' +#12 OBJECTID self +#12 '*' +#12 OBJECTID c +#12 '+' +#12 '+' +#13 LOOP +#13 POOL +#13 WHILE +#13 BOOL_CONST true +#13 OBJECTID or +#13 NOT +#13 BOOL_CONST false +#13 LET +#13 IN +#13 CASE +#13 OF +#13 ESAC *) \ No newline at end of file diff --git a/tests/lexer/iis6_error.txt b/tests/lexer/iis6_error.txt index d7fad9c79..79a9d5aee 100644 --- a/tests/lexer/iis6_error.txt +++ b/tests/lexer/iis6_error.txt @@ -1 +1 @@ -(8, 60) - LexicographicError: ERROR "_" +(8, 60) - LexicographicError: ERROR "_" diff --git a/tests/lexer/mixed1.cl b/tests/lexer/mixed1.cl index 803d58ef5..d3e520a10 100644 --- a/tests/lexer/mixed1.cl +++ b/tests/lexer/mixed1.cl @@ -1,14 +1,14 @@ -"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 -adsfasklj# -LKldsajf iNhERITS -"lkdsajf" - -(* -#1 STR_CONST "lkjdsafkljdsalfju0000dsafdsafu0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl" -#1 INT_CONST 123 -#2 OBJECTID adsfasklj -#2 ERROR "#" -#3 TYPEID LKldsajf -#3 INHERITS -#4 STR_CONST "lkdsajf" +"lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 +adsfasklj# +LKldsajf iNhERITS +"lkdsajf" + +(* +#1 STR_CONST "lkjdsafkljdsalfju0000dsafdsafu0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl" +#1 INT_CONST 123 +#2 OBJECTID adsfasklj +#2 ERROR "#" +#3 TYPEID LKldsajf +#3 INHERITS +#4 STR_CONST "lkdsajf" *) \ No newline at end of file diff --git a/tests/lexer/mixed1_error.txt b/tests/lexer/mixed1_error.txt index 99af5fbdc..a142c2edd 100644 --- a/tests/lexer/mixed1_error.txt +++ b/tests/lexer/mixed1_error.txt @@ -1 +1 @@ -(2, 10) - LexicographicError: ERROR "#" +(2, 10) - LexicographicError: ERROR "#" diff --git a/tests/lexer/mixed2.cl b/tests/lexer/mixed2.cl index 12039e123..759bf9523 100644 --- a/tests/lexer/mixed2.cl +++ b/tests/lexer/mixed2.cl @@ -1,20 +1,20 @@ -"kjas\"lnnsdj\nfljrdsaf" -@.$.@ -@*%*@ -"alkjfldajf""dasfadsf - -(* -#1 STR_CONST "kjas\"lnnsdj\nfljrdsaf" -#2 '@' -#2 '.' -#2 ERROR "$" -#2 '.' -#2 '@' -#3 '@' -#3 '*' -#3 ERROR "%" -#3 '*' -#3 '@' -#4 STR_CONST "alkjfldajf" -#4 ERROR "Unterminated string constant" +"kjas\"lnnsdj\nfljrdsaf" +@.$.@ +@*%*@ +"alkjfldajf""dasfadsf + +(* +#1 STR_CONST "kjas\"lnnsdj\nfljrdsaf" +#2 '@' +#2 '.' +#2 ERROR "$" +#2 '.' +#2 '@' +#3 '@' +#3 '*' +#3 ERROR "%" +#3 '*' +#3 '@' +#4 STR_CONST "alkjfldajf" +#4 ERROR "Unterminated string constant" *) \ No newline at end of file diff --git a/tests/lexer/mixed2_error.txt b/tests/lexer/mixed2_error.txt index 097dc2a07..37cb73ac2 100644 --- a/tests/lexer/mixed2_error.txt +++ b/tests/lexer/mixed2_error.txt @@ -1,3 +1,3 @@ -(2, 3) - LexicographicError: ERROR "$" -(3, 3) - LexicographicError: ERROR "%" -(4, 22) - LexicographicError: Unterminated string constant +(2, 3) - LexicographicError: ERROR "$" +(3, 3) - LexicographicError: ERROR "%" +(4, 22) - LexicographicError: Unterminated string constant diff --git a/tests/lexer/string1.cl b/tests/lexer/string1.cl index 6c3c00833..f0a5bd873 100644 --- a/tests/lexer/string1.cl +++ b/tests/lexer/string1.cl @@ -1,6 +1,6 @@ -(* A non-escaped newline character may not appear in a string *) - -"This \ -is OK" -"This is not +(* A non-escaped newline character may not appear in a string *) + +"This \ +is OK" +"This is not OK" \ No newline at end of file diff --git a/tests/lexer/string1_error.txt b/tests/lexer/string1_error.txt index 078c12bbb..1dd4d70d9 100644 --- a/tests/lexer/string1_error.txt +++ b/tests/lexer/string1_error.txt @@ -1,2 +1,2 @@ -(5, 13) - LexicographicError: Unterminated string constant +(5, 13) - LexicographicError: Unterminated string constant (6, 4) - LexicographicError: EOF in string constant \ No newline at end of file diff --git a/tests/lexer/string2.cl b/tests/lexer/string2.cl index 3704b6ae7..cb3024180 100644 --- a/tests/lexer/string2.cl +++ b/tests/lexer/string2.cl @@ -1,19 +1,19 @@ -(* A string may not contain EOF *) - -" May the Triforce \ - 0 \ - 0v0 \ - 0vvv0 \ - 0vvvvv0 \ - 0vvvvvvv0 \ - 0vvvvvvvvv0 \ - 0vvvvvvvvvvv0 \ - 000000000000000 \ - 0v0 0v0 \ - 0vvv0 0vvv0 \ - 0vvvvv0 0vvvvv0 \ - 0vvvvvvv0 0vvvvvvv0 \ - 0vvvvvvvvv0 0vvvvvvvvv0 \ - 0vvvvvvvvvvv0 0vvvvvvvvvvv0 \ - 00000000000000000000000000000 \ +(* A string may not contain EOF *) + +" May the Triforce \ + 0 \ + 0v0 \ + 0vvv0 \ + 0vvvvv0 \ + 0vvvvvvv0 \ + 0vvvvvvvvv0 \ + 0vvvvvvvvvvv0 \ + 000000000000000 \ + 0v0 0v0 \ + 0vvv0 0vvv0 \ + 0vvvvv0 0vvvvv0 \ + 0vvvvvvv0 0vvvvvvv0 \ + 0vvvvvvvvv0 0vvvvvvvvv0 \ + 0vvvvvvvvvvv0 0vvvvvvvvvvv0 \ + 00000000000000000000000000000 \ be with you! \ No newline at end of file diff --git a/tests/lexer/string4.cl b/tests/lexer/string4.cl index f4d39c027..7ca4eb42b 100644 --- a/tests/lexer/string4.cl +++ b/tests/lexer/string4.cl @@ -1,38 +1,38 @@ -class Main { - str <- "The big brown fox - jumped over the fence"; - main() : Object { - { - out_string("Yay! This is the newest shites ); - } - }; -}; - -(* -#1 CLASS -#1 TYPEID Main -#1 '{' -#2 OBJECTID str -#2 ASSIGN -#3 ERROR "Unterminated string constant" -#3 OBJECTID jumped -#3 OBJECTID over -#3 OBJECTID the -#3 OBJECTID fence -#4 ERROR "Unterminated string constant" -#4 OBJECTID main -#4 '(' -#4 ')' -#4 ':' -#4 TYPEID Object -#4 '{' -#5 '{' -#6 OBJECTID out_string -#6 '(' -#7 ERROR "Unterminated string constant" -#7 '}' -#8 '}' -#8 ';' -#9 '}' -#9 ';' +class Main { + str <- "The big brown fox + jumped over the fence"; + main() : Object { + { + out_string("Yay! This is the newest shites ); + } + }; +}; + +(* +#1 CLASS +#1 TYPEID Main +#1 '{' +#2 OBJECTID str +#2 ASSIGN +#3 ERROR "Unterminated string constant" +#3 OBJECTID jumped +#3 OBJECTID over +#3 OBJECTID the +#3 OBJECTID fence +#4 ERROR "Unterminated string constant" +#4 OBJECTID main +#4 '(' +#4 ')' +#4 ':' +#4 TYPEID Object +#4 '{' +#5 '{' +#6 OBJECTID out_string +#6 '(' +#7 ERROR "Unterminated string constant" +#7 '}' +#8 '}' +#8 ';' +#9 '}' +#9 ';' *) \ No newline at end of file diff --git a/tests/lexer/string4_error.txt b/tests/lexer/string4_error.txt index 5ab0ea847..bf420217c 100644 --- a/tests/lexer/string4_error.txt +++ b/tests/lexer/string4_error.txt @@ -1,3 +1,3 @@ -(2, 30) - LexicographicError: Unterminated string constant -(3, 36) - LexicographicError: Unterminated string constant +(2, 30) - LexicographicError: Unterminated string constant +(3, 36) - LexicographicError: Unterminated string constant (6, 58) - LexicographicError: Unterminated string constant \ No newline at end of file diff --git a/tests/lexer_test.py b/tests/lexer_test.py index 2a27223d3..68fc35982 100644 --- a/tests/lexer_test.py +++ b/tests/lexer_test.py @@ -10,4 +10,7 @@ @pytest.mark.run(order=1) @pytest.mark.parametrize("cool_file", tests) def test_lexer_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') + +# if __name__ == "__main__": +# pytest.main(["-m", "lexer"]) \ No newline at end of file diff --git a/tests/parser/assignment1.cl b/tests/parser/assignment1.cl index 75b4c5bbd..e89ade368 100644 --- a/tests/parser/assignment1.cl +++ b/tests/parser/assignment1.cl @@ -1,37 +1,37 @@ -(* An assignment has the form <- *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(): String { - Test1 <- "Hello World" -- Identifiers begin with a lower case letter - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): String { + Test1 <- "Hello World" -- Identifiers begin with a lower case letter + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/assignment2.cl b/tests/parser/assignment2.cl index 4efb96487..7b8ed54ba 100644 --- a/tests/parser/assignment2.cl +++ b/tests/parser/assignment2.cl @@ -1,37 +1,37 @@ -(* An assignment has the form <- *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 - 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(): Int { - test1 <-- ~(1 + 2 + 3 + 4 + 5) -- The left side must be an expression - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 - 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): Int { + test1 <-- ~(1 + 2 + 3 + 4 + 5) -- The left side must be an expression + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/assignment3.cl b/tests/parser/assignment3.cl index ff633f331..f54305e27 100644 --- a/tests/parser/assignment3.cl +++ b/tests/parser/assignment3.cl @@ -1,37 +1,37 @@ -(* An assignment has the form <- *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(): Bool { - test1 <- true++ -- The left side must be an expression - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An assignment has the form <- *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(): Bool { + test1 <- true++ -- The left side must be an expression + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/attribute1.cl b/tests/parser/attribute1.cl index 063a02c02..59740336d 100644 --- a/tests/parser/attribute1.cl +++ b/tests/parser/attribute1.cl @@ -1,34 +1,34 @@ -(* An attribute of class A specifies a variable that is part of the state of objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - -- Attributes names must begin with lowercase letters - Test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + -- Attributes names must begin with lowercase letters + Test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/attribute2.cl b/tests/parser/attribute2.cl index c05211483..337696859 100644 --- a/tests/parser/attribute2.cl +++ b/tests/parser/attribute2.cl @@ -1,34 +1,34 @@ -(* An attribute of class A specifies a variable that is part of the state of objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - -- Type names must begin with uppercase letters - test3: string <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + -- Type names must begin with uppercase letters + test3: string <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/attribute3.cl b/tests/parser/attribute3.cl index d858ae47c..b29b4b26d 100644 --- a/tests/parser/attribute3.cl +++ b/tests/parser/attribute3.cl @@ -1,34 +1,34 @@ -(* An attribute of class A specifies a variable that is part of the state of objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - -- Expected '<-' not '<=' - test3: String <= "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* An attribute of class A specifies a variable that is part of the state of objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + -- Expected '<-' not '<=' + test3: String <= "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/block1.cl b/tests/parser/block1.cl index 3613d9268..f15872812 100644 --- a/tests/parser/block1.cl +++ b/tests/parser/block1.cl @@ -1,87 +1,87 @@ -(* A block has the form { ; ... ; } *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - pow: Int <- 1; - count: Int <- 0; - - testing6(a: Int): IO { - { - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2 -- Missing ";" - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2 -- Missing ";" + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/block2.cl b/tests/parser/block2.cl index f485dd0b1..1f45fca4c 100644 --- a/tests/parser/block2.cl +++ b/tests/parser/block2.cl @@ -1,87 +1,87 @@ -(* A block has the form { ; ... ; } *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - pow: Int <- 1; - count: Int <- 0; - - testing6(a: Int): IO { - -- Missing "{" - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + -- Missing "{" + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/block3.cl b/tests/parser/block3.cl index ae1598c3b..9b63b0015 100644 --- a/tests/parser/block3.cl +++ b/tests/parser/block3.cl @@ -1,87 +1,87 @@ -(* A block has the form { ; ... ; } *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - pow: Int <- 1; - count: Int <- 0; - - testing6(a: Int): IO { - { - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - -- Missing "}" - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + -- Missing "}" + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/block4.cl b/tests/parser/block4.cl index 8fd883d02..c144dae48 100644 --- a/tests/parser/block4.cl +++ b/tests/parser/block4.cl @@ -1,88 +1,88 @@ -(* A block has the form { ; ... ; } *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - pow: Int <- 1; - count: Int <- 0; - - testing6(a: Int): IO { - { - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - true++; -- Only expressions - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A block has the form { ; ... ; } *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + pow: Int <- 1; + count: Int <- 0; + + testing6(a: Int): IO { + { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + true++; -- Only expressions + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case1.cl b/tests/parser/case1.cl index c2f508809..35fe5af53 100644 --- a/tests/parser/case1.cl +++ b/tests/parser/case1.cl @@ -1,91 +1,91 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - -- Every case expression must have at least one branch - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + -- Every case expression must have at least one branch + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case2.cl b/tests/parser/case2.cl index f9162e49f..12cbb87b5 100644 --- a/tests/parser/case2.cl +++ b/tests/parser/case2.cl @@ -1,93 +1,93 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case "2 + 2" of - x: Int => new IO.out_string("Es un entero!") -- Missing ";" - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case "2 + 2" of + x: Int => new IO.out_string("Es un entero!") -- Missing ";" + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case3.cl b/tests/parser/case3.cl index a7eedc18b..8fd851836 100644 --- a/tests/parser/case3.cl +++ b/tests/parser/case3.cl @@ -1,93 +1,93 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + false of - x: Int => new IO.out_string("Es un entero!"); - y: string => new IO.out_string("Es una cadena!"); -- Type identifiers starts with a uppercase letter - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + false of + x: Int => new IO.out_string("Es un entero!"); + y: string => new IO.out_string("Es una cadena!"); -- Type identifiers starts with a uppercase letter + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case4.cl b/tests/parser/case4.cl index 25ca3858f..eb8a3d3a2 100644 --- a/tests/parser/case4.cl +++ b/tests/parser/case4.cl @@ -1,93 +1,93 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case true of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - Mazinger_Z: Bool => new IO.out_string("Es un booleano!"); -- Identifiers starts with a lowercase letter - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case true of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + Mazinger_Z: Bool => new IO.out_string("Es un booleano!"); -- Identifiers starts with a lowercase letter + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case5.cl b/tests/parser/case5.cl index b36c663e1..f0483f1f5 100644 --- a/tests/parser/case5.cl +++ b/tests/parser/case5.cl @@ -1,93 +1,93 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case test2 of - x: Int <- new IO.out_string("Es un entero!"); -- Must be '=>' not '<-'; - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case test2 of + x: Int <- new IO.out_string("Es un entero!"); -- Must be '=>' not '<-'; + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/case6.cl b/tests/parser/case6.cl index 66e7df2ab..c49467a89 100644 --- a/tests/parser/case6.cl +++ b/tests/parser/case6.cl @@ -1,93 +1,93 @@ -(* Case expressions provide runtime type tests on objects *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 -- Missing "of" - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Case expressions provide runtime type tests on objects *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 -- Missing "of" + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/class1.cl b/tests/parser/class1.cl index f4815e3f4..1c0641a94 100644 --- a/tests/parser/class1.cl +++ b/tests/parser/class1.cl @@ -1,20 +1,20 @@ -(* A class is a list of features *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - testing(): Int { - 2 + 2 - }; -}; - --- Class names must begin with uppercase letters -class alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Class names must begin with uppercase letters +class alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class2.cl b/tests/parser/class2.cl index f363b032a..baf290822 100644 --- a/tests/parser/class2.cl +++ b/tests/parser/class2.cl @@ -1,20 +1,20 @@ -(* A class is a list of features *) - -CLaSS Main { - main(): Object { - (new Alpha).print() - }; -}; - -CLaSS Test { - testing(): Int { - 2 + 2 - }; -}; - --- Type names must begin with uppercase letters -CLaSS Alpha iNHeRiTS iO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +CLaSS Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Type names must begin with uppercase letters +CLaSS Alpha iNHeRiTS iO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class3.cl b/tests/parser/class3.cl index 0c801372a..5c89c5eb8 100644 --- a/tests/parser/class3.cl +++ b/tests/parser/class3.cl @@ -1,34 +1,34 @@ -(* A class is a list of features *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - -- Missing semicolon - testing2(a: Alpha, b: Int): Int { - 2 + 2 - } - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Missing semicolon + testing2(a: Alpha, b: Int): Int { + 2 + 2 + } + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class4.cl b/tests/parser/class4.cl index 5c286b5e6..cdfbc313c 100644 --- a/tests/parser/class4.cl +++ b/tests/parser/class4.cl @@ -1,36 +1,36 @@ -(* A class is a list of features *) - -CLaSS Main { - main(): Object { - (new Alpha).print() - }; -}; - -CLaSS Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - -- Only features - 2 + 2; - - testing3(): String { - "2 + 2" - }; -}; - -CLaSS Alpha iNHeRiTS IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +CLaSS Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Only features + 2 + 2; + + testing3(): String { + "2 + 2" + }; +}; + +CLaSS Alpha iNHeRiTS IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class5.cl b/tests/parser/class5.cl index 3f40c36eb..d6b5c5fda 100644 --- a/tests/parser/class5.cl +++ b/tests/parser/class5.cl @@ -1,34 +1,34 @@ -(* A class is a list of features *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - --- Missing '{' -class Test - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing '{' +class Test + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/class6.cl b/tests/parser/class6.cl index 8501d2593..af9ecbf15 100644 --- a/tests/parser/class6.cl +++ b/tests/parser/class6.cl @@ -1,34 +1,34 @@ -(* A class is a list of features *) - -CLaSS Main { - main(): Object { - (new Alpha).print() - }; -}; - --- Missing '}' -CLaSS Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -; - -CLaSS Alpha iNHeRiTS IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* A class is a list of features *) + +CLaSS Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing '}' +CLaSS Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +; + +CLaSS Alpha iNHeRiTS IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/conditional1.cl b/tests/parser/conditional1.cl index 4d546fc44..f03b9c4e6 100644 --- a/tests/parser/conditional1.cl +++ b/tests/parser/conditional1.cl @@ -1,69 +1,69 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - if a.length() < b.length() -- Mising "then" - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - else - if a.length() = b.length() then - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - else - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fi - fi - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + if a.length() < b.length() -- Mising "then" + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + else + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + else + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fi + fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/conditional2.cl b/tests/parser/conditional2.cl index 4f10c2957..9ebd7fe84 100644 --- a/tests/parser/conditional2.cl +++ b/tests/parser/conditional2.cl @@ -1,69 +1,69 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - if a.length() < b.length() then - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - else - if a.length() = b.length() then - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - else - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - -- Missing "fi" - fi - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + if a.length() < b.length() then + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + else + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + else + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + -- Missing "fi" + fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/conditional3.cl b/tests/parser/conditional3.cl index 67e991ade..ac143ad42 100644 --- a/tests/parser/conditional3.cl +++ b/tests/parser/conditional3.cl @@ -1,69 +1,69 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - iF a.length() < b.length() tHen - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - elsE - if a.length() = b.length() then - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - eLseif -- elseif isn't a keyword - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + iF a.length() < b.length() tHen + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + elsE + if a.length() = b.length() then + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + eLseif -- elseif isn't a keyword + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/conditional4.cl b/tests/parser/conditional4.cl index 0792fdc85..51337f874 100644 --- a/tests/parser/conditional4.cl +++ b/tests/parser/conditional4.cl @@ -1,73 +1,73 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(): Int { - if true++ then 1 else 0 -- Condition must be an expression - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true++ then 1 else 0 -- Condition must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/conditional5.cl b/tests/parser/conditional5.cl index 0c1e1aad0..399515701 100644 --- a/tests/parser/conditional5.cl +++ b/tests/parser/conditional5.cl @@ -1,73 +1,73 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(): Int { - if true then true++ else 0 -- If branch must be an expression - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true then true++ else 0 -- If branch must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/conditional6.cl b/tests/parser/conditional6.cl index 02310404a..8daa35d7f 100644 --- a/tests/parser/conditional6.cl +++ b/tests/parser/conditional6.cl @@ -1,73 +1,73 @@ -(* A conditional has the form if then else fi *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(): Int { - if true then 1 else false++ -- Else branch must be an expression - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A conditional has the form if then else fi *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(): Int { + if true then 1 else false++ -- Else branch must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch1.cl b/tests/parser/dispatch1.cl index 2ca394716..2eba9db03 100644 --- a/tests/parser/dispatch1.cl +++ b/tests/parser/dispatch1.cl @@ -1,45 +1,45 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - Test1.testing4(1, 2).testing4(3, 4).testing4(5, 6) -- Objet identifiers begin with a lower case letter - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + Test1.testing4(1, 2).testing4(3, 4).testing4(5, 6) -- Objet identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch2.cl b/tests/parser/dispatch2.cl index 0b57467a1..139eba918 100644 --- a/tests/parser/dispatch2.cl +++ b/tests/parser/dispatch2.cl @@ -1,45 +1,45 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13,) -- Extra comma - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13,) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch3.cl b/tests/parser/dispatch3.cl index 9f1a5afff..0d88f5c23 100644 --- a/tests/parser/dispatch3.cl +++ b/tests/parser/dispatch3.cl @@ -1,45 +1,45 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).Testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) -- Identifiers begin with a lower case letter - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).Testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) -- Identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch4.cl b/tests/parser/dispatch4.cl index d1efc469d..dc13fd762 100644 --- a/tests/parser/dispatch4.cl +++ b/tests/parser/dispatch4.cl @@ -1,53 +1,53 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - self.testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true++) -- Arguments must be expressions - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + self.testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true++) -- Arguments must be expressions + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch5.cl b/tests/parser/dispatch5.cl index 63a5afa79..b7bae25e1 100644 --- a/tests/parser/dispatch5.cl +++ b/tests/parser/dispatch5.cl @@ -1,53 +1,53 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, ,true + fALSE) -- Extra comma - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, ,true + fALSE) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch6.cl b/tests/parser/dispatch6.cl index 0a953e2e6..6887c60cd 100644 --- a/tests/parser/dispatch6.cl +++ b/tests/parser/dispatch6.cl @@ -1,57 +1,57 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@object.copy() -- Type identifiers begin with a upper case letter - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@object.copy() -- Type identifiers begin with a upper case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch7.cl b/tests/parser/dispatch7.cl index 3ecac4d0f..a9ff1b67a 100644 --- a/tests/parser/dispatch7.cl +++ b/tests/parser/dispatch7.cl @@ -1,57 +1,57 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.Copy() -- Identifiers begin with a lower case letter - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.Copy() -- Identifiers begin with a lower case letter + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch8.cl b/tests/parser/dispatch8.cl index eef0455ef..c1bb2abba 100644 --- a/tests/parser/dispatch8.cl +++ b/tests/parser/dispatch8.cl @@ -1,57 +1,57 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy(,) -- Extra comma - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy(,) -- Extra comma + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/dispatch9.cl b/tests/parser/dispatch9.cl index 5fdef22d6..8914a18c2 100644 --- a/tests/parser/dispatch9.cl +++ b/tests/parser/dispatch9.cl @@ -1,61 +1,61 @@ -(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; - - testing5(): Object { - test1:Object.copy() -- Must be '@' not ':' - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* There are three forms of dispatch (i.e. method call) in Cool. The three forms differ only in how the called method is selected *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; + + testing5(): Object { + test1:Object.copy() -- Must be '@' not ':' + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let1.cl b/tests/parser/let1.cl index 576ae383c..0e5fc6d17 100644 --- a/tests/parser/let1.cl +++ b/tests/parser/let1.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let Count: Int <- 0, pow: Int <- 1 -- Object identifiers starts with a lowercase letter - in { - -- count <- 0; - -- pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let Count: Int <- 0, pow: Int <- 1 -- Object identifiers starts with a lowercase letter + in { + -- count <- 0; + -- pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let2.cl b/tests/parser/let2.cl index 4cfaef0f8..01d055dac 100644 --- a/tests/parser/let2.cl +++ b/tests/parser/let2.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int, pow: int <- 1 -- Type identifiers starts with a uppercase letter - in { - count <- 0; - -- pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int, pow: int <- 1 -- Type identifiers starts with a uppercase letter + in { + count <- 0; + -- pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let3.cl b/tests/parser/let3.cl index 91e567fd8..b2b2fb005 100644 --- a/tests/parser/let3.cl +++ b/tests/parser/let3.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int, pow: Int, -- Extra comma - in { - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int, pow: Int, -- Extra comma + in { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let4.cl b/tests/parser/let4.cl index a716c332d..c7d0ea8e3 100644 --- a/tests/parser/let4.cl +++ b/tests/parser/let4.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- true++, pow: Int <- 1 -- Initialization must be an expression - in { - count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- true++, pow: Int <- 1 -- Initialization must be an expression + in { + count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let5.cl b/tests/parser/let5.cl index d974cc138..cc4ed7a99 100644 --- a/tests/parser/let5.cl +++ b/tests/parser/let5.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int = 0, pow: Int -- Must be '<-' not '=' - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int = 0, pow: Int -- Must be '<-' not '=' + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let6.cl b/tests/parser/let6.cl index b6e51d7e1..8bc8c4883 100644 --- a/tests/parser/let6.cl +++ b/tests/parser/let6.cl @@ -1,74 +1,74 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int <- 1 - in false++ -- Let body must be an expression - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int <- 1 + in false++ -- Let body must be an expression + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/let7.cl b/tests/parser/let7.cl index 6fd63e6a7..816c59845 100644 --- a/tests/parser/let7.cl +++ b/tests/parser/let7.cl @@ -1,85 +1,85 @@ -(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - (* Missing "in" *) { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A let expression has the form let : [ <- ], ..., : [ <- ] in *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + (* Missing "in" *) { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/loop1.cl b/tests/parser/loop1.cl index 7d0d7688f..2065de506 100644 --- a/tests/parser/loop1.cl +++ b/tests/parser/loop1.cl @@ -1,78 +1,78 @@ -(* A loop has the form while loop pool *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - count: Int <- 1; - - testing6(): Object { - while count < 1024*1024 - -- Missing "loop" - count <- count * 2 - pool - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + -- Missing "loop" + count <- count * 2 + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/loop2.cl b/tests/parser/loop2.cl index a9613c487..70f8cd910 100644 --- a/tests/parser/loop2.cl +++ b/tests/parser/loop2.cl @@ -1,78 +1,78 @@ -(* A loop has the form while loop pool *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - count: Int <- 1; - - testing6(): Object { - while count < 1024*1024 - loop - count <- count * 2 - -- Missing "pool" - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + loop + count <- count * 2 + -- Missing "pool" + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/loop3.cl b/tests/parser/loop3.cl index 860adb4d1..fbb3a56b4 100644 --- a/tests/parser/loop3.cl +++ b/tests/parser/loop3.cl @@ -1,78 +1,78 @@ -(* A loop has the form while loop pool *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - count: Int <- 1; - - testing6(): Object { - while count => 1024*1024 -- Condition must be an expression - loop - count <- count * 2 - pool - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count => 1024*1024 -- Condition must be an expression + loop + count <- count * 2 + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/loop4.cl b/tests/parser/loop4.cl index 0a1194e82..47b0e5f4a 100644 --- a/tests/parser/loop4.cl +++ b/tests/parser/loop4.cl @@ -1,78 +1,78 @@ -(* A loop has the form while loop pool *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - count: Int <- 1; - - testing6(): Object { - while count < 1024*1024 - loop - count <- true++ -- While body must be an expression - pool - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A loop has the form while loop pool *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + count: Int <- 1; + + testing6(): Object { + while count < 1024*1024 + loop + count <- true++ -- While body must be an expression + pool + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method1.cl b/tests/parser/method1.cl index fcfbbcd30..d86661430 100644 --- a/tests/parser/method1.cl +++ b/tests/parser/method1.cl @@ -1,34 +1,34 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - -- Method names must begin with lowercase letters - Testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Method names must begin with lowercase letters + Testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method2.cl b/tests/parser/method2.cl index d5bdfd85c..83648f50d 100644 --- a/tests/parser/method2.cl +++ b/tests/parser/method2.cl @@ -1,34 +1,34 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - -- Parameter names must begin with lowercase letters - testing2(a: Alpha, B: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Parameter names must begin with lowercase letters + testing2(a: Alpha, B: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method3.cl b/tests/parser/method3.cl index 1e5c9eb53..428b25fec 100644 --- a/tests/parser/method3.cl +++ b/tests/parser/method3.cl @@ -1,34 +1,34 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - -- Type names must begin with uppercase letters - testing2(a: Alpha, b: int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Type names must begin with uppercase letters + testing2(a: Alpha, b: int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method4.cl b/tests/parser/method4.cl index 019ada276..52ec07bce 100644 --- a/tests/parser/method4.cl +++ b/tests/parser/method4.cl @@ -1,34 +1,34 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - -- Missing paremeter - testing3(x: Int,): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Missing paremeter + testing3(x: Int,): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method5.cl b/tests/parser/method5.cl index 13127f664..706a3145c 100644 --- a/tests/parser/method5.cl +++ b/tests/parser/method5.cl @@ -1,34 +1,34 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - -- Type names must begin with uppercase letters - testing3(): string { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + -- Type names must begin with uppercase letters + testing3(): string { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/method6.cl b/tests/parser/method6.cl index d48cd1293..26ce7f19f 100644 --- a/tests/parser/method6.cl +++ b/tests/parser/method6.cl @@ -1,33 +1,33 @@ -(* A method of class A is a procedure that may manipulate the variables and objects of class A *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - -- Body can't be empty - testing2(a: Alpha, b: Int): Int { - }; - - testing3(): String { - "2 + 2" - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* A method of class A is a procedure that may manipulate the variables and objects of class A *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + -- Body can't be empty + testing2(a: Alpha, b: Int): Int { + }; + + testing3(): String { + "2 + 2" + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/mixed1.cl b/tests/parser/mixed1.cl index a27879513..b13e679da 100644 --- a/tests/parser/mixed1.cl +++ b/tests/parser/mixed1.cl @@ -1,100 +1,100 @@ -(* Cool has four binary arithmetic operations: +, -, *, /. *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; - - a: Int <- 1; - - testing8(x: Int, y: Int): Bool { - let z: Int <- 3, w: Int <- 4 - in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) - }; -}-- Mising ";" - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}-- Mising ";" + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/mixed2.cl b/tests/parser/mixed2.cl index f5477e0bb..6776fcc12 100644 --- a/tests/parser/mixed2.cl +++ b/tests/parser/mixed2.cl @@ -1,14 +1,14 @@ -class Main { - main(): Object { - (new Alpha).print() - }; - -}; - -(* Class names must begin with uppercase letters *) -class alpha inherits IO { - print() : Object { - out_string("reached!!\n"); - }; -}; - +class Main { + main(): Object { + (new Alpha).print() + }; + +}; + +(* Class names must begin with uppercase letters *) +class alpha inherits IO { + print() : Object { + out_string("reached!!\n"); + }; +}; + diff --git a/tests/parser/mixed3.cl b/tests/parser/mixed3.cl index 1bdcad743..f5271eb3e 100644 --- a/tests/parser/mixed3.cl +++ b/tests/parser/mixed3.cl @@ -1,40 +1,40 @@ -class Main inherits IO { - main() : Object { - { - out_string("Enter a number to check if number is prime\n"); - let i : Int <- in_int() in { - if(i <= 1) then { - out_string("Invalid Input\n"); - abort(); - } else { - if (isPrime(i) = 1) then - out_string("Number is prime\n") - else - out_string("Number is composite\n") - fi; - } - fi; - }; - } - }; - - mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. - i - (i/k)*k - }; - - isPrime(i : Int) : Int { - { - let x : Int <- 2, - c : Int <- 1 in - { - while (not (x = i)) loop - if (mod(i, x) = 0) then { - c <- 0; - x <- i; - } else x <- x + 1 fi - pool; - c; - }; - } - }; -}; +class Main inherits IO { + main() : Object { + { + out_string("Enter a number to check if number is prime\n"); + let i : Int <- in_int() in { + if(i <= 1) then { + out_string("Invalid Input\n"); + abort(); + } else { + if (isPrime(i) = 1) then + out_string("Number is prime\n") + else + out_string("Number is composite\n") + fi; + } + fi; + }; + } + }; + + mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. + i - (i/k)*k + }; + + isPrime(i : Int) : Int { + { + let x : Int <- 2, + c : Int <- 1 in + { + while (not (x = i)) loop + if (mod(i, x) = 0) then { + c <- 0; + x <- i; + } else x <- x + 1 fi + pool; + c; + }; + } + }; +}; diff --git a/tests/parser/mixed4.cl b/tests/parser/mixed4.cl index e752253be..47e6ea5e9 100644 --- a/tests/parser/mixed4.cl +++ b/tests/parser/mixed4.cl @@ -1,21 +1,21 @@ -class Main inherits IO { - main() : Object { - { - out_string("Enter number of numbers to multiply\n"); - out_int(prod(in_int())); - out_string("\n"); - } - }; - - prod(i : Int) : Int { - let y : Int <- 1 in { - while (not (i = 0) ) loop { - out_string("Enter Number: "); - y <- y * in_int(Main : Int); -- the parser correctly catches the error here - i <- i - 1; - } - pool; - y; - } - }; -}; +class Main inherits IO { + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(Main : Int); -- the parser correctly catches the error here + i <- i - 1; + } + pool; + y; + } + }; +}; diff --git a/tests/parser/mixed5.cl b/tests/parser/mixed5.cl index c9176a890..d4ca68f44 100644 --- a/tests/parser/mixed5.cl +++ b/tests/parser/mixed5.cl @@ -1,20 +1,20 @@ -class Main inherits IO { - str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - main() : Object { - { - out_string("Enter number of numbers to multiply\n"); - out_int(prod(in_int())); - out_string("\n"); - } - }; - prod(i : Int) : Int { - let y : Int <- 1 in { - while (not (i = 0) ) loop { - out_string("Enter Number: "); - y <- y * in_int(); - i <- i - 1; - } - y; - } - }; -} +class Main inherits IO { + str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; + main() : Object { + { + out_string("Enter number of numbers to multiply\n"); + out_int(prod(in_int())); + out_string("\n"); + } + }; + prod(i : Int) : Int { + let y : Int <- 1 in { + while (not (i = 0) ) loop { + out_string("Enter Number: "); + y <- y * in_int(); + i <- i - 1; + } + y; + } + }; +} diff --git a/tests/parser/mixed6.cl b/tests/parser/mixed6.cl index 5da80da31..0a51656c9 100644 --- a/tests/parser/mixed6.cl +++ b/tests/parser/mixed6.cl @@ -1,5 +1,5 @@ -classs Doom { - i : Int <- 0; - main() : Object { - if i = 0 then out_string("This is da real *h*t") - +classs Doom { + i : Int <- 0; + main() : Object { + if i = 0 then out_string("This is da real *h*t") + diff --git a/tests/parser/operation1.cl b/tests/parser/operation1.cl index d38eb72d0..d892ec8a6 100644 --- a/tests/parser/operation1.cl +++ b/tests/parser/operation1.cl @@ -1,101 +1,101 @@ -(* Cool has four binary arithmetic operations: +, -, *, /. *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; - - a: Int <- 1; - - testing8(x: Int, y: Int): Bool { - let z: Int <- 3, w: Int <- 4 - -- Missing ')' - in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a)/(0)*(((4 * 4))))) - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Missing ')' + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a)/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/operation2.cl b/tests/parser/operation2.cl index 2dc628359..1f167409a 100644 --- a/tests/parser/operation2.cl +++ b/tests/parser/operation2.cl @@ -1,101 +1,101 @@ -(* Cool has four binary arithmetic operations: +, -, *, /. *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; - - a: Int <- 1; - - testing8(x: Int, y: Int): Bool { - let z: Int <- 3, w: Int <- 4 - -- Type identifiers starts with a uppercase letter - in isvoid (3 + a * (x / w + new int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Type identifiers starts with a uppercase letter + in isvoid (3 + a * (x / w + new int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/operation3.cl b/tests/parser/operation3.cl index 61d6cbfa8..ef125927a 100644 --- a/tests/parser/operation3.cl +++ b/tests/parser/operation3.cl @@ -1,101 +1,101 @@ -(* Cool has four binary arithmetic operations: +, -, *, /. *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; - - a: Int <- 1; - - testing8(x: Int, y: Int): Bool { - let z: Int <- 3, w: Int <- 4 - -- Object identifiers starts with a lowercase letter - in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~Mazinger_Z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Object identifiers starts with a lowercase letter + in isvoid (3 + a * (x / w + new Int) - y - (((if tRue = not faLSe then ~Mazinger_Z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/operation4.cl b/tests/parser/operation4.cl index bae7de5b5..2212740e7 100644 --- a/tests/parser/operation4.cl +++ b/tests/parser/operation4.cl @@ -1,101 +1,101 @@ -(* Cool has four binary arithmetic operations: +, -, *, /. *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - test1: Object; - - testing1(): Int { - 2 + 2 - }; - - test2: Int <- 1; - - test3: String <- "1"; - - testing2(a: Alpha, b: Int): Int { - 2 + 2 - }; - - testing3(): String { - "2 + 2" - }; - - testing4(x: Int, y: Int): Test { - self - }; - - testing5(a: String, b: String): IO { - If a.length() < b.length() THeN - new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) - eLSe - if a.length() = b.length() THeN - new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) - ElsE - new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) - fI - Fi - }; - - testing6(a: Int): IO { - let count: Int <- 0, pow: Int - in { - -- count <- 0; - pow <- 1; - while pow < a - loop - { - count <- count + 1; - pow <- pow * 2; - } - pool; - new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); - } - }; - - testing7(): Object { - case 2 + 2 of - x: Int => new IO.out_string("Es un entero!"); - y: String => new IO.out_string("Es una cadena!"); - z: Bool => new IO.out_string("Es un booleano!"); - esac - }; - - a: Int <- 1; - - testing8(x: Int, y: Int): Bool { - let z: Int <- 3, w: Int <- 4 - -- Double "+" - in isvoid (3 + a * (x / w++ new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) - }; -}; - -class Test2 { - test1: Test <- new Test; - - testing1(): Test { - test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) - }; - - testing2(x: Int, y: Int): Test2 { - self - }; - - testing3(): Test2 { - testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) - }; - - testing4(): Object { - test1@Object.copy() - }; -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; +(* Cool has four binary arithmetic operations: +, -, *, /. *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + test1: Object; + + testing1(): Int { + 2 + 2 + }; + + test2: Int <- 1; + + test3: String <- "1"; + + testing2(a: Alpha, b: Int): Int { + 2 + 2 + }; + + testing3(): String { + "2 + 2" + }; + + testing4(x: Int, y: Int): Test { + self + }; + + testing5(a: String, b: String): IO { + If a.length() < b.length() THeN + new IO.out_string("La cadena \"".concat(b).concat("\" es mas larga que la cadena \"").concat(a).concat("\".")) + eLSe + if a.length() = b.length() THeN + new IO.out_string("La cadena \"".concat(a).concat("\" mide igual que la cadena \"").concat(b).concat("\".")) + ElsE + new IO.out_string("La cadena \"".concat(a).concat("\" es mas larga que la cadena \"").concat(b).concat("\".")) + fI + Fi + }; + + testing6(a: Int): IO { + let count: Int <- 0, pow: Int + in { + -- count <- 0; + pow <- 1; + while pow < a + loop + { + count <- count + 1; + pow <- pow * 2; + } + pool; + new IO.out_string("El logaritmo en base 2 de ").out_int(a).out_string(" es ").out_int(count); + } + }; + + testing7(): Object { + case 2 + 2 of + x: Int => new IO.out_string("Es un entero!"); + y: String => new IO.out_string("Es una cadena!"); + z: Bool => new IO.out_string("Es un booleano!"); + esac + }; + + a: Int <- 1; + + testing8(x: Int, y: Int): Bool { + let z: Int <- 3, w: Int <- 4 + -- Double "+" + in isvoid (3 + a * (x / w++ new Int) - y - (((if tRue = not faLSe then ~z else 3 <= 4 + "hey".length() fi + a))/(0)*(((4 * 4))))) + }; +}; + +class Test2 { + test1: Test <- new Test; + + testing1(): Test { + test1.testing4(1 + 1, 1 + 2).testing4(2 + 3, 3 + 5).testing4(5 + 8, 8 + 13) + }; + + testing2(x: Int, y: Int): Test2 { + self + }; + + testing3(): Test2 { + testing2(1 + 1, 1 + 2).testing2(2 + 3, 3 + 5).testing2(5 + 8, true + fALSE) + }; + + testing4(): Object { + test1@Object.copy() + }; +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; }; \ No newline at end of file diff --git a/tests/parser/program2.cl b/tests/parser/program2.cl index f8b16779c..a281c6c14 100644 --- a/tests/parser/program2.cl +++ b/tests/parser/program2.cl @@ -1,20 +1,20 @@ -(* Cool programs are sets of classes *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - --- Missing semicolon -class Test { - testing(): Int { - 2 + 2 - }; -} - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* Cool programs are sets of classes *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +-- Missing semicolon +class Test { + testing(): Int { + 2 + 2 + }; +} + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser/program3.cl b/tests/parser/program3.cl index e27889c57..10d2dc71e 100644 --- a/tests/parser/program3.cl +++ b/tests/parser/program3.cl @@ -1,24 +1,24 @@ -(* Cool programs are sets of classes *) - -class Main { - main(): Object { - (new Alpha).print() - }; -}; - -class Test { - testing(): Int { - 2 + 2 - }; -}; - --- Only classes -suma(a: Int, b: Int) int { - a + b -}; - -class Alpha inherits IO { - print() : Object { - out_string("reached!!\n") - }; -}; +(* Cool programs are sets of classes *) + +class Main { + main(): Object { + (new Alpha).print() + }; +}; + +class Test { + testing(): Int { + 2 + 2 + }; +}; + +-- Only classes +suma(a: Int, b: Int) int { + a + b +}; + +class Alpha inherits IO { + print() : Object { + out_string("reached!!\n") + }; +}; diff --git a/tests/parser_test.py b/tests/parser_test.py index 129c0f20a..86c4ffaec 100644 --- a/tests/parser_test.py +++ b/tests/parser_test.py @@ -10,4 +10,7 @@ @pytest.mark.run(order=2) @pytest.mark.parametrize("cool_file", tests) def test_parser_errors(compiler_path, cool_file): - compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') \ No newline at end of file + compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt') + +# if __name__ == "__main__": +# pytest.main(["-m", "parser"]) \ No newline at end of file diff --git a/tests/semantic/arithmetic1.cl b/tests/semantic/arithmetic1.cl index bf94eb194..65719c064 100644 --- a/tests/semantic/arithmetic1.cl +++ b/tests/semantic/arithmetic1.cl @@ -1,11 +1,11 @@ ---The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Int <- 1 * 2 / 3 - 4 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in x <- x + new A.type_name().concat(new B.type_name().concat(new C.type_name())); +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 * 2 / 3 - 4 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x + new A.type_name().concat(new B.type_name().concat(new C.type_name())); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic10.cl b/tests/semantic/arithmetic10.cl index bbfe6cdb3..b2488ad7f 100644 --- a/tests/semantic/arithmetic10.cl +++ b/tests/semantic/arithmetic10.cl @@ -1,15 +1,15 @@ -(* -The expression ~ is the integer -complement of . The expression must have static type Int and the entire expression -has static type Int. -*) - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in ~new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in ~new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic11.cl b/tests/semantic/arithmetic11.cl index fc067dc1a..05cec0465 100644 --- a/tests/semantic/arithmetic11.cl +++ b/tests/semantic/arithmetic11.cl @@ -1,14 +1,14 @@ -(* -The expression not is the boolean complement of . The expression - must have static type Bool and the entire expression has static type Bool. -*) - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in not 1 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 + new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic12.cl b/tests/semantic/arithmetic12.cl index 2e012fc41..05a2da918 100644 --- a/tests/semantic/arithmetic12.cl +++ b/tests/semantic/arithmetic12.cl @@ -1,14 +1,14 @@ -(* -The expression not is the boolean complement of . The expression - must have static type Bool and the entire expression has static type Bool. -*) - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in not 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +(* +The expression not is the boolean complement of . The expression + must have static type Bool and the entire expression has static type Bool. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in not 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic1_error.txt b/tests/semantic/arithmetic1_error.txt index a74ebf3da..59213724d 100644 --- a/tests/semantic/arithmetic1_error.txt +++ b/tests/semantic/arithmetic1_error.txt @@ -1 +1 @@ -(10, 27) - TypeError: non-Int arguments: Int + String +(10, 27) - TypeError: non-Int arguments: Int + String diff --git a/tests/semantic/arithmetic2.cl b/tests/semantic/arithmetic2.cl index 59532573d..f1f0935e2 100644 --- a/tests/semantic/arithmetic2.cl +++ b/tests/semantic/arithmetic2.cl @@ -1,11 +1,11 @@ ---The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Int <- 1 + 2 * 3 / 4 - new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in x <- x - new A.type_name().concat(new B.type_name().concat(new C.type_name())); +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 + 2 * 3 / 4 - new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x - new A.type_name().concat(new B.type_name().concat(new C.type_name())); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic2_error.txt b/tests/semantic/arithmetic2_error.txt index 2c7952af8..aebc7aab9 100644 --- a/tests/semantic/arithmetic2_error.txt +++ b/tests/semantic/arithmetic2_error.txt @@ -1 +1 @@ -(10, 27) - TypeError: non-Int arguments: Int - String +(10, 27) - TypeError: non-Int arguments: Int - String diff --git a/tests/semantic/arithmetic3.cl b/tests/semantic/arithmetic3.cl index b208957f5..df64d8000 100644 --- a/tests/semantic/arithmetic3.cl +++ b/tests/semantic/arithmetic3.cl @@ -1,11 +1,11 @@ ---The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Int <- 1 - 2 + 3 * 4 / new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in x <- x / new A.type_name().concat(new B.type_name().concat(new C.type_name())); +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 - 2 + 3 * 4 / new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x / new A.type_name().concat(new B.type_name().concat(new C.type_name())); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic3_error.txt b/tests/semantic/arithmetic3_error.txt index 81d88331a..d0af01bb5 100644 --- a/tests/semantic/arithmetic3_error.txt +++ b/tests/semantic/arithmetic3_error.txt @@ -1 +1 @@ -(10, 27) - TypeError: non-Int arguments: Int / String +(10, 27) - TypeError: non-Int arguments: Int / String diff --git a/tests/semantic/arithmetic4.cl b/tests/semantic/arithmetic4.cl index 2c7dd4fc9..68512ca44 100644 --- a/tests/semantic/arithmetic4.cl +++ b/tests/semantic/arithmetic4.cl @@ -1,11 +1,11 @@ ---The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())); +--The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic5.cl b/tests/semantic/arithmetic5.cl index bc08c6e82..fd77c7971 100644 --- a/tests/semantic/arithmetic5.cl +++ b/tests/semantic/arithmetic5.cl @@ -1,11 +1,11 @@ ---The static type of the expression is Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Bool <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +--The static type of the expression is Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Int <- 1 / 2 - 3 + 4 * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in x <- x * new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); }; \ No newline at end of file diff --git a/tests/semantic/arithmetic5_error.txt b/tests/semantic/arithmetic5_error.txt index dd5346844..8c67c2f53 100644 --- a/tests/semantic/arithmetic5_error.txt +++ b/tests/semantic/arithmetic5_error.txt @@ -1 +1 @@ -(9, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. +(9, 19) - TypeError: Inferred type Int of initialization of attribute test does not conform to declared type Bool. diff --git a/tests/semantic/arithmetic6.cl b/tests/semantic/arithmetic6.cl index a0c3d03ff..d4da66a73 100644 --- a/tests/semantic/arithmetic6.cl +++ b/tests/semantic/arithmetic6.cl @@ -1,11 +1,11 @@ - --The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in 1 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())); -}; + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 <= new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; diff --git a/tests/semantic/arithmetic6_error.txt b/tests/semantic/arithmetic6_error.txt index 2e43dfc17..a0d67cb48 100644 --- a/tests/semantic/arithmetic6_error.txt +++ b/tests/semantic/arithmetic6_error.txt @@ -1 +1 @@ -(10, 22) - TypeError: non-Int arguments: Int <= String +(10, 22) - TypeError: non-Int arguments: Int <= String diff --git a/tests/semantic/arithmetic7.cl b/tests/semantic/arithmetic7.cl index c00c75cde..b98a4b0e2 100644 --- a/tests/semantic/arithmetic7.cl +++ b/tests/semantic/arithmetic7.cl @@ -1,12 +1,12 @@ - --The static types of the two sub-expressions must be Int. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())); -}; - + --The static types of the two sub-expressions must be Int. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Bool <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())); +}; + diff --git a/tests/semantic/arithmetic7_error.txt b/tests/semantic/arithmetic7_error.txt index 6f3537117..166bcc8ef 100644 --- a/tests/semantic/arithmetic7_error.txt +++ b/tests/semantic/arithmetic7_error.txt @@ -1 +1 @@ -(10, 22) - TypeError: non-Int arguments: Int < String +(10, 22) - TypeError: non-Int arguments: Int < String diff --git a/tests/semantic/arithmetic8.cl b/tests/semantic/arithmetic8.cl index 3210bdb8a..f3ad37ec4 100644 --- a/tests/semantic/arithmetic8.cl +++ b/tests/semantic/arithmetic8.cl @@ -1,13 +1,13 @@ - --The rules are exactly the same as for the binary arithmetic operations, except that the result is a Bool. - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); -}; - - + --The rules are exactly the same as for the binary arithmetic operations, except that the result is a Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length(); +}; + + diff --git a/tests/semantic/arithmetic8_error.txt b/tests/semantic/arithmetic8_error.txt index ebcaa3797..5a8814e1a 100644 --- a/tests/semantic/arithmetic8_error.txt +++ b/tests/semantic/arithmetic8_error.txt @@ -1 +1 @@ -(9, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. +(9, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/arithmetic9.cl b/tests/semantic/arithmetic9.cl index 95579e134..b7b4d3645 100644 --- a/tests/semantic/arithmetic9.cl +++ b/tests/semantic/arithmetic9.cl @@ -1,15 +1,15 @@ -(* -The expression ~ is the integer -complement of . The expression must have static type Int and the entire expression -has static type Int. -*) - -class A { }; -class B inherits A { }; -class C inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() - in 1 + ~new A.type_name().concat(new B.type_name().concat(new C.type_name())); +(* +The expression ~ is the integer +complement of . The expression must have static type Int and the entire expression +has static type Int. +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + test: Int <- let x: Bool <- 1 / 2 - 3 + 4 < new A.type_name().concat(new B.type_name().concat(new C.type_name())).length() + in 1 + ~new A.type_name().concat(new B.type_name().concat(new C.type_name())); }; \ No newline at end of file diff --git a/tests/semantic/assignment1.cl b/tests/semantic/assignment1.cl index 19ab70219..174f93e2b 100644 --- a/tests/semantic/assignment1.cl +++ b/tests/semantic/assignment1.cl @@ -1,7 +1,7 @@ ---The static type of the expression must conform to the declared type of the identifier - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: Int <- "String"; -}; +--The static type of the expression must conform to the declared type of the identifier + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- "String"; +}; diff --git a/tests/semantic/assignment1_error.txt b/tests/semantic/assignment1_error.txt index 6eb883012..9d05707aa 100644 --- a/tests/semantic/assignment1_error.txt +++ b/tests/semantic/assignment1_error.txt @@ -1 +1 @@ -(6, 18) - TypeError: Inferred type String of initialization of attribute test does not conform to declared type Int. +(6, 18) - TypeError: Inferred type String of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/assignment2.cl b/tests/semantic/assignment2.cl index cace221ae..c7f3d7873 100644 --- a/tests/semantic/assignment2.cl +++ b/tests/semantic/assignment2.cl @@ -1,13 +1,13 @@ ---The static type of an assignment is the static type of . - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: A): B { a <- new C }; - test2(a: A): D { a <- new C }; -}; +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A): B { a <- new C }; + test2(a: A): D { a <- new C }; +}; diff --git a/tests/semantic/assignment2_error.txt b/tests/semantic/assignment2_error.txt index ed10b7f38..55f5aa214 100644 --- a/tests/semantic/assignment2_error.txt +++ b/tests/semantic/assignment2_error.txt @@ -1 +1 @@ -(12, 22) - TypeError: Inferred return type C of method test2 does not conform to declared return type D. +(12, 22) - TypeError: Inferred return type C of method test2 does not conform to declared return type D. diff --git a/tests/semantic/assignment3.cl b/tests/semantic/assignment3.cl index eba0d69e2..9d60a4b6c 100644 --- a/tests/semantic/assignment3.cl +++ b/tests/semantic/assignment3.cl @@ -1,14 +1,14 @@ ---The static type of an assignment is the static type of . - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - a: A; - b: B <- a <- new C; - d: D <- a <- new C; -}; +--The static type of an assignment is the static type of . + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A; + b: B <- a <- new C; + d: D <- a <- new C; +}; diff --git a/tests/semantic/attributes1.cl b/tests/semantic/attributes1.cl index 3fa0440e4..d11ea7cdb 100644 --- a/tests/semantic/attributes1.cl +++ b/tests/semantic/attributes1.cl @@ -1,13 +1,13 @@ ---The static type of the expression must conform to the declared type of the attribute. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - test1: IO <- new Main; - test2: B <- new A; - - main(): IO { out_string("Hello World!")}; +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: B <- new A; + + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/attributes1_error.txt b/tests/semantic/attributes1_error.txt index 9cb8460c9..22e45b837 100644 --- a/tests/semantic/attributes1_error.txt +++ b/tests/semantic/attributes1_error.txt @@ -1 +1 @@ -(10, 17) - TypeError: Inferred type A of initialization of attribute test2 does not conform to declared type B. +(10, 17) - TypeError: Inferred type A of initialization of attribute test2 does not conform to declared type B. diff --git a/tests/semantic/attributes2.cl b/tests/semantic/attributes2.cl index 7937c2cc8..85c791b5e 100644 --- a/tests/semantic/attributes2.cl +++ b/tests/semantic/attributes2.cl @@ -1,13 +1,13 @@ ---The static type of the expression must conform to the declared type of the attribute. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - test1: IO <- new Main; - test2: C <- new D; - - main(): IO { out_string("Hello World!")}; +--The static type of the expression must conform to the declared type of the attribute. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + test1: IO <- new Main; + test2: C <- new D; + + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/attributes2_error.txt b/tests/semantic/attributes2_error.txt index 6d601b7cd..d7694b0ad 100644 --- a/tests/semantic/attributes2_error.txt +++ b/tests/semantic/attributes2_error.txt @@ -1 +1 @@ -(10, 17) - TypeError: Inferred type D of initialization of attribute test2 does not conform to declared type C. +(10, 17) - TypeError: Inferred type D of initialization of attribute test2 does not conform to declared type C. diff --git a/tests/semantic/attributes3.cl b/tests/semantic/attributes3.cl index 8a67decd1..0c8294fa2 100644 --- a/tests/semantic/attributes3.cl +++ b/tests/semantic/attributes3.cl @@ -1,25 +1,25 @@ ---Attributes are local to the class in which they are defined or inherited. - -class A { - a: Int <- 5; - test(x1: Int, y1: Int): Int { - let x: Int <- x1, y: Int <-y1 in { - x <- x + a; - y <- y + a; - if b then x + y else x - y fi; - } - }; -}; -class B inherits A { - b: Bool <- true; -}; -class C inherits B { - c: String <- "C"; -}; -class D inherits B { - d: IO <- new Main.main(); -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!") }; +--Attributes are local to the class in which they are defined or inherited. + +class A { + a: Int <- 5; + test(x1: Int, y1: Int): Int { + let x: Int <- x1, y: Int <-y1 in { + x <- x + a; + y <- y + a; + if b then x + y else x - y fi; + } + }; +}; +class B inherits A { + b: Bool <- true; +}; +class C inherits B { + c: String <- "C"; +}; +class D inherits B { + d: IO <- new Main.main(); +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!") }; }; \ No newline at end of file diff --git a/tests/semantic/attributes3_error.txt b/tests/semantic/attributes3_error.txt index 6195c816c..68a2ba571 100644 --- a/tests/semantic/attributes3_error.txt +++ b/tests/semantic/attributes3_error.txt @@ -1 +1 @@ -(9, 16) - NameError: Undeclared identifier b. +(9, 16) - NameError: Undeclared identifier b. diff --git a/tests/semantic/basics1.cl b/tests/semantic/basics1.cl index 32ae16564..af84ca0c9 100644 --- a/tests/semantic/basics1.cl +++ b/tests/semantic/basics1.cl @@ -1,10 +1,10 @@ --- It is an error to redefine the IO class. - -class IO { - scan(): String { ":)" }; - print(s: String): IO { new IO }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; +-- It is an error to redefine the IO class. + +class IO { + scan(): String { ":)" }; + print(s: String): IO { new IO }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/basics1_error.txt b/tests/semantic/basics1_error.txt index 676f5049c..0db23a051 100644 --- a/tests/semantic/basics1_error.txt +++ b/tests/semantic/basics1_error.txt @@ -1 +1 @@ -(3, 7) - SemanticError: Redefinition of basic class IO. +(3, 7) - SemanticError: Redefinition of basic class IO. diff --git a/tests/semantic/basics2.cl b/tests/semantic/basics2.cl index cf2b1cd2f..61399a989 100644 --- a/tests/semantic/basics2.cl +++ b/tests/semantic/basics2.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine Int. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class A inherits Int { - is_prime(): Bool { false }; -}; +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Int { + is_prime(): Bool { false }; +}; diff --git a/tests/semantic/basics2_error.txt b/tests/semantic/basics2_error.txt index 69a3b6814..e2810833a 100644 --- a/tests/semantic/basics2_error.txt +++ b/tests/semantic/basics2_error.txt @@ -1 +1 @@ -(7, 18) - SemanticError: Class A cannot inherit class Int. +(7, 18) - SemanticError: Class A cannot inherit class Int. diff --git a/tests/semantic/basics3.cl b/tests/semantic/basics3.cl index fef017a8d..8c28b31e1 100644 --- a/tests/semantic/basics3.cl +++ b/tests/semantic/basics3.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine Int. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class Int { - is_prime(): Bool { false }; +-- It is an error to inherit from or redefine Int. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Int { + is_prime(): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics3_error.txt b/tests/semantic/basics3_error.txt index d8f80cb12..ed382c8eb 100644 --- a/tests/semantic/basics3_error.txt +++ b/tests/semantic/basics3_error.txt @@ -1 +1 @@ -(7, 7) - SemanticError: Redefinition of basic class Int. +(7, 7) - SemanticError: Redefinition of basic class Int. diff --git a/tests/semantic/basics4.cl b/tests/semantic/basics4.cl index 9266ec79b..4475bc08f 100644 --- a/tests/semantic/basics4.cl +++ b/tests/semantic/basics4.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine String. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class A inherits String { - is_palindrome(): Bool { false }; +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits String { + is_palindrome(): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics4_error.txt b/tests/semantic/basics4_error.txt index d5cd4c3db..bfe08a9a6 100644 --- a/tests/semantic/basics4_error.txt +++ b/tests/semantic/basics4_error.txt @@ -1 +1 @@ -(7, 18) - SemanticError: Class A cannot inherit class String. +(7, 18) - SemanticError: Class A cannot inherit class String. diff --git a/tests/semantic/basics5.cl b/tests/semantic/basics5.cl index bad5eff13..f0d4dafb3 100644 --- a/tests/semantic/basics5.cl +++ b/tests/semantic/basics5.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine String. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class String { - is_palindrome(): Bool { false }; +-- It is an error to inherit from or redefine String. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class String { + is_palindrome(): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics5_error.txt b/tests/semantic/basics5_error.txt index 8437accf7..47b247faa 100644 --- a/tests/semantic/basics5_error.txt +++ b/tests/semantic/basics5_error.txt @@ -1 +1 @@ -(7, 7) - SemanticError: Redefinition of basic class String. +(7, 7) - SemanticError: Redefinition of basic class String. diff --git a/tests/semantic/basics6.cl b/tests/semantic/basics6.cl index 47266ebed..c16572a31 100644 --- a/tests/semantic/basics6.cl +++ b/tests/semantic/basics6.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine Bool. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class A inherits Bool { - xor(b: Bool): Bool { false }; +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class A inherits Bool { + xor(b: Bool): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics6_error.txt b/tests/semantic/basics6_error.txt index b4d22da13..9adf1d488 100644 --- a/tests/semantic/basics6_error.txt +++ b/tests/semantic/basics6_error.txt @@ -1 +1 @@ -(7, 18) - SemanticError: Class A cannot inherit class Bool. +(7, 18) - SemanticError: Class A cannot inherit class Bool. diff --git a/tests/semantic/basics7.cl b/tests/semantic/basics7.cl index 0f30aaec3..38f789245 100644 --- a/tests/semantic/basics7.cl +++ b/tests/semantic/basics7.cl @@ -1,9 +1,9 @@ --- It is an error to inherit from or redefine Bool. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class Bool { - xor(b: Bool): Bool { false }; +-- It is an error to inherit from or redefine Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Bool { + xor(b: Bool): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics7_error.txt b/tests/semantic/basics7_error.txt index 92660ab9f..9f1347200 100644 --- a/tests/semantic/basics7_error.txt +++ b/tests/semantic/basics7_error.txt @@ -1 +1 @@ -(7, 7) - SemanticError: Redefinition of basic class Bool. +(7, 7) - SemanticError: Redefinition of basic class Bool. diff --git a/tests/semantic/basics8.cl b/tests/semantic/basics8.cl index 3b9697d4f..d45cd941d 100644 --- a/tests/semantic/basics8.cl +++ b/tests/semantic/basics8.cl @@ -1,9 +1,9 @@ --- It is an error redefine Object. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - -class Object { - xor(b: Bool): Bool { false }; +-- It is an error redefine Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + +class Object { + xor(b: Bool): Bool { false }; }; \ No newline at end of file diff --git a/tests/semantic/basics8_error.txt b/tests/semantic/basics8_error.txt index 652f47b30..45767c9c5 100644 --- a/tests/semantic/basics8_error.txt +++ b/tests/semantic/basics8_error.txt @@ -1 +1 @@ -(7, 7) - SemanticError: Redefinition of basic class Object. +(7, 7) - SemanticError: Redefinition of basic class Object. diff --git a/tests/semantic/blocks1.cl b/tests/semantic/blocks1.cl index 1e928908b..bad9093d7 100644 --- a/tests/semantic/blocks1.cl +++ b/tests/semantic/blocks1.cl @@ -1,31 +1,31 @@ ---The static type of a block is the static type of the last expression. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: B <- { - new A; - { - new B; - { - new C; - { - new D; - { - new E; - { - new F; - }; - }; - }; - }; - }; - }; +--The static type of a block is the static type of the last expression. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- { + new A; + { + new B; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; }; \ No newline at end of file diff --git a/tests/semantic/blocks1_error.txt b/tests/semantic/blocks1_error.txt index 2f0e2caf3..6bd9d6118 100644 --- a/tests/semantic/blocks1_error.txt +++ b/tests/semantic/blocks1_error.txt @@ -1 +1 @@ -(13, 16) - TypeError: Inferred type F of initialization of attribute test does not conform to declared type B. +(13, 16) - TypeError: Inferred type F of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case1.cl b/tests/semantic/case1.cl index 82c6a4d61..af452f11c 100644 --- a/tests/semantic/case1.cl +++ b/tests/semantic/case1.cl @@ -1,23 +1,23 @@ ---For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- case "true" of - i: Int => New C; - b: Bool => New D; - s: String => New E; - esac; - - test: B <- case 0 of - b: Bool => new F; - i: Int => new E; - esac; -}; +--For each branch, let Ti be the static type of . The static type of a case expression is Join 1≤i≤n Ti. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: B <- case 0 of + b: Bool => new F; + i: Int => new E; + esac; +}; diff --git a/tests/semantic/case1_error.txt b/tests/semantic/case1_error.txt index f05ce31b9..70c7d16ca 100644 --- a/tests/semantic/case1_error.txt +++ b/tests/semantic/case1_error.txt @@ -1 +1 @@ -(19, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. +(19, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/case2.cl b/tests/semantic/case2.cl index ae97b41da..dbbe4148c 100644 --- a/tests/semantic/case2.cl +++ b/tests/semantic/case2.cl @@ -1,23 +1,23 @@ --- The variables declared on each branch of a case must all have distinct types. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- case "true" of - i: Int => New C; - b: Bool => New D; - s: String => New E; - esac; - - test: A <- case 0 of - b: Bool => new F; - i: Bool => new E; - esac; +-- The variables declared on each branch of a case must all have distinct types. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Bool => new E; + esac; }; \ No newline at end of file diff --git a/tests/semantic/case3.cl b/tests/semantic/case3.cl index da79bbfe6..9ff06336a 100644 --- a/tests/semantic/case3.cl +++ b/tests/semantic/case3.cl @@ -1,23 +1,23 @@ --- Missing type - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- case "true" of - i: Int => New C; - b: Bool => New D; - s: String => New E; - esac; - - test: A <- case 0 of - b: Bool => new F; - i: Ball => new E; - esac; +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- case "true" of + i: Int => New C; + b: Bool => New D; + s: String => New E; + esac; + + test: A <- case 0 of + b: Bool => new F; + i: Ball => new E; + esac; }; \ No newline at end of file diff --git a/tests/semantic/class1.cl b/tests/semantic/class1.cl index ed83da9d1..576a3d0eb 100644 --- a/tests/semantic/class1.cl +++ b/tests/semantic/class1.cl @@ -1,9 +1,9 @@ --- Classes may not be redefined. - -class Repeat { - sum(a: Int, b: Int): Int { a + b }; -}; - -class Repeat { - mult(a: Int, b: Int): Int { a * b }; +-- Classes may not be redefined. + +class Repeat { + sum(a: Int, b: Int): Int { a + b }; +}; + +class Repeat { + mult(a: Int, b: Int): Int { a * b }; }; \ No newline at end of file diff --git a/tests/semantic/class1_error.txt b/tests/semantic/class1_error.txt index 19c507672..6337828d0 100644 --- a/tests/semantic/class1_error.txt +++ b/tests/semantic/class1_error.txt @@ -1,2 +1,2 @@ -(7, 5) - SemanticError: Classes may not be redefined - +(7, 5) - SemanticError: Classes may not be redefined + diff --git a/tests/semantic/conditionals1.cl b/tests/semantic/conditionals1.cl index 3446a8b0f..46af8cc73 100644 --- a/tests/semantic/conditionals1.cl +++ b/tests/semantic/conditionals1.cl @@ -1,14 +1,14 @@ ---The predicate must have static type Bool. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - a: A <- if new F then new D else new C fi; +--The predicate must have static type Bool. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- if new F then new D else new C fi; }; \ No newline at end of file diff --git a/tests/semantic/conditionals1_error.txt b/tests/semantic/conditionals1_error.txt index b86345359..52db300b9 100644 --- a/tests/semantic/conditionals1_error.txt +++ b/tests/semantic/conditionals1_error.txt @@ -1 +1 @@ -(13, 16) - TypeError: Predicate of 'if' does not have type Bool. +(13, 16) - TypeError: Predicate of 'if' does not have type Bool. diff --git a/tests/semantic/conditionals2.cl b/tests/semantic/conditionals2.cl index 9d6313d75..8814177fc 100644 --- a/tests/semantic/conditionals2.cl +++ b/tests/semantic/conditionals2.cl @@ -1,24 +1,24 @@ -(* -Let T and F be the static types of the branches of the conditional. Then the static type of the -conditional is T t F. (think: Walk towards Object from each of T and F until the paths meet.) -*) - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- if true then - new C - else - if false then new D - else new E fi - fi; - - test: B <- if not true then new F else new E fi; -}; +(* +Let T and F be the static types of the branches of the conditional. Then the static type of the +conditional is T t F. (think: Walk towards Object from each of T and F until the paths meet.) +*) + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if true then + new C + else + if false then new D + else new E fi + fi; + + test: B <- if not true then new F else new E fi; +}; diff --git a/tests/semantic/conditionals2_error.txt b/tests/semantic/conditionals2_error.txt index d6f5fc307..8f54d195e 100644 --- a/tests/semantic/conditionals2_error.txt +++ b/tests/semantic/conditionals2_error.txt @@ -1,2 +1,2 @@ -(23, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. - +(23, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. + diff --git a/tests/semantic/dispatch1.cl b/tests/semantic/dispatch1.cl index 1c0457fa3..bfd90f075 100644 --- a/tests/semantic/dispatch1.cl +++ b/tests/semantic/dispatch1.cl @@ -1,33 +1,33 @@ -(* -e0 .f(e1, . . . , en ) -Assume e0 has static type A. -Class A must have a method f -*) - -class A inherits IO { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int): Int { v + v + v }; - - back(s: String): B { { - out_string(s); - self; - } }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: B <- new D.back("Hello ").back("World!"); +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.back("Hello ").back("World!"); }; \ No newline at end of file diff --git a/tests/semantic/dispatch1_error.txt b/tests/semantic/dispatch1_error.txt index 7fb22edce..89fa22b77 100644 --- a/tests/semantic/dispatch1_error.txt +++ b/tests/semantic/dispatch1_error.txt @@ -1 +1 @@ -(32, 37) - AttributeError: Dispatch to undefined method back. +(32, 37) - AttributeError: Dispatch to undefined method back. diff --git a/tests/semantic/dispatch2.cl b/tests/semantic/dispatch2.cl index 5182912b8..ebca718ac 100644 --- a/tests/semantic/dispatch2.cl +++ b/tests/semantic/dispatch2.cl @@ -1,34 +1,34 @@ -(* -e0 .f(e1, . . . , en ) -Assume e0 has static type A. -Class A must have a method f -the dispatch and the definition of f must have the same number of arguments -*) - -class A inherits IO { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int): Int { v + v + v }; - - back(s: String): B { { - out_string(s); - self; - } }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: Int <- new D.back("Hello ").g(2, 2); +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the dispatch and the definition of f must have the same number of arguments +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: Int <- new D.back("Hello ").g(2, 2); }; \ No newline at end of file diff --git a/tests/semantic/dispatch2_error.txt b/tests/semantic/dispatch2_error.txt index a86c35340..1530fb82c 100644 --- a/tests/semantic/dispatch2_error.txt +++ b/tests/semantic/dispatch2_error.txt @@ -1 +1 @@ -(33, 39) - SemanticError: Method g called with wrong number of arguments. +(33, 39) - SemanticError: Method g called with wrong number of arguments. diff --git a/tests/semantic/dispatch3.cl b/tests/semantic/dispatch3.cl index ecb1535db..98c19da77 100644 --- a/tests/semantic/dispatch3.cl +++ b/tests/semantic/dispatch3.cl @@ -1,36 +1,36 @@ -(* -e0 .f(e1, . . . , en ) -Assume e0 has static type A. -Class A must have a method f -the static type of the ith actual parameter must conform to the declared type of the ith formal parameter. -*) - -class A inherits IO { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int): Int { v + v + v }; - - back(s: String): B { { - out_string(s); - self; - } }; - - alphabet(a: A, b: B, c: C): D { self }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: B <- new D.alphabet(new D, new D, new D.back("Hello ")).back("World!"); +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +the static type of the ith actual parameter must conform to the declared type of the ith formal parameter. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: B <- new D.alphabet(new D, new D, new D.back("Hello ")).back("World!"); }; \ No newline at end of file diff --git a/tests/semantic/dispatch3_error.txt b/tests/semantic/dispatch3_error.txt index 0def5cf03..77e81db72 100644 --- a/tests/semantic/dispatch3_error.txt +++ b/tests/semantic/dispatch3_error.txt @@ -1 +1 @@ -(35, 45) - TypeError: In call of method alphabet, type B of parameter c does not conform to declared type C. +(35, 45) - TypeError: In call of method alphabet, type B of parameter c does not conform to declared type C. diff --git a/tests/semantic/dispatch4.cl b/tests/semantic/dispatch4.cl index 9cadd8332..604e462a2 100644 --- a/tests/semantic/dispatch4.cl +++ b/tests/semantic/dispatch4.cl @@ -1,36 +1,36 @@ -(* -e0 .f(e1, . . . , en ) -Assume e0 has static type A. -Class A must have a method f -If f has return type B and B is a class name, then the static type of the dispatch is B. -*) - -class A inherits IO { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int): Int { v + v + v }; - - back(s: String): B { { - out_string(s); - self; - } }; - - alphabet(a: A, b: B, c: C): D { self }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: D <- new D.alphabet(new D, new D.back("Hello "), new C).back("World!"); +(* +e0 .f(e1, . . . , en ) +Assume e0 has static type A. +Class A must have a method f +If f has return type B and B is a class name, then the static type of the dispatch is B. +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + + back(s: String): B { { + out_string(s); + self; + } }; + + alphabet(a: A, b: B, c: C): D { self }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: D <- new D.alphabet(new D, new D.back("Hello "), new C).back("World!"); }; \ No newline at end of file diff --git a/tests/semantic/dispatch5.cl b/tests/semantic/dispatch5.cl index b4437b1b4..9820e5ee1 100644 --- a/tests/semantic/dispatch5.cl +++ b/tests/semantic/dispatch5.cl @@ -1,31 +1,31 @@ -(* -(,...,) is shorthand for self.(,...,). -*) - -class A inherits IO { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; - sum(m: Int, n: Int, p: Int): Int { m + n + p }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - - back(s: String): B { { - out_string(s); - g(2); - sum(1, 2, 3); - self; - } }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; +(* +(,...,) is shorthand for self.(,...,). +*) + +class A inherits IO { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + + back(s: String): B { { + out_string(s); + g(2); + sum(1, 2, 3); + self; + } }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/dispatch5_error.txt b/tests/semantic/dispatch5_error.txt index d26bf34a1..6a6922f32 100644 --- a/tests/semantic/dispatch5_error.txt +++ b/tests/semantic/dispatch5_error.txt @@ -1 +1 @@ -(24, 9) - AttributeError: Dispatch to undefined method sum. +(24, 9) - AttributeError: Dispatch to undefined method sum. diff --git a/tests/semantic/dispatch6.cl b/tests/semantic/dispatch6.cl index fcc033f2c..bbe58fbb1 100644 --- a/tests/semantic/dispatch6.cl +++ b/tests/semantic/dispatch6.cl @@ -1,32 +1,32 @@ -(* -e@B.f() invokes the method -f in class B on the object that is the value of e. For this form of dispatch, the static type to the left of -“@”must conform to the type specified to the right of “@”. -*) - -class A { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; - sum(m: Int, n: Int, p: Int): Int { m + n + p }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int): Int { v + v + v }; - sum(v: Int, w: Int, z: Int): Int { v - w - z }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - a: A <- new D; - b: Int <- new D@B.sum(1, 2, 3); - test: Int <- a@B.sum(1, 2, 3); -}; +(* +e@B.f() invokes the method +f in class B on the object that is the value of e. For this form of dispatch, the static type to the left of +“@”must conform to the type specified to the right of “@”. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; + sum(m: Int, n: Int, p: Int): Int { m + n + p }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int): Int { v + v + v }; + sum(v: Int, w: Int, z: Int): Int { v - w - z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: A <- new D; + b: Int <- new D@B.sum(1, 2, 3); + test: Int <- a@B.sum(1, 2, 3); +}; diff --git a/tests/semantic/dispatch6_error.txt b/tests/semantic/dispatch6_error.txt index ae9184b2f..7d5ec3780 100644 --- a/tests/semantic/dispatch6_error.txt +++ b/tests/semantic/dispatch6_error.txt @@ -1 +1 @@ -(31, 18) - TypeError: Expression type A does not conform to declared static dispatch type B. +(31, 18) - TypeError: Expression type A does not conform to declared static dispatch type B. diff --git a/tests/semantic/eq1.cl b/tests/semantic/eq1.cl index 88f2a7ffe..dc8a0cd43 100644 --- a/tests/semantic/eq1.cl +++ b/tests/semantic/eq1.cl @@ -1,17 +1,17 @@ -(* -The comparison = is a special -case. If either or has static type Int, Bool, or String, then the other must have the -same static type. Any other types, including SELF TYPE, may be freely compared. -*) - -class A { }; -class B inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - x: Bool <- 1 = 2; - test: Bool <- 1 = new A; - y: Bool <- "1" = "2"; - z: Bool <- true = not false; +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + test: Bool <- 1 = new A; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; }; \ No newline at end of file diff --git a/tests/semantic/eq1_error.txt b/tests/semantic/eq1_error.txt index f81425683..0b85d2fa0 100644 --- a/tests/semantic/eq1_error.txt +++ b/tests/semantic/eq1_error.txt @@ -1 +1 @@ -(14, 21) - TypeError: Illegal comparison with a basic type. +(14, 21) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq2.cl b/tests/semantic/eq2.cl index d76852780..f4b2ffac7 100644 --- a/tests/semantic/eq2.cl +++ b/tests/semantic/eq2.cl @@ -1,17 +1,17 @@ -(* -The comparison = is a special -case. If either or has static type Int, Bool, or String, then the other must have the -same static type. Any other types, including SELF TYPE, may be freely compared. -*) - -class A { }; -class B inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - x: Bool <- 1 = 2; - y: Bool <- "1" = "2"; - test: Bool <- "1" = new B; - z: Bool <- true = not false; -}; +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + test: Bool <- "1" = new B; + z: Bool <- true = not false; +}; diff --git a/tests/semantic/eq2_error.txt b/tests/semantic/eq2_error.txt index a44ab0d51..1bb29ca32 100644 --- a/tests/semantic/eq2_error.txt +++ b/tests/semantic/eq2_error.txt @@ -1 +1 @@ -(15, 23) - TypeError: Illegal comparison with a basic type. +(15, 23) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq3.cl b/tests/semantic/eq3.cl index 4dad693ee..b7ee462c5 100644 --- a/tests/semantic/eq3.cl +++ b/tests/semantic/eq3.cl @@ -1,17 +1,17 @@ -(* -The comparison = is a special -case. If either or has static type Int, Bool, or String, then the other must have the -same static type. Any other types, including SELF TYPE, may be freely compared. -*) - -class A { }; -class B inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - x: Bool <- 1 = 2; - y: Bool <- "1" = "2"; - z: Bool <- true = not false; - test: Bool <- "true" = not false; -}; +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. +*) + +class A { }; +class B inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- true = not false; + test: Bool <- "true" = not false; +}; diff --git a/tests/semantic/eq3_error.txt b/tests/semantic/eq3_error.txt index c4e27eb8a..d57841b95 100644 --- a/tests/semantic/eq3_error.txt +++ b/tests/semantic/eq3_error.txt @@ -1 +1 @@ -(16, 26) - TypeError: Illegal comparison with a basic type. +(16, 26) - TypeError: Illegal comparison with a basic type. diff --git a/tests/semantic/eq4.cl b/tests/semantic/eq4.cl index 11afc119f..63c1067f0 100644 --- a/tests/semantic/eq4.cl +++ b/tests/semantic/eq4.cl @@ -1,17 +1,17 @@ -(* -The comparison = is a special -case. If either or has static type Int, Bool, or String, then the other must have the -same static type. Any other types, including SELF TYPE, may be freely compared. The result is a Bool. -*) - -class A { }; -class B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - x: Bool <- 1 = 2; - y: Bool <- "1" = "2"; - z: Bool <- new A = new B; - test: Int <- new A = new B; -}; +(* +The comparison = is a special +case. If either or has static type Int, Bool, or String, then the other must have the +same static type. Any other types, including SELF TYPE, may be freely compared. The result is a Bool. +*) + +class A { }; +class B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + x: Bool <- 1 = 2; + y: Bool <- "1" = "2"; + z: Bool <- new A = new B; + test: Int <- new A = new B; +}; diff --git a/tests/semantic/eq4_error.txt b/tests/semantic/eq4_error.txt index 3ead21d0e..f075fecbe 100644 --- a/tests/semantic/eq4_error.txt +++ b/tests/semantic/eq4_error.txt @@ -1 +1 @@ -(16, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. +(16, 18) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type Int. diff --git a/tests/semantic/isvoid1.cl b/tests/semantic/isvoid1.cl index 072720d85..7c3a83a77 100644 --- a/tests/semantic/isvoid1.cl +++ b/tests/semantic/isvoid1.cl @@ -1,26 +1,26 @@ ---evaluates to true if expr is void and evaluates to false if expr is not void. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- if isvoid new F then - new C - else - if false then new D - else new E fi - fi; - - test: B <- isvoid if isvoid new F then - new C - else - if false then new D - else new E fi - fi; +--evaluates to true if expr is void and evaluates to false if expr is not void. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- if isvoid new F then + new C + else + if false then new D + else new E fi + fi; + + test: B <- isvoid if isvoid new F then + new C + else + if false then new D + else new E fi + fi; }; \ No newline at end of file diff --git a/tests/semantic/isvoid1_error.txt b/tests/semantic/isvoid1_error.txt index 0922de909..3fd0157b4 100644 --- a/tests/semantic/isvoid1_error.txt +++ b/tests/semantic/isvoid1_error.txt @@ -1 +1 @@ -(20, 16) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type B. +(20, 16) - TypeError: Inferred type Bool of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let1.cl b/tests/semantic/let1.cl index 26ef63026..9220d3dbc 100644 --- a/tests/semantic/let1.cl +++ b/tests/semantic/let1.cl @@ -1,15 +1,15 @@ ---The type of an initialization expression must conform to the declared type of the identifier. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; - test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: C <- new E in b; +--The type of an initialization expression must conform to the declared type of the identifier. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: C <- new E in b; }; \ No newline at end of file diff --git a/tests/semantic/let1_error.txt b/tests/semantic/let1_error.txt index 16ecf780c..56547dae5 100644 --- a/tests/semantic/let1_error.txt +++ b/tests/semantic/let1_error.txt @@ -1 +1 @@ -(14, 76) - TypeError: Inferred type E of initialization of b does not conform to identifier's declared type C. +(14, 76) - TypeError: Inferred type E of initialization of b does not conform to identifier's declared type C. diff --git a/tests/semantic/let2.cl b/tests/semantic/let2.cl index c5956ead3..2949fb94d 100644 --- a/tests/semantic/let2.cl +++ b/tests/semantic/let2.cl @@ -1,15 +1,15 @@ ---The type of let is the type of the body. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; - test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: A <- new E in b; +--The type of let is the type of the body. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: A <- new E in b; }; \ No newline at end of file diff --git a/tests/semantic/let2_error.txt b/tests/semantic/let2_error.txt index b1e8a365d..3b7c669a3 100644 --- a/tests/semantic/let2_error.txt +++ b/tests/semantic/let2_error.txt @@ -1 +1 @@ -(14, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. +(14, 16) - TypeError: Inferred type A of initialization of attribute test does not conform to declared type B. diff --git a/tests/semantic/let3.cl b/tests/semantic/let3.cl index 8c0670ab8..0a4a9ceaf 100644 --- a/tests/semantic/let3.cl +++ b/tests/semantic/let3.cl @@ -1,15 +1,15 @@ --- Missing type - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; - test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: Cadena in new B; +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + b: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: B <- new E in b; + test: B <- let a: Bool, a: Int <- 5, a: String, a: A <- new F, b: Cadena in new B; }; \ No newline at end of file diff --git a/tests/semantic/loops1.cl b/tests/semantic/loops1.cl index de3a624d2..6a0a81818 100644 --- a/tests/semantic/loops1.cl +++ b/tests/semantic/loops1.cl @@ -1,8 +1,8 @@ ---The predicate must have static type Bool. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - i: Int <- 1; - test: Object <- while "true" loop i <- i + 1 pool; +--The predicate must have static type Bool. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while "true" loop i <- i + 1 pool; }; \ No newline at end of file diff --git a/tests/semantic/loops2.cl b/tests/semantic/loops2.cl index dea69fa14..d52169da7 100644 --- a/tests/semantic/loops2.cl +++ b/tests/semantic/loops2.cl @@ -1,9 +1,9 @@ ---The static type of a loop expression is Object. - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - i: Int <- 1; - test: Object <- while not false loop i <- i + 1 pool; - test2: Int <- while not false loop i <- i + 1 pool; -}; +--The static type of a loop expression is Object. + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + i: Int <- 1; + test: Object <- while not false loop i <- i + 1 pool; + test2: Int <- while not false loop i <- i + 1 pool; +}; diff --git a/tests/semantic/loops2_error.txt b/tests/semantic/loops2_error.txt index 9711cdf6a..ab79de8da 100644 --- a/tests/semantic/loops2_error.txt +++ b/tests/semantic/loops2_error.txt @@ -1 +1 @@ -(8, 19) - TypeError: Inferred type Object of initialization of attribute test2 does not conform to declared type Int. +(8, 19) - TypeError: Inferred type Object of initialization of attribute test2 does not conform to declared type Int. diff --git a/tests/semantic/methods1.cl b/tests/semantic/methods1.cl index d12031970..f4ff07bb0 100644 --- a/tests/semantic/methods1.cl +++ b/tests/semantic/methods1.cl @@ -1,12 +1,12 @@ ---The identifiers used in the formal parameter list must be distinct - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: A, a: B): Int { 4 }; +--The identifiers used in the formal parameter list must be distinct + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, a: B): Int { 4 }; }; \ No newline at end of file diff --git a/tests/semantic/methods1_error.txt b/tests/semantic/methods1_error.txt index 06ab88a92..809036803 100644 --- a/tests/semantic/methods1_error.txt +++ b/tests/semantic/methods1_error.txt @@ -1 +1 @@ -(11, 16) - SemanticError: Formal parameter a is multiply defined. +(11, 16) - SemanticError: Formal parameter a is multiply defined. diff --git a/tests/semantic/methods2.cl b/tests/semantic/methods2.cl index 3865f0e13..c010df01e 100644 --- a/tests/semantic/methods2.cl +++ b/tests/semantic/methods2.cl @@ -1,12 +1,12 @@ ---The type of the method body must conform to the declared return type. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: A, b: B): C { new D }; +--The type of the method body must conform to the declared return type. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): C { new D }; }; \ No newline at end of file diff --git a/tests/semantic/methods2_error.txt b/tests/semantic/methods2_error.txt index f7e4a330d..1a4baea17 100644 --- a/tests/semantic/methods2_error.txt +++ b/tests/semantic/methods2_error.txt @@ -1 +1 @@ -(11, 27) - TypeError: Inferred return type D of method test does not conform to declared return type C. +(11, 27) - TypeError: Inferred return type D of method test does not conform to declared return type C. diff --git a/tests/semantic/methods3.cl b/tests/semantic/methods3.cl index b92faeb97..9aff4d167 100644 --- a/tests/semantic/methods3.cl +++ b/tests/semantic/methods3.cl @@ -1,14 +1,14 @@ ---A formal parameter hides any definition of an attribute of the same name. - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - a: C <- new C; - test(a: D): D { a }; - test2(a: B): C { a }; +--A formal parameter hides any definition of an attribute of the same name. + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + a: C <- new C; + test(a: D): D { a }; + test2(a: B): C { a }; }; \ No newline at end of file diff --git a/tests/semantic/methods3_error.txt b/tests/semantic/methods3_error.txt index 1165b7595..a0f6d9db2 100644 --- a/tests/semantic/methods3_error.txt +++ b/tests/semantic/methods3_error.txt @@ -1 +1 @@ -(13, 22) - TypeError: Inferred return type B of method test2 does not conform to declared return type C. +(13, 22) - TypeError: Inferred return type B of method test2 does not conform to declared return type C. diff --git a/tests/semantic/methods4.cl b/tests/semantic/methods4.cl index be8fa36ef..e093bac1c 100644 --- a/tests/semantic/methods4.cl +++ b/tests/semantic/methods4.cl @@ -1,19 +1,19 @@ -(* -The rule is -simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited -definition of f provided the number of arguments, the types of the formal parameters, and the return -type are exactly the same in both definitions. -*) - -class A { - f(x: Int, y: Int): Int { x + y }; -}; -class B inherits A { - f(x: Int, y: Object): Int { x }; -}; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(x: Int, y: Object): Int { x }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/methods4_error.txt b/tests/semantic/methods4_error.txt index 9f1486dec..c9fc2d12a 100644 --- a/tests/semantic/methods4_error.txt +++ b/tests/semantic/methods4_error.txt @@ -1 +1 @@ -(12, 15) - SemanticError: In redefined method f, parameter type Object is different from original type Int. +(12, 15) - SemanticError: In redefined method f, parameter type Object is different from original type Int. diff --git a/tests/semantic/methods5.cl b/tests/semantic/methods5.cl index 3905dfdd6..732e4d408 100644 --- a/tests/semantic/methods5.cl +++ b/tests/semantic/methods5.cl @@ -1,20 +1,20 @@ -(* -The rule is -simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited -definition of f provided the number of arguments, the types of the formal parameters, and the return -type are exactly the same in both definitions. -*) - -class A { - f(x: Int, y: Int): Int { x + y }; -}; -class B inherits A { - f(a: Int, b: Int): Object { a - b }; -}; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; -}; - +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; +}; +class B inherits A { + f(a: Int, b: Int): Object { a - b }; +}; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; +}; + diff --git a/tests/semantic/methods5_error.txt b/tests/semantic/methods5_error.txt index 8b6bdf36e..073eee8c5 100644 --- a/tests/semantic/methods5_error.txt +++ b/tests/semantic/methods5_error.txt @@ -1 +1 @@ -(12, 24) - SemanticError: In redefined method f, return type Object is different from original return type Int. +(12, 24) - SemanticError: In redefined method f, return type Object is different from original return type Int. diff --git a/tests/semantic/methods6.cl b/tests/semantic/methods6.cl index dd2b73da6..61a62b4b0 100644 --- a/tests/semantic/methods6.cl +++ b/tests/semantic/methods6.cl @@ -1,27 +1,27 @@ -(* -The rule is -simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited -definition of f provided the number of arguments, the types of the formal parameters, and the return -type are exactly the same in both definitions. -*) - -class A { - f(x: Int, y: Int): Int { x + y }; - g(x: Int): Int { x + x }; -}; -class B inherits A { - f(a: Int, b: Int): Int { a - b }; -}; -class C inherits B { - ident(m: Int): Int { m }; - f(m: Int, n: Int): Int { m * n }; -}; -class D inherits B { - ident(v: String): IO { new IO.out_string(v) }; - f(v: Int, w: Int): Int { v / w }; - g(v: Int, w: Int, z: Int): Int { v + w + z }; -}; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; +(* +The rule is +simple: If a class C inherits a method f from an ancestor class P, then C may override the inherited +definition of f provided the number of arguments, the types of the formal parameters, and the return +type are exactly the same in both definitions. +*) + +class A { + f(x: Int, y: Int): Int { x + y }; + g(x: Int): Int { x + x }; +}; +class B inherits A { + f(a: Int, b: Int): Int { a - b }; +}; +class C inherits B { + ident(m: Int): Int { m }; + f(m: Int, n: Int): Int { m * n }; +}; +class D inherits B { + ident(v: String): IO { new IO.out_string(v) }; + f(v: Int, w: Int): Int { v / w }; + g(v: Int, w: Int, z: Int): Int { v + w + z }; +}; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; }; \ No newline at end of file diff --git a/tests/semantic/methods6_error.txt b/tests/semantic/methods6_error.txt index 8e32663b9..70ad02e32 100644 --- a/tests/semantic/methods6_error.txt +++ b/tests/semantic/methods6_error.txt @@ -1 +1 @@ -(22, 5) - SemanticError: Incompatible number of formal parameters in redefined method g. +(22, 5) - SemanticError: Incompatible number of formal parameters in redefined method g. diff --git a/tests/semantic/methods7.cl b/tests/semantic/methods7.cl index e5a01f682..21e8ca275 100644 --- a/tests/semantic/methods7.cl +++ b/tests/semantic/methods7.cl @@ -1,12 +1,12 @@ --- Missing type - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: A, b: Ball): Int { 4 }; +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: Ball): Int { 4 }; }; \ No newline at end of file diff --git a/tests/semantic/methods8.cl b/tests/semantic/methods8.cl index 3fccab54c..121210748 100644 --- a/tests/semantic/methods8.cl +++ b/tests/semantic/methods8.cl @@ -1,12 +1,12 @@ --- Missing type - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: A, b: B): Integrer { 4 }; +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: A, b: B): Integrer { 4 }; }; \ No newline at end of file diff --git a/tests/semantic/new1.cl b/tests/semantic/new1.cl index d007fc03d..40a8b9e9b 100644 --- a/tests/semantic/new1.cl +++ b/tests/semantic/new1.cl @@ -1,31 +1,31 @@ --- Missing type - -class A { }; -class B inherits A { }; -class C inherits B { }; -class D inherits B { }; -class E inherits B { }; -class F inherits A { }; - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test: F <- { - new A; - { - new Ball; - { - new C; - { - new D; - { - new E; - { - new F; - }; - }; - }; - }; - }; - }; +-- Missing type + +class A { }; +class B inherits A { }; +class C inherits B { }; +class D inherits B { }; +class E inherits B { }; +class F inherits A { }; + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test: F <- { + new A; + { + new Ball; + { + new C; + { + new D; + { + new E; + { + new F; + }; + }; + }; + }; + }; + }; }; \ No newline at end of file diff --git a/tests/semantic/self1.cl b/tests/semantic/self1.cl index 3387fd263..399f6ff06 100644 --- a/tests/semantic/self1.cl +++ b/tests/semantic/self1.cl @@ -1,11 +1,11 @@ -(* -But it is an error to assign to self or to bind self in a let, a -case, or as a formal parameter. It is also illegal to have attributes named self. -*) - - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(a: Main): IO { self <- a }; -}; +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(a: Main): IO { self <- a }; +}; diff --git a/tests/semantic/self1_error.txt b/tests/semantic/self1_error.txt index 6beb3cda2..f9f51b9b3 100644 --- a/tests/semantic/self1_error.txt +++ b/tests/semantic/self1_error.txt @@ -1 +1 @@ -(10, 30) - SemanticError: Cannot assign to 'self'. +(10, 30) - SemanticError: Cannot assign to 'self'. diff --git a/tests/semantic/self2.cl b/tests/semantic/self2.cl index 2e6921a92..6ef75e368 100644 --- a/tests/semantic/self2.cl +++ b/tests/semantic/self2.cl @@ -1,10 +1,10 @@ -(* -But it is an error to assign to self or to bind self in a let, a -case, or as a formal parameter. It is also illegal to have attributes named self. -*) - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(): IO { let self: Main <- new Main in self }; -}; +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(): IO { let self: Main <- new Main in self }; +}; diff --git a/tests/semantic/self2_error.txt b/tests/semantic/self2_error.txt index 20c883c91..2e53bb210 100644 --- a/tests/semantic/self2_error.txt +++ b/tests/semantic/self2_error.txt @@ -1 +1 @@ -(9, 22) - SemanticError: 'self' cannot be bound in a 'let' expression. +(9, 22) - SemanticError: 'self' cannot be bound in a 'let' expression. diff --git a/tests/semantic/self3.cl b/tests/semantic/self3.cl index 81709b4b5..d314798a9 100644 --- a/tests/semantic/self3.cl +++ b/tests/semantic/self3.cl @@ -1,10 +1,10 @@ -(* -But it is an error to assign to self or to bind self in a let, a -case, or as a formal parameter. It is also illegal to have attributes named self. -*) - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - test(self: IO): IO { self }; -}; +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + test(self: IO): IO { self }; +}; diff --git a/tests/semantic/self3_error.txt b/tests/semantic/self3_error.txt index 0ae382007..0015bbe0a 100644 --- a/tests/semantic/self3_error.txt +++ b/tests/semantic/self3_error.txt @@ -1 +1 @@ -(9, 10) - SemanticError: 'self' cannot be the name of a formal parameter. +(9, 10) - SemanticError: 'self' cannot be the name of a formal parameter. diff --git a/tests/semantic/self4.cl b/tests/semantic/self4.cl index 7c2b960cb..9185c8760 100644 --- a/tests/semantic/self4.cl +++ b/tests/semantic/self4.cl @@ -1,10 +1,10 @@ -(* -But it is an error to assign to self or to bind self in a let, a -case, or as a formal parameter. It is also illegal to have attributes named self. -*) - -class Main inherits IO { - main(): IO { out_string("Hello World!")}; - - self: IO <- self; +(* +But it is an error to assign to self or to bind self in a let, a +case, or as a formal parameter. It is also illegal to have attributes named self. +*) + +class Main inherits IO { + main(): IO { out_string("Hello World!")}; + + self: IO <- self; }; \ No newline at end of file diff --git a/tests/semantic/self4_error.txt b/tests/semantic/self4_error.txt index c19ca400f..bf8740604 100644 --- a/tests/semantic/self4_error.txt +++ b/tests/semantic/self4_error.txt @@ -1 +1 @@ -(9, 5) - SemanticError: 'self' cannot be the name of an attribute. +(9, 5) - SemanticError: 'self' cannot be the name of an attribute. diff --git a/tests/semantic_test.py b/tests/semantic_test.py index cac9cd78b..215d4302f 100644 --- a/tests/semantic_test.py +++ b/tests/semantic_test.py @@ -11,4 +11,7 @@ @pytest.mark.parametrize("cool_file", tests) def test_semantic_errors(compiler_path, cool_file): compare_errors(compiler_path, tests_dir + cool_file, tests_dir + cool_file[:-3] + '_error.txt', \ - cmp=first_error_only_line) \ No newline at end of file + cmp=first_error_only_line) + +# if __name__ == "__main__": +# pytest.main(["-m", "semantic"]) \ No newline at end of file diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 961cf7cbc..71983839d 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -45,7 +45,8 @@ def get_file_name(path: str): def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str, cmp=first_error, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + # sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) return_code, output = sp.returncode, sp.stdout.decode() except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -67,7 +68,8 @@ def compare_errors(compiler_path: str, cool_file_path: str, error_file_path: str (?:Loaded: .+\n)*''' def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: str, output_file_path: str, timeout=100): try: - sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + # sp = subprocess.run(['bash', compiler_path, cool_file_path], capture_output=True, timeout=timeout) + sp = subprocess.run(['bash', compiler_path, cool_file_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) except subprocess.TimeoutExpired: assert False, COMPILER_TIMEOUT @@ -76,7 +78,8 @@ def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: st try: fd = open(input_file_path, 'rb') - sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) + # sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), capture_output=True, timeout=timeout) + sp = subprocess.run(['spim', '-file', spim_file], input=fd.read(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) fd.close() mo = re.match(SPIM_HEADER, sp.stdout.decode()) if mo: @@ -89,3 +92,22 @@ def compare_outputs(compiler_path: str, cool_file_path: str, input_file_path: st fd.close() assert output == eoutput, UNEXPECTED_OUTPUT % (spim_file, repr(output), repr(eoutput)) + +def compare_outputs_icil(main_path: str, cool_file_path: str, input_file_path: str, output_file_path, timeout=100): + out_file = cool_file_path + '.cil' + fd = open(input_file_path, 'rb') + + try: + # sp = subprocess.run(['python3', compiler_path, cool_file_path, out_file, '-icil', '-c'], capture_output=True, timeout=timeout) + sp = subprocess.run(['python3', main_path, cool_file_path, out_file, '-icil', '-c'], input=fd.read(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + assert sp.returncode == 0, TEST_MUST_COMPILE % get_file_name(cool_file_path) + except subprocess.TimeoutExpired: + assert False, COMPILER_TIMEOUT + + output = sp.stdout.decode() + + fd = open(output_file_path, 'r') + eoutput = fd.read() + fd.close() + + assert output == eoutput, UNEXPECTED_OUTPUT % (cool_file_path, repr(output), repr(eoutput)) \ No newline at end of file