├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── pull_request_template.md
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── assets
├── LogoLong.png
└── LogoSingle.png
├── examples
├── big_project
│ ├── main.mws
│ ├── menu.mws
│ └── node.mws
├── brainfuck.mws
├── calculator.mws
├── clock.mws
├── fizzbuzz.mws
├── stack.mws
├── tasks
│ ├── fib.mws
│ ├── find_word.mws
│ └── guessing_game.mws
└── truthmachine.mws
├── inc
├── commands.hpp
├── defs.hpp
├── errors.hpp
├── expressions.hpp
├── functions.hpp
├── global.hpp
├── list.hpp
├── meowscript.hpp
├── modules.hpp
├── objects.hpp
├── reader.hpp
├── runner.hpp
├── scopes.hpp
├── tools.hpp
└── variables.hpp
├── src
├── commands.cpp
├── expressions.cpp
├── functions.cpp
├── global.cpp
├── main.cpp
├── modules.cpp
├── objects.cpp
├── reader.cpp
├── runner.cpp
├── scopes.cpp
├── tools.cpp
└── variables.cpp
└── stdlib
├── filesystem.cpp
├── math.cpp
└── os.cpp
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Do '...'
16 | 2. Execute '...'
17 | 3. Run interpreter like '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. Windows/Linux]
28 | - Version [e.g. v1.0.0]
29 |
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Title
2 | Author: your username/the participans
3 | Date: current date
4 |
5 | ## What I added
6 | Write a short description of what you added.
7 | - Added a cute duck
8 | - Gave the rabbits some carrots
9 | - Removed the angry bears
10 | - ...
11 |
12 | ## Why I added it
13 | Write a short text why you added this.
14 |
15 | It always bothered me that ...
16 | I wanted to be able to do ...
17 |
18 | ## Why it couldn't be done with a module
19 | Write a short explanation why it could be better as a commit then a MeowScript module.
20 |
21 | It was not possible because ...
22 | There would be a problem because ...
23 |
24 | ## How I added it
25 | Short explanation of how you implemented the additions/deletions.
26 |
27 | ## Additional notes
28 | Do you want to add something?
29 |
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | TODOLIST.txt
2 | build
3 | bin
4 | .vscode
5 | meow-script
6 | stdlib/threading.cpp
7 | testing/
8 | examples/big_project
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.9)
2 | project(meow-script
3 | VERSION 1.3.0
4 | LANGUAGES CXX
5 | DESCRIPTION "An easy extendable scripting language"
6 | )
7 | set(CMAKE_CXX_STANDARD 17)
8 | set(BINARY meow-script)
9 | set(SOURCE
10 | src/commands.cpp
11 | src/expressions.cpp
12 | src/functions.cpp
13 | src/global.cpp
14 | src/main.cpp
15 | src/modules.cpp
16 | src/objects.cpp
17 | src/reader.cpp
18 | src/runner.cpp
19 | src/scopes.cpp
20 | src/tools.cpp
21 | src/variables.cpp
22 |
23 |
24 | stdlib/filesystem.cpp
25 | stdlib/math.cpp
26 | stdlib/os.cpp
27 | )
28 |
29 | add_executable(${BINARY} ${SOURCE})
30 | target_link_libraries(meow-script dl)
31 |
32 | # can be ignored if it errors
33 | if(UNIX)
34 | target_compile_options(${BINARY} PUBLIC -g -rdynamic -Wl,-E -fPIC -Wl,--export-dynamic)
35 | add_compile_options(-g -rdynamic -Wl,-E -fPIC -Wl,--export-dynamic)
36 | endif()
37 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Hey, very cool that you want to contribute something!
2 | Before you do add stuff you might want to read this article though.
3 |
4 | # How to contribute
5 | Before you start to do anything, you might add an issue or start a discussion about what you plan to add and talk about it with the maintainers.
6 | This way you don't work hard for something that later on doesn't get added.
7 | Please be also aware that your work might need some changes before it can be pushed. This is not criticism but we (I) want keep the MeowScript standards.
8 | Also Maybe consider making a **module** instead!
9 |
10 | Important: Never ever commit a pull request to the `main` branch! Only to the `developer/` branch where all the ongoing work is stored, so we can asure nothing breaks when we release a new update. Thanks for understanding!
11 |
12 | ## When to contribute and when to make a module
13 | Modules are for external things like making wrapers for libraries/frameworks or writing their own.
14 | There should be no need for a "better-meowscript" module, but for something like "curl-lib" or "algorihm-collection".
15 |
16 | A commit is done when something essential that can't be done with modules gets added. This might include natice commands, new types or concepts.
17 | To get permission to commit something is because of that also not that easy to get, we don't want to merge something broken that we have to fix afterwards.
18 |
19 | Modules are the users resposibility to function. But we have to assure that MeowScript keeps stable and save as well as portable.
20 |
21 | # What a contribution should look like
22 | First of all follow the instruction on the template.
23 | Please tell us exactly what you added, why you added it, how you added it (not that in detail but in general)
24 | and why it could not be done with a simple module.
25 |
26 | Be prepared to change stuff after a review, and keep in mind that we don't get paid for doing this, so we will take our time.
27 | It's also possible that we wont add your request at all, because of the reasons given above.
28 |
29 | We are flattered that you want to add something and we try to best to listen to your suggestions!
30 |
31 | Now you are ready, if you are confident that a pull request is the perfect match, go for it.
32 | If you realize a module would be better, follow our template and add your ideas just as easy as watering your flowers!
33 | We are looking forward to your additions to this community!!
34 |
35 | Cya,
36 | LabRicecat~
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 LabRicecat
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # !! MOVED TO CODEBERG.ORG !!
2 | **This is an old version, please visit the current version at [codeberg.org](https://codeberg.org/LabRicecat/meowscript)!**
3 |
4 | # MeowScript
5 |
6 | 
7 |
8 |
9 |
10 |
11 |
12 |
13 | A small interpreted, easy and extendable programming language.
14 |
15 | ## Requirements
16 | | | Compiler | Build tool | Recommended |
17 | |-------------|---------------------|----------------|-------------|
18 | | Linux | g++/clang++ | cmake | ----------- |
19 | | Windows* | mingw64-g++/clang++ | nmake & cmake | Msys2 |
20 | | MacOS* | ------------------- | -------------- | ----------- |
21 |
22 | \*: still not fully supported
23 |
24 | ## Installing
25 | Execute these commands in your shell to download and build MeowScript:
26 | ```sh
27 | git clone https://github.com/LabRicecat/MeowScript.git
28 | cd MeowScript
29 | mkdir build
30 | cd build
31 | cmake ..
32 | make
33 | ```
34 | Now you can run the interpreter:
35 | ```sh
36 | meow-script --help
37 | ```
38 |
39 | ## How to use
40 | **[Read the wiki here](https://github.com/SirWolfi/MeowScript/wiki)**
41 |
42 | ## Try it out
43 | You can try out MeowScript REPL by using the `--shell` option or make a `main.mws` and run it with
44 | ```sh
45 | meow-script main.mws
46 | ```
47 |
48 | ## Credits
49 | Cute cat on the PC by DALL-E 2.0
50 |
--------------------------------------------------------------------------------
/assets/LogoLong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LabRicecat/MeowScript/64f4fb60df64ecb40befb7eb0c5f407705ad02d8/assets/LogoLong.png
--------------------------------------------------------------------------------
/assets/LogoSingle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LabRicecat/MeowScript/64f4fb60df64ecb40befb7eb0c5f407705ad02d8/assets/LogoSingle.png
--------------------------------------------------------------------------------
/examples/big_project/main.mws:
--------------------------------------------------------------------------------
1 | import "menu"
2 |
3 | Menu menu("Cool menu!",["Opt1","Opt2","Opt3"])
4 |
5 | menu.request_option()
--------------------------------------------------------------------------------
/examples/big_project/menu.mws:
--------------------------------------------------------------------------------
1 | struct Menu {
2 | new options []
3 | new name ""
4 |
5 | gen_set options
6 | gen_get options
7 | gen_get name
8 |
9 | func Menu(name_s :: String, options_s :: List)->Void {
10 | set options options_s
11 | set name name_s
12 | }
13 |
14 | func screen_text()->String {
15 | new ret_str ""
16 | for i in {options.length()} {
17 | set ret_str (ret_str + {string((i+1))} + ". " + {string({options.at(i)})} + "\n")
18 | }
19 | return ret_str
20 | }
21 |
22 | func get_option(idx :: Number)->Any {
23 | return {options.at((idx-1))}
24 | }
25 |
26 | func get_input()->Number {
27 | new inp {input("> ")}
28 | new inp {number(inp)}
29 |
30 | if({typeof inp} == "Void") {
31 | print "Invalid input!"
32 | return 0
33 | }
34 |
35 | if(inp == 0 || inp > {options.length()}) {
36 | print "Invalid input!"
37 | return 0
38 | }
39 |
40 | return inp
41 | }
42 |
43 | func request_option()->Any {
44 | print ("---# " + name + " #---")
45 | print {screen_text()}
46 | new inp {get_input()}
47 | if(inp == 0) {
48 | return 0
49 | }
50 |
51 | return {get_option(inp)}
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/examples/big_project/node.mws:
--------------------------------------------------------------------------------
1 | new nodes {}
2 | new error_bit 0
3 |
4 | func node_count()->Number {
5 | return {nodes.length()}
6 | }
7 |
8 | func add_node(name :: String, value)->Void {
9 | if({nodes.has(name)}) {
10 | set error_bit 1
11 | }
12 | else {
13 | nodes.set(name,value)
14 | set error_bit 0
15 | }
16 | }
17 |
18 | func get_node()->Any {
19 | if({nodes.has(name)} == 0) {
20 | set error_bit 1
21 | return 0
22 | }
23 | return {nodes.get(name)}
24 | }
--------------------------------------------------------------------------------
/examples/brainfuck.mws:
--------------------------------------------------------------------------------
1 | using os
2 | using filesystem
3 |
4 | event public error(message :: String)
5 |
6 | listen error(message :: String) {
7 | print "An error occured:"
8 | print message
9 | os.exit(1)
10 | }
11 |
12 | func get_file()->String {
13 | new arg_list {os.args()}
14 | if({arg_list.length()} == 0) {
15 | occur error("No file given!")
16 | }
17 | new fname {arg_list.at(0)}
18 | if({filesystem.exists fname} == 0) {
19 | occur error("Given file does not exist!")
20 | }
21 | return fname
22 | }
23 |
24 | new data [0]
25 | new index 0
26 |
27 | func parse(content :: String)->Void {
28 | new c ""
29 |
30 | new i 0
31 | while(i < {content.length()}) {
32 | set c {content.at(i)}
33 | if(c == "+") {
34 | data.replace(index,({data.at(index)}+1))
35 | }
36 | elif(c == "-") {
37 | data.replace(index,({data.at(index)}-1))
38 | }
39 | elif(c == "<") {
40 | if(index == 0) {
41 | occur error("Index out of bounce!")
42 | }
43 | set index (index - 1)
44 | }
45 | elif(c == ">") {
46 | while((index+1) >= {data.length()}) {
47 | data.push_back(0)
48 | }
49 | set index (index + 1)
50 | }
51 | elif(c == ".") {
52 | print {data.at(index)}
53 | }
54 | elif(c == "]") {
55 | occur error("Unexcpected token: ]")
56 | }
57 | elif(c == "[") {
58 | new loop_content ""
59 | set i (i+1)
60 | while(i < {content.length()} && {content.at(i)} != "]") {
61 | set loop_content (loop_content + {content.at(i)})
62 | set i (i+1)
63 | }
64 | while({data.at(index)} != 0) {
65 | parse(loop_content)
66 | }
67 | }
68 | else {
69 | # ignore
70 | }
71 |
72 | set i (i+1)
73 | }
74 | }
75 |
76 | if({os.main_file()}) {
77 | new file {get_file()}
78 | parse({filesystem.read file})
79 | }
--------------------------------------------------------------------------------
/examples/calculator.mws:
--------------------------------------------------------------------------------
1 | using os
2 | using math
3 |
4 | event public error(message :: String)
5 |
6 | func error_check(a :: String, b :: String)->Void {
7 | if(a == "") {
8 | occur error("No left number was given!")
9 | }
10 | if(b == "") {
11 | occur error("No right number was given!")
12 | }
13 | if({typeof {number(a)}} == "Void") {
14 | occur error("Expected a number as left!")
15 | }
16 | if({typeof {number(b)}} == "Void") {
17 | occur error("Expected a number as right!")
18 | }
19 | }
20 |
21 | func calc(inp :: String)->Number {
22 | new num1_s ""
23 | new num2_s ""
24 | new op ""
25 |
26 | for i in inp {
27 | if(i == "+" || i == "-" || i == "/" || i == "*" || i == "^") {
28 | if(op != "") {
29 | occur error("Two operators found!")
30 | }
31 | set op i
32 | }
33 | elif(i == " ") {
34 | # nothing
35 | }
36 | elif(op == "") {
37 | set num1_s (num1_s + i)
38 | }
39 | else {
40 | set num2_s (num2_s + i)
41 | }
42 | }
43 | error_check(num1_s,num2_s)
44 | new num1 {number(num1_s)}
45 | new num2 {number(num2_s)}
46 |
47 | if(op == "+") {
48 | return (num1 + num2)
49 | }
50 | elif(op == "-") {
51 | return (num1 - num2)
52 | }
53 | elif(op == "*") {
54 | return (num1 * num2)
55 | }
56 | elif(op == "^") {
57 | return (num1 ^ num2)
58 | }
59 | elif(op == "/") {
60 | if(num2 == 0) {
61 | occur error("Can't devide by 0!")
62 | }
63 | return (num1 / num2)
64 | }
65 | return 0
66 | }
67 |
68 | listen error(message) {
69 | print "An error occured:"
70 | print message
71 | os.exit(0)
72 | }
73 |
74 | func main()->Void {
75 | new inp ""
76 | print "MeowScript calculator!"
77 | print "Type \"exit\" to quit!\n"
78 | while(1) {
79 | set inp {input(">")}
80 | if(inp == "exit") {
81 | break;
82 | }
83 | print ("< " + {string({calc(inp)})})
84 | }
85 | }
86 |
87 | if({os.main_file()}) {
88 | main()
89 | }
--------------------------------------------------------------------------------
/examples/clock.mws:
--------------------------------------------------------------------------------
1 | using os
2 | using math
3 |
4 | # distance from a to b
5 | func distance(a :: Number,b :: Number)->Number {
6 | return ({math.max(a,b)} - {math.min(a,b)})
7 | }
8 |
9 | # returns b if a is closer to b and c if a is closer to c
10 | func closer_to(a :: Number,b :: Number,c :: Number)->Number {
11 | if({distance(a,b)} < {distance(a,c)}) {
12 | return b
13 | }
14 | return c
15 | }
16 |
17 | # returns the closest direction for a given time
18 | func closest(a :: Number)->Number {
19 | if({closer_to(a,45,15)} == 15) {
20 | if({closer_to(a,0,30)} == 30) {
21 | return {closer_to(a,15,30)}
22 | }
23 | else {
24 | return {closer_to(a,0,15)}
25 | }
26 | }
27 | else {
28 | if({closer_to(a,0,30)} == 30) {
29 | return {closer_to(a,45,30)}
30 | }
31 | else {
32 | return {closer_to(a,0,45)}
33 | }
34 | }
35 | }
36 |
37 | func get_min_pos()->List {
38 | new L0 [
39 | ["","","","","","","","",""],
40 | ["","","","","|","","","",""],
41 | ["","","","","|","","","",""],
42 | ["","","","","","","","",""],
43 | ["","","","","","","","",""],
44 | ["","","","","","","","",""],
45 | ["","","","","","","","",""]
46 | ]
47 | new L15 [
48 | ["","","","","","","","",""],
49 | ["","","","","","","","",""],
50 | ["","","","","","","","",""],
51 | ["","","","","","-","-","-",""],
52 | ["","","","","","","","",""],
53 | ["","","","","","","","",""],
54 | ["","","","","","","","",""]
55 | ]
56 | new L30 [
57 | ["","","","","","","","",""],
58 | ["","","","","","","","",""],
59 | ["","","","","","","","",""],
60 | ["","","","","","","","",""],
61 | ["","","","","|","","","",""],
62 | ["","","","","|","","","",""],
63 | ["","","","","","","","",""]
64 | ]
65 | new L45 [
66 | ["","","","","","","","",""],
67 | ["","","","","","","","",""],
68 | ["","","","","","","","",""],
69 | ["","-","-","-","","","","",""],
70 | ["","","","","","","","",""],
71 | ["","","","","","","","",""],
72 | ["","","","","","","","",""]
73 | ]
74 |
75 | new clst {closest({os.time("minutes")})}
76 |
77 | if(clst == 0) {
78 | return L0
79 | }
80 | elif(clst == 15) {
81 | return L15
82 | }
83 | elif(clst == 30) {
84 | return L30
85 | }
86 | elif(clst == 45) {
87 | return L45
88 | }
89 | }
90 |
91 | func get_hour_pos()->List {
92 | new L0 [
93 | ["","","","","","","","",""],
94 | ["","","","","","","","",""],
95 | ["","","","","#","","","",""],
96 | ["","","","","","","","",""],
97 | ["","","","","","","","",""],
98 | ["","","","","","","","",""],
99 | ["","","","","","","","",""]
100 | ]
101 | new L15 [
102 | ["","","","","","","","",""],
103 | ["","","","","","","","",""],
104 | ["","","","","","","","",""],
105 | ["","","","","","#","#","",""],
106 | ["","","","","","","","",""],
107 | ["","","","","","","","",""],
108 | ["","","","","","","","",""]
109 | ]
110 | new L30 [
111 | ["","","","","","","","",""],
112 | ["","","","","","","","",""],
113 | ["","","","","","","","",""],
114 | ["","","","","","","","",""],
115 | ["","","","","#","","","",""],
116 | ["","","","","","","","",""],
117 | ["","","","","","","","",""]
118 | ]
119 | new L45 [
120 | ["","","","","","","","",""],
121 | ["","","","","","","","",""],
122 | ["","","","","","","","",""],
123 | ["","","#","#","","","","",""],
124 | ["","","","","","","","",""],
125 | ["","","","","","","","",""],
126 | ["","","","","","","","",""]
127 | ]
128 |
129 | new clst {closest({os.time("hours")})}
130 |
131 | if(clst == 0) {
132 | return L0
133 | }
134 | elif(clst == 15) {
135 | return L15
136 | }
137 | elif(clst == 30) {
138 | return L30
139 | }
140 | elif(clst == 45) {
141 | return L45
142 | }
143 | }
144 |
145 | func generate_buffer()->String {
146 | new buffer ">> CLOCK: <<\n"
147 |
148 | new min_pos {get_min_pos()}
149 | new hour_pos {get_hour_pos()}
150 |
151 | new time_numbers [
152 | ["","","","","0","","","",""],
153 | ["","","","","","","","",""],
154 | ["","","","","","","","",""],
155 | ["9","","","","@","","","","3"],
156 | ["","","","","","","","",""],
157 | ["","","","","","","","",""],
158 | ["","","","","6","","","",""]
159 | ]
160 |
161 | for y in {min_pos.length()} {
162 | new line_m {min_pos.at(y)}
163 | new line_h {hour_pos.at(y)}
164 | new line_t {time_numbers.at(y)}
165 | for x in {line_h.length()} {
166 | new add " "
167 | if({line_m.at(x)} != "") {
168 | set add {line_m.at(x)}
169 | }
170 | if({line_h.at(x)} != "") {
171 | set add {line_h.at(x)}
172 | }
173 | if({line_t.at(x)} != "") {
174 | set add {line_t.at(x)}
175 | }
176 |
177 | set buffer (buffer + add)
178 | }
179 | if(y+1 != {min_pos.length()}) {
180 | set buffer (buffer + "\n")
181 | }
182 | }
183 | return buffer
184 | }
185 |
186 | func schedule()->Void {
187 | while(1) {
188 | os.clear()
189 | print {generate_buffer()}
190 | os.sleep(3000)
191 | }
192 | }
193 |
194 | if({os.main_file()}) {
195 | schedule()
196 | }
--------------------------------------------------------------------------------
/examples/fizzbuzz.mws:
--------------------------------------------------------------------------------
1 | using os
2 |
3 | new amount {input("Please enter the range:")}
4 |
5 | if({typeof {number(amount)}} == "Void") {
6 | print "Please enter a valid number!"
7 | os.exit(0)
8 | }
9 | set amount {number(amount)}
10 |
11 | for i in amount {
12 | if(i % 3 == 0 && i % 2 == 0) {
13 | print "FizzBuzz"
14 | }
15 | elif(i % 2 == 0) {
16 | print "Fizz"
17 | }
18 | elif(i % 3 == 0) {
19 | print "Buzz"
20 | }
21 | else {
22 | print i
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/stack.mws:
--------------------------------------------------------------------------------
1 | struct Stack {
2 | new data []
3 | gen_get data
4 |
5 | func push(d)->Void {
6 | data.push_back(d)
7 | }
8 | func pop()->Void {
9 | data.pop_back()
10 | }
11 |
12 | func top()->Any {
13 | return {data.back()}
14 | }
15 |
16 | func size()->Number {
17 | return {data.length()}
18 | }
19 | }
20 |
21 | Stack stk()
22 |
23 | stk.push(11)
24 | stk.push("hihi")
25 | stk.push([1,2,3])
26 |
27 | while({stk.size()} != 0) {
28 | new top {stk.top()}
29 | stk.pop()
30 | print top
31 | }
--------------------------------------------------------------------------------
/examples/tasks/fib.mws:
--------------------------------------------------------------------------------
1 | func fib(a :: Number)->Number {
2 | if(a == 0 || a == 1) {
3 | return a
4 | }
5 | else {
6 | new f1 (a-1)
7 | new f2 (a-2)
8 | return ({fib(f1)} + {fib(f2)})
9 | }
10 | }
11 |
12 | func fib2(n :: Number)->Number {
13 | new a 1
14 | new b 0
15 |
16 | for i in n {
17 | set b (a+b)
18 | set a (b-a)
19 | }
20 | return b
21 | }
22 |
23 | # slower
24 | fib(0)
25 | fib(1)
26 | fib(6)
27 | fib(20)
28 |
29 | # faster
30 | fib2(0)
31 | fib2(1)
32 | fib2(6)
33 | fib2(20)
--------------------------------------------------------------------------------
/examples/tasks/find_word.mws:
--------------------------------------------------------------------------------
1 | using filesystem
2 | using os
3 |
4 | func matches(left :: String, right :: String, sensitivity)->Number {
5 | if(sensitivity == 0) {
6 | left.to_upper()
7 | right.to_upper()
8 | }
9 |
10 | return (left == right)
11 | }
12 |
13 | func find_words(file :: String, search :: String, sensitivity :: Number)->List {
14 | new tmp ""
15 | new line 1
16 | new found_l []
17 |
18 | new content {filesystem.read file}
19 | if(content == "") {
20 | print "The file is empty!"
21 | os.exit(0)
22 | }
23 |
24 | for i in content {
25 | if(i == "\n") {
26 | set tmp ""
27 | set line (line+1)
28 | }
29 | else {
30 | set tmp (tmp + i)
31 |
32 | if({tmp.length()} > {search.length()}) {
33 | tmp.pop_front();
34 | }
35 | if({matches(search,tmp,sensitivity)}) {
36 | found_l.push_back(line)
37 | }
38 | }
39 | }
40 |
41 | return found_l
42 | }
43 |
44 | func main()->Void {
45 | new file ""
46 | new search ""
47 | set sensitivity ""
48 |
49 | set file {input("The file to read: ")}
50 | if({filesystem.exists file} == 0) {
51 | print "No such file!"
52 | os.exit(0)
53 | }
54 | set search {input("The sequence to search for: ")}
55 | if(search == "") {
56 | print "Please enter a valid sequence!"
57 | os.exit(0)
58 | }
59 |
60 | set sensitivity {input("Do you want case sensitivity? [Y,n]:")}
61 | if(sensitivity == "" || sensitivity == "Y" || sensitivity == "y") {
62 | set sensitivity 1
63 | }
64 | else {
65 | set sensitivity 0
66 | }
67 |
68 | new found {find_words(file,search,sensitivity)}
69 |
70 | if({found.length()} == 0) {
71 | print "\nThe given sequence was not found in the file!"
72 | os.exit(0)
73 | }
74 | else {
75 | print "\nThe sequence was found in the lines:"
76 | print found
77 | }
78 | }
79 |
80 | main()
--------------------------------------------------------------------------------
/examples/tasks/guessing_game.mws:
--------------------------------------------------------------------------------
1 | using os
2 |
3 | new tries 10
4 | new solution {os.rand(100,1)}
5 | new answ 0
6 |
7 | print "Try to guess the number! You have 10 tries!"
8 | while (answ != solution && tries != 0) {
9 | set answ {input("Your guess:")}
10 | if({typeof {number(answ)}} == "Void") {
11 | set answ 0
12 | print "Please enter a valid number!"
13 | continue
14 | }
15 | set answ {number(answ)}
16 | if(answ < solution) {
17 | print ("It's bigger! (" + {string((tries-1))} + " tries left)")
18 | }
19 | if(answ > solution) {
20 | print ("It's smaller! (" + {string((tries-1))} + " tries left)")
21 | }
22 |
23 | set tries (tries-1)
24 | }
25 |
26 | # We ran out of tries
27 | if(answ != solution) {
28 | print "You ran out of tries :c"
29 | print ("The number was: " + {string(solution)})
30 | }
31 | else {
32 | print "Congrats!"
33 | }
--------------------------------------------------------------------------------
/examples/truthmachine.mws:
--------------------------------------------------------------------------------
1 | new inp {input(":")}
2 | while(inp == "1") {
3 | print "1"
4 | }
5 | print "0"
--------------------------------------------------------------------------------
/inc/commands.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_COMMANDS_HPP
2 | #define MEOWSCRIPT_IG_COMMANDS_HPP
3 |
4 | #include "defs.hpp"
5 | #include "errors.hpp"
6 | #include "reader.hpp"
7 |
8 | MEOWSCRIPT_HEADER_BEGIN
9 |
10 | #define MWS_MUST_BE_IN_STRUCT() {if(global::in_struct == 0) {throw errors::MWSMessageException{"Command only allowed in struct!",global::get_line()};}}
11 | #define MWS_MUST_NOT_BE_IN_STRUCT() {if(global::in_struct != 0) {throw errors::MWSMessageException{"Command not allowed in struct!",global::get_line()};}}
12 | #define MWS_CAN_BE_IN_STRUCT()
13 |
14 | struct CommandArgReqirement {
15 | std::vector carry;
16 |
17 | CommandArgReqirement operator|(CommandArgReqirement car) {
18 | CommandArgReqirement car_c = car;
19 | CommandArgReqirement this_c = *this;
20 | for(auto i : car_c.carry) {
21 | this_c.carry.push_back(i);
22 | }
23 | this_c.single = false;
24 | return this_c;
25 | }
26 | // Do not modify!
27 | bool single = true;
28 |
29 | void operator=(int i) {
30 | carry.clear();
31 | single = true;
32 | carry.push_back(i);
33 | }
34 | void operator=(General_type type) {
35 | carry.clear();
36 | single = true;
37 | carry.push_back(static_cast(type)+1);
38 | }
39 |
40 | bool operator==(CommandArgReqirement car) {
41 | if(!car.single || !single || car.carry.empty() || carry.empty()) {
42 | return false;
43 | }
44 | return carry[0] == car.carry[0];
45 | }
46 | bool operator!=(CommandArgReqirement car) {
47 | return !operator==(car);
48 | }
49 |
50 | CommandArgReqirement(int i) {
51 | operator=(i);
52 | }
53 | CommandArgReqirement(General_type i) {
54 | operator=(i);
55 | }
56 | CommandArgReqirement() {}
57 |
58 | bool has_carry(int in) const;
59 | bool matches(Token tk);
60 | bool matches(CommandArgReqirement car);
61 | //bool matches(General_type type);
62 | };
63 |
64 | inline CommandArgReqirement car_Any = 0;
65 | inline CommandArgReqirement car_Number = General_type::NUMBER;
66 | inline CommandArgReqirement car_String = General_type::STRING;
67 | inline CommandArgReqirement car_List = General_type::LIST;
68 | inline CommandArgReqirement car_Function = General_type::FUNCTION;
69 | inline CommandArgReqirement car_Command = General_type::COMMAND;
70 | inline CommandArgReqirement car_Compound = General_type::COMPOUND;
71 | inline CommandArgReqirement car_Name = General_type::NAME;
72 | inline CommandArgReqirement car_Expression = General_type::EXPRESSION;
73 | inline CommandArgReqirement car_ArgumentList = General_type::ARGUMENTLIST;
74 | inline CommandArgReqirement car_ParameterList = General_type::PARAMETERLIST;
75 | inline CommandArgReqirement car_Operator = General_type::OPERATOR;
76 | inline CommandArgReqirement car_Module = General_type::MODULE;
77 | inline CommandArgReqirement car_Event = General_type::EVENT;
78 | inline CommandArgReqirement car_Keyword = General_type::KEYWORD;
79 | inline CommandArgReqirement car_Dictionary = General_type::DICTIONARY;
80 | inline CommandArgReqirement car_Object = General_type::OBJECT;
81 | inline CommandArgReqirement car_Struct = General_type::STRUCT;
82 | inline CommandArgReqirement car_PlaceHolderAble = car_Expression | car_Compound | car_Name;
83 | inline CommandArgReqirement car_Ongoing = 200;
84 |
85 | struct GeneralTypeToken;
86 |
87 | struct Command {
88 | std::string name;
89 | std::vector args;
90 |
91 | GeneralTypeToken (*run)(std::vector args);
92 | };
93 |
94 | std::vector* get_command_list();
95 |
96 | bool is_command(std::string name);
97 | Command* get_command(std::string name);
98 |
99 | Command* get_command_overload(std::string name,std::vector tokens);
100 |
101 | MEOWSCRIPT_HEADER_END
102 |
103 | #endif
--------------------------------------------------------------------------------
/inc/defs.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_DEFS_HPP
2 | #define MEOWSCRIPT_IG_DEFS_HPP
3 |
4 | #define MEOWSCRIPT_VERSION_PATCH 3
5 | #define MEOWSCRIPT_VERSION_MINOR 3
6 | #define MEOWSCRIPT_VERSION_MAJOR 1
7 |
8 | #define MEOWSCRIPT_VERSION_STR std::to_string(MEOWSCRIPT_VERSION_MAJOR) + "." + std::to_string(MEOWSCRIPT_VERSION_MINOR) + "." + std::to_string(MEOWSCRIPT_VERSION_MINOR)
9 |
10 | #define MEOWSCRIPT_HEADER_BEGIN namespace MeowScript {
11 | #define MEOWSCRIPT_HEADER_END }
12 |
13 | #define MEOWSCRIPT_SOURCE_FILE using namespace MeowScript;
14 |
15 | #define MEOWSCRIPT_MODULE MEOWSCRIPT_SOURCE_FILE
16 |
17 | #ifdef __linux__
18 | # define MEOWSCRIPT_DIR_SL "/"
19 | # define MEOWSCRIPT_USE_LINUX
20 | # define MEOWSCRIPT_SHARED_OBJECT_EXT ".so"
21 | # define MEOWSCRIPT_OS_NAME "Linux"
22 | #elif defined(_WIN32) || defined(__MINGW32__) || defined(__MINGW64__)
23 | # define MEOWSCRIPT_DIR_SL "\\"
24 | # define MEOWSCRIPT_USE_WINDOWS
25 | # define MEOWSCRIPT_SHARED_OBJECT_EXT ".dll"
26 | # define MEOWSCRIPT_OS_NAME "Windows"
27 | #else
28 | # define MEOWSCRIPT_DIR_SL "/" // something like that?
29 | # define MEOWSCRIPT_USE_ELSE
30 | # define MEOWSCRIPT_SHARED_OBJECT_EXT ""
31 | # define MEOWSCRIPT_OS_NAME "Unknown"
32 | #endif
33 |
34 | #include
35 | namespace fs = std::filesystem;
36 |
37 | #endif
--------------------------------------------------------------------------------
/inc/errors.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_ERRORS_HPP
2 | #define MEOWSCRIPT_IG_ERRORS_HPP
3 |
4 | #include
5 | #include
6 | #include "defs.hpp"
7 |
8 | MEOWSCRIPT_HEADER_BEGIN
9 |
10 | namespace errors {
11 | class MWSException : std::exception {
12 | public:
13 | unsigned int line = 0;
14 | virtual const char* what() const throw() {
15 | return "MWSException";
16 | }
17 |
18 | MWSException() {}
19 | MWSException(unsigned int line) : line(line) {}
20 |
21 | virtual const int constexpr get_line() const {
22 | return line;
23 | }
24 | };
25 |
26 | class MWSMessageException : public MWSException {
27 | std::string message = "";
28 | public:
29 | using MWSException::MWSException;
30 | virtual const char* what() const throw() {
31 | return message.c_str();
32 | }
33 |
34 | MWSMessageException() {}
35 | MWSMessageException(std::string msg, unsigned int line) {message = msg; MWSException::line = line;}
36 | };
37 | }
38 |
39 | MEOWSCRIPT_HEADER_END
40 |
41 | #endif
--------------------------------------------------------------------------------
/inc/expressions.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_EXPRESSIONS_HPP
2 | #define MEOWSCRIPT_IG_EXPRESSIONS_HPP
3 |
4 | #include "defs.hpp"
5 | #include "variables.hpp"
6 | #include "scopes.hpp"
7 | #include "global.hpp"
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | MEOWSCRIPT_HEADER_BEGIN
15 |
16 | // RULE: all operators with the SAME name MUST have the SAME priority!
17 | // If not, the first priority is taken
18 | struct Operator {
19 | General_type req_left;
20 | General_type req_right;
21 | int priority = 0;
22 |
23 | Variable (*parse)(GeneralTypeToken left, GeneralTypeToken right);
24 | };
25 |
26 | bool is_operator(std::string name);
27 |
28 | Operator* get_operator(std::string name, General_type left, General_type right);
29 |
30 | Variable parse_expression(std::string s);
31 |
32 | bool is_expression(std::string s);
33 |
34 | inline std::unordered_map> operators = {
35 | {
36 | {"+", {
37 | {
38 | General_type::NUMBER, General_type::NUMBER, 1,
39 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
40 | Variable left_v = left.to_variable();
41 | Variable right_v = right.to_variable();
42 | return left_v.storage.number + right_v.storage.number;
43 | }
44 | },
45 | {
46 | General_type::STRING, General_type::STRING, 1,
47 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
48 | Variable left_v = left.to_variable();
49 | Variable right_v = right.to_variable();
50 | Variable ret;
51 | ret.set(left_v.storage.string.content + right_v.storage.string.content);
52 | return ret;
53 | }
54 | },
55 | }},
56 | {"-", {
57 | {
58 | General_type::NUMBER, General_type::NUMBER, 1,
59 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
60 | Variable left_v = left.to_variable();
61 | Variable right_v = right.to_variable();
62 | return left_v.storage.number - right_v.storage.number;
63 | }
64 | },
65 | }},
66 | {"*", {
67 | {
68 | General_type::NUMBER, General_type::NUMBER, 2,
69 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
70 | Variable left_v = left.to_variable();
71 | Variable right_v = right.to_variable();
72 | return left_v.storage.number * right_v.storage.number;
73 | }
74 | },
75 | }},
76 | {"/", {
77 | {
78 | General_type::NUMBER, General_type::NUMBER, 2,
79 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
80 | Variable left_v = left.to_variable();
81 | Variable right_v = right.to_variable();
82 | if(right_v.storage.number == 0) {
83 | throw errors::MWSMessageException{"Can't devide by 0!",global::get_line()};
84 | }
85 | return left_v.storage.number / right_v.storage.number;
86 | }
87 | },
88 | }},
89 | {"%", {
90 | {
91 | General_type::NUMBER, General_type::NUMBER, 2,
92 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
93 | Variable left_v = left.to_variable();
94 | Variable right_v = right.to_variable();
95 | if(right_v.storage.number == 0) {
96 | throw errors::MWSMessageException{"Can't devide by 0!",global::get_line()};
97 | }
98 | return int(left_v.storage.number) % int(right_v.storage.number);
99 | }
100 | },
101 | }},
102 | {"^", {
103 | {
104 | General_type::NUMBER, General_type::NUMBER, 3,
105 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
106 | Variable left_v = left.to_variable();
107 | Variable right_v = right.to_variable();
108 | return std::pow(left_v.storage.number,right_v.storage.number);
109 | }
110 | },
111 | }},
112 | {"==", {
113 | {
114 | General_type::NUMBER, General_type::NUMBER, 0,
115 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
116 | Variable left_v = left.to_variable();
117 | Variable right_v = right.to_variable();
118 | return left_v.storage.number == right_v.storage.number;
119 | }
120 | },
121 | {
122 | General_type::STRING, General_type::STRING, 0,
123 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
124 | Variable left_v = left.to_variable();
125 | Variable right_v = right.to_variable();
126 | return left_v.storage.string.content == right_v.storage.string.content;
127 | }
128 | },
129 | {
130 | General_type::OBJECT, General_type::OBJECT, 0,
131 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
132 | Variable left_v = left.to_variable();
133 | Variable right_v = right.to_variable();
134 | return struct_matches(&left_v.storage.obj,&right_v.storage.obj);
135 | }
136 | },
137 | }},
138 | {"!=", {
139 | {
140 | General_type::NUMBER, General_type::NUMBER, 0,
141 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
142 | Variable left_v = left.to_variable();
143 | Variable right_v = right.to_variable();
144 | return left_v.storage.number != right_v.storage.number;
145 | }
146 | },
147 | {
148 | General_type::STRING, General_type::STRING, 0,
149 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
150 | Variable left_v = left.to_variable();
151 | Variable right_v = right.to_variable();
152 | return left_v.storage.string.content != right_v.storage.string.content;
153 | }
154 | },
155 | {
156 | General_type::OBJECT, General_type::OBJECT, 0,
157 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
158 | Variable left_v = left.to_variable();
159 | Variable right_v = right.to_variable();
160 | return !struct_matches(&left_v.storage.obj,&right_v.storage.obj);
161 | }
162 | },
163 | }},
164 | {">", {
165 | {
166 | General_type::NUMBER, General_type::NUMBER, 0,
167 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
168 | Variable left_v = left.to_variable();
169 | Variable right_v = right.to_variable();
170 | return left_v.storage.number > right_v.storage.number;
171 | }
172 | },
173 | }},
174 | {"<", {
175 | {
176 | General_type::NUMBER, General_type::NUMBER, 0,
177 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
178 | Variable left_v = left.to_variable();
179 | Variable right_v = right.to_variable();
180 | return left_v.storage.number < right_v.storage.number;
181 | }
182 | },
183 | }},
184 | {"<=", {
185 | {
186 | General_type::NUMBER, General_type::NUMBER, 0,
187 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
188 | Variable left_v = left.to_variable();
189 | Variable right_v = right.to_variable();
190 | return left_v.storage.number <= right_v.storage.number;
191 | }
192 | },
193 | }},
194 | {">=", {
195 | {
196 | General_type::NUMBER, General_type::NUMBER, 0,
197 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
198 | Variable left_v = left.to_variable();
199 | Variable right_v = right.to_variable();
200 | return left_v.storage.number >= right_v.storage.number;
201 | }
202 | },
203 | }},
204 | {"&&", {
205 | {
206 | General_type::NUMBER, General_type::NUMBER, -1,
207 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
208 | Variable left_v = left.to_variable();
209 | Variable right_v = right.to_variable();
210 | return left_v.storage.number==1 && right_v.storage.number==1;
211 | }
212 | },
213 | }},
214 | {"||", {
215 | {
216 | General_type::NUMBER, General_type::NUMBER, -1,
217 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
218 | Variable left_v = left.to_variable();
219 | Variable right_v = right.to_variable();
220 | return left_v.storage.number==1 || right_v.storage.number==1;
221 | }
222 | },
223 | }},
224 | {"^^", { // xor
225 | {
226 | General_type::NUMBER, General_type::NUMBER, -1,
227 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
228 | Variable left_v = left.to_variable();
229 | Variable right_v = right.to_variable();
230 | return left_v.storage.number==1 ^ right_v.storage.number==1;
231 | }
232 | },
233 | }},
234 |
235 | {"=", { // assign
236 | {
237 | General_type::NAME, General_type::UNKNOWN, -999,
238 | [](GeneralTypeToken left, GeneralTypeToken right)->Variable {
239 | if(!is_variable(left.source)) {
240 | throw errors::MWSMessageException{"Can't assign to not existing variable!",global::get_line()};
241 | }
242 | Variable s;
243 | GeneralTypeToken gtt;
244 | bool rethrow = false;
245 | try {
246 | switch(right.type) {
247 | case General_type::NAME:
248 | s = tools::check4var(right).to_variable();
249 | break;
250 | case General_type::COMPOUND:
251 | try {
252 | gtt = tools::check4compound(right);
253 | }
254 | catch(errors::MWSMessageException& err) {
255 | rethrow = true;
256 | throw err;
257 | }
258 | s = gtt.to_variable();
259 | break;
260 | case General_type::EXPRESSION:
261 | s = tools::check4expression(right).to_variable();
262 | break;
263 | default:
264 | s = right.to_variable();
265 | }
266 | }
267 | catch(errors::MWSMessageException& err) {
268 | if(rethrow) {
269 | throw err;
270 | }
271 | throw errors::MWSMessageException{"Invalid assign to variable! Only VariableType's allowed, but got: " + general_t2token(right.type).content,global::get_line()};
272 | }
273 | set_variable(left.source,s);
274 | Variable ret;
275 | ret.type = Variable::Type::VOID;
276 | return ret;
277 | }
278 | },
279 | }},
280 | }
281 | };
282 |
283 | MEOWSCRIPT_HEADER_END
284 |
285 | #endif
--------------------------------------------------------------------------------
/inc/functions.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_FUNCTIONS_HPP
2 | #define MEOWSCRIPT_IG_FUNCTIONS_HPP
3 |
4 | #include "defs.hpp"
5 | #include "variables.hpp"
6 | #include "errors.hpp"
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | MEOWSCRIPT_HEADER_BEGIN
13 |
14 | struct Parameter {
15 | Variable::Type type = Variable::Type::ANY;
16 | std::string name;
17 | std::string struct_name;
18 |
19 | Parameter() {}
20 | Parameter(Variable::Type type) : type(type) {}
21 | Parameter(Variable::Type type, std::string name) : type(type), name(name) {}
22 | Parameter(Variable::Type type, std::string name, std::string struct_name) : type(type), name(name), struct_name(struct_name) {}
23 | void operator=(Variable::Type type) {
24 | this->type = type;
25 | }
26 |
27 | bool matches(Variable var) const;
28 | bool matches(Parameter param) const;
29 |
30 | void operator=(Parameter p) {
31 | this->type = p.type;
32 | this->name = p.name;
33 | this->struct_name = p.struct_name;
34 | }
35 | };
36 |
37 | bool paramlist_matches(std::vector params1,std::vector params2);
38 |
39 | class Function {
40 | public:
41 | using ReturnType = Parameter;
42 | std::vector body;
43 | std::vector params;
44 | unsigned int scope_idx = 0;
45 | ReturnType return_type = Variable::Type::UNKNOWN;
46 | fs::path file;
47 | // Takes care of the required amount of arguments and their types as well as the return value
48 | // Throws `MWSMessageException` on error
49 | Variable run(std::vector args, bool method_mode = false);
50 | };
51 |
52 | struct Event {
53 | std::vector listeners;
54 | std::string from_file;
55 | enum class Visibility {
56 | PUBLIC,
57 | PRIVATE,
58 | LISTEN_ONLY,
59 | OCCUR_ONLY
60 | }visibility = Visibility::PUBLIC;
61 |
62 | std::vector params;
63 | };
64 |
65 | namespace global {
66 | inline std::map events;
67 | }
68 |
69 | MEOWSCRIPT_HEADER_END
70 |
71 | #endif
--------------------------------------------------------------------------------
/inc/global.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_GLOBAL_HPP
2 | #define MEOWSCRIPT_IG_GLOBAL_HPP
3 |
4 | #include "defs.hpp"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | namespace fs = std::filesystem;
12 |
13 | MEOWSCRIPT_HEADER_BEGIN
14 |
15 | struct Variable;
16 |
17 | namespace global {
18 | inline std::stack include_path;
19 | inline int runner_should_return = 0;
20 | inline int runner_should_exit = 0;
21 | inline int in_compound = 0;
22 | inline int in_expression = 0;
23 | inline int in_argument_list = 0;
24 | inline int in_loop = 0;
25 | inline int break_loop = 0;
26 | inline int continue_loop = 0;
27 | inline std::stack line_count;
28 | inline std::vector imported_files;
29 | bool is_imported(fs::path file);
30 | unsigned int get_line();
31 |
32 | inline std::vector args;
33 |
34 | inline std::stack> call_trace;
35 | void add_trace(unsigned int line, std::string name,std::string file);
36 | bool pop_trace();
37 |
38 | inline std::string origin_file = "";
39 |
40 | fs::path include_parent_path();
41 |
42 | inline int in_struct = 0;
43 | }
44 |
45 |
46 | MEOWSCRIPT_HEADER_END
47 |
48 | #endif
--------------------------------------------------------------------------------
/inc/list.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_LIST_HPP
2 | #define MEOWSCRIPT_IG_LIST_HPP
3 |
4 | #include "defs.hpp"
5 | #include "reader.hpp"
6 |
7 | #include
8 | #include
9 |
10 | namespace MeowScript {
11 |
12 | struct Variable;
13 |
14 | struct List {
15 | std::vector elements;
16 |
17 | static inline bool valid_list(Token context) {
18 | if(context.content == "" || context.in_quotes || !brace_check(context,'[',']')) {
19 | return false;
20 | }
21 | context.content.erase(context.content.begin());
22 | context.content.erase(context.content.begin()+context.content.size()-1);
23 | if(context.content.size() == 0) {
24 | return true;
25 | }
26 |
27 | context.content = "(" + context.content + ")";
28 | return is_valid_argumentlist(context.content);
29 | }
30 |
31 | std::string to_string() const;
32 | };
33 |
34 | List construct_list(Token context);
35 |
36 | struct CommandArgReqirement;
37 | struct GeneralTypeToken;
38 |
39 | using MethodArgReqirement = CommandArgReqirement;
40 | template
41 | struct Method {
42 | std::string name;
43 | std::vector args;
44 |
45 | GeneralTypeToken (*run)(std::vector args, Self* self);
46 | };
47 |
48 | std::vector>* get_list_method_list();
49 | Method* get_list_method(std::string name);
50 | bool is_list_method(std::string name);
51 |
52 | std::vector>* get_string_method_list();
53 | Method* get_string_method(std::string name);
54 | bool is_string_method(std::string name);
55 |
56 | struct Dictionary;
57 |
58 | std::vector>* get_dictionary_method_list();
59 | Method* get_dictionary_method(std::string name);
60 | bool is_dictionary_method(std::string name);
61 |
62 |
63 | }
64 |
65 | #endif
--------------------------------------------------------------------------------
/inc/meowscript.hpp:
--------------------------------------------------------------------------------
1 | #include "defs.hpp"
2 | #include "errors.hpp"
3 | #include "commands.hpp"
4 | #include "functions.hpp"
5 | #include "modules.hpp"
6 | #include "global.hpp"
7 | #include "list.hpp"
8 | #include "variables.hpp"
9 | #include "runner.hpp"
10 | #include "scopes.hpp"
11 |
--------------------------------------------------------------------------------
/inc/modules.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_MODULES_HPP
2 | #define MEOWSCRIPT_IG_MODULES_HPP
3 |
4 | #include "defs.hpp"
5 | #include
6 | #include
7 | #include
8 |
9 | MEOWSCRIPT_HEADER_BEGIN
10 |
11 | struct Command;
12 | struct Variable;
13 |
14 | struct Module {
15 | std::string name;
16 | std::vector commands;
17 | std::map variables;
18 |
19 | Command* get_command(std::string name);
20 | bool has_command(std::string name);
21 | Variable* get_variable(std::string name);
22 | bool has_variable(std::string name);
23 | Module& add_command(Command command);
24 | Module& add_variable(std::string name, Variable var);
25 |
26 | Module() {}
27 | Module(std::string name) : name(name) {}
28 | Module(std::string name,std::vector commands) : name(name), commands(commands) {}
29 |
30 | bool enabled = true;
31 | };
32 |
33 | inline std::vector modules;
34 |
35 | Module* get_module(std::string name);
36 | bool is_loaded_module(std::string name);
37 |
38 | void add_module(Module module);
39 |
40 | std::vector* get_module_list();
41 |
42 | std::string get_username();
43 |
44 | void make_paths();
45 | bool check_paths();
46 |
47 | // Unloading via deconstructor of class!
48 | void load_all_modules();
49 |
50 | // returns false on error
51 | bool load_module(std::string name);
52 |
53 | bool is_loadable_module(std::string name);
54 |
55 | bool build_stdlib();
56 |
57 | MEOWSCRIPT_HEADER_END
58 |
59 | #endif
--------------------------------------------------------------------------------
/inc/objects.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_OBJECTS_HPP
2 | #define MEOWSCRIPT_IG_OBJECTS_HPP
3 |
4 | #include "defs.hpp"
5 | #include "reader.hpp"
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | MEOWSCRIPT_HEADER_BEGIN
12 |
13 | struct Variable;
14 | struct Function;
15 | struct GeneralTypeToken;
16 | struct Parameter;
17 |
18 | struct Object {
19 | int parent_scope = 0;
20 |
21 | std::map members;
22 | std::map> methods;
23 | std::map structs;
24 |
25 | std::vector>> on_deconstruct;
26 | };
27 |
28 | Function generate_get(Token name, Variable member);
29 | Function generate_set(Token name, Variable member);
30 | Object construct_object(GeneralTypeToken context);
31 |
32 | bool has_method(Object obj, Token name);
33 | bool has_member(Object obj, Token name);
34 | bool has_struct(Object obj, Token name);
35 |
36 | Function* get_method(Object* obj, Token name, std::vector params);
37 | Function* get_method(Object* obj, Token name, std::vector params);
38 | Variable* get_member(Object* obj, Token name);
39 | Object* get_struct(Object* obj, Token name);
40 |
41 | Variable run_method(Object* obj, Token name, std::vector args);
42 |
43 | // `obj2` might match `obj1` but not vice versa!
44 | // This is because we check if `obj2` has all requirements to be a
45 | // `obj1`
46 | bool struct_matches(Object* obj1, Object* obj2);
47 |
48 | bool sibling_method(std::string name);
49 |
50 | MEOWSCRIPT_HEADER_END
51 |
52 | #endif
--------------------------------------------------------------------------------
/inc/reader.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_READER_HPP
2 | #define MEOWSCRIPT_IG_READER_HPP
3 |
4 | #include "defs.hpp"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | MEOWSCRIPT_HEADER_BEGIN
13 |
14 | std::streamsize get_flength(std::ifstream& file);
15 |
16 | std::string read(std::string path);
17 |
18 | struct Token {
19 | bool in_quotes = false;
20 | std::string content;
21 | unsigned int line = 0;
22 |
23 | operator std::string() {
24 | return content;
25 | }
26 |
27 | Token(std::string str) {
28 | content = str;
29 | }
30 | Token(const char* cstr) {
31 | content = std::string(cstr);
32 | }
33 | Token() {}
34 |
35 | void operator=(std::string str) {
36 | in_quotes = false;
37 | content = str;
38 | }
39 |
40 | bool operator>(Token tk) {
41 | return
42 | tk.content.size() < content.size() ||
43 | !(tk.content.size() > content.size()) ||
44 | [=]()->bool{
45 | for(size_t i = 0; i < tk.content.size(); ++i) {
46 | if(tk.content[i] > content[i]) {
47 | return false;
48 | }
49 | }
50 | return true;
51 | }();
52 | }
53 |
54 | bool operator<(Token tk) {
55 | return !operator>(tk);
56 | }
57 |
58 | bool operator<=(Token tk) {
59 | return tk.content == content || operator<(tk);
60 | }
61 | bool operator>=(Token tk) {
62 | return tk.content == content || operator>(tk);
63 | }
64 |
65 | bool operator==(Token tk) {
66 | return content == tk.content && in_quotes == tk.in_quotes;
67 | }
68 | bool operator==(const Token tk) const {
69 | return content == tk.content && in_quotes == tk.in_quotes;
70 | }
71 | };
72 |
73 | struct Line {
74 | std::vector source;
75 | uint32_t line_count = 0;
76 | operator std::vector() {
77 | return source;
78 | }
79 |
80 | };
81 |
82 | bool is_newline(char c);
83 | bool is_open_brace(char c);
84 | bool is_closing_brace(char c);
85 | bool is_number(char c);
86 | bool is_capsuled_number(Token text);
87 | bool all_numbers(Token text, bool allow_dot = true);
88 | bool is_valid_general_t(Token text);
89 | bool is_valid_var_t(Token text);
90 | bool is_valid_operator_char(char ch);
91 | bool is_valid_operator_name(Token text);
92 | bool is_valid_name(Token text);
93 | bool is_known_keyword(Token text);
94 | bool is_valid_argumentlist(Token context);
95 | bool is_valid_parameterlist(Token context);
96 | bool is_brace_pair(char open,char close);
97 | bool is_event(std::string name);
98 | bool is_dictionary(Token context);
99 |
100 | using lexed_tokens = std::vector;
101 |
102 | lexed_tokens lex(std::string file);
103 | lexed_tokens lex_text(std::string source);
104 |
105 | bool brace_check(Token context, char open, char close);
106 |
107 | enum class General_type {
108 | NUMBER,
109 | STRING,
110 | LIST,
111 | FUNCTION,
112 | COMMAND,
113 | COMPOUND,
114 | NAME,
115 | EXPRESSION,
116 | ARGUMENTLIST,
117 | PARAMETERLIST,
118 | OPERATOR,
119 | MODULE,
120 | EVENT,
121 | KEYWORD,
122 | DICTIONARY,
123 | STRUCT,
124 | OBJECT,
125 | UNKNOWN,
126 | VOID,
127 | OUT_OF_RANGE
128 | };
129 |
130 | MEOWSCRIPT_HEADER_END
131 |
132 | #endif
--------------------------------------------------------------------------------
/inc/runner.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_RUNNER_HPP
2 | #define MEOWSCRIPT_IG_RUNNER_HPP
3 |
4 | #include "reader.hpp"
5 | #include "scopes.hpp"
6 | #include "commands.hpp"
7 | #include "variables.hpp"
8 | #include "commands.hpp"
9 | #include "global.hpp"
10 | #include "errors.hpp"
11 |
12 | #include
13 |
14 | MEOWSCRIPT_HEADER_BEGIN
15 |
16 | GeneralTypeToken run_file(std::string file, bool new_scope = true, bool save_scope = false, int load_idx = -1, std::map external_vars = {}, fs::path from = "", bool pass_return_down = false, bool same_scope = false);
17 | GeneralTypeToken run_text(std::string text, bool new_scope = true, bool save_scope = false, int load_idx = -1, std::map external_vars = {},fs::path from = "", bool pass_return_down = false, bool same_scope = false);
18 | GeneralTypeToken run_lexed(lexed_tokens lexed, bool new_scope = true, bool save_scope = false, int load_idx = -1, std::map external_vars = {},fs::path from = "", bool pass_return_down = false, bool same_scope = false);
19 |
20 |
21 | MEOWSCRIPT_HEADER_END
22 |
23 | #endif
--------------------------------------------------------------------------------
/inc/scopes.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_SCOPES_HPP
2 | #define MEOWSCRIPT_IG_SCOPES_HPP
3 |
4 | #include "defs.hpp"
5 | #include "reader.hpp"
6 | #include "variables.hpp"
7 | #include "functions.hpp"
8 | #include "objects.hpp"
9 |
10 | #include
11 | #include
12 |
13 | MEOWSCRIPT_HEADER_BEGIN
14 |
15 | struct Object;
16 |
17 | struct Scope {
18 | std::map vars;
19 | std::map> functions;
20 | std::map structs;
21 | int parent = -1;
22 | int index = -1;
23 | bool freed = false;
24 | bool last_if_result = true;
25 |
26 | unsigned int current_line = 1;
27 |
28 | std::stack current_obj;
29 | };
30 |
31 | inline std::vector scopes;
32 | inline std::stack scope_trace;
33 |
34 | Scope* current_scope();
35 |
36 | // parent = -1 => last
37 | // parent = -2 => none
38 | void new_scope(int parent = -1, std::map external_vars = {});
39 | void pop_scope(bool save = false);
40 |
41 | // The external_vars are NOT being deleted, but overriden if they already exist!
42 | // Actually just copies the data of the scope
43 | void load_scope(int idx, std::map external_vars = {}, bool hard_load = false);
44 |
45 | void call_obj_deconstruct(Object& obj);
46 |
47 | unsigned int get_new_scope();
48 |
49 | bool is_variable(std::string name);
50 | Variable* get_variable(std::string name);
51 | void set_variable(std::string name, Variable var);
52 | void new_variable(std::string name, Variable var);
53 |
54 | bool is_function(std::string name);
55 | bool is_object(std::string name);
56 | bool is_struct(std::string name);
57 |
58 | Object* get_struct(std::string name);
59 | Object* get_object(std::string name);
60 |
61 | bool func_param_match(Function fun,std::vector params);
62 | bool func_param_match(Function fun,std::vector params);
63 | Function* get_function(std::string name, std::vector params);
64 | Function* get_function(std::string name, std::vector params);
65 | // returns false if it fails
66 | // does not override existing functions in scope
67 |
68 | bool add_function(std::string name, Function fun);
69 | void add_object(std::string name, Object obj);
70 | bool add_struct(std::string name, Object struc);
71 |
72 | MEOWSCRIPT_HEADER_END
73 |
74 | #endif
--------------------------------------------------------------------------------
/inc/tools.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_TOOLS_HPP
2 | #define MEOWSCRIPT_IG_TOOLS_HPP
3 |
4 | #include "defs.hpp"
5 | #include "reader.hpp"
6 |
7 | #include
8 | #include
9 |
10 | MEOWSCRIPT_HEADER_BEGIN
11 |
12 | struct GeneralTypeToken;
13 |
14 | using argument_list = std::vector;
15 | namespace tools {
16 | argument_list parse_argument_list(GeneralTypeToken context);
17 | argument_list parse_argument_list(Token context);
18 |
19 | // Checks if token could be a variable name and if yes \
20 | // tries to convert this variable into a GeneralTypeToken and returns it.
21 | // If it fails, returns `token`
22 | GeneralTypeToken check4var(GeneralTypeToken token);
23 |
24 | // Checks if token is a runnable compound and tries to run it and return it's result.
25 | GeneralTypeToken check4compound(GeneralTypeToken token);
26 |
27 | // Runs check4compound and chack4var in that order
28 | GeneralTypeToken check4placeholder(GeneralTypeToken token);
29 |
30 | GeneralTypeToken check4expression(GeneralTypeToken token);
31 |
32 | Token remove_unneeded_chars(Token token);
33 |
34 | Token remove_uness_decs(Token num, bool to_int);
35 |
36 | Token until_newline(std::vector tks);
37 | }
38 |
39 | MEOWSCRIPT_HEADER_END
40 |
41 | #endif
--------------------------------------------------------------------------------
/inc/variables.hpp:
--------------------------------------------------------------------------------
1 | #ifndef MEOWSCRIPT_IG_VARIABLES_HPP
2 | #define MEOWSCRIPT_IG_VARIABLES_HPP
3 |
4 | #include "defs.hpp"
5 | #include "reader.hpp"
6 | #include "list.hpp"
7 | #include "commands.hpp"
8 | #include "tools.hpp"
9 | #include "objects.hpp"
10 |
11 | #include
12 |
13 | MEOWSCRIPT_HEADER_BEGIN
14 |
15 | General_type get_type(Token context, CommandArgReqirement expected = car_Any);
16 |
17 | struct GeneralTypeToken;
18 |
19 | struct Dictionary {
20 | private:
21 | std::vector i_keys;
22 | std::vector i_values;
23 | public:
24 | const std::vector> pairs() const;
25 | std::vector> pairs();
26 |
27 | const std::vector& keys() const;
28 | const std::vector& values() const;
29 | std::vector& keys();
30 | std::vector& values();
31 |
32 | bool has(const GeneralTypeToken gtt) const;
33 |
34 | GeneralTypeToken& operator[](GeneralTypeToken gtt);
35 | };
36 |
37 | Dictionary dic_from_token(Token tk);
38 | Token dic_to_token(Dictionary dic);
39 |
40 | struct Variable {
41 | private:
42 | struct stor_ {
43 | long double number = 0.0;
44 | Token string;
45 | List list;
46 | Dictionary dict;
47 | Object obj;
48 | };
49 | public:
50 | enum class Type {
51 | Number,
52 | String,
53 | List,
54 | Dictionary,
55 | Object,
56 | UNKNOWN, // Dont use
57 | ANY, // Also don't use
58 | VOID, // Guess what
59 | OUT_OF_RANGE,
60 | }type = Type::UNKNOWN;
61 |
62 | stor_ storage;
63 |
64 | Variable(List list) {type = Type::List; storage.list = list;}
65 | Variable(Token string) {type = Type::String; storage.string = string; storage.string.in_quotes = true;}
66 | Variable(long double number) {type = Type::Number; storage.number = number;}
67 | Variable(Dictionary dic) {type = Variable::Type::Dictionary, storage.dict = dic;}
68 | Variable(Object obj) {type = Variable::Type::Object, storage.obj = obj;}
69 | Variable(Type ty) : type(ty) {}
70 | Variable() {}
71 |
72 | std::string to_string() const;
73 |
74 | bool fixed_type = false;
75 | bool constant = false;
76 |
77 | // all `set` return false if they fail because of `fixed_type` or `constant`
78 | bool set(std::string str);
79 | bool set(List list);
80 | bool set(long double num);
81 | bool set(Variable var);
82 |
83 | bool operator==(Variable v) {
84 | return this->type == v.type && this->to_string() == v.to_string();
85 | }
86 | };
87 |
88 | bool matches(Variable::Type type1, General_type type2);
89 | bool matches(std::vector types, General_type gtype);
90 |
91 | General_type var_t2general_t(Variable::Type type);
92 |
93 | template
94 | struct mws_either {
95 | Tleft left;
96 | Tright right;
97 | bool ileft = true;
98 |
99 | mws_either(Tleft l) {operator=(l);}
100 | mws_either(Tright r) {operator=(r);}
101 |
102 | void operator=(Tleft l) {left = l; ileft = true;}
103 | void operator=(Tright r) {right = r; ileft = false;}
104 | };
105 |
106 | struct GeneralTypeToken {
107 | Token source;
108 | General_type type = General_type::VOID;
109 |
110 | GeneralTypeToken(Token context) {
111 | source = context;
112 | type = get_type(context);
113 | if(!source.in_quotes && type == General_type::STRING) {
114 | source.content.erase(source.content.begin());
115 | source.content.erase(source.content.begin()+source.content.size()-1);
116 | source = tools::remove_unneeded_chars(source);
117 | source.in_quotes = true;
118 | }
119 | }
120 | GeneralTypeToken(Variable var) {
121 | switch(var.type) {
122 | case Variable::Type::Number:
123 | source = std::to_string(var.storage.number);
124 | type = General_type::NUMBER;
125 | break;
126 | case Variable::Type::String:
127 | source = var.storage.string;
128 | type = General_type::STRING;
129 | break;
130 | case Variable::Type::List:
131 | source = var.storage.list.to_string();
132 | type = General_type::LIST;
133 | break;
134 | case Variable::Type::Dictionary:
135 | source = dic_to_token(var.storage.dict);
136 | type = General_type::DICTIONARY;
137 | break;
138 | case Variable::Type::Object:
139 | source = (std::string)"#OBJECT#";
140 | type = General_type::OBJECT;
141 | use_save_obj = true;
142 | saveobj = var.storage.obj;
143 | break;
144 | default:
145 | type = General_type::VOID;
146 | }
147 | }
148 | GeneralTypeToken(Token token, CommandArgReqirement cars) {
149 | type = get_type(token,cars);
150 | source = token;
151 | if(!source.in_quotes && type == General_type::STRING) {
152 | source.content.erase(source.content.begin());
153 | source.content.erase(source.content.begin()+source.content.size()-1);
154 | source = tools::remove_unneeded_chars(source);
155 | source.in_quotes = true;
156 | }
157 |
158 | }
159 | GeneralTypeToken() {}
160 |
161 | Variable to_variable() const;
162 | std::string to_string() const;
163 |
164 | // casts
165 | GeneralTypeToken(long double i) {
166 | source = std::to_string(i);
167 | source.in_quotes = false;
168 | type = General_type::NUMBER;
169 | }
170 | GeneralTypeToken(List list) {
171 | source = list.to_string();
172 | source.in_quotes = false;
173 | type = General_type::LIST;
174 | }
175 | GeneralTypeToken(const char* str) {
176 | source = std::string(str);
177 | source.in_quotes = true;
178 | type = General_type::STRING;
179 | }
180 | GeneralTypeToken(std::string str) {
181 | source = str;
182 | source.in_quotes = true;
183 | type = General_type::STRING;
184 | }
185 | GeneralTypeToken(Dictionary dict) {
186 | source = dic_to_token(dict);
187 | source.in_quotes = false;
188 | type = General_type::DICTIONARY;
189 | }
190 |
191 | bool operator==(GeneralTypeToken gtt) {
192 | /*if(gtt.type != General_type::OBJECT) {
193 | return gtt.type == type && gtt.source == source;
194 | }*/
195 | return gtt.type == type && gtt.source == source;
196 | }
197 | bool operator==(const GeneralTypeToken gtt) const {
198 | return gtt.type == type && gtt.source == source;
199 | }
200 | bool operator!=(GeneralTypeToken gtt) {
201 | return !operator==(gtt);
202 | }
203 | bool operator!=(const GeneralTypeToken gtt) const {
204 | return !operator==(gtt);
205 | }
206 |
207 | bool use_save_obj = false;
208 |
209 | Object saveobj;
210 | };
211 |
212 | struct Parameter;
213 | namespace tools {
214 | std::vector parse_function_params(Token context);
215 |
216 | inline std::map replaces = {
217 | {"pi",GeneralTypeToken(3.14159)},
218 | {"phi",GeneralTypeToken(1.61803)},
219 | {"e",GeneralTypeToken(2.71828)},
220 | {"true",GeneralTypeToken(1)},
221 | {"false",GeneralTypeToken("0",car_Number)}
222 | };
223 |
224 | GeneralTypeToken check4replace(GeneralTypeToken token);
225 | Token check4replace(Token token);
226 | }
227 |
228 | inline const GeneralTypeToken general_null = GeneralTypeToken{};
229 |
230 | // Conversion functions
231 | Variable::Type general_t2var_t(General_type type);
232 | Token general_t2token(General_type type);
233 | Token var_t2token(Variable::Type type);
234 | Variable::Type token2var_t(Token token);
235 |
236 | // constructs a variable based of the given context
237 | Variable make_variable(Token context, Variable::Type ty_ = Variable::Type::UNKNOWN);
238 |
239 | MEOWSCRIPT_HEADER_END
240 |
241 | #endif
--------------------------------------------------------------------------------
/src/expressions.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/expressions.hpp"
2 | #include "../inc/errors.hpp"
3 | #include "../inc/global.hpp"
4 | #include "../inc/tools.hpp"
5 |
6 | MEOWSCRIPT_SOURCE_FILE
7 |
8 | bool MeowScript::is_operator(std::string name) {
9 | return operators.count(name) != 0;
10 | }
11 |
12 | Operator* MeowScript::get_operator(std::string name, General_type left, General_type right) {
13 | if(!is_operator(name)) {
14 | return nullptr;
15 | }
16 | auto& ops = operators[name];
17 |
18 | for(auto& i : ops) {
19 | if((i.req_left == left || i.req_left == General_type::UNKNOWN) && (i.req_right == right || i.req_right == General_type::UNKNOWN)) {
20 | return &i;
21 | }
22 | }
23 | return nullptr;
24 | }
25 |
26 | Variable MeowScript::parse_expression(std::string str) {
27 | if(!brace_check(str,'(',')')) {
28 | return Variable();
29 | }
30 | str.erase(str.begin());
31 | str.erase(str.begin()+str.size()-1);
32 |
33 | auto lines = lex_text(str);
34 | std::vector vec;
35 | // To make it one line
36 | for(auto i : lines) {
37 | for(auto j : i.source) {
38 | vec.push_back(j);
39 | }
40 | }
41 |
42 | std::vector lexed;
43 | bool look_for_opers = false;
44 | std::string operator_carry;
45 | // Try to get the operators:
46 | for(size_t i = 0; i < vec.size(); ++i) {
47 | if(vec[i].in_quotes || vec[i].content.size() != 1 || !is_valid_operator_char(vec[i].content[0]) || lexed.size() == 0) {
48 | lexed.push_back(vec[i]);
49 | }
50 | else {
51 | // Is an operator and could be merged!
52 | if(lexed.back().content.size() > 0 && !lexed.back().in_quotes && is_valid_operator_char(lexed.back().content[0])) {
53 | lexed.back().content.push_back(vec[i].content[0]);
54 | }
55 | else {
56 | lexed.push_back(vec[i]);
57 | }
58 | }
59 | }
60 |
61 | if(lexed.size() == 1) {
62 | return tools::check4placeholder(lexed[0]).to_variable();
63 | }
64 |
65 | ++global::in_expression;
66 | std::stack ops;
67 | std::stack st;
68 | for(size_t i = 0; i < lexed.size(); ++i) {
69 | if(get_type(lexed[i],car_Expression) == General_type::EXPRESSION) {
70 | st.push(parse_expression(lexed[i]));
71 | }
72 | else if(!lexed[i].in_quotes && is_operator(lexed[i].content)) {
73 | if(st.empty()) {
74 | --global::in_expression;
75 | throw errors::MWSMessageException{"Invalid expression: " + str,global::get_line()};
76 | }
77 | auto op = operators[lexed[i].content];
78 | while(!ops.empty() && operators[ops.top()][0].priority >= op[0].priority) {
79 | GeneralTypeToken right = st.top(); st.pop();
80 | GeneralTypeToken left = st.top(); st.pop();
81 |
82 | Operator* roper;
83 | roper = get_operator(ops.top(),left.type,right.type);
84 | if(roper == nullptr) {
85 | GeneralTypeToken l2 = tools::check4placeholder(left);
86 | GeneralTypeToken r2 = tools::check4placeholder(right);
87 | roper = get_operator(ops.top(),l2.type,right.type);
88 | if(roper == nullptr) {
89 | roper = get_operator(ops.top(),left.type,r2.type);
90 | if(roper == nullptr) {
91 | roper = get_operator(ops.top(),l2.type,r2.type);
92 | right = r2;
93 | left = l2;
94 | }
95 | else {
96 | right = r2;
97 | }
98 | }
99 | else {
100 | left = l2;
101 | }
102 | }
103 | if(roper == nullptr) {
104 | --global::in_expression;
105 | throw errors::MWSMessageException{"No overload of operator \"" + ops.top() + "\" matches the types: " + general_t2token(left.type).content + " | " + general_t2token(right.type).content,global::get_line()};
106 | }
107 |
108 | st.push(roper->parse(left,right));
109 | ops.pop();
110 | }
111 | ops.push(lexed[i].content);
112 | }
113 | else {
114 | st.push(GeneralTypeToken(lexed[i]));
115 | }
116 | }
117 |
118 |
119 | while(!ops.empty()) {
120 | GeneralTypeToken right = st.top(); st.pop();
121 | GeneralTypeToken left = st.top(); st.pop();
122 |
123 | Operator* roper;
124 | roper = get_operator(ops.top(),left.type,right.type);
125 | if(roper == nullptr) {
126 | GeneralTypeToken l2 = tools::check4placeholder(left);
127 | GeneralTypeToken r2 = tools::check4placeholder(right);
128 | roper = get_operator(ops.top(),l2.type,right.type);
129 | if(roper == nullptr) {
130 | roper = get_operator(ops.top(),left.type,r2.type);
131 | if(roper == nullptr) {
132 | roper = get_operator(ops.top(),l2.type,r2.type);
133 | right = r2;
134 | left = l2;
135 | }
136 | else {
137 | right = r2;
138 | }
139 | }
140 | else {
141 | left = l2;
142 | }
143 | }
144 | if(roper == nullptr) {
145 | --global::in_expression;
146 | throw errors::MWSMessageException{"No overload of operator \"" + ops.top() + "\" matches the types: " + general_t2token(left.type).content + " | " + general_t2token(right.type).content,global::get_line()};
147 | }
148 |
149 | st.push(roper->parse(left,right));
150 | ops.pop();
151 | }
152 | --global::in_expression;
153 | if(st.size() != 1) {
154 | throw errors::MWSMessageException{"Invalid expression: " + str,global::get_line()};
155 | }
156 |
157 | if(st.top().type == General_type::VOID) {
158 | return Variable(Variable::Type::VOID);
159 | }
160 | return st.top().to_variable();
161 | }
162 |
163 | bool MeowScript::is_expression(std::string str) {
164 | if(!brace_check(str,'(',')')) {
165 | return false;
166 | }
167 | str.erase(str.begin());
168 | str.erase(str.begin()+str.size()-1);
169 |
170 | auto lines = lex_text(str);
171 | std::vector vec;
172 | // To make it one line
173 | for(auto i : lines) {
174 | for(auto j : i.source) {
175 | vec.push_back(j);
176 | }
177 | }
178 |
179 | std::vector lexed;
180 | bool look_for_opers = false;
181 | std::string operator_carry;
182 | // Try to get the operators:
183 | for(size_t i = 0; i < vec.size(); ++i) {
184 | if(vec[i].in_quotes || vec[i].content.size() != 1 || !is_valid_operator_char(vec[i].content[0]) || lexed.size() == 0) {
185 | lexed.push_back(vec[i]);
186 | }
187 | else {
188 | // Is an operator and could be merged!
189 | if(lexed.back().content.size() > 0 && !lexed.back().in_quotes && is_valid_operator_char(lexed.back().content[0])) {
190 | lexed.back().content.push_back(vec[i].content[0]);
191 | }
192 | else {
193 | lexed.push_back(vec[i]);
194 | }
195 | }
196 | }
197 |
198 | if(lexed.size() == 1) {
199 | return get_type(lexed[0]) != General_type::COMMAND;
200 | }
201 |
202 | std::stack ops;
203 | int st = 0;
204 | for(size_t i = 0; i < lexed.size(); ++i) {
205 | if(get_type(lexed[i]) == General_type::EXPRESSION) {
206 | ++st;
207 | }
208 | else if(!lexed[i].in_quotes && is_operator(lexed[i].content)) {
209 | if(st == 0) {
210 | return false;
211 | }
212 | auto op = operators[lexed[i].content];
213 | while(!ops.empty() && operators[ops.top()][0].priority >= op[0].priority) {
214 | --st;
215 | if(!is_operator(ops.top())) {
216 | return false;
217 | }
218 | ops.pop();
219 | }
220 | ops.push(lexed[i].content);
221 | }
222 | else {
223 | ++st;
224 | }
225 | }
226 |
227 |
228 | while(!ops.empty()) {
229 | --st;
230 | if(!is_operator(ops.top())) {
231 | return false;
232 | }
233 | ops.pop();
234 | }
235 | if(st != 1) {
236 | return false;
237 | }
238 |
239 | return true;
240 | }
--------------------------------------------------------------------------------
/src/functions.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/functions.hpp"
2 | #include "../inc/global.hpp"
3 | #include "../inc/runner.hpp"
4 | #include "../inc/objects.hpp"
5 |
6 | MEOWSCRIPT_SOURCE_FILE
7 |
8 | bool Parameter::matches(Variable var) const {
9 | return \
10 | type == Variable::Type::UNKNOWN ||
11 | type == Variable::Type::ANY ||
12 | (
13 | var.type == Variable::Type::Object &&
14 | struct_name == "" &&
15 | type == Variable::Type::Object
16 | ) ||
17 | (
18 | var.type == Variable::Type::Object &&
19 | type == Variable::Type::Object &&
20 | struct_matches(get_struct(struct_name),&var.storage.obj)
21 | ) ||
22 | (
23 | var.type != Variable::Type::Object &&
24 | var.type == type
25 | );
26 | }
27 | // TODO: fix potential recursion problem
28 | bool Parameter::matches(Parameter param) const {
29 | return \
30 | type == Variable::Type::UNKNOWN ||
31 | type == Variable::Type::ANY ||
32 | (
33 | param.type == Variable::Type::Object &&
34 | struct_name == "" &&
35 | type == Variable::Type::Object
36 | ) ||
37 | (
38 | param.type == Variable::Type::Object &&
39 | param.struct_name == "" &&
40 | type == Variable::Type::Object
41 | ) ||
42 | (
43 | param.type == Variable::Type::Object &&
44 | type == Variable::Type::Object &&
45 | struct_matches(get_struct(struct_name),get_struct(param.struct_name))
46 | ) ||
47 | (
48 | param.type != Variable::Type::Object &&
49 | param.type == type
50 | );
51 | }
52 |
53 | bool MeowScript::paramlist_matches(std::vector params1,std::vector params2) {
54 | for(size_t i = 0; i < params1.size(); ++i) {
55 | if(!params1[i].matches(params2[i])) {
56 | return false;
57 | }
58 | }
59 | return true;
60 | }
61 |
62 |
63 | Variable MeowScript::Function::run(std::vector args, bool method_mode) {
64 | if(args.size() != this->params.size()) {
65 | std::string err = "Too many/few arguemnts for function!\n\t- Expected: " + std::to_string(this->params.size()) + "\n\t- But got: " + std::to_string(args.size());
66 | throw errors::MWSMessageException{err,global::get_line()};
67 | }
68 |
69 | std::map arg_map;
70 | for(size_t i = 0; i < args.size(); ++i) {
71 | if(!this->params[i].matches(args[i])) {
72 | std::string err = "Invalid argument! (" + std::to_string(i) + ")\n\t- Expected: " + var_t2token(this->params[i].type).content + "\n\t- But got: " + var_t2token(args[i].type).content;
73 | throw errors::MWSMessageException{err,global::get_line()};
74 | }
75 |
76 | arg_map[params[i].name] = args[i];
77 | }
78 | int saved_istruct = global::in_struct;
79 | global::in_struct = 0;
80 | GeneralTypeToken gtt_ret;
81 | if(method_mode) {
82 | gtt_ret = run_lexed(body,false,false,-1,arg_map,this->file);
83 | }
84 | else {
85 | gtt_ret = run_lexed(body,false,true,scope_idx,arg_map,this->file);
86 | }
87 | global::in_struct = saved_istruct;
88 | if(gtt_ret.type != General_type::VOID && gtt_ret.type != General_type::UNKNOWN) {
89 | Variable var_ret;
90 | try {
91 | var_ret = gtt_ret.to_variable();
92 | }
93 | catch(errors::MWSMessageException& err) {
94 | std::string err_msg = "Invalid return type!\n\t- Expected: " + var_t2token(return_type.type).content + "\n\t- But got: " + general_t2token(gtt_ret.type).content;
95 | throw errors::MWSMessageException{err_msg,global::get_line()};
96 | }
97 | return var_ret;
98 | }
99 | else {
100 | return Variable();
101 | }
102 | }
--------------------------------------------------------------------------------
/src/global.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/global.hpp"
2 | #include "../inc/scopes.hpp"
3 |
4 | MEOWSCRIPT_SOURCE_FILE
5 |
6 | bool MeowScript::global::is_imported(fs::path file) {
7 | for(auto i : imported_files) {
8 | if(i == file.string()) {
9 | return true;
10 | }
11 | }
12 | return false;
13 | }
14 |
15 | unsigned int MeowScript::global::get_line() {
16 | if(current_scope()->index == 0) {
17 | return current_scope()->current_line;
18 | }
19 | unsigned int line = 0;
20 | int index = current_scope()->index;
21 | while(index > 0) {
22 | line += scopes[index].current_line;
23 | index = scopes[index].parent;
24 | }
25 | // line += scopes[index].current_line;
26 | return line;
27 | }
28 |
29 | void MeowScript::global::add_trace(unsigned int line, std::string name,std::string file) {
30 | call_trace.push(std::make_tuple(line,name,file));
31 | }
32 |
33 | bool MeowScript::global::pop_trace() {
34 | if(!call_trace.empty()) {
35 | call_trace.pop();
36 | return true;
37 | }
38 | return false;
39 | }
40 |
41 | fs::path MeowScript::global::include_parent_path() {
42 | if(include_path.top().has_parent_path()) {
43 | return include_path.top().parent_path().string() + std::string(MEOWSCRIPT_DIR_SL);
44 | }
45 | return "";
46 | }
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/runner.hpp"
2 | #include "../inc/tools.hpp"
3 | #include "../inc/expressions.hpp"
4 | #include "../inc/modules.hpp"
5 |
6 | void print_help() {
7 | std::cout << "## MeowScript ##\n"
8 | << "A dynamic and easy extendable programming language.\n\n"
9 | << "Usage: meow-script [options] [file]\n"
10 | << "Options are:\n"
11 | << " --help, -h \t: Prints this and exits\n"
12 | << " --version, -v \t: Prints the version and exits\n"
13 | << " --shell, -s \t: Opens the MeowScript shell\n\n"
14 | << "(c) LabRiceCat 2022\n"
15 | << "Github repo: https://github.com/LabRiceCat/MeowScript\n";
16 | }
17 |
18 | void error_message_pretty(MeowScript::errors::MWSMessageException& err) {
19 | std::cout << "\n--------\nError in line " << err.get_line() << ":\n" << err.what() << "\n";
20 | std::cout << "\nCall Trace (most recent first)\n";
21 |
22 | while(!MeowScript::global::call_trace.empty()) {
23 | auto [line_c,line_s,file] = MeowScript::global::call_trace.top();
24 | MeowScript::global::pop_trace();
25 |
26 | std::cout << "In " << file << ":" << line_c << "\n- " << line_s << "\n";
27 | }
28 | }
29 |
30 | // #define MEOWSCRIPT_DEBUG_MODE
31 |
32 | int main(int argc, char** argv) {
33 | if(argc == 1) {
34 | print_help();
35 | return 0;
36 | }
37 |
38 | std::string arg = std::string(argv[1]);
39 |
40 | std::vector args;
41 | for(size_t i = 2; i < argc; ++i) {
42 | args.push_back(std::string(argv[i]));
43 | }
44 |
45 | if(!MeowScript::check_paths()) {
46 | MeowScript::make_paths();
47 | }
48 |
49 | if(arg == "--help" || arg == "-h") {
50 | print_help();
51 | return 0;
52 | }
53 | #ifdef MEOWSCRIPT_DEBUG_MODE
54 | else if(arg == "--debug" || arg == "-d") {
55 | return 0;
56 | }
57 | #endif
58 | else if(arg == "--version" || arg == "-v") {
59 | std::cout << MEOWSCRIPT_VERSION_STR << "\n";
60 | return 0;
61 | }
62 | else if(arg == "--shell" || arg == "-s") {
63 | MeowScript::new_scope();
64 | std::string input;
65 | std::cout << ">>> MeowScript shell <<<\n"
66 | << "Type `:exit` to exit the shell.\n";
67 | while(true) {
68 | std::cout << "$> ";
69 | std::getline(std::cin,input);
70 | if(input == ":exit" || input == ":quit" || input == ":q" || input == ":e") {
71 | MeowScript::pop_scope();
72 | return 0;
73 | }
74 | try {
75 | MeowScript::run_text(input,false,false,-1,{},fs::current_path(),false,true);
76 | }
77 | catch(MeowScript::errors::MWSMessageException& err) {
78 | error_message_pretty(err);
79 | return 1;
80 | }
81 | }
82 |
83 | MeowScript::pop_scope();
84 | return 0;
85 | }
86 | else {
87 | if(!MeowScript::check_paths()) {
88 | MeowScript::make_paths();
89 | }
90 |
91 | if(!fs::exists(std::string(argv[1]))) {
92 | std::cout << "No such file: \"" + std::string(argv[1]) + "\"\n";
93 | return 1;
94 | }
95 | else if(fs::is_directory(std::string(argv[1]))) {
96 | std::cout << "Can't parse directory! (\"" + std::string(argv[1]) + "\")\n";
97 | return 1;
98 | }
99 | try {
100 | for(auto i : args) {
101 | MeowScript::Variable var;
102 | var.storage.string = i;
103 | var.storage.string.in_quotes = true;
104 | var.type = MeowScript::Variable::Type::String;
105 | MeowScript::global::args.push_back(var);
106 | }
107 | fs::path from = fs::path(std::string(argv[1]));
108 | MeowScript::global::origin_file = from.string();
109 | MeowScript::run_file(std::string(argv[1]),true,false,-1,{},from);
110 | }
111 | catch(MeowScript::errors::MWSMessageException& err) {
112 | error_message_pretty(err);
113 | return 1;
114 | }
115 | return 0;
116 | }
117 |
118 | return 1;
119 | }
--------------------------------------------------------------------------------
/src/modules.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/modules.hpp"
2 | #include "../inc/commands.hpp"
3 | #include "../inc/variables.hpp"
4 | #include "../inc/global.hpp"
5 |
6 | #include "../inc/meowscript.hpp"
7 |
8 | MEOWSCRIPT_SOURCE_FILE
9 |
10 | #include
11 | #include
12 |
13 | #ifdef MEOWSCRIPT_USE_LINUX
14 | #include
15 | #include
16 | #include
17 |
18 | std::string MeowScript::get_username() {
19 | uid_t uid = geteuid();
20 | struct passwd *pw = getpwuid(uid);
21 | if (pw)
22 | {
23 | return std::string(pw->pw_name);
24 | }
25 | return {};
26 | }
27 |
28 | #define MEOWSCRIPT_PATH ("/home/" + MeowScript::get_username() + "/.meowscript/")
29 | #define MEOWSCRIPT_CONFIG_PATH ("/home/" + MeowScript::get_username() + "/.meowscript/config.mwsconf")
30 | #define MEOWSCRIPT_MODULE_PATH ("/home/" + MeowScript::get_username() + "/.meowscript/lib/")
31 |
32 | void MeowScript::load_all_modules() {
33 | for(auto i : fs::recursive_directory_iterator(MEOWSCRIPT_MODULE_PATH)) {
34 | if(i.path().extension() == MEOWSCRIPT_SHARED_OBJECT_EXT) {
35 | std::string pth = i.path().string();
36 | void* handle = dlopen(pth.c_str(),RTLD_LAZY);
37 | if(handle == nullptr) {
38 | throw errors::MWSMessageException{dlerror(),0};
39 | }
40 | }
41 | }
42 | }
43 |
44 | static bool first_load = true;
45 |
46 | bool MeowScript::load_module(std::string name) {
47 | #ifndef MEOWSCRIPT_USE_LINUX
48 | dlopen(NULL,RTLD_NOW|RTLD_GLOBAL);
49 | #endif
50 | first_load = false;
51 | for(auto i : fs::recursive_directory_iterator(MEOWSCRIPT_MODULE_PATH)) {
52 | if(i.path().filename() == name && i.path().extension() == MEOWSCRIPT_SHARED_OBJECT_EXT) {
53 | std::string pth = i.path().string();
54 | void* handle = dlopen(pth.c_str(),RTLD_LAZY);
55 | if(handle == nullptr) {
56 | throw errors::MWSMessageException{dlerror(),0};
57 | }
58 | return true;
59 | }
60 | }
61 | return false;
62 | }
63 |
64 | #elif defined(MEOWSCRIPT_USE_WINDOWS)
65 | #include
66 | #include
67 |
68 | #define MEOWSCRIPT_PATH "C:\\ProgramData\\.meowscript\\"
69 | #define MEOWSCRIPT_CONFIG_PATH "C:\\ProgramData\\.meowscript\\config.mwsconf"
70 | #define MEOWSCRIPT_MODULE_PATH "C:\\ProgramData\\.meowscript\\lib\\"
71 |
72 | static std::string wstring2string(std::wstring wstr) {
73 | using convert_typeX = std::codecvt_utf8;
74 | std::wstring_convert converterX;
75 |
76 | return converterX.to_bytes(wstr);
77 | }
78 |
79 | std::string MeowScript::get_username() {
80 | char username[UNLEN+1];
81 | DWORD size = UNLEN +1;
82 | GetUserName(username,&size);
83 | std::string tmp(username,size-1);
84 |
85 | return tmp;
86 | }
87 |
88 | void MeowScript::load_all_modules() {
89 | for(auto i : fs::recursive_directory_iterator(MEOWSCRIPT_MODULE_PATH)) {
90 | if(i.path().extension() == ".dll") {
91 | // auto pth = string2wstring(i.path().string());
92 | auto h = LoadLibrary(i.path().string().c_str());
93 | if(h) {
94 | throw errors::MWSMessageException{"Error while loading module!",0};
95 | }
96 | }
97 | }
98 | }
99 |
100 | bool MeowScript::load_module(std::string name) {
101 | for(auto i : fs::recursive_directory_iterator(MEOWSCRIPT_MODULE_PATH)) {
102 | if(i.path().filename() == name) {
103 | //auto pth = string2wstring(i.path().string());
104 | auto h = LoadLibrary(i.path().string().c_str());
105 | if(h) {
106 | throw errors::MWSMessageException{"Error while loading module!",0};
107 | }
108 | return true;
109 | }
110 | }
111 | return false;
112 | }
113 |
114 | #else
115 |
116 | std::string MeowScript::get_username() {
117 | // meh...
118 | }
119 |
120 | #define MEOWSCRIPT_PATH ""
121 | #define MEOWSCRIPT_CONFIG_PATH ""
122 | #define MEOWSCRIPT_MODULE_PATH ""
123 |
124 | #endif
125 |
126 | Command* MeowScript::Module::get_command(std::string name) {
127 | for(auto& i : commands) {
128 | if(i.name == name) {
129 | return &i;
130 | }
131 | }
132 | return nullptr;
133 | }
134 |
135 | bool MeowScript::Module::has_command(std::string name) {
136 | return this->get_command(name) != nullptr;
137 | }
138 |
139 | Variable* MeowScript::Module::get_variable(std::string name) {
140 | if(has_variable(name)) {
141 | return &this->variables[name];
142 | }
143 | return nullptr;
144 | }
145 |
146 | bool MeowScript::Module::has_variable(std::string name) {
147 | return this->variables.count(name) != 0;
148 | }
149 |
150 | Module& MeowScript::Module::add_command(Command command) {
151 | commands.push_back(command);
152 | return *this;
153 | }
154 |
155 | Module& MeowScript::Module::add_variable(std::string name, Variable var) {
156 | variables[name] = var;
157 | return *this;
158 | }
159 |
160 | Module* MeowScript::get_module(std::string name) {
161 | for(auto& i : modules) {
162 | if(i.name == name) {
163 | return &i;
164 | }
165 | }
166 | return nullptr;
167 | }
168 |
169 | bool MeowScript::is_loaded_module(std::string name) {
170 | return get_module(name) != nullptr;
171 | }
172 |
173 | void MeowScript::add_module(Module module) {
174 | if(!is_loaded_module(module.name)) {
175 | modules.push_back(module);
176 | }
177 | else {
178 | throw errors::MWSMessageException{"Name conflict! Tried to add module \"" + module.name + "\" twice!",global::get_line()};
179 | }
180 | }
181 |
182 | std::vector* MeowScript::get_module_list() {
183 | return &modules;
184 | }
185 |
186 | bool MeowScript::is_loadable_module(std::string name) {
187 | for(auto i : fs::recursive_directory_iterator(MEOWSCRIPT_MODULE_PATH)) {
188 | if(i.path().extension() == MEOWSCRIPT_SHARED_OBJECT_EXT && i.path().filename() == name + MEOWSCRIPT_SHARED_OBJECT_EXT) {
189 | return true;
190 | }
191 | }
192 | return false;
193 | }
194 |
195 | void MeowScript::make_paths() {
196 | if(!fs::exists(MEOWSCRIPT_PATH)) {
197 | fs::create_directory(MEOWSCRIPT_PATH);
198 | }
199 | if(!fs::exists(MEOWSCRIPT_CONFIG_PATH)) {
200 | std::ofstream of(MEOWSCRIPT_CONFIG_PATH, std::ios::app);
201 | of.close();
202 | }
203 | if(!fs::exists(MEOWSCRIPT_MODULE_PATH)) {
204 | fs::create_directory(MEOWSCRIPT_MODULE_PATH);
205 | }
206 | }
207 |
208 | bool MeowScript::check_paths() {
209 | if(!fs::exists(MEOWSCRIPT_PATH)) {
210 | return false;
211 | }
212 | if(!fs::exists(MEOWSCRIPT_CONFIG_PATH)) {
213 | return false;
214 | }
215 | if(!fs::exists(MEOWSCRIPT_MODULE_PATH)) {
216 | return false;
217 | }
218 | return true;
219 | }
220 |
221 | bool MeowScript::build_stdlib() {
222 | if(!fs::exists(".." MEOWSCRIPT_DIR_SL "stdlib")) {
223 | std::cout << "Could not find stdlib/ directory! Sure you run in installation folder?\n";
224 | return false;
225 | }
226 | if(!system(NULL)) {
227 | std::cout << "No shell avalable, try to execute meow-script somehow else!\n";
228 | }
229 | system("cd .. && cd stdlib && mkdir build && cd build && cmake ../ && make");
230 | for(auto i : fs::recursive_directory_iterator(".." MEOWSCRIPT_DIR_SL "stdlib" MEOWSCRIPT_DIR_SL "build")) {
231 | if(i.path().extension() == MEOWSCRIPT_SHARED_OBJECT_EXT) {
232 | std::string name = i.path().filename().string();
233 | name.erase(name.begin(),name.begin()+3); // remove the `lib`
234 |
235 | if(fs::exists(std::string(MEOWSCRIPT_MODULE_PATH) + name.c_str())) {
236 | fs::remove_all(std::string(MEOWSCRIPT_MODULE_PATH) + name.c_str());
237 | }
238 | fs::copy(i.path(),MEOWSCRIPT_MODULE_PATH + name);
239 | }
240 | }
241 | fs::remove_all(".." MEOWSCRIPT_DIR_SL "stdlib" MEOWSCRIPT_DIR_SL "build");
242 | return true;
243 | }
--------------------------------------------------------------------------------
/src/objects.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/objects.hpp"
2 | #include "../inc/scopes.hpp"
3 | #include "../inc/runner.hpp"
4 | #include "../inc/scopes.hpp"
5 | #include "../inc/variables.hpp"
6 | #include "../inc/functions.hpp"
7 |
8 | MEOWSCRIPT_SOURCE_FILE
9 |
10 | bool MeowScript::struct_matches(Object* obj1, Object* obj2) {
11 | if(obj1->members.size() > obj2->members.size() || obj1->methods.size() > obj2->methods.size() || obj1->structs.size() > obj2->structs.size()) {
12 | return false;
13 | }
14 | for(auto i : obj1->members) {
15 | Variable* vr_obj2 = get_member(obj2,i.first);
16 | if(vr_obj2 == nullptr || (i.second.fixed_type && vr_obj2->type != i.second.type)) {
17 | return false;
18 | }
19 | }
20 | for(auto i : obj1->methods) {
21 | for(auto j : i.second) {
22 | Function* fn_obj2 = get_method(obj2,i.first,j.params);
23 | if(fn_obj2 == nullptr || !j.return_type.matches(fn_obj2->return_type) || !paramlist_matches(j.params,fn_obj2->params)) {
24 | return false;
25 | }
26 | }
27 | }
28 | for(auto i : obj1->structs) {
29 | Object* st_obj2 = get_struct(obj2,i.first);
30 | if(st_obj2 == nullptr || !struct_matches(&i.second,st_obj2)) {
31 | return false;
32 | }
33 | }
34 | return true;
35 | }
36 |
37 | Function MeowScript::generate_get(Token name, Variable member) {
38 | Function func;
39 | func.body = lex_text("return " + name.content + "\n");
40 | if(member.fixed_type)
41 | func.return_type = member.type;
42 | else
43 | func.return_type = Variable::Type::ANY;
44 |
45 | return func;
46 | }
47 |
48 | Function MeowScript::generate_set(Token name, Variable member) {
49 | Function func;
50 | func.body = lex_text("set " + name.content + " " + name.content +"_set\n");
51 | if(member.fixed_type)
52 | func.params.push_back(Parameter(member.type,name.content +"_set"));
53 | else
54 | func.params.push_back(Parameter(Variable::Type::ANY,name.content +"_set"));
55 | func.return_type = Variable::Type::VOID;
56 | return func;
57 | }
58 |
59 | Object MeowScript::construct_object(GeneralTypeToken context) {
60 | if(context.type != General_type::COMPOUND) {
61 | return Object{};
62 | }
63 | context.source.content.erase(context.source.content.begin());
64 | context.source.content.erase(context.source.content.end()-1);
65 | Object retobj;
66 | new_scope(-1);
67 | ++global::in_struct;
68 | current_scope()->current_obj.push(retobj);
69 | run_text(context.source.content,false,true,-1,{},"",false,true);
70 | retobj = current_scope()->current_obj.top();
71 | current_scope()->current_obj.pop();
72 | --global::in_struct;
73 | retobj.members = current_scope()->vars;
74 | retobj.methods = current_scope()->functions;
75 | retobj.structs = current_scope()->structs;
76 | retobj.parent_scope = current_scope()->parent;
77 |
78 | scopes[current_scope()->index].freed = true;
79 | scopes[current_scope()->index].current_obj = {};
80 | scopes[current_scope()->index].functions = {};
81 | scopes[current_scope()->index].vars = {};
82 | scopes[current_scope()->index].structs = {};
83 |
84 | scope_trace.pop();
85 | return retobj;
86 | }
87 |
88 | bool MeowScript::has_method(Object obj, Token name) {
89 | return obj.methods.count(name.content) != 0;
90 | }
91 | bool MeowScript::has_member(Object obj, Token name) {
92 | return obj.members.count(name.content) != 0;
93 | }
94 | bool MeowScript::has_struct(Object obj, Token name) {
95 | return obj.structs.count(name.content) != 0;
96 | }
97 |
98 |
99 | Function* MeowScript::get_method(Object* obj, Token name, std::vector params) {
100 | if(!has_method(*obj,name)) {
101 | return nullptr;
102 | }
103 | for(auto& i : obj->methods[name]) {
104 | if(func_param_match(i,params)) {
105 | return &i;
106 | }
107 | }
108 | return nullptr;
109 | }
110 | Function* MeowScript::get_method(Object* obj, Token name, std::vector params) {
111 | if(!has_method(*obj,name)) {
112 | return nullptr;
113 | }
114 | for(auto& i : obj->methods[name]) {
115 | if(func_param_match(i,params)) {
116 | return &i;
117 | }
118 | }
119 | return nullptr;
120 | }
121 | Variable* MeowScript::get_member(Object* obj, Token name) {
122 | if(!has_member(*obj,name)) {
123 | return nullptr;
124 | }
125 | return &obj->members[name.content];
126 | }
127 | Object* MeowScript::get_struct(Object* obj, Token name) {
128 | if(!has_struct(*obj,name)) {
129 | return nullptr;
130 | }
131 | return &obj->structs[name.content];
132 | }
133 |
134 | Variable MeowScript::run_method(Object* obj, Token name, std::vector args) {
135 | Function* func = get_method(obj,name.content,args);
136 | if(func == nullptr) {
137 | return Variable();
138 | }
139 | new_scope(obj->parent_scope);
140 |
141 | current_scope()->vars = obj->members;
142 | current_scope()->functions = obj->methods;
143 | current_scope()->structs = obj->structs;
144 |
145 | current_scope()->current_obj.push(*obj);
146 |
147 | Variable ret = func->run(args,true);
148 |
149 | *obj = current_scope()->current_obj.top();
150 | current_scope()->current_obj.pop();
151 |
152 | obj->members = current_scope()->vars;
153 | obj->methods = current_scope()->functions;
154 | obj->structs = current_scope()->structs;
155 |
156 | pop_scope(false);
157 |
158 | return ret;
159 | }
160 |
161 | bool MeowScript::sibling_method(std::string name) {
162 | int index = current_scope()->index;
163 | while(index > 0) {
164 | if(!current_scope()->current_obj.empty() && has_method(current_scope()->current_obj.top(),name)) {
165 | return true;
166 | }
167 | index = scopes[index].parent;
168 | }
169 | return false;
170 | }
--------------------------------------------------------------------------------
/src/reader.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/reader.hpp"
2 | #include "../inc/expressions.hpp"
3 | #include "../inc/global.hpp"
4 |
5 | MEOWSCRIPT_SOURCE_FILE
6 |
7 | std::streamsize MeowScript::get_flength(std::ifstream& file) {
8 | if(!file.is_open()) {
9 | return 0;
10 | }
11 | std::streampos temp_1 = file.tellg();
12 | file.seekg(0, std::fstream::end);
13 | std::streampos temp_2 = file.tellg();
14 | file.seekg(temp_1, std::fstream::beg);
15 |
16 | return temp_2;
17 | }
18 |
19 | std::string MeowScript::read(std::string path) {
20 | std::ifstream ifile;
21 | ifile.open(path, std::ios::binary);
22 | std::streamsize len = get_flength(ifile);
23 | char* dummy = new char[len];
24 |
25 | try {
26 | ifile.read(dummy, len);
27 | }
28 | catch(std::exception& err) {
29 | ifile.close();
30 | delete dummy;
31 | return "";
32 | }
33 | if (dummy == nullptr || strlen(dummy) == 0) {
34 | ifile.close();
35 | delete dummy;
36 | return "";
37 | }
38 | ifile.close();
39 | //dummy += '\0';
40 | std::string re;
41 | re.assign(dummy, len);
42 |
43 | delete[] dummy;
44 | dummy = nullptr;
45 |
46 | return re;
47 | }
48 |
49 | std::vector MeowScript::lex(std::string file) {
50 | return lex_text(read(file));
51 | }
52 |
53 | bool MeowScript::is_newline(char c) {
54 | switch(c) {
55 | case '\n':
56 | #ifdef MEOWSCRIPT_WINDOWS
57 | case '\r\n':
58 | #endif
59 | case ';':
60 | return true;
61 | default:
62 | return false;
63 | }
64 | return false;
65 | }
66 |
67 | bool MeowScript::is_open_brace(char c) {
68 | switch(c) {
69 | case '(':
70 | case '[':
71 | case '{':
72 | return true;
73 | default:
74 | return false;
75 | }
76 | return false;
77 | }
78 | bool MeowScript::is_closing_brace(char c) {
79 | switch(c) {
80 | case ')':
81 | case ']':
82 | case '}':
83 | return true;
84 | default:
85 | return false;
86 | }
87 | return false;
88 | }
89 |
90 | bool MeowScript::is_number(char c) {
91 | return c <= '9' && c >= '0';
92 | }
93 |
94 | bool MeowScript::is_capsuled_number(Token text) {
95 | if(text.in_quotes) {
96 | return false;
97 | }
98 | if(!brace_check(text,'(',')')) {
99 | return false;
100 | }
101 | text.content.erase(text.content.begin());
102 | text.content.erase(text.content.begin()+text.content.size()-1);
103 |
104 | auto lines = lex_text(text);
105 | std::vector lexed;
106 | for(auto i : lines)
107 | for(auto j : i.source)
108 | lexed.push_back(j);
109 |
110 | if(lexed.size() == 0) {
111 | return false;
112 | }
113 | bool found_op = false;
114 | bool b = false;
115 | for(auto i : lexed) {
116 | if(get_type(i) == General_type::NUMBER) {
117 | b = true;
118 | }
119 | else if((i.content == "-" || i.content == "+") && b) {
120 | return false;
121 | }
122 | else if(i.content == "-" || i.content == "+") {
123 | found_op = true;
124 | }
125 | else {
126 | return false;
127 | }
128 | }
129 | if(global::in_expression == 0 && global::in_argument_list == 0 && !found_op) {
130 | return false;
131 | }
132 | return true;
133 | }
134 |
135 | bool MeowScript::all_numbers(Token context, bool allow_dot) {
136 | if(context.in_quotes) {
137 | return false;
138 | }
139 | if(context.content.size() != 0 && context.content[0] == '-') {
140 | context.content.erase(context.content.begin());
141 | }
142 | if(context.content.size() == 0) {
143 | return false;
144 | }
145 | bool dot = false;
146 | for(auto i : context.content) {
147 | if(i == '.') {
148 | if(dot || !allow_dot) {
149 | return false;
150 | }
151 | dot = true;
152 | }
153 | else if(i > '9' || i < '0') {
154 | return false;
155 | }
156 | }
157 | return true;
158 | }
159 |
160 | bool MeowScript::is_valid_var_t(Token context) {
161 | std::vector var_t_str = {
162 | "Number",
163 | "String",
164 | "List",
165 | "Dictionary",
166 | "Object",
167 | "Any",
168 | "Void",
169 | };
170 |
171 | for(auto i : var_t_str) {
172 | if(context.content == i) {
173 | return true;
174 | }
175 | }
176 | return false;
177 | }
178 |
179 | bool MeowScript::is_valid_general_t(Token context) {
180 | std::vector general_t_str = {
181 | "Number",
182 | "String",
183 | "List",
184 | "Function",
185 | "Command",
186 | "Compound",
187 | "Name",
188 | "Expression",
189 | "Argumentlist",
190 | "Parameterlist,"
191 | "Operator",
192 | "Module",
193 | "Event",
194 | "Keyword",
195 | "Dictionary",
196 | "Struct",
197 | "Object",
198 | "Unknown",
199 | "Void"
200 | };
201 | for(auto i : general_t_str) {
202 | if(context.content == i) {
203 | return true;
204 | }
205 | }
206 | return false;
207 | }
208 |
209 | bool MeowScript::is_valid_operator_char(char ch) {
210 | return
211 | ch == '+' ||
212 | ch == '-' ||
213 | ch == '~' ||
214 | ch == '=' ||
215 | ch == '<' ||
216 | ch == '>' ||
217 | ch == '^' ||
218 | ch == '!' ||
219 | ch == '?' ||
220 | ch == '*' ||
221 | ch == '/' ||
222 | ch == '%' ||
223 | ch == ':' ||
224 | ch == '.';
225 | }
226 |
227 | bool MeowScript::is_valid_operator_name(Token text) {
228 | for(auto i : text.content) {
229 | if(!is_valid_operator_char(i)) {
230 | return false;
231 | }
232 | }
233 | return true;
234 | }
235 |
236 | bool MeowScript::is_valid_name(Token context) {
237 | if(context.content == "" || context.in_quotes) {
238 | return false;
239 | }
240 | if(is_number(context.content.front())) {
241 | return false;
242 | }
243 | for(auto i : context.content) {
244 | if((i > 'z' || i < 'A' || (i > 'Z' && i < 'a')) && !is_number(i) && i != '_') {
245 | return false;
246 | }
247 | }
248 | return true;
249 | }
250 |
251 | bool MeowScript::is_known_keyword(Token text) {
252 | return (
253 | text.content == "public" ||
254 | text.content == "private" ||
255 | text.content == "listen_only" ||
256 | text.content == "occur_only"
257 | );
258 | }
259 |
260 | bool MeowScript::is_valid_argumentlist(Token context) {
261 | if(context.content == "" || context.in_quotes || !brace_check(context,'(',')')) {
262 | return false;
263 | }
264 | context.content.erase(context.content.begin());
265 | context.content.erase(context.content.begin()+context.content.size()-1);
266 | if(context.content.size() == 0) {
267 | return true;
268 | }
269 |
270 | auto lexed = lex_text(context);
271 | std::vector line;
272 | for(auto i : lexed)
273 | for(auto j : i.source)
274 | line.push_back(j);
275 |
276 | GeneralTypeToken last = general_null;
277 | bool found_sl = true;
278 |
279 | for(auto i : line) {
280 | if(i.content == ",") {
281 | if(last == general_null) {
282 | return false;
283 | }
284 | last = general_null;
285 | found_sl = true;
286 | }
287 | else if(found_sl) {
288 | last = i;
289 | found_sl = false;
290 | }
291 | else {
292 | return false;
293 | }
294 | }
295 | if(last != general_null && found_sl) {
296 | return false;
297 | }
298 |
299 | return true;
300 | }
301 |
302 | bool MeowScript::is_valid_parameterlist(Token context) {
303 | if(!brace_check(context,'(',')')) {
304 | return false;
305 | }
306 |
307 | context.content.erase(context.content.begin());
308 | context.content.erase(context.content.begin()+context.content.size()-1);
309 |
310 | auto lines = lex_text(context.content);
311 | if(lines.empty()) {
312 | return true;
313 | }
314 | std::vector ret;
315 | std::vector line;
316 | for(auto i : lines) {
317 | for(auto j : i.source) {
318 | line.push_back(j);
319 | }
320 | }
321 |
322 | std::vector nline;
323 | for(size_t i = 0; i < line.size(); ++i) {
324 | nline.push_back("");
325 | for(size_t j = 0; j < line[i].content.size(); ++j) {
326 | if(line[i].content[j] == ',') {
327 | nline.push_back(",");
328 | nline.push_back("");
329 | }
330 | else {
331 | nline.back().content += line[i].content[j];
332 | }
333 | }
334 | }
335 |
336 | std::vector> arguments;
337 | if(nline.size() != 0)
338 | arguments.push_back({});
339 | for(size_t i = 0; i < nline.size(); ++i) {
340 | if(nline[i].content == ",") {
341 | if(arguments.back().empty()) {
342 | return false;
343 | }
344 | arguments.push_back({});
345 | }
346 | else {
347 | arguments.back().push_back(nline[i]);
348 | }
349 | }
350 |
351 | for(auto i : arguments) {
352 | for(size_t j = 0; j < i.size(); ++j) {
353 | if(i[j].content == "" && !i[j].in_quotes) {
354 | i.erase(i.begin()+j);
355 | --j;
356 | }
357 | }
358 |
359 | if(i.size() == 1) {
360 | if(!is_valid_name(i[0]) /*|| is_variable(context) || is_struct(context) || is_function(context)*/) {
361 | return false;
362 | }
363 | }
364 | else if(i.size() == 3) {
365 | if(!is_valid_name(i[0]) /*|| is_variable(context) || is_struct(context) || is_function(context)*/) {
366 | return false;
367 | }
368 | if(i[1].content != "::" && i[1].content != ":") {
369 | return false;
370 | }
371 | }
372 | else {
373 | return false;
374 | }
375 | }
376 | return true;
377 | }
378 |
379 | bool MeowScript::is_brace_pair(char open,char close) {
380 | return (open=='('&&close==')') || (open=='['&&close==']') || (open=='{'&&close=='}');
381 | }
382 |
383 | bool MeowScript::is_dictionary(Token context) {
384 | if(context.in_quotes || context.content == "") {
385 | return false;
386 | }
387 | if(!brace_check(context,'{','}')) {
388 | return false;
389 | }
390 | context.content.erase(context.content.begin());
391 | context.content.erase(context.content.end()-1);
392 |
393 | auto lines = lex_text(context.content);
394 | std::vector lexed;
395 | for(auto i : lines)
396 | for(auto j : i.source)
397 | lexed.push_back(j);
398 |
399 | if(lexed.size() == 0) {
400 | return true;
401 | }
402 |
403 | GeneralTypeToken key;
404 | GeneralTypeToken value;
405 | bool got_equals = false;
406 |
407 | for(auto i : lexed) {
408 | if(!i.in_quotes && i.content == "=") {
409 | if(got_equals || key == general_null) {
410 | return false;
411 | }
412 | got_equals = true;
413 | }
414 | else if(key == general_null) {
415 | key = GeneralTypeToken(i);
416 | }
417 | else if(got_equals && value == general_null) {
418 | value = GeneralTypeToken(i);
419 | }
420 | else if(!i.in_quotes && (i.content == "," || i.content == ";")) {
421 | if(!got_equals || key == general_null || key.type == General_type::UNKNOWN || value == general_null || value.type == General_type::UNKNOWN) {
422 | return false;
423 | }
424 | got_equals = false;
425 | key = general_null;
426 | value = general_null;
427 | }
428 | else if(tools::remove_unneeded_chars(i.content).content != "") {
429 | return false;
430 | }
431 | }
432 | return !(!got_equals || key == general_null || key.type == General_type::UNKNOWN || value == general_null || value.type == General_type::UNKNOWN);
433 | }
434 |
435 | bool MeowScript::brace_check(Token context, char open, char close) {
436 | if(context.in_quotes) {
437 | return false;
438 | }
439 |
440 | int brace_counter = 0;
441 | bool in_brace_until_quote = false;
442 | bool in_quote = false;
443 | bool until_eoc = false;
444 | bool until_nl = false;
445 | for(size_t i = 0; i < context.content.size(); ++i) {
446 | if(context.content[i] == '"' && !until_eoc && !until_nl) {
447 | if(brace_counter == 1) {
448 | in_quote = !in_quote;
449 | }
450 | else {
451 | in_brace_until_quote = !in_brace_until_quote;
452 | }
453 | }
454 | else if(context.content[i] == open && !in_quote && !until_eoc && !until_nl && !in_brace_until_quote) {
455 | ++brace_counter;
456 | }
457 | else if(context.content[i] == close && !in_quote && !until_eoc && !until_nl && !in_brace_until_quote) {
458 | --brace_counter;
459 | }
460 | else if(context.content[i] == '#' && !in_quote && !in_brace_until_quote) {
461 | if(context.content.size() != i+1 && context.content[i+1] == '#') {
462 | until_eoc = !until_eoc;
463 | ++i;
464 | until_nl = false;
465 | }
466 | else if(!until_eoc) {
467 | until_nl = true;
468 | }
469 | }
470 | else if(is_newline(context.content[i]) && (until_nl && context.content[i] != ';') && !in_quote && !in_brace_until_quote) {
471 | until_nl = false;
472 | }
473 |
474 | if(brace_counter == 0 && i+1 >= context.content.size() && context.content[i] != close) {
475 | return false;
476 | }
477 | }
478 | return brace_counter == 0;
479 | }
480 |
481 | std::vector MeowScript::lex_text(std::string source) {
482 | std::vector ret;
483 |
484 | bool in_quote = false;
485 | std::stack in_braces;
486 | bool until_nl = false;
487 | bool until_eoc = false;
488 | bool in_brace_until_quote = false;
489 | uint32_t line_counter = 1;
490 | Line tmp_line;
491 | tmp_line.line_count = 1;
492 | Token tmp_token;
493 | for(size_t i = 0; i < source.size(); ++i) {
494 | if(is_newline(source[i]) && !in_quote && in_braces.empty() && !until_eoc) {
495 | if(tmp_token.content != "" || tmp_token.in_quotes) {
496 | tmp_line.source.push_back(tmp_token);
497 | }
498 | ret.push_back(tmp_line);
499 |
500 | tmp_line.source.clear();
501 | tmp_token.content = "";
502 | tmp_token.in_quotes = false;
503 | if(source[i] != ';') {
504 | ++line_counter;
505 | }
506 | tmp_line.line_count = line_counter;
507 | until_nl = false;
508 | }
509 | else if(is_newline(source[i]) && (until_nl && source[i] != ';') && !until_eoc) {
510 | tmp_token.content += source[i];
511 | ++line_counter;
512 | until_nl = false;
513 | }
514 | else if(is_open_brace(source[i]) && !in_quote && !until_eoc && !until_nl && !in_brace_until_quote) {
515 | // So that things like add(1,1) is lexed as {"add","(1,1)"} !
516 | if((tmp_token.content != "" || tmp_token.in_quotes) && in_braces.empty()) {
517 | tmp_line.source.push_back(tmp_token);
518 | tmp_token.content = "";
519 | tmp_token.in_quotes = false;
520 | }
521 | tmp_token.content += source[i];
522 | in_braces.push(source[i]);
523 | }
524 | else if(is_closing_brace(source[i]) && !in_quote && !until_eoc && !until_nl && !in_brace_until_quote) {
525 | if(in_braces.empty() || !is_brace_pair(in_braces.top(),source[i])) {
526 | std::string err = "Unexpected token: " + std::string(1,source[i]);
527 | throw errors::MWSMessageException{err,line_counter};
528 | }
529 | tmp_token.content += source[i];
530 | in_braces.pop();
531 | }
532 | else if(source[i] == '\\' && in_braces.empty()) {
533 | if(i != source.size()-1) {
534 | if(source[i+1] == '"') {
535 | tmp_token.content += '"';
536 | ++i;
537 | }
538 | else if(source[i+1] == '\\') {
539 | tmp_token.content += '\\';
540 | ++i;
541 | }
542 | else if(source[i+1] == 't') {
543 | tmp_token.content += "\t";
544 | ++i;
545 | }
546 | else if(source[i+1] == 'r') {
547 | tmp_token.content += "\r";
548 | ++i;
549 | }
550 | else if(source[i+1] == 'n' && in_quote) {
551 | tmp_token.content += '\n';
552 | ++i;
553 | }
554 | else {
555 | tmp_token.content += '\\';
556 | }
557 | }
558 | //else {
559 | // tmp_token.content += '\\';
560 | //}
561 | }
562 | else if(source[i] == '"' && !until_eoc && !until_nl) {
563 | if(in_braces.empty()) {
564 | if(in_quote) {
565 | in_quote = false;
566 | if(source.size()-1 != i && source[i+1] != '\t' && source[i+1] != ' ' && source[i+1] != ',' && source[i+1] != ';' && !is_newline(source[i+1]) && !is_valid_operator_char(source[i+1])) {
567 | throw errors::MWSMessageException{"Unexpected token: " + std::string(1,source[i]),line_counter};
568 | }
569 | }
570 | else {
571 | tmp_token.in_quotes = true;
572 | in_quote = true;
573 | }
574 | }
575 | else {
576 | in_brace_until_quote = !in_brace_until_quote;
577 | tmp_token.content += source[i];
578 | }
579 | }
580 | else if((source[i] == ' ' || source[i] == '\t' || source[i] == ',') && !in_quote && in_braces.empty() && !until_eoc && !until_nl) {
581 | if(tmp_token.content != "" || tmp_token.in_quotes) {
582 | tmp_line.source.push_back(tmp_token);
583 | tmp_token.content = "";
584 | tmp_token.in_quotes = false;
585 | if(source[i] == ',') {
586 | tmp_line.source.push_back(",");
587 | }
588 | }
589 | }
590 | else if(is_valid_operator_char(source[i]) && !in_quote && in_braces.empty() && !until_eoc && !until_nl) {
591 | if(tmp_token.content != "" || tmp_token.in_quotes) {
592 | if(tmp_token.in_quotes && source[i-1] != '"') {
593 | throw errors::MWSMessageException{"Unexpected token: " + std::string(1,source[i]),line_counter};
594 | }
595 | tmp_line.source.push_back(tmp_token);
596 | tmp_token.content = "";
597 | tmp_token.in_quotes = false;
598 | }
599 | tmp_line.source.push_back(std::string(1,source[i]));
600 | }
601 | else if(source[i] == '#' && !in_quote && !in_brace_until_quote) {
602 | if(source.size() != i+1 && source[i+1] == '#') {
603 | if(until_eoc) {
604 | if(tmp_token.content != "" || tmp_token.in_quotes) {
605 | tmp_line.source.push_back(tmp_token);
606 | }
607 | ret.push_back(tmp_line);
608 |
609 | tmp_line.source.clear();
610 | tmp_token.content = "";
611 | tmp_token.in_quotes = false;
612 | if(source[i] != ';') {
613 | ++line_counter;
614 | }
615 | tmp_line.line_count = line_counter;
616 | }
617 | until_eoc = !until_eoc;
618 | ++i;
619 | }
620 | else if(!until_eoc) {
621 | until_nl = true;
622 | }
623 | }
624 | else if(!until_eoc && !until_nl) {
625 | tmp_token.content += source[i];
626 | }
627 | }
628 | if(tmp_token.content != "" || tmp_token.in_quotes) {
629 | tmp_line.source.push_back(tmp_token);
630 | }
631 | if(!tmp_line.source.empty()) {
632 | ret.push_back(tmp_line);
633 | }
634 | std::vector tm_ret;
635 | for(auto line : ret) {
636 | Line ln;
637 | ln.line_count = line.line_count;
638 | for(size_t i = 0; i < line.source.size(); ++i) {
639 | if(line.source[i].in_quotes || line.source[i].content.size() != 1 || !is_valid_operator_char(line.source[i].content[0]) || ln.source.size() == 0) {
640 | ln.source.push_back(line.source[i]);
641 | }
642 | else {
643 | // Is an operator and could be merged!
644 | if(ln.source.back().content.size() > 0 && !ln.source.back().in_quotes && is_valid_operator_char(ln.source.back().content[0])) {
645 | ln.source.back().content.push_back(line.source[i].content[0]);
646 | }
647 | else {
648 | ln.source.push_back(line.source[i]);
649 | }
650 | }
651 | }
652 | tm_ret.push_back(ln);
653 | }
654 | for(auto& i : tm_ret) {
655 | for(auto& j : i.source)
656 | j = tools::check4replace(j);
657 | }
658 | for(auto& i : tm_ret) {
659 | for(size_t j = 0; j < i.source.size(); ++j) {
660 | if(j != 0 && j != i.source.size()-1
661 | && i.source[j].content == "."
662 | && all_numbers(i.source[j-1],false)
663 | && all_numbers(i.source[j+1],false)
664 | ) {
665 | i.source[j-1].content = i.source[j-1].content + "." + i.source[j+1].content;
666 | i.source.erase(i.source.begin()+j);
667 | i.source.erase(i.source.begin()+j);
668 | }
669 | }
670 | }
671 |
672 | return tm_ret;
673 | }
--------------------------------------------------------------------------------
/src/runner.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/runner.hpp"
2 | #include "../inc/tools.hpp"
3 | #include "../inc/modules.hpp"
4 | #include "../inc/objects.hpp"
5 | #include "../inc/expressions.hpp"
6 |
7 | MEOWSCRIPT_SOURCE_FILE
8 |
9 | GeneralTypeToken MeowScript::run_file(std::string file, bool new_scope, bool save_scope, int load_idx, std::map external_vars, fs::path from, bool pass_return_down, bool same_scope) {
10 | return run_text(read(file),true,save_scope,load_idx,external_vars,from,pass_return_down,same_scope);
11 | }
12 |
13 | GeneralTypeToken MeowScript::run_lexed(lexed_tokens lines, bool new_scope, bool save_scope, int load_idx, std::map external_vars, fs::path from, bool pass_return_down, bool same_scope) {
14 | if(from != "") {
15 | global::include_path.push(from);
16 | }
17 | if(load_idx < 0) {
18 | if(!new_scope) {
19 | save_scope = false; // potential "memory leak" if else!
20 | }
21 | if(!same_scope) {
22 | MeowScript::new_scope(new_scope ? -2:-1,external_vars);
23 | }
24 | }
25 | else {
26 | load_scope(load_idx,external_vars);
27 | save_scope = false;
28 | }
29 |
30 | unsigned int ln = current_scope()->current_line;
31 |
32 | global::line_count.push(0);
33 |
34 | for(size_t i = 0; i < lines.size(); ++i) {
35 | GeneralTypeToken ret;
36 | global::line_count.top() = lines[i].line_count;
37 | current_scope()->current_line = lines[i].line_count;
38 | if(lines[i].source.empty()) {
39 | continue;
40 | }
41 |
42 | std::vector identf_line;
43 | identf_line.push_back(get_type(lines[i].source[0]));
44 | global::add_trace(global::get_line(),tools::until_newline(lines[i].source),global::include_path.empty() ? std::filesystem::current_path().string() : global::include_path.top().string());
45 |
46 | while(identf_line.front() == General_type::COMPOUND) {
47 | lines[i].source[0] = tools::check4compound(lines[i].source[0]).to_string();
48 | identf_line.front() = get_type(lines[i].source[0]);
49 | }
50 |
51 | std::string name = lines[i].source[0];
52 |
53 | std::string str_line;
54 | for(auto i : lines[i].source) {
55 | for(size_t j = 0; j < i.content.size(); ++j) {
56 | if(i.content[j] == '\"') {
57 | i.content.insert(i.content.end() - 2 - j,'\\');
58 | ++j;
59 | }
60 | }
61 | if(i.in_quotes) {
62 | i = "\"" + i.content + "\"";
63 | }
64 | str_line += " " + i.content;
65 | }
66 |
67 | if(get_type(str_line,car_Expression) != General_type::EXPRESSION && is_expression("(" + str_line + ")")) {
68 | Variable result = parse_expression("(" + str_line + ")");
69 | ret = result;
70 | }
71 | else if(identf_line.front() == General_type::COMMAND) {
72 | auto cp = lines[i].source;
73 | if(cp.size() != 0)
74 | cp.erase(cp.begin());
75 | Command* command = get_command_overload(name,cp);
76 |
77 | std::vector args;
78 | identf_line.erase(identf_line.begin());
79 | if(command == nullptr) {
80 | std::string err_msg = "No overload of command \"" + name + "\" matches arglist!\n\t- Got: [";
81 | for(size_t k = 0; k < cp.size(); ++k) {
82 | err_msg += (k == 0 ? "":", ") + general_t2token(get_type(cp[k])).content;
83 | }
84 | throw errors::MWSMessageException(err_msg + "]",global::get_line());
85 | }
86 | if((command->args.size() == 0 || !(command->args.back().matches(car_Ongoing))) && command->args.size() != lines[i].source.size()-1) {
87 | std::string err = "Too many/few arguments for command: " + command->name + "\n\t- Expected: " + std::to_string(command->args.size()) + "\n\t- But got: " + std::to_string(lines[i].source.size()-1);
88 | throw errors::MWSMessageException{err,global::get_line()};
89 | }
90 |
91 | bool f_ongoing = false;
92 | for(size_t j = 0; j < cp.size(); ++j) {
93 | if(f_ongoing) {
94 | args.push_back(GeneralTypeToken(cp[j]));
95 | }
96 | else {
97 | auto identf = get_type(cp[j],command->args[j]);
98 | if(command->args[j].matches(car_Ongoing)) {
99 | f_ongoing = true;
100 | args.push_back(GeneralTypeToken(cp[j]));
101 | continue;
102 | }
103 | if(!command->args[j].matches(identf)) {
104 | std::string err_msg = "Invalid argument:\n\t- Expected: [";
105 | for(size_t k = 0; k < command->args[j].carry.size(); ++k) {
106 | err_msg += (k == 0 ? "":",") + general_t2token(General_type(command->args[j].carry[k]-1)).content;
107 | }
108 | err_msg += "]\n\t- But got: " + general_t2token(identf).content + " (" + cp[j].content + ")";
109 | throw errors::MWSMessageException(err_msg,global::get_line());
110 | }
111 | else {
112 | args.push_back(GeneralTypeToken(cp[j],command->args[j]));
113 | }
114 | }
115 | }
116 |
117 | ret = command->run(args);
118 | }
119 | else if(identf_line.front() == General_type::FUNCTION) {
120 | bool shadow_return = false;
121 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
122 | identf_line.push_back(get_type(lines[i].source[j]));
123 | }
124 | if(identf_line.size() > 3 || identf_line.size() < 2) {
125 | throw errors::MWSMessageException{"Too many/few arguments for primitiv function call!\n- Call Sytax: name()[!]",global::get_line()};
126 | }
127 | auto arglist = get_type(lines[i].source[1],General_type::ARGUMENTLIST);
128 | if(arglist != General_type::ARGUMENTLIST) {
129 | std::string err = "Unexpected token after function call:\n\t- Expected: Argumentlist\n\t- But got: " + (identf_line.size() != 1 ? general_t2token(identf_line[1]).content : "VOID");
130 | throw errors::MWSMessageException{err,global::get_line()};
131 | }
132 | if(identf_line.size() == 3) {
133 | if(identf_line[2] != General_type::OPERATOR) {
134 | std::string err = "Unexpected token after function call:\n\t- Expected: \"!\"\n\t- But got: " + general_t2token(identf_line[1]).content;
135 | throw errors::MWSMessageException{err,global::get_line()};
136 | }
137 | if(lines[i].source[2].content != "!") {
138 | std::string err = "Unexpected token after function call:\n\t- Expected: \"!\"\n\t- But got: " + lines[i].source[2].content;
139 | throw errors::MWSMessageException{err,global::get_line()};
140 | }
141 | shadow_return = true;
142 | }
143 |
144 | argument_list alist = tools::parse_argument_list(lines[i].source[1]);
145 |
146 | for(size_t j = 0; j < alist.size(); ++j) {
147 | alist[j] = tools::check4placeholder(alist[j]);
148 | }
149 |
150 | std::vector args;
151 | for(auto i : alist) {
152 | try {
153 | args.push_back(i.to_variable());
154 | }
155 | catch(errors::MWSMessageException& err) {
156 | throw err; // TODO: better message
157 | }
158 | catch(...) {
159 | std::string err_msg = "Can't convert GeneralType " + general_t2token(i.type).content + " to VariableType as function parameter for function: " + name;
160 | throw errors::MWSMessageException{err_msg,global::get_line()};
161 | }
162 | }
163 |
164 | Function* funptr = get_function(name,args);
165 | if(funptr == nullptr) {
166 | std::string err_msg = "No overload of function " + name + " matches agumentlist!\n- Got: [";
167 | for(auto i : args) {
168 | err_msg += var_t2token(i.type).content + ",";
169 | }
170 | err_msg.pop_back();
171 | throw errors::MWSMessageException{err_msg + "]",global::get_line()};
172 | }
173 | Function fun = *funptr;
174 |
175 | Variable vret;
176 | if(sibling_method(name)) {
177 | Object obj = current_scope()->current_obj.top();
178 | MeowScript::new_scope(obj.parent_scope);
179 |
180 | current_scope()->vars = obj.members;
181 | current_scope()->functions = obj.methods;
182 | current_scope()->structs = obj.structs;
183 | current_scope()->current_obj.push(obj);
184 |
185 | vret = fun.run(args,true);
186 |
187 | current_scope()->current_obj.pop();
188 |
189 | obj.members = current_scope()->vars;
190 | obj.methods = current_scope()->functions;
191 | obj.structs = current_scope()->structs;
192 |
193 | current_scope()->current_obj.top() = obj;
194 | pop_scope(false);
195 | }
196 | else {
197 | vret = fun.run(args);
198 | }
199 |
200 | if(!fun.return_type.matches(vret)) {
201 | throw errors::MWSMessageException{"Invalid return type!\n\t- Expected: " + var_t2token(fun.return_type.type).content + "\n\t- But got: " + general_t2token(ret.type).content,global::get_line()};
202 | }
203 | ret = vret;
204 | if(shadow_return) {
205 | ret = general_null;
206 | }
207 | }
208 | else if(identf_line.front() == General_type::MODULE) {
209 | if(!get_module(name)->enabled) {
210 | throw errors::MWSMessageException{"Module \"" + name + "\" is not enabled!",global::get_line()};
211 | }
212 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
213 | identf_line.push_back(get_type(lines[i].source[j]));
214 | }
215 |
216 | if(identf_line.size() < 3 || lines[i].source[1].content != ".") {
217 | throw errors::MWSMessageException{"Invalid module-command call!\n\t- Expected: module.command ...",global::get_line()};
218 | }
219 | Module* mod = get_module(name);
220 | identf_line.erase(identf_line.begin()); // module-name
221 | identf_line.erase(identf_line.begin()); // .
222 |
223 | Command* command = mod->get_command(lines[i].source[2].content);
224 | if(command == nullptr) {
225 | throw errors::MWSMessageException{"Module \"" + mod->name + "\" does not have command: " + lines[i].source[2].content,global::get_line()};
226 | }
227 |
228 | std::vector args;
229 | if(command->args.size() != lines[i].source.size()-3) {
230 | std::string err = "Too many/few arguments for command: " + command->name + "\n\t- Expected: " + std::to_string(command->args.size()) + "\n\t- But got: " + std::to_string(lines[i].source.size()-3);
231 | throw errors::MWSMessageException{err,global::get_line()};
232 | }
233 |
234 | for(size_t j = 0; j < command->args.size(); ++j) {
235 | auto identf = get_type(lines[i].source[j+3],command->args[j]);
236 | if(!command->args[j].matches(identf)) {
237 | std::string err_msg = "Invalid argument:\n\t- Expected: [";
238 | for(size_t k = 0; k < command->args[j].carry.size(); ++k) {
239 | err_msg += (k == 0 ? "":",") + general_t2token(General_type(command->args[j].carry[k]-1)).content;
240 | }
241 | err_msg += "]\n\t- But got: " + general_t2token(get_type(lines[i].source[j+3].content)).content + " (" + lines[i].source[j+3].content + ")";
242 | throw errors::MWSMessageException(err_msg,global::get_line());
243 | }
244 | else {
245 | args.push_back(GeneralTypeToken(lines[i].source[j+3],command->args[j]));
246 | }
247 | }
248 |
249 | ret = command->run(args);
250 | }
251 | else if(identf_line.front() == General_type::STRING || (identf_line.front() == General_type::NAME && is_variable(lines[i].source[0]) && get_variable(lines[i].source[0])->type == Variable::Type::String)) {
252 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
253 | identf_line.push_back(get_type(lines[i].source[j]));
254 | }
255 |
256 | if(identf_line.size() < 3 || lines[i].source[1].content != ".") {
257 | throw errors::MWSMessageException{"Invalid string-method call!\n\t- Expected: string.method ...",global::get_line()};
258 | }
259 | auto idf_first = identf_line.front();
260 | identf_line.erase(identf_line.begin()); // string
261 | identf_line.erase(identf_line.begin()); // .
262 |
263 | Method* method = get_string_method(lines[i].source[2].content);
264 | if(method == nullptr) {
265 | throw errors::MWSMessageException{"Unknown string method: " + lines[i].source[2].content,global::get_line()};
266 | }
267 |
268 | std::vector args;
269 | if(method->args.size() != lines[i].source.size()-3) {
270 | std::string err = "Too many/few arguments for string method: " + method->name + "\n\t- Expected: " + std::to_string(method->args.size()) + "\n\t- But got: " + std::to_string(lines[i].source.size()-3);
271 | throw errors::MWSMessageException{err,global::get_line()};
272 | }
273 |
274 | for(size_t j = 0; j < method->args.size(); ++j) {
275 | auto identf = get_type(lines[i].source[j+3],method->args[j]);
276 | if(!method->args[j].matches(identf)) {
277 | std::string err_msg = "Invalid argument:\n\t- Expected: [";
278 | for(size_t k = 0; k < method->args[j].carry.size(); ++k) {
279 | err_msg += (k == 0 ? "":",") + general_t2token(General_type(method->args[j].carry[k]-1)).content;
280 | }
281 | err_msg += "]\n\t- But got: " + general_t2token(get_type(lines[i].source[j+3].content)).content + " (" + lines[i].source[j+3].content + ")";
282 | throw errors::MWSMessageException(err_msg,global::get_line());
283 | }
284 | else {
285 | args.push_back(GeneralTypeToken(lines[i].source[j+3],method->args[j]));
286 | }
287 | }
288 |
289 | if(idf_first == General_type::STRING) {
290 | Token tk = lines[i].source[0];
291 | ret = method->run(args,&tk);
292 | }
293 | else {
294 | Token tk = get_variable(lines[i].source[0])->storage.string;
295 | ret = method->run(args,&tk);
296 | get_variable(lines[i].source[0])->storage.string = tk;
297 | }
298 | }
299 | else if(identf_line.front() == General_type::LIST || (identf_line.front() == General_type::NAME && is_variable(lines[i].source[0]) && get_variable(lines[i].source[0])->type == Variable::Type::List)) {
300 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
301 | identf_line.push_back(get_type(lines[i].source[j]));
302 | }
303 |
304 | if(identf_line.size() < 3 || lines[i].source[1].content != ".") {
305 | throw errors::MWSMessageException{"Invalid string-method call!\n\t- Expected: string.method ...",global::get_line()};
306 | }
307 | auto idf_first = identf_line.front();
308 | identf_line.erase(identf_line.begin()); // string
309 | identf_line.erase(identf_line.begin()); // .
310 |
311 | Method* method = get_list_method(lines[i].source[2].content);
312 | if(method == nullptr) {
313 | throw errors::MWSMessageException{"Unknown list method: " + lines[i].source[2].content,global::get_line()};
314 | }
315 |
316 | std::vector args;
317 | if(method->args.size() != lines[i].source.size()-3) {
318 | std::string err = "Too many/few arguments for list method: " + method->name + "\n\t- Expected: " + std::to_string(method->args.size()) + "\n\t- But got: " + std::to_string(lines[i].source.size()-3);
319 | throw errors::MWSMessageException{err,global::get_line()};
320 | }
321 |
322 | for(size_t j = 0; j < method->args.size(); ++j) {
323 | auto identf = get_type(lines[i].source[j+3],method->args[j]);
324 | if(!method->args[j].matches(identf)) {
325 | std::string err_msg = "Invalid argument:\n\t- Expected: [";
326 | for(size_t k = 0; k < method->args[j].carry.size(); ++k) {
327 | err_msg += (k == 0 ? "":",") + general_t2token(General_type(method->args[j].carry[k]-1)).content;
328 | }
329 | err_msg += "]\n\t- But got: " + general_t2token(get_type(lines[i].source[j+3].content)).content + " (" + lines[i].source[j+3].content + ")";
330 | throw errors::MWSMessageException(err_msg,global::get_line());
331 | }
332 | else {
333 | args.push_back(GeneralTypeToken(lines[i].source[j+3],method->args[j]));
334 | }
335 | }
336 |
337 | if(idf_first == General_type::LIST) {
338 | List ls = construct_list(lines[i].source[0].content);
339 | ret = method->run(args,&ls);
340 | }
341 | else {
342 | List ls = get_variable(lines[i].source[0])->storage.list;
343 | ret = method->run(args,&ls);
344 | get_variable(lines[i].source[0])->storage.list = ls;
345 | }
346 | }
347 | else if(identf_line.front() == General_type::DICTIONARY || (identf_line.front() == General_type::NAME && is_variable(lines[i].source[0]) && get_variable(lines[i].source[0])->type == Variable::Type::Dictionary)) {
348 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
349 | identf_line.push_back(get_type(lines[i].source[j]));
350 | }
351 |
352 | if(identf_line.size() < 3 || lines[i].source[1].content != ".") {
353 | throw errors::MWSMessageException{"Invalid dictionary-method call!\n\t- Expected: object.method ...",global::get_line()};
354 | }
355 | auto idf_first = identf_line.front();
356 | identf_line.erase(identf_line.begin()); // dictionary
357 | identf_line.erase(identf_line.begin()); // .
358 |
359 | Method* method = get_dictionary_method(lines[i].source[2].content);
360 | if(method == nullptr) {
361 | throw errors::MWSMessageException{"Unknown dictionary method: " + lines[i].source[2].content,global::get_line()};
362 | }
363 |
364 | std::vector args;
365 | if(method->args.size() != lines[i].source.size()-3) {
366 | std::string err = "Too many/few arguments for dictionary method: " + method->name + "\n\t- Expected: " + std::to_string(method->args.size()) + "\n\t- But got: " + std::to_string(lines[i].source.size()-3);
367 | throw errors::MWSMessageException{err,global::get_line()};
368 | }
369 |
370 | for(size_t j = 0; j < method->args.size(); ++j) {
371 | auto identf = get_type(lines[i].source[j+3],method->args[j]);
372 | if(!method->args[j].matches(identf)) {
373 | std::string err_msg = "Invalid argument:\n\t- Expected: [";
374 | for(size_t k = 0; k < method->args[j].carry.size(); ++k) {
375 | err_msg += (k == 0 ? "":",") + general_t2token(General_type(method->args[j].carry[k]-1)).content;
376 | }
377 | err_msg += "]\n\t- But got: " + general_t2token(get_type(lines[i].source[j+3].content)).content + " (" + lines[i].source[j+3].content + ")";
378 | throw errors::MWSMessageException(err_msg,global::get_line());
379 | }
380 | else {
381 | args.push_back(GeneralTypeToken(lines[i].source[j+3],method->args[j]));
382 | }
383 | }
384 |
385 | if(idf_first == General_type::DICTIONARY) {
386 | Dictionary dic = dic_from_token(lines[i].source[0]);
387 | ret = method->run(args,&dic);
388 | }
389 | else {
390 | Dictionary dic = get_variable(lines[i].source[0])->storage.dict;
391 | ret = method->run(args,&dic);
392 | get_variable(lines[i].source[0])->storage.dict = dic;
393 | }
394 | }
395 | else if(identf_line.front() == General_type::STRUCT) {
396 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
397 | identf_line.push_back(get_type(lines[i].source[j]));
398 | }
399 |
400 | if(lines[i].source.size() != 3 || get_type(lines[i].source[1]) != General_type::NAME ||
401 | get_type(lines[i].source[2],car_ArgumentList) != General_type::ARGUMENTLIST) {
402 | throw errors::MWSMessageException{"Invalid pattern for a struct initialisation!\n\t- Pattern: ()",global::get_line()};
403 | }
404 | Token struct_name = lines[i].source[0];
405 | Token instance_name = lines[i].source[1];
406 |
407 | argument_list args = tools::parse_argument_list(lines[i].source[2]);
408 | std::vector call_args;
409 | for(auto i : args)
410 | call_args.push_back(i.to_variable());
411 |
412 | int scope_idx = get_new_scope();
413 | Object obj;
414 | Object* struc = get_struct(struct_name);
415 | obj.methods = struc->methods;
416 | obj.members = struc->members;
417 | obj.parent_scope = struc->parent_scope;
418 | obj.structs = struc->structs;
419 | obj.on_deconstruct = struc->on_deconstruct;
420 |
421 | for(auto& i : obj.methods) {
422 | for(auto& j : i.second) {
423 | int sscope = j.scope_idx;
424 | j.scope_idx = get_new_scope();
425 | scopes[j.scope_idx] = scopes[sscope];
426 | scopes[j.scope_idx].parent = obj.parent_scope;
427 | scopes[j.scope_idx].index = j.scope_idx;
428 | }
429 | }
430 | set_variable(instance_name,obj);
431 | if(has_method(obj,struct_name)) {
432 | run_method(&obj,struct_name,call_args);
433 | }
434 | set_variable(instance_name,obj);
435 | }
436 | else if(identf_line.front() == General_type::OBJECT || (identf_line.front() == General_type::NAME && is_variable(lines[i].source[0]) && get_variable(lines[i].source[0])->type == Variable::Type::Object)) {
437 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
438 | identf_line.push_back(get_type(lines[i].source[j]));
439 | }
440 |
441 | if(lines[i].source.size()-1 < 3 || lines[i].source[1].content != "." || lines[i].source[1].in_quotes) {
442 | throw errors::MWSMessageException{"Invalid object-method call!\n\t- Expected: object.method ...",global::get_line()};
443 | }
444 | auto cpy = lines[i].source;
445 | cpy.erase(cpy.begin()); // object
446 | cpy.erase(cpy.begin()); // .
447 |
448 | Object obj = *get_object(lines[i].source[0].content);
449 | Token method_name = lines[i].source[2];
450 |
451 | if(!has_method(obj,method_name)) {
452 | throw errors::MWSMessageException{"Unknown object method: " + method_name.content,global::get_line()};
453 | }
454 |
455 | std::vector args;
456 | std::vector arglist = tools::parse_argument_list(lines[i].source[3]);
457 |
458 | for(auto i : arglist) {
459 | args.push_back(tools::check4placeholder(i).to_variable());
460 | }
461 |
462 | Function* method = get_method(&obj,method_name,args);
463 | if(method == nullptr) {
464 | std::string err_msg = "No overload of method " + name + " matches agumentlist!\n- Got: [";
465 | for(auto i : args) {
466 | err_msg += var_t2token(i.type).content + ",";
467 | }
468 | err_msg.pop_back();
469 | throw errors::MWSMessageException{err_msg + "]",global::get_line()};
470 | }
471 |
472 | ret = run_method(&obj,method_name,args);
473 | *get_object(lines[i].source[0].content) = obj;
474 | }
475 | else if(identf_line.front() == General_type::EXPRESSION) {
476 | for(size_t j = 1; j < lines[i].source.size(); ++j) {
477 | identf_line.push_back(get_type(lines[i].source[j]));
478 | }
479 | bool shadow_return = false;
480 | if(identf_line.size() > 2) {
481 | std::string err = "Invalid start of line!\n\t- Expected: [Command,Function,Module,String,List,Dictionary,Object,Struct]\n\t- But got: " + general_t2token(identf_line.front()).content + " (" + lines[i].source[0].content + ")\n";
482 | throw errors::MWSMessageException{err,global::get_line()};
483 | }
484 | if(identf_line.size() == 2) {
485 | if(identf_line[1] != General_type::OPERATOR) {
486 | std::string err = "Unexpected token after expression:\n\t- Expected: \"!\"\n\t- But got: " + general_t2token(identf_line[1]).content;
487 | throw errors::MWSMessageException{err,global::get_line()};
488 | }
489 | if(lines[i].source[1].content != "!") {
490 | std::string err = "Unexpected token after expression:\n\t- Expected: \"!\"\n\t- But got: " + lines[i].source[2].content;
491 | throw errors::MWSMessageException{err,global::get_line()};
492 | }
493 | shadow_return = true;
494 | }
495 | if(shadow_return) {
496 | parse_expression(lines[i].source[0]);
497 | }
498 | else {
499 | ret = parse_expression(lines[i].source[0]);
500 | }
501 | }
502 | else {
503 | std::string err = "Invalid start of line!\n\t- Expected: [Command,Function,Module,String,List,Dictionary,Object,Struct]\n\t- But got: " + general_t2token(identf_line.front()).content + " (" + lines[i].source[0].content + ")\n";
504 | throw errors::MWSMessageException{err,global::get_line()};
505 | }
506 |
507 | global::pop_trace();
508 |
509 | if(ret.type == General_type::OBJECT) {
510 | Object* obj = get_object(ret.source);
511 | if(obj != nullptr) {
512 | ret.saveobj = *obj;
513 | ret.use_save_obj = true;
514 | }
515 | }
516 |
517 | if(global::runner_should_return != 0) {
518 | if(!pass_return_down) {
519 | --global::runner_should_return;
520 | }
521 | if(from != "") {
522 | global::include_path.pop();
523 | }
524 | if(!same_scope) {
525 | pop_scope(save_scope);
526 | }
527 | global::line_count.pop();
528 | if(same_scope) {
529 | current_scope()->current_line = ln;
530 | }
531 | return ret;
532 | }
533 | else if(global::runner_should_exit != 0) {
534 | if(from != "") {
535 | global::include_path.pop();
536 | }
537 | if(!same_scope) {
538 | pop_scope(save_scope);
539 | }
540 | global::line_count.pop();
541 | if(same_scope) {
542 | current_scope()->current_line = ln;
543 | }
544 | return GeneralTypeToken();
545 | }
546 | else if(global::break_loop != 0 || global::continue_loop != 0) {
547 | if(from != "") {
548 | global::include_path.pop();
549 | }
550 | if(!same_scope) {
551 | pop_scope(save_scope);
552 | }
553 | global::line_count.pop();
554 | if(same_scope) {
555 | current_scope()->current_line = ln;
556 | }
557 | return GeneralTypeToken();
558 | }
559 | else if(global::in_compound != 0 && i+1 == lines.size()) {
560 | if(from != "") {
561 | global::include_path.pop();
562 | }
563 | if(!same_scope) {
564 | pop_scope(save_scope);
565 | }
566 | global::line_count.pop();
567 | if(same_scope) {
568 | current_scope()->current_line = ln;
569 | }
570 | return ret;
571 | }
572 | else if(ret.type != General_type::VOID && ret.type != General_type::UNKNOWN) {
573 | std::cout << ret.to_string() << "\n";
574 | }
575 | }
576 |
577 | if(from != "") {
578 | global::include_path.pop();
579 | }
580 | if(!same_scope) {
581 | pop_scope(save_scope);
582 | }
583 | global::line_count.pop();
584 | if(same_scope) {
585 | current_scope()->current_line = ln;
586 | }
587 | return general_null;
588 | }
589 |
590 | GeneralTypeToken MeowScript::run_text(std::string text, bool new_scope, bool save_scope, int load_idx, std::map external_vars, fs::path from, bool pass_return_down, bool same_scope) {
591 | auto lines = lex_text(text);
592 | return run_lexed(lines,new_scope,save_scope,load_idx,external_vars,from,pass_return_down,same_scope);
593 | }
--------------------------------------------------------------------------------
/src/scopes.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/scopes.hpp"
2 | #include "../inc/global.hpp"
3 |
4 | MEOWSCRIPT_SOURCE_FILE
5 |
6 | Scope* MeowScript::current_scope() {
7 | if(scope_trace.empty()) {
8 | return nullptr;
9 | }
10 | return &scopes[scope_trace.top()];
11 | }
12 |
13 | void MeowScript::new_scope(int parent, std::map external_vars) {
14 | Scope ns;
15 | if(parent != -2) {
16 | if(parent == -1 && scopes.size() != 0) {
17 | parent = scopes[scope_trace.top()].index;
18 | }
19 | ns.parent = parent;
20 | }
21 | for(auto& i : scopes) {
22 | if(i.freed) {
23 | ns.index = i.index;
24 | i.vars.clear();
25 | i.freed = false;
26 | i.parent = ns.parent;
27 | for(auto j : external_vars) {
28 | i.vars[j.first] = j.second;
29 | }
30 | scope_trace.push(i.index);
31 | return;
32 | }
33 | }
34 | for(auto i : external_vars) {
35 | ns.vars[i.first] = i.second;
36 | }
37 | ns.index = scopes.size();
38 | scope_trace.push(ns.index);
39 | scopes.push_back(ns);
40 | }
41 |
42 | void MeowScript::pop_scope(bool save) {
43 | if(!scope_trace.empty()) {
44 | for(auto& i : current_scope()->vars) {
45 | if(i.second.type == Variable::Type::Object) {
46 | call_obj_deconstruct(i.second.storage.obj);
47 | }
48 | }
49 | if(!save) {
50 | scopes[current_scope()->index].freed = true;
51 | scopes[current_scope()->index].current_obj = {};
52 | scopes[current_scope()->index].functions = {};
53 | scopes[current_scope()->index].vars = {};
54 | scopes[current_scope()->index].structs = {};
55 | }
56 |
57 | scope_trace.pop();
58 | }
59 | }
60 |
61 | void MeowScript::load_scope(int idx, std::map external_vars, bool hard_copy) {
62 | if(hard_copy) {
63 | scope_trace.push(idx);
64 | for(auto i : external_vars) {
65 | current_scope()->vars[i.first] = i.second;
66 | }
67 | }
68 | else {
69 | new_scope(scopes[idx].parent,scopes[idx].vars);
70 | current_scope()->functions = scopes[idx].functions;
71 | for(auto i : external_vars) {
72 | current_scope()->vars[i.first] = i.second;
73 | }
74 | }
75 | }
76 |
77 | void MeowScript::call_obj_deconstruct(Object& obj) {
78 | for(auto [name,args] : obj.on_deconstruct) {
79 | run_method(&obj,name,args);
80 | }
81 | }
82 |
83 | unsigned int MeowScript::get_new_scope() {
84 | for(size_t i = 0; i < scopes.size(); ++i) {
85 | if(scopes[i].freed) {
86 | scopes[i].freed = false;
87 | scopes[i].vars = {};
88 | scopes[i].functions = {};
89 | scopes[i].structs = {};
90 | scopes[i].parent = 0;
91 | scopes[i].current_obj = {};
92 | return i;
93 | }
94 | }
95 | scopes.push_back(Scope());
96 | scopes.back().index = scopes.size()-1;
97 | return scopes.size()-1;
98 | }
99 |
100 | bool MeowScript::is_variable(std::string name) {
101 | return get_variable(name) != nullptr;
102 | }
103 |
104 | Variable* MeowScript::get_variable(std::string name) {
105 | int index = current_scope()->index;
106 | while(index > -1) {
107 | for(auto& i : scopes[index].vars) {
108 | if(i.first == name) {
109 | return &i.second;
110 | }
111 | }
112 | index = scopes[index].parent;
113 | }
114 | return nullptr;
115 | }
116 |
117 | void MeowScript::set_variable(std::string name, Variable var) {
118 | Variable* vptr = get_variable(name);
119 | if(vptr == nullptr) {
120 | new_variable(name,var);
121 | return;
122 | }
123 | if(vptr->constant) {
124 | throw errors::MWSMessageException{"Const variable \"" + name + "\" can not get a new value! (" + var.to_string() + ")",global::get_line()};
125 | }
126 | //if(vptr->type == Variable::Type::Object) {
127 | //call_obj_deconstruct(vptr->storage.obj);
128 | //}
129 | vptr->set(var); // TODO: on error -> handling
130 | }
131 |
132 | void MeowScript::new_variable(std::string name, Variable var) {
133 | current_scope()->vars[name] = var;
134 | }
135 |
136 | bool MeowScript::is_function(std::string name) {
137 | int index = current_scope()->index;
138 | while(index > -1) {
139 | for(auto& i : scopes[index].functions) {
140 | if(i.first == name) {
141 | return true;
142 | }
143 | }
144 | index = scopes[index].parent;
145 | }
146 | return false;
147 | }
148 |
149 | bool MeowScript::is_event(std::string name) {
150 | return global::events.count(name) != 0;
151 | }
152 |
153 | bool MeowScript::is_object(std::string name) {
154 | int index = current_scope()->index;
155 | while(index > -1) {
156 | for(auto i : scopes[index].vars) {
157 | if(i.first == name && i.second.type == Variable::Type::Object) {
158 | return true;
159 | }
160 | }
161 | index = scopes[index].parent;
162 | }
163 | return false;
164 | }
165 |
166 | bool MeowScript::is_struct(std::string name) {
167 | int index = current_scope()->index;
168 | while(index > -1) {
169 | for(auto i : scopes[index].structs) {
170 | if(i.first == name) {
171 | return true;
172 | }
173 | }
174 | index = scopes[index].parent;
175 | }
176 | return false;
177 | }
178 |
179 | Object* MeowScript::get_struct(std::string name) {
180 | int index = current_scope()->index;
181 | while(index > -1) {
182 | for(auto& i : scopes[index].structs) {
183 | if(i.first == name) {
184 | return &i.second;
185 | }
186 | }
187 | index = scopes[index].parent;
188 | }
189 | return nullptr;
190 | }
191 |
192 | Object* MeowScript::get_object(std::string name) {
193 | int index = current_scope()->index;
194 | while(index > -1) {
195 | for(auto& i : scopes[index].vars) {
196 | if(i.first == name && i.second.type == Variable::Type::Object) {
197 | return &i.second.storage.obj;
198 | }
199 | }
200 | index = scopes[index].parent;
201 | }
202 | return nullptr;
203 | }
204 |
205 | bool MeowScript::func_param_match(Function fun,std::vector params) {
206 | if(fun.params.size() != params.size()) {
207 | return false;
208 | }
209 | for(size_t i = 0; i < fun.params.size(); ++i) {
210 | if(!fun.params[i].matches(params[i])) {
211 | return false;
212 | }
213 | }
214 | return true;
215 | }
216 |
217 | bool MeowScript::func_param_match(Function fun,std::vector params) {
218 | if(fun.params.size() != params.size()) {
219 | return false;
220 | }
221 | for(size_t i = 0; i < fun.params.size(); ++i) {
222 | if(!fun.params[i].matches(params[i])) {
223 | return false;
224 | }
225 | }
226 | return true;
227 | }
228 |
229 | Function* MeowScript::get_function(std::string name,std::vector params) {
230 | int index = current_scope()->index;
231 | while(index > -1) {
232 | for(auto& i : scopes[index].functions) {
233 | if(i.first == name) {
234 | for(auto& j : i.second) {
235 | if(func_param_match(j,params)) {
236 | return &j;
237 | }
238 | }
239 | }
240 | }
241 | index = scopes[index].parent;
242 | }
243 | return nullptr;
244 | }
245 |
246 | Function* MeowScript::get_function(std::string name,std::vector params) {
247 | int index = current_scope()->index;
248 | while(index > -1) {
249 | for(auto& i : scopes[index].functions) {
250 | if(i.first == name) {
251 | for(auto& j : i.second) {
252 | if(func_param_match(j,params)) {
253 | return &j;
254 | }
255 | }
256 | }
257 | }
258 | index = scopes[index].parent;
259 | }
260 | return nullptr;
261 | }
262 |
263 | bool MeowScript::add_function(std::string name, Function fun) {
264 | if(::get_function(name,fun.params) != nullptr) {
265 | return false;
266 | }
267 | if(fun.scope_idx == 0) {
268 | fun.scope_idx = get_new_scope();
269 | scopes[fun.scope_idx].parent = current_scope()->index;
270 | }
271 | current_scope()->functions[name].push_back(fun);
272 | return true;
273 | }
274 |
275 | void MeowScript::add_object(std::string name, Object obj) {
276 | for(auto& i : obj.methods) {
277 | for(auto& j : i.second) {
278 | int sscope = j.scope_idx;
279 | j.scope_idx = get_new_scope();
280 | scopes[j.scope_idx] = scopes[sscope];
281 | scopes[j.scope_idx].parent = obj.parent_scope;
282 | scopes[j.scope_idx].index = j.scope_idx;
283 | }
284 | }
285 | set_variable(name,obj);
286 | }
287 |
288 | bool MeowScript::add_struct(std::string name, Object struc) {
289 | for(auto i : current_scope()->structs) {
290 | if(i.first == name) {
291 | return false;
292 | }
293 | }
294 | current_scope()->structs[name] = struc;
295 | return true;
296 | }
--------------------------------------------------------------------------------
/src/tools.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/tools.hpp"
2 | #include "../inc/errors.hpp"
3 | #include "../inc/runner.hpp"
4 | #include "../inc/expressions.hpp"
5 |
6 | MEOWSCRIPT_SOURCE_FILE
7 |
8 | argument_list MeowScript::tools::parse_argument_list(GeneralTypeToken context) {
9 | return parse_argument_list(context.source);
10 | }
11 |
12 | argument_list MeowScript::tools::parse_argument_list(Token context) {
13 | argument_list ret;
14 | if(context.content == "" || context.in_quotes || !brace_check(context,'(',')')) {
15 | return argument_list();
16 | }
17 | context.content.erase(context.content.begin());
18 | context.content.erase(context.content.begin()+context.content.size()-1);
19 | if(context.content.size() == 0) {
20 | return argument_list();
21 | }
22 |
23 | auto lexed = lex_text(context);
24 | std::vector line;
25 | for(auto i : lexed)
26 | for(auto j : i.source)
27 | line.push_back(j);
28 |
29 | GeneralTypeToken last = general_null;
30 | bool found_sl = true;
31 |
32 | for(auto i : line) {
33 | if(i.content == ",") {
34 | if(last == general_null) {
35 | return argument_list();
36 | }
37 | ret.push_back(last);
38 | last = general_null;
39 | found_sl = true;
40 | }
41 | else if(found_sl) {
42 | last = i;
43 | found_sl = false;
44 | }
45 | else {
46 | return argument_list();
47 | }
48 | }
49 | if(last != general_null) {
50 | if(!found_sl) {
51 | ret.push_back(last);
52 | }
53 | else {
54 | return argument_list();
55 | }
56 | }
57 |
58 | return ret;
59 | }
60 |
61 | const std::vector> Dictionary::pairs() const {
62 | std::vector> ret;
63 | for(size_t i = 0; i < keys().size(); ++i) {
64 | ret.push_back(std::make_pair(keys()[i],values()[i]));
65 | }
66 | return ret;
67 | }
68 | std::vector> Dictionary::pairs() {
69 | std::vector> ret;
70 | for(size_t i = 0; i < keys().size(); ++i) {
71 | ret.push_back(std::make_pair(keys()[i],values()[i]));
72 | }
73 | return ret;
74 | }
75 |
76 | const std::vector& Dictionary::keys() const {
77 | return i_keys;
78 | }
79 | const std::vector& Dictionary::values() const {
80 | return i_values;
81 | }
82 | std::vector& Dictionary::keys() {
83 | return i_keys;
84 | }
85 | std::vector& Dictionary::values() {
86 | return i_values;
87 | }
88 |
89 | bool Dictionary::has(const GeneralTypeToken gtt) const {
90 | for(size_t i = 0; i < keys().size(); ++i) {
91 | if(keys()[i] == gtt) {
92 | return true;
93 | }
94 | }
95 | return false;
96 | }
97 |
98 | GeneralTypeToken& Dictionary::operator[](GeneralTypeToken gtt) {
99 | for(size_t i = 0; i < keys().size(); ++i) {
100 | if(keys()[i] == gtt) {
101 | return values()[i];
102 | }
103 | }
104 |
105 | keys().push_back(gtt);
106 | values().push_back(general_null);
107 | return values().back();
108 | }
109 |
110 | std::vector MeowScript::tools::parse_function_params(Token context) {
111 | if(brace_check(context,'(',')')) {
112 | context.content.erase(context.content.begin());
113 | context.content.erase(context.content.begin()+context.content.size()-1);
114 | }
115 | auto lines = lex_text(context.content);
116 | if(lines.empty()) {
117 | return {};
118 | }
119 | std::vector ret;
120 | std::vector line;
121 | for(auto i : lines) {
122 | for(auto j : i.source) {
123 | line.push_back(j);
124 | }
125 | }
126 |
127 | std::vector nline;
128 | for(size_t i = 0; i < line.size(); ++i) {
129 | nline.push_back("");
130 | for(size_t j = 0; j < line[i].content.size(); ++j) {
131 | if(line[i].content[j] == ',') {
132 | nline.push_back(",");
133 | nline.push_back("");
134 | }
135 | else {
136 | nline.back().content += line[i].content[j];
137 | }
138 | }
139 | }
140 |
141 | std::vector> arguments;
142 | if(nline.size() != 0)
143 | arguments.push_back({});
144 | for(size_t i = 0; i < nline.size(); ++i) {
145 | if(nline[i].content == ",") {
146 | if(arguments.back().empty()) {
147 | throw errors::MWSMessageException{"Invalid argument format!",global::get_line()};
148 | }
149 | arguments.push_back({});
150 | }
151 | else {
152 | arguments.back().push_back(nline[i]);
153 | }
154 | }
155 |
156 | for(auto i : arguments) {
157 | for(size_t j = 0; j < i.size(); ++j) {
158 | if(i[j].content == "" && !i[j].in_quotes) {
159 | i.erase(i.begin()+j);
160 | --j;
161 | }
162 | }
163 |
164 | if(i.size() == 1) {
165 | if(!is_valid_name(i[0])) {
166 | throw errors::MWSMessageException{"Enexpected token: " + i[0].content,global::get_line()};
167 | }
168 | ret.push_back(Parameter(Variable::Type::UNKNOWN,i[0]));
169 | }
170 | else if(i.size() == 3) {
171 | if(!is_valid_name(i[0])) {
172 | throw errors::MWSMessageException{"Enexpected token: " + i[0].content,global::get_line()};
173 | }
174 | if(i[1].content != "::" && i[1].content != ":") {
175 | throw errors::MWSMessageException{"Invalid argument format!",global::get_line()};
176 | }
177 | if(!is_struct(i[2]) && !is_valid_var_t(i[2])) {
178 | throw errors::MWSMessageException{i[2].content + " is not a known VariableType or struct!",global::get_line()};
179 | }
180 | if(is_struct(i[2])) {
181 | ret.push_back(Parameter(Variable::Type::Object,i[0],i[2]));
182 | }
183 | else {
184 | ret.push_back(Parameter(token2var_t(i[2]),i[0]));
185 | }
186 | }
187 | else {
188 | throw errors::MWSMessageException{"Invalid argument format!",global::get_line()};
189 | }
190 | }
191 | return ret;
192 | }
193 |
194 | GeneralTypeToken MeowScript::tools::check4var(GeneralTypeToken token) {
195 | if(token.type == General_type::NAME) {
196 | Variable* var = get_variable(token.source);
197 | if(var != nullptr) {
198 | return GeneralTypeToken(*var);
199 | }
200 | }
201 | return token;
202 | }
203 |
204 | GeneralTypeToken MeowScript::tools::check4compound(GeneralTypeToken token) {
205 | if(token.type == General_type::COMPOUND) {
206 | token.source.content.erase(token.source.content.begin());
207 | token.source.content.erase(token.source.content.begin()+token.source.content.size()-1);
208 | ++global::in_compound;
209 | int saved_istruct = global::in_struct;
210 | global::in_struct = 0;
211 | GeneralTypeToken ret = run_text(token.source,false);
212 | global::in_struct = saved_istruct;
213 | --global::in_compound;
214 | //if(ret.type == General_type::VOID) {
215 | // throw errors::MWSMessageException{"Compound did not return anything!",global::get_line()};
216 | //}
217 | return ret;
218 | }
219 | return token;
220 | }
221 |
222 | GeneralTypeToken MeowScript::tools::check4placeholder(GeneralTypeToken token) {
223 | return check4var(check4compound(check4expression(token)));
224 | }
225 |
226 | GeneralTypeToken MeowScript::tools::check4expression(GeneralTypeToken token) {
227 | if(token.type == General_type::EXPRESSION) {
228 | Variable ret = parse_expression(token.to_string());
229 | return GeneralTypeToken(ret);
230 | }
231 | return token;
232 | }
233 |
234 | GeneralTypeToken MeowScript::tools::check4replace(GeneralTypeToken token) {
235 | if(token.type == General_type::NAME) {
236 | if(replaces.count(token.source.content) != 0) {
237 | return replaces[token.source.content];
238 | }
239 | return token;
240 | }
241 | return token;
242 | }
243 |
244 | Token MeowScript::tools::check4replace(Token token) {
245 | if(replaces.count(token.content) != 0 && !token.in_quotes) {
246 | return replaces[token.content].to_string();
247 | }
248 | return token;
249 | }
250 |
251 | Token MeowScript::tools::remove_unneeded_chars(Token token) {
252 | if(token.in_quotes) {
253 | return token;
254 | }
255 | size_t i = 0;
256 | for(i = 0; i < token.content.size(); ++i) {
257 | if(token.content[i] != ' ' && token.content[i] != '\t' && !is_newline(token.content[i])) {
258 | break;
259 | }
260 | }
261 | token.content.erase(token.content.begin(),token.content.begin()+i);
262 | for(i = token.content.size(); i != -1; --i) {
263 | if(token.content[i] != ' ' && token.content[i] != '\t' && !is_newline(token.content[i])) {
264 | break;
265 | }
266 | }
267 | token.content.erase(token.content.begin()+i,token.content.end());
268 | return token;
269 | }
270 |
271 |
272 | Token MeowScript::tools::remove_uness_decs(Token num, bool to_int) {
273 | if(num.in_quotes) {
274 | return num;
275 | }
276 | bool has_dot = false;
277 | bool all_zero = true;
278 | for(auto i : num.content) {
279 | // vvvvvvvv - just in case
280 | all_zero &= (i == '0' || i == '.');
281 | if(i == '.') has_dot = true;
282 | }
283 | if(all_zero) {
284 | return "0";
285 | }
286 | if(!has_dot) {
287 | return num;
288 | }
289 |
290 | if(to_int) {
291 | for(size_t i = 0; i < num.content.size(); ++i) {
292 | if(num.content[i] == '.') {
293 | num.content.erase(num.content.begin()+i,num.content.end());
294 | return num;
295 | }
296 | }
297 | return num;
298 | }
299 |
300 | for(size_t i = num.content.size()-1; i != -1; --i) {
301 | if(num.content[i] == '.') {
302 | num.content.erase(num.content.begin()+i);
303 | break;
304 | }
305 | else if(num.content[i] == '0') {
306 | num.content.erase(num.content.begin()+i);
307 | }
308 | else {
309 | break;
310 | }
311 | }
312 |
313 | return num;
314 | }
315 |
316 | Token MeowScript::tools::until_newline(std::vector tks) {
317 | Token ret;
318 | for(auto i : tks) {
319 | for(auto j : i.content) {
320 | if(j == '\n') {
321 | return ret;
322 | }
323 | ret.content += j;
324 | }
325 | ret.content += " ";
326 | }
327 | ret.content.pop_back();
328 | return ret;
329 | }
330 |
--------------------------------------------------------------------------------
/stdlib/filesystem.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/meowscript.hpp"
2 |
3 | MEOWSCRIPT_MODULE
4 |
5 | class ModuleFilesystem {
6 | public:
7 | ModuleFilesystem() {
8 | Module filesystem("filesystem");
9 | filesystem.add_command(
10 | {"read",
11 | {
12 | car_String | car_PlaceHolderAble
13 | },
14 | [](std::vector args)->GeneralTypeToken {
15 | auto fname = tools::check4placeholder(args[0]);
16 | if(fname.type != General_type::STRING) {
17 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
18 | }
19 | std::string file = global::include_parent_path().string() + fname.source.content;
20 | if(!fs::exists(file)) {
21 | throw errors::MWSMessageException{"File does not exist! (" + file + ")",global::get_line()};
22 | }
23 | std::string content = read(file);
24 |
25 | GeneralTypeToken ret;
26 | ret.type = General_type::STRING;
27 | ret.source.content = content;
28 | ret.source.in_quotes = true;
29 | return ret;
30 | }
31 | }
32 | ).add_command(
33 | {"get_line",
34 | {
35 | car_String | car_PlaceHolderAble,
36 | car_Number | car_PlaceHolderAble
37 | },
38 | [](std::vector args)->GeneralTypeToken {
39 | auto fname = tools::check4placeholder(args[0]);
40 | if(fname.type != General_type::STRING) {
41 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
42 | }
43 | std::string file = global::include_parent_path().string() + fname.source.content;
44 | if(!fs::exists(file)) {
45 | throw errors::MWSMessageException{"File does not exist! (" + file + ")",global::get_line()};
46 | }
47 | auto line_n = tools::check4placeholder(args[1]);
48 | if(line_n.type != General_type::NUMBER) {
49 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(line_n.type).content,global::get_line()};
50 | }
51 | int line_num = line_n.to_variable().storage.number;
52 | if(line_num < 1) {
53 | throw errors::MWSMessageException{"Line index must be grater than zero! (" + std::to_string(line_num) + ")",global::get_line()};
54 | }
55 | std::string content = read(file);
56 |
57 | std::vector lines;
58 | std::string tmp;
59 | for(auto i : content) {
60 | if(i == '\n') {
61 | lines.push_back(tmp);
62 | tmp = "";
63 | }
64 | else {
65 | tmp += i;
66 | }
67 | }
68 | if(tmp != "") {
69 | lines.push_back(tmp);
70 | }
71 | if(line_num > lines.size()) {
72 | throw errors::MWSMessageException{"File does not have line: " + std::to_string(line_num),global::get_line()};
73 | }
74 | return lines[line_num-1];
75 | }
76 | }
77 | ).add_command(
78 | {"exists",
79 | {
80 | car_String | car_PlaceHolderAble
81 | },
82 | [](std::vector args)->GeneralTypeToken {
83 | auto fname = tools::check4placeholder(args[0]);
84 | if(fname.type != General_type::STRING) {
85 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
86 | }
87 | std::string file = global::include_parent_path().string() + fname.source.content;
88 | if(!fs::exists(file)) {
89 | throw errors::MWSMessageException{"File does not exist! (" + file + ")",global::get_line()};
90 | }
91 | return fs::exists(file);
92 | }
93 | }
94 | ).add_command(
95 | {"is_directory",
96 | {
97 | car_String | car_PlaceHolderAble
98 | },
99 | [](std::vector args)->GeneralTypeToken {
100 | auto fname = tools::check4placeholder(args[0]);
101 | if(fname.type != General_type::STRING) {
102 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
103 | }
104 | std::string file = global::include_parent_path().string() + fname.source.content;
105 | if(!fs::exists(file)) {
106 | throw errors::MWSMessageException{"File does not exist! (" + file + ")",global::get_line()};
107 | }
108 |
109 | return fs::is_directory(file);
110 | }
111 | }
112 | ).add_command(
113 | {"extention",
114 | {
115 | car_String | car_PlaceHolderAble
116 | },
117 | [](std::vector args)->GeneralTypeToken {
118 | auto fname = tools::check4placeholder(args[0]);
119 | if(fname.type != General_type::STRING) {
120 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
121 | }
122 | std::string file = global::include_parent_path().string() + fname.source.content;
123 |
124 | GeneralTypeToken ret;
125 | ret.type = General_type::STRING;
126 | ret.source.content = fs::path(file).extension().string();
127 | ret.source.in_quotes = true;
128 | return ret;
129 | }
130 | }
131 | ).add_command(
132 | {"filename",
133 | {
134 | car_String | car_PlaceHolderAble
135 | },
136 | [](std::vector args)->GeneralTypeToken {
137 | auto fname = tools::check4placeholder(args[0]);
138 | if(fname.type != General_type::STRING) {
139 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
140 | }
141 | std::string file = global::include_parent_path().string() + fname.source.content;
142 |
143 | GeneralTypeToken ret;
144 | ret.type = General_type::STRING;
145 | ret.source.content = fs::path(file).filename().string();
146 | ret.source.in_quotes = true;
147 | return ret;
148 | }
149 | }
150 | ).add_command(
151 | {"write",
152 | {
153 | car_String | car_PlaceHolderAble,
154 | car_String | car_Number | car_List | car_PlaceHolderAble,
155 | },
156 | [](std::vector args)->GeneralTypeToken {
157 | auto fname = tools::check4placeholder(args[0]);
158 | if(fname.type != General_type::STRING) {
159 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
160 | }
161 | std::string file = global::include_parent_path().string() + fname.source.content;
162 | Variable to_write = tools::check4placeholder(args[1]).to_variable();
163 | if(to_write.type != Variable::Type::String && to_write.type != Variable::Type::Number && to_write.type != Variable::Type::List) {
164 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: [String,Number,List]\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
165 | }
166 | std::ofstream off(file,std::ios::trunc);
167 | off.close();
168 | off.open(file,std::ios::app);
169 | if(to_write.type == Variable::Type::String) {
170 | off << to_write.storage.string.content;
171 | }
172 | else {
173 | off << to_write.to_string();
174 | }
175 | off.close();
176 | return general_null;
177 | }
178 | }
179 | ).add_command(
180 | {"append",
181 | {
182 | car_String | car_PlaceHolderAble,
183 | car_String | car_Number | car_List | car_PlaceHolderAble,
184 | },
185 | [](std::vector args)->GeneralTypeToken {
186 | auto fname = tools::check4placeholder(args[0]);
187 | if(fname.type != General_type::STRING) {
188 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
189 | }
190 | std::string file = global::include_parent_path().string() + fname.source.content;
191 | Variable to_write = tools::check4placeholder(args[1]).to_variable();
192 | if(to_write.type != Variable::Type::String && to_write.type != Variable::Type::Number && to_write.type != Variable::Type::List) {
193 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: [String,Number,List]\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
194 | }
195 | std::ofstream off(file,std::ios::app);
196 | if(to_write.type == Variable::Type::String) {
197 | off << to_write.storage.string.content;
198 | }
199 | else {
200 | off << to_write.to_string();
201 | }
202 | off.close();
203 | return general_null;
204 | }
205 | }
206 | ).add_command(
207 | {"size",
208 | {
209 | car_String | car_PlaceHolderAble,
210 | },
211 | [](std::vector args)->GeneralTypeToken {
212 | auto fname = tools::check4placeholder(args[0]);
213 | if(fname.type != General_type::STRING) {
214 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(fname.type).content,global::get_line()};
215 | }
216 | std::string file = global::include_parent_path().string() + fname.source.content;
217 | if(!fs::exists(file)) {
218 | throw errors::MWSMessageException{"File does not exist! (" + file + ")",global::get_line()};
219 | }
220 |
221 | return fs::file_size(file);
222 | }
223 | }
224 | );
225 | filesystem.enabled = false;
226 | add_module(filesystem);
227 | }
228 |
229 | }static module_filesystem;
--------------------------------------------------------------------------------
/stdlib/math.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/meowscript.hpp"
2 | #include
3 |
4 | MEOWSCRIPT_MODULE
5 |
6 | class ModuleMath {
7 | public:
8 | ModuleMath() {
9 | Module math("math");
10 | math.add_command(
11 | {"max",
12 | {
13 | car_ArgumentList
14 | },
15 | [](std::vector args)->GeneralTypeToken {
16 | argument_list alist = tools::parse_argument_list(args[0]);
17 | if(alist.size() != 2) {
18 | throw errors::MWSMessageException{"Too many/few arguments for command: max\n\t- Expected: 2\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
19 | }
20 | auto n1 = tools::check4placeholder(alist[0]);
21 | auto n2 = tools::check4placeholder(alist[1]);
22 |
23 | if(n1.type != General_type::NUMBER) {
24 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n1.type).content,global::get_line()};
25 | }
26 | if(n2.type != General_type::NUMBER) {
27 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n2.type).content,global::get_line()};
28 | }
29 |
30 | return std::max(n1.to_variable().storage.number,n2.to_variable().storage.number);
31 | }}
32 | ).add_command(
33 | {"min",
34 | {
35 | car_ArgumentList
36 | },
37 | [](std::vector args)->GeneralTypeToken {
38 | argument_list alist = tools::parse_argument_list(args[0]);
39 | if(alist.size() != 2) {
40 | throw errors::MWSMessageException{"Too many/few arguments for command: max\n\t- Expected: 2\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
41 | }
42 | auto n1 = tools::check4placeholder(alist[0]);
43 | auto n2 = tools::check4placeholder(alist[1]);
44 |
45 | if(n1.type != General_type::NUMBER) {
46 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n1.type).content,global::get_line()};
47 | }
48 | if(n2.type != General_type::NUMBER) {
49 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n2.type).content,global::get_line()};
50 | }
51 |
52 | return std::min(n1.to_variable().storage.number,n2.to_variable().storage.number);
53 | }}
54 | ).add_command(
55 | {"sqrt",
56 | {
57 | car_Number | car_PlaceHolderAble
58 | },
59 | [](std::vector args)->GeneralTypeToken {
60 | auto v = tools::check4placeholder(args[0]);
61 | if(v.type != General_type::NUMBER) {
62 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
63 | }
64 | return std::sqrt(v.to_variable().storage.number);
65 | }}
66 | ).add_command(
67 | {"floor",
68 | {
69 | car_Number | car_PlaceHolderAble
70 | },
71 | [](std::vector args)->GeneralTypeToken {
72 | auto v = tools::check4placeholder(args[0]);
73 | if(v.type != General_type::NUMBER) {
74 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
75 | }
76 | return std::floor(v.to_variable().storage.number);
77 | }}
78 | ).add_command(
79 | {"ceil",
80 | {
81 | car_Number | car_PlaceHolderAble
82 | },
83 | [](std::vector args)->GeneralTypeToken {
84 | auto v = tools::check4placeholder(args[0]);
85 | if(v.type != General_type::NUMBER) {
86 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
87 | }
88 | return std::ceil(v.to_variable().storage.number);
89 | }}
90 | ).add_command(
91 | {"sin",
92 | {
93 | car_ArgumentList
94 | },
95 | [](std::vector args)->GeneralTypeToken {
96 | auto alist = tools::parse_argument_list(args[0]);
97 | if(alist.size() != 1) {
98 | throw errors::MWSMessageException{"Too many/few arguments for command: sin\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
99 | }
100 | auto n = tools::check4placeholder(alist[1]);
101 |
102 | if(n.type != General_type::NUMBER) {
103 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n.type).content,global::get_line()};
104 | }
105 | return std::sin(args[0].to_variable().storage.number);
106 | }}
107 | ).add_command(
108 | {"cos",
109 | {
110 | car_ArgumentList
111 | },
112 | [](std::vector args)->GeneralTypeToken {
113 | auto alist = tools::parse_argument_list(args[0]);
114 | if(alist.size() != 1) {
115 | throw errors::MWSMessageException{"Too many/few arguments for command: cos\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
116 | }
117 | auto n = tools::check4placeholder(alist[1]);
118 |
119 | if(n.type != General_type::NUMBER) {
120 | throw errors::MWSMessageException{"Wrong argument for argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n.type).content,global::get_line()};
121 | }
122 | return std::cos(args[0].to_variable().storage.number);
123 | }}
124 | ).add_command(
125 | {"tan",
126 | {
127 | car_ArgumentList
128 | },
129 | [](std::vector args)->GeneralTypeToken {
130 | auto alist = tools::parse_argument_list(args[0]);
131 | if(alist.size() != 1) {
132 | throw errors::MWSMessageException{"Too many/few arguments for command: tan\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
133 | }
134 | auto n = tools::check4placeholder(alist[1]);
135 |
136 | if(n.type != General_type::NUMBER) {
137 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(n.type).content,global::get_line()};
138 | }
139 | return std::tan(args[0].to_variable().storage.number);
140 | }}
141 | ).add_command(
142 | {"abs",
143 | {
144 | car_Number | car_PlaceHolderAble
145 | },
146 | [](std::vector args)->GeneralTypeToken {
147 | auto v = tools::check4placeholder(args[0]);
148 | if(v.type != General_type::NUMBER) {
149 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
150 | }
151 | return std::abs(v.to_variable().storage.number);
152 | }}
153 | ).add_command(
154 | {"log10",
155 | {
156 | car_Number | car_PlaceHolderAble
157 | },
158 | [](std::vector args)->GeneralTypeToken {
159 | auto v = tools::check4placeholder(args[0]);
160 | if(v.type != General_type::NUMBER) {
161 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
162 | }
163 | return std::log10(v.to_variable().storage.number);
164 | }}
165 | ).add_command(
166 | {"int",
167 | {
168 | car_Number | car_PlaceHolderAble
169 | },
170 | [](std::vector args)->GeneralTypeToken {
171 | auto v = tools::check4placeholder(args[0]);
172 | if(v.type != General_type::NUMBER) {
173 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
174 | }
175 | return (int)(v.to_variable().storage.number);
176 | }}
177 | ).add_command(
178 | {"round",
179 | {
180 | car_Number | car_PlaceHolderAble,
181 | car_Number | car_PlaceHolderAble
182 | },
183 | [](std::vector args)->GeneralTypeToken {
184 | auto v = tools::check4placeholder(args[0]);
185 | if(v.type != General_type::NUMBER) {
186 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
187 | }
188 | auto rto = tools::check4placeholder(args[1]);
189 | if(rto.type != General_type::NUMBER) {
190 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(rto.type).content,global::get_line()};
191 | }
192 | Variable vv = v.to_variable();
193 | Variable rtov = rto.to_variable().storage.number;
194 | vv.storage.number *= pow(10,rtov.storage.number);
195 | vv.storage.number += 0.5;
196 | vv.storage.number = (int)vv.storage.number;
197 | vv.storage.number /= pow(10,rtov.storage.number);
198 |
199 | return vv.storage.number;
200 | }}
201 | ).add_command(
202 | {"ceil",
203 | {
204 | car_Number | car_PlaceHolderAble,
205 | car_Number | car_PlaceHolderAble
206 | },
207 | [](std::vector args)->GeneralTypeToken {
208 | auto v = tools::check4placeholder(args[0]);
209 | if(v.type != General_type::NUMBER) {
210 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
211 | }
212 | auto rto = tools::check4placeholder(args[1]);
213 | if(rto.type != General_type::NUMBER) {
214 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(rto.type).content,global::get_line()};
215 | }
216 | Variable vv = v.to_variable();
217 | Variable rtov = rto.to_variable().storage.number;
218 | vv.storage.number *= pow(10,rtov.storage.number);
219 | if((int)vv.storage.number*10 % 10 != 0) {
220 | vv.storage.number += 1;
221 | }
222 | vv.storage.number = (int)vv.storage.number;
223 | vv.storage.number /= pow(10,rtov.storage.number);
224 |
225 | return vv.storage.number;
226 | }}
227 | ).add_command(
228 | {"floor",
229 | {
230 | car_Number | car_PlaceHolderAble,
231 | car_Number | car_PlaceHolderAble
232 | },
233 | [](std::vector args)->GeneralTypeToken {
234 | auto v = tools::check4placeholder(args[0]);
235 | if(v.type != General_type::NUMBER) {
236 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(v.type).content,global::get_line()};
237 | }
238 | auto rto = tools::check4placeholder(args[1]);
239 | if(rto.type != General_type::NUMBER) {
240 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(rto.type).content,global::get_line()};
241 | }
242 | Variable vv = v.to_variable();
243 | Variable rtov = rto.to_variable().storage.number;
244 | vv.storage.number *= pow(10,rtov.storage.number);
245 | vv.storage.number = (int)vv.storage.number;
246 | vv.storage.number /= pow(10,rtov.storage.number);
247 |
248 | return vv.storage.number;
249 | }}
250 | );
251 |
252 | math.enabled = false;
253 | add_module(math);
254 | }
255 | }static module_math;
--------------------------------------------------------------------------------
/stdlib/os.cpp:
--------------------------------------------------------------------------------
1 | #include "../inc/meowscript.hpp"
2 | #include
3 | #include
4 | #include
5 |
6 | #ifdef MEOWSCIPT_USE_WINDOWS
7 | #include
8 |
9 | void mw_sleep(int milliseconds) {
10 | Sleep(milliseconds);
11 | }
12 |
13 | void mw_clear() {
14 | system("cls");
15 | }
16 | #elif defined(MEOWSCRIPT_USE_LINUX)
17 | #include
18 |
19 | void mw_sleep(int milliseconds) {
20 | std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
21 | }
22 |
23 | void mw_clear() {
24 | system("clear");
25 | }
26 | #else
27 | void mw_sleep(int milliseconds) {}
28 | void mw_clear() {}
29 | #endif
30 |
31 | MEOWSCRIPT_MODULE
32 |
33 | class ModuleOS {
34 | public:
35 | ModuleOS() {
36 | Module os("os");
37 | os.add_command(
38 | {"rand",
39 | {
40 | car_ArgumentList
41 | },
42 | [](std::vector args)->GeneralTypeToken {
43 | argument_list alist = tools::parse_argument_list(args[0]);
44 | if(alist.size() > 2) {
45 | throw errors::MWSMessageException{"Too many arguments for command: rand\n\t- Expected: <=2\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
46 | }
47 | int max = 0;
48 | int min = 0;
49 |
50 | if(alist.size() > 0 && alist[0].type == General_type::NUMBER) {
51 | max = alist[0].to_variable().storage.number;
52 | }
53 | else if(alist.size() > 0) {
54 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(alist[0].type).content,global::get_line()};
55 | }
56 |
57 | if(alist.size() > 1 && alist[1].type == General_type::NUMBER) {
58 | min = alist[1].to_variable().storage.number;
59 | }
60 | else if(alist.size() > 1) {
61 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(alist[0].type).content,global::get_line()};
62 | }
63 |
64 | if(min > max) {
65 | throw errors::MWSMessageException{"Invalid argument! \"max\" is not allowed to be smaller than \"min\"!",global::get_line()};
66 | }
67 | srand(time(NULL)+rand()*rand()-rand());
68 | int result = 0;
69 | if(max == min) {
70 | return max;
71 | }
72 | if(max == 0)
73 | return (rand() + min);
74 | result = (rand() % (max-min) + min);
75 | if(result > max) {
76 | result = max;
77 | }
78 | return result;
79 |
80 | }}
81 | ).add_command(
82 | {"date",
83 | {
84 | car_ArgumentList
85 | },
86 | [](std::vector args)->GeneralTypeToken {
87 | argument_list alist = tools::parse_argument_list(args[0]);
88 | if(alist.size() != 0) {
89 | throw errors::MWSMessageException{"Too many/few arguments for command: date\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
90 | }
91 | time_t t;
92 | time(&t);
93 | std::string ret = std::asctime(std::localtime(&t));
94 | return ret.substr(0,ret.size()-1); // removes a nasty '\n'
95 | }}
96 | ).add_command(
97 | {"sleep",
98 | {
99 | car_ArgumentList
100 | },
101 | [](std::vector args)->GeneralTypeToken {
102 | argument_list alist = tools::parse_argument_list(args[0]);
103 | if(alist.size() != 1) {
104 | throw errors::MWSMessageException{"Too many/few arguments for command: sleep\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
105 | }
106 | alist[0] = tools::check4placeholder(alist[0]);
107 | if(alist[0].type != General_type::NUMBER) {
108 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(alist[0].type).content,global::get_line()};
109 | }
110 |
111 | mw_sleep(alist[0].to_variable().storage.number);
112 | return general_null;
113 | }}
114 | ).add_command(
115 | {"name",
116 | {
117 | car_ArgumentList
118 | },
119 | [](std::vector args)->GeneralTypeToken {
120 | argument_list alist = tools::parse_argument_list(args[0]);
121 | if(alist.size() != 0) {
122 | throw errors::MWSMessageException{"Too many/few arguments for command: name\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
123 | }
124 | return MEOWSCRIPT_OS_NAME;
125 | }}
126 | ).add_command(
127 | {"exit",
128 | {
129 | car_ArgumentList
130 | },
131 | [](std::vector args)->GeneralTypeToken {
132 | argument_list alist = tools::parse_argument_list(args[0]);
133 | if(alist.size() != 1) {
134 | throw errors::MWSMessageException{"Too many/few arguments for command: exit\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
135 | }
136 | alist[0] = tools::check4placeholder(alist[0]);
137 | if(alist[0].type != General_type::NUMBER) {
138 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: Number\n\t- But got: " + general_t2token(alist[0].type).content,global::get_line()};
139 | }
140 | std::exit(alist[0].to_variable().storage.number);
141 | return general_null;
142 | }}
143 | ).add_command(
144 | {"version",
145 | {
146 | car_ArgumentList
147 | },
148 | [](std::vector args)->GeneralTypeToken {
149 | argument_list alist = tools::parse_argument_list(args[0]);
150 | if(alist.size() != 0) {
151 | throw errors::MWSMessageException{"Too many/few arguments for command: version\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
152 | }
153 | return MEOWSCRIPT_VERSION_STR;
154 | }}
155 | ).add_command(
156 | {"origin_file",
157 | {
158 | car_ArgumentList
159 | },
160 | [](std::vector args)->GeneralTypeToken {
161 | argument_list alist = tools::parse_argument_list(args[0]);
162 | if(alist.size() != 0) {
163 | throw errors::MWSMessageException{"Too many/few arguments for command: origin_file\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
164 | }
165 | return global::origin_file;
166 | }}
167 | ).add_command(
168 | {"main_file",
169 | {
170 | car_ArgumentList
171 | },
172 | [](std::vector args)->GeneralTypeToken {
173 | argument_list alist = tools::parse_argument_list(args[0]);
174 | if(alist.size() != 0) {
175 | throw errors::MWSMessageException{"Too many/few arguments for command: main_file\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
176 | }
177 | return global::origin_file == global::include_path.top().string();
178 | }}
179 | ).add_command(
180 | {"file",
181 | {
182 | car_ArgumentList
183 | },
184 | [](std::vector args)->GeneralTypeToken {
185 | argument_list alist = tools::parse_argument_list(args[0]);
186 | if(alist.size() != 0) {
187 | throw errors::MWSMessageException{"Too many/few arguments for command: file\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
188 | }
189 | return global::include_path.top().string();
190 | }}
191 | ).add_command(
192 | {"clear",
193 | {
194 | car_ArgumentList
195 | },
196 | [](std::vector args)->GeneralTypeToken {
197 | argument_list alist = tools::parse_argument_list(args[0]);
198 | if(alist.size() != 0) {
199 | throw errors::MWSMessageException{"Too many/few arguments for command: clear\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
200 | }
201 | mw_clear();
202 | return general_null;
203 | }}
204 | ).add_command(
205 | {"args",
206 | {
207 | car_ArgumentList
208 | },
209 | [](std::vector args)->GeneralTypeToken {
210 | argument_list alist = tools::parse_argument_list(args[0]);
211 | if(alist.size() != 0) {
212 | throw errors::MWSMessageException{"Too many/few arguments for command: args\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
213 | }
214 | List ret;
215 | ret.elements = global::args;
216 | return ret;
217 | }}
218 | ).add_command(
219 | {"utime",
220 | {
221 | car_ArgumentList
222 | },
223 | [](std::vector args)->GeneralTypeToken {
224 | argument_list alist = tools::parse_argument_list(args[0]);
225 | if(alist.size() != 0) {
226 | throw errors::MWSMessageException{"Too many/few arguments for command: utime\n\t- Expected: 0\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
227 | }
228 |
229 | return std::to_string(time(NULL));
230 | }}
231 | ).add_command(
232 | {"time",
233 | {
234 | car_ArgumentList
235 | },
236 | [](std::vector args)->GeneralTypeToken {
237 | argument_list alist = tools::parse_argument_list(args[0]);
238 | if(alist.size() != 1) {
239 | throw errors::MWSMessageException{"Too many/few arguments for command: time\n\t- Expected: 1\n\t- But got: " + std::to_string(alist.size()) ,global::get_line()};
240 | }
241 | alist[0] = tools::check4placeholder(alist[0]);
242 | if(alist[0].type != General_type::STRING) {
243 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: String\n\t- But got: " + general_t2token(alist[0].type).content,global::get_line()};
244 | }
245 | std::time_t t = std::time(0);
246 | std::tm* now = std::localtime(&t);
247 | if(alist[0].source.content == "hours") {
248 | int ret = now->tm_hour;
249 | return ret;
250 | }
251 | else if(alist[0].source.content == "minutes") {
252 | int ret = now->tm_min;
253 | return ret;
254 | }
255 | else if(alist[0].source.content == "seconds") {
256 | int ret = now->tm_sec;
257 | return ret;
258 | }
259 | else {
260 | throw errors::MWSMessageException{"Invalid argument!\n\t- Expected: [\"hours\",\"minutes\",\"seconds\"]\n\t- But got: " + alist[0].to_string(),global::get_line()};
261 | }
262 | return general_null;
263 | }}
264 | );
265 | os.enabled = false;
266 | add_module(os);
267 | }
268 | }static module_os;
--------------------------------------------------------------------------------