2017-02-18 6 views
1

マクロ内に新しい変数を作成したいと思います。 (「unexpected token: %を」)Crystalマクロの新しい変数に値を割り当てる

EDITを

macro test() 
    %p = "a = 3" 
    %p 
end 

test() 
puts(a) 

が、私は、エラーundefined local variable or method 'a'

を取得し、私は{{ }}または{% %}%pをラップしようとしたが、それはコンパイルされません:私のコードはに減らすことができます

ここにいくつかの文脈があります。

いくつかの共通フィールドを持つ2つの名前付きタプルを使用しなければならないことが多く、JSONに変換されて別のクライアントに送信されます。

a = {x: xx, y: yy, w: ww} 
b = {x: xx, y: yy, z: zz} 

現在、私は両方を繰り返し書きます。 ww、xx、yy、zzの値はコンパイル時には分かりません。私は、コンパイル時にマージを行うマクロへの呼び出しに置き換えたいと思います。

私は手動でコードI現在入力の行を作成して、次のコードを思い付いた:

macro merge(common, aOnly, bOnly) 
    # Start, middle and end parts of target instructions 
    %p1a = "a = {" 
    %p1b = "b = {" 
    %p2 = "" 
    %p2a = "" 
    %p2b = "" 
    %p3 = "}" 

    # Creating the middle part 
    {% for key, value in common %} 
    %p2 = %p2 + "{{key.id}}" + ": " + "{{value}}" + ',' 
    {% end %} 
    %p2a = %p2 
    {% for key, value in aOnly %} 
    %p2a = %p2a + "{{key.id}}" + ": " + "{{value}}" + ',' 
    {% end %} 
    %p2b = %p2 
    {% for key, value in bOnly %} 
    %p2b = %p2b + "{{key.id}}" + ": " + "{{value}}" + ',' 
    {% end %} 

    # Removing unneeded comma 
    %p2a = %p2a.chomp(",") 
    %p2b = %p2b.chomp(",") 

    # Display 
    puts(%p1a + %p2a + %p3) 
    puts(%p1b + %p2b + %p3) 

    # Definition of new variables 
    %p1a + %p2a + %p3 
    %p1b + %p2b + %p3 
end 

merge({x: xx, y: yy}, {w: ww}, {z: zz}) 
+0

[あなたのプログラム](https://carc.in/#/r/1nfdは)に展開: '__temp_22 = "= 3 A"; __temp_22; puts(a) 'は、私がこの構文を使用すると期待していたものですが、おそらくあなたは何か異なることを期待しています。しかし、あなたが期待したことを推測することはできませんので、あなたの質問を拡大してください。 –

+0

私はいくつかの文脈を追加しました。 –

+2

マクロは新しい変数を定義することはできません。変数は解析時に決定されます。たとえば、あるメソッドの中で 'a = 1'を実行すると、パーサーは' a'が変数であることを知ります。マクロ呼び出しの中でそれを行うと、パーサはそれを知りません。それはバグではなく、言語機能です。メソッドに突然現れる変数をバグが生じやすく混乱させる。 – asterite

答えて

2

ここでの主な問題は、%namesの誤解です。これは、命令をコンパイルするための構造ではありません。 %a = 5を書くことはguaranteed_unique_name = 5 –と同じですが、これは同じスコープ内に存在するかもしれない他の変数との干渉を回避する方法ですが、それでも通常のランタイム変数の割り当てです。

文字列を作成してコンパイル時に出力することは、マクロを使用するための実行可能なアプローチではなく、マクロ変数に別の値を再割り当てすることができないためほとんど不可能になります。

macro merge(common, a_only, b_only) 
    a = { 
    {% for key, value in common %} 
     {{key}}: {{value}}, 
    {% end %} 
    {% for key, value in a_only %} 
     {{key}}: {{value}}, 
    {% end %} 
    } 

    b = { 
    {% for key, value in common %} 
     {{key}}: {{value}}, 
    {% end %} 
    {% for key, value in b_only %} 
     {{key}}: {{value}}, 
    {% end %} 
    } 
end 

merge({x: "a", y: 5}, {w: "b"}, {z: 7}) 

pp a, b 

:今、私はちょうどより多くの通常の構築物であなたの例を書き換えます

macro merge(common, aOnly, bOnly) 
    # Start, middle and end parts of target instructions 
    {% 
    p1a = "a = {" 
    p1b = "b = {" 
    p2 = "" 
    p2a = "" 
    p2b = "" 
    p3 = "}" 
    %} 

    # Creating the middle part 
    {% for key, value in common %} 
    {% p2 = p2 + "#{key.id}: #{value}," %} 
    {% end %} 
    {% p2a = p2 %} 
    {% for key, value in aOnly %} 
    {% p2a += "#{key.id}: #{value}," %} 
    {% end %} 
    {% p2b = p2 %} 
    {% for key, value in bOnly %} 
    {% p2b += "#{key.id}: #{value}," %} 
    {% end %} 

    # Removing unneeded comma 
    {% p2a = p2a.chomp(",") %} 
    {% p2b = p2b.chomp(",") %} 

    # Definition of new variables 
    {{(p1a + p2a + p3).id}} 
    {{(p1b + p2b + p3).id}} 
end 

merge({x: xx, y: yy}, {w: ww}, {z: zz}) 

:しかし、ここでそれはまだ文字列で、あなたのアプローチを使用しようと、それが実際に働いていた場合どのように見えるかの例ですご覧のとおり、マクロ本体に入れた通常のコードはランタイムコードですが、{% %}{{ }}のものはコンパイル時に実行されます。コンパイル時のループを作成し、それらを通常のコード行と絡めて、複雑なコードを自然に作成することができます。

「Crystalマクロの新しい変数に値を割り当てる」と答えてください。ランタイム変数に何かを割り当てるには、マクロ内のランタイムコードを出力するのと同じことをしてください。–あなたはただ書きますa = 5のように、デフォルトではマクロは出力ランタイムコードを出力し、{%{{はコンパイル時の構造を区切るためです。ここでは、コメントに返信する


は、おそらく多くの慣用的なバージョンで、それも一時的な/ユニークな変数名を示しています。これを使用してタプルを作成し、マクロの実行結果は、めったに行われない副作用に頼るのではなく、簡単に解凍できるタプルです。

macro merge(common, a_only, b_only) 
    %a = { 
    {% for key, value in common %} 
     {{key}}: {{value}}, 
    {% end %} 
    {% for key, value in a_only %} 
     {{key}}: {{value}}, 
    {% end %} 
    } 

    %b = { 
    {% for key, value in common %} 
     {{key}}: {{value}}, 
    {% end %} 
    {% for key, value in b_only %} 
     {{key}}: {{value}}, 
    {% end %} 
    } 

    { %a, %b } 
end 

first, second = merge({x: "a", y: 5}, {w: "b"}, {z: 7}) 

puts first 
+0

ありがとうございました。私は第2版がもっと慣れ親しんでいることを理解しています。しかし、なぜ私は変数 "a"と "b"を表示するために "puts"を使うことができないのですか?これを行うと、メッセージ "未定義のローカル変数またはメソッド '' 'が生成されます。 –

+0

@ClementJ。ええと、これはちょっと変わった振る舞いです。マクロは通常、ハードコードされた名前を持つ新しい変数を作成するためには使用されないため、これはよく研究された言語の一部ではありません。マクロを呼び出す前に変数を "予期する"必要があると思います: 'a = nil;マージ({x: "a"、y:5}、{w: "b"}、{z:7}); (フルコード)(https://carc.in/#/r/1nfz) –

+0

@ClementJ。、私の答えに追加を確認してください –

関連する問題