smalldragon - a simple Transpiler to C

Gast #6744414
Lesenswert?

Hallo Forum,

ich wuerde euch gerne kurz das smalldragon-Projekt vorstellen.

smalldragon ist eine einfache statisch typisierte Programmiersprache,
die nach C transpiliert werden kann.

Beispiel-Code:
1
//struct-field reordering will get applied to improve structure packing
2
struct Example {
3
    @private char a; //only accessible in this file
4
    uint32 b;
5
    char c;
6
    uint32 d;
7
}
8
fn main() ~> int {
9
    
10
    x = 2; //lokale variablen typinferenz
11

12
    if 0 < x < 3 { //comparison-operator-chaining
13
        x++;
14
    }
15

16
    uint8 y = 3; //fixed-width integer types
17

18
    for i in 0 .. x { //ranges
19
        y = subr((m)->m+1, x); //basic lambda support
20
    }
21
    return 0;
22
}
23
@deprecated //a few basic annotations
24
fn subr( ((int)->int) f, int k) -> int {
25
    return f(k);
26
}

Das Projekt ist nicht als Ersatz fuer C/C++ oder so gedacht,
sondern als Ergaenzung um schnell kleine Software-Module erstellen
zu koennen, und dennoch die Vorteile von C zu nutzen bezueglich
der Performance, Support fuer viele Architekturen, etc..

Bestimmte Features von C werden in smalldragon vorraussichtlich nicht
verfuegbar sein, wie etwa pointer-arithmetik, preprocessor, 
inline-assembly,
etc...

Ueber euer Feedback wuerde ich mich freuen :)

Projekt-Website: https://smalldragon.org/
Github: https://github.com/pointbazaar/smalldragon

Gruss, Alexander
#6744436
Lesenswert?

Andras H. schrieb:
> Ehrlich? Ist es nicht egal ob man

Die Grammatik von C ist kein genialer Wurf gewesen. Wenn jemand eine 
neue definiert, kann ich das nachvollziehen. Allerdings würde ich 
empfehlen, auch Variablendeklarationen mit einem Keyword einzuleiten, 
statt mit einem Typ. Dann sind Typnamen normale Identifier. Mit den 
später nachgereichten Typedefs ging in C der Spass los.
#6744479
Lesenswert?

Naja, mir gefällt reines C ehrlich gesagt besser.

Die Funktionsschreibweise mit fn ~> (wie in rust / go) ist etwas 
ungewohnt.

Bei der lokale variablen typinferenz habe ich etwas bedenken, weil man 
die Variable überhaupt nicht deklarieren muss. Wie ist dort der scope?
By python kann man schnell mal in sowas rein laufen:
1
#!python
2
def x(name):
3
  for name in ["test"]:
4
    pass
5
  return name # ist immer "test"
Kann einem hier sowas auch passieren? Sind die Variablen implizit 
Funktions oder Block scope? Hat die Sprache überhaupt blöcke und block 
scopes? Und hier: 
https://smalldragon.org/html/local-var-typeinference.html ist das 
wirklich "runtime cost" oder ist da "compiletime cost" gemeint?

Ein paar Beispiele enthalten while(true){}, aber anderenorts sind keine 
Klammern. Wäre while true {} nicht konsistenter? Oder ist das nur ein 
Dokumentationsartefakt?

Dann zu den Generics. Für mich sind das eher typ templates. Unter einem 
Generic würde ich eher sowas verstehen:
1
struct something_generic {
2
  int a;
3
  void* x;
4
  int b;
5
}
6

7
struct something_int {
8
  int a;
9
  int* x;
10
  int b;
11
}

Der Unterschied ist, something_int und something_generic sind gleich 
gross. Man kann struct something_int nach struct something_generic und 
zurück casten, wie in Java. Wäre x hier kein pointer, ist das nicht der 
fall. Das ist dann wie bei C++ templates.

Ich bin mir auch nicht sicher, wie sinnvoll es ist, die Funktionen als 
"Subroutinen" zu bezeichnen. Haben diese irgendwelche speziellen 
Semantiken? Kehren sie nicht immer zurück wie in ASM, oder haben sie 
keinen Stack für die Argumente wie Fortran, oder gibt es andere 
Besonderheiten bezüglich des control flows (können sie yieldn wie ein 
Generator, oder zwischeneinander switchen wie coroutinen?). Eine 
Funktion ist auch eine Subroutine, aber ist da irgend was was diese 
"Subroutinen" hier von Funktionen unterscheidet?

Der nächste Punkt wäre Modularität und Interfaces. Ich bin ein grosser 
Fan von Modularität und Interfaces. In C, jede Kompillationsunit ist 
unabhängig kompilierbar, und die Headerfiles stellen ein Interface dar, 
um alles zusammenzusetzen. Ist sowas hier noch machbar.

Das nächste wäre compile time reflection  introspection  Macros. Gibt 
es hier irgendws?

Und dann zum Schluss, naja, wie immer sind vor allem die Dinge nicht 
drin, die für mich eigentlich speziell interessant wären. Dinge die ich 
unter anderem gerne in meinen Programmen verwende sind:
 * Linktime linked lists, also globale unveränderbare Listen über 
mehrere Dateien verteilt, sowie optionale Implementierungen. Solches 
Zeugs: 
https://www.mikrocontroller.net/articles/C_Linkerhacks_%2B_Modularisierung
 * Interfaces. In C, im Grunde einfach ein Structtyp mit 
Funktionspointern, und ein Structtype einen Pointer darauf hat. Das 
Implementieren des Interface ist dann einfach, letzteres bei einem 
anderen Struct als member zu haben, und beim Instantiieren den Pointer 
auf die Implementation (das struct objekt mit den Funktionen drinn), zu 
setzen.
 * Mehr STL zeugs. Hashmaps, Dynamische Arrays, (Doubly) Linked Listen, 
eventuell ein generisches Listeninterface für alle. Eventuell was für 
reference counting, wie in C++ die smart pointer. Was man halt früher 
oder später so braucht.

Was auch toll wäre, ist aber eher Wunschdenken:
 * Exception handling. Es gibt ja viele Methoden, throw in C++, Optional 
/ tuple zeug in anderen Sprachen (also per typisiertem sentinel im 
Rückgabewert). Einfach was besseres als setjump...
 * Da kommt mir gerade noch der Gedanke, Optional, tuple zeug, 
typisierte Sentinelwerte. Sowas wäre schon praktisch.
 * async / await & Generatoren fände ich echt praktisch, aber leider 
schwierig umzusetzen. Aber Allgemein, primitive für event loops, warten 
auf input (eventuell bytes von Files, anderes Zeugs von anderen 
Programmteilen (pipes), etc.), managen von callbacks, solches zeugs, 
sind immer sehr nützlich. Leider aber auch sehr, sehr schwer nicht 
invasiv und gut umzusetzen.
Gast #6744753
Lesenswert?

Daniel A. schrieb:
> Oh, ich habe gerade gesehen, mit -> und ~> hast du eine Unterscheidung
> zwischen Idempotenten (ohne Seiteneffekte) und normalen Funktionen (mit
> Seiteneffekten).
> Das Finde ich gut.

Der Unterschied zwischen „~>“ und „->“ ist beim überfliegen je nach Font 
viel zu klein, imo. Da fänd ich ein extra Keyword besser (meinetwegen 
„sub“ für Nebeneffekte und „fn“ für reine Funktionen?).

Ich lese die Doku so, dass die Typinferenz zur Laufzeit geschieht? Das 
wäre zumindest unituitiv, sofern da keine Variant-Konstrukte im Spiel 
sind.

Rückgabetypen nach den Namen, aber Variablentypen vor den Namen ist imo 
etwas inkonsistent. Zumal Variablentypen hinter den Namen eine deutlich 
sauberere Syntax für Inferenz ermöglicht.

Lambdas in C … Ein Traum ^^

Die Sprache hätte für mich aktuell allerdings wohl nicht genug „selling 
points“ um sie statt C zu benutzen und anderen Alternativen vorzuziehen.

Aber wenn ich das Projekt richtig verstehe, ist der Fokus aber auch gar 
nicht, die komplette Software in der Sprache zu schreiben. Dann wäre 
etwas Doku, wie man das Resultat dann in C/C++ einbindet wohl hilfreich.
Gast #6744760
Lesenswert?

Ach ja: Gibt es überhaupt Arrays in irgendeiner Form? Braucht man ja 
hin- und wieder mal. In der Standardbibliothek gibt es auf jeden Fall 
Funktionen, die welche verarbeiten, aber nirgendwo was, wie man sie 
erstellt oder deklariert.
Moderator #6744776
Lesenswert?

Endlich binden die bitweisen Operatoren &, ^ und | stärker als die
Vergleichsoperatoren, so wie es sein soll.

Ein paar Probleme gibt es noch mit Array-Überläufen bei langen
Variablen- und Typnamen, aber darauf hast du ja teilweise in Kommentaren
schon hingewiesen und wirst das sicher noch beheben.
#6745230
Lesenswert?

Daniel A. schrieb:
> Oh, ich habe gerade gesehen, mit -> und ~> hast du eine Unterscheidung
> zwischen Idempotenten (ohne Seiteneffekte) und normalen Funktionen (mit
> Seiteneffekten).
> Das Finde ich gut.
>
> Und wie hast du eigentlich das halting Problem mit @halts gelöst?

Hallo Daniel,

Vielen Dank fuer dein Feedback :)
@halts ist bei mir eine Annotation, die hier (vielleicht zu kurz) 
dokumentiert ist:
https://smalldragon.org/html/annotations.html

Natuerlich kann man nicht fuer jede Funktion entscheiden, ob sie 
terminiert
oder nicht.

Man kann @halts aber benutzen um einige wenige funktionen zu
annotieren, bei denen es sehr leicht ist zu zeigen, dass sie 
terminieren.
So leicht, dass das sogar der Transpiler uebernehmen kann.

Wenn smalldragon dann nicht zeigen kann, dass es terminiert, gibt's
ne kleine Fehlermeldung.
#6745295
Lesenswert?

Jemand schrieb:
> Ach ja: Gibt es überhaupt Arrays in irgendeiner Form? Braucht man ja
> hin- und wieder mal. In der Standardbibliothek gibt es auf jeden Fall
> Funktionen, die welche verarbeiten, aber nirgendwo was, wie man sie
> erstellt oder deklariert.

Hallo,

Arrays gibt es konzeptionell schon, dynamisch alloziert mit malloc.
1
 
2
[char] arr = malloc(30);
3
arr[4] = 'k';
ist ein Beispiel.
In den Ordnern stdlib/ bzw. examples/ sollten sich weitere finden :)
Allerdings ist das momentan eher ein Kompromiss,
da ich das Konzept von sizeof noch nicht uebertragen habe.
Man muss sozusagen wissen, wie gross der datentyp ist, von dem man ein
Array allozieren will.

Gruss
#6745302
Lesenswert?

Jemand schrieb:
> Daniel A. schrieb:
>> Oh, ich habe gerade gesehen, mit -> und ~> hast du eine Unterscheidung
>> zwischen Idempotenten (ohne Seiteneffekte) und normalen Funktionen (mit
>> Seiteneffekten).
>> Das Finde ich gut.
>
> Der Unterschied zwischen „~>“ und „->“ ist beim überfliegen je nach Font
> viel zu klein, imo. Da fänd ich ein extra Keyword besser (meinetwegen
> „sub“ für Nebeneffekte und „fn“ für reine Funktionen?).
>
> Ich lese die Doku so, dass die Typinferenz zur Laufzeit geschieht? Das
> wäre zumindest unituitiv, sofern da keine Variant-Konstrukte im Spiel
> sind.
>
> Rückgabetypen nach den Namen, aber Variablentypen vor den Namen ist imo
> etwas inkonsistent. Zumal Variablentypen hinter den Namen eine deutlich
> sauberere Syntax für Inferenz ermöglicht.
>
> Lambdas in C … Ein Traum ^^
>
> Die Sprache hätte für mich aktuell allerdings wohl nicht genug „selling
> points“ um sie statt C zu benutzen und anderen Alternativen vorzuziehen.
>
> Aber wenn ich das Projekt richtig verstehe, ist der Fokus aber auch gar
> nicht, die komplette Software in der Sprache zu schreiben. Dann wäre
> etwas Doku, wie man das Resultat dann in C/C++ einbindet wohl hilfreich.

Hallo,

den Unterschied von "->" zu "~>" beim Lesen ist etwas klein, da hast du 
Recht.
Das mit dem extra Keyword finde ich ist eine gute Idee.

Die Typinferenz passiert nicht zur Laufzeit, das war etwas ungluecklich
formuliert. Habe es umformuliert.

Du hast Recht, dass
1
 
2
uint x = 3;
3
fn main () ~> int {}
den Typ mit dem Bezeichner jeweils andersherum haben.
Das ist inkonsistent, allerdings habe ich mich da
bei den Variablen erstmal fuer die gaengige Konvention enschieden.

Wie meinst du, dass
>Zumal Variablentypen hinter den Namen eine deutlich
> sauberere Syntax für Inferenz ermöglicht.
?

Ja, genau, es ist dafuer gedacht dass man es alongside C
bzw auch einmalig verwenden kann.

Wenn man kurz etwas aufschreiben will, oder fuer eine
implementierung besonders viel mit Funktionspointern arbeitet,
dann kann man dafuer smalldragon verwenden,
einen C Code transpilieren, das ganze durch astyle jagen oder
per IDE so formatieren wie man will und dann einfach
nur noch mit dem C Code weitermachen, den man dann
verfeinern und optimieren kann.

Bzgl. der Beispiele hast du Recht, es sollte eine Anleitung geben,
wie man es zusammen mit C verwendet.


Danke fuer dein Feedback :)
#6750526
Lesenswert?

Hallo Alexander,

was genau ist deine Intention, SmallDragon zu
entwickeln/zu verwenden? Eine abstrahiertere
Sprache als C verwenden, um trotzdem andere
C-Libs leicht anbinden zu können? Performance-
Vorteile durch Benutzung etablierter C-Compiler?

Dazu habe ich auf den Webseiten nichts gefunden.

merciless
#6750886
Lesenswert?

Dirk K. schrieb:
> Hallo Alexander,
>
> was genau ist deine Intention, SmallDragon zu
> entwickeln/zu verwenden? Eine abstrahiertere
> Sprache als C verwenden, um trotzdem andere
> C-Libs leicht anbinden zu können? Performance-
> Vorteile durch Benutzung etablierter C-Compiler?
>
> Dazu habe ich auf den Webseiten nichts gefunden.
>
> merciless

Hallo Dirk,

beide deine Punkte sind korrekt. ich will eine (fuer C Programmierer)
leicht verstaendliche aber abstrahiertere Programmiersprache bieten,
wo man sowas wie
- Lambdas,
- Lokale-Variablen Typinferenz,
- Generics(spaeter),
- try-catch Exception Handling
...
einfach verwenden kann, und immer weiss, was im Hintergrund passiert.

Momentan kann man die generierten C Sources dazu ja einfach einsehen.
z.b. try-catch verwendet einfach <setjmp.h> und der jmp_buf wird
als pointer weitergereicht.

Die Performance-Vorteile bei Verwendung etablierter C-Compiler
sind natuerlich beachtlich zur Alternative, etwa ein eigenes
Backend fuer x86 zu schreiben.

smalldragon soll leicht in existierende C-Projekte einzubinden sein,
und es soll auch einfach sein, C-Code in ein smalldragon Projekt 
einzubinden.

Es ist nicht stabil und hat bestimmt viele Bugs, aber wenn man die C 
Sources
einmal generiert hat, braucht man die smalldragon Sources ja auch nicht 
mehr ^^.

Allgemeine Ziele sowie Design-Entscheidungen sind hier zu finden:
https://smalldragon.org/html/project-goals.html

Allerdings wird diese Seite auch nicht jede Frage beantworten koennen :)
Daher immer gerne Fragen/Kritik.

Gruss
#6752256
Lesenswert?

Dirk K. schrieb:
> Alexander H. schrieb:
>> aber wenn man die C
>> Sources
>> einmal generiert hat, braucht man die smalldragon Sources ja auch nicht
>> mehr ^^.
> Du benutzt SmallDragon nur einmalig, um C-Sourcen
> zu generieren? Und die Pflege erfolgt dann in den
> C-Sourcen?
>
> merciless

Hi Dirk,
so kann man es benutzen. Ich habe darauf geachtet dass die generierten
C Sources noch lesbar sind, die namen von variablen usw. werden 1:1 
uebernommen.
Wenn man einen anderen Style/Indentation haben will, kann man es ja noch 
durch astyle jagen :). Mit dem -h Flag kann man auch entsprechende 
Header generieren.

Ich habe es selbst nicht so benutzt, weil ich momentan eher an 
smalldragon
arbeite, anstatt an Projekten mit smalldragon (beides nebenher waere zu 
viel fuer mich).

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren