diff --git a/.gitignore b/.gitignore index 290657a0..693095af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /build -/llvm_build +/llvm_build* .idea *.exe /.vscode/*.log diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b1e296f..9d3cc8e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ Der Changelog von DDP. Sortiert nach Release. ## In Entwicklung +- [Fix] Duden/Uri parset nun absolute Uris der Form /pfad?query korrekt +- [Neu] Duden/Netzwerk stellt Typen und Funktionen für (low-level) TCP und UDP Kommunikation zur Verfügung. +- [Fix] Konstanten können nun nicht mehr in Zuweisungen oder als Referenzen verwendet werden - [Neu] Numerische Datentypen werden in Zuweisungen jetzt automatisch in einander umgewandelt - [Neu] Es gibt jetzt den Byte Datentyp, der eine natürliche Zahl im Bereich 0 bis einschließlich 255 darstellt - [Neu] Typanpassende Ausdrücke können nun als Referenzen übergeben werden, solange sie nur Typaliase bzw. Typdefinitionen behandeln diff --git a/cmd/internal/linker/link.go b/cmd/internal/linker/link.go index ff7ea7b8..66fd823c 100644 --- a/cmd/internal/linker/link.go +++ b/cmd/internal/linker/link.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strings" "github.com/DDP-Projekt/Kompilierer/cmd/internal/gcc" @@ -138,6 +139,9 @@ func LinkDDPFiles(options Options) ([]byte, error) { args = append(args, "-llzma") args = append(args, "-lbz2") args = append(args, "-llz4") + if runtime.GOOS == "windows" { + args = append(args, "-lws2_32") + } // add additional gcc-flags such as other needed libraries if options.GCCFlags != "" { diff --git a/lib/runtime/include/DDP/ddpwindows.h b/lib/runtime/include/DDP/ddpwindows.h index c67f9bff..7736a283 100644 --- a/lib/runtime/include/DDP/ddpwindows.h +++ b/lib/runtime/include/DDP/ddpwindows.h @@ -10,6 +10,15 @@ #define NOMINMAX #define WIN32_LEAN_AND_MEAN + +#ifndef WINVER +#define WINVER 0x0A00 +#endif // WINVER + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0A00 +#endif // _WIN32_WINNT + #include #endif // DDPOS_WINDOWS diff --git a/lib/stdlib/Duden/C.ddp b/lib/stdlib/Duden/C.ddp index 17eddc5a..7cb41e25 100644 --- a/lib/stdlib/Duden/C.ddp +++ b/lib/stdlib/Duden/C.ddp @@ -5,6 +5,8 @@ [ Repräsentiert einen C-Zeiger (void*) ] Wir definieren einen Zeiger öffentlich als eine Zahl. +[ Repräsentiert einen int ] +Wir definieren einen C_int oeffentlich als einen Buchstaben. Die öffentliche Funktion C_Null gibt einen Zeiger zurück, macht: Gib 0 als Zeiger zurück. @@ -46,3 +48,10 @@ Die öffentliche Funktion Erstelle_Byte_Puffer mit dem Parameter n vom Typ Zahl, ist in "libddpstdlib.a" definiert Und kann so benutzt werden: "ein neuer Puffer der Länge " + +[ close(int fd) ] +Die oeffentliche Funktion close mit dem Parameter fd vom Typ C_int, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Schließe ", + "schließe " diff --git a/lib/stdlib/Duden/Listen.ddp b/lib/stdlib/Duden/Listen.ddp index f6062b03..c05cf799 100644 --- a/lib/stdlib/Duden/Listen.ddp +++ b/lib/stdlib/Duden/Listen.ddp @@ -14,6 +14,12 @@ ist in "libddpstdlib.a" definiert Und kann so benutzt werden: "efficient_list_append " +[Hilfsfunktion für Hinzufügen_X] +Die generische Funktion efficient_list_append_list mit den Parametern list, other und v vom Typ T Listen Referenz, T Listen Referenz und Variablen Referenz, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +Und kann so benutzt werden: + "efficient_list_append_list " + [ Fügt ein Element ans Ende der gegeben Liste an. ] @@ -24,6 +30,16 @@ Und kann so benutzt werden: "Füge an an", "füge an an" +[ + Fügt eine Liste ans Ende der gegeben Liste an. +] +Die öffentliche generische Funktion Hinzufügen_Liste_Liste mit den Parametern liste und other vom Typ T Listen Referenz und T Liste, gibt nichts zurück, macht: + Die Variable v ist der Standardwert von einem T. + efficient_list_append_list liste other v. +Und kann so benutzt werden: + "Füge an an", + "füge an an" + Die generische Funktion efficient_list_insert mit den Parametern list, index, elem und v vom Typ T Listen Referenz, Zahl, T Referenz und Variablen Referenz, gibt nichts zurück, ist in "libddpstdlib.a" definiert Und kann so benutzt werden: @@ -59,6 +75,11 @@ ist in "libddpstdlib.a" definiert Und kann so benutzt werden: "efficient_list_prepend " +Die generische Funktion efficient_list_prepend_list mit den Parametern liste, other und v vom Typ T Listen Referenz, T Listen Referenz und Variablen Referenz, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +Und kann so benutzt werden: + "efficient_list_prepend_list " + [ Fügt ein Element an Anfang der gegeben Liste an. Ist der Index invalide wird ein Laufzeitfehler ausgelöst @@ -70,6 +91,17 @@ Die öffentliche generische Funktion Voranstellen_Liste mit den Parametern liste Und kann so benutzt werden: "Stelle vor " +[ + Fügt eine Liste an Anfang der gegeben Liste an. + Ist der Index invalide wird ein Laufzeitfehler ausgelöst +] +Die öffentliche generische Funktion Voranstellen_Liste_Liste mit den Parametern liste und other vom Typ T Listen Referenz und T Liste, gibt nichts zurück, macht: + [Speichere elm verkettet mit liste in liste.] + Die Variable v ist der Standardwert von einem T. + efficient_list_prepend_list liste other v. +Und kann so benutzt werden: + "Stelle vor " + Die generische Funktion efficient_list_delete_range mit den Parametern list, start, end und v vom Typ T Listen Referenz, Zahl, Zahl und Variablen Referenz, gibt nichts zurück, ist in "libddpstdlib.a" definiert Und kann so benutzt werden: diff --git a/lib/stdlib/Duden/Netzwerk.ddp b/lib/stdlib/Duden/Netzwerk.ddp new file mode 100644 index 00000000..cc76178c --- /dev/null +++ b/lib/stdlib/Duden/Netzwerk.ddp @@ -0,0 +1,244 @@ +[ + Duden/Netzwerk stellt low-level Funktionen zum Arbeiten mit Sockets zur Verfügung. +] + +Binde "Duden/C" ein. +Binde "Duden/Fehlerbehandlung" ein. +Binde "Duden/Laufzeit" ein. +Binde "Duden/Texte" ein. + +Die Funktion Init_Windows gibt einen Wahrheitswert zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "windows sockets initialisiert wurden" + +Der Wahrheitswert windows_initialisiert ist wahr, wenn windows sockets initialisiert wurden. + +Wir definieren eine AddressInfo öffentlich als einen Zeiger. + +Wir nennen die öffentliche Kombination aus + der Zahl padding1, + der Zahl padding2, + der Zahl padding3, + der Zahl padding4, + der Zahl padding5, + der Zahl padding6, + der Zahl padding7, + der Zahl padding8, + der Zahl padding9, + der Zahl padding10, + der Zahl padding11, + der Zahl padding12, + der Zahl padding13, + der Zahl padding14, + der Zahl padding15, + der Zahl padding16, + dem C_int size, +eine KlientenAddresse, +und erstellen sie so: + "eine leere KlientenAddresse", + "eine ungefüllte KlientenAddresse" + +Wir nennen die öffentliche Kombination aus + dem C_int fd, + dem C_int familie, + dem C_int typ, +einen Socket. + +[ AF_UNSPEC ] +Der öffentliche C_int IPV4_ODER_IPV6 ist 0 als Buchstabe als C_int. +[ AF_INET ] +Der öffentliche C_int IPV4 ist 2 als Buchstabe als C_int. +[ SOCK_STREAM ] +Der öffentliche C_int TCP ist 1 als Buchstabe als C_int. +[ SOCK_DGRAM ] +Der öffentliche C_int UDP ist 2 als Buchstabe als C_int. + +[ AF_INET6 ] +Die öffentliche Funktion AF_IPV6 gibt einen C_int zurück, macht: + Gib (26, falls das Betriebssystem gleich "Windows" ist, ansonsten 10) als Buchstabe als C_int zurück. +Und kann so benutzt werden: + "IPV6" + +Die öffentliche Funktion Lade_AddressInfo mit den Parametern familie, typ, name und service vom Typ C_int, C_int, Text und Text, gibt eine AddressInfo zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "die AddressInfo der Familie vom Typ für den Namen und den Service " oder + "die AddressInfo für den Namen und den Service " oder + "eine AddressInfo der Familie vom Typ für den Namen und den Service " oder + "eine AddressInfo für den Namen und den Service " + +Die öffentliche Funktion freeaddrinfo mit dem Parameter info vom Typ AddressInfo, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Befreie " + +[ + Wandelt die ERSTE addresse in AddrInfo zu einem Text um. +] +Die öffentliche Funktion AddressInfo_zu_Text mit dem Parameter info vom Typ AddressInfo, gibt einen Text zurück, +ist in "libddpstdlib.a" definiert +und überlädt den "als" Operator. + +Die öffentliche Funktion Socket_Erstellen mit den Parametern familie und typ vom Typ C_int und C_int, gibt einen Socket zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "ein Socket der Familie vom Typ ", + "einen Socket der Familie vom Typ " + +Die öffentliche Funktion Socket_Erstellen_Typ mit dem Parameter typ vom Typ C_int, gibt einen Socket zurück, macht: + Gib einen Socket der Familie IPV4 vom Typ typ zurück. +Und kann so benutzt werden: + "ein Socket", + "einen Socket" + +Die Funktion Schließe_Socket_Windows mit dem Parameter sock vom Typ Socket, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "schließe unter Windows" + +Die öffentliche Funktion Schließe_Socket mit dem Parameter sock vom Typ Socket, gibt nichts zurück, macht: + Wenn das Betriebssystem gleich "Windows" ist, schließe sock unter Windows. + Sonst schließe (fd von sock). +Und kann so benutzt werden: + "Schließe " + +Die öffentliche Funktion Socket_Binden mit den Parametern sock und info vom Typ Socket und AddressInfo, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Setze auf " + +Die öffentliche Funktion Socket_Binden_Name_Service mit den Parametern sock, name und service vom Typ Socket, Text und Text, gibt nichts zurück, macht: + Die AddressInfo info ist die AddressInfo der Familie (familie von sock) vom Typ (typ von sock) für den Namen name und den Service service. + Setze sock auf info. + Befreie info. +Und kann so benutzt werden: + "Setze auf " + +Die öffentliche Funktion Socket_Binden_Name_Port mit den Parametern sock, name und service vom Typ Socket, Text und Zahl, gibt nichts zurück, macht: + Setze sock auf name (service als Text). +Und kann so benutzt werden: + "Setze auf " + +Die öffentliche Funktion Socket_Verbinden mit den Parametern sock und info vom Typ Socket und AddressInfo, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Verbinde mit " + +Die öffentliche Funktion Socket_Verbinden_Name_Service mit den Parametern sock, name und service vom Typ Socket, Text und Text, gibt nichts zurück, macht: + Die AddressInfo info ist die AddressInfo der Familie (familie von sock) vom Typ (typ von sock) für den Namen name und den Service service. + Verbinde sock mit info. + Befreie info. +Und kann so benutzt werden: + "Verbinde mit " + +Die öffentliche Funktion Socket_Verbinden_Name_Port mit den Parametern sock, name und port vom Typ Socket, Text und Zahl, gibt nichts zurück, macht: + Verbinde sock mit name (port als Text). +Und kann so benutzt werden: + "Verbinde mit " + +Die öffentliche Funktion Socket_Zuhoeren mit den Parametern sock und backlog vom Typ Socket und Zahl, gibt nichts zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Lass auf maximal Verbindungen warten" oder + "Lass auf maximal Verbindung warten" + +Die öffentliche Funktion Socket_Verbindung_Annehmen mit den Parametern sock und client vom Typ Socket und KlientenAddresse Referenz, gibt einen Socket zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "die nächste Verbindung von auf " + +Die öffentliche Funktion Socket_Verbindung_Annehmen_Ohne_Klient mit dem Parameter sock vom Typ Socket, gibt einen Socket zurück, macht: + Die KlientenAddresse client ist eine leere KlientenAddresse. + Der Socket verbindung ist die nächste Verbindung von client auf sock. + Gib verbindung zurück. +Und kann so benutzt werden: + "die nächste Verbindung auf " + +Die öffentliche Funktion Socket_Senden mit den Parametern verbindung und daten vom Typ Socket und Byte Listen Referenz, gibt eine Zahl zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Sende über " oder + "wie viele Bytes von über gesendet wurden" + +Die öffentliche Funktion Socket_Senden_Wert mit den Parametern verbindung und daten vom Typ Socket und Byte Liste, gibt eine Zahl zurück, macht: + Gib wie viele Bytes von daten über verbindung gesendet wurden zurück. +Und kann so benutzt werden: + "Sende über " oder + "wie viele Bytes von über gesendet wurden" + +Die öffentliche Funktion Socket_Empfangen mit den Parametern verbindung und max vom Typ Socket und Zahl, gibt eine Byte Liste zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "maximal Bytes aus ", + "maximal die nächsten Bytes aus ", + "maximal den nächsten Bytes aus " + +Die öffentliche Funktion Socket_Senden_An_Klient mit den Parametern verbindung, daten und client vom Typ Socket, Byte Listen Referenz und KlientenAddresse, gibt eine Zahl zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Sende über an " oder + "wie viele Bytes von über an gesendet wurden" + +Die öffentliche Funktion Socket_Senden_An mit den Parametern verbindung, daten und info vom Typ Socket, Byte Listen Referenz und AddressInfo, gibt eine Zahl zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "Sende über an " oder + "wie viele Bytes von über an gesendet wurden" + +Die öffentliche Funktion Socket_Empfangen_Von mit den Parametern verbindung, max und client vom Typ Socket, Zahl und KlientenAddresse Referenz, gibt eine Byte Liste zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "das nächste maximal Bytes große Packet aus von ", + "dem nächsten maximal Bytes großen Packet aus von " + +Die öffentliche Funktion Socket_Empfangen_Von_Ohne_Klient mit den Parametern verbindung und max vom Typ Socket und Zahl, gibt eine Byte Liste zurück, macht: + Die KlientenAddresse client ist eine leere KlientenAddresse. + Gib das nächste maximal max Bytes große Packet aus verbindung von client zurück. +Und kann so benutzt werden: + "das nächste maximal Bytes große Packet aus ", + "dem nächsten maximal Bytes großen Packet aus " + +Die öffentliche Funktion Socket_Senden_Text mit den Parametern verbindung und daten vom Typ Socket und Text Referenz, gibt eine Zahl zurück, macht: + Gib wie viele Bytes von (den Bytes von daten) über verbindung gesendet wurden zurück. +Und kann so benutzt werden: + "Sende über " oder + "wie viele Bytes von über gesendet wurden" + +Die öffentliche Funktion Socket_Senden_Text_Wert mit den Parametern verbindung und daten vom Typ Socket und Text, gibt eine Zahl zurück, macht: + Gib wie viele Bytes von daten über verbindung gesendet wurden zurück. +Und kann so benutzt werden: + "Sende über " oder + "wie viele Bytes von über gesendet wurden" + +Die öffentliche Funktion Socket_Empfangen_Text mit den Parametern verbindung und max vom Typ Socket und Zahl, gibt einen Text zurück, macht: + Gib die Bytes (maximal max Bytes aus verbindung) als Text zurück. +Und kann so benutzt werden: + "der maximal Bytes lange Text aus ", + "der nächste maximal Bytes lange Text aus ", + "dem nächste maximal Bytes lange Text aus " + +Die öffentliche Funktion Socket_Senden_An_Klient_Text mit den Parametern verbindung, daten und client vom Typ Socket, Text Referenz und KlientenAddresse, gibt eine Zahl zurück, macht: + Gib wie viele Bytes von (den Bytes von daten) über verbindung gesendet wurden zurück. +Und kann so benutzt werden: + "Sende über an " oder + "wie viele Bytes von über an gesendet wurden" + +Die öffentliche Funktion Socket_Senden_An_Text mit den Parametern verbindung, daten und info vom Typ Socket, Text Referenz und AddressInfo, gibt eine Zahl zurück, macht: + Gib wie viele Bytes von daten über verbindung an info gesendet wurden zurück. +Und kann so benutzt werden: + "Sende über an " oder + "wie viele Bytes von über an gesendet wurden" + +Die öffentliche Funktion Socket_Empfangen_Von_Text mit den Parametern verbindung, max und client vom Typ Socket, Zahl und KlientenAddresse Referenz, gibt einen Text zurück, macht: + Gib die Bytes (das nächste maximal max Bytes große Packet aus verbindung von client) als Text zurück. +Und kann so benutzt werden: + "der nächste maximal Bytes große Text aus von ", + "dem nächsten maximal Bytes großen Text aus von " + +Die öffentliche Funktion Socket_Empfangen_Von_Ohne_Klient_Text mit den Parametern verbindung und max vom Typ Socket und Zahl, gibt einen Text zurück, macht: + Die KlientenAddresse client ist eine leere KlientenAddresse. + Gib die Bytes (das nächste maximal max Bytes große Packet aus verbindung von client) als Text zurück. +Und kann so benutzt werden: + "der nächste maximal Bytes große Text aus ", + "dem nächsten maximal Bytes großen Text aus " diff --git a/lib/stdlib/Duden/Texte.ddp b/lib/stdlib/Duden/Texte.ddp index 9a2cf031..69348cb5 100644 --- a/lib/stdlib/Duden/Texte.ddp +++ b/lib/stdlib/Duden/Texte.ddp @@ -955,4 +955,32 @@ Und kann so benutzt werden: "den Worten in ", "alle Worte in ", "allen Worten in ", - " in Worte unterteilt" \ No newline at end of file + " in Worte unterteilt" + +Die öffentliche Funktion Text_Zu_ByteListe mit dem Parameter t vom Typ Text Referenz, gibt eine Byte Liste zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "die Bytes von " oder + "den Bytes von " oder + "der Bytes von " + +Die öffentliche Funktion Text_Zu_ByteListe_Wert mit dem Parameter t vom Typ Text, gibt eine Byte Liste zurück, macht: + Gib die Bytes von t zurück. +Und kann so benutzt werden: + "die Bytes von " oder + "den Bytes von " oder + "der Bytes von " + +Die öffentliche Funktion ByteListe_Zu_Text mit dem Parameter b vom Typ Byte Listen Referenz, gibt einen Text zurück, +ist in "libddpstdlib.a" definiert +und kann so benutzt werden: + "die Bytes als Text" oder + "den Bytes als Text" oder + "der Bytes als Text" + +Die öffentliche Funktion ByteListe_Zu_Text_Wert mit dem Parameter b vom Typ Byte Liste, gibt einen Text zurück, macht: + Gib die Bytes b als Text zurück. +Und kann so benutzt werden: + "die Bytes als Text" oder + "den Bytes als Text" oder + "der Bytes als Text" \ No newline at end of file diff --git a/lib/stdlib/Duden/Uri.ddp b/lib/stdlib/Duden/Uri.ddp index 37c8e3e0..5028cde5 100644 --- a/lib/stdlib/Duden/Uri.ddp +++ b/lib/stdlib/Duden/Uri.ddp @@ -60,7 +60,7 @@ Die öffentliche Funktion Uri_Zu_Text mit dem Parameter uri vom Typ Uri, gibt ei Füge ':' an t an. [URN edge case] - Wenn (Host von uri) nicht leer ist oder '/' am Anfang von (Pfad von uri) steht, dann: + Wenn ((Host von uri) nicht leer ist oder '/' am Anfang von (Pfad von uri) steht) und (Schema von uri) nicht leer ist, dann: Füge "//" an t an. Wenn (Host von uri) nicht leer ist, dann: diff --git a/lib/stdlib/source/DDP/lists.c b/lib/stdlib/source/DDP/lists.c index d1c386d9..a05188ce 100644 --- a/lib/stdlib/source/DDP/lists.c +++ b/lib/stdlib/source/DDP/lists.c @@ -3,10 +3,12 @@ #include "DDP/utf8/utf8.h" #include -static void grow_if_needed(ddpgenericlistref list, ddpint elem_size) { - if (list->len == list->cap) { +#define DDP_MAX(a, b) ((a) > (b) ? (a) : (b)) + +static void grow_if_needed(ddpgenericlistref list, ddpint elem_size, ddpint n) { + if (list->len + n >= list->cap) { ddpint old_cap = list->cap; - list->cap = DDP_GROW_CAPACITY(list->cap); + list->cap = DDP_MAX(DDP_GROW_CAPACITY(list->cap), list->len + n); list->arr = ddp_reallocate(list->arr, old_cap * elem_size, list->cap * elem_size); } } @@ -20,7 +22,7 @@ static void claim_non_primitive(const ddpvtable *vtable, ddpgenericref elem, ddp void efficient_list_append(ddpgenericlistref list, ddpgenericref elem, ddpanyref any) { const ddpvtable *vtable = ddp_get_generic_vtable(any); - grow_if_needed(list, vtable->type_size); + grow_if_needed(list, vtable->type_size, 1); memcpy(&((uint8_t *)list->arr)[list->len * vtable->type_size], elem, vtable->type_size); list->len++; @@ -30,7 +32,7 @@ void efficient_list_append(ddpgenericlistref list, ddpgenericref elem, ddpanyref void efficient_list_prepend(ddpgenericlistref list, ddpgenericref elem, ddpanyref any) { const ddpvtable *vtable = ddp_get_generic_vtable(any); - grow_if_needed(list, vtable->type_size); + grow_if_needed(list, vtable->type_size, 1); memmove(&((uint8_t *)list->arr)[vtable->type_size], list->arr, list->len * vtable->type_size); memcpy(list->arr, elem, vtable->type_size); list->len++; @@ -38,6 +40,31 @@ void efficient_list_prepend(ddpgenericlistref list, ddpgenericref elem, ddpanyre claim_non_primitive(vtable, elem, any); } +void efficient_list_append_list(ddpgenericlistref list, ddpgenericlistref other, ddpanyref any) { + const ddpvtable *vtable = ddp_get_generic_vtable(any); + + grow_if_needed(list, vtable->type_size, other->len); + memcpy(&((uint8_t *)list->arr)[list->len * vtable->type_size], other->arr, vtable->type_size * other->len); + list->len += other->len; + + for (ddpint i = 0; i < other->len; i++) { + claim_non_primitive(vtable, &((uint8_t *)other->arr)[i * vtable->type_size], any); + } +} + +void efficient_list_prepend_list(ddpgenericlistref list, ddpgenericlistref other, ddpanyref any) { + const ddpvtable *vtable = ddp_get_generic_vtable(any); + + grow_if_needed(list, vtable->type_size, other->len); + memmove(&((uint8_t *)list->arr)[vtable->type_size * other->len], list->arr, list->len * vtable->type_size); + memcpy(list->arr, other->arr, vtable->type_size * other->len); + list->len += other->len; + + for (ddpint i = 0; i < other->len; i++) { + claim_non_primitive(vtable, &((uint8_t *)other->arr)[i * vtable->type_size], any); + } +} + #define CLAMP(index, len) ((index) < 0 ? 0 : ((index) >= (len) ? (len)-1 : (index))) // the range is inclusive [start, end] @@ -76,7 +103,7 @@ void efficient_list_insert(ddpgenericlistref list, ddpint index, ddpgenericref e const ddpvtable *vtable = ddp_get_generic_vtable(any); - grow_if_needed(list, vtable->type_size); + grow_if_needed(list, vtable->type_size, 1); memmove(&((uint8_t *)list->arr)[(index + 1) * vtable->type_size], &((uint8_t *)list->arr)[index * vtable->type_size], (list->len - index) * vtable->type_size); memcpy(&((uint8_t *)list->arr)[index * vtable->type_size], elem, vtable->type_size); list->len++; diff --git a/lib/stdlib/source/DDP/network.c b/lib/stdlib/source/DDP/network.c new file mode 100644 index 00000000..cceca9f6 --- /dev/null +++ b/lib/stdlib/source/DDP/network.c @@ -0,0 +1,257 @@ +#include "DDP/ddpmemory.h" +#include "DDP/ddptypes.h" +#include "DDP/ddpwindows.h" +#include "DDP/error.h" +#include +#include + +#ifdef DDPOS_WINDOWS +#include +#include +#else +#include +#include +#include +#include +#include +#endif // DDPOS_WINDOWS + +static_assert(sizeof(ddpchar) == sizeof(int), "sizeof(ddpchar) == sizeof(int)"); + +static_assert(AF_UNSPEC == 0, "AF_UNSPEC == 0"); +static_assert(AF_INET == 2, "AF_INET == 2"); +#ifdef DDPOS_WINDOWS +static_assert(AF_INET6 == 23, "AF_INET6 == 23"); +#else +static_assert(AF_INET6 == 10, "AF_INET6 == 10"); +#endif // DDPOS_WINDOWS + +static_assert(SOCK_STREAM == 1, "SOCK_STREAM == 1"); +static_assert(SOCK_DGRAM == 2, "SOCK_DGRAM == 2"); + +typedef struct ddpsockaddr_storage_padding { + ddpint padding1; + ddpint padding2; + ddpint padding3; + ddpint padding4; + ddpint padding5; + ddpint padding6; + ddpint padding7; + ddpint padding8; + ddpint padding9; + ddpint padding10; + ddpint padding11; + ddpint padding12; + ddpint padding13; + ddpint padding14; + ddpint padding15; + ddpint padding16; +} ddpsockaddr_storage_padding; + +typedef struct ddpsockaddr_storage { + ddpsockaddr_storage_padding storage; + socklen_t size; +} ddpsockaddr_storage; + +static_assert(sizeof(socklen_t) == sizeof(int), "sizeof(socklen_t) == sizeof(int)"); +static_assert(sizeof(struct sockaddr_storage) == sizeof(ddpsockaddr_storage_padding), "sizeof (struct sockaddr_storage) == sizeof(ddp_sockaddr_storage)"); + +typedef struct ddpsocket { + int fd; + int family; + int type; +} ddpsocket; + +#ifdef DDPOS_WINDOWS + +static void cleanup_winsock(void) { + WSACleanup(); +} + +ddpbool Init_Windows(void) { + WSADATA wsaData; + + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + ddp_error("WSAStartup failed", false); + return false; + } + + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 2) { + ddp_error("Version 2.2 of Winsock not available", false); + WSACleanup(); + return false; + } + + atexit(cleanup_winsock); + + return true; +} + +void Schließe_Socket_Windows(ddpsocket *sock) { + closesocket(sock->fd); +} + +#else + +void Schließe_Socket_Windows(ddpsocket *sock) {} + +ddpbool Init_Windows(void) { + return true; +} + +#endif // DDPOS_WINDOWS + +struct addrinfo *Lade_AddressInfo(int family, int type, const ddpstring *name, const ddpstring *service) { + int status; + struct addrinfo hints; + struct addrinfo *servinfo; // will point to the results + + memset(&hints, 0, sizeof hints); // make sure the struct is empty + hints.ai_family = family; // IPv4 or IPv6 + hints.ai_socktype = type; // TCP/UDP + hints.ai_flags = AI_PASSIVE; // fill in the ip in case of null + + if ((status = getaddrinfo(name->str, service->str, &hints, &servinfo)) != 0) { + ddp_error("getaddrinfo Fehler: %s", false, gai_strerror(status)); + return NULL; + } + + return servinfo; +} + +void AddressInfo_zu_Text(ddpstring *ret, const struct addrinfo *info) { + void *addr; + char ipstr[INET6_ADDRSTRLEN]; + + // get the pointer to the address itself, + // different fields in IPv4 and IPv6: + if (info->ai_family == AF_INET) { // IPv4 + struct sockaddr_in *ipv4 = (struct sockaddr_in *)info->ai_addr; + addr = &(ipv4->sin_addr); + } else { // IPv6 + struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)info->ai_addr; + addr = &(ipv6->sin6_addr); + } + + // convert the IP to a string and print it: + if (inet_ntop(info->ai_family, addr, ipstr, sizeof ipstr) == NULL) { + ddp_error("inet_ntop Fehler: ", true); + *ret = DDP_EMPTY_STRING; + return; + } + + ddp_string_from_constant(ret, ipstr); +} + +void Socket_Erstellen(ddpsocket *ret, int family, int type) { + int sock = socket(family, type, 0); + if (sock < 0) { + ddp_error("socket Fehler: ", true); + } + ret->fd = sock; + ret->family = family; + ret->type = type; +} + +void Socket_Binden(const ddpsocket *sock, struct addrinfo *info) { + for (struct addrinfo *p = info; p != NULL; p = p->ai_next) { + if (bind(sock->fd, info->ai_addr, info->ai_addrlen) < 0) { + ddp_error("bind Fehler: ", true); + } else { + break; + } + } +} + +void Socket_Verbinden(const ddpsocket *sock, struct addrinfo *info) { + for (struct addrinfo *p = info; p != NULL; p = p->ai_next) { + if (connect(sock->fd, info->ai_addr, info->ai_addrlen) < 0) { + ddp_error("connect Fehler: ", true); + } else { + break; + } + } +} + +void Socket_Zuhoeren(const ddpsocket *sock, ddpint backlog) { + if (listen(sock->fd, (int)backlog) < 0) { + ddp_error("listen Fehler: ", true); + } +} + +void Socket_Verbindung_Annehmen(ddpsocket *ret, const ddpsocket *sock, ddpsockaddr_storage *client_addr) { + client_addr->size = sizeof client_addr->storage; + int conn = accept(sock->fd, (struct sockaddr *)&client_addr->storage, &client_addr->size); + if (conn < 0) { + ddp_error("accept Fehler: ", true); + } + ret->fd = conn; + ret->family = ((struct sockaddr_storage *)client_addr)->ss_family; + ret->type = sock->type; +} + +ddpint Socket_Senden(const ddpsocket *sock, const ddpbytelistref data) { + ddpint result = 0; + while (result < data->len) { + int sent; + if ((sent = send(sock->fd, (const char *)&data->arr[result], data->len - result, 0)) < 0) { + ddp_error("send Fehler: ", true); + return result; + } + result += sent; + } + return result; +} + +void Socket_Empfangen(ddpbytelist *ret, ddpsocket *sock, const ddpint max) { + ddpbyte *buf = DDP_ALLOCATE(ddpbyte, max); + ddpint got = (ddpint)recv(sock->fd, (char *)buf, max, 0); + if (got < 0) { + *ret = DDP_EMPTY_LIST(ddpbytelist); + DDP_FREE_ARRAY(ddpbyte, buf, max); + ddp_error("recv Fehler: ", true); + return; + } + + if (got == 0) { + *ret = DDP_EMPTY_LIST(ddpbytelist); + DDP_FREE_ARRAY(ddpbyte, buf, max); + return; + } + + ret->cap = got; + ret->len = got; + ret->arr = ddp_reallocate(buf, max, ret->len); +} + +ddpint Socket_Senden_An_Klient(const ddpsocket *sock, const ddpbytelistref data, const ddpsockaddr_storage *client) { + ddpint sent = 0; + if ((sent = (ddpint)sendto(sock->fd, (const char *)data->arr, data->len, 0, (struct sockaddr *)&client->storage, client->size)) < 0) { + ddp_error("sendto Fehler: ", true); + } + + return sent; +} + +ddpint Socket_Senden_An(const ddpsocket *sock, const ddpbytelistref data, const struct addrinfo *info) { + ddpsockaddr_storage client; + client.size = info->ai_addrlen; + memcpy(&client.storage, info->ai_addr, info->ai_addrlen); + return Socket_Senden_An_Klient(sock, data, &client); +} + +void Socket_Empfangen_Von(ddpbytelist *ret, ddpsocket *sock, ddpint max, ddpsockaddr_storage *client_addr) { + ddpbyte *buf = DDP_ALLOCATE(ddpbyte, max); + client_addr->size = sizeof(client_addr->storage); + ddpint got = (ddpint)recvfrom(sock->fd, (char *)buf, max, 0, (struct sockaddr *)&client_addr->storage, &client_addr->size); + if (got < 0) { + *ret = DDP_EMPTY_LIST(ddpbytelist); + DDP_FREE_ARRAY(char, buf, max); + ddp_error("recvfrom Fehler: ", true); + return; + } + ret->cap = got; + ret->len = got; + ret->arr = ddp_reallocate(buf, max, ret->len); +} diff --git a/lib/stdlib/source/DDP/strings.c b/lib/stdlib/source/DDP/strings.c new file mode 100644 index 00000000..07e79bfb --- /dev/null +++ b/lib/stdlib/source/DDP/strings.c @@ -0,0 +1,26 @@ +#include "DDP/ddpmemory.h" +#include "DDP/ddptypes.h" +#include + +void Text_Zu_ByteListe(ddpbytelist *ret, ddpstringref t) { + if (ddp_string_empty(t)) { + *ret = DDP_EMPTY_LIST(ddpbytelist); + return; + } + ret->cap = t->cap - 1; + ret->len = ret->cap; + ret->arr = DDP_ALLOCATE(ddpbyte, ret->len); + memcpy(ret->arr, t->str, ret->len); +} + +void ByteListe_Zu_Text(ddpstring *ret, ddpbytelistref b) { + if (b->len == 0) { + *ret = DDP_EMPTY_STRING; + return; + } + + ret->cap = b->len + 1; + ret->str = DDP_ALLOCATE(char, ret->cap); + memcpy(ret->str, b->arr, b->len); + ret->str[b->len] = '\0'; +} diff --git a/src/ddperror/codes.go b/src/ddperror/codes.go index 6f481c5c..266ed89c 100644 --- a/src/ddperror/codes.go +++ b/src/ddperror/codes.go @@ -58,6 +58,7 @@ const ( SEM_ERROR_INSTANTIATING_GENERIC_FUNCTION // an error occured while instantiating a generic function SEM_CANNOT_INSTANTIATE_NON_GENERIC_TYPE // a non-generic type was given with type parameters SEM_UNABLE_TO_UNIFY_FIELD_TYPES // for a generic struct alias not all typeparamters could be unified + SEM_CONSTANT_IS_NOT_ASSIGNABLE // for a generic struct alias not all typeparamters could be unified ) // type error codes diff --git a/src/parser/expressions.go b/src/parser/expressions.go index 01033af9..9758452c 100644 --- a/src/parser/expressions.go +++ b/src/parser/expressions.go @@ -779,6 +779,11 @@ func (p *parser) assigneable() ast.Assigneable { ident := &ast.Ident{ Literal: *p.previous(), } + decl, ok, _ := p.scope().LookupDecl(ident.Literal.Literal) + if _, isVar := decl.(*ast.VarDecl); ok && !isVar { + p.err(ddperror.SEM_CONSTANT_IS_NOT_ASSIGNABLE, p.previous().Range, "Eine konstante kann nicht in als Referenz verwendet werden") + } + var ass ast.Assigneable = ident for p.matchAny(token.ALS) { diff --git a/tests/testdata/stdlib/Listen/Listen.ddp b/tests/testdata/stdlib/Listen/Listen.ddp index 97df44f7..abd15985 100644 --- a/tests/testdata/stdlib/Listen/Listen.ddp +++ b/tests/testdata/stdlib/Listen/Listen.ddp @@ -257,4 +257,12 @@ Schreibe (jede Kommazahl aus (einer Liste, die aus 1,0, 2,0, 4,0 besteht) mit (e Schreibe (jede Zahl aus (einer Liste, die aus 1, 2, 3 besteht) mit (einer Liste, die aus 4, 5, 6 besteht) dividiert) auf eine Zeile. Schreibe (jede Kommazahl aus (einer Liste, die aus 1,0, 2,0, 3,0 besteht) mit (einer Liste, die aus 0,2, 0,2, 0,2 besteht) dividiert) auf eine Zeile. Schreibe (jeden Text aus (einer Liste, die aus "a", "b" besteht) mit (einer Liste, die aus "c", "d" besteht) verkettet) auf eine Zeile. -Schreibe (alle Texte in (einer Liste, die aus "a", "b", "" besteht) aneinandergehängt) auf eine Zeile. \ No newline at end of file +Schreibe (alle Texte in (einer Liste, die aus "a", "b", "" besteht) aneinandergehängt) auf eine Zeile. + +[ append_list ] +Die Text Liste zahlen ist eine Liste, die aus "1", "2", "3" besteht. +Schreibe zahlen auf eine Zeile. +Füge (eine Liste, die aus "4", "5", "6" besteht) an zahlen an. +Schreibe zahlen auf eine Zeile. +Stelle (eine Liste, die aus "7", "8", "9" besteht) vor zahlen. +Schreibe zahlen auf eine Zeile. \ No newline at end of file diff --git a/tests/testdata/stdlib/Listen/expected.txt b/tests/testdata/stdlib/Listen/expected.txt index 92e53ed3..41a1a4ad 100644 --- a/tests/testdata/stdlib/Listen/expected.txt +++ b/tests/testdata/stdlib/Listen/expected.txt @@ -121,3 +121,6 @@ hallo 5, 10, 15 ac, bd ab +1, 2, 3 +1, 2, 3, 4, 5, 6 +7, 8, 9, 1, 2, 3, 4, 5, 6 diff --git a/tests/testdata/stdlib/Texte/Texte.ddp b/tests/testdata/stdlib/Texte/Texte.ddp index 614a2243..b751d37b 100644 --- a/tests/testdata/stdlib/Texte/Texte.ddp +++ b/tests/testdata/stdlib/Texte/Texte.ddp @@ -295,4 +295,10 @@ Schreibe ("\rHallo \r\nWelt" anhand der Spaltmenge " \r\n" gespalten) auf eine Z Schreibe '\n'. [Text_Worte] -Schreibe (alle Worte in " Hallo du schöne Welt!") auf eine Zeile. \ No newline at end of file +Schreibe (alle Worte in " Hallo du schöne Welt!") auf eine Zeile. + +Schreibe '\n'. + +[ Text <-> Byte Liste ] +Schreibe (die Bytes von "Hallo") auf eine Zeile. +Schreibe (die Bytes (eine Liste, die aus 72 als Byte, 97 als Byte, 108 als Byte, 108 als Byte, 111 als Byte besteht) als Text) auf eine Zeile. \ No newline at end of file diff --git a/tests/testdata/stdlib/Texte/expected.txt b/tests/testdata/stdlib/Texte/expected.txt index 2b745a02..964e5043 100644 --- a/tests/testdata/stdlib/Texte/expected.txt +++ b/tests/testdata/stdlib/Texte/expected.txt @@ -172,3 +172,6 @@ Hallo, Welt Hallo, Welt Hallo, du, schöne, Welt! + +72, 97, 108, 108, 111 +Hallo diff --git a/tests/testdata/stdlib/Uri/Uri.ddp b/tests/testdata/stdlib/Uri/Uri.ddp index a056aca2..e10894ba 100644 --- a/tests/testdata/stdlib/Uri/Uri.ddp +++ b/tests/testdata/stdlib/Uri/Uri.ddp @@ -17,6 +17,7 @@ Und kann so benutzt werden: "Schreibe " Schreibe ("" als Uri). +Schreibe ("/index.html?a=hi&b=bye#anchor" als Uri). Schreibe ("https://user:password@example.com:8080/index.html?a=hi&b=bye#anchor" als Uri). Schreibe ("https://de.wikipedia.org/wiki/Uniform_Resource_Identifier" als Uri). Schreibe ("https://ddp.bafto.dev/Spielplatz/?nolines&readonly" als Uri). diff --git a/tests/testdata/stdlib/Uri/expected.txt b/tests/testdata/stdlib/Uri/expected.txt index b455511f..cc44545d 100644 --- a/tests/testdata/stdlib/Uri/expected.txt +++ b/tests/testdata/stdlib/Uri/expected.txt @@ -1,4 +1,5 @@ | | | | | | | +/index.html?a=hi&b=bye#anchor | | | | | /index.html | a=hi&b=bye | anchor https://user:password@example.com:8080/index.html?a=hi&b=bye#anchor | https | user:password | example.com | 8080 | /index.html | a=hi&b=bye | anchor https://de.wikipedia.org/wiki/Uniform_Resource_Identifier | https | | de.wikipedia.org | | /wiki/Uniform_Resource_Identifier | | https://ddp.bafto.dev/Spielplatz/?nolines&readonly | https | | ddp.bafto.dev | | /Spielplatz/ | nolines&readonly |