Cross-Language Interface Format =============================== The idea is that a new (or existing?) format could be used as a cross-language "header" format, that would support language functions that are not available in C (such as memory safety declarations, e.g. arenas, ownership, array lengths, etc). The examples uses a DER OID (ASN.1) parser as an example (might not be the best example, but it covers some different areas of SLUL). Goals: * be machine-readable (but sort of user readable) * be very easy to parse * support "any" functionality in "any" language. * support ad-hoc addition of new features in the format. Additionally (this is hard): * Be concise (but still user-friendly and flexible) Format ideas ------------ Basic format - Alternative 1, a subset of scheme: ; this is a comment (can start anywhere on a line, but not in a string) abc-def-123 # <-- an identifier -123 # <-- a 64-bit signed number true # <-- a boolean value "hello\"world" # <-- a string. \" and \\ are the only escapes (func ....) # <-- a function call Basic format - Alternative 2, custom format: # comment func abc { param abc { type { pointer{int{const}} } } return - { } } Bascially: * A "statement" consists of: 1. a number of words 2. optionally a { } containing nested statements A statement shall be terminated ";" IF it does not have a { } part AND it's not followed by a } * Words consist of the following characters: a-z A-Z 0-9 - _ "Words" containing other characters have to be placed in a string: "abc \"123\"" The supported escape sequences are \" and \\ Newlines are NOT allowed in strings. The special word - means none/null. Put it in a string "-" to have an actual - * The encoding must be UTF-8, without any BOM. * Comments can start anywhere in a line, except inside strings Basic format - Alternative 3, use NestedText abc: def ghi: - jkl - mno pqr Example ------- ... \depends bigint 0.0.1 \interface_depends something 0.0.1 ... type DerOid = record { inline EncodedDer der } type EncodedDer = record { usize len ref [len]byte bytes } func DerOid.get_num_components() -> int<1..> or DerError func DerOid.get_components(out [len]DerInteger components, usize len) or DerError func DerOid.to_string(arena) -> string Converted to "CLIF": import something { what { types } version { "0.0.1" } } type DerOid { def { struct { field der{type{named{EncodedDer}}} } } } type EncodedDer { def { struct { field len{type{size_t}} field bytes{type{ptr{ array{ elemtype{byte} length{fieldref{len}}} const }}} } } } func DerOid_get_num_components { classname DerOid; methodname get_num_components; params {} return - { type{ or-type{ int{range{min 1}} named{DerError} }}} } func DerOid_get_components { classname DerOid; methodname get_components; params { param components { out; type { ptr{ array{ elemtype{named{DerInteger}} length{paramref{len}} } var } } } param len { type{size_t} } } return - { type { or-type{ void named{DerError} } } } } func DerOid_to_string { classname DerOid; methodname to_string; params { param arena { type { ptr{any-data} with-protocol { slul-arena } } } } return - { type { ptr{any-data} with-protocol { slul-string } } } } Alternative syntax (compact) ---------------------------- !import something $what=types $version=0.0.1 !type DerOid %struct{ !field der %type{%named{EncodedDer}} } !type EncodedDer %struct{ !field len %type{%size_t} !field bytes %type{%ptr{ %array{ %elemtype{%byte} %length{len}} } const} }} } func DerOid.get_num_components() -> int<1..> or DerError func DerOid.get_components(out [len]DerInteger components, usize len) or DerError func DerOid.to_string(arena) -> string Alternative - C header with extra info -------------------------------------- /*!CLIF! version=0.0.1*/ #include "something.h" struct EncodedDer { size_t len; /*!CLIF! const; length=len */ unsigned char *bytes; }; struct DerOid { struct EncodedDer der; }; /*!CLIF! thisparam=param[0]; class=DerOid; method=get_num_components; return=or_type(min(1), typeref(DerError)) */ int DerOid_get_num_components(struct DerOid *); /*!CLIF! ... */ int DerOid_get_components(out [len]DerInteger components, usize len) or DerError func DerOid.to_string(arena) -> string try 2: #include "something.h" /*%%version=0.0.1*/ struct EncodedDer { size_t len; /*%%const*/ unsigned char /*%%length=len*/ *bytes; }; struct DerOid { struct EncodedDer der; }; /*%%min=1;or=DerError*/int /*%%cmsplit=_*/DerOid_get_num_components(struct DerOid * /*%%this*/); /*%%ok=0;or=DerError*/int /*%%cmsplit=_*/DerOid_get_components( struct DerOid * /*%%this*/, /*%%out*/struct DerInteger /*%%length=len*/ **components, size_t len); struct SlulString * /*%%cmsplit=_*/DerOid_to_string(struct DerOid * /*%%this*/, /*%%slul_arena*/void *); try 3: #include "something.h" /*%%version=0.0.1*/ struct EncodedDer { size_t len; CLIF_CONST unsigned char CLIF_LEN(len) *bytes; }; struct DerOid { struct EncodedDer der; }; CLIF_MIN(1) CLIF_OR(DerError) int CLIF_SPLIT('_')DerOid_get_num_components(struct DerOid * CLIF_THIS); CLIF_OK(0) CLIF_OR(DerError) int CLIF_SPLIT('_')DerOid_get_components( struct DerOid * CLIF_THIS, CLIF_OUT struct DerInteger CLIF_LEN(len) **components, size_t len); struct SlulString * CLIF_SPLIT('_')DerOid_to_string(struct DerOid * CLIF_THIS, CLIF_SLUL_ARENA void *); try 4: #include "something.h" /*%%version=0.0.1*/ struct EncodedDer { size_t len; CLIF_CONST unsigned char CLIF_LEN(len) *bytes; }; struct DerOid { struct EncodedDer der; }; CLIF_FUNC_DEFAULT(CLIF_CMSPLIT('_')) CLIF_MIN(1) CLIF_OR(DerError) int DerOid_get_num_components(struct DerOid * CLIF_THIS); CLIF_OK(0) CLIF_OR(DerError) int DerOid_get_components( struct DerOid * CLIF_THIS, CLIF_OUT struct DerInteger CLIF_LEN(len) **components, size_t len); struct SlulString * DerOid_to_string(struct DerOid * CLIF_THIS, CLIF_SLUL_ARENA void *);