oktopios 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
oktopios-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mouanwiya Ali Soule
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: oktopios
3
+ Version: 0.0.1
4
+ Summary: Oktopios β€” un langage de programmation moderne et expressif πŸ™
5
+ Author: Mouanwiya Ali Soule
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Mouanwiya Ali Soule
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/ALISOULEMOUANWIYA/oktopios
29
+ Project-URL: Issues, https://github.com/ALISOULEMOUANWIYA/oktopios/issues
30
+ Keywords: language,programming,interpreter,oktopios,okp
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Programming Language :: Python :: 3.10
33
+ Classifier: Programming Language :: Python :: 3.11
34
+ Classifier: Programming Language :: Python :: 3.12
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Topic :: Software Development :: Interpreters
38
+ Classifier: Intended Audience :: Developers
39
+ Requires-Python: >=3.10
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: colorama>=0.4.6
43
+ Requires-Dist: tabulate>=0.9.0
44
+ Requires-Dist: camelcase>=0.2
45
+ Requires-Dist: psutil>=5.9
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest>=7.0; extra == "dev"
48
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
49
+ Dynamic: license-file
50
+ Dynamic: requires-python
51
+
52
+ # πŸ™ Oktopios
53
+
54
+ > Un langage de programmation moderne, expressif et orientΓ© objet, interprΓ©tΓ© en Python.
55
+
56
+ ---
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install oktopios
62
+ ```
63
+
64
+ Ou depuis les sources :
65
+
66
+ ```bash
67
+ git clone https://github.com/mouanwiya/oktopios
68
+ cd oktopios
69
+ pip install -e .
70
+ ```
71
+
72
+ ## Utilisation rapide
73
+
74
+ ```bash
75
+ # ExΓ©cuter un fichier
76
+ okp mon_programme.okp
77
+
78
+ # Code en ligne
79
+ okp 'print("Bonjour πŸ™")'
80
+
81
+ # Mode interactif (REPL)
82
+ okp --repl
83
+
84
+ # Aide complète
85
+ okp --help
86
+ ```
87
+
88
+ ## Syntaxe de base
89
+
90
+ ```okp
91
+ // Variables et constantes
92
+ var age: int = 25
93
+ val nom: string = "Mouanwiya"
94
+
95
+ // Fonctions
96
+ fun saluer(prenom: string): string {
97
+ return "Bonjour " + prenom + " !"
98
+ }
99
+ print(saluer(nom))
100
+
101
+ // Surcharge de fonctions
102
+ fun calcule(a: int, b: int): int { return a + b }
103
+ fun calcule(a: int, b: int, c: int): int { return (a + b) * c }
104
+
105
+ // Lambdas
106
+ val doubler = lambda(x: int) => x * 2
107
+ print(doubler(5)) // 10
108
+
109
+ // Boucles
110
+ loop (i = 0; i < 5; i += 1) {
111
+ print(i)
112
+ }
113
+
114
+ // Classes
115
+ class Animal {
116
+ var nom: string
117
+
118
+ fun __construct(n: string) {
119
+ this.nom = n
120
+ }
121
+
122
+ fun parler(): string {
123
+ return this.nom + " dit bonjour"
124
+ }
125
+ }
126
+
127
+ var chat = new Animal("Mimi")
128
+ print(chat.parler())
129
+
130
+ // Modules natifs
131
+ inject Math as math
132
+ inject String
133
+
134
+ print(Math.sqrt(16)) // 4.0
135
+ print(String.upper("hello")) // HELLO
136
+ ```
137
+
138
+ ## FonctionnalitΓ©s
139
+
140
+ - βœ… Variables typΓ©es (`var`, `val`)
141
+ - βœ… Fonctions avec surcharge (overloading)
142
+ - βœ… Lambdas et fonctions anonymes
143
+ - βœ… Classes, interfaces, classes abstraites
144
+ - βœ… HΓ©ritage, `override`, `super`
145
+ - βœ… Γ‰numΓ©rations
146
+ - βœ… Modules natifs : `Math`, `String`, `Time`, `IO`, `List`, `Dict`...
147
+ - βœ… Boucles avancΓ©es : `loop`, `filterLoop`, `sortLoop`, `permuteLoop`...
148
+ - βœ… Gestion des exceptions (`try / catch / finally / throw`)
149
+ - βœ… REPL interactif
150
+ - βœ… Importation de fichiers `.okp`
151
+
152
+ ## Commandes CLI
153
+
154
+ | Commande | Description |
155
+ |---|---|
156
+ | `okp fichier.okp` | ExΓ©cute un fichier |
157
+ | `okp 'code'` | ExΓ©cute du code inline |
158
+ | `okp --repl` | Lance le REPL |
159
+ | `okp --check fichier.okp` | VΓ©rifie la syntaxe |
160
+ | `okp --version` | Affiche la version |
161
+ | `okp --keywords` | Liste les mots-clΓ©s |
162
+ | `okp --native` | Liste les fonctions natives |
163
+ | `okp --doc` | Documentation intΓ©grΓ©e |
164
+ | `okp --init NomProjet` | CrΓ©e un projet |
165
+
166
+ ## Licence
167
+
168
+ MIT Β© Mouanwiya Ali Soule
@@ -0,0 +1,117 @@
1
+ # πŸ™ Oktopios
2
+
3
+ > Un langage de programmation moderne, expressif et orientΓ© objet, interprΓ©tΓ© en Python.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install oktopios
11
+ ```
12
+
13
+ Ou depuis les sources :
14
+
15
+ ```bash
16
+ git clone https://github.com/mouanwiya/oktopios
17
+ cd oktopios
18
+ pip install -e .
19
+ ```
20
+
21
+ ## Utilisation rapide
22
+
23
+ ```bash
24
+ # ExΓ©cuter un fichier
25
+ okp mon_programme.okp
26
+
27
+ # Code en ligne
28
+ okp 'print("Bonjour πŸ™")'
29
+
30
+ # Mode interactif (REPL)
31
+ okp --repl
32
+
33
+ # Aide complète
34
+ okp --help
35
+ ```
36
+
37
+ ## Syntaxe de base
38
+
39
+ ```okp
40
+ // Variables et constantes
41
+ var age: int = 25
42
+ val nom: string = "Mouanwiya"
43
+
44
+ // Fonctions
45
+ fun saluer(prenom: string): string {
46
+ return "Bonjour " + prenom + " !"
47
+ }
48
+ print(saluer(nom))
49
+
50
+ // Surcharge de fonctions
51
+ fun calcule(a: int, b: int): int { return a + b }
52
+ fun calcule(a: int, b: int, c: int): int { return (a + b) * c }
53
+
54
+ // Lambdas
55
+ val doubler = lambda(x: int) => x * 2
56
+ print(doubler(5)) // 10
57
+
58
+ // Boucles
59
+ loop (i = 0; i < 5; i += 1) {
60
+ print(i)
61
+ }
62
+
63
+ // Classes
64
+ class Animal {
65
+ var nom: string
66
+
67
+ fun __construct(n: string) {
68
+ this.nom = n
69
+ }
70
+
71
+ fun parler(): string {
72
+ return this.nom + " dit bonjour"
73
+ }
74
+ }
75
+
76
+ var chat = new Animal("Mimi")
77
+ print(chat.parler())
78
+
79
+ // Modules natifs
80
+ inject Math as math
81
+ inject String
82
+
83
+ print(Math.sqrt(16)) // 4.0
84
+ print(String.upper("hello")) // HELLO
85
+ ```
86
+
87
+ ## FonctionnalitΓ©s
88
+
89
+ - βœ… Variables typΓ©es (`var`, `val`)
90
+ - βœ… Fonctions avec surcharge (overloading)
91
+ - βœ… Lambdas et fonctions anonymes
92
+ - βœ… Classes, interfaces, classes abstraites
93
+ - βœ… HΓ©ritage, `override`, `super`
94
+ - βœ… Γ‰numΓ©rations
95
+ - βœ… Modules natifs : `Math`, `String`, `Time`, `IO`, `List`, `Dict`...
96
+ - βœ… Boucles avancΓ©es : `loop`, `filterLoop`, `sortLoop`, `permuteLoop`...
97
+ - βœ… Gestion des exceptions (`try / catch / finally / throw`)
98
+ - βœ… REPL interactif
99
+ - βœ… Importation de fichiers `.okp`
100
+
101
+ ## Commandes CLI
102
+
103
+ | Commande | Description |
104
+ |---|---|
105
+ | `okp fichier.okp` | ExΓ©cute un fichier |
106
+ | `okp 'code'` | ExΓ©cute du code inline |
107
+ | `okp --repl` | Lance le REPL |
108
+ | `okp --check fichier.okp` | VΓ©rifie la syntaxe |
109
+ | `okp --version` | Affiche la version |
110
+ | `okp --keywords` | Liste les mots-clΓ©s |
111
+ | `okp --native` | Liste les fonctions natives |
112
+ | `okp --doc` | Documentation intΓ©grΓ©e |
113
+ | `okp --init NomProjet` | CrΓ©e un projet |
114
+
115
+ ## Licence
116
+
117
+ MIT Β© Mouanwiya Ali Soule
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: oktopios
3
+ Version: 0.0.1
4
+ Summary: Oktopios β€” un langage de programmation moderne et expressif πŸ™
5
+ Author: Mouanwiya Ali Soule
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Mouanwiya Ali Soule
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/ALISOULEMOUANWIYA/oktopios
29
+ Project-URL: Issues, https://github.com/ALISOULEMOUANWIYA/oktopios/issues
30
+ Keywords: language,programming,interpreter,oktopios,okp
31
+ Classifier: Programming Language :: Python :: 3
32
+ Classifier: Programming Language :: Python :: 3.10
33
+ Classifier: Programming Language :: Python :: 3.11
34
+ Classifier: Programming Language :: Python :: 3.12
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Topic :: Software Development :: Interpreters
38
+ Classifier: Intended Audience :: Developers
39
+ Requires-Python: >=3.10
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: colorama>=0.4.6
43
+ Requires-Dist: tabulate>=0.9.0
44
+ Requires-Dist: camelcase>=0.2
45
+ Requires-Dist: psutil>=5.9
46
+ Provides-Extra: dev
47
+ Requires-Dist: pytest>=7.0; extra == "dev"
48
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
49
+ Dynamic: license-file
50
+ Dynamic: requires-python
51
+
52
+ # πŸ™ Oktopios
53
+
54
+ > Un langage de programmation moderne, expressif et orientΓ© objet, interprΓ©tΓ© en Python.
55
+
56
+ ---
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install oktopios
62
+ ```
63
+
64
+ Ou depuis les sources :
65
+
66
+ ```bash
67
+ git clone https://github.com/mouanwiya/oktopios
68
+ cd oktopios
69
+ pip install -e .
70
+ ```
71
+
72
+ ## Utilisation rapide
73
+
74
+ ```bash
75
+ # ExΓ©cuter un fichier
76
+ okp mon_programme.okp
77
+
78
+ # Code en ligne
79
+ okp 'print("Bonjour πŸ™")'
80
+
81
+ # Mode interactif (REPL)
82
+ okp --repl
83
+
84
+ # Aide complète
85
+ okp --help
86
+ ```
87
+
88
+ ## Syntaxe de base
89
+
90
+ ```okp
91
+ // Variables et constantes
92
+ var age: int = 25
93
+ val nom: string = "Mouanwiya"
94
+
95
+ // Fonctions
96
+ fun saluer(prenom: string): string {
97
+ return "Bonjour " + prenom + " !"
98
+ }
99
+ print(saluer(nom))
100
+
101
+ // Surcharge de fonctions
102
+ fun calcule(a: int, b: int): int { return a + b }
103
+ fun calcule(a: int, b: int, c: int): int { return (a + b) * c }
104
+
105
+ // Lambdas
106
+ val doubler = lambda(x: int) => x * 2
107
+ print(doubler(5)) // 10
108
+
109
+ // Boucles
110
+ loop (i = 0; i < 5; i += 1) {
111
+ print(i)
112
+ }
113
+
114
+ // Classes
115
+ class Animal {
116
+ var nom: string
117
+
118
+ fun __construct(n: string) {
119
+ this.nom = n
120
+ }
121
+
122
+ fun parler(): string {
123
+ return this.nom + " dit bonjour"
124
+ }
125
+ }
126
+
127
+ var chat = new Animal("Mimi")
128
+ print(chat.parler())
129
+
130
+ // Modules natifs
131
+ inject Math as math
132
+ inject String
133
+
134
+ print(Math.sqrt(16)) // 4.0
135
+ print(String.upper("hello")) // HELLO
136
+ ```
137
+
138
+ ## FonctionnalitΓ©s
139
+
140
+ - βœ… Variables typΓ©es (`var`, `val`)
141
+ - βœ… Fonctions avec surcharge (overloading)
142
+ - βœ… Lambdas et fonctions anonymes
143
+ - βœ… Classes, interfaces, classes abstraites
144
+ - βœ… HΓ©ritage, `override`, `super`
145
+ - βœ… Γ‰numΓ©rations
146
+ - βœ… Modules natifs : `Math`, `String`, `Time`, `IO`, `List`, `Dict`...
147
+ - βœ… Boucles avancΓ©es : `loop`, `filterLoop`, `sortLoop`, `permuteLoop`...
148
+ - βœ… Gestion des exceptions (`try / catch / finally / throw`)
149
+ - βœ… REPL interactif
150
+ - βœ… Importation de fichiers `.okp`
151
+
152
+ ## Commandes CLI
153
+
154
+ | Commande | Description |
155
+ |---|---|
156
+ | `okp fichier.okp` | ExΓ©cute un fichier |
157
+ | `okp 'code'` | ExΓ©cute du code inline |
158
+ | `okp --repl` | Lance le REPL |
159
+ | `okp --check fichier.okp` | VΓ©rifie la syntaxe |
160
+ | `okp --version` | Affiche la version |
161
+ | `okp --keywords` | Liste les mots-clΓ©s |
162
+ | `okp --native` | Liste les fonctions natives |
163
+ | `okp --doc` | Documentation intΓ©grΓ©e |
164
+ | `okp --init NomProjet` | CrΓ©e un projet |
165
+
166
+ ## Licence
167
+
168
+ MIT Β© Mouanwiya Ali Soule
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ oktopios.egg-info/PKG-INFO
6
+ oktopios.egg-info/SOURCES.txt
7
+ oktopios.egg-info/dependency_links.txt
8
+ oktopios.egg-info/entry_points.txt
9
+ oktopios.egg-info/requires.txt
10
+ oktopios.egg-info/top_level.txt
11
+ tests/test_interpreter.py
12
+ tests/test_lexer.py
13
+ tests/test_parser.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ okp = oktopios.vm.main:main
@@ -0,0 +1,8 @@
1
+ colorama>=0.4.6
2
+ tabulate>=0.9.0
3
+ camelcase>=0.2
4
+ psutil>=5.9
5
+
6
+ [dev]
7
+ pytest>=7.0
8
+ pytest-cov>=4.0
@@ -0,0 +1,56 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "oktopios"
7
+ version = "0.0.1"
8
+ description = "Oktopios β€” un langage de programmation moderne et expressif πŸ™"
9
+ readme = "README.md"
10
+ license = { file = "LICENSE" }
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "Mouanwiya Ali Soule" }
14
+ ]
15
+ keywords = ["language", "programming", "interpreter", "oktopios", "okp"]
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "License :: OSI Approved :: MIT License",
22
+ "Operating System :: OS Independent",
23
+ "Topic :: Software Development :: Interpreters",
24
+ "Intended Audience :: Developers",
25
+ ]
26
+ dependencies = [
27
+ "colorama>=0.4.6",
28
+ "tabulate>=0.9.0",
29
+ "camelcase>=0.2",
30
+ "psutil>=5.9",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=7.0",
36
+ "pytest-cov>=4.0",
37
+ ]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/ALISOULEMOUANWIYA/oktopios"
41
+ Issues = "https://github.com/ALISOULEMOUANWIYA/oktopios/issues"
42
+
43
+ [project.scripts]
44
+ okp = "oktopios.vm.main:main"
45
+
46
+ [tool.setuptools.packages.find]
47
+ where = ["."]
48
+ include = ["oktopios*"]
49
+
50
+ [tool.setuptools.package-data]
51
+ "oktopios" = ["metadata/*.txt", "metadata/*.md", "vm/modules/*.okp"]
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+ python_files = ["test_*.py"]
56
+ python_functions = ["test_*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,24 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="oktopios",
5
+ version="0.0.1",
6
+ description="Oktopios β€” un langage de programmation moderne et expressif πŸ™",
7
+ author="Mouanwiya Ali Soule",
8
+ license="MIT",
9
+ python_requires=">=3.10",
10
+ packages=find_packages(),
11
+ install_requires=[
12
+ "colorama>=0.4.6",
13
+ "tabulate>=0.9.0",
14
+ ],
15
+ entry_points={
16
+ "console_scripts": [
17
+ "okp=vm.main:main",
18
+ ],
19
+ },
20
+ include_package_data=True,
21
+ package_data={
22
+ "": ["metadata/*.txt", "metadata/*.md", "vm/modules/*.okp"],
23
+ },
24
+ )
@@ -0,0 +1,293 @@
1
+ """
2
+ test_interpreter.py β€” Tests d'intΓ©gration de l'interprΓ©teur Oktopios.
3
+ """
4
+ import sys, os
5
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "vm"))
6
+
7
+ import pytest
8
+ from lexer import tokenize
9
+ from parser import Parser
10
+ from interpreter import Interpreter
11
+
12
+
13
+ def run(code: str, capsys=None):
14
+ tokens = list(tokenize(code))
15
+ ast = Parser(tokens).parse()
16
+ Interpreter().interpret(ast)
17
+ if capsys:
18
+ return capsys.readouterr().out.strip()
19
+ return None
20
+
21
+
22
+ def out(code: str, capsys) -> str:
23
+ return run(code, capsys)
24
+
25
+
26
+ # ── Valeurs primitives ────────────────────────────────────────────────────────
27
+
28
+ def test_print_entier(capsys):
29
+ assert out("print(42)", capsys) == "42"
30
+
31
+
32
+ def test_print_float(capsys):
33
+ assert out("print(3.14)", capsys) == "3.14"
34
+
35
+
36
+ def test_print_string(capsys):
37
+ assert out('print("Bonjour")', capsys) == "Bonjour"
38
+
39
+
40
+ def test_print_bool_true(capsys):
41
+ assert out("print(true)", capsys) == "true"
42
+
43
+
44
+ def test_print_bool_false(capsys):
45
+ assert out("print(false)", capsys) == "false"
46
+
47
+
48
+ # ── ArithmΓ©tique ──────────────────────────────────────────────────────────────
49
+
50
+ def test_addition(capsys):
51
+ assert out("print(3 + 4)", capsys) == "7"
52
+
53
+
54
+ def test_soustraction(capsys):
55
+ assert out("print(10 - 3)", capsys) == "7"
56
+
57
+
58
+ def test_multiplication(capsys):
59
+ assert out("print(3 * 4)", capsys) == "12"
60
+
61
+
62
+ def test_division(capsys):
63
+ result = out("print(10 / 4)", capsys)
64
+ assert float(result) == pytest.approx(2.5)
65
+
66
+
67
+ def test_modulo(capsys):
68
+ assert out("print(10 % 3)", capsys) == "1"
69
+
70
+
71
+ def test_priorite_ops(capsys):
72
+ assert out("print(2 + 3 * 4)", capsys) == "14"
73
+
74
+
75
+ def test_parentheses(capsys):
76
+ assert out("print((2 + 3) * 4)", capsys) == "20"
77
+
78
+
79
+ # ── Variables ─────────────────────────────────────────────────────────────────
80
+
81
+ def test_var_int(capsys):
82
+ assert out("var x: int = 99\nprint(x)", capsys) == "99"
83
+
84
+
85
+ def test_var_reassign(capsys):
86
+ assert out("var x = 1\nx = 2\nprint(x)", capsys) == "2"
87
+
88
+
89
+ def test_val_immutable():
90
+ with pytest.raises(Exception):
91
+ run("val x = 5\nx = 6")
92
+
93
+
94
+ def test_var_string(capsys):
95
+ assert out('var s = "ok"\nprint(s)', capsys) == "ok"
96
+
97
+
98
+ def test_concat_string(capsys):
99
+ assert out('print("Hello" + " " + "World")', capsys) == "Hello World"
100
+
101
+
102
+ # ── Fonctions ─────────────────────────────────────────────────────────────────
103
+
104
+ def test_fun_call(capsys):
105
+ code = "fun double(n: int): int { return n * 2 }\nprint(double(5))"
106
+ assert out(code, capsys) == "10"
107
+
108
+
109
+ def test_fun_default_param(capsys):
110
+ code = 'fun salut(nom: string = "ami") { print(nom) }\nsalut()'
111
+ assert out(code, capsys) == "ami"
112
+
113
+
114
+ def test_fun_default_override(capsys):
115
+ code = 'fun salut(nom: string = "ami") { print(nom) }\nsalut("Ali")'
116
+ assert out(code, capsys) == "Ali"
117
+
118
+
119
+ def test_fun_surcharge(capsys):
120
+ code = """
121
+ fun f(a: int): int { return a }
122
+ fun f(a: int, b: int): int { return a + b }
123
+ print(f(5))
124
+ print(f(3, 4))
125
+ """
126
+ lines = out(code, capsys).split("\n")
127
+ assert lines[0] == "5"
128
+ assert lines[1] == "7"
129
+
130
+
131
+ def test_recursion(capsys):
132
+ code = """
133
+ fun fact(n: int): int {
134
+ if(n <= 1) { return 1 }
135
+ return n * fact(n - 1)
136
+ }
137
+ print(fact(6))
138
+ """
139
+ assert out(code, capsys) == "720"
140
+
141
+
142
+ def test_fun_imbriquee(capsys):
143
+ code = """
144
+ fun externe() {
145
+ var msg: string = "Salut"
146
+ fun interne() { print(msg) }
147
+ interne()
148
+ }
149
+ externe()
150
+ """
151
+ assert out(code, capsys) == "Salut"
152
+
153
+
154
+ # ── Lambda ────────────────────────────────────────────────────────────────────
155
+
156
+ def test_lambda_simple(capsys):
157
+ assert out("val double = lambda(n: int) => n * 2\nprint(double(5))", capsys) == "10"
158
+
159
+
160
+ def test_lambda_multi_param(capsys):
161
+ assert out("val add = lambda(a: int, b: int) => a + b\nprint(add(3, 4))", capsys) == "7"
162
+
163
+
164
+ # ── Conditions ────────────────────────────────────────────────────────────────
165
+
166
+ def test_if_vrai(capsys):
167
+ assert out("if(true) { print(1) }", capsys) == "1"
168
+
169
+
170
+ def test_if_faux(capsys):
171
+ assert out("if(false) { print(1) } else { print(0) }", capsys) == "0"
172
+
173
+
174
+ def test_if_elif(capsys):
175
+ code = "var n = 5\nif(n > 10) { print(\"grand\") } elif(n == 5) { print(\"cinq\") } else { print(\"autre\") }"
176
+ assert out(code, capsys) == "cinq"
177
+
178
+
179
+ def test_comparaison_egalite(capsys):
180
+ assert out("print(3 == 3)", capsys) == "true"
181
+
182
+
183
+ def test_comparaison_inegalite(capsys):
184
+ assert out("print(3 != 4)", capsys) == "true"
185
+
186
+
187
+ # ── Boucles ───────────────────────────────────────────────────────────────────
188
+
189
+ def test_while(capsys):
190
+ code = "var i = 0\nwhile(i < 3) { print(i)\ni += 1 }"
191
+ lines = out(code, capsys).split("\n")
192
+ assert lines == ["0", "1", "2"]
193
+
194
+
195
+ def test_for_cstyle(capsys):
196
+ code = "for(var i: int = 0; i < 3; i += 1) { print(i) }"
197
+ lines = out(code, capsys).split("\n")
198
+ assert lines == ["0", "1", "2"]
199
+
200
+
201
+ def test_for_each(capsys):
202
+ code = "var nums: int[] = [1, 2, 3]\nfor(n in nums) { print(n) }"
203
+ lines = out(code, capsys).split("\n")
204
+ assert lines == ["1", "2", "3"]
205
+
206
+
207
+ def test_break(capsys):
208
+ code = "var i = 0\nwhile(i < 10) { if(i == 3) { break }\nprint(i)\ni += 1 }"
209
+ lines = out(code, capsys).split("\n")
210
+ assert "3" not in lines
211
+ assert lines[-1] == "2"
212
+
213
+
214
+ # ── Classes ───────────────────────────────────────────────────────────────────
215
+
216
+ def test_class_instanciation(capsys):
217
+ code = """
218
+ class Point {
219
+ var x: int
220
+ var y: int
221
+ fun __construct(px: int, py: int) {
222
+ this.x = px
223
+ this.y = py
224
+ }
225
+ fun afficher(): string {
226
+ return "(" + this.x + ", " + this.y + ")"
227
+ }
228
+ }
229
+ var p = new Point(3, 4)
230
+ print(p.afficher())
231
+ """
232
+ assert out(code, capsys) == "(3, 4)"
233
+
234
+
235
+ def test_class_heritage(capsys):
236
+ code = """
237
+ class Animal {
238
+ var nom: string
239
+ fun __construct(n: string) { this.nom = n }
240
+ fun parler(): string { return this.nom + " parle" }
241
+ }
242
+ class Chien extends Animal {
243
+ override fun parler(): string { return this.nom + " aboie" }
244
+ }
245
+ var rex = new Chien("Rex")
246
+ print(rex.parler())
247
+ """
248
+ assert out(code, capsys) == "Rex aboie"
249
+
250
+
251
+ # ── Modules natifs ────────────────────────────────────────────────────────────
252
+
253
+ def test_math_sqrt(capsys):
254
+ assert out("inject Math\nprint(Math.sqrt(16))", capsys) == "4.0"
255
+
256
+
257
+ def test_math_abs(capsys):
258
+ assert out("inject Math\nprint(Math.abs(-7))", capsys) == "7"
259
+
260
+
261
+ def test_string_upper(capsys):
262
+ assert out('inject String\nprint(String.upper("hello"))', capsys) == "HELLO"
263
+
264
+
265
+ def test_string_lower(capsys):
266
+ assert out('inject String\nprint(String.lower("MONDE"))', capsys) == "monde"
267
+
268
+
269
+ def test_string_length(capsys):
270
+ assert out('inject String\nprint(String.length("okp"))', capsys) == "3"
271
+
272
+
273
+ # ── Gestion d'erreurs ─────────────────────────────────────────────────────────
274
+
275
+ def test_variable_inconnue():
276
+ with pytest.raises(Exception):
277
+ run("print(variableInexistante)")
278
+
279
+
280
+ def test_division_par_zero():
281
+ with pytest.raises(Exception):
282
+ run("print(1 / 0)")
283
+
284
+
285
+ def test_try_catch(capsys):
286
+ code = """
287
+ try {
288
+ throw "Erreur test"
289
+ } catch(e) {
290
+ print("AttrapΓ©")
291
+ }
292
+ """
293
+ assert out(code, capsys) == "AttrapΓ©"
@@ -0,0 +1,194 @@
1
+ """
2
+ test_lexer.py β€” Tests unitaires du lexeur Oktopios.
3
+ """
4
+ import sys, os
5
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "vm"))
6
+
7
+ import pytest
8
+ from lexer import tokenize
9
+ from token_type import TokenType
10
+
11
+
12
+ def tok(code):
13
+ return list(tokenize(code))
14
+
15
+
16
+ # ── Primitives ────────────────────────────────────────────────────────────────
17
+
18
+ def test_entier():
19
+ tokens = tok("42")
20
+ assert tokens[0].type == TokenType.NUMBER
21
+ assert tokens[0].value == 42
22
+
23
+
24
+ def test_float():
25
+ tokens = tok("3.14")
26
+ assert tokens[0].type == TokenType.NUMBER
27
+ assert abs(tokens[0].value - 3.14) < 1e-9
28
+
29
+
30
+ def test_string():
31
+ tokens = tok('"Bonjour"')
32
+ assert tokens[0].type == TokenType.STR
33
+ assert tokens[0].value == "Bonjour"
34
+
35
+
36
+ def test_booleen_true():
37
+ tokens = tok("true")
38
+ assert tokens[0].type == TokenType.BOOLVAL
39
+ assert tokens[0].value == "true"
40
+
41
+
42
+ def test_booleen_false():
43
+ tokens = tok("false")
44
+ assert tokens[0].type == TokenType.BOOLVAL
45
+
46
+
47
+ # ── Mots-clΓ©s ─────────────────────────────────────────────────────────────────
48
+
49
+ def test_keyword_var():
50
+ tokens = tok("var")
51
+ assert tokens[0].type == TokenType.VAR
52
+
53
+
54
+ def test_keyword_val():
55
+ tokens = tok("val")
56
+ assert tokens[0].type == TokenType.VAL
57
+
58
+
59
+ def test_keyword_fun():
60
+ tokens = tok("fun")
61
+ assert tokens[0].type == TokenType.FUN
62
+
63
+
64
+ def test_keyword_if():
65
+ tokens = tok("if")
66
+ assert tokens[0].type == TokenType.IF
67
+
68
+
69
+ def test_keyword_return():
70
+ tokens = tok("return")
71
+ assert tokens[0].type == TokenType.RETURN
72
+
73
+
74
+ def test_keyword_class():
75
+ tokens = tok("class")
76
+ assert tokens[0].type == TokenType.CLASS
77
+
78
+
79
+ def test_keyword_loop():
80
+ tokens = tok("loop")
81
+ assert tokens[0].type == TokenType.LOOP
82
+
83
+
84
+ def test_keyword_for():
85
+ tokens = tok("for")
86
+ assert tokens[0].type == TokenType.FOR
87
+
88
+
89
+ def test_keyword_while():
90
+ tokens = tok("while")
91
+ assert tokens[0].type == TokenType.WHILE
92
+
93
+
94
+ def test_keyword_lambda():
95
+ tokens = tok("lambda")
96
+ assert tokens[0].type == TokenType.LAMBDA
97
+
98
+
99
+ def test_keyword_inject():
100
+ tokens = tok("inject")
101
+ assert tokens[0].type == TokenType.INJECT
102
+
103
+
104
+ def test_keyword_enum():
105
+ tokens = tok("enum")
106
+ assert tokens[0].type == TokenType.ENUM
107
+
108
+
109
+ # ── OpΓ©rateurs ────────────────────────────────────────────────────────────────
110
+
111
+ def test_op_plus():
112
+ tokens = tok("+")
113
+ assert tokens[0].type == TokenType.PLUS
114
+
115
+
116
+ def test_op_minus():
117
+ tokens = tok("-")
118
+ assert tokens[0].type == TokenType.MINUS
119
+
120
+
121
+ def test_op_eqeq():
122
+ tokens = tok("==")
123
+ assert tokens[0].type == TokenType.EQEQ
124
+
125
+
126
+ def test_op_neq():
127
+ tokens = tok("!=")
128
+ assert tokens[0].type == TokenType.NEQ
129
+
130
+
131
+ def test_op_lte():
132
+ tokens = tok("<=")
133
+ assert tokens[0].type == TokenType.LTE
134
+
135
+
136
+ def test_op_gte():
137
+ tokens = tok(">=")
138
+ assert tokens[0].type == TokenType.GTE
139
+
140
+
141
+ def test_op_pluseq():
142
+ tokens = tok("+=")
143
+ assert tokens[0].type == TokenType.PLUSEQ
144
+
145
+
146
+ # ── Positions (ligne / colonne) ────────────────────────────────────────────────
147
+
148
+ def test_position_ligne():
149
+ tokens = tok("var x = 1\nvar y = 2")
150
+ # 'var' de la 2e ligne
151
+ y_tok = next(t for t in tokens if t.value == "y")
152
+ assert y_tok.line == 2
153
+
154
+
155
+ def test_position_colonne():
156
+ tokens = tok("var x = 42")
157
+ x_tok = next(t for t in tokens if t.value == "x")
158
+ assert x_tok.column == 4
159
+
160
+
161
+ # ── Commentaires ignorΓ©s ──────────────────────────────────────────────────────
162
+
163
+ def test_commentaire_ignore():
164
+ tokens = tok("// ceci est un commentaire\nvar x = 1")
165
+ types = [t.type for t in tokens]
166
+ assert TokenType.VAR in types
167
+ # Aucun token de type commentaire
168
+ assert all(t.type != TokenType.EOF or True for t in tokens)
169
+
170
+
171
+ # ── SΓ©quences complexes ───────────────────────────────────────────────────────
172
+
173
+ def test_sequence_declaration():
174
+ tokens = tok("var age: int = 25")
175
+ types = [t.type for t in tokens[:-1]] # sans EOF
176
+ assert TokenType.VAR in types
177
+ assert TokenType.INT in types
178
+ assert TokenType.NUMBER in types
179
+
180
+
181
+ def test_not_in_fusion():
182
+ """'not in' doit Γͺtre fusionnΓ© en un seul token NOT_IN."""
183
+ tokens = tok("x not in liste")
184
+ assert any(t.type == TokenType.NOT_IN for t in tokens)
185
+
186
+
187
+ def test_eof_present():
188
+ tokens = tok("42")
189
+ assert tokens[-1].type == TokenType.EOF
190
+
191
+
192
+ def test_caractere_inattendu():
193
+ with pytest.raises((SyntaxError, Exception)):
194
+ tok("var x = @")
@@ -0,0 +1,200 @@
1
+ """
2
+ test_parser.py β€” Tests unitaires du parseur Oktopios.
3
+ """
4
+ import sys, os
5
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "vm"))
6
+
7
+ import pytest
8
+ from lexer import tokenize
9
+ from parser import Parser
10
+ from ast_nodes import (
11
+ Program, VarDecl, FunDecl, ClassDeclaration,
12
+ IfStmt, WhileStmt, ForEachStmt, BlockStmt,
13
+ ReturnStmt, PrintStmt, Literal, Variable, BinaryOp, FuncCall
14
+ )
15
+
16
+
17
+ def parse(code):
18
+ tokens = list(tokenize(code))
19
+ return Parser(tokens).parse()
20
+
21
+
22
+ # ── Programme vide ────────────────────────────────────────────────────────────
23
+
24
+ def test_programme_vide():
25
+ ast = parse("")
26
+ assert isinstance(ast, Program)
27
+ assert ast.body == []
28
+
29
+
30
+ # ── DΓ©clarations de variables ─────────────────────────────────────────────────
31
+
32
+ def test_var_int():
33
+ ast = parse("var x: int = 42")
34
+ node = ast.body[0]
35
+ assert isinstance(node, VarDecl)
36
+ assert node.name == "x"
37
+
38
+
39
+ def test_val_string():
40
+ ast = parse('val msg: string = "Oktopios"')
41
+ node = ast.body[0]
42
+ assert isinstance(node, VarDecl)
43
+ assert node.name == "msg"
44
+ assert node.is_constant is True
45
+
46
+
47
+ def test_var_sans_type():
48
+ ast = parse("var x = 10")
49
+ node = ast.body[0]
50
+ assert isinstance(node, VarDecl)
51
+
52
+
53
+ # ── Fonctions ─────────────────────────────────────────────────────────────────
54
+
55
+ def test_fun_simple():
56
+ ast = parse("fun saluer() { }")
57
+ node = ast.body[0]
58
+ assert isinstance(node, FunDecl)
59
+ assert node.name == "saluer"
60
+
61
+
62
+ def test_fun_avec_params():
63
+ ast = parse("fun add(a: int, b: int): int { return a + b }")
64
+ node = ast.body[0]
65
+ assert isinstance(node, FunDecl)
66
+ assert len(node.params) == 2
67
+ assert node.params[0][0] == "a"
68
+ assert node.params[1][0] == "b"
69
+
70
+
71
+ def test_fun_return_type():
72
+ ast = parse("fun get(): string { return \"ok\" }")
73
+ node = ast.body[0]
74
+ assert isinstance(node, FunDecl)
75
+ assert node.return_type == "string"
76
+
77
+
78
+ def test_fun_surcharge():
79
+ ast = parse("""
80
+ fun f(a: int): int { return a }
81
+ fun f(a: int, b: int): int { return a + b }
82
+ """)
83
+ funs = [n for n in ast.body if isinstance(n, FunDecl)]
84
+ assert len(funs) == 2
85
+
86
+
87
+ # ── Conditions ────────────────────────────────────────────────────────────────
88
+
89
+ def test_if_simple():
90
+ ast = parse("if(x > 0) { print(x) }")
91
+ node = ast.body[0]
92
+ assert isinstance(node, IfStmt)
93
+
94
+
95
+ def test_if_else():
96
+ ast = parse("if(x > 0) { print(1) } else { print(0) }")
97
+ node = ast.body[0]
98
+ assert isinstance(node, IfStmt)
99
+ assert node.else_body is not None
100
+
101
+
102
+ def test_if_elif_else():
103
+ ast = parse("if(x > 0) { print(1) } elif(x == 0) { print(0) } else { print(-1) }")
104
+ node = ast.body[0]
105
+ assert isinstance(node, IfStmt)
106
+
107
+
108
+ # ── Boucles ───────────────────────────────────────────────────────────────────
109
+
110
+ def test_while():
111
+ ast = parse("while(i < 10) { i += 1 }")
112
+ # WhileStmt peut Γͺtre wrappΓ© dans un BlockStmt
113
+ node = ast.body[0]
114
+ assert isinstance(node, WhileStmt)
115
+
116
+
117
+ def test_for_each():
118
+ ast = parse("for(n in nums) { print(n) }")
119
+ node = ast.body[0]
120
+ assert isinstance(node, ForEachStmt)
121
+ assert node.var_name == "n"
122
+
123
+
124
+ def test_for_cstyle():
125
+ ast = parse("for(var i: int = 0; i < 3; i += 1) { print(i) }")
126
+ # Produit un BlockStmt(VarDecl, WhileStmt)
127
+ node = ast.body[0]
128
+ assert isinstance(node, (BlockStmt, WhileStmt))
129
+
130
+
131
+ # ── Classes ───────────────────────────────────────────────────────────────────
132
+
133
+ def test_class_vide():
134
+ ast = parse("class Animal { }")
135
+ node = ast.body[0]
136
+ assert isinstance(node, ClassDeclaration)
137
+ assert node.name == "Animal"
138
+
139
+
140
+ def test_class_avec_methode():
141
+ ast = parse("""
142
+ class Chat {
143
+ fun parler(): string {
144
+ return "Miaou"
145
+ }
146
+ }
147
+ """)
148
+ node = ast.body[0]
149
+ assert isinstance(node, ClassDeclaration)
150
+
151
+
152
+ def test_class_extends():
153
+ ast = parse("class Chien extends Animal { }")
154
+ node = ast.body[0]
155
+ assert isinstance(node, ClassDeclaration)
156
+ assert node.superclass is not None
157
+
158
+
159
+ # ── Expressions ───────────────────────────────────────────────────────────────
160
+
161
+ def test_binop_addition():
162
+ ast = parse("print(1 + 2)")
163
+ # Ne doit pas lever d'exception
164
+
165
+
166
+ def test_binop_precedence():
167
+ ast = parse("print(2 + 3 * 4)")
168
+ # 2 + (3*4) = 14, pas (2+3)*4 = 20
169
+
170
+
171
+ def test_appel_fonction():
172
+ ast = parse("add(1, 2)")
173
+ node = ast.body[0]
174
+ # FuncCall ou ExpressionStmt wrappant FuncCall
175
+ assert node is not None
176
+
177
+
178
+ def test_acces_attribut():
179
+ ast = parse("obj.nom")
180
+
181
+
182
+ def test_new():
183
+ ast = parse("var a = new Animal()")
184
+
185
+
186
+ # ── Erreurs de syntaxe ────────────────────────────────────────────────────────
187
+
188
+ def test_accolade_manquante():
189
+ with pytest.raises(Exception):
190
+ parse("fun f() { ")
191
+
192
+
193
+ def test_paren_non_fermee():
194
+ with pytest.raises(Exception):
195
+ parse("print(42")
196
+
197
+
198
+ def test_expression_invalide():
199
+ with pytest.raises(Exception):
200
+ parse("var x = ")