using System; using System.Collections.Generic; namespace Parser.Internal { public static class SyntaxFacts { public static readonly HashSet Keywords; static SyntaxFacts() { Keywords = new HashSet { "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.Assignment: return Precedence.Assignment; case TokenKind.LogicalOr: return Precedence.LogicalOr; case TokenKind.LogicalAnd: return Precedence.LogicalAnd; case TokenKind.BitwiseOr: return Precedence.BitwiseOr; case TokenKind.BitwiseAnd: return Precedence.BitwiseAnd; case TokenKind.Less: case TokenKind.LessOrEqual: case TokenKind.Greater: case TokenKind.GreaterOrEqual: case TokenKind.Equality: case TokenKind.Inequality: return Precedence.Relational; case TokenKind.Colon: return Precedence.Colon; case TokenKind.Plus: case TokenKind.Minus: return Precedence.Additive; case TokenKind.Multiply: case TokenKind.DotMultiply: case TokenKind.Divide: case TokenKind.DotDivide: case TokenKind.Backslash: case TokenKind.DotBackslash: return Precedence.Multiplicative; case TokenKind.Not: return Precedence.Unary; case TokenKind.Power: case TokenKind.DotPower: case TokenKind.Transpose: case TokenKind.DotTranspose: 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.OpeningBrace: case TokenKind.OpeningBracket: case TokenKind.OpeningSquareBracket: return true; default: return false; } } public static bool IsClosingToken(TokenKind tokenKind) { switch (tokenKind) { case TokenKind.ClosingBrace: case TokenKind.ClosingBracket: case TokenKind.ClosingSquareBracket: 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.ClosingBrace: return TokenKind.OpeningBrace; case TokenKind.ClosingBracket: return TokenKind.OpeningBracket; case TokenKind.ClosingSquareBracket: return TokenKind.OpeningSquareBracket; 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.Plus: case TokenKind.Minus: case TokenKind.Not: case TokenKind.QuestionMark: 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.Assignment: case TokenKind.LogicalOr: case TokenKind.LogicalAnd: case TokenKind.BitwiseOr: case TokenKind.BitwiseAnd: case TokenKind.Less: case TokenKind.LessOrEqual: case TokenKind.Greater: case TokenKind.GreaterOrEqual: case TokenKind.Equality: case TokenKind.Inequality: case TokenKind.Colon: case TokenKind.Plus: case TokenKind.Minus: case TokenKind.Multiply: case TokenKind.DotMultiply: case TokenKind.Divide: case TokenKind.DotDivide: case TokenKind.Backslash: case TokenKind.DotBackslash: case TokenKind.Not: case TokenKind.Power: case TokenKind.DotPower: 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.Plus: return TokenKind.UnaryPlus; case TokenKind.Minus: return TokenKind.UnaryMinus; case TokenKind.Not: return TokenKind.UnaryNot; case TokenKind.QuestionMark: return TokenKind.UnaryQuestionMark; default: throw new ArgumentException(nameof(kind)); } } } }