├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── Tron.svg ├── errors.md ├── src ├── commands │ ├── bench.rs │ ├── help.rs │ ├── mod.rs │ ├── new.rs │ ├── run.rs │ ├── uninstall.rs │ ├── update.rs │ ├── version.rs │ └── watch.rs ├── environment │ ├── clock_impl.rs │ ├── get_globals.rs │ └── mod.rs ├── interpreter │ ├── expressions.rs │ └── mod.rs ├── library │ ├── .gitignore │ └── mod.rs ├── main.rs ├── parser.rs ├── resolver.rs ├── scanner.rs └── utils │ └── mod.rs ├── versions └── 3.1.0 └── vstron ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .vscodeignore ├── README.md ├── client ├── out │ ├── extension.js │ └── extension.js.map ├── package-lock.json ├── package.json ├── src │ ├── extension.js │ └── extension.ts └── tsconfig.json ├── language-configuration.json ├── package-lock.json ├── package.json ├── server ├── out │ ├── server.js │ └── server.js.map ├── package-lock.json ├── package.json ├── src │ ├── server.js │ └── server.ts └── tsconfig.json ├── syntaxes └── tron.tmLanguage.json ├── tron-lang-2.0.0.vsix ├── tron-lang-3.0.0.vsix ├── tron.png └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /test 3 | /target 4 | /.vscode 5 | /todo.md -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 3.1.0 - Mar 28 2 | 3 | - variable and function type declarations are no longer optional 4 | - removed callbacks 5 | - added function expression (anonymous) 6 | 7 | # 3.0.0 - Mar 24 8 | 9 | ### core changes 10 | 11 | - added objects 12 | - added new types 13 | - added function return types 14 | - added callback functions 15 | - updated internal api 16 | - updated standart library 17 | - updated std function naming (`sin` -> `@sin`) 18 | - updated `and` operator (`&&` -> `&`) 19 | - updated error managment 20 | - removed multiple syntax choices 21 | - removed integer types 22 | - removed multiple variable declaration 23 | - removed `print`, `panic`, `exit`, `bench`, `wait/before` statements 24 | - removed `random`, `cube`, `cubicroot`, `power2`, `root2` operators 25 | - fixed type system 26 | - fixed exact types 27 | 28 | ### other 29 | 30 | - updated extension 31 | - removed documentation 32 | - removed examples 33 | 34 | # 2.8.0 - Feb 22 35 | 36 | ### core changes 37 | 38 | - added `switch` statement (`switch`, `match`, `cases`) 39 | - improved perfonmance 40 | - custom integer/float types 41 | 42 | ### documentation 43 | 44 | - changed documentation structure 45 | - rewrote articles 46 | - added new sections 47 | 48 | ### extension 49 | 50 | - added new keywords 51 | 52 | # 2.7.0 - Feb 14 53 | 54 | ### core changes 55 | 56 | - short function syntax changed (`:` -> `=`) 57 | - added new types: (`integer`, `big integer`) 58 | - fixed type annonations 59 | 60 | ### other changes 61 | 62 | - updated tronlang.org 63 | - updated documentation 64 | 65 | # 2.6.0 - Feb 1 66 | 67 | - if statement can now handle multiple expressions 68 | - else if statement can now handle multiple expressions 69 | - while statement can now handle multiple expressions 70 | - assignent can now handle multiple variables 71 | - variables with uppercase name now will be immutable 72 | - updates now will be released once in two weeks 73 | 74 | # 2.5.0 - Jan 15 75 | 76 | - added type system 77 | - added 5 types: `number`, `string`, `bool`, `null`, `array` 78 | - added type checking for variables and function paramters: 79 | 80 | ``` 81 | let i: number = 0; 82 | // let i = 0; is still valid 83 | 84 | fn sum(x: number , y: number) { 85 | // fn sum(x,y) is still valid 86 | return x + y; 87 | } 88 | ``` 89 | 90 | # 2.4.1 - Jan 14 91 | 92 | - fixed bugs 93 | - new operators: `**`(`**3` = 9) and `&`(`&9` = 3) 94 | - new keywords: 95 | 96 | > - `And` : `&&` 97 | > - `Or`: `||` 98 | > - `Else if`: `??` 99 | > - `multiply`: `times` 100 | > - `>`: `more`, `more than` 101 | > - `<`: `less`, `less than` 102 | > - `/`: `slash` 103 | 104 | - removed `#` keyword for `else if` 105 | 106 | # 2.4.0 - Jan 13 107 | 108 | - added short functions 109 | 110 | ``` 111 | fn main(x) : x + 1; 112 | print main(6); 113 | 114 | // 7 115 | ``` 116 | 117 | - added sleep native: `sleep(time)`: 118 | 119 | ``` 120 | sleep(2000); 121 | 122 | // will create delay for 2s 123 | ``` 124 | 125 | - added ternary native: `ternary(statement, value1, value2):`: 126 | 127 | ``` 128 | let i = 0; 129 | let x = ternary(i > 1, 4, 5); 130 | print x; 131 | 132 | // 5 133 | // if statement is true, return value1, if not: value2 134 | ``` 135 | 136 | - added cmd native: `cmd("command")`: 137 | 138 | ``` 139 | let x = cmd("echo hi"); 140 | print x; 141 | 142 | // "hi" 143 | ``` 144 | 145 | - removed cmd functions 146 | 147 | # 2.3.1 - Jan 13 148 | 149 | - performance improvements 150 | - binary size reduction 151 | - removed external libraries (except rand) 152 | 153 | # 2.3.0 - Jan 12 154 | 155 | - new cli command `tron update` 156 | - added new `wait/before` statement: 157 | 158 | ``` 159 | wait 1000 { 160 | print 1; 161 | } 162 | ``` 163 | 164 | will print 1 after 1000ms delay 165 | 166 | ``` 167 | wait 1000 { 168 | print 1; 169 | } before 200 { 170 | print 0; 171 | } 172 | ``` 173 | 174 | will print 0, with 200ms delay 1000/200 times, and then print 1; 175 | 176 | wait keywords: wait, hold pause 177 | before keywords: before, until, during 178 | 179 | - removed `.` and `:` as end/start 180 | - removed `#` comments 181 | `?>>` elif => `#` 182 | 183 | # 2.2.0 - Jan 11 184 | 185 | - added variable immutability 186 | - removed try/catch statement, input statement and #array library 187 | - numbers changed from f64 to f32 type 188 | - added `then` (start bracket), `as` (assign operator), `exe`(cmd function), `execute`(cmd function), `run`(cmd function), `cmd`(cmd function) 189 | - removed `incr` (increment), `decr`(decrement), `what if`(elif), `whatif`(elif), `dec`(variable), `state`(variable), `respond`(return), `append`(return) 190 | 191 | # 2.1.1 - Jan 11 192 | 193 | - `len()` now returns numbers 194 | - `pow()`, `root()`, `random()`, `min()`, `max()`, `log()`, `log2`, `log10`, `ceil` to math library 195 | - changed output style 196 | - released cmds, `fn name <- ` 197 | 198 | ``` 199 | fn echo <- "ls"; 200 | let response = echo(); 201 | say response; 202 | ``` 203 | 204 | # 2.1.0 - Jan 10 205 | 206 | ### Syntatic Sweetness 207 | 208 | Developers can now choose, which keyword they want to use: 209 | 210 | | name | variants | 211 | | :---------- | :------------------------------------------------------------ | 212 | | function | fn, fun, function, def, define | 213 | | block start | `{`, do, start, doing, begin, `:` | 214 | | block end | `}`, end, done, stop, `.` | 215 | | if | if, `?` | 216 | | else | else, otherwise, if, nor, `?>` | 217 | | elif | else if, elif, what if, whatif, ?>> | 218 | | true | affirmative, true, yes | 219 | | false | negative, false, falsy, no | 220 | | null | null, nil | 221 | | print | print, say, shout, log, out, output, tell | 222 | | input | input, in, inp | 223 | | error | panic, alaram, throw, error, err | 224 | | import | include, import, require, use, payload, unload, lib | 225 | | exit | exit, kill, terminate | 226 | | return | return, respond, append | 227 | | variable | let, var, const, state, declare, dec, `$` | 228 | | while | while, loop | 229 | | bench | bench, test, measure, time | 230 | | plus | plus, `+` | 231 | | minus | minus, `-` | 232 | | multiply | multiply, multiplied by, `*` | 233 | | divide | divide, divided by, `/` | 234 | | assign | `=`, `assign`, `equal`, `equals`, `is`, `are`, `assigned to`, | 235 | | comments | // or # | 236 | 237 | # 2.0.0 - Jan 10 238 | 239 | ## New features 240 | 241 | - libraries 242 | > ability to add external functions 243 | - standart libraries 244 | > use `include "#math"` or `include "#array"` to import math and array native function. 245 | - Tronlang extension is back! 246 | 247 | ## 📝 Changes 248 | 249 | - changed syntax: 250 | 251 | code blocks 252 | 253 | ```rs 254 | // before 255 | 256 | fn greet(){ 257 | print "hi"; 258 | } 259 | 260 | // now 261 | 262 | fn greet() do 263 | print "hi"; 264 | end 265 | ``` 266 | 267 | else if statement 268 | 269 | ```rs 270 | // before 271 | 272 | if smthng { 273 | 274 | } elif smthng { 275 | 276 | } else { 277 | 278 | } 279 | 280 | // now 281 | 282 | if smthng do 283 | 284 | end else if smthng do 285 | 286 | end else do 287 | 288 | end 289 | ``` 290 | 291 | input statement 292 | 293 | ```rs 294 | // before 295 | 296 | in("whats your name"); 297 | 298 | // now 299 | 300 | input("whats your name"); 301 | ``` 302 | 303 | - enchanced interpreter 304 | - optimized statements 305 | - better error handling 306 | 307 | ## 🐛 Fixed 308 | 309 | - Fixed memory issues 310 | - Fixed `include` statement 311 | - Fixed parsing errors 312 | - Fixed error handling errors 313 | - Fixed environment timing errors 314 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "tron-lang" 7 | version = "3.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tron-lang" 3 | version = "3.1.0" 4 | edition = "2021" 5 | authors = ["418e"] 6 | readme= "README.md" 7 | license-file = "LICENSE" 8 | 9 | [dependencies] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2024 418e 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 | # Tron Programming Language 2 | 3 | Statically typed general purpose programming language. 4 | 5 | -------------------------------------------------------------------------------- /Tron.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /errors.md: -------------------------------------------------------------------------------- 1 | ```diff 2 | E0000: System Errors 3 | - E0001: failed to run file 4 | - E0002: failed to run command 5 | - E0003: unsupported platform 6 | E1000: Scanner Errors 7 | - E1001: unterminated string 8 | - E1002: unrecognized character: {character} 9 | - E1003: unsupported character: {character} 10 | - E1004: failed to scan tokens: \n {message} 11 | E2000: Parser Errors 12 | - E2001: failed to parse statements: \n {message} 13 | - E2002: failed to parse block statement 14 | - E2003: unexpected token: {token | message} 15 | - E2004: function can't have more than 32 arguments 16 | - E2005: invalid assignment target 17 | E3000: Resolver Errors 18 | - E3001: failed to resolve {statement_name} statement: incorrect type 19 | - E3002: variable {variable_name} already exists 20 | - E3003: failed to read local variable 21 | - E3004: failed to resolve a variable in a too deep level 22 | - E3005: failed to define a variable in a too deep level 23 | - E3006: return isn't allowed outside of a function 24 | - E3007: break isn't allowed outside of a loop 25 | E4000: Interpreter Errors 26 | - E4001: {function_name}() is expecting {arity} arguments, but got {args.len} 27 | - E4002: {function_name}({arg_name}: {arg_type}) 28 | - E4003: {statement} {name} is expecting {value_type} type, but got {type} 29 | - E4004: failed to execute command: \n {message} 30 | - E4005: failed to find library: {library} 31 | - E4006: failed to make function 32 | - E4007: failed to unwrap {unwraping_value} as {unwrap_target} 33 | - E4008: failed to create type from {invalid_type} 34 | - E4009: array index is out of bounds 35 | - E4010: failed to perform operation on array 36 | - E4011: variable {variable_name} has not been declared 37 | - E4012: immutable variables can't be re-declared 38 | - E4013: failed to call 39 | - E4014: function call argument count doesn't match parameter count 40 | - E4015: {operator} is not implemented for {target} 41 | - E4016: invalid operator: {operator} 42 | - E4017: invalid function output type 43 | - E4018: {function} requires at least {arguments} arguments --- throw 44 | - E4019: {function} requires more than {arguments} arguments --- throw 45 | - E4020: {function} requires exactly {arguments} arguments --- throw 46 | - E4021: {function} expects {type} type as {argument} argument --- throw 47 | ``` 48 | -------------------------------------------------------------------------------- /src/commands/bench.rs: -------------------------------------------------------------------------------- 1 | // run benchmarks 2 | -------------------------------------------------------------------------------- /src/commands/help.rs: -------------------------------------------------------------------------------- 1 | pub fn cli_help() { 2 | println!( 3 | " 4 | \x1B[36mtron\x1B[0m \x1B[32mrun\x1B[0m \x1B[31m\x1B[0m - run tron files 5 | \x1B[36mtron\x1B[0m \x1B[32mversion\x1B[0m - installed version 6 | \x1B[36mtron\x1B[0m \x1B[32mupdate\x1B[0m - install the latest version 7 | 8 | \x1B[36mTron Programming Language (3.1.0)\x1B[0m 9 | " 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod run; 2 | pub mod version; 3 | pub mod update; 4 | pub mod help; 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/commands/new.rs: -------------------------------------------------------------------------------- 1 | // initialize new project -------------------------------------------------------------------------------- /src/commands/run.rs: -------------------------------------------------------------------------------- 1 | use crate::run_file; 2 | use std::{path::PathBuf, process::exit}; 3 | 4 | pub fn cli_run(command: &str, path: PathBuf) { 5 | let path_buf = path.join(command); 6 | let input = path_buf.to_str(); 7 | match input { 8 | Some(input) => match run_file(input) { 9 | Ok(_) => exit(0), 10 | Err(_msg) => { 11 | exit(1); 12 | } 13 | }, 14 | None => { 15 | println!("Error: Non-Unicode file path"); 16 | exit(1); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/commands/uninstall.rs: -------------------------------------------------------------------------------- 1 | // uninstall tron 2 | -------------------------------------------------------------------------------- /src/commands/update.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | pub fn cli_update() { 4 | println!("Updating...."); 5 | let _output = Command::new("bash") 6 | .arg("-c") 7 | .arg("curl -sSL https://tronlang.org/install.sh | bash") 8 | .output() 9 | .expect("Failed to execute command"); 10 | println!("Update completed"); 11 | } 12 | -------------------------------------------------------------------------------- /src/commands/version.rs: -------------------------------------------------------------------------------- 1 | pub fn cli_version() { 2 | println!("v3.1.0"); 3 | } -------------------------------------------------------------------------------- /src/commands/watch.rs: -------------------------------------------------------------------------------- 1 | // listen to the changes 2 | -------------------------------------------------------------------------------- /src/environment/clock_impl.rs: -------------------------------------------------------------------------------- 1 | use crate::expressions::TronType; 2 | 3 | pub fn clock_impl(_args: &Vec) -> TronType { 4 | let now = std::time::SystemTime::now() 5 | .duration_since(std::time::SystemTime::UNIX_EPOCH) 6 | .expect("Could not get system time") 7 | .as_millis(); 8 | println!("{}", now); 9 | TronType::Number(now as f32 / 1000.0) 10 | } 11 | -------------------------------------------------------------------------------- /src/environment/get_globals.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::RefCell, collections::HashMap, rc::Rc}; 2 | 3 | use crate::expressions::{CallableImpl, StdFunctionImpl, TronType}; 4 | 5 | use super::clock_impl; 6 | 7 | pub fn get_globals() -> Rc>> { 8 | let mut env = HashMap::new(); 9 | let fun_impl: StdFunctionImpl = StdFunctionImpl { 10 | name: "clock".to_string(), 11 | arity: 0, 12 | function: Rc::new(clock_impl), 13 | }; 14 | let callable_impl = CallableImpl::StdFunction(fun_impl); 15 | env.insert("clock".to_string(), TronType::Callable(callable_impl)); 16 | Rc::new(RefCell::new(env)) 17 | } 18 | -------------------------------------------------------------------------------- /src/environment/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{expressions::TronType, utils::TronError}; 2 | use std::{cell::RefCell, collections::HashMap, rc::Rc}; 3 | mod clock_impl; 4 | use clock_impl::clock_impl; 5 | mod get_globals; 6 | use get_globals::get_globals; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct Environment { 10 | pub values: Rc>>, 11 | pub value_types: Rc>>, 12 | locals: Rc>>, 13 | pub enclosing: Option>, 14 | } 15 | 16 | impl Environment { 17 | pub fn new(locals: HashMap) -> Self { 18 | Self { 19 | values: get_globals(), 20 | value_types: Rc::new(RefCell::new(HashMap::new())), 21 | locals: Rc::new(RefCell::new(locals)), 22 | enclosing: None, 23 | } 24 | } 25 | pub fn get_value_type(&self, name: &str) -> Option { 26 | self.value_types.borrow().get(name).cloned() 27 | } 28 | pub fn set_value_type(&self, name: String, type_annotation: String) { 29 | self.value_types.borrow_mut().insert(name, type_annotation); 30 | } 31 | pub fn resolve(&self, locals: HashMap) { 32 | for (key, val) in locals.iter() { 33 | self.locals.borrow_mut().insert(*key, *val); 34 | } 35 | } 36 | pub fn enclose(&self) -> Environment { 37 | Self { 38 | values: Rc::new(RefCell::new(HashMap::new())), 39 | value_types: self.value_types.clone(), 40 | locals: self.locals.clone(), 41 | enclosing: Some(Box::new(self.clone())), 42 | } 43 | } 44 | pub fn define(&self, name: String, value: TronType) { 45 | self.values.borrow_mut().insert(name, value); 46 | } 47 | pub fn get(&self, name: &str, expr_id: usize) -> Option { 48 | let distance = self.locals.borrow().get(&expr_id).cloned(); 49 | self.get_internal(name, distance) 50 | } 51 | fn get_internal(&self, name: &str, distance: Option) -> Option { 52 | if distance.is_none() { 53 | match &self.enclosing { 54 | None => self.values.borrow().get(name).cloned(), 55 | Some(env) => env.get_internal(name, distance), 56 | } 57 | } else { 58 | let distance = distance.unwrap(); 59 | if distance == 0 { 60 | self.values.borrow().get(name).cloned() 61 | } else { 62 | match &self.enclosing { 63 | None => { 64 | TronError::throw("E3004", 0, vec![]); 65 | Some(TronType::Null) 66 | } 67 | Some(env) => { 68 | assert!(distance > 0); 69 | env.get_internal(name, Some(distance - 1)) 70 | } 71 | } 72 | } 73 | } 74 | } 75 | pub fn assign(&self, name: &str, value: TronType, expr_id: usize) -> bool { 76 | let distance = self.locals.borrow().get(&expr_id).cloned(); 77 | self.assign_internal(name, value, distance) 78 | } 79 | fn assign_internal(&self, name: &str, value: TronType, distance: Option) -> bool { 80 | if distance.is_none() { 81 | match &self.enclosing { 82 | Some(env) => env.assign_internal(name, value, distance), 83 | None => match self.values.borrow_mut().insert(name.to_string(), value) { 84 | Some(_) => true, 85 | None => false, 86 | }, 87 | } 88 | } else { 89 | let distance = distance.unwrap(); 90 | if distance == 0 { 91 | self.values.borrow_mut().insert(name.to_string(), value); 92 | true 93 | } else { 94 | match &self.enclosing { 95 | None => { 96 | TronError::throw("E3005", 0, vec![]); 97 | false 98 | } 99 | Some(env) => env.assign_internal(name, value, Some(distance - 1)), 100 | }; 101 | true 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/interpreter/expressions.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone)] 2 | pub enum CallableImpl { 3 | Function(FunctionImpl), 4 | StdFunction(StdFunctionImpl), 5 | } 6 | #[derive(Clone, Debug)] 7 | pub struct FunctionImpl { 8 | pub name: String, 9 | pub arity: usize, 10 | pub parent_env: Environment, 11 | pub params: Vec<(Token, Token)>, 12 | pub body: Vec>, 13 | pub output_type: Token, 14 | } 15 | #[derive(Clone)] 16 | pub struct StdFunctionImpl { 17 | pub name: String, 18 | pub arity: usize, 19 | pub function: Rc) -> TronType>, 20 | } 21 | #[derive(Clone)] 22 | 23 | pub struct ObjectImpl { 24 | pub name: String, 25 | pub params: Vec<(Token, Expression)>, 26 | } 27 | 28 | #[derive(Clone)] 29 | pub struct CallbackImpl { 30 | pub id: usize, 31 | pub args: Vec<(Token, Option)>, 32 | pub body: Vec>, 33 | } 34 | 35 | #[derive(Clone)] 36 | 37 | pub enum TronType { 38 | Number(f32), 39 | StringValue(String), 40 | True, 41 | False, 42 | Null, 43 | ArrayValue(Vec), 44 | Callable(CallableImpl), 45 | Object(HashMap), 46 | } 47 | 48 | use std::{ 49 | collections::HashMap, 50 | hash::{Hash, Hasher}, 51 | rc::Rc, 52 | }; 53 | 54 | use TronType::*; 55 | impl std::fmt::Debug for TronType { 56 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 57 | write!(f, "{}", self.to_string()) 58 | } 59 | } 60 | impl PartialEq for TronType { 61 | fn eq(&self, other: &Self) -> bool { 62 | match (self, other) { 63 | (Number(x), Number(y)) => x == y, 64 | ( 65 | Callable(CallableImpl::Function(FunctionImpl { name, arity, .. })), 66 | Callable(CallableImpl::Function(FunctionImpl { 67 | name: name2, 68 | arity: arity2, 69 | .. 70 | })), 71 | ) => name == name2 && arity == arity2, 72 | ( 73 | Callable(CallableImpl::StdFunction(StdFunctionImpl { name, arity, .. })), 74 | Callable(CallableImpl::StdFunction(StdFunctionImpl { 75 | name: name2, 76 | arity: arity2, 77 | .. 78 | })), 79 | ) => name == name2 && arity == arity2, 80 | (StringValue(x), StringValue(y)) => x == y, 81 | (True, True) => true, 82 | (False, False) => true, 83 | (Null, Null) => true, 84 | _ => false, 85 | } 86 | } 87 | } 88 | fn unwrap_as_f64(literal: Option) -> f64 { 89 | match literal { 90 | Some(LiteralValue::NumericValue(x)) => x as f64, 91 | _ => { 92 | TronError::throw("E4007", 0, vec!["uknown".to_string(), "f64".to_string()]); 93 | 0.0 94 | } 95 | } 96 | } 97 | fn unwrap_as_string(literal: Option) -> String { 98 | match literal { 99 | Some(LiteralValue::StringValue(s)) => s.clone(), 100 | _ => { 101 | TronError::throw("E4007", 0, vec!["uknown".to_string(), "string".to_string()]); 102 | "".to_string() 103 | } 104 | } 105 | } 106 | impl TronType { 107 | pub fn to_string(&self) -> String { 108 | match self { 109 | TronType::Object(fields) => { 110 | let fields_str = fields 111 | .iter() 112 | .map(|(key, value)| format!("{}: {}", key, value.to_string())) 113 | .collect::>() 114 | .join(", "); 115 | format!("{{{}}}", fields_str) 116 | } 117 | TronType::Number(x) => x.to_string(), 118 | TronType::ArrayValue(x) => format!("\"{:?}\"", x), 119 | TronType::StringValue(x) => format!("\"{}\"", x), 120 | TronType::True => "true".to_string(), 121 | TronType::False => "false".to_string(), 122 | TronType::Null => "null".to_string(), 123 | TronType::Callable(CallableImpl::Function(FunctionImpl { name, arity, .. })) => { 124 | format!("{name}/{arity}") 125 | } 126 | TronType::Callable(CallableImpl::StdFunction(StdFunctionImpl { 127 | name, arity, .. 128 | })) => format!("{name}/{arity}"), 129 | } 130 | } 131 | pub fn to_type(&self) -> &str { 132 | match self { 133 | TronType::Object(_) => "object", 134 | TronType::Number(_) => "number", 135 | TronType::StringValue(_) => "string", 136 | TronType::ArrayValue(_) => "array", 137 | TronType::True => "boolean", 138 | TronType::False => "boolean", 139 | TronType::Null => "null", 140 | TronType::Callable(_) => "function", 141 | } 142 | } 143 | pub fn from_token(token: Token) -> Self { 144 | match token.token_type { 145 | TokenType::Number => Self::Number(unwrap_as_f64(token.literal) as f32), 146 | TokenType::StringLit => Self::StringValue(unwrap_as_string(token.literal)), 147 | TokenType::False => Self::False, 148 | TokenType::True => Self::True, 149 | TokenType::Null => Self::Null, 150 | _ => { 151 | TronError::throw( 152 | "E001", 153 | 0, 154 | vec![token.token_type.to_string(), "uknown".to_string()], 155 | ); 156 | Self::Null 157 | } 158 | } 159 | } 160 | pub fn from_bool(b: bool) -> Self { 161 | if b { 162 | True 163 | } else { 164 | False 165 | } 166 | } 167 | pub fn is_falsy(&self) -> TronType { 168 | match self { 169 | Object(_) => False, 170 | Number(x) => { 171 | if *x == 0.0 as f32 { 172 | True 173 | } else { 174 | False 175 | } 176 | } 177 | StringValue(s) => { 178 | if s.len() == 0 { 179 | True 180 | } else { 181 | False 182 | } 183 | } 184 | ArrayValue(x) => { 185 | if x.len() == 0 { 186 | True 187 | } else { 188 | False 189 | } 190 | } 191 | True => False, 192 | False => True, 193 | Null => True, 194 | Callable(_) => True, 195 | } 196 | } 197 | pub fn is_truthy(&self) -> TronType { 198 | match self { 199 | Object(_) => True, 200 | Number(x) => { 201 | if *x == 0.0 as f32 { 202 | False 203 | } else { 204 | True 205 | } 206 | } 207 | 208 | StringValue(s) => { 209 | if s.len() == 0 { 210 | False 211 | } else { 212 | True 213 | } 214 | } 215 | ArrayValue(x) => { 216 | if x.len() == 0 { 217 | False 218 | } else { 219 | True 220 | } 221 | } 222 | True => True, 223 | False => False, 224 | Null => False, 225 | Callable(_) => False, 226 | } 227 | } 228 | } 229 | use crate::{scanner::Statement, utils::TronError, Interpreter, LiteralValue, Token, TokenType}; 230 | 231 | use super::Environment; 232 | #[derive(Clone)] 233 | pub enum Expression { 234 | Object { 235 | id: usize, 236 | properties: Vec<(Token, Expression)>, 237 | }, 238 | ObjectCall { 239 | id: usize, 240 | key: Token, 241 | name: Token, 242 | }, 243 | Array { 244 | id: usize, 245 | elements: Vec>, 246 | }, 247 | Assign { 248 | id: usize, 249 | name: Token, 250 | value: Box, 251 | }, 252 | Binary { 253 | id: usize, 254 | left: Box, 255 | operator: Token, 256 | right: Box, 257 | }, 258 | Call { 259 | id: usize, 260 | callee: Box, 261 | paren: Token, 262 | arguments: Vec, 263 | }, 264 | Grouping { 265 | id: usize, 266 | expression: Box, 267 | }, 268 | Literal { 269 | id: usize, 270 | value: TronType, 271 | }, 272 | Logical { 273 | id: usize, 274 | left: Box, 275 | operator: Token, 276 | right: Box, 277 | }, 278 | Unary { 279 | id: usize, 280 | operator: Token, 281 | right: Box, 282 | }, 283 | Variable { 284 | id: usize, 285 | name: Token, 286 | }, 287 | Function { 288 | id: usize, 289 | name: Token, 290 | params: Vec<(Token, Token)>, 291 | body: Vec>, 292 | output_type: Token, 293 | } 294 | } 295 | 296 | impl std::fmt::Debug for Expression { 297 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 298 | write!(f, "{}: {}", self.get_id(), self.to_string()) 299 | } 300 | } 301 | impl Hash for Expression { 302 | fn hash(&self, state: &mut H) { 303 | std::ptr::hash(self, state) 304 | } 305 | } 306 | impl PartialEq for Expression { 307 | fn eq(&self, other: &Self) -> bool { 308 | let ptr = std::ptr::addr_of!(self); 309 | let ptr2 = std::ptr::addr_of!(other); 310 | ptr == ptr2 311 | } 312 | } 313 | impl Eq for Expression {} 314 | impl Expression { 315 | pub fn get_id(&self) -> usize { 316 | match self { 317 | Expression::Function { 318 | id, 319 | name: _, 320 | params: _, 321 | body: _, 322 | output_type: _, 323 | } => *id, 324 | Expression::ObjectCall { 325 | id, 326 | key: _, 327 | name: _, 328 | } => *id, 329 | Expression::Object { id, properties: _ } => *id, 330 | Expression::Array { id, elements: _ } => *id, 331 | Expression::Assign { 332 | id, 333 | name: _, 334 | value: _, 335 | } => *id, 336 | Expression::Binary { 337 | id, 338 | left: _, 339 | operator: _, 340 | right: _, 341 | } => *id, 342 | Expression::Call { 343 | id, 344 | callee: _, 345 | paren: _, 346 | arguments: _, 347 | } => *id, 348 | Expression::Grouping { id, expression: _ } => *id, 349 | Expression::Literal { id, value: _ } => *id, 350 | Expression::Logical { 351 | id, 352 | left: _, 353 | operator: _, 354 | right: _, 355 | } => *id, 356 | Expression::Unary { 357 | id, 358 | operator: _, 359 | right: _, 360 | } => *id, 361 | Expression::Variable { id, name: _ } => *id, 362 | } 363 | } 364 | } 365 | impl Expression { 366 | pub fn to_string(&self) -> String { 367 | match self { 368 | Expression::Function { 369 | id: _, 370 | name, 371 | params, 372 | body: _, 373 | output_type, 374 | } => format!( 375 | "{}({}): {}", 376 | name.lexeme, 377 | params 378 | .iter() 379 | .map(|(name, typ)| format!("{}: {}", name.lexeme, typ.lexeme).to_string()) 380 | .collect::>() 381 | .join(", "), 382 | output_type.lexeme 383 | ), 384 | Expression::Object { id: _, properties } => { 385 | let properties_str = properties 386 | .iter() 387 | .map(|(key, value)| format!("{}: {}", key.lexeme, value.to_string())) 388 | .collect::>() 389 | .join(", "); 390 | format!("{{{}}}", properties_str) 391 | } 392 | Expression::ObjectCall { 393 | id: _, 394 | key, 395 | name: _, 396 | } => format!("{}", key.lexeme), // 397 | Expression::Array { id: _, elements } => { 398 | let elements_str = elements 399 | .iter() 400 | .map(|e| e.to_string()) 401 | .collect::>() 402 | .join(", "); 403 | format!("[{}]", elements_str) 404 | } 405 | Expression::Assign { id: _, name, value } => { 406 | format!("({name:?} = {}", value.to_string()) 407 | } 408 | Expression::Binary { 409 | id: _, 410 | left, 411 | operator, 412 | right, 413 | } => format!( 414 | "({} {} {})", 415 | operator.lexeme, 416 | left.to_string(), 417 | right.to_string() 418 | ), 419 | Expression::Call { 420 | id: _, 421 | callee, 422 | paren: _, 423 | arguments, 424 | } => format!("({} {:?})", (*callee).to_string(), arguments), 425 | Expression::Grouping { id: _, expression } => { 426 | format!("(group {})", (*expression).to_string()) 427 | } 428 | Expression::Literal { id: _, value } => format!("{}", value.to_string()), 429 | Expression::Logical { 430 | id: _, 431 | left, 432 | operator, 433 | right, 434 | } => format!( 435 | "({} {} {})", 436 | operator.to_string(), 437 | left.to_string(), 438 | right.to_string() 439 | ), 440 | Expression::Unary { 441 | id: _, 442 | operator, 443 | right, 444 | } => { 445 | let operator_str = operator.lexeme.clone(); 446 | let right_str = (*right).to_string(); 447 | format!("({}({}))", operator_str, right_str) 448 | } 449 | Expression::Variable { id: _, name } => format!("(let {})", name.lexeme), 450 | } 451 | } 452 | 453 | pub fn evaluate(&self, environment: Environment) -> Result { 454 | match self { 455 | Expression::Function { 456 | id: _, 457 | name, 458 | params, 459 | body, 460 | output_type, 461 | } => { 462 | let function_impl = FunctionImpl { 463 | name: name.clone().lexeme, 464 | arity: params.len(), 465 | parent_env: environment.clone(), 466 | params: params.clone(), 467 | body: body.clone(), 468 | output_type: output_type.clone(), 469 | }; 470 | let callback_env = environment.enclose(); 471 | 472 | let int = Interpreter::with_env(callback_env.clone()); 473 | let callable = int.make_function(&Statement::FunctionStatement { 474 | name: name.clone(), 475 | params: function_impl.clone().params, 476 | body: function_impl.clone().body, 477 | output_type: function_impl.clone().output_type, 478 | line: name.line_number, 479 | }); 480 | let fun = TronType::Callable(CallableImpl::Function(callable)); 481 | environment.define(function_impl.clone().name.clone(), fun); 482 | Ok(TronType::Callable(CallableImpl::Function(function_impl))) 483 | } 484 | Expression::Object { id: _, properties } => { 485 | let mut fields = HashMap::new(); 486 | for (key, value_expr) in properties { 487 | let value = value_expr.evaluate(environment.clone())?; 488 | fields.insert(key.lexeme.clone(), value); 489 | } 490 | Ok(TronType::Object(fields)) 491 | } 492 | Expression::ObjectCall { id, key, name } => { 493 | let object = environment.get(&name.lexeme, *id); 494 | match object { 495 | Some(TronType::Object(fields)) => match fields.get(&key.lexeme) { 496 | Some(value) => Ok(value.clone()), 497 | None => Err(format!("Key '{}' not found in object", key.lexeme)), 498 | }, 499 | _ => Err(format!("'{}' is not an object", key.lexeme)), 500 | } 501 | } 502 | Expression::Array { id: _, elements } => { 503 | if elements.len() == 2 { 504 | let array = elements[0].evaluate(environment.clone())?; 505 | let index = elements[1].evaluate(environment.clone())?; 506 | if let TronType::Number(index_num) = index { 507 | if let TronType::ArrayValue(arr) = array { 508 | let idx = index_num as usize; 509 | return arr.get(idx).cloned().ok_or_else(|| { 510 | TronError::throw("E4009", 0, vec![]); 511 | "".to_string() 512 | }); 513 | } 514 | } 515 | 516 | TronError::throw("E4010", 0, vec![]); 517 | Ok(TronType::Null) 518 | } else { 519 | let mut array_elements = Vec::new(); 520 | for element_expr in elements.iter() { 521 | let evaluated = element_expr.evaluate(environment.clone())?; 522 | array_elements.push(evaluated); 523 | } 524 | Ok(TronType::ArrayValue(array_elements)) 525 | } 526 | } 527 | Expression::Assign { id: _, name, value } => { 528 | if name.lexeme.chars().next().unwrap().is_uppercase() { 529 | TronError::throw("E4012", name.line_number, vec![]); 530 | } 531 | let new_value = (*value).evaluate(environment.clone())?; 532 | let assign_success = 533 | environment.assign(&name.lexeme, new_value.clone(), self.get_id()); 534 | let type_annotation = environment.get_value_type(&name.lexeme); 535 | match type_annotation { 536 | Some(expected_type) => match (expected_type.as_str(), &new_value) { 537 | ("number", TronType::Number(_)) => {} 538 | ("string", TronType::StringValue(_)) => {} 539 | ("array", TronType::ArrayValue(_)) => {} 540 | ("object", TronType::Object(_)) => {} 541 | ("bool", TronType::True) | ("bool", TronType::False) => {} 542 | ("null", TronType::Null) => {} 543 | _ => TronError::throw( 544 | "E4003", 545 | 0, 546 | vec![ 547 | "variable".to_string(), 548 | name.lexeme.to_string(), 549 | expected_type, 550 | new_value.to_type().to_string(), 551 | ], 552 | ), 553 | }, 554 | None => {} 555 | } 556 | if assign_success { 557 | Ok(new_value) 558 | } else { 559 | TronError::throw("E4011", name.line_number, vec![name.lexeme.to_string()]); 560 | Ok(TronType::Null) 561 | } 562 | } 563 | Expression::Call { 564 | id: _, 565 | callee, 566 | paren: _, 567 | arguments, 568 | } => { 569 | let callable: TronType = (*callee).evaluate(environment.clone())?; 570 | match callable { 571 | Callable(CallableImpl::Function(tronfun)) => { 572 | run_tron_function(tronfun, arguments, environment) 573 | } 574 | Callable(CallableImpl::StdFunction(nativefun)) => { 575 | let mut evaluated_arguments = vec![]; 576 | for argument in arguments { 577 | evaluated_arguments.push(argument.evaluate(environment.clone())?); 578 | } 579 | Ok((nativefun.function)(&evaluated_arguments)) 580 | } 581 | _ => { 582 | TronError::throw("E4013", 0, vec![]); 583 | Ok(TronType::Null) 584 | } 585 | } 586 | } 587 | Expression::Variable { id: _, name } => { 588 | let parts: Vec<&str> = name.lexeme.split('.').collect(); 589 | if parts.len() == 2 { 590 | let object_name = parts[0]; 591 | let key = parts[1]; 592 | match environment.get(object_name, self.get_id()) { 593 | Some(TronType::Object(fields)) => match fields.get(key) { 594 | Some(value) => Ok(value.clone()), 595 | None => Err(format!( 596 | "Key '{}' not found in object '{}'", 597 | key, object_name 598 | )), 599 | }, 600 | _ => Err(format!("'{}' is not an object", object_name)), 601 | } 602 | } else { 603 | match environment.get(&name.lexeme, self.get_id()) { 604 | Some(value) => Ok(value.clone()), 605 | None => { 606 | TronError::throw("E4011", name.line_number, vec![name.clone().lexeme]); 607 | Ok(TronType::Null) 608 | } 609 | } 610 | } 611 | } 612 | Expression::Literal { id: _, value } => Ok((*value).clone()), 613 | Expression::Logical { 614 | id: _, 615 | left, 616 | operator, 617 | right, 618 | } => match operator.token_type { 619 | TokenType::Or => { 620 | let lhs_value = left.evaluate(environment.clone())?; 621 | let lhs_true = lhs_value.is_truthy(); 622 | if lhs_true == True { 623 | Ok(lhs_value) 624 | } else { 625 | right.evaluate(environment.clone()) 626 | } 627 | } 628 | TokenType::Xor => { 629 | let lhs_value = left.evaluate(environment.clone())?; 630 | let lhs_true = lhs_value.is_truthy(); 631 | if lhs_true == True { 632 | Ok(False) 633 | } else { 634 | Ok(True) 635 | } 636 | } 637 | TokenType::Nor => { 638 | let lhs_value = left.evaluate(environment.clone())?; 639 | let lhs_true = lhs_value.is_truthy(); 640 | if lhs_true == False { 641 | Ok(True) 642 | } else { 643 | Ok(False) 644 | } 645 | } 646 | TokenType::And => { 647 | let lhs_value = left.evaluate(environment.clone())?; 648 | let lhs_true = lhs_value.is_truthy(); 649 | if lhs_true == False { 650 | Ok(lhs_true) 651 | } else { 652 | right.evaluate(environment.clone()) 653 | } 654 | } 655 | operator => { 656 | TronError::throw("E4016", 0, vec![operator.to_string()]); 657 | Ok(TronType::Null) 658 | } 659 | }, 660 | Expression::Grouping { id: _, expression } => expression.evaluate(environment), 661 | Expression::Unary { 662 | id: _, 663 | operator, 664 | right, 665 | } => { 666 | let right = right.evaluate(environment)?; 667 | match (&right, operator.token_type) { 668 | // minus 669 | (Number(x), TokenType::Minus) => Ok(Number(-x)), 670 | (True, TokenType::Minus) => Ok(False), 671 | (False, TokenType::Minus) => Ok(True), 672 | (e, TokenType::Minus) => { 673 | TronError::throw("E4015", 0, vec!["minus".to_string(), e.to_string()]); 674 | Ok(TronType::Null) 675 | } 676 | (Number(x), TokenType::Increment) => Ok(Number(x + 1.0)), 677 | (Number(x), TokenType::Decrement) => Ok(Number(x - 1.0)), 678 | (e, TokenType::Increment) => { 679 | TronError::throw("E4015", 0, vec!["increment".to_string(), e.to_string()]); 680 | 681 | Ok(TronType::Null) 682 | } 683 | (e, TokenType::Decrement) => { 684 | TronError::throw("E4015", 0, vec!["decrement".to_string(), e.to_string()]); 685 | Ok(TronType::Null) 686 | } 687 | (e, TokenType::Percent) => { 688 | TronError::throw("E4015", 0, vec!["percent".to_string(), e.to_string()]); 689 | Ok(TronType::Null) 690 | } 691 | (any, TokenType::Bang) => Ok(any.is_falsy()), 692 | (e, f) => { 693 | TronError::throw("E4015", 0, vec![f.to_string(), e.to_string()]); 694 | Ok(TronType::Null) 695 | } 696 | } 697 | } 698 | Expression::Binary { 699 | id: _, 700 | left, 701 | operator, 702 | right, 703 | } => { 704 | let left = left.evaluate(environment.clone())?; 705 | let right = right.evaluate(environment.clone())?; 706 | match (&left, operator.token_type, &right) { 707 | (Number(x), TokenType::Plus, Number(y)) => Ok(Number(x + y)), 708 | (StringValue(x), TokenType::Plus, Number(y)) => { 709 | Ok(StringValue(format!("{}{}", x, y.to_string()))) 710 | } 711 | (Number(x), TokenType::Plus, StringValue(y)) => { 712 | Ok(StringValue(format!("{}{}", x.to_string(), y))) 713 | } 714 | (StringValue(x), TokenType::Plus, StringValue(y)) => { 715 | Ok(StringValue(format!("{}{}", x.to_string(), y))) 716 | } 717 | (Number(x), TokenType::Minus, Number(y)) => Ok(Number(x - y)), 718 | (Number(x), TokenType::Star, Number(y)) => Ok(Number(x * y)), 719 | (Number(x), TokenType::Slash, Number(y)) => Ok(Number(x / y)), 720 | (Number(x), TokenType::Greater, Number(y)) => Ok(TronType::from_bool(x > y)), 721 | (StringValue(x), TokenType::Greater, StringValue(y)) => { 722 | Ok(TronType::from_bool(x.len() > y.len())) 723 | } 724 | (Number(x), TokenType::GreaterEqual, Number(y)) => { 725 | Ok(TronType::from_bool(x >= y)) 726 | } 727 | (StringValue(x), TokenType::GreaterEqual, StringValue(y)) => { 728 | Ok(TronType::from_bool(x.len() >= y.len())) 729 | } 730 | (Number(x), TokenType::Less, Number(y)) => Ok(TronType::from_bool(x < y)), 731 | (StringValue(x), TokenType::Less, StringValue(y)) => { 732 | Ok(TronType::from_bool(x.len() < y.len())) 733 | } 734 | (Number(x), TokenType::LessEqual, Number(y)) => Ok(TronType::from_bool(x <= y)), 735 | (StringValue(x), TokenType::LessEqual, StringValue(y)) => { 736 | Ok(TronType::from_bool(x.len() <= y.len())) 737 | } 738 | (StringValue(_), e, Number(_)) => { 739 | TronError::throw( 740 | "E4015", 741 | 0, 742 | vec!["string and number".to_string(), e.to_string()], 743 | ); 744 | Ok(TronType::Null) 745 | } 746 | (Number(_), e, StringValue(_)) => { 747 | TronError::throw( 748 | "E4015", 749 | 0, 750 | vec!["number and string".to_string(), e.to_string()], 751 | ); 752 | Ok(TronType::Null) 753 | } 754 | (x, TokenType::BangEqual, y) => Ok(TronType::from_bool(x != y)), 755 | (x, TokenType::EqualEqual, y) => Ok(TronType::from_bool(x == y)), 756 | (f, e, c) => { 757 | TronError::throw( 758 | "E4015", 759 | 0, 760 | vec![ 761 | format!("{} and {}", f.to_string(), c.to_string()).to_string(), 762 | e.to_string(), 763 | ], 764 | ); 765 | Ok(TronType::Null) 766 | } 767 | } 768 | } 769 | } 770 | } 771 | } 772 | pub fn run_tron_function( 773 | tronfun: FunctionImpl, 774 | arguments: &Vec, 775 | eval_env: Environment, 776 | ) -> Result { 777 | if arguments.len() != tronfun.arity { 778 | return Err(format!( 779 | "Callable {} expected {} arguments but got {}", 780 | tronfun.name, 781 | tronfun.arity, 782 | arguments.len() 783 | )); 784 | } 785 | let mut arg_vals = vec![]; 786 | for arg in arguments { 787 | let val = arg.evaluate(eval_env.clone())?; 788 | arg_vals.push(val); 789 | } 790 | let fun_env = tronfun.parent_env.enclose(); 791 | for (i, val) in arg_vals.iter().enumerate() { 792 | if i < tronfun.params.len() { 793 | let (param_name_token, param_type_token) = &tronfun.params[i]; 794 | let param_name_lexeme = ¶m_name_token.lexeme; 795 | 796 | let param_type_lexeme = ¶m_type_token.lexeme; 797 | 798 | match (param_type_lexeme.as_str(), val) { 799 | ("number", TronType::Number(_)) => {} 800 | ("string", TronType::StringValue(_)) => {} 801 | ("array", TronType::ArrayValue(_)) => {} 802 | ("object", TronType::Object(_)) => {} 803 | ("bool", TronType::True) | ("bool", TronType::False) => {} 804 | ("null", TronType::Null) => {} 805 | _ => { 806 | TronError::throw( 807 | "E4002", 808 | 0, 809 | vec![ 810 | tronfun.name.to_string(), 811 | param_name_lexeme.to_string(), 812 | val.to_type().to_string(), 813 | param_type_lexeme.to_string(), 814 | ], 815 | ); 816 | } 817 | } 818 | 819 | fun_env.define(param_name_lexeme.clone(), val.clone()); 820 | } else { 821 | TronError::throw("E4014", 0, vec![]); 822 | } 823 | } 824 | let mut int = Interpreter::with_env(fun_env); 825 | for stmt in tronfun.body.iter() { 826 | let result = int.interpret(vec![stmt.as_ref()]); 827 | if let Err(_e) = result { 828 | TronError::throw("E4006", 0, vec![]); 829 | } else if let Some(value) = int.specials.get("return") { 830 | let output_type_lexeme = &tronfun.output_type.lexeme; 831 | let value_clone = value.clone(); 832 | let value_clone_type = value_clone.to_type(); 833 | let value_clone_string = value_clone.to_string(); 834 | if !(output_type_lexeme == value_clone_type 835 | || output_type_lexeme.clone() == value_clone_string) 836 | { 837 | TronError::throw("E4017", 0, vec![]); 838 | } 839 | return Ok(value.clone()); 840 | } 841 | } 842 | 843 | let output_type_lexeme = &tronfun.output_type.lexeme; 844 | if output_type_lexeme != "null" { 845 | TronError::throw("E4017", 0, vec![]); 846 | } 847 | 848 | Ok(TronType::Null) 849 | } 850 | -------------------------------------------------------------------------------- /src/interpreter/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::environment::*; 2 | use crate::expressions::*; 3 | use crate::library::standard_library; 4 | use crate::parser::*; 5 | use crate::resolver::*; 6 | use crate::scanner::*; 7 | use crate::utils::TronError; 8 | use std::collections::HashMap; 9 | pub mod expressions; 10 | 11 | #[derive(Debug)] 12 | pub struct Interpreter { 13 | pub specials: HashMap, 14 | pub environment: Environment, 15 | } 16 | 17 | impl Interpreter { 18 | pub fn new() -> Self { 19 | let mut interpreter = Self { 20 | specials: HashMap::new(), 21 | environment: Environment::new(HashMap::new()), 22 | }; 23 | standard_library(&mut interpreter.environment); 24 | 25 | interpreter 26 | } 27 | pub fn resolve(&mut self, locals: HashMap) { 28 | self.environment.resolve(locals); 29 | } 30 | pub fn with_env(env: Environment) -> Self { 31 | Self { 32 | specials: HashMap::new(), 33 | environment: env, 34 | } 35 | } 36 | pub fn interpret(&mut self, stmts: Vec<&Statement>) -> Result<(), String> { 37 | for stmt in stmts { 38 | match stmt { 39 | Statement::ExpressionStatement { 40 | expression, 41 | line: _, 42 | } => { 43 | expression.evaluate(self.environment.clone())?; 44 | } 45 | Statement::UseStatement { expression, line } => { 46 | let value = expression.evaluate(self.environment.clone())?; 47 | let path = std::env::current_dir().unwrap(); 48 | let path_buf = 49 | path.join(value.to_string().trim_matches('"').trim_start_matches('/')); 50 | match value.to_string().as_str() { 51 | // "\"#math\"" => include_math_natives(&mut self.environment), 52 | _ => { 53 | if std::path::Path::new(&path_buf).exists() { 54 | let lib_contents = std::fs::read_to_string(&path_buf) 55 | .map_err(|e| e.to_string())?; 56 | self.execute_lib(&lib_contents)?; 57 | } else { 58 | TronError::throw("E4005", *line, vec![value.to_string()]); 59 | } 60 | } 61 | } 62 | } 63 | Statement::VariableStatement { 64 | name, 65 | value_type: _, 66 | value, 67 | line: _, 68 | } => { 69 | let value = value.evaluate(self.environment.clone())?; 70 | let value_clone = value.clone(); 71 | self.environment.define(name.lexeme.clone(), value_clone); 72 | } 73 | Statement::BlockStatement { 74 | statements, 75 | line: _, 76 | } => { 77 | let new_environment = self.environment.enclose(); 78 | let old_environment = self.environment.clone(); 79 | self.environment = new_environment; 80 | let block_result = 81 | self.interpret((*statements).iter().map(|b| b.as_ref()).collect()); 82 | self.environment = old_environment; 83 | block_result?; 84 | } 85 | Statement::IfStatement { 86 | conditions, 87 | then_branch, 88 | elif_branches, 89 | else_branch, 90 | line: _, 91 | } => { 92 | let mut all_true = true; 93 | for condition in conditions { 94 | let truth_value = condition.evaluate(self.environment.clone())?; 95 | if truth_value.is_truthy() != TronType::True { 96 | all_true = false; 97 | break; 98 | } 99 | } 100 | if all_true { 101 | self.interpret(vec![then_branch.as_ref()])?; 102 | } else { 103 | let mut executed_branch = false; 104 | for (elif_predicates, elif_stmt) in elif_branches { 105 | let mut all_true = true; 106 | for elif_predicate in elif_predicates { 107 | let elif_truth_value = 108 | elif_predicate.evaluate(self.environment.clone())?; 109 | if elif_truth_value.is_truthy() != TronType::True { 110 | all_true = false; 111 | break; 112 | } 113 | } 114 | if all_true { 115 | self.interpret(vec![elif_stmt.as_ref()])?; 116 | executed_branch = true; 117 | break; 118 | } 119 | } 120 | if !executed_branch { 121 | if let Some(els_stmt) = else_branch { 122 | self.interpret(vec![els_stmt.as_ref()])?; 123 | } 124 | } 125 | } 126 | } 127 | Statement::WhileStatement { 128 | conditions, 129 | body, 130 | line: _, 131 | } => { 132 | let mut all_true = true; 133 | for condition in conditions { 134 | let truth_value = condition.evaluate(self.environment.clone())?; 135 | if truth_value.is_truthy() != TronType::True { 136 | all_true = false; 137 | break; 138 | } 139 | } 140 | while all_true { 141 | self.interpret(vec![body.as_ref()])?; 142 | all_true = true; 143 | for condition in conditions { 144 | let truth_value = condition.evaluate(self.environment.clone())?; 145 | if truth_value.is_truthy() != TronType::True { 146 | all_true = false; 147 | break; 148 | } 149 | } 150 | } 151 | } 152 | Statement::FunctionStatement { 153 | name, 154 | params: _, 155 | body: _, 156 | output_type: _, 157 | line: _, 158 | } => { 159 | let callable = self.make_function(stmt); 160 | let fun = TronType::Callable(CallableImpl::Function(callable)); 161 | self.environment.define(name.lexeme.clone(), fun); 162 | } 163 | Statement::ReturnStatement { 164 | keyword: _, 165 | value, 166 | line: _, 167 | } => { 168 | let eval_val; 169 | if let Some(value) = value { 170 | eval_val = value.evaluate(self.environment.clone())?; 171 | } else { 172 | eval_val = TronType::Null; 173 | } 174 | self.specials.insert("return".to_string(), eval_val); 175 | } 176 | Statement::BreakStatement { .. } => { 177 | return Err("break".to_string()); 178 | } 179 | Statement::SwitchStatement { 180 | condition, 181 | case_branches, 182 | default_branch, 183 | line: _, 184 | } => { 185 | let condition_value = condition.evaluate(self.environment.clone())?; 186 | let mut executed = false; 187 | for (case_value, case_body) in case_branches { 188 | let case_value = case_value.evaluate(self.environment.clone())?; 189 | if condition_value == case_value { 190 | self.interpret(case_body.iter().collect())?; 191 | executed = true; 192 | break; 193 | } 194 | } 195 | if !executed && default_branch.is_some() { 196 | self.interpret(default_branch.as_ref().unwrap().iter().collect())?; 197 | } 198 | } 199 | }; 200 | } 201 | Ok(()) 202 | } 203 | fn make_function(&self, fn_stmt: &Statement) -> FunctionImpl { 204 | if let Statement::FunctionStatement { 205 | name, 206 | params, 207 | body, 208 | output_type, 209 | line: _, 210 | } = fn_stmt 211 | { 212 | let arity = params.len(); 213 | let params: Vec<(Token, Token)> = params 214 | .iter() 215 | .map(|(name, type_token)| (name.clone(), type_token.clone())) 216 | .collect(); 217 | let body: Vec> = body.iter().map(|b| (*b).clone()).collect(); 218 | let name_clone = name.lexeme.clone(); 219 | let output_type_clone = output_type.clone(); 220 | let parent_env = self.environment.clone(); 221 | let callable_impl = FunctionImpl { 222 | name: name_clone, 223 | arity, 224 | parent_env, 225 | params, 226 | body, 227 | output_type: output_type_clone, 228 | }; 229 | callable_impl 230 | } else { 231 | TronError::throw("E4006", 0, vec![]); 232 | FunctionImpl { 233 | name: "err".to_string(), 234 | arity: 0, 235 | parent_env: self.environment.clone(), 236 | params: vec![], 237 | body: vec![], 238 | output_type: Token { 239 | token_type: TokenType::Null, 240 | lexeme: "".to_string(), 241 | literal: None, 242 | line_number: 0, 243 | }, 244 | } 245 | } 246 | } 247 | fn execute_lib(&mut self, lib_contents: &str) -> Result<(), String> { 248 | let scanner = Scanner::new(lib_contents); 249 | let tokens = scanner.scan_tokens().map_err(|e| e.to_string())?; 250 | let mut parser = Parser::new(tokens); 251 | let stmts = parser.parse().map_err(|e| e.to_string())?; 252 | let stmts_refs: Vec<&Statement> = stmts.iter().collect(); 253 | let resolver = Resolver::new(); 254 | let locals = resolver.resolve(&stmts.iter().collect(), &mut self.environment)?; 255 | self.resolve(locals); 256 | self.interpret(stmts_refs) 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/library/.gitignore: -------------------------------------------------------------------------------- 1 | # reserved for future updates 2 | /time 3 | /test 4 | /sync 5 | /string 6 | /process 7 | /os 8 | /object 9 | /number 10 | /null 11 | /network 12 | /memory 13 | /io 14 | /fs 15 | /error 16 | /convert 17 | /boolean 18 | /array -------------------------------------------------------------------------------- /src/library/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::environment::*; 2 | use crate::expressions::*; 3 | use crate::panic; 4 | use crate::utils::TronError; 5 | use std::io as std_io; 6 | use std::process::exit; 7 | use std::process::Command; 8 | use std::rc::Rc; 9 | 10 | pub fn declare_function( 11 | name: String, 12 | args: usize, 13 | fun: impl Fn(&Vec) -> TronType + 'static, 14 | environment: &mut Environment, 15 | ) { 16 | environment.define( 17 | name.clone(), 18 | TronType::Callable(CallableImpl::StdFunction(StdFunctionImpl { 19 | name: name.clone(), 20 | arity: args, 21 | function: Rc::new(fun), 22 | })), 23 | ) 24 | } 25 | 26 | pub fn standard_library(environment: &mut Environment) { 27 | declare_function( 28 | "@print".to_string(), 29 | 1, 30 | |args: &Vec| { 31 | if args.len() > 0 { 32 | for arg in args { 33 | println!("{:?}", arg); 34 | } 35 | } else { 36 | println!(""); 37 | } 38 | TronType::Null 39 | }, 40 | environment, 41 | ); 42 | declare_function( 43 | "@panic".to_string(), 44 | 1, 45 | |args: &Vec| -> TronType { 46 | if args.len() > 0 { 47 | for arg in args { 48 | eprintln!("\x1B[31m{:?}\x1B[0m \n", arg); 49 | } 50 | } else { 51 | exit(1); 52 | } 53 | TronType::Null 54 | }, 55 | environment, 56 | ); 57 | declare_function( 58 | "@shift".to_string(), 59 | 1, 60 | |args: &Vec| -> TronType { 61 | if args.len() == 1 { 62 | if let TronType::ArrayValue(arr) = &args[0] { 63 | let mut arr = arr.clone(); 64 | if arr.is_empty() { 65 | return TronType::ArrayValue(arr); 66 | } 67 | arr.remove(0); 68 | TronType::ArrayValue(arr) 69 | } else { 70 | TronError::throw( 71 | "E4021", 72 | 0, 73 | vec![ 74 | "@shift".to_string(), 75 | "array".to_string(), 76 | "first".to_string(), 77 | ], 78 | ); 79 | exit(1) 80 | } 81 | } else { 82 | TronError::throw("E4018", 0, vec!["@shift".to_string(), 1.to_string()]); 83 | exit(1); 84 | } 85 | }, 86 | environment, 87 | ); 88 | declare_function( 89 | "@pop".to_string(), 90 | 1, 91 | |args: &Vec| -> TronType { 92 | if args.len() == 1 { 93 | if let TronType::ArrayValue(arr) = &args[0] { 94 | let mut arr = arr.clone(); 95 | if arr.is_empty() { 96 | return TronType::ArrayValue(arr); 97 | } 98 | arr.pop(); 99 | TronType::ArrayValue(arr) 100 | } else { 101 | TronError::throw( 102 | "E4021", 103 | 0, 104 | vec!["@pop".to_string(), "array".to_string(), "first".to_string()], 105 | ); 106 | exit(1) 107 | } 108 | } else { 109 | TronError::throw("E4018", 0, vec!["@pop".to_string(), 1.to_string()]); 110 | exit(1); 111 | } 112 | }, 113 | environment, 114 | ); 115 | declare_function( 116 | "@join".to_string(), 117 | 2, 118 | |args: &Vec| -> TronType { 119 | if args.len() == 2 { 120 | match (&args[0], &args[1]) { 121 | (TronType::ArrayValue(arr), TronType::StringValue(join_str)) => { 122 | let mut strings = Vec::new(); 123 | for val in arr.iter() { 124 | match val { 125 | TronType::Number(num) => strings.push(num.to_string()), 126 | TronType::StringValue(s) => strings.push(s.clone()), 127 | _ => panic("\n join() requires an array of strings or numbers"), 128 | } 129 | } 130 | let joined = strings.join(join_str); 131 | 132 | TronType::StringValue(joined) 133 | } 134 | _ => { 135 | TronError::throw( 136 | "E4021", 137 | 0, 138 | vec![ 139 | "@join".to_string(), 140 | "array".to_string(), 141 | "first".to_string(), 142 | ], 143 | ); 144 | exit(1) 145 | } 146 | } 147 | } else { 148 | TronError::throw("E4018", 0, vec!["@join".to_string(), 2.to_string()]); 149 | exit(1); 150 | } 151 | }, 152 | environment, 153 | ); 154 | 155 | declare_function( 156 | "@push".to_string(), 157 | 2, 158 | |args: &Vec| -> TronType { 159 | if args.len() == 2 { 160 | match &args[0] { 161 | TronType::ArrayValue(arr) => { 162 | let mut arr = arr.clone(); 163 | arr.push(args[1].clone()); 164 | TronType::ArrayValue(arr) 165 | } 166 | _ => { 167 | TronError::throw( 168 | "E4021", 169 | 0, 170 | vec![ 171 | "@push".to_string(), 172 | "array".to_string(), 173 | "first".to_string(), 174 | ], 175 | ); 176 | exit(1) 177 | } 178 | } 179 | } else { 180 | TronError::throw("E4018", 0, vec!["@push".to_string(), 2.to_string()]); 181 | exit(1); 182 | } 183 | }, 184 | environment, 185 | ); 186 | declare_function( 187 | "@length".to_string(), 188 | 1, 189 | |args: &Vec| -> TronType { 190 | if args.len() == 1 { 191 | match &args[0] { 192 | TronType::StringValue(n) => TronType::Number(n.len() as f32), 193 | TronType::ArrayValue(n) => TronType::Number(n.len() as f32), 194 | _ => { 195 | TronError::throw( 196 | "E4021", 197 | 0, 198 | vec![ 199 | "@length".to_string(), 200 | "array or string".to_string(), 201 | "first".to_string(), 202 | ], 203 | ); 204 | exit(1) 205 | } 206 | } 207 | } else { 208 | TronError::throw("E4018", 0, vec!["@length".to_string(), 1.to_string()]); 209 | exit(1); 210 | } 211 | }, 212 | environment, 213 | ); 214 | declare_function( 215 | "@ask".to_string(), 216 | 1, 217 | |args: &Vec| -> TronType { 218 | if args.len() == 1 { 219 | match &args[0] { 220 | TronType::StringValue(n) => { 221 | println!("{}", n.to_string()); 222 | let mut input = String::new(); 223 | std_io::stdin().read_line(&mut input).unwrap(); 224 | TronType::StringValue(format!("{}", input)) 225 | } 226 | _ => { 227 | TronError::throw( 228 | "E4021", 229 | 0, 230 | vec![ 231 | "@ask".to_string(), 232 | "string".to_string(), 233 | "first".to_string(), 234 | ], 235 | ); 236 | exit(1) 237 | } 238 | } 239 | } else { 240 | TronError::throw("E4018", 0, vec!["@ask".to_string(), 1.to_string()]); 241 | exit(1); 242 | } 243 | }, 244 | environment, 245 | ); 246 | 247 | declare_function( 248 | "@typeof".to_string(), 249 | 1, 250 | |args: &Vec| -> TronType { 251 | if args.len() == 1 { 252 | TronType::StringValue(args[0].to_type().to_string()) 253 | } else { 254 | TronError::throw("E4018", 0, vec!["@typeof".to_string(), 1.to_string()]); 255 | exit(1); 256 | } 257 | }, 258 | environment, 259 | ); 260 | 261 | declare_function( 262 | "@if".to_string(), 263 | 3, 264 | |args: &Vec| -> TronType { 265 | if args.len() == 3 { 266 | match &args[0] { 267 | TronType::True => args[1].clone(), 268 | TronType::False => args[2].clone(), 269 | _ => { 270 | TronError::throw( 271 | "E4021", 272 | 0, 273 | vec![ 274 | "@if".to_string(), 275 | "boolean".to_string(), 276 | "first".to_string(), 277 | ], 278 | ); 279 | exit(1) 280 | } 281 | } 282 | } else { 283 | TronError::throw("E4018", 0, vec!["@if".to_string(), 3.to_string()]); 284 | exit(1); 285 | } 286 | }, 287 | environment, 288 | ); 289 | 290 | declare_function( 291 | "@sleep".to_string(), 292 | 1, 293 | |args: &Vec| -> TronType { 294 | if args.len() == 1 { 295 | match &args[0] { 296 | TronType::Number(time) => { 297 | std::thread::sleep(std::time::Duration::from_millis(*time as u64)); 298 | TronType::Number(*time) 299 | } 300 | _ => { 301 | TronError::throw( 302 | "E4021", 303 | 0, 304 | vec![ 305 | "@sleep".to_string(), 306 | "number".to_string(), 307 | "first".to_string(), 308 | ], 309 | ); 310 | exit(1) 311 | } 312 | } 313 | } else { 314 | TronError::throw("E4018", 0, vec!["@sleep".to_string(), 1.to_string()]); 315 | exit(1); 316 | } 317 | }, 318 | environment, 319 | ); 320 | declare_function( 321 | "@cmd".to_string(), 322 | 1, 323 | |args: &Vec| -> TronType { 324 | if args.len() == 1 { 325 | match &args[0] { 326 | TronType::StringValue(command) => { 327 | let output = Command::new("sh").arg("-c").arg(command).output(); 328 | match output { 329 | Ok(output) => { 330 | if output.status.success() { 331 | let stdout = String::from_utf8_lossy(&output.stdout); 332 | TronType::StringValue(stdout.to_string()) 333 | } else { 334 | let stderr = String::from_utf8_lossy(&output.stderr); 335 | TronError::throw("E4004", 0, vec![stderr.to_string()]); 336 | exit(1) 337 | } 338 | } 339 | Err(error) => { 340 | TronError::throw("E4004", 0, vec![error.to_string()]); 341 | exit(1) 342 | } 343 | } 344 | } 345 | _ => { 346 | TronError::throw( 347 | "E4021", 348 | 0, 349 | vec![ 350 | "@cmd".to_string(), 351 | "string".to_string(), 352 | "first".to_string(), 353 | ], 354 | ); 355 | exit(1) 356 | } 357 | } 358 | } else { 359 | TronError::throw("E4018", 0, vec!["@cmd".to_string(), 1.to_string()]); 360 | exit(1); 361 | } 362 | }, 363 | environment, 364 | ); 365 | 366 | declare_function( 367 | "@sin".to_string(), 368 | 1, 369 | |args: &Vec| -> TronType { 370 | if args.len() == 1 { 371 | match &args[0] { 372 | TronType::Number(angle) => TronType::Number(angle.to_radians().sin()), 373 | _ => { 374 | TronError::throw( 375 | "E4021", 376 | 0, 377 | vec![ 378 | "@sin".to_string(), 379 | "number".to_string(), 380 | "first".to_string(), 381 | ], 382 | ); 383 | exit(1) 384 | } 385 | } 386 | } else { 387 | TronError::throw("E4018", 0, vec!["@sin".to_string(), 1.to_string()]); 388 | exit(1); 389 | } 390 | }, 391 | environment, 392 | ); 393 | 394 | declare_function( 395 | "@cos".to_string(), 396 | 1, 397 | |args: &Vec| -> TronType { 398 | if args.len() == 1 { 399 | match &args[0] { 400 | TronType::Number(angle) => TronType::Number(angle.to_radians().cos()), 401 | _ => { 402 | TronError::throw( 403 | "E4021", 404 | 0, 405 | vec![ 406 | "@cos".to_string(), 407 | "number".to_string(), 408 | "first".to_string(), 409 | ], 410 | ); 411 | exit(1) 412 | } 413 | } 414 | } else { 415 | TronError::throw("E4018", 0, vec!["@cos".to_string(), 1.to_string()]); 416 | exit(1); 417 | } 418 | }, 419 | environment, 420 | ); 421 | 422 | declare_function( 423 | "@tan".to_string(), 424 | 1, 425 | |args: &Vec| -> TronType { 426 | if args.len() == 1 { 427 | match &args[0] { 428 | TronType::Number(angle) => TronType::Number(angle.to_radians().tan()), 429 | _ => { 430 | TronError::throw( 431 | "E4021", 432 | 0, 433 | vec![ 434 | "@tan".to_string(), 435 | "number".to_string(), 436 | "first".to_string(), 437 | ], 438 | ); 439 | exit(1) 440 | } 441 | } 442 | } else { 443 | TronError::throw("E4018", 0, vec!["@tan".to_string(), 1.to_string()]); 444 | exit(1); 445 | } 446 | }, 447 | environment, 448 | ); 449 | 450 | declare_function( 451 | "@round".to_string(), 452 | 1, 453 | |args: &Vec| -> TronType { 454 | if args.len() == 1 { 455 | match &args[0] { 456 | TronType::Number(angle) => TronType::Number(angle.round()), 457 | _ => { 458 | TronError::throw( 459 | "E4021", 460 | 0, 461 | vec![ 462 | "@round".to_string(), 463 | "number".to_string(), 464 | "first".to_string(), 465 | ], 466 | ); 467 | exit(1) 468 | } 469 | } 470 | } else { 471 | TronError::throw("E4018", 0, vec!["@round".to_string(), 1.to_string()]); 472 | exit(1); 473 | } 474 | }, 475 | environment, 476 | ); 477 | declare_function( 478 | "@floor".to_string(), 479 | 1, 480 | |args: &Vec| -> TronType { 481 | if args.len() == 1 { 482 | match &args[0] { 483 | TronType::Number(angle) => TronType::Number(angle.floor()), 484 | _ => { 485 | TronError::throw( 486 | "E4021", 487 | 0, 488 | vec![ 489 | "@floor".to_string(), 490 | "number".to_string(), 491 | "first".to_string(), 492 | ], 493 | ); 494 | exit(1) 495 | } 496 | } 497 | } else { 498 | TronError::throw("E4018", 0, vec!["@floor".to_string(), 1.to_string()]); 499 | exit(1); 500 | } 501 | }, 502 | environment, 503 | ); 504 | 505 | declare_function( 506 | "@ceil".to_string(), 507 | 1, 508 | |args: &Vec| -> TronType { 509 | if args.len() == 1 { 510 | match &args[0] { 511 | TronType::Number(angle) => TronType::Number(angle.ceil()), 512 | _ => { 513 | TronError::throw( 514 | "E4021", 515 | 0, 516 | vec![ 517 | "@ceil".to_string(), 518 | "number".to_string(), 519 | "first".to_string(), 520 | ], 521 | ); 522 | exit(1) 523 | } 524 | } 525 | } else { 526 | TronError::throw("E4018", 0, vec!["@ceil".to_string(), 1.to_string()]); 527 | exit(1); 528 | } 529 | }, 530 | environment, 531 | ); 532 | declare_function( 533 | "@pow".to_string(), 534 | 2, 535 | |args: &Vec| -> TronType { 536 | if args.len() == 2 { 537 | match (&args[0], &args[1]) { 538 | (TronType::Number(base), TronType::Number(exp)) => { 539 | TronType::Number(base.powf(*exp)) 540 | } 541 | _ => { 542 | TronError::throw( 543 | "E4021", 544 | 0, 545 | vec!["@pow".to_string(), "number".to_string(), "both".to_string()], 546 | ); 547 | exit(1) 548 | } 549 | } 550 | } else { 551 | TronError::throw("E4018", 0, vec!["@pow".to_string(), 2.to_string()]); 552 | exit(1); 553 | } 554 | }, 555 | environment, 556 | ); 557 | 558 | declare_function( 559 | "@root".to_string(), 560 | 2, 561 | |args: &Vec| -> TronType { 562 | if args.len() == 2 { 563 | match (&args[0], &args[1]) { 564 | (TronType::Number(number), TronType::Number(n)) => { 565 | TronType::Number(number.powf(1.0 / n)) 566 | } 567 | _ => { 568 | TronError::throw( 569 | "E4021", 570 | 0, 571 | vec![ 572 | "@root".to_string(), 573 | "number".to_string(), 574 | "both".to_string(), 575 | ], 576 | ); 577 | exit(1) 578 | } 579 | } 580 | } else { 581 | TronError::throw("E4018", 0, vec!["@root".to_string(), 2.to_string()]); 582 | exit(1); 583 | } 584 | }, 585 | environment, 586 | ); 587 | } 588 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod commands; 2 | mod environment; 3 | mod interpreter; 4 | mod library; 5 | mod parser; 6 | mod resolver; 7 | mod scanner; 8 | mod utils; 9 | use crate::commands::help::cli_help; 10 | use crate::commands::run::cli_run; 11 | use crate::commands::update::cli_update; 12 | use crate::commands::version::cli_version; 13 | use crate::{interpreter::*, parser::*, resolver::*, scanner::*}; 14 | use std::{env, fs, process::exit}; 15 | use utils::TronError; 16 | 17 | pub fn panic(message: &str) { 18 | eprintln!("\x1B[31m{}\x1B[0m \n", message); 19 | exit(1); 20 | } 21 | 22 | pub fn run_file(path: &str) -> Result<(), String> { 23 | let current_dir = std::env::current_dir().unwrap(); 24 | match fs::read_to_string(¤t_dir.join(path).to_str().unwrap().to_string()) { 25 | Err(_msg) => { 26 | TronError::throw("E0001", 0, vec![]); 27 | Ok(()) 28 | } 29 | Ok(contents) => run(&contents), 30 | } 31 | } 32 | 33 | fn run(contents: &str) -> Result<(), String> { 34 | let mut interpreter = Interpreter::new(); 35 | let scanner = Scanner::new(contents); 36 | let tokens = scanner.scan_tokens()?; 37 | let mut parser = Parser::new(tokens); 38 | let stmts = parser.parse()?; 39 | let resolver = Resolver::new(); 40 | let locals = resolver.resolve(&stmts.iter().collect(), &mut interpreter.environment)?; 41 | interpreter.resolve(locals); 42 | interpreter.interpret(stmts.iter().collect())?; 43 | Ok(()) 44 | } 45 | 46 | fn main() { 47 | let args: Vec = env::args().collect(); 48 | let path = std::env::current_dir().unwrap(); 49 | if args.len() == 1 { 50 | TronError::throw("E0002", 0, vec![]); 51 | exit(64); 52 | } 53 | let command = args[1].as_str(); 54 | match command { 55 | "version" => cli_version(), 56 | "update" => cli_update(), 57 | "help" => cli_help(), 58 | "run" => cli_run(args[2].as_str(), path), 59 | _ => TronError::throw("E0002", 0, vec![]), 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/resolver.rs: -------------------------------------------------------------------------------- 1 | use crate::environment::Environment; 2 | use crate::expressions::Expression; 3 | use crate::scanner::{Statement, Token}; 4 | use crate::utils::TronError; 5 | use std::collections::HashMap; 6 | 7 | #[derive(Copy, Clone, PartialEq, Debug)] 8 | enum FunctionType { 9 | None, 10 | Function, 11 | } 12 | #[derive(Copy, Clone, PartialEq, Debug)] 13 | enum LoopType { 14 | None, 15 | } 16 | /// The `Resolver` struct in Rust is responsible for resolving symbols. 17 | /// It maintains a stack of scopes, tracks the current function and loop context, and manages local variables. 18 | /// 19 | /// # Fields 20 | /// 21 | /// - `scopes`: A stack of scopes, where each scope is a `HashMap` mapping variable names to a boolean indicating if the variable is initialized. 22 | /// - `current_function`: The type of the current function being resolved. 23 | /// - `current_loop`: The type of the current loop being resolved. 24 | /// - `locals`: A map of local variable IDs to their scope depth. 25 | /// 26 | /// # Usage 27 | /// 28 | /// The `Resolver` struct is used to resolve symbols in the Tron language. It is typically instantiated with the `new` method and then used to resolve statements and expressions within a given environment. 29 | /// 30 | /// # Example 31 | /// 32 | /// ``` 33 | /// let mut Resolver::new(); 34 | /// let mut environment = Environment::new(); 35 | /// let statements = vec![/* ... */]; 36 | /// let result = resolver.resolve(&statements, &mut environment); 37 | /// ``` 38 | /// 39 | /// ### Last Updated: (v3.0.0) 40 | #[derive(Debug, Clone)] 41 | pub struct Resolver { 42 | scopes: Vec>, 43 | current_function: FunctionType, 44 | current_loop: LoopType, 45 | locals: HashMap, 46 | } 47 | impl Resolver { 48 | /// The `new()` function is a constructor for the `Resolver` struct. 49 | /// 50 | /// It initializes the `Resolver` with an empty stack of scopes, a `None` current function, a `None` current loop, and an empty map of locals. 51 | /// 52 | /// # Return Value 53 | /// 54 | /// A new instance of the `Resolver` struct. 55 | /// 56 | /// # Usage 57 | /// 58 | /// The `new()` function is typically called when you want to create a new `Resolver` to resolve symbols in the Tron language. 59 | /// 60 | /// # Example 61 | /// 62 | /// ``` 63 | /// let resolver = Resolver::new(); 64 | /// ``` 65 | /// 66 | /// ### Last Updated: (v3.0.0) 67 | pub fn new() -> Self { 68 | Self { 69 | scopes: vec![], 70 | current_function: FunctionType::None, 71 | current_loop: LoopType::None, 72 | locals: HashMap::new(), 73 | } 74 | } 75 | /// Resolves a single statement within the given environment. 76 | /// 77 | /// This method is responsible for handling various types of statements, including blocks, variable declarations, function declarations, expressions, and control flow statements like if, while, and switch. It recursively resolves nested statements and expressions, ensuring that all symbols are correctly resolved within the current scope. 78 | /// 79 | /// # Parameters 80 | /// 81 | /// - `stmt`: A reference to the statement to be resolved. 82 | /// - `environment`: A mutable reference to the environment in which the statement is being resolved. 83 | /// 84 | /// # Returns 85 | /// 86 | /// - `Result<(), String>`: Returns `Ok(())` if the statement is successfully resolved, or an error message if resolution fails. 87 | /// 88 | /// # Examples 89 | /// 90 | /// ``` 91 | /// let mut resolver = Resolver::new(); 92 | /// let mut environment = Environment::new(); 93 | /// let statement = Statement::VariableStatement 94 | /// ``` 95 | /// 96 | /// # Panics 97 | /// 98 | /// - Panics if a return statement is encountered outside of a function context. 99 | /// - Panics if a break statement is encountered outside of a loop context. 100 | /// - Panics if a variable is declared with a mismatched type. 101 | /// 102 | /// ### Last Updated: (v3.0.0) 103 | fn resolve_internal( 104 | &mut self, 105 | stmt: &Statement, 106 | environment: &mut Environment, 107 | ) -> Result<(), String> { 108 | match stmt { 109 | Statement::BlockStatement { 110 | statements: _, 111 | line, 112 | } => self.resolve_block(stmt, environment, *line)?, 113 | Statement::VariableStatement { 114 | name: _, 115 | value_type: _, 116 | value: _, 117 | line, 118 | } => self.resolve_var(stmt, environment, *line)?, 119 | Statement::FunctionStatement { 120 | name: _, 121 | params: _, 122 | body: _, 123 | output_type: _, 124 | line: _, 125 | } => self.resolve_function(stmt, FunctionType::Function, environment)?, 126 | Statement::ExpressionStatement { expression, line } => { 127 | self.resolve_expr(expression, *line, environment)? 128 | } 129 | Statement::IfStatement { 130 | conditions: _, 131 | then_branch: _, 132 | elif_branches: _, 133 | else_branch: _, 134 | line, 135 | } => self.resolve_if_stmt(stmt, environment, *line)?, 136 | Statement::UseStatement { expression, line } => { 137 | self.resolve_expr(expression, *line, environment)? 138 | } 139 | Statement::ReturnStatement { 140 | keyword: _, 141 | value, 142 | line, 143 | } => { 144 | if self.current_function == FunctionType::None { 145 | TronError::throw("E3006", *line, vec![]); 146 | } else if let Some(value) = value { 147 | self.resolve_expr(value, *line, environment)?; 148 | } 149 | } 150 | Statement::WhileStatement { 151 | conditions, 152 | body, 153 | line, 154 | } => { 155 | for condition in conditions { 156 | self.resolve_expr(condition, *line, environment)?; 157 | } 158 | self.resolve_internal(body.as_ref(), environment)?; 159 | } 160 | Statement::BreakStatement { keyword: _, line } => { 161 | if self.current_loop == LoopType::None { 162 | TronError::throw("E3007", *line, vec![]); 163 | } 164 | } 165 | Statement::SwitchStatement { 166 | condition, 167 | case_branches, 168 | default_branch, 169 | line, 170 | } => { 171 | self.resolve_expr(condition, *line, environment)?; 172 | for case_branch in case_branches { 173 | for branch in case_branch.1.clone() { 174 | self.resolve_internal(&branch, environment)?; 175 | } 176 | } 177 | if let Some(default_branch) = default_branch { 178 | for branch in default_branch { 179 | self.resolve_internal(&branch, environment)?; 180 | } 181 | } 182 | } 183 | } 184 | Ok(()) 185 | } 186 | /// Resolves a collection of statements within the given environment. 187 | /// 188 | /// This method iterates over a collection of statements and resolves each one using the `resolve_internal` method. It's designed to handle multiple statements in sequence, ensuring that all symbols within the statements are correctly resolved within the current scope. 189 | /// 190 | /// # Parameters 191 | /// 192 | /// - `stmts`: A reference to a vector of statements to be resolved. 193 | /// - `environment`: A mutable reference to the environment in which the statements are being resolved. 194 | /// 195 | /// # Returns 196 | /// 197 | /// - `Result<(), String>`: Returns `Ok(())` if all statements are successfully resolved, or an error message if resolution fails for any statement. 198 | /// 199 | /// # Examples 200 | /// 201 | /// ``` 202 | /// let mut resolver = Resolver::new(); 203 | /// let mut environment = Evnrionment::new(); 204 | /// let statements = vec![/* ... */]; 205 | /// resolver.resolve_many(&statements, &mut environment)?; 206 | /// ``` 207 | /// 208 | /// ### Last Updated: (v3.0.0) 209 | fn resolve_many( 210 | &mut self, 211 | stmts: &Vec<&Statement>, 212 | environment: &mut Environment, 213 | ) -> Result<(), String> { 214 | for stmt in stmts { 215 | self.resolve_internal(stmt, environment)?; 216 | } 217 | Ok(()) 218 | } 219 | /// Resolves a collection of statements within the given environment and returns a map of local variable IDs to their scope depth. 220 | /// 221 | /// This method is a wrapper around `resolve_many` that also returns the `locals` map of the `Resolver` instance. It's designed to resolve multiple statements in sequence and then provide information about the local variables that were resolved. 222 | /// 223 | /// # Parameters 224 | /// 225 | /// - `stmts`: A reference to a vector of statements to be resolved. 226 | /// - `environment`: A mutable reference to the environment in which the statements are being resolved. 227 | /// 228 | /// # Returns 229 | /// 230 | /// - `Result, String>`: Returns a `HashMap` mapping local variable IDs to their scope depth if all statements are successfully resolved, or an error message if resolution fails for any statement. 231 | /// 232 | /// # Examples 233 | /// 234 | /// ``` 235 | /// let mut resolver = Resolve::new(); 236 | /// let mut environment = Environment::new(); 237 | /// let statements = vec![/* ... */]; 238 | /// let result = resolver.resolve(&statements, &mut environment)?; 239 | /// ``` 240 | /// 241 | /// ### Last Updated: (v3.0.0) 242 | pub fn resolve( 243 | mut self, 244 | stmts: &Vec<&Statement>, 245 | environment: &mut Environment, 246 | ) -> Result, String> { 247 | self.resolve_many(stmts, environment)?; 248 | Ok(self.locals) 249 | } 250 | /// Resolves a block statement within the given environment. 251 | /// 252 | /// This method is responsible for handling block statements, which are essentially a collection of statements enclosed within curly braces `{}`. It begins a new scope for the block, resolves all statements within the block, and then ends the scope. This ensures that any variables declared within the block are properly scoped and do not leak into the surrounding environment. 253 | /// 254 | /// # Parameters 255 | /// 256 | /// - `stmt`: A reference to the block statement to be resolved. 257 | /// - `environment`: A mutable reference to the environment in which the block statement is being resolved. 258 | /// 259 | /// # Returns 260 | /// 261 | /// - `Result<(), String>`: Returns `Ok(())` if the block statement is successfully resolved, or an error message if resolution fails. 262 | /// 263 | /// # Examples 264 | /// 265 | /// ``` 266 | /// let mut resolver = Resolver::new(); 267 | /// let mut environment = Environment::new(); 268 | /// let block_statement = Statement::BlockStatement { 269 | /// statements: vec![/* ... */] 270 | /// }; 271 | /// resolver.resolve_block(&block_statement, &mut environment)?; 272 | /// ``` 273 | /// 274 | /// 275 | /// # Panics 276 | /// 277 | /// - Panics if the provided statement is not a block statement. 278 | /// 279 | /// ### Last Updated: (v3.0.0) 280 | fn resolve_block( 281 | &mut self, 282 | stmt: &Statement, 283 | environment: &mut Environment, 284 | line: usize, 285 | ) -> Result<(), String> { 286 | match stmt { 287 | Statement::BlockStatement { 288 | statements, 289 | line: _, 290 | } => { 291 | self.begin_scope(); 292 | self.resolve_many( 293 | &statements.iter().map(|b| b.as_ref()).collect(), 294 | environment, 295 | )?; 296 | self.end_scope(); 297 | } 298 | _ => TronError::throw("E3001", line, vec!["block".to_string()]), 299 | } 300 | Ok(()) 301 | } 302 | /// Resolves a variable declaration statement within the given environment. 303 | /// 304 | /// This method is responsible for handling variable declarations. It declares the variable in the current scope, checks for type mismatches if a type is specified, and then defines the variable. This ensures that variables are correctly declared and initialized within the current scope. 305 | /// 306 | /// # Parameters 307 | /// 308 | /// - `stmt`: A reference to the variable declaration statement to be resolved. 309 | /// - `environment`: A mutable reference to the environment in which the variable declaration is being resolved. 310 | /// 311 | /// # Returns 312 | /// 313 | /// - `Result<(), String>`: Returns `Ok(())` if the variable declaration is successfully resolved, or an error message if resolution fails. 314 | /// 315 | /// # Examples 316 | /// 317 | /// ``` 318 | /// let mut resolver = Resolver::new(); 319 | /// let mut environment = Environment::new(); 320 | /// let variable_statement = Statement::VariableStatement {/* ... */}; 321 | /// resolver.resolve_var(&variable_statement, &mut environment)?; 322 | /// ``` 323 | /// 324 | /// # Panics 325 | /// 326 | /// - Panics if the provided statement is not a variable declaration statement. 327 | /// - Panics if a variable is declared with a mismatched type. 328 | /// 329 | /// ### Last Updated: (v3.0.0) 330 | fn resolve_var( 331 | &mut self, 332 | stmt: &Statement, 333 | environment: &mut Environment, 334 | line: usize, 335 | ) -> Result<(), String> { 336 | if let Statement::VariableStatement { 337 | name, 338 | value_type, 339 | value, 340 | line, 341 | } = stmt 342 | { 343 | self.declare(name)?; 344 | let new_value = (*value).evaluate(environment.clone())?; 345 | let value_clone = new_value.clone(); 346 | 347 | if value_type.lexeme == value_clone.to_type() 348 | || value_type.lexeme == value_clone.to_string() 349 | { 350 | environment.set_value_type(name.lexeme.clone(), value_type.lexeme.clone()); 351 | } else { 352 | TronError::throw( 353 | "E4003", 354 | *line, 355 | vec![ 356 | "variable".to_string(), 357 | name.lexeme.to_string(), 358 | value_type.lexeme.to_string(), 359 | value_clone.to_type().to_string(), 360 | ], 361 | ); 362 | } 363 | self.resolve_expr(value, *line, environment)?; 364 | self.define(name); 365 | } else { 366 | TronError::throw("E3001", line, vec!["variable".to_string()]); 367 | } 368 | Ok(()) 369 | } 370 | /// Resolves a function declaration statement within the given environment. 371 | /// 372 | /// This method is responsible for handling function declarations. It declares the function in the current scope, checks for type mismatches if a type is specified, and then defines the function. This ensures that functions are correctly declared and initialized within the current scope. 373 | /// 374 | /// # Parameters 375 | /// 376 | /// - `stmt`: A reference to the function declaration statement to be resolved. 377 | /// - `resolving_function`: The type of the function being resolved. 378 | /// - `environment`: A mutable reference to the environment in which the function declaration is being resolved. 379 | /// 380 | /// # Returns 381 | /// 382 | /// - `Result<(), String>`: Returns `Ok(())` if the function declaration is successfully resolved, or an error message if resolution fails. 383 | /// 384 | /// # Examples 385 | /// 386 | /// ``` 387 | /// let mut resolver = Resolver::new(); 388 | /// let mut environment = Environment::new(); 389 | /// let function_statement = Statement::FunctionStatement {/* ... */}; 390 | /// resolver.resolve_function(&function_statement, FunctionType::Function, &mut environment)?; 391 | /// ``` 392 | /// 393 | /// # Panics 394 | /// 395 | /// - Panics if the provided statement is not a function declaration statement. 396 | /// 397 | /// ### Last Updated: (v3.0.0) 398 | fn resolve_function( 399 | &mut self, 400 | stmt: &Statement, 401 | resolving_function: FunctionType, 402 | environment: &mut Environment, 403 | ) -> Result<(), String> { 404 | if let Statement::FunctionStatement { 405 | name: _, 406 | params, 407 | body, 408 | output_type: _, 409 | line: _, 410 | } = stmt 411 | { 412 | let enclosing_function = self.current_function; 413 | self.current_function = resolving_function; 414 | self.begin_scope(); 415 | for (param_name, _param_type) in params { 416 | self.declare(param_name)?; 417 | self.define(param_name); 418 | } 419 | self.resolve_many(&body.iter().map(|b| b.as_ref()).collect(), environment)?; 420 | self.end_scope(); 421 | self.current_function = enclosing_function; 422 | Ok(()) 423 | } else { 424 | panic!("resolve_function called with non-function statement"); 425 | } 426 | } 427 | /// Resolves an if statement within the given environment. 428 | /// 429 | /// This method is responsible for handling if statements, which are conditional branches in the code. It resolves the conditions and the branches of the if statement, ensuring that all symbols within the branches are correctly resolved within the current scope. 430 | /// 431 | /// # Parameters 432 | /// 433 | /// - `stmt`: A reference to the if statement to be resolved. 434 | /// - `environment`: A mutable reference to the environment in which the if statement is being resolved. 435 | /// 436 | /// # Returns 437 | /// 438 | /// - `Result<(), String>`: Returns `Ok(())` if the if statement is successfully resolved, or an error message if resolution fails. 439 | /// 440 | /// # Examples 441 | /// 442 | /// ``` 443 | /// let mut resolver = Resolve::new(); 444 | /// let mut environment = Statement:IfStatement {/* ... */}; 445 | /// resolver.resolve_if_stmt(&if_statement, &mut environment)?; 446 | /// ``` 447 | /// 448 | /// # Panics 449 | /// 450 | /// - Panics if the provided statement is not an if statement. 451 | /// 452 | /// ### Last Updated: (v3.0.0) 453 | fn resolve_if_stmt( 454 | &mut self, 455 | stmt: &Statement, 456 | environment: &mut Environment, 457 | line: usize, 458 | ) -> Result<(), String> { 459 | if let Statement::IfStatement { 460 | conditions, 461 | then_branch: then, 462 | elif_branches, 463 | else_branch: els, 464 | line, 465 | } = stmt 466 | { 467 | for condition in conditions { 468 | self.resolve_expr(condition, *line, environment)?; 469 | } 470 | self.resolve_internal(then.as_ref(), environment)?; 471 | for (elif_predicates, elif_stmt) in elif_branches { 472 | for elif_predicate in elif_predicates { 473 | self.resolve_expr(elif_predicate, *line, environment)?; 474 | } 475 | self.resolve_internal(elif_stmt.as_ref(), environment)?; 476 | } 477 | if let Some(els) = els { 478 | self.resolve_internal(els.as_ref(), environment)?; 479 | } 480 | Ok(()) 481 | } else { 482 | TronError::throw("E3001", line, vec!["if".to_string()]); 483 | Ok(()) 484 | } 485 | } 486 | /// Begins a new scope for variable resolution. 487 | /// 488 | /// This method is called to start a new scope, which is typically used when entering a block of code. It pushes a new `HashMap` onto the `scopes` stack to track variables declared within this scope. 489 | /// 490 | /// # Examples 491 | /// 492 | /// ``` 493 | /// let mut resolver = Resolver::new(); 494 | /// resolver.begin_scope(); 495 | /// ``` 496 | /// 497 | /// ### Last Updated: (v3.0.0) 498 | fn begin_scope(&mut self) { 499 | self.scopes.push(HashMap::new()); 500 | } 501 | /// Ends the current scope for variable resolution. 502 | /// 503 | /// This method is called to end the current scope, which is typically used when exiting a block of code. It pops the last `HashMap` from the `scopes` stack, effectively closing the scope and making any variables declared within it inaccessible. 504 | /// 505 | /// # Examples 506 | /// 507 | /// ``` 508 | /// let mut resolver = Resolver::new(); 509 | /// resolver.begin_scope(); 510 | /// // ... resolve statements within the scope ... 511 | /// resolver.end_scope(); 512 | /// ``` 513 | /// 514 | /// ### Last Updated: (v3.0.0) 515 | fn end_scope(&mut self) { 516 | self.scopes.pop().expect("Stack underflow"); 517 | } 518 | /// Declares a variable in the current scope. 519 | /// 520 | /// This method is used to declare a variable in the current scope. It checks if the variable is already declared in the current scope and panics if it is. Otherwise, it adds the variable to the current scope's `HashMap`. 521 | /// 522 | /// # Parameters 523 | /// 524 | /// - `name`: The token representing the variable name to be declared. 525 | /// 526 | /// # Returns 527 | /// 528 | /// - `Result<(), String>`: Returns `Ok(())` if the variable is successfully declared, or an error message if the variable is already declared in the current scope. 529 | /// 530 | /// # Examples 531 | /// 532 | /// ``` 533 | /// let mut resolver = Resolver::new(); 534 | /// let variable_name = Token::new(TokenType::identifier, "testVar", None, 1); 535 | /// resolver.declare(&variable_name)?; 536 | /// ``` 537 | /// 538 | /// # Panics 539 | /// 540 | /// - Panics if a variable with the same name is already declared in the current scope. 541 | /// 542 | /// ### Last Updated: (v3.0.0) 543 | fn declare(&mut self, name: &Token) -> Result<(), String> { 544 | let size = self.scopes.len(); 545 | if self.scopes.is_empty() { 546 | return Ok(()); 547 | } else if self.scopes[size - 1].contains_key(&name.lexeme.clone()) { 548 | TronError::throw("E3004", name.line_number, vec![]); 549 | } 550 | self.scopes[size - 1].insert(name.lexeme.clone(), false); 551 | Ok(()) 552 | } 553 | /// Defines a variable in the current scope. 554 | /// 555 | /// This method is used to define a variable in the current scope after it has been declared. It marks the variable as initialized in the current scope's `HashMap`. 556 | /// 557 | /// # Parameters 558 | /// 559 | /// - `name`: The token representing the variable name to be defined. 560 | /// 561 | /// # Examples 562 | /// 563 | /// ``` 564 | /// let mut resolver = Resolver::new(); 565 | /// let variable_name = TokenType::Identifier, "testVar", None, 1); 566 | /// resolver.declare(&variable_name)?; 567 | /// resolver.define(&variable_name); 568 | /// ``` 569 | /// 570 | /// ### Last Updated: (v3.0.0) 571 | fn define(&mut self, name: &Token) { 572 | if self.scopes.is_empty() { 573 | return; 574 | } 575 | let size = self.scopes.len(); 576 | self.scopes[size - 1].insert(name.lexeme.clone(), true); 577 | } 578 | /// Resolves an expression within the given environment. 579 | /// 580 | /// This method is responsible for handling various types of expressions, including literals, variables, binary operations, unary operations, and function calls. It recursively resolves nested expressions, ensuring that all symbols are correctly resolved within the current scope. 581 | /// 582 | /// # Parameters 583 | /// 584 | /// - `expr`: A reference to the expression to be resolved. 585 | /// 586 | /// # Returns 587 | /// 588 | /// - `Result<(), String>`: Returns `Ok(())` if the expression is successfully resolved, or an error message if resolution fails. 589 | /// 590 | /// # Examples 591 | /// 592 | /// ``` 593 | /// let mut resolver = Resolver::new(); 594 | /// let mut environment = Environment::new(); 595 | /// let expression = Expressiion::Variable {id : 0, name: Token::new(TokenTYpe::Identifier, "testVar", None, 1)}; 596 | /// resolver.resolve_expr(&expression)?; 597 | /// ``` 598 | /// 599 | /// ### Last Updated: (v3.0.0) 600 | fn resolve_expr( 601 | &mut self, 602 | expr: &Expression, 603 | line: usize, 604 | environment: &mut Environment, 605 | ) -> Result<(), String> { 606 | match expr { 607 | Expression::Function { 608 | id: _, 609 | name: _, 610 | params, 611 | body, 612 | output_type: _, 613 | } => { 614 | let enclosing_function = self.current_function; 615 | self.current_function = FunctionType::Function; 616 | self.begin_scope(); 617 | for (param_name, _param_type) in params { 618 | self.declare(param_name)?; 619 | self.define(param_name); 620 | } 621 | self.resolve_many(&body.iter().map(|b| b.as_ref()).collect(), environment)?; 622 | self.end_scope(); 623 | self.current_function = enclosing_function; 624 | Ok(()) 625 | } 626 | Expression::Object { id: _, properties } => { 627 | for (_, value_expr) in properties { 628 | self.resolve_expr(value_expr, line, environment)?; 629 | } 630 | Ok(()) 631 | } 632 | Expression::ObjectCall { 633 | id: _, 634 | key: _, 635 | name: _, 636 | } => Ok(()), // 637 | Expression::Variable { id: _, name: _ } => { 638 | self.resolve_expr_var(expr, expr.get_id(), line) 639 | } 640 | Expression::Assign { 641 | id: _, 642 | name: _, 643 | value: _, 644 | } => self.resolve_expr_assign(expr, expr.get_id(), line, environment), 645 | Expression::Array { id: _, elements } => { 646 | for element in elements { 647 | self.resolve_expr(element, line, environment)?; 648 | } 649 | Ok(()) 650 | } 651 | Expression::Binary { 652 | id: _, 653 | left, 654 | operator: _, 655 | right, 656 | } => { 657 | self.resolve_expr(left, line, environment)?; 658 | self.resolve_expr(right, line, environment) 659 | } 660 | Expression::Call { 661 | id: _, 662 | callee, 663 | paren: _, 664 | arguments, 665 | } => { 666 | self.resolve_expr(callee.as_ref(), line, environment)?; 667 | for arg in arguments { 668 | self.resolve_expr(arg, line, environment)?; 669 | } 670 | Ok(()) 671 | } 672 | Expression::Grouping { id: _, expression } => { 673 | self.resolve_expr(expression, line, environment) 674 | } 675 | Expression::Literal { id: _, value: _ } => Ok(()), 676 | Expression::Logical { 677 | id: _, 678 | left, 679 | operator: _, 680 | right, 681 | } => { 682 | self.resolve_expr(left, line, environment)?; 683 | self.resolve_expr(right, line, environment) 684 | } 685 | Expression::Unary { 686 | id: _, 687 | operator: _, 688 | right, 689 | } => self.resolve_expr(right, line, environment), 690 | } 691 | } 692 | /// Resolves a variable expression within the given environment. 693 | /// 694 | /// This method is used to resolve a variable expression, ensuring that the variable is declared and initialized in the current scope. It also handles the resolution of function calls where the callee is a variable. 695 | /// 696 | /// # Parameters 697 | /// 698 | /// - `expr`: A reference to the expression to be resolved. 699 | /// - `resolve_id`: The ID of the expression to be resolved. 700 | /// 701 | /// # Returns 702 | /// 703 | /// - `Result<(), String>`: Returns `Ok(())` if the variable expression is successfully resolved, or an error message if resolution fails. 704 | /// 705 | /// # Examples 706 | /// 707 | /// ``` 708 | /// let mut resolver = Resolver::new(); 709 | /// let mut environment = Environment::new(); 710 | /// let variable_expression = Expressiion::Variable {id : 0, name: Token::new(TokenTYpe::Identifier, "testVar", None, 1)}; 711 | /// resolver.resolve_expr_var(&variable_expression, variable_expression.get_id())?; 712 | /// ``` 713 | /// 714 | /// # Panics 715 | /// 716 | /// - Panics if the provided expression is not a variable expression or a function call with a variable callee. 717 | /// 718 | /// ### Last Updated: (v3.0.0) 719 | fn resolve_expr_var( 720 | &mut self, 721 | expr: &Expression, 722 | resolve_id: usize, 723 | line: usize, 724 | ) -> Result<(), String> { 725 | match expr { 726 | Expression::Variable { id: _, name } => { 727 | if !self.scopes.is_empty() { 728 | if let Some(false) = self.scopes[self.scopes.len() - 1].get(&name.lexeme) { 729 | TronError::throw("E3003", name.line_number, vec![]); 730 | } 731 | } 732 | self.resolve_local(name, resolve_id) 733 | } 734 | Expression::Call { 735 | id: _, 736 | callee, 737 | paren: _, 738 | arguments: _, 739 | } => match callee.as_ref() { 740 | Expression::Variable { id: _, name } => self.resolve_local(&name, resolve_id), 741 | _ => { 742 | TronError::throw("E3001", line, vec!["variable".to_string()]); 743 | Ok(()) 744 | } 745 | }, 746 | _ => { 747 | TronError::throw("E3001", line, vec!["variable".to_string()]); 748 | Ok(()) 749 | } 750 | } 751 | } 752 | /// Resolves a local variable within the given environment. 753 | /// 754 | /// This method is used to resolve a local variable, ensuring that the variable is declared and initialized in the current scope. It also handles the resolution of function calls where the callee is a variable. 755 | /// 756 | /// # Parameters 757 | /// 758 | /// - `name`: The token representing the variable name to be resolved. 759 | /// - `resolve_id`: The ID of the expression to be resolved. 760 | /// 761 | /// # Returns 762 | /// 763 | /// - `Result<(), String>`: Returns `Ok(())` if the local variable is successfully resolved, or an error message if resolution fails. 764 | /// 765 | /// # Examples 766 | /// 767 | /// ``` 768 | /// let mut resolver = Resolver::new(); 769 | /// let variable_name = Token::new(TokenType::Identifier, "testVar", None, 1); 770 | /// resolver.resolve_local(&variable_name, variable_name.get_id())? 771 | /// ``` 772 | /// 773 | /// ### Last Updated: (v3.0.0) 774 | fn resolve_local(&mut self, name: &Token, resolve_id: usize) -> Result<(), String> { 775 | let size = self.scopes.len(); 776 | if size == 0 { 777 | return Ok(()); 778 | } 779 | for i in (0..=(size - 1)).rev() { 780 | let scope = &self.scopes[i]; 781 | if scope.contains_key(&name.lexeme) { 782 | self.locals.insert(resolve_id, size - 1 - i); 783 | return Ok(()); 784 | } 785 | } 786 | Ok(()) 787 | } 788 | /// Resolves an assignment expression within the given environment. 789 | /// 790 | /// This method is used to resolve an assignment expression, ensuring that the variable being assigned to is declared and initialized in the current scope. It also handles the resolution of function calls where the callee is a variable. 791 | /// 792 | /// # Parameters 793 | /// 794 | /// - `expr`: A reference to the expression to be resolved. 795 | /// - `resolve_id`: The ID of the expression to be resolved. 796 | /// 797 | /// # Returns 798 | /// 799 | /// - `Result<(), String>`: Returns `Ok(())` if the assignment expression is successfully resolved, or an error message if resolution fails. 800 | /// 801 | /// # Examples 802 | /// 803 | /// ``` 804 | /// 805 | /// let mut resolver = Resolver::new(); 806 | /// let mut environment = Environment::new(); 807 | /// let assignment_expression = Expression::Assign { /* ... */ }; 808 | /// resolver.resolve_expr_assign(&assignment_expression, assignment_expression.get_id())?; 809 | /// ``` 810 | /// 811 | /// # Panics 812 | /// 813 | /// - Panics if the provided expression is not an assignment expression. 814 | /// 815 | /// ### Last Updated: (v3.0.0) 816 | fn resolve_expr_assign( 817 | &mut self, 818 | expr: &Expression, 819 | resolve_id: usize, 820 | line: usize, 821 | environment: &mut Environment, 822 | ) -> Result<(), String> { 823 | if let Expression::Assign { id: _, name, value } = expr { 824 | self.resolve_expr(value.as_ref(), line, environment)?; 825 | self.resolve_local(name, resolve_id)?; 826 | } else { 827 | TronError::throw("E3001", line, vec!["assign".to_string()]); 828 | } 829 | Ok(()) 830 | } 831 | } 832 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | use std::process::exit; 2 | 3 | pub struct TronError { 4 | pub code: String, 5 | pub line: usize, 6 | pub message: String, 7 | } 8 | 9 | impl TronError { 10 | pub fn throw(error_code: &str, line: usize, args: Vec) { 11 | let message: String = match args.len() { 12 | 0 => match error_code { 13 | "E0001" => "failed to run file".to_string(), 14 | "E0002" => "failed to run command".to_string(), 15 | "E0003" => "unsupported platform".to_string(), 16 | "E1001" => "unterminated string".to_string(), 17 | "E2002" => "failed to parse block statement".to_string(), 18 | "E2004" => "function can't have more than 32 arguments".to_string(), 19 | "E2005" => "invalid assigment target".to_string(), 20 | "E3003" => "failed to read local variable".to_string(), 21 | "E3004" => "failed to resolve a variable in a too deep level".to_string(), 22 | "E3005" => "failed to define a variable in a too deep level".to_string(), 23 | "E3006" => "return isn't allowed outside of a function".to_string(), 24 | "E3007" => "break isn't allowed outside of a loop".to_string(), 25 | "E4006" => "failed to make function".to_string(), 26 | "E4009" => "array index is out of bounds".to_string(), 27 | "E4010" => "failed to perform operation on array".to_string(), 28 | "E4012" => "immutable variables can't be re-declared".to_string(), 29 | "E4013" => "failed to call".to_string(), 30 | "E4014" => "function call argument count doesn't match parameter count".to_string(), 31 | "E4017" => "invalid function output type".to_string(), 32 | _ => "uknwon error".to_string(), 33 | }, 34 | 1 => { 35 | let e1002 = format!("unrecognized character: {}", args[0]); 36 | let e1003 = format!("unsupported character: {}", args[0]); 37 | let e1004 = format!("failted to scan tokens: \n {}", args[0]); 38 | let e2001 = format!("failed to parse statements: \n {}", args[0]); 39 | let e2003 = format!("unexpected token: {}", args[0]); 40 | let e3001 = format!("failed to resolve {} statement: incorrect type", args[0]); 41 | let e3002 = format!("variable {} already exists", args[0]); 42 | let e4004 = format!("failed to execute command: \n {}", args[0]); 43 | let e4005 = format!("failed to find library: {}", args[0]); 44 | let e4008 = format!("failed to create type from {}", args[0]); 45 | let e4011 = format!("variable {} has not been declared", args[0]); 46 | let e4016 = format!("invalid operator {}", args[0]); 47 | 48 | match error_code { 49 | "E1002" => e1002, 50 | "E1003" => e1003, 51 | "E1004" => e1004, 52 | "E2001" => e2001, 53 | "E2003" => e2003, 54 | "E3001" => e3001, 55 | "E3002" => e3002, 56 | "E4004" => e4004, 57 | "E4005" => e4005, 58 | "E4008" => e4008, 59 | "E4011" => e4011, 60 | "E4016" => e4016, 61 | _ => "uknwon error".to_string(), 62 | } 63 | } 64 | 2 => { 65 | let e4007 = format!("failed to unwrap {} as {}", args[0], args[1]); 66 | let e4015 = format!("{} is not implemented for {}", args[0], args[1]); 67 | let e4018 = format!("{} requires at least {} arguments", args[0], args[1]); 68 | let e4019 = format!("{} requires more than {} arguments", args[0], args[1]); 69 | let e4020 = format!("{} exactly exactly {} arguments", args[0], args[1]); 70 | match error_code { 71 | "E4007" => e4007, 72 | "E4015" => e4015, 73 | "E4018" => e4018, 74 | "E4019" => e4019, 75 | "E4020" => e4020, 76 | _ => "uknwon error".to_string(), 77 | } 78 | } 79 | 3 => { 80 | let e4001 = format!( 81 | "{}() is expecting {} arguments, but got{}", 82 | args[0], args[1], args[2] 83 | ); 84 | let e4002 = format!("{}({}: {})", args[0], args[1], args[2]); 85 | let e4018 = format!( 86 | "{} expects {} type as {} argument", 87 | args[0], args[1], args[2] 88 | ); 89 | 90 | match error_code { 91 | "E4001" => e4001, 92 | "E4002" => e4002, 93 | "E4018" => e4018, 94 | _ => "uknwon error".to_string(), 95 | } 96 | } 97 | _ => { 98 | let e4003 = format!( 99 | "{} {} is expecting {} type, but got {}", 100 | args[0], args[1], args[2], args[3] 101 | ); 102 | 103 | if error_code == "E4003" { 104 | e4003 105 | } else { 106 | "uknwon error".to_string() 107 | } 108 | } 109 | }; 110 | 111 | if line == 0 { 112 | eprintln!( 113 | "[\x1B[91;1m{}\x1B[0m] \x1B[91;1m{} \x1B[0m", 114 | error_code, message 115 | ); 116 | } else { 117 | eprintln!( 118 | "[\x1B[91;1m{}\x1B[0m] \x1B[91;1m{} \x1B[0m(\x1B[96mline {}\x1B[0m)", 119 | error_code, message, line 120 | ); 121 | } 122 | 123 | match error_code { 124 | "E1001" => exit(1), 125 | "E4018" => exit(1), 126 | "E4019" => exit(1), 127 | "E4020" => exit(1), 128 | "E4021" => exit(1), 129 | _ => {} 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /versions/3.1.0: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/418e/Tron/b1cae6d6c1680df750d257b627eddbef3bd4fc14/versions/3.1.0 -------------------------------------------------------------------------------- /vstron/.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | client/node_modules 3 | client/out/** 4 | server/node_modules 5 | server/out/** -------------------------------------------------------------------------------- /vstron/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /**@type {import('eslint').Linter.Config} */ 2 | // eslint-disable-next-line no-undef 3 | module.exports = { 4 | root: true, 5 | parser: '@typescript-eslint/parser', 6 | plugins: [ 7 | '@typescript-eslint', 8 | ], 9 | extends: [ 10 | 'eslint:recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | ], 13 | rules: { 14 | 'semi': [2, "always"], 15 | '@typescript-eslint/no-unused-vars': 0, 16 | '@typescript-eslint/no-explicit-any': 0, 17 | '@typescript-eslint/explicit-module-boundary-types': 0, 18 | '@typescript-eslint/no-non-null-assertion': 0, 19 | } 20 | }; -------------------------------------------------------------------------------- /vstron/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.vscode 3 | /client/node_modules 4 | /server/node_modules -------------------------------------------------------------------------------- /vstron/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | vsc-extension-quickstart.md 5 | node_modules 6 | client/node_modules/** 7 | !client/node_modules/vscode-jsonrpc/** 8 | !client/node_modules/vscode-languageclient/** 9 | !client/node_modules/vscode-languageserver-protocol/** 10 | !client/node_modules/vscode-languageserver-types/** 11 | !client/node_modules/{minimatch,brace-expansion,concat-map,balanced-match}/** 12 | !client/node_modules/{semver,lru-cache,yallist}/** -------------------------------------------------------------------------------- /vstron/README.md: -------------------------------------------------------------------------------- 1 | # VSTron -------------------------------------------------------------------------------- /vstron/client/out/extension.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.deactivate = exports.activate = void 0; 4 | var path = require("path"); 5 | var vscode_1 = require("vscode"); 6 | var node_1 = require("vscode-languageclient/node"); 7 | var client; 8 | function activate(context) { 9 | var serverModule = context.asAbsolutePath(path.join("server", "out", "server.js")); 10 | var serverOptions = { 11 | run: { module: serverModule, transport: node_1.TransportKind.ipc }, 12 | debug: { 13 | module: serverModule, 14 | transport: node_1.TransportKind.ipc, 15 | }, 16 | }; 17 | var clientOptions = { 18 | documentSelector: [{ scheme: "file", language: "tron" }], 19 | synchronize: { 20 | fileEvents: vscode_1.workspace.createFileSystemWatcher("**/.clientrc"), 21 | }, 22 | }; 23 | client = new node_1.LanguageClient("languageServerExample", "Language Server Example", serverOptions, clientOptions); 24 | client.start().then(function () { 25 | context.subscriptions.push(vscode_1.languages.registerDocumentFormattingEditProvider("tron", { 26 | provideDocumentFormattingEdits: function (document, options, token) { 27 | return client.sendRequest("textDocument/formatting", { 28 | textDocument: { uri: document.uri.toString() }, 29 | options: options, 30 | }, token); 31 | }, 32 | })); 33 | }); 34 | } 35 | exports.activate = activate; 36 | function deactivate() { 37 | if (!client) { 38 | return undefined; 39 | } 40 | return client.stop(); 41 | } 42 | exports.deactivate = deactivate; 43 | -------------------------------------------------------------------------------- /vstron/client/out/extension.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,mCAAqD;AAErD,qDAKoC;AAEpC,IAAI,MAAsB,CAAC;AAC3B,SAAgB,QAAQ,CAAC,OAAyB;IAChD,MAAM,YAAY,GAAG,OAAO,CAAC,cAAc,CACzC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CACxC,CAAC;IACF,MAAM,aAAa,GAAkB;QACnC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,oBAAa,CAAC,GAAG,EAAE;QAC3D,KAAK,EAAE;YACL,MAAM,EAAE,YAAY;YACpB,SAAS,EAAE,oBAAa,CAAC,GAAG;SAC7B;KACF,CAAC;IAEF,MAAM,aAAa,GAA0B;QAC3C,gBAAgB,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACxD,WAAW,EAAE;YACX,UAAU,EAAE,kBAAS,CAAC,uBAAuB,CAAC,cAAc,CAAC;SAC9D;KACF,CAAC;IACF,MAAM,GAAG,IAAI,qBAAc,CACzB,uBAAuB,EACvB,yBAAyB,EACzB,aAAa,EACb,aAAa,CACd,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC;AAzBD,4BAyBC;AAED,SAAgB,UAAU;IACxB,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,SAAS,CAAC;KAClB;IACD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AALD,gCAKC"} -------------------------------------------------------------------------------- /vstron/client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron-lsp-client", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tron-lsp-client", 9 | "version": "0.0.1", 10 | "license": "MIT", 11 | "dependencies": { 12 | "vscode-languageclient": "^9.0.1" 13 | }, 14 | "devDependencies": { 15 | "@types/vscode": "^1.75.1", 16 | "@vscode/test-electron": "^2.3.8" 17 | }, 18 | "engines": { 19 | "vscode": "^1.75.0" 20 | } 21 | }, 22 | "node_modules/@tootallnate/once": { 23 | "version": "1.1.2", 24 | "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", 25 | "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", 26 | "dev": true, 27 | "engines": { 28 | "node": ">= 6" 29 | } 30 | }, 31 | "node_modules/@types/vscode": { 32 | "version": "1.85.0", 33 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.85.0.tgz", 34 | "integrity": "sha512-CF/RBon/GXwdfmnjZj0WTUMZN5H6YITOfBCP4iEZlOtVQXuzw6t7Le7+cR+7JzdMrnlm7Mfp49Oj2TuSXIWo3g==", 35 | "dev": true 36 | }, 37 | "node_modules/@vscode/test-electron": { 38 | "version": "2.3.8", 39 | "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.8.tgz", 40 | "integrity": "sha512-b4aZZsBKtMGdDljAsOPObnAi7+VWIaYl3ylCz1jTs+oV6BZ4TNHcVNC3xUn0azPeszBmwSBDQYfFESIaUQnrOg==", 41 | "dev": true, 42 | "dependencies": { 43 | "http-proxy-agent": "^4.0.1", 44 | "https-proxy-agent": "^5.0.0", 45 | "jszip": "^3.10.1", 46 | "semver": "^7.5.2" 47 | }, 48 | "engines": { 49 | "node": ">=16" 50 | } 51 | }, 52 | "node_modules/agent-base": { 53 | "version": "6.0.2", 54 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", 55 | "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", 56 | "dev": true, 57 | "dependencies": { 58 | "debug": "4" 59 | }, 60 | "engines": { 61 | "node": ">= 6.0.0" 62 | } 63 | }, 64 | "node_modules/balanced-match": { 65 | "version": "1.0.2", 66 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 67 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 68 | }, 69 | "node_modules/brace-expansion": { 70 | "version": "2.0.1", 71 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 72 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 73 | "dependencies": { 74 | "balanced-match": "^1.0.0" 75 | } 76 | }, 77 | "node_modules/core-util-is": { 78 | "version": "1.0.3", 79 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 80 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", 81 | "dev": true 82 | }, 83 | "node_modules/debug": { 84 | "version": "4.3.4", 85 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 86 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 87 | "dev": true, 88 | "dependencies": { 89 | "ms": "2.1.2" 90 | }, 91 | "engines": { 92 | "node": ">=6.0" 93 | }, 94 | "peerDependenciesMeta": { 95 | "supports-color": { 96 | "optional": true 97 | } 98 | } 99 | }, 100 | "node_modules/http-proxy-agent": { 101 | "version": "4.0.1", 102 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", 103 | "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", 104 | "dev": true, 105 | "dependencies": { 106 | "@tootallnate/once": "1", 107 | "agent-base": "6", 108 | "debug": "4" 109 | }, 110 | "engines": { 111 | "node": ">= 6" 112 | } 113 | }, 114 | "node_modules/https-proxy-agent": { 115 | "version": "5.0.1", 116 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", 117 | "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", 118 | "dev": true, 119 | "dependencies": { 120 | "agent-base": "6", 121 | "debug": "4" 122 | }, 123 | "engines": { 124 | "node": ">= 6" 125 | } 126 | }, 127 | "node_modules/immediate": { 128 | "version": "3.0.6", 129 | "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", 130 | "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", 131 | "dev": true 132 | }, 133 | "node_modules/inherits": { 134 | "version": "2.0.4", 135 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 136 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 137 | "dev": true 138 | }, 139 | "node_modules/isarray": { 140 | "version": "1.0.0", 141 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 142 | "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", 143 | "dev": true 144 | }, 145 | "node_modules/jszip": { 146 | "version": "3.10.1", 147 | "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", 148 | "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", 149 | "dev": true, 150 | "dependencies": { 151 | "lie": "~3.3.0", 152 | "pako": "~1.0.2", 153 | "readable-stream": "~2.3.6", 154 | "setimmediate": "^1.0.5" 155 | } 156 | }, 157 | "node_modules/lie": { 158 | "version": "3.3.0", 159 | "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", 160 | "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", 161 | "dev": true, 162 | "dependencies": { 163 | "immediate": "~3.0.5" 164 | } 165 | }, 166 | "node_modules/lru-cache": { 167 | "version": "6.0.0", 168 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 169 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 170 | "dependencies": { 171 | "yallist": "^4.0.0" 172 | }, 173 | "engines": { 174 | "node": ">=10" 175 | } 176 | }, 177 | "node_modules/minimatch": { 178 | "version": "5.1.6", 179 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", 180 | "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", 181 | "dependencies": { 182 | "brace-expansion": "^2.0.1" 183 | }, 184 | "engines": { 185 | "node": ">=10" 186 | } 187 | }, 188 | "node_modules/ms": { 189 | "version": "2.1.2", 190 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 191 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 192 | "dev": true 193 | }, 194 | "node_modules/pako": { 195 | "version": "1.0.11", 196 | "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", 197 | "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", 198 | "dev": true 199 | }, 200 | "node_modules/process-nextick-args": { 201 | "version": "2.0.1", 202 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 203 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 204 | "dev": true 205 | }, 206 | "node_modules/readable-stream": { 207 | "version": "2.3.8", 208 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", 209 | "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", 210 | "dev": true, 211 | "dependencies": { 212 | "core-util-is": "~1.0.0", 213 | "inherits": "~2.0.3", 214 | "isarray": "~1.0.0", 215 | "process-nextick-args": "~2.0.0", 216 | "safe-buffer": "~5.1.1", 217 | "string_decoder": "~1.1.1", 218 | "util-deprecate": "~1.0.1" 219 | } 220 | }, 221 | "node_modules/safe-buffer": { 222 | "version": "5.1.2", 223 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 224 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 225 | "dev": true 226 | }, 227 | "node_modules/semver": { 228 | "version": "7.5.4", 229 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 230 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 231 | "dependencies": { 232 | "lru-cache": "^6.0.0" 233 | }, 234 | "bin": { 235 | "semver": "bin/semver.js" 236 | }, 237 | "engines": { 238 | "node": ">=10" 239 | } 240 | }, 241 | "node_modules/setimmediate": { 242 | "version": "1.0.5", 243 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", 244 | "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", 245 | "dev": true 246 | }, 247 | "node_modules/string_decoder": { 248 | "version": "1.1.1", 249 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 250 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 251 | "dev": true, 252 | "dependencies": { 253 | "safe-buffer": "~5.1.0" 254 | } 255 | }, 256 | "node_modules/util-deprecate": { 257 | "version": "1.0.2", 258 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 259 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 260 | "dev": true 261 | }, 262 | "node_modules/vscode-jsonrpc": { 263 | "version": "8.2.0", 264 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", 265 | "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", 266 | "engines": { 267 | "node": ">=14.0.0" 268 | } 269 | }, 270 | "node_modules/vscode-languageclient": { 271 | "version": "9.0.1", 272 | "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", 273 | "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", 274 | "dependencies": { 275 | "minimatch": "^5.1.0", 276 | "semver": "^7.3.7", 277 | "vscode-languageserver-protocol": "3.17.5" 278 | }, 279 | "engines": { 280 | "vscode": "^1.82.0" 281 | } 282 | }, 283 | "node_modules/vscode-languageserver-protocol": { 284 | "version": "3.17.5", 285 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", 286 | "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", 287 | "dependencies": { 288 | "vscode-jsonrpc": "8.2.0", 289 | "vscode-languageserver-types": "3.17.5" 290 | } 291 | }, 292 | "node_modules/vscode-languageserver-types": { 293 | "version": "3.17.5", 294 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", 295 | "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" 296 | }, 297 | "node_modules/yallist": { 298 | "version": "4.0.0", 299 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 300 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /vstron/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron-lsp-client", 3 | "description": "VSCode part of a tron programming language server", 4 | "author": "418e", 5 | "license": "MIT", 6 | "version": "0.0.1", 7 | "publisher": "tronlang", 8 | "engines": { 9 | "vscode": "^1.75.0" 10 | }, 11 | "dependencies": { 12 | "vscode-languageclient": "^9.0.1" 13 | }, 14 | "devDependencies": { 15 | "@types/vscode": "^1.75.1", 16 | "@vscode/test-electron": "^2.3.8" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /vstron/client/src/extension.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | var desc = Object.getOwnPropertyDescriptor(m, k); 5 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { 6 | desc = { enumerable: true, get: function() { return m[k]; } }; 7 | } 8 | Object.defineProperty(o, k2, desc); 9 | }) : (function(o, m, k, k2) { 10 | if (k2 === undefined) k2 = k; 11 | o[k2] = m[k]; 12 | })); 13 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 14 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 15 | }) : function(o, v) { 16 | o["default"] = v; 17 | }); 18 | var __importStar = (this && this.__importStar) || function (mod) { 19 | if (mod && mod.__esModule) return mod; 20 | var result = {}; 21 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 22 | __setModuleDefault(result, mod); 23 | return result; 24 | }; 25 | Object.defineProperty(exports, "__esModule", { value: true }); 26 | exports.deactivate = exports.activate = void 0; 27 | const path = __importStar(require("path")); 28 | const vscode_1 = require("vscode"); 29 | const node_1 = require("vscode-languageclient/node"); 30 | let client; 31 | function activate(context) { 32 | const serverModule = context.asAbsolutePath(path.join("server", "out", "server.js")); 33 | const serverOptions = { 34 | run: { module: serverModule, transport: node_1.TransportKind.ipc }, 35 | debug: { 36 | module: serverModule, 37 | transport: node_1.TransportKind.ipc, 38 | }, 39 | }; 40 | const clientOptions = { 41 | documentSelector: [{ scheme: "file", language: "tron" }], 42 | synchronize: { 43 | fileEvents: vscode_1.workspace.createFileSystemWatcher("**/.clientrc"), 44 | }, 45 | }; 46 | client = new node_1.LanguageClient("languageServerExample", "Language Server Example", serverOptions, clientOptions); 47 | client.start().then(() => { 48 | context.subscriptions.push(vscode_1.languages.registerDocumentFormattingEditProvider("tron", { 49 | provideDocumentFormattingEdits(document, options, token) { 50 | return client.sendRequest("textDocument/formatting", { 51 | textDocument: { uri: document.uri.toString() }, 52 | options: options, 53 | }, token); 54 | }, 55 | })); 56 | }); 57 | } 58 | exports.activate = activate; 59 | function deactivate() { 60 | if (!client) { 61 | return undefined; 62 | } 63 | return client.stop(); 64 | } 65 | exports.deactivate = deactivate; 66 | -------------------------------------------------------------------------------- /vstron/client/src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as path from "path"; 2 | import { 3 | workspace, 4 | ExtensionContext, 5 | languages, 6 | DocumentFormattingEditProvider, 7 | TextDocument, 8 | FormattingOptions, 9 | CancellationToken, 10 | ProviderResult, 11 | TextEdit, 12 | } from "vscode"; 13 | import { 14 | LanguageClient, 15 | LanguageClientOptions, 16 | ServerOptions, 17 | TransportKind, 18 | } from "vscode-languageclient/node"; 19 | 20 | let client: LanguageClient; 21 | export function activate(context: ExtensionContext) { 22 | const serverModule = context.asAbsolutePath( 23 | path.join("server", "out", "server.js") 24 | ); 25 | const serverOptions: ServerOptions = { 26 | run: { module: serverModule, transport: TransportKind.ipc }, 27 | debug: { 28 | module: serverModule, 29 | transport: TransportKind.ipc, 30 | }, 31 | }; 32 | 33 | const clientOptions: LanguageClientOptions = { 34 | documentSelector: [{ scheme: "file", language: "tron" }], 35 | synchronize: { 36 | fileEvents: workspace.createFileSystemWatcher("**/.clientrc"), 37 | }, 38 | }; 39 | 40 | client = new LanguageClient( 41 | "languageServerExample", 42 | "Language Server Example", 43 | serverOptions, 44 | clientOptions 45 | ); 46 | client.start().then(() => { 47 | context.subscriptions.push( 48 | languages.registerDocumentFormattingEditProvider("tron", { 49 | provideDocumentFormattingEdits( 50 | document: TextDocument, 51 | options: FormattingOptions, 52 | token: CancellationToken 53 | ): ProviderResult { 54 | return client.sendRequest( 55 | "textDocument/formatting", 56 | { 57 | textDocument: { uri: document.uri.toString() }, 58 | options: options, 59 | }, 60 | token 61 | ); 62 | }, 63 | }) 64 | ); 65 | }); 66 | } 67 | 68 | export function deactivate(): Thenable | undefined { 69 | if (!client) { 70 | return undefined; 71 | } 72 | return client.stop(); 73 | } 74 | -------------------------------------------------------------------------------- /vstron/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2020", 5 | "lib": ["es2020"], 6 | "outDir": "out", 7 | "rootDir": "src", 8 | "sourceMap": true 9 | }, 10 | "include": ["src"], 11 | "exclude": ["node_modules", ".vscode-test"] 12 | } 13 | -------------------------------------------------------------------------------- /vstron/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//" 4 | }, 5 | "brackets": [ 6 | ["{", "}"], 7 | ["[", "]"], 8 | ["(", ")"], 9 | ["<", ">"] 10 | ], 11 | "autoClosingPairs": [ 12 | { "open": "{", "close": "}" }, 13 | { "open": "[", "close": "]" }, 14 | { "open": "(", "close": ")" }, 15 | { "open": "\"", "close": "\"", "notIn": ["string"] }, 16 | { "open": "'", "close": "'", "notIn": ["string"] }, 17 | ], 18 | "surroundingPairs": [ 19 | ["{", "}"], 20 | ["[", "]"], 21 | ["(", ")"], 22 | ["\"", "\""] 23 | ], 24 | "folding": { 25 | 26 | }, 27 | "onEnterRules": [ 28 | { 29 | "beforeText": "^\\s*(?:fn|class|for|if|else if|else|while|switch|case|finally).*?:\\s*$", 30 | "action": { "indent": "indent" } 31 | } 32 | ], 33 | "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)" 34 | } 35 | -------------------------------------------------------------------------------- /vstron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron-lang", 3 | "displayName": "Tron Programming Language", 4 | "publisher": "tronlang", 5 | "description": "VSC plugin for Tron programming language", 6 | "version": "3.0.0", 7 | "license": "MIT", 8 | "icon": "tron.png", 9 | "main": "./client/out/extension", 10 | "engines": { 11 | "vscode": "^1.52.0" 12 | }, 13 | "dependencies": { 14 | "vscode-languageclient": "^7.0.0" 15 | }, 16 | "devDependencies": { 17 | "@types/mocha": "^10.0.6", 18 | "@types/node": "^18.14.6", 19 | "@typescript-eslint/eslint-plugin": "^6.14.0", 20 | "@typescript-eslint/parser": "^6.14.0", 21 | "eslint": "^8.56.0", 22 | "mocha": "^10.2.0", 23 | "typescript": "^5.3.3" 24 | }, 25 | "categories": [ 26 | "Programming Languages" 27 | ], 28 | "scripts": { 29 | "vscode:prepublish": "npm run compile", 30 | "compile": "tsc -b", 31 | "watch": "tsc -b -w", 32 | "lint": "eslint ./client/src ./server/src --ext .ts,.tsx", 33 | "postinstall": "cd client && npm install && cd ../server && npm install && cd .." 34 | }, 35 | "contributes": { 36 | "languages": [ 37 | { 38 | "id": "tron", 39 | "icon": { 40 | "dark": "./tron.png", 41 | "light": "./tron.png" 42 | }, 43 | "aliases": [ 44 | "tron", 45 | "tronlang" 46 | ], 47 | "extensions": [ 48 | ".tron" 49 | ], 50 | "configuration": "./language-configuration.json" 51 | } 52 | ], 53 | "configuration": { 54 | "type": "object", 55 | "title": "tron configuration", 56 | "properties": { 57 | "languageServerExample.maxNumberOfProblems": { 58 | "scope": "resource", 59 | "type": "number", 60 | "default": 100, 61 | "description": "Controls the maximum number of problems produced by the server." 62 | }, 63 | "languageServerExample.trace.server": { 64 | "scope": "window", 65 | "type": "string", 66 | "enum": [ 67 | "off", 68 | "messages", 69 | "verbose" 70 | ], 71 | "default": "off", 72 | "description": "Traces the communication between VS Code and the language server." 73 | } 74 | } 75 | }, 76 | "grammars": [ 77 | { 78 | "language": "tron", 79 | "scopeName": "source.tron", 80 | "path": "./syntaxes/tron.tmLanguage.json" 81 | } 82 | ] 83 | }, 84 | "activationEvents": [ 85 | "onLanguage:tron" 86 | ] 87 | } 88 | -------------------------------------------------------------------------------- /vstron/server/out/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const node_1 = require("vscode-languageserver/node"); 4 | const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); 5 | const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all); 6 | const documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument); 7 | let hasConfigurationCapability = false; 8 | let hasWorkspaceFolderCapability = false; 9 | connection.onInitialize((params) => { 10 | const capabilities = params.capabilities; 11 | hasConfigurationCapability = !!(capabilities.workspace && !!capabilities.workspace.configuration); 12 | hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders); 13 | const result = { 14 | capabilities: { 15 | textDocumentSync: node_1.TextDocumentSyncKind.Incremental, 16 | completionProvider: { 17 | resolveProvider: true, 18 | }, 19 | }, 20 | }; 21 | if (hasWorkspaceFolderCapability) { 22 | result.capabilities.workspace = { 23 | workspaceFolders: { 24 | supported: true, 25 | }, 26 | }; 27 | } 28 | return result; 29 | }); 30 | connection.onInitialized(() => { 31 | if (hasConfigurationCapability) { 32 | connection.client.register(node_1.DidChangeConfigurationNotification.type, undefined); 33 | } 34 | }); 35 | const variableDeclarations = new Map(); 36 | function trackVariableDeclarations(document) { 37 | const text = document.getText(); 38 | const regex = /let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]*);/g; 39 | let match; 40 | while ((match = regex.exec(text)) !== null) { 41 | const variableName = match[1]; 42 | const variableType = match[2]; 43 | const variableValue = match[3]; 44 | variableDeclarations.set(variableName, { 45 | declaration: match[0], 46 | type: variableType, 47 | value: variableValue, 48 | }); 49 | } 50 | } 51 | function extractParameters(functionDeclaration) { 52 | const regex = /fn\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(([^)]*)\)/; 53 | const match = functionDeclaration.match(regex); 54 | if (!match) { 55 | return []; 56 | } 57 | const paramsString = match[1]; 58 | const paramsRegex = /\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*/g; 59 | let paramsMatch; 60 | const parameters = []; 61 | while ((paramsMatch = paramsRegex.exec(paramsString)) !== null) { 62 | parameters.push({ 63 | name: paramsMatch[1], 64 | type: paramsMatch[2], 65 | }); 66 | } 67 | return parameters; 68 | } 69 | const functionDeclarations = new Map(); 70 | function trackFunctionDeclarations(document) { 71 | const text = document.getText(); 72 | const regex = /fn\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\{[^]*?\}/g; 73 | let match; 74 | while ((match = regex.exec(text)) !== null) { 75 | const functionName = match[1]; 76 | const functionDeclaration = match[0]; 77 | const parameters = extractParameters(functionDeclaration); 78 | const returnType = match[3]; 79 | functionDeclarations.set(functionName, { 80 | declaration: functionDeclaration, 81 | parameters, 82 | returnType, 83 | }); 84 | } 85 | } 86 | documents.onDidChangeContent((change) => { 87 | trackVariableDeclarations(change.document); 88 | trackFunctionDeclarations(change.document); 89 | }); 90 | connection.onCompletion((_textDocumentPosition) => { 91 | const completions = [ 92 | { 93 | label: "break", 94 | kind: node_1.CompletionItemKind.Keyword, 95 | }, 96 | { 97 | label: "else if", 98 | kind: node_1.CompletionItemKind.Keyword, 99 | }, 100 | { 101 | label: "else", 102 | kind: node_1.CompletionItemKind.Keyword, 103 | }, 104 | { 105 | label: "false", 106 | kind: node_1.CompletionItemKind.Keyword, 107 | }, 108 | { 109 | label: "for", 110 | kind: node_1.CompletionItemKind.Keyword, 111 | }, 112 | { 113 | label: "fn", 114 | kind: node_1.CompletionItemKind.Keyword, 115 | }, 116 | { 117 | label: "if", 118 | kind: node_1.CompletionItemKind.Keyword, 119 | }, 120 | { 121 | label: "use", 122 | kind: node_1.CompletionItemKind.Keyword, 123 | }, 124 | { 125 | label: "null", 126 | kind: node_1.CompletionItemKind.Keyword, 127 | }, 128 | { 129 | label: "true", 130 | kind: node_1.CompletionItemKind.Keyword, 131 | }, 132 | { 133 | label: "let", 134 | kind: node_1.CompletionItemKind.Keyword, 135 | }, 136 | { 137 | label: "while", 138 | kind: node_1.CompletionItemKind.Keyword, 139 | }, 140 | { 141 | label: "case", 142 | kind: node_1.CompletionItemKind.Keyword, 143 | }, 144 | { 145 | label: "default", 146 | kind: node_1.CompletionItemKind.Keyword, 147 | }, 148 | { 149 | label: "switch", 150 | kind: node_1.CompletionItemKind.Keyword, 151 | }, 152 | { 153 | label: "number", 154 | kind: node_1.CompletionItemKind.Keyword, 155 | }, 156 | { 157 | label: "string", 158 | kind: node_1.CompletionItemKind.Keyword, 159 | }, 160 | ]; 161 | variableDeclarations.forEach((declaration, variableName) => { 162 | completions.push({ 163 | label: variableName, 164 | kind: node_1.CompletionItemKind.Variable, 165 | detail: declaration.declaration, 166 | }); 167 | }); 168 | functionDeclarations.forEach((declaration, functionName) => { 169 | completions.push({ 170 | label: functionName, 171 | kind: node_1.CompletionItemKind.Function, 172 | detail: declaration.declaration, 173 | }); 174 | declaration.parameters.forEach((param) => { 175 | completions.push({ 176 | label: param.name, 177 | kind: node_1.CompletionItemKind.Variable 178 | }); 179 | }); 180 | }); 181 | return completions; 182 | }); 183 | connection.onCompletionResolve((item) => { 184 | return item; 185 | }); 186 | function formatTronDocument(text, options) { 187 | const lines = text.split(/\r?\n/); 188 | const indentStack = []; 189 | function getIndentation(line) { 190 | return indentStack[indentStack.length - 1] || ""; 191 | } 192 | function formatLine(line) { 193 | const trimmedLine = line.trim(); 194 | if (trimmedLine === "") { 195 | return ""; 196 | } 197 | else { 198 | let indentation = getIndentation(trimmedLine); 199 | if (trimmedLine.endsWith("{")) { 200 | indentStack.push(indentation + " "); 201 | } 202 | else if (trimmedLine === "}") { 203 | indentStack.pop(); 204 | indentation = getIndentation(trimmedLine); 205 | } 206 | return indentation + trimmedLine; 207 | } 208 | } 209 | const formattedLines = lines.map(formatLine); 210 | const formattedText = formattedLines.join("\n"); 211 | if (indentStack.length > 0) { 212 | throw new Error("Mismatched curly braces in the document"); 213 | } 214 | return formattedText; 215 | } 216 | connection.onDocumentFormatting((params) => { 217 | const document = documents.get(params.textDocument.uri); 218 | if (!document) { 219 | return []; 220 | } 221 | const text = document.getText(); 222 | const formattedText = formatTronDocument(text, params.options); 223 | return [ 224 | node_1.TextEdit.replace(node_1.Range.create(document.positionAt(0), document.positionAt(text.length)), formattedText), 225 | ]; 226 | }); 227 | documents.listen(connection); 228 | connection.listen(); 229 | //# sourceMappingURL=server.js.map -------------------------------------------------------------------------------- /vstron/server/out/server.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;AAAA,qDAcoC;AAEpC,2FAAkE;AAElE,MAAM,UAAU,GAAG,IAAA,uBAAgB,EAAC,uBAAgB,CAAC,GAAG,CAAC,CAAC;AAC1D,MAAM,SAAS,GAAgC,IAAI,oBAAa,CAAC,iDAAY,CAAC,CAAC;AAE/E,IAAI,0BAA0B,GAAG,KAAK,CAAC;AACvC,IAAI,4BAA4B,GAAG,KAAK,CAAC;AAEzC,UAAU,CAAC,YAAY,CAAC,CAAC,MAAwB,EAAE,EAAE;IACnD,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IACzC,0BAA0B,GAAG,CAAC,CAAC,CAC7B,YAAY,CAAC,SAAS,IAAI,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CACjE,CAAC;IACF,4BAA4B,GAAG,CAAC,CAAC,CAC/B,YAAY,CAAC,SAAS,IAAI,CAAC,CAAC,YAAY,CAAC,SAAS,CAAC,gBAAgB,CACpE,CAAC;IAEF,MAAM,MAAM,GAAqB;QAC/B,YAAY,EAAE;YACZ,gBAAgB,EAAE,2BAAoB,CAAC,WAAW;YAClD,kBAAkB,EAAE;gBAClB,eAAe,EAAE,IAAI;aACtB;SACF;KACF,CAAC;IACF,IAAI,4BAA4B,EAAE,CAAC;QACjC,MAAM,CAAC,YAAY,CAAC,SAAS,GAAG;YAC9B,gBAAgB,EAAE;gBAChB,SAAS,EAAE,IAAI;aAChB;SACF,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC,CAAC;AAEH,UAAU,CAAC,aAAa,CAAC,GAAG,EAAE;IAC5B,IAAI,0BAA0B,EAAE,CAAC;QAC/B,UAAU,CAAC,MAAM,CAAC,QAAQ,CACxB,yCAAkC,CAAC,IAAI,EACvC,SAAS,CACV,CAAC;IACJ,CAAC;AACH,CAAC,CAAC,CAAC;AASH,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAEpE,SAAS,yBAAyB,CAAC,QAAsB;IACvD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,KAAK,GACT,+EAA+E,CAAC;IAClF,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,oBAAoB,CAAC,GAAG,CAAC,YAAY,EAAE;YACrC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;YACrB,IAAI,EAAE,YAAY;YAClB,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAOD,SAAS,iBAAiB,CAAC,mBAA2B;IACpD,MAAM,KAAK,GAAG,2CAA2C,CAAC;IAC1D,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,WAAW,GACf,gEAAgE,CAAC;IACnE,IAAI,WAAW,CAAC;IAChB,MAAM,UAAU,GAAgB,EAAE,CAAC;IAEnC,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/D,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;YACpB,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAQD,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAEpE,SAAS,yBAAyB,CAAC,QAAsB;IACvD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,KAAK,GACT,yFAAyF,CAAC;IAC5F,IAAI,KAAK,CAAC;IACV,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,mBAAmB,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG,iBAAiB,CAAC,mBAAmB,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,oBAAoB,CAAC,GAAG,CAAC,YAAY,EAAE;YACrC,WAAW,EAAE,mBAAmB;YAChC,UAAU;YACV,UAAU;SACX,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,EAAE;IACtC,yBAAyB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3C,yBAAyB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC7C,CAAC,CAAC,CAAC;AAEH,UAAU,CAAC,YAAY,CACrB,CAAC,qBAAiD,EAAoB,EAAE;IAEtE,MAAM,WAAW,GAAqB;QACpC;YACE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,OAAO;YACd,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,SAAS;YAChB,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;QACD;YACE,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,yBAAkB,CAAC,OAAO;SACjC;KACF,CAAC;IACF,oBAAoB,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE;QACzD,WAAW,CAAC,IAAI,CAAC;YACf,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,yBAAkB,CAAC,QAAQ;YACjC,MAAM,EAAE,WAAW,CAAC,WAAW;SAChC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,oBAAoB,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,EAAE;QACzD,WAAW,CAAC,IAAI,CAAC;YACf,KAAK,EAAE,YAAY;YACnB,IAAI,EAAE,yBAAkB,CAAC,QAAQ;YACjC,MAAM,EAAE,WAAW,CAAC,WAAW;SAChC,CAAC,CAAC;QACH,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACvC,WAAW,CAAC,IAAI,CAAC;gBACf,KAAK,EAAE,KAAK,CAAC,IAAI;gBACjB,IAAI,EAAE,yBAAkB,CAAC,QAAQ;aAClC,CAAC,CAAA;QACJ,CAAC,CAAE,CAAA;IACL,CAAC,CAAC,CAAC;IACH,OAAO,WAAW,CAAC;AACrB,CAAC,CACF,CAAC;AACF,UAAU,CAAC,mBAAmB,CAAC,CAAC,IAAoB,EAAkB,EAAE;IACtE,OAAO,IAAI,CAAC;AACd,CAAC,CAAC,CAAC;AAEH,SAAS,kBAAkB,CAAC,IAAY,EAAE,OAA0B;IAClE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,SAAS,cAAc,CAAC,IAAY;QAClC,OAAO,WAAW,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,SAAS,UAAU,CAAC,IAAY;QAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,WAAW,KAAK,EAAE,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,IAAI,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;YAC9C,IAAI,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9B,WAAW,CAAC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,CAAC;YACzC,CAAC;iBAAM,IAAI,WAAW,KAAK,GAAG,EAAE,CAAC;gBAC/B,WAAW,CAAC,GAAG,EAAE,CAAC;gBAClB,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;YAC5C,CAAC;YACD,OAAO,WAAW,GAAG,WAAW,CAAC;QACnC,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,UAAU,CAAC,oBAAoB,CAAC,CAAC,MAAM,EAAc,EAAE;IACrD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;IAChC,MAAM,aAAa,GAAG,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAE/D,OAAO;QACL,eAAQ,CAAC,OAAO,CACd,YAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EACtE,aAAa,CACd;KACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAC7B,UAAU,CAAC,MAAM,EAAE,CAAC"} -------------------------------------------------------------------------------- /vstron/server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron-lsp-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tron-lsp-server", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "vscode-languageserver": "^9.0.1", 13 | "vscode-languageserver-textdocument": "^1.0.11" 14 | }, 15 | "engines": { 16 | "node": "*" 17 | } 18 | }, 19 | "node_modules/vscode-jsonrpc": { 20 | "version": "8.2.0", 21 | "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", 22 | "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", 23 | "engines": { 24 | "node": ">=14.0.0" 25 | } 26 | }, 27 | "node_modules/vscode-languageserver": { 28 | "version": "9.0.1", 29 | "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", 30 | "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", 31 | "dependencies": { 32 | "vscode-languageserver-protocol": "3.17.5" 33 | }, 34 | "bin": { 35 | "installServerIntoExtension": "bin/installServerIntoExtension" 36 | } 37 | }, 38 | "node_modules/vscode-languageserver-protocol": { 39 | "version": "3.17.5", 40 | "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", 41 | "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", 42 | "dependencies": { 43 | "vscode-jsonrpc": "8.2.0", 44 | "vscode-languageserver-types": "3.17.5" 45 | } 46 | }, 47 | "node_modules/vscode-languageserver-textdocument": { 48 | "version": "1.0.11", 49 | "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz", 50 | "integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==" 51 | }, 52 | "node_modules/vscode-languageserver-types": { 53 | "version": "3.17.5", 54 | "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", 55 | "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vstron/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron-lsp-server", 3 | "description": "Tron language support server", 4 | "version": "1.0.0", 5 | "author": "418e", 6 | "license": "MIT", 7 | "engines": { 8 | "node": "*" 9 | }, 10 | "dependencies": { 11 | "vscode-languageserver": "^9.0.1", 12 | "vscode-languageserver-textdocument": "^1.0.11" 13 | }, 14 | "scripts": {} 15 | } 16 | -------------------------------------------------------------------------------- /vstron/server/src/server.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const node_1 = require("vscode-languageserver/node"); 4 | const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); 5 | const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all); 6 | const documents = new node_1.TextDocuments(vscode_languageserver_textdocument_1.TextDocument); 7 | let hasConfigurationCapability = false; 8 | let hasWorkspaceFolderCapability = false; 9 | connection.onInitialize((params) => { 10 | const capabilities = params.capabilities; 11 | hasConfigurationCapability = !!(capabilities.workspace && !!capabilities.workspace.configuration); 12 | hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders); 13 | const result = { 14 | capabilities: { 15 | textDocumentSync: node_1.TextDocumentSyncKind.Incremental, 16 | completionProvider: { 17 | resolveProvider: true, 18 | }, 19 | }, 20 | }; 21 | if (hasWorkspaceFolderCapability) { 22 | result.capabilities.workspace = { 23 | workspaceFolders: { 24 | supported: true, 25 | }, 26 | }; 27 | } 28 | return result; 29 | }); 30 | connection.onInitialized(() => { 31 | if (hasConfigurationCapability) { 32 | connection.client.register(node_1.DidChangeConfigurationNotification.type, undefined); 33 | } 34 | }); 35 | const variableDeclarations = new Map(); 36 | function trackVariableDeclarations(document) { 37 | const text = document.getText(); 38 | const regex = /let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]*);/g; 39 | let match; 40 | while ((match = regex.exec(text)) !== null) { 41 | const variableName = match[1]; 42 | const variableType = match[2]; 43 | const variableValue = match[3]; 44 | variableDeclarations.set(variableName, { 45 | declaration: match[0], 46 | type: variableType, 47 | value: variableValue, 48 | }); 49 | } 50 | } 51 | function extractParameters(functionDeclaration) { 52 | const regex = /fn\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(([^)]*)\)/; 53 | const match = functionDeclaration.match(regex); 54 | if (!match) { 55 | return []; 56 | } 57 | const paramsString = match[1]; 58 | const paramsRegex = /\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*/g; 59 | let paramsMatch; 60 | const parameters = []; 61 | while ((paramsMatch = paramsRegex.exec(paramsString)) !== null) { 62 | parameters.push({ 63 | name: paramsMatch[1], 64 | type: paramsMatch[2], 65 | }); 66 | } 67 | return parameters; 68 | } 69 | const functionDeclarations = new Map(); 70 | function trackFunctionDeclarations(document) { 71 | const text = document.getText(); 72 | const regex = /fn\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\{[^]*?\}/g; 73 | let match; 74 | while ((match = regex.exec(text)) !== null) { 75 | const functionName = match[1]; 76 | const functionDeclaration = match[0]; 77 | const parameters = extractParameters(functionDeclaration); 78 | const returnType = match[3]; 79 | functionDeclarations.set(functionName, { 80 | declaration: functionDeclaration, 81 | parameters, 82 | returnType, 83 | }); 84 | } 85 | } 86 | documents.onDidChangeContent((change) => { 87 | trackVariableDeclarations(change.document); 88 | trackFunctionDeclarations(change.document); 89 | }); 90 | connection.onCompletion((_textDocumentPosition) => { 91 | const completions = [ 92 | { 93 | label: "break", 94 | kind: node_1.CompletionItemKind.Keyword, 95 | }, 96 | { 97 | label: "else if", 98 | kind: node_1.CompletionItemKind.Keyword, 99 | }, 100 | { 101 | label: "else", 102 | kind: node_1.CompletionItemKind.Keyword, 103 | }, 104 | { 105 | label: "false", 106 | kind: node_1.CompletionItemKind.Keyword, 107 | }, 108 | { 109 | label: "for", 110 | kind: node_1.CompletionItemKind.Keyword, 111 | }, 112 | { 113 | label: "fn", 114 | kind: node_1.CompletionItemKind.Keyword, 115 | }, 116 | { 117 | label: "if", 118 | kind: node_1.CompletionItemKind.Keyword, 119 | }, 120 | { 121 | label: "use", 122 | kind: node_1.CompletionItemKind.Keyword, 123 | }, 124 | { 125 | label: "null", 126 | kind: node_1.CompletionItemKind.Keyword, 127 | }, 128 | { 129 | label: "true", 130 | kind: node_1.CompletionItemKind.Keyword, 131 | }, 132 | { 133 | label: "let", 134 | kind: node_1.CompletionItemKind.Keyword, 135 | }, 136 | { 137 | label: "while", 138 | kind: node_1.CompletionItemKind.Keyword, 139 | }, 140 | { 141 | label: "case", 142 | kind: node_1.CompletionItemKind.Keyword, 143 | }, 144 | { 145 | label: "default", 146 | kind: node_1.CompletionItemKind.Keyword, 147 | }, 148 | { 149 | label: "switch", 150 | kind: node_1.CompletionItemKind.Keyword, 151 | }, 152 | { 153 | label: "number", 154 | kind: node_1.CompletionItemKind.Keyword, 155 | }, 156 | { 157 | label: "string", 158 | kind: node_1.CompletionItemKind.Keyword, 159 | }, 160 | ]; 161 | variableDeclarations.forEach((declaration, variableName) => { 162 | completions.push({ 163 | label: variableName, 164 | kind: node_1.CompletionItemKind.Variable, 165 | detail: declaration.declaration, 166 | }); 167 | }); 168 | functionDeclarations.forEach((declaration, functionName) => { 169 | completions.push({ 170 | label: functionName, 171 | kind: node_1.CompletionItemKind.Function, 172 | detail: declaration.declaration, 173 | }); 174 | declaration.parameters.forEach((param) => { 175 | completions.push({ 176 | label: param.name, 177 | kind: node_1.CompletionItemKind.Variable 178 | }); 179 | }); 180 | }); 181 | return completions; 182 | }); 183 | connection.onCompletionResolve((item) => { 184 | return item; 185 | }); 186 | function formatTronDocument(text, options) { 187 | const lines = text.split(/\r?\n/); 188 | const indentStack = []; 189 | function getIndentation(line) { 190 | return indentStack[indentStack.length - 1] || ""; 191 | } 192 | function formatLine(line) { 193 | const trimmedLine = line.trim(); 194 | if (trimmedLine === "") { 195 | return ""; 196 | } 197 | else { 198 | let indentation = getIndentation(trimmedLine); 199 | if (trimmedLine.endsWith("{")) { 200 | indentStack.push(indentation + " "); 201 | } 202 | else if (trimmedLine === "}") { 203 | indentStack.pop(); 204 | indentation = getIndentation(trimmedLine); 205 | } 206 | return indentation + trimmedLine; 207 | } 208 | } 209 | const formattedLines = lines.map(formatLine); 210 | const formattedText = formattedLines.join("\n"); 211 | if (indentStack.length > 0) { 212 | throw new Error("Mismatched curly braces in the document"); 213 | } 214 | return formattedText; 215 | } 216 | connection.onDocumentFormatting((params) => { 217 | const document = documents.get(params.textDocument.uri); 218 | if (!document) { 219 | return []; 220 | } 221 | const text = document.getText(); 222 | const formattedText = formatTronDocument(text, params.options); 223 | return [ 224 | node_1.TextEdit.replace(node_1.Range.create(document.positionAt(0), document.positionAt(text.length)), formattedText), 225 | ]; 226 | }); 227 | documents.listen(connection); 228 | connection.listen(); 229 | -------------------------------------------------------------------------------- /vstron/server/src/server.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createConnection, 3 | TextDocuments, 4 | ProposedFeatures, 5 | InitializeParams, 6 | DidChangeConfigurationNotification, 7 | CompletionItem, 8 | CompletionItemKind, 9 | TextDocumentPositionParams, 10 | TextDocumentSyncKind, 11 | InitializeResult, 12 | TextEdit, 13 | FormattingOptions, 14 | Range, 15 | } from "vscode-languageserver/node"; 16 | 17 | import { TextDocument } from "vscode-languageserver-textdocument"; 18 | 19 | const connection = createConnection(ProposedFeatures.all); 20 | const documents: TextDocuments = new TextDocuments(TextDocument); 21 | 22 | let hasConfigurationCapability = false; 23 | let hasWorkspaceFolderCapability = false; 24 | 25 | connection.onInitialize((params: InitializeParams) => { 26 | const capabilities = params.capabilities; 27 | hasConfigurationCapability = !!( 28 | capabilities.workspace && !!capabilities.workspace.configuration 29 | ); 30 | hasWorkspaceFolderCapability = !!( 31 | capabilities.workspace && !!capabilities.workspace.workspaceFolders 32 | ); 33 | 34 | const result: InitializeResult = { 35 | capabilities: { 36 | textDocumentSync: TextDocumentSyncKind.Incremental, 37 | completionProvider: { 38 | resolveProvider: true, 39 | }, 40 | }, 41 | }; 42 | if (hasWorkspaceFolderCapability) { 43 | result.capabilities.workspace = { 44 | workspaceFolders: { 45 | supported: true, 46 | }, 47 | }; 48 | } 49 | return result; 50 | }); 51 | 52 | connection.onInitialized(() => { 53 | if (hasConfigurationCapability) { 54 | connection.client.register( 55 | DidChangeConfigurationNotification.type, 56 | undefined 57 | ); 58 | } 59 | }); 60 | 61 | 62 | interface VariableDeclaration { 63 | declaration: string; 64 | type: string; 65 | value: string; 66 | } 67 | 68 | const variableDeclarations = new Map(); 69 | 70 | function trackVariableDeclarations(document: TextDocument): void { 71 | const text = document.getText(); 72 | const regex = 73 | /let\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*([^;]*);/g; 74 | let match; 75 | while ((match = regex.exec(text)) !== null) { 76 | const variableName = match[1]; 77 | const variableType = match[2]; 78 | const variableValue = match[3]; 79 | variableDeclarations.set(variableName, { 80 | declaration: match[0], 81 | type: variableType, 82 | value: variableValue, 83 | }); 84 | } 85 | } 86 | 87 | interface Parameter { 88 | name: string; 89 | type: string; 90 | } 91 | 92 | function extractParameters(functionDeclaration: string): Parameter[] { 93 | const regex = /fn\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(([^)]*)\)/; 94 | const match = functionDeclaration.match(regex); 95 | if (!match) { 96 | return []; 97 | } 98 | 99 | const paramsString = match[1]; 100 | const paramsRegex = 101 | /\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*/g; 102 | let paramsMatch; 103 | const parameters: Parameter[] = []; 104 | 105 | while ((paramsMatch = paramsRegex.exec(paramsString)) !== null) { 106 | parameters.push({ 107 | name: paramsMatch[1], 108 | type: paramsMatch[2], 109 | }); 110 | } 111 | 112 | return parameters; 113 | } 114 | 115 | interface FunctionDeclaration { 116 | declaration: string; 117 | parameters: Parameter[]; 118 | returnType: string; 119 | } 120 | 121 | const functionDeclarations = new Map(); 122 | 123 | function trackFunctionDeclarations(document: TextDocument): void { 124 | const text = document.getText(); 125 | const regex = 126 | /fn\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*:\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\{[^]*?\}/g; 127 | let match; 128 | while ((match = regex.exec(text)) !== null) { 129 | const functionName = match[1]; 130 | const functionDeclaration = match[0]; 131 | const parameters = extractParameters(functionDeclaration); 132 | const returnType = match[3]; 133 | functionDeclarations.set(functionName, { 134 | declaration: functionDeclaration, 135 | parameters, 136 | returnType, 137 | }); 138 | } 139 | } 140 | 141 | documents.onDidChangeContent((change) => { 142 | trackVariableDeclarations(change.document); 143 | trackFunctionDeclarations(change.document); 144 | }); 145 | 146 | connection.onCompletion( 147 | (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => { 148 | 149 | const completions: CompletionItem[] = [ 150 | { 151 | label: "break", 152 | kind: CompletionItemKind.Keyword, 153 | }, 154 | { 155 | label: "else if", 156 | kind: CompletionItemKind.Keyword, 157 | }, 158 | { 159 | label: "else", 160 | kind: CompletionItemKind.Keyword, 161 | }, 162 | { 163 | label: "false", 164 | kind: CompletionItemKind.Keyword, 165 | }, 166 | { 167 | label: "for", 168 | kind: CompletionItemKind.Keyword, 169 | }, 170 | { 171 | label: "fn", 172 | kind: CompletionItemKind.Keyword, 173 | }, 174 | { 175 | label: "if", 176 | kind: CompletionItemKind.Keyword, 177 | }, 178 | { 179 | label: "use", 180 | kind: CompletionItemKind.Keyword, 181 | }, 182 | { 183 | label: "null", 184 | kind: CompletionItemKind.Keyword, 185 | }, 186 | { 187 | label: "true", 188 | kind: CompletionItemKind.Keyword, 189 | }, 190 | { 191 | label: "let", 192 | kind: CompletionItemKind.Keyword, 193 | }, 194 | { 195 | label: "while", 196 | kind: CompletionItemKind.Keyword, 197 | }, 198 | { 199 | label: "case", 200 | kind: CompletionItemKind.Keyword, 201 | }, 202 | { 203 | label: "default", 204 | kind: CompletionItemKind.Keyword, 205 | }, 206 | { 207 | label: "switch", 208 | kind: CompletionItemKind.Keyword, 209 | }, 210 | { 211 | label: "number", 212 | kind: CompletionItemKind.Keyword, 213 | }, 214 | { 215 | label: "string", 216 | kind: CompletionItemKind.Keyword, 217 | }, 218 | ]; 219 | variableDeclarations.forEach((declaration, variableName) => { 220 | completions.push({ 221 | label: variableName, 222 | kind: CompletionItemKind.Variable, 223 | detail: declaration.declaration, 224 | }); 225 | }); 226 | functionDeclarations.forEach((declaration, functionName) => { 227 | completions.push({ 228 | label: functionName, 229 | kind: CompletionItemKind.Function, 230 | detail: declaration.declaration, 231 | }); 232 | declaration.parameters.forEach((param) => { 233 | completions.push({ 234 | label: param.name, 235 | kind: CompletionItemKind.Variable 236 | }) 237 | } ) 238 | }); 239 | return completions; 240 | } 241 | ); 242 | connection.onCompletionResolve((item: CompletionItem): CompletionItem => { 243 | return item; 244 | }); 245 | 246 | function formatTronDocument(text: string, options: FormattingOptions): string { 247 | const lines = text.split(/\r?\n/); 248 | const indentStack: string[] = []; 249 | function getIndentation(line: string): string { 250 | return indentStack[indentStack.length - 1] || ""; 251 | } 252 | 253 | function formatLine(line: string): string { 254 | const trimmedLine = line.trim(); 255 | if (trimmedLine === "") { 256 | return ""; 257 | } else { 258 | let indentation = getIndentation(trimmedLine); 259 | if (trimmedLine.endsWith("{")) { 260 | indentStack.push(indentation + " "); 261 | } else if (trimmedLine === "}") { 262 | indentStack.pop(); 263 | indentation = getIndentation(trimmedLine); 264 | } 265 | return indentation + trimmedLine; 266 | } 267 | } 268 | 269 | const formattedLines = lines.map(formatLine); 270 | const formattedText = formattedLines.join("\n"); 271 | if (indentStack.length > 0) { 272 | throw new Error("Mismatched curly braces in the document"); 273 | } 274 | 275 | return formattedText; 276 | } 277 | 278 | connection.onDocumentFormatting((params): TextEdit[] => { 279 | const document = documents.get(params.textDocument.uri); 280 | if (!document) { 281 | return []; 282 | } 283 | 284 | const text = document.getText(); 285 | const formattedText = formatTronDocument(text, params.options); 286 | 287 | return [ 288 | TextEdit.replace( 289 | Range.create(document.positionAt(0), document.positionAt(text.length)), 290 | formattedText 291 | ), 292 | ]; 293 | }); 294 | 295 | documents.listen(connection); 296 | connection.listen(); 297 | -------------------------------------------------------------------------------- /vstron/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["es2020"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "sourceMap": true, 8 | "strict": true, 9 | "outDir": "out", 10 | "rootDir": "src" 11 | }, 12 | "include": ["src", "out/server.js"], 13 | "exclude": ["node_modules", ".vscode-test"] 14 | } -------------------------------------------------------------------------------- /vstron/syntaxes/tron.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tron", 3 | "scopeName": "source.tron", 4 | "fileTypes": ["tron"], 5 | "patterns": [ 6 | { 7 | "include": "#comments" 8 | }, 9 | { 10 | "include": "#strings" 11 | }, 12 | { 13 | "include": "#keywords" 14 | }, 15 | { 16 | "include": "#functions" 17 | } 18 | ], 19 | "repository": { 20 | "comments": { 21 | "patterns": [ 22 | { 23 | "name": "comment.line.double-slash.tron", 24 | "match": "//.*$" 25 | } 26 | ] 27 | }, 28 | "strings": { 29 | "name": "string.quoted.double.tron", 30 | "begin": "\"", 31 | "end": "\"", 32 | "patterns": [ 33 | { 34 | "name": "constant.character.escape.tron", 35 | "match": "\\\\." 36 | } 37 | ] 38 | }, 39 | "keywords": { 40 | "patterns": [ 41 | { 42 | "name": "keyword.control.tron", 43 | "match": "\\b(if|else|else if|while|for|return|break|fn|let|use|switch|case|default)\\b" 44 | } 45 | ] 46 | }, 47 | "functions": { 48 | "patterns": [ 49 | { 50 | "name": "support.function.tron", 51 | "match": "\\b[a-zA-Z_][a-zA-Z0-9_]*\\s*(?=\\()" 52 | } 53 | ] 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /vstron/tron-lang-2.0.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/418e/Tron/b1cae6d6c1680df750d257b627eddbef3bd4fc14/vstron/tron-lang-2.0.0.vsix -------------------------------------------------------------------------------- /vstron/tron-lang-3.0.0.vsix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/418e/Tron/b1cae6d6c1680df750d257b627eddbef3bd4fc14/vstron/tron-lang-3.0.0.vsix -------------------------------------------------------------------------------- /vstron/tron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/418e/Tron/b1cae6d6c1680df750d257b627eddbef3bd4fc14/vstron/tron.png -------------------------------------------------------------------------------- /vstron/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "commonjs", /* Specify what module code is generated. */ 29 | // "rootDir": "./", /* Specify the root folder within your source files. */ 30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ 39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ 40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ 41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ 42 | // "resolveJsonModule": true, /* Enable importing .json files. */ 43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ 44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 45 | 46 | /* JavaScript Support */ 47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 50 | 51 | /* Emit */ 52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 58 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 59 | // "removeComments": true, /* Disable emitting comments. */ 60 | // "noEmit": true, /* Disable emitting files from a compilation. */ 61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 68 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 75 | 76 | /* Interop Constraints */ 77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ 79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 83 | 84 | /* Type Checking */ 85 | "strict": true, /* Enable all strict type-checking options. */ 86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 104 | 105 | /* Completeness */ 106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 108 | } 109 | } 110 | --------------------------------------------------------------------------------