├── .coveragerc
├── .gitignore
├── .travis.yml
├── INSTALL.rst
├── LICENSE
├── MANIFEST.in
├── README.rst
├── appveyor.yml
├── data
├── icons
│ ├── logo-32x32.png
│ ├── logo-64x64.png
│ ├── pytuga.svg
│ └── text-x-pytuga.svg
├── mime
│ ├── pynguin.mime
│ └── pynguin.sharedmimeinfo
├── pytg.xml
├── pytuga-avatar.svg
├── pytuga-logo.png
├── pytuga-simple-logo.svg
├── pytuga.desktop
└── pytuga.lang
├── dependencies.txt
├── docs
├── Makefile
├── conf.py
├── dev.rst
├── index.rst
├── install.rst
├── license.rst
├── python.rst
├── referencia.rst
└── tutorial.rst
├── requirements.txt
├── setup.py
├── src
└── pytuga
│ ├── __init__.py
│ ├── __main__.py
│ ├── assets
│ ├── kernel.js
│ ├── logo-32x32.png
│ └── logo-64x64.png
│ ├── curses.py
│ ├── keywords.py
│ ├── lexer.py
│ └── transpyler.py
├── tests
├── __init__.py
├── _test_documentation.py
├── test_core.py
├── test_errors.py
├── test_keywords.py
├── test_language.py
├── test_pytugacore.py
├── test_runtime.py
├── test_tuga_io.py
├── test_tuga_math.py
└── test_tuga_std.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | include = src/*
3 | branch = True
4 |
5 |
6 | [report]
7 | # Regexes for lines to exclude from consideration
8 | exclude_lines =
9 | # Have to re-enable the standard pragma
10 | pragma: no cover
11 |
12 | # Don't complain about missing debug-only code:
13 | def __repr__
14 | if self\.debug
15 |
16 | # Don't complain if tests don't hit defensive assertion code:
17 | raise AssertionError
18 | raise NotImplementedError
19 | return NotImplemented
20 |
21 | # Don't complain if non-runnable code isn't run:
22 | if 0:
23 | if False:
24 | if __name__ == .__main__.:
25 | while 0:
26 | while False:
27 |
28 | ignore_errors = True
29 |
30 |
31 | [paths]
32 | source = src/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Cached builds
2 | __pycache__/
3 | *.pyc
4 | *.pyo
5 | *.pyd
6 | *.so
7 | *.dll
8 | *.egg
9 | *.egg-info/
10 | .cache/
11 | .coverage
12 | .coverage.xml
13 |
14 | # Build directories
15 | docs/_build/
16 | build/
17 | dist/
18 |
19 | # Python-boilerplate auto generated files
20 | src/transpyler/__meta__.py
21 |
22 | # IDEs
23 | .idea/
24 | .settings/
25 |
26 | # Testing and temporary files
27 | .tox/
28 | .pytest_cache/
29 |
30 | # MAC OS files
31 | .DS_Store
32 |
33 | # Coverage
34 | htmlcov/
35 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | cache: pip
3 | dist: trusty
4 |
5 | # Environment variables
6 | env:
7 | TEST_QT=false
8 |
9 | # Test environments
10 | matrix:
11 | include:
12 | - env: TOXENV=py34
13 | python: 3.4
14 | #- env: TOXENV=py35
15 | # python: 3.5
16 | #- env: TOXENV=py36
17 | # python: 3.6
18 |
19 | # Prepare installation
20 | addons:
21 | apt:
22 | sources:
23 | sdfsd
24 |
25 |
26 | before_install:
27 | - sudo apt-get update
28 | - sudo apt-get -qq install python3-pyqt5 python3-pyqt5.qsci
29 |
30 | # Package installation
31 | install:
32 | - apt-get install python3-pyqt5
33 | - pip install tox codecov
34 |
35 | # Run tests
36 | script:
37 | - tox
38 |
39 | # Register code coverage in coveralls
40 | after_success:
41 | - codecov
--------------------------------------------------------------------------------
/INSTALL.rst:
--------------------------------------------------------------------------------
1 | ==========
2 | Instalação
3 | ==========
4 |
5 |
6 | Pytuguês se baseia e é implementado em Python 3. Antes da instalação completa do
7 | Pytuguês, é necessário instalar antes algumas bibliotecas adicionais
8 | do Python. As instruções de instalação diferem ligeiramente em cada plataforma.
9 |
10 |
11 | -----
12 | Linux
13 | -----
14 |
15 | Você precisa do Python3 e do PyQt5. Existe uma chance razoável que ambos
16 | estejam instalados. Se sua distribuição for baseada no Debian/Ubuntu,
17 | basta fazer download do arquivo dependencies.txt e executar o comando abaixo
18 | para que todas as bibliotecas necessárias sejam instaladas::
19 |
20 | $ sudo apt-get install $(cat dependencies.txt)
21 |
22 | Se quiser apenas fazer a instalação local, o comando fica::
23 |
24 | $ pip3 install pytuga --user
25 |
26 | (Ignore a opção --user, caso queira instalar para todos os usuários. Neste caso
27 | é necessário executar o comando como *sudo*.). Uma vez instalado, você pode
28 | atualizar a versão do Pytuguês executando::
29 |
30 | $ pip3 install pytuga -U --user
31 |
32 | O script de instalação salva os arquivos executáveis na pasta ``~/.local/bin.``
33 | e na pasta ``~/bin/``, se a mesma existir.
34 |
35 |
36 | -------
37 | Windows
38 | -------
39 |
40 | Existem duas opções de instalação no Windows. A primeira funciona somente para
41 | o Windows 64bits e consiste em baixar o arquivo auto-executável do pytuga__.
42 | Baixe este arquivo em qualquer lugar do seu computador e execute-o com um clique
43 | duplo.
44 |
45 | .. __: http://tinyurl.com/pytg-exe
46 |
47 | A segunda opção consiste em baixar os pacotes do Python 3.4 e PyQt5 manualmente
48 | e realizar a instalação via pip. Para isto, escolha os instaladores correspondentes
49 | à sua versão do windows.
50 |
51 | 32 bits
52 | -------
53 |
54 | * `Python 3.4`__
55 | * PyQt5__
56 |
57 | .. __: https://www.python.org/ftp/python/3.4.4/python-3.4.4.msi
58 | .. __: https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x32.exe
59 |
60 |
61 | 64 bits
62 | -------
63 |
64 | * `Python 3.4`__
65 | * PyQt5__
66 |
67 | .. __: https://www.python.org/ftp/python/3.4.4/python-3.4.4.amd64.msi
68 | .. __: https://sourceforge.net/projects/pyqt/files/PyQt5/PyQt-5.5.1/PyQt5-5.5.1-gpl-Py3.4-Qt5.5.1-x64.exe
69 |
70 | É importante marcar a opção "Add python.exe to your path" durante a instalação.
71 | Isto facilitará a execução do Pytuguês posteriormente. Depois de terminada a
72 | instalação, abra o terminal do Windows (Win+R e digite "cmd") e execute os
73 | comandos::
74 |
75 | python -m pip install pytuga -U
76 |
77 | Se o código anterior não funcionar, provavelmente significa que o Python não
78 | está no caminho padrão de procura do Windows. Se este for o caso, é necessário
79 | mudar para o diretório onde o Python estiver instalado. Digite::
80 |
81 | cd c:\Python34\
82 |
83 | Agora repita os comandos anteriores. Se você decidiu instalar o Python em
84 | outro caminho, modifique o comando acima para indicar o caminho correto.
85 |
86 | Para executar em modo gráfico, aperte Win+R e digite "pytuga" no prompt. Caso
87 | isto não funcione (especialmente nas versões mais novas do Windows), procure
88 | o executável do tugalinhas na pasta ``c:\Python34\Scripts\`` ou execute o
89 | comando ``python -m pytuga`` do terminal.
90 |
91 | ==========
92 | Configurando Ambiente de Desenvolvimento
93 | ==========
94 |
95 | Para contribuir deve-se usar git clone e fork nos projetos transpyler, qturtle e pytuga no link
96 | oficial do repositório https://github.com/Transpyler::
97 |
98 | $ git clone url_your_fork.git
99 |
100 | Em cada um você pode adicionar o remote do repositório oficial, para manter seu fork sempre
101 | atualizado::
102 |
103 | $ git remote add upstream url_oficial_repo.git
104 |
105 | Uma vez clonado os três repositórios, na ordem transpyler qturtle pytuga,
106 | execute o seguinte comando::
107 |
108 | $ python3 setup.py develop --user
109 |
110 | Atenção: A sequência de instalação *transpyler - qturtle - pytuga* deve ser obedecida,
111 | pois garante a integridade das dependencias.
112 |
113 | Caso queira desinstalar, basta::
114 |
115 | pip3 uninstall pytuga transpyler qturtle
116 |
117 | Então você pode executar usando::
118 |
119 | $ pytuga
120 |
121 | Ou como módulo do python::
122 |
123 | $ python3 -m pytuga
124 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Pytuga. Um Python com sotaque lusitano.
2 | Copyright (C) 2017 Fábio Macêdo Mendes
3 |
4 | This program is free software: you can redistribute it and/or modify it under
5 | the terms of the GNU General Public License as published by the Free Software
6 | Foundation, either version 3 of the License, or (at your option) any later
7 | version.
8 |
9 | This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 |
13 | You should have received a copy of the GNU General Public License along with
14 | this program. If not, see .
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include VERSION
2 | include README.rst
3 | include INSTALL.rst
4 | include setup.cfg
5 | recursive-include data *.*
6 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. image:: https://travis-ci.org/pwener/pytuga.svg?branch=master
2 | :target: https://travis-ci.org/pwener/pytuga
3 |
4 | .. image:: https://codecov.io/gh/transpyler-mes/pytuga/branch/master/graph/badge.svg
5 | :target: https://codecov.io/gh/transpyler-mes/pytuga
6 |
7 | ========
8 | Pytuguês
9 | ========
10 |
11 | Pytuguês é uma versão da linguagem de programação Python que tenta se aproximar
12 | o máximo possível de um *pseudo-código* em português. A motivação principal em
13 | aprender Pytuguês é evitar as barreiras com a língua inglesa quando iniciamos
14 | a aprender programação. Uma vantagem do Pytuguês com relação a outras soluções
15 | semelhantes é que a transição para uma linguagem de programação de uso comum é
16 | bastante suave, já que é possível misturar código Python e Pytuguês no mesmo
17 | programa.
18 |
19 | A sintaxe da linguagem de programação Python muitas vezes é comparada a um
20 | *pseudo-código* ou algorítimo executável. Ainda que existam alguns recursos
21 | sintáticos avançados que certamente violam esta simplicidade, o Python
22 | provavelmente é uma das linguagens de programação de uso geral com a sintaxe
23 | mais próxima da linguagem natural. Programas em Python frequentemente se
24 | assemelham muito a uma descrição (em inglês) do algorítmo que ele implementa.
25 | Com o Pytuguês, esta facilidade também se aplica aos falantes da língua de
26 | Camões.
27 |
28 | Assim como o Python, o Pytuguês é uma linguagem dinâmica que não precisa ser
29 | compilada. O código é executado diretamente pelo interpretador ou ainda pode
30 | ser criado em modo interativo no estilo REPL (read/eval/print/loop, do inglês
31 | loop de ler, avaliar e imprimir). Neste modo, o interpretador executa
32 | imediatamente os comandos digitados pelo usuário e já mostra o resultado na
33 | tela.
34 |
35 | Este pacote instala o "pytuga", que consiste em um ambiente de programação
36 | visual, no estilo da linguagem LOGO. Para começar sua interação com o Pytuguês,
37 | execute no prompt
38 | ``$ pytuga``. Uma vez aberta a janela do terminal de Pytuguês, digite o
39 | comando::
40 |
41 | >>> mostre("olá, mundo!")
42 |
43 | Boa programação!
44 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # We are using Appveyor.io to build our Windows Python packages. Check
2 | # instructions at https://packaging.python.org/appveyor
3 | environment:
4 | global:
5 | TEST_QT: false
6 | matrix:
7 | #- PYTHON: "C:\\Python34"
8 | # TOXENV: 'py34'
9 |
10 | #- PYTHON: "C:\\Python34-x64"
11 | # TOXENV: 'py34'
12 |
13 | #- PYTHON: "C:\\Python35"
14 | # TOXENV: 'py35'
15 |
16 | #- PYTHON: "C:\\Python35-x64"
17 | # TOXENV: 'py35'
18 |
19 | - PYTHON: "C:\\Python36"
20 | TOXENV: 'py36'
21 |
22 | - PYTHON: "C:\\Python36-x64"
23 | TOXENV: 'py36'
24 |
25 | install:
26 | - "%PYTHON%\\python.exe -m pip install pip -U --user"
27 | - "%PYTHON%\\python.exe -m pip install tox wheel cx_Freeze pynsist PyQt5 --user"
28 | - "%PYTHON%\\python.exe -m pip install pytugacore --user"
29 | - "%PYTHON%\\python.exe -m pip install qturtle --user"
30 | - "%PYTHON%\\python.exe -m pip install pygments --user"
31 | - "%PYTHON%\\python.exe -m pip install -e . --user"
32 |
33 | build_script:
34 | - ECHO "skip build"
35 | #- "%PYTHON%\\python.exe setup.py build"
36 |
37 | test_script:
38 | - ECHO "skip test"
39 | #- "%PYTHON%\\python.exe -m tox"
40 |
41 | after_test:
42 | - '%PYTHON%\\python.exe setup.py build_exe --cx-freeze'
43 | - '%PYTHON%\\python.exe setup.py bdist_msi --cx-freeze'
44 | - ps: "mv build/exe* build/pytuga"
45 | - "%PYTHON%\\python.exe -m zipfile -c pytuga.zip build/pytuga/"
46 | - ps: "mv pytuga.zip dist/"
47 | #- "%PYTHON%\\python.exe -m nsist installer.cfg"
48 | #- "%PYTHON%\\python.exe setup.py bdist_wininst"
49 | #- "%PYTHON%\\python.exe setup.py bdist_wheel"
50 |
51 | artifacts:
52 | - path: dist\*
53 |
54 | #on_success:
55 | # - TODO: upload the content of dist/*.whl to a public wheelhouse
56 |
--------------------------------------------------------------------------------
/data/icons/logo-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/data/icons/logo-32x32.png
--------------------------------------------------------------------------------
/data/icons/logo-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/data/icons/logo-64x64.png
--------------------------------------------------------------------------------
/data/icons/pytuga.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
203 |
--------------------------------------------------------------------------------
/data/icons/text-x-pytuga.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
203 |
--------------------------------------------------------------------------------
/data/mime/pynguin.mime:
--------------------------------------------------------------------------------
1 | application/x-pytuga; pytuga %s; ; test=test -n "$DISPLAY"
2 |
--------------------------------------------------------------------------------
/data/mime/pynguin.sharedmimeinfo:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pytuga
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/data/pytg.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/data/pytuga-avatar.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
379 |
--------------------------------------------------------------------------------
/data/pytuga-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/data/pytuga-logo.png
--------------------------------------------------------------------------------
/data/pytuga-simple-logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
409 |
--------------------------------------------------------------------------------
/data/pytuga.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Encoding=UTF-8
3 | MimeType=text/plain;
4 | Type=Application
5 | Exec=tugalinhas %u
6 | Icon=pytuga
7 | Comment=Pytuguês programming language
8 | Terminal=false
9 | Name=Pytuga
10 | Categories=Application;ComputerScience;Education;
11 | GenericName=Pytuguês programming language
12 | GenericName[pt_BR]=Programação em português
13 |
--------------------------------------------------------------------------------
/data/pytuga.lang:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
26 | *.pytg
27 | #
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | [_a-zA-Z][_a-zA-Z0-9]*
50 | [1-9][0-9]*
51 |
52 |
53 | (b|B)?
54 | (r|R|rb|RB|rB|Rb|br|BR|bR|Br)
55 |
56 |
57 | \%{string-prefix}"""
58 | """
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | \%{string-prefix}'''
67 | '''
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | \%{string-prefix}"
76 | "
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | \%{string-prefix}'
86 | '
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | \%{raw-string-prefix}"""
96 | """
97 |
98 |
99 |
100 |
101 |
102 |
103 | \%{raw-string-prefix}'''
104 | '''
105 |
106 |
107 |
108 |
109 |
110 |
111 | \%{raw-string-prefix}"
112 | "
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | \%{raw-string-prefix}'
121 | '
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 | (?<![\w\.])0[bB][0-1]+[lL]?(?![\w\.])
154 |
155 |
156 |
157 | (?<![\w\.])0[oO][0-7]+[lL]?(?![\w\.])
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 | nonlocal
167 |
168 |
169 | repetir
170 | vezes
171 | faça
172 | para
173 | cada
174 | de
175 | até
176 | a
177 | em
178 | ou
179 | e
180 | não
181 | é
182 | definir
183 | defina
184 | repita
185 | função
186 | enquanto
187 | se
188 | então
189 | senão
190 |
191 |
192 |
193 |
194 |
195 | (?<![\w\.])
196 | ResourceWarning
197 |
198 |
199 |
200 |
201 | (?<![\w\.])
202 | ascii
203 | bin
204 | bytearray
205 | bytes
206 | exec
207 | format
208 | memoryview
209 | next
210 | print
211 |
212 |
213 | (?<![\w\.])
214 | mostre
215 | mostrar
216 | leia_texto
217 | ler_texto
218 | leia_número
219 | ler_número
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
--------------------------------------------------------------------------------
/dependencies.txt:
--------------------------------------------------------------------------------
1 | python3-all
2 | python3-pyqt5
3 | python3-pyqt5.qsci
4 | python3-pyqt5.qtsvg
5 | python3-pyqt5.qtwebkit
6 | python3-pip
7 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | #
2 | # Makefile for Sphinx documentation
3 | #
4 |
5 | # You can set these variables from the command line.
6 | SPHINXOPTS =
7 | SPHINXBUILD = sphinx-build
8 | PAPER =
9 | BUILDDIR = build
10 |
11 | # Internal variables.
12 | PAPEROPT_a4 = -D latex_paper_size=a4
13 | PAPEROPT_letter = -D latex_paper_size=letter
14 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
15 |
16 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
17 |
18 | help:
19 | @echo "Please use \`make ' where is one of"
20 | @echo " html to make standalone HTML files"
21 | @echo " dirhtml to make HTML files named index.html in directories"
22 | @echo " singlehtml to make a single large HTML file"
23 | @echo " pickle to make pickle files"
24 | @echo " json to make JSON files"
25 | @echo " htmlhelp to make HTML files and a HTML help project"
26 | @echo " qthelp to make HTML files and a qthelp project"
27 | @echo " devhelp to make HTML files and a Devhelp project"
28 | @echo " epub to make an epub"
29 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
30 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
31 | @echo " text to make text files"
32 | @echo " man to make manual pages"
33 | @echo " changes to make an overview of all changed/added/deprecated items"
34 | @echo " linkcheck to check all external links for integrity"
35 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
36 |
37 | clean:
38 | -rm -rf $(BUILDDIR)/*
39 |
40 | html:
41 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
42 | @echo
43 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
44 |
45 | dirhtml:
46 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
47 | @echo
48 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
49 |
50 | singlehtml:
51 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
52 | @echo
53 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
54 |
55 | pickle:
56 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
57 | @echo
58 | @echo "Build finished; now you can process the pickle files."
59 |
60 | json:
61 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
62 | @echo
63 | @echo "Build finished; now you can process the JSON files."
64 |
65 | htmlhelp:
66 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
67 | @echo
68 | @echo "Build finished; now you can run HTML Help Workshop with the" \
69 | ".hhp project file in $(BUILDDIR)/htmlhelp."
70 |
71 | qthelp:
72 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
73 | @echo
74 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
75 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
76 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/FGAme.qhcp"
77 | @echo "To view the help file:"
78 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/FGAme.qhc"
79 |
80 | devhelp:
81 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
82 | @echo
83 | @echo "Build finished."
84 | @echo "To view the help file:"
85 | @echo "# mkdir -p $$HOME/.local/share/devhelp/FGAme"
86 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/FGAme"
87 | @echo "# devhelp"
88 |
89 | epub:
90 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
91 | @echo
92 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
93 |
94 | latex:
95 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
96 | @echo
97 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
98 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
99 | "(use \`make latexpdf' here to do that automatically)."
100 |
101 | latexpdf:
102 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
103 | @echo "Running LaTeX files through pdflatex..."
104 | make -C $(BUILDDIR)/latex all-pdf
105 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
106 |
107 | text:
108 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
109 | @echo
110 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
111 |
112 | man:
113 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
114 | @echo
115 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
116 |
117 | changes:
118 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
119 | @echo
120 | @echo "The overview file is in $(BUILDDIR)/changes."
121 |
122 | linkcheck:
123 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
124 | @echo
125 | @echo "Link check complete; look for any errors in the above output " \
126 | "or in $(BUILDDIR)/linkcheck/output.txt."
127 |
128 | doctest:
129 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
130 | @echo "Testing of doctests in the sources finished, look at the " \
131 | "results in $(BUILDDIR)/doctest/output.txt."
132 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # pytuga documentation build configuration file, created by
4 | # sphinx-quickstart on Wed Sep 16 22:39:01 2015.
5 | #
6 | # This file is execfile()d with the current directory set to its
7 | # containing dir.
8 | #
9 | # Note that not all possible configuration values are present in this
10 | # autogenerated file.
11 | #
12 | # All configuration values have a default; values that are commented out
13 | # serve to show the default.
14 |
15 | import os
16 |
17 | # If extensions (or modules to document with autodoc) are in another directory,
18 | # add these directories to sys.path here. If the directory is relative to the
19 | # documentation root, use os.path.abspath to make it absolute, like shown here.
20 | #sys.path.insert(0, os.path.abspath('.'))
21 |
22 | # -- General configuration ------------------------------------------------
23 |
24 | # If your documentation needs a minimal Sphinx version, state it here.
25 | #needs_sphinx = '1.0'
26 |
27 | # Add any Sphinx extension module names here, as strings. They can be
28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
29 | # ones.
30 | extensions = [
31 | 'sphinx.ext.autodoc',
32 | 'sphinx.ext.napoleon',
33 | 'sphinx.ext.doctest',
34 | 'sphinx.ext.intersphinx',
35 | 'sphinx.ext.todo',
36 | 'sphinx.ext.imgmath',
37 | ]
38 |
39 | # Add any paths that contain templates here, relative to this directory.
40 | templates_path = ['_templates']
41 |
42 | # The suffix(es) of source filenames.
43 | # You can specify multiple suffix as a list of string:
44 | # source_suffix = ['.rst', '.md']
45 | source_suffix = '.rst'
46 |
47 | # The encoding of source files.
48 | #source_encoding = 'utf-8-sig'
49 |
50 | # The master toctree document.
51 | master_doc = 'index'
52 |
53 | # General information about the project.
54 | project = u'pytuga'
55 | copyright = u'2015, Fábio Macêdo Mendes'
56 | author = u'Fábio Macêdo Mendes'
57 |
58 | # The version info for the project you're documenting, acts as replacement for
59 | # |version| and |release|, also used in various other places throughout the
60 | # built documents.
61 | #
62 | # The short X.Y version.
63 | proj_root = os.path.dirname(os.path.dirname(__file__))
64 | version = open(os.path.join(proj_root, 'VERSION')).read().strip()
65 |
66 | # The full version, including alpha/beta/rc tags.
67 | release = version
68 |
69 | # The language for content autogenerated by Sphinx. Refer to documentation
70 | # for a list of supported languages.
71 | #
72 | # This is also used if you do content translation via gettext catalogs.
73 | # Usually you set "language" from the command line for these cases.
74 | language = 'pt'
75 |
76 | # There are two options for replacing |today|: either, you set today to some
77 | # non-false value, then it is used:
78 | #today = ''
79 | # Else, today_fmt is used as the format for a strftime call.
80 | #today_fmt = '%B %d, %Y'
81 |
82 | # List of patterns, relative to source directory, that match files and
83 | # directories to ignore when looking for source files.
84 | exclude_patterns = []
85 |
86 | # The reST default role (used for this markup: `text`) to use for all
87 | # documents.
88 | #default_role = None
89 |
90 | # If true, '()' will be appended to :func: etc. cross-reference text.
91 | add_function_parentheses = True
92 |
93 | # If true, the current module name will be prepended to all description
94 | # unit titles (such as .. function::).
95 | add_module_names = False
96 |
97 | # If true, sectionauthor and moduleauthor directives will be shown in the
98 | # output. They are ignored by default.
99 | #show_authors = False
100 |
101 | # The name of the Pygments (syntax highlighting) style to use.
102 | pygments_style = None
103 |
104 | # A list of ignored prefixes for module index sorting.
105 | #modindex_common_prefix = []
106 |
107 | # If true, keep warnings as "system message" paragraphs in the built documents.
108 | #keep_warnings = False
109 |
110 | # If true, `todo` and `todoList` produce output, else they produce nothing.
111 | todo_include_todos = True
112 |
113 |
114 | # -- Options for HTML output ----------------------------------------------
115 |
116 | # The theme to use for HTML and HTML Help pages. See the documentation for
117 | # a list of builtin themes.
118 | # html_theme = 'alabaster'
119 | html_theme = 'sphinx_rtd_theme'
120 |
121 | # Theme options are theme-specific and customize the look and feel of a theme
122 | # further. For a list of options available for each theme, see the
123 | # documentation.
124 | #html_theme_options = {}
125 |
126 | # Add any paths that contain custom themes here, relative to this directory.
127 | #html_theme_path = []
128 |
129 | # The name for this set of Sphinx documents. If None, it defaults to
130 | # " v documentation".
131 | #html_title = None
132 |
133 | # A shorter title for the navigation bar. Default is the same as html_title.
134 | #html_short_title = None
135 |
136 | # The name of an image file (relative to this directory) to place at the top
137 | # of the sidebar.
138 | #html_logo = None
139 |
140 | # The name of an image file (within the static path) to use as favicon of the
141 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
142 | # pixels large.
143 | #html_favicon = None
144 |
145 | # Add any paths that contain custom static files (such as style sheets) here,
146 | # relative to this directory. They are copied after the builtin static files,
147 | # so a file named "default.media" will overwrite the builtin "default.media".
148 | html_static_path = ['_static']
149 |
150 | # Add any extra paths that contain custom files (such as robots.txt or
151 | # .htaccess) here, relative to this directory. These files are copied
152 | # directly to the root of the documentation.
153 | #html_extra_path = []
154 |
155 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
156 | # using the given strftime format.
157 | #html_last_updated_fmt = '%b %d, %Y'
158 |
159 | # If true, SmartyPants will be used to convert quotes and dashes to
160 | # typographically correct entities.
161 | #html_use_smartypants = True
162 |
163 | # Custom sidebar templates, maps document names to template names.
164 | #html_sidebars = {}
165 |
166 | # Additional templates that should be rendered to pages, maps page names to
167 | # template names.
168 | #html_additional_pages = {}
169 |
170 | # If false, no module index is generated.
171 | #html_domain_indices = True
172 |
173 | # If false, no index is generated.
174 | #html_use_index = True
175 |
176 | # If true, the index is split into individual pages for each letter.
177 | #html_split_index = False
178 |
179 | # If true, links to the reST sources are added to the pages.
180 | #html_show_sourcelink = True
181 |
182 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
183 | #html_show_sphinx = True
184 |
185 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
186 | #html_show_copyright = True
187 |
188 | # If true, an OpenSearch description file will be output, and all pages will
189 | # contain a tag referring to it. The value of this option must be the
190 | # base URL from which the finished HTML is served.
191 | #html_use_opensearch = ''
192 |
193 | # This is the file name suffix for HTML files (e.g. ".xhtml").
194 | #html_file_suffix = None
195 |
196 | # Language to be used for generating the HTML full-text search index.
197 | # Sphinx supports the following languages:
198 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
199 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
200 | html_search_language = 'pt'
201 |
202 | # A dictionary with options for the search language support, empty by default.
203 | # Now only 'ja' uses this config value
204 | #html_search_options = {'type': 'default'}
205 |
206 | # The name of a javascript file (relative to the configuration directory) that
207 | # implements a search results scorer. If empty, the default will be used.
208 | #html_search_scorer = 'scorer.js'
209 |
210 | # Output file base name for HTML help builder.
211 | htmlhelp_basename = 'pytugadoc'
212 |
213 | # -- Options for LaTeX output ---------------------------------------------
214 |
215 | latex_elements = {
216 | # The paper size ('letterpaper' or 'a4paper').
217 | #'papersize': 'letterpaper',
218 |
219 | # The font size ('10pt', '11pt' or '12pt').
220 | #'pointsize': '10pt',
221 |
222 | # Additional stuff for the LaTeX preamble.
223 | #'preamble': '',
224 |
225 | # Latex figure (float) alignment
226 | #'figure_align': 'htbp',
227 | }
228 |
229 | # Grouping the document tree into LaTeX files. List of tuples
230 | # (source start file, target name, title,
231 | # author, documentclass [howto, manual, or own class]).
232 | latex_documents = [
233 | (master_doc, 'pytuga.tex', u'pytuga Documentation',
234 | u'Fábio Macêdo Mendes', 'manual'),
235 | ]
236 |
237 | # The name of an image file (relative to this directory) to place at the top of
238 | # the title page.
239 | #latex_logo = None
240 |
241 | # For "manual" documents, if this is true, then toplevel headings are parts,
242 | # not chapters.
243 | #latex_use_parts = False
244 |
245 | # If true, show page references after internal links.
246 | #latex_show_pagerefs = False
247 |
248 | # If true, show URL addresses after external links.
249 | #latex_show_urls = False
250 |
251 | # Documents to append as an appendix to all manuals.
252 | #latex_appendices = []
253 |
254 | # If false, no module index is generated.
255 | #latex_domain_indices = True
256 |
257 |
258 | # -- Options for manual page output ---------------------------------------
259 |
260 | # One entry per manual page. List of tuples
261 | # (source start file, name, description, authors, manual section).
262 | man_pages = [
263 | (master_doc, 'pytuga', u'pytuga Documentation',
264 | [author], 1)
265 | ]
266 |
267 | # If true, show URL addresses after external links.
268 | #man_show_urls = False
269 |
270 |
271 | # -- Options for Texinfo output -------------------------------------------
272 |
273 | # Grouping the document tree into Texinfo files. List of tuples
274 | # (source start file, target name, title, author,
275 | # dir menu entry, description, category)
276 | texinfo_documents = [
277 | (master_doc, 'pytuga', u'pytuga Documentation',
278 | author, 'pytuga', 'One line description of project.',
279 | 'Miscellaneous'),
280 | ]
281 |
282 | # Documents to append as an appendix to all manuals.
283 | #texinfo_appendices = []
284 |
285 | # If false, no module index is generated.
286 | #texinfo_domain_indices = True
287 |
288 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
289 | #texinfo_show_urls = 'footnote'
290 |
291 | # If true, do not generate a @detailmenu in the "Top" node's menu.
292 | #texinfo_no_detailmenu = False
293 |
294 |
295 | # -- Options for Epub output ----------------------------------------------
296 |
297 | # Bibliographic Dublin Core info.
298 | epub_title = project
299 | epub_author = author
300 | epub_publisher = author
301 | epub_copyright = copyright
302 |
303 | # The basename for the epub file. It defaults to the project name.
304 | #epub_basename = project
305 |
306 | # The HTML theme for the epub output. Since the default themes are not optimized
307 | # for small screen space, using the same theme for HTML and epub output is
308 | # usually not wise. This defaults to 'epub', a theme designed to save visual
309 | # space.
310 | #epub_theme = 'epub'
311 |
312 | # The language of the text. It defaults to the language option
313 | # or 'en' if the language is not set.
314 | #epub_language = ''
315 |
316 | # The scheme of the identifier. Typical schemes are ISBN or URL.
317 | #epub_scheme = ''
318 |
319 | # The unique identifier of the text. This can be a ISBN number
320 | # or the project homepage.
321 | #epub_identifier = ''
322 |
323 | # A unique identification for the text.
324 | #epub_uid = ''
325 |
326 | # A tuple containing the cover image and cover page html template filenames.
327 | #epub_cover = ()
328 |
329 | # A sequence of (type, uri, title) tuples for the guide element of content.opf.
330 | #epub_guide = ()
331 |
332 | # HTML files that should be inserted before the pages created by sphinx.
333 | # The format is a list of tuples containing the path and title.
334 | #epub_pre_files = []
335 |
336 | # HTML files shat should be inserted after the pages created by sphinx.
337 | # The format is a list of tuples containing the path and title.
338 | #epub_post_files = []
339 |
340 | # A list of files that should not be packed into the epub file.
341 | epub_exclude_files = ['search.html']
342 |
343 | # The depth of the table of contents in toc.ncx.
344 | #epub_tocdepth = 3
345 |
346 | # Allow duplicate toc entries.
347 | #epub_tocdup = True
348 |
349 | # Choose between 'default' and 'includehidden'.
350 | #epub_tocscope = 'default'
351 |
352 | # Fix unsupported image types using the Pillow.
353 | #epub_fix_images = False
354 |
355 | # Scale large images.
356 | #epub_max_image_width = 0
357 |
358 | # How to display URL addresses: 'footnote', 'no', or 'inline'.
359 | #epub_show_urls = 'inline'
360 |
361 | # If false, no index is generated.
362 | #epub_use_index = True
363 |
364 |
365 | # Example configuration for intersphinx: refer to the Python standard library.
366 | intersphinx_mapping = {'https://docs.python.org/': None}
367 | napoleon_numpy_docstring = True
368 |
--------------------------------------------------------------------------------
/docs/dev.rst:
--------------------------------------------------------------------------------
1 | ===============================
2 | Definições e design do Pytuguês
3 | ===============================
4 |
5 | Zen do Pytuguês
6 | ===============
7 |
8 | ::
9 | import this
10 |
11 | The Zen of Python, by Tim Peters
12 |
13 | Beautiful is better than ugly.
14 | Explicit is better than implicit.
15 | Simple is better than complex.
16 | Complex is better than complicated.
17 | Flat is better than nested.
18 | Sparse is better than dense.
19 | Readability counts.
20 | Special cases aren't special enough to break the rules.
21 | Although practicality beats purity.
22 | Errors should never pass silently.
23 | Unless explicitly silenced.
24 | In the face of ambiguity, refuse the temptation to guess.
25 | There should be one-- and preferably only one --obvious way to do it.
26 | Although that way may not be obvious at first unless you're Dutch.
27 | Now is better than never.
28 | Although never is often better than *right* now.
29 | If the implementation is hard to explain, it's a bad idea.
30 | If the implementation is easy to explain, it may be a good idea.
31 | Namespaces are one honking great idea -- let's do more of those
32 |
33 | Pytuguês é um dialeto de Python, com sotaque lusitano. Python é uma linguagem
34 | excelente para o ensino de programação e o foco do Pytuguês é exatamente este.
35 | No entanto, Python também é uma linguagem de uso profissional e isto acaba
36 | levando a algumas decisões que enfatizam as "boas práticas", mas que podem
37 | aumentar um pouco a curva de dificuldade de um programador iniciante.
38 |
39 | É lógico que acreditamos que *"Beautiful is better than ugly"*, *"Simple is better
40 | than complex"*, etc. Dado o foco do Pytuguês, devemos acrescentar algumas
41 | prioridades no topo::
42 |
43 | É possível programar sem saber inglês.
44 | Programar é divertido.
45 | Até uma criança consegue fazer.
46 | Programadores não gostam de surpresas.
47 | Programadores não gostam de erros, mas devemos destacar e não esconder os
48 | erros de um programa.
49 |
50 | Sendo assim, as vezes desviamos de uma linguagem puramente "pythonica" para para
51 | priorizar estes novos elementos.
52 |
53 |
54 | Questões específicas do Pytuguês
55 | ================================
56 |
57 | Acentuação:
58 | Diferentemente do Inglês, Português possui muitas palavras com acentos.
59 | Deste modo, tanto elementos básicos da sintaxe tais quais palavras chave e
60 | comandos, quanto os elementos definidos pelo usuário como funções e variáveis devem ser
61 | acentuados normalmente. Acentos são fáceis de se esquecer e algumas
62 | pessoas realmente não gostam da idéia de acentuar código fonte. Pensando
63 | nisto, disponibilizamos "apelidos" não acentuados para cada comando e cada
64 | função na biblioteca básica.
65 | Verbosidade:
66 | Não esperamos que se criem códigos para "produção" em Pytuguês, nem
67 | imaginamos Pytuguês como uma linguagem extremamente produtiva. Deste modo,
68 | achamos que é mais importante deixar que a intenção de um programa seja
69 | clara do que tornar os programs compactos e fáceis de digitar. Por isto, sempre
70 | optamos por nomes longos e explícitos ao invés de nomes curtos e ambíguos.
71 | Inclusive acreditamos que o fato de Python exigir menos digitação funciona
72 | como um incentivo de migração do Pytuguês para o Python.
73 | Tempos verbais:
74 | O inglês muitas vezes não diferencia o infinitivo do imperativo (a não ser
75 | pelo "to", como em "to eat" vs. "eat"). O Português conjuga o imperativo
76 | como em "comer" vs "coma" e ambas as formas parecem maneiras válidas de
77 | expressar uma ação em um programa. O modo imperativo se baseia na
78 | idéia que um programa é uma sequência de comandos transmitidos para o
79 | computador executar, como em ``mostre('olá, mundo!')``.
80 | Já o modo infinitivo concebe um programa como uma idéia abstrata e impessoal,
81 | como em ``mostrar('olá, mundo!')``. O Pytuguês suporta as duas
82 | formas de cada comando, tanto no nível da sintaxe, quanto no nível da
83 | biblioteca de funções.
84 | Argumentos de funções:
85 | Iniciantes muitas vezes tem dificuldades em utilizar funções com número
86 | variável de argumentos. A documentação do Pytuguês evita mencionar
87 | argumentos variáveis (mesmo quando eles são suportados) e a maior
88 | parte das funções do Pytuguês espera um número fixo de argumentos. De um
89 | modo geral, preferimos criar duplicatas de funções em suas versões com cada
90 | número de argumentos.
91 |
92 |
93 | Estensões sintáticas para o Python
94 | ==================================
95 |
96 | Além da tradução (e algumas vezes adição de palavras chaves redundantes, apenas
97 | para enfatizar o contexto), o Pytuguês possui algumas estensões sintáticas
98 | com relação ao Python.
99 |
100 |
101 | Repetir
102 | -------
103 |
104 | A estrutura de repetição mais simples é dada pelo comando "repetir" (ou repita),
105 | que simplesmente repete o conteúdo de um bloco pelo número especificado de vezes
106 |
107 | ::
108 |
109 | repetir vezes:
110 |
111 |
112 | O laço "repetir" é a introdução às estruturas de repetição, e muitas vezes é
113 | o suficiente para problemas simples como desenhar figuras na tela.
114 |
115 |
116 | Range explícito
117 | ---------------
118 |
119 | Programadores iniciantes possuem uma certa dificuldade com a função range().
120 | É uma função que possui três assinaturas diferentes e é fácil confundir a
121 | indexação baseada em zero. Se pensarmos em termos de intervalos numéricos,
122 | ela inclui o ponto de início, mas exclui o ponto final. Para evitar estas
123 | complicações, Pytuguês também suporta o laço::
124 |
125 | para cada de até [a cada ] faça:
126 |
127 |
128 | Na nova forma, tanto o início do intervalo numérico quanto o seu fim estão
129 | marcados explicitamente. Isto deixa o código mais óbvio para aqueles que
130 | nunca entraram em contato com a linguagem e desconhecem as particularidades da
131 | função "range()". Por examplo, contamos de 1 até 10 fazendo::
132 |
133 | para cada x de 1 até 10 faça:
134 | mostre(x)
135 |
136 | Sintaxe redundante
137 | ------------------
138 |
139 | Alguns comandos do Pytuguês introduzem sintaxe redundante, com a única função
140 | de tornar a intenção do programador mais explícita. Estas palavras redundantes
141 | são opcionais e o programador pode escolher utilizá-las ou não, de acordo com
142 | o estilo pessoal::
143 |
144 | # Laços
145 | para [cada] x em L [faça]:
146 |
147 |
148 | para [cada] x de 1 até 10 [a] cada 2 [faça]:
149 |
150 |
151 | enquanto x > 10 [faça]:
152 |
153 |
154 | # Condicionais
155 | se x > 10 [então] [faça]:
156 |
157 | ou [então] se x > 10 [então] [faça]:
158 |
159 | senão [faça]:
160 |
161 |
162 |
163 | Problemas abertos
164 | =================
165 |
166 | * Operador "is" é traduzido como "é". A versão não-acentuada colide com o
167 | operador lógico "e". Encontrar outros sinónimos para identidade?
168 | ``x [é] idêntico [a] y``?
169 | * Keywords com espaços: Pytuguês possui alguns comandos que funcionam como
170 | "keywords" com espaços (Ex.: para x de 1 até 10 *a cada* 2: ...). O
171 | identificador "a" poderia ser tratado como keyword incodicional ou poderia
172 | ser tratado assim somente quando aparecer em "a cada". Escolhemos a segunda
173 | opção pois se "a" for promovido a uma keyword, podemos ter várias colisões de
174 | nomes.
175 | * Dois pontos são necessários para delimitar o início de um bloco? O uso de ":"
176 | para delimitar o início de um bloco é redundante em Python (já que a
177 | indentação sozinha já é capaz de resolver esta questão), mas aumenta a
178 | legibilidade do código e possui uma certa congruência com o uso do mesmo
179 | símbolo em linguagem natural. O fato é que iniciantes frequentemente esquecem
180 | os dois pontos e se frustram quando o código não funciona. Devemos ignorar a
181 | ausência dos mesmos ou simplesmente mostrar uma mensagem de erro mais clara,
182 | explicando que o usuário deve inserir o ":" em uma linha específica?
183 | Esta ausência deve ser tolerada apenas em sintaxe específica do Pytuguês ou
184 | também em sintaxe Python?
185 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. pytuga documentation master file, created by
2 | sphinx-quickstart on Wed Sep 16 22:39:01 2015.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | #####################################
7 | Bem vindos à documentação do Pytuguês
8 | #####################################
9 |
10 | Você gostaria de programar em Português? Pytuguês é uma versão da linguagem de
11 | programação Python que também entende o português.
12 |
13 | .. toctree::
14 | :maxdepth: 2
15 |
16 | Instalação
17 | Tutorial
18 | Biblioteca de funções
19 | Migrando para Python
20 | Para programadores e colaboradores
21 | Licença
22 |
23 |
24 | Tabelas e índices
25 | =================
26 |
27 | * :ref:`genindex`
28 | * :ref:`modindex`
29 | * :ref:`search`
30 |
--------------------------------------------------------------------------------
/docs/install.rst:
--------------------------------------------------------------------------------
1 | .. include:: ../INSTALL.rst
--------------------------------------------------------------------------------
/docs/license.rst:
--------------------------------------------------------------------------------
1 | =======
2 | Licença
3 | =======
4 |
5 | .. include:: ../LICENSE
--------------------------------------------------------------------------------
/docs/python.rst:
--------------------------------------------------------------------------------
1 | ====================
2 | Migrando para Python
3 | ====================
4 |
5 | Pytuguês foi criado, desde o início, como uma linguagem simplificada para
6 | ajudar no aprendizado de programação. Pense como se fossem as rodinhas numa
7 | bicicleta: elas ajudam no início quando não conseguimos manter o equilíbrio,
8 | mas uma vez que você consegue manter a bicicleta equilibrada, elas começam a
9 | atrapalhar. Este é um guia para converter o código Pytuguês para Python.
10 |
11 | Comandos básicos
12 | ================
13 |
14 | Condicionais
15 | ------------
16 |
17 | Os comandos ``se/senão`` podem ser convertidos para Python traduzindo os comandos
18 | ``se`` para ``if``, ``senão`` para ``else`` e ``ou se`` para ``elif``. O Python
19 | não aceita as palavras opcionais ``então`` e ``faça`` (nem mesmo traduzindo-as).
20 | Deste modo, o exemplo abaixo em Pytuguês
21 |
22 | ::
23 |
24 | se x % 2 == 1 então:
25 | y = (x + 1) / 2
26 | ou então se x == 0 faça:
27 | y = 0.0
28 | senão faça:
29 | y = x / 2
30 |
31 | torna-se
32 |
33 | ::
34 |
35 | if x % 2 == 1:
36 | y = (x + 1) / 2
37 | elif x == 0:
38 | y = 0.0
39 | else:
40 | y = x / 2
41 |
42 | Laço ``enquanto``
43 | -----------------
44 |
45 | Para convertermos um laço do tipo ``enquanto``, simplesmente traduzimos para o
46 | correspondente em inglês ``while``. Lembramos quet a palavra opcional ``faça``
47 | não é suportada em Python.
48 |
49 | Deste modo, o código
50 |
51 | ::
52 |
53 | enquanto x < 100 faça:
54 | x = x - 1
55 |
56 | vira simplesmente
57 |
58 | ::
59 |
60 | while x < 100:
61 | x = x - 1
62 |
63 | Laço ``para cada``
64 | ----------------
65 |
66 | O laço ``para cada`` vira o comando ``for`` em Python. Deste modo, se quisermos
67 | iterar sobre uma lista, como no código abaixo, basta fazer::
68 |
69 | S = 0
70 | para cada x em [1, 4, 9, 16] faça:
71 | S += x
72 |
73 | Em Python, isto seria::
74 |
75 | S = 0
76 | for x in [1, 4, 9, 16]:
77 | S += x
78 |
79 | Observe que a instrução ``faça`` não aparece em Python.
80 |
81 | Devemos tomar cuidado em utilizar a versão numérica do comando ``para cada`` já
82 | que não existe uma correspondência direta em Python. Em Python, o laço ``for``
83 | sempre atua em uma sequência. Se quisermos iterar sobre uma sequência de números,
84 | é necessário criar esta sequência manualmente.
85 |
86 | O método mais conveniente é utilizar a função ``range()`` do Python. Ela pode
87 | ser chamada de três maneiras, o que pode deixar as coisas um pouco confusas.
88 |
89 | ``range(n)``:
90 | Gera **n** números de **0** até **n - 1**. É importante tomar cuidado com
91 | isto pois ``range(5)`` gera os números ``0, 1, 2, 3, 4``, **não incluindo**
92 | o valor final de ``5``.
93 | ``range(a, b)``:
94 | Como a anterior, mas inicia a geração de números a partir de **a** e não de
95 | **0**. ``range(0, n)`` é idêntico a ``range(n)``.
96 | ``range(a, b, c)``:
97 | Como a anterior, cria os números saltando a cada ``c``. Assim,
98 | ``range(2, 10, 2)`` gera os números de 2 até 9, saltando de 2 em dois
99 | (``2, 4, 6, 8``).
100 |
101 | Podemos converter o código Pytuguês abaixo::
102 |
103 | S = 0
104 | para cada x de 1 até 100:
105 | S += x
106 |
107 | E o correspondente Python::
108 |
109 | S = 0
110 | for x in range(1, 101):
111 | S += x
112 |
113 | Note o limite superior do ``range`` igual à 101, para incluir o número 100 na
114 | sequênca.
115 |
116 |
117 | Laço ``repetir``
118 | ----------------
119 |
120 | O laço ``repetir`` não existe em Python. No entanto, podemos trocá-lo facilmente
121 | por um laço do tipo for::
122 |
123 | repetir 4 vezes:
124 | frente(100)
125 | esquerda(90)
126 |
127 | Em Python::
128 |
129 | for x in range(4):
130 | frente(100)
131 | esquerda(90)
132 |
133 |
134 | Funções
135 | =======
136 |
137 | A maior parte das funções possui uma tradução direta para Python. Para sabermos
138 | o equivalente de cada função, devemos consultar a documentação da mesma, fazendo
139 | ``help()``.
140 |
141 |
--------------------------------------------------------------------------------
/docs/referencia.rst:
--------------------------------------------------------------------------------
1 | =====================
2 | Biblioteca de funções
3 | =====================
4 |
5 | .. highlight:: pytuga
6 |
7 | .. automodule:: pytugacore.lib.tuga_io
8 | :members:
9 | :member-order: source
10 |
11 | .. automodule:: pytugacore.lib.tuga_std
12 | :members:
13 | :member-order: source
14 |
15 | .. automodule:: pytugacore.lib.tuga_math
16 | :members:
17 | :member-order: source
18 |
19 | .. automodule:: pytugacore.lib.tuga_strings
20 | :members:
21 | :member-order: source
22 |
--------------------------------------------------------------------------------
/docs/tutorial.rst:
--------------------------------------------------------------------------------
1 | ========
2 | Tutorial
3 | ========
4 |
5 | Um programa de computador pode ser entendido como uma série de instruções que
6 | são executadas em sequência para completar uma determinada tarefa. As
7 | tarefas podem ir do extremamente simples, como mostrar mensagens na tela,
8 | até o extremamente complicado como fazer um cálculo científico ou dirigir um
9 | carro. No caso do Pytuguês você provavelmente iniciará o contato com a
10 | programação desenhando figuras na tela. No início, iremos programar o
11 | computador para realizar tarefas como quadrados, triângulos, estrelas ou
12 | outras figuras geométricas.
13 |
14 | Podemos iniciar o ambiente de programação em modo texto invocando o comando
15 | **pytuga** no terminal. Uma vez aberta a aplicação, nos deparamos com o shell
16 | de Pytuguês (que inicia com ``>>>``) onde podemos digitar comandos diretamente.
17 | Para mostrar uma mensagem na tela, por exemplo, digite::
18 |
19 | >>> mostre("olá, mundo!")
20 | olá, mundo
21 |
22 | Experimente também com operações básicas, para ter um sabor dos recursos
23 | disponíveis no terminal de Pytuguês::
24 |
25 | >>> 5 * 4 * 3 * 2 * 1
26 | 120
27 | >>> 40 + 2
28 | 42
29 |
30 | A sintaxe do Pytuguês foi criada para produzir códigos que se assemelhem o
31 | máximo possível com um *pseudo-código* em português. Queremos que o significado
32 | dos programas mais simples seja óbvio para um usuário que não conhece a
33 | linguagem ou que nunca programou na vida, e que a linguagem seja fácil de
34 | aprender e pareça natural para programadores iniciantes. O Python oferece
35 | isto para falantes do inglês, o Pytuguês oferece o mesmo para brasileiros,
36 | portugueses, angolanos, etc.
37 |
38 | Esta seção vai percorrer os principais recursos do Pytuguês para que você possa
39 | começar a programar em poucos minutos. Normalmente a primeira interação com o
40 | Pytuguês se dá por meio da programação gráfica, onde controlamos a trajetória de
41 | um pequeno "robô" que desenha figuras geométricas na tela. Inicie o TurtleMainWindow
42 | ou o pytuga. Os comandos básicos para interagir com o cursor na tela são::
43 |
44 | >>> frente(100) # avança 100 pixels
45 | >>> trás(100) # recua 100 pixels
46 | >>> direita(90) # gira 90 graus no sentido horário
47 | >>> esquerda(90) # gira 90 graus no sentido anti-horário
48 |
49 |
50 | Digite os comandos no terminal interativo para ver o Tuga se mexer. Aos poucos
51 | podemos construir interações complexas e interessantes utilizando estes blocos
52 | básicos e os recursos comuns de programação como repetições, execução
53 | condicional, interação com o usuário, etc.
54 |
55 | **Desafio!**
56 |
57 | Utilize estes comandos para desenhar uma figura regular como quadrado, triângulo, ou
58 | pentágono.
59 |
60 | ----------------
61 | Comandos básicos
62 | ----------------
63 |
64 | Esta seção apresenta os recursos mais básicos do Pytuguês que serão utilizados
65 | posteriormente para construir programas mais complexos e interessantes.
66 |
67 |
68 | Operações matemáticas
69 | ---------------------
70 |
71 | Talvez o uso mais simples do interpretador de Pytuguês seja como uma
72 | calculadora. Além das operações aritméticas comuns, o Pytuguês permite salvar
73 | variáveis, utilizar funções científicas, definir as nossas próprias funções
74 | matemáticas, além de vários outros recursos.
75 |
76 | A notação para as operações matemáticas é usual, onde apenas lembramos que as
77 | casas decimais são separadas por pontos e não por vírgulas::
78 |
79 | 1 + 1 # soma
80 | 2 - 1 # subtração
81 | 3.14 * 2 # multiplicação
82 | 1 / 2 # divisão
83 | 3**2 # potência
84 |
85 | É possível criar variáveis e reaproveitá-las em outras partes do código. As
86 | funções matemáticas mais comuns também estão imediatamente disponíveis.
87 | Experimente estes comandos no terminal interativo::
88 |
89 | >>> x = raiz(4)
90 | >>> x + 1
91 | 3.0
92 | >>> x * x
93 | 4.0
94 | >>> módulo(1 - x)
95 | 1.0
96 |
97 | O operador de igual ``=``, possui o sentido usual da maioria das linguagens de
98 | programação, mas que é diferente do da matemática. Ele não estabelece ou testa
99 | uma relação de igualdade. Ele é utilizado na atribuição de variáveis. Portanto
100 | um código do tipo::
101 |
102 | x = x + 1
103 |
104 | não é uma falsidade matemática. Na realidade, estamos atribuindo um novo valor
105 | para a variável ``x`` que é igual ao valor anterior adicionado de 1.
106 |
107 |
108 | **Desafio!**
109 |
110 | Calcule ``x = 42**42``. Muito provavelmente este resultado é maior que o que
111 | cabe na sua calculadora! Confira.
112 |
113 |
114 | Interação com o usuário
115 | -----------------------
116 |
117 | Em um programa de computador muitas vezes queremos perguntar algum tipo de
118 | informação ao usuário. O Pytuguês oferece algumas funções para salvar valores
119 | digitados pelo usuário em variáveis. Os principais métodos de entrada são as
120 | funções ``leia_texto(msg)``, ``leia_número(msg)`` e ``leia_arquivo(arquivo)``.
121 | O código a seguir, por exemplo, pergunta o nome e a idade do usuário::
122 |
123 | nome = leia_texto("Qual é o seu nome? ")
124 | idade = leia_número("Qual é a sua idade? ")
125 |
126 | A variável ``nome`` contêm o texto que o usuário digitou como sendo o seu nome e
127 | a variável ``idade`` guarda a idade em um formato numérico. A diferença entre
128 | ``leia_número(msg)`` e ``leia_texto(msg)`` está em que a primeira salva o
129 | resultado em formato numérico e obriga o usuário a digitar um número válido. A
130 | segunda conterá sempre um texto, mesmo quando o usuário digitar um número. Observe
131 | a diferença que existe entre um número e um texto que contêm um número:
132 | enquanto o primeiro admite as operações matemáticas, o segundo corresponde a um
133 | valor textual que por um acaso pode ser interpretado (por nós humanos, não pelo
134 | computador!) como um número.
135 |
136 |
137 | As funções mencionadas acima são conhecidas como "funções de entrada", já que
138 | permitem que o usuário do programa dê a entrada em valores que serão utilizados
139 | posteriormente. As *funções de saída* são aquelas que fornecem informação de
140 | volta para o usuário. A mais importante delas é a função ``mostre(valor)``, que
141 | mostra o conteúdo do argumento na tela. Podemos fazer a saída na forma de um
142 | arquivo, utilizando a função ``salve_arquivo(nome_do_arquivo, valor)``. Teste
143 | também a função ``alerte(valor)``: ela é semelhante à função "mostre", mas em
144 | modo gráfico ela mostra a mensagem em uma caixa de diálogo.
145 |
146 | Teste
147 | .....
148 |
149 | Crie uma função que pergunte o ano de nascimento do usuário e calcule a sua
150 | idade.
151 |
152 |
153 | ---------------------------
154 | Controle de fluxo de código
155 | ---------------------------
156 |
157 | Alguns comandos do Pytuguês executam ações imediatas, como por exemplo, o
158 | comando ``frente(passo)``. Podemos construir programas interessantes encadeando
159 | vários destes comandos. O programa abaixo, por exemplo, desenha um triângulo::
160 |
161 | frente(100)
162 | esquerda(120)
163 | frente(100)
164 | esquerda(120)
165 | frente(100)
166 |
167 | (você consegue fazer o triângulo apontar para baixo?)
168 |
169 | Em alguns casos é necessário controlar o "fluxo de código"; ou seja, temos que
170 | decidir quais comandos serão executados e quantas vezes será realizada cada
171 | execução. Esta seção mostra as principais estruturas de controle de fluxo de
172 | código do Pytuguês: ``repetir``, ``para cada``, ``enquanto`` e ``se/senão``.
173 |
174 |
175 | Repetições: ``repetir``
176 | -----------------------
177 |
178 | Muitas tarefas que um programa realiza envovem um grande número de repetições de
179 | tarefas mais simples. Na realidade computadores são muito bons nisso: podem
180 | repetir exatamente a mesma sequência de passos uma quantidade gigantesca de
181 | vezes sem ficarem cansados, errarem ou reclamarem. O comando mais básico de
182 | repetição do Pytuguês é o comando ``repetir``. Ele simplesmente repete um bloco
183 | de instruções pelo número dado de vezes::
184 |
185 | repetir 3 vezes:
186 | frente(100)
187 | esquerda(120)
188 |
189 | Em programação, chamamos cada uma destas repetições de uma "iteração". No exemplo
190 | acima, repetimos o os comandos ``frente(100)`` e ``esquerda(120)`` três
191 | vezes, nesta ordem. De modo mais abstrato, podemos descrever o comando repetir
192 | como::
193 |
194 | repetir vezes:
195 |
196 |
197 | Onde o campo representa qualquer número inteiro ou variável numérica e
198 | é uma sequência de instruções como a
199 | ``frente(100)/esquerda(90)`` dada anteriormente. Devemos nos atentar para os
200 | espaços em branco durante a definição do bloco de instruções. São eles que
201 | delimitam o bloco de instruções e dizem para o Pytuguês quais instruções devem
202 | ser repetidas e quais não fazem mais parte do bloco de repetição e serão
203 | executadas após o término de todas iterações.
204 |
205 | O código abaixo, por exemplo, é muito semelhate ao anterior, mas o comando
206 | ``esquerda(120)`` está alinhado ao início da linha. Isto faz com que apenas a
207 | parte ``frente(100)`` seja executada as três vezes. O comando esquerda está fora
208 | do bloco ``repetir`` e portanto é executado apenas uma única vez após o bloco
209 | terminar::
210 |
211 | repetir 3 vezes:
212 | frente(100)
213 | esquerda(120)
214 |
215 |
216 | .. important:: Indentação
217 | O número de espaços em branco antes de cada linha dentro do código define
218 | o nível de indentação da linha. A indentação é importantíssima em
219 | Pytuguês pois é o que delimita onde começa e onde termina cada bloco de
220 | instruções. Normalmente utilizamos quatro espaços para cada nível de
221 | indentação (mas você pode utilizar uma indentação diferente, se preferir).
222 |
223 | É importante prestar atenção ao nível de indentação de cada linha. Em
224 | Pytuguês, todos os comandos que terminam com um símbolo de ``:`` definem um
225 | início de bloco e portanto exigem que se aumente um nível de indentação. Para
226 | sair do bloco devemos voltar à indentação anterior.
227 |
228 |
229 | **Desafio!**
230 |
231 |
232 | Faça uma estrela de 5 pontas utilizando o comando repetir. Depois tente fazer a
233 | estrela de Davi (neste caso pode ser necessário usar 2 repetições).
234 |
235 |
236 |
237 | Repetições: ``para cada``
238 | -------------------------
239 |
240 | Muitas vezes queremos repetir um bloco de comandos onde em cada iteração uma
241 | variável deve mudar de valor de forma previsível. Por exemplo, se quisermos
242 | cumprimentar várias pessoas numa lista, é possível escrever algo como::
243 |
244 | lista = ["Maria", "João", "José"]
245 |
246 | para cada nome em lista faça:
247 | mostre("Olá " + nome)
248 |
249 | Neste caso, a variável ``nome`` assume um valor diferente em cada iteração
250 | percorrendo a lista de nomes fornecida.
251 |
252 | É muito comum também realizar iterações sobre sequências numéricas. O comando
253 | muda ligeiramente, onde especificamos o intervalo de valores inteiros que
254 | queremos percorrer. O exemplo abaixo soma todos os números de 1 até 10::
255 |
256 | soma = 0
257 |
258 | para cada x de 1 até 10 faça:
259 | soma = soma + x
260 |
261 | mostre(soma)
262 |
263 |
264 | Se quisermos pular de dois em dois, a sintaxe muda um pouquinho::
265 |
266 | soma = 0
267 |
268 | para cada x de 1 até 10 a cada 2 faça:
269 | soma = soma + x
270 |
271 | mostre(soma)
272 |
273 | Neste caso, somente os ímpares seriam contabilizados na soma.
274 |
275 | A sintaxe geral do comando ``para cada`` é dada abaixo. Na forma de sequência, ela
276 | funciona como::
277 |
278 | para cada em faça:
279 |
280 |
281 | Caso seja uma sequência numérica, podemos usar::
282 |
283 | para cada de até a cada faça:
284 |
285 |
286 | Assim como no bloco ``repetir``, o comando ``faça`` é opcional. Podemos também
287 | trocar o comando ``para cada`` por simplesmente ``para``, na forma compacta.
288 | Finalmente, podemos omitir o passo na segunda versão do comando caso ele seja
289 | igual à 1.
290 |
291 | **Desafio!**
292 |
293 | Desenhe uma espiral quadrada de 10 braços em que o tamanho de cada avanço varie
294 | segundo o padrão 10px, 20px, 30px, ..., 100px. A forma ingênua criar este
295 | programa seria algo do tipo::
296 |
297 | frente(10)
298 | esquerda(90)
299 |
300 | frente(20)
301 | esquerda(90)
302 |
303 | frente(30)
304 | esquerda(90)
305 |
306 | frente(40)
307 | esquerda(90)
308 | ...
309 |
310 | É lógico que podemos fazer algo bem melhor com o comando ``para cada`` (ou até mesmo
311 | com o comando repetir).
312 |
313 |
314 | Repetições: enquanto
315 | --------------------
316 |
317 | O comando ``para cada`` é útil quando sabemos de antemão o número de iterações que
318 | devem ser executadas. Muitas vezes, no entanto, queremos repetir um bloco de
319 | código por um número indefinido de vezes até que um determinado critério de
320 | parada seja satisfeito. O código abaixo, por exemplo, repete uma pergunta até
321 | que o usuário acerte a resposta correta::
322 |
323 | enquanto ler_texto("Baterista dos Beatles: ") != "Ringo" faça:
324 | mostre("Resposta errada! Tente novamente...")
325 |
326 | De um modo geral, o comando ``enquanto`` possui a estrutura::
327 |
328 | enquanto faça:
329 |
330 |
331 | No exemplo acima, a condição testada no início do laço é se o resultado da
332 | função ``ler_texto()`` é diferente (``!=``) do valor ``"Ringo"``. O laço ``enquanto``
333 | executa o bloco de comandos indefinidamente enquanto a condição fornecida
334 | for verdadeira. Caso a condição se torne falsa, ele interrompe *antes* de
335 | executar o bloco de comandos.
336 |
337 | O comando ``enquanto`` é talvez a forma mais geral das estruturas de repetição.
338 | Podemos reescrever todos os laços do tipo ``para cada`` ou ``repetir`` utilizando o
339 | comando ``enquanto``. Existe um custo nisto: o código pode ficar mais longo,
340 | confuso e, em alguns casos, até mesmo um pouco mais lento. O código abaixo, por
341 | exemplo, desenha um triângulo utilizando o comando ``enquanto``. Este código funciona
342 | sem maiores problemas. No entanto, o fato de termos que lidar com variáveis adicionais
343 | tira a elegância e concisão da versão que utilizava o comando ``repetir``::
344 |
345 | n_iterações = 0
346 |
347 | enquanto n_iterações < 3:
348 | frente(100)
349 | esquerda(120)
350 | n_iterações = n_iterações + 1
351 |
352 | **Desafio!**
353 |
354 | A função ``aleatório()`` produz um número aleatório entre 0 e 1. O programa
355 | abaixo, por exemplo, produz 100 "passos do bêbado" e imprime a coordenada x após
356 | o passo::
357 |
358 | repetir 100 vezes:
359 | # Dá um passo
360 | frente(50)
361 | esquerda(aleatório() * 360)
362 |
363 | # Imprime a coordenada x
364 | x, y = posição()
365 | mostre(x)
366 |
367 | Modifique o comando acima para que o "passo do bêbado" termine quando o cursor
368 | atingir uma distância de 300 px da origem.
369 |
370 |
371 | Condicionais
372 | ------------
373 |
374 | Se quisermos executar um comando apenas se determinada condição for satisfeita,
375 | então usamos o bloco *se*::
376 |
377 | x = leia_número("Diga um número: ")
378 |
379 | se x > 10 então faça:
380 | mostre("x é muito grande")
381 |
382 | Neste caso, o comando ``mostre(...)`` será executado somente se o usuário
383 | digitar um valor maior que 10. Se quisermos adicionar uma condição que deva ser
384 | executada caso o teste x > 10 falhe, basta adicionar um bloco do tipo ``senão``::
385 |
386 | x = leia_número("Diga um número: ")
387 |
388 | se x > 10 então faça:
389 | mostre("x é muito grande")
390 | senão faça:
391 | mostre("x é pequeno")
392 |
393 | Este código imprime na tela que x é muito grande caso o usuário diga um número
394 | maior que 10, ou imprime que x é pequeno caso contrário. É possível adicionar
395 | condições intermediárias usando o bloco *ou então se*. Neste caso, somente a
396 | primeira condição a ser satisfeita é executada. A sintaxe completa é portanto::
397 |
398 | x = leia_número("Diga um número: ")
399 |
400 | se x > 10 então faça:
401 | mostre("x é muito grande")
402 | ou então se x == 7 faça:
403 | mostre("x é meu número da sorte")
404 | senão faça:
405 | mostre("x é pequeno")
406 |
407 | De um modo geral, a estrutura condicional pode ser escrita como::
408 |
409 | se então faça:
410 |
411 | ou então se faça:
412 |
413 | ou então se faça:
414 |
415 | ...
416 | senão faça:
417 |
418 |
419 | No máximo um dos blocos de código será executado, sendo este o que corresponde à
420 | primeira condição satisfeita. Analogamente aos laços repetição, os termos
421 | ``então faça`` e ``faça`` são opcionais.
422 |
423 | O condicional funciona assim.
424 |
425 | * Primeiramente testamos a *condição 1*. Se ela for satisfeita, o bloco de
426 | código correspondente é executado e o Pytuguês ignora todos os outros blocos
427 | restantes e continua a execução a partir daí.
428 | * Caso a condição seja falsa, partimos para a *condição 2*. Se ela for
429 | satisfeita, executamos o segundo bloco de código e pulamos sobre todos os
430 | outros.
431 | * Somente se nenhuma das condições for satisfeita, executa-se o bloco ``senão``.
432 | Caso o bloco senão não exista, nenhum comando é executado.
433 |
434 | Talvez fique mais claro em um exemplo::
435 |
436 | se x == 1:
437 | mostre("uma unidade")
438 | ou então se x > 10:
439 | mostre("x é grande")
440 | ou então se x < 0:
441 | mostre("x é pequeno")
442 | ou então se x % 2 == 0:
443 | mostre("x é par")
444 | ou então se x == 20:
445 | mostre("esta linha nunca será executada pois 20 > 10")
446 | senão:
447 | mostre(x)
448 |
449 | Se ``x`` for igual a 4, o programa imprimirá *"x é par"*, pois a condição
450 | ``x % 2 == 0`` (resto da divisão de ``x`` por ``2`` é igual a zero) é a primeira condição
451 | satisfeita no bloco condicional. Caso ``x`` seja igual a 12, a mensagem mostrada
452 | será *"x é grande"*, pois apesar de tanto ``x > 10`` quanto ``x % 2 == 0`` serem
453 | satisfeitos para este valor, a primeira condição é selecionada pois aparece
454 | primeiro no bloco condicional. Para executarmos o bloco ``senão``, é necessário
455 | utilizar um valor de ``x`` que viole todas as condições apresentadas. Neste
456 | caso, qualquer um dos valores 3, 5, 7 e 9 funcionam. Você consegue dizer o que acontece
457 | se ``x`` for igual a 20?
458 |
459 |
460 | **Desafio!**
461 |
462 | Pergunte a idade do usuário e imprima uma das mensagens abaixo dependendo da
463 | faixa em que ele se situa.
464 |
465 | * negativo: "você ainda não nasceu!"
466 | * 0-3: "você é um bebê"
467 | * 4-9: "você é uma criança"
468 | * 10-12: "você é um pré-adolescente"
469 | * 13-19: "você é um adolescente"
470 | * 20-59: "você é um adulto"
471 | * 60 ou mais: "você é um idoso"
472 |
473 | O Pytuguês aceita condições compostas, assim podemos usar o teste
474 | ``0 <= idade <= 3`` para verificar se a idade está no intervalo entre 0 e 3.
475 |
476 |
477 | -----------------
478 | Funções e módulos
479 | -----------------
480 |
481 | Uma função, em computação é entendida como um comando que recebe zero ou mais argumentos, realiza uma ação e
482 | opcionalmente pode retornar um valor. Isto é um pouco diferente e mais abrangente que as funções da matemática, que
483 | devem possuir pelo menos uma entrada e uma única saída. Pense numa função como uma sequência fixa de operações que você
484 | pode querer executar em um programa.
485 |
486 | Pense na função ``cubo(x)``, que eleva o argumento de entrada ``x`` ao cubo e retorna o resultado (ela não existe em
487 | Pytuguês, mas logo aprenderemos como definí-la). Esta é uma função tanto no sentido matemático, como no computacional.
488 | Neste caso, para calcular o cubo do argumento, simplesmente obtemos o resultado da multiplicação ``x * x * x``. Já a
489 | função ``aleatório()`` que mencionamos anteriormente é uma função no sentido computacional mas não no sentido
490 | matemático: ela não possui qualquer argumento de entrada e a cada vez que for chamada, retorna um valor diferente::
491 |
492 | x = aleatório()
493 | y = aleatório()
494 | mostre(x, y)
495 |
496 | Ao executarmos o programa acima, vemos que x e y (muito provavelmente) possuem valores diferentes e que a cada execução
497 | estes valores mudam. ``aleatório()`` não é uma função no sentido matemático. Ela apenas representa a ação de obter um
498 | número aleatório.
499 |
500 | O conceito de funções é muito importante em computação. Podemos compor funções simples para criar funções um pouco mais
501 | complexas e seguir compondo estas funções em camadas até criar um programa altamente sofisticado. É claro que estamos
502 | apenas começando e não vamos já de cara desenvolver um editor de textos ou um jogo de tiros em primeira pessoa. Estes
503 | programas podem involver literalmente milhões de linhas de códigos que são desenvolvidas por grandes times de
504 | programadores durante longos intervalos de tempo. Vamos, no entanto, aprender a definir funções para dar o primeiro passo
505 | para virarmos bons programadores.
506 |
507 | Definindo uma função
508 | --------------------
509 |
510 | Pense numa função como um pedaço de código reutilizável. Vamos voltar ao exemplo de como construir um quadrado::
511 |
512 | repetir 4 vezes:
513 | frente(100)
514 | esquerda(90)
515 |
516 | Se quisermos fazer algum tipo de arte (ou um programa) que envolva a criação de vários quadrados, copiar e colar este
517 | código pode se tornar repetitivo. Para evitar muitas repetições, podemos colocar este código dentro de uma função::
518 |
519 | função quadrado():
520 | repetir 4 vezes:
521 | frente(100)
522 | esquerda(90)
523 |
524 | Simplesmente colocamos o código que queremos reutilizar dentro do corpo da função ``quadrado()``. Note que isto não executa
525 | a sequência de comandos fornecido. Para isto, é necessário chamar ``quadrado()`` explicitamente::
526 |
527 | quadrado() # desenha um quadrado
528 | esquerda(45)
529 | quadrado() # desenha outro quadrado inclinado, pois iniciamos de uma posição inclinada
530 |
531 | Compondo funções, é possível criar programas relativamente complexos de forma simples::
532 |
533 | repetir 8 vezes:
534 | quadrado()
535 | esquereda(45)
536 |
537 | O código acima desenha uma mandala a partir de oito quadrados.
538 |
539 |
540 | **Desafio**
541 |
542 | Crie duas funções: ``quadrado_grande()`` e ``quadrado_pequeno()`` e desenhe uma mandala compondo os dois tipos de quadrados,
543 | chamando suas respectivas funções. Obs.: este exerício pode ser resolvido sem utilizar funções, mas muito provavelmente
544 | o código ficará mais longo e confuso.
545 |
546 |
547 | Entrada de parâmetros
548 | ---------------------
549 |
550 | Vimos como criar uma função que repete uma sequência fixa de comandos. Muitas vezes é necessário alterar o comportamento
551 | da função a cada chamada passando parâmetros adicionas. No exemplo dos quadrados acima, poderíamos, por exemplo,
552 | controlar o tamanho do quadrado desenhado em cada chamada passando o mesmo como argumento para a função. O Pytuguês
553 | suporta este recurso simplesmente escrevendo os parâmetros adicionais na definição da função::
554 |
555 | função quadrado(lado):
556 | repetir 4 vezes:
557 | frente(lado)
558 | esquerda(90)
559 |
560 | Esta função pode ser chamada como ``quadrado(100)`` para desenhar um quadrado de 100 px de lado. O parâmetro passado
561 | é atribuído à variável ``lado`` que posteriormente pode ser utilizado no corpo da função como uma variável qualquer.
562 | Neste caso, ela aparece na linha ``frente(lado)`` que comanda o cursor a andar para frente pelo valor especificado.
563 |
564 | Uma função pode possuir qualquer número de parâmetros de entrada, que são passados na mesma ordem de chamada. Considere
565 | a função que desenha um polígono regular::
566 |
567 | função polígono_regular(N, lado):
568 | ângulo = 360 / N
569 | repetir N vezes:
570 | frente(lado)
571 | esquerda(ângulo)
572 |
573 | Esta função é chamada com dois parâmetros (por exemplo, ``polígono_regular(3, 100)`` desenha um triângulo de lados de
574 | 100px). É importante passar os parâmetros na mesma ordem em que eles aparecem na definição da função. Por exemplo,
575 | ``polígono_regular(100, 3)`` provavelmente é um erro, mas talvez seja um usuário que realmente queira desenhar um
576 | polígono de 100 lados de tamanho 3px. Não tem como o computador adivinhar a intenção real de quem chamou a função e
577 | mesmo que isso fosse possível em alguns casos, não é senstato depender da inteligência do computador para acertar nossas
578 | intenções. Devemos treinar um certo rigor nos comandos que são passados para o computador.
579 |
580 | Lembrar a ordem de cada parâmetro pode ser bastante confuso e sujeito a
581 | erros, principalmente em funções com um grande número de parâmetros. Pensando
582 | nisto, o Pytuguês permite passar os parâmetros por nome (e permite até
583 | definir parâmetros opcionais, mas isto é um tópico mais avançado que não
584 | trataremos aqui). Podemos chamar ``polígono_regular(lado=100, N=3)`` passando
585 | os argumentos de entrada explicitamente a partir dos seus nomes. Neste caso, a
586 | ordem dos parâmetros é irrelevante.
587 |
588 | **Desafio**
589 |
590 | Crie uma função que desenha uma mandala a partir de uma figura regular de N
591 | lados utilizando a mesma técnica que fizemos anteriormente com o quadrado.
592 |
593 |
594 | Valores de saída
595 | ----------------
596 |
597 | Todas as funções em Pytuguês possuem um certo número de parâmetros de entrada
598 | e um valor de saída. Isto permite que a função retorne um resultado
599 | potencialmente útil para o usuário. Podemos, por exemplo, definir uma função
600 | ``cubo(x)`` que retorna o valor terceira potência do argumento ``x``. Para
601 | retornar um valor explícito, é necessário inserir a cláusula
602 | ``retornar `` no corpo da função::
603 |
604 | definir função cubo(x):
605 | resultado = x * x * x
606 | retornar resultado
607 |
608 | A partir daí podemos utilizar esta função para calcular o cubo de qualquer valor fornecido::
609 |
610 | valor = cubo(2)
611 | mostre(valor)
612 |
613 | Neste caso, o programa mostrará o número 8.
614 |
615 | Observe que as funções que não possuem uma cláusula do tipo ``retornar`` implicitamente retornam o valor ``nulo``,
616 | como em::
617 |
618 | valor = polígono_regular(4, 100)
619 | mostre(valor)
620 |
621 | Isto irá mostrar ``nulo`` na tela. É possível retornar o valor ``nulo`` explicitamente
622 | utilizando ``retornar nulo``, mas isto não é necessário.
623 |
624 |
625 | **Desafio**
626 |
627 | Crie uma função que calcula e retorna o alcance de um projétil a partir do ângulo de arremesso e da velocidade de saída.
628 | Lembre-se das aulas de física: o alcance é dado por :latex:`$\frac{v_0^2 sin(2\theta)}{g}$`.
629 |
630 |
631 | -------------------
632 | Estruturas de dados
633 | -------------------
634 |
635 | Vimos até agora apenas alguns tipos de variáveis bem simples: números e, de
636 | forma superficial, textos (*strings*) e variáveis lógicas. As variávies em
637 | Pytuguês podem assumir vários outros tipos de valores (e inclusive você poderá
638 | criar os seus próprios tipos quando estiver mais experiente em programação).
639 | Nesta seção discutiremos principalmente os tipos de sequêcias e agrupamentos e
640 | as relações entre eles. O tipo mais básico e intuitivo talvez seja a lista.
641 | Definimos uma lista simplesmente enumerando seus elementos dentro de colchetes::
642 |
643 | L = [1, 2, 9, 16]
644 |
645 | Podemos acessar os elementos da lista utilizando a notação de índices. Em
646 | Pytuguês, os índices começam em zero. Desta forma, o primeiro elemento da lista
647 | pode ser acessado como ``L[0]``, o segundo como ``L[1]`` e assim por diante.
648 | Cada elemento da lista anterior pode ser acessado como::
649 |
650 | L[0] --> 1
651 | L[1] --> 2
652 | L[2] --> 9
653 | L[3] --> 16
654 |
655 | Índices negativos podem ser utilizados para acessar a lista de trás para frente.
656 | Desta forma L[-1] corresponde ao último elemento, L[-2] ao penúltimo e assim
657 | por diante.
658 |
659 | Podemos encontrar o número de elementos da lista utilizando a função
660 | ``tamanho(L)``. Muitas vezes utilizamos a função ``tamanho`` para determinar os
661 | índices sobre o qual queremos iterar::
662 |
663 | N = tamanho(L)
664 | para cada i de 0 até N - 1 faça:
665 | mostre(i, L[i])
666 |
667 | Se quisermos percorrer os elementos sem nos importarmos com os índices podemos
668 | realizar um laço do tipo ``para cada`` diretamente sobre a lista::
669 |
670 | para cada x em L faça:
671 | mostre(x)
672 |
673 |
674 | Modificando uma lista
675 | ---------------------
676 |
677 | Podemos alterar os elementos de uma lista, apagá-los, ou inserir novos elementos.
678 |
679 | Modificamos o valor contido em um determinado local da lista como::
680 |
681 | >>> L[2] = 0 # altera o terceiro elemento da lista para zero
682 |
683 | Para apagar um elemento específico da lista utilizamos o comando ``remover``::
684 |
685 | >>> remover L[2]
686 | >>> mostre(L)
687 | [1, 2, 16]
688 |
689 | Observe que o terceiro elemento foi removido e o quarto passou a ocupar o seu lugar.
690 |
691 | Podemos inserir elementos na lista utilizando duas funções diferentes. A função
692 | ``acrescentar(lista, elemento)`` adiciona um novo elemento no final da lista. É
693 | muito comum utilizar a função ``acrescentar`` para construir uma lista aos
694 | poucos a partir de uma lista vazia. No exemplo abaixo, criamos uma lista com os
695 | 100 primeiros quadrados perfeitos::
696 |
697 | quadrados = []
698 | para cada x de 1 até 100:
699 | acrescentar(quadrados, x * x)
700 |
701 | Já a função ``inserir(lista, índice, elemento)`` insere um novo elemento no
702 | índice dado deslocando todos os elementos subsequentes para frente. Podemos ver
703 | como isto funciona no exemplo::
704 |
705 | >>> beatles = ['Paul', 'George', 'Ringo']
706 | >>> inserir(beatles, 1, 'John')
707 | >>> mostre(beatles)
708 | ['Paul', 'John', 'George', 'Ringo']
709 |
710 |
711 | **Desafio**
712 |
713 | Crie uma lista que começa com ``L = [1, 1]``. Cada novo elemento é criado
714 | somando os dois anteriores. Esta regra cria os números de Fibonacci, que foram
715 | propostos inicialmente para descrever o crescimento de uma população de coelhos.
716 | Complete esta lista até que ela tenha 10 elementos.
717 |
718 |
719 | Texto (*strings*)
720 | -----------------
721 |
722 | Representamos uma variável do tipo texto (*string*, em inglês) colocando o
723 | conteúdo entre aspas, como em ``msg = "Olá, todo mundo!"``. A variável ``msg``
724 | é do tipo texto, e aceita operações como concatenamento, conversão entre
725 | maiúsculas e minúsculas, etc. Sob vários aspectos, uma variável de texto se
726 | assemelha a uma lista de caracteres. Podemos, por exemplo, extrair uma letra
727 | específica do texto utilizando a notação de indexamento::
728 |
729 | >>> [msg[0], msg[1], msg[2], msg[-1]]
730 | ['O', 'l', 'á', '!']
731 |
732 | Diferentemente das listas, as variáveis de texto não podem ser modificadas.
733 | Para realizar uma alteração em uma *string* é sempre necessário criar uma nova
734 | *string* com o valor alterado. Em alguns casos, pode ser necessário converter a
735 | *string* para uma lista de caracteres, modificar a lista e finalmente juntá-la
736 | numa *string* final::
737 |
738 | >>> L = lista("hello")
739 | >>> L[0] = "H"
740 | >>> acrescentar(L, "!")
741 | >>> mostre(juntar(L))
742 | Hello!
743 |
744 | Strings de texto aceitam algumas operações matemáticas úteis. A soma de duas
745 | stings corresponde à concatenação::
746 |
747 | >>> "olá" + "mundo"
748 | 'olámundo'
749 |
750 | Já a multiplicação de uma *string* por um número inteiro corresponde a uma
751 | repetição::
752 |
753 | >>> "abc" * 3
754 | 'abcabcabc'
755 |
756 | Existem várias funções auxiliares aplicadas sobre *strings* que podem ser
757 | acessadas pela notação ``.``, como por exemplo em::
758 |
759 | >>> nome = "ringo"
760 | >>> nome.maiúsculas()
761 | 'RINGO'
762 |
763 | A função ``nome.maiúsculas()`` é um método associado apenas às variáveis do tipo
764 | *string*. Como se trata de uma função com aplicação bem restrita --- não faz
765 | sentido, por exemplo, converter um número para letras maiúsculas --- esta função
766 | não possui escopo global.
767 |
768 | Podemos obter a lista completa de funções associadas a cada tipo usando
769 | o comando ``ajuda()``, onde substituímos o nome do tipo por
770 | ``Texto`` para acessar as funções específicas de *strings*. A maior parte das
771 | funções é auto-explicativa: explore-as para se familiarizar com os recursos de
772 | processamento de texto disponíveis no Pytuguês.
773 |
774 |
775 | **Desafio**
776 |
777 | Crie uma função que remova todos os acentos de uma palavra. Para este exercício
778 | considere apenas os acentos que normalmente aparecem em português.
779 |
780 |
781 | Dicionário
782 | ----------
783 |
784 | Um dicionário em Pytuguês (algumas vezes chamado de *hash table*) define um
785 | mapeamento entre um conjunto de índices (as chaves) para um conjunto de valores.
786 | Podemos, por exemplo, relacionar um grupo de pessoas às suas respectivas idades::
787 |
788 | D = {'João': 31, 'Maria': 29, 'José': 3}
789 |
790 | Note que as chaves podem ser do tipo texto ou qualquer outro valor imutável:
791 | você pode utilizar números inteiros ou decimais, mesclar textos com números, etc.
792 | No entanto, não é possível utilizar valores mutáveis como chaves. Podemos
793 | acessar o valor associado a uma chave no dicionário usando a notação de índices::
794 |
795 | >>> D['José'] + 1
796 | 4
797 |
798 | Para acrescentar valores ao dicionário, basta fazer uma atribuição e o elemento
799 | será inserido automaticamente (caso a chave já exista, substitui-se seu valor)::
800 |
801 | >>> D['Joana'] = 1
802 | >>> tamanho(D)
803 | 4
804 |
805 |
806 | **Desafio**
807 |
808 | Crie um programa encriptador de mensagens. Para isto, defina um dicionário que
809 | troque algumas letras do alfabeto de lugar até criar uma mensagem
810 | incompreensível. Depois crie um outro programa que decodifique a mensagem
811 | secreta.
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | -e .
2 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import sys
4 |
5 | from setuptools import setup, find_packages
6 |
7 | # cx_Freeze: we added a undocumented option to enable building frozen versions
8 | # of our packages. This should be refactored for a more safe approach in the
9 | # future.
10 | setup_kwargs = {}
11 | if '--cx-freeze' in sys.argv:
12 | from cx_Freeze import setup, Executable
13 |
14 | build_options = {
15 | 'include_files': [],
16 | 'packages': ['os', 'pytuga', 'pygments', 'transpyler'],
17 | 'excludes': [
18 | 'tkinter', 'redis', 'lxml',
19 | 'nltk', 'textblob',
20 | 'matplotlib', 'scipy', 'numpy', 'sklearn',
21 | 'notebook',
22 | 'java',
23 | 'sphinx', 'PIL', 'PyQt4'
24 | ],
25 | 'optimize': 1,
26 | }
27 | base = 'Win32GUI' if sys.platform == 'win32' else None
28 |
29 | setup_kwargs['executables'] = [
30 | Executable(
31 | 'src/pytuga/__main__.py',
32 | base=base,
33 | targetName='Pytuga.exe' if sys.platform == 'win32' else 'pytuga',
34 | shortcutName='Pytuga',
35 | shortcutDir='DesktopFolder',
36 | )
37 | ]
38 | setup_kwargs['options'] = {'build_exe': build_options}
39 | sys.argv.remove('--cx-freeze')
40 |
41 | # Extract version
42 | init = open(os.path.join('src', 'pytuga', '__init__.py')).read()
43 | m = re.search(r"__version__ ?= ?'([0-9a-z.]+)'", init)
44 | version = m.group(1)
45 |
46 |
47 | # Wraps command classes to register pytuga kernel during installation
48 | def wrapped_cmd(cmd):
49 | class Command(cmd):
50 | def run(self):
51 | if 'src' not in sys.path:
52 | sys.path.append('src')
53 |
54 | from transpyler.jupyter.setup import setup_assets
55 | setup_assets(True)
56 | cmd.run(self)
57 |
58 | return Command
59 |
60 |
61 | # Run setup() function
62 | setup(
63 | name='pytuga',
64 | version=version,
65 | description='Interpretador de Pytuguês: um Python com sotaque lusitano.',
66 | author='Fábio Macêdo Mendes',
67 | author_email='fabiomacedomendes@gmail.com',
68 | url='https://github.com/transpyler/pytuga',
69 | long_description=('''
70 | Pytuguês é uma linguagem de programação que modifica a sintaxe do
71 | Python para aceitar comandos em português. A linguagem foi desenvolvida
72 | como uma extens~ao do Python que aceita comandos em português.
73 |
74 | O único objetivo do Pytuguês é facilitar o aprendizado de programação. Uma
75 | vez que os conceitos básicos forem apreendidos, a transição para uma
76 | linguagem real (no caso o Python) torna-se gradual e natural.
77 | '''),
78 | classifiers=[
79 | 'Development Status :: 4 - Beta',
80 | 'Intended Audience :: Developers',
81 | 'License :: OSI Approved :: GNU General Public License (GPL)',
82 | 'Operating System :: POSIX',
83 | 'Programming Language :: Python',
84 | 'Topic :: Software Development :: Libraries',
85 | ],
86 |
87 | # Packages and dependencies
88 | package_dir={'': 'src'},
89 | packages=find_packages('src'),
90 | install_requires=[
91 | 'qturtle~=0.5.0',
92 | ],
93 |
94 | # Wrapped commands (for ipytuga)
95 | # cmdclass={
96 | # 'install': wrapped_cmd(_install),
97 | # 'develop': wrapped_cmd(_develop),
98 | # },
99 |
100 | # Scripts
101 | entry_points={
102 | 'console_scripts': [
103 | 'pytuga = pytuga.__main__:main',
104 | ],
105 | },
106 |
107 | # Data files
108 | package_data={
109 | 'pytuga': [
110 | 'assets/*.*',
111 | 'doc/html/*.*',
112 | 'doc/html/_modules/*.*',
113 | 'doc/html/_modules/tugalib/*.*',
114 | 'doc/html/_sources/*.*',
115 | 'doc/html/_static/*.*',
116 | 'examples/*.pytg'
117 | ],
118 | 'pytuga': [
119 | 'ipytuga/assets/*.*',
120 | ],
121 | },
122 | # data_files=DATA_FILES,
123 | zip_safe=False,
124 | **setup_kwargs
125 | )
126 |
--------------------------------------------------------------------------------
/src/pytuga/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '0.13.0'
2 | __author__ = 'F\xe1bio Mac\xeado Mendes'
3 |
4 | from .transpyler import PytugaTranspyler
5 |
6 | # Update core functions (we do not update globals() to make static analysis
7 | # tools happy).
8 | _ns = PytugaTranspyler.core_functions()
9 |
10 | init, namespace = _ns.pop('init'), _ns.pop('namespace')
11 | exec, eval = _ns.pop('exec'), _ns.pop('eval')
12 | compile, transpile = _ns.pop('compile'), _ns.pop('transpile')
13 | is_incomplete_source = _ns.pop('is_incomplete_source')
14 |
15 | assert not _ns, _ns
16 | del _ns
17 |
--------------------------------------------------------------------------------
/src/pytuga/__main__.py:
--------------------------------------------------------------------------------
1 | from transpyler import get_transpyler
2 |
3 |
4 | def main():
5 | """
6 | Pytuga main entry point.
7 | """
8 | get_transpyler().start_main()
9 |
10 |
11 | if __name__ == '__main__':
12 | main()
13 |
--------------------------------------------------------------------------------
/src/pytuga/assets/kernel.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Author: Clinton Dreisbach
3 | * Branched from CodeMirror's Clojure mode (by Hans Engel)
4 | *
5 | * Author: Hans Engel
6 | * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
7 | * copied from https://github.com/cndreisbach/lighttable-hylang/blob/master/codemirror/hy.js
8 | */
9 |
10 |
11 | /** TODO: adapt to python
12 |
13 | define(["codemirror/lib/codemirror", "base/js/namespace"],
14 | function(CodeMirror, IPython){
15 |
16 | return {onload: function(){
17 |
18 |
19 | CodeMirror.defineMode("hy", function () {
20 | var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2",
21 | ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword";
22 | var INDENT_WORD_SKIP = 2;
23 |
24 | function makeKeywords(str) {
25 | var obj = {}, words = str.split(" ");
26 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
27 | return obj;
28 | }
29 |
30 | var atoms = makeKeywords("true false nil");
31 |
32 | var keywords = makeKeywords(
33 | "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle setv input raw-input with list-comp defclass");
34 |
35 | var builtins = makeKeywords(
36 | "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->> pow");
37 |
38 | var indentKeys = makeKeywords(
39 | // Built-ins
40 | "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
41 |
42 | // Binding forms
43 | "let letfn binding loop for doseq dotimes when-let if-let " +
44 |
45 | // Data structures
46 | "defstruct struct-map assoc " +
47 |
48 | // clojure.test
49 | "testing deftest " +
50 |
51 | // contrib
52 | "handler-case handle dotrace deftrace");
53 |
54 | var tests = {
55 | digit: /\d/,
56 | digit_or_colon: /[\d:]/,
57 | hex: /[0-9a-f]/i,
58 | sign: /[+-]/,
59 | exponent: /e/i,
60 | keyword_char: /[^\s\(\[\;\)\]]/,
61 | symbol: /[\w*+!\-\._?:\/]/
62 | };
63 |
64 | function stateStack(indent, type, prev) { // represents a state stack object
65 | this.indent = indent;
66 | this.type = type;
67 | this.prev = prev;
68 | }
69 |
70 | function pushStack(state, indent, type) {
71 | state.indentStack = new stateStack(indent, type, state.indentStack);
72 | }
73 |
74 | function popStack(state) {
75 | state.indentStack = state.indentStack.prev;
76 | }
77 |
78 | function isNumber(ch, stream){
79 | // hex
80 | if ( ch === '0' && stream.eat(/x/i) ) {
81 | stream.eatWhile(tests.hex);
82 | return true;
83 | }
84 |
85 | // leading sign
86 | if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {
87 | stream.eat(tests.sign);
88 | ch = stream.next();
89 | }
90 |
91 | if ( tests.digit.test(ch) ) {
92 | stream.eat(ch);
93 | stream.eatWhile(tests.digit);
94 |
95 | if ( '.' == stream.peek() ) {
96 | stream.eat('.');
97 | stream.eatWhile(tests.digit);
98 | }
99 |
100 | if ( stream.eat(tests.exponent) ) {
101 | stream.eat(tests.sign);
102 | stream.eatWhile(tests.digit);
103 | }
104 |
105 | return true;
106 | }
107 |
108 | return false;
109 | }
110 |
111 | // Eat character that starts after backslash \
112 | function eatCharacter(stream) {
113 | var first = stream.next();
114 | // Read special literals: backspace, newline, space, return.
115 | // Just read all lowercase letters.
116 | if (first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
117 | return;
118 | }
119 | // Read unicode character: \u1000 \uA0a1
120 | if (first === "u") {
121 | stream.match(/[0-9a-z]{4}/i, true);
122 | }
123 | }
124 |
125 | return {
126 | startState: function () {
127 | return {
128 | indentStack: null,
129 | indentation: 0,
130 | mode: false
131 | };
132 | },
133 |
134 | token: function (stream, state) {
135 | if (state.indentStack == null && stream.sol()) {
136 | // update indentation, but only if indentStack is empty
137 | state.indentation = stream.indentation();
138 | }
139 |
140 | // skip spaces
141 | if (stream.eatSpace()) {
142 | return null;
143 | }
144 | var returnType = null;
145 |
146 | switch(state.mode){
147 | case "string": // multi-line string parsing mode
148 | var next, escaped = false;
149 | while ((next = stream.next()) != null) {
150 | if (next == "\"" && !escaped) {
151 |
152 | state.mode = false;
153 | break;
154 | }
155 | escaped = !escaped && next == "\\";
156 | }
157 | returnType = STRING; // continue on in string mode
158 | break;
159 | default: // default parsing mode
160 | var ch = stream.next();
161 |
162 | if (ch == "\"") {
163 | state.mode = "string";
164 | returnType = STRING;
165 | } else if (ch == "\\") {
166 | eatCharacter(stream);
167 | returnType = CHARACTER;
168 | } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
169 | returnType = ATOM;
170 | } else if (ch == ";") { // comment
171 | stream.skipToEnd(); // rest of the line is a comment
172 | returnType = COMMENT;
173 | } else if (isNumber(ch,stream)){
174 | returnType = NUMBER;
175 | } else if (ch == "(" || ch == "[" || ch == "{" ) {
176 | var keyWord = '', indentTemp = stream.column(), letter;
177 | // Either
178 | // (indent-word ..
179 | // (non-indent-word ..
180 | // (;something else, bracket, etc.
181 |
182 | if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
183 | keyWord += letter;
184 | }
185 |
186 | if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) ||
187 | /^(?:def|with)/.test(keyWord))) { // indent-word
188 | pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
189 | } else { // non-indent word
190 | // we continue eating the spaces
191 | stream.eatSpace();
192 | if (stream.eol() || stream.peek() == ";") {
193 | // nothing significant after
194 | // we restart indentation 1 space after
195 | pushStack(state, indentTemp + 1, ch);
196 | } else {
197 | pushStack(state, indentTemp + stream.current().length, ch); // else we match
198 | }
199 | }
200 | stream.backUp(stream.current().length - 1); // undo all the eating
201 |
202 | returnType = BRACKET;
203 | } else if (ch == ")" || ch == "]" || ch == "}") {
204 | returnType = BRACKET;
205 | if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) {
206 | popStack(state);
207 | }
208 | } else if ( ch == ":" ) {
209 | stream.eatWhile(tests.symbol);
210 | return ATOM;
211 | } else {
212 | stream.eatWhile(tests.symbol);
213 |
214 | if (keywords && keywords.propertyIsEnumerable(stream.current())) {
215 | returnType = KEYWORD;
216 | } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
217 | returnType = BUILTIN;
218 | } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
219 | returnType = ATOM;
220 | } else returnType = null;
221 | }
222 | }
223 |
224 | return returnType;
225 | },
226 |
227 | indent: function (state) {
228 | if (state.indentStack == null) return state.indentation;
229 | return state.indentStack.indent;
230 | },
231 |
232 | lineComment: ";;"
233 | };
234 | });
235 |
236 | CodeMirror.defineMIME("text/x-hylang", "hy");
237 |
238 | }};//returned module
239 | });//define
240 |
241 | */
--------------------------------------------------------------------------------
/src/pytuga/assets/logo-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/src/pytuga/assets/logo-32x32.png
--------------------------------------------------------------------------------
/src/pytuga/assets/logo-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/src/pytuga/assets/logo-64x64.png
--------------------------------------------------------------------------------
/src/pytuga/curses.py:
--------------------------------------------------------------------------------
1 | from transpyler.utils import normalize_accented_keywords, synonyms
2 |
3 |
4 | #
5 | # These classes are mixed with regular builtins using the same technics as in
6 | # the forbiddenfruit package
7 | #
8 | class Lista(list):
9 | """
10 | Uma lista representa uma sequência de objetos.
11 |
12 | Pode ser incializada com a sintaxe:
13 |
14 | >>> L = [1, 2, 3, 4]
15 | """
16 |
17 | @synonyms('acrescente')
18 | def acrescentar(self, elemento):
19 | """Acrescenta um elemento no final da lista."""
20 |
21 | self.append(elemento)
22 |
23 | @synonyms('limpe')
24 | def limpar(self):
25 | """Remove todos os elementos, ficando vazio."""
26 |
27 | self.clear()
28 |
29 | def cópia(self):
30 | """Retorna uma cópia da lista."""
31 |
32 | return self.copy()
33 |
34 | @synonyms('conte')
35 | def contar(self, valor):
36 | """Retorna o número de ocorrências do valor dado."""
37 |
38 | return self.count(valor)
39 |
40 | @synonyms('estenda')
41 | def estender(self, seq):
42 | """Adiciona todos os elementos da sequência dada no fim da lista."""
43 |
44 | self.extend(seq)
45 |
46 | def índice(self, valor, *args):
47 | """Retorna o índice da primeira ocorrência do valor fornecido."""
48 |
49 | return self.index(valor, *args)
50 |
51 | def índice_em_intervalo(self, valor, i, j):
52 | """Retorna o índice da primeira ocorrência do valor fornecido no
53 | intervalo entre i e j."""
54 |
55 | return self.index(valor, i, j)
56 |
57 | @normalize_accented_keywords
58 | @synonyms('insira')
59 | def inserir(self, índice, valor):
60 | """Insere o elemento dado na posição dada pelo índice."""
61 |
62 | self.insert(índice, valor)
63 |
64 | @synonyms('remova')
65 | def remover(self, valor):
66 | """Remove primeira ocorrência de um elemento com o valor fornecido."""
67 |
68 | self.remove(valor)
69 |
70 | @synonyms('inverta')
71 | def inverter(self):
72 | """Reordena a lista na ordem inversa."""
73 |
74 | self.reverse()
75 |
76 | @synonyms('ordene')
77 | def ordenar(self, **kwds):
78 | """Ordena a lista."""
79 |
80 | self.sort(**kwds)
81 |
82 | @normalize_accented_keywords
83 | @synonyms('ordene_por')
84 | def ordenar_por(self, função, invertido=False):
85 | """Ordena a lista a partir segundo o resultado da aplicação da função
86 | dada em cada elemento."""
87 |
88 | self.sort(key=função, reverse=invertido)
89 |
90 | @synonyms('retire', 'retirar_último', 'retire_último')
91 | def retirar(self, *args):
92 | """Remove o último elemento da lista e o retorna."""
93 |
94 | return self.pop(*args)
95 |
96 | @normalize_accented_keywords
97 | @synonyms('retire_de')
98 | def retirar_de(self, índice):
99 | """Remove o elemento no índice dado e o retorna."""
100 |
101 | return self.pop(índice)
102 |
103 |
104 | class Tupla(tuple):
105 | """Uma tupla funciona como uma lista imutável de elementos.
106 |
107 | Tuplas podem ser chaves de dicionários, enquanto listas não.
108 |
109 | Pode ser incializada com a sintaxe::
110 |
111 | >>> pto = (1, 2, 3)
112 | """
113 |
114 | contar = Lista.contar
115 | índice = Lista.índice
116 | índice_em_intervalo = Lista.índice_em_intervalo
117 |
118 |
119 | class Conjunto(set):
120 | """Um conjunto guarda apeanas uma cópia de cada elemento distinto fornecido.
121 | Conjuntos não possuem ordenamento defindo e são inicializados com a
122 | sintaxe::
123 |
124 | >>> C = {1, 1, 2, 3} # equivalente à {1, 2, 3}
125 | """
126 |
127 | # Single element operations
128 | adicionar = adicione = set.add
129 | retirar = Lista.retirar
130 | remover = Lista.remover
131 | limpar = Lista.limpar
132 | cópia = Lista.cópia
133 | descartar = descarte = set.discard
134 |
135 | # Set properties
136 | é_disjunto = set.isdisjoint
137 | é_subconjunto = set.issubset
138 | é_superconjunto = set.issuperset
139 |
140 | # Set operations
141 | diferença = set.difference
142 | intersecção = interseção = set.intersection
143 | diferença_simétrica = set.symmetric_difference
144 | união = set.union
145 |
146 | # Set update
147 | atualizar = atualize = set.update
148 | atualizar_com_diferença = atualize_com_diferença = set.difference_update
149 | atualizar_com_diferença_simétrica = atualize_com_diferença_simétrica = \
150 | set.symmetric_difference_update
151 | atualizar_com_intersecção = atualizar_com_interseção = \
152 | atualize_com_intersecção = atualize_com_interseção = \
153 | set.intersection_update
154 |
155 |
156 | class Dicionário(dict):
157 | """
158 | Dicionário representa um mapa entre um conjunto de chaves e seus
159 | respectivos valores.
160 |
161 | Pode ser incializado com a sintaxe::
162 |
163 | >>> D = {"um": 1, "dois": 2, "três": 3}
164 | """
165 |
166 | limpar = Lista.limpar
167 | cópia = Lista.copy
168 |
169 | # = dict.fromkeys
170 | obter = obtenha = dict.get
171 |
172 | # Iterators
173 | itens = dict.items
174 | chaves = dict.keys
175 | valores = dict.values
176 |
177 | padrão = dict.setdefault
178 | atualizar = atualize = dict.update
179 | retirar = retire = dict.pop
180 | retirar_item = retire_item = dict.popitem
181 |
182 |
183 | class Texto(str):
184 | """
185 | Representa uma sequência de letras em um texto.
186 |
187 | Envolvemos o conteúdo do texto em aspas simples ou duplas:
188 |
189 | >>> texto1 = "Olá, mundo!"
190 | >>> texto2 = 'Aspas simples também funcionam ;-)'
191 | """
192 |
193 | # Case control
194 | capitalizado = str.capitalize
195 | minúsculas = str.lower
196 | maiúsculas = str.upper
197 | normalizado = str.casefold
198 | caso_trocado = str.swapcase
199 | título = str.title
200 |
201 | # Aligment
202 | centralizado = str.center
203 | justificado_à_esquerda = str.ljust
204 | justificado_à_direita = str.rjust
205 |
206 | # Queries
207 | é_alfanumérico = str.isalnum
208 | é_alfabético = str.isalpha
209 | é_decimal = str.isdecimal
210 | é_digito = str.isdigit
211 | é_numérico = str.isnumeric
212 | é_identificador = str.isidentifier
213 | é_minúscula = str.islower
214 | é_maiúscula = str.isupper
215 | é_título = str.istitle
216 | é_imprimível = str.isprintable
217 | é_espaço = str.isspace
218 |
219 | # TODO: other str methods?
220 | '''
221 | = str.count
222 | = str.encode
223 | = str.endswith
224 | = str.expandtabs
225 | = str.find
226 | = str.format
227 | = str.format_map
228 | = str.index
229 | = str.join
230 | = str.lstrip
231 | = str.maketrans
232 | = str.partition
233 | = str.replace
234 | = str.rfind
235 | = str.rindex
236 | = str.rpartition
237 | = str.rsplit
238 | = str.rstrip
239 | = str.split
240 | = str.splitlines
241 | = str.startswith
242 | = str.strip
243 | = str.translate
244 | = str.zfill
245 | '''
--------------------------------------------------------------------------------
/src/pytuga/keywords.py:
--------------------------------------------------------------------------------
1 | import collections
2 | import keyword
3 |
4 | TRANSLATIONS = dict(
5 | # Loops
6 | enquanto='while',
7 | para='for',
8 | quebre='break', quebrar='break',
9 | continuar='continue', # continue='continue',
10 | para_cada='for',
11 |
12 | # Conditions
13 | se='if',
14 | senão='else', senao='else',
15 | ou_então_se='elif', ou_entao_se='elif',
16 | ou_se='elif',
17 |
18 | # Singleton values
19 | Falso='False', falso='False',
20 | Verdadeiro='True', verdadeiro='True',
21 | nulo='None', Nulo='None',
22 |
23 | # Operators
24 | é='is', eh='is',
25 | e='and',
26 | ou='or',
27 | não='not', nao='not',
28 | em='in', na='in', no='in',
29 | como='as',
30 |
31 | # Function definition
32 | função='def', funcao='def', definir='def', defina='def',
33 | retorne='return', retornar='return',
34 | gere='yield', gerar='yield',
35 |
36 | # Error handling
37 | tente='try', tentar='try',
38 | exceção='except', excecao='except',
39 | finalmente='finally',
40 | levante_error='raise', levantar_erro='raise', # ???
41 |
42 | # Other
43 | apague='del', apagar='del',
44 | prossiga='pass', prosseguir='pass',
45 | classe='class',
46 | importe='import', importar='import',
47 | usando='with', # ???
48 | # global='global',
49 |
50 | # Pytugues to pytugues
51 | até='ate',
52 | ateh='ate',
53 | )
54 |
55 | SEQUENCE_TRANSLATIONS = {
56 | # Block ending
57 | ('faça', ':'): ':',
58 | ('faca', ':'): ':',
59 | ('fazer', ':'): ':',
60 |
61 | # Loops
62 | ('para', 'cada'): 'for',
63 |
64 | # Conditions
65 | ('então', 'faça', ':'): ':',
66 | ('então', ':'): ':',
67 | ('entao', 'faca', ':'): ':',
68 | ('entao', ':'): ':',
69 | ('ou', 'então', 'se'): 'elif',
70 | ('ou', 'entao', 'se'): 'elif',
71 | ('ou', 'se'): 'elif',
72 |
73 | # Definitions
74 | ('definir', 'função'): 'def',
75 | ('definir', 'funcao'): 'def',
76 | ('defina', 'função'): 'def',
77 | ('defina', 'funcao'): 'def',
78 | ('definir', 'classe'): 'class',
79 | ('defina', 'classe'): 'class',
80 | }
81 |
82 | ERROR_GROUPS = collections.OrderedDict(
83 | (x, 'Repetição inválida: %s' % (' '.join(x)))
84 | for x in [
85 | ('faça', 'faça'), ('faça', 'fazer'), ('fazer', 'faça'),
86 | ('então', 'então'),
87 | ]
88 | )
89 |
90 | PURE_PYTG_KEYWORDS = set(TRANSLATIONS)
91 | PURE_PYTG_KEYWORDS.update({'repetir', 'repita', 'vezes', 'cada', 'de',
92 | 'ate', 'fazer', 'faça', 'faca'})
93 | kwlist = set(PURE_PYTG_KEYWORDS)
94 | kwlist.update(keyword.kwlist)
95 | constants = (
96 | 'True', 'False', 'None',
97 | 'Verdadeiro', 'Falso', 'Nulo',
98 | 'verdadeiro', 'falso', 'nulo',
99 | )
100 |
101 |
102 | def iskeyword(k):
103 | """
104 | Return True if k is a valid Pytuguês keyword.
105 | """
106 |
107 | return k in kwlist
108 |
109 |
110 | del keyword
111 |
--------------------------------------------------------------------------------
/src/pytuga/lexer.py:
--------------------------------------------------------------------------------
1 | from tokenize import NEWLINE
2 |
3 | from transpyler import token
4 | from transpyler.lexer import Lexer
5 | from transpyler.token import Token
6 |
7 | __all__ = ['PytugaLexer']
8 |
9 |
10 | class PytugaLexer(Lexer):
11 | """
12 | Pytuga lexer.
13 |
14 | Defines the "repetir n vezes" and "de X ate Y a cada Z" commands.
15 | """
16 |
17 | def process_repetir_command(self, tokens):
18 | """
19 | Converts command::
20 |
21 | repetir vezes:
22 |
23 |
24 | or::
25 |
26 | repita vezes:
27 |
28 |
29 | to::
30 |
31 | for ___ in range():
32 |
33 | """
34 |
35 | matches = [('repetir',), ('repita',), ('vezes',), (NEWLINE,)]
36 | iterator = token.token_find(tokens, matches)
37 |
38 | for idx, match, start, end in iterator:
39 | # Send tokens to the beginning of the equivalent "for" loop
40 | starttokens = Token.from_strings(
41 | tokens[idx].start, 'for', '___', 'in', 'range', '('
42 | )
43 | del tokens[idx]
44 | token.insert_tokens_at(tokens, idx, starttokens, end=end)
45 |
46 | # Matches the 'vezes' token
47 | try:
48 | idx, match, start, end = next(iterator)
49 | except StopIteration:
50 | match = [None]
51 |
52 | if match[0] != 'vezes':
53 | raise SyntaxError(
54 | 'comando repetir malformado na linha %s.\n'
55 | ' Espera comando do tipo\n\n'
56 | ' repetir vezes:\n'
57 | ' \n\n'
58 | ' Palavra chave "vezes" está faltando!' % (start.lineno))
59 | else:
60 | tokens[idx] = Token(')', start=start)
61 | token.displace_tokens(tokens[idx + 1:], -4)
62 |
63 | return tokens
64 |
65 | def process_de_ate_command(self, tokens):
66 | """
67 | Converts command::
68 |
69 | de até [a cada ]
70 |
71 | to::
72 |
73 | in range(, + 1[, ])
74 |
75 | """
76 |
77 | matches = [('de',), ('ate',), ('a', 'cada',), (NEWLINE,), (':',)]
78 | iterator = token.token_find(tokens, matches)
79 | for idx, match, start, end in iterator:
80 | # Waits for a 'de' token to start processing
81 | if match[0] != 'de':
82 | continue
83 |
84 | # Send tokens for the beginning of the equivalent in range(...)
85 | # test
86 | start = tokens[idx].start
87 | starttokens = Token.from_strings(start, 'in', 'range', '(')
88 | del tokens[idx]
89 | token.insert_tokens_at(tokens, idx, starttokens, end=end)
90 |
91 | # Matches the 'até' token and insert a comma separator
92 | idx, match, start, end = next(iterator)
93 | if match[0] in ['até', 'ate']:
94 | token.displace_tokens(tokens[idx:], -3)
95 | tokens[idx] = Token(',', start=tokens[idx - 1].end)
96 | else:
97 | raise SyntaxError(
98 | 'comando para cada malformado na linha %s.\n'
99 | ' Espera comando do tipo\n\n'
100 | ' para cada de até :\n'
101 | ' \n\n'
102 | ' Palavra chave "até" está faltando!' % (start.lineno)
103 | )
104 |
105 | idx, match, start, end = next(iterator)
106 |
107 | # Matches "a cada" or the end of the line
108 | if match == ('a', 'cada'):
109 | middletokens = Token.from_strings(start, '+', '1', ',')
110 | del tokens[idx:idx + 2]
111 | token.insert_tokens_at(tokens, idx, middletokens, end=end)
112 |
113 | # Proceed to the end of the line
114 | idx, match, start, end = next(iterator)
115 | if match[0] not in (NEWLINE, ':'):
116 | raise SyntaxError(
117 | 'comando malformado na linha %s.\n'
118 | ' Espera um ":" no fim do bloco' % (start.lineno)
119 | )
120 | endtok = Token(')', start=start)
121 | token.displace_tokens(tokens[idx:], 1)
122 | tokens.insert(idx, endtok)
123 |
124 | # Finish command
125 | elif match[0] in (NEWLINE, ':'):
126 | token.displace_tokens(tokens[idx:], 1)
127 | endtokens = Token.from_strings(start, '+', '1', ')')
128 | token.insert_tokens_at(tokens, idx, endtokens, end=end)
129 |
130 | # Unexpected token
131 | else:
132 | raise SyntaxError(
133 | 'comando malformado na linha %s.\n'
134 | ' Espera um ":" no fim do bloco' % (start.lineno)
135 | )
136 |
137 | return tokens
138 |
139 | def transpile_tokens(self, tokens):
140 | tokens = super().transpile_tokens(tokens)
141 | tokens = self.process_repetir_command(tokens)
142 | tokens = self.process_de_ate_command(tokens)
143 | return tokens
144 |
--------------------------------------------------------------------------------
/src/pytuga/transpyler.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | from transpyler import Transpyler
4 | from transpyler.curses import curse_none_repr, curse_bool_repr, apply_curses
5 | from transpyler.utils import pretty_callable
6 | from . import __version__
7 | from . import curses
8 | from .keywords import TRANSLATIONS, SEQUENCE_TRANSLATIONS, ERROR_GROUPS
9 | from .lexer import PytugaLexer
10 |
11 |
12 | class PytugaTranspyler(Transpyler):
13 | """
14 | Pytuguês support.
15 | """
16 |
17 | name = 'pytuga'
18 | display_name = 'Pytuguês'
19 | lexer_factory = PytugaLexer
20 | translations = dict(TRANSLATIONS)
21 | translations.update(SEQUENCE_TRANSLATIONS)
22 | error_dict = ERROR_GROUPS
23 | lang = 'pt_BR'
24 |
25 | def apply_curses(self):
26 | """
27 | Apply all curses.
28 | """
29 |
30 | curse_none_repr('Nulo')
31 | curse_bool_repr('Verdadeiro', 'Falso')
32 | apply_curses({
33 | list: curses.Lista,
34 | tuple: curses.Tupla,
35 | set: curses.Conjunto,
36 | dict: curses.Dicionário,
37 | str: curses.Texto,
38 | })
39 |
40 | def __make_global_namespace(self):
41 | ns = super().make_global_namespace()
42 | exit_function = ns['exit']
43 |
44 | @pretty_callable(
45 | 'digite "sair()" para terminar a execução',
46 | autoexec=True, autoexec_message='tchau! ;-)'
47 | )
48 | def sair():
49 | """
50 | Finaliza a execução do terminal de Pytuguês.
51 | """
52 |
53 | exit_function()
54 |
55 | # Update exit function and Python constants.
56 | ns.update(
57 | sair=sair,
58 | Verdadeiro=True,
59 | verdadeiro=True,
60 | Falso=False,
61 | false=False,
62 | Nulo=None,
63 | nulo=None,
64 | )
65 | return ns
66 |
67 |
68 | # TODO: Add the help string once we implement those functions.
69 | # # HELP = (
70 | # # '\n\n'
71 | # # 'digite "ajuda()", "licença()" ou "tutorial()" para maiores informações.'
72 | # )
73 | HELP = ''
74 |
75 | PytugaTranspyler.short_banner = \
76 | '''Pytuga %s
77 | Python %s
78 |
79 | Bem-vindo ao Pytuguês, um Python com sotaque lusitano.''' \
80 | % (__version__, sys.version.splitlines()[0]) + HELP
81 |
82 | PytugaTranspyler.long_banner = \
83 | r'''Pytuga %s
84 | Python %s
85 | __
86 | /\ \__
87 | _____ __ __\ \ ,_\ __ __ __ __
88 | /\ '__`\ /\ \/\ \\ \ \/ /\ \/\ \ /'_ `\ /'__`\
89 | \ \ \L\ \\ \ \_\ \\ \ \_\ \ \_\ \/\ \L\ \ /\ \L\.\_
90 | \ \ ,__/ \/`____ \\ \__\\ \____/\ \____ \\ \__/.\_\
91 | \ \ \/ `/___/> \\/__/ \/___/ \/___L\ \\/__/\/_/
92 | \ \_\ /\___/ /\____/
93 | \/_/ \/__/ \/___/
94 |
95 |
96 | Bem-vindo ao Pytuguês, um Python com sotaque lusitano.''' \
97 | % (__version__, sys.version.splitlines()[0]) + HELP
98 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Transpyler/pytuga/6c4ea7054d3154f81498238a97761401e6ca90e2/tests/__init__.py
--------------------------------------------------------------------------------
/tests/_test_documentation.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import pytest
4 | import manuel.ignore
5 | import manuel.codeblock
6 | import manuel.doctest
7 | import manuel.testing
8 |
9 |
10 | def make_manuel_suite(ns):
11 | """
12 | Prepare Manuel test suite.
13 |
14 | Test functions are injected in the given namespace.
15 | """
16 |
17 | # Wrap function so pytest does not expect an spurious "self" fixture.
18 | def _wrapped(func, name):
19 | wrapped = lambda: func()
20 | wrapped.__name__ = name
21 | return wrapped
22 |
23 | # Collect documentation files
24 | cd = os.path.dirname
25 | path = cd(cd(cd(cd(__file__))))
26 | doc_path = os.path.join(path, 'docs')
27 | readme = os.path.join(path, 'README.rst')
28 | files = sorted(os.path.join(doc_path, f) for f in os.listdir(doc_path))
29 | files = [f for f in files if f.endswith('.rst') or f.endswith('.txt')]
30 | files.append(readme)
31 |
32 | # Create manuel suite
33 | m = manuel.ignore.Manuel()
34 | m += manuel.doctest.Manuel()
35 | m += manuel.codeblock.Manuel()
36 |
37 | # Copy tests from the suite to the global namespace
38 | suite = manuel.testing.TestSuite(m, *files)
39 | for i, test in enumerate(suite):
40 | name = 'test_doc_%s' % i
41 | ns[name] = pytest.mark.documentation(_wrapped(test.runTest, name))
42 | return suite
43 |
44 | try:
45 | make_manuel_suite(globals())
46 | except OSError:
47 | print('Documentation files not found: disabling tests!')
48 |
--------------------------------------------------------------------------------
/tests/test_core.py:
--------------------------------------------------------------------------------
1 | from pytuga import namespace, compile, transpile, exec
2 |
3 |
4 | def test_namespace():
5 | ns = namespace()
6 |
7 |
8 | def test_transpile():
9 | py = transpile('enquanto verdadeiro ou falso: prosseguir')
10 | assert py == 'while True or False: pass'
11 |
12 |
13 | def test_exec():
14 | D = {}
15 | exec('x = raiz(0 ou 1) ', D)
16 | assert D['x'] == 1
17 |
18 |
19 | def test_compile():
20 | code = compile('x = raiz(0 ou 1)', '', 'exec')
21 |
22 | D = {}
23 | exec(code, D)
24 | assert D['x'] == 1
25 |
26 | D = {}
27 | exec(code, D)
28 | assert D['x'] == 1
29 |
--------------------------------------------------------------------------------
/tests/test_errors.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from pytuga import exec
4 |
5 | # Examples with bad syntax
6 | bad_syntax_ = """
7 | ### loops
8 | para cada x de 1:
9 | pass
10 |
11 | ##
12 | para cada x de 1 em 1:
13 | pass
14 |
15 | ##
16 | para cada x de 1 aa 1:
17 | pass
18 |
19 | ##
20 | 4 vezes:
21 | ...
22 |
23 | ##
24 | repetir 4:
25 | ...
26 |
27 | ### create invalid python code (syntax error not raised by transpyler)
28 | a b
29 |
30 | """.split('##')[1:]
31 |
32 |
33 | # @pytest.fixture(params=bad_syntax_)
34 | # def bad_syntax(request):
35 | # return request.param
36 |
37 |
38 | # def test_bad_syntax_raises_syntax_error(bad_syntax):
39 | # with pytest.raises(SyntaxError):
40 | # exec(bad_syntax)
41 |
--------------------------------------------------------------------------------
/tests/test_keywords.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import pytuga.keywords as keywords
3 |
4 | def test_iskeyword():
5 | k = 'is'
6 | assert type(keywords.iskeyword(k)) is bool
7 |
8 |
--------------------------------------------------------------------------------
/tests/test_language.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from pytuga import transpile
4 | from transpyler import get_transpyler
5 |
6 | tokenize = get_transpyler().lexer.tokenize
7 |
8 |
9 | def pytg(src):
10 | return [repr(x) for x in tokenize(transpile(src))]
11 |
12 |
13 | def py(src):
14 | return [repr(x) for x in tokenize(src)]
15 |
16 |
17 | #
18 | # Dictionary of translations. Each test case is separated by a line of ='s and
19 | # where the 1st part has a Pytugues code and the second part has the
20 | # corresponding python source
21 | #
22 | data = r'''
23 | ================================================================================
24 |
25 | --------------------------------------------------------------------------------
26 |
27 | ================================================================================
28 | verdadeiro, falso, nulo, Verdadeiro, Falso, Nulo
29 | --------------------------------------------------------------------------------
30 | True, False, None, True, False, None
31 | ================================================================================
32 | a ou b, a e b, a é b
33 | --------------------------------------------------------------------------------
34 | a or b, a and b, a is b
35 | ================================================================================
36 | repetir 4 vezes: prosseguir
37 | --------------------------------------------------------------------------------
38 | for ___ in range(4): pass
39 | ================================================================================
40 | repetir 4 vezes:
41 | prosseguir
42 | --------------------------------------------------------------------------------
43 | for ___ in range(4):
44 | pass
45 | ================================================================================
46 | repetir 4 vezes:
47 | prosseguir
48 | --------------------------------------------------------------------------------
49 | for ___ in range(4):
50 | pass
51 | ================================================================================
52 | para x em L:
53 | prosseguir
54 | --------------------------------------------------------------------------------
55 | for x in L:
56 | pass
57 | ================================================================================
58 | para x em L faça:
59 | prosseguir
60 | --------------------------------------------------------------------------------
61 | for x in L:
62 | pass
63 | ================================================================================
64 | para cada x em L faça:
65 | prosseguir
66 | --------------------------------------------------------------------------------
67 | for x in L:
68 | pass
69 | ================================================================================
70 | para cada x em L faca:
71 | prosseguir
72 | --------------------------------------------------------------------------------
73 | for x in L:
74 | pass
75 | ================================================================================
76 | para cada x de 1 até 10:
77 | prosseguir
78 | --------------------------------------------------------------------------------
79 | for x in range(1, 10 + 1):
80 | pass
81 | ================================================================================
82 | '''.split('=' * 80)
83 |
84 | data = [x.split('-' * 80) for x in data if x.strip()]
85 |
86 |
87 | @pytest.fixture(params=data)
88 | def sources(request):
89 | return request.param
90 |
91 |
92 | def test_pytuga_to_python_transpile(sources):
93 | pytuga, python = sources
94 | assert pytg(pytuga) == py(python)
95 |
96 |
97 | #
98 | # Passthru translations. Each test case is separated by a blank line.
99 | #
100 | data = r'''
101 | mostre(42)
102 |
103 | x + y, x * y
104 | '''.split('\n\n')
105 |
106 |
107 | @pytest.fixture(params=data)
108 | def passtru(request):
109 | return request.param
110 |
111 |
112 | def test_passthru(passtru):
113 | assert py(passtru) == pytg(passtru)
114 |
115 |
116 | #
117 | # Old tests
118 | #
119 | def test_para_cada_in_range():
120 | ptsrc = 'para x de 1 até 10: mostre(x)'
121 | pysrc = 'for x in range(1, 10 + 1): mostre(x)'
122 | assert pytg(ptsrc) == py(pysrc)
123 |
124 | ptsrc = 'para x de 1 até 10:\n mostre(x)'
125 | pysrc = 'for x in range(1, 10 + 1):\n mostre(x)'
126 | assert pytg(ptsrc) == py(pysrc)
127 |
128 | ptsrc = 'para x de 1 até 10 faça: mostre(x)'
129 | pysrc = 'for x in range(1, 10 + 1): mostre(x)'
130 | assert pytg(ptsrc) == py(pysrc)
131 |
132 | ptsrc = 'para x de 1 até 10 a cada 2: mostre(x)'
133 | pysrc = 'for x in range(1, 10 + 1, 2): mostre(x)'
134 | assert pytg(ptsrc) == py(pysrc)
135 |
136 | ptsrc = 'para x de 1 até 10 a cada 2 faça: mostre(x)'
137 | pysrc = 'for x in range(1, 10 + 1, 2): mostre(x)'
138 | assert pytg(ptsrc) == py(pysrc)
139 |
140 | ptsrc = 'para x de 1 até 10 a cada 2 faça:\n mostre(x)'
141 | pysrc = 'for x in range(1, 10 + 1, 2):\n mostre(x)'
142 | assert pytg(ptsrc) == py(pysrc)
143 |
144 | ptsrc = '\n\npara cada x em [1, 2, 3]: mostre(x)'
145 | pysrc = '\n\nfor x in [1, 2, 3]: mostre(x)'
146 | assert pytg(ptsrc) == py(pysrc)
147 |
148 | ptsrc = 'para x de 10 até 20: mostre(x)'
149 | pysrc = 'for x in range(10, 20 + 1): mostre(x)'
150 | assert pytg(ptsrc) == py(pysrc)
151 |
152 | ptsrc = 'para xx de 10 até 20: mostre(x)'
153 | pysrc = 'for xx in range(10, 20 + 1): mostre(x)'
154 | assert pytg(ptsrc) == py(pysrc)
155 |
156 |
157 | def test_enquanto():
158 | ptsrc = 'enquanto x < 1: mostre(x)'
159 | pysrc = 'while x < 1: mostre(x)'
160 | assert pytg(ptsrc) == py(pysrc)
161 |
162 | ptsrc = 'enquanto x < 1 faça: mostre(x)'
163 | pysrc = 'while x < 1: mostre(x)'
164 | assert pytg(ptsrc) == py(pysrc)
165 |
166 | ptsrc = 'enquanto x < 1 faça:\n mostre(x)'
167 | pysrc = 'while x < 1:\n mostre(x)'
168 | assert pytg(ptsrc) == py(pysrc)
169 |
170 | ptsrc = 'enquanto não x: mostre(x)'
171 | pysrc = 'while not x: mostre(x)'
172 | assert pytg(ptsrc) == py(pysrc)
173 |
174 |
175 | def test_se():
176 | ptsrc = 'se x < 1 então: mostre(x)'
177 | pysrc = 'if x < 1: mostre(x)'
178 | assert pytg(ptsrc) == py(pysrc)
179 |
180 | ptsrc = 'se x < 1: mostre(x)'
181 | pysrc = 'if x < 1: mostre(x)'
182 | assert pytg(ptsrc) == py(pysrc)
183 |
184 | ptsrc = 'se x < 1 então:\n mostre(x)'
185 | pysrc = 'if x < 1:\n mostre(x)'
186 | assert pytg(ptsrc) == py(pysrc)
187 |
188 | ptsrc = 'se não x: mostre(x)'
189 | pysrc = 'if not x: mostre(x)'
190 | assert pytg(ptsrc) == py(pysrc)
191 |
192 | ptsrc = '\n\n\nse não x: mostre(x)'
193 | pysrc = '\n\n\nif not x: mostre(x)'
194 | assert pytg(ptsrc) == py(pysrc)
195 |
196 |
197 | def test_se_senao():
198 | ptsrc = '''
199 | se x < 1 então:
200 | mostre(x)
201 | senão:
202 | mostre(-x)
203 | '''
204 | pysrc = '''
205 | if x < 1:
206 | mostre(x)
207 | else:
208 | mostre(-x)
209 | '''
210 | assert pytg(ptsrc) == py(pysrc)
211 |
212 |
213 | def test_se__ou_entao_se__senao():
214 | ptsrc = '''
215 | se x < 1 então:
216 | mostre(x)
217 | ou então se x > 3:
218 | mostre(0)
219 | senão:
220 | mostre(-x)
221 | '''
222 | pysrc = '''
223 | if x < 1:
224 | mostre(x)
225 | elif x > 3:
226 | mostre(0)
227 | else:
228 | mostre(-x)
229 | '''
230 | assert pytg(ptsrc) == py(pysrc)
231 |
232 |
233 | def test_funcion_definition():
234 | ptsrc = 'função foo(x): retorne x'
235 | pysrc = 'def foo(x): return x'
236 | assert pytg(ptsrc) == py(pysrc)
237 |
238 | ptsrc = 'definir foo(x): retorne x'
239 | pysrc = 'def foo(x): return x'
240 | assert pytg(ptsrc) == py(pysrc)
241 |
242 | ptsrc = 'definir função foo(x): retorne x'
243 | pysrc = 'def foo(x): return x'
244 | assert pytg(ptsrc) == py(pysrc)
245 |
246 | ptsrc = 'definir função foo(x):\n retorne x'
247 | pysrc = 'def foo(x):\n return x'
248 | assert pytg(ptsrc) == py(pysrc)
249 |
250 | # Integração
251 | ptsrc = 'para cada x em [1, 2, 3]:\n mostre(x ou z)'
252 | pysrc = 'for x in [1, 2, 3]:\n mostre(x or z)'
253 | assert pytg(ptsrc) == py(pysrc)
254 |
255 |
256 | #
257 | # Simple binary operators
258 | #
259 | def test_logical_and():
260 | ptsrc = 'x e y'
261 | pysrc = 'x and y'
262 | assert pytg(ptsrc) == py(pysrc)
263 |
264 |
265 | def test_is_operator():
266 | ptsrc = 'x é verdadeiro'
267 | pysrc = 'x is True'
268 | assert pytg(ptsrc) == py(pysrc)
269 |
270 |
271 | def test_nested_loops():
272 | ptsrc = '''
273 | repetir 2 vezes:
274 | repetir 2 vezes:
275 | mostre(1)
276 | '''
277 |
278 | pysrc = '''
279 | for ___ in range(2):
280 | for ___ in range(2):
281 | mostre(1)
282 | '''
283 | assert pytg(ptsrc) == py(pysrc)
284 |
285 |
286 | def test_prefixed_nested_repetir_loops():
287 | ptsrc = '''
288 | repetir 2 vezes:
289 | 1
290 | repetir 2 vezes:
291 | 1
292 | '''
293 |
294 | pysrc = '''
295 | for ___ in range(2):
296 | 1
297 | for ___ in range(2):
298 | 1
299 | '''
300 | print(pytg(ptsrc))
301 | print(py(pysrc))
302 | assert pytg(ptsrc) == py(pysrc)
303 |
304 |
305 | def test_prefixed_nested_para_cada_loops():
306 | ptsrc = '''
307 | para cada x de 1 até 2:
308 | 1
309 | para cada y de 1 até 2:
310 | 1
311 | '''
312 |
313 | pysrc = '''
314 | for x in range(1, 2 + 1):
315 | 1
316 | for y in range(1, 2 + 1):
317 | 1
318 | '''
319 | print(pytg(ptsrc))
320 | print(py(pysrc))
321 | assert pytg(ptsrc) == py(pysrc)
322 |
323 |
324 | #
325 | # Bug tracker: these are all examples that have failed in some point and do not
326 | # belong to any category in special
327 | #
328 | def test_separate_command_blocks_regression():
329 | ptsrc = 'mostre(1)\n\n\n\npara cada x em [1, 2, 3]: mostre(x)'
330 | pysrc = 'mostre(1)\n\n\n\nfor x in [1, 2, 3]: mostre(x)'
331 | assert pytg(ptsrc) == py(pysrc)
332 |
333 | ptsrc = 'mostre(1)\n\n\n\npara x de 1 até 3: mostre(x)'
334 | pysrc = 'mostre(1)\n\n\n\nfor x in range(1, 3 + 1): mostre(x)'
335 | assert pytg(ptsrc) == py(pysrc)
336 |
337 | ptsrc = '\n\n\nsenão: mostre(x)'
338 | pysrc = '\n\n\nelse: mostre(x)'
339 | assert pytg(ptsrc) == py(pysrc)
340 |
341 | ptsrc = '\n\n\nsenão faça: mostre(x)'
342 | pysrc = '\n\n\nelse: mostre(x)'
343 | assert pytg(ptsrc) == py(pysrc)
344 |
345 |
346 | def test_function_with_long_docstring():
347 | ptsrc = '''
348 | função foo():
349 | """
350 | x
351 | """
352 | x
353 | '''
354 | pysrc = '''
355 | def foo():
356 | """
357 | x
358 | """
359 | x
360 | '''
361 | assert pytg(ptsrc) == py(pysrc)
362 |
363 |
364 | def test_full_conditional_command():
365 | ptsrc = 'se x então faça:\n pass'
366 | pysrc = 'if x:\n pass'
367 | assert pytg(ptsrc) == py(pysrc)
368 |
--------------------------------------------------------------------------------
/tests/test_pytugacore.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import pytuga
3 |
4 |
5 | def test_project_defines_author_and_version():
6 | assert hasattr(pytuga, '__author__')
7 | assert hasattr(pytuga, '__version__')
8 |
--------------------------------------------------------------------------------
/tests/test_runtime.py:
--------------------------------------------------------------------------------
1 | from pytuga import exec
2 |
3 |
4 | # def test_exec_with_locals():
5 | # loc = {}
6 | # glob = {}
7 | # exec("a = 1", glob, loc)
8 | # assert loc
9 | # assert glob
10 | # assert loc['a'] == 1
11 |
--------------------------------------------------------------------------------
/tests/test_tuga_io.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from faker import Faker
3 | from random import randint
4 | import pytuga.lib.tuga_io as tuga_io
5 | fake = Faker()
6 |
7 | def test_mostrar_alerta(capsys):
8 | random_name = fake.name()
9 | tuga_io.mostrar(random_name)
10 | out, err = capsys.readouterr()
11 | assert out == "{}\n".format(random_name)
12 | tuga_io._alert(random_name)
13 | out, err = capsys.readouterr()
14 | assert out == "{}\n".format(random_name)
15 | tuga_io.alerta(random_name)
16 | out, err = capsys.readouterr()
17 | assert out == "{}\n".format(random_name)
18 |
19 | def test_mostrar_formatado(capsys):
20 | random_name = fake.name()
21 | name_tag = "{} %s".format(random_name)
22 | random_int = randint(0, 100)
23 | tuga_io.mostrar_formatado(name_tag, random_int)
24 | out, err = capsys.readouterr()
25 | assert out == "{} {}\n".format(random_name, random_int)
26 |
27 | def test_pausar(capsys):
28 | with capsys.disabled():
29 | tuga_io.pausar()
30 |
--------------------------------------------------------------------------------
/tests/test_tuga_math.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import math as _math
3 | import random as _random
4 |
5 | import pytuga.lib.tuga_math as math
6 |
7 | pi = _math.pi
8 | neperiano = _math.exp(1)
9 |
10 | def test_raiz():
11 |
12 | assert(math.raiz(4) == 2.0)
13 | assert(math.raiz(16) == 4.0)
14 |
15 | def test_seno():
16 |
17 | assert(math.seno(0) == 0.0)
18 |
19 |
20 | def test_cosseno():
21 |
22 | assert(math.cosseno(0) == 1.0)
23 |
24 |
25 | def test_tangente():
26 |
27 | assert(math.tangente(0) == 0.0)
28 |
29 | def test_exponencial():
30 |
31 | assert(math.exponencial(1) == 2.718281828459045)
32 |
33 | def test_logaritimo():
34 |
35 | assert(math.logarítimo(1) == 0.0)
36 |
37 | def test_log10():
38 |
39 | assert(math.log10(10) == 1.0)
40 |
41 | def test_modulo():
42 |
43 | assert(math.módulo(-1) == 1)
44 |
45 | def test_sinal():
46 |
47 | assert(math.sinal(-32.0) == -1)
48 |
49 | def test_arredondar():
50 |
51 | assert(math.arredondar(1.6) == 2)
52 |
53 | def test_truncar():
54 |
55 | assert(math.truncar(1.6) == 1)
56 | assert(math.truncar(1.8) == 1)
57 | assert(math.truncar(5.3) == 5)
58 | assert(math.truncar(3.14) == 3)
59 | assert(math.truncar(1.806) == 1)
60 | assert(math.truncar(9.7) == 9)
61 |
62 | def test_maximo():
63 |
64 | assert(math.máximo([1, 5, 42, 0]) == 42)
65 |
66 | def test_minimo():
67 |
68 | assert(math.mínimo([1, 5, 42, 0]) == 0)
69 |
70 | def test_soma():
71 |
72 | assert(math.soma([1, 2, 3, 4]) == 10)
73 |
74 | def test_produto():
75 |
76 | assert(math.produto([1, 2, 3, 4, 5]) == 120)
77 |
78 | def test_todos():
79 |
80 | assert(math.todos([True, True, True]) == True)
81 | assert(math.todos([True, False, True]) == False)
82 |
83 | def test_algum():
84 |
85 | assert(math.algum([True, False, False]) == True)
86 | assert(math.algum([False, False, False]) == False)
87 |
88 |
89 | def test_aleatorio():
90 |
91 | resultado1 = math.aleatório()
92 | resultado2 = math.aleatório()
93 | resultado3 = math.aleatório()
94 | resultado4 = math.aleatório()
95 | resultado5 = math.aleatório()
96 |
97 | assert(resultado1 >= 0 and resultado1 <= 1)
98 | assert(resultado2 >= 0 and resultado2 <= 1)
99 | assert(resultado3 >= 0 and resultado3 <= 1)
100 | assert(resultado4 >= 0 and resultado4 <= 1)
101 | assert(resultado5 >= 0 and resultado5 <= 1)
102 |
103 | def test_inteiro_aleatório():
104 |
105 | resultado = math.inteiro_aleatório(1, 20)
106 | assert(resultado >= 1 and resultado <= 20)
107 |
108 | def test_lancar_dado():
109 |
110 | resultado1 = math.lançar_dado()
111 | resultado2 = math.lançar_dado()
112 | resultado3 = math.lançar_dado()
113 | resultado4 = math.lançar_dado()
114 | resultado5 = math.lançar_dado()
115 |
116 | assert(resultado1 >= 1 and resultado1 <= 6)
117 | assert(resultado2 >= 1 and resultado2 <= 6)
118 | assert(resultado3 >= 1 and resultado3 <= 6)
119 | assert(resultado4 >= 1 and resultado4 <= 6)
120 | assert(resultado5 >= 1 and resultado5 <= 6)
121 |
--------------------------------------------------------------------------------
/tests/test_tuga_std.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | import time as _time
3 |
4 | import pytuga.lib.tuga_std as std
5 |
6 | def test_real():
7 |
8 | assert(std.real(5) == 5.0)
9 | assert(std.real(673.23) == 673.23)
10 | assert(std.real("673.23") == 673.23)
11 | assert(std.real("3.1415") == 3.1415)
12 | assert(std.real(42) == 42.0)
13 |
14 | def test_inteiro():
15 |
16 | assert(std.inteiro(4.3) == 4)
17 | assert(std.inteiro(44.6E-1) == 4)
18 | assert(std.inteiro("23") == 23)
19 |
20 | def test_booleano():
21 |
22 | assert(std.booleano(0) == False)
23 | assert(std.booleano(1) == True)
24 |
25 | def test_binario():
26 |
27 | assert(std.binário(2796202) == '0b1010101010101010101010')
28 | assert(std.binário(3) == '0b11')
29 | assert(std.binário(42) == '0b101010')
30 |
31 | def test_octal():
32 |
33 | assert(std.octal(22052015) == '0o124076257')
34 | assert(std.octal(1024) == '0o2000')
35 | assert(std.octal(42) == '0o52')
36 |
37 | def test_hexadecimal():
38 |
39 | assert(std.hexadecimal(6745) == '0x1a59')
40 | assert(std.hexadecimal(2017) == '0x7e1')
41 | assert(std.hexadecimal(42) == '0x2a')
42 |
43 | def test_caractere():
44 |
45 | assert(std.caractere(227) == 'ã')
46 | assert(std.caractere(231) == 'ç')
47 | assert(std.caractere(224) == 'à')
48 |
49 | def test_tamanho():
50 |
51 | assert(std.tamanho("programando em python") == 21)
52 | assert(std.tamanho("Testando o pytuga") == 17)
53 | assert(std.tamanho("") == 0)
54 |
55 | def test_enumerar():
56 |
57 | musica = ['uni', 'duni', 'te']
58 |
59 | assert(std.listar(std.enumerar(musica)) == [(0, 'uni'), (1, 'duni'), (2, 'te')])
60 |
61 | def test_dicionario():
62 |
63 | assert(std.dicionário([(0, 'zero'), (1, 'um'), (2, 'dois')]) == {0: 'zero', 1: 'um', 2: 'dois'})
64 |
65 | def test_tupla():
66 |
67 | assert(std.tupla([1, 2, 3]) == (1, 2, 3))
68 |
69 | def test_lista():
70 |
71 | assert(std.lista(None) == [])
72 | assert(std.lista('olá') == ['o', 'l', 'á'])
73 | [1, 2, 3, 4, 5]
74 |
75 | def test_listar():
76 |
77 | assert(std.listar('olá') == ['o', 'l', 'á'])
78 |
79 | def test_listar_invertido():
80 |
81 | assert(std.listar_invertido(['uni', 'duni', 'te']) == ['te', 'duni', 'uni'])
82 |
83 | def test_ordenado():
84 |
85 | assert(std.ordenado([5, 2, 3, 1, 4]) == [1, 2, 3, 4, 5])
86 |
87 | def test_texto():
88 |
89 | assert(std.texto(42) == "42")
90 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | env =
3 | PYTHONPATH=src/:$PYTHONPATH
4 | norecursedirs =
5 | .tox
6 | testpaths =
7 | tests/
8 | addopts = --maxfail=2
9 |
10 |
11 | [flake8]
12 | # E127: over indents for visual indent
13 | # E501: line > 79 characters
14 | ignore = E501
15 |
16 | exclude =
17 | .git,
18 | __pycache__,
19 | docs/conf.py,
20 | tasks.py,
21 | build,
22 | dist,
23 | src/**/tests,
24 | src/**/__init__.py
25 | max-complexity = 7
26 |
--------------------------------------------------------------------------------