Finalize migration to new expression interface

This commit is contained in:
Sameer Rahmani 2021-04-11 00:02:56 +01:00
parent e4b0823e49
commit 555e770c01
28 changed files with 561 additions and 216 deletions

View File

@ -60,7 +60,13 @@ int main(int argc, char *argv[]) {
case Action::DumpIR: {
reader::FileReader *r = new reader::FileReader(inputFile);
serene::sir::dumpSIR(*r->read());
auto ast = r->read();
if (!ast) {
throw ast.takeError();
}
serene::sir::dumpSIR(*ast);
delete r;
return 0;
}

31
include/serene/errors.h Normal file
View File

@ -0,0 +1,31 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 SERENE_ERRORS_H
#define SERENE_ERRORS_H
#include "serene/errors/errc.h"
#include "serene/errors/error.h"
#endif

View File

@ -0,0 +1,83 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 SERENE_ERRORS_ERRC_H
#define SERENE_ERRORS_ERRC_H
#include "llvm/Support/Errc.h"
namespace serene {
/// A collection of common error codes in Serene
enum class errc {
argument_list_too_long = int(std::errc::argument_list_too_long),
argument_out_of_domain = int(std::errc::argument_out_of_domain),
bad_address = int(std::errc::bad_address),
bad_file_descriptor = int(std::errc::bad_file_descriptor),
broken_pipe = int(std::errc::broken_pipe),
device_or_resource_busy = int(std::errc::device_or_resource_busy),
directory_not_empty = int(std::errc::directory_not_empty),
executable_format_error = int(std::errc::executable_format_error),
file_exists = int(std::errc::file_exists),
file_too_large = int(std::errc::file_too_large),
filename_too_long = int(std::errc::filename_too_long),
function_not_supported = int(std::errc::function_not_supported),
illegal_byte_sequence = int(std::errc::illegal_byte_sequence),
inappropriate_io_control_operation =
int(std::errc::inappropriate_io_control_operation),
interrupted = int(std::errc::interrupted),
invalid_argument = int(std::errc::invalid_argument),
invalid_seek = int(std::errc::invalid_seek),
io_error = int(std::errc::io_error),
is_a_directory = int(std::errc::is_a_directory),
no_child_process = int(std::errc::no_child_process),
no_lock_available = int(std::errc::no_lock_available),
no_space_on_device = int(std::errc::no_space_on_device),
no_such_device_or_address = int(std::errc::no_such_device_or_address),
no_such_device = int(std::errc::no_such_device),
no_such_file_or_directory = int(std::errc::no_such_file_or_directory),
no_such_process = int(std::errc::no_such_process),
not_a_directory = int(std::errc::not_a_directory),
not_enough_memory = int(std::errc::not_enough_memory),
not_supported = int(std::errc::not_supported),
operation_not_permitted = int(std::errc::operation_not_permitted),
permission_denied = int(std::errc::permission_denied),
read_only_file_system = int(std::errc::read_only_file_system),
resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur),
resource_unavailable_try_again =
int(std::errc::resource_unavailable_try_again),
result_out_of_range = int(std::errc::result_out_of_range),
too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system),
too_many_files_open = int(std::errc::too_many_files_open),
too_many_links = int(std::errc::too_many_links)
};
/// The **official way** to create `std::error_code` in context of Serene.
inline std::error_code make_error_code(errc E) {
return std::error_code(static_cast<int>(E), std::generic_category());
};
}; // namespace serene
#endif

View File

@ -0,0 +1,30 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 SERENE_ERRORS_ERROR_H
#define SERENE_ERRORS_ERROR_H
#include "llvm/Support/Error.h"
#endif

View File

@ -30,136 +30,67 @@
namespace serene {
/// Contains all the builtin expressions including those which do not appear in
/// the syntax directly. Like function definitions.
/// Contains all the builtin AST expressions including those which do not appear
/// in the syntax directly. Like function definitions.
namespace exprs {
/// This enum represent the expression type and **not** the value type.
enum class ExprType {
Symbol,
List,
Number,
};
/// The polymorphic type that works as the entry point to the exprs system.
/// Each expression has to define the interface of the `ExpressionConcept`
/// class as generic functions. **REMEMBER TO NOT INHERIT FROM THESE CLASSES**
/// The base class of the expressions which provides the common interface for
/// the expressions to implement.
class Expression {
public:
/// The location range provide information regarding to where in the input
/// string the current expression is used.
reader::LocationRange location;
Expression(const reader::LocationRange &loc) : location(loc){};
virtual ~Expression() = default;
/// Returns the type of the expression. We need this funciton to perform
/// dynamic casting of expression object to implementations such as lisp or
/// symbol.
virtual ExprType getType() const = 0;
/// The AST representation of an expression
virtual std::string toString() const = 0;
};
using node = std::shared_ptr<Expression>;
using ast = llvm::SmallVector<node, 0>;
/// Create a new Expression of type `T` and forwards any given parameter
/// Create a new `node` of type `T` and forwards any given parameter
/// to the constructor of type `T`. This is the **official way** to create
/// a new `Expression`. Here is an example:
/// \code
/// auto list = Expression::make<List>();
/// auto list = make<List>();
/// \endcode
///
/// \param loc A `serene::reader::LocationRange` instance to point to exact
/// location of the expression in the input string.
/// \param[args] Any argument with any type passed to this function will be
/// passed to the constructor of type T.
/// \return A new expression containing a value of type T and act as tyep T.
// template <typename T, typename... Args> std::shared_ptr<T> make(Args
// &&...args);
template <typename T, typename... Args>
std::shared_ptr<T> make(Args &&...args) {
/// \return A shared pointer to an Expression
template <typename T, typename... Args> node make(Args &&...args) {
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
};
using node = std::shared_ptr<Expression>;
using ast = llvm::SmallVector<node, 0>;
// /// Creates a new expression by moving the given object of the type T into
// /// a new internal container.
// ///
// /// \param e and expression of type T
// template <typename T> Expression(T e) : self(new Impl<T>(std::move(e))){};
// /// The copy constructor which actually just move the other expression into
// /// a new implementation container.
// ///
// /// \param e is the other expression to copy from
// Expression(const Expression &e) : self(e.self->copy_()){}; // Copy ctor
// Expression(Expression &&e) noexcept = default; // Move ctor
// Expression &operator=(const Expression &e);
// Expression &operator=(Expression &&e) noexcept = default;
// /// Returns the type of the expression. More precisely, It returns the type
// /// of the expression that it contains.
// ///
// /// \return The type of expression.
// ExprType getType();
// /// Return the string representation of the expression in the context
// /// of the AST. Think of it as dump of the AST for each expression.
// ///
// /// \return the exoression in string format.
// std::string toString();
// /// Create a new Expression of type `T` and forwards any given parameter
// /// to the constructor of type `T`. This is the **official way** to create
// /// a new `Expression`. Here is an example:
// /// \code
// /// auto list = Expression::make<List>();
// /// \endcode
// ///
// /// \param loc A `serene::reader::LocationRange` instance to point to exact
// /// location of the expression in the input string.
// /// \param[args] Any argument with any type passed to this function will be
// /// passed to the constructor of type T.
// /// \return A new expression containing a value of type T and act as tyep T.
// template <typename T, typename... Args>
// static Expression make(Args &&...args) {
// return Expression(T(std::forward<Args>(args)...));
// };
// template <typename T> std::unique_ptr<T> *to();
// // template <typename T> static Expression make(reader::LocationRange &&loc)
// {
// // Expression e(T(std::forward<reader::LocationRange>(loc)));
// // return e;
// // };
// /// The generic interface which each type of expression has to implement
// /// in order to act like an `Expression`
// class ExpressionConcept {
// public:
// virtual ~ExpressionConcept() = default;
// virtual ExpressionConcept *copy_() const = 0;
// /// Return the type of the expression
// virtual ExprType getType() = 0;
// /// Return the string representation of the expression in the context
// /// of the AST. Think of it as dump of the AST for each expression
// virtual std::string toString() = 0;
// };
// /// The generic implementation of `ExpressionConcept` which acts as the
// /// dispatcher on type.
// template <typename T> struct Impl : ExpressionConcept {
// Impl(T e) : expr(std::move(e)){};
// ExpressionConcept *copy_() const { return new Impl(*this); }
// /// In order to make llvm's RTTI to work we need this method.
// ExprType getType() const { return expr.getType(); }
// std::string toString() { return expr.toString(); }
// T expr;
// };
// /// The internal container to keep the object implementing the
// /// `ExpressionConcept`. This might be a `List` for example or a `Symbol`.
// std::unique_ptr<ExpressionConcept> self;
/// Create a new `node` of type `T` and forwards any given parameter
/// to the constructor of type `T`. This is the **official way** to create
/// a new `Expression`. Here is an example:
/// \code
/// auto list = make<List>();
/// \endcode
///
/// \param[args] Any argument with any type passed to this function will be
/// passed to the constructor of type T.
/// \return A shared pointer to a value of type T.
template <typename T, typename... Args>
std::shared_ptr<T> makeAndCast(Args &&...args) {
return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
};
} // namespace exprs
} // namespace serene

View File

@ -33,8 +33,12 @@ namespace serene {
namespace exprs {
/// This class represents a List in the AST level and not the List as the data
/// type.
class List : public Expression {
public:
// Internal elements of the lest (small vector of shared pointers to
// expressions)
ast elements;
List(const List &l); // Copy ctor
@ -47,6 +51,8 @@ public:
ExprType getType() const;
std::string toString() const;
void append(node);
static bool classof(const Expression *e);
~List() = default;

View File

@ -0,0 +1,59 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 EXPRS_NUMBER_H
#define EXPRS_NUMBER_H
#include "serene/exprs/expression.h"
namespace serene {
namespace exprs {
/// This data structure represent the Lisp symbol. Just a symbol
/// in the context of the AST and nothing else.
struct Number : public Expression {
std::string value;
bool isNeg;
bool isFloat;
Number(reader::LocationRange &loc, const std::string &num, bool isNeg,
bool isFloat)
: Expression(loc), value(num), isNeg(isNeg), isFloat(isFloat){};
ExprType getType() const;
std::string toString() const;
int64_t toI64();
static bool classof(const Expression *e);
~Number() = default;
};
} // namespace exprs
} // namespace serene
#endif

View File

@ -33,6 +33,8 @@ namespace serene {
namespace exprs {
/// This data structure represent the Lisp symbol. Just a symbol
/// in the context of the AST and nothing else.
struct Symbol : public Expression {
std::string name;

View File

@ -27,18 +27,15 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Value.h"
#include "serene/expr.hpp"
#include "serene/exprs/expression.h"
#include "serene/llvm/IR/Value.h"
#include "serene/logger.hpp"
#include "llvm/ADT/DenseMap.h"
#include <llvm/IR/Module.h>
#include <string>
#if defined(ENABLE_LOG) || defined(ENABLE_NAMESPACE_LOG)
#define NAMESPACE_LOG(...) __LOG("NAMESPACE", __VA_ARGS__);
#else
#define NAMESPACE_LOG(...) ;
#endif
#define NAMESPACE_LOG(...) \
DEBUG_WITH_TYPE("NAMESPACE", llvm::dbgs() << __VA_ARGS__ << "\n");
using ScopeMap = llvm::DenseMap<llvm::StringRef, mlir::Value>;
using PairT = std::pair<llvm::StringRef, mlir::Value>;
@ -48,7 +45,7 @@ class AExpr;
class Namespace {
private:
ast_tree tree{};
exprs::ast tree{};
bool initialized = false;
ScopeMap rootScope;
@ -59,8 +56,8 @@ public:
Namespace(llvm::StringRef ns_name, llvm::Optional<llvm::StringRef> filename);
ast_tree &Tree();
mlir::LogicalResult setTree(ast_tree);
exprs::ast &Tree();
mlir::LogicalResult setTree(exprs::ast &);
// TODO: Fix it to return llvm::Optional<mlir::Value> instead
llvm::Optional<mlir::Value> lookup(llvm::StringRef name);
mlir::LogicalResult insert_symbol(llvm::StringRef name, mlir::Value v);

View File

@ -0,0 +1,64 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 SERENE_READER_ERRORS_H
#define SERENE_READER_ERRORS_H
#include "serene/errors.h"
namespace serene {
namespace reader {
class ReadError : public std::exception {
private:
char *message;
public:
ReadError(char *msg) : message(msg){};
const char *what() const throw() { return message; }
};
class MissingFileError : public llvm::ErrorInfo<MissingFileError> {
using llvm::ErrorInfo<MissingFileError>::log;
using llvm::ErrorInfo<MissingFileError>::convertToErrorCode;
public:
static char ID;
std::string path;
// TODO: Move this to an error namespace somewhere.
int file_is_missing = int();
void log(llvm::raw_ostream &os) const {
os << "File does not exist: " << path << "\n";
}
MissingFileError(llvm::StringRef path) : path(path.str()){};
std::error_code convertToErrorCode() const {
return make_error_code(errc::no_such_file_or_directory);
}
};
} // namespace reader
} // namespace serene
#endif

View File

@ -29,15 +29,19 @@
#include <sstream>
#include <stdexcept>
#include <string>
#include <system_error>
#include <vector>
#include "serene/expr.hpp"
#include "serene/list.hpp"
#include "serene/errors.h"
#include "serene/exprs/expression.h"
#include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
#include "serene/logger.hpp"
#include "serene/reader/errors.h"
#include "serene/reader/location.h"
#include "serene/serene.h"
#include "serene/symbol.hpp"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#define READER_LOG(...) \
DEBUG_WITH_TYPE("READER", llvm::dbgs() << __VA_ARGS__ << "\n");
@ -45,15 +49,6 @@
namespace serene {
namespace reader {
class ReadError : public std::exception {
private:
char *message;
public:
ReadError(char *msg) : message(msg){};
const char *what() const throw() { return message; }
};
class Reader {
private:
char current_char = ';'; // Some arbitary char to begin with
@ -65,19 +60,19 @@ private:
bool isValidForIdentifier(char c);
// The property to store the ast tree
ast_tree ast;
ast_node readSymbol();
ast_node readNumber(bool);
ast_list_node readList();
ast_node readExpr();
exprs::ast ast;
exprs::node readSymbol();
exprs::node readNumber(bool);
exprs::node readList();
exprs::node readExpr();
public:
Reader() : input_stream(""){};
Reader(const std::string);
Reader(const llvm::StringRef string);
void setInput(const std::string);
void setInput(const llvm::StringRef string);
std::unique_ptr<ast_tree> read();
llvm::Expected<exprs::ast> read();
// Dumps the AST data to stdout
void dumpAST();
@ -95,7 +90,7 @@ public:
// Dumps the AST data to stdout
void dumpAST();
std::unique_ptr<ast_tree> read();
llvm::Expected<exprs::ast> read();
~FileReader();
};

View File

@ -30,7 +30,7 @@
#include "mlir/IR/MLIRContext.h"
#include "serene/expr.hpp"
#include "serene/list.hpp"
#include "serene/namespace.hpp"
#include "serene/namespace.h"
#include "serene/number.hpp"
#include "serene/symbol.hpp"
#include "llvm/ADT/ScopedHashTable.h"

View File

@ -26,7 +26,7 @@
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/MLIRContext.h"
#include "serene/expr.hpp"
#include "serene/exprs/expression.h"
#include "serene/sir/generator.hpp"
#include <memory>
@ -41,12 +41,12 @@ private:
public:
SIR();
mlir::OwningModuleRef generate(::serene::Namespace *ns);
mlir::OwningModuleRef generate(serene::Namespace *ns);
~SIR();
};
void dumpSIR(ast_tree &t);
void dumpSIR(exprs::ast &t);
} // namespace sir
} // namespace serene

View File

@ -27,7 +27,7 @@
#include "serene/llvm/IR/Value.h"
#include "serene/logger.hpp"
//#include "serene/namespace.hpp"
//#include "serene/namespace.h"
#include <llvm/IR/Module.h>
#include <string>

View File

@ -4,10 +4,16 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/exprs/expression.h"
"${INCLUDE_DIR}/serene/exprs/symbol.h"
"${INCLUDE_DIR}/serene/exprs/list.h"
"${INCLUDE_DIR}/serene/exprs/number.h"
# Reader
"${INCLUDE_DIR}/serene/reader/reader.h"
"${INCLUDE_DIR}/serene/reader/location.h"
"${INCLUDE_DIR}/serene/reader/errors.h"
"${INCLUDE_DIR}/serene/errors.h"
"${INCLUDE_DIR}/serene/errors/error.h"
"${INCLUDE_DIR}/serene/errors/errc.h"
"${INCLUDE_DIR}/serene/expr.hpp"
@ -23,13 +29,15 @@ set(HEADER_LIST
"${INCLUDE_DIR}/serene/sir/sir.hpp"
"${INCLUDE_DIR}/serene/sir/dialect.hpp"
"${INCLUDE_DIR}/serene/sir/generator.hpp"
"${INCLUDE_DIR}/serene/namespace.hpp")
"${INCLUDE_DIR}/serene/namespace.h")
# Make an automatic library - will be static or dynamic based on user setting
add_library(serene
exprs/expression.cpp
exprs/symbol.cpp
exprs/list.cpp
exprs/number.cpp
serene.cpp
symbol.cpp
@ -42,6 +50,7 @@ add_library(serene
# Reader
reader/reader.cpp
reader/location.cpp
reader/errors.cpp
# IR
sir/sir.cpp

View File

@ -25,7 +25,7 @@
#include "serene/error.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/namespace.h"
#include "serene/state.hpp"
#include <assert.h>
#include <fmt/core.h>

View File

@ -53,5 +53,6 @@ bool List::classof(const Expression *e) {
return e->getType() == ExprType::List;
};
void List::append(node n) { elements.push_back(n); }
} // namespace exprs
} // namespace serene

50
src/exprs/number.cpp Normal file
View File

@ -0,0 +1,50 @@
/*
* Serene programming language.
*
* Copyright (c) 2019-2021 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/exprs/number.h"
#include "llvm/Support/FormatVariadic.h"
namespace serene {
namespace exprs {
int64_t Number::toI64() {
// TODO: Handle float case as well
// TODO: Cache the value
return std::stoi(value);
};
ExprType Number::getType() const { return ExprType::Number; };
std::string Number::toString() const {
return llvm::formatv("<Symbol [loc: {0} | {1}]: {2}>",
this->location.start.toString(),
this->location.end.toString(), this->value);
}
bool Number::classof(const Expression *e) {
return e->getType() == ExprType::Number;
};
} // namespace exprs
} // namespace serene

View File

@ -28,7 +28,6 @@
namespace serene {
namespace exprs {
ExprType Symbol::getType() const { return ExprType::Symbol; };
std::string Symbol::toString() const {
@ -37,7 +36,7 @@ std::string Symbol::toString() const {
this->location.end.toString(), this->name);
}
bool Symbol::classof(const Expression *e) {
bool Symbol::classof(const Expression *e) {
return e->getType() == ExprType::List;
};

View File

@ -22,8 +22,8 @@
* SOFTWARE.
*/
#include "serene/namespace.hpp"
#include "serene/expr.hpp"
#include "serene/namespace.h"
#include "serene/exprs/expression.h"
#include "serene/llvm/IR/Value.h"
#include "llvm/ADT/StringRef.h"
#include <fmt/core.h>
@ -41,7 +41,7 @@ Namespace::Namespace(llvm::StringRef ns_name,
this->name = ns_name;
};
ast_tree &Namespace::Tree() { return this->tree; }
exprs::ast &Namespace::Tree() { return this->tree; }
llvm::Optional<mlir::Value> Namespace::lookup(llvm::StringRef name) {
if (auto value = rootScope.lookup(name)) {
@ -51,7 +51,7 @@ llvm::Optional<mlir::Value> Namespace::lookup(llvm::StringRef name) {
return llvm::None;
};
mlir::LogicalResult Namespace::setTree(ast_tree t) {
mlir::LogicalResult Namespace::setTree(exprs::ast &t) {
if (initialized) {
return mlir::failure();
}

View File

@ -25,7 +25,7 @@
#include "serene/number.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/namespace.h"
#include "serene/state.hpp"
#include <assert.h>
#include <fmt/core.h>

32
src/reader/errors.cpp Normal file
View File

@ -0,0 +1,32 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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/reader/errors.h"
namespace serene {
namespace reader {
/// This one should be here, llvm's rules
char MissingFileError::ID;
}; // namespace reader
}; // namespace serene

View File

@ -24,49 +24,48 @@
#include "serene/reader/reader.h"
#include "serene/error.hpp"
#include "serene/list.hpp"
#include "serene/number.hpp"
#include "serene/symbol.hpp"
#include "serene/exprs/list.h"
#include "serene/exprs/number.h"
#include "serene/exprs/symbol.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MemoryBuffer.h"
#include <assert.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
using namespace std;
namespace serene {
namespace reader {
Reader::Reader(const string input) { this->setInput(input); };
/**
* Set the input of the reader.
* @param input Set the input to the given string
*/
void Reader::setInput(const string input) {
input_stream.write(input.c_str(), input.size());
Reader::Reader(const llvm::StringRef input) { this->setInput(input); };
/// Set the input of the reader.
///\param input Set the input to the given string
void Reader::setInput(const llvm::StringRef input) {
input_stream.write(input.str().c_str(), input.size());
};
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
*/
/// Return the next character in the buffer and moves the location.
///\param skip_whitespace If true it will skip whitespaces and EOL chars
/// \return next char in the buffer.
char Reader::getChar(bool skip_whitespace) {
for (;;) {
char c = input_stream.get();
this->current_char = c;
// TODO: Handle the end of line with respect to the OS.
// increase the current position in the buffer with respect to the end
// of line.
inc_location(current_location, c == '\n');
if (skip_whitespace == true && isspace(c)) {
continue;
} else {
return c;
@ -74,12 +73,15 @@ char Reader::getChar(bool skip_whitespace) {
}
};
/// Moves back the location by one char. Basically unreads the last character.
void Reader::ungetChar() {
input_stream.unget();
// The char that we just unget
dec_location(current_location, this->current_char == '\n');
};
/// A predicate function indicating whether the given char `c` is a valid
/// char for the starting point of a symbol or not.
bool Reader::isValidForIdentifier(char c) {
switch (c) {
case '!':
@ -110,7 +112,7 @@ bool Reader::isValidForIdentifier(char c) {
return false;
}
ast_node Reader::readNumber(bool neg) {
exprs::node Reader::readNumber(bool neg) {
std::string number(neg ? "-" : "");
bool floatNum = false;
bool empty = false;
@ -141,13 +143,13 @@ ast_node Reader::readNumber(bool neg) {
if (!empty) {
ungetChar();
loc.end = current_location;
return makeNumber(loc, number, neg, floatNum);
return exprs::make<exprs::Number>(loc, number, neg, floatNum);
}
return nullptr;
};
ast_node Reader::readSymbol() {
exprs::node Reader::readSymbol() {
bool empty = true;
char c = getChar(false);
@ -186,16 +188,15 @@ ast_node Reader::readSymbol() {
if (!empty) {
ungetChar();
loc.end = current_location;
return makeSymbol(loc, sym);
return exprs::make<exprs::Symbol>(loc, sym);
}
// TODO: it should never happens
return nullptr;
};
// std::unique_ptr<List> list
ast_list_node Reader::readList() {
auto list = makeList(current_location);
exprs::node Reader::readList() {
auto list = exprs::makeAndCast<exprs::List>(current_location);
char c = getChar(true);
assert(c == '(');
@ -210,7 +211,7 @@ ast_list_node Reader::readList() {
throw ReadError(const_cast<char *>("EOF reached before closing of list"));
case ')':
list_terminated = true;
list->location->end = current_location;
list->location.end = current_location;
break;
@ -222,9 +223,9 @@ ast_list_node Reader::readList() {
} while (!list_terminated);
return list;
}
};
ast_node Reader::readExpr() {
exprs::node Reader::readExpr() {
char c = getChar(false);
READER_LOG("CHAR: " << c);
@ -241,9 +242,9 @@ ast_node Reader::readExpr() {
default:
return readSymbol();
}
}
};
std::unique_ptr<ast_tree> Reader::read() {
llvm::Expected<exprs::ast> Reader::read() {
char c = getChar(true);
while (c != EOF) {
@ -255,18 +256,25 @@ std::unique_ptr<ast_tree> Reader::read() {
c = getChar(true);
}
return std::make_unique<ast_tree>(this->ast);
}
return this->ast;
};
void Reader::dumpAST() {
ast_tree ast = *this->read();
auto maybeAst = read();
std::string result = "";
for (auto &node : ast) {
result = fmt::format("{0} {1}", result, node->dumpAST());
}
}
std::unique_ptr<ast_tree> FileReader::read() {
if (!maybeAst) {
throw maybeAst.takeError();
}
exprs::ast ast = *maybeAst;
for (auto &node : ast) {
result = llvm::formatv("{0} {1}", result, node->toString());
}
};
llvm::Expected<exprs::ast> FileReader::read() {
// TODO: Add support for relative path as well
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
@ -276,7 +284,7 @@ std::unique_ptr<ast_tree> FileReader::read() {
llvm::errs() << "Could not open input file: " << EC.message() << "\n";
llvm::errs() << fmt::format("File: '{}'\n", file);
llvm::errs() << "Use absolute path for now\n";
return nullptr;
return llvm::make_error<MissingFileError>(file);
}
reader->setInput(fileOrErr.get()->getBuffer().str());
@ -285,17 +293,19 @@ std::unique_ptr<ast_tree> FileReader::read() {
void FileReader::dumpAST() {
auto maybeAst = this->read();
ast_tree ast;
exprs::ast ast;
if (maybeAst) {
ast = *maybeAst;
if (!maybeAst) {
throw maybeAst.takeError();
}
ast = *maybeAst;
std::string result = "";
for (auto &node : ast) {
result = fmt::format("{0} {1}", result, node->dumpAST());
result = llvm::formatv("{0} {1}", result, node->toString());
}
cout << result << endl;
llvm::outs() << result << "\n";
}
FileReader::~FileReader() {

View File

@ -24,7 +24,7 @@
#include "serene/sir/sir.hpp"
#include "mlir/IR/MLIRContext.h"
#include "serene/expr.hpp"
#include "serene/exprs/expression.h"
#include "serene/sir/dialect.hpp"
#include "serene/sir/generator.hpp"
#include <memory>
@ -41,7 +41,7 @@ mlir::OwningModuleRef SIR::generate(::serene::Namespace *ns) {
SIR::~SIR() {}
void dumpSIR(ast_tree &t) {
void dumpSIR(exprs::ast &t) {
auto ns = new ::serene::Namespace("user", llvm::None);
SIR s{};

View File

@ -24,7 +24,7 @@
#include "serene/state.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/namespace.h"
#include <fmt/core.h>
#include <string>

View File

@ -25,7 +25,7 @@
#include "serene/symbol.hpp"
#include "serene/expr.hpp"
#include "serene/llvm/IR/Value.h"
#include "serene/namespace.hpp"
#include "serene/namespace.h"
#include "serene/state.hpp"
#include <assert.h>
#include <fmt/core.h>

View File

@ -37,30 +37,9 @@ TEST_CASE("Public Expression API", "[expression]") {
REQUIRE(sym->getType() == ExprType::Symbol);
REQUIRE(sym->toString() == "<Symbol [loc: 2:20:40 | 3:30:80]: example>");
};
TEST_CASE("List Expression", "[expression]") {
std::unique_ptr<reader::LocationRange> range(dummyLocation());
auto sym = make<Symbol>(*range.get(), llvm::StringRef("example"));
auto list = makeAndCast<List>(*range.get(), sym);
auto list = make<List>(*range.get());
auto list2 = make<List>(*range.get(), list);
auto list3 = make<List>(*range.get(), llvm::ArrayRef<node>{list, list2, sym});
REQUIRE(list->toString() == "<List [loc: 2:20:40 | 3:30:80]: ->");
REQUIRE(list->getType() == ExprType::List);
REQUIRE(
list2->toString() ==
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: ->>");
REQUIRE(list3->toString() ==
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: -> "
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: "
"->> <Symbol [loc: 2:20:40 | 3:30:80]: example>>");
list->elements.push_back(sym);
REQUIRE(list->getType() == ExprType::List);
REQUIRE(list->toString() == "<List [loc: 2:20:40 | 3:30:80]: <Symbol [loc: "
"2:20:40 | 3:30:80]: example>>");
};

61
tests/exprs/list_test.cpp Normal file
View File

@ -0,0 +1,61 @@
/* -*- C++ -*-
* Serene programming language.
*
* Copyright (c) 2019-2021 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 "../test_helpers.cpp.inc"
#include "serene/exprs/list.h"
#include "serene/exprs/symbol.h"
namespace serene {
namespace exprs {
TEST_CASE("List Expression", "[expression]") {
std::unique_ptr<reader::LocationRange> range(dummyLocation());
auto sym = make<Symbol>(*range.get(), llvm::StringRef("example"));
auto list = make<List>(*range.get());
auto list2 = make<List>(*range.get(), list);
auto list3 = make<List>(*range.get(), llvm::ArrayRef<node>{list, list2, sym});
REQUIRE(list->toString() == "<List [loc: 2:20:40 | 3:30:80]: ->");
REQUIRE(list->getType() == ExprType::List);
REQUIRE(
list2->toString() ==
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: ->>");
REQUIRE(list3->toString() ==
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: -> "
"<List [loc: 2:20:40 | 3:30:80]: <List [loc: 2:20:40 | 3:30:80]: "
"->> <Symbol [loc: 2:20:40 | 3:30:80]: example>>");
auto l = llvm::dyn_cast<List>(list);
l.append(sym);
REQUIRE(list->getType() == ExprType::List);
REQUIRE(list->toString() == "<List [loc: 2:20:40 | 3:30:80]: <Symbol [loc: "
"2:20:40 | 3:30:80]: example>>");
};
} // namespace exprs
} // namespace serene