90分钟实现一门编程语言(极简解释器教程)

2019-12-30 14:54:22王冬梅


public class SBool : SObject {
  public static readonly SBool False = new SBool();
  public static readonly SBool True = new SBool();
  public override String ToString() {
    return ((Boolean)this).ToString();
  }
  public static implicit operator Boolean(SBool value) {
    return value == SBool.True;
  }
  public static implicit operator SBool(Boolean value) {
    return value ? True : False;
  }
}

这里同样使用了 C# 的 隐式操作符重载,这使得我们可以:


SBool foo = a > 1;
if (foo) {
  // Do something...
}

而不用


SBool foo = a > 1 ? SBool.True: SBool.False;
if (foo == SBool.True) {
  // Do something...
}

同样,为 SObject 增加 隐式操作符重载:


public class SObject {
  ...
  public static implicit operator SObject(Boolean value) {
    return (SBool)value;
  }
}

列表类型

iScheme使用.Net中的 IEnumberable<T> 实现列表类型 SList :


public class SList : SObject, IEnumerable<SObject> {
  private readonly IEnumerable<SObject> values;
  public SList(IEnumerable<SObject> values) {
    this.values = values;
  }
  public override String ToString() {
    return "(list " + " ".Join(this.values) + ")";
  }
  public IEnumerator<SObject> GetEnumerator() {
    return this.values.GetEnumerator();
  }
  IEnumerator IEnumerable.GetEnumerator() {
    return this.values.GetEnumerator();
  }
}

实现 IEnumerable<SObject> 后,就可以直接使用LINQ的一系列扩展方法,十分方便。

函数类型

iScheme 的函数类型( SFunction )由三部分组成:

函数体:即对应的 SExpression 。 参数列表。 作用域:函数拥有自己的作用域

SFunction的实现


public class SFunction : SObject {
  public SExpression Body { get; private set; }
  public String[] Parameters { get; private set; }
  public SScope Scope { get; private set; }
  public Boolean IsPartial {
    get {
      return this.ComputeFilledParameters().Length.InBetween(1, this.Parameters.Length);
    }
  }
  public SFunction(SExpression body, String[] parameters, SScope scope) {
    this.Body = body;
    this.Parameters = parameters;
    this.Scope = scope;
  }
  public SObject Evaluate() {
    String[] filledParameters = this.ComputeFilledParameters();
    if (filledParameters.Length < Parameters.Length) {
      return this;
    } else {
      return this.Body.Evaluate(this.Scope);
    }
  }
  public override String ToString() {
    return String.Format("(func ({0}) {1})",
      " ".Join(this.Parameters.Select(p => {
        SObject value = null;
        if ((value = this.Scope.FindInTop(p)) != null) {
          return p + ":" + value;
        }
        return p;
      })), this.Body);
  }
  private String[] ComputeFilledParameters() {
    return this.Parameters.Where(p => Scope.FindInTop(p) != null).ToArray();
  }
}