Python in Objective-C
Verfasst: Sonntag 16. Januar 2011, 11:47
Verrückte Idee: Wie wäre es, einen kleinen in Objective-C geschriebenen Python-Interpreter zu haben, der z.B. unter iOS funktioniert?
Hat jemand Lust, so etwas zu entwickeln?
Um eine einfache Interaktion mit Objective-C und den Apple-Bibliotheken hinzubekommen, wäre ich zu folgenden Zugeständnissen bereit:
1) Damit Methoden wie `addObject:forKey:` nicht als `self.addObject_forKey_(value, key)` geschrieben werden müssen, wäre ich bereit die Python-Syntax zu ändern und z.B. `self.(addObject:value forKey:key)` zuzulassen.
Die Grammatik muss dafür nur minimal geändert werden:
2) Datentypen sollten die Foundation-Klassen sein, also z.B. `NSMutableDictionary` für `dict` oder `NSArray` für `tuple`. Für Zahlen ist das ineffizient, aber ich glaube, man spart sich Konvertierungen, wenn man Objective-C-Methoden aufrufen will. Außerdem kann man so wahrscheinlich auch Zugriff auf alle existierenden Methoden gewähren. Möglicherweise ist es sinnvoll, wie MacRuby vorzugehen, und jeweils von den Foundation-Klassen zu erben.
3) Objekte müssen explizit freigegeben werden, d.h. es gibt eine `release`-Methode und in jede eigenen Klasse muss man `dealloc` implementieren.
Mein Python-Parser lässt sich relativ direkt in Objective-C überführen. Es müssen etwa 60 AST-Klassen definiert und etwa 100 Parser-Methoden portiert werden. Das ist Fleißarbeit.
Mein Parser ist leider sehr schlecht, was Fehlermeldungen angeht. Er sagt einfach, es ist etwas falsch. Minimal notwendig wäre, die Zeilennummer zu kennen. Ich habe eine `Token`-Klasse eingeführt, die die Position des Tokens im Quelltext kennt und die man so nach einer Zeilennummer fragen könnte. Vielleicht reicht das.
Hier ist ein Beispiel, wie Parser-Methoden aussehen könnten:
Ich bin bei den Klassenmethoden von dem Pattern, "Class classWith..." abgewichen und nutze einfach nur "Class with...", das möge man mir verzeihen. Auch wäre es wahrscheinlich üblicher, `parseOrTest` und `parseTestlistOptAsTuple` zu benutzen.
Die meiste Arbeit wäre, das Laufzeitsystem zu entwickeln. Insbesondere ist mir hier noch nicht klar, wie man die Speicherverwaltung in den Griff bekommt. Und wie man mit z.B. Klassen aus dem UIKit interagieren kann.
Bei der Semantik würde ich mich munter aus Python 1.x bis 3.x bedienen. So reicht es IMHO, einfache Vererbung zu haben und keine Unterklassen von vordefinierten Typen bilden zu können. Strings sollten aber wie `NSString` Unicode-Zeichen enthalten können und ein `bytes`-Typ würde prima auf `NSData` abbildbar sein. Standardfunktionen wie `locals` oder `globals` würde ich vorschlagen wegzulassen und auch von Generatoren würde ich mich zunächst verabschieden wollen.
Ach ja, da Objective-C 2.0 Blöcke kennt und diese vermehrt Einzug in die Klassenbibliothek halten, wäre es überlegenswert, dafür auch eine Syntax zu haben. Vielleicht so:
Solange immer ein `|` hinter `[` folgt, kann man diesen Ausdruck von einer Liste unterscheiden. Das würde ebenso mit `{}` funktionieren. Oder man macht es wie Objective-C, wo ein `^` den Block einleitet. Das Zeichen wird in Python nicht verwendet:
Grammatik wäre dann:
Gibt es weitere Anforderungen? Wünsche? Kommentare?
Stefan
Hat jemand Lust, so etwas zu entwickeln?
Um eine einfache Interaktion mit Objective-C und den Apple-Bibliotheken hinzubekommen, wäre ich zu folgenden Zugeständnissen bereit:
1) Damit Methoden wie `addObject:forKey:` nicht als `self.addObject_forKey_(value, key)` geschrieben werden müssen, wäre ich bereit die Python-Syntax zu ändern und z.B. `self.(addObject:value forKey:key)` zuzulassen.
Die Grammatik muss dafür nur minimal geändert werden:
Code: Alles auswählen
trailer: '(' [testlist] ')' | '[' subscript ']' | '.' (NAME | message_send)
message_send: '(' keyword_expr {keyword_expr} ')'
keyword_expr: NAME ':' test [',']
3) Objekte müssen explizit freigegeben werden, d.h. es gibt eine `release`-Methode und in jede eigenen Klasse muss man `dealloc` implementieren.
Mein Python-Parser lässt sich relativ direkt in Objective-C überführen. Es müssen etwa 60 AST-Klassen definiert und etwa 100 Parser-Methoden portiert werden. Das ist Fleißarbeit.
Mein Parser ist leider sehr schlecht, was Fehlermeldungen angeht. Er sagt einfach, es ist etwas falsch. Minimal notwendig wäre, die Zeilennummer zu kennen. Ich habe eine `Token`-Klasse eingeführt, die die Position des Tokens im Quelltext kennt und die man so nach einer Zeilennummer fragen könnte. Vielleicht reicht das.
Hier ist ein Beispiel, wie Parser-Methoden aussehen könnten:
Code: Alles auswählen
@implementation Parser
- (Expr *)parse_or_test {
Expr *expr = [self parse_and_test];
while ([self at:@"or"]) {
expr = [OrExpr withLeftExpr:expr rightExpr:[self parse_and_test]];
}
return expr;
}
- (Expr *)parse_testlist_opt_as_tuple {
if ([self has_test]) {
Expr *expr = [self parse_test];
if (![self at:@","]) {
return expr;
}
NSMutableArray *exprs = [NSMutableArray arrayWithObject:expr];
if (![self has_test]) {
return [TupleExpr withExprs:exprs];
}
[exprs addObjectsFromArray:[self parse_testlist_opt]];
return [TupleExpr withExprs:exprs]
}
}
@end
Ich bin bei den Klassenmethoden von dem Pattern, "Class classWith..." abgewichen und nutze einfach nur "Class with...", das möge man mir verzeihen. Auch wäre es wahrscheinlich üblicher, `parseOrTest` und `parseTestlistOptAsTuple` zu benutzen.
Die meiste Arbeit wäre, das Laufzeitsystem zu entwickeln. Insbesondere ist mir hier noch nicht klar, wie man die Speicherverwaltung in den Griff bekommt. Und wie man mit z.B. Klassen aus dem UIKit interagieren kann.
Bei der Semantik würde ich mich munter aus Python 1.x bis 3.x bedienen. So reicht es IMHO, einfache Vererbung zu haben und keine Unterklassen von vordefinierten Typen bilden zu können. Strings sollten aber wie `NSString` Unicode-Zeichen enthalten können und ein `bytes`-Typ würde prima auf `NSData` abbildbar sein. Standardfunktionen wie `locals` oder `globals` würde ich vorschlagen wegzulassen und auch von Generatoren würde ich mich zunächst verabschieden wollen.
Ach ja, da Objective-C 2.0 Blöcke kennt und diese vermehrt Einzug in die Klassenbibliothek halten, wäre es überlegenswert, dafür auch eine Syntax zu haben. Vielleicht so:
Code: Alles auswählen
regexp.(enumerateMatchesInString:s usingBlock:[|match, flags, stop|
...
])
Code: Alles auswählen
regexp.(enumerateMatchesInString:s usingBlock:^(match, flags, stop):
...
)
Code: Alles auswählen
test: ... | block
block: '^' [params] ':' suite
Gibt es weitere Anforderungen? Wünsche? Kommentare?
Stefan