├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE.md
├── README.md
├── docs
├── arithmetic.md
├── cppext.md
├── data.md
├── flow.md
├── index.md
├── io.md
├── list.md
├── manList
├── map.md
├── naming.md
├── procedure.md
├── requirements.txt
├── structure.md
├── text.md
└── time.md
├── images
├── big-ldpl4.0-logo.png
├── ldpl-4.0-badge.png
├── ldpl-4.0-logo.png
├── ldpl-logo-white.png
├── ldpl-logo.png
├── ldpl-open-graph.png
├── ldplsaur-4.0.png
├── ldplsaur-briefcase.png
├── ldplsaur-giant.png
├── ldplsaur.png
├── lpm-logo.png
├── reference-logo.png
├── release-logos
│ ├── 5.1.0.png
│ ├── active-argentinosaurus-white.png
│ ├── active-argentinosaurus.png
│ ├── busy-brontosaurus-white.png
│ ├── busy-brontosaurus.png
│ ├── creative-carnotaurus-white.png
│ ├── creative-carnotaurus.png
│ ├── diligent-dreadnoughtus-white.png
│ ├── diligent-dreadnoughtus.png
│ ├── eloquent-eoraptor-white.png
│ ├── eloquent-eoraptor.png
│ ├── friendly-falcarius-white.png
│ ├── friendly-falcarius.png
│ ├── groovy-gualicho.png
│ └── source
│ │ └── 5.1.0.acorn
└── tutorial-logo.png
├── makefile
├── man
├── README
├── compileman.php
├── generateMan.sh
├── ldpl.1
└── ldplman-intro
├── mkdocs.yml
├── snapcraft.yaml
└── src
├── CMakeLists.txt
├── aux
├── aux_c_format.cpp
├── aux_code.cpp
├── aux_compile_line.cpp
├── aux_container.cpp
├── aux_format.cpp
├── aux_info.cpp
├── aux_line_like.cpp
├── aux_state.cpp
├── aux_tokenizer.cpp
└── aux_typecheck.cpp
├── data_types
├── code_location.h
└── compiler_state.h
├── ldpl.cpp
├── ldpl.h
├── ldpl_lib
├── BigInt.hpp
└── ldpl_lib.cpp
└── libraries
├── cpptrim.h
└── vector_contains.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | ldpl
3 | ldpl.o
4 | ldpl.exe
5 | ldpl_included_lib.cpp
6 | lpm
7 | src/ldpl.1
8 | testing/*
9 | testing
10 | build
11 | .vscode
12 | *-bin
13 | Icon
14 | test
15 | test/*
16 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | Welcome, mighty one! You are about to learn the ways of the dinosaur tamers. Please take a moment to familiarize yourself with them before trying to tame any dinosaurs yourself.
4 |
5 | ## Nomenclature
6 |
7 | In this document we use the term **dinosaur tamer** to refer anyone who contributes
8 | to LDPL, including (but not limited to) contributors to the repository code,
9 | mantainers, bug reporters, people who code in LDPL, people who submit issues
10 | and anyone interested and/or involved with the language in any way.
11 |
12 | 
13 |
14 | ## Our Pledge
15 |
16 | In the interest of fostering an open and welcoming environment, we as
17 | dinosaur tamers pledge to making participation in our project and
18 | our community a harassment-free experience for everyone, regardless of age, body
19 | size, disability, ethnicity, sex characteristics, gender identity and expression,
20 | level of experience, education, socio-economic status, nationality, personal
21 | appearance, race, religion, dislikeness of COBOL or sexual identity, and orientation.
22 |
23 | ## Our Standards
24 |
25 | Examples of behavior that contributes to creating a positive environment
26 | include:
27 |
28 | * Using welcoming and inclusive language
29 | * Being respectful of differing viewpoints and experiences
30 | * Gracefully accepting constructive criticism
31 | * Focusing on what is best for the community
32 | * Showing empathy towards other community members
33 |
34 | Examples of unacceptable behavior by participants include:
35 |
36 | * The use of sexualized language or imagery and unwelcome sexual attention or
37 | advances
38 | * Trolling, insulting/derogatory comments, and personal or political attacks
39 | * Public or private harassment
40 | * Publishing others' private information, such as a physical or electronic
41 | address, without explicit permission
42 | * Other conduct which could reasonably be considered inappropriate in a
43 | professional setting
44 |
45 | ## Our Responsibilities
46 |
47 | Project maintaining dinosaur tamers are responsible for clarifying the standards of acceptable
48 | behavior and are expected to take appropriate and fair corrective action in
49 | response to any instances of unacceptable behavior.
50 |
51 | Project maintaining dinosaur tamers have the right and responsibility to remove, edit, or
52 | reject comments, commits, code, wiki edits, issues, and other contributions
53 | that are not aligned to this Code of Conduct, or to ban temporarily or
54 | permanently any contributor for other behaviors that they deem inappropriate,
55 | threatening, offensive, or harmful.
56 |
57 | ## Scope
58 |
59 | This Code of Conduct applies both within project spaces and in public spaces
60 | when an individual is representing the LDPL project or its community. Examples of
61 | representing the project or community include using an official LDPL e-mail
62 | address, posting via an official LDPL social media account, or acting as an appointed LDPL
63 | representative at an online or offline event. Representation of the LDPL project may be
64 | further defined and clarified by project maintaining dinosaur tamers.
65 |
66 | ## Enforcement
67 |
68 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
69 | reported by contacting the project team at ***martin (at) ldpl-lang.org***. All
70 | complaints will be reviewed and investigated and will result in a response that
71 | is deemed necessary and appropriate to the circumstances. The project team is
72 | obligated to maintain confidentiality with regard to the reporter of an incident.
73 | Further details of specific enforcement policies may be posted separately.
74 |
75 | Project maintainers who do not follow or enforce the Dinosaur Tamers Code in good
76 | faith may face temporary or permanent repercussions as determined by other
77 | members of the project's leadership.
78 |
79 | ## Attribution
80 |
81 | This Code of Conduct is ~stolen~ adapted from the [Contributor Covenant][homepage], version 1.4,
82 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
83 |
84 | [homepage]: https://www.contributor-covenant.org
85 |
86 | For answers to common questions about this code of conduct, see
87 | https://www.contributor-covenant.org/faq
88 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ### Hello there!
2 |
3 | Welcome to the LDPL contributors guide, thank you for being here! This guide will tell you all you need to know in order to contribute to the LDPL project.
4 |
5 | ### Who can contribute to LDPL?
6 |
7 | Anyone can contribute to the LDPL project! As stated on the README.md file, we accept all kinds of contributions anyone can make. From adding statements to the language (that's in fact really easy!) to fixing bugs, adding issues, writing examples, documentation writing some software in LDPL, etc. Anything you consider will make the project grow and better, you are welcome to contribute it. Even a simple drawing or telling your friends about LDPL!
8 |
9 | ### What do I need to know to contribute to LDPL?
10 |
11 | Please take a moment to familiarize yourself with the [Code Of Conduct](/CODE_OF_CONDUCT) (you are expected and required to behave by this code) and the [LDPL reference](https://docs.ldpl-lang.org/) (not really a *must* per se, but that's where all the language is documented).
12 |
13 | C++ knowledge is a must if you want to contribute to the compiler code, and LDPL knowledge is a must if you want to write examples or LDPL software. Drawing is not really a must if you want to submit a drawing, but you may get better results if you know how to draw. We'll love your art anyway, though.
14 |
15 | ### Will you accept my pull request?
16 |
17 | We tend to accept most pull requests, unless they break the language in some way or another. In that case, we'll discuss with you what can be done to have it accepted. We wouldn't like your hard made contribution to go to waste!
18 |
19 | ### Steps for creating good issues or pull requests.
20 |
21 | Please take a moment to understand the LDPL compiler source code if you are submiting a new feature to it. It's made of just three files: `ldpl.cpp` where the compiler is mostly written, `ldpl.h` with variable and function definitions (and an occasional struct) and `ldpl_lib.cpp` that is a library that is included in every binary compiled with the LDPL compiler, that includes definitions for many functions used within the language.
22 |
23 | LDPL is one big `if` statement, with one `if` for every statement of the language. Check the ones that are already written if you want to submit new statements, is really easy. **Test your new statements** before submiting them, please!
24 |
25 | If you are writing documentation, try to make it as clear as possible. It's nice when you don't know nothing about a certain technology and you find a tutorial that explains everything from the ground up in a way you can understand without reading pages and pages of man documentation and shady html files. You love the guy who wrote that tutorial. Be that guy.
26 |
27 | If you are writing LDPL examples, please comment them. Comment every line if you deem it necessary. But make them as clear as possible.
28 |
29 | If you are writing LDPL software, please try to make your code clear as well. It's your code, though, we won't bite you if you don't want to make it nice.
30 |
31 | If you are submiting issues, PLEASE be as clear as possible. Tell us where the error happened, tell us what were you doing, what code triggered it, etc. It just doesn't work when someone posts "please fix this function it doesn't work thx bye".
32 |
33 | If you are submiting a drawing, feel free to take any artistic license you like. "Look mom, I drew the LDPL dinosaur!".
34 |
35 | If you are submiting LDPL fanfiction, please ask yourself why am I doing this. Then kindly create a pull request.
36 |
37 | ### Links to external documentation, mailing lists, or a code of conduct.
38 |
39 | - Official LDPL Website: [https://www.ldpl-lang.org/](https://www.ldpl-lang.org/)
40 | - LDPL Reference: [https://docs.ldpl-lang.org/](https://docs.ldpl-lang.org/)
41 | - LDPL Reddit Community: [https://reddit.com/r/ldpl](https://reddit.com/r/ldpl)
42 | - IRC Channel: #ldpl at [irc.freenode.net](http://irc.freenode.net)
43 | - [Dinosaur Tamers Code](/CODE_OF_CONDUCT)
44 | - You can also send me an email at *mdelrio (at) dc.uba.ar*.
45 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:latest as build_stage
2 |
3 | RUN apk add --no-cache make g++ cmake
4 |
5 | WORKDIR /app
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | [**LDPL**](https://www.ldpl-lang.org/) is a powerful, general-purpose compiled programming language designed
13 | from the ground up to be excessively **expressive**, **readable**, **fast** and **easy** to learn.
14 | It mimics plain English, inspired by the best aspects of older programming languages like COBOL and FoxPRO.
15 | It even supports UTF-8 out of the box.
16 |
17 | This repository contains the source code and [releases](https://github.com/Lartu/ldpl/releases) of the LDPL compiler.
18 |
19 | ### Example Code
20 |
21 | ```ruby
22 | # Hello There Example
23 | DATA:
24 | name IS TEXT
25 | i IS NUMBER
26 |
27 | PROCEDURE:
28 | DISPLAY "Hello there, what's your name?"
29 | ACCEPT name
30 | FOR i FROM 0 TO 10 STEP 1 DO
31 | DISPLAY "你好, " name "!" CRLF
32 | REPEAT
33 | ```
34 |
35 | This code greets the user and asks them to enter their name, then it greets them in Chinese, ten times. Easy as pie and super legible.
36 |
37 | LDPL supports multiple datatypes and programming patterns. It is a full-fledged programming language.
38 | Check the [documentation](https://docs.ldpl-lang.org) for more information, and the [official website](https://www.ldpl-lang.org/)
39 | to see other examples, including a BF interpreter and Bellman-Ford's Algorithm!
40 |
41 | ## LDPL Philosophy
42 |
43 | LDPL is a language designed to be easy to understand, learn, write, and use. We believe coding should be like that. Compiling code should be effortless and straightforward: a single, flagless command should be enough to compile any source. Every statement in the language should perform one, and only one, function, independent of the context. The compiler should handle complex, low-level tasks like encoding, sockets, floating-point number comparison, etc., transparently to the user. Difficult things shouldn’t feel difficult.
44 |
45 | We understand that this philosophy may result in longer source code, more verbose statements, and additional steps to reach a solution, but it aims to make coding in LDPL easier and more enjoyable than in other languages.
46 |
47 | As one user once said:
48 |
49 | >*"Usually when I'm programming, I feel like I'm in a big fancy jet and there's a lot of turbulence and it's not going well but then all of a sudden it's smooth air again and the drink cart comes along and I get a ginger ale and it's great. But with LDPL, I feel like I'm a cub scout out in the woods with a box of matches and a hatchet and my Scout's Handbook (the LDPL Docs) just exploring and figuring it out as I go. Whenever I run into a problem I just check my handbook and, sure enough, there's a solution right there waiting for me!"*
50 |
51 | We want LDPL to be a language you’ll love — not because it lets you do many things in one line or because it’s modern, but because it’s designed to stay by your side and reassure you that everything will be okay, even when things look rough.
52 |
53 | ## Installing LDPL
54 |
55 | To install LDPL, clone this repository, navigate to the cloned directory, open a terminal, and run `make` followed by `make install`. That's it!
56 |
57 | You can also optionally run `make man` to re-build the man documentation (PHP is required for this).
58 | This process will install LDPL and its documentation (`man ldpl`) on your system.
59 | LDPL only requires **C++11** to compile and run.
60 |
61 | ### Alternative Installation Methods
62 |
63 | Bear in mind that these other installation methods may install an outdated version of LDPL, as they are maintained by external contributors.
64 | Make sure that the version you are about to install matches the last LDPL release.
65 |
66 | * **🍺 Homebrew**: If you prefer [Homebrew](https://brew.sh), you can install LDPL by running `brew install ldpl`.
67 | * **🐦 Snap**: If you prefer [Snap](https://snapcraft.io/), you can install LDPL by running `snap install ldpl-lang`.
68 |
69 |
70 | ## Learning LDPL and Read the Docs
71 |
72 | 
73 |
74 | If you want to learn how to code in LDPL, there is a brief tutorial available at [https://learnxinyminutes.com/docs/ldpl](https://learnxinyminutes.com/docs/ldpl). Additionally, be sure to check out the examples on the official LDPL website.
75 |
76 | [The **LDPL Documentation** is available here](https://docs.ldpl-lang.org/).
77 | The documentation is also uploaded to the [docs](docs) folder of this repository and can be read and modified from there.
78 |
79 | The LDPL documentation can also be found on your system using `man ldpl` when you install LDPL using `make install`.
80 | The man page is also available in the [man](/man) folder of this repository.
81 |
82 | ## How to use this compiler
83 |
84 | To use the compiler, you must have a C++ compiler installed on your system and ensure it is accessible as `c++` in your PATH.
85 | The LDPL compiler translates LDPL code into C++ code, making this a necessary requirement for it to function.
86 |
87 | Once the compiler is set up, write some LDPL source code — for example, `source.ldpl`.
88 | Then, compile the source code using `ldpl source.ldpl`. The compiled executable binary will be saved as `source-bin`.
89 | For more information about the compiler, run `ldpl -h` or refer to the [docs](https://docs.ldpl-lang.org/#the-ldpl-compiler).
90 |
91 | ### C++ extensions
92 |
93 | LDPL supports extensions written in C++. Extensions are `.cpp`, `.o`, or `.a` files that can be imported into your program.
94 |
95 | For a guide on writing and building C++ extensions, refer to the [LDPL Docs](https://docs.ldpl-lang.org/cppext/).
96 |
97 | ## How can I contribute to LDPL?
98 |
99 | 
100 |
101 | There are many ways to contribute to the LDPL project.
102 | You can fix bugs, open issues, write examples, develop software in LDPL, and more.
103 | Check the [contribution guide](https://www.ldpl-lang.org/contribute.html) for details.
104 | Almost any contribution is welcome — even simply telling your friends about LDPL is an easy and valuable way to help.
105 |
106 | Contributors are expected to adhere to the [LDPL Code of Conduct](https://www.ldpl-lang.org/conduct.html). In short: be nice to everyone.
107 |
108 | ### Community
109 |
110 | If you’d like to chat with us, join the LDPL community in the [LDPL Programming Language **Telegram** Group](https://t.me/ldpllang)!
111 | There's also [r/LDPL](https://reddit.com/r/LDPL) on **Reddit**.
112 |
113 | You are also welcome to create new LDPL channels on any other platform.
114 |
115 | ## Merchandise
116 |
117 | Due to popular demand, [LDPL merchandise is available](https://www.teepublic.com/user/lartu). We’ve partnered with TeePublic to offer a variety of items, from shirts and mousepads to coffee mugs.
118 |
119 | ## Getting Help
120 |
121 | f you have any questions about the LDPL project, feel free to submit an issue in this repository, visit the [LDPL website](https://www.ldpl-lang.org) or join the community channels mentioned in the previous section. Remember, there are no dumb questions — just ask!
122 |
123 | ## 📜 License
124 |
125 | The LDPL Compiler is distributed under the Apache 2.0 License.
126 | All LDPL Dinosaur logos were created by [Lartu](https://github.com/Lartu) and are released under the Creative Commons Attribution 4.0 International (CC BY 4.0) license.
127 |
--------------------------------------------------------------------------------
/docs/arithmetic.md:
--------------------------------------------------------------------------------
1 | !!!Note
2 | While this section is up-to-date and complete, it has to be reformated
3 | to be easier on the eyes. All UPPERCASE statement names and code should
4 | be changed to lowercase.
5 |
6 | ## `IN _ SOLVE _`
7 |
8 | The `IN - SOLVE` statement will solve a simple arithmetic expression and place the result in a NUMBER variable. Only `+`, `-`, `/`, `*` operators, NUMBER values, and TEXT values can be used in a MATH-EXPRESSION. Other LDPL arithmetic functions, like `floor` and `modulo`, are not supported by this statement and should be used as standalone statements. TEXT values will be implicitly converted to NUMBERs using the same algorithm as the one used in `store _ in _`.
9 |
10 | Spaces **must** be used to separate numbers, variables and operators.
11 |
12 | As in actual arithmetic, `*` and `/` have higher precedence than `+` and `-` , while parens `()` can be used to group expressions.
13 |
14 | **Syntax:**
15 |
16 | ```coffeescript
17 | IN SOLVE
18 | ```
19 |
20 | **Example:**
21 |
22 | ```coffeescript
23 | IN myNumVariable SOLVE 1 + 1
24 | ```
25 |
26 | Will set the value of `myNumVariable` to `2`.
27 |
28 | **Area of Circle:**
29 |
30 | ```coffeescript
31 | DATA:
32 | Radius is NUMBER
33 | Area is NUMBER
34 |
35 | PROCEDURE:
36 | DISPLAY "Enter Radius: "
37 | ACCEPT Radius
38 |
39 | IN Area SOLVE 3.14159 * (Radius * Radius)
40 | DISPLAY "Area is: " Area CRLF
41 | ```
42 |
43 | Outputs:
44 |
45 | ```text
46 | Enter Radius: 0.5
47 | Area is: 0.7853975
48 | ```
49 |
50 | ## `FLOOR`
51 |
52 | The `FLOOR` statement rounds down the value of NUMBER-VAR to the nearest lower integer.
53 |
54 | **Syntax:**
55 |
56 | ```coffeescript
57 | FLOOR
58 | ```
59 |
60 | ## `CEIL`
61 |
62 | The `CEIL` statement rounds up the value of NUMBER-VAR to the nearest higher integer.
63 |
64 | **Syntax:**
65 |
66 | ```coffeescript
67 | CEIL
68 | ```
69 |
70 | ## `FLOOR _ IN _`
71 |
72 | The `FLOOR _ IN _` statement rounds down the value of NUMBER-VAR to the nearest lower integer
73 | and stores the result in a NUMBER variable.
74 |
75 | **Syntax:**
76 |
77 | ```coffeescript
78 | FLOOR IN
79 | ```
80 |
81 | ## `CEIL _ IN _`
82 |
83 | The `CEIL _ IN _` statement rounds up the value of NUMBER-VAR to the nearest higher integer
84 | and stores the result in a NUMBER variable.
85 |
86 | **Syntax:**
87 |
88 | ```coffeescript
89 | CEIL IN
90 | ```
91 |
92 | ## `ADD _ AND _ IN _`
93 |
94 | The `ADD` statement adds two NUMBER values and stores the result in a NUMBER variable.
95 |
96 | **Syntax:**
97 |
98 | ```coffeescript
99 | ADD AND IN
100 | ```
101 |
102 | ## `SUBTRACT _ FROM _ IN _`
103 |
104 | The `SUBTRACT` statement subtracts two NUMBER values and stores the result in a NUMBER variable.
105 |
106 | **Syntax:**
107 |
108 | ```coffeescript
109 | SUBTRACT FROM IN
110 | ```
111 |
112 | ## `MULTIPLY _ BY _ IN _`
113 |
114 | The `MULTIPLY` statement multiplies two NUMBER values and stores the result in a NUMBER variable.
115 |
116 | **Syntax:**
117 |
118 | ```coffeescript
119 | MULTIPLY BY IN
120 | ```
121 |
122 |
123 | ## `DIVIDE _ BY _ IN _`
124 |
125 | The `DIVIDE` statement divides two NUMBER values and stores the result in a NUMBER variable.
126 |
127 | **Syntax:**
128 |
129 | ```coffeescript
130 | DIVIDE BY IN
131 | ```
132 |
133 | ## `MODULO _ BY _ IN _`
134 |
135 | The `MODULO` statement calculates the remainder of the modulo operation between two NUMBER values and stores the result in a NUMBER variable.
136 |
137 | **Syntax:**
138 |
139 | ```coffeescript
140 | MODULO BY IN
141 | ```
142 |
143 |
144 | ## `GET RANDOM IN _`
145 |
146 | The `GET RANDOM` statement stores a random value between 0 \(inclusive\) and 1 \(noninclusive\) in a NUMBER variable.
147 |
148 | **Syntax:**
149 |
150 | ```coffeescript
151 | GET RANDOM IN
152 | ```
153 |
154 | ## `RAISE _ TO _ IN _`
155 |
156 | The `RAISE TO IN ` statement calculates `a^b` and stores the result in `c`.
157 |
158 | **Syntax:**
159 |
160 | ```coffeescript
161 | RAISE TO IN
162 | ```
163 |
164 | ## `LOG _ IN _`
165 |
166 | The `LOG _ IN _` statement calculates the natural logarithm of a NUMBER and stores the result in a NUMBER variable.
167 |
168 | **Syntax:**
169 |
170 | ```coffeescript
171 | LOG IN
172 | ```
173 |
174 | ## `SIN _ IN _`
175 |
176 | The `SIN _ IN _` statement calculates the sine of a NUMBER and stores the result in a NUMBER variable.
177 |
178 | **Syntax:**
179 |
180 | ```coffeescript
181 | SIN IN
182 | ```
183 |
184 | ## `COS _ IN _`
185 |
186 | The `COS _ IN _` statement calculates the cosine of a NUMBER and stores the result in a NUMBER variable.
187 |
188 | **Syntax:**
189 |
190 | ```coffeescript
191 | COS IN
192 | ```
193 |
194 | ## `TAN _ IN _`
195 |
196 | The `TAN _ IN _` statement calculates the tangent of a NUMBER and stores the result in a NUMBER variable.
197 |
198 | **Syntax:**
199 |
200 | ```coffeescript
201 | TAN IN
202 | ```
--------------------------------------------------------------------------------
/docs/cppext.md:
--------------------------------------------------------------------------------
1 | ## About C++ Extensions
2 |
3 | **C++ extensions** are packages of code written in C++ that can interface with LDPL
4 | code and be added to your LDPL projects.
5 |
6 | Because LDPL programs compile down to C++, there is no need for a translation layer or bridge: extensions can be included directly into LDPL programs and manipulate, share, and access subprocedures and variables natively. All that's needed is a few naming conventions on the C++ side and the use of the `external` syntax for variables and subprocedures on the LDPL side. External variable and sub-procedure naming conventions are explained in detail in the **Naming Schemes** section of this documentation.
7 |
8 | Extensions contain sub-procedures and variables that are considered to be _external_.
9 | This means that they are not part of an LDPL source code and thus must be accessed and called in a different way to what you might be used to. **External sub-procedures** should be called using the `call external` statement. While it is explained in greater detail in the **Control Flow Statements** section of this documentation, the statement works just like the normal `call` statement with the exception that it doesn't accept parameters.
10 |
11 | ```c++
12 | // In C++
13 | void CPPFUNCTION(){
14 | //...
15 | }
16 | ```
17 |
18 | ```coffeescript
19 | # In LDPL
20 | call external cppFunction
21 | ```
22 |
23 | **External variables** (declared in a C++ file) should be **re-declared** again in your LDPL data section with the same type they have in the C++ file, appending to their type the `extenal` keyword. This allows programmers to extend LDPL with new features or to wrap 3rd party libraries and re-use their functionality.
24 |
25 | ```c++
26 | // In C++
27 | ldpl_number MYNUMBER = 9;
28 | ```
29 |
30 | ```coffeescript
31 | # In LDPL
32 | data:
33 | myNumber is external number
34 | ```
35 |
36 | This will be explained in greater detail in the following sections.
37 |
38 | ## Writing C++ Extensions
39 |
40 | If LDPL lacks some feature that C++ might offer, for example graphics or networking,
41 | you might find yourself in the need of writing a C++ extension (provided an extension
42 | for what you are looking for has not been already written, of course).
43 |
44 | Extensions can create variables and functions that are accessible from LDPL through the `call external` and `external` data type keyword, as explained in the previous section. Typically, all you need is a single `.cpp` file that you include from your LDPL source using the `extension` keyword (explained in the **Code Structure** section of this documentation), but you may also include `.o` files, `.a` files, or any combination of them all.
45 |
46 | ### Functions
47 |
48 | To create a function in C++ that can be called from an LDPL program, you must follow four rules:
49 |
50 | 1. The function type must be `void(void)`, ex: `void MY_FUNC();`
51 | 2. The function name must conform to LDPL's external identifier naming conventions explained in the **Naming Schemes** section of this documentation.
52 | 3. The function must not take any parameters.
53 | 4. The function must not return any values.
54 |
55 | Because LDPL does not _know_ the name of any variables or functions declared in non-LDPL files, it allows the programmer to call any function or variable, existing or not, by using the `external` syntax. If the variable or function you are trying to access does not exist, the C++ linker will throw a nasty error. Also, all C++ variable and function names must contain only `A-Z`, `0-9`, and the `_` character. Every character on the LDPL side will be converted to upper case, and non alpha-numeric characters will be converted to an underscore \(`_`\) when referencing the C++ side (again, as stated in the **Naming Schemes** section of this documentation).
56 |
57 | **Example:**
58 |
59 | For example, this function in a file called **add.cpp**
60 |
61 | ```cpp
62 | void PROMPT_ADD()
63 | {
64 | int a, b, sum;
65 | cout << "1st number: ";
66 | cin >> a;
67 | cout << "2nd number: ";
68 | cin >> b;
69 | cout << "sum: " << sum << end;
70 | }
71 | ```
72 |
73 | can be accessed from LDPL in the following way
74 |
75 | ```coffeescript
76 | external "add.cpp"
77 |
78 | procedure:
79 | call external prompt_add
80 | ```
81 |
82 | ### Variables
83 |
84 | To create a variable in a C++ extension that can be accessed from LDPL code, you must follow two rules:
85 |
86 | 1. The variable's name must conform to the LDPL external identifier naming convention stated in the **Naming Schemes** section of this documentation.
87 | 2. The C++ type of the variable must match the type used by LDPL for the data type represented by that variable.
88 |
89 | The first rule should be familiar from the previous section: all C++ variable and function names must contain only `A-Z`, `0-9`, and the `_` character. Everything else on the LDPL side will get converted to an underscore \(`_`\).
90 |
91 | For the second rule, the LDPL compiler provides the data types `ldpl_number`, `ldpl_text`, `ldpl_list` and `ldpl_map`. These will be explained in greater detail in the next section.
92 |
93 | **Example:**
94 |
95 | Declaring variables is easy on the C++ side:
96 |
97 | ```cpp
98 | ldpl_text NAME;
99 | ldpl_number AGE;
100 | ldpl_text STREET_ADDRESS;
101 | ```
102 |
103 | These will be available to an LDPL program when declared as external in its `data:` section:
104 |
105 | ```coffeescript
106 | data:
107 | name is external text
108 | age is external number
109 | street_address is external text
110 | ```
111 |
112 | ### The LDPL Data Types
113 |
114 | The LDPL compiler provides the data types `ldpl_number`, `ldpl_text`, `ldpl_list` and `ldpl_map`. To use
115 | them, just use them as if they were declared and the LDPL compiler will add the declarations and definitions for you
116 | once the extension is compiled.
117 |
118 | * The `ldpl_number` data type is just a rename for `double`.
119 | * The `ldpl_text` data type is a special UTF-8 string class used just like the regular C++ `std::string` class, with the exception that if you want to get an `std::string` from an `ldpl_text` you can call the `ldpl_text` method `ldpl_text::str_rep()` to get the `std::string` representation of an `ldpl_text`. Just like you would use `std::string::c_str()` to get the C `char*` representation of an `std::string`.
120 | * The `ldpl_list` data type represents an `std::vector` with a special `[]` operator overload.
121 | * The `ldpl_map` data type represents an `std::unordered_map` with special `[]` operator overloadings.
122 |
123 | You can read the definition of these data types on the [ldpl_lib.cpp](https://github.com/Lartu/ldpl/blob/master/src/ldpl_lib.cpp) file of the LDPL source repository.
124 |
125 | ### Accessing Variables in C++ Functions
126 |
127 | Since LDPL and C++ are using the same variable when you use the `external` keyword (say, for example, `MY_VAR` in C++ and external `my-var` in LDPL), any changes you make to the content of said variables are shared. Use them just like you would use any regular variable, both in C++ and LDPL.
128 |
129 | ```cpp
130 | ldpl_number A, B, SUM;
131 | void ADD()
132 | {
133 | SUM = A + B;
134 | }
135 | ```
136 |
137 | ```coffeescript
138 | data:
139 | a is external number
140 | b is external number
141 | sum is external number
142 |
143 | procedure:
144 | store 100 in a
145 | store 250 in b
146 | call external add
147 | display sum lf
148 | ```
149 |
150 | Building and running this program will print `350`.
151 |
152 | ## Building C++ Extensions
153 |
154 | Extensions are easy to build: when compiling your LDPL program, use the `extension` keyword (explained in detail in the **Code Structure** section of this documentation) to add `.cpp` files, `.o` files, or `.a` files to your LDPL project. They will be included in your program and become available using the `external` statements.
155 |
156 | If your C++ extension files require extra flags to be passed to the C++ compiler in order to compile \(for example, `-lSDL` when working with SDL\) you can use the `flag` statement (explained in detail in the **Code Structure** section of this documentation) to pass flags to the C++ compiler.
157 |
158 | :::coffeescript
159 | external "otherFile.cpp"
160 | flag "-fpermisive"
161 | flag "-lSDL2"
162 | data:
163 | #...
164 | procedure:
165 | #...
166 |
167 | ## "Hello World" C++ Example
168 |
169 | File **simple.cpp**:
170 | ```cpp
171 | #include
172 | void SIMPLE(){
173 | std::cout << "Very simple!" << std::endl;
174 | }
175 | ```
176 |
177 | File **simple.ldpl**:
178 | ```coffeescript
179 | extension "simple.cpp"
180 |
181 | procedure:
182 | call external simple
183 |
184 | ```
185 |
186 | Console:
187 |
188 | ```bash
189 | $ ldpl simple.ldpl
190 | LDPL: Compiling...
191 | * File(s) compiled successfully.
192 | * Saved as simple-bin
193 | $ ./simple-bin
194 | Very simple!
195 | ```
196 |
197 | ## External Sub-procedures
198 |
199 | Sometimes when writing C++ Extensions you'll find yourself in the need of declaring a function in C++ but coding it in LDPL. This is the opposite of writing C++ functions and calling them from LDPL, it's writing LDPL sub-procedures and calling them from C++.
200 |
201 | These C++ callable sub-procedures are called **external sub-procedures**, as they can be called from an external medium.
202 |
203 | In order to declare an external sub-procedure, you must first forward-declare it in your C++ source code. Say, for example, that you want to declare a sub-procedure called `helloWorld`. In your C++ you should write the following line:
204 |
205 | ```cpp
206 | void HELLOWORLD();
207 | ```
208 |
209 | Note that external sub-procedures **cannot receive any kind of parameters** and must be declared as `void`. You may then call the external sub-procedure from C++ code like this:
210 |
211 | ```cpp
212 | int myCPPFunction(){
213 | HELLOWORLD();
214 | return 1;
215 | }
216 | ```
217 |
218 | Once that's taken care of, you can declare your external sub-procedure as any other sub-procedure in LDPL by prepending the identifier `external` to the sub-procedure declaration:
219 |
220 | ```coffeescript
221 | external sub-procedure myExternalSub
222 | #...
223 | end sub-procedure
224 | ```
225 |
226 | or just
227 |
228 | ```coffeescript
229 | external sub myExternalSub
230 | #...
231 | end sub
232 | ```
233 |
234 | These sub-procedures can be called from LDPL like you would call any other sub-procedure, but their names must follow the external identifier naming scheme detailed in the **Naming Schemes** section of this documentation as any other C++ interfacing identifier.
235 |
236 |
237 | ## External Variables
238 |
239 | Variables defined in extensions can be accessed by prefacing their data type declaration with the `external` keyword. This must occur in the **data** section of your LDPL code. Once an external variable is declared, it can be used just like any other LDPL variable.
240 |
241 | **Syntax:**
242 |
243 | ```text
244 | is external
245 | ```
246 |
247 | **Example:**
248 |
249 | ```coffeescript
250 | data:
251 | rl-prompt is external text
252 | window.size is external number
253 | ```
254 |
255 |
256 |
--------------------------------------------------------------------------------
/docs/data.md:
--------------------------------------------------------------------------------
1 | ## The Data Section
2 |
3 | The **data** section is where global variables are declared (you can use them
4 | anywhere in your program). If no variables are declared, the data section can
5 | be skipped altogether.
6 |
7 | The data section is defined and preceded by the `data:` keyword.
8 | An empty data section looks like this:
9 |
10 | :::coffeescript
11 | data:
12 |
13 | On every line within the data section (that is, on every line after the `data:`
14 | keyword and before the `procedure` keyword) one and only one variable can be
15 | declared.
16 |
17 | The syntax for declaring a variable in LDPL is:
18 |
19 | :::coffeescript
20 | variable-name is data-type
21 |
22 | **Variable naming schemes** and **data types** will be explained later on this
23 | document.
24 |
25 | A data section cannot contain anything but variable declarations, comments and
26 | empty lines. An example data section may end up looking like this:
27 |
28 | :::coffeescript
29 | data: # this is an example data section
30 | foo is number
31 | bar is text map
32 |
33 | # foobar is my number list
34 | foobar is number list
35 |
36 | ## Variable Data Types
37 |
38 | LDPL natively supports the scalar **number** and **text** data types. It also
39 | supports containers of said scalar types: **maps** and **lists**, combined in
40 | any way.
41 |
42 | Variables may be declared, as stated above, using the syntax:
43 |
44 | :::coffeescript
45 | variable-name is data-type
46 |
47 | within the data section. The name of a data type is composed of either a scalar
48 | data type name (**number** or **text**) or a container type plus one or more
49 | scalar or container type names. For example:
50 |
51 | :::coffeescript
52 | foo is number
53 | bar is text
54 | foobar is map of lists of text
55 |
56 | In the case above, **foobar** is a **map of lists of text values**.
57 |
58 | ### The Number Data Type
59 |
60 | The **number** data type, as its name suggests, depicts numeric values.
61 | It's recommended that it be represented internally as a binary64
62 | double-precision floating-point format number as defined by the IEEE 754.
63 |
64 | Both variables and numeric constants can be members of the number type.
65 |
66 | Valid number literals must begin with a decimal value (for example 5 or 0.12,
67 | .12 wouldn't be a valid number) and may be preceded by a minus sign for
68 | negative numbers (-5, -567.912). Numbers may not be preceded by a plus sign
69 | (+5 is not a valid number literal). The literal -0 is implicitly transformed
70 | into 0.
71 |
72 | :::coffeescript
73 | -231897.123 # is an example number
74 |
75 | ### The Text Data Type
76 |
77 | The **text** data type, as its name suggests, represents alphanumeric strings.
78 | In the interest of supporting as many locales as possible, texts should be utf-8
79 | encoded to be compatible with Unicode. A text maximum length for text values is
80 | explicitly not defined and it should be limited only by the amount of available
81 | memory on the system. Strings in LDPL are enclosed between two "quotes".
82 |
83 | :::coffeescript
84 | "This is an example string!"
85 |
86 | LDPL strings may contain multiple escape sequences / control characters in
87 | them. Each escape sequence counts as only one character. The available escape
88 | sequences are:
89 |
90 | * `\a` = alert (bell)
91 | * `\b` = backspace
92 | * `\t` = horizontal tab
93 | * `\n` = newline / line feed
94 | * `\v` = vertical tab
95 | * `\f` = form feed
96 | * `\r` = carriage return
97 | * `\e` = non-standard GCC escape
98 | * `\0` = null byte
99 | * `\\` = \ character
100 | * `\"` = " character
101 |
102 | For example, the string `"hello,\nworld"` will be displayed as
103 |
104 | :::text
105 | hello,
106 | world
107 |
108 | when printed to the console.
109 |
110 | ### The List Data Type
111 |
112 | The **list** data type is a collection of number or text values, or containers
113 | of possibly more containers of said types. Values can be pushed to lists and
114 | then be accessed and modified using the `:` operator. List indexes consist of
115 | integer numbers. The first index of a list is index 0, and the rest count up to
116 | the length of the list minus one.
117 |
118 | Lists, as collections of number or text values (or collections of said types),
119 | can only have one defined type at any given time: text or number. A single list
120 | is not capable of storing both numeric and alphanumeric values.
121 |
122 | :::coffeescript
123 | data:
124 | foo is number list # This is a list
125 |
126 | procedure:
127 | push 10 to foo
128 | display foo:0 lf
129 |
130 | !!!note
131 | The `display` statement prints values to the screen. While it will be
132 | explained in more detail later, the line
133 |
134 | :::python
135 | `display foo:0 lf`
136 |
137 | prints
138 | the value of `foo:0` (the index `0` of the list `foo`) followed by
139 | a line break (`lf`).
140 |
141 | In most other languages, you may have to declare a list and specify how many
142 | elements or components it contains. In such languages, the declaration causes a
143 | contiguous block of memory to be allocated for that many elements. LDPL lists,
144 | however, are different: they are dynamic. This means that you can store as many
145 | values as you want in a single list without fear of running out of place (of
146 | course, this is limited by the memory allocated by your operating system for
147 | your LDPL program).
148 |
149 | Suppose you store the values `"hi"`, `"there"`, `"I love"` and
150 | `"LDPL, it's great!"` in a `text list`, in that particular order. Then the
151 | contents of the list and the **index** associated with each **element** will be
152 |
153 | | Index | Element |
154 | | :---: | :---: |
155 | | 0 | `"hi"` |
156 | | 1 | `"there"` |
157 | | 2 | `"I love"` |
158 | | 3 | `"LDPL, it's great!"` |
159 |
160 | We have shown the pairs in order because their order is relevant: if you added
161 | a new element to the list, it would be inserted after the last element, thus
162 | being associated with index `4`.
163 |
164 | To add values to a list, you must first push them to the list. For example,
165 | if you want to add the numbers `10`, `20` and `30` to a `number list`, your
166 | code should look like this:
167 |
168 | :::coffeescript
169 | data:
170 | myList is number list
171 | procedure:
172 | push 10 to myList # 10 is stored in index 0 of myList
173 | push 20 to myList # 20 is stored in index 1 of myList
174 | push 30 to myList # 30 is stored in index 2 of myList
175 |
176 |
177 | Values in lists can be stored and accessed just like any other variable
178 | (see the **store - in** statement for further details) using the `:` operator.
179 | This operator indicates what index of the list we are writing to or reading
180 | from. Here we declare a `number list` and store the values `5` and `-10.2` in
181 | it, and then replace the number `5` by the number `890`:
182 |
183 | :::coffeescript
184 | data:
185 | myList is number list
186 | procedure:
187 | push 5 to myList
188 | # 5 is stored in index 0 of myList
189 | push -10.2 to myList
190 | # -10.2 is stored in index 1 of myList
191 | store 890 in myList:0
192 | # We store 890 in index 0 of myList, thus replacing the 5
193 |
194 | !!!note
195 | The `push` statement adds a value at the end of a list. Also, the `store
196 | - in` statement stores a value in a variable. These two statements will
197 | be explained in more detail in their respective sections of this document.
198 |
199 | Please note that as a list is **variable** that's a collection of values, a
200 | single index of a list is a variable in itself. This means that any subindex
201 | of a list that resolves to a scalar value be used in any position where you
202 | could use a variable of the same type of that value. So, if you have something
203 | like this:
204 |
205 | ```coffeescript
206 | store in
207 | ```
208 |
209 | You could use a `number list` with a defined sub-index \(for example, in the
210 | example above, `myList:0`\) where it says number-var, just like in
211 | the `store - in` examples in the code extracts above.
212 |
213 | In the **list statements** section, you'll find a collection of statements that
214 | can be used to work with lists.
215 |
216 | ### The Map Data Type
217 |
218 | The **map** data type is a collection of number or text values. Maps
219 | superficially resemble lists but with fundamental differences. The biggest one
220 | is that any number or string in LDPL may be used as an array index, not just
221 | consecutive integers. Also, values in maps have no order.
222 |
223 | :::python
224 | data:
225 | foo is number map # This is a map
226 |
227 | procedure:
228 | store 19 in foo:"hi there!"
229 | display foo:"hi there!" lf
230 |
231 | Maps, as collections of number or text values (or collections of said types),
232 | can only have one defined type at any given time: text or number. A single map
233 | is not capable of storing both numeric and alphanumeric values.
234 |
235 | Unlike lists, maps are **associative**. This means that each map is a
236 | collection of pairs: a key and its corresponding element. For example,
237 | you could have a `number map` with the following contents:
238 |
239 | | Key | Element |
240 | | :---: | :---: |
241 | | 4 | 30 |
242 | | 2 | 10 |
243 | | "Hi there!" | -56.3 |
244 | | "99ldplrocks89" | 0 |
245 |
246 | We have shown the pairs in jumbled order because their order is irrelevant.
247 | One advantage of maps is that new pairs can be added at any time. maps can be
248 | sparse: they can have missing keys \(say for example you have keys 1 and 5, but
249 | don't have keys 2, 3 and 4\). Another consequence of maps is that the keys
250 | don't necessarily have to be positive integers. Any number, or even a string,
251 | can be a key.
252 |
253 | Values in maps can be stored and accessed just like any other variable
254 | (see the **store - in** statement for further details) using the `:` operator.
255 | This operator indicates what key of the map we are writing to or reading from.
256 | Here we declare a `number map` and store the values `5` and `-10.2` in the
257 | keys `1` and `5`, respectively.
258 |
259 | :::coffeescript
260 | data:
261 | myMap is number map
262 | procedure:
263 | store 5 in myMap:1 #Stores 5 in key 1 of myMap
264 | store -10.2 in myMap:5 #Stores -10.2 in key 5 of myMap
265 |
266 | As stated before, map keys don't always have to be constant numbers.
267 | They can also be number variables, text and text variables, or even sub-indexes
268 | of lists or elements from other maps. For example:
269 |
270 | :::coffeescript
271 | data:
272 | myMap is number map
273 | myOtherMap is number map
274 | myVar is number
275 |
276 | procedure:
277 | store 17 in myVar
278 | store 1 in myMap:"hello"
279 | #Stores 1 in key "hello" of myMap
280 | store 7 in myMap:myVar
281 | #Stores 7 in a key equal to the current value of myVar
282 | store 3 in myMap:myOtherMap:4
283 | #Stores 3 in a key of equal value to the key of myMap with value equal to
284 | #key 4 of myOtherMap
285 |
286 | In fact, when you use a number value as a subindex for a map, it is silently
287 | casted into a text value. For example, `myMap:1` will be interpreted \(an thus,
288 | the same\) as `myMap:"1"`.
289 |
290 | Please note that as a map is **variable** that's a collection of values,
291 | a single key of a map is a variable in itself. This means that any key of a
292 | map that resolves to a scalar value can be used in any position where you could
293 | use a variable of the same type of that value. So, if you have something like
294 | this:
295 |
296 | ```coffeescript
297 | store in
298 | ```
299 |
300 | You could use a `number map` with a particular key where it says number-var,
301 | just like in the `store - in` examples in the code extracts above
302 | \(for example `myMap:"hello"`\).
303 |
304 | As you'll see in the **Default Variable Values** section, you can access
305 | undeclared keys of a map, just like if they were declared.
306 | See the following example:
307 |
308 | ```coffeescript
309 | data:
310 | myMap is number map
311 | procedure:
312 | display myMap:99
313 | ```
314 |
315 | In the example above, `0` will be printed and no errors displayed during
316 | compilation, even though the key `99` of `myMap` hasn't been explicitly
317 | declared. This is because when you try to access an element that hasn't
318 | been declared yet, LDPL declares it for you and initializes it to its type
319 | default value.
320 |
321 | It's important to note that this very feature is a double-edged weapon. While
322 | you can use it to access uninitialized map keys, you cannot check if a value
323 | exists in a map without initializing it if it wasn't there before. Statements
324 | like **store key count of** and **store keys of** are provided as means to
325 | overcome this situation.
326 |
327 | In the **map statements** section, you'll find a collection of statements that
328 | can be used to work with maps.
329 |
330 | !!!warning
331 | In older versions of LDPL, **map**s were called **vector**s.
332 | Starting from LDPL 3.1.0 Diligent Dreadnoughtus, they have been renamed
333 | to reflect the real data structure they represent. While it might still be
334 | possible to call them vectors in code, and legacy code that declares maps
335 | as vectors is and will continue to be supported, this nomenclature is
336 | **deprecated** and shouldn't be used anymore.
337 |
338 | ## Multicontainers
339 |
340 | As stated before, _"The name of a data type is composed of either a scalar
341 | data type name (**number** or **text**) or a container type plus one or more
342 | scalar or container type names."_ This means that you can declare variables like:
343 |
344 | :::coffeescript
345 | myVariable is list of lists of text
346 | myOtherVariable is map of lists of maps of maps of lists of maps of numbers
347 | pleaseStop is list of maps of maps of lists of maps of maps of maps of lists of lists of maps of lists of lists of text
348 |
349 | These variables are called **multicontainers**. Multicontainers hold other
350 | containers, which can hold more containers or scalar values to an arbitrary
351 | depth. For example, a `map of lists of text` is a **map** that holds **lists**
352 | of **text** values. You may access a value stored in a `map of lists of text`
353 | like so:
354 |
355 | :::coffeescript
356 | display foo:"hi":0
357 |
358 | where `hi` is the key used to access a list stored in the map, and `0` the
359 | index used to access a text value stored in the list that was stored in the
360 | map.
361 |
362 | If you want to push a list to a `list of lists` or a map to a `list of maps` you
363 | must use the `push list to _` and `push map to _` statements, respectively:
364 |
365 | :::coffeescript
366 | data:
367 | listOfMaps is list of maps of texts
368 | listOfLists is list of lists of texts
369 | procedure:
370 | push map to listOfMaps
371 | store "Hello!" in listOfMaps:0:"hi!"
372 | # Pushes a map to listOfMaps and then stores
373 | # the value "Hello!" in the key "hi!" of the pushed map
374 | push list to listOfLists
375 | push "Hello!" listOfLists:0
376 | # Pushes a map to listOfLists and then pushes
377 | # the value "Hello!" at index 0 of the pushed list
378 |
379 | These will be explained in more detail in their respective sections.
380 |
381 | The LDPL compiler supports plural data-type names, as shown above. One can
382 | use `numbers` instead of `number`, `texts` instead of `text`,
383 | `lists` instead of `lists` and `maps`
384 | instead of `map`. A `list of list of number` is the same as a `list of lists of numbers`.
385 |
386 | !!!Note
387 | In LDPL 4.3, multicontainers were introduced with a right-to-left syntax.
388 | A `map of list of text` was defined as `text list map`. This syntax is
389 | still supported.
390 |
391 | ## Default Type Values
392 |
393 | In LDPL, each variable is initialized with a value by default. This means
394 | that when you declare a variable, it will, by default, hold this value
395 | until it's changed.
396 |
397 | * **Number** variables are initialized with the value `0`. Each element of
398 | a **number map** is a number variable, and thus also initialized to `0`.
399 | * **Text** variables are initialized to the empty string `""`. The same goes
400 | for **text maps**, where each element it contains is also initialized to `""`.
401 | * **Lists** are initialized empty by default and trying to access a
402 | non-existing index will result in an error.
403 | * Keys of **Maps of Lists** (`map of list`) are declared as empty lists of the
404 | scalar type of the multicontainer by default.
405 |
406 | ## Predeclared Variables
407 |
408 | Some variables in LDPL are already declared for you without you having to
409 | declare them. These variables are the **argv** text list, and the **errorcode**
410 | and **errortext** variables.
411 |
412 | ### The *argv* list variable
413 |
414 | Every LDPL program comes with the `argv` **text list** variable declared by
415 | default.
416 |
417 | If you pass command line arguments to your LDPL compiled program \(running, for
418 | example, something like `myBinary argument1 argument2)`, the values stored
419 | in the `argv` list \(_argument vector_\) will be the values of each argument
420 | passed \(in this case, `"argument1"` will be stored in `argv:0` and
421 | `"argument2"` in `argv:1`\).
422 |
423 | !!!hint
424 | Given that `argv` is a **text list**, the values passed as arguments are
425 | always stored as **text**, even numbers.
426 |
427 | Naturally, if no arguments are passed to the program, the `argv` list will be
428 | empty.
429 |
430 | ### The *errorcode* and *errortext* variables
431 |
432 | Some LDPL operations may fail when executed. Maybe you tried loading a file
433 | that wasn't there or getting the ASCII value of a multi-byte emoji. These
434 | operations make use of the `errorcode` and `errortext` variables to
435 | tell you if they ran successfully or not.
436 |
437 | The `errorcode` and `errortext` variables come declared by default.
438 | Some statements may modify their values to express their results.
439 |
440 | The `errorcode` variable is a **number** variable. It will hold the value 0
441 | if the statement ran successfully, and any other number if it did not.
442 |
443 | The `errortext` variable is a **text** variable that will be empty if the
444 | statement ran successfully. If it did not, it will store a human readable
445 | description of what went wrong.
446 |
447 | The `errorcode` and `errortext` variables can be read and written like any other
448 | LDPL variable.
449 |
450 | !!!warning
451 | When handling error checks, please bear in mind that the content of the
452 | `errortext` variable may change in future releases of LDPL. The value
453 | stored in `errorcode`, however, will not change and so that's the value
454 | that should be used to check whether an operation ran successfully or not.
455 |
--------------------------------------------------------------------------------
/docs/flow.md:
--------------------------------------------------------------------------------
1 | # Control Flow Statements
2 |
3 | !!!Note
4 | While this section is up-to-date and complete, it has to be reformated
5 | to be easier on the eyes. All UPPERCASE statement names and code should
6 | be changed to lowercase.
7 |
8 | ## `STORE _ IN _`
9 |
10 | The `STORE` statement assigns a value to a variable.
11 |
12 | **Syntax:**
13 |
14 | :::coffeescript
15 | STORE IN
16 |
17 |
18 | **Type Conversion Notes:**
19 |
20 | If the value to be stored is NUMBER and it's to be stored in a TEXT variable,
21 | the value will be converted to text, so `15` will be turned into `"15"`. If the
22 | value to be stored is a TEXT value two things can happen. If it contains any
23 | non-numeric characters \(for example letters, or more than one minus sign or
24 | more than one decimal point, for example `"--1.2"` or `"15a"`\) the conversion
25 | will fail and 0 will be stored in the NUMBER variable. If the TEXT contains a
26 | proper number, though, for example `"-416.419"` or `"89"` it will be converted
27 | to its number equivalent and stored in the variable. If a string literal depicting
28 | a number is preceded by leading zeros, these will be trimmed \(turning `0005`
29 | into `5`, `-0002.3` into `-2.3` and `00.23` into `0.23`\).
30 |
31 | ## `IF _ IS _ THEN`
32 |
33 | The `IF` statement evaluates if the condition given is positive. If it is, the code in the positive branch is executed. If it is not, the code in the negative branch is executed \(if available\). Execution then continues normally.
34 |
35 | **Syntax:**
36 |
37 | ```coffeescript
38 | IF THEN
39 | #Code goes here (positive branch)
40 | ELSE
41 | #Code goes here (negative branch)
42 | END IF
43 | ```
44 |
45 | or
46 |
47 | ```coffeescript
48 | IF THEN
49 | #Code goes here (positive branch)
50 | END IF
51 | ```
52 |
53 | The `` may be a relational operator between two values with the same type:
54 |
55 | * ` IS `
56 | * ` IS `
57 | * ` IS `
58 | * ` IS `
59 | * ` IS `
60 | * ` IS `
61 |
62 | **Possible values of `REL-OP-A`:**
63 |
64 | * `EQUAL TO`
65 | * `NOT EQUAL TO`
66 | * `GREATER THAN`
67 | * `LESS THAN`
68 | * `GREATER THAN OR EQUAL TO`
69 | * `LESS THAN OR EQUAL TO`
70 |
71 | **Possible values of `REL-OP-B`:**
72 |
73 | * `EQUAL TO`
74 | * `NOT EQUAL TO`
75 |
76 | For containers, both values must have the same type. You **cannot** compare, for example,
77 | a `list of lists of numbers` with a `list of lists of lists of numbers` or a `number map`
78 | with a `text map`.
79 |
80 | The `` may also be a membership operator:
81 |
82 | * ` IN `
83 | * ` IN `
84 |
85 | When using a membership operator, if the second value is a list, it checks if the first value
86 | is contained within that list. If the second value is a map, however, it checks if the first
87 | value is contained within the keys of that map.
88 |
89 | The first value must always be a scalar value, you **cannot** check if, for example, a
90 | `map of numbers` is contained within a `list of maps of numbers`.
91 |
92 | You can also write **compound conditions** using `AND`, `OR` and parenthesis:
93 |
94 | * ` AND ` is positive if both conditions are positive
95 | * ` OR ` is positive if any of the conditions is positive
96 | * `( )` is positive if the condition is positive and it's used to alter the default precedence
97 |
98 | The `AND` has higher precedence than `OR`, and the conditions inside parenthesis will be evaluated first. That means that `C1 AND C2 OR C3` is the same as `( C1 AND C2 ) OR C3`, but you can make the `OR` evaluate first if you write `C1 AND ( C2 OR C3 )`. Mind the spaces surrounding the parenthesis: `()` is **not** a
99 | valid condition, while `( )` is.
100 |
101 | Both `AND` and `OR` perform short-circuit evaluation: If the first operand of an AND is negative the second will not be evaluated and the `AND` condition is determined as negative. If the first operand of an OR is positive the second will not be evaluated and the `OR` condition is determined as positive.
102 |
103 | For example:
104 |
105 | ```coffeescript
106 | DATA:
107 | names IS TEXT LIST
108 | length IS NUMBER
109 | PROCEDURE:
110 | GET LENGTH OF names IN length
111 | IF length IS GREATER THAN 0 AND ( names:0 IS EQUAL TO "Alice" OR names:0 IS EQUAL TO "Bob" ) THEN
112 | #Code
113 | END IF
114 | ```
115 |
116 | The `names` list is empty, so the `length is greater than 0` condition is negative, and the second one is not evaluated \(and the execution continues after the `END IF`\). Thanks to short-circuit evaluation `names:0` is not evaluated and we don\`t get an index out of range runtime error!
117 |
118 | ## `ELSE IF _ IS _ THEN`
119 |
120 | The `ELSE IF` statement is equivalent to writing an `IF` statement inside the `ELSE` statement of another `IF` statement, but shorter. Must be used after an IF statement and before `END IF` or `ELSE`.
121 |
122 | **Syntax:**
123 |
124 | All the different `IF` variants of the [IF statement](./) apply, just with `ELSE` added before them.
125 |
126 | **Example:**
127 |
128 | ```coffeescript
129 | DATA:
130 | name IS TEXT
131 | PROCEDURE:
132 | STORE "Mike" IN name
133 | IF name IS equal to "John" THEN
134 | DISPLAY "Hello there, John!" CRLF
135 | ELSE IF name IS equal to "Mike" THEN
136 | DISPLAY "Hello there, Mike!" CRLF
137 | ELSE IF name IS equal to "Robert" THEN
138 | DISPLAY "Hello there, Robert!" CRLF
139 | ELSE
140 | DISPLAY "I don't know you, " name CRLF
141 | END IF
142 | ```
143 |
144 |
145 |
146 | ## `WHILE _ IS _ DO`
147 |
148 | The `WHILE` statement evaluates if the condition given is positive. While it is, the code between the `WHILE` and `REPEAT` statements is repeatedly ran.
149 |
150 | **Syntax:**
151 |
152 | ```coffeescript
153 | WHILE DO
154 | #Code goes here
155 | REPEAT
156 | ```
157 |
158 | The `` that you can use are the same as the [IF](if-is-then/) statement ones.
159 |
160 | ## `FOR _ FROM _ TO _ STEP _ DO`
161 |
162 | The `FOR` statement repeatedly run the code in its body a number of times, given a `counter` variable, the `start` of the range, its `end` and a `step`.
163 |
164 | When the loop starts, `start` is assigned to `counter` and starts an iteration, evaluating a condition. The condition is `counter < end` if `step >= 0` and `counter > end` if `step < 0`. If the condition passes, the code in the body of the `FOR` is executed, otherwise the loop will end. After the code is ran the `counter` is incremeted by `step` and a new iteration is started \(checking the condition and so on\).
165 |
166 | **Syntax:**
167 |
168 | ```coffeescript
169 | FOR FROM TO STEP DO
170 | #Code goes here
171 | REPEAT
172 | ```
173 |
174 | **Example:**
175 |
176 | ```coffeescript
177 | DATA:
178 | i IS NUMBER
179 | PROCEDURE:
180 | FOR i FROM 0 TO 10 STEP 2 DO
181 | DISPLAY i " "
182 | REPEAT
183 | # Will display "0 2 4 6 8 10"
184 | ```
185 |
186 | ## `FOR EACH _ IN _ DO`
187 |
188 | The `FOR EACH` statement repeatedly run the code in its body for every element in a given `LIST` or `MAP`. At the start of each iteration an element of the collection is assigned to a variable matching its type. This even works with multicontainers. For example, you can iterate a `NUMBER MAP LIST` using a `NUMBER MAP` as the iteration variable.
189 |
190 | If the collection is a `LIST`, its elements will be iterated increasingly from index `0`, while in the case of a `MAP` all the elements will be iterated in no particular order.
191 |
192 | !!! info
193 | Starting from LDPL 5 *Groovy Gualicho*, `FOR EACH` iterates over the may keys, instead of its elements. The iteration variable type must thus be `TEXT`.
194 |
195 | **Syntax:**
196 |
197 | ```coffeescript
198 | FOR EACH IN DO
199 | #Code goes here
200 | REPEAT
201 | ```
202 |
203 | **Example:**
204 |
205 | ```coffeescript
206 | DATA:
207 | letter IS TEXT
208 | letters IS TEXT LIST
209 | PROCEDURE:
210 | PUSH "L" TO letters
211 | PUSH "D" TO letters
212 | PUSH "P" TO letters
213 | PUSH "L" TO letters
214 | FOR EACH letter IN letters DO
215 | DISPLAY letter
216 | REPEAT
217 | # Will display "LDPL"
218 | ```
219 |
220 | ## `BREAK`
221 |
222 | The `BREAK` statement breaks the execution of the innermost `WHILE`, `FOR` or `FOR EACH` loop. Will throw a compiler error if used outside one.
223 |
224 | **Syntax:**
225 |
226 | ```coffeescript
227 | BREAK
228 | ```
229 |
230 | ## `CONTINUE`
231 |
232 | The `CONTINUE` statement jumps to the next iteration of the innermost `WHILE` or `FOR` loop. Will throw a compiler error if used outside one.
233 |
234 | **Syntax:**
235 |
236 | ```coffeescript
237 | CONTINUE
238 | ```
239 |
240 | ## `CALL SUB-PROCEDURE`
241 |
242 | The `CALL SUB-PROCEDURE` statement executes a SUB-PROCEDURE. Once the SUB-PROCEDURE returns, execution continues from the line following the `CALL SUB-PROCEDURE`.
243 |
244 | **Syntax:**
245 |
246 | ```coffeescript
247 | CALL SUB-PROCEDURE
248 | CALL SUB-PROCEDURE WITH
249 | ```
250 |
251 | Or
252 |
253 | ```coffeescript
254 | CALL
255 | CALL WITH
256 | ```
257 |
258 | Of course, a SUB-PROCEDURE must be declared **somewhere** in your program for you to call it.
259 |
260 | If the SUB-PROCEDURE you call doesn't have any declared parameters, you must call it without the `WITH` keyword, otherwise you must include it and pass all required parameters after it, in the same order declared in the `PARAMETERS` section of the SUB-PROCEDURE.
261 |
262 | ## `RETURN`
263 |
264 | The `RETURN` statement returns from a SUB-PROCEDURE. Will throw a compiler error if used outside one.
265 |
266 | **Syntax:**
267 |
268 | ```coffeescript
269 | RETURN
270 | ```
271 |
272 | ## `EXIT`
273 |
274 | The `EXIT` statement ends execution of the program.
275 |
276 | **Syntax:**
277 |
278 | ```coffeescript
279 | EXIT
280 | ```
281 |
282 | ## `WAIT _ MILLISECONDS`
283 |
284 | The `WAIT` statement pauses the execution of a program for the given number of milliseconds.
285 |
286 | **Syntax:**
287 |
288 | ```coffeescript
289 | WAIT MILLISECONDS
290 | ```
291 |
292 | ## `GOTO and LABEL`
293 |
294 | > "If you want to go somewhere, goto is the best way to get there."
295 | > -- Ken Thompson
296 |
297 | The `GOTO` statement performs a **one-way transfer** of control to a line of code marked by a `LABEL` statement. In lame man terms, the execution jumps to the line where the wanted `LABEL` is found and continues from there.
298 |
299 | While maligned by [Edsger W. Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra) and his cohorts, `GOTO` is very useful in many situations. Its reputation is undeserved and mostly perpetuated by people that don't understand the origins of the criticism or how the statement can be used.
300 |
301 | You also can't make a COBOL-_esque_ language without `GOTO`, so \(due to popular request\) we've added it to the language.
302 |
303 | **Syntax:**
304 |
305 | ```text
306 | LABEL
307 | ```
308 |
309 | ```text
310 | GOTO
311 | ```
312 |
313 | !!!hint
314 | Label names follow the naming rules stated in the **Identifier Naming Schemes** section of this documentation.
315 |
316 |
317 | **Example:**
318 |
319 | ```coffeescript
320 | PROCEDURE:
321 | GOTO start
322 |
323 | LABEL start
324 | display "> starting..." crlf
325 |
326 | GOTO ending
327 |
328 | LABEL middle
329 | display "> entering the middle section..." crlf
330 |
331 | sub cool-code
332 | GOTO cool
333 | display "hmm... is this cool?" crlf
334 | LABEL cool
335 | display "wow, yeah! cool code!" crlf
336 | end sub
337 |
338 | LABEL ending
339 | CALL cool-code
340 | display "> that's the end" crlf
341 | ```
342 |
343 | In the output of this program you can see the `middle` LABEL and the start of the `cool-code` SUB-PROCEDURE are skipped:
344 |
345 | ```text
346 | > starting...
347 | wow, yeah! cool code!
348 | > that's the end
349 | ```
350 |
351 | In order to keep `GOTO` from turning your source into _unmaintainable spaghetti code_, both your `GOTO` statements and the `LABEL`s they jump to have to be declared together in the same sub-procedure or in the main code body of an LDPL program. You can't `goto` across sub-procedures or into them, or anything like that.
352 |
353 | ## `CREATE STATEMENT _ EXECUTING _`
354 |
355 | The `CREATE STATEMENT` statement lets you add custom statements to LDPL that execute SUB-PROCEDUREs.
356 |
357 | **Syntax:**
358 |
359 | ```coffeescript
360 | CREATE STATEMENT EXECUTING
361 | ```
362 |
363 | The `TEXT` describes the new statement syntax and must contain tokens separated by whitespace. Each token can be a keyword, which is a word with `A-Z` characters \(preferably in English\), or `"$"`, a character that marks where parameters are passed. At least one keyword token is required and the number of `"$"` tokens must be the same as the number of parameters of the SUB-PROCEDURE you pass after `EXECUTING`. For example, a valid `TEXT` is `"DISPLAY $ $ TIMES"` if the SUB-PROCEDURE has exactly two parameters. The SUB-PROCEDURE must be declared before creating the statement.
364 |
365 | After a statement is created you can use it like any other LDPL statement in `PROCEDURE` sections, just write a line with all the tokens of the `TEXT` in the same order but placing values instead of `"$"`. The types of the values must be the same as the parameter types of the SUB-PROCEDURE the statement executes following the same order. Using the new statement will produce the same effect as `CALL`ing the SUB-PROCEDURE \(parameters are passed by reference too\).
366 |
367 | You can create two different statements with same `TEXT` and use both if at least one of the parameter types are different in each SUB-PROCEDURE, because the resulting syntaxes will differ from each other. Using this you can create two versions of the same statements dealing with different parameter types, like the first example shows.
368 |
369 | Bear in mind that a line in your program could match more than one statement: If all of them were created with `CREATE STATEMENT`, the one that was created first will be executed. If one of the them is a LDPL built-in statement, this will be executed. For example, if you create `"DISPLAY $ $ TIMES"`, declare a variable `TIMES` and use the line `DISPLAY "Hi!" 3 TIMES`, the LDPL `DISPLAY` statement will be executed, because the line matches its syntax. This is illustrated in the second example.
370 |
371 | **Example 1:**
372 |
373 | ```coffeescript
374 | PROCEDURE:
375 | SUB-PROCEDURE displayNValueTimes
376 | PARAMETERS:
377 | value is number
378 | times is number
379 | LOCAL DATA:
380 | i is number
381 | PROCEDURE:
382 | FOR i FROM 0 TO times STEP 1 DO
383 | DISPLAY value " "
384 | REPEAT
385 | END SUB-PROCEDURE
386 | CREATE STATEMENT "DISPLAY $ $ TIMES" EXECUTING displayNValueTimes
387 | # Syntax for this new statement: DISPLAY TIMES
388 |
389 | SUB-PROCEDURE displayTValueTimes
390 | PARAMETERS:
391 | value is text
392 | times is number
393 | LOCAL DATA:
394 | i is number
395 | PROCEDURE:
396 | FOR i FROM 0 to times STEP 1 DO
397 | DISPLAY value " "
398 | REPEAT
399 | END SUB-PROCEDURE
400 | CREATE STATEMENT "DISPLAY $ $ TIMES" EXECUTING displayTValueTimes
401 | # Syntax for this new statement: DISPLAY TIMES
402 |
403 | # We can imagine that we have only one new statement:
404 | # DISPLAY TIMES
405 |
406 | DISPLAY 100 2 TIMES # This executes: CALL displayNValueTimes with 100 2
407 | DISPLAY "Hi!" 3 TIMES # This executes: CALL displayTValueTimes with "Hi!" 3
408 |
409 | # This program displays "100 100 Hi! Hi! "
410 | ```
411 |
412 | **Example 2:**
413 |
414 | ```coffeescript
415 | DATA:
416 | times is number
417 | PROCEDURE:
418 | SUB-PROCEDURE displayTValueTimes
419 | PARAMETERS:
420 | value is text
421 | times is number
422 | LOCAL DATA:
423 | i is number
424 | PROCEDURE:
425 | FOR i FROM 0 to times STEP 1 DO
426 | DISPLAY value " "
427 | REPEAT
428 | END SUB-PROCEDURE
429 | CREATE STATEMENT "DISPLAY $ $ TIMES" EXECUTING displayTValueTimes
430 | # Syntax for this new statement: DISPLAY TIMES
431 |
432 | DISPLAY "Hi!" 3 TIMES # This executes the LDPL DISPLAY statement!
433 | # This program displays "Hi!30" because times is equal to 0
434 | ```
435 |
436 | ## `CALL EXTERNAL _`
437 |
438 | !!!hint
439 | This section talks about external sub-procedure calling for **C++ Extensions**. If
440 | you have not read the section on C++ Extensions yet, ignore this and then come
441 | back later.
442 |
443 |
444 | The `CALL EXTERNAL` statement executes a SUB-PROCEDURE defined in an extension to LDPL, typically in C++. It otherwise operates the same as `CALL SUB-PROCEDURE`, except that external SUB-PROCEDURES do not receive parameters.
445 |
446 | **Syntax:**
447 |
448 | ```text
449 | CALL EXTERNAL
450 | ```
451 |
452 | **Example:**
453 |
454 | ```text
455 | CALL EXTERNAL http-get
456 | ```
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # LDPL Docs
2 |
3 | ## Introduction
4 |
5 | The **LDPL Community** has compiled this document with the desire to teach
6 | and standardize the **LDPL** programming language. This document contains the
7 | specification for the **LDPL** programming language, as well as explanations,
8 | instructions and examples for every feature included in it.
9 |
10 | 
11 |
12 | Feedback, corrections and suggestions are welcome, both on the main
13 | [LDPL repository](https://github.com/Lartu/ldpl)
14 | or by e-mail to [martin@ldpl-lang.org](mailto:martin@ldpl-lang.org).
15 | You can join the LDPL community at [r/ldpl](https://reddit.com/r/ldpl)
16 | or via IRC on irc.freenode.net channel #ldpl.
17 |
18 | The source code for this documentation is available in the LDPL repository.
19 |
20 | ## About LDPL
21 |
22 | **LDPL** is a powerful compiled programming language designed from the
23 | ground up to be expressive, readable, fast and easy to learn. It mimics plain
24 | English, in the likeness of the good parts of older programming languages like
25 | COBOL, with the desire that it can be understood by anybody. LDPL was designed
26 | to run on Unix systems, including AMD-64 Linux, macOS, ARMv8 Linux, Android
27 | Termux and both Intel and PowerPC OS X (tested from Tiger 10.4 onwards).
28 | It even supports UTF-8 out of the box.
29 |
30 | :::coffeescript
31 | # LDPL 'Hello World' example
32 |
33 | data:
34 | name is text # Your name will go here.
35 |
36 | procedure:
37 | display "Hello World!" lf "What's your name? "
38 | accept name
39 | display "你好, " name ", welcome to LDPL!" lf
40 |
41 | LDPL also aims to suppress unreadable code and redundancy by only having one
42 | way of doing anything. What a command does should never overlap with the
43 | purpose of another command and, as such, every LDPL command does one and only
44 | one thing. Every line is a step further towards the completion of an algorithm,
45 | no more, no less.
46 |
47 | ## The LDPL Compiler
48 |
49 | To use LDPL, you should first download or compile the LDPL compiler.
50 | For more information on how to do that, read the
51 | [*How to install LDPL* section](https://github.com/Lartu/ldpl#-how-to-install-ldpl)
52 | on the LDPL Readme.
53 |
54 | To use the compiler, you must have a C++ compiler already installed on your
55 | system and have mapped it to `c++`, found on your PATH. The LDPL Compiler
56 | compiles LDPL code to C++ code and thus this is a requirement for it to work.
57 |
58 | Once the compiler is set up, go write some LDPL source code, say `source.ldpl`.
59 | Then compile the source code using `ldpl source.ldpl`. The compiled, executable
60 | binary file will be saved as `source-bin`. Done!
61 |
62 | ### Compiler Switches
63 |
64 | To use the LDPL compiler, the syntax is as follows:
65 |
66 | ldpl [-i='']... |-c
67 | [-o=''|-r] [-f='']... [-n]
68 | ldpl [-v|-h]
69 |
70 | The `-f` flag can be used to pass extra options to the `c++` compiler when. For
71 | example, `-f=-lSDL` could be used to link against SDL. The `flag` statement can
72 | also be used as well (`flag "-lSDL"`) and its use is recommended. More on this
73 | later.
74 |
75 | By using `-r` you can just compile your project and print the C++ representation
76 | for that code.
77 |
78 | You can set the filename for the compiled binary with the `-o` flag. For
79 | example, if you want to name your program "dog", you could compile it with
80 | `ldpl -o=dog main.ldpl`.
81 |
82 | On Linux platforms, LDPL builds static binaries by default. If you want to
83 | build non-static ones use the `-ns` flag.
84 |
85 | The `-c` flag tells LDPL to accept source code from the standard input.
86 |
87 |
88 | You can import extra files and extensions to your LDPL compilation by using the
89 | `-i=` flag. Extensions can be imported by passing `.o`, `.a`, or `.cpp` files
90 | to this flag; see the Extensions section for more information. The use of the
91 | `INCLUDE` statement is preferred.
92 |
93 | `-v` and `--version` print out version info and release details.
94 |
95 | `-h` and `--help` print this list of options.
96 |
97 | ## File Extensions
98 |
99 | The preferred file extension for LDPL source files is **'.ldpl'**.
100 | The extension **'.lsc'** (LDPL Source File) should also be accepted in case
101 | the preferred extension couldn't be used for any reason.
102 |
103 | !!! tip
104 | File extensions are important: they help editors to recognize what language
105 | your source code is written in and they tell the LDPL compiler how to treat
106 | your files.
107 |
108 | ## License
109 |
110 | This LDPL Compiler is distributed under the Apache 2.0 License.
111 | All LDPL Dinosaur logos were created by [Lartu](https://lartu.net) and are
112 | released under a Creative Commons Attribution 4.0 International (CC BY 4.0)
113 | license. This documentation is released under the Apache 2.0 License.
114 |
115 |
116 |
--------------------------------------------------------------------------------
/docs/io.md:
--------------------------------------------------------------------------------
1 | !!!Note
2 | While this section is up-to-date and complete, it has to be reformated
3 | to be easier on the eyes. All UPPERCASE statement names and code should
4 | be changed to lowercase.
5 |
6 | ## `DISPLAY`
7 |
8 | The `DISPLAY` statement outputs the values passed to the output stream. `CRLF` means line break and is a sugar syntax for the `"\n"` escape sequence.
9 |
10 | **Syntax:**
11 |
12 | ```coffeescript
13 | DISPLAY
14 | ```
15 |
16 | **Example:**
17 |
18 | ```coffeescript
19 | DISPLAY "Hello, " nameVariable "! This is a number -> " 89.1 " :)" CRLF
20 | ```
21 |
22 | ## `ACCEPT _`
23 |
24 | The `ACCEPT` command is used to gather input from the user. If a TEXT variable is specified, anything the user enters before pressing the 'return' key will be accepted. If a NUMBER variable is specified, the user must enter a number \(if any non-numeric key is entered, the error message "Redo from start" will be output and the ACCEPT command rerun\).
25 |
26 | **Syntax:**
27 |
28 | ```coffeescript
29 | ACCEPT
30 | ```
31 |
32 | ## `EXECUTE _`
33 |
34 | The `EXECUTE` statement executes the specified system command.
35 |
36 | **Syntax:**
37 |
38 | ```coffeescript
39 | EXECUTE
40 | ```
41 |
42 | **Example 1:**
43 |
44 | ```coffeescript
45 | # Prepare the command to execute
46 | IN myTextVar JOIN "echo " myVariable " >> myFile"
47 | # Execute it
48 | EXECUTE myTextVar
49 | ```
50 |
51 | **Example 2:**
52 |
53 | ```coffeescript
54 | # Execute "dir" to list the files in the current directory under Windows
55 | EXECUTE "dir"
56 | ```
57 |
58 | ## `EXECUTE _ AND STORE OUTPUT IN _`
59 |
60 | The `EXECUTE - AND STORE OUTPUT IN` executes the specified command and stores any resulting text in the passed variable.
61 |
62 | **Syntax:**
63 |
64 | ```coffeescript
65 | EXECUTE AND STORE OUTPUT IN
66 | ```
67 |
68 | ## `EXECUTE _ AND STORE EXIT CODE IN _`
69 |
70 | The `EXECUTE - AND STORE EXIT CODE IN` executes the specified command and stores the exit code in the passed variable.
71 |
72 | **Syntax:**
73 |
74 | ```coffeescript
75 | EXECUTE AND STORE EXIT CODE IN
76 | ```
77 |
78 | ## `ACCEPT _ UNTIL EOF`
79 |
80 | The `ACCEPT UNTIL EOF` statement accepts input from standard input until an EOF state is reached and stores all data gathered in TEXT-VAR.
81 |
82 | **Syntax:**
83 |
84 | ```coffeescript
85 | ACCEPT UNTIL EOF
86 | ```
87 |
88 | ## `LOAD FILE _ IN _`
89 |
90 |
91 | The `LOAD FILE` statement loads the contents of a file into a text variable.
92 |
93 | **Syntax:**
94 |
95 | ```coffeescript
96 | LOAD FILE IN
97 | ```
98 |
99 | **Example:**
100 |
101 | ```coffeescript
102 | LOAD FILE "myFolder/myTextFile.txt" IN myVariable
103 | ```
104 |
105 | **Error Codes:**
106 |
107 | If the LOAD operation should fail, the following values will be returned into the `ERRORCODE` and `ERRORTEXT` variables:
108 |
109 | * `ERRORCODE`: 1
110 | * `ERRORTEXT`: "The file '<filename>' couldn't be opened."
111 |
112 | !!!warning
113 | Always use the `ERRORCODE` variable to check if the operation was successful or not. Do **not** use `ERRORTEXT` for anything else than displaying the error found, as its contents may change in future releases of LDPL.
114 |
115 | ## `WRITE _ TO FILE _`
116 |
117 | The `WRITE x TO FILE y` statement writes the value of `x` to the file called `y`. If the file already exists, everything in it will be overwritten by `x`.
118 |
119 | **Syntax:**
120 |
121 | ```coffeescript
122 | WRITE TO FILE
123 | ```
124 |
125 | **Example:**
126 |
127 | ```coffeescript
128 | WRITE "Hello there!" TO FILE "hello.txt"
129 | ```
130 |
131 | **Error Codes:**
132 |
133 | If the WRITE operation should fail, the `ERRORCODE` and `ERRORTEXT` variables will be set to the following values:
134 |
135 | * `ERRORCODE`: 1
136 | * `ERRORTEXT`: "Could not open '<filename>'"
137 | * `ERRORCODE`: 2
138 | * `ERRORTEXT`: "Could not write to '<filename>'"
139 |
140 | ## `APPEND _ TO FILE _`
141 |
142 | The `APPEND x TO FILE y` statement appends the value of `x` to the file called `y`. If the file already exists, `x` will be added at the end of its contents.
143 |
144 | **Syntax:**
145 |
146 | ```coffeescript
147 | APPEND TO FILE
148 | ```
149 |
150 | **Example:**
151 |
152 | ```coffeescript
153 | APPEND "\nHow are you?" TO FILE "hello.txt"
154 | ```
155 |
156 | in this case, the file `hello.txt` (created in the example of the `WRITE _ TO FILE _` function and modified as stated there) will contain the text
157 |
158 | ```text
159 | Hello there!
160 | How are you?
161 | ```
162 |
163 | **Error Codes:**
164 |
165 | If the APPEND operation should fail, the `ERRORCODE` and `ERRORTEXT` variables will be set to the following values:
166 |
167 | * `ERRORCODE`: 1
168 | * `ERRORTEXT`: "Could not open '<filename>'"
169 | * `ERRORCODE`: 2
170 | * `ERRORTEXT`: "Could not write to '<filename>'"
171 |
--------------------------------------------------------------------------------
/docs/list.md:
--------------------------------------------------------------------------------
1 | !!!Note
2 | While this section is up-to-date and complete, it has to be reformated
3 | to be easier on the eyes. All UPPERCASE statement names and code should
4 | be changed to lowercase.
5 |
6 | ## `PUSH _ TO _`
7 |
8 | The `PUSH - TO` statement is used to add elements to a LIST. When you push an element to a LIST it is appended at the end of the list.
9 |
10 | **Syntax:**
11 |
12 | ```coffeescript
13 | PUSH TO
14 | PUSH TO
15 | ```
16 |
17 | **Example:**
18 |
19 | ```coffeescript
20 | DATA:
21 | foo IS TEXT LIST
22 | PROCEDURE:
23 | PUSH "First index" TO foo
24 | PUSH "Second index" TO foo
25 | ```
26 |
27 | In the above example, `foo` now contains the value `"First index"` at index `0` and the value `"Second index"` at index `1`.
28 |
29 | ## `CLEAR`
30 |
31 | The `CLEAR` statement empties a LIST, thus deleting all its contents. The LIST itself is not deleted though, and can still be used and filled with new elements after a `CLEAR` statement has been executed.
32 |
33 | **Syntax:**
34 |
35 | ```coffeescript
36 | CLEAR
37 | ```
38 |
39 | ## `COPY _ TO _`
40 |
41 | The `COPY - TO` statement copies all the elements of a LIST with their respective indices to another LIST **of the same type**. The original LIST is untouched, but the destination LIST is completely overwritten by the contents of the copied LIST and any elements that existed in it prior to the copy are deleted. In other words, the destination LIST is `CLEAR`ed before the copy.
42 |
43 | **Syntax:**
44 |
45 | ```coffeescript
46 | COPY TO
47 | COPY TO
48 | ```
49 |
50 | **Example:**
51 |
52 | ```coffeescript
53 | DATA:
54 | foo IS TEXT LIST
55 | bar IS TEXT LIST
56 | PROCEDURE:
57 | PUSH "Hello there!" TO foo
58 | PUSH "How are you?" TO foo
59 | COPY foo TO bar
60 | DISPLAY bar:0 " " bar:1 CRLF
61 | # Will display "Hello there! How are you?"
62 | ```
63 |
64 | ## `GET LENGTH OF _ IN _`
65 |
66 | The `GET LENGTH OF - IN` statement stores the amount of elements stored in a LIST \(or, analogously, the length of the LIST\) into a numeric variable.
67 |
68 | **Syntax:**
69 |
70 | ```coffeescript
71 | GET LENGTH OF IN
72 | ```
73 |
74 | **Example:**
75 |
76 | ```coffeescript
77 | DATA:
78 | foo IS TEXT LIST
79 | count IS NUMBER
80 | PROCEDURE:
81 | PUSH "Hello there!" TO foo
82 | PUSH "How are you?" TO foo
83 | STORE LENGTH OF foo IN count
84 | DISPLAY count CRLF
85 | # Will display 2
86 | ```
87 |
88 | ## `DELETE LAST ELEMENT OF _`
89 |
90 |
91 | The `DELETE LAST ELEMENT OF` deletes the last element pushed to a LIST. If the LIST was empty, this statement does nothing.
92 |
93 | **Syntax:**
94 |
95 | ```coffeescript
96 | DELETE LAST ELEMENT OF
97 | ```
98 |
99 | ## `REMOVE ELEMENT AT _ FROM _`
100 |
101 | The `REMOVE ELEMENT AT - FROM` statement deletes the element at the specified index from a LIST. If the index is out of bounds, this statement does nothing.
102 |
103 | **Syntax:**
104 |
105 | ```coffeescript
106 | REMOVE ELEMENT AT FROM
107 | ```
108 |
109 | **Example:**
110 |
111 | ```coffeescript
112 | DATA:
113 | foo IS TEXT LIST
114 | PROCEDURE:
115 | PUSH "Hello there!" TO foo
116 | PUSH "How are you?" TO foo
117 | REMOVE ELEMENT AT 0 FROM foo
118 | DISPLAY foo:0 CRLF
119 | # Will display "How are you?"
120 | ```
121 |
--------------------------------------------------------------------------------
/docs/manList:
--------------------------------------------------------------------------------
1 | index.md
2 | structure.md
3 | data.md
4 | procedure.md
5 | naming.md
6 | flow.md
7 | arithmetic.md
8 | time.md
9 | text.md
10 | list.md
11 | map.md
12 | io.md
13 | cppext.md
14 |
--------------------------------------------------------------------------------
/docs/map.md:
--------------------------------------------------------------------------------
1 | !!!Note
2 | While this section is up-to-date and complete, it has to be reformated
3 | to be easier on the eyes. All UPPERCASE statement names and code should
4 | be changed to lowercase.
5 |
6 | ## `CLEAR`
7 |
8 | The `CLEAR` statement empties a MAP, thus deleting all its contents. The MAP itself is not deleted though, and can still be used and filled with new elements after a `CLEAR` statement has been executed.
9 |
10 | **Syntax:**
11 |
12 | ```coffeescript
13 | CLEAR
14 | ```
15 |
16 | ## `COPY _ TO _`
17 |
18 | The `COPY - TO` statement copies all the elements of a MAP with their respective keys to another MAP **of the same type**. The original MAP is untouched, but the destination MAP is completely overwritten by the contents of the copied MAP and any elements that existed in it prior to the copy are deleted. In other words, the destination MAP is `CLEAR`ed before the copy.
19 |
20 | **Syntax:**
21 |
22 | ```coffeescript
23 | COPY TO
24 | COPY TO
25 | ```
26 |
27 | **Example:**
28 |
29 | ```coffeescript
30 | DATA:
31 | foo IS TEXT MAP
32 | bar IS TEXT MAP
33 | PROCEDURE:
34 | STORE "Hello there!" IN foo:0
35 | STORE "How are you?" IN foo:7
36 | COPY foo TO bar
37 | DISPLAY bar:0 " " bar:7 CRLF
38 | # Will display "Hello there! How are you?"
39 | ```
40 |
41 |
42 | ## `GET KEY COUNT OF _ IN _`
43 |
44 | The `GET KEY COUNT OF - IN` statement stores the amount of elements \(or, analogously, keys\) stored in a MAP into a numeric variable.
45 |
46 | **Syntax:**
47 |
48 | ```coffeescript
49 | GET KEY COUNT OF IN
50 | ```
51 |
52 | **Example:**
53 |
54 | ```coffeescript
55 | DATA:
56 | foo IS TEXT MAP
57 | count IS NUMBER
58 | PROCEDURE:
59 | STORE "Hello there!" IN foo:0
60 | STORE "How are you?" IN foo:7
61 | GET KEY COUNT OF foo IN count
62 | DISPLAY count CRLF
63 | # Will display 2
64 | ```
65 |
66 |
67 | ## `GET KEYS OF _ IN _`
68 |
69 | The `GET KEYS OF - IN` statement stores all the keys of a MAP into a TEXT LIST. Say you have a MAP with keys `0`, `"cat"` and `"dog"`. The elements these keys point to are not important. Using the `GET KEYS OF` statement, you can copy the keys of this MAP to a LIST. Thus, the resulting LIST will \(for example\) have the value `0` at index 0, the value `"cat"` at index 1 and the value `"dog"` at index 2. This statement is thus used to find all the keys of a particular MAP.
70 |
71 | **Syntax:**
72 |
73 | ```coffeescript
74 | GET KEYS OF IN
75 | ```
76 |
77 | **Example:**
78 |
79 | ```coffeescript
80 | DATA:
81 | foo IS TEXT MAP
82 | bar IS TEXT LIST
83 | PROCEDURE:
84 | STORE "Hello there!" IN foo:0
85 | STORE "How are you?" IN foo:7
86 | STORE "I like cats" IN foo:"cat"
87 | STORE "I love dogs" IN foo:"dog"
88 | STORE "LDPL is nice" IN foo:3
89 | GET KEYS OF foo IN bar
90 | ```
91 |
92 | At the end of the execution of the previous excerpt of code, the `TEXT LIST` called `bar` will contain the values `"0"`, `"7"`, `"cat"`, `"dog"` and `"3"` at indexes that are consecutive integers starting at zero.
93 |
94 |
--------------------------------------------------------------------------------
/docs/naming.md:
--------------------------------------------------------------------------------
1 | ## Identifier Naming Schemes
2 |
3 | Variables and sub-procedure names follow the same naming rules. Their names
4 | can't be empty and may consist of any character with few exceptions \(listed
5 | below\). Like statements, variable and sub-procedure names in LDPL are not case
6 | sensitive.
7 |
8 | * Variable and sub-procedure names cannot contain the character `:`, as it is
9 | used for **map** and **list** accesses.
10 | * Variable and sub-procedure names cannot contain the character `"`, as it is
11 | used to delimit strings.
12 | * Variable and sub-procedure names cannot contain spaces.
13 | * Variable and sub-procedure names cannot be valid numbers \(they may contain
14 | numbers, though\).
15 | * Variable and sub-procedure names cannot contain the character `(` nor the
16 | character `)` as these characters are used in mathematical expressions.
17 | * Variables and sub-procedures cannot be called `CRLF`, as it is internally
18 | turned into `"\r\n"`.
19 | * Variables and sub-procedures cannot be called `LF`, as it is internally
20 | turned into `"\r\n"`.
21 | * Variables and sub-procedures cannot be called `+` nor `-` nor `*` nor `/` as
22 | these characters are used in mathematical expressions.
23 |
24 |
25 | !!!warning
26 | External Identifiers follow different naming rules. Please check the
27 | **External Identifier Naming Scheme** section for more information.
28 |
29 | ## Label Naming Schemes
30 |
31 | Labels are identifiers used alongside the `label` statement.
32 | Labels in LDPL may not be empty strings and may contain any character except spaces and
33 | `"` (double quotes). Labels cannot be named `CRLF` nor `LF` for the same reasons explained in
34 | the section above.
35 |
36 | ## External Identifier Naming Schemes
37 |
38 | !!!hint
39 | This section talks about identifier naming schemes for **C++ Extensions**. If
40 | you have not read the section on C++ Extensions yet, ignore this and then come
41 | back later.
42 |
43 | All C++ variables and functions accessible to LDPL programs may contain only
44 | `A-Z`, `0-9`, and the `_` character in their names. All other characters used
45 | on the LDPL side to reference a variable or function will get converted to an
46 | underscore (`_`) or, if it's a letter, capitalized.
47 |
48 | For example:
49 |
50 | | LDPL Identifier | Result When Converted to a C++ Identifier |
51 | | :--- | :--- |
52 | | window.rows | WINDOW\_ROWS |
53 | | HTTP/get | HTTP\_GET |
54 | | SDL/Font.new | SDL\_FONT\_NEW |
55 | | sdl.font-new | SDL\_FONT\_NEW |
56 | | NAME | NAME |
57 | | version\_number | VERSION\_NUMBER |
58 |
59 | !!!warning
60 | Note that this conversion scheme may cause collisions.
61 | All of the following LDPL variables will be converted to `ONE_TWO:`
62 |
63 | * `One-Two`
64 | * `one.two`
65 | * `one/two`
66 | * `OnE-TWO`
67 |
--------------------------------------------------------------------------------
/docs/procedure.md:
--------------------------------------------------------------------------------
1 | ## The Procedure Section
2 |
3 | The **procedure** section is where all the code of a LDPL program that is not a
4 | variable declaration is written. An LDPL program **must** contain a procedure
5 | section, even if it's empty. Execution should and will fail otherwise.
6 |
7 | Within the procedure section, every line can contain either a comment,
8 | a statement, a statement and a comment or be empty. No two statements can be
9 | written on the same line.
10 |
11 | An example procedure section may end up looking like this:
12 |
13 | :::coffeescript
14 | procedure:
15 | store 5 in foo
16 | store "hi there" in bar:"hi"
17 | # Note that these are the variables
18 | # declared in the data section above.
19 |
20 | Code within the procedure section is executed from top to bottom,
21 | skipping sub-procedure declarations, unless they are explicitly called.
22 |
23 | Available statements and sub-procedure declarations will be explained further
24 | in the following sections of this document.
25 |
26 | ## Sub-procedures
27 | A **sub-procedure** is a piece of code that can be called and executed from other
28 | parts of the script. Sub-procedure subsections must be declared within the
29 | **procedure** section of the code using a `sub-procedure ` statement and
30 | end with an `end sub-procedure` statement. Alternatively, the shorter versions
31 | `sub ` and `end sub` may be used. Bear in mind that you can't define a
32 | sub-procedure within a sub-procedure.
33 |
34 | Sub-procedures may be invoked at any point in your code by **calling** them with
35 | the `call` statement. When you do that, the sub-procedure is executed and once
36 | it finishes executing, the line after the `call` that called the sub-procedure
37 | is executed and execution continues normally. More on the call statement later.
38 |
39 | Also bear in mind that you can `call` a
40 | sub-procedure before it has been declared, but the compilation process will
41 | fail if the compiler doesn't find the sub-procedure once it has parsed all the
42 | files in your program.
43 |
44 | The full syntax for declaring sub-procedures is this one:
45 |
46 | :::coffeescript
47 | sub-procedure procedureName
48 | parameters:
49 | # parameters go here
50 | local data:
51 | # local variable declarations go here
52 | procedure:
53 | # code goes here
54 | end sub-procedure
55 |
56 | Or you may, as stated, use the shorter version:
57 |
58 | :::coffeescript
59 | sub procedureName
60 | parameters:
61 | # parameters go here
62 | local data:
63 | # local variable declarations go here
64 | procedure:
65 | # code goes here
66 | end sub
67 |
68 | In context, the full declaration of a sub-procedure looks like this:
69 |
70 | :::coffeescript
71 | data:
72 | # ...
73 | procedure:
74 | # ...
75 | sub mySubprocedure
76 | parameters:
77 | # ...
78 | local data:
79 | # ...
80 | procedure:
81 | # ...
82 | end sub
83 |
84 | The **parameters** and local **data** sub-sections are optional (more on these
85 | later). If you decide to not include any of those sub-sections, you can skip
86 | the **procedure** tag altogether and just go ahead writing your code like this:
87 |
88 | :::coffeescript
89 | sub someOtherSub
90 | display "Hello there!" lf
91 | end sub
92 |
93 | You cannot have more than one sub-procedure with the same name. Also,
94 | sub-procedure names must follow the guidelines stated in the **Naming Schemes**
95 | section of this document.
96 |
97 | ### The Procedure Subsection:
98 |
99 | In the **procedure** sub-section of the sub-procedure you may write the code
100 | of your sub-procedure using statements like in the main **procedure** section.
101 | In this procedure sub-section, however, you may also use the `RETURN` statement
102 | to halt execution of the sub-procedure and return to the point where it was
103 | called from.
104 |
105 | ### The Parameters and Local Data Sub-Sections
106 |
107 | Within the **parameters** and **data** sub-sections of a function you may only
108 | declare variables just like in the global **data** section. The variables
109 | defined here, however, can only be used inside the procedure sub-section of the
110 | same sub-procedure they where declared in.
111 |
112 | Variables between the parameters and local data sub-sections may not share
113 | names.
114 |
115 | If a variable declared within the parameters or data sub-sections of
116 | a sub-procedure shares its name with a global variable, when using that name
117 | within the procedure section of the sub-procedure, it will always refer to the
118 | variable declared in said sub-procedure and not the global one.
119 |
120 | At the start of the sub-procedure execution, all the variables declared in its
121 | **local data** section will be initialized with their type default values, and
122 | each invocation of the function will have its own copy of the local variables.
123 | This is important if you want to implement recursive sub-procedures:
124 |
125 | :::coffeescript
126 | data:
127 | execution is number
128 | procedure:
129 | sub myRecursiveSub
130 | local data:
131 | myLocalVar is number
132 | procedure:
133 | in executions solve executions + 1
134 | if executions is equal to 3 then
135 | return # We don't want this to run forever!
136 | end if
137 | display "[myLocalVar starts at " myLocalVar "!"
138 | store executions in myLocalVar
139 | call myRecursiveSub
140 | display "I'm execution n°" myLocalVar "!]"
141 | end sub
142 |
143 | call myRecursiveSub
144 |
145 | That weird recursive function displays the following output:
146 |
147 | :::text
148 | [myLocalVar starts at 0![myLocalVar starts at 0!I'm execution Nº2!]I'm execution Nº1!]
149 |
150 | !!!hint
151 | Most of the statements used in this example will be explained later.
152 | Don't feel bad if you don't yet understand completely what that sub-procedure
153 | does.
154 |
155 | Variables declared within the **parameters** sub-section are quite different.
156 | When calling sub-procedures using the `call` statement, you may also use the
157 | optional `with` keyword to specify values to be passed to the sub-procedure.
158 | The variables declared in the **parameters** sub-section will take these values,
159 | following the order they were declared in.
160 |
161 | For example, if you declare a sub-procedure like this:
162 |
163 | :::coffeescript
164 | sub addTwoNumbers
165 | parameters:
166 | a is number
167 | b is number
168 | c is number
169 | procedure:
170 | # ...
171 | end sub
172 |
173 | You may then call it like this:
174 |
175 | :::coffeescript
176 | call addTwoNumbers with 5 6 7
177 |
178 | And `a` will take the value 5, `b` the value 6 and `c` the value 7.
179 |
180 | While this is fine, it gets more powerful when using variables instead of
181 | fixed values. LDPL is a pass-by-reference language. This means that if you
182 | pass a variable to a sub-procedure with the `with` keyword and its value is
183 | assigned to a parameter variable, if you modify that parameter variable the
184 | original variable will be modified as well. Let's see an example:
185 |
186 | :::coffeescript
187 | data:
188 | result is number
189 |
190 | procedure:
191 | sub addTwoNumbers
192 | parameters:
193 | a is number
194 | b is number
195 | c is number
196 | procedure:
197 | in c solve a + b
198 | end sub
199 |
200 | # the variable result is initialized to 0 by default
201 | call addTwoNumbers with 4 5 result
202 | display "The result is: " result "." lf
203 |
204 | !!!hint
205 | The `in _ solve _` statement is used to solve mathematical expressions.
206 | If you execute, for example, `in foo solve 5 + 6 - 8`, the result of solving
207 | 5 + 6 - 8 will be stored in the number variable `foo`.
208 |
209 |
210 | That code displays the following text:
211 |
212 | :::text
213 | The result is 9.
214 |
215 | This is because, as we called the variable with a variable as a parameter
216 | (`call addTwoNumbers with 4 5 result`, **result** is the variable here) it was
217 | *somewhat* aliased to the local parameter variable `c` and, thus, when we
218 | solved `a + b` in `c`, we stored the result of `a + b` in `result`.
219 |
220 | Passing variables by reference lets you return results from your sub-procedure,
221 | as shown in the example above.
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | mkdocs-material
2 |
--------------------------------------------------------------------------------
/docs/structure.md:
--------------------------------------------------------------------------------
1 | # LDPL Source Code Structure
2 |
3 | ## Case Sensitivity
4 |
5 | LDPL is a **case-insensitive** language. This means that variables and statements
6 | that consist of the same characters are understood to be the same variable
7 | or statement regardless of their case. For example, in other languages the
8 | variables `foo` and `FOO` would represent two different variables, but in
9 | LDPL they are **the same one**. This same thing happens with statements. For
10 | LDPL it's the same if you write `display` or `dIsPlAy` (but please don't do so).
11 |
12 | !!! warning
13 | LDPL is case-insensitive only for latin A-z characters. Accented characters and
14 | non-ASCII letters will be matched in a case-insensitive manner. Depending
15 | on the LDPL implementation, `ááá` and `ÁÁÁ` may not represent the same
16 | identifier. It is good practice to write your code in a single case and
17 | always call your variables and functions by the exact name used when
18 | declaring them.
19 |
20 | ## Comments
21 | Comments in LDPL are denoted with a hash symbol ('#') and can be placed both
22 | on their own line or at the end of a line that already contains a statement.
23 | Everything after the hash is considered to be part of the comment and,
24 | therefore, not executed.
25 |
26 | :::coffeescript
27 | data:
28 | # This won't be executed
29 | # This won't be either
30 | procedure:
31 | # This line won't be interpreted
32 |
33 | ## Data and Procedure Sections
34 | LDPL was designed to be a rigidly structured programming
35 | language and, as such, variable declarations and the remaining code procedures
36 | are separated into two different, mutually exclusive sections within every
37 | source file: the `data:` section and the `procedure:` section.
38 |
39 | :::coffeescript
40 | data:
41 | # Variables go here
42 | procedure:
43 | # The rest of the code goes here
44 |
45 | Variable declarations should be placed within the **data** section, while the
46 | rest of the code should be placed inside the **procedure** section. Further
47 | sub-procedures should be placed also within the **procedure** section, inside their
48 | own **sub-procedure** subsections.
49 |
50 | The **data** section may be obviated if no variables are used.
51 |
52 | If your project consists of multiple LDPL source files, each file must have its
53 | own data and procedure sections.
54 |
55 | ## Including More Source Files
56 |
57 | You can import other LDPL source files to your LDPL source by using the
58 | **include** statement. For example, say you have two sources:
59 |
60 | :::coffeescript
61 | # This is 'firstSource.ldpl'
62 | procedure:
63 | call someSubprocedure
64 |
65 | and
66 |
67 | :::coffeescript
68 | # This is 'includedFile.ldpl'
69 | procedure:
70 | sub someSubprocedure
71 | display "Hi there!"
72 | end sub
73 |
74 | You can import the second source into the first one in order to create one
75 | big source file like this:
76 |
77 | :::coffeescript
78 | # This is 'firstSource.ldpl'
79 | include "includedFile.ldpl"
80 | procedure:
81 | call someSubprocedure
82 |
83 | When you run the code above, it will print
84 |
85 | :::text
86 | Hi there!
87 |
88 | using the sub-procedure `someSubprocedure` included from the second file.
89 |
90 | The location where the included files are searched for is relative to the file
91 | that includes them. You may include as many files as you like.
92 |
93 | The `include` statement can only be used **before** the **data** section.
94 |
95 | ## C++ Extensions
96 |
97 | LDPL source code can be extended using **C++ Extensions**, C++ source files
98 | that can be compiled along the C++ source code generated by the LDPL compiler.
99 | While these are explained in greater detail in their respective section of
100 | this document, two statements are relevant to this part of the documentation:
101 | the `flag` and `extension` statements.
102 |
103 | ## C++ Compiler Flags
104 |
105 | When writing C++ code, you may need to pass some flags to the C++ compiler.
106 | Say, for example, you are writing something using the SDL Library. When
107 | trying to compile your code, you will need to pass the flag `-lSDL` to your
108 | C++ compiler. This same thing can be achieved under LDPL by using the `flag`
109 | statement.
110 |
111 | Following the example above, if you want to pass the flag `-lSDL` to the C++
112 | compiler that compiles the code generated by the LDPL compiler from your LDPL
113 | source code, you may do this:
114 |
115 | :::coffeescript
116 | flag "-lSDL"
117 | flag "-fpermissive" # you can pass as many flags as you want
118 | data:
119 | #...
120 | procedure:
121 | #...
122 |
123 | Often, different operating systems require different flags. In those cases,
124 | you can restrict the `flag` statement to a particular OS:
125 |
126 | :::coffeescript
127 | flag "-O3"
128 | flag linux "-lncursesw"
129 | flag macos "-lncurses"
130 | flag macos "-D_XOPEN_SOURCE_EXTENDED" # multiple flags per OS are permitted
131 | data:
132 | #...
133 | procedure:
134 | #...
135 |
136 | !!! tip
137 | LDPL officially supports the following operating systems:
138 |
139 | - Linux
140 | - MacOS
141 | - Android
142 |
143 | And includes experimental support for these fine systems:
144 |
145 | - BSD
146 | - Emscripten
147 |
148 | The `flag` statement can only be used **before** the **data** section.
149 |
150 | ## C++ Extension Including
151 |
152 | Extensions are C++ source files that you can compile along your LDPL source
153 | in order to extend the language, as stated above. If you want to include an
154 | extension, you may use the `extension` statement. For example:
155 |
156 | :::coffeescript
157 | extension "someDirectory/someFile.cpp"
158 | flag "-O3"
159 | data:
160 | #...
161 | procedure:
162 | #...
163 |
164 | The `extension` statement can only be used **before** the **data** section.
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/docs/text.md:
--------------------------------------------------------------------------------
1 | !!!Note
2 | While this section is up-to-date and complete, it has to be reformated
3 | to be easier on the eyes. All UPPERCASE statement names and code should
4 | be changed to lowercase.
5 |
6 | ## `IN _ JOIN _`
7 |
8 | The `IN JOIN` statement concatenates two or more values and stores them in a TEXT variable. If any of those values is a number, it is converted to a string before concatenation.
9 |
10 | **Syntax:**
11 |
12 | ```coffeescript
13 | IN JOIN
14 | ```
15 |
16 | **Example:**
17 |
18 | ```coffeescript
19 | IN myTextVariable JOIN "Hello World!" " " "Welcome to LDPL!" crlf
20 | ```
21 |
22 | will store
23 |
24 | ```coffeescript
25 | "Hello World! Welcome to LDPL!\n"
26 | ```
27 |
28 | in `myTextVariable`.
29 |
30 |
31 | ## `REPLACE _ WITH _ FROM _ IN _`
32 |
33 |
34 | The `REPLACE` statement finds and replaces every occurrence of some TEXT in a TEXT variable or value some other TEXT. The result is then stored in a TEXT variable.
35 |
36 | **Syntax:**
37 |
38 | ```coffeescript
39 | REPLACE WITH FROM IN
40 | ```
41 |
42 | **Example:**
43 |
44 | ```coffeescript
45 | REPLACE "COBOL" FROM "COBOL is great!" WITH "LDPL" IN sentiment
46 | DISPLAY sentiment crlf
47 | ```
48 |
49 | Outputs:
50 |
51 | ```text
52 | LDPL is great!
53 | ```
54 |
55 | ## `SPLIT _ BY _ IN _`
56 |
57 |
58 | The `SPLIT` statement breaks up a single TEXT variable into multiple parts based on another TEXT variable and puts those parts into sub-indexes of a `TEXT LIST`, starting at the NUMBER `0` and incrementing by whole numbers. This allows you to break up a text sentence into multiple parts by splitting on spaces, for example. Or to split a file into lines by splitting on `"\n"`
59 |
60 | To break TEXT into individual characters, split by the empty string of `""`.
61 |
62 | **Syntax:**
63 |
64 | ```coffeescript
65 | SPLIT BY IN
66 | ```
67 |
68 | **Example:**
69 |
70 | ```coffeescript
71 | DATA:
72 | parts IS TEXT LIST
73 | PROCEDURE:
74 | SPLIT "Hello there!" BY " " IN parts
75 | display parts:0 crlf parts:1 crlf
76 | ```
77 |
78 | will output:
79 |
80 | ```text
81 | Hello
82 | there!
83 | ```
84 |
85 | **Split into characters:**
86 |
87 | ```coffeescript
88 | DATA:
89 | parts IS TEXT LIST
90 | PROCEDURE:
91 | SPLIT "onomatopoeia" BY "" IN parts
92 | DISPLAY parts:3 " is M " crlf
93 | ```
94 |
95 | will output:
96 |
97 | ```text
98 | m is M
99 | ```
100 |
101 | ## `GET CHARACTER AT _ FROM _ IN _`
102 |
103 | The `GET CHARACTER AT` statement gets the character at the position indicated by the NUMBER value from the TEXT value and stores it in a TEXT variable.
104 |
105 | **Syntax:**
106 |
107 | ```coffeescript
108 | GET CHARACTER AT FROM IN
109 | ```
110 |
111 | ## `GET LENGTH OF _ IN _`
112 |
113 | The `GET LENGTH OF` statement counts the number of characters in the passed TEXT and stores that number in the NUMBER variable.
114 |
115 | **Syntax:**
116 |
117 | ```coffeescript
118 | GET LENGTH OF IN
119 | ```
120 |
121 | ## `GET ASCII CHARACTER _ IN _`
122 |
123 | The `GET ASCII CHARACTER` statement stores the character with the ASCII code passed in NUMBER or NUMBER-VAR in TEXT-VAR.
124 |
125 | **Syntax:**
126 |
127 | ```coffeescript
128 | GET ASCII CHARACTER IN
129 | ```
130 |
131 | ## `GET CHARACTER CODE OF _ IN _`
132 |
133 | The `GET CHARACTER CODE OF` statement stores the ASCII code of the character passed in TEXT or TEXT-VAR in NUMBER-VAR. Will fail if the length of the string passed in TEXT or TEXT-VAR is not 1.
134 |
135 | **Syntax:**
136 |
137 | ```c
138 | GET CHARACTER CODE OF IN
139 | ```
140 |
141 | **Error Codes:**
142 |
143 | Multi-byte characters \(like emojis and non-ASCII characters\) cannot be parsed by this statement. When trying to do so, the operation will fail and the following values will be returned into the `ERRORCODE` and `ERRORTEXT` variables:
144 |
145 | * `ERRORCODE`: 1
146 | * `ERRORTEXT`: "Multibyte character received \(probably UTF-8\). Can't be parsed into a single number."
147 |
148 | !!!warning
149 | Always use the `ERRORCODE` variable to check if the operation was successful or not. Do **not** use `ERRORTEXT` for anything else than displaying the error found, as its contents may change in future releases of LDPL.
150 |
151 |
152 | ## `STORE QUOTE _ IN _`
153 |
154 | The `STORE QUOTE IN` statement allows you to store multiple lines in a single TEXT variable. Between the `STORE QUOTE IN` and `END QUOTE` statements whitespace is preserved literally, escape codes like `\t` and `\e` work the same as they do in regular text variables \(and can themselves be escaped using `\\`\), and double quotes \(`"`\) don't need to be escaped.
155 |
156 | **Syntax:**
157 |
158 | ```python
159 | STORE QUOTE IN
160 | #Text goes here
161 | END QUOTE
162 | ```
163 |
164 | **Example:**
165 |
166 | ```coffeescript
167 | DATA:
168 | template IS TEXT
169 |
170 | PROCEDURE:
171 | STORE QUOTE IN template
172 |
173 | {{title}}
174 | {{body}}
175 |
176 | END QUOTE
177 |
178 | # ...code to use the template...
179 | ```
180 |
181 | ## `GET INDEX OF _ FROM _ IN _`
182 |
183 |
184 | The `GET INDEX OF - FROM - IN` statement stores in a NUMBER variable the position of the first occurrence of a specified value in a string or TEXT variable. The first position of a string \(the first letter\) is considered to be the position number `0`. The value `-1` is stored if there are no occurrences.
185 |
186 | **Syntax:**
187 |
188 | ```coffeescript
189 | GET INDEX OF FROM IN
190 | ```
191 |
192 | **Example:**
193 |
194 | ```coffeescript
195 | DATA:
196 | position IS NUMBER
197 | PROCEDURE:
198 | GET INDEX OF "is" FROM "LDPL is nice!" IN position
199 | DISPLAY position CRLF
200 | # Will display 5.
201 | ```
202 |
203 | ## `COUNT _ FROM _ IN _`
204 |
205 | The `COUNT - FROM - IN` statement counts all the appearances of a string in another string and stores that value in a NUMBER variable.
206 |
207 | **Syntax:**
208 |
209 | ```coffeescript
210 | COUNT FROM IN
211 | ```
212 |
213 | **Example:**
214 |
215 | ```coffeescript
216 | DATA:
217 | count IS NUMBER
218 | PROCEDURE:
219 | COUNT "the" FROM "the cat is called theodore" IN count
220 | DISPLAY count CRLF
221 | # Will display 2, as the can be found two times in that sentence.
222 | ```
223 |
224 | ## `SUBSTRING _ FROM _ LENGTH _ IN _`
225 |
226 | The `SUBSTRING - FROM - LENGTH - IN` statement extracts parts of a string, beginning at the character at the specified position and storing in the destination TEXT variable the specified number of characters.
227 |
228 | **Syntax:**
229 |
230 | ```coffeescript
231 | SUBSTRING FROM LENGTH IN
232 | ```
233 |
234 | **Example:**
235 |
236 | ```coffeescript
237 | DATA:
238 | foo IS TEXT
239 | PROCEDURE:
240 | SUBSTRING "Hello there!" FROM 1 LENGTH 4 IN foo
241 | # This will extract 4 characters from position 1
242 | DISPLAY foo CRLF
243 | # Will display "ello"
244 | ```
245 |
246 | ## `TRIM _ IN`
247 |
248 |
249 | The `TRIM - IN` statement removes whitespace from both sides of a string and stores the resulting string in a TEXT variable.
250 |
251 | **Syntax:**
252 |
253 | ```coffeescript
254 | TRIM IN
255 | ```
256 |
257 | **Example:**
258 |
259 | ```coffeescript
260 | DATA:
261 | foo IS TEXT
262 | PROCEDURE:
263 | TRIM " hello there! " IN foo
264 | DISPLAY foo CRLF
265 | # Will display "hello there!"
266 | ```
267 |
268 | ## `CONVERT _ TO UPPERCASE IN _`
269 |
270 | The `CONVERT - TO UPPERCASE IN` statement converts all the characters in a string to uppercase and stores the resulting string in a TEXT variable.
271 |
272 | **Syntax:**
273 |
274 | ```coffeescript
275 | CONVERT TO UPPERCASE IN
276 | ```
277 |
278 | **Example:**
279 |
280 | ```coffeescript
281 | DATA:
282 | greeting IS TEXT
283 | PROCEDURE:
284 | CONVERT "hello there!" TO UPPERCASE IN greeting
285 | DISPLAY greeting CRLF
286 | # Will display "HELLO THERE!"
287 | ```
288 |
289 | ## `CONVERT _ TO LOWERCASE IN _`
290 |
291 | The `CONVERT - TO LOWERCASE IN` statement converts all the characters in a string to lowercase and stores the resulting string in a TEXT variable.
292 |
293 | **Syntax:**
294 |
295 | ```coffeescript
296 | CONVERT TO LOWERCASE IN
297 | ```
298 |
299 | **Example:**
300 |
301 | ```coffeescript
302 | DATA:
303 | greeting IS TEXT
304 | PROCEDURE:
305 | CONVERT "HELLO THERE!" TO LOWERCASE IN greeting
306 | DISPLAY greeting CRLF
307 | # Will display "hello there!"
308 | ```
309 |
--------------------------------------------------------------------------------
/docs/time.md:
--------------------------------------------------------------------------------
1 | ## `get year in _`
2 |
3 | The `get year in _` stores the current year number in the passed number variable.
4 |
5 | **Syntax:**
6 |
7 | ```coffeescript
8 | get year in
9 | ```
10 |
11 | ## `get month in _`
12 |
13 | The `get month in _` stores the current month number (1 - 12) in the passed number variable.
14 |
15 | **Syntax:**
16 |
17 | ```coffeescript
18 | get month in
19 | ```
20 |
21 | ## `get day in _`
22 |
23 | The `get day in _` stores the current day of the month (1 - 31) in the passed number variable.
24 |
25 | **Syntax:**
26 |
27 | ```coffeescript
28 | get day in
29 | ```
30 |
31 | ## `get hour in _`
32 |
33 | The `get hour in _` stores the current hour in the passed number variable.
34 |
35 | **Syntax:**
36 |
37 | ```coffeescript
38 | get hour in
39 | ```
40 |
41 | ## `get minutes in _`
42 |
43 | The `get minutes in _` stores the current minutes in the passed number variable.
44 |
45 | **Syntax:**
46 |
47 | ```coffeescript
48 | get minutes in
49 | ```
50 |
51 | ## `get seconds in _`
52 |
53 | The `get seconds in _` stores the current seconds in the passed number variable.
54 |
55 | **Syntax:**
56 |
57 | ```coffeescript
58 | get seconds in
59 | ```
60 |
61 | ## `get epoch in _`
62 |
63 | The `get epoch in _` stores the current Unix time (the number of seconds that
64 | have elapsed since the Unix epoch, that is the time 00:00:00 UTC on 1 January
65 | 1970) in the passed number variable.
66 |
67 | **Syntax:**
68 |
69 | ```coffeescript
70 | get epoch in
71 | ```
72 |
--------------------------------------------------------------------------------
/images/big-ldpl4.0-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/big-ldpl4.0-logo.png
--------------------------------------------------------------------------------
/images/ldpl-4.0-badge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldpl-4.0-badge.png
--------------------------------------------------------------------------------
/images/ldpl-4.0-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldpl-4.0-logo.png
--------------------------------------------------------------------------------
/images/ldpl-logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldpl-logo-white.png
--------------------------------------------------------------------------------
/images/ldpl-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldpl-logo.png
--------------------------------------------------------------------------------
/images/ldpl-open-graph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldpl-open-graph.png
--------------------------------------------------------------------------------
/images/ldplsaur-4.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldplsaur-4.0.png
--------------------------------------------------------------------------------
/images/ldplsaur-briefcase.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldplsaur-briefcase.png
--------------------------------------------------------------------------------
/images/ldplsaur-giant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldplsaur-giant.png
--------------------------------------------------------------------------------
/images/ldplsaur.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/ldplsaur.png
--------------------------------------------------------------------------------
/images/lpm-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/lpm-logo.png
--------------------------------------------------------------------------------
/images/reference-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/reference-logo.png
--------------------------------------------------------------------------------
/images/release-logos/5.1.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/5.1.0.png
--------------------------------------------------------------------------------
/images/release-logos/active-argentinosaurus-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/active-argentinosaurus-white.png
--------------------------------------------------------------------------------
/images/release-logos/active-argentinosaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/active-argentinosaurus.png
--------------------------------------------------------------------------------
/images/release-logos/busy-brontosaurus-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/busy-brontosaurus-white.png
--------------------------------------------------------------------------------
/images/release-logos/busy-brontosaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/busy-brontosaurus.png
--------------------------------------------------------------------------------
/images/release-logos/creative-carnotaurus-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/creative-carnotaurus-white.png
--------------------------------------------------------------------------------
/images/release-logos/creative-carnotaurus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/creative-carnotaurus.png
--------------------------------------------------------------------------------
/images/release-logos/diligent-dreadnoughtus-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/diligent-dreadnoughtus-white.png
--------------------------------------------------------------------------------
/images/release-logos/diligent-dreadnoughtus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/diligent-dreadnoughtus.png
--------------------------------------------------------------------------------
/images/release-logos/eloquent-eoraptor-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/eloquent-eoraptor-white.png
--------------------------------------------------------------------------------
/images/release-logos/eloquent-eoraptor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/eloquent-eoraptor.png
--------------------------------------------------------------------------------
/images/release-logos/friendly-falcarius-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/friendly-falcarius-white.png
--------------------------------------------------------------------------------
/images/release-logos/friendly-falcarius.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/friendly-falcarius.png
--------------------------------------------------------------------------------
/images/release-logos/groovy-gualicho.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/groovy-gualicho.png
--------------------------------------------------------------------------------
/images/release-logos/source/5.1.0.acorn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/release-logos/source/5.1.0.acorn
--------------------------------------------------------------------------------
/images/tutorial-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lartu/ldpl/5a11fe8e8c8acf9b6d8f7a1a13558d6e92122351/images/tutorial-logo.png
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | # +=============================================+
2 | # | |
3 | # | The __ ____ ____ __ |
4 | # | / / / __ \/ __ \/ / |
5 | # | / / / / / / /_/ / / |
6 | # | / /___/ /_/ / ____/ /___ |
7 | # | /_____/_____/_/ /_____/ |
8 | # | Programming Language |
9 | # | http://www.ldpl-lang.org/ |
10 | # | |
11 | # +=============================================+
12 |
13 | # +----------+
14 | # | MAKEFILE |
15 | # +----------+
16 | # Usage:
17 | # make [x86=true] [version='""']
18 | # make install
19 |
20 | # --- Version Information ---
21 | VERSION = '"5.2.0"' #LDPL Version
22 | VERSIONNAME = '"Groovy Gualicho"' #LDPL Version Name
23 |
24 | # --- Options ---
25 | # Alternative version name (make version="")
26 | ifdef version
27 | VERSION = '"$(version)"'
28 | endif
29 | # x86 cross compilation options (make x86=true)
30 | ifdef x86
31 | CROSS = -m32
32 | VERSION = '"$(version) (i386)"'
33 | endif
34 | #Flags for static compilation on Windows and Linux (not Android)
35 | ifneq ($(shell uname -s),Darwin)
36 | ifneq ($(shell uname -o),Android)
37 | LFLAGS = -static-libgcc -static-libstdc++
38 | endif
39 | endif
40 | #PREFIX is environment variable, but if it is not set, then set default value
41 | ifeq ($(PREFIX),)
42 | PREFIX := /usr/local
43 | endif
44 |
45 | # --- Makefile Data ---
46 | SOURCE = ldpl.cpp
47 | OUT = ldpl
48 | LPMLOCATION = ~/ldpl/lpm/
49 | LDPLLIBLOCATION = /lib/ldpl
50 |
51 | # --- Compilation Flags ---
52 | FLAGS = -Wall -std=gnu++11 -fpermissive -DVERSION=$(VERSION) -DVERSIONNAME=$(VERSIONNAME) -DCOMPILEDATE='"$(shell date +%Y-%m-%d)"' -DCOMPILEHOUR='"$(shell date +%H:%M:%S)"' -DLPMLOCATION='"$(DESTDIR)$(PREFIX)$(LPMLOCATION)"' -DLDPLLIBLOCATION='"$(DESTDIR)$(PREFIX)$(LDPLLIBLOCATION)"'
53 |
54 | # --- Build Rules ---
55 | # Build LDPL
56 | all:
57 | cd src && $(CXX) $(FLAGS) $(CROSS) $(SOURCE) -o $(OUT) $(LFLAGS)
58 | mkdir -p build
59 | mv src/$(OUT) build
60 |
61 | # Delete built file
62 | clean:
63 | rm -rf build
64 |
65 | install: build/ldpl
66 | install -d $(DESTDIR)$(PREFIX)/bin/
67 | install -m 775 build/ldpl $(DESTDIR)$(PREFIX)/bin/
68 | install -d $(DESTDIR)$(PREFIX)/lib/ldpl
69 | install src/ldpl_lib/ldpl_lib.cpp $(DESTDIR)$(PREFIX)$(LDPLLIBLOCATION)
70 | install src/ldpl_lib/BigInt.hpp $(DESTDIR)$(PREFIX)$(LDPLLIBLOCATION)
71 |
72 | uninstall:
73 | rm $(DESTDIR)$(PREFIX)/bin/ldpl
74 | rm -rf $(DESTDIR)$(PREFIX)$(LDPLLIBLOCATION)
75 |
--------------------------------------------------------------------------------
/man/README:
--------------------------------------------------------------------------------
1 | +------------------------------+
2 | | LDPL Only Man File Generator |
3 | | (LDPL OMFG) |
4 | +------------------------------+
5 |
6 | *** Usage ***
7 |
8 | Run the command:
9 |
10 | $ ./generateMan.sh
11 |
12 | to generate an updated LDPL man page. Done.
13 | Your new man page is 'ldpl.1'.
14 |
15 | *** Alternatively, you can walk through the process step-by-step ***
16 |
17 | To recompile a man page for LDPL, clone the LDPL documentation repository
18 | (git clone https://www.github.com/lartu/ldpl-docs) in this folder.
19 |
20 | Then copy compileman.php and ldplman-intro into the cloned folder and
21 | go inside it. Then run:
22 |
23 | $ php compileman.php > ldpl.1
24 |
25 | A file called ldpl.1 will be generated. Copy it to the previous
26 | folder and delete the cloned folder.
27 |
28 | You can add it to your the new man file to your man pages or just open it by
29 | running:
30 |
31 | $ man ./ldpl.1
32 |
33 | Please note that as man pages for LDPL are generated from the LDPL
34 | documentation, they SHOULD NEVER be edited by hand.
35 |
--------------------------------------------------------------------------------
/man/compileman.php:
--------------------------------------------------------------------------------
1 | 0){
9 | $manPage = $manPage . "\n\n" . file_get_contents($line);
10 | }
11 | else if(strlen($line) > 0 && trim(substr($line, 0, 2)) == "##"){
12 | $manPage = $manPage . "\n\n" . ".ce 1\n.SH -=-=-=-=- DOCS: " . trim(strtoupper(substr($line, 2))) . " -=-=-=-=-";
13 | }
14 | }
15 |
16 | //Replace all originally blank lines with
17 | $manPage = explode("\n", $manPage);
18 | foreach($manPage as &$line){
19 | if(strlen(trim($line)) == 0){
20 | $line = "";
21 | }
22 | }
23 | $manPage = implode("\n", $manPage);
24 |
25 | $manPage = str_replace("\\", "\\\\", $manPage);
26 | $manPage = str_replace("\(", "(", $manPage);
27 | $manPage = str_replace("\)", ")", $manPage);
28 | $manPage = str_replace("**", "", $manPage);
29 | $manPage = str_replace("_ ", " ", $manPage);
30 | $manPage = str_replace(" _", " ", $manPage);
31 | $manPage = preg_replace("/\!\[(.*?)\]\(.*?\)/m", "", $manPage);
32 | $manPage = preg_replace("/\[(.*?)\]\(.*?\)/m", "$1", $manPage);
33 | $manPage = preg_replace("/\:\:\:.*/m", "", $manPage);
34 | $manPage = preg_replace("/\!\!\!\s*warning/m", "~ Warning ~", $manPage);
35 | $manPage = preg_replace("/\!\!\!\s*hint/m", "~ Hint ~", $manPage);
36 | $manPage = preg_replace("/\!\!\!\s*note/m", "~ Note ~", $manPage);
37 | $manPage = preg_replace("/\!\!\!\s*tip/m", "~ Tip ~", $manPage);
38 | $manPage = preg_replace("/\!\!\!\s*Warning/m", "~ Warning ~", $manPage);
39 | $manPage = preg_replace("/\!\!\!\s*Hint/m", "~ Hint ~", $manPage);
40 | $manPage = preg_replace("/\!\!\!\s*Note/m", "~ Note ~", $manPage);
41 | $manPage = preg_replace("/\!\!\!\s*Tip/m", "~ Tip ~", $manPage);
42 |
43 |
44 | /*$manPage = str_replace("\(", "(", $manPage);
45 | $manPage = str_replace("\)", ")", $manPage);
46 | $manPage = str_replace('{% hint style="info" %}', "-- Note:\n.br", $manPage);
47 | $manPage = str_replace('{% hint style="warning" %}', "-- Warning:\n.br", $manPage);
48 | $manPage = str_replace('{% endhint %}', ".br\n--", $manPage);
49 | $manPage = str_replace('{% endcode-tabs-item %}', "", $manPage);
50 | $manPage = str_replace('{% endcode-tabs %}', "", $manPage);
51 | $manPage = str_replace('{% code-tabs %}', "", $manPage);
52 | $manPage = str_replace('{% code-tabs-item title="', "File: ", $manPage);
53 | $manPage = str_replace('" %}', "\n.br", $manPage);
54 | $manPage = str_replace("\\", "\\\\", $manPage);
55 |
56 |
57 | $manPage = str_replace("\[", "[", $manPage);
58 | $manPage = str_replace("\]", "]", $manPage);
59 | $manPage = str_replace("\#", "#", $manPage);
60 | $manPage = str_replace(">", ">", $manPage);
61 | $manPage = str_replace("<", "<", $manPage);*/
62 |
63 |
64 | $manPage = explode("\n", $manPage);
65 |
66 | $incode = false;
67 | $lineNum = 1;
68 |
69 | //Convert each page to groff
70 | foreach($manPage as &$line){
71 |
72 | $line = rtrim($line);
73 |
74 | if(strlen($line) > 0 && substr($line, 0, 3) == "```"){
75 | $incode = !$incode;
76 | if($incode) $lineNum = 1;
77 | $line = "";
78 | }
79 | else if($incode){
80 | /*if($lineNum < 10)
81 | $line = $lineNum . " | " . $line . "\n.br";
82 | else
83 | $line = $lineNum . "| " . $line . "\n.br";
84 | $lineNum++;*/
85 | $line = " " . $line . "\n.br";
86 | }
87 | else if(strlen($line) > 0 && substr(trim($line), 0, 2) == "* "){
88 | //$line = ".br\n • " . trim(substr($line, 2));
89 | $count = 1;
90 | $line = str_replace("*", "•", $line, $count);
91 | if(substr($line, 0, 4) != " "){
92 | $line = " " . trim($line);
93 | }
94 | }
95 | else if(strlen($line) > 0 && substr(trim($line), 0, 2) == "- "){
96 | //$line = ".br\n • " . trim(substr($line, 2));
97 | $count = 1;
98 | $line = str_replace("-", "•", $line, $count);
99 | if(substr($line, 0, 4) != " "){
100 | $line = " " . trim($line);
101 | }
102 | }
103 | else if(strlen($line) > 0 && substr($line, 0, 1) == "|"){
104 | $line = ".br\n" . trim($line);
105 | }
106 | /*else if(strlen($line) > 0 && trim(substr($line, 0, 4)) == "####"){
107 | $line = ".B " . trim(substr($line, 4));
108 | }
109 | if(strlen($line) > 0 && trim(substr($line, 0, 3)) == "###"){
110 | $line = ".B " . trim(substr($line, 3));
111 | }
112 | else if(strlen($line) > 0 && trim(substr($line, 0, 2)) == "##"){
113 | $line = ".B " . trim(substr($line, 2));
114 | }
115 | else if(strlen($line) > 0 && substr($line, 0, 1) == "#"){
116 | $line = ".SH " . strtoupper(trim(substr($line, 1)));
117 | }
118 | else if($line == "!"){
119 | $line = "";
120 | }*/
121 | }
122 |
123 | $manPage = implode("\n", $manPage);
124 |
125 | $manPage = str_replace('`', "'", $manPage);
126 | $manPage = str_replace("\n\n", "\n", $manPage, $count);
127 | $manPage = str_replace("\n\n", "\n\n", $manPage, $count);
128 | $manPage = str_replace("", "", $manPage, $count);
129 | echo file_get_contents("ldplman-intro") . "\n" . $manPage . "\n";
130 | ?>
131 |
--------------------------------------------------------------------------------
/man/generateMan.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | cp -r ../docs docs
3 | cp compileman.php docs/
4 | cp ldplman-intro docs/
5 | cd docs
6 | php compileman.php > ldpl.1
7 | cp ldpl.1 ..
8 | cd ..
9 | rm -rf docs
10 |
--------------------------------------------------------------------------------
/man/ldplman-intro:
--------------------------------------------------------------------------------
1 | .TH LDPL 1 "5 may 2019" "LDPL Man 1.0"
2 |
3 | .SH NAME
4 | ldpl - The LDPL programming language compiler
5 |
6 | .SH SYNOPSIS
7 | .PP
8 | ldpl [-i=]... |-c
9 | [-o=|-r] [-f=]... [-n]
10 | .br
11 | ldpl [-v|-h]
12 |
13 | For more information on these options you can run "ldpl -h".
14 |
15 | .SH DESCRIPTION
16 | .PP
17 | This program compiles LDPL source code into executable binaries.
18 | LDPL is a programming language designed from the ground up to be excessively expressive, fast, readable and easy to learn.
19 | In order to be able to properly compile LDPL executables you
20 | .I
21 | must
22 | have a valid C++ compiler on your $PATH linked to the name 'c++'.
23 |
24 | Documentation and reference for the LDPL Programming Language can be found in the sections below.
25 |
26 | .SH OPTIONS
27 | .PP
28 | -v, --version
29 | Print out LDPL version info and release details.
30 |
31 | -h, --help
32 | Print this list of options.
33 |
34 | -r
35 | By using -r you can just compile the project and print the C++ representation for that code.
36 |
37 | -o=
38 | You can set the output file for the compiled binary with the -o flag. For example, if you want to name your program "dog", you could compile it with ldpl -o=dog main.ldpl.
39 |
40 | -i=
41 | Extensions can be imported by using this flag; see the Extensions section.
42 |
43 | -f=
44 | The -f flag can be used to add flags to the C++ compilation line. See the Building C++ Extensions section for more information.
45 |
46 | -n, --non-static
47 | On Linux and Windows platforms, LDPL builds static binaries by default. If you want to build non-static ones use the -ns flag. To build on Android Termux you must use this flag.
48 |
49 | -c
50 | The -c flag tells LDPL to accept source code from the standard input.
51 |
52 | .SH AUTHOR
53 | This document is based on the LDPL Reference, written by Martín del Río in collaboration with Chris West.
54 |
55 | .SH REPORTING BUGS
56 | Report any bugs to .
57 |
58 | .SH COPYRIGHT
59 | Copyright © 2018 - 2019, Martín del Río. LDPL may be copied only under the terms of the GNU General Public License 3.0, which may be found in the LDPL repository.
60 | .br
61 | This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
62 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: LDPL Docs
2 | nav:
3 | - Introduction: index.md
4 | - Code Structure: structure.md
5 | - Data Section & Variables: data.md
6 | - Procedure Section & Subs: procedure.md
7 | - Naming Schemes: naming.md
8 | - Control Flow Statements: flow.md
9 | - Arithmetic Statements: arithmetic.md
10 | - Time Statements: time.md
11 | - Text Statements: text.md
12 | - List Statements: list.md
13 | - Map Statements: map.md
14 | - I/O Statements: io.md
15 | - C++ Extensions: cppext.md
16 | theme:
17 | name: 'material'
18 |
19 | markdown_extensions:
20 | - admonition
21 | - codehilite:
22 | linenums: true
23 |
24 |
--------------------------------------------------------------------------------
/snapcraft.yaml:
--------------------------------------------------------------------------------
1 | name: ldpl-lang
2 | base: core22
3 | version: '5.1.0'
4 | summary: Compiled programming language for Unix systems, inspired by COBOL
5 | description: |
6 | The LDPL project produces the LDPL Programming Language, a free, powerful, compiled, open-source programming language designed from the ground up to be excessively expressive, readable, fast and easy to learn. LDPL was designed to run on Unix systems, including AMD-64 Linux, macOS, ARMv8 Linux, Android Termux and both Intel and PowerPC OS X (tested from Tiger 10.4 onwards). It even supports UTF-8 out of the box.
7 |
8 | grade: stable
9 | confinement: classic
10 |
11 | apps:
12 | ldpl:
13 | command: bin/ldpl
14 |
15 | parts:
16 | ldpl:
17 | plugin: autotools
18 | source: https://github.com/Lartu/ldpl.git
19 | source-tag: '5.1.0'
20 | build-packages:
21 | - g++
22 | - build-essential
23 | - make
24 | - man-db
25 | - libc6-dev
26 | override-build: |
27 | make
28 | make install
29 | organize:
30 | /usr/local/bin/ldpl: bin/
31 |
32 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.13) # CMake version check
2 | project(ldpl) # Create project "simple_example"
3 | set(CMAKE_CXX_STANDARD 11) # Enable c++11 standard
4 |
5 | # Add main.cpp file of project root directory as source file
6 | set(SOURCE_FILES ldpl.cpp)
7 |
8 | set(VERSION "5.0")
9 | set(VERSIONNAME "Groovy Gualicho")
10 |
11 | # Alternative version name (cmake -Dversion="")
12 | if (version)
13 | set(VERSION ${version})
14 | endif ()
15 |
16 | if (CMAKE_SIZEOF_VOID_P EQUAL 4)
17 | string(CONCAT VERSION ${VERSION} " (i386)")
18 | add_definitions(-m32)
19 | endif ()
20 |
21 | # add VERSION
22 | set(VERSION " -DVERSION='\"${VERSION}\"' ")
23 | add_definitions(${VERSION})
24 |
25 | # add VERSIONNAME
26 | set(VERSIONNAME " -DVERSIONNAME='\"${VERSIONNAME}\"' ")
27 | add_definitions(${VERSIONNAME})
28 |
29 | add_definitions(-Wall -fpermissive)
30 |
31 | # Add DATE
32 | string(TIMESTAMP DATE "%Y-%m-%d")
33 | set(DATE " -DCOMPILEDATE='\"${DATE}\"' ")
34 | add_definitions(${DATE})
35 |
36 | # Add HOUR
37 | string(TIMESTAMP HOUR "+%H:%M:%S")
38 | set(HOUR " -DCOMPILEHOUR='\"${HOUR}\"' ")
39 | add_definitions(${HOUR})
40 |
41 | # add LPMLOCATION
42 | set(LPMLOCATION " -DLPMLOCATION='\"~/ldpl/lpm/\"' ")
43 | add_definitions(${LPMLOCATION})
44 |
45 | # add LDPLLIBLOCATION
46 | string(CONCAT LDPLLIBLOCATION ${CMAKE_INSTALL_PREFIX} "/lib/ldpl")
47 | set(LDPLLIBLOCATION " -DLDPLLIBLOCATION='\"${LDPLLIBLOCATION}\"' ")
48 | add_definitions(${LDPLLIBLOCATION})
49 |
50 | # Add executable target with source files listed in SOURCE_FILES variable
51 | add_executable(ldpl ${SOURCE_FILES})
52 |
53 | if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin|Android")
54 | target_link_libraries(ldpl -static-libgcc -static-libstdc++)
55 | endif ()
56 |
57 | install(TARGETS ldpl)
58 | install(FILES ldpl_lib/ldpl_lib.cpp TYPE LIB)
59 | install(FILES ../man/ldpl.1 TYPE MAN)
60 |
61 |
--------------------------------------------------------------------------------
/src/aux/aux_code.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions that add C++ code to the generated C++
2 | * file */
3 |
4 | // +---------------------------------------------+
5 | // | TODO: comment and format this file properly |
6 | // +---------------------------------------------+
7 |
8 | // This is called when we know all parameters of a subprocedure
9 | void open_subprocedure_code(compiler_state &state) {
10 | string name = state.current_subprocedure;
11 | vector ¶meters = state.subprocedures[name];
12 | vector> types;
13 | string code;
14 | code = "void " + fix_identifier(name, false) + "(";
15 | for (size_t i = 0; i < parameters.size(); ++i) {
16 | string identifier = fix_identifier(parameters[i], true, state);
17 | string type = state.get_c_type(state.variables[name][parameters[i]]);
18 | code += type + " & " + identifier;
19 | if (i < parameters.size() - 1) code += ", ";
20 | types.push_back(state.variables[name][parameters[i]]);
21 | }
22 | if (!state.correct_subprocedure_types(name, types))
23 | badcode(
24 | "SUB-PROCEDURE declaration parameter types doesn't match previous CALL",
25 | state.where);
26 | code += "){";
27 | state.add_code(code, state.where);
28 | state.remove_expected_subprocedure(name);
29 | }
30 |
31 | void add_call_code(string &subprocedure, vector ¶meters,
32 | compiler_state &state) {
33 | string code = fix_identifier(subprocedure, false) + "(";
34 | for (size_t i = 0; i < parameters.size(); ++i) {
35 | if (is_number(parameters[i]) || is_string(parameters[i])) {
36 | // C++ doen't allow passing literals in reference parameters, we create
37 | // vars for them
38 | string literal_paramater_var = state.new_literal_parameter_var();
39 | state.add_code((is_number(parameters[i]) ? "ldpl_number " : "graphemedText ") +
40 | literal_paramater_var + " = " + parameters[i] + ";",
41 | state.where);
42 | code += literal_paramater_var;
43 | } else {
44 | code += get_c_variable(state, parameters[i]);
45 | }
46 | if (i < parameters.size() - 1) code += ", ";
47 | }
48 | code += ");";
49 | state.add_code(code, state.where);
50 | }
--------------------------------------------------------------------------------
/src/aux/aux_container.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions to split and access [multi]containers
2 | */
3 |
4 | // +---------------------------------------------+
5 | // | TODO: comment and format this file properly |
6 | // +---------------------------------------------+
7 |
8 | // Given a 'full variable' (for example 'bar' or 'foo:0:"hi there":4'), a place
9 | // to store a variable name and a vector of strings to store all indexes, we get
10 | // the variable name and all its subindexes (if any) into the corresponding
11 | // variables.
12 | void split_vector(string &token, string &var_name, vector &indexes,
13 | compiler_state &state) {
14 | // First of all we want to know if we are dealing with a container variable,
15 | // that is a LIST of something of a MAP of something. Thus, we look for any
16 | // ':' in the full variable and store the possition of the (possible) first
17 | // one.
18 | size_t pos = token.find(":");
19 | // If we didn't find any ':', then we are dealing with a scalar variable.
20 | // We just get its name (the full variable) and an empty vector of indexes.
21 | if (pos == string::npos) {
22 | var_name = token;
23 | indexes = {};
24 | }
25 | // If we found a ':', but it's the last character in the full variable, that
26 | // means that we received something like 'foo:'. That's not right, so we rise
27 | // an error.
28 | else if (pos == token.size() - 1)
29 | error("Incomplete MAP or LIST access found (can't end on ':').");
30 | else {
31 | // If none of the above happened, then our container is formatted correctly.
32 | // Now it's time to split it. As we can have something like foo IS NUMBER
33 | // LIST LIST bar IS NUMBER LIST and try to access foo using a value stored
34 | // in bar (for example foo:bar:0:1, meaning the foo[bar[0]][1]), we have to
35 | // know how many indexes our container expects. We tokenize our container
36 | // using the tokenize function.
37 | vector tokens;
38 | tokenize(token, tokens, state.where, true, ':');
39 | // We take the first token as the variable name and then discard it.
40 | var_name = tokens[0];
41 | tokens.erase(tokens.begin(), tokens.begin() + 1);
42 | // For each of the remaining, we have to check if its a variable or not. If
43 | // its a variable name, it may be another container. For each container we
44 | // find, we append as many indexes that container requires to the previous
45 | // token we found (the index name). So, if we had foo and bar as stated
46 | // above, the parsing of foo:bar:0:1 would go like this:
47 | // - foo is taken as the variable name and thus skipped.
48 | // - bar is a container that takes one index. We'll then 'skip' one index.
49 | // We then push bar to a list of tokens we've already checked.
50 | // - 1 is an index, and we said we were going to 'skip' one index. What we
51 | // do
52 | // is, instead of pushing 1 to the list of tokens we've already checked,
53 | // we append it to the last token we found as an index access. So we take
54 | // the 'bar' that's already in our checked list and we turn it into
55 | // 'bar:1'.
56 | // - 0 is an index. We are not skipping anymore indexes as we already
57 | // skipped
58 | // '1', so we push it into our checked tokens list.
59 | // Our checked tokens list will end up like {'bar:1', 0}, that are the
60 | // indexes of foo we are trying to access.
61 | vector checked_tokens;
62 | size_t tokens_to_skip = 0;
63 | for (size_t i = 0; i < tokens.size(); ++i) {
64 | if (is_number(tokens[i]) || is_string(tokens[i])) {
65 | if (tokens_to_skip > 0) {
66 | checked_tokens.back() += ":" + tokens[i];
67 | tokens_to_skip--;
68 | } else {
69 | checked_tokens.push_back(tokens[i]);
70 | }
71 | }
72 | // If the current token is not a number nor a string, it must be a
73 | // variable name.
74 | else {
75 | // We get the types of the current variable.
76 | vector cvar_types = variable_type(tokens[i], state);
77 | // If the variable doesn't exist, we raise an error.
78 | if (cvar_types == vector{0}) {
79 | error("The variable " + tokens[i] + " doesn't exist in " + token +
80 | ".");
81 | }
82 | // We remove an element of the current variable types as the main type
83 | // (NUMBER or TEXT) never names a container type and thus cannot be
84 | // indexed.
85 | cvar_types.pop_back();
86 | // If we had to skip this token, we append it to the last token we have.
87 | if (tokens_to_skip > 0) {
88 | checked_tokens.back() += ":" + tokens[i];
89 | tokens_to_skip--;
90 | } else {
91 | checked_tokens.push_back(tokens[i]);
92 | }
93 | // We tell the splitter to skip this many tokens.
94 | tokens_to_skip += cvar_types.size();
95 | }
96 | }
97 | // After we've got all indexes we needed, we store our checked tokens list
98 | // into the indexes vector, that is what we are going to return with the
99 | // variable name.
100 | indexes = checked_tokens;
101 | }
102 | }
--------------------------------------------------------------------------------
/src/aux/aux_format.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions that do text or number formatting */
2 |
3 | void replace_whitespace(string &code) {
4 | // -- Replaces all whitespace within string --
5 | for (char &c : code) {
6 | if (isspace(c)) {
7 | c = ' ';
8 | }
9 | }
10 | }
11 |
12 | string fix_identifier(string ident, bool isVar, compiler_state &state) {
13 | // -- Replaces invalid C++ characters in internal and external identifiers --
14 | // when state is provided to fix_identifier it can fix external variables too.
15 | if (is_external(ident, state)) {
16 | return fix_external_identifier(ident, isVar);
17 | } else {
18 | return fix_identifier(ident, isVar);
19 | }
20 | }
21 |
22 | string fix_identifier(string identifier, bool isVariable) {
23 | // -- Appends a prefix based on its type to an identifier --
24 | return string(isVariable ? "VAR_" : "SUBPR_") + fix_identifier(identifier);
25 | }
26 |
27 | string fix_identifier(string identifier) {
28 | // -- Replaces invalid C++ characters in identifiers --
29 | const string validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:";
30 | ostringstream new_id;
31 | for (unsigned int i = 0; i < identifier.size(); ++i) {
32 | if (validChars.find(identifier[i]) != string::npos) {
33 | new_id << identifier[i];
34 | } else {
35 | new_id << "c" << (unsigned int)identifier[i] << "_";
36 | }
37 | }
38 | return new_id.str();
39 | }
40 |
41 | string fix_external_identifier(string identifier, bool isVariable) {
42 | // -- Replaces invalid C++ characters in external identifiers --
43 | // External identifiers are used by C++ extensions and thus have a simpler but
44 | // more restrictive name mangling algorithm: The only characters allowed are
45 | // `A-Z`, `0-9`, and `_`. All other characters are converted to `_`.
46 | const string validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:";
47 | string new_id;
48 | for (unsigned int i = 0; i < identifier.size(); ++i) {
49 | if (validChars.find(identifier[i]) != string::npos) {
50 | new_id += identifier[i];
51 | } else {
52 | new_id += "_";
53 | }
54 | }
55 | return new_id;
56 | }
57 |
58 | string &escape_c_quotes(string &str) {
59 | // -- Replaces all " in the passed string for \" --
60 | for (unsigned int i = 0; i < str.size(); ++i) {
61 | if (str[i] == '"') {
62 | str.erase(i, 1);
63 | str.insert(i, "\\\"");
64 | ++i;
65 | }
66 | }
67 | return str;
68 | }
69 |
70 | string &escape_c_backslashes(string &str) {
71 | // -- Replaces all " in the passed string for \" --
72 | for (unsigned int i = 0; i < str.size(); ++i) {
73 | if (str[i] == '\\') {
74 | str.erase(i, 1);
75 | str.insert(i, "\\\\");
76 | ++i;
77 | }
78 | }
79 | return str;
80 | }
81 |
82 | string expandHomeDirectory(string &filename) {
83 | // -- Expands a home directory (normaly when the character ~ is used) --
84 | #if defined(_WIN32)
85 | return filename;
86 | #else
87 | string homeDir = exec("echo $HOME");
88 | trim(homeDir);
89 | string newPath = "";
90 | for (size_t i = 0; i < filename.length(); ++i) {
91 | if (filename[i] == '~') {
92 | newPath += homeDir;
93 | } else {
94 | newPath += filename[i];
95 | }
96 | }
97 | return newPath;
98 | #endif
99 | }
--------------------------------------------------------------------------------
/src/aux/aux_info.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions that display information about the
2 | * compiler and the system */
3 |
4 | /// @brief Displays the LDPL version information message.
5 | void displayVersionInfo()
6 | {
7 | cout << endl;
8 | cout << " This is \033[32;1mLDPL version " << VERSION << "\033[0m '\033[32;1m"
9 | << VERSIONNAME << "\033[0m'." << endl;
10 | cout << endl;
11 | cout << " Copyright 2018-2024, \033[35;1mLartu\033[0m (www.lartu.net)."
12 | << endl;
13 | cout << " Built with amazing contributions from \033[35;1mChris West\033[0m, "
14 | "\033[35;1mDamián Garro\033[0m,"
15 | << endl;
16 | cout << " \033[35;1mIgnacio Losiggio\033[0m and other wonderful contributors."
17 | << endl;
18 | cout << endl;
19 | cout << " The LDPL Home Page can be found at "
20 | "\033[36;1mwww.ldpl-lang.org\033[0m."
21 | << endl;
22 | cout << " The LDPL source code is available at "
23 | "\033[36;1mwww.github.com/lartu/ldpl\033[0m."
24 | << endl;
25 | cout << endl;
26 | cout << " Complete documentation for LDPL should be found on this system"
27 | << endl;
28 | cout << " using '\033[33;1mman ldpl\033[0m'. If you have access to the "
29 | "internet, the"
30 | << endl;
31 | cout << " documentation can also be found online at "
32 | "\033[36;1mdocs.ldpl-lang.org\033[0m."
33 | << endl;
34 | cout << endl;
35 | cout << " LDPL may be copied only under the terms of the Apache License"
36 | << endl;
37 | cout << " Version 2.0, which may be found in the LDPL repository." << endl;
38 | cout << endl;
39 | cout << " This binary was compiled on \033[31;1m" << COMPILEDATE
40 | << "\033[0m at \033[31;1m" << COMPILEHOUR << "\033[0m." << endl;
41 | cout << endl;
42 | }
43 |
44 | /// @brief Displays the LDPL help information message.
45 | void displayHelpInfo()
46 | {
47 | cout << endl;
48 | cout << " \033[33;1mUsage:\033[0m" << endl;
49 | cout << " ldpl [-i='']... |-c" << endl;
50 | cout << " [-o=''|-r] [-f='']... [-n]" << endl;
51 | cout << " ldpl [-v|-h]" << endl;
52 | cout << endl;
53 | cout << " \033[33;1mOptions:\033[0m" << endl;
54 | cout << " -v --version Display LDPL version information"
55 | << endl;
56 | cout << " -h --help Display this information" << endl;
57 | cout << " -r Display generated C++ code" << endl;
58 | cout << " -o= Set output file for compiled binary"
59 | << endl;
60 | cout << " -i= Include file in current compilation"
61 | << endl;
62 | cout << " -f= Pass a flag to the C++ compiler" << endl;
63 | #ifdef STATIC_BUILDS
64 | cout << " -n --non-static Disables static binary building" << endl;
65 | #endif
66 | cout << " -c Compile from standard input" << endl;
67 | cout << endl;
68 | cout << " Complete documentation for LDPL should be found on this system"
69 | << endl;
70 | cout << " using '\033[33;1mman ldpl\033[0m'. If you have access to the "
71 | "internet, the"
72 | << endl;
73 | cout << " documentation can also be found online at "
74 | "\033[36;1mdocs.ldpl-lang.org\033[0m."
75 | << endl;
76 | cout << endl;
77 | }
78 |
79 | /// @brief Prints a non-fatal warning message.
80 | void warning(const string &msg)
81 | {
82 | cerr << "\033[1;35mLDPL Warning: ";
83 | cerr << msg;
84 | cerr << "\033[0m" << endl;
85 | }
86 |
87 | /// @brief Prints a message preceded by a *
88 | void bullet_msg(const string &msg)
89 | {
90 | cerr << "\033[1;33m*\033[0m ";
91 | cerr << msg << endl;
92 | }
93 |
94 | /// @brief Shows where the error was in a code error.
95 | void badcode(const string &msg, const code_location where)
96 | {
97 | error(msg + " (\033[0m" + where.current_file + ":" + to_string(where.current_line) + "\033[1;31m)");
98 | }
99 |
100 | /// @brief Shows a fatal error message and exits.
101 | void error(const string &msg)
102 | {
103 | cerr << "\033[1;31mLDPL Error: ";
104 | cerr << msg;
105 | cerr << "\033[0m" << endl;
106 | exit(1);
107 | }
108 |
109 | /// @brief Returns the current operating system
110 | string current_os()
111 | {
112 | // https://sourceforge.net/p/predef/wiki/OperatingSystems/
113 | #if defined(__linux__)
114 | return "LINUX";
115 | #elif defined(__APPLE__)
116 | return "MACOS";
117 | #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
118 | return "BSD";
119 | #elif defined(__ANDROID__)
120 | return "ANDROID";
121 | #elif defined(__EMSCRIPTEN__)
122 | return "EMSCRIPTEN";
123 | #else
124 | return "UNKNOWN";
125 | #endif
126 | }
--------------------------------------------------------------------------------
/src/aux/aux_line_like.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains the line_like function used for pattern matching lines */
2 |
3 | // +---------------------------------------------+
4 | // | TODO: comment and format this file properly |
5 | // +---------------------------------------------+
6 |
7 | #include "../ldpl.h"
8 |
9 | // Check if the tokens of a line passed are like the ones of a model line
10 | bool line_like(string model_line, vector &tokens,
11 | compiler_state &state)
12 | {
13 | // Tokenize model line
14 | vector model_tokens;
15 | tokenize(model_line, model_tokens, state.where, false, ' ');
16 | // Check that tokens match between line and model line
17 | if (tokens.size() < model_tokens.size())
18 | return false;
19 | unsigned int i = 0;
20 | unsigned int j = 0;
21 | for (; i < model_tokens.size(); ++i)
22 | {
23 | if (model_tokens[i] == "$name") // $name is a valid identifier for a
24 | // variable or a sub-procedure
25 | {
26 | for (char letter : tokens[j])
27 | if (letter == ':')
28 | return false;
29 | for (char letter : tokens[j])
30 | if (letter == '\"')
31 | return false;
32 | for (char letter : tokens[j])
33 | if (letter == '(')
34 | return false;
35 | for (char letter : tokens[j])
36 | if (letter == ')')
37 | return false;
38 | if (is_number(tokens[j]))
39 | return false;
40 | if (tokens[j] == "+")
41 | return false;
42 | if (tokens[j] == "-")
43 | return false;
44 | if (tokens[j] == "*")
45 | return false;
46 | if (tokens[j] == "/")
47 | return false;
48 | if (tokens[j] == "%")
49 | return false;
50 | }
51 | else if (model_tokens[i] == "$num-var") // $num-var is NUMBER variable
52 | {
53 | if (!is_num_var(tokens[j], state))
54 | return false;
55 | }
56 | else if (model_tokens[i] == "$str-var") // $str-var is TEXT variable
57 | {
58 | if (!is_txt_var(tokens[j], state))
59 | return false;
60 | }
61 | // $var is either a NUMBER variable or a TEXT variable
62 | else if (model_tokens[i] == "$var")
63 | {
64 | if (!is_scalar_variable(tokens[j], state))
65 | return false;
66 | }
67 | else if (model_tokens[i] == "$anyVar") // $anyVar is any variable
68 | {
69 | if (!variable_exists(tokens[j], state))
70 | return false;
71 | }
72 | else if (model_tokens[i] == "$scalar-map")
73 | { // $scalar-map is TEXT MAP, NUMBER MAP
74 | if (!is_scalar_map(tokens[j], state))
75 | return false;
76 | }
77 | else if (model_tokens[i] == "$num-vec") // $num-vec is NUMBER vector
78 | {
79 | if (!is_num_map(tokens[j], state))
80 | return false;
81 | }
82 | else if (model_tokens[i] == "$str-vec") // $str-vec is TEXT vector
83 | {
84 | if (!is_txt_map(tokens[j], state))
85 | return false;
86 | }
87 | else if (model_tokens[i] == "$list")
88 | { // $list is a LIST
89 | if (variable_type(tokens[j], state).back() != 3)
90 | return false;
91 | }
92 | else if (model_tokens[i] == "$map")
93 | { // $map is a MAP
94 | if (variable_type(tokens[j], state).back() != 4)
95 | return false;
96 | }
97 | else if (model_tokens[i] == "$scalar-list")
98 | { // $scalar-list is a LIST of scalar values
99 | if (!is_scalar_list(tokens[j], state))
100 | return false;
101 | }
102 | else if (model_tokens[i] == "$num-list") // $num-vec is NUMBER list
103 | {
104 | if (!is_num_list(tokens[j], state))
105 | return false;
106 | }
107 | else if (model_tokens[i] == "$str-list") // $str-vec is TEXT list
108 | {
109 | if (!is_txt_list(tokens[j], state))
110 | return false;
111 | }
112 | else if (model_tokens[i] == "$list-list") // $str-vec is a LIST of LISTs
113 | {
114 | if (!is_list_list(tokens[j], state))
115 | return false;
116 | }
117 | else if (model_tokens[i] == "$map-list") // $str-vec is LIST of MAPs
118 | {
119 | if (!is_map_list(tokens[j], state))
120 | return false;
121 | }
122 | else if (model_tokens[i] == "$collection") // $collection is either a MAP or a LIST
123 | {
124 | // if(!is_scalar_map(tokens[j], state) && !is_scalar_list(tokens[j],
125 | // state) && (variable_type(tokens[j], state).size() < 2)) return false;
126 | if (variable_type(tokens[j], state).size() < 2)
127 | return false;
128 | }
129 | else if (model_tokens[i] == "$literal") // $literal is either a NUMBER or a TEXT
130 | {
131 | if (!is_string(tokens[j]) && !is_number(tokens[j]))
132 | return false;
133 | }
134 | else if (model_tokens[i] == "$string") // $string is a TEXT literal
135 | {
136 | if (!is_string(tokens[j]))
137 | return false;
138 | }
139 | else if (model_tokens[i] == "$number") // $number is a NUMBER literal
140 | {
141 | if (!is_number(tokens[j]))
142 | return false;
143 | }
144 | else if (model_tokens[i] == "$expression") // $expression is NUMBER,
145 | // TEXT, TEXT-VAR, NUMBER-VAR
146 | {
147 | if (!is_expression(tokens[j], state))
148 | return false;
149 | }
150 | else if (model_tokens[i] == "$str-expr") // $str-expr is either a TEXT or a TEXT variable
151 | {
152 | if (!is_txt_expr(tokens[j], state))
153 | return false;
154 | }
155 | else if (model_tokens[i] == "$num-expr") // $num-expr is either a NUMBER
156 | // or a NUMBER variable
157 | {
158 | if (!is_num_expr(tokens[j], state))
159 | return false;
160 | }
161 | else if (model_tokens[i].find("$var-type-") == 0) // variable with a given type number
162 | {
163 | vector actual_type = variable_type(tokens[j], state);
164 | string expected_type = model_tokens[i].substr(10);
165 | if (actual_type.size() != expected_type.length())
166 | return false;
167 | for (size_t t = 0; t < actual_type.size(); ++t)
168 | {
169 | if ((int)actual_type[t] != expected_type[t] - '0')
170 | return false;
171 | }
172 | }
173 | else if (model_tokens[i] == "$natural") // $natural is an integer greater than 0
174 | {
175 | if (!is_natural(tokens[j]))
176 | return false;
177 | }
178 | else if (model_tokens[i] == "$display") // multiple NUMBER, TEXT, TEXT-VAR, NUMBER-VAR
179 | {
180 | for (; j < tokens.size(); ++j)
181 | {
182 | if (!is_expression(tokens[j], state))
183 | return false;
184 | }
185 | }
186 | else if (model_tokens[i] == "$subprocedure") // $subprocedure is a SUB-PROCEDURE
187 | {
188 | if (!is_subprocedure(tokens[j], state))
189 | return false;
190 | }
191 | else if (model_tokens[i] == "$external") // $external is a C++ function defined elsewhere
192 | {
193 | return !is_subprocedure(tokens[j], state) &&
194 | !is_expression(tokens[j], state);
195 | }
196 | else if (model_tokens[i] == "$label") // $label is a GOTO label
197 | {
198 | return is_label(tokens[j]);
199 | }
200 | else if (model_tokens[i] == "$math") // $math is a math expression
201 | {
202 | vector maths; // further tokenize math expressions
203 | string math_token = "";
204 | for (; j < tokens.size(); ++j)
205 | {
206 | for (unsigned int z = 0; z < tokens[j].size(); ++z)
207 | {
208 | if (tokens[j][z] == '(' || tokens[j][z] == ')')
209 | {
210 | if (!math_token.empty())
211 | maths.push_back(math_token);
212 | math_token = tokens[j][z];
213 | maths.push_back(math_token);
214 | math_token = "";
215 | }
216 | else
217 | {
218 | math_token += tokens[j][z];
219 | }
220 | }
221 | if (!math_token.empty())
222 | maths.push_back(math_token);
223 | math_token = "";
224 | }
225 | // replace LDPL line tokens with new math tokens
226 | tokens.erase(tokens.begin() + i, tokens.end());
227 | tokens.insert(tokens.end(), maths.begin(), maths.end());
228 |
229 | // validate the new tokens
230 | for (unsigned int z = i; z < tokens.size(); ++z)
231 | {
232 | if (!is_math_symbol(tokens[z]) && !is_expression(tokens[z], state))
233 | return false;
234 | }
235 | return true;
236 | }
237 | else if (model_tokens[i] == "$condition") // $condition is a IF/WHILE condition
238 | {
239 | // Skip to the last token (THEN/DO),
240 | // the condition is validated in get_c_condition
241 | j = tokens.size() - 1;
242 | continue;
243 | }
244 | else if (model_tokens[i] == "$anything")
245 | return true;
246 | else if (model_tokens[i] != tokens[j])
247 | return false;
248 | ++j;
249 | }
250 | if (j < tokens.size())
251 | return false;
252 | return true;
253 | }
--------------------------------------------------------------------------------
/src/aux/aux_state.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions that check the current compilation
2 | * state */
3 |
4 | #include "../ldpl.h"
5 |
6 | bool is_num_map(string &token, compiler_state &state)
7 | {
8 | // -- Returns if the variable is a NUMBER MAP or an access to a multicontainer
9 | // that results in a NUMBER MAP --
10 | vector type = variable_type(token, state);
11 | if (type.size() == 2 && type[0] == 1 && type[1] == 4)
12 | return true;
13 | return false;
14 | }
15 |
16 | bool is_txt_map(string &token, compiler_state &state)
17 | {
18 | // -- Returns if the variable is a TEXT MAP or an access to a multicontainer
19 | // that results in a TEXT MAP --
20 | vector type = variable_type(token, state);
21 | if (type.size() == 2 && type[0] == 2 && type[1] == 4)
22 | return true;
23 | return false;
24 | }
25 |
26 | bool is_num_list(string &token, compiler_state &state)
27 | {
28 | // -- Returns if the variable is a NUMBER LIST or an access to a
29 | // multicontainer that results in a NUMBER LIST --
30 | vector type = variable_type(token, state);
31 | if (type.size() == 2 && type[0] == 1 && type[1] == 3)
32 | return true;
33 | return false;
34 | }
35 |
36 | bool is_txt_list(string &token, compiler_state &state)
37 | {
38 | // -- Returns if the variable is a TEXT MAP or an access to a multicontainer
39 | // that results in a TEXT MAP --
40 | vector type = variable_type(token, state);
41 | if (type.size() == 2 && type[0] == 2 && type[1] == 3)
42 | return true;
43 | return false;
44 | }
45 |
46 | bool is_list_list(string &token, compiler_state &state)
47 | {
48 | // -- Returns if the variable is a NUMBER/TEXT LIST LIST multicontainer or a
49 | // multicontainer access that results in a LIST of LISTs --
50 | vector type = variable_type(token, state);
51 | if (type.size() >= 2 && type[type.size() - 2] == 3 && type.back() == 3)
52 | return true;
53 | return false;
54 | }
55 |
56 | bool is_map_list(string &token, compiler_state &state)
57 | {
58 | // -- Returns if the variable is a multicontainer NUMBER/TEXT LIST MAP or a
59 | // multicontainer access that results in a LIST of MAPs --
60 | vector type = variable_type(token, state);
61 | if (type.size() >= 2 && type[type.size() - 2] == 4 && type.back() == 3)
62 | return true;
63 | return false;
64 | }
65 |
66 | bool is_scalar_map(string &token, compiler_state &state)
67 | {
68 | // -- Returns if the variable is a NUMBER MAP or an access to a multicontainer
69 | // that results in a NUMBER MAP --
70 | // -- or if the variable is a TEXT MAP or an access to a multicontainer that
71 | // results in a TEXT MAP --
72 | return is_num_map(token, state) || is_txt_map(token, state);
73 | }
74 |
75 | bool is_map_map(string &token, compiler_state &state)
76 | {
77 | // -- Returns if the variable is a NUMBER/TEXT MAP MAP multicontainer or a
78 | // multicontainer access that results in a MAP of MAPs --
79 | vector type = variable_type(token, state);
80 | if (type.size() >= 2 && type[type.size() - 2] == 4 && type.back() == 4)
81 | return true;
82 | return false;
83 | }
84 |
85 | bool is_map(string &token, compiler_state &state)
86 | {
87 | // -- Returns true if the variable is a MAP, regardless of a map of what
88 | // (multicontainer or not) --
89 | vector type = variable_type(token, state);
90 | return type.back() == 4;
91 | }
92 |
93 | bool is_scalar_list(string &token, compiler_state &state)
94 | {
95 | // -- Returns if the variable is a NUMBER LIST or an access to a
96 | // multicontainer that results in a NUMBER LIST --
97 | // -- or if the variable is a TEXT LIST or an access to a multicontainer that
98 | // results in a TEXT LIST --
99 | return is_num_list(token, state) || is_txt_list(token, state);
100 | }
101 |
102 | bool is_num_var(string &token, compiler_state &state)
103 | {
104 | // -- Checks if token is a NUMBER variable (or an access to a container that
105 | // results in a NUMBER variable) --
106 | return (variable_type(token, state) == vector{1});
107 | }
108 |
109 | bool is_txt_var(string &token, compiler_state &state)
110 | {
111 | // -- Checks if token is a TEXT variable (or an access to a container that
112 | // results in a TEXT variable) --
113 | return (variable_type(token, state) == vector{2});
114 | }
115 |
116 | bool is_scalar_variable(string &token, compiler_state &state)
117 | {
118 | // -- Returns is an identifier is a valid scalar variable or an access that
119 | // results in one --
120 | return is_num_var(token, state) || is_txt_var(token, state);
121 | }
122 |
123 | bool is_num_expr(string &token, compiler_state &state)
124 | {
125 | // -- Returns is an identifier is a valid scalar variable or number or an
126 | // access that results in one --
127 | return is_num_var(token, state) || is_number(token);
128 | }
129 |
130 | bool is_txt_expr(string &token, compiler_state &state)
131 | {
132 | // -- Returns is an identifier is a valid scalar variable or text or an access
133 | // that results in one --
134 | return is_txt_var(token, state) || is_string(token);
135 | }
136 |
137 | bool is_expression(string &token, compiler_state &state)
138 | {
139 | // -- Returns is an identifier is a valid scalar variable or text or number or
140 | // an access that results in one --
141 | return is_num_expr(token, state) || is_txt_expr(token, state);
142 | }
143 |
144 | bool is_external(string &token, compiler_state &state)
145 | {
146 | // -- Returns if an identifier maps to an external variable --
147 | return state.externals[token];
148 | }
149 |
150 | bool variable_exists(string &token, compiler_state &state)
151 | {
152 | // -- Returns if a variable has been declared or not --
153 | // (Bear in mind that myList is a variable, myList:0 is not, that's an access
154 | // for all this function is concerned)
155 | return variable_type(token, state) != vector{0};
156 | }
157 |
158 | bool is_subprocedure(string &token, compiler_state &state)
159 | {
160 | // -- Returns if an identifier maps to a valid, existing sub-procedure --
161 | for (auto &subprocedure : state.subprocedures)
162 | if (subprocedure.first == token)
163 | return true;
164 | return false;
165 | }
166 |
167 | bool in_procedure_section(compiler_state &state)
168 | {
169 | // -- Returns if the compiler is currently compiling a procedure section or
170 | // not --
171 | if (state.section_state == 3)
172 | {
173 | // We're inside a SUB-PROCEDURE procedure with no sections
174 | state.section_state = 2;
175 | open_subprocedure_code(state);
176 | }
177 | return state.section_state == 2;
178 | }
179 |
180 | vector variable_type(string &token, compiler_state &state)
181 | {
182 | // -- Returns the LDPL internal representation of the type of a variable --
183 | //
184 | // Return the number of the type or {0} if the variable doesn't exist. This
185 | // function can take full variables (foo:0:"hi"). Returns all the types of the
186 | // variable. If foo is number map list {1, 4, 3} and we just pass it foo:0, it
187 | // will return {1, 4}, that is the type foo:0 has.
188 | //
189 | // Variables can have mixed types. For example, a LIST of MAPS of NUMBERS
190 | // called foo is a NUMBER when you access both containers (foo:0:"hi") a
191 | // NUMBER MAP when you access just the list (foo:0) or a NUMBER MAP LIST when
192 | // you access nothing (foo) So we first split the full variable with accesses
193 | // and everything into tokens by :
194 | vector tokens;
195 | string varName = "";
196 | tokenize(token, tokens, state.where, true, ':');
197 | // So, for example, foo:0:"hi" will be split into {foo, 0, "hi"}
198 | // We take the first element as the variable name
199 | varName = tokens[0];
200 | // Then we check if the variable exists. If it does, we store its types in a
201 | // variable.
202 | vector types;
203 | if (state.variables[state.current_subprocedure].count(varName) > 0)
204 | types = state.variables[state.current_subprocedure][varName];
205 | else if (state.variables[""].count(varName) > 0)
206 | types = state.variables[""][varName];
207 | // If the variable wasn't found, we return {0}
208 | else
209 | return {0};
210 | // If it was found, though, we want to get its current type.
211 | // If, in the example above, we had foo:0, then our current type would be {1,
212 | // 4} meaning, a NUMBER (1) MAP (4). But the type the variable has stored is
213 | // {1, 4, 3}, because it is a NUMBER MAP LIST (LIST is 3). We have to remove
214 | // all accessed elements from the type vector ({1, 4, 3} would turn into {1,
215 | // 4} because we accessed the list when we did :0). The number of elements to
216 | // pop from the vector is equal to the number of : found within the full
217 | // variable (foo:0). As we've already splitted the variable into tokens, the
218 | // number of elements to pop from the vector is equal to the number of tokens
219 | // we have minus one. If the container access should contain other container
220 | // accesses (for example foo:bar:0), the thing changes, and we must make sure
221 | // to discard those indexes that access the other containers and not the one
222 | // we are trying to get the types of.
223 | size_t tokensToSkip = 0;
224 | for (size_t i = 1; i < tokens.size(); ++i)
225 | {
226 | // If the current token is a scalar literal, we can skip it safely.
227 | if (is_number(tokens[i]) || is_string(tokens[i]))
228 | {
229 | if (tokensToSkip > 0)
230 | tokensToSkip--;
231 | }
232 | // If it's not, then it must be a variable name.
233 | else
234 | {
235 | // If the variable doesn't exist in the current context, we rise an error.
236 | if (state.variables[state.current_subprocedure].count(tokens[i]) == 0 &&
237 | state.variables[""].count(tokens[i]) == 0)
238 | error("The variable " + tokens[i] + " used in " + token +
239 | " doesn't exist.");
240 | vector cvar_types = variable_type(tokens[i], state);
241 | if (cvar_types.size() > 1)
242 | // If the variable exists and is a container, then we skip as many
243 | // tokens as that variable takes.
244 | tokensToSkip += cvar_types.size() - 1;
245 | else
246 | // If the variable exists and is a scalar, we can skip it
247 | if (tokensToSkip > 0)
248 | tokensToSkip--;
249 | }
250 | if (tokensToSkip == 0)
251 | types.pop_back();
252 | }
253 | // We return {0} if there is an incomplete container access
254 | // that must be complete to resolve as a scalar index
255 | if (tokensToSkip > 0)
256 | return {0};
257 | // Now we have the types and can return them.
258 | return types;
259 | }
--------------------------------------------------------------------------------
/src/aux/aux_tokenizer.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains functions used to tokenize an LDPL source file */
2 |
3 | // +---------------------------------------------+
4 | // | TODO: comment and format this file properly |
5 | // +---------------------------------------------+
6 |
7 | // Tokenizes a line splitting by 'splitChar' with optional convertion of tokens
8 | // to uppercase (except in strings)
9 | void tokenize(string &line, vector &tokens, code_location &where,
10 | bool uppercase, char splitChar) {
11 | bool in_string = false;
12 | string current_token = "";
13 | // For each letter in the line
14 | for (unsigned int i = 0; i < line.size(); ++i) {
15 | char letter = line[i];
16 | if (letter == splitChar) {
17 | if (in_string)
18 | current_token += letter;
19 | else {
20 | if (current_token.size() > 0) tokens.push_back(current_token);
21 | current_token = "";
22 | }
23 | } else if (letter == '"') {
24 | in_string = !in_string;
25 | current_token += letter;
26 | } else if (letter == '\\' && in_string) {
27 | if (i < line.size() - 1) {
28 | char next_letter = line[++i];
29 | switch (next_letter) {
30 | case '\\':
31 | case '"':
32 | case '0':
33 | case 'a':
34 | case 'b':
35 | case 't':
36 | case 'n':
37 | case 'v':
38 | case 'f':
39 | case 'r':
40 | case 'e':
41 | current_token += "\\" + string(1, next_letter);
42 | break;
43 | default:
44 | badcode("unknown escape sequence", where);
45 | }
46 | } else
47 | badcode("\\ found alone on a string", where);
48 | } else if (letter == '#') // Comment character
49 | {
50 | if (in_string)
51 | current_token += letter;
52 | else {
53 | if (current_token.size() > 0) tokens.push_back(current_token);
54 | return;
55 | }
56 | } else {
57 | current_token += (uppercase && !in_string) ? toupper(letter) : letter;
58 | }
59 | if (i == line.size() - 1 && letter != splitChar) {
60 | if (in_string) badcode("Unterminated string", where);
61 | if (current_token.size() > 0) tokens.push_back(current_token);
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/aux/aux_typecheck.cpp:
--------------------------------------------------------------------------------
1 | /* This file contains auxiliary functions to check data type compliance */
2 | #include "../ldpl.h"
3 |
4 | bool is_number(string &number)
5 | {
6 | // -- Checks if a string is a valid real number --
7 | unsigned int firstchar = 0;
8 | if (number[0] == '-')
9 | firstchar = 1;
10 | if (number[firstchar] == '.')
11 | return false; // .12 is not a valid decimal in LDPL, 0.12 is.
12 | if (number[firstchar] == '+')
13 | return false; // +5 is not a valid decimal in LDPL, 5 is.
14 | istringstream iss(number);
15 | double f;
16 | iss >> f;
17 | bool isNumber = iss.eof() && !iss.fail();
18 | // If it is a number, it might be an octal literal (e.g. 025, 067, 003 etc)
19 | // so we proceed to fix the original number to make it decimal.
20 | if (isNumber)
21 | {
22 | string f_number = "";
23 | unsigned int i;
24 | for (i = 1; i < number.length(); ++i)
25 | {
26 | if (number[i - 1] != '0')
27 | {
28 | // If prev char not 0
29 | if (number[i - 1] == '-')
30 | // if prev char is -, continue check
31 | f_number += '-';
32 | else
33 | // if prev char is number, break
34 | break;
35 | }
36 | else if (number[i] == '.')
37 | // If prev number is 0
38 | f_number += '0';
39 | }
40 | f_number += number.substr(i - 1);
41 | number = f_number;
42 | return true;
43 | }
44 | else
45 | return false;
46 | }
47 |
48 | bool is_natural(string number)
49 | {
50 | // -- Checks if a string is a valid natural number --
51 | if (!is_number(number))
52 | return false;
53 | if (stod(number) <= 0)
54 | return false;
55 | for (char l : number)
56 | if (l == '.')
57 | return false;
58 | return true;
59 | }
60 |
61 | bool is_label(string &token)
62 | {
63 | // -- Checks if a string is a valid label --
64 | for (char letter : token)
65 | if (letter == '\"')
66 | return false;
67 | return true;
68 | }
69 |
70 | bool is_math_symbol(string &token)
71 | {
72 | // -- Checks if a string is a valid math symbol --
73 | string syms = "+-*/()%";
74 | return token.size() == 1 && syms.find(token[0]) != string::npos;
75 | }
76 |
77 | bool is_string(string &token)
78 | {
79 | // -- Checks if a string is a valid LDPL string --
80 | if (token.size() < 2 || token[0] != '"' || token[token.size() - 1] != '"')
81 | return false;
82 | // Check for unescaped quotes
83 | for (unsigned int i = 1; i < token.size() - 1; ++i)
84 | {
85 | if (token[i] == '\"' && token[i - 1] != '\\')
86 | return false;
87 | }
88 | return true;
89 | }
--------------------------------------------------------------------------------
/src/data_types/code_location.h:
--------------------------------------------------------------------------------
1 | struct code_location {
2 | string current_file;
3 | int current_line;
4 | };
--------------------------------------------------------------------------------
/src/data_types/compiler_state.h:
--------------------------------------------------------------------------------
1 | // TODO: Change vectors to maps
2 | struct compiler_state {
3 | unsigned int section_state = 0;
4 | // 0 no section, 1 data or local, 2 procedure, 3 sub-procedure start, 4
5 | // parameters Code to output (plain C code)
6 | code_location where = {"", 0};
7 | vector variable_code;
8 | vector output_code;
9 | vector subroutine_code; // code outside main()
10 | // variables
11 | map>>
12 | variables; // map