├── .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 | ![Error Loading Image!](./assets/LogoLong.png) 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; --------------------------------------------------------------------------------