Syntax
Die Syntax der Spezifikationssprache von Meson wurde so einfach wie möglich gehalten. Sie ist stark typisiert, sodass kein Objekt unter der Haube in ein anderes konvertiert wird. Variablen haben keinen sichtbaren Typ, was Meson dynamisch typisiert (auch bekannt als Duck-Typisierung) macht.
Die Hauptbausteine der Sprache sind Variablen, Zahlen, Booleans, Strings, Arrays, Funktionsaufrufe, Methodenaufrufe, if-Anweisungen und includes.
Normalerweise nimmt eine Meson-Anweisung nur eine Zeile ein. Es gibt keine Möglichkeit, mehrere Anweisungen in einer Zeile zu haben, wie z. B. in C. Funktions- und Methodenaufrufe können über mehrere Zeilen aufgeteilt werden. Meson erkennt diesen Fall automatisch und macht das Richtige.
In anderen Fällen können Sie mit (hinzugefügt 0.50) mehrzeilige Anweisungen erhalten, indem Sie die Zeile mit einem \ beenden. Abgesehen von Zeilenumbrüchen hat Leerraum keine syntaktische Bedeutung.
Variablen
Variablen in Meson funktionieren wie in anderen High-Level-Programmiersprachen. Eine Variable kann einen Wert eines beliebigen Typs enthalten, z. B. eine Ganzzahl oder einen String. Variablen müssen nicht vordeklariert werden; Sie können ihnen einfach Werte zuweisen, und sie erscheinen. So würden Sie Werten für zwei verschiedene Variablen zuweisen.
var1 = 'hello'
var2 = 102
Ein wichtiger Unterschied in der Funktionsweise von Variablen in Meson ist, dass alle Objekte unveränderlich sind. Wenn Sie eine Operation sehen, die wie eine Mutation aussieht, wird tatsächlich ein neues Objekt erstellt und dem Namen zugewiesen. Dies unterscheidet sich von der Funktionsweise von Python bei Objekten, ist aber ähnlich wie z. B. Python-Strings.
var1 = [1, 2, 3]
var2 = var1
var2 += [4]
# var2 is now [1, 2, 3, 4]
# var1 is still [1, 2, 3]
Zahlen
Meson unterstützt nur Ganzzahlen. Sie werden einfach durch Ausschreiben deklariert. Grundlegende arithmetische Operationen werden unterstützt.
x = 1 + 2
y = 3 * 4
d = 5 % 3 # Yields 2.
Hexadezimale Literale werden seit Version 0.45.0 unterstützt.
int_255 = 0xFF
Oktale und binäre Literale werden seit Version 0.47.0 unterstützt.
int_493 = 0o755
int_1365 = 0b10101010101
Strings können wie folgt in eine Zahl konvertiert werden
string_var = '42'
num = string_var.to_int()
Zahlen können in einen String konvertiert werden
int_var = 42
string_var = int_var.to_string()
Booleans
Ein Boolean ist entweder true oder false.
truth = true
Booleans können in einen String oder eine Zahl konvertiert werden
bool_var = true
string_var = bool_var.to_string()
int_var = bool_var.to_int()
Strings
Strings werden in Meson mit einfachen Anführungszeichen deklariert. Um ein literales einfaches Anführungszeichen einzugeben, machen Sie es so
single_quote = 'contains a \' character'
Die vollständige Liste der Escape-Sequenzen ist
-
\\Backslash -
\'Einfaches Anführungszeichen -
\aGlockenton -
\bRückschritt -
\fSeitenvorschub -
\nZeilenvorschub -
\rWagenrücklauf -
\tHorizontaler Tabulator -
\vVertikaler Tabulator -
\oooZeichen mit oktalem Wert ooo -
\xhhZeichen mit hexadezimalem Wert hh -
\uxxxxZeichen mit 16-Bit-Hexadezimalwert xxxx -
\UxxxxxxxxZeichen mit 32-Bit-Hexadezimalwert xxxxxxxx -
\N{name}Zeichen mit dem Namen name in der Unicode-Datenbank
Wie in Python und C werden bei \ooo bis zu drei oktale Ziffern akzeptiert.
Nicht erkannte Escape-Sequenzen bleiben unverändert im String, d. h. der Backslash bleibt im String erhalten.
String-Verkettung
Strings können mit dem +-Symbol zu einem neuen String verkettet werden.
str1 = 'abc'
str2 = 'xyz'
combined = str1 + '_' + str2 # combined is now abc_xyz
String-Pfad-Erstellung
(Hinzugefügt 0.49)
Sie können zwei beliebige Strings mit / als Operator verketten, um Pfade zu erstellen. Dies verwendet immer / als Pfadtrennzeichen auf allen Plattformen.
joined = '/usr/share' / 'projectname' # => /usr/share/projectname
joined = '/usr/local' / '/etc/name' # => /etc/name
joined = 'C:\\foo\\bar' / 'builddir' # => C:/foo/bar/builddir
joined = 'C:\\foo\\bar' / 'D:\\builddir' # => D:/builddir
Beachten Sie, dass dies der Verwendung von join_paths() entspricht, die durch diesen Operator obsolet wurde.
Strings, die sich über mehrere Zeilen erstrecken
Mehrzeilige Strings können mit drei einfachen Anführungszeichen deklariert werden, wie hier
multiline_string = '''#include <foo.h>
int main (int argc, char ** argv) {
return FOO_SUCCESS;
}'''
Dies sind rohe Strings, die die oben aufgeführten Escape-Sequenzen nicht unterstützen. Diese Strings können auch mit der String-Formatierungsfunktionalität über .format() kombiniert werden, wie unten beschrieben.
Beachten Sie, dass die Unterstützung für mehrzeilige f-Strings in Version 0.63 hinzugefügt wurde.
String-Index
Strings unterstützen den Indexierungsoperator ([<num>]). Dieser Operator ermöglicht den (schreibgeschützten) Zugriff auf ein bestimmtes Zeichen. Der zurückgegebene Wert ist garantiert ein String der Länge 1.
foo = 'abcd'
message(foo[1]) # Will print 'b'
foo[2] = 'C' # ERROR: Meson objects are immutable!
String-Formatierung
.format()
Strings können mit der String-Formatierungsfunktionalität erstellt werden.
template = 'string: @0@, number: @1@, bool: @2@'
res = template.format('text', 1, true)
# res now has value 'string: text, number: 1, bool: true'
Wie zu sehen ist, funktioniert die Formatierung, indem Platzhalter vom Typ @number@ durch das entsprechende Argument ersetzt werden.
Format-Strings
(Hinzugefügt 0.58)
Format-Strings können als alternative, nicht-positionelle Variante zur oben beschriebenen String-Formatierungsfunktionalität verwendet werden. Beachten Sie, dass die Unterstützung für mehrzeilige f-Strings in Version 0.63 hinzugefügt wurde.
n = 10
m = 'hi'
s = f'int: @n@, string: @m@'
# s now has the value 'int: 10, string: hi'
Derzeit werden nur Identitätsausdrücke innerhalb von Format-Strings unterstützt, d. h. Sie können keine beliebigen Meson-Ausdrücke darin verwenden.
n = 10
m = 5
# The following is not a valid format string
s = f'result: @n + m@'
String-Methoden
Strings unterstützen auch eine Reihe anderer Methoden, die transformierte Kopien zurückgeben.
.replace()
Seit 0.58.0 können Sie eine Teilzeichenkette aus einem String ersetzen.
# Replaces all instances of one substring with another
s = 'semicolons;as;separators'
s = s.replace('as', 'are')
# 's' now has the value of 'semicolons;are;separators'
.strip()
# Similar to the Python str.strip(). Removes leading/ending spaces and newlines.
define = ' -Dsomedefine '
stripped_define = define.strip()
# 'stripped_define' now has the value '-Dsomedefine'
# You may also pass a string to strip, which specifies the set of characters to
# be removed instead of the default whitespace.
string = 'xyxHelloxyx'.strip('xy')
# 'string' now has the value 'Hello'
Seit 0.43.0 können Sie ein positionelles String-Argument angeben, und alle Zeichen in diesem String werden entfernt.
.to_upper(), .to_lower()
target = 'x86_FreeBSD'
upper = target.to_upper() # t now has the value 'X86_FREEBSD'
lower = target.to_lower() # t now has the value 'x86_freebsd'
.to_int()
version = '1'
# Converts the string to an int and throws an error if it can't be
ver_int = version.to_int()
.contains(), .startswith(), .endswith()
target = 'x86_FreeBSD'
is_fbsd = target.to_lower().contains('freebsd')
# is_fbsd now has the boolean value 'true'
is_x86 = target.startswith('x86') # boolean value 'true'
is_bsd = target.to_lower().endswith('bsd') # boolean value 'true'
.substring()
Seit 0.56.0 können Sie einen Teilstring aus einem String extrahieren.
# Similar to the Python str[start:end] syntax
target = 'x86_FreeBSD'
platform = target.substring(0, 3) # prefix string value 'x86'
system = target.substring(4) # suffix string value 'FreeBSD'
Die Methode akzeptiert negative Werte, wobei ein negativer start relativ zum Ende des Strings len(string) - start ist, ebenso wie ein negativer end.
string = 'foobar'
string.substring(-5, -3) # => 'oo'
string.substring(1, -1) # => 'ooba'
.split(), .join()
# Similar to the Python str.split()
components = 'a b c d '.split()
# components now has the value ['a', 'b', 'c', 'd']
components = 'a b c d '.split(' ')
# components now has the value ['a', 'b', '', '', 'c', 'd', '']
# Similar to the Python str.join()
output = ' '.join(['foo', 'bar'])
# Output value is 'foo bar'
pathsep = ':'
path = pathsep.join(['/usr/bin', '/bin', '/usr/local/bin'])
# path now has the value '/usr/bin:/bin:/usr/local/bin'
# For joining path elements, you should use path1 / path2
# This has the advantage of being cross-platform
path = '/usr' / 'local' / 'bin'
# path now has the value '/usr/local/bin'
# For sources files, use files():
my_sources = files('foo.c')
...
my_sources += files('bar.c')
# This has the advantage of always calculating the correct relative path, even
# if you add files in another directory or use them in a different directory
# than they're defined in
# Example to set an API version for use in library(), install_header(), etc
project('project', 'c', version: '0.2.3')
version_array = meson.project_version().split('.')
# version_array now has the value ['0', '2', '3']
api_version = '.'.join([version_array[0], version_array[1]])
# api_version now has the value '0.2'
# We can do the same with .format() too:
api_version = '@0@.@1@'.format(version_array[0], version_array[1])
# api_version now (again) has the value '0.2'
.underscorify()
name = 'Meson Docs.txt#Reference-manual'
# Replaces all characters other than `a-zA-Z0-9` with `_` (underscore)
# Useful for substituting into #defines, filenames, etc.
underscored = name.underscorify()
# underscored now has the value 'Meson_Docs_txt_Reference_manual'
.version_compare()
version = '1.2.3'
# Compare version numbers semantically
is_new = version.version_compare('>=2.0')
# is_new now has the boolean value false
# Supports the following operators: '>', '<', '>=', '<=', '!=', '==', '='
Konventionen für den Vergleich von Meson-Versionen beinhalten
'3.6'.version_compare('>=3.6.0') == false
Es ist am besten, eindeutig zu sein und die vollständige Revisionsstufe anzugeben, die verglichen werden soll.
Arrays
Arrays sind durch Klammern abgegrenzt. Ein Array kann eine beliebige Anzahl von Objekten beliebigen Typs enthalten.
my_array = [1, 2, 'string', some_obj]
Der Zugriff auf Elemente eines Arrays kann über Array-Indizierung erfolgen
my_array = [1, 2, 'string', some_obj]
second_element = my_array[1]
last_element = my_array[-1]
Sie können weitere Elemente zu einem Array wie folgt hinzufügen
my_array += ['foo', 3, 4, another_obj]
Beim Hinzufügen eines einzelnen Elements müssen Sie es nicht in ein Array einschließen
my_array += ['something']
# This also works
my_array += 'else'
Beachten Sie, dass das Anhängen an ein Array immer ein neues Array-Objekt erstellt und es my_array zuweist, anstatt das Original zu ändern, da alle Objekte in Meson unveränderlich sind.
Seit 0.49.0 können Sie wie folgt überprüfen, ob ein Array ein Element enthält
my_array = [1, 2]
if 1 in my_array
# This condition is true
endif
if 1 not in my_array
# This condition is false
endif
Array-Methoden
Die folgenden Methoden sind für alle Arrays definiert
-
length, die Größe des Arrays -
contains, gibttruezurück, wenn das Array das als Argument übergebene Objekt enthält, andernfallsfalse -
get, gibt das Objekt am angegebenen Index zurück; negative Indizes zählen vom Ende des Arrays aus; Indizierung außerhalb der Grenzen ist ein fataler Fehler. Zur Abwärtskompatibilität bereitgestellt, ist es identisch mit der Array-Indizierung.
Wörterbücher
Wörterbücher sind durch geschweifte Klammern abgegrenzt. Ein Wörterbuch kann eine beliebige Anzahl von Schlüssel:Wert-Paaren enthalten. Schlüssel müssen Strings sein, aber Werte können Objekte beliebigen Typs sein. Vor 0.53.0 mussten Schlüssel literale Strings sein, d. h. Sie konnten keine Variable, die einen String-Wert enthält, als Schlüssel verwenden.
my_dict = {'foo': 42, 'bar': 'baz'}
Schlüssel müssen eindeutig sein
# This will fail
my_dict = {'foo': 42, 'foo': 43}
Der Zugriff auf Elemente eines Wörterbuchs funktioniert ähnlich wie die Array-Indizierung
my_dict = {'foo': 42, 'bar': 'baz'}
forty_two = my_dict['foo']
# This will fail
my_dict['does_not_exist']
Wörterbücher sind unveränderlich und haben keine garantierte Reihenfolge.
Wörterbücher sind seit 0.47.0 verfügbar.
Besuchen Sie die dict Objekte Seite im Referenzhandbuch, um mehr über die von Wörterbüchern bereitgestellten Methoden zu erfahren.
Seit 0.49.0 können Sie wie folgt überprüfen, ob ein Wörterbuch einen Schlüssel enthält
my_dict = {'foo': 42, 'bar': 43}
if 'foo' in my_dict
# This condition is true
endif
if 42 in my_dict
# This condition is false
endif
if 'foo' not in my_dict
# This condition is false
endif
Seit 0.53.0 Schlüssel können jeder Ausdruck sein, der zu einem String-Wert ausgewertet wird, nicht mehr auf String-Literale beschränkt.
d = {'a' + 'b' : 42}
k = 'cd'
d += {k : 43}
Funktionsaufrufe
Meson bietet eine Reihe von nutzbaren Funktionen. Der häufigste Anwendungsfall ist die Erstellung von Build-Objekten.
executable('progname', 'prog.c')
Die meisten Funktionen nehmen nur wenige positionelle Argumente, aber mehrere Schlüsselwortargumente, die wie folgt angegeben werden
executable('progname',
sources: 'prog.c',
c_args: '-DFOO=1')
Ab Version 0.49.0 können Schlüsselwortargumente dynamisch angegeben werden. Dies geschieht, indem ein Wörterbuch, das die zu setzenden Schlüssel repräsentiert, im kwargs-Schlüsselwort übergeben wird. Das vorherige Beispiel würde wie folgt angegeben werden
d = {'sources': 'prog.c',
'c_args': '-DFOO=1'}
executable('progname',
kwargs: d)
Eine einzelne Funktion kann sowohl direkte Schlüsselwortargumente im Funktionsaufruf als auch indirekte über das kwargs-Schlüsselwortargument entgegennehmen. Die einzige Einschränkung ist, dass es ein harter Fehler ist, einen bestimmten Schlüssel sowohl als direktes als auch als indirektes Argument zu übergeben.
d = {'c_args': '-DFOO'}
executable('progname', 'prog.c',
c_args: '-DBAZ=1',
kwargs: d) # This is an error!
Der Versuch, dies zu tun, führt dazu, dass Meson sofort mit einem Fehler beendet wird.
Argument-Flattening
Argument-Flattening ist eine Meson-Funktion, die darauf abzielt, die Verwendung von Methoden und Funktionen zu vereinfachen. Für Funktionen, bei denen diese Funktion aktiv ist, nimmt Meson die Liste der Argumente und vereinfacht alle verschachtelten Listen zu einer großen Liste.
Zum Beispiel sind die folgenden Funktionsaufrufe an executable() in Meson identisch
# A normal example:
executable('exe1', ['foo.c', 'bar.c', 'foobar.c'])
# A more contrived example that also works but certainly
# isn't good Meson code:
l1 = ['bar.c']
executable('exe1', [[['foo.c', l1]], ['foobar.c']])
# How meson will treat all the previous calls internally:
executable('exe1', 'foo.c', 'bar.c', 'foobar.c')
Aufgrund eines internen Implementierungsdetails wird die folgende Syntax derzeit ebenfalls unterstützt, obwohl das erste Argument von executable() ein einzelner str und kein list ist
# WARNING: This example is only valid because of an internal
# implementation detail and not because it is intended
#
# PLEASE DO NOT DO SOMETHING LIKE THIS!
#
executable(['exe1', 'foo.c'], 'bar.c', 'foobar.c')
Dieser Code wird derzeit akzeptiert, da das Argument-Flattening derzeit erfolgt, bevor die Parameter ausgewertet werden. Die "Unterstützung" für solche Konstrukte wird wahrscheinlich in zukünftigen Meson-Versionen entfernt werden!
Argument-Flattening wird von den meisten, aber nicht von allen Meson-Funktionen und -Methoden unterstützt. Als allgemeine Regel kann davon ausgegangen werden, dass eine Funktion oder Methode Argument-Flattening unterstützt, wenn die genaue Listenstruktur für eine Funktion irrelevant ist.
Ob eine Funktion Argument-Flattening unterstützt, ist im Referenzhandbuch dokumentiert.
Methodenaufrufe
Objekte können Methoden haben, die mit dem Punktoperator aufgerufen werden. Die genauen Methoden hängen vom Objekt ab.
myobj = some_function()
myobj.do_something('now')
If-Anweisungen
If-Anweisungen funktionieren wie in anderen Sprachen.
var1 = 1
var2 = 2
if var1 == var2 # Evaluates to false
something_broke()
elif var3 == var2
something_else_broke()
else
everything_ok()
endif
opt = get_option('someoption')
if opt != 'foo'
do_something()
endif
Logische Operationen
Meson verfügt über die Standardpalette logischer Operationen, die in if-Anweisungen verwendet werden können.
if a and b
# do something
endif
if c or d
# do something
endif
if not e
# do something
endif
if not (f or g)
# do something
endif
Logische Operationen funktionieren nur mit booleschen Werten.
Foreach-Anweisungen
Um eine Operation für alle Elemente eines Iterables durchzuführen, verwenden Sie den Befehl foreach.
Beachten Sie, dass Meson-Variablen unveränderlich sind. Der Versuch, dem iterierten Objekt innerhalb einer foreach-Schleife einen neuen Wert zuzuweisen, hat keinen Einfluss auf den Kontrollfluss von foreach.
Foreach mit einem Array
Hier ist ein Beispiel, wie Sie zwei ausführbare Programme mit entsprechenden Tests unter Verwendung von Arrays und foreach definieren könnten.
progs = [['prog1', ['prog1.c', 'foo.c']],
['prog2', ['prog2.c', 'bar.c']]]
foreach p : progs
exe = executable(p[0], p[1])
test(p[0], exe)
endforeach
Foreach mit einem Wörterbuch
Hier ist ein Beispiel, wie Sie eine Reihe von Komponenten iterieren könnten, die gemäß einer bestimmten Konfiguration kompiliert werden sollen. Dies verwendet ein Wörterbuch, das seit 0.47.0 verfügbar ist.
components = {
'foo': ['foo.c'],
'bar': ['bar.c'],
'baz': ['baz.c'],
}
# compute a configuration based on system dependencies, custom logic
conf = configuration_data()
conf.set('USE_FOO', 1)
# Determine the sources to compile
sources_to_compile = []
foreach name, sources : components
if conf.get('USE_@0@'.format(name.to_upper()), 0) == 1
sources_to_compile += sources
endif
endforeach
Foreach break und continue
Seit 0.49.0 können die Schlüsselwörter break und continue innerhalb von foreach-Schleifen verwendet werden.
items = ['a', 'continue', 'b', 'break', 'c']
result = []
foreach i : items
if i == 'continue'
continue
elif i == 'break'
break
endif
result += i
endforeach
# result is ['a', 'b']
Kommentare
Ein Kommentar beginnt mit dem #-Zeichen und erstreckt sich bis zum Ende der Zeile.
some_function() # This is a comment
some_other_function()
Ternärer Operator
Der ternäre Operator funktioniert wie in anderen Sprachen.
x = condition ? true_value : false_value
Die einzige Ausnahme ist, dass verschachtelte ternäre Operatoren verboten sind, um die Lesbarkeit zu verbessern. Wenn Ihre Verzweigungsanforderungen komplexer sind, müssen Sie eine if/else-Konstruktion schreiben.
Includes
Die meisten Quellbaumstrukturen haben mehrere Unterverzeichnisse zu verarbeiten. Diese können mit dem subdir-Befehl von Meson gehandhabt werden. Er wechselt in das angegebene Unterverzeichnis und führt den Inhalt von meson.build in diesem Unterverzeichnis aus. Der gesamte Zustand (Variablen usw.) wird an und aus dem Unterverzeichnis übergeben. Die Wirkung ist ungefähr die gleiche, als ob der Inhalt der Meson-Datei des Unterverzeichnisses dort geschrieben worden wäre, wo der include-Befehl steht.
test_data_dir = 'data'
subdir('tests')
Benutzerdefinierte Funktionen und Methoden
Meson unterstützt derzeit keine benutzerdefinierten Funktionen oder Methoden. Die Hinzufügung benutzerdefinierter Funktionen würde Meson Turing-vollständig machen, was es schwieriger zu verstehen und schwieriger mit Tools wie IDEs zu integrieren macht. Mehr Details dazu finden Sie in der FAQ. Wenn Sie aufgrund dieser Einschränkung feststellen, dass Sie viel Code kopieren und einfügen, können Sie stattdessen eine foreach-Schleife verwenden.
Stabilitätszusagen
Meson wird sehr aktiv entwickelt und kontinuierlich verbessert. Es besteht die Möglichkeit, dass zukünftige Verbesserungen des Meson-Build-Systems Änderungen an der Syntax erfordern. Solche Änderungen könnten die Hinzufügung neuer reservierter Schlüsselwörter, die Änderung der Bedeutung bestehender Schlüsselwörter oder Ergänzungen rund um die grundlegenden Bausteine wie Anweisungen und grundlegende Typen sein. Es ist geplant, die Syntax mit der Version 1.0 zu stabilisieren.
Grammatik
Dies ist die vollständige Meson-Grammatik, wie sie zum Parsen von Meson-Build-Definitionsdateien verwendet wird
additive_expression: multiplicative_expression | (additive_expression additive_operator multiplicative_expression)
additive_operator: "+" | "-"
argument_list: positional_arguments ["," keyword_arguments] | keyword_arguments
array_literal: "[" [expression_list] "]"
assignment_statement: expression assignment_operator expression
assignment_operator: "=" | "+="
binary_literal: "0b" BINARY_NUMBER
BINARY_NUMBER: /[01]+/
boolean_literal: "true" | "false"
build_definition: (NEWLINE | statement)*
condition: expression
conditional_expression: logical_or_expression | (logical_or_expression "?" expression ":" assignment_expression
decimal_literal: DECIMAL_NUMBER
DECIMAL_NUMBER: /[1-9][0-9]*/
dictionary_literal: "{" [key_value_list] "}"
equality_expression: relational_expression | (equality_expression equality_operator relational_expression)
equality_operator: "==" | "!="
expression: conditional_expression | logical_or_expression
expression_list: expression ("," expression)*
expression_statement: expression
function_expression: id_expression "(" [argument_list] ")"
hex_literal: "0x" HEX_NUMBER
HEX_NUMBER: /[a-fA-F0-9]+/
id_expression: IDENTIFIER
IDENTIFIER: /[a-zA-Z_][a-zA-Z_0-9]*/
identifier_list: id_expression ("," id_expression)*
integer_literal: decimal_literal | octal_literal | hex_literal
iteration_statement: "foreach" identifier_list ":" id_expression NEWLINE (statement | jump_statement)* "endforeach"
jump_statement: ("break" | "continue") NEWLINE
key_value_item: expression ":" expression
key_value_list: key_value_item ("," key_value_item)*
keyword_item: id_expression ":" expression
keyword_arguments: keyword_item ("," keyword_item)*
literal: integer_literal | string_literal | boolean_literal | array_literal | dictionary_literal
logical_and_expression: equality_expression | (logical_and_expression "and" equality_expression)
logical_or_expression: logical_and_expression | (logical_or_expression "or" logical_and_expression)
method_expression: postfix_expression "." function_expression
multiplicative_expression: unary_expression | (multiplicative_expression multiplicative_operator unary_expression)
multiplicative_operator: "*" | "/" | "%"
octal_literal: "0o" OCTAL_NUMBER
OCTAL_NUMBER: /[0-7]+/
positional_arguments: expression ("," expression)*
postfix_expression: primary_expression | subscript_expression | function_expression | method_expression
primary_expression: literal | ("(" expression ")") | id_expression
relational_expression: additive_expression | (relational_expression relational_operator additive_expression)
relational_operator: ">" | "<" | ">=" | "<=" | "in" | ("not" "in")
selection_statement: "if" condition NEWLINE (statement)* ("elif" condition NEWLINE (statement)*)* ["else" (statement)*] "endif"
statement: (expression_statement | selection_statement | iteration_statement | assignment_statement) NEWLINE
string_literal: ("'" STRING_SIMPLE_VALUE "'") | ("'''" STRING_MULTILINE_VALUE "'''")
STRING_MULTILINE_VALUE: \.*?(''')\
STRING_SIMPLE_VALUE: \.*?(?<!\\)(\\\\)*?'\
subscript_expression: postfix_expression "[" expression "]"
unary_expression: postfix_expression | (unary_operator unary_expression)
unary_operator: "not" | "-"
Die Ergebnisse der Suche sind