private static void TryReadDigit(TokenizerContext context, List <StyleToken> output) { if (context.IsConsumed()) { return; } bool foundDot = false; int startIndex = context.ptr; context.Save(); if (context.input[context.ptr] == '-') { context.Advance(); } if (!char.IsDigit(context.input[context.ptr])) { context.Restore(); return; } // 1 // 1.4 // 1.4f while (context.HasMore() && (char.IsDigit(context.input[context.ptr]) || (!foundDot && context.input[context.ptr] == '.'))) { if (context.input[context.ptr] == '.') { foundDot = true; } context.Advance(); } int length = context.ptr - startIndex; string digit = context.input.Substring(startIndex, length); context.Restore(); output.Add(new StyleToken(StyleTokenType.Number, digit, context.line, context.column)); context.Advance(length); // a trailing f should be considered part of a float, except the f is followed by more characters like in a unit '2fr' // we don't want it to appear in the value, though. If it's ever used to differentiate something we should add a // more specific type like StyleTokenType.Float? Also what about 'm' and 'd' postfixes? if (context.HasMore() && context.input[context.ptr] == 'f' && context.HasMuchMore(1) && !char.IsLetter(context.input[context.ptr + 1])) { context.Advance(); } TryConsumeWhiteSpace(context); }
private static void TryConsumeComment(TokenizerContext context) { if (context.ptr + 1 >= context.input.Length) { return; } if (!(context.input[context.ptr] == '/' && context.input[context.ptr + 1] == '/')) { return; } while (context.HasMore()) { char current = context.input[context.ptr]; if (current == '\n') { TryConsumeWhiteSpace(context); TryConsumeComment(context); return; } context.Advance(); } }
private static void TryReadString(TokenizerContext context, List <StyleToken> output) { if (context.IsConsumed()) { return; } if (context.input[context.ptr] != '"') { return; } int start = context.ptr; context.Save(); context.Advance(); while (context.HasMore() && context.input[context.ptr] != '"') { context.Advance(); } if (context.IsConsumed()) { context.Restore(); return; } if (context.input[context.ptr] != '"') { context.Restore(); return; } context.Advance(); // strip the quotes // "abc" // 01234 int length = context.ptr - start; string substring = context.input.Substring(start + 1, length - 2); context.Restore(); output.Add(new StyleToken(StyleTokenType.String, substring, context.line, context.column)); context.Advance(length); TryConsumeWhiteSpace(context); }
private static void TryConsumeWhiteSpace(TokenizerContext context) { if (context.IsConsumed()) { return; } while (context.HasMore() && char.IsWhiteSpace(context.input[context.ptr])) { context.Advance(); } }
private static void TryReadValue(TokenizerContext context, List <StyleToken> output) { if (context.IsConsumed()) { return; } if (context.input[context.ptr] != '=') { return; } context.Save(); context.Advance(); TryConsumeWhiteSpace(context); int start = context.ptr; while (context.HasMore() && context.input[context.ptr] != ';' && context.input[context.ptr] != '\n') { if (context.input[context.ptr] == '/' && context.ptr + 1 < context.input.Length && context.input[context.ptr + 1] == '/') { break; } context.Advance(); } if (context.IsConsumed()) { context.Restore(); return; } string value = context.input.Substring(start, context.ptr - start); output.Add(new StyleToken(StyleTokenType.Value, value, context.line, context.column)); TryConsumeWhiteSpace(context); }
private static void TryReadIdentifier(TokenizerContext context, List <StyleToken> output) { if (context.IsConsumed()) { return; } int start = context.ptr; char first = context.input[context.ptr]; if (!char.IsLetter(first) && first != '_' && first != '$') { return; } context.Save(); while (context.HasMore()) { char character = context.input[context.ptr]; if (!(char.IsLetterOrDigit(character) || character == '_' || character == '-' || character == '$')) { break; } context.Advance(); } int length = context.ptr - start; string identifier = context.input.Substring(start, length); context.Restore(); output.Add(TransformIdentifierToTokenType(context, identifier)); context.Advance(length); TryConsumeWhiteSpace(context); }
private static void TryReadCharacters(TokenizerContext context, string match, StyleTokenType styleTokenType, List <StyleToken> output) { if (context.ptr + match.Length > context.input.Length) { return; } for (int i = 0; i < match.Length; i++) { if (context.input[context.ptr + i] != match[i]) { return; } } output.Add(new StyleToken(styleTokenType, match, context.line, context.column)); TryConsumeWhiteSpace(context.Advance(match.Length)); }
private static void TryConsumeWhiteSpace(TokenizerContext context) { if (context.IsConsumed()) { return; } while (context.ptr < context.input.Length) { char c = context.input[context.ptr]; if (!(c == ' ' || c >= '\t' && c <= '\r' || (c == ' ' || c == '\x0085'))) { break; } context.Advance(); } }
private static void TryReadCharacterSequence(TokenizerContext context, string match1, string match2, ExpressionTokenType expressionTokenType, StructList <ExpressionToken> output) { if (context.ptr + match1.Length > context.input.Length) { return; } int ptr = context.ptr; for (int i = 0; i < match1.Length; i++) { if (context.input[ptr++] != match1[i]) { return; } } while (ptr < context.input.Length) { if (char.IsWhiteSpace(context.input[ptr])) { ptr++; } else { break; } } for (int i = 0; i < match2.Length; i++) { if (context.input[ptr++] != match2[i]) { return; } } output.Add(new ExpressionToken(expressionTokenType, match1 + " " + match2, context.line, context.column)); TryConsumeWhiteSpace(context.Advance(ptr - context.ptr)); }
private static void TryReadHashColor(TokenizerContext context, List <StyleToken> output) { if (context.IsConsumed()) { return; } if (context.input[context.ptr] != '#') { return; } int start = context.ptr; while (context.HasMore() && context.input[context.ptr] != ';' && !char.IsWhiteSpace(context.input[context.ptr])) { context.Advance(); } string colorHash = context.input.Substring(start, context.ptr - start); output.Add(new StyleToken(StyleTokenType.HashColor, colorHash, context.line, context.column)); TryConsumeWhiteSpace(context); }
private static void TryReadDigit(TokenizerContext context, StructList <ExpressionToken> output) { if (context.IsConsumed()) { return; } bool foundDot = false; int startIndex = context.ptr; context.Save(); if (context.input[context.ptr] == '-') { context.Advance(); } if (!char.IsDigit(context.input[context.ptr])) { context.Restore(); return; } while (context.HasMore() && (char.IsDigit(context.input[context.ptr]) || (!foundDot && context.input[context.ptr] == '.'))) { if (context.input[context.ptr] == '.') { foundDot = true; } context.Advance(); } if (context.HasMore()) { char next = context.input[context.ptr]; // todo -- enable the below to making parsing numbers better in the compiler (since we already know what type to try to parse it as) //ExpressionTokenType type = ExpressionTokenType.Number; // if (next == 'f') { // type = ExpressionTokenType.Number_Float; // } // // if (next == 'd') { // type = ExpressionTokenType.Number_Double; // } // // if (next == 'l') { // type = ExpressionTokenType.Number_Long; // } // // if (next == 'u') { // // todo -- check for ul here // type = ExpressionTokenType.Number_UInt; // } // // if (next == 'm') { // type = ExpressionTokenType.Number_Decimal; // } if (next == 'f' || next == 'd' || next == 'l' || next == 'u' || next == 'm') { if (next != '.') { context.Advance(); } } } // if (context.HasMore() // && context.input[context.ptr] == 'f' // && context.input[context.ptr - 1] != '.') { // context.Advance(); // } int length = context.ptr - startIndex; string digit = context.input.Substring(startIndex, length); context.Restore(); output.Add(new ExpressionToken(ExpressionTokenType.Number, digit, context.line, context.column)); context.Advance(length); TryConsumeWhiteSpace(context); }