hzengine-core 0.1.2-dev

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.
Files changed (103) hide show
  1. package/dist/async/index.js +162 -0
  2. package/dist/async/zeppos_timer.js +58 -0
  3. package/dist/audio/index.js +260 -0
  4. package/dist/config/index.js +57 -0
  5. package/dist/debug/index.js +8 -0
  6. package/dist/index.js +103 -0
  7. package/dist/platform/index.js +1 -0
  8. package/dist/plugins/basic_command/$.js +8 -0
  9. package/dist/plugins/basic_command/audio.js +40 -0
  10. package/dist/plugins/basic_command/basic.js +124 -0
  11. package/dist/plugins/basic_command/character.js +112 -0
  12. package/dist/plugins/basic_command/conditional.js +260 -0
  13. package/dist/plugins/basic_command/config.js +22 -0
  14. package/dist/plugins/basic_command/decorator.js +24 -0
  15. package/dist/plugins/basic_command/eval.js +67 -0
  16. package/dist/plugins/basic_command/img.js +249 -0
  17. package/dist/plugins/basic_command/index.js +22 -0
  18. package/dist/plugins/basic_command/menu.js +140 -0
  19. package/dist/plugins/global_gesture/index.js +25 -0
  20. package/dist/plugins/transform/animation.js +440 -0
  21. package/dist/plugins/transform/commands.js +38 -0
  22. package/dist/plugins/transform/example_profiles.js +32 -0
  23. package/dist/plugins/transform/hz_anime.js +211 -0
  24. package/dist/plugins/transform/index.js +93 -0
  25. package/dist/script/index.js +537 -0
  26. package/dist/script/readscript.js +15 -0
  27. package/dist/script/strtools.js +157 -0
  28. package/dist/storage/decorator.js +260 -0
  29. package/dist/storage/fs.js +96 -0
  30. package/dist/storage/index.js +442 -0
  31. package/dist/system/index.js +144 -0
  32. package/dist/ui/index.js +535 -0
  33. package/dist/utils/path.js +289 -0
  34. package/license.txt +202 -0
  35. package/package.json +26 -0
  36. package/src/async/index.ts +124 -0
  37. package/src/async/zeppos_timer.js +65 -0
  38. package/src/audio/index.ts +224 -0
  39. package/src/config/index.ts +80 -0
  40. package/src/debug/index.ts +11 -0
  41. package/src/index.ts +122 -0
  42. package/src/platform/index.ts +158 -0
  43. package/src/plugins/basic_command/$.ts +11 -0
  44. package/src/plugins/basic_command/audio.ts +53 -0
  45. package/src/plugins/basic_command/basic.ts +145 -0
  46. package/src/plugins/basic_command/character.ts +144 -0
  47. package/src/plugins/basic_command/conditional.ts +349 -0
  48. package/src/plugins/basic_command/config.ts +29 -0
  49. package/src/plugins/basic_command/decorator.ts +29 -0
  50. package/src/plugins/basic_command/eval.ts +88 -0
  51. package/src/plugins/basic_command/img.ts +317 -0
  52. package/src/plugins/basic_command/index.ts +24 -0
  53. package/src/plugins/basic_command/menu.ts +178 -0
  54. package/src/plugins/global_gesture/index.ts +29 -0
  55. package/src/plugins/transform/animation.ts +542 -0
  56. package/src/plugins/transform/commands.ts +53 -0
  57. package/src/plugins/transform/example_profiles.ts +36 -0
  58. package/src/plugins/transform/hz_anime.ts +214 -0
  59. package/src/plugins/transform/index.ts +141 -0
  60. package/src/plugins/transform/readme.md +1 -0
  61. package/src/script/index.ts +623 -0
  62. package/src/script/readscript.ts +17 -0
  63. package/src/script/strtools.ts +159 -0
  64. package/src/storage/decorator.ts +473 -0
  65. package/src/storage/fs.ts +104 -0
  66. package/src/storage/index.ts +541 -0
  67. package/src/system/index.ts +95 -0
  68. package/src/ui/index.ts +699 -0
  69. package/src/utils/path.js +338 -0
  70. package/tsconfig.json +111 -0
  71. package/types/async/index.d.ts +24 -0
  72. package/types/async/zeppos_timer.d.ts +14 -0
  73. package/types/audio/index.d.ts +64 -0
  74. package/types/config/index.d.ts +9 -0
  75. package/types/debug/index.d.ts +6 -0
  76. package/types/index.d.ts +41 -0
  77. package/types/platform/index.d.ts +134 -0
  78. package/types/plugins/basic_command/$.d.ts +2 -0
  79. package/types/plugins/basic_command/audio.d.ts +2 -0
  80. package/types/plugins/basic_command/basic.d.ts +3 -0
  81. package/types/plugins/basic_command/character.d.ts +2 -0
  82. package/types/plugins/basic_command/conditional.d.ts +2 -0
  83. package/types/plugins/basic_command/config.d.ts +2 -0
  84. package/types/plugins/basic_command/decorator.d.ts +2 -0
  85. package/types/plugins/basic_command/eval.d.ts +2 -0
  86. package/types/plugins/basic_command/img.d.ts +2 -0
  87. package/types/plugins/basic_command/index.d.ts +2 -0
  88. package/types/plugins/basic_command/menu.d.ts +2 -0
  89. package/types/plugins/global_gesture/index.d.ts +2 -0
  90. package/types/plugins/transform/animation.d.ts +131 -0
  91. package/types/plugins/transform/commands.d.ts +7 -0
  92. package/types/plugins/transform/example_profiles.d.ts +2 -0
  93. package/types/plugins/transform/hz_anime.d.ts +51 -0
  94. package/types/plugins/transform/index.d.ts +13 -0
  95. package/types/script/index.d.ts +123 -0
  96. package/types/script/readscript.d.ts +2 -0
  97. package/types/script/strtools.d.ts +31 -0
  98. package/types/storage/decorator.d.ts +41 -0
  99. package/types/storage/fs.d.ts +1 -0
  100. package/types/storage/index.d.ts +86 -0
  101. package/types/system/index.d.ts +35 -0
  102. package/types/ui/index.d.ts +167 -0
  103. package/types/utils/path.d.ts +84 -0
@@ -0,0 +1,40 @@
1
+ import Path from "../../utils/path.js";
2
+ export function audio_command(core) {
3
+ // play command: play <channel> "<path>"
4
+ core.script.use((ctx, next) => {
5
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "play" &&
6
+ ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "queue")
7
+ return next();
8
+ if (ctx.slicedArgs.length !== 3)
9
+ throw `${ctx.slicedArgs[0].str.toUpperCase()} Command: incorrect amount of args`;
10
+ if (!ctx.slicedArgs[2].isQuoted)
11
+ throw `the third arg of ${ctx.slicedArgs[0].str} command should be quoted as string path`;
12
+ let channel_name = ctx.slicedArgs[1].str;
13
+ let path = ctx.slicedArgs[2].str;
14
+ core.debug.log(`Play Command: play ${channel_name} ${path}`);
15
+ let channel = core.audio.channels[channel_name];
16
+ if (!channel) {
17
+ throw `audio channel ${channel_name} not found`;
18
+ }
19
+ if (ctx.slicedArgs[0].str !== "queue") {
20
+ channel.stop();
21
+ }
22
+ channel.push({ path: Path.join(core.storage.projectRoot, "audio", path) });
23
+ channel.play();
24
+ });
25
+ // stop command: stop <channel>
26
+ core.script.use((ctx, next) => {
27
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "stop") {
28
+ return next();
29
+ }
30
+ if (ctx.slicedArgs.length !== 2) {
31
+ throw `Stop Command: incorrect amount of args`;
32
+ }
33
+ let channel_name = ctx.slicedArgs[1].str;
34
+ let channel = core.audio.channels[channel_name];
35
+ if (!channel) {
36
+ throw `audio channel ${channel_name} not found`;
37
+ }
38
+ channel.stop();
39
+ });
40
+ }
@@ -0,0 +1,124 @@
1
+ export function basic_commands(core) {
2
+ // jump command
3
+ core.script.use((ctx, next) => {
4
+ let strArr = ctx.rawtext.trim().split(/ +/);
5
+ if (strArr.length === 0 || strArr[0].toLowerCase() !== "jump")
6
+ return next();
7
+ if (strArr.length !== 2)
8
+ throw "Jump Command: incorrect amount of args";
9
+ core.debug.log(`Jump Command: jump to label [${strArr[1]}]`);
10
+ core.script.jumpLabel(strArr[1]);
11
+ });
12
+ // call command
13
+ core.script.use((ctx, next) => {
14
+ let strArr = ctx.rawtext.trim().split(/ +/);
15
+ if (strArr.length === 0 || strArr[0].toLowerCase() !== "call")
16
+ return next();
17
+ if (strArr.length !== 2)
18
+ throw "Call Command: incorrect amount of args";
19
+ core.debug.log(`Call Command: call label [${strArr[1]}]`);
20
+ core.script.callLabel(strArr[1]);
21
+ });
22
+ // return command
23
+ core.script.use((ctx, next) => {
24
+ let strArr = ctx.rawtext.trim().split(/ +/);
25
+ if (strArr.length === 0 || strArr[0].toLowerCase() !== "return")
26
+ return next();
27
+ if (strArr.length !== 1)
28
+ throw "Return Command: this command can not have args";
29
+ core.debug.log(`Return Command: return`);
30
+ core.script.return();
31
+ });
32
+ // (debug) echo command
33
+ core.script.use((ctx, next) => {
34
+ let str = ctx.rawtext.trim();
35
+ if (!str.startsWith("echo"))
36
+ return next();
37
+ core.debug.log(`[ECHO] ${core.script.parseString(str.slice(4).trim())}`);
38
+ });
39
+ // say command
40
+ core.script.use((ctx, next) => {
41
+ if (!ctx.rawtext.trim().startsWith('"'))
42
+ return next();
43
+ function parseSayCommandArgs() {
44
+ if (ctx.slicedArgs.length > 0 &&
45
+ ctx.slicedArgs[ctx.slicedArgs.length - 1].str === "nowait") {
46
+ ctx.slicedArgs = ctx.slicedArgs.slice(0, ctx.slicedArgs.length - 1);
47
+ return {
48
+ wait: false,
49
+ };
50
+ }
51
+ else {
52
+ return {
53
+ wait: true,
54
+ };
55
+ }
56
+ }
57
+ let parsed = parseSayCommandArgs();
58
+ if (ctx.slicedArgs.length > 2 || ctx.slicedArgs.length < 1) {
59
+ throw `Say Command: incorrect amount of args`;
60
+ }
61
+ if (ctx.slicedArgs.length === 1) {
62
+ core.debug.log(`[SAY] ${ctx.slicedArgs[0].str}`);
63
+ sayAction(core, "", ctx.slicedArgs[0].str, parsed.wait);
64
+ }
65
+ else {
66
+ if (!ctx.slicedArgs[1].isQuoted)
67
+ throw `Say Command: second arg should be quoted`;
68
+ core.debug.log(`[SAY] ${ctx.slicedArgs[0].str}: ${ctx.slicedArgs[1].str}`);
69
+ sayAction(core, ctx.slicedArgs[0].str, ctx.slicedArgs[1].str, parsed.wait);
70
+ }
71
+ // if (parsed?.wait) core.system.pause();
72
+ });
73
+ // pause command
74
+ core.script.use((ctx, next) => {
75
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "pause")
76
+ return next();
77
+ if (ctx.slicedArgs.length > 2)
78
+ throw `Pause Command: incorrect amount of args`;
79
+ if (ctx.slicedArgs.length === 2) {
80
+ if (ctx.slicedArgs[1].isQuoted ||
81
+ !isFinite(Number(ctx.slicedArgs[1].str)))
82
+ throw `Pause Command: the second arg must be a number`;
83
+ core.system.pause(Number(ctx.slicedArgs[1].str) * 1000);
84
+ }
85
+ else
86
+ core.system.pause();
87
+ });
88
+ }
89
+ export function sayAction(core, who, what, wait) {
90
+ const say_view_tag = "hzengine.say";
91
+ const say_view_name = "say";
92
+ what = core.script.parseString(what);
93
+ let message = {
94
+ who,
95
+ what,
96
+ };
97
+ let router = core.ui.getRouter(say_view_tag);
98
+ if (!router) {
99
+ core.ui.addRouter(say_view_tag, "ct");
100
+ router = core.ui.getRouter(say_view_tag);
101
+ }
102
+ if (!router.length) {
103
+ // @ts-ignore
104
+ router.push(say_view_name, message);
105
+ }
106
+ else {
107
+ // @ts-ignore
108
+ router.update(message);
109
+ }
110
+ if (wait) {
111
+ if (core.config.getConfig("game.autoplay.enable")) {
112
+ let delay = core.config.getConfig("game.autoplay.extra_delay") +
113
+ core.config.getConfig("game.autoplay.ms_per_char") *
114
+ what.length;
115
+ if (isNaN(delay) || !isFinite(delay) || delay < 0) {
116
+ throw `Say Action: AutoPlay Delay Error: ${delay} ms`;
117
+ }
118
+ core.system.pause(delay);
119
+ }
120
+ else {
121
+ core.system.pause();
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,112 @@
1
+ import { sayAction } from "./basic.js";
2
+ export function character_command(core) {
3
+ // character command
4
+ // Used to create a character, and save it to script field in archive storage,
5
+ // so that it can be used when the archive is loaded next time the game starts
6
+ // by loading the archive.
7
+ // syntax: character <short_name> <display_name>
8
+ // if the short name is conflict with an existing character, the script will throw an error
9
+ core.script.use((ctx, next) => {
10
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "character")
11
+ return next();
12
+ if (ctx.slicedArgs.length > 3)
13
+ throw `Character Command: incorrect amount of args`;
14
+ if (ctx.slicedArgs.length === 1)
15
+ throw `Character Command: incorrect amount of args`;
16
+ if (ctx.slicedArgs.length === 2)
17
+ throw `Character Command: display name not specified`;
18
+ if (ctx.slicedArgs[1].isQuoted)
19
+ throw `Character Command: short name should not be quoted`;
20
+ // Check if the short name is conflict with an existing character
21
+ let short_name = ctx.slicedArgs[1].str;
22
+ let characterMap = getCharacterMap();
23
+ if (characterMap[short_name] != null) {
24
+ if (characterMap[short_name].declare_info.path === ctx.currentPath &&
25
+ characterMap[short_name].declare_info.index === ctx.currentLineIndex) {
26
+ }
27
+ else
28
+ throw `Character Command: short name [${short_name}] conflict, at file [${characterMap[short_name].declare_info.path}] line [${characterMap[short_name].declare_info.index + 1}] and `;
29
+ }
30
+ else {
31
+ let display_name = ctx.slicedArgs[2].isQuoted
32
+ ? core.script.parseString(ctx.slicedArgs[2].str)
33
+ : ctx.slicedArgs[2].str;
34
+ characterMap[short_name] = buildCharacterInfo(short_name, display_name);
35
+ }
36
+ function buildCharacterInfo(short_name, display_name) {
37
+ return {
38
+ short_name,
39
+ display_name,
40
+ declare_info: {
41
+ path: ctx.currentPath,
42
+ index: ctx.currentLineIndex,
43
+ },
44
+ };
45
+ }
46
+ });
47
+ function getCharacterMap() {
48
+ // // Check core.storage.archiveData
49
+ // if (typeof core.storage.archiveData == null)
50
+ // throw `[HZEngine] ArchiveData is null`;
51
+ // if (typeof core.storage.archiveData != "object")
52
+ // throw `[HZEngine] ArchiveData is not a object(Record or Array)`;
53
+ // if (Array.isArray(core.storage.archiveData))
54
+ // throw `[HZEngine] ArchiveData is an Array`;
55
+ // // Check core.storage.archiveData.script
56
+ // if (core.storage.archiveData.script == null) {
57
+ // console.log(`[HZEngine] ArchiveData.script is null, create it`);
58
+ // core.storage.archiveData.script = {};
59
+ // }
60
+ // if (typeof core.storage.archiveData.script != "object")
61
+ // throw `[HZEngine] ArchiveData.script is not a object(Record or Array)`;
62
+ // if (Array.isArray(core.storage.archiveData.script))
63
+ // throw `[HZEngine] ArchiveData.script is an Array`;
64
+ // // Check core.storage.archiveData.script.characterMap
65
+ // if (core.storage.archiveData.script.characterMap == null) {
66
+ // console.log(
67
+ // `[HZEngine] ArchiveData.script.characterMap is null, create it`
68
+ // );
69
+ // core.storage.archiveData.script.characterMap = {};
70
+ // }
71
+ // if (typeof core.storage.archiveData.script.characterMap != "object")
72
+ // throw `[HZEngine] ArchiveData.script.characterMap is not a object(Record or Array)`;
73
+ // if (Array.isArray(core.storage.archiveData.script.characterMap))
74
+ // throw `[HZEngine] ArchiveData.script.characterMap is an Array`;
75
+ // return core.storage.archiveData.script.characterMap as any; // TODO
76
+ return core.storage.getSaveableData(core.storage.archiveData, true, "script", "characterMap");
77
+ }
78
+ // Gramma: %short_name% "{message}"
79
+ core.script.use((ctx, next) => {
80
+ if (ctx.slicedArgs[0].isQuoted)
81
+ return next();
82
+ let characterMap = getCharacterMap();
83
+ let short_name = ctx.slicedArgs[0].str;
84
+ for (let key in characterMap) {
85
+ // console.log(`Character Say Command: key=${key} sn=${short_name}`);
86
+ function parseSayCommandArgs() {
87
+ if (ctx.slicedArgs.length > 0 &&
88
+ ctx.slicedArgs[ctx.slicedArgs.length - 1].str === "nowait") {
89
+ ctx.slicedArgs = ctx.slicedArgs.slice(0, ctx.slicedArgs.length - 1);
90
+ return {
91
+ wait: false,
92
+ };
93
+ }
94
+ else {
95
+ return {
96
+ wait: true,
97
+ };
98
+ }
99
+ }
100
+ let parsed = parseSayCommandArgs();
101
+ if (key === short_name) {
102
+ if (ctx.slicedArgs.length != 2)
103
+ throw `Character Say Command: incorrect amount of args`;
104
+ console.log("Character Say Command:", short_name, ctx.slicedArgs[1].str);
105
+ sayAction(core, characterMap[key].display_name, ctx.slicedArgs[1].str, parsed.wait);
106
+ // if(parsed.wait) core.system.pause();
107
+ return;
108
+ }
109
+ }
110
+ return next();
111
+ });
112
+ }
@@ -0,0 +1,260 @@
1
+ export function conditional(core) {
2
+ // if ... [elif] ... [else] ... end if
3
+ // syntax:
4
+ // if <expression>
5
+ // <code>
6
+ // [elif <expression>]
7
+ // <code>
8
+ // [else]
9
+ // <code>
10
+ // end if
11
+ // if statement start
12
+ core.script.use((ctx, next) => {
13
+ if (ctx.slicedArgs[0].isQuoted ||
14
+ ctx.slicedArgs[0].str.toLowerCase() !== "if") {
15
+ return next();
16
+ }
17
+ let data = ctx.startStatement("if");
18
+ // console.log(`if data=${JSON.stringify(data)}`);
19
+ let if_expression_res = core.script.evalExpression(data.if_expression);
20
+ if (typeof if_expression_res !== "boolean") {
21
+ throw `If statement: if expression must return boolean, at file [${data.start_position[0]}] line [${data.start_position[1]}]`;
22
+ }
23
+ if (if_expression_res) {
24
+ // continue to execute next line
25
+ return;
26
+ }
27
+ // analyse elif
28
+ for (let i = 0; i < data.elif_list.length; i++) {
29
+ let item = data.elif_list[i];
30
+ let elif_expression_res = core.script.evalExpression(item.expression);
31
+ if (typeof elif_expression_res !== "boolean") {
32
+ throw `If statement: elif expression must return boolean, at file [${item.position[0]}] line [${item.position[1]}]`;
33
+ }
34
+ if (elif_expression_res) {
35
+ // jump to next line of elif statement
36
+ core.script.jump(item.position[0], item.position[1] + 1);
37
+ return;
38
+ }
39
+ }
40
+ // analyse else
41
+ if (data.else_position) {
42
+ core.script.jump(data.else_position[0], data.else_position[1] + 1);
43
+ return;
44
+ }
45
+ // the expressions are all false
46
+ // jump to the end of if statement
47
+ core.script.jump(data.end_position[0], data.end_position[1]);
48
+ });
49
+ // elif statement
50
+ // when come across next elif statement, jump to "end if" statement to stop execute.
51
+ core.script.use((ctx, next) => {
52
+ if (ctx.slicedArgs[0].isQuoted ||
53
+ ctx.slicedArgs[0].str.toLowerCase() !== "elif") {
54
+ return next();
55
+ }
56
+ if (ctx.statementStack.length === 0 ||
57
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "if") {
58
+ throw `If statement: elif statement must come after if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
59
+ }
60
+ let data = ctx.statementStack[ctx.statementStack.length - 1][2];
61
+ // check if this elif statement belong to the closest if statement
62
+ for (let i = 0; i < data.elif_list.length; i++) {
63
+ let item = data.elif_list[i];
64
+ if (item.position[0] === ctx.currentPath &&
65
+ item.position[1] === ctx.currentLineIndex) {
66
+ // jump to the "end if" statement
67
+ core.script.jump(data.end_position[0], data.end_position[1]);
68
+ return;
69
+ }
70
+ }
71
+ // the elif statement is not belong to the closest if statement, so throw error
72
+ throw `If statement: elif statement not belong to the closest if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
73
+ });
74
+ // else statement
75
+ core.script.use((ctx, next) => {
76
+ if (ctx.slicedArgs[0].isQuoted ||
77
+ ctx.slicedArgs[0].str.toLowerCase() !== "else") {
78
+ return next();
79
+ }
80
+ if (ctx.statementStack.length === 0 ||
81
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "if") {
82
+ throw `If statement: else statement must come after if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
83
+ }
84
+ let data = ctx.statementStack[ctx.statementStack.length - 1][2];
85
+ // check if this else statement belong to the closest if statement
86
+ if (data.else_position) {
87
+ if (data.else_position[0] === ctx.currentPath &&
88
+ data.else_position[1] === ctx.currentLineIndex) {
89
+ // jump to the "end if" statement
90
+ core.script.jump(data.end_position[0], data.end_position[1]);
91
+ return;
92
+ }
93
+ }
94
+ // the else statement is not belong to the closest if statement, so throw error
95
+ throw `If statement: else statement not belong to the closest if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
96
+ });
97
+ // end if statement
98
+ core.script.use((ctx, next) => {
99
+ if (ctx.rawtext.trim().split(/ +/).join(" ").toLowerCase() !== "end if") {
100
+ return next();
101
+ }
102
+ if (ctx.statementStack.length === 0 ||
103
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "if") {
104
+ throw `If statement: end if statement must come after if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
105
+ }
106
+ ctx.endStatement("if");
107
+ });
108
+ // analyse statement
109
+ // if statement
110
+ core.script.useAnalyseStatement((ctx, next) => {
111
+ if (ctx.slicedArgs[0].isQuoted ||
112
+ ctx.slicedArgs[0].str.toLowerCase() !== "if") {
113
+ return next();
114
+ }
115
+ if (ctx.slicedArgs.length < 2) {
116
+ throw `If statement: no expression specified, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
117
+ }
118
+ ctx.startStatement("if", {
119
+ start_position: [ctx.currentPath, ctx.currentLineIndex],
120
+ if_expression: ctx.rawtext.trim().slice(2).trim(),
121
+ elif_list: [],
122
+ else_position: null,
123
+ });
124
+ });
125
+ // elif statement
126
+ core.script.useAnalyseStatement((ctx, next) => {
127
+ if (ctx.slicedArgs[0].isQuoted ||
128
+ ctx.slicedArgs[0].str.toLowerCase() !== "elif") {
129
+ return next();
130
+ }
131
+ if (ctx.slicedArgs.length < 2) {
132
+ throw `If statement: no expression specified, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
133
+ }
134
+ // check if the closest statement is if statement
135
+ if (ctx.statementStack.length === 0 ||
136
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "if") {
137
+ throw `If statement: elif statement must come after if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
138
+ }
139
+ let data = ctx.statementStack[ctx.statementStack.length - 1][2];
140
+ data.elif_list.push({
141
+ position: [ctx.currentPath, ctx.currentLineIndex],
142
+ expression: ctx.rawtext.trim().slice(4).trim(),
143
+ });
144
+ });
145
+ // else statement
146
+ core.script.useAnalyseStatement((ctx, next) => {
147
+ if (ctx.slicedArgs[0].isQuoted ||
148
+ ctx.slicedArgs[0].str.toLowerCase() !== "else") {
149
+ return next();
150
+ }
151
+ // check if the closest statement is if statement
152
+ if (ctx.statementStack.length === 0 ||
153
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "if") {
154
+ throw `If statement: else statement must come after if statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
155
+ }
156
+ let data = ctx.statementStack[ctx.statementStack.length - 1][2];
157
+ data.else_position = [ctx.currentPath, ctx.currentLineIndex];
158
+ });
159
+ // end if statement
160
+ core.script.useAnalyseStatement((ctx, next) => {
161
+ if (ctx.rawtext.trim().split(/ +/).join(" ").toLowerCase() !== "end if") {
162
+ return next();
163
+ }
164
+ let data = ctx.endStatement("if");
165
+ data.end_position = [ctx.currentPath, ctx.currentLineIndex];
166
+ ctx.setStatementData(data, [...data.start_position]);
167
+ });
168
+ // while ... end while
169
+ // while statement start
170
+ core.script.use((ctx, next) => {
171
+ if (ctx.slicedArgs[0].isQuoted ||
172
+ ctx.slicedArgs[0].str.toLowerCase() !== "while") {
173
+ return next();
174
+ }
175
+ let data = ctx.startStatement("while");
176
+ // test if expression return boolean
177
+ let expression = data.while_expression;
178
+ let expression_res = core.script.evalExpression(expression);
179
+ if (typeof expression_res !== "boolean") {
180
+ throw `While statement: while expression must return boolean, at file [${data.start_position[0]}] line [${data.start_position[1]}]`;
181
+ }
182
+ if (!expression_res) {
183
+ ctx.endStatement("while");
184
+ core.script.jump(...data.end_position, false);
185
+ core.script.incrementNextPosition();
186
+ }
187
+ else {
188
+ return;
189
+ }
190
+ });
191
+ // while statement end
192
+ core.script.use((ctx, next) => {
193
+ if (ctx.rawtext.trim().split(/ +/).join(" ").toLowerCase() !== "end while") {
194
+ return next();
195
+ }
196
+ // check if the closest statement is while statement
197
+ if (ctx.statementStack.length === 0 ||
198
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "while") {
199
+ throw `While statement: end while statement must come after while statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
200
+ }
201
+ // jump to while statement start line (loop)
202
+ let data = ctx.statementStack[ctx.statementStack.length - 1][2];
203
+ ctx.endStatement("while");
204
+ core.script.jump(...data.start_position, false);
205
+ });
206
+ // analyse while statement start
207
+ core.script.useAnalyseStatement((ctx, next) => {
208
+ if (ctx.slicedArgs[0].isQuoted ||
209
+ ctx.slicedArgs[0].str.toLowerCase() !== "while") {
210
+ return next();
211
+ }
212
+ let while_expression = ctx.rawtext.trim().slice(5).trim();
213
+ if (while_expression === "") {
214
+ throw `While statement: no expression specified, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
215
+ }
216
+ ctx.startStatement("while", {
217
+ start_position: [ctx.currentPath, ctx.currentLineIndex],
218
+ while_expression,
219
+ end_position: [ctx.currentPath, ctx.currentLineIndex],
220
+ });
221
+ });
222
+ // analyse while statement end
223
+ core.script.useAnalyseStatement((ctx, next) => {
224
+ if (ctx.rawtext.trim().split(/ +/).join(" ").toLowerCase() !== "end while") {
225
+ return next();
226
+ }
227
+ let data = ctx.endStatement("while");
228
+ data.end_position = [ctx.currentPath, ctx.currentLineIndex];
229
+ ctx.setStatementData(data, [...data.start_position]);
230
+ });
231
+ // do ... end do until
232
+ // break command
233
+ core.script.use((ctx, next) => {
234
+ if (ctx.slicedArgs[0].isQuoted ||
235
+ ctx.slicedArgs.length !== 1 ||
236
+ ctx.slicedArgs[0].str.toLowerCase() !== "break") {
237
+ return next();
238
+ }
239
+ // find the closest breakable statement
240
+ // (currently only while statement is breakable)
241
+ //(debug) output stack
242
+ // console.log("Stack="+JSON.stringify(ctx.statementStack));
243
+ let resIndex = -1;
244
+ for (let i = ctx.statementStack.length - 1; i >= 0; i--) {
245
+ if (ctx.statementStack[i][0] === "while") {
246
+ resIndex = i;
247
+ break;
248
+ }
249
+ }
250
+ if (resIndex === -1) {
251
+ throw `Break command: break statement must come after while statement, at file [${ctx.currentPath}] line [${ctx.currentLineIndex}]`;
252
+ }
253
+ let data = ctx.statementStack[resIndex][2];
254
+ core.debug.log(`Break command: break from ${ctx.statementStack[resIndex][0]} statement at file [${data.start_position[0]}] line [${data.start_position[1] + 1}]`);
255
+ core.script.jump(...data.end_position, false);
256
+ core.script.incrementNextPosition();
257
+ // clear statement stack from breakable statement
258
+ ctx.statementStack.splice(resIndex + 1, ctx.statementStack.length - resIndex - 1);
259
+ });
260
+ }
@@ -0,0 +1,22 @@
1
+ export function config_command(core) {
2
+ // set command: set <key> <value>
3
+ core.script.use((ctx, next) => {
4
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "set")
5
+ return next();
6
+ if (ctx.slicedArgs.length !== 3)
7
+ throw `Set Command: incorrect amount of args`;
8
+ let key = ctx.slicedArgs[1].str;
9
+ let val = ctx.slicedArgs[2].str;
10
+ if (!ctx.slicedArgs[2].isQuoted) {
11
+ if (val === "true" || val === "false") {
12
+ val = val === "true";
13
+ }
14
+ else if (!isNaN(val)) {
15
+ val = Number(val);
16
+ }
17
+ else
18
+ throw `Set Command: value type not supported`;
19
+ }
20
+ core.config.setConfig(key, val);
21
+ });
22
+ }
@@ -0,0 +1,24 @@
1
+ import { splitStr2Strs } from "../../script/strtools.js";
2
+ export function decorator_module(core) {
3
+ core.script.use((ctx, next) => {
4
+ if (!ctx.slicedArgs[0].isSquared)
5
+ return next();
6
+ let decorator = ctx.slicedArgs[0].str.toLowerCase();
7
+ switch (splitStr2Strs(decorator).join("").toLowerCase()) {
8
+ case "real=true":
9
+ core.storage.globalData.realEnv = true;
10
+ break;
11
+ case "real":
12
+ if (!core.storage.globalData.realEnv) {
13
+ return;
14
+ }
15
+ break;
16
+ default:
17
+ core.debug.log(`Decorator: Unknown decorator [${decorator}]`);
18
+ }
19
+ ctx.rawtext = ctx.rawtext.trim().slice(ctx.slicedArgs[0].str.length + 2).trim();
20
+ if (!ctx.rawtext.length)
21
+ return;
22
+ return next();
23
+ }, true);
24
+ }
@@ -0,0 +1,67 @@
1
+ export function eval_module(core) {
2
+ // single line eval command
3
+ // syntax: eval <code>
4
+ core.script.use((ctx, next) => {
5
+ if (ctx.slicedArgs[0].isQuoted ||
6
+ ctx.slicedArgs[0].str.toLowerCase() !== "eval") {
7
+ return next();
8
+ }
9
+ if (ctx.slicedArgs.length === 1) {
10
+ throw `Eval Command: no code specified`;
11
+ }
12
+ if (ctx.slicedArgs.length === 2) {
13
+ core.script.evalScope(ctx.slicedArgs[1].str);
14
+ }
15
+ else {
16
+ // delete "eval" prefix
17
+ core.script.evalScope(ctx.rawtext.trim().slice(4).trim());
18
+ }
19
+ });
20
+ // multi line eval statement (script ... end script)
21
+ // syntax:
22
+ // script
23
+ // <code>
24
+ // end script
25
+ // script statement start
26
+ core.script.use((ctx, next) => {
27
+ if (ctx.rawtext.trim().split(" ")[0] !== "script") {
28
+ return next();
29
+ }
30
+ let data = ctx.startStatement("script");
31
+ core.script.evalScope(data.js_code_scope);
32
+ core.script.jump(data.end_position[0], data.end_position[1]);
33
+ });
34
+ // script statement end
35
+ core.script.use((ctx, next) => {
36
+ if (ctx.rawtext.trim().split(/ +/).join(" ") !== "end script")
37
+ return next();
38
+ ctx.endStatement("script");
39
+ });
40
+ // analyze script statement start
41
+ core.script.useAnalyseStatement((ctx, next) => {
42
+ if (ctx.rawtext.trim().split(" ")[0] !== "script") {
43
+ return next();
44
+ }
45
+ let data = ctx.startStatement("script");
46
+ data.start_position = [ctx.currentPath, ctx.currentLineIndex];
47
+ data.js_code_scope = "";
48
+ });
49
+ // analyze script code scope/statement end
50
+ core.script.useAnalyseStatement((ctx, next) => {
51
+ if (ctx.statementStack.length &&
52
+ ctx.statementStack[ctx.statementStack.length - 1][0] === "script") {
53
+ if (ctx.rawtext.trim().split(/ +/).join(" ") === "end script") {
54
+ // end script
55
+ let data = ctx.endStatement("script");
56
+ data.end_position = [ctx.currentPath, ctx.currentLineIndex];
57
+ ctx.setStatementData(data, [...data.start_position]);
58
+ }
59
+ else {
60
+ // add code line to code scope
61
+ ctx.statementStack[ctx.statementStack.length - 1][2].js_code_scope += ctx.rawtext.trim() + '\n';
62
+ }
63
+ }
64
+ else
65
+ return next();
66
+ }, true);
67
+ }