nadesiko3
Version:
Japanese Programming Language
1,774 lines • 120 kB
JavaScript
import { NakoRuntimeError } from './nako_errors.mjs';
export default {
'meta': {
type: 'const',
value: {
pluginName: 'plugin_system', // プラグインの名前
description: 'システム関連の命令を提供するプラグイン', // プラグインの説明
pluginVersion: '3.6.0', // プラグインのバージョン
nakoRuntime: ['wnako', 'cnako', 'phpnako'], // 対象ランタイム
nakoVersion: '3.6.0' // 要求なでしこバージョン
}
},
'初期化': {
type: 'func',
josi: [],
pure: false,
fn: function (sys) {
// システム変数の初期化
const system = sys;
sys.pathSeparator = '/'; // パス記号 #2185
sys.engine = '?'; // エンジン名
sys.isDebug = false;
// システム変数にアクセスするための関数を定義
sys.__setSysVar = (name, value) => system.__v0.set(name, value);
sys.__getSysVar = (name, defaultValue = undefined) => {
const v = system.__v0.get(name);
if (v === undefined) {
return defaultValue;
}
return v;
};
sys.__setSore = (v) => { sys.__vars.set('それ', v); return v; };
sys.__getSore = () => sys.__vars.get('それ');
sys.tags = {}; // タグ - プラグイン側で自由に使えるオブジェクト
// 言語バージョンを設定
sys.__setSysVar('ナデシコバージョン', sys.version);
sys.__setSysVar('ナデシコ言語バージョン', sys.coreVersion);
if (!system.__namespaceList) {
system.__namespaceList = [];
}
// なでしこの関数や変数を探して返す
sys.__findVar = function (nameStr, def) {
if (typeof nameStr === 'function') {
return nameStr;
}
// ローカル変数を探す
const localVar = system.__locals.get(nameStr);
if (localVar) {
return localVar;
}
// 名前空間が指定されている場合
if (nameStr.indexOf('__') >= 0) {
for (let i = 2; i >= 0; i--) {
const varScope = system.__varslist[i];
const scopeValue = varScope.get(nameStr);
if (scopeValue) {
return scopeValue;
}
}
return def;
}
// 名前空間を参照して関数・変数名を解決する
const modList = system.__modList ? system.__modList : [system.__modName];
for (const modName of modList) {
const gname = `${modName}__${nameStr}`;
for (let i = 2; i >= 0; i--) {
const scope = system.__varslist[i];
const scopeValue = scope.get(gname);
if (scopeValue) {
return scopeValue;
}
}
}
return def;
};
// 文字列から関数を探す
sys.__findFunc = function (nameStr, parentFunc) {
const f = sys.__findVar(nameStr);
if (typeof f === 'function') {
return f;
}
throw new Error(`『${parentFunc}』に実行できない関数が指定されました。`);
};
// システム関数を実行
sys.__exec = function (func, params) {
// システム命令を優先
const f0 = sys.__getSysVar(func);
if (f0) {
return f0.apply(this, params);
}
// グローバル・ローカルを探す
const f = sys.__findVar(func);
if (!f) {
throw new Error('システム関数でエイリアスの指定ミス:' + func);
}
return f.apply(this, params);
};
// タイマーに関する処理(タイマーは「!クリア」で全部停止する)
sys.__timeout = [];
sys.__interval = [];
// 日付処理などに使う
const z2 = sys.__zero2 = (s) => {
s = '00' + String(s);
return s.substring(s.length - 2);
};
sys.__zero = (s, keta) => {
let zeroS = '';
for (let i = 0; i < keta; i++) {
zeroS += '0';
}
s = zeroS + s;
return s.substring(s.length - keta);
};
sys.__formatDate = (t) => {
return String(t.getFullYear()) + '/' + z2(t.getMonth() + 1) + '/' + z2(t.getDate());
};
sys.__formatTime = (t) => {
return z2(t.getHours()) + ':' + z2(t.getSeconds()) + ':' + z2(t.getMinutes());
};
sys.__formatDateTime = (t, fmt) => {
const dateStr = String(t.getFullYear()) + '/' + z2(t.getMonth() + 1) + '/' + z2(t.getDate());
const timeStr = z2(t.getHours()) + ':' + z2(t.getMinutes()) + ':' + z2(t.getSeconds());
if (fmt.match(/^\d+\/\d+\/\d+\s+\d+:\d+:\d+$/)) {
return dateStr + ' ' + timeStr;
}
if (fmt.match(/^\d+\/\d+\/\d+$/)) {
return dateStr;
}
if (fmt.match(/^\d+:\d+:\d+$/)) {
return timeStr;
}
return dateStr + ' ' + timeStr;
};
sys.__str2date = (s) => {
// trim
s = ('' + s).replace(/(^\s+|\s+$)/, '');
// is unix time
if (s.match(/^(\d+|\d+\.\d+)$/)) {
return new Date(parseFloat(s) * 1000);
}
// is time ?
if (s.match(/^\d+:\d+(:\d+)?$/)) {
const t = new Date();
const a = (s + ':0').split(':');
return new Date(t.getFullYear(), t.getMonth(), t.getDate(), parseInt(a[0]), parseInt(a[1]), parseInt(a[2]));
}
// replace splitter to '/'
s = s.replace(/[\s:\-T]/g, '/');
s += '/0/0/0'; // 日付だけのときのために時間分を足す
const a = s.split('/');
return new Date(parseInt(a[0]), parseInt(a[1]) - 1, parseInt(a[2]), parseInt(a[3]), parseInt(a[4]), parseInt(a[5]));
};
// 『継続表示』のための一時変数(『表示』実行で初期化)
sys.__printPool = '';
// 暗黙の型変換で足し算を行うときに使用。bigint はそのまま、その他は number に自動変換
sys.__parseFloatOrBigint = (v) => {
return (typeof v) === 'bigint' ? v : parseFloat(v);
};
// undefinedチェック
system.chk = (value, constId) => {
if (typeof value === 'undefined') {
const cp = system.constPools[constId];
const [msgNo, msgArgs, fileNo, lineNo] = cp;
let msg = system.constPoolsTemplate[msgNo];
for (const i in msgArgs) {
const arg = system.constPoolsTemplate[msgArgs[i]];
msg = msg.split(`$${i}`).join(arg);
}
const fileStr = system.constPoolsTemplate[fileNo];
sys.logger.warn(msg, { file: fileStr, line: lineNo });
}
return value;
};
// eval function #1733
sys.__evalSafe = (src) => {
// evalのスコープを変えるためのテクニック
// https://esbuild.github.io/content-types/#direct-eval
const _eval = eval;
try {
return _eval(src);
}
catch (e) {
console.warn('[eval]', e);
return null;
}
};
// eval function #1733 - 互換性を優先するため、direct evalを使うことに
sys.__evalJS = (src, sys) => {
try {
// まず従来通りevalで評価(式の値を返す互換性を維持)
return eval(src);
}
catch (e) {
// return文によるSyntaxErrorの場合のみIIFEで再試行 (#NE-006)
if (e instanceof SyntaxError && e.message.includes('return')) {
try {
return (new Function('sys', `return (function(sys){\n${src}\n})(sys)`))(sys);
}
catch (e2) {
console.warn('[eval]', e2);
return null;
}
}
console.warn('[eval]', e);
return null;
}
};
// Propアクセス支援
sys.__registPropAccessor = (f, getProp, setProp) => {
system.__propAccessor.push({
target: f,
getProp,
setProp
});
};
sys.__checkPropAccessor = (mode, obj) => {
if ((mode === 'get' && obj.__getProp === undefined) || (mode === 'set' && obj.__setProp === undefined)) {
for (let i = 0; i < system.__propAccessor.length; i++) {
const accs = system.__propAccessor[i];
if (accs.target[Symbol.hasInstance](obj)) {
if (accs.getProp) {
obj.__getProp = accs.getProp;
}
else {
obj.__getProp = null;
}
if (accs.setProp) {
obj.__setProp = accs.setProp;
}
else {
obj.__setProp = null;
}
return;
}
}
obj.__getProp = obj.__setProp = null;
}
};
// 「??」ハテナ関数の設定
sys.__hatena = sys.__getSysVar('デバッグ表示');
}
},
'!クリア': {
type: 'func',
josi: [],
fn: function (sys) {
if (sys.__exec) {
sys.__exec('全タイマー停止', [sys]);
}
sys.__setSysVar('表示ログ', '');
}
},
// @システム定数
'ナデシコバージョン': { type: 'const', value: '?' }, // @なでしこばーじょん
'ナデシコ言語バージョン': { type: 'const', value: '?' }, // @なでしこげんごばーじょん
'ナデシコエンジン': { type: 'const', value: 'nadesi.com/v3' }, // @なでしこえんじん
'ナデシコ種類': { type: 'const', value: '?' }, // @なでしこしゅるい
'はい': { type: 'const', value: true }, // @はい
'いいえ': { type: 'const', value: false }, // @いいえ
'真': { type: 'const', value: true }, // @しん
'偽': { type: 'const', value: false }, // @ぎ
'永遠': { type: 'const', value: true }, // @えいえん
'オン': { type: 'const', value: true }, // @おん
'オフ': { type: 'const', value: false }, // @おふ
'改行': { type: 'const', value: '\n' }, // @かいぎょう
'タブ': { type: 'const', value: '\t' }, // @たぶ
'カッコ': { type: 'const', value: '「' }, // @かっこ
'カッコ閉': { type: 'const', value: '」' }, // @かっことじ
'波カッコ': { type: 'const', value: '{' }, // @なみかっこ
'波カッコ閉': { type: 'const', value: '}' }, // @なみかっことじ
'OK': { type: 'const', value: true }, // @OK
'NG': { type: 'const', value: false }, // @NG
'キャンセル': { type: 'const', value: 0 }, // @きゃんせる
'TRUE': { type: 'const', value: true }, // @TRUE
'FALSE': { type: 'const', value: false }, // @FALSE
'true': { type: 'const', value: true }, // @true
'false': { type: 'const', value: false }, // @false
'PI': { type: 'const', value: Math.PI }, // @PI
'空': { type: 'const', value: '' }, // @から
'NULL': { type: 'const', value: null }, // @NULL
'undefined': { type: 'const', value: undefined }, // @undefined
'未定義': { type: 'const', value: undefined }, // @みていぎ
'エラーメッセージ': { type: 'const', value: '' }, // @えらーめっせーじ
'対象': { type: 'const', value: '' }, // @たいしょう
'対象キー': { type: 'const', value: '' }, // @たいしょうきー
'回数': { type: 'const', value: '' }, // @かいすう
'CR': { type: 'const', value: '\r' }, // @CR
'LF': { type: 'const', value: '\n' }, // @LF
'非数': { type: 'const', value: NaN }, // @ひすう
'無限大': { type: 'const', value: Infinity }, // @むげんだい
'戻値無': { type: 'const', value: 0 }, // @もどりちなし
'戻値有': { type: 'const', value: 1 }, // @もどりちあり
'空配列': {
type: 'func',
josi: [],
pure: true,
fn: function () {
return [];
}
},
'空辞書': {
type: 'func',
josi: [],
pure: true,
fn: function () {
return {};
}
},
'空ハッシュ': {
type: 'func',
josi: [],
pure: true,
fn: function () {
return {};
}
},
'空オブジェクト': {
type: 'func',
josi: [],
pure: false,
fn: function (sys) {
return sys.__exec('空ハッシュ', [sys]);
}
},
'真偽判定': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (b) {
return b ? '真' : '偽';
}
},
// @標準出力
'表示': {
type: 'func',
josi: [['を', 'と']],
pure: true,
fn: function (s, sys) {
// 継続表示の一時プールを出力
s = String(sys.__printPool) + s;
sys.__printPool = '';
//
sys.__setSysVar('表示ログ', String(sys.__getSysVar('表示ログ')) + s + '\n');
sys.logger.send('stdout', s + '');
},
return_none: true
},
'継続表示': {
type: 'func',
josi: [['を', 'と']],
pure: true,
fn: function (s, sys) {
sys.__printPool += s;
},
return_none: true
},
'連続表示': {
type: 'func',
josi: [['と', 'を']],
isVariableJosi: true,
pure: true,
fn: function (...a) {
const sys = a.pop();
const v = a.join('');
sys.__exec('表示', [v, sys]);
},
return_none: true
},
'連続無改行表示': {
type: 'func',
josi: [['と', 'を']],
isVariableJosi: true,
pure: true,
fn: function (...a) {
const sys = a.pop();
const v = a.join('');
sys.__exec('継続表示', [v, sys]);
},
return_none: true
},
'表示ログ': { type: 'const', value: '' }, // @ひょうじろぐ
'表示ログクリア': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
sys.__setSysVar('表示ログ', '');
},
return_none: true
},
'言': {
type: 'func',
josi: [['を', 'と']],
pure: true,
fn: function (s, sys) {
sys.logger.send('stdout', s + '');
},
return_none: true
},
'コンソール表示': {
type: 'func',
josi: [['を', 'と']],
pure: true,
fn: function (s) {
console.log(s);
},
return_none: true
},
// @四則演算
'足': {
type: 'func',
josi: [['に', 'と'], ['を']],
isVariableJosi: false,
pure: true,
fn: function (a, b) {
if (typeof (a) === 'bigint' || typeof (b) === 'bigint') {
return BigInt(a) + BigInt(b);
}
return parseFloat(a) + parseFloat(b);
}
},
'合計': {
type: 'func',
josi: [['と', 'を', 'の']],
isVariableJosi: true,
pure: true,
fn: function (...a) {
const sys = a.pop(); // remove NakoSystem
if (a.length >= 1 && a[0] instanceof Array) {
return sys.__exec('配列合計', [a[0], sys]);
}
let isBigInt = false;
let sum = 0;
for (const v of a) {
if (typeof (v) === 'bigint') {
isBigInt = true;
break;
}
sum += parseFloat(v);
}
if (isBigInt) {
let bigsum = 0n;
for (const v of a) {
bigsum += BigInt(v);
}
return bigsum;
}
return sum;
}
},
'引': {
type: 'func',
josi: [['から'], ['を']],
pure: true,
fn: function (a, b) {
return a - b;
}
},
'掛': {
type: 'func',
josi: [['に', 'と'], ['を']],
pure: true,
fn: function (a, b) {
// 数値の掛け算
if (typeof a === 'number') {
return a * b;
}
// 文字列の掛け算(文字列の繰り返し)
if (typeof a === 'string') {
let s = '';
for (let i = 0; i < parseInt(b); i++) {
s += a;
}
return s;
}
// 配列の繰り返し
if (a instanceof Array) {
const aa = [];
for (let i = 0; i < parseInt(b); i++) {
aa.push(...a);
}
return aa;
}
return a * b;
}
},
'倍': {
type: 'func',
josi: [['の', 'を'], ['']],
pure: true,
fn: function (a, b) {
return a * b;
}
},
'割': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (a, b) {
return a / b;
}
},
'割余': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (a, b) {
return a % b;
}
},
'偶数': {
type: 'func',
josi: [['が']],
pure: true,
fn: function (a) {
return (parseInt(a) % 2 === 0);
}
},
'奇数': {
type: 'func',
josi: [['が']],
pure: true,
fn: function (a) {
return (parseInt(a) % 2 === 1);
}
},
'二乗': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (a) {
return a * a;
}
},
'べき乗': {
type: 'func',
josi: [['の'], ['の']],
pure: true,
fn: function (a, b) {
return Math.pow(a, b);
}
},
'以上': {
type: 'func',
josi: [['が'], ['']],
pure: true,
fn: function (a, b) {
return a >= b;
}
},
'以下': {
type: 'func',
josi: [['が'], ['']],
pure: true,
fn: function (a, b) {
return a <= b;
}
},
'未満': {
type: 'func',
josi: [['が'], ['']],
pure: true,
fn: function (a, b) {
return a < b;
}
},
'超': {
type: 'func',
josi: [['が'], ['']],
pure: true,
fn: function (a, b) {
return a > b;
}
},
'等': {
type: 'func',
josi: [['が'], ['と']],
pure: true,
fn: function (a, b) {
return a === b;
}
},
'等無': {
type: 'func',
josi: [['が'], ['と']],
pure: true,
fn: function (a, b) {
return a !== b;
}
},
'一致': {
type: 'func',
josi: [['が'], ['と']],
pure: true,
fn: function (a, b) {
// オブジェクトの場合、JSONに変換して比較
if (typeof (a) === 'object') {
const jsonA = JSON.stringify(a);
const jsonB = JSON.stringify(b);
return jsonA === jsonB;
}
return a === b;
}
},
'不一致': {
type: 'func',
josi: [['が'], ['と']],
pure: true,
fn: function (a, b) {
// オブジェクトの場合、JSONに変換して比較
if (typeof (a) === 'object') {
const jsonA = JSON.stringify(a);
const jsonB = JSON.stringify(b);
return jsonA !== jsonB;
}
return a !== b;
}
},
'範囲内': {
type: 'func',
josi: [['が'], ['から'], ['の', 'までの']],
pure: true,
fn: function (v, a, b) {
return (a <= v) && (v <= b);
}
},
'範囲': {
type: 'func',
josi: [['から'], ['の', 'までの']],
pure: true,
fn: function (a, b) {
return {
'先頭': a,
'末尾': b
};
}
},
'連続加算': {
type: 'func',
josi: [['を'], ['に', 'と']],
isVariableJosi: true,
pure: true,
fn: function (b, ...a) {
a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外
a.push(b);
return a.reduce((p, c) => p + c);
}
},
'MAX': {
type: 'func',
josi: [['の'], ['と']],
isVariableJosi: true,
pure: true,
fn: function (b, ...a) {
const sys = a.pop();
return sys.__exec('最大値', [b, ...a, sys]);
}
},
'最大値': {
type: 'func',
josi: [['の'], ['と']],
isVariableJosi: true,
pure: true,
fn: function (b, ...a) {
a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外
a.push(b);
return a.reduce((p, c) => Math.max(p, c));
}
},
'MIN': {
type: 'func',
josi: [['の'], ['と']],
isVariableJosi: true,
pure: true,
fn: function (b, ...a) {
const sys = a.pop();
return sys.__exec('最小値', [b, ...a, sys]);
}
},
'最小値': {
type: 'func',
josi: [['の'], ['と']],
isVariableJosi: true,
pure: true,
fn: function (b, ...a) {
a.pop(); // 必ず末尾に sys があるので、末尾のシステム変数を除外
a.push(b);
return a.reduce((p, c) => Math.min(p, c));
}
},
'CLAMP': {
type: 'func',
josi: [['の', 'を'], ['から'], ['までの', 'で']],
pure: true,
fn: function (x, a, b) {
return Math.min(Math.max(x, a), b);
}
},
// @敬語
'ください': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__reisetu) {
sys.__reisetu = 0;
}
sys.__reisetu++;
},
return_none: true
},
'お願': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__reisetu) {
sys.__reisetu = 0;
}
sys.__reisetu++;
},
return_none: true
},
'です': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__reisetu) {
sys.__reisetu = 0;
}
sys.__reisetu++;
},
return_none: true
},
'拝啓': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
sys.__reisetu = 0;
},
return_none: true
},
'敬具': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
sys.__reisetu += 100; // bonus point
},
return_none: true
},
'礼節レベル取得': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
if (!sys.__reisetu) {
sys.__reisetu = 0;
}
return sys.__reisetu;
}
},
// @特殊命令
'JS実行': {
type: 'func',
josi: [['を', 'で']],
pure: true,
fn: function (src, sys) {
return sys.__evalJS(src, sys); // #1733
}
},
'JSオブジェクト取得': {
type: 'func',
josi: [['の']],
pure: false,
fn: function (name, sys) {
return sys.__findVar(name, null);
}
},
'JS関数実行': {
type: 'func',
josi: [['を'], ['で']],
fn: function (name, args, sys) {
// nameが文字列ならevalして関数を得る
if (typeof name === 'string') {
name = sys.__evalJS(name, sys);
}
if (typeof name !== 'function') {
throw new Error('JS関数取得で実行できません。');
}
// argsがArrayでなければArrayに変換する
if (!(args instanceof Array)) {
args = [args];
}
// 実行
// eslint-disable-next-line prefer-spread
return name.apply(null, args);
}
},
'ASYNC': {
type: 'func',
josi: [],
asyncFn: true,
pure: true,
fn: async function () {
// empty
},
return_none: true
},
'AWAIT実行': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
asyncFn: true,
fn: async function (f, args, sys) {
// nameが文字列ならevalして関数を得る
if (typeof f === 'string') {
f = sys.__findFunc(f, 'AWAIT実行');
}
if (!(f instanceof Function)) {
throw new Error('『AWAIT実行』の第一引数はなでしこ関数名かFunction型で指定してください。');
}
// 実行
return await f(...args);
}
},
'JSメソッド実行': {
type: 'func',
josi: [['の'], ['を'], ['で']],
fn: function (obj, m, args, sys) {
// objが文字列ならevalして関数を得る
if (typeof obj === 'string') {
obj = sys.__evalJS(obj, sys);
}
if (typeof obj !== 'object') {
throw new Error('JSオブジェクトを取得できませんでした。');
}
// method を求める
if (typeof m !== 'function') {
m = obj[m];
}
// argsがArrayでなければArrayに変換する
if (!(args instanceof Array)) {
args = [args];
}
// 実行
return m.apply(obj, args);
}
},
'ナデシコ': {
type: 'func',
josi: [['を', 'で']],
pure: false,
asyncFn: true,
fn: async function (code, sys) {
const options = {
resetEnv: false,
resetAll: true,
nakoGlobal: sys
};
const tmpLog = String(sys.__getSysVar('表示ログ', ''));
sys.__setSysVar('表示ログ', '');
await sys.__self.runAsync(code, sys.__modName, options);
const outLog = String(sys.__getSysVar('表示ログ'));
sys.__setSysVar('表示ログ', tmpLog + outLog);
return outLog;
}
},
'ナデシコ続': {
type: 'func',
josi: [['を', 'で']],
pure: false,
asyncFn: true,
fn: async function (code, sys) {
const options = {
resetEnv: false,
resetAll: false,
nakoGlobal: sys.__self
};
const tmpLog = sys.__getSysVar('表示ログ', '');
sys.__setSysVar('表示ログ', '');
await sys.__self.runAsync(code, sys.__modName, options);
const outLog = String(sys.__getSysVar('表示ログ'));
if (outLog) {
sys.logger.trace(outLog);
}
sys.__setSysVar('表示ログ', tmpLog + outLog);
return outLog;
}
},
'実行': {
type: 'func',
josi: [['を', 'に', 'で']],
pure: false,
fn: function (f, sys) {
// #938 の規則に従って処理
// 引数が関数なら実行
if (typeof f === 'function') {
return f(sys);
}
// 文字列なら関数に変換できるか判定して実行
if (typeof f === 'string') {
const tf = sys.__findFunc(f, '実行');
if (typeof tf === 'function') {
return tf(sys);
}
}
// それ以外ならそのまま値を返す
return f;
}
},
'実行時間計測': {
type: 'func',
josi: [['の']],
pure: false,
fn: function (f, sys) {
if (typeof f === 'string') {
f = sys.__findFunc(f, '実行時間計測');
}
//
if (performance && performance.now) {
const t1 = performance.now();
f(sys);
const t2 = performance.now();
return (t2 - t1);
}
else {
const t1 = Date.now();
f(sys);
const t2 = Date.now();
return (t2 - t1);
}
}
},
'終': {
type: 'func',
josi: [],
pure: true,
fn: function (sys) {
// デバッグモードでなければ例外を投げることでプログラムを終了させる
sys.__setSysVar('__forceClose', true);
if (!sys.__getSysVar('__useDebug')) {
throw new Error('__終わる__');
}
}
},
// @型変換
'変数型確認': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return (typeof v);
}
},
'TYPEOF': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return (typeof v);
}
},
'文字列変換': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return String(v);
}
},
'TOSTR': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return String(v);
}
},
'整数変換': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return parseInt(v);
}
},
'TOINT': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return parseInt(v);
}
},
'実数変換': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return parseFloat(v);
}
},
'TOFLOAT': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return parseFloat(v);
}
},
'INT': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return parseInt(v);
}
},
'FLOAT': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return parseFloat(v);
}
},
'NAN判定': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
return isNaN(v);
}
},
'非数判定': {
type: 'func',
josi: [['を']],
pure: true,
fn: function (v) {
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
return Number.isNaN(v);
}
},
'HEX': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (a) {
return parseInt(a).toString(16);
}
},
'進数変換': {
type: 'func',
josi: [['を', 'の'], ['']],
pure: true,
fn: function (v, n) {
return parseInt(v).toString(n);
}
},
'二進': {
type: 'func',
josi: [['を', 'の', 'から']],
pure: true,
fn: function (v) {
return parseInt(v).toString(2);
}
},
'二進表示': {
type: 'func',
josi: [['を', 'の', 'から']],
pure: true,
fn: function (v, sys) {
const s = parseInt(v).toString(2);
sys.__exec('表示', [s, sys]);
}
},
'RGB': {
type: 'func',
josi: [['と'], ['の'], ['で']],
pure: true,
fn: function (r, g, b) {
const z2 = (v) => {
const v2 = '00' + (parseInt(String(v)).toString(16));
return v2.substring(v2.length - 2, v2.length);
};
return '#' + z2(r) + z2(g) + z2(b);
}
},
// @論理演算
'論理OR': {
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function (a, b) {
return (a || b);
}
},
'論理AND': {
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function (a, b) {
return (a && b);
}
},
'論理NOT': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return (!v);
}
},
// @ビット演算
'OR': {
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function (a, b) {
return (a | b);
}
},
'AND': {
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function (a, b) {
return (a & b);
}
},
'XOR': {
type: 'func',
josi: [['と'], ['の']],
pure: true,
fn: function (a, b) {
return (a ^ b);
}
},
'NOT': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
return (~v);
}
},
'SHIFT_L': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (v, a) {
return (v << a);
}
},
'SHIFT_R': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (v, a) {
return (v >> a);
}
},
'SHIFT_UR': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (v, a) {
return (v >>> a);
}
},
// @文字列処理
'文字数': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
if (!Array.from) {
return String(v).length;
}
// Unicodeのサロゲートペアを考慮して文字数をカウント #1954 を参照
return Array.from(v).length;
}
},
'何文字目': {
type: 'func',
josi: [['で', 'の'], ['が']],
pure: true,
fn: function (s, a) {
// Unicodeのサロゲートペアを考慮して、文字列を検索 #1954 を参照
// return String(s).indexOf(a) + 1 // サロゲートペアを無視した場合
const strArray = Array.from(s);
const searchArray = Array.from(a);
for (let i = 0; i < strArray.length; i++) {
if (strArray.slice(i, i + searchArray.length).join('') === searchArray.join('')) {
return i + 1;
}
}
return 0;
}
},
'CHR': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
// 数値のとき
if (typeof v === 'number') {
if (!String.fromCodePoint) {
return String.fromCharCode(v);
}
return String.fromCodePoint(v);
}
// 配列のとき
const res = [];
for (const s of v) {
if (!String.fromCodePoint) {
res.push(String.fromCharCode(s));
}
res.push(String.fromCodePoint(s));
}
return res;
}
},
'ASC': {
type: 'func',
josi: [['の']],
pure: true,
fn: function (v) {
if (typeof v === 'string') {
if (!String.prototype.codePointAt) {
return String(v).charCodeAt(0);
}
return String(v).codePointAt(0) || 0;
}
const res = [];
for (const s of v) {
if (!String.prototype.codePointAt) {
res.push(String(s).charCodeAt(0));
}
res.push(String(s).codePointAt(0) || 0);
}
return res;
}
},
'文字挿入': {
type: 'func',
josi: [['で', 'の'], ['に', 'へ'], ['を']],
pure: true,
fn: function (s, i, a) {
if (i <= 0) {
i = 1;
}
const strArray = Array.from(s);
strArray.splice(i - 1, 0, a);
return strArray.join('');
}
},
'文字検索': {
type: 'func',
josi: [['で', 'の'], ['から'], ['を']],
pure: true,
fn: function (s, a, b) {
// サロゲートペアを考慮して文字列を検索する
// return String(s).indexOf(b, a - 1) + 1
if (a <= 0) {
a = 1;
}
const strArray = Array.from(s);
const searchArray = Array.from(b);
// Unicode単位で検索
for (let i = a - 1; i < strArray.length; i++) {
if (strArray.slice(i, i + searchArray.length).join('') === searchArray.join('')) {
// 合致した
return i + 1;
}
}
return 0;
}
},
'追加': {
type: 'func',
josi: [['で', 'に', 'へ'], ['を']],
pure: true,
fn: function (s, a) {
if (s instanceof Array) {
s.push(a);
return s;
}
return String(s) + String(a);
}
},
'一行追加': {
type: 'func',
josi: [['で', 'に', 'へ'], ['を']],
pure: true,
fn: function (s, a) {
if (s instanceof Array) {
s.push(a);
return s;
}
return String(s) + String(a) + '\n';
}
},
'連結': {
type: 'func',
josi: [['と', 'を']],
pure: true,
isVariableJosi: true,
fn: function (...a) {
a.pop(); // NakoSystemを取り除く
return a.join('');
}
},
'文字列連結': {
type: 'func',
josi: [['と', 'を']],
pure: true,
isVariableJosi: true,
fn: function (...a) {
a.pop(); // NakoSystemを取り除く
return a.join('');
}
},
'文字列分解': {
type: 'func',
josi: [['を', 'の', 'で']],
pure: true,
fn: function (v) {
if (!Array.from) {
return String(v).split('');
}
return Array.from(v);
}
},
'リフレイン': {
type: 'func',
josi: [['を', 'の'], ['で']],
pure: true,
fn: function (v, cnt) {
let s = '';
for (let i = 0; i < cnt; i++) {
s += String(v);
}
return s;
}
},
'出現回数': {
type: 'func',
josi: [['で'], ['の']],
pure: true,
fn: function (s, a) {
s = '' + s;
a = '' + a;
return s.split(a).length - 1;
}
},
'MID': {
type: 'func',
josi: [['で', 'の'], ['から'], ['を']],
pure: true,
fn: function (s, a, cnt, sys) {
return sys.__exec('文字抜出', [s, a, cnt]);
}
},
'文字抜出': {
type: 'func',
josi: [['で', 'の'], ['から'], ['を', '']],
pure: true,
fn: function (s, a, cnt) {
// 引数の型チェック #1995
if (typeof a === 'string') {
a = parseInt(a);
}
if (typeof cnt === 'string') {
cnt = parseInt(cnt);
}
// もし、cntが0以下なら空文字を返す
if (cnt <= 0) {
return '';
}
// サロゲートペアを考慮した処理を行う
const strArray = Array.from(s);
// もし、aの値が0未満の時は後ろからa文字目からcnt文字を抽出
if (a < 0) {
a = strArray.length + a + 1;
if (a < 0) {
a = 1;
}
}
return strArray.slice(a - 1, a + cnt - 1).join('');
}
},
'LEFT': {
type: 'func',
josi: [['の', 'で'], ['だけ']],
pure: true,
fn: function (s, cnt, sys) {
return sys.__exec('文字左部分', [s, cnt]);
}
},
'文字左部分': {
type: 'func',
josi: [['の', 'で'], ['だけ', '']],
pure: true,
fn: function (s, cnt) {
// return (String(s).substring(0, cnt))
// サロゲートペアを考慮
const strArray = Array.from(s);
return strArray.slice(0, cnt).join('');
}
},
'RIGHT': {
type: 'func',
josi: [['の', 'で'], ['だけ']],
pure: true,
fn: function (s, cnt, sys) {
return sys.__exec('文字右部分', [s, cnt]);
}
},
'文字右部分': {
type: 'func',
josi: [['の', 'で'], ['だけ', '']],
pure: true,
fn: function (s, cnt) {
// return (s.substring(s.length - cnt, s.length))
// サロゲートペアを考慮
const strArray = Array.from(s);
let index = strArray.length - cnt;
if (index < 0) {
index = 0;
}
return strArray.slice(index, strArray.length).join('');
}
},
'区切': {
type: 'func',
josi: [['の', 'を'], ['で']],
pure: true,
fn: function (s, a) {
return ('' + s).split('' + a);
}
},
'文字列分割': {
type: 'func',
josi: [['を'], ['で']],
pure: true,
fn: function (s, a) {
s = '' + s;
a = '' + a;
const i = s.indexOf(a);
if (i < 0) {
return [s];
}
return [s.substring(0, i), s.substring(i + a.length)];
}
},
'切取': {
type: 'func',
josi: [['から', 'の'], ['まで', 'を']],
pure: true,
fn: function (s, a, sys) {
s = String(s);
const i = s.indexOf(a);
if (i < 0) {
sys.__setSysVar('対象', '');
return s;
}
sys.__setSysVar('対象', s.substring(i + a.length));
return s.substring(0, i);
}
},
'範囲切取': {
type: 'func',
josi: [['で', 'の'], ['から'], ['まで', 'を']],
pure: true,
fn: function (s, a, b, sys) {
s = String(s);
let mae = '';
let usiro = '';
const i = s.indexOf(a);
if (i < 0) {
sys.__setSysVar('対象', s);
return '';
}
mae = s.substring(0, i);
const subS = s.substring(i + a.length);
const j = subS.indexOf(b);
if (j < 0) {
sys.__setSysVar('対象', mae);
return subS;
}
const result = subS.substring(0, j);
usiro = subS.substring(j + b.length);
sys.__setSysVar('対象', mae + usiro);
return result;
}
},
'文字削除': {
type: 'func',
josi: [['の'], ['から'], ['だけ', 'を', '']],
pure: true,
fn: function (s, a, b) {
// サロゲートペアを考慮
const strArray = Array.from(s);
strArray.splice(a - 1, b);
return strArray.join('');
}
},
'文字始': {
type: 'func',
josi: [['が'], ['で', 'から']],
pure: true,
fn: function (s, a) {
return s.startsWith(a);
}
},
'文字終': {
type: 'func',
josi: [['が'], ['で']],
pure: true,
fn: function (s, a) {
return s.endsWith(a);
}
},
'出現': {
type: 'func',
josi: [['に', 'で'], ['が']],
pure: true,
fn: function (s, a) {
if (typeof (s) === 'string') {
return s.includes(a);
}
if (s instanceof Array) {
return s.includes(a);
}
const ss = String(s);
return ss.includes(a);
}
},
// @置換・トリム
'置換': {
type: 'func',
josi: [['の', 'で'], ['を', 'から'], ['に', 'へ']],
pure: true,
fn: function (s, a, b) {
return String(s).split(a).join(b);
}
},
'単置換': {
type: 'func',
josi: [['の', 'で'], ['を'], ['に', 'へ']],
pure: true,
fn: function (s, a, b) {
// replaceは最初の一度だけ置換する
return String(s).replace(a, b);
}
},
'トリム': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/^\s+/, '').replace(/\s+$/, '');
}
},
'空白除去': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/^\s+/, '').replace(/\s+$/, '');
}
},
'右トリム': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/\s+$/, '');
}
},
'左トリム': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/^\s+/, '');
}
},
'末尾空白除去': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/\s+$/, '');
}
},
// @文字変換
'大文字変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).toUpperCase();
}
},
'小文字変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).toLowerCase();
}
},
'平仮名変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
const kanaToHira = (str) => {
return String(str).replace(/[\u30a1-\u30f6]/g, function (m) {
const chr = m.charCodeAt(0) - 0x60;
return String.fromCharCode(chr);
});
};
return kanaToHira('' + s);
}
},
'カタカナ変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
const hiraToKana = (str) => {
return String(str).replace(/[\u3041-\u3096]/g, function (m) {
const chr = m.charCodeAt(0) + 0x60;
return String.fromCharCode(chr);
});
};
return hiraToKana('' + s);
}
},
'英数全角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/[A-Za-z0-9]/g, function (v) {
return String.fromCharCode(v.charCodeAt(0) + 0xFEE0);
});
}
},
'英数半角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/[A-Za-z0-9]/g, function (v) {
return String.fromCharCode(v.charCodeAt(0) - 0xFEE0);
});
}
},
'英数記号全角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/[\x20-\x7E]/g, function (v) {
if (v === ' ') {
return ' ';
} // 半角スペース(0x20)を全角スペース(U+3000)に
return String.fromCharCode(v.charCodeAt(0) + 0xFEE0);
});
}
},
'英数記号半角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s) {
return String(s).replace(/[\u3000\uFF00-\uFF5F]/g, function (v) {
if (v === ' ') {
return ' ';
} // 全角スペース(U+3000)を半角スペース(U+0020)
return String.fromCharCode(v.charCodeAt(0) - 0xFEE0);
});
}
},
'カタカナ全角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s, sys) {
// 半角カタカナ
const zen1 = sys.__getSysVar('全角カナ一覧');
const han1 = sys.__getSysVar('半角カナ一覧');
const zen2 = sys.__getSysVar('全角カナ濁音一覧');
const han2 = sys.__getSysVar('半角カナ濁音一覧');
let str = '';
let i = 0;
while (i < s.length) {
// 濁点の変換
const c2 = s.substring(i, i + 2);
const n2 = han2.indexOf(c2);
if (n2 >= 0) {
str += zen2.charAt(n2 / 2);
i += 2;
continue;
}
// 濁点以外の変換
const c = s.charAt(i);
const n = han1.indexOf(c);
if (n >= 0) {
str += zen1.charAt(n);
i++;
continue;
}
str += c;
i++;
}
return str;
}
},
'カタカナ半角変換': {
type: 'func',
josi: [['の', 'を']],
pure: true,
fn: function (s, sys) {
// 半角カタカナ
const zen1 = sys.__getSysVar('全角カナ一覧');
const han1 = sys.__getSysVar('半角カナ一覧');
const zen2 = sys.__getSysVar('全角カナ濁音一覧');
const han2 = sys.__getSysVar('半角カナ濁音一覧');
return s.split('').map((c) => {
const i = zen1.indexOf(c);
if (i >= 0) {
return han1.charAt(i);
}
const j = zen2.indexOf(c);
if (j >= 0) {
return han2.substring(j * 2, j * 2 + 2);
}
return c;
}).join('');
}
},
'全角変換': {
type: 'func',
josi: [['の', 'を']],
pure: false,
fn: function (s, sys) {
let result = s;
result = sys.__exec('カタカナ全角変換', [result, sys]);
result = sys.__exec('英数記号全角変換', [result, sys]);
return result;
}
},
'半角変換': {
type: 'func',
josi: [['の', 'を']],
pure: false,
fn: function (s, sys) {
let result = s;
result = sys.__exec('カタカナ半角変換', [result, sys]);
result = sys.__exec('英数記号半角変換', [result, sys]);
return result;
}
},
'全角カナ一覧': { type: 'const', value: 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァィゥェォャュョッ、。ー「」' }, // @ぜんかくかないちらん
'全角カナ濁音一覧': { type: 'const', value: 'ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ' }, // @ぜんかくかなだくおんいちらん
'半角カナ一覧': { type: 'const', value: 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲンァ