Implement classof in derived expressions

This commit is contained in:
Sameer Rahmani 2021-03-31 19:37:32 +01:00
parent 3a899d82b3
commit f6ca246f0d
16 changed files with 365 additions and 59 deletions

7
.gitignore vendored
View File

@ -16,3 +16,10 @@ _deps
.clangd
.cache/
.vscode/
CMakeDoxyfile.in
CMakeDoxygenDefaults.cmake
DartConfiguration.tcl
bin/serenec_CXX_cotire.cmake
/config.h
docs/Doxyfile.docs

View File

@ -1,2 +1,4 @@
(print 4)
(print -43)
(print 3.4)
(println asd)

View File

@ -40,7 +40,7 @@ public:
const std::string &message() const;
ExprId id() const override { return error; }
SereneType getType() const override { return SereneType::Error; }
std::string string_repr() const override;
std::string dumpAST() const override;
};

View File

@ -37,8 +37,13 @@
namespace serene {
// TODO: Rename this enum and move it to a namespace
enum ExprId : unsigned char { aexpr = 0, symbol, list, def, error };
enum class SereneType {
Expression,
Symbol,
List,
Error,
Number,
};
class AExpr {
public:
@ -46,7 +51,7 @@ public:
virtual ~AExpr() = default;
virtual ExprId id() const = 0;
virtual SereneType getType() const = 0;
virtual std::string string_repr() const = 0;
virtual std::string dumpAST() const = 0;
};

View File

@ -35,22 +35,24 @@
namespace serene {
class List : public AExpr {
std::list<ast_node> nodes_;
std::vector<ast_node> nodes_;
public:
List(){};
List(std::vector<ast_node> elements);
List(reader::Location start);
ExprId id() const override { return list; }
SereneType getType() const override { return SereneType::List; }
std::string dumpAST() const override;
std::string string_repr() const override;
size_t length() const;
void cons(ast_node f);
size_t count() const;
void append(ast_node t);
std::unique_ptr<List> from(uint begin);
llvm::Optional<ast_node> at(uint index) const;
static bool classof(const AExpr *);
};
std::unique_ptr<List> makeList(reader::Location);

58
include/serene/number.hpp Normal file
View File

@ -0,0 +1,58 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef NUMBER_H
#define NUMBER_H
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/reader/location.hpp"
#include "serene/state.hpp"
#include <string>
namespace serene {
class Number : public AExpr {
const std::string num_;
public:
bool isNeg;
bool isFloat;
Number(reader::LocationRange loc, const std::string &, bool, bool);
~Number();
SereneType getType() const override { return SereneType::Number; }
std::string string_repr() const override;
std::string dumpAST() const override;
int64_t toI64();
static bool classof(const AExpr *);
};
std::unique_ptr<Number> makeNumber(reader::LocationRange, std::string, bool,
bool);
} // namespace serene
#endif

View File

@ -64,16 +64,16 @@ private:
std::stringstream input_stream;
Location current_location{0, 0, 0};
char get_char(bool skip_whitespace);
void unget_char();
bool is_valid_for_identifier(char c);
char getChar(bool skip_whitespace);
void ungetChar();
bool isValidForIdentifier(char c);
// The property to store the ast tree
ast_tree ast;
ast_node read_symbol();
ast_list_node read_list();
ast_node read_expr();
ast_node readSymbol();
ast_node readNumber(bool);
ast_list_node readList();
ast_node readExpr();
public:
Reader() : input_stream(""){};

View File

@ -28,7 +28,10 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/expr.hpp"
#include "serene/list.hpp"
#include "serene/namespace.hpp"
#include "serene/number.hpp"
#include "serene/symbol.hpp"
namespace serene {
namespace sir {
@ -36,11 +39,16 @@ namespace sir {
class Generator {
private:
::mlir::OpBuilder builder;
::serene::Namespace &ns;
public:
Generator(mlir::MLIRContext &context) : builder(&context) {}
Generator(mlir::MLIRContext &context, ::serene::Namespace &ns)
: builder(&context), ns(ns) {}
mlir::ModuleOp generate(::serene::Namespace &ns);
mlir::Operation *generateNumber(Number *);
mlir::Operation *generateExpression(AExpr *);
mlir::Operation *generateList(List *);
mlir::ModuleOp generate();
~Generator();
};

View File

@ -41,9 +41,11 @@ public:
const std::string &name() const;
ExprId id() const override { return symbol; }
SereneType getType() const override { return SereneType::Symbol; }
std::string string_repr() const override;
std::string dumpAST() const override;
static bool classof(const AExpr *);
};
std::unique_ptr<Symbol> makeSymbol(reader::LocationRange, std::string);

View File

@ -1,6 +1,11 @@
set(HEADER_LIST
"${INCLUDE_DIR}/serene/expr.hpp"
"${INCLUDE_DIR}/serene/serene.hpp"
"${INCLUDE_DIR}/serene/number.hpp"
"${INCLUDE_DIR}/serene/symbol.hpp"
"${INCLUDE_DIR}/serene/list.hpp"
"${INCLUDE_DIR}/serene/error.hpp"
"${INCLUDE_DIR}/serene/state.hpp"
# Reader
"${INCLUDE_DIR}/serene/reader/reader.hpp"
@ -19,6 +24,8 @@ add_library(serene
list.cpp
namespace.cpp
state.cpp
error.cpp
number.cpp
# Reader
reader/reader.cpp

View File

@ -39,18 +39,21 @@ List::List(reader::Location startLoc) {
this->location.reset(new reader::LocationRange(startLoc));
}
List::List(std::vector<ast_node> elements) {
auto startLoc = elements[0]->location->start;
auto endLoc = elements[elements.size() - 1]->location->end;
this->location.reset(new reader::LocationRange(startLoc, endLoc));
this->nodes_ = elements;
}
llvm::Optional<ast_node> List::at(uint index) const {
if (index >= nodes_.size()) {
return llvm::None;
}
auto itr = cbegin(nodes_);
std::advance(itr, index);
return llvm::Optional<ast_node>(*itr);
return llvm::Optional<ast_node>(this->nodes_[index]);
}
void List::cons(ast_node node) { nodes_.push_front(std::move(node)); }
void List::append(ast_node node) { nodes_.push_back(std::move(node)); }
std::string List::string_repr() const {
@ -76,7 +79,35 @@ std::string List::dumpAST() const {
this->location->end.toString(), s);
}
inline size_t List::length() const { return nodes_.size(); }
/**
* Return a sub set of elements starting from the `begin` index to the end
* and an empty list otherwise.
*/
std::unique_ptr<List> List::from(uint begin) {
if (this->count() - begin < 1) {
return makeList(this->location->end);
}
std::vector<ast_node>::const_iterator first = this->nodes_.begin() + begin;
std::vector<ast_node>::const_iterator last = this->nodes_.end();
fmt::print("#### {} {} \n", this->nodes_.size(), this->nodes_.max_size());
fmt::print("MM {}\n", this->string_repr());
std::vector<ast_node> newCopy(first, last);
return std::make_unique<List>(newCopy);
};
size_t List::count() const { return nodes_.size(); }
/**
* `classof` is a enabler static method that belongs to the LLVM RTTI interface
* `llvm::isa`, `llvm::cast` and `llvm::dyn_cast` use this method.
*/
bool List::classof(const AExpr *expr) {
return expr->getType() == SereneType::List;
}
/**
* Make an empty List in starts at the given location `loc`.

71
src/number.cpp Normal file
View File

@ -0,0 +1,71 @@
/**
* Serene programming language.
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "serene/number.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/state.hpp"
#include <assert.h>
#include <fmt/core.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Type.h>
#include <string>
namespace serene {
std::string Number::string_repr() const { return num_; }
std::string Number::dumpAST() const {
return fmt::format("<Number [loc: {} | {}]: {}>",
this->location->start.toString(),
this->location->end.toString(), this->num_);
}
Number::Number(reader::LocationRange loc, const std::string &num, bool isNeg,
bool isFloat)
: num_(num), isNeg(isNeg), isFloat(isFloat) {
this->location.reset(new reader::LocationRange(loc));
}
int64_t Number::toI64() {
// TODO: Handle float case as well
return std::stoi(num_);
};
/**
* `classof` is a enabler static method that belongs to the LLVM RTTI interface
* `llvm::isa`, `llvm::cast` and `llvm::dyn_cast` use this method.
*/
bool Number::classof(const AExpr *expr) {
return expr->getType() == SereneType::Number;
}
Number::~Number() { EXPR_LOG("Destroying number"); }
std::unique_ptr<Number> makeNumber(reader::LocationRange loc, std::string num,
bool isNeg, bool isFloat) {
return std::make_unique<Number>(loc, num, isNeg, isFloat);
}
} // namespace serene

View File

@ -25,6 +25,7 @@
#include "serene/reader/reader.hpp"
#include "serene/error.hpp"
#include "serene/list.hpp"
#include "serene/number.hpp"
#include "serene/symbol.hpp"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
@ -55,7 +56,7 @@ Reader::~Reader() { READER_LOG("Destroying the reader"); }
* Return the next character in the buffer.
* @param skip_whitespace If true it will skip whitespaces and EOL chars
*/
char Reader::get_char(bool skip_whitespace) {
char Reader::getChar(bool skip_whitespace) {
for (;;) {
char c = input_stream.get();
@ -71,16 +72,32 @@ char Reader::get_char(bool skip_whitespace) {
}
};
void Reader::unget_char() {
void Reader::ungetChar() {
input_stream.unget();
// The char that we just unget
dec_location(current_location, this->current_char == '\n');
};
bool Reader::is_valid_for_identifier(char c) {
bool Reader::isValidForIdentifier(char c) {
switch (c) {
case '!' | '$' | '%' | '&' | '*' | '+' | '-' | '.' | '~' | '/' | ':' | '<' |
'=' | '>' | '?' | '@' | '^' | '_':
case '!':
case '$':
case '%':
case '&':
case '*':
case '+':
case '-':
case '.':
case '~':
case '/':
case ':':
case '<':
case '=':
case '>':
case '?':
case '@':
case '^':
case '_':
return true;
}
@ -91,31 +108,82 @@ bool Reader::is_valid_for_identifier(char c) {
return false;
}
ast_node Reader::read_symbol() {
ast_node Reader::readNumber(bool neg) {
std::string number(neg ? "-" : "");
bool floatNum = false;
bool empty = false;
LocationRange loc;
char c = getChar(false);
loc.start = current_location;
while (c != EOF &&
((!(isspace(c)) && ((c >= '0' && c <= '9') | (c == '.'))))) {
if (c == '.' && floatNum == true) {
llvm::errs() << "Two float points in a number?\n";
// TODO: Return a proper error
return nullptr;
}
if (c == '.') {
floatNum = true;
}
number += c;
c = getChar(false);
empty = false;
}
if (!empty) {
ungetChar();
loc.end = current_location;
return makeNumber(loc, number, neg, floatNum);
}
return nullptr;
};
ast_node Reader::readSymbol() {
bool empty = true;
char c = get_char(false);
char c = getChar(false);
READER_LOG("Reading symbol");
if (!this->is_valid_for_identifier(c)) {
if (!this->isValidForIdentifier(c)) {
// TODO: Replece this with a tranceback function or something to raise
// synatx error.
fmt::print("Invalid character at the start of a symbol: '{}'\n", c);
// fmt::print("Invalid character at the start of a symbol: '{}'\n", c);
llvm::errs() << fmt::format(
"Invalid character at the start of a symbol: '{}'\n", c);
exit(1);
}
if (c == '-') {
char next = getChar(false);
if (next >= '0' && next <= '9') {
ungetChar();
return readNumber(true);
}
}
if (c >= '0' && c <= '9') {
ungetChar();
return readNumber(false);
}
std::string sym("");
LocationRange loc;
loc.start = current_location;
while (c != EOF && ((!(isspace(c)) && this->is_valid_for_identifier(c)))) {
while (c != EOF && ((!(isspace(c)) && this->isValidForIdentifier(c)))) {
sym += c;
c = get_char(false);
c = getChar(false);
empty = false;
}
if (!empty) {
unget_char();
ungetChar();
loc.end = current_location;
return makeSymbol(loc, sym);
}
@ -123,17 +191,18 @@ ast_node Reader::read_symbol() {
// TODO: it should never happens
return nullptr;
};
// std::unique_ptr<List> list
ast_list_node Reader::read_list() {
ast_list_node Reader::readList() {
auto list = makeList(current_location);
char c = get_char(true);
char c = getChar(true);
assert(c == '(');
bool list_terminated = false;
do {
char c = get_char(true);
char c = getChar(true);
switch (c) {
case EOF:
@ -145,8 +214,8 @@ ast_list_node Reader::read_list() {
break;
default:
unget_char();
list->append(read_expr());
ungetChar();
list->append(readExpr());
}
} while (!list_terminated);
@ -154,35 +223,35 @@ ast_list_node Reader::read_list() {
return list;
}
ast_node Reader::read_expr() {
char c = get_char(false);
ast_node Reader::readExpr() {
char c = getChar(false);
READER_LOG("CHAR: {}", c);
unget_char();
ungetChar();
switch (c) {
case '(': {
return read_list();
return readList();
}
case EOF:
return nullptr;
default:
return read_symbol();
return readSymbol();
}
}
std::unique_ptr<ast_tree> Reader::read() {
char c = get_char(true);
char c = getChar(true);
while (c != EOF) {
unget_char();
auto tmp{read_expr()};
ungetChar();
auto tmp{readExpr()};
if (tmp) {
this->ast.push_back(move(tmp));
}
c = get_char(true);
c = getChar(true);
}
return std::make_unique<ast_tree>(this->ast);

View File

@ -32,17 +32,53 @@
namespace serene {
namespace sir {
mlir::ModuleOp Generator::generate(::serene::Namespace &ns) {
mlir::ModuleOp Generator::generate() {
auto module = mlir::ModuleOp::create(builder.getUnknownLoc());
// for (auto &x : ns.Tree()) {
// this->generate(x);
// }
module.push_back(
builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)3));
for (auto x : ns.Tree()) {
module.push_back(generateExpression(x.get()));
}
return module;
};
mlir::Operation *Generator::generateExpression(AExpr *x) {
switch (x->getType()) {
case SereneType::Number: {
return generateNumber(llvm::cast<Number>(x));
}
case SereneType::List: {
return generateList(llvm::cast<List>(x));
}
default: {
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)3);
}
}
};
mlir::Operation *Generator::generateList(List *l) {
auto first = l->at(0);
if (!first) {
// Empty list.
// TODO: Return Nil or empty list.
// Just for now.
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)0);
}
// for (auto x : l->from(1)) {
// generateExpression(x);
// }
return builder.create<ValueOp>(builder.getUnknownLoc(), (uint64_t)0);
};
mlir::Operation *Generator::generateNumber(Number *x) {
return builder.create<ValueOp>(builder.getUnknownLoc(), x->toI64());
};
Generator::~Generator(){};
} // namespace sir

View File

@ -33,9 +33,9 @@ namespace sir {
SIR::SIR() { context.getOrLoadDialect<::serene::sir::SereneDialect>(); }
mlir::OwningModuleRef SIR::generate(::serene::Namespace &ns) {
Generator g{context};
Generator g{context, ns};
return g.generate(ns);
return g.generate();
};
SIR::~SIR() {}

View File

@ -52,6 +52,14 @@ Symbol::Symbol(reader::LocationRange loc, const string &name) : name_(name) {
this->location.reset(new reader::LocationRange(loc));
}
/**
* `classof` is a enabler static method that belongs to the LLVM RTTI interface
* `llvm::isa`, `llvm::cast` and `llvm::dyn_cast` use this method.
*/
bool Symbol::classof(const AExpr *expr) {
return expr->getType() == SereneType::Symbol;
}
Symbol::~Symbol() { EXPR_LOG("Destroying symbol"); }
std::unique_ptr<Symbol> makeSymbol(reader::LocationRange loc,