SASS、SCSSの勉強に作ってみました。実行環境によって動作が違って大変でした……。
制作過程
まず、文字列のn文字目の文字を返す関数を作ります。環境によっては動かなかったりするので、色々調整します。
@function str-nth($str, $num) {
@return str-slice($str, $num, $num);
// 動かない場合1
@return str-slice($str, $num, $num - str-length($str));
// 動かない場合2
@return str-slice(str-slice($str, $num - 1, $num), 2, 3);
}
次に、10進数を16進数に変換する関数を作ります。
@function dec2hex($num) {
@if ($num == 0) {
@return "0";
}
$digit: "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f";
$out: "";
@while $num > 0 {
$hex: $num % 16;
$out: nth($digit, $hex + 1) + $out;
$num: ($num - $hex) / 16;
}
@return $out;
}
これを何に使うかというと、Unicodeのコードポイントで表した文字列を返す関数を作るためです。
@function char($codepoint) {
@return unquote("\\") + dec2hex($codepoint);
}
そして、関数本体を作ります。
@function bf($src) {
// 変数宣言
$array: (0, 0); // 配列。(0)だけだとリスト扱いされない場合がある
$p: 1; // ポインタ
$i: 1; // ソースコードの何文字目か
$out: unquote(""); // 出力結果。「"」が付かない文字列にする
// 1文字ずつループ
@while $i <= str-length($src) {
$c: str-nth($src, $i);
@if $c == ">" {
$p: $p + 1;
@if $p > length($array) {
$array: append($array, 0); // ポインタが端を超えたら配列を増やす
}
}
@else if $c == "<" {
$p: $p - 1;
@if $p < 1 {
@return "Error!"; // ポインタが負になったらエラー
}
}
@else if $c == "+" {
$array: set-nth($array, $p, (nth($array, $p) + 1) % 256);
}
@else if $c == "-" {
$array: set-nth($array, $p, (nth($array, $p) + 255) % 256);
}
@else if $c == "." {
$out: $out + char(nth($array, $p));
}
@else if $c == "," {
// 入力の実装はなし
}
@else if $c == "[" {
@if nth($array, $p) == 0 {
$b: 1; // カッコの対応を数える
@while $b != 0 {
$i: $i + 1;
@if $i > str-length($src) {
@return "Error!"; // 正しく対応していなかったらエラー
}
@else if str-nth($src, $i) == "[" {
$b: $b + 1;
}
@else if str-nth($src, $i) == "]" {
$b: $b - 1;
}
}
}
} @else if $c == "]" {
@if nth($array, $p) != 0 {
$b: -1; // 対応するカッコを数える
@while $b != 0 {
$i: $i - 1;
@if $i < 1 {
@return "Error!"; // 正しく対応していなかったらエラー
}
@else if str-nth($src, $i) == "[" {
$b: $b + 1;
}
@else if str-nth($src, $i) == "]" {
$b: $b - 1;
}
}
}
}
$i: $i + 1;
}
// クオートで囲んで返す
@return unquote("\"") + $out + unquote("\"");
}
表示してみます。
$helloworld: "+++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.------------.<++++++++.--------.+++.------.--------.>+.";
#log::before {
content: bf($helloworld);
}
コンパイル結果
#output::before {
content: "\48\65\6c\6c\6f\2c\20\77\6f\72\6c\64\21";
}
HTML
<div id="output"></div>
表示結果
Hello, world!
SASS、SCSSはチューリング完全なんですね。