From 2baf2b223e104575fbdbdb0300e85afff7783123 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 17 Nov 2018 15:57:26 +0100 Subject: [PATCH] Adds support for strings --- Upsilon/BaseTypes/LuaString.cs | 76 +++++++++++++++++++++++++++ Upsilon/BaseTypes/LuaType.cs | 2 +- Upsilon/Binder/Binder.cs | 4 ++ Upsilon/Binder/BoundBinaryOperator.cs | 9 ++++ Upsilon/Evaluator/Evaluator.cs | 8 ++- Upsilon/Parser/Lexer.cs | 20 +++++++ Upsilon/Parser/Parser.cs | 7 +++ Upsilon/Parser/SyntaxKind.cs | 1 + 8 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 Upsilon/BaseTypes/LuaString.cs diff --git a/Upsilon/BaseTypes/LuaString.cs b/Upsilon/BaseTypes/LuaString.cs new file mode 100644 index 0000000..1e964db --- /dev/null +++ b/Upsilon/BaseTypes/LuaString.cs @@ -0,0 +1,76 @@ +using System; +using Upsilon.BaseTypes.Number; + +namespace Upsilon.BaseTypes +{ + internal class LuaString : LuaType + { + public LuaString(string value) + { + Value = value; + } + + public string Value { get; } + public override Type Type => Type.String; + public override object ToCSharpObject() + { + return Value; + } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (!(obj is LuaString s)) + return false; + return Equals(s); + } + + public override int GetHashCode() + { + return (Value != null ? Value.GetHashCode() : 0); + } + + public bool Equals(LuaString s) + { + if (s == null) return false; + return string.Equals(s.Value, Value); + } + + public static LuaString operator +(LuaString a, LuaType b) + { + switch (b) + { + case LuaString s: + return a + s; + case LuaBoolean bl: + return a + bl; + case NumberLong l: + return a + l; + case NumberDouble d: + return a + d; + } + throw new ArgumentException($"Adding Type '{b.Type}' to a LuaString is not supported."); + } + + public static LuaString operator +(LuaString a, LuaString b) + { + return new LuaString(a.Value + b.Value); + } + + public static LuaString operator +(LuaString a, LuaBoolean b) + { + return new LuaString(a.Value + b.Value); + } + + public static LuaString operator +(LuaString a, NumberLong b) + { + return new LuaString(a.Value + b.Value); + } + + public static LuaString operator +(LuaString a, NumberDouble b) + { + return new LuaString(a.Value + b.Value); + } + } +} \ No newline at end of file diff --git a/Upsilon/BaseTypes/LuaType.cs b/Upsilon/BaseTypes/LuaType.cs index f76791e..698c88d 100644 --- a/Upsilon/BaseTypes/LuaType.cs +++ b/Upsilon/BaseTypes/LuaType.cs @@ -1,6 +1,6 @@ namespace Upsilon.BaseTypes { - internal abstract class LuaType + public abstract class LuaType { public abstract Type Type { get; } public abstract object ToCSharpObject(); diff --git a/Upsilon/Binder/Binder.cs b/Upsilon/Binder/Binder.cs index 8bf73d5..1887db8 100644 --- a/Upsilon/Binder/Binder.cs +++ b/Upsilon/Binder/Binder.cs @@ -129,9 +129,13 @@ namespace Upsilon.Binder case bool b: outValue = new LuaBoolean(b); break; + case string s: + outValue = new LuaString(s); + break; case null: outValue = new LuaNull(); break; + default: _diagnostics.LogUnknownType(e.Span); break; diff --git a/Upsilon/Binder/BoundBinaryOperator.cs b/Upsilon/Binder/BoundBinaryOperator.cs index 783534d..64fdf4a 100644 --- a/Upsilon/Binder/BoundBinaryOperator.cs +++ b/Upsilon/Binder/BoundBinaryOperator.cs @@ -48,6 +48,15 @@ namespace Upsilon.Binder // Boolean equality new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean), new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean), + + // String operators + new BoundBinaryOperator(OperatorKind.Addition, Type.String, Type.String, Type.String), + new BoundBinaryOperator(OperatorKind.Addition, Type.String, Type.Number, Type.String), + new BoundBinaryOperator(OperatorKind.Addition, Type.String, Type.Boolean, Type.String), + + // String equality + new BoundBinaryOperator(OperatorKind.Equality, Type.String, Type.String, Type.Boolean), + new BoundBinaryOperator(OperatorKind.Inequality, Type.String, Type.String, Type.Boolean), }; public static BoundBinaryOperator Bind(SyntaxKind operatorToken, Type left, Type right) diff --git a/Upsilon/Evaluator/Evaluator.cs b/Upsilon/Evaluator/Evaluator.cs index 574a8ed..a72bfdb 100644 --- a/Upsilon/Evaluator/Evaluator.cs +++ b/Upsilon/Evaluator/Evaluator.cs @@ -163,7 +163,13 @@ namespace Upsilon.Evaluator switch (e.Operator.Kind) { case BoundBinaryOperator.OperatorKind.Addition: - return ((Number)left) + ((Number)right); + if (left.Type == Type.Number) + return ((Number)left) + ((Number)right); + else if (left.Type == Type.String) + { + return ((LuaString) left) + right; + } + goto default; case BoundBinaryOperator.OperatorKind.Subtraction: return ((Number)left) - ((Number)right); case BoundBinaryOperator.OperatorKind.Multiplication: diff --git a/Upsilon/Parser/Lexer.cs b/Upsilon/Parser/Lexer.cs index 4771520..77e45de 100644 --- a/Upsilon/Parser/Lexer.cs +++ b/Upsilon/Parser/Lexer.cs @@ -84,6 +84,8 @@ namespace Upsilon.Parser return new SyntaxToken(SyntaxKind.CloseParenthesis, _position, ")", null); case ',': return new SyntaxToken(SyntaxKind.Comma, _position, ",", null); + case '"': + return LexString(); case '=': if (Next == '=') { @@ -135,6 +137,24 @@ namespace Upsilon.Parser return new SyntaxToken(SyntaxKind.Number, start, numStr.ToString(), o); } + private SyntaxToken LexString() + { + var start = _position; + var sb = new StringBuilder(); + while (true) + { + _position++; + if (Current == '"') + break; + sb.Append(Current); + } + + _position++; + + var res = sb.ToString(); + return new SyntaxToken(SyntaxKind.String, start, $"\"{res}\"", res); + } + private SyntaxToken LexIdentifierOrKeyword() { var start = _position; diff --git a/Upsilon/Parser/Parser.cs b/Upsilon/Parser/Parser.cs index b0fbb70..52090b7 100644 --- a/Upsilon/Parser/Parser.cs +++ b/Upsilon/Parser/Parser.cs @@ -223,6 +223,8 @@ namespace Upsilon.Parser case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: return ParseBoolean(); + case SyntaxKind.String: + return ParseString(); case SyntaxKind.Identifier: if (Next.Kind == SyntaxKind.OpenParenthesis) return ParseFunctionCallExpression(); @@ -277,5 +279,10 @@ namespace Upsilon.Parser return new LiteralExpressionSyntax(token, isTrue); } + private ExpressionSyntax ParseString() + { + var stringToken = MatchToken(SyntaxKind.String); + return new LiteralExpressionSyntax(stringToken, stringToken.Value); + } } } \ No newline at end of file diff --git a/Upsilon/Parser/SyntaxKind.cs b/Upsilon/Parser/SyntaxKind.cs index bd6d7ff..4485b84 100644 --- a/Upsilon/Parser/SyntaxKind.cs +++ b/Upsilon/Parser/SyntaxKind.cs @@ -20,6 +20,7 @@ namespace Upsilon.Parser Tilde, TildeEquals, Comma, + String, // key words TrueKeyword,