%E6%96%B0%E6%A7%8B%E6%96%87%E4%BD%BF%E7%94%A8%E4%BE%8B - stuncloud/UWSCR GitHub Wiki

目次

三項演算子

0.0.1 より

? 真で返す式 : 偽で返す式

式を評価しその真偽により値を返します
単行のIF文に似ていますが、こちらは式なので値を返します

a = FALSE
print a ? "a is TRUE": "a is FALSE"

入れ子もできる

// fizzbuzz
for i = 1 to 100
    print i mod 15 ? i mod 5 ? i mod 3 ? i : "fizz" : "buzz" : "fizzbuzz"
next

文は書けないのでこういうのはダメ

// printは文なのでエラーになる
hoge ? print "hoge is truthy" : print "hoge is falsy"

代入演算子

0.1.5より

変数 :=

:=を使うことで式の中で変数への代入が行なえます
また、代入した値を返す式として機能します

// 条件式での代入
select name := GetSomeName() // 関数の戻り値を代入し、その値を条件とする
    case "foo", "bar", "baz"
        print "you got <#name>"
    default
        print "<#name> is not a valid name"
selend

// 複数の変数に同じ値を代入
a = b := c := 10
print a // 10
print b // 10
print c // 10
// a := b := c := 10 でも可

複合代入演算子

0.0.2 より

変数 +=// 変数 = 変数 + 式 と同等
変数 -=// 変数 = 変数 - 式 と同等
変数 *=// 変数 = 変数 * 式 と同等
変数 /=// 変数 = 変数 / 式 と同等

左辺の値と右辺の値で演算を行い、それを左辺の変数に代入します

a = 10
a += 10
print a // 20
a -= 10
print a // 10
a *= 2
print a // 20
a /= 10
print a // 2

無名関数

0.0.1 より
※ procedureは0.0.2から

変数 = function()
    result = 戻り値
fend

変数 = procedure()
fend

変数に関数を代入できます

print2 = function(a, b)
    result = a + " " + b
fend

print print2("hello", "world!")

通常の関数定義と異なり、代入処理を行う際に関数が評価されます
そのため以下のような記述はNGです

print hoge()

hoge = function()
    result = "これは未定義エラーになる"
fend

高階関数

0.0.1 より

関数の引数に関数を指定できます

print Math(10, 5, Add)      // 15
print Math(10, 5, Multiply) // 50

subtract = function(n, m)
    result = n - m
fend

print Math(10, 5, subtract) // 5


function Math(n, m, func)
    result = func(n, m)
fend

function Add(n, m)
    result = n + m
fend

function Multiply(n, m)
    result = n * m
fend

クロージャ

0.0.3 より

クロージャが使えます

hoge = test(5)
print hoge(3)    // 8
print hoge(7)    // 12
print hoge("あ") // 5あ

function test(n)
    result = function(m)
        result = n + m
    fend
fend

ビルトイン関数のエイリアス

ビルトイン関数も変数に代入できるので別名をつけて実行できます

public rp = replace
print rp("あいうえお", "い", "イ")

UObject

0.1.7より

json互換オブジェクト
jsonを@で括ることでUObjectを生成できます

obj = @{
    "a": 1,
    "b": [1,2,3],
    "c": {
        "d": 10,
        "e": 20
    }
}@

print obj.a // 1
print obj.b[1] // 2
print obj.c.d // 10
print obj["c"]["d"] // 10

arr = @[1, [2, 3]]@

print arr[0] // 1
print arr[1][0] // 2

変数展開を行います

foo = '文字列を展開'
bar = 123
textblock baz
,
"baz":{
    "qux": "なんでも書き込める"
}
endtextblock

obj = @{
    "foo": "<#foo>",
    "bar": <#bar>
    <#baz>
}@

print obj.foo     // 文字列を展開
print obj.bar     // 123
print obj.baz.qux // なんでも書き込める

UObject <-> json 変換

json = ToJson(obj) // UObjectからjson文字列に変換
obj = FromJson(json) // json文字列からUObjectに変換

CLASS

0.1.3 より

UWSCのCLASSとは機能が異なります
UWSCのCLASSと同等の機能が必要な場合はMODULEを使ってください

CLASS定義

クラス名と同名のプロシージャ(コンストラクタ)を定義する必要があります
また_クラス名_()というプロシージャはデストラクタとなります
デストラクタは必須ではありません

class MyClass
    procedure MyClass() // コンストラクタ (必須)
    fend

    procedure _MyClass_() // デストラクタ (オプション)
    fend
endclass

インスタンスの作成

コンストラクタ()を実行するとインスタンスを返します

ins1 = MyClass(10)
print ins1.GetN() // 10
ins2 = MyClass(20)
print ins2.GetN() // 20

class MyClass
    dim n
    procedure MyClass(n)
        this.n = n
    fend
    function GetN()
        result = n
    fend
endclass

インスタンスの破棄

インスタンス変数にNOTHINGを代入するとインスタンスを明示的に破棄できます
その際にデストラクタが(定義してあれば)実行されます
インスタンス変数はインスタンスの参照なので別の変数に代入していた場合いずれもNOTHINGになります

ins1 = MyClass("hoge")
ins2 = ins1
ins1 = NOTHING // "hogeが破棄されました" がprintされる
print ins1 // NOTHING
print ins2 // NOTHING ※ ins1と同じインスタンスを参照しているのでこちらもNOTHINGになる

class MyClass
    dim name
    procedure MyClass(name)
        this.name = name
    fend
    procedure _MyClass_()
        print "<#name>が破棄されました"
    fend
endclass

インスタンスの自動破棄

明示的に破棄を行わなかった場合は、インスタンスが作成されたスコープから抜ける際にすべてのインスタンスが自動的に破棄されます
ただし、public変数やresultなどスコープ外にインスタンスが作られる場合は例外です
withでインスタンスを作成した場合はendwithで破毀されます

public pub
ins1 = MyClass("in main script")
ins2 = f() // 関数の戻り値がインスタンスの場合、このスコープの終わりに破棄される
MyClass("no variable").PrintName() // 変数にインスタンスを代入しない場合もスコープ終了時に破棄される

with MyClass("with")
    .PrintName()
endwith // ここで破棄される

print "end of main script"

function f()
    ins = MyClass("in function") // 関数fのスコープ内で作成されたので関数の終わりに破棄される
    pub = MyClass("public") // public変数のため関数スコープでは破棄されない
    result = MyClass("result") // resultのため関数スコープでは破棄されない
    print "end of function"
fend

class MyClass
    dim name
    procedure MyClass(name)
        this.name = name
    fend
    procedure PrintName()
        print "nameは<#name>です"
    fend
    procedure _MyClass_()
        print "<#name>が破棄されました"
    fend
endclass

実行結果

end of function
in functionが破棄されました
nameはno variableです
nameはwithです
withが破棄されました
end of main script
in main scriptが破棄されました
resultが破棄されました
no variableが破棄されました
publicが破棄されました

Enum

0.1.7 より

シンプルな列挙体
enum定数として定義され、値は数値のみです

enum E
    foo
    bar
    baz
endenum

print E.foo // 0
print E.bar // 1
print E.baz // 2

enum E2
    foo = 100
    bar
    baz = 200
    qux
endenum

print E.foo // 100
print E.bar // 101
print E.baz // 200
print E.qux // 201

タスク

任意の関数を非同期に実行する仕組みです

タスク利用の流れ

  • タスク関数を使う
    1. Task関数でタスクを得る
    2. WaitTask関数でタスクの終了を待ち非同期実行した関数の戻り値を得る
  • async/awaitを使う
    1. async宣言した関数をawaitして呼ぶ
  • asyncとWaitTask
    1. async宣言した関数を実行しタスクを得る
    2. WaitTask関数でタスクの終了を待ち非同期実行した関数の戻り値を得る
function MyTask()
    // 時間のかかる処理
    result = somevalue
fend

t = Task(MyTask) // タスクを作る

// タスク終了を待つ間別の処理を行う
DoSomething()

r = WaitTask(t) // somevalueを得る

上記は以下のようにも書けます

// async宣言
async function MyTask()
    // 時間のかかる処理
    result = somevalue
fend

t = MyTask() // async宣言した関数はタスクを返す
DoSomething()
r = WaitTask(t)

async宣言した関数はawaitで呼ぶことで完了を待ち戻り値を得られます

async function MyTask()
    // 時間のかかる処理
    result = somevalue
fend

r = await MyTask() // 実行をブロックして関数の終了を待つ

真偽性の評価

以下では真偽性が評価されます

  • ifの条件式 (if 条件式 then ...)
  • elseifの条件式 (elseif 条件式 then ...)
  • 三項演算子の条件式 (条件式 ? ...)
  • whileの条件式 (while 条件式 ...)
  • untilの条件式 (... until 条件式)
  • 論理演算子の両辺 (左辺 andL 右辺)

以下は偽(falsy)と判定されます

  • FALSE
  • 0
  • EMPTY
  • NOTHING
    • 破棄されたインスタンスを含む
  • "" (空の文字列)
  • [] (空の配列)

それ以外は真(truthy)です

if FALSE then
elseif
    print "FALSEが偽"
endif

print NOTHING ? '' : 'NOTHINGは偽'

while ""
    print "空文字列は偽なのでこの文字列はprintされません"
wend

repeat
    print "空でない文字列は真なのでこのループは一周で終了します"
until "ループを抜けます"

論理演算子・ビット演算子

AND、OR、XORは両辺により論理演算またはビット演算が行われていましたが
それとは別に以下が追加されました

  • 論理演算のみを行う演算子 (末尾がL)
    • 演算結果がbool値
  • ビット演算のみを行う演算子 (末尾がB)
    • 演算結果が数値
// 論理演算子
// 両辺の真偽性を評価してから演算を行う
print true andl false // false
print true andl NOTHING // false
print NULL andl 'a' // true
print 1 xorl [1,2] // false

// ビット演算子
// 両辺を数値として評価してから演算を行う
print 3 andb 5 // 1
print 3 orb 5 // 7
print 3 xorb 5 // 6
print 1 andb '1' // 1
print 1 andb true // 1

演算子の特殊な使い方

* 演算子による文字列の繰り返し

文字列 * 数値 で数値分文字列を繰り返します

print 'a' * 6 // aaaaaa
print 'abc' * 3 // abcabcabc
a = 'a'
a *= 3
print a // aaa

// NULLは chr(0) 相当
buf = NULL * 260
print buf         // 
print length(buf) // 260

NULL結合

文字列にNULL文字を追加できます

hoge = "hoge" + NULL
print hoge         // hoge
print length(hoge) // 5

構造体定義

struct-endstruct 構文で定義した構造体をDLL関数に渡すことができます
def_dllで定義する際に struct を指定します
var struct で渡した構造体に値を受け取れます

def_dll SetWindowPlacement(hwnd, struct):bool:user32.dll
def_dll GetWindowPlacement(hwnd, var struct):bool:user32.dll

struct WindowPlacement
    length  : uint
    flags   : uint
    showCmd : uint
    min_x   : long
    min_y   : long
    max_x   : long
    max_y   : long
    left    : long
    top     : long
    right   : long
    bottom  : long
endstruct

// 構造体のインスタンスを作る
wp = WindowPlacement()
// 値をセット
wp.length = length(WindowPlacement) // 構造体サイズはlengthで得られる
// wp.length = length(wp) // これでもOK
wp.showCmd = 1
wp.left    = 200
wp.top     = 200
wp.right   = 600
wp.bottom  = 600

id = exec('notepad', false, 0, 0, 300, 300)
print id
h = idtohnd(id)
print '1秒後にSetWindowPlacement'
sleep(1)

print SetWindowPlacement(h, wp)

print '1秒後にacwでサイズ変更しGetWindowPlacement'
acw(id, 300, 300, 500, 500, 1000)
print GetWindowPlacement(h, wp)
print 'GetWindowPlacement ' + [wp.top, wp.top, wp.right, wp.bottom]

引数の型指定

ユーザー定義関数の引数定義にデータ型を併記することで受ける型を限定できます
引数名: 型名 で定義します

データ型が指定可能な引数の種類

  • 通常の引数
    • 引数名: 型名
  • 参照渡し
    • var 引数名: 型名
    • ref 引数名: 型名
  • デフォルト値
    • 引数名: 型名 = デフォルト値

指定可能な型

  • 文字列
    • string
      function f(s: string)
      fend
      
      f("展開可能文字列")
      f('文字列')
  • 数値
    • number
      function f(n: number)
      fend
      
      f(123)
      f($FF)
  • 真偽値 (TRUE/FALSE)
    • bool
      function f(b: bool)
      fend
      
      f(TRUE)
      f(FALSE)
  • 配列
    • array
      function f(a: array)
      fend
      
      f([1,2,3])
      arr[] = 4,5,6
      f(arr)
  • 連想配列
    • hash
      function f(h: hash)
      fend
      
      hashtbl h
      h[1] = 1
      f(h)
  • 関数 (ユーザー定義関数, 無名関数)
    • func
      function f1(f: func)
      fend
      function f2()
      fend
      f3 = function()
      fend
      
      f1(f2)
      f1(f3)
      f1(|=>1|)
  • UObject
    • uobject
      function f(o: uobject)
      fend
      
      f(@{"a": 1}@)
      o = @{
          "foo": 1,
          "bar": 2
      }@
      f(o)
  • クラスオブジェクトインスタンス
    • クラス名
      function f(c: Hoge)
      fend
      
      class Hoge()
          procedure Hoge
          fend
      endclass
      class Fuga()
          procedure Fuga
          fend
      endclass
      
      hoge = Hoge()
      fuga = Fuga()
      
      f(hoge) // OK
      f(fuga) // エラー

INI関数のfid利用

readini/writeini/deleteiniのファイルパスの代わりにfopenして得たfidを渡せるようになりました

fid = fopen(path, F_READ)
readini(section, key1, fid)
readini(section, key2, fid)
readini(section, key3, fid)
fclose(fid)

fid = fopen(path, F_READ or F_WRITE)
writeini(section, key1, value, fid)
deleteini(section, key3, fid)
fclose(fid) // 書き込みが反映される

// iniの読み書きに排他制御を入れる
fid = fopen(path, F_READ or F_WRITE or F_EXCLUSIVE)
writeini(section, key3, value, fid)
fclose(fid)

連想配列一括定義

hash-endhash文を使うことで連想配列定義と同時にキーと値も定義できます

hash foobar
    foo = 1
    bar = 2
endhash

print foobar['foo'] // 1
print foobar['bar'] // 2

// publicやオプション指定する場合
hash public pub
endhash
hash with_option = HASH_SORT or HASH_CASECARE
endhash

call文のURL対応

web上のスクリプトをcallできます

call url[http://example.com/mymodule.uws]

print MyModule.Do()

for-else-endfor

forループをbreakしなかった場合にelseを実行します

for i = 0 to length(items) - 1
    if items[i] == target then
        // 要素のいずれかがtargetと一致した場合break
        target_found()
        break
    endif
else
    // いずれの要素もtargetと一致しない場合はbreakしないのでこちらが実行される
    target_not_found()
endfor

// for-inにも対応
for item in items
    if item == target then
        target_found()
        break
    endif
else
    target_not_found()
endfor

// ループ内の処理が行われない場合でもelseが実行される
for i = 0 to -1
    print 1 // 実行されないため表示もされない
else
    print 2 // 2と表示される
endfor
for a in []
    print 1 // 実行されない
else
    print 2 // 2と表示される
endfor
⚠️ **GitHub.com Fallback** ⚠️