From 6a396d63688a3e69f1de240d2339a033ba3d756b Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 17 Nov 2018 19:13:05 +0100 Subject: [PATCH] Adds Tables --- Upsilon/BaseTypes/LuaTable.cs | 29 ++++++++++++ Upsilon/Binder/Binder.cs | 46 +++++++++++++++++++ .../BoundExpressions/BoundTableExpression.cs | 24 ++++++++++ Upsilon/Binder/BoundKind.cs | 3 +- Upsilon/Evaluator/Evaluator.cs | 13 ++++++ .../ExpressionSyntax/TableExpressionSyntax.cs | 31 +++++++++++++ Upsilon/Parser/Lexer.cs | 25 +++------- Upsilon/Parser/Parser.cs | 22 +++++++++ Upsilon/Parser/SyntaxKind.cs | 5 +- Ycicle/Program.cs | 34 +++++++++++++- 10 files changed, 210 insertions(+), 22 deletions(-) create mode 100644 Upsilon/BaseTypes/LuaTable.cs create mode 100644 Upsilon/Binder/BoundExpressions/BoundTableExpression.cs create mode 100644 Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs diff --git a/Upsilon/BaseTypes/LuaTable.cs b/Upsilon/BaseTypes/LuaTable.cs new file mode 100644 index 0000000..d0ed040 --- /dev/null +++ b/Upsilon/BaseTypes/LuaTable.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Upsilon.BaseTypes +{ + public class LuaTable : LuaType + { + private Dictionary _map; + + public LuaTable() + { + _map = new Dictionary(); + } + + public LuaTable(Dictionary map) + { + _map = map; + } + + + public override Type Type => Type.Table; + public override object ToCSharpObject() + { + return _map.ToDictionary(x => x.Key, x => x.Value.ToCSharpObject()); + } + + + } +} \ No newline at end of file diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 1887db8..e6b19af 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -78,6 +78,8 @@ namespace Upsilon.Binder return BindVariableExpression((VariableExpressionSyntax) e); case SyntaxKind.FunctionCallExpression: return BindFunctionCallExpression((FunctionCallExpressionSyntax) e); + case SyntaxKind.TableExpression: + return BindTableExpression((TableExpressionSyntax) e); case SyntaxKind.BadExpression: break; case SyntaxKind.ScriptUnit: @@ -352,5 +354,49 @@ namespace Upsilon.Binder return new BoundReturnStatement(expression); } + private BoundExpression BindTableExpression(TableExpressionSyntax e) + { + var keyType = Type.Unknown; + var valueType = Type.Unknown; + var currentKey = 0; + var dictionary = new Dictionary(); + foreach (var expressionSyntax in e.Expressions) + { + if (expressionSyntax.Kind == SyntaxKind.AssignmentStatement) + { + var assignment = (AssignmentExpressionSyntax) expressionSyntax; + var key = assignment.Identifier.Name; + if (keyType == Type.Unknown) + keyType = Type.String; + if (dictionary.ContainsKey(key)) + { + // TODO: Log + continue; + } + var bound = BindExpression(assignment.Expression); + if (valueType == Type.Unknown) + valueType = bound.Type; + dictionary.Add(key, bound); + } + else + { + var expression = (ExpressionSyntax) expressionSyntax; + currentKey++; + if (dictionary.ContainsKey(currentKey.ToString())) + { + // TODO: Log + continue; + } + if (keyType == Type.Unknown) + keyType = Type.Number; + var bound = BindExpression(expression); + if (valueType == Type.Unknown) + valueType = bound.Type; + dictionary.Add(currentKey.ToString(), bound); + } + } + return new BoundTableExpression(keyType, valueType, dictionary); + } + } } \ No newline at end of file diff --git a/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs new file mode 100644 index 0000000..f1a0892 --- /dev/null +++ b/Upsilon/Binder/BoundExpressions/BoundTableExpression.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using Upsilon.BaseTypes; + +namespace Upsilon.Binder +{ + public class BoundTableExpression : BoundExpression + { + public BoundTableExpression(Type keyType, Type valueType, Dictionary expressions) + { + KeyType = keyType; + ValueType = valueType; + Expressions = expressions; + } + + public override BoundKind Kind => BoundKind.BoundTableExpression; + public override Type Type => Type.Table; + + public Type KeyType { get; } + public Type ValueType { get; } + + public Dictionary Expressions { get; } + } +} \ No newline at end of file diff --git a/Upsilon/Binder/BoundKind.cs b/Upsilon/Binder/BoundKind.cs index 5585abd..cc803c4 100644 --- a/Upsilon/Binder/BoundKind.cs +++ b/Upsilon/Binder/BoundKind.cs @@ -9,6 +9,7 @@ namespace Upsilon.Binder BoundUnaryExpression, VariableExpression, BoundFunctionCallExpression, + BoundTableExpression, // Statements BoundAssignmentStatement, @@ -18,6 +19,6 @@ namespace Upsilon.Binder BoundElseStatement, BoundFunctionStatement, BoundPromise, - BoundReturnStatement + BoundReturnStatement, } } \ No newline at end of file diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index a72bfdb..6f3a0b3 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -68,6 +68,7 @@ namespace Upsilon.Evaluator case BoundKind.BoundUnaryExpression: case BoundKind.VariableExpression: case BoundKind.BoundFunctionCallExpression: + case BoundKind.BoundTableExpression: _lastValue = EvaluateExpression((BoundExpression) b); break; case BoundKind.BoundAssignmentStatement: @@ -135,6 +136,8 @@ namespace Upsilon.Evaluator return EvaluateVariableExpression((BoundVariableExpression) e); case BoundKind.BoundFunctionCallExpression: return EvaluateBoundFunctionCallExpression((BoundFunctionCallExpression) e); + case BoundKind.BoundTableExpression: + return EvaluateTableExpression((BoundTableExpression) e); default: throw new NotImplementedException(); } @@ -287,5 +290,15 @@ namespace Upsilon.Evaluator HasReturned = true; } + private LuaType EvaluateTableExpression(BoundTableExpression e) + { + var dic = new Dictionary(); + foreach (var boundExpression in e.Expressions) + { + var evaluated = EvaluateExpression(boundExpression.Value); + dic.Add(boundExpression.Key, evaluated); + } + return new LuaTable(dic); + } } } \ No newline at end of file diff --git a/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs b/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs new file mode 100644 index 0000000..b5d1b8d --- /dev/null +++ b/Upsilon/Parser/ExpressionSyntax/TableExpressionSyntax.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using Upsilon.Text; + +namespace Upsilon.Parser +{ + public sealed class TableExpressionSyntax : ExpressionSyntax + { + public TableExpressionSyntax(SyntaxToken openBrace, ImmutableArray expressions, SyntaxToken closeBrace) + { + Expressions = expressions; + OpenBrace = openBrace; + CloseBrace = closeBrace; + Span = new TextSpan(OpenBrace.Span.Start, CloseBrace.Span.End - OpenBrace.Span.Start); + } + + public override SyntaxKind Kind => SyntaxKind.TableExpression; + + public SyntaxToken OpenBrace { get; } + public ImmutableArray Expressions { get; } + public SyntaxToken CloseBrace { get; } + + public override IEnumerable ChildNodes() + { + yield return OpenBrace; + foreach (var e in Expressions) + yield return e; + yield return CloseBrace; + } + } +} \ No newline at end of file diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index e9a3531..213a299 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -22,25 +22,8 @@ namespace Upsilon.Parser return lexer.Lex(); } - private char Current - { - get - { - if (_position >= _text.Length) - return '\0'; - return _text[_position]; - } - } - - private char Next - { - get - { - if (_position + 1 >= _text.Length) - return '\0'; - return _text[_position + 1]; - } - } + private char Current => _position >= _text.Length ? '\0' : _text[_position]; + private char Next => _position + 1 >= _text.Length ? '\0' : _text[_position + 1]; private ImmutableArray Lex() @@ -82,6 +65,10 @@ namespace Upsilon.Parser return new SyntaxToken(SyntaxKind.OpenParenthesis, _position, "(", null); case ')': return new SyntaxToken(SyntaxKind.CloseParenthesis, _position, ")", null); + case '{': + return new SyntaxToken(SyntaxKind.OpenBrace, _position, "{", null); + case '}': + return new SyntaxToken(SyntaxKind.CloseBrace, _position, "}", null); case ',': return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); case '"': diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index 52090b7..a1a67fd 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -230,6 +230,8 @@ namespace Upsilon.Parser return ParseFunctionCallExpression(); var token = MatchToken(SyntaxKind.Identifier); return new VariableExpressionSyntax((IdentifierToken) token); + case SyntaxKind.OpenBrace: + return ParseTable(); case SyntaxKind.NilKeyword: var nilToken = MatchToken(SyntaxKind.NilKeyword); return new LiteralExpressionSyntax(nilToken, null); @@ -284,5 +286,25 @@ namespace Upsilon.Parser var stringToken = MatchToken(SyntaxKind.String); return new LiteralExpressionSyntax(stringToken, stringToken.Value); } + + private ExpressionSyntax ParseTable() + { + var openBrace = MatchToken(SyntaxKind.OpenBrace); + var arrBuilder = ImmutableArray.CreateBuilder(); + bool lastCommaFound = true; + while (Current.Kind != SyntaxKind.CloseBrace) + { + if (!lastCommaFound) + break; + var parsed = ParseExpression(); + arrBuilder.Add(parsed); + lastCommaFound = Current.Kind == SyntaxKind.Comma; + if (lastCommaFound) NextToken(); + + } + + var closeBrace = MatchToken(SyntaxKind.CloseBrace); + return new TableExpressionSyntax(openBrace, arrBuilder.ToImmutable(), closeBrace); + } } } \ No newline at end of file diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index 4485b84..a83891e 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -21,6 +21,8 @@ namespace Upsilon.Parser TildeEquals, Comma, String, + OpenBrace, + CloseBrace, // key words TrueKeyword, @@ -49,6 +51,7 @@ namespace Upsilon.Parser VariableExpression, FunctionCallExpression, BadExpression, + TableExpression, // script unit ScriptUnit, @@ -60,6 +63,6 @@ namespace Upsilon.Parser ElseIfStatement, ElseStatement, FunctionStatement, - ReturnStatement + ReturnStatement, } } \ No newline at end of file diff --git a/Ycicle/Program.cs b/Ycicle/Program.cs index 1ea564a..1ec7170 100644 --- a/Ycicle/Program.cs +++ b/Ycicle/Program.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Text; using Upsilon; using Upsilon.Evaluator; @@ -46,7 +48,8 @@ namespace Ycicle if (evaluate == null) continue; Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine(evaluate); + + Console.WriteLine(ParseEvaluated(evaluate)); Console.ResetColor(); } } @@ -68,5 +71,34 @@ namespace Ycicle Console.Write(message.LineAfterError()); Console.WriteLine(); } + + private static string ParseEvaluated(object o, int jumps = 0) + { + var sb = new StringBuilder(); + if (o is Dictionary dic) + { + for (var i = 0; i < jumps; i++) sb.Append(" "); + sb.Append("{\n"); + foreach (var (key, value) in dic) + { + for (var i = 0; i < jumps; i++) sb.Append(" "); + sb.Append(" {"); + sb.Append("\""); + sb.Append(key); + sb.Append("\": "); + sb.Append(ParseEvaluated(value, jumps + 1)); + sb.Append(" }"); + sb.Append(",\n"); + } + for (var i = 0; i < jumps; i++) sb.Append(" "); + sb.Append("}\n"); + } + else + { + sb.Append(o.ToString()); + } + + return sb.ToString(); + } } } \ No newline at end of file