/// <summary> /// Reads a goto statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadGoto(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'goto' if (debug.Value != "goto") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "goto", "ReadGoto")); // read the target var name = Read(input, ref debug); if (!IsName(name.Value)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "goto", name.Value), input.Name, debug); if (_reserved.Contains(name.Value)) throw new SyntaxException( string.Format(Resources.TokenReserved, name.Value), input.Name, name); prev.Append(debug); return new GotoItem(name.Value) { Debug = debug }; }
/// <summary> /// Reads a do statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadDo(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'do' if (debug.Value != "do") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "do", "ReadDo")); // read the block var ret = ReadBlock(input, ref debug); // ensure that it ends with 'end' Token end = Read(input, ref debug); if (end.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, end.Value, "do", "end"), input.Name, end); prev.Append(debug); return ret; }
/// <summary> /// Reads a label statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadLabel(ITokenizer input, ref Token prev) { var debug = input.Read(); // read '::' if (debug.Value != "::") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "::", "ReadLabel")); // read the label Token label = Read(input, ref debug); // read '::' var name = Read(input, ref debug); if (name.Value != "::") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "label", "::"), input.Name, debug); prev.Append(debug); return new LabelItem(label.Value) { Debug = debug }; }
/// <summary> /// Reads a break statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadBreak(ITokenizer input, ref Token prev) { var ret = input.Read(); if (ret.Value != "break") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "break", "ReadBreak")); prev.Append(ret); return new GotoItem("<break>") { Debug = ret }; }
/// <summary> /// Reads an if statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadIf(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'if' IfItem i = new IfItem(); if (debug.Value != "if") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "if", "ReadIf")); // read the initial expression i.Exp = ReadExp(input, ref debug); // read 'then' var name = Read(input, ref debug); if (name.Value != "then") throw new SyntaxException( string.Format(Resources.TokenInvalid, name.Value, "if"), input.Name, debug); // read the block var readBlock = ReadBlock(input, ref debug); i.Block = readBlock; // handle elseif(s) while ((name = input.Peek()).Value == "elseif") { Read(input, ref debug); // read 'elseif' // read the expression var readExp = ReadExp(input, ref debug); // read 'then' name = Read(input, ref debug); if (name.Value != "then") throw new SyntaxException( string.Format(Resources.TokenInvalid, name.Value, "elseif"), input.Name, debug); // read the block readBlock = ReadBlock(input, ref debug); i.AddElse(readExp, readBlock); } // handle else if (name.Value != "else" && name.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalid, name.Value, "if"), input.Name, debug); if (name.Value == "else") { Read(input, ref debug); // read 'else' // read the block readBlock = ReadBlock(input, ref debug); i.ElseBlock = readBlock; } // read 'end' name = Read(input, ref debug); if (name.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalid, name.Value, "if"), input.Name, debug); prev.Append(debug); i.Debug = debug; return i; }
/// <summary> /// Reads a repeat statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadRepeat(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'repeat' RepeatItem repeat = new RepeatItem(); if (debug.Value != "repeat") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "repeat", "ReadRepeat")); // read the block repeat.Block = ReadBlock(input, ref debug); // read 'until' var name = Read(input, ref debug); if (name.Value != "until") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "repeat", "until"), input.Name, name); // read the expression repeat.Expression = ReadExp(input, ref debug); prev.Append(debug); repeat.Debug = debug; return repeat; }
/// <summary> /// Reads a return statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual ReturnItem ReadReturn(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'return' ReturnItem r = new ReturnItem(); if (debug.Value != "return") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "return", "ReadReturn")); var name = input.Peek(); if (name.Value != "end" && name.Value != "until" && name.Value != "elseif" && name.Value != "else") { r.AddExpression(ReadExp(input, ref debug)); while (input.Peek().Value == ",") { Read(input, ref debug); // read ',' r.AddExpression(ReadExp(input, ref debug)); } if (input.Peek().Value == ";") { Read(input, ref debug); // read ';' } // look at the next token for validation but keep it in the // reader for the parrent. name = input.Peek(); if (name.Value != "end" && name.Value != "until" && name.Value != "elseif" && name.Value != "else" && !IsNullOrWhiteSpace(name.Value)) throw new SyntaxException( Resources.ReturnAtEnd, input.Name, debug); } prev.Append(debug); r.Debug = debug; return r; }
/// <summary> /// Reads a function from the input. Input must either be on the word 'function' or /// on the next token. If it is on 'function' and canName is true, it will give /// the function the read name; otherwise it will give it a null name. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="token">The token to append the read Token to.</param> /// <param name="canName">True if the function can have a name, otherwise false.</param> /// <param name="local">True if this function is a local definition, otherwise false.</param> /// <returns>The function definition that was read.</returns> protected virtual FuncDefItem ReadFunctionHelper(ITokenizer input, ref Token token, bool canName, bool local) { IParseVariable name = null; string inst = null; Token last = input.Peek(), debug = last; if (last.Value == "function") { input.Read(); // read 'function' last = input.Peek(); if (IsName(last.Value)) { Token nameTok = input.Read(); // read name name = new NameItem(last.Value) { Debug = last }; // handle indexers last = input.Peek(); while (last.Value == ".") { Read(input, ref nameTok); // read '.' last = input.Peek(); if (!IsName(last.Value)) break; name = new IndexerItem(name, new LiteralItem(last.Value) { Debug = last }) { Debug = nameTok }; Read(input, ref nameTok); } if (input.Peek().Value == ":") { Read(input, ref nameTok); inst = Read(input, ref nameTok).Value; if (!IsName(inst)) throw new SyntaxException(string.Format(Resources.TokenInvalid, last.Value, "function"), input.Name, last); } debug.Append(nameTok); } } if (name != null && !canName) throw new SyntaxException(Resources.FunctionCantHaveName, input.Name, debug); FuncDefItem ret = new FuncDefItem(name, local); ret.InstanceName = inst; last = Read(input, ref debug); if (last.Value != "(") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "function", "("), input.Name, last); last = input.Peek(); while (last.Value != ")") { Token temp = Read(input, ref debug); // read the name if (!IsName(last.Value) && last.Value != "...") throw new SyntaxException(string.Format(Resources.TokenInvalid, last.Value, "function"), input.Name, temp); ret.AddArgument(new NameItem(last.Value) { Debug = last }); last = input.Peek(); if (last.Value == ",") Read(input, ref debug); else if (last.Value != ")") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting2, last.Value, "function", ",", ")"), input.Name, last); last = input.Peek(); } if (last.Value != ")") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "function", ")"), input.Name, last); Read(input, ref debug); // read ')' BlockItem chunk = ReadBlock(input, ref debug); chunk.Return = chunk.Return ?? new ReturnItem(); ret.Block = chunk; last = Read(input, ref debug); if (last.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "function", "end"), input.Name, last); token.Append(debug); ret.Debug = debug; return ret; }
/// <summary> /// Reads a local statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadLocal(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'local' if (debug.Value != "local") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "local", "ReadLocal")); var name = input.Peek(); if (name.Value == "function") { prev.Append(debug); return ReadFunctionHelper(input, ref prev, true, true); } else { Read(input, ref debug); // read name if (!IsName(name.Value)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "local", name.Value), input.Name, name); if (_reserved.Contains(name.Value)) throw new SyntaxException( string.Format(Resources.TokenReserved, name.Value), input.Name, name); var i = ReadAssignment(input, ref debug, true, new NameItem(name.Value) { Debug = name }); prev.Append(debug); return i; } }
/// <summary> /// Reads a class statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadClass(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'class' string sname = null; List<string> imp = new List<string>(); if (debug.Value != "class") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "class", "ReadClass")); if (input.Peek().Value.StartsWith("'", StringComparison.Ordinal) || input.Peek().Value.StartsWith("\"", StringComparison.Ordinal)) { var name = Read(input, ref debug); sname = name.Value.Substring(1); if (input.Peek().Value == "(") { Read(input, ref debug); // read '(' while (input.Peek().Value != ")") { // read the name name = Read(input, ref debug); if (!IsName(name.Value)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "class", name.Value), input.Name, name); imp.Add(name.Value); // read ',' name = Read(input, ref debug); if (name.Value != ",") throw new SyntaxException( string.Format(Resources.TokenInvalid, name.Value, "class"), input.Name, name); } Read(input, ref debug); // read ')' } } else { var name = Read(input, ref debug); sname = name.Value; if (!IsName(sname)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "class", name.Value), input.Name, name); if (input.Peek().Value == ":") { do { // simply include the '.' in the name. string n = ""; do { Read(input, ref debug); // read ':' or ',' n += (n == "" ? "" : ".") + Read(input, ref debug).Value; } while (input.Peek().Value == "."); imp.Add(n); } while (input.Peek().Value == ","); } } prev.Append(debug); return new ClassDefItem(sname, imp.ToArray()) { Debug = debug }; }
/// <summary> /// Reads a token from the tokenizer and appends the read /// value to the given token. /// </summary> /// <param name="input">Where to get the input from.</param> /// <param name="token">A token to append the read token to.</param> /// <returns>The token that was read.</returns> protected static Token Read(ITokenizer input, ref Token token) { Token ret = input.Read(); token.Append(ret); return ret; }
/// <summary> /// Reads a block of code from the input. Any end tokens /// should not be read and are handled by the parrent call /// (e.g. 'end' or 'until'). /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append the total token onto.</param> /// <returns>The item that was read.</returns> protected virtual BlockItem ReadBlock(ITokenizer input, ref Token prev) { BlockItem ret = new BlockItem(); Token total = input.Peek(); total.Value = ""; Token name; while ((name = input.Peek()).Value != null) { if (Functions.ContainsKey(name.Value)) { var temp = Functions[name.Value](input, ref total); ret.AddItem(temp); } else if (name.Value == "return") { ret.Return = ReadReturn(input, ref total); return ret; } else if (name.Value == ";") { Read(input, ref total); // read ';' } else if (name.Value == "end" || name.Value == "else" || name.Value == "elseif" || name.Value == "until") { // don'type read as it will be handled by the parrent prev.Append(total); // don't add 'end' to the prev ret.Debug = total; // or the current block, this return ret; // end belongs to the parrent. } else { Token debug = name; debug.Value = ""; var exp = ReadExp(input, ref debug); if (exp is FuncCallItem) { (exp as FuncCallItem).Statement = true; ret.AddItem((FuncCallItem)exp); } else if (exp is LiteralItem) { throw new SyntaxException( "A literal is not a variable.", input.Name, debug); } else if (exp is NameItem || exp is IndexerItem) { var i = ReadAssignment(input, ref debug, false, (IParseVariable)exp); ret.AddItem(i); } else throw new SyntaxException( string.Format(Resources.TokenStatement, name.Value), input.Name, debug); total.Append(debug); } } // end While // only gets here if this is the global function ret.Debug = total; ret.Return = ret.Return ?? new ReturnItem(); return ret; }
/// <summary> /// Reads a table from the input. Input must be either on the starting '{'. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="token">The token to append the read Tokenm to.</param> /// <returns>The table that was read.</returns> protected virtual TableItem ReadTable(ITokenizer input, ref Token token) { Token debug = input.Read(); if (debug.Value != "{") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, debug.Value, "table", "{"), input.Name, debug); TableItem ret = new TableItem(); Token last = input.Peek(); while (last.Value != "}") { if (last.Value == "[") { Read(input, ref debug); // read the "[" var temp = ReadExp(input, ref debug); if (temp == null) throw new SyntaxException(string.Format(Resources.InvalidDefinition, "table"), input.Name, debug); // read ']' last = Read(input, ref debug); if (last.Value != "]") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "table", "]"), input.Name, last); // read '=' last = Read(input, ref debug); if (last.Value != "=") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "table", "="), input.Name, last); // read the expression var val = ReadExp(input, ref debug); if (val == null) throw new SyntaxException(string.Format(Resources.InvalidDefinition, "table"), input.Name, debug); ret.AddItem(temp, val); } else { var val = ReadExp(input, ref debug); if (input.Peek().Value == "=") { Read(input, ref debug); // read '=' NameItem name = val as NameItem; if (name == null) throw new SyntaxException(string.Format(Resources.InvalidDefinition, "table"), input.Name, debug); // read the expression var exp = ReadExp(input, ref debug); ret.AddItem(new LiteralItem(name.Name), exp); } else { ret.AddItem(null, val); } } if (input.Peek().Value != "," && input.Peek().Value != ";") break; else Read(input, ref debug); last = input.Peek(); } // end While Token end = Read(input, ref debug); // read the "}" if (end.Value != "}") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, end.Value, "table", "}"), input.Name, end); ret.Debug = debug; token.Append(debug); return ret; }
/// <summary> /// Reads a while statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadWhile(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'while' WhileItem w = new WhileItem(); if (debug.Value != "while") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "while", "ReadWhile")); // read the expression w.Exp = ReadExp(input, ref debug); // read 'do' var name = Read(input, ref debug); if (name.Value != "do") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "while", "do"), input.Name, name); // read the block w.Block = ReadBlock(input, ref debug); // read 'end' name = Read(input, ref debug); if (name.Value != "end") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, name.Value, "while", "end"), input.Name, name); prev.Append(debug); w.Debug = debug; return w; }
/// <summary> /// Reads a for statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="prev">The token to append what is read into.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement ReadFor(ITokenizer input, ref Token prev) { var debug = input.Read(); // read 'for' if (debug.Value != "for") throw new InvalidOperationException(string.Format(Resources.MustBeOn, "for", "ReadFor")); // read a name var name = Read(input, ref debug); if (!IsName(name.Value)) throw new SyntaxException( string.Format(Resources.TokenNotAName, "for", name.Value), input.Name, name); if (_reserved.Contains(name.Value)) throw new SyntaxException( string.Format(Resources.TokenReserved, name.Value), input.Name, name); // numeric for if (input.Peek().Value == "=") { var ret = ReadNumberFor(input, ref debug, name); prev.Append(debug); return ret; } // generic for statement else { var ret = ReadGenericFor(input, ref debug, name); prev.Append(debug); return ret; } }
/// <summary> /// Reads a prefix-expression from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="token">The token to append the total token onto.</param> /// <returns>The expression that was read.</returns> protected virtual IParseExp ReadPrefixExp(ITokenizer input, ref Token token) { Stack<UnaryInfo> ex = new Stack<UnaryInfo>(); IParseExp o = null; Token last, debug = input.Peek(); debug.Value = ""; // check for unary operators last = input.Peek(); while (last.Value == "-" || last.Value == "not" || last.Value == "#") { Read(input, ref debug); if (last.Value == "-") { ex.Push(new UnaryInfo(1, last.StartPos, last.StartLine)); } else if (last.Value == "not") { ex.Push(new UnaryInfo(2, last.StartPos, last.StartLine)); } else { Contract.Assert(last.Value == "#"); ex.Push(new UnaryInfo(3, last.StartPos, last.StartLine)); } last = input.Peek(); } // check for literals last = input.Peek(); int over = -1; if (last.Value != null) { NumberFormatInfo ni = CultureInfo.CurrentCulture.NumberFormat; if (last.Value != "..." && (char.IsNumber(last.Value, 0) || last.Value.StartsWith(ni.NumberDecimalSeparator, StringComparison.CurrentCulture))) { Read(input, ref debug); // read the number. try { o = new LiteralItem(double.Parse(last.Value, CultureInfo.CurrentCulture)) { Debug = last }; } catch (FormatException e) { throw new SyntaxException(Resources.BadNumberFormat, input.Name, last, e); } } else if (last.Value.StartsWith("&", StringComparison.Ordinal)) { Read(input, ref debug); try { o = new LiteralItem(Convert.ToDouble(long.Parse(last.Value.Substring(1), NumberStyles.AllowHexSpecifier, CultureInfo.CurrentCulture))) { Debug = last }; } catch (FormatException e) { throw new SyntaxException(Resources.BadNumberFormat, input.Name, last, e); } } else if (last.Value.StartsWith("\"", StringComparison.Ordinal)) { Read(input, ref debug); o = new LiteralItem(last.Value.Substring(1)) { Debug = last }; } else if (last.Value.StartsWith("{", StringComparison.Ordinal)) { o = ReadTable(input, ref debug); } else if (last.Value == "(") { Read(input, ref debug); o = ReadExp(input, ref debug); last = Read(input, ref debug); if (last.Value != ")") throw new SyntaxException(string.Format(Resources.TokenInvalidExpecting, last.Value, "expression", ")"), input.Name, last); } else if (last.Value == "true") { Read(input, ref debug); o = new LiteralItem(true) { Debug = last }; } else if (last.Value == "false") { Read(input, ref debug); o = new LiteralItem(false) { Debug = last }; } else if (last.Value == "nil") { Read(input, ref debug); o = new LiteralItem(null) { Debug = last }; } else if (last.Value == "function") { o = ReadFunctionHelper(input, ref debug, false, false); } else { // allow for specifying overloads on global variables if (last.Value.IndexOf('`') != -1) { if (!int.TryParse(last.Value.Substring(last.Value.IndexOf('`') + 1), out over)) throw new InvalidOperationException(Resources.OnlyNumbersInOverload); last.Value = last.Value.Substring(0, last.Value.IndexOf('`')); } Read(input, ref debug); o = new NameItem(last.Value) { Debug = last }; } } // read function calls and indexers { string inst = null; bool cont = true; while (cont) { last = input.Peek(); last.Value = last.Value ?? ""; if (last.Value == ".") { Read(input, ref debug); if (over != -1) throw new SyntaxException(Resources.FunctionCallAfterOverload, input.Name, last); if (inst != null) throw new SyntaxException(Resources.IndexerAfterInstance, input.Name, last); last = Read(input, ref debug); // allow for specifying an overload if (last.Value.IndexOf('`') != -1) { if (!int.TryParse(last.Value.Substring(last.Value.IndexOf('`') + 1), out over)) throw new InvalidOperationException(Resources.OnlyNumbersInOverload); last.Value = last.Value.Substring(0, last.Value.IndexOf('`')); } if (!IsName(last.Value)) throw new SyntaxException(string.Format(Resources.TokenNotAName, "indexer", last.Value), input.Name, last); if (!(o is IParsePrefixExp)) throw new SyntaxException(Resources.IndexAfterExpression, input.Name, last); o = new IndexerItem(o, new LiteralItem(last.Value) { Debug = last }) { Debug = debug }; } else if (last.Value == ":") { Read(input, ref debug); if (over != -1) throw new SyntaxException(Resources.FunctionCallAfterOverload, input.Name, last); if (inst != null) throw new SyntaxException(Resources.OneInstanceCall, input.Name, last); inst = Read(input, ref debug).Value; if (!IsName(inst)) throw new SyntaxException(string.Format(Resources.TokenNotAName, "indexer", last.Value), input.Name, last); } else if (last.Value == "[") { Read(input, ref debug); if (over != -1) throw new SyntaxException(Resources.FunctionCallAfterOverload, input.Name, last); if (inst != null) throw new SyntaxException(Resources.IndexerAfterInstance, input.Name, last); var temp = ReadExp(input, ref debug); last = Read(input, ref debug); o = new IndexerItem(o, temp) { Debug = debug }; if (last.Value != "]") throw new SyntaxException( string.Format(Resources.TokenInvalidExpecting, last.Value, "indexer", "]"), input.Name, last); } else if (last.Value.StartsWith("\"", StringComparison.Ordinal)) { Read(input, ref debug); FuncCallItem temp = new FuncCallItem(o, inst, over) { Debug = debug }; o = temp; temp.AddItem(new LiteralItem(last.Value.Substring(1)), false); inst = null; over = -1; } else if (last.Value == "{") { var temp = ReadTable(input, ref debug); FuncCallItem func = new FuncCallItem(o, inst, over) { Debug = debug }; o = func; func.AddItem(temp, false); inst = null; over = -1; } else if (last.Value == "(") { Read(input, ref debug); FuncCallItem func = new FuncCallItem(o, inst, over); o = func; inst = null; over = -1; while (input.Peek().Value != ")" && input.Peek().Value != null) { bool? byRef = null; if (input.Peek().Value == "@") { byRef = false; Read(input, ref debug); } else if (input.Peek().Value == "ref") { Read(input, ref debug); if (input.Peek().Value == "(") { Read(input, ref debug); byRef = true; } else byRef = false; } var temp = ReadExp(input, ref debug); if (byRef != null && !(temp is NameItem) && !(temp is IndexerItem)) throw new SyntaxException(Resources.OnlyVarByReference, input.Name, last); if (temp == null) throw new SyntaxException(string.Format(Resources.InvalidDefinition, "function call"), input.Name, last); func.AddItem(temp, byRef != null); if (byRef == true && (last = input.Read()).Value != ")") throw new SyntaxException(Resources.RefOneArgument, input.Name, last); if (input.Peek().Value == ",") Read(input, ref debug); else if (input.Peek().Value == ")") break; else throw new SyntaxException(string.Format(Resources.TokenInvalidExpecting2, input.Peek().Value, "function call", ",", ")"), input.Name, last); } if (input.Peek() == null) throw new SyntaxException(string.Format(Resources.UnexpectedEOF, "function call"), input.Name, last); Read(input, ref debug); func.Debug = debug; } else { if (inst != null) throw new SyntaxException(Resources.InstanceMissingArgs, input.Name, last); if (over != -1) throw new SyntaxException(Resources.OverloadMissingArgs, input.Name, last); cont = false; } } } // read exponents // HACK: This is needed here because the power operator has // higher precedence than the unary operators. Rather than // have unary operators handled in ReadExp, they are handled // so exponents need to be handled before we apply the // unary operators. if (input.Peek().Value == "^") { Read(input, ref debug); var temp = ReadPrefixExp(input, ref debug); BinOpItem item = new BinOpItem(o, BinaryOperationType.Power, temp) { Debug = debug }; o = item; } // now apply the unary operators while (ex.Count > 0) { var loc = ex.Pop(); Token tok = new Token(debug.Value, loc.StartPos, debug.EndPos, loc.StartLine, debug.EndLine); switch (loc.Version) { case 1: // neg if (o is LiteralItem) { object oo = (o as LiteralItem).Value; if (!(oo is double)) throw new SyntaxException(Resources.InvalidUnary, input.Name, debug); o = new LiteralItem(-(double)oo) { Debug = tok }; } else o = new UnOpItem(o, UnaryOperationType.Minus) { Debug = tok }; break; case 2: // not o = new UnOpItem(o, UnaryOperationType.Not) { Debug = tok }; break; case 3: // len o = new UnOpItem(o, UnaryOperationType.Length) { Debug = tok }; break; } } // finaly return token.Append(debug); return o; }
/// <summary> /// Reads an expression from the input and returns the /// item that was read. /// </summary> /// <param name="input">Where to read input from.</param> /// <param name="precedence">The precedence of the previous expression /// or -1 if a root.</param> /// <param name="token">The Token that represents the entire expression /// should be appended to this variable.</param> /// <returns>The expression that was read.</returns> protected virtual IParseExp ReadExp(ITokenizer input, ref Token token, int precedence = -1) { Token debug = input.Peek(); debug.Value = ""; IParseExp cur = ReadPrefixExp(input, ref debug); BinOpItem ret = null; start: Token last = input.Peek(); BinaryOperationType type = GetOperationType(last.Value); int nPrec = GetPrecedence(type); if (nPrec != -1 && (precedence == -1 || precedence > nPrec)) { Read(input, ref debug); // read the exp var temp = ReadExp(input, ref debug, nPrec); ret = new BinOpItem(ret ?? cur, type, temp); ret.Debug = debug; goto start; } token.Append(debug); return ret ?? cur; }