diff --git a/helix.code-workspace b/helix.code-workspace new file mode 100644 index 0000000..292e30e --- /dev/null +++ b/helix.code-workspace @@ -0,0 +1,10 @@ +{ + "folders": [ + { + "path": "helix-lang" + } + ], + "settings": { + "svg.preview.background": "editor" + } +} \ No newline at end of file diff --git a/source/cli/include/cli.hh b/source/cli/include/cli.hh new file mode 100644 index 0000000..f46f820 --- /dev/null +++ b/source/cli/include/cli.hh @@ -0,0 +1,5 @@ +#include "cli/include/args.hh" +#include +#include +#include +#include \ No newline at end of file diff --git a/source/cli/source/cli.cc b/source/cli/source/cli.cc index 01737f4..d5a0621 100644 --- a/source/cli/source/cli.cc +++ b/source/cli/source/cli.cc @@ -1,48 +1,3 @@ -/* -helix - command line interface - -Usage: - helix [options] [options-2] - helix (-h | --help) - helix --version - helix --license - -Options: - -O1 --optimize1 Optimization level 1. - -O2 --optimize2 Optimization level 2. - -O3 --optimize3 Optimization level 3. - -O4 --optimize4 Optimization level 4. - - -h --help Show this screen. - --version Show version. - --license Show license information. - - --verbose Show verbose output. - --quiet Show no output. - - --ast Show abstract syntax tree. - --tokens Show tokens. - --emit-llvm Show LLVM IR. - --emit-asm Show assembly. - --emit-ir Show intermediate representation. (C | C++) - --emit-doc Only extract doc-comments along with signatures. - - --target Target triple. - --arch Target architecture. - --os Target operating system. - - --config Specify configuration file. - --release Build in release mode. - --debug Build in debug mode. - -Options-2: - -o Output file. - --lib Compile as library. - -I Include directory. - -L Library directory. - -l Link library. -*/ - /* Helios - package manager / build system @@ -64,6 +19,154 @@ Helios - package manager / build system helios doc-gen Generate documentation. */ -#include +/* +helix - command line interface + +Usage: + helix [options] [options-2] + helix (-h | --help) + helix --version + helix --license + +options: + -O1 --optimize1 Optimization level 1. + -O2 --optimize2 Optimization level 2. + -O3 --optimize3 Optimization level 3. + -O4 --optimize4 Optimization level 4. + -O5 --optimize5 Optimization level 5. + + -h --help Show this screen. + -v --version Show version. + -l --license Show license information. + + --verbose Show verbose output. + --quiet Show no output. + + --emit-tokens Show tokens. + --emit-llvm Show LLVM IR. + --emit-asm Show assembly. + --emit-ast Show AST in json format + --emit-ir Show intermediate representation. (C++) + --emit-doc Only extract doc-comments along with signatures in json format. + + --toolchain Set the toolchain to use + + --config Specify configuration file. + -r --release Build in release mode. + -d --debug Build in debug mode with symbols. + +options-2: + --lib [abi-options] Compile as library. + -o Output file. + -I Include directory. + -L Library directory. + -l Link library. + +options-3: + --target Target triple. + --arch Target architecture. + --os Target operating system. + + +abi-options: + -py --python Python stub files gen and pylib compile + -rs --rust Rust source files gen and a rust compiler lib + -cxx --cxx C++ header files gen and linkable object file + -hlx --helix Helix ABI compatable libary +*/ + +#include +#include +#include +#include + +#include "cli/include/args.hh" + +namespace command_line { +class CLIArgs { + template + explicit CLIArgs(int argc, char **argv) { + args::ArgumentParser parser( + "This is a test program with a really long description that is probably going to have " + "to be wrapped across multiple different lines. This is a test to see how the line " + "wrapping works", + "This goes after the options. This epilog is also long enough that it will have to be " + "properly wrapped to display correctly on the screen"); + + args::HelpFlag help(parser, "HELP", "Show this help menu.", {'h', "help"}); + + args::ValueFlag foo(parser, "FOO", "The foo flag.", + {'a', 'b', 'c', "a", "b", "c", "the-foo-flag"}); + + args::ValueFlag bar( + parser, "BAR", + "The bar flag. This one has a lot of options, and will need wrapping in the " + "description, along with its long flag list.", + {'d', 'e', 'f', "d", "e", "f"}); + + args::ValueFlag baz( + parser, "FOO", + "The baz flag. This one has a lot of options, and will need wrapping in the " + "description, even with its short flag list.", + {"baz"}); + + args::Positional pos1(parser, "POS1", "The pos1 argument."); + args::PositionalList poslist1(parser, "POSLIST1", "The poslist1 argument."); + + try { + parser.ParseCLI(argc, argv); + } catch (args::Help) { + std::cout << parser; + return; + } catch (args::ParseError e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return; + } catch (args::ValidationError e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + return; + } + } +}; + +struct HelixArguments { + // File and optional output file + std::string file; + std::optional output_file; + + // Options + bool optimize1 = false; + bool optimize2 = false; + bool optimize3 = false; + bool optimize4 = false; + + bool help = false; + bool version = false; + bool license = false; + + bool verbose = false; + bool quiet = false; + + bool show_ast = false; + bool show_tokens = false; + bool emit_llvm = false; + bool emit_asm = false; + bool emit_ir = false; + bool emit_doc = false; + + std::optional target_triple; + std::optional target_arch; + std::optional target_os; + + std::optional config_file; + bool release = false; + bool debug = false; -void parse() {} + // Options-2 + bool compile_as_library = false; + std::vector include_dirs; + std::vector library_dirs; + std::vector link_libraries; +}; +} // end namespace command_line diff --git a/source/main.cc b/source/main.cc index 5a95b25..8a07880 100644 --- a/source/main.cc +++ b/source/main.cc @@ -14,20 +14,25 @@ #include #include +#include #include "token/include/lexer.hh" #include "token/include/token.hh" -#include "parser/ast/include/parser.hh" +#include "parser/ast/include/nodes.hh" +#include "cli/include/cli.hh" +#include "parser/ast/include/ast.hh" #include "tools/controllers/include/file_system.hh" #include "parser/preprocessor/include/preprocessor.hh" -int main() { +int main(int argc, char **argv) { using namespace token; using namespace parser; using namespace lexer; auto start = std::chrono::high_resolution_clock::now(); + + std::string file_name = "/Volumes/Container/Projects/Helix/helix-lang/tests/main.hlx"; // relative to current working dir in POSIX shell (cmd/bash) // read the file and tokenize its contents : stage 0 @@ -43,15 +48,15 @@ int main() { // preprocessor::import_tree->print_tree(preprocessor::import_tree->get_root()); // print the preprocessed tokens - print_tokens(tokens); + // print_tokens(tokens); + - for (auto &tok_ref : tokens) { - if (tok_ref->token_kind() == tokens::KEYWORD_FUNCTION) { - tok_ref.peek(); - std::cout << tok_ref.peek()->get().value() << "\n"; - } - } + auto node = std::make_unique>(tokens); + + node->parse(); + print(node->to_string()); + // Print the time taken in nanoseconds and milliseconds print("time taken: ", diff.count() * 1e+9, " ns"); print(" ", diff.count() * 1000, " ms"); diff --git a/source/parser/ast/include/ast.hh b/source/parser/ast/include/ast.hh index da29679..ee48a5f 100644 --- a/source/parser/ast/include/ast.hh +++ b/source/parser/ast/include/ast.hh @@ -15,6 +15,7 @@ #ifndef __AST_HH__ #define __AST_HH__ +#include #include #include #include @@ -22,8 +23,7 @@ #include #include -#include -#include +#include "token/include/token.hh" /* something like: 2 * (3 + 4) / 5 @@ -154,108 +154,6 @@ comments */ -#define AST_NODE_METHODS(name) \ - inline string to_string(u16 depth = 1) const override; \ - inline string node_name() const override { return #name; } \ - ParseResult validate(TokenList tokens) override; \ - void accept(class Visitor &visitor) override - -namespace parser::ast { -using std::string; -using std::string_view; -using namespace token; - -inline string get_indent(u16 depth) noexcept { - return string(static_cast(depth * 4), ' '); -}; - -template -struct AstNode; - -struct ParseError { - ParseError() = default; - explicit ParseError(const error::Compiler &diagnostic) { - (error::Error(diagnostic)); - std::exit(1); - } -}; - -using AstNodePtr = std::unique_ptr>; - -template -using AstNodeRef = std::shared_ptr>; - -template -using ParseResult = std::expected, ParseError>; - -template -using AstNodeList = std::vector>; - -template <> -struct AstNode { - AstNode() = default; - AstNode(const AstNode &) = default; - AstNode &operator=(const AstNode &) = default; - AstNode &operator=(AstNode &&) = default; - AstNode(AstNode &&) = default; - virtual ~AstNode() = default; - - [[nodiscard]] virtual string to_string(u16 depth = 1) const = 0; - [[nodiscard]] virtual string node_name() const = 0; - - virtual void accept(class Visitor &visitor) = 0; - [[noreturn]] void validate(TokenList tokens) { - ParseError(error::Compiler{ - .file_name = "unknown", - .message = "void ast node pointer called", - .fix = "this message would never or should never be seen if it is, report it"}); - - std::exit(1); - }; -}; - -template -struct AstNode : public AstNode { - AstNode() = default; - AstNode(const AstNode &) = default; - AstNode &operator=(const AstNode &) = default; - AstNode &operator=(AstNode &&) = default; - AstNode(AstNode &&) = default; - virtual ~AstNode() = default; - - [[nodiscard]] virtual string to_string(u16 depth = 1) const override = 0; - [[nodiscard]] virtual string node_name() const override = 0; - - virtual ParseResult validate(TokenList tokens) = 0; - virtual void accept(class Visitor &visitor) override = 0; -}; - -// struct Variable : AstNode { // a | _a | a1 | _a1 -// Location loc; -// string name; -// -// explicit Variable(const Token &token) -// : loc(token) -// , name(token.value()) {} -// -// [[nodiscard]] string to_string(u16 depth = 1) const override { -// return get_indent(depth) + "Variable(" + name + ")"; -// } -// -// [[nodiscard]] string node_name() const override { -// return "Variable"; -// } -// -// ParseResult parse(TokenList tokens) override { -// // Implement parsing logic for Variable node -// return std::make_unique(tokens.current()); -// } -// -// void accept(Visitor &visitor) override { -// // Implement visitor pattern logic -// } -// }; - /* the following parsed and translated: a: i16; // i16 a(); @@ -318,5 +216,62 @@ struct AstNode : public AstNode { */ +namespace parser::ast { +inline string get_indent(u16 depth) noexcept { return string(static_cast(depth * 4), ' '); }; + +struct ParseError {}; + +// concept AstBase = requires(T t) { +// { t.parse(token::TokenList) } -> std::expected, ParseError>; +// { t.to_string() } -> std::string; +// }; + +using ParseResult = std::optional; + +using TokenListRef = std::reference_wrapper; + +template +struct ASTBase; + +template <> +struct ASTBase: { + // virtual std::expected,AstError> parse(std::span tokens) = 0; + virtual ~ASTBase() = default; + ASTBase() = default; + ASTBase(ASTBase &&) = default; + ASTBase(const ASTBase &) = default; + ASTBase &operator=(ASTBase &&) = default; + ASTBase &operator=(const ASTBase &) = delete; + + [[nodiscard]] virtual ParseResult parse() = 0; + [[nodiscard]] virtual std::string to_string() const = 0; +}; + +template +struct ASTBase : ASTBase { + virtual ~ASTBase() = default; + ASTBase() = default; + explicit ASTBase(TokenListRef parse_tokens); + ASTBase(ASTBase &&) = default; + ASTBase(const ASTBase &) = default; + ASTBase &operator=(ASTBase &&) = default; + ASTBase &operator=(const ASTBase &) = delete; +}; + +template +concept ASTNode = std::derived_from>; + +template +using ASTNodePtr = std::unique_ptr>; + +template +using ASTNodeList = std::vector>; + +template +using ASTNodeRef = std::reference_wrapper>; + +template +using ASTSlice = const std::reference_wrapper>; + } // namespace parser::ast -#endif // __AST_HH__ \ No newline at end of file +#endif // __AST_HH__44 \ No newline at end of file diff --git a/source/parser/ast/include/nodes.hh b/source/parser/ast/include/nodes.hh index f1d4fc0..1690f70 100644 --- a/source/parser/ast/include/nodes.hh +++ b/source/parser/ast/include/nodes.hh @@ -14,184 +14,266 @@ #ifndef __NODES_HH__ #define __NODES_HH__ +#include +#include #include +#include +#include #include +#include -#include +#include "include/error/error.hh" +#include "parser/ast/include/ast.hh" +#include "token/include/token.hh" + +#define AST_NODE_METHODS(name) \ + virtual ~name() = default; \ + explicit name(TokenListRef parse_tokens) \ + : tokens(parse_tokens){}; \ + name() = default; \ + name(name &&) = default; \ + name(const name &) = default; \ + name &operator=(name &&) = default; \ + name &operator=(const name &) = delete; \ + \ + private: \ + std::optional tokens; namespace parser::ast { -/* Literals */ -struct StringLiteral : AstNode { // "Hello, world!" | 'H' - Token value; - explicit StringLiteral(Token token); - AST_NODE_METHODS(StringLiteral); -}; +using namespace token; -struct BooleanLiteral : AstNode { // true | false - Token value; - explicit BooleanLiteral(Token token); - AST_NODE_METHODS(BooleanLiteral); -}; +// TODO: Rename to StringLiteral -struct NullLiteral : AstNode { // null - Token value; - explicit NullLiteral(Token token); - AST_NODE_METHODS(NullLiteral); -}; +template +struct Quoted : ASTBase> { + public: + enum class Format : char { + Invalid, + None = quote, + Raw = 'r', + Bytes = 'b', + Unicode = 'u', + Formatted = 'f', // does not work for char....., but it could if someone really wanted too + }; -struct NumericLiteral : AstNode { // 1 | 1.0 | 1.0d | 0x1 | 0b1 | 0o1 - Token value; - explicit NumericLiteral(Token token); - AST_NODE_METHODS(NumericLiteral); -}; + AST_NODE_METHODS(Quoted); -struct GenericArgument : AstNode { // | - AstNodeList<> arguments; - explicit GenericArgument(AstNodeList<> arguments); - AST_NODE_METHODS(GenericArgument); -}; +public: + ParseResult parse() override { + // Do we have suffixes? + Token &toke = tokens->get().front(); -struct GenericInvocation - : AstNode { // ref | ptr | SomeGeneric - Token value; // ref | ptr | SomeGeneric - AstNodeList arguments; // | - explicit GenericInvocation(Token token, AstNodeList arguments); - AST_NODE_METHODS(GenericInvocation); -}; + if (toke.token_kind() != toke_type) { + error::Error(error::Line(toke, "Expected a quote literal")); + }; + + // There in no need to check for the token kind as the value of this + this->format = static_cast(toke.value().at(0)); + + if (format == Format::Invalid) { + error::Error(error::Line(toke.file_name(), toke.line_number(), toke.column_number(), 1, + "Invalid format specifier")); + } + + this->value = toke; -/* Statements */ -struct Identifier : AstNode { // a | _a | a1 | _a1 + // Remove the format specifier (if it is there) and quotes + this->value.set_value(toke.value().substr( + this->format == Format::None ? // Check if the there is a format specifier + 1 // Remove the quotes only + : + 2, // Remove the quotes and the format specifier + toke.value().size() - 3)); + // - 1 is the actual length + // - 2 is removing the \0 + // - 3 removes the quote + + print(this->value.value()); + + // Check for format + // TODO: make f"hi {name if !name.empty() else "john doe"}" -> string: "hi {}", fmt_args + // (astExpr): name if !name.empty() else "john doe" + + return std::nullopt; + }; + + std::string to_string() const override { + + std::string format; + + switch (this->format) { + case Format::Raw: + format = "r"; + break; + case Format::Bytes: + format = "b"; + break; + case Format::Unicode: + format = "u"; + break; + case Format::Formatted: + format = "f"; + break; + case Format::None: + break; + } + + return format + quote + this->value.to_string() + quote; + }; + + private: Token value; - explicit Identifier(Token token); - AST_NODE_METHODS(Identifier); + Format format = Format::None; }; -struct Variable : AstNode { // a: int<8> | a: i32 = 5 | a: i32? = null - AstNodeRef name; // a - AstNodeRef type; // int<8> | i32 - AstNodePtr value; // 5 | null - bool is_nullable; - Token reference; // & | && - Token pointer; // * - explicit Variable(AstNodeRef name, AstNodeRef type, - AstNodePtr value, bool is_nullable = false, Token reference = Token(), - Token pointer = Token()); - AST_NODE_METHODS(Variable); -}; +struct BoolLiteral : ASTBase { + public: + enum class BoolValue : std::uint8_t { + True = 't', + False = 'f', + }; -struct Return : AstNode { // return 5 | return null - AstNodePtr value; // 5 | null - explicit Return(AstNodePtr value); - AST_NODE_METHODS(Return); -}; + AST_NODE_METHODS(BoolLiteral); + ParseResult parse() override; + std::string to_string() const override; -/* Expressions */ -struct BinaryOperation : AstNode { // 2 * (3 + 4) / 5 - Token op; // * - AstNodePtr left; // 2 - AstNodePtr right; // (3 + 4) / 5 - explicit BinaryOperation(Token op, AstNodePtr left, AstNodePtr right); - AST_NODE_METHODS(BinaryOperation); + private: + Token value; + // BoolValue value; // should this be a bool? }; -struct ObjectInvocation - : AstNode { // print("Hello, world!") | print("Hello, world!", end=" ") - // print("Hello, world!") - Token name; // print - AstNodeList<> arguments; // ("Hello, world!") - AstNodeList generics; // - AstNodeList<> named_arguments; // (end=" ") - explicit ObjectInvocation(Token name, AstNodeList<> arguments, - AstNodeList generics, AstNodeList<> named_arguments); - AST_NODE_METHODS(ObjectInvocation); -}; +using StringLiteral = Quoted<'"', tokens::LITERAL_STRING>; +using CharLiteral = Quoted<'\'', tokens::LITERAL_CHAR>; -struct StructureInvocation - : AstNode { // SomeStruct { a: 5, b: 6 } | SomeStruct { a, b } - Token name; // SomeStruct - AstNodeList<> arguments; // { a: 5, b: 6 } | { a, b } - shorthand - AstNodeList generics; // - explicit StructureInvocation(Token name, AstNodeList<> arguments, - AstNodeList generics, - AstNodeList<> named_arguments); - AST_NODE_METHODS(StructureInvocation); -}; -struct CommentNode : AstNode { // // hello this is a comment - Token value; // "hello this is a comment" - AstNodePtr owner; // if this is on top of a function decl this would be the function - explicit CommentNode(Token value, AstNodePtr owner) - : value(std::move(value)) - , owner(std::move(owner)) {} - - explicit CommentNode(Token value) - : value(std::move(value)) - , owner(nullptr) {} - - inline string to_string(u16 depth = 1) const override { - return get_indent(depth) + "CommentNode(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + ",\n" + get_indent(depth + 1) + - "owner: " + (owner ? owner->to_string(depth + 1) : "nullptr") + '\n' + - get_indent(depth) + ")"; - } +template < tokens StartToken, const char StartChar, typename Middle, const char EndChar, const tokens EndTokens> +struct Delimited:ASTBase> { + public: + AST_NODE_METHODS(Delimited); + public: - inline string node_name() const override { return "CommentNode"; } - - ParseResult validate(TokenList tokens) override { - // validate - return std::unexpected(ParseError()); - } + Delimited(TokenList parse_tokens) : tokens(parse_tokens) {} + + // const char start = StartChar; + // const char end = EndChar; - void accept(class Visitor &visitor) override { - // accepct - } -}; -struct ProgramNode : AstNode { - Token entry_point; // main | WinMain | wWinMain | DllMain - // mainCRTStartup | wmain | kernel_main - string filename; // example.hlx - any file (imported) not just the root file in the compile - // command - std::unique_ptr comment; // a file comment on the first few lines or after imports - AstNodeList<> body; // all the sub ast nodes - explicit ProgramNode(Token entry_point, string filename, AstNodeList<> body, - std::unique_ptr comment) - : entry_point(std::move(entry_point)) - , filename(std::move(filename)) - , comment(std::move(comment)) - , body(std::move(body)) {} - - inline string to_string(u16 depth = 1) const override { - std::string result = get_indent(depth) + "Program("+ '\n' - + get_indent(depth + 1) + "entry_point: " + entry_point.value() + ", " + '\n' - + get_indent(depth + 1) + "filename: " + filename + ", " + '\n' - + get_indent(depth + 1) + "comment: " + comment->to_string() + ", " + '\n' - + get_indent(depth + 1) + "body: [" + '\n'; - - for (auto node : body) { - result += node->to_string(depth + 2) + ",\n"; + ParseResult parse() { + // Check if the first token is the start token + if (tokens->get().front().token_kind() != StartToken) { + error::Error(error::Line(tokens->get().front(), "Expected a start token")); } - if (!body.empty()) { - result = result.substr(0, result.size() - 2) + "\n"; + // construct the middle + // make unique + + this->value = Middle{tokens}; + + // Parse the middle + this->value.get().parse(); + + // Check if the last token is the end token + if (tokens->get().back().token_kind() != EndTokens) { + error::Error(error::Line(tokens->get().back(), "Expected an end token")); } + - result += get_indent(depth + 1) + "]\n" + get_indent(depth) + ")"; - return result; + return std::nullopt; } - inline string node_name() const override { return "ProgramNode"; } - - ParseResult validate(TokenList tokens) override { - // validate - return std::unexpected(ParseError()); + std::string to_string() const { + return StartChar + this->value.get().to_string() + EndChar; } - void accept(class Visitor &visitor) override { - // accepct - } + private: + std::optional value = std::nullopt; }; + +template +using Parentheses = Delimited; + +template +using CurlyBraces = Delimited; + +template +using SquareBrack = Delimited; + +template +using AngleBrace = Delimited', tokens::PUNCTUATION_CLOSE_ANGLE>; + +template +using PipeDelimited = Delimited; + + + + + +/* + the following parsed and translated: + a: i16; // i16 a(); + a: i16 = 5; // i16 a = 5; + a: i16? = null; // std::optional a = std::nullopt; + a: ptr; // i16* a = std::make_unique(); + b: i16 = ref; // i16 b = &a; + c: i16 = ref>; // i16 c = &&a; + + ref parsed as: + Generic( + name: "ref", + arguments: [ + Identifier("a") + ] + ) + + fn add(a: T, b: T) -> T { + return a + b; + } + + + + add(5, 6) parsed as: + FunctionCall( + name: "add", + arguments: [ + Number(5), + Number(6) + ] + ) + + fn add(a: T, b: T) -> T parsed as: + FunctionDeclaration( + name: "add", + arguments: [ + Variable(name: "a", type: "T"), + Variable(name: "b", type: "T") + ], + return_type: "T", + generics: [ + Generic( + name: "add", + arguments: [ + Variable( + name: "T", + type: "Addable" + ) + ] + ) + ], + body: [ + Return( + value: BinaryOperation( + left: Variable("a"), + op: '+', + right: Variable("b") + ) + ) + ] + ) + +*/ } // namespace parser::ast +#undef AST_NODE_METHODS + #endif // __NODES_HH__ \ No newline at end of file diff --git a/source/parser/ast/include/parser.hh b/source/parser/ast/include/parser.hh index 05c6ef7..e577b5b 100644 --- a/source/parser/ast/include/parser.hh +++ b/source/parser/ast/include/parser.hh @@ -75,82 +75,7 @@ all possiblities to parse: */ class Parser { - private: - ast::AstNodeList<> body; - ast::AstNodeList<> stack; - token::TokenList &tokens; - - /* - StringLiteral - BooleanLiteral - NullLiteral - NumericLiteral - */ - inline void parse_literal(token::tokens type, std::vector::const_iterator &it) { - switch (type) { - case token::tokens::LITERAL_TRUE: - case token::tokens::LITERAL_FALSE: - body.push_back(std::make_unique(*it)); - ++it; // Advance the iterator - break; - case token::tokens::LITERAL_INTEGER: - case token::tokens::LITERAL_FLOATING_POINT: - body.push_back(std::make_unique(*it)); - ++it; // Advance the iterator - break; - case token::tokens::LITERAL_STRING: - case token::tokens::LITERAL_CHAR: - body.push_back(std::make_unique(*it)); - ++it; // Advance the iterator - break; - case token::tokens::LITERAL_NULL: - body.push_back(std::make_unique(*it)); - ++it; // Advance the iterator - break; - case token::tokens::EOF_TOKEN: - std::cout << "end of file" - << "\n"; - break; - default: - break; - } - } - - public: - explicit Parser(token::TokenList &tokens) - : tokens(tokens) {}; - - std::unique_ptr parse() { - token::tokens current_token_type{}; - - for (auto it = tokens.cbegin(); it != tokens.cend();) { - const token::Token ¤t_token = *it; - current_token_type = current_token.token_kind(); - - switch (current_token_type) { - case token::tokens::LITERAL_TRUE: - case token::tokens::LITERAL_FALSE: - case token::tokens::LITERAL_INTEGER: - case token::tokens::LITERAL_FLOATING_POINT: - case token::tokens::LITERAL_STRING: - case token::tokens::LITERAL_CHAR: - parse_literal(current_token_type, it); - break; - default: - ++it; // Manually advance the iterator if not handled by parse_literal - break; - } - } - - return std::make_unique( - // Token entry_point, string filename, AstNodeList<> body, std::unique_ptr comment - token::Token(), tokens.file_name(), body, std::make_unique( - token::Token( - 0, 0, 0, 0, "// this is a file comment", tokens.file_name(), "//" - ) - ) - ); - } + }; } // namespace parser diff --git a/source/parser/ast/source/ast.cc b/source/parser/ast/source/ast.cc index d670316..d063804 100644 --- a/source/parser/ast/source/ast.cc +++ b/source/parser/ast/source/ast.cc @@ -12,14 +12,11 @@ * https://helix-lang.com/ for more information. */ -#include +//#include #include #include #include -using namespace token; -using namespace parser::ast; - namespace parser::ast { -} // namespace parser::ast \ No newline at end of file +} // namespace parser::ast \ No newline at end of file diff --git a/source/parser/ast/source/nodes.cc b/source/parser/ast/source/nodes.cc index 000f95f..92fb1c9 100644 --- a/source/parser/ast/source/nodes.cc +++ b/source/parser/ast/source/nodes.cc @@ -11,327 +11,13 @@ * @note This code is provided by the creators of Helix. Visit our website at: * https://helix-lang.com/ for more information. */ -#include +//#include "parser/ast/include/nodes.hh" +#include +#include +#include "include/error/error.hh" +#include "include/printV2" namespace parser::ast { +using namespace token; -/* ----------------------------- NumericLiteral ---------------------------- */ -NumericLiteral::NumericLiteral(Token token) - : value(std::move(token)) {} - -string NumericLiteral::to_string(u16 depth) const { - return get_indent(depth) + "NumericLiteral(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult NumericLiteral::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void NumericLiteral::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ----------------------------- StringLiteral ----------------------------- */ -StringLiteral::StringLiteral(Token token) - : value(std::move(token)) {} - -string StringLiteral::to_string(u16 depth) const { - return get_indent(depth) + "StringLiteral(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult StringLiteral::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void StringLiteral::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ----------------------------- BooleanLiteral ---------------------------- */ -BooleanLiteral::BooleanLiteral(Token token) - : value(std::move(token)) {} - -string BooleanLiteral::to_string(u16 depth) const { - return get_indent(depth) + "BooleanLiteral(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult BooleanLiteral::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void BooleanLiteral::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ------------------------------ NullLiteral ------------------------------ */ -NullLiteral::NullLiteral(Token token) - : value(std::move(token)) {} - -string NullLiteral::to_string(u16 depth) const { - return get_indent(depth) + "NullLiteral(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult NullLiteral::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void NullLiteral::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ----------------------------- Identifier ----------------------------- */ -Identifier::Identifier(Token token) - : value(std::move(token)) {} - -string Identifier::to_string(u16 depth) const { - return get_indent(depth) + "Identifier(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult Identifier::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void Identifier::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ---------------------------- GenericArgument ---------------------------- */ -GenericArgument::GenericArgument(AstNodeList<> arguments) - : arguments(std::move(arguments)) {} - -string GenericArgument::to_string(u16 depth) const { - string result = - get_indent(depth) + "GenericArgument(" + '\n' + get_indent(depth + 1) + "arguments: ["; - - for (const auto &arg : arguments) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!arguments.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += "]\n" + get_indent(depth) + ")"; - - return result; -} - -ParseResult GenericArgument::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void GenericArgument::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* --------------------------- GenericInvocation --------------------------- */ -GenericInvocation::GenericInvocation(Token token, AstNodeList arguments) - : value(std::move(token)) - , arguments(std::move(arguments)) {} - -string GenericInvocation::to_string(u16 depth) const { - string result = get_indent(depth) + "GenericInvocation(" + '\n' + get_indent(depth + 1) + - "value: " + value.value() + '\n' + get_indent(depth + 1) + "arguments: ["; - - for (const auto &arg : arguments) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!arguments.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += "]\n" + get_indent(depth) + ")"; - return result; -} - -ParseResult GenericInvocation::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void GenericInvocation::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ------------------------------- Variable -------------------------------- */ -Variable::Variable(AstNodeRef name, AstNodeRef type, AstNodePtr value, - bool is_nullable, Token reference, Token pointer) - : name(std::move(name)) - , type(std::move(type)) - , value(std::move(value)) - , is_nullable(is_nullable) - , reference(std::move(reference)) - , pointer(std::move(pointer)) {} - -string Variable::to_string(u16 depth) const { - return get_indent(depth) + "Variable(" + '\n' + get_indent(depth + 1) + - "name: " + name->to_string(depth + 1) + '\n' + get_indent(depth + 1) + - "type: " + (type ? type->to_string(depth + 1) : "null") + '\n' + get_indent(depth + 1) + - "value: " + (value ? value->to_string(depth + 1) : "null") + '\n' + - get_indent(depth + 1) + "is_nullable: " + (is_nullable ? "true" : "false") + '\n' + - get_indent(depth + 1) + "reference: " + reference.value() + '\n' + - get_indent(depth + 1) + "pointer: " + pointer.value() + '\n' + get_indent(depth) + ")"; -} - -ParseResult Variable::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void Variable::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* -------------------------------- Return --------------------------------- */ -Return::Return(AstNodePtr value) - : value(std::move(value)) {} - -string Return::to_string(u16 depth) const { - return get_indent(depth) + "Return(" + '\n' + get_indent(depth + 1) + - "value: " + (value ? value->to_string(depth + 1) : "null") + '\n' + get_indent(depth) + - ")"; -} - -ParseResult Return::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void Return::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* -------------------------- BinaryOperation ----------------------------- */ -BinaryOperation::BinaryOperation(Token op, AstNodePtr left, AstNodePtr right) - : op(std::move(op)) - , left(std::move(left)) - , right(std::move(right)) {} - -string BinaryOperation::to_string(u16 depth) const { - return get_indent(depth) + "BinaryOperation(" + '\n' + get_indent(depth + 1) + - "op: " + op.value() + '\n' + get_indent(depth + 1) + - "left: " + left->to_string(depth + 1) + '\n' + get_indent(depth + 1) + - "right: " + right->to_string(depth + 1) + '\n' + get_indent(depth) + ")"; -} - -ParseResult BinaryOperation::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void BinaryOperation::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* --------------------------- ObjectInvocation ---------------------------- */ -ObjectInvocation::ObjectInvocation(Token name, AstNodeList<> arguments, - AstNodeList generics, - AstNodeList<> named_arguments) - : name(std::move(name)) - , arguments(std::move(arguments)) - , generics(std::move(generics)) - , named_arguments(std::move(named_arguments)) {} - -string ObjectInvocation::to_string(u16 depth) const { - string result = get_indent(depth) + "ObjectInvocation(" + '\n' + get_indent(depth + 1) + - "name: " + name.value() + '\n' + get_indent(depth + 1) + "arguments: ["; - - for (const auto &arg : arguments) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!arguments.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += std::string("]") + "\n" + get_indent(depth + 1) + "generics: ["; - - for (const auto &arg : generics) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!generics.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += std::string("]") + "\n" + get_indent(depth + 1) + "named_arguments: ["; - - for (const auto &arg : named_arguments) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!named_arguments.empty()) { - result = result.substr(0, result.size() - 2); - } - - return result + "\n" + get_indent(depth) + ")"; -} - -ParseResult ObjectInvocation::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void ObjectInvocation::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -/* ------------------------- StructureInvocation -------------------------- */ -StructureInvocation::StructureInvocation(Token name, AstNodeList<> arguments, - AstNodeList generics, - AstNodeList<> named_arguments) - : name(std::move(name)) - , arguments(std::move(arguments)) - , generics(std::move(generics)) { - // prase named_arguments into arguments - } - -string StructureInvocation::to_string(u16 depth) const { - string result = get_indent(depth) + "ObjectInvocation(" + '\n' + get_indent(depth + 1) + - "name: " + name.value() + '\n' + get_indent(depth + 1) + "arguments: ["; - - for (const auto &arg : arguments) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!arguments.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += std::string("]") + "\n" + get_indent(depth + 1) + "generics: ["; - - for (const auto &arg : generics) { - result += arg->to_string(depth + 1) + ", "; - } - - if (!generics.empty()) { - result = result.substr(0, result.size() - 2); - } - - result += std::string("]"); - - return result + "\n" + get_indent(depth) + ")"; -} - -ParseResult StructureInvocation::validate(TokenList tokens) { - // Add validation logic here - return {}; -} - -void StructureInvocation::accept(class Visitor &visitor) { - // Add visitor pattern logic here -} - -} // namespace parser::ast \ No newline at end of file +} // namespace parser::ast diff --git a/source/token/include/token.hh b/source/token/include/token.hh index 48650f0..615d45e 100644 --- a/source/token/include/token.hh +++ b/source/token/include/token.hh @@ -48,6 +48,7 @@ struct Token { Token &operator=(const Token &other); Token(Token &&other) noexcept; Token &operator=(Token &&other) noexcept; + Token &operator=(const std::string &other); Token(); explicit Token(tokens token_type, const std::string &filename, std::string value = ""); @@ -61,7 +62,7 @@ struct Token { tokens token_kind() const; std::string value() const; std::string_view token_kind_repr() const; - std::string_view file_name() const; + std::string file_name() const; std::string to_string() const; bool operator==(const Token &rhs) const; @@ -70,6 +71,7 @@ struct Token { /* ====-------------------------- setters ---------------------------==== */ void set_file_name(const std::string &file_name); + void set_value(const std::string &other); }; /** @@ -95,7 +97,7 @@ class TokenList : public std::vector { bool operator!=(const TokenListIter &other) const; bool operator==(const TokenListIter &other) const; - std::unique_ptr operator->(); // TODO: change if a shared ptr is needed + Token* operator->(); // TODO: change if a shared ptr is needed TokenListIter &operator*(); std::reference_wrapper operator--(); std::reference_wrapper operator++(); @@ -111,14 +113,9 @@ class TokenList : public std::vector { using const_iterator = std::vector::const_iterator; mutable const_iterator it; - std::optional yes(); + TokenList() = default; explicit TokenList(std::string filename); - Token next(u32 n = 1) const; - [[nodiscard]] Token peek(u32 n = 1) const; - [[nodiscard]] Token current() const; - TokenListIter begin() { return TokenListIter(*this); } - TokenListIter end() { return TokenListIter(*this, this->size() - 1); } [[nodiscard]] std::vector::const_iterator cbegin() const { return std::vector::begin(); @@ -134,13 +131,14 @@ class TokenList : public std::vector { return std::vector::end(); } - [[nodiscard]] Token previous(u32 n = 1) const; + TokenListIter begin() { return TokenListIter(*this); } + TokenListIter end() { return TokenListIter(*this, this->size() - 1); } + void remove_left(); void reset(); void append(const Token &token); TokenList slice(u64 start, u64 end); - [[nodiscard]] bool reached_end() const; [[nodiscard]] std::string file_name() const; void insert_remove(TokenList &tokens, u64 start, u64 end); diff --git a/source/token/source/token.cc b/source/token/source/token.cc index bad617b..1f219bd 100644 --- a/source/token/source/token.cc +++ b/source/token/source/token.cc @@ -134,16 +134,18 @@ std::string Token::value() const { return val; } std::string_view Token::token_kind_repr() const { return tokens_map.at(kind).value(); } -std::string_view Token::file_name() const { return filename; } +std::string Token::file_name() const { return filename; } void Token::set_file_name(const std::string &file_name) { this->filename = std::string(file_name); } +void Token::set_value(const std::string &other) { this->val = std::string(other); } + std::string Token::to_string() const { return std::string("Token(") + std::string("line: ") + std::to_string(line) + std::string(", column: ") + std::to_string(column) + std::string(", len: ") + std::to_string(len) + std::string(", offset: ") + std::to_string(_offset) + - std::string(", kind: ") + std::string(token_kind_repr()) + std::string(", val: ") + - std::string(val) + ")"; + std::string(", kind: ") + std::string(token_kind_repr()) + std::string(", val: \"") + + std::string(val) + "\")"; } bool Token::operator==(const Token &rhs) const { diff --git a/source/token/source/token_list.cc b/source/token/source/token_list.cc index e309d94..6e08c5c 100644 --- a/source/token/source/token_list.cc +++ b/source/token/source/token_list.cc @@ -12,6 +12,7 @@ * https://helix-lang.com/ for more information. */ +#include #include #include @@ -29,49 +30,6 @@ TokenList::TokenList(std::string filename, std::vector::const_iterator st : std::vector(start, end) , filename(std::move(filename)) {} -Token TokenList::next(u32 n) const { - if (it == this->cend()) { - return {}; - } - - if (it + n >= this->cend()) { - return *(this->cend() - 1); - } - - return *(it + n++); -} - -Token TokenList::peek(u32 n) const { - if (it == this->cend()) { - return {}; - } - - if (it + n >= this->cend()) { - return *(this->cend() - 1); - } - - return *(it + n); -} - -Token TokenList::current() const { - if (it == this->cbegin()) { - return {}; - } - return *(it - 1); -} - -Token TokenList::previous(u32 n) const { - if (it == this->cbegin()) { - return {}; - } - - if (it - n < this->cbegin()) { - return *(this->cbegin()); - } - - return *(it - n); -} - void TokenList::remove_left() { this->erase(this->cbegin(), it); it = this->cbegin(); @@ -116,8 +74,6 @@ void TokenList::insert_remove(TokenList &tokens, u64 start, u64 end) { this->insert(start_it, tokens.cbegin(), tokens.cend()); } -bool TokenList::reached_end() const { return it == this->cend(); } - void print_tokens(token::TokenList &tokens) { u16 indent = 0; @@ -180,9 +136,10 @@ bool TokenList::TokenListIter::operator==(const TokenListIter &other) const { return cursor_position == other.cursor_position; } -std::unique_ptr TokenList::TokenListIter::operator->() { - return std::make_unique(tokens.get()[cursor_position]); -} // TODO: change if a shared ptr is needed +// FIXME : This is a temporary fix, need to change this to a a reference +Token* TokenList::TokenListIter::operator->() { + return &tokens.get()[cursor_position]; +} // TODO: change if a shared ptr is needed TokenList::TokenListIter &TokenList::TokenListIter::operator*() { return *this; } diff --git a/source/tools/controllers/source/resolve.cc b/source/tools/controllers/source/resolve.cc index 60ca03e..664c0c0 100644 --- a/source/tools/controllers/source/resolve.cc +++ b/source/tools/controllers/source/resolve.cc @@ -11,7 +11,7 @@ * @note This code is provided by the creators of Helix. Visit our website at: * https://helix-lang.com/ for more information. */ -#include +#include "tools/controllers/include/file_system.hh" #include #include diff --git a/tests/main.hlx b/tests/main.hlx index 909f767..5750376 100644 --- a/tests/main.hlx +++ b/tests/main.hlx @@ -1,51 +1,4 @@ -// import test_imports; // module import -// import test_imports::some_import; // file import -import test_imports::test; -#[ - doc(" - --- - title: Main API - --- - import { Tabs, TabItem } from '@astrojs/starlight/components'; +("hello world"); - Welcome to Helix! It's traditional when learning a new language to write a program that prints "Hello, World!" to the screen. We'll follow this tradition here. - - :::note - This guide assumes basic familiarity with the command line. Helix makes no specific demands about your editing tools or where your code lives. Feel free to use your favorite IDE. Many IDEs support Helix; check their documentation for details. - ::: - - ## Writing and Running a Helix Program - - First, create a new directory for your Helix project. Ideally in `~/projects/hello_world` - Next, create a new source file and call it `main.hlx`. Helix files use the `.hlx` extension. If you're using more than one word in your filename, use an underscore to separate them (e.g., `hello_world.hlx`). - - Open the `main.hlx` file you just created and enter the following code: - - ```Helix title=\"main.hlx\" - fn main() { - print(\"Hello, World!\"); - } - ``` - - ### Compiling and Running the Program - - Save the file and return to your terminal in the `~/projects/hello_world` directory. To compile your Helix program, run: - - ```sh - helix main.hlx - ``` - - This is a doc comment - its in mdx format and would be used - by the auto doc-gen tool built into the compiler - it allows for users to write clea and readable comments. - ") -] -fn main() -> int? { // becomes std::optional - print("hey there", "hello"); -} - -fn main2() -> int { - print("hey there", "hello"); -} \ No newline at end of file +# \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index 761e26e..2028add 100644 --- a/xmake.lua +++ b/xmake.lua @@ -30,7 +30,7 @@ target("tests") add_files("tests/**.cc") -- add all files in the tests directory add_files("source/**.cc") -- add all .cc files in the source directory and its subdirectories remove_files("source/main.cc") -- exclude main.cc from the source directory - + add_headerfiles("source/**.hh") -- add all headers in the source directory add_headerfiles("tests/**.hh") -- add all headers in the tests directory