Skip to content

Commit

Permalink
Merge pull request #27 from yiyuan-he/merge-parser-to-v1_33_6
Browse files Browse the repository at this point in the history
Merge custom parser to v1_33_6 branch
  • Loading branch information
mxiamxia authored Dec 17, 2024
2 parents b6acced + f547a7f commit 087f988
Show file tree
Hide file tree
Showing 6 changed files with 864 additions and 115 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.instrumentation.awssdk.v1_11;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BedrockJsonParser {

// Prevent instantiation
private BedrockJsonParser() {
throw new UnsupportedOperationException("Utility class");
}

public static LlmJson parse(String jsonString) {
JsonParser parser = new JsonParser(jsonString);
Map<String, Object> jsonBody = parser.parse();
return new LlmJson(jsonBody);
}

static class JsonParser {
private final String json;
private int position;

public JsonParser(String json) {
this.json = json.trim();
this.position = 0;
}

private void skipWhitespace() {
while (position < json.length() && Character.isWhitespace(json.charAt(position))) {
position++;
}
}

private char currentChar() {
return json.charAt(position);
}

private static boolean isHexDigit(char c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}

private void expect(char c) {
skipWhitespace();
if (currentChar() != c) {
throw new IllegalArgumentException(
"Expected '" + c + "' but found '" + currentChar() + "'");
}
position++;
}

private String readString() {
skipWhitespace();
expect('"'); // Ensure the string starts with a quote
StringBuilder result = new StringBuilder();
while (currentChar() != '"') {
// Handle escape sequences
if (currentChar() == '\\') {
position++; // Move past the backslash
if (position >= json.length()) {
throw new IllegalArgumentException("Unexpected end of input in string escape sequence");
}
char escapeChar = currentChar();
switch (escapeChar) {
case '"':
case '\\':
case '/':
result.append(escapeChar);
break;
case 'b':
result.append('\b');
break;
case 'f':
result.append('\f');
break;
case 'n':
result.append('\n');
break;
case 'r':
result.append('\r');
break;
case 't':
result.append('\t');
break;
case 'u': // Unicode escape sequence
if (position + 4 >= json.length()) {
throw new IllegalArgumentException("Invalid unicode escape sequence in string");
}
char[] hexChars = new char[4];
for (int i = 0; i < 4; i++) {
position++; // Move to the next character
char hexChar = json.charAt(position);
if (!isHexDigit(hexChar)) {
throw new IllegalArgumentException(
"Invalid hexadecimal digit in unicode escape sequence");
}
hexChars[i] = hexChar;
}
int unicodeValue = Integer.parseInt(new String(hexChars), 16);
result.append((char) unicodeValue);
break;
default:
throw new IllegalArgumentException("Invalid escape character: \\" + escapeChar);
}
position++;
} else {
result.append(currentChar());
position++;
}
}
position++; // Skip closing quote
return result.toString();
}

private Object readValue() {
skipWhitespace();
char c = currentChar();

if (c == '"') {
return readString();
} else if (Character.isDigit(c)) {
return readScopedNumber();
} else if (c == '{') {
return readObject(); // JSON Objects
} else if (c == '[') {
return readArray(); // JSON Arrays
} else if (json.startsWith("true", position)) {
position += 4;
return true;
} else if (json.startsWith("false", position)) {
position += 5;
return false;
} else if (json.startsWith("null", position)) {
position += 4;
return null; // JSON null
} else {
throw new IllegalArgumentException("Unexpected character: " + c);
}
}

private Number readScopedNumber() {
int start = position;

// Consume digits and the optional decimal point
while (position < json.length()
&& (Character.isDigit(json.charAt(position)) || json.charAt(position) == '.')) {
position++;
}

String number = json.substring(start, position);

if (number.contains(".")) {
double value = Double.parseDouble(number);
if (value < 0.0 || value > 1.0) {
throw new IllegalArgumentException(
"Value out of bounds for Bedrock Floating Point Attribute: " + number);
}
return value;
} else {
return Integer.parseInt(number);
}
}

private Map<String, Object> readObject() {
Map<String, Object> map = new HashMap<>();
expect('{');
skipWhitespace();
while (currentChar() != '}') {
String key = readString();
expect(':');
Object value = readValue();
map.put(key, value);
skipWhitespace();
if (currentChar() == ',') {
position++;
}
}
position++; // Skip closing brace
return map;
}

private List<Object> readArray() {
List<Object> list = new ArrayList<>();
expect('[');
skipWhitespace();
while (currentChar() != ']') {
list.add(readValue());
skipWhitespace();
if (currentChar() == ',') {
position++;
}
}
position++;
return list;
}

public Map<String, Object> parse() {
return readObject();
}
}

// Resolves paths in a JSON structure
static class JsonPathResolver {

// Private constructor to prevent instantiation
private JsonPathResolver() {
throw new UnsupportedOperationException("Utility class");
}

public static Object resolvePath(LlmJson llmJson, String... paths) {
for (String path : paths) {
Object value = resolvePath(llmJson.getJsonBody(), path);
if (value != null) {
return value;
}
}
return null;
}

private static Object resolvePath(Map<String, Object> json, String path) {
String[] keys = path.split("/");
Object current = json;

for (String key : keys) {
if (key.isEmpty()) {
continue;
}

if (current instanceof Map) {
current = ((Map<?, ?>) current).get(key);
} else if (current instanceof List) {
try {
int index = Integer.parseInt(key);
current = ((List<?>) current).get(index);
} catch (NumberFormatException | IndexOutOfBoundsException e) {
return null;
}
} else {
return null;
}

if (current == null) {
return null;
}
}
return current;
}
}

public static class LlmJson {
private final Map<String, Object> jsonBody;

public LlmJson(Map<String, Object> jsonBody) {
this.jsonBody = jsonBody;
}

public Map<String, Object> getJsonBody() {
return jsonBody;
}
}
}
Loading

0 comments on commit 087f988

Please sign in to comment.