lt-script 1.0.1 → 1.0.5

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/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,10 @@ export class LuaEmitter {
148
148
  case AST.NodeType.CommandStmt:
149
149
  this.emitCommandStmt(stmt);
150
150
  break;
151
+ case AST.NodeType.TypeDecl:
152
+ case AST.NodeType.TypeAliasDecl:
153
+ // Type declarations are compile-time only, no Lua output
154
+ break;
151
155
  default:
152
156
  // Expression statement
153
157
  // Optimize UpdateExpr used as statement (i++)
@@ -299,7 +303,13 @@ export class LuaEmitter {
299
303
  this.emitStatement(s);
300
304
  }
301
305
  }
302
- this.line('return');
306
+ // Emit return with optional value
307
+ if (stmt.returnValue) {
308
+ this.line(`return ${this.emitExpr(stmt.returnValue)}`);
309
+ }
310
+ else {
311
+ this.line('return');
312
+ }
303
313
  this.indent--;
304
314
  this.line('end');
305
315
  }
@@ -509,11 +519,18 @@ export class LuaEmitter {
509
519
  let op = expr.operator;
510
520
  if (op === '!=')
511
521
  op = '~=';
522
+ if (op === '&&')
523
+ op = 'and';
524
+ if (op === '||')
525
+ op = 'or';
512
526
  return `(${left} ${op} ${right})`;
513
527
  }
514
528
  emitUnaryExpr(expr) {
515
- const space = expr.operator === 'not' ? ' ' : '';
516
- return `${expr.operator}${space}${this.emitExpr(expr.operand)}`;
529
+ let op = expr.operator;
530
+ if (op === '!')
531
+ op = 'not';
532
+ const space = (op === 'not' || op === 'and' || op === 'or') ? ' ' : '';
533
+ return `${op}${space}${this.emitExpr(expr.operand)}`;
517
534
  }
518
535
  emitCallExpr(expr) {
519
536
  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,8 @@ export declare enum NodeType {
28
28
  EmitStmt = "EmitStmt",
29
29
  EventHandler = "EventHandler",
30
30
  ExportDecl = "ExportDecl",
31
+ TypeDecl = "TypeDecl",
32
+ TypeAliasDecl = "TypeAliasDecl",
31
33
  BinaryExpr = "BinaryExpr",
32
34
  UnaryExpr = "UnaryExpr",
33
35
  UpdateExpr = "UpdateExpr",// ++, --
@@ -83,10 +85,25 @@ export interface Parameter {
83
85
  typeAnnotation?: string;
84
86
  defaultValue?: Expression;
85
87
  }
88
+ export interface TypeField {
89
+ name: string;
90
+ type: string;
91
+ }
92
+ export interface TypeDecl extends Statement {
93
+ kind: NodeType.TypeDecl;
94
+ name: Identifier;
95
+ fields: TypeField[];
96
+ }
97
+ export interface TypeAliasDecl extends Statement {
98
+ kind: NodeType.TypeAliasDecl;
99
+ name: Identifier;
100
+ type: string;
101
+ }
86
102
  export interface AssignmentStmt extends Statement {
87
103
  kind: NodeType.AssignmentStmt;
88
104
  targets: Expression[];
89
105
  values: Expression[];
106
+ typeAnnotation?: string;
90
107
  }
91
108
  export interface CompoundAssignment extends Statement {
92
109
  kind: NodeType.CompoundAssignment;
@@ -151,6 +168,7 @@ export interface GuardStmt extends Statement {
151
168
  kind: NodeType.GuardStmt;
152
169
  condition: Expression;
153
170
  elseBody?: Statement[];
171
+ returnValue?: Expression;
154
172
  }
155
173
  export interface SafeCallStmt extends Statement {
156
174
  kind: NodeType.SafeCallStmt;
@@ -33,6 +33,9 @@ export var NodeType;
33
33
  NodeType["EmitStmt"] = "EmitStmt";
34
34
  NodeType["EventHandler"] = "EventHandler";
35
35
  NodeType["ExportDecl"] = "ExportDecl";
36
+ // Type System
37
+ NodeType["TypeDecl"] = "TypeDecl";
38
+ NodeType["TypeAliasDecl"] = "TypeAliasDecl";
36
39
  // Expressions
37
40
  NodeType["BinaryExpr"] = "BinaryExpr";
38
41
  NodeType["UnaryExpr"] = "UnaryExpr";
@@ -10,6 +10,8 @@ export declare class Parser {
10
10
  constructor(tokens: Token[]);
11
11
  parse(): AST.Program;
12
12
  private parseStatement;
13
+ private parseType;
14
+ private parseTypeAlias;
13
15
  private parseVariableDecl;
14
16
  private parseIfStmt;
15
17
  private parseForStmt;
@@ -30,6 +32,7 @@ export declare class Parser {
30
32
  private parseSwitchStmt;
31
33
  private parseCommandStmt;
32
34
  private parseExportDecl;
35
+ private parseTypeDecl;
33
36
  private parseExpressionStatement;
34
37
  private parseExpression;
35
38
  private parseAssignment;
@@ -44,15 +47,18 @@ export declare class Parser {
44
47
  private parseMultiplicative;
45
48
  private parseUnary;
46
49
  private parseCallMember;
50
+ private parseMemberSuffix;
47
51
  private parseCallExpr;
48
52
  private parsePrimary;
49
53
  private parseStringLiteral;
50
54
  private parseInterpolatedString;
55
+ private parseEmbeddedExpression;
51
56
  private parseParenOrArrow;
52
57
  private parseArrayLiteral;
53
58
  private parseTableLiteral;
54
59
  private parseVectorLiteral;
55
60
  private parseIdentifier;
61
+ private parseIdentifierName;
56
62
  private parseParameter;
57
63
  private parseObjectDestructure;
58
64
  private parseArrayDestructure;