Ast.ComplexNumberNode ParseComplex(SeekableStringReader sr) { //complex = complextuple | imaginary . //imaginary = ['+' | '-' ] ( float | int ) 'j' . //complextuple = '(' ( float | int ) imaginary ')' . if (sr.Peek() == '(') { // complextuple sr.Read(); // ( string numberstr; if (sr.Peek() == '-' || sr.Peek() == '+') { // starts with a sign, read that first otherwise the readuntil will return immediately numberstr = sr.Read(1) + sr.ReadUntil(new char[] { '+', '-' }); } else { numberstr = sr.ReadUntil(new char[] { '+', '-' }); } double realpart; try { realpart = double.Parse(numberstr, CultureInfo.InvariantCulture); } catch (FormatException x) { throw new ParseException("invalid float format", x); } sr.Rewind(1); // rewind the +/- double imaginarypart = ParseImaginaryPart(sr); if (sr.Read() != ')') { throw new ParseException("expected ) to end a complex number"); } return(new Ast.ComplexNumberNode() { Real = realpart, Imaginary = imaginarypart }); } else { // imaginary double imag = ParseImaginaryPart(sr); return(new Ast.ComplexNumberNode() { Real = 0, Imaginary = imag }); } }
Ast.TupleNode ParseTuple(SeekableStringReader sr) { //tuple = tuple_empty | tuple_one | tuple_more //tuple_empty = '()' . //tuple_one = '(' expr ',' <whitespace> ')' . //tuple_more = '(' expr_list ')' . sr.Read(); // ( sr.SkipWhitespace(); Ast.TupleNode tuple = new Ast.TupleNode(); if (sr.Peek() == ')') { sr.Read(); return(tuple); // empty tuple } Ast.INode firstelement = ParseExpr(sr); if (sr.Peek() == ',') { sr.Read(); sr.SkipWhitespace(); if (sr.Read() == ')') { // tuple with just a single element tuple.Elements.Add(firstelement); return(tuple); } sr.Rewind(1); // undo the thing that wasn't a ) } tuple.Elements = ParseExprList(sr); tuple.Elements.Insert(0, firstelement); if (!sr.HasMore()) { throw new ParseException("missing ')'"); } char closechar = sr.Read(); if (closechar == ',') { closechar = sr.Read(); } if (closechar != ')') { throw new ParseException("expected ')'"); } return(tuple); }
public Ast.INode ParseSingle(SeekableStringReader sr) { // single = int | float | complex | string | bool | none . sr.SkipWhitespace(); switch (sr.Peek()) { case 'N': return(ParseNone(sr)); case 'T': case 'F': return(ParseBool(sr)); case '\'': case '"': return(ParseString(sr)); } // int or float or complex. int bookmark = sr.Bookmark(); try { return(ParseComplex(sr)); } catch (ParseException) { sr.FlipBack(bookmark); try { return(ParseFloat(sr)); } catch (ParseException) { sr.FlipBack(bookmark); return(ParseInt(sr)); } } }
Ast.ListNode ParseList(SeekableStringReader sr) { // list = list_empty | list_nonempty . // list_empty = '[]' . // list_nonempty = '[' expr_list ']' . sr.Read(); // [ sr.SkipWhitespace(); Ast.ListNode list = new Ast.ListNode(); if (sr.Peek() == ']') { sr.Read(); return(list); // empty list } list.Elements = ParseExprList(sr); if (!sr.HasMore()) { throw new ParseException("missing ']'"); } char closechar = sr.Read(); if (closechar != ']') { throw new ParseException("expected ']'"); } return(list); }
/// <summary> /// Parse from a string with the Python literal expression /// </summary> public Ast Parse(string expression) { Ast ast = new Ast(); if (string.IsNullOrEmpty(expression)) { return(ast); } SeekableStringReader sr = new SeekableStringReader(expression); if (sr.Peek() == '#') { sr.ReadUntil('\n'); // skip comment line } try { ast.Root = ParseExpr(sr); sr.SkipWhitespace(); if (sr.HasMore()) { throw new ParseException("garbage at end of expression"); } return(ast); } catch (ParseException x) { string faultLocation = ExtractFaultLocation(sr); throw new ParseException(x.Message + " (at position " + sr.Bookmark() + "; '" + faultLocation + "')", x); } }
private Ast.INode ParseCompound(SeekableStringReader sr) { // compound = tuple | dict | list | set . sr.SkipWhitespace(); switch (sr.Peek()) { case '[': return(ParseList(sr)); case '{': { int bm = sr.Bookmark(); try { return(ParseSet(sr)); } catch (ParseException) { sr.FlipBack(bm); return(ParseDict(sr)); } } case '(': // tricky case here, it can be a tuple but also a complex number: // if the last character before the closing parenthesis is a 'j', it is a complex number { int bm = sr.Bookmark(); string betweenparens = sr.ReadUntil(')', '\n').TrimEnd(); sr.FlipBack(bm); return(betweenparens.EndsWith("j") ? (Ast.INode)ParseComplex(sr) : ParseTuple(sr)); } default: throw new ParseException("invalid sequencetype char"); } }
List <Ast.INode> ParseKeyValueList(SeekableStringReader sr) { //keyvalue_list = keyvalue { ',' keyvalue } . List <Ast.INode> kvs = new List <Ast.INode>(); kvs.Add(ParseKeyValue(sr)); while (sr.HasMore() && sr.Peek() == ',') { sr.Read(); kvs.Add(ParseKeyValue(sr)); } return(kvs); }
List <Ast.INode> ParseExprList(SeekableStringReader sr) { //expr_list = expr { ',' expr } . List <Ast.INode> exprList = new List <Ast.INode>(); exprList.Add(ParseExpr(sr)); while (sr.HasMore() && sr.Peek() == ',') { sr.Read(); exprList.Add(ParseExpr(sr)); } return(exprList); }
private Ast.KeyValueNode ParseKeyValue(SeekableStringReader sr) { //keyvalue = expr ':' expr . Ast.INode key = ParseExpr(sr); if (!sr.HasMore() || sr.Peek() != ':') { throw new ParseException("expected ':'"); } sr.Read(); // : Ast.INode value = ParseExpr(sr); return(new Ast.KeyValueNode { Key = key, Value = value }); }
Ast.DictNode ParseDict(SeekableStringReader sr) { //dict = '{' keyvalue_list '}' . //keyvalue_list = keyvalue { ',' keyvalue } . //keyvalue = expr ':' expr . sr.Read(); // { sr.SkipWhitespace(); Ast.DictNode dict = new Ast.DictNode(); if (sr.Peek() == '}') { sr.Read(); return(dict); // empty dict } List <Ast.INode> elts = ParseKeyValueList(sr); if (!sr.HasMore()) { throw new ParseException("missing '}'"); } char closechar = sr.Read(); if (closechar != '}') { throw new ParseException("expected '}'"); } // make sure it has dict semantics (remove duplicate keys) Dictionary <Ast.INode, Ast.INode> fixedDict = new Dictionary <Ast.INode, Ast.INode>(elts.Count); foreach (Ast.KeyValueNode kv in elts) { fixedDict[kv.Key] = kv.Value; } foreach (var kv in fixedDict) { dict.Elements.Add(new Ast.KeyValueNode() { Key = kv.Key, Value = kv.Value }); } return(dict); }
List <Ast.INode> ParseKeyValueList(SeekableStringReader sr) { //keyvalue_list = keyvalue { ',' keyvalue } . List <Ast.INode> kvs = new List <Ast.INode>(); kvs.Add(ParseKeyValue(sr)); while (sr.HasMore() && sr.Peek() == ',') { sr.Read(); try { kvs.Add(ParseKeyValue(sr)); } catch (ParseException) { sr.Rewind(1); break; } } return(kvs); }
Ast.INode ParseExpr(SeekableStringReader sr) { // expr = [ <whitespace> ] single | compound [ <whitespace> ] . sr.SkipWhitespace(); char c = sr.Peek(); Ast.INode node; if (c == '{' || c == '[' || c == '(') { node = ParseCompound(sr); } else { node = ParseSingle(sr); } sr.SkipWhitespace(); return(node); }
List <Ast.INode> ParseExprList(SeekableStringReader sr) { //expr_list = expr { ',' expr } . List <Ast.INode> exprList = new List <Ast.INode>(); exprList.Add(ParseExpr(sr)); while (sr.HasMore() && sr.Peek() == ',') { sr.Read(); try { exprList.Add(ParseExpr(sr)); } catch (ParseException) { sr.Rewind(1); break; } } return(exprList); }
private Ast.INode ParseExpr(SeekableStringReader sr) { // expr = [ <whitespace> ] single | compound [ <whitespace> ] . sr.SkipWhitespace(); if (!sr.HasMore()) { throw new ParseException("unexpected end of line, missing expression or close/open character"); } char c = sr.Peek(); Ast.INode node; if (c == '{' || c == '[' || c == '(') { node = ParseCompound(sr); } else { node = ParseSingle(sr); } sr.SkipWhitespace(); return(node); }
Ast.INode ParseCompound(SeekableStringReader sr) { // compound = tuple | dict | list | set . sr.SkipWhitespace(); switch (sr.Peek()) { case '[': return(ParseList(sr)); case '{': { int bm = sr.Bookmark(); try { return(ParseSet(sr)); } catch (ParseException) { sr.FlipBack(bm); return(ParseDict(sr)); } } case '(': // tricky case here, it can be a tuple but also a complex number. // try complex number first { int bm = sr.Bookmark(); try { return(ParseComplex(sr)); } catch (ParseException) { sr.FlipBack(bm); return(ParseTuple(sr)); } } default: throw new ParseException("invalid sequencetype char"); } }
private Ast.SetNode ParseSet(SeekableStringReader sr) { // set = '{' expr_list trailing_comma '}' . // trailing_comma = '' | ',' . sr.Read(); // { sr.SkipWhitespace(); Ast.SetNode setnode = new Ast.SetNode(); var elts = ParseExprList(sr); // handle trailing comma if present sr.SkipWhitespace(); if (!sr.HasMore()) { throw new ParseException("missing '}'"); } if (sr.Peek() == ',') { sr.Read(); } if (!sr.HasMore()) { throw new ParseException("missing '}'"); } char closechar = sr.Read(); if (closechar != '}') { throw new ParseException("expected '}'"); } // make sure it has set semantics (remove duplicate elements) var h = new HashSet <Ast.INode>(elts); setnode.Elements = new List <Ast.INode>(h); return(setnode); }
private double ParseImaginaryPart(SeekableStringReader sr) { //imaginary = ['+' | '-' ] ( float | int ) 'j' . // string numberstr = sr.ReadUntil('j'); // try { // return this.ParseDouble(numberstr); // } catch(FormatException x) { // throw new ParseException("invalid float format", x); // } if (!sr.HasMore()) { throw new ParseException("unexpected end of input string"); } char signOrDigit = sr.Peek(); if (signOrDigit == '+') { sr.Read(); // skip the '+' } // now an int or float follows. double doubleValue; int bookmark = sr.Bookmark(); try { doubleValue = ParseFloat(sr).Value; } catch (ParseException) { sr.FlipBack(bookmark); var integerPart = ParseInt(sr); var integerNode = integerPart as Ast.IntegerNode; if (integerNode != null) { doubleValue = integerNode.Value; } else { var longNode = integerPart as Ast.LongNode; if (longNode != null) { doubleValue = longNode.Value; } else { var decimalNode = integerPart as Ast.DecimalNode; if (decimalNode != null) { doubleValue = Convert.ToDouble(decimalNode.Value); } else { throw new ParseException("not an integer for the imaginary part"); } } } } // now a 'j' must follow! sr.SkipWhitespace(); try { if (sr.Read() != 'j') { throw new ParseException("not an imaginary part"); } } catch (IndexOutOfRangeException) { throw new ParseException("not an imaginary part"); } return(doubleValue); }
private Ast.ComplexNumberNode ParseComplex(SeekableStringReader sr) { //complex = complextuple | imaginary . //imaginary = ['+' | '-' ] ( float | int ) 'j' . //complextuple = '(' ( float | int ) imaginary ')' . if (sr.Peek() == '(') { // complextuple sr.Read(); // ( string numberstr; if (sr.Peek() == '-' || sr.Peek() == '+') { // starts with a sign, read that first otherwise the readuntil will return immediately numberstr = sr.Read(1) + sr.ReadUntil('+', '-'); } else { numberstr = sr.ReadUntil('+', '-'); } sr.Rewind(1); // rewind the +/- // because we're a bit more cautious here with reading chars than in the float parser, // it can be that the parser now stopped directly after the 'e' in a number like "3.14e+20". // ("3.14e20" is fine) So, check if the last char is 'e' and if so, continue reading 0..9. if (numberstr.EndsWith("e", StringComparison.InvariantCultureIgnoreCase)) { // if the next symbol is + or -, accept it, then read the exponent integer if (sr.Peek() == '-' || sr.Peek() == '+') { numberstr += sr.Read(1); } numberstr += sr.ReadWhile("0123456789"); } sr.SkipWhitespace(); double realpart; try { realpart = ParseDouble(numberstr); } catch (FormatException x) { throw new ParseException("invalid float format", x); } double imaginarypart = ParseImaginaryPart(sr); if (sr.Read() != ')') { throw new ParseException("expected ) to end a complex number"); } return(new Ast.ComplexNumberNode { Real = realpart, Imaginary = imaginarypart }); } // imaginary double imag = ParseImaginaryPart(sr); return(new Ast.ComplexNumberNode { Real = 0, Imaginary = imag }); }
private Ast.INode ParseDict(SeekableStringReader sr) { //dict = '{' keyvalue_list trailing_comma '}' . //keyvalue_list = keyvalue { ',' keyvalue } . //keyvalue = expr ':' expr . // trailing_comma = '' | ',' . sr.Read(); // { sr.SkipWhitespace(); Ast.DictNode dict = new Ast.DictNode(); if (sr.Peek() == '}') { sr.Read(); return(dict); // empty dict } var elts = ParseKeyValueList(sr); // handle trailing comma if present sr.SkipWhitespace(); if (!sr.HasMore()) { throw new ParseException("missing '}'"); } if (sr.Peek() == ',') { sr.Read(); } if (!sr.HasMore()) { throw new ParseException("missing '}'"); } char closechar = sr.Read(); if (closechar != '}') { throw new ParseException("expected '}'"); } // make sure it has dict semantics (remove duplicate keys) var fixedDict = new Dictionary <Ast.INode, Ast.INode>(elts.Count); foreach (var node in elts) { var kv = (Ast.KeyValueNode)node; fixedDict[kv.Key] = kv.Value; } foreach (var kv in fixedDict) { dict.Elements.Add(new Ast.KeyValueNode { Key = kv.Key, Value = kv.Value }); } // SPECIAL CASE: {'__class__':'float','value':'nan'} ---> Double.NaN if (dict.Elements.Count != 2) { return(dict); } if (!dict.Elements.Contains(new Ast.KeyValueNode(new Ast.StringNode("__class__"), new Ast.StringNode("float")))) { return(dict); } if (dict.Elements.Contains(new Ast.KeyValueNode(new Ast.StringNode("value"), new Ast.StringNode("nan")))) { return(new Ast.DoubleNode(double.NaN)); } return(dict); }