From 255045c5521685babe3a9e42cf15d3fc9016ef92 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Tue, 11 Jul 2023 18:40:26 +0100 Subject: [PATCH] Remove all the serene stuff that are not required --- README.md | 1 + dev.org | 244 -- devtools/CMakeLists.txt | 93 - devtools/slir-lsp-server.cpp | 35 - devtools/slir-opt.cpp | 39 - libserene.v0/CMakeLists.txt | 81 - libserene.v0/cmake/SereneConfig.cmake.in | 21 - libserene.v0/include/CMakeLists.txt | 3 - libserene.v0/include/serene/config.h.in | 16 - libserene.v0/include/serene/context.h | 285 -- libserene.v0/include/serene/conventions.h | 39 - libserene.v0/include/serene/diagnostics.h | 127 - libserene.v0/include/serene/environment.h | 80 - libserene.v0/include/serene/errors.h | 82 - .../include/serene/errors/CMakeLists.txt | 5 - libserene.v0/include/serene/errors/base.h | 65 - libserene.v0/include/serene/errors/errors.td | 76 - libserene.v0/include/serene/errors/variant.h | 43 - libserene.v0/include/serene/exprs/call.h | 76 - libserene.v0/include/serene/exprs/def.h | 72 - .../include/serene/exprs/expression.h | 148 - libserene.v0/include/serene/exprs/fn.h | 77 - libserene.v0/include/serene/exprs/list.h | 88 - libserene.v0/include/serene/exprs/number.h | 65 - libserene.v0/include/serene/exprs/symbol.h | 81 - libserene.v0/include/serene/exprs/traits.h | 47 - libserene.v0/include/serene/jit/README.org | 18 - libserene.v0/include/serene/jit/engine.h | 180 -- libserene.v0/include/serene/jit/halley.h | 196 -- libserene.v0/include/serene/jit/layers.h | 164 -- libserene.v0/include/serene/llvm/IR/Value.h | 7 - libserene.v0/include/serene/llvm/patches.h | 57 - libserene.v0/include/serene/namespace.h | 178 -- libserene.v0/include/serene/passes.h | 44 - .../include/serene/passes/CMakeLists.txt | 9 - libserene.v0/include/serene/passes/passes.td | 43 - libserene.v0/include/serene/reader/location.h | 92 - libserene.v0/include/serene/reader/reader.h | 137 - libserene.v0/include/serene/reader/traits.h | 40 - libserene.v0/include/serene/semantics.h | 75 - libserene.v0/include/serene/serene.h | 79 - .../include/serene/slir/CMakeLists.txt | 12 - libserene.v0/include/serene/slir/dialect.h | 45 - libserene.v0/include/serene/slir/dialect.td | 126 - .../include/serene/slir/generatable.h | 121 - libserene.v0/include/serene/slir/ops.h | 40 - libserene.v0/include/serene/slir/ops.td | 370 --- libserene.v0/include/serene/slir/slir.h | 39 - libserene.v0/include/serene/slir/symbol.h | 81 - libserene.v0/include/serene/slir/traits.h | 117 - .../include/serene/slir/type_converter.h | 86 - libserene.v0/include/serene/slir/types.h | 34 - libserene.v0/include/serene/slir/types.td | 141 - libserene.v0/include/serene/slir/utils.h | 40 - libserene.v0/include/serene/source_mgr.h | 190 -- libserene.v0/include/serene/traits.h | 123 - .../include/serene/traits/locatable.h | 22 - libserene.v0/include/serene/types/type.h | 35 - libserene.v0/include/serene/utils.h | 140 - libserene.v0/lib/CMakeLists.txt | 169 -- libserene.v0/lib/context.cpp | 185 -- libserene.v0/lib/diagnostics.cpp | 218 -- libserene.v0/lib/errors.cpp | 42 - libserene.v0/lib/exprs/call.cpp | 141 - libserene.v0/lib/exprs/def.cpp | 138 - libserene.v0/lib/exprs/expression.cpp | 46 - libserene.v0/lib/exprs/fn.cpp | 166 -- libserene.v0/lib/exprs/list.cpp | 118 - libserene.v0/lib/exprs/number.cpp | 59 - libserene.v0/lib/exprs/symbol.cpp | 46 - libserene.v0/lib/jit/engine.cpp | 110 - libserene.v0/lib/jit/halley.cpp | 457 --- libserene.v0/lib/jit/layers.cpp | 162 - libserene.v0/lib/namespace.cpp | 224 -- libserene.v0/lib/passes/slir_lowering.cpp | 761 ----- libserene.v0/lib/passes/to_llvm_dialect.cpp | 87 - libserene.v0/lib/reader/reader.cpp | 438 --- libserene.v0/lib/semantics.cpp | 71 - libserene.v0/lib/serene.cpp | 157 - libserene.v0/lib/slir/dialect.cpp | 48 - libserene.v0/lib/slir/generatable.cpp | 172 -- libserene.v0/lib/slir/ops.cpp | 57 - libserene.v0/lib/slir/slir.cpp | 65 - libserene.v0/lib/slir/type_converter.cpp | 86 - libserene.v0/lib/slir/types.cpp | 52 - libserene.v0/lib/slir/utils.cpp | 36 - libserene.v0/lib/slir/value_op.cpp | 28 - libserene.v0/lib/source_mgr.cpp | 225 -- libserene.v0/tests/CMakeLists.txt | 29 - libserene.v0/tests/context_tests.cpp.inc | 161 - libserene.v0/tests/environment_tests.cpp.inc | 95 - libserene.v0/tests/errors/error_tests.cpp.inc | 66 - .../tests/exprs/expression_tests.cpp.inc | 43 - libserene.v0/tests/exprs/list_tests.cpp.inc | 196 -- libserene.v0/tests/exprs/number_tests.cpp.inc | 42 - libserene.v0/tests/exprs/symbol_tests.cpp.inc | 35 - libserene.v0/tests/namespace_tests.cpp.inc | 50 - .../tests/reader/reader_tests.cpp.inc | 110 - libserene.v0/tests/serenetests.cpp | 33 - libserene.v0/tests/setup.cpp.inc | 37 - libserene.v0/tests/test_helpers.cpp.inc | 66 - libserene.v0/tests/traits_tests.cpp.inc | 129 - libserene.v0/tests/utils_tests.cpp.inc | 34 - libserene/CMakeLists.txt | 82 - libserene/cmake/SereneConfig.cmake.in | 21 - libserene/include/serene/config.h.in | 22 - libserene/include/serene/context.h | 124 - libserene/include/serene/fs.h | 59 - libserene/include/serene/jit/README.org | 18 - libserene/include/serene/jit/halley.h | 249 -- libserene/include/serene/jit/packer.h | 71 - libserene/include/serene/options.h | 44 - libserene/include/serene/serene.h | 50 - libserene/include/serene/types/types.h | 70 - libserene/lib/CMakeLists.txt | 82 - libserene/lib/context.cpp | 52 - libserene/lib/fs.cpp | 119 - libserene/lib/jit/halley.cpp | 867 ------ libserene/lib/jit/packer.cpp | 116 - libserene/lib/serene.cpp | 93 - resources/benchmarks/parsers/example_code.srn | 85 - resources/docker/llvm/Dockerfile | 69 - resources/docker/llvm/Dockerfile.ci | 11 - resources/docker/llvm/Dockerfile.source_base | 24 - resources/docker/serene/Dockerfile | 9 - resources/docker/toolchain/stage0/Dockerfile | 47 - resources/docker/toolchain/stage0/Sysroot | 22 - resources/emacs/serene-dev.el | 122 - resources/images/logo-history.svg | 413 --- resources/images/serene.svg | 80 - resources/museum/SUPPORTERS | 1 - resources/museum/first_executable_2021_07_12 | Bin 19600 -> 0 bytes resources/museum/first_object_file_2021_06_29 | Bin 2400 -> 0 bytes serene-repl/CMakeLists.txt | 66 - serene-repl/serene-repl.cpp | 112 - serene-repl/serene/linenoise.h | 2606 ----------------- serene-tblgen/CMakeLists.txt | 35 - serene-tblgen/main.cpp | 84 - serene-tblgen/serene/errors-backend.cpp | 191 -- serene-tblgen/serene/errors-backend.h | 30 - serene/CMakeLists.txt | 135 - serene/include/CMakeLists.txt | 17 - serene/include/serene/commands.h | 27 - serene/include/serene/config.h.in | 22 - serene/src/CMakeLists.txt | 21 - serene/src/commands/commands.cpp | 30 - serene/src/serene.cpp | 70 - serenec/CMakeLists.txt | 69 - serenec/serenec.cpp | 468 --- 149 files changed, 1 insertion(+), 17764 deletions(-) delete mode 100644 dev.org delete mode 100644 devtools/CMakeLists.txt delete mode 100644 devtools/slir-lsp-server.cpp delete mode 100644 devtools/slir-opt.cpp delete mode 100644 libserene.v0/CMakeLists.txt delete mode 100644 libserene.v0/cmake/SereneConfig.cmake.in delete mode 100644 libserene.v0/include/CMakeLists.txt delete mode 100644 libserene.v0/include/serene/config.h.in delete mode 100644 libserene.v0/include/serene/context.h delete mode 100644 libserene.v0/include/serene/conventions.h delete mode 100644 libserene.v0/include/serene/diagnostics.h delete mode 100644 libserene.v0/include/serene/environment.h delete mode 100644 libserene.v0/include/serene/errors.h delete mode 100644 libserene.v0/include/serene/errors/CMakeLists.txt delete mode 100644 libserene.v0/include/serene/errors/base.h delete mode 100644 libserene.v0/include/serene/errors/errors.td delete mode 100644 libserene.v0/include/serene/errors/variant.h delete mode 100644 libserene.v0/include/serene/exprs/call.h delete mode 100644 libserene.v0/include/serene/exprs/def.h delete mode 100644 libserene.v0/include/serene/exprs/expression.h delete mode 100644 libserene.v0/include/serene/exprs/fn.h delete mode 100644 libserene.v0/include/serene/exprs/list.h delete mode 100644 libserene.v0/include/serene/exprs/number.h delete mode 100644 libserene.v0/include/serene/exprs/symbol.h delete mode 100644 libserene.v0/include/serene/exprs/traits.h delete mode 100644 libserene.v0/include/serene/jit/README.org delete mode 100644 libserene.v0/include/serene/jit/engine.h delete mode 100644 libserene.v0/include/serene/jit/halley.h delete mode 100644 libserene.v0/include/serene/jit/layers.h delete mode 100644 libserene.v0/include/serene/llvm/IR/Value.h delete mode 100644 libserene.v0/include/serene/llvm/patches.h delete mode 100644 libserene.v0/include/serene/namespace.h delete mode 100644 libserene.v0/include/serene/passes.h delete mode 100644 libserene.v0/include/serene/passes/CMakeLists.txt delete mode 100644 libserene.v0/include/serene/passes/passes.td delete mode 100644 libserene.v0/include/serene/reader/location.h delete mode 100644 libserene.v0/include/serene/reader/reader.h delete mode 100644 libserene.v0/include/serene/reader/traits.h delete mode 100644 libserene.v0/include/serene/semantics.h delete mode 100644 libserene.v0/include/serene/serene.h delete mode 100644 libserene.v0/include/serene/slir/CMakeLists.txt delete mode 100644 libserene.v0/include/serene/slir/dialect.h delete mode 100644 libserene.v0/include/serene/slir/dialect.td delete mode 100644 libserene.v0/include/serene/slir/generatable.h delete mode 100644 libserene.v0/include/serene/slir/ops.h delete mode 100644 libserene.v0/include/serene/slir/ops.td delete mode 100644 libserene.v0/include/serene/slir/slir.h delete mode 100644 libserene.v0/include/serene/slir/symbol.h delete mode 100644 libserene.v0/include/serene/slir/traits.h delete mode 100644 libserene.v0/include/serene/slir/type_converter.h delete mode 100644 libserene.v0/include/serene/slir/types.h delete mode 100644 libserene.v0/include/serene/slir/types.td delete mode 100644 libserene.v0/include/serene/slir/utils.h delete mode 100644 libserene.v0/include/serene/source_mgr.h delete mode 100644 libserene.v0/include/serene/traits.h delete mode 100644 libserene.v0/include/serene/traits/locatable.h delete mode 100644 libserene.v0/include/serene/types/type.h delete mode 100644 libserene.v0/include/serene/utils.h delete mode 100644 libserene.v0/lib/CMakeLists.txt delete mode 100644 libserene.v0/lib/context.cpp delete mode 100644 libserene.v0/lib/diagnostics.cpp delete mode 100644 libserene.v0/lib/errors.cpp delete mode 100644 libserene.v0/lib/exprs/call.cpp delete mode 100644 libserene.v0/lib/exprs/def.cpp delete mode 100644 libserene.v0/lib/exprs/expression.cpp delete mode 100644 libserene.v0/lib/exprs/fn.cpp delete mode 100644 libserene.v0/lib/exprs/list.cpp delete mode 100644 libserene.v0/lib/exprs/number.cpp delete mode 100644 libserene.v0/lib/exprs/symbol.cpp delete mode 100644 libserene.v0/lib/jit/engine.cpp delete mode 100644 libserene.v0/lib/jit/halley.cpp delete mode 100644 libserene.v0/lib/jit/layers.cpp delete mode 100644 libserene.v0/lib/namespace.cpp delete mode 100644 libserene.v0/lib/passes/slir_lowering.cpp delete mode 100644 libserene.v0/lib/passes/to_llvm_dialect.cpp delete mode 100644 libserene.v0/lib/reader/reader.cpp delete mode 100644 libserene.v0/lib/semantics.cpp delete mode 100644 libserene.v0/lib/serene.cpp delete mode 100644 libserene.v0/lib/slir/dialect.cpp delete mode 100644 libserene.v0/lib/slir/generatable.cpp delete mode 100644 libserene.v0/lib/slir/ops.cpp delete mode 100644 libserene.v0/lib/slir/slir.cpp delete mode 100644 libserene.v0/lib/slir/type_converter.cpp delete mode 100644 libserene.v0/lib/slir/types.cpp delete mode 100644 libserene.v0/lib/slir/utils.cpp delete mode 100644 libserene.v0/lib/slir/value_op.cpp delete mode 100644 libserene.v0/lib/source_mgr.cpp delete mode 100644 libserene.v0/tests/CMakeLists.txt delete mode 100644 libserene.v0/tests/context_tests.cpp.inc delete mode 100644 libserene.v0/tests/environment_tests.cpp.inc delete mode 100644 libserene.v0/tests/errors/error_tests.cpp.inc delete mode 100644 libserene.v0/tests/exprs/expression_tests.cpp.inc delete mode 100644 libserene.v0/tests/exprs/list_tests.cpp.inc delete mode 100644 libserene.v0/tests/exprs/number_tests.cpp.inc delete mode 100644 libserene.v0/tests/exprs/symbol_tests.cpp.inc delete mode 100644 libserene.v0/tests/namespace_tests.cpp.inc delete mode 100644 libserene.v0/tests/reader/reader_tests.cpp.inc delete mode 100644 libserene.v0/tests/serenetests.cpp delete mode 100644 libserene.v0/tests/setup.cpp.inc delete mode 100644 libserene.v0/tests/test_helpers.cpp.inc delete mode 100644 libserene.v0/tests/traits_tests.cpp.inc delete mode 100644 libserene.v0/tests/utils_tests.cpp.inc delete mode 100644 libserene/CMakeLists.txt delete mode 100644 libserene/cmake/SereneConfig.cmake.in delete mode 100644 libserene/include/serene/config.h.in delete mode 100644 libserene/include/serene/context.h delete mode 100644 libserene/include/serene/fs.h delete mode 100644 libserene/include/serene/jit/README.org delete mode 100644 libserene/include/serene/jit/halley.h delete mode 100644 libserene/include/serene/jit/packer.h delete mode 100644 libserene/include/serene/options.h delete mode 100644 libserene/include/serene/serene.h delete mode 100644 libserene/include/serene/types/types.h delete mode 100644 libserene/lib/CMakeLists.txt delete mode 100644 libserene/lib/context.cpp delete mode 100644 libserene/lib/fs.cpp delete mode 100644 libserene/lib/jit/halley.cpp delete mode 100644 libserene/lib/jit/packer.cpp delete mode 100644 libserene/lib/serene.cpp delete mode 100644 resources/benchmarks/parsers/example_code.srn delete mode 100644 resources/docker/llvm/Dockerfile delete mode 100644 resources/docker/llvm/Dockerfile.ci delete mode 100644 resources/docker/llvm/Dockerfile.source_base delete mode 100644 resources/docker/serene/Dockerfile delete mode 100644 resources/docker/toolchain/stage0/Dockerfile delete mode 100644 resources/docker/toolchain/stage0/Sysroot delete mode 100644 resources/emacs/serene-dev.el delete mode 100644 resources/images/logo-history.svg delete mode 100644 resources/images/serene.svg delete mode 100644 resources/museum/SUPPORTERS delete mode 100755 resources/museum/first_executable_2021_07_12 delete mode 100644 resources/museum/first_object_file_2021_06_29 delete mode 100644 serene-repl/CMakeLists.txt delete mode 100644 serene-repl/serene-repl.cpp delete mode 100644 serene-repl/serene/linenoise.h delete mode 100644 serene-tblgen/CMakeLists.txt delete mode 100644 serene-tblgen/main.cpp delete mode 100644 serene-tblgen/serene/errors-backend.cpp delete mode 100644 serene-tblgen/serene/errors-backend.h delete mode 100644 serene/CMakeLists.txt delete mode 100644 serene/include/CMakeLists.txt delete mode 100644 serene/include/serene/commands.h delete mode 100644 serene/include/serene/config.h.in delete mode 100644 serene/src/CMakeLists.txt delete mode 100644 serene/src/commands/commands.cpp delete mode 100644 serene/src/serene.cpp delete mode 100644 serenec/CMakeLists.txt delete mode 100644 serenec/serenec.cpp diff --git a/README.md b/README.md index 8cedff1..6a1e2d5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Serene lang +[![Please don't upload to GitHub](https://nogithub.codeberg.page/badge.svg)](https://nogithub.codeberg.page) [![status-badge](https://ci.devheroes.codes/api/badges/Serene/serene/status.svg)](https://ci.devheroes.codes/Serene/serene) Serene is a modern typed lisp. It's not done yet, and it's heavily under development. Don't diff --git a/dev.org b/dev.org deleted file mode 100644 index e6c2dac..0000000 --- a/dev.org +++ /dev/null @@ -1,244 +0,0 @@ -#+TITLE: Serene Development -#+AUTHOR: Sameer Rahmani -#+SEQ_TODO: TODO(t/!) NEXT(n/!) BLOCKED(b@/!) | DONE(d%) WONT_DO(c@/!) FAILED(f@/!) -#+TAGS: DOCS(d) EXAMPLES(e) serenecli(c) reader(r) context(x) Misc(m) JIT(j) GC(g) Tool(t) -#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty nolatexpreview -#+OPTIONS: tex:t -#+HTML_MATHJAX: align: left indent: 5em tagside: left font: Neo-Eule -#+LATEX_CLASS: article -#+LATEX_CLASS_OPTIONS: [a4paper] -#+LATEX_HEADER: \usepackage{tcolorbox} -#+LATEX_HEADER: \usepackage{mathabx} -#+LATEX_HEADER: \newtcolorbox{infobox}[2][]{colback=cyan!5!white,before skip=14pt,after skip=8pt,colframe=cyan!75!black,sharp corners,title={#2},#1} - -* Serene's Development Resources -This document is dedicated to the process of developing *Serene*. It contains a collection of resources -from the early days of the project and resources that need to be studied and A list of tasks and features -that needs to be done. This document is written using [[https://orgmode.org/][org-mode]]. You can use [[https://emacsclub.github.io/html/org_tutorial.html#sec-7][this cheatsheet]] as a quick guide -for the format but you will get more out of it using org-mode. - -* Resources -For a generic list of resources on compiler design take a look at -[[https://tomassetti.me/resources-create-programming-languages/][the list of resource to create a programming language]] and [[https://www.reddit.com/r/ProgrammingLanguages/comments/8ggx2n/is_llvm_a_good_backend_for_functional_languages/][this list]] -** Parser -First of all you need to read [[https://tomassetti.me/guide-parsing-algorithms-terminology/][All you need to know about Parser algorithms]]. -Then here is the list or parsers that we have considered - -- [[https://github.com/Geal/nom/][Rust parser combinator framework]] -- [[https://github.com/lalrpop/lalrpop][LR(1) parser generator for Rust]] -- [[https://github.com/Marwes/combine][A parser combinator library for Rust]] -- [[https://github.com/kevinmehall/rust-peg][Parsing Expression Grammar (PEG) parser generator for Rust]] -- [[https://pest.rs/][General purpose parser]] - -** Lisp -- [[https://github.com/kanaka/mal/blob/master/process/guide.md][Make a Lisp]] -*** Quasiquotation -- [[http://www.lispworks.com/documentation/HyperSpec/Body/02_df.htm][Backquote in CL]] -- [[https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node367.html][Backquote spec in Common Lisp the Language, 2nd Edition]] -- [[http://christophe.rhodes.io/notes/blog/posts/2014/backquote_and_pretty_printing/][Backquote and pretty printing]] -*** Compilers -- https://bernsteinbear.com/blog/compiling-a-lisp-0/ -** Rust -- [[https://doc.rust-lang.org/book/][The Rust book]] (in [[https://www.reddit.com/r/rust/comments/2s1zj2/the_rust_programming_language_book_as_epub/][EPUB]] format) -** LLVM -- [[https://www.infoworld.com/article/3247799/what-is-llvm-the-power-behind-swift-rust-clang-and-more.html][Brief overview of LLVM]] -- [[https://aosabook.org/en/llvm.html][A bit in depth details on LLVM]] -- [[https://llvm.org/docs/tutorial/][Official LLVM tutorial C++]] -- [[https://blog.llvm.org/posts/2020-11-30-interactive-cpp-with-cling/][Interactive C++ with Cling]] -- [[https://www.wilfred.me.uk/blog/2015/02/21/my-first-llvm-compiler/][My First LLVM Compiler]] -- [[https://mukulrathi.co.uk/create-your-own-programming-language/llvm-ir-cpp-api-tutorial/][A Complete Guide to LLVM for Programming Language Creators]] -** Data structures -- [[https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf][Pure functional datastructures papaer]] -- [[https://reader.elsevier.com/reader/sd/pii/0167642394000042?token=CEFF5C5D1B03FD680762FC4889A14C0CA2BB28FE390EC51099984536E12AC358F3D28A5C25C274296ACBBC32E5AE23CD][Dynamic typing: syntax and proof theory]] -- [[https://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.4394][Representing Type Information in Dynamically Typed Languages]] -- [[https://www.researchgate.net/publication/259634489_An_empirical_study_on_the_impact_of_static_typing_on_software_maintainability][An empirical study on the impact of static typing on software maintainability]] - -** Other languages -- [[https://julialang.org/research/julia-fresh-approach-BEKS.pdf][Julia: A Fresh Approach toNumerical Computing]] -** Cranelift -- [[https://github.com/bytecodealliance/wasmtime/tree/master/cranelift][Source tree]] -** Type Systems -- [[https://www.cs.cmu.edu/~rwh/courses/hott/][Homotopy Type Theory]] -- No, dynamic type systems are not inherently more open: - https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-type-systems-are-not-inherently-more-open/ -- Type theory resources: - https://github.com/jozefg/learn-tt - -** Memory management -- [[https://deepu.tech/memory-management-in-golang/][Visualizing memory management in Golang]] -- [[http://goog-perftools.sourceforge.net/doc/tcmalloc.html][TCMalloc : Thread-Caching Malloc]] -- [[https://medium.com/@ankur_anand/a-visual-guide-to-golang-memory-allocator-from-ground-up-e132258453ed][A visual guide to Go Memory Allocator from scratch (Golang)]] -** Concurrency -- [[https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part1.html][Scheduling In Go (Series)]] - -** Garbage collection :GC: -- [[https://v8.dev/blog/high-performance-cpp-gc][GC on V8]] -- [[https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf][Perceus: Garbage Free Reference Counting with Reuse]] -*** [[https://www.hboehm.info/gc/][Boehm GC]] :Tool: -*** [[https://www.ravenbrook.com/project/mps/][MPS]] :Tool: -*** [[https://www.mmtk.io/code][MMTK]] :Tool: -*** [[https://github.com/JWesleySM/Whiro][Whiro]] :Tool: -This is not GC but a tool to debug GC and memory allocation. - -** JIT -- [[https://asmjit.com/][Machine code generator for C++]] -- https://www.youtube.com/watch?v=hILdR8XRvdQ&t=1511s - -** Optimizations -- [[https://sunfishcode.github.io/blog/2018/10/22/Canonicalization.html][Canonicalization]] - -** Compiler -- [[https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64][Stack frame layout on x86-64]] -*** Branch instructions -It would be cool to have macro to instruct the compiler about the likelyhood -of a branch in a conditional. Something similar to kernel's *likely* and *unlikely* -macros -*** How to learn compilers: LLVM Edition -https://lowlevelbits.org/how-to-learn-compilers-llvm-edition/ -*** Pointers Are Complicated III, or: Pointer-integer casts exposed -https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html -*** Execution Instrumentation -The compiler should be able to embed some code in the program to collect data about -the different execution paths or function instrumentation and other useful data the -can help the compiler to optimize the program even further. For example Imagine a -scenario which we compile a program with out any optimization ( in debug mode ) and -using some test cases or real usage of the program in several iteration we collect -data about the compiled application in a file (let's call it the ADF short for Analytic -Data File), and the we can pass that ADF file to the compiler to let it compile and optimize -the program by using the usual passes alonge side with some extra passes that operate -on ADF -** Lang -*** Scheme -- [[https://call-cc.org][Chicken Scheme - Easy-to-use compiler and interpreter, with lots of libraries]] -- [[https://github.com/barak/stalin][Stalin - Brutally optimizing Scheme compiler, with lots of optimization flags]] -** Utilities -- [[https://www.ralfj.de/blog/2020/12/14/provenance.html][Pointers Are Complicated]] -*** Emacs mode -- [[https://www.wilfred.me.uk/blog/2015/03/19/adding-a-new-language-to-emacs/][Adding A New Language to Emacs]] -- [[https://www.wilfred.me.uk/blog/2014/09/27/the-definitive-guide-to-syntax-highlighting/][The Definitive Guide To Syntax Highlighting]] - -** Linker -- [[https://lwn.net/Articles/276782/][20 part linker essay]] -- [[https://lld.llvm.org/index.html][LLD Usage]] -** LLVM -- [[https://blog.yossarian.net/2021/07/19/LLVM-internals-part-1-bitcode-format][LLVM Internals]] -*** TableGen -- [[https://llvm.org/docs/TableGen/BackGuide.html#creating-a-new-backend][Create a backend]] -** Toolchain -- https://llvm.org/docs/BuildingADistribution.html - -** Cross compilation - -- https://blog.gibson.sh/2017/11/26/creating-portable-linux-binaries/#some-general-suggestions - A nice to read article on some of the common problems when linking statically - with none default libc or libc++ - -** Useful courses and resources -- https://www.cs.cornell.edu/courses/cs6120/2020fa/lesson/ -- https://cs.lmu.edu/~ray/notes/languagedesignnotes/ -* Considerations -** Hashmaps -*** DOS attack -- https://www.anchor.com.au/blog/2012/12/how-to-explain-hash-dos-to-your-parents-by-using-cats/ -- https://en.wikipedia.org/wiki/Collision_attack -* Ideas -** Destructure types -Imagine a type that is a subset of a Coll, and when we -pass a Coll to its type constructor in destructs the input and -construct the type base on the data that it needs only and -leave the rest untouched -** Hot function optimization -it would be nice for the JIT to add instrumentation to the compiled -functions and detect hot functions similar to how javascript jits do it -and recompile those functions with more optimization passes -* Conversations -** Solutions to link other ~libc~ rather than the default -From my discassion with ~lhames~ -#+BEGIN_QUOTE -I can think of a few approaches with different trade-offs: -- Link your whole JIT (including LLVM) against musl rather than the default -- JIT'd - code uses the desired libc, there's only one libc in the JIT'd process, but the - cost is high (perhaps prohibitive, depending on your constraints) -- JIT out-of-process -- JIT (including LLVM) uses default libc and is compiled only once, - executor links the (alternative) desired libc at compile time and must be compiled each - time that you want to change it -- JIT'd code uses the desired libc, there's only one libc - in the JIT'd process, but the config is involved (requires a cross-process setup) -- JIT in process, link desired libc via JIT -- Easy to set up, but now you've got two - libcs in the process. I've never tested that config. It might just work, it might - fail at link or runtime in weird ways. -#+END_QUOTE -* TODOs -** Strings -*** TODO How to concat to strings in a functional and immutable way? -Should we include an pointer to another string??? -** TODO Create =Catch2= generators to be used in tests. Specially for the =reader= tests -** TODO Investigate possible implementanion for Internal Errors -- An option is to use llvm registry functionality like the one used in =clang-doc= instead of - =errorVariants= var. - -** TODO In =SereneContext::getLatestJITDylib= function, make sure that the JITDylib is still valid -Make sure that the returning Dylib still exists in the JIT -by calling =jit->engine->getJITDylibByName(dylib_name);= -** TODO Provide the CLI arguments to pass the =createTargetMachine=. -We need a way to tweak the target machine object. It's better to provide cli tools -to do so. -** TODO Walk the module and register the symbols with the engine (lazy and nonlazy) :JIT: -** TODO Change the compilation layer to accept MLIR modules instead of LLVM IR :JIT: -This way we can fine tune MLIR's passes based on the JIT settings as well -** TODO Create a pass to rename functions to include the ns name -** TODO Use =const= where ever it makes sense -** TODO Create different pass pipeline for different compilation phases -So we can use them directly via command line, like -O1 for example - -** TODO Investigate the huge size of serenec -So far it seems that the static linking and the lack of tree shaking is the issue -** DONE Add the support for =ns-paths= :serenecli:context: -CLOSED: [2021-09-25 Sat 19:22] -:LOGBOOK: -- State "DONE" from "TODO" [2021-09-25 Sat 19:22] -:END: -We need to add the support for an array of paths to lookup namespaces. The =ns-paths= should -be an array that each entry represents a path which serene has to look into in order to find -a namespace. For instance, when serene wants to load the =foo.bar= namespace, it should walk -the paths in =ns-paths= and look for that ns. Similar to =classpath= in the JVM or =LOAD_PATH= -in python. -- [ ] Add the support to the *Context*. -- [ ] Add the support to *Namespace*. -- [ ] Add the cli argument to the =bin/serene.cpp= - -** TODO Error handling -Create proper error handling for the internal infra -** TODO Replace =llvm::outs()= with debug statements -** TODO Move the generatable logic out of its files and remove them -** TODO Add a CLI option to get any extra pass -** TODO Add support for =sourcemgr= for input files -** TODO Language Spec :DOCS: -** TODO A proper List implementation -** TODO Vector implementation -** TODO Hashmap implementation -** TODO Meta data support -** TODO Docstring support :DOCS: -- [ ] For functions and macros -- [ ] For namespaces and projects -- [ ] API to interact with docstrings and helps -** TODO FFI interface -** TODO nREPL -** TODO Emacs mode :Misc: -** TODO Number implementation -** TODO String implementation -** TODO Enum implementation -** TODO Protocol -** TODO Struct implementation -** TODO Multi arity functions -** TODO QuasiQuotation -** TODO Linter :Misc: -** TODO Document generator :DOCS:Misc: -** TODO Spec like functionality -** TODO Laziness implementation -** TODO Investigate the Semantic Error tree and tracking -Basically we should be able to create an error tree on semantic analysis -time and trace semantic errors on different layers and intensively. -Is it a good idea ? -** Standard libraries -*** TODO IO library -*** TODO Test library diff --git a/devtools/CMakeLists.txt b/devtools/CMakeLists.txt deleted file mode 100644 index ab3f46e..0000000 --- a/devtools/CMakeLists.txt +++ /dev/null @@ -1,93 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -if (SERENE_ENABLE_DEVTOOLS) - -add_executable(slir-lsp-server slir-lsp-server.cpp) -add_executable(Serene::SLIR::LSP ALIAS slir-lsp-server) - -set_target_properties(slir-lsp-server PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -if(SERENE_ENABLE_TIDY) - set_target_properties(slir-lsp-server PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if (CPP_20_SUPPORT) - target_compile_features(slir-lsp-server PRIVATE cxx_std_20) -else() - target_compile_features(slir-lsp-server PRIVATE cxx_std_17) -endif() - - -target_link_libraries(slir-lsp-server - PRIVATE - Serene::lib - MLIRLspServerLib -) - -target_include_directories(slir-lsp-server PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(slir-lsp-server PRIVATE ${INCLUDE_DIR}) - -install(TARGETS slir-lsp-server - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - -# ======== -# slir-opt -# ======== -add_executable(slir-opt slir-opt.cpp) -add_executable(Serene::SLIR::Opt ALIAS slir-opt) - -set_target_properties(slir-opt PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -if(SERENE_ENABLE_TIDY) - set_target_properties(slir-opt PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if (CPP_20_SUPPORT) - target_compile_features(slir-opt PRIVATE cxx_std_20) -else() - target_compile_features(slir-opt PRIVATE cxx_std_17) -endif() - - -target_link_libraries(slir-opt - PRIVATE - Serene::lib - MLIROptLib -) - -target_include_directories(slir-opt PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(slir-opt PRIVATE ${INCLUDE_DIR}) - -install(TARGETS slir-opt - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - -endif() diff --git a/devtools/slir-lsp-server.cpp b/devtools/slir-lsp-server.cpp deleted file mode 100644 index 07fb3cc..0000000 --- a/devtools/slir-lsp-server.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/dialect.h" - -#include -#include -#include - -int main(int argc, char **argv) { - mlir::DialectRegistry registry; - - serene::slir::registerTo(registry); - - registry.insert(); - - // TODO: Register passes here - return static_cast( - mlir::failed(mlir::MlirLspServerMain(argc, argv, registry))); -} diff --git a/devtools/slir-opt.cpp b/devtools/slir-opt.cpp deleted file mode 100644 index 550cb5a..0000000 --- a/devtools/slir-opt.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/passes.h" -#include "serene/slir/dialect.h" - -#include -#include -#include -#include -#include - -int main(int argc, char **argv) { - mlir::DialectRegistry registry; - - serene::slir::registerTo(registry); - registry.insert(); - - serene::passes::registerAllPasses(); - - return static_cast( - mlir::failed(mlir::MlirOptMain(argc, argv, "slir-opt", registry))); -} diff --git a/libserene.v0/CMakeLists.txt b/libserene.v0/CMakeLists.txt deleted file mode 100644 index 3b31159..0000000 --- a/libserene.v0/CMakeLists.txt +++ /dev/null @@ -1,81 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -include_directories(${INCLUDE_DIR}) - -add_subdirectory(include) -add_subdirectory(lib) - -# Install rules for libserene target -install(TARGETS serene - EXPORT SereneExports - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - -# Install rules for the public header files. -install(DIRECTORY ${INCLUDE_DIR}/serene - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN *.h - PATTERN *.td - PATTERN "CMake*" EXCLUDE) - -# Install rule for the public generated header files -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN *.h - PATTERN *.td - PATTERN *.h.inc - PATTERN "CMake*" EXCLUDE) - -include(CMakePackageConfigHelpers) - -# Package config file let us use find_package with serene -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - - INSTALL_DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - ) - -write_basic_package_version_file( - "${PROJECT_NAME}ConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion - ) - -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - ) - -# Install the package exports -install(EXPORT SereneExports - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - NAMESPACE serene::) - -# Testing only available if this is the main app -# Emergency override SERENE_CMAKE_BUILD_TESTING provided as well -if(SERENE_BUILD_TESTING) - message("Build the test binary") - add_subdirectory(tests) -endif() diff --git a/libserene.v0/cmake/SereneConfig.cmake.in b/libserene.v0/cmake/SereneConfig.cmake.in deleted file mode 100644 index c638645..0000000 --- a/libserene.v0/cmake/SereneConfig.cmake.in +++ /dev/null @@ -1,21 +0,0 @@ - # Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Exports.cmake") - -check_required_components("@PROJECT_NAME@") diff --git a/libserene.v0/include/CMakeLists.txt b/libserene.v0/include/CMakeLists.txt deleted file mode 100644 index 1c51b2a..0000000 --- a/libserene.v0/include/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory("serene/slir/") -add_subdirectory("serene/passes/") -add_subdirectory("serene/errors/") diff --git a/libserene.v0/include/serene/config.h.in b/libserene.v0/include/serene/config.h.in deleted file mode 100644 index bc74d63..0000000 --- a/libserene.v0/include/serene/config.h.in +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -// the configured options and settings - -#define SERENE_VERSION "@PROJECT_VERSION@" - -// Why so obvious? to make the linter shutup :)) -#define I8_SIZE 8 -#define I32_SIZE 32 -#define I64_SIZE 64 - -// Should we build the support for MLIR CL OPTIONS? -#cmakedefine SERENE_WITH_MLIR_CL_OPTION - -#endif diff --git a/libserene.v0/include/serene/context.h b/libserene.v0/include/serene/context.h deleted file mode 100644 index 3a2a4aa..0000000 --- a/libserene.v0/include/serene/context.h +++ /dev/null @@ -1,285 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_CONTEXT_H -#define SERENE_CONTEXT_H - -#include "serene/diagnostics.h" -#include "serene/environment.h" -#include "serene/export.h" -#include "serene/jit/halley.h" -#include "serene/namespace.h" -#include "serene/passes.h" -#include "serene/slir/dialect.h" -#include "serene/source_mgr.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DEFAULT_NS_NAME "serene.user" -#define INTERNAL_NS "serene.internal" - -namespace serene { -class SereneContext; - -namespace reader { -class LocationRange; -} // namespace reader - -namespace exprs { -class Expression; -using Node = std::shared_ptr; -} // namespace exprs - -/// This enum describes the different operational phases for the compiler -/// in order. Anything below `NoOptimization` is considered only for debugging -enum class CompilationPhase { - Parse, - Analysis, - SLIR, - MLIR, // Lowered slir to other dialects - LIR, // Lowered to the llvm ir dialect - IR, // Lowered to the LLVMIR itself - NoOptimization, - O1, - O2, - O3, -}; - -/// Terminates the serene compiler process in a thread safe manner -SERENE_EXPORT void terminate(SereneContext &ctx, int exitCode); - -/// Options describes the compiler options that can be passed to the -/// compiler via command line. Anything that user should be able to -/// tweak about the compiler has to end up here regardless of the -/// different subsystem that might use it. -struct SERENE_EXPORT Options { - - /// Whether to use colors for the output or not - bool withColors = true; - - // JIT related flags - bool JITenableObjectCache = true; - bool JITenableGDBNotificationListener = true; - bool JITenablePerfNotificationListener = true; - bool JITLazy = false; - - Options() = default; -}; - -class SERENE_EXPORT SereneContext { - -public: - template - using CurrentNSFn = std::function; - - mlir::MLIRContext mlirContext; - mlir::PassManager pm; - std::unique_ptr diagEngine; - std::unique_ptr jit; - - /// The source manager is responsible for loading namespaces and practically - /// managing the source code in form of memory buffers. - SourceMgr sourceManager; - - /// The set of options to change the compilers behaivoirs - Options opts; - - const llvm::Triple triple; - - /// Insert the given `ns` into the context. The Context object is - /// the owner of all the namespaces. The `ns` will overwrite any - /// namespace with the same name. - void insertNS(NSPtr &ns); - - /// Execute the given function \p f by setting the `currentNS` - /// to the given \p nsName. It will restore the value of `currentNS` - /// after \p f returned. - template - T withCurrentNS(llvm::StringRef nsName, CurrentNSFn f) { - assert(!currentNS.empty() && "The currentNS is not initialized!"); - auto tmp = this->currentNS; - this->currentNS = nsName.str(); - - T res = f(); - this->currentNS = tmp; - return res; - }; - - // void specialization - template <> - void withCurrentNS(llvm::StringRef nsName, CurrentNSFn f) { - assert(!currentNS.empty() && "The currentNS is not initialized!"); - auto tmp = this->currentNS; - this->currentNS = nsName.str(); - - f(); - this->currentNS = tmp; - } - - /// Return the current namespace that is being processed at the moment - Namespace &getCurrentNS(); - - /// Lookup the namespace with the give name in the current context and - /// return a pointer to it or a `nullptr` in it doesn't exist. - Namespace *getNS(llvm::StringRef nsName); - - /// Lookup and return a shared pointer to the given \p ns_name. This - /// method should be used only if you need to own the namespace as well - /// and want to keep it long term (like the JIT). - NSPtr getSharedPtrToNS(llvm::StringRef nsName); - - SereneContext(Options &options) - : pm(&mlirContext), diagEngine(makeDiagnosticEngine(*this)), - opts(options), triple(llvm::sys::getDefaultTargetTriple()), - targetPhase(CompilationPhase::NoOptimization) { - mlirContext.getOrLoadDialect(); - mlirContext.getOrLoadDialect(); - mlirContext.getOrLoadDialect(); - - // We need to create one empty namespace, so that the JIT can - // start it's operation. - auto ns = Namespace::make(*this, DEFAULT_NS_NAME, std::nullopt); - - insertNS(ns); - currentNS = ns->name; - - // TODO: Get the crash report path dynamically from the cli - // pm.enableCrashReproducerGeneration("/home/lxsameer/mlir.mlir"); - }; - - /// Set the target compilation phase of the compiler. The compilation - /// phase dictates the behavior and the output type of the compiler. - void setOperationPhase(CompilationPhase phase); - - CompilationPhase getTargetPhase() { return targetPhase; }; - int getOptimizatioLevel(); - - // Namespace stuff --- - - /// Create an empty namespace with the given \p name and optional \p filename - /// and then insert it into the context - NSPtr makeNamespace(llvm::StringRef name, - std::optional filename); - - /// Read a namespace with the given \p name and returns a share pointer - /// to the name or an Error. - /// - /// It just `read` the namespace by parsing it and running the semantic - /// analyzer on it. - MaybeNS readNamespace(const std::string &name); - MaybeNS readNamespace(const std::string &name, reader::LocationRange loc); - - /// Reads and add the namespace with the given \p name to the context. The - /// namespace will be added to the context and the JIT engine as well. - /// - /// It will \r a shared pointer to the namespace or an error tree. - MaybeNS importNamespace(const std::string &name); - MaybeNS importNamespace(const std::string &name, reader::LocationRange loc); - // --- - - static std::unique_ptr genLLVMContext() { - return std::make_unique(); - }; - - static std::unique_ptr make(Options &options) { - auto ctx = std::make_unique(options); - auto *ns = ctx->getNS(DEFAULT_NS_NAME); - - assert(ns != nullptr && "Default ns doesn't exit!"); - - auto maybeJIT = serene::jit::makeHalleyJIT(*ctx); - - if (!maybeJIT) { - auto err = maybeJIT.takeError(); - panic(*ctx, err); - } - - ctx->jit.swap(*maybeJIT); - - // Make serene.user which is the defult NS available on the - // JIT - auto loc = reader::LocationRange::UnknownLocation(INTERNAL_NS); - if (auto err = ctx->jit->addNS(*ns, loc)) { - panic(*ctx, err); - } - - return ctx; - }; - - // JIT JITDylib related functions --- - - // TODO: For Dylib related functions, make sure that the namespace in questoin - // is aleady registered in the context - - /// Return a pointer to the most registered JITDylib of the given \p ns - ////name - llvm::orc::JITDylib *getLatestJITDylib(Namespace &ns); - - /// Register the given pointer to a `JITDylib` \p l, with the give \p ns. - void pushJITDylib(Namespace &ns, llvm::orc::JITDylib *l); - - /// Returns the number of registered `JITDylib` for the given \p ns. - size_t getNumberOfJITDylibs(Namespace &ns); - -private: - CompilationPhase targetPhase; - - // TODO: We need to keep different instances of the namespace - // because if any one of them gets cleaned up via reference - // count (if we are still using shared ptr for namespaces if not - // remove this todo) then we will end up with dangling references - // it the JIT - - /// The namespace table. Every namespace that needs to be compiled has - /// to register itself with the context and appear on this table. - /// This table acts as a cache as well. - std::map namespaces; - - /// Why string vs pointer? We might rewrite the namespace and - /// holding a pointer means that it might point to the old version - std::string currentNS; - - /// A vector of pointers to all the jitDylibs for namespaces. Usually - /// There will be only one pre NS but in case of forceful reloads of a - /// namespace there will be more. - llvm::StringMap> jitDylibs; -}; - -/// Creates a new context object. Contexts are used through out the compilation -/// process to store the state. -/// -/// \p opts is an instance of \c Options that can be used to set options of -/// of the compiler. -SERENE_EXPORT std::unique_ptr -makeSereneContext(Options opts = Options()); - -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/conventions.h b/libserene.v0/include/serene/conventions.h deleted file mode 100644 index eebe34f..0000000 --- a/libserene.v0/include/serene/conventions.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_CONVENTIONS_H -#define SERENE_CONVENTIONS_H - -#include "serene/config.h" - -#include - -#include - -namespace serene { -// static std::string mangleInternalStringName(llvm::StringRef str) { -// return "__serene__internal__str__" + str.str(); -// } - -// static std::string mangleInternalSymName(llvm::StringRef str) { -// return "__serene__symbol__" + str.str(); -// } - -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/diagnostics.h b/libserene.v0/include/serene/diagnostics.h deleted file mode 100644 index 48b3a37..0000000 --- a/libserene.v0/include/serene/diagnostics.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - * `DiagEngine` is in charge of error handling of the compiler. It receives - * the incoming errors (`llvm::Error`) and print them out to stderr. - * - * Errors might raise from different contextes and the incoming channel might - * vary. For exmaple in many case we just return `llvm::Error` from functions - * and propagate them to the highest level call site and deal with them there - * or during the pass management we call the `emit()` function on operations - * to report back an error. - * - * Serene extends `llvm::Error`. For more info have a look at - * `serene/errors/base.h` and the `serene/errors/errors.td`. - */ - -#ifndef SERENE_DIAGNOSTICS_H -#define SERENE_DIAGNOSTICS_H - -#include "serene/errors.h" -#include "serene/export.h" -#include "serene/reader/location.h" -#include "serene/source_mgr.h" - -#include -#include -#include - -#include - -namespace serene { -class SereneContext; -class DiagnosticEngine; - -// TODO: Finish up the Diagnostic interface and utility functions -// to build diagnostics from Errors - -class Diagnostic { - // TODO: Add support for llvm::SMFixIt - friend DiagnosticEngine; - - enum Type { - Error, - - // TODO: Add support for remarks and notes - Remark, - Note, - }; - - SereneContext &ctx; - reader::LocationRange loc; - std::string fn; - llvm::Error *err = nullptr; - Type type = Type::Error; - std::string message, lineContents; - - std::string getPrefix(llvm::StringRef prefix = ""); - -public: - Diagnostic(SereneContext &ctx, reader::LocationRange loc, llvm::Error *e, - llvm::StringRef msg, llvm::StringRef fn = "") - : ctx(ctx), loc(loc), fn(fn), err(e), message(msg){}; - -protected: - void print(llvm::raw_ostream &os, llvm::StringRef prefix = "") const; - void writeColorByType(llvm::raw_ostream &os, llvm::StringRef str); -}; - -/// DiagnosticEngine is the central hub for dealing with errors in Serene. It -/// integrates with MLIR's diag engine and LLVM's error system to handle error -/// reporting for Serene's compiler -class DiagnosticEngine { - SereneContext &ctx; - - mlir::DiagnosticEngine &diagEngine; - - Diagnostic toDiagnostic(reader::LocationRange loc, llvm::Error &e, - llvm::StringRef msg, llvm::StringRef fn = ""); - - void print(llvm::raw_ostream &os, Diagnostic &d); - -public: - DiagnosticEngine(SereneContext &ctx); - - void enqueueError(llvm::StringRef msg); - void emitSyntaxError(reader::LocationRange loc, llvm::Error &e, - llvm::StringRef msg = ""); - - void emit(const llvm::Error &err); -}; - -/// Create a new instance of the `DiagnosticEngine` from the give -/// `SereneContext` -std::unique_ptr makeDiagnosticEngine(SereneContext &ctx); - -// ---------------------------------------------------------------------------- -// Public API -// ---------------------------------------------------------------------------- - -/// Throw out an error with the given \p and terminate the execution. -SERENE_EXPORT void panic(SereneContext &ctx, llvm::Twine msg); - -/// Throw out the give error \p err and stop the execution. -SERENE_EXPORT void panic(SereneContext &ctx, const llvm::Error &err); - -/// Throw the give `llvm::Error` \p errs to the stderr. -SERENE_EXPORT void throwErrors(SereneContext &ctx, const llvm::Error &err); -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/environment.h b/libserene.v0/include/serene/environment.h deleted file mode 100644 index 4a7b4e5..0000000 --- a/libserene.v0/include/serene/environment.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TEST_ENVIRONMENT_H -#define SERENE_TEST_ENVIRONMENT_H - -#include "serene/utils.h" - -#include -#include - -namespace serene { - -/// This class represents a classic lisp environment (or scope) that holds the -/// bindings from type `K` to type `V`. For example an environment of symbols -/// to expressions would be `Environment` -template -class Environment { - - Environment *parent; - - using StorageType = llvm::StringMap; - // The actual bindings storage - StorageType pairs; - -public: - Environment() : parent(nullptr) {} - Environment(Environment *parent) : parent(parent){}; - - /// Look up the given `key` in the environment and return it. - std::optional lookup(llvm::StringRef key) { - if (auto value = pairs.lookup(key)) { - return value; - } - - if (parent) { - return parent->lookup(key); - } - - return std::nullopt; - }; - - /// Insert the given `key` with the given `value` into the storage. This - /// operation will shadow an aleady exist `key` in the parent environment - mlir::LogicalResult insert_symbol(llvm::StringRef key, V value) { - auto result = pairs.insert_or_assign(key, value); - UNUSED(result); - return mlir::success(); - }; - - inline typename StorageType::iterator begin() { return pairs.begin(); } - - inline typename StorageType::iterator end() { return pairs.end(); } - - inline typename StorageType::const_iterator begin() const { - return pairs.begin(); - } - inline typename StorageType::const_iterator end() const { - return pairs.end(); - } -}; - -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/errors.h b/libserene.v0/include/serene/errors.h deleted file mode 100644 index 0626857..0000000 --- a/libserene.v0/include/serene/errors.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_ERRORS_H -#define SERENE_ERRORS_H - -#include "serene/export.h" -#include "serene/reader/location.h" - -#define GET_CLASS_DEFS -#include "serene/errors/errs.h.inc" - -#include -#include - -namespace serene { -class SereneContext; -} // namespace serene - -namespace serene::errors { - -class SERENE_EXPORT SereneError : public llvm::ErrorInfo { -public: - static char ID; - ErrorType errorType; - - SereneContext &ctx; - reader::LocationRange location; - std::string msg; - - void log(llvm::raw_ostream &os) const override { os << msg; } - - std::error_code convertToErrorCode() const override { - // TODO: Fix this by creating a mapping from ErrorType to standard - // errc or return the ErrorType number instead - return std::make_error_code(std::errc::io_error); - } - - SereneError(SereneContext &ctx, ErrorType errtype, reader::LocationRange &loc) - : errorType(errtype), ctx(ctx), location(loc){}; - - SereneError(SereneContext &ctx, ErrorType errtype, reader::LocationRange &loc, - llvm::StringRef msg) - : errorType(errtype), ctx(ctx), location(loc), msg(msg.str()){}; - - reader::LocationRange &where() { return location; }; -}; - -/// Create and return a Serene flavored `llvm::Error` by passing the parameters -/// directly to the constructor of type `E`. -/// -/// This is the official way of creating error objects in Serene. -template -SERENE_EXPORT llvm::Error makeError(SereneContext &ctx, ErrorType errtype, - Args &&...args) { - return llvm::make_error(ctx, errtype, - std::forward(args)...); -}; - -/// Returns the messange that the given error \p e is holding. It doesn't cast -/// the error to a concrete error type. -SERENE_EXPORT std::string getMessage(const llvm::Error &e); - -SERENE_EXPORT const ErrorVariant *getVariant(ErrorType t); -} // namespace serene::errors - -#endif diff --git a/libserene.v0/include/serene/errors/CMakeLists.txt b/libserene.v0/include/serene/errors/CMakeLists.txt deleted file mode 100644 index 5c8aaac..0000000 --- a/libserene.v0/include/serene/errors/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS errors.td) - -serene_tablegen(errs.h.inc -errors-backend) - -add_public_tablegen_target(SereneErrorGen) diff --git a/libserene.v0/include/serene/errors/base.h b/libserene.v0/include/serene/errors/base.h deleted file mode 100644 index 788095b..0000000 --- a/libserene.v0/include/serene/errors/base.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_ERRORS_BASE_H -#define SERENE_ERRORS_BASE_H - -#include "serene/export.h" -#include "serene/reader/location.h" - -#define GET_CLASS_DEFS -#include "serene/errors/errs.h.inc" - -#include - -#include -#include - -namespace serene::errors { - -class SERENE_EXPORT Error {}; - -class SERENE_EXPORT SereneError : public llvm::ErrorInfo { -public: - static char ID; - ErrorType errorType; - - SereneContext &ctx; - reader::LocationRange location; - std::string msg; - - void log(llvm::raw_ostream &os) const override { os << msg; } - - std::error_code convertToErrorCode() const override { - // TODO: Fix this by creating a mapping from ErrorType to standard - // errc or return the ErrorType number instead - return std::make_error_code(std::errc::io_error); - } - - SereneError(SereneContext &ctx, ErrorType errtype, reader::LocationRange &loc) - : errorType(errtype), ctx(ctx), location(loc){}; - - SereneError(SereneContext &ctx, ErrorType errtype, reader::LocationRange &loc, - llvm::StringRef msg) - : errorType(errtype), ctx(ctx), location(loc), msg(msg.str()){}; - - reader::LocationRange &where() { return location; }; -}; - -}; // namespace serene::errors -#endif diff --git a/libserene.v0/include/serene/errors/errors.td b/libserene.v0/include/serene/errors/errors.td deleted file mode 100644 index 71b64d7..0000000 --- a/libserene.v0/include/serene/errors/errors.td +++ /dev/null @@ -1,76 +0,0 @@ - - -class Error { - string desc = _desc; - string help = _help; -} - -// Examples of how to define a new error -// def Err : Error<"Err1 titel"> { -// let description = [{ -// err1 -// multiline -// desc}]; -// } - -// def Err2 : Error { -// let title = "err 2 titel"; -// let description = "err2 desc"; -// } - -// def Err3 : Error<"err3", [{ -// err3 -// multiline -// desc -// }]>; - -def UnknownError: Error<"Can't find any description for this error.">; - -def DefExpectSymbol: Error<"The first argument to 'def' has to be a Symbol.">; - -def DefWrongNumberOfArgs: Error<"Wrong number of arguments is passed to the 'def' form.">; - -def FnNoArgsList: Error<"'fn' form requires an argument list.">; - -def FnArgsMustBeList: Error<"'fn' arguments should be a list.">; - -def CantResolveSymbol: Error<"Can't resolve the given name.">; - -def DontKnowHowToCallNode: Error<"Don't know how to call the given expression.">; - -def PassFailureError: Error<"Pass Failure.">; - -def NSLoadError: Error<"Faild to find a namespace.">; - -def NSAddToSMError: Error<"Faild to add the namespace to the source manager.">; - -def - EOFWhileScaningAList: Error<"EOF reached before closing of list">; - -def InvalidDigitForNumber: Error<"Invalid digit for a number.">; - -def - TwoFloatPoints: Error<"Two or more float point characters in a number">; - -def - InvalidCharacterForSymbol: Error<"Invalid character for a symbol">; - -def CompilationError: Error<"Compilation error!">; - -defvar errorsIndex = [ - UnknownError, - DefExpectSymbol, - DefWrongNumberOfArgs, - FnNoArgsList, - FnArgsMustBeList, - CantResolveSymbol, - DontKnowHowToCallNode, - PassFailureError, - NSLoadError, - NSAddToSMError, - EOFWhileScaningAList, - InvalidDigitForNumber, - TwoFloatPoints, - InvalidCharacterForSymbol, - CompilationError, -]; diff --git a/libserene.v0/include/serene/errors/variant.h b/libserene.v0/include/serene/errors/variant.h deleted file mode 100644 index 11e5a17..0000000 --- a/libserene.v0/include/serene/errors/variant.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_ERRORS_VARIANT_H -#define SERENE_ERRORS_VARIANT_H - -#include - -namespace serene::errors { - -// This class is used in the generated code -struct ErrorVariant { - const int id; - const std::string title; - const std::string desc; - const std::string help; - - static ErrorVariant make(const int id, const char *t, const char *d, - const char *h) { - return ErrorVariant(id, t, d, h); - }; - -private: - ErrorVariant(const int id, const char *t, const char *d, const char *h) - : id(id), title(t), desc(d), help(h){}; -}; -} // namespace serene::errors -#endif diff --git a/libserene.v0/include/serene/exprs/call.h b/libserene.v0/include/serene/exprs/call.h deleted file mode 100644 index ce0cdf5..0000000 --- a/libserene.v0/include/serene/exprs/call.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_CALL_H -#define SERENE_EXPRS_CALL_H - -#include "serene/context.h" -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" - -#include -#include - -#include -#include - -namespace serene { - -namespace exprs { -class List; - -/// This data structure represents a function. with a collection of -/// arguments and the ast of a body -class Call : public Expression { - -public: - Node target; - Ast params; - - Call(reader::LocationRange &loc, Node &target, Ast ¶ms) - : Expression(loc), target(target), params(params){}; - - Call(Call &) = delete; - - ExprType getType() const override; - std::string toString() const override; - MaybeNode analyze(semantics::AnalysisState &state) override; - void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) override { - UNUSED(ns); - UNUSED(m); - }; - - static bool classof(const Expression *e); - - /// Creates a call node out of a list. - /// For exmaple: `(somefn (param1 param2) param3)`. This function - /// is supposed to be used in the semantic analysis phase. - /// - /// \param ctx The semantic analysis context object. - /// \param env The environment that this node exists in. - /// \param list the list in question. - static MaybeNode make(semantics::AnalysisState &state, List *list); - - ~Call() = default; -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/def.h b/libserene.v0/include/serene/exprs/def.h deleted file mode 100644 index 82165c3..0000000 --- a/libserene.v0/include/serene/exprs/def.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_DEF_H -#define SERENE_EXPRS_DEF_H - -#include "serene/context.h" -#include "serene/errors.h" -#include "serene/exprs/expression.h" - -#include -#include - -#include -#include - -namespace serene { - -namespace exprs { -class List; - -/// This data structure represents the operation to define a new binding via -/// the `def` special form. -class Def : public Expression { - -public: - std::string binding; - Node value; - - Def(reader::LocationRange &loc, llvm::StringRef binding, Node &v) - : Expression(loc), binding(binding), value(v){}; - - Def(Def &d) = delete; - - ExprType getType() const override; - std::string toString() const override; - - MaybeNode analyze(semantics::AnalysisState &state) override; - void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) override; - - static bool classof(const Expression *e); - - /// Create a Def node out a list. The list should contain the - /// correct `def` form like `(def blah value)`. This function - /// is supposed to be used in the semantic analysis phase. - /// - /// \param state is the semantic analysis state to use in creation time. - /// \param list the list containing the `def` form - static MaybeNode make(semantics::AnalysisState &state, List *list); - - ~Def() = default; -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/expression.h b/libserene.v0/include/serene/exprs/expression.h deleted file mode 100644 index 127f491..0000000 --- a/libserene.v0/include/serene/exprs/expression.h +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_EXPRESSION_H -#define SERENE_EXPRS_EXPRESSION_H - -#include "serene/context.h" -#include "serene/errors.h" -#include "serene/exprs/traits.h" -#include "serene/namespace.h" -#include "serene/reader/location.h" -#include "serene/semantics.h" -#include "serene/utils.h" - -#include -#include - -#include - -namespace serene { - -/// Contains all the builtin AST expressions including those which do not appear -/// in the syntax directly. Like function definitions. -namespace exprs { - -class Expression; - -using Node = std::shared_ptr; -using MaybeNode = llvm::Expected; - -using Ast = std::vector; -using MaybeAst = llvm::Expected; - -constexpr static auto EmptyNode = nullptr; - -/// The base class of the expressions which provides the common interface for -/// the expressions to implement. -class SERENE_EXPORT 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; - - /// Analyzes the semantics of current node and return a new node in case - /// that we need to semantically rewrite the current node and replace it with - /// another node. For example to change from a List containing `(def a b)` - /// to a `Def` node that represents defining a new binding. - /// - /// \param state is the analysis state object of the semantic analyzer. - virtual MaybeNode analyze(semantics::AnalysisState &state) = 0; - - /// Genenates the correspondig SLIR of the expressoin and attach it to the - /// given module. - /// - /// \param ns The namespace that current expression is in it. - /// \param m The target MLIR moduleOp to attach the operations to - virtual void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) = 0; -}; - -/// 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(); -/// \endcode -/// -/// \param[args] Any argument with any type passed to this function will be -/// passed to the constructor of type T. -/// \return A unique pointer to an Expression -template -Node make(Args &&...args) { - return std::make_shared(std::forward(args)...); -}; -/// 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 = makeAndCast(); -/// \endcode -/// -/// \param[args] Any argument with any type passed to this function will be -/// passed to the constructor of type T. -/// \return A unique pointer to a value of type T. -template -std::shared_ptr makeAndCast(Args &&...args) { - return std::make_shared(std::forward(args)...); -}; - -/// The helper function to create a new `Node` and returnsit. It should be useds -/// where every we want to return a `MaybeNode` successfully. -template -MaybeNode makeSuccessfulNode(Args &&...args) { - return make(std::forward(args)...); -}; - -/// The hlper function to creates an Error (`llvm::Error`) by passing all -/// the given arguments to the constructor of the template param `E`. -template -llvm::Expected makeErrorful(Args &&...args) { - return llvm::make_error(std::forward(args)...); -}; - -/// The hlper function to creates an Error (`llvm::Error`) by passing all -/// the given arguments to the constructor of the template param `E`. -template -MaybeNode makeErrorNode(Args &&...args) { - return makeErrorful(std::forward(args)...); -}; - -/// Convert the given AST to string by calling the `toString` method -/// of each node. -SERENE_EXPORT std::string astToString(const Ast *); -/// Converts the given ExprType to string. -std::string stringifyExprType(ExprType); - -/// Converts the given AST to string and prints it out -void dump(Ast &); - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/fn.h b/libserene.v0/include/serene/exprs/fn.h deleted file mode 100644 index cb2192a..0000000 --- a/libserene.v0/include/serene/exprs/fn.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_FN_H -#define SERENE_EXPRS_FN_H - -#include "serene/context.h" -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/namespace.h" - -#include -#include - -#include -#include - -namespace serene { - -namespace exprs { -class List; - -/// This data structure represents a function. with a collection of -/// arguments and the ast of a body -class Fn : public Expression { - -public: - std::string name; - - // TODO: Use a coll type instead of a list here - List args; - Ast body; - - Fn(SereneContext &ctx, reader::LocationRange &loc, List &args, Ast body); - - Fn(Fn &f) = delete; - - ExprType getType() const override; - std::string toString() const override; - MaybeNode analyze(semantics::AnalysisState &state) override; - void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) override; - - static bool classof(const Expression *e); - - /// Creates a function node out of a function definition - /// in a list. the list has to contain the correct definition - /// of a function, for exmaple: `(fn (args1 arg2) body)`.This function - /// is supposed to be used in the semantic analysis phase. - /// - /// \param state is the semantic analysis state to use. - /// \param list the list containing the `fn` form - static MaybeNode make(semantics::AnalysisState &state, List *list); - - void setName(std::string); - ~Fn() = default; -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/list.h b/libserene.v0/include/serene/exprs/list.h deleted file mode 100644 index 28225f2..0000000 --- a/libserene.v0/include/serene/exprs/list.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_LIST_H -#define SERENE_EXPRS_LIST_H - -#include "serene/context.h" -#include "serene/export.h" -#include "serene/exprs/expression.h" - -#include - -#include - -namespace serene { - -namespace exprs { - -/// This class represents a List in the AST level and not the List as the data -/// type. -class SERENE_EXPORT List : public Expression { -public: - // Internal elements of the lest (small vector of shared pointers to - // expressions) - Ast elements; - - List(const List &l); // Copy ctor - List(List &&e) noexcept = default; // Move ctor - - List(const reader::LocationRange &loc) : Expression(loc){}; - List(const reader::LocationRange &loc, Node &e); - List(const reader::LocationRange &loc, Ast elems); - - ExprType getType() const override; - std::string toString() const override; - - void append(Node); - - size_t count() const; - - Ast from(uint index); - - std::optional at(uint index); - - /// Return an iterator to be used with the `for` loop. It's implicitly called - /// by the for loop. - std::vector::const_iterator cbegin(); - - /// Return an iterator to be used with the `for` loop. It's implicitly called - /// by the for loop. - std::vector::const_iterator cend(); - - /// Return an iterator to be used with the `for` loop. It's implicitly called - /// by the for loop. - std::vector::iterator begin(); - - /// Return an iterator to be used with the `for` loop. It's implicitly called - /// by the for loop. - std::vector::iterator end(); - - MaybeNode analyze(semantics::AnalysisState &state) override; - // NOLINTNEXTLINE(readability-named-parameter) - void generateIR(serene::Namespace &, mlir::ModuleOp &) override{}; - - ~List() = default; - - static bool classof(const Expression *e); -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/number.h b/libserene.v0/include/serene/exprs/number.h deleted file mode 100644 index 828a14a..0000000 --- a/libserene.v0/include/serene/exprs/number.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_NUMBER_H -#define SERENE_EXPRS_NUMBER_H - -#include "serene/context.h" -#include "serene/export.h" -#include "serene/exprs/expression.h" -#include "serene/namespace.h" - -#include - -namespace serene { -namespace exprs { - -/// This data structure represent a number. I handles float points, integers, -/// positive and negative numbers. This is not a data type representative. -/// So it won't cast to actual numeric types and it has a string container -/// to hold the parsed value. -struct SERENE_EXPORT Number : public Expression { - - // TODO: Use a variant here instead to store different number types - 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 override; - std::string toString() const override; - - MaybeNode analyze(semantics::AnalysisState &state) override; - void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) override; - - // TODO: This is horrible, we need to fix it after the mvp - int toI64() const; - - ~Number() = default; - - static bool classof(const Expression *e); -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/symbol.h b/libserene.v0/include/serene/exprs/symbol.h deleted file mode 100644 index a1f7b0a..0000000 --- a/libserene.v0/include/serene/exprs/symbol.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_SYMBOL_H -#define SERENE_EXPRS_SYMBOL_H - -#include "serene/context.h" -#include "serene/export.h" -#include "serene/exprs/expression.h" -#include "serene/namespace.h" - -#include - -#include - -namespace serene { - -namespace exprs { - -/// This data structure represent the Lisp symbol. Just a symbol -/// in the context of the AST and nothing else. -class SERENE_EXPORT Symbol : public Expression { - -public: - std::string name; - std::string nsName; - - Symbol(const reader::LocationRange &loc, llvm::StringRef name, - llvm::StringRef currentNS) - : Expression(loc) { - // IMPORTANT NOTE: the `name` and `currentNS` should be valid string and - // already validated. - auto partDelimiter = name.find('/'); - if (partDelimiter == std::string::npos) { - nsName = currentNS.str(); - this->name = name.str(); - - } else { - this->name = name.substr(partDelimiter + 1, name.size()).str(); - nsName = name.substr(0, partDelimiter).str(); - } - }; - - Symbol(Symbol &s) : Expression(s.location) { - this->name = s.name; - this->nsName = s.nsName; - } - - ExprType getType() const override; - std::string toString() const override; - - MaybeNode analyze(semantics::AnalysisState &state) override; - void generateIR(serene::Namespace &ns, mlir::ModuleOp &m) override { - UNUSED(ns); - UNUSED(m); - }; - - ~Symbol() = default; - - static bool classof(const Expression *e); -}; - -} // namespace exprs -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/exprs/traits.h b/libserene.v0/include/serene/exprs/traits.h deleted file mode 100644 index 9fcb7f8..0000000 --- a/libserene.v0/include/serene/exprs/traits.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_EXPRS_TRAITS_H -#define SERENE_EXPRS_TRAITS_H - -#include "serene/context.h" -#include "serene/reader/location.h" -#include "serene/reader/traits.h" -#include "serene/traits.h" -#include "serene/utils.h" - -namespace serene::exprs { -/// This enum represent the expression type and **not** the value type. -enum class ExprType { - Symbol, - List, - Number, - Def, - Error, - Fn, - Call, -}; - -/// The string represantion of built in expr types (NOT DATATYPES). -static const char *exprTypes[] = { - "Symbol", "List", "Number", "Def", "Error", "Fn", "Call", -}; - -}; // namespace serene::exprs - -#endif diff --git a/libserene.v0/include/serene/jit/README.org b/libserene.v0/include/serene/jit/README.org deleted file mode 100644 index a2b2525..0000000 --- a/libserene.v0/include/serene/jit/README.org +++ /dev/null @@ -1,18 +0,0 @@ -#+TITLE: Serene JIT -#+AUTHOR: Sameer Rahmani -#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty nolatexpreview -#+OPTIONS: tex:t -* SereneJIT -** Development Notes -*** Steps to take -You usually want a custom =MaterializationUnit= for your program representation, and a custom =Layer=. The Layer will have two -operations: =add= and =emit=. The =add= operation takes an instance of your program representation, builds one of your custom -=MaterializationUnits= to hold it, then adds it to a =JITDylib=. The =emit= operation takes a =MaterializationResponsibility= -object and an instance of your program representation and materializes it, usually by compiling it and handing the resulting -object off to an =ObjectLinkingLayer=. - -Your custom =MaterializationUnit= will have two operations: =materialize= and =discard=. The =materialize= function will be -called for you when any symbol provided by the unit is looked up, and it should just call the =emit= function on your layer, -passing in the given =MaterializationResponsibility= and the wrapped program representation. The =discard= function will be -called if some weak symbol provided by your unit is not needed (because the JIT found an overriding definition). -You can use this to drop your definition early, or just ignore it and let the linker drop the definition later. diff --git a/libserene.v0/include/serene/jit/engine.h b/libserene.v0/include/serene/jit/engine.h deleted file mode 100644 index f96fb37..0000000 --- a/libserene.v0/include/serene/jit/engine.h +++ /dev/null @@ -1,180 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - */ - -// TODO: Look at the LLJITBuilderState::prepareForConstruction to setup the -// object linking layer - -#ifndef SERENE_JIT_ENGINE_H -#define SERENE_JIT_ENGINE_H - -#include "serene/jit/layers.h" -#include "serene/namespace.h" - -#include // for ConcurrentIRCompiler -#include -#include -#include // for DynamicLibrarySearchGenerator -#include -#include -#include -#include -#include -#include - -#include - -#define JIT_LOG(...) \ - DEBUG_WITH_TYPE("jit", llvm::dbgs() << "[JIT]: " << __VA_ARGS__ << "\n"); - -namespace orc = llvm::orc; - -namespace serene { - -class SereneContext; - -namespace jit { - -class SereneJIT { - /// An ExecutionSession represents a running JIT program. - std::unique_ptr es; - - std::unique_ptr epciu; - - llvm::DataLayout dl; - - /// Mangler in responsible for changing the symbol names based on our - /// naming convention. - orc::MangleAndInterner mangler; - - // Layers ------------------------------------------------------------------- - // Serene's JIT follows the same design as the ORC and uses the framework that - // it provides. - // - // Layers are the building blocks of the JIT and work on top of each other - // to add different functionalities to the JIT. Order is important here and - // layers call each other and pa - - /// The object linking layer allows object files to be added to the JIT - orc::RTDyldObjectLinkingLayer objectLayer; - - /// The compiler layer is responsible to compile the LLVMIR to target code - /// for us - orc::IRCompileLayer compileLayer; - - // TODO: Enable these two layers when we add the `Platform support` - // std::unique_ptr transformLayer; - // std::unique_ptr initHelperTransformLayer; - - // orc::CompileOnDemandLayer compileOnDemandLayer; - - /// Transform layaer is responsible for running a pass pipeline on the AST - /// and generate LLVM IR - orc::IRTransformLayer transformLayer; - - // The AST Layer reads and import the Serene Ast directly to the JIT - AstLayer astLayer; - - /// NS layer is responsible for adding namespace to the JIT by name. - /// It will import the entire namespace. - NSLayer nsLayer; - - /// This a symbol table tha holds symbols from whatever code we execute - orc::JITDylib &mainJD; - - serene::SereneContext &ctx; - - /// The name of the NS which we are in it at the moment. - std::string inNS; - - static llvm::Expected - optimizeModule(orc::ThreadSafeModule tsm, - const orc::MaterializationResponsibility &r) { - // TSM.withModuleDo([](Module &M) { - // // Create a function pass manager. - // auto FPM = std::make_unique(&M); - - // // Add some optimizations. - // FPM->add(createInstructionCombiningPass()); - // FPM->add(createReassociatePass()); - // FPM->add(createGVNPass()); - // FPM->add(createCFGSimplificationPass()); - // FPM->doInitialization(); - - // // Run the optimizations over all functions in the module being added - // to - // // the JIT. - // for (auto &F : M) - // FPM->run(F); - // }); - UNUSED(r); - return std::move(tsm); - } - - Namespace ¤tNS; - -public: - SereneJIT(Namespace &entryNS, std::unique_ptr es, - std::unique_ptr epciu, - orc::JITTargetMachineBuilder jtmb, llvm::DataLayout &&dl); - - ~SereneJIT() { - // if (compileThreads) { - // compileThreads->wait(); - // } - - if (auto err = es->endSession()) { - es->reportError(std::move(err)); - } - }; - - Namespace &getCurrentNS() { return currentNS; } - - const llvm::DataLayout &getDataLayout() const { return dl; } - - orc::JITDylib &getMainJITDylib() { return mainJD; } - - llvm::Error addModule(orc::ThreadSafeModule tsm, - orc::ResourceTrackerSP rt = nullptr) { - if (!rt) { - rt = mainJD.getDefaultResourceTracker(); - } - - return compileLayer.add(rt, std::move(tsm)); - } - - llvm::Error addNS(llvm::StringRef nsname, - orc::ResourceTrackerSP rt = nullptr); - - llvm::Error addAst(exprs::Ast &ast, orc::ResourceTrackerSP rt = nullptr); - - llvm::Expected lookup(llvm::StringRef name) { - JIT_LOG("Looking up symbol: " + name); - return es->lookup({&mainJD}, mangler(name.str())); - } -}; - -llvm::Expected> makeSereneJIT(Namespace &ns); - -}; // namespace jit -}; // namespace serene - -#endif diff --git a/libserene.v0/include/serene/jit/halley.h b/libserene.v0/include/serene/jit/halley.h deleted file mode 100644 index 8b70dcb..0000000 --- a/libserene.v0/include/serene/jit/halley.h +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - This is the first working attempt on building a JIT engine for Serene - and named after Edmond Halley. - - - It supports both ASTs and Namespaces - - Every Namespace might have one or more JITDylibs. Depends on the method - of the compilation. - - It operates in lazy (for REPL) and non-lazy mode and wraps LLJIT - and LLLazyJIT - - It uses an object cache layer to cache module (not NSs) objects. - */ - -#ifndef SERENE_JIT_HALLEY_H -#define SERENE_JIT_HALLEY_H - -#include "serene/errors.h" -#include "serene/export.h" -#include "serene/namespace.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define HALLEY_LOG(...) \ - DEBUG_WITH_TYPE("halley", llvm::dbgs() \ - << "[HALLEY]: " << __VA_ARGS__ << "\n"); - -namespace serene { - -class SereneContext; -class Namespace; - -namespace exprs { -class Symbol; -} // namespace exprs - -namespace jit { -class Halley; - -using MaybeJIT = llvm::Expected>; -using MaybeJITPtr = llvm::Expected; - -/// A simple object cache following Lang's LLJITWithObjectCache example and -/// MLIR's SimpelObjectCache. -class ObjectCache : public llvm::ObjectCache { -public: - /// Cache the given `objBuffer` for the given module `m`. The buffer contains - /// the combiled objects of the module - void notifyObjectCompiled(const llvm::Module *m, - llvm::MemoryBufferRef objBuffer) override; - - // Lookup the cache for the given module `m` or returen a nullptr. - std::unique_ptr getObject(const llvm::Module *m) override; - - /// Dump cached object to output file `filename`. - void dumpToObjectFile(llvm::StringRef filename); - -private: - llvm::StringMap> cachedObjects; -}; - -class SERENE_EXPORT Halley { - // TODO: Replace this with a variant of LLJIT and LLLazyJIT - std::unique_ptr engine; - std::unique_ptr cache; - - /// GDB notification listener. - llvm::JITEventListener *gdbListener; - - /// Perf notification listener. - llvm::JITEventListener *perfListener; - - llvm::orc::JITTargetMachineBuilder jtmb; - llvm::DataLayout &dl; - SereneContext &ctx; - - std::shared_ptr activeNS; - - bool isLazy = false; - -public: - Halley(serene::SereneContext &ctx, llvm::orc::JITTargetMachineBuilder &&jtmb, - llvm::DataLayout &&dl); - - static MaybeJIT make(serene::SereneContext &ctx, - llvm::orc::JITTargetMachineBuilder &&jtmb); - - void setEngine(std::unique_ptr e, bool isLazy); - /// Looks up a packed-argument function with the given sym name and returns a - /// pointer to it. Propagates errors in case of failure. - MaybeJITPtr lookup(exprs::Symbol &sym) const; - - /// Invokes the function with the given name passing it the list of opaque - /// pointers to the actual arguments. - // llvm::Error - // invokePacked(llvm::StringRef name, - // llvm::MutableArrayRef args = std::nullopt) const; - - /// Trait that defines how a given type is passed to the JIT code. This - /// defaults to passing the address but can be specialized. - template - struct Argument { - static void pack(llvm::SmallVectorImpl &args, T &val) { - args.push_back(&val); - } - }; - - /// Tag to wrap an output parameter when invoking a jitted function. - template - struct FnResult { - FnResult(T &result) : value(result) {} - T &value; - }; - - /// Helper function to wrap an output operand when using - /// ExecutionEngine::invoke. - template - static FnResult result(T &t) { - return FnResult(t); - } - - // Specialization for output parameter: their address is forwarded directly to - // the native code. - template - struct Argument> { - static void pack(llvm::SmallVectorImpl &args, FnResult &result) { - args.push_back(&result.value); - } - }; - - /// Invokes the function with the given name passing it the list of arguments - /// by value. Function result can be obtain through output parameter using the - /// `FnResult` wrapper defined above. For example: - /// - /// func @foo(%arg0 : i32) -> i32 attributes { llvm.emit_c_interface } - /// - /// can be invoked: - /// - /// int32_t result = 0; - /// llvm::Error error = jit->invoke("foo", 42, - /// result(result)); - // template - // llvm::Error invoke(llvm::StringRef funcName, Args... args) { - // const std::string adapterName = std::string("") + funcName.str(); - // llvm::SmallVector argsArray; - // // Pack every arguments in an array of pointers. Delegate the packing to - // a - // // trait so that it can be overridden per argument type. - // // TODO: replace with a fold expression when migrating to C++17. - // int dummy[] = {0, ((void)Argument::pack(argsArray, args), 0)...}; - // (void)dummy; - // return invokePacked(adapterName, argsArray); - // }; - - void dumpToObjectFile(llvm::StringRef filename); - - llvm::Error addNS(Namespace &ns, reader::LocationRange &loc); - - llvm::Error addAST(exprs::Ast &ast); - - Namespace &getActiveNS(); -}; - -llvm::Expected> makeHalleyJIT(SereneContext &ctx); - -} // namespace jit -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/jit/layers.h b/libserene.v0/include/serene/jit/layers.h deleted file mode 100644 index e28842e..0000000 --- a/libserene.v0/include/serene/jit/layers.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_JIT_LAYERS_H -#define SERENE_JIT_LAYERS_H - -#include "serene/namespace.h" -#include "serene/reader/location.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include -#include - -#define LAYER_LOG(...) \ - DEBUG_WITH_TYPE("layer", llvm::dbgs() << "[Layer]: " << __VA_ARGS__ << "\n"); - -namespace orc = llvm::orc; - -namespace serene { -class SereneContext; -class Namespace; - -namespace exprs { -class Expression; -using Node = std::shared_ptr; -using Ast = std::vector; -} // namespace exprs - -namespace jit { - -class AstLayer; - -/// This will compile the ast to llvm ir. -llvm::orc::ThreadSafeModule compileAst(Namespace &ns, exprs::Ast &ast); - -class AstMaterializationUnit : public orc::MaterializationUnit { -public: - AstMaterializationUnit(Namespace &ns, AstLayer &l, exprs::Ast &ast); - - llvm::StringRef getName() const override { - return "SereneAstMaterializationUnit"; - } - - void - materialize(std::unique_ptr r) override; - -private: - void discard(const orc::JITDylib &jd, - const orc::SymbolStringPtr &sym) override { - UNUSED(jd); - UNUSED(sym); - llvm_unreachable("Serene functions are not overridable"); - } - - Namespace &ns; - AstLayer &astLayer; - exprs::Ast * -}; - -class AstLayer { - orc::IRLayer &baseLayer; - orc::MangleAndInterner &mangler; - -public: - AstLayer(orc::IRLayer &baseLayer, orc::MangleAndInterner &mangler) - : baseLayer(baseLayer), mangler(mangler){}; - - llvm::Error add(orc::ResourceTrackerSP &rt, Namespace &ns, exprs::Ast &ast) { - return rt->getJITDylib().define( - std::make_unique(ns, *this, ast), rt); - } - - void emit(std::unique_ptr mr, - Namespace &ns, exprs::Ast &e) { - - baseLayer.emit(std::move(mr), compileAst(ns, e)); - } - orc::MaterializationUnit::Interface getInterface(Namespace &ns, - exprs::Ast &e); -}; - -/// NS Layer ================================================================== -class NSLayer; - -/// This will compile the NS to llvm ir. -llvm::orc::ThreadSafeModule compileNS(Namespace &ns); - -class NSMaterializationUnit : public orc::MaterializationUnit { -public: - NSMaterializationUnit(NSLayer &l, Namespace &ns); - - llvm::StringRef getName() const override { return "NSMaterializationUnit"; } - - void - materialize(std::unique_ptr r) override; - -private: - void discard(const orc::JITDylib &jd, - const orc::SymbolStringPtr &sym) override { - UNUSED(jd); - UNUSED(sym); - llvm_unreachable("Serene functions are not overridable"); - // TODO: Check the ctx to see whether we need to remove the sym or not - } - - NSLayer &nsLayer; - Namespace &ns; -}; - -/// NS Layer is responsible for adding namespaces to the JIT -class NSLayer { - serene::SereneContext &ctx; - orc::IRLayer &baseLayer; - orc::MangleAndInterner &mangler; - const llvm::DataLayout &dl; - -public: - NSLayer(SereneContext &ctx, orc::IRLayer &baseLayer, - orc::MangleAndInterner &mangler, const llvm::DataLayout &dl) - : ctx(ctx), baseLayer(baseLayer), mangler(mangler), dl(dl){}; - - llvm::Error add(orc::ResourceTrackerSP &rt, llvm::StringRef nsname) { - auto loc = serene::reader::LocationRange::UnknownLocation(nsname); - - return add(rt, nsname, loc); - } - - llvm::Error add(orc::ResourceTrackerSP &rt, llvm::StringRef nsname, - serene::reader::LocationRange &loc); - - void emit(std::unique_ptr mr, - serene::Namespace &ns) { - // TODO: We need to pass dl to the compilerNS later to aviod recreating - // the data layout all the time - UNUSED(dl); - LAYER_LOG("Emit namespace"); - baseLayer.emit(std::move(mr), compileNS(ns)); - } - - orc::MaterializationUnit::Interface getInterface(serene::Namespace &ns); -}; -} // namespace jit -} // namespace serene -#endif diff --git a/libserene.v0/include/serene/llvm/IR/Value.h b/libserene.v0/include/serene/llvm/IR/Value.h deleted file mode 100644 index fac0004..0000000 --- a/libserene.v0/include/serene/llvm/IR/Value.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef LLVM_IR_VALUE_H -#define LLVM_IR_VALUE_H - -#pragma clang diagnostic ignored "-Wunused-parameter" -#include - -#endif diff --git a/libserene.v0/include/serene/llvm/patches.h b/libserene.v0/include/serene/llvm/patches.h deleted file mode 100644 index c348f6b..0000000 --- a/libserene.v0/include/serene/llvm/patches.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LLVM_PATCHES_H -#define LLVM_PATCHES_H - -#include -#include - -namespace llvm { - -// Our specialization of DensMapInfo for string type. This will allow use to use -// string -template <> -struct DenseMapInfo { - static inline std::string getEmptyKey() { return ""; } - - static inline std::string getTombstoneKey() { - // Maybe we need to use something else beside strings ???? - return "0TOMBED"; - } - - static unsigned getHashValue(const std::string &Val) { - assert(Val != getEmptyKey() && "Cannot hash the empty key!"); - assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!"); - return (unsigned)(llvm::hash_value(Val)); - } - - static bool isEqual(const std::string &LHS, const std::string &RHS) { - if (RHS == getEmptyKey()) { - return LHS == getEmptyKey(); - } - if (RHS == getTombstoneKey()) { - return LHS == getTombstoneKey(); - } - return LHS == RHS; - } -}; - -} // namespace llvm - -#endif diff --git a/libserene.v0/include/serene/namespace.h b/libserene.v0/include/serene/namespace.h deleted file mode 100644 index 245661e..0000000 --- a/libserene.v0/include/serene/namespace.h +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - * Rules of a namespace: - * - A namespace has have a name and it has to own it. - * - A namespace may or may not be associated with a file - * - The internal AST of a namespace is an evergrowing tree which may expand at - * any given time. For example via iteration of a REPL - * - `environments` vector is the owner of all the semantic envs - * - The first env in the `environments` is the root env. - * - * How to create a namespace ? - * The official way to create a namespace object is to use the `SereneContext` - * object and call `readNamespace`, `importNamespace` or `makeNamespace`. - */ - -// TODO: Add a mechanism to figure out whether a namespace has changed or not -// either on memory or disk - -#ifndef SERENE_NAMESPACE_H -#define SERENE_NAMESPACE_H - -#include "serene/environment.h" -#include "serene/errors.h" -#include "serene/export.h" -#include "serene/slir/generatable.h" -#include "serene/traits.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define NAMESPACE_LOG(...) \ - DEBUG_WITH_TYPE("NAMESPACE", llvm::dbgs() << __VA_ARGS__ << "\n"); - -namespace serene { -class SereneContext; -class Namespace; - -namespace exprs { -class Expression; -using Node = std::shared_ptr; -using Ast = std::vector; -} // namespace exprs - -using NSPtr = std::shared_ptr; -using MaybeNS = llvm::Expected; -using MaybeModule = std::optional; -using MaybeModuleOp = std::optional>; -using SemanticEnv = Environment; -using SemanticEnvPtr = std::unique_ptr; -using SemanticEnvironments = std::vector; -using Form = std::pair; -using Forms = std::vector
; - -/// Serene's namespaces are the unit of compilation. Any code that needs to be -/// compiled has to be in a namespace. The official way to create a new -/// namespace is to use the `readNamespace`, `importNamespace` and -/// `makeNamespace` member functions of `SereneContext`. -class SERENE_EXPORT Namespace { - friend SereneContext; - -private: - SereneContext &ctx; - - // Anonymous function counter. We need to assing a unique name to each - // anonymous function and we use this counter to generate those names - std::atomic fn_counter = 0; - - /// The content of the namespace. It should alway hold a semantically - /// correct AST. It means thet the AST that we want to store here has - /// to pass the semantic analyzer checks. - exprs::Ast tree; - - SemanticEnvironments environments; - - std::vector symbolList; - -public: - std::string name; - std::optional filename; - - /// Create a naw namespace with the given `name` and optional `filename` and - /// return a shared pointer to it in the given Serene context. - static NSPtr make(SereneContext &ctx, llvm::StringRef name, - std::optional filename); - - Namespace(SereneContext &ctx, llvm::StringRef ns_name, - std::optional filename); - - /// Create a new environment with the give \p parent as the parent, - /// push the environment to the internal environment storage and - /// return a reference to it. The namespace itself is the owner of - /// environments. - SemanticEnv &createEnv(SemanticEnv *parent); - - /// Return a referenece to the top level (root) environment of ns. - SemanticEnv &getRootEnv(); - - /// Define a new binding in the root environment with the given \p name - /// and the given \p node. Defining a new binding with a name that - /// already exists in legal and will overwrite the previous binding and - /// the given name will point to a new value from now on. - mlir::LogicalResult define(std::string &name, exprs::Node &node); - - /// Add the given \p ast to the namespace and return any possible error. - /// The given \p ast will be added to a vector of ASTs by expanding - /// the tree vector to contain \p ast. - /// - /// This function runs the semantic analyzer on the \p ast as well. - llvm::Error addTree(exprs::Ast &ast); - - exprs::Ast &getTree(); - - const std::vector &getSymList() { return symbolList; }; - - /// Increase the function counter by one - uint nextFnCounter(); - - SereneContext &getContext(); - - /// Generate and return a MLIR ModuleOp tha contains the IR of the namespace - /// with respect to the compilation phase - MaybeModuleOp generate(unsigned offset = 0); - - /// Compile the namespace to a llvm module. It will call the - /// `generate` method of the namespace to generate the IR. - MaybeModule compileToLLVM(); - - /// Compile the given namespace from the given \p offset of AST till the end - /// of the trees. - MaybeModule compileToLLVMFromOffset(unsigned offset); - - /// Run all the passes specified in the context on the given MLIR ModuleOp. - mlir::LogicalResult runPasses(mlir::ModuleOp &m); - - /// Dumps the namespace with respect to the compilation phase - void dump(); - - ~Namespace(); -}; - -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/passes.h b/libserene.v0/include/serene/passes.h deleted file mode 100644 index 9ec33e3..0000000 --- a/libserene.v0/include/serene/passes.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_PASSES_H -#define SERENE_PASSES_H - -#include "serene/export.h" - -#include - -#define PASS_LOG(...) \ - DEBUG_WITH_TYPE("PASSES", llvm::dbgs() << __VA_ARGS__ << "\n"); - -namespace serene::passes { - -/// Return a pass to lower the serene.symbol op -SERENE_EXPORT std::unique_ptr createLowerSymbol(); - -SERENE_EXPORT void registerAllPasses(); -/// Return a pass to convert SLIR dialect to built-in dialects -/// of MLIR. -std::unique_ptr createSLIRLowerToMLIRPass(); - -/// Return a pass to convert different dialects of MLIR to LLVM dialect. -std::unique_ptr createSLIRLowerToLLVMDialectPass(); - -} // namespace serene::passes - -#endif diff --git a/libserene.v0/include/serene/passes/CMakeLists.txt b/libserene.v0/include/serene/passes/CMakeLists.txt deleted file mode 100644 index 0b30d08..0000000 --- a/libserene.v0/include/serene/passes/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS passes.td) - -mlir_tablegen(passes.h.inc -gen-pass-decls) - -if(SERENE_ENABLE_DOCS) - mlir_tablegen(passes.md.inc -gen-pass-doc) -endif() - -add_public_tablegen_target(SerenePassGen) diff --git a/libserene.v0/include/serene/passes/passes.td b/libserene.v0/include/serene/passes/passes.td deleted file mode 100644 index 6627a8f..0000000 --- a/libserene.v0/include/serene/passes/passes.td +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_PASSES_TD -#define SERENE_PASSES_TD - -include "mlir/Pass/PassBase.td" - - -// TODO: When we add and utilize namespace operations we need -// use NsOp instead of the ModuleOp for root of lowering -def LowerSLIR : Pass<"lower-slir", "mlir::ModuleOp"> { - let summary = "Lowers the SLIR dialect to LLVM IR indirectly"; - - let description = [{ - Lowers the SLIR dialect to LLVM IR indirectly meaning - that it will lower SLIR to other dialects that in turn will - eventually lower to llvm ir. - }]; - - // This is how we can create the default instance of this pass. - // via `createLowerSymbol` function - let constructor = "serene::passes::createLowerSLIR()"; - let dependentDialects = ["mlir::func::FuncDialect", "mlir::arith::ArithmeticDialect"]; - -} - -#endif // SERENE_PASSES_TD diff --git a/libserene.v0/include/serene/reader/location.h b/libserene.v0/include/serene/reader/location.h deleted file mode 100644 index 9b0526e..0000000 --- a/libserene.v0/include/serene/reader/location.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_READER_LOCATION_H -#define SERENE_READER_LOCATION_H - -#include -#include - -#include - -namespace serene { -class SereneContext; - -namespace reader { - -/// It represents a location in the input string to the parser via `line`, -struct Location { - /// Since namespaces are our unit of compilation, we need to have - /// a namespace in hand - llvm::StringRef ns; - - std::optional filename = std::nullopt; - /// A pointer to the character that this location is pointing to - /// it the input buffer - const char *c = nullptr; - - /// At this stage we only support 65535 lines of code in each file - unsigned short int line = 0; - /// At this stage we only support 65535 chars in each line - unsigned short int col = 0; - - bool knownLocation = true; - - ::std::string toString() const; - - Location() = default; - Location(llvm::StringRef ns, - std::optional fname = std::nullopt, - const char *c = nullptr, unsigned short int line = 0, - unsigned short int col = 0, bool knownLocation = true) - : ns(ns), filename(fname), c(c), line(line), col(col), - knownLocation(knownLocation){}; - - Location clone() const; - - mlir::Location toMLIRLocation(SereneContext &ctx); - - /// Returns an unknown location for the given \p ns. - static Location UnknownLocation(llvm::StringRef ns) { - return Location(ns, std::nullopt, nullptr, 0, 0, false); - } -}; - -class LocationRange { -public: - Location start; - Location end; - - LocationRange() = default; - LocationRange(Location _start) : start(_start), end(_start){}; - LocationRange(Location _start, Location _end) : start(_start), end(_end){}; - // LocationRange(const LocationRange &); - - bool isKnownLocation() const { return start.knownLocation; }; - - static LocationRange UnknownLocation(llvm::StringRef ns) { - return LocationRange(Location::UnknownLocation(ns)); - } -}; - -void incLocation(Location &, const char *); -void decLocation(Location &, const char *); - -} // namespace reader -} // namespace serene -#endif diff --git a/libserene.v0/include/serene/reader/reader.h b/libserene.v0/include/serene/reader/reader.h deleted file mode 100644 index f5ba731..0000000 --- a/libserene.v0/include/serene/reader/reader.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - * `Reader` is the base parser class and accepts a buffer like objenct (usually - * `llvm::StringRef`) as the input and parsess it to create an AST (look at the - * `serene::exprs::Expression` class). - * - * The parsing algorithm is quite simple and it is a LL(2). It means that, we - * start parsing the input from the very first character and parse the input - * one char at a time till we reach the end of the input. Please note that - * when we call the `advance` function to move forward in the buffer, we - * can't go back. In order to look ahead in the buffer without moving in the - * buffer we use the `nextChar` method. - * - * We have dedicated methods to read different forms like `list`, `symbol` - * `number` and etc. Each of them return a `MaybeNode` that in the success - * case contains the node and an `Error` on the failure case. - */ - -#ifndef SERENE_READER_READER_H -#define SERENE_READER_READER_H - -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" -#include "serene/reader/location.h" -#include "serene/serene.h" - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define READER_LOG(...) \ - DEBUG_WITH_TYPE("READER", llvm::dbgs() \ - << "[READER]: " << __VA_ARGS__ << "\n"); - -namespace serene::reader { - -/// Base reader class which reads from a string directly. -class Reader { -private: - SereneContext &ctx; - - llvm::StringRef ns; - std::optional filename; - - const char *currentChar = NULL; - - llvm::StringRef buf; - - /// The position tracker that we will use to determine the end of the - /// buffer since the buffer might not be null terminated - size_t currentPos = -1; - - Location currentLocation; - - bool readEOL = false; - - /// Returns a clone of the current location - Location getCurrentLocation(); - /// Returns the next character from the stream. - /// @param skip_whitespace An indicator to whether skip white space like chars - /// or not - void advance(bool skipWhitespace = false); - void advanceByOne(); - - const char *nextChar(bool skipWhitespace = false, unsigned count = 1); - - /// Returns a boolean indicating whether the given input character is valid - /// for an identifier or not. - static bool isValidForIdentifier(char c); - - // The property to store the ast tree - exprs::Ast ast; - - exprs::MaybeNode readSymbol(); - exprs::MaybeNode readNumber(bool); - exprs::MaybeNode readList(); - exprs::MaybeNode readExpr(); - - bool isEndOfBuffer(const char *); - -public: - Reader(SereneContext &ctx, llvm::StringRef buf, llvm::StringRef ns, - std::optional filename); - Reader(SereneContext &ctx, llvm::MemoryBufferRef buf, llvm::StringRef ns, - std::optional filename); - - // void setInput(const llvm::StringRef string); - - /// Parses the the input and creates a possible AST out of it or errors - /// otherwise. - exprs::MaybeAst read(); - - ~Reader(); -}; - -/// Parses the given `input` string and returns a `Result` -/// which may contains an AST or an `llvm::Error` -SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, llvm::StringRef input, - llvm::StringRef ns, - std::optional filename); -SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, - llvm::MemoryBufferRef input, - llvm::StringRef ns, - std::optional filename); -} // namespace serene::reader - -#endif diff --git a/libserene.v0/include/serene/reader/traits.h b/libserene.v0/include/serene/reader/traits.h deleted file mode 100644 index cd7d264..0000000 --- a/libserene.v0/include/serene/reader/traits.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_READER_TRAITS_H -#define SERENE_READER_TRAITS_H - -#include "serene/reader/location.h" -#include "serene/traits.h" - -namespace serene::reader { - -template -class ILocatable : public TraitBase { -public: - ILocatable(){}; - ILocatable(const ILocatable &) = delete; - serene::reader::LocationRange &where() const { - return this->Object().where(); - } -}; - -template -serene::reader::LocationRange &where(ILocatable &); -} // namespace serene::reader -#endif diff --git a/libserene.v0/include/serene/semantics.h b/libserene.v0/include/serene/semantics.h deleted file mode 100644 index 966baef..0000000 --- a/libserene.v0/include/serene/semantics.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SEMANTICS_H -#define SERENE_SEMANTICS_H - -#include "serene/environment.h" -#include "serene/errors.h" -#include "serene/export.h" -#include "serene/utils.h" - -#include - -#include - -namespace serene { - -namespace exprs { -class Expression; -using Node = std::shared_ptr; -using Ast = std::vector; -}; // namespace exprs - -class Namespace; -using SemanticEnv = Environment; -namespace semantics { - -using AnalyzeResult = llvm::Expected; - -/// This struct represent the state necessary for each analysis job. -struct AnalysisState { - Namespace &ns; - SemanticEnv &env; - - AnalysisState(Namespace &ns, SemanticEnv &env) : ns(ns), env(env){}; - - std::unique_ptr moveToNewEnv(); -}; - -/// Create an new `AnalysisState` by forwarding all parameters off this -/// function directly to the ctor of `AnalysisState` and returns a -/// unique pointer to the state. -template -std::unique_ptr makeAnalysisState(Args &&...args) { - return std::make_unique(std::forward(args)...); -}; - -/// The entry point to the Semantic analysis phase. It calls the `analyze` -/// method of each node in the given \p form and creates a new AST that -/// contains a more comprehensive set of nodes in a semantically correct -/// AST. If the `analyze` method of a node return a `nullptr` value then the -/// original node will be used instead. Any possible error will be returned. -/// -/// \param state The semantic analysis state that keep track of the envs. -/// \param form The actual AST in question. -SERENE_EXPORT AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms); - -} // namespace semantics -} // namespace serene -#endif diff --git a/libserene.v0/include/serene/serene.h b/libserene.v0/include/serene/serene.h deleted file mode 100644 index 037e807..0000000 --- a/libserene.v0/include/serene/serene.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SERENE_H -#define SERENE_SERENE_H - -#include "serene/config.h" -#include "serene/context.h" -#include "serene/export.h" -#include "serene/exprs/expression.h" -#include "serene/source_mgr.h" - -namespace serene { - -/// Clinet applications have to call this function before any interaction with -/// the Serene's compiler API. -SERENE_EXPORT void initCompiler(); - -/// Register the global CLI options of the serene compiler. If the client -/// application needs to setup the compilers options automatically use this -/// function in conjunction with `applySereneCLOptions`. -SERENE_EXPORT void registerSereneCLOptions(); - -/// Applies the global compiler options on the give \p SereneContext. This -/// function has to be called after `llvm::cl::ParseCommandLineOptions`. -SERENE_EXPORT void applySereneCLOptions(SereneContext &ctx); - -/// \brief Reads the the given \p input as Serene source code in the given -/// \c SereneContext \p ctx and returns the possible AST tree of the input or an -/// error otherwise. -/// -/// If any thing goes wrong it will return an \return \c llvm::Error describing -/// the issue. -/// -/// Be aware than this function reads the input in the context of the current -/// namespace. So for example if the input is somthing like: -/// -/// (ns example.code) .... -/// -/// and the current ns is `user` then if there is a syntax error in the input -/// the error will be reported under the `user` ns. This is logical because -/// this function reads the code and not evaluate it. the `ns` form has to be -/// evaluated in order to change the ns. -SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, std::string &input); - -/// Evaluates the given AST form \p input in the given \c SereneContext \p ctx -/// and retuns a new expression as the result or a possible error. -/// -/// In case of an error Serene will throw the error messages vis the diagnostic -/// engine as well and the error that this function returns will be the -/// generic error message. -SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast &input); - -// TODO: Return a Serene String type instead of the std::string -// TODO: Create an overload to get a stream instead of the result string -/// Prints the given AST form \p input in the given \c SereneContext \p ctx -/// into the given \p result. -/// Note: print is a lisp action. Don't confuse it with a print function such -/// as `println`. -SERENE_EXPORT void print(SereneContext &ctx, const exprs::Ast &input, - std::string &result); - -} // namespace serene -#endif diff --git a/libserene.v0/include/serene/slir/CMakeLists.txt b/libserene.v0/include/serene/slir/CMakeLists.txt deleted file mode 100644 index efa02d9..0000000 --- a/libserene.v0/include/serene/slir/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -set(LLVM_TARGET_DEFINITIONS dialect.td) -mlir_tablegen(ops.h.inc -gen-op-decls) -mlir_tablegen(ops.cpp.inc -gen-op-defs) - -mlir_tablegen(attrs.h.inc -gen-attrdef-decls) -mlir_tablegen(attrs.cpp.inc -gen-attrdef-defs) -mlir_tablegen(types.h.inc -gen-typedef-decls ) -mlir_tablegen(types.cpp.inc -gen-typedef-defs) - -mlir_tablegen(dialect.h.inc -gen-dialect-decls) -mlir_tablegen(dialect.cpp.inc -gen-dialect-defs) -add_public_tablegen_target(SereneDialectGen) diff --git a/libserene.v0/include/serene/slir/dialect.h b/libserene.v0/include/serene/slir/dialect.h deleted file mode 100644 index 84057c1..0000000 --- a/libserene.v0/include/serene/slir/dialect.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef SERENE_SLIR_DIALECT_H -#define SERENE_SLIR_DIALECT_H - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Include the auto-generated header file containing the declaration of the -// serene's dialect. -#include "serene/slir/dialect.h.inc" -#include "serene/slir/types.h" - -namespace serene::slir { -SERENE_EXPORT void registerTo(mlir::DialectRegistry ®istry); -} // namespace serene::slir - // -#endif // SERENE_SLIR_DIALECT_H diff --git a/libserene.v0/include/serene/slir/dialect.td b/libserene.v0/include/serene/slir/dialect.td deleted file mode 100644 index aae1382..0000000 --- a/libserene.v0/include/serene/slir/dialect.td +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_DIALECT_TD -#define SERENE_DIALECT_TD - - -include "mlir/IR/OpBase.td" -include "mlir/IR/OpAsmInterface.td" -include "mlir/IR/AttrTypeBase.td" -include "mlir/Interfaces/SideEffectInterfaces.td" -include "mlir/Interfaces/ControlFlowInterfaces.td" -include "mlir/Interfaces/InferTypeOpInterface.td" -include "mlir/Interfaces/DataLayoutInterfaces.td" -include "mlir/Interfaces/VectorInterfaces.td" - -// Dialect definition. It will directly generate the SereneDialect class -def Serene_Dialect : Dialect { - let name = "serene"; - let cppNamespace = "::serene::slir"; - let summary = "Primary IR of serene language."; - let description = [{ - This dialect tries to map the special forms of a lisp into - IR level operations. - }]; - - // All the types have to define a mnemonic - let useDefaultTypePrinterParser = 1; - - // TODO: Uncomment this when ever we have custom attrs - // All the attributes have to define a mnemonic - // let useDefaultAttributePrinterParser = 1; - - let dependentDialects = [ - "mlir::arith::ArithmeticDialect", - "mlir::func::FuncDialect", - "mlir::LLVM::LLVMDialect" - ]; - - let extraClassDeclaration = [{ - /// Register all the Serene types - void registerType(); - }]; -} - - -include "types.td" -include "ops.td" - -// ============================================================================ -// Old operations that are we need to replace -// ============================================================================ -def Value1Op: Serene_Op<"value1"> { - let summary = "This operation represent a compile time value"; - let description = [{ - ValueOp represent a value in compile time. For example: - - ```mlir - %0 = "serene.value"(){value = 3} : () -> i64 - ``` - }]; - - let arguments = (ins I64Attr:$value); - let results = (outs I64); - - //let verifier = [{ return serene::sir::verify(*this); }]; - - let builders = [ - OpBuilder<(ins "int":$value), [{ - // Build from fix 64 bit int - build(odsBuilder, odsState, odsBuilder.getI64Type(), (uint64_t) value); - }]>, - - ]; -} - -def Fn1Op: Serene_Op<"fn1", [ - AffineScope, AutomaticAllocationScope, - IsolatedFromAbove, -]> { - - let summary = "This operation is just a place holder for a function"; - let description = [{ - A place holder for an anonymous function. For example consider an expression - like `(def a (fn (x) x))`, in this case we don't immediately create an anonymous - function since we need to set the name and create the function later. - }]; - - let arguments = (ins StrAttr:$name, - DictionaryAttr:$args, - OptionalAttr:$sym_visibility); - - let regions = (region AnyRegion:$body); - let results = (outs FnType); - -} - -def Return1Op: Serene_Op<"return", [NoSideEffect, HasParent<"Fn1Op">, - ReturnLike, Terminator]> { - - let summary = "This operation marks the return value of a function"; - let description = [{ - ReturnOp - }]; - - let arguments = (ins AnyType:$operand); - let assemblyFormat = - [{ attr-dict $operand `:` type($operand) }]; -} - -#endif // SERENE_DIALECT diff --git a/libserene.v0/include/serene/slir/generatable.h b/libserene.v0/include/serene/slir/generatable.h deleted file mode 100644 index 30f9f5f..0000000 --- a/libserene.v0/include/serene/slir/generatable.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SLIR_GENERATABLE_H -#define SERENE_SLIR_GENERATABLE_H - -#include "serene/slir/dialect.h" -#include "serene/traits.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace serene { -class Namespace; -class SereneContext; -} // namespace serene - -namespace serene::slir { - -template -class GeneratableUnit : public TraitBase { -public: - GeneratableUnit(){}; - GeneratableUnit(const GeneratableUnit &) = delete; - - void generate(serene::Namespace &ns) { - // TODO: should we return any status or possible error here or - // should we just populate them in a ns wide state? - this->Object().generateIR(ns); - }; -}; - -template -class Generatable : public TraitBase { -public: - Generatable(){}; - Generatable(const Generatable &) = delete; - - mlir::LogicalResult generate() { return this->Object().generate(); }; - mlir::LogicalResult runPasses() { return this->Object().runPasses(); }; - - mlir::ModuleOp &getModule() { return this->Object().getModule(); }; - serene::SereneContext &getContext() { return this->Object().getContext(); }; - - void dump() { this->Object().dump(); }; -}; - -template -mlir::LogicalResult generate(Generatable &t) { - return t.generate(); -}; - -template -std::unique_ptr toLLVMIR(Generatable &t) { - auto &module = t.getModule(); - auto &ctx = t.getContext(); - // Register the translation to LLVM IR with the MLIR context. - mlir::registerLLVMDialectTranslation(ctx.mlirContext); - - // Convert the module to LLVM IR in a new LLVM IR context. - auto llvmModule = mlir::translateModuleToLLVMIR(module, ctx.llvmContext); - if (!llvmModule) { - // TODO: Return a Result type instead - llvm::errs() << "Failed to emit LLVM IR\n"; - throw std::runtime_error("Failed to emit LLVM IR\n"); - } - - // Initialize LLVM targets. - llvm::InitializeNativeTarget(); - // llvm::InitializeNativeTargetAsmPrinter(); - - // TODO: replace this call with our own version of setupTargetTriple - mlir::ExecutionEngine::setupTargetTriple(llvmModule.get()); - - /// Optionally run an optimization pipeline over the llvm module. - auto optPipeline = mlir::makeOptimizingTransformer( - /*optLevel=*/ctx.getOptimizatioLevel(), /*sizeLevel=*/0, - /*targetMachine=*/nullptr); - if (auto err = optPipeline(llvmModule.get())) { - llvm::errs() << "Failed to optimize LLVM IR " << err << "\n"; - throw std::runtime_error("Failed to optimize LLVM IR"); - } - - return std::move(llvmModule); -}; - -template -void dump(Generatable &t) { - t.dump(); -}; - -} // namespace serene::slir - -#endif diff --git a/libserene.v0/include/serene/slir/ops.h b/libserene.v0/include/serene/slir/ops.h deleted file mode 100644 index 4e0be10..0000000 --- a/libserene.v0/include/serene/slir/ops.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_DIALECT_OPS_H -#define SERENE_DIALECT_OPS_H - -#include "serene/slir/types.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define GET_OP_CLASSES -#include "serene/slir/ops.h.inc" - -#endif diff --git a/libserene.v0/include/serene/slir/ops.td b/libserene.v0/include/serene/slir/ops.td deleted file mode 100644 index 5c12137..0000000 --- a/libserene.v0/include/serene/slir/ops.td +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_DIALECT_OPS_TD -#define SERENE_DIALECT_OPS_TD - -include "mlir/IR/OpBase.td" -include "mlir/Interfaces/CallInterfaces.td" -include "mlir/IR/RegionKindInterface.td" -include "mlir/IR/SymbolInterfaces.td" -include "mlir/IR/OpAsmInterface.td" - -// Base class for Serene dialect operations. This operation inherits from the base -// `Op` class in OpBase.td, and provides: -// * The parent dialect of the operation. -// * The mnemonic for the operation, or the name without the dialect prefix. -// * A list of traits for the operation. -class Serene_Op traits = []> : - Op; - - -// serene.value -def ValueOp : Serene_Op<"value", [ - ConstantLike, NoSideEffect, - TypesMatchWith< - "result and attribute have the same type", - "value", "result", "$_self">]> { - - let summary = "This operation represent a compile time value"; - let description = [{ - The `value` operation produces an SSA value equal to value - specified by an attribute. This is the way Serene marks constant - compile time values. - - Example: - - ``` - // Integer constant - %1 = serene.value 42 : i32 - - // Equivalent generic form - %1 = "serene.value"() {value = 42 : i32} : () -> i32 - ``` - }]; - - let arguments = (ins AnyAttr:$value); - let results = (outs AnyType:$result); - - let builders = [ - OpBuilder<(ins "mlir::Attribute":$value), - [{ build($_builder, $_state, value.getType(), value); }]>, - OpBuilder<(ins "mlir::Attribute":$value, "mlir::Type":$type), - [{ build($_builder, $_state, type, value); }]>, - ]; - - let extraClassDeclaration = [{ - /// Whether the constant op can be constructed with a particular value and - /// type. - static bool isBuildableWith(mlir::Attribute value, mlir::Type type); - }]; - - // Need to define the ::fold() method to make value op foldable - // let hasFolder = 1; - let assemblyFormat = "attr-dict $value"; - let hasFolder = 1; -} - -// serene.intern -def InternOp : Serene_Op<"intern", [ - NoSideEffect -]> { - - let summary = "This operation is the runtime contructor for symbol type"; - let description = [{ - The `intern` operation produces an SSA value that holds a value of type - symbol at runtime. - - Example: - - ``` - - %ns = serene.string "some.ns" - %name = serene.string "symbol_name" - %1 = serene.intern %ns %name - - // Equivalent generic form - %1 = "serene.symbol"(%ns, %name){} : (!serene.string, !serene.string) -> !serene.ptr - ``` - }]; - - let arguments = (ins StringType:$ns, StringType:$name); - let results = (outs Ptr:$result); - - let assemblyFormat = "attr-dict $ns $name"; -} - -// serene.symbol -def SymbolOp : Serene_Op<"symbol", [ - NoSideEffect, ConstantLike, -]> { - - let summary = "This operation is the compile time contructor for symbol type"; - let description = [{ - The `symbol` operation produces an SSA value that holds a value of type - symbol at compile time. - - Example: - - ``` - - %1 = serene.symbol "some.ns" "symbol_name" - - // Equivalent generic form - %1 = "serene.symbol"() {ns = "some.ns", name = "symbol_name"} : () -> i32 - ``` - }]; - - let arguments = (ins SymbolAttr:$value); - let results = (outs Ptr:$result); - - let assemblyFormat = "attr-dict $value"; - let hasFolder = 1; -} - -// serene.convert -def ConvertOp : Serene_Op<"convert", [ - NoSideEffect -]> { - - let summary = "This operation converts a symbol to the equivelant llvm type"; - let description = [{ - This operation converts a symbol to the equivelant llvm type - }]; - - let arguments = (ins AnyType:$value); - - let results = (outs AnyType:$result); - - let assemblyFormat = [{ - $value attr-dict `:` functional-type($value, results) - }]; - -} - -// ============================================================================ -// Define Family -// ============================================================================ - -// serene.define -def DefineOp: Serene_Op<"define", [Symbol]> { - let summary = "This operation defines a global binding in the current namespace"; - let description = [{ - `define` defines a global binding in the current namespace. It always return a - symbol type. - - Examples: - - ```mlir - %foo = "serene.define"(%0){name = "foo"}: (i64) -> !serene.symbol - - // compact form - %bar = serene.define "bar", %0 : i64 - ``` - }]; - - let arguments = (ins SymbolNameAttr:$sym_name, AnyType:$value, - OptionalAttr:$is_top_level, - OptionalAttr:$sym_visibility); - - //let results = (outs SereneSymbol); - let assemblyFormat = "attr-dict $sym_name `,` $value `:` type($value)"; -} - -// serene.define_constant -def DefineConstantOp: Serene_Op<"define_constant", [Symbol]> { - let summary = "This operation defines a constant global binding in the current namespace"; - let description = [{ - `define` defines a constant global binding in the current namespace. It always return a - symbol type. - - Examples: - - ```mlir - %foo = "serene.define_constant"(%0){name = "foo"}: (i64) -> !serene.symbol - - // compact form - %bar = serene.define_constant "bar", %0 : i64 - ``` - }]; - - let arguments = (ins SymbolNameAttr:$sym_name, AnyAttr:$value, - OptionalAttr:$is_top_level, - OptionalAttr:$sym_visibility); - - // let results = (outs SereneSymbol); - let assemblyFormat = "attr-dict $sym_name $value"; -} - -// serene.set_value -def SetValueOp: Serene_Op<"set_value", []> { - - let summary = "Sets the value of a SLIRS global varible."; - let description = [{ - This operation sets the value of a SLIR global variable. This operation - is NOT threadsafe. - - }]; - - let arguments = (ins SymbolRefAttr:$var, - AnyType:$value); - - let assemblyFormat = "attr-dict $var `,` $value `:` type($value)"; -} - -// serene.fn -def FnOp: Serene_Op<"fn", [ - AffineScope, AutomaticAllocationScope, - IsolatedFromAbove, -]> { - - let summary = "This operation is just a place holder for a function"; - let description = [{ - A place holder for an anonymous function. For example consider an expression - like `(def a (fn (x) x))`, in this case we don't immediately create an anonymous - function since we need to set the name and create the function later. - - - }]; - - let arguments = (ins StrAttr:$name, - TypeAttr:$return_type, - OptionalAttr:$sym_visibility); - - let regions = (region VariadicRegion:$bodies); - let results = (outs FnType); -} - - -// serene.ret -def ReturnOp: Serene_Op<"ret", [ - NoSideEffect, HasParent<"FnOp">, - ReturnLike, Terminator - // MemRefsNormalizable -]> { - - let summary = "This operation marks the return value of a function"; - let description = [{ - `ret` marks the return value of a function body. - Example: - - ```mlir - serene.ret %foo : i32 - ``` - }]; - - let arguments = (ins Variadic:$operands); - - let builders = [OpBuilder<(ins), [{ - build($_builder, $_state, llvm::None); - }]>]; - - let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?"; - // TODO: Turn on the verifier for `ret` - // let hasVerifier = 1; -} - - -// serene.call -def CallOp : Serene_Op<"call", - [MemRefsNormalizable]> { - let summary = "call operation"; - let description = [{ - The `serene.call` operation represents a direct call to a function that is - within the same symbol scope as the call. The operands and result types of - the call must match the specified function type. The callee is encoded as a - symbol reference attribute named "callee". - - Example: - - ```mlir - %2 = serene.call @my_add(%0, %1) : (f32, f32) -> f32 - ``` - }]; - - let arguments = (ins FnType:$fn, - Variadic:$args); - let results = (outs Variadic); - - let assemblyFormat = [{ - $fn `(` $args `)` attr-dict `:` functional-type($args, results) - }]; -} - - -// TODO: Do we need to have a NS type? -def NsOp : Serene_Op<"ns", [ - AffineScope, IsolatedFromAbove, NoRegionArguments, SymbolTable, Symbol, - OpAsmOpInterface -] # GraphRegionNoTerminator.traits> { - let summary = "This operation represents a Serene namespace."; - let description = [{ - The `serene.ns` operation represents a namespace that will eventually - lowers to a `mlir::ModuleOp`. - - Example: - - ```mlir - serene.ns @some.ns { - .... - } - ``` - }]; - - // TODO: Create a new Attr type that is an array to represent - // required namespaces - let arguments = (ins SymbolNameAttr:$sym_name, - OptionalAttr:$sym_visibility); - - let regions = (region SizedRegion<1>:$body); - - let assemblyFormat = "$sym_name attr-dict-with-keyword $body"; - - let builders = [ - OpBuilder<(ins CArg<"llvm::Optional", "{}">:$name)> - ]; - - let extraClassDeclaration = [{ - /// Construct a namespace from the given location with an optional name. - // static NsOp create(slir::reader::LocationRange loc, Optional name = llvm::None); - - /// Return the name of this module if present. - llvm::StringRef getName() { return sym_name(); } - - //===------------------------------------------------------------------===// - // SymbolOpInterface Methods - //===------------------------------------------------------------------===// - - /// A ModuleOp may optionally define a symbol. - bool isOptionalSymbol() { return false; } - - //===------------------------------------------------------------------===// - // DataLayoutOpInterface Methods - //===------------------------------------------------------------------===// - mlir::DataLayoutSpecInterface getDataLayoutSpec(); - - //===------------------------------------------------------------------===// - // OpAsmOpInterface Methods - //===------------------------------------------------------------------===// - static ::llvm::StringRef getDefaultDialect() { - return "builtin"; - } - }]; -} - -#endif // SERENE_DIALECT_OPS diff --git a/libserene.v0/include/serene/slir/slir.h b/libserene.v0/include/serene/slir/slir.h deleted file mode 100644 index 63c805c..0000000 --- a/libserene.v0/include/serene/slir/slir.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef SERENE_SLIR_SLIR_H -#define SERENE_SLIR_SLIR_H - -#include "serene/exprs/expression.h" - -#include -#include -#include - -#include - -namespace serene { -namespace slir { -// std::unique_ptr compileToLLVMIR(serene::SereneContext &ctx, -// mlir::ModuleOp &module); - -std::optional -compileToLLVMIR(serene::SereneContext &ctx, mlir::ModuleOp &module); -} // namespace slir -} // namespace serene - -#endif diff --git a/libserene.v0/include/serene/slir/symbol.h b/libserene.v0/include/serene/slir/symbol.h deleted file mode 100644 index b99ceab..0000000 --- a/libserene.v0/include/serene/slir/symbol.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// SereneSymbol is the Symbil type in SLIT that represents an expr::Sympol - -#ifndef SERENE_SLIR_SYMBOL_H -#define SERENE_SLIR_SYMBOL_H - -#include -#include - -namespace serene { -namespace slir { -namespace detail { -/// This is the storage class for the `SymbolType` (SereneSymbol in ODS) -// class SymbolTypeStorage : public mlir::TypeStorage { -// using KeyTy = std::string; - -// SymbolTypeStorage(std::string &ns, std::string &name) : ns(ns), name(name) -// {} SymbolTypeStorage(const KeyTy &k) { - -// auto partDelimiter = k.find('/'); -// if (partDelimiter == std::string::npos) { -// llvm::llvm_unreachable_internal("SLIR symbol has to have NS"); -// } else { -// name = k.substr(partDelimiter + 1, k.size()); -// ns = k.substr(0, partDelimiter); -// } -// } - -// /// The hash key for this storage is a pair of the integer and type params. - -// /// Define the comparison function for the key type. -// bool operator==(const KeyTy &key) const { -// // TODO: Use formatv to concat strings -// return key == ns + "/" + name; -// } - -// static llvm::hash_code hashKey(const KeyTy &key) { -// return llvm::hash_combine(key); -// } - -// /// Define a construction function for the key type. -// /// Note: This isn't necessary because KeyTy can be directly constructed -// with -// /// the given parameters. -// static KeyTy getKey(std::string &ns, std::string &name) { -// // TODO: Use formatv to concat strings -// return KeyTy(ns + "/" + name); -// } - -// /// Define a construction method for creating a new instance of this -// storage. static SymbolTypeStorage *construct(mlir::TypeStorageAllocator -// &allocator, -// const KeyTy &key) { -// return new (allocator.allocate()) -// SymbolTypeStorage(key); -// } - -// std::string ns; -// std::string name; -// }; -}; // namespace detail -}; // namespace slir -}; // namespace serene -#endif diff --git a/libserene.v0/include/serene/slir/traits.h b/libserene.v0/include/serene/slir/traits.h deleted file mode 100644 index d34b5ab..0000000 --- a/libserene.v0/include/serene/slir/traits.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SLIR_TRAITS_H -#define SERENE_SLIR_TRAITS_H - -#include "serene/slir/dialect.h" -#include "serene/traits.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace serene { -class Namespace; -class SereneContext; -} // namespace serene - -namespace serene::slir { - -template -class GeneratableUnit : public TraitBase { -public: - GeneratableUnit(){}; - GeneratableUnit(const GeneratableUnit &) = delete; - - void generate(serene::Namespace &ns) { this->Object().generateIR(ns); }; -}; - -template -class Generatable : public TraitBase { -public: - Generatable(){}; - Generatable(const Generatable &) = delete; - - mlir::LogicalResult generate() { return this->Object().generate(); }; - mlir::LogicalResult runPasses() { return this->Object().runPasses(); }; - - mlir::ModuleOp &getModule() { return this->Object().getModule(); }; - serene::SereneContext &getContext() { return this->Object().getContext(); }; - - void dump() { this->Object().dump(); }; -}; - -template -mlir::LogicalResult generate(Generatable &t) { - return t.generate(); -}; - -template -std::unique_ptr toLLVMIR(Generatable &t) { - auto &module = t.getModule(); - auto &ctx = t.getContext(); - // Register the translation to LLVM IR with the MLIR context. - mlir::registerLLVMDialectTranslation(ctx.mlirContext); - - // Convert the module to LLVM IR in a new LLVM IR context. - auto llvmModule = mlir::translateModuleToLLVMIR(module, ctx.llvmContext); - if (!llvmModule) { - // TODO: Return a Result type instead - llvm::errs() << "Failed to emit LLVM IR\n"; - throw std::runtime_error("Failed to emit LLVM IR\n"); - } - - // Initialize LLVM targets. - llvm::InitializeNativeTarget(); - // llvm::InitializeNativeTargetAsmPrinter(); - - // TODO: replace this call with our own version of setupTargetTriple - mlir::ExecutionEngine::setupTargetTriple(llvmModule.get()); - - /// Optionally run an optimization pipeline over the llvm module. - auto optPipeline = mlir::makeOptimizingTransformer( - /*optLevel=*/ctx.getOptimizatioLevel(), /*sizeLevel=*/0, - /*targetMachine=*/nullptr); - if (auto err = optPipeline(llvmModule.get())) { - llvm::errs() << "Failed to optimize LLVM IR " << err << "\n"; - throw std::runtime_error("Failed to optimize LLVM IR"); - } - - return std::move(llvmModule); -}; - -template -void dump(Generatable &t) { - t.dump(); -}; - -} // namespace serene::slir - -#endif diff --git a/libserene.v0/include/serene/slir/type_converter.h b/libserene.v0/include/serene/slir/type_converter.h deleted file mode 100644 index 86f99dd..0000000 --- a/libserene.v0/include/serene/slir/type_converter.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SLIR_TYPE_CONVERTER_H -#define SERENE_SLIR_TYPE_CONVERTER_H - -#include "serene/config.h" -#include "serene/context.h" -#include "serene/export.h" -#include "serene/slir/dialect.h" -#include "serene/slir/ops.h" -#include "serene/slir/types.h" -#include "serene/utils.h" - -#include -#include -#include - -namespace serene::slir { -class SymbolType; -class PtrType; - -/// Returns the LLVM pointer type to the type `T` that is Serene pointer -/// `p` is pointing to. -mlir::Type getPtrTypeinLLVM(mlir::MLIRContext &ctx, PtrType p); - -/// Returns the conversion result of converting Serene String type -/// to LLVM dialect -mlir::Type getStringTypeinLLVM(mlir::MLIRContext &ctx); - -/// Returns the conversoin result of converting Serene Symbol type -/// to LLVM dialect -mlir::Type getSymbolTypeinLLVM(mlir::MLIRContext &ctx); - -class TypeConverter : public mlir::TypeConverter { - mlir::MLIRContext &ctx; - - using mlir::TypeConverter::convertType; - - using MaybeType = std::optional; - using MaybeValue = std::optional; - using ConverterFn = std::function; - - std::function - - materializeSymbolFn() { - return [&](mlir::OpBuilder &builder, SymbolType type, - mlir::ValueRange values, mlir::Location loc) -> MaybeValue { - auto targetType = convertType(type); - auto ret = builder.create(loc, targetType, values[0]); - llvm::outs() << "RR: " << ret << "\n"; - return ret.getResult(); - }; - }; - - /// This method will be called via `convertType` to convert Serene types - /// to llvm dialect types - ConverterFn convertSereneTypes(); - -public: - TypeConverter(mlir::MLIRContext &ctx) : ctx(ctx) { - addConversion([](mlir::Type type) { return type; }); - addConversion(convertSereneTypes()); - addArgumentMaterialization(materializeSymbolFn()); - addTargetMaterialization(materializeSymbolFn()); - } -}; -} // namespace serene::slir - -#endif diff --git a/libserene.v0/include/serene/slir/types.h b/libserene.v0/include/serene/slir/types.h deleted file mode 100644 index b470492..0000000 --- a/libserene.v0/include/serene/slir/types.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_DIALECT_TYPES_H -#define SERENE_DIALECT_TYPES_H - -#include -#include -#include -#include -#include - -#define GET_ATTRDEF_CLASSES -#include "serene/slir/attrs.h.inc" - -#define GET_TYPEDEF_CLASSES -#include "serene/slir/types.h.inc" - -#endif diff --git a/libserene.v0/include/serene/slir/types.td b/libserene.v0/include/serene/slir/types.td deleted file mode 100644 index d9dff8d..0000000 --- a/libserene.v0/include/serene/slir/types.td +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_DIALECT_TYPES_TD -#define SERENE_DIALECT_TYPES_TD - -include "mlir/IR/OpBase.td" -include "mlir/IR/AttrTypeBase.td" - -// The base class for all the Serene types -class Serene_Type traits = []> - : TypeDef { - let mnemonic = typeMnemonic; -} - -// The base class for all the Serene attributes -class Serene_Attr traits = []> - : AttrDef { - let mnemonic = attrMnemonic; -} - -// Attributes ================================================================= -def SymbolAttr : Serene_Attr<"Symbol", "symbol"> { - let summary = "An Attribute containing a symbol value."; - let description = [{ - An integer attribute is a literal attribute that represents a symbol - value. - }]; - - let parameters = (ins StringRefParameter<"The namespace of the symbol">:$ns, - StringRefParameter<"The symbol name itself">:$name); - - let assemblyFormat = "`<` $ns `,` $name `>`"; -} - -// Type Traits ================================================================ -def AnyPtr : Type()">, - "Serene pointer type", "Ptr">; - -class Ptr : Type< - And<[AnyPtr.predicate, - Or<[CPred<"$_self.cast().isOpaque()">, - SubstLeaves< - "$_self", - "$_self.cast().getPointeeType()", - type.predicate>]>]>, - "A pointer to type " # type.summary, - "PtrType">, - // We need Ptr to be buildable coz we need to be able to infer - // the type out of it when we use Ptr as the result type - // of an operation - SameBuildabilityAs { - Type pointeeType = type; -} - - -// Types ====================================================================== -def PtrType : Serene_Type<"Ptr", "ptr"> { - let summary = "A pointer to a value of type T."; - - let description = [{ - A pointer to a value of type T. For example - - %0 = serene.address-of %1 : (!serene.symbol) -> !ptr - }]; - - let parameters = (ins "mlir::Type":$pointeeType, DefaultValuedParameter<"unsigned", "0">:$addressSpace); - let genAccessors = 1; - let assemblyFormat = "`<` qualified($pointeeType) `>`"; - - let extraClassDeclaration = [{ - /// Gets or creates an instance of pointer type pointing to an - /// object of `pointee` type in the given address space. The pointer type is - /// created in the same context as `pointee`. If the pointee is not provided, - /// creates an opaque pointer in the given context and address space. - static PtrType get(mlir::MLIRContext *context, unsigned addressSpace = 0); - static PtrType get(mlir::Type pointee, unsigned addressSpace = 0); - - bool isOpaque() const; - }]; -} - -def StringType : Serene_Type<"String", "string"> { - let summary = "A simple string type"; - - let description = [{ - A simple string type that contains the following structure: - - i8*: buffer; pointer to the character buffer - i32: length; the number of chars in the buffer - }]; -} - - -def SymbolType : Serene_Type<"Symbol", "symbol"> { - let summary = "A Lisp symbol type"; - - let description = [{ - A Lisp symbol type - }]; - // let parameters = (ins "std::string":$ns, "std::string":$name); -} - -def FnType : Serene_Type<"Fn", "fn"> { - - let summary = "Function type"; - - let description = [{ - Function type represent any function, anonymous or named with multiple - bodies. - }]; - - // TODO: do we need to know about number of bodies and the signature - // of each one? - // let parameters = (ins "std::string":$ns, "std::string":$name); -} - -def Serene_Type : AnyTypeOf<[ - PtrType, - SymbolType, - StringType, - FnType -]>; - - -#endif // SERENE_DIALECT_TYPES_TD diff --git a/libserene.v0/include/serene/slir/utils.h b/libserene.v0/include/serene/slir/utils.h deleted file mode 100644 index 3610480..0000000 --- a/libserene.v0/include/serene/slir/utils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SLIR_UTILS_H -#define SERENE_SLIR_UTILS_H - -#include "serene/reader/location.h" - -#include - -namespace serene { -class Namespace; -} // namespace serene - -namespace serene::slir { - -/** - * Convert a Serene location to MLIR FileLineLoc Location - */ -::mlir::Location toMLIRLocation(serene::Namespace &, - serene::reader::Location &); - -} // namespace serene::slir - -#endif diff --git a/libserene.v0/include/serene/source_mgr.h b/libserene.v0/include/serene/source_mgr.h deleted file mode 100644 index ac627c9..0000000 --- a/libserene.v0/include/serene/source_mgr.h +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SOURCE_MGR_H -#define SERENE_SOURCE_MGR_H - -#include "serene/namespace.h" -#include "serene/reader/location.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SMGR_LOG(...) \ - DEBUG_WITH_TYPE("sourcemgr", llvm::dbgs() \ - << "[SMGR]: " << __VA_ARGS__ << "\n"); - -namespace serene { -class SereneContext; - -/// This class is quite similar to the `llvm::SourceMgr` in functionality. We -/// even borrowed some of the code from the original implementation but removed -/// a lot of code that were irrelevant to us. -/// -/// SouceMgr is responsible for finding a namespace in the `loadPaths` and read -/// the content of the `.srn` (or any of the `DEFAULT_SUFFIX`) into a -/// `llvm::MemoryBuffer` embedded in a `SrcBuffer` object as the owner of the -/// source files and then it will call the `reader` on the buffer to parse it -/// and create the actual `Namespace` object from the parsed AST. -/// -/// Later on, whenever we need to refer to the source file of a namespace for -/// diagnosis purposes or any other purpose we can use the functions in this -/// class to get hold of a pointer to a specific `reader::Location` of the -/// buffer. -/// -/// Note: Unlike the original version, SourceMgr does not handle the diagnostics -/// and it uses the Serene's `DiagnosticEngine` for that matter. -class SERENE_EXPORT SourceMgr { - -public: - // TODO: Make it a vector of supported suffixes - std::string DEFAULT_SUFFIX = "srn"; - -private: - struct SrcBuffer { - /// The memory buffer for the file. - std::unique_ptr buffer; - - /// Vector of offsets into Buffer at which there are line-endings - /// (lazily populated). Once populated, the '\n' that marks the end of - /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since - /// these offsets are in sorted (ascending) order, they can be - /// binary-searched for the first one after any given offset (eg. an - /// offset corresponding to a particular SMLoc). - /// - /// Since we're storing offsets into relatively small files (often smaller - /// than 2^8 or 2^16 bytes), we select the offset vector element type - /// dynamically based on the size of Buffer. - mutable void *offsetCache = nullptr; - - /// Look up a given \p ptr in in the buffer, determining which line it came - /// from. - unsigned getLineNumber(const char *ptr) const; - template - unsigned getLineNumberSpecialized(const char *ptr) const; - - /// Return a pointer to the first character of the specified line number or - /// null if the line number is invalid. - const char *getPointerForLineNumber(unsigned lineNo) const; - - template - const char *getPointerForLineNumberSpecialized(unsigned lineNo) const; - - /// This is the location of the parent import or unknown location if it is - /// the main namespace - reader::LocationRange importLoc; - - SrcBuffer() = default; - SrcBuffer(SrcBuffer &&) noexcept; - SrcBuffer(const SrcBuffer &) = delete; - SrcBuffer &operator=(const SrcBuffer &) = delete; - ~SrcBuffer(); - }; - using MemBufPtr = std::unique_ptr; - - /// This is all of the buffers that we are reading from. - std::vector buffers; - - /// A hashtable that works as an index from namespace names to the buffer - /// position it the `buffer` - llvm::StringMap nsTable; - - // This is the list of directories we should search for include files in. - std::vector loadPaths; - - // Find a namespace file with the given \p name in the load path and \r retuns - // a unique pointer to the memory buffer containing the content or an error. - // In the success case it will put the path of the file into the \p - // importedFile. - MemBufPtr findFileInLoadPath(const std::string &name, - std::string &importedFile); - - bool isValidBufferID(unsigned i) const; - - /// Converts the ns name to a partial path by replacing the dots with slashes - static std::string convertNamespaceToPath(std::string ns_name); - -public: - SourceMgr() = default; - SourceMgr(const SourceMgr &) = delete; - SourceMgr &operator=(const SourceMgr &) = delete; - SourceMgr(SourceMgr &&) = default; - SourceMgr &operator=(SourceMgr &&) = default; - ~SourceMgr() = default; - - /// Set the `loadPaths` to the given \p dirs. `loadPaths` is a vector of - /// directories that Serene will look in order to find a file that constains a - /// namespace which it is looking for. - void setLoadPaths(std::vector &dirs) { loadPaths.swap(dirs); } - - /// Return a reference to a `SrcBuffer` with the given ID \p i. - const SrcBuffer &getBufferInfo(unsigned i) const { - assert(isValidBufferID(i)); - return buffers[i - 1]; - } - - /// Return a reference to a `SrcBuffer` with the given namspace name \p ns. - const SrcBuffer &getBufferInfo(llvm::StringRef ns) const { - auto bufferId = nsTable.lookup(ns); - - if (bufferId == 0) { - // No such namespace - llvm_unreachable("couldn't find the src buffer for a namespace. It " - "should never happen."); - } - - return buffers[bufferId - 1]; - } - - /// Return a pointer to the internal `llvm::MemoryBuffer` of the `SrcBuffer` - /// with the given ID \p i. - const llvm::MemoryBuffer *getMemoryBuffer(unsigned i) const { - assert(isValidBufferID(i)); - return buffers[i - 1].buffer.get(); - } - - unsigned getNumBuffers() const { return buffers.size(); } - - /// Add a new source buffer to this source manager. This takes ownership of - /// the memory buffer. - unsigned AddNewSourceBuffer(std::unique_ptr f, - reader::LocationRange includeLoc); - - /// Lookup for a file containing the namespace definition of with given - /// namespace name \p name. In case that the file exists, it returns an - /// `ErrorTree`. It will use the parser to read the file and create an AST - /// from it. Then create a namespace, set the its AST to the AST that we just - /// read from the file and return a shared pointer to the namespace. - /// - /// \p importLoc is a location in the source code where the give namespace is - /// imported. - MaybeNS readNamespace(SereneContext &ctx, std::string name, - reader::LocationRange importLoc); -}; - -}; // namespace serene - -#endif diff --git a/libserene.v0/include/serene/traits.h b/libserene.v0/include/serene/traits.h deleted file mode 100644 index a80471b..0000000 --- a/libserene.v0/include/serene/traits.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * This is a CRTP based Trait implementation that allows to use Trait like - * classes to create polymorphic functions and API statically at compile type - * without any runtime shenanigans. For more on CRTP checkout: - * - * https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern - * - * In order to define a trait, use the `TraitBase` class like: - - * \code - * template - * class Blahable : public TraitBase {} - * \endcode - * - * Every Trait has to take the `ConcreteType` as template argument and pass it - * to the `TraitBase`. Checkout the documentation of `TraitBase` for more info - * on creating a new Trait. - * - * Alongside with each Trait type, you should provide the "Official" interface - * of the Trait via some standalone functions that operates on the Trait type. - * For example Imagine we have a Trait type called `ABC` with two main - * functionality `foo` and `bar`. We need to create two functions as follows: - * - * \code - * template - * SomeType Foo(ABC &t) { return t.foo(); }; - * - * template - * SomeType bar(ABC &t, int x) { return t.bar(x); }; - * \endcode - * - * These two functions will be the official interface to the trait `ABC`. - * IMPORTANT NOTE: Make sure to pass a reference of type `ABC` to the - * functions and DO NOT PASS BY COPY. Since copying will copy the value by the - * trait type only, we would not be able to statically case it to the - * implementor type and it will lead to some allocation problem. - * - * Traits can be used via `WithTrait` helper class which provides a clean - * interface to mix and match Trait types. - * - */ -#ifndef SERENE_TRAITS_H -#define SERENE_TRAITS_H - -#include - -#include - -namespace serene { - -/// A placeholder structure that replaces the concrete type of the -/// Imlementations Which might have child classes. -struct FinalImpl; - -/// In order to use Traits, we can use `WithTrait` class as the base -/// of any implementation class and pass the Trait classes as template argument -/// for example: -/// -/// \code -/// class Expression : public WithTrait {} -/// \endcode -template class... Traits> -class WithTrait : public Traits... { -protected: - WithTrait(){}; - friend ConcreteType; -}; - -/// This class provides the common functionality among the Trait Types and -/// every Trait has to inherit from this class. Here is an example: -/// -/// \code -/// template -/// class Blahable : public TraitBase {} -/// \endcode -/// -/// In the Trait class the underlaying object which implements the Trait -/// is accessable via the `Object` method. -template class TraitType> -class TraitBase { -protected: - /// Statically casts the object to the concrete type object to be - /// used in the Trait Types. - // const ConcreteType &Object() const { - // return static_cast(*this); - // }; - - ConcreteType &Object() { return static_cast(*this); }; -}; - -template -class IDebuggable : public TraitBase { -public: - IDebuggable(){}; - IDebuggable(const IDebuggable &) = delete; - std::string toString() const { return this->Object().toString(); } -}; - -template -std::string toString(IDebuggable &t) { - return t.toString(); -} - -}; // namespace serene -#endif diff --git a/libserene.v0/include/serene/traits/locatable.h b/libserene.v0/include/serene/traits/locatable.h deleted file mode 100644 index 2806bda..0000000 --- a/libserene.v0/include/serene/traits/locatable.h +++ /dev/null @@ -1,22 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TRAITS_LOCATABLE_H -#define SERENE_TRAITS_LOCATABLE_H - -#endif diff --git a/libserene.v0/include/serene/types/type.h b/libserene.v0/include/serene/types/type.h deleted file mode 100644 index c9ba5bf..0000000 --- a/libserene.v0/include/serene/types/type.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TYPES_TYPE_H -#define SERENE_TYPES_TYPE_H - -#include - -namespace serene::types { - -class Type { -public: - virtual ~Type() = default; - - /// The AST representation of a type - virtual std::string toString() const = 0; -}; -}; // namespace serene::types - -#endif diff --git a/libserene.v0/include/serene/utils.h b/libserene.v0/include/serene/utils.h deleted file mode 100644 index d55d814..0000000 --- a/libserene.v0/include/serene/utils.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_UTILS_H -#define SERENE_UTILS_H - -#include "serene/export.h" - -#include - -#include - -// Sometimes we need this to make both analyzer happy -// and the fn signature right. -#define UNUSED(x) (void)(x) - -// We use this value with llvm::SmallString -#define MAX_PATH_SLOTS 256 -// C++17 required. We can't go back to 14 any more :)) - -namespace serene { - -/// A similar type to Rust's Result data structure. It either holds a value of -/// type `T` successfully or holds a value of type `E` errorfully. It is -/// designed to be used in situations which the return value of a function might -/// contains some errors. The official way to use this type is to use the -/// factory functions `Success` and `Error`. For example: -/// -/// \code -/// auto successfulResult = Result::success(3); -/// auto notOkResult = Result::error(SomeLLVMError()); -// \endcode -/// -/// In order check for a value being errorful or successful checkout the `ok` -/// method or simply use the value as a conditiona. -/// -/// This class is setup in a way tha you can us a value of type `T` in places -/// that the compiler expects a `Result`. So for example: -/// -/// \code -/// Result fn() {return 2;} -/// \endcode -/// -/// works perfectly. -template -class SERENE_EXPORT Result { - - // The actual data container - std::variant contents; - - /// The main constructor which we made private to avoid ambiguousness in - /// input type. `Success` and `Error` call this ctor. - template - Result(InPlace i, Content &&c) : contents(i, std::forward(c)){}; - -public: - constexpr Result(const T &v) - : Result(std::in_place_index_t<0>(), std::move(v)){}; - - /// Return a pointer to the success case value of the result. It is - /// important to check for the success case before calling this function. - constexpr const T *getPointer() const { return &getValue(); } - - /// Return a pointer to the success case value of the result. It is - /// important to check for the success case before calling this function. - T *getPointer() { return &getValue(); } - - /// Return a pointer to the success case value of the result. It is - /// important to check for the success case before calling this function. - T *operator->() { return getPointer(); } - - /// Return a pointer to the success case value of the result. It is - /// important to check for the success case before calling this function. - constexpr const T *operator->() const { return getPointer(); } - - /// Dereference the success case and returns the value. It is - /// important to check for the success case before calling this function. - constexpr const T &operator*() const & { return getValue(); } - - /// Dereference the success case and returns the value. It is - /// important to check for the success case before calling this function. - T &operator*() & { return getValue(); } - - /// Create a succesfull result with the given value of type `T`. - static Result success(T v) { - return Result(std::in_place_index_t<0>(), std::move(v)); - } - - /// Create an errorful result with the given value of type `E` (default - /// `llvm::Error`). - static Result error(E e) { - return Result(std::in_place_index_t<1>(), std::move(e)); - } - - /// Return the value if it's successful otherwise throw an error - T &&getValue() && { return std::move(std::get<0>(contents)); }; - - /// Return the error value if it's errorful otherwise throw an error - E &&getError() && { return std::move(std::get<1>(contents)); }; - - // using std::get, it'll throw if contents doesn't contain what you ask for - - /// Return the value if it's successful otherwise throw an error - T &getValue() & { return std::get<0>(contents); }; - - /// Return the error value if it's errorful otherwise throw an error - E &getError() & { return std::get<1>(contents); }; - - const T &getValue() const & { return std::get<0>(contents); } - const E &getError() const & { return std::get<1>(contents); } - - /// Return the a boolean value indicating whether the value is succesful - /// or errorful. - bool ok() const { return std::holds_alternative(contents); }; - - operator bool() const { return ok(); } -}; - -inline void makeFQSymbolName(const llvm::StringRef &ns, - const llvm::StringRef &sym, std::string &result) { - result = (ns + "/" + sym).str(); -}; - -} // namespace serene -#endif diff --git a/libserene.v0/lib/CMakeLists.txt b/libserene.v0/lib/CMakeLists.txt deleted file mode 100644 index d718ef6..0000000 --- a/libserene.v0/lib/CMakeLists.txt +++ /dev/null @@ -1,169 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -#TODO: To support MacOS look into cmake's public headers -# https://cmake.org/cmake/help/latest/prop_tgt/PUBLIC_HEADER.html - -# Prevent any future RPATH issue on Posix -if(NOT APPLE) - set(CMAKE_INSTALL_RPATH $ORIGIN) -endif() - -add_library(serene - exprs/symbol.cpp - exprs/list.cpp - exprs/number.cpp - exprs/expression.cpp - exprs/def.cpp - exprs/fn.cpp - exprs/call.cpp - - serene.cpp - context.cpp - namespace.cpp - source_mgr.cpp - diagnostics.cpp - semantics.cpp - - # jit.cpp - # jit/engine.cpp - # jit/layers.cpp - jit/halley.cpp - - errors.cpp - - # Reader - reader/reader.cpp - - # IR - slir/types.cpp - slir/slir.cpp - slir/value_op.cpp - slir/generatable.cpp - slir/utils.cpp - slir/ops.cpp - slir/type_converter.cpp - slir/dialect.cpp - passes/slir_lowering.cpp - passes/to_llvm_dialect.cpp - ) - -# Create an ALIAS target. This way if we mess up the name -# there will be an cmake error inseat of a linker error which is harder -# to understand. So any binary that wants to use serene has to -# use `Serene::lib` alias instead -add_library(Serene::lib ALIAS serene) - -set_target_properties(serene PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -if(SERENE_ENABLE_TIDY) - set_target_properties(serene PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -# Do we need to build serene as a shared lib? default is "yes" -if(SERENE_SHARED_LIB) - - # We need to use libsan as a shared lib on debug mode. The - # target executable has to be built with `-fsanitize=address` - # as well and it has to run with: - # LD_PRELOAD=$(clang -print-file-name=libclang_rt.asan-x86_64.so) - target_compile_options(serene PRIVATE - $<$:-shared-libsan> - ) - target_link_options( - serene PRIVATE - $<$:-shared-libsan> - ) -endif() - - -if (CPP_20_SUPPORT) - target_compile_features(serene PUBLIC cxx_std_20) -else() - target_compile_features(serene PUBLIC cxx_std_17) -endif() - -# Generate the tablegen ODS files before this target -add_dependencies(serene SereneTablegen SereneDialectGen SerenePassGen SereneErrorGen) - -# We need this directory, and users of our library will need it too -target_include_directories(serene PUBLIC "$") -target_include_directories(serene PUBLIC "$") - -# Generate the export.h -include(GenerateExportHeader) -generate_export_header(serene EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/include/serene/export.h) -target_compile_definitions( - serene PUBLIC "$<$>:SERENE_STATIC_DEFINE>") - -get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) -get_property(conversion_libs GLOBAL PROPERTY MLIR_CONVERSION_LIBS) - - -if(SERENE_SHOW_MLIR_DIALECTS) - message(STATUS "MLIR Dialects to choose from:") - foreach(lib ${dialect_libs}) - message(STATUS "\t${lib}") - endforeach() -endif() - - -if(SERENE_SHOW_MLIR_TRANSFORMERS) - message(STATUS "MLIR Dialects transformers to choose from:") - foreach(lib ${conversion_libs}) - message(STATUS "\t${lib}") - endforeach() -endif() - -if(SERENE_SHOW_LLVM_LIBS) - execute_process(COMMAND llvm-config --libs all - OUTPUT_VARIABLE SERENE_LLVM_LIBS) - message(STATUS "LLVM libs available:\n ${SERENE_LLVM_LIBS}") -endif() - - -set(serene_lib_dialects_in_use - MLIRFunc) - -set(serene_lib_transformers_in_use - MLIRFuncToLLVM) - -target_link_libraries(serene PRIVATE - MLIRIR - MLIRPass - MLIRTransforms - - ${serene_lib_dialects_in_use} - ${serene_lib_transformers_in_use} - - #TODO: Remove this lib, we're just using one func - MLIRExecutionEngine - - # LLVM's JIT lib - LLVMExecutionEngine - LLVMOrcJIT - MLIRLLVMToLLVMIRTranslation - - LLVMTarget - LLVMX86AsmParser - - ${llvm_libs}) diff --git a/libserene.v0/lib/context.cpp b/libserene.v0/lib/context.cpp deleted file mode 100644 index 364f524..0000000 --- a/libserene.v0/lib/context.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/context.h" - -#include "serene/namespace.h" -#include "serene/passes.h" -#include "serene/reader/location.h" -#include "serene/slir/generatable.h" - -#include - -#include - -namespace serene { - -void SereneContext::insertNS(NSPtr &ns) { - auto nsName = ns->name; - namespaces[nsName] = ns; -}; - -Namespace *SereneContext::getNS(llvm::StringRef nsName) { - if (namespaces.count(nsName.str()) != 0) { - return namespaces[nsName.str()].get(); - } - - return nullptr; -}; - -Namespace &SereneContext::getCurrentNS() { - if (this->currentNS.empty() || (namespaces.count(this->currentNS) == 0)) { - panic(*this, llvm::formatv("getCurrentNS: Namespace '{0}' does not exist", - this->currentNS) - .str()); - } - - return *namespaces[this->currentNS]; -}; - -NSPtr SereneContext::getSharedPtrToNS(llvm::StringRef nsName) { - if (namespaces.count(nsName.str()) == 0) { - return nullptr; - } - - return namespaces[nsName.str()]; -}; - -void SereneContext::setOperationPhase(CompilationPhase phase) { - this->targetPhase = phase; - - if (phase == CompilationPhase::SLIR) { - return; - } - - if (phase >= CompilationPhase::MLIR) { - pm.addPass(serene::passes::createSLIRLowerToMLIRPass()); - } - - if (phase >= CompilationPhase::LIR) { - pm.addPass(serene::passes::createSLIRLowerToLLVMDialectPass()); - } -}; - -int SereneContext::getOptimizatioLevel() { - if (targetPhase <= CompilationPhase::NoOptimization) { - return 0; - } - - if (targetPhase == CompilationPhase::O1) { - return 1; - } - if (targetPhase == CompilationPhase::O2) { - return 2; - } - return 3; -} - -NSPtr SereneContext::makeNamespace(llvm::StringRef name, - std::optional filename) { - auto ns = Namespace::make(*this, name, filename); - - if (ns != nullptr) { - insertNS(ns); - } - - return ns; -}; - -MaybeNS SereneContext::readNamespace(const std::string &name) { - // TODO: Replace this location with a proper location indicating - // the reason why the location data is not available. - // For example, because the ns might be the entry point ns. - auto loc = reader::LocationRange::UnknownLocation(name); - - return readNamespace(name, loc); -}; - -MaybeNS SereneContext::readNamespace(const std::string &name, - reader::LocationRange loc) { - return withCurrentNS(name, [&]() -> MaybeNS { - return this->sourceManager.readNamespace(*this, name, loc); - }); -} - -MaybeNS SereneContext::importNamespace(const std::string &name) { - auto loc = reader::LocationRange::UnknownLocation(name); - return importNamespace(name, loc); -} - -MaybeNS SereneContext::importNamespace(const std::string &name, - reader::LocationRange loc) { - auto maybeNS = readNamespace(name, loc); - - if (maybeNS) { - auto &ns = *maybeNS; - if (auto err = jit->addNS(*ns, loc)) { - return err; - } - - insertNS(ns); - } - - return maybeNS; -} - -llvm::orc::JITDylib *SereneContext::getLatestJITDylib(Namespace &ns) { - - if (jitDylibs.count(ns.name) == 0) { - return nullptr; - } - - auto vec = jitDylibs[ns.name]; - // TODO: Make sure that the returning Dylib still exists in the JIT - // by calling jit->engine->getJITDylibByName(dylib_name); - return vec.empty() ? nullptr : vec.back(); -}; - -void SereneContext::pushJITDylib(Namespace &ns, llvm::orc::JITDylib *l) { - if (jitDylibs.count(ns.name) == 0) { - llvm::SmallVector vec{l}; - jitDylibs[ns.name] = vec; - return; - } - auto vec = jitDylibs[ns.name]; - vec.push_back(l); - jitDylibs[ns.name] = vec; -} - -size_t SereneContext::getNumberOfJITDylibs(Namespace &ns) { - if (jitDylibs.count(ns.name) == 0) { - return 0; - } - auto vec = jitDylibs[ns.name]; - return vec.size(); -}; - -void terminate(SereneContext &ctx, int exitCode) { - UNUSED(ctx); - // TODO: Since we are running in a single thread for now using exit is fine - // but we need to adjust and change it to a thread safe termination - // process later on. - // NOLINTNEXTLINE(concurrency-mt-unsafe) - std::exit(exitCode); -} - -std::unique_ptr makeSereneContext(Options opts) { - return SereneContext::make(opts); -}; - -}; // namespace serene diff --git a/libserene.v0/lib/diagnostics.cpp b/libserene.v0/lib/diagnostics.cpp deleted file mode 100644 index bc52bab..0000000 --- a/libserene.v0/lib/diagnostics.cpp +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/diagnostics.h" - -#include "serene/context.h" -#include "serene/reader/location.h" -#include "serene/source_mgr.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include - -#include - -namespace serene { -void Diagnostic::writeColorByType(llvm::raw_ostream &os, llvm::StringRef str) { - llvm::ColorMode mode = - ctx.opts.withColors ? llvm::ColorMode::Auto : llvm::ColorMode::Disable; - - llvm::WithColor s(os, llvm::raw_ostream::SAVEDCOLOR, true, false, mode); - - switch (type) { - case Type::Error: - s.changeColor(llvm::raw_ostream::Colors::RED); - break; - // case Type::Warning: - // s.changeColor(llvm::raw_ostream::Colors::YELLOW); - // break; - case Type::Note: - s.changeColor(llvm::raw_ostream::Colors::CYAN); - break; - case Type::Remark: - s.changeColor(llvm::raw_ostream::Colors::MAGENTA); - break; - } - - s << str; - s.resetColor(); -}; - -std::string Diagnostic::getPrefix(llvm::StringRef prefix) { - if (!prefix.empty()) { - return prefix.str(); - } - - switch (type) { - case Type::Error: - return "Error"; - break; - case Type::Note: - return "Note"; - case Type::Remark: - return "Remark"; - } -}; - -void Diagnostic::print(llvm::raw_ostream &os, llvm::StringRef prefix) const { - llvm::ColorMode mode = - ctx.opts.withColors ? llvm::ColorMode::Auto : llvm::ColorMode::Disable; - - llvm::WithColor s(os, llvm::raw_ostream::SAVEDCOLOR, true, false, mode); - UNUSED(prefix); - UNUSED(err); - // s << "\n["; - // writeColorByType(os, "Error"); - // s << "]>\n"; - - // s << "In ns '"; - // s.changeColor(llvm::raw_ostream::Colors::MAGENTA); - // s << loc.start.ns; - // s.resetColor(); - - // if (loc.start.filename.hasValue()) { - // s << "' At: "; - // s.changeColor(llvm::raw_ostream::Colors::YELLOW); - // s << loc.start.filename.getValue(); - // s.resetColor(); - // s << ":"; - // s.changeColor(llvm::raw_ostream::Colors::CYAN); - // s << loc.start.line; - // s.resetColor(); - // s << ":"; - // s.changeColor(llvm::raw_ostream::Colors::CYAN); - // s << loc.start.col; - // s.resetColor(); - // } - - // s << "\n\n"; - - // const auto &srcBuf = ctx.sourceManager.getBufferInfo(loc.start.ns); - // const char *line = srcBuf.getPointerForLineNumber(loc.start.line); - - // while (*line != '\n' && line != srcBuf.buffer->getBufferEnd()) { - // s << *line; - // line++; - // } - - // s << '\n'; - - // s.changeColor(llvm::raw_ostream::Colors::GREEN); - // s << llvm::formatv("{0}", llvm::fmt_pad("^", (size_t)loc.start.col - 1, - // 0)); s.resetColor(); - - // s << '\n'; - - // s << "["; - // if (err != nullptr) { - // writeColorByType(os, err->getErrId 8()); - // } - // s << "] "; - // writeColorByType(os, getPrefix(prefix)); - // s << ": "; - - // if (err != nullptr) { - // s << err->description << '\n'; - // } - - // if (!message.empty()) { - // s.changeColor(llvm::raw_ostream::Colors::YELLOW); - // s << "With message"; - // s.resetColor(); - // s << ": " << message << "\n"; - // } - - // if (err != nullptr) { - // s << "For more information checkout"; - // s.changeColor(llvm::raw_ostream::Colors::CYAN); - // s << " `serenec --explain "; - // s << err->getErrId() << "`\n"; - // } -}; - -DiagnosticEngine::DiagnosticEngine(SereneContext &ctx) - : ctx(ctx), diagEngine(ctx.mlirContext.getDiagEngine()){}; - -void DiagnosticEngine::print(llvm::raw_ostream &os, Diagnostic &d) { - UNUSED(ctx); - UNUSED(os); - UNUSED(d); -}; - -Diagnostic DiagnosticEngine::toDiagnostic(reader::LocationRange loc, - llvm::Error &e, llvm::StringRef msg, - llvm::StringRef fn) { - return Diagnostic(ctx, loc, &e, msg, fn); -}; - -void DiagnosticEngine::enqueueError(llvm::StringRef msg) { - llvm::errs() << llvm::formatv("FIX ME (better emit error): {0}\n", msg); - terminate(ctx, 1); -}; - -void DiagnosticEngine::emitSyntaxError(reader::LocationRange loc, - llvm::Error &e, llvm::StringRef msg) { - Diagnostic diag(ctx, loc, &e, msg); - - diag.print(llvm::errs(), "SyntaxError"); - terminate(ctx, 1); -}; - -std::unique_ptr makeDiagnosticEngine(SereneContext &ctx) { - return std::make_unique(ctx); -} - -void DiagnosticEngine::emit(const llvm::Error &err) { - UNUSED(ctx); - // TODO: create a diag and print it - llvm::errs() << "[Error]: " << err << "\n"; -}; - -// void DiagnosticEngine::emit(const llvm::Error &errs) { -// -// // for (const auto &e : errs) { -// // emit(e); -// // } -// -// }; - -void panic(SereneContext &ctx, llvm::Twine msg) { - - auto err = - llvm::make_error(msg, llvm::inconvertibleErrorCode()); - ctx.diagEngine->emit(err); - terminate(ctx, 1); -}; - -void panic(SereneContext &ctx, const llvm::Error &err) { - ctx.diagEngine->emit(err); - terminate(ctx, 1); -}; - -void throwErrors(SereneContext &ctx, const llvm::Error &err) { - // llvm::handleErrors(errs, - // [](const errors::SereneError &e){}); - ctx.diagEngine->emit(err); -}; - -} // namespace serene diff --git a/libserene.v0/lib/errors.cpp b/libserene.v0/lib/errors.cpp deleted file mode 100644 index ea3f2d2..0000000 --- a/libserene.v0/lib/errors.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/errors.h" - -#include -#include - -namespace serene::errors { - -// We need this to make Error class a llvm::Error friendy implementation -char SereneError::ID; - -std::string getMessage(const llvm::Error &e) { - std::string msg; - llvm::raw_string_ostream os(msg); - os << e; - return os.str(); -}; - -const ErrorVariant *getVariant(ErrorType t) { - if ((0 <= (int)t) && (t < NUMBER_OF_ERRORS)) { - return &errorVariants[t]; - } - return nullptr; -}; -} // namespace serene::errors diff --git a/libserene.v0/lib/exprs/call.cpp b/libserene.v0/lib/exprs/call.cpp deleted file mode 100644 index cf4864b..0000000 --- a/libserene.v0/lib/exprs/call.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/call.h" - -#include "serene/errors.h" -#include "serene/exprs/def.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" -#include "serene/namespace.h" -#include "serene/utils.h" - -#include -#include -#include - -namespace serene { -namespace exprs { - -ExprType Call::getType() const { return ExprType::Call; }; - -std::string Call::toString() const { - return llvm::formatv("", this->target->toString(), - astToString(&this->params)); -} - -MaybeNode Call::analyze(semantics::AnalysisState &state) { - UNUSED(state); - - return EmptyNode; -}; - -bool Call::classof(const Expression *e) { - return e->getType() == ExprType::Call; -}; - -MaybeNode Call::make(semantics::AnalysisState &state, List *list) { - - auto &ctx = state.ns.getContext(); - // TODO: replace this with a runtime check - assert((list->count() != 0) && "Empty call? Seriously ?"); - - // Let's find out what is the first element of the list - auto maybeFirst = list->elements[0]->analyze(state); - - if (!maybeFirst) { - // There's something wrong with the first element. Return the error - return maybeFirst; - } - - Node &first = *maybeFirst; - - // No rewrite is needed for the first element - if (!first) { - first = list->elements[0]; - } - - Node targetNode; - Ast rawParams; - - if (list->count() > 1) { - rawParams = list->from(1); - } - - // We need to create the Call node based on the type of the first - // element after it being analyzed. - switch (first->getType()) { - - // In case of a Symbol, We should look it up in the current scope and - // if it resolves to a value. Then we have to make sure that the - // return value is callable. - case ExprType::Symbol: { - - auto *sym = llvm::dyn_cast(first.get()); - - if (sym == nullptr) { - llvm_unreachable("Couldn't case to Symbol while the type is symbol!"); - } - - auto maybeResult = state.env.lookup(sym->name); - - if (!maybeResult.hasValue()) { - std::string msg = - llvm::formatv("Can't resolve the symbol '{0}'", sym->name); - return errors::makeError(ctx, errors::CantResolveSymbol, sym->location, - msg); - } - - targetNode = std::move(maybeResult.getValue()); - break; - } - - case ExprType::Def: - - // If the first element was a Call itself we need to just chain it - // with a new call. It would be something like `((blah 1) 4)`. `blah` - // should return a callable expression itself, which we need to let - // the typechecker to check - case ExprType::Call: - // If the first element was a function, then just use it as the target - // of the call. It would be like `((fn (x) x) 4)` - case ExprType::Fn: { - targetNode = first; - break; - } - - // Otherwise we don't know how to call the first element. - default: { - std::string msg = llvm::formatv("Don't know how to call a '{0}'", - stringifyExprType(first->getType())); - return errors::makeError(ctx, errors::DontKnowHowToCallNode, - first->location, msg); - } - }; - - auto analyzedParams = semantics::analyze(state, rawParams); - - if (!analyzedParams) { - return analyzedParams.takeError(); - } - - return makeSuccessfulNode(list->location, targetNode, *analyzedParams); -}; -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/def.cpp b/libserene.v0/lib/exprs/def.cpp deleted file mode 100644 index 0f076be..0000000 --- a/libserene.v0/lib/exprs/def.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/def.h" - -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/fn.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" -#include "serene/exprs/traits.h" -#include "serene/slir/dialect.h" -#include "serene/slir/utils.h" - -#include -#include -#include - -namespace serene { -namespace exprs { - -ExprType Def::getType() const { return ExprType::Def; }; - -std::string Def::toString() const { - return llvm::formatv(" {1}>", this->binding, - this->value->toString()); -} - -MaybeNode Def::analyze(semantics::AnalysisState &state) { - UNUSED(state); - - return EmptyNode; -}; - -bool Def::classof(const Expression *e) { - return e->getType() == ExprType::Def; -}; - -MaybeNode Def::make(semantics::AnalysisState &state, List *list) { - auto &ctx = state.ns.getContext(); - - // TODO: Add support for docstring as the 3rd argument (4th element) - if (list->count() != 3) { - std::string msg = llvm::formatv("Expected 3 got {0}", list->count()); - return errors::makeError(ctx, errors::DefWrongNumberOfArgs, - list->elements[0]->location, msg); - } - - // Make sure that the list starts with a `def` - Symbol *defSym = llvm::dyn_cast(list->elements[0].get()); - - assert((defSym && defSym->name == "def") && - "The first element of the list should be a 'def'."); - - // Make sure that the first argument is a Symbol - Symbol *binding = llvm::dyn_cast(list->elements[1].get()); - if (binding == nullptr) { - return errors::makeError(ctx, errors::DefExpectSymbol, - list->elements[1]->location); - } - - // Analyze the value - MaybeNode value = list->elements[2]->analyze(state); - Node analyzedValue; - - // TODO: To refactor this logic into a generic function - if (value) { - // Success value - auto &valueNode = *value; - - if (valueNode) { - // A rewrite is necessary - analyzedValue = valueNode; - } else { - // no rewrite - analyzedValue = list->elements[2]; - } - } else { - // Error value - return value; - } - - if (analyzedValue->getType() == ExprType::Fn) { - Fn *tmp = llvm::dyn_cast(analyzedValue.get()); - if (tmp == nullptr) { - llvm_unreachable("inconsistent getType for function"); - } - - tmp->setName(binding->name); - } - - auto result = state.ns.define(binding->name, analyzedValue); - - if (result.succeeded()) { - return makeSuccessfulNode(list->location, binding->name, - analyzedValue); - } - llvm_unreachable("Inserting a value in the semantic env failed!"); -}; - -void Def::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { - - if (value->getType() == ExprType::Fn) { - value->generateIR(ns, m); - return; - } - - // auto loc = slir::toMLIRLocation(ns, location.start); - // auto &mctx = ns.getContext().mlirContext; - - // mlir::OpBuilder builder(&mctx); - - // auto sym = slir::SymbolType::get(&mctx, ns.name, binding); - - // TODO: we need to change the generate method of expressions - // to return mlir::Value or any wrapper of that which would - // be the ssa form of the result of the expression. - // and then use it to define the def op here. - // auto def = builder.create(sym, binding, value); - m.emitError("Def: not implemented!"); -}; -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/expression.cpp b/libserene.v0/lib/exprs/expression.cpp deleted file mode 100644 index c47df08..0000000 --- a/libserene.v0/lib/exprs/expression.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/expression.h" - -#include - -namespace serene { -namespace exprs { - -std::string astToString(const Ast *tree) { - if (tree->empty()) { - return ""; - } - - std::string result = tree->at(0)->toString(); - - for (unsigned int i = 1; i < tree->size(); i++) { - result = llvm::formatv("{0} {1}", result, tree->at(i)->toString()); - } - - return result; -} - -std::string stringifyExprType(ExprType t) { return exprTypes[(int)t]; }; - -/// Dump the given AST tree to the standard out -void dump(Ast &tree) { llvm::outs() << astToString(&tree) << "\n"; }; - -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/fn.cpp b/libserene.v0/lib/exprs/fn.cpp deleted file mode 100644 index 24a9b77..0000000 --- a/libserene.v0/lib/exprs/fn.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/fn.h" - -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" -#include "serene/slir/dialect.h" -#include "serene/slir/ops.h" -#include "serene/slir/utils.h" - -#include -#include -#include -#include - -#include - -namespace serene { -namespace exprs { - -Fn::Fn(SereneContext &ctx, reader::LocationRange &loc, List &args, Ast body) - : Expression(loc), args(args), body(std::move(body)) { - this->setName( - llvm::formatv("___fn___{0}", ctx.getCurrentNS().nextFnCounter())); -}; - -ExprType Fn::getType() const { return ExprType::Fn; }; - -std::string Fn::toString() const { - return llvm::formatv("", - this->name.empty() ? "Anonymous" : this->name, - this->args.toString(), - this->body.empty() ? "<>" : astToString(&this->body)); -} - -MaybeNode Fn::analyze(semantics::AnalysisState &state) { - UNUSED(state); - - return EmptyNode; -}; - -bool Fn::classof(const Expression *e) { return e->getType() == ExprType::Fn; }; - -void Fn::setName(std::string n) { this->name = std::move(n); }; - -MaybeNode Fn::make(semantics::AnalysisState &state, List *list) { - - auto &ctx = state.ns.getContext(); - - // TODO: Add support for docstring as the 3rd argument (4th element) - if (list->count() < 2) { - return errors::makeError(ctx, errors::FnNoArgsList, - list->elements[0]->location, - "The argument list is mandatory."); - } - - Symbol *fnSym = llvm::dyn_cast(list->elements[0].get()); - - // TODO: Replace this assert with a runtime check - assert((fnSym && fnSym->name == "fn") && - "The first element of the list should be a 'fn'."); - - List *args = llvm::dyn_cast(list->elements[1].get()); - - if (args == nullptr) { - std::string msg = - llvm::formatv("Arguments of a function has to be a list, got '{0}'", - stringifyExprType(list->elements[1]->getType())); - - return errors::makeError(ctx, errors::FnArgsMustBeList, - list->elements[1]->location, msg); - } - - Ast body; - - // If there is a body for this function analyze the body and set - // the retuned ast as the final body - if (list->count() > 2) { - body = std::vector(list->begin() + 2, list->end()); - - // TODO: call state.moveToNewEnv to create a new env and set the - // arguments into the new env. - - auto maybeAst = semantics::analyze(state, body); - - if (!maybeAst) { - return maybeAst.takeError(); - } - - body = *maybeAst; - } - - return makeSuccessfulNode(ctx, list->location, *args, body); -}; - -void Fn::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { - auto loc = slir::toMLIRLocation(ns, location.start); - auto &ctx = ns.getContext(); - - mlir::OpBuilder builder(&ctx.mlirContext); - - // llvm::SmallVector arg_types; - llvm::SmallVector arguments; - // at the moment we only support integers - for (auto &arg : args) { - auto *argSym = llvm::dyn_cast(arg.get()); - - if (argSym == nullptr) { - m->emitError(llvm::formatv( - "Arguments of a function have to be symbols. Fn: '{0}'", name)); - return; - } - - arguments.push_back(builder.getNamedAttr( - argSym->name, mlir::TypeAttr::get(builder.getI64Type()))); - } - - auto fn = builder.create( - loc, builder.getI64Type(), name, - mlir::DictionaryAttr::get(builder.getContext(), arguments), - builder.getStringAttr("public")); - - if (!fn) { - m.emitError(llvm::formatv("Can't create the function '{0}'", name)); - return; - } - - auto &body = fn.body(); - auto *entryBlock = new mlir::Block(); - - body.push_back(entryBlock); - - builder.setInsertionPointToStart(entryBlock); - auto retVal = builder.create(loc, 0).getResult(); - - slir::Return1Op returnOp = builder.create(loc, retVal); - - if (!returnOp) { - m.emitError( - llvm::formatv("Can't create the return value of function '{0}'", name)); - fn.erase(); - return; - } - - m.push_back(fn); -}; -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/list.cpp b/libserene.v0/lib/exprs/list.cpp deleted file mode 100644 index 0ef7923..0000000 --- a/libserene.v0/lib/exprs/list.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/list.h" - -#include "serene/errors.h" -#include "serene/exprs/call.h" -#include "serene/exprs/def.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/fn.h" -#include "serene/exprs/symbol.h" - -#include -#include -#include - -#include -#include - -namespace serene { -namespace exprs { - -List::List(const List &l) : Expression(l.location) { - this->elements = l.elements; -}; - -List::List(const reader::LocationRange &loc, Node &e) : Expression(loc) { - elements.push_back(e); -}; - -List::List(const reader::LocationRange &loc, Ast elems) - : Expression(loc), elements(std::move(elems)){}; - -ExprType List::getType() const { return ExprType::List; }; - -std::string List::toString() const { - std::string s{this->elements.empty() ? "-" : ""}; - - for (const auto &n : this->elements) { - s = llvm::formatv("{0} {1}", s, n->toString()); - } - - return llvm::formatv("", s); -}; - -MaybeNode List::analyze(semantics::AnalysisState &state) { - - if (!elements.empty()) { - auto *first = elements[0].get(); - - if (first->getType() == ExprType::Symbol) { - auto *sym = llvm::dyn_cast(first); - - if (sym != nullptr) { - if (sym->name == "def") { - return Def::make(state, this); - } - - if (sym->name == "fn") { - return Fn::make(state, this); - } - } - } - - return Call::make(state, this); - } - - return EmptyNode; -}; - -bool List::classof(const Expression *e) { - return e->getType() == ExprType::List; -}; - -std::vector::const_iterator List::cbegin() { return elements.begin(); } - -std::vector::const_iterator List::cend() { return elements.end(); } - -std::vector::iterator List::begin() { return elements.begin(); } - -std::vector::iterator List::end() { return elements.end(); } - -size_t List::count() const { return elements.size(); } - -std::optional List::at(uint index) { - if (index >= elements.size()) { - return llvm::None; - } - - return std::optional(this->elements[index].get()); -} - -Ast List::from(uint index) { - if (index < elements.size()) { - return Ast(elements.begin() + index, elements.end()); - } - - return Ast(); -} - -void List::append(Node n) { elements.push_back(std::move(n)); } -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/number.cpp b/libserene.v0/lib/exprs/number.cpp deleted file mode 100644 index e08f997..0000000 --- a/libserene.v0/lib/exprs/number.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/number.h" - -#include "serene/exprs/expression.h" -#include "serene/slir/dialect.h" -#include "serene/slir/ops.h" -#include "serene/slir/utils.h" - -namespace serene { -namespace exprs { - -ExprType Number::getType() const { return ExprType::Number; }; - -std::string Number::toString() const { - return llvm::formatv("", value); -} - -MaybeNode Number::analyze(semantics::AnalysisState &state) { - UNUSED(state); - - return EmptyNode; -}; - -bool Number::classof(const Expression *e) { - return e->getType() == ExprType::Number; -}; - -int Number::toI64() const { return std::stoi(this->value); }; - -void Number::generateIR(serene::Namespace &ns, mlir::ModuleOp &m) { - mlir::OpBuilder builder(&ns.getContext().mlirContext); - - auto op = builder.create( - serene::slir::toMLIRLocation(ns, location.start), toI64()); - - if (op) { - m.push_back(op); - } - // TODO: in case of failure attach the error to the NS -}; -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/exprs/symbol.cpp b/libserene.v0/lib/exprs/symbol.cpp deleted file mode 100644 index b4c0d2a..0000000 --- a/libserene.v0/lib/exprs/symbol.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/symbol.h" - -#include "serene/exprs/expression.h" - -#include -#include - -namespace serene { -namespace exprs { - -ExprType Symbol::getType() const { return ExprType::Symbol; }; - -std::string Symbol::toString() const { - return llvm::formatv("", nsName, name); -} - -MaybeNode Symbol::analyze(semantics::AnalysisState &state) { - UNUSED(state); - - return EmptyNode; -}; - -bool Symbol::classof(const Expression *e) { - return e->getType() == ExprType::Symbol; -}; - -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/lib/jit/engine.cpp b/libserene.v0/lib/jit/engine.cpp deleted file mode 100644 index 68eb87e..0000000 --- a/libserene.v0/lib/jit/engine.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/jit/engine.h" - -#include "serene/context.h" -#include "serene/jit/layers.h" -#include "serene/utils.h" - -#include - -namespace serene::jit { - -static void handleLazyCallThroughError() { - // TODO: Report to the diag engine - llvm::errs() << "LazyCallThrough error: Could not find function body"; - // TODO: terminate ? -} - -SereneJIT::SereneJIT(Namespace &entryNS, - std::unique_ptr es, - std::unique_ptr epciu, - orc::JITTargetMachineBuilder jtmb, llvm::DataLayout &&dl) - - : es(std::move(es)), epciu(std::move(epciu)), dl(dl), - mangler(*this->es, this->dl), - objectLayer( - *this->es, - []() { return std::make_unique(); }), - compileLayer( - *this->es, objectLayer, - std::make_unique(std::move(jtmb))), - transformLayer(*this->es, compileLayer, optimizeModule), - astLayer(transformLayer, mangler), - nsLayer(entryNS.getContext(), transformLayer, mangler, dl), - mainJD(this->es->createBareJITDylib(entryNS.name)), - ctx(entryNS.getContext()), currentNS(entryNS) { - UNUSED(this->ctx); - mainJD.addGenerator( - cantFail(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - dl.getGlobalPrefix()))); - - // if (numCompileThreads > 0) { - // compileOnDemandLayer.setCloneToNewContextOnEmit(true); - // } -} - -llvm::Error SereneJIT::addNS(llvm::StringRef nsname, - orc::ResourceTrackerSP rt) { - if (!rt) { - rt = mainJD.getDefaultResourceTracker(); - } - - return nsLayer.add(rt, nsname); -}; - -llvm::Error SereneJIT::addAst(exprs::Ast &ast, orc::ResourceTrackerSP rt) { - if (!rt) { - rt = mainJD.getDefaultResourceTracker(); - } - - return astLayer.add(rt, getCurrentNS(), ast); -}; - -llvm::Expected> makeSereneJIT(Namespace &ns) { - auto epc = orc::SelfExecutorProcessControl::Create(); - if (!epc) { - return epc.takeError(); - } - auto es = std::make_unique(std::move(*epc)); - auto epciu = - orc::EPCIndirectionUtils::Create(es->getExecutorProcessControl()); - if (!epciu) { - return epciu.takeError(); - } - - (*epciu)->createLazyCallThroughManager( - *es, llvm::pointerToJITTargetAddress(&handleLazyCallThroughError)); - - if (auto err = setUpInProcessLCTMReentryViaEPCIU(**epciu)) { - return std::move(err); - } - - orc::JITTargetMachineBuilder jtmb( - es->getExecutorProcessControl().getTargetTriple()); - - auto dl = jtmb.getDefaultDataLayoutForTarget(); - if (!dl) { - return dl.takeError(); - } - - return std::make_unique(ns, std::move(es), std::move(*epciu), - std::move(jtmb), std::move(*dl)); -}; -} // namespace serene::jit diff --git a/libserene.v0/lib/jit/halley.cpp b/libserene.v0/lib/jit/halley.cpp deleted file mode 100644 index cd4c0ad..0000000 --- a/libserene.v0/lib/jit/halley.cpp +++ /dev/null @@ -1,457 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/jit/halley.h" - -#include "serene/context.h" -#include "serene/diagnostics.h" -#include "serene/errors.h" -#include "serene/exprs/symbol.h" -#include "serene/namespace.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define COMMON_ARGS_COUNT 8 -// Just to make the linter happy -#define I64_BIT_SIZE 64 - -namespace serene { - -namespace jit { - -static std::string makePackedFunctionName(llvm::StringRef name) { - // TODO: move the "_serene_" constant to a macro or something - return "_serene_" + name.str(); -} - -static void packFunctionArguments(llvm::Module *module) { - auto &ctx = module->getContext(); - llvm::IRBuilder<> builder(ctx); - llvm::DenseSet interfaceFunctions; - for (auto &func : module->getFunctionList()) { - if (func.isDeclaration()) { - continue; - } - if (interfaceFunctions.count(&func) != 0) { - continue; - } - - // Given a function `foo(<...>)`, define the interface function - // `serene_foo(i8**)`. - auto *newType = llvm::FunctionType::get( - builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(), - /*isVarArg=*/false); - auto newName = makePackedFunctionName(func.getName()); - auto funcCst = module->getOrInsertFunction(newName, newType); - llvm::Function *interfaceFunc = - llvm::cast(funcCst.getCallee()); - interfaceFunctions.insert(interfaceFunc); - - // Extract the arguments from the type-erased argument list and cast them to - // the proper types. - auto *bb = llvm::BasicBlock::Create(ctx); - bb->insertInto(interfaceFunc); - builder.SetInsertPoint(bb); - llvm::Value *argList = interfaceFunc->arg_begin(); - llvm::SmallVector args; - args.reserve(llvm::size(func.args())); - for (const auto &indexedArg : llvm::enumerate(func.args())) { - llvm::Value *argIndex = llvm::Constant::getIntegerValue( - builder.getInt64Ty(), llvm::APInt(I64_BIT_SIZE, indexedArg.index())); - llvm::Value *argPtrPtr = - builder.CreateGEP(builder.getInt8PtrTy(), argList, argIndex); - llvm::Value *argPtr = - builder.CreateLoad(builder.getInt8PtrTy(), argPtrPtr); - llvm::Type *argTy = indexedArg.value().getType(); - argPtr = builder.CreateBitCast(argPtr, argTy->getPointerTo()); - llvm::Value *arg = builder.CreateLoad(argTy, argPtr); - args.push_back(arg); - } - - // Call the implementation function with the extracted arguments. - llvm::Value *result = builder.CreateCall(&func, args); - - // Assuming the result is one value, potentially of type `void`. - if (!result->getType()->isVoidTy()) { - llvm::Value *retIndex = llvm::Constant::getIntegerValue( - builder.getInt64Ty(), - llvm::APInt(I64_BIT_SIZE, llvm::size(func.args()))); - llvm::Value *retPtrPtr = - builder.CreateGEP(builder.getInt8PtrTy(), argList, retIndex); - llvm::Value *retPtr = - builder.CreateLoad(builder.getInt8PtrTy(), retPtrPtr); - retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo()); - builder.CreateStore(result, retPtr); - } - - // The interface function returns void. - builder.CreateRetVoid(); - } -}; - -void ObjectCache::notifyObjectCompiled(const llvm::Module *m, - llvm::MemoryBufferRef objBuffer) { - cachedObjects[m->getModuleIdentifier()] = - llvm::MemoryBuffer::getMemBufferCopy(objBuffer.getBuffer(), - objBuffer.getBufferIdentifier()); -} - -std::unique_ptr -ObjectCache::getObject(const llvm::Module *m) { - auto i = cachedObjects.find(m->getModuleIdentifier()); - - if (i == cachedObjects.end()) { - HALLEY_LOG("No object for " + m->getModuleIdentifier() + - " in cache. Compiling."); - return nullptr; - } - HALLEY_LOG("Object for " + m->getModuleIdentifier() + " loaded from cache."); - return llvm::MemoryBuffer::getMemBuffer(i->second->getMemBufferRef()); -} - -void ObjectCache::dumpToObjectFile(llvm::StringRef outputFilename) { - // Set up the output file. - std::string errorMessage; - auto file = mlir::openOutputFile(outputFilename, &errorMessage); - if (!file) { - llvm::errs() << errorMessage << "\n"; - return; - } - - // Dump the object generated for a single module to the output file. - // TODO: Replace this with a runtime check - assert(cachedObjects.size() == 1 && "Expected only one object entry."); - - auto &cachedObject = cachedObjects.begin()->second; - file->os() << cachedObject->getBuffer(); - file->keep(); -} - -Halley::Halley(serene::SereneContext &ctx, - llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl) - : cache(ctx.opts.JITenableObjectCache ? new ObjectCache() : nullptr), - gdbListener(ctx.opts.JITenableGDBNotificationListener - - ? llvm::JITEventListener::createGDBRegistrationListener() - : nullptr), - perfListener(ctx.opts.JITenablePerfNotificationListener - ? llvm::JITEventListener::createPerfJITEventListener() - : nullptr), - jtmb(jtmb), dl(dl), ctx(ctx), - activeNS(ctx.getSharedPtrToNS(ctx.getCurrentNS().name)) { - assert(activeNS != nullptr && "Active NS is null!!!"); -}; - -MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { - HALLEY_LOG("Looking up: " << sym.toString()); - auto *ns = ctx.getNS(sym.nsName); - - if (ns == nullptr) { - return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, - "Can't find the namespace in the context: " + - sym.nsName); - } - - auto *dylib = ctx.getLatestJITDylib(*ns); - // - - if (dylib == nullptr) { - return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, - "Don't know about namespace: " + sym.nsName); - } - - auto expectedSymbol = - engine->lookup(*dylib, makePackedFunctionName(sym.name)); - - // JIT lookup may return an Error referring to strings stored internally by - // the JIT. If the Error outlives the ExecutionEngine, it would want have a - // dangling reference, which is currently caught by an assertion inside JIT - // thanks to hand-rolled reference counting. Rewrap the error message into a - // string before returning. Alternatively, ORC JIT should consider copying - // the string into the error message. - if (!expectedSymbol) { - std::string errorMessage; - llvm::raw_string_ostream os(errorMessage); - llvm::handleAllErrors(expectedSymbol.takeError(), - [&os](llvm::ErrorInfoBase &ei) { ei.log(os); }); - return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, - os.str()); - } - - auto rawFPtr = expectedSymbol->getValue(); - // NOLINTNEXTLINE(performance-no-int-to-ptr) - auto fptr = reinterpret_cast(rawFPtr); - - if (fptr == nullptr) { - return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, - "Lookup function is null!"); - } - - return fptr; -}; - -// llvm::Error Halley::invokePacked(llvm::StringRef name, -// llvm::MutableArrayRef args) const { -// auto expectedFPtr = lookup(name); -// if (!expectedFPtr) { -// return expectedFPtr.takeError(); -// } -// auto fptr = *expectedFPtr; - -// (*fptr)(args.data()); - -// return llvm::Error::success(); -// } - -llvm::Error Halley::addNS(Namespace &ns, reader::LocationRange &loc) { - - HALLEY_LOG(llvm::formatv("Creating Dylib {0}#{1}", ns.name, - ctx.getNumberOfJITDylibs(ns) + 1)); - - auto newDylib = engine->createJITDylib( - llvm::formatv("{0}#{1}", ns.name, ctx.getNumberOfJITDylibs(ns) + 1)); - - if (!newDylib) { - return errors::makeError(ctx, errors::CompilationError, loc, - "Filed to create dylib for " + ns.name); - } - - ctx.pushJITDylib(ns, &(*newDylib)); - - // TODO: Fix compileToLLVM to return proper errors - auto maybeModule = ns.compileToLLVM(); - - if (!maybeModule.hasValue()) { - return errors::makeError(ctx, errors::CompilationError, loc); - } - - auto tsm = std::move(maybeModule.getValue()); - tsm.withModuleDo([](llvm::Module &m) { packFunctionArguments(&m); }); - - // TODO: Make sure that the data layout of the module is the same as the - // engine - cantFail(engine->addIRModule(*newDylib, std::move(tsm))); - return llvm::Error::success(); -}; - -void Halley::setEngine(std::unique_ptr e, bool isLazy) { - // Later on we might use different classes of JIT which might need some - // work for lazyness - engine = std::move(e); - this->isLazy = isLazy; -}; - -void Halley::dumpToObjectFile(llvm::StringRef filename) { - cache->dumpToObjectFile(filename); -}; - -MaybeJIT Halley::make(SereneContext &serene_ctx, - llvm::orc::JITTargetMachineBuilder &&jtmb) { - - auto dl = jtmb.getDefaultDataLayoutForTarget(); - if (!dl) { - return dl.takeError(); - } - - auto jitEngine = - std::make_unique(serene_ctx, std::move(jtmb), std::move(*dl)); - - // Why not the llvmcontext from the SereneContext?? - // Sice we're going to pass the ownership of this context to a thread - // safe module later on and we will only create the jit function wrappers - // with it, then it is fine to use a new context. - // - // What might go wrong? - // in a repl env when we have to create new modules on top of each other - // having two different contex might be a problem, but i think since we - // use the first context to generate the IR and the second one to just - // run it. - std::unique_ptr ctx(new llvm::LLVMContext); - - // Callback to create the object layer with symbol resolution to current - // process and dynamically linked libraries. - auto objectLinkingLayerCreator = [&](llvm::orc::ExecutionSession &session, - const llvm::Triple &tt) { - UNUSED(tt); - - auto objectLayer = - std::make_unique(session, []() { - return std::make_unique(); - }); - - // Register JIT event listeners if they are enabled. - if (jitEngine->gdbListener != nullptr) { - objectLayer->registerJITEventListener(*jitEngine->gdbListener); - } - if (jitEngine->perfListener != nullptr) { - objectLayer->registerJITEventListener(*jitEngine->perfListener); - } - - // COFF format binaries (Windows) need special handling to deal with - // exported symbol visibility. - // cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp - // LLJIT::createObjectLinkingLayer - - if (serene_ctx.triple.isOSBinFormatCOFF()) { - objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); - objectLayer->setAutoClaimResponsibilityForObjectSymbols(true); - } - - // Resolve symbols from shared libraries. - // for (auto libPath : sharedLibPaths) { - // auto mb = llvm::MemoryBuffer::getFile(libPath); - // if (!mb) { - // llvm::errs() << "Failed to create MemoryBuffer for: " << libPath - // << "\nError: " << mb.getError().message() << "\n"; - // continue; - // } - // auto &JD = session.createBareJITDylib(std::string(libPath)); - // auto loaded = llvm::orc::DynamicLibrarySearchGenerator::Load( - // libPath.data(), dataLayout.getGlobalPrefix()); - // if (!loaded) { - // llvm::errs() << "Could not load " << libPath << ":\n " - // << loaded.takeError() << "\n"; - // continue; - // } - - // JD.addGenerator(std::move(*loaded)); - // cantFail(objectLayer->add(JD, std::move(mb.get()))); - // } - - return objectLayer; - }; - - // Callback to inspect the cache and recompile on demand. This follows Lang's - // LLJITWithObjectCache example. - auto compileFunctionCreator = [&](llvm::orc::JITTargetMachineBuilder JTMB) - -> llvm::Expected< - std::unique_ptr> { - llvm::CodeGenOpt::Level jitCodeGenOptLevel = - static_cast(serene_ctx.getOptimizatioLevel()); - - JTMB.setCodeGenOptLevel(jitCodeGenOptLevel); - - auto targetMachine = JTMB.createTargetMachine(); - if (!targetMachine) { - return targetMachine.takeError(); - } - - return std::make_unique( - std::move(*targetMachine), jitEngine->cache.get()); - }; - - if (serene_ctx.opts.JITLazy) { - // Setup a LLLazyJIT instance to the times that latency is important - // for example in a REPL. This way - - auto jit = - cantFail(llvm::orc::LLLazyJITBuilder() - .setCompileFunctionCreator(compileFunctionCreator) - .setObjectLinkingLayerCreator(objectLinkingLayerCreator) - .create()); - jitEngine->setEngine(std::move(jit), true); - - } else { - // Setup a LLJIT instance for the times that performance is important - // and we want to compile everything as soon as possible. For instance - // when we run the JIT in the compiler - auto jit = - cantFail(llvm::orc::LLJITBuilder() - .setCompileFunctionCreator(compileFunctionCreator) - .setObjectLinkingLayerCreator(objectLinkingLayerCreator) - .create()); - - jitEngine->setEngine(std::move(jit), false); - } - - jitEngine->engine->getIRCompileLayer().setNotifyCompiled( - [&](llvm::orc::MaterializationResponsibility &r, - llvm::orc::ThreadSafeModule tsm) { - auto syms = r.getRequestedSymbols(); - tsm.withModuleDo([&](llvm::Module &m) { - HALLEY_LOG("Compiled " - << syms << " for the module: " << m.getModuleIdentifier()); - }); - }); - - // Resolve symbols that are statically linked in the current process. - llvm::orc::JITDylib &mainJD = jitEngine->engine->getMainJITDylib(); - mainJD.addGenerator( - cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - jitEngine->dl.getGlobalPrefix()))); - - return MaybeJIT(std::move(jitEngine)); -}; - -llvm::Error Halley::addAST(exprs::Ast &ast) { - auto offset = activeNS->getTree().size(); - - if (auto errs = activeNS->addTree(ast)) { - return errs; - } - - auto maybeModule = activeNS->compileToLLVMFromOffset(offset); - - auto tsm = std::move(maybeModule.getValue()); - tsm.withModuleDo([](llvm::Module &m) { packFunctionArguments(&m); }); - - auto *dylib = ctx.getLatestJITDylib(*activeNS); - // TODO: Make sure that the data layout of the module is the same as the - // engine - cantFail(engine->addIRModule(*dylib, std::move(tsm))); - return llvm::Error::success(); -}; - -Namespace &Halley::getActiveNS() { return *activeNS; }; - -llvm::Expected> makeHalleyJIT(SereneContext &ctx) { - - llvm::orc::JITTargetMachineBuilder jtmb(ctx.triple); - auto maybeJIT = Halley::make(ctx, std::move(jtmb)); - if (!maybeJIT) { - return maybeJIT.takeError(); - } - - return maybeJIT; -}; -} // namespace jit -} // namespace serene diff --git a/libserene.v0/lib/jit/layers.cpp b/libserene.v0/lib/jit/layers.cpp deleted file mode 100644 index 09044fd..0000000 --- a/libserene.v0/lib/jit/layers.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/jit/layers.h" - -#include "serene/context.h" -#include "serene/exprs/fn.h" -#include "serene/exprs/traits.h" - -#include -#include // for report_fatal_error - -#include - -namespace serene::jit { - -llvm::orc::ThreadSafeModule compileAst(Namespace &ns, exprs::Ast &ast) { - - assert(ns.getTree().size() < ast.size() && "Did you add the ast to the NS?"); - - LAYER_LOG("Compile in context of namespace: " + ns.name); - unsigned offset = ns.getTree().size() - ast.size(); - - auto maybeModule = ns.compileToLLVMFromOffset(offset); - - if (!maybeModule) { - // TODO: Handle failure - llvm::report_fatal_error("Couldn't compile lazily JIT'd function"); - } - - return std::move(maybeModule.getValue()); -}; - -AstMaterializationUnit::AstMaterializationUnit(Namespace &ns, AstLayer &l, - exprs::Ast &ast) - : orc::MaterializationUnit(l.getInterface(ns, ast)), ns(ns), astLayer(l), - ast(ast){}; - -void AstMaterializationUnit::materialize( - std::unique_ptr r) { - astLayer.emit(std::move(r), ns, ast); -} - -orc::MaterializationUnit::Interface AstLayer::getInterface(Namespace &ns, - exprs::Ast &e) { - orc::SymbolFlagsMap Symbols; - auto symList = ns.getSymList(); - unsigned index = symList.size(); - - // This probably will change symList - auto err = ns.addTree(e); - - if (err) { - // TODO: Fix this by a call to diag engine or return the err - llvm::outs() << "Fixme: semantic err\n"; - return orc::MaterializationUnit::Interface(std::move(Symbols), nullptr); - } - - auto &env = ns.getRootEnv(); - auto populateTableFn = [&env, this, &Symbols](auto name) { - auto flags = llvm::JITSymbolFlags::Exported; - auto maybeExpr = env.lookup(name.str()); - - if (!maybeExpr) { - LAYER_LOG("Skiping '" + name + "' symbol"); - return; - } - - auto expr = maybeExpr.getValue(); - - if (expr->getType() == exprs::ExprType::Fn) { - flags = flags | llvm::JITSymbolFlags::Callable; - } - - auto mangledSym = this->mangler(name); - LAYER_LOG("Mangle symbol for: " + name + " = " << mangledSym); - Symbols[mangledSym] = llvm::JITSymbolFlags(flags); - }; - - std::for_each(symList.begin() + index, symList.end(), populateTableFn); - return orc::MaterializationUnit::Interface(std::move(Symbols), nullptr); -} - -/// NS Layer ================================================================== - -llvm::orc::ThreadSafeModule compileNS(Namespace &ns) { - LAYER_LOG("Compile namespace: " + ns.name); - - auto maybeModule = ns.compileToLLVM(); - - if (!maybeModule) { - // TODO: Handle failure - llvm::report_fatal_error("Couldn't compile lazily JIT'd function"); - } - - return std::move(maybeModule.getValue()); -}; - -NSMaterializationUnit::NSMaterializationUnit(NSLayer &l, Namespace &ns) - : MaterializationUnit(l.getInterface(ns)), nsLayer(l), ns(ns){}; - -void NSMaterializationUnit::materialize( - std::unique_ptr r) { - nsLayer.emit(std::move(r), ns); -} - -llvm::Error NSLayer::add(orc::ResourceTrackerSP &rt, llvm::StringRef nsname, - reader::LocationRange &loc) { - - LAYER_LOG("Add namespace: " + nsname); - auto maybeNS = ctx.readNamespace(nsname.str(), loc); - - if (!maybeNS) { - // TODO: Fix this by making Serene errors compatible with llvm::Error - auto err = maybeNS.takeError(); - return err; - } - - auto ns = *maybeNS; - - LAYER_LOG("Add the materialize unit for: " + nsname); - return rt->getJITDylib().define( - std::make_unique(*this, *ns), rt); -} - -orc::MaterializationUnit::Interface -NSLayer::getInterface(serene::Namespace &ns) { - orc::SymbolFlagsMap Symbols; - - for (auto &k : ns.getRootEnv()) { - auto flags = llvm::JITSymbolFlags::Exported; - auto name = k.getFirst(); - auto expr = k.getSecond(); - - if (expr->getType() == exprs::ExprType::Fn) { - flags = flags | llvm::JITSymbolFlags::Callable; - } - - auto mangledSym = mangler(name); - LAYER_LOG("Mangle symbol for: " + name + " = " << mangledSym); - Symbols[mangledSym] = llvm::JITSymbolFlags(flags); - } - - return orc::MaterializationUnit::Interface(std::move(Symbols), nullptr); -} - -} // namespace serene::jit diff --git a/libserene.v0/lib/namespace.cpp b/libserene.v0/lib/namespace.cpp deleted file mode 100644 index 11b3880..0000000 --- a/libserene.v0/lib/namespace.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "serene/namespace.h" - -#include "serene/context.h" -#include "serene/export.h" -#include "serene/exprs/expression.h" -#include "serene/llvm/IR/Value.h" -#include "serene/semantics.h" -#include "serene/slir/slir.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace std; -using namespace llvm; - -namespace serene { - -Namespace::Namespace(SereneContext &ctx, llvm::StringRef ns_name, - std::optional filename) - : ctx(ctx), name(ns_name) { - if (filename.hasValue()) { - this->filename.emplace(filename.getValue().str()); - } - - // Create the root environment - createEnv(nullptr); -}; - -SemanticEnv &Namespace::createEnv(SemanticEnv *parent) { - auto env = std::make_unique(parent); - environments.push_back(std::move(env)); - - return *environments.back(); -}; - -SemanticEnv &Namespace::getRootEnv() { - assert(!environments.empty() && "Root env is not created!"); - - return *environments.front(); -}; - -mlir::LogicalResult Namespace::define(std::string &name, exprs::Node &node) { - auto &rootEnv = getRootEnv(); - - if (failed(rootEnv.insert_symbol(name, node))) { - return mlir::failure(); - } - - symbolList.push_back(name); - return mlir::success(); -} - -exprs::Ast &Namespace::getTree() { return this->tree; } - -llvm::Error Namespace::addTree(exprs::Ast &ast) { - - // If the target phase is just parsing we don't want - // to run the semantic analyzer or anything beyond parser - if (ctx.getTargetPhase() == CompilationPhase::Parse) { - // we just want the raw AST - this->tree.insert(this->tree.end(), ast.begin(), ast.end()); - return llvm::Error::success(); - } - - auto &rootEnv = getRootEnv(); - - auto state = semantics::makeAnalysisState(*this, rootEnv); - // Run the semantic analyer on the ast and then if everything - // is ok add the form to the tree and forms - auto maybeForm = semantics::analyze(*state, ast); - - if (!maybeForm) { - return maybeForm.takeError(); - } - - auto semanticAst = std::move(*maybeForm); - this->tree.insert(this->tree.end(), semanticAst.begin(), semanticAst.end()); - - return llvm::Error::success(); -} - -uint Namespace::nextFnCounter() { return fn_counter++; }; - -SereneContext &Namespace::getContext() { return this->ctx; }; - -MaybeModuleOp Namespace::generate(unsigned offset) { - // The reason why we return an optional value instead of Errors - // is the way MLIR's diagnostic engine works. Passes may use - // the `emit` function of operations to report errors to the - // diagnostic engine. So we can't return any error diractly. - - mlir::OpBuilder builder(&ctx.mlirContext); - - // TODO: Fix the unknown location by pointing to the `ns` form - auto module = mlir::ModuleOp::create(builder.getUnknownLoc(), - std::optional(name)); - - auto treeSize = getTree().size(); - - // Walk the AST and call the `generateIR` function of each node. - // Since nodes will have access to the a reference of the - // namespace they can use the builder and keep adding more - // operations to the module via the builder - for (unsigned i = offset; i < treeSize; ++i) { - auto &node = getTree()[i]; - node->generateIR(*this, module); - } - - if (mlir::failed(mlir::verify(module))) { - module.emitError("Can't verify the module"); - module.erase(); - return llvm::None; - } - - if (mlir::failed(runPasses(module))) { - // TODO: Report a proper error - module.emitError("Failure in passes!"); - module.erase(); - return llvm::None; - } - - return MaybeModuleOp(module); -} - -mlir::LogicalResult Namespace::runPasses(mlir::ModuleOp &m) { - return ctx.pm.run(m); -}; - -void Namespace::dump() { - llvm::outs() << "\nMLIR: \n"; - auto maybeModuleOp = generate(); - - if (!maybeModuleOp) { - - llvm::errs() << "Failed to generate the IR.\n"; - return; - } - - mlir::OpPrintingFlags flags; - flags.enableDebugInfo(); - - maybeModuleOp.getValue()->print(llvm::outs(), flags); -}; - -MaybeModule Namespace::compileToLLVM() { - // The reason why we return an optional value instead of Errors - // is the way MLIR's diagnostic engine works. Passes may use - // the `emit` function of operations to report errors to the - // diagnostic engine. So we can't return any error diractly. - - auto maybeModule = generate(); - - if (!maybeModule) { - NAMESPACE_LOG("IR generation failed for '" << name << "'"); - return llvm::None; - } - - if (ctx.getTargetPhase() >= CompilationPhase::IR) { - mlir::ModuleOp module = maybeModule.getValue().get(); - return ::serene::slir::compileToLLVMIR(ctx, module); - } - - return llvm::None; -}; - -MaybeModule Namespace::compileToLLVMFromOffset(unsigned offset) { - // The reason why we return an optional value instead of Errors - // is the way MLIR's diagnostic engine works. Passes may use - // the `emit` function of operations to report errors to the - // diagnostic engine. So we can't return any error diractly. - - auto maybeModule = generate(offset); - - if (!maybeModule) { - NAMESPACE_LOG("IR generation failed for '" << name << "'"); - return llvm::None; - } - - if (ctx.getTargetPhase() >= CompilationPhase::IR) { - mlir::ModuleOp module = maybeModule.getValue().get(); - return ::serene::slir::compileToLLVMIR(ctx, module); - } - - return llvm::None; -}; - -NSPtr Namespace::make(SereneContext &ctx, llvm::StringRef name, - std::optional filename) { - return std::make_shared(ctx, name, filename); -}; - -Namespace::~Namespace() { - // TODO: Clean up anything related to this namespace in the context - // TODO: Remove anything related to this namespace in the JIT - NAMESPACE_LOG("Destructing NS: " << name); -}; - -} // namespace serene diff --git a/libserene.v0/lib/passes/slir_lowering.cpp b/libserene.v0/lib/passes/slir_lowering.cpp deleted file mode 100644 index 289d43f..0000000 --- a/libserene.v0/lib/passes/slir_lowering.cpp +++ /dev/null @@ -1,761 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/context.h" -#include "serene/conventions.h" -#include "serene/diagnostics.h" -#include "serene/passes.h" -#include "serene/slir/dialect.h" -#include "serene/slir/ops.h" -#include "serene/slir/type_converter.h" -#include "serene/slir/types.h" -#include "serene/utils.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ll = mlir::LLVM; - -namespace serene::passes { - -// static ll::GlobalOp getOrCreateInternalString(mlir::Location loc, -// mlir::OpBuilder &builder, -// llvm::StringRef name, -// llvm::StringRef value, -// mlir::ModuleOp module) { - -// // Create the global at the entry of the module. -// ll::GlobalOp global; - -// if (!(global = module.lookupSymbol(name))) { -// mlir::OpBuilder::InsertionGuard insertGuard(builder); -// builder.setInsertionPointToStart(module.getBody()); - -// auto type = ll::LLVMArrayType::get( -// mlir::IntegerType::get(builder.getContext(), I8_SIZE), value.size()); -// // TODO: Do we want link once ? -// global = builder.create(loc, type, /*isConstant=*/true, -// ll::Linkage::Linkonce, name, -// builder.getStringAttr(value), -// /*alignment=*/0); -// } - -// return global; -// }; - -// static mlir::Value getPtrToInternalString(mlir::OpBuilder &builder, -// ll::GlobalOp global) { -// auto loc = global.getLoc(); -// auto I8 = mlir::IntegerType::get(builder.getContext(), I8_SIZE); -// // Get the pointer to the first character in the global string. -// mlir::Value globalPtr = builder.create(loc, global); -// mlir::Value cst0 = builder.create( -// loc, mlir::IntegerType::get(builder.getContext(), I64_SIZE), -// builder.getIntegerAttr(builder.getIndexType(), 0)); - -// return builder.create(loc, ll::LLVMPointerType::get(I8), -// globalPtr, -// llvm::ArrayRef({cst0})); -// }; - -// static ll::GlobalOp getOrCreateString(mlir::Location loc, -// mlir::OpBuilder &builder, -// llvm::StringRef name, -// llvm::StringRef value, uint32_t len, -// mlir::ModuleOp module) { -// auto *ctx = builder.getContext(); -// ll::GlobalOp global; - -// if (!(global = module.lookupSymbol(name))) { - -// mlir::OpBuilder::InsertionGuard insertGuard(builder); -// builder.setInsertionPointToStart(module.getBody()); - -// mlir::Attribute initValue{}; -// auto type = slir::getStringTypeinLLVM(*ctx); - -// global = builder.create( -// loc, type, /*isConstant=*/true, ll::Linkage::Linkonce, name, -// initValue); - -// auto &gr = global.getInitializerRegion(); -// auto *block = builder.createBlock(&gr); - -// if (block == nullptr) { -// module.emitError("Faild to create block of the globalOp!"); -// // TODO: change the return type to Expected and return -// // an error here -// } - -// builder.setInsertionPoint(block, block->begin()); - -// mlir::Value structInstant = builder.create(loc, type); - -// auto strOp = getOrCreateInternalString(loc, builder, name, value, -// module); auto ptrToStr = getPtrToInternalString(builder, strOp); - -// auto length = builder.create( -// loc, mlir::IntegerType::get(ctx, I32_SIZE), -// builder.getI32IntegerAttr(len)); - -// // Setting the string pointer field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, ptrToStr, -// builder.getI64ArrayAttr(0)); - -// // Setting the len field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, length, -// builder.getI64ArrayAttr(1)); - -// builder.create(loc, structInstant); -// } - -// return global; -// }; - -// static ll::GlobalOp getOrCreateSymbol(mlir::Location loc, -// mlir::OpBuilder &builder, -// llvm::StringRef ns, llvm::StringRef -// name, mlir::ModuleOp module) { -// std::string fqName; -// ll::GlobalOp global; - -// auto *ctx = builder.getContext(); -// auto symName = serene::mangleInternalSymName(fqName); - -// makeFQSymbolName(ns, name, fqName); - -// if (!(global = module.lookupSymbol(symName))) { -// mlir::OpBuilder::InsertionGuard insertGuard(builder); -// builder.setInsertionPointToStart(module.getBody()); - -// mlir::Attribute initValue{}; -// auto type = slir::getSymbolTypeinLLVM(*ctx); - -// // We want to allow merging the strings representing the ns or name part -// // of the symbol with other modules to unify them. -// ll::Linkage linkage = ll::Linkage::Linkonce; - -// global = builder.create(loc, type, /*isConstant=*/true, -// linkage, symName, initValue); - -// auto &gr = global.getInitializerRegion(); -// auto *block = builder.createBlock(&gr); - -// if (block == nullptr) { -// module.emitError("Faild to create block of the globalOp!"); -// // TODO: change the return type to Expected and return -// // an error here -// } - -// builder.setInsertionPoint(block, block->begin()); - -// mlir::Value structInstant = builder.create(loc, type); - -// // We want to use the mangled ns as the name of the constant that -// // holds the ns string -// auto mangledNSName = serene::mangleInternalStringName(ns); -// // The globalop that we want to use for the ns field -// auto nsField = -// getOrCreateString(loc, builder, mangledNSName, ns, ns.size(), -// module); -// auto ptrToNs = builder.create(loc, nsField); - -// // We want to use the mangled 'name' as the name of the constant that -// // holds the 'name' string -// auto mangledName = serene::mangleInternalStringName(name); -// // The global op to use as the 'name' field -// auto nameField = -// getOrCreateString(loc, builder, mangledName, name, name.size(), -// module); -// auto ptrToName = builder.create(loc, nameField); - -// // Setting the string pointer field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, ptrToNs, -// builder.getI64ArrayAttr(0)); - -// // Setting the len field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, ptrToName, -// builder.getI64ArrayAttr(0)); - -// builder.create(loc, structInstant); -// } - -// return global; -// }; - -// static ll::GlobalOp getOrCreateSymbol(mlir::Location loc, -// mlir::OpBuilder &builder, mlir::Value -// ns, mlir::Value name, mlir::ModuleOp -// module) { - -// assert(!ns.getType().isa() && -// !ns.getType().isa() && -// "TypeError: ns and name has to be strings"); - -// std::string fqName; -// ll::GlobalOp global; - -// auto *ctx = builder.getContext(); -// auto symName = serene::mangleInternalSymName(fqName); - -// makeFQSymbolName(ns, name, fqName); - -// if (!(global = module.lookupSymbol(symName))) { -// mlir::OpBuilder::InsertionGuard insertGuard(builder); -// builder.setInsertionPointToStart(module.getBody()); - -// mlir::Attribute initValue{}; -// auto type = slir::getSymbolTypeinLLVM(*ctx); - -// // We want to allow merging the strings representing the ns or name part -// // of the symbol with other modules to unify them. -// ll::Linkage linkage = ll::Linkage::Linkonce; - -// global = builder.create(loc, type, /*isConstant=*/true, -// linkage, symName, initValue); - -// auto &gr = global.getInitializerRegion(); -// auto *block = builder.createBlock(&gr); - -// if (block == nullptr) { -// module.emitError("Faild to create block of the globalOp!"); -// // TODO: change the return type to Expected and return -// // an error here -// } - -// builder.setInsertionPoint(block, block->begin()); - -// mlir::Value structInstant = builder.create(loc, type); - -// // We want to use the mangled ns as the name of the constant that -// // holds the ns string -// auto mangledNSName = serene::mangleInternalStringName(ns); -// // The globalop that we want to use for the ns field -// auto nsField = -// getOrCreateString(loc, builder, mangledNSName, ns, ns.size(), -// module); -// auto ptrToNs = builder.create(loc, nsField); - -// // We want to use the mangled 'name' as the name of the constant that -// // holds the 'name' string -// auto mangledName = serene::mangleInternalStringName(name); -// // The global op to use as the 'name' field -// auto nameField = -// getOrCreateString(loc, builder, mangledName, name, name.size(), -// module); -// auto ptrToName = builder.create(loc, nameField); - -// // Setting the string pointer field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, ptrToNs, -// builder.getI64ArrayAttr(0)); - -// // Setting the len field -// structInstant = builder.create( -// loc, structInstant.getType(), structInstant, ptrToName, -// builder.getI64ArrayAttr(0)); - -// builder.create(loc, structInstant); -// } - -// return global; -// }; - -// struct LowerIntern : public mlir::OpConversionPattern { -// using OpConversionPattern::OpConversionPattern; - -// mlir::LogicalResult -// matchAndRewrite(serene::slir::InternOp op, OpAdaptor adaptor, -// mlir::ConversionPatternRewriter &rewriter) const override; -// }; - -// mlir::LogicalResult -// LowerIntern::matchAndRewrite(serene::slir::InternOp op, OpAdaptor adaptor, -// mlir::ConversionPatternRewriter &rewriter) const -// { - -// UNUSED(adaptor); -// auto ns = op.ns(); -// auto name = op.name(); -// auto loc = op.getLoc(); -// auto module = op->getParentOfType(); - -// // If there is no use for the result of this op then simply erase it -// if (op.getResult().use_empty()) { -// rewriter.eraseOp(op); -// return mlir::success(); -// } - -// auto global = getOrCreateSymbol(loc, rewriter, ns, name, module); -// auto ptr = rewriter.create(loc, global); - -// rewriter.replaceOp(op, ptr.getResult()); - -// return mlir::success(); -// } - -// struct LowerSymbol : public mlir::OpConversionPattern { -// using OpConversionPattern::OpConversionPattern; - -// mlir::LogicalResult -// matchAndRewrite(serene::slir::SymbolOp op, OpAdaptor adaptor, -// mlir::ConversionPatternRewriter &rewriter) const override; -// }; - -// mlir::LogicalResult -// LowerSymbol::matchAndRewrite(serene::slir::SymbolOp op, OpAdaptor adaptor, -// mlir::ConversionPatternRewriter &rewriter) const -// { - -// UNUSED(adaptor); -// auto ns = op.ns(); -// auto name = op.name(); -// auto loc = op.getLoc(); -// auto module = op->getParentOfType(); - -// // If there is no use for the result of this op then simply erase it -// if (op.getResult().use_empty()) { -// rewriter.eraseOp(op); -// return mlir::success(); -// } - -// auto global = getOrCreateSymbol(loc, rewriter, ns, name, module); -// auto ptr = rewriter.create(loc, global); - -// rewriter.replaceOp(op, ptr.getResult()); - -// return mlir::success(); -// } - -struct LowerDefine : public mlir::OpConversionPattern { - using OpConversionPattern::OpConversionPattern; - - mlir::LogicalResult - matchAndRewrite(serene::slir::DefineOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const override; -}; - -mlir::LogicalResult -LowerDefine::matchAndRewrite(serene::slir::DefineOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const { - - (void)rewriter; - (void)adaptor; - - auto value = op.value(); - auto *valueop = value.getDefiningOp(); - auto maybeTopLevel = op.is_top_level(); - bool isTopLevel = false; - - if (maybeTopLevel) { - isTopLevel = *maybeTopLevel; - } - - // If the value than we bind a name to is a constant, rewrite to - // `define_constant` - - // TODO: Replace the isConstantLike with a `hasTrait` call - if (mlir::detail::isConstantLike(valueop)) { - - mlir::Attribute constantValue; - if (!mlir::matchPattern(value, mlir::m_Constant(&constantValue))) { - PASS_LOG( - "Failure: The constant like op don't have a constant attribute."); - return mlir::failure(); - } - - rewriter.replaceOpWithNewOp( - op, op.sym_name(), constantValue, rewriter.getBoolAttr(isTopLevel), - op.sym_visibilityAttr()); - - if (valueop->use_empty()) { - PASS_LOG("Erase op due to empty use:" << valueop); - rewriter.eraseOp(valueop); - } - - return mlir::success(); - } - - // If the value was a Function literal (like an anonymous function) - // rewrite to a Func.FuncOp - if (mlir::isa(valueop)) { - // TODO: Lower to a function op - rewriter.eraseOp(op); - return mlir::success(); - } - - // TODO: [lib] If we're building an executable `linkonce` is a good choice - // but for a library we need to choose a better link type - ll::Linkage linkage = ll::Linkage::Linkonce; - auto loc = op.getLoc(); - auto moduleOp = op->getParentOfType(); - auto ns = moduleOp.getNameAttr(); - auto name = op.getName(); - - mlir::Attribute initAttr{}; - std::string fqsym; - - makeFQSymbolName(ns.getValue(), name, fqsym); - - if (!isTopLevel) { - auto llvmType = typeConverter->convertType(value.getType()); - - { - mlir::PatternRewriter::InsertionGuard insertGuard(rewriter); - rewriter.setInsertionPointToStart(moduleOp.getBody()); - - auto globalOp = rewriter.create(loc, llvmType, - /*isConstant=*/false, - linkage, fqsym, initAttr); - auto &gr = globalOp.getInitializerRegion(); - auto *block = rewriter.createBlock(&gr); - - if (block == nullptr) { - op.emitError("Faild to create block of the globalOp!"); - return mlir::failure(); - } - - rewriter.setInsertionPointToStart(block); - - auto undef = rewriter.create(loc, llvmType); - rewriter.create(loc, undef.getResult()); - } - - rewriter.setInsertionPointAfter(op); - - auto symRef = mlir::SymbolRefAttr::get(rewriter.getContext(), fqsym); - // auto llvmValue = typeConverter->materializeTargetConversion( - // rewriter, loc, llvmType, value); - - // llvm::outs() << ">>> " << symRef << "|" << llvmValue << "|" << op << - // "\n"; - rewriter.replaceOpWithNewOp(op, symRef, value); - // auto setvalOp = rewriter.create(loc, symRef, - // llvmValue); rewriter.insert(setvalOp); rewriter.eraseOp(op); - return mlir::success(); - } - - // auto globop = rewriter.create(loc, value.getType(), - // /*isConstant=*/false, - // linkage, fqsym, - // initAttr); - // auto &gr = globop.getInitializerRegion(); - // auto *block = rewriter.createBlock(&gr); - - // block->addArgument(value.getType(), value.getLoc()); - - // rewriter.setInsertionPoint(block, block->begin()); - - // rewriter.create(value.getLoc(), - // adaptor.getOperands()); - - // if (!op.getResult().use_empty()) { - // auto symValue = rewriter.create(loc, ns, name); - - // rewriter.replaceOp(op, symValue.getResult()); - // } - - rewriter.eraseOp(op); - - return mlir::success(); -} - -struct LowerDefineConstant - : public mlir::OpConversionPattern { - using OpConversionPattern::OpConversionPattern; - - mlir::LogicalResult - matchAndRewrite(serene::slir::DefineConstantOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const override; -}; - -mlir::LogicalResult LowerDefineConstant::matchAndRewrite( - serene::slir::DefineConstantOp op, OpAdaptor adaptor, - mlir::ConversionPatternRewriter &rewriter) const { - - (void)rewriter; - (void)adaptor; - - auto value = op.value(); - auto name = op.getName(); - auto loc = op.getLoc(); - auto moduleOp = op->getParentOfType(); - auto ns = moduleOp.getNameAttr(); - std::string fqsym; - - makeFQSymbolName(ns.getValue(), name, fqsym); - - // TODO: [lib] If we're building an executable `linkonce` is a good choice - // but for a library we need to choose a better link type - ll::Linkage linkage = ll::Linkage::Linkonce; - - // TODO: use ll::ConstantOp instead - UNUSED(rewriter.create(loc, value.getType(), - /*isConstant=*/true, linkage, fqsym, - value)); - - // if (!op.value().use_empty()) { - // auto symValue = rewriter.create(loc, ns, name); - - // rewriter.replaceOp(op, symValue.getResult()); - // } - - rewriter.eraseOp(op); - return mlir::success(); -} - -#define GEN_PASS_CLASSES -#include "serene/passes/passes.h.inc" - -class LowerSLIR : public LowerSLIRBase { - void runOnOperation() override { - mlir::ModuleOp module = getOperation(); - - // The first thing to define is the conversion target. This will define the - // final target for this lowering. - mlir::ConversionTarget target(getContext()); - - slir::TypeConverter typeConverter(getContext()); - - // We define the specific operations, or dialects, that are legal targets - // for this lowering. In our case, we are lowering to the `Standard` - // dialects. - target.addLegalDialect(); - target.addLegalDialect(); - target.addLegalDialect(); - - // We also define the SLIR dialect as Illegal so that the conversion will - // fail if any of these operations are *not* converted. - target.addIllegalDialect(); - - // Mark operations that are LEGAL for this pass. It means that we don't - // lower them is this pass but we will in another pass. So we don't want to - // get an error since we are not lowering them. - // target.addLegalOp(); - target.addLegalOp(); - - // Now that the conversion target has been defined, we just need to provide - // the set of patterns that will lower the SLIR operations. - mlir::RewritePatternSet patterns(&getContext()); - - // Pattern to lower ValueOp and FnOp - // LowerDefineConstant - patterns.add(typeConverter, - &getContext()); - - // With the target and rewrite patterns defined, we can now attempt the - // conversion. The conversion will signal failure if any of our `illegal` - // operations were not converted successfully. - if (failed(applyPartialConversion(module, target, std::move(patterns)))) { - signalPassFailure(); - } - } -}; - -std::unique_ptr createLowerSLIR() { - return std::make_unique(); -} - -#define GEN_PASS_REGISTRATION -#include "serene/passes/passes.h.inc" - -// ---------------------------------------------------------------------------- -// ValueOp lowering to constant op -struct ValueOpLowering : public mlir::OpRewritePattern { - using OpRewritePattern::OpRewritePattern; - - mlir::LogicalResult - matchAndRewrite(serene::slir::Value1Op op, - mlir::PatternRewriter &rewriter) const final; -}; - -mlir::LogicalResult -ValueOpLowering::matchAndRewrite(serene::slir::Value1Op op, - mlir::PatternRewriter &rewriter) const { - auto value = op.value(); - mlir::Location loc = op.getLoc(); - - llvm::SmallVector arg_types(0); - auto func_type = rewriter.getFunctionType(arg_types, rewriter.getI64Type()); - // TODO: use a mechanism to generate unique names - auto fn = rewriter.create(loc, "randomname", func_type); - - auto *entryBlock = fn.addEntryBlock(); - rewriter.setInsertionPointToStart(entryBlock); - - // Since we only support i64 at the moment we use ConstantOp - auto retVal = rewriter - .create(loc, (int64_t)value, - rewriter.getI64Type()) - .getResult(); - - UNUSED(rewriter.create(loc, retVal)); - - fn.setPrivate(); - - // Erase the original ValueOP - rewriter.eraseOp(op); - return mlir::success(); -} - -// ---------------------------------------------------------------------------- -// Fn lowering pattern -struct FnOpLowering : public mlir::OpRewritePattern { - using OpRewritePattern::OpRewritePattern; - - mlir::LogicalResult - matchAndRewrite(serene::slir::Fn1Op op, - mlir::PatternRewriter &rewriter) const final; -}; - -mlir::LogicalResult -FnOpLowering::matchAndRewrite(serene::slir::Fn1Op op, - mlir::PatternRewriter &rewriter) const { - auto args = op.args(); - auto name = op.name(); - auto isPublic = op.sym_visibility().getValueOr("public") == "public"; - mlir::Location loc = op.getLoc(); - - llvm::SmallVector arg_types; - - for (const auto &arg : args) { - auto attr = arg.getValue().dyn_cast(); - - if (!attr) { - op.emitError("It's not a type attr"); - return mlir::failure(); - } - arg_types.push_back(attr.getValue()); - } - - auto func_type = rewriter.getFunctionType(arg_types, rewriter.getI64Type()); - auto fn = rewriter.create(loc, name, func_type); - - auto *entryBlock = fn.addEntryBlock(); - - rewriter.setInsertionPointToStart(entryBlock); - - auto retVal = rewriter - .create(loc, (int64_t)3, - rewriter.getI64Type()) - .getResult(); - - rewriter.create(loc, retVal); - - if (!isPublic) { - fn.setPrivate(); - } - - rewriter.eraseOp(op); - return mlir::success(); -} - -// ---------------------------------------------------------------------------- -// SLIR lowering pass -// This Pass will lower SLIR to MLIR's standard dialect. -struct SLIRToMLIRPass - : public mlir::PassWrapper> { - void getDependentDialects(mlir::DialectRegistry ®istry) const override; - void runOnOperation() final; - void runOnModule(); - mlir::ModuleOp getModule(); -}; - -// Mark what dialects we need for this pass. It's basically translate to what -// dialects do we want to lower to -void SLIRToMLIRPass::getDependentDialects( - mlir::DialectRegistry ®istry) const { - registry.insert(); -}; - -/// Return the current function being transformed. -mlir::ModuleOp SLIRToMLIRPass::getModule() { return this->getOperation(); } - -void SLIRToMLIRPass::runOnOperation() { runOnModule(); } - -void SLIRToMLIRPass::runOnModule() { - - auto module = getModule(); - - // The first thing to define is the conversion target. This will define the - // final target for this lowering. - mlir::ConversionTarget target(getContext()); - - // We define the specific operations, or dialects, that are legal targets for - // this lowering. In our case, we are lowering to the `Standard` dialects. - target.addLegalDialect(); - target.addLegalDialect(); - - // We also define the SLIR dialect as Illegal so that the conversion will fail - // if any of these operations are *not* converted. - target.addIllegalDialect(); - - // Mark operations that are LEGAL for this pass. It means that we don't lower - // them is this pass but we will in another pass. So we don't want to get - // an error since we are not lowering them. - // target.addLegalOp(); - target.addLegalOp(); - - // Now that the conversion target has been defined, we just need to provide - // the set of patterns that will lower the SLIR operations. - mlir::RewritePatternSet patterns(&getContext()); - - // Pattern to lower ValueOp and FnOp - patterns.add(&getContext()); - - // With the target and rewrite patterns defined, we can now attempt the - // conversion. The conversion will signal failure if any of our `illegal` - // operations were not converted successfully. - if (failed(applyPartialConversion(module, target, std::move(patterns)))) { - signalPassFailure(); - } -}; - -std::unique_ptr createSLIRLowerToMLIRPass() { - return std::make_unique(); -}; - -void registerAllPasses() { registerPasses(); } -} // namespace serene::passes diff --git a/libserene.v0/lib/passes/to_llvm_dialect.cpp b/libserene.v0/lib/passes/to_llvm_dialect.cpp deleted file mode 100644 index 963ace2..0000000 --- a/libserene.v0/lib/passes/to_llvm_dialect.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/passes.h" -#include "serene/slir/dialect.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace serene::passes { -struct SLIRToLLVMDialect - : public mlir::PassWrapper> { - void getDependentDialects(mlir::DialectRegistry ®istry) const override { - registry.insert(); - } - - void runOnOperation() final; -}; - -void SLIRToLLVMDialect::runOnOperation() { - // The first thing to define is the conversion target. This will define the - // final target for this lowering. For this lowering, we are only targeting - // the LLVM dialect. - mlir::LLVMConversionTarget target(getContext()); - target.addLegalOp(); - - // During this lowering, we will also be lowering the MemRef types, that are - // currently being operated on, to a representation in LLVM. To perform this - // conversion we use a TypeConverter as part of the lowering. This converter - // details how one type maps to another. This is necessary now that we will be - // doing more complicated lowerings, involving loop region arguments. - mlir::LLVMTypeConverter typeConverter(&getContext()); - - // Now that the conversion target has been defined, we need to provide the - // patterns used for lowering. At this point of the compilation process, we - // have a combination of `serene`, `affine`, and `std` operations. Luckily, - // there are already exists a set of patterns to transform `affine` and `std` - // dialects. These patterns lowering in multiple stages, relying on transitive - // lowerings. Transitive lowering, or A->B->C lowering, is when multiple - // patterns must be applied to fully transform an illegal operation into a - // set of legal ones. - mlir::RewritePatternSet patterns(&getContext()); - - mlir::populateFuncToLLVMConversionPatterns(typeConverter, patterns); - mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, - patterns); - // patterns.add(&getContext()); - - // We want to completely lower to LLVM, so we use a `FullConversion`. This - // ensures that only legal operations will remain after the conversion. - auto module = getOperation(); - if (failed(applyFullConversion(module, target, std::move(patterns)))) { - signalPassFailure(); - } -}; - -std::unique_ptr createSLIRLowerToLLVMDialectPass() { - return std::make_unique(); -}; - -} // namespace serene::passes diff --git a/libserene.v0/lib/reader/reader.cpp b/libserene.v0/lib/reader/reader.cpp deleted file mode 100644 index ce0f59c..0000000 --- a/libserene.v0/lib/reader/reader.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/reader/reader.h" - -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/number.h" -#include "serene/exprs/symbol.h" -#include "serene/namespace.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace serene { - -namespace reader { -// LocationRange::LocationRange(const LocationRange &loc) { -// start = loc.start.clone(); -// end = loc.end.clone(); -// } - -/// Return the string represenation of the location. -std::string Location::toString() const { - return llvm::formatv("{0}:{1}", line, col); -}; - -Location Location::clone() const { - return Location{ns, filename, c, line, col, knownLocation}; -} - -mlir::Location Location::toMLIRLocation(SereneContext &ctx) { - // TODO: Create a new Location attribute that is namespace base - if (filename.hasValue()) { - return mlir::FileLineColLoc::get(&ctx.mlirContext, filename.getValue(), - line, col); - } - return mlir::FileLineColLoc::get(&ctx.mlirContext, ns, line, col); -} -/// Increase the given location by one and set the line/col value in respect to -/// the `newline` in place. -/// \param loc The `Location` data -/// \param c A pointer to the current char that the location has to point to -void incLocation(Location &loc, const 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. - auto newline = *c == '\n'; - - if (!newline) { - loc.col++; - } else { - loc.line++; - loc.col = 0; - } -} - -/// decrease the given location by one and set the line/col value in respect to -/// the `newline` in place. -/// \param loc The `Location` data -/// \param c A pointer to the current char that the location has to point to -void decLocation(Location &loc, const 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. - auto newline = *c == '\n'; - - if (newline) { - loc.line = loc.line == 0 ? 0 : loc.line - 1; - - // We don't move back the `col` value because we simply don't know it - } else { - loc.col = loc.col == 0 ? 0 : loc.col - 1; - } -} - -Reader::Reader(SereneContext &ctx, llvm::StringRef buffer, llvm::StringRef ns, - std::optional filename) - : ctx(ctx), ns(ns), filename(filename), buf(buffer), - currentLocation(Location(ns, filename)) { - UNUSED(this->ctx); - READER_LOG("Setting the first char of the buffer"); - currentChar = buf.begin() - 1; - currentPos = 1; - currentLocation.line = 1; - currentLocation.col = 1; -}; - -Reader::Reader(SereneContext &ctx, llvm::MemoryBufferRef buffer, - llvm::StringRef ns, std::optional filename) - : Reader(ctx, buffer.getBuffer(), ns, filename){}; - -Reader::~Reader() { READER_LOG("Destroying the reader"); } - -void Reader::advanceByOne() { - currentChar++; - currentPos++; - currentLocation.col++; - - if (*currentChar == '\n') { - READER_LOG("Detected end of line"); - - if (readEOL) { - currentLocation.col = 1; - currentLocation.line++; - } - - readEOL = true; - } else { - if (readEOL) { - currentLocation.line++; - currentLocation.col = 1; - } - readEOL = false; - } - - READER_LOG("Moving to Char: " << *currentChar << " at location: " - << currentLocation.toString()); -}; -void Reader::advance(bool skipWhitespace) { - if (skipWhitespace) { - for (;;) { - const auto *next = currentChar + 1; - - if (isspace(*next) == 0) { - return; - } - - advanceByOne(); - } - } else { - advanceByOne(); - } -}; - -const char *Reader::nextChar(bool skipWhitespace, unsigned count) { - if (!skipWhitespace) { - READER_LOG("Next char: " << *(currentChar + count)); - return currentChar + count; - } - - const auto *c = currentChar + 1; - while (isspace(*c) != 0) { - c++; - }; - - READER_LOG("Next char: " << *c); - return c; -}; - -bool Reader::isEndOfBuffer(const char *c) { - return *c == '\0' || currentPos > buf.size() || ((const int)*c == EOF); -}; - -Location Reader::getCurrentLocation() { return currentLocation.clone(); }; - -/// 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 '!': - case '$': - case '%': - case '&': - case '*': - case '+': - case '-': - case '.': - case '~': - case '/': - case ':': - case '<': - case '=': - case '>': - case '?': - case '@': - case '^': - case '_': - return true; - } - - return std::isalnum(c) != 0; -} - -/// Reads a number, -/// \param neg whether to read a negative number or not. -exprs::MaybeNode Reader::readNumber(bool neg) { - READER_LOG("Reading a number..."); - std::string number(neg ? "-" : ""); - bool floatNum = false; - bool empty = false; - - const auto *c = nextChar(); - advance(); - - LocationRange loc(getCurrentLocation()); - - if (isdigit(*c) == 0) { - return errors::makeError(ctx, errors::InvalidDigitForNumber, loc); - } - - for (;;) { - number += *c; - c = nextChar(false); - empty = false; - - if ((isdigit(*c) != 0) || *c == '.') { - if (*c == '.' && floatNum) { - loc = LocationRange(getCurrentLocation()); - return errors::makeError(ctx, errors::TwoFloatPoints, loc); - } - - if (*c == '.') { - floatNum = true; - } - - advance(); - continue; - } - break; - } - - if (((std::isalpha(*c) != 0) && !empty) || empty) { - advance(); - loc.start = getCurrentLocation(); - return errors::makeError(ctx, errors::InvalidDigitForNumber, loc); - } - - loc.end = getCurrentLocation(); - return exprs::make(loc, number, neg, floatNum); -}; - -/// Reads a symbol. If the symbol looks like a number -/// If reads it as number -exprs::MaybeNode Reader::readSymbol() { - READER_LOG("Reading a symbol..."); - LocationRange loc; - const auto *c = nextChar(); - - if (!this->isValidForIdentifier(*c) || isEndOfBuffer(c) || - (isspace(*c) != 0)) { - advance(); - loc = LocationRange(getCurrentLocation()); - std::string msg; - - if (*c == ')') { - msg = "An extra ')' is detected."; - } - - return errors::makeError(ctx, errors::InvalidCharacterForSymbol, loc, msg); - } - - if (*c == '-') { - const auto *next = nextChar(false, 2); - if (isdigit(*next) != 0) { - // Swallow the - - advance(); - return readNumber(true); - } - } - - if (isdigit(*c) != 0) { - return readNumber(false); - } - - std::string sym; - advance(); - - for (;;) { - sym += *c; - c = nextChar(); - - if (!isEndOfBuffer(c) && - ((((isspace(*c)) == 0) && this->isValidForIdentifier(*c)))) { - advance(); - continue; - } - break; - } - - // TODO: Make sure that the symbol has 0 or 1 '/'. - - // TODO: Make sure that `/` is not at the start or at the end of the symbol - - loc.end = getCurrentLocation(); - return exprs::makeSuccessfulNode(loc, sym, this->ns); -}; - -/// Reads a list recursively -exprs::MaybeNode Reader::readList() { - READER_LOG("Reading a list..."); - - const auto *c = nextChar(); - advance(); - - auto list = exprs::makeAndCast(getCurrentLocation()); - - // TODO: Replace the assert with an actual check. - assert(*c == '('); - - bool list_terminated = false; - - do { - const auto *c = nextChar(true); - - if (isEndOfBuffer(c)) { - advance(true); - advance(); - list->location.end = getCurrentLocation(); - return errors::makeError(ctx, errors::EOFWhileScaningAList, - list->location); - } - - switch (*c) { - case ')': - advance(true); - advance(); - list_terminated = true; - list->location.end = getCurrentLocation(); - break; - - default: - advance(true); - auto expr = readExpr(); - if (!expr) { - return expr; - } - - list->append(*expr); - } - - } while (!list_terminated); - - return list; -}; - -/// Reads an expression by dispatching to the proper reader function. -exprs::MaybeNode Reader::readExpr() { - const auto *c = nextChar(true); - - READER_LOG("Read char at `readExpr`: " << *c); - - if (isEndOfBuffer(c)) { - return exprs::EmptyNode; - } - - switch (*c) { - case '(': { - advance(true); - return readList(); - } - - default: - advance(true); - return readSymbol(); - } -}; - -/// Reads all the expressions in the reader's buffer as an AST. -/// Each expression type (from the reader perspective) has a -/// reader function. -exprs::MaybeAst Reader::read() { - - for (size_t current_pos = 0; current_pos < buf.size();) { - const auto *c = nextChar(true); - - if (isEndOfBuffer(c)) { - break; - } - - advance(true); - - auto tmp = readExpr(); - - if (tmp) { - if (*tmp == nullptr) { - break; - } - - this->ast.push_back(std::move(*tmp)); - - } else { - return tmp.takeError(); - } - } - - return std::move(this->ast); -}; - -exprs::MaybeAst read(SereneContext &ctx, const llvm::StringRef input, - llvm::StringRef ns, - std::optional filename) { - reader::Reader r(ctx, input, ns, filename); - auto ast = r.read(); - return ast; -} - -exprs::MaybeAst read(SereneContext &ctx, const llvm::MemoryBufferRef input, - llvm::StringRef ns, - std::optional filename) { - reader::Reader r(ctx, input, ns, filename); - - auto ast = r.read(); - return ast; -} -} // namespace reader -} // namespace serene diff --git a/libserene.v0/lib/semantics.cpp b/libserene.v0/lib/semantics.cpp deleted file mode 100644 index b44b690..0000000 --- a/libserene.v0/lib/semantics.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/semantics.h" - -#include "serene/context.h" -#include "serene/exprs/expression.h" -#include "serene/namespace.h" - -#include - -namespace serene::semantics { - -std::unique_ptr AnalysisState::moveToNewEnv() { - auto &newEnv = ns.createEnv(&env); - return makeAnalysisState(ns, newEnv); -}; - -AnalyzeResult analyze(AnalysisState &state, exprs::Ast &forms) { - llvm::Error errors = llvm::Error::success(); - exprs::Ast ast; - - for (auto &element : forms) { - auto maybeNode = element->analyze(state); - - // Is it a `success` result - if (maybeNode) { - auto &node = *maybeNode; - - if (node) { - // is there a new node to replace the current node ? - ast.push_back(node); - } else { - // Analyze returned a `nullptr`. No rewrite is needed. - // Use the current element instead. - ast.push_back(element); - } - } else { - - // `analyze` returned an errorful result. This type of error - // is llvm related and has to be raised later - // (std::move()); - auto err = maybeNode.takeError(); - errors = llvm::joinErrors(std::move(errors), std::move(err)); - } - } - - // If the errors (which is an ErrorList) contains error and is - // not succssful - if (!errors) { - return std::move(ast); - } - - return std::move(errors); -}; -}; // namespace serene::semantics diff --git a/libserene.v0/lib/serene.cpp b/libserene.v0/lib/serene.cpp deleted file mode 100644 index 2261301..0000000 --- a/libserene.v0/lib/serene.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/serene.h" - -#include "serene/diagnostics.h" -#include "serene/exprs/expression.h" - -// TODO: Remove it -#include "serene/exprs/number.h" -#include "serene/jit/halley.h" -#include "serene/reader/reader.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include -#include - -namespace serene { -using exprs::Number; - -void initCompiler() { - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); - llvm::InitializeAllAsmPrinters(); -}; - -// CLI Option ---------------- - -/// All the global CLI option ar defined here. If you need to add a new global -/// option -/// make sure that you are handling it in `applySereneCLOptions` too. -struct SereneOptions { - - llvm::cl::OptionCategory clOptionsCategory{"Discovery options"}; - - llvm::cl::list loadPaths{ - "l", llvm::cl::desc("The load path to use for compilation."), - llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs, - llvm::cl::cat(clOptionsCategory)}; - - llvm::cl::list sharedLibraryPaths{ - "sl", llvm::cl::desc("Where to find shared libraries"), - llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs, - llvm::cl::cat(clOptionsCategory)}; -}; - -static llvm::ManagedStatic options; - -void registerSereneCLOptions() { - // Make sure that the options struct has been constructed. - *options; - -#ifdef SERENE_WITH_MLIR_CL_OPTION - // mlir::registerAsmPrinterCLOptions(); - mlir::registerMLIRContextCLOptions(); - mlir::registerPassManagerCLOptions(); -#endif -} - -void applySereneCLOptions(SereneContext &ctx) { - if (!options.isConstructed()) { - return; - } - - ctx.sourceManager.setLoadPaths(options->loadPaths); - -#ifdef SERENE_WITH_MLIR_CL_OPTION - mlir::applyPassManagerCLOptions(ctx.pm); -#endif -} - -SERENE_EXPORT exprs::MaybeAst read(SereneContext &ctx, std::string &input) { - auto ¤tNS = ctx.getCurrentNS(); - auto filename = - !currentNS.filename.hasValue() - ? llvm::None - : std::optional(currentNS.filename.getValue()); - - return reader::read(ctx, input, currentNS.name, filename); -}; - -SERENE_EXPORT exprs::MaybeNode eval(SereneContext &ctx, exprs::Ast &input) { - - auto loc = reader::LocationRange::UnknownLocation("nsname"); - - // auto ns = ctx.importNamespace("docs.examples.hello_world", loc); - - // if (!ns) { - // auto es = ns.getError(); - // auto nsloadErr = errors::makeError(loc, errors::NSLoadError); - // es.push_back(nsloadErr); - // return exprs::MaybeNode::error(es); - // } - - auto errs = ctx.jit->addAST(input); - if (errs) { - return errs; - } - - // auto e = input[0]; - // auto *sym = llvm::dyn_cast(e.get()); - - // if (sym == nullptr) { - // return exprs::makeErrorNode(e->location, errors::UnknownError, "only - // sym"); - // } - - // llvm::outs() << "Read: " << sym->toString() << "\n"; - - // // Get the anonymous expression's JITSymbol. - // auto symptr = ctx.jit->lookup(*sym); - // if (!symptr) { - // return exprs::MaybeNode::error(symptr.getError()); - // } - - llvm::outs() << "eval here\n"; - - // sym((void **)3); - - // err = ctx.jit->addAst(input); - // if (err) { - // llvm::errs() << err; - // auto e = errors::makeErrorTree(loc, errors::NSLoadError); - - // return exprs::makeErrorNode(loc, errors::NSLoadError); - // } - return exprs::make(loc, "4", false, false); -}; - -SERENE_EXPORT void print(SereneContext &ctx, const exprs::Ast &input, - std::string &result) { - UNUSED(ctx); - result = exprs::astToString(&input); -}; - -} // namespace serene diff --git a/libserene.v0/lib/slir/dialect.cpp b/libserene.v0/lib/slir/dialect.cpp deleted file mode 100644 index 5b1def0..0000000 --- a/libserene.v0/lib/slir/dialect.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/dialect.h" - -#include "serene/slir/dialect.cpp.inc" -#include "serene/slir/ops.h" -#include "serene/slir/types.h" - -#include -#include -#include -#include - -namespace serene { -namespace slir { - -/// Dialect initialization, the instance will be owned by the context. This is -/// the point of registration of types and operations for the dialect. -void SereneDialect::initialize() { - registerType(); - addOperations< -#define GET_OP_LIST -#include "serene/slir/ops.cpp.inc" - >(); -} - -void registerTo(mlir::DialectRegistry ®istry) { - registry.insert(); -}; - -} // namespace slir -} // namespace serene diff --git a/libserene.v0/lib/slir/generatable.cpp b/libserene.v0/lib/slir/generatable.cpp deleted file mode 100644 index 906eef9..0000000 --- a/libserene.v0/lib/slir/generatable.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/generatable.h" - -#include "serene/slir/dialect.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace serene { -namespace slir { - -// mlir::Operation *Generatable::generate(exprs::Expression *x) { -// switch (x->getType()) { -// case SereneType::Number: { -// return generate(llvm::cast(x)); -// } - -// case SereneType::List: { -// generate(llvm::cast(x)); -// return nullptr; -// } - -// default: { -// return builder.create(builder.getUnknownLoc(), (uint64_t)3); -// } -// } -//}; - -// mlir::Value Generator::generate(exprs::List *l) { -// auto first = l->at(0); - -// 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()); -// // } -// return builder.create(builder.getUnknownLoc(), (uint64_t)100); -//}; - -// 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); - -// if (!fn) { -// module.emitError("Can not create the function."); -// } - -// 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())) { - -// 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); - -// // 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) -// // func::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{}))); -// // } - -// return fn; -// } -} // namespace slir - -} // namespace serene diff --git a/libserene.v0/lib/slir/ops.cpp b/libserene.v0/lib/slir/ops.cpp deleted file mode 100644 index 92fca28..0000000 --- a/libserene.v0/lib/slir/ops.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/ops.h" - -#include "serene/slir/dialect.h" -#include "serene/slir/types.h" -#include "serene/utils.h" - -#include -#include -#include -#include -#include - -#define GET_OP_CLASSES -#include "serene/slir/ops.cpp.inc" - -namespace serene::slir { - -mlir::DataLayoutSpecInterface NsOp::getDataLayoutSpec() { - // Take the first and only (if present) attribute that implements the - // interface. This needs a linear search, but is called only once per data - // layout object construction that is used for repeated queries. - for (mlir::NamedAttribute attr : getOperation()->getAttrs()) { - if (auto spec = attr.getValue().dyn_cast()) { - return spec; - } - } - return {}; -} - -mlir::OpFoldResult SymbolOp::fold(llvm::ArrayRef operands) { - UNUSED(operands); - return value(); -}; - -mlir::OpFoldResult ValueOp::fold(llvm::ArrayRef operands) { - UNUSED(operands); - return value(); -}; -} // namespace serene::slir diff --git a/libserene.v0/lib/slir/slir.cpp b/libserene.v0/lib/slir/slir.cpp deleted file mode 100644 index 276b28d..0000000 --- a/libserene.v0/lib/slir/slir.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/slir.h" - -namespace serene { -namespace slir { - -std::optional -compileToLLVMIR(serene::SereneContext &ctx, mlir::ModuleOp &module) { - - auto llvmContext = serene::SereneContext::genLLVMContext(); - // Register the translation to LLVM IR with the MLIR context. - mlir::registerLLVMDialectTranslation(*module.getContext()); - - // Convert the module to LLVM IR in a new LLVM IR context. - auto llvmModule = mlir::translateModuleToLLVMIR(module, *llvmContext); - - if (!llvmModule) { - // TODO: Return a Result type instead - module.emitError("Failed to emit LLVM IR\n"); - return llvm::None; - } - - // Initialize LLVM targets. - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - // TODO: replace this call with our own version of setupTargetTriple - mlir::ExecutionEngine::setupTargetTriple(llvmModule.get()); - - /// Optionally run an optimization pipeline over the llvm module. - auto optPipeline = mlir::makeOptimizingTransformer( - /*optLevel=*/ctx.getOptimizatioLevel(), /*sizeLevel=*/0, - /*targetMachine=*/nullptr); - - if (auto err = optPipeline(llvmModule.get())) { - // TODO: Return a proper error - module.emitError("Failed to optimize LLVM IR\n"); - return llvm::None; - } - - auto tsm = llvm::orc::ThreadSafeModule(std::move(llvmModule), - std::move(llvmContext)); - return tsm; -}; - -} // namespace slir - -} // namespace serene diff --git a/libserene.v0/lib/slir/type_converter.cpp b/libserene.v0/lib/slir/type_converter.cpp deleted file mode 100644 index dbb442b..0000000 --- a/libserene.v0/lib/slir/type_converter.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/type_converter.h" - -#include "serene/slir/dialect.h" - -#include -#include - -namespace ll = mlir::LLVM; - -namespace serene { -namespace slir { - -mlir::Type getStringTypeinLLVM(mlir::MLIRContext &ctx) { - auto stringStruct = - ll::LLVMStructType::getIdentified(&ctx, "serene.core.string"); - - mlir::SmallVector subtypes; - - subtypes.push_back( - ll::LLVMPointerType::get(mlir::IntegerType::get(&ctx, I8_SIZE))); - // Length field - subtypes.push_back(mlir::IntegerType::get(&ctx, I32_SIZE)); - (void)stringStruct.setBody(subtypes, false); - - return stringStruct; -}; - -mlir::Type getSymbolTypeinLLVM(mlir::MLIRContext &ctx) { - auto symbolStruct = - ll::LLVMStructType::getIdentified(&ctx, "serene.core.symbol"); - - auto strType = getStringTypeinLLVM(ctx); - auto strPtr = ll::LLVMPointerType::get(strType); - - llvm::SmallVector strings{strPtr, strPtr}; - - // We discard the result becasue if the body was already set it means - // that we're ok and the struct already exists - (void)symbolStruct.setBody(strings, false); - return symbolStruct; -}; - -mlir::Type getPtrTypeinLLVM(mlir::MLIRContext &ctx, PtrType p) { - UNUSED(ctx); - auto T = p.getPointeeType(); - auto llvmPtr = ll::LLVMPointerType::get(T); - return llvmPtr; -} - -TypeConverter::ConverterFn TypeConverter::convertSereneTypes() { - return [&](mlir::Type type) -> MaybeType { - if (type.isa()) { - return getStringTypeinLLVM(ctx); - } - - if (type.isa()) { - return getSymbolTypeinLLVM(ctx); - } - - if (type.isa()) { - return getPtrTypeinLLVM(ctx, type.cast()); - } - - return llvm::None; - }; -} -} // namespace slir -} // namespace serene diff --git a/libserene.v0/lib/slir/types.cpp b/libserene.v0/lib/slir/types.cpp deleted file mode 100644 index 96b924d..0000000 --- a/libserene.v0/lib/slir/types.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/slir/types.h" - -#include "serene/slir/dialect.h" - -#define GET_ATTRDEF_CLASSES -#include "serene/slir/attrs.cpp.inc" - -#define GET_TYPEDEF_CLASSES -#include "serene/slir/types.cpp.inc" - -namespace serene::slir { - -PtrType PtrType::get(mlir::MLIRContext *context, unsigned addressSpace) { - return Base::get(context, mlir::Type(), addressSpace); -} - -PtrType PtrType::get(mlir::Type pointee, unsigned addressSpace) { - return Base::get(pointee.getContext(), pointee, addressSpace); -} - -bool PtrType::isOpaque() const { return !getImpl()->pointeeType; } - -void SereneDialect::registerType() { - addAttributes< -#define GET_ATTRDEF_LIST -#include "serene/slir/attrs.cpp.inc" - >(); - addTypes< -#define GET_TYPEDEF_LIST -#include "serene/slir/types.cpp.inc" - >(); -}; - -} // namespace serene::slir diff --git a/libserene.v0/lib/slir/utils.cpp b/libserene.v0/lib/slir/utils.cpp deleted file mode 100644 index 598a885..0000000 --- a/libserene.v0/lib/slir/utils.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/context.h" -#include "serene/namespace.h" -#include "serene/reader/location.h" - -#include - -namespace serene::slir { -::mlir::Location toMLIRLocation(serene::Namespace &ns, - serene::reader::Location &loc) { - mlir::OpBuilder builder(&ns.getContext().mlirContext); - auto file = ns.filename; - std::string filename{file.getValueOr("REPL")}; - - return mlir::FileLineColLoc::get(builder.getStringAttr(filename), loc.line, - loc.col); -} - -} // namespace serene::slir diff --git a/libserene.v0/lib/slir/value_op.cpp b/libserene.v0/lib/slir/value_op.cpp deleted file mode 100644 index fd1a5d6..0000000 --- a/libserene.v0/lib/slir/value_op.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "serene/slir/dialect.h" -#include "serene/slir/slir.h" - -#include -#include -#include -#include - -namespace serene { -namespace slir {} // namespace slir -} // namespace serene diff --git a/libserene.v0/lib/source_mgr.cpp b/libserene.v0/lib/source_mgr.cpp deleted file mode 100644 index 5f5ac93..0000000 --- a/libserene.v0/lib/source_mgr.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/source_mgr.h" - -#include "serene/namespace.h" -#include "serene/reader/location.h" -#include "serene/reader/reader.h" -#include "serene/utils.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace serene { - -std::string SourceMgr::convertNamespaceToPath(std::string ns_name) { - std::replace(ns_name.begin(), ns_name.end(), '.', '/'); - - llvm::SmallString path; - path.append(ns_name); - llvm::sys::path::native(path); - - return std::string(path); -}; - -bool SourceMgr::isValidBufferID(unsigned i) const { - return i != 0 && i <= buffers.size(); -}; - -SourceMgr::MemBufPtr SourceMgr::findFileInLoadPath(const std::string &name, - std::string &importedFile) { - - auto path = convertNamespaceToPath(name); - - // If the file didn't exist directly, see if it's in an include path. - for (unsigned i = 0, e = loadPaths.size(); i != e; ++i) { - - // TODO: Ugh, Udgly, fix this using llvm::sys::path functions - importedFile = loadPaths[i] + llvm::sys::path::get_separator().data() + - path + "." + DEFAULT_SUFFIX; - - SMGR_LOG("Try to load the ns from: " + importedFile); - auto newBufOrErr = llvm::MemoryBuffer::getFile(importedFile); - - if (auto err = newBufOrErr.getError()) { - llvm::consumeError(llvm::errorCodeToError(err)); - continue; - } - - return std::move(*newBufOrErr); - } - - return nullptr; -}; - -MaybeNS SourceMgr::readNamespace(SereneContext &ctx, std::string name, - reader::LocationRange importLoc) { - std::string importedFile; - - SMGR_LOG("Attempt to load namespace: " + name); - MemBufPtr newBufOrErr(findFileInLoadPath(name, importedFile)); - - if (newBufOrErr == nullptr) { - auto msg = llvm::formatv("Couldn't find namespace '{0}'", name).str(); - return errors::makeError(ctx, errors::NSLoadError, importLoc, msg); - } - - auto bufferId = AddNewSourceBuffer(std::move(newBufOrErr), importLoc); - - UNUSED(nsTable.insert_or_assign(name, bufferId)); - - if (bufferId == 0) { - auto msg = llvm::formatv("Couldn't add namespace '{0}'", name).str(); - return errors::makeError(ctx, errors::NSAddToSMError, importLoc, msg); - } - - // Since we moved the buffer to be added as the source storage we - // need to get a pointer to it again - const auto *buf = getMemoryBuffer(bufferId); - - // Read the content of the buffer by passing it the reader - auto maybeAst = reader::read(ctx, buf->getBuffer(), name, - std::optional(llvm::StringRef(importedFile))); - - if (!maybeAst) { - SMGR_LOG("Couldn't Read namespace: " + name); - return maybeAst.takeError(); - } - - // Create the NS and set the AST - auto ns = - ctx.makeNamespace(name, std::optional(llvm::StringRef(importedFile))); - - if (auto errs = ns->addTree(*maybeAst)) { - SMGR_LOG("Couldn't set the AST for namespace: " + name); - return errs; - } - - return ns; -}; - -unsigned SourceMgr::AddNewSourceBuffer(std::unique_ptr f, - reader::LocationRange includeLoc) { - SrcBuffer nb; - nb.buffer = std::move(f); - nb.importLoc = includeLoc; - buffers.push_back(std::move(nb)); - return buffers.size(); -}; - -template -static std::vector &GetOrCreateOffsetCache(void *&offsetCache, - llvm::MemoryBuffer *buffer) { - if (offsetCache) { - return *static_cast *>(offsetCache); - } - - // Lazily fill in the offset cache. - auto *offsets = new std::vector(); - size_t sz = buffer->getBufferSize(); - - // TODO: Replace this assert with a realtime check - assert(sz <= std::numeric_limits::max()); - - llvm::StringRef s = buffer->getBuffer(); - for (size_t n = 0; n < sz; ++n) { - if (s[n] == '\n') { - offsets->push_back(static_cast(n)); - } - } - - offsetCache = offsets; - return *offsets; -} - -template -const char *SourceMgr::SrcBuffer::getPointerForLineNumberSpecialized( - unsigned lineNo) const { - std::vector &offsets = - GetOrCreateOffsetCache(offsetCache, buffer.get()); - - // We start counting line and column numbers from 1. - if (lineNo != 0) { - --lineNo; - } - - const char *bufStart = buffer->getBufferStart(); - - // The offset cache contains the location of the \n for the specified line, - // we want the start of the line. As such, we look for the previous entry. - if (lineNo == 0) { - return bufStart; - } - - if (lineNo > offsets.size()) { - return nullptr; - } - return bufStart + offsets[lineNo - 1] + 1; -} - -/// Return a pointer to the first character of the specified line number or -/// null if the line number is invalid. -const char * -SourceMgr::SrcBuffer::getPointerForLineNumber(unsigned lineNo) const { - size_t sz = buffer->getBufferSize(); - if (sz <= std::numeric_limits::max()) { - return getPointerForLineNumberSpecialized(lineNo); - } - - if (sz <= std::numeric_limits::max()) { - return getPointerForLineNumberSpecialized(lineNo); - } - - if (sz <= std::numeric_limits::max()) { - return getPointerForLineNumberSpecialized(lineNo); - } - - return getPointerForLineNumberSpecialized(lineNo); -} - -SourceMgr::SrcBuffer::SrcBuffer(SourceMgr::SrcBuffer &&other) noexcept - : buffer(std::move(other.buffer)), offsetCache(other.offsetCache), - importLoc(other.importLoc) { - other.offsetCache = nullptr; -} - -SourceMgr::SrcBuffer::~SrcBuffer() { - if (offsetCache != nullptr) { - size_t sz = buffer->getBufferSize(); - if (sz <= std::numeric_limits::max()) { - delete static_cast *>(offsetCache); - } else if (sz <= std::numeric_limits::max()) { - delete static_cast *>(offsetCache); - } else if (sz <= std::numeric_limits::max()) { - delete static_cast *>(offsetCache); - } else { - delete static_cast *>(offsetCache); - } - offsetCache = nullptr; - } -} - -}; // namespace serene diff --git a/libserene.v0/tests/CMakeLists.txt b/libserene.v0/tests/CMakeLists.txt deleted file mode 100644 index d483cdf..0000000 --- a/libserene.v0/tests/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# Catch2 should be installed system wide -#find_package(Catch2 3 REQUIRED) - -# Tests need to be added as executables first -add_executable(libsereneTests serenetests.cpp) - -add_dependencies(libsereneTests SereneDialectGen) -add_dependencies(libsereneTests serene) - -target_link_libraries(libsereneTests PRIVATE - serene - ${llvm_libs} - MLIRAnalysis - MLIRIR - MLIRParser - MLIRSideEffectInterfaces - MLIRTransforms - - Catch2::Catch2WithMain - ) - -target_compile_features(libsereneTests PRIVATE cxx_std_17) - -# target_include_directories(serene SYSTEM PRIVATE $ENV{INCLUDE}) -# target_include_directories(serene PUBLIC ${INCLUDE_DIR}) - -include(CTest) -include(Catch) -catch_discover_tests(libsereneTests) diff --git a/libserene.v0/tests/context_tests.cpp.inc b/libserene.v0/tests/context_tests.cpp.inc deleted file mode 100644 index 054612d..0000000 --- a/libserene.v0/tests/context_tests.cpp.inc +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef SERENE_TEST_CONTEXT_H -#define SERENE_TEST_CONTEXT_H - -#include "serene/context.h" -#include "serene/namespace.h" -#include "serene/reader/location.h" -#include "serene/serene.h" - -#include "./test_helpers.cpp.inc" -#include -#include - -#include - -namespace serene { - -TEST_CASE("Compiler options", "[context]") { - auto opts = Options(); - opts.JITLazy = !opts.JITLazy; - opts.JITenableGDBNotificationListener = - !opts.JITenableGDBNotificationListener; - - auto ctx = makeSereneContext(opts); - - CHECK(ctx->opts.JITLazy == opts.JITLazy); - CHECK(ctx->opts.JITenableGDBNotificationListener == - opts.JITenableGDBNotificationListener); -}; - -TEST_CASE("makeNamespace & getNS", "[context]") { - auto ctx = makeSereneContext(); - auto *ns = ctx->getNS("blah"); - - REQUIRE_FALSE(ns); - - auto userNs = - ctx->makeNamespace("user", llvm::Optional("/some/file")); - - CHECK(userNs->name == "user"); - REQUIRE(userNs->filename); - CHECK(userNs->filename.getValue() == "/some/file"); - - ns = ctx->getNS("user"); - - REQUIRE(ns); - CHECK(ns->name == userNs->name); - - /// Creating new ns with the same name overrides the old one - auto userNs1 = ctx->makeNamespace( - "user", llvm::Optional("/some/other/file")); - - ns = ctx->getNS("user"); - - REQUIRE(ns); - CHECK(ns->name == userNs1->name); - REQUIRE(ns->filename); - CHECK(ns->filename.getValue() == "/some/other/file"); -}; - -TEST_CASE( - "withCurrentNS run a function with the given namespace as the current NS", - "[context]") { - auto ctx = makeSereneContext(); - auto userNs = - ctx->makeNamespace("user", llvm::Optional("/some/file")); - - ctx->withCurrentNS("user", [&]() -> int { - CHECK(ctx->getCurrentNS().name == userNs->name); - return 0; - }); - - // Checking the `void` type specialization - ctx->withCurrentNS("user", [&]() -> void { - CHECK(ctx->getCurrentNS().name == userNs->name); - }); - - CHECK(ctx->getCurrentNS().name == DEFAULT_NS_NAME); -}; - -TEST_CASE("getSharedPtrToNS returns a shared ptr to the NS", "[context]") { - auto ctx = makeSereneContext(); - auto userNs = - ctx->makeNamespace("user", llvm::Optional("/some/file")); - - auto userNs1 = ctx->makeNamespace( - "user1", llvm::Optional("/some/file1")); - - CHECK(ctx->getCurrentNS().name == DEFAULT_NS_NAME); - - NSPtr shouldBeUser1 = ctx->getSharedPtrToNS("user"); - - REQUIRE(shouldBeUser1); - CHECK(shouldBeUser1->name == userNs->name); -}; - -TEST_CASE("Compilation phase", "[context]") { - auto ctx = makeSereneContext(); - auto cp = CompilationPhase::O3; - - ctx->setOperationPhase(cp); - - CHECK(ctx->getTargetPhase() == cp); - CHECK(ctx->getOptimizatioLevel() == 3); - - // Anything below 0 is 0 - cp = CompilationPhase::MLIR; - ctx->setOperationPhase(cp); - CHECK(ctx->getOptimizatioLevel() == 0); -}; - -TEST_CASE("makeNamespace", "[context]") { - auto ctx = makeSereneContext(); - - auto ns = ctx->makeNamespace("example.ns", llvm::None); - - // Namespace has to be empty - CHECK(ns->name == "example.ns"); - CHECK(ns->getTree().empty()); - CHECK(ns->filename == llvm::None); -}; - -TEST_CASE("context and jit", "[context]") { - auto ctx = makeSereneContext(); - - auto ns = ctx->makeNamespace("example.ns", llvm::None); - - REQUIRE(ctx->jit); - - // no JITDylib should be defined for an empty NS - CHECK(ctx->getNumberOfJITDylibs(*ns) == 0); - - SECTION("JITDylib management") { - auto unknown = reader::LocationRange::UnknownLocation(DEFAULT_NS_NAME); - REQUIRE(!ctx->jit->addNS(*ns, unknown)); - - CHECK(ctx->getNumberOfJITDylibs(*ns) == 1); - - REQUIRE(ctx->getLatestJITDylib(*ns)); - CHECK(ctx->getLatestJITDylib(*ns)->getName() == "example.ns#1"); - }; -}; - -} // namespace serene -#endif diff --git a/libserene.v0/tests/environment_tests.cpp.inc b/libserene.v0/tests/environment_tests.cpp.inc deleted file mode 100644 index 52a3e9c..0000000 --- a/libserene.v0/tests/environment_tests.cpp.inc +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/environment.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/symbol.h" -#include "serene/reader/location.h" -#include "serene/serene.h" - -#include "./test_helpers.cpp.inc" -#include -#include - -#include - -namespace serene { - -TEST_CASE("Environment tests", "[environment]") { - std::unique_ptr range(dummyLocation()); - - exprs::Node sym = exprs::make(*range, "example", "ns"); - - Environment e; - llvm::Optional result = e.lookup("a"); - - REQUIRE_FALSE(result.hasValue()); - - auto status = e.insert_symbol("a", sym); - - REQUIRE(status.succeeded()); - - result = e.lookup("a"); - - REQUIRE(result.hasValue()); - CHECK(result.getValue() == sym); - - auto *fetchedSym = llvm::dyn_cast(result.getValue().get()); - REQUIRE(fetchedSym != nullptr); - CHECK(fetchedSym->name == "example"); - CHECK(fetchedSym->nsName == "ns"); - - SECTION("Testing the environment copy") { - Environment e1(&e); - - result = e1.lookup("b"); - REQUIRE_FALSE(result.hasValue()); - - // It should lookup the value in the parent environment - result = e1.lookup("a"); - REQUIRE(result.hasValue()); - CHECK(result.getValue() == sym); - }; -}; - -TEST_CASE("Test generic Environment usage", "[environment]") { - Environment env; - - auto result = env.lookup("blah"); - REQUIRE_FALSE(result); - - auto status = env.insert_symbol("blah", 'A'); - REQUIRE(status.succeeded()); - - result = env.lookup("blah"); - REQUIRE(result); - CHECK(*result == 'A'); - - result = env.lookup("blah"); - REQUIRE(result); - CHECK(*result == 'A'); - - // Test the overwrite functionality - status = env.insert_symbol("blah", 'B'); - REQUIRE(status.succeeded()); - - result = env.lookup("blah"); - REQUIRE(result); - CHECK(*result == 'B'); -} -} // namespace serene diff --git a/libserene.v0/tests/errors/error_tests.cpp.inc b/libserene.v0/tests/errors/error_tests.cpp.inc deleted file mode 100644 index bb49f29..0000000 --- a/libserene.v0/tests/errors/error_tests.cpp.inc +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TEST_ERRORS_H -#define SERENE_TEST_ERRORS_H - -#include "serene/context.h" -#include "serene/errors.h" - -#include "../test_helpers.cpp.inc" -#include - -#include -#include -#include - -namespace serene { -namespace errors { - -TEST_CASE("Serene Error construction", "[errors]") { - - std::unique_ptr range(dummyLocation()); - auto ctx = makeSereneContext(); - llvm::Error err = makeError(*ctx, PassFailureError, *range, "test error"); - - auto unhandled = - llvm::handleErrors(std::move(err), [&](const SereneError &e) { - REQUIRE(e.message() == "test error"); - const auto *v = getVariant(e.errorType); - REQUIRE(v != nullptr); - CHECK(v->title == "PassFailureError"); - CHECK(v->desc == "Pass Failure."); - CHECK(v->help.empty()); - }); - - CHECK(!unhandled); -} - -TEST_CASE("getMessage function", "[errors]") { - std::unique_ptr range(dummyLocation()); - auto ctx = makeSereneContext(); - llvm::Error err = makeError(*ctx, PassFailureError, *range, "test error"); - - CHECK(getMessage(err) == "test error"); - CHECK_SERENE_ERR(PassFailureError, std::move(err)); -} - -}; // namespace errors -} // namespace serene - -#endif diff --git a/libserene.v0/tests/exprs/expression_tests.cpp.inc b/libserene.v0/tests/exprs/expression_tests.cpp.inc deleted file mode 100644 index 4bfe883..0000000 --- a/libserene.v0/tests/exprs/expression_tests.cpp.inc +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" - -#include "../test_helpers.cpp.inc" - -#include - -namespace serene { -namespace exprs { - -TEST_CASE("Public Expression API", "[expression]") { - std::unique_ptr range(dummyLocation()); - auto sym = make(*range, "example", "user"); - - REQUIRE(sym->getType() == ExprType::Symbol); - CHECK(sym->toString() == ""); - - auto list = makeAndCast(*range, sym); - - CHECK(list->toString() == ">"); -}; - -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/tests/exprs/list_tests.cpp.inc b/libserene.v0/tests/exprs/list_tests.cpp.inc deleted file mode 100644 index 04d69eb..0000000 --- a/libserene.v0/tests/exprs/list_tests.cpp.inc +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/errors.h" -#include "serene/exprs/expression.h" -#include "serene/exprs/list.h" -#include "serene/exprs/symbol.h" -#include "serene/namespace.h" -#include "serene/reader/reader.h" -#include "serene/semantics.h" - -#include "../test_helpers.cpp.inc" - -#include - -namespace serene { -namespace exprs { - -TEST_CASE("List Expression", "[expression]") { - std::unique_ptr range(dummyLocation()); - - Node sym = make(*range, "example", "user"); - Node sym1 = make(*range, "example1", "user"); - - Node list = make(*range); - - REQUIRE(list->getType() == ExprType::List); - CHECK(list->toString() == ""); - - Node list2 = make(*range, list); - CHECK(list2->toString() == ">"); - - Ast elements; - elements.push_back(list); - elements.push_back(list2); - elements.push_back(sym); - - auto list3 = make(*range, elements); - - CHECK(list3->toString() == - " > >"); - - auto l = llvm::dyn_cast(list.get()); - - l->append(sym1); - - REQUIRE(list->getType() == ExprType::List); - CHECK(list->toString() == ">"); - - l->append(sym); - REQUIRE(l->count() == 2); - - auto expr = l->at(1); - REQUIRE(expr.hasValue()); - CHECK(expr.getValue()->toString() == ""); - - expr = l->at(2); - REQUIRE_FALSE(expr.hasValue()); - - for (auto x : *l) { - CHECK(x->getType() == ExprType::Symbol); - } -}; - -TEST_CASE("List semantic analysis of 'def'", "[semantic,expression,list]") { - - auto ctx = makeSereneContext(); - auto ns = ctx->makeNamespace("user", llvm::None); - auto ast = llvm::cantFail(READ("(def (a) b)")); - - SemanticEnv env; - semantics::AnalysisState state(*ns, env); - auto afterAst = semantics::analyze(state, ast); - - REQUIRE_FALSE(afterAst); - { - auto err = afterAst.takeError(); - CHECK(err.isA()); - } - ast = llvm::cantFail(READ("(def a)")); - afterAst = semantics::analyze(state, ast); - REQUIRE_FALSE(afterAst); - CHECK(errors::getMessage(afterAst.takeError()) == "Expected 3 got 2"); - - ast = llvm::cantFail(READ("(def a b c)")); - afterAst = semantics::analyze(state, ast); - REQUIRE_FALSE(afterAst); - CHECK(errors::getMessage(afterAst.takeError()) == "Expected 3 got 4"); - - ast = llvm::cantFail(READ("(def a b)")); - afterAst = semantics::analyze(state, ast); - REQUIRE(afterAst); - CHECK(astToString(&(*afterAst)) == " >"); - - ast = llvm::cantFail(READ("(def a (fn () a))")); - afterAst = semantics::analyze(state, ast); - REQUIRE(afterAst); - CHECK(astToString(&(*afterAst)) == - " to >>"); -} - -// TEST_CASE("List semantic analysis for 'fn'", "[semantic]") { -// auto ctx = makeSereneContext(); -// auto ns = ctx->makeNamespace("user", llvm::None); -// auto ast = READ("(fn)"); -// auto afterAst = semantics::analyze(*ctx, *ast); - -// REQUIRE_FALSE(afterAst); -// REQUIRE(afterAst.takeError().size() == 1); -// CHECK(afterAst.getError()[0]->toString() == -// ""); - -// ast = reader::read("(fn ())"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == " to -// <>>"); - -// ast = reader::read("(fn (a b c) a a a)"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == -// " > to -// " -// " >"); - -// ast = reader::read("(fn () a b)"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == -// " to >"); - -// ast = reader::read("(fn (x) (fn (y) x) z)"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == -// "> to > -// " "to > >"); - -// ast = reader::read("(fn (x) (def a b) (def b c))"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == -// "> to > -// " -// ">>"); -// } - -// TEST_CASE("Complex semantic analysis", "[semantic]") { -// auto ctx = makeSereneContext(); -// auto ns = makeNamespace(*ctx, "user", llvm::None); -// auto ast = -// reader::read("(def a (fn (x) x))\n((def b (fn (x) (fn (y) y))))\n\n"); -// auto afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); -// CHECK(astToString(&afterAst.getValue()) == -// " > to >> " -// "> to > to " -// ">>> >"); - -// ctx = makeSereneContext(); -// ns = makeNamespace(*ctx, "user", llvm::None); -// ast = reader::read("((a b))"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE_FALSE(afterAst); -// auto errs = afterAst.getError(); -// CHECK(errs[0]->toString() == ""); - -// ctx = makeSereneContext(); -// ns = makeNamespace(*ctx, "user", llvm::None); -// ast = reader::read("(def a (fn (x) x)) (a b)"); -// afterAst = semantics::analyze(*ctx, ast.getValue()); -// REQUIRE(afterAst); - -// CHECK(astToString(&afterAst.getValue()) == -// " > to >> > to > >"); -// } -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/tests/exprs/number_tests.cpp.inc b/libserene.v0/tests/exprs/number_tests.cpp.inc deleted file mode 100644 index 71a3932..0000000 --- a/libserene.v0/tests/exprs/number_tests.cpp.inc +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/number.h" - -#include "../test_helpers.cpp.inc" - -namespace serene { -namespace exprs { -TEST_CASE("Number Expression", "[expression]") { - std::unique_ptr range(dummyLocation()); - - auto num1 = makeAndCast(*range, "3", false, false); - auto num2 = makeAndCast(*range, "3.4", false, true); - // Hence the `isNeg` being true. We need to provide the sign as the input - // anyway - auto num3 = makeAndCast(*range, "3", true, false); - auto num4 = makeAndCast(*range, "-3", true, false); - - CHECK(num1->toString() == ""); - CHECK(num2->toString() == ""); - CHECK(num3->toString() == ""); - CHECK(num4->toString() == ""); -}; - -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/tests/exprs/symbol_tests.cpp.inc b/libserene.v0/tests/exprs/symbol_tests.cpp.inc deleted file mode 100644 index 65b13a4..0000000 --- a/libserene.v0/tests/exprs/symbol_tests.cpp.inc +++ /dev/null @@ -1,35 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/exprs/expression.h" -#include "serene/exprs/symbol.h" - -#include "../test_helpers.cpp.inc" - -namespace serene { -namespace exprs { - -TEST_CASE("Public Symbol API", "[expression]") { - std::unique_ptr range(dummyLocation()); - auto sym = make(*range, "example", "user"); - - REQUIRE(sym->getType() == ExprType::Symbol); - CHECK(sym->toString() == ""); -}; -} // namespace exprs -} // namespace serene diff --git a/libserene.v0/tests/namespace_tests.cpp.inc b/libserene.v0/tests/namespace_tests.cpp.inc deleted file mode 100644 index b88c5a9..0000000 --- a/libserene.v0/tests/namespace_tests.cpp.inc +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/context.h" -#include "serene/exprs/expression.h" -#include "serene/namespace.h" -#include "serene/reader/reader.h" - -#include "./test_helpers.cpp.inc" -#include - -namespace serene { - -TEST_CASE("Namespace tests", "[namespace]") { - auto ctx = makeSereneContext(); - auto userNs = makeNamespace(*ctx, "user", - llvm::Optional("/some/file")); - - auto maybeAst = reader::read("(x 1) (def b a)"); - - if (!maybeAst) { - FAIL(); - } - - auto result = userNs->setTree(maybeAst.getValue()); - - REQUIRE(result.succeeded()); - - REQUIRE_FALSE(userNs->getTree().empty()); - CHECK(exprs::astToString(&userNs->getTree()) == - " > >"); -}; - -} // namespace serene diff --git a/libserene.v0/tests/reader/reader_tests.cpp.inc b/libserene.v0/tests/reader/reader_tests.cpp.inc deleted file mode 100644 index 227cb67..0000000 --- a/libserene.v0/tests/reader/reader_tests.cpp.inc +++ /dev/null @@ -1,110 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TEST_READER_H -#define SERENE_TEST_READER_H - -#include "serene/reader/reader.h" - -#include "../test_helpers.cpp.inc" -#include - -namespace serene { -namespace reader { - -TEST_CASE("Read numbers", "[reader]") { - auto ctx = makeSereneContext(); - auto maybeAst = READ("3"); - - if (!maybeAst) { - FAIL(); - } - - auto ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == ""); - - maybeAst = READ("-34"); - - if (!maybeAst) { - FAIL(); - } - - ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == ""); - - maybeAst = READ("-3.5434"); - - if (!maybeAst) { - FAIL(); - } - - ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == ""); - - maybeAst = READ("444323 2123 123123"); - - if (!maybeAst) { - FAIL(); - } - - ast = *maybeAst; - REQUIRE(ast.size() == 3); - CHECK(ast.front()->toString() == ""); - CHECK(ast[1]->toString() == ""); - CHECK(ast[2]->toString() == ""); -}; - -TEST_CASE("Read Lists and Symbols", "[reader]") { - auto ctx = makeSereneContext(); - auto maybeAst = READ("(x 1)"); - - if (!maybeAst) { - FAIL(); - } - - auto ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == " >"); - - maybeAst = READ("(x (y (z)))"); - - if (!maybeAst) { - FAIL(); - } - - ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == " >>>"); - - maybeAst = READ("(x \n y)"); - - if (!maybeAst) { - FAIL(); - } - - ast = *maybeAst; - REQUIRE_FALSE(ast.empty()); - CHECK(ast.front()->toString() == " >"); -}; -} // namespace reader -} // namespace serene -#endif diff --git a/libserene.v0/tests/serenetests.cpp b/libserene.v0/tests/serenetests.cpp deleted file mode 100644 index b502518..0000000 --- a/libserene.v0/tests/serenetests.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define CATCH_CONFIG_MAIN -#include "./context_tests.cpp.inc" -#include "./environment_tests.cpp.inc" -#include "./errors/error_tests.cpp.inc" -#include "./exprs/expression_tests.cpp.inc" -#include "./exprs/list_tests.cpp.inc" -#include "./exprs/number_tests.cpp.inc" -#include "./exprs/symbol_tests.cpp.inc" -#include "./setup.cpp.inc" -// #include "./namespace_tests.cpp.inc" -#include "./reader/reader_tests.cpp.inc" -// #include "./traits_tests.cpp.inc" -// #include "./utils_tests.cpp.inc" -// include -#include diff --git a/libserene.v0/tests/setup.cpp.inc b/libserene.v0/tests/setup.cpp.inc deleted file mode 100644 index 45e82b1..0000000 --- a/libserene.v0/tests/setup.cpp.inc +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/serene.h" -#include "serene/utils.h" - -#include -#include - -#include - -class testRunListener : public Catch::EventListenerBase { -public: - using Catch::EventListenerBase::EventListenerBase; - - void testRunStarting(Catch::TestRunInfo const &info) override { - UNUSED(info); - serene::initCompiler(); - } -}; - -CATCH_REGISTER_LISTENER(testRunListener) diff --git a/libserene.v0/tests/test_helpers.cpp.inc b/libserene.v0/tests/test_helpers.cpp.inc deleted file mode 100644 index 9ffc0c5..0000000 --- a/libserene.v0/tests/test_helpers.cpp.inc +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef TEST_HEALPERS_H -#define TEST_HEALPERS_H - -#include "serene/reader/location.h" - -// *IMPORTANT NOTE:* The `READ` macro is just a quick way to eliminate -// the overhead of writing the same function signature -// over and over again. Nothing special about it. -#define READ(input) reader::read(*ctx, input, "user", llvm::None) - -#define CHECK_ERR_MSG(e, s) CHECK(serene::errors::getMessage(e) == s) -// `llvm::Error`s has to be checked in the same scope. This macro makes -// the check easy while were testing the other aspects of the error. -// `t` is the concrete error type and `e` is the error instance. -#define CHECK_SERENE_ERR(t, e) \ - auto unhandled = llvm::handleErrors( \ - e, [&](const SereneError &x) { CHECK(x.errorType == t); }); \ - CHECK(!unhandled); - -#define CHECK_ERR(t, e) \ - auto unhandled = llvm::handleErrors(e, [&](const t &x) { \ - (void)x; \ - CHECK(true); \ - }); \ - CHECK(!unhandled); - -namespace serene { - -reader::LocationRange *dummyLocation() { - reader::Location start("serene.test.ns"); - reader::Location end("serene.test.ns"); - - constexpr const int line1 = 2; - constexpr const int line2 = 3; - constexpr const int col1 = 20; - constexpr const int col2 = 30; - - start.line = line1; - start.col = col1; - end.line = line2; - end.col = col2; - - return new reader::LocationRange(start, end); -}; - -} // namespace serene - -#endif diff --git a/libserene.v0/tests/traits_tests.cpp.inc b/libserene.v0/tests/traits_tests.cpp.inc deleted file mode 100644 index ad59fc2..0000000 --- a/libserene.v0/tests/traits_tests.cpp.inc +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/traits.h" - -#include "./test_helpers.cpp.inc" -#include - -namespace serene { - -template -class Printable : public TraitBase { -public: - Printable(){}; - Printable(const Printable &) = delete; - std::string Print() { return this->Object().Print(); } -}; - -template -class Analyzable : public TraitBase { -public: - Analyzable(){}; - Analyzable(const Analyzable &) = delete; - std::string Analyze() { return this->Object().Analyze(); } -}; - -template -std::string Print(Printable &t) { - return t.Print(); -} - -template -std::string Analyze(Analyzable &t) { - return t.Analyze(); -}; - -class A : public WithTrait { - - std::string x; - -public: - A(std::string a) : x(a){}; - std::string Print() const { return "A: print"; } - - std::string Analyze() const { return "A: " + x; } -}; - -template -class B : public std::conditional, - WithTrait, Printable, Analyzable>, - WithTrait>::type { - - std::string y; - -public: - B(std::string a) : y(a){}; - std::string Print() const { return "B: print"; } - - std::string Analyze() const { return "B: " + y; } -}; - -class C : public B { - - std::string z; - std::string w; - -public: - C(std::string a, std::string b, std::string c) : B(a), z(b), w(c){}; - std::string Print() const { return z; } - - std::string Analyze() const { return w; } -}; - -class D : public WithTrait { -public: - std::string Print() const { return "D: print"; } - - std::string Analyze() const { return "D: analyze with no trait"; } -}; - -template -class MetaTrait : public WithTrait {}; - -class E : public MetaTrait { -public: - std::string Print() const { return "E: print"; }; - - std::string Analyze() const { return "E: in E"; }; -}; - -TEST_CASE("Trait functionality tests", "[Traits]") { - auto a = A("in A"); - auto b = B("in B"); - auto c = C("gray", "white", "black"); - auto d = D(); - auto e = E(); - - CHECK(Print(a) == "A: print"); - CHECK(Print(b) == "B: print"); - CHECK(Print(c) == "white"); - CHECK(Print(d) == "D: print"); - CHECK(Print(e) == "E: print"); - - CHECK(Analyze(a) == "A: in A"); - CHECK(Analyze(b) == "B: in B"); - CHECK(Analyze(c) == "black"); - CHECK(Analyze(e) == "E: in E"); - - // Even though D has a Analyze method, It's not Analyzable to the - // Analyze function signature won't match - CHECK(d.Analyze() == "D: analyze with no trait"); -}; - -} // namespace serene diff --git a/libserene.v0/tests/utils_tests.cpp.inc b/libserene.v0/tests/utils_tests.cpp.inc deleted file mode 100644 index 7ddedc6..0000000 --- a/libserene.v0/tests/utils_tests.cpp.inc +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "serene/utils.h" - -#include "./test_helpers.cpp.inc" - -namespace serene { -TEST_CASE("Result Type", "[utils]") { - auto r = Result::success(4); - - REQUIRE(r == true); - CHECK(r.getValue() == 4); - - auto r1 = Result::error('c'); - - REQUIRE_FALSE(r1); - CHECK(r1.getError() == 'c'); -}; -} // namespace serene diff --git a/libserene/CMakeLists.txt b/libserene/CMakeLists.txt deleted file mode 100644 index de7d9fd..0000000 --- a/libserene/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) -set(LIBSERENE_INCLUDE_DIR ${INCLUDE_DIR} PARENT_SCOPE) -include_directories(${INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/lib) - -add_subdirectory(lib) - -# Install rules for libserene target -install(TARGETS serene - EXPORT SereneExports - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - - -# Install rules for the public header files. -install(DIRECTORY ${INCLUDE_DIR}/serene - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN *.h - PATTERN *.td - PATTERN "CMake*" EXCLUDE) - -# Install rule for the public generated header files -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING - PATTERN *.h - PATTERN *.td - PATTERN *.h.inc - PATTERN "CMake*" EXCLUDE) - -include(CMakePackageConfigHelpers) - -# Package config file let us use find_package with serene -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - - INSTALL_DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - ) - -write_basic_package_version_file( - "${PROJECT_NAME}ConfigVersion.cmake" - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMajorVersion - ) - -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - ) - -# Install the package exports -install(EXPORT SereneExports - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/serene-${PROJECT_VERSION} - NAMESPACE serene::) - -# Testing only available if this is the main app -# Emergency override SERENE_CMAKE_BUILD_TESTING provided as well -if(SERENE_BUILD_TESTING) - message("Build the test binary") - add_subdirectory(tests) -endif() diff --git a/libserene/cmake/SereneConfig.cmake.in b/libserene/cmake/SereneConfig.cmake.in deleted file mode 100644 index c638645..0000000 --- a/libserene/cmake/SereneConfig.cmake.in +++ /dev/null @@ -1,21 +0,0 @@ - # Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Exports.cmake") - -check_required_components("@PROJECT_NAME@") diff --git a/libserene/include/serene/config.h.in b/libserene/include/serene/config.h.in deleted file mode 100644 index c151f63..0000000 --- a/libserene/include/serene/config.h.in +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -// the configured options and settings - -#define SERENE_VERSION "@PROJECT_VERSION@" - -// Why so obvious? to make the linter shutup :)) -#define I8_SIZE 8 -#define I32_SIZE 32 -#define I64_SIZE 64 - -#define MAX_PATH_SLOTS 256 - -#define COMMON_ARGS_COUNT 6 - -#define PACKED_FUNCTION_NAME_PREFIX "__serene_" - -// Should we build the support for MLIR CL OPTIONS? -#cmakedefine SERENE_WITH_MLIR_CL_OPTION - -#endif diff --git a/libserene/include/serene/context.h b/libserene/include/serene/context.h deleted file mode 100644 index e97ed91..0000000 --- a/libserene/include/serene/context.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_CONTEXT_H -#define SERENE_CONTEXT_H - -#include "serene/export.h" // for SERENE_EXPORT -#include "serene/options.h" // for Options - -#include // for Twine -#include // for LLVMContext -#include // for getDefaultTargetTriple -#include // for Triple - -#include // for function -#include // for make_unique, unique_ptr -#include // for basic_string, string -#include // for vector - -namespace serene { -class SereneContext; - -/// This enum describes the different operational phases for the compiler -/// in order. Anything below `NoOptimization` is considered only for debugging -enum class CompilationPhase { - Parse, - Analysis, - SLIR, - MLIR, // Lowered slir to other dialects - LIR, // Lowered to the llvm ir dialect - IR, // Lowered to the LLVMIR itself - NoOptimization, - O1, - O2, - O3, -}; - -/// Terminates the serene compiler process in a thread safe manner -/// This function is only meant to be used in the compiler context -/// if you want to terminate the process in context of a serene program -/// via the JIT use an appropriate function in the `serene.core` ns. -SERENE_EXPORT void terminate(SereneContext &ctx, int exitCode); - -class SERENE_EXPORT SereneContext { - -public: - template - using CurrentNSFn = std::function; - - /// The set of options to change the compilers behaivoirs - Options opts; - - const llvm::Triple triple; - - explicit SereneContext(Options &options) - : opts(options), triple(llvm::sys::getDefaultTargetTriple()), - targetPhase(CompilationPhase::NoOptimization){}; - - /// Set the target compilation phase of the compiler. The compilation - /// phase dictates the behavior and the output type of the compiler. - void setOperationPhase(CompilationPhase phase); - - CompilationPhase getTargetPhase() { return targetPhase; }; - int getOptimizatioLevel(); - - static std::unique_ptr genLLVMContext() { - return std::make_unique(); - }; - - /// Setup the load path for namespace lookups - void setLoadPaths(std::vector &dirs) { loadPaths.swap(dirs); }; - - /// Return the load paths for namespaces - std::vector &getLoadPaths() { return loadPaths; }; - // JIT JITDylib related functions --- - - // TODO: For Dylib related functions, make sure that the namespace in questoin - // is aleady registered in the context - - /// Return a pointer to the most registered JITDylib of the given \p ns - ////name - // llvm::orc::JITDylib *getLatestJITDylib(Namespace &ns); - - // /// Register the given pointer to a `JITDylib` \p l, with the give \p ns. - // void pushJITDylib(Namespace &ns, llvm::orc::JITDylib *l); - - // /// Returns the number of registered `JITDylib` for the given \p ns. - // size_t getNumberOfJITDylibs(Namespace &ns); - -private: - CompilationPhase targetPhase; - std::vector loadPaths; - /// A vector of pointers to all the jitDylibs for namespaces. Usually - /// There will be only one pre NS but in case of forceful reloads of a - /// namespace there will be more. - // llvm::StringMap> jitDylibs; -}; - -/// Creates a new context object. Contexts are used through out the compilation -/// process to store the state. -/// -/// \p opts is an instance of \c Options that can be used to set options of -/// of the compiler. -SERENE_EXPORT std::unique_ptr -makeSereneContext(Options opts = Options()); - -} // namespace serene - -#endif diff --git a/libserene/include/serene/fs.h b/libserene/include/serene/fs.h deleted file mode 100644 index f4fb6f9..0000000 --- a/libserene/include/serene/fs.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_FS_H -#define SERENE_FS_H - -#include // for StringRef - -#include // for string - -#define MAX_PATH_SLOTS 256 - -namespace serene { -class SereneContext; -}; // namespace serene - -namespace serene::fs { - -enum class NSFileType { - Source = 0, - TextIR, - BinaryIR, - ObjectFile, - StaticLib, - SharedLib -}; - -std::string extensionFor(SereneContext &ctx, NSFileType t); -/// Converts the given namespace name `nsName` to the file name -/// for that name space. E.g, `some.random.ns` will be translated -/// to `some_random_ns`. -std::string namespaceToPath(llvm::StringRef nsName); - -bool isStaticLib(llvm::StringRef path); -bool isSharedLib(llvm::StringRef path); - -/// Return a boolean indicating whether or not the given path exists. -bool exists(llvm::StringRef path); -/// Join the given `path1` and `path2` with respect to the platform -/// conventions. -std::string join(llvm::StringRef path1, llvm::StringRef path2); - -}; // namespace serene::fs -#endif diff --git a/libserene/include/serene/jit/README.org b/libserene/include/serene/jit/README.org deleted file mode 100644 index a2b2525..0000000 --- a/libserene/include/serene/jit/README.org +++ /dev/null @@ -1,18 +0,0 @@ -#+TITLE: Serene JIT -#+AUTHOR: Sameer Rahmani -#+STARTUP: logdrawer logdone logreschedule indent content align constSI entitiespretty nolatexpreview -#+OPTIONS: tex:t -* SereneJIT -** Development Notes -*** Steps to take -You usually want a custom =MaterializationUnit= for your program representation, and a custom =Layer=. The Layer will have two -operations: =add= and =emit=. The =add= operation takes an instance of your program representation, builds one of your custom -=MaterializationUnits= to hold it, then adds it to a =JITDylib=. The =emit= operation takes a =MaterializationResponsibility= -object and an instance of your program representation and materializes it, usually by compiling it and handing the resulting -object off to an =ObjectLinkingLayer=. - -Your custom =MaterializationUnit= will have two operations: =materialize= and =discard=. The =materialize= function will be -called for you when any symbol provided by the unit is looked up, and it should just call the =emit= function on your layer, -passing in the given =MaterializationResponsibility= and the wrapped program representation. The =discard= function will be -called if some weak symbol provided by your unit is not needed (because the JIT found an overriding definition). -You can use this to drop your definition early, or just ignore it and let the linker drop the definition later. diff --git a/libserene/include/serene/jit/halley.h b/libserene/include/serene/jit/halley.h deleted file mode 100644 index 0c66560..0000000 --- a/libserene/include/serene/jit/halley.h +++ /dev/null @@ -1,249 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - This is the first working attempt on building a JIT engine for Serene - and named after Edmond Halley. - - - It operates in lazy (for REPL) and non-lazy mode and wraps LLJIT - and LLLazyJIT - - It uses an object cache layer to cache module (not NSs) objects. - */ - -// TODO: [jit] When we want to load any static or dynamic lib for -// namespace as a dependency first look up the `ExecutionSession` -// to make sure that we did not load it already. If we did just -// use the existing `JITDylib` for it. - -// TODO: [jit] Use Bare JITDylibs for the static and dynamic libs. -// Hint: Look at `createBareJITDylib` on the `ExecutionSession` - -// TODO: [jit] Create a generator class that generates symbols -// from Serene's code and add them to the JitDylib of a namespace -// instead of having multiple jitDylibs per NS - -// TODO: [jit] Create a another overload of the `lookup` function -// than returns a pointer to the symbol. This new functions will -// be used to call those core functions that we already know the -// signature and we don't want to wrap them. For examples functions -// in the `serene.core` namespace - -#ifndef SERENE_JIT_HALLEY_H -#define SERENE_JIT_HALLEY_H - -#include "serene/context.h" // for Serene... -#include "serene/export.h" // for SERENE... - -#include // for Mutabl... -#include // for SmallV... -#include // for StringMap -#include // for StringRef -#include // for Object... -#include // for JITTar... -#include // for LLJIT -#include // for dbgs -#include // for Error -#include // for Memory... -#include // for Memory... -#include // for raw_os... - -#include // for unique... -#include // for nullopt -#include // for size_t -#include // for string -#include // for vector - -namespace llvm { -class DataLayout; -class JITEventListener; -class Module; -namespace orc { -class JITDylib; -} // namespace orc -} // namespace llvm - -namespace serene { -namespace fs { -enum class NSFileType; -} // namespace fs -namespace types { -struct Namespace; -struct Symbol; -struct InternalString; -} // namespace types -} // namespace serene - -#define HALLEY_LOG(...) \ - DEBUG_WITH_TYPE("halley", llvm::dbgs() \ - << "[HALLEY]: " << __VA_ARGS__ << "\n"); - -#define MAIN_PROCESS_JD_NAME "" - -namespace serene { -namespace jit { -class Halley; -// Why? This is the lazy man's way to make it easier to replace -// the class under the hood later on to test different implementaion -// with the same interface -using Engine = Halley; -using EnginePtr = std::unique_ptr; -using MaybeEngine = llvm::Expected; -using JitWrappedAddress = void (*)(void **); -using MaybeJitAddress = llvm::Expected; -using Dylib = llvm::orc::JITDylib; -using DylibPtr = Dylib *; -using MaybeDylibPtr = llvm::Expected; -using MaybeNSFileTypeArr = std::optional>; - -/// A simple object cache following Lang's LLJITWithObjectCache example and -/// MLIR's SimpelObjectCache. -class ObjectCache : public llvm::ObjectCache { -public: - /// Cache the given `objBuffer` for the given module `m`. The buffer contains - /// the combiled objects of the module - void notifyObjectCompiled(const llvm::Module *m, - llvm::MemoryBufferRef objBuffer) override; - - // Lookup the cache for the given module `m` or returen a nullptr. - std::unique_ptr getObject(const llvm::Module *m) override; - - /// Dump cached object to output file `filename`. - void dumpToObjectFile(llvm::StringRef filename); - -private: - llvm::StringMap> cachedObjects; -}; - -class SERENE_EXPORT Halley { - // TODO: Replace this with a variant of LLJIT and LLLazyJIT - std::unique_ptr engine; - std::unique_ptr cache; - /// GDB notification listener. - llvm::JITEventListener *gdbListener; - /// Perf notification listener. - llvm::JITEventListener *perfListener; - llvm::orc::JITTargetMachineBuilder jtmb; - // TODO: [cleanup][jit] Since we can access to the data layout via - // `engine.getDataLayout`, remove this attribute and it's usecases - llvm::DataLayout &dl; - // /TODO - - std::unique_ptr ctx; - bool isLazy = false; - - // TODO: [jit] Replace this vector with a thread safe time-optimized - // datastructure that is capable of indexing strings and own all - // the strings. A lockless algorithm would be even better - - /// Owns all the internal strings used in the compilation process - std::vector stringStorage; - - std::vector nsStorage; - // /TODO - - // JIT JITDylib related functions --- - llvm::StringMap> jitDylibs; - - /// Register the given pointer to a `JITDylib` \p l, with the give \p ns. - void pushJITDylib(types::Namespace &ns, llvm::orc::JITDylib *l); - - // /// Returns the number of registered `JITDylib` for the given \p ns. - size_t getNumberOfJITDylibs(types::Namespace &ns); - - types::Namespace &makeNamespace(const char *name); - - // ========================================================================== - // Loading namespaces from different sources like source files, objectfiles - // etc - // ========================================================================== - struct NSLoadRequest { - llvm::StringRef nsName; - llvm::StringRef path; - std::string &nsToFileName; - }; - - /// This function loads the namespace by the given `nsName` from the file - /// in the given `path`. It assumes that the `path` exists. - MaybeDylibPtr loadNamespaceFrom(fs::NSFileType type_, NSLoadRequest &req); - - template - MaybeDylibPtr loadNamespaceFrom(NSLoadRequest &req); - // ========================================================================== - - std::vector getContainedNamespaces(llvm::StringRef name, - DylibPtr jd); - - llvm::Error createCurrentProcessJD(); - -public: - Halley(std::unique_ptr ctx, - llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl); - - // TODO: [jit] Create a function to "require" a namespace as a dependency. - // If the namespace already exists return it otherwise call `loadNamespace`. - - /// Load a namespace by exploring the load paths and different file - /// formats to find the namespace. We assume that we want to load - /// the namespace from file even if it exists already. - MaybeDylibPtr loadNamespace(std::string &nsName); - - // TODO: [jit] Move all the loader related functions to a Loader class - /// Load the shared library in the given `path` to the given JITDylib - /// `jd` via the give ExecutionSession `es`. - /// This function assumes that the shared lib exists. - MaybeDylibPtr loadSharedLibFile(llvm::StringRef name, llvm::StringRef path); - MaybeDylibPtr loadStaticLibrary(const std::string &name); - MaybeDylibPtr loadSharedLibrary(const std::string &name); - // /TODO - - static MaybeEngine make(std::unique_ptr sereneCtxPtr, - llvm::orc::JITTargetMachineBuilder &&jtmb); - - SereneContext &getContext() { return *ctx; }; - - llvm::Error createEmptyNS(const char *name); - const types::InternalString &getInternalString(const char *s); - - /// Return a pointer to the most registered JITDylib of the given \p ns - ////name - llvm::orc::JITDylib *getLatestJITDylib(const types::Namespace &ns); - llvm::orc::JITDylib *getLatestJITDylib(const char *nsName); - - void setEngine(std::unique_ptr e, bool isLazy); - /// Looks up a packed-argument function with the given sym name and returns a - /// pointer to it. Propagates errors in case of failure. - MaybeJitAddress lookup(const char *nsName, const char *sym) const; - MaybeJitAddress lookup(const types::Symbol &sym) const; - - /// Invokes the function with the given name passing it the list of opaque - /// pointers to the actual arguments. - llvm::Error - invokePacked(const types::Symbol &name, - llvm::MutableArrayRef args = std::nullopt) const; - - llvm::Error loadModule(const char *nsName, const char *file); - void dumpToObjectFile(llvm::StringRef filename); -}; - -MaybeEngine makeHalleyJIT(std::unique_ptr ctx); - -} // namespace jit -} // namespace serene - -#endif diff --git a/libserene/include/serene/jit/packer.h b/libserene/include/serene/jit/packer.h deleted file mode 100644 index 1a83328..0000000 --- a/libserene/include/serene/jit/packer.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_JIT_PACKER_H -#define SERENE_JIT_PACKER_H - -#include // for SmallVectorImpl -#include // for StringRef - -#include // for string - -namespace llvm { -class Module; -} - -namespace serene::jit { - -struct Packer { - /// Trait that defines how a given type is passed to the JIT code. This - /// defaults to passing the address but can be specialized. - template - struct Argument { - static void pack(llvm::SmallVectorImpl &args, T &val) { - args.push_back(&val); - } - }; - - /// Tag to wrap an output parameter when invoking a jitted function. - template - struct FnResult { - explicit FnResult(T &result) : value(result) {} - T &value; - }; - - /// Helper function to wrap an output operand when using - /// ExecutionEngine::invoke. - template - static FnResult result(T &t) { - return FnResult(t); - } - - // Specialization for output parameter: their address is forwarded directly to - // the native code. - template - struct Argument> { - static void pack(llvm::SmallVectorImpl &args, FnResult &result) { - args.push_back(&result.value); - } - }; -}; - -std::string makePackedFunctionName(llvm::StringRef name); -void packFunctionArguments(llvm::Module *module); - -} // namespace serene::jit -#endif diff --git a/libserene/include/serene/options.h b/libserene/include/serene/options.h deleted file mode 100644 index a75c30e..0000000 --- a/libserene/include/serene/options.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_OPTIONS_H -#define SERENE_OPTIONS_H - -#include "serene/export.h" - -namespace serene { -/// Options describes the compiler options that can be passed to the -/// compiler via command line. Anything that user should be able to -/// tweak about the compiler has to end up here regardless of the -/// different subsystem that might use it. -struct SERENE_EXPORT Options { - - /// Whether to use colors for the output or not - bool withColors = true; - - // JIT related flags - bool JITenableObjectCache = true; - bool JITenableGDBNotificationListener = true; - bool JITenablePerfNotificationListener = true; - bool JITLazy = false; - - // namespace serene Options() = default; -}; -} // namespace serene - -#endif diff --git a/libserene/include/serene/serene.h b/libserene/include/serene/serene.h deleted file mode 100644 index a6bd7be..0000000 --- a/libserene/include/serene/serene.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_SERENE_H -#define SERENE_SERENE_H - -#include "serene/export.h" // for SERENE_EXPORT -#include "serene/jit/halley.h" // for Engine, MaybeEngine -#include "serene/options.h" // for Options - -#include // for GC_INIT - -#define SERENE_INIT() \ - GC_INIT(); \ - initSerene(); - -namespace serene { - -/// Clinet applications have to call this function before any interaction -/// with the Serene's compiler API. -void SERENE_EXPORT initSerene(); - -/// Register the global CLI options of the serene compiler. If the client -/// application needs to setup the compilers options automatically use this -/// function in conjunction with `applySereneCLOptions`. -void SERENE_EXPORT registerSereneCLOptions(); - -/// Applies the global compiler options on the give \p SereneContext. This -/// function has to be called after `llvm::cl::ParseCommandLineOptions`. -void SERENE_EXPORT applySereneCLOptions(serene::jit::Engine &engine); - -serene::jit::MaybeEngine SERENE_EXPORT makeEngine(Options opts = Options()); - -} // namespace serene -#endif diff --git a/libserene/include/serene/types/types.h b/libserene/include/serene/types/types.h deleted file mode 100644 index 9a2ab3b..0000000 --- a/libserene/include/serene/types/types.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_TYPES_TYPE_H -#define SERENE_TYPES_TYPE_H - -#include -namespace serene::types { - -// ============================================================================ -// Expression -// ============================================================================ -struct Expression { - const unsigned char *data; - explicit Expression(const unsigned char *data) : data(data){}; -}; - -// ============================================================================ -// Internal String -// ============================================================================ - -/// Internal string represts a smaller type of string with limited set of -/// functionalities that we use only for internal usage -struct InternalString { - // We store the actual string in a "string" data section - const char *data; - size_t len; - - InternalString(const char *data, const unsigned int len) - : data(data), len(len){}; -}; - -// ============================================================================ -// Symbol -// ============================================================================ -struct Symbol { - const InternalString *ns; - const InternalString *name; - - Symbol(const InternalString *ns, const InternalString *name) - : ns(ns), name(name){}; -}; - -// ============================================================================ -// Namespace -// ============================================================================ -struct Namespace { - const InternalString *name; - - explicit Namespace(const InternalString *name) : name(name){}; -}; - -}; // namespace serene::types - -#endif diff --git a/libserene/lib/CMakeLists.txt b/libserene/lib/CMakeLists.txt deleted file mode 100644 index 6ab49f7..0000000 --- a/libserene/lib/CMakeLists.txt +++ /dev/null @@ -1,82 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -#TODO: To support MacOS look into cmake's public headers -# https://cmake.org/cmake/help/latest/prop_tgt/PUBLIC_HEADER.html - -# Prevent any future RPATH issue on Posix -if(NOT APPLE) - set(CMAKE_INSTALL_RPATH $ORIGIN) -endif() - -add_library(serene - serene.cpp - context.cpp - fs.cpp - - jit/halley.cpp - jit/packer.cpp) - -# Create an ALIAS target. This way if we mess up the name -# there will be an cmake error inseat of a linker error which is harder -# to understand. So any binary that wants to use serene has to -# use `Serene::lib` alias instead -add_library(Serene::lib ALIAS serene) - -set_target_properties(serene PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path}" - C_INCLUDE_WHAT_YOU_USE "${iwyu_path}" - - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -target_compile_options(serene - PRIVATE) - -target_link_options(serene - PRIVATE) - -if(SERENE_ENABLE_TIDY) - set_target_properties(serene PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if (CPP_20_SUPPORT) - target_compile_features(serene PUBLIC cxx_std_20) -else() - target_compile_features(serene PUBLIC cxx_std_17) -endif() - -# Generate the tablegen ODS files before this target -#add_dependencies(serene) - -# We need this directory, and users of our library will need it too -target_include_directories(serene PUBLIC "$") -target_include_directories(serene PUBLIC "$") - -# Generate the export.h -include(GenerateExportHeader) - -generate_export_header(serene EXPORT_FILE_NAME ${PROJECT_BINARY_DIR}/include/serene/export.h) -target_compile_definitions( - serene PUBLIC "$<$>:SERENE_STATIC_DEFINE>") - - -target_link_libraries(serene PRIVATE ${llvm_libs} BDWgc::gc) -llvm_update_compile_flags(serene) diff --git a/libserene/lib/context.cpp b/libserene/lib/context.cpp deleted file mode 100644 index 61be7eb..0000000 --- a/libserene/lib/context.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/context.h" - -#include // for exit - -namespace serene { - -int SereneContext::getOptimizatioLevel() { - if (targetPhase <= CompilationPhase::NoOptimization) { - return 0; - } - - if (targetPhase == CompilationPhase::O1) { - return 1; - } - if (targetPhase == CompilationPhase::O2) { - return 2; - } - return 3; -} - -void terminate(SereneContext &ctx, int exitCode) { - (void)ctx; - // TODO: Since we are running in a single thread for now using exit is fine - // but we need to adjust and change it to a thread safe termination - // process later on. - // NOLINTNEXTLINE(concurrency-mt-unsafe) - std::exit(exitCode); -} - -std::unique_ptr makeSereneContext(Options opts) { - return std::make_unique(opts); -}; - -}; // namespace serene diff --git a/libserene/lib/fs.cpp b/libserene/lib/fs.cpp deleted file mode 100644 index de80a3c..0000000 --- a/libserene/lib/fs.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/fs.h" - -#include // for error_code - -#include // for SmallString -#include // for Twine -#include // for file_magic, identify_magic -#include // for exists, status, file_status -#include // for native, get_separator - -#include // for replace - -namespace serene::fs { - -std::string extensionFor(SereneContext &ctx, NSFileType t) { - // TODO: [fs] Create a mapping from OS type and NSFileTypes and - // append the appropriate extension to the path. For now - // only few that we need are enough. - (void)ctx; - switch (t) { - case NSFileType::Source: - return ".srn"; - case NSFileType::TextIR: - return ".ll"; - break; - case NSFileType::StaticLib: - return ".a"; - break; - case NSFileType::SharedLib: - return ".so"; - break; - - default: - // TODO: This is temporary, remove this when created - // the mapping - return ".unknown"; - }; -}; - -/// Converts the given namespace name `nsName` to the file name -/// for that name space. E.g, `some.random.ns` will be translated -/// to `some_random_ns`. -std::string namespaceToPath(llvm::StringRef nsName) { - // TODO: [fs][perf] This function is not efficient. Fix it - std::string nsNameCopy = nsName.str(); - std::replace(nsNameCopy.begin(), nsNameCopy.end(), '.', '/'); - - llvm::SmallString path; - path.append(nsNameCopy); - llvm::sys::path::native(path); - - return std::string(path); -}; - -bool isStaticLib(llvm::StringRef path) { - llvm::file_magic magic; - // llvm::identify_magic returns an error code on failure - if (llvm::identify_magic(path, magic)) { - // If there was an error loading the file then skip it. - return false; - } - - return (magic == llvm::file_magic::archive || - magic == llvm::file_magic::macho_universal_binary); -}; - -bool isSharedLib(llvm::StringRef path) { - llvm::file_magic magic; - // llvm::identify_magic returns an error code on failure - if (llvm::identify_magic(path, magic)) { - // If there was an error loading the file then skip it. - return false; - } - - return (magic == llvm::file_magic::macho_dynamically_linked_shared_lib || - magic == llvm::file_magic::elf_shared_object); -}; - -/// Return a boolean indicating whether or not the given path exists. -bool exists(llvm::StringRef path) { - llvm::sys::fs::file_status status; - auto err = llvm::sys::fs::status(path, status); - - if (err) { - return false; - }; - - return llvm::sys::fs::exists(status); -} - -/// Join the given `path1` and `path2` with respect to the platform -/// conventions. -std::string join(llvm::StringRef path1, llvm::StringRef path2) { - llvm::SmallString path; - path.append(path1); - path.append(llvm::sys::path::get_separator().data()); - path.append(path2); - llvm::sys::path::native(path); - return std::string(path); -}; -}; // namespace serene::fs diff --git a/libserene/lib/jit/halley.cpp b/libserene/lib/jit/halley.cpp deleted file mode 100644 index 2957438..0000000 --- a/libserene/lib/jit/halley.cpp +++ /dev/null @@ -1,867 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/jit/halley.h" - -#include "serene/context.h" -#include "serene/fs.h" -#include "serene/options.h" -#include "serene/types/types.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define COMMON_ARGS_COUNT 8 - -namespace serene { - -namespace jit { - -// TODO: [error] Replace this function when we implemented -// the error subsystem with the official implementation -llvm::Error tempError(SereneContext &ctx, llvm::Twine s) { - (void)ctx; - return llvm::make_error( - std::make_error_code(std::errc::executable_format_error), - "[Error]: " + s); -}; -// /TODO - -void ObjectCache::notifyObjectCompiled(const llvm::Module *m, - llvm::MemoryBufferRef objBuffer) { - cachedObjects[m->getModuleIdentifier()] = - llvm::MemoryBuffer::getMemBufferCopy(objBuffer.getBuffer(), - objBuffer.getBufferIdentifier()); -} - -std::unique_ptr -ObjectCache::getObject(const llvm::Module *m) { - auto i = cachedObjects.find(m->getModuleIdentifier()); - - if (i == cachedObjects.end()) { - HALLEY_LOG("No object for " + m->getModuleIdentifier() + - " in cache. Compiling."); - return nullptr; - } - - HALLEY_LOG("Object for " + m->getModuleIdentifier() + " loaded from cache."); - return llvm::MemoryBuffer::getMemBuffer(i->second->getMemBufferRef()); -} - -void ObjectCache::dumpToObjectFile(llvm::StringRef outputFilename) { - // Set up the output file. - std::error_code error; - - auto file = std::make_unique(outputFilename, error, - llvm::sys::fs::OF_None); - if (error) { - - llvm::errs() << "cannot open output file '" + outputFilename.str() + - "': " + error.message() - << "\n"; - return; - } - // Dump the object generated for a single module to the output file. - // TODO: Replace this with a runtime check - assert(cachedObjects.size() == 1 && "Expected only one object entry."); - - auto &cachedObject = cachedObjects.begin()->second; - file->os() << cachedObject->getBuffer(); - file->keep(); -} - -llvm::orc::JITDylib *Halley::getLatestJITDylib(const types::Namespace &ns) { - return getLatestJITDylib(ns.name->data); -}; - -llvm::orc::JITDylib *Halley::getLatestJITDylib(const char *nsName) { - if (jitDylibs.count(nsName) == 0) { - return nullptr; - } - - auto vec = jitDylibs[nsName]; - // TODO: Make sure that the returning Dylib still exists in the JIT - // by calling jit->engine->getJITDylibByName(dylib_name); - return vec.empty() ? nullptr : vec.back(); -}; - -void Halley::pushJITDylib(types::Namespace &ns, llvm::orc::JITDylib *l) { - if (jitDylibs.count(ns.name->data) == 0) { - llvm::SmallVector vec{l}; - jitDylibs[ns.name->data] = vec; - return; - } - auto vec = jitDylibs[ns.name->data]; - vec.push_back(l); - jitDylibs[ns.name->data] = vec; -} - -size_t Halley::getNumberOfJITDylibs(types::Namespace &ns) { - if (jitDylibs.count(ns.name->data) == 0) { - return 0; - } - - return jitDylibs[ns.name->data].size(); -}; - -Halley::Halley(std::unique_ptr ctx, - llvm::orc::JITTargetMachineBuilder &&jtmb, llvm::DataLayout &&dl) - : cache(ctx->opts.JITenableObjectCache ? new ObjectCache() : nullptr), - gdbListener(ctx->opts.JITenableGDBNotificationListener - - ? llvm::JITEventListener::createGDBRegistrationListener() - : nullptr), - perfListener(ctx->opts.JITenablePerfNotificationListener - ? llvm::JITEventListener::createPerfJITEventListener() - : nullptr), - jtmb(jtmb), dl(dl), ctx(std::move(ctx)){}; - -// MaybeJITPtr Halley::lookup(exprs::Symbol &sym) const { -// HALLEY_LOG("Looking up: " << sym.toString()); -// auto *ns = ctx.getNS(sym.nsName); - -// if (ns == nullptr) { -// return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, -// "Can't find the namespace in the context: " + -// sym.nsName); -// } - -// auto *dylib = ctx.getLatestJITDylib(*ns); -// // - -// if (dylib == nullptr) { -// return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, -// "Don't know about namespace: " + sym.nsName); -// } - -// auto expectedSymbol = -// engine->lookup(*dylib, makePackedFunctionName(sym.name)); - -// // JIT lookup may return an Error referring to strings stored internally by -// // the JIT. If the Error outlives the ExecutionEngine, it would want have a -// // dangling reference, which is currently caught by an assertion inside JIT -// // thanks to hand-rolled reference counting. Rewrap the error message into -// a -// // string before returning. Alternatively, ORC JIT should consider copying -// // the string into the error message. -// if (!expectedSymbol) { -// std::string errorMessage; -// llvm::raw_string_ostream os(errorMessage); -// llvm::handleAllErrors(expectedSymbol.takeError(), -// [&os](llvm::ErrorInfoBase &ei) { ei.log(os); }); -// return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, -// os.str()); -// } - -// auto rawFPtr = expectedSymbol->getValue(); -// // NOLINTNEXTLINE(performance-no-int-to-ptr) -// auto fptr = reinterpret_cast(rawFPtr); - -// if (fptr == nullptr) { -// return errors::makeError(ctx, errors::CantResolveSymbol, sym.location, -// "Lookup function is null!"); -// } - -// return fptr; -// }; - -void Halley::setEngine(std::unique_ptr e, bool isLazy) { - // Later on we might use different classes of JIT which might need some - // work for lazyness - (void)ctx; - engine = std::move(e); - this->isLazy = isLazy; -}; - -void Halley::dumpToObjectFile(llvm::StringRef filename) { - cache->dumpToObjectFile(filename); -}; - -MaybeEngine Halley::make(std::unique_ptr sereneCtxPtr, - llvm::orc::JITTargetMachineBuilder &&jtmb) { - auto dl = jtmb.getDefaultDataLayoutForTarget(); - if (!dl) { - return dl.takeError(); - } - - auto jitEngine = std::make_unique(std::move(sereneCtxPtr), - std::move(jtmb), std::move(*dl)); - - // Why not the llvmcontext from the SereneContext?? - // Sice we're going to pass the ownership of this context to a thread - // safe module later on and we will only create the jit function wrappers - // with it, then it is fine to use a new context. - // - // What might go wrong? - // in a repl env when we have to create new modules on top of each other - // having two different contex might be a problem, but i think since we - // use the first context to generate the IR and the second one to just - // run it. - std::unique_ptr ctx(new llvm::LLVMContext); - - // Since we moved the original sereneCtxPtr into the engine. - auto &sereneCtx = jitEngine->getContext(); - - // Callback to create the object layer with symbol resolution to current - // process and dynamically linked libraries. - auto objectLinkingLayerCreator = [&](llvm::orc::ExecutionSession &session, - const llvm::Triple &tt) { - (void)tt; - - auto objectLayer = - std::make_unique(session, []() { - return std::make_unique(); - }); - - // Register JIT event listeners if they are enabled. - if (jitEngine->gdbListener != nullptr) { - objectLayer->registerJITEventListener(*jitEngine->gdbListener); - } - if (jitEngine->perfListener != nullptr) { - objectLayer->registerJITEventListener(*jitEngine->perfListener); - } - - // COFF format binaries (Windows) need special handling to deal with - // exported symbol visibility. - // cf llvm/lib/ExecutionEngine/Orc/LLJIT.cpp - // LLJIT::createObjectLinkingLayer - if (sereneCtx.triple.isOSBinFormatCOFF()) { - objectLayer->setOverrideObjectFlagsWithResponsibilityFlags(true); - objectLayer->setAutoClaimResponsibilityForObjectSymbols(true); - } - - return objectLayer; - }; - - // Callback to inspect the cache and recompile on demand. This follows - // Lang's LLJITWithObjectCache example. - auto compileFunctionCreator = [&](llvm::orc::JITTargetMachineBuilder JTMB) - -> llvm::Expected< - std::unique_ptr> { - llvm::CodeGenOpt::Level jitCodeGenOptLevel = - static_cast(sereneCtx.getOptimizatioLevel()); - - JTMB.setCodeGenOptLevel(jitCodeGenOptLevel); - - auto targetMachine = JTMB.createTargetMachine(); - if (!targetMachine) { - return targetMachine.takeError(); - } - - return std::make_unique( - std::move(*targetMachine), jitEngine->cache.get()); - }; - - // TODO: [jit] This is not a proper way to handle both engines. - // Create two different classes for different execution modes - // (`lazy` vs `eager`) with the same interface and use them - // where appropriate. - if (sereneCtx.opts.JITLazy) { - // Setup a LLLazyJIT instance to the times that latency is important - // for example in a REPL. This way - - auto jit = - cantFail(llvm::orc::LLLazyJITBuilder() - .setCompileFunctionCreator(compileFunctionCreator) - .setObjectLinkingLayerCreator(objectLinkingLayerCreator) - .create()); - - jitEngine->setEngine(std::move(jit), sereneCtx.opts.JITLazy); - } else { - // Setup a LLJIT instance for the times that performance is important - // and we want to compile everything as soon as possible. For instance - // when we run the JIT in the compiler - auto jit = - cantFail(llvm::orc::LLJITBuilder() - .setCompileFunctionCreator(compileFunctionCreator) - .setObjectLinkingLayerCreator(objectLinkingLayerCreator) - .create()); - jitEngine->setEngine(std::move(jit), sereneCtx.opts.JITLazy); - } - // /TODO - - jitEngine->engine->getIRCompileLayer().setNotifyCompiled( - [&](llvm::orc::MaterializationResponsibility &r, - llvm::orc::ThreadSafeModule tsm) { - auto syms = r.getRequestedSymbols(); - tsm.withModuleDo([&](llvm::Module &m) { - HALLEY_LOG("Compiled " - << syms << " for the module: " << m.getModuleIdentifier()); - }); - }); - - if (auto err = jitEngine->createCurrentProcessJD()) { - return err; - } - - return MaybeEngine(std::move(jitEngine)); -}; - -const types::InternalString &Halley::getInternalString(const char *s) { - // TODO: [serene.core] We need to provide some functions on llvm level to - // build instances from these type in a functional way. We need to avoid - // randomly build instances here and there that causes unsafe memory - assert(s && "s is nullptr: getInternalString"); - auto len = std::strlen(s); - - auto *str = static_cast( - GC_MALLOC(sizeof(types::InternalString))); - - // str->data = (char *)GC_MALLOC_ATOMIC(len); - // memcpy((void *)str->data, (void *)s, len); - memcpy(static_cast(str), static_cast(s), len); - str->len = len; - - stringStorage.push_back(str); - return *str; - // /TODO -}; - -types::Namespace &Halley::makeNamespace(const char *name) { - // TODO: [serene.core] We need to provide some functions on llvm level to - // build instances from these type in a functional way. We need to avoid - // randomly build instances here and there that causes unsafe memory - assert(name && "name is nullptr: createNamespace"); - const auto &nsName = getInternalString(name); - auto *ns = - static_cast(GC_MALLOC(sizeof(types::Namespace))); - ns->name = &nsName; - - nsStorage.push_back(ns); - return *ns; - // /TODO -}; - -llvm::Error Halley::createEmptyNS(const char *name) { - assert(name && "name is nullptr: createEmptyNS"); - // TODO: Look up the Namespace first. - auto &ns = makeNamespace(name); - auto numOfDylibs = getNumberOfJITDylibs(ns) + 1; - - HALLEY_LOG( - llvm::formatv("Creating Dylib {0}#{1}", ns.name->data, numOfDylibs)); - - auto newDylib = engine->createJITDylib( - llvm::formatv("{0}#{1}", ns.name->data, numOfDylibs)); - - if (!newDylib) { - llvm::errs() << "Couldn't create the jitDylib\n"; - serene::terminate(*ctx, 1); - } - - pushJITDylib(ns, &(*newDylib)); - return llvm::Error::success(); -}; - -MaybeJitAddress Halley::lookup(const types::Symbol &sym) const { - return lookup(sym.ns->data, sym.name->data); -} - -MaybeJitAddress Halley::lookup(const char *nsName, const char *sym) const { - assert(sym != nullptr && "'sym' is null: lookup"); - assert(nsName != nullptr && "'nsName' is null: lookup"); - - llvm::StringRef s{sym}; - llvm::StringRef ns{nsName}; - - std::string fqsym = (ns + "/" + s).str(); - - HALLEY_LOG("Looking up symbol: " << fqsym); - auto *dylib = const_cast(this)->jitDylibs[nsName].back(); - - if (dylib == nullptr) { - return tempError(*ctx, "No dylib " + s); - } - - HALLEY_LOG("Looking in dylib: " << static_cast(dylib)); - auto expectedSymbol = engine->lookup(*dylib, fqsym); - - // JIT lookup may return an Error referring to strings stored internally by - // the JIT. If the Error outlives the ExecutionEngine, it would want have a - // dangling reference, which is currently caught by an assertion inside JIT - // thanks to hand-rolled reference counting. Rewrap the error message into a - // string before returning. Alternatively, ORC JIT should consider copying - // the string into the error message. - if (!expectedSymbol) { - return expectedSymbol.takeError(); - } - - auto fptr = expectedSymbol->toPtr(); - - if (fptr == nullptr) { - return tempError(*ctx, "Lookup function is null!"); - } - - HALLEY_LOG("Found symbol '" << fqsym << "' at " - << static_cast(&fptr)); - return fptr; -}; - -// TODO: Remove this function before prod release -llvm::Error Halley::loadModule(const char *nsName, const char *file) { - assert(file && "'file' is nullptr: loadModule"); - assert(nsName && "'nsName' is nullptr: loadModule"); - - auto llvmContext = ctx->genLLVMContext(); - llvm::SMDiagnostic error; - - auto *dylib = jitDylibs[nsName].back(); - - auto module = llvm::parseIRFile(file, error, *llvmContext); - - if (module == nullptr) { - return llvm::make_error( - std::make_error_code(std::errc::executable_format_error), - error.getMessage().str() + " File: " + file); - } - - auto tsm = - llvm::orc::ThreadSafeModule(std::move(module), std::move(llvmContext)); - - return engine->addIRModule(*dylib, std::move(tsm)); -}; -// /TODO - -// TODO: [error] Remove this function when we implemented -// the error subsystem -llvm::Error NotImplemented(llvm::StringRef s) { - return llvm::make_error( - std::make_error_code(std::errc::executable_format_error), - "Not Implemented: " + s); -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - (void)req; - return nullptr; -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - (void)req; - return nullptr; -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - (void)req; - return nullptr; -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - - auto file = fs::join(req.path, req.nsToFileName + ".o"); - - if (!fs::exists(file)) { - // Can't locate any object file, skit to the next loader - HALLEY_LOG("File does not exist: " << file << "\n"); - return nullptr; - } - - auto err = createEmptyNS(req.nsName.str().c_str()); - if (err) { - return err; - } - - auto *jd = getLatestJITDylib(req.nsName.str().c_str()); - assert(jd != nullptr && "'jd' must not be null since we just created it."); - - auto buf = llvm::errorOrToExpected(llvm::MemoryBuffer::getFile(file)); - if (!buf) { - return buf.takeError(); - } - - err = engine->getObjLinkingLayer().add(*jd, std::move(*buf)); - - if (err) { - return err; - } - - return jd; -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - - // Skip missing or non-regular paths. - if (llvm::sys::fs::get_file_type(req.path) != - llvm::sys::fs::file_type::regular_file) { - return tempError(*ctx, "Not a regular file: " + req.path); - } - - llvm::file_magic magic; - if (auto ec = llvm::identify_magic(req.path, magic)) { - // If there was an error loading the file then skip it. - return tempError(*ctx, - ec.message() + "\nFile Identification Erorr: " + req.path); - } - - if (magic != llvm::file_magic::archive || - magic != llvm::file_magic::macho_universal_binary) { - return tempError(*ctx, "Not a static lib: " + req.path); - } - - auto err = createEmptyNS(req.nsName.str().c_str()); - if (err) { - return err; - } - - auto &session = engine->getExecutionSession(); - auto *jd = getLatestJITDylib(req.nsName.str().c_str()); - assert(jd == nullptr && "'jd' must not be null since we just created it."); - - // TODO: Handle hidden static libs as well look at the addLibrary/AddArchive - // in llvm-jitlink - - auto generator = llvm::orc::StaticLibraryDefinitionGenerator::Load( - engine->getObjLinkingLayer(), req.path.str().c_str(), - session.getExecutorProcessControl().getTargetTriple(), - std::move(llvm::orc::getObjectFileInterface)); - - if (!generator) { - return generator.takeError(); - } - - jd->addGenerator(std::move(*generator)); - return jd; -}; - -template <> -MaybeDylibPtr -Halley::loadNamespaceFrom(NSLoadRequest &req) { - (void)req; - // switch (magic) { - // case llvm::file_magic::elf_shared_object: - // case llvm::file_magic::macho_dynamically_linked_shared_lib: { - // // TODO: On first reference to LibPath this should create a JITDylib - // // with a generator and add it to JD's links-against list. Subsquent - // // references should use the JITDylib created on the first - // // reference. - // auto g = llvm::EPCDynamicLibrarySearchGenerator::Load(session, path); - // if (!g) - // return g.takeError(); - // jd.addGenerator(std::move(*g)); - // break; - // } - // case llvm::file_magic::archive: - // case llvm::file_magic::macho_universal_binary: { - // } - // default: - // // This file isn't a recognized library kind. - // LibFound = false; - // break; - // } - - return NotImplemented("loadNamespaceFrom"); -}; - -MaybeDylibPtr Halley::loadNamespaceFrom(fs::NSFileType type_, - NSLoadRequest &req) { - switch (type_) { - case fs::NSFileType::Source: - return loadNamespaceFrom(req); - case fs::NSFileType::TextIR: - return loadNamespaceFrom(req); - case fs::NSFileType::BinaryIR: - return loadNamespaceFrom(req); - case fs::NSFileType::ObjectFile: - return loadNamespaceFrom(req); - case fs::NSFileType::StaticLib: - case fs::NSFileType::SharedLib: - return loadNamespaceFrom(req); - }; - llvm_unreachable("Halley::loadNamespaceFrom unhandled NSFileType"); -}; - -MaybeDylibPtr Halley::loadNamespace(std::string &nsName) { - if (ctx->getLoadPaths().empty()) { - return tempError(*ctx, "Load paths should not be empty"); - } - - for (auto &path : ctx->getLoadPaths()) { - auto nsFileName = fs::namespaceToPath(nsName); - NSLoadRequest req{nsName, path, nsFileName}; - - for (auto type_ : {fs::NSFileType::Source, fs::NSFileType::ObjectFile}) { - auto maybeJDptr = loadNamespaceFrom(type_, req); - - if (!maybeJDptr) { - return maybeJDptr.takeError(); - } - - if (*maybeJDptr != nullptr) { - auto *processJD = engine->getExecutionSession().getJITDylibByName( - MAIN_PROCESS_JD_NAME); - - if (processJD == nullptr) { - // TODO: [jit] Panic here - return tempError(*ctx, "Can't find the main process JD"); - // /TODO - } - - (*maybeJDptr)->addToLinkOrder(*processJD); - return *maybeJDptr; - } - } - } - - return tempError(*ctx, "Can't find namespace: " + nsName); -}; - -MaybeDylibPtr Halley::loadStaticLibrary(const std::string &name) { - if (ctx->getLoadPaths().empty()) { - return tempError(*ctx, "Load paths should not be empty"); - } - - for (auto &path : ctx->getLoadPaths()) { - auto file = fs::join(path, name + ".a"); - - if (!fs::exists(file)) { - continue; - } - - if (!fs::isStaticLib(file)) { - return tempError(*ctx, "Not a static lib: " + file); - } - - auto *objectLayer = &engine->getObjLinkingLayer(); - - auto generator = llvm::orc::StaticLibraryDefinitionGenerator::Load( - *objectLayer, file.c_str(), - engine->getExecutionSession() - .getExecutorProcessControl() - .getTargetTriple(), - std::move(llvm::orc::getObjectFileInterface)); - - if (!generator) { - return generator.takeError(); - } - - auto jd = engine->createJITDylib(llvm::formatv("{0}#{1}", name, 0)); - - if (!jd) { - return jd.takeError(); - } - - jd->addGenerator(std::move(*generator)); - - std::vector nsNames = {name}; - - auto definition = engine->lookup(*jd, "__serene_namespaces"); - - if (!definition) { - HALLEY_LOG("Library '" << name << "' is not a Serene lib."); - // We just want to ignore the error - llvm::consumeError(definition.takeError()); - } else { - HALLEY_LOG("Library '" << name << "' is a Serene lib."); - // TODO: call the __serene_namespaces and set nsNames to - // the list of namespaces that it returns - (void)*definition; - } - - for (auto &nsName : nsNames) { - auto ns = makeNamespace(nsName.str().c_str()); - pushJITDylib(ns, &(*jd)); - } - - return &jd.get(); - } - - return tempError(*ctx, "Can't find static lib: " + name); -}; - -MaybeDylibPtr Halley::loadSharedLibFile(llvm::StringRef name, - llvm::StringRef path) { - if (!fs::isSharedLib(path)) { - return tempError(*ctx, "Not a shared lib: " + path); - } - - auto generator = llvm::orc::EPCDynamicLibrarySearchGenerator::Load( - engine->getExecutionSession(), path.str().c_str()); - - if (!generator) { - return generator.takeError(); - } - - auto jd = engine->createJITDylib(llvm::formatv("{0}#{1}", name, 0)); - - if (!jd) { - return jd.takeError(); - } - - jd->addGenerator(std::move(*generator)); - - return &jd.get(); -}; - -MaybeDylibPtr Halley::loadSharedLibrary(const std::string &name) { - if (ctx->getLoadPaths().empty()) { - return tempError(*ctx, "Load paths should not be empty"); - } - - for (auto &path : ctx->getLoadPaths()) { - auto file = fs::join(path, name + ".so"); - - if (!fs::exists(file)) { - continue; - } - - auto maybeJD = loadSharedLibFile(name, file); - if (!maybeJD) { - return maybeJD.takeError(); - } - - auto *jd = *maybeJD; - auto nsNames = getContainedNamespaces(name, jd); - - for (const auto *nsName : nsNames) { - auto ns = makeNamespace(nsName); - pushJITDylib(ns, jd); - } - - return jd; - } - - return tempError(*ctx, "Can't find the dynamic lib: " + name); -}; - -std::vector Halley::getContainedNamespaces(llvm::StringRef name, - DylibPtr jd) { - - std::vector nsNames = {name.str().c_str()}; - auto definition = engine->lookup(*jd, "__serene_namespaces"); - - if (!definition) { - HALLEY_LOG("Library is not a Serene lib."); - // We just want to ignore the error - llvm::consumeError(definition.takeError()); - } - HALLEY_LOG("Library is a Serene lib."); - // TODO: call the __serene_namespaces and set nsNames to - // the list of namespaces that it returns - - return nsNames; -}; - -llvm::Error Halley::createCurrentProcessJD() { - - auto &es = engine->getExecutionSession(); - auto *processJDPtr = es.getJITDylibByName(MAIN_PROCESS_JD_NAME); - - if (processJDPtr != nullptr) { - // We already created the JITDylib for the current process - return llvm::Error::success(); - } - - auto processJD = es.createJITDylib(MAIN_PROCESS_JD_NAME); - - if (!processJD) { - return processJD.takeError(); - } - - auto generator = - llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess( - engine->getDataLayout().getGlobalPrefix()); - - if (!generator) { - return generator.takeError(); - } - - processJD->addGenerator(std::move(*generator)); - return llvm::Error::success(); -}; - -llvm::Error Halley::invokePacked(const types::Symbol &name, - llvm::MutableArrayRef args) const { - auto expectedFPtr = lookup(name); - if (!expectedFPtr) { - return expectedFPtr.takeError(); - } - - auto *fptr = *expectedFPtr; - (*fptr)(args.data()); - - return llvm::Error::success(); -} - -MaybeEngine makeHalleyJIT(std::unique_ptr ctx) { - llvm::orc::JITTargetMachineBuilder jtmb(ctx->triple); - auto maybeJIT = Halley::make(std::move(ctx), std::move(jtmb)); - if (!maybeJIT) { - return maybeJIT.takeError(); - } - - return maybeJIT; -}; - -} // namespace jit -} // namespace serene diff --git a/libserene/lib/jit/packer.cpp b/libserene/lib/jit/packer.cpp deleted file mode 100644 index bfd7a59..0000000 --- a/libserene/lib/jit/packer.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/jit/packer.h" - -#include "serene/config.h" // for I64_SIZE, COMMON_ARGS_COUNT - -#include // for APInt -#include // for DenseSet -#include // for size, enumerate, enumerator -#include // for operator!=, ilist_iterator -#include // for iterator_facade_base -#include // for iterator_range -#include // for Argument -#include // for BasicBlock -#include // for Constant -#include // for PointerType, IntegerType, Funct... -#include // for Function -#include // for IRBuilder -#include // for LoadInst, CallInst -#include // for Module -#include // for Type -#include // for Value -#include // for cast - -#include // for uint64_t -namespace serene::jit { - -std::string makePackedFunctionName(llvm::StringRef name) { - // TODO: move the "_serene_" constant to a macro or something - return PACKED_FUNCTION_NAME_PREFIX + name.str(); -} - -void packFunctionArguments(llvm::Module *module) { - auto &ctx = module->getContext(); - llvm::IRBuilder<> builder(ctx); - llvm::DenseSet interfaceFunctions; - for (auto &func : module->getFunctionList()) { - if (func.isDeclaration()) { - continue; - } - if (interfaceFunctions.count(&func) != 0) { - continue; - } - - // Given a function `foo(<...>)`, define the interface function - // `serene_foo(i8**)`. - auto *newType = llvm::FunctionType::get( - builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(), - /*isVarArg=*/false); - auto newName = makePackedFunctionName(func.getName()); - auto funcCst = module->getOrInsertFunction(newName, newType); - llvm::Function *interfaceFunc = - llvm::cast(funcCst.getCallee()); - interfaceFunctions.insert(interfaceFunc); - - // Extract the arguments from the type-erased argument list and cast them to - // the proper types. - auto *bb = llvm::BasicBlock::Create(ctx); - bb->insertInto(interfaceFunc); - builder.SetInsertPoint(bb); - llvm::Value *argList = interfaceFunc->arg_begin(); - llvm::SmallVector args; - - args.reserve(static_cast(llvm::size(func.args()))); - for (const auto &indexedArg : llvm::enumerate(func.args())) { - llvm::Value *argIndex = llvm::Constant::getIntegerValue( - builder.getInt64Ty(), llvm::APInt(I64_SIZE, indexedArg.index())); - llvm::Value *argPtrPtr = - builder.CreateGEP(builder.getInt8PtrTy(), argList, argIndex); - llvm::Value *argPtr = - builder.CreateLoad(builder.getInt8PtrTy(), argPtrPtr); - llvm::Type *argTy = indexedArg.value().getType(); - argPtr = builder.CreateBitCast(argPtr, argTy->getPointerTo()); - llvm::Value *arg = builder.CreateLoad(argTy, argPtr); - args.push_back(arg); - } - - // Call the implementation function with the extracted arguments. - llvm::Value *result = builder.CreateCall(&func, args); - - // Assuming the result is one value, potentially of type `void`. - if (!result->getType()->isVoidTy()) { - llvm::Value *retIndex = llvm::Constant::getIntegerValue( - builder.getInt64Ty(), - llvm::APInt(I64_SIZE, - static_cast(llvm::size(func.args())))); - llvm::Value *retPtrPtr = - builder.CreateGEP(builder.getInt8PtrTy(), argList, retIndex); - llvm::Value *retPtr = - builder.CreateLoad(builder.getInt8PtrTy(), retPtrPtr); - retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo()); - builder.CreateStore(result, retPtr); - } - - // The interface function returns void. - builder.CreateRetVoid(); - } -}; - -} // namespace serene::jit diff --git a/libserene/lib/serene.cpp b/libserene/lib/serene.cpp deleted file mode 100644 index c2fbd10..0000000 --- a/libserene/lib/serene.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "serene/serene.h" - -#include "serene/context.h" // for SereneContext, makeSereneCon... -#include "serene/jit/halley.h" // for makeHalleyJIT, Engine, Maybe... - -#include // for StringRef -#include // for list, MiscFlags, cat, desc -#include // for ManagedStatic -#include // for InitializeAllAsmParsers, Ini... - -#include // for string -#include // for move -#include // for vector - -namespace serene { -// CLI Option ---------------- - -/// All the global CLI option ar defined here. If you need to add a new global -/// option -/// make sure that you are handling it in `applySereneCLOptions` too. -struct SereneOptions { - - llvm::cl::OptionCategory clOptionsCategory{"Discovery options"}; - - llvm::cl::list loadPaths{ - "l", llvm::cl::desc("The load path to use for compilation."), - llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs, - llvm::cl::cat(clOptionsCategory)}; - - llvm::cl::list sharedLibraryPaths{ - "sl", llvm::cl::desc("Where to find shared libraries"), - llvm::cl::ZeroOrMore, llvm::cl::MiscFlags::PositionalEatsArgs, - llvm::cl::cat(clOptionsCategory)}; -}; - -static llvm::ManagedStatic options; - -void registerSereneCLOptions() { - // Make sure that the options struct has been constructed. - *options; - - // #ifdef SERENE_WITH_MLIR_CL_OPTION - // // mlir::registerAsmPrinterCLOptions(); - // mlir::registerMLIRContextCLOptions(); - // mlir::registerPassManagerCLOptions(); - // #endif -} - -void applySereneCLOptions(serene::jit::Engine &engine) { - if (!options.isConstructed()) { - return; - } - - // TODO: [engine] Should we move this to the engine itself? - auto &ctx = engine.getContext(); - ctx.setLoadPaths(options->loadPaths); - - // #ifdef SERENE_WITH_MLIR_CL_OPTION - // mlir::applyPassManagerCLOptions(ctx.pm); - // #endif -} - -void initSerene() { - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargets(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); - llvm::InitializeAllAsmPrinters(); -}; - -serene::jit::MaybeEngine makeEngine(Options opts) { - auto ctx = makeSereneContext(opts); - return serene::jit::makeHalleyJIT(std::move(ctx)); -}; - -} // namespace serene diff --git a/resources/benchmarks/parsers/example_code.srn b/resources/benchmarks/parsers/example_code.srn deleted file mode 100644 index 9b6610e..0000000 --- a/resources/benchmarks/parsers/example_code.srn +++ /dev/null @@ -1,85 +0,0 @@ -;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*- - -;; Copyright (C) 2010-2020 The Magit Project Contributors -;; -;; You should have received a copy of the AUTHORS.md file which -;; lists all contributors. If not, see http://magit.vc/authors. - -;; Author: Jonas Bernoulli -;; Maintainer: Jonas Bernoulli - -;; Magit is free software; you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; Magit is distributed in the hope that it will be useful, but WITHOUT -;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public -;; License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with Magit. If not, see http://www.gnu.org/licenses. - -;;; Commentary: - -;; This library implements support for looking at Git diffs and -;; commits. - -;;; Code: - -(eval-when-compile - (require 'ansi-color) - (require 'subr-x)) - -(require 'git-commit) -(require 'magit-core) - -;; For `magit-diff-popup' -(declare-function magit-stash-show "magit-stash" (stash optional args files)) -;; For `magit-diff-visit-file' -(declare-function dired-jump "dired-x" (optional other-window file-name)) -(declare-function magit-find-file-noselect "magit-files" (rev file)) -(declare-function magit-status-setup-buffer "magit-status" (directory)) -;; For `magit-diff-while-committing' -(declare-function magit-commit-message-buffer "magit-commit" ()) -;; For `magit-insert-revision-gravatar' -(defvar gravatar-size) -;; For `magit-show-commit' and `magit-diff-show-or-scroll' -(declare-function magit-current-blame-chunk "magit-blame" ()) -(declare-function magit-blame-mode "magit-blame" (optional arg)) -(defvar magit-blame-mode) -;; For `magit-diff-show-or-scroll' -(declare-function git-rebase-current-line "git-rebase" ()) -;; For `magit-diff-unmerged' -(declare-function magit-merge-in-progress-p "magit-merge" ()) -(declare-function magit--merge-range "magit-merge" (optional head)) -;; For `magit-diff--dwim' -(declare-function forge--pullreq-ref "forge-pullreq" (pullreq)) -;; For `magit-diff-wash-diff' -(declare-function ansi-color-apply-on-region "ansi-color" (begin end)) - -(eval-when-compile - (cl-pushnew 'base-ref eieio--known-slot-names) - (cl-pushnew 'orig-rev eieio--known-slot-names) - (cl-pushnew 'action-type eieio--known-slot-names) - (cl-pushnew 'target eieio--known-slot-names)) - -(require 'diff-mode) -(require 'smerge-mode) - -;;; Options -;;;; Diff Mode - -(defgroup magit-diff nil - "Inspect and manipulate Git diffs." - link '(info-link "(magit)Diffing") - group 'magit-modes - type 'float) - -(asd 234 (asd zxc wqe asd asd rewe asd (asd asd (asd asd asd (123 3213123 'asd 'asd "sadasd" (asd asdsad (zxczxc (asdasd asd asd (asdas asd as 234234 324 (234 234 asd 342 ("asdasd" sadf 234 asd ((((((((((((((((((((((((((((((((asd asd asdasd (((((((((((((asdasdasd (((((((((((((((asdasdasd (asdasdasdasd asdas )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) - - --234234 -ascent -9393 diff --git a/resources/docker/llvm/Dockerfile b/resources/docker/llvm/Dockerfile deleted file mode 100644 index 7d9b382..0000000 --- a/resources/docker/llvm/Dockerfile +++ /dev/null @@ -1,69 +0,0 @@ -FROM docker.io/debian:sid-slim - -ARG VERSION - -RUN apt-get update && \ - apt-get install --no-install-recommends -y \ - gnupg \ - cmake \ - ccache \ - git \ - ninja-build \ - binutils \ - lsb-release \ - wget \ - software-properties-common \ - zlib1g \ - cppcheck \ - shellcheck \ - zlib1g-dev - -RUN wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh -RUN ./llvm.sh ${VERSION} all -RUN apt-get update --fix-missing && \ - apt-get install -y --no-install-recommends \ - mlir-${VERSION}-tools \ - libmlir-${VERSION}-dev \ - libmlir-${VERSION} \ - libmlir-${VERSION}-dbgsym \ - liblld-${VERSION} \ - liblld-${VERSION}-dev \ - clang-format-${VERSION} \ - clang-tidy-${VERSION} - -RUN ln -s `which lld-${VERSION}` /usr/bin/lld && \ - ln -s `which clang-${VERSION}` /usr/bin/clang && \ - ln -s `which clang++-${VERSION}` /usr/bin/clang++ && \ - ln -s `which clang-format-${VERSION}` /usr/bin/clang-format && \ - ln -s `which clang-tidy-${VERSION}` /usr/bin/clang-tidy && \ - ln -s `which mlir-tblgen-${VERSION}` /usr/bin/mlir-tblgen - -ENV MLIR_DIR /usr/lib/llvm-${VERSION} -ENV CMAKE_PREFIX_PATH=/usr/lib/llvm-${VERSION} -ENV LD_LIBRARY_PATH=/usr/lib/llvm-${VERSION}/lib/clang/${VERSION}.0.0/lib/linux/ -ENV CC=/usr/bin/clang -ENV CXX=/usr/bin/clang++ - -# --branch clang_${VERSION} -WORKDIR /iwuy -RUN git clone https://github.com/include-what-you-use/include-what-you-use.git --depth 1 && \ - mkdir build && cd build && \ - cmake -G Ninja -DCMAKE_PREFIX_PATH=/usr/lib/llvm-${VERSION} ../include-what-you-use && \ - cmake --build . && \ - cmake -P cmake_install.cmake - -WORKDIR /boehm -RUN git clone https://github.com/ivmai/bdwgc.git --depth 1 --branch v8.2.0 && \ - mkdir build && cd build && \ - cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -Denable_cplusplus=ON -Denable_threads=ON \ - -Denable_gcj_support=OFF -Dinstall_headers=ON \ - -DCMAKE_POSITION_INDEPENDENT_CODE=ON ../bdwgc && \ - cmake --build . --config Release && \ - cmake -P cmake_install.cmake - -WORKDIR /app -RUN rm /iwuy -rf && rm /boehm -rf && rm /llvm.sh - -RUN apt-get purge -y git software-properties-common wget && \ - apt-get autoremove -y && \ - apt-get clean diff --git a/resources/docker/llvm/Dockerfile.ci b/resources/docker/llvm/Dockerfile.ci deleted file mode 100644 index 2acf41a..0000000 --- a/resources/docker/llvm/Dockerfile.ci +++ /dev/null @@ -1,11 +0,0 @@ -FROM rg.fr-par.scw.cloud/serene/llvm:latest - -WORKDIR /app -# For CI -COPY .pre-commit-config.yaml . -RUN apt-get update && \ - apt-get install -y --no-install-recommends git python3 python3-pip && \ - pip3 install pre-commit && \ - git init . && \ - pre-commit autoupdate && \ - rm -fv /app/.pre-commit-config.yaml diff --git a/resources/docker/llvm/Dockerfile.source_base b/resources/docker/llvm/Dockerfile.source_base deleted file mode 100644 index 21bc286..0000000 --- a/resources/docker/llvm/Dockerfile.source_base +++ /dev/null @@ -1,24 +0,0 @@ -FROM debian:sid-slim as builder - -RUN apt-get update --fix-missing && apt-get install -y wget gnupg ccache cmake ccache git ninja-build build-essential binutils - -RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|apt-key add - -RUN echo "deb http://apt.llvm.org/unstable/ llvm-toolchain main" >> /etc/apt/sources.list - -RUN apt-get update --fix-missing && apt-get install -y clang-format-15 clang-tidy-15 clang-tools-15 clang-15 clangd-15 libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-15-dev libclang1-15 liblldb-15-dev lld-15 lldb-15 llvm-15-dev llvm-15-runtime llvm python3-clang-15 python3-lldb-15 mlir-15-tools libmlir-15-dev - -RUN mkdir -p /opt/build - -WORKDIR /opt/build -COPY ./ /usr/src/llvm-project - -RUN ln -s `which lld-15` /usr/bin/lld && ln -s `which lldb-15` /usr/bin/lldb - -RUN cmake -G Ninja /usr/src/llvm-project/llvm -DCMAKE_INSTALL_PREFIX=/opt/llvm -DLLVM_PARALLEL_COMPILE_JOBS=7 -DLLVM_PARALLEL_LINK_JOBS=1 -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_CCACHE_BUILD=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DLLVM_ENABLE_PROJECTS='clang;lldb;lld;mlir;clang-tools-extra;compiler-rt' -DCMAKE_C_COMPILER=clang-15 -DCMAKE_CXX_COMPILER=clang++-15 -DLLVM_ENABLE_LLD=ON - -RUN cmake --build . -RUN cmake -DCMAKE_INSTALL_PREFIX=/opt/llvm -P cmake_install.cmake - -FROM debian:sid-slim - -COPY --from=builder /opt/llvm /opt/llvm diff --git a/resources/docker/serene/Dockerfile b/resources/docker/serene/Dockerfile deleted file mode 100644 index 3fada0c..0000000 --- a/resources/docker/serene/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM rg.fr-par.scw.cloud/serene/llvm:15-8 - -ARG TASK=build - -WORKDIR /app - -COPY . . - -RUN ./builder ${TASK} diff --git a/resources/docker/toolchain/stage0/Dockerfile b/resources/docker/toolchain/stage0/Dockerfile deleted file mode 100644 index c9e02f7..0000000 --- a/resources/docker/toolchain/stage0/Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -FROM alpine:edge - -RUN apk update \ - && apk add --no-cache \ - ninja \ - make \ - clang \ - clang-dev \ - bison \ - flex \ - # compiler-rt \ # - # llvm-libunwind \ - # lld \ - gcc \ - libgcc - curl \ - g++ \ - alpine-sdk \ - libatomic \ - libgcc \ - cmake \ - bash \ - git \ - linux-headers \ - zlib \ - zlib-dev \ - zstd \ - zstd-dev \ - tar \ - xz \ - python3 - -# RUN ln -sf /usr/bin/clang /usr/bin/cc \ -# && ln -sf /usr/bin/clang++ /usr/bin/c++ \ -# && ls -l /usr/bin/cc /usr/bin/c++ \ -# && cc --version \ -# && c++ --version - # && update-alternatives --install /usr/bin/cc cc /usr/bin/clang 10\ - # && update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 10\ - - -RUN addgroup -S serene && \ - adduser -h /home/serene -S serene -G serene - -USER serene:serene -ENV HOME=/home/serene -WORKDIR /home/serene/serene diff --git a/resources/docker/toolchain/stage0/Sysroot b/resources/docker/toolchain/stage0/Sysroot deleted file mode 100644 index f63e579..0000000 --- a/resources/docker/toolchain/stage0/Sysroot +++ /dev/null @@ -1,22 +0,0 @@ -FROM alpine:edge - -RUN apk update \ - && apk upgrade \ - && apk add --no-cache \ - alpine-sdk \ - linux-headers \ - gcc \ - g++ \ - libgcc \ - build-base \ - zlib \ - zlib-dev \ - zstd \ - zstd-dev - # clang-dev \ - # compiler-rt \ - # libc++-dev \ - # llvm-runtimes \ - # libc++-static \ - # llvm-libunwind \ - # lld \ diff --git a/resources/emacs/serene-dev.el b/resources/emacs/serene-dev.el deleted file mode 100644 index 345b35c..0000000 --- a/resources/emacs/serene-dev.el +++ /dev/null @@ -1,122 +0,0 @@ -;;; serene-dev --- Serene's development lib for Emacs users -*- lexical-binding: t; -*- -;; -;; Copyright (c) 2019-2023 Sameer Rahmani -;; -;; Author: Sameer Rahmani -;; URL: https://serene-lang.org -;; Version: 0.1.0 -;; Package-Requires: (projectile) -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . -;; -;;; Commentary: -;; In order to use this library just put it somewhere that Emacs can load it -;; either via `require' or `load' and then call `serene/setup-dev-env' in your -;; init file. -;; -;; Keybindings: -;; * `s-c c' Runs `./builder compile' -;; * `s-c b' Runs `./builder build' -;; -;;; Code: - - -(defvar serene/compile-buffer "*compile*") - - -(defmacro serene/builder (command &optional buf-name sync) - "Run the given COMMAND via the builder script. -Use the optional BUF-NAME as the buffer. - -If SYNC is non-nil it will block." - (let ((buf (or buf-name (format "*%s*" command)))) - (if (not sync) - `(projectile-run-async-shell-command-in-root - (format "./builder %s" ,command) ,buf) - `(projectile-run-shell-command-in-root - (format "./builder %s" ,command) ,buf)))) - - -(defun serene/compile (&optional sync) - "Compile the project. -It will run the `./builder compile' asynchronously or synchronously if -SYNC is non-nil." - (interactive) - (serene/builder "compile" serene/compile-buffer sync)) - - -(defun serene/build () - "Compile the project. -It will run the `./builder build' asynchronously." - (interactive) - (serene/builder "build" serene/compile-buffer)) - - -(defun serene/build-release () - "Compile the project. -It will run the `./builder build-release' asynchronously." - (interactive) - (serene/builder "build-release" serene/compile-buffer)) - - -(defun serene/run (args) - "Run the project with the give ARGS. -It will run the `./builder build-release' asynchronously." - (interactive "sRun: ") - (serene/builder (format "run %s" args) serene/compile-buffer)) - - -(defun serene/run-hello-world (args) - "Run the project with the give ARGS. -It will run the `./builder build-release' asynchronously." - (interactive "s-b . -l `pwd` docs.examples.hello_world ") - (let ((cmd (format "run -b . -l `pwd` docs.examples.hello_world %s" args))) - (serene/builder cmd serene/compile-buffer))) - - -(defun serene/run-hello-world-emit (args) - "Run the project with the give ARGS. -It will run the `./builder build-release' asynchronously." - (interactive (list (completing-read "Emit: " '("ast" "semantic" "slir" "mlir" "lir" "ir" "jit" "object" "target")))) - (let ((cmd (format "run -b . -l `pwd` docs.examples.hello_world -emit %s" args))) - (serene/builder cmd serene/compile-buffer))) - - -(defun serene/setup-keybindings () - "Setup the serene-dev keybindings." - (interactive) - (define-key c++-mode-map (kbd "s-c c") #'serene/compile) - (define-key c++-mode-map (kbd "s-c b") #'serene/build) - (define-key c++-mode-map (kbd "s-c r") #'serene/run) - (define-key c++-mode-map (kbd "s-c e") #'serene/run-hello-world-emit)) - - -(defun serene/format-buffer () - "Format the buffer if `lsp-format-buffer' is available." - (when (and (eq major-mode 'c++-mode) (featurep 'lsp-mode)) - (lsp-format-buffer))) - - -(defun serene/setup-dev-env () - "Setup the development env of Serene." - (interactive) - (add-hook 'c++-mode-hook - (lambda () - (require 'projectile) - (serene/setup-keybindings) - (add-hook 'before-save-hook #'serene/format-buffer)))) - - -(provide 'serene-dev) -;;; serene-dev.el ends here diff --git a/resources/images/logo-history.svg b/resources/images/logo-history.svg deleted file mode 100644 index 74766bf..0000000 --- a/resources/images/logo-history.svg +++ /dev/null @@ -1,413 +0,0 @@ - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/resources/images/serene.svg b/resources/images/serene.svg deleted file mode 100644 index cb605d1..0000000 --- a/resources/images/serene.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/resources/museum/SUPPORTERS b/resources/museum/SUPPORTERS deleted file mode 100644 index 30f90ea..0000000 --- a/resources/museum/SUPPORTERS +++ /dev/null @@ -1 +0,0 @@ -Here is a list of all the generous people who has supported Serene so far: diff --git a/resources/museum/first_executable_2021_07_12 b/resources/museum/first_executable_2021_07_12 deleted file mode 100755 index 6b9b7ea7c064980f6869b6171964f4a53f8a8f94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19600 zcmeHPYiu0HeV@JMktb0)zVx)*>YSJ5I(H{hG(kUT-SJ@^8_J?&$&z8q>*d|v1G?Kg z?d_42;kd5lv}R+a3WA_5VALNP6h^<)MO)NpgT{u0xJAFj{ZJSvg1SZ12uR|}Nt^_2 zV)pl+ng8)_NyYvU^wSQw^MC(m_CK?;Gjluqt+|DVB8DM2MZ|-GsKj7KvQ#d_;H)Gy zZ&LJ&jQE7OL-c~vgDWE?1Qo`x98m&>F|B6;lHIFX{%Rxxis%dhal6bnAlHx}*=?kZ zMiqRQ93wFlgNi1*D507b`u-SR(FHJMy>@vCGDb>dBw!fRb__f1C^m~JrM~!}vSav; zwtH7Ywxe*6-Ba4`DQ(B_s@7-7@uZm0bzR5vdL#pi=nMgokog8AT}q4J@e73aB#0uI z>4M{u5`rPyorE3L^W!EC`zc-Ct>W^UzCVT>o^-XcG%=p87LwJ9+geSoPEI5z##7CD zYE0fY`6u0D51)}$qHdr=A!(BFB^e(xBb(tZbngN$u?1gP7HXQen!fG%R?V)sf@rGf zggCY^KRsiOrN&bCK(AD*yIRkJCskVmwHyJ(@oL>x*+#No(`DT}nvodAp6bTwXC3^` z`(}9v!w7^C2qO?iAdEm5fiMDL1i}b}5eOrYyZrrF?u*eMq=m?R;SE2s{;k~Q>#=L? zz>NN2e(miib8G*RyZoOw7f;W>^~Q5U8IgPI&4dJR34rz8e+u&-4;-8o;`Kurh^Hv` zM_wm4z?#=g(=8SLV-u}=Z zYJ2F@9)kAIP1z`0wDz9Kt$pXlv+L{Y-;ACB$2fmY)+ea{y)Si_|2i!cuWj&xboT7R zm8mUk46~ zg|#0pti3n8_TB9Iu7As|U(4P5?bi1ww2z<9K9N12eKKpIf*C=PmTk}#bs3&83nLIl zAdEm5fiMDL1i}b}5eOp?Mj(tp7=bVXzp@Az_-)ZRVBUWi9_jb-+i$L~F97}=@EO1z z@2{_4B|hNS0G|Q;KHx4~l#HiO31fB8IIyEHcGc(`BtHFi{}2DYzJ50;=(M%I`kj;X zS5Y4So=m@eQhodm9<~+)T@CP_02I^l!QYR}$M=27oQo%}^vuN%y%e2|AO4-*&&4M% z_szyLmH1>femEOHG#yV&$M->hIv$h1tG)#D7vZP#_fv8irZ56w1i}b}5eOp?Mj(tp z7=bVXVFbbmgc11o5xA+ptA0a6USrWWt(0~sfQ4U1Vmmec0)9uPv|r}LE! z_7#E^&x03IbB^%0_Y&x#@8Kh{zCQ$r_CzbLPgR`I~n)&-``J6ZQO6h z55%F~H;8T$`IPAIe-JF#>=9<1bnoq-A3+m-Mi4-wNd@%VUc;ClF~IA)1I}Ut5Rk^U z-Nv2!iM>54E&9hh{2bl?07~AG5=Zy5^E;{1eVKiKFb&Dhl(D6R{Kcakjv{;iW*YTH z5ZTZCh~^FUBPzpvWHJPCjPF5&$0ynSDu#^AFHOvG#yHoK{E5A3JV zDNEcO9XRL_GZZt!_}@6gpd($%=hHaJVNHxD8+m=QqvW>IYJf>s z+il+Qr z)Yw%_A@y1&?inXHj9RtgiG_tnkIz=@s+0GR*9)zxBhqSgqakioRO@ajAu}2^EQ{{T zvOUkfqz;3KX60$e@`d9rH#%=Ty=;4Fzt%`M>Yi_x&>EMT2-#9IU7`~v$+6UtBS~*G zy;Aosbgl6~ITr#pCw2G*K$d_%84$mZJMn`#kPu6TNU!H1SxKy<- zIEiGfR$E2x){{pHZhZx4vq@~^V+tIRpy?2V8U*7u(ERG?1WD|25ujFIULrHwX(A`J zGAT9k)mp1cNWGDFeNtGeDTV4v14yw(YS0HVuCUcQ36^RVo zc!j2e0OKCKV!lifvI|s5akc3I;E`G;2NKpBbdT_k8r(BFMv-X~4r#ZkysoxVY-r7f z=M)_urTA3ae6?6@HOtDW^iNfjh>o(dE?n&NyhK%Om$OXKZ&Q_ayp`p$3UgaN4tb-? z_xQ5wR84(aY_gw5&SO#lT%we7mYUf_A3*7^|U27Al_hrih7gU45#3RxiN+(&+(cV7!t{3!}jdjRCP3&xASEuNl*RM5!_)= zfb(uzI)Pr#(y>mn$?o50#&Q4qX^Nr!dIkIZqY=C-243N`-)| zIbO+0+SO_j4-by8xjq`W=+#?pq2iX%oBc9q2=W(_4G)3H`*jZvJsQ*Kx%A6P$Mak? zagiFaTM^8~`I%qlz^^uwwR*v+PSL1{F*NC{I(cDxrMw&#`E(r(TckmfWi`4L>a8UV zwO!+>1jCOiFxyd8F%kg!pOlmSsOQB_P6(08p&+Z!MnD7ezj9*VqS4$OZ}eqx~^M4+Ft*4^Lxcs z>n;&FDI`?~p9^~p(cCzobF+uP@;J0&JonY`ZZ=I;=EuDF}OQ}DUmZhl-$ zCNiBYiJM}ey?*W#n)vmT*UjDhA+gmu(8S4CK5yEsk69(Y=ME+lzY6c$lD}Kf_uau{ z3R=5uPNu*_c#C8TUR8Gs&GxQAkk7jXK|b#)1o^jjGc;wkPv3TnO}U!v=Fx-KBi>){ z=3;Js3qI*>rBCZrtOho^HU7q}Jzs6G;>(gxSac0=I;m8)_$>vo>$D(M{ThE$(?BVS3`I+wbp*)lh7UucZT+Vvv zRQC9sm76^!tYZr&rn3vyiH9C~WbU+eIy=2EXLY`8{wah3BrAv9vJ=1-< zomBOLCUDf_>498@T_GC zk!oJ5`Suc^k0lX7%o-IYXIc%BaxqCsWvAzpSTczeraP&!-7Je#;gSnu1$|FRmN7T0 z)ZH$^g3NQOHW`SNoO7gnXVn)e8IqJ&moZ5>Wvht!oMV*>uwY7AsMVdaU>xr3S|yLN z>hOgu)u;kd&T!8nm9N)o*lq*QS!$JFXS*c_d_^`|OK`A3SKMNqW%kmN=PWZtQ#-~H z9Y(8l6yEmbUuwYDuOQLLimt8a02}|$ga6M*aD*k@&h$wTeYhf;c|DSm82?|3grqhy zevX+#vzwn_PnGR?o^V4mxO}$5wog~OA5=dswvU+^DUZ>d2q~ukCR6G@*`D7_GvJdd z+b?SSMQyLfY3)S&*r3#SO?$*_&-0TPwLOm?Tz}SMcn;2J&zWhS$6VF+30+vQ{#=I= z5c19TJl}au+w(p*mmj?Ui?F3O<$4O97Y%}m6nwL@A0-uH1xTlTLfa>_y-mW7q}grG z=Ye(F^E~T?A*I6m^K1|-|FX6pW`#sXVF?9-`b;yV_ZyYZ@#A@0kG7{h($2(o%=;rC zo%TGxn@lK;Z?U3=9Dip22@slt>*i|D1Nr~01ofF_NblQ$4tt(2o=bs=#CnR_pqc-7 z5K!B5`8==W|7UYmw;%OCN^HmNcpW@aVSAo`-lT~S66+~y!=C;8BLtoH?Rn~9Wx>zs zt?d6fV9)c8ecJw3<+HzcfKXky{``JFr0uz$tgpktr1&;4;%W6ZpY0E}ISOHWhW`aN z*#95y CaO<%E diff --git a/resources/museum/first_object_file_2021_06_29 b/resources/museum/first_object_file_2021_06_29 deleted file mode 100644 index 0f83cc4d34ff0ce3c89c3307a62e5e6dd488e209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2400 zcmbW2&1(};5WweU`;mUQZR$r`D;mLGDsEa3L`55`Rg_di(R%Pull0XF^TqB)S}!7q z=Ys!%M~~v6cmDy8{uQEl5j^P3?#yQMe7!iZJM(@sZ)V=dCa+dYw=+tCh=S|T8wmx- z5BBV0WELTZkp~VAK5u&yXWm3K9;=+1caIJ_?&S2G`)Or1r>2GgG9HjooN2j^yF3fv zq`{T3t78P=F+KxPvTW2zCbG@f2?U7;lY^ppkx)yK^kZCQvr+e?6jM@(AW(sO|AVx;MWR)_H|2(s&?y* zEr9jaaw$HtKDatm1@=3FTe}+ZU~;Q8x?kRy47&6qXQGR@UkO}X9uC*=dZW6+wte= zwc4Tf?%aQLAqXqA=Y3I)dP_6VJDb}+X0-eWc$hq_RKW}OnxyHgk3aTg4gX=h$2sYH zC@FS$^A7~DHowjZW=`^LaDd!59{v;i03EjZ?|1@zpJ_2; z@1Zk&&m{H>U#2`ypuQ2<|0lC=e&?$!VX=sUEKxXUz zJ0Gg_N&OGwWA;zK7qwiFIuAPeg;zD0(fI>st`TqrD`Hmp~ diff --git a/serene-repl/CMakeLists.txt b/serene-repl/CMakeLists.txt deleted file mode 100644 index 5188e37..0000000 --- a/serene-repl/CMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -add_executable(serene-repl serene-repl.cpp) -add_executable(Serene::Repl ALIAS serene-repl) - -set_target_properties(serene-repl PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -if(SERENE_ENABLE_TIDY) - set_target_properties(serene-repl PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if (CPP_20_SUPPORT) - target_compile_features(serene-repl PRIVATE cxx_std_20) -else() - target_compile_features(serene-repl PRIVATE cxx_std_17) -endif() - - -target_link_libraries(serene-repl - PRIVATE - Serene::lib -) - -target_compile_options(serene-repl - PRIVATE - $<$:-fsanitize=address> - $<$:-static-libsan> - ) - -target_link_options(serene-repl - PRIVATE - $<$:-fsanitize=address> - $<$:-static-libsan> - ) - -target_include_directories(serene-repl PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(serene-repl PRIVATE ${INCLUDE_DIR}) - -install(TARGETS serene-repl - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - -# if(SERENE_BUILD_TESTING) -# message("Build the test binary") -# add_subdirectory(tests) -# endif() diff --git a/serene-repl/serene-repl.cpp b/serene-repl/serene-repl.cpp deleted file mode 100644 index fc8bd35..0000000 --- a/serene-repl/serene-repl.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/diagnostics.h" -#include "serene/linenoise.h" -#include "serene/serene.h" - -#include -#include -#include - -using namespace serene; -namespace cl = llvm::cl; - -static std::string banner = - llvm::formatv("\nSerene Compiler Version {0}" - "\nCopyright (C) 2019-2023 " - "Sameer Rahmani \n" - "Serene comes with ABSOLUTELY NO WARRANTY;\n" - "This is free software, and you are welcome\n" - "to redistribute it under certain conditions; \n" - "for details take a look at the LICENSE file.\n", - SERENE_VERSION); - -static std::string art = "\n"; - -// TODO: Change the default value to be OS agnostic -static cl::opt - historyFile("h", cl::desc("The absolute path to the history file to use."), - cl::value_desc("filename"), cl::init("~/.serene-repl.history")); - -int main(int argc, char *argv[]) { - initCompiler(); - registerSereneCLOptions(); - - cl::ParseCommandLineOptions(argc, argv, banner); - - llvm::outs() << banner << art; - - serene::Options opts; - opts.JITLazy = true; - - auto ctx = makeSereneContext(opts); - - applySereneCLOptions(*ctx); - - // Enable the multi-line mode - linenoise::SetMultiLine(true); - - // Set max length of the history - linenoise::SetHistoryMaxLen(4); - - // Load history - linenoise::LoadHistory(historyFile.c_str()); - - // TODO: Read the optimization as an input and as part of the global - // public arguments like -l - ctx->setOperationPhase(CompilationPhase::NoOptimization); - - while (true) { - // Read line - std::string line; - std::string result; - std::string prompt = ctx->jit->getActiveNS().name + "> "; - - auto quit = linenoise::Readline(prompt.c_str(), line); - - if (quit) { - break; - } - - auto maybeAst = serene::read(*ctx, line); - - if (!maybeAst) { - auto err = maybeAst.takeError(); - serene::throwErrors(*ctx, err); - continue; - } - - auto x = serene::eval(*ctx, *maybeAst); - - if (!x) { - auto err = x.takeError(); - serene::throwErrors(*ctx, err); - continue; - } - - serene::print(*ctx, *maybeAst, result); - llvm::outs() << result << "\n"; - - // Add text to history - linenoise::AddHistory(line.c_str()); - } - - // Save history - linenoise::SaveHistory(historyFile.c_str()); -} diff --git a/serene-repl/serene/linenoise.h b/serene-repl/serene/linenoise.h deleted file mode 100644 index 04e254c..0000000 --- a/serene-repl/serene/linenoise.h +++ /dev/null @@ -1,2606 +0,0 @@ -/* -*- C++ -*- - * linenoise.h -- Multi-platfrom C++ header-only linenoise library. - * - * All credits and commendations have to go to the authors of the - * following excellent libraries. - * - * - linenoise.h and linenose.c (https://github.com/antirez/linenoise) - * - ANSI.c (https://github.com/adoxa/ansicon) - * - Win32_ANSI.h and Win32_ANSI.c (https://github.com/MSOpenTech/redis) - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2015 yhirose - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* linenoise.h -- guerrilla line editing library against the idea that a - * line editing lib needs to be 20,000 lines of C code. - * - * See linenoise.c for more information. - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2010, Salvatore Sanfilippo - * Copyright (c) 2010, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * ANSI.c - ANSI escape sequence console driver. - * - * Copyright (C) 2005-2014 Jason Hood - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the author be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * Jason Hood - * jadoxa@yahoo.com.au - */ - -/* - * Win32_ANSI.h and Win32_ANSI.c - * - * Derived from ANSI.c by Jason Hood, from his ansicon project - * (https://github.com/adoxa/ansicon), with modifications. - * - * Copyright (c), Microsoft Open Technologies, Inc. - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef LINENOISE_HPP -#define LINENOISE_HPP - -#ifndef _WIN32 -#include - -#include -#include -#else -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#include -#ifndef STDIN_FILENO -#define STDIN_FILENO (_fileno(stdin)) -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif -#define isatty _isatty -#define write win32_write -#define read _read -#pragma warning(push) -#pragma warning(disable : 4996) -#endif -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace linenoise { - -typedef std::function &)> - CompletionCallback; - -#ifdef _WIN32 - -namespace ansi { - -#define lenof(array) (sizeof(array) / sizeof(*(array))) - -typedef struct { - BYTE foreground; // ANSI base color (0 to 7; add 30) - BYTE background; // ANSI base color (0 to 7; add 40) - BYTE bold; // console FOREGROUND_INTENSITY bit - BYTE underline; // console BACKGROUND_INTENSITY bit - BYTE rvideo; // swap foreground/bold & background/underline - BYTE concealed; // set foreground/bold to background/underline - BYTE reverse; // swap console foreground & background attributes -} GRM, *PGRM; // Graphic Rendition Mode - -inline bool is_digit(char c) { return '0' <= c && c <= '9'; } - -// ========== Global variables and constants - -HANDLE hConOut; // handle to CONOUT$ - -const char ESC = '\x1B'; // ESCape character -const char BEL = '\x07'; -const char SO = '\x0E'; // Shift Out -const char SI = '\x0F'; // Shift In - -const int MAX_ARG = 16; // max number of args in an escape sequence -int state; // automata state -WCHAR prefix; // escape sequence prefix ( '[', ']' or '(' ); -WCHAR prefix2; // secondary prefix ( '?' or '>' ); -WCHAR suffix; // escape sequence suffix -int es_argc; // escape sequence args count -int es_argv[MAX_ARG]; // escape sequence args -WCHAR Pt_arg[MAX_PATH * 2]; // text parameter for Operating System Command -int Pt_len; -BOOL shifted; - -// DEC Special Graphics Character Set from -// http://vt100.net/docs/vt220-rm/table2-4.html -// Some of these may not look right, depending on the font and code page (in -// particular, the Control Pictures probably won't work at all). -const WCHAR G1[] = { - ' ', // _ - blank - L'\x2666', // ` - Black Diamond Suit - L'\x2592', // a - Medium Shade - L'\x2409', // b - HT - L'\x240c', // c - FF - L'\x240d', // d - CR - L'\x240a', // e - LF - L'\x00b0', // f - Degree Sign - L'\x00b1', // g - Plus-Minus Sign - L'\x2424', // h - NL - L'\x240b', // i - VT - L'\x2518', // j - Box Drawings Light Up And Left - L'\x2510', // k - Box Drawings Light Down And Left - L'\x250c', // l - Box Drawings Light Down And Right - L'\x2514', // m - Box Drawings Light Up And Right - L'\x253c', // n - Box Drawings Light Vertical And Horizontal - L'\x00af', // o - SCAN 1 - Macron - L'\x25ac', // p - SCAN 3 - Black Rectangle - L'\x2500', // q - SCAN 5 - Box Drawings Light Horizontal - L'_', // r - SCAN 7 - Low Line - L'_', // s - SCAN 9 - Low Line - L'\x251c', // t - Box Drawings Light Vertical And Right - L'\x2524', // u - Box Drawings Light Vertical And Left - L'\x2534', // v - Box Drawings Light Up And Horizontal - L'\x252c', // w - Box Drawings Light Down And Horizontal - L'\x2502', // x - Box Drawings Light Vertical - L'\x2264', // y - Less-Than Or Equal To - L'\x2265', // z - Greater-Than Or Equal To - L'\x03c0', // { - Greek Small Letter Pi - L'\x2260', // | - Not Equal To - L'\x00a3', // } - Pound Sign - L'\x00b7', // ~ - Middle Dot -}; - -#define FIRST_G1 '_' -#define LAST_G1 '~' - -// color constants - -#define FOREGROUND_BLACK 0 -#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE - -#define BACKGROUND_BLACK 0 -#define BACKGROUND_WHITE BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE - -const BYTE foregroundcolor[8] = { - FOREGROUND_BLACK, // black foreground - FOREGROUND_RED, // red foreground - FOREGROUND_GREEN, // green foreground - FOREGROUND_RED | FOREGROUND_GREEN, // yellow foreground - FOREGROUND_BLUE, // blue foreground - FOREGROUND_BLUE | FOREGROUND_RED, // magenta foreground - FOREGROUND_BLUE | FOREGROUND_GREEN, // cyan foreground - FOREGROUND_WHITE // white foreground -}; - -const BYTE backgroundcolor[8] = { - BACKGROUND_BLACK, // black background - BACKGROUND_RED, // red background - BACKGROUND_GREEN, // green background - BACKGROUND_RED | BACKGROUND_GREEN, // yellow background - BACKGROUND_BLUE, // blue background - BACKGROUND_BLUE | BACKGROUND_RED, // magenta background - BACKGROUND_BLUE | BACKGROUND_GREEN, // cyan background - BACKGROUND_WHITE, // white background -}; - -const BYTE attr2ansi[8] = // map console attribute to ANSI number - { - 0, // black - 4, // blue - 2, // green - 6, // cyan - 1, // red - 5, // magenta - 3, // yellow - 7 // white -}; - -GRM grm; - -// saved cursor position -COORD SavePos; - -// ========== Print Buffer functions - -#define BUFFER_SIZE 2048 - -int nCharInBuffer; -WCHAR ChBuffer[BUFFER_SIZE]; - -//----------------------------------------------------------------------------- -// FlushBuffer() -// Writes the buffer to the console and empties it. -//----------------------------------------------------------------------------- - -inline void FlushBuffer(void) { - DWORD nWritten; - if (nCharInBuffer <= 0) - return; - WriteConsoleW(hConOut, ChBuffer, nCharInBuffer, &nWritten, NULL); - nCharInBuffer = 0; -} - -//----------------------------------------------------------------------------- -// PushBuffer( WCHAR c ) -// Adds a character in the buffer. -//----------------------------------------------------------------------------- - -inline void PushBuffer(WCHAR c) { - if (shifted && c >= FIRST_G1 && c <= LAST_G1) - c = G1[c - FIRST_G1]; - ChBuffer[nCharInBuffer] = c; - if (++nCharInBuffer == BUFFER_SIZE) - FlushBuffer(); -} - -//----------------------------------------------------------------------------- -// SendSequence( LPCWSTR seq ) -// Send the string to the input buffer. -//----------------------------------------------------------------------------- - -inline void SendSequence(LPCWSTR seq) { - DWORD out; - INPUT_RECORD in; - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - - in.EventType = KEY_EVENT; - in.Event.KeyEvent.bKeyDown = TRUE; - in.Event.KeyEvent.wRepeatCount = 1; - in.Event.KeyEvent.wVirtualKeyCode = 0; - in.Event.KeyEvent.wVirtualScanCode = 0; - in.Event.KeyEvent.dwControlKeyState = 0; - for (; *seq; ++seq) { - in.Event.KeyEvent.uChar.UnicodeChar = *seq; - WriteConsoleInput(hStdIn, &in, 1, &out); - } -} - -// ========== Print functions - -//----------------------------------------------------------------------------- -// InterpretEscSeq() -// Interprets the last escape sequence scanned by ParseAndPrintANSIString -// prefix escape sequence prefix -// es_argc escape sequence args count -// es_argv[] escape sequence args array -// suffix escape sequence suffix -// -// for instance, with \e[33;45;1m we have -// prefix = '[', -// es_argc = 3, es_argv[0] = 33, es_argv[1] = 45, es_argv[2] = 1 -// suffix = 'm' -//----------------------------------------------------------------------------- - -inline void InterpretEscSeq(void) { - int i; - WORD attribut; - CONSOLE_SCREEN_BUFFER_INFO Info; - CONSOLE_CURSOR_INFO CursInfo; - DWORD len, NumberOfCharsWritten; - COORD Pos; - SMALL_RECT Rect; - CHAR_INFO CharInfo; - - if (prefix == '[') { - if (prefix2 == '?' && (suffix == 'h' || suffix == 'l')) { - if (es_argc == 1 && es_argv[0] == 25) { - GetConsoleCursorInfo(hConOut, &CursInfo); - CursInfo.bVisible = (suffix == 'h'); - SetConsoleCursorInfo(hConOut, &CursInfo); - return; - } - } - // Ignore any other \e[? or \e[> sequences. - if (prefix2 != 0) - return; - - GetConsoleScreenBufferInfo(hConOut, &Info); - switch (suffix) { - case 'm': - if (es_argc == 0) - es_argv[es_argc++] = 0; - for (i = 0; i < es_argc; i++) { - if (30 <= es_argv[i] && es_argv[i] <= 37) - grm.foreground = es_argv[i] - 30; - else if (40 <= es_argv[i] && es_argv[i] <= 47) - grm.background = es_argv[i] - 40; - else - switch (es_argv[i]) { - case 0: - case 39: - case 49: { - WCHAR def[4]; - int a; - *def = '7'; - def[1] = '\0'; - GetEnvironmentVariableW(L"ANSICON_DEF", def, lenof(def)); - a = wcstol(def, NULL, 16); - grm.reverse = FALSE; - if (a < 0) { - grm.reverse = TRUE; - a = -a; - } - if (es_argv[i] != 49) - grm.foreground = attr2ansi[a & 7]; - if (es_argv[i] != 39) - grm.background = attr2ansi[(a >> 4) & 7]; - if (es_argv[i] == 0) { - if (es_argc == 1) { - grm.bold = a & FOREGROUND_INTENSITY; - grm.underline = a & BACKGROUND_INTENSITY; - } else { - grm.bold = 0; - grm.underline = 0; - } - grm.rvideo = 0; - grm.concealed = 0; - } - } break; - - case 1: - grm.bold = FOREGROUND_INTENSITY; - break; - case 5: // blink - case 4: - grm.underline = BACKGROUND_INTENSITY; - break; - case 7: - grm.rvideo = 1; - break; - case 8: - grm.concealed = 1; - break; - case 21: // oops, this actually turns on double underline - case 22: - grm.bold = 0; - break; - case 25: - case 24: - grm.underline = 0; - break; - case 27: - grm.rvideo = 0; - break; - case 28: - grm.concealed = 0; - break; - } - } - if (grm.concealed) { - if (grm.rvideo) { - attribut = - foregroundcolor[grm.foreground] | backgroundcolor[grm.foreground]; - if (grm.bold) - attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } else { - attribut = - foregroundcolor[grm.background] | backgroundcolor[grm.background]; - if (grm.underline) - attribut |= FOREGROUND_INTENSITY | BACKGROUND_INTENSITY; - } - } else if (grm.rvideo) { - attribut = - foregroundcolor[grm.background] | backgroundcolor[grm.foreground]; - if (grm.bold) - attribut |= BACKGROUND_INTENSITY; - if (grm.underline) - attribut |= FOREGROUND_INTENSITY; - } else - attribut = foregroundcolor[grm.foreground] | grm.bold | - backgroundcolor[grm.background] | grm.underline; - if (grm.reverse) - attribut = ((attribut >> 4) & 15) | ((attribut & 15) << 4); - SetConsoleTextAttribute(hConOut, attribut); - return; - - case 'J': - if (es_argc == 0) - es_argv[es_argc++] = 0; // ESC[J == ESC[0J - if (es_argc != 1) - return; - switch (es_argv[0]) { - case 0: // ESC[0J erase from cursor to end of display - len = (Info.dwSize.Y - Info.dwCursorPosition.Y - 1) * Info.dwSize.X + - Info.dwSize.X - Info.dwCursorPosition.X - 1; - FillConsoleOutputCharacter(hConOut, ' ', len, Info.dwCursorPosition, - &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, - Info.dwCursorPosition, - &NumberOfCharsWritten); - return; - - case 1: // ESC[1J erase from start to cursor. - Pos.X = 0; - Pos.Y = 0; - len = Info.dwCursorPosition.Y * Info.dwSize.X + - Info.dwCursorPosition.X + 1; - FillConsoleOutputCharacter(hConOut, ' ', len, Pos, - &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, Pos, - &NumberOfCharsWritten); - return; - - case 2: // ESC[2J Clear screen and home cursor - Pos.X = 0; - Pos.Y = 0; - len = Info.dwSize.X * Info.dwSize.Y; - FillConsoleOutputCharacter(hConOut, ' ', len, Pos, - &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, Pos, - &NumberOfCharsWritten); - SetConsoleCursorPosition(hConOut, Pos); - return; - - default: - return; - } - - case 'K': - if (es_argc == 0) - es_argv[es_argc++] = 0; // ESC[K == ESC[0K - if (es_argc != 1) - return; - switch (es_argv[0]) { - case 0: // ESC[0K Clear to end of line - len = Info.dwSize.X - Info.dwCursorPosition.X + 1; - FillConsoleOutputCharacter(hConOut, ' ', len, Info.dwCursorPosition, - &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, len, - Info.dwCursorPosition, - &NumberOfCharsWritten); - return; - - case 1: // ESC[1K Clear from start of line to cursor - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y; - FillConsoleOutputCharacter(hConOut, ' ', Info.dwCursorPosition.X + 1, - Pos, &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, - Info.dwCursorPosition.X + 1, Pos, - &NumberOfCharsWritten); - return; - - case 2: // ESC[2K Clear whole line. - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y; - FillConsoleOutputCharacter(hConOut, ' ', Info.dwSize.X, Pos, - &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, Info.dwSize.X, - Pos, &NumberOfCharsWritten); - return; - - default: - return; - } - - case 'X': // ESC[#X Erase # characters. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[X == ESC[1X - if (es_argc != 1) - return; - FillConsoleOutputCharacter(hConOut, ' ', es_argv[0], - Info.dwCursorPosition, &NumberOfCharsWritten); - FillConsoleOutputAttribute(hConOut, Info.wAttributes, es_argv[0], - Info.dwCursorPosition, &NumberOfCharsWritten); - return; - - case 'L': // ESC[#L Insert # blank lines. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[L == ESC[1L - if (es_argc != 1) - return; - Rect.Left = 0; - Rect.Top = Info.dwCursorPosition.Y; - Rect.Right = Info.dwSize.X - 1; - Rect.Bottom = Info.dwSize.Y - 1; - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y + es_argv[0]; - CharInfo.Char.UnicodeChar = ' '; - CharInfo.Attributes = Info.wAttributes; - ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo); - return; - - case 'M': // ESC[#M Delete # lines. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[M == ESC[1M - if (es_argc != 1) - return; - if (es_argv[0] > Info.dwSize.Y - Info.dwCursorPosition.Y) - es_argv[0] = Info.dwSize.Y - Info.dwCursorPosition.Y; - Rect.Left = 0; - Rect.Top = Info.dwCursorPosition.Y + es_argv[0]; - Rect.Right = Info.dwSize.X - 1; - Rect.Bottom = Info.dwSize.Y - 1; - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y; - CharInfo.Char.UnicodeChar = ' '; - CharInfo.Attributes = Info.wAttributes; - ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo); - return; - - case 'P': // ESC[#P Delete # characters. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[P == ESC[1P - if (es_argc != 1) - return; - if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1) - es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X; - Rect.Left = Info.dwCursorPosition.X + es_argv[0]; - Rect.Top = Info.dwCursorPosition.Y; - Rect.Right = Info.dwSize.X - 1; - Rect.Bottom = Info.dwCursorPosition.Y; - CharInfo.Char.UnicodeChar = ' '; - CharInfo.Attributes = Info.wAttributes; - ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Info.dwCursorPosition, - &CharInfo); - return; - - case '@': // ESC[#@ Insert # blank characters. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[@ == ESC[1@ - if (es_argc != 1) - return; - if (Info.dwCursorPosition.X + es_argv[0] > Info.dwSize.X - 1) - es_argv[0] = Info.dwSize.X - Info.dwCursorPosition.X; - Rect.Left = Info.dwCursorPosition.X; - Rect.Top = Info.dwCursorPosition.Y; - Rect.Right = Info.dwSize.X - 1 - es_argv[0]; - Rect.Bottom = Info.dwCursorPosition.Y; - Pos.X = Info.dwCursorPosition.X + es_argv[0]; - Pos.Y = Info.dwCursorPosition.Y; - CharInfo.Char.UnicodeChar = ' '; - CharInfo.Attributes = Info.wAttributes; - ScrollConsoleScreenBuffer(hConOut, &Rect, NULL, Pos, &CharInfo); - return; - - case 'k': // ESC[#k - case 'A': // ESC[#A Moves cursor up # lines - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[A == ESC[1A - if (es_argc != 1) - return; - Pos.Y = Info.dwCursorPosition.Y - es_argv[0]; - if (Pos.Y < 0) - Pos.Y = 0; - Pos.X = Info.dwCursorPosition.X; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'e': // ESC[#e - case 'B': // ESC[#B Moves cursor down # lines - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[B == ESC[1B - if (es_argc != 1) - return; - Pos.Y = Info.dwCursorPosition.Y + es_argv[0]; - if (Pos.Y >= Info.dwSize.Y) - Pos.Y = Info.dwSize.Y - 1; - Pos.X = Info.dwCursorPosition.X; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'a': // ESC[#a - case 'C': // ESC[#C Moves cursor forward # spaces - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[C == ESC[1C - if (es_argc != 1) - return; - Pos.X = Info.dwCursorPosition.X + es_argv[0]; - if (Pos.X >= Info.dwSize.X) - Pos.X = Info.dwSize.X - 1; - Pos.Y = Info.dwCursorPosition.Y; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'j': // ESC[#j - case 'D': // ESC[#D Moves cursor back # spaces - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[D == ESC[1D - if (es_argc != 1) - return; - Pos.X = Info.dwCursorPosition.X - es_argv[0]; - if (Pos.X < 0) - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'E': // ESC[#E Moves cursor down # lines, column 1. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[E == ESC[1E - if (es_argc != 1) - return; - Pos.Y = Info.dwCursorPosition.Y + es_argv[0]; - if (Pos.Y >= Info.dwSize.Y) - Pos.Y = Info.dwSize.Y - 1; - Pos.X = 0; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'F': // ESC[#F Moves cursor up # lines, column 1. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[F == ESC[1F - if (es_argc != 1) - return; - Pos.Y = Info.dwCursorPosition.Y - es_argv[0]; - if (Pos.Y < 0) - Pos.Y = 0; - Pos.X = 0; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case '`': // ESC[#` - case 'G': // ESC[#G Moves cursor column # in current row. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[G == ESC[1G - if (es_argc != 1) - return; - Pos.X = es_argv[0] - 1; - if (Pos.X >= Info.dwSize.X) - Pos.X = Info.dwSize.X - 1; - if (Pos.X < 0) - Pos.X = 0; - Pos.Y = Info.dwCursorPosition.Y; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'd': // ESC[#d Moves cursor row #, current column. - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[d == ESC[1d - if (es_argc != 1) - return; - Pos.Y = es_argv[0] - 1; - if (Pos.Y < 0) - Pos.Y = 0; - if (Pos.Y >= Info.dwSize.Y) - Pos.Y = Info.dwSize.Y - 1; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 'f': // ESC[#;#f - case 'H': // ESC[#;#H Moves cursor to line #, column # - if (es_argc == 0) - es_argv[es_argc++] = 1; // ESC[H == ESC[1;1H - if (es_argc == 1) - es_argv[es_argc++] = 1; // ESC[#H == ESC[#;1H - if (es_argc > 2) - return; - Pos.X = es_argv[1] - 1; - if (Pos.X < 0) - Pos.X = 0; - if (Pos.X >= Info.dwSize.X) - Pos.X = Info.dwSize.X - 1; - Pos.Y = es_argv[0] - 1; - if (Pos.Y < 0) - Pos.Y = 0; - if (Pos.Y >= Info.dwSize.Y) - Pos.Y = Info.dwSize.Y - 1; - SetConsoleCursorPosition(hConOut, Pos); - return; - - case 's': // ESC[s Saves cursor position for recall later - if (es_argc != 0) - return; - SavePos = Info.dwCursorPosition; - return; - - case 'u': // ESC[u Return to saved cursor position - if (es_argc != 0) - return; - SetConsoleCursorPosition(hConOut, SavePos); - return; - - case 'n': // ESC[#n Device status report - if (es_argc != 1) - return; // ESC[n == ESC[0n -> ignored - switch (es_argv[0]) { - case 5: // ESC[5n Report status - SendSequence(L"\33[0n"); // "OK" - return; - - case 6: // ESC[6n Report cursor position - { - WCHAR buf[32]; - swprintf(buf, 32, L"\33[%d;%dR", Info.dwCursorPosition.Y + 1, - Info.dwCursorPosition.X + 1); - SendSequence(buf); - } - return; - - default: - return; - } - - case 't': // ESC[#t Window manipulation - if (es_argc != 1) - return; - if (es_argv[0] == 21) // ESC[21t Report xterm window's title - { - WCHAR buf[MAX_PATH * 2]; - len = GetConsoleTitleW(buf + 3, lenof(buf) - 3 - 2); - // Too bad if it's too big or fails. - buf[0] = ESC; - buf[1] = ']'; - buf[2] = 'l'; - buf[3 + len] = ESC; - buf[3 + len + 1] = '\\'; - buf[3 + len + 2] = '\0'; - SendSequence(buf); - } - return; - - default: - return; - } - } else // (prefix == ']') - { - // Ignore any \e]? or \e]> sequences. - if (prefix2 != 0) - return; - - if (es_argc == 1 && es_argv[0] == 0) // ESC]0;titleST - { - SetConsoleTitleW(Pt_arg); - } - } -} - -//----------------------------------------------------------------------------- -// ParseAndPrintANSIString(hDev, lpBuffer, nNumberOfBytesToWrite) -// Parses the string lpBuffer, interprets the escapes sequences and prints the -// characters in the device hDev (console). -// The lexer is a three states automata. -// If the number of arguments es_argc > MAX_ARG, only the MAX_ARG-1 firsts and -// the last arguments are processed (no es_argv[] overflow). -//----------------------------------------------------------------------------- - -inline BOOL ParseAndPrintANSIString(HANDLE hDev, LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten) { - DWORD i; - LPCSTR s; - - if (hDev != hConOut) // reinit if device has changed - { - hConOut = hDev; - state = 1; - shifted = FALSE; - } - for (i = nNumberOfBytesToWrite, s = (LPCSTR)lpBuffer; i > 0; i--, s++) { - if (state == 1) { - if (*s == ESC) - state = 2; - else if (*s == SO) - shifted = TRUE; - else if (*s == SI) - shifted = FALSE; - else - PushBuffer(*s); - } else if (state == 2) { - if (*s == ESC) - ; // \e\e...\e == \e - else if ((*s == '[') || (*s == ']')) { - FlushBuffer(); - prefix = *s; - prefix2 = 0; - state = 3; - Pt_len = 0; - *Pt_arg = '\0'; - } else if (*s == ')' || *s == '(') - state = 6; - else - state = 1; - } else if (state == 3) { - if (is_digit(*s)) { - es_argc = 0; - es_argv[0] = *s - '0'; - state = 4; - } else if (*s == ';') { - es_argc = 1; - es_argv[0] = 0; - es_argv[1] = 0; - state = 4; - } else if (*s == '?' || *s == '>') { - prefix2 = *s; - } else { - es_argc = 0; - suffix = *s; - InterpretEscSeq(); - state = 1; - } - } else if (state == 4) { - if (is_digit(*s)) { - es_argv[es_argc] = 10 * es_argv[es_argc] + (*s - '0'); - } else if (*s == ';') { - if (es_argc < MAX_ARG - 1) - es_argc++; - es_argv[es_argc] = 0; - if (prefix == ']') - state = 5; - } else { - es_argc++; - suffix = *s; - InterpretEscSeq(); - state = 1; - } - } else if (state == 5) { - if (*s == BEL) { - Pt_arg[Pt_len] = '\0'; - InterpretEscSeq(); - state = 1; - } else if (*s == '\\' && Pt_len > 0 && Pt_arg[Pt_len - 1] == ESC) { - Pt_arg[--Pt_len] = '\0'; - InterpretEscSeq(); - state = 1; - } else if (Pt_len < lenof(Pt_arg) - 1) - Pt_arg[Pt_len++] = *s; - } else if (state == 6) { - // Ignore it (ESC ) 0 is implicit; nothing else is supported). - state = 1; - } - } - FlushBuffer(); - if (lpNumberOfBytesWritten != NULL) - *lpNumberOfBytesWritten = nNumberOfBytesToWrite - i; - return (i == 0); -} - -} // namespace ansi - -HANDLE hOut; -HANDLE hIn; -DWORD consolemodeIn = 0; - -inline int win32read(int *c) { - DWORD foo; - INPUT_RECORD b; - KEY_EVENT_RECORD e; - BOOL altgr; - - while (1) { - if (!ReadConsoleInput(hIn, &b, 1, &foo)) - return 0; - if (!foo) - return 0; - - if (b.EventType == KEY_EVENT && b.Event.KeyEvent.bKeyDown) { - - e = b.Event.KeyEvent; - *c = b.Event.KeyEvent.uChar.AsciiChar; - - altgr = e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED); - - if (e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) && - !altgr) { - - /* Ctrl+Key */ - switch (*c) { - case 'D': - *c = 4; - return 1; - case 'C': - *c = 3; - return 1; - case 'H': - *c = 8; - return 1; - case 'T': - *c = 20; - return 1; - case 'B': /* ctrl-b, left_arrow */ - *c = 2; - return 1; - case 'F': /* ctrl-f right_arrow*/ - *c = 6; - return 1; - case 'P': /* ctrl-p up_arrow*/ - *c = 16; - return 1; - case 'N': /* ctrl-n down_arrow*/ - *c = 14; - return 1; - case 'U': /* Ctrl+u, delete the whole line. */ - *c = 21; - return 1; - case 'K': /* Ctrl+k, delete from current to end of line. */ - *c = 11; - return 1; - case 'A': /* Ctrl+a, go to the start of the line */ - *c = 1; - return 1; - case 'E': /* ctrl+e, go to the end of the line */ - *c = 5; - return 1; - } - - /* Other Ctrl+KEYs ignored */ - } else { - - switch (e.wVirtualKeyCode) { - - case VK_ESCAPE: /* ignore - send ctrl-c, will return -1 */ - *c = 3; - return 1; - case VK_RETURN: /* enter */ - *c = 13; - return 1; - case VK_LEFT: /* left */ - *c = 2; - return 1; - case VK_RIGHT: /* right */ - *c = 6; - return 1; - case VK_UP: /* up */ - *c = 16; - return 1; - case VK_DOWN: /* down */ - *c = 14; - return 1; - case VK_HOME: - *c = 1; - return 1; - case VK_END: - *c = 5; - return 1; - case VK_BACK: - *c = 8; - return 1; - case VK_DELETE: - *c = 4; /* same as Ctrl+D above */ - return 1; - default: - if (*c) - return 1; - } - } - } - } - - return -1; /* Makes compiler happy */ -} - -inline int win32_write(int fd, const void *buffer, unsigned int count) { - if (fd == _fileno(stdout)) { - DWORD bytesWritten = 0; - if (FALSE != ansi::ParseAndPrintANSIString(GetStdHandle(STD_OUTPUT_HANDLE), - buffer, (DWORD)count, - &bytesWritten)) { - return (int)bytesWritten; - } else { - errno = GetLastError(); - return 0; - } - } else if (fd == _fileno(stderr)) { - DWORD bytesWritten = 0; - if (FALSE != ansi::ParseAndPrintANSIString(GetStdHandle(STD_ERROR_HANDLE), - buffer, (DWORD)count, - &bytesWritten)) { - return (int)bytesWritten; - } else { - errno = GetLastError(); - return 0; - } - } else { - return _write(fd, buffer, count); - } -} -#endif // _WIN32 - -#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 -#define LINENOISE_MAX_LINE 4096 -static const char *unsupported_term[] = {"dumb", "cons25", "emacs", NULL}; -static CompletionCallback completionCallback; - -#ifndef _WIN32 -static struct termios orig_termios; /* In order to restore at exit.*/ -#endif -static bool rawmode = - false; /* For atexit() function to check if restore is needed*/ -static bool mlmode = false; /* Multi line mode. Default is single line. */ -static bool atexit_registered = false; /* Register atexit just 1 time. */ -static size_t history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; -static std::vector history; - -/* The linenoiseState structure represents the state during line editing. - * We pass this state to functions implementing specific editing - * functionalities. */ -struct linenoiseState { - int ifd; /* Terminal stdin file descriptor. */ - int ofd; /* Terminal stdout file descriptor. */ - char *buf; /* Edited line buffer. */ - int buflen; /* Edited line buffer size. */ - std::string prompt; /* Prompt to display. */ - int pos; /* Current cursor position. */ - int oldcolpos; /* Previous refresh cursor column position. */ - int len; /* Current edited line length. */ - int cols; /* Number of columns in terminal. */ - int maxrows; /* Maximum num of rows used so far (multiline mode) */ - int history_index; /* The history index we are currently editing. */ -}; - -enum KEY_ACTION { - KEY_NULL = 0, /* NULL */ - CTRL_A = 1, /* Ctrl+a */ - CTRL_B = 2, /* Ctrl-b */ - CTRL_C = 3, /* Ctrl-c */ - CTRL_D = 4, /* Ctrl-d */ - CTRL_E = 5, /* Ctrl-e */ - CTRL_F = 6, /* Ctrl-f */ - CTRL_H = 8, /* Ctrl-h */ - TAB = 9, /* Tab */ - CTRL_K = 11, /* Ctrl+k */ - CTRL_L = 12, /* Ctrl+l */ - ENTER = 13, /* Enter */ - CTRL_N = 14, /* Ctrl-n */ - CTRL_P = 16, /* Ctrl-p */ - CTRL_T = 20, /* Ctrl-t */ - CTRL_U = 21, /* Ctrl+u */ - CTRL_W = 23, /* Ctrl+w */ - ESC = 27, /* Escape */ - BACKSPACE = 127 /* Backspace */ -}; - -void linenoiseAtExit(void); -bool AddHistory(const char *line); -void refreshLine(struct linenoiseState *l); - -/* ============================ UTF8 utilities ============================== */ - -static unsigned long unicodeWideCharTable[][2] = { - {0x1100, 0x115F}, - {0x2329, 0x232A}, - { - 0x2E80, - 0x2E99, - }, - { - 0x2E9B, - 0x2EF3, - }, - { - 0x2F00, - 0x2FD5, - }, - { - 0x2FF0, - 0x2FFB, - }, - { - 0x3000, - 0x303E, - }, - { - 0x3041, - 0x3096, - }, - { - 0x3099, - 0x30FF, - }, - { - 0x3105, - 0x312D, - }, - { - 0x3131, - 0x318E, - }, - { - 0x3190, - 0x31BA, - }, - { - 0x31C0, - 0x31E3, - }, - { - 0x31F0, - 0x321E, - }, - { - 0x3220, - 0x3247, - }, - { - 0x3250, - 0x4DBF, - }, - { - 0x4E00, - 0xA48C, - }, - { - 0xA490, - 0xA4C6, - }, - { - 0xA960, - 0xA97C, - }, - { - 0xAC00, - 0xD7A3, - }, - { - 0xF900, - 0xFAFF, - }, - { - 0xFE10, - 0xFE19, - }, - { - 0xFE30, - 0xFE52, - }, - { - 0xFE54, - 0xFE66, - }, - { - 0xFE68, - 0xFE6B, - }, - { - 0xFF01, - 0xFFE6, - }, - { - 0x1B000, - 0x1B001, - }, - { - 0x1F200, - 0x1F202, - }, - { - 0x1F210, - 0x1F23A, - }, - { - 0x1F240, - 0x1F248, - }, - { - 0x1F250, - 0x1F251, - }, - { - 0x20000, - 0x3FFFD, - }, -}; - -static int unicodeWideCharTableSize = - sizeof(unicodeWideCharTable) / sizeof(unicodeWideCharTable[0]); - -static int unicodeIsWideChar(unsigned long cp) { - int i; - for (i = 0; i < unicodeWideCharTableSize; i++) { - if (unicodeWideCharTable[i][0] <= cp && cp <= unicodeWideCharTable[i][1]) { - return 1; - } - } - return 0; -} - -static unsigned long unicodeCombiningCharTable[] = { - 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, - 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F, - 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, - 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F, - 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, - 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F, - 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, - 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F, - 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, - 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F, - 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, - 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F, - 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, - 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F, - 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0591, 0x0592, 0x0593, - 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, - 0x059C, 0x059D, 0x059E, 0x059F, 0x05A0, 0x05A1, 0x05A2, 0x05A3, - 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, - 0x05AC, 0x05AD, 0x05AE, 0x05AF, 0x05B0, 0x05B1, 0x05B2, 0x05B3, - 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, - 0x05BC, 0x05BD, 0x05BF, 0x05C1, 0x05C2, 0x05C4, 0x05C5, 0x05C7, - 0x0610, 0x0611, 0x0612, 0x0613, 0x0614, 0x0615, 0x0616, 0x0617, - 0x0618, 0x0619, 0x061A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, - 0x0650, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0657, - 0x0658, 0x0659, 0x065A, 0x065B, 0x065C, 0x065D, 0x065E, 0x065F, - 0x0670, 0x06D6, 0x06D7, 0x06D8, 0x06D9, 0x06DA, 0x06DB, 0x06DC, - 0x06DF, 0x06E0, 0x06E1, 0x06E2, 0x06E3, 0x06E4, 0x06E7, 0x06E8, - 0x06EA, 0x06EB, 0x06EC, 0x06ED, 0x0711, 0x0730, 0x0731, 0x0732, - 0x0733, 0x0734, 0x0735, 0x0736, 0x0737, 0x0738, 0x0739, 0x073A, - 0x073B, 0x073C, 0x073D, 0x073E, 0x073F, 0x0740, 0x0741, 0x0742, - 0x0743, 0x0744, 0x0745, 0x0746, 0x0747, 0x0748, 0x0749, 0x074A, - 0x07A6, 0x07A7, 0x07A8, 0x07A9, 0x07AA, 0x07AB, 0x07AC, 0x07AD, - 0x07AE, 0x07AF, 0x07B0, 0x07EB, 0x07EC, 0x07ED, 0x07EE, 0x07EF, - 0x07F0, 0x07F1, 0x07F2, 0x07F3, 0x0816, 0x0817, 0x0818, 0x0819, - 0x081B, 0x081C, 0x081D, 0x081E, 0x081F, 0x0820, 0x0821, 0x0822, - 0x0823, 0x0825, 0x0826, 0x0827, 0x0829, 0x082A, 0x082B, 0x082C, - 0x082D, 0x0859, 0x085A, 0x085B, 0x08E3, 0x08E4, 0x08E5, 0x08E6, - 0x08E7, 0x08E8, 0x08E9, 0x08EA, 0x08EB, 0x08EC, 0x08ED, 0x08EE, - 0x08EF, 0x08F0, 0x08F1, 0x08F2, 0x08F3, 0x08F4, 0x08F5, 0x08F6, - 0x08F7, 0x08F8, 0x08F9, 0x08FA, 0x08FB, 0x08FC, 0x08FD, 0x08FE, - 0x08FF, 0x0900, 0x0901, 0x0902, 0x093A, 0x093C, 0x0941, 0x0942, - 0x0943, 0x0944, 0x0945, 0x0946, 0x0947, 0x0948, 0x094D, 0x0951, - 0x0952, 0x0953, 0x0954, 0x0955, 0x0956, 0x0957, 0x0962, 0x0963, - 0x0981, 0x09BC, 0x09C1, 0x09C2, 0x09C3, 0x09C4, 0x09CD, 0x09E2, - 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A41, 0x0A42, 0x0A47, 0x0A48, - 0x0A4B, 0x0A4C, 0x0A4D, 0x0A51, 0x0A70, 0x0A71, 0x0A75, 0x0A81, - 0x0A82, 0x0ABC, 0x0AC1, 0x0AC2, 0x0AC3, 0x0AC4, 0x0AC5, 0x0AC7, - 0x0AC8, 0x0ACD, 0x0AE2, 0x0AE3, 0x0B01, 0x0B3C, 0x0B3F, 0x0B41, - 0x0B42, 0x0B43, 0x0B44, 0x0B4D, 0x0B56, 0x0B62, 0x0B63, 0x0B82, - 0x0BC0, 0x0BCD, 0x0C00, 0x0C3E, 0x0C3F, 0x0C40, 0x0C46, 0x0C47, - 0x0C48, 0x0C4A, 0x0C4B, 0x0C4C, 0x0C4D, 0x0C55, 0x0C56, 0x0C62, - 0x0C63, 0x0C81, 0x0CBC, 0x0CBF, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, - 0x0CE3, 0x0D01, 0x0D41, 0x0D42, 0x0D43, 0x0D44, 0x0D4D, 0x0D62, - 0x0D63, 0x0DCA, 0x0DD2, 0x0DD3, 0x0DD4, 0x0DD6, 0x0E31, 0x0E34, - 0x0E35, 0x0E36, 0x0E37, 0x0E38, 0x0E39, 0x0E3A, 0x0E47, 0x0E48, - 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0EB1, 0x0EB4, - 0x0EB5, 0x0EB6, 0x0EB7, 0x0EB8, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, - 0x0EC9, 0x0ECA, 0x0ECB, 0x0ECC, 0x0ECD, 0x0F18, 0x0F19, 0x0F35, - 0x0F37, 0x0F39, 0x0F71, 0x0F72, 0x0F73, 0x0F74, 0x0F75, 0x0F76, - 0x0F77, 0x0F78, 0x0F79, 0x0F7A, 0x0F7B, 0x0F7C, 0x0F7D, 0x0F7E, - 0x0F80, 0x0F81, 0x0F82, 0x0F83, 0x0F84, 0x0F86, 0x0F87, 0x0F8D, - 0x0F8E, 0x0F8F, 0x0F90, 0x0F91, 0x0F92, 0x0F93, 0x0F94, 0x0F95, - 0x0F96, 0x0F97, 0x0F99, 0x0F9A, 0x0F9B, 0x0F9C, 0x0F9D, 0x0F9E, - 0x0F9F, 0x0FA0, 0x0FA1, 0x0FA2, 0x0FA3, 0x0FA4, 0x0FA5, 0x0FA6, - 0x0FA7, 0x0FA8, 0x0FA9, 0x0FAA, 0x0FAB, 0x0FAC, 0x0FAD, 0x0FAE, - 0x0FAF, 0x0FB0, 0x0FB1, 0x0FB2, 0x0FB3, 0x0FB4, 0x0FB5, 0x0FB6, - 0x0FB7, 0x0FB8, 0x0FB9, 0x0FBA, 0x0FBB, 0x0FBC, 0x0FC6, 0x102D, - 0x102E, 0x102F, 0x1030, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, - 0x1037, 0x1039, 0x103A, 0x103D, 0x103E, 0x1058, 0x1059, 0x105E, - 0x105F, 0x1060, 0x1071, 0x1072, 0x1073, 0x1074, 0x1082, 0x1085, - 0x1086, 0x108D, 0x109D, 0x135D, 0x135E, 0x135F, 0x1712, 0x1713, - 0x1714, 0x1732, 0x1733, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, - 0x17B4, 0x17B5, 0x17B7, 0x17B8, 0x17B9, 0x17BA, 0x17BB, 0x17BC, - 0x17BD, 0x17C6, 0x17C9, 0x17CA, 0x17CB, 0x17CC, 0x17CD, 0x17CE, - 0x17CF, 0x17D0, 0x17D1, 0x17D2, 0x17D3, 0x17DD, 0x180B, 0x180C, - 0x180D, 0x18A9, 0x1920, 0x1921, 0x1922, 0x1927, 0x1928, 0x1932, - 0x1939, 0x193A, 0x193B, 0x1A17, 0x1A18, 0x1A1B, 0x1A56, 0x1A58, - 0x1A59, 0x1A5A, 0x1A5B, 0x1A5C, 0x1A5D, 0x1A5E, 0x1A60, 0x1A62, - 0x1A65, 0x1A66, 0x1A67, 0x1A68, 0x1A69, 0x1A6A, 0x1A6B, 0x1A6C, - 0x1A73, 0x1A74, 0x1A75, 0x1A76, 0x1A77, 0x1A78, 0x1A79, 0x1A7A, - 0x1A7B, 0x1A7C, 0x1A7F, 0x1AB0, 0x1AB1, 0x1AB2, 0x1AB3, 0x1AB4, - 0x1AB5, 0x1AB6, 0x1AB7, 0x1AB8, 0x1AB9, 0x1ABA, 0x1ABB, 0x1ABC, - 0x1ABD, 0x1B00, 0x1B01, 0x1B02, 0x1B03, 0x1B34, 0x1B36, 0x1B37, - 0x1B38, 0x1B39, 0x1B3A, 0x1B3C, 0x1B42, 0x1B6B, 0x1B6C, 0x1B6D, - 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73, 0x1B80, 0x1B81, - 0x1BA2, 0x1BA3, 0x1BA4, 0x1BA5, 0x1BA8, 0x1BA9, 0x1BAB, 0x1BAC, - 0x1BAD, 0x1BE6, 0x1BE8, 0x1BE9, 0x1BED, 0x1BEF, 0x1BF0, 0x1BF1, - 0x1C2C, 0x1C2D, 0x1C2E, 0x1C2F, 0x1C30, 0x1C31, 0x1C32, 0x1C33, - 0x1C36, 0x1C37, 0x1CD0, 0x1CD1, 0x1CD2, 0x1CD4, 0x1CD5, 0x1CD6, - 0x1CD7, 0x1CD8, 0x1CD9, 0x1CDA, 0x1CDB, 0x1CDC, 0x1CDD, 0x1CDE, - 0x1CDF, 0x1CE0, 0x1CE2, 0x1CE3, 0x1CE4, 0x1CE5, 0x1CE6, 0x1CE7, - 0x1CE8, 0x1CED, 0x1CF4, 0x1CF8, 0x1CF9, 0x1DC0, 0x1DC1, 0x1DC2, - 0x1DC3, 0x1DC4, 0x1DC5, 0x1DC6, 0x1DC7, 0x1DC8, 0x1DC9, 0x1DCA, - 0x1DCB, 0x1DCC, 0x1DCD, 0x1DCE, 0x1DCF, 0x1DD0, 0x1DD1, 0x1DD2, - 0x1DD3, 0x1DD4, 0x1DD5, 0x1DD6, 0x1DD7, 0x1DD8, 0x1DD9, 0x1DDA, - 0x1DDB, 0x1DDC, 0x1DDD, 0x1DDE, 0x1DDF, 0x1DE0, 0x1DE1, 0x1DE2, - 0x1DE3, 0x1DE4, 0x1DE5, 0x1DE6, 0x1DE7, 0x1DE8, 0x1DE9, 0x1DEA, - 0x1DEB, 0x1DEC, 0x1DED, 0x1DEE, 0x1DEF, 0x1DF0, 0x1DF1, 0x1DF2, - 0x1DF3, 0x1DF4, 0x1DF5, 0x1DFC, 0x1DFD, 0x1DFE, 0x1DFF, 0x20D0, - 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, - 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20E1, 0x20E5, 0x20E6, 0x20E7, - 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF, - 0x20F0, 0x2CEF, 0x2CF0, 0x2CF1, 0x2D7F, 0x2DE0, 0x2DE1, 0x2DE2, - 0x2DE3, 0x2DE4, 0x2DE5, 0x2DE6, 0x2DE7, 0x2DE8, 0x2DE9, 0x2DEA, - 0x2DEB, 0x2DEC, 0x2DED, 0x2DEE, 0x2DEF, 0x2DF0, 0x2DF1, 0x2DF2, - 0x2DF3, 0x2DF4, 0x2DF5, 0x2DF6, 0x2DF7, 0x2DF8, 0x2DF9, 0x2DFA, - 0x2DFB, 0x2DFC, 0x2DFD, 0x2DFE, 0x2DFF, 0x302A, 0x302B, 0x302C, - 0x302D, 0x3099, 0x309A, 0xA66F, 0xA674, 0xA675, 0xA676, 0xA677, - 0xA678, 0xA679, 0xA67A, 0xA67B, 0xA67C, 0xA67D, 0xA69E, 0xA69F, - 0xA6F0, 0xA6F1, 0xA802, 0xA806, 0xA80B, 0xA825, 0xA826, 0xA8C4, - 0xA8E0, 0xA8E1, 0xA8E2, 0xA8E3, 0xA8E4, 0xA8E5, 0xA8E6, 0xA8E7, - 0xA8E8, 0xA8E9, 0xA8EA, 0xA8EB, 0xA8EC, 0xA8ED, 0xA8EE, 0xA8EF, - 0xA8F0, 0xA8F1, 0xA926, 0xA927, 0xA928, 0xA929, 0xA92A, 0xA92B, - 0xA92C, 0xA92D, 0xA947, 0xA948, 0xA949, 0xA94A, 0xA94B, 0xA94C, - 0xA94D, 0xA94E, 0xA94F, 0xA950, 0xA951, 0xA980, 0xA981, 0xA982, - 0xA9B3, 0xA9B6, 0xA9B7, 0xA9B8, 0xA9B9, 0xA9BC, 0xA9E5, 0xAA29, - 0xAA2A, 0xAA2B, 0xAA2C, 0xAA2D, 0xAA2E, 0xAA31, 0xAA32, 0xAA35, - 0xAA36, 0xAA43, 0xAA4C, 0xAA7C, 0xAAB0, 0xAAB2, 0xAAB3, 0xAAB4, - 0xAAB7, 0xAAB8, 0xAABE, 0xAABF, 0xAAC1, 0xAAEC, 0xAAED, 0xAAF6, - 0xABE5, 0xABE8, 0xABED, 0xFB1E, 0xFE00, 0xFE01, 0xFE02, 0xFE03, - 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, - 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F, 0xFE20, 0xFE21, 0xFE22, 0xFE23, - 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, - 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F, 0x101FD, 0x102E0, 0x10376, 0x10377, - 0x10378, 0x10379, 0x1037A, 0x10A01, 0x10A02, 0x10A03, 0x10A05, 0x10A06, - 0x10A0C, 0x10A0D, 0x10A0E, 0x10A0F, 0x10A38, 0x10A39, 0x10A3A, 0x10A3F, - 0x10AE5, 0x10AE6, 0x11001, 0x11038, 0x11039, 0x1103A, 0x1103B, 0x1103C, - 0x1103D, 0x1103E, 0x1103F, 0x11040, 0x11041, 0x11042, 0x11043, 0x11044, - 0x11045, 0x11046, 0x1107F, 0x11080, 0x11081, 0x110B3, 0x110B4, 0x110B5, - 0x110B6, 0x110B9, 0x110BA, 0x11100, 0x11101, 0x11102, 0x11127, 0x11128, - 0x11129, 0x1112A, 0x1112B, 0x1112D, 0x1112E, 0x1112F, 0x11130, 0x11131, - 0x11132, 0x11133, 0x11134, 0x11173, 0x11180, 0x11181, 0x111B6, 0x111B7, - 0x111B8, 0x111B9, 0x111BA, 0x111BB, 0x111BC, 0x111BD, 0x111BE, 0x111CA, - 0x111CB, 0x111CC, 0x1122F, 0x11230, 0x11231, 0x11234, 0x11236, 0x11237, - 0x112DF, 0x112E3, 0x112E4, 0x112E5, 0x112E6, 0x112E7, 0x112E8, 0x112E9, - 0x112EA, 0x11300, 0x11301, 0x1133C, 0x11340, 0x11366, 0x11367, 0x11368, - 0x11369, 0x1136A, 0x1136B, 0x1136C, 0x11370, 0x11371, 0x11372, 0x11373, - 0x11374, 0x114B3, 0x114B4, 0x114B5, 0x114B6, 0x114B7, 0x114B8, 0x114BA, - 0x114BF, 0x114C0, 0x114C2, 0x114C3, 0x115B2, 0x115B3, 0x115B4, 0x115B5, - 0x115BC, 0x115BD, 0x115BF, 0x115C0, 0x115DC, 0x115DD, 0x11633, 0x11634, - 0x11635, 0x11636, 0x11637, 0x11638, 0x11639, 0x1163A, 0x1163D, 0x1163F, - 0x11640, 0x116AB, 0x116AD, 0x116B0, 0x116B1, 0x116B2, 0x116B3, 0x116B4, - 0x116B5, 0x116B7, 0x1171D, 0x1171E, 0x1171F, 0x11722, 0x11723, 0x11724, - 0x11725, 0x11727, 0x11728, 0x11729, 0x1172A, 0x1172B, 0x16AF0, 0x16AF1, - 0x16AF2, 0x16AF3, 0x16AF4, 0x16B30, 0x16B31, 0x16B32, 0x16B33, 0x16B34, - 0x16B35, 0x16B36, 0x16F8F, 0x16F90, 0x16F91, 0x16F92, 0x1BC9D, 0x1BC9E, - 0x1D167, 0x1D168, 0x1D169, 0x1D17B, 0x1D17C, 0x1D17D, 0x1D17E, 0x1D17F, - 0x1D180, 0x1D181, 0x1D182, 0x1D185, 0x1D186, 0x1D187, 0x1D188, 0x1D189, - 0x1D18A, 0x1D18B, 0x1D1AA, 0x1D1AB, 0x1D1AC, 0x1D1AD, 0x1D242, 0x1D243, - 0x1D244, 0x1DA00, 0x1DA01, 0x1DA02, 0x1DA03, 0x1DA04, 0x1DA05, 0x1DA06, - 0x1DA07, 0x1DA08, 0x1DA09, 0x1DA0A, 0x1DA0B, 0x1DA0C, 0x1DA0D, 0x1DA0E, - 0x1DA0F, 0x1DA10, 0x1DA11, 0x1DA12, 0x1DA13, 0x1DA14, 0x1DA15, 0x1DA16, - 0x1DA17, 0x1DA18, 0x1DA19, 0x1DA1A, 0x1DA1B, 0x1DA1C, 0x1DA1D, 0x1DA1E, - 0x1DA1F, 0x1DA20, 0x1DA21, 0x1DA22, 0x1DA23, 0x1DA24, 0x1DA25, 0x1DA26, - 0x1DA27, 0x1DA28, 0x1DA29, 0x1DA2A, 0x1DA2B, 0x1DA2C, 0x1DA2D, 0x1DA2E, - 0x1DA2F, 0x1DA30, 0x1DA31, 0x1DA32, 0x1DA33, 0x1DA34, 0x1DA35, 0x1DA36, - 0x1DA3B, 0x1DA3C, 0x1DA3D, 0x1DA3E, 0x1DA3F, 0x1DA40, 0x1DA41, 0x1DA42, - 0x1DA43, 0x1DA44, 0x1DA45, 0x1DA46, 0x1DA47, 0x1DA48, 0x1DA49, 0x1DA4A, - 0x1DA4B, 0x1DA4C, 0x1DA4D, 0x1DA4E, 0x1DA4F, 0x1DA50, 0x1DA51, 0x1DA52, - 0x1DA53, 0x1DA54, 0x1DA55, 0x1DA56, 0x1DA57, 0x1DA58, 0x1DA59, 0x1DA5A, - 0x1DA5B, 0x1DA5C, 0x1DA5D, 0x1DA5E, 0x1DA5F, 0x1DA60, 0x1DA61, 0x1DA62, - 0x1DA63, 0x1DA64, 0x1DA65, 0x1DA66, 0x1DA67, 0x1DA68, 0x1DA69, 0x1DA6A, - 0x1DA6B, 0x1DA6C, 0x1DA75, 0x1DA84, 0x1DA9B, 0x1DA9C, 0x1DA9D, 0x1DA9E, - 0x1DA9F, 0x1DAA1, 0x1DAA2, 0x1DAA3, 0x1DAA4, 0x1DAA5, 0x1DAA6, 0x1DAA7, - 0x1DAA8, 0x1DAA9, 0x1DAAA, 0x1DAAB, 0x1DAAC, 0x1DAAD, 0x1DAAE, 0x1DAAF, - 0x1E8D0, 0x1E8D1, 0x1E8D2, 0x1E8D3, 0x1E8D4, 0x1E8D5, 0x1E8D6, 0xE0100, - 0xE0101, 0xE0102, 0xE0103, 0xE0104, 0xE0105, 0xE0106, 0xE0107, 0xE0108, - 0xE0109, 0xE010A, 0xE010B, 0xE010C, 0xE010D, 0xE010E, 0xE010F, 0xE0110, - 0xE0111, 0xE0112, 0xE0113, 0xE0114, 0xE0115, 0xE0116, 0xE0117, 0xE0118, - 0xE0119, 0xE011A, 0xE011B, 0xE011C, 0xE011D, 0xE011E, 0xE011F, 0xE0120, - 0xE0121, 0xE0122, 0xE0123, 0xE0124, 0xE0125, 0xE0126, 0xE0127, 0xE0128, - 0xE0129, 0xE012A, 0xE012B, 0xE012C, 0xE012D, 0xE012E, 0xE012F, 0xE0130, - 0xE0131, 0xE0132, 0xE0133, 0xE0134, 0xE0135, 0xE0136, 0xE0137, 0xE0138, - 0xE0139, 0xE013A, 0xE013B, 0xE013C, 0xE013D, 0xE013E, 0xE013F, 0xE0140, - 0xE0141, 0xE0142, 0xE0143, 0xE0144, 0xE0145, 0xE0146, 0xE0147, 0xE0148, - 0xE0149, 0xE014A, 0xE014B, 0xE014C, 0xE014D, 0xE014E, 0xE014F, 0xE0150, - 0xE0151, 0xE0152, 0xE0153, 0xE0154, 0xE0155, 0xE0156, 0xE0157, 0xE0158, - 0xE0159, 0xE015A, 0xE015B, 0xE015C, 0xE015D, 0xE015E, 0xE015F, 0xE0160, - 0xE0161, 0xE0162, 0xE0163, 0xE0164, 0xE0165, 0xE0166, 0xE0167, 0xE0168, - 0xE0169, 0xE016A, 0xE016B, 0xE016C, 0xE016D, 0xE016E, 0xE016F, 0xE0170, - 0xE0171, 0xE0172, 0xE0173, 0xE0174, 0xE0175, 0xE0176, 0xE0177, 0xE0178, - 0xE0179, 0xE017A, 0xE017B, 0xE017C, 0xE017D, 0xE017E, 0xE017F, 0xE0180, - 0xE0181, 0xE0182, 0xE0183, 0xE0184, 0xE0185, 0xE0186, 0xE0187, 0xE0188, - 0xE0189, 0xE018A, 0xE018B, 0xE018C, 0xE018D, 0xE018E, 0xE018F, 0xE0190, - 0xE0191, 0xE0192, 0xE0193, 0xE0194, 0xE0195, 0xE0196, 0xE0197, 0xE0198, - 0xE0199, 0xE019A, 0xE019B, 0xE019C, 0xE019D, 0xE019E, 0xE019F, 0xE01A0, - 0xE01A1, 0xE01A2, 0xE01A3, 0xE01A4, 0xE01A5, 0xE01A6, 0xE01A7, 0xE01A8, - 0xE01A9, 0xE01AA, 0xE01AB, 0xE01AC, 0xE01AD, 0xE01AE, 0xE01AF, 0xE01B0, - 0xE01B1, 0xE01B2, 0xE01B3, 0xE01B4, 0xE01B5, 0xE01B6, 0xE01B7, 0xE01B8, - 0xE01B9, 0xE01BA, 0xE01BB, 0xE01BC, 0xE01BD, 0xE01BE, 0xE01BF, 0xE01C0, - 0xE01C1, 0xE01C2, 0xE01C3, 0xE01C4, 0xE01C5, 0xE01C6, 0xE01C7, 0xE01C8, - 0xE01C9, 0xE01CA, 0xE01CB, 0xE01CC, 0xE01CD, 0xE01CE, 0xE01CF, 0xE01D0, - 0xE01D1, 0xE01D2, 0xE01D3, 0xE01D4, 0xE01D5, 0xE01D6, 0xE01D7, 0xE01D8, - 0xE01D9, 0xE01DA, 0xE01DB, 0xE01DC, 0xE01DD, 0xE01DE, 0xE01DF, 0xE01E0, - 0xE01E1, 0xE01E2, 0xE01E3, 0xE01E4, 0xE01E5, 0xE01E6, 0xE01E7, 0xE01E8, - 0xE01E9, 0xE01EA, 0xE01EB, 0xE01EC, 0xE01ED, 0xE01EE, 0xE01EF, -}; - -static int unicodeCombiningCharTableSize = - sizeof(unicodeCombiningCharTable) / sizeof(unicodeCombiningCharTable[0]); - -inline int unicodeIsCombiningChar(unsigned long cp) { - int i; - for (i = 0; i < unicodeCombiningCharTableSize; i++) { - if (unicodeCombiningCharTable[i] == cp) { - return 1; - } - } - return 0; -} - -/* Get length of previous UTF8 character - */ -inline int unicodePrevUTF8CharLen(char *buf, int pos) { - int end = pos--; - while (pos >= 0 && ((unsigned char)buf[pos] & 0xC0) == 0x80) { - pos--; - } - return end - pos; -} - -/* Get length of previous UTF8 character - */ -inline int unicodeUTF8CharLen(char *buf, int buf_len, int pos) { - if (pos == buf_len) { - return 0; - } - unsigned char ch = buf[pos]; - if (ch < 0x80) { - return 1; - } else if (ch < 0xE0) { - return 2; - } else if (ch < 0xF0) { - return 3; - } else { - return 4; - } -} - -/* Convert UTF8 to Unicode code point - */ -inline int unicodeUTF8CharToCodePoint(const char *buf, int len, int *cp) { - if (len) { - unsigned char byte = buf[0]; - if ((byte & 0x80) == 0) { - *cp = byte; - return 1; - } else if ((byte & 0xE0) == 0xC0) { - if (len >= 2) { - *cp = (((unsigned long)(buf[0] & 0x1F)) << 6) | - ((unsigned long)(buf[1] & 0x3F)); - return 2; - } - } else if ((byte & 0xF0) == 0xE0) { - if (len >= 3) { - *cp = (((unsigned long)(buf[0] & 0x0F)) << 12) | - (((unsigned long)(buf[1] & 0x3F)) << 6) | - ((unsigned long)(buf[2] & 0x3F)); - return 3; - } - } else if ((byte & 0xF8) == 0xF0) { - if (len >= 4) { - *cp = (((unsigned long)(buf[0] & 0x07)) << 18) | - (((unsigned long)(buf[1] & 0x3F)) << 12) | - (((unsigned long)(buf[2] & 0x3F)) << 6) | - ((unsigned long)(buf[3] & 0x3F)); - return 4; - } - } - } - return 0; -} - -/* Get length of grapheme - */ -inline int unicodeGraphemeLen(char *buf, int buf_len, int pos) { - if (pos == buf_len) { - return 0; - } - int beg = pos; - pos += unicodeUTF8CharLen(buf, buf_len, pos); - while (pos < buf_len) { - int len = unicodeUTF8CharLen(buf, buf_len, pos); - int cp = 0; - unicodeUTF8CharToCodePoint(buf + pos, len, &cp); - if (!unicodeIsCombiningChar(cp)) { - return pos - beg; - } - pos += len; - } - return pos - beg; -} - -/* Get length of previous grapheme - */ -inline int unicodePrevGraphemeLen(char *buf, int pos) { - if (pos == 0) { - return 0; - } - int end = pos; - while (pos > 0) { - int len = unicodePrevUTF8CharLen(buf, pos); - pos -= len; - int cp = 0; - unicodeUTF8CharToCodePoint(buf + pos, len, &cp); - if (!unicodeIsCombiningChar(cp)) { - return end - pos; - } - } - return 0; -} - -inline int isAnsiEscape(const char *buf, int buf_len, int *len) { - if (buf_len > 2 && !memcmp("\033[", buf, 2)) { - int off = 2; - while (off < buf_len) { - switch (buf[off++]) { - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'J': - case 'K': - case 'S': - case 'T': - case 'f': - case 'm': - *len = off; - return 1; - } - } - } - return 0; -} - -/* Get column position for the single line mode. - */ -inline int unicodeColumnPos(const char *buf, int buf_len) { - int ret = 0; - - int off = 0; - while (off < buf_len) { - int len; - if (isAnsiEscape(buf + off, buf_len - off, &len)) { - off += len; - continue; - } - - int cp = 0; - len = unicodeUTF8CharToCodePoint(buf + off, buf_len - off, &cp); - - if (!unicodeIsCombiningChar(cp)) { - ret += unicodeIsWideChar(cp) ? 2 : 1; - } - - off += len; - } - - return ret; -} - -/* Get column position for the multi line mode. - */ -inline int unicodeColumnPosForMultiLine(char *buf, int buf_len, int pos, - int cols, int ini_pos) { - int ret = 0; - int colwid = ini_pos; - - int off = 0; - while (off < buf_len) { - int cp = 0; - int len = unicodeUTF8CharToCodePoint(buf + off, buf_len - off, &cp); - - int wid = 0; - if (!unicodeIsCombiningChar(cp)) { - wid = unicodeIsWideChar(cp) ? 2 : 1; - } - - int dif = (int)(colwid + wid) - (int)cols; - if (dif > 0) { - ret += dif; - colwid = wid; - } else if (dif == 0) { - colwid = 0; - } else { - colwid += wid; - } - - if (off >= pos) { - break; - } - - off += len; - ret += wid; - } - - return ret; -} - -/* Read UTF8 character from file. - */ -inline int unicodeReadUTF8Char(int fd, char *buf, int *cp) { - int nread = read(fd, &buf[0], 1); - - if (nread <= 0) { - return nread; - } - - unsigned char byte = buf[0]; - - if ((byte & 0x80) == 0) { - ; - } else if ((byte & 0xE0) == 0xC0) { - nread = read(fd, &buf[1], 1); - if (nread <= 0) { - return nread; - } - } else if ((byte & 0xF0) == 0xE0) { - nread = read(fd, &buf[1], 2); - if (nread <= 0) { - return nread; - } - } else if ((byte & 0xF8) == 0xF0) { - nread = read(fd, &buf[1], 3); - if (nread <= 0) { - return nread; - } - } else { - return -1; - } - - return unicodeUTF8CharToCodePoint(buf, 4, cp); -} - -/* ======================= Low level terminal handling ====================== */ - -/* Set if to use or not the multi line mode. */ -inline void SetMultiLine(bool ml) { mlmode = ml; } - -/* Return true if the terminal name is in the list of terminals we know are - * not able to understand basic escape sequences. */ -inline bool isUnsupportedTerm(void) { -#ifndef _WIN32 - char *term = getenv("TERM"); - int j; - - if (term == NULL) - return false; - for (j = 0; unsupported_term[j]; j++) - if (!strcasecmp(term, unsupported_term[j])) - return true; -#endif - return false; -} - -/* Raw mode: 1960 magic shit. */ -inline bool enableRawMode(int fd) { -#ifndef _WIN32 - struct termios raw; - - if (!isatty(STDIN_FILENO)) - goto fatal; - if (!atexit_registered) { - atexit(linenoiseAtExit); - atexit_registered = true; - } - if (tcgetattr(fd, &orig_termios) == -1) - goto fatal; - - raw = orig_termios; /* modify the original mode */ - /* input modes: no break, no CR to NL, no parity check, no strip char, - * no start/stop output control. */ - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - /* output modes - disable post processing */ - // NOTE: Multithreaded issue #20 - // (https://github.com/yhirose/cpp-linenoise/issues/20) raw.c_oflag &= - // ~(OPOST); - /* control modes - set 8 bit chars */ - raw.c_cflag |= (CS8); - /* local modes - echoing off, canonical off, no extended functions, - * no signal chars (^Z,^C) */ - raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); - /* control chars - set return condition: min number of bytes and timer. - * We want read to return every single byte, without timeout. */ - raw.c_cc[VMIN] = 1; - raw.c_cc[VTIME] = 0; /* 1 byte, no timer */ - - /* put terminal in raw mode after flushing */ - if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) - goto fatal; - rawmode = true; -#else - if (!atexit_registered) { - /* Cleanup them at exit */ - atexit(linenoiseAtExit); - atexit_registered = true; - - /* Init windows console handles only once */ - hOut = GetStdHandle(STD_OUTPUT_HANDLE); - if (hOut == INVALID_HANDLE_VALUE) - goto fatal; - } - - DWORD consolemodeOut; - if (!GetConsoleMode(hOut, &consolemodeOut)) { - CloseHandle(hOut); - errno = ENOTTY; - return false; - }; - - hIn = GetStdHandle(STD_INPUT_HANDLE); - if (hIn == INVALID_HANDLE_VALUE) { - CloseHandle(hOut); - errno = ENOTTY; - return false; - } - - GetConsoleMode(hIn, &consolemodeIn); - /* Enable raw mode */ - SetConsoleMode(hIn, consolemodeIn & ~ENABLE_PROCESSED_INPUT); - - rawmode = true; -#endif - return true; - -fatal: - errno = ENOTTY; - return false; -} - -inline void disableRawMode(int fd) { -#ifdef _WIN32 - if (consolemodeIn) { - SetConsoleMode(hIn, consolemodeIn); - consolemodeIn = 0; - } - rawmode = false; -#else - /* Don't even check the return value as it's too late. */ - if (rawmode && tcsetattr(fd, TCSAFLUSH, &orig_termios) != -1) - rawmode = false; -#endif -} - -/* Use the ESC [6n escape sequence to query the horizontal cursor position - * and return it. On error -1 is returned, on success the position of the - * cursor. */ -inline int getCursorPosition(int ifd, int ofd) { - char buf[32]; - int cols, rows; - unsigned int i = 0; - - /* Report cursor location */ - if (write(ofd, "\x1b[6n", 4) != 4) - return -1; - - /* Read the response: ESC [ rows ; cols R */ - while (i < sizeof(buf) - 1) { - if (read(ifd, buf + i, 1) != 1) - break; - if (buf[i] == 'R') - break; - i++; - } - buf[i] = '\0'; - - /* Parse it. */ - if (buf[0] != ESC || buf[1] != '[') - return -1; - if (sscanf(buf + 2, "%d;%d", &rows, &cols) != 2) - return -1; - return cols; -} - -/* Try to get the number of columns in the current terminal, or assume 80 - * if it fails. */ -inline int getColumns(int ifd, int ofd) { -#ifdef _WIN32 - CONSOLE_SCREEN_BUFFER_INFO b; - - if (!GetConsoleScreenBufferInfo(hOut, &b)) - return 80; - return b.srWindow.Right - b.srWindow.Left; -#else - struct winsize ws; - - if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) { - /* ioctl() failed. Try to query the terminal itself. */ - int start, cols; - - /* Get the initial position so we can restore it later. */ - start = getCursorPosition(ifd, ofd); - if (start == -1) - goto failed; - - /* Go to right margin and get position. */ - if (write(ofd, "\x1b[999C", 6) != 6) - goto failed; - cols = getCursorPosition(ifd, ofd); - if (cols == -1) - goto failed; - - /* Restore position. */ - if (cols > start) { - char seq[32]; - snprintf(seq, 32, "\x1b[%dD", cols - start); - if (write(ofd, seq, strlen(seq)) == -1) { - /* Can't recover... */ - } - } - return cols; - } else { - return ws.ws_col; - } - -failed: - return 80; -#endif -} - -/* Clear the screen. Used to handle ctrl+l */ -inline void linenoiseClearScreen(void) { - if (write(STDOUT_FILENO, "\x1b[H\x1b[2J", 7) <= 0) { - /* nothing to do, just to avoid warning. */ - } -} - -/* Beep, used for completion when there is nothing to complete or when all - * the choices were already shown. */ -inline void linenoiseBeep(void) { - fprintf(stderr, "\x7"); - fflush(stderr); -} - -/* ============================== Completion ================================ */ - -/* This is an helper function for linenoiseEdit() and is called when the - * user types the key in order to complete the string currently in the - * input. - * - * The state of the editing is encapsulated into the pointed linenoiseState - * structure as described in the structure definition. */ -inline int completeLine(struct linenoiseState *ls, char *cbuf, int *c) { - std::vector lc; - int nread = 0, nwritten; - *c = 0; - - completionCallback(ls->buf, lc); - if (lc.empty()) { - linenoiseBeep(); - } else { - int stop = 0, i = 0; - - while (!stop) { - /* Show completion or original buffer */ - if (i < static_cast(lc.size())) { - struct linenoiseState saved = *ls; - - ls->len = ls->pos = static_cast(lc[i].size()); - ls->buf = &lc[i][0]; - refreshLine(ls); - ls->len = saved.len; - ls->pos = saved.pos; - ls->buf = saved.buf; - } else { - refreshLine(ls); - } - - // nread = read(ls->ifd,&c,1); -#ifdef _WIN32 - nread = win32read(c); - if (nread == 1) { - cbuf[0] = *c; - } -#else - nread = unicodeReadUTF8Char(ls->ifd, cbuf, c); -#endif - if (nread <= 0) { - *c = -1; - return nread; - } - - switch (*c) { - case 9: /* tab */ - i = (i + 1) % (lc.size() + 1); - if (i == static_cast(lc.size())) - linenoiseBeep(); - break; - case 27: /* escape */ - /* Re-show original buffer */ - if (i < static_cast(lc.size())) - refreshLine(ls); - stop = 1; - break; - default: - /* Update buffer and return */ - if (i < static_cast(lc.size())) { - nwritten = snprintf(ls->buf, ls->buflen, "%s", &lc[i][0]); - ls->len = ls->pos = nwritten; - } - stop = 1; - break; - } - } - } - - return nread; -} - -/* Register a callback function to be called for tab-completion. */ -inline void SetCompletionCallback(CompletionCallback fn) { - completionCallback = fn; -} - -/* =========================== Line editing ================================= */ - -/* Single line low level line refresh. - * - * Rewrite the currently edited line accordingly to the buffer content, - * cursor position, and number of columns of the terminal. */ -inline void refreshSingleLine(struct linenoiseState *l) { - char seq[64]; - int pcolwid = - unicodeColumnPos(l->prompt.c_str(), static_cast(l->prompt.length())); - int fd = l->ofd; - char *buf = l->buf; - int len = l->len; - int pos = l->pos; - std::string ab; - - while ((pcolwid + unicodeColumnPos(buf, pos)) >= l->cols) { - int glen = unicodeGraphemeLen(buf, len, 0); - buf += glen; - len -= glen; - pos -= glen; - } - while (pcolwid + unicodeColumnPos(buf, len) > l->cols) { - len -= unicodePrevGraphemeLen(buf, len); - } - - /* Cursor to left edge */ - snprintf(seq, 64, "\r"); - ab += seq; - /* Write the prompt and the current buffer content */ - ab += l->prompt; - ab.append(buf, len); - /* Erase to right */ - snprintf(seq, 64, "\x1b[0K"); - ab += seq; - /* Move cursor to original position. */ - snprintf(seq, 64, "\r\x1b[%dC", (int)(unicodeColumnPos(buf, pos) + pcolwid)); - ab += seq; - if (write(fd, ab.c_str(), static_cast(ab.length())) == -1) { - } /* Can't recover from write error. */ -} - -/* Multi line low level line refresh. - * - * Rewrite the currently edited line accordingly to the buffer content, - * cursor position, and number of columns of the terminal. */ -inline void refreshMultiLine(struct linenoiseState *l) { - char seq[64]; - int pcolwid = - unicodeColumnPos(l->prompt.c_str(), static_cast(l->prompt.length())); - int colpos = - unicodeColumnPosForMultiLine(l->buf, l->len, l->len, l->cols, pcolwid); - int colpos2; /* cursor column position. */ - int rows = (pcolwid + colpos + l->cols - 1) / - l->cols; /* rows used by current buf. */ - int rpos = - (pcolwid + l->oldcolpos + l->cols) / l->cols; /* cursor relative row. */ - int rpos2; /* rpos after refresh. */ - int col; /* colum position, zero-based. */ - int old_rows = (int)l->maxrows; - int fd = l->ofd, j; - std::string ab; - - /* Update maxrows if needed. */ - if (rows > (int)l->maxrows) - l->maxrows = rows; - - /* First step: clear all the lines used before. To do so start by - * going to the last row. */ - if (old_rows - rpos > 0) { - snprintf(seq, 64, "\x1b[%dB", old_rows - rpos); - ab += seq; - } - - /* Now for every row clear it, go up. */ - for (j = 0; j < old_rows - 1; j++) { - snprintf(seq, 64, "\r\x1b[0K\x1b[1A"); - ab += seq; - } - - /* Clean the top line. */ - snprintf(seq, 64, "\r\x1b[0K"); - ab += seq; - - /* Write the prompt and the current buffer content */ - ab += l->prompt; - ab.append(l->buf, l->len); - - /* Get text width to cursor position */ - colpos2 = - unicodeColumnPosForMultiLine(l->buf, l->len, l->pos, l->cols, pcolwid); - - /* If we are at the very end of the screen with our prompt, we need to - * emit a newline and move the prompt to the first column. */ - if (l->pos && l->pos == l->len && (colpos2 + pcolwid) % l->cols == 0) { - ab += "\n"; - snprintf(seq, 64, "\r"); - ab += seq; - rows++; - if (rows > (int)l->maxrows) - l->maxrows = rows; - } - - /* Move cursor to right position. */ - rpos2 = (pcolwid + colpos2 + l->cols) / - l->cols; /* current cursor relative row. */ - - /* Go up till we reach the expected positon. */ - if (rows - rpos2 > 0) { - snprintf(seq, 64, "\x1b[%dA", rows - rpos2); - ab += seq; - } - - /* Set column. */ - col = (pcolwid + colpos2) % l->cols; - if (col) - snprintf(seq, 64, "\r\x1b[%dC", col); - else - snprintf(seq, 64, "\r"); - ab += seq; - - l->oldcolpos = colpos2; - - if (write(fd, ab.c_str(), static_cast(ab.length())) == -1) { - } /* Can't recover from write error. */ -} - -/* Calls the two low level functions refreshSingleLine() or - * refreshMultiLine() according to the selected mode. */ -inline void refreshLine(struct linenoiseState *l) { - if (mlmode) - refreshMultiLine(l); - else - refreshSingleLine(l); -} - -/* Insert the character 'c' at cursor current position. - * - * On error writing to the terminal -1 is returned, otherwise 0. */ -inline int linenoiseEditInsert(struct linenoiseState *l, const char *cbuf, - int clen) { - if (l->len < l->buflen) { - if (l->len == l->pos) { - memcpy(&l->buf[l->pos], cbuf, clen); - l->pos += clen; - l->len += clen; - ; - l->buf[l->len] = '\0'; - if ((!mlmode && unicodeColumnPos(l->prompt.c_str(), - static_cast(l->prompt.length())) + - unicodeColumnPos(l->buf, l->len) < - l->cols) /* || mlmode */) { - /* Avoid a full update of the line in the - * trivial case. */ - if (write(l->ofd, cbuf, clen) == -1) - return -1; - } else { - refreshLine(l); - } - } else { - memmove(l->buf + l->pos + clen, l->buf + l->pos, l->len - l->pos); - memcpy(&l->buf[l->pos], cbuf, clen); - l->pos += clen; - l->len += clen; - l->buf[l->len] = '\0'; - refreshLine(l); - } - } - return 0; -} - -/* Move cursor on the left. */ -inline void linenoiseEditMoveLeft(struct linenoiseState *l) { - if (l->pos > 0) { - l->pos -= unicodePrevGraphemeLen(l->buf, l->pos); - refreshLine(l); - } -} - -/* Move cursor on the right. */ -inline void linenoiseEditMoveRight(struct linenoiseState *l) { - if (l->pos != l->len) { - l->pos += unicodeGraphemeLen(l->buf, l->len, l->pos); - refreshLine(l); - } -} - -/* Move cursor to the start of the line. */ -inline void linenoiseEditMoveHome(struct linenoiseState *l) { - if (l->pos != 0) { - l->pos = 0; - refreshLine(l); - } -} - -/* Move cursor to the end of the line. */ -inline void linenoiseEditMoveEnd(struct linenoiseState *l) { - if (l->pos != l->len) { - l->pos = l->len; - refreshLine(l); - } -} - -/* Substitute the currently edited line with the next or previous history - * entry as specified by 'dir'. */ -#define LINENOISE_HISTORY_NEXT 0 -#define LINENOISE_HISTORY_PREV 1 -inline void linenoiseEditHistoryNext(struct linenoiseState *l, int dir) { - if (history.size() > 1) { - /* Update the current history entry before to - * overwrite it with the next one. */ - history[history.size() - 1 - l->history_index] = l->buf; - /* Show the new entry */ - l->history_index += (dir == LINENOISE_HISTORY_PREV) ? 1 : -1; - if (l->history_index < 0) { - l->history_index = 0; - return; - } else if (l->history_index >= (int)history.size()) { - l->history_index = static_cast(history.size()) - 1; - return; - } - memset(l->buf, 0, l->buflen); - strcpy(l->buf, history[history.size() - 1 - l->history_index].c_str()); - l->len = l->pos = static_cast(strlen(l->buf)); - refreshLine(l); - } -} - -/* Delete the character at the right of the cursor without altering the cursor - * position. Basically this is what happens with the "Delete" keyboard key. */ -inline void linenoiseEditDelete(struct linenoiseState *l) { - if (l->len > 0 && l->pos < l->len) { - int glen = unicodeGraphemeLen(l->buf, l->len, l->pos); - memmove(l->buf + l->pos, l->buf + l->pos + glen, l->len - l->pos - glen); - l->len -= glen; - l->buf[l->len] = '\0'; - refreshLine(l); - } -} - -/* Backspace implementation. */ -inline void linenoiseEditBackspace(struct linenoiseState *l) { - if (l->pos > 0 && l->len > 0) { - int glen = unicodePrevGraphemeLen(l->buf, l->pos); - memmove(l->buf + l->pos - glen, l->buf + l->pos, l->len - l->pos); - l->pos -= glen; - l->len -= glen; - l->buf[l->len] = '\0'; - refreshLine(l); - } -} - -/* Delete the previosu word, maintaining the cursor at the start of the - * current word. */ -inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) { - int old_pos = l->pos; - int diff; - - while (l->pos > 0 && l->buf[l->pos - 1] == ' ') - l->pos--; - while (l->pos > 0 && l->buf[l->pos - 1] != ' ') - l->pos--; - diff = old_pos - l->pos; - memmove(l->buf + l->pos, l->buf + old_pos, l->len - old_pos + 1); - l->len -= diff; - refreshLine(l); -} - -/* This function is the core of the line editing capability of linenoise. - * It expects 'fd' to be already in "raw mode" so that every key pressed - * will be returned ASAP to read(). - * - * The resulting string is put into 'buf' when the user type enter, or - * when ctrl+d is typed. - * - * The function returns the length of the current buffer. */ -inline int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, int buflen, - const char *prompt) { - struct linenoiseState l; - - /* Populate the linenoise state that we pass to functions implementing - * specific editing functionalities. */ - l.ifd = stdin_fd; - l.ofd = stdout_fd; - l.buf = buf; - l.buflen = buflen; - l.prompt = prompt; - l.oldcolpos = l.pos = 0; - l.len = 0; - l.cols = getColumns(stdin_fd, stdout_fd); - l.maxrows = 0; - l.history_index = 0; - - /* Buffer starts empty. */ - l.buf[0] = '\0'; - l.buflen--; /* Make sure there is always space for the nulterm */ - - /* The latest history entry is always our current buffer, that - * initially is just an empty string. */ - AddHistory(""); - - if (write(l.ofd, prompt, static_cast(l.prompt.length())) == -1) - return -1; - while (1) { - int c; - char cbuf[4]; - int nread; - char seq[3]; - -#ifdef _WIN32 - nread = win32read(&c); - if (nread == 1) { - cbuf[0] = c; - } -#else - nread = unicodeReadUTF8Char(l.ifd, cbuf, &c); -#endif - if (nread <= 0) - return (int)l.len; - - /* Only autocomplete when the callback is set. It returns < 0 when - * there was an error reading from fd. Otherwise it will return the - * character that should be handled next. */ - if (c == 9 && completionCallback != NULL) { - nread = completeLine(&l, cbuf, &c); - /* Return on errors */ - if (c < 0) - return l.len; - /* Read next character when 0 */ - if (c == 0) - continue; - } - - switch (c) { - case ENTER: /* enter */ - if (!history.empty()) - history.pop_back(); - if (mlmode) - linenoiseEditMoveEnd(&l); - return (int)l.len; - case CTRL_C: /* ctrl-c */ - errno = EAGAIN; - return -1; - case BACKSPACE: /* backspace */ - case 8: /* ctrl-h */ - linenoiseEditBackspace(&l); - break; - case CTRL_D: /* ctrl-d, remove char at right of cursor, or if the - line is empty, act as end-of-file. */ - if (l.len > 0) { - linenoiseEditDelete(&l); - } else { - history.pop_back(); - return -1; - } - break; - case CTRL_T: /* ctrl-t, swaps current character with previous. */ - if (l.pos > 0 && l.pos < l.len) { - char aux = buf[l.pos - 1]; - buf[l.pos - 1] = buf[l.pos]; - buf[l.pos] = aux; - if (l.pos != l.len - 1) - l.pos++; - refreshLine(&l); - } - break; - case CTRL_B: /* ctrl-b */ - linenoiseEditMoveLeft(&l); - break; - case CTRL_F: /* ctrl-f */ - linenoiseEditMoveRight(&l); - break; - case CTRL_P: /* ctrl-p */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); - break; - case CTRL_N: /* ctrl-n */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); - break; - case ESC: /* escape sequence */ - /* Read the next two bytes representing the escape sequence. - * Use two calls to handle slow terminals returning the two - * chars at different times. */ - if (read(l.ifd, seq, 1) == -1) - break; - if (read(l.ifd, seq + 1, 1) == -1) - break; - - /* ESC [ sequences. */ - if (seq[0] == '[') { - if (seq[1] >= '0' && seq[1] <= '9') { - /* Extended escape, read additional byte. */ - if (read(l.ifd, seq + 2, 1) == -1) - break; - if (seq[2] == '~') { - switch (seq[1]) { - case '3': /* Delete key. */ - linenoiseEditDelete(&l); - break; - } - } - } else { - switch (seq[1]) { - case 'A': /* Up */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_PREV); - break; - case 'B': /* Down */ - linenoiseEditHistoryNext(&l, LINENOISE_HISTORY_NEXT); - break; - case 'C': /* Right */ - linenoiseEditMoveRight(&l); - break; - case 'D': /* Left */ - linenoiseEditMoveLeft(&l); - break; - case 'H': /* Home */ - linenoiseEditMoveHome(&l); - break; - case 'F': /* End*/ - linenoiseEditMoveEnd(&l); - break; - } - } - } - - /* ESC O sequences. */ - else if (seq[0] == 'O') { - switch (seq[1]) { - case 'H': /* Home */ - linenoiseEditMoveHome(&l); - break; - case 'F': /* End*/ - linenoiseEditMoveEnd(&l); - break; - } - } - break; - default: - if (linenoiseEditInsert(&l, cbuf, nread)) - return -1; - break; - case CTRL_U: /* Ctrl+u, delete the whole line. */ - buf[0] = '\0'; - l.pos = l.len = 0; - refreshLine(&l); - break; - case CTRL_K: /* Ctrl+k, delete from current to end of line. */ - buf[l.pos] = '\0'; - l.len = l.pos; - refreshLine(&l); - break; - case CTRL_A: /* Ctrl+a, go to the start of the line */ - linenoiseEditMoveHome(&l); - break; - case CTRL_E: /* ctrl+e, go to the end of the line */ - linenoiseEditMoveEnd(&l); - break; - case CTRL_L: /* ctrl+l, clear screen */ - linenoiseClearScreen(); - refreshLine(&l); - break; - case CTRL_W: /* ctrl+w, delete previous word */ - linenoiseEditDeletePrevWord(&l); - break; - } - } - return l.len; -} - -/* This function calls the line editing function linenoiseEdit() using - * the STDIN file descriptor set in raw mode. */ -inline bool linenoiseRaw(const char *prompt, std::string &line) { - bool quit = false; - - if (!isatty(STDIN_FILENO)) { - /* Not a tty: read from file / pipe. */ - std::getline(std::cin, line); - } else { - /* Interactive editing. */ - if (enableRawMode(STDIN_FILENO) == false) { - return quit; - } - - char buf[LINENOISE_MAX_LINE]; - auto count = linenoiseEdit(STDIN_FILENO, STDOUT_FILENO, buf, - LINENOISE_MAX_LINE, prompt); - if (count == -1) { - quit = true; - } else { - line.assign(buf, count); - } - - disableRawMode(STDIN_FILENO); - printf("\n"); - } - return quit; -} - -/* The high level function that is the main API of the linenoise library. - * This function checks if the terminal has basic capabilities, just checking - * for a blacklist of stupid terminals, and later either calls the line - * editing function or uses dummy fgets() so that you will be able to type - * something even in the most desperate of the conditions. */ -inline bool Readline(const char *prompt, std::string &line) { - if (isUnsupportedTerm()) { - printf("%s", prompt); - fflush(stdout); - std::getline(std::cin, line); - return false; - } else { - return linenoiseRaw(prompt, line); - } -} - -inline std::string Readline(const char *prompt, bool &quit) { - std::string line; - quit = Readline(prompt, line); - return line; -} - -inline std::string Readline(const char *prompt) { - bool quit; // dummy - return Readline(prompt, quit); -} - -/* ================================ History ================================= */ - -/* At exit we'll try to fix the terminal to the initial conditions. */ -inline void linenoiseAtExit(void) { disableRawMode(STDIN_FILENO); } - -/* This is the API call to add a new entry in the linenoise history. - * It uses a fixed array of char pointers that are shifted (memmoved) - * when the history max length is reached in order to remove the older - * entry and make room for the new one, so it is not exactly suitable for huge - * histories, but will work well for a few hundred of entries. - * - * Using a circular buffer is smarter, but a bit more complex to handle. */ -inline bool AddHistory(const char *line) { - if (history_max_len == 0) - return false; - - /* Don't add duplicated lines. */ - if (!history.empty() && history.back() == line) - return false; - - /* If we reached the max length, remove the older line. */ - if (history.size() == history_max_len) { - history.erase(history.begin()); - } - history.push_back(line); - - return true; -} - -/* Set the maximum length for the history. This function can be called even - * if there is already some history, the function will make sure to retain - * just the latest 'len' elements if the new history length value is smaller - * than the amount of items already inside the history. */ -inline bool SetHistoryMaxLen(size_t len) { - if (len < 1) - return false; - history_max_len = len; - if (len < history.size()) { - history.resize(len); - } - return true; -} - -/* Save the history in the specified file. On success *true* is returned - * otherwise *false* is returned. */ -inline bool SaveHistory(const char *path) { - std::ofstream f(path); // TODO: need 'std::ios::binary'? - if (!f) - return false; - for (const auto &h : history) { - f << h << std::endl; - } - return true; -} - -/* Load the history from the specified file. If the file does not exist - * zero is returned and no operation is performed. - * - * If the file exists and the operation succeeded *true* is returned, otherwise - * on error *false* is returned. */ -inline bool LoadHistory(const char *path) { - std::ifstream f(path); - if (!f) - return false; - std::string line; - while (std::getline(f, line)) { - AddHistory(line.c_str()); - } - return true; -} - -inline const std::vector &GetHistory() { return history; } - -} // namespace linenoise - -#ifdef _WIN32 -#undef isatty -#undef write -#undef read -#pragma warning(pop) -#endif - -#endif /* __LINENOISE_HPP */ diff --git a/serene-tblgen/CMakeLists.txt b/serene-tblgen/CMakeLists.txt deleted file mode 100644 index 0f1f913..0000000 --- a/serene-tblgen/CMakeLists.txt +++ /dev/null @@ -1,35 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -include_directories(${PROJECT_SOURCE_DIR}/serene-tblgen) - -add_executable(serene-tblgen - serene/errors-backend.cpp - main.cpp -) - -add_executable(SereneTablegen ALIAS serene-tblgen) - -set(SERENE_TABLEGEN $ CACHE - STRING "Native TableGen executable. Saves building one when cross-compiling.") - -set(SERENE_TABLEGEN_EXE SereneTablegen - CACHE STRING "Where to find the tbl-srn binary") -set(SERENE_TABLEGEN_TARGET SereneTablegen CACHE - STRING "Target name for the tbl-srn") - -target_link_libraries(serene-tblgen PRIVATE LLVMTableGenGlobalISel ${llvm_libs}) -set_target_properties(serene-tblgen PROPERTIES FOLDER "serene-tblgen") diff --git a/serene-tblgen/main.cpp b/serene-tblgen/main.cpp deleted file mode 100644 index 2977d42..0000000 --- a/serene-tblgen/main.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - * This is the main file for Serene's tablegen instance. All the backends - * are local to this instance and we use this instance alongside the official - * instances. - */ - -#include "serene/errors-backend.h" // for emitErrors - -#include // for SmallVector -#include // for StringRef -#include // for opt, ParseCommandLineOptions -#include // for LLVM_ATTRIBUTE_USED -#include // for InitLLVM -#include // for raw_ostream -#include // for TableGenMain -#include // for operator<<, RecordKeeper (ptr ... - -namespace cl = llvm::cl; - -namespace serene { -enum ActionType { PrintRecords, ErrorsBackend }; - -cl::opt action( - cl::desc("Action to perform:"), - - cl::values( - clEnumValN(ErrorsBackend, "errors-backend", - "Generate a C++ file containing errors in the input file"), - clEnumValN(PrintRecords, "print-records", - "Print all records to stdout (default)"))); - -bool llvmTableGenMain(llvm::raw_ostream &os, llvm::RecordKeeper &records) { - switch (action) { - case ErrorsBackend: - emitErrors(records, os); - break; - case PrintRecords: - os << records; - break; - } - return false; -} -} // namespace serene - -int main(int argc, char **argv) { - llvm::InitLLVM x(argc, argv); - cl::ParseCommandLineOptions(argc, argv); - - return llvm::TableGenMain(argv[0], &serene::llvmTableGenMain); -} - -#ifndef __has_feature -#define __has_feature(x) 0 -#endif - -#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) || \ - __has_feature(leak_sanitizer) - -#include // for __lsan_is_turned_off - -// Disable LeakSanitizer for this binary as it has too many leaks that are not -// very interesting to fix. See compiler-rt/include/sanitizer/lsan_interface.h -LLVM_ATTRIBUTE_USED int __lsan_is_turned_off() { return 1; } - -#endif diff --git a/serene-tblgen/serene/errors-backend.cpp b/serene-tblgen/serene/errors-backend.cpp deleted file mode 100644 index 0642dcb..0000000 --- a/serene-tblgen/serene/errors-backend.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * Commentary: - * This is a `tablegen` backend to read from generate error definitions - * from the given tablegen records defined in a `.td` file. It relies on - * Two main classes to be available in the target source code. `SereneError` - * and `ErrorVariant`. Checkout `libserene/include/serene/errors/base.h`. - */ - -// The "serene/" part is due to a convention that we use in the project -#include "serene/errors-backend.h" - -#include // for StringRef -#include // for operator+ -#include // for dyn_cast -#include // for line_iterator -#include // for MemoryBufferRef -#include // for raw_ostream -#include // for PrintError -#include // for ListInit, Record, RecordK... -#include // for emitSourceFileHeader - -#include // for function -#include // for size_t - -#define DEBUG_TYPE "errors-backend" -#define INSTANCE_SUFFIX "Instance" - -namespace serene { - -// Any helper data structures can be defined here. Some backends use -// structs to collect information from the records. - -class ErrorsBackend { -private: - llvm::RecordKeeper &records; - -public: - explicit ErrorsBackend(llvm::RecordKeeper &rk) : records(rk) {} - - void createNSBody(llvm::raw_ostream &os); - void createErrorClass(int id, llvm::Record &defRec, llvm::raw_ostream &os); - void run(llvm::raw_ostream &os); -}; // emitter class - -static void inNamespace(llvm::StringRef name, llvm::raw_ostream &os, - std::function f) { - - os << "namespace " << name << " {\n\n"; - f(os); - os << "}; // namespace " << name << "\n"; -}; - -void ErrorsBackend::createErrorClass(const int id, llvm::Record &defRec, - llvm::raw_ostream &os) { - (void)records; - (void)id; - - const auto recName = defRec.getName(); - - os << " " << recName << ",\n"; - // os << "class " << recName << " : public llvm::ErrorInfo<" << recName << ", - // " - // << "SereneError> {\n" - // << "public:\n" - // << " using llvm::ErrorInfo<" << recName << ", " - // << "SereneError>::ErrorInfo;\n" - // << " constexpr static const int ID = " << id << ";\n};\n\n"; -}; - -void ErrorsBackend::createNSBody(llvm::raw_ostream &os) { - auto *index = records.getGlobal("errorsIndex"); - - if (index == nullptr) { - llvm::PrintError("'errorsIndex' var is missing!"); - return; - } - - auto *indexList = llvm::dyn_cast(index); - - if (indexList == nullptr) { - llvm::PrintError("'errorsIndex' has to be a list!"); - return; - } - - os << "#ifdef GET_CLASS_DEFS\n"; - inNamespace("serene::errors", os, [&](llvm::raw_ostream &os) { - os << "enum ErrorType {\n"; - for (unsigned int i = 0; i < static_cast(indexList->size()); - i++) { - llvm::Record *defRec = indexList->getElementAsRecord(i); - - if (!defRec->isSubClassOf("Error")) { - continue; - } - - createErrorClass(static_cast(i), *defRec, os); - } - os << "};\n\n"; - - os << "#define NUMBER_OF_ERRORS " << indexList->size() << "\n"; - os << "static const ErrorVariant errorVariants[" << indexList->size() - << "] = {\n"; - - for (size_t i = 0; i < indexList->size(); i++) { - llvm::Record *defRec = - indexList->getElementAsRecord(static_cast(i)); - auto recName = defRec->getName(); - - if (!defRec->isSubClassOf("Error")) { - continue; - } - - os << " ErrorVariant::make(" << i << ", \n"; - os << " \"" << recName << "\",\n"; - - auto desc = defRec->getValueAsString("desc"); - - if (desc.empty()) { - llvm::PrintError("'desc' field is empty for " + recName); - } - - os << " \"" << desc << "\",\n"; - - auto help = defRec->getValueAsString("help"); - - if (!help.empty()) { - - const llvm::MemoryBufferRef value(help, "help"); - - llvm::line_iterator lines(value, false); - while (!lines.is_at_end()) { - if (lines.line_number() != 1) { - os << '\t'; - } - auto prevLine = *lines; - lines++; - os << '"' << prevLine << '"'; - - if (lines.is_at_end()) { - os << ";\n"; - } else { - os << '\n'; - } - } - } else { - os << " \"\""; - } - - os << "),\n"; - } - - os << "};\n"; - }); - - os << "#undef GET_CLASS_DEFS\n#endif\n\n"; -} - -void ErrorsBackend::run(llvm::raw_ostream &os) { - (void)records; - llvm::emitSourceFileHeader("Serene's Errors collection", os); - - // DO NOT GUARD THE HEADER WITH #ifndef ... - os << "#include \"serene/errors/variant.h\"\n\n#include " - "\n\n"; - - createNSBody(os); -} - -void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os) { - ErrorsBackend(rk).run(os); -} - -} // namespace serene diff --git a/serene-tblgen/serene/errors-backend.h b/serene-tblgen/serene/errors-backend.h deleted file mode 100644 index 2759718..0000000 --- a/serene-tblgen/serene/errors-backend.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -namespace llvm { -class RecordKeeper; -class raw_ostream; -} // namespace llvm - -#define DEBUG_TYPE "errors-backend" - -namespace serene { - -void emitErrors(llvm::RecordKeeper &rk, llvm::raw_ostream &os); - -} // namespace serene diff --git a/serene/CMakeLists.txt b/serene/CMakeLists.txt deleted file mode 100644 index 6e4e24d..0000000 --- a/serene/CMakeLists.txt +++ /dev/null @@ -1,135 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -find_package(BDWgc 8.2.0 REQUIRED) - -# Main Binary ================================================================= -add_executable(serene) - -set_target_properties(serene PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - C_INCLUDE_WHAT_YOU_USE ${iwyu} - CXX_INCLUDE_WHAT_YOU_USE ${iwyu} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE -) - -if (CPP_20_SUPPORT) - target_compile_features(serene PRIVATE cxx_std_20) -else() - target_compile_features(serene PRIVATE cxx_std_17) -endif() - -# Setup header directory and auto generated headers -target_include_directories(serene - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/include -) - -target_include_directories(serene SYSTEM PUBLIC - # We don't want the generated files from table gen - # to be treated as local since the contain warnings - ${PROJECT_BINARY_DIR}/serene/include) - -target_link_libraries(serene PRIVATE - LLVMSupport -) - -# Autogenerate the `config.h` file -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/serene/config.h.in include/serene/config.h) - - -target_compile_options(serene - PRIVATE - $<$>:-stdlib=libc++> - - # LLVM has it's own RTTI - -fno-rtti - -fno-builtin-strlen - - # Dedicate a section to each function, so the linker - # can do a better job on dead code elimination - -ffunction-sections - -fdata-sections - - $<$:-fsanitize=address> - $<$:-static-libsan> - $<$:-g3> - $<$:-O0> - $<$:-ggdb> - # For the sake of debugging - $<$:-fno-inline> - # To make the local ccache happy - $<$:-fdebug-prefix-map=${PROJECT_SOURCE_DIR}=.> - - # No tail call elimination on Debug to let asan provide - # better stacktrackes - $<$:-fno-optimize-sibling-calls> - - $<$:-fno-omit-frame-pointer> - $<$:-fomit-frame-pointer> - $<$:-O3> - $<$:-fmerge-all-constants> -) - -target_link_options(serene PRIVATE - $<$>:-stdlib=libc++> - $<$>:-lc++abi> - $<$>:--rtlib=compiler-rt> - - -Wl,--gc-sections - $<$:-s> - - $<$:-fsanitize=address> - $<$:-static-libsan> - # Do not link against shared libraries - --static -) - - -if(SERENE_ENABLE_BUILDID) - target_link_options(serene -Wl,--build-id) -endif() - -if(SERENE_ENABLE_TIDY) - set_target_properties(serene PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if(SERENE_ENABLE_THINLTO) - include(CheckIPOSupported) - # Optional IPO. Do not use IPO if it's not supported by compiler. - check_ipo_supported(RESULT result OUTPUT output) - if(result) - message(STATUS "IPO is supported and is turned on") - set_property(TARGET serene PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) - else() - message(WARNING "IPO is not supported: ${output}") - message(WARNING "Make sure to use lld") - endif() -endif() - - -include(GNUInstallDirs) - -install(TARGETS serene EXPORT SereneTargets - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -add_subdirectory(src) -add_subdirectory(include) diff --git a/serene/include/CMakeLists.txt b/serene/include/CMakeLists.txt deleted file mode 100644 index 6064235..0000000 --- a/serene/include/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# add_subdirectory("serene/slir/") diff --git a/serene/include/serene/commands.h b/serene/include/serene/commands.h deleted file mode 100644 index 57cacf0..0000000 --- a/serene/include/serene/commands.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef SERENE_COMMANDS_H -#define SERENE_COMMANDS_H - -namespace serene::commands { -int cc(int argc, char **argv); -int run(); -} // namespace serene::commands - -#endif diff --git a/serene/include/serene/config.h.in b/serene/include/serene/config.h.in deleted file mode 100644 index c151f63..0000000 --- a/serene/include/serene/config.h.in +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -// the configured options and settings - -#define SERENE_VERSION "@PROJECT_VERSION@" - -// Why so obvious? to make the linter shutup :)) -#define I8_SIZE 8 -#define I32_SIZE 32 -#define I64_SIZE 64 - -#define MAX_PATH_SLOTS 256 - -#define COMMON_ARGS_COUNT 6 - -#define PACKED_FUNCTION_NAME_PREFIX "__serene_" - -// Should we build the support for MLIR CL OPTIONS? -#cmakedefine SERENE_WITH_MLIR_CL_OPTION - -#endif diff --git a/serene/src/CMakeLists.txt b/serene/src/CMakeLists.txt deleted file mode 100644 index 532bb28..0000000 --- a/serene/src/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -target_sources(serene PRIVATE - serene.cpp - - commands/commands.cpp -) diff --git a/serene/src/commands/commands.cpp b/serene/src/commands/commands.cpp deleted file mode 100644 index 714eb98..0000000 --- a/serene/src/commands/commands.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/commands.h" - -#include - -namespace serene::commands { -int cc(int argc, char **argv) { - printf(">> %d, %s\n", argc, argv[0]); - return 0; -} - -int run() { return 0; } -} // namespace serene::commands diff --git a/serene/src/serene.cpp b/serene/src/serene.cpp deleted file mode 100644 index 1fa50fb..0000000 --- a/serene/src/serene.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/commands.h" -#include "serene/config.h" - -#include -#include - -#include -#include - -namespace cl = llvm::cl; - -static std::string banner = - llvm::formatv("\n\nSerene Compiler Version {0}" - "\nCopyright (C) 2019-2023 " - "Sameer Rahmani \n" - "Serene comes with ABSOLUTELY NO WARRANTY;\n" - "This is free software, and you are welcome\n" - "to redistribute it under certain conditions; \n" - "for details take a look at the LICENSE file.\n", - SERENE_VERSION); - -namespace serene::opts { -// Global options =========================================================== -static cl::opt verbose("v", cl::desc("Use verbose output"), - cl::cat(cl::getGeneralCategory()), - cl::sub(cl::SubCommand::getAll())); - -// Subcommands ============================================================== -// We don't use this subcommand directly but we need it for the CLI interface -static cl::SubCommand CC("cc", "Serene's C compiler interface"); - -static cl::SubCommand Run("run", "Run a Serene file"); -} // namespace serene::opts - -int main(int argc, char **argv) { - - // We don't use llvm::cl here cause we want to let - // the clang take care of the argument parsing. - if ((argc >= 2) && (strcmp(argv[1], "cc") == 0)) { - return serene::commands::cc(--argc, ++argv); - } - - // We start using llvm::cl from here onward which - // enforces our rules even for the subcommands. - cl::ParseCommandLineOptions(argc, argv, banner); - - if (serene::opts::Run) { - serene::commands::run(); - } - - return 0; -} diff --git a/serenec/CMakeLists.txt b/serenec/CMakeLists.txt deleted file mode 100644 index 0fbc8aa..0000000 --- a/serenec/CMakeLists.txt +++ /dev/null @@ -1,69 +0,0 @@ -# Serene Programming Language -# -# Copyright (c) 2019-2023 Sameer Rahmani -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, version 2. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -add_executable(serenec serenec.cpp) - -set_target_properties(serenec PROPERTIES - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} - # Warn on unused libs - LINK_WHAT_YOU_USE TRUE - - # LTO support - INTERPROCEDURAL_OPTIMIZATION TRUE) - -target_compile_options(serenec - PRIVATE - $<$:-fsanitize=address> - $<$:-static-libsan> - ) - -target_link_options(serenec - PRIVATE - $<$:-fsanitize=address> - $<$:-static-libsan> - ) - -add_dependencies(serenec Serene::core) - -if(SERENE_ENABLE_TIDY) - set_target_properties(serenec PROPERTIES CXX_CLANG_TIDY ${CLANG_TIDY_PATH}) -endif() - -if (CPP_20_SUPPORT) - target_compile_features(serenec PRIVATE cxx_std_20) -else() - target_compile_features(serenec PRIVATE cxx_std_17) -endif() - -target_link_libraries(serenec - PRIVATE - - Serene::lib - #MLIRPass - - #LLVMTarget - #LLVMOption - #lldDriver - #lldELF - ) - -target_include_directories(serenec PRIVATE ${PROJECT_BINARY_DIR}) -target_include_directories(serenec PRIVATE ${INCLUDE_DIR}) - - -install(TARGETS serenec - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/serenec/serenec.cpp b/serenec/serenec.cpp deleted file mode 100644 index f55190a..0000000 --- a/serenec/serenec.cpp +++ /dev/null @@ -1,468 +0,0 @@ -/* -*- C++ -*- - * Serene Programming Language - * - * Copyright (c) 2019-2023 Sameer Rahmani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "serene/config.h" // for SERENE_VERSION -#include "serene/jit/halley.h" // for Halley -#include "serene/options.h" // for serene -#include "serene/serene.h" // for applySereneCLOptions -#include "serene/types/types.h" // for InternalString - -#include // for ParseCommandLineOptions -#include // for operator<<, Error -#include // for formatv, formatv_object -#include // for provider_format_adapter -#include // for errs, raw_ostream - -#include // for allocator, unique_ptr -#include // for string -#include // for tuple - -// #include "serene/jit/halley.h" -// #include "serene/namespace.h" -// #include "serene/reader/location.h" -// #include "serene/reader/reader.h" -// #include "serene/semantics.h" -// #include "serene/serene.h" -// #include "serene/slir/generatable.h" -// #include "serene/slir/slir.h" - -// #include - -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// //#include -// #include - -// #include -// #include -// #include -// #include -// #include - -// #include - -// using namespace std; -using namespace serene; - -namespace cl = llvm::cl; - -// namespace { -// enum Action { -// None, -// DumpAST, -// DumpSLIR, -// DumpMLIR, -// DumpSemantic, -// DumpLIR, -// DumpIR, -// CompileToObject, -// Compile, -// // TODO: Remove this option and replace it by a subcommand -// RunJIT, -// }; -// } // namespace - -static std::string banner = - llvm::formatv("\n\nSerene Compiler Version {0}" - "\nCopyright (C) 2019-2023 " - "Sameer Rahmani \n" - "Serene comes with ABSOLUTELY NO WARRANTY;\n" - "This is free software, and you are welcome\n" - "to redistribute it under certain conditions; \n" - "for details take a look at the LICENSE file.\n", - SERENE_VERSION); - -// static cl::opt inputNS(cl::Positional, cl::desc(""), -// cl::Required); - -// static cl::opt outputFile( -// "o", cl::desc("The relative path to the output file from the build dir"), -// cl::init("-"), cl::value_desc("filename")); - -// static cl::opt -// outputDir("b", cl::desc("The absolute path to the build directory"), -// cl::value_desc("dir"), cl::Required); - -// static cl::opt emitAction( -// "emit", cl::desc("Select what to dump."), cl::init(Compile), -// cl::values(clEnumValN(DumpSemantic, "semantic", -// "Output the AST after one level of analysis -// only")), -// cl::values(clEnumValN(DumpIR, "ir", "Output the lowered IR only")), -// cl::values(clEnumValN(DumpSLIR, "slir", "Output the SLIR only")), -// cl::values(clEnumValN(DumpMLIR, "mlir", -// "Output the MLIR only (Lowered SLIR)")), -// cl::values(clEnumValN(DumpLIR, "lir", -// "Output the LIR only (Lowerd to LLVM dialect)")), -// cl::values(clEnumValN(DumpAST, "ast", "Output the AST only")), -// cl::values(clEnumValN(CompileToObject, "object", -// "Compile to object file.")), -// cl::values(clEnumValN(Compile, "target", -// "Compile to target code. (Default)")), -// cl::values(clEnumValN(RunJIT, "jit", -// "Run the give input file with the JIT.")) - -// ); - -// int dumpAsObject(Namespace &ns) { -// // TODO: Move the compilation process to the Namespace class -// auto maybeModule = ns.compileToLLVM(); -// // TODO: Fix this call to raise the wrapped error instead -// if (!maybeModule) { -// // TODO: Rais and error: "Faild to generato LLVM IR for namespace" -// return -1; -// } - -// auto module = std::move(maybeModule.getValue()); -// auto &ctx = ns.getContext(); - -// // TODO: We need to set the triple data layout and everything to that sort -// in -// // one place. We want them for the JIT as well and also we're kinda -// // duplicating what we're doing in `Namespace#compileToLLVM`. -// module->setTargetTriple(ctx.targetTriple); - -// std::string Error; -// const auto *target = -// llvm::TargetRegistry::lookupTarget(ctx.targetTriple, Error); - -// // Print an error and exit if we couldn't find the requested target. -// // This generally occurs if we've forgotten to initialise the -// // TargetRegistry or we have a bogus target triple. -// if (target == nullptr) { -// llvm::errs() << Error; -// return 1; -// } - -// const auto *cpu = "generic"; -// const auto *features = ""; - -// llvm::TargetOptions opt; -// auto rm = std::optional(); -// auto *targetMachinePtr = -// target->createTargetMachine(ctx.targetTriple, cpu, features, opt, rm); -// auto targetMachine = -// std::unique_ptr(targetMachinePtr); - -// module->setDataLayout(targetMachine->createDataLayout()); - -// const auto *filename = -// strcmp(outputFile.c_str(), "-") == 0 ? "output" : outputFile.c_str(); - -// std::error_code ec; -// const auto pathSize(256); - -// llvm::SmallString destFile(outputDir); -// llvm::sys::path::append(destFile, filename); -// auto destObjFilePath = llvm::formatv("{0}.o", destFile).str(); -// llvm::raw_fd_ostream dest(destObjFilePath, ec, llvm::sys::fs::OF_None); - -// if (ec) { -// llvm::errs() << "Could not open file: " << destObjFilePath; -// llvm::errs() << "Could not open file: " << ec.message(); -// return 1; -// } - -// llvm::legacy::PassManager pass; -// auto fileType = llvm::CGFT_ObjectFile; - -// if (targetMachine->addPassesToEmitFile(pass, dest, nullptr, fileType)) { -// llvm::errs() << "TheTargetMachine can't emit a file of this type"; -// return 1; -// } - -// pass.run(*module); -// dest.flush(); - -// if (emitAction == Action::Compile) { -// std::vector args = {"serenec"}; - -// args.push_back("--eh-frame-hdr"); -// args.push_back("-m"); -// args.push_back("elf_x86_64"); -// args.push_back("-dynamic-linker"); -// args.push_back("/lib64/ld-linux-x86-64.so.2"); -// args.push_back( -// "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crt1.o"); -// args.push_back( -// "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crti.o"); -// args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtbegin.o"); -// args.push_back("-L"); -// args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/"); -// args.push_back("-L"); -// args.push_back("/usr/lib64/"); - -// args.push_back(destObjFilePath.c_str()); -// args.push_back("-o"); -// args.push_back(destFile.c_str()); -// args.push_back("-lgcc"); -// args.push_back("--as-needed"); -// args.push_back("-lgcc_s"); -// args.push_back("--no-as-needed"); -// args.push_back("-lc"); -// args.push_back("-lgcc"); -// args.push_back("--as-needed"); -// args.push_back("-lgcc_s"); -// args.push_back("--no-as-needed"); -// args.push_back("/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/crtend.o"); -// args.push_back( -// "/usr/lib/gcc/x86_64-pc-linux-gnu/11.2.0/../../../../lib64/crtn.o"); - -// lld::elf::link(args, false, llvm::outs(), llvm::errs()); - -// // llvm::IntrusiveRefCntPtr opts = -// // new clang::DiagnosticOptions; -// // clang::DiagnosticsEngine diags( -// // new clang::DiagnosticIDs, opts, -// // new clang::TextDiagnosticPrinter(llvm::errs(), opts.get())); - -// // clang::driver::Driver d("clang", ctx.targetTriple, diags, -// // "Serene compiler"); -// // std::vector args = {"serenec"}; - -// // args.push_back(destObjFilePath.c_str()); -// // args.push_back("-o"); -// // args.push_back(destFile.c_str()); - -// // d.setCheckInputsExist(true); - -// // std::unique_ptr compilation; -// // compilation.reset(d.BuildCompilation(args)); - -// // if (!compilation) { -// // llvm::errs() << "can't create the compilation!\n"; -// // return 1; -// // } - -// // llvm::SmallVector> -// // failCommand; - -// // d.ExecuteCompilation(*compilation, failCommand); - -// // if (failCommand.empty()) { -// // llvm::outs() << "Done!\n"; -// // } else { -// // llvm::errs() << "Linking failed!\n"; -// // failCommand.front().second->Print(llvm::errs(), "\n", false); -// // } -// // } - -// return 0; -// }; - -int main(int argc, char *argv[]) { - SERENE_INIT(); - - registerSereneCLOptions(); - - cl::ParseCommandLineOptions(argc, argv, banner); - - auto maybeEngine = makeEngine(); - - if (!maybeEngine) { - llvm::errs() << "Error: Couldn't create the engine due to '" - << maybeEngine.takeError() << "'\n"; - return 1; - } - - auto &engine = *maybeEngine; - applySereneCLOptions(*engine); - - const std::string forms{"some.ns/sym"}; - const types::InternalString data(forms.c_str(), forms.size()); - - auto err = engine->createEmptyNS("some.ns"); - - if (err) { - llvm::errs() << "Error: " << err << "'\n"; - return 1; - } - - // err = engine->loadModule("some.ns", "/home/lxsameer/test.ll"); - - // if (err) { - // llvm::errs() << "Error: " << err << "'\n"; - // return 1; - // } - - std::string core = "serene.core"; - auto maybeCore = engine->loadNamespace(core); - if (!maybeCore) { - llvm::errs() << "Error: " << maybeCore.takeError() << "'\n"; - return 1; - } - - auto bt = engine->lookup("serene.core", "compile"); - - if (!bt) { - llvm::errs() << "Error: " << bt.takeError() << "'\n"; - return 1; - } - - if (*bt == nullptr) { - llvm::errs() << "Error: nullptr?\n"; - return 1; - } - auto *c = *bt; - - (void)c; - // void *res = c(); - // // for (int i = 0; i <= 10; i++) { - // // printf(">> %02x", *(c + i)); - // // } - // printf("Res >> %p\n", res); - // llvm::outs() << "Res: " << *((int *)res) << "\n"; - // (void)res; - - // // TODO: handle the outputDir by not forcing it. it should be - // // default to the current working dir - // if (outputDir == "-") { - // llvm::errs() << "Error: The build directory is not set. Did you - // forget to - // " - // "use '-b'?\n"; - // return 1; - // } - - // switch (emitAction) { - - // case Action::RunJIT: { - // // TODO: Replace it by a proper jit configuration - // ctx->setOperationPhase(CompilationPhase::NoOptimization); - // break; - // }; - - // // Just print out the raw AST - // case Action::DumpAST: { - // ctx->setOperationPhase(CompilationPhase::Parse); - // break; - // }; - - // case Action::DumpSemantic: { - // ctx->setOperationPhase(CompilationPhase::Analysis); - // break; - // }; - - // case Action::DumpSLIR: { - // ctx->setOperationPhase(CompilationPhase::SLIR); - // break; - // } - - // case Action::DumpMLIR: { - // ctx->setOperationPhase(CompilationPhase::MLIR); - // break; - // } - - // case Action::DumpLIR: { - // ctx->setOperationPhase(CompilationPhase::LIR); - // break; - // } - - // case Action::DumpIR: { - // ctx->setOperationPhase(CompilationPhase::IR); - // break; - // } - - // case Action::CompileToObject: { - // ctx->setOperationPhase(CompilationPhase::NoOptimization); - // break; - // } - - // case Action::Compile: { - // ctx->setOperationPhase(CompilationPhase::NoOptimization); - // break; - // } - - // default: { - // llvm::errs() << "No action specified. TODO: Print out help here\n"; - // return 1; - // } - // } - - // auto runLoc = reader::LocationRange::UnknownLocation(inputNS); - // auto maybeNS = ctx->importNamespace(inputNS, runLoc); - - // if (!maybeNS) { - // auto err = maybeNS.takeError(); - // throwErrors(*ctx, err); - // return (int)std::errc::no_such_file_or_directory; - // } - - // auto ns = *maybeNS; - - // switch (emitAction) { - // case Action::DumpAST: - // case Action::DumpSemantic: { - // auto ast = ns->getTree(); - // llvm::outs() << exprs::astToString(&ast) << "\n"; - // return 0; - // } - - // case Action::DumpSLIR: - // case Action::DumpMLIR: - // case Action::DumpLIR: { - // ns->dump(); - // break; - // }; - // case Action::DumpIR: { - // auto maybeModule = ns->compileToLLVM(); - - // if (!maybeModule) { - // llvm::errs() << "Failed to generate the IR.\n"; - // return 1; - // } - - // auto tsm = std::move(*maybeModule); - // tsm.withModuleDo([](auto &m) { m.dump(); }); - - // break; - // }; - - // // case Action::RunJIT: { - // // auto maybeJIT = JIT::make(*ns); - // // if (!maybeJIT) { - // // // TODO: panic in here: "Couldn't creat the JIT!" - // // return -1; - // // } - // // auto jit = std::move(maybeJIT.getValue()); - - // // if (jit->invoke("main")) { - // // llvm::errs() << "Faild to invoke the 'main' function.\n"; - // // return 1; - // // } - // // llvm::outs() << "Done!"; - // // break; - // // }; - - // // case Action::Compile: - // // case Action::CompileToObject: { - // // return dumpAsObject(*ns); - // // }; - // default: { - // llvm::errs() << "Action is not supported yet!\n"; - // }; - // } - - return 0; -}