160 lines
7.0 KiB
C#
160 lines
7.0 KiB
C#
using System;
|
|
using System.Linq;
|
|
using Upsilon.Parser;
|
|
using Type = Upsilon.BaseTypes.Type;
|
|
|
|
namespace Upsilon.Binder
|
|
{
|
|
public class BoundBinaryOperator
|
|
{
|
|
public enum OperatorKind
|
|
{
|
|
Addition, Subtraction, Multiplication, Division, Equality, Inequality,
|
|
GreaterEquals,
|
|
Greater,
|
|
LessEquals,
|
|
Less,
|
|
And,
|
|
Or,
|
|
Exponent,
|
|
Remainder
|
|
}
|
|
|
|
private Type LeftType { get; }
|
|
private Type RightType { get; }
|
|
public Type OutType { get; }
|
|
public OperatorKind Kind { get; }
|
|
|
|
private BoundBinaryOperator(OperatorKind kind, Type outType)
|
|
{
|
|
Kind = kind;
|
|
LeftType = outType;
|
|
RightType = outType;
|
|
OutType = outType;
|
|
}
|
|
|
|
private BoundBinaryOperator(OperatorKind kind, Type leftType, Type rightType, Type outType)
|
|
{
|
|
Kind = kind;
|
|
LeftType = leftType;
|
|
RightType = rightType;
|
|
OutType = outType;
|
|
}
|
|
|
|
private static readonly BoundBinaryOperator[] Operators = {
|
|
// Math operators
|
|
new BoundBinaryOperator(OperatorKind.Addition, Type.Number),
|
|
new BoundBinaryOperator(OperatorKind.Subtraction, Type.Number),
|
|
new BoundBinaryOperator(OperatorKind.Multiplication, Type.Number),
|
|
new BoundBinaryOperator(OperatorKind.Division, Type.Number),
|
|
new BoundBinaryOperator(OperatorKind.Exponent, Type.Number),
|
|
new BoundBinaryOperator(OperatorKind.Remainder, Type.Number),
|
|
|
|
// Number equality
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Number, Type.Number, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Number, Type.Number, Type.Boolean),
|
|
|
|
// Number comparison
|
|
new BoundBinaryOperator(OperatorKind.Less, Type.Number, Type.Number, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.LessEquals, Type.Number, Type.Number, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Greater, Type.Number, Type.Number, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.GreaterEquals, Type.Number, Type.Number, Type.Boolean),
|
|
|
|
// Boolean equality
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean),
|
|
|
|
// Boolean chaining
|
|
new BoundBinaryOperator(OperatorKind.And, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Or, 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),
|
|
|
|
// general nil checks
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.String, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.String, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.UserData, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.UserData, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Table, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Table, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Boolean, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Boolean, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.Unknown, Type.Nil, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.Unknown, Type.Nil, Type.Boolean),
|
|
|
|
// Userdata equality
|
|
new BoundBinaryOperator(OperatorKind.Equality, Type.UserData, Type.UserData, Type.Boolean),
|
|
new BoundBinaryOperator(OperatorKind.Inequality, Type.UserData, Type.UserData, Type.Boolean),
|
|
};
|
|
|
|
public static BoundBinaryOperator Bind(SyntaxKind operatorToken, Type left, Type right)
|
|
{
|
|
if (left == Type.UserData) left = Type.Unknown;
|
|
if (right == Type.UserData) right = Type.Unknown;
|
|
OperatorKind kind;
|
|
switch (operatorToken)
|
|
{
|
|
case SyntaxKind.Plus:
|
|
kind = OperatorKind.Addition;
|
|
break;
|
|
case SyntaxKind.Minus:
|
|
kind = OperatorKind.Subtraction;
|
|
break;
|
|
case SyntaxKind.Star:
|
|
kind = OperatorKind.Multiplication;
|
|
break;
|
|
case SyntaxKind.Slash:
|
|
kind = OperatorKind.Division;
|
|
break;
|
|
case SyntaxKind.PercentSign:
|
|
kind = OperatorKind.Remainder;
|
|
break;
|
|
case SyntaxKind.RoofSign:
|
|
kind = OperatorKind.Exponent;
|
|
break;
|
|
case SyntaxKind.EqualsEquals:
|
|
kind = OperatorKind.Equality;
|
|
break;
|
|
case SyntaxKind.TildeEquals:
|
|
kind = OperatorKind.Inequality;
|
|
break;
|
|
case SyntaxKind.Less:
|
|
kind = OperatorKind.Less;
|
|
break;
|
|
case SyntaxKind.LessEquals:
|
|
kind = OperatorKind.LessEquals;
|
|
break;
|
|
case SyntaxKind.Greater:
|
|
kind = OperatorKind.Greater;
|
|
break;
|
|
case SyntaxKind.GreaterEquals:
|
|
kind = OperatorKind.GreaterEquals;
|
|
break;
|
|
case SyntaxKind.AndKeyword:
|
|
kind = OperatorKind.And;
|
|
break;
|
|
case SyntaxKind.OrKeyword:
|
|
kind = OperatorKind.Or;
|
|
break;
|
|
default:
|
|
throw new Exception("Unknown binary operator token: " + operatorToken);
|
|
}
|
|
|
|
if (left == Type.Unknown && right == Type.Unknown)
|
|
return Operators.FirstOrDefault(op => op.Kind == kind);
|
|
if (left == Type.Unknown)
|
|
return Operators.FirstOrDefault(op => op.Kind == kind && op.RightType == right);
|
|
if (right == Type.Unknown)
|
|
return Operators.FirstOrDefault(op => op.Kind == kind && op.LeftType == left);
|
|
|
|
return Operators.FirstOrDefault(op => op.Kind == kind && op.LeftType == left && op.RightType == right);
|
|
}
|
|
}
|
|
} |