/// <summary> /// Adds an expression to the item. This defines the right-hand-side /// of the statement. /// </summary> /// <param name="item">The item that defines the expression.</param> /// <exception cref="System.ArgumentNullException">If item is null.</exception> public void AddItem(IParseExp item) { if (item == null) throw new ArgumentNullException("item"); exps.Add(item); }
/// <summary> /// Adds an expression to the statement. /// </summary> /// <param name="expression">The expression to add.</param> /// <exception cref="System.ArgumentNullException">If expression is null.</exception> public void AddExpression(IParseExp expression) { if (expression == null) throw new ArgumentNullException("expression"); exps.Add(expression); }
/// <summary> /// Reads an if statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement _readIf(Lexer input) { Token debug = input.Expect(TokenType.If); var exp = _readExp(input, out _); input.Expect(TokenType.Then); var block = _readBlock(input); var elseIfs = new List <IfItem.ElseInfo>(); while (input.ReadIfType(TokenType.ElseIf)) { IParseExp elseExp = _readExp(input, out _); input.Expect(TokenType.Then); BlockItem elseIfBlock = _readBlock(input); elseIfs.Add(new IfItem.ElseInfo(elseExp, elseIfBlock)); } BlockItem elseBlock = null; if (input.ReadIfType(TokenType.Else)) { elseBlock = _readBlock(input); } input.Expect(TokenType.End); return(new IfItem(exp, block, elseIfs.ToArray(), elseBlock) { Debug = debug }); }
public IfItem(IParseExp exp, BlockItem block, ElseInfo[] elses, BlockItem elseBlock = null) { Expression = exp; Block = block; Elses = elses; ElseBlock = elseBlock; }
/// <summary> /// Creates a new UnOpItem with the given state. /// </summary> /// <param name="target">The target expression.</param> /// <param name="type">The type of operation.</param> /// <exception cref="System.ArgumentNullException">If target is null.</exception> public UnOpItem(IParseExp target, UnaryOperationType type) { if (target == null) throw new ArgumentNullException("target"); this.target = target; this.OperationType = type; }
/// <summary> /// Adds a new item to the table definition. /// </summary> /// <param name="index">The index expression.</param> /// <param name="exp">The value expression.</param> /// <exception cref="System.ArgumentNullException">If exp is null.</exception> public void AddItem(IParseExp index, IParseExp exp) { if (exp == null) throw new ArgumentNullException("exp"); if (index == null) index = new LiteralItem(i++); fields.Add(new KeyValuePair<IParseExp, IParseExp>(index, exp)); }
/// <summary> /// Adds an expression to the item. This defines the right-hand-side /// of the statement. /// </summary> /// <param name="item">The item that defines the expression.</param> /// <exception cref="System.ArgumentNullException">If item is null.</exception> public void AddItem(IParseExp item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } exps.Add(item); }
/// <summary> /// Adds an expression to the statement. /// </summary> /// <param name="expression">The expression to add.</param> /// <exception cref="System.ArgumentNullException">If expression is null.</exception> public void AddExpression(IParseExp expression) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } exps.Add(expression); }
/// <summary> /// Adds an argument expression to the function call. /// </summary> /// <param name="item">The expression item to add.</param> /// <param name="byRef">Whether the argument is passed by reference.</param> /// <exception cref="System.ArgumentNullException">If item is null.</exception> public void AddItem(IParseExp item, bool byRef) { if (item == null) { throw new ArgumentNullException(nameof(item)); } args.Add(new ArgumentInfo(item, byRef)); }
/// <summary> /// Creates a new instance of FuncCallItem with the given state. /// </summary> /// <param name="prefix">The prefix expression that defines the call.</param> /// <param name="args">The arguments to call with.</param> /// <exception cref="System.ArgumentException"> /// If prefix is not an expression or prefix-expression. /// </exception> /// <exception cref="System.ArgumentNullException">If prefix is null.</exception> public FuncCallItem(IParseExp prefix, ArgumentInfo[] args) { if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } Arguments = args; Prefix = prefix; }
/// <summary> /// Creates a new UnOpItem with the given state. /// </summary> /// <param name="target">The target expression.</param> /// <param name="type">The type of operation.</param> /// <exception cref="System.ArgumentNullException">If target is null.</exception> public UnOpItem(IParseExp target, UnaryOperationType type) { if (target == null) { throw new ArgumentNullException(nameof(target)); } this.target = target; this.OperationType = type; }
/// <summary> /// Creates a new instance of FuncCallItem with the given state. /// </summary> /// <param name="prefix">The prefix expression that defines the call.</param> /// <param name="instance">The string instance call name or null if /// not an instance call.</param> /// <param name="overload">The zero-based index of the overload to call, /// or negative to use overload resolution.</param> /// <exception cref="System.ArgumentException">If prefix is not an /// expression or prefix-expression.</exception> /// <exception cref="System.ArgumentNullException">If prefix is null.</exception> public FuncCallItem(IParseExp prefix, string instance, int overload) { if (prefix == null) throw new ArgumentNullException("prefix"); this.prefix = prefix; this.args = new List<ArgumentInfo>(); this.InstanceName = instance; this.IsTailCall = false; this.Overload = overload; }
/// <summary> /// Adds an else expression to this instance. /// </summary> /// <param name="exp">The else expression.</param> /// <param name="block">The else block.</param> /// <exception cref="System.ArgumentNullException">If exp or block is null.</exception> /// <exception cref="System.ArgumentException">If exp is not an expression.</exception> public void AddElse(IParseExp exp, BlockItem block) { if (exp == null) { throw new ArgumentNullException(nameof(exp)); } if (block == null) { throw new ArgumentNullException(nameof(block)); } elses.Add(new ElseInfo(exp, block)); }
/// <summary> /// Adds a new item to the table definition. /// </summary> /// <param name="index">The index expression.</param> /// <param name="exp">The value expression.</param> /// <exception cref="System.ArgumentNullException">If exp is null.</exception> public void AddItem(IParseExp index, IParseExp exp) { if (exp == null) { throw new ArgumentNullException(nameof(exp)); } if (index == null) { index = new LiteralItem(i++); } fields.Add(new KeyValuePair <IParseExp, IParseExp>(index, exp)); }
/// <summary> /// Creates a new instance of FuncCallItem with the given state. /// </summary> /// <param name="prefix">The prefix expression that defines the call.</param> /// <param name="instance">The string instance call name or null if /// not an instance call.</param> /// <param name="overload">The zero-based index of the overload to call, /// or negative to use overload resolution.</param> /// <exception cref="System.ArgumentException">If prefix is not an /// expression or prefix-expression.</exception> /// <exception cref="System.ArgumentNullException">If prefix is null.</exception> public FuncCallItem(IParseExp prefix, string instance, int overload) { if (prefix == null) { throw new ArgumentNullException(nameof(prefix)); } this.prefix = prefix; this.args = new List <ArgumentInfo>(); this.InstanceName = instance; this.IsTailCall = false; this.IsLastArgSingle = false; this.Overload = overload; }
/// <summary> /// Creates a new ForNumItem with the given name. /// </summary> /// <param name="name">The name of the variable defined.</param> /// <param name="limit">The item that defines the limit of the loop.</param> /// <param name="start">The item that defines the start of the loop.</param> /// <param name="step">The item that defines the step of the loop.</param> /// <exception cref="System.ArgumentNullException">If name, start, /// or limit is null.</exception> public ForNumItem(NameItem name, IParseExp start, IParseExp limit, IParseExp step) { if (name == null) throw new ArgumentNullException("name"); if (start == null) throw new ArgumentNullException("start"); if (limit == null) throw new ArgumentNullException("limit"); this.start = start; this.limit = limit; this.Step = step; this.Name = name; this.Break = new LabelItem("<break>"); }
/// <summary> /// Creates a new instance with the given state. /// </summary> /// <param name="lhs">The left-hand-side of the epxression.</param> /// <param name="rhs">The right-hand-side of the epxression.</param> /// <param name="type">The type of the expression.</param> /// <exception cref="System.ArgumentNullException">If lhs is null.</exception> public BinOpItem(IParseExp lhs, BinaryOperationType type, IParseExp rhs) { if (lhs == null) { throw new ArgumentNullException(nameof(lhs)); } if (rhs == null) { throw new ArgumentNullException(nameof(rhs)); } this.lhs = lhs; this.rhs = rhs; this.OperationType = type; }
/// <summary> /// Reads a table from the input. Input must be either on the starting '{'. /// </summary> /// <param name="input">Where to read input from.</param> /// <returns>The table that was read.</returns> protected virtual TableItem _readTable(Lexer input) { Token debug = input.Expect(TokenType.BeginTable); double id = 1; var values = new List <KeyValuePair <IParseExp, IParseExp> >(); while (!input.PeekType(TokenType.EndTable)) { if (input.ReadIfType(TokenType.BeginBracket)) { IParseExp temp = _readExp(input, out _); input.Expect(TokenType.EndBracket); input.Expect(TokenType.Assign); IParseExp val = _readExp(input, out _); values.Add(new KeyValuePair <IParseExp, IParseExp>(temp, val)); } else { IParseExp val = _readExp(input, out _); if (input.ReadIfType(TokenType.Assign)) { if (!(val is NameItem name)) { throw new SyntaxException(string.Format(Resources.InvalidDefinition, "table"), input.Name, debug); } IParseExp exp = _readExp(input, out _); values.Add(new KeyValuePair <IParseExp, IParseExp>(new LiteralItem(name.Name), exp)); } else { values.Add(new KeyValuePair <IParseExp, IParseExp>(new LiteralItem(id++), val)); } } if (!input.ReadIfType(TokenType.Comma) && !input.ReadIfType(TokenType.Semicolon)) { break; } } input.Expect(TokenType.EndTable); return(new TableItem(values.ToArray()) { Debug = debug }); }
/// <summary> /// Creates a new ForNumItem with the given name. /// </summary> /// <param name="name">The name of the variable defined.</param> /// <param name="limit">The item that defines the limit of the loop.</param> /// <param name="start">The item that defines the start of the loop.</param> /// <param name="step">The item that defines the step of the loop.</param> /// <exception cref="System.ArgumentNullException">If name, start, /// or limit is null.</exception> public ForNumItem(NameItem name, IParseExp start, IParseExp limit, IParseExp step) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (start == null) { throw new ArgumentNullException(nameof(start)); } if (limit == null) { throw new ArgumentNullException(nameof(limit)); } this.start = start; this.limit = limit; this.Step = step; this.Name = name; this.Break = new LabelItem("<break>"); }
/// <summary> /// Creates a new ForNumItem with the given name. /// </summary> /// <param name="name">The name of the variable defined.</param> /// <param name="limit">The item that defines the limit of the loop.</param> /// <param name="start">The item that defines the start of the loop.</param> /// <param name="step">The item that defines the step of the loop.</param> /// <exception cref="System.ArgumentNullException">If name, start, or limit is null.</exception> public ForNumItem(NameItem name, IParseExp start, IParseExp limit, IParseExp step, BlockItem block) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (start == null) { throw new ArgumentNullException(nameof(start)); } if (limit == null) { throw new ArgumentNullException(nameof(limit)); } Start = start; Limit = limit; Step = step; Name = name; Block = block; }
/// <summary> /// Creates a new IndexerItem. /// </summary> /// <param name="prefix">The prefix expression.</param> /// <param name="name">The name of the accessed member.</param> /// <exception cref="System.ArgumentNullException">If prefix /// or name is null.</exception> public IndexerItem(IParseExp prefix, string name) : this(prefix, new LiteralItem(name)) { }
/// <summary> /// Creates a new instance of WhileItem. /// </summary> public WhileItem(IParseExp exp, BlockItem block) { Expression = exp; Block = block; }
/// <summary> /// Adds an argument expression to the function call. /// </summary> /// <param name="item">The expression item to add.</param> /// <param name="byRef">Whether the argument is passed by reference.</param> /// <exception cref="System.ArgumentNullException">If item is null.</exception> public void AddItem(IParseExp item, bool byRef) { if (item == null) throw new ArgumentNullException("item"); args.Add(new ArgumentInfo(item, byRef)); }
/// <summary> /// Reads an expression from the input. /// </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> /// <returns>The expression that was read.</returns> protected virtual IParseExp _readExp(Lexer input, out bool isParentheses, int precedence = -1) { Token debug = input.Peek(); IParseExp ret; var unOpType = _getUnaryOperationType(input.Peek().Type); isParentheses = false; if (unOpType != UnaryOperationType.Unknown) { input.Read(); int unaryPrec = 11; if (unaryPrec > precedence && precedence >= 0) { unaryPrec = precedence; } ret = new UnOpItem(_readExp(input, out _, unaryPrec), unOpType) { Debug = debug }; } else if (input.ReadIfType(TokenType.Nil)) { ret = new LiteralItem(null) { Debug = debug }; } else if (input.ReadIfType(TokenType.False)) { ret = new LiteralItem(false) { Debug = debug }; } else if (input.ReadIfType(TokenType.True)) { ret = new LiteralItem(true) { Debug = debug }; } else if (input.ReadIfType(TokenType.NumberLiteral)) { ret = new LiteralItem(Helpers.ParseNumber(debug.Value)) { Debug = debug }; } else if (input.ReadIfType(TokenType.StringLiteral)) { ret = new LiteralItem(debug.Value) { Debug = debug }; } else if (input.ReadIfType(TokenType.Elipsis)) { ret = new NameItem("...") { Debug = debug }; } else if (input.PeekType(TokenType.BeginTable)) { ret = _readTable(input); } else if (input.PeekType(TokenType.Function)) { ret = _readFunctionHelper(input, false, false); } else { ret = _readPrefixExp(input, out isParentheses); } while (true) { BinaryOperationType binOpType = _getBinaryOperationType(input.Peek().Type); int newPrecedence = _getPrecedence(binOpType); if (binOpType == BinaryOperationType.Unknown || (newPrecedence < precedence && precedence >= 0)) { break; } input.Read(); // For left-associative operations, use a lower precedence so the nested call doesn't read // more than it should. a+b+c should be (a+b)+c, so we need the first add to be its own // item and then have that should be the lhs of another add. Note this only works if // operations of the same precedence have the same associativity. int extra = _isRightAssociative(binOpType) ? 0 : 1; IParseExp other = _readExp(input, out _, newPrecedence + extra); ret = new BinOpItem(ret, binOpType, other) { Debug = debug }; isParentheses = false; } return(ret); }
/// <summary> /// Creates a new IndexerItem. /// </summary> /// <param name="prefix">The prefix expression.</param> /// <param name="exp">The expression of the accessed member.</param> /// <exception cref="System.ArgumentNullException">If prefix /// or exp is null.</exception> public IndexerItem(IParseExp prefix, IParseExp exp) { this.Prefix = prefix; this.Expression = exp; }
/// <summary> /// Creates a new instance of FuncCallItem with the given state. /// </summary> /// <param name="prefix">The prefix expression that defines the call.</param> /// <exception cref="System.ArgumentException">If prefix is not an /// expression or prefix-expression.</exception> /// <exception cref="System.ArgumentNullException">If prefix is null.</exception> public FuncCallItem(IParseExp prefix) : this(prefix, null, -1) { }
public IfItem(IParseExp exp, BlockItem block) : this(exp, block, new ElseInfo[0], null) { }
/// <inheritdoc cref="FuncCallItem(IParseExp, ArgumentInfo[])"/> public FuncCallItem(IParseExp prefix) : this(prefix, new ArgumentInfo[0]) { }
/// <summary> /// Creates a new instance of ArgumentInfo. /// </summary> /// <param name="exp">The expression for the argument.</param> /// <param name="byRef">Whether the argument is passed by-ref.</param> public ArgumentInfo(IParseExp exp, bool byRef) { Expression = exp; IsByRef = byRef; }
/// <summary> /// Creates a new UnOpItem with the given state. /// </summary> /// <param name="target">The target expression.</param> /// <param name="type">The type of operation.</param> public UnOpItem(IParseExp target, UnaryOperationType type) { Target = target; OperationType = type; }
/// <summary> /// Adds an else expression to this instance. /// </summary> /// <param name="exp">The else expression.</param> /// <param name="block">The else block.</param> /// <exception cref="System.ArgumentNullException">If exp or block is null.</exception> /// <exception cref="System.ArgumentException">If exp is not an expression.</exception> public void AddElse(IParseExp exp, BlockItem block) { if (exp == null) throw new ArgumentNullException("exp"); if (block == null) throw new ArgumentNullException("block"); elses.Add(new ElseInfo(exp, block)); }
/// <summary> /// Creates a new IndexerItem. /// </summary> /// <param name="prefix">The prefix expression.</param> /// <param name="exp">The expression of the accessed member.</param> public IndexerItem(IParseExp prefix, IParseExp exp) { Prefix = prefix; Expression = exp; }
/// <summary> /// Reads a prefix-expression from the input. /// </summary> /// <param name="input">The input to read from.</param> /// <returns>The parsed expression.</returns> protected virtual IParseExp _readPrefixExp(Lexer input, out bool isParentheses) { Token debug = input.Peek(); IParseExp ret; if (input.ReadIfType(TokenType.BeginParen)) { isParentheses = true; ret = _readExp(input, out _); input.Expect(TokenType.EndParen); } else { isParentheses = false; Token name = input.Expect(TokenType.Identifier); ret = new NameItem(name.Value) { Debug = name }; } while (true) { if (input.ReadIfType(TokenType.BeginBracket)) { isParentheses = false; IParseExp temp = _readExp(input, out _); ret = new IndexerItem(ret, temp) { Debug = debug }; input.Expect(TokenType.EndBracket); } else if (input.ReadIfType(TokenType.Indexer)) { isParentheses = false; Token token = input.Expect(TokenType.Identifier); var name = new LiteralItem(token.Value) { Debug = token }; ret = new IndexerItem(ret, name) { Debug = debug }; } else { string instName = null; int overload = -1; if (input.ReadIfType(TokenType.Colon)) { instName = input.Expect(TokenType.Identifier).Value; int idx = instName.IndexOf('`'); if (idx >= 0) { if (!int.TryParse(instName.Substring(idx + 1), out overload)) { throw input.SyntaxError(Resources.OnlyNumbersInOverload); } instName = instName.Substring(0, idx); } } else if (ret is NameItem name) { int idx = name.Name.IndexOf('`'); if (idx >= 0) { if (!int.TryParse(name.Name.Substring(idx + 1), out overload)) { throw input.SyntaxError(Resources.OnlyNumbersInOverload); } name.Name = name.Name.Substring(0, idx); } } bool isLastSingle = false; var args = new List <FuncCallItem.ArgumentInfo>(); if (input.PeekType(TokenType.BeginTable)) { args.Add(new FuncCallItem.ArgumentInfo(_readTable(input), false)); } else if (input.PeekType(TokenType.StringLiteral)) { Token token = input.Expect(TokenType.StringLiteral); args.Add(new FuncCallItem.ArgumentInfo(new LiteralItem(token.Value) { Debug = token }, false)); } else if (input.ReadIfType(TokenType.BeginParen)) { if (!input.PeekType(TokenType.EndParen)) { do { bool isRef = input.ReadIfType(TokenType.Ref); bool isRefParen = false; if (isRef) { isRefParen = input.ReadIfType(TokenType.BeginParen); } else { isRef = input.ReadIfType(TokenType.RefSymbol); } args.Add(new FuncCallItem.ArgumentInfo(_readExp(input, out isLastSingle), isRef)); if (isRefParen) { input.Expect(TokenType.EndParen); } } while (input.ReadIfType(TokenType.Comma)); } input.Expect(TokenType.EndParen); } else { break; } isParentheses = false; ret = new FuncCallItem(ret, args.ToArray()) { Debug = debug, InstanceName = instName, Overload = overload, IsLastArgSingle = isLastSingle, }; } } return(ret); }
/// <summary> /// Creates a new instance with the given state. /// </summary> /// <param name="lhs">The left-hand-side of the epxression.</param> /// <param name="rhs">The right-hand-side of the epxression.</param> /// <param name="type">The type of the expression.</param> /// <exception cref="System.ArgumentNullException">If lhs is null.</exception> public BinOpItem(IParseExp lhs, BinaryOperationType type, IParseExp rhs) { if (lhs == null) throw new ArgumentNullException("lhs"); if (rhs == null) throw new ArgumentNullException("rhs"); this.lhs = lhs; this.rhs = rhs; this.OperationType = type; }
/// <summary> /// Reads a block of code from the input. Any end tokens should not be read and are handled by /// the parent call (e.g. 'end' or 'until'). /// </summary> /// <param name="input">Where to read input from.</param> /// <returns>The item that was read.</returns> protected virtual BlockItem _readBlock(Lexer input) { var debug = input.Peek(); IList <IParseStatement> statements = new List <IParseStatement>(); Token cur; while ((cur = input.Peek()).Type != TokenType.None) { if (_functions.ContainsKey(cur.Type)) { statements.Add(_functions[cur.Type](input)); } else if (cur.Type == TokenType.Return) { var ret = _readReturn(input); return(new BlockItem(statements.ToArray()) { Return = ret, Debug = debug }); } else if (cur.Type == TokenType.Semicolon) { input.Expect(TokenType.Semicolon); } else if (cur.Type == TokenType.End || cur.Type == TokenType.Else || cur.Type == TokenType.ElseIf || cur.Type == TokenType.Until) { // Don't read as it will be handled by the parent or the current block, this end belongs // to the parent. return(new BlockItem(statements.ToArray()) { Debug = debug }); } else { IParseExp exp = _readExp(input, out _); if (exp is FuncCallItem funcCall) { funcCall.Statement = true; statements.Add(funcCall); } else if (exp is LiteralItem) { throw new SyntaxException("A literal is not a variable.", input.Name, cur); } else if (exp is NameItem || exp is IndexerItem) { statements.Add(_readAssignment(input, cur, false, (IParseVariable)exp)); } else { throw new SyntaxException(string.Format(Resources.TokenStatement, cur.Value), input.Name, cur); } } } // Only gets here if this is the global function return(new BlockItem(statements.ToArray()) { Return = new ReturnItem(), Debug = debug }); }
/// <summary> /// Creates a new instance of ElseInfo. /// </summary> /// <param name="exp">The expression for the else if statement.</param> /// <param name="block">The block of the else if statement.</param> public ElseInfo(IParseExp exp, BlockItem block) { Expression = exp; Block = block; }
/// <summary> /// Creates a new instance of RepeatItem. /// </summary> public RepeatItem(IParseExp exp, BlockItem block) { Block = block; Expression = exp; }
/// <summary> /// Reads a for statement from the input. /// </summary> /// <param name="input">Where to read input from.</param> /// <returns>The object that was read.</returns> protected virtual IParseStatement _readFor(Lexer input) { Token debug = input.Expect(TokenType.For); Token name = input.Expect(TokenType.Identifier); var nameItem = new NameItem(name.Value) { Debug = name }; if (input.ReadIfType(TokenType.Assign)) { // Numeric for IParseExp start = _readExp(input, out _); input.Expect(TokenType.Comma); IParseExp limit = _readExp(input, out _); IParseExp step = null; if (input.ReadIfType(TokenType.Comma)) { step = _readExp(input, out _); } input.Expect(TokenType.Do); var block = _readBlock(input); input.Expect(TokenType.End); return(new ForNumItem(nameItem, start, limit, step, block) { Debug = debug }); } else { // Generic for statement // Read the variables var names = new List <NameItem>() { nameItem }; while (input.ReadIfType(TokenType.Comma)) { Token token = input.Expect(TokenType.Identifier); names.Add(new NameItem(token.Value) { Debug = token }); } input.Expect(TokenType.In); // Read the expression-list var exps = new List <IParseExp>(); exps.Add(_readExp(input, out _)); while (input.ReadIfType(TokenType.Comma)) { exps.Add(_readExp(input, out _)); } input.Expect(TokenType.Do); var block = _readBlock(input); input.Expect(TokenType.End); return(new ForGenItem(names.ToArray(), exps.ToArray(), block) { Debug = debug }); } }