diff --git a/batch/pickup_command.nako3 b/batch/pickup_command.nako3
index 6de01b520..9babb5655 100644
--- a/batch/pickup_command.nako3
+++ b/batch/pickup_command.nako3
@@ -27,12 +27,12 @@ REPOSパス=基本パスを「../」で相対パス展開。
['src/plugin_promise.js', 'wnako']
]
拡張プラグイン一覧は[
- ['nadesiko3-sqlite3/src/nadesiko3-sqlite3.js', 'cnako'],
- ['nadesiko3-sqlite3sync/nadesiko3-sqlite3sync.js', 'cnako'],
+ ['nadesiko3-sqlite3/nadesiko3-sqlite3.js', 'cnako'],
['nadesiko3-drone/nadesiko3-drone.js', 'cnako'],
['nadesiko3-htmlparser/nadesiko3-htmlparser.js', 'cnako'],
['nadesiko3-websocket/nadesiko3-websocket.js', 'cnako'],
['nadesiko3-ml/nadesiko3-ml.js', 'cnako'],
+ ['nadesiko3-mecab/nadesiko3-mecab.js', 'cnako'],
['nadesiko3-odbc/src/plugin_odbc.js', 'cnako'],
['nadesiko3-mssql/src/plugin_mssql.js', 'cnako'],
['nadesiko3-mysql/src/plugin_mysql.js', 'cnako'],
@@ -42,7 +42,8 @@ REPOSパス=基本パスを「../」で相対パス展開。
# サポートしない
# 'nadesiko3-firebase/plugin_firebase.js',
# 'nadesiko3-googlehome/plugin_googlehome.js',
-
+# 'nadesiko3-sqlite3sync/nadesiko3-sqlite3sync.js', # 利用は非推奨に
+
#------------------------
結果データ=「」
基本プラグイン一覧を反復
diff --git a/demo/browsers.html b/demo/browsers.html
index 029c91bec..fd2c60529 100644
--- a/demo/browsers.html
+++ b/demo/browsers.html
@@ -9,23 +9,23 @@
デスクトップ
- IE (11以上)
- - Edge (99/98/97以上)
- - Firefox (98/97/96/91以上)
- - Chrome (100/99/98/97/96以上)
- - Safari (15.4/15.2-15.3/14.1以上)
+ - Edge (98/97/96以上)
+ - Firefox (96/95/91/78以上)
+ - Chrome (98/97/96/93以上)
+ - Safari (15.2-15.3/15.1/14.1以上)
- Opera (83/82以上)
- - Node.js (17.4.0/16.13.0/14.19.0/12.22.0以上)
+ - Node.js (17.0.0/16.12.0/14.18.0/12.22.0以上)
モバイル
- - Safari on iOS (15.4/15.2-15.3/15.0-15.1/14.5-14.8/14.0-14.4/12.2-12.5以上)
+ - Safari on iOS (15.2-15.3/15.0-15.1/14.5-14.8/14.0-14.4/12.2-12.5以上)
- Opera Mini (all以上)
- - Android Browser (99以上)
+ - Android Browser (97以上)
- Opera Mobile (64以上)
- - Chrome for Android (100以上)
- - Firefox for Android (98以上)
+ - Chrome for Android (97以上)
+ - Firefox for Android (96以上)
- UC Browser for Android (12.12以上)
- Samsung Internet (16.0/15.0以上)
- QQ Browser (10.4以上)
diff --git a/doc/browsers.md b/doc/browsers.md
index a8f4dbafa..c1f980834 100644
--- a/doc/browsers.md
+++ b/doc/browsers.md
@@ -5,21 +5,21 @@
## デスクトップ
- IE (11以上)
-- Edge (99/98/97以上)
-- Firefox (98/97/96/91以上)
-- Chrome (100/99/98/97/96以上)
-- Safari (15.4/15.2-15.3/14.1以上)
+- Edge (98/97/96以上)
+- Firefox (96/95/91/78以上)
+- Chrome (98/97/96/93以上)
+- Safari (15.2-15.3/15.1/14.1以上)
- Opera (83/82以上)
-- Node.js (17.4.0/16.13.0/14.19.0/12.22.0以上)
+- Node.js (17.0.0/16.12.0/14.18.0/12.22.0以上)
## モバイル
-- Safari on iOS (15.4/15.2-15.3/15.0-15.1/14.5-14.8/14.0-14.4/12.2-12.5以上)
+- Safari on iOS (15.2-15.3/15.0-15.1/14.5-14.8/14.0-14.4/12.2-12.5以上)
- Opera Mini (all以上)
-- Android Browser (99以上)
+- Android Browser (97以上)
- Opera Mobile (64以上)
-- Chrome for Android (100以上)
-- Firefox for Android (98以上)
+- Chrome for Android (97以上)
+- Firefox for Android (96以上)
- UC Browser for Android (12.12以上)
- Samsung Internet (16.0/15.0以上)
- QQ Browser (10.4以上)
diff --git a/node_modules.7z b/node_modules.7z
index 69067d889..cbded0613 100644
Binary files a/node_modules.7z and b/node_modules.7z differ
diff --git a/nodejs.7z b/nodejs.7z
index 085d30840..369c9bbd0 100644
Binary files a/nodejs.7z and b/nodejs.7z differ
diff --git a/package.json b/package.json
index 2610ab63f..227850659 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "nadesiko3",
- "version": "3.2.47",
+ "version": "3.2.51",
"description": "Japanese Programming Language",
"main": "src/index.js",
"bin": {
@@ -139,7 +139,6 @@
"mocha-css": "^1.0.1",
"module-alias": "^2.2.2",
"multer": "^1.4.3",
- "nadesiko3-hoge": "0.0.3",
"npm-check-updates": "^12.0.2",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
@@ -152,6 +151,7 @@
"ssri": "^8.0.1",
"standard": "^16.0.4",
"stats-webpack-plugin": "^0.7.0",
+ "stream-browserify": "^3.0.0",
"style-loader": "^3.3.1",
"stylelint": "^14.0.1",
"stylelint-config-standard": "^24.0.0",
@@ -179,8 +179,7 @@
"webpack": "^5.63.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.1",
- "ws": "^8.2.3",
- "stream-browserify": "^3.0.0"
+ "ws": "^8.2.3"
},
"dependencies": {
"body-parser": "^1.19.0",
@@ -195,6 +194,8 @@
"html": "^1.0.0",
"iconv-lite": "^0.6.3",
"marked": "^4.0.0",
+ "nadesiko3-htmlparser": "^0.0.4",
+ "nadesiko3-websocket": "^0.0.5",
"node-fetch": "^2.6.6",
"opener": "^1.5.2",
"readline-sync": "^1.4.10",
diff --git a/src/browsers.json b/src/browsers.json
index bf8bfb22b..fb4c2ebf7 100644
--- a/src/browsers.json
+++ b/src/browsers.json
@@ -1 +1 @@
-{"and_chr":["100"],"and_ff":["98"],"and_qq":["10.4"],"and_uc":["12.12"],"android":["99"],"baidu":["7.12"],"chrome":["100","99","98","97","96"],"edge":["99","98","97"],"firefox":["98","97","96","91"],"ie":["11"],"ios_saf":["15.4","15.2-15.3","15.0-15.1","14.5-14.8","14.0-14.4","12.2-12.5"],"kaios":["2.5"],"node":["17.4.0","16.13.0","14.19.0","12.22.0"],"op_mini":["all"],"op_mob":["64"],"opera":["83","82"],"safari":["15.4","15.2-15.3","14.1"],"samsung":["16.0","15.0"]}
\ No newline at end of file
+{"and_chr":["97"],"and_ff":["96"],"and_qq":["10.4"],"and_uc":["12.12"],"android":["97"],"baidu":["7.12"],"chrome":["98","97","96","93"],"edge":["98","97","96"],"firefox":["96","95","91","78"],"ie":["11"],"ios_saf":["15.2-15.3","15.0-15.1","14.5-14.8","14.0-14.4","12.2-12.5"],"kaios":["2.5"],"node":["17.0.0","16.12.0","14.18.0","12.22.0"],"op_mini":["all"],"op_mob":["64"],"opera":["83","82"],"safari":["15.2-15.3","15.1","14.1"],"samsung":["16.0","15.0"]}
\ No newline at end of file
diff --git a/src/nako3.js b/src/nako3.js
index 82c7e61b6..d0894379a 100644
--- a/src/nako3.js
+++ b/src/nako3.js
@@ -87,10 +87,10 @@ function NakoGen (mode) {
* checkInit?: boolean
* }} Ast
*
- * @typedef {(
- * | { type: 'func', josi: string[][], pure?: boolean, fn?: Function, return_none: boolean }
+ * @typedef {
+ * | { type: 'func', josi: string[][], pure?: boolean, fn?: Function, return_none: boolean, asyncFn: boolean }
* | { type: 'var' | 'const', value: any}
- * )} NakoFunction
+ * } NakoFunction
*/
class NakoCompiler {
@@ -123,7 +123,7 @@ class NakoCompiler {
this.pluginfiles = {} // 取り込んだファイル一覧
this.isSetter = false // 代入的関数呼び出しを管理(#290)
this.commandlist = new Set() // プラグインで定義された定数・変数・関数の名前
- /** @type {Record} */
+ /** @type {Record} */
this.nako_func = {} // __v1に配置するJavaScriptのコードで定義された関数
this.logger = new NakoLogger()
@@ -758,7 +758,7 @@ class NakoCompiler {
throw new Error('プラグインの追加でエラー。')
}
// コマンドを登録するか?
- if (key === '初期化' || key.substr(0, 1) === '!') { // 登録しない関数名
+ if (key === '初期化' || key.substring(0, 1) === '!') { // 登録しない関数名
continue
}
this.commandlist.add(key)
@@ -811,10 +811,11 @@ class NakoCompiler {
* @param {string} key 関数名
* @param {string[][]} josi 助詞
* @param {Function} fn 関数
- * @param {boolean} returnNone 値を返す関数の場合はfalseを設定する。
+ * @param {boolean} returnNone 値を返す関数の場合はfalseを指定
+ * @param {boolean} asyncFn Promiseを返す関数かを指定
*/
- addFunc (key, josi, fn, returnNone = true) {
- this.funclist[key] = { josi, fn, type: 'func', return_none: returnNone }
+ addFunc (key, josi, fn, returnNone = true, asyncFn = false) {
+ this.funclist[key] = { josi, fn, type: 'func', return_none: returnNone, asyncFn }
this.pluginFunclist[key] = cloneAsJSON(this.funclist[key])
this.__varslist[0][key] = fn
}
diff --git a/src/nako_from_dncl.js b/src/nako_from_dncl.js
index 440b68da1..3fe2cd18c 100644
--- a/src/nako_from_dncl.js
+++ b/src/nako_from_dncl.js
@@ -27,7 +27,7 @@ function isIndentSyntaxEnabled(src) {
const keywords = DNCL_KEYWORDS
const lines = src.split('\n', 30)
for (const line of lines) {
- const line2 = line.replace('!', '!')
+ const line2 = line.replace(/(!|💡)/, '!')
if (keywords.indexOf(line2) >= 0) {
return true
}
diff --git a/src/nako_gen.js b/src/nako_gen.js
index 5f1c23f9a..7138ec8b4 100644
--- a/src/nako_gen.js
+++ b/src/nako_gen.js
@@ -8,6 +8,17 @@
const { NakoSyntaxError, NakoError, NakoRuntimeError } = require('./nako_errors')
const nakoVersion = require('./nako_version')
+const isIE11 = () => {
+ if (typeof(window) == 'object' && window.navigator && window.navigator.userAgent) {
+ return (window.navigator.userAgent.indexOf('MSIE') >= 0)
+ }
+ return false
+}
+
+// なでしこで定義した関数の開始コードと終了コード
+const topOfFunction = '(function(){\n'
+const endOfFunction = '})'
+const topOfFunctionAsync = '(async function(){\n'
/**
* @typedef {import("./nako3").Ast} Ast
@@ -24,13 +35,18 @@ class NakoGen {
static generate (com, ast, isTest) {
const gen = new NakoGen(com)
- // ユーザー定義関数をシステムに登録する
+ // ※ [関数定義に関するコード生成のヒント]
+ // ※ 関数の名前だけを(1)で登録して、(2)で実際に関数のコードを生成する。
+ // ※ ただし(2)では生成するだけなので、(3)でプログラム冒頭に関数定義のコードを記述する。
+ // この順番を変えることはできない (グローバル変数が認識できなくなったり、関数定義のタイミングがずれる)
+
+ // (1) ユーザー定義関数をシステムに登録する
gen.registerFunction(ast)
- // JSコードを生成する
+ // (2) JSコードを生成する
let js = gen.convGen(ast, !!isTest)
-
- // JSコードを実行するための事前ヘッダ部分の生成
+
+ // (3) JSコードを実行するための事前ヘッダ部分の生成
js = gen.getDefFuncCode(isTest) + js
// テストの実行
@@ -39,11 +55,7 @@ class NakoGen {
}
// async method
if (gen.numAsyncFn > 0) {
- let canAsync = true
- if (typeof(window) == 'object' && window.navigator && window.navigator.userAgent) {
- const ua = window.navigator.userAgent
- canAsync = (ua.indexOf('MSIE') === -1)
- }
+ let canAsync = !isIE11()
if (canAsync) {
js = `
//
@@ -130,6 +142,12 @@ try {
* @type {number}
*/
this.numAsyncFn = 0
+ /**
+ * 関数定義の際、関数の中でasyncFn=trueの関数を呼び出したかどうかを調べる
+ * @type {boolean}
+ * @see convDefFuncCommon
+ */
+ this.usedAsyncFn = false
/**
* 変換中の処理が、ループの中かどうかを判定する
@@ -182,9 +200,13 @@ try {
}
// 暫定変数
+ /** @type { number } */
this.warnUndefinedReturnUserFunc = 1
- this.warnUndefinedCallingUserFuncArgs = 1
- this.warnUndefinedCallingSystemFuncArgs = 1
+ /** @type { number } */
+ this.warnUndefinedCallingUserFunc = 1
+ /** @type { number } */
+ this.warnUndefinedCallingSystemFunc = 1
+ /** @type { number } */
this.warnUndefinedCalledUserFuncArgs = 1
}
@@ -297,8 +319,9 @@ try {
let nakoFuncCode = ''
for (const key in this.nako_func) {
const f = this.nako_func[key].fn
+ const isAsync = this.nako_func[key].asyncFn ? 'true' : 'false'
nakoFuncCode += '' +
- `//[DEF_FUNC name='${key}']\n` +
+ `//[DEF_FUNC name='${key}' asyncFn=${isAsync}]\n` +
`__v1["${key}"]=${f};\n;` +
`//[/DEF_FUNC name='${key}']\n`
}
@@ -396,6 +419,11 @@ try {
registerFunction (ast) {
if (ast.type !== 'block') { throw NakoSyntaxError.fromNode('構文解析に失敗しています。構文は必ずblockが先頭になります', ast) }
+ /** 関数一覧
+ * @type {Array<{name: string, node: Object}>}
+ */
+ const funcList = []
+ // なでしこ関数を定義して this.nako_func[name] に定義する
const registFunc = (node) => {
for (let i = 0; i < node.block.length; i++) {
const t = node.block[i]
@@ -403,20 +431,24 @@ try {
const name = t.name.value
this.used_func.add(name)
this.__self.__varslist[1][name] = function () { } // 事前に適当な値を設定
+ this.varslistSet[1].names.add(name) // global
this.nako_func[name] = {
josi: t.name.meta.josi,
fn: '',
- type: 'func'
+ type: 'func',
+ asyncFn: false
}
- } else
- if (t.type === 'speed_mode') {
+ funcList.push({name: name, node: t})
+ }
+ // 実行速度優先 などのオプションが付いている場合の処理
+ else if (t.type === 'speed_mode') {
if (t.block.type === 'block') {
registFunc(t.block)
} else {
registFunc(t)
}
- } else
- if (t.type === 'performance_monitor') {
+ }
+ else if (t.type === 'performance_monitor') {
if (t.block.type === 'block') {
registFunc(t.block)
} else {
@@ -425,6 +457,7 @@ try {
}
}
}
+ // 関数の登録
registFunc(ast)
// __self.__varslistの変更を反映
@@ -435,6 +468,11 @@ try {
this.varsSet = { isFunction: false, names: initialNames, readonly: new Set() }
this.varslistSet = this.__self.__varslist.map((v) => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
this.varslistSet[2] = this.varsSet
+
+ // 非同期関数(asyncFn)があるかどうかテストする --- 後ほど改めて再度同じ関数を呼ぶ
+ for (let ff of funcList) {
+ this.convDefFuncCommon(ff.node, ff.name)
+ }
}
/**
@@ -524,7 +562,7 @@ try {
case 'func':
case 'func_pointer':
case 'calc_func':
- code += this.convFunc(node, isExpression)
+ code += this.convCallFunc(node, isExpression)
break
case 'if':
code += this.convIf(node)
@@ -734,8 +772,6 @@ try {
'try {\n'
performanceMonitorInjectAtEnd = '} finally { performanceMonitorEnd(); }\n'
}
- const topOfFunction = '(function(){\n'
- const endOfFunction = '})'
let variableDeclarations = ''
let popStack = ''
const initialNames = new Set()
@@ -756,7 +792,7 @@ try {
const meta = (!name) ? node.meta : node.name.meta
for (let i = 0; i < meta.varnames.length; i++) {
const word = meta.varnames[i]
- if (this.warnUndefinedCalledUserFunc === 0) {
+ if (this.warnUndefinedCalledUserFuncArgs === 0) {
code += ` ${this.varname(word)} = arguments[${i}];\n`
} else
if (name) {
@@ -770,13 +806,19 @@ try {
if (name) {
this.used_func.add(name)
this.varslistSet[1].names.add(name)
- this.nako_func[name] = {
- josi: node.name.meta.josi,
- fn: '',
- type: 'func'
+ if (this.nako_func[name] === undefined) {
+ // 既に generate で作成済みのはず(念のため)
+ this.nako_func[name] = {
+ josi: node.name.meta.josi,
+ fn: '',
+ type: 'func',
+ asyncFn: false
+ }
}
}
// ブロックを解析
+ const oldUsedAsyncFn = this.usedAsyncFn
+ this.usedAsyncFn = false
const block = this._convGen(node.block, false)
code += block.split('\n').map((line) => ' ' + line).join('\n') + '\n'
// 関数の最後に、変数「それ」をreturnするようにする
@@ -785,6 +827,10 @@ try {
}
// パフォーマンスモニタ:ユーザ関数のinject
code += performanceMonitorInjectAtEnd
+ // ブロックでasyncFnを使ったか
+ if (name && this.usedAsyncFn) {
+ this.nako_func[name].asyncFn = true
+ }
// 関数の末尾に、ローカル変数をPOP
// 関数内で定義されたローカル変数の宣言
@@ -808,15 +854,23 @@ try {
variableDeclarations += ` ${this.varname('それ')} = '';`
}
}
- code = topOfFunction + performanceMonitorInjectAtStart + variableDeclarations + code + popStack
+ // usedAsyncFnの値に応じて関数定義の方法を変更
+ const tof = (this.usedAsyncFn) ? topOfFunctionAsync : topOfFunction
+ // 関数コード全体を構築
+ code = tof + performanceMonitorInjectAtStart + variableDeclarations + code + popStack
code += endOfFunction
- if (name) { this.nako_func[name].fn = code }
+ // 名前があれば、関数を登録する
+ if (name) {
+ this.nako_func[name].fn = code
+ this.nako_func[name].asyncFn = this.usedAsyncFn
+ meta.asyncFn = this.usedAsyncFn
+ }
+ this.usedAsyncFn = oldUsedAsyncFn // 以前の値を戻す
this.varslistSet.pop()
this.varsSet = this.varslistSet[this.varslistSet.length - 1]
- if (name) { this.__self.__varslist[1][name] = code }
-
+ if (name) {this.__self.__varslist[1][name] = code }
return code
}
@@ -842,10 +896,12 @@ try {
}
convDefFunc (node) {
+ // ※ [関数定義のメモ]
+ // ※ 関数の定義はプログラムの冒頭に移される。
+ // ※ そのため、生成されたコードはここでは返さない
+ // ※ registerFunction を参照
const name = NakoGen.getFuncName(node.name.value)
this.convDefFuncCommon(node, name)
- // ★この時点では関数のコードを生成しない★
- // プログラム冒頭でコード生成時に関数定義を行う
return ''
}
@@ -1192,12 +1248,14 @@ try {
* @param {boolean} isExpression
* @returns string コード
*/
- convFunc (node, isExpression) {
+ convCallFunc (node, isExpression) {
const funcName = NakoGen.getFuncName(node.name)
const res = this.findVar(funcName)
if (res === null) {
throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node)
}
+ // どの関数を呼び出すのか関数を特定する
+ /** @type {import('./nako3').NakoFunction} */
let func
if (res.i === 0) { // plugin function
func = this.__self.funclist[funcName]
@@ -1213,9 +1271,6 @@ try {
if (node.type === 'func_pointer') {
return res.js
}
- // なでしこで定義した関数?
- // const isUserFunc = (typeof(func.fn) === 'string')
- // console.log('@@@', funcName, typeof(func.fn))
// 関数の参照渡しでない場合
// 関数定義より助詞を一つずつ調べる
@@ -1280,6 +1335,7 @@ try {
}
// 関数呼び出しコードの構築
+ /** @type {string} */
let argsCode
if ((this.warnUndefinedCallingUserFunc === 0 && res.i !== 0) || (this.warnUndefinedCallingSystemFunc === 0 && res.i === 0)) {
argsCode = args.join(',')
@@ -1304,6 +1360,7 @@ try {
funcDef = `async ${funcDef}`
funcCall = `await ${funcCall}`
this.numAsyncFn++
+ this.usedAsyncFn = true
}
if (res.i === 0 && this.performanceMonitor.systemFunctionBody !== 0) {
let key = funcName
diff --git a/src/nako_indent.js b/src/nako_indent.js
index 1009b944f..592621f53 100644
--- a/src/nako_indent.js
+++ b/src/nako_indent.js
@@ -27,7 +27,8 @@ function isIndentSyntaxEnabled (code) {
const keywords = ['!インデント構文', '!ここまでだるい']
const lines = code.split('\n', 30)
for (const line of lines) {
- const s9 = line.substr(0, 8).replace('!', '!')
+ const sline = line.replace(/^(!|💡)/, '!')
+ const s9 = sline.substring(0, 8)
if (keywords.indexOf(s9) >= 0) {
return true
}
diff --git a/src/nako_lex_rules.js b/src/nako_lex_rules.js
index 6980776d5..5be08bf56 100644
--- a/src/nako_lex_rules.js
+++ b/src/nako_lex_rules.js
@@ -2,7 +2,7 @@
* なでしこ3字句解析のためのルール
*/
-const kanakanji = /^[\u3005\u4E00-\u9FCF_a-zA-Z0-9ァ-ヶー]+/
+const kanakanji = /^[\u3005\u4E00-\u9FCF_a-zA-Z0-9ァ-ヶー\u2460-\u24FF\u2776-\u277F\u3251-\u32BF]+/
const nakoJosiList = require('./nako_josi_list')
const josiRE = nakoJosiList.josiRE
const removeJosiMap = nakoJosiList.removeJosiMap
@@ -53,9 +53,9 @@ module.exports = {
{ name: 'lteq', pattern: /^(≦|<=|=<)/ },
{ name: 'noteq', pattern: /^(≠|<>|!=)/ },
{ name: '←', pattern: /^(←|<--)/ }, // 関数呼び出し演算子 #891 #899
- { name: 'eq', pattern: /^=/ },
- { name: 'line_comment', pattern: /^!(インデント構文|ここまでだるい)[^\n]*/ },
- { name: 'not', pattern: /^!/ },
+ { name: 'eq', pattern: /^(=|🟰)/ },
+ { name: 'line_comment', pattern: /^(!|💡)(インデント構文|ここまでだるい)[^\n]*/ }, // #1184
+ { name: 'not', pattern: /^(!|💡)/ }, // #1184
{ name: 'gt', pattern: /^>/ },
{ name: 'lt', pattern: /^ },
{ name: 'and', pattern: /^(かつ|&&)/ },
@@ -96,7 +96,7 @@ module.exports = {
// 単語句
{
name: 'word',
- pattern: /^[_a-zA-Z\u3005\u4E00-\u9FCFぁ-んァ-ヶ]/,
+ pattern: /^[_a-zA-Z\u3005\u4E00-\u9FCFぁ-んァ-ヶ\u2460-\u24FF\u2776-\u277F\u3251-\u32BF]/,
cbParser: cbWordParser
}
],
diff --git a/src/nako_lexer.js b/src/nako_lexer.js
index 7051d692a..391e7b23d 100644
--- a/src/nako_lexer.js
+++ b/src/nako_lexer.js
@@ -236,6 +236,7 @@ class NakoLexer {
type: 'func',
josi,
fn: null,
+ asyncFn: false,
varnames,
funcPointers
}
@@ -498,7 +499,7 @@ class NakoLexer {
columnCurrent = column
lineCurrent = line
column += m[0].length
- src = src.substr(m[0].length)
+ src = src.substring(m[0].length)
if ((rule.name === 'eol' && value === '\n') || rule.name === '_eol') {
value = line++
column = 1
@@ -509,7 +510,7 @@ class NakoLexer {
// 単位があれば読み飛ばす
const um = lexRules.unitRE.exec(src)
if (um) {
- src = src.substr(um[0].length)
+ src = src.substring(um[0].length)
column += m[0].length
}
}
@@ -520,10 +521,10 @@ class NakoLexer {
if (j) {
josi = j[0].replace(/^\s+/, '')
column += j[0].length
- src = src.substr(j[0].length)
+ src = src.substring(j[0].length)
// 助詞の直後にあるカンマを無視 #877
if (src.charAt(0) === ',') {
- src = src.substr(1)
+ src = src.substring(1)
}
// 「**である」なら削除 #939 #974
if (removeJosiMap[josi]) { josi = '' }
diff --git a/src/nako_parser3.js b/src/nako_parser3.js
index 7565495e6..b4db4f1db 100644
--- a/src/nako_parser3.js
+++ b/src/nako_parser3.js
@@ -551,13 +551,13 @@ class NakoParser extends NakoParserBase {
}
}
- /** @returns {Ast | null} */
- yGetArg () {
- // 値を一つ読む
- const value1 = this.yValue()
- if (value1 === null) { return null }
- // 計算式がある場合を考慮
- const args = [value1]
+ /**
+ * 1つ目の値を与え、その後に続く計算式を取得し、優先規則に沿って並び替えして戻す
+ * @param {Ast | null} firstValue
+ * @returns {Ast | null}
+ */
+ yGetArgOperator (firstValue) {
+ const args = [firstValue]
while (!this.isEOF()) {
// 演算子がある?
const op = this.peek()
@@ -568,7 +568,7 @@ class NakoParser extends NakoParserBase {
if (v === null) {
throw NakoSyntaxError.fromNode(
`計算式で演算子『${op.value}』後に値がありません`,
- value1)
+ firstValue)
}
args.push(v)
continue
@@ -580,6 +580,15 @@ class NakoParser extends NakoParserBase {
return this.infixToAST(args)
}
+ /** @returns {Ast | null} */
+ yGetArg () {
+ // 値を一つ読む
+ const value1 = this.yValue()
+ if (value1 === null) { return null }
+ // 計算式がある場合を考慮
+ return this.yGetArgOperator(value1)
+ }
+
infixToPolish (list) {
// 中間記法から逆ポーランドに変換
const priority = (t) => {
@@ -832,8 +841,11 @@ class NakoParser extends NakoParserBase {
yReturn () {
const map = this.peekSourceMap()
if (!this.check('戻る')) { return null }
- this.get() // skip '戻る'
+ const modoru = this.get() // skip '戻る'
const v = this.popStack(['で', 'を'])
+ if (this.stack.length > 0) {
+ throw NakoSyntaxError.fromNode('『戻』文の直前に未解決の引数があります。『(式)を戻す』のように式をカッコで括ってください。', modoru)
+ }
return {
type: 'return',
value: v,
@@ -1101,7 +1113,11 @@ class NakoParser extends NakoParserBase {
this.pushStack(r)
continue
}
- return r
+ // 関数呼び出しの直後に、四則演算があるか?
+ if (!this.checkTypes(operatorList)) { return r } // なければ関数呼び出しを戻す
+ // 四則演算があった場合、計算してスタックに載せる
+ this.pushStack(this.yGetArgOperator(r))
+ continue
}
// 値のとき → スタックに載せる
const t = this.yGetArg()
diff --git a/src/nako_prepare.js b/src/nako_prepare.js
index e7be8c7fb..0a5ef55cc 100644
--- a/src/nako_prepare.js
+++ b/src/nako_prepare.js
@@ -122,7 +122,11 @@ class NakoPrepare {
0x3011: ']', // '】'
// 読点は「,」に変換する (#877)
0x3001: ',', // 読点 --- JSON記法で「,」と「、」を区別したいので読点は変換しないことに。(#276)
- 0xFF0C: ',' // 読点 ',' 論文などで利用、ただし句点はドットと被るので変換しない (#735)
+ 0xFF0C: ',', // 読点 ',' 論文などで利用、ただし句点はドットと被るので変換しない (#735)
+ 0x2716: '*', // ×の絵文字 (#1183)
+ 0x2795: '+', // +の絵文字 (#1183)
+ 0x2796: '-', // -の絵文字 (#1183)
+ 0x2797: '÷' // ÷の絵文字 (#1183)
}
}
diff --git a/src/nako_version.js b/src/nako_version.js
index a7e9243e9..c19bc939c 100644
--- a/src/nako_version.js
+++ b/src/nako_version.js
@@ -1,8 +1,8 @@
// なでしこバージョン
const nakoVersion = {
- version: '3.2.47',
+ version: '3.2.51',
major: 3,
minor: 2,
- patch: 47
+ patch: 51
}
module.exports = nakoVersion
diff --git a/src/plugin_node.js b/src/plugin_node.js
index 6a8a03f9a..8a71b0aae 100644
--- a/src/plugin_node.js
+++ b/src/plugin_node.js
@@ -553,18 +553,6 @@ const PluginNode = {
},
return_none: true
},
- '秒待': { // @NodeでN秒待つ // @びょうまつ
- type: 'func',
- josi: [['']],
- pure: true,
- fn: function (sec, sys) {
- const msleep = (n) => {
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n) // eslint-disable-line no-undef
- }
- msleep(sec * 1000)
- },
- return_none: true
- },
'OS取得': { // @OSプラットフォームを返す(darwin/win32/linux) // @OSしゅとく
type: 'func',
josi: [],
diff --git a/test/common/basic_test.js b/test/common/basic_test.js
index 0df23a8f0..32de1c840 100644
--- a/test/common/basic_test.js
+++ b/test/common/basic_test.js
@@ -129,6 +129,19 @@ describe('basic', () => {
'2'
)
})
+ it('💡のインデント構文 #1184', () => {
+ cmp(
+ '💡インデント構文\n' +
+ '3で条件分岐\n' +
+ ' 2ならば\n' +
+ ' 2を表示\n' +
+ ' 3ならば\n' +
+ ' 3を表示\n' +
+ ' 違えば\n' +
+ ' 5を表示\n',
+ '3'
+ )
+ })
it('独立した助詞『ならば』の位置の取得', () => {
const out = nako.lex('もし存在するならば\nここまで', '')
const sonzai = out.tokens.find((t) => t.value === '存在')
diff --git a/test/common/calc_test.js b/test/common/calc_test.js
index 943d082c9..fe2c02939 100644
--- a/test/common/calc_test.js
+++ b/test/common/calc_test.js
@@ -136,4 +136,9 @@ describe('calc_test.js', () => {
cmp('N=「」;もし、N=0ならば「OK」と表示。', 'OK')
cmp('N=「」;もし、N===0ならば「NG」と表示。違えば「OK」と表示。', 'OK')
})
+ it('なでしこ式関数呼び出しで、途中に四則演算がある場合の処理 (#1188)', () => {
+ cmp('3.14のINT+2を表示。', '5')
+ cmp('3の5倍×2を表示', '30')
+ cmp('1+3の2倍×2を表示', '16')
+ })
})
diff --git a/test/common/dncl_test.js b/test/common/dncl_test.js
index d6df2ad15..1695ce4b9 100644
--- a/test/common/dncl_test.js
+++ b/test/common/dncl_test.js
@@ -87,5 +87,9 @@ describe('dncl (#1140)', () => {
cmpNako('!DNCLモード\n7/2を表示する', '3.5')
cmpNako('!DNCLモード\n7÷2を表示する', '3')
})
+ it('「!」を💡で書けるようにする #1184', () =>{
+ cmpNako('💡DNCLモード\n7/2を表示する', '3.5')
+ cmpNako('💡DNCLモード\n7÷2を表示する', '3')
+ })
})
diff --git a/test/common/lex_test.js b/test/common/lex_test.js
index 9f4c0351f..4833fb5c6 100644
--- a/test/common/lex_test.js
+++ b/test/common/lex_test.js
@@ -146,4 +146,10 @@ describe('lex_test', () => {
it('助詞の前後に空白があるとエラーになる問題 #1079', () => {
cmp('x=1;x と 2 と "3" を連続表示', '123')
})
+ it('丸付き数字が変数名として使えない #1185', () => {
+ cmp('⓪=0;①=1;㊿=50;❿=10;⓪+①+㊿+❿を表示', '61')
+ })
+ it('絵文字の四則演算を認識する #1183', () => {
+ cmp('リンゴ🟰3✖5;ミカン🟰9➗3;リンゴ+ミカンを表示', '18')
+ })
})
diff --git a/test/node/plugin_test.js b/test/node/plugin_test.js
index babe407ed..0bae0bf89 100644
--- a/test/node/plugin_test.js
+++ b/test/node/plugin_test.js
@@ -1,6 +1,6 @@
const assert = require('assert')
const CNako3 = require('../../src/cnako3')
-
+const path = require('path')
describe('plugin_test', () => {
const nako = new CNako3()
// nako.logger.addListener('trace', ({ browserConsole }) => { console.log(...browserConsole) })
@@ -11,6 +11,8 @@ describe('plugin_test', () => {
assert.strictEqual(ret.log, res)
}
it('「取り込む」', () => {
- cmp('!「nadesiko3-hoge」を取り込む。\n3と5をHOGE足して、表示。', '8')
+ const plug = path.join(__dirname, '..', '..', 'src', 'plugin_keigo.js')
+ cmp(`!「${plug}」を取り込む。\n拝啓。お世話になっております。礼節レベル取得して表示。`, '1')
})
})
+