updated antlr4 version, further progress (TypeAnalysis)

This commit is contained in:
Ludwig Lehnert 2024-12-23 14:04:23 +01:00
parent e35ceeacf9
commit c23fc2ee86
63 changed files with 1131 additions and 565 deletions

View File

@ -30,7 +30,7 @@ add_custom_command(PRE_BUILD
OUTPUT ${ANTLR_INC}
COMMENT "Generating plsm_parser"
COMMAND java -jar
${CMAKE_SOURCE_DIR}/thirdparty/antlr-4.13.1-complete.jar
${CMAKE_SOURCE_DIR}/thirdparty/antlr4-4.13.2-complete.jar
${CMAKE_SOURCE_DIR}/plsm.g4
-o ${GEN_DIR} -Dlanguage=Cpp -no-listener -visitor
COMMAND ${CMAKE_COMMAND} -E copy ${GEN_DIR}/*.h ${INC_DIR}

View File

@ -9,7 +9,7 @@ include(ExternalProject)
set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime)
set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src)
# set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git)
set(ANTLR4_ZIP_REPOSITORY ${PROJECT_SOURCE_DIR}/thirdparty/antlr-4.13.1.zip)
set(ANTLR4_ZIP_REPOSITORY ${PROJECT_SOURCE_DIR}/thirdparty/antlr4-4.13.2.zip)
if(NOT DEFINED ANTLR4_TAG)
# Set to branch name to keep library updated at the cost of needing to rebuild after 'clean'
# Set to commit hash to keep the build stable and does not need to rebuild after 'clean'
@ -47,7 +47,7 @@ else()
set(ANTLR4_SHARED_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.13.1.dll)
${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.13.2.dll)
elseif(APPLE)
set(ANTLR4_RUNTIME_LIBRARIES
${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dylib)

View File

@ -14,6 +14,7 @@
#include "Module/Module.h"
#include "Stmt/AssignStmt.h"
#include "Stmt/Block.h"
#include "Stmt/ExprStmt.h"
#include "Stmt/FnDecl.h"
#include "Stmt/IfStmt.h"
@ -24,4 +25,4 @@
#include "Type/FunctionType.h"
#include "Type/PrimitiveType.h"
#include "TypeName/PrimitiveTypeName.h"
#include "TypeName/NamedTypeName.h"

View File

@ -3,15 +3,17 @@
#include <any>
#include <boost/json/serialize.hpp>
#include <exception>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
#include <utility>
#include <boost/json.hpp>
#include "Terminal.h"
#define LOC_ARG const SourceRange &sourceRange
namespace plsm {
@ -30,6 +32,7 @@ class Import;
class Module;
class AssignStmt;
class Block;
class ExprStmt;
class FnParam;
class FnDecl;
@ -38,7 +41,7 @@ class RetStmt;
class VarDecl;
class WhileStmt;
class PrimitiveTypeName;
class NamedTypeName;
class ASTVisitor {
public:
@ -57,6 +60,7 @@ public:
virtual std::any visit(Module &module, std::any param) = 0;
virtual std::any visit(AssignStmt &assignStmt, std::any param) = 0;
virtual std::any visit(Block &block, std::any param) = 0;
virtual std::any visit(ExprStmt &exprStmt, std::any param) = 0;
virtual std::any visit(FnParam &fnParam, std::any param) = 0;
virtual std::any visit(FnDecl &fnDecl, std::any param) = 0;
@ -65,8 +69,7 @@ public:
virtual std::any visit(VarDecl &varDecl, std::any param) = 0;
virtual std::any visit(WhileStmt &whileStmt, std::any param) = 0;
virtual std::any visit(PrimitiveTypeName &primitiveTypeName,
std::any param) = 0;
virtual std::any visit(NamedTypeName &namedTypeName, std::any param) = 0;
};
} // namespace ast
@ -79,7 +82,7 @@ class Jsonable {
public:
virtual ~Jsonable() = default;
virtual boost::json::value toJson() = 0;
virtual boost::json::value toJson() const = 0;
protected:
template <class CurrNode>
@ -114,7 +117,8 @@ protected:
template <class CurrNode, class SubNode>
static inline auto fromJsonProperty(boost::json::value json,
std::string property) {
return SubNode::fromJson(getJsonProperty<CurrNode>(json, property));
return std::unique_ptr<SubNode>(
SubNode::fromJson(getJsonProperty<CurrNode>(json, property)));
}
template <class CurrNode, class SubNode>
@ -122,9 +126,9 @@ protected:
std::string property) {
auto arr = getJsonProperty<CurrNode>(json, property).as_array();
std::vector<SubNode *> result;
std::vector<std::unique_ptr<SubNode>> result;
for (auto &el : arr) {
result.push_back(SubNode::fromJson(el));
result.push_back(std::unique_ptr<SubNode>(SubNode::fromJson(el)));
}
return result;
@ -133,7 +137,7 @@ protected:
class SourceRange {
public:
SourceRange(const std::string &file, const std::string &text,
SourceRange(const std::string &file, std::string text,
std::pair<size_t, size_t> start, std::pair<size_t, size_t> end)
: file(file), text(text), start(start), end(end) {}
@ -141,27 +145,34 @@ public:
const std::pair<size_t, size_t> start, end;
static SourceRange unknown() {
return SourceRange("<?>", "<?>", {-1, -1}, {-1, -1});
return SourceRange("<?>", "<?>", {0, 0}, {0, 0});
};
static SourceRange json() {
return SourceRange("<json>", "<?>", {-1, -1}, {-1, -1});
return SourceRange("<json>", "<json>", {0, 0}, {0, 0});
};
};
class TypeName;
class Type : public Jsonable {
public:
Type() : Jsonable() {}
virtual ~Type() = default;
virtual TypeName *toTypeName() = 0;
virtual bool operator==(const Type &other) = 0;
virtual bool operator!=(const Type &other) { return !(*this == other); }
static Type *fromJson(boost::json::value json);
};
class Symbol {
public:
const std::string name;
std::shared_ptr<Type> type;
public:
Symbol(const std::string &name) : name(name) {}
Symbol(const std::string &name, Type *type) : name(name), type(type) {}
};
@ -173,29 +184,40 @@ public:
const SourceRange sourceRange;
virtual std::string toJsonString() {
virtual std::string toJsonString() const {
return boost::json::serialize(toJson(), {});
}
static ASTNode *fromJson(boost::json::value json);
virtual bool isExpr() { return false; }
virtual bool isStmt() { return false; }
virtual bool isTypeName() { return false; }
virtual bool isExpr() const { return false; }
virtual bool isStmt() const { return false; }
virtual bool isTypeName() const { return false; }
virtual std::string error(const std::string &message) const {
std::stringstream ss;
ss << "In file " << sourceRange.file << ":" << sourceRange.start.first
<< ":" << sourceRange.start.second + 1 << "\n"
<< terminal::cyan << sourceRange.text << terminal::reset << "\n"
<< terminal::red << message << terminal::reset;
return ss.str();
}
virtual std::any accept(ASTVisitor *visitor, std::any param) = 0;
};
class Expr : public ASTNode {
public:
std::shared_ptr<Type> type;
public:
Expr(LOC_ARG) : ASTNode(sourceRange) {}
virtual ~Expr() = default;
static Expr *fromJson(boost::json::value json);
virtual bool isExpr() override { return true; }
virtual bool isExpr() const override { return true; }
};
class Stmt : public ASTNode {
@ -205,17 +227,19 @@ public:
static Stmt *fromJson(boost::json::value json);
virtual bool isStmt() override { return true; }
virtual bool isStmt() const override { return true; }
};
class TypeName : public ASTNode {
public:
std::shared_ptr<Type> type;
TypeName(LOC_ARG) : ASTNode(sourceRange) {}
virtual ~TypeName() = default;
static TypeName *fromJson(boost::json::value json);
virtual bool isTypeName() override { return true; }
virtual bool isTypeName() const override { return true; }
};
} // namespace ast

View File

@ -10,15 +10,19 @@ public:
BaseASTVisitor() : ASTVisitor() {};
virtual std::any visit(BinExpr &binExpr, std::any param) override {
if (binExpr.lhs.get())
binExpr.lhs->accept(this, param);
if (binExpr.rhs.get())
binExpr.rhs->accept(this, param);
return std::any();
}
virtual std::any visit(CallExpr &callExpr, std::any param) override {
if (callExpr.callee.get())
callExpr.callee->accept(this, param);
for (auto &arg : callExpr.args) {
if (arg.get())
arg->accept(this, param);
}
@ -26,7 +30,9 @@ public:
}
virtual std::any visit(CastExpr &castExpr, std::any param) override {
if (castExpr.value.get())
castExpr.value->accept(this, param);
if (castExpr.typeName.get())
castExpr.typeName->accept(this, param);
return std::any();
}
@ -36,18 +42,22 @@ public:
}
virtual std::any visit(LambdaExpr &lambdaExpr, std::any param) override {
for (auto &param : lambdaExpr.params) {
param->accept(this, param);
if (lambdaExpr.returnTypeName.get())
lambdaExpr.returnTypeName->accept(this, param);
for (auto &p : lambdaExpr.params) {
if (p.get())
p->accept(this, param);
}
for (auto &body : lambdaExpr.body) {
body->accept(this, param);
}
if (lambdaExpr.body.get())
lambdaExpr.body->accept(this, param);
return std::any();
}
virtual std::any visit(UnExpr &unExpr, std::any param) override {
if (unExpr.expr.get())
unExpr.expr->accept(this, param);
return std::any();
}
@ -70,6 +80,7 @@ public:
}
for (auto &stmt : module.stmts) {
if (stmt.get())
stmt->accept(this, param);
}
@ -77,68 +88,82 @@ public:
}
virtual std::any visit(AssignStmt &assignStmt, std::any param) override {
if (assignStmt.lval.get())
assignStmt.lval->accept(this, param);
if (assignStmt.rval.get())
assignStmt.rval->accept(this, param);
return std::any();
}
virtual std::any visit(Block &block, std::any param) override {
for (auto &stmt : block.stmts) {
if (stmt.get())
stmt->accept(this, param);
}
return std::any();
}
virtual std::any visit(ExprStmt &exprStmt, std::any param) override {
if (exprStmt.expr.get())
exprStmt.expr->accept(this, param);
return std::any();
}
virtual std::any visit(FnParam &fnParam, std::any param) override {
if (fnParam.typeName.get())
fnParam.typeName->accept(this, param);
return std::any();
}
virtual std::any visit(FnDecl &fnDecl, std::any param) override {
for (auto &param : fnDecl.params) {
param->accept(this, param);
if (fnDecl.returnTypeName.get())
fnDecl.returnTypeName->accept(this, param);
for (auto &p : fnDecl.params) {
if (p.get())
p->accept(this, param);
}
for (auto &body : fnDecl.body) {
body->accept(this, param);
}
if (fnDecl.body.get())
fnDecl.body->accept(this, param);
return std::any();
}
virtual std::any visit(IfStmt &ifStmt, std::any param) override {
if (ifStmt.condition.get())
ifStmt.condition->accept(this, param);
for (auto &ifBody : ifStmt.ifBody) {
ifBody->accept(this, param);
}
for (auto &elseBody : ifStmt.elseBody) {
elseBody->accept(this, param);
}
if (ifStmt.ifBody.get())
ifStmt.ifBody->accept(this, param);
if (ifStmt.elseBody.get())
ifStmt.elseBody->accept(this, param);
return std::any();
}
virtual std::any visit(RetStmt &retStmt, std::any param) override {
if (retStmt.value.get())
retStmt.value->accept(this, param);
return std::any();
}
virtual std::any visit(VarDecl &varDecl, std::any param) override {
if (varDecl.typeName.get())
varDecl.typeName->accept(this, param);
return std::any();
}
virtual std::any visit(WhileStmt &whileStmt, std::any param) override {
if (whileStmt.condition.get())
whileStmt.condition->accept(this, param);
for (auto &body : whileStmt.body) {
body->accept(this, param);
}
if (whileStmt.body.get())
whileStmt.body->accept(this, param);
return std::any();
}
virtual std::any visit(PrimitiveTypeName &primitiveTypeName,
virtual std::any visit(NamedTypeName &namedTypeName,
std::any param) override {
return std::any();
}

View File

@ -2,7 +2,6 @@
#include "AST/Base.h"
#include <memory>
#include <string>
namespace plsm {
namespace ast {
@ -28,12 +27,17 @@ enum BinOp {
class BinExpr : public Expr {
public:
const BinOp op;
const std::shared_ptr<Expr> lhs, rhs;
std::unique_ptr<Expr> lhs, rhs;
BinExpr(LOC_ARG, const BinOp op, Expr *lhs, Expr *rhs)
: Expr(sourceRange), op(op), lhs(lhs), rhs(rhs) {}
BinExpr(LOC_ARG, const BinOp op, std::unique_ptr<Expr> lhs,
std::unique_ptr<Expr> rhs)
: Expr(sourceRange), op(op), lhs(std::move(lhs)), rhs(std::move(rhs)) {}
virtual boost::json::value toJson() override;
BinExpr(LOC_ARG, const BinOp op, std::unique_ptr<Expr> &lhs,
std::unique_ptr<Expr> &rhs)
: Expr(sourceRange), op(op), lhs(std::move(lhs)), rhs(std::move(rhs)) {}
virtual boost::json::value toJson() const override;
static BinExpr *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -9,17 +9,14 @@ namespace ast {
class CallExpr : public Expr {
public:
const std::shared_ptr<Expr> callee;
std::vector<std::shared_ptr<Expr>> args;
std::unique_ptr<Expr> callee;
std::vector<std::unique_ptr<Expr>> args;
CallExpr(LOC_ARG, Expr *callee, std::vector<Expr *> args)
: Expr(sourceRange), callee(callee), args() {
for (auto &arg : args) {
this->args.push_back(std::shared_ptr<Expr>(arg));
}
}
CallExpr(LOC_ARG, std::unique_ptr<Expr> callee,
std::vector<std::unique_ptr<Expr>> args)
: Expr(sourceRange), callee(std::move(callee)), args(std::move(args)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static CallExpr *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -1,20 +1,21 @@
#pragma once
#include "AST/Base.h"
#include <string>
namespace plsm {
namespace ast {
class CastExpr : public Expr {
public:
const std::shared_ptr<Expr> value;
const std::shared_ptr<TypeName> typeName;
std::unique_ptr<Expr> value;
std::unique_ptr<TypeName> typeName;
CastExpr(LOC_ARG, Expr *value, TypeName *typeName)
: Expr(sourceRange), value(value), typeName(typeName) {}
CastExpr(LOC_ARG, std::unique_ptr<Expr> value,
std::unique_ptr<TypeName> typeName)
: Expr(sourceRange), value(std::move(value)),
typeName(std::move(typeName)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static CastExpr *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -14,7 +14,7 @@ public:
Identifier(LOC_ARG, const std::string &name)
: Expr(sourceRange), name(name) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static Identifier *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -2,7 +2,6 @@
#include "AST/Base.h"
#include <memory>
#include <string>
#include <vector>
namespace plsm {
@ -11,21 +10,17 @@ class FnParam;
class LambdaExpr : public Expr {
public:
std::vector<std::shared_ptr<FnParam>> params;
std::vector<std::shared_ptr<Expr>> body;
std::vector<std::unique_ptr<FnParam>> params;
std::unique_ptr<TypeName> returnTypeName;
std::unique_ptr<Block> body;
LambdaExpr(LOC_ARG, std::vector<FnParam *> params, std::vector<Expr *> body)
: Expr(sourceRange), params(), body() {
for (auto &param : params) {
this->params.push_back(std::shared_ptr<FnParam>(param));
}
LambdaExpr(LOC_ARG, std::vector<std::unique_ptr<FnParam>> params,
std::unique_ptr<TypeName> returnTypeName,
std::unique_ptr<Block> body)
: Expr(sourceRange), params(std::move(params)),
returnTypeName(std::move(returnTypeName)), body(std::move(body)) {}
for (auto &expr : body) {
this->body.push_back(std::shared_ptr<Expr>(expr));
}
}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static LambdaExpr *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -2,7 +2,6 @@
#include "AST/Base.h"
#include <memory>
#include <string>
namespace plsm {
namespace ast {
@ -15,12 +14,12 @@ enum UnOp {
class UnExpr : public Expr {
public:
const UnOp op;
const std::shared_ptr<Expr> expr;
std::unique_ptr<Expr> expr;
UnExpr(LOC_ARG, const UnOp op, Expr *expr)
: Expr(sourceRange), op(op), expr(expr) {}
UnExpr(LOC_ARG, const UnOp op, std::unique_ptr<Expr> expr)
: Expr(sourceRange), op(op), expr(std::move(expr)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static UnExpr *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -3,7 +3,6 @@
#include "AST/Base.h"
#include <cfloat>
#include <cstdint>
#include <string>
namespace plsm {
namespace ast {
@ -11,7 +10,7 @@ namespace ast {
// public:
// NullValue(LOC_ARG) : Expr(sourceRange) {}
// virtual boost::json::value toJson() override;
// virtual boost::json::value toJson() const override;
// static std::unique_ptr<NullValue> fromJson(boost::json::value json);
// };
@ -21,7 +20,7 @@ public:
IntValue(LOC_ARG, int64_t value) : Expr(sourceRange), value(value) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static IntValue *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
@ -35,7 +34,7 @@ public:
FloatValue(LOC_ARG, double value) : Expr(sourceRange), value(value) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static FloatValue *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -12,7 +12,7 @@ public:
Import(LOC_ARG, const std::string &moduleName)
: ASTNode(sourceRange), moduleName(moduleName) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static Import *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -11,22 +11,16 @@ class Import;
class Module : public ASTNode {
public:
const std::string name;
std::vector<std::shared_ptr<Import>> imports;
std::vector<std::shared_ptr<Stmt>> stmts;
std::vector<std::unique_ptr<Import>> imports;
std::vector<std::unique_ptr<Stmt>> stmts;
Module(LOC_ARG, const std::string &name, const std::vector<Import *> &imports,
const std::vector<Stmt *> &stmts)
: ASTNode(sourceRange), name(name), imports(), stmts() {
for (auto &import : imports) {
this->imports.push_back(std::shared_ptr<Import>(import));
}
Module(LOC_ARG, const std::string &name,
std::vector<std::unique_ptr<Import>> imports,
std::vector<std::unique_ptr<Stmt>> stmts)
: ASTNode(sourceRange), name(name), imports(std::move(imports)),
stmts(std::move(stmts)) {}
for (auto &stmt : stmts) {
this->stmts.push_back(std::shared_ptr<Stmt>(stmt));
}
}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static Module *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -2,20 +2,19 @@
#include "AST/Base.h"
#include <memory>
#include <string>
namespace plsm {
namespace ast {
class AssignStmt : public Stmt {
public:
const std::shared_ptr<Expr> lval;
const std::shared_ptr<Expr> rval;
std::unique_ptr<Expr> lval;
std::unique_ptr<Expr> rval;
AssignStmt(LOC_ARG, Expr *lval, Expr *rval)
: Stmt(sourceRange), lval(lval), rval(rval) {}
AssignStmt(LOC_ARG, std::unique_ptr<Expr> lval, std::unique_ptr<Expr> rval)
: Stmt(sourceRange), lval(std::move(lval)), rval(std::move(rval)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static AssignStmt *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -0,0 +1,24 @@
#pragma once
#include "AST/Base.h"
namespace plsm {
namespace ast {
class Block : public ASTNode {
public:
std::vector<std::unique_ptr<Stmt>> stmts;
Block(LOC_ARG, std::vector<std::unique_ptr<Stmt>> stmts)
: ASTNode(sourceRange), stmts(std::move(stmts)) {}
virtual boost::json::value toJson() const override;
static Block *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
return visitor->visit(*this, param);
}
};
} // namespace ast
} // namespace plsm

View File

@ -7,11 +7,12 @@ namespace plsm {
namespace ast {
class ExprStmt : public Stmt {
public:
const std::shared_ptr<Expr> expr;
std::unique_ptr<Expr> expr;
ExprStmt(LOC_ARG, Expr *expr) : Stmt(sourceRange), expr(expr) {}
ExprStmt(LOC_ARG, std::unique_ptr<Expr> expr)
: Stmt(sourceRange), expr(std::move(expr)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static ExprStmt *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -11,14 +11,14 @@ namespace ast {
class FnParam : public ASTNode {
public:
const std::string name;
const std::shared_ptr<TypeName> typeName;
std::unique_ptr<TypeName> typeName;
std::shared_ptr<Symbol> symbol;
FnParam(LOC_ARG, const std::string &name, TypeName *typeName)
: ASTNode(sourceRange), name(name), typeName(typeName) {}
FnParam(LOC_ARG, const std::string &name, std::unique_ptr<TypeName> typeName)
: ASTNode(sourceRange), name(name), typeName(std::move(typeName)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static FnParam *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
@ -29,26 +29,19 @@ public:
class FnDecl : public Stmt {
public:
const std::string name;
std::vector<std::shared_ptr<FnParam>> params;
const std::shared_ptr<TypeName> returnTypeName;
std::vector<std::shared_ptr<Stmt>> body;
std::vector<std::unique_ptr<FnParam>> params;
std::unique_ptr<TypeName> returnTypeName;
std::unique_ptr<Block> body;
std::shared_ptr<Symbol> symbol;
FnDecl(LOC_ARG, const std::string &name, const std::vector<FnParam *> &params,
TypeName *returnTypeName, const std::vector<Stmt *> &body)
: Stmt(sourceRange), name(name), params(), returnTypeName(returnTypeName),
body() {
for (auto &param : params) {
this->params.push_back(std::shared_ptr<FnParam>(param));
}
FnDecl(LOC_ARG, const std::string &name,
std::vector<std::unique_ptr<FnParam>> params,
std::unique_ptr<TypeName> returnTypeName, std::unique_ptr<Block> body)
: Stmt(sourceRange), name(name), params(std::move(params)),
returnTypeName(std::move(returnTypeName)), body(std::move(body)) {}
for (auto &stmt : body) {
this->body.push_back(std::shared_ptr<Stmt>(stmt));
}
}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static FnDecl *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -2,29 +2,21 @@
#include "AST/Base.h"
#include <memory>
#include <vector>
namespace plsm {
namespace ast {
class IfStmt : public Stmt {
public:
const std::shared_ptr<Expr> condition;
std::vector<std::shared_ptr<Stmt>> ifBody, elseBody;
std::unique_ptr<Expr> condition;
std::unique_ptr<Block> ifBody, elseBody;
IfStmt(LOC_ARG, Expr *condition, const std::vector<Stmt *> &ifBody,
const std::vector<Stmt *> &elseBody)
: Stmt(sourceRange), condition(condition) {
for (auto &stmt : ifBody) {
this->ifBody.push_back(std::shared_ptr<Stmt>(stmt));
}
IfStmt(LOC_ARG, std::unique_ptr<Expr> condition,
std::unique_ptr<Block> ifBody, std::unique_ptr<Block> elseBody)
: Stmt(sourceRange), condition(std::move(condition)),
ifBody(std::move(ifBody)), elseBody(std::move(elseBody)) {}
for (auto &stmt : elseBody) {
this->elseBody.push_back(std::shared_ptr<Stmt>(stmt));
}
}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static IfStmt *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -7,11 +7,12 @@ namespace plsm {
namespace ast {
class RetStmt : public Stmt {
public:
const std::shared_ptr<Expr> value;
std::unique_ptr<Expr> value;
RetStmt(LOC_ARG, Expr *value) : Stmt(sourceRange), value(value) {}
RetStmt(LOC_ARG, std::unique_ptr<Expr> value)
: Stmt(sourceRange), value(std::move(value)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static RetStmt *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -10,14 +10,14 @@ namespace ast {
class VarDecl : public Stmt {
public:
const std::string name;
const std::shared_ptr<TypeName> typeName;
std::unique_ptr<TypeName> typeName;
std::shared_ptr<Symbol> symbol;
VarDecl(LOC_ARG, const std::string &name, TypeName *typeName)
: Stmt(sourceRange), name(name), typeName(typeName) {}
VarDecl(LOC_ARG, const std::string &name, std::unique_ptr<TypeName> typeName)
: Stmt(sourceRange), name(name), typeName(std::move(typeName)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static VarDecl *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {

View File

@ -2,28 +2,26 @@
#include "AST/Base.h"
#include <memory>
#include <vector>
namespace plsm {
namespace ast {
class WhileStmt : public Stmt {
public:
const std::shared_ptr<Expr> condition;
std::vector<std::shared_ptr<Stmt>> body;
std::unique_ptr<Expr> condition;
std::unique_ptr<Block> body;
WhileStmt(LOC_ARG, Expr *condition, const std::vector<Stmt *> &body)
: Stmt(sourceRange), condition(condition) {
for (auto &stmt : body) {
this->body.push_back(std::shared_ptr<Stmt>(stmt));
}
}
WhileStmt(LOC_ARG, std::unique_ptr<Expr> condition,
std::unique_ptr<Block> body)
: Stmt(sourceRange), condition(std::move(condition)),
body(std::move(body)) {}
virtual boost::json::value toJson() override;
virtual boost::json::value toJson() const override;
static WhileStmt *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
return visitor->visit(*this, param);
}
};
} // namespace ast
} // namespace plsm

View File

@ -11,14 +11,36 @@ public:
std::vector<std::shared_ptr<Type>> paramTypes;
const std::shared_ptr<Type> returnType;
FunctionType(const std::vector<Type *> &paramTypes, Type *returnType)
: Type(), returnType(returnType) {
for (auto &paramType : paramTypes) {
this->paramTypes.push_back(std::shared_ptr<Type>(paramType));
}
FunctionType(std::vector<std::shared_ptr<Type>> paramTypes,
std::shared_ptr<Type> returnType)
: Type(), paramTypes(paramTypes), returnType(returnType) {}
virtual TypeName *toTypeName() override;
virtual bool operator==(const Type &other) override {
if (const FunctionType *ft = dynamic_cast<const FunctionType *>(&other)) {
Type &lhsType = *returnType;
Type &rhsType = *ft->returnType;
if (lhsType != rhsType)
return false;
if (paramTypes.size() != ft->paramTypes.size())
return false;
for (ssize_t i = 0; i < paramTypes.size(); i++) {
Type &lhsType = *paramTypes[i];
Type &rhsType = *ft->paramTypes[i];
if (lhsType != rhsType)
return false;
}
virtual boost::json::value toJson() override;
return true;
}
return false;
}
virtual boost::json::value toJson() const override;
static FunctionType *fromJson(boost::json::value json);
};
} // namespace ast

View File

@ -11,10 +11,17 @@ public:
PrimitiveType(const std::string &name) : Type(), name(name) {}
bool operator==(const PrimitiveType &other) { return name == other.name; }
bool operator!=(const PrimitiveType &other) { return !(*this == other); }
virtual TypeName *toTypeName() override;
virtual boost::json::value toJson() override;
virtual bool operator==(const Type &other) override {
if (const PrimitiveType *pt = dynamic_cast<const PrimitiveType *>(&other)) {
return name == pt->name;
}
return false;
}
virtual boost::json::value toJson() const override;
static PrimitiveType *fromJson(boost::json::value json);
};

View File

@ -0,0 +1,27 @@
#pragma once
#include "AST/Base.h"
namespace plsm {
namespace ast {
class NamedTypeName : public TypeName {
public:
const std::string name;
NamedTypeName(LOC_ARG, const std::string &name)
: TypeName(sourceRange), name(name) {}
bool operator==(const NamedTypeName &other) { return name == other.name; }
bool operator!=(const NamedTypeName &other) { return !(*this == other); }
virtual boost::json::value toJson() const override;
static NamedTypeName *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
return visitor->visit(*this, param);
}
};
} // namespace ast
} // namespace plsm

View File

@ -1,27 +0,0 @@
#pragma once
#include "AST/Base.h"
namespace plsm {
namespace ast {
class PrimitiveTypeName : public TypeName {
public:
const std::string name;
PrimitiveTypeName(LOC_ARG, const std::string &name)
: TypeName(sourceRange), name(name) {}
bool operator==(const PrimitiveTypeName &other) { return name == other.name; }
bool operator!=(const PrimitiveTypeName &other) { return !(*this == other); }
virtual boost::json::value toJson() override;
static PrimitiveTypeName *fromJson(boost::json::value json);
virtual std::any accept(ASTVisitor *visitor, std::any param) override {
return visitor->visit(*this, param);
}
};
} // namespace ast
} // namespace plsm

View File

@ -4,6 +4,7 @@
namespace plsm {
void performNameAnalysis(std::shared_ptr<ast::Module> module);
void performNameAnalysis(std::unique_ptr<ast::Module> &module);
void performTypeAnalysis(std::unique_ptr<ast::Module> &module);
}
} // namespace plsm

13
compiler/include/Errors.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <string>
#include <vector>
namespace plsm {
namespace errors {
void put(const std::string &msg);
std::vector<std::string> get();
} // namespace errors
} // namespace plsm

View File

@ -6,6 +6,6 @@
#include "AST/AST.h"
namespace plsm {
std::shared_ptr<ast::Module> parse(const std::string &file,
std::unique_ptr<ast::Module> parse(const std::string &file,
const std::string &input);
}

View File

@ -0,0 +1,10 @@
#pragma once
namespace terminal {
const auto reset = "\x1B[0m";
const auto cyan = "\x1B[36m";
const auto red = "\x1B[31m";
const auto yellow = "\x1B[33m";
} // namespace terminal

View File

@ -1,3 +1,5 @@
#pragma once
#include <boost/json.hpp>
#include <functional>
#include <vector>
@ -5,7 +7,7 @@
namespace plsm {
namespace utils {
template <typename T> auto mapToJson(const std::vector<T> &vector) {
template <typename T> inline auto mapToJson(const std::vector<T> &vector) {
boost::json::array result(vector.size());
for (size_t i = 0; i < vector.size(); i++)
result[i] = vector[i]->toJson();
@ -13,12 +15,30 @@ template <typename T> auto mapToJson(const std::vector<T> &vector) {
}
template <typename T, typename Mapper>
auto mapToJson(const std::vector<T> &vector, const Mapper &mapper) {
inline auto mapToJson(const std::vector<T> &vector, const Mapper &mapper) {
boost::json::array result(vector.size());
for (size_t i = 0; i < vector.size(); i++)
result[i] = mapper(vector[i]);
return result;
}
template <typename B, typename A> inline bool is(const A *value) {
return value && dynamic_cast<const B *>(value);
}
template <typename A, typename B>
inline std::unique_ptr<A> ptrcast(std::unique_ptr<B> &ptr) {
return std::unique_ptr<A>(static_cast<A *>(ptr.release()));
}
template <typename A, typename B>
inline std::shared_ptr<A> ptrcast(std::shared_ptr<B> &ptr) {
return std::static_pointer_cast<A>(ptr);
}
// template <typename B, typename A> inline bool is(const A &value) {
// return dynamic_cast<const B *>(&value) != nullptr;
// }
} // namespace utils
} // namespace plsm

View File

@ -2,189 +2,199 @@ grammar plsm;
@parser::header {
#include "AST/AST.h"
#include "Utils.h"
#include <memory>
#include <boost/algorithm/string.hpp>
using namespace plsm::utils;
using namespace plsm::ast;
}
@parser::members {
std::string filename;
std::string filename, sourceText;
void setFileName(const std::string &filename) { this->filename = filename; }
void setSourceText(const std::string &sourceText) { this->sourceText = sourceText; }
inline SourceRange getSourceRange(antlr4::ParserRuleContext *ctx) {
if (!ctx->getStart() || !ctx->getStop()) {
return SourceRange::unknown();
}
auto start = ctx->start;
auto stop = getCurrentToken();
return SourceRange(
filename, ctx->getText(),
std::pair<size_t, size_t>(ctx->getStart()->getLine(),
ctx->getStart()->getCharPositionInLine()),
std::pair<size_t, size_t>(ctx->getStop()->getLine(),
ctx->getStop()->getCharPositionInLine()));
}
auto startPos = std::pair<size_t, size_t>(start->getLine(),
start->getCharPositionInLine());
auto stopPos = std::pair<size_t, size_t>(stop->getLine(),
stop->getCharPositionInLine());
auto text = sourceText.substr(
start->getStartIndex(), stop->getStartIndex() - start->getStartIndex());
text = boost::trim_copy(text);
// std::cout << "text: `" << text << "`" << std::endl;
return SourceRange(filename, text, startPos, stopPos);
}
}
module
returns[Module *ast]: (stmts += topLevelStmt)* {
std::vector<Stmt *> stmts;
returns[std::unique_ptr<Module> ast]: (stmts += topLevelStmt)* EOF {
std::vector<std::unique_ptr<Stmt>> stmts;
for (auto &stmt : $ctx->stmts) {
stmts.push_back(stmt->ast);
stmts.push_back(std::move(stmt->ast));
}
$ast = new Module(getSourceRange($ctx), "default", std::vector<Import *>(), stmts);
$ast = std::make_unique<Module>(getSourceRange($ctx), "default", std::vector<std::unique_ptr<Import>>(), std::move(stmts));
};
topLevelStmt
returns[Stmt *ast]:
returns[std::unique_ptr<Stmt> ast]:
varDecl {
$ast = $ctx->varDecl()->ast;
$ast = ptrcast<Stmt>($ctx->varDecl()->ast);
}
| fnDecl {
$ast = $ctx->fnDecl()->ast;
$ast = ptrcast<Stmt>($ctx->fnDecl()->ast);
};
block
returns[std::unique_ptr<Block> ast]:
(stmts += stmt)* {
std::vector<std::unique_ptr<Stmt>> stmts;
for (auto &stmt : $ctx->stmts) {
stmts.push_back(std::move(stmt->ast));
}
$ast = std::make_unique<Block>(getSourceRange($ctx), std::move(stmts));
};
singleStmtBlock
returns[std::unique_ptr<Block> ast]:
stmt {
std::vector<std::unique_ptr<Stmt>> stmts;
stmts.push_back(std::move($ctx->stmt()->ast));
$ast = std::make_unique<Block>(getSourceRange($ctx), std::move(stmts));
};
stmt
returns[Stmt *ast]:
returns[std::unique_ptr<Stmt> ast]:
exprStmt {
$ast = $ctx->exprStmt()->ast;
$ast = ptrcast<Stmt>($ctx->exprStmt()->ast);
}
| varDecl {
$ast = $ctx->varDecl()->ast;
$ast = ptrcast<Stmt>($ctx->varDecl()->ast);
}
| retStmt {
$ast = $ctx->retStmt()->ast;
$ast = ptrcast<Stmt>($ctx->retStmt()->ast);
}
| assignStmt {
$ast = $ctx->assignStmt()->ast;
$ast = ptrcast<Stmt>($ctx->assignStmt()->ast);
}
| implDeclAssignStmt {
$ast = $ctx->implDeclAssignStmt()->ast;
$ast = ptrcast<Stmt>($ctx->implDeclAssignStmt()->ast);
}
| ifStmt {
$ast = $ctx->ifStmt()->ast;
$ast = ptrcast<Stmt>($ctx->ifStmt()->ast);
}
| whileStmt {
$ast = $ctx->whileStmt()->ast;
$ast = ptrcast<Stmt>($ctx->whileStmt()->ast);
};
whileStmt
returns[WhileStmt *ast]:
returns[std::unique_ptr<WhileStmt> ast]:
'while' '(' condition = expr ')' (
'{' (stmts += stmt)* '}'
| singleStmt = stmt
'{' block '}'
| singleStmtBlock
) {
auto cond = $ctx->condition->ast;
std::unique_ptr<Block> body;
if ($ctx->block()) body = std::move($ctx->block()->ast);
else body = std::move($ctx->singleStmtBlock()->ast);
std::vector<Stmt *> body;
for (auto &stmt : $ctx->stmts) {
body.push_back(stmt->ast);
}
if ($ctx->singleStmt) body.push_back($ctx->singleStmt->ast);
$ast = new WhileStmt(getSourceRange($ctx), cond, body);
$ast = std::make_unique<WhileStmt>(getSourceRange($ctx), std::move($ctx->condition->ast), std::move(body));
};
ifStmt
returns[IfStmt *ast]:
returns[std::unique_ptr<IfStmt> ast]:
'if' '(' condition = expr ')' (
'{' (ifStmts += stmt)* '}'
| ifSingleStmt = stmt
'{' ifBlock = block '}'
| ifSingleBlock = singleStmtBlock
) (
'else' (
'{' (elseStmts += stmt)* '}'
| elseSingleStmt = stmt
'{' elseBlock = block '}'
| elseSingleBlock = singleStmtBlock
)
)? {
auto cond = $ctx->condition->ast;
std::unique_ptr<Block> ifBody;
if ($ctx->ifBlock) ifBody = std::move($ctx->ifBlock->ast);
else ifBody = std::move($ctx->ifSingleBlock->ast);
std::vector<Stmt *> ifBody;
for (auto &stmt : $ctx->ifStmts) {
ifBody.push_back(stmt->ast);
}
if ($ctx->ifSingleStmt) ifBody.push_back($ctx->ifSingleStmt->ast);
std::unique_ptr<Block> elseBody;
if ($ctx->elseBlock) elseBody = std::move($ctx->elseBlock->ast);
else if ($ctx->elseSingleBlock) elseBody = std::move($ctx->elseSingleBlock->ast);
else elseBody = std::make_unique<Block>(SourceRange::unknown(), std::vector<std::unique_ptr<Stmt>>());
std::vector<Stmt *> elseBody;
for (auto &stmt : $ctx->elseStmts) {
elseBody.push_back(stmt->ast);
}
if ($ctx->elseSingleStmt) elseBody.push_back($ctx->elseSingleStmt->ast);
$ast = new IfStmt(getSourceRange($ctx), cond, ifBody, elseBody);
$ast = std::make_unique<IfStmt>(getSourceRange($ctx), std::move($ctx->condition->ast), std::move(ifBody), std::move(elseBody));
};
implDeclAssignStmt
returns[Stmt *ast]:
returns[std::unique_ptr<Stmt> ast]:
IDENTIFIER ':=' expr {
// TODO
};
assignStmt
returns[AssignStmt *ast]:
lval = expr '=' rval = expr {
$ast = new AssignStmt(getSourceRange($ctx), $ctx->lval->ast, $ctx->rval->ast);
returns[std::unique_ptr<AssignStmt> ast]:
lval = expr '=' rval = expr ';' {
$ast = std::make_unique<AssignStmt>(getSourceRange($ctx), std::move($ctx->lval->ast), std::move($ctx->rval->ast));
};
retStmt
returns[RetStmt *ast]:
returns[std::unique_ptr<RetStmt> ast]:
'ret' expr ';' {
$ast = new RetStmt(getSourceRange($ctx), $ctx->expr()->ast);
$ast = std::make_unique<RetStmt>(getSourceRange($ctx), std::move($ctx->expr()->ast));
};
fnDecl
returns[FnDecl *ast]:
returns[std::unique_ptr<FnDecl> ast]:
'fun' name = IDENTIFIER '(' (
params += fnParam (',' params += fnParam)*
)? ')' typeName '{' (stmts += stmt)* '}' {
)? ')' typeName '{' block '}' {
auto name = $ctx->name->getText();
std::vector<FnParam *> params;
std::vector<std::unique_ptr<FnParam>> params;
for (auto &param : $ctx->params) {
params.push_back(param->ast);
params.push_back(std::move(param->ast));
}
auto returnTypeName = $ctx->typeName()->ast;
std::vector<Stmt *> body;
for (auto &stmt : $ctx->stmts) {
body.push_back(stmt->ast);
}
$ast = new FnDecl(getSourceRange($ctx), name, params, returnTypeName, body);
$ast = std::make_unique<FnDecl>(getSourceRange($ctx), name, std::move(params), std::move($ctx->typeName()->ast), std::move($ctx->block()->ast));
};
fnParam
returns[FnParam *ast]:
returns[std::unique_ptr<FnParam> ast]:
IDENTIFIER typeName {
$ast = new FnParam(getSourceRange($ctx), $ctx->IDENTIFIER()->getText(), $ctx->typeName()->ast);
$ast = std::make_unique<FnParam>(getSourceRange($ctx), $ctx->IDENTIFIER()->getText(), std::move($ctx->typeName()->ast));
};
varDecl
returns[VarDecl *ast]:
returns[std::unique_ptr<VarDecl> ast]:
'var' IDENTIFIER ':' typeName ';' {
auto name = $ctx->IDENTIFIER()->getText();
$ast = new VarDecl(getSourceRange($ctx), name, $ctx->typeName()->ast);
$ast = std::make_unique<VarDecl>(getSourceRange($ctx), name, std::move($ctx->typeName()->ast));
};
exprStmt
returns[ExprStmt *ast]:
returns[std::unique_ptr<ExprStmt> ast]:
expr ';' {
$ast = new ExprStmt(getSourceRange($ctx), $ctx->expr()->ast);
$ast = std::make_unique<ExprStmt>(getSourceRange($ctx), std::move($ctx->expr()->ast));
};
expr
returns[Expr *ast]:
returns[std::unique_ptr<Expr> ast]:
value = binaryExpr {
$ast = $ctx->value->ast;
$ast = std::move($ctx->value->ast);
};
binaryExpr
returns[Expr *ast]:
returns[std::unique_ptr<Expr> ast]:
value = unaryExpr {
$ast = $ctx->value->ast;
$ast = std::move($ctx->value->ast);
}
| lhs = binaryExpr op = ('*' | '/' | '%') rhs = binaryExpr {
auto opText = $ctx->op->getText();
@ -194,7 +204,8 @@ binaryExpr
if (opText == "/") op = BinOp::DIV;
if (opText == "%") op = BinOp::MOD;
$ast = new BinExpr(getSourceRange($ctx), op, $ctx->lhs->ast, $ctx->rhs->ast);
auto binExpr = std::make_unique<BinExpr>(getSourceRange($ctx), op, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast));
$ast = ptrcast<Expr>(binExpr);
}
| lhs = binaryExpr op = ('+' | '-') rhs = binaryExpr {
auto opText = $ctx->op->getText();
@ -203,10 +214,12 @@ binaryExpr
if (opText == "+") op = BinOp::ADD;
if (opText == "-") op = BinOp::SUB;
$ast = new BinExpr(getSourceRange($ctx), op, $ctx->lhs->ast, $ctx->rhs->ast);
auto binExpr = std::make_unique<BinExpr>(getSourceRange($ctx), op, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast));
$ast = ptrcast<Expr>(binExpr);
}
| operand = binaryExpr 'as' typeName {
$ast = new CastExpr(getSourceRange($ctx), $ctx->operand->ast, $ctx->typeName()->ast);
auto castExpr = std::make_unique<CastExpr>(getSourceRange($ctx), std::move($ctx->operand->ast), std::move($ctx->typeName()->ast));
$ast = ptrcast<Expr>(castExpr);
}
| lhs = binaryExpr op = (
'=='
@ -226,37 +239,44 @@ binaryExpr
if (opText == ">") op = BinOp::GT;
if (opText == "<") op = BinOp::LT;
$ast = new BinExpr(getSourceRange($ctx), op, $ctx->lhs->ast, $ctx->rhs->ast);
auto binExpr = std::make_unique<BinExpr>(getSourceRange($ctx), op, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast));
$ast = ptrcast<Expr>(binExpr);
}
| lhs = binaryExpr '&&' rhs = binaryExpr {
$ast = new BinExpr(getSourceRange($ctx), BinOp::AND, $ctx->lhs->ast, $ctx->rhs->ast);
auto binExpr = std::make_unique<BinExpr>(getSourceRange($ctx), BinOp::AND, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast));
$ast = ptrcast<Expr>(binExpr);
}
| lhs = binaryExpr '||' rhs = binaryExpr {
$ast = new BinExpr(getSourceRange($ctx), BinOp::OR, $ctx->lhs->ast, $ctx->rhs->ast);
auto binExpr = std::make_unique<BinExpr>(getSourceRange($ctx), BinOp::OR, std::move($ctx->lhs->ast), std::move($ctx->rhs->ast));
$ast = ptrcast<Expr>(binExpr);
};
unaryExpr
returns[Expr *ast]:
returns[std::unique_ptr<Expr> ast]:
factorExpr {
$ast = $ctx->factorExpr()->ast;
$ast = ptrcast<Expr>($ctx->factorExpr()->ast);
}
| functionCall {
$ast = $ctx->functionCall()->ast;
$ast = ptrcast<Expr>($ctx->functionCall()->ast);
}
| '!' unaryExpr {
$ast = new UnExpr(getSourceRange($ctx), UnOp::NOT, $ctx->unaryExpr()->ast);
auto unExpr = std::make_unique<UnExpr>(getSourceRange($ctx), UnOp::NOT, std::move($ctx->unaryExpr()->ast));
$ast = ptrcast<Expr>(unExpr);
}
| '+' unaryExpr {
$ast = new UnExpr(getSourceRange($ctx), UnOp::POS, $ctx->unaryExpr()->ast);
auto unExpr = std::make_unique<UnExpr>(getSourceRange($ctx), UnOp::POS, std::move($ctx->unaryExpr()->ast));
$ast = ptrcast<Expr>(unExpr);
}
| '-' unaryExpr {
$ast = new UnExpr(getSourceRange($ctx), UnOp::NEG, $ctx->unaryExpr()->ast);
auto unExpr = std::make_unique<UnExpr>(getSourceRange($ctx), UnOp::NEG, std::move($ctx->unaryExpr()->ast));
$ast = ptrcast<Expr>(unExpr);
};
factorExpr
returns[Expr *ast]:
returns[std::unique_ptr<Expr> ast]:
IDENTIFIER {
$ast = new Identifier(getSourceRange($ctx), $ctx->IDENTIFIER()->getText());
auto id = std::make_unique<Identifier>(getSourceRange($ctx), $ctx->IDENTIFIER()->getText());
$ast = ptrcast<Expr>(id);
}
| INT {
auto text = $ctx->INT()->getText();
@ -275,7 +295,8 @@ factorExpr
else
value = std::strtol(text.data(), NULL, 10);
$ast = new IntValue(getSourceRange($ctx), value);
auto val = std::make_unique<IntValue>(getSourceRange($ctx), value);
$ast = ptrcast<Expr>(val);
}
| FLOAT {
auto text = $ctx->FLOAT()->getText();
@ -286,32 +307,35 @@ factorExpr
text = "0" + text;
double value = std::strtod(text.data(), NULL);
$ast = new FloatValue(getSourceRange($ctx), value);
auto val = std::make_unique<FloatValue>(getSourceRange($ctx), value);
$ast = ptrcast<Expr>(val);
}
| BOOL {
auto text = $ctx->BOOL()->getText();
$ast = new IntValue(getSourceRange($ctx), text == "true" ? 1 : 0);
auto val = std::make_unique<IntValue>(getSourceRange($ctx), text == "true" ? 1 : 0);
$ast = ptrcast<Expr>(val);
}
| '(' expr ')' {
$ast = $ctx->expr()->ast;
$ast = std::move($ctx->expr()->ast);
};
functionCall
returns[Expr *ast]:
returns[std::unique_ptr<CallExpr> ast]:
callee = factorExpr '(' (args += expr (',' args += expr)*)? ')' {
std::vector<Expr *> args;
std::vector<std::unique_ptr<Expr>> args;
for (auto &arg : $ctx->args) {
args.push_back(arg->ast);
args.push_back(std::move(arg->ast));
}
$ast = new CallExpr(getSourceRange($ctx), $ctx->callee->ast, args);
$ast = std::make_unique<CallExpr>(getSourceRange($ctx), std::move($ctx->callee->ast), std::move(args));
};
typeName
returns[TypeName *ast]:
returns[std::unique_ptr<TypeName> ast]:
IDENTIFIER {
auto text = $ctx->IDENTIFIER()->getText();
$ast = new PrimitiveTypeName(getSourceRange($ctx), text);
auto named = std::make_unique<NamedTypeName>(getSourceRange($ctx), text);
$ast = ptrcast<TypeName>(named);
};
INT: [0-9]+ | '0x' [0-9a-fA-F]+ | '0o' [0-7]+ | '0b' [01]+;

View File

@ -57,8 +57,8 @@ ASTNode *ASTNode::fromJson(boost::json::value json) {
if (type == "WhileStmt")
return WhileStmt::fromJson(json);
if (type == "PrimitiveTypeName")
return PrimitiveTypeName::fromJson(json);
if (type == "NamedTypeName")
return NamedTypeName::fromJson(json);
throw std::runtime_error("json conversion for '" + type +
"' not implemented");

View File

@ -18,7 +18,7 @@ static const std::unordered_map<std::string, BinOp> stringToBinOp = {
{"||", BinOp::OR},
};
boost::json::value BinExpr::toJson() {
boost::json::value BinExpr::toJson() const {
return {
{"@type", "BinExpr"},
{"op", binOpToString.at(op)},
@ -34,7 +34,7 @@ BinExpr *BinExpr::fromJson(boost::json::value json) {
auto lhs = fromJsonProperty<BinExpr, Expr>(json, "lhs");
auto rhs = fromJsonProperty<BinExpr, Expr>(json, "rhs");
return new BinExpr(SourceRange::json(), op, lhs, rhs);
return new BinExpr(SourceRange::json(), op, std::move(lhs), std::move(rhs));
}
} // namespace ast

View File

@ -4,7 +4,7 @@
namespace plsm {
namespace ast {
boost::json::value CallExpr::toJson() {
boost::json::value CallExpr::toJson() const {
return {
{"@type", "CallExpr"},
{"callee", callee->toJson()},
@ -15,7 +15,7 @@ boost::json::value CallExpr::toJson() {
CallExpr *CallExpr::fromJson(boost::json::value json) {
auto callee = fromJsonProperty<CallExpr, Expr>(json, "callee");
auto args = fromJsonVector<CallExpr, Expr>(json, "args");
return new CallExpr(SourceRange::json(), callee, args);
return new CallExpr(SourceRange::json(), std::move(callee), std::move(args));
}
} // namespace ast

View File

@ -4,7 +4,7 @@
namespace plsm {
namespace ast {
boost::json::value CastExpr::toJson() {
boost::json::value CastExpr::toJson() const {
return {
{"@type", "CastExpr"},
{"value", value->toJson()},
@ -15,7 +15,8 @@ boost::json::value CastExpr::toJson() {
CastExpr *CastExpr::fromJson(boost::json::value json) {
auto value = fromJsonProperty<CastExpr, Expr>(json, "value");
auto typeName = fromJsonProperty<CastExpr, TypeName>(json, "typeName");
return new CastExpr(SourceRange::json(), value, typeName);
return new CastExpr(SourceRange::json(), std::move(value),
std::move(typeName));
}
} // namespace ast

View File

@ -3,7 +3,7 @@
namespace plsm {
namespace ast {
boost::json::value Identifier::toJson() {
boost::json::value Identifier::toJson() const {
return {
{"@type", "Identifier"},
{"name", name},

View File

@ -4,18 +4,22 @@
namespace plsm {
namespace ast {
boost::json::value LambdaExpr::toJson() {
boost::json::value LambdaExpr::toJson() const {
return {
{"@type", "LambdaExpr"},
{"params", utils::mapToJson(params)},
{"body", utils::mapToJson(body)},
{"returnTypeName", returnTypeName->toJson()},
{"body", body->toJson()},
};
}
LambdaExpr *LambdaExpr::fromJson(boost::json::value json) {
auto params = fromJsonVector<LambdaExpr, FnParam>(json, "params");
auto body = fromJsonVector<LambdaExpr, Expr>(json, "body");
return new LambdaExpr(SourceRange::json(), params, body);
auto returnTypeName =
fromJsonProperty<LambdaExpr, TypeName>(json, "returnTypeName");
auto body = fromJsonProperty<LambdaExpr, Block>(json, "body");
return new LambdaExpr(SourceRange::json(), std::move(params),
std::move(returnTypeName), std::move(body));
}
} // namespace ast

View File

@ -16,7 +16,7 @@ static const std::unordered_map<std::string, UnOp> stringToUnOp = {
{"!", UnOp::NOT},
};
boost::json::value UnExpr::toJson() {
boost::json::value UnExpr::toJson() const {
return {
{"@type", "UnExpr"},
{"op", unOpToString.at(op)},
@ -29,7 +29,7 @@ UnExpr *UnExpr::fromJson(boost::json::value json) {
auto op = stringToUnOp.at(opString);
auto expr = fromJsonProperty<UnExpr, Expr>(json, "expr");
return new UnExpr(SourceRange::json(), op, expr);
return new UnExpr(SourceRange::json(), op, std::move(expr));
}
} // namespace ast

View File

@ -3,20 +3,20 @@
namespace plsm {
namespace ast {
// boost::json::value NullValue::toJson() { return nullptr; }
// boost::json::value NullValue::toJson() const { return nullptr; }
// std::unique_ptr<NullValue>
// NullValue::fromJson(boost::json::value json) {
// return std::make_unique<NullValue>(SourceRange::json());
// }
boost::json::value IntValue::toJson() { return value; }
boost::json::value IntValue::toJson() const { return value; }
IntValue *IntValue::fromJson(boost::json::value json) {
return new IntValue(SourceRange::json(), json.as_int64());
}
boost::json::value FloatValue::toJson() { return value; }
boost::json::value FloatValue::toJson() const { return value; }
FloatValue *FloatValue::fromJson(boost::json::value json) {
return new FloatValue(SourceRange::json(), json.as_double());

View File

@ -4,7 +4,7 @@
namespace plsm {
namespace ast {
boost::json::value Import::toJson() {
boost::json::value Import::toJson() const {
return {{"@type", "Import"}, {"moduleName", moduleName}};
}
Import *Import::fromJson(boost::json::value json) {

View File

@ -4,7 +4,7 @@
namespace plsm {
namespace ast {
boost::json::value Module::toJson() {
boost::json::value Module::toJson() const {
return {
{"@type", "Module"},
{"name", name},
@ -18,7 +18,8 @@ Module *Module::fromJson(boost::json::value json) {
auto imports = fromJsonVector<Module, Import>(json, "imports");
auto stmts = fromJsonVector<Module, Stmt>(json, "stmts");
return new Module(SourceRange::json(), name, imports, stmts);
return new Module(SourceRange::json(), name, std::move(imports),
std::move(stmts));
}
} // namespace ast

View File

@ -3,7 +3,7 @@
namespace plsm {
namespace ast {
boost::json::value AssignStmt::toJson() {
boost::json::value AssignStmt::toJson() const {
return {
{"@type", "AssignStmt"},
{"lval", lval->toJson()},
@ -14,7 +14,7 @@ boost::json::value AssignStmt::toJson() {
AssignStmt *AssignStmt::fromJson(boost::json::value json) {
auto lval = fromJsonProperty<AssignStmt, Expr>(json, "lval");
auto rval = fromJsonProperty<AssignStmt, Expr>(json, "rval");
return new AssignStmt(SourceRange::json(), lval, rval);
return new AssignStmt(SourceRange::json(), std::move(lval), std::move(rval));
}
} // namespace ast

View File

@ -0,0 +1,20 @@
#include "AST/AST.h"
#include "Utils.h"
namespace plsm {
namespace ast {
boost::json::value Block::toJson() const {
return {
{"@type", "Block"},
{"stmts", utils::mapToJson(stmts)},
};
}
Block *Block::fromJson(boost::json::value json) {
auto stmts = fromJsonVector<Block, Stmt>(json, "stmts");
return new Block(SourceRange::json(), std::move(stmts));
}
} // namespace ast
} // namespace plsm

View File

@ -3,7 +3,7 @@
namespace plsm {
namespace ast {
boost::json::value ExprStmt::toJson() {
boost::json::value ExprStmt::toJson() const {
return {
{"@type", "ExprStmt"},
{"expr", expr->toJson()},
@ -12,7 +12,7 @@ boost::json::value ExprStmt::toJson() {
ExprStmt *ExprStmt::fromJson(boost::json::value json) {
auto expr = fromJsonProperty<ExprStmt, Expr>(json, "expr");
return new ExprStmt(SourceRange::json(), expr);
return new ExprStmt(SourceRange::json(), std::move(expr));
}
} // namespace ast

View File

@ -4,7 +4,7 @@
namespace plsm {
namespace ast {
boost::json::value FnParam::toJson() {
boost::json::value FnParam::toJson() const {
return {
{"@type", "FnParam"},
{"name", name},
@ -15,16 +15,16 @@ boost::json::value FnParam::toJson() {
FnParam *FnParam::fromJson(boost::json::value json) {
auto name = getJsonValue<FnParam, std::string>(json, "name");
auto typeName = fromJsonProperty<FnParam, TypeName>(json, "typeName");
return new FnParam(SourceRange::json(), name, typeName);
return new FnParam(SourceRange::json(), name, std::move(typeName));
}
boost::json::value FnDecl::toJson() {
boost::json::value FnDecl::toJson() const {
return {
{"@type", "FnDecl"},
{"name", name},
{"params", utils::mapToJson(params)},
{"returnTypeName", returnTypeName->toJson()},
{"body", utils::mapToJson(body)},
{"body", body->toJson()},
};
}
@ -33,8 +33,9 @@ FnDecl *FnDecl::fromJson(boost::json::value json) {
auto params = fromJsonVector<FnDecl, FnParam>(json, "params");
auto returnTypeName =
fromJsonProperty<FnDecl, TypeName>(json, "returnTypeName");
auto body = fromJsonVector<FnDecl, Stmt>(json, "body");
return new FnDecl(SourceRange::json(), name, params, returnTypeName, body);
auto body = fromJsonProperty<FnDecl, Block>(json, "body");
return new FnDecl(SourceRange::json(), name, std::move(params),
std::move(returnTypeName), std::move(body));
}
} // namespace ast

View File

@ -4,20 +4,21 @@
namespace plsm {
namespace ast {
boost::json::value IfStmt::toJson() {
boost::json::value IfStmt::toJson() const {
return {
{"@type", "IfStmt"},
{"condition", condition->toJson()},
{"ifBody", utils::mapToJson(ifBody)},
{"elseBody", utils::mapToJson(elseBody)},
{"ifBody", ifBody->toJson()},
{"elseBody", elseBody->toJson()},
};
}
IfStmt *IfStmt::fromJson(boost::json::value json) {
auto condition = fromJsonProperty<IfStmt, Expr>(json, "condition");
auto ifBody = fromJsonVector<IfStmt, Stmt>(json, "ifBody");
auto elseBody = fromJsonVector<IfStmt, Stmt>(json, "elseBody");
return new IfStmt(SourceRange::json(), condition, ifBody, elseBody);
auto ifBody = fromJsonProperty<IfStmt, Block>(json, "ifBody");
auto elseBody = fromJsonProperty<IfStmt, Block>(json, "elseBody");
return new IfStmt(SourceRange::json(), std::move(condition),
std::move(ifBody), std::move(elseBody));
}
} // namespace ast

View File

@ -3,7 +3,7 @@
namespace plsm {
namespace ast {
boost::json::value RetStmt::toJson() {
boost::json::value RetStmt::toJson() const {
return {
{"@type", "RetStmt"},
{"value", value->toJson()},
@ -12,7 +12,7 @@ boost::json::value RetStmt::toJson() {
RetStmt *RetStmt::fromJson(boost::json::value json) {
auto value = fromJsonProperty<RetStmt, Expr>(json, "value");
return new RetStmt(SourceRange::json(), value);
return new RetStmt(SourceRange::json(), std::move(value));
}
} // namespace ast

View File

@ -3,7 +3,7 @@
namespace plsm {
namespace ast {
boost::json::value VarDecl::toJson() {
boost::json::value VarDecl::toJson() const {
return {
{"@type", "VarDecl"},
{"name", name},
@ -14,7 +14,7 @@ boost::json::value VarDecl::toJson() {
VarDecl *VarDecl::fromJson(boost::json::value json) {
auto name = getJsonValue<VarDecl, std::string>(json, "name");
auto typeName = fromJsonProperty<VarDecl, TypeName>(json, "typeName");
return new VarDecl(SourceRange::json(), name, typeName);
return new VarDecl(SourceRange::json(), name, std::move(typeName));
}
} // namespace ast

View File

@ -4,18 +4,19 @@
namespace plsm {
namespace ast {
boost::json::value WhileStmt::toJson() {
boost::json::value WhileStmt::toJson() const {
return {
{"@type", "WhileStmt"},
{"condition", condition->toJson()},
{"body", utils::mapToJson(body)},
{"body", body->toJson()},
};
}
WhileStmt *WhileStmt::fromJson(boost::json::value json) {
auto condition = fromJsonProperty<WhileStmt, Expr>(json, "condition");
auto body = fromJsonVector<WhileStmt, Stmt>(json, "body");
return new WhileStmt(SourceRange::json(), condition, body);
auto body = fromJsonProperty<WhileStmt, Block>(json, "body");
return new WhileStmt(SourceRange::json(), std::move(condition),
std::move(body));
}
} // namespace ast

View File

@ -1,10 +1,13 @@
#include "AST/Type/FunctionType.h"
#include "AST/AST.h"
#include "AST/Base.h"
#include "Utils.h"
#include <memory>
namespace plsm {
namespace ast {
boost::json::value FunctionType::toJson() {
boost::json::value FunctionType::toJson() const {
return {
{"@type", "FunctionType"},
{"paramTypes", utils::mapToJson(paramTypes)},
@ -13,10 +16,19 @@ boost::json::value FunctionType::toJson() {
}
FunctionType *FunctionType::fromJson(boost::json::value json) {
auto paramTypes = fromJsonVector<FunctionType, Type>(json, "paramTypes");
auto returnType = fromJsonProperty<FunctionType, Type>(json, "returnType");
auto paramTypesU = fromJsonVector<FunctionType, Type>(json, "paramTypes");
auto returnTypeU = fromJsonProperty<FunctionType, Type>(json, "returnType");
std::vector<std::shared_ptr<Type>> paramTypes;
for (auto &paramType : paramTypesU)
paramTypes.push_back(std::shared_ptr<Type>(paramType.release()));
auto returnType = std::shared_ptr<Type>(returnTypeU.release());
return new FunctionType(paramTypes, returnType);
}
TypeName *FunctionType::toTypeName() { return nullptr; }
} // namespace ast
} // namespace plsm

View File

@ -1,9 +1,12 @@
#include "AST/AST.h"
#include "AST/Base.h"
#include "AST/TypeName/NamedTypeName.h"
#include <memory>
namespace plsm {
namespace ast {
boost::json::value PrimitiveType::toJson() {
boost::json::value PrimitiveType::toJson() const {
return {
{"@type", "PrimitiveType"},
{"name", name},
@ -15,5 +18,9 @@ PrimitiveType *PrimitiveType::fromJson(boost::json::value json) {
return new PrimitiveType(name);
}
TypeName *PrimitiveType::toTypeName() {
return new NamedTypeName(SourceRange::unknown(), name);
}
} // namespace ast
} // namespace plsm

View File

@ -3,13 +3,13 @@
namespace plsm {
namespace ast {
boost::json::value PrimitiveTypeName::toJson() {
return {{"@type", "PrimitiveTypeName"}, {"name", name}};
boost::json::value NamedTypeName::toJson() const {
return {{"@type", "NamedTypeName"}, {"name", name}};
}
PrimitiveTypeName *PrimitiveTypeName::fromJson(boost::json::value json) {
auto name = getJsonValue<PrimitiveTypeName, std::string>(json, "name");
return new PrimitiveTypeName(SourceRange::json(), name);
NamedTypeName *NamedTypeName::fromJson(boost::json::value json) {
auto name = getJsonValue<NamedTypeName, std::string>(json, "name");
return new NamedTypeName(SourceRange::json(), name);
}
} // namespace ast

View File

@ -1,58 +1,138 @@
#include "AST/BaseASTVisitor.h"
#include "Analysis.h"
#include "Errors.h"
#include "Utils.h"
#include <map>
#include <stack>
#include <vector>
namespace plsm {
namespace {
class NameAnalysisVisitor1 : public ast::BaseASTVisitor {
std::stack<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
public:
NameAnalysisVisitor1(
std::stack<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
: scopes(scopes) {}
virtual std::any visit(ast::FnDecl &fnDecl, std::any param) override {
if (!fnDecl.name.size())
return std::any();
auto symbol = std::make_shared<ast::Symbol>(fnDecl.name);
fnDecl.symbol = symbol;
scopes->top()[fnDecl.name] = symbol;
scopes->back()[fnDecl.name] = symbol;
return std::any();
}
virtual std::any visit(ast::VarDecl &varDecl, std::any param) override {
if (!varDecl.name.size())
return std::any();
auto symbol = std::make_shared<ast::Symbol>(varDecl.name);
varDecl.symbol = symbol;
scopes->top()[varDecl.name] = symbol;
scopes->back()[varDecl.name] = symbol;
return std::any();
}
};
class NameAnalysisVisitor2 : public ast::BaseASTVisitor {
std::stack<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes;
void push() {
scopes->push(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(); }
void pop() { scopes->pop_back(); }
std::shared_ptr<ast::Symbol> findSymbol(std::string name) {
for (long i = scopes->size() - 1; i >= 0; i--) {
auto scope = scopes->at(i);
if (scope.count(name))
return scope[name];
}
return std::shared_ptr<ast::Symbol>();
}
public:
NameAnalysisVisitor2(
std::stack<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> *scopes)
: scopes(scopes) {}
virtual std::any visit(ast::FnParam &fnParam, std::any param) override {
if (!fnParam.name.size())
return std::any();
auto symbol = std::make_shared<ast::Symbol>(fnParam.name);
fnParam.symbol = symbol;
scopes->back()[fnParam.name] = symbol;
return std::any();
}
virtual std::any visit(ast::FnDecl &fnDecl, std::any param) override {
push();
BaseASTVisitor::visit(fnDecl, param);
pop();
return std::any();
}
virtual std::any visit(ast::Block &block, std::any param) override {
push();
BaseASTVisitor::visit(block, param);
pop();
return std::any();
}
virtual std::any visit(ast::LambdaExpr &lambdaExpr, std::any param) override {
push();
BaseASTVisitor::visit(lambdaExpr, param);
pop();
return std::any();
}
virtual std::any visit(ast::Identifier &identifier, std::any param) override {
if (!identifier.name.size())
return std::any();
auto symbol = findSymbol(identifier.name);
if (!symbol.get()) {
errors::put(identifier.error("unable to resolve identifier '" +
identifier.name + "'"));
return std::any();
}
identifier.symbol = symbol;
return std::any();
}
virtual std::any visit(ast::VarDecl &varDecl, std::any param) override {
if (!varDecl.name.size())
return std::any();
auto symbol = std::make_shared<ast::Symbol>(varDecl.name);
varDecl.symbol = symbol;
scopes->back()[varDecl.name] = symbol;
return std::any();
}
};
} // namespace
void performNameAnalysis(std::shared_ptr<ast::Module> module) {
std::stack<std::map<std::string, std::shared_ptr<ast::Symbol>>> scopes;
scopes.push(std::map<std::string, std::shared_ptr<ast::Symbol>>());
void performNameAnalysis(std::unique_ptr<ast::Module> &module) {
std::vector<std::map<std::string, std::shared_ptr<ast::Symbol>>> scopes;
scopes.push_back(std::map<std::string, std::shared_ptr<ast::Symbol>>());
NameAnalysisVisitor1 visitor1(&scopes);
NameAnalysisVisitor2 visitor2(&scopes);
@ -62,6 +142,7 @@ void performNameAnalysis(std::shared_ptr<ast::Module> module) {
}
for (auto &stmt : module->stmts) {
if (utils::is<ast::FnDecl>(stmt.get()))
stmt->accept(&visitor2, nullptr);
}
}

View File

@ -0,0 +1,407 @@
#include "AST/Base.h"
#include "AST/Type/PrimitiveType.h"
#include "Analysis.h"
#include "AST/BaseASTVisitor.h"
#include "Errors.h"
#include "Utils.h"
#include <map>
#include <memory>
#include <stdexcept>
namespace plsm {
using namespace ast;
namespace {
static std::map<std::string, std::shared_ptr<PrimitiveType>> primitiveTypes = {
{"i8", std::make_shared<PrimitiveType>("i8")},
{"i16", std::make_shared<PrimitiveType>("i16")},
{"i32", std::make_shared<PrimitiveType>("i32")},
{"i64", std::make_shared<PrimitiveType>("i64")},
{"u8", std::make_shared<PrimitiveType>("u8")},
{"u16", std::make_shared<PrimitiveType>("u16")},
{"u32", std::make_shared<PrimitiveType>("u32")},
{"u64", std::make_shared<PrimitiveType>("u64")},
{"float", std::make_shared<PrimitiveType>("float")},
{"double", std::make_shared<PrimitiveType>("double")},
};
static std::shared_ptr<Type> resolveTypeName(const TypeName *typeName) {
if (utils::is<NamedTypeName>(typeName)) {
auto named = (NamedTypeName *)typeName;
if (primitiveTypes.count(named->name))
return primitiveTypes[named->name];
errors::put(
typeName->error("unable to resolve named type '" + named->name + "'"));
return std::shared_ptr<Type>(nullptr);
}
// TODO: function type
errors::put(typeName->error("unable to resolve type"));
return std::shared_ptr<Type>(nullptr);
}
static void castTo(std::unique_ptr<Expr> &expr,
const std::shared_ptr<Type> &type) {
auto cast = new CastExpr(expr->sourceRange, std::move(expr),
std::unique_ptr<TypeName>(type->toTypeName()));
cast->type = type;
cast->typeName->type = type;
auto newExpr = std::unique_ptr<Expr>(cast);
expr.swap(newExpr);
}
static bool tryAssignTo(std::unique_ptr<Expr> &from,
const std::shared_ptr<Type> &toType) {
if (*from->type == *toType)
return true;
if (utils::is<PrimitiveType>(from->type.get()) &&
utils::is<PrimitiveType>(toType.get())) {
PrimitiveType *fromT = (PrimitiveType *)from->type.get();
const PrimitiveType *toT = (PrimitiveType *)toType.get();
std::map<std::string, std::vector<std::string>> castMatrix = {
{"i8", {"i16", "i32", "i64", "u8", "u16", "u32", "u64"}},
{"i16", {"i32", "i64", "u16", "u32", "u64"}},
{"i32", {"i64", "u32", "u64"}},
{"i64", {"u64"}},
{"u8", {"i16", "i32", "i64", "u16", "u32", "u64"}},
{"u16", {"i32", "i64", "u32", "u64"}},
{"u32", {"i64", "u64"}},
{"u64", {}},
{"float", {"double"}},
{"double", {}},
};
if (!castMatrix.count(fromT->name))
return false;
auto castableTo = castMatrix[fromT->name];
for (auto &toName : castableTo) {
if (toT->name == toName) {
castTo(from, toType);
return true;
}
}
return false;
}
return false;
}
static bool canBeCastedTo(std::unique_ptr<Expr> &from,
const std::shared_ptr<Type> &toType) {
if (*from->type == *toType)
return true;
if (utils::is<PrimitiveType>(from->type.get()) &&
utils::is<PrimitiveType>(toType.get())) {
PrimitiveType *fromT = (PrimitiveType *)from->type.get();
const PrimitiveType *toT = (PrimitiveType *)toType.get();
std::vector<std::string> allNumberTypes = {"i8", "i16", "i32", "i64",
"u8", "u16", "u32", "u64",
"float", "double"};
std::map<std::string, std::vector<std::string>> castMatrix = {
{"i8", allNumberTypes}, {"i16", allNumberTypes},
{"i32", allNumberTypes}, {"i64", allNumberTypes},
{"u8", allNumberTypes}, {"u16", allNumberTypes},
{"u32", allNumberTypes}, {"u64", allNumberTypes},
{"float", allNumberTypes}, {"double", allNumberTypes},
};
if (!castMatrix.count(fromT->name))
return false;
auto castableTo = castMatrix[fromT->name];
for (auto &toName : castableTo) {
if (toT->name == toName) {
castTo(from, toType);
return true;
}
}
return false;
}
return false;
}
class TypeAnalysisVisitor1 : public BaseASTVisitor {
public:
virtual std::any visit(NamedTypeName &namedTypeName,
std::any param) override {
namedTypeName.type = resolveTypeName(&namedTypeName);
return std::any();
}
virtual std::any visit(VarDecl &varDecl, std::any param) override {
if (!varDecl.typeName.get() || !varDecl.symbol.get())
return std::any();
varDecl.typeName->accept(this, param);
if (varDecl.typeName->type.get())
varDecl.symbol->type = varDecl.typeName->type;
return std::any();
}
virtual std::any visit(FnParam &fnParam, std::any param) override {
if (!fnParam.typeName.get() || !fnParam.symbol.get())
return std::any();
fnParam.typeName->accept(this, param);
if (fnParam.typeName->type.get())
fnParam.symbol->type = fnParam.typeName->type;
return std::any();
}
virtual std::any visit(FnDecl &fnDecl, std::any param) override {
if (!fnDecl.symbol.get())
return std::any();
std::shared_ptr<Type> returnType(nullptr);
if (fnDecl.returnTypeName.get()) {
fnDecl.returnTypeName->accept(this, param);
returnType = fnDecl.returnTypeName->type;
}
std::vector<std::shared_ptr<Type>> paramTypes;
for (auto &p : fnDecl.params) {
if (p.get())
p->accept(this, param);
if (p->symbol.get()) {
paramTypes.push_back(p->symbol->type);
} else {
paramTypes.push_back(std::shared_ptr<Type>(nullptr));
}
}
fnDecl.symbol->type =
std::make_shared<FunctionType>(paramTypes, returnType);
return std::any();
}
};
class TypeAnalysisVisitor2 : public BaseASTVisitor {
std::shared_ptr<Type> currentReturnType = nullptr;
public:
virtual std::any visit(NamedTypeName &namedTypeName,
std::any param) override {
namedTypeName.type = resolveTypeName(&namedTypeName);
return std::any();
}
virtual std::any visit(VarDecl &varDecl, std::any param) override {
if (!varDecl.typeName.get() || !varDecl.symbol.get())
return std::any();
varDecl.typeName->accept(this, param);
if (varDecl.typeName->type.get())
varDecl.symbol->type = varDecl.typeName->type;
return std::any();
}
virtual std::any visit(FnParam &fnParam, std::any param) override {
if (!fnParam.typeName.get() || !fnParam.symbol.get())
return std::any();
fnParam.typeName->accept(this, param);
fnParam.symbol->type = resolveTypeName(fnParam.typeName.get());
return std::any();
}
virtual std::any visit(FnDecl &fnDecl, std::any param) override {
if (fnDecl.symbol.get() && fnDecl.symbol->type.get()) {
auto functionType = (FunctionType *)fnDecl.symbol->type.get();
currentReturnType = functionType->returnType;
} else {
currentReturnType = std::shared_ptr<Type>(nullptr);
}
if (fnDecl.body.get())
fnDecl.body->accept(this, param);
return std::any();
}
virtual std::any visit(Identifier &identifier, std::any param) override {
if (!identifier.symbol.get())
return std::any();
identifier.type = identifier.symbol->type;
return std::any();
}
virtual std::any visit(IntValue &intValue, std::any param) override {
if ((int8_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("i8");
} else if ((uint8_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("u8");
} else if ((int16_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("i16");
} else if ((uint16_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("u16");
} else if ((int32_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("i32");
} else if ((uint32_t)intValue.value == intValue.value) {
intValue.type = std::make_shared<PrimitiveType>("u32");
} else {
intValue.type = std::make_shared<PrimitiveType>("i64");
}
return std::any();
}
virtual std::any visit(FloatValue &floatValue, std::any param) override {
if ((float_t)floatValue.value == floatValue.value) {
floatValue.type = std::make_shared<PrimitiveType>("float");
} else {
floatValue.type = std::make_shared<PrimitiveType>("double");
}
return std::any();
}
virtual std::any visit(CastExpr &castExpr, std::any param) override {
BaseASTVisitor::visit(castExpr, param);
// do not multiplicate errors
if (!castExpr.value.get() || !castExpr.value->type.get())
return std::any();
if (!castExpr.typeName.get() || !castExpr.typeName->type.get())
return std::any();
if (!canBeCastedTo(castExpr.value, castExpr.typeName->type)) {
errors::put(castExpr.error("cast type mismatch"));
return std::any();
}
castExpr.type = castExpr.typeName->type;
return std::any();
}
virtual std::any visit(AssignStmt &assignStmt, std::any param) override {
BaseASTVisitor::visit(assignStmt, param);
// do not multiplicate errors
if (!assignStmt.lval.get() || !assignStmt.lval->type.get())
return std::any();
if (!assignStmt.lval.get() || !assignStmt.rval->type.get())
return std::any();
if (!tryAssignTo(assignStmt.rval, assignStmt.lval->type)) {
errors::put(assignStmt.error("assignment type mismatch"));
return std::any();
}
return std::any();
}
virtual std::any visit(RetStmt &retStmt, std::any param) override {
BaseASTVisitor::visit(retStmt, param);
// do not multiplicate errors
if (!retStmt.value.get() || !retStmt.value->type.get())
return std::any();
if (!currentReturnType.get())
return std::any();
if (!tryAssignTo(retStmt.value, currentReturnType)) {
errors::put(retStmt.error("return type mismatch"));
return std::any();
}
return std::any();
}
virtual std::any visit(IfStmt &ifStmt, std::any param) override {
BaseASTVisitor::visit(ifStmt, param);
// do not multiplicate errors
if (ifStmt.condition.get() && ifStmt.condition->type.get()) {
if (!utils::is<PrimitiveType>(ifStmt.condition->type.get())) {
errors::put(ifStmt.error("condition must be of primitive type"));
} else {
// cast condition to int (to make sure jnz succeeds)
castTo(ifStmt.condition, std::make_shared<PrimitiveType>("i32"));
}
}
return std::any();
}
virtual std::any visit(WhileStmt &whileStmt, std::any param) override {
BaseASTVisitor::visit(whileStmt, param);
// do not multiplicate errors
if (whileStmt.condition.get() && whileStmt.condition->type.get()) {
if (!utils::is<PrimitiveType>(whileStmt.condition->type.get())) {
errors::put(whileStmt.error("condition must be of primitive type"));
return std::any();
} else {
// cast condition to int (to make sure jnz succeeds)
castTo(whileStmt.condition, std::make_shared<PrimitiveType>("i32"));
}
}
return std::any();
}
virtual std::any visit(CallExpr &callExpr, std::any param) override {
BaseASTVisitor::visit(callExpr, param);
// do not multiplicate errors
if (!callExpr.callee.get() || !callExpr.callee->type.get())
return std::any();
if (!utils::is<FunctionType>(callExpr.callee->type.get())) {
errors::put(callExpr.error("callee must be a function"));
return std::any();
}
callExpr.type = callExpr.callee->type;
auto functionType = (FunctionType *)(callExpr.callee->type.get());
if (functionType->paramTypes.size() != callExpr.args.size()) {
errors::put(callExpr.error("wrong number of arguments"));
return std::any();
}
return std::any();
}
};
} // namespace
void performTypeAnalysis(std::unique_ptr<Module> &module) {
TypeAnalysisVisitor1 visitor1;
TypeAnalysisVisitor2 visitor2;
for (auto &stmt : module->stmts) {
stmt->accept(&visitor1, std::any());
}
for (auto &stmt : module->stmts) {
if (utils::is<FnDecl>(stmt.get()))
stmt->accept(&visitor2, std::any());
}
}
} // namespace plsm

7
compiler/src/Errors.cpp Normal file
View File

@ -0,0 +1,7 @@
#include "Errors.h"
static std::vector<std::string> _errors;
void plsm::errors::put(const std::string &error) { _errors.push_back(error); }
std::vector<std::string> plsm::errors::get() { return std::vector(_errors); }

View File

@ -1,46 +1,49 @@
#include "Parser.h"
#include "AST/AST.h"
#include "Errors.h"
#include "plsmBaseVisitor.h"
#include "plsmLexer.h"
#include "plsmParser.h"
namespace plsm {
namespace {
class MyAntlr4ErrorListener : public antlr4::BaseErrorListener {
std::string file;
std::string *error;
public:
MyAntlr4ErrorListener(const std::string &file, std::string *error)
: file(file), error(error) {}
MyAntlr4ErrorListener(const std::string &file) : file(file) {}
virtual void syntaxError(antlr4::Recognizer *recognizer,
antlr4::Token *offendingSymbol, size_t line,
size_t charPositionInLine, const std::string &msg,
std::exception_ptr e) override {
std::stringstream ss;
ss << file << ": line " << line << ":" << charPositionInLine << ": " << msg;
*error = ss.str();
ss << "In file " << file << ":" << line << ":" << charPositionInLine << "\n"
<< terminal::red << msg << terminal::reset;
errors::put(ss.str());
}
};
} // namespace
namespace plsm {
std::shared_ptr<ast::Module> parse(const std::string &file,
std::unique_ptr<ast::Module> parse(const std::string &file,
const std::string &input) {
auto istream = antlr4::ANTLRInputStream(input);
auto lexer = plsmLexer(&istream);
auto tokens = antlr4::CommonTokenStream(&lexer);
auto parser = plsmParser(&tokens);
parser.setFileName(file);
parser.setSourceText(input);
std::string error;
MyAntlr4ErrorListener listener(file, &error);
MyAntlr4ErrorListener listener(file);
parser.removeErrorListeners();
parser.addErrorListener(&listener);
auto tree = parser.module();
return std::shared_ptr<Module>(tree->ast);
return std::move(tree->ast);
}
} // namespace plsm

View File

@ -4,6 +4,7 @@
#include <sstream>
#include "Analysis.h"
#include "Errors.h"
#include "Parser.h"
static std::string readFile(const std::string &path) {
@ -25,21 +26,36 @@ int main(int argc, char *argv[]) {
// std::cout << input << std::endl;
int exitStatus = EXIT_SUCCESS;
try {
auto module = plsm::parse(argv[1], input);
std::cout << module->toJsonString() << std::endl;
// std::cout << module->toJsonString() << std::endl;
plsm::performNameAnalysis(module);
plsm::performTypeAnalysis(module);
// std::cout << "\n\n";
// std::cout << plsm::ast::Module::fromJson(module->toJson())->toJson() <<
// std::endl;
} catch (std::runtime_error &err) {
if (strlen(err.what()) > 0)
std::cerr << err.what() << std::endl;
exit(EXIT_FAILURE);
exitStatus = EXIT_FAILURE;
}
auto errors = plsm::errors::get();
for (size_t i = 0; i < errors.size(); i++) {
exitStatus = EXIT_FAILURE;
std::cerr << errors[i] << std::endl;
if (i != errors.size() - 1)
std::cerr << std::endl;
}
exit(exitStatus);
// auto module = Parser().parse(argv[1], readFile(argv[1]));
// auto fn = (ast::FnDef *)module->stmts.at(0);

View File

@ -1,142 +0,0 @@
{
"@type": "Module",
"name": "default",
"imports": [],
"stmts": [
{
"@type": "FnDecl",
"name": "main",
"params": [],
"returnTypeName": {
"@type": "PrimitiveTypeName",
"name": "i64"
},
"body": [
{
"@type": "VarDecl",
"name": "asdf",
"typeName": {
"@type": "PrimitiveTypeName",
"name": "int"
}
},
{
"@type": "AssignStmt",
"lval": {
"@type": "Identifier",
"name": "asdf"
},
"rval": 100
},
{
"@type": "IfStmt",
"condition": {
"@type": "BinExpr",
"op": ">",
"lhs": {
"@type": "Identifier",
"name": "asdf"
},
"rhs": 1000
},
"ifBody": [
{
"@type": "AssignStmt",
"lval": {
"@type": "Identifier",
"name": "a"
},
"rval": 1
}
],
"elseBody": [
{
"@type": "IfStmt",
"condition": {
"@type": "BinExpr",
"op": ">",
"lhs": {
"@type": "Identifier",
"name": "asdf"
},
"rhs": 500
},
"ifBody": [
{
"@type": "AssignStmt",
"lval": {
"@type": "Identifier",
"name": "a"
},
"rval": 2
}
],
"elseBody": [
{
"@type": "AssignStmt",
"lval": {
"@type": "Identifier",
"name": "a"
},
"rval": 3
}
]
}
]
},
{
"@type": "WhileStmt",
"condition": {
"@type": "BinExpr",
"op": "<",
"lhs": {
"@type": "Identifier",
"name": "a"
},
"rhs": 10
},
"body": [
{
"@type": "AssignStmt",
"lval": {
"@type": "Identifier",
"name": "a"
},
"rval": {
"@type": "Identifier",
"name": "a"
}
},
{
"@type": "ExprStmt",
"expr": {
"@type": "UnExpr",
"op": "+",
"expr": 1
}
}
]
},
{
"@type": "RetStmt",
"value": {
"@type": "BinExpr",
"op": "+",
"lhs": {
"@type": "BinExpr",
"op": "*",
"lhs": 3,
"rhs": 10
},
"rhs": {
"@type": "BinExpr",
"op": "*",
"lhs": 21,
"rhs": 2
}
}
}
]
}
]
}

View File

@ -1,6 +1,8 @@
fun main() i64 {
var asdf : int;
asdf = 100;
var asdf : i64;
fun main(arg0 i64) i8 {
var a : i64;
a = 10 + 2;
if (asdf > 1000) {
a = 1;
@ -10,9 +12,5 @@ fun main() i64 {
a = 3;
}
while (a < 10) {
a = a + 1;
}
ret 3 * 10 + 21.0 * 2;
ret 100;
}

4
examples/new1.plsm Normal file
View File

@ -0,0 +1,4 @@
fun main() i64 {
var a : int;
ret a;
}