var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; // features/core/i18n/core.ts var I18n = class { constructor(defaultLang, messages) { this.defaultLang = defaultLang; this.messages = messages; } localize(localizer, value) { const res = localizer(value); return this.get(res[0], res[1]); } get(path, args, lang = this.defaultLang) { const [name, key] = path.split(".", 2); return this.messages[name]?.[lang]?.[key]?.(...args) ?? `<${lang}: ${path}>`; } }; // features/core/errors/AiSyntaxError.ts var AiSyntaxErrorId = /* @__PURE__ */ ((AiSyntaxErrorId2) => { AiSyntaxErrorId2[AiSyntaxErrorId2["invalidAttribute"] = 0] = "invalidAttribute"; AiSyntaxErrorId2[AiSyntaxErrorId2["UnExpectedToken"] = 1] = "UnExpectedToken"; AiSyntaxErrorId2[AiSyntaxErrorId2["MultipleStatementsOnSingleLine"] = 2] = "MultipleStatementsOnSingleLine"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingThenClause"] = 3] = "MissingThenClause"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingCondition"] = 4] = "MissingCondition"; AiSyntaxErrorId2[AiSyntaxErrorId2["SeparatorExpected"] = 5] = "SeparatorExpected"; AiSyntaxErrorId2[AiSyntaxErrorId2["NonNumericSign"] = 6] = "NonNumericSign"; AiSyntaxErrorId2[AiSyntaxErrorId2["CanNotUseSpacesInReference"] = 7] = "CanNotUseSpacesInReference"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingIdentifier"] = 8] = "MissingIdentifier"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingType"] = 9] = "MissingType"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingParams"] = 10] = "MissingParams"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingFunctionBody"] = 11] = "MissingFunctionBody"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingExpr"] = 12] = "MissingExpr"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingKeyword"] = 13] = "MissingKeyword"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingBody"] = 14] = "MissingBody"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingBracket"] = 15] = "MissingBracket"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingAttribute"] = 16] = "MissingAttribute"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingLineBreak"] = 17] = "MissingLineBreak"; AiSyntaxErrorId2[AiSyntaxErrorId2["MissingStatement"] = 18] = "MissingStatement"; return AiSyntaxErrorId2; })(AiSyntaxErrorId || {}); var AiSyntaxError = class extends Error { constructor(messageId, token, location) { super(AiSyntaxErrorId[messageId]); this.messageId = messageId; this.token = token; this.location = location; } }; var AiMissingKeywordError = class extends AiSyntaxError { constructor(keyword, token, location) { super(13 /* MissingKeyword */, token, location); this.keyword = keyword; } }; var AiMissingBracketError = class extends AiSyntaxError { constructor(bracket, token, location) { super(15 /* MissingBracket */, token, location); this.bracket = bracket; } }; // features/core/i18n/aiscript/syntaxError.ts var syntaxErrorMessage = { ja: { invalidAttribute() { return "\u4E0D\u6B63\u306AAttribute\u3067\u3059\u3002"; }, UnExpectedToken() { return `\u4E88\u671F\u3057\u306A\u3044\u30C8\u30FC\u30AF\u30F3\u304C\u73FE\u308C\u307E\u3057\u305F\u3002`; }, MultipleStatementsOnSingleLine() { return "\u8907\u6570\u306E\u30B9\u30C6\u30FC\u30C8\u30E1\u30F3\u30C8\u306F\u540C\u3058\u884C\u306B\u7F6E\u304F\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002"; }, MissingThenClause() { return "if\u6587\u306B\u306Fthen\u7BC0\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingCondition() { return "if\u6587\u306B\u306F\u6761\u4EF6\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, SeparatorExpected() { return "\u30BB\u30D1\u30EC\u30FC\u30BF\u30FC\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, NonNumericSign() { return "\u6570\u5024\u4EE5\u5916\u306B\u306F\u3053\u306E\u6F14\u7B97\u5B50\u306F\u4F7F\u3048\u307E\u305B\u3093\u3002"; }, CanNotUseSpacesInReference() { return "\u8B58\u5225\u5B50\u306B\u7A7A\u767D\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002"; }, MissingIdentifier() { return "\u8B58\u5225\u5B50\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingType() { return "\u578B\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingParams() { return "\u5F15\u6570\u90E8\u5206\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingFunctionBody() { return "\u95A2\u6570\u306B\u306F\u5185\u5BB9\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingExpr() { return "\u5F0F\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingKeyword(name) { return `\`${name}\`\u30AD\u30FC\u30EF\u30FC\u30C9\u304C\u5FC5\u8981\u3067\u3059\u3002`; }, MissingBody() { return `\u30B3\u30FC\u30C9\u30D6\u30ED\u30C3\u30AF\u304C\u5FC5\u8981\u3067\u3059\u3002`; }, MissingBracket(bracket) { return `\`${bracket}\`\u304C\u5FC5\u8981\u3067\u3059\u3002`; }, MissingAttribute() { return "Attribute\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingLineBreak() { return "\u6539\u884C\u304C\u5FC5\u8981\u3067\u3059\u3002"; }, MissingStatement() { return "\u30B9\u30C6\u30FC\u30C8\u30E1\u30F3\u30C8\u304C\u5FC5\u8981\u3067\u3059\u3002"; } } }; var parserErrorLocalizer = (err) => { if (err instanceof AiMissingBracketError) { return ["syntax.MissingBracket", [err.bracket]]; } else if (err instanceof AiMissingKeywordError) { return ["syntax.MissingKeyword", [err.keyword]]; } switch (err.messageId) { case 15 /* MissingBracket */: { return ["syntax.MissingBracket", [""]]; } case 13 /* MissingKeyword */: { return ["syntax.MissingKeyword", [""]]; } default: { const id = err.messageId; return [ `syntax.${AiSyntaxErrorId[id]}`, [] ]; } } }; // features/core/errors/AiTypeError.ts var AiTypeErrorKind = /* @__PURE__ */ ((AiTypeErrorKind2) => { AiTypeErrorKind2[AiTypeErrorKind2["AlreadyDeclaredVariable"] = 0] = "AlreadyDeclaredVariable"; AiTypeErrorKind2[AiTypeErrorKind2["NotAssignableType"] = 1] = "NotAssignableType"; AiTypeErrorKind2[AiTypeErrorKind2["CanNotCall"] = 2] = "CanNotCall"; AiTypeErrorKind2[AiTypeErrorKind2["MissingArgumentError"] = 3] = "MissingArgumentError"; AiTypeErrorKind2[AiTypeErrorKind2["InvalidArgumentError"] = 4] = "InvalidArgumentError"; AiTypeErrorKind2[AiTypeErrorKind2["CanNotAssignToImmutableVariable"] = 5] = "CanNotAssignToImmutableVariable"; AiTypeErrorKind2[AiTypeErrorKind2["UnDeclaredVariable"] = 6] = "UnDeclaredVariable"; AiTypeErrorKind2[AiTypeErrorKind2["CanNotReadProperty"] = 7] = "CanNotReadProperty"; return AiTypeErrorKind2; })(AiTypeErrorKind || {}); var AiTypeError = class extends Error { constructor(kind, location) { super(AiTypeErrorKind[kind]); this.kind = kind; this.location = location; } }; var AiAlreadyDeclaredVariableError = class extends AiTypeError { constructor(name, location) { super(0 /* AlreadyDeclaredVariable */, location); this.name = name; } }; var AiNotAssignableTypeError = class extends AiTypeError { constructor(left, right, location) { super(1 /* NotAssignableType */, location); this.left = left; this.right = right; } }; var AiCanNotCallError = class extends AiTypeError { constructor(type, location) { super(2 /* CanNotCall */, location); this.type = type; } }; var AiMissingArgumentError = class extends AiTypeError { constructor(pos, expectType, location) { super(3 /* MissingArgumentError */, location); this.pos = pos; this.expectType = expectType; } }; var AiInvalidArgumentError = class extends AiTypeError { constructor(pos, expectType, butType, location) { super(4 /* InvalidArgumentError */, location); this.pos = pos; this.expectType = expectType; this.butType = butType; } }; var AiCanNotAssignToImmutableVariableError = class extends AiTypeError { constructor(name, location) { super(5 /* CanNotAssignToImmutableVariable */, location); this.name = name; } }; var AiUnDeclaredVariableError = class extends AiTypeError { constructor(name, location) { super(6 /* UnDeclaredVariable */, location); this.name = name; } }; var AiCanNotReadPropertyError = class extends AiTypeError { constructor(targetType, name, location) { super(7 /* CanNotReadProperty */, location); this.targetType = targetType; this.name = name; } }; // features/core/i18n/aiscript/typeError.ts var typeErrorMessage = { ja: { NotAssignableType(dest, value) { return `\u578B\`${dest}\`\u306B\u3001\`${value}\`\u306F\u4EE3\u5165\u3067\u304D\u307E\u305B\u3093\u3002`; }, AlreadyDeclaredVariable(name) { return `\u5909\u6570\`${name}\`\u306F\u3059\u3067\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059\u3002`; }, CanNotCall(type) { return `\u578B\`${type}\`\u306F\u95A2\u6570\u578B\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002`; }, InvalidArgumentError(pos, dest, but) { return `${pos}\u756A\u76EE\u306E\u5F15\u6570\u306B\u306F\u578B\`${dest}\`\u304C\u5FC5\u8981\u3067\u3059\u304C\u3001\`${but}\`\u304C\u4E0E\u3048\u3089\u308C\u307E\u3057\u305F\u3002`; }, MissingArgumentError(pos, dest) { return `${pos}\u756A\u76EE\u306E\u5F15\u6570\u306B\u306F\u578B\`${dest}\`\u304C\u5FC5\u8981\u3067\u3059\u304C\u3001\u4F55\u3082\u4E0E\u3048\u3089\u308C\u3066\u3044\u307E\u305B\u3093\u3002`; }, CanNotAssignToImmutableVariable(name) { return `\u5909\u6570\`${name}\`\u306F\u4E0D\u5909\u306A\u306E\u3067\u3001\u65B0\u305F\u306B\u4EE3\u5165\u3059\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093\u3002`; }, UnDeclaredVariable(name) { return `\u5909\u6570\`${name}\`\u306F\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002`; }, CanNotReadProperty(target, name) { return `\u578B\`${target}\`\u304B\u3089\`${name}\`\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u8AAD\u307F\u53D6\u308C\u307E\u305B\u3093\u3002`; } } }; var typeErrorLocalizer = (error) => { if (error instanceof AiNotAssignableTypeError) { return ["typing.NotAssignableType", [error.left, error.right]]; } else if (error instanceof AiAlreadyDeclaredVariableError) { return ["typing.AlreadyDeclaredVariable", [error.name]]; } else if (error instanceof AiCanNotCallError) { return ["typing.CanNotCall", [error.type]]; } else if (error instanceof AiInvalidArgumentError) { return [ "typing.InvalidArgumentError", [error.pos, error.expectType, error.butType] ]; } else if (error instanceof AiMissingArgumentError) { return ["typing.MissingArgumentError", [error.pos, error.expectType]]; } else if (error instanceof AiCanNotAssignToImmutableVariableError) { return ["typing.CanNotAssignToImmutableVariable", [error.name]]; } else if (error instanceof AiUnDeclaredVariableError) { return ["typing.UnDeclaredVariable", [error.name]]; } else if (error instanceof AiCanNotReadPropertyError) { return ["typing.CanNotReadProperty", [error.targetType, error.name]]; } switch (error.kind) { case 0 /* AlreadyDeclaredVariable */: return ["typing.AlreadyDeclaredVariable", ["<:unknown:>"]]; case 1 /* NotAssignableType */: return ["typing.NotAssignableType", ["<:unknown:>", "<:unknown:>"]]; case 2 /* CanNotCall */: return ["typing.CanNotCall", ["<:unknown:>"]]; case 4 /* InvalidArgumentError */: return [ "typing.InvalidArgumentError", [-1, "<:unknown:>", "<:unknown:>"] ]; case 3 /* MissingArgumentError */: return ["typing.MissingArgumentError", [NaN, "<:unknown:>"]]; case 5 /* CanNotAssignToImmutableVariable */: return ["typing.CanNotAssignToImmutableVariable", ["<:unknown:>"]]; case 6 /* UnDeclaredVariable */: return ["typing.UnDeclaredVariable", ["<:unknown:>"]]; case 7 /* CanNotReadProperty */: return ["typing.CanNotReadProperty", ["<:unknown:>", "<:unknown:>"]]; } }; // features/core/i18n/aiscript/index.ts var initAiScriptI18n = (lang) => new I18n(lang, { syntax: syntaxErrorMessage, typing: typeErrorMessage }); // aiscript/src/error.ts var AiScriptError = class _AiScriptError extends Error { // name is read by Error.prototype.toString name = "AiScript"; info; loc; constructor(message, info) { super(message); this.info = info; if (Error.captureStackTrace) { Error.captureStackTrace(this, _AiScriptError); } } }; var NonAiScriptError = class extends AiScriptError { name = "Internal"; constructor(error) { super(error.message ?? `${error}`, error); } }; var AiScriptSyntaxError = class extends AiScriptError { constructor(message, loc2, info) { super(`${message} (Line ${loc2.line}, Column ${loc2.column})`, info); this.loc = loc2; } name = "Syntax"; }; var AiScriptNamespaceError = class extends AiScriptError { constructor(message, loc2, info) { super(`${message} (Line ${loc2.line}, Column ${loc2.column})`, info); this.loc = loc2; } name = "Namespace"; }; var AiScriptRuntimeError = class extends AiScriptError { name = "Runtime"; constructor(message, info) { super(message, info); } }; var AiScriptIndexOutOfRangeError = class extends AiScriptRuntimeError { constructor(message, info) { super(message, info); } }; // aiscript/src/parser/streams/char-stream.ts var CharStream = class { pages; firstPageIndex; lastPageIndex; pageIndex; address; _char; /** zero-based number */ line; /** zero-based number */ column; constructor(source, opts) { this.pages = /* @__PURE__ */ new Map(); this.pages.set(0, source); this.firstPageIndex = 0; this.lastPageIndex = 0; this.pageIndex = 0; this.address = 0; this.line = opts?.line ?? 0; this.column = opts?.column ?? 0; this.moveNext(); } /** * ストリームの終わりに達しているかどうかを取得します。 */ get eof() { return this.endOfPage && this.isLastPage; } /** * カーソル位置にある文字を取得します。 */ get char() { if (this.eof) { throw new Error("end of stream"); } return this._char; } /** * カーソル位置に対応するソースコード上の行番号と列番号を取得します。 */ getPos() { return { line: this.line + 1, column: this.column + 1 }; } /** * カーソル位置を次の文字へ進めます。 */ next() { if (!this.eof && this._char === "\n") { this.line++; this.column = 0; } else { this.column++; } this.incAddr(); this.moveNext(); } /** * カーソル位置を前の文字へ戻します。 */ prev() { this.decAddr(); this.movePrev(); } get isFirstPage() { return this.pageIndex <= this.firstPageIndex; } get isLastPage() { return this.pageIndex >= this.lastPageIndex; } get endOfPage() { const page = this.pages.get(this.pageIndex); return this.address >= page.length; } moveNext() { this.loadChar(); while (true) { if (!this.eof && this._char === "\r") { this.incAddr(); this.loadChar(); continue; } break; } } incAddr() { if (!this.endOfPage) { this.address++; } else if (!this.isLastPage) { this.pageIndex++; this.address = 0; } } movePrev() { this.loadChar(); while (true) { if (!this.eof && this._char === "\r") { this.decAddr(); this.loadChar(); continue; } break; } } decAddr() { if (this.address > 0) { this.address--; } else if (!this.isFirstPage) { this.pageIndex--; this.address = this.pages.get(this.pageIndex).length - 1; } } loadChar() { if (this.eof) { this._char = void 0; } else { this._char = this.pages.get(this.pageIndex)[this.address]; } } }; // aiscript/src/parser/token.ts var TokenKind = /* @__PURE__ */ ((TokenKind2) => { TokenKind2[TokenKind2["EOF"] = 0] = "EOF"; TokenKind2[TokenKind2["NewLine"] = 1] = "NewLine"; TokenKind2[TokenKind2["Identifier"] = 2] = "Identifier"; TokenKind2[TokenKind2["NumberLiteral"] = 3] = "NumberLiteral"; TokenKind2[TokenKind2["StringLiteral"] = 4] = "StringLiteral"; TokenKind2[TokenKind2["Template"] = 5] = "Template"; TokenKind2[TokenKind2["TemplateStringElement"] = 6] = "TemplateStringElement"; TokenKind2[TokenKind2["TemplateExprElement"] = 7] = "TemplateExprElement"; TokenKind2[TokenKind2["NullKeyword"] = 8] = "NullKeyword"; TokenKind2[TokenKind2["TrueKeyword"] = 9] = "TrueKeyword"; TokenKind2[TokenKind2["FalseKeyword"] = 10] = "FalseKeyword"; TokenKind2[TokenKind2["EachKeyword"] = 11] = "EachKeyword"; TokenKind2[TokenKind2["ForKeyword"] = 12] = "ForKeyword"; TokenKind2[TokenKind2["LoopKeyword"] = 13] = "LoopKeyword"; TokenKind2[TokenKind2["BreakKeyword"] = 14] = "BreakKeyword"; TokenKind2[TokenKind2["ContinueKeyword"] = 15] = "ContinueKeyword"; TokenKind2[TokenKind2["MatchKeyword"] = 16] = "MatchKeyword"; TokenKind2[TokenKind2["CaseKeyword"] = 17] = "CaseKeyword"; TokenKind2[TokenKind2["DefaultKeyword"] = 18] = "DefaultKeyword"; TokenKind2[TokenKind2["IfKeyword"] = 19] = "IfKeyword"; TokenKind2[TokenKind2["ElifKeyword"] = 20] = "ElifKeyword"; TokenKind2[TokenKind2["ElseKeyword"] = 21] = "ElseKeyword"; TokenKind2[TokenKind2["ReturnKeyword"] = 22] = "ReturnKeyword"; TokenKind2[TokenKind2["EvalKeyword"] = 23] = "EvalKeyword"; TokenKind2[TokenKind2["VarKeyword"] = 24] = "VarKeyword"; TokenKind2[TokenKind2["LetKeyword"] = 25] = "LetKeyword"; TokenKind2[TokenKind2["ExistsKeyword"] = 26] = "ExistsKeyword"; TokenKind2[TokenKind2["Not"] = 27] = "Not"; TokenKind2[TokenKind2["NotEq"] = 28] = "NotEq"; TokenKind2[TokenKind2["OpenSharpBracket"] = 29] = "OpenSharpBracket"; TokenKind2[TokenKind2["Sharp3"] = 30] = "Sharp3"; TokenKind2[TokenKind2["Percent"] = 31] = "Percent"; TokenKind2[TokenKind2["And2"] = 32] = "And2"; TokenKind2[TokenKind2["OpenParen"] = 33] = "OpenParen"; TokenKind2[TokenKind2["CloseParen"] = 34] = "CloseParen"; TokenKind2[TokenKind2["Asterisk"] = 35] = "Asterisk"; TokenKind2[TokenKind2["Plus"] = 36] = "Plus"; TokenKind2[TokenKind2["PlusEq"] = 37] = "PlusEq"; TokenKind2[TokenKind2["Comma"] = 38] = "Comma"; TokenKind2[TokenKind2["Minus"] = 39] = "Minus"; TokenKind2[TokenKind2["MinusEq"] = 40] = "MinusEq"; TokenKind2[TokenKind2["Dot"] = 41] = "Dot"; TokenKind2[TokenKind2["Slash"] = 42] = "Slash"; TokenKind2[TokenKind2["Colon"] = 43] = "Colon"; TokenKind2[TokenKind2["Colon2"] = 44] = "Colon2"; TokenKind2[TokenKind2["SemiColon"] = 45] = "SemiColon"; TokenKind2[TokenKind2["Lt"] = 46] = "Lt"; TokenKind2[TokenKind2["LtEq"] = 47] = "LtEq"; TokenKind2[TokenKind2["Out"] = 48] = "Out"; TokenKind2[TokenKind2["Eq"] = 49] = "Eq"; TokenKind2[TokenKind2["Eq2"] = 50] = "Eq2"; TokenKind2[TokenKind2["Arrow"] = 51] = "Arrow"; TokenKind2[TokenKind2["Gt"] = 52] = "Gt"; TokenKind2[TokenKind2["GtEq"] = 53] = "GtEq"; TokenKind2[TokenKind2["At"] = 54] = "At"; TokenKind2[TokenKind2["OpenBracket"] = 55] = "OpenBracket"; TokenKind2[TokenKind2["BackSlash"] = 56] = "BackSlash"; TokenKind2[TokenKind2["CloseBracket"] = 57] = "CloseBracket"; TokenKind2[TokenKind2["Hat"] = 58] = "Hat"; TokenKind2[TokenKind2["OpenBrace"] = 59] = "OpenBrace"; TokenKind2[TokenKind2["Or2"] = 60] = "Or2"; TokenKind2[TokenKind2["CloseBrace"] = 61] = "CloseBrace"; return TokenKind2; })(TokenKind || {}); var Token = class { constructor(kind, loc2, hasLeftSpacing = false, value, children) { this.kind = kind; this.loc = loc2; this.hasLeftSpacing = hasLeftSpacing; this.value = value; this.children = children; } }; function TOKEN(kind, loc2, opts) { return new Token(kind, loc2, opts?.hasLeftSpacing, opts?.value, opts?.children); } // aiscript/src/parser/scanner.ts var spaceChars = [" ", " "]; var lineBreakChars = ["\r", "\n"]; var digit = /^[0-9]$/; var wordChar = /^[A-Za-z0-9_]$/; var Scanner = class { stream; _tokens = []; constructor(x) { if (typeof x === "string") { this.stream = new CharStream(x); } else { this.stream = x; } this._tokens.push(this.readToken()); } /** * カーソル位置にあるトークンを取得します。 */ get token() { return this._tokens[0]; } /** * カーソル位置にあるトークンの種類を取得します。 */ get kind() { return this.token.kind; } /** * カーソル位置を次のトークンへ進めます。 */ next() { if (this._tokens[0].kind === 0 /* EOF */) { return; } this._tokens.shift(); if (this._tokens.length === 0) { this._tokens.push(this.readToken()); } } /** * トークンの先読みを行います。カーソル位置は移動されません。 */ lookahead(offset) { while (this._tokens.length <= offset) { this._tokens.push(this.readToken()); } return this._tokens[offset]; } /** * カーソル位置にあるトークンが指定したトークンの種類と一致するかを確認します。 * 一致しなかった場合には文法エラーを発生させます。 */ expect(kind) { if (this.kind !== kind) { throw new AiScriptSyntaxError(`unexpected token: ${TokenKind[this.kind]}`, this.token.loc); } } /** * カーソル位置にあるトークンが指定したトークンの種類と一致することを確認し、 * カーソル位置を次のトークンへ進めます。 */ nextWith(kind) { this.expect(kind); this.next(); } readToken() { let token; let hasLeftSpacing = false; while (true) { if (this.stream.eof) { token = TOKEN(0 /* EOF */, this.stream.getPos(), { hasLeftSpacing }); break; } if (spaceChars.includes(this.stream.char)) { this.stream.next(); hasLeftSpacing = true; continue; } const loc2 = this.stream.getPos(); if (lineBreakChars.includes(this.stream.char)) { this.stream.next(); token = TOKEN(1 /* NewLine */, loc2, { hasLeftSpacing }); return token; } switch (this.stream.char) { case "!": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(28 /* NotEq */, loc2, { hasLeftSpacing }); } else { token = TOKEN(27 /* Not */, loc2, { hasLeftSpacing }); } break; } case '"': case "'": { token = this.readStringLiteral(hasLeftSpacing); break; } case "#": { this.stream.next(); if (!this.stream.eof && this.stream.char === "#") { this.stream.next(); if (!this.stream.eof && this.stream.char === "#") { this.stream.next(); token = TOKEN(30 /* Sharp3 */, loc2, { hasLeftSpacing }); } } else if (!this.stream.eof && this.stream.char === "[") { this.stream.next(); token = TOKEN(29 /* OpenSharpBracket */, loc2, { hasLeftSpacing }); } else { throw new AiScriptSyntaxError('invalid character: "#"', loc2); } break; } case "%": { this.stream.next(); token = TOKEN(31 /* Percent */, loc2, { hasLeftSpacing }); break; } case "&": { this.stream.next(); if (!this.stream.eof && this.stream.char === "&") { this.stream.next(); token = TOKEN(32 /* And2 */, loc2, { hasLeftSpacing }); } break; } case "(": { this.stream.next(); token = TOKEN(33 /* OpenParen */, loc2, { hasLeftSpacing }); break; } case ")": { this.stream.next(); token = TOKEN(34 /* CloseParen */, loc2, { hasLeftSpacing }); break; } case "*": { this.stream.next(); token = TOKEN(35 /* Asterisk */, loc2, { hasLeftSpacing }); break; } case "+": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(37 /* PlusEq */, loc2, { hasLeftSpacing }); } else { token = TOKEN(36 /* Plus */, loc2, { hasLeftSpacing }); } break; } case ",": { this.stream.next(); token = TOKEN(38 /* Comma */, loc2, { hasLeftSpacing }); break; } case "-": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(40 /* MinusEq */, loc2, { hasLeftSpacing }); } else { token = TOKEN(39 /* Minus */, loc2, { hasLeftSpacing }); } break; } case ".": { this.stream.next(); token = TOKEN(41 /* Dot */, loc2, { hasLeftSpacing }); break; } case "/": { this.stream.next(); if (!this.stream.eof && this.stream.char === "*") { this.stream.next(); this.skipCommentRange(); continue; } else if (!this.stream.eof && this.stream.char === "/") { this.stream.next(); this.skipCommentLine(); continue; } else { token = TOKEN(42 /* Slash */, loc2, { hasLeftSpacing }); } break; } case ":": { this.stream.next(); if (!this.stream.eof && this.stream.char === ":") { this.stream.next(); token = TOKEN(44 /* Colon2 */, loc2, { hasLeftSpacing }); } else { token = TOKEN(43 /* Colon */, loc2, { hasLeftSpacing }); } break; } case ";": { this.stream.next(); token = TOKEN(45 /* SemiColon */, loc2, { hasLeftSpacing }); break; } case "<": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(47 /* LtEq */, loc2, { hasLeftSpacing }); } else if (!this.stream.eof && this.stream.char === ":") { this.stream.next(); token = TOKEN(48 /* Out */, loc2, { hasLeftSpacing }); } else { token = TOKEN(46 /* Lt */, loc2, { hasLeftSpacing }); } break; } case "=": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(50 /* Eq2 */, loc2, { hasLeftSpacing }); } else if (!this.stream.eof && this.stream.char === ">") { this.stream.next(); token = TOKEN(51 /* Arrow */, loc2, { hasLeftSpacing }); } else { token = TOKEN(49 /* Eq */, loc2, { hasLeftSpacing }); } break; } case ">": { this.stream.next(); if (!this.stream.eof && this.stream.char === "=") { this.stream.next(); token = TOKEN(53 /* GtEq */, loc2, { hasLeftSpacing }); } else { token = TOKEN(52 /* Gt */, loc2, { hasLeftSpacing }); } break; } case "@": { this.stream.next(); token = TOKEN(54 /* At */, loc2, { hasLeftSpacing }); break; } case "[": { this.stream.next(); token = TOKEN(55 /* OpenBracket */, loc2, { hasLeftSpacing }); break; } case "\\": { this.stream.next(); token = TOKEN(56 /* BackSlash */, loc2, { hasLeftSpacing }); break; } case "]": { this.stream.next(); token = TOKEN(57 /* CloseBracket */, loc2, { hasLeftSpacing }); break; } case "^": { this.stream.next(); token = TOKEN(58 /* Hat */, loc2, { hasLeftSpacing }); break; } case "`": { token = this.readTemplate(hasLeftSpacing); break; } case "{": { this.stream.next(); token = TOKEN(59 /* OpenBrace */, loc2, { hasLeftSpacing }); break; } case "|": { this.stream.next(); if (!this.stream.eof && this.stream.char === "|") { this.stream.next(); token = TOKEN(60 /* Or2 */, loc2, { hasLeftSpacing }); } break; } case "}": { this.stream.next(); token = TOKEN(61 /* CloseBrace */, loc2, { hasLeftSpacing }); break; } } if (token == null) { const digitToken = this.tryReadDigits(hasLeftSpacing); if (digitToken) { token = digitToken; break; } const wordToken = this.tryReadWord(hasLeftSpacing); if (wordToken) { token = wordToken; break; } throw new AiScriptSyntaxError(`invalid character: "${this.stream.char}"`, loc2); } break; } return token; } tryReadWord(hasLeftSpacing) { let value = ""; const loc2 = this.stream.getPos(); while (!this.stream.eof && wordChar.test(this.stream.char)) { value += this.stream.char; this.stream.next(); } if (value.length === 0) { return; } switch (value) { case "null": { return TOKEN(8 /* NullKeyword */, loc2, { hasLeftSpacing }); } case "true": { return TOKEN(9 /* TrueKeyword */, loc2, { hasLeftSpacing }); } case "false": { return TOKEN(10 /* FalseKeyword */, loc2, { hasLeftSpacing }); } case "each": { return TOKEN(11 /* EachKeyword */, loc2, { hasLeftSpacing }); } case "for": { return TOKEN(12 /* ForKeyword */, loc2, { hasLeftSpacing }); } case "loop": { return TOKEN(13 /* LoopKeyword */, loc2, { hasLeftSpacing }); } case "break": { return TOKEN(14 /* BreakKeyword */, loc2, { hasLeftSpacing }); } case "continue": { return TOKEN(15 /* ContinueKeyword */, loc2, { hasLeftSpacing }); } case "match": { return TOKEN(16 /* MatchKeyword */, loc2, { hasLeftSpacing }); } case "case": { return TOKEN(17 /* CaseKeyword */, loc2, { hasLeftSpacing }); } case "default": { return TOKEN(18 /* DefaultKeyword */, loc2, { hasLeftSpacing }); } case "if": { return TOKEN(19 /* IfKeyword */, loc2, { hasLeftSpacing }); } case "elif": { return TOKEN(20 /* ElifKeyword */, loc2, { hasLeftSpacing }); } case "else": { return TOKEN(21 /* ElseKeyword */, loc2, { hasLeftSpacing }); } case "return": { return TOKEN(22 /* ReturnKeyword */, loc2, { hasLeftSpacing }); } case "eval": { return TOKEN(23 /* EvalKeyword */, loc2, { hasLeftSpacing }); } case "var": { return TOKEN(24 /* VarKeyword */, loc2, { hasLeftSpacing }); } case "let": { return TOKEN(25 /* LetKeyword */, loc2, { hasLeftSpacing }); } case "exists": { return TOKEN(26 /* ExistsKeyword */, loc2, { hasLeftSpacing }); } default: { return TOKEN(2 /* Identifier */, loc2, { hasLeftSpacing, value }); } } } tryReadDigits(hasLeftSpacing) { let wholeNumber = ""; let fractional = ""; const loc2 = this.stream.getPos(); while (!this.stream.eof && digit.test(this.stream.char)) { wholeNumber += this.stream.char; this.stream.next(); } if (wholeNumber.length === 0) { return; } if (!this.stream.eof && this.stream.char === ".") { this.stream.next(); while (!this.stream.eof && digit.test(this.stream.char)) { fractional += this.stream.char; this.stream.next(); } if (fractional.length === 0) { throw new AiScriptSyntaxError("digit expected", loc2); } } let value; if (fractional.length > 0) { value = wholeNumber + "." + fractional; } else { value = wholeNumber; } return TOKEN(3 /* NumberLiteral */, loc2, { hasLeftSpacing, value }); } readStringLiteral(hasLeftSpacing) { let value = ""; const literalMark = this.stream.char; let state = "string"; const loc2 = this.stream.getPos(); this.stream.next(); while (state !== "finish") { switch (state) { case "string": { if (this.stream.eof) { throw new AiScriptSyntaxError("unexpected EOF", loc2); } if (this.stream.char === "\\") { this.stream.next(); state = "escape"; break; } if (this.stream.char === literalMark) { this.stream.next(); state = "finish"; break; } value += this.stream.char; this.stream.next(); break; } case "escape": { if (this.stream.eof) { throw new AiScriptSyntaxError("unexpected EOF", loc2); } value += this.stream.char; this.stream.next(); state = "string"; break; } } } return TOKEN(4 /* StringLiteral */, loc2, { hasLeftSpacing, value }); } readTemplate(hasLeftSpacing) { const elements = []; let buf = ""; let tokenBuf = []; let state = "string"; const loc2 = this.stream.getPos(); let elementLoc = loc2; this.stream.next(); while (state !== "finish") { switch (state) { case "string": { if (this.stream.eof) { throw new AiScriptSyntaxError("unexpected EOF", loc2); } if (this.stream.char === "\\") { this.stream.next(); state = "escape"; break; } if (this.stream.char === "`") { this.stream.next(); if (buf.length > 0) { elements.push(TOKEN(6 /* TemplateStringElement */, elementLoc, { hasLeftSpacing, value: buf })); } state = "finish"; break; } if (this.stream.char === "{") { this.stream.next(); if (buf.length > 0) { elements.push(TOKEN(6 /* TemplateStringElement */, elementLoc, { hasLeftSpacing, value: buf })); buf = ""; } elementLoc = this.stream.getPos(); state = "expr"; break; } buf += this.stream.char; this.stream.next(); break; } case "escape": { if (this.stream.eof) { throw new AiScriptSyntaxError("unexpected EOF", loc2); } buf += this.stream.char; this.stream.next(); state = "string"; break; } case "expr": { if (this.stream.eof) { throw new AiScriptSyntaxError("unexpected EOF", loc2); } if (spaceChars.includes(this.stream.char)) { this.stream.next(); continue; } if (this.stream.char === "}") { this.stream.next(); elements.push(TOKEN(7 /* TemplateExprElement */, elementLoc, { hasLeftSpacing, children: tokenBuf })); tokenBuf = []; elementLoc = this.stream.getPos(); state = "string"; break; } const token = this.readToken(); tokenBuf.push(token); break; } } } return TOKEN(5 /* Template */, loc2, { hasLeftSpacing, children: elements }); } skipCommentLine() { while (true) { if (this.stream.eof) { break; } if (this.stream.char === "\n") { this.stream.next(); break; } this.stream.next(); } } skipCommentRange() { while (true) { if (this.stream.eof) { break; } if (this.stream.char === "*") { this.stream.next(); if (this.stream.char === "/") { this.stream.next(); break; } continue; } this.stream.next(); } } }; // features/core/parser/utils.ts function NODE(type, params, loc2) { return { type, ...params, loc: loc2 }; } function CALL_NODE(name, args, loc2) { return NODE( "call", { target: NODE("identifier", { name }, loc2), args }, loc2 ); } // features/core/parser/syntaxes/common.ts function parseParams(s, e) { const items = []; if (s.token.kind != 33 /* OpenParen */) { return null; } s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } while (s.kind !== 34 /* CloseParen */) { if (s.kind !== 2 /* Identifier */) { e.push( new AiSyntaxError( 8 /* MissingIdentifier */, s.token, s.token.loc ) ); } const name = s.token.value; s.next(); let type; if (s.kind === 43 /* Colon */) { s.next(); type = parseType(s, e); } items.push({ name, argType: type ?? void 0 }); switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 34 /* CloseParen */: { break; } default: { throw new AiScriptSyntaxError("separator expected", s.token.loc); } } } if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } else { s.next(); } return items; } function parseBlock(s, e) { if (s.kind !== 59 /* OpenBrace */) return null; s.next(); while (s.kind === 1 /* NewLine */) { s.next(); } const steps = []; while (s.kind !== 61 /* CloseBrace */) { const stmt = parseStatement(s, e); if (stmt == null) { return null; } steps.push(stmt); switch (s.kind) { case 1 /* NewLine */: case 45 /* SemiColon */: { while ([1 /* NewLine */, 45 /* SemiColon */].includes(s.kind)) { s.next(); } break; } case 61 /* CloseBrace */: { break; } default: { throw new AiScriptSyntaxError( `Multiple statements cannot be placed on a single line.`, s.token.loc ); } } } if (s.kind !== 61 /* CloseBrace */) { e.push(new AiMissingBracketError("}", s.token, s.token.loc)); } else { s.next(); } return steps; } function parseType(s, e) { if (s.kind === 54 /* At */) { return parseFnType(s, e); } else { return parseNamedType(s, e); } } function parseFnType(s, e) { const loc2 = s.token.loc; if (s.kind !== 54 /* At */) { return null; } else { s.next(); } if (s.kind !== 33 /* OpenParen */) { e.push(new AiMissingBracketError("(", s.token, s.token.loc)); } else { s.next(); } const params = []; while (s.kind !== 34 /* CloseParen */) { if (params.length > 0) { switch (s.kind) { case 38 /* Comma */: { s.next(); break; } default: { throw new AiScriptSyntaxError("separator expected", s.token.loc); } } } const type = parseType(s, e); if (type == null) { e.push( new AiSyntaxError(9 /* MissingType */, s.token, s.token.loc) ); } else { params.push(type); } } if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } else { s.next(); } if (s.kind !== 51 /* Arrow */) { e.push(new AiMissingKeywordError("=>", s.token, s.token.loc)); } else { s.next(); } let resultType = parseType(s, e); if (resultType == null) { e.push( new AiSyntaxError(9 /* MissingType */, s.token, s.token.loc) ); resultType = NODE( "namedTypeSource", { name: "any", inner: void 0 }, s.token.loc ); } return NODE("fnTypeSource", { args: params, result: resultType }, loc2); } function parseNamedType(s, e) { const loc2 = s.token.loc; if (s.kind !== 2 /* Identifier */) { return null; } const name = s.token.value; s.next(); let inner = null; if (s.kind === 46 /* Lt */) { s.next(); inner = parseType(s, e); if (s.kind !== 52 /* Gt */) { e.push(new AiMissingBracketError(">", s.token, s.token.loc)); } else { s.next(); } } return NODE("namedTypeSource", { name, inner: inner ?? void 0 }, loc2); } // aiscript/src/parser/streams/token-stream.ts var TokenStream = class { source; index; _token; constructor(source) { this.source = source; this.index = 0; this.load(); } get eof() { return this.index >= this.source.length; } /** * カーソル位置にあるトークンを取得します。 */ get token() { if (this.eof) { return TOKEN(0 /* EOF */, { line: -1, column: -1 }); } return this._token; } /** * カーソル位置にあるトークンの種類を取得します。 */ get kind() { return this.token.kind; } /** * カーソル位置を次のトークンへ進めます。 */ next() { if (!this.eof) { this.index++; } this.load(); } /** * トークンの先読みを行います。カーソル位置は移動されません。 */ lookahead(offset) { if (this.index + offset < this.source.length) { return this.source[this.index + offset]; } else { return TOKEN(0 /* EOF */, { line: -1, column: -1 }); } } /** * カーソル位置にあるトークンが指定したトークンの種類と一致するかを確認します。 * 一致しなかった場合には文法エラーを発生させます。 */ expect(kind) { if (this.kind !== kind) { throw new AiScriptSyntaxError(`unexpected token: ${TokenKind[this.kind]}`, this.token.loc); } } /** * カーソル位置にあるトークンが指定したトークンの種類と一致することを確認し、 * カーソル位置を次のトークンへ進めます。 */ nextWith(kind) { this.expect(kind); this.next(); } load() { if (this.eof) { this._token = TOKEN(0 /* EOF */, { line: -1, column: -1 }); } else { this._token = this.source[this.index]; } } }; // features/core/parser/syntaxes/expressions.ts function parseExpr(s, e, isStatic) { if (isStatic) { return parseAtom(s, e, true); } else { return parsePratt(s, e, 0); } } var operators = [ { opKind: "postfix", kind: 33 /* OpenParen */, bp: 20 }, { opKind: "postfix", kind: 55 /* OpenBracket */, bp: 20 }, { opKind: "infix", kind: 41 /* Dot */, lbp: 18, rbp: 19 }, { opKind: "infix", kind: 58 /* Hat */, lbp: 17, rbp: 16 }, { opKind: "prefix", kind: 36 /* Plus */, bp: 14 }, { opKind: "prefix", kind: 39 /* Minus */, bp: 14 }, { opKind: "prefix", kind: 27 /* Not */, bp: 14 }, { opKind: "infix", kind: 35 /* Asterisk */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 42 /* Slash */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 31 /* Percent */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 36 /* Plus */, lbp: 10, rbp: 11 }, { opKind: "infix", kind: 39 /* Minus */, lbp: 10, rbp: 11 }, { opKind: "infix", kind: 46 /* Lt */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 47 /* LtEq */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 52 /* Gt */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 53 /* GtEq */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 50 /* Eq2 */, lbp: 6, rbp: 7 }, { opKind: "infix", kind: 28 /* NotEq */, lbp: 6, rbp: 7 }, { opKind: "infix", kind: 32 /* And2 */, lbp: 4, rbp: 5 }, { opKind: "infix", kind: 60 /* Or2 */, lbp: 2, rbp: 3 } ]; function parsePrefix(s, e, minBp) { const loc2 = s.token.loc; const op = s.kind; s.next(); if (s.kind === 56 /* BackSlash */) { s.next(); if (s.kind !== 1 /* NewLine */) { return null; } s.next(); } const expr = parsePratt(s, e, minBp); if (expr == null) return null; switch (op) { case 36 /* Plus */: { if (expr.type === "num") { return NODE("num", { value: expr.value }, loc2); } else { e.push(new AiSyntaxError(6 /* NonNumericSign */, expr, loc2)); } } case 39 /* Minus */: { if (expr.type === "num") { return NODE("num", { value: -1 * expr.value }, loc2); } else { e.push(new AiSyntaxError(6 /* NonNumericSign */, expr, loc2)); } } case 27 /* Not */: { return NODE("not", { expr }, loc2); } default: { e.push(new AiSyntaxError(6 /* NonNumericSign */, s.token, loc2)); } } return null; } function parseInfix(s, e, left, minBp) { const loc2 = s.token.loc; const op = s.kind; s.next(); if (s.kind === 56 /* BackSlash */) { s.next(); if (s.kind !== 1 /* NewLine */) { return null; } s.next(); } if (op === 41 /* Dot */) { let ident2; if (s.kind !== 2 /* Identifier */) { e.push( new AiSyntaxError(8 /* MissingIdentifier */, s.token, loc2) ); } else { ident2 = s.token; s.next(); } const name = ident2?.value ?? ""; return NODE( "prop", { target: left, name }, loc2 ); } else { let right; { const expr = parsePratt(s, e, minBp); if (expr == null) { e.push( new AiSyntaxError( 1 /* UnExpectedToken */, s.token, s.token.loc ) ); right = NODE("null", {}, s.token.loc); } else { right = expr; } } switch (op) { case 58 /* Hat */: { return CALL_NODE("Core:pow", [left, right], loc2); } case 35 /* Asterisk */: { return CALL_NODE("Core:mul", [left, right], loc2); } case 42 /* Slash */: { return CALL_NODE("Core:div", [left, right], loc2); } case 31 /* Percent */: { return CALL_NODE("Core:mod", [left, right], loc2); } case 36 /* Plus */: { return CALL_NODE("Core:add", [left, right], loc2); } case 39 /* Minus */: { return CALL_NODE("Core:sub", [left, right], loc2); } case 46 /* Lt */: { return CALL_NODE("Core:lt", [left, right], loc2); } case 47 /* LtEq */: { return CALL_NODE("Core:lteq", [left, right], loc2); } case 52 /* Gt */: { return CALL_NODE("Core:gt", [left, right], loc2); } case 53 /* GtEq */: { return CALL_NODE("Core:gteq", [left, right], loc2); } case 50 /* Eq2 */: { return CALL_NODE("Core:eq", [left, right], loc2); } case 28 /* NotEq */: { return CALL_NODE("Core:neq", [left, right], loc2); } case 32 /* And2 */: { return NODE("and", { left, right }, loc2); } case 60 /* Or2 */: { return NODE("or", { left, right }, loc2); } default: { e.push(new AiSyntaxError(6 /* NonNumericSign */, s.token, loc2)); } } } return null; } function parsePostfix(s, e, expr) { const loc2 = s.token.loc; const op = s.kind; switch (op) { case 33 /* OpenParen */: { return parseCall(s, e, expr); } case 55 /* OpenBracket */: { const bracketLoc = s.token.loc; s.next(); const index = parseExpr(s, e, false); if (index == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, bracketLoc) ); } if (s.kind !== 57 /* CloseBracket */) { e.push(new AiSyntaxError(15 /* MissingBracket */, s.token, loc2)); } else { s.next(); } return NODE( "index", { target: expr, index: index ?? NODE("null", {}, bracketLoc) }, loc2 ); } default: { e.push(new AiSyntaxError(6 /* NonNumericSign */, s.token, loc2)); return null; } } } function parseAtom(s, e, isStatic) { const loc2 = s.token.loc; switch (s.kind) { case 19 /* IfKeyword */: { if (isStatic) break; return parseIf(s, e); } case 54 /* At */: { if (isStatic) break; return parseFnExpr(s, e); } case 16 /* MatchKeyword */: { if (isStatic) break; return parseMatch(s, e); } case 23 /* EvalKeyword */: { if (isStatic) break; return parseEval(s, e); } case 26 /* ExistsKeyword */: { if (isStatic) break; return parseExists(s, e); } case 5 /* Template */: { const values = []; if (isStatic) break; for (const element of s.token.children) { switch (element.kind) { case 6 /* TemplateStringElement */: { values.push(NODE("str", { value: element.value }, element.loc)); break; } case 7 /* TemplateExprElement */: { const exprStream = new TokenStream(element.children); const expr = parseExpr(exprStream, e, false); if (expr == null || exprStream.kind !== 0 /* EOF */) { e.push( new AiSyntaxError(1 /* UnExpectedToken */, s.token, loc2) ); break; } values.push(expr ?? NODE("null", {}, s.token.loc)); break; } default: { e.push( new AiSyntaxError(1 /* UnExpectedToken */, s.token, loc2) ); break; } } } s.next(); return NODE("tmpl", { tmpl: values }, loc2); } case 4 /* StringLiteral */: { const value = s.token.value; s.next(); return NODE("str", { value }, loc2); } case 3 /* NumberLiteral */: { const value = Number(s.token.value); s.next(); return NODE("num", { value }, loc2); } case 9 /* TrueKeyword */: case 10 /* FalseKeyword */: { const value = s.kind === 9 /* TrueKeyword */; s.next(); return NODE("bool", { value }, loc2); } case 8 /* NullKeyword */: { s.next(); return NODE("null", {}, loc2); } case 59 /* OpenBrace */: { return parseObject(s, e, isStatic); } case 55 /* OpenBracket */: { return parseArray(s, e, isStatic); } case 2 /* Identifier */: { if (isStatic) break; return parseReference(s, e) ?? NODE("null", {}, s.token.loc); } case 33 /* OpenParen */: { s.next(); const expr = parseExpr(s, e, isStatic); if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } s.next(); return expr; } } return null; } function parseCall(s, e, target) { const loc2 = s.token.loc; const items = []; if (s.kind !== 33 /* OpenParen */) { return null; } s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } while (s.kind !== 34 /* CloseParen */) { items.push(parseExpr(s, e, false) ?? NODE("null", {}, s.token.loc)); switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 34 /* CloseParen */: { break; } default: { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); s.next(); break; } } } if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } else { s.next(); } return NODE( "call", { target, args: items }, loc2 ); } function parseIf(s, e) { const loc2 = s.token.loc; if (s.kind !== 19 /* IfKeyword */) { return null; } s.next(); let cond = parseExpr(s, e, false); let then = parseBlockOrStatement(s, e); if (cond == null) { e.push(new AiSyntaxError(4 /* MissingCondition */, s.token, loc2)); } if (then == null) { e.push(new AiSyntaxError(3 /* MissingThenClause */, s.token, loc2)); } if (s.kind === 1 /* NewLine */ && [20 /* ElifKeyword */, 21 /* ElseKeyword */].includes(s.lookahead(1).kind)) { s.next(); } const elseif = []; while (s.kind === 20 /* ElifKeyword */) { s.next(); const elifCond = parseExpr(s, e, false) ?? NODE("null", {}, s.token.loc); const elifThen = parseBlockOrStatement(s, e); if (s.kind === 1 /* NewLine */ && [20 /* ElifKeyword */, 21 /* ElseKeyword */].includes( s.lookahead(1).kind )) { s.next(); } elseif.push({ cond: elifCond, then: elifThen ?? NODE("block", { statements: [] }, elifCond.loc) }); } let _else = void 0; if (s.kind === 21 /* ElseKeyword */) { s.next(); _else = parseBlockOrStatement(s, e); if (_else == null) { e.push( new AiSyntaxError(14 /* MissingBody */, s.token, s.token.loc) ); } } return NODE( "if", { cond: cond ?? NODE("null", {}, s.token.loc), then: then ?? NODE("block", { statements: [] }, s.token.loc), elseif, else: _else ?? void 0 }, loc2 ); } function parseFnExpr(s, e) { const loc2 = s.token.loc; if (s.kind !== 54 /* At */) { return null; } s.next(); const params = parseParams(s, e); if (params == null) { e.push( new AiSyntaxError(10 /* MissingParams */, s.token, s.token.loc) ); } let type; if (s.kind === 43 /* Colon */) { s.next(); type = parseType(s, e); if (type == null) { e.push( new AiSyntaxError(9 /* MissingType */, s.token, s.token.loc) ); } } const body = parseBlock(s, e); if (body == null) { e.push( new AiSyntaxError(14 /* MissingBody */, s.token, s.token.loc) ); } return NODE( "fn", { args: params ?? [], retType: type ?? void 0, children: body ?? [] }, loc2 ); } function parseMatch(s, e) { const loc2 = s.token.loc; if (s.kind !== 16 /* MatchKeyword */) { return null; } let about = parseExpr(s, e, false); if (about === null) { e.push(new AiSyntaxError(12 /* MissingExpr */, s.token, loc2)); } if (s.kind !== 59 /* OpenBrace */) { e.push(new AiMissingBracketError("{", s.token, loc2)); } else { s.next(); } if (s.kind === 1 /* NewLine */) { s.next(); } const qs = []; while (s.kind !== 18 /* DefaultKeyword */ && s.kind !== 61 /* CloseBrace */) { if (s.kind !== 17 /* CaseKeyword */) { e.push(new AiMissingKeywordError("case", s.token, s.token.loc)); } else { s.next(); } const q = parseExpr(s, e, false) ?? NODE("null", {}, s.token.loc); if (s.kind !== 51 /* Arrow */) { e.push(new AiMissingKeywordError("=>", s.token, s.token.loc)); } else { s.next(); } const a = parseBlockOrStatement(s, e) ?? NODE("block", { statements: [] }, q.loc); qs.push({ q, a }); switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 18 /* DefaultKeyword */: case 61 /* CloseBrace */: { break; } default: { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } } } let x; if (s.kind === 18 /* DefaultKeyword */) { s.next(); if (s.kind !== 51 /* Arrow */) { e.push(new AiMissingKeywordError("=>", s.token, s.token.loc)); } else { s.next(); } x = parseBlockOrStatement(s, e); switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 61 /* CloseBrace */: { break; } default: { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } } } if (s.kind !== 61 /* CloseBrace */) { e.push(new AiMissingBracketError("}", s.token, s.token.loc)); } else { s.next(); } return NODE( "match", { about: about ?? NODE("null", {}, loc2), qs, default: x ?? void 0 }, loc2 ); } function parseEval(s, e) { const loc2 = s.token.loc; if (s.kind !== 23 /* EvalKeyword */) { return null; } s.next(); const statements = parseBlock(s, e); if (statements == null) { e.push(new AiSyntaxError(14 /* MissingBody */, s.token, loc2)); } return NODE("block", { statements: statements ?? [] }, loc2); } function parseExists(s, e) { const loc2 = s.token.loc; if (s.kind !== 26 /* ExistsKeyword */) { return null; } const identifier = parseReference(s, e); if (identifier == null) { e.push(new AiSyntaxError(8 /* MissingIdentifier */, s.token, loc2)); } return NODE( "exists", { identifier: identifier ?? NODE("identifier", { name: "" }, loc2) }, loc2 ); } function parseReference(s, e) { const loc2 = s.token.loc; const segs = []; while (true) { if (segs.length > 0) { if (s.kind === 43 /* Colon */) { if (s.token.hasLeftSpacing) { e.push( new AiSyntaxError( 7 /* CanNotUseSpacesInReference */, s.token, s.token.loc ) ); } s.next(); if (s.token.hasLeftSpacing) { e.push( new AiSyntaxError( 7 /* CanNotUseSpacesInReference */, s.token, s.token.loc ) ); } } else { break; } } if (s.kind !== 2 /* Identifier */) { return null; } segs.push(s.token.value); s.next(); } return NODE("identifier", { name: segs.join(":") }, loc2); } function parseObject(s, e, isStatic) { const loc2 = s.token.loc; if (s.kind !== 59 /* OpenBrace */) { return null; } s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } const map = /* @__PURE__ */ new Map(); while (s.kind !== 61 /* CloseBrace */) { let k; if (s.kind !== 2 /* Identifier */) { e.push( new AiSyntaxError( 8 /* MissingIdentifier */, s.token, s.token.loc ) ); k = ""; } else { k = s.token.value; s.next(); } if (s.kind !== 43 /* Colon */) { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } else { s.next(); } const v = parseExpr(s, e, isStatic); if (v == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } else { map.set(k, v); } switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 61 /* CloseBrace */: { break; } default: { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } } } if (s.kind !== 61 /* CloseBrace */) { e.push(new AiMissingBracketError("}", s.token, s.token.loc)); } else { s.next(); } return NODE("obj", { value: map }, loc2); } function parseArray(s, e, isStatic) { const loc2 = s.token.loc; if (s.kind !== 55 /* OpenBracket */) { return null; } s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } const value = []; while (s.kind !== 57 /* CloseBracket */) { const expr = parseExpr(s, e, isStatic); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } value.push(expr ?? NODE("null", {}, s.token.loc)); switch (s.kind) { case 1 /* NewLine */: { s.next(); break; } case 38 /* Comma */: { s.next(); if (s.kind === 1 /* NewLine */) { s.next(); } break; } case 57 /* CloseBracket */: { break; } default: { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } } } if (s.kind !== 57 /* CloseBracket */) { e.push(new AiMissingBracketError("]", s.token, s.token.loc)); } else { s.next(); } return NODE("arr", { value: value ?? [] }, loc2); } function parsePratt(s, e, minBp) { let left; const tokenKind = s.kind; const prefix = operators.find( (x) => x.opKind === "prefix" && x.kind === tokenKind ); if (prefix != null) { const expr = parsePrefix(s, e, prefix.bp); if (expr == null) return null; left = expr; } else { const expr = parseAtom(s, e, false); if (expr == null) return null; left = expr; } while (true) { if (s.kind === 56 /* BackSlash */) { s.next(); if (s.kind !== 1 /* NewLine */) { e.push( new AiSyntaxError( 17 /* MissingLineBreak */, s.token, s.token.loc ) ); } else { break; } } const tokenKind2 = s.kind; const postfix = operators.find( (x) => x.opKind === "postfix" && x.kind === tokenKind2 ); if (postfix != null) { if (postfix.bp < minBp) { break; } if ([55 /* OpenBracket */, 33 /* OpenParen */].includes(tokenKind2) && s.token.hasLeftSpacing) { } else { const expr = parsePostfix(s, e, left); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } left = expr ?? NODE("null", {}, s.token.loc); continue; } } const infix = operators.find( (x) => x.opKind === "infix" && x.kind === tokenKind2 ); if (infix != null) { if (infix.lbp < minBp) { break; } const expr = parseInfix(s, e, left, infix.rbp); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } left = expr ?? NODE("null", {}, s.token.loc); continue; } break; } return left; } // features/core/parser/syntaxes/statements.ts function parseStatement(s, e) { const loc2 = s.token.loc; switch (s.kind) { case 24 /* VarKeyword */: case 25 /* LetKeyword */: { return parseVarDef(s, e); } case 54 /* At */: { if (s.lookahead(1).kind === 2 /* Identifier */) { return parseFnDef(s, e); } break; } case 48 /* Out */: { return parseOut(s, e); } case 22 /* ReturnKeyword */: { return parseReturn(s, e); } case 29 /* OpenSharpBracket */: { return parseStatementWithAttr(s, e); } case 11 /* EachKeyword */: { return parseEach(s, e); } case 12 /* ForKeyword */: { return parseFor(s, e); } case 13 /* LoopKeyword */: { return parseLoop(s, e); } case 14 /* BreakKeyword */: { s.next(); return NODE("break", {}, loc2); } case 15 /* ContinueKeyword */: { s.next(); return NODE("continue", {}, loc2); } } const expr = parseExpr(s, e, false); if (expr == null) return null; const assign = tryParseAssign(s, e, expr); if (assign) { return assign; } return expr; } function parseDefStatement(s, e) { switch (s.kind) { case 24 /* VarKeyword */: case 25 /* LetKeyword */: { return parseVarDef(s, e); } case 54 /* At */: { return parseFnDef(s, e); } default: { e.push( new AiSyntaxError(1 /* UnExpectedToken */, s.token, s.token.loc) ); return null; } } } function parseBlockOrStatement(s, e) { const loc2 = s.token.loc; if (s.kind === 59 /* OpenBrace */) { const statements = parseBlock(s, e); return NODE("block", { statements: statements ?? [] }, loc2); } else { return parseStatement(s, e); } } function parseVarDef(s, e) { const loc2 = s.token.loc; let mut; switch (s.kind) { case 25 /* LetKeyword */: { mut = false; break; } case 24 /* VarKeyword */: { mut = true; break; } default: { e.push( new AiSyntaxError(1 /* UnExpectedToken */, s.token, s.token.loc) ); return null; } } s.next(); let name; if (s.kind === 2 /* Identifier */) { name = s.token.value ?? ""; s.next(); } else { e.push(new AiSyntaxError(8 /* MissingIdentifier */, s.token, loc2)); name = ""; } let type; if (s.kind === 43 /* Colon */) { s.next(); const tmp = parseType(s, e); if (tmp == null) { e.push( new AiSyntaxError(9 /* MissingType */, s.token, s.token.loc) ); type = void 0; } else { type = tmp; } } if (s.kind === 49 /* Eq */) { s.next(); } else { e.push(new AiMissingKeywordError("=", s.token, s.token.loc)); } if (s.kind === 1 /* NewLine */) { s.next(); } const expr = parseExpr(s, e, false); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } return NODE( "def", { name, varType: type ?? void 0, expr: expr ?? NODE("null", {}, s.token.loc), mut, attr: [] }, loc2 ); } function parseFnDef(s, e) { const loc2 = s.token.loc; if (s.kind !== 54 /* At */) { return null; } s.next(); let name; if (s.kind === 2 /* Identifier */) { name = s.token.value; s.next(); } else { e.push(new AiSyntaxError(8 /* MissingIdentifier */, s.token, loc2)); name = ""; } const params = parseParams(s, e); if (params == null) { e.push( new AiSyntaxError(10 /* MissingParams */, s.token, s.token.loc) ); } let type; if (s.kind === 43 /* Colon */) { s.next(); type = parseType(s, e); } const body = parseBlock(s, e); if (body == null) { e.push( new AiSyntaxError( 11 /* MissingFunctionBody */, s.token, s.token.loc ) ); } return NODE( "def", { name, varType: void 0, expr: NODE( "fn", { args: params ?? [], retType: type ?? void 0, children: body ?? [] }, loc2 ), mut: false, attr: [] }, loc2 ); } function parseOut(s, e) { const loc2 = s.token.loc; if (s.kind !== 48 /* Out */) { return null; } s.next(); const expr = parseExpr(s, e, false); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } return CALL_NODE("print", [expr ?? NODE("null", {}, s.token.loc)], loc2); } function parseEach(s, e) { const loc2 = s.token.loc; let hasParen = false; if (s.kind !== 11 /* EachKeyword */) { return null; } s.next(); if (s.kind === 33 /* OpenParen */) { hasParen = true; s.next(); } if (s.kind === 25 /* LetKeyword */) { s.next(); } else { e.push(new AiMissingKeywordError("let", s.token, s.token.loc)); } let name; if (s.kind === 2 /* Identifier */) { name = s.token.value; s.next(); } else { name = null; } if (s.kind === 38 /* Comma */) { s.next(); } else { e.push( new AiSyntaxError(5 /* SeparatorExpected */, s.token, s.token.loc) ); } const items = parseExpr(s, e, false); if (hasParen) { if (s.kind === 34 /* CloseParen */) { s.next(); } else { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); return NODE( "each", { var: name ?? "", items: items ?? NODE("null", {}, s.token.loc), for: NODE("block", { statements: [] }, s.token.loc) }, loc2 ); } } const body = parseBlockOrStatement(s, e); return NODE( "each", { var: name ?? "", items: items ?? NODE("null", {}, s.token.loc), for: body ?? NODE("block", { statements: [] }, s.token.loc) }, loc2 ); } function parseFor(s, e) { const loc2 = s.token.loc; let hasParen = false; if (s.kind !== 12 /* ForKeyword */) { return null; } s.next(); if (s.kind === 33 /* OpenParen */) { hasParen = true; s.next(); } if (s.kind === 25 /* LetKeyword */) { s.next(); const identLoc = s.token.loc; let name; if (s.kind !== 2 /* Identifier */) { e.push( new AiSyntaxError( 8 /* MissingIdentifier */, s.token, s.token.loc ) ); name = ""; } else { name = s.token.value; s.next(); } let _from; if (s.kind === 49 /* Eq */) { s.next(); _from = parseExpr(s, e, false); if (_from == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, identLoc) ); _from = NODE("num", { value: 0 }, identLoc); } } else { _from = NODE("num", { value: 0 }, identLoc); } if (s.kind === 38 /* Comma */) { s.next(); } else { e.push( new AiSyntaxError( 5 /* SeparatorExpected */, s.token, s.token.loc ) ); } const to = parseExpr(s, e, false); if (_from == null) { e.push(new AiSyntaxError(12 /* MissingExpr */, s.token, identLoc)); } if (hasParen) { if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } else { s.next(); } } const body = parseBlockOrStatement(s, e); if (body == null) { e.push( new AiSyntaxError(14 /* MissingBody */, s.token, s.token.loc) ); } return NODE( "for", { var: name, from: _from, to: to ?? NODE("num", { value: 0 }, s.token.loc), for: body ?? NODE("block", { statements: [] }, s.token.loc), times: void 0 }, loc2 ); } else { const times = parseExpr(s, e, false); if (times == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } if (hasParen) { if (s.kind !== 34 /* CloseParen */) { e.push(new AiMissingBracketError(")", s.token, s.token.loc)); } else { s.next(); } } const body = parseBlockOrStatement(s, e); if (body == null) { e.push( new AiSyntaxError(14 /* MissingBody */, s.token, s.token.loc) ); } return NODE( "for", { times: times ?? NODE("num", { value: 0 }, s.token.loc), for: body ?? NODE("block", { statements: [] }, s.token.loc), from: void 0, to: void 0, var: void 0 }, loc2 ); } } function parseReturn(s, e) { const loc2 = s.token.loc; if (s.kind !== 22 /* ReturnKeyword */) { return null; } s.next(); const expr = parseExpr(s, e, false); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } return NODE("return", { expr: expr ?? NODE("null", {}, s.token.loc) }, loc2); } function parseStatementWithAttr(s, e) { const attrs = []; while (s.kind === 29 /* OpenSharpBracket */) { const bracket = s.token; const attr = parseAttr(s, e); if (attr == null) { e.push( new AiSyntaxError( 16 /* MissingAttribute */, bracket, bracket.loc ) ); break; } attrs.push(attr); if (s.kind !== 1 /* NewLine */) { e.push( new AiSyntaxError(17 /* MissingLineBreak */, s.token, attr.loc) ); } else { s.next(); } } const statement = parseStatement(s, e); if (statement == null) { e.push( new AiSyntaxError(18 /* MissingStatement */, s.token, s.token.loc) ); } else if (statement.type !== "def") { e.push( new AiSyntaxError( 0 /* invalidAttribute */, statement, statement.loc ) ); return null; } else if (statement.attr != null) { statement.attr.push(...attrs); } else { statement.attr = attrs; } return statement; } function parseAttr(s, e) { const loc2 = s.token.loc; if (s.kind !== 29 /* OpenSharpBracket */) { return null; } s.next(); let name; if (s.kind === 2 /* Identifier */) { name = s.token.value; s.next(); } else { name = ""; e.push( new AiSyntaxError(8 /* MissingIdentifier */, s.token, s.token.loc) ); } let value; if (s.kind !== 57 /* CloseBracket */) { const expr = parseExpr(s, e, true); if (expr == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); value = NODE("bool", { value: true }, loc2); } else { value = expr; } } else { value = NODE("bool", { value: true }, loc2); } if (s.kind === 57 /* CloseBracket */) { s.next(); } else { e.push( new AiSyntaxError(15 /* MissingBracket */, s.token, s.token.loc) ); } return NODE("attr", { name, value }, loc2); } function parseLoop(s, e) { const loc2 = s.token.loc; if (s.kind !== 13 /* LoopKeyword */) { return null; } s.next(); const statements = parseBlock(s, e); if (statements == null) { e.push(new AiSyntaxError(14 /* MissingBody */, s.token, loc2)); } return NODE("loop", { statements: statements ?? [] }, loc2); } function tryParseAssign(s, e, dest) { const loc2 = s.token.loc; switch (s.kind) { case 49 /* Eq */: { s.next(); let expr = parseExpr(s, e, false); if (expr == null) { e.push(new AiSyntaxError(12 /* MissingExpr */, s.token, loc2)); expr = NODE("identifier", { name: "" }, loc2); } return NODE("assign", { dest, expr }, loc2); } case 37 /* PlusEq */: { s.next(); let expr = parseExpr(s, e, false); if (expr == null) { e.push(new AiSyntaxError(12 /* MissingExpr */, s.token, loc2)); expr = NODE("identifier", { name: "" }, loc2); } return NODE("addAssign", { dest, expr }, loc2); } case 40 /* MinusEq */: { s.next(); let expr = parseExpr(s, e, false); if (expr == null) { e.push(new AiSyntaxError(12 /* MissingExpr */, s.token, loc2)); expr = NODE("identifier", { name: "" }, loc2); } return NODE("subAssign", { dest, expr }, loc2); } default: { return; } } } // features/core/parser/syntaxes/toplevel.ts function parseTopLevel(s, e) { const nodes = []; while (s.kind === 1 /* NewLine */) { s.next(); } while (s.kind !== 0 /* EOF */) { switch (s.kind) { case 44 /* Colon2 */: { const ns = parseNamespace(s, e); if (ns == null) { break; } nodes.push(ns); break; } case 30 /* Sharp3 */: { nodes.push(parseMeta(s, e)); break; } default: { const stmt = parseStatement(s, e); if (stmt == null) { break; } nodes.push(stmt); break; } } switch (s.kind) { case 1 /* NewLine */: case 45 /* SemiColon */: { while ([1 /* NewLine */, 45 /* SemiColon */].includes(s.kind)) { s.next(); } break; } case 0 /* EOF */: { break; } default: { throw new AiScriptSyntaxError( "Multiple statements cannot be placed on a single line.", s.token.loc ); } } } return nodes; } function parseNamespace(s, e) { const loc2 = s.token.loc; s.nextWith(44 /* Colon2 */); s.expect(2 /* Identifier */); const name = s.token.value; s.next(); const members = []; s.nextWith(59 /* OpenBrace */); while (s.kind === 1 /* NewLine */) { s.next(); } while (s.kind !== 61 /* CloseBrace */) { switch (s.kind) { case 24 /* VarKeyword */: case 25 /* LetKeyword */: case 54 /* At */: { const stmt = parseDefStatement(s, e); if (stmt == null) { break; } members.push(stmt); break; } case 44 /* Colon2 */: { const ns = parseNamespace(s, e); if (ns == null) { break; } members.push(ns); break; } } switch (s.kind) { case 1 /* NewLine */: case 45 /* SemiColon */: { while ([1 /* NewLine */, 45 /* SemiColon */].includes(s.kind)) { s.next(); } break; } case 61 /* CloseBrace */: { break; } default: { e.push( new AiSyntaxError( 2 /* MultipleStatementsOnSingleLine */, s.token, s.token.loc ) ); return null; } } } s.nextWith(61 /* CloseBrace */); return NODE("ns", { name, members }, loc2); } function parseMeta(s, e) { const loc2 = s.token.loc; s.nextWith(30 /* Sharp3 */); let name = null; if (s.kind === 2 /* Identifier */) { name = s.token.value; s.next(); } const value = parseExpr(s, e, true); if (value == null) { e.push( new AiSyntaxError(12 /* MissingExpr */, s.token, s.token.loc) ); } return NODE( "meta", { name, value: value ?? NODE("null", {}, s.token.loc) }, loc2 ); } // features/core/parser/index.ts var Parser = class { constructor() { } parseFromString(text, errors) { return parseTopLevel(new Scanner(text), errors); } parseFromScanner(scanner, errors) { return parseTopLevel(scanner, errors); } }; // features/core/server/LanguageServer.ts import { DiagnosticSeverity, TextDocuments, TextDocumentSyncKind } from "vscode-languageserver"; import { TextDocument } from "vscode-languageserver-textdocument"; // features/core/server/location.ts function aiLocation2LspPosition(location) { return { character: location.column - 1, line: location.line - 1 }; } // aiscript/src/utils/mini-autobind.ts function autobind(target, key, descriptor) { let fn = descriptor.value; return { configurable: true, get() { const bound = fn.bind(this); Object.defineProperty(this, key, { configurable: true, writable: true, value: bound }); return bound; }, set(newFn) { fn = newFn; } }; } // aiscript/src/interpreter/scope.ts var _Scope = class _Scope { parent; layerdStates; name; opts = {}; constructor(layerdStates = [], parent, name) { this.layerdStates = layerdStates; this.parent = parent; this.name = name || (layerdStates.length === 1 ? "" : ""); } log(type, params) { if (this.parent) { this.parent.log(type, params); } else { if (this.opts.log) this.opts.log(type, params); } } onUpdated(name, value) { if (this.parent) { this.parent.onUpdated(name, value); } else { if (this.opts.onUpdated) this.opts.onUpdated(name, value); } } createChildScope(states = /* @__PURE__ */ new Map(), name) { const layer = [states, ...this.layerdStates]; return new _Scope(layer, this, name); } get(name) { for (const layer of this.layerdStates) { if (layer.has(name)) { const state = layer.get(name).value; this.log("read", { var: name, val: state }); return state; } } throw new AiScriptRuntimeError( `No such variable '${name}' in scope '${this.name}'`, { scope: this.layerdStates } ); } exists(name) { for (const layer of this.layerdStates) { if (layer.has(name)) { this.log("exists", { var: name }); return true; } } this.log("not exists", { var: name }); return false; } getAll() { const vars = this.layerdStates.reduce((arr, layer) => { return [...arr, ...layer]; }, []); return new Map(vars); } add(name, variable) { this.log("add", { var: name, val: variable }); const states = this.layerdStates[0]; if (states.has(name)) { throw new AiScriptRuntimeError( `Variable '${name}' is alerady exists in scope '${this.name}'`, { scope: this.layerdStates } ); } states.set(name, variable); if (this.parent == null) this.onUpdated(name, variable.value); } assign(name, val) { let i = 1; for (const layer of this.layerdStates) { if (layer.has(name)) { const variable = layer.get(name); if (!variable.isMutable) { throw new AiScriptRuntimeError(`Cannot assign to an immutable variable ${name}.`); } variable.value = val; this.log("assign", { var: name, val }); if (i === this.layerdStates.length) this.onUpdated(name, val); return; } i++; } throw new AiScriptRuntimeError( `No such variable '${name}' in scope '${this.name}'`, { scope: this.layerdStates } ); } }; __decorateClass([ autobind ], _Scope.prototype, "log", 1); __decorateClass([ autobind ], _Scope.prototype, "onUpdated", 1); __decorateClass([ autobind ], _Scope.prototype, "createChildScope", 1); __decorateClass([ autobind ], _Scope.prototype, "get", 1); __decorateClass([ autobind ], _Scope.prototype, "exists", 1); __decorateClass([ autobind ], _Scope.prototype, "getAll", 1); __decorateClass([ autobind ], _Scope.prototype, "add", 1); __decorateClass([ autobind ], _Scope.prototype, "assign", 1); var Scope = _Scope; // aiscript/src/interpreter/lib/std.ts import { v4 as uuid } from "uuid"; import seedrandom from "seedrandom"; // aiscript/src/interpreter/value.ts var NULL = { type: "null" }; var TRUE = { type: "bool", value: true }; var FALSE = { type: "bool", value: false }; var NUM = (num) => ({ type: "num", value: num }); var STR = (str) => ({ type: "str", value: str }); var BOOL = (bool) => ({ type: "bool", value: bool }); var OBJ = (obj) => ({ type: "obj", value: obj }); var ARR = (arr) => ({ type: "arr", value: arr }); var FN = (args, statements, scope) => ({ type: "fn", args, statements, scope }); var FN_NATIVE = (fn) => ({ type: "fn", native: fn }); var RETURN = (v) => ({ type: "return", value: v }); var BREAK = () => ({ type: "break", value: null }); var CONTINUE = () => ({ type: "continue", value: null }); var unWrapRet = (v) => v.type === "return" ? v.value : v; var ERROR = (name, info) => ({ type: "error", value: name, info }); // aiscript/src/interpreter/util.ts function expectAny(val) { if (val == null) { throw new AiScriptRuntimeError("Expect anything, but got nothing."); } } function assertBoolean(val) { if (val == null) { throw new AiScriptRuntimeError("Expect boolean, but got nothing."); } if (val.type !== "bool") { throw new AiScriptRuntimeError(`Expect boolean, but got ${val.type}.`); } } function assertFunction(val) { if (val == null) { throw new AiScriptRuntimeError("Expect function, but got nothing."); } if (val.type !== "fn") { throw new AiScriptRuntimeError(`Expect function, but got ${val.type}.`); } } function assertString(val) { if (val == null) { throw new AiScriptRuntimeError("Expect string, but got nothing."); } if (val.type !== "str") { throw new AiScriptRuntimeError(`Expect string, but got ${val.type}.`); } } function assertNumber(val) { if (val == null) { throw new AiScriptRuntimeError("Expect number, but got nothing."); } if (val.type !== "num") { throw new AiScriptRuntimeError(`Expect number, but got ${val.type}.`); } } function assertObject(val) { if (val == null) { throw new AiScriptRuntimeError("Expect object, but got nothing."); } if (val.type !== "obj") { throw new AiScriptRuntimeError(`Expect object, but got ${val.type}.`); } } function assertArray(val) { if (val == null) { throw new AiScriptRuntimeError("Expect array, but got nothing."); } if (val.type !== "arr") { throw new AiScriptRuntimeError(`Expect array, but got ${val.type}.`); } } function isObject(val) { return val.type === "obj"; } function isArray(val) { return val.type === "arr"; } function eq(a, b) { if (a.type === "fn" || b.type === "fn") return false; if (a.type === "null" && b.type === "null") return true; if (a.type === "null" || b.type === "null") return false; return a.value === b.value; } function valToJs(val) { switch (val.type) { case "fn": return ""; case "arr": return val.value.map((item) => valToJs(item)); case "bool": return val.value; case "null": return null; case "num": return val.value; case "obj": { const obj = {}; for (const [k, v] of val.value.entries()) { obj[k] = valToJs(v); } return obj; } case "str": return val.value; default: throw new Error(`Unrecognized value type: ${val.type}`); } } function jsToVal(val) { if (val === null) return NULL; if (typeof val === "boolean") return BOOL(val); if (typeof val === "string") return STR(val); if (typeof val === "number") return NUM(val); if (Array.isArray(val)) return ARR(val.map((item) => jsToVal(item))); if (typeof val === "object") { const obj = /* @__PURE__ */ new Map(); for (const [k, v] of Object.entries(val)) { obj.set(k, jsToVal(v)); } return OBJ(obj); } return NULL; } function reprValue(value, literalLike = false, processedObjects = /* @__PURE__ */ new Set()) { if ((value.type === "arr" || value.type === "obj") && processedObjects.has(value.value)) { return "..."; } if (literalLike && value.type === "str") return '"' + value.value.replace(/["\\\r\n]/g, (x) => `\\${x}`) + '"'; if (value.type === "str") return value.value; if (value.type === "num") return value.value.toString(); if (value.type === "arr") { processedObjects.add(value.value); const content = []; for (const item of value.value) { content.push(reprValue(item, true, processedObjects)); } return "[ " + content.join(", ") + " ]"; } if (value.type === "obj") { processedObjects.add(value.value); const content = []; for (const [key, val] of value.value) { content.push(`${key}: ${reprValue(val, true, processedObjects)}`); } return "{ " + content.join(", ") + " }"; } if (value.type === "bool") return value.value.toString(); if (value.type === "null") return "null"; if (value.type === "fn") { return `@( ${(value.args ?? []).join(", ")} ) { ... }`; } return "?"; } // aiscript/src/interpreter/lib/std.ts var std = { "help": STR("SEE: https://github.com/syuilo/aiscript/blob/master/docs/get-started.md"), //#region Core "Core:v": STR("0.16.0"), // TODO: package.jsonを参照 "Core:ai": STR("kawaii"), "Core:not": FN_NATIVE(([a]) => { assertBoolean(a); return a.value ? FALSE : TRUE; }), "Core:eq": FN_NATIVE(([a, b]) => { expectAny(a); expectAny(b); return eq(a, b) ? TRUE : FALSE; }), "Core:neq": FN_NATIVE(([a, b]) => { expectAny(a); expectAny(b); return eq(a, b) ? FALSE : TRUE; }), "Core:and": FN_NATIVE(([a, b]) => { assertBoolean(a); if (!a.value) return FALSE; assertBoolean(b); return b.value ? TRUE : FALSE; }), "Core:or": FN_NATIVE(([a, b]) => { assertBoolean(a); if (a.value) return TRUE; assertBoolean(b); return b.value ? TRUE : FALSE; }), "Core:add": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(a.value + b.value); }), "Core:sub": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(a.value - b.value); }), "Core:mul": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(a.value * b.value); }), "Core:pow": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); const res = a.value ** b.value; if (isNaN(res)) throw new AiScriptRuntimeError("Invalid operation."); return NUM(res); }), "Core:div": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); const res = a.value / b.value; if (isNaN(res)) throw new AiScriptRuntimeError("Invalid operation."); return NUM(res); }), "Core:mod": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(a.value % b.value); }), "Core:gt": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return a.value > b.value ? TRUE : FALSE; }), "Core:lt": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return a.value < b.value ? TRUE : FALSE; }), "Core:gteq": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return a.value >= b.value ? TRUE : FALSE; }), "Core:lteq": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return a.value <= b.value ? TRUE : FALSE; }), "Core:type": FN_NATIVE(([v]) => { expectAny(v); return STR(v.type); }), "Core:to_str": FN_NATIVE(([v]) => { expectAny(v); return STR(reprValue(v)); }), "Core:range": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); if (a.value < b.value) { return ARR(Array.from({ length: b.value - a.value + 1 }, (_, i) => NUM(i + a.value))); } else if (a.value > b.value) { return ARR(Array.from({ length: a.value - b.value + 1 }, (_, i) => NUM(a.value - i))); } else { return ARR([a]); } }), "Core:sleep": FN_NATIVE(async ([delay]) => { assertNumber(delay); await new Promise((r) => setTimeout(r, delay.value)); return NULL; }), //#endregion //#region Util "Util:uuid": FN_NATIVE(() => { return STR(uuid()); }), //#endregion //#region Json "Json:stringify": FN_NATIVE(([v]) => { expectAny(v); return STR(JSON.stringify(valToJs(v))); }), "Json:parse": FN_NATIVE(([json]) => { assertString(json); try { return jsToVal(JSON.parse(json.value)); } catch (e) { return ERROR("not_json"); } }), "Json:parsable": FN_NATIVE(([str]) => { assertString(str); try { JSON.parse(str.value); } catch (e) { return BOOL(false); } return BOOL(true); }), //#endregion //#region Date "Date:now": FN_NATIVE(() => { return NUM(Date.now()); }), "Date:year": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getFullYear()); }), "Date:month": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getMonth() + 1); }), "Date:day": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getDate()); }), "Date:hour": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getHours()); }), "Date:minute": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getMinutes()); }), "Date:second": FN_NATIVE(([v]) => { if (v) { assertNumber(v); } return NUM(new Date(v?.value || Date.now()).getSeconds()); }), "Date:parse": FN_NATIVE(([v]) => { assertString(v); return NUM(new Date(v.value).getTime()); }), //#endregion //#region Math "Math:Infinity": NUM(Infinity), "Math:E": NUM(Math.E), "Math:LN2": NUM(Math.LN2), "Math:LN10": NUM(Math.LN10), "Math:LOG2E": NUM(Math.LOG2E), "Math:LOG10E": NUM(Math.LOG10E), "Math:PI": NUM(Math.PI), "Math:SQRT1_2": NUM(Math.SQRT1_2), "Math:SQRT2": NUM(Math.SQRT2), "Math:abs": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.abs(v.value)); }), "Math:acos": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.acos(v.value)); }), "Math:acosh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.acosh(v.value)); }), "Math:asin": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.asin(v.value)); }), "Math:asinh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.asinh(v.value)); }), "Math:atan": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.atan(v.value)); }), "Math:atanh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.atanh(v.value)); }), "Math:atan2": FN_NATIVE(([y, x]) => { assertNumber(y); assertNumber(x); return NUM(Math.atan2(y.value, x.value)); }), "Math:cbrt": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.cbrt(v.value)); }), "Math:ceil": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.ceil(v.value)); }), "Math:clz32": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.clz32(v.value)); }), "Math:cos": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.cos(v.value)); }), "Math:cosh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.cosh(v.value)); }), "Math:exp": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.exp(v.value)); }), "Math:expm1": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.expm1(v.value)); }), "Math:floor": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.floor(v.value)); }), "Math:fround": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.fround(v.value)); }), "Math:hypot": FN_NATIVE(([vs]) => { assertArray(vs); const values = []; for (const v of vs.value) { assertNumber(v); values.push(v.value); } return NUM(Math.hypot(...values)); }), "Math:imul": FN_NATIVE(([x, y]) => { assertNumber(x); assertNumber(y); return NUM(Math.imul(x.value, y.value)); }), "Math:log": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.log(v.value)); }), "Math:log1p": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.log1p(v.value)); }), "Math:log10": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.log10(v.value)); }), "Math:log2": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.log2(v.value)); }), "Math:max": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(Math.max(a.value, b.value)); }), "Math:min": FN_NATIVE(([a, b]) => { assertNumber(a); assertNumber(b); return NUM(Math.min(a.value, b.value)); }), "Math:pow": FN_NATIVE(([x, y]) => { assertNumber(x); assertNumber(y); return NUM(Math.pow(x.value, y.value)); }), "Math:round": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.round(v.value)); }), "Math:sign": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.sign(v.value)); }), "Math:sin": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.sin(v.value)); }), "Math:sinh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.sinh(v.value)); }), "Math:sqrt": FN_NATIVE(([v]) => { assertNumber(v); const res = Math.sqrt(v.value); if (isNaN(res)) throw new AiScriptRuntimeError("Invalid operation."); return NUM(res); }), "Math:tan": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.tan(v.value)); }), "Math:tanh": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.tanh(v.value)); }), "Math:trunc": FN_NATIVE(([v]) => { assertNumber(v); return NUM(Math.trunc(v.value)); }), "Math:rnd": FN_NATIVE(([min, max]) => { if (min && min.type === "num" && max && max.type === "num") { return NUM(Math.floor(Math.random() * (Math.floor(max.value) - Math.ceil(min.value) + 1) + Math.ceil(min.value))); } return NUM(Math.random()); }), "Math:gen_rng": FN_NATIVE(([seed]) => { expectAny(seed); if (seed.type !== "num" && seed.type !== "str") return NULL; const rng = seedrandom(seed.value.toString()); return FN_NATIVE(([min, max]) => { if (min && min.type === "num" && max && max.type === "num") { return NUM(Math.floor(rng() * (Math.floor(max.value) - Math.ceil(min.value) + 1) + Math.ceil(min.value))); } return NUM(rng()); }); }), //#endregion //#region Num "Num:to_hex": FN_NATIVE(([v]) => { assertNumber(v); return STR(v.value.toString(16)); }), "Num:from_hex": FN_NATIVE(([v]) => { assertString(v); return NUM(parseInt(v.value, 16)); }), //#endregion //#region Str "Str:lf": STR("\n"), "Str:lt": FN_NATIVE(([a, b]) => { assertString(a); assertString(b); if (a.value < b.value) { return NUM(-1); } else if (a.value === b.value) { return NUM(0); } else { return NUM(1); } }), "Str:gt": FN_NATIVE(([a, b]) => { assertString(a); assertString(b); if (a.value > b.value) { return NUM(-1); } else if (a.value === b.value) { return NUM(0); } else { return NUM(1); } }), "Str:from_codepoint": FN_NATIVE(([codePoint]) => { assertNumber(codePoint); return STR(String.fromCodePoint(codePoint.value)); }), //#endregion //#region Arr //#endregion //#region Obj "Obj:keys": FN_NATIVE(([obj]) => { assertObject(obj); return ARR(Array.from(obj.value.keys()).map((k) => STR(k))); }), "Obj:vals": FN_NATIVE(([obj]) => { assertObject(obj); return ARR(Array.from(obj.value.values())); }), "Obj:kvs": FN_NATIVE(([obj]) => { assertObject(obj); return ARR(Array.from(obj.value.entries()).map(([k, v]) => ARR([STR(k), v]))); }), "Obj:get": FN_NATIVE(([obj, key]) => { assertObject(obj); assertString(key); return obj.value.get(key.value) ?? NULL; }), "Obj:set": FN_NATIVE(([obj, key, value]) => { assertObject(obj); assertString(key); expectAny(value); obj.value.set(key.value, value); return NULL; }), "Obj:has": FN_NATIVE(([obj, key]) => { assertObject(obj); assertString(key); return BOOL(obj.value.has(key.value)); }), "Obj:copy": FN_NATIVE(([obj]) => { assertObject(obj); return OBJ(new Map(obj.value)); }), "Obj:merge": FN_NATIVE(([a, b]) => { assertObject(a); assertObject(b); return OBJ(new Map([...a.value, ...b.value])); }), //#endregion //#region Error "Error:create": FN_NATIVE(([name, info]) => { assertString(name); return ERROR(name.value, info); }), //#endregion //#region Async "Async:interval": FN_NATIVE(async ([interval, callback, immediate], opts) => { assertNumber(interval); assertFunction(callback); if (immediate) { assertBoolean(immediate); if (immediate.value) opts.call(callback, []); } const id = setInterval(() => { opts.topCall(callback, []); }, interval.value); const abortHandler = () => { clearInterval(id); }; opts.registerAbortHandler(abortHandler); return FN_NATIVE(([], opts2) => { clearInterval(id); opts2.unregisterAbortHandler(abortHandler); }); }), "Async:timeout": FN_NATIVE(async ([delay, callback], opts) => { assertNumber(delay); assertFunction(callback); const id = setTimeout(() => { opts.topCall(callback, []); }, delay.value); const abortHandler = () => { clearTimeout(id); }; opts.registerAbortHandler(abortHandler); return FN_NATIVE(([], opts2) => { clearTimeout(id); opts2.unregisterAbortHandler(abortHandler); }); }) //#endregion }; // aiscript/src/interpreter/primitive-props.ts import { substring, length, indexOf, toArray } from "stringz"; var PRIMITIVE_PROPS = { num: { to_str: (target) => FN_NATIVE(async (_, _opts) => { return STR(target.value.toString()); }) }, str: { to_num: (target) => FN_NATIVE(async (_, _opts) => { const parsed = parseInt(target.value, 10); if (isNaN(parsed)) return NULL; return NUM(parsed); }), len: (target) => NUM(length(target.value)), replace: (target) => FN_NATIVE(async ([a, b], _opts) => { assertString(a); assertString(b); return STR(target.value.split(a.value).join(b.value)); }), index_of: (target) => FN_NATIVE(async ([search], _opts) => { assertString(search); return NUM(indexOf(target.value, search.value)); }), incl: (target) => FN_NATIVE(async ([search], _opts) => { assertString(search); return target.value.includes(search.value) ? TRUE : FALSE; }), trim: (target) => FN_NATIVE(async (_, _opts) => { return STR(target.value.trim()); }), upper: (target) => FN_NATIVE(async (_, _opts) => { return STR(target.value.toUpperCase()); }), lower: (target) => FN_NATIVE(async (_, _opts) => { return STR(target.value.toLowerCase()); }), split: (target) => FN_NATIVE(async ([splitter], _opts) => { if (splitter) assertString(splitter); if (splitter) { return ARR(target.value.split(splitter ? splitter.value : "").map((s) => STR(s))); } else { return ARR(toArray(target.value).map((s) => STR(s))); } }), slice: (target) => FN_NATIVE(async ([begin, end], _opts) => { assertNumber(begin); assertNumber(end); return STR(substring(target.value, begin.value, end.value)); }), pick: (target) => FN_NATIVE(async ([i], _opts) => { assertNumber(i); const chars = toArray(target.value); const char = chars[i.value]; return char ? STR(char) : NULL; }), codepoint_at: (target) => FN_NATIVE(([i], _) => { assertNumber(i); const res = target.value.charCodeAt(i.value); return Number.isNaN(res) ? NULL : NUM(res); }) }, arr: { len: (target) => NUM(target.value.length), push: (target) => FN_NATIVE(async ([val], _opts) => { expectAny(val); target.value.push(val); return target; }), unshift: (target) => FN_NATIVE(async ([val], _opts) => { expectAny(val); target.value.unshift(val); return target; }), pop: (target) => FN_NATIVE(async (_, _opts) => { return target.value.pop() ?? NULL; }), shift: (target) => FN_NATIVE(async (_, _opts) => { return target.value.shift() ?? NULL; }), concat: (target) => FN_NATIVE(async ([x], _opts) => { assertArray(x); return ARR(target.value.concat(x.value)); }), slice: (target) => FN_NATIVE(async ([begin, end], _opts) => { assertNumber(begin); assertNumber(end); return ARR(target.value.slice(begin.value, end.value)); }), join: (target) => FN_NATIVE(async ([joiner], _opts) => { if (joiner) assertString(joiner); return STR(target.value.map((i) => i.type === "str" ? i.value : "").join(joiner ? joiner.value : "")); }), map: (target) => FN_NATIVE(async ([fn], opts) => { assertFunction(fn); const vals = target.value.map(async (item, i) => { return await opts.call(fn, [item, NUM(i)]); }); return ARR(await Promise.all(vals)); }), filter: (target) => FN_NATIVE(async ([fn], opts) => { assertFunction(fn); const vals = []; for (let i = 0; i < target.value.length; i++) { const item = target.value[i]; const res = await opts.call(fn, [item, NUM(i)]); assertBoolean(res); if (res.value) vals.push(item); } return ARR(vals); }), reduce: (target) => FN_NATIVE(async ([fn, initialValue], opts) => { assertFunction(fn); const withInitialValue = initialValue != null; let accumulator = withInitialValue ? initialValue : target.value[0]; for (let i = withInitialValue ? 0 : 1; i < target.value.length; i++) { const item = target.value[i]; accumulator = await opts.call(fn, [accumulator, item, NUM(i)]); } return accumulator; }), find: (target) => FN_NATIVE(async ([fn], opts) => { assertFunction(fn); for (let i = 0; i < target.value.length; i++) { const item = target.value[i]; const res = await opts.call(fn, [item, NUM(i)]); assertBoolean(res); if (res.value) return item; } return NULL; }), incl: (target) => FN_NATIVE(async ([val], _opts) => { expectAny(val); if (val.type !== "str" && val.type !== "num" && val.type !== "bool" && val.type !== "null") return FALSE; const getValue = (v) => { return v.value.map((i) => { if (i.type === "str") return i.value; if (i.type === "num") return i.value; if (i.type === "bool") return i.value; if (i.type === "null") return null; return Symbol(); }); }; return getValue(target).includes(val.type === "null" ? null : val.value) ? TRUE : FALSE; }), reverse: (target) => FN_NATIVE(async (_, _opts) => { target.value.reverse(); return NULL; }), copy: (target) => FN_NATIVE(async (_, _opts) => { return ARR([...target.value]); }), sort: (target) => FN_NATIVE(async ([comp], opts) => { const mergeSort = async (arr, comp2) => { if (arr.length <= 1) return arr; const mid = Math.floor(arr.length / 2); const left = await mergeSort(arr.slice(0, mid), comp2); const right = await mergeSort(arr.slice(mid), comp2); return merge(left, right, comp2); }; const merge = async (left, right, comp2) => { const result = []; let leftIndex = 0; let rightIndex = 0; while (leftIndex < left.length && rightIndex < right.length) { const l = left[leftIndex]; const r = right[rightIndex]; const compValue = await opts.call(comp2, [l, r]); assertNumber(compValue); if (compValue.value < 0) { result.push(left[leftIndex]); leftIndex++; } else { result.push(right[rightIndex]); rightIndex++; } } return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex)); }; assertFunction(comp); assertArray(target); target.value = await mergeSort(target.value, comp); return target; }) }, error: { name: (target) => STR(target.value), info: (target) => target.info ?? NULL } }; function getPrimProp(target, name) { if (Object.hasOwn(PRIMITIVE_PROPS, target.type)) { const props = PRIMITIVE_PROPS[target.type]; if (Object.hasOwn(props, name)) { return props[name](target); } else { throw new AiScriptRuntimeError(`No such prop (${name}) in ${target.type}.`); } } else { throw new AiScriptRuntimeError(`Cannot read prop of ${target.type}. (reading ${name})`); } } // aiscript/src/interpreter/variable.ts var Variable = { mut(value) { return { isMutable: true, value }; }, const(value) { return { isMutable: false, value }; } }; // aiscript/src/interpreter/index.ts var IRQ_RATE = 300; var IRQ_AT = IRQ_RATE - 1; var Interpreter = class { constructor(consts, opts = {}) { this.opts = opts; const io = { print: FN_NATIVE(([v]) => { expectAny(v); if (this.opts.out) this.opts.out(v); }), readline: FN_NATIVE(async (args) => { const q = args[0]; assertString(q); if (this.opts.in == null) return NULL; const a = await this.opts.in(q.value); return STR(a); }) }; this.vars = Object.fromEntries(Object.entries({ ...consts, ...std, ...io }).map(([k, v]) => [k, Variable.const(v)])); this.scope = new Scope([new Map(Object.entries(this.vars))]); this.scope.opts.log = (type, params) => { switch (type) { case "add": this.log("var:add", params); break; case "read": this.log("var:read", params); break; case "write": this.log("var:write", params); break; default: break; } }; } stepCount = 0; stop = false; scope; abortHandlers = []; vars = {}; async exec(script) { if (script == null || script.length === 0) return; try { await this.collectNs(script); const result = await this._run(script, this.scope); this.log("end", { val: result }); } catch (e) { this.handleError(e); } } async execFn(fn, args) { return await this._fn(fn, args).catch((e) => { this.handleError(e); return ERROR("func_failed"); }); } execFnSimple(fn, args) { return this._fn(fn, args); } static collectMetadata(script) { if (script == null || script.length === 0) return; function nodeToJs(node) { switch (node.type) { case "arr": return node.value.map((item) => nodeToJs(item)); case "bool": return node.value; case "null": return null; case "num": return node.value; case "obj": { const obj = {}; for (const [k, v] of node.value.entries()) { obj[k] = nodeToJs(v); } return obj; } case "str": return node.value; default: return void 0; } } const meta = /* @__PURE__ */ new Map(); for (const node of script) { switch (node.type) { case "meta": { meta.set(node.name, nodeToJs(node.value)); break; } default: { } } } return meta; } // eslint-disable-next-line @typescript-eslint/no-explicit-any handleError(e) { if (this.opts.err) { if (!this.stop) { this.abort(); if (e instanceof AiScriptError) { this.opts.err(e); } else { this.opts.err(new NonAiScriptError(e)); } } } else { throw e; } } log(type, params) { if (this.opts.log) this.opts.log(type, params); } async collectNs(script) { for (const node of script) { switch (node.type) { case "ns": { await this.collectNsMember(node); break; } default: { } } } } async collectNsMember(ns) { const scope = this.scope.createChildScope(); for (const node of ns.members) { switch (node.type) { case "def": { if (node.mut) { throw new AiScriptNamespaceError('No "var" in namespace declaration: ' + node.name, node.loc); } const variable = { isMutable: node.mut, value: await this._eval(node.expr, scope) }; scope.add(node.name, variable); this.scope.add(ns.name + ":" + node.name, variable); break; } case "ns": { break; } default: { const n = node; const nd = n; throw new AiScriptNamespaceError("invalid ns member type: " + nd.type, nd.loc); } } } } async _fn(fn, args) { if (fn.native) { const result = fn.native(args, { call: this.execFnSimple, topCall: this.execFn, registerAbortHandler: this.registerAbortHandler, unregisterAbortHandler: this.unregisterAbortHandler }); return result ?? NULL; } else { const _args = /* @__PURE__ */ new Map(); for (let i = 0; i < (fn.args ?? []).length; i++) { _args.set(fn.args[i], { isMutable: true, value: args[i] }); } const fnScope = fn.scope.createChildScope(_args); return unWrapRet(await this._run(fn.statements, fnScope)); } } _eval(node, scope) { return this.__eval(node, scope).catch((e) => { if (e.loc) throw e; else { const e2 = e instanceof AiScriptError ? e : new NonAiScriptError(e); e2.loc = node.loc; e2.message = `${e2.message} (Line ${node.loc.line}, Column ${node.loc.column})`; throw e2; } }); } async __eval(node, scope) { if (this.stop) return NULL; if (this.stepCount % IRQ_RATE === IRQ_AT) await new Promise((resolve) => setTimeout(resolve, 5)); this.stepCount++; if (this.opts.maxStep && this.stepCount > this.opts.maxStep) { throw new AiScriptRuntimeError("max step exceeded"); } switch (node.type) { case "call": { const callee = await this._eval(node.target, scope); assertFunction(callee); const args = await Promise.all(node.args.map((expr) => this._eval(expr, scope))); return this._fn(callee, args); } case "if": { const cond = await this._eval(node.cond, scope); assertBoolean(cond); if (cond.value) { return this._eval(node.then, scope); } else { if (node.elseif && node.elseif.length > 0) { for (const elseif of node.elseif) { const cond2 = await this._eval(elseif.cond, scope); assertBoolean(cond2); if (cond2.value) { return this._eval(elseif.then, scope); } } if (node.else) { return this._eval(node.else, scope); } } else if (node.else) { return this._eval(node.else, scope); } } return NULL; } case "match": { const about = await this._eval(node.about, scope); for (const qa of node.qs) { const q = await this._eval(qa.q, scope); if (eq(about, q)) { return await this._eval(qa.a, scope); } } if (node.default) { return await this._eval(node.default, scope); } return NULL; } case "loop": { while (true) { const v = await this._run(node.statements, scope.createChildScope()); if (v.type === "break") { break; } else if (v.type === "return") { return v; } } return NULL; } case "for": { if (node.times) { const times = await this._eval(node.times, scope); assertNumber(times); for (let i = 0; i < times.value; i++) { const v = await this._eval(node.for, scope); if (v.type === "break") { break; } else if (v.type === "return") { return v; } } } else { const from = await this._eval(node.from, scope); const to = await this._eval(node.to, scope); assertNumber(from); assertNumber(to); for (let i = from.value; i < from.value + to.value; i++) { const v = await this._eval(node.for, scope.createChildScope(/* @__PURE__ */ new Map([ [node.var, { isMutable: false, value: NUM(i) }] ]))); if (v.type === "break") { break; } else if (v.type === "return") { return v; } } } return NULL; } case "each": { const items = await this._eval(node.items, scope); assertArray(items); for (const item of items.value) { const v = await this._eval(node.for, scope.createChildScope(/* @__PURE__ */ new Map([ [node.var, { isMutable: false, value: item }] ]))); if (v.type === "break") { break; } else if (v.type === "return") { return v; } } return NULL; } case "def": { const value = await this._eval(node.expr, scope); if (node.attr.length > 0) { const attrs = []; for (const nAttr of node.attr) { attrs.push({ name: nAttr.name, value: await this._eval(nAttr.value, scope) }); } value.attr = attrs; } scope.add(node.name, { isMutable: node.mut, value }); return NULL; } case "identifier": { return scope.get(node.name); } case "assign": { const v = await this._eval(node.expr, scope); await this.assign(scope, node.dest, v); return NULL; } case "addAssign": { const target = await this._eval(node.dest, scope); assertNumber(target); const v = await this._eval(node.expr, scope); assertNumber(v); await this.assign(scope, node.dest, NUM(target.value + v.value)); return NULL; } case "subAssign": { const target = await this._eval(node.dest, scope); assertNumber(target); const v = await this._eval(node.expr, scope); assertNumber(v); await this.assign(scope, node.dest, NUM(target.value - v.value)); return NULL; } case "null": return NULL; case "bool": return BOOL(node.value); case "num": return NUM(node.value); case "str": return STR(node.value); case "arr": return ARR(await Promise.all(node.value.map((item) => this._eval(item, scope)))); case "obj": { const obj = /* @__PURE__ */ new Map(); for (const k of node.value.keys()) { obj.set(k, await this._eval(node.value.get(k), scope)); } return OBJ(obj); } case "prop": { const target = await this._eval(node.target, scope); if (isObject(target)) { if (target.value.has(node.name)) { return target.value.get(node.name); } else { return NULL; } } else { return getPrimProp(target, node.name); } } case "index": { const target = await this._eval(node.target, scope); const i = await this._eval(node.index, scope); if (isArray(target)) { assertNumber(i); const item = target.value[i.value]; if (item === void 0) { throw new AiScriptIndexOutOfRangeError(`Index out of range. index: ${i.value} max: ${target.value.length - 1}`); } return item; } else if (isObject(target)) { assertString(i); if (target.value.has(i.value)) { return target.value.get(i.value); } else { return NULL; } } else { throw new AiScriptRuntimeError(`Cannot read prop (${reprValue(i)}) of ${target.type}.`); } } case "not": { const v = await this._eval(node.expr, scope); assertBoolean(v); return BOOL(!v.value); } case "fn": { return FN(node.args.map((arg) => arg.name), node.children, scope); } case "block": { return this._run(node.statements, scope.createChildScope()); } case "exists": { return BOOL(scope.exists(node.identifier.name)); } case "tmpl": { let str = ""; for (const x of node.tmpl) { if (typeof x === "string") { str += x; } else { const v = await this._eval(x, scope); str += reprValue(v); } } return STR(str); } case "return": { const val = await this._eval(node.expr, scope); this.log("block:return", { scope: scope.name, val }); return RETURN(val); } case "break": { this.log("block:break", { scope: scope.name }); return BREAK(); } case "continue": { this.log("block:continue", { scope: scope.name }); return CONTINUE(); } case "ns": { return NULL; } case "meta": { return NULL; } case "and": { const leftValue = await this._eval(node.left, scope); assertBoolean(leftValue); if (!leftValue.value) { return leftValue; } else { const rightValue = await this._eval(node.right, scope); assertBoolean(rightValue); return rightValue; } } case "or": { const leftValue = await this._eval(node.left, scope); assertBoolean(leftValue); if (leftValue.value) { return leftValue; } else { const rightValue = await this._eval(node.right, scope); assertBoolean(rightValue); return rightValue; } } default: { throw new Error("invalid node type"); } } } async _run(program, scope) { this.log("block:enter", { scope: scope.name }); let v = NULL; for (let i = 0; i < program.length; i++) { const node = program[i]; v = await this._eval(node, scope); if (v.type === "return") { this.log("block:return", { scope: scope.name, val: v.value }); return v; } else if (v.type === "break") { this.log("block:break", { scope: scope.name }); return v; } else if (v.type === "continue") { this.log("block:continue", { scope: scope.name }); return v; } } this.log("block:leave", { scope: scope.name, val: v }); return v; } registerAbortHandler(handler) { this.abortHandlers.push(handler); } unregisterAbortHandler(handler) { this.abortHandlers = this.abortHandlers.filter((h) => h !== handler); } abort() { this.stop = true; for (const handler of this.abortHandlers) { handler(); } this.abortHandlers = []; } async assign(scope, dest, value) { if (dest.type === "identifier") { scope.assign(dest.name, value); } else if (dest.type === "index") { const assignee = await this._eval(dest.target, scope); const i = await this._eval(dest.index, scope); if (isArray(assignee)) { assertNumber(i); assignee.value[i.value] = value; } else if (isObject(assignee)) { assertString(i); assignee.value.set(i.value, value); } else { throw new AiScriptRuntimeError(`Cannot read prop (${reprValue(i)}) of ${assignee.type}.`); } } else if (dest.type === "prop") { const assignee = await this._eval(dest.target, scope); assertObject(assignee); assignee.value.set(dest.name, value); } else { throw new AiScriptRuntimeError("The left-hand side of an assignment expression must be a variable or a property/index access."); } } }; __decorateClass([ autobind ], Interpreter.prototype, "exec", 1); __decorateClass([ autobind ], Interpreter.prototype, "execFn", 1); __decorateClass([ autobind ], Interpreter.prototype, "execFnSimple", 1); __decorateClass([ autobind ], Interpreter.prototype, "handleError", 1); __decorateClass([ autobind ], Interpreter.prototype, "log", 1); __decorateClass([ autobind ], Interpreter.prototype, "collectNs", 1); __decorateClass([ autobind ], Interpreter.prototype, "collectNsMember", 1); __decorateClass([ autobind ], Interpreter.prototype, "_fn", 1); __decorateClass([ autobind ], Interpreter.prototype, "_eval", 1); __decorateClass([ autobind ], Interpreter.prototype, "__eval", 1); __decorateClass([ autobind ], Interpreter.prototype, "_run", 1); __decorateClass([ autobind ], Interpreter.prototype, "registerAbortHandler", 1); __decorateClass([ autobind ], Interpreter.prototype, "unregisterAbortHandler", 1); __decorateClass([ autobind ], Interpreter.prototype, "abort", 1); __decorateClass([ autobind ], Interpreter.prototype, "assign", 1); __decorateClass([ autobind ], Interpreter, "collectMetadata", 1); // aiscript/src/parser/syntaxes/expressions.ts var operators2 = [ { opKind: "postfix", kind: 33 /* OpenParen */, bp: 20 }, { opKind: "postfix", kind: 55 /* OpenBracket */, bp: 20 }, { opKind: "infix", kind: 41 /* Dot */, lbp: 18, rbp: 19 }, { opKind: "infix", kind: 58 /* Hat */, lbp: 17, rbp: 16 }, { opKind: "prefix", kind: 36 /* Plus */, bp: 14 }, { opKind: "prefix", kind: 39 /* Minus */, bp: 14 }, { opKind: "prefix", kind: 27 /* Not */, bp: 14 }, { opKind: "infix", kind: 35 /* Asterisk */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 42 /* Slash */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 31 /* Percent */, lbp: 12, rbp: 13 }, { opKind: "infix", kind: 36 /* Plus */, lbp: 10, rbp: 11 }, { opKind: "infix", kind: 39 /* Minus */, lbp: 10, rbp: 11 }, { opKind: "infix", kind: 46 /* Lt */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 47 /* LtEq */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 52 /* Gt */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 53 /* GtEq */, lbp: 8, rbp: 9 }, { opKind: "infix", kind: 50 /* Eq2 */, lbp: 6, rbp: 7 }, { opKind: "infix", kind: 28 /* NotEq */, lbp: 6, rbp: 7 }, { opKind: "infix", kind: 32 /* And2 */, lbp: 4, rbp: 5 }, { opKind: "infix", kind: 60 /* Or2 */, lbp: 2, rbp: 3 } ]; // aiscript/src/node.ts var node_exports = {}; __export(node_exports, { isExpression: () => isExpression, isStatement: () => isStatement }); var statementTypes = [ "def", "return", "each", "for", "loop", "break", "continue", "assign", "addAssign", "subAssign" ]; function isStatement(x) { return statementTypes.includes(x.type); } var expressionTypes = [ "if", "fn", "match", "block", "exists", "tmpl", "str", "num", "bool", "null", "obj", "arr", "not", "and", "or", "identifier", "call", "index", "prop" ]; function isExpression(x) { return expressionTypes.includes(x.type); } // features/core/typing/TypeValue.ts var primitiveTypeNames = ["str", "num", "bool", "null"]; var objectTypeName = ["obj", "arr"]; var typeNames = [ ...primitiveTypeNames, ...objectTypeName, "error" ]; function loc(line = 1, column = 1) { return { line, column }; } function ident(name, location = loc()) { return { type: "identifier", name, loc: location }; } function primitiveType(name) { return { type: "PrimitiveType", name }; } function arrayType(item) { return { type: "ArrayType", item }; } function errorType(info) { return { type: "ErrorType", name: { type: "PrimitiveType", name: "str" }, info }; } function fnType(params, returnType) { return { type: "FunctionType", params, returnType }; } function union(...types) { return { type: "UnionType", contents: types }; } var anyType = { type: "AnyType" }; // features/core/typing/std/Core.ts function installCoreTypes(scope) { scope.defineVariable(ident("help"), { isMut: false, type: primitiveType("str") }); scope.defineVariable(ident("Core:ai"), { isMut: false, type: primitiveType("str") }); scope.defineVariable(ident("Core:v"), { isMut: false, type: primitiveType("str") }); scope.defineVariable(ident("Core:not"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("bool") }], primitiveType("bool") ) }); scope.defineVariable(ident("Core:eq"), { isMut: false, type: fnType( [ { isOptional: false, type: anyType }, { isOptional: false, type: anyType } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:neq"), { isMut: false, type: fnType( [ { isOptional: false, type: anyType }, { isOptional: false, type: anyType } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:and"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("bool") }, { isOptional: false, type: primitiveType("bool") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:or"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("bool") }, { isOptional: false, type: primitiveType("bool") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:add"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:sub"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:mul"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:div"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:pow"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:mod"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Core:gt"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:lt"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:gteq"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:lteq"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("bool") ) }); scope.defineVariable(ident("Core:type"), { isMut: false, type: fnType([{ isOptional: false, type: anyType }], primitiveType("str")) }); scope.defineVariable(ident("Core:to_str"), { isMut: false, type: fnType([{ isOptional: false, type: anyType }], primitiveType("str")) }); scope.defineVariable(ident("Core:range"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], arrayType(primitiveType("num")) ) }); scope.defineVariable(ident("Core:sleep"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("null") ) }); } // features/core/typing/std/Date.ts function installDateTypes(scope) { scope.defineVariable(ident("Date:now"), { isMut: false, type: fnType([], primitiveType("str")) }); scope.defineVariable(ident("Date:year"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:month"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:day"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:hour"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:minute"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:second"), { isMut: false, type: fnType( [{ isOptional: true, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Date:parse"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("str") }], primitiveType("num") ) }); } // features/core/typing/std/Json.ts function installJsonTypes(scope) { scope.defineVariable(ident("Json:stringify"), { isMut: false, type: fnType([{ isOptional: false, type: anyType }], primitiveType("str")) }); scope.defineVariable(ident("Json:parse"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("str") }], union(anyType, errorType(anyType)) ) }); scope.defineVariable(ident("Json:parseable"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("str") }], primitiveType("bool") ) }); } // features/core/typing/std/Math.ts function installMathTypes(scope) { scope.defineVariable(ident("Math:Infinity"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:E"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:LN2"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:LN10"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:LOG2E"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:LOG10E"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:PI"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:SQRT1_2"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:SQRT2"), { isMut: false, type: primitiveType("num") }); scope.defineVariable(ident("Math:abs"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:acos"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:acosh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:asin"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:asinh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:atan"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:atanh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:atan2"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:cbrt"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:ceil"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:clz32"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:cos"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:cosh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:exp"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:expm1"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:floor"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:fround"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:hypot"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:imul"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:log"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:log1p"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:log10"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:log2"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:max"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:min"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:pow"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("num") }, { isOptional: false, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:round"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:sign"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:sin"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:sinh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:sqrt"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:tan"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:tanh"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:trunc"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("num") ) }); scope.defineVariable(ident("Math:rnd"), { isMut: false, type: fnType( [ { isOptional: true, type: primitiveType("num") }, { isOptional: true, type: primitiveType("num") } ], primitiveType("num") ) }); scope.defineVariable(ident("Math:gen_rng"), { isMut: false, type: fnType( [ { isOptional: false, type: union(primitiveType("num"), primitiveType("str")) } ], fnType( [ { isOptional: true, type: primitiveType("num") }, { isOptional: true, type: primitiveType("num") } ], primitiveType("num") ) ) }); } // features/core/typing/std/Num.ts function installNumTypes(scope) { scope.defineVariable(ident("Num:to_hex"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("str") ) }); scope.defineVariable(ident("Num:from_hex"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("str") }], primitiveType("num") ) }); } // features/core/typing/std/Str.ts function installStrTypes(scope) { scope.defineVariable(ident("Str:lf"), { isMut: false, type: primitiveType("str") }); scope.defineVariable(ident("Str:lt"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("str") }, { isOptional: false, type: primitiveType("str") } ], primitiveType("num") ) }); scope.defineVariable(ident("Str:gt"), { isMut: false, type: fnType( [ { isOptional: false, type: primitiveType("str") }, { isOptional: false, type: primitiveType("str") } ], primitiveType("num") ) }); scope.defineVariable(ident("Str:from_codepoint"), { isMut: false, type: fnType( [{ isOptional: false, type: primitiveType("num") }], primitiveType("str") ) }); } // features/core/typing/std/Util.ts function installUtilTypes(scope) { scope.defineVariable(ident("Util:uuid"), { isMut: false, type: fnType([], primitiveType("str")) }); } // features/core/typing/std/index.ts function installStdTypes(scope) { installCoreTypes(scope); installUtilTypes(scope); installJsonTypes(scope); installDateTypes(scope); installMathTypes(scope); installNumTypes(scope); installStrTypes(scope); } // features/core/typing/Scope.ts var Scope2 = class _Scope2 { constructor(parent, types = /* @__PURE__ */ new Map(), variables = /* @__PURE__ */ new Map(), overridedVariables = /* @__PURE__ */ new Map()) { this.parent = parent; this.types = types; this.variables = variables; this.overridedVariables = overridedVariables; } copy() { return new _Scope2(this.parent, new Map(this.types), new Map(this.variables)); } createChild() { return new _Scope2(this); } createNamespace(name) { return new NamespaceScope(name, this); } declareType(ident2, type) { this.types.set(ident2.name, type); } getType(ident2) { return this.parent?.getType(ident2) ?? this.types.get(ident2.name) ?? null; } hasType(ident2) { return this.parent?.hasType(ident2) || this.types.has(ident2.name); } defineVariable(ident2, variable) { if (this.variables.has(ident2.name)) { return new AiAlreadyDeclaredVariableError(ident2.name, ident2.loc); } this.variables.set(ident2.name, variable); } overrideVariable(ident2, variable) { this.overridedVariables.set(ident2.name, variable); } getVariable(ident2) { return this.overridedVariables.get(ident2.name) ?? this.parent?.getVariable(ident2) ?? this.variables.get(ident2.name) ?? null; } hasVariable(ident2) { return this.parent?.hasVariable(ident2) ?? this.variables.has(ident2.name); } isDeclared(name) { return this.variables.has(name); } }; var NamespaceScope = class extends Scope2 { constructor(namespace, _parent, types = /* @__PURE__ */ new Map(), _variables = /* @__PURE__ */ new Map()) { super(_parent, types, _variables); this.namespace = namespace; this._parent = _parent; this._variables = _variables; } defineVariable(ident2, variable) { if (this._variables.has(ident2.name) == null) { return new AiAlreadyDeclaredVariableError(ident2.name, ident2.loc); } this._variables.set(ident2.name, variable); return this._parent.defineVariable( { type: "identifier", name: this.namespace + ":" + ident2.name, loc: ident2.loc }, variable ); } }; function createGlobalScope() { const scope = new Scope2(); scope.declareType(ident("void"), primitiveType("null")); installStdTypes(scope); return scope; } // features/core/utils/excludeDuplicatedType.ts function excludeDuplicatedType(types, typeChecker) { const res = []; loop: for (const item of types) { for (let i = 0; i < res.length; i++) { const x = res[i]; if (typeChecker.isAssignableType(item, x)) { res.splice(i--, 1); continue; } else if (typeChecker.isAssignableType(x, item)) { continue loop; } } res.push(item); } return res; } // features/core/typing/TypeChecker.ts var TypeChecker = class { constructor(globalScope = new Scope2()) { this.globalScope = globalScope; } /** 型を文字の表現に戻す */ reprType(type, indent = 0) { const ws = " ".repeat(indent); switch (type.type) { case "PrimitiveType": case "PrimitiveType": { let res = type.name; if ("inner" in type && type.inner) { res += `<${this.reprType(type)}>`; } return res; } case "AnyType": { return "any"; } case "PrimitiveType": { return type.name; } case "FunctionType": { return `@(${type.params.map( (x) => ( // オプショナルな引数を表現する構文は無いのでとりあえず ? を付けてる x.isOptional ? `${this.reprType(x.type)}?` : this.reprType(x.type) ) ).join(", ")}) => ${this.reprType(type.returnType)}`; } case "NothingType": { return "<:NothingType:>"; } case "UnionType": { return type.contents.map((x) => this.reprType(x)).join(" | "); } case "ObjectType": { if (type.items instanceof Map) { return `{ ${ws} ${[...type.items.entries()].map( ([name, type2]) => `${name}: ${this.reprType(type2, indent + 1)}` ).join(` ${ws} `)} ${ws}}`; } else { return `obj<${this.reprType(type.items)}>`; } } case "ArrayType": { return `arr<${this.reprType(type.item)}>`; } case "ErrorType": { return "error"; } } } runBlock(statements, scope, errors) { let returnType = { type: "PrimitiveType", name: "null" }; loop: for (const tree of statements) { switch (tree.type) { case "return": { returnType = this.run(tree.expr, scope, errors) ?? returnType; break loop; } case "break": case "continue": { break loop; } default: { returnType = this.run(tree, scope, errors) ?? returnType; break; } } } return returnType; } /** インタープリターがASTを実行してゆくように、型チェックを行う */ run(node, scope, errors) { if (node_exports.isStatement(node)) { return this.runStmt(node, scope, errors); } else if (node_exports.isExpression(node)) { return this.runExpr(node, scope, errors); } else if (node.type == "namedTypeSource" || node.type == "fnTypeSource") { return this.inferFromTypeSource(node, scope, errors); } else { return null; } } runStmt(ast, scope, errors) { switch (ast.type) { case "def": { if (scope.isDeclared(ast.name)) { errors.push(new AiAlreadyDeclaredVariableError(ast.name, ast.loc)); } let type; if (ast.varType) { type = this.inferFromTypeSource(ast.varType, scope, errors); const exprType = this.runExpr(ast.expr, scope, errors); if (!this.isAssignableType(type, exprType)) { errors.push( new AiNotAssignableTypeError( this.reprType(type), this.reprType(exprType), ast.loc ) ); } } else { type = this.runExpr(ast.expr, scope, errors); } const res = scope.defineVariable( { type: "identifier", name: ast.name, loc: ast.loc }, { isMut: ast.mut, type } ); if (res instanceof AiTypeError) { errors.push(res); } return null; } case "addAssign": case "subAssign": case "assign": { if (ast.dest.type === "identifier") { const variable = scope.getVariable(ast.dest); if (variable?.isMut === false) { errors.push( new AiCanNotAssignToImmutableVariableError( ast.dest.name, ast.dest.loc ) ); } } const dest = this.runExpr(ast.dest, scope, errors); const value = this.runExpr(ast.expr, scope, errors); if (ast.dest.type == "identifier" && dest.type == "NothingType") { const variable = scope.getVariable(ast.dest); scope.overrideVariable(ast.dest, { isMut: variable?.isMut ?? false, type: value }); return null; } if (!this.isAssignableType(dest, value)) { errors.push( new AiNotAssignableTypeError( this.reprType(dest), this.reprType(value), ast.loc ) ); } return null; } } return null; } runExpr(ast, scope, errors) { switch (ast.type) { case "fn": { const childScope = scope.createChild(); const params = []; for (const param of ast.args) { let paramType; if (param.argType) { paramType = this.inferFromTypeSource(param.argType, scope, errors); } else { paramType = { type: "NothingType" }; } params.push({ isOptional: false, type: paramType }); const err = childScope.defineVariable( { type: "identifier", name: param.name, loc: ast.loc }, { isMut: true, type: paramType } ); if (err) errors.push(err); } let returnType; if (ast.retType) { returnType = this.inferFromTypeSource(ast.retType, scope, errors); const realType = this.runBlock(ast.children, childScope, errors); if (!this.isAssignableType(returnType, realType)) { errors.push( new AiNotAssignableTypeError( this.reprType(returnType), this.reprType(realType), ast.loc ) ); } } else { returnType = this.runBlock(ast.children, childScope, errors); } return { type: "FunctionType", params, returnType }; } case "block": { return this.runBlock(ast.statements, scope.createChild(), errors); } case "call": { const target = this.runExpr(ast.target, scope, errors); if (!this.isCallableType(target)) { errors.push(new AiCanNotCallError(this.reprType(target), ast.loc)); } else if (target.type === "FunctionType") { for (let i = 0; i < target.params.length; i++) { if (i < ast.args.length) { const dest = target.params[i].type; const value = this.runExpr(ast.args[i], scope, errors); if (!this.isAssignableType(dest, value)) { errors.push( new AiInvalidArgumentError( i, this.reprType(dest), this.reprType(value), ast.loc ) ); } } else if (!target.params[i].isOptional) { errors.push( new AiMissingArgumentError( i, this.reprType(target.params[i].type), ast.loc ) ); } } return target.returnType; } return { type: "AnyType" }; } case "str": { return { type: "PrimitiveType", name: "str" }; } case "num": { return { type: "PrimitiveType", name: "num" }; } case "bool": { return { type: "PrimitiveType", name: "bool" }; } case "null": { return { type: "PrimitiveType", name: "null" }; } case "arr": { let itemType; const itemTypes = ast.value.map((x) => this.runExpr(x, scope, errors)); if (ast.value.length == 0 || itemTypes.length === 0) { itemType = { type: "AnyType" }; } else if (itemTypes.length === 1) { itemType = itemTypes[0]; } else { itemType = { type: "UnionType", contents: excludeDuplicatedType(itemTypes, this) }; } return { type: "ArrayType", item: itemType }; } case "obj": { const items = /* @__PURE__ */ new Map(); for (const [name, expr] of ast.value) { items.set(name, this.runExpr(expr, scope, errors)); } return { type: "ObjectType", items }; } case "identifier": { const variable = scope.getVariable(ast); if (variable == null) { return { type: "AnyType" }; } return variable.type; } case "prop": { const target = this.runExpr(ast.target, scope, errors); if (target.type == "ObjectType") { if (target.items instanceof Map) { return target.items.get(ast.name) ?? { type: "AnyType" }; } else { return target.items; } } else { errors.push( new AiCanNotReadPropertyError( this.reprType(target), ast.name, ast.loc ) ); return { type: "AnyType" }; } } case "index": { const target = this.runExpr(ast.target, scope, errors); const indexType = this.runExpr(ast.index, scope, errors); if (target.type == "ObjectType") { if (target.items instanceof Map) { return union(...excludeDuplicatedType(target.items.values(), this)); } else { return target.items; } } else if (target.type == "ArrayType") { return target.item; } else { errors.push( new AiCanNotReadPropertyError( this.reprType(target), this.reprType(indexType), ast.loc ) ); return { type: "AnyType" }; } } case "and": { const left = this.runExpr(ast.left, scope, errors); const right = this.runExpr(ast.right, scope, errors); if (!this.isAssignableType(primitiveType("bool"), left)) { errors.push( new AiNotAssignableTypeError( this.reprType(primitiveType("bool")), this.reprType(left), ast.left.loc ) ); } if (!this.isAssignableType(primitiveType("bool"), right)) { errors.push( new AiNotAssignableTypeError( this.reprType(primitiveType("bool")), this.reprType(right), ast.right.loc ) ); } return primitiveType("bool"); } case "or": { const left = this.runExpr(ast.left, scope, errors); const right = this.runExpr(ast.right, scope, errors); if (!this.isAssignableType(primitiveType("bool"), left)) { errors.push( new AiNotAssignableTypeError( this.reprType(primitiveType("bool")), this.reprType(left), ast.left.loc ) ); } if (!this.isAssignableType(primitiveType("bool"), right)) { errors.push( new AiNotAssignableTypeError( this.reprType(primitiveType("bool")), this.reprType(right), ast.right.loc ) ); } return primitiveType("bool"); } case "not": { const expr = this.runExpr(ast.expr, scope, errors); if (!this.isAssignableType(primitiveType("bool"), expr)) { errors.push( new AiNotAssignableTypeError( this.reprType(primitiveType("bool")), this.reprType(expr), ast.expr.loc ) ); } return primitiveType("bool"); } case "exists": { return primitiveType("bool"); } case "if": { this.runExpr(ast.cond, scope, errors); const res = []; res.push(this.run(ast.then, scope, errors)); for (const tree of ast.elseif) { this.runExpr(tree.cond, scope, errors); res.push(this.run(tree.then, scope, errors)); } if (ast.else) { res.push(this.run(ast.else, scope, errors)); } return union( ...excludeDuplicatedType( res.filter((x) => x != null), this ) ); } default: { return { type: "AnyType" }; } } } /** `dest`に`value`が代入可能であるか */ isAssignableType(dest, value) { if (value.type === "AnyType") { return true; } else if (dest.type === "AnyType") { return true; } if (dest.type === "ErrorType" && value.type == "ErrorType") { return true; } if (dest.type === "FunctionType" && value.type === "FunctionType") { if (dest.params.length !== value.params.length) { return false; } for (let i = 0; i < dest.params.length; i++) { const x = dest.params[i]; const y = value.params[i]; if (x.isOptional && !y.isOptional) return false; if (!this.isAssignableType(x.type, y.type)) return false; } return true; } if (dest.type === "PrimitiveType" && value.type === "PrimitiveType") { return dest.name === value.name; } if (dest.type === "ObjectType" && value.type === "ObjectType") { if (dest.items instanceof Map && value.items instanceof Map) { for (const [name, destType] of dest.items) { const valueType = value.items.get(name); if (!valueType || !this.isAssignableType(destType, valueType)) return false; } return true; } else if (dest.items instanceof Map) { const valueType = value.items instanceof Map ? union(...excludeDuplicatedType(value.items.values(), this)) : value.items; for (const [_, destType] of dest.items) { if (!this.isAssignableType(destType, valueType)) return false; } return true; } else if (value.items instanceof Map) { const destType = dest.items instanceof Map ? union(...excludeDuplicatedType(dest.items.values(), this)) : dest.items; for (const [_, valueType] of value.items) { if (!this.isAssignableType(destType, valueType)) return false; } return true; } else { const destValue = dest.items instanceof Map ? union(...excludeDuplicatedType(dest.items.values(), this)) : dest.items; const valueType = value.items instanceof Map ? union(...excludeDuplicatedType(value.items.values(), this)) : value.items; return this.isAssignableType(destValue, valueType); } } if (dest.type === "ArrayType" && value.type === "ArrayType") { return this.isAssignableType(dest.item, value.item); } if (dest.type === "UnionType" && value.type !== "UnionType") { for (const destType of dest.contents) { if (this.isAssignableType(destType, value)) return true; } return false; } else if (dest.type === "UnionType" && value.type === "UnionType") { for (const valueType of value.contents) { if (!this.isAssignableType(dest, valueType)) return false; } return true; } return false; } /** 呼び出し可能な型なのかチェック */ isCallableType(type) { if (type.type === "AnyType") return true; if (type.type === "FunctionType") return true; return false; } /** 型の表現から、型を生成 */ inferFromTypeSource(ast, scope, errors) { switch (ast.type) { case "namedTypeSource": { if (primitiveTypeNames.some((x) => x === ast.name)) { return { type: "PrimitiveType", name: ast.name }; } else if (ast.name === "obj") { return { type: "ObjectType", items: ast.inner ? this.inferFromTypeSource(ast.inner, scope, errors) : { type: "AnyType" } }; } else if (ast.name === "arr") { return { type: "ArrayType", item: ast.inner ? this.inferFromTypeSource(ast.inner, scope, errors) : { type: "AnyType" } }; } return { type: "AnyType" }; } case "fnTypeSource": { return { type: "FunctionType", params: ast.args.map((x) => ({ isOptional: false, type: this.inferFromTypeSource(x, scope, errors) })), returnType: this.inferFromTypeSource(ast.result, scope, errors) }; } } } preRunBlock(body, scope, errors) { for (const node of body) { switch (node.type) { case "ns": { this.preRun(node, scope, errors); break; } } } } preRun(node, scope, errors) { switch (node.type) { case "ns": { this.preRunBlock( node.members, scope.createNamespace(node.name), errors ); return; } case "def": { this.run(node, scope, errors); } } } }; // features/core/server/LanguageServer.ts import * as Lsp from "vscode-languageserver"; import * as TextDocument2 from "vscode-languageserver-textdocument"; var LanguageServer = class { constructor(i18n, conn, parser = new Parser(), typeChecker = new TypeChecker(createGlobalScope())) { this.i18n = i18n; this.conn = conn; this.parser = parser; this.typeChecker = typeChecker; conn.console.log("language server started"); conn.onInitialize(() => { conn.console.log("initialize"); return { capabilities: { textDocumentSync: TextDocumentSyncKind.Incremental } }; }); this.documents.onDidChangeContent((change) => { this.onDidChangeContent(change); }); } documents = new TextDocuments(TextDocument); listen() { this.documents.listen(this.conn); this.conn.listen(); } onDidChangeContent(change) { const text = change.document.getText(); const parserErrors = []; const typeErrors = []; const diagnostics = []; this.conn.console.log("did change content - " + change.document.uri); try { this.conn.console.log("start parse"); const ast = this.parser.parseFromString(text, parserErrors); this.conn.console.log("end parse"); for (const error of parserErrors) { const message = this.i18n.localize(parserErrorLocalizer, error); diagnostics.push({ severity: DiagnosticSeverity.Error, message, range: { start: aiLocation2LspPosition(error.location), end: aiLocation2LspPosition(error.location) }, source: "aiscript-parser" }); } const scope = this.typeChecker.globalScope.copy(); this.conn.console.log("start type check"); this.typeChecker.preRunBlock(ast, scope, typeErrors); this.typeChecker.runBlock(ast, scope, typeErrors); this.conn.console.log("end type check"); for (const error of typeErrors) { const message = this.i18n.localize(typeErrorLocalizer, error); diagnostics.push({ severity: DiagnosticSeverity.Error, message, range: { start: aiLocation2LspPosition(error.location), end: aiLocation2LspPosition(error.location) }, source: "aiscript-typing" }); } this.conn.sendDiagnostics({ uri: change.document.uri, diagnostics }); } catch (err) { const loc2 = (err instanceof AiScriptError ? err.loc : null) ?? { column: 0, line: 0 }; this.conn.sendDiagnostics({ uri: change.document.uri, diagnostics: [ { message: "" + err, range: { start: aiLocation2LspPosition(loc2), end: aiLocation2LspPosition(loc2) } } ] }); } } }; export { I18n, initAiScriptI18n, Parser, LanguageServer, Lsp, TextDocument2 as TextDocument };