public object ExecuteExpr(Expr expr) { object result = null; if (expr is Literal) { Literal literal = (Literal)expr; if (literal.Type == ExprType.String) { result = literal.Value; } else if (literal.Type == ExprType.Bytes) { result = Utility.StringToBytes(literal.Value); } else if (literal.Type == ExprType.Name) { result = Variables[literal.Value.ToLowerInvariant()]; } else if (literal.Type == ExprType.Bool) { result = Boolean.Parse(literal.Value); } else if (literal.Type == ExprType.Number) { result = Double.Parse(literal.Value); } else if (literal.Type == ExprType.HexInt) { result = Int32.Parse(literal.Value, System.Globalization.NumberStyles.AllowHexSpecifier); } else if (literal.Type == ExprType.Null) { } else { throw new Exception("Unexpected literal: " + literal.Type); } } else if (expr is Command) { Command cmd = (Command)expr; if (cmd.Type == ExprType.Root) { foreach (var arg in cmd.Args) { if (arg.Type == ExprType.Assign) { result = ExecuteExpr(arg); } else { result = ExecuteExpr(arg); defaultVar = result; } } } else if ((cmd.Type == ExprType.DotInstanceDefault) || (cmd.Type == ExprType.DotInstanceDefaultChain)) { result = ExecuteFunction((Command)cmd.Args[1], ExecuteExpr(cmd.Args[0]), true); } else if ((cmd.Type == ExprType.DotInstance) || (cmd.Type == ExprType.DotInstanceChain)) { result = ExecuteFunction((Command)cmd.Args[1], ExecuteExpr(cmd.Args[0]), false); } else if (cmd.Type == ExprType.DotDefault) { result = ExecuteFunction((Command)cmd.Args[0], null, true); } else if (cmd.Type == ExprType.Function) { result = ExecuteFunction(cmd, null, false); } else if ((cmd.Type == ExprType.DotProperty) || (cmd.Type == ExprType.DotPropertyChain)) { object obj = ExecuteExpr(cmd.Args[0]); string propertyName = ((Literal)cmd.Args[1]).Value; result = obj.GetType().GetProperty(propertyName).GetValue(obj, null); } else if (cmd.Type == ExprType.Indexed) { object obj = ExecuteExpr(cmd.Args[0]); int index = Int32.Parse(((Literal)cmd.Args[1]).Value); var type = obj.GetType(); if (type.IsArray) { result = ((Array)obj).GetValue(index); } else { var attributes = type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); if (attributes.Length > 0) { var indexerName = ((DefaultMemberAttribute)attributes[0]).MemberName; result = type.GetProperty(indexerName).GetValue(obj, new object[] { index }); } else { throw new Exception(obj.ToString() + " can't be indexed."); } } } else if (cmd.Type == ExprType.Array) { object[] array = new object[cmd.Args.Count]; for (int i = 0; i < array.Length; i++) { array[i] = ExecuteExpr(cmd.Args[i]); } result = array; } else if (cmd.Type == ExprType.Assign) { string name = ((Literal)cmd.Args[0]).Value.ToLowerInvariant(); result = ExecuteExpr(cmd.Args[1]); if (Variables.ContainsKey(name)) { Variables[name] = result; } else { Variables.Add(name, result); } } else if (cmd.Type == ExprType.Negative) { result = ((double)ExecuteExpr(cmd.Args[0])) * -1; } else if (cmd.Type == ExprType.Mod) { result = ((double)ExecuteExpr(cmd.Args[0])) % ((double)ExecuteExpr(cmd.Args[1])); } else if (cmd.Type == ExprType.Div) { result = ((double)ExecuteExpr(cmd.Args[0])) / ((double)ExecuteExpr(cmd.Args[1])); } else if (cmd.Type == ExprType.Mul) { result = ((double)ExecuteExpr(cmd.Args[0])) * ((double)ExecuteExpr(cmd.Args[1])); } else if (cmd.Type == ExprType.Sub) { result = ((double)ExecuteExpr(cmd.Args[0])) - ((double)ExecuteExpr(cmd.Args[1])); } else if (cmd.Type == ExprType.Add) { object left = ExecuteExpr(cmd.Args[0]); object right = ExecuteExpr(cmd.Args[1]); if ((left is String) && (right is String)) { result = ((string)left) + ((string)right); } else { result = ((double)left) + ((double)right); } } else { throw new Exception("Unexpected command: " + cmd.Type); } } return result; }
Expr GetIndexed(Expr result, List<Token> tokens, ref int tokenIdx) { if ((tokenIdx < tokens.Count) && (tokens[tokenIdx].Type == TokenType.HexOrIndex || tokens[tokenIdx].Type == TokenType.Name)) { Command cmd = new Command(ExprType.Indexed); cmd.Args.Add(result); cmd.Args.Add(new Literal(tokens[tokenIdx].Type == TokenType.HexOrIndex ? ExprType.Number : ExprType.Name, tokens[tokenIdx].Value)); tokenIdx++; result = cmd; } return result; }
Expr GetDotPropertyChain(Expr result, List<Token> tokens, ref int tokenIdx) { Expr chain = null; if ((tokenIdx < tokens.Count) && (tokens[tokenIdx].Type == TokenType.Dot) && ((tokenIdx + 1) < tokens.Count) && (tokens[tokenIdx + 1].Type == TokenType.Name)) { Token property = tokens[tokenIdx + 1]; tokenIdx += 2; Command cmd = new Command(ExprType.DotPropertyChain); cmd.Args.Add(result); cmd.Args.Add(new Literal(ExprType.Name, property.Value)); chain = cmd; chain = GetIndexed(chain, tokens, ref tokenIdx); chain = GetChain(chain, tokens, ref tokenIdx); } return chain; }
Expr GetDotInstanceDefaultChain(Expr result, List<Token> tokens, ref int tokenIdx) { Expr chain = null; if ((tokenIdx < tokens.Count) && (tokens[tokenIdx].Type == TokenType.Dot) && ((tokenIdx + 1) < tokens.Count) && (tokens[tokenIdx + 1].Type == TokenType.Dot)) { Token token = tokens[tokenIdx]; tokenIdx += 2; Command cmd = new Command(ExprType.DotInstanceDefaultChain); chain = cmd; cmd.Args.Add(result); Expr expr = GetFunction(tokens, ref tokenIdx); if (expr == null) { throw new Exception("Expected a function" + token.Error(2)); } cmd.Args.Add(expr); } return chain; }
Expr GetChain(Expr result, List<Token> tokens, ref int tokenIdx) { Expr chain = null; if ((chain = GetDotInstanceDefaultChain(result, tokens, ref tokenIdx)) != null) { return chain; } else if ((chain = GetDotInstanceChain(result, tokens, ref tokenIdx)) != null) { return chain; } else if ((chain = GetDotPropertyChain(result, tokens, ref tokenIdx)) != null) { return chain; } return result; }
Expr GetArithHelper(Expr result, ExprType exprType, List<Token> tokens, ref int tokenIdx) { Token token = tokens[tokenIdx]; tokenIdx++; Command cmd = new Command(exprType); cmd.Args.Add(result); Expr expr = GetArith(tokens, ref tokenIdx); if (expr == null) { throw new Exception("Expected a numeric expression" + token.Error()); } cmd.Args.Add(expr); return cmd; }