From 15b506649998671c4fe7a931f22142aa258cdb64 Mon Sep 17 00:00:00 2001 From: Jonathan Havron Date: Tue, 21 Nov 2017 12:08:52 -0600 Subject: [PATCH] add if/then/else functions --- Wul/Interpreter/Bool.cs | 4 ++-- Wul/Interpreter/Function.cs | 14 +++++++----- Wul/Interpreter/GlobalScope.cs | 8 ++++++- Wul/Interpreter/IFunction.cs | 2 +- Wul/Interpreter/ListTable.cs | 5 +++++ Wul/Interpreter/Table.cs | 2 +- Wul/Interpreter/WulInterpreter.cs | 14 ++++++++---- Wul/Parser/List.cs | 12 +++++------ Wul/StdLib/Arithmetic.cs | 31 +++++++++++++------------- Wul/StdLib/Comparison.cs | 9 ++++++++ Wul/StdLib/General.cs | 36 +++++++++++++++++++++++++++++++ Wul/Wul.cs | 2 +- 12 files changed, 103 insertions(+), 36 deletions(-) diff --git a/Wul/Interpreter/Bool.cs b/Wul/Interpreter/Bool.cs index e5b43d2..da46bb2 100644 --- a/Wul/Interpreter/Bool.cs +++ b/Wul/Interpreter/Bool.cs @@ -2,8 +2,8 @@ { class Bool : IValue { - public static Bool True => new Bool(true); - public static Bool False => new Bool(false); + public static Bool True = new Bool(true); + public static Bool False = new Bool(false); public readonly bool Value; diff --git a/Wul/Interpreter/Function.cs b/Wul/Interpreter/Function.cs index a9f2b7f..bbe98cb 100644 --- a/Wul/Interpreter/Function.cs +++ b/Wul/Interpreter/Function.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using Wul.Parser; namespace Wul.Interpreter @@ -27,12 +28,15 @@ public IValue Evaluate(List arguments, Scope scope) { string argName = ArgumentNames[i]; currentScope[argName] = arguments[i]; + Debug.WriteLine($"Binding {argName} = {arguments[i].AsString()}"); } - return WulInterpreter.Interpret(Body, currentScope); + IValue result = WulInterpreter.Interpret(Body, currentScope); + Debug.WriteLine($"Returning {result.AsString()}"); + return result; } - public virtual void Execute(ListNode list, Scope scope) + public virtual IValue Execute(ListNode list, Scope scope) { throw new NotImplementedException(); } @@ -62,7 +66,7 @@ public IValue Evaluate(List arguments, Scope scope) return Body(arguments, scope); } - public virtual void Execute(ListNode list, Scope scope) + public virtual IValue Execute(ListNode list, Scope scope) { throw new NotImplementedException(); } @@ -91,9 +95,9 @@ public IValue Evaluate(List arguments, Scope scope) throw new NotImplementedException(); } - public virtual void Execute(ListNode list, Scope scope) + public virtual IValue Execute(ListNode list, Scope scope) { - Body(list, scope); + return Body(list, scope); } public string AsString() diff --git a/Wul/Interpreter/GlobalScope.cs b/Wul/Interpreter/GlobalScope.cs index 0337824..4ae22d0 100644 --- a/Wul/Interpreter/GlobalScope.cs +++ b/Wul/Interpreter/GlobalScope.cs @@ -17,6 +17,12 @@ public static void RegisterDefaultFunctions() //Comparison Scope["="] = StdLib.Comparison.Equal; + Scope["<"] = StdLib.Comparison.LessThan; + + //Conditional + Scope["if"] = StdLib.General.If; + Scope["then"] = StdLib.General.Then; + Scope["else"] = StdLib.General.Then; //Not a typo! //Bools Scope["true"] = Bool.True; @@ -29,7 +35,7 @@ public static void RegisterDefaultFunctions() //Arith Scope["+"] = StdLib.Arithmetic.Add; Scope["-"] = StdLib.Arithmetic.Subtract; - Scope["<"] = StdLib.Arithmetic.LessThan; + Scope["*"] = StdLib.Arithmetic.Multiply; } } } diff --git a/Wul/Interpreter/IFunction.cs b/Wul/Interpreter/IFunction.cs index e1715ab..2d19d3b 100644 --- a/Wul/Interpreter/IFunction.cs +++ b/Wul/Interpreter/IFunction.cs @@ -8,6 +8,6 @@ interface IFunction : IValue string Name { get; } List ArgumentNames { get; } IValue Evaluate(List arguments, Scope scope); - void Execute(ListNode list, Scope scope); + IValue Execute(ListNode list, Scope scope); } } \ No newline at end of file diff --git a/Wul/Interpreter/ListTable.cs b/Wul/Interpreter/ListTable.cs index fb320bb..14aa55d 100644 --- a/Wul/Interpreter/ListTable.cs +++ b/Wul/Interpreter/ListTable.cs @@ -56,6 +56,11 @@ public override void Assign(IValue key, IValue value) public override Number Count => _list.Count; + public override string AsString() + { + return "(" + string.Join(", ", _list.Select(s => s.AsString()).ToList()) + ")"; + } + public override IValue this[IValue key] { get => Get(key); diff --git a/Wul/Interpreter/Table.cs b/Wul/Interpreter/Table.cs index a7ef87b..6f320a5 100644 --- a/Wul/Interpreter/Table.cs +++ b/Wul/Interpreter/Table.cs @@ -12,7 +12,7 @@ abstract class Table : IValue public abstract Number Count { get; } - public string AsString() + public virtual string AsString() { return $"List[{Count.Value}]"; } diff --git a/Wul/Interpreter/WulInterpreter.cs b/Wul/Interpreter/WulInterpreter.cs index d036230..7a8da89 100644 --- a/Wul/Interpreter/WulInterpreter.cs +++ b/Wul/Interpreter/WulInterpreter.cs @@ -81,7 +81,7 @@ private static IValue Evaluate(ListNode list, Scope currentScope = null) } else if (first is ListNode) { - value = Evaluate((ListNode) first); + value = Evaluate((ListNode) first, currentScope); } IFunction function = value as IFunction; @@ -96,14 +96,20 @@ private static IValue Evaluate(ListNode list, Scope currentScope = null) { //Invoke a magic function //Magic functions do not have their arguments evaluated, it's up the function to do so - magicFunction.Execute(list, currentScope); - value = Value.Nil; + value = magicFunction.Execute(list, currentScope); } else { //Evaluate a list var remaining = list.Children.Select(node => Interpret(node, currentScope)).ToArray(); - value = new ListTable(remaining); + if (remaining.Length > 1) + { + value = new ListTable(remaining); + } + else if (remaining.Length == 1) + { + value = remaining[0]; + } } return value; diff --git a/Wul/Parser/List.cs b/Wul/Parser/List.cs index 8f23699..05fe73a 100644 --- a/Wul/Parser/List.cs +++ b/Wul/Parser/List.cs @@ -32,27 +32,27 @@ public override SyntaxNode Parse(string token) List children = new List(); int currentIndex = 0; - int openParenthesis = 0; - int closeParenthesis = 0; + int openParentheses = 0; + int closeParentheses = 0; int startIndex = 0; while (currentIndex < inner.Length) { if (inner[currentIndex] == '(') { - openParenthesis++; + openParentheses++; } else if (inner[currentIndex] == ')') { - closeParenthesis++; + closeParentheses++; } - if (closeParenthesis > openParenthesis) + if (closeParentheses > openParentheses) { throw new Exception("Mismatched parenthesis, have fun"); } currentIndex++; - if ((currentIndex == inner.Length || inner[currentIndex] == ' ' || inner[currentIndex] == ')') && openParenthesis == closeParenthesis) + if ((currentIndex == inner.Length || inner[currentIndex] == ' ' || inner[currentIndex] == ')') && openParentheses == closeParentheses) { string currentInner = inner.Substring(startIndex, currentIndex - startIndex); var item = Parse(currentInner) ?? identifierParser.Parse(currentInner) ?? numericParser.Parse(currentInner); diff --git a/Wul/StdLib/Arithmetic.cs b/Wul/StdLib/Arithmetic.cs index 9f3129b..2f8e260 100644 --- a/Wul/StdLib/Arithmetic.cs +++ b/Wul/StdLib/Arithmetic.cs @@ -16,20 +16,6 @@ internal class Arithmetic return (Number) sum; }, "+"); - internal static IFunction LessThan = new NetFunction((list, scope) => - { - var first = list.First() as Number; - var second = list.Skip(1).First() as Number; - if (first.Value < second.Value) - { - return (Number) 1; - } - else - { - return (Number) 0; - } - }, "<"); - internal static IFunction Subtract = new NetFunction((list, scope) => { var first = list.First() as Number; @@ -40,6 +26,21 @@ internal class Arithmetic } double sum = numbers.Sum(x => x.Value); return (Number) (first.Value - sum); - }, "+"); + }, "-"); + + internal static IFunction Multiply = new NetFunction((list, scope) => + { + var numbers = list.Select(x => x as Number).Where(x => x != null).ToArray(); + if (!numbers.Any()) + { + return Value.Nil; + } + double multiplied = numbers[0]; + for (int i = 1; i < numbers.Length; ++i) + { + multiplied *= numbers[i]; + } + return (Number)multiplied; + }, "*"); } } diff --git a/Wul/StdLib/Comparison.cs b/Wul/StdLib/Comparison.cs index d1c22a6..dfb1d09 100644 --- a/Wul/StdLib/Comparison.cs +++ b/Wul/StdLib/Comparison.cs @@ -12,5 +12,14 @@ internal class Comparison bool equal = first.Equals(second); return equal ? Bool.True : Bool.False; }, "="); + + internal static IFunction LessThan = new NetFunction((list, scope) => + { + Number first = list[0] as Number; + Number second = list[1] as Number; + //TODO make all IValue override Equals + bool lessThan = first.Value < second.Value; + return lessThan ? Bool.True : Bool.False; + }, "<"); } } diff --git a/Wul/StdLib/General.cs b/Wul/StdLib/General.cs index 89d91c7..da6c5d2 100644 --- a/Wul/StdLib/General.cs +++ b/Wul/StdLib/General.cs @@ -33,5 +33,41 @@ class General return function; }, "def"); + + internal static IFunction Then = new NetFunction((list, scope) => + { + if (list.Count == 1) + { + return list.First(); + } + else + { + return new ListTable(list.ToArray()); + } + }, "then/else"); + + internal static IFunction If = new MagicNetFunction((list, scope) => + { + var children = list.Children.Skip(1).ToArray(); + + var condition = children[0]; + var result = WulInterpreter.Interpret(condition, scope); + + var listChildren = children.OfType(); + + IValue returnValue = Value.Nil; + if (result != Value.Nil && result != Bool.False) + { + var thenBlock = listChildren.FirstOrDefault(l => (l.Children.First() as IdentifierNode)?.Name == "then"); + returnValue = WulInterpreter.Interpret(thenBlock, scope); + } + else + { + var elseBlock = listChildren.FirstOrDefault(l => (l.Children.First() as IdentifierNode)?.Name == "else"); + returnValue = WulInterpreter.Interpret(elseBlock, scope); + } + + return returnValue; + }, "if"); } } diff --git a/Wul/Wul.cs b/Wul/Wul.cs index ea99e1b..ef2d8e5 100644 --- a/Wul/Wul.cs +++ b/Wul/Wul.cs @@ -11,7 +11,7 @@ class Wul { static void Main(string[] args) { - //built ins: def, if, -, <, then, else + //built ins: if, then, else var parser = new ProgramParser(); Global.RegisterDefaultFunctions();