ゲーム用に Java でスクリプト言語を構築しており、現在はパーサーに取り組んでいます。この言語は、カスタムの呪文や効果を作成するために、プレイヤー/改造者/私自身によって利用されます。ただし、現在のシステムで静的型付けをスムーズに実装する方法を想像するのは困難です (パフォーマンスのニーズによって引き起こされる苦痛な必要性)。コンパイルが高速かどうかはあまり気にしませんが、実際の実行は可能な限り高速である必要があります (少なくとも、合理的な範囲内で。これをすぐに実行したいと考えています)。
したがって、パーサーには 、トークンのストリームを反復処理するためのメソッドがnext()
あります。peek()
現在、型の優先順位を保持する方法で相互に呼び出す階層メソッド (定数、変数などを返す「最下位」のメソッド) で構築されています。各メソッドは、それが「解決」するIResolve
ジェネリック型を持つ を返します。<T>
たとえば、「and」がより緊密に結合された「or」式を処理するメソッドを次に示します。
protected final IResolve checkGrammar_Or() throws ParseException
{
IResolve left = checkGrammar_And();
if (left == null)
return null;
if (peek().type != TokenType.IDENTIFIER || !"or".equals((String)peek().value))
return left;
next();
IResolve right = checkGrammar_Or();
if (right == null)
throwExpressionException();
return new BinaryOperation(left, right, new LogicOr());
}
問題は、型に依存する関数を実装する必要がある場合です。お気づきかもしれませんが、ジェネリック型はパーサーによって指定されておらず、設計上の問題の一部です。この関数では、次のようなことをしたいと思っていました (ジェネリック型の消去のためにこれは機能しませんが...)
protected final IResolve checkGrammar_Comparison() throws ParseException
{
IResolve left = checkGrammer_Term();
if (left == null)
return null;
IBinaryOperationType op;
switch (peek().type)
{
default:
return left;
case LOGIC_LT:
//This ain't gonna work because of erasure
if (left instanceof IResolve<Double>)
op = new LogicLessThanDouble();
break;
//And the same for these
case LOGIC_LT_OR_EQUAL:
case LOGIC_GT:
case LOGIC_GT_OR_EQUAL:
}
next();
IResolve right = checkGrammar_Comparison();
if (right == null)
throwExpressionException();
return new BinaryOperation(left, right, op);
}
接続できるようにしたい問題点は、switch ステートメントにあります。int
特に将来ユーザー定義クラスをサポートしたい場合は、IResolve を非ジェネリックにし、何かを返す「getType()」メソッドを与える必要があることはすでに確信しています。
質問は:
私の現在の構造と混合継承 (Java や C# などのユーザー定義のクラスとインターフェイス) への欲求を考慮して、静的型付けを実現する最善の方法は何ですか? 良い方法がない場合、それを達成するために構造を変更または再構築するにはどうすればよいですか?
注: 私は、自分が何に夢中になってしまったのかを理解しているとは主張していません。建設的な批判は大歓迎です。何か明確にする必要がある場合は、お知らせください。
別のメモ: あなたが「なぜ静的型付けなのか?」と考えていることは知っていますが、通常はその意見に同意しますが、ゲームの世界はボクセル (正確には Minecraft の mod です) で構成されており、それらを操作するには速いです。O(n^2) アルゴリズムが 100 ブロック以上を 1 秒間に 20 回反復するスクリプトを想像してみてください。30 人以上のプレイヤーが、すでにかろうじて音を立てている安価なサーバーで... または、1 回の大規模な爆発が必然的に数千のブロックに影響を与えます。恐ろしいラグスパイクを引き起こします。したがって、バックエンドの型チェックやダックタイピングの任意の形式は、それをカットするつもりはありません (私はそれがどうしても欲しくてたまらないのですが)。