式の構文解析の前に
式の構文解析に移りたいのですが、先にちょっとした確認用の機能を作っておきます。これが済んだら式の解析です。
ASTからソースコードを復元する機能
今回は、デバッグ用に使える機能を追加していきます。ASTからソースコードを作成する機能です。これがあると、後の式の解析機能を実装するのが楽になります。
ToCode()
INode
に ToCode()
を追加します。すべてのASTは ToCode()
を実装し、各ノードの状態に対応したコードを返します。
public interface INode
{
string TokenLiteral();
string ToCode();
}
追加すると INode を実装するクラス(Root, LetStatement, ReturnStatement, Identifier)についてエラーがコンパイルエラーになるので、それぞれに実装を追加します。
Root に追加
まずは Root です。
Ast/Root.cs
public class Root : INode
{
// ..
public string ToCode()
{
var builder = new StringBuilder();
foreach (var ast in this.Statements)
{
builder.AppendLine(ast.ToCode());
}
return builder.ToString().TrimEnd();
}
}
プログラムを構成するすべての式について、ToCode()
を呼び出した結果を改行区切りで連結した文字列を返します。
末尾に改行文字が余計につくので Trim しています。
後はそれぞれのクラスに元のコードになるように文字列を復元します。
Identifier に追加
public class Identifier : IExpression
{
// ..
public string TokenLiteral() => this.Token?.Literal ?? "";
}
LetStatement に追加
public class LetStatement : IStatement
{
// ..
public string ToCode()
{
var builder = new StringBuilder();
builder.Append(this.Token?.Literal ?? "");
builder.Append(" ");
builder.Append(this.Name?.ToCode() ?? "");
builder.Append(" = ");
builder.Append(this.Value?.ToCode() ?? "");
builder.Append(";");
return builder.ToString();
}
}
ReturnStatement に追加
public class ReturnStatement : IStatement
{
// ..
public string ToCode()
{
var builder = new StringBuilder();
builder.Append(this.Token?.Literal ?? "");
builder.Append(" ");
builder.Append(this.ReturnValue?.ToCode() ?? "");
builder.Append(";");
return builder.ToString();
}
}
テストで確認する
AstTest.cs
using Gorilla.Ast;
using Gorilla.Ast.Expressions;
using Gorilla.Ast.Statements;
using Gorilla.Lexing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
namespace UnitTestProject
{
[TestClass]
public class AstTest
{
[TestMethod]
public void TestNodeToCode1()
{
var code = "let x = abc;";
var root = new Root();
root.Statements = new List<IStatement>();
root.Statements.Add(
new LetStatement()
{
Token = new Token(TokenType.LET, "let"),
Name = new Identifier(
new Token(TokenType.IDENT, "x"),
"x"
),
Value = new Identifier(
new Token(TokenType.IDENT, "abc"),
"abc"
),
}
);
Assert.AreEqual(code, root.ToCode(), "Root.ToCode() の結果が間違っています。");
}
}
}
let x = abc;
に相当するASTをコンストラクタを使って構築し、それをコードにして確認しています。右辺の式については実装済なのが識別子だけなので、それを使います。
テストが通れば準備完了です。式の解析にようやく移れます。
テスト名: TestNodeToCode1
テストの完全名: UnitTestProject.AstTest.TestNodeToCode1
テスト ソース: E:\work\cs\Gorilla\UnitTestProject\AstTest.cs : 行 14
テスト成果: 成功
テスト継続時間: 0:00:00.035122
ここまでのコード
mntm0/Gorilla at ee7f1a767813115d1440002aefb11e5533c607e7
以上。
コメントを書く