private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer) { ExpressionBase clause; switch (tokenizer.NextChar) { case '!': tokenizer.Advance(); clause = ParseClause(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ConditionalExpression(null, ConditionalOperation.Not, clause)); case '(': if (AnonymousUserFunctionDefinitionExpression.IsAnonymousParameterList(tokenizer)) { return(AnonymousUserFunctionDefinitionExpression.ParseAnonymous(tokenizer)); } tokenizer.Advance(); clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } if (tokenizer.NextChar != ')') { if (tokenizer.NextChar == '\0') { return(ParseError(tokenizer, "No closing parenthesis found")); } return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar)); } clause.IsLogicalUnit = true; tokenizer.Advance(); return(clause); case '"': try { var stringValue = tokenizer.ReadQuotedString().ToString(); return(new StringConstantExpression(stringValue)); } catch (InvalidOperationException ex) { return(ParseError(tokenizer, ex.Message)); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return(ParseNumber(tokenizer, true)); case '-': var tokenStart = tokenizer.Location; tokenizer.Advance(); if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9') { var result = ParseNumber(tokenizer, false); var tokenEnd = result.Location.End; switch (result.Type) { case ExpressionType.IntegerConstant: result = new IntegerConstantExpression(-((IntegerConstantExpression)result).Value); break; case ExpressionType.FloatConstant: result = new FloatConstantExpression(-((FloatConstantExpression)result).Value); break; default: return(result); } result.Location = new TextRange(tokenStart, tokenEnd); return(result); } return(ParseError(tokenizer, "Minus without value", tokenStart.Line, tokenStart.Column)); case '{': tokenizer.Advance(); return(DictionaryExpression.Parse(tokenizer)); case '[': tokenizer.Advance(); return(ParseArray(tokenizer)); default: var line = tokenizer.Line; var column = tokenizer.Column; var identifier = tokenizer.ReadIdentifier(); if (identifier.IsEmpty) { var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar); tokenizer.Advance(); return(error); } SkipWhitespace(tokenizer); if (identifier == "return") { clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause)); } if (identifier == "function") { return(UserFunctionDefinitionExpression.Parse(tokenizer, line, column)); } if (identifier == "for") { return(ForExpression.Parse(tokenizer, line, column)); } if (identifier == "if") { return(IfExpression.Parse(tokenizer, line, column)); } if (identifier == "true") { return(new BooleanConstantExpression(true, line, column)); } if (identifier == "false") { return(new BooleanConstantExpression(false, line, column)); } if (tokenizer.NextChar == '(') { tokenizer.Advance(); var parameters = new List <ExpressionBase>(); ParseParameters(tokenizer, parameters); var functionCall = new FunctionCallExpression(new FunctionNameExpression(identifier.ToString(), line, column), parameters); functionCall.Location = new TextRange(line, column, tokenizer.Line, tokenizer.Column - 1); return(functionCall); } if (tokenizer.NextChar == '[') { IndexedVariableExpression parent = null; do { tokenizer.Advance(); var index = ExpressionBase.Parse(tokenizer); if (index.Type == ExpressionType.ParseError) { return(index); } SkipWhitespace(tokenizer); if (tokenizer.NextChar != ']') { return(ParseError(tokenizer, "Expecting closing bracket after index")); } tokenizer.Advance(); SkipWhitespace(tokenizer); if (parent != null) { parent = new IndexedVariableExpression(parent, index); } else { parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index); } } while (tokenizer.NextChar == '['); return(parent); } return(new VariableExpression(identifier.ToString(), line, column)); } }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { if (Entries.Count == 0) { result = this; return(true); } var dictScope = new InterpreterScope(scope); var entries = new List <DictionaryEntry>(); foreach (var entry in Entries) { ExpressionBase key, value; key = entry.Key; dictScope.Context = new AssignmentExpression(new VariableExpression("@key"), key); if (key.Type == ExpressionType.FunctionCall) { var expression = (FunctionCallExpression)key; if (!expression.ReplaceVariables(dictScope, out value)) { result = value; return(false); } key = value; } if (!key.ReplaceVariables(dictScope, out key)) { result = key; return(false); } switch (key.Type) { case ExpressionType.StringConstant: dictScope.Context = new AssignmentExpression(new VariableExpression("[" + ((StringConstantExpression)key).Value + "]"), entry.Value); break; case ExpressionType.IntegerConstant: dictScope.Context = new AssignmentExpression(new VariableExpression("[" + ((IntegerConstantExpression)key).Value.ToString() + "]"), entry.Value); break; default: result = new ParseErrorExpression("Dictionary key must evaluate to a constant", key); return(false); } if (!entry.Value.ReplaceVariables(dictScope, out value)) { result = value; return(false); } if (entries.Exists(e => e.Key == key)) { StringBuilder builder = new StringBuilder(); key.AppendString(builder); builder.Append(" already exists in dictionary"); result = new ParseErrorExpression(builder.ToString(), entry.Key); return(false); } entries.Add(new DictionaryEntry { Key = key, Value = value }); } result = new DictionaryExpression { Entries = entries }; return(true); }
/// <summary> /// Replaces the variables in the expression with values from <paramref name="scope" />. /// </summary> /// <param name="scope">The scope object containing variable values.</param> /// <param name="result">[out] The new expression containing the replaced variables.</param> /// <returns> /// <c>true</c> if substitution was successful, <c>false</c> if something went wrong, in which case <paramref name="result" /> will likely be a <see cref="ParseErrorExpression" />. /// </returns> public override bool ReplaceVariables(InterpreterScope scope, out ExpressionBase result) { var newDict = new DictionaryExpression(); var entries = newDict._entries; if (_state == DictionaryState.Unprocessed) { result = UpdateState(); if (result != null) { return(false); } } // constant dictionary if (_state == DictionaryState.ConstantSorted) { entries.AddRange(_entries); result = newDict; CopyLocation(result); return(true); } // non-constant dictionary - have to evaluate var dictScope = new InterpreterScope(scope); foreach (var entry in _entries) { ExpressionBase key, value; key = entry.Key; if (!key.IsConstant) { dictScope.Context = new AssignmentExpression(new VariableExpression("@key"), key); if (!key.ReplaceVariables(dictScope, out value)) { result = value; return(false); } if (!value.IsConstant) { result = new ParseErrorExpression("Dictionary key must evaluate to a constant", key); return(false); } key = value; } if (entry.Value.IsConstant) { value = entry.Value; } else { var builder = new StringBuilder(); builder.Append('['); key.AppendString(builder); builder.Append(']'); dictScope.Context = new AssignmentExpression(new VariableExpression(builder.ToString()), entry.Value); if (!entry.Value.ReplaceVariables(dictScope, out value)) { result = value; return(false); } } var newEntry = new DictionaryEntry { Key = key, Value = value }; if (_state == DictionaryState.ConstantKeysSorted) { entries.Add(newEntry); } else { var index = entries.BinarySearch(newEntry, newEntry); if (index >= 0) { StringBuilder builder = new StringBuilder(); key.AppendString(builder); builder.Append(" already exists in dictionary"); result = new ParseErrorExpression(builder.ToString(), entry.Key); return(false); } entries.Insert(~index, newEntry); } } newDict._state = DictionaryState.ConstantSorted; result = newDict; CopyLocation(result); return(true); }
private static ExpressionBase ParseClauseCore(PositionalTokenizer tokenizer) { ExpressionBase clause; switch (tokenizer.NextChar) { case '!': tokenizer.Advance(); clause = ParseClause(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ConditionalExpression(null, ConditionalOperation.Not, clause)); case '(': tokenizer.Advance(); clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } if (tokenizer.NextChar != ')') { if (tokenizer.NextChar == '\0') { return(ParseError(tokenizer, "No closing parenthesis found")); } return(ParseError(tokenizer, "Expected closing parenthesis, found: " + tokenizer.NextChar)); } clause.IsLogicalUnit = true; tokenizer.Advance(); return(clause); case '"': try { var stringValue = tokenizer.ReadQuotedString().ToString(); return(new StringConstantExpression(stringValue)); } catch (InvalidOperationException ex) { return(ParseError(tokenizer, ex.Message)); } case '0': if (tokenizer.Match("0x")) { string hexNumber = ""; while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f')) { hexNumber += tokenizer.NextChar; tokenizer.Advance(); } int hexValue = 0; Int32.TryParse(hexNumber, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out hexValue); return(new IntegerConstantExpression(hexValue)); } goto case '1'; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { var number = tokenizer.ReadNumber(); uint value; UInt32.TryParse(number.ToString(), out value); return(new IntegerConstantExpression((int)value)); } case '-': tokenizer.Advance(); if (tokenizer.NextChar >= '0' && tokenizer.NextChar <= '9') { if (tokenizer.Match("0x")) { string hexNumber = ""; while (Char.IsDigit(tokenizer.NextChar) || (tokenizer.NextChar >= 'A' && tokenizer.NextChar <= 'F') || (tokenizer.NextChar >= 'a' && tokenizer.NextChar <= 'f')) { hexNumber += tokenizer.NextChar; tokenizer.Advance(); } int hexValue = 0; Int32.TryParse(hexNumber, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.CurrentCulture, out hexValue); return(new IntegerConstantExpression(-hexValue)); } var number = tokenizer.ReadNumber(); int value; Int32.TryParse(number.ToString(), out value); return(new IntegerConstantExpression(-value)); } return(ParseError(tokenizer, "Minus without value")); case '{': tokenizer.Advance(); return(DictionaryExpression.Parse(tokenizer)); case '[': tokenizer.Advance(); return(ParseArray(tokenizer)); default: var line = tokenizer.Line; var column = tokenizer.Column; var identifier = tokenizer.ReadIdentifier(); if (identifier.IsEmpty) { var error = ParseError(tokenizer, "Unexpected character: " + tokenizer.NextChar); tokenizer.Advance(); return(error); } SkipWhitespace(tokenizer); if (identifier == "return") { clause = ExpressionBase.Parse(tokenizer); if (clause.Type == ExpressionType.ParseError) { return(clause); } return(new ReturnExpression(new KeywordExpression(identifier.ToString(), line, column), clause)); } if (identifier == "function") { return(FunctionDefinitionExpression.Parse(tokenizer, line, column)); } if (identifier == "for") { return(ForExpression.Parse(tokenizer, line, column)); } if (identifier == "if") { return(IfExpression.Parse(tokenizer, line, column)); } if (tokenizer.NextChar == '(') { tokenizer.Advance(); var parameters = new List <ExpressionBase>(); ParseParameters(tokenizer, parameters); var functionCall = new FunctionCallExpression(new VariableExpression(identifier.ToString(), line, column), parameters); functionCall.EndLine = tokenizer.Line; functionCall.EndColumn = tokenizer.Column - 1; return(functionCall); } if (tokenizer.NextChar == '[') { IndexedVariableExpression parent = null; do { tokenizer.Advance(); var index = ExpressionBase.Parse(tokenizer); if (index.Type == ExpressionType.ParseError) { return(index); } SkipWhitespace(tokenizer); if (tokenizer.NextChar != ']') { return(ParseError(tokenizer, "Expecting closing bracket after index")); } tokenizer.Advance(); SkipWhitespace(tokenizer); if (parent != null) { parent = new IndexedVariableExpression(parent, index); } else { parent = new IndexedVariableExpression(new VariableExpression(identifier.ToString(), line, column), index); } } while (tokenizer.NextChar == '['); return(parent); } return(new VariableExpression(identifier.ToString(), line, column)); } }