diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e66f844 --- /dev/null +++ b/LICENSE @@ -0,0 +1,7 @@ +Copyright 2025 Afonya + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c215016 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Astro Lang +Egy magyar + GenZ programozási nyelv + +--- + +## Miben jobb: +- többszavas változók +- magyar kulcsszavak +- teljes értékű dokumentáció +- Rustban írt + +--- + +## Példa: +```asl +gethelj a = 10 +ugass(a) +``` + +--- + +Weboldal és dokumentáció: [itt](https://astrolang.afonyanet.hu) + +Kiadások: [itt](https://git.afonyanet.hu/afonya/AstroLang/releases) + +Licensz: MIT \ No newline at end of file diff --git a/docs/LICENSE b/docs/LICENSE new file mode 100644 index 0000000..e66f844 --- /dev/null +++ b/docs/LICENSE @@ -0,0 +1,7 @@ +Copyright 2025 Afonya + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..da94e10 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,26 @@ +# Astro Lang Docs +Egy magyar + GenZ programozási nyelv + +--- + +## Miben jobb: +- többszavas változók +- magyar kulcsszavak +- teljes értékű dokumentáció +- Rustban írt + +--- + +## Példa: +```asl +gethelj a = 10 +ugass(a) +``` + +--- + +Weboldal és dokumentáció: [itt](https://astrolang.afonyanet.hu) + +Kiadások: [itt](https://git.afonyanet.hu/afonya/AstroLang/releases) + +Licensz: MIT \ No newline at end of file diff --git a/docs/docs/asx.md b/docs/docs/asx.md index 04263d8..7062399 100644 --- a/docs/docs/asx.md +++ b/docs/docs/asx.md @@ -36,6 +36,8 @@ Ezt megtudod nézni a `ASL viewx ` parancs használatával. |Szövegek|Lásd: [Szövegek](#szövegek)|| |Funkciók száma|Elmondja, hogy a funkcióban mennyi funkció meghívás van.|4 bytes| |Funkciók|Lásd: [Funkció meghívások](#funkció-meghívások)|| +|Catch pos|Megmutatja a catch funkció helyzetét, csak try-ban. Normál funkciók esetén 0|4 bytes| +|Instrukciók száma|Elmondja, hogy a funkcióban mennyi instrukció van.|4 bytes| |Instukciók|Lásd: [Instrukciók](#instrukciók)|| ## Változók: diff --git a/docs/docs/enviroment.md b/docs/docs/enviroment.md index 8a5fbda..893e3fc 100644 --- a/docs/docs/enviroment.md +++ b/docs/docs/enviroment.md @@ -15,6 +15,8 @@ description: Az Astro Lang környezete |csömör|Hibával befejezi a programot.|`csömör(error: string)`|`csömör(szaft"Sikertelen: Sikeresen befejezve!"szaft)`| |tarh|Kíírja, hogy a megadott érték milyen típusú.|`tarh(object: any): string`|`tarh(82)`| |bimbabemb|Átalakítja a megadott érétk típusát, ha lehetséges.|`bimbabemb(object: any, target: string): any`|`bimbabemb(7,szaft"string"szaft)`| +|mennyi az idő|Visszaadja a pillanatnyi UNIX időt milisec-ben.|`mennyi az idő(): number`|`mennyi az idő()`| +|joink|Bekér egy szöveget a terminálból.|`joink(): string`|`joink()`| --- @@ -65,7 +67,7 @@ Példa: `szaft.csemerd fel` --- -## Tábla (Tábla) +## Tábla (Table) Táblákkal lévő funkciók :::tip @@ -117,6 +119,7 @@ Példa: `kábel.halgass` |Név|Leírás|Használat|Példa| |---|---|---|---| |halgass|Hallgat egy porton.|`halgass(host: string, port: number): halgató`|`halgass(szaft"0.0.0.0"szaft,1010)`| +|kapcsolódj|Rákapcsolódik egy célra.|`kapcsolódj(target: string): kapcsolat`|`kapcsolódj(szaft"example.com:80"szaft)`| :::warning @@ -134,4 +137,50 @@ Ezek a funkciók kérik, hogy az első értékük a szülő táblájuk legyen |---|---|---|---| |olvass|Beleolvas a kapcsolatba.|`olvass(stream: kapcsolat, len: number): string`|`olvass(stream, 1024)`| |írj|Beleír a kapcsolatba.|`írj(stream: kapcsolat, data: string)`|`írj(stream, szaft"Hello from ASL!"szaft)`| -|zár|Bezárja a kapcsolatot.|`zár(stream: kapcsolat)`|`zár(stream)`| \ No newline at end of file +|zár|Bezárja a kapcsolatot.|`zár(stream: kapcsolat)`|`zár(stream)`| + +--- + +## Intéző (Filesystem) +Fájlokkal lévő funkciók +:::tip + +A példák elé kell írni a kulcsszót: `intéző` + +Példa: `intéző.létezik` + +::: +:::warning + +A fájlok, helyét bárhogy megadhatod, viszont a törlésnél légy óvatos! + +A fájl írása felülírja a már fájlban lévő adatokat! + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|létezik|Megnézi, hogy létezik-e az elérési út.|`létezik(path: string): boolean`|`létezik(szaft"test.asl"szaft)`| +|infó|Lekéri a metaadatokat az adott elérési útból.|`infó(path: string): table`|`infó(szaft"test.asl"szaft)`| +|mappít|Létrehozza a mappákat, hogy elérje az elérési útat.|`mappít(path: string)`|`mappít(szaft"test1/test2/"szaft)`| +|mappát töröl|Kitöröl egy mappát.|`mappát töröl(path: string)`|`mappát töröl(szaft"test1/"szaft)`| +|fájlt töröl|Kitöröl egy fájlt.|`fájlt töröl(path: string)`|`fájlt töröl(szaft"compiled.asx"szaft)`| +|olvass|Beolvas egy fájlt.|`olvass(path: string): string`|`olvass(szaft"test.asl"szaft)`| +|írj|Beleírja egy fájlba a kapott adatokat.|`írj(path: string, data: string)`|`írj(szaft"test.txt"szaft, szaft"Hello from ASL!"szaft)`| + +--- + +## Krumpli (Coroutine) +Multi-tasking funkciók +:::tip + +A példák elé kell írni a kulcsszót: `krumpli` + +Példa: `krumpli.várj` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|várj|Visszaadja a futást az előző thread-nak.|`várj()`|`várj()`| +|létrehoz|Létrehoz egy új thread-et.|`létrehoz(f: function): coroutine`|`létrehoz(lőcsve() { ugass(7) })`| +|folytat|Folytatja a thread-et.|`folytat(c: coroutine)`|`folytat(c)`| +|státusz|Visszaadja a thread státuszát.|`folytat(c: coroutine)`|`folytat(c)`| \ No newline at end of file diff --git a/docs/docs/langfunctions.md b/docs/docs/langfunctions.md index 8434f5a..72244b1 100644 --- a/docs/docs/langfunctions.md +++ b/docs/docs/langfunctions.md @@ -252,7 +252,7 @@ ugass(a[0]) // 1 ``` ### Gyors lekérés -Használat: `tábla[kulcs]` +Használat: `tábla.kulcs` :::warning @@ -275,4 +275,27 @@ gethelj a = {1,2,3} ugass(a[0]) // 1 a[0] = 12 ugass(a[0]) // 12 +``` + +--- + +## Try/Catch (Próbáld ki) +Kulcsszó: `piszolj, csecs` + +Használat: `piszolj {amit ki kell próbálni} csecs (error) {ha hiba}` + +:::warning + +A catch rész itt nem rakható bárhova, nem úgy mint az if-nél! + +::: + +Példa: +```asl title="example.asl" +piszolj { + gethelj test = szaft"a"szaft+1 +} csecs (e) { + //Ez akkor fog lefutni, mikor hiba van + ugass(e) +} ``` \ No newline at end of file diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 1303cd7..1b44412 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -23,6 +23,12 @@ function HomepageHeader() { to="/docs/intro"> Nézd meg a dokumentációt! + + Töltsd le! + diff --git a/docs/versioned_docs/version-1.0.0/asx.md b/docs/versioned_docs/version-1.0.0/asx.md new file mode 100644 index 0000000..7062399 --- /dev/null +++ b/docs/versioned_docs/version-1.0.0/asx.md @@ -0,0 +1,110 @@ +--- +sidebar_position: 5 +description: Az ASX fájl leírása +--- + +# ASX (Astro Lang Executable) fájl + +--- + +:::info + +ASX Verzió: `0.2.0` + +::: + +:::info + +Ezt megtudod nézni a `ASL viewx ` parancs használatával. + +::: + +## Fájl felépítése: +|Név|Leírás|Méret| +|---|---|---| +|Doctype: ASX|Elmondja a fájlról, hogy tényleg ASX.|3 bytes| +|Verzió|Elmondja a fájl ASX verzióját. (byte.byte.byte)|3 bytes| +|Funkciók száma|Elmondja, hogy mennyi funkció van a fájlban.|4 bytes| +|Funkciók|Lásd: [Funkciók](#funkciók)|| + +## Funkciók: +|Név|Leírás|Méret| +|---|---|---| +|Változók száma|Elmondja, hogy a funkcióban mennyi változó van.|4 bytes| +|Változók|Lásd: [Változók](#változók)|| +|Szövegek száma|Elmondja, hogy a funkcióban mennyi szöveg van.|4 bytes| +|Szövegek|Lásd: [Szövegek](#szövegek)|| +|Funkciók száma|Elmondja, hogy a funkcióban mennyi funkció meghívás van.|4 bytes| +|Funkciók|Lásd: [Funkció meghívások](#funkció-meghívások)|| +|Catch pos|Megmutatja a catch funkció helyzetét, csak try-ban. Normál funkciók esetén 0|4 bytes| +|Instrukciók száma|Elmondja, hogy a funkcióban mennyi instrukció van.|4 bytes| +|Instukciók|Lásd: [Instrukciók](#instrukciók)|| + +## Változók: +|Név|Méret| +|---|---| +|Változó nevének hossza|4 bytes| +|Változó neve|| +|Változó ID-je|3 bytes| +|Változó kezdő ponja|4 bytes| +|Változó végpontja|4 bytes| + +## Szövegek: +|Név|Méret| +|---|---| +|Szöveg ID-je|3 bytes| +|A szöveg hossza|4 bytes| +|A szöveg|| + +## Funkció meghívások: +|Név|Méret| +|---|---| +|A meghívás ID-je|3 bytes| +|A meghívott funkció pozíciója|4 bytes| + +## Instrukciók: +:::info + +Minden instrukció végére hozzáadunk még 3 bit-et, így összesen 10 byte-ba belefér minden instrukció. + +::: +|OP Code - 5 bits|Rövid név|Leírás|Arg1 - 4 bits|Arg2 - 64 bits|Arg3 - 4 bits| +|---|---|---|---|---|---| +|0|HLT|Befejezi a program futtatását|||| +|1|LDS|Betölt egy szöveget a regiszterbe|R(A)|Szöveg ID|| +|2|LDM|Betölti a változót a memóriából|R(A)|Változó ID|| +|3|LDI|Betölt egy számot a regiszterbe|R(A)|Szám|| +|4|LDB|Betölt egy logikai értéket a regiszterbe|R(A)|Logikai érték|| +|5|LDF|Betölt egy funkciót a regiszterbe|R(A)|Funkció ID|| +|6|LDN|Betölt egy null-t/táblát a regiszterbe|R(A)|Ez egy tábla?|| +|7|ASS|Hozzáad egy változó ID-t a regiszerhez|R(A)|Változó ID|| +|8|UNB|Leválaszja a regiszterről a változót|R(A)||| +|9|MOV|Átmásolja R(A) pointerjét R(B)-be|R(A)|R(B)|| +|10|ADD|`R(C) = R(A) + R(B)`|R(A)|R(B)|R(C)| +|11|SUB|`R(C) = R(A) - R(B)`|R(A)|R(B)|R(C)| +|12|MUL|`R(C) = R(A) * R(B)`|R(A)|R(B)|R(C)| +|13|DIV|`R(C) = R(A) / R(B)`|R(A)|R(B)|R(C)| +|14|POW|`R(C) = R(A) ^ R(B)`|R(A)|R(B)|R(C)| +|15|MOD|`R(C) = R(A) % R(B)`|R(A)|R(B)|R(C)| +|16|AND|`R(C) = R(A) && R(B)`|R(A)|R(B)|R(C)| +|17|OR|`R(C) = R(A) \|\| R(B)`|R(A)|R(B)|R(C)| +|18|EQ|`R(C) = R(A) == R(B)`|R(A)|R(B)|R(C)| +|19|NEQ|`R(C) = R(A) != R(B)`|R(A)|R(B)|R(C)| +|20|GRE|`R(C) = R(A) > R(B)`|R(A)|R(B)|R(C)| +|21|GRQ|`R(C) = R(A) >= R(B)`|R(A)|R(B)|R(C)| +|22|LES|`R(C) = R(A) < R(B)`|R(A)|R(B)|R(C)| +|23|LEQ|`R(C) = R(A) <= R(B)`|R(A)|R(B)|R(C)| +|24|NOT|`R(B) = !R(A)`|R(A)|R(B)|| +|25|JMP|Oda ugrik a kódban||Hely|| +|26|CJP|Oda ugrik a kódban, ha a regiszter igaz|R(A)|Hely|| +|27|CAL|Meghív egy funkciót, majd a kimenetet elmenti R(B)-be|R(A)|R(B)|| +|28|PSH|Egy értéket belerak a következő funkció bemeneteihez|R(A)||| +|29|RET|Visszad egy értéket|R(A)||| +|30|GET|Lekér egy értéket a táblából `R(C) = R(A)[R(B)]`|R(A)|R(B)|R(C)| +|31|SET|Beállít egy értéket a táblának `R(A)[R(B)] = R(C)`|R(A)|R(B)|R(C)| + +:::tip + +Ha az ENV-ből szeretnénk lekérni valamit akkor a `GET`-et kell használni, úgy, hogy `R(A) = 0`! + +::: \ No newline at end of file diff --git a/docs/versioned_docs/version-1.0.0/enviroment.md b/docs/versioned_docs/version-1.0.0/enviroment.md new file mode 100644 index 0000000..893e3fc --- /dev/null +++ b/docs/versioned_docs/version-1.0.0/enviroment.md @@ -0,0 +1,186 @@ +--- +sidebar_position: 4 +description: Az Astro Lang környezete +--- + +# Környezet + +--- + +## Alapfunkciók +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|ugass|Kíírja a megadott értékeket.|`ugass(...)`|`ugass(6,7,szaft"test"szaft)`| +|bimba|Várakozik adott ideig (miliszekundum-ban).|`ugass(ms: number)`|`bimba(1000)`| +|csömör|Hibával befejezi a programot.|`csömör(error: string)`|`csömör(szaft"Sikertelen: Sikeresen befejezve!"szaft)`| +|tarh|Kíírja, hogy a megadott érték milyen típusú.|`tarh(object: any): string`|`tarh(82)`| +|bimbabemb|Átalakítja a megadott érétk típusát, ha lehetséges.|`bimbabemb(object: any, target: string): any`|`bimbabemb(7,szaft"string"szaft)`| +|mennyi az idő|Visszaadja a pillanatnyi UNIX időt milisec-ben.|`mennyi az idő(): number`|`mennyi az idő()`| +|joink|Bekér egy szöveget a terminálból.|`joink(): string`|`joink()`| + +--- + +## Nerd (Math) +Matematikai funkciók +:::tip + +A példák elé kell írni a kulcsszót: `nerd` + +Példa: `nerd.abs` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|abs|Visszaadja a megadott érték abszolút értékét.|`abs(n: number): number`|`abs(-2)`| +|kerek|Visszaadja a megadott érték kerekített értékét. Irányok: `fel, le, közel`|`kerek(n: number, direction: string): number`|`kerek(1.2, szaft"fel"szaft)`| +|sin|Visszaadja a megadott érték szinusz értékét.|`sin(n: number): number`|`sin(0)`| +|cos|Visszaadja a megadott érték koszinusz értékét.|`cos(n: number): number`|`cos(90)`| +|tan|Visszaadja a megadott érték tangens értékét.|`tan(n: number): number`|`tan(0)`| +|sqrt|Visszaadja a megadott érték gyökét.|`sqrt(n: number): number`|`sqrt(-2)`| +|legnagyobb|Visszaadja a megadott értékek közül a legnagyobbat.|`legnagyobb(...: number): number`|`legnagyobb(1,2,3)`| +|legkisebb|Visszaadja a megadott értékek közül a legkisebbet.|`legkisebb(...: number): number`|`legkisebb(1,2,3)`| +|pi|A pi értékét tárolja.|`pi: number`|`pi`| + +--- + +## Szaft (String) +Szöveggel lévő funkciók +:::tip + +A példák elé kell írni a kulcsszót: `szaft` + +Példa: `szaft.csemerd fel` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|csemerd fel|Visszaadja a megadott szöveget végig nagy betűkkel.|`csemerd fel(s: string): string`|`csemerd fel(szaft"TeSt"szaft)`| +|csemerd le|Visszaadja a megadott szöveget végig kis betűkkel.|`csemerd le(s: string): string`|`csemerd le(szaft"TeSt"szaft)`| +|hossz|Visszaadja a megadott szöveg hosszát.|`hossz(s: string): number`|`hossz(szaft"test"szaft)`| +|ismételd|A megadott szöveget `n` szer ismételve adja vissza.|`ismételd(s: string, n: number): string`|`ismételd(szaft"test"szaft, 3)`| +|uno reverse|A megadott szöveget fordítva adja vissza.|`uno reverse(s: string): string`|`uno reverse(szaft"test"szaft)`| +|darabos|Visszaadja a megadott szöveg egy darabját.|`darabos(s: string, start: number, end: number): string`|`darabos(szaft"test"szaft, 0, 1)`| +|keres|Megnézi, hogy a megadott szövegben megtalálható-e a másik szöveg.|`keres(s: string, find: string): boolean`|`keres(szaft"test"szaft,szaft"st"szaft)`| +|átrak|A megadott szövegben kicseréli a másik szöveget egy harmadikkal.|`átrak(s: string, from: string, to: string): string`|`átrak(szaft"test"szaft,szaft"st"szaft,szaft"bemb"szaft)`| +|számmá|A megadott szövegben az `n`-edik karakter szám megfelelőjét adja vissza.|`számmá(s: string, n: number): number`|`számmá(szaft"test"szaft,0)`| +|betűvé|A megadott szám betű megfelelőjét adja vissza.|`átrak(n: number): string`|`átrak(65)`| + +--- + +## Tábla (Table) +Táblákkal lévő funkciók +:::tip + +A példák elé kell írni a kulcsszót: `tábla` + +Példa: `tábla.hozzáad` + +::: +:::warning + +A funkciók végeredményét ajánlott beleírni a táblába, mert ez nem történik meg alapból. + +Példa: `a = tábla.hozzáad(a, 7)` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|hozzáad|Hozzáad egy értéket egy táblához.|`hozzáad(t: table, value: any): table`|`hozzáad({1,2,3}, 7)`| +|töröl|Töröl egy értéket a táblából.|`töröl(t: table, n: number): table`|`töröl({1,2,3}, 0)`| +|kulcsok|Visszaadja a tábla kulcsait egy másik táblában.|`kulcsok(t: table): table`|`kulcsok({1,2,3})`| +|hossz|Visszaadja a tábla hosszát.|`hossz(t: table): number`|`hozzáad({1,2,3})`| + +--- + +## Szenvedés (Process) +A feladattal kapcsolatos funkciók +:::tip + +A példák elé kell írni a kulcsszót: `szenvedés` + +Példa: `szenvedés.vége` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|vége|Befejezi a programot egy kilépő kóddal.|`vége(n: number)`|`vége(0)`| + +--- + +## Kábel (Net) +A nettel kapcsolatos funkciót +:::tip + +A példák elé kell írni a kulcsszót: `kábel` + +Példa: `kábel.halgass` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|halgass|Hallgat egy porton.|`halgass(host: string, port: number): halgató`|`halgass(szaft"0.0.0.0"szaft,1010)`| +|kapcsolódj|Rákapcsolódik egy célra.|`kapcsolódj(target: string): kapcsolat`|`kapcsolódj(szaft"example.com:80"szaft)`| + +:::warning + +Ezek a funkciók kérik, hogy az első értékük a szülő táblájuk legyen + +::: + +### Halgató: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|kérés|Várakozik egy kérésre, majd visszaadja azt.|`kérés(listener: halgató): kapcsolat`|`kérés(listener)`| + +### Kapcsolat: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|olvass|Beleolvas a kapcsolatba.|`olvass(stream: kapcsolat, len: number): string`|`olvass(stream, 1024)`| +|írj|Beleír a kapcsolatba.|`írj(stream: kapcsolat, data: string)`|`írj(stream, szaft"Hello from ASL!"szaft)`| +|zár|Bezárja a kapcsolatot.|`zár(stream: kapcsolat)`|`zár(stream)`| + +--- + +## Intéző (Filesystem) +Fájlokkal lévő funkciók +:::tip + +A példák elé kell írni a kulcsszót: `intéző` + +Példa: `intéző.létezik` + +::: +:::warning + +A fájlok, helyét bárhogy megadhatod, viszont a törlésnél légy óvatos! + +A fájl írása felülírja a már fájlban lévő adatokat! + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|létezik|Megnézi, hogy létezik-e az elérési út.|`létezik(path: string): boolean`|`létezik(szaft"test.asl"szaft)`| +|infó|Lekéri a metaadatokat az adott elérési útból.|`infó(path: string): table`|`infó(szaft"test.asl"szaft)`| +|mappít|Létrehozza a mappákat, hogy elérje az elérési útat.|`mappít(path: string)`|`mappít(szaft"test1/test2/"szaft)`| +|mappát töröl|Kitöröl egy mappát.|`mappát töröl(path: string)`|`mappát töröl(szaft"test1/"szaft)`| +|fájlt töröl|Kitöröl egy fájlt.|`fájlt töröl(path: string)`|`fájlt töröl(szaft"compiled.asx"szaft)`| +|olvass|Beolvas egy fájlt.|`olvass(path: string): string`|`olvass(szaft"test.asl"szaft)`| +|írj|Beleírja egy fájlba a kapott adatokat.|`írj(path: string, data: string)`|`írj(szaft"test.txt"szaft, szaft"Hello from ASL!"szaft)`| + +--- + +## Krumpli (Coroutine) +Multi-tasking funkciók +:::tip + +A példák elé kell írni a kulcsszót: `krumpli` + +Példa: `krumpli.várj` + +::: +|Név|Leírás|Használat|Példa| +|---|---|---|---| +|várj|Visszaadja a futást az előző thread-nak.|`várj()`|`várj()`| +|létrehoz|Létrehoz egy új thread-et.|`létrehoz(f: function): coroutine`|`létrehoz(lőcsve() { ugass(7) })`| +|folytat|Folytatja a thread-et.|`folytat(c: coroutine)`|`folytat(c)`| +|státusz|Visszaadja a thread státuszát.|`folytat(c: coroutine)`|`folytat(c)`| \ No newline at end of file diff --git a/docs/versioned_docs/version-1.0.0/intro.md b/docs/versioned_docs/version-1.0.0/intro.md new file mode 100644 index 0000000..90445fd --- /dev/null +++ b/docs/versioned_docs/version-1.0.0/intro.md @@ -0,0 +1,23 @@ +--- +sidebar_position: 1 +description: Az Astro Lang bemutatása +--- + +# Astro Lang +Egy magyar + GenZ programozási nyelv + +--- + +Miben jobb: +- többszavas változók +- magyar kulcsszavak +- teljes értékű dokumentáció +- Rustban írt + +--- + +Példa: +```asl title="example.asl" +gethelj a = 10 +ugass(a) +``` \ No newline at end of file diff --git a/docs/versioned_docs/version-1.0.0/langfunctions.md b/docs/versioned_docs/version-1.0.0/langfunctions.md new file mode 100644 index 0000000..72244b1 --- /dev/null +++ b/docs/versioned_docs/version-1.0.0/langfunctions.md @@ -0,0 +1,301 @@ +--- +sidebar_position: 3 +description: Az Astro Lang fukciói +--- + +# Nyelvi funkciók + +--- + +## Assignment (Változó beállítás) +Kucsszó: `gethelj` + +Használat: `gethelj változó = érték` + +Példa: +```asl title="example.asl" +gethelj test = 17 +``` + +--- + +## Var read (Változó olvasás) +Kucsszó: `-` + +Használat: `változó` + +Példa: +```asl title="example.asl" +gethelj test = 17 +ugass(test) +``` + +--- + +## Var update (Változó frissítés) +Kucsszó: `-` + +Használat: `változó = érték` + +Példa: +```asl title="example.asl" +gethelj test = 17 +ugass(test) +test = 18 +ugass(test) +``` + +--- + +## Function (Funkció) +Kucsszó: `lőcsve` + +Használat: `lőcsve változó(változók) {lefutatott kód}` + +Példa: +```asl title="example.asl" +lőcsve test(a) { + //Ez akkor fut le mikor meghívod a funkciót +} +test(8) //így tudsz meghívni egy funkciót, ebben az esetben az "a" 8 lesz +``` + +--- + +## If (Ha) +Kulcsszó: `ha geny` + +Használat: `ha geny(feltétel) {ha igaz}` + +Példa: +```asl title="example.asl" +ha geny(piszv) { + //Ez akkor fut le, ha a feltétel igaz + //Ebben az esetben mindig +} +``` + +--- + +## Else (Különben) +Kulcsszó: `ha nem geny` + +Használat: `ha nem geny {ha hamis}` + +Példa: +```asl title="example.asl" +ha geny(nem piszv) { + //Ez akkor fut le, ha a feltétel igaz + //Ebben az esetben soha +} ha nem geny { + //Ez akkor fut le, ha a feltétel hamis + //Ebben az esetben mindig +} +``` + +:::tip + +Nem kötelező egyből a ha után rakni, a kódban bárhol elfogadható és az előzőleg lefutott if-t veszi figyelembe. + +::: + +--- + +## Else if (Különben-Ha) +Kulcsszó: `ha nem geny akkor geny` + +Használat: `ha nem geny akkor geny(feltétel) {ha igaz}` + +Példa: +```asl title="example.asl" +ha geny(nem piszv) { + //Ez akkor fut le, ha a feltétel igaz + //Ebben az esetben soha +} ha nem geny akkor geny(piszv) { + //Ez akkor fut le, ha az előző if feltétele hamis és a feltétel igaz + //Ebben az esetben mindig +} +``` + +:::tip + +Nem kötelező egyből a ha után rakni, a kódban bárhol elfogadható és az előzőleg lefutott if-t veszi figyelembe. + +::: + +--- + +## While (Amíg) +Kulcsszó: `amíg geny` + +Használat: `amíg geny(feltétel) {amíg igaz}` + +Példa: +```asl title="example.asl" +amíg geny(piszv) { + //Ez addig fut le, amíg a feltétel igaz + //Ebben az esetben örökké fog futni +} +``` + +--- + +## For (Változós amíg) +Kulcsszó: `kopva` + +Használat: `kopva(beállítás;feltétel;frissítés) {amíg igaz}` + +:::info + +A beállítás első futás előtt fut le, csak 1 utasítást tartalmazhat. + +A frissítés minden futás után fut le, csak 1 utasítást tartalmazhat. + +::: + +Példa: +```asl title="example.asl" +kopva(gethelj i = 0; i < 10; i = i + 1) { + //Ez addig fut le, amíg a feltétel igaz +} +``` + +--- + +## Break (Törés) +Kulcsszó: `kraf` + +Használat: `kraf` + +Példa: +```asl title="example.asl" +kopva(gethelj i = 0; i < 10; i = i + 1) { + kraf //Ez az első futásnál be fogja fejezni az amíg-ot +} +``` + +--- + +## Continue (Folytasd) +Kulcsszó: `szard le` + +Használat: `szard le` + +Példa: +```asl title="example.asl" +kopva(gethelj i = 0; i < 10; i = i + 1) { + ugass(i) + szard le + ugass(78) //Ez soha nem fog lefutni, mert át lesz ugorva +} +``` + +--- + +## Return (Funkció visszadása) +Kulcsszó: `reti` + +Használat: `reti [változó]` + +Példa: +```asl title="example.asl" +lőcsve test(a) { + reti a +} +gethelj a = test(8) //Az "a" értéke "8" lesz, mert azt adja vissza. +``` + +--- + +## Import (Betöltés) +Kulcsszó: `hámozd, be/ba` + +Használat: `hámozd változó be/ba` + +:::tip + +Ez egyből létrehoz egy változót. +Pontos fájlnevet tudsz megadni! + +::: + +Példa: +```asl title="example.asl" +hámozd test be szaft"test.asl"szaft +``` + +--- + +## Table (Tábla) + +:::tip + +A kulcs bármilyen érték típus lehet, kivéve: funkció, tábla. + +::: + +### Létrehozás +Használat: `{érték,érték}, {[kulcs]=érték}` + +Példa: +```asl title="example.asl" +gethelj a = {1,2,3} +``` + +### Lekérés +Használat: `tábla[kulcs]` + +Példa: +```asl title="example.asl" +gethelj a = {1,2,3} +ugass(a[0]) // 1 +``` + +### Gyors lekérés +Használat: `tábla.kulcs` + +:::warning + +Csak a szöveges kulcsokkal működik, viszont több szót is támogat! + +::: + +Példa: +```asl title="example.asl" +gethelj a = {1,2,3,[szaft"test"szaft]=73} +ugass(a.test) // 73 +``` + +### Beállítás +Használat: `tábla[kulcs] = érték` + +Példa: +```asl title="example.asl" +gethelj a = {1,2,3} +ugass(a[0]) // 1 +a[0] = 12 +ugass(a[0]) // 12 +``` + +--- + +## Try/Catch (Próbáld ki) +Kulcsszó: `piszolj, csecs` + +Használat: `piszolj {amit ki kell próbálni} csecs (error) {ha hiba}` + +:::warning + +A catch rész itt nem rakható bárhova, nem úgy mint az if-nél! + +::: + +Példa: +```asl title="example.asl" +piszolj { + gethelj test = szaft"a"szaft+1 +} csecs (e) { + //Ez akkor fog lefutni, mikor hiba van + ugass(e) +} +``` \ No newline at end of file diff --git a/docs/versioned_docs/version-1.0.0/syntax.md b/docs/versioned_docs/version-1.0.0/syntax.md new file mode 100644 index 0000000..794b9b3 --- /dev/null +++ b/docs/versioned_docs/version-1.0.0/syntax.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 2 +description: Az Astro Lang synatx bemutatása +--- + +# Syntax + +--- + +## Típusok: +|Típus neve|Magyar neve|Leírása|Példa| +|---|---|---|---| +|String|Szöveg|Minden ami szöveg.|`szaft"test"szaft`| +|Number|Szám|Minden ami szám.|`2, 3.14, -5`| +|Identifier|Azonosító|A változók, dolgok neve/azonosítója, több szót is támogat. Fontos: szám nem lehet a szavak elején, mert az már számnak számít!|`teszt, több szót is támogat, ez is jo72`| +|Operator|Művelet|Minden ami művelet.|`+, -, *`| +|Keyword|Kulcsszó|Azok az azonosítók amelyek valamilyen funkciót látnak el a programnyelben.|`gethelj, lőcsve, ha geny`| +|Separator|Elválasztó|Olyan karakterek, melyek elválaszják a többi típust egymástól.|`=, (, {`| + +Példa: +```asl +gethelj a = 15 + 2 +^ ^ ^ ^ ^ ^ Number +| | | | | Operator +| | | | Number +| | | Separator +| | Identifier +| Keyword +``` + +## Egyéb: +### Komment: +Ezek nem befolyásolják a kód futását, csak leírást adnak arról, hogy mi mit csinál. +- Egysoros kommentet így tudsz létrehozni: `//komment` +- Többsoros kommentet pedig így: `/*komment*/` +### Logikai érték: +:::info + +A nyelv ezeket kulcsszóként kezeli! + +::: +Igaz (piszv) vagy hamis (nem piszv) +### Semmi: +:::info + +A nyelv ezt is kulcsszóként kezeli! + +::: +Null (nincs hám) \ No newline at end of file diff --git a/docs/versioned_sidebars/version-1.0.0-sidebars.json b/docs/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000..2782dc0 --- /dev/null +++ b/docs/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,8 @@ +{ + "sidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/docs/versions.json b/docs/versions.json index 3145067..25a2ff2 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,3 +1,4 @@ [ + "1.0.0", "0.2.0" ] diff --git a/extension/.gitignore b/extension/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/extension/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/extension/LICENSE b/extension/LICENSE new file mode 100644 index 0000000..e66f844 --- /dev/null +++ b/extension/LICENSE @@ -0,0 +1,7 @@ +Copyright 2025 Afonya + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/extension/README.md b/extension/README.md new file mode 100644 index 0000000..7ddfcf8 --- /dev/null +++ b/extension/README.md @@ -0,0 +1,26 @@ +# Astro Lang Extension +Egy magyar + GenZ programozási nyelv + +--- + +## Miben jobb: +- többszavas változók +- magyar kulcsszavak +- teljes értékű dokumentáció +- Rustban írt + +--- + +## Példa: +```asl +gethelj a = 10 +ugass(a) +``` + +--- + +Weboldal és dokumentáció: [itt](https://astrolang.afonyanet.hu) + +Kiadások: [itt](https://git.afonyanet.hu/afonya/AstroLang/releases) + +Licensz: MIT \ No newline at end of file diff --git a/extension/asl.png b/extension/asl.png new file mode 100644 index 0000000..cbed5a6 Binary files /dev/null and b/extension/asl.png differ diff --git a/extension/astrolang-extension-1.0.2.vsix b/extension/astrolang-extension-1.0.2.vsix new file mode 100644 index 0000000..0651d87 Binary files /dev/null and b/extension/astrolang-extension-1.0.2.vsix differ diff --git a/extension/astrolang.tmLanguage.json b/extension/astrolang.tmLanguage.json new file mode 100644 index 0000000..4036bb6 --- /dev/null +++ b/extension/astrolang.tmLanguage.json @@ -0,0 +1,35 @@ +{ + "scopeName": "source.astrolang", + "patterns": [ + { + "name": "comment.line.astrolang", + "match": "//.*$" + }, + { + "name": "comment.block.astrolang", + "begin": "/\\*", + "end": "\\*/" + }, + { + "name": "keyword.control.astrolang", + "match": "\\b(kraf|piszolj|ha nem geny akkor geny|ha nem geny|nem piszv|kopva|gethelj|ha geny|lőcsve|csecs|reti|piszv|amíg geny|nincs hám|szard le|hámozd|be|ba)\\b" + }, + { + "name": "keyword.operator.astrolang", + "match": "(\\+|-|\\*|\\/|%|=|==|!=|<=|>=|<|>|&&|\\|\\||!)" + }, + { + "name": "string.quoted.double.astrolang", + "begin": "(?<=szaft)\"", + "end": "\"(?=szaft)" + }, + { + "name": "variable.astrolang", + "match": "\\b([a-zA-Zöüóőúéáűí_][a-zA-Zöüóőúéáűí0-9_]*)\\b" + }, + { + "name": "constant.numeric.astrolang", + "match": "([0-9]+)" + } + ] +} \ No newline at end of file diff --git a/extension/index.js b/extension/index.js new file mode 100644 index 0000000..c07fe37 --- /dev/null +++ b/extension/index.js @@ -0,0 +1,95 @@ +import * as vscode from 'vscode' + +vscode.languages.registerCompletionItemProvider('astrolang', { + provideCompletionItems() { + const words = [ + "kraf", + "piszolj", + "ha nem geny akkor geny", + "ha nem geny", + "nem piszv", + "kopva", + "gethelj", + "ha geny", + "lőcsve", + "csecs", + "reti", + "piszv", + "amíg geny", + "nincs hám", + "szard le", + "hámozd", + "be", + "ba", + "szaft" + ] + const env = [ + "ugass", + "bimba", + "csömör", + "tarh", + "bimbabemb", + "nerd", + "tábla", + "kábel", + "szenvedés", + "mennyi az idő", + "joink", + "intéző", + "krumpli", + + "abs", + "kerek", + "sin", + "cos", + "tan", + "sqrt", + "legnagyobb", + "legkisebb", + "pi", + + "csemerd fel", + "csemerd le", + "hossz", + "ismételd", + "uno reverse", + "darabos", + "keres", + "átrak", + "számmá", + "betűvé", + + "hozzáad", + "töröl", + "kulcsok", + + "vége", + + "halgass", + "kapcsolódj", + "kérés", + "írj", + "olvass", + "zár", + + "létezik", + "infó", + "mappít", + "mappát töröl", + "fájlt töröl", + + "várj", + "létrehoz", + "folytat", + "státusz" + ] + let out = [] + for (let i = 0; i < words.length; i++) { + out.push(new vscode.CompletionItem(words[i], vscode.CompletionItemKind.Keyword)) + } + for (let i = 0; i < env.length; i++) { + out.push(new vscode.CompletionItem(env[i], vscode.CompletionItemKind.Variable)) + } + return out + } +}) \ No newline at end of file diff --git a/extension/language-configuration.json b/extension/language-configuration.json new file mode 100644 index 0000000..c973f64 --- /dev/null +++ b/extension/language-configuration.json @@ -0,0 +1,24 @@ +{ + "comments": { + "lineComment": "//", + "blockComment": ["/*", "*/"] + }, + "brackets": [ + ["{", "}"], + ["[", "]"], + ["(", ")"] + ], + "autoClosingPairs": [ + { "open": "{", "close": "}" }, + { "open": "[", "close": "]" }, + { "open": "(", "close": ")" }, + { "open": "/*", "close": " */", "notIn": ["string"] }, + { "open": "szaft\"", "close": "\"szaft", "notIn": ["string"] } + ], + "surroundingPairs": [ + ["{", "}"], + ["[", "]"], + ["(", ")"], + ["szaft\"", "\"szaft"] + ] +} diff --git a/extension/package.json b/extension/package.json new file mode 100644 index 0000000..36ff78e --- /dev/null +++ b/extension/package.json @@ -0,0 +1,51 @@ +{ + "name": "astrolang-extension", + "displayName": "Astro Lang", + "icon": "asl.png", + "version": "1.0.2", + "description": "The extension for Astro Lang", + "license": "MIT", + "author": "Afonya", + "publisher": "afonya", + "type": "module", + "main": "index.js", + "repository": { + "type": "git", + "url": "https://git.afonyanet.hu/afonya/AstroLang" + }, + "engines": { + "vscode": "^1.22.0" + }, + "activationEvents": [ + "onStartupFinished" + ], + "contributes": { + "languages": [ + { + "id": "astrolang", + "aliases": [ + "Astro Lang", + "AstroLang", + "ASL" + ], + "extensions": [ + ".asl" + ], + "configuration": "./language-configuration.json" + } + ], + "grammars": [ + { + "language": "astrolang", + "scopeName": "source.astrolang", + "path": "./astrolang.tmLanguage.json" + } + ], + "snippets": [ + { + "language": "astrolang", + "path": "./snippets.json" + } + ] + } +} diff --git a/extension/snippets.json b/extension/snippets.json new file mode 100644 index 0000000..b949adb --- /dev/null +++ b/extension/snippets.json @@ -0,0 +1,84 @@ +{ + "if": { + "prefix": "ha geny", + "body": [ + "ha geny(${1:feltétel}) {", + "$0", + "}" + ], + "description": "Egy if" + }, + "else": { + "prefix": "ha nem geny", + "body": [ + "ha nem geny {", + "$0", + "}" + ], + "description": "Egy else" + }, + "elseif": { + "prefix": "ha nem geny akkor geny", + "body": [ + "ha nem geny akkor geny(${1:feltétel}) {", + "$0", + "}" + ], + "description": "Egy else if" + }, + "while": { + "prefix": "amíg geny", + "body": [ + "amíg geny(${1:feltétel}) {", + "$0", + "}" + ], + "description": "Egy while ciklus" + }, + "for": { + "prefix": "kraf", + "body": [ + "kraf(gethelj ${1:i} = ${2:0}; ${3:feltétel}; ${1:i}=${1:i}+1) {", + "$0", + "}" + ], + "description": "Egy for ciklus" + }, + "var create": { + "prefix": "gethelj", + "body": [ + "gethelj ${1:változó} = ${2:érték}" + ], + "description": "Egy változó létrehozása" + }, + "function create": { + "prefix": "lőcsve", + "body": [ + "lőcsve ${1:függvény név}(${2:paraméterek}) {", + "$0", + "}" + ], + "description": "Egy függvény létrehozása" + }, + "import": { + "prefix": "hámozd", + "body": [ + "hámozd ${1:modul név} ${2|be,ba|} szaft\"${3:elérési út}\"szaft" + ], + "description": "Egy modul importálása" + }, + "string": { + "prefix": "szaft", + "body": [ + "szaft\"${1:szöveg}\"szaft" + ], + "description": "Egy szöveg létrehozása" + }, + "print": { + "prefix": "ugass", + "body": [ + "ugass(${1:üzenet})" + ], + "description": "Egy üzenet kiírása a konzolra" + } +} \ No newline at end of file diff --git a/src/compiler.rs b/src/compiler.rs index 5431925..49110e5 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, fs, process, vec}; use crate::{errors::{create_error, print_error, ErrorSubType, ErrorType}, lexer::lex, parser::{parse, ASTPart}, Context}; -const ASXVERSION: [u8; 3] = [0,2,0]; +const ASXVERSION: [u8; 3] = [1,0,0]; #[derive(Debug, Clone)] pub struct Operation { @@ -31,7 +31,9 @@ struct Compiled { operations: Vec, variables: Vec, strings: HashMap, - functions: HashMap + functions: HashMap, + try_catch: Option, + ctx: Context } #[derive(Debug, Clone)] @@ -103,6 +105,7 @@ fn allocate_register(registers: &Vec) -> AllocateResult { let mut oldest_register: u8 = 0; let mut oldest_temp: usize = 0; let mut oldest_temp_register: u8 = 0; + let mut tempc = 0; for register in registers { if ((register.last_used < oldest) || (oldest == 0)) && register.id != 0 { oldest = register.last_used; @@ -112,13 +115,16 @@ fn allocate_register(registers: &Vec) -> AllocateResult { oldest_temp = register.last_used; oldest_temp_register = register.id; } + if register.id != 0 && register.variable == 0 { + tempc += 1; + } } - /*if oldest_temp_register != 0 { + if oldest_temp_register != 0 && tempc > 3 { return AllocateResult { register: oldest_temp_register, unbind_before: false, }; - }*/ + } return AllocateResult { register: oldest_register, unbind_before: true, @@ -234,7 +240,7 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va variables: variables.clone(), previous: Some(Box::new(traceback.clone())), }; - functions.insert(func_id, compile_function(func.body, Some(func.args), registers, next_var_id, ctx, &self_tb)); + functions.insert(func_id, compile_function(func.body, Some(func.args), registers, next_var_id, ctx, &self_tb, None)); *next_function_id += 1; let reg = allocate_register(registers); if reg.unbind_before { @@ -245,7 +251,6 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va return reg.register; }, ASTPart::Call(call) => { - let func = do_ast_op(*call.function, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx, traceback); for arg in call.args { let arg_reg = do_ast_op(arg, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx, traceback); ops.push(Operation { opcode: 28, arg1: Some(arg_reg), arg2: None, arg3: None, pos: call.pos as u32 }); @@ -254,6 +259,7 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va set_register(registers, RegisterState { id: arg_reg, used: false, variable: 0, last_used: 0 }); } } + let func = do_ast_op(*call.function, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx, traceback); let ret_reg = allocate_register(registers); if ret_reg.unbind_before { ops.push(Operation { opcode: 8, arg1: Some(ret_reg.register), arg2: None, arg3: None, pos: call.pos as u32 }); @@ -304,8 +310,8 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::Else(else_part) => { if get_variable_by_name(variables, "__LASTIF", ops.len(), traceback).is_none() { - let err = create_error(&format!("Else used without an if statement before it"), else_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf); - print_error(&err, &ctx); + let err = create_error(&format!("Else used without an if statement before it"), else_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf, ctx); + print_error(&err); process::exit(1); } let reg = get_register_by_variable(registers, get_variable_by_name(variables, "__LASTIF", ops.len(), traceback).expect("__LASTIF should exist").clone()); @@ -352,8 +358,8 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::ElseIf(elseif_part) => { if get_variable_by_name(variables, "__LASTIF", ops.len(), traceback).is_none() { - let err = create_error(&format!("Else if used without an if statement before it"), elseif_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf); - print_error(&err, &ctx); + let err = create_error(&format!("Else if used without an if statement before it"), elseif_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf, ctx); + print_error(&err); process::exit(1); } let reg = get_register_by_variable(registers, get_variable_by_name(variables, "__LASTIF", ops.len(), traceback).expect("__LASTIF should exist").clone()); @@ -466,13 +472,13 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va } }, ASTPart::Break(brk) => { - let err = create_error(&format!("Unexpected break outside of loop"), brk.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected break outside of loop"), brk.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop, ctx); + print_error(&err); process::exit(1); }, ASTPart::Continue(cont) => { - let err = create_error(&format!("Unexpected continue outside of loop"), cont.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected continue outside of loop"), cont.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop, ctx); + print_error(&err); process::exit(1); }, ASTPart::For(for_part) => { @@ -569,8 +575,8 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va return reg.register; }, _ => { - let err = create_error(&format!("Unknown operator `{}`", op.operator), op.pos, ErrorType::SyntaxError, ErrorSubType::UnknownOperation); - print_error(&err, &ctx); + let err = create_error(&format!("Unknown operator `{}`", op.operator), op.pos, ErrorType::SyntaxError, ErrorSubType::UnknownOperation, ctx); + print_error(&err); process::exit(1); }, }; @@ -580,8 +586,8 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::VarUpdate(upd) => { if get_variable_by_name(variables, &upd.variable, ops.len(), traceback).is_none() { - let err = create_error(&format!("Variable `{}` does not exist", upd.variable), upd.pos, ErrorType::SemanticError, ErrorSubType::VariableNotFound); - print_error(&err, &ctx); + let err = create_error(&format!("Variable `{}` does not exist", upd.variable), upd.pos, ErrorType::SemanticError, ErrorSubType::VariableNotFound, ctx); + print_error(&err); process::exit(1); } let value_reg = do_ast_op(*upd.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx, traceback); @@ -596,8 +602,8 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::Assigment(asign) => { if get_variable_by_name(variables, &asign.variable, ops.len(), traceback).is_some() { - let err = create_error(&format!("Variable `{}` already exists", asign.variable), asign.pos, ErrorType::SemanticError, ErrorSubType::VariableAlreadyExists); - print_error(&err, &ctx); + let err = create_error(&format!("Variable `{}` already exists", asign.variable), asign.pos, ErrorType::SemanticError, ErrorSubType::VariableAlreadyExists, ctx); + print_error(&err); process::exit(1); } let reg = do_ast_op(*asign.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx, traceback); @@ -654,7 +660,7 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }; let lexed = lex(data, &imp_ctx); let ast = parse(lexed, &imp_ctx); - let compiled = compile_function(ast, None, registers, next_var_id, &imp_ctx, &self_tb); + let compiled = compile_function(ast, None, registers, next_var_id, &imp_ctx, &self_tb, None); functions.insert(*next_function_id, compiled); *next_function_id += 1; let reg = allocate_register(registers); @@ -667,18 +673,43 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va return reg.register; }, Err(e) => { - let err = create_error(&format!("Failed to read file `{}`: {}", impr.path, e), impr.pos, ErrorType::IOError, ErrorSubType::FileError); - print_error(&err, &ctx); + let err = create_error(&format!("Failed to read file `{}`: {}", impr.path, e), impr.pos, ErrorType::IOError, ErrorSubType::FileError, ctx); + print_error(&err); process::exit(1); } } }, + ASTPart::TryCatch(tc) => { + let self_tb = PrevFunc { + variables: variables.clone(), + previous: Some(Box::new(traceback.clone())), + }; + let catch_f = compile_function(tc.catch_block.body, Some(tc.catch_block.args), registers, next_var_id, ctx, &self_tb, None); + let mut try_f = compile_function(tc.try_block.body, None, registers, next_var_id, ctx, &self_tb, Some(0)); + let mut nextt_f = 1; + for (fid, _) in &try_f.functions { + if fid >= &nextt_f { + nextt_f = fid+1; + } + } + try_f.functions.insert(nextt_f, catch_f); + try_f.try_catch = Some(nextt_f); + functions.insert(*next_function_id, try_f); + *next_function_id += 1; + let reg = allocate_register(registers); + if reg.unbind_before { + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: tc.pos as u32 }); + } + ops.push(Operation { opcode: 5, arg1: Some(reg.register), arg2: Some((*next_function_id-1) as f64), arg3: None, pos: tc.pos as u32 }); + ops.push(Operation { opcode: 27, arg1: Some(reg.register), arg2: None, arg3: None, pos: tc.pos as u32 }); + set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); + }, _ => {} } return 0; } -fn compile_function(ast: Vec, args: Option>, registers: &mut Vec, next_var_id: &mut u32, ctx: &Context, traceback: &PrevFunc) -> Compiled { +fn compile_function(ast: Vec, args: Option>, registers: &mut Vec, next_var_id: &mut u32, ctx: &Context, traceback: &PrevFunc, try_catch: Option) -> Compiled { let mut ops: Vec = vec![]; let mut variables: Vec = vec![]; @@ -696,8 +727,8 @@ fn compile_function(ast: Vec, args: Option>, registers: &mu Some(arg_list) => { for arg in arg_list { if get_variable_by_name(&variables, &arg, 0, &empty_tb).is_some() { - let err = create_error(&format!("Argument `{}` already exists", arg), 0, ErrorType::SemanticError, ErrorSubType::ArgumentDuplication); - print_error(&err, &ctx); + let err = create_error(&format!("Argument `{}` already exists", arg), 0, ErrorType::SemanticError, ErrorSubType::ArgumentDuplication, ctx); + print_error(&err); process::exit(1); } variables.push( Variable { name: arg, id: *next_var_id, start: 0, end: 0, no_end: true }); @@ -723,6 +754,8 @@ fn compile_function(ast: Vec, args: Option>, registers: &mu variables, strings, functions, + try_catch, + ctx: ctx.clone(), }; } @@ -794,13 +827,21 @@ fn compile_body(compiled: Compiled, fpos: &mut usize, ctx: &Context) -> (Vec *fpos += 1; append_be_num(&mut output, 3, *funcs as usize); append_be_num(&mut output, 4, *fpos); - let (compiled, mut context) = compile_body(compiled.functions[funcs].clone(), fpos, ctx); + let (compiled, mut context) = compile_body(compiled.functions[funcs].clone(), fpos, &compiled.functions[funcs].ctx); for c in &mut context { c.c_funcid = *fpos } contexts.extend_from_slice(&context); additional.push(compiled); } + match compiled.try_catch { + Some(tc) => { + append_be_num(&mut output, 4, tc as usize); + }, + None => { + append_be_num(&mut output, 4, 0); + } + } //function body append_be_num(&mut output, 4, compiled.operations.len()); for ops in compiled.operations { @@ -847,7 +888,7 @@ pub fn compile(ast: Vec, ctx: &Context) -> (Vec, Vec) { variables: vec![], previous: None, }; - let compiled = compile_function(ast, None, &mut registers, &mut next_var_id, ctx, &empty_tb); + let compiled = compile_function(ast, None, &mut registers, &mut next_var_id, ctx, &empty_tb, None); let mut output: Vec = vec![]; //doctype specifier diff --git a/src/decompiler.rs b/src/decompiler.rs index ae39057..924feaf 100644 --- a/src/decompiler.rs +++ b/src/decompiler.rs @@ -1,13 +1,14 @@ use std::collections::HashMap; -const ASXVERSION: [u8; 3] = [0,2,0]; +const ASXVERSION: [u8; 3] = [1,0,0]; #[derive(Debug, Clone)] pub struct DecompiledFunction { pub body: Vec, pub variables: Vec, pub strings: HashMap, - pub functions: HashMap + pub functions: HashMap, + pub try_catch: u32, } #[derive(Debug, Clone)] pub struct DecompiledOperation { @@ -145,6 +146,8 @@ fn load_func(data: Vec, offset: &mut usize) -> DecompiledFunction { *offset += 4; functions.insert(func_id, func_pos); } + let try_catch = read_be_num(&data[*offset..*offset + 4]); + *offset += 4; let mut body: Vec = Vec::new(); let instr_len: usize = read_be_num(&data[*offset..*offset + 4]); *offset += 4; @@ -170,6 +173,7 @@ fn load_func(data: Vec, offset: &mut usize) -> DecompiledFunction { variables: variables, strings: strings, functions: functions, + try_catch: try_catch as u32, }; } diff --git a/src/enviroment.rs b/src/enviroment.rs index 08c9a4f..4a99d64 100644 --- a/src/enviroment.rs +++ b/src/enviroment.rs @@ -1,6 +1,6 @@ -use std::{collections::HashMap, io::{BufReader, Read, Write}, net::{self, TcpListener, TcpStream}, process, thread::sleep, time::Duration, vec}; +use std::{collections::HashMap, fs, io::{stdin, BufReader, Read, Write}, net::{self, TcpListener, TcpStream}, process, thread::sleep, time::{Duration, UNIX_EPOCH}, vec}; -use crate::{decompiler::DecompiledOperation, errors::{create_error, print_error, ErrorSubType, ErrorType}, virtualmachine::{Machine, TableValue, VMMemory, VMMemoryBoolean, VMMemoryNativeFunction, VMMemoryNull, VMMemoryNumber, VMMemoryString, VMMemoryTable}}; +use crate::{decompiler::{DecompiledFunction, DecompiledOperation}, errors::{convert_subtypes_to_string, convert_types_to_string, create_error, print_error, ErrorSubType, ErrorType}, virtualmachine::{Machine, TableValue, VMMemory, VMMemoryBoolean, VMMemoryNativeFunction, VMMemoryNull, VMMemoryNumber, VMMemoryString, VMMemoryTable, VMState}, Context}; fn get_string_from_vmmem(mem: &VMMemory) -> String { let mut out = String::new(); @@ -58,10 +58,10 @@ fn arg_expect(args: &Vec, pos: usize, expected_type: &str, machine: &M } } fn error(msg: String, machine: &Machine, op: &DecompiledOperation) { - let err = create_error(&msg, op.pos, ErrorType::MachineError, ErrorSubType::RuntimeError); let curr = machine.call_stack.len()-1; let func = machine.call_stack[curr].func; - print_error(&err, &machine.ctx[func]); + let err = create_error(&msg, op.pos, ErrorType::MachineError, ErrorSubType::RuntimeError, &machine.ctx[func]); + print_error(&err); process::exit(1); } fn set_mem_tbl_val(tbl: &mut VMMemoryTable, key: VMMemory, value: VMMemory) { @@ -204,6 +204,27 @@ fn bimbabemb(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + let now = match UNIX_EPOCH.elapsed() { + Ok(duration) => duration.as_millis() as f64, + Err(e) => { + error(format!("Failed to get elapsed time: {}", e), machine, op); + 0.0 + } + }; + return VMMemory::Number(VMMemoryNumber { value: now, variable_id: 0 }); +} +fn joink(machine: &mut Machine, op: &DecompiledOperation, _args: Vec) -> VMMemory { + let mut str = String::new(); + match stdin().read_line(&mut str) { + Err(e) => { + error(format!("Failed to read from stdin: {}", e), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + }, + _ => {} + }; + return VMMemory::String(VMMemoryString { value: str, variable_id: 0 }); +} fn nerd_abs(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "number", machine, op); @@ -415,12 +436,12 @@ fn kabel_irj(machine: &mut Machine, op: &DecompiledOperation, args: Vec s.value.clone(), _ => String::new() }; - match listener.write_all(write.as_bytes()) { + match stream.write_all(write.as_bytes()) { Ok(_) => {}, Err(e) => { error(format!("Failed to write to stream: {}", e), machine, op); @@ -519,6 +540,40 @@ fn kabel_keres(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let stream = match TcpStream::connect(&str) { + Ok(s) => s, + Err(err) => { + error(format!("Failed to connect to {}: {}", str, err), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + machine.storage.push(Box::new(stream)); + let ret_table: Vec = vec![ + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("olvass"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_olvass, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("írj"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_irj, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("zár"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_zar, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("id"), variable_id: 0 }), + value: VMMemory::Number(VMMemoryNumber { value: (machine.storage.len()-1) as f64, variable_id: 0 }), + } + ]; + return VMMemory::Table(VMMemoryTable { values: ret_table, variable_id: 0 }); +} fn kabel_halgass(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "string", machine, op); arg_expect(&args, 1, "number", machine, op); @@ -739,6 +794,35 @@ fn tabla_kulcsok(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "table", machine, op); + let tbl = match &args[0] { + VMMemory::Table(tbl) => tbl.clone(), + _ => { + error(String::from("Expected a table"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let mut vals = VMMemoryTable { + values: vec![], + variable_id: 0, + }; + for kv in &tbl.values { + vals.values.push(TableValue { key: VMMemory::Number(VMMemoryNumber { value: vals.values.len() as f64, variable_id: 0 }), value: kv.value.clone() }); + } + return VMMemory::Table(vals); +} +fn tabla_hossz(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "table", machine, op); + let tbl = match &args[0] { + VMMemory::Table(tbl) => tbl.clone(), + _ => { + error(String::from("Expected a table"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + return VMMemory::Number(VMMemoryNumber { value: tbl.values.len() as f64, variable_id: 0 }); +} fn szenvedes_vege(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { arg_expect(&args, 0, "number", machine, op); @@ -752,6 +836,310 @@ fn szenvedes_vege(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let res = match fs::exists(str) { + Ok(exists) => exists, + Err(e) => { + error(format!("Failed to check if file exists: {}", e), machine, op); + false + } + }; + return VMMemory::Boolean(VMMemoryBoolean { value: res, variable_id: 0 }); +} +fn intezo_info(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let res = match fs::metadata(str) { + Ok(exists) => exists, + Err(e) => { + error(format!("Failed to get file metadata: {}", e), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let modf = match res.modified() { + Ok(time) => time.duration_since(UNIX_EPOCH).unwrap().as_millis() as f64, + Err(e) => { + error(format!("Failed to get file modification time: {}", e), machine, op); + 0.0 + } + }; + let creatf = match res.created() { + Ok(time) => time.duration_since(UNIX_EPOCH).unwrap().as_millis() as f64, + Err(e) => { + error(format!("Failed to get file modification time: {}", e), machine, op); + 0.0 + } + }; + let mut to_tbl: HashMap = HashMap::new(); + to_tbl.insert(String::from("mappa-e"), VMMemory::Boolean(VMMemoryBoolean { value: res.is_dir(), variable_id: 0 })); + to_tbl.insert(String::from("fájl-e"), VMMemory::Boolean(VMMemoryBoolean { value: res.is_file(), variable_id: 0 })); + to_tbl.insert(String::from("szerkesztve"), VMMemory::Number(VMMemoryNumber { value: modf, variable_id: 0 })); + to_tbl.insert(String::from("létrehozva"), VMMemory::Number(VMMemoryNumber { value: creatf, variable_id: 0 })); + to_tbl.insert(String::from("hossz"), VMMemory::Number(VMMemoryNumber { value: res.len() as f64, variable_id: 0 })); + let mut res_tbl = VMMemoryTable { + values: vec![], + variable_id: 0, + }; + for (k, v) in to_tbl { + set_mem_tbl_val(&mut res_tbl, VMMemory::String(VMMemoryString { value: k, variable_id: 0 }), v); + } + return VMMemory::Table(res_tbl); +} +fn intezo_mappit(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + match fs::create_dir_all(str) { + Err(e) => { + error(format!("Failed to create directory: {}", e), machine, op); + }, + _ => {} + } + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} +fn intezo_mappattorol(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let res = match fs::exists(&str) { + Ok(exists) => exists, + Err(_) => { + error(format!("Folder does not exist"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + if !res { + error(format!("Folder does not exist"), machine, op); + } + match fs::remove_dir(&str) { + Err(e) => { + error(format!("Failed to remove directory: {}", e), machine, op); + }, + _ => {} + }; + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} +fn intezo_fajlttorol(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let res = match fs::exists(&str) { + Ok(exists) => exists, + Err(_) => { + error(format!("File does not exist"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + if !res { + error(format!("File does not exist"), machine, op); + } + match fs::remove_file(&str) { + Err(e) => { + error(format!("Failed to remove file: {}", e), machine, op); + }, + _ => {} + }; + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} +fn intezo_olvass(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let res = match fs::exists(&str) { + Ok(exists) => exists, + Err(_) => { + error(format!("File does not exist"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + if !res { + error(format!("File does not exist"), machine, op); + } + let data = match fs::read_to_string(&str) { + Ok(data) => data, + Err(e) => { + error(format!("Failed to read file: {}", e), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + return VMMemory::String(VMMemoryString { value: data, variable_id: 0 }); +} +fn intezo_irj(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "string", machine, op); + arg_expect(&args, 1, "string", machine, op); + let str = match &args[0] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + let str2 = match &args[1] { + VMMemory::String(s) => s.value.clone(), + _ => String::new() + }; + match fs::write(&str, str2) { + Err(e) => { + error(format!("Failed to write file: {}", e), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + }, + _ => {} + }; + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} + +fn krumpli_varj(machine: &mut Machine, _op: &DecompiledOperation, _args: Vec) -> VMMemory { + machine.state = VMState::Paused; + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} +fn add_func(n_funcs: &mut Vec, n_ctx: &mut Vec, machine: &mut Machine, func: usize, pos: &mut usize) { + let mut exe_func = machine.functions[func].clone(); + let func_clone = machine.functions.clone(); + n_ctx.push(machine.ctx[func].clone()); + let start = n_funcs.len(); + for (fid, fpos) in &func_clone[func].functions { + *pos += 1; + add_func(n_funcs, n_ctx, machine, *fpos as usize, pos); + exe_func.functions.insert(*fid, *pos as u32); + } + n_funcs.insert(start, exe_func); +} +fn krumpli_letrehoz(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "function", machine, op); + let func = match &args[0] { + VMMemory::Function(func) => func.clone(), + _ => { + error(String::from("Expected a function"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let mut n_funcs: Vec = vec![]; + let mut n_ctx: Vec = vec![]; + add_func(&mut n_funcs, &mut n_ctx, machine, func.id, &mut 0); + let mut vm = Machine::new(n_ctx); + vm.load_functions(n_funcs); + let cor_id = machine.storage.len(); + machine.storage.push(Box::new(vm)); + return VMMemory::Number(VMMemoryNumber { value: cor_id as f64, variable_id: 0 }); +} +fn krumpli_folytat(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value as usize, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let vm = machine.storage.get_mut(num); + if vm.is_none() { + error(String::from("Coroutine not found"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + let boxed_vm = vm.unwrap(); + let vm = boxed_vm.downcast_mut::(); + if vm.is_none() { + error(String::from("Coroutine is not a VM"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + let vm = vm.unwrap(); + match vm.state { + VMState::Paused => { + vm.memory = machine.memory.clone(); + vm.registers = machine.registers.clone(); + vm.resume(); + machine.memory = vm.memory.clone(); + machine.registers = vm.registers.clone(); + }, + _ => { + error(String::from("Coroutine is not paused"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + } + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); +} +fn krumpli_status(machine: &mut Machine, op: &DecompiledOperation, args: Vec) -> VMMemory { + arg_expect(&args, 0, "number", machine, op); + let num = match &args[0] { + VMMemory::Number(n) => n.value as usize, + _ => { + error(String::from("Expected a number"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + }; + let vm = machine.storage.get_mut(num); + if vm.is_none() { + error(String::from("Coroutine not found"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + let boxed_vm = vm.unwrap(); + let vm = boxed_vm.downcast_ref::(); + if vm.is_none() { + error(String::from("Coroutine is not a VM"), machine, op); + return VMMemory::Null(VMMemoryNull { variable_id: 0 }); + } + let vm = vm.unwrap(); + + let mut to_tbl: HashMap = HashMap::new(); + let stat = match vm.state { + VMState::Running => String::from("running"), + VMState::Paused => String::from("paused"), + VMState::Finished => String::from("finished"), + VMState::Error(_) => String::from("error"), + }; + let err = match &vm.state { + VMState::Error(e) => Some(e.clone()), + _ => None + }; + if let Some(e) = err { + let err_tbl: Vec = vec![ + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("message"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: e.message, variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("position"), variable_id: 0 }), + value: VMMemory::Number(VMMemoryNumber { value: e.position as f64, variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("type"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: convert_types_to_string(&e.typ), variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("subtype"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: convert_subtypes_to_string(&e.subtype), variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("code"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: e.code, variable_id: 0 }) + }, + ]; + to_tbl.insert(String::from("error"), VMMemory::Table(VMMemoryTable { values: err_tbl, variable_id: 0 })); + } + to_tbl.insert(String::from("status"), VMMemory::String(VMMemoryString { value: stat, variable_id: 0 })); + let mut res_tbl = VMMemoryTable { + values: vec![], + variable_id: 0, + }; + for (k, v) in to_tbl { + set_mem_tbl_val(&mut res_tbl, VMMemory::String(VMMemoryString { value: k, variable_id: 0 }), v); + } + return VMMemory::Table(res_tbl); +} + pub fn generate() -> HashMap { let mut mem: HashMap = HashMap::new(); @@ -760,6 +1148,8 @@ pub fn generate() -> HashMap { mem.insert(String::from("csömör"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: csomor, variable_id: 0 })); mem.insert(String::from("tarh"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: tarh, variable_id: 0 })); mem.insert(String::from("bimbabemb"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: bimbabemb, variable_id: 0 })); + mem.insert(String::from("mennyi az idő"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: mennyiazido, variable_id: 0 })); + mem.insert(String::from("joink"), VMMemory::NativeFunction(VMMemoryNativeFunction { func: joink, variable_id: 0 })); let nerd: Vec = vec![ TableValue { @@ -805,6 +1195,10 @@ pub fn generate() -> HashMap { TableValue { key: VMMemory::String(VMMemoryString { value: String::from("halgass"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_halgass, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("kapcsolódj"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: kabel_kapcsolodj, variable_id: 0 }), } ]; mem.insert(String::from("kábel"), VMMemory::Table(VMMemoryTable { values: kabel, variable_id: 0 })); @@ -865,6 +1259,14 @@ pub fn generate() -> HashMap { TableValue { key: VMMemory::String(VMMemoryString { value: String::from("kulcsok"), variable_id: 0 }), value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: tabla_kulcsok, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("értékek"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: tabla_ertekek, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("hossz"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: tabla_hossz, variable_id: 0 }), } ]; mem.insert(String::from("tábla"), VMMemory::Table(VMMemoryTable { values: table, variable_id: 0 })); @@ -877,5 +1279,57 @@ pub fn generate() -> HashMap { ]; mem.insert(String::from("szenvedés"), VMMemory::Table(VMMemoryTable { values: szenvedes, variable_id: 0 })); + let intezo: Vec = vec![ + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("létezik"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_letezik, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("infó"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_info, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("mappít"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_mappit, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("mappát töröl"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_mappattorol, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("fájlt töröl"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_fajlttorol, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("olvass"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_olvass, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("írj"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: intezo_irj, variable_id: 0 }), + }, + ]; + mem.insert(String::from("intéző"), VMMemory::Table(VMMemoryTable { values: intezo, variable_id: 0 })); + + let krumpli: Vec = vec![ + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("várj"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: krumpli_varj, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("létrehoz"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: krumpli_letrehoz, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("folytat"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: krumpli_folytat, variable_id: 0 }), + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("státusz"), variable_id: 0 }), + value: VMMemory::NativeFunction(VMMemoryNativeFunction { func: krumpli_status, variable_id: 0 }), + }, + ]; + mem.insert(String::from("krumpli"), VMMemory::Table(VMMemoryTable { values: krumpli, variable_id: 0 })); + return mem; } \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs index ad9a024..30b51d6 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,5 +1,6 @@ use crate::Context; +#[derive(Debug, Clone)] pub enum ErrorType { SyntaxError, SemanticError, @@ -9,6 +10,7 @@ pub enum ErrorType { IOError, } +#[derive(Debug, Clone)] pub enum ErrorSubType { //Syntax errors UnexpectedEnd, @@ -25,6 +27,7 @@ pub enum ErrorSubType { VariableAlreadyExists, ArgumentDuplication, TooManyArguments, + NotEnoughArguments, NoExpression, //Machine errors RegisterNotFound, @@ -43,15 +46,17 @@ pub enum ErrorSubType { FileError } +#[derive(Debug, Clone)] pub struct ASLError { pub message: String, pub position: usize, pub typ: ErrorType, pub subtype: ErrorSubType, pub code: String, + ctx: Context } -fn convert_types_to_string(typ: &ErrorType) -> String { +pub fn convert_types_to_string(typ: &ErrorType) -> String { match typ { ErrorType::SyntaxError => String::from("Syntax Error: "), ErrorType::TypeError => String::from("Type Error: "), @@ -82,7 +87,7 @@ pub fn reverse_type_short(str: String) -> ErrorType { _ => panic!("Unknown error type short: {}", str), } } -fn convert_subtypes_to_string(stype: &ErrorSubType) -> String { +pub fn convert_subtypes_to_string(stype: &ErrorSubType) -> String { match stype { ErrorSubType::UnexpectedEnd => String::from("Unexpected end"), ErrorSubType::UnexpectedOperation => String::from("Unexpected operation"), @@ -109,6 +114,7 @@ fn convert_subtypes_to_string(stype: &ErrorSubType) -> String { ErrorSubType::FileError => String::from("File error"), ErrorSubType::RuntimeError => String::from("Runtime error"), ErrorSubType::NoExpression => String::from("No expression found"), + ErrorSubType::NotEnoughArguments => String::from("Not enough arguments"), } } fn convert_subtypes_to_short(stype: &ErrorSubType) -> String { @@ -138,6 +144,7 @@ fn convert_subtypes_to_short(stype: &ErrorSubType) -> String { ErrorSubType::FileError => String::from("FE:"), ErrorSubType::RuntimeError => String::from("RE:"), ErrorSubType::NoExpression => String::from("NE:"), + ErrorSubType::NotEnoughArguments => String::from("NA:"), } } pub fn reverse_subtype_short(str: String) -> ErrorSubType { @@ -167,13 +174,16 @@ pub fn reverse_subtype_short(str: String) -> ErrorSubType { "FE" => ErrorSubType::FileError, "RE" => ErrorSubType::RuntimeError, "NE" => ErrorSubType::NoExpression, + "NA" => ErrorSubType::NotEnoughArguments, _ => panic!("Unknown error subtype short: {}", str), } } -pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: ErrorSubType) -> ASLError { +pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: ErrorSubType, ctx: &Context) -> ASLError { let mut code = convert_types_to_short(&typ); code.push_str(&convert_subtypes_to_short(&stype)); + code.push_str(ctx.c_funcid.to_string().as_str()); + code.push(':'); code.push_str(&position.to_string()); ASLError { message: String::from(message), @@ -181,6 +191,7 @@ pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: Error typ, subtype: stype, code, + ctx: ctx.clone() } } @@ -223,7 +234,7 @@ fn get_sorrunding_lines(file: &String, line: usize) -> (String, String, String) (before, current, after) } -pub fn print_error(error: &ASLError, ctx: &Context) { +pub fn print_error(error: &ASLError) { let mut out = String::new(); out.push_str(&convert_types_to_string(&error.typ)); if error.message.len() < 1 { @@ -232,18 +243,18 @@ pub fn print_error(error: &ASLError, ctx: &Context) { out.push_str(&error.message); } - if ctx.known { + if error.ctx.known { out.push_str(" at position "); - let (line, column) = get_exact_pos(&ctx.raw_file, error.position); - out.push_str(&ctx.file); + let (line, column) = get_exact_pos(&error.ctx.raw_file, error.position); + out.push_str(&error.ctx.file); out.push_str(":"); out.push_str(&line.to_string()); out.push_str(":"); out.push_str(&column.to_string()); out.push_str("\n"); - let (before, current, after) = get_sorrunding_lines(&ctx.raw_file, line); + let (before, current, after) = get_sorrunding_lines(&error.ctx.raw_file, line); if line > 1 { out.push_str(&(line-1).to_string()); out.push_str(" | "); @@ -276,7 +287,5 @@ pub fn print_error(error: &ASLError, ctx: &Context) { out.push_str("\n"); out.push_str("Error Code: "); out.push_str(&error.code); - out.push_str(":"); - out.push_str(&ctx.c_funcid.to_string()); println!("{}", out); } \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index 7494f78..22fb976 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -70,8 +70,8 @@ fn read_string(splitted: &Vec<&str>, pos: &mut usize, out: &mut Vec, ctx: str += nchar; } if !success { - let err = create_error("Unexpected end of string", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error("Unexpected end of string", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 5; @@ -94,8 +94,8 @@ fn read_comment(splitted: &Vec<&str>, pos: &mut usize, is_multiline: bool, ctx: str += nchar; } if !success { - let err = create_error("Unexpected end of comment", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error("Unexpected end of comment", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; diff --git a/src/main.rs b/src/main.rs index bf38df7..0b758b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::{env, fs, time::Instant}; use virtualmachine::Machine; -use crate::{decompiler::{operation_to_name, process}, errors::{create_error, print_error, reverse_subtype_short, reverse_type_short}}; +use crate::{decompiler::{operation_to_name, process}, errors::{create_error, print_error, reverse_subtype_short, reverse_type_short}, virtualmachine::VMState}; mod lexer; mod parser; @@ -10,9 +10,9 @@ mod virtualmachine; mod errors; mod decompiler; -const CLIVER: [u8; 3] = [0, 2, 0]; +const CLIVER: [u8; 3] = [1,0,2]; -#[derive(Clone)] +#[derive(Debug, Clone)] struct Context { file: String, raw_file: String, @@ -59,7 +59,19 @@ fn main() { println!("Build successful. Took: {}ms", ntime.as_millis()); let mut vm = Machine::new(contexts); vm.load(&compiled); - vm.run(); + while let VMState::Paused = vm.state { + vm.resume(); + } + match vm.state { + VMState::Finished => { + println!("Execution finished successfully."); + }, + VMState::Error(err) => { + print_error(&err); + panic!("Execution failed with an error."); + }, + _ => {} + } }, Result::Err(err) => { panic!("Can't read file: {}", err); @@ -76,7 +88,19 @@ fn main() { } let mut vm = Machine::new(contexts); vm.load(&data); - vm.run(); + while let VMState::Paused = vm.state { + vm.resume(); + } + match vm.state { + VMState::Finished => { + println!("Execution finished successfully."); + }, + VMState::Error(err) => { + print_error(&err); + panic!("Execution failed with an error."); + }, + _ => {} + } }, Result::Err(err) => { panic!("Can't read file: {}", err); @@ -143,13 +167,13 @@ fn main() { println!("Build successful. Took: {}ms", ntime.as_millis()); let decompiled = process(&compiled); let errcode_data: Vec<&str> = args[3].split(":").collect(); - if decompiled.func_count <= errcode_data[3].parse().unwrap() { + if decompiled.func_count <= errcode_data[2].parse().unwrap() { println!("Error code {} is invalid for this file.", args[3]); return; } - let error = create_error("", errcode_data[2].parse().unwrap(), reverse_type_short(errcode_data[0].to_string()), reverse_subtype_short(errcode_data[1].to_string())); - let func_ctx = contexts[errcode_data[3].parse::().unwrap()].clone(); - print_error(&error, &func_ctx); + let func_ctx = contexts[errcode_data[2].parse::().unwrap()].clone(); + let error = create_error("", errcode_data[3].parse().unwrap(), reverse_type_short(errcode_data[0].to_string()), reverse_subtype_short(errcode_data[1].to_string()), &func_ctx); + print_error(&error); return; }, Result::Err(err) => { @@ -183,6 +207,7 @@ fn main() { for (id, pos) in &func.functions { println!(" {}: {}", id, pos); } + println!(" Try/Catch: {}", func.try_catch); println!(" Body:"); //Print these under each other like when you tabulate let mut longest_cols: Vec = vec![0, 0, 0, 0]; @@ -195,13 +220,14 @@ fn main() { let mut longest = 0; for op in &func.body { let op_name = operation_to_name(op.opcode); - let str = format!(" {}{} {}{} {}{} {} at {}", + let str = format!(" {}{} {}{} {}{} {}{} at {}", + " ".repeat(longest_cols[0] - op_name.len()), op_name, - " ".repeat(longest_cols[0] - op_name.len()), - op.arg1, " ".repeat(longest_cols[1] - op.arg1.to_string().len()), - op.arg2, + op.arg1, " ".repeat(longest_cols[2] - op.arg2.to_string().len()), + op.arg2, + " ".repeat(longest_cols[3] - op.arg3.to_string().len()), op.arg3, op.pos); longest = longest.max(str.len()+4); diff --git a/src/parser.rs b/src/parser.rs index 929ee50..e52fee6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -26,6 +26,7 @@ pub enum ASTPart { TableGet(AstTableGet), TableSet(AstTableSet), Import(AstImport), + TryCatch(AstTryCatch), NOOP } #[derive(Debug, Clone, PartialEq)] @@ -156,6 +157,12 @@ pub struct AstImport { pub path: String, pub pos: usize } +#[derive(Debug, Clone, PartialEq)] +pub struct AstTryCatch { + pub try_block: AstFunction, + pub catch_block: AstFunction, + pub pos: usize +} fn is_end(input: &Token, end: &Vec) -> bool { for token in end { @@ -213,7 +220,7 @@ fn shunt(input: Vec, ctx: &Context) -> ASTPart { output.push(part); }, ASTPart::Call(_) => { - stack.push(part); + output.push(part); }, ASTPart::VarRead(_) => { output.push(part); @@ -270,8 +277,8 @@ fn shunt(input: Vec, ctx: &Context) -> ASTPart { if op.operator == "!" { println!("{:?}", output); if i < 1 { - let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation, ctx); + print_error(&err); process::exit(1); } let left = output[i-1].clone(); @@ -284,8 +291,8 @@ fn shunt(input: Vec, ctx: &Context) -> ASTPart { output.remove(i-1); } else { if i < 2 { - let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation, ctx); + print_error(&err); process::exit(1); } let left = output[i-2].clone(); @@ -307,8 +314,8 @@ fn shunt(input: Vec, ctx: &Context) -> ASTPart { } } if output.len() == 0 { - let err = create_error(&format!("No expressions found after applying order of operations"), 0, ErrorType::SemanticError, ErrorSubType::NoExpression); - print_error(&err, &ctx); + let err = create_error(&format!("No expressions found after applying order of operations"), 0, ErrorType::SemanticError, ErrorSubType::NoExpression, ctx); + print_error(&err); process::exit(1); } return output[0].clone(); @@ -318,8 +325,8 @@ fn read_function(input: &Vec, pos: &mut usize, with_args: bool, ctx: &Con let start_pos = input[*pos].pos; if with_args { if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "(" { - let err = create_error(&format!("Expected `(`"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `(`"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -335,21 +342,21 @@ fn read_function(input: &Vec, pos: &mut usize, with_args: bool, ctx: &Con if token.typ == TokenType::IDENTIFIER { args.push(token.value.clone()); } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - let err = create_error(&format!("Unexpected end of arguments"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of arguments"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "{" { - let err = create_error(&format!("Expected {{"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected {{"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -363,8 +370,8 @@ fn read_function(input: &Vec, pos: &mut usize, with_args: bool, ctx: &Con ]; let body = parse_internal(input, &op_ends, &parse_ends, pos, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "}" { - let err = create_error(&format!("Unexpected end of function"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of function"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -396,26 +403,26 @@ fn read_table(input: &Vec, pos: &mut usize, ctx: &Context) -> ASTPart { let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, ASTPart::Function(_) => { - let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "=" { - let err = create_error(&format!("Expected `=` after key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `=` after key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -436,8 +443,8 @@ fn read_table(input: &Vec, pos: &mut usize, ctx: &Context) -> ASTPart { *pos += 1; continue; } else { - let err = create_error(&format!("Unexpected end of table"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of table"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } } @@ -496,8 +503,8 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: let func = read_function(input, pos, true, ctx); expressions.push(func); } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } else if token.typ == TokenType::IDENTIFIER { @@ -514,20 +521,20 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, ASTPart::Function(_) => { - let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -538,8 +545,8 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: *pos += 1; let keyy = &input[*pos]; if keyy.typ != TokenType::IDENTIFIER { - let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -560,8 +567,8 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == ")" { *pos += 1; } else { - let err = create_error(&format!("Unclosed parenthesis"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Unclosed); - print_error(&err, &ctx); + let err = create_error(&format!("Unclosed parenthesis"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Unclosed, ctx); + print_error(&err); process::exit(1); } expressions.push(exp); @@ -569,13 +576,13 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: let tbl = read_table(input, pos, ctx); expressions.push(tbl); } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } @@ -604,20 +611,20 @@ fn check_continue(pos: &mut usize, input: &Vec, prev: ASTPart, op_ends: & let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, ASTPart::Function(_) => { - let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -628,8 +635,8 @@ fn check_continue(pos: &mut usize, input: &Vec, prev: ASTPart, op_ends: & *pos += 1; let keyy = &input[*pos]; if keyy.typ != TokenType::IDENTIFIER { - let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -661,8 +668,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let variable = &input[*pos]; *pos += 1; if variable.typ != TokenType::IDENTIFIER { - let err = create_error(&format!("Unexpected `{:?}`", variable.typ,), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}`", variable.typ,), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } let eq = &input[*pos]; @@ -673,8 +680,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par return ASTPart::Assigment(AstAssigment { variable: variable.value.clone(), value: Box::new(value), pos: token.pos }); } else if token.value == "ha geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -683,8 +690,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par ]; let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -692,16 +699,16 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let real_body = match body { ASTPart::Function(func) => func.body, _ => { - let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } }; return ASTPart::If(AstIf { condition: Box::new(condition), body: real_body, pos: token.pos }); } else if token.value == "amíg geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -710,8 +717,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par ]; let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -719,8 +726,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let real_body = match body { ASTPart::Function(func) => func.body, _ => { - let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } }; @@ -729,8 +736,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par return ASTPart::Break(AstBreak { pos: token.pos }); } else if token.value == "kopva" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -740,32 +747,32 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par ]; let init = parse_internal(input, &ends, &ends, pos, ctx); if init.len() != 1 { - let err = create_error(&format!("Only one expression is expected for init"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Only one expression is expected for init"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" { - let err = create_error(&format!("Unexpected end of init"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of init"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; let condition = read_exp(pos, input, &ends, &ends, ctx); if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" { - let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; let update = parse_internal(input, &ends, &ends, pos, ctx); if update.len() != 1 { - let err = create_error(&format!("Only one expression is expected for update"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Only one expression is expected for update"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - let err = create_error(&format!("Unexpected end of update"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of update"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -773,8 +780,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let real_body = match body { ASTPart::Function(func) => func.body, _ => { - let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } }; @@ -783,8 +790,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par return ASTPart::Continue(AstContinue { pos: token.pos }); } else if token.value == "ha nem geny akkor geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -793,8 +800,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par ]; let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -802,8 +809,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let real_body = match body { ASTPart::Function(func) => func.body, _ => { - let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } }; @@ -813,8 +820,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let real_body = match body { ASTPart::Function(func) => func.body, _ => { - let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } }; @@ -830,20 +837,20 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let var = &input[*pos]; *pos += 1; if var.typ != TokenType::IDENTIFIER { - let err = create_error(&format!("Expected identifier after hámozd"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected identifier after hámozd"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } if input[*pos].typ != TokenType::KEYWORD || (input[*pos].value != "be" && input[*pos].value != "ba") { - let err = create_error(&format!("Expected `be`/`ba` after hámozd"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected `be`/`ba` after hámozd"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; let path = &input[*pos]; if path.typ != TokenType::STRING { - let err = create_error(&format!("Expected string for hámozd"), path.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected string for hámozd"), path.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -857,9 +864,35 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let func = read_function(input, pos, true, ctx); return check_continue(pos, input, func, op_ends, parse_ends, ctx); } + } else if token.value == "piszolj" { + let func = read_function(input, pos, false, ctx); + let tryp = match func { + ASTPart::Function(f) => f, + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); + process::exit(1); + } + }; + if input[*pos].typ != TokenType::KEYWORD || input[*pos].value != "csecs" { + let err = create_error(&format!("Expected `csecs` after piszolj"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); + process::exit(1); + } + *pos += 1; + let func2 = read_function(input, pos, true, ctx); + let catchp = match func2 { + ASTPart::Function(f) => f, + _ => { + let err = create_error(&format!("Expected function body"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); + process::exit(1); + } + }; + return ASTPart::TryCatch(AstTryCatch { try_block: tryp, catch_block: catchp, pos: token.pos }); } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } else if token.typ == TokenType::IDENTIFIER { @@ -872,8 +905,8 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par *pos += 1; let keyy = &input[*pos]; if keyy.typ != TokenType::IDENTIFIER { - let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected); - print_error(&err, &ctx); + let err = create_error(&format!("Expected identifier after `.`"), keyy.pos, ErrorType::SyntaxError, ErrorSubType::Expected, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -887,20 +920,20 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, ASTPart::Function(_) => { - let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); - print_error(&err, &ctx); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys, ctx); + print_error(&err); process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd, ctx); + print_error(&err); process::exit(1); } *pos += 1; @@ -917,13 +950,13 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let value = read_exp(pos, input, op_ends, parse_ends, ctx); return ASTPart::VarUpdate(AstVarUpdate { variable: token.value.clone(), value: Box::new(value), pos: token.pos }); } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } else { - let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); - print_error(&err, &ctx); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected, ctx); + print_error(&err); process::exit(1); } } diff --git a/src/virtualmachine.rs b/src/virtualmachine.rs index 6ff9e46..d49a882 100644 --- a/src/virtualmachine.rs +++ b/src/virtualmachine.rs @@ -1,5 +1,5 @@ -use std::{any::Any, collections::HashMap, process, vec}; -use crate::{decompiler::{operation_to_name, process, DecompiledFunction, DecompiledOperation}, enviroment, errors::{create_error, print_error, ErrorSubType, ErrorType}, Context}; +use std::{any::Any, collections::HashMap, vec}; +use crate::{decompiler::{operation_to_name, process, DecompiledFunction, DecompiledOperation}, enviroment, errors::{convert_subtypes_to_string, convert_types_to_string, create_error, ASLError, ErrorSubType, ErrorType}, Context}; #[derive(Debug, Clone)] pub enum VMMemory { @@ -64,15 +64,24 @@ pub struct CallStack { pub pc: usize, } +#[derive(Debug, Clone)] +pub enum VMState { + Running, + Paused, + Finished, + Error(ASLError), +} + pub struct Machine { pub memory: Vec, - functions: Vec, + pub functions: Vec, pub stack: Vec, pub registers: Vec, pub call_stack: Vec, pub env: HashMap, pub ctx: Vec, pub storage: Vec>, + pub state: VMState, } fn get_register_by_id(registers: &Vec, id: u8) -> Option<&Register> { @@ -175,22 +184,79 @@ fn set_var_id(var: &mut VMMemory, target: u32) { } } -fn do_operation_operation(registers: &mut Vec, memory: &mut Vec, operation: &DecompiledOperation, ctx: &Context) { - let reg_clone = registers.clone(); +fn fallback_to_catch(memory: &mut Vec, state: &mut VMState, functions: &mut Vec, call_stack: &mut Vec, executed_stack: &mut usize, executed_func: &DecompiledFunction, err: ASLError) { + call_stack.pop(); + if call_stack.len() < 1 { + *state = VMState::Finished; + return; + } + let catchf = match executed_func.functions.get(&executed_func.try_catch) { + Some(f) => f, + None => { + panic!("Try/Catch function not found!"); + } + }; + call_stack.push(CallStack { func: *catchf as usize, return_reg: 0, pc: 0 }); + *executed_stack = call_stack.len() - 1; + let func = &functions[*catchf as usize]; + let err_tbl: Vec = vec![ + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("message"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: err.message, variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("position"), variable_id: 0 }), + value: VMMemory::Number(VMMemoryNumber { value: err.position as f64, variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("type"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: convert_types_to_string(&err.typ), variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("subtype"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: convert_subtypes_to_string(&err.subtype), variable_id: 0 }) + }, + TableValue { + key: VMMemory::String(VMMemoryString { value: String::from("code"), variable_id: 0 }), + value: VMMemory::String(VMMemoryString { value: err.code, variable_id: 0 }) + }, + ]; + if func.variables.len() < 1 || func.variables[0].start != 0 { + return; + } + memory.push(VMMemory::Table(VMMemoryTable { values: err_tbl, variable_id: func.variables[0].id })); +} + +fn do_operation_operation(machine: &mut Machine, operation: &DecompiledOperation, executed_stack: &mut usize, executed_func: &DecompiledFunction) { + let registers = &mut machine.registers; + let memory = &mut machine.memory; + let ctx = &machine.ctx[machine.call_stack[*executed_stack].func].clone(); + let func = machine.functions[machine.call_stack[*executed_stack].func].clone(); + let reg_clone: Vec = registers.clone(); let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg1.is_none() || reg2.is_none() || reg3.is_none() { - let err = create_error(&format!("One or more registers not found for operation"), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("One or more registers not found for operation"), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } let mem1 = reg1.unwrap().pointer; let mem2 = reg2.unwrap().pointer; if mem1 >= memory.len() || mem2 >= memory.len() || mem1 < 1 || mem2 < 1 { - let err = create_error(&format!("Memory location out of bounds `{}` or `{}`", mem1, mem2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Memory location out of bounds `{}` or `{}`", mem1, mem2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } let mut result: VMMemory; match (&memory[mem1], &memory[mem2]) { @@ -207,9 +273,14 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { if num2.value == 0.0 { - let err = create_error(&format!("Division by zero"), operation.pos, ErrorType::MathError, ErrorSubType::DivisionByZero); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Division by zero"), operation.pos, ErrorType::MathError, ErrorSubType::DivisionByZero, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } result = VMMemory::Number(VMMemoryNumber { value: num1.value / num2.value, variable_id: 0 }); }, @@ -238,9 +309,14 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - let err = create_error(&format!("Unknown operation code for number operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Unknown operation code for number operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } }; }, @@ -256,9 +332,14 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - let err = create_error(&format!("Unknown operation code for string operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Unknown operation code for string operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } }; }, @@ -277,9 +358,14 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - let err = create_error(&format!("Unknown operation code for boolean operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Unknown operation code for boolean operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } }; }, @@ -292,16 +378,26 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - let err = create_error(&format!("Unknown operation code for null operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Unknown operation code for null operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } }; }, _ => { - let err = create_error(&format!("Wrong memory types for operation: `{}`, position: `{}` and `{}`", operation_to_name(operation.opcode), mem1, mem2), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &ctx); - process::exit(1); + let err = create_error(&format!("Wrong memory types for operation: `{}`, position: `{}` and `{}`", operation_to_name(operation.opcode), mem1, mem2), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, ctx); + if func.try_catch > 0 { + fallback_to_catch(memory, &mut machine.state, &mut machine.functions, &mut machine.call_stack, executed_stack, executed_func, err); + return; + } else { + machine.state = VMState::Error(err); + return; + } } } let mut reg3_pointer = reg3.unwrap().pointer; @@ -339,15 +435,28 @@ impl Machine { env: enviroment::generate(), ctx: ctx, storage: Vec::new(), + state: VMState::Finished }; } pub fn load(&mut self, data: &Vec) { let dec = process(data); self.functions = dec.functions; + self.state = VMState::Paused } - pub fn run(&mut self) { + pub fn load_functions(&mut self, functions: Vec) { + self.functions = functions; + self.state = VMState::Paused; + } + + pub fn resume(&mut self) { + match self.state { + VMState::Paused => {}, + _ => { + panic!("Unable to resume VM, current state is not paused"); + } + }; if self.call_stack.len() == 0 { return; } @@ -355,26 +464,38 @@ impl Machine { let executed_func = func_clone.get(self.call_stack[self.call_stack.len()-1].func); let mut executed_stack = self.call_stack.len()-1; if executed_func.is_none() { - let err = create_error(&format!("Current function not found"), 1, ErrorType::MachineError, ErrorSubType::UnknownFunction); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + panic!("Unable to resume VM, current function not found in function list"); } let mut executed_func = executed_func.unwrap(); + self.state = VMState::Running; while self.call_stack[executed_stack].pc < executed_func.body.len() { + match self.state { + VMState::Running => {}, + _ => { + return; + } + }; let operation = &executed_func.body[self.call_stack[executed_stack].pc]; self.call_stack[executed_stack].pc += 1; match operation.opcode { 0 => { //HLT + self.state = VMState::Finished; return; }, 1 => { //LDS let str = executed_func.strings.get(&(operation.arg2 as u32)); if str.is_none() { - let err = create_error(&format!("String with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownString); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("String with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownString, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let str = str.unwrap(); self.memory.push(VMMemory::String(VMMemoryString { value: str.clone(), variable_id: 0 })); @@ -384,15 +505,27 @@ impl Machine { //LDM let mem = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if mem.is_none() { - let err = create_error(&format!("Memory with variable ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory with variable ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem = mem.unwrap(); if mem >= self.memory.len() || mem < 1 { - let err = create_error(&format!("Memory location out of bounds for variable ID `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location out of bounds for variable ID `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mut nmem = self.memory[mem].clone(); match &mut nmem { @@ -435,16 +568,28 @@ impl Machine { //LDF let func_pos = executed_func.functions.get(&(operation.arg2 as u32)); if func_pos.is_none() { - let err = create_error(&format!("Function with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Function with ID `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let func_pos = func_pos.unwrap(); let func = self.functions.get(*func_pos as usize); if func.is_none() { - let err = create_error(&format!("Function with position `{}` not found", func_pos), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Function with position `{}` not found", func_pos), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownFunction, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } self.memory.push(VMMemory::Function(VMMemoryFunction { id: *func_pos as usize, @@ -466,15 +611,27 @@ impl Machine { //ASS let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let reg = reg.unwrap(); if reg.pointer >= self.memory.len() || reg.pointer < 1 { - let err = create_error(&format!("Register `{}` points to an invalid memory location", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` points to an invalid memory location", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let used_var = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if let Some(pos) = used_var { @@ -491,15 +648,22 @@ impl Machine { let temp_regs = self.registers.clone(); let reg1 = get_register_by_id(&temp_regs, operation.arg1); if reg1.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let reg1 = reg1.unwrap(); set_register(&mut self.registers, Register { id: operation.arg2 as u8, pointer: reg1.pointer }); }, 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 => { - do_operation_operation(&mut self.registers, &mut self.memory, operation, &self.ctx[self.call_stack[executed_stack].func].clone()); + do_operation_operation(self, operation, &mut executed_stack, executed_func); + executed_func = &func_clone[self.call_stack[executed_stack].func]; }, 24 => { //NOT @@ -507,15 +671,27 @@ impl Machine { let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); if reg1.is_none() || reg2.is_none() { - let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem1 = reg1.unwrap().pointer; if mem1 >= self.memory.len() || mem1 < 1 { - let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mut result: VMMemory; match &self.memory[mem1] { @@ -523,9 +699,15 @@ impl Machine { result = VMMemory::Boolean(VMMemoryBoolean { value: !bool.value, variable_id: 0 }); }, _ => { - let err = create_error(&format!("Wrong memory type for NOT operation, position: `{}`", mem1), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Wrong memory type for NOT operation, position: `{}`", mem1), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } let mut reg2_pointer = reg2.unwrap().pointer; @@ -546,16 +728,28 @@ impl Machine { //CJP let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { - let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem = mem.unwrap(); match &mem { @@ -565,9 +759,15 @@ impl Machine { } } _ => { - let err = create_error(&format!("Wrong memory type for CJP operation, position: `{}`", reg.pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Wrong memory type for CJP operation, position: `{}`", reg.pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } }, } }, @@ -575,32 +775,75 @@ impl Machine { //CAL let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { - let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem = mem.unwrap().clone(); match mem { VMMemory::Function(func) => { let arg = 0; + let mut nocon = false; for i in &self.stack { let mut new_mem = i.clone(); if self.functions[func.id].variables.len() <= arg || self.functions[func.id].variables[arg].start != 0 { - let err = create_error(&format!("Too many arguments supplied for function: `{}`", func.id), operation.pos, ErrorType::SemanticError, ErrorSubType::TooManyArguments); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Too many arguments supplied for function: `{}`", func.id), operation.pos, ErrorType::SemanticError, ErrorSubType::TooManyArguments, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + nocon = true; + break; + } else { + self.state = VMState::Error(err); + return; + } } set_var_id(&mut new_mem, self.functions[func.id].variables[arg].id); self.memory.push(new_mem); } + for arg in &self.functions[func.id].variables { + if arg.start != 0 { + break; + } + match get_mem_pos_by_var_id(&self.memory, arg.id) { + None => { + let err = create_error(&format!("Not enough arguments supplied for function: `{}`", func.id), operation.pos, ErrorType::SemanticError, ErrorSubType::NotEnoughArguments, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + nocon = true; + break; + } else { + self.state = VMState::Error(err); + return; + } + }, + _ => {} + } + } self.stack.clear(); + if nocon { + continue; + } self.call_stack.push(CallStack { func: func.id, return_reg: operation.arg2 as usize, pc: 0 }); executed_func = &func_clone[func.id]; @@ -610,9 +853,15 @@ impl Machine { let mut result = (nfunc.func)(self, &operation, self.stack.clone()); let ret_reg = get_register_by_id(&self.registers, operation.arg2 as u8); if ret_reg.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mut ret_pointer = ret_reg.unwrap().pointer; if ret_pointer >= self.memory.len() || ret_pointer < 1 { @@ -627,9 +876,15 @@ impl Machine { self.stack.clear(); }, _ => { - let err = create_error(&format!("Unable to call non-function type"), operation.pos, ErrorType::MachineError, ErrorSubType::NonFunctionCall); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Unable to call non-function type"), operation.pos, ErrorType::MachineError, ErrorSubType::NonFunctionCall, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } }, @@ -637,16 +892,28 @@ impl Machine { //PSH let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); if mem.is_none() { - let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem = mem.unwrap(); self.stack.push(mem.clone()); @@ -656,15 +923,27 @@ impl Machine { let target_reg = get_register_by_id(&self.registers, self.call_stack[executed_stack].return_reg as u8); let ret_reg = get_register_by_id(&self.registers, operation.arg1); if target_reg.is_none() || ret_reg.is_none() { - let err = create_error(&format!("Register `{}` or `{}` not found", self.call_stack[executed_stack].return_reg, operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` or `{}` not found", self.call_stack[executed_stack].return_reg, operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let ret_mem = self.memory.get(ret_reg.unwrap().pointer); if ret_mem.is_none() { - let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}`", operation.arg1), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let return_value = ret_mem.unwrap().clone(); let target_reg_pointer = self.memory.len(); @@ -673,6 +952,7 @@ impl Machine { self.memory[target_reg_pointer] = return_value; self.call_stack.pop(); if self.call_stack.len() < 1 { + self.state = VMState::Finished; return; } executed_stack = self.call_stack.len() - 1; @@ -686,15 +966,27 @@ impl Machine { let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg2.is_none() || reg3.is_none() { - let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem2 = self.memory.get(reg2.unwrap().pointer); if mem2.is_none() { - let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location out of bounds for register `{}`", operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem2 = mem2.unwrap().clone(); let mut result: VMMemory; @@ -708,9 +1000,15 @@ impl Machine { } }, _ => { - let err = create_error(&format!("Only string keys are allowed for GET enviroment"), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Only string keys are allowed for GET enviroment"), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } let mut reg3_pointer = reg3.unwrap().pointer; @@ -728,16 +1026,28 @@ impl Machine { let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { - let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); if mem1.is_none() || mem2.is_none() { - let err = create_error(&format!("Memory location not found for register `{}` or `{}`", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}` or `{}`", operation.arg1, operation.arg2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem1 = mem1.unwrap().clone(); let mem2 = mem2.unwrap().clone(); @@ -752,9 +1062,15 @@ impl Machine { } }, _ => { - let err = create_error(&format!("Wrong memory type for GET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Wrong memory type for GET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } let mut reg3_pointer = reg3.unwrap().pointer; @@ -773,17 +1089,29 @@ impl Machine { let reg2 = get_register_by_id(&self.registers, operation.arg2 as u8); let reg3 = get_register_by_id(&self.registers, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { - let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); let mem3 = self.memory.get(reg3.unwrap().pointer); if mem1.is_none() || mem2.is_none() || mem3.is_none() { - let err = create_error(&format!("Memory location not found for register `{}` or `{}` or `{}`", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Memory location not found for register `{}` or `{}` or `{}`", operation.arg1, operation.arg2, operation.arg3), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } let mem2 = mem2.unwrap().clone(); let mem3 = mem3.unwrap().clone(); @@ -793,18 +1121,31 @@ impl Machine { set_mem_tbl_val(tbl, mem2, mem3); }, _ => { - let err = create_error(&format!("Wrong memory type for SET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Wrong memory type for SET operation, position: `{}`", reg.unwrap().pointer), operation.pos, ErrorType::TypeError, ErrorSubType::WrongType, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } }, _ => { - let err = create_error(&format!("Unknown operation code: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); - print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); - process::exit(1); + let err = create_error(&format!("Unknown operation code: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode, &self.ctx[self.call_stack[executed_stack].func].clone()); + if executed_func.try_catch > 0 { + fallback_to_catch(&mut self.memory, &mut self.state, &mut self.functions, &mut self.call_stack, &mut executed_stack, executed_func, err); + executed_func = &func_clone[self.call_stack[executed_stack].func]; + continue; + } else { + self.state = VMState::Error(err); + return; + } } } } + self.state = VMState::Finished; } } \ No newline at end of file diff --git a/test.asl b/test.asl index 005e58d..3324140 100644 --- a/test.asl +++ b/test.asl @@ -1,18 +1,2 @@ -gethelj a = 125 -gethelj b = 567 -gethelj c = 8765 -gethelj d = 123 -gethelj e = 123 -gethelj f = 123 -gethelj g = 123 -gethelj h = 123 -gethelj i = 123 -gethelj j = 123 -gethelj k = 123 -gethelj l = 123 -gethelj m = 123 -gethelj n = 123 -gethelj o = 123 -gethelj p = 123 -gethelj q = 123 -ugass(a+b+c) \ No newline at end of file +hámozd test be szaft"test2.asl"szaft +gethelj a = szaft"asd"szaft+1 \ No newline at end of file