mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-24 10:56:53 +00:00
feat: add types, base components
This commit is contained in:
parent
a37a98b0ae
commit
b856cdadf7
@ -1,5 +1,11 @@
|
||||
import QueryWhereClause from './WhereClause/WhereClause';
|
||||
|
||||
function QueryBuilderV2(): JSX.Element {
|
||||
return <div className="query-builder-v2">QueryBuilderV2</div>;
|
||||
return (
|
||||
<div className="query-builder-v2">
|
||||
<QueryWhereClause />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default QueryBuilderV2;
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
.where-clause {
|
||||
width: 100%;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 2px;
|
||||
background-color: #fff;
|
||||
|
||||
&-header {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
&-content {
|
||||
padding: 12px;
|
||||
|
||||
.query-input {
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
font-family: monospace;
|
||||
|
||||
&.error {
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.valid {
|
||||
border-color: #52c41a;
|
||||
}
|
||||
}
|
||||
|
||||
.error-alert,
|
||||
.success-alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.query-examples {
|
||||
margin-top: 8px;
|
||||
|
||||
ul {
|
||||
margin: 8px 0;
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin: 4px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.condition-builder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.conditions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.condition-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
background: #f5f5f5;
|
||||
color: #000;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.where-clause-content {
|
||||
.query-examples {
|
||||
ul {
|
||||
li {
|
||||
margin: 4px 0;
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
|
||||
color: #000;
|
||||
|
||||
code {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,138 @@
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import './WhereClause.styles.scss';
|
||||
|
||||
import { Input, Typography } from 'antd';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { IQueryContext, IValidationResult } from 'types/antlrQueryTypes';
|
||||
import { getQueryContextAtCursor, validateQuery } from 'utils/antlrQueryUtils';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
function QueryWhereClause(): JSX.Element {
|
||||
const [query, setQuery] = useState<string>('');
|
||||
const [cursorPosition, setCursorPosition] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [queryContext, setQueryContext] = useState<IQueryContext | null>(null);
|
||||
const [validation, setValidation] = useState<IValidationResult>({
|
||||
isValid: false,
|
||||
message: '',
|
||||
errors: [],
|
||||
});
|
||||
|
||||
console.log({
|
||||
cursorPosition,
|
||||
queryContext,
|
||||
validation,
|
||||
isLoading,
|
||||
});
|
||||
|
||||
const handleQueryChange = useCallback(async (newQuery: string) => {
|
||||
setIsLoading(true);
|
||||
setQuery(newQuery);
|
||||
|
||||
try {
|
||||
const validationResponse = validateQuery(newQuery);
|
||||
setValidation(validationResponse);
|
||||
} catch (error) {
|
||||
setValidation({
|
||||
isValid: false,
|
||||
message: 'Failed to process query',
|
||||
errors: [error instanceof Error ? error.message : 'Unknown error'],
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (query) {
|
||||
const context = getQueryContextAtCursor(query, cursorPosition);
|
||||
setQueryContext(context as IQueryContext);
|
||||
}
|
||||
}, [query, cursorPosition]);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const { value, selectionStart } = e.target;
|
||||
setQuery(value);
|
||||
setCursorPosition(selectionStart || 0);
|
||||
handleQueryChange(value);
|
||||
};
|
||||
|
||||
const handleCursorMove = (e: React.SyntheticEvent<HTMLInputElement>): void => {
|
||||
const { selectionStart } = e.currentTarget;
|
||||
setCursorPosition(selectionStart || 0);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="where-clause">
|
||||
<div className="where-clause-header">
|
||||
<Text strong>Where</Text>
|
||||
</div>
|
||||
<div className="where-clause-content">
|
||||
<Input
|
||||
value={query}
|
||||
onChange={handleChange}
|
||||
onSelect={handleCursorMove}
|
||||
onKeyUp={handleCursorMove}
|
||||
placeholder="Enter your query (e.g., status = 'error' AND service = 'frontend')"
|
||||
/>
|
||||
|
||||
{queryContext && (
|
||||
<div className="query-context">
|
||||
<h3>Current Context</h3>
|
||||
<div className="context-details">
|
||||
<p>
|
||||
<strong>Token:</strong> {queryContext.currentToken}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Type:</strong> {queryContext.tokenType}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Context:</strong>{' '}
|
||||
{queryContext.isInValue
|
||||
? 'Value'
|
||||
: queryContext.isInKey
|
||||
? 'Key'
|
||||
: queryContext.isInOperator
|
||||
? 'Operator'
|
||||
: queryContext.isInFunction
|
||||
? 'Function'
|
||||
: 'Unknown'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="query-examples">
|
||||
<Text type="secondary">Examples:</Text>
|
||||
<ul>
|
||||
<li>
|
||||
<Text code>status = 'error'</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>
|
||||
service = 'frontend' AND level = 'error'
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>message LIKE '%timeout%'</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>duration {'>'} 1000</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>tags IN ['prod', 'frontend']</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>
|
||||
NOT (status = 'error' OR level = 'error')
|
||||
</Text>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default QueryWhereClause;
|
||||
11
frontend/src/container/Home/Home2.tsx
Normal file
11
frontend/src/container/Home/Home2.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import QueryBuilderV2 from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
|
||||
function Home2(): JSX.Element {
|
||||
return (
|
||||
<div>
|
||||
<QueryBuilderV2 />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home2;
|
||||
@ -1,7 +1,7 @@
|
||||
import Home from 'container/Home';
|
||||
import Home2 from 'container/Home/Home2';
|
||||
|
||||
function HomePage(): JSX.Element {
|
||||
return <Home />;
|
||||
return <Home2 />;
|
||||
}
|
||||
|
||||
export default HomePage;
|
||||
|
||||
104
frontend/src/query-grammar/.antlr/FilterQuery.interp
Normal file
104
frontend/src/query-grammar/.antlr/FilterQuery.interp
Normal file
File diff suppressed because one or more lines are too long
49
frontend/src/query-grammar/.antlr/FilterQuery.tokens
Normal file
49
frontend/src/query-grammar/.antlr/FilterQuery.tokens
Normal file
@ -0,0 +1,49 @@
|
||||
LPAREN=1
|
||||
RPAREN=2
|
||||
LBRACK=3
|
||||
RBRACK=4
|
||||
COMMA=5
|
||||
EQUALS=6
|
||||
NOT_EQUALS=7
|
||||
NEQ=8
|
||||
LT=9
|
||||
LE=10
|
||||
GT=11
|
||||
GE=12
|
||||
LIKE=13
|
||||
NOT_LIKE=14
|
||||
ILIKE=15
|
||||
NOT_ILIKE=16
|
||||
BETWEEN=17
|
||||
NOT_BETWEEN=18
|
||||
EXISTS=19
|
||||
NOT_EXISTS=20
|
||||
REGEXP=21
|
||||
NOT_REGEXP=22
|
||||
CONTAINS=23
|
||||
NOT_CONTAINS=24
|
||||
IN=25
|
||||
NOT_IN=26
|
||||
NOT=27
|
||||
AND=28
|
||||
OR=29
|
||||
HAS=30
|
||||
HASANY=31
|
||||
HASALL=32
|
||||
HASNONE=33
|
||||
BOOL=34
|
||||
NUMBER=35
|
||||
QUOTED_TEXT=36
|
||||
KEY=37
|
||||
WS=38
|
||||
'('=1
|
||||
')'=2
|
||||
'['=3
|
||||
']'=4
|
||||
','=5
|
||||
'!='=7
|
||||
'<>'=8
|
||||
'<'=9
|
||||
'<='=10
|
||||
'>'=11
|
||||
'>='=12
|
||||
132
frontend/src/query-grammar/.antlr/FilterQueryLexer.interp
Normal file
132
frontend/src/query-grammar/.antlr/FilterQueryLexer.interp
Normal file
File diff suppressed because one or more lines are too long
371
frontend/src/query-grammar/.antlr/FilterQueryLexer.java
Normal file
371
frontend/src/query-grammar/.antlr/FilterQueryLexer.java
Normal file
@ -0,0 +1,371 @@
|
||||
// Generated from /Users/younix/Documents/SigNoz-Repos/signoz/frontend/src/query-grammar/FilterQuery.g4 by ANTLR 4.13.1
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
|
||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"})
|
||||
public class FilterQueryLexer extends Lexer {
|
||||
static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); }
|
||||
|
||||
protected static final DFA[] _decisionToDFA;
|
||||
protected static final PredictionContextCache _sharedContextCache =
|
||||
new PredictionContextCache();
|
||||
public static final int
|
||||
LPAREN=1, RPAREN=2, LBRACK=3, RBRACK=4, COMMA=5, EQUALS=6, NOT_EQUALS=7,
|
||||
NEQ=8, LT=9, LE=10, GT=11, GE=12, LIKE=13, NOT_LIKE=14, ILIKE=15, NOT_ILIKE=16,
|
||||
BETWEEN=17, NOT_BETWEEN=18, EXISTS=19, NOT_EXISTS=20, REGEXP=21, NOT_REGEXP=22,
|
||||
CONTAINS=23, NOT_CONTAINS=24, IN=25, NOT_IN=26, NOT=27, AND=28, OR=29,
|
||||
HAS=30, HASANY=31, HASALL=32, HASNONE=33, BOOL=34, NUMBER=35, QUOTED_TEXT=36,
|
||||
KEY=37, WS=38;
|
||||
public static String[] channelNames = {
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
|
||||
};
|
||||
|
||||
public static String[] modeNames = {
|
||||
"DEFAULT_MODE"
|
||||
};
|
||||
|
||||
private static String[] makeRuleNames() {
|
||||
return new String[] {
|
||||
"LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS",
|
||||
"NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE",
|
||||
"BETWEEN", "NOT_BETWEEN", "EXISTS", "NOT_EXISTS", "REGEXP", "NOT_REGEXP",
|
||||
"CONTAINS", "NOT_CONTAINS", "IN", "NOT_IN", "NOT", "AND", "OR", "HAS",
|
||||
"HASANY", "HASALL", "HASNONE", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY",
|
||||
"WS", "DIGIT"
|
||||
};
|
||||
}
|
||||
public static final String[] ruleNames = makeRuleNames();
|
||||
|
||||
private static String[] makeLiteralNames() {
|
||||
return new String[] {
|
||||
null, "'('", "')'", "'['", "']'", "','", null, "'!='", "'<>'", "'<'",
|
||||
"'<='", "'>'", "'>='"
|
||||
};
|
||||
}
|
||||
private static final String[] _LITERAL_NAMES = makeLiteralNames();
|
||||
private static String[] makeSymbolicNames() {
|
||||
return new String[] {
|
||||
null, "LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS",
|
||||
"NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE",
|
||||
"BETWEEN", "NOT_BETWEEN", "EXISTS", "NOT_EXISTS", "REGEXP", "NOT_REGEXP",
|
||||
"CONTAINS", "NOT_CONTAINS", "IN", "NOT_IN", "NOT", "AND", "OR", "HAS",
|
||||
"HASANY", "HASALL", "HASNONE", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY",
|
||||
"WS"
|
||||
};
|
||||
}
|
||||
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
|
||||
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #VOCABULARY} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String[] tokenNames;
|
||||
static {
|
||||
tokenNames = new String[_SYMBOLIC_NAMES.length];
|
||||
for (int i = 0; i < tokenNames.length; i++) {
|
||||
tokenNames[i] = VOCABULARY.getLiteralName(i);
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = VOCABULARY.getSymbolicName(i);
|
||||
}
|
||||
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = "<INVALID>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String[] getTokenNames() {
|
||||
return tokenNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Vocabulary getVocabulary() {
|
||||
return VOCABULARY;
|
||||
}
|
||||
|
||||
|
||||
public FilterQueryLexer(CharStream input) {
|
||||
super(input);
|
||||
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGrammarFileName() { return "FilterQuery.g4"; }
|
||||
|
||||
@Override
|
||||
public String[] getRuleNames() { return ruleNames; }
|
||||
|
||||
@Override
|
||||
public String getSerializedATN() { return _serializedATN; }
|
||||
|
||||
@Override
|
||||
public String[] getChannelNames() { return channelNames; }
|
||||
|
||||
@Override
|
||||
public String[] getModeNames() { return modeNames; }
|
||||
|
||||
@Override
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
public static final String _serializedATN =
|
||||
"\u0004\u0000&\u0167\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+
|
||||
"\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+
|
||||
"\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+
|
||||
"\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+
|
||||
"\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+
|
||||
"\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+
|
||||
"\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+
|
||||
"\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+
|
||||
"\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+
|
||||
"\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+
|
||||
"\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+
|
||||
"!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+
|
||||
"&\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0002\u0001\u0002"+
|
||||
"\u0001\u0003\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005"+
|
||||
"\u0001\u0005\u0003\u0005]\b\u0005\u0001\u0006\u0001\u0006\u0001\u0006"+
|
||||
"\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001"+
|
||||
"\t\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f"+
|
||||
"\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0004\rx\b\r"+
|
||||
"\u000b\r\f\ry\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001"+
|
||||
"\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001"+
|
||||
"\u000f\u0001\u000f\u0001\u000f\u0004\u000f\u008b\b\u000f\u000b\u000f\f"+
|
||||
"\u000f\u008c\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f"+
|
||||
"\u0001\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010"+
|
||||
"\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011"+
|
||||
"\u0001\u0011\u0004\u0011\u00a1\b\u0011\u000b\u0011\f\u0011\u00a2\u0001"+
|
||||
"\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+
|
||||
"\u0011\u0001\u0011\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+
|
||||
"\u0012\u0001\u0012\u0003\u0012\u00b3\b\u0012\u0001\u0013\u0001\u0013\u0001"+
|
||||
"\u0013\u0001\u0013\u0004\u0013\u00b9\b\u0013\u000b\u0013\f\u0013\u00ba"+
|
||||
"\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013"+
|
||||
"\u0003\u0013\u00c3\b\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014"+
|
||||
"\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0015\u0001\u0015\u0001\u0015"+
|
||||
"\u0001\u0015\u0004\u0015\u00d0\b\u0015\u000b\u0015\f\u0015\u00d1\u0001"+
|
||||
"\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001"+
|
||||
"\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001"+
|
||||
"\u0016\u0001\u0016\u0001\u0016\u0003\u0016\u00e3\b\u0016\u0001\u0017\u0001"+
|
||||
"\u0017\u0001\u0017\u0001\u0017\u0004\u0017\u00e9\b\u0017\u000b\u0017\f"+
|
||||
"\u0017\u00ea\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017\u0001\u0017"+
|
||||
"\u0001\u0017\u0001\u0017\u0001\u0017\u0003\u0017\u00f5\b\u0017\u0001\u0018"+
|
||||
"\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+
|
||||
"\u0004\u0019\u00fe\b\u0019\u000b\u0019\f\u0019\u00ff\u0001\u0019\u0001"+
|
||||
"\u0019\u0001\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+
|
||||
"\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+
|
||||
"\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001e\u0001"+
|
||||
"\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001"+
|
||||
"\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001"+
|
||||
"\u001f\u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001!"+
|
||||
"\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0003!\u0133"+
|
||||
"\b!\u0001\"\u0004\"\u0136\b\"\u000b\"\f\"\u0137\u0001\"\u0001\"\u0004"+
|
||||
"\"\u013c\b\"\u000b\"\f\"\u013d\u0003\"\u0140\b\"\u0001#\u0001#\u0001#"+
|
||||
"\u0001#\u0005#\u0146\b#\n#\f#\u0149\t#\u0001#\u0001#\u0001#\u0001#\u0001"+
|
||||
"#\u0005#\u0150\b#\n#\f#\u0153\t#\u0001#\u0003#\u0156\b#\u0001$\u0001$"+
|
||||
"\u0005$\u015a\b$\n$\f$\u015d\t$\u0001%\u0004%\u0160\b%\u000b%\f%\u0161"+
|
||||
"\u0001%\u0001%\u0001&\u0001&\u0000\u0000\'\u0001\u0001\u0003\u0002\u0005"+
|
||||
"\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n"+
|
||||
"\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011"+
|
||||
"#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b"+
|
||||
"7\u001c9\u001d;\u001e=\u001f? A!C\"E#G$I%K&M\u0000\u0001\u0000\u001c\u0002"+
|
||||
"\u0000LLll\u0002\u0000IIii\u0002\u0000KKkk\u0002\u0000EEee\u0002\u0000"+
|
||||
"NNnn\u0002\u0000OOoo\u0002\u0000TTtt\u0002\u0000\t\t \u0002\u0000BBb"+
|
||||
"b\u0002\u0000WWww\u0002\u0000XXxx\u0002\u0000SSss\u0002\u0000RRrr\u0002"+
|
||||
"\u0000GGgg\u0002\u0000PPpp\u0002\u0000CCcc\u0002\u0000AAaa\u0002\u0000"+
|
||||
"DDdd\u0002\u0000HHhh\u0002\u0000YYyy\u0002\u0000UUuu\u0002\u0000FFff\u0002"+
|
||||
"\u0000\"\"\\\\\u0002\u0000\'\'\\\\\u0004\u000009AZ__az\u0006\u0000..0"+
|
||||
"9A[]]__az\u0003\u0000\t\n\r\r \u0001\u000009\u017c\u0000\u0001\u0001"+
|
||||
"\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000\u0005\u0001"+
|
||||
"\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000\t\u0001\u0000"+
|
||||
"\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000"+
|
||||
"\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'"+
|
||||
"\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000"+
|
||||
"\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000"+
|
||||
"\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005"+
|
||||
"\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000"+
|
||||
"\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000"+
|
||||
"\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C"+
|
||||
"\u0001\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000"+
|
||||
"\u0000\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000"+
|
||||
"\u0001O\u0001\u0000\u0000\u0000\u0003Q\u0001\u0000\u0000\u0000\u0005S"+
|
||||
"\u0001\u0000\u0000\u0000\u0007U\u0001\u0000\u0000\u0000\tW\u0001\u0000"+
|
||||
"\u0000\u0000\u000b\\\u0001\u0000\u0000\u0000\r^\u0001\u0000\u0000\u0000"+
|
||||
"\u000fa\u0001\u0000\u0000\u0000\u0011d\u0001\u0000\u0000\u0000\u0013f"+
|
||||
"\u0001\u0000\u0000\u0000\u0015i\u0001\u0000\u0000\u0000\u0017k\u0001\u0000"+
|
||||
"\u0000\u0000\u0019n\u0001\u0000\u0000\u0000\u001bs\u0001\u0000\u0000\u0000"+
|
||||
"\u001d\u0080\u0001\u0000\u0000\u0000\u001f\u0086\u0001\u0000\u0000\u0000"+
|
||||
"!\u0094\u0001\u0000\u0000\u0000#\u009c\u0001\u0000\u0000\u0000%\u00ac"+
|
||||
"\u0001\u0000\u0000\u0000\'\u00b4\u0001\u0000\u0000\u0000)\u00c4\u0001"+
|
||||
"\u0000\u0000\u0000+\u00cb\u0001\u0000\u0000\u0000-\u00da\u0001\u0000\u0000"+
|
||||
"\u0000/\u00e4\u0001\u0000\u0000\u00001\u00f6\u0001\u0000\u0000\u00003"+
|
||||
"\u00f9\u0001\u0000\u0000\u00005\u0104\u0001\u0000\u0000\u00007\u0108\u0001"+
|
||||
"\u0000\u0000\u00009\u010c\u0001\u0000\u0000\u0000;\u010f\u0001\u0000\u0000"+
|
||||
"\u0000=\u0113\u0001\u0000\u0000\u0000?\u011a\u0001\u0000\u0000\u0000A"+
|
||||
"\u0121\u0001\u0000\u0000\u0000C\u0132\u0001\u0000\u0000\u0000E\u0135\u0001"+
|
||||
"\u0000\u0000\u0000G\u0155\u0001\u0000\u0000\u0000I\u0157\u0001\u0000\u0000"+
|
||||
"\u0000K\u015f\u0001\u0000\u0000\u0000M\u0165\u0001\u0000\u0000\u0000O"+
|
||||
"P\u0005(\u0000\u0000P\u0002\u0001\u0000\u0000\u0000QR\u0005)\u0000\u0000"+
|
||||
"R\u0004\u0001\u0000\u0000\u0000ST\u0005[\u0000\u0000T\u0006\u0001\u0000"+
|
||||
"\u0000\u0000UV\u0005]\u0000\u0000V\b\u0001\u0000\u0000\u0000WX\u0005,"+
|
||||
"\u0000\u0000X\n\u0001\u0000\u0000\u0000Y]\u0005=\u0000\u0000Z[\u0005="+
|
||||
"\u0000\u0000[]\u0005=\u0000\u0000\\Y\u0001\u0000\u0000\u0000\\Z\u0001"+
|
||||
"\u0000\u0000\u0000]\f\u0001\u0000\u0000\u0000^_\u0005!\u0000\u0000_`\u0005"+
|
||||
"=\u0000\u0000`\u000e\u0001\u0000\u0000\u0000ab\u0005<\u0000\u0000bc\u0005"+
|
||||
">\u0000\u0000c\u0010\u0001\u0000\u0000\u0000de\u0005<\u0000\u0000e\u0012"+
|
||||
"\u0001\u0000\u0000\u0000fg\u0005<\u0000\u0000gh\u0005=\u0000\u0000h\u0014"+
|
||||
"\u0001\u0000\u0000\u0000ij\u0005>\u0000\u0000j\u0016\u0001\u0000\u0000"+
|
||||
"\u0000kl\u0005>\u0000\u0000lm\u0005=\u0000\u0000m\u0018\u0001\u0000\u0000"+
|
||||
"\u0000no\u0007\u0000\u0000\u0000op\u0007\u0001\u0000\u0000pq\u0007\u0002"+
|
||||
"\u0000\u0000qr\u0007\u0003\u0000\u0000r\u001a\u0001\u0000\u0000\u0000"+
|
||||
"st\u0007\u0004\u0000\u0000tu\u0007\u0005\u0000\u0000uw\u0007\u0006\u0000"+
|
||||
"\u0000vx\u0007\u0007\u0000\u0000wv\u0001\u0000\u0000\u0000xy\u0001\u0000"+
|
||||
"\u0000\u0000yw\u0001\u0000\u0000\u0000yz\u0001\u0000\u0000\u0000z{\u0001"+
|
||||
"\u0000\u0000\u0000{|\u0007\u0000\u0000\u0000|}\u0007\u0001\u0000\u0000"+
|
||||
"}~\u0007\u0002\u0000\u0000~\u007f\u0007\u0003\u0000\u0000\u007f\u001c"+
|
||||
"\u0001\u0000\u0000\u0000\u0080\u0081\u0007\u0001\u0000\u0000\u0081\u0082"+
|
||||
"\u0007\u0000\u0000\u0000\u0082\u0083\u0007\u0001\u0000\u0000\u0083\u0084"+
|
||||
"\u0007\u0002\u0000\u0000\u0084\u0085\u0007\u0003\u0000\u0000\u0085\u001e"+
|
||||
"\u0001\u0000\u0000\u0000\u0086\u0087\u0007\u0004\u0000\u0000\u0087\u0088"+
|
||||
"\u0007\u0005\u0000\u0000\u0088\u008a\u0007\u0006\u0000\u0000\u0089\u008b"+
|
||||
"\u0007\u0007\u0000\u0000\u008a\u0089\u0001\u0000\u0000\u0000\u008b\u008c"+
|
||||
"\u0001\u0000\u0000\u0000\u008c\u008a\u0001\u0000\u0000\u0000\u008c\u008d"+
|
||||
"\u0001\u0000\u0000\u0000\u008d\u008e\u0001\u0000\u0000\u0000\u008e\u008f"+
|
||||
"\u0007\u0001\u0000\u0000\u008f\u0090\u0007\u0000\u0000\u0000\u0090\u0091"+
|
||||
"\u0007\u0001\u0000\u0000\u0091\u0092\u0007\u0002\u0000\u0000\u0092\u0093"+
|
||||
"\u0007\u0003\u0000\u0000\u0093 \u0001\u0000\u0000\u0000\u0094\u0095\u0007"+
|
||||
"\b\u0000\u0000\u0095\u0096\u0007\u0003\u0000\u0000\u0096\u0097\u0007\u0006"+
|
||||
"\u0000\u0000\u0097\u0098\u0007\t\u0000\u0000\u0098\u0099\u0007\u0003\u0000"+
|
||||
"\u0000\u0099\u009a\u0007\u0003\u0000\u0000\u009a\u009b\u0007\u0004\u0000"+
|
||||
"\u0000\u009b\"\u0001\u0000\u0000\u0000\u009c\u009d\u0007\u0004\u0000\u0000"+
|
||||
"\u009d\u009e\u0007\u0005\u0000\u0000\u009e\u00a0\u0007\u0006\u0000\u0000"+
|
||||
"\u009f\u00a1\u0007\u0007\u0000\u0000\u00a0\u009f\u0001\u0000\u0000\u0000"+
|
||||
"\u00a1\u00a2\u0001\u0000\u0000\u0000\u00a2\u00a0\u0001\u0000\u0000\u0000"+
|
||||
"\u00a2\u00a3\u0001\u0000\u0000\u0000\u00a3\u00a4\u0001\u0000\u0000\u0000"+
|
||||
"\u00a4\u00a5\u0007\b\u0000\u0000\u00a5\u00a6\u0007\u0003\u0000\u0000\u00a6"+
|
||||
"\u00a7\u0007\u0006\u0000\u0000\u00a7\u00a8\u0007\t\u0000\u0000\u00a8\u00a9"+
|
||||
"\u0007\u0003\u0000\u0000\u00a9\u00aa\u0007\u0003\u0000\u0000\u00aa\u00ab"+
|
||||
"\u0007\u0004\u0000\u0000\u00ab$\u0001\u0000\u0000\u0000\u00ac\u00ad\u0007"+
|
||||
"\u0003\u0000\u0000\u00ad\u00ae\u0007\n\u0000\u0000\u00ae\u00af\u0007\u0001"+
|
||||
"\u0000\u0000\u00af\u00b0\u0007\u000b\u0000\u0000\u00b0\u00b2\u0007\u0006"+
|
||||
"\u0000\u0000\u00b1\u00b3\u0007\u000b\u0000\u0000\u00b2\u00b1\u0001\u0000"+
|
||||
"\u0000\u0000\u00b2\u00b3\u0001\u0000\u0000\u0000\u00b3&\u0001\u0000\u0000"+
|
||||
"\u0000\u00b4\u00b5\u0007\u0004\u0000\u0000\u00b5\u00b6\u0007\u0005\u0000"+
|
||||
"\u0000\u00b6\u00b8\u0007\u0006\u0000\u0000\u00b7\u00b9\u0007\u0007\u0000"+
|
||||
"\u0000\u00b8\u00b7\u0001\u0000\u0000\u0000\u00b9\u00ba\u0001\u0000\u0000"+
|
||||
"\u0000\u00ba\u00b8\u0001\u0000\u0000\u0000\u00ba\u00bb\u0001\u0000\u0000"+
|
||||
"\u0000\u00bb\u00bc\u0001\u0000\u0000\u0000\u00bc\u00bd\u0007\u0003\u0000"+
|
||||
"\u0000\u00bd\u00be\u0007\n\u0000\u0000\u00be\u00bf\u0007\u0001\u0000\u0000"+
|
||||
"\u00bf\u00c0\u0007\u000b\u0000\u0000\u00c0\u00c2\u0007\u0006\u0000\u0000"+
|
||||
"\u00c1\u00c3\u0007\u000b\u0000\u0000\u00c2\u00c1\u0001\u0000\u0000\u0000"+
|
||||
"\u00c2\u00c3\u0001\u0000\u0000\u0000\u00c3(\u0001\u0000\u0000\u0000\u00c4"+
|
||||
"\u00c5\u0007\f\u0000\u0000\u00c5\u00c6\u0007\u0003\u0000\u0000\u00c6\u00c7"+
|
||||
"\u0007\r\u0000\u0000\u00c7\u00c8\u0007\u0003\u0000\u0000\u00c8\u00c9\u0007"+
|
||||
"\n\u0000\u0000\u00c9\u00ca\u0007\u000e\u0000\u0000\u00ca*\u0001\u0000"+
|
||||
"\u0000\u0000\u00cb\u00cc\u0007\u0004\u0000\u0000\u00cc\u00cd\u0007\u0005"+
|
||||
"\u0000\u0000\u00cd\u00cf\u0007\u0006\u0000\u0000\u00ce\u00d0\u0007\u0007"+
|
||||
"\u0000\u0000\u00cf\u00ce\u0001\u0000\u0000\u0000\u00d0\u00d1\u0001\u0000"+
|
||||
"\u0000\u0000\u00d1\u00cf\u0001\u0000\u0000\u0000\u00d1\u00d2\u0001\u0000"+
|
||||
"\u0000\u0000\u00d2\u00d3\u0001\u0000\u0000\u0000\u00d3\u00d4\u0007\f\u0000"+
|
||||
"\u0000\u00d4\u00d5\u0007\u0003\u0000\u0000\u00d5\u00d6\u0007\r\u0000\u0000"+
|
||||
"\u00d6\u00d7\u0007\u0003\u0000\u0000\u00d7\u00d8\u0007\n\u0000\u0000\u00d8"+
|
||||
"\u00d9\u0007\u000e\u0000\u0000\u00d9,\u0001\u0000\u0000\u0000\u00da\u00db"+
|
||||
"\u0007\u000f\u0000\u0000\u00db\u00dc\u0007\u0005\u0000\u0000\u00dc\u00dd"+
|
||||
"\u0007\u0004\u0000\u0000\u00dd\u00de\u0007\u0006\u0000\u0000\u00de\u00df"+
|
||||
"\u0007\u0010\u0000\u0000\u00df\u00e0\u0007\u0001\u0000\u0000\u00e0\u00e2"+
|
||||
"\u0007\u0004\u0000\u0000\u00e1\u00e3\u0007\u000b\u0000\u0000\u00e2\u00e1"+
|
||||
"\u0001\u0000\u0000\u0000\u00e2\u00e3\u0001\u0000\u0000\u0000\u00e3.\u0001"+
|
||||
"\u0000\u0000\u0000\u00e4\u00e5\u0007\u0004\u0000\u0000\u00e5\u00e6\u0007"+
|
||||
"\u0005\u0000\u0000\u00e6\u00e8\u0007\u0006\u0000\u0000\u00e7\u00e9\u0007"+
|
||||
"\u0007\u0000\u0000\u00e8\u00e7\u0001\u0000\u0000\u0000\u00e9\u00ea\u0001"+
|
||||
"\u0000\u0000\u0000\u00ea\u00e8\u0001\u0000\u0000\u0000\u00ea\u00eb\u0001"+
|
||||
"\u0000\u0000\u0000\u00eb\u00ec\u0001\u0000\u0000\u0000\u00ec\u00ed\u0007"+
|
||||
"\u000f\u0000\u0000\u00ed\u00ee\u0007\u0005\u0000\u0000\u00ee\u00ef\u0007"+
|
||||
"\u0004\u0000\u0000\u00ef\u00f0\u0007\u0006\u0000\u0000\u00f0\u00f1\u0007"+
|
||||
"\u0010\u0000\u0000\u00f1\u00f2\u0007\u0001\u0000\u0000\u00f2\u00f4\u0007"+
|
||||
"\u0004\u0000\u0000\u00f3\u00f5\u0007\u000b\u0000\u0000\u00f4\u00f3\u0001"+
|
||||
"\u0000\u0000\u0000\u00f4\u00f5\u0001\u0000\u0000\u0000\u00f50\u0001\u0000"+
|
||||
"\u0000\u0000\u00f6\u00f7\u0007\u0001\u0000\u0000\u00f7\u00f8\u0007\u0004"+
|
||||
"\u0000\u0000\u00f82\u0001\u0000\u0000\u0000\u00f9\u00fa\u0007\u0004\u0000"+
|
||||
"\u0000\u00fa\u00fb\u0007\u0005\u0000\u0000\u00fb\u00fd\u0007\u0006\u0000"+
|
||||
"\u0000\u00fc\u00fe\u0007\u0007\u0000\u0000\u00fd\u00fc\u0001\u0000\u0000"+
|
||||
"\u0000\u00fe\u00ff\u0001\u0000\u0000\u0000\u00ff\u00fd\u0001\u0000\u0000"+
|
||||
"\u0000\u00ff\u0100\u0001\u0000\u0000\u0000\u0100\u0101\u0001\u0000\u0000"+
|
||||
"\u0000\u0101\u0102\u0007\u0001\u0000\u0000\u0102\u0103\u0007\u0004\u0000"+
|
||||
"\u0000\u01034\u0001\u0000\u0000\u0000\u0104\u0105\u0007\u0004\u0000\u0000"+
|
||||
"\u0105\u0106\u0007\u0005\u0000\u0000\u0106\u0107\u0007\u0006\u0000\u0000"+
|
||||
"\u01076\u0001\u0000\u0000\u0000\u0108\u0109\u0007\u0010\u0000\u0000\u0109"+
|
||||
"\u010a\u0007\u0004\u0000\u0000\u010a\u010b\u0007\u0011\u0000\u0000\u010b"+
|
||||
"8\u0001\u0000\u0000\u0000\u010c\u010d\u0007\u0005\u0000\u0000\u010d\u010e"+
|
||||
"\u0007\f\u0000\u0000\u010e:\u0001\u0000\u0000\u0000\u010f\u0110\u0007"+
|
||||
"\u0012\u0000\u0000\u0110\u0111\u0007\u0010\u0000\u0000\u0111\u0112\u0007"+
|
||||
"\u000b\u0000\u0000\u0112<\u0001\u0000\u0000\u0000\u0113\u0114\u0007\u0012"+
|
||||
"\u0000\u0000\u0114\u0115\u0007\u0010\u0000\u0000\u0115\u0116\u0007\u000b"+
|
||||
"\u0000\u0000\u0116\u0117\u0007\u0010\u0000\u0000\u0117\u0118\u0007\u0004"+
|
||||
"\u0000\u0000\u0118\u0119\u0007\u0013\u0000\u0000\u0119>\u0001\u0000\u0000"+
|
||||
"\u0000\u011a\u011b\u0007\u0012\u0000\u0000\u011b\u011c\u0007\u0010\u0000"+
|
||||
"\u0000\u011c\u011d\u0007\u000b\u0000\u0000\u011d\u011e\u0007\u0010\u0000"+
|
||||
"\u0000\u011e\u011f\u0007\u0000\u0000\u0000\u011f\u0120\u0007\u0000\u0000"+
|
||||
"\u0000\u0120@\u0001\u0000\u0000\u0000\u0121\u0122\u0007\u0012\u0000\u0000"+
|
||||
"\u0122\u0123\u0007\u0010\u0000\u0000\u0123\u0124\u0007\u000b\u0000\u0000"+
|
||||
"\u0124\u0125\u0007\u0004\u0000\u0000\u0125\u0126\u0007\u0005\u0000\u0000"+
|
||||
"\u0126\u0127\u0007\u0004\u0000\u0000\u0127\u0128\u0007\u0003\u0000\u0000"+
|
||||
"\u0128B\u0001\u0000\u0000\u0000\u0129\u012a\u0007\u0006\u0000\u0000\u012a"+
|
||||
"\u012b\u0007\f\u0000\u0000\u012b\u012c\u0007\u0014\u0000\u0000\u012c\u0133"+
|
||||
"\u0007\u0003\u0000\u0000\u012d\u012e\u0007\u0015\u0000\u0000\u012e\u012f"+
|
||||
"\u0007\u0010\u0000\u0000\u012f\u0130\u0007\u0000\u0000\u0000\u0130\u0131"+
|
||||
"\u0007\u000b\u0000\u0000\u0131\u0133\u0007\u0003\u0000\u0000\u0132\u0129"+
|
||||
"\u0001\u0000\u0000\u0000\u0132\u012d\u0001\u0000\u0000\u0000\u0133D\u0001"+
|
||||
"\u0000\u0000\u0000\u0134\u0136\u0003M&\u0000\u0135\u0134\u0001\u0000\u0000"+
|
||||
"\u0000\u0136\u0137\u0001\u0000\u0000\u0000\u0137\u0135\u0001\u0000\u0000"+
|
||||
"\u0000\u0137\u0138\u0001\u0000\u0000\u0000\u0138\u013f\u0001\u0000\u0000"+
|
||||
"\u0000\u0139\u013b\u0005.\u0000\u0000\u013a\u013c\u0003M&\u0000\u013b"+
|
||||
"\u013a\u0001\u0000\u0000\u0000\u013c\u013d\u0001\u0000\u0000\u0000\u013d"+
|
||||
"\u013b\u0001\u0000\u0000\u0000\u013d\u013e\u0001\u0000\u0000\u0000\u013e"+
|
||||
"\u0140\u0001\u0000\u0000\u0000\u013f\u0139\u0001\u0000\u0000\u0000\u013f"+
|
||||
"\u0140\u0001\u0000\u0000\u0000\u0140F\u0001\u0000\u0000\u0000\u0141\u0147"+
|
||||
"\u0005\"\u0000\u0000\u0142\u0146\b\u0016\u0000\u0000\u0143\u0144\u0005"+
|
||||
"\\\u0000\u0000\u0144\u0146\t\u0000\u0000\u0000\u0145\u0142\u0001\u0000"+
|
||||
"\u0000\u0000\u0145\u0143\u0001\u0000\u0000\u0000\u0146\u0149\u0001\u0000"+
|
||||
"\u0000\u0000\u0147\u0145\u0001\u0000\u0000\u0000\u0147\u0148\u0001\u0000"+
|
||||
"\u0000\u0000\u0148\u014a\u0001\u0000\u0000\u0000\u0149\u0147\u0001\u0000"+
|
||||
"\u0000\u0000\u014a\u0156\u0005\"\u0000\u0000\u014b\u0151\u0005\'\u0000"+
|
||||
"\u0000\u014c\u0150\b\u0017\u0000\u0000\u014d\u014e\u0005\\\u0000\u0000"+
|
||||
"\u014e\u0150\t\u0000\u0000\u0000\u014f\u014c\u0001\u0000\u0000\u0000\u014f"+
|
||||
"\u014d\u0001\u0000\u0000\u0000\u0150\u0153\u0001\u0000\u0000\u0000\u0151"+
|
||||
"\u014f\u0001\u0000\u0000\u0000\u0151\u0152\u0001\u0000\u0000\u0000\u0152"+
|
||||
"\u0154\u0001\u0000\u0000\u0000\u0153\u0151\u0001\u0000\u0000\u0000\u0154"+
|
||||
"\u0156\u0005\'\u0000\u0000\u0155\u0141\u0001\u0000\u0000\u0000\u0155\u014b"+
|
||||
"\u0001\u0000\u0000\u0000\u0156H\u0001\u0000\u0000\u0000\u0157\u015b\u0007"+
|
||||
"\u0018\u0000\u0000\u0158\u015a\u0007\u0019\u0000\u0000\u0159\u0158\u0001"+
|
||||
"\u0000\u0000\u0000\u015a\u015d\u0001\u0000\u0000\u0000\u015b\u0159\u0001"+
|
||||
"\u0000\u0000\u0000\u015b\u015c\u0001\u0000\u0000\u0000\u015cJ\u0001\u0000"+
|
||||
"\u0000\u0000\u015d\u015b\u0001\u0000\u0000\u0000\u015e\u0160\u0007\u001a"+
|
||||
"\u0000\u0000\u015f\u015e\u0001\u0000\u0000\u0000\u0160\u0161\u0001\u0000"+
|
||||
"\u0000\u0000\u0161\u015f\u0001\u0000\u0000\u0000\u0161\u0162\u0001\u0000"+
|
||||
"\u0000\u0000\u0162\u0163\u0001\u0000\u0000\u0000\u0163\u0164\u0006%\u0000"+
|
||||
"\u0000\u0164L\u0001\u0000\u0000\u0000\u0165\u0166\u0007\u001b\u0000\u0000"+
|
||||
"\u0166N\u0001\u0000\u0000\u0000\u0018\u0000\\y\u008c\u00a2\u00b2\u00ba"+
|
||||
"\u00c2\u00d1\u00e2\u00ea\u00f4\u00ff\u0132\u0137\u013d\u013f\u0145\u0147"+
|
||||
"\u014f\u0151\u0155\u015b\u0161\u0001\u0006\u0000\u0000";
|
||||
public static final ATN _ATN =
|
||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||
static {
|
||||
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
|
||||
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
|
||||
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
49
frontend/src/query-grammar/.antlr/FilterQueryLexer.tokens
Normal file
49
frontend/src/query-grammar/.antlr/FilterQueryLexer.tokens
Normal file
@ -0,0 +1,49 @@
|
||||
LPAREN=1
|
||||
RPAREN=2
|
||||
LBRACK=3
|
||||
RBRACK=4
|
||||
COMMA=5
|
||||
EQUALS=6
|
||||
NOT_EQUALS=7
|
||||
NEQ=8
|
||||
LT=9
|
||||
LE=10
|
||||
GT=11
|
||||
GE=12
|
||||
LIKE=13
|
||||
NOT_LIKE=14
|
||||
ILIKE=15
|
||||
NOT_ILIKE=16
|
||||
BETWEEN=17
|
||||
NOT_BETWEEN=18
|
||||
EXISTS=19
|
||||
NOT_EXISTS=20
|
||||
REGEXP=21
|
||||
NOT_REGEXP=22
|
||||
CONTAINS=23
|
||||
NOT_CONTAINS=24
|
||||
IN=25
|
||||
NOT_IN=26
|
||||
NOT=27
|
||||
AND=28
|
||||
OR=29
|
||||
HAS=30
|
||||
HASANY=31
|
||||
HASALL=32
|
||||
HASNONE=33
|
||||
BOOL=34
|
||||
NUMBER=35
|
||||
QUOTED_TEXT=36
|
||||
KEY=37
|
||||
WS=38
|
||||
'('=1
|
||||
')'=2
|
||||
'['=3
|
||||
']'=4
|
||||
','=5
|
||||
'!='=7
|
||||
'<>'=8
|
||||
'<'=9
|
||||
'<='=10
|
||||
'>'=11
|
||||
'>='=12
|
||||
1413
frontend/src/query-grammar/.antlr/FilterQueryParser.java
Normal file
1413
frontend/src/query-grammar/.antlr/FilterQueryParser.java
Normal file
File diff suppressed because it is too large
Load Diff
39
frontend/src/types/antlrQueryTypes.ts
Normal file
39
frontend/src/types/antlrQueryTypes.ts
Normal file
@ -0,0 +1,39 @@
|
||||
export interface IValidationResult {
|
||||
isValid: boolean;
|
||||
message: string;
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
export interface IToken {
|
||||
type: number;
|
||||
text: string;
|
||||
start: number;
|
||||
stop: number;
|
||||
channel?: number;
|
||||
}
|
||||
|
||||
export interface IQueryContext {
|
||||
tokenType: number;
|
||||
text: string;
|
||||
start: number;
|
||||
stop: number;
|
||||
currentToken: string;
|
||||
isInValue: boolean;
|
||||
isInKey: boolean;
|
||||
isInOperator: boolean;
|
||||
isInFunction: boolean;
|
||||
}
|
||||
|
||||
export interface IDetailedError {
|
||||
message: string;
|
||||
line: number;
|
||||
column: number;
|
||||
offendingSymbol?: string;
|
||||
expectedTokens?: string[];
|
||||
}
|
||||
|
||||
export interface ASTNode {
|
||||
type: string;
|
||||
value?: string;
|
||||
children?: ASTNode[];
|
||||
}
|
||||
340
frontend/src/utils/antlrQueryUtils.ts
Normal file
340
frontend/src/utils/antlrQueryUtils.ts
Normal file
@ -0,0 +1,340 @@
|
||||
/* eslint-disable sonarjs/no-collapsible-if */
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { CharStreams, CommonTokenStream } from 'antlr4';
|
||||
import FilterQueryLexer from 'parser/FilterQueryLexer';
|
||||
import FilterQueryParser from 'parser/FilterQueryParser';
|
||||
import {
|
||||
IDetailedError,
|
||||
IQueryContext,
|
||||
IToken,
|
||||
IValidationResult,
|
||||
} from 'types/antlrQueryTypes';
|
||||
|
||||
// Custom error listener to capture ANTLR errors
|
||||
class QueryErrorListener {
|
||||
private errors: IDetailedError[] = [];
|
||||
|
||||
syntaxError(
|
||||
_recognizer: any,
|
||||
offendingSymbol: any,
|
||||
line: number,
|
||||
column: number,
|
||||
msg: string,
|
||||
): void {
|
||||
// For unterminated quotes, we only want to show one error
|
||||
if (this.hasUnterminatedQuoteError() && msg.includes('expecting')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const error: IDetailedError = {
|
||||
message: msg,
|
||||
line,
|
||||
column,
|
||||
offendingSymbol: offendingSymbol?.text || String(offendingSymbol),
|
||||
};
|
||||
|
||||
// Extract expected tokens if available
|
||||
if (msg.includes('expecting')) {
|
||||
const expectedTokens = msg
|
||||
.split('expecting')[1]
|
||||
.trim()
|
||||
.split(',')
|
||||
.map((token) => token.trim());
|
||||
error.expectedTokens = expectedTokens;
|
||||
}
|
||||
|
||||
// Check if this is a duplicate error (same location and similar message)
|
||||
const isDuplicate = this.errors.some(
|
||||
(e) =>
|
||||
e.line === line &&
|
||||
e.column === column &&
|
||||
this.isSimilarError(e.message, msg),
|
||||
);
|
||||
|
||||
if (!isDuplicate) {
|
||||
this.errors.push(error);
|
||||
}
|
||||
}
|
||||
|
||||
private hasUnterminatedQuoteError(): boolean {
|
||||
return this.errors.some(
|
||||
(error) =>
|
||||
error.message.includes('unterminated') ||
|
||||
(error.message.includes('missing') && error.message.includes("'")),
|
||||
);
|
||||
}
|
||||
|
||||
private isSimilarError = (msg1: string, msg2: string): boolean => {
|
||||
// Consider errors similar if they're for the same core issue
|
||||
const normalize = (msg: string): string =>
|
||||
msg.toLowerCase().replace(/['"`]/g, 'quote').replace(/\s+/g, ' ').trim();
|
||||
|
||||
return normalize(msg1) === normalize(msg2);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
reportAmbiguity = (): void => {};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
reportAttemptingFullContext = (): void => {};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
reportContextSensitivity = (): void => {};
|
||||
|
||||
getErrors(): IDetailedError[] {
|
||||
return this.errors;
|
||||
}
|
||||
|
||||
hasErrors(): boolean {
|
||||
return this.errors.length > 0;
|
||||
}
|
||||
|
||||
getFormattedErrors(): string[] {
|
||||
return this.errors.map((error) => {
|
||||
let message = `Line ${error.line}:${error.column} - ${error.message}`;
|
||||
|
||||
if (error.offendingSymbol && error.offendingSymbol !== 'undefined') {
|
||||
message += `\nOffending symbol: '${error.offendingSymbol}'`;
|
||||
}
|
||||
|
||||
if (error.expectedTokens && error.expectedTokens.length > 0) {
|
||||
message += `\nExpected: ${error.expectedTokens.join(', ')}`;
|
||||
}
|
||||
|
||||
return message;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const validateQuery = (query: string): IValidationResult => {
|
||||
// Empty query is considered invalid
|
||||
if (!query.trim()) {
|
||||
return {
|
||||
isValid: false,
|
||||
message: 'Query cannot be empty',
|
||||
errors: ['Query cannot be empty'],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const errorListener = new QueryErrorListener();
|
||||
const inputStream = CharStreams.fromString(query);
|
||||
|
||||
// Setup lexer
|
||||
const lexer = new FilterQueryLexer(inputStream);
|
||||
lexer.removeErrorListeners(); // Remove default error listeners
|
||||
lexer.addErrorListener(errorListener);
|
||||
|
||||
// Setup parser
|
||||
const tokenStream = new CommonTokenStream(lexer);
|
||||
const parser = new FilterQueryParser(tokenStream);
|
||||
parser.removeErrorListeners(); // Remove default error listeners
|
||||
parser.addErrorListener(errorListener);
|
||||
|
||||
// Try parsing
|
||||
const parsedTree = parser.query();
|
||||
|
||||
console.log('parsedTree', parsedTree);
|
||||
|
||||
// Check if any errors were captured
|
||||
if (errorListener.hasErrors()) {
|
||||
return {
|
||||
isValid: false,
|
||||
message: 'Query syntax error',
|
||||
errors: errorListener.getFormattedErrors(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
isValid: true,
|
||||
message: 'Query is valid!',
|
||||
errors: [],
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Invalid query syntax';
|
||||
return {
|
||||
isValid: false,
|
||||
message: 'Invalid query syntax',
|
||||
errors: [errorMessage],
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export function getQueryContextAtCursor(
|
||||
query: string,
|
||||
cursorIndex: number,
|
||||
): IQueryContext {
|
||||
try {
|
||||
// Create input stream and lexer
|
||||
const input = query || '';
|
||||
const chars = CharStreams.fromString(input);
|
||||
const lexer = new FilterQueryLexer(chars);
|
||||
|
||||
// Create token stream and force token generation
|
||||
const tokenStream = new CommonTokenStream(lexer);
|
||||
tokenStream.fill();
|
||||
|
||||
// Get all tokens including whitespace
|
||||
const allTokens = tokenStream.tokens as IToken[];
|
||||
|
||||
// Find exact token at cursor, including whitespace
|
||||
let exactToken: IToken | null = null;
|
||||
let previousToken: IToken | null = null;
|
||||
let nextToken: IToken | null = null;
|
||||
|
||||
// Handle cursor at the very end of input
|
||||
if (cursorIndex === input.length && allTokens.length > 0) {
|
||||
const lastRealToken = allTokens
|
||||
.filter((t) => t.type !== FilterQueryLexer.EOF)
|
||||
.pop();
|
||||
if (lastRealToken) {
|
||||
exactToken = lastRealToken;
|
||||
previousToken =
|
||||
allTokens.filter((t) => t.stop < lastRealToken.start).pop() || null;
|
||||
}
|
||||
} else {
|
||||
// Normal token search
|
||||
for (let i = 0; i < allTokens.length; i++) {
|
||||
const token = allTokens[i];
|
||||
// Skip EOF token in normal search
|
||||
if (token.type === FilterQueryLexer.EOF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if cursor is within token bounds (inclusive)
|
||||
if (token.start <= cursorIndex && cursorIndex <= token.stop + 1) {
|
||||
exactToken = token;
|
||||
previousToken = i > 0 ? allTokens[i - 1] : null;
|
||||
nextToken = i < allTokens.length - 1 ? allTokens[i + 1] : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If cursor is between tokens, find surrounding tokens
|
||||
if (!exactToken) {
|
||||
for (let i = 0; i < allTokens.length - 1; i++) {
|
||||
const current = allTokens[i];
|
||||
const next = allTokens[i + 1];
|
||||
if (current.type === FilterQueryLexer.EOF) {
|
||||
continue;
|
||||
}
|
||||
if (next.type === FilterQueryLexer.EOF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.stop + 1 < cursorIndex && cursorIndex < next.start) {
|
||||
previousToken = current;
|
||||
nextToken = next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Cursor context:', {
|
||||
cursorIndex,
|
||||
query,
|
||||
exact: exactToken,
|
||||
prev: previousToken,
|
||||
next: nextToken,
|
||||
});
|
||||
|
||||
// Determine the context based on cursor position and surrounding tokens
|
||||
let currentToken: IToken | null = null;
|
||||
|
||||
if (exactToken) {
|
||||
// If cursor is in a non-whitespace token, use that
|
||||
if (exactToken.channel === 0) {
|
||||
currentToken = exactToken;
|
||||
} else {
|
||||
// If in whitespace, use the previous non-whitespace token
|
||||
currentToken = previousToken?.channel === 0 ? previousToken : nextToken;
|
||||
}
|
||||
} else if (previousToken?.channel === 0) {
|
||||
// If between tokens, prefer the previous non-whitespace token
|
||||
currentToken = previousToken;
|
||||
} else if (nextToken?.channel === 0) {
|
||||
// Otherwise use the next non-whitespace token
|
||||
currentToken = nextToken;
|
||||
}
|
||||
|
||||
// If still no token (empty query or all whitespace), return default context
|
||||
if (!currentToken) {
|
||||
return {
|
||||
tokenType: -1,
|
||||
text: '',
|
||||
start: cursorIndex,
|
||||
stop: cursorIndex,
|
||||
currentToken: '',
|
||||
isInValue: false,
|
||||
isInKey: false,
|
||||
isInOperator: false,
|
||||
isInFunction: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Determine the context based on the token type
|
||||
const isInValue = [
|
||||
FilterQueryLexer.QUOTED_TEXT,
|
||||
FilterQueryLexer.NUMBER,
|
||||
FilterQueryLexer.BOOL,
|
||||
].includes(currentToken.type);
|
||||
|
||||
const isInKey = currentToken.type === FilterQueryLexer.KEY;
|
||||
|
||||
const isInOperator = [
|
||||
FilterQueryLexer.EQUALS,
|
||||
FilterQueryLexer.NOT_EQUALS,
|
||||
FilterQueryLexer.NEQ,
|
||||
FilterQueryLexer.LT,
|
||||
FilterQueryLexer.LE,
|
||||
FilterQueryLexer.GT,
|
||||
FilterQueryLexer.GE,
|
||||
FilterQueryLexer.LIKE,
|
||||
FilterQueryLexer.NOT_LIKE,
|
||||
FilterQueryLexer.ILIKE,
|
||||
FilterQueryLexer.NOT_ILIKE,
|
||||
FilterQueryLexer.BETWEEN,
|
||||
FilterQueryLexer.EXISTS,
|
||||
FilterQueryLexer.REGEXP,
|
||||
FilterQueryLexer.CONTAINS,
|
||||
FilterQueryLexer.IN,
|
||||
FilterQueryLexer.NOT,
|
||||
].includes(currentToken.type);
|
||||
|
||||
const isInFunction = [
|
||||
FilterQueryLexer.HAS,
|
||||
FilterQueryLexer.HASANY,
|
||||
FilterQueryLexer.HASALL,
|
||||
FilterQueryLexer.HASNONE,
|
||||
].includes(currentToken.type);
|
||||
|
||||
return {
|
||||
tokenType: currentToken.type,
|
||||
text: currentToken.text,
|
||||
start: currentToken.start,
|
||||
stop: currentToken.stop,
|
||||
currentToken: currentToken.text,
|
||||
isInValue,
|
||||
isInKey,
|
||||
isInOperator,
|
||||
isInFunction,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in getQueryContextAtCursor:', error);
|
||||
return {
|
||||
tokenType: -1,
|
||||
text: '',
|
||||
start: cursorIndex,
|
||||
stop: cursorIndex,
|
||||
currentToken: '',
|
||||
isInValue: false,
|
||||
isInKey: false,
|
||||
isInOperator: false,
|
||||
isInFunction: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user