public override IMatched <Unit> Parse(ParseState state, Token[] tokens, ExpressionBuilder builder) { var type = AlternateStringType.Standard; switch (tokens[2].Text) { case "r": type = AlternateStringType.Raw; break; case "l": type = AlternateStringType.List; break; } state.Colorize(tokens, Color.Whitespace, Color.StringPart, Color.String); var stringBuilder = new StringBuilder(); var escaped = false; var start = state.Index; var length = 0; while (state.More) { var ch = state.CurrentSource[0]; switch (ch) { case '"': if (escaped) { stringBuilder.Append('"'); escaped = false; } else if (state.CurrentSource.Drop(1).StartsWith("\"")) { escaped = true; } else { state.Move(1); state.AddToken(start, length + 1, Color.String); if (type == AlternateStringType.List) { builder.Add(new StringListSymbol(stringBuilder.ToString())); } else { builder.Add(new StringSymbol(stringBuilder.ToString())); } return(Unit.Matched()); } break; default: stringBuilder.Append(ch); escaped = false; break; } length++; state.Move(1); } return(failedMatch <Unit>(openString())); }
public override IMatched <Unit> Parse(ParseState state, Token[] tokens, ExpressionBuilder builder) { state.Colorize(tokens, Color.Whitespace, Color.Structure); var pattern = new StringBuilder(); var type = RegexParsingType.Outside; var ignoreCase = false; var multiline = false; var global = false; var textOnly = false; while (state.More) { var ch = state.CurrentSource[0]; switch (type) { case RegexParsingType.Outside: switch (ch) { case '\\': state.AddToken(Color.Structure); state.Move(1); builder.Add(new RegexSymbol(pattern.ToString(), ignoreCase, multiline, global, textOnly)); return(Unit.Matched()); case '\'': type = RegexParsingType.WaitingForSingleQuote; pattern.Append(ch); state.AddToken(Color.String); break; case '"': type = RegexParsingType.WaitingForDoubleQuote; pattern.Append(ch); state.AddToken(Color.String); break; case ';': type = RegexParsingType.AwaitingOption; state.AddToken(Color.Structure); break; default: pattern.Append(ch); var color = Color.Operator; switch (ch) { case '{': case '}': case '>': case '<': case '[': case ']': case ',': case '|': case '(': case ')': color = Color.Structure; break; default: if (char.IsNumber(ch)) { color = Color.Number; } else if (char.IsLetter(ch)) { color = Color.Identifier; } break; } state.AddToken(color); break; } break; case RegexParsingType.WaitingForSingleQuote: switch (ch) { case '\'': type = RegexParsingType.Outside; break; case '\\': type = RegexParsingType.EscapedSingleQuote; break; } pattern.Append(ch); state.AddToken(Color.String); break; case RegexParsingType.WaitingForDoubleQuote: switch (ch) { case '"': type = RegexParsingType.Outside; break; case '\\': type = RegexParsingType.EscapedDoubleQuote; break; } pattern.Append(ch); state.AddToken(Color.String); break; case RegexParsingType.EscapedSingleQuote: type = RegexParsingType.WaitingForSingleQuote; pattern.Append(ch); state.AddToken(Color.String); break; case RegexParsingType.EscapedDoubleQuote: type = RegexParsingType.WaitingForDoubleQuote; pattern.Append(ch); state.AddToken(Color.String); break; case RegexParsingType.AwaitingOption: switch (ch) { case 'i': case 'I': ignoreCase = true; break; case 'm': case 'M': multiline = true; break; case 'g': case 'G': global = true; break; case 't': case 'T': textOnly = true; break; case '\\': state.AddToken(Color.Structure); state.Move(1); builder.Add(new RegexSymbol(pattern.ToString(), ignoreCase, multiline, global, textOnly)); return(Unit.Matched()); default: return($"Didn't understand option '{ch}'".FailedMatch <Unit>()); } state.AddToken(Color.Symbol); break; } state.Move(1); } return("Open regex".FailedMatch <Unit>()); }
public override IMatched <Unit> Parse(ParseState state, Token[] tokens, ExpressionBuilder builder) { var prefix = tokens[2].Text; var mutable = prefix == "m"; var binary = prefix == "b"; var symbol = prefix == "`"; state.Colorize(tokens, Color.Whitespace, Color.StringPart, Color.String); var text = new StringBuilder(); var escaped = false; var index = state.Index; var length = 0; var hex = false; var hexText = new StringBuilder(); while (state.More) { var ch = state.CurrentSource[0]; switch (ch) { case '"': if (escaped) { text.Append('"'); escaped = false; break; } if (hex) { if (fromHex(hexText.ToString()).If(out var matchedChar, out var anyException)) { text.Append(matchedChar); } else if (anyException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(badHex(hexText.ToString()))); } } state.Move(1); state.AddToken(index, length + 1, Color.String); if (mutable) { builder.Add(new MutStringSymbol(text.ToString())); return(Unit.Matched()); } else if (binary) { builder.Add(new ByteArraySymbol(text.ToString())); return(Unit.Matched()); } else if (symbol) { builder.Add(new SymbolSymbol(text.ToString())); return(Unit.Matched()); } else { builder.Add(new StringSymbol(text.ToString())); return(Unit.Matched()); } case '\\': if (escaped) { text.Append('\\'); escaped = false; break; } escaped = true; break; case 'n': if (escaped) { text.Append('\n'); escaped = false; break; } text.Append('n'); break; case 'r': if (escaped) { text.Append('\r'); escaped = false; break; } text.Append('r'); break; case 't': if (escaped) { text.Append('\t'); escaped = false; break; } text.Append('t'); break; case 'u': if (escaped) { hex = true; hexText.Clear(); escaped = false; break; } text.Append('u'); break; case '{': if (escaped) { hex = true; hexText.Clear(); escaped = false; break; } text.Append('{'); break; default: if (hex) { if (ch.Between('0').And('9') || ch.Between('a').And('f') && hexText.Length < 6) { hexText.Append(ch); } else { hex = false; if (fromHex(hexText.ToString()).ValueOrCast <Unit>(out var matchedChar, out var asUnit)) { text.Append(matchedChar); } else if (asUnit.IsFailedMatch) { return(asUnit); } if (ch == 96) { text.Append(ch); } } } else { text.Append(ch); } escaped = false; break; } length++; state.Move(1); } return(failedMatch <Unit>(openString())); }
public override IMatched <Unit> Parse(ParseState state, Token[] tokens, ExpressionBuilder builder) { var isFailure = tokens[2].Text == "f"; state.Colorize(tokens, Color.Whitespace, Color.StringPart, Color.String); var firstString = none <string>(); var expressions = new List <Expression>(); var suffixes = new List <string>(); var text = new StringBuilder(); var escaped = false; var index = state.Index; var length = 0; var hex = false; var hexText = new StringBuilder(); while (state.More) { var ch = state.CurrentSource[0]; switch (ch) { case '"': { if (escaped) { text.Append('"'); escaped = false; break; } if (hex) { if (fromHex(hexText.ToString()).If(out var matchedChar, out var anyException)) { text.Append(matchedChar); } else if (anyException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(badHex(hexText.ToString()))); } } state.Move(1); state.AddToken(index, length + 1, Color.String); var symbol = firstString.Map(prefix => { suffixes.Add(text.ToString()); var expressionsArray = expressions.ToArray(); var suffixesArray = suffixes.ToArray(); return((Symbol) new InterpolatedStringSymbol(prefix, expressionsArray, suffixesArray, isFailure)); }).DefaultTo(() => new StringSymbol(text.ToString(), isFailure)); builder.Add(symbol); return(Unit.Matched()); } case '(': { if (escaped) { text.Append('('); escaped = false; break; } state.Move(1); state.AddToken(index, length, Color.String); state.AddToken(index + length, 1, Color.OpenParenthesis); if (firstString.IsNone) { firstString = text.ToString().Some(); } else { suffixes.Add(text.ToString()); } text.Clear(); if (getExpression(state, "^ /')'", builder.Flags, Color.CloseParenthesis) .If(out var expression, out var anyException)) { expressions.Add(expression); index = state.Index; length = 0; continue; } else if (anyException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(expectedExpression())); } } case '\\': if (escaped) { text.Append('\\'); escaped = false; break; } escaped = true; break; case 'n': if (escaped) { text.Append('\n'); escaped = false; break; } text.Append('n'); break; case 'r': if (escaped) { text.Append('\r'); escaped = false; break; } text.Append('r'); break; case 't': if (escaped) { text.Append('\t'); escaped = false; break; } text.Append('t'); break; case 'u': if (escaped) { hex = true; hexText.Clear(); escaped = false; break; } text.Append('u'); break; default: { if (escaped) { if (ch.Between('0').And('9') || ch.Between('a').And('f') && hexText.Length < 6) { hexText.Append(ch); } else { escaped = false; if (fromHex(hexText.ToString()).If(out var charMatched, out var anyException)) { hexText.Append(charMatched); hexText.Append(ch); } else if (anyException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(badHex(hexText.ToString()))); } } } else { text.Append(ch); } escaped = false; } break; } length++; state.Move(1); } return(failedMatch <Unit>(openString())); }
public override IMatched <Unit> Parse(ParseState state, Token[] tokens, ExpressionBuilder builder) { state.Colorize(tokens, Color.Whitespace, Color.String, Color.String); var text = new StringBuilder(); var escaped = false; var index = state.Index; var length = 0; var hex = false; var hexText = new StringBuilder(); while (state.More && !state.CurrentSource.IsMatch("^ (/r /n | /r | /n) [dquote]3")) { var ch = state.CurrentSource[0]; switch (ch) { case '\\': if (escaped) { text.Append('\\'); escaped = false; break; } escaped = true; break; case 'n': if (escaped) { text.Append('\n'); escaped = false; break; } text.Append('n'); break; case 'r': if (escaped) { text.Append('\r'); escaped = false; break; } text.Append('r'); break; case 't': if (escaped) { text.Append('\t'); escaped = false; break; } text.Append('t'); break; case 'u': if (escaped) { hex = true; hexText.Clear(); escaped = false; break; } text.Append('u'); break; case '{': if (escaped) { hex = true; hexText.Clear(); escaped = false; break; } text.Append('{'); break; default: if (hex) { if (ch.Between('0').And('9') || ch.Between('a').And('f') && hexText.Length < 6) { hexText.Append(ch); } else { hex = false; if (fromHex(hexText.ToString()).ValueOrCast <Unit>(out var matchedChar, out var asUnit)) { text.Append(matchedChar); } else if (asUnit.IsFailedMatch) { return(asUnit); } if (ch == 96) { text.Append(ch); } } } else { text.Append(ch); } escaped = false; break; } length++; state.Move(1); } if (state.Scan("^ /(/r /n | /r | /n) /([dquote]3)", Color.Whitespace, Color.String).If(out _, out var anyMatchException)) { if (hex) { if (fromHex(hexText.ToString()).If(out var matchedChar, out var anyException)) { text.Append(matchedChar); } else if (anyException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(badHex(hexText.ToString()))); } } state.Move(1); state.AddToken(index, length + 1, Color.String); builder.Add(new StringSymbol(text.ToString())); return(Unit.Matched()); } else if (anyMatchException.If(out var exception)) { return(failedMatch <Unit>(exception)); } else { return(failedMatch <Unit>(openString())); } }