diff --git a/.clangd b/.clangd index 098375d..8b2f6a1 100644 --- a/.clangd +++ b/.clangd @@ -1,4 +1,2 @@ -CompileFlags: # Tweak the parse settings, example directory given to show format - Add: - - "-std=c++2b" - - "-I/opt/homebrew/opt/llvm/include" \ No newline at end of file +CompileFlags: + CompileCommandsDir: . \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fd2b60a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,20 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Install xmake + run: | + curl -fsSL https://xmake.io/shget.text | sh + - name: Configure and build + run: | + xmake f -m debug + xmake + - name: Run tests + run: | + xmake run test diff --git a/.gitignore b/.gitignore index 1521057..d472c05 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ build/ # MacOS Cache .DS_Store - +# Clanged Cache +.clangd/ +.cache/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 112e5f2..1c1c1ad 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,8 @@ "*.db": "sql", "*.v": "verilog", "*.fs": "fsharp", - "*.py": "python" + "*.py": "python", + "*.def": "cpp", }, "files.autoSave": "afterDelay", "explorer.confirmDelete": false, diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..e367323 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,21 @@ +[ +{ + "directory": "/Volumes/Container/Projects/Helix/helix-lang", + "arguments": ["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-c", "-Qunused-arguments", "-target", "arm64-apple-macos14.5", "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk", "-g", "-Wall", "-O3", "-std=c++2b", "-I", "/Users/dhruvan/.xmake/packages/c/catch2/v3.6.0/0a747bbcabc64c97b99b19d67325207e/include", "-stdlib=libc++", "-fno-rtti", "-I/opt/llvm-aarch64/include", "-o", "build/.objs/test/macosx/arm64/debug/tests/test_tokens.cc.o", "tests/test_tokens.cc"], + "file": "tests/test_tokens.cc" +}, +{ + "directory": "/Volumes/Container/Projects/Helix/helix-lang", + "arguments": ["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-c", "-Qunused-arguments", "-target", "arm64-apple-macos14.5", "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk", "-g", "-Wall", "-O3", "-std=c++2b", "-stdlib=libc++", "-fno-rtti", "-I/opt/llvm-aarch64/include", "-o", "build/.objs/helix-lang/macosx/arm64/debug/source/main.cc.o", "source/main.cc"], + "file": "source/main.cc" +}, +{ + "directory": "/Volumes/Container/Projects/Helix/helix-lang", + "arguments": ["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-c", "-Qunused-arguments", "-target", "arm64-apple-macos14.5", "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk", "-g", "-Wall", "-O3", "-std=c++2b", "-stdlib=libc++", "-fno-rtti", "-I/opt/llvm-aarch64/include", "-o", "build/.objs/helix-lang/macosx/arm64/debug/source/cli/cli.cc.o", "source/cli/cli.cc"], + "file": "source/cli/cli.cc" +}, +{ + "directory": "/Volumes/Container/Projects/Helix/helix-lang", + "arguments": ["/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang", "-c", "-Qunused-arguments", "-target", "arm64-apple-macos14.5", "-isysroot", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk", "-g", "-Wall", "-O3", "-std=c++2b", "-stdlib=libc++", "-fno-rtti", "-I/opt/llvm-aarch64/include", "-o", "build/.objs/helix-lang/macosx/arm64/debug/source/parser/cpp/fn_signatures.cc.o", "source/parser/cpp/fn_signatures.cc"], + "file": "source/parser/cpp/fn_signatures.cc" +}] diff --git a/source/codegen/cpp/emitter.hh b/source/generator/cpp/emitter.hh similarity index 100% rename from source/codegen/cpp/emitter.hh rename to source/generator/cpp/emitter.hh diff --git a/source/codegen/llvm/emitter.hh b/source/generator/llvm/emitter.hh similarity index 100% rename from source/codegen/llvm/emitter.hh rename to source/generator/llvm/emitter.hh diff --git a/source/token/define.hh b/source/token/define.hh deleted file mode 100644 index abe20d0..0000000 --- a/source/token/define.hh +++ /dev/null @@ -1,405 +0,0 @@ -#ifndef __DEFINE_H__ -#define __DEFINE_H__ - -#include -#include -#include -#include - -#include "../include/inttypes.hh" - -using std::string; - -template -struct Mapping { - std::array, N> data; - - [[nodiscard]] constexpr std::optional at(std::string_view x) const noexcept { - for (const auto &[key, value] : data) { - if (value == x) - return key; - } - return std::nullopt; - } - - [[nodiscard]] constexpr std::optional at(Enum x) const noexcept { - for (const auto &[key, value] : data) { - if (key == x) - return value; - } - return std::nullopt; - } -}; - -namespace token { -enum keywords { - /* ==-------- control flow -------== */ - IF, // if - ELSE, // else - UNLESS, // unless - /* ==----------- macros ----------== */ - MACRO, // macro - DEFINE, // define - /* ==--------- functions ---------== */ - FUNCTION, // fn - OPERATOR, // op - INLINE, // inline - RETURN, // return - ENCLOSING, // enclosing - /* ==-------- concurrency --------== */ - ASYNC, // async - SPAWN, // spawn - AWAIT, // await - THREAD, // thread - /* ==----------- loops -----------== */ - FOR, // for - WHILE, // while - BREAK, // break - CONTINUE, // continue - /* ==---- control structures ----== */ - CASE, // case - MATCH, // match - SWITCH, // switch - DEFAULT, // default - /* ==------ data structures ------== */ - ENUM, // enum - TYPE, // type - CLASS, // class - UNION, // union - STRUCT, // struct - DERIVES, // derives - ABSTRACT, // abstract - INTERFACE, // interface - /* ==------- type checking -------== */ - IS, // is - /* ==------ error handling ------== */ - TRY, // try - PANIC, // panic - CATCH, // catch - FINALLY, // finally - /* ==--- variable declaration ---== */ - LET, // let - PRIVATE, // priv - AUTO, // auto - CONST, // const - GLOBAL, // global // TODO: Add to syntax - /* ==------- module system -------== */ - FROM, // from - USING, // using - IMPORT, // import - EXTERN, // extern // TODO: Add to syntax - AS, // as // TODO: Add to syntax - /* ==--------- generators --------== */ - YIELD, // yield - /* ==----------- others ----------== */ - NAMESPACE // namespace - /* ==--------- end of list -------== */ -}; - -constexpr Mapping keywords_map{{std::pair{IF, "if"}, - std::pair{ELSE, "else"}, - std::pair{UNLESS, "unless"}, - std::pair{MACRO, "macro"}, - std::pair{DEFINE, "define"}, - std::pair{FUNCTION, "fn"}, - std::pair{OPERATOR, "op"}, - std::pair{INLINE, "inline"}, - std::pair{RETURN, "return"}, - std::pair{ENCLOSING, "enclosing"}, - std::pair{ASYNC, "async"}, - std::pair{SPAWN, "spawn"}, - std::pair{AWAIT, "await"}, - std::pair{THREAD, "thread"}, - std::pair{FOR, "for"}, - std::pair{WHILE, "while"}, - std::pair{BREAK, "break"}, - std::pair{CONTINUE, "continue"}, - std::pair{CASE, "case"}, - std::pair{MATCH, "match"}, - std::pair{SWITCH, "switch"}, - std::pair{DEFAULT, "default"}, - std::pair{ENUM, "enum"}, - std::pair{TYPE, "type"}, - std::pair{CLASS, "class"}, - std::pair{UNION, "union"}, - std::pair{STRUCT, "struct"}, - std::pair{ABSTRACT, "abstract"}, - std::pair{INTERFACE, "interface"}, - std::pair{IS, "is"}, - std::pair{TRY, "try"}, - std::pair{PANIC, "panic"}, - std::pair{CATCH, "catch"}, - std::pair{FINALLY, "finally"}, - std::pair{LET, "let"}, - std::pair{PRIVATE, "priv"}, - std::pair{AUTO, "auto"}, - std::pair{CONST, "const"}, - std::pair{GLOBAL, "global"}, - std::pair{FROM, "from"}, - std::pair{USING, "using"}, - std::pair{IMPORT, "import"}, - std::pair{EXTERN, "extern"}, - std::pair{YIELD, "yield"}, - std::pair{AS, "as"}, - std::pair{DERIVES, "derives"}, - std::pair{NAMESPACE, "namespace"}}}; - -enum primitives { - /* ==---------- 1 byte -----------== */ - VOID, // void - BOOL, // bool - BYTE, // byte - /* ==---------- 4 bytes ----------== */ - CHAR, // char - POINTER, // ptr - /* ==---------- 8 bytes ----------== */ - I8, // i8 - U8, // u8 - /* ==---------- 16 bytes ---------== */ - I16, // i16 - U16, // u16 - /* ==---------- 32 bytes ---------== */ - I32, // i32 - U32, // u32 - F32, // f32 - /* ==---------- 64 bytes ---------== */ - I64, // i64 - U64, // u64 - F64, // f64 - /* ==--------- 128 bytes ---------== */ - FLOAT, // float - I128, // i128 - U128, // u128 - /* ==---- 4 + infinite bytes -----== */ - INT, // int - DECIMAL, // decimal - STRING, // string - LIST, // list - TUPLE, // tuple - SET, // set - MAP, // map - ANY, // any - /* ==--------- end of list -------== */ -}; - -constexpr Mapping primitives_map{ - {std::pair{VOID, "void"}, std::pair{BOOL, "bool"}, std::pair{BYTE, "byte"}, - std::pair{CHAR, "char"}, std::pair{POINTER, "ptr"}, std::pair{I8, "i8"}, - std::pair{U8, "u8"}, std::pair{I16, "i16"}, std::pair{U16, "u16"}, - std::pair{I32, "i32"}, std::pair{U32, "u32"}, std::pair{F32, "f32"}, - std::pair{I64, "i64"}, std::pair{U64, "u64"}, std::pair{F64, "f64"}, - std::pair{FLOAT, "float"}, std::pair{I128, "i128"}, std::pair{U128, "u128"}, - std::pair{INT, "int"}, std::pair{DECIMAL, "decimal"}, std::pair{STRING, "string"}, - std::pair{LIST, "list"}, std::pair{TUPLE, "tuple"}, std::pair{SET, "set"}, - std::pair{MAP, "map"}, std::pair{ANY, "any"}}}; - -enum operators { - /* ==--------- arithmetic --------== */ - ADD, // + - SUB, // - - MUL, // * - DIV, // / - MOD, // % - MAT, // @ - POW, // ** - ABS, // +- - /* ==---------- bitwise ----------== */ - BITWISE_AND, // & - BITWISE_NAND, // ~& - BITWISE_OR, // | - BITWISE_NOR, // ~| - BITWISE_XOR, // ^ - BITWISE_NOT, // ~ - BITWISE_L_SHIFT, // << - BITWISE_R_SHIFT, // >> - /* ==--------- relational --------== */ - EQUAL, // == - NOT_EQUAL, // != - GREATER_THAN, // > - LESS_THAN, // < - GREATER_THAN_EQUALS, // >= - LESS_THAN_EQUALS, // <= - REF_EQUAL, // === - /* ==--------- assignment --------== */ - ASSIGN, // = - ADD_ASSIGN, // += - SUB_ASSIGN, // -= - MUL_ASSIGN, // *= - DIV_ASSIGN, // /= - MOD_ASSIGN, // %= - MAT_ASSIGN, // @= - NOT_ASSIGN, // ~= - POWER_ASSIGN, // **= - /* ==------ logic assignment -----== */ - AND_ASSIGN, // &&= - NAND_ASSIGN, // !&= - OR_ASSIGN, // ||= - NOR_ASSIGN, // !|= - XOR_ASSIGN, // ^^= - /* ==----- bitwise assignment ----== */ - BITWISE_AND_ASSIGN, // &= - BITWISE_NAND_ASSIGN, // ~&= - BITWISE_OR_ASSIGN, // |= - BITWISE_NOR_ASSIGN, // ~|= - BITWISE_XOR_ASSIGN, // ^= - BITWISE_NOT_ASSIGN, // ~= - BITWISE_L_SHIFT_ASSIGN, // <<= - BITWISE_R_SHIFT_ASSIGN, // >>= - /* ==---------- increment --------== */ - INC, // ++ - DEC, // -- - /* ==---------- logical ----------== */ - LOGICAL_NOT, // ! - LOGICAL_AND, // && - LOGICAL_NAND, // !& - LOGICAL_OR, // || - LOGICAL_NOR, // !| - LOGICAL_XOR, // ^^ - /* ==----------- range -----------== */ - RANGE, // .. - RANGE_INCLUSIVE, // ..= - /* ==----------- member ----------== */ - ARROW, // -> - /* ==----------- scope -----------== */ - SCOPE, // :: - /* ==-------- end of list --------== */ -}; - -constexpr Mapping operators_map{{std::pair{ADD, "+"}, - std::pair{SUB, "-"}, - std::pair{MUL, "*"}, - std::pair{DIV, "/"}, - std::pair{MOD, "%"}, - std::pair{MAT, "@"}, - std::pair{POW, "**"}, - std::pair{ABS, "+-"}, - std::pair{BITWISE_AND, "&"}, - std::pair{BITWISE_NAND, "~&"}, - std::pair{BITWISE_OR, "|"}, - std::pair{BITWISE_NOR, "~|"}, - std::pair{BITWISE_XOR, "^"}, - std::pair{BITWISE_NOT, "~"}, - std::pair{BITWISE_L_SHIFT, "<<"}, - std::pair{BITWISE_R_SHIFT, ">>"}, - std::pair{EQUAL, "=="}, - std::pair{NOT_EQUAL, "!="}, - std::pair{GREATER_THAN, ">"}, - std::pair{LESS_THAN, "<"}, - std::pair{GREATER_THAN_EQUALS, ">="}, - std::pair{LESS_THAN_EQUALS, "<="}, - std::pair{REF_EQUAL, "==="}, - std::pair{ASSIGN, "="}, - std::pair{ADD_ASSIGN, "+="}, - std::pair{SUB_ASSIGN, "-="}, - std::pair{MUL_ASSIGN, "*="}, - std::pair{DIV_ASSIGN, "/="}, - std::pair{MOD_ASSIGN, "%="}, - std::pair{MAT_ASSIGN, "@="}, - std::pair{NOT_ASSIGN, "~="}, - std::pair{POWER_ASSIGN, "**="}, - std::pair{AND_ASSIGN, "&&="}, - std::pair{NAND_ASSIGN, "!&="}, - std::pair{OR_ASSIGN, "||="}, - std::pair{NOR_ASSIGN, "!|="}, - std::pair{XOR_ASSIGN, "^^="}, - std::pair{BITWISE_AND_ASSIGN, "&="}, - std::pair{BITWISE_NAND_ASSIGN, "~&="}, - std::pair{BITWISE_OR_ASSIGN, "|="}, - std::pair{BITWISE_NOR_ASSIGN, "~|"}, - std::pair{BITWISE_XOR_ASSIGN, "^="}, - std::pair{BITWISE_NOT_ASSIGN, "~="}, - std::pair{BITWISE_L_SHIFT_ASSIGN, "<<="}, - std::pair{BITWISE_R_SHIFT_ASSIGN, ">>="}, - std::pair{INC, "++"}, - std::pair{DEC, "--"}, - std::pair{LOGICAL_NOT, "!"}, - std::pair{LOGICAL_AND, "&&"}, - std::pair{LOGICAL_NAND, "!&"}, - std::pair{LOGICAL_OR, "||"}, - std::pair{LOGICAL_NOR, "!|"}, - std::pair{LOGICAL_XOR, "^^"}, - std::pair{RANGE, ".."}, - std::pair{RANGE_INCLUSIVE, "..="}, - std::pair{ARROW, "->"}, - std::pair{SCOPE, "::"}}}; - -enum literals { - /* ==---------- boolean ----------== */ - TRUE, // true - FALSE, // false - /* ==---------- integer ----------== */ - INTEGER, // 0 - COMPLIER_DIRECTIVE, // #[] - /* ==---------- floating ---------== */ - FLOATING, // 0.0 - /* ==----- character / string ----== */ - STRING_LITERAL, // "" - CHAR_LITERAL, // '' - /* ==-------- end of list --------== */ -}; - -constexpr Mapping literals_map{ - {std::pair{TRUE, "true"}, std::pair{FALSE, "false"}, std::pair{INTEGER, "0"}, - std::pair{FLOATING, "0.0"}, std::pair{STRING_LITERAL, "\"\""}, std::pair{CHAR_LITERAL, "''"}, - std::pair{COMPLIER_DIRECTIVE, "#[]"}}}; - -enum punctuation { - /* ==--------- brackets ----------== */ - OPEN_PAREN, // ( - CLOSE_PAREN, // ) - OPEN_BRACE, // { - CLOSE_BRACE, // } - OPEN_BRACKET, // [ - CLOSE_BRACKET, // ] - OPEN_ANGLE, // < - CLOSE_ANGLE, // > - /* ==--------- operators ---------== */ - COMMA, // , - SEMICOLON, // ; - COLON, // : - QUESTION_MARK, // ? - DOT, // . - HASH, // # - /* ==---------- comments ---------== */ - SINGLE_LINE_COMMENT, // // - MULTI_LINE_COMMENT, // /* - /* ==--------- end of list -------== */ -}; - -constexpr Mapping punctuation_map{ - {std::pair{OPEN_PAREN, "("}, std::pair{CLOSE_PAREN, ")"}, std::pair{OPEN_BRACE, "{"}, - std::pair{CLOSE_BRACE, "}"}, std::pair{OPEN_BRACKET, "["}, std::pair{CLOSE_BRACKET, "]"}, - std::pair{OPEN_ANGLE, "<"}, std::pair{CLOSE_ANGLE, ">"}, std::pair{COMMA, ","}, - std::pair{SEMICOLON, ";"}, std::pair{COLON, ":"}, std::pair{QUESTION_MARK, "?"}, - std::pair{DOT, "."}, std::pair{SINGLE_LINE_COMMENT, "//"}, std::pair{MULTI_LINE_COMMENT, "/*"}, - std::pair{HASH, "#"}}}; - -enum delimiters { - /* ==-------- whitespace ---------== */ - TAB, // \t - NEWLINE, // \n - SPACE, // ' ' - /* ==-------- end of list --------== */ -}; - -constexpr Mapping delimiters_map{ - {std::pair{TAB, "\t"}, std::pair{NEWLINE, "\n"}, std::pair{SPACE, " "}}}; - -enum identifiers { - /* ==--------- identifiers -------== */ - IDENTIFIER, // id - /* ==--------- end of list -------== */ -}; - -enum discriminant { - KEYWORDS, - PRIMITIVES, - OPERATORS, - LITERALS, - PUNCTUATION, - DELIMITERS, - IDENTIFIERS -}; -} // namespace token - -#endif // __DEFINE_H__ \ No newline at end of file diff --git a/source/token/enums/delimiters.def b/source/token/enums/delimiters.def new file mode 100644 index 0000000..2f9d6a3 --- /dev/null +++ b/source/token/enums/delimiters.def @@ -0,0 +1,11 @@ +#ifndef __DELIMITERS_H__ +#define __DELIMITERS_H__ + +#define DELIMITER_TOKENS_COUNT 3 + +#define DELIMITER_TOKENS(MACRO) \ + MACRO(DELIMITER_TAB, "\t") \ + MACRO(DELIMITER_NEWLINE, "\n") \ + MACRO(DELIMITER_SPACE, " ") + +#endif // __DELIMITERS_H__ \ No newline at end of file diff --git a/source/token/enums/keywords.def b/source/token/enums/keywords.def new file mode 100644 index 0000000..2e369e6 --- /dev/null +++ b/source/token/enums/keywords.def @@ -0,0 +1,55 @@ +#ifndef __KEYWORDS_H__ +#define __KEYWORDS_H__ + +#define KEYWORD_TOKENS_COUNT 47 + +#define KEYWORD_TOKENS(MACRO) \ + MACRO(KEYWORD_IF, "if") \ + MACRO(KEYWORD_ELSE, "else") \ + MACRO(KEYWORD_UNLESS, "unless") \ + MACRO(KEYWORD_MACRO, "macro") \ + MACRO(KEYWORD_DEFINE, "define") \ + MACRO(KEYWORD_FUNCTION, "fn") \ + MACRO(KEYWORD_OPERATOR, "op") \ + MACRO(KEYWORD_INLINE, "inline") \ + MACRO(KEYWORD_RETURN, "return") \ + MACRO(KEYWORD_ENCLOSING, "enclosing") \ + MACRO(KEYWORD_ASYNC, "async") \ + MACRO(KEYWORD_SPAWN, "spawn") \ + MACRO(KEYWORD_AWAIT, "await") \ + MACRO(KEYWORD_THREAD, "thread") \ + MACRO(KEYWORD_FOR, "for") \ + MACRO(KEYWORD_WHILE, "while") \ + MACRO(KEYWORD_BREAK, "break") \ + MACRO(KEYWORD_CONTINUE, "continue") \ + MACRO(KEYWORD_CASE, "case") \ + MACRO(KEYWORD_MATCH, "match") \ + MACRO(KEYWORD_SWITCH, "switch") \ + MACRO(KEYWORD_DEFAULT, "default") \ + MACRO(KEYWORD_ENUM, "enum") \ + MACRO(KEYWORD_TYPE, "type") \ + MACRO(KEYWORD_CLASS, "class") \ + MACRO(KEYWORD_UNION, "union") \ + MACRO(KEYWORD_STRUCT, "struct") \ + MACRO(KEYWORD_ABSTRACT, "abstract") \ + MACRO(KEYWORD_INTERFACE, "interface") \ + MACRO(KEYWORD_IS, "is") \ + MACRO(KEYWORD_TRY, "try") \ + MACRO(KEYWORD_PANIC, "panic") \ + MACRO(KEYWORD_CATCH, "catch") \ + MACRO(KEYWORD_FINALLY, "finally") \ + MACRO(KEYWORD_LET, "let") \ + MACRO(KEYWORD_PRIVATE, "priv") \ + MACRO(KEYWORD_AUTO, "auto") \ + MACRO(KEYWORD_CONST, "const") \ + MACRO(KEYWORD_GLOBAL, "global") \ + MACRO(KEYWORD_FROM, "from") \ + MACRO(KEYWORD_USING, "using") \ + MACRO(KEYWORD_IMPORT, "import") \ + MACRO(KEYWORD_EXTERN, "extern") \ + MACRO(KEYWORD_YIELD, "yield") \ + MACRO(KEYWORD_AS, "as") \ + MACRO(KEYWORD_DERIVES, "derives") \ + MACRO(KEYWORD_NAMESPACE, "namespace") + +#endif // __KEYWORDS_H__ \ No newline at end of file diff --git a/source/token/enums/literals.def b/source/token/enums/literals.def new file mode 100644 index 0000000..0c12cf7 --- /dev/null +++ b/source/token/enums/literals.def @@ -0,0 +1,15 @@ +#ifndef __LITERALS_H__ +#define __LITERALS_H__ + +#define LITERAL_TOKENS_COUNT 7 + +#define LITERAL_TOKENS(MACRO) \ + MACRO(LITERAL_TRUE, "true") \ + MACRO(LITERAL_FALSE, "false") \ + MACRO(LITERAL_INTEGER, "integer") \ + MACRO(LITERAL_COMPLIER_DIRECTIVE, "complier_directive") \ + MACRO(LITERAL_FLOATING_POINT, "floating_point") \ + MACRO(LITERAL_STRING, "string") \ + MACRO(LITERAL_CHAR, "char") + +#endif // __LITERALS_H__ \ No newline at end of file diff --git a/source/token/enums/operators.def b/source/token/enums/operators.def new file mode 100644 index 0000000..f294e8e --- /dev/null +++ b/source/token/enums/operators.def @@ -0,0 +1,65 @@ +#ifndef __OPERATORS_H__ +#define __OPERATORS_H__ + +#define OPERATOR_TOKENS_COUNT 57 + +#define OPERATOR_TOKENS(MACRO) \ + MACRO(OPERATOR_ADD, "+") \ + MACRO(OPERATOR_SUB, "-") \ + MACRO(OPERATOR_MUL, "*") \ + MACRO(OPERATOR_DIV, "/") \ + MACRO(OPERATOR_MOD, "%") \ + MACRO(OPERATOR_MAT, "@") \ + MACRO(OPERATOR_POW, "**") \ + MACRO(OPERATOR_ABS, "+-") \ + MACRO(OPERATOR_BITWISE_AND, "&") \ + MACRO(OPERATOR_BITWISE_NAND, "~&") \ + MACRO(OPERATOR_BITWISE_OR, "|") \ + MACRO(OPERATOR_BITWISE_NOR, "~|") \ + MACRO(OPERATOR_BITWISE_XOR, "^") \ + MACRO(OPERATOR_BITWISE_NOT, "~") \ + MACRO(OPERATOR_BITWISE_L_SHIFT, "<<") \ + MACRO(OPERATOR_BITWISE_R_SHIFT, ">>") \ + MACRO(OPERATOR_EQUAL, "==") \ + MACRO(OPERATOR_NOT_EQUAL, "!=") \ + MACRO(OPERATOR_GREATER_THAN, ">") \ + MACRO(OPERATOR_LESS_THAN, "<") \ + MACRO(OPERATOR_GREATER_THAN_EQUALS, ">=") \ + MACRO(OPERATOR_LESS_THAN_EQUALS, "<=") \ + MACRO(OPERATOR_REF_EQUAL, "===") \ + MACRO(OPERATOR_ASSIGN, "=") \ + MACRO(OPERATOR_ADD_ASSIGN, "+=") \ + MACRO(OPERATOR_SUB_ASSIGN, "-=") \ + MACRO(OPERATOR_MUL_ASSIGN, "*=") \ + MACRO(OPERATOR_DIV_ASSIGN, "/=") \ + MACRO(OPERATOR_MOD_ASSIGN, "%=") \ + MACRO(OPERATOR_MAT_ASSIGN, "@=") \ + MACRO(OPERATOR_NOT_ASSIGN, "~=") \ + MACRO(OPERATOR_POWER_ASSIGN, "**=") \ + MACRO(OPERATOR_AND_ASSIGN, "&&=") \ + MACRO(OPERATOR_NAND_ASSIGN, "!&=") \ + MACRO(OPERATOR_OR_ASSIGN, "||=") \ + MACRO(OPERATOR_NOR_ASSIGN, "!|=") \ + MACRO(OPERATOR_XOR_ASSIGN, "^^=") \ + MACRO(OPERATOR_BITWISE_AND_ASSIGN, "&=") \ + MACRO(OPERATOR_BITWISE_NAND_ASSIGN, "~&=") \ + MACRO(OPERATOR_BITWISE_OR_ASSIGN, "|=") \ + MACRO(OPERATOR_BITWISE_NOR_ASSIGN, "~|") \ + MACRO(OPERATOR_BITWISE_XOR_ASSIGN, "^=") \ + MACRO(OPERATOR_BITWISE_NOT_ASSIGN, "~=") \ + MACRO(OPERATOR_BITWISE_L_SHIFT_ASSIGN, "<<=") \ + MACRO(OPERATOR_BITWISE_R_SHIFT_ASSIGN, ">>=") \ + MACRO(OPERATOR_INC, "++") \ + MACRO(OPERATOR_DEC, "--") \ + MACRO(OPERATOR_LOGICAL_NOT, "!") \ + MACRO(OPERATOR_LOGICAL_AND, "&&") \ + MACRO(OPERATOR_LOGICAL_NAND, "!&") \ + MACRO(OPERATOR_LOGICAL_OR, "||") \ + MACRO(OPERATOR_LOGICAL_NOR, "!|") \ + MACRO(OPERATOR_LOGICAL_XOR, "^^") \ + MACRO(OPERATOR_RANGE, "..") \ + MACRO(OPERATOR_RANGE_INCLUSIVE, "..=") \ + MACRO(OPERATOR_ARROW, "->") \ + MACRO(OPERATOR_SCOPE, "::") + +#endif // __OPERATORS_H__ \ No newline at end of file diff --git a/source/token/enums/others.def b/source/token/enums/others.def new file mode 100644 index 0000000..a191070 --- /dev/null +++ b/source/token/enums/others.def @@ -0,0 +1,10 @@ +#ifndef __OTHERS_H__ +#define __OTHERS_H__ + +#define OTHER_TOKENS_COUNT 2 + +#define OTHER_TOKENS(MACRO) \ + MACRO(IDENTIFIER, "id") \ + MACRO(OTHERS, "other") + +#endif // __OTHERS_H__ \ No newline at end of file diff --git a/source/token/enums/primitives.def b/source/token/enums/primitives.def new file mode 100644 index 0000000..e6b0ad0 --- /dev/null +++ b/source/token/enums/primitives.def @@ -0,0 +1,34 @@ +#ifndef __PRIMITIVES_H__ +#define __PRIMITIVES_H__ + +#define PRIMITIVE_TOKENS_COUNT 26 + +#define PRIMITIVE_TOKENS(MACRO) \ + MACRO(VOID, "void") \ + MACRO(BOOL, "bool") \ + MACRO(BYTE, "byte") \ + MACRO(CHAR, "char") \ + MACRO(POINTER, "ptr") \ + MACRO(I8, "i8") \ + MACRO(U8, "u8") \ + MACRO(I16, "i16") \ + MACRO(U16, "u16") \ + MACRO(I32, "i32") \ + MACRO(U32, "u32") \ + MACRO(F32, "f32") \ + MACRO(I64, "i64") \ + MACRO(U64, "u64") \ + MACRO(F64, "f64") \ + MACRO(FLOAT, "float") \ + MACRO(I128, "i128") \ + MACRO(U128, "u128") \ + MACRO(INT, "int") \ + MACRO(DECIMAL, "decimal") \ + MACRO(STRING, "string") \ + MACRO(LIST, "list") \ + MACRO(TUPLE, "tuple") \ + MACRO(SET, "set") \ + MACRO(MAP, "map") \ + MACRO(ANY, "any") + +#endif // __PRIMITIVES_H__ \ No newline at end of file diff --git a/source/token/enums/punctuation.def b/source/token/enums/punctuation.def new file mode 100644 index 0000000..5d7ed10 --- /dev/null +++ b/source/token/enums/punctuation.def @@ -0,0 +1,24 @@ +#ifndef __PUNCTUATION_H__ +#define __PUNCTUATION_H__ + +#define PUNCTUATION_TOKENS_COUNT 16 + +#define PUNCTUATION_TOKENS(MACRO) \ + MACRO(OPEN_PAREN, "(") \ + MACRO(CLOSE_PAREN, ")") \ + MACRO(OPEN_BRACE, "{") \ + MACRO(CLOSE_BRACE, "}") \ + MACRO(OPEN_BRACKET, "[") \ + MACRO(CLOSE_BRACKET, "]") \ + MACRO(OPEN_ANGLE, "<") \ + MACRO(CLOSE_ANGLE, ">") \ + MACRO(COMMA, ",") \ + MACRO(SEMICOLON, ";") \ + MACRO(COLON, ":") \ + MACRO(QUESTION_MARK, "?") \ + MACRO(DOT, ".") \ + MACRO(SINGLE_LINE_COMMENT, "//") \ + MACRO(MULTI_LINE_COMMENT, "/*") \ + MACRO(HASH, "#") + +#endif // __PUNCTUATION_H__ \ No newline at end of file diff --git a/source/token/enums/readme.md b/source/token/enums/readme.md new file mode 100644 index 0000000..4dd0aee --- /dev/null +++ b/source/token/enums/readme.md @@ -0,0 +1,3 @@ +## Readme for source/token/enums + +This directory contains the macro invocations for the tokens that are used in the lexer. The tokens are defined in the `token` module. \ No newline at end of file diff --git a/source/token/include/token_types.hh b/source/token/include/token_types.hh new file mode 100644 index 0000000..6406d94 --- /dev/null +++ b/source/token/include/token_types.hh @@ -0,0 +1,40 @@ +/* + * token_types.hh + * + * This file contains the header for the token types in the Helix programming language. + * It includes various header files that define the enums for delimiters, keywords, literals, + * operators, others, primitives, and punctuations. + */ + +#ifndef __TOKEN_TYPES_H__ +#define __TOKEN_TYPES_H__ + +#include "./tokens.def" + +namespace token { + GENERATE_TOKENS_ENUM_AND_MAPPING() // generate enum and maps for all tokens + + // undefine the macros to prevent global namespace pollution + #undef MAKE_TOKEN + #undef MAKE_TOKEN_PAIR + #undef GENERATE_TOKENS_ENUM_AND_MAPPING + + #undef KEYWORD_TOKENS_COUNT + #undef DELIMITER_TOKENS_COUNT + #undef LITERAL_TOKENS_COUNT + #undef OPERATOR_TOKENS_COUNT + #undef OTHER_TOKENS_COUNT + #undef PRIMITIVE_TOKENS_COUNT + #undef PUNCTUATION_TOKENS_COUNT + + #undef TOKENS + #undef KEYWORD_TOKENS + #undef DELIMITER_TOKENS + #undef LITERAL_TOKENS + #undef OPERATOR_TOKENS + #undef OTHER_TOKENS + #undef PRIMITIVE_TOKENS + #undef PUNCTUATION_TOKENS +} + +#endif // __TOKEN_TYPES_H__ \ No newline at end of file diff --git a/source/token/include/tokens.def b/source/token/include/tokens.def new file mode 100644 index 0000000..cf84591 --- /dev/null +++ b/source/token/include/tokens.def @@ -0,0 +1,41 @@ +#ifndef __TOKENS_H__ +#define __TOKENS_H__ + +#include "../enums/delimiters.def" +#include "../enums/keywords.def" +#include "../enums/literals.def" +#include "../enums/operators.def" +#include "../enums/others.def" +#include "../enums/primitives.def" +#include "../enums/punctuation.def" +#include "../types/mapping.hh" + +#define MAKE_TOKEN(name, string) name, +#define MAKE_TOKEN_PAIR(name, string) std::pair{name, string}, + +#define GENERATE_TOKENS_ENUM_AND_MAPPING() \ + namespace token { \ + enum tokens { TOKENS(MAKE_TOKEN) }; \ + \ + constexpr Mapping tokens_map{{TOKENS(MAKE_TOKEN_PAIR)}}; \ + } + +#define TOKENS_COUNT \ + KEYWORD_TOKENS_COUNT \ + + DELIMITER_TOKENS_COUNT \ + + LITERAL_TOKENS_COUNT \ + + OPERATOR_TOKENS_COUNT \ + + OTHER_TOKENS_COUNT \ + + PRIMITIVE_TOKENS_COUNT \ + + PUNCTUATION_TOKENS_COUNT \ + +#define TOKENS(MACRO) \ + KEYWORD_TOKENS(MACRO) \ + DELIMITER_TOKENS(MACRO) \ + LITERAL_TOKENS(MACRO) \ + OPERATOR_TOKENS(MACRO) \ + OTHER_TOKENS(MACRO) \ + PRIMITIVE_TOKENS(MACRO) \ + PUNCTUATION_TOKENS(MACRO) + +#endif // __TOKENS_H__ \ No newline at end of file diff --git a/source/token/token.hh b/source/token/token.hh index 4cba502..a1f3d76 100644 --- a/source/token/token.hh +++ b/source/token/token.hh @@ -1,103 +1,116 @@ +/// Part of the Helix Language Project +/// (c) 2024 The Helix Team +/// This code is licensed under the MIT License. + #ifndef __TOKEN_H__ #define __TOKEN_H__ -#include "define.hh" +#include #include #include -#include +#include +#include +#include "../include/inttypes.hh" +#include "./enums/delimiters.hh" +#include "./enums/keywords.hh" +#include "./enums/literals.hh" +#include "./enums/operators.hh" +#include "./enums/others.hh" +#include "./enums/primitives.hh" +#include "./enums/punctuation.hh" +#include "./include/define.hh" namespace token { +/** + * @brief Union representing the different possible types of a token. + */ union TokenType { - keywords keyword; - primitives primitive; - operators operator_; - literals literal; - punctuation punct; - delimiters delim; - identifiers ident; + keywords keyword; ///< Keyword token type + primitives primitive; ///< Primitive token type + operators operator_; ///< Operator token type + literals literal; ///< Literal token type + punctuation punct; ///< Punctuation token type + delimiters delim; ///< Delimiter token type + other ident; ///< Other token type (identifier) }; +/** + * @brief Structure representing a token in the source code. + */ struct Token { - private: - TokenType type; // type of the token - discriminant kind; // kind of the token + private: + std::variant + type; ///< Variant holding the specific type of the token + discriminant kind; ///< Discriminant indicating the kind of token + + public: + u32 line; ///< Line number where the token is located + u32 column; ///< Column number where the token starts + u16 length; ///< Length of the token + u64 offset; ///< Offset from the beginning of the file + std::string value; ///< String value of the token - public: - u32 line; // line number - u32 column; // column number - u16 length; // length of the token - u64 offset; // offset from the beginning of the file - string value; // value of the token + /** + * @brief Constructs a Token with the specified attributes. + * + * @param line Line number where the token is located. + * @param column Column number where the token starts. + * @param length Length of the token. + * @param offset Offset from the beginning of the file. + * @param value String value of the token. + */ + Token(u32 line, u32 column, u16 length, u64 offset, std::string_view value) + : line(line), column(column), length(length), offset(offset), value(value) { + auto check_and_set_kind = [this](const auto &map, std::string_view value, auto kind_value) -> bool { + auto type_opt = map.at(value); + if (type_opt.has_value()) { + type = type_opt.value(); + this->kind = kind_value; + return true; + } + return false; + }; - Token(u32 line, u32 column, u16 length, u64 offset, std::string value) : line(line), column(column), length(length), offset(offset), value(std::move(value)) { - if (keywords_map.at(value).has_value()) { - type.keyword = keywords_map.at(value).value(); - this->kind = discriminant::KEYWORDS; - } else if (primitives_map.at(value).has_value()) { - type.primitive = primitives_map.at(value).value(); - this->kind = discriminant::PRIMITIVES; - } else if (operators_map.at(value).has_value()) { - type.operator_ = operators_map.at(value).value(); - this->kind = discriminant::OPERATORS; - } else if (literals_map.at(value).has_value()) { - type.literal = literals_map.at(value).value(); - this->kind = discriminant::LITERALS; - } else if (punctuation_map.at(value).has_value()) { - type.punct = punctuation_map.at(value).value(); - this->kind = discriminant::PUNCTUATION; - } else if (delimiters_map.at(value).has_value()) { - type.delim = delimiters_map.at(value).value(); - this->kind = discriminant::DELIMITERS; - } else { - type.ident = identifiers::IDENTIFIER; - this->kind = discriminant::IDENTIFIERS; + if (check_and_set_kind(keywords_map, value, discriminant::KEYWORDS) || + check_and_set_kind(primitives_map, value, discriminant::PRIMITIVES) || + check_and_set_kind(operators_map, value, discriminant::OPERATORS) || + check_and_set_kind(punctuation_map, value, discriminant::PUNCTUATION) || + check_and_set_kind(delimiters_map, value, discriminant::DELIMITERS)) { + return; } } - /// use of get_token(): - /// auto tokenType = token.get_token(); // returns some token type such as keyword::IF - /// // can also use for comparison - /// if (token.get_kind() == discriminant::KEYWORDS) { // true if token is a keyword - /// if (token.get_token() == keyword::IF) { // true if token is a keyword and is IF - /// // do something - /// } - /// } - - discriminant get_kind() const { - return kind; + /** + * @brief Gets the specific token type. + * + * @tparam T The type to retrieve from the variant. + * @return The specific type of the token. + * + * @note Example usage: + * @code + * auto tokenType = token.get_token(); // returns some token type such as keyword::IF + * if (token.get_kind() == discriminant::KEYWORDS) { // true if token is a keyword + * if (token.get_token() == keyword::IF) { // true if token is + * a keyword and is IF + * // do something + * } + * } + * @endcode + */ + template + [[nodiscard]] T get_token() const noexcept { + return std::get(type); } - template >> - T get_token() const { - switch (kind) { - case discriminant::KEYWORDS: - return static_cast(type.keyword); - case discriminant::PRIMITIVES: - return static_cast(type.primitive); - case discriminant::OPERATORS: - return static_cast(type.operator_); - case discriminant::LITERALS: - return static_cast(type.literal); - case discriminant::PUNCTUATION: - return static_cast(type.punct); - case discriminant::DELIMITERS: - return static_cast(type.delim); - case discriminant::IDENTIFIERS: - return static_cast(type.ident); - default: - throw std::runtime_error("Invalid token kind"); - } - } + /** + * @brief Gets the kind of the token. + * + * @return The discriminant indicating the kind of the token. + */ + [[nodiscard]] discriminant get_kind() const noexcept { return kind; } }; +} // namespace token -inline void test() { - Token token(1, 1, 1, 1, "if"); - assert(token.get_kind() == discriminant::KEYWORDS); - assert(token.get_token() == keywords::IF); -} - -} - -#endif // __TOKEN_H__ \ No newline at end of file +#endif // __TOKEN_H__ diff --git a/source/token/types/mapping.hh b/source/token/types/mapping.hh new file mode 100644 index 0000000..6f85cd7 --- /dev/null +++ b/source/token/types/mapping.hh @@ -0,0 +1,38 @@ +#ifndef __MAPPING_H__ +#define __MAPPING_H__ + +#include +#include +#include +#include + +using std::string; + +namespace token { +template +struct Mapping { + std::array, N> data; + + constexpr Mapping(std::array, N> init_data) : data(init_data) {} + + [[nodiscard]] constexpr std::optional at(std::string_view x) const noexcept { + for (const auto &[key, value] : data) { + if (value == x) { + return key; + } + } + return std::nullopt; + } + + [[nodiscard]] constexpr std::optional at(Enum x) const noexcept { + for (const auto &[key, value] : data) { + if (key == x) { + return value; + } + } + return std::nullopt; + } +}; +} // namespace token + +#endif // __MAPPING_H__ \ No newline at end of file diff --git a/tests/test_tokens.cc b/tests/test_tokens.cc new file mode 100644 index 0000000..d8cdfd7 --- /dev/null +++ b/tests/test_tokens.cc @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +#include "../source/token/token.hh" + +using std::string; + +#define REQUIRE_DURATION_UNDER_500NS(start, end) \ + REQUIRE_THROWS_AS(std::chrono::duration_cast((end) - (start)).count() < 500, std::overflow_error); + +inline void check_token(u32 line, u32 column, u16 length, u64 offset, std::string_view value, token::discriminant kind, auto expected, + const char *token_str) { + auto start = std::chrono::high_resolution_clock::now(); + token::Token token(line, column, length, offset, value); + auto end = std::chrono::high_resolution_clock::now(); + REQUIRE(token.get_kind() == kind); + REQUIRE(token.get_token() == expected); + + REQUIRE_DURATION_UNDER_500NS(start, end); +} + +#include +#include +#include +#include "../source/token/token.hh" + +using std::string; + +#define REQUIRE_DURATION_UNDER_500NS(start, end) \ + REQUIRE(std::chrono::duration_cast(end - start).count() < 500); + +void check_token(int line, int col, int start, int end, std::string_view text, + token::discriminant kind, auto expected, const char* token_str) { + auto start_time = std::chrono::high_resolution_clock::now(); + token::Token token(line, col, start, end, text); + auto end_time = std::chrono::high_resolution_clock::now(); + REQUIRE(token.get_kind() == kind); + REQUIRE(token.get_token() == expected); + REQUIRE_DURATION_UNDER_500NS(start_time, end_time); +} + +TEST_CASE("Test token::Token constructor", "[token::Token]") { + SECTION("testing keyword 'if'") { + check_token(1, 1, 1, 1, std::string_view("if"), token::discriminant::KEYWORDS, + token::keywords::IF, "if"); + } + SECTION("testing keyword 'else'") { + check_token(1, 1, 1, 1, std::string_view("else"), token::discriminant::KEYWORDS, + token::keywords::ELSE, "else"); + } + SECTION("testing primitive 'int'") { + check_token(1, 1, 1, 1, std::string_view("int"), token::discriminant::PRIMITIVES, + token::primitives::INT, "int"); + } + SECTION("testing operator '+'") { + check_token(1, 1, 1, 1, std::string_view("+"), token::discriminant::OPERATORS, + token::operators::ADD, "+"); + } + SECTION("testing identifier 'identifier'") { + check_token(1, 1, 1, 1, std::string_view("identifier"), + token::discriminant::OTHER, token::other::IDENTIFIER, "identifier"); + } + SECTION("testing operator '=='") { + check_token(1, 1, 1, 1, std::string_view("=="), token::discriminant::OPERATORS, + token::operators::EQUAL, "=="); + } + SECTION("testing operator '!='") { + check_token(1, 1, 1, 1, std::string_view("!="), token::discriminant::OPERATORS, + token::operators::NOT_EQUAL, "!="); + } + SECTION("testing operator '&&'") { + check_token(1, 1, 1, 1, std::string_view("&&"), token::discriminant::OPERATORS, + token::operators::LOGICAL_AND, "&&"); + } + SECTION("testing identifier '1L'") { + check_token(1, 1, 1, 1, std::string_view("1L"), token::discriminant::OTHER, + token::other::IDENTIFIER, "1L"); + } + SECTION("testing identifier '1.0F'") { + check_token(1, 1, 1, 1, std::string_view("1.0F"), token::discriminant::OTHER, + token::other::IDENTIFIER, "1.0F"); + } +} \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index 67edb0c..8610be6 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,16 +1,24 @@ +-------------------------------------------- xmake.lua --------------------------------------------- + set_project("helix-lang") -add_rules ("mode.debug", "mode.release") +add_rules("mode.debug", "mode.release") ----------------------------------------------------------------------------------------------------- +------------------------------------------- dependencies ------------------------------------------- + +add_requires("catch2 3", { system = false, configs = {components = {"main"}, }}) + +-- for clanged support run "xmake project -k compile_commands" to generate compile_commands.json -target("helix-lang") +-------------------------------------------- helix -------------------------------------------- + +target("helix") set_kind("binary") set_warnings("all") add_files("source/*.cc") -- add all files in the source directory add_files("source/**/*.cc") -- add all files in the source directory's subdirectories - set_languages("c++2b") -- set the standard c++ version to c++2b + set_languages("c++2b") -- set the standard C++ version to C++2b set_optimize ("fastest") add_includedirs("/opt/llvm-aarch64/include") @@ -18,33 +26,161 @@ target("helix-lang") add_links("LLVM-18", "clang", "clang-cpp", "c++", "c++abi") -- explicitly add LLVM libraries - add_cxxflags("-stdlib=libc++" , "-fno-rtti", "-I/opt/llvm-aarch64/include" ) - add_ldflags ("-L/opt/llvm-aarch64/lib", "-lc++abi" , "-Wl,-rpath,/opt/llvm-aarch64/lib") + add_cxxflags("-stdlib=libc++", "-fno-rtti", "-I/opt/llvm-aarch64/include") + add_ldflags ("-L/opt/llvm-aarch64/lib", "-lc++abi", "-Wl,-rpath,/opt/llvm-aarch64/lib") ----------------------------------------------------------------------------------------------------- +----------------------------------------------- test ----------------------------------------------- + +target("tests") + set_kind("binary") + set_warnings("all") + + add_files("tests/*.cc") -- add all files in the tests directory + + if os.isdir("tests/*") then + add_files("tests/**/*.cc") -- add all files in the tests directory's subdirectories + end + + set_languages("c++2b") -- set the standard C++ version to C++2b + set_optimize ("fastest") + + add_includedirs("/opt/llvm-aarch64/include") + + add_linkdirs ("/opt/llvm-aarch64/lib") + + add_links("LLVM-18", "clang", "clang-cpp", "c++", "c++abi", "Catch2", "Catch2Main") -- add LLVM libs + + add_cxxflags("-stdlib=libc++" , "-fno-rtti", "-I/opt/llvm-aarch64/include") + add_ldflags ("-L/opt/llvm-aarch64/lib", "-lc++abi" , "-Wl,-rpath,/opt/llvm-aarch64/lib") --- TODO: add testing target + add_packages("catch2") ----------------------------------------------------------------------------------------------------- +----------------------------------------------- llvm ----------------------------------------------- -before_build( - function(target) - import("lib.detect.find_tool") - - local llvm_config = find_tool("llvm-config", {paths = "/opt/llvm-aarch64/bin"}) - - if llvm_config then - local llvm_includedir = os.iorunv(llvm_config.program, {"--includedir"}):trim() - local llvm_libdir = os.iorunv(llvm_config.program, {"--libdir"} ):trim() - - target:add("includedirs", llvm_includedir) - target:add("linkdirs" , llvm_libdir ) - - else - raise("llvm-config not found!") +before_build(function(target) + import("lib.detect.find_tool") + + local llvm_config = find_tool("llvm-config", {paths = "/opt/llvm-aarch64/bin"}) + + if llvm_config then + local llvm_includedir = os.iorunv(llvm_config.program, {"--includedir"}):trim() + local llvm_libdir = os.iorunv(llvm_config.program, {"--libdir"}):trim() - end + target:add("includedirs", llvm_includedir) + target:add("linkdirs", llvm_libdir) + else + raise("llvm-config not found!") end -) +end) + +-------------------------------------------- build modes ------------------------------------------- + +if is_mode("debug") then + set_runtimes("MDd") +else + set_runtimes("MD") +end + +---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------- \ No newline at end of file +-- -------------------------------------------- xmake.lua --------------------------------------------- +-- +-- set_project("helix-lang") +-- add_rules("mode.debug", "mode.release") +-- +-- ------------------------------------------- dependencies ------------------------------------------- +-- +-- add_requires("catch2 3", { system = false, configs = {components = {"main"}, }}) +-- +-- -- for clanged support run "xmake project -k compile_commands" to generate compile_commands.json +-- +-- -------------------------------------------- fucntions --------------------------------------------- +-- +-- ----------------------------------------- target_setup.lua ----------------------------------------- +-- +-- local target_setup = function(target) +-- if os.isdir(target) then +-- set_kind("binary") +-- set_warnings("all") +-- +-- add_files(target .. "/*.cc") -- add all files in the tests directory +-- +-- if os.isdir(target .. "/*") then +-- add_files(target .. "/**/*.cc") -- add all files in the tests directory's subdirectories +-- end +-- +-- set_languages("c++2b") -- set the standard C++ version to C++2b +-- set_optimize ("fastest") +-- end +-- end +-- +-- ------------------------------------------ links_setup.lua ----------------------------------------- +-- +-- local links_setup = function(...) +-- add_linkdirs ("/opt/llvm-aarch64/lib") +-- add_links(...) +-- end +-- +-- ---------------------------------------- includes_setup.lua ---------------------------------------- +-- +-- local includes_setup = function(...) +-- add_includedirs(...) +-- end +-- +-- ------------------------------------------ base_setup.lua ------------------------------------------ +-- +-- local base_setup = function(target, ...) +-- target_setup(target) +-- links_setup("LLVM-18", "clang", "clang-cpp", "c++", "c++abi", ...) +-- includes_setup("/opt/llvm-aarch64/include") +-- end +-- +-- -------------------------------------------- helix-lang -------------------------------------------- +-- +-- target("helix-lang") +-- base_setup("source") +-- add_cxxflags("-stdlib=libc++" , "-fno-rtti", "-I/opt/llvm-aarch64/include") +-- add_ldflags ("-L/opt/llvm-aarch64/lib" , "-Wl,-rpath,/opt/llvm-aarch64/lib") +-- +-- ----------------------------------------------- test ----------------------------------------------- +-- +-- target("test") +-- base_setup("tests", "Catch2", "Catch2Main") +-- add_cxxflags("-stdlib=libc++" , "-fno-rtti", "-I/opt/llvm-aarch64/include") +-- add_ldflags ("-L/opt/llvm-aarch64/lib" , "-Wl,-rpath,/opt/llvm-aarch64/lib") +-- add_packages("catch2") +-- +-- ------------------------------------------- before_build ------------------------------------------- +-- +-- before_build(function(target) +-- import("lib.detect.find_tool") +-- +-- local llvm_config = find_tool("llvm-config", {paths = "/opt/llvm-aarch64/bin"}) +-- +-- if llvm_config then +-- local llvm_includedir = os.iorunv(llvm_config.program, {"--includedir"}):trim() +-- local llvm_libdir = os.iorunv(llvm_config.program, {"--libdir"}):trim() +-- +-- target:add("includedirs", llvm_includedir) +-- target:add("linkdirs", llvm_libdir) +-- else +-- raise("llvm-config not found!") +-- end +-- end) +-- +-- -------------------------------------------- build modes ------------------------------------------- +-- +-- if is_mode("debug") then +-- set_runtimes("MDd") +-- else +-- set_runtimes("MD") +-- end +-- +-- ----------------------------------------------- run ------------------------------------------------ +-- +-- on_load(function (target) +-- import("core.base.task") +-- task.run("require") +-- end) +-- +-- ---------------------------------------------------------------------------------------------------- \ No newline at end of file