/* cslul.h -- Interface to C implementation of SLUL Copyright © 2021-2024 Samuel Lidén Borell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef CSLUL_H #define CSLUL_H #define CSLUL_VERSION_STR "0.0.0~unreleased" #include /* for FILE */ #include /* On some compilers, the platform specific macros are defined in stddef.h! */ #if (defined(_WIN64) || defined(_WIN32) || defined(__WIN32__) || \ defined(__WINDOWS__)) && !defined(CSLUL_FORCE_POSIX) #define CSLUL_WINDOWS #endif enum CSlulPhase { /** Internal initialization phase */ CSLUL_P_INIT = 0, /** Parsing the module header */ CSLUL_P_MODULEHEADER, /** Parsing the module interface */ CSLUL_P_IFACE, /** Parsing the implementation code */ CSLUL_P_IMPL, /** Parsing interfaces of dependencies */ CSLUL_P_DEPS, /** Resolving identifiers, verifying types, lifetimes, etc. */ CSLUL_P_VERIFY, /** Generating code */ CSLUL_P_CODEGEN }; enum CSlulErrorCode { CSLUL_E_NOERROR = 0, CSLUL_E_OUTOFMEMORY, CSLUL_E_OPENFILE, CSLUL_E_READFILE, CSLUL_E_CREATEFILE, CSLUL_E_WRITEFILE, CSLUL_E_INVALIDCHAR, CSLUL_E_TAB, CSLUL_E_BADUTF8, CSLUL_E_DISALLOWEDUNICODE, CSLUL_E_INDENTEDATTR, CSLUL_E_IDENTTOOLONG, CSLUL_E_UNEXPECTEDEOF, CSLUL_E_TRAILINGSPACE, CSLUL_E_BADATTRCHAR, CSLUL_E_NOEOFNEWLINE, CSLUL_E_BADATTRNAME, CSLUL_E_WRONGATTRORDER, CSLUL_E_MISSINGATTRVALUE, CSLUL_E_BADFILENAMECHAR, CSLUL_E_FILENAMEDOT, CSLUL_E_FILENAMEROOT, CSLUL_E_FILENAMEDOUBLESLASH, CSLUL_E_FILENAMEDOTDOT, CSLUL_E_NONSLULFILE, CSLUL_E_BADDIRNAME, CSLUL_E_MAXSOURCEFILES, CSLUL_E_TREETOODEEP, CSLUL_E_DUPLICATEFILE, CSLUL_E_SOURCECASEDUP, CSLUL_E_BADMODULETYPE, CSLUL_E_MODNAMELENGTH, CSLUL_E_MODNAMESTART, CSLUL_E_MODNAMECHAR, CSLUL_E_VERSTRLENGTH, CSLUL_E_VERSTRSTART, CSLUL_E_VERSTRCHAR, CSLUL_E_MODTYPEUNSTABLE, CSLUL_E_SPECWITHSOURCE, CSLUL_E_MISSINGSOURCE, CSLUL_E_MISSINGATTR, CSLUL_E_OUTPUTSPEC, CSLUL_E_OUTPUTLIB, CSLUL_E_OUTPUTPLUGIN, CSLUL_E_OUTPUTEXE, CSLUL_E_BADCPUABICOMBO, CSLUL_E_BADSYSABICOMBO, CSLUL_E_BADARCHFORMAT, CSLUL_E_BADARCHCPU, CSLUL_E_BADARCHITEM, CSLUL_E_BADESCAPE, CSLUL_E_STRINGTOOLONG, CSLUL_E_ESCAPETOOLONG, CSLUL_E_BADUNICODEESCAPE, CSLUL_E_MISSINGESCAPE, CSLUL_E_BADNUMBERTYPE, CSLUL_E_NODIGITS, CSLUL_E_BADNUMBERCHAR, CSLUL_E_NUMBERTOOLARGE, CSLUL_E_LEADINGZERO, CSLUL_E_DOUBLEDECPOINT, CSLUL_E_EXPONENTTOOLARGE, CSLUL_E_NOEXPDIGITS, CSLUL_E_NOFRACDIGITS, CSLUL_E_IDENTIFIEREXPECTED, CSLUL_E_BADTYPE, CSLUL_E_TYPEFUNCREFNOTFUNC, CSLUL_E_BADINITVALTOKEN, CSLUL_E_BADINITVALBLANKLINE, CSLUL_E_IDENTEXISTS, CSLUL_E_BADTOPLEVELTOKEN, CSLUL_E_BADTOPLEVELCONTINUATION, CSLUL_E_BADTOPLEVELCOLUMN, CSLUL_E_TYPEDEFWITHOUTEQUAL, CSLUL_E_TYPETOODEEP, CSLUL_E_DUPLFIELD, CSLUL_E_NOFUNCENDCURLY, CSLUL_E_NOIFEND, CSLUL_E_ELSEWITHOUTRCURLY, CSLUL_E_NOLOOPEND, CSLUL_E_BADSTMTLINESTART, CSLUL_E_EXPRTOODEEP, CSLUL_E_BADEXPRTOKEN, CSLUL_E_OPERATOREXPECTED, CSLUL_E_MISSINGOPERAND, CSLUL_E_TRAILINGCOMMA, CSLUL_E_TRAILINGCOMMAINDEX, CSLUL_E_TRAILINGCOMMASTRUCT, CSLUL_E_UNCLOSEDPAREN, CSLUL_E_INCOMPLETEEXPR, CSLUL_E_OPERATORNOTEXP, CSLUL_E_AMBIGUOUSOPERMIX, CSLUL_E_BLOCKTOODEEP, CSLUL_E_LOOPWITHOUTBRACES, CSLUL_E_DOWITHOUTWHILE, CSLUL_E_BREAKOUTSIDELOOP, CSLUL_E_CONTINUEOUTSIDELOOP, CSLUL_E_DOTWITHOUTIDENT, CSLUL_E_DOTSPACEIDENT, CSLUL_E_FIELDINITCONTEXT, CSLUL_E_NOTAFIELDINIT, CSLUL_E_INITOPENSTRUCT, CSLUL_E_STRUCTINITWRONGORDER, CSLUL_E_STRUCTINITTOOMANY, CSLUL_E_STRUCTINITTOOFEW, CSLUL_E_LOOPENDWITHOUTBREAK, CSLUL_E_LOOPEMPTYENDORDER, CSLUL_E_DUPLICATELOOPEMPTY, CSLUL_E_DUPLICATELOOPEND, CSLUL_E_NOIN, CSLUL_E_DUPLICATEGOTO, CSLUL_E_UNDEFINEDGOTO, CSLUL_E_CASEEXPECTED, CSLUL_E_LCURLYEXPECTED, CSLUL_E_LCURLYEXPECTEDONLY, CSLUL_E_CASEOUTSIDESWITCH, CSLUL_E_NOCOLONAFTERDEFAULT, CSLUL_E_NOCASECOMMACOLON, CSLUL_E_REPEATEDCASE, CSLUL_E_SUBCASEOUTSIDECASE, CSLUL_E_NONEWLINE, CSLUL_E_NORETURNNEWLINE, CSLUL_E_NOCURLYSTMT, CSLUL_E_TOOMANYRCURLY, CSLUL_E_FINALRCURLYINDENTED, CSLUL_E_DUPLQUAL, CSLUL_E_BADIMPLQUAL, CSLUL_E_DIRTRAILINGDOT, CSLUL_E_DEVICEFILENAME, CSLUL_E_DEVICEMODNAME, CSLUL_E_MISSINGVARIDENT, CSLUL_E_DECLMISSINGEQUALS, CSLUL_E_VARDEFINSIDELINE, CSLUL_E_BADSEMICOLON, CSLUL_E_INDENTEDBLANKLINE, CSLUL_E_UNTERMINATEDSTRING, CSLUL_E_IFACEIMPLDUPLICATE, CSLUL_E_INLINEPLUSIMPL, CSLUL_E_CONSTANTWITHDATA, CSLUL_E_MISSINGIMPLDEF, CSLUL_E_MISSINGIMPLCLASS, CSLUL_E_SELFDEPEND, CSLUL_E_DUPLICATEDEP, CSLUL_E_BADDEPFLAG, CSLUL_E_BADIFACEDEPFLAG, CSLUL_E_DUPLDEPFLAG, CSLUL_E_DUPLIFACEDEPFLAG, CSLUL_E_DEPFLAGSORDER, CSLUL_E_IFACEDEPFLAGSORDER, CSLUL_E_IFACEDEPHIGHERTHANDEP, CSLUL_E_DUPLENUMIDENT, CSLUL_E_ENUMCOMMA, CSLUL_E_ENUMEQUALSWITHOUTBASE, CSLUL_E_ENUMOUTSIDETYPEDEF, CSLUL_E_GENERICENUM, CSLUL_E_GENERICELEMENTARY, CSLUL_E_APPWITHAPI, CSLUL_E_TOOMANYATTRPARAMS, CSLUL_E_NODEPENDSVERSION, CSLUL_E_UNSUPPORTEDLANGVER, CSLUL_E_BADLANGVERSYNTAX, CSLUL_E_DUPLICATEATTR, CSLUL_E_MHNOBACKSLASH, CSLUL_E_MISSINGMODULEHEADER, CSLUL_E_OPTIONALNONREF, CSLUL_E_DUPLFUNCPARAM, CSLUL_E_TOKENAFTEROPERATOR, CSLUL_E_MISSINGDEP, CSLUL_E_OLDDEP, CSLUL_E_VERNOTSUPPORTED, CSLUL_E_NOIFACEDEPVERSION, CSLUL_E_NOSINCE, CSLUL_E_NOSINCEVERSION, CSLUL_E_SINCEWITHOUTMODVER, CSLUL_E_REPEATEDSINCE, CSLUL_E_NESTEDSINCE, CSLUL_E_APPWITHIFACEDEP, CSLUL_E_DUPLICATEIFACEDEP, CSLUL_E_IFACEDEPENDBUNDLED, CSLUL_E_TYPEPARAMNOCOMMA, CSLUL_E_TOOMANYTYPEPARAMS, CSLUL_E_EMPTYPARAMDEF, CSLUL_E_BADPARAMTYPE, CSLUL_E_PARAMDEFEND, CSLUL_E_VERSTRDOTDOT, CSLUL_E_VERSTRDOTEND, CSLUL_E_APIDEFWITHOUTMODVER, CSLUL_E_APIDEFUNSTABLE, CSLUL_E_MAXAPIDEFS, CSLUL_E_BADAPIHASHLEN, CSLUL_E_BADAPIHASH, CSLUL_E_DUPLICATEAPIDEF, CSLUL_E_IFACEDEPWITHOUTAPIDEF, CSLUL_E_SCRIPTESCAPEDUPL, CSLUL_E_SCRIPTESCAPEORDER, CSLUL_E_SCRIPTESCAPEBAD, CSLUL_E_SCRIPTESCAPEUNKNOWN, CSLUL_E_SCRIPTLATIN, CSLUL_E_SCRIPTCYRILLIC, CSLUL_E_SCRIPTGREEK, CSLUL_E_SCRIPTSPECIALS, CSLUL_E_SCRIPTOTHER, CSLUL_E_SCRIPTRTL, CSLUL_E_SOURCEMAINSLUL, CSLUL_E_WRONGPARENTYPE, CSLUL_E_LIFETIMENONIDENTTOK, CSLUL_E_LIFETIMENONGREATERTOK, CSLUL_E_LIFETIMESAMEPARAM, CSLUL_E_LIFETIMEIDENTNOTFOUND, CSLUL_E_LIFETIMENONREF, CSLUL_E_PRIVATEINIMPL, CSLUL_E_PRIVATENONSTRUCT, CSLUL_E_APPWITHIMPLSLULVER, CSLUL_E_STABLEWITHOUTAPIDEF, CSLUL_E_SLULIMPLVEROLDER, CSLUL_E_SLULMAXVEROLDER, CSLUL_E_UNSUPPORTEDIMPLLANGVER, CSLUL_E_VERSTRZEROPREFIXED, CSLUL_E_BADTLDATAQUAL, CSLUL_E_BADTLDATAREF, CSLUL_E_IMPLDATAWITHOUTINITVAL, CSLUL_E_VERSIONEDINIMPL, CSLUL_E_IMPLFUNCWITHOUTBODY, CSLUL_E_FUNCNOLCURLY, CSLUL_E_FUNCNOARROW, CSLUL_E_FUNCBADKEYWORD, CSLUL_E_VERSIONWITHOUTAPIDEF, CSLUL_E_MISSINGVERWITHAPIDEF, CSLUL_E_SINCEVERSIONINIMPL, CSLUL_E_EMPTYSINCE, CSLUL_E_SAMEVERSION, CSLUL_E_VERSIONEARLIERTHANDECL, CSLUL_E_SINCEVERNOTCHRONOLOGICAL, CSLUL_E_NOTABACKPORT, CSLUL_E_VERSIONEDLOCALREF, CSLUL_E_NOSUCHVERSION, CSLUL_E_UNVERSIONEDAFTERVERSIONED, CSLUL_E_QUALNOTALLOWED, CSLUL_E_NOQUALSONTYPE, CSLUL_E_AMBIGUOUSIDENT, CSLUL_E_AMBIGUOUSTYPEIDENT, CSLUL_E_SAMECLASSNAMEDIFFTYPE, CSLUL_E_TLTYPENOTDEF, CSLUL_E_TLIDENTNOTDEF, CSLUL_E_TLTYPETOONEW, CSLUL_E_TLIDENTTOONEW, CSLUL_E_TYPEIDENTTOONEW, CSLUL_E_FIELDTOONEW, CSLUL_E_TLTYPELATERLOWER, CSLUL_E_TLIDENTLATERLOWER, CSLUL_E_TYPEIDENTLATERLOWER, CSLUL_E_FIELDLATERLOWER, CSLUL_E_NOTYPESCOPEFUNC, CSLUL_E_NOTYPESCOPEDATA, CSLUL_E_BADFUNCIDENT, CSLUL_E_CLASSDOTTOKEN, CSLUL_E_UPPERFUNCNAME, CSLUL_E_FUNCDEFIDENT, CSLUL_E_THISOUTSIDEMETHOD, CSLUL_E_NONPARAMETRICTYPE, CSLUL_E_TYPEPARAMNONSLOT, CSLUL_E_PRIVATENONREF, CSLUL_E_AMBIGUOUSEXPRTYPE, CSLUL_E_CONSTEXPRBADOP, CSLUL_E_CYCLICDECL, CSLUL_E_CYCLICTYPEDECL, CSLUL_E_VERIFYTOODEEP, CSLUL_E_IDENTNOTCOMPILETIME, CSLUL_E_TYPESCOPENOTARGET, CSLUL_E_NOTYPESCOPE, CSLUL_E_TYPEIDENTNOTFOUND, CSLUL_E_BADAPIDEFFLAG, CSLUL_E_LOWERCASETYPE, CSLUL_E_VOIDNOTATYPE, CSLUL_E_CAPITALIZEDNONTYPE, CSLUL_E_TYPESNOTEQUAL, CSLUL_E_REFTYPESNOTEQUAL, CSLUL_E_REFREFTYPESNOTEQUAL, CSLUL_E_QUALSNOTEQUAL, CSLUL_E_QUALSNOTCOMPATIBLE, CSLUL_E_NAMEDTYPESMUSTBESAME, CSLUL_E_ACCESSPRIVATETYPE, CSLUL_E_INCOMPATIBLENESTEDTYPES, CSLUL_E_INCOMPATIBLETYPES, CSLUL_E_FIELDNONSTRUCT, CSLUL_E_FIELDNOTFOUND, CSLUL_E_ASSERTTRUE, CSLUL_E_ALWAYSFALSE, CSLUL_E_ALWAYSTRUE, CSLUL_E_STMTSAFTERRETURN, CSLUL_E_STMTSAFTERGOTO, CSLUL_E_AFTERWHILETRUE, CSLUL_E_AFTERDOWHILETRUE, CSLUL_E_UNREACHABLESTMT, CSLUL_E_NOMETHODNAMESPACE, CSLUL_E_METHODNOTFOUND, CSLUL_E_METHODCONSTR, CSLUL_E_NOTAMETHOD, CSLUL_E_NOTCALLABLE, CSLUL_E_TOOMANYFUNCARGS, CSLUL_E_TOOFEWFUNCARGS, CSLUL_E_PARAMWRONGORDER, CSLUL_E_PARAMNOTFOUND, CSLUL_E_NOHOSTTARGET, CSLUL_E_FUNCLPAREN, CSLUL_E_STMTENDSHERE, CSLUL_E_VARNOTASSIGNED, CSLUL_E_VARNOTASSIGNGOTO, CSLUL_E_VARMAYBENONE, CSLUL_E_CANTACCESSOPTIONAL, CSLUL_E_FUNCMISSINGRETURN, CSLUL_E_ENDLESSWITHLOOPEMPTY, CSLUL_E_NOGOTOPREDECESSOR, CSLUL_E_CANTTAKENONE, CSLUL_E_TARGETTYPENOTARRAY, CSLUL_E_TARGETTYPENOTSTRUCT, CSLUL_E_CASEAFTERDEFAULT, CSLUL_E_DUPLICATEDEFAULT, CSLUL_E_DIVBYZERO, CSLUL_E_ARRAYVARIABLENESSDIFFER, CSLUL_E_ARRAYLENGTHDIFFER, CSLUL_E_ARRAYLENGTUNKNOWN, CSLUL_E_FLOATTOINT, CSLUL_E_SYSDEPTOFIXED, CSLUL_E_FIXEDTOSYSDEP, CSLUL_E_SIGNEDTOUNSIGNED, CSLUL_E_NARROWERRANGE, CSLUL_E_NUMREQUIREDBUTUNKNOWN, CSLUL_E_NUMREQUIRED, CSLUL_E_OPNOEFFECT, CSLUL_E_STRUCTSCOUNTDIFFER, CSLUL_E_TARGETTYPENOTCLOSED, CSLUL_E_SUBEXPRTYPENOTCLOSED, CSLUL_E_VERSIONEDCLOSEDTYPE, CSLUL_E_EXPECTEDVERORRCURLY, CSLUL_E_OPENWITHOUTREF, CSLUL_E_OPENTLDATA, CSLUL_E_STRUCTSOPEN, CSLUL_E_STRUCTTARGETOPEN, CSLUL_E_STRUCTSOURCEOPEN, CSLUL_E_DEREFNONREF, CSLUL_E_TARGETNOTREF, CSLUL_E_SLOTNONTYPEPARAM, CSLUL_E_TYPEPARAMWITHOUTSLOT, CSLUL_E_TYPEPARAMNOTFOUND, CSLUL_E_MLCOMMENTNOTCLOSED, CSLUL_E_MLCOMMENTNOTLINESTART, CSLUL_E_MODNAMEMISMATCH, CSLUL_E_BADLIBRARYTYPE, CSLUL_E_REQUIREDDEP, CSLUL_E_REQUIREDDEPVER, CSLUL_E_REQUIREDDEPVERSELF, CSLUL_E_MISSINGNESTEDONLY, CSLUL_E_IFACEDEPFLAGSCHANGE, CSLUL_E_CRNEWLINE, CSLUL_E_BADVERSIONFLAG, CSLUL_E_APPWITHOUTMAIN, CSLUL_E_MAINMALFORMED, CSLUL_E_MAINNOTAPP, CSLUL_E_DOUBLEUNDERSCORE, CSLUL_E_TYPEUNDERSCORE, /* Last normal error */ CSLUL_E_LAST, /* Internal errors */ CSLUL_INTERR_BASE = 0x1000, CSLUL_INTERR_MAX = 0x7FFF }; #define CSLUL_E_FIRST_ERRCODE 1 #define CSLUL_IS_INTERNAL_ERR(errcode) ((errcode) >= CSLUL_INTERR_BASE) #define CSLUL_IS_SYSTEM_ERR(errcode) ((errcode) == CSLUL_E_OUTOFMEMORY || \ (errcode) == CSLUL_E_OPENFILE || (errcode) == CSLUL_E_READFILE || \ (errcode) == CSLUL_E_CREATEFILE || (errcode) == CSLUL_E_WRITEFILE) /** Gets the "minor code" of internal errors. The minor code does not have a textual representation */ #define CSLUL_GET_INTERR_MINOR_CODE(errnum) ((errnum) & 0xFF) enum CSlulMessageLevel { /** Out of memory, a compiler bug or a language version mismatch has occurred. Continued compilation of the same compilation context is not possible */ CSLUL_L_FATAL = 0, /** There's an error in a source file */ CSLUL_L_ERROR, /** There's a warning (likely a programming error) in a source file */ CSLUL_L_WARNING, /** There's a notice (possible optimization or cleanup) in a source file */ CSLUL_L_NOTICE, /** Style remark */ CSLUL_L_STYLE }; enum CSlulLocationType { /** The entry is not used */ CSLUL_LT_INVALID = 0, /** Main location of an error */ CSLUL_LT_MAIN, /** Main location, with text instead of referencing a source span (length refers to the text message, not the source location) */ CSLUL_LT_MAINTEXT, /** Definition */ CSLUL_LT_DEFINITION, /** Defined in module or class */ CSLUL_LT_DEFINED_IN, /** Dependency (including interface dependency) */ CSLUL_LT_DEPENDENCY, /** Minimum (for versions or similar) */ CSLUL_LT_MINIMUM, /** Installed version */ CSLUL_LT_INSTALLED, /** Duplicate */ CSLUL_LT_DUPLICATE, /** Left expression */ CSLUL_LT_EXPR_LEFT, /** Right expression */ CSLUL_LT_EXPR_RIGHT, /** Source type */ CSLUL_LT_TYPE_SOURCE, /** Target type */ CSLUL_LT_TYPE_TARGET }; #define CSLUL_MAX_LOCATIONS 5 struct CSlulLocation { const char *filename; /** Type of location, or CSLUL_LT_INVALID if not in use */ enum CSlulLocationType type; int line, column; int length; /**< Size in bytes of the token/etc. */ const char *text; /**< Text of identifier/token. Not null terminated! */ /* TODO add a function for getting source text from a line (if available in the buffer, otherwise will need to read the buffer again (maybe not a good idea?)) */ }; struct CSlulState { struct CSlulConfig *cfg; /** Compilation context. NULL for errors from configuration functions */ struct CSlul *ctx; /** Current phase (buildfile, module interface or implementation) */ enum CSlulPhase phase; enum CSlulErrorCode errorcode; /**< Error code */ enum CSlulMessageLevel level; /**< Level: fatal/error/warning/notice */ /** Source code references */ struct CSlulLocation locs[CSLUL_MAX_LOCATIONS]; }; /** The size of an "API version hash" in bytes */ #define CSLUL_APIHASHBYTES 24 /** Characters in a Base64 encoded API version hash */ #define CSLUL_APIHASHCHARS 32 /** The dependency does not use versions and is bundled with the module */ #define CSLUL_DF_BUNDLED 0x1 /** The version can have API changes. Alpha/beta/rc versions should usually be marked with unstable_api. Not having this flags means that the module promises to never have breaking changes. Versions with this flag have severly limited utility. XXX detect API stability from the version number? "~"-versions (e.g. 1.0~alpha could be considered unstable). */ #define CSLUL_DF_UNSTABLE_API 0x2 /** Optional dependency. FIXME what should this mean? 1) statically checked at build time, or 2) loaded at runtime? */ #define CSLUL_DF_OPTIONAL 0x4 /** The dependency is only used by other dependencies. */ #define CSLUL_DF_NESTEDONLY 0x8 /** Interface-only dependency. This is an internal flag, since interface dependencies are added into the dependencies_root after parsing. */ #define CSLUL_DF_IFACEONLY 0x10 /** * Iterator for module dependencies for the current module. */ struct CSlulDepIter { size_t size; struct CSlulDependency *internal; const char *module_name; size_t modnamelen; const char *min_version; unsigned flags; }; /** * Iterator for interface dependencies for the current module. * * Interface dependencies are also visible in the module's interface. * Modules that depend on a module with an interface dependency also need * to add that dependency as a dependency itself (at least as "typesonly") */ struct CSlulInterfaceDepIter { size_t size; struct CSlulInterfaceDep *internal; int inited; const char *min_version; const char *since_version; size_t sinceverlen; }; struct CSlulSrcIter { size_t size; struct CSlulSourceFile *internal; const char *filename; size_t namelen; }; #define CSlulFile FILE * struct CSlulInitParams { size_t size; /**< Must be set to sizeof(CSlulInitParams) */ char dirsep; /**< Directory separator of the operating system */ /* FIXME should there be a "user pointer" for these? */ void *(*fptr_malloc)(size_t size); void (*fptr_free)(void *p); /** realloc is seldom called. Only for re-allocating the list of arenas */ void *(*fptr_realloc)(void *p, size_t size); CSlulFile (*fptr_fopen)(const char *filename, const char *mode); /** Creates an executable file for writing in binary mode */ CSlulFile (*fptr_createexec)(const char *filename); int (*fptr_fclose)(CSlulFile file); int (*fptr_ferror)(CSlulFile file); int (*fptr_remove)(const char *filename); size_t (*fptr_fwrite)(const void *buffer, size_t size, size_t nmemb, CSlulFile file); size_t (*fptr_fread)(void *buffer, size_t size, size_t nmemb, CSlulFile file); /** Creates a directory, and returns 1 if the directory exists now or 0 on error */ int (*fptr_mkdir)(const char *filename); /** Optional function that can be set for dropping privileges. If non-null, it is called after all files have been opened */ int (*fptr_dropprivs)(void); /* There is no point in adding memcpy etc. here, since those calls can be inserted by the compiler, so we have no control of those calls. */ }; enum CSlulToken { CSLUL_T_EOF = -1, CSLUL_T_NEEDDATA = 0, /* Long tokens */ CSLUL_T_Integer = 1, CSLUL_T_Float, CSLUL_T_GotoTarget, CSLUL_T_UpperIdent, CSLUL_T_LowerIdent, CSLUL_T_Version, CSLUL_T_String, CSLUL_T_Newline, /**< only returned for build files */ CSLUL_INT_Whitespace, /**< used internally */ CSLUL_INT_Comment, /**< used internally */ /* Parentheses */ CSLUL_T_LParen, CSLUL_T_RParen, CSLUL_T_LSquare, CSLUL_T_RSquare, CSLUL_T_LCurly, CSLUL_T_RCurly, /* Operators that allow can be combined with =, like += >= etc */ CSLUL_T_Plus, CSLUL_T_Minus, CSLUL_T_Asterisk, CSLUL_T_Slash, CSLUL_T_Less, CSLUL_T_Assign, CSLUL_T_Greater, CSLUL_T_Exclamation, /* Misc */ CSLUL_T_Comma, CSLUL_T_Dot, CSLUL_T_Question, CSLUL_T_Colon, CSLUL_T_Semicolon, /* Multi-character operators */ CSLUL_T_PlusAssign, CSLUL_T_MinusAssign, CSLUL_T_MultiplyAssign, CSLUL_T_DivideAssign, CSLUL_T_LessEqual, CSLUL_T_Equal, CSLUL_T_GreaterEqual, CSLUL_T_NotEqual, CSLUL_T_RArrow, /* Keyword operators */ CSLUL_T_KW_Not, CSLUL_T_KW_And, CSLUL_T_KW_Or, CSLUL_T_KW_Mod, CSLUL_T_KW_Deref, CSLUL_T_KW_RefTo, CSLUL_T_KW_RefIs, CSLUL_T_KW_RefIsNot, /* Keywords - Builtin values */ CSLUL_T_KW_None, CSLUL_T_KW_Undef, CSLUL_T_KW_This, CSLUL_T_KW_False, CSLUL_T_KW_True, /* Keywords - Top levels */ CSLUL_T_KW_Data, CSLUL_T_KW_Func, CSLUL_T_KW_Type, /* Keywords - Elementary types */ CSLUL_T_KW_Bool, CSLUL_T_KW_USize, CSLUL_T_KW_SSize, CSLUL_T_KW_FileOffs, /* A string is implemented as a pointer-sized item: - 0 is a null pointer. - Values 1 <= x <= 255 are single characters. - Otherwise it is a pointer to a "magic byte array". Magic byte arrays: - If it starts with byte 0-247 it is a zero-terminated string - If it starts with 248-255, then it is a "complex" string. bit 0x4 = chunked format bit 0x2|0x1 = size of length (0,1,2,3 = 8,16,32,64 bit length) Strings can be looped over: for byte b in s { ... } for uint32 codepoint in s { ... } # what value should be used for invalid UTF-8? FIXME this is problematic with strings that come from C and that are not strictly guaranteed to be UTF-8, if the strings starts with one of the control byte values 248-255. That will require a check of the first byte and maybe an allocation to create a "complex" string. */ CSLUL_T_KW_String, /* FIXME clean up integer types further? */ CSLUL_T_KW_Int8, CSLUL_T_KW_Byte, CSLUL_T_KW_WUInt8, CSLUL_T_KW_Int16, CSLUL_T_KW_UInt16, CSLUL_T_KW_WUInt16, CSLUL_T_KW_Int, /* 16 or 32 bit */ CSLUL_T_KW_UInt, CSLUL_T_KW_WUInt, CSLUL_T_KW_Int32, CSLUL_T_KW_UInt32, CSLUL_T_KW_WUInt32, CSLUL_T_KW_Int64, CSLUL_T_KW_UInt64, CSLUL_T_KW_WUInt64, /* Keywords - Other types */ CSLUL_T_KW_Ref, CSLUL_T_KW_Own, CSLUL_T_KW_Arena, CSLUL_T_KW_Slot, CSLUL_T_KW_FuncRef, CSLUL_T_KW_NoReturn, CSLUL_T_KW_Struct, CSLUL_T_KW_Enum, CSLUL_T_KW_Lifetime, CSLUL_T_KW_Since, /* Keywords - Qualifiers */ CSLUL_T_KW_Var, CSLUL_T_KW_WriteOnly, CSLUL_T_KW_Aliased, CSLUL_T_KW_Threaded, CSLUL_T_KW_Closed, /* TODO rename this to "frozen"? */ /* Keywords - Control statements */ CSLUL_T_KW_If, CSLUL_T_KW_Else, CSLUL_T_KW_While, CSLUL_T_KW_Do, CSLUL_T_KW_For, CSLUL_T_KW_In, CSLUL_T_KW_LoopEnd, CSLUL_T_KW_LoopEmpty, CSLUL_T_KW_Switch, CSLUL_T_KW_Case, CSLUL_T_KW_With, CSLUL_T_KW_Default, CSLUL_T_KW_SubCase, CSLUL_T_KW_Assert, CSLUL_T_KW_Break, CSLUL_T_KW_Continue, CSLUL_T_KW_Goto, CSLUL_T_KW_Return }; #define CSLUL_IS_IDENT(t) ((t) == CSLUL_T_UpperIdent || \ (t) == CSLUL_T_LowerIdent) #define CSLUL_IS_TOPLEVEL(t) ((t) >= CSLUL_T_KW_Data && \ (t) <= CSLUL_T_KW_Type) #define CSLUL_T_FirstQual CSLUL_T_KW_Var #define CSLUL_T_LastQual CSLUL_T_KW_Closed #define CSLUL_T_FirstElemType CSLUL_T_KW_Bool #define CSLUL_T_LastElemType CSLUL_T_KW_WUInt64 enum CSlulModuleHeaderToken { CSLUL_MHT_EOF = -1, CSLUL_MHT_NEEDDATA = 0, CSLUL_MHT_BareIdentifier, CSLUL_MHT_AttrName, CSLUL_MHT_AttrValue }; #define CSLUL_T_NONE_QUEUED CSLUL_T_NEEDDATA #define CSLUL_MHT_NONE_QUEUED CSLUL_MHT_NEEDDATA /** A module may be of one of these types. To combine multiple types (e.g. a library with some configuration utility), then a separate (sub)module should be used. */ enum CSlulModuleType { CSLUL_MT_INVALID = -1, CSLUL_MT_UNSET = 0, /** A module without any stable API. Builds to an object file by default, so it can be called within a project, possibly from other languages than SLUL */ CSLUL_MT_INTERNAL = 1, /** A module with a stable API that builds to a library. Libraries may be called from other languages than SLUL. (unstable versions are allowed in order to simplify development) */ CSLUL_MT_LIBRARY, /** A plugin that follows a "plugin specification". */ CSLUL_MT_PLUGIN, /** A specification for a library, i.e. which functions and data structures it should have. Libraries may implement a libraryspec */ CSLUL_MT_LIBRARYSPEC, /** A specification for a plugin. */ CSLUL_MT_PLUGINSPEC, /** An application */ CSLUL_MT_APP /* Future extensions? CSLUL_MT_WEBAPP - web application (running from e.g. a FastCGI server) CSLUL_MT_MOBILE - mobile application (or just use GUI?) CSLUL_MT_TCPSERVER - a server (could be compiled to use inetd, systemd or work as a plain unix daemon... or WinNT service) CSLUL_MT_SERVICE - general purpose system service */ }; enum CSlulOutputType { CSLUL_OT_AUTO, /**< Module type decides output type */ CSLUL_OT_CHECK, /**< Just check, do not generate output */ CSLUL_OT_OBJFILE, /**< Output an object file (and C header? */ CSLUL_OT_LIBRARY, /**< Output dynamic library, static lib (and C header? */ CSLUL_OT_DYNLIB, /**< Output a dynamic library (and C header?) */ CSLUL_OT_STATLIB, /**< Output a static library (and C header?) */ CSLUL_OT_HEADER, /**< Output a C header only */ CSLUL_OT_PLUGIN, /**< Output a plugin */ CSLUL_OT_EXE /**< Output an executable */ }; /** * Handler for fatal/error/warning/notice messages. */ typedef void CSlulMessageHandler(const struct CSlulState *state); /* ========================= Configurqtion ========================= */ /** * Creates a configuration object with the givem parameters (function * pointers to system functions), and defaults for everything else. * * Configuration objects are used to override the defaults when creating a * compilatiom context (struct CSlul). * * \param params Functions for memory allocation and file I/O. * Optional, may be NULL, for system defaults: * malloc/stdio for POSIX, kernel32 APIs for Windows. * \return New configuratiom object */ struct CSlulConfig *cslul_config_create( const struct CSlulInitParams *params); /** * Frees a configuration object */ void cslul_config_free(struct CSlulConfig *cfg); /** * Sets the minimum message level to report to the message handler. */ void cslul_config_set_message_level(struct CSlulConfig *cfg, enum CSlulMessageLevel level); /** * Sets the function that will receive error/warning messages. * * \param cfg Configuration object * \param mh Message handler. Set to NULL to ignore messages */ void cslul_config_set_message_handler(struct CSlulConfig *cfg, CSlulMessageHandler *mh); #if 0 /** * Sets a compiler option (e.g. output directory). * See enum CSlulStringOpt * * Options may not be changed after parsing has begun. * * \param cfg Configuration object * \param option Option number * \param value String value * \return 1 if the option was set, 0 if the option did not exist * (or was not applicable) or the value was invalid. */ int cslul_config_set_string(struct CSlulConfig *cfg, enum CSlulStringOpt option, const char *value); /** * Sets a compiler option (e.g. output type). * See enum CSlulIntOpt * * Options may not be changed after parsing has begun. * * \param cfg Configuration object * \param option Option number * \param value Integer (or boolean or enum) value * \return 1 if the option was set, 0 if the option did not exist * (or was not applicable) or the value was invalid. */ int cslul_config_set_int(struct CSlulConfig *cfg, enum CSlulIntOpt option, int value); #endif /** * Adds an interface directory. They should be added in the following order: * 1. Distribution's system directories (e.g. /usr/share/slul-interfaces) * 2. Custom system directories (e.g. /usr/local/share/slul-interfaces) * 3. User directories (e.g. ~/.local/share/slul-interfaces) * 4. Vendored project directories (e.g. ~/project/bundled/slul-interfaces) * * Do NOT free the string until all compilation contexts that use the *configuration have been freed. * * \return 1 on success, 0 on error (e.g. out of memory) */ int cslul_config_add_iface_dir(struct CSlulConfig *cfg, const char *path); /** * Adds the default interface directories based on which the operating * system is, on environment variables, and on data returned from * system functions. * * The system functions that this function calls are not necessarilly * thead-safe. * * \return 1 on success, 0 on error (e.g. out of memory) */ int cslul_config_add_default_iface_dirs(struct CSlulConfig *cfg); /** * Adds the host architecture as a target. * * \return 1 on success, 0 on error (e.g. out of memory) */ int cslul_config_add_host_arch(struct CSlulConfig *cfg); /** * Adds an architecture as a target. * * \param cfg Configuration object * \param archtriple Architecture triple (e.g. "x86_64-linux-gnu") * \return 1 on success, 0 on error (e.g. out of memory) */ int cslul_config_add_arch(struct CSlulConfig *cfg, const char *archtriple); /** * Add one or more architectures as targets. Separate architectures by comma. * * \param cfg Configuration object * \param archtriple Comma-separated list of architecture triples * \return 1 on success, 0 on error (e.g. out of memory) */ int cslul_config_add_arches(struct CSlulConfig *cfg, const char *archtriples); /** * Sets the output type. By default, it is auto-detected for the module * being compiled. */ void cslul_config_set_output_type(struct CSlulConfig *cfg, enum CSlulOutputType outtype); /** * Sets the output directory. By default, the current directory is used. * * When compiling for multiple architectures, a separate directory structure * will be used: bin// for executables and lib// * for libraries. */ void cslul_config_set_output_directory(struct CSlulConfig *cfg, const char *dir); /** * Returns 1 if the configuration has any errors (even if errors are turned * off). Note that file paths are NOT checked. */ int cslul_config_has_errors(struct CSlulConfig *cfg); /* ========================= Initialization ========================= */ /** * Creates a compilation context. You always have to create a compilation * context. * * A compilation context has six phases: * 1. Parsing module header (initial mode) * 2. Parsing the interface of the module * 3. Parsing the implementation of the module * 4. Parsing the interfaces of dependencies * 5. Semantic verifiation * 6. Code generation * * Usually you will only have one compilation context, but if you wish * to compile multiple modules at the same time, you can use multiple * compilation contexts, and possibly in parallel threads. Another * possibly use of compilation contexts is for starting fresh after * a compilation error. * * When using default settings (NULL), system functions that are not necessarilly * thead-safe might be called by this function. * * \param config Optional configuration, or NULL for defsults. * \return Compilation context, or NULL on out-of-memory error. */ struct CSlul *cslul_create(const struct CSlulConfig *config); /** * Frees a compilation context. */ void cslul_free(struct CSlul *ctx); /** * Returns the supported language versions as a space separated, * null-terminated, string. * * \returns List of supported languages. Do not free or modify. */ const char *cslul_supported_langver(void); /** * Looks up the text of an error message. The returned value is a format string * suitable for translation. * * For internal errors, it returns the name (without file extension) of the file * where the error occurred. This data should not be translated. * * \return Null-terminated string, or NULL if the message code is invalid. */ const char *cslul_lookup_message(enum CSlulErrorCode errorcode); /* ======================= Simple compilation ======================= */ /** * Compiles and generates output files in the given directory. * * The filename encoding should be practically always be UTF-8. * - Always UTF-8 on Windows (it is converted automatically). * - The "file system encoding" on other systems. This is almost always * UTF-8 except on ancient systems. * * \param ctx Compilation context * \param directory Directory. NULL means current directory * \return 1 on success, 0 on failure (then the message handler is called). */ int cslul_build(struct CSlul *ctx, const char *directory); /* ====================== Low level compilation ===================== */ /** * Progresses to a subsequent compilation phase. It is not possible to * go backwards. * * \param ctx Compilation context * \param phase Phase * \return 1 if successful, 0 if not */ int cslul_ll_start_phase(struct CSlul *ctx, enum CSlulPhase phase); /** * Leaves the module header of a module dependency, and prepares * for parsing the module interface. */ void cslul_ll_leave_dep_moduleheader(struct CSlul *ctx); /** * Sets the file name of the current file. Call this function before * calling cslul_ll_set_input_buffer. Calling this with a NULL * argument clears the filename, so the filename will not incorrectly * appear in unrelated error messages. * * NOTE: Do not free or modify the filename string until * until ctx has been free'd. It may be used when reporting errors, * from other files, that reference identifiers in this file. * * \param ctx Compilation context * \param filename Current filename */ void cslul_ll_set_current_filename(struct CSlul *ctx, const char *filename); /** * Sets the compilation input buffer. The input source code must be in * UTF-8 encoding without byte order marks (or other control characters * other than newlines and spaces). * * \param ctx Compilation context * \param buffer Source code buffer * \param buffer_size Size of buffer in bytes * \param is_last 0 if there are more buffers, 1 if this is the last one. */ void cslul_ll_set_input_buffer(struct CSlul *ctx, const char *buffer, size_t buffer_size, int is_last); /** * Advances to the next token. Must also be called one time to go the * first token. There must be enough buffer data (set by * cslul_ll_set_input_buffer). * * Do NOT call this function if you are parsing with any of the "simple" * functions or using cslul_ll_parse. Those functions call this function * automatically when needed. * * \return The token, or CSLUL_T_NEEDDATA when the next buffer needs to be * set with cslul_ll_set_input_buffer, or CSLUL_T_EOF when end of * file is reached. */ enum CSlulToken cslul_ll_next_slul_token(struct CSlul *ctx); /** * Like cslul_ll_next_slul_token, but parses a token from a module header. * * You should switch to parsing regular SLUL tokens when a * CSLUL_MHT_AttrName with the name "end" is reached. * * \return The token, or CSLUL_MH_NEEDDATA when the next buffer needs to be * set with cslul_ll_set_input_buffer, or CSLUL_MH_EOF if end of * file is reached. */ enum CSlulModuleHeaderToken cslul_ll_next_mh_token(struct CSlul *ctx); /** * Get current token value. For identifiers, this is the name, * and for strings, this is the unescaped value. The returned * string is NOT null-terminated. */ void cslul_ll_current_value(struct CSlul *ctx, const char **name, size_t *length); /** * Parses data from the current input buffer. Note that the main.slul * file needs to be parsed in two phases, first one for the module header, * and then the interface or implementation code (depending on module type). */ void cslul_ll_parse(struct CSlul *ctx); /** * Returns 1 if the compilation context has any errors * (parsing errors, semantic errors or fatal errors * such as out of memory). */ int cslul_ll_has_errors(struct CSlul *ctx); /** * Returns 1 if the compilation context has fatal errors * (such as out of memory, internal compiler errors and * language version mismatch). * Do not continue parsing in that case. */ int cslul_ll_has_fatal_errors(struct CSlul *ctx); /** * Once the module header has been parsed, this function can be called * to obtain a list of modules that are required. Call it repeatedly * until it returns 0. * * You must set depiter.module_name=NULL before the first call. * * \return 1 if an item was placed in depiter, 0 if there * are no more results. */ int cslul_ll_dependency_iter(struct CSlul *ctx, struct CSlulDepIter *depiter); /** * Initializes parsing of the module that "depiter" refers to. * The filename and buffer must be set afterwards with * cslul_ll_set_current_filename and cslul_ll_set_input_buffer. * * \return 1 if successful, 0 on out of memory or similar. */ int cslul_ll_start_parsing_dep(struct CSlul *ctx, struct CSlulDepIter *depiter, const char *filename); /** * Finalizes parsing of a module dependency. */ void cslul_ll_done_parsing_dep(struct CSlul *ctx); /** * A module interface itself can depend on a module, if it needs types * from the dependency in its declarations. * * If the module interface does not use any types from the dependency, * then this should be an empty list. If the module interface has several * versions, it is possible that the dependency's version number has * increased between the versions. In that case, multiple entries will * be returned. * * You must set ifacedepiter.inited=0 before the first call. * * \return 1 if an item was placed in ifacedepiter, 0 if there * are no more results. */ int cslul_ll_ifacedep_iter(struct CSlul *ctx, struct CSlulDepIter *dep, struct CSlulInterfaceDepIter *iter); /** * Once the module header has been parsed, this function can be called * to obtain the list of source file names (interface files are not * included in the result). Call it repeatedly until it returns 0 * to get all file names. * * You must set srciter.filename=NULL before the first call. * * \param ctx Compilation context * \param srciter Iterator structure * \return 1 if an item was placed in srciter, 0 if there * are no more results. */ int cslul_ll_implsource_iter(struct CSlul *ctx, struct CSlulSrcIter *srciter); #endif