lt-script 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,33 +1,274 @@
1
- # LT Language Compiler
1
+ # LT Language
2
2
 
3
- A compiler for the LT language, targeting FiveM Lua.
3
+ <p align="center">
4
+ <img src="https://img.shields.io/npm/v/lt-script?color=blue&label=npm" alt="npm version">
5
+ <img src="https://img.shields.io/github/license/laot7490/lt-script" alt="license">
6
+ <img src="https://img.shields.io/badge/FiveM-Ready-green" alt="FiveM Ready">
7
+ </p>
4
8
 
5
- ## Installation
9
+ **LT** is a modern, developer-friendly language that compiles to FiveM Lua. It brings TypeScript-like syntax, modern JavaScript features, and FiveM-specific sugar to the Lua ecosystem — making your scripts cleaner, safer, and more enjoyable to write.
10
+
11
+ ## ✨ Why LT?
12
+
13
+ Writing vanilla Lua for FiveM can be tedious. LT fixes that with:
14
+
15
+ - **Modern Syntax**: Arrow functions, destructuring, spread operator, optional chaining
16
+ - **FiveM Sugar**: Built-in `thread`, `wait`, `netevent`, `addcmd`, `export` keywords
17
+ - **Type Safety**: Static type checking catches errors at compile time
18
+ - **Clean Code**: No more boilerplate — just write what you mean
19
+
20
+ ## 📦 Installation
6
21
 
7
22
  ```bash
8
- npm install -g lt-compiler
23
+ npm install -g lt-script
9
24
  ```
10
25
 
11
- ## Usage
26
+ ## 🚀 Quick Start
12
27
 
13
- ```bash
14
- ltc help
28
+ Create a file called `main.lt`:
29
+
30
+ ```typescript
31
+ // Variables with modern scoping
32
+ let health: number = 100
33
+ const MAX_HEALTH = 200
34
+
35
+ // Arrow functions
36
+ let double = (x) => x * 2
37
+
38
+ // String interpolation
39
+ print("Health: $health / $MAX_HEALTH")
40
+
41
+ // FiveM thread with wait
42
+ thread
43
+ loop (true)
44
+ wait 1000
45
+ print("Tick...")
46
+ end
47
+ end
48
+
49
+ // Register a command easily
50
+ addcmd "heal" (source, args)
51
+ health = MAX_HEALTH
52
+ print("Player healed!")
53
+ end
54
+
55
+ // Network events without boilerplate
56
+ netevent "player:spawn" (data)
57
+ print("Player spawned: $data")
58
+ end
15
59
  ```
16
60
 
17
- ### Compiler
61
+ Compile it:
18
62
 
19
63
  ```bash
20
- ltc build <sourceDir> <outDir>
64
+ ltc build .
21
65
  ```
22
66
 
23
- ### Watch Mode
67
+ Output `main.lua`:
68
+ ```lua
69
+ local health = 100
70
+ local MAX_HEALTH <const> = 200
24
71
 
25
- ```bash
26
- ltc watch <sourceDir> <outDir>
72
+ local double = function(x) return x * 2 end
73
+
74
+ print("Health: " .. tostring(health) .. " / " .. tostring(MAX_HEALTH))
75
+
76
+ CreateThread(function()
77
+ while true do
78
+ Wait(1000)
79
+ print("Tick...")
80
+ end
81
+ end)
82
+
83
+ RegisterCommand("heal", function(source, args)
84
+ health = MAX_HEALTH
85
+ print("Player healed!")
86
+ end, false)
87
+
88
+ RegisterNetEvent("player:spawn")
89
+ AddEventHandler("player:spawn", function(data)
90
+ print("Player spawned: " .. tostring(data))
91
+ end)
92
+ ```
93
+
94
+ ## 🛠️ CLI Commands
95
+
96
+ | Command | Description |
97
+ |---------|-------------|
98
+ | `ltc build <dir>` | Compile all `.lt` files in directory |
99
+ | `ltc watch <dir>` | Watch mode — auto-compile on save |
100
+
101
+ ## 🎯 Feature Highlights
102
+
103
+ ### Variables & Constants
104
+ ```typescript
105
+ var globalVar = "I am global" // Global variable
106
+ let localVar = 10 // Local variable
107
+ const MAX = 100 // Constant (Lua 5.4 <const>)
108
+ ```
109
+
110
+ ### Type System
111
+ ```typescript
112
+ // Explicit types
113
+ let name: string = "John"
114
+ let age: number = 25
115
+ let active: boolean = true
116
+
117
+ // Type Aliases
118
+ interface PlayerData = {
119
+ name: string,
120
+ level: number,
121
+ isVip: boolean
122
+ }
123
+
124
+ func Calculate(a: number, b: number)
125
+ return a + b
126
+ end
127
+ ```
128
+
129
+ ### Arrow Functions
130
+ ```typescript
131
+ let add = (a, b) => a + b
132
+ let greet = (name) => print("Hello, $name!")
133
+ ```
134
+
135
+ ### Destructuring
136
+ ```typescript
137
+ let player = { name: "Alex", level: 50 }
138
+ let { name, level } = player
139
+
140
+ let coords = [100, 200, 300]
141
+ let [x, y, z] = coords
142
+ ```
143
+
144
+ ### Optional Chaining & Null Coalescing
145
+ ```typescript
146
+ let job = player?.metadata?.job?.label ?? "Unemployed"
147
+ ```
148
+
149
+ ### Vector Literals
150
+ ```typescript
151
+ let pos = <100.0, 50.0, 20.0> // vector3
152
+ let rot = <0.0, 90.0> // vector2
153
+ ```
154
+
155
+ ### Switch/Case
156
+ ```typescript
157
+ switch weather
158
+ case "RAIN", "THUNDER"
159
+ print("Stay inside!")
160
+ case "CLEAR"
161
+ print("Nice day!")
162
+ default
163
+ print("Unknown weather")
164
+ end
165
+ ```
166
+
167
+ ### For Loops
168
+ ```typescript
169
+ // Range loop
170
+ for i in 1..10 do
171
+ print(i)
172
+ end
173
+
174
+ // Range with step
175
+ for i in 10..1 by -1 do
176
+ print(i)
177
+ end
178
+
179
+ // C-style loop
180
+ for i = 0, 100, 5 do
181
+ print(i)
182
+ end
183
+ ```
184
+
185
+ ### FiveM Specific
186
+
187
+ #### Threads & Wait
188
+ ```typescript
189
+ thread
190
+ wait 1000
191
+ print("After 1 second")
192
+ end
193
+ ```
194
+
195
+ #### Events
196
+ ```typescript
197
+ netevent "myResource:sync" (data)
198
+ -- RegisterNetEvent + AddEventHandler
199
+ end
200
+
201
+ event "localEvent" (data)
202
+ -- AddEventHandler only
203
+ end
204
+ ```
205
+
206
+ #### Commands
207
+ ```typescript
208
+ addcmd "teleport" (source, args)
209
+ print("Teleporting...")
210
+ end
211
+ ```
212
+
213
+ #### Exports
214
+ ```typescript
215
+ export func GetPlayerData(id)
216
+ return players[id]
217
+ end
27
218
  ```
28
219
 
29
- ## Features
220
+ #### Guard Statements
221
+ ```typescript
222
+ guard player return // Early return if nil/false
223
+ guard player.job == "police" return print("Access denied")
224
+
225
+ // Guard with else block
226
+ guard isValid else
227
+ print("Invalid state")
228
+ return
229
+ end
230
+ ```
231
+
232
+ #### Try/Catch
233
+ ```typescript
234
+ try
235
+ riskyOperation()
236
+ catch err
237
+ print("Error: $err")
238
+ end
239
+ ```
240
+
241
+ ## 📁 Project Structure
242
+
243
+ ```
244
+ my-resource/
245
+ ├── src/
246
+ │ ├── client.lt
247
+ │ └── server.lt
248
+ ├── client.lua (generated)
249
+ ├── server.lua (generated)
250
+ └── fxmanifest.lua
251
+ ```
252
+
253
+ Run `ltc watch .` in your resource folder for automatic compilation.
254
+
255
+ ## 🔧 VS Code Extension
256
+
257
+ Get syntax highlighting and IntelliSense for `.lt` files:
258
+
259
+ **[LT Language Extension](https://marketplace.visualstudio.com/items?itemName=laot.lt-language)**
260
+
261
+ - Syntax Highlighting
262
+ - IntelliSense for Variables & Functions
263
+ - **Native FiveM Autocompletion** (GetHashKey, CreateVehicle, etc.)
264
+ - Snippets for common patterns
265
+
266
+ ## 📜 License
267
+
268
+ MIT © [LaotScripts](https://github.com/laot7490)
269
+
270
+ ---
30
271
 
31
- - Transpiles LT to Lua 5.4 (FiveM compatible)
32
- - Supports static typing syntax (transpiled to comments or checked)
33
- - FiveM native function support
272
+ <p align="center">
273
+ Made with ❤️ for the FiveM community
274
+ </p>
package/dist/cli/ltc.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { compile } from '../index.js';
3
3
  import * as fs from 'fs';
4
4
  import * as path from 'path';
5
- import { getAllFiles, ensureDirectoryExistence } from './utils.js';
5
+ import { getAllFiles, ensureDirectoryExistence, style } from './utils.js';
6
6
  const args = process.argv.slice(2);
7
7
  const command = args[0];
8
8
  if (!command) {
@@ -17,52 +17,59 @@ switch (command) {
17
17
  handleBuild(args.slice(1));
18
18
  break;
19
19
  default:
20
- console.error(`Unknown command: ${command}`);
20
+ console.error(style.red(`\n[LT] Error: Unknown command '${command}'`));
21
21
  printUsage();
22
22
  process.exit(1);
23
23
  }
24
24
  function printUsage() {
25
25
  console.log(`
26
- Usage:
27
- ltc watch <targetDir> # Watches <targetDir>/src and builds to <targetDir>/build
28
- ltc watch <sourceDir> <outDir> # Watches <sourceDir> and builds to <outDir>
29
- ltc build <targetDir> # Builds <targetDir>/src to <targetDir>/build once
30
- ltc build <sourceDir> <outDir> # Builds <sourceDir> to <outDir> once
26
+ ${style.bold('LT Language Compiler')} ${style.gray('(v1.0.0)')}
27
+ ${style.gray('----------------------------------------')}
28
+
29
+ ${style.bold('Usage:')}
30
+ ${style.cyan('ltc watch')} ${style.yellow('<targetDir>')}
31
+ ${style.cyan('ltc watch')} ${style.yellow('<srcDir> <outDir>')}
32
+ ${style.cyan('ltc build')} ${style.yellow('<targetDir>')}
33
+ ${style.cyan('ltc build')} ${style.yellow('<srcDir> <outDir>')}
34
+
35
+ ${style.bold('Examples:')}
36
+ ${style.gray('$')} ltc watch lt-fuel
37
+ ${style.gray('$')} ltc build src dist
31
38
  `);
32
39
  }
33
40
  function parsePaths(cmdArgs) {
34
- if (cmdArgs.length === 0)
41
+ if (cmdArgs.length === 0) {
42
+ console.error(style.red(`\n[LT] Error: Missing arguments.`));
43
+ printUsage();
35
44
  return null;
45
+ }
36
46
  let srcDir = '';
37
47
  let outDir = '';
38
48
  const target = cmdArgs[0];
39
49
  if (cmdArgs.length === 1) {
40
- // Convention mode: ltc watch lt-fuel
41
50
  const potentialSrc = path.join(target, 'src');
42
51
  if (fs.existsSync(potentialSrc) && fs.statSync(potentialSrc).isDirectory()) {
43
52
  srcDir = potentialSrc;
44
- outDir = path.join(target, 'build');
45
- console.log(`[LT] Auto-detected structure. Source: ${srcDir}, Output: ${outDir}`);
53
+ outDir = target;
54
+ console.log(`${style.blue('[LT]')} Auto-detected project structure:`);
55
+ console.log(` ${style.gray('Source:')} ${srcDir}`);
56
+ console.log(` ${style.gray('Output:')} ${outDir}`);
46
57
  }
47
58
  else {
48
- // Fallback? Or strict?
49
- // If just passing a folder that HAS .lt files but no src/ folder?
50
- // Let's assume strict src/build convention for single argument or error
51
- console.error(`[LT] Error: Could not find 'src' directory in '${target}'.`);
52
- console.error(` Please use 'ltc ${command} <sourceDir> <outDir>' for explicit paths.`);
59
+ console.error(style.red(`\n[LT] Error: Could not find 'src' directory in '${target}'.`));
60
+ console.error(` Expected: ${potentialSrc}`);
61
+ console.error(` To specify custom paths, use: ${style.cyan('ltc ' + command + ' <srcDir> <outDir>')}`);
53
62
  return null;
54
63
  }
55
64
  }
56
65
  else {
57
- // Explicit mode
58
66
  srcDir = cmdArgs[0];
59
67
  outDir = cmdArgs[1];
60
68
  }
61
- // Resolve to absolute
62
69
  srcDir = path.resolve(srcDir);
63
70
  outDir = path.resolve(outDir);
64
71
  if (!fs.existsSync(srcDir)) {
65
- console.error(`[LT] Error: Source directory '${srcDir}' does not exist.`);
72
+ console.error(style.red(`\n[LT] Error: Source directory '${srcDir}' does not exist.`));
66
73
  return null;
67
74
  }
68
75
  return { srcDir, outDir };
@@ -71,64 +78,67 @@ function compileFile(srcPath, srcRoot, outRoot) {
71
78
  try {
72
79
  const relative = path.relative(srcRoot, srcPath);
73
80
  const outPath = path.join(outRoot, relative.replace(/\.lt$/, '.lua'));
74
- console.log(`[LT] Compiling: ${relative}`);
81
+ process.stdout.write(`${style.blue('[LT]')} Compiling ${style.yellow(relative)}... `);
75
82
  const content = fs.readFileSync(srcPath, 'utf-8');
76
83
  const start = performance.now();
77
84
  const lua = compile(content);
78
85
  const end = performance.now();
79
86
  ensureDirectoryExistence(outPath);
80
87
  fs.writeFileSync(outPath, lua, 'utf8');
81
- console.log(`[LT] ✓ Success (${(end - start).toFixed(2)}ms)`);
88
+ console.log(style.green(`✓ ${(end - start).toFixed(0)}ms`));
82
89
  }
83
90
  catch (e) {
84
- console.error(`[LT] Error compiling ${srcPath}:`);
85
- console.error(e.message);
91
+ console.log(style.red(''));
92
+ console.error(`${style.red('[LT] Error compiling')} ${style.bold(srcPath)}:`);
93
+ console.error(style.yellow(e.message));
86
94
  }
87
95
  }
88
96
  function handleBuild(cmdArgs) {
97
+ console.log(style.bold(`\nStarting Build...`));
89
98
  const paths = parsePaths(cmdArgs);
90
99
  if (!paths)
91
100
  process.exit(1);
92
101
  const { srcDir, outDir } = paths;
93
- console.log(`[LT] Building from '${srcDir}' to '${outDir}'...`);
94
102
  const files = getAllFiles(srcDir, '.lt');
103
+ if (files.length === 0) {
104
+ console.log(style.yellow(`[LT] No .lt files found in ${srcDir}`));
105
+ return;
106
+ }
95
107
  files.forEach(file => compileFile(file, srcDir, outDir));
96
- console.log(`[LT] Build complete. ${files.length} files processed.`);
108
+ console.log(style.green(`\n[LT] Build complete. ${files.length} files processed.`));
97
109
  }
98
110
  function handleWatch(cmdArgs) {
111
+ console.log(style.bold(`\nStarting Watch Mode...`));
99
112
  const paths = parsePaths(cmdArgs);
100
113
  if (!paths)
101
114
  process.exit(1);
102
115
  const { srcDir, outDir } = paths;
103
- // Initial build
104
116
  handleBuild(cmdArgs);
105
- console.log(`[LT] Watching for changes in '${srcDir}'...`);
117
+ console.log(style.blue(`\n[LT] Watching for changes in '${srcDir}'...`));
118
+ console.log(style.gray(` (Press Ctrl+C to stop)`));
106
119
  let fsWait = null;
107
- // Recursive watch
108
120
  fs.watch(srcDir, { recursive: true }, (event, filename) => {
109
121
  if (!filename)
110
122
  return;
111
- // Windows/Mac returning filename
112
123
  if (!filename.endsWith('.lt'))
113
- return; // Ignore non-lt files
124
+ return;
114
125
  const fullPath = path.join(srcDir, filename);
115
126
  if (fsWait)
116
127
  clearTimeout(fsWait);
117
128
  fsWait = setTimeout(() => {
118
129
  fsWait = null;
119
130
  if (fs.existsSync(fullPath)) {
120
- // Modified or Created
131
+ console.log(style.gray(`\n[LT] File changed: ${filename}`));
121
132
  compileFile(fullPath, srcDir, outDir);
122
133
  }
123
134
  else {
124
- // Deleted
125
135
  const relative = path.relative(srcDir, fullPath);
126
136
  const outPath = path.join(outDir, relative.replace(/\.lt$/, '.lua'));
127
137
  if (fs.existsSync(outPath)) {
128
138
  fs.unlinkSync(outPath);
129
- console.log(`[LT] Removed: ${relative.replace(/\.lt$/, '.lua')}`);
139
+ console.log(style.red(`[LT] Removed: ${relative.replace(/\.lt$/, '.lua')}`));
130
140
  }
131
141
  }
132
- }, 100); // 100ms debounce
142
+ }, 100);
133
143
  });
134
144
  }
@@ -1,2 +1,42 @@
1
1
  export declare function getAllFiles(dir: string, extension: string, fileList?: string[]): string[];
2
2
  export declare function ensureDirectoryExistence(filePath: string): void;
3
+ export declare const colors: {
4
+ reset: string;
5
+ bright: string;
6
+ dim: string;
7
+ underscore: string;
8
+ blink: string;
9
+ reverse: string;
10
+ hidden: string;
11
+ fg: {
12
+ black: string;
13
+ red: string;
14
+ green: string;
15
+ yellow: string;
16
+ blue: string;
17
+ magenta: string;
18
+ cyan: string;
19
+ white: string;
20
+ gray: string;
21
+ };
22
+ bg: {
23
+ black: string;
24
+ red: string;
25
+ green: string;
26
+ yellow: string;
27
+ blue: string;
28
+ magenta: string;
29
+ cyan: string;
30
+ white: string;
31
+ };
32
+ };
33
+ export declare const style: {
34
+ green: (text: string) => string;
35
+ red: (text: string) => string;
36
+ yellow: (text: string) => string;
37
+ blue: (text: string) => string;
38
+ cyan: (text: string) => string;
39
+ gray: (text: string) => string;
40
+ bold: (text: string) => string;
41
+ white: (text: string) => string;
42
+ };
package/dist/cli/utils.js CHANGED
@@ -24,3 +24,43 @@ export function ensureDirectoryExistence(filePath) {
24
24
  ensureDirectoryExistence(dirname);
25
25
  fs.mkdirSync(dirname);
26
26
  }
27
+ export const colors = {
28
+ reset: "\x1b[0m",
29
+ bright: "\x1b[1m",
30
+ dim: "\x1b[2m",
31
+ underscore: "\x1b[4m",
32
+ blink: "\x1b[5m",
33
+ reverse: "\x1b[7m",
34
+ hidden: "\x1b[8m",
35
+ fg: {
36
+ black: "\x1b[30m",
37
+ red: "\x1b[31m",
38
+ green: "\x1b[32m",
39
+ yellow: "\x1b[33m",
40
+ blue: "\x1b[34m",
41
+ magenta: "\x1b[35m",
42
+ cyan: "\x1b[36m",
43
+ white: "\x1b[37m",
44
+ gray: "\x1b[90m",
45
+ },
46
+ bg: {
47
+ black: "\x1b[40m",
48
+ red: "\x1b[41m",
49
+ green: "\x1b[42m",
50
+ yellow: "\x1b[43m",
51
+ blue: "\x1b[44m",
52
+ magenta: "\x1b[45m",
53
+ cyan: "\x1b[46m",
54
+ white: "\x1b[47m",
55
+ }
56
+ };
57
+ export const style = {
58
+ green: (text) => `${colors.fg.green}${text}${colors.reset}`,
59
+ red: (text) => `${colors.fg.red}${text}${colors.reset}`,
60
+ yellow: (text) => `${colors.fg.yellow}${text}${colors.reset}`,
61
+ blue: (text) => `${colors.fg.blue}${text}${colors.reset}`,
62
+ cyan: (text) => `${colors.fg.cyan}${text}${colors.reset}`,
63
+ gray: (text) => `${colors.fg.gray}${text}${colors.reset}`,
64
+ bold: (text) => `${colors.bright}${text}${colors.reset}`,
65
+ white: (text) => `${colors.fg.white}${text}${colors.reset}`,
66
+ };
@@ -148,6 +148,9 @@ export class LuaEmitter {
148
148
  case AST.NodeType.CommandStmt:
149
149
  this.emitCommandStmt(stmt);
150
150
  break;
151
+ case AST.NodeType.TypeDecl:
152
+ // Type declarations are compile-time only, no Lua output
153
+ break;
151
154
  default:
152
155
  // Expression statement
153
156
  // Optimize UpdateExpr used as statement (i++)
@@ -299,7 +302,13 @@ export class LuaEmitter {
299
302
  this.emitStatement(s);
300
303
  }
301
304
  }
302
- this.line('return');
305
+ // Emit return with optional value
306
+ if (stmt.returnValue) {
307
+ this.line(`return ${this.emitExpr(stmt.returnValue)}`);
308
+ }
309
+ else {
310
+ this.line('return');
311
+ }
303
312
  this.indent--;
304
313
  this.line('end');
305
314
  }
@@ -509,11 +518,18 @@ export class LuaEmitter {
509
518
  let op = expr.operator;
510
519
  if (op === '!=')
511
520
  op = '~=';
521
+ if (op === '&&')
522
+ op = 'and';
523
+ if (op === '||')
524
+ op = 'or';
512
525
  return `(${left} ${op} ${right})`;
513
526
  }
514
527
  emitUnaryExpr(expr) {
515
- const space = expr.operator === 'not' ? ' ' : '';
516
- return `${expr.operator}${space}${this.emitExpr(expr.operand)}`;
528
+ let op = expr.operator;
529
+ if (op === '!')
530
+ op = 'not';
531
+ const space = (op === 'not' || op === 'and' || op === 'or') ? ' ' : '';
532
+ return `${op}${space}${this.emitExpr(expr.operand)}`;
517
533
  }
518
534
  emitCallExpr(expr) {
519
535
  const callee = this.emitExpr(expr.callee);
@@ -7,10 +7,12 @@ export class Lexer {
7
7
  source;
8
8
  tokens = [];
9
9
  pos = 0;
10
- line = 1;
11
- column = 1;
10
+ line;
11
+ column;
12
12
  constructor(source) {
13
13
  this.source = source;
14
+ this.line = 1;
15
+ this.column = 1;
14
16
  }
15
17
  tokenize() {
16
18
  while (!this.isEOF()) {
@@ -75,6 +77,8 @@ export class Lexer {
75
77
  // Two-char operators
76
78
  const twoChar = ch + next;
77
79
  const twoCharMap = {
80
+ '&&': TokenType.AND,
81
+ '||': TokenType.OR,
78
82
  '=>': TokenType.ARROW,
79
83
  '?.': TokenType.OPT_DOT,
80
84
  '?[': TokenType.OPT_BRACKET,
@@ -120,6 +124,7 @@ export class Lexer {
120
124
  '.': TokenType.DOT,
121
125
  ':': TokenType.COLON,
122
126
  ';': TokenType.SEMICOLON,
127
+ '!': TokenType.NOT,
123
128
  '?': TokenType.QUESTION,
124
129
  };
125
130
  if (singleCharMap[ch]) {
@@ -48,7 +48,8 @@ export declare enum TokenType {
48
48
  EVENT = "EVENT",
49
49
  NETEVENT = "NETEVENT",
50
50
  EXPORT = "EXPORT",
51
- COMMAND = "COMMAND",
51
+ ADDCMD = "ADDCMD",
52
+ INTERFACE = "INTERFACE",
52
53
  AND = "AND",
53
54
  OR = "OR",
54
55
  NOT = "NOT",
@@ -55,7 +55,9 @@ export var TokenType;
55
55
  TokenType["EVENT"] = "EVENT";
56
56
  TokenType["NETEVENT"] = "NETEVENT";
57
57
  TokenType["EXPORT"] = "EXPORT";
58
- TokenType["COMMAND"] = "COMMAND";
58
+ TokenType["ADDCMD"] = "ADDCMD";
59
+ // Type System
60
+ TokenType["INTERFACE"] = "INTERFACE";
59
61
  // Logical
60
62
  TokenType["AND"] = "AND";
61
63
  TokenType["OR"] = "OR";
@@ -157,7 +159,9 @@ export const KEYWORDS = {
157
159
  event: TokenType.EVENT,
158
160
  netevent: TokenType.NETEVENT,
159
161
  export: TokenType.EXPORT,
160
- command: TokenType.COMMAND,
162
+ addcmd: TokenType.ADDCMD,
163
+ // Type System
164
+ interface: TokenType.INTERFACE,
161
165
  // Logical
162
166
  and: TokenType.AND,
163
167
  or: TokenType.OR,
@@ -28,6 +28,7 @@ export declare enum NodeType {
28
28
  EmitStmt = "EmitStmt",
29
29
  EventHandler = "EventHandler",
30
30
  ExportDecl = "ExportDecl",
31
+ TypeDecl = "TypeDecl",
31
32
  BinaryExpr = "BinaryExpr",
32
33
  UnaryExpr = "UnaryExpr",
33
34
  UpdateExpr = "UpdateExpr",// ++, --
@@ -83,10 +84,20 @@ export interface Parameter {
83
84
  typeAnnotation?: string;
84
85
  defaultValue?: Expression;
85
86
  }
87
+ export interface TypeField {
88
+ name: string;
89
+ type: string;
90
+ }
91
+ export interface TypeDecl extends Statement {
92
+ kind: NodeType.TypeDecl;
93
+ name: Identifier;
94
+ fields: TypeField[];
95
+ }
86
96
  export interface AssignmentStmt extends Statement {
87
97
  kind: NodeType.AssignmentStmt;
88
98
  targets: Expression[];
89
99
  values: Expression[];
100
+ typeAnnotation?: string;
90
101
  }
91
102
  export interface CompoundAssignment extends Statement {
92
103
  kind: NodeType.CompoundAssignment;
@@ -151,6 +162,7 @@ export interface GuardStmt extends Statement {
151
162
  kind: NodeType.GuardStmt;
152
163
  condition: Expression;
153
164
  elseBody?: Statement[];
165
+ returnValue?: Expression;
154
166
  }
155
167
  export interface SafeCallStmt extends Statement {
156
168
  kind: NodeType.SafeCallStmt;