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,42 +103,57 @@ 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) {
|
||||||
outputs.push_back(std::move(output->ast));
|
outputs.push_back(std::move(output->ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<InlineAsmConstraint>> inputs;
|
std::vector<std::unique_ptr<InlineAsmConstraint>> inputs;
|
||||||
for (auto &input : $ctx->inputs) {
|
for (auto &input : $ctx->inputs) {
|
||||||
inputs.push_back(std::move(input->ast));
|
inputs.push_back(std::move(input->ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> clobbers;
|
std::vector<std::string> clobbers;
|
||||||
for (auto &clobber : $ctx->clobbers) {
|
for (auto &clobber : $ctx->clobbers) {
|
||||||
clobbers.push_back(clobber->value);
|
clobbers.push_back(clobber->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
$ast = std::make_unique<InlineAsm>(
|
$ast = std::make_unique<InlineAsm>(
|
||||||
getSourceRange($ctx), code, std::move(outputs), std::move(inputs), clobbers);
|
getSourceRange($ctx), code, std::move(outputs), std::move(inputs), clobbers);
|
||||||
};
|
};
|
||||||
|
|
||||||
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())
|
||||||
auto store = builder.CreateAlloca(arg.getType(), nullptr);
|
break;
|
||||||
builder.CreateStore(&arg, store);
|
|
||||||
symbolMap[fnDecl.params[i - 1]->symbol.get()] = store;
|
auto store = builder.CreateAlloca(arg.getType(), nullptr);
|
||||||
}
|
builder.CreateStore(&arg, 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 (llvm::Value *)builder.CreateLoad(closureType, value);
|
||||||
return 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,10 +534,9 @@ 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_);
|
|
||||||
|
|
||||||
mod.setDataLayout(targetMachine->createDataLayout());
|
mod.setDataLayout(targetMachine->createDataLayout());
|
||||||
|
|
||||||
@ -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,13 +408,15 @@ 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"));
|
|
||||||
} else {
|
if (!utils::is<PrimitiveType>(ifStmt.condition->type.get()) &&
|
||||||
// cast condition to int (to make sure jnz succeeds)
|
!utils::is<PointerType>(ifStmt.condition->type.get())) {
|
||||||
castTo(ifStmt.condition, std::make_shared<PrimitiveType>("i32"));
|
errors::put(ifStmt.error("condition must be of primitive or pointer type"));
|
||||||
}
|
} else {
|
||||||
|
// cast condition to int (to make sure jnz succeeds)
|
||||||
|
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