Skip to content

Commit

Permalink
WIP: Add builtin operators and fix parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
NeilKleistGao committed Jan 24, 2025
1 parent 18e52bb commit 7a06ad4
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 12 deletions.
4 changes: 2 additions & 2 deletions Src/Parser/ParseResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public abstract class ResultList<TRes, TEnv>: IEvaluatable<TRes, TEnv> {
protected List<IEvaluatable<TRes, TEnv>> list = new List<IEvaluatable<TRes, TEnv>>();

public void Append(IEvaluatable<TRes, TEnv> res) {
list.Append(res);
list.Add(res);
}

public abstract TRes Evaluate(TEnv env);
Expand All @@ -39,7 +39,7 @@ public abstract class StringLiteral<TRes, TEnv> : Literal<TRes, TEnv> {
}

public abstract class Symbol<TRes, TEnv>: IEvaluatable<TRes, TEnv> {
private string name;
protected string name;

public abstract TRes Evaluate(TEnv env);

Expand Down
42 changes: 42 additions & 0 deletions Src/Runtime/Builtin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Marionette.Parser;

namespace Marionette.Runtime {
public class BinaryOperator : IEvaluatable<Value, Environment> {
private string name;

private Value Add(Value lhs, Value rhs) {
if (lhs is LiteralValue<int> i1 && rhs is LiteralValue<int> i2) {
return new LiteralValue<int>(i1.Value + i2.Value);
}
else if (lhs is LiteralValue<int> i && rhs is LiteralValue<double> d) {
return new LiteralValue<double>(i.Value + d.Value);
}
else if (lhs is LiteralValue<double> d2 && rhs is LiteralValue<int> i3) {
return new LiteralValue<double>(i3.Value + d2.Value);
}
else if (lhs is LiteralValue<double> d3 && rhs is LiteralValue<double> d4) {
return new LiteralValue<double>(d3.Value + d4.Value);
}
else if (lhs is LiteralValue<string> s1 && rhs is LiteralValue<string> s2) {
return new LiteralValue<string>(s1.Value + s2.Value);
}

throw new Exception(string.Format("cannot add {0} and {1}.", lhs.Show(), rhs.Show()));
}

public Value Evaluate(Environment env) {
var lhs = new EvalSymbol("lhs").Evaluate(env);
var rhs = new EvalSymbol("rhs").Evaluate(env);
if (name == "+") {
return Add(lhs, rhs);
}
// TODO: other

throw new Exception(string.Format("{0} cannot be used as a builtin symbol here.", name));
}

public BinaryOperator(string name) {
this.name = name;
}
}
} // namespace Marionette.Runtime
28 changes: 28 additions & 0 deletions Src/Runtime/EvaluationNodes.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Marionette.Parser;
using Marionette.Utils;

namespace Marionette.Runtime {
public class EvalIntLit: IntLiteral<Value, Environment> {
Expand Down Expand Up @@ -41,6 +42,33 @@ public EvalStringLit(string s) {
}
}

public class EvalList: ResultList<Value, Environment> {
public EvalList() {}

public override Value Evaluate(Environment env){
if (list.IsEmpty()) {
throw new Exception("Empty invocation.");
}

var fun = list[0].Evaluate(env); // TODO:
if (fun is Closure closure) {
list.RemoveAt(0);
return closure.Evaluate(list.Map(x => x.Evaluate(env)).ToArray());
}
else {
throw new Exception(string.Format("{0} is not a function.", fun.Show()));
}
}
}

public class EvalSymbol: Symbol<Value, Environment> {
public override Value Evaluate(Environment env){
return env.GetOrElse(name, n => throw new Exception(string.Format("name not found: {0}", n)));
}

public EvalSymbol(string name) : base(name) {}
}

public class EvalEOF: EOF<Value, Environment> {
public override Value Evaluate(Environment env) {
return new UnitValue();
Expand Down
37 changes: 31 additions & 6 deletions Src/Runtime/Interpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,45 @@ namespace Marionette.Runtime {
public class Environment {
private Dictionary<string, Value> env = new Dictionary<string, Value>();

private Environment? parent = null;

private Environment() {
env.Add("+", new Closure(["lhs", "rhs"], globalEnvironment, new BinaryOperator("+")));
}

public Environment(Environment parent) {
this.parent = parent;
}

private static Environment globalEnvironment = new Environment();

public static Environment GlobalEnvironment() {
return globalEnvironment;
}

public static Environment CreateEmpty() {
return new Environment();
public void Add(string name, Value value) {
env[name] = value;
}

public Value GetOrElse(string name, Func<string, Value> fallback) {
if (env.ContainsKey(name)) {
return env[name];
}
else if (parent is Environment p) {
return parent.GetOrElse(name, fallback);
}
else {
return fallback(name);
}
}
}

public class Interpreter {

private Environment env = Environment.CreateEmpty();
private Environment env = Environment.GlobalEnvironment();

private ResultList<Value, Environment> AllocateList() {
throw new NotImplementedException();
return new EvalList();
}

private Literal<Value, Environment> AllocateLiteral(string text) {
Expand Down Expand Up @@ -51,7 +76,7 @@ private Literal<Value, Environment> AllocateLiteral(string text) {
else if (text.StartsWith("0b")) {
return new EvalIntLit(flag * Convert.ToInt32(text[2..], 2));
}
else if (text.StartsWith("0")) {
else if (text.StartsWith("0") && text.Length > 1) {
return new EvalIntLit(flag * Convert.ToInt32(text[1..], 8));
}
else {
Expand All @@ -63,7 +88,7 @@ private Literal<Value, Environment> AllocateLiteral(string text) {
}

private Symbol<Value, Environment> AllocateSymbol(string name) {
throw new NotImplementedException();
return new EvalSymbol(name);
}

private EOF<Value, Environment> AllocateEOF() {
Expand Down
39 changes: 35 additions & 4 deletions Src/Runtime/Values.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Marionette.Parser;

namespace Marionette.Runtime {
public abstract class Value {
public abstract string Show();
Expand All @@ -19,13 +21,42 @@ public override string Show() {
}
}

public class UnitValue : Value {
public override string Show() {
return "";
public class Closure : Value {
private string[] bindings;
private Environment environment;
private IEvaluatable<Value, Environment> body;

public override string Show() {
return "[Function]";
}

public Closure(string[] bindings, Environment environment, IEvaluatable<Value, Environment> body) {
this.bindings = bindings;
this.environment = environment;
this.body = body;
}

public Value Evaluate(Value[] values) {
if (bindings.Length != values.Length) {
throw new Exception(string.Format("Expect {0} argument{1}, got {2}", bindings.Length, (bindings.Length > 1) ? "s" : "", values.Length));
}

var nestCxt = new Environment(environment);
foreach (var p in bindings.Zip(values)) {
nestCxt.Add(p.First, p.Second);
}

return body.Evaluate(nestCxt);
}
}

public class UnitValue : Value {
public override string Show() {
return "";
}
}

public class Result {
public class Result {
private bool succeeded = false;
private List<Utils.Diagnosis> diagnosis = new List<Utils.Diagnosis>();
private Value value = new UnitValue();
Expand Down
9 changes: 9 additions & 0 deletions Src/Utils/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ public static class ListExtensions {
public static bool IsEmpty<T>(this List<T> value) {
return value == null || value.Count == 0;
}

public static List<S> Map<T, S>(this List<T> value, Func<T, S> func) {
var res = new List<S>();
foreach (var item in value) {
res.Add(func(item));
}

return res;
}
}

public static class ArrayExtensions {
Expand Down
28 changes: 28 additions & 0 deletions Tests/Mario/calc.mario
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
(+ 1 1)
;;|| --- Result --- ||
;;|| Res: 2


(+ 3.14 6.28)
;;|| --- Result --- ||
;;|| Res: 9.42


(+ 0b1100 0b0011)
;;|| --- Result --- ||
;;|| Res: 15


(+ 1 1.14)
;;|| --- Result --- ||
;;|| Res: 2.1399999999999997


(+ 5.14 0)
;;|| --- Result --- ||
;;|| Res: 5.14


(+ "hello " "world")
;;|| --- Result --- ||
;;|| Res: hello world

0 comments on commit 7a06ad4

Please sign in to comment.