NScripterで連想配列を使えるようにする

Luaのテーブル変数をNScripterの文字列変数に圧縮・その逆の展開 - 永字八法NSPopID()の実験 - 永字八法の続き。

概要

NScripterネイティブから、連想配列を使えるようにする。(後々オブジェクト指向プログラミングへの布石を意識している)

使い方

onew %0 ; 新規連想配列を取得し、そのIDを%0に収める。
oset %0,file,"a.jpg"
; 連想配列のfileプロパティに、"a.jpg"を設定する。
oset %0,width,300,height,200
; 連想配列のwidthプロパティとheightプロパティに数値を設定する。
osave %0 ; その連想配列を、一行にまとめて文字列変数に格納する。文字列変数の番号は、連想配列のIDに等しい。
oload %0 ; 一行にまとめた文字列を、連想配列に展開する。$1500を展開したなら、その連想配列のIDは1500になる。

特色

  • osetメソッドとogetメソッドは、遅延引数取得を利用して不定長引数を実現している。一度に複数のプロパティを指定したい時は、その分だけどんどんつなげて伸ばせばいい。
  • どちらも、プロパティを指定する時はダブルクォートでプロパティ名を囲まない。逆に囲むとエラーになる。
  • プロパティは「0文字以上の、アルファベットで始まる制御記号を含まない半角文字の集合」と規定する。
  • luacallを使っているので、saveやloadにも対応している……はず。
  • key_typeテーブルに、あるプロパティがどんなデータ型を持っているかを記述し、それによって使う引数取得命令を変更する。月見 - senzogawaのNな日々で指摘されている「型混在の命令」に対する不完全な解答。

00.txt

*define
luacall savepoint
luacall load
luasub onew
luasub oget
luasub oset
luasub osave
luasub oload
game
*start
csvopen "dump.txt","w"
onew %0
%0:$%0
csvwrite $%0
oset %0,width,200,height,300
oset %0,file,"a013.jpg"
%0:$%0
csvwrite $%0
osave %0
%0:$%0
csvwrite $%0
oget %0,file,$0
$0
click
end

system.lua

local objs = {}
local obj_start = 1000
local obj_end = 2000

function NSCALL_savepoint()
	for num, obj in pairs(objs) do
		if obj.is_changed == true then obj_save(obj) end
	end
	return true
end

function NSCOM_osave()
	local num = NSPopInt()
	local obj = obj_load(num)
	if obj.is_changed == true then obj_save(obj) end
end

function obj_save(obj)
	local str = ""
	obj.is_changed = nil
	for key, value in pairs(obj) do
		str = str .. key .. "\t" .. value .. "\t"
	end
	NSSetStrValue(obj.id, str)
	obj.is_changed = false
	return true
end

function NSCALL_load(save_num)
	local str = ""
	for num = obj_start, obj_end do
		str = NSGetStrValue(num)
		if str ~= "" then obj_load(num) end
	end
	return true
end

function NSCOM_oload()
	local obj = obj_load(NSPopInt())
end

function obj_load(num)
	local temp = objs[num]
	if temp ~= nil then return temp end
	temp = {}
	local str = ""
	str = NSGetStrValue(num)
	if str ~= "" then
		for key, value in string.gmatch(str, "([^\t]*)[\t]([^\t]*)[\t]") do
			temp[key] = value
		end
	end
	temp.id = num
	objs[num] = temp
	if str == "" then obj_save(temp) end
	return temp
end

function NSCOM_onew()
	NSSetIntValue(NSPopIntRef(), onew())
end

function onew()
	local num = obj_start
	while NSGetStrValue(num) ~= "" do
		num = num + 1
	end
	obj_load(num)
	return num
end

local key_type = {
	width = "number",
	height = "number",
	x = "number",
	y = "number"
}

function NSCOM_oset()
	local num = NSPopInt()
	local obj = obj_load(num)
	local key = ""
	local value = ""
	while NSCheckComma() == true do
		NSPopComma()
		key = NSPopID()
		NSPopComma()
		if key_type[key] == "number" then
			value = NSPopInt()
		else
			value = NSPopStr()
		end
		obj[key] = value
	end
	obj.is_changed = true
end

function NSCOM_oget()
	local num = NSPopInt()
	local obj = obj_load(num)
	local key = ""
	local res = 0
	while NSCheckComma() == true do
		NSPopComma()
		key = NSPopID()
		NSPopComma()
		if key_type[key] == "number" then
			res = NSPopIntRef()
			NSSetIntValue(res, obj[key])
		else
			res = NSPopStrRef()
			NSSetStrValue(res, obj[key])
		end
	end
end

今後の展開

NScripterで、オブジェクト指向プログラミングを……いや、そんなプログラマー的自己満足はおいておいて。
スプライトのグループ化とか、スプライト番号の管理のパッケージ化とか考えてますよ、と。
一つの連想配列に、fileやx,yなどを設定した後、spメソッドに連想配列を渡すと、足りない部分を自動で整えてスプライトを表示するような、そういう仕組みがいいなー。