306 lines
9.9 KiB
C#
306 lines
9.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Parser.Internal
|
|
{
|
|
public static class SyntaxFacts
|
|
{
|
|
public static readonly HashSet<string> Keywords;
|
|
|
|
static SyntaxFacts()
|
|
{
|
|
Keywords = new HashSet<string>
|
|
{
|
|
"for", "if", "function", "while", "case", "try", "catch", "end",
|
|
"switch", "classdef", "elseif", "persistent", "else"
|
|
};
|
|
}
|
|
|
|
public enum Precedence
|
|
{
|
|
// see https://mathworks.com/help/matlab/matlab_prog/operator-precedence.html
|
|
Expression = 0,
|
|
Assignment,
|
|
LogicalOr,
|
|
LogicalAnd,
|
|
BitwiseOr,
|
|
BitwiseAnd,
|
|
Relational,
|
|
Colon,
|
|
Additive,
|
|
Multiplicative,
|
|
Unary,
|
|
WeirdPower,
|
|
Power
|
|
}
|
|
|
|
public static Precedence GetPrecedence(TokenKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TokenKind.EqualsToken:
|
|
return Precedence.Assignment;
|
|
case TokenKind.PipePipeToken:
|
|
return Precedence.LogicalOr;
|
|
case TokenKind.AmpersandAmpersandToken:
|
|
return Precedence.LogicalAnd;
|
|
case TokenKind.PipeToken:
|
|
return Precedence.BitwiseOr;
|
|
case TokenKind.AmpersandToken:
|
|
return Precedence.BitwiseAnd;
|
|
case TokenKind.LessToken:
|
|
case TokenKind.LessOrEqualsToken:
|
|
case TokenKind.GreaterToken:
|
|
case TokenKind.GreaterOrEqualsToken:
|
|
case TokenKind.EqualsEqualsToken:
|
|
case TokenKind.TildeEqualsToken:
|
|
return Precedence.Relational;
|
|
case TokenKind.ColonToken:
|
|
return Precedence.Colon;
|
|
case TokenKind.PlusToken:
|
|
case TokenKind.MinusToken:
|
|
return Precedence.Additive;
|
|
case TokenKind.StarToken:
|
|
case TokenKind.DotStarToken:
|
|
case TokenKind.SlashToken:
|
|
case TokenKind.DotSlashToken:
|
|
case TokenKind.BackslashToken:
|
|
case TokenKind.DotBackslashToken:
|
|
return Precedence.Multiplicative;
|
|
case TokenKind.TildeToken:
|
|
return Precedence.Unary;
|
|
case TokenKind.CaretToken:
|
|
case TokenKind.DotCaretToken:
|
|
case TokenKind.ApostropheToken:
|
|
case TokenKind.DotApostropheToken:
|
|
return Precedence.Power;
|
|
default:
|
|
return Precedence.Expression;
|
|
}
|
|
}
|
|
|
|
public static bool IsDigit(char c)
|
|
{
|
|
return c >= '0' && c <= '9';
|
|
}
|
|
|
|
public static bool IsDigitOrDot(char c)
|
|
{
|
|
return c == '.' || (c >= '0' && c <= '9');
|
|
}
|
|
|
|
public static bool IsEolOrEof(char c)
|
|
{
|
|
return c == '\n' || c == '\r' || c == '\0';
|
|
}
|
|
|
|
public static bool IsEof(char c)
|
|
{
|
|
return c == '\0';
|
|
}
|
|
|
|
public static bool IsEol(char c)
|
|
{
|
|
return c == '\n' || c == '\r';
|
|
}
|
|
|
|
public static bool IsWhitespace(char c)
|
|
{
|
|
return c == ' ' || c == '\t' || c == '\n';
|
|
}
|
|
|
|
public static bool IsOpeningToken(TokenKind tokenKind)
|
|
{
|
|
switch (tokenKind)
|
|
{
|
|
case TokenKind.OpenBraceToken:
|
|
case TokenKind.OpenParenthesisToken:
|
|
case TokenKind.OpenSquareBracketToken:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsClosingToken(TokenKind tokenKind)
|
|
{
|
|
switch (tokenKind)
|
|
{
|
|
case TokenKind.CloseBraceToken:
|
|
case TokenKind.CloseParenthesisToken:
|
|
case TokenKind.CloseSquareBracketToken:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsBracket(TokenKind tokenKind)
|
|
{
|
|
return IsOpeningToken(tokenKind) || IsClosingToken(tokenKind);
|
|
}
|
|
|
|
public static TokenKind? OpeningFromClosing(TokenKind tokenKind)
|
|
{
|
|
switch (tokenKind)
|
|
{
|
|
case TokenKind.CloseBraceToken:
|
|
return TokenKind.OpenBraceToken;
|
|
case TokenKind.CloseParenthesisToken:
|
|
return TokenKind.OpenParenthesisToken;
|
|
case TokenKind.CloseSquareBracketToken:
|
|
return TokenKind.OpenSquareBracketToken;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static readonly string?[] StringFromKind =
|
|
{
|
|
null, // None = 0,
|
|
null, // BadToken = 1,
|
|
null, // EndOfFile = 2,
|
|
null, // Identifier = 3,
|
|
null, // NumberLiteral = 4,
|
|
null, // StringLiteral = 5,
|
|
null, // DoubleQuotedStringLiteral = 6,
|
|
null, // UnquotedStringLiteral = 7
|
|
null, null, null, null, null, null, null, null, null, null, null, null,
|
|
"=", // Assignment = 20,
|
|
"==", // Equality = 21,
|
|
"~=", // Inequality = 22,
|
|
"&&", // LogicalAnd = 23,
|
|
"||", // LogicalOr = 24,
|
|
"&", // BitwiseAnd = 25,
|
|
"|", // BitwiseOr = 26,
|
|
"<", // Less = 27,
|
|
"<=", // LessOrEqual = 28,
|
|
">", // Greater = 29,
|
|
">=", // GreaterOrEqual = 30,
|
|
"~", // Not = 31,
|
|
"+", // Plus = 32,
|
|
"-", // Minus = 33,
|
|
"*", // Multiply = 34,
|
|
"/", // Divide = 35,
|
|
"^", // Power = 36,
|
|
"\\", // Backslash = 37,
|
|
"'", // Transpose = 38,
|
|
".*", // DotMultiply = 39,
|
|
"./", // DotDivide = 40,
|
|
".^", // DotPower = 41,
|
|
".\\", // DotBackslash = 42,
|
|
".'", // DotTranspose = 43,
|
|
"@", // At = 44,
|
|
":", // Colon = 45,
|
|
"?", // QuestionMark = 46,
|
|
",", // Comma = 47,
|
|
";", // Semicolon = 48,
|
|
"{", // OpeningBrace = 49,
|
|
"}", // ClosingBrace = 50,
|
|
"[", // OpeningSquareBracket = 51,
|
|
"]", // ClosingSquareBracket = 52,
|
|
"(", // OpeningBracket = 53,
|
|
")", // ClosingBracket = 54,
|
|
".", // Dot = 55,
|
|
null, // DotDotDot = 56, // This is not used at the moment.
|
|
|
|
"+", // UnaryPlus = 57,
|
|
"-", // UnaryMinus = 58,
|
|
"~", // UnaryNot = 59,
|
|
"?", // UnaryQuestionMark = 60,
|
|
};
|
|
|
|
public static string? GetText(TokenKind kind)
|
|
{
|
|
if ((int) kind < (int) TokenKind.File)
|
|
{
|
|
return StringFromKind[(int) kind];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static bool IsUnaryOperator(TokenKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TokenKind.PlusToken:
|
|
case TokenKind.MinusToken:
|
|
case TokenKind.TildeToken:
|
|
case TokenKind.QuestionToken:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsUnaryTokenKind(TokenKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TokenKind.UnaryPlus:
|
|
case TokenKind.UnaryMinus:
|
|
case TokenKind.UnaryNot:
|
|
case TokenKind.UnaryQuestionMark:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsBinaryOperator(TokenKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TokenKind.EqualsToken:
|
|
case TokenKind.PipePipeToken:
|
|
case TokenKind.AmpersandAmpersandToken:
|
|
case TokenKind.PipeToken:
|
|
case TokenKind.AmpersandToken:
|
|
case TokenKind.LessToken:
|
|
case TokenKind.LessOrEqualsToken:
|
|
case TokenKind.GreaterToken:
|
|
case TokenKind.GreaterOrEqualsToken:
|
|
case TokenKind.EqualsEqualsToken:
|
|
case TokenKind.TildeEqualsToken:
|
|
case TokenKind.ColonToken:
|
|
case TokenKind.PlusToken:
|
|
case TokenKind.MinusToken:
|
|
case TokenKind.StarToken:
|
|
case TokenKind.DotStarToken:
|
|
case TokenKind.SlashToken:
|
|
case TokenKind.DotSlashToken:
|
|
case TokenKind.BackslashToken:
|
|
case TokenKind.DotBackslashToken:
|
|
case TokenKind.TildeToken:
|
|
case TokenKind.CaretToken:
|
|
case TokenKind.DotCaretToken:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool IsLeftAssociative(TokenKind kind)
|
|
{
|
|
return true; // TODO: really?
|
|
}
|
|
|
|
public static TokenKind ConvertToUnaryTokenKind(TokenKind kind)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TokenKind.PlusToken:
|
|
return TokenKind.UnaryPlus;
|
|
case TokenKind.MinusToken:
|
|
return TokenKind.UnaryMinus;
|
|
case TokenKind.TildeToken:
|
|
return TokenKind.UnaryNot;
|
|
case TokenKind.QuestionToken:
|
|
return TokenKind.UnaryQuestionMark;
|
|
default:
|
|
throw new ArgumentException(nameof(kind));
|
|
}
|
|
}
|
|
}
|
|
} |