diff --git a/bin/serene.cpp b/bin/serene.cpp index 9b8ddbf..26a272d 100644 --- a/bin/serene.cpp +++ b/bin/serene.cpp @@ -22,7 +22,7 @@ * SOFTWARE. */ -#include "serene/serene.hpp" +#include "serene/serene.h" #include "serene/reader/reader.hpp" #include "serene/sir/sir.hpp" #include diff --git a/include/serene/exprs/expression.h b/include/serene/exprs/expression.h new file mode 100644 index 0000000..4916eb9 --- /dev/null +++ b/include/serene/exprs/expression.h @@ -0,0 +1,69 @@ +/* -*- C++ -*- + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * 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_EXPRESSION_H +#define EXPRS_EXPRESSION_H + +#include + +namespace serene { + +/// Contains all the builtin expressions including those which do not appear in +/// the syntax directly. Like function definitions. +namespace exprs { + +/// 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** +class Expression { +public: + template + Expression(T e) : self(new ExpressionImpl(std::move(e))){}; + +private: + /// The generic interface which each type of expression has to implement + /// in order to act like an `Expression` + struct ExpressionConcept { + virtual ~ExpressionConcept() = default; + virtual ExpressionConcept *copy_() const = 0; + }; + + /// The generic implementation of `ExpressionConcept` which acts as the + /// dispatcher on type. + template struct ExpressionImpl : ExpressionConcept { + ExpressionImpl(T e) : expr(std::move(e)){}; + ExpressionConcept *copy_() const { return new ExpressionImpl(*this); } + + 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 self; +}; + +} // namespace exprs +} // namespace serene + +#endif diff --git a/include/serene/exprs/list.h b/include/serene/exprs/list.h new file mode 100644 index 0000000..d0a338e --- /dev/null +++ b/include/serene/exprs/list.h @@ -0,0 +1,43 @@ +/* -*- C++ -*- + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * 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_SYMBOL_H +#define EXPRS_SYMBOL_H + +#include "serene/exprs/expression.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace serene { + +namespace exprs { + +struct List { + llvm::SmallVector elements; +}; + +} // namespace exprs +} // namespace serene + +#endif diff --git a/include/serene/exprs/symbol.h b/include/serene/exprs/symbol.h new file mode 100644 index 0000000..aadfa3b --- /dev/null +++ b/include/serene/exprs/symbol.h @@ -0,0 +1,41 @@ +/* -*- C++ -*- + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * 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_SYMBOL_H +#define EXPRS_SYMBOL_H + +#include + +namespace serene { + +namespace exprs { + +struct Symbol { + std::string name; +}; + +} // namespace exprs +} // namespace serene + +#endif diff --git a/include/serene/reader/reader.hpp b/include/serene/reader/reader.hpp index 1908921..7e369b7 100644 --- a/include/serene/reader/reader.hpp +++ b/include/serene/reader/reader.hpp @@ -37,7 +37,7 @@ #include "serene/list.hpp" #include "serene/logger.hpp" #include "serene/reader/location.hpp" -#include "serene/serene.hpp" +#include "serene/serene.h" #include "serene/symbol.hpp" #if defined(ENABLE_READER_LOG) || defined(ENABLE_LOG) diff --git a/include/serene/serene.hpp b/include/serene/serene.h similarity index 95% rename from include/serene/serene.hpp rename to include/serene/serene.h index 6003ca7..3a13f2b 100644 --- a/include/serene/serene.hpp +++ b/include/serene/serene.h @@ -1,7 +1,7 @@ -/** +/* * Serene programming language. * - * Copyright (c) 2020 Sameer Rahmani + * Copyright (c) 2019-2021 Sameer Rahmani * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/include/serene/sir/generator.hpp b/include/serene/sir/generator.hpp index cb91504..fe913f4 100644 --- a/include/serene/sir/generator.hpp +++ b/include/serene/sir/generator.hpp @@ -55,8 +55,8 @@ private: // TODO: Should we use builder here? maybe there is a better option ::mlir::Location toMLIRLocation(serene::reader::Location *); - mlir::FuncOp generateFn(serene::reader::Location, std::string, List *, - List *); + // mlir::FuncOp generateFn(serene::reader::Location, std::string, List *, + // List *); public: Generator(mlir::MLIRContext &context, ::serene::Namespace *ns) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3f06a34..f9b77c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,14 @@ set(HEADER_LIST + "${INCLUDE_DIR}/serene/serene.h" + + "${INCLUDE_DIR}/serene/exprs/expression.h" + "${INCLUDE_DIR}/serene/exprs/symbol.h" + "${INCLUDE_DIR}/serene/exprs/list.h" + + + "${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" @@ -19,6 +27,9 @@ set(HEADER_LIST # Make an automatic library - will be static or dynamic based on user setting add_library(serene + exprs/symbol.cpp + exprs/list.cpp + serene.cpp symbol.cpp list.cpp diff --git a/src/exprs/list.cpp b/src/exprs/list.cpp new file mode 100644 index 0000000..0fda9d8 --- /dev/null +++ b/src/exprs/list.cpp @@ -0,0 +1,25 @@ +/* + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * 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/list.h" diff --git a/src/exprs/symbol.cpp b/src/exprs/symbol.cpp new file mode 100644 index 0000000..ed0739c --- /dev/null +++ b/src/exprs/symbol.cpp @@ -0,0 +1,25 @@ +/* + * Serene programming language. + * + * Copyright (c) 2019-2021 Sameer Rahmani + * + * 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/symbol.h" diff --git a/src/serene.cpp b/src/serene.cpp index 196c3d8..c0e58e4 100644 --- a/src/serene.cpp +++ b/src/serene.cpp @@ -22,6 +22,6 @@ * SOFTWARE. */ -#include "serene/serene.hpp" +#include "serene/serene.h" #include "serene/reader/reader.hpp" #include diff --git a/src/sir/generator.cpp b/src/sir/generator.cpp index 3f22b15..2bee14e 100644 --- a/src/sir/generator.cpp +++ b/src/sir/generator.cpp @@ -40,139 +40,144 @@ namespace serene { namespace sir { mlir::ModuleOp Generator::generate() { - for (auto x : ns->Tree()) { - generate(x.get()); - } + // for (auto x : ns->Tree()) { + // generate(x.get()); + // } return module; }; mlir::Operation *Generator::generate(AExpr *x) { - switch (x->getType()) { - case SereneType::Number: { - return generate(llvm::cast(x)); - } + // switch (x->getType()) { + // case SereneType::Number: { + // return generate(llvm::cast(x)); + // } - case SereneType::List: { - generate(llvm::cast(x)); - return nullptr; - } + // case SereneType::List: { + // generate(llvm::cast(x)); + // return nullptr; + // } - default: { - return builder.create(builder.getUnknownLoc(), (uint64_t)3); - } - } + // default: { + return builder.create(builder.getUnknownLoc(), (uint64_t)3); + // } + // } }; mlir::Value Generator::generate(List *l) { - auto first = l->at(0); + // auto first = l->at(0); - if (!first) { - // Empty list. - // TODO: Return Nil or empty list. + // if (!first) { + // // Empty list. + // // TODO: Return Nil or empty list. - // Just for now. - return builder.create(builder.getUnknownLoc(), (uint64_t)0); - } - - if (first->get()->getType() == SereneType::Symbol) { - auto fnNameSymbol = llvm::dyn_cast(first->get()); - - if (fnNameSymbol->getName() == "fn") { - if (l->count() <= 3) { - module.emitError("'fn' form needs exactly 2 arguments."); - } - - auto args = llvm::dyn_cast(l->at(1).getValue().get()); - auto body = llvm::dyn_cast(l->from(2).get()); - - if (!args) { - module.emitError("The first element of 'def' has to be a symbol."); - } - - // Create a new anonymous function and push it to the anonymous functions - // map, later on we - auto loc(fnNameSymbol->location->start); - auto anonymousName = fmt::format("__fn_{}__", anonymousFnCounter); - anonymousFnCounter++; - - auto fn = generateFn(loc, anonymousName, args, body); - mlir::Identifier fnid = builder.getIdentifier(anonymousName); - anonymousFunctions.insert({fnid, fn}); - return builder.create(builder.getUnknownLoc(), fnid.str()); - } - } - // auto rest = l->from(1); - // auto loc = toMLIRLocation(&first->get()->location->start); - // for (auto x : *rest) { - // generate(x.get()); + // // Just for now. + // return builder.create(builder.getUnknownLoc(), (uint64_t)0); // } + // if (first->get()->getType() == SereneType::Symbol) { + // auto fnNameSymbol = llvm::dyn_cast(first->get()); + + // if (fnNameSymbol->getName() == "fn") { + // if (l->count() <= 3) { + // module.emitError("'fn' form needs exactly 2 arguments."); + // } + + // auto args = llvm::dyn_cast(l->at(1).getValue().get()); + // auto body = llvm::dyn_cast(l->from(2).get()); + + // if (!args) { + // module.emitError("The first element of 'def' has to be a symbol."); + // } + + // // Create a new anonymous function and push it to the anonymous + // functions + // // map, later on we + // auto loc(fnNameSymbol->location->start); + // auto anonymousName = fmt::format("__fn_{}__", anonymousFnCounter); + // anonymousFnCounter++; + + // auto fn = generateFn(loc, anonymousName, args, body); + // mlir::Identifier fnid = builder.getIdentifier(anonymousName); + // anonymousFunctions.insert({fnid, fn}); + // return builder.create(builder.getUnknownLoc(), fnid.str()); + // } + // } + // // auto rest = l->from(1); + // // auto loc = toMLIRLocation(&first->get()->location->start); + // // for (auto x : *rest) { + // // generate(x.get()); + // // } + return builder.create(builder.getUnknownLoc(), (uint64_t)100); }; -mlir::FuncOp Generator::generateFn(serene::reader::Location loc, - std::string name, List *args, List *body) { +// mlir::FuncOp Generator::generateFn(serene::reader::Location loc, +// std::string name, List *args, List *body) +// { - auto location = toMLIRLocation(&loc); - llvm::SmallVector arg_types(args->count(), - builder.getI64Type()); - auto func_type = builder.getFunctionType(arg_types, builder.getI64Type()); - auto proto = mlir::FuncOp::create(location, name, func_type); - mlir::FuncOp fn(proto); +// auto location = toMLIRLocation(&loc); +// llvm::SmallVector arg_types(args->count(), +// builder.getI64Type()); +// auto func_type = builder.getFunctionType(arg_types, builder.getI64Type()); +// auto proto = mlir::FuncOp::create(location, name, func_type); +// mlir::FuncOp fn(proto); - if (!fn) { - module.emitError("Can not create the function."); - } +// if (!fn) { +// module.emitError("Can not create the function."); +// } - auto &entryBlock = *fn.addEntryBlock(); - llvm::ScopedHashTableScope scope(symbolTable); +// auto &entryBlock = *fn.addEntryBlock(); +// llvm::ScopedHashTableScope +// scope(symbolTable); - // Declare all the function arguments in the symbol table. - for (const auto arg : - llvm::zip(args->asArrayRef(), entryBlock.getArguments())) { +// // Declare all the function arguments in the symbol table. +// for (const auto arg : +// llvm::zip(args->asArrayRef(), entryBlock.getArguments())) { - auto argSymbol = llvm::dyn_cast(std::get<0>(arg).get()); - if (!argSymbol) { - module.emitError("Function parameters must be symbols"); - } - if (symbolTable.count(argSymbol->getName())) { - return nullptr; - } - symbolTable.insert(argSymbol->getName(), std::get<1>(arg)); - } +// auto argSymbol = llvm::dyn_cast(std::get<0>(arg).get()); +// if (!argSymbol) { +// module.emitError("Function parameters must be symbols"); +// } +// if (symbolTable.count(argSymbol->getName())) { +// return nullptr; +// } +// symbolTable.insert(argSymbol->getName(), std::get<1>(arg)); +// } - // Set the insertion point in the builder to the beginning of the function - // body, it will be used throughout the codegen to create operations in this - // function. - builder.setInsertionPointToStart(&entryBlock); +// // Set the insertion point in the builder to the beginning of the function +// // body, it will be used throughout the codegen to create operations in +// this +// // function. +// builder.setInsertionPointToStart(&entryBlock); - // Emit the body of the function. - if (!generate(body)) { - fn.erase(); - return nullptr; - } +// // Emit the body of the function. +// if (!generate(body)) { +// fn.erase(); +// return nullptr; +// } - // // Implicitly return void if no return statement was emitted. - // // FIXME: we may fix the parser instead to always return the last - // expression - // // (this would possibly help the REPL case later) - // ReturnOp returnOp; +// // // Implicitly return void if no return statement was emitted. +// // // FIXME: we may fix the parser instead to always return the last +// // expression +// // // (this would possibly help the REPL case later) +// // ReturnOp returnOp; - // if (!entryBlock.empty()) - // returnOp = dyn_cast(entryBlock.back()); - // if (!returnOp) { - // builder.create(loc(funcAST.getProto()->loc())); - // } else if (returnOp.hasOperand()) { - // // Otherwise, if this return operation has an operand then add a result - // to - // // the function. - // function.setType(builder.getFunctionType(function.getType().getInputs(), - // getType(VarType{}))); - // } +// // if (!entryBlock.empty()) +// // returnOp = dyn_cast(entryBlock.back()); +// // if (!returnOp) { +// // builder.create(loc(funcAST.getProto()->loc())); +// // } else if (returnOp.hasOperand()) { +// // // Otherwise, if this return operation has an operand then add a +// result +// // to +// // // the function. +// // function.setType(builder.getFunctionType(function.getType().getInputs(), +// // getType(VarType{}))); +// // } - return fn; -} +// return fn; +// } mlir::Operation *Generator::generate(Number *x) { return builder.create(builder.getUnknownLoc(), x->toI64());