├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .idea
├── codeStyles
│ └── codeStyleConfig.xml
├── enact.iml
├── misc.xml
├── modules.xml
└── vcs.xml
├── .travis.yml
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.md
├── PULL_REQUEST_TEMPLATE.md
├── README.md
├── docs
├── img
│ ├── enact-logo-text.png
│ ├── enact_icon.png
│ └── tmp
└── implementation.md
├── include
└── Enact.h
├── lib
├── AstSerialise.cpp
├── AstSerialise.h
├── CMakeLists.txt
├── InsertionOrderMap.h
├── Natives.cpp
├── Natives.h
├── analyser
│ ├── Analyser.cpp
│ ├── Analyser.h
│ └── CMakeLists.txt
├── ast
│ ├── AstVisitor.h
│ ├── CMakeLists.txt
│ ├── Expr.h
│ ├── Pattern.h
│ ├── Stmt.h
│ └── generate.py
├── bytecode
│ ├── CMakeLists.txt
│ ├── Chunk.cpp
│ └── Chunk.h
├── common.h
├── compiler
│ ├── CMakeLists.txt
│ ├── Compiler.cpp
│ └── Compiler.h
├── context
│ ├── CMakeLists.txt
│ ├── CompileContext.cpp
│ ├── CompileContext.h
│ ├── Options.cpp
│ └── Options.h
├── memory
│ ├── CMakeLists.txt
│ ├── GC.cpp
│ └── GC.h
├── parser
│ ├── CMakeLists.txt
│ ├── Lexer.cpp
│ ├── Lexer.h
│ ├── Parser.cpp
│ ├── Parser.h
│ ├── Token.h
│ ├── Typename.cpp
│ └── Typename.h
├── sema
│ ├── CMakeLists.txt
│ ├── Sema.cpp
│ ├── Sema.h
│ ├── SemaDecls.cpp
│ ├── SemaDecls.h
│ ├── SemaDefs.cpp
│ ├── SemaDefs.h
│ └── VariableInfo.h
├── trivialStructs.h
├── type
│ ├── CMakeLists.txt
│ ├── Type.cpp
│ └── Type.h
├── value
│ ├── CMakeLists.txt
│ ├── Object.cpp
│ ├── Object.h
│ ├── Value.cpp
│ └── Value.h
└── vm
│ ├── CMakeLists.txt
│ ├── VM.cpp
│ └── VM.h
└── src
├── CMakeLists.txt
└── main.cpp
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | labels:
5 |
6 | ---
7 |
8 | **Describe the bug**
9 | A clear and concise description of what the bug is.
10 |
11 | **To Reproduce**
12 | - If you are setting any flags, list them here.
13 | - If the problem occurs when running a program, paste a link to a gist containing it.
14 | - If the problem occurs elsewhere, explain where it is happening and how to reproduce the behavior.
15 |
16 | **Expected behavior**
17 | A clear and concise description of what you expected to happen.
18 |
19 | **Output**
20 | Paste output from Enact with the `-verbose` flag set.
21 |
22 | **Platform**
23 | - Enact version: [e.g. 0.1.1]
24 | - OS [e.g. Ubuntu Linux, Windows]
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | labels:
5 |
6 | ---
7 |
8 | **Is your feature request related to a problem? Please describe.**
9 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
10 |
11 | **Describe the solution you'd like**
12 | A clear and concise description of what you want to happen.
13 |
14 | **Describe alternatives you've considered**
15 | A clear and concise description of any alternative solutions or features you've considered.
16 |
17 | **Additional context**
18 | Add any other context or screenshots about the feature request here.
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++
2 | ## Prerequisites
3 | *.d
4 |
5 | ## Compiled Object files
6 | *.slo
7 | *.lo
8 | *.o
9 | *.obj
10 |
11 | ## Precompiled Headers
12 | *.gch
13 | *.pch
14 |
15 | ## Compiled Dynamic libraries
16 | *.so
17 | *.dylib
18 | *.dll
19 |
20 | ## Fortran module files
21 | *.mod
22 | *.smod
23 |
24 | ## Compiled Static libraries
25 | *.lai
26 | *.la
27 | *.a
28 | *.lib
29 |
30 | ## Executables
31 | *.exe
32 | *.out
33 | *.app
34 |
35 | # CLion
36 | ## User-specific stuff
37 | .idea/**/workspace.xml
38 | .idea/**/tasks.xml
39 | .idea/**/usage.statistics.xml
40 | .idea/**/dictionaries
41 | .idea/**/shelf
42 |
43 | ## Generated files
44 | .idea/**/contentModel.xml
45 |
46 | ## Sensitive or high-churn files
47 | .idea/**/dataSources/
48 | .idea/**/dataSources.ids
49 | .idea/**/dataSources.local.xml
50 | .idea/**/sqlDataSources.xml
51 | .idea/**/dynamic.xml
52 | .idea/**/uiDesigner.xml
53 | .idea/**/dbnavigator.xml
54 |
55 | ## Gradle
56 | .idea/**/gradle.xml
57 | .idea/**/libraries
58 |
59 | ## Gradle and Maven with auto-import
60 | ### When using Gradle or Maven with auto-import, you should exclude module files,
61 | ### since they will be recreated, and may cause churn. Uncomment if using
62 | ### auto-import.
63 | #### .idea/modules.xml
64 | #### .idea/*.iml
65 | #### .idea/modules
66 |
67 | ## CMake
68 | cmake-build-*/
69 |
70 | ## Mongo Explorer plugin
71 | .idea/**/mongoSettings.xml
72 |
73 | ## File-based project format
74 | *.iws
75 |
76 | ## IntelliJ
77 | out/
78 |
79 | ## mpeltonen/sbt-idea plugin
80 | .idea_modules/
81 |
82 | ## JIRA plugin
83 | atlassian-ide-plugin.xml
84 |
85 | ## Cursive Clojure plugin
86 | .idea/replstate.xml
87 |
88 | ## Crashlytics plugin (for Android Studio and IntelliJ)
89 | com_crashlytics_export_strings.xml
90 | crashlytics.properties
91 | crashlytics-build.properties
92 | fabric.properties
93 |
94 | ## Editor-based Rest Client
95 | .idea/httpRequests
96 |
97 | ## Android studio 3.1+ serialized cache file
98 | .idea/caches/build_file_checksums.ser
99 | .idea/workspace.xml
100 |
101 | # Xcode
102 | ## User settings
103 | xcuserdata/
104 |
105 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
106 | *.xcscmblueprint
107 | *.xccheckout
108 |
109 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
110 | build/
111 | DerivedData/
112 | *.moved-aside
113 | *.pbxuser
114 | !default.pbxuser
115 | *.mode1v3
116 | !default.mode1v3
117 | *.mode2v3
118 | !default.mode2v3
119 | *.perspectivev3
120 | !default.perspectivev3
121 |
122 | ## Gcc Patch
123 | /*.gcno
124 |
125 | # macOS
126 | .DS_Store
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/enact.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: bionic
2 |
3 | language: cpp
4 | compiler: gcc
5 |
6 | addons:
7 | apt:
8 | sources:
9 | - ubuntu-toolchain-r-test
10 | packages:
11 | - gcc-8
12 | - g++-8
13 | - cmake
14 |
15 | script:
16 | - export CC=gcc-8
17 | - export CXX=g++-8
18 | - cmake ./
19 | - cmake --build ./ --target enact-cli -- -j 2
20 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.9.2)
2 | project(enact CXX)
3 |
4 | set(CMAKE_CXX_STANDARD 17)
5 |
6 | add_compile_definitions(DEBUG)
7 |
8 | include_directories(include)
9 | add_subdirectory(lib)
10 | add_subdirectory(src)
11 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at abuse@matilda.dandigit.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Enact
2 |
3 | Welcome to the Enact project. It's wonderful to have you here to contribute!
4 | Before you get started helping out, have a quick read over this guide to know what to expect.
5 |
6 | ## Code of Conduct
7 |
8 | All participation in the Enact project is to be governed by the [Code of Conduct](https://github.com/Dandigit/matilda/blob/master/CODE_OF_CONDUCT.md). Any abusive behaviour may be reported to
9 | `enact@dandigit.com`.
10 |
11 | ## How can I contribute?
12 |
13 | ### Bug reports
14 |
15 | If you find a bug in Enact, open a **Bug Report** issue and fill out the template! Help us improve the experience by providing
16 | detailed reports with plenty of info.
17 |
18 | ### Feature requests
19 |
20 | Perhaps you use Enact on the daily and think there's a missing piece of the language that's really bugging you. Propose a new
21 | feature by opening a **Feature Request** issue. Keep in mind that all feature requests are purely proposals and may or may not
22 | become part of the language.
23 |
24 | ### Writing code
25 |
26 | If you're fluent in C++ you can be a huge help to the Enact project. Take a look at bug reports and see if there's any you'd
27 | like to fix, then submit a pull request fixing the bug and explaining how you fixed it. Make sure to include the original bug
28 | report in your PR. Approved feature requests waiting for implementation can also use your help. Submit a pull request with your
29 | implementation of the feature, including the original feature request issue.
30 |
31 | \
32 | Hopefully you've been inspired to contribute to Enact in one way or another! I look forward to seeing you around!
33 |
34 | **- Dan** \
35 | Project maintainer
36 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2018 Daniel Boulton and contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | **Related issue:** (Link to the original issue here. If N/A, specify.)
2 |
3 | **Changes made** \
4 | What changes does this PR make? Why are they necessary?
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Enact is a new compiled general-purpose programming language that's not designed to be unique or groundbreaking.
10 | Instead, Enact aims to be familiar, taking advantage of already established techniques and paradigms and making them
11 | nicer .
12 |
13 |
14 | ## Example
15 | ```
16 | // FizzBuzz in Enact
17 |
18 | func fizzBuzz(n int) {
19 | for i in 1...n {
20 | switch (i % 3 == 0, i % 5 == 0) {
21 | case (true, false) => print("Fizz");
22 | case (false, true) => print("Buzz");
23 | case (true, true) => print("FizzBuzz");
24 | default => print(n);
25 | }
26 | }
27 | }
28 | ```
29 |
30 | ## Features
31 | - Static types that help, not hinder
32 | - Efficient compile-time memory management
33 | - Easy-to-use generics, hygienic macros
34 | - Pattern matching and tail-calls
35 | - Clean and familiar syntax
36 | - Built-in build system and package management
37 |
38 | ## Goals
39 | - Easy to pick up from other compiled languages like C, C++, Rust and Go
40 | - More memory-safe than C, more approachable than Rust, more peformant than Go
41 | - Small standard library with a strong ecosystem of external packages
--------------------------------------------------------------------------------
/docs/img/enact-logo-text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enact-lang/enact/6315773acda3f9f4bb25d220a73581641801b68a/docs/img/enact-logo-text.png
--------------------------------------------------------------------------------
/docs/img/enact_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/enact-lang/enact/6315773acda3f9f4bb25d220a73581641801b68a/docs/img/enact_icon.png
--------------------------------------------------------------------------------
/docs/img/tmp:
--------------------------------------------------------------------------------
1 | tmp
2 |
--------------------------------------------------------------------------------
/docs/implementation.md:
--------------------------------------------------------------------------------
1 | # Enact
2 | ## Planned interpreter structure
3 |
4 | Mainly I'm just writing this down for myself, however potential contributors may find this interesting as well.
5 | Enact is first and foremost an interpreted language, with the possibility of a JIT compiler in the future.
6 |
7 | This repository contains source for a program that compiles Enact source code (`.en` files) down to a high level bytecode and runs
8 | this bytecode on a virtual machine.
9 |
10 | Enact has a planned 5 pass interpreter:
11 | - First, the source is parsed and converted into an AST. \[ done ✔️ \]
12 | - Next, the AST is walked to resolve variables and check types. \[ done ✔️ \]
13 | - Afterwards, the AST is walked again and compiled down to bytecode. \[ in progress 🚧 \]
14 | - This bytecode is optimized by yet another pass. \[ not implemented ❌ \]
15 | - Finally, the VM takes the bytecode and runs it. \[ in progress 🚧 \]
16 |
17 | Currently, the focus of development is implementing the VM abd compiler, and things that come along with that, like garbage collection.
18 |
--------------------------------------------------------------------------------
/include/Enact.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_ENACT_H
2 | #define ENACT_ENACT_H
3 |
4 | #include "../lib/context/CompileContext.h"
5 |
6 | #endif //ENACT_ENACT_H
7 |
--------------------------------------------------------------------------------
/lib/AstSerialise.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "AstSerialise.h"
4 |
5 | namespace enact {
6 | std::string AstSerialise::operator()(Stmt &stmt) {
7 | return visitStmt(stmt);
8 | }
9 |
10 | std::string AstSerialise::operator()(Expr &expr) {
11 | return visitExpr(expr);
12 | }
13 |
14 | std::string AstSerialise::visitBreakStmt(BreakStmt &stmt) {
15 | return m_ident + "(Stmt::Break)";
16 | }
17 |
18 | std::string AstSerialise::visitContinueStmt(ContinueStmt &stmt) {
19 | return m_ident + "(Stmt::Continue)";
20 | }
21 |
22 | std::string AstSerialise::visitEnumStmt(EnumStmt &stmt) {
23 | std::stringstream s;
24 | s << "(Stmt::Enum " << stmt.name.lexeme << " (";
25 |
26 | s << ") (\n";
27 | m_ident += " ";
28 |
29 | for (const EnumStmt::Variant& variant : stmt.variants) {
30 | s << m_ident << "(" << variant.name.lexeme << " " << variant.typename_->name() << ")\n";
31 | }
32 |
33 | m_ident.erase(0, 4);
34 | s << ")";
35 |
36 | return s.str();
37 | }
38 |
39 | std::string AstSerialise::visitExpressionStmt(ExpressionStmt &stmt) {
40 | return m_ident + "(Stmt::Expression " + visitExpr(*stmt.expr) + ")";
41 | }
42 |
43 | std::string AstSerialise::visitFunctionStmt(FunctionStmt &stmt) {
44 | std::stringstream s;
45 |
46 | s << "(Stmt::Function " << stmt.name.lexeme << " (";
47 |
48 | std::string separator;
49 | for (auto ¶m : stmt.params) {
50 | s << separator << param.name.lexeme << ' ' << param.typename_->name();
51 | separator = " ";
52 | }
53 |
54 | s << ") " << stmt.returnTypename->name() << " (\n";
55 | m_ident += " ";
56 |
57 | s << visitExpr(*stmt.body);
58 |
59 | m_ident.erase(0, 4);
60 | s << ')';
61 |
62 | return s.str();
63 | }
64 |
65 | std::string AstSerialise::visitImplStmt(ImplStmt &stmt) {
66 | std::stringstream s;
67 | s << m_ident << "(Stmt::Impl " << stmt.typename_->name() << ' ';
68 |
69 | if (stmt.traitTypename != nullptr) {
70 | s << stmt.traitTypename->name() << ' ';
71 | }
72 |
73 | s << "(\n";
74 | m_ident += " ";
75 |
76 | for (const std::unique_ptr& method : stmt.methods) {
77 | s << visitFunctionStmt(*method);
78 | }
79 |
80 | m_ident.erase(0, 4);
81 | s << ")";
82 |
83 | return s.str();
84 | }
85 |
86 | std::string AstSerialise::visitReturnStmt(ReturnStmt &stmt) {
87 | return "(Stmt::Return " + visitExpr(*stmt.value) + ")";
88 | }
89 |
90 | std::string AstSerialise::visitStructStmt(StructStmt &stmt) {
91 | std::stringstream s;
92 | s << m_ident << "(Stmt::Struct " << stmt.name.lexeme << " (";
93 |
94 | s << ") (\n";
95 | m_ident += " ";
96 |
97 | for (auto &field : stmt.fields) {
98 | s << m_ident << "(" << field.name.lexeme << " " << field.typename_->name() << ")\n";
99 | }
100 |
101 | m_ident.erase(0, 4);
102 | s << ")";
103 |
104 | return s.str();
105 | }
106 |
107 | std::string AstSerialise::visitTraitStmt(TraitStmt &stmt) {
108 | std::stringstream s;
109 |
110 | s << m_ident << "(Stmt::Trait " << stmt.name.lexeme << " (\n";
111 | m_ident += " ";
112 |
113 | for (auto &method : stmt.methods) {
114 | s << m_ident << visitStmt(*method) << "\n";
115 | }
116 |
117 | m_ident.erase(0, 4);
118 | s << ")";
119 |
120 | return s.str();
121 | }
122 |
123 | std::string AstSerialise::visitVariableStmt(VariableStmt &stmt) {
124 | std::stringstream s;
125 |
126 | s << m_ident << "(Stmt::Variable ";
127 | s << stmt.keyword.lexeme << ' ';
128 | s << stmt.typeName->name() << (stmt.typeName->name().empty() ? "" : " ");
129 | s << stmt.name.lexeme + " " + visitExpr(*stmt.initializer) << ")";
130 |
131 | return s.str();
132 | }
133 |
134 | std::string AstSerialise::visitAssignExpr(AssignExpr &expr) {
135 | return "(= " + visitExpr(*expr.target) + " " + visitExpr(*expr.value) + ")";
136 | }
137 |
138 | std::string AstSerialise::visitBinaryExpr(BinaryExpr &expr) {
139 | return "(" + expr.oper.lexeme + " " + visitExpr(*expr.left) + " " + visitExpr(*expr.right) + ")";
140 | }
141 |
142 | std::string AstSerialise::visitBlockExpr(BlockExpr &expr) {
143 | std::stringstream s;
144 |
145 | s << m_ident << "(Expr::Block (\n";
146 | m_ident += " ";
147 |
148 | for (auto &statement : expr.stmts) {
149 | s << m_ident << visitStmt(*statement) << '\n';
150 | }
151 | s << m_ident << visitExpr(*expr.expr) << ')';
152 |
153 | m_ident.erase(0, 4);
154 |
155 | return s.str();
156 | }
157 |
158 | std::string AstSerialise::visitBooleanExpr(BooleanExpr &expr) {
159 | return (expr.value ? "true" : "false");
160 | }
161 |
162 | std::string AstSerialise::visitCallExpr(CallExpr &expr) {
163 | std::stringstream s;
164 |
165 | s << "(() " << visitExpr(*expr.callee);
166 | for (auto &arg : expr.args) {
167 | s << " " << visitExpr(*arg);
168 | }
169 | s << ")";
170 |
171 | return s.str();
172 | }
173 |
174 | std::string AstSerialise::visitCastExpr(CastExpr& expr) {
175 | return "(" + expr.oper.lexeme + " " + visitExpr(*expr.expr) + " " + expr.typename_->name() + ")";
176 | }
177 |
178 | std::string AstSerialise::visitFloatExpr(FloatExpr &expr) {
179 | return std::to_string(expr.value);
180 | }
181 |
182 | std::string AstSerialise::visitForExpr(ForExpr& expr) {
183 | std::stringstream s;
184 |
185 | s << m_ident << "(Expr::For (" << expr.name.lexeme << " " << visitExpr(*expr.object) << ")\n";
186 | m_ident += " ";
187 |
188 | s << visitExpr(*expr.body);
189 |
190 | m_ident.erase(0, 4);
191 | s << m_ident << ")";
192 |
193 | return s.str();
194 | }
195 |
196 | std::string AstSerialise::visitGetExpr(FieldExpr &expr) {
197 | return "(. " + visitExpr(*expr.object) + " " + expr.name.lexeme + ")";
198 | }
199 |
200 | std::string AstSerialise::visitIfExpr(IfExpr& expr) {
201 | std::stringstream s;
202 |
203 | s << m_ident << "(Expr::If " << visitExpr(*expr.condition) << '\n';
204 | m_ident += " ";
205 |
206 | s << visitExpr(*expr.thenBody) << '\n';
207 | s << visitExpr(*expr.elseBody) << ')';
208 |
209 | m_ident.erase(0, 4);
210 |
211 | return s.str();
212 | }
213 |
214 | std::string AstSerialise::visitIntegerExpr(IntegerExpr &expr) {
215 | return std::to_string(expr.value);
216 | }
217 |
218 | std::string AstSerialise::visitInterpolationExpr(InterpolationExpr &expr) {
219 | return visitExpr(*expr.start) + "\\(" + visitExpr(*expr.interpolated) + ")" + visitExpr(*expr.end);
220 | }
221 |
222 | std::string AstSerialise::visitLogicalExpr(LogicalExpr &expr) {
223 | return "(" + expr.oper.lexeme + " " + visitExpr(*expr.left) + " " + visitExpr(*expr.right) + ")";
224 | }
225 |
226 | std::string AstSerialise::visitReferenceExpr(ReferenceExpr &expr) {
227 | return "(&" +
228 | (expr.permission ? expr.permission->lexeme : "") + " " +
229 | (expr.region ? expr.region->lexeme : "") + " " +
230 | visitExpr(*expr.expr) + ")";
231 | }
232 |
233 | std::string AstSerialise::visitStringExpr(StringExpr &expr) {
234 | std::stringstream s;
235 | s << "\"" << expr.value << "\"";
236 | return s.str();
237 | }
238 |
239 | std::string AstSerialise::visitSwitchExpr(SwitchExpr& expr) {
240 | std::stringstream s;
241 |
242 | s << m_ident << "(Expr::Switch " << visitExpr(*expr.value) << " (\n";
243 | m_ident += " ";
244 |
245 | for (auto &case_ : expr.cases) {
246 | s << m_ident << "(" << visitPattern(*case_.pattern) << " " <<
247 | visitExpr(*case_.predicate) << " (\n";
248 | m_ident += " ";
249 |
250 | s << visitExpr(*case_.body);
251 |
252 | m_ident.erase(0, 4);
253 | s << m_ident << ")\n";
254 | }
255 |
256 | m_ident.erase(0, 4);
257 | s << m_ident << ")";
258 |
259 | return s.str();
260 | }
261 |
262 | std::string AstSerialise::visitSymbolExpr(SymbolExpr& expr) {
263 | return expr.name.lexeme;
264 | }
265 |
266 | std::string AstSerialise::visitTupleExpr(TupleExpr &expr) {
267 | std::ostringstream s;
268 | s << '(';
269 |
270 | std::string separator;
271 | for (const std::unique_ptr& elem : expr.elems) {
272 | s << separator << visitExpr(*elem);
273 | separator = ", ";
274 | }
275 |
276 | s << ')';
277 | return s.str();
278 | }
279 |
280 | std::string AstSerialise::visitUnaryExpr(UnaryExpr &expr) {
281 | return "(" + expr.oper.lexeme + " " + visitExpr(*expr.operand) + ")";
282 | }
283 |
284 | std::string AstSerialise::visitUnitExpr(UnitExpr &expr) {
285 | return "()";
286 | }
287 |
288 | std::string AstSerialise::visitWhileExpr(WhileExpr& expr) {
289 | std::stringstream s;
290 |
291 | s << m_ident << "(Expr::While " << visitExpr(*expr.condition) << '\n';
292 | m_ident += " ";
293 |
294 | s << visitExpr(*expr.body);
295 |
296 | m_ident.erase(0, 4);
297 | s << m_ident << ")";
298 |
299 | return s.str();
300 | }
301 |
302 | std::string AstSerialise::visitValuePattern(ValuePattern &pattern) {
303 | return visitExpr(*pattern.value);
304 | }
305 |
306 | std::string AstSerialise::visitWildcardPattern(WildcardPattern &pattern) {
307 | return "_";
308 | }
309 | }
--------------------------------------------------------------------------------
/lib/AstSerialise.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_ASTSERIALISE_H
2 | #define ENACT_ASTSERIALISE_H
3 |
4 | #include "ast/AstVisitor.h"
5 |
6 | namespace enact {
7 | // A functor which takes an AST node (Stmt/Decl/Expr), serializes it,
8 | // and returns the output as an std::string.
9 | class AstSerialise : private AstVisitor {
10 | std::string m_ident = "";
11 |
12 | std::string visitBreakStmt(BreakStmt& stmt) override;
13 | std::string visitContinueStmt(ContinueStmt& stmt) override;
14 | std::string visitEnumStmt(EnumStmt& stmt) override;
15 | std::string visitExpressionStmt(ExpressionStmt& stmt) override;
16 | std::string visitFunctionStmt(FunctionStmt& stmt) override;
17 | std::string visitImplStmt(ImplStmt& stmt) override;
18 | std::string visitReturnStmt(ReturnStmt& stmt) override;
19 | std::string visitStructStmt(StructStmt& stmt) override;
20 | std::string visitTraitStmt(TraitStmt& stmt) override;
21 | std::string visitVariableStmt(VariableStmt& stmt) override;
22 |
23 | std::string visitAssignExpr(AssignExpr& expr) override;
24 | std::string visitBinaryExpr(BinaryExpr& expr) override;
25 | std::string visitBlockExpr(BlockExpr& expr) override;
26 | std::string visitBooleanExpr(BooleanExpr& expr) override;
27 | std::string visitCallExpr(CallExpr& expr) override;
28 | std::string visitCastExpr(CastExpr& expr) override;
29 | std::string visitFloatExpr(FloatExpr& expr) override;
30 | std::string visitForExpr(ForExpr& expr) override;
31 | std::string visitGetExpr(FieldExpr& expr) override;
32 | std::string visitIfExpr(IfExpr& expr) override;
33 | std::string visitIntegerExpr(IntegerExpr& expr) override;
34 | std::string visitInterpolationExpr(InterpolationExpr& expr) override;
35 | std::string visitLogicalExpr(LogicalExpr& expr) override;
36 | std::string visitReferenceExpr(ReferenceExpr& expr) override;
37 | std::string visitStringExpr(StringExpr& expr) override;
38 | std::string visitSwitchExpr(SwitchExpr& expr) override;
39 | std::string visitSymbolExpr(SymbolExpr& expr) override;
40 | std::string visitTupleExpr(TupleExpr& expr) override;
41 | std::string visitUnaryExpr(UnaryExpr& expr) override;
42 | std::string visitUnitExpr(UnitExpr& expr) override;
43 | std::string visitWhileExpr(WhileExpr& expr) override;
44 |
45 | std::string visitValuePattern(ValuePattern& pattern) override;
46 | std::string visitWildcardPattern(WildcardPattern& pattern) override;
47 |
48 | public:
49 | std::string operator()(Stmt& stmt);
50 | std::string operator()(Expr& expr);
51 | };
52 | }
53 |
54 | #endif //ENACT_ASTSERIALISE_H
55 |
--------------------------------------------------------------------------------
/lib/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | add_subdirectory(ast)
2 | add_subdirectory(context)
3 | add_subdirectory(parser)
4 |
5 | set(ENACT_SRC
6 | ${AST_SRC}
7 | ${CONTEXT_SRC}
8 | ${PARSER_SRC}
9 |
10 | ${CMAKE_CURRENT_SOURCE_DIR}/AstSerialise.cpp
11 | ${CMAKE_CURRENT_SOURCE_DIR}/AstSerialise.h
12 | ${CMAKE_CURRENT_SOURCE_DIR}/common.h
13 | ${CMAKE_CURRENT_SOURCE_DIR}/InsertionOrderMap.h
14 | ${CMAKE_CURRENT_SOURCE_DIR}/trivialStructs.h)
15 | set(ENACT_SRC ${ENACT_SRC} PARENT_SCOPE)
16 |
17 | add_library(enact ${ENACT_SRC})
--------------------------------------------------------------------------------
/lib/InsertionOrderMap.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_INSERTIONORDERMAP_H
2 | #define ENACT_INSERTIONORDERMAP_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | namespace enact {
11 | template
12 | class InsertionOrderMapIter;
13 |
14 | template
15 | class InsertionOrderMapConstIter;
16 |
17 | template
18 | class InsertionOrderMap {
19 | friend class InsertionOrderMapIter;
20 |
21 | friend class InsertionOrderMapConstIter;
22 |
23 | std::unordered_map m_map{};
24 | std::vector m_insertionOrder{};
25 |
26 | public:
27 | /* Constructors */
28 | InsertionOrderMap() = default;
29 |
30 | InsertionOrderMap(std::initializer_list> values) :
31 | m_map{values},
32 | m_insertionOrder{} {
33 | std::transform(begin(values), end(values),
34 | std::back_inserter(m_insertionOrder),
35 | [](const auto &pair) { return pair.first; });
36 | };
37 |
38 | /* Iterators */
39 | using iterator = InsertionOrderMapIter;
40 | using const_iterator = InsertionOrderMapConstIter;
41 |
42 | iterator begin() {
43 | return iterator{*this, 0};
44 | }
45 |
46 | iterator end() {
47 | return iterator{*this, length()};
48 | }
49 |
50 | const_iterator begin() const {
51 | return const_iterator{*this, 0};
52 | }
53 |
54 | const_iterator end() const {
55 | return const_iterator{*this, length()};
56 | }
57 |
58 | const_iterator cbegin() const {
59 | return const_iterator{*this, 0};
60 | }
61 |
62 | const_iterator cend() const {
63 | return const_iterator{*this, length()};
64 | }
65 |
66 | /* Length */
67 | bool empty() const {
68 | return length() == 0;
69 | }
70 |
71 | size_t length() const {
72 | return m_insertionOrder.size();
73 | }
74 |
75 | /* Insertion and removal */
76 | void insert(const std::pair &value) {
77 | m_map.insert(value);
78 | m_insertionOrder.push_back(value.first);
79 | }
80 |
81 | template
82 | void emplace(const KeyType& key, Args... constructorArgs) {
83 | m_map.emplace(key, constructorArgs...);
84 | m_insertionOrder.push_back(key);
85 | }
86 |
87 | void insertOrAssign(const std::pair &value) {
88 | if (contains(value.first)) {
89 | m_map[value.first] = value.second;
90 | m_insertionOrder.push_back(value.first);
91 | } else {
92 | insert(value);
93 | }
94 | }
95 |
96 | template
97 | void emplaceOrAssign(const KeyType& key, Args... constructorArgs) {
98 | if (contains(key)) {
99 | m_map[key] = ValueType{constructorArgs...};
100 | m_insertionOrder.push_back(key);
101 | } else {
102 | emplace(key, constructorArgs...);
103 | }
104 | }
105 |
106 | void erase(size_t index) {
107 | m_map.erase(m_insertionOrder[index]);
108 | m_insertionOrder.erase(index);
109 | }
110 |
111 | void clear() {
112 | m_map.clear();
113 | m_insertionOrder.clear();
114 | }
115 |
116 | /* Element access */
117 | ValueType &operator[](const KeyType &key) {
118 | return m_map[key];
119 | }
120 |
121 | const ValueType &operator[](const KeyType &key) const {
122 | return m_map[key];
123 | }
124 |
125 | std::optional> at(const KeyType &key) {
126 | if (contains(key)) return m_map.at(key);
127 | return {};
128 | }
129 |
130 | std::optional> at(const KeyType &key) const {
131 | if (contains(key)) return m_map.at(key);
132 | return {};
133 | }
134 |
135 | std::optional> atIndex(size_t index) {
136 | if (index < length()) return m_map[m_insertionOrder[index]];
137 | return {};
138 | }
139 |
140 | std::optional> atIndex(size_t index) const {
141 | if (index < length()) return m_map[m_insertionOrder[index]];
142 | return {};
143 | }
144 |
145 | std::optional find(const KeyType &key) const {
146 | size_t index = 0;
147 | for (const auto &myKeyType : m_insertionOrder) {
148 | if (myKeyType == key) return index;
149 | ++index;
150 | }
151 |
152 | return {};
153 | }
154 |
155 | /* Checking */
156 | size_t count(const KeyType &key) const {
157 | return m_map.count(key);
158 | }
159 |
160 | bool contains(const KeyType &key) const {
161 | return count(key) > 0;
162 | }
163 |
164 | /* Keys and values */
165 | std::vector> keys() {
166 | std::vector> keys{};
167 | std::transform(
168 | m_insertionOrder.begin(), m_insertionOrder.end(),
169 | std::back_inserter(keys),
170 | [](auto &key) { return std::ref(key.get()); });
171 | return keys;
172 | }
173 |
174 | std::vector> keys() const {
175 | std::vector> keys{};
176 | std::transform(
177 | m_insertionOrder.begin(), m_insertionOrder.end(),
178 | std::back_inserter(keys),
179 | [](const auto &key) { return std::cref(key); });
180 | return keys;
181 | }
182 |
183 | std::vector> values() {
184 | std::vector> values;
185 | std::transform(
186 | m_insertionOrder.begin(), m_insertionOrder.end(),
187 | std::back_inserter(values),
188 | [this](auto &key) { return std::ref(m_map[key]); });
189 | return values;
190 | }
191 |
192 | std::vector> values() const {
193 | std::vector> values;
194 | std::transform(
195 | m_insertionOrder.begin(), m_insertionOrder.end(),
196 | std::back_inserter(values),
197 | [this](const auto &key) { return std::cref(m_map.at(key)); });
198 | return values;
199 | }
200 | };
201 |
202 | template
203 | class InsertionOrderMapIter {
204 | InsertionOrderMap &m_map;
205 | size_t m_index;
206 |
207 | public:
208 | InsertionOrderMapIter(InsertionOrderMap &map, size_t index) :
209 | m_map{map},
210 | m_index{index} {
211 | }
212 |
213 | std::pair &operator*() {
214 | return *m_map.m_map.find(m_map.m_insertionOrder[m_index]);
215 | }
216 |
217 | InsertionOrderMapIter &operator++() {
218 | ++m_index;
219 | return *this;
220 | }
221 |
222 | InsertionOrderMapIter operator++(int) {
223 | return InsertionOrderMapIter{m_map, m_index++};
224 | }
225 |
226 | InsertionOrderMapIter &operator--() {
227 | --m_index;
228 | return *this;
229 | }
230 |
231 | InsertionOrderMapIter operator--(int) {
232 | return InsertionOrderMapIter{m_map, m_index--};
233 | }
234 |
235 | bool operator==(const InsertionOrderMapIter &other) const {
236 | return &m_map == &other.m_map && m_index == other.m_index;
237 | }
238 |
239 | bool operator!=(const InsertionOrderMapIter &other) const {
240 | return &m_map != &other.m_map || m_index != other.m_index;
241 | }
242 | };
243 |
244 | template
245 | class InsertionOrderMapConstIter {
246 | const InsertionOrderMap &m_map;
247 | size_t m_index;
248 |
249 | public:
250 | InsertionOrderMapConstIter(const InsertionOrderMap &map, size_t index) :
251 | m_map{map},
252 | m_index{index} {
253 | }
254 |
255 | const std::pair &operator*() {
256 | return *m_map.m_map.find(m_map.m_insertionOrder[m_index]);
257 | };
258 |
259 | InsertionOrderMapConstIter &operator++() {
260 | ++m_index;
261 | return *this;
262 | }
263 |
264 | InsertionOrderMapConstIter operator++(int) {
265 | return InsertionOrderMapIter{m_map, m_index++};
266 | }
267 |
268 | InsertionOrderMapConstIter &operator--() {
269 | --m_index;
270 | return *this;
271 | }
272 |
273 | InsertionOrderMapConstIter operator--(int) {
274 | return InsertionOrderMapIter{m_map, m_index--};
275 | }
276 |
277 | bool operator==(const InsertionOrderMapConstIter &other) const {
278 | return &m_map == &other.m_map && m_index == other.m_index;
279 | }
280 |
281 | bool operator!=(const InsertionOrderMapConstIter &other) const {
282 | return &m_map != &other.m_map || m_index != other.m_index;
283 | }
284 | };
285 | }
286 |
287 | #endif //ENACT_INSERTIONORDERMAP_H
288 |
--------------------------------------------------------------------------------
/lib/Natives.cpp:
--------------------------------------------------------------------------------
1 | #include "bytecode/Chunk.h"
2 | #include "value/Object.h"
3 |
4 | #include "Natives.h"
5 |
6 | namespace enact {
7 | Value Natives::print(uint8_t argCount, Value *args) {
8 | std::cout << args[0] << "\n";
9 | return Value{};
10 | }
11 |
12 | Value Natives::put(uint8_t argCount, Value *args) {
13 | std::cout << args[0];
14 | return Value{};
15 | }
16 |
17 | Value Natives::dis(uint8_t count, Value *args) {
18 | Chunk &chunk = args[0].asObject()->as()->getFunction()->getChunk();
19 | return Value{new StringObject{chunk.disassemble()}};
20 | }
21 | }
--------------------------------------------------------------------------------
/lib/Natives.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_NATIVES_H
2 | #define ENACT_NATIVES_H
3 |
4 | #include "value/Value.h"
5 |
6 | namespace enact {
7 | namespace Natives {
8 | Value print(uint8_t argCount, Value *args);
9 | Value put(uint8_t argCount, Value *args);
10 | Value dis(uint8_t argCount, Value *args);
11 | }
12 | }
13 |
14 | #endif //ENACT_NATIVES_H
15 |
--------------------------------------------------------------------------------
/lib/analyser/Analyser.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_ANALYSER_H
2 | #define ENACT_ANALYSER_H
3 |
4 | #include "../ast/Stmt.h"
5 | #include "../type/Type.h"
6 |
7 | namespace enact {
8 | class CompileContext;
9 |
10 | // Walks the AST and assigns a Type to each node.
11 |
12 | class Analyser : private StmtVisitor, private ExprVisitor {
13 | CompileContext &m_context;
14 |
15 | std::unordered_map m_types{
16 | std::pair("int", INT_TYPE),
17 | std::pair("float", FLOAT_TYPE),
18 | std::pair("bool", BOOL_TYPE),
19 | std::pair("String", STRING_TYPE),
20 | std::pair("any", DYNAMIC_TYPE),
21 | std::pair("nothing", NOTHING_TYPE),
22 | };
23 |
24 | struct Variable {
25 | Type type = nullptr;
26 | bool isConst = false;
27 | };
28 |
29 | std::vector> m_scopes{};
30 |
31 | // Keep track of whether we can use break/continue
32 | uint32_t m_loopCount = 0;
33 |
34 | // Keep track of the current function type to see if return statements are valid. Acts like a stack for nested
35 | // functions. If the stack is empty, then we are at the global scope.
36 | std::vector m_currentFunctions{};
37 |
38 | // Keep track of functions that need to be analysed later
39 | std::vector> m_globalFunctions{};
40 |
41 | bool m_hadError = false;
42 |
43 | void analyse(Stmt &stmt);
44 | void analyse(Expr &expr);
45 |
46 | void analyseFunctionBody(FunctionStmt &stmt);
47 |
48 | Type getFunctionType(const FunctionStmt &stmt, bool isMethod = false, bool isNative = false);
49 |
50 | Variable &lookUpVariable(const Token &name);
51 | void declareVariable(const std::string &name, const Variable &variable);
52 |
53 | void beginScope();
54 | void endScope();
55 |
56 | class AnalysisError : public std::runtime_error {
57 | public:
58 | AnalysisError() : std::runtime_error{
59 | "Internal error, raising exception:\nUncaught AnalysisError! Private Analyser::analyse() was likely called by mistake where public Analyser::analyse() was supposed to be called instead."} {}
60 | };
61 |
62 | AnalysisError errorAt(const Token &token, const std::string &message);
63 |
64 | void visitBlockStmt(BlockStmt &stmt) override;
65 | void visitBreakStmt(BreakStmt &stmt) override;
66 | void visitContinueStmt(ContinueStmt &stmt) override;
67 | void visitEachStmt(EachStmt &stmt) override;
68 | void visitExpressionStmt(ExpressionStmt &stmt) override;
69 | void visitForStmt(ForStmt &stmt) override;
70 | void visitFunctionStmt(FunctionStmt &stmt) override;
71 | void visitGivenStmt(GivenStmt &stmt) override;
72 | void visitIfStmt(IfStmt &stmt) override;
73 | void visitReturnStmt(ReturnStmt &stmt) override;
74 | void visitStructStmt(StructStmt &stmt) override;
75 | void visitTraitStmt(TraitStmt &stmt) override;
76 | void visitWhileStmt(WhileStmt &stmt) override;
77 | void visitVariableStmt(VariableStmt &stmt) override;
78 | void visitAllotExpr(AllotExpr &expr) override;
79 | void visitAnyExpr(AnyExpr &expr) override;
80 | void visitArrayExpr(ArrayExpr &expr) override;
81 | void visitAssignExpr(AssignExpr &expr) override;
82 | void visitBinaryExpr(BinaryExpr &expr) override;
83 | void visitBooleanExpr(BooleanExpr &expr) override;
84 | void visitCallExpr(CallExpr &expr) override;
85 | void visitFloatExpr(FloatExpr &expr) override;
86 | void visitGetExpr(GetExpr &expr) override;
87 | void visitIntegerExpr(IntegerExpr &expr) override;
88 | void visitLogicalExpr(LogicalExpr &expr) override;
89 | void visitNilExpr(NilExpr &expr) override;
90 | void visitSetExpr(SetExpr &expr) override;
91 | void visitStringExpr(StringExpr &expr) override;
92 | void visitSubscriptExpr(SubscriptExpr &expr) override;
93 | void visitTernaryExpr(TernaryExpr &expr) override;
94 | void visitUnaryExpr(UnaryExpr &expr) override;
95 | void visitVariableExpr(VariableExpr &expr) override;
96 |
97 | public:
98 | Analyser(CompileContext &context);
99 | ~Analyser() = default;
100 |
101 | std::vector> analyse(std::vector> ast);
102 |
103 | Type lookUpType(const Typename &name);
104 |
105 | bool hadError();
106 | };
107 | }
108 |
109 | #endif //ENACT_ANALYSER_H
110 |
--------------------------------------------------------------------------------
/lib/analyser/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(ANALYSER_SRC
2 | ${CMAKE_CURRENT_SOURCE_DIR}/Analyser.cpp
3 | ${CMAKE_CURRENT_SOURCE_DIR}/Analyser.h
4 |
5 | PARENT_SCOPE)
--------------------------------------------------------------------------------
/lib/ast/AstVisitor.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_ASTVISITOR_H
2 | #define ENACT_ASTVISITOR_H
3 |
4 | #include "Stmt.h"
5 |
6 | namespace enact {
7 | template
8 | class AstVisitor : public StmtVisitor, public ExprVisitor, public PatternVisitor {
9 | };
10 | }
11 |
12 | #endif //ENACT_ASTVISITOR_H
13 |
--------------------------------------------------------------------------------
/lib/ast/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(AST_SRC
2 | ${CMAKE_CURRENT_SOURCE_DIR}/AstVisitor.h
3 | ${CMAKE_CURRENT_SOURCE_DIR}/Expr.h
4 | ${CMAKE_CURRENT_SOURCE_DIR}/Stmt.h
5 |
6 | PARENT_SCOPE)
--------------------------------------------------------------------------------
/lib/ast/Expr.h:
--------------------------------------------------------------------------------
1 | // This file was automatically generated.
2 | // "See generate.py" for details.
3 |
4 | #ifndef ENACT_EXPR_H
5 | #define ENACT_EXPR_H
6 |
7 | #include
8 | #include
9 |
10 | #include "../parser/Typename.h"
11 |
12 | #include "Pattern.h"
13 |
14 | namespace enact {
15 | // From "Stmt.h":
16 | class Stmt;
17 |
18 | template
19 | class ExprVisitor;
20 |
21 | class Expr {
22 | public:
23 | //SemaInfo semaInfo{};
24 |
25 | virtual ~Expr() = default;
26 |
27 | // We need to overload for every possible visitor return type here, as we cannot
28 | // have a templated virtual member function.
29 | virtual std::string accept(ExprVisitor *visitor) = 0;
30 | virtual void accept(ExprVisitor *visitor) = 0;
31 | };
32 |
33 | class AssignExpr;
34 | class BinaryExpr;
35 | class BlockExpr;
36 | class BooleanExpr;
37 | class CallExpr;
38 | class CastExpr;
39 | class FloatExpr;
40 | class ForExpr;
41 | class FieldExpr;
42 | class IfExpr;
43 | class IntegerExpr;
44 | class InterpolationExpr;
45 | class LogicalExpr;
46 | class ReferenceExpr;
47 | class StringExpr;
48 | class SwitchExpr;
49 | class SymbolExpr;
50 | class TupleExpr;
51 | class UnaryExpr;
52 | class UnitExpr;
53 | class WhileExpr;
54 |
55 | template
56 | class ExprVisitor {
57 | public:
58 | R visitExpr(Expr& expr) {
59 | return expr.accept(this);
60 | }
61 |
62 | virtual R visitAssignExpr(AssignExpr& expr) = 0;
63 | virtual R visitBinaryExpr(BinaryExpr& expr) = 0;
64 | virtual R visitBlockExpr(BlockExpr& expr) = 0;
65 | virtual R visitBooleanExpr(BooleanExpr& expr) = 0;
66 | virtual R visitCallExpr(CallExpr& expr) = 0;
67 | virtual R visitCastExpr(CastExpr& expr) = 0;
68 | virtual R visitFloatExpr(FloatExpr& expr) = 0;
69 | virtual R visitForExpr(ForExpr& expr) = 0;
70 | virtual R visitGetExpr(FieldExpr& expr) = 0;
71 | virtual R visitIfExpr(IfExpr& expr) = 0;
72 | virtual R visitIntegerExpr(IntegerExpr& expr) = 0;
73 | virtual R visitInterpolationExpr(InterpolationExpr& expr) = 0;
74 | virtual R visitLogicalExpr(LogicalExpr& expr) = 0;
75 | virtual R visitReferenceExpr(ReferenceExpr& expr) = 0;
76 | virtual R visitStringExpr(StringExpr& expr) = 0;
77 | virtual R visitSwitchExpr(SwitchExpr& expr) = 0;
78 | virtual R visitSymbolExpr(SymbolExpr& expr) = 0;
79 | virtual R visitTupleExpr(TupleExpr& expr) = 0;
80 | virtual R visitUnaryExpr(UnaryExpr& expr) = 0;
81 | virtual R visitUnitExpr(UnitExpr& expr) = 0;
82 | virtual R visitWhileExpr(WhileExpr& expr) = 0;
83 | };
84 |
85 | class AssignExpr : public Expr {
86 | public:
87 | std::unique_ptr target;
88 | std::unique_ptr value;
89 | Token oper;
90 |
91 | AssignExpr(std::unique_ptr target, std::unique_ptr value, Token oper) :
92 | target{std::move(target)},
93 | value{std::move(value)},
94 | oper{std::move(oper)} {}
95 |
96 | ~AssignExpr() override = default;
97 |
98 | std::string accept(ExprVisitor *visitor) override {
99 | return visitor->visitAssignExpr(*this);
100 | }
101 |
102 | void accept(ExprVisitor *visitor) override {
103 | return visitor->visitAssignExpr(*this);
104 | }
105 | };
106 |
107 | class BinaryExpr : public Expr {
108 | public:
109 | std::unique_ptr left;
110 | std::unique_ptr right;
111 | Token oper;
112 |
113 | BinaryExpr(std::unique_ptr left, std::unique_ptr right, Token oper) :
114 | left{std::move(left)},
115 | right{std::move(right)},
116 | oper{std::move(oper)} {}
117 |
118 | ~BinaryExpr() override = default;
119 |
120 | std::string accept(ExprVisitor *visitor) override {
121 | return visitor->visitBinaryExpr(*this);
122 | }
123 |
124 | void accept(ExprVisitor *visitor) override {
125 | return visitor->visitBinaryExpr(*this);
126 | }
127 | };
128 |
129 | class BlockExpr : public Expr {
130 | public:
131 | // Statements preceeding the final expression
132 | std::vector> stmts;
133 |
134 | // The final expression
135 | std::unique_ptr expr;
136 |
137 | BlockExpr(std::vector> stmts, std::unique_ptr expr) :
138 | stmts{std::move(stmts)},
139 | expr{std::move(expr)} {}
140 |
141 | ~BlockExpr() override = default;
142 |
143 | std::string accept(ExprVisitor *visitor) override {
144 | return visitor->visitBlockExpr(*this);
145 | }
146 |
147 | void accept(ExprVisitor *visitor) override {
148 | return visitor->visitBlockExpr(*this);
149 | }
150 | };
151 |
152 | class BooleanExpr : public Expr {
153 | public:
154 | bool value;
155 |
156 | explicit BooleanExpr(bool value) :
157 | value{value} {}
158 |
159 | ~BooleanExpr() override = default;
160 |
161 | std::string accept(ExprVisitor *visitor) override {
162 | return visitor->visitBooleanExpr(*this);
163 | }
164 |
165 | void accept(ExprVisitor *visitor) override {
166 | return visitor->visitBooleanExpr(*this);
167 | }
168 | };
169 |
170 | class CallExpr : public Expr {
171 | public:
172 | std::unique_ptr callee;
173 | std::vector> args;
174 | Token paren;
175 |
176 | CallExpr(std::unique_ptr callee, std::vector> args, Token paren) :
177 | callee{std::move(callee)},
178 | args{std::move(args)},
179 | paren{std::move(paren)} {}
180 |
181 | ~CallExpr() override = default;
182 |
183 | std::string accept(ExprVisitor *visitor) override {
184 | return visitor->visitCallExpr(*this);
185 | }
186 |
187 | void accept(ExprVisitor *visitor) override {
188 | return visitor->visitCallExpr(*this);
189 | }
190 | };
191 |
192 | class CastExpr : public Expr {
193 | public:
194 | public:
195 | std::unique_ptr expr;
196 | std::unique_ptr typename_;
197 | Token oper;
198 |
199 | CastExpr(std::unique_ptr expr, std::unique_ptr typename_, Token oper) :
200 | expr{std::move(expr)},
201 | typename_{std::move(typename_)},
202 | oper{std::move(oper)} {}
203 |
204 | ~CastExpr() override = default;
205 |
206 | std::string accept(ExprVisitor *visitor) override {
207 | return visitor->visitCastExpr(*this);
208 | }
209 |
210 | void accept(ExprVisitor *visitor) override {
211 | return visitor->visitCastExpr(*this);
212 | }
213 | };
214 |
215 | class FloatExpr : public Expr {
216 | public:
217 | double value;
218 |
219 | explicit FloatExpr(double value) :
220 | value{value} {}
221 |
222 | ~FloatExpr() override = default;
223 |
224 | std::string accept(ExprVisitor *visitor) override {
225 | return visitor->visitFloatExpr(*this);
226 | }
227 |
228 | void accept(ExprVisitor *visitor) override {
229 | return visitor->visitFloatExpr(*this);
230 | }
231 | };
232 |
233 | class ForExpr : public Expr {
234 | public:
235 | Token name;
236 | std::unique_ptr object;
237 | std::unique_ptr body;
238 |
239 | ForExpr(Token name, std::unique_ptr object, std::unique_ptr body) :
240 | name{std::move(name)},
241 | object{std::move(object)},
242 | body{std::move(body)} {}
243 |
244 | ~ForExpr() override = default;
245 |
246 | std::string accept(ExprVisitor *visitor) override {
247 | return visitor->visitForExpr(*this);
248 | }
249 |
250 | void accept(ExprVisitor *visitor) override {
251 | return visitor->visitForExpr(*this);
252 | }
253 | };
254 |
255 | class FieldExpr : public Expr {
256 | public:
257 | std::unique_ptr object;
258 | Token name;
259 | Token oper;
260 |
261 | FieldExpr(std::unique_ptr object, Token name, Token oper) :
262 | object{std::move(object)},
263 | name{std::move(name)},
264 | oper{std::move(oper)} {}
265 |
266 | ~FieldExpr() override = default;
267 |
268 | std::string accept(ExprVisitor *visitor) override {
269 | return visitor->visitGetExpr(*this);
270 | }
271 |
272 | void accept(ExprVisitor *visitor) override {
273 | return visitor->visitGetExpr(*this);
274 | }
275 | };
276 |
277 | class IfExpr : public Expr {
278 | public:
279 | std::unique_ptr condition;
280 | std::unique_ptr thenBody;
281 | std::unique_ptr elseBody;
282 | Token keyword;
283 |
284 | IfExpr(std::unique_ptr condition,
285 | std::unique_ptr thenBody,
286 | std::unique_ptr elseBody,
287 | Token keyword) :
288 | condition{std::move(condition)},
289 | thenBody{std::move(thenBody)},
290 | elseBody{std::move(elseBody)},
291 | keyword{std::move(keyword)} {}
292 |
293 | ~IfExpr() override = default;
294 |
295 | std::string accept(ExprVisitor *visitor) override {
296 | return visitor->visitIfExpr(*this);
297 | }
298 |
299 | void accept(ExprVisitor *visitor) override {
300 | return visitor->visitIfExpr(*this);
301 | }
302 | };
303 |
304 | class IntegerExpr : public Expr {
305 | public:
306 | int value;
307 |
308 | explicit IntegerExpr(int value) :
309 | value{value} {}
310 |
311 | ~IntegerExpr() override = default;
312 |
313 | std::string accept(ExprVisitor *visitor) override {
314 | return visitor->visitIntegerExpr(*this);
315 | }
316 |
317 | void accept(ExprVisitor *visitor) override {
318 | return visitor->visitIntegerExpr(*this);
319 | }
320 | };
321 |
322 | class InterpolationExpr : public Expr {
323 | public:
324 | std::unique_ptr start;
325 | std::unique_ptr interpolated;
326 | std::unique_ptr end;
327 | Token token;
328 |
329 | InterpolationExpr(
330 | std::unique_ptr start,
331 | std::unique_ptr interpolated,
332 | std::unique_ptr end,
333 | Token token) :
334 | start{std::move(start)},
335 | interpolated{std::move(interpolated)},
336 | end{std::move(end)},
337 | token{std::move(token)} {}
338 |
339 | ~InterpolationExpr() override = default;
340 |
341 | std::string accept(ExprVisitor *visitor) override {
342 | return visitor->visitInterpolationExpr(*this);
343 | }
344 |
345 | void accept(ExprVisitor *visitor) override {
346 | return visitor->visitInterpolationExpr(*this);
347 | }
348 | };
349 |
350 | class LogicalExpr : public Expr {
351 | public:
352 | std::unique_ptr left;
353 | std::unique_ptr right;
354 | Token oper;
355 |
356 | LogicalExpr(std::unique_ptr left, std::unique_ptr right, Token oper) :
357 | left{std::move(left)},
358 | right{std::move(right)},
359 | oper{std::move(oper)} {}
360 |
361 | ~LogicalExpr() override = default;
362 |
363 | std::string accept(ExprVisitor *visitor) override {
364 | return visitor->visitLogicalExpr(*this);
365 | }
366 |
367 | void accept(ExprVisitor *visitor) override {
368 | return visitor->visitLogicalExpr(*this);
369 | }
370 | };
371 |
372 | class ReferenceExpr : public Expr {
373 | public:
374 | std::unique_ptr expr;
375 | Token oper;
376 | std::optional permission;
377 | std::optional region;
378 |
379 | ReferenceExpr(
380 | std::unique_ptr expr,
381 | Token oper,
382 | std::optional permission,
383 | std::optional region) :
384 | expr{std::move(expr)},
385 | oper{std::move(oper)},
386 | permission{std::move(permission)},
387 | region{std::move(region)} {}
388 |
389 | ~ReferenceExpr() override = default;
390 |
391 | std::string accept(ExprVisitor *visitor) override {
392 | return visitor->visitReferenceExpr(*this);
393 | }
394 |
395 | void accept(ExprVisitor *visitor) override {
396 | return visitor->visitReferenceExpr(*this);
397 | }
398 | };
399 |
400 | class StringExpr : public Expr {
401 | public:
402 | std::string value;
403 |
404 | explicit StringExpr(std::string value) :
405 | value{std::move(value)} {}
406 |
407 | ~StringExpr() override = default;
408 |
409 | std::string accept(ExprVisitor *visitor) override {
410 | return visitor->visitStringExpr(*this);
411 | }
412 |
413 | void accept(ExprVisitor *visitor) override {
414 | return visitor->visitStringExpr(*this);
415 | }
416 | };
417 |
418 | struct SwitchCase {
419 | std::unique_ptr pattern;
420 | std::unique_ptr predicate;
421 | std::unique_ptr body;
422 | Token keyword;
423 | };
424 |
425 | class SwitchExpr : public Expr {
426 | public:
427 | std::unique_ptr value;
428 | std::vector cases;
429 |
430 | SwitchExpr(std::unique_ptr value, std::vector&& cases) :
431 | value{std::move(value)},
432 | cases{std::move(cases)} {}
433 |
434 | ~SwitchExpr() override = default;
435 |
436 | std::string accept(ExprVisitor *visitor) override {
437 | return visitor->visitSwitchExpr(*this);
438 | }
439 |
440 | void accept(ExprVisitor *visitor) override {
441 | return visitor->visitSwitchExpr(*this);
442 | }
443 | };
444 |
445 | class SymbolExpr : public Expr {
446 | public:
447 | Token name;
448 |
449 | explicit SymbolExpr(Token name) :
450 | name{std::move(name)} {}
451 |
452 | ~SymbolExpr() override = default;
453 |
454 | std::string accept(ExprVisitor *visitor) override {
455 | return visitor->visitSymbolExpr(*this);
456 | }
457 |
458 | void accept(ExprVisitor *visitor) override {
459 | return visitor->visitSymbolExpr(*this);
460 | }
461 | };
462 |
463 | class TupleExpr : public Expr {
464 | public:
465 | std::vector> elems;
466 | Token paren;
467 |
468 | TupleExpr(std::vector> elems, Token paren) :
469 | elems{std::move(elems)},
470 | paren{std::move(paren)} {}
471 |
472 | ~TupleExpr() override = default;
473 |
474 | std::string accept(ExprVisitor *visitor) override {
475 | return visitor->visitTupleExpr(*this);
476 | }
477 |
478 | void accept(ExprVisitor *visitor) override {
479 | return visitor->visitTupleExpr(*this);
480 | }
481 | };
482 |
483 | class UnaryExpr : public Expr {
484 | public:
485 | std::unique_ptr operand;
486 | Token oper;
487 |
488 | UnaryExpr(std::unique_ptr operand, Token oper) :
489 | operand{std::move(operand)},
490 | oper{std::move(oper)} {}
491 |
492 | ~UnaryExpr() override = default;
493 |
494 | std::string accept(ExprVisitor *visitor) override {
495 | return visitor->visitUnaryExpr(*this);
496 | }
497 |
498 | void accept(ExprVisitor *visitor) override {
499 | return visitor->visitUnaryExpr(*this);
500 | }
501 | };
502 |
503 | class UnitExpr : public Expr {
504 | public:
505 | Token token;
506 |
507 | UnitExpr(Token token) :
508 | token{std::move(token)} {}
509 |
510 | ~UnitExpr() override = default;
511 |
512 | std::string accept(ExprVisitor *visitor) override {
513 | return visitor->visitUnitExpr(*this);
514 | }
515 |
516 | void accept(ExprVisitor *visitor) override {
517 | return visitor->visitUnitExpr(*this);
518 | }
519 | };
520 |
521 | class WhileExpr : public Expr {
522 | public:
523 | std::unique_ptr condition;
524 | std::unique_ptr body;
525 | Token keyword;
526 |
527 | WhileExpr(std::unique_ptr condition, std::unique_ptr body, Token keyword) :
528 | condition{std::move(condition)},
529 | body{std::move(body)},
530 | keyword{std::move(keyword)} {}
531 |
532 | ~WhileExpr() override = default;
533 |
534 | std::string accept(ExprVisitor *visitor) override {
535 | return visitor->visitWhileExpr(*this);
536 | }
537 |
538 | void accept(ExprVisitor *visitor) override {
539 | return visitor->visitWhileExpr(*this);
540 | }
541 | };
542 | }
543 |
544 | #endif // ENACT_EXPR_H
545 |
--------------------------------------------------------------------------------
/lib/ast/Pattern.h:
--------------------------------------------------------------------------------
1 | #ifndef ENACT_PATTERN_H
2 | #define ENACT_PATTERN_H
3 |
4 | namespace enact {
5 | // From "Expr.h":
6 | class Expr;
7 |
8 | template
9 | class PatternVisitor;
10 |
11 | class Pattern {
12 | public:
13 | virtual ~Pattern() = default;
14 |
15 | // We need to overload for every possible visitor return type here, as we cannot
16 | // have a templated virtual member function.
17 | virtual std::string accept(PatternVisitor *visitor) = 0;
18 | virtual void accept(PatternVisitor *visitor) = 0;
19 | };
20 |
21 | class ValuePattern;
22 | class WildcardPattern;
23 |
24 | template
25 | class PatternVisitor {
26 | public:
27 | R visitPattern(Pattern &pattern) {
28 | return pattern.accept(this);
29 | }
30 |
31 | virtual R visitValuePattern(ValuePattern& pattern) = 0;
32 | virtual R visitWildcardPattern(WildcardPattern& pattern) = 0;
33 | // TODO: add other pattern types
34 | };
35 |
36 | class ValuePattern : public Pattern {
37 | public:
38 | std::unique_ptr value;
39 |
40 | ValuePattern(std::unique_ptr value) :
41 | value{std::move(value)} {}
42 |
43 | ~ValuePattern() override = default;
44 |
45 | std::string accept(PatternVisitor* visitor) override {
46 | return visitor->visitValuePattern(*this);
47 | }
48 |
49 | void accept(PatternVisitor* visitor) override {
50 | return visitor->visitValuePattern(*this);
51 | }
52 | };
53 |
54 | class WildcardPattern : public Pattern {
55 | public:
56 | Token keyword;
57 |
58 | WildcardPattern(Token keyword) :
59 | keyword{std::move(keyword)} {}
60 |
61 | ~WildcardPattern() override = default;
62 |
63 | std::string accept(PatternVisitor* visitor) override {
64 | return visitor->visitWildcardPattern(*this);
65 | }
66 |
67 | void accept(PatternVisitor* visitor) override {
68 | return visitor->visitWildcardPattern(*this);
69 | }
70 | };
71 | }
72 |
73 | #endif //ENACT_PATTERN_H
74 |
--------------------------------------------------------------------------------
/lib/ast/Stmt.h:
--------------------------------------------------------------------------------
1 | // This file was automatically generated.
2 | // "See generate.py" for details.
3 |
4 | #ifndef ENACT_STMT_H
5 | #define ENACT_STMT_H
6 |
7 | #include "../trivialStructs.h"
8 |
9 | #include "Expr.h"
10 |
11 | namespace enact {
12 | template
13 | class StmtVisitor;
14 |
15 | class Stmt {
16 | public:
17 | virtual ~Stmt() = default;
18 |
19 | // We need to overload for every possible visitor return type here, as we cannot
20 | // have a templated virtual member function.
21 | virtual std::string accept(StmtVisitor *visitor) = 0;
22 | virtual void accept(StmtVisitor *visitor) = 0;
23 | };
24 |
25 | class BreakStmt;
26 | class ContinueStmt;
27 | class EnumStmt;
28 | class ExpressionStmt;
29 | class FunctionStmt;
30 | class ImplStmt;
31 | class ReturnStmt;
32 | class StructStmt;
33 | class TraitStmt;
34 | class VariableStmt;
35 |
36 | template
37 | class StmtVisitor {
38 | public:
39 | R visitStmt(Stmt& stmt) {
40 | return stmt.accept(this);
41 | };
42 |
43 | virtual R visitBreakStmt(BreakStmt &stmt) = 0;
44 | virtual R visitContinueStmt(ContinueStmt &stmt) = 0;
45 | virtual R visitEnumStmt(EnumStmt& stmt) = 0;
46 | virtual R visitExpressionStmt(ExpressionStmt &stmt) = 0;
47 | virtual R visitFunctionStmt(FunctionStmt &stmt) = 0;
48 | virtual R visitImplStmt(ImplStmt& stmt) = 0;
49 | virtual R visitReturnStmt(ReturnStmt &stmt) = 0;
50 | virtual R visitStructStmt(StructStmt &stmt) = 0;
51 | virtual R visitTraitStmt(TraitStmt &stmt) = 0;
52 | virtual R visitVariableStmt(VariableStmt &stmt) = 0;
53 | };
54 |
55 | class BreakStmt : public Stmt {
56 | public:
57 | Token keyword;
58 | std::unique_ptr value;
59 |
60 | BreakStmt(Token keyword, std::unique_ptr value) :
61 | keyword{std::move(keyword)},
62 | value{std::move(value)} {}
63 |
64 | ~BreakStmt() override = default;
65 |
66 | std::string accept(StmtVisitor *visitor) override {
67 | return visitor->visitBreakStmt(*this);
68 | }
69 |
70 | void accept(StmtVisitor *visitor) override {
71 | return visitor->visitBreakStmt(*this);
72 | }
73 | };
74 |
75 | class ContinueStmt : public Stmt {
76 | public:
77 | Token keyword;
78 |
79 | explicit ContinueStmt(Token keyword) :
80 | keyword{std::move(keyword)} {}
81 |
82 | ~ContinueStmt() override = default;
83 |
84 | std::string accept(StmtVisitor *visitor) override {
85 | return visitor->visitContinueStmt(*this);
86 | }
87 |
88 | void accept(StmtVisitor *visitor) override {
89 | return visitor->visitContinueStmt(*this);
90 | }
91 | };
92 |
93 | class EnumStmt : public Stmt {
94 | public:
95 | struct Variant {
96 | Token name;
97 | std::unique_ptr typename_;
98 | };
99 |
100 | Token name;
101 | std::vector variants;
102 |
103 | explicit EnumStmt(Token name, std::vector&& variants) :
104 | name{std::move(name)},
105 | variants{std::move(variants)} {}
106 |
107 | ~EnumStmt() override = default;
108 |
109 | std::string accept(StmtVisitor *visitor) override {
110 | return visitor->visitEnumStmt(*this);
111 | }
112 |
113 | void accept(StmtVisitor *visitor) override {
114 | return visitor->visitEnumStmt(*this);
115 | }
116 | };
117 |
118 | class ExpressionStmt : public Stmt {
119 | public:
120 | std::unique_ptr expr;
121 |
122 | explicit ExpressionStmt(std::unique_ptr expr) :
123 | expr{std::move(expr)} {}
124 |
125 | ~ExpressionStmt() override = default;
126 |
127 | std::string accept(StmtVisitor *visitor) override {
128 | return visitor->visitExpressionStmt(*this);
129 | }
130 |
131 | void accept(StmtVisitor *visitor) override {
132 | return visitor->visitExpressionStmt(*this);
133 | }
134 | };
135 |
136 | class FunctionStmt : public Stmt {
137 | public:
138 | struct Param {
139 | Token name;
140 | std::unique_ptr typename_;
141 | };
142 |
143 | Token name;
144 | std::unique_ptr returnTypename;
145 | std::vector params;
146 | std::unique_ptr body;
147 |
148 | FunctionStmt(Token name, std::unique_ptr returnTypename, std::vector &¶ms,
149 | std::unique_ptr body) :
150 | name{std::move(name)},
151 | returnTypename{std::move(returnTypename)},
152 | params{std::move(params)},
153 | body{std::move(body)} {}
154 |
155 | ~FunctionStmt() override = default;
156 |
157 | std::string accept(StmtVisitor *visitor) override {
158 | return visitor->visitFunctionStmt(*this);
159 | }
160 |
161 | void accept(StmtVisitor *visitor) override {
162 | return visitor->visitFunctionStmt(*this);
163 | }
164 | };
165 |
166 | class ImplStmt : public Stmt {
167 | public:
168 | std::unique_ptr typename_;
169 | std::unique_ptr traitTypename;
170 | std::vector> methods;
171 |
172 | ImplStmt(std::unique_ptr typename_,
173 | std::unique_ptr traitTypename,
174 | std::vector> methods) :
175 | typename_{std::move(typename_)},
176 | traitTypename{std::move(traitTypename)},
177 | methods{std::move(methods)} {}
178 |
179 | ~ImplStmt() override = default;
180 |
181 | std::string accept(StmtVisitor *visitor) override {
182 | return visitor->visitImplStmt(*this);
183 | }
184 |
185 | void accept(StmtVisitor *visitor) override {
186 | return visitor->visitImplStmt(*this);
187 | }
188 | };
189 |
190 | class ReturnStmt : public Stmt {
191 | public:
192 | Token keyword;
193 | std::unique_ptr value;
194 |
195 | ReturnStmt(Token keyword, std::unique_ptr value) :
196 | keyword{std::move(keyword)},
197 | value{std::move(value)} {}
198 |
199 | ~ReturnStmt() override = default;
200 |
201 | std::string accept(StmtVisitor *visitor) override {
202 | return visitor->visitReturnStmt(*this);
203 | }
204 |
205 | void accept(StmtVisitor *visitor) override {
206 | return visitor->visitReturnStmt(*this);
207 | }
208 | };
209 |
210 | class StructStmt : public Stmt {
211 | public:
212 | struct Field {
213 | Token name;
214 | std::unique_ptr typename_;
215 | };
216 |
217 | Token name;
218 | std::vector fields;
219 |
220 | StructStmt(Token name, std::vector&& fields) :
221 | name{std::move(name)},
222 | fields{std::move(fields)} {}
223 |
224 | ~StructStmt() override = default;
225 |
226 | std::string accept(StmtVisitor *visitor) override {
227 | return visitor->visitStructStmt(*this);
228 | }
229 |
230 | void accept(StmtVisitor *visitor) override {
231 | return visitor->visitStructStmt(*this);
232 | }
233 | };
234 |
235 | class TraitStmt : public Stmt {
236 | public:
237 | Token name;
238 | std::vector> methods;
239 |
240 | TraitStmt(Token name, std::vector> methods) :
241 | name{std::move(name)},
242 | methods{std::move(methods)} {}
243 |
244 | ~TraitStmt() override = default;
245 |
246 | std::string accept(StmtVisitor *visitor) override {
247 | return visitor->visitTraitStmt(*this);
248 | }
249 |
250 | void accept(StmtVisitor *visitor) override {
251 | return visitor->visitTraitStmt(*this);
252 | }
253 | };
254 |
255 | class VariableStmt : public Stmt {
256 | public:
257 | Token keyword;
258 | Token name;
259 | std::unique_ptr typeName;
260 | std::unique_ptr initializer;
261 |
262 | VariableStmt(
263 | Token keyword,
264 | Token name,
265 | std::unique_ptr typeName,
266 | std::unique_ptr initializer) :
267 | keyword{std::move(keyword)},
268 | name{std::move(name)},
269 | typeName{std::move(typeName)},
270 | initializer{std::move(initializer)} {}
271 |
272 | ~VariableStmt() override = default;
273 |
274 | std::string accept(StmtVisitor *visitor) override {
275 | return visitor->visitVariableStmt(*this);
276 | }
277 |
278 | void accept(StmtVisitor *visitor) override {
279 | return visitor->visitVariableStmt(*this);
280 | }
281 | };
282 | }
283 |
284 | #endif // ENACT_STMT_H
285 |
--------------------------------------------------------------------------------
/lib/ast/generate.py:
--------------------------------------------------------------------------------
1 | # THIS SCRIPT IS DEPRECATED
2 | # It will NOT generate a correct AST
3 |
4 | # This script generates the AST classes found in Expr.h/cpp and Stmt.h/cpp.
5 |
6 |
7 | def uncapitalize(s):
8 | s[:1].lower() + s[1:] if s else ''
9 |
10 |
11 | def generate_ast_visitor(name, type_fields, visitor_types):
12 | ret = f"template \nclass {name}Visitor {{\npublic:\n"
13 | for key in type_fields:
14 | ret += f" virtual R visit{key}{name}({key}{name}& {name.lower()}) = 0;\n"
15 | ret += "};\n\n"
16 | return ret
17 |
18 |
19 | def generate_ast_class_visitors(name, type_fields, visitor_types):
20 | ret = ""
21 | for type in visitor_types:
22 | ret += f" virtual {type} accept({name}Visitor<{type}> *visitor) = 0;\n"
23 | return ret
24 |
25 |
26 | def generate_ast_subclasses(name, type_fields, visitor_types):
27 | ret = ""
28 | for key in type_fields:
29 | ret += f"class {key}{name} : public {name}Base {{\npublic:\n"
30 | if len(type_fields[key]) > 0:
31 | for field in type_fields[key]:
32 | ret += " " + field + ";\n"
33 | ret += f"\n {key}{name}("
34 | for field in type_fields[key]:
35 | ret += field + ","
36 | ret = ret[:len(ret)-1]
37 | ret += ") : \n "
38 | for field in type_fields[key]:
39 | ret += f"{field.split(' ')[1]}{{{field.split(' ')[1]}}},"
40 | ret = ret[:len(ret)-1]
41 | ret += " {}\n"
42 | else:
43 | ret += f" {key}{name}() = default;\n"
44 |
45 | ret += f" ~{key}{name}() override = default;\n"
46 |
47 | for visitor_type in visitor_types:
48 | ret += f"\n {visitor_type} accept({name}Visitor<{visitor_type}> *visitor) override {{\n return visitor->visit{key+name}(*this);\n }}\n"
49 | ret += "};\n\n"
50 | return ret
51 |
52 |
53 | def generate_ast_subclass_decls(name, type_fields):
54 | ret = ""
55 | for type_field in type_fields:
56 | ret += f"class {type_field}{name};\n"
57 | ret += "\n"
58 | return ret
59 |
60 |
61 | def generate_ast_class_body(name, type_fields, visitor_types):
62 | ret = f" virtual ~{name}Base() = default;\n"
63 | ret += "\n" + generate_ast_class_visitors(name, type_fields, visitor_types)
64 | ret += "};\n\n"
65 | return ret
66 |
67 |
68 | def generate_includes(includes):
69 | ret = ""
70 | for include in includes:
71 | ret += f"#include {include}\n"
72 | return ret
73 |
74 |
75 | def generate_ast_class(name, type_fields, visitor_types, includes):
76 | type_field = ""
77 | type_getter = ""
78 |
79 | if name == "Expr":
80 | type_field = " Type m_type = nullptr;\n"
81 | type_getter = " virtual void setType(Type t) { m_type = t; }\n virtual const Type& getType() {\n ENACT_ASSERT(m_type != nullptr, \"Expr::getType(): Tried to get uninitialized type.\");\n return m_type;\n }\n"
82 |
83 | ret = ("// This file was automatically generated.\n"
84 | "// \"See generate.py\" for details.\n\n"
85 | f"#ifndef ENACT_{name.upper()}_H\n"
86 | f"#define ENACT_{name.upper()}_H\n\n"
87 |
88 | f"{generate_includes(includes)}\n"
89 |
90 | f"template \nclass {name}Visitor;\n\n"
91 |
92 | f"class {name}Base {{\n"
93 |
94 | f"{type_field}"
95 |
96 | "public:\n"
97 |
98 | f"{type_getter}"
99 |
100 | f"{generate_ast_class_body(name, type_fields, visitor_types)}"
101 |
102 | f"typedef std::shared_ptr<{name}Base> {name};\n\n"
103 |
104 | f"{generate_ast_subclass_decls(name, type_fields)}"
105 | f"{generate_ast_visitor(name, type_fields, visitor_types)}"
106 |
107 | f"{generate_ast_subclasses(name, type_fields, visitor_types)}"
108 |
109 | f"#endif // ENACT_{name.upper()}_H\n"
110 | )
111 | return ret
112 |
113 |
114 | def generate_tree(name, type_fields, visitor_types, includes):
115 | with open(name + ".h", "w") as file:
116 | file.write(generate_ast_class(name, type_fields, visitor_types, includes))
117 |
118 |
119 | generate_tree(
120 | "Expr",
121 | {
122 | "Allot": ["std::shared_ptr target", "Expr value", "Token oper"],
123 | "Any": [],
124 | "Array": ["std::vector value", "Token square", "std::unique_ptr typeName"],
125 | "Assign": ["std::shared_ptr target", "Expr value", "Token oper"],
126 | "Binary": ["Expr left", "Expr right", "Token oper"],
127 | "Boolean": ["bool value"],
128 | "Call": ["Expr callee", "std::vector arguments", "Token paren"],
129 | "Float": ["double value"],
130 | "Get": ["Expr object", "Token name", "Token oper"],
131 | "Integer": ["int value"],
132 | "Logical": ["Expr left", "Expr right", "Token oper"],
133 | "Nil": [],
134 | "String": ["std::string value"],
135 | "Subscript":["Expr object", "Expr index", "Token square"],
136 | "Ternary": ["Expr condition", "Expr thenExpr", "Expr elseExpr", "Token oper"],
137 | "Unary": ["Expr operand", "Token oper"],
138 | "Variable": ["Token name"]
139 | },
140 | ["std::string", "void"],
141 | ['"../h/Type.h"', '"../h/Typename.h"', "", ""]
142 | )
143 |
144 | generate_tree(
145 | "Stmt",
146 | {
147 | "Block": ["std::vector statements"],
148 | "Break": ["Token keyword"],
149 | "Continue": ["Token keyword"],
150 | "Each": ["Token name", "Expr object", "std::vector body"],
151 | "Expression": ["Expr expr"],
152 | "For": ["Stmt initializer", "Expr condition", "Expr increment", "std::vector body", "Token keyword"],
153 | "Function": ["Token name", "std::unique_ptr returnTypename", "std::vector> params", "std::vector body", "Type type"],
154 | "Given": ["Expr value", "std::vector cases"],
155 | "If": ["Expr condition", "std::vector thenBlock", "std::vector elseBlock", "Token keyword"],
156 | "Return": ["Token keyword", "Expr value"],
157 | "Struct": ["Token name", "std::vector