further progress
This commit is contained in:
		
							parent
							
								
									ceab70ed84
								
							
						
					
					
						commit
						b416776527
					
				
							
								
								
									
										45
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								README.md
									
									
									
									
									
								
							@ -1,2 +1,45 @@
 | 
				
			|||||||
# plsm
 | 
					# plsm
 | 
				
			||||||
Mainly functional general purpose programming language
 | 
					
 | 
				
			||||||
 | 
					Toy general purpose systems programming lanugage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Hello World Example (+ unicode, yeah)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This example just looks like C without its syntax when in reality, plsm aims to be different. It shall have support for classes, lambdas, interfaces/traits and easy modularization.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```plsm
 | 
				
			||||||
 | 
					fun write(fd : i64, msg : &u8, len : u64) i64 {
 | 
				
			||||||
 | 
					  inline asm (
 | 
				
			||||||
 | 
					    "mov $0, %rax"         // syscall: write
 | 
				
			||||||
 | 
					    "mov $1, %rdi"         // file descriptor: stdout
 | 
				
			||||||
 | 
					    "mov $2, %rsi"         // message to write
 | 
				
			||||||
 | 
					    "mov $3, %rdx"         // length of message
 | 
				
			||||||
 | 
					    "syscall"              // make the syscall
 | 
				
			||||||
 | 
					    :
 | 
				
			||||||
 | 
					    : "r"(1 as i64), "r"(1 as i64), "r"(msg), "r"(len)  // input: different params
 | 
				
			||||||
 | 
					    : "rax", "rdi", "rsi", "rdx"                        // clobbered registers
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun exit(code : u8) i64 {
 | 
				
			||||||
 | 
					  inline asm (
 | 
				
			||||||
 | 
					    "mov $0, %rax"
 | 
				
			||||||
 | 
					    "mov $1, %rdi"
 | 
				
			||||||
 | 
					    "syscall"
 | 
				
			||||||
 | 
					    :
 | 
				
			||||||
 | 
					    : "r"(60 as i64), "r"(code as i64)
 | 
				
			||||||
 | 
					    : "rax", "rdi"
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun main(argc : i32) u8 {
 | 
				
			||||||
 | 
					  write(1, "Hello World!\n", 14);
 | 
				
			||||||
 | 
					  write(1, "Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ Ơ ơ Ƣ ƣ Ƥ ƥ\n", 69);
 | 
				
			||||||
 | 
					  exit(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
							
								
								
									
										1
									
								
								compiler/.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								compiler/.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@ -4,6 +4,7 @@
 | 
				
			|||||||
    "${workspaceFolder}/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src",
 | 
					    "${workspaceFolder}/build/antlr4_runtime/src/antlr4_runtime/runtime/Cpp/runtime/src",
 | 
				
			||||||
    "/usr/lib64/llvm18/include",
 | 
					    "/usr/lib64/llvm18/include",
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 | 
					  "clang-format.style": "{ColumnLimit: 110}",
 | 
				
			||||||
  "files.associations": {
 | 
					  "files.associations": {
 | 
				
			||||||
    "*.embeddedhtml": "html",
 | 
					    "*.embeddedhtml": "html",
 | 
				
			||||||
    "iosfwd": "cpp",
 | 
					    "iosfwd": "cpp",
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,8 @@
 | 
				
			|||||||
#include "Stmt/WhileStmt.h"
 | 
					#include "Stmt/WhileStmt.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "Type/FunctionType.h"
 | 
					#include "Type/FunctionType.h"
 | 
				
			||||||
 | 
					#include "Type/PointerType.h"
 | 
				
			||||||
#include "Type/PrimitiveType.h"
 | 
					#include "Type/PrimitiveType.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "TypeName/NamedTypeName.h"
 | 
					#include "TypeName/NamedTypeName.h"
 | 
				
			||||||
 | 
					#include "TypeName/PointerTypeName.h"
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@ class LambdaExpr;
 | 
				
			|||||||
class UnExpr;
 | 
					class UnExpr;
 | 
				
			||||||
class IntValue;
 | 
					class IntValue;
 | 
				
			||||||
class FloatValue;
 | 
					class FloatValue;
 | 
				
			||||||
 | 
					class StringValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Import;
 | 
					class Import;
 | 
				
			||||||
class Module;
 | 
					class Module;
 | 
				
			||||||
@ -37,11 +38,14 @@ class ExprStmt;
 | 
				
			|||||||
class FnParam;
 | 
					class FnParam;
 | 
				
			||||||
class FnDecl;
 | 
					class FnDecl;
 | 
				
			||||||
class IfStmt;
 | 
					class IfStmt;
 | 
				
			||||||
 | 
					class InlineAsm;
 | 
				
			||||||
 | 
					class InlineAsmConstraint;
 | 
				
			||||||
class RetStmt;
 | 
					class RetStmt;
 | 
				
			||||||
class VarDecl;
 | 
					class VarDecl;
 | 
				
			||||||
class WhileStmt;
 | 
					class WhileStmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NamedTypeName;
 | 
					class NamedTypeName;
 | 
				
			||||||
 | 
					class PointerTypeName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ASTVisitor {
 | 
					class ASTVisitor {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
@ -55,6 +59,7 @@ public:
 | 
				
			|||||||
  virtual std::any visit(UnExpr &unExpr, std::any param) = 0;
 | 
					  virtual std::any visit(UnExpr &unExpr, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(IntValue &intValue, std::any param) = 0;
 | 
					  virtual std::any visit(IntValue &intValue, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(FloatValue &floatValue, std::any param) = 0;
 | 
					  virtual std::any visit(FloatValue &floatValue, std::any param) = 0;
 | 
				
			||||||
 | 
					  virtual std::any visit(StringValue &stringValue, std::any param) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(Import &import, std::any param) = 0;
 | 
					  virtual std::any visit(Import &import, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(Module &module, std::any param) = 0;
 | 
					  virtual std::any visit(Module &module, std::any param) = 0;
 | 
				
			||||||
@ -65,14 +70,14 @@ public:
 | 
				
			|||||||
  virtual std::any visit(FnParam &fnParam, std::any param) = 0;
 | 
					  virtual std::any visit(FnParam &fnParam, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(FnDecl &fnDecl, std::any param) = 0;
 | 
					  virtual std::any visit(FnDecl &fnDecl, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(IfStmt &ifStmt, std::any param) = 0;
 | 
					  virtual std::any visit(IfStmt &ifStmt, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint,
 | 
					  virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint, std::any param) = 0;
 | 
				
			||||||
                         std::any param) = 0;
 | 
					 | 
				
			||||||
  virtual std::any visit(InlineAsm &inlineAsm, std::any param) = 0;
 | 
					  virtual std::any visit(InlineAsm &inlineAsm, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(RetStmt &retStmt, std::any param) = 0;
 | 
					  virtual std::any visit(RetStmt &retStmt, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(VarDecl &varDecl, std::any param) = 0;
 | 
					  virtual std::any visit(VarDecl &varDecl, std::any param) = 0;
 | 
				
			||||||
  virtual std::any visit(WhileStmt &whileStmt, std::any param) = 0;
 | 
					  virtual std::any visit(WhileStmt &whileStmt, std::any param) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(NamedTypeName &namedTypeName, std::any param) = 0;
 | 
					  virtual std::any visit(NamedTypeName &namedTypeName, std::any param) = 0;
 | 
				
			||||||
 | 
					  virtual std::any visit(PointerTypeName &pointerTypeName, std::any param) = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ast
 | 
					} // namespace ast
 | 
				
			||||||
@ -89,8 +94,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
  template <class CurrNode>
 | 
					  template <class CurrNode>
 | 
				
			||||||
  static inline boost::json::value getJsonProperty(boost::json::value json,
 | 
					  static inline boost::json::value getJsonProperty(boost::json::value json, std::string property) {
 | 
				
			||||||
                                                   std::string property) {
 | 
					 | 
				
			||||||
    boost::json::value prop;
 | 
					    boost::json::value prop;
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      if (!json.as_object().contains(property))
 | 
					      if (!json.as_object().contains(property))
 | 
				
			||||||
@ -98,8 +102,8 @@ protected:
 | 
				
			|||||||
      prop = json.as_object().at(property);
 | 
					      prop = json.as_object().at(property);
 | 
				
			||||||
    } catch (...) {
 | 
					    } catch (...) {
 | 
				
			||||||
      std::cout << boost::json::serialize(json) << std::endl;
 | 
					      std::cout << boost::json::serialize(json) << std::endl;
 | 
				
			||||||
      throw std::runtime_error("missing property '" + property + "' in " +
 | 
					      throw std::runtime_error("missing property '" + property + "' in " + typeid(CurrNode).name() +
 | 
				
			||||||
                               typeid(CurrNode).name() + "::fromJson");
 | 
					                               "::fromJson");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return prop;
 | 
					    return prop;
 | 
				
			||||||
@ -111,22 +115,18 @@ protected:
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      return boost::json::value_to<T>(prop);
 | 
					      return boost::json::value_to<T>(prop);
 | 
				
			||||||
    } catch (...) {
 | 
					    } catch (...) {
 | 
				
			||||||
      throw std::runtime_error("invalid value for property '" + property +
 | 
					      throw std::runtime_error("invalid value for property '" + property + "' in " + typeid(CurrNode).name() +
 | 
				
			||||||
                               "' in " + typeid(CurrNode).name() +
 | 
					 | 
				
			||||||
                               "::fromJson");
 | 
					                               "::fromJson");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <class CurrNode, class SubNode>
 | 
					  template <class CurrNode, class SubNode>
 | 
				
			||||||
  static inline auto fromJsonProperty(boost::json::value json,
 | 
					  static inline auto fromJsonProperty(boost::json::value json, std::string property) {
 | 
				
			||||||
                                      std::string property) {
 | 
					    return std::unique_ptr<SubNode>(SubNode::fromJson(getJsonProperty<CurrNode>(json, property)));
 | 
				
			||||||
    return std::unique_ptr<SubNode>(
 | 
					 | 
				
			||||||
        SubNode::fromJson(getJsonProperty<CurrNode>(json, property)));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <class CurrNode, class SubNode>
 | 
					  template <class CurrNode, class SubNode>
 | 
				
			||||||
  static inline auto fromJsonVector(boost::json::value json,
 | 
					  static inline auto fromJsonVector(boost::json::value json, std::string property) {
 | 
				
			||||||
                                    std::string property) {
 | 
					 | 
				
			||||||
    auto arr = getJsonProperty<CurrNode>(json, property).as_array();
 | 
					    auto arr = getJsonProperty<CurrNode>(json, property).as_array();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<std::unique_ptr<SubNode>> result;
 | 
					    std::vector<std::unique_ptr<SubNode>> result;
 | 
				
			||||||
@ -140,20 +140,16 @@ protected:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SourceRange {
 | 
					class SourceRange {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  SourceRange(const std::string &file, std::string text,
 | 
					  SourceRange(const std::string &file, std::string text, std::pair<size_t, size_t> start,
 | 
				
			||||||
              std::pair<size_t, size_t> start, std::pair<size_t, size_t> end)
 | 
					              std::pair<size_t, size_t> end)
 | 
				
			||||||
      : file(file), text(text), start(start), end(end) {}
 | 
					      : file(file), text(text), start(start), end(end) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const std::string file, text;
 | 
					  const std::string file, text;
 | 
				
			||||||
  const std::pair<size_t, size_t> start, end;
 | 
					  const std::pair<size_t, size_t> start, end;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static SourceRange unknown() {
 | 
					  static SourceRange unknown() { return SourceRange("<?>", "<?>", {0, 0}, {0, 0}); };
 | 
				
			||||||
    return SourceRange("<?>", "<?>", {0, 0}, {0, 0});
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static SourceRange json() {
 | 
					  static SourceRange json() { return SourceRange("<json>", "<json>", {0, 0}, {0, 0}); };
 | 
				
			||||||
    return SourceRange("<json>", "<json>", {0, 0}, {0, 0});
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TypeName;
 | 
					class TypeName;
 | 
				
			||||||
@ -166,7 +162,7 @@ public:
 | 
				
			|||||||
  virtual TypeName *toTypeName() = 0;
 | 
					  virtual TypeName *toTypeName() = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual bool operator==(const Type &other) = 0;
 | 
					  virtual bool operator==(const Type &other) = 0;
 | 
				
			||||||
  virtual bool operator!=(const Type &other) { return !(*this == other); }
 | 
					  virtual bool operator!=(const Type &other) { return !((*this) == other); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static Type *fromJson(boost::json::value json);
 | 
					  static Type *fromJson(boost::json::value json);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -187,9 +183,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const SourceRange sourceRange;
 | 
					  const SourceRange sourceRange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::string toJsonString() const {
 | 
					  virtual std::string toJsonString() const { return boost::json::serialize(toJson(), {}); }
 | 
				
			||||||
    return boost::json::serialize(toJson(), {});
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static ASTNode *fromJson(boost::json::value json);
 | 
					  static ASTNode *fromJson(boost::json::value json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -200,8 +194,8 @@ public:
 | 
				
			|||||||
  virtual std::string error(const std::string &message) const {
 | 
					  virtual std::string error(const std::string &message) const {
 | 
				
			||||||
    std::stringstream ss;
 | 
					    std::stringstream ss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ss << "In file " << sourceRange.file << ":" << sourceRange.start.first
 | 
					    ss << "In file " << sourceRange.file << ":" << sourceRange.start.first << ":"
 | 
				
			||||||
       << ":" << sourceRange.start.second + 1 << "\n"
 | 
					       << sourceRange.start.second + 1 << "\n"
 | 
				
			||||||
       << terminal::cyan << sourceRange.text << terminal::reset << "\n"
 | 
					       << terminal::cyan << sourceRange.text << terminal::reset << "\n"
 | 
				
			||||||
       << terminal::red << message << terminal::reset;
 | 
					       << terminal::red << message << terminal::reset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -37,9 +37,7 @@ public:
 | 
				
			|||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(Identifier &identifier, std::any param) override {
 | 
					  virtual std::any visit(Identifier &identifier, std::any param) override { return std::any(); }
 | 
				
			||||||
    return std::any();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(LambdaExpr &lambdaExpr, std::any param) override {
 | 
					  virtual std::any visit(LambdaExpr &lambdaExpr, std::any param) override {
 | 
				
			||||||
    if (lambdaExpr.returnTypeName.get())
 | 
					    if (lambdaExpr.returnTypeName.get())
 | 
				
			||||||
@ -62,17 +60,13 @@ public:
 | 
				
			|||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(IntValue &intValue, std::any param) override {
 | 
					  virtual std::any visit(IntValue &intValue, std::any param) override { return std::any(); }
 | 
				
			||||||
    return std::any();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FloatValue &floatValue, std::any param) override {
 | 
					  virtual std::any visit(FloatValue &floatValue, std::any param) override { return std::any(); }
 | 
				
			||||||
    return std::any();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(Import &import, std::any param) override {
 | 
					  virtual std::any visit(StringValue &stringValue, std::any param) override { return std::any(); }
 | 
				
			||||||
    return std::any();
 | 
					
 | 
				
			||||||
  }
 | 
					  virtual std::any visit(Import &import, std::any param) override { return std::any(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(Module &module, std::any param) override {
 | 
					  virtual std::any visit(Module &module, std::any param) override {
 | 
				
			||||||
    for (auto &import : module.imports) {
 | 
					    for (auto &import : module.imports) {
 | 
				
			||||||
@ -142,8 +136,9 @@ public:
 | 
				
			|||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint,
 | 
					  virtual std::any visit(InlineAsmConstraint &inlineAsmConstraint, std::any param) override {
 | 
				
			||||||
                         std::any param) override {
 | 
					    if (inlineAsmConstraint.value.get())
 | 
				
			||||||
 | 
					      inlineAsmConstraint.value->accept(this, param);
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -182,8 +177,11 @@ public:
 | 
				
			|||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(NamedTypeName &namedTypeName,
 | 
					  virtual std::any visit(NamedTypeName &namedTypeName, std::any param) override { return std::any(); }
 | 
				
			||||||
                         std::any param) override {
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(PointerTypeName &pointerTypeName, std::any param) override {
 | 
				
			||||||
 | 
					    if (pointerTypeName.baseTypeName.get())
 | 
				
			||||||
 | 
					      pointerTypeName.baseTypeName->accept(this, param);
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ class IntValue : public Expr {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
  const std::int64_t value;
 | 
					  const std::int64_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  IntValue(LOC_ARG, int64_t value) : Expr(sourceRange), value(value) {}
 | 
					  IntValue(LOC_ARG, std::int64_t value) : Expr(sourceRange), value(value) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual boost::json::value toJson() const override;
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
  static IntValue *fromJson(boost::json::value json);
 | 
					  static IntValue *fromJson(boost::json::value json);
 | 
				
			||||||
@ -32,7 +32,7 @@ class FloatValue : public Expr {
 | 
				
			|||||||
public:
 | 
					public:
 | 
				
			||||||
  const std::double_t value;
 | 
					  const std::double_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FloatValue(LOC_ARG, double value) : Expr(sourceRange), value(value) {}
 | 
					  FloatValue(LOC_ARG, std::double_t value) : Expr(sourceRange), value(value) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual boost::json::value toJson() const override;
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
  static FloatValue *fromJson(boost::json::value json);
 | 
					  static FloatValue *fromJson(boost::json::value json);
 | 
				
			||||||
@ -42,5 +42,19 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StringValue : public Expr {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  const std::string value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  StringValue(LOC_ARG, std::string value) : Expr(sourceRange), value(value) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
 | 
					  static StringValue *fromJson(boost::json::value json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any accept(ASTVisitor *visitor, std::any param) override {
 | 
				
			||||||
 | 
					    return visitor->visit(*this, param);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ast
 | 
					} // namespace ast
 | 
				
			||||||
} // namespace plsm
 | 
					} // namespace plsm
 | 
				
			||||||
 | 
				
			|||||||
@ -5,10 +5,11 @@ namespace ast {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class InlineAsmConstraint : public ASTNode {
 | 
					class InlineAsmConstraint : public ASTNode {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  std::string constraint, variable;
 | 
					  std::string constraint;
 | 
				
			||||||
 | 
					  std::unique_ptr<Expr> value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  InlineAsmConstraint(LOC_ARG, std::string constraint, std::string variable)
 | 
					  InlineAsmConstraint(LOC_ARG, std::string constraint, std::unique_ptr<Expr> value)
 | 
				
			||||||
      : ASTNode(sourceRange), constraint(constraint), variable(variable) {}
 | 
					      : ASTNode(sourceRange), constraint(constraint), value(std::move(value)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual boost::json::value toJson() const override;
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
  static InlineAsmConstraint *fromJson(boost::json::value json);
 | 
					  static InlineAsmConstraint *fromJson(boost::json::value json);
 | 
				
			||||||
@ -25,12 +26,10 @@ public:
 | 
				
			|||||||
  std::vector<std::unique_ptr<InlineAsmConstraint>> inputs;
 | 
					  std::vector<std::unique_ptr<InlineAsmConstraint>> inputs;
 | 
				
			||||||
  std::vector<std::string> clobbers;
 | 
					  std::vector<std::string> clobbers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  InlineAsm(LOC_ARG, std::string code,
 | 
					  InlineAsm(LOC_ARG, std::string code, std::vector<std::unique_ptr<InlineAsmConstraint>> outputs,
 | 
				
			||||||
            std::vector<std::unique_ptr<InlineAsmConstraint>> outputs,
 | 
					            std::vector<std::unique_ptr<InlineAsmConstraint>> inputs, std::vector<std::string> clobbers)
 | 
				
			||||||
            std::vector<std::unique_ptr<InlineAsmConstraint>> inputs,
 | 
					      : Stmt(sourceRange), code(code), outputs(std::move(outputs)), inputs(std::move(inputs)),
 | 
				
			||||||
            std::vector<std::string> clobbers)
 | 
					        clobbers(std::move(clobbers)) {}
 | 
				
			||||||
      : Stmt(sourceRange), code(code), outputs(std::move(outputs)),
 | 
					 | 
				
			||||||
        inputs(std::move(inputs)), clobbers(clobbers) {}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual boost::json::value toJson() const override;
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
  static InlineAsm *fromJson(boost::json::value json);
 | 
					  static InlineAsm *fromJson(boost::json::value json);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								compiler/include/AST/Type/PointerType.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								compiler/include/AST/Type/PointerType.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "AST/Base.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace plsm {
 | 
				
			||||||
 | 
					namespace ast {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PointerType : public Type {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  const std::shared_ptr<Type> baseType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PointerType(const std::shared_ptr<Type> &baseType) : Type(), baseType(baseType) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual TypeName *toTypeName() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual bool operator==(const Type &other) override {
 | 
				
			||||||
 | 
					    if (const PointerType *pt = dynamic_cast<const PointerType *>(&other)) {
 | 
				
			||||||
 | 
					      return *baseType == *pt->baseType;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
 | 
					  static PointerType *fromJson(boost::json::value json);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ast
 | 
				
			||||||
 | 
					} // namespace plsm
 | 
				
			||||||
							
								
								
									
										24
									
								
								compiler/include/AST/TypeName/PointerTypeName.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								compiler/include/AST/TypeName/PointerTypeName.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "AST/Base.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace plsm {
 | 
				
			||||||
 | 
					namespace ast {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PointerTypeName : public TypeName {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  const std::unique_ptr<TypeName> baseTypeName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PointerTypeName(LOC_ARG, std::unique_ptr<TypeName> baseTypeName)
 | 
				
			||||||
 | 
					      : TypeName(sourceRange), baseTypeName(std::move(baseTypeName)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual boost::json::value toJson() const override;
 | 
				
			||||||
 | 
					  static PointerTypeName *fromJson(boost::json::value json);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any accept(ASTVisitor *visitor, std::any param) override {
 | 
				
			||||||
 | 
					    return visitor->visit(*this, param);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ast
 | 
				
			||||||
 | 
					} // namespace plsm
 | 
				
			||||||
@ -103,16 +103,25 @@ stmt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
inlineAsm
 | 
					inlineAsm
 | 
				
			||||||
	returns[std::unique_ptr<InlineAsm> ast]:
 | 
						returns[std::unique_ptr<InlineAsm> ast]:
 | 
				
			||||||
	'inline' 'asm' '(' inlineAsmCode = string (
 | 
						'inline' 'asm' '(' (inlineAsmCode += string)+ (
 | 
				
			||||||
		':' outputs += inlineAsmConstraint (
 | 
							':' (
 | 
				
			||||||
 | 
								outputs += inlineAsmConstraint (
 | 
				
			||||||
				',' outputs += inlineAsmConstraint
 | 
									',' outputs += inlineAsmConstraint
 | 
				
			||||||
			)*
 | 
								)*
 | 
				
			||||||
 | 
							)?
 | 
				
			||||||
	)? (
 | 
						)? (
 | 
				
			||||||
		':' inputs += inlineAsmConstraint (
 | 
							':' (
 | 
				
			||||||
 | 
								inputs += inlineAsmConstraint (
 | 
				
			||||||
				',' inputs += inlineAsmConstraint
 | 
									',' inputs += inlineAsmConstraint
 | 
				
			||||||
			)*
 | 
								)*
 | 
				
			||||||
	)? (':' clobbers += string ( ',' clobbers += string)*)? ')' ';' {
 | 
							)?
 | 
				
			||||||
        auto code = $ctx->inlineAsmCode->value;
 | 
						)? (':' (clobbers += string ( ',' clobbers += string)*)?)? ')' ';' {
 | 
				
			||||||
 | 
					          std::string code = "";
 | 
				
			||||||
 | 
					          for (auto &asmCode : $ctx->inlineAsmCode) {
 | 
				
			||||||
 | 
					               code += asmCode->value;
 | 
				
			||||||
 | 
					               code += ";";
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          code.pop_back();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          std::vector<std::unique_ptr<InlineAsmConstraint>> outputs;
 | 
					          std::vector<std::unique_ptr<InlineAsmConstraint>> outputs;
 | 
				
			||||||
          for (auto &output : $ctx->outputs) {
 | 
					          for (auto &output : $ctx->outputs) {
 | 
				
			||||||
@ -135,10 +144,16 @@ inlineAsm
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
inlineAsmConstraint
 | 
					inlineAsmConstraint
 | 
				
			||||||
	returns[std::unique_ptr<InlineAsmConstraint> ast]:
 | 
						returns[std::unique_ptr<InlineAsmConstraint> ast]:
 | 
				
			||||||
	string '(' IDENTIFIER ')' {
 | 
						string '(' expr ')' {
 | 
				
			||||||
        auto constraint = $ctx->string()->value;
 | 
					        auto constraint = $ctx->string()->value;
 | 
				
			||||||
        auto variable = $ctx->IDENTIFIER()->getText();
 | 
					        $ast = std::make_unique<InlineAsmConstraint>(getSourceRange($ctx), constraint, std::move($ctx->expr()->ast));
 | 
				
			||||||
        $ast = std::make_unique<InlineAsmConstraint>(getSourceRange($ctx), constraint, variable);
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inlineAsmLvalueConstraint
 | 
				
			||||||
 | 
						returns[std::unique_ptr<InlineAsmConstraint> ast]:
 | 
				
			||||||
 | 
						string '(' lvalue ')' {
 | 
				
			||||||
 | 
					        auto constraint = $ctx->string()->value;
 | 
				
			||||||
 | 
					        $ast = std::make_unique<InlineAsmConstraint>(getSourceRange($ctx), constraint, std::move($ctx->lvalue()->ast));
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
whileStmt
 | 
					whileStmt
 | 
				
			||||||
@ -185,10 +200,16 @@ implDeclAssignStmt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
assignStmt
 | 
					assignStmt
 | 
				
			||||||
	returns[std::unique_ptr<AssignStmt> ast]:
 | 
						returns[std::unique_ptr<AssignStmt> ast]:
 | 
				
			||||||
	lval = expr '=' rval = expr ';' {
 | 
						lval = lvalue '=' rval = expr ';' {
 | 
				
			||||||
          $ast = std::make_unique<AssignStmt>(getSourceRange($ctx), std::move($ctx->lval->ast), std::move($ctx->rval->ast));
 | 
					          $ast = std::make_unique<AssignStmt>(getSourceRange($ctx), std::move($ctx->lval->ast), std::move($ctx->rval->ast));
 | 
				
			||||||
     };
 | 
					     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					lvalue
 | 
				
			||||||
 | 
						returns[std::unique_ptr<Expr> ast]:
 | 
				
			||||||
 | 
						identifier {
 | 
				
			||||||
 | 
					          $ast = ptrcast<Expr>($ctx->identifier()->ast);
 | 
				
			||||||
 | 
					     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
retStmt
 | 
					retStmt
 | 
				
			||||||
	returns[std::unique_ptr<RetStmt> ast]:
 | 
						returns[std::unique_ptr<RetStmt> ast]:
 | 
				
			||||||
	'ret' expr ';' {
 | 
						'ret' expr ';' {
 | 
				
			||||||
@ -361,6 +382,9 @@ factorExpr
 | 
				
			|||||||
     }
 | 
					     }
 | 
				
			||||||
	| lambdaExpr {
 | 
						| lambdaExpr {
 | 
				
			||||||
          $ast = ptrcast<Expr>($ctx->lambdaExpr()->ast);
 | 
					          $ast = ptrcast<Expr>($ctx->lambdaExpr()->ast);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
						| string {
 | 
				
			||||||
 | 
					          $ast = std::unique_ptr<Expr>((Expr *) new StringValue(getSourceRange($ctx), $ctx->string()->value));
 | 
				
			||||||
     }
 | 
					     }
 | 
				
			||||||
	| '(' expr ')' {
 | 
						| '(' expr ')' {
 | 
				
			||||||
          $ast = std::move($ctx->expr()->ast);
 | 
					          $ast = std::move($ctx->expr()->ast);
 | 
				
			||||||
@ -394,6 +418,11 @@ typeName
 | 
				
			|||||||
          auto text = $ctx->IDENTIFIER()->getText();
 | 
					          auto text = $ctx->IDENTIFIER()->getText();
 | 
				
			||||||
          auto named = std::make_unique<NamedTypeName>(getSourceRange($ctx), text);
 | 
					          auto named = std::make_unique<NamedTypeName>(getSourceRange($ctx), text);
 | 
				
			||||||
          $ast = ptrcast<TypeName>(named);
 | 
					          $ast = ptrcast<TypeName>(named);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
						| '&' typeName {
 | 
				
			||||||
 | 
					          auto typeName = std::move($ctx->typeName()->ast);
 | 
				
			||||||
 | 
					          auto ptr = std::make_unique<PointerTypeName>(getSourceRange($ctx), std::move(typeName));
 | 
				
			||||||
 | 
					          $ast = ptrcast<TypeName>(ptr);
 | 
				
			||||||
     };
 | 
					     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
string
 | 
					string
 | 
				
			||||||
@ -404,6 +433,12 @@ string
 | 
				
			|||||||
          $value = decoded.as_string();
 | 
					          $value = decoded.as_string();
 | 
				
			||||||
     };
 | 
					     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					identifier
 | 
				
			||||||
 | 
						returns[std::unique_ptr<Identifier> ast]:
 | 
				
			||||||
 | 
						IDENTIFIER {
 | 
				
			||||||
 | 
					          $ast = std::make_unique<Identifier>(getSourceRange($ctx), $ctx->IDENTIFIER()->getText());
 | 
				
			||||||
 | 
					     };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
STRING: '"' (ESC | ~["\\\r\n])* '"';
 | 
					STRING: '"' (ESC | ~["\\\r\n])* '"';
 | 
				
			||||||
fragment ESC: '\\' (["\\/bfnrt] | 'u' HEX HEX HEX HEX);
 | 
					fragment ESC: '\\' (["\\/bfnrt] | 'u' HEX HEX HEX HEX);
 | 
				
			||||||
fragment HEX: [0-9a-fA-F];
 | 
					fragment HEX: [0-9a-fA-F];
 | 
				
			||||||
 | 
				
			|||||||
@ -22,5 +22,11 @@ FloatValue *FloatValue::fromJson(boost::json::value json) {
 | 
				
			|||||||
  return new FloatValue(SourceRange::json(), json.as_double());
 | 
					  return new FloatValue(SourceRange::json(), json.as_double());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					boost::json::value StringValue::toJson() const { return boost::json::value_from(value); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					StringValue *StringValue::fromJson(boost::json::value json) {
 | 
				
			||||||
 | 
					  return new StringValue(SourceRange::json(), json.as_string().c_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ast
 | 
					} // namespace ast
 | 
				
			||||||
} // namespace plsm
 | 
					} // namespace plsm
 | 
				
			||||||
 | 
				
			|||||||
@ -8,37 +8,34 @@ boost::json::value InlineAsmConstraint::toJson() const {
 | 
				
			|||||||
  return {
 | 
					  return {
 | 
				
			||||||
      {"@type", "InlineAsmConstraint"},
 | 
					      {"@type", "InlineAsmConstraint"},
 | 
				
			||||||
      {"constraint", constraint},
 | 
					      {"constraint", constraint},
 | 
				
			||||||
      {"variable", variable},
 | 
					      {"value", value->toJson()},
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InlineAsmConstraint *InlineAsmConstraint::fromJson(boost::json::value json) {
 | 
					InlineAsmConstraint *InlineAsmConstraint::fromJson(boost::json::value json) {
 | 
				
			||||||
  auto constraint =
 | 
					  auto constraint = getJsonValue<InlineAsmConstraint, std::string>(json, "constraint");
 | 
				
			||||||
      getJsonValue<InlineAsmConstraint, std::string>(json, "constraint");
 | 
					  auto value = fromJsonProperty<InlineAsmConstraint, Expr>(json, "value");
 | 
				
			||||||
  auto variable =
 | 
					  return new InlineAsmConstraint(SourceRange::json(), constraint, std::move(value));
 | 
				
			||||||
      getJsonValue<InlineAsmConstraint, std::string>(json, "variable");
 | 
					 | 
				
			||||||
  return new InlineAsmConstraint(SourceRange::json(), constraint, variable);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
boost::json::value InlineAsm::toJson() const {
 | 
					boost::json::value InlineAsm::toJson() const {
 | 
				
			||||||
 | 
					  boost::json::array jsonClobbers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
      {"@type", "InlineAsm"},
 | 
					      {"@type", "InlineAsm"},
 | 
				
			||||||
      {"code", code},
 | 
					      {"code", code},
 | 
				
			||||||
      {"outputs", utils::mapToJson(outputs)},
 | 
					      {"outputs", utils::mapToJson(outputs)},
 | 
				
			||||||
      {"inputs", utils::mapToJson(inputs)},
 | 
					      {"inputs", utils::mapToJson(inputs)},
 | 
				
			||||||
      {"clobbers", clobbers},
 | 
					      {"clobbers", utils::mapToJson(clobbers, [](const std::string &clobber) { return clobber; })},
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
InlineAsm *InlineAsm::fromJson(boost::json::value json) {
 | 
					InlineAsm *InlineAsm::fromJson(boost::json::value json) {
 | 
				
			||||||
  auto name = getJsonValue<InlineAsm, std::string>(json, "name");
 | 
					  auto name = getJsonValue<InlineAsm, std::string>(json, "name");
 | 
				
			||||||
  auto outputs =
 | 
					  auto outputs = fromJsonVector<InlineAsm, InlineAsmConstraint>(json, "outputs");
 | 
				
			||||||
      fromJsonVector<InlineAsm, InlineAsmConstraint>(json, "outputs");
 | 
					 | 
				
			||||||
  auto inputs = fromJsonVector<InlineAsm, InlineAsmConstraint>(json, "inputs");
 | 
					  auto inputs = fromJsonVector<InlineAsm, InlineAsmConstraint>(json, "inputs");
 | 
				
			||||||
  auto clobbers =
 | 
					  auto clobbers = getJsonValue<InlineAsm, std::vector<std::string>>(json, "clobbers");
 | 
				
			||||||
      getJsonValue<InlineAsm, std::vector<std::string>>(json, "clobbers");
 | 
					  return new InlineAsm(SourceRange::json(), name, std::move(outputs), std::move(inputs), std::move(clobbers));
 | 
				
			||||||
  return new InlineAsm(SourceRange::json(), name, std::move(outputs),
 | 
					 | 
				
			||||||
                       std::move(inputs), clobbers);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace ast
 | 
					} // namespace ast
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										24
									
								
								compiler/src/AST/Type/PointerType.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								compiler/src/AST/Type/PointerType.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#include "AST/AST.h"
 | 
				
			||||||
 | 
					#include "AST/Base.h"
 | 
				
			||||||
 | 
					#include "AST/TypeName/NamedTypeName.h"
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace plsm {
 | 
				
			||||||
 | 
					namespace ast {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					boost::json::value PointerType::toJson() const {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					      {"@type", "PointerType"},
 | 
				
			||||||
 | 
					      {"baseType", baseType->toJson()},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PointerType *PointerType::fromJson(boost::json::value json) {
 | 
				
			||||||
 | 
					  auto baseType = fromJsonProperty<PointerType, Type>(json, "baseType");
 | 
				
			||||||
 | 
					  return new PointerType(std::shared_ptr<Type>(baseType.release()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TypeName *PointerType::toTypeName() { return nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ast
 | 
				
			||||||
 | 
					} // namespace plsm
 | 
				
			||||||
							
								
								
									
										19
									
								
								compiler/src/AST/TypeName/PointerTypeName.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								compiler/src/AST/TypeName/PointerTypeName.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#include "AST/AST.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace plsm {
 | 
				
			||||||
 | 
					namespace ast {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					boost::json::value PointerTypeName::toJson() const {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					      {"@type", "PointerTypeName"},
 | 
				
			||||||
 | 
					      {"baseTypeName", baseTypeName->toJson()},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PointerTypeName *PointerTypeName::fromJson(boost::json::value json) {
 | 
				
			||||||
 | 
					  auto baseTypeName = fromJsonProperty<PointerTypeName, TypeName>(json, "baseTypeName");
 | 
				
			||||||
 | 
					  return new PointerTypeName(SourceRange::json(), std::move(baseTypeName));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace ast
 | 
				
			||||||
 | 
					} // namespace plsm
 | 
				
			||||||
@ -10,6 +10,7 @@
 | 
				
			|||||||
#include <llvm/CodeGen/Passes.h>
 | 
					#include <llvm/CodeGen/Passes.h>
 | 
				
			||||||
#include <llvm/IR/Function.h>
 | 
					#include <llvm/IR/Function.h>
 | 
				
			||||||
#include <llvm/IR/IRBuilder.h>
 | 
					#include <llvm/IR/IRBuilder.h>
 | 
				
			||||||
 | 
					#include <llvm/IR/InlineAsm.h>
 | 
				
			||||||
#include <llvm/IR/LLVMContext.h>
 | 
					#include <llvm/IR/LLVMContext.h>
 | 
				
			||||||
#include <llvm/IR/LegacyPassManager.h>
 | 
					#include <llvm/IR/LegacyPassManager.h>
 | 
				
			||||||
#include <llvm/IR/Module.h>
 | 
					#include <llvm/IR/Module.h>
 | 
				
			||||||
@ -28,8 +29,7 @@ using namespace ast;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static llvm::Type *getLLVMType(llvm::LLVMContext &ctx,
 | 
					static llvm::Type *getLLVMType(llvm::LLVMContext &ctx, const std::shared_ptr<Type> &type) {
 | 
				
			||||||
                               const std::shared_ptr<Type> &type) {
 | 
					 | 
				
			||||||
  if (utils::is<PrimitiveType>(type.get())) {
 | 
					  if (utils::is<PrimitiveType>(type.get())) {
 | 
				
			||||||
    auto primitiveType = (PrimitiveType *)type.get();
 | 
					    auto primitiveType = (PrimitiveType *)type.get();
 | 
				
			||||||
    if (primitiveType->name == "i8" || primitiveType->name == "u8")
 | 
					    if (primitiveType->name == "i8" || primitiveType->name == "u8")
 | 
				
			||||||
@ -48,14 +48,20 @@ static llvm::Type *getLLVMType(llvm::LLVMContext &ctx,
 | 
				
			|||||||
      return llvm::Type::getDoubleTy(ctx);
 | 
					      return llvm::Type::getDoubleTy(ctx);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  else if (utils::is<PointerType>(type.get())) {
 | 
				
			||||||
 | 
					    auto pointerType = (PointerType *)type.get();
 | 
				
			||||||
 | 
					    auto baseType = getLLVMType(ctx, pointerType->baseType);
 | 
				
			||||||
 | 
					    return baseType->getPointerTo();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  else if (utils::is<FunctionType>(type.get())) {
 | 
					  else if (utils::is<FunctionType>(type.get())) {
 | 
				
			||||||
    auto functionType = (FunctionType *)type.get();
 | 
					    auto functionType = (FunctionType *)type.get();
 | 
				
			||||||
    auto returnType = getLLVMType(ctx, functionType->returnType);
 | 
					    auto returnType = getLLVMType(ctx, functionType->returnType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<llvm::Type *> llvmParams;
 | 
					    std::vector<llvm::Type *> llvmParams;
 | 
				
			||||||
    llvmParams.push_back(llvm::IntegerType::get(ctx, 8)->getPointerTo());
 | 
					 | 
				
			||||||
    for (auto ¶mType : functionType->paramTypes)
 | 
					    for (auto ¶mType : functionType->paramTypes)
 | 
				
			||||||
      llvmParams.push_back(getLLVMType(ctx, paramType));
 | 
					      llvmParams.push_back(getLLVMType(ctx, paramType));
 | 
				
			||||||
 | 
					    llvmParams.push_back(llvm::IntegerType::get(ctx, 8)->getPointerTo());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return llvm::FunctionType::get(returnType, llvmParams, false);
 | 
					    return llvm::FunctionType::get(returnType, llvmParams, false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -72,29 +78,20 @@ class IRGenerator1 : public BaseASTVisitor {
 | 
				
			|||||||
  std::set<llvm::Value *> &functions;
 | 
					  std::set<llvm::Value *> &functions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  IRGenerator1(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
					  IRGenerator1(llvm::LLVMContext &ctx, llvm::Module &mod, llvm::IRBuilder<> &builder,
 | 
				
			||||||
               llvm::IRBuilder<> &builder,
 | 
					               std::map<Symbol *, llvm::Value *> &symbolMap, std::set<llvm::Value *> &functions)
 | 
				
			||||||
               std::map<Symbol *, llvm::Value *> &symbolMap,
 | 
					      : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap), functions(functions) {}
 | 
				
			||||||
               std::set<llvm::Value *> &functions)
 | 
					 | 
				
			||||||
      : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap),
 | 
					 | 
				
			||||||
        functions(functions) {}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
					  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
				
			||||||
    auto llvmType = getLLVMType(ctx, varDecl.symbol->type);
 | 
					    auto llvmType = getLLVMType(ctx, varDecl.symbol->type);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // auto global = new llvm::GlobalVariable(mod, llvmType, false,
 | 
					 | 
				
			||||||
    //                                        llvm::GlobalValue::ExternalLinkage,
 | 
					 | 
				
			||||||
    //                                        nullptr, varDecl.name);
 | 
					 | 
				
			||||||
    auto global = mod.getOrInsertGlobal(varDecl.name, llvmType);
 | 
					    auto global = mod.getOrInsertGlobal(varDecl.name, llvmType);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    symbolMap[varDecl.symbol.get()] = global;
 | 
					    symbolMap[varDecl.symbol.get()] = global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
					  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
				
			||||||
    auto functionType =
 | 
					    auto functionType = (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type);
 | 
				
			||||||
        (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mod.getOrInsertFunction(fnDecl.name, functionType);
 | 
					    mod.getOrInsertFunction(fnDecl.name, functionType);
 | 
				
			||||||
    auto function = mod.getFunction(fnDecl.name);
 | 
					    auto function = mod.getFunction(fnDecl.name);
 | 
				
			||||||
@ -117,53 +114,51 @@ class IRGenerator2 : public BaseASTVisitor {
 | 
				
			|||||||
  llvm::Value *retStore = nullptr;
 | 
					  llvm::Value *retStore = nullptr;
 | 
				
			||||||
  llvm::BasicBlock *retBlock = nullptr;
 | 
					  llvm::BasicBlock *retBlock = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  llvm::Value *rvalueForLValue = nullptr;
 | 
					  bool requireLValue = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t labelCounter = 0;
 | 
					  llvm::StructType *closureType = nullptr;
 | 
				
			||||||
  std::string createLabel() { return "L" + std::to_string(labelCounter++); }
 | 
					  llvm::PointerType *pointerType = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  llvm::Value *wrapCallee(llvm::Value *callee) {
 | 
					  llvm::Value *wrapCallee(llvm::Value *callee) {
 | 
				
			||||||
    auto ptr = llvm::IntegerType::get(ctx, 8)->getPointerTo();
 | 
					    auto value = (llvm::Value *)llvm::UndefValue::get(closureType);
 | 
				
			||||||
    auto structType = llvm::StructType::get(ptr, callee->getType());
 | 
					    auto calleePointer = builder.CreatePointerCast(callee, pointerType);
 | 
				
			||||||
 | 
					    value = builder.CreateInsertValue(value, calleePointer, 0);
 | 
				
			||||||
 | 
					    auto nullContext = llvm::ConstantPointerNull::get(pointerType);
 | 
				
			||||||
 | 
					    value = builder.CreateInsertValue(value, nullContext, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto store = builder.CreateAlloca(structType);
 | 
					    return value;
 | 
				
			||||||
    auto ep = builder.CreateStructGEP(structType, store, 0);
 | 
					 | 
				
			||||||
    builder.CreateStore(llvm::ConstantPointerNull::get(ptr), ep);
 | 
					 | 
				
			||||||
    ep = builder.CreateStructGEP(structType, store, 1);
 | 
					 | 
				
			||||||
    builder.CreateStore(callee, ep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return store;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // (f() -> asdf) -> { context, f() -> asdf }
 | 
					    // (f() -> asdf) -> { context, f() -> asdf }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  IRGenerator2(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
					  IRGenerator2(llvm::LLVMContext &ctx, llvm::Module &mod, llvm::IRBuilder<> &builder,
 | 
				
			||||||
               llvm::IRBuilder<> &builder,
 | 
					               std::map<Symbol *, llvm::Value *> &symbolMap, std::set<llvm::Value *> &functions)
 | 
				
			||||||
               std::map<Symbol *, llvm::Value *> &symbolMap,
 | 
					      : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap), functions(functions) {
 | 
				
			||||||
               std::set<llvm::Value *> &functions)
 | 
					    this->pointerType = llvm::IntegerType::get(ctx, 8)->getPointerTo();
 | 
				
			||||||
      : ctx(ctx), mod(mod), builder(builder), symbolMap(symbolMap),
 | 
					    this->closureType = llvm::StructType::get(pointerType, pointerType);
 | 
				
			||||||
        functions(functions) {}
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
					  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
				
			||||||
    auto function = mod.getFunction(fnDecl.name);
 | 
					    auto function = mod.getFunction(fnDecl.name);
 | 
				
			||||||
    auto block = llvm::BasicBlock::Create(ctx, createLabel(), function);
 | 
					    auto block = llvm::BasicBlock::Create(ctx, "", function);
 | 
				
			||||||
    builder.SetInsertPoint(block);
 | 
					    builder.SetInsertPoint(block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t i = 0;
 | 
					    size_t i = 0;
 | 
				
			||||||
    for (auto &arg : function->args()) {
 | 
					    for (auto &arg : function->args()) {
 | 
				
			||||||
      if (i > 0) {
 | 
					      if (i == fnDecl.params.size())
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      auto store = builder.CreateAlloca(arg.getType(), nullptr);
 | 
					      auto store = builder.CreateAlloca(arg.getType(), nullptr);
 | 
				
			||||||
      builder.CreateStore(&arg, store);
 | 
					      builder.CreateStore(&arg, store);
 | 
				
			||||||
        symbolMap[fnDecl.params[i - 1]->symbol.get()] = store;
 | 
					      symbolMap[fnDecl.params[i]->symbol.get()] = store;
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      i += 1;
 | 
					      i += 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto fnType = (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type);
 | 
					    auto fnType = (llvm::FunctionType *)getLLVMType(ctx, fnDecl.symbol->type);
 | 
				
			||||||
    retStore = builder.CreateAlloca(fnType->getReturnType());
 | 
					    retStore = builder.CreateAlloca(fnType->getReturnType());
 | 
				
			||||||
    retBlock = llvm::BasicBlock::Create(ctx, createLabel(), function);
 | 
					    retBlock = llvm::BasicBlock::Create(ctx, "", function);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    BaseASTVisitor::visit(fnDecl, param);
 | 
					    BaseASTVisitor::visit(fnDecl, param);
 | 
				
			||||||
    if (!fnDecl.body->alywasReturns())
 | 
					    if (!fnDecl.body->alywasReturns())
 | 
				
			||||||
@ -268,8 +263,7 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(CastExpr &castExpr, std::any param) override {
 | 
					  virtual std::any visit(CastExpr &castExpr, std::any param) override {
 | 
				
			||||||
    auto value =
 | 
					    auto value = std::any_cast<llvm::Value *>(castExpr.value->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(castExpr.value->accept(this, param));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (utils::is<PrimitiveType>(castExpr.value->type.get()) &&
 | 
					    if (utils::is<PrimitiveType>(castExpr.value->type.get()) &&
 | 
				
			||||||
        utils::is<PrimitiveType>(castExpr.type.get())) {
 | 
					        utils::is<PrimitiveType>(castExpr.type.get())) {
 | 
				
			||||||
@ -278,11 +272,9 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      auto newType = getLLVMType(ctx, castExpr.type);
 | 
					      auto newType = getLLVMType(ctx, castExpr.type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      auto wasFloat =
 | 
					      auto wasFloat = primitiveType->name == "float" || primitiveType->name == "double";
 | 
				
			||||||
          primitiveType->name == "float" || primitiveType->name == "double";
 | 
					 | 
				
			||||||
      auto wasUnsigned = primitiveType->name[0] == 'u';
 | 
					      auto wasUnsigned = primitiveType->name[0] == 'u';
 | 
				
			||||||
      auto willFloat = newPrimitiveType->name == "float" ||
 | 
					      auto willFloat = newPrimitiveType->name == "float" || newPrimitiveType->name == "double";
 | 
				
			||||||
                       newPrimitiveType->name == "double";
 | 
					 | 
				
			||||||
      auto willUnsigned = newPrimitiveType->name[0] == 'u';
 | 
					      auto willUnsigned = newPrimitiveType->name[0] == 'u';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (wasFloat) {
 | 
					      if (wasFloat) {
 | 
				
			||||||
@ -320,63 +312,69 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(CallExpr &callExpr, std::any param) override {
 | 
					  virtual std::any visit(CallExpr &callExpr, std::any param) override {
 | 
				
			||||||
    auto callee =
 | 
					    auto callee = std::any_cast<llvm::Value *>(callExpr.callee->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(callExpr.callee->accept(this, param));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto ptrType = llvm::IntegerType::get(ctx, 8)->getPointerTo();
 | 
					    auto realCallee = builder.CreateExtractValue(callee, 0);
 | 
				
			||||||
    auto structType = llvm::StructType::get(ptrType, ptrType);
 | 
					    auto callCtx = builder.CreateExtractValue(callee, 1);
 | 
				
			||||||
    auto ep = builder.CreateStructGEP(structType, callee, 0);
 | 
					 | 
				
			||||||
    auto callCtx = builder.CreateLoad(ptrType, ep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ep = builder.CreateStructGEP(structType, callee, 1);
 | 
					 | 
				
			||||||
    auto realCallee = (llvm::Value *)builder.CreateLoad(ptrType, ep);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // realCallee = builder.CreatePointerCast(realCallee, calleeType);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<llvm::Value *> llvmArgs;
 | 
					    std::vector<llvm::Value *> llvmArgs;
 | 
				
			||||||
 | 
					    for (auto &arg : callExpr.args)
 | 
				
			||||||
 | 
					      llvmArgs.push_back(std::any_cast<llvm::Value *>(arg->accept(this, param)));
 | 
				
			||||||
    llvmArgs.push_back(callCtx);
 | 
					    llvmArgs.push_back(callCtx);
 | 
				
			||||||
    for (auto &arg : callExpr.args) {
 | 
					 | 
				
			||||||
      llvmArgs.push_back(
 | 
					 | 
				
			||||||
          std::any_cast<llvm::Value *>(arg->accept(this, param)));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto calleeType =
 | 
					    auto calleeType = (llvm::FunctionType *)getLLVMType(ctx, callExpr.callee->type);
 | 
				
			||||||
        (llvm::FunctionType *)getLLVMType(ctx, callExpr.callee->type);
 | 
					 | 
				
			||||||
    return (llvm::Value *)builder.CreateCall(calleeType, realCallee, llvmArgs);
 | 
					    return (llvm::Value *)builder.CreateCall(calleeType, realCallee, llvmArgs);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(Identifier &identifier, std::any param) override {
 | 
					  virtual std::any visit(Identifier &identifier, std::any param) override {
 | 
				
			||||||
    auto value = symbolMap[identifier.symbol.get()];
 | 
					    auto value = symbolMap[identifier.symbol.get()];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rvalueForLValue) {
 | 
					    if (requireLValue)
 | 
				
			||||||
      builder.CreateStore(rvalueForLValue, value);
 | 
					      return value;
 | 
				
			||||||
      return nullptr;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else {
 | 
					 | 
				
			||||||
    if (functions.count(value))
 | 
					    if (functions.count(value))
 | 
				
			||||||
      return wrapCallee(value);
 | 
					      return wrapCallee(value);
 | 
				
			||||||
    if (utils::is<FunctionType>(identifier.type.get()))
 | 
					    if (utils::is<FunctionType>(identifier.type.get()))
 | 
				
			||||||
        return value;
 | 
					      return (llvm::Value *)builder.CreateLoad(closureType, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto loadType = getLLVMType(ctx, identifier.type);
 | 
					    auto loadType = getLLVMType(ctx, identifier.type);
 | 
				
			||||||
    return (llvm::Value *)builder.CreateLoad(loadType, value);
 | 
					    return (llvm::Value *)builder.CreateLoad(loadType, value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(IntValue &intValue, std::any param) override {
 | 
					  virtual std::any visit(IntValue &intValue, std::any param) override {
 | 
				
			||||||
    return (llvm::Value *)llvm::ConstantInt::get(
 | 
					    return (llvm::Value *)llvm::ConstantInt::get(getLLVMType(ctx, intValue.type), intValue.value);
 | 
				
			||||||
        getLLVMType(ctx, intValue.type), intValue.value);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FloatValue &floatValue, std::any param) override {
 | 
					  virtual std::any visit(FloatValue &floatValue, std::any param) override {
 | 
				
			||||||
    return (llvm::Value *)llvm::ConstantFP::get(
 | 
					    return (llvm::Value *)llvm::ConstantFP::get(getLLVMType(ctx, floatValue.type), floatValue.value);
 | 
				
			||||||
        getLLVMType(ctx, floatValue.type), floatValue.value);
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(StringValue &stringValue, std::any param) override {
 | 
				
			||||||
 | 
					    return (llvm::Value *)builder.CreateGlobalStringPtr(stringValue.value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto valType = llvm::Type::getInt8Ty(ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto size = stringValue.value.size() + 1;
 | 
				
			||||||
 | 
					    auto store = builder.CreateAlloca(llvm::Type::getInt8Ty(ctx), size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t i = 0;
 | 
				
			||||||
 | 
					    for (auto &c : stringValue.value) {
 | 
				
			||||||
 | 
					      auto ep = builder.CreateConstGEP1_64(valType, store, i);
 | 
				
			||||||
 | 
					      builder.CreateStore(llvm::ConstantInt::get(valType, c), ep);
 | 
				
			||||||
 | 
					      i += 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // add null terminator
 | 
				
			||||||
 | 
					    auto ep = builder.CreateConstGEP1_64(valType, store, i);
 | 
				
			||||||
 | 
					    builder.CreateStore(llvm::ConstantInt::get(valType, 0), ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto ptr = builder.CreatePointerCast(store, pointerType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (llvm::Value *)ptr;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(RetStmt &retStmt, std::any param) override {
 | 
					  virtual std::any visit(RetStmt &retStmt, std::any param) override {
 | 
				
			||||||
    auto value =
 | 
					    auto value = std::any_cast<llvm::Value *>(retStmt.value->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(retStmt.value->accept(this, param));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    builder.CreateStore(value, retStore);
 | 
					    builder.CreateStore(value, retStore);
 | 
				
			||||||
    builder.CreateBr(retBlock);
 | 
					    builder.CreateBr(retBlock);
 | 
				
			||||||
@ -385,16 +383,15 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(IfStmt &ifStmt, std::any param) override {
 | 
					  virtual std::any visit(IfStmt &ifStmt, std::any param) override {
 | 
				
			||||||
    auto cond =
 | 
					    auto cond = std::any_cast<llvm::Value *>(ifStmt.condition->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(ifStmt.condition->accept(this, param));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto fn = builder.GetInsertBlock()->getParent();
 | 
					    auto fn = builder.GetInsertBlock()->getParent();
 | 
				
			||||||
    auto ifBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					    auto ifBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
    auto elseBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					    auto elseBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    llvm::BasicBlock *endBlock = nullptr;
 | 
					    llvm::BasicBlock *endBlock = nullptr;
 | 
				
			||||||
    if (!ifStmt.alywasReturns())
 | 
					    if (!ifStmt.alywasReturns())
 | 
				
			||||||
      endBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					      endBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    builder.CreateCondBr(cond, ifBlock, elseBlock);
 | 
					    builder.CreateCondBr(cond, ifBlock, elseBlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -416,15 +413,14 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(WhileStmt &whileStmt, std::any param) override {
 | 
					  virtual std::any visit(WhileStmt &whileStmt, std::any param) override {
 | 
				
			||||||
    auto fn = builder.GetInsertBlock()->getParent();
 | 
					    auto fn = builder.GetInsertBlock()->getParent();
 | 
				
			||||||
    auto condBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					    auto condBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
    auto whileBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					    auto whileBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
    auto endBlock = llvm::BasicBlock::Create(ctx, createLabel(), fn);
 | 
					    auto endBlock = llvm::BasicBlock::Create(ctx, "", fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    builder.CreateBr(condBlock);
 | 
					    builder.CreateBr(condBlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    builder.SetInsertPoint(condBlock);
 | 
					    builder.SetInsertPoint(condBlock);
 | 
				
			||||||
    auto cond =
 | 
					    auto cond = std::any_cast<llvm::Value *>(whileStmt.condition->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(whileStmt.condition->accept(this, param));
 | 
					 | 
				
			||||||
    builder.CreateCondBr(cond, whileBlock, endBlock);
 | 
					    builder.CreateCondBr(cond, whileBlock, endBlock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    builder.SetInsertPoint(whileBlock);
 | 
					    builder.SetInsertPoint(whileBlock);
 | 
				
			||||||
@ -438,12 +434,56 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(AssignStmt &assignStmt, std::any param) override {
 | 
					  virtual std::any visit(AssignStmt &assignStmt, std::any param) override {
 | 
				
			||||||
    auto rvalue =
 | 
					    auto rvalue = std::any_cast<llvm::Value *>(assignStmt.rval->accept(this, param));
 | 
				
			||||||
        std::any_cast<llvm::Value *>(assignStmt.rval->accept(this, param));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rvalueForLValue = rvalue;
 | 
					    requireLValue = true;
 | 
				
			||||||
    auto lvalue = assignStmt.lval->accept(this, param);
 | 
					    auto lvalue = std::any_cast<llvm::Value *>(assignStmt.lval->accept(this, param));
 | 
				
			||||||
    rvalueForLValue = nullptr;
 | 
					    requireLValue = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    builder.CreateStore(rvalue, lvalue);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(InlineAsm &inlineAsm, std::any param) override {
 | 
				
			||||||
 | 
					    // Handle the inline assembly code.
 | 
				
			||||||
 | 
					    auto codeValue = builder.CreateGlobalStringPtr(inlineAsm.code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Build constraints string for LLVM InlineAsm
 | 
				
			||||||
 | 
					    std::string asmConstraints;
 | 
				
			||||||
 | 
					    for (const auto &output : inlineAsm.outputs)
 | 
				
			||||||
 | 
					      asmConstraints += "=" + output->constraint + ",";
 | 
				
			||||||
 | 
					    for (const auto &input : inlineAsm.inputs)
 | 
				
			||||||
 | 
					      asmConstraints += input->constraint + ",";
 | 
				
			||||||
 | 
					    for (const auto &clobber : inlineAsm.clobbers)
 | 
				
			||||||
 | 
					      asmConstraints += "~{" + clobber + "}" + ",";
 | 
				
			||||||
 | 
					    if (!asmConstraints.empty())
 | 
				
			||||||
 | 
					      asmConstraints.pop_back(); // Remove trailing comma
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Process inputs and prepare arguments
 | 
				
			||||||
 | 
					    std::vector<llvm::Value *> llvmArgs;
 | 
				
			||||||
 | 
					    for (const auto &output : inlineAsm.outputs) {
 | 
				
			||||||
 | 
					      requireLValue = true;
 | 
				
			||||||
 | 
					      auto outputValue = std::any_cast<llvm::Value *>(output->value->accept(this, param));
 | 
				
			||||||
 | 
					      requireLValue = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      llvmArgs.push_back(outputValue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const auto &input : inlineAsm.inputs) {
 | 
				
			||||||
 | 
					      auto inputValue = std::any_cast<llvm::Value *>(input->value->accept(this, param));
 | 
				
			||||||
 | 
					      llvmArgs.push_back(inputValue);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<llvm::Type *> paramTypes;
 | 
				
			||||||
 | 
					    for (const auto &arg : llvmArgs)
 | 
				
			||||||
 | 
					      paramTypes.push_back(arg->getType());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto asmType = llvm::FunctionType::get(llvm::Type::getVoidTy(ctx), paramTypes, false);
 | 
				
			||||||
 | 
					    auto inlineAsmValue = llvm::InlineAsm::get(asmType, inlineAsm.code, asmConstraints,
 | 
				
			||||||
 | 
					                                               true /* hasSideEffects */, false /* isAlignStack */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    builder.CreateCall(inlineAsmValue, llvmArgs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -466,8 +506,8 @@ static void runMPM(llvm::Module &mod) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  passBuilder.crossRegisterProxies(lam, fam, gam, mam);
 | 
					  passBuilder.crossRegisterProxies(lam, fam, gam, mam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mpm = passBuilder.buildModuleOptimizationPipeline(
 | 
					  mpm = passBuilder.buildModuleOptimizationPipeline(llvm::OptimizationLevel::O3,
 | 
				
			||||||
      llvm::OptimizationLevel::O3, llvm::ThinOrFullLTOPhase::None);
 | 
					                                                    llvm::ThinOrFullLTOPhase::None);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mpm.run(mod, mam);
 | 
					  mpm.run(mod, mam);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -477,8 +517,7 @@ static void runMPM(llvm::Module &mod) {
 | 
				
			|||||||
  lam.clear();
 | 
					  lam.clear();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
					static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod, llvm::IRBuilder<> &builder,
 | 
				
			||||||
                        llvm::IRBuilder<> &builder,
 | 
					 | 
				
			||||||
                        const std::string &outfile) {
 | 
					                        const std::string &outfile) {
 | 
				
			||||||
  llvm::InitializeAllTargetInfos();
 | 
					  llvm::InitializeAllTargetInfos();
 | 
				
			||||||
  llvm::InitializeAllTargets();
 | 
					  llvm::InitializeAllTargets();
 | 
				
			||||||
@ -495,8 +534,7 @@ static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
				
			|||||||
  if (!t)
 | 
					  if (!t)
 | 
				
			||||||
    throw std::runtime_error(err);
 | 
					    throw std::runtime_error(err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  llvm::TargetMachine *targetMachine =
 | 
					  llvm::TargetMachine *targetMachine = t->createTargetMachine(target, "", "", llvm::TargetOptions(),
 | 
				
			||||||
      t->createTargetMachine(target, "", "", llvm::TargetOptions(),
 | 
					 | 
				
			||||||
                                                              // TODO: make configurable
 | 
					                                                              // TODO: make configurable
 | 
				
			||||||
                                                              llvm::Reloc::PIC_);
 | 
					                                                              llvm::Reloc::PIC_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -514,8 +552,7 @@ static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
				
			|||||||
  pm.add(new llvm::TargetLibraryInfoWrapperPass());
 | 
					  pm.add(new llvm::TargetLibraryInfoWrapperPass());
 | 
				
			||||||
  pm.add(new llvm::MachineModuleInfoWrapperPass(&tm));
 | 
					  pm.add(new llvm::MachineModuleInfoWrapperPass(&tm));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool objResult = targetMachine->addPassesToEmitFile(
 | 
					  bool objResult = targetMachine->addPassesToEmitFile(pm, dest, nullptr, llvm::CodeGenFileType::ObjectFile);
 | 
				
			||||||
      pm, dest, nullptr, llvm::CodeGenFileType::ObjectFile);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (objResult)
 | 
					  if (objResult)
 | 
				
			||||||
    throw std::runtime_error("failed to produce " + outfile);
 | 
					    throw std::runtime_error("failed to produce " + outfile);
 | 
				
			||||||
@ -526,8 +563,7 @@ static void writeToFile(llvm::LLVMContext &ctx, llvm::Module &mod,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void compileModule(std::unique_ptr<ast::Module> &module,
 | 
					void compileModule(std::unique_ptr<ast::Module> &module, const std::string &filename) {
 | 
				
			||||||
                   const std::string &filename) {
 | 
					 | 
				
			||||||
  auto moduleId = filename;
 | 
					  auto moduleId = filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  llvm::LLVMContext ctx;
 | 
					  llvm::LLVMContext ctx;
 | 
				
			||||||
@ -550,6 +586,9 @@ void compileModule(std::unique_ptr<ast::Module> &module,
 | 
				
			|||||||
    mod.print(llvm::outs(), nullptr);
 | 
					    mod.print(llvm::outs(), nullptr);
 | 
				
			||||||
    llvm::outs().flush();
 | 
					    llvm::outs().flush();
 | 
				
			||||||
    throw std::runtime_error("Module verification failed");
 | 
					    throw std::runtime_error("Module verification failed");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    mod.print(llvm::outs(), nullptr);
 | 
				
			||||||
 | 
					    llvm::outs().flush();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  runMPM(mod); // info: does not work, programs will malfunction
 | 
					  runMPM(mod); // info: does not work, programs will malfunction
 | 
				
			||||||
 | 
				
			|||||||
@ -13,8 +13,7 @@ class NameAnalysisVisitor1 : public ast::BaseASTVisitor {
 | 
				
			|||||||
  std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
 | 
					  std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  NameAnalysisVisitor1(
 | 
					  NameAnalysisVisitor1(std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
 | 
				
			||||||
      std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
 | 
					 | 
				
			||||||
      : scopes(scopes) {}
 | 
					      : scopes(scopes) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(ast::FnDecl &fnDecl, std::any param) override {
 | 
					  virtual std::any visit(ast::FnDecl &fnDecl, std::any param) override {
 | 
				
			||||||
@ -22,8 +21,7 @@ public:
 | 
				
			|||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (scopes->back().count(fnDecl.name)) {
 | 
					    if (scopes->back().count(fnDecl.name)) {
 | 
				
			||||||
      errors::put(
 | 
					      errors::put(fnDecl.error("redeclaration of global symbol '" + fnDecl.name + "'"));
 | 
				
			||||||
          fnDecl.error("redeclaration of global symbol '" + fnDecl.name + "'"));
 | 
					 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,8 +37,7 @@ public:
 | 
				
			|||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (scopes->back().count(varDecl.name)) {
 | 
					    if (scopes->back().count(varDecl.name)) {
 | 
				
			||||||
      errors::put(varDecl.error("redeclaration of global symbol '" +
 | 
					      errors::put(varDecl.error("redeclaration of global symbol '" + varDecl.name + "'"));
 | 
				
			||||||
                                varDecl.name + "'"));
 | 
					 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -55,9 +52,7 @@ public:
 | 
				
			|||||||
class NameAnalysisVisitor2 : public ast::BaseASTVisitor {
 | 
					class NameAnalysisVisitor2 : public ast::BaseASTVisitor {
 | 
				
			||||||
  std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
 | 
					  std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void push() {
 | 
					  void push() { scopes->push_back(std::map<std::string, std::shared_ptr<ast::Symbol>>()); }
 | 
				
			||||||
    scopes->push_back(std::map<std::string, std::shared_ptr<ast::Symbol>>());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void pop() { scopes->pop_back(); }
 | 
					  void pop() { scopes->pop_back(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -72,8 +67,7 @@ class NameAnalysisVisitor2 : public ast::BaseASTVisitor {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  NameAnalysisVisitor2(
 | 
					  NameAnalysisVisitor2(std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
 | 
				
			||||||
      std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
 | 
					 | 
				
			||||||
      : scopes(scopes) {}
 | 
					      : scopes(scopes) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(ast::FnParam &fnParam, std::any param) override {
 | 
					  virtual std::any visit(ast::FnParam &fnParam, std::any param) override {
 | 
				
			||||||
@ -118,8 +112,7 @@ public:
 | 
				
			|||||||
    auto symbol = findSymbol(identifier.name);
 | 
					    auto symbol = findSymbol(identifier.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!symbol.get()) {
 | 
					    if (!symbol.get()) {
 | 
				
			||||||
      errors::put(identifier.error("unable to resolve identifier '" +
 | 
					      errors::put(identifier.error("unable to resolve identifier '" + identifier.name + "'"));
 | 
				
			||||||
                                   identifier.name + "'"));
 | 
					 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -32,29 +32,36 @@ static std::map<std::string, std::shared_ptr<PrimitiveType>> primitiveTypes = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static std::shared_ptr<Type> resolveTypeName(const TypeName *typeName) {
 | 
					static std::shared_ptr<Type> resolveTypeName(const TypeName *typeName) {
 | 
				
			||||||
 | 
					  if (!typeName)
 | 
				
			||||||
 | 
					    return std::shared_ptr<Type>(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (utils::is<NamedTypeName>(typeName)) {
 | 
					  if (utils::is<NamedTypeName>(typeName)) {
 | 
				
			||||||
    auto named = (NamedTypeName *)typeName;
 | 
					    auto named = (NamedTypeName *)typeName;
 | 
				
			||||||
    if (primitiveTypes.count(named->name))
 | 
					    if (primitiveTypes.count(named->name))
 | 
				
			||||||
      return primitiveTypes[named->name];
 | 
					      return primitiveTypes[named->name];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    errors::put(
 | 
					    errors::put(typeName->error("unable to resolve named type '" + named->name + "'"));
 | 
				
			||||||
        typeName->error("unable to resolve named type '" + named->name + "'"));
 | 
					 | 
				
			||||||
    return std::shared_ptr<Type>(nullptr);
 | 
					    return std::shared_ptr<Type>(nullptr);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (utils::is<PointerTypeName>(typeName)) {
 | 
				
			||||||
 | 
					    auto ptr = (PointerTypeName *)typeName;
 | 
				
			||||||
 | 
					    auto baseType = resolveTypeName(ptr->baseTypeName.get());
 | 
				
			||||||
 | 
					    if (baseType.get())
 | 
				
			||||||
 | 
					      return std::make_shared<PointerType>(baseType);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO: function type
 | 
					  // TODO: function type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  errors::put(typeName->error("unable to resolve type"));
 | 
					  errors::put(typeName->error("unable to resolve type"));
 | 
				
			||||||
  return std::shared_ptr<Type>(nullptr);
 | 
					  return std::shared_ptr<Type>(nullptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void castTo(std::unique_ptr<Expr> &expr,
 | 
					static void castTo(std::unique_ptr<Expr> &expr, const std::shared_ptr<Type> &type) {
 | 
				
			||||||
                   const std::shared_ptr<Type> &type) {
 | 
					 | 
				
			||||||
  if (*expr->type == *type)
 | 
					  if (*expr->type == *type)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto cast = new CastExpr(expr->sourceRange, std::move(expr),
 | 
					  auto cast = new CastExpr(expr->sourceRange, std::move(expr), std::unique_ptr<TypeName>(type->toTypeName()));
 | 
				
			||||||
                           std::unique_ptr<TypeName>(type->toTypeName()));
 | 
					 | 
				
			||||||
  cast->type = type;
 | 
					  cast->type = type;
 | 
				
			||||||
  cast->typeName->type = type;
 | 
					  cast->typeName->type = type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -62,19 +69,16 @@ static void castTo(std::unique_ptr<Expr> &expr,
 | 
				
			|||||||
  expr.swap(newExpr);
 | 
					  expr.swap(newExpr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool tryAssignTo(std::unique_ptr<Expr> &from,
 | 
					static bool tryAssignTo(std::unique_ptr<Expr> &from, const std::shared_ptr<Type> &toType) {
 | 
				
			||||||
                        const std::shared_ptr<Type> &toType) {
 | 
					  if ((*from->type) == *toType)
 | 
				
			||||||
  if (*from->type == *toType)
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (utils::is<PrimitiveType>(from->type.get()) &&
 | 
					  if (utils::is<PrimitiveType>(from->type.get()) && utils::is<PrimitiveType>(toType.get())) {
 | 
				
			||||||
      utils::is<PrimitiveType>(toType.get())) {
 | 
					 | 
				
			||||||
    PrimitiveType *fromT = (PrimitiveType *)from->type.get();
 | 
					    PrimitiveType *fromT = (PrimitiveType *)from->type.get();
 | 
				
			||||||
    const PrimitiveType *toT = (PrimitiveType *)toType.get();
 | 
					    const PrimitiveType *toT = (PrimitiveType *)toType.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::map<std::string, std::vector<std::string>> castMatrix = {
 | 
					    std::map<std::string, std::vector<std::string>> castMatrix = {
 | 
				
			||||||
        {"i8",
 | 
					        {"i8", {"i16", "i32", "i64", "u8", "u16", "u32", "u64", "i128", "u128"}},
 | 
				
			||||||
         {"i16", "i32", "i64", "u8", "u16", "u32", "u64", "i128", "u128"}},
 | 
					 | 
				
			||||||
        {"i16", {"i32", "i64", "u16", "u32", "u64", "i128", "u128"}},
 | 
					        {"i16", {"i32", "i64", "u16", "u32", "u64", "i128", "u128"}},
 | 
				
			||||||
        {"i32", {"i64", "u32", "u64", "i128", "u128"}},
 | 
					        {"i32", {"i64", "u32", "u64", "i128", "u128"}},
 | 
				
			||||||
        {"i64", {"u64", "i128", "u128"}},
 | 
					        {"i64", {"u64", "i128", "u128"}},
 | 
				
			||||||
@ -103,29 +107,39 @@ static bool tryAssignTo(std::unique_ptr<Expr> &from,
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  else if (utils::is<PrimitiveType>(from->type.get()) && utils::is<PointerType>(toType.get())) {
 | 
				
			||||||
 | 
					    castTo(from, toType);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  else if (utils::is<PointerType>(from->type.get()) && utils::is<PointerType>(toType.get())) {
 | 
				
			||||||
 | 
					    castTo(from, toType);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  else if (utils::is<PointerType>(from->type.get()) && utils::is<PrimitiveType>(toType.get())) {
 | 
				
			||||||
 | 
					    castTo(from, toType);
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool canBeCastedTo(std::unique_ptr<Expr> &from,
 | 
					static bool canBeCastedTo(std::unique_ptr<Expr> &from, const std::shared_ptr<Type> &toType) {
 | 
				
			||||||
                          const std::shared_ptr<Type> &toType) {
 | 
					 | 
				
			||||||
  if (*from->type == *toType)
 | 
					  if (*from->type == *toType)
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (utils::is<PrimitiveType>(from->type.get()) &&
 | 
					  if (utils::is<PrimitiveType>(from->type.get()) && utils::is<PrimitiveType>(toType.get())) {
 | 
				
			||||||
      utils::is<PrimitiveType>(toType.get())) {
 | 
					 | 
				
			||||||
    PrimitiveType *fromT = (PrimitiveType *)from->type.get();
 | 
					    PrimitiveType *fromT = (PrimitiveType *)from->type.get();
 | 
				
			||||||
    const PrimitiveType *toT = (PrimitiveType *)toType.get();
 | 
					    const PrimitiveType *toT = (PrimitiveType *)toType.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::vector<std::string> allNumberTypes = {
 | 
					    std::vector<std::string> allNumberTypes = {"i8",  "i16", "i32", "i64",  "i128",  "u8",
 | 
				
			||||||
        "i8",  "i16", "i32", "i64",  "i128",  "u8",
 | 
					 | 
				
			||||||
                                               "u16", "u32", "u64", "u128", "float", "double"};
 | 
					                                               "u16", "u32", "u64", "u128", "float", "double"};
 | 
				
			||||||
    std::map<std::string, std::vector<std::string>> castMatrix = {
 | 
					    std::map<std::string, std::vector<std::string>> castMatrix = {
 | 
				
			||||||
        {"i8", allNumberTypes},    {"i16", allNumberTypes},
 | 
					        {"i8", allNumberTypes},   {"i16", allNumberTypes},   {"i32", allNumberTypes},
 | 
				
			||||||
        {"i32", allNumberTypes},   {"i64", allNumberTypes},
 | 
					        {"i64", allNumberTypes},  {"i128", allNumberTypes},  {"u8", allNumberTypes},
 | 
				
			||||||
        {"i128", allNumberTypes},  {"u8", allNumberTypes},
 | 
					        {"u16", allNumberTypes},  {"u32", allNumberTypes},   {"u64", allNumberTypes},
 | 
				
			||||||
        {"u16", allNumberTypes},   {"u32", allNumberTypes},
 | 
					        {"u128", allNumberTypes}, {"float", allNumberTypes}, {"double", allNumberTypes},
 | 
				
			||||||
        {"u64", allNumberTypes},   {"u128", allNumberTypes},
 | 
					 | 
				
			||||||
        {"float", allNumberTypes}, {"double", allNumberTypes},
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!castMatrix.count(fromT->name))
 | 
					    if (!castMatrix.count(fromT->name))
 | 
				
			||||||
@ -148,12 +162,16 @@ static bool canBeCastedTo(std::unique_ptr<Expr> &from,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class TypeAnalysisVisitor1 : public BaseASTVisitor {
 | 
					class TypeAnalysisVisitor1 : public BaseASTVisitor {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  virtual std::any visit(NamedTypeName &namedTypeName,
 | 
					  virtual std::any visit(NamedTypeName &namedTypeName, std::any param) override {
 | 
				
			||||||
                         std::any param) override {
 | 
					 | 
				
			||||||
    namedTypeName.type = resolveTypeName(&namedTypeName);
 | 
					    namedTypeName.type = resolveTypeName(&namedTypeName);
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(PointerTypeName &pointerTypeName, std::any param) override {
 | 
				
			||||||
 | 
					    pointerTypeName.type = resolveTypeName(&pointerTypeName);
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
					  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
				
			||||||
    if (!varDecl.typeName.get() || !varDecl.symbol.get())
 | 
					    if (!varDecl.typeName.get() || !varDecl.symbol.get())
 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
@ -178,8 +196,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
					  virtual std::any visit(FnDecl &fnDecl, std::any param) override {
 | 
				
			||||||
    if (!(fnDecl.body.get() && fnDecl.body->alywasReturns())) {
 | 
					    if (!(fnDecl.body.get() && fnDecl.body->alywasReturns())) {
 | 
				
			||||||
      errors::put(fnDecl.error("function '" + fnDecl.name +
 | 
					      errors::put(fnDecl.error("function '" + fnDecl.name + "' does not always return a value"));
 | 
				
			||||||
                               "' does not always return a value"));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!fnDecl.symbol.get())
 | 
					    if (!fnDecl.symbol.get())
 | 
				
			||||||
@ -203,8 +220,7 @@ public:
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fnDecl.symbol->type =
 | 
					    fnDecl.symbol->type = std::make_shared<FunctionType>(paramTypes, returnType);
 | 
				
			||||||
        std::make_shared<FunctionType>(paramTypes, returnType);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -214,12 +230,16 @@ class TypeAnalysisVisitor2 : public BaseASTVisitor {
 | 
				
			|||||||
  std::shared_ptr<Type> currentReturnType = nullptr;
 | 
					  std::shared_ptr<Type> currentReturnType = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  virtual std::any visit(NamedTypeName &namedTypeName,
 | 
					  virtual std::any visit(NamedTypeName &namedTypeName, std::any param) override {
 | 
				
			||||||
                         std::any param) override {
 | 
					 | 
				
			||||||
    namedTypeName.type = resolveTypeName(&namedTypeName);
 | 
					    namedTypeName.type = resolveTypeName(&namedTypeName);
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(PointerTypeName &pointerTypeName, std::any param) override {
 | 
				
			||||||
 | 
					    pointerTypeName.type = resolveTypeName(&pointerTypeName);
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
					  virtual std::any visit(VarDecl &varDecl, std::any param) override {
 | 
				
			||||||
    if (!varDecl.typeName.get() || !varDecl.symbol.get())
 | 
					    if (!varDecl.typeName.get() || !varDecl.symbol.get())
 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
@ -315,6 +335,12 @@ public:
 | 
				
			|||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(StringValue &stringValue, std::any param) override {
 | 
				
			||||||
 | 
					    stringValue.type = std::make_shared<PointerType>(std::make_shared<PrimitiveType>("u8"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  virtual std::any visit(FloatValue &floatValue, std::any param) override {
 | 
					  virtual std::any visit(FloatValue &floatValue, std::any param) override {
 | 
				
			||||||
    if ((float_t)floatValue.value == floatValue.value) {
 | 
					    if ((float_t)floatValue.value == floatValue.value) {
 | 
				
			||||||
      floatValue.type = std::make_shared<PrimitiveType>("float");
 | 
					      floatValue.type = std::make_shared<PrimitiveType>("float");
 | 
				
			||||||
@ -353,11 +379,6 @@ public:
 | 
				
			|||||||
    if (!assignStmt.lval.get() || !assignStmt.rval->type.get())
 | 
					    if (!assignStmt.lval.get() || !assignStmt.rval->type.get())
 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!utils::is<Identifier>(assignStmt.lval.get())) {
 | 
					 | 
				
			||||||
      errors::put(assignStmt.error("invalid lvalue"));
 | 
					 | 
				
			||||||
      return std::any();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!tryAssignTo(assignStmt.rval, assignStmt.lval->type)) {
 | 
					    if (!tryAssignTo(assignStmt.rval, assignStmt.lval->type)) {
 | 
				
			||||||
      errors::put(assignStmt.error("assignment type mismatch"));
 | 
					      errors::put(assignStmt.error("assignment type mismatch"));
 | 
				
			||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
@ -387,14 +408,16 @@ public:
 | 
				
			|||||||
    BaseASTVisitor::visit(ifStmt, param);
 | 
					    BaseASTVisitor::visit(ifStmt, param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // do not multiplicate errors
 | 
					    // do not multiplicate errors
 | 
				
			||||||
    if (ifStmt.condition.get() && ifStmt.condition->type.get()) {
 | 
					    if (!ifStmt.condition.get() || !ifStmt.condition->type.get())
 | 
				
			||||||
      if (!utils::is<PrimitiveType>(ifStmt.condition->type.get())) {
 | 
					      return std::any();
 | 
				
			||||||
        errors::put(ifStmt.error("condition must be of primitive type"));
 | 
					
 | 
				
			||||||
 | 
					    if (!utils::is<PrimitiveType>(ifStmt.condition->type.get()) &&
 | 
				
			||||||
 | 
					        !utils::is<PointerType>(ifStmt.condition->type.get())) {
 | 
				
			||||||
 | 
					      errors::put(ifStmt.error("condition must be of primitive or pointer type"));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // cast condition to int (to make sure jnz succeeds)
 | 
					      // cast condition to int (to make sure jnz succeeds)
 | 
				
			||||||
      castTo(ifStmt.condition, std::make_shared<PrimitiveType>("i32"));
 | 
					      castTo(ifStmt.condition, std::make_shared<PrimitiveType>("i32"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -409,7 +432,7 @@ public:
 | 
				
			|||||||
        return std::any();
 | 
					        return std::any();
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        // cast condition to int (to make sure jnz succeeds)
 | 
					        // cast condition to int (to make sure jnz succeeds)
 | 
				
			||||||
        castTo(whileStmt.condition, std::make_shared<PrimitiveType>("i32"));
 | 
					        castTo(whileStmt.condition, std::make_shared<PrimitiveType>("i64"));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -437,8 +460,7 @@ public:
 | 
				
			|||||||
      return std::any();
 | 
					      return std::any();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    size_t smallerArgCount =
 | 
					    size_t smallerArgCount = std::min(functionType->paramTypes.size(), callExpr.args.size());
 | 
				
			||||||
        std::min(functionType->paramTypes.size(), callExpr.args.size());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t i = 0; i < smallerArgCount; i++) {
 | 
					    for (size_t i = 0; i < smallerArgCount; i++) {
 | 
				
			||||||
      if (!callExpr.args[i].get() || !functionType->paramTypes[i].get())
 | 
					      if (!callExpr.args[i].get() || !functionType->paramTypes[i].get())
 | 
				
			||||||
@ -495,8 +517,7 @@ public:
 | 
				
			|||||||
    case BinOp::DIV: {
 | 
					    case BinOp::DIV: {
 | 
				
			||||||
      if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) {
 | 
					      if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) {
 | 
				
			||||||
        if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) {
 | 
					        if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) {
 | 
				
			||||||
          errors::put(
 | 
					          errors::put(binExpr.error("operands incompatible, explicit cast required"));
 | 
				
			||||||
              binExpr.error("operands incompatible, explicit cast required"));
 | 
					 | 
				
			||||||
          return std::any();
 | 
					          return std::any();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -506,10 +527,8 @@ public:
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case BinOp::MOD: {
 | 
					    case BinOp::MOD: {
 | 
				
			||||||
      auto lhsSuccess =
 | 
					      auto lhsSuccess = tryAssignTo(binExpr.lhs, std::make_shared<PrimitiveType>("i64"));
 | 
				
			||||||
          tryAssignTo(binExpr.lhs, std::make_shared<PrimitiveType>("i64"));
 | 
					      auto rhsSuccess = tryAssignTo(binExpr.rhs, std::make_shared<PrimitiveType>("i64"));
 | 
				
			||||||
      auto rhsSuccess =
 | 
					 | 
				
			||||||
          tryAssignTo(binExpr.rhs, std::make_shared<PrimitiveType>("i64"));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (!lhsSuccess || !rhsSuccess) {
 | 
					      if (!lhsSuccess || !rhsSuccess) {
 | 
				
			||||||
        errors::put(binExpr.error("operands must be of integer type"));
 | 
					        errors::put(binExpr.error("operands must be of integer type"));
 | 
				
			||||||
@ -526,8 +545,7 @@ public:
 | 
				
			|||||||
    case BinOp::GE: {
 | 
					    case BinOp::GE: {
 | 
				
			||||||
      if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) {
 | 
					      if (!tryAssignTo(binExpr.rhs, binExpr.lhs->type)) {
 | 
				
			||||||
        if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) {
 | 
					        if (!tryAssignTo(binExpr.lhs, binExpr.rhs->type)) {
 | 
				
			||||||
          errors::put(
 | 
					          errors::put(binExpr.error("operands incompatible, explicit cast required"));
 | 
				
			||||||
              binExpr.error("operands incompatible, explicit cast required"));
 | 
					 | 
				
			||||||
          return std::any();
 | 
					          return std::any();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -549,6 +567,38 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return std::any();
 | 
					    return std::any();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(InlineAsmConstraint &constraint, std::any param) override {
 | 
				
			||||||
 | 
					    if (constraint.constraint.empty()) {
 | 
				
			||||||
 | 
					      errors::put(constraint.error("inline assembly constraint cannot be empty"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // For simplicity, assume constraints are string-based and should match
 | 
				
			||||||
 | 
					    // certain patterns. You can add regex-based validation if needed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BaseASTVisitor::visit(constraint, param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual std::any visit(InlineAsm &inlineAsm, std::any param) override {
 | 
				
			||||||
 | 
					    if (inlineAsm.code.empty()) {
 | 
				
			||||||
 | 
					      errors::put(inlineAsm.error("inline assembly code cannot be empty"));
 | 
				
			||||||
 | 
					      return std::any();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BaseASTVisitor::visit(inlineAsm, param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (const auto &clobber : inlineAsm.clobbers) {
 | 
				
			||||||
 | 
					      if (clobber.empty()) {
 | 
				
			||||||
 | 
					        errors::put(inlineAsm.error("clobber cannot be empty"));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // Optionally, check if clobber registers are valid (e.g., using a
 | 
				
			||||||
 | 
					      // whitelist of registers).
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return std::any();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								examples/new
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/new
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,22 +1,35 @@
 | 
				
			|||||||
fun addFirst(n : i32) i32 {
 | 
					fun write(fd : i64, msg : &u8, len : u64) i64 {
 | 
				
			||||||
  var result : i32;
 | 
					  inline asm (
 | 
				
			||||||
  result = 0;
 | 
					    "mov $0, %rax"         // syscall: write
 | 
				
			||||||
 | 
					    "mov $1, %rdi"         // file descriptor: stdout
 | 
				
			||||||
 | 
					    "mov $2, %rsi"         // message to write
 | 
				
			||||||
 | 
					    "mov $3, %rdx"         // length of message
 | 
				
			||||||
 | 
					    "syscall"              // make the syscall
 | 
				
			||||||
 | 
					    :
 | 
				
			||||||
 | 
					    : "r"(1 as i64), "r"(1 as i64), "r"(msg), "r"(len)  // input: different params
 | 
				
			||||||
 | 
					    : "rax", "rdi", "rsi", "rdx"                        // clobbered registers
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var i : i32;
 | 
					  ret 0;
 | 
				
			||||||
  i = 0;
 | 
					 | 
				
			||||||
  while (i < n) {
 | 
					 | 
				
			||||||
    result = result + i;
 | 
					 | 
				
			||||||
    i = i + 1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ret result;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// fun f(n : i32) i32 {
 | 
					fun exit(code : u8) i64 {
 | 
				
			||||||
//   if (n < 2) ret n;
 | 
					  inline asm (
 | 
				
			||||||
//   ret f(n - 1);
 | 
					    "mov $0, %rax"
 | 
				
			||||||
// }
 | 
					    "mov $1, %rdi"
 | 
				
			||||||
 | 
					    "syscall"
 | 
				
			||||||
 | 
					    :
 | 
				
			||||||
 | 
					    : "r"(60 as i64), "r"(code as i64)
 | 
				
			||||||
 | 
					    : "rax", "rdi"
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun main(argc : i32) u8 {
 | 
					fun main(argc : i32) u8 {
 | 
				
			||||||
  ret addFirst(argc) as u8;
 | 
					  write(1, "Hello World!\n", 14);
 | 
				
			||||||
 | 
					  write(1, "Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ Ơ ơ Ƣ ƣ Ƥ ƥ\n", 69);
 | 
				
			||||||
 | 
					  exit(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ret 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user