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 +21 -0
- oktopios-0.0.1/PKG-INFO +168 -0
- oktopios-0.0.1/README.md +117 -0
- oktopios-0.0.1/oktopios.egg-info/PKG-INFO +168 -0
- oktopios-0.0.1/oktopios.egg-info/SOURCES.txt +13 -0
- oktopios-0.0.1/oktopios.egg-info/dependency_links.txt +1 -0
- oktopios-0.0.1/oktopios.egg-info/entry_points.txt +2 -0
- oktopios-0.0.1/oktopios.egg-info/requires.txt +8 -0
- oktopios-0.0.1/oktopios.egg-info/top_level.txt +1 -0
- oktopios-0.0.1/pyproject.toml +56 -0
- oktopios-0.0.1/setup.cfg +4 -0
- oktopios-0.0.1/setup.py +24 -0
- oktopios-0.0.1/tests/test_interpreter.py +293 -0
- oktopios-0.0.1/tests/test_lexer.py +194 -0
- oktopios-0.0.1/tests/test_parser.py +200 -0
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.
|
oktopios-0.0.1/PKG-INFO
ADDED
|
@@ -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
|
oktopios-0.0.1/README.md
ADDED
|
@@ -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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -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_*"]
|
oktopios-0.0.1/setup.cfg
ADDED
oktopios-0.0.1/setup.py
ADDED
|
@@ -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 = ")
|