The AWK˜plus Language Guide

AWK~plus

AWK の彼方に (Over The AWK)

The AWK˜plus Programming Language は、
  • プログラム言語AWK (The AWK Programming Language) 仕様と GNU GAWK の主要な拡張機能の実装。
  • アトミック変数とスレッドセーフな関数オブジェクトによる並行処理プログラミングのサポート。
  • 動的・静的型付け可能な、Apache Groovy との融合による広い守備範囲。
などの特徴を持つ 次世代スクリプト実行環境です。

互換性 (Compatibility)

Note:  『プログラム言語AWK』の例題をそのまま実行可能であり、実行結果は GNU GAWK とバイナリレベルで一致する。
(改行コードは初期値として '\n'(ORS) を使用する Ver2.)

オブジェクト指向 (Object Oriented)

関数型プログラミング (Functional programming)

関数オブジェクト (Function object)

関数オブジェクトは他の関数と同じように呼び出せるオブジェクトで、 apply メソドが呼び出されたときに実行される。

関数オブジェクト = '.' 関数名 ;
 関数オブジェクト = '..' 関数名 ; コンカレント呼び出し

function add(a, b) { return a + b }
 function calc(x: Function) { return x.apply() } # 関数オブジェクト呼び出しコンテナ
 print calc(.add(1, 2)) # -> 3

ダックタイピング (Duck typing)

関数オブジェクトを使用して クラスの継承関係を無視した メソッド呼び出しが 安全に実行できる。

 if (duck is bird.Duck) duck.quacks() # duckがクラス bird.Duckのインスタンスなら quacksを呼び出す(通常の方法)
 if (.quacks() in duck) duck.quacks() # インスタンス duckにメソド quacksが存在すれば quacksを呼び出す

Note:  duck typing
In Computer Programming, duck typing is a style of dynamic typing in which an object's current set of methods and properties determines the valid semantics, rather than its inheritance from a particular class. The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows: If it walks like a duck and quacks like a duck, I would call it a duck.

リスナーの実装 (Listener)

関数オブジェクトを指定して、リスナーを生成できる。 (sample/ImageViewer.awk 参照)

import java.awt.Point
import java.awt.event.ActionListener
import java.awt.event.MouseEvent
import javax.swing.ImageIcon
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.SwingConstants
import javax.swing.Timer
import plus.awt.Mouse
import plus.reflect.Reflection
  val imageLabel = new JLabel("", SwingConstants.CENTER)
  val frame = new JFrame("AWK˜plus - ImageViewer")
  val DELAY_SECONDS = 10 # 表示間隔
  val FRAME_HEIGHT = 600 # 画像サイズ
  val FRAME_WIDTH = 400
  var imgnumber = 0
  var images = ""
  var imgpos = -1
BEGIN {
  images = ARGV[1] # 画像のパス
  imgnumber = ARGV[2] # 画像の枚数
  frame.setDefaultCloseOperation(3)
  val dim = frame.getToolkit().getScreenSize
  frame.setLocation(new Point(dim.width - 8 - FRAME_WIDTH, dim.height - 32 - FRAME_HEIGHT))
  val container = frame.getContentPane
    container.add(imageLabel)
  val adapter = new Mouse(.mouseDragged(null), .mousePressed(null))# ヘルパ関数 Mouseで関数オブジェクトをラッピング
    container.addMouseListener(adapter); container.addMouseMotionListener(adapter)
  actionPerformed(null)
  frame.pack
  frame.setVisible(true)
  val actionListener: ActionListener =
    Reflection.implement("java.awt.event.ActionListener", .actionPerformed(null))# リスナーインターフェイスの動的実装
  new Timer(1000 * DELAY_SECONDS, actionListener).start
}
function actionPerformed(actionEvent) {
  imgpos = ++imgpos % imgnumber
  imageLabel.setIcon(new ImageIcon(images "/" imgpos ".jpg"))
}
function mouseDragged(e: MouseEvent) {
  val opacity: Float = 0.01 * (100 - Math.abs(e.getY) % 100)
  frame.setOpacity(opacity) # Java8 No longer supported
}
function mousePressed(e: MouseEvent) { # Right button click
  if (1 != e.getButton) frame.setAlwaysOnTop(!frame.isAlwaysOnTop)
}

スレッドの生成 (Concurrent)

関数オブジェクトを指定してスレッドを生成できる。(sample/Atomic2.awk 参照)

var counter: Int = 0
var sum: Int = 0
function atomCount()(n: Int) {
  while (10000 >= (n = ++counter)) sum += n # スレッドセーフに共有変数を更新
}
val T[1] = Future(..atomCount()) # スレッド(1)を生成
val T[2] = Future(..atomCount()) # スレッド(2)を生成
Join(T) # スレッドの終了を待ち合わせる

Note:  スレッドを生成時に'.'の代わりに'..'を付加すると、コンカレント呼び出しとなる。

Note:  Future など拡張された組み込み関数については lib/predef?.awk を参照。

型変換 (Cast)

変数の型変換は以下のとおり。

 "" X # 文字列に変換
 X -0 # 数値タイプに変換
 int(X) # 組み込み関数を使用してプリミティブ数値に変換 (他に double,float,long)

実行 (Plus,Run,Go)

コマンドラインオプション (Options)

-sp
スクリプトパスを指定
-lib
ライブラリパスを指定
-e "<AWK script>"
コマンドラインでスクリプトを直接指定
-F [fs]
--field-separator [fs]
組み込み変数 FS に fs を設定する (空白を設定する場合は、値を省略しても良い)
-v var=val
--assign var=val
スクリプトが実行される前に、組込変数または、グローバル(Class)変数 var に値 val を設定する。

Note:  空白を含む文字列は、" または、' で囲み、'='の前後には、空白を入れない。

実行時パラメータ (Run-time parameters)

ARGV変数のファイル名の変わりに(-v 無し)var=val 指定を行った場合は、その ARGV参照時に var=val を実行する。

注意:  [パス/]ファイル名に '='を含む場合 (正確には、/^[A-Za-z_$][\w$]+[\s]*=/) は、先頭にパス './' を付加すること。
空白を含むパラメータまたは、ファイル名は、" ' で囲み、 " ' 文字を入力するときは、\" \' エスケープする。

Note:  sample/T8GroovyType.awk 参照

インタプリタ (Interpreter)

インタープリタは AWK˜plus 言語仕様の全てをサポートする。

 $(PLUS) スクリプト名 [[コマンドラインオプション] 実行パラメータ ]

コンパイラ (Compiler, Generator)

Groovyは、動的型推論または、静的型付けモードで動作する。

# Generate&Run
 $(RUN) スクリプト名 [[コマンドラインオプション] 実行パラメータ ]
# Generate&Compile&Go
 $(Go) クラス名 [[コマンドラインオプション] 実行パラメータ ]

Note:  $(RUN)と$(Go)は、バイトコードの出力先がメモリかディスク かの違いで、実行スピードの差は無い。

ベンチマーク (Bench mark)

エラトステネスのふるい (Eratosthenes) による、 四則演算、文字列結合、連想配列アクセスを多用 した場合の実行結果を以下に示す。

 make bench

« Plus Ver.2: Windows10, i5 2.6GHz 2020/5 »
言語 実行時間(秒) 相対値
Java 14 0.20 1
GNU AWK 4.1.4 1.xx 5
plus (Groovy Compiler+) 3.19 15
plus (Interpreter) 4.85 24
plus (Groovy Compiler) 9.94 49

Note:  (Groovy Compiler+) は、静的型付けコンパイルができるよう、AWK˜Plus に書換えたもの。

« Plus Ver.1: Windows-XP 2012/10 »
言語 実行時間(秒) 相対値
Java 1.7 0.23 1
Kotlin 0.24 1
Xtend 0.34 1
 plus (Kotlin Compiler)  0.86 4
Scala 1.00 4
GNU AWK 4.0.1 1.xx 4
plus (Scala Compiler) 1.34 6
Groovy 2.39 10
Jython (Python) 3.66 16
plus (Interpreter) 8.84 38


The AWK˜plus Programming Language
  1. AWK の彼方に (Over The AWK)
    1. 互換性 (Compatibility)
    2. オブジェクト指向 (Object Oriented)
    3. 関数型プログラミング (Functional programming)
    4. 型変換 (Cast)
  2. 実行 (Plus,Run,Go)
    1. インタプリタ (Interpreter)
    2. コンパイラ (Compiler)
    3. ベンチマーク (Bench mark)