♻️ 重构tree-sitter-tsf
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
# 完整的 TSLX 块匹配规则
|
||||
|
||||
## 基本原则
|
||||
- 在 `<?tslx>` 之后进入 `tslx_block`,默认所有内容都是文本(`tslx_content`)
|
||||
- Scanner 通过 lookahead 判断 `<?tsl` 和 `<?=` 的行为
|
||||
|
||||
---
|
||||
|
||||
## 匹配规则
|
||||
|
||||
### 规则 1:配对的 `<?tsl ... ?>`
|
||||
**条件**:遇到 `<?tsl` 且能找到对应的 `?>`
|
||||
**行为**:匹配为 `tsl_statement_block`
|
||||
**Token 序列**:`tsl_statement_start_tag` → `statement...` → `tsl_statement_end_tag`
|
||||
**结果**:`tslx_block` 继续
|
||||
|
||||
---
|
||||
|
||||
### 规则 2:配对的 `<?= ... ?>`
|
||||
**条件**:遇到 `<?=` 且能找到对应的 `?>`
|
||||
**行为**:匹配为 `tsl_expression_block`
|
||||
**Token 序列**:`tsl_expression_start_tag` → `expression` → `tsl_expression_end_tag`
|
||||
**结果**:`tslx_block` 继续
|
||||
|
||||
---
|
||||
|
||||
### 规则 3:未配对的 `<?tsl`(关键特性)
|
||||
**条件**:遇到 `<?tsl` 但找不到对应的 `?>`
|
||||
**行为**:
|
||||
- Scanner 通过 lookahead 判断后面没有 `?>`
|
||||
- **`<?tsl` 本身被识别为 `tslx_end_tag`**(不是生成额外的 token)
|
||||
- `tslx_block` 结束
|
||||
- Parser 跳出 `tslx_block`,继续解析后续内容(如 `a := 1;`)
|
||||
|
||||
**Token 序列**:
|
||||
```
|
||||
tslx_end_tag: "<?tsl" ← 这个 token 的文本内容就是 "<?tsl"
|
||||
```
|
||||
|
||||
**结果**:`tslx_block` 结束,后续内容由 `root` 的其他规则处理
|
||||
|
||||
---
|
||||
|
||||
### 规则 4:未配对的 `<?=`(错误情况)
|
||||
**条件**:遇到 `<?=` 但找不到对应的 `?>`
|
||||
**行为**:
|
||||
- Scanner 返回 `tsl_expression_start_tag`
|
||||
- Parser 期望 `expression` 和 `tsl_expression_end_tag`
|
||||
- 找不到 `?>` 导致**语法错误**
|
||||
|
||||
**结果**:Parser 报错
|
||||
|
||||
---
|
||||
|
||||
### 规则 5:到达 EOF
|
||||
**条件**:到达文件末尾,且之前没有遇到未配对的 `<?tsl`
|
||||
**行为**:在 EOF 位置生成 `tslx_end_tag`
|
||||
**结果**:`tslx_block` 正常结束
|
||||
|
||||
---
|
||||
|
||||
## Scanner Lookahead 策略
|
||||
|
||||
Scanner 需要判断 `<?tsl` 或 `<?=` 后面是否有匹配的 `?>`:
|
||||
|
||||
### 推荐策略(需选择其一):
|
||||
|
||||
**策略 A:扫描到换行或分号**
|
||||
```
|
||||
<?tsl ← 向前扫描
|
||||
a := 1; ← 遇到 ; 前没有 ?>,判定为未配对
|
||||
```
|
||||
- 优点:快速判断,符合单行语句的直觉
|
||||
- 缺点:多行语句可能误判
|
||||
|
||||
**策略 B:扫描到下一个 `<?` 或 EOF**
|
||||
```
|
||||
<?tsl ← 向前扫描
|
||||
a := 1;
|
||||
<?tsl ... ← 遇到下一个 <? 前没有 ?>,判定为未配对
|
||||
```
|
||||
- 优点:支持多行语句
|
||||
- 缺点:扫描距离可能较长
|
||||
|
||||
**策略 C:扫描固定距离(如 1000 字符)**
|
||||
```
|
||||
<?tsl ← 向前看 N 个字符
|
||||
... ← 如果在范围内找不到 ?>,判定为未配对
|
||||
```
|
||||
- 优点:性能可控
|
||||
- 缺点:可能误判超长的配对块
|
||||
|
||||
**当前实现**:_[填入你选择的策略]_
|
||||
|
||||
---
|
||||
|
||||
## 示例解析
|
||||
|
||||
### 示例 1:未配对的 `<?tsl`
|
||||
|
||||
#### 输入:
|
||||
```typescript
|
||||
|
||||
aaaa
|
||||
<?tsl
|
||||
a := 1;
|
||||
```
|
||||
|
||||
#### Token 序列:
|
||||
```
|
||||
1. tslx_tag "<?tslx>"
|
||||
2. tslx_content "\naaaa\n"
|
||||
3. tslx_end_tag "<?tsl" ← <?tsl 本身就是这个 token
|
||||
4. identifier "a"
|
||||
5. := ":="
|
||||
6. number "1"
|
||||
7. ; ";"
|
||||
```
|
||||
|
||||
#### AST 结构:
|
||||
```
|
||||
root
|
||||
├── tslx_block
|
||||
│ ├── tslx_tag: "<?tslx>"
|
||||
│ ├── tslx_content: "\naaaa\n"
|
||||
│ └── tslx_end_tag: "<?tsl"
|
||||
└── var_declaration
|
||||
├── name: "a"
|
||||
└── value: 1
|
||||
```
|
||||
|
||||
#### 说明:
|
||||
- `<?tsl` 触发 `tslx_block` 结束
|
||||
- `a := 1;` 在 `tslx_block` **外部**,由 `root` 的 `var_declaration` 匹配
|
||||
|
||||
---
|
||||
|
||||
### 示例 2:全部配对 + EOF
|
||||
|
||||
#### 输入:
|
||||
```typescript
|
||||
|
||||
aaaa
|
||||
|
||||
bbb
|
||||
```
|
||||
|
||||
#### Token 序列:
|
||||
```
|
||||
1. tslx_tag "<?tslx>"
|
||||
2. tslx_content "\naaaa\n"
|
||||
3. tsl_statement_start_tag "<?tsl"
|
||||
4. identifier "echo"
|
||||
5. number "1"
|
||||
6. ; ";"
|
||||
7. tsl_statement_end_tag "?>"
|
||||
8. tslx_content "\nbbb\n"
|
||||
9. tslx_end_tag "" ← EOF 位置生成
|
||||
```
|
||||
|
||||
#### AST 结构:
|
||||
```
|
||||
root
|
||||
└── tslx_block
|
||||
├── tslx_tag: "<?tslx>"
|
||||
├── tslx_content: "\naaaa\n"
|
||||
├── tsl_statement_block
|
||||
│ └── expression_statement
|
||||
│ └── call_expression: echo(1)
|
||||
├── tslx_content: "\nbbb\n"
|
||||
└── tslx_end_tag: (EOF)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 示例 3:未配对的 `<?=`(错误)
|
||||
|
||||
#### 输入:
|
||||
```typescript
|
||||
|
||||
<?=
|
||||
a + 1
|
||||
```
|
||||
|
||||
#### Token 序列:
|
||||
```
|
||||
1. tslx_tag "<?tslx>"
|
||||
2. tslx_content "\n"
|
||||
3. tsl_expression_start_tag "<?="
|
||||
4. identifier "a"
|
||||
5. + "+"
|
||||
6. number "1"
|
||||
[ERROR] 期望 tsl_expression_end_tag (?>),但遇到 EOF
|
||||
```
|
||||
|
||||
#### 结果:
|
||||
**语法错误**:`<?=` 必须有匹配的 `?>`
|
||||
|
||||
---
|
||||
|
||||
### 示例 4:混合使用
|
||||
|
||||
#### 输入:
|
||||
```typescript
|
||||
|
||||
text1
|
||||
|
||||
text2
|
||||
<?= 1 + 1 ?>
|
||||
text3
|
||||
<?tsl
|
||||
var x := 1;
|
||||
```
|
||||
|
||||
#### Token 序列:
|
||||
```
|
||||
1. tslx_tag "<?tslx>"
|
||||
2. tslx_content "\ntext1\n"
|
||||
3. tsl_statement_start_tag "<?tsl"
|
||||
4. ... (echo "hello")
|
||||
5. tsl_statement_end_tag "?>"
|
||||
6. tslx_content "\ntext2\n"
|
||||
7. tsl_expression_start_tag "<?="
|
||||
8. ... (1 + 1)
|
||||
9. tsl_expression_end_tag "?>"
|
||||
10. tslx_content "\ntext3\n"
|
||||
11. tslx_end_tag "<?tsl" ← 未配对,结束 tslx_block
|
||||
12. identifier "var"
|
||||
13. ... (x := 1)
|
||||
```
|
||||
|
||||
#### AST 结构:
|
||||
```
|
||||
root
|
||||
├── tslx_block
|
||||
│ ├── tslx_tag
|
||||
│ ├── tslx_content: "\ntext1\n"
|
||||
│ ├── tsl_statement_block: echo("hello")
|
||||
│ ├── tslx_content: "\ntext2\n"
|
||||
│ ├── tsl_expression_block: 1 + 1
|
||||
│ ├── tslx_content: "\ntext3\n"
|
||||
│ └── tslx_end_tag: "<?tsl"
|
||||
└── var_declaration: x := 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Grammar.js 修改建议
|
||||
|
||||
### 当前定义:
|
||||
```javascript
|
||||
tslx_block: ($) =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.tslx_tag,
|
||||
repeat(
|
||||
choice(
|
||||
$.tslx_content,
|
||||
$._tsl_statement_block,
|
||||
$._tsl_expression_block,
|
||||
$.tslx_end_tag // ❌ 问题:允许 end_tag 后继续匹配
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
```
|
||||
|
||||
### 建议修改:
|
||||
```javascript
|
||||
tslx_block: ($) =>
|
||||
prec.right(
|
||||
seq(
|
||||
$.tslx_tag,
|
||||
repeat(
|
||||
choice(
|
||||
$.tslx_content,
|
||||
$._tsl_statement_block,
|
||||
$._tsl_expression_block,
|
||||
),
|
||||
),
|
||||
$.tslx_end_tag // ✅ 移到 repeat 外面,作为结束标记
|
||||
),
|
||||
),
|
||||
```
|
||||
|
||||
**理由**:
|
||||
- `tslx_end_tag` 是 `tslx_block` 的**终结符**,不应该在循环体内
|
||||
- 这样确保 `tslx_end_tag` 后不会再匹配 `tslx_content` 等内容
|
||||
|
||||
---
|
||||
|
||||
## 核心要点总结
|
||||
|
||||
1. ✅ `<?tsl` 有**双重身份**:
|
||||
- 有 `?>` → `tsl_statement_start_tag`
|
||||
- 无 `?>` → `tslx_end_tag`
|
||||
|
||||
2. ✅ `<?=` **必须配对**,否则语法错误
|
||||
|
||||
3. ✅ `<?tsl` 作为 `tslx_end_tag` 时,其文本内容就是 `"<?tsl"`
|
||||
|
||||
4. ✅ Scanner 通过 **lookahead** 判断是否有匹配的 `?>`
|
||||
|
||||
5. ✅ `tslx_end_tag` 在 Grammar 中应该是 `tslx_block` 的**终结符**
|
||||
|
||||
6. ✅ EOF 时自动生成 `tslx_end_tag` 来正常结束 `tslx_block`
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tree-sitter-tsf_binding",
|
||||
"dependencies": [
|
||||
"<!(node -p \"require('node-addon-api').targets\"):node_addon_api_except"
|
||||
],
|
||||
"include_dirs": [
|
||||
"src"
|
||||
],
|
||||
"sources": [
|
||||
"bindings/node/binding.cc",
|
||||
"src/parser.c",
|
||||
"src/scanner.c"
|
||||
],
|
||||
"conditions": [
|
||||
["OS!='win'", {
|
||||
"cflags_c": [
|
||||
"-std=c11"
|
||||
]
|
||||
}, {
|
||||
"cflags_c": [
|
||||
"/std:c11",
|
||||
"/utf-8"
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include <napi.h>
|
||||
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
|
||||
extern "C" TSLanguage *tree_sitter_tsf();
|
||||
|
||||
// "tree_sitter_your_language_binding" is the symbol that Node.js looks for.
|
||||
Napi::Object Init(Napi::Env env, Napi::Object exports) {
|
||||
exports["name"] = Napi::String::New(env, "tsf");
|
||||
auto language = Napi::External<TSLanguage>::New(env, tree_sitter_tsf());
|
||||
exports["language"] = language;
|
||||
return exports;
|
||||
}
|
||||
|
||||
NODE_API_MODULE(tree_sitter_tsf_binding, Init)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,437 @@
|
||||
#include <wctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "tree_sitter/parser.h"
|
||||
|
||||
/* #define DEBUG 1 */
|
||||
#if DEBUG
|
||||
#define LOG(...) fprintf(stderr, "[SCANNER] " __VA_ARGS__)
|
||||
#else
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
enum TokenType
|
||||
{
|
||||
TSLX_CONTENT,
|
||||
TSL_STATEMENT_START_TAG,
|
||||
TSL_STATEMENT_END_TAG,
|
||||
TSL_EXPRESSION_START_TAG,
|
||||
TSL_EXPRESSION_END_TAG,
|
||||
TSLX_END_TAG
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
STATE_ROOT,
|
||||
STATE_TSLX,
|
||||
STATE_TSL_STATEMENT,
|
||||
STATE_TSL_EXPRESSION
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
enum State* states;
|
||||
size_t capacity;
|
||||
size_t size;
|
||||
} StateStack;
|
||||
|
||||
static void stack_init(StateStack* stack)
|
||||
{
|
||||
stack->capacity = 8;
|
||||
stack->size = 0;
|
||||
stack->states = malloc(stack->capacity * sizeof(enum State));
|
||||
if (stack->states)
|
||||
{
|
||||
stack->states[0] = STATE_ROOT;
|
||||
stack->size = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void stack_free(StateStack* stack)
|
||||
{
|
||||
if (stack->states)
|
||||
{
|
||||
free(stack->states);
|
||||
stack->states = NULL;
|
||||
}
|
||||
stack->size = 0;
|
||||
stack->capacity = 0;
|
||||
}
|
||||
|
||||
static void stack_push(StateStack* stack, enum State state)
|
||||
{
|
||||
if (stack->size >= stack->capacity)
|
||||
{
|
||||
stack->capacity *= 2;
|
||||
stack->states = realloc(stack->states, stack->capacity * sizeof(enum State));
|
||||
}
|
||||
if (stack->states)
|
||||
{
|
||||
stack->states[stack->size++] = state;
|
||||
}
|
||||
}
|
||||
|
||||
static enum State stack_pop(StateStack* stack)
|
||||
{
|
||||
if (stack->size > 1)
|
||||
{
|
||||
return stack->states[--stack->size];
|
||||
}
|
||||
return STATE_ROOT;
|
||||
}
|
||||
|
||||
static enum State stack_top(const StateStack* stack)
|
||||
{
|
||||
return stack->size > 0 ? stack->states[stack->size - 1] : STATE_ROOT;
|
||||
}
|
||||
|
||||
void* tree_sitter_tsf_external_scanner_create()
|
||||
{
|
||||
StateStack* stack = malloc(sizeof(StateStack));
|
||||
if (stack)
|
||||
{
|
||||
stack_init(stack);
|
||||
}
|
||||
LOG("Scanner created\n");
|
||||
return stack;
|
||||
}
|
||||
|
||||
void tree_sitter_tsf_external_scanner_destroy(void* payload)
|
||||
{
|
||||
StateStack* stack = (StateStack*)payload;
|
||||
if (stack)
|
||||
{
|
||||
stack_free(stack);
|
||||
free(stack);
|
||||
}
|
||||
LOG("Scanner destroyed\n");
|
||||
}
|
||||
|
||||
unsigned tree_sitter_tsf_external_scanner_serialize(void* payload, char* buffer)
|
||||
{
|
||||
StateStack* stack = (StateStack*)payload;
|
||||
if (!stack || stack->size == 0)
|
||||
return 0;
|
||||
|
||||
size_t bytes_to_copy = stack->size * sizeof(enum State);
|
||||
if (bytes_to_copy > TREE_SITTER_SERIALIZATION_BUFFER_SIZE)
|
||||
{
|
||||
bytes_to_copy = TREE_SITTER_SERIALIZATION_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
memcpy(buffer, stack->states, bytes_to_copy);
|
||||
return bytes_to_copy;
|
||||
}
|
||||
|
||||
void tree_sitter_tsf_external_scanner_deserialize(void* payload, const char* buffer, unsigned length)
|
||||
{
|
||||
StateStack* stack = (StateStack*)payload;
|
||||
if (!stack)
|
||||
return;
|
||||
|
||||
stack_free(stack);
|
||||
stack_init(stack);
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
size_t count = length / sizeof(enum State);
|
||||
for (size_t i = 0; i < count && i < stack->capacity; i++)
|
||||
{
|
||||
enum State state;
|
||||
memcpy(&state, buffer + i * sizeof(enum State), sizeof(enum State));
|
||||
if (i == 0)
|
||||
{
|
||||
stack->states[0] = state;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack_push(stack, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void skip_whitespace(TSLexer* lexer)
|
||||
{
|
||||
while (iswspace(lexer->lookahead))
|
||||
{
|
||||
lexer->advance(lexer, true);
|
||||
}
|
||||
}
|
||||
|
||||
static bool lookahead_for_close_tag(TSLexer* lexer)
|
||||
{
|
||||
LOG(" [lookahead_for_close_tag] Starting lookahead\n");
|
||||
|
||||
while (lexer->lookahead != '\0')
|
||||
{
|
||||
if (lexer->lookahead == '?')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == '>')
|
||||
{
|
||||
LOG(" [lookahead_for_close_tag] Found ?>, returning true\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (lexer->lookahead == '<')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == '?')
|
||||
{
|
||||
LOG(" [lookahead_for_close_tag] Found next <?, returning false\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(" [lookahead_for_close_tag] Reached EOF, returning false\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static int peek_special_tag(TSLexer* lexer)
|
||||
{
|
||||
if (lexer->lookahead != '<')
|
||||
return 0;
|
||||
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead != '?')
|
||||
return 0;
|
||||
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
if (lexer->lookahead == '=')
|
||||
{
|
||||
LOG(" [peek_special_tag] Found <?=\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (towlower(lexer->lookahead) == 't')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (towlower(lexer->lookahead) == 's')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (towlower(lexer->lookahead) == 'l')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (!iswalnum(lexer->lookahead) && lexer->lookahead != '_')
|
||||
{
|
||||
LOG(" [peek_special_tag] Found <?tsl\n");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool scan_tslx_content(TSLexer* lexer)
|
||||
{
|
||||
bool has_content = false;
|
||||
LOG(" [scan_tslx_content] Starting scan\n");
|
||||
|
||||
while (lexer->lookahead != '\0')
|
||||
{
|
||||
if (lexer->lookahead == '<')
|
||||
{
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
int tag_type = peek_special_tag(lexer);
|
||||
|
||||
if (tag_type > 0)
|
||||
{
|
||||
LOG(" [scan_tslx_content] Found special tag, stopping. has_content=%d\n", has_content);
|
||||
return has_content;
|
||||
}
|
||||
|
||||
has_content = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
has_content = true;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(" [scan_tslx_content] Reached EOF, has_content=%d\n", has_content);
|
||||
return has_content;
|
||||
}
|
||||
|
||||
bool tree_sitter_tsf_external_scanner_scan(void* payload, TSLexer* lexer, const bool* valid_symbols)
|
||||
{
|
||||
StateStack* stack = (StateStack*)payload;
|
||||
if (!stack)
|
||||
{
|
||||
LOG("ERROR: stack is NULL\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
enum State current_state = stack_top(stack);
|
||||
|
||||
LOG("\n=== SCAN START ===\n");
|
||||
LOG("Current state: %d (0=ROOT, 1=TSLX, 2=TSL_STATEMENT, 3=TSL_EXPRESSION)\n", current_state);
|
||||
LOG("Current char: '%c' (0x%02x)\n", lexer->lookahead, lexer->lookahead);
|
||||
LOG("Valid symbols: CONTENT=%d, TSL_START=%d, TSL_END=%d, EXPR_START=%d, EXPR_END=%d, TSLX_END=%d\n",
|
||||
valid_symbols[TSLX_CONTENT],
|
||||
valid_symbols[TSL_STATEMENT_START_TAG],
|
||||
valid_symbols[TSL_STATEMENT_END_TAG],
|
||||
valid_symbols[TSL_EXPRESSION_START_TAG],
|
||||
valid_symbols[TSL_EXPRESSION_END_TAG],
|
||||
valid_symbols[TSLX_END_TAG]);
|
||||
|
||||
// ⚠️ 关键修复:通过 valid_symbols 推断状态切换
|
||||
// 如果当前在 ROOT 状态,但 parser 期望 TSLX 内部的 token,说明刚匹配完 <?tslx>
|
||||
if (current_state == STATE_ROOT &&
|
||||
(valid_symbols[TSLX_CONTENT] ||
|
||||
valid_symbols[TSL_STATEMENT_START_TAG] ||
|
||||
valid_symbols[TSL_EXPRESSION_START_TAG] ||
|
||||
valid_symbols[TSLX_END_TAG]))
|
||||
{
|
||||
LOG("State transition: ROOT -> TSLX (inferred from valid_symbols)\n");
|
||||
stack_push(stack, STATE_TSLX);
|
||||
current_state = STATE_TSLX;
|
||||
}
|
||||
|
||||
if (current_state == STATE_TSL_STATEMENT || current_state == STATE_TSL_EXPRESSION)
|
||||
{
|
||||
skip_whitespace(lexer);
|
||||
LOG("After skip whitespace: '%c' (0x%02x)\n", lexer->lookahead, lexer->lookahead);
|
||||
}
|
||||
|
||||
if (current_state == STATE_TSLX)
|
||||
{
|
||||
LOG("In STATE_TSLX\n");
|
||||
|
||||
if (lexer->lookahead == '\0' && valid_symbols[TSLX_END_TAG])
|
||||
{
|
||||
LOG("Found EOF, returning TSLX_END_TAG\n");
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = TSLX_END_TAG;
|
||||
stack_pop(stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (lexer->lookahead == '<')
|
||||
{
|
||||
LOG("Found '<', checking for tag\n");
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
if (lexer->lookahead == '?')
|
||||
{
|
||||
LOG("Found '<?', checking tag type\n");
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
if (lexer->lookahead == '=' && valid_symbols[TSL_EXPRESSION_START_TAG])
|
||||
{
|
||||
LOG("Found '<?=', returning TSL_EXPRESSION_START_TAG\n");
|
||||
lexer->advance(lexer, false);
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = TSL_EXPRESSION_START_TAG;
|
||||
stack_push(stack, STATE_TSL_EXPRESSION);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (towlower(lexer->lookahead) == 't')
|
||||
{
|
||||
LOG("Found 't', checking for 'tsl'\n");
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
if (towlower(lexer->lookahead) == 's')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
if (towlower(lexer->lookahead) == 'l')
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
|
||||
LOG("Found 'tsl', next char: '%c' (0x%02x)\n", lexer->lookahead, lexer->lookahead);
|
||||
|
||||
if (!iswalnum(lexer->lookahead) && lexer->lookahead != '_')
|
||||
{
|
||||
LOG("Valid <?tsl delimiter, performing lookahead\n");
|
||||
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
bool has_close_tag = lookahead_for_close_tag(lexer);
|
||||
LOG("Lookahead result: has_close_tag = %d\n", has_close_tag);
|
||||
|
||||
if (has_close_tag && valid_symbols[TSL_STATEMENT_START_TAG])
|
||||
{
|
||||
LOG("Returning TSL_STATEMENT_START_TAG\n");
|
||||
lexer->result_symbol = TSL_STATEMENT_START_TAG;
|
||||
stack_push(stack, STATE_TSL_STATEMENT);
|
||||
return true;
|
||||
}
|
||||
else if (!has_close_tag && valid_symbols[TSLX_END_TAG])
|
||||
{
|
||||
LOG("Returning TSLX_END_TAG (<?tsl without ?>)\n");
|
||||
lexer->result_symbol = TSLX_END_TAG;
|
||||
stack_pop(stack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_symbols[TSLX_CONTENT])
|
||||
{
|
||||
LOG("Trying to scan TSLX_CONTENT\n");
|
||||
if (scan_tslx_content(lexer))
|
||||
{
|
||||
LOG("Successfully scanned TSLX_CONTENT\n");
|
||||
lexer->result_symbol = TSLX_CONTENT;
|
||||
return true;
|
||||
}
|
||||
LOG("Failed to scan TSLX_CONTENT\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (current_state == STATE_TSL_STATEMENT)
|
||||
{
|
||||
LOG("In STATE_TSL_STATEMENT\n");
|
||||
if (lexer->lookahead == '?' && valid_symbols[TSL_STATEMENT_END_TAG])
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == '>')
|
||||
{
|
||||
LOG("Found '?>', returning TSL_STATEMENT_END_TAG\n");
|
||||
lexer->advance(lexer, false);
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = TSL_STATEMENT_END_TAG;
|
||||
stack_pop(stack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current_state == STATE_TSL_EXPRESSION)
|
||||
{
|
||||
LOG("In STATE_TSL_EXPRESSION\n");
|
||||
if (lexer->lookahead == '?' && valid_symbols[TSL_EXPRESSION_END_TAG])
|
||||
{
|
||||
lexer->advance(lexer, false);
|
||||
if (lexer->lookahead == '>')
|
||||
{
|
||||
LOG("Found '?>', returning TSL_EXPRESSION_END_TAG\n");
|
||||
lexer->advance(lexer, false);
|
||||
lexer->mark_end(lexer);
|
||||
lexer->result_symbol = TSL_EXPRESSION_END_TAG;
|
||||
stack_pop(stack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG("Returning false (no match)\n");
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef TREE_SITTER_ALLOC_H_
|
||||
#define TREE_SITTER_ALLOC_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Allow clients to override allocation functions
|
||||
#ifdef TREE_SITTER_REUSE_ALLOCATOR
|
||||
|
||||
extern void *(*ts_current_malloc)(size_t size);
|
||||
extern void *(*ts_current_calloc)(size_t count, size_t size);
|
||||
extern void *(*ts_current_realloc)(void *ptr, size_t size);
|
||||
extern void (*ts_current_free)(void *ptr);
|
||||
|
||||
#ifndef ts_malloc
|
||||
#define ts_malloc ts_current_malloc
|
||||
#endif
|
||||
#ifndef ts_calloc
|
||||
#define ts_calloc ts_current_calloc
|
||||
#endif
|
||||
#ifndef ts_realloc
|
||||
#define ts_realloc ts_current_realloc
|
||||
#endif
|
||||
#ifndef ts_free
|
||||
#define ts_free ts_current_free
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef ts_malloc
|
||||
#define ts_malloc malloc
|
||||
#endif
|
||||
#ifndef ts_calloc
|
||||
#define ts_calloc calloc
|
||||
#endif
|
||||
#ifndef ts_realloc
|
||||
#define ts_realloc realloc
|
||||
#endif
|
||||
#ifndef ts_free
|
||||
#define ts_free free
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ALLOC_H_
|
||||
@@ -0,0 +1,291 @@
|
||||
#ifndef TREE_SITTER_ARRAY_H_
|
||||
#define TREE_SITTER_ARRAY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "./alloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4101)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#endif
|
||||
|
||||
#define Array(T) \
|
||||
struct { \
|
||||
T *contents; \
|
||||
uint32_t size; \
|
||||
uint32_t capacity; \
|
||||
}
|
||||
|
||||
/// Initialize an array.
|
||||
#define array_init(self) \
|
||||
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
|
||||
|
||||
/// Create an empty array.
|
||||
#define array_new() \
|
||||
{ NULL, 0, 0 }
|
||||
|
||||
/// Get a pointer to the element at a given `index` in the array.
|
||||
#define array_get(self, _index) \
|
||||
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
|
||||
|
||||
/// Get a pointer to the first element in the array.
|
||||
#define array_front(self) array_get(self, 0)
|
||||
|
||||
/// Get a pointer to the last element in the array.
|
||||
#define array_back(self) array_get(self, (self)->size - 1)
|
||||
|
||||
/// Clear the array, setting its size to zero. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_clear(self) ((self)->size = 0)
|
||||
|
||||
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
|
||||
/// less than the array's current capacity, this function has no effect.
|
||||
#define array_reserve(self, new_capacity) \
|
||||
_array__reserve((Array *)(self), array_elem_size(self), new_capacity)
|
||||
|
||||
/// Free any memory allocated for this array. Note that this does not free any
|
||||
/// memory allocated for the array's contents.
|
||||
#define array_delete(self) _array__delete((Array *)(self))
|
||||
|
||||
/// Push a new `element` onto the end of the array.
|
||||
#define array_push(self, element) \
|
||||
(_array__grow((Array *)(self), 1, array_elem_size(self)), \
|
||||
(self)->contents[(self)->size++] = (element))
|
||||
|
||||
/// Increase the array's size by `count` elements.
|
||||
/// New elements are zero-initialized.
|
||||
#define array_grow_by(self, count) \
|
||||
do { \
|
||||
if ((count) == 0) break; \
|
||||
_array__grow((Array *)(self), count, array_elem_size(self)); \
|
||||
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
|
||||
(self)->size += (count); \
|
||||
} while (0)
|
||||
|
||||
/// Append all elements from one array to the end of another.
|
||||
#define array_push_all(self, other) \
|
||||
array_extend((self), (other)->size, (other)->contents)
|
||||
|
||||
/// Append `count` elements to the end of the array, reading their values from the
|
||||
/// `contents` pointer.
|
||||
#define array_extend(self, count, contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), (self)->size, \
|
||||
0, count, contents \
|
||||
)
|
||||
|
||||
/// Remove `old_count` elements from the array starting at the given `index`. At
|
||||
/// the same index, insert `new_count` new elements, reading their values from the
|
||||
/// `new_contents` pointer.
|
||||
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||
_array__splice( \
|
||||
(Array *)(self), array_elem_size(self), _index, \
|
||||
old_count, new_count, new_contents \
|
||||
)
|
||||
|
||||
/// Insert one `element` into the array at the given `index`.
|
||||
#define array_insert(self, _index, element) \
|
||||
_array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element))
|
||||
|
||||
/// Remove one element from the array at the given `index`.
|
||||
#define array_erase(self, _index) \
|
||||
_array__erase((Array *)(self), array_elem_size(self), _index)
|
||||
|
||||
/// Pop the last element off the array, returning the element by value.
|
||||
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||
|
||||
/// Assign the contents of one array to another, reallocating if necessary.
|
||||
#define array_assign(self, other) \
|
||||
_array__assign((Array *)(self), (const Array *)(other), array_elem_size(self))
|
||||
|
||||
/// Swap one array with another
|
||||
#define array_swap(self, other) \
|
||||
_array__swap((Array *)(self), (Array *)(other))
|
||||
|
||||
/// Get the size of the array contents
|
||||
#define array_elem_size(self) (sizeof *(self)->contents)
|
||||
|
||||
/// Search a sorted array for a given `needle` value, using the given `compare`
|
||||
/// callback to determine the order.
|
||||
///
|
||||
/// If an existing element is found to be equal to `needle`, then the `index`
|
||||
/// out-parameter is set to the existing value's index, and the `exists`
|
||||
/// out-parameter is set to true. Otherwise, `index` is set to an index where
|
||||
/// `needle` should be inserted in order to preserve the sorting, and `exists`
|
||||
/// is set to false.
|
||||
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
|
||||
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
|
||||
|
||||
/// Search a sorted array for a given `needle` value, using integer comparisons
|
||||
/// of a given struct field (specified with a leading dot) to determine the order.
|
||||
///
|
||||
/// See also `array_search_sorted_with`.
|
||||
#define array_search_sorted_by(self, field, needle, _index, _exists) \
|
||||
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
|
||||
|
||||
/// Insert a given `value` into a sorted array, using the given `compare`
|
||||
/// callback to determine the order.
|
||||
#define array_insert_sorted_with(self, compare, value) \
|
||||
do { \
|
||||
unsigned _index, _exists; \
|
||||
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
|
||||
if (!_exists) array_insert(self, _index, value); \
|
||||
} while (0)
|
||||
|
||||
/// Insert a given `value` into a sorted array, using integer comparisons of
|
||||
/// a given struct field (specified with a leading dot) to determine the order.
|
||||
///
|
||||
/// See also `array_search_sorted_by`.
|
||||
#define array_insert_sorted_by(self, field, value) \
|
||||
do { \
|
||||
unsigned _index, _exists; \
|
||||
array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
|
||||
if (!_exists) array_insert(self, _index, value); \
|
||||
} while (0)
|
||||
|
||||
// Private
|
||||
|
||||
typedef Array(void) Array;
|
||||
|
||||
/// This is not what you're looking for, see `array_delete`.
|
||||
static inline void _array__delete(Array *self) {
|
||||
if (self->contents) {
|
||||
ts_free(self->contents);
|
||||
self->contents = NULL;
|
||||
self->size = 0;
|
||||
self->capacity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_erase`.
|
||||
static inline void _array__erase(Array *self, size_t element_size,
|
||||
uint32_t index) {
|
||||
assert(index < self->size);
|
||||
char *contents = (char *)self->contents;
|
||||
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
||||
(self->size - index - 1) * element_size);
|
||||
self->size--;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_reserve`.
|
||||
static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) {
|
||||
if (new_capacity > self->capacity) {
|
||||
if (self->contents) {
|
||||
self->contents = ts_realloc(self->contents, new_capacity * element_size);
|
||||
} else {
|
||||
self->contents = ts_malloc(new_capacity * element_size);
|
||||
}
|
||||
self->capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_assign`.
|
||||
static inline void _array__assign(Array *self, const Array *other, size_t element_size) {
|
||||
_array__reserve(self, element_size, other->size);
|
||||
self->size = other->size;
|
||||
memcpy(self->contents, other->contents, self->size * element_size);
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_swap`.
|
||||
static inline void _array__swap(Array *self, Array *other) {
|
||||
Array swap = *other;
|
||||
*other = *self;
|
||||
*self = swap;
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
|
||||
static inline void _array__grow(Array *self, uint32_t count, size_t element_size) {
|
||||
uint32_t new_size = self->size + count;
|
||||
if (new_size > self->capacity) {
|
||||
uint32_t new_capacity = self->capacity * 2;
|
||||
if (new_capacity < 8) new_capacity = 8;
|
||||
if (new_capacity < new_size) new_capacity = new_size;
|
||||
_array__reserve(self, element_size, new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// This is not what you're looking for, see `array_splice`.
|
||||
static inline void _array__splice(Array *self, size_t element_size,
|
||||
uint32_t index, uint32_t old_count,
|
||||
uint32_t new_count, const void *elements) {
|
||||
uint32_t new_size = self->size + new_count - old_count;
|
||||
uint32_t old_end = index + old_count;
|
||||
uint32_t new_end = index + new_count;
|
||||
assert(old_end <= self->size);
|
||||
|
||||
_array__reserve(self, element_size, new_size);
|
||||
|
||||
char *contents = (char *)self->contents;
|
||||
if (self->size > old_end) {
|
||||
memmove(
|
||||
contents + new_end * element_size,
|
||||
contents + old_end * element_size,
|
||||
(self->size - old_end) * element_size
|
||||
);
|
||||
}
|
||||
if (new_count > 0) {
|
||||
if (elements) {
|
||||
memcpy(
|
||||
(contents + index * element_size),
|
||||
elements,
|
||||
new_count * element_size
|
||||
);
|
||||
} else {
|
||||
memset(
|
||||
(contents + index * element_size),
|
||||
0,
|
||||
new_count * element_size
|
||||
);
|
||||
}
|
||||
}
|
||||
self->size += new_count - old_count;
|
||||
}
|
||||
|
||||
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
|
||||
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
|
||||
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
|
||||
do { \
|
||||
*(_index) = start; \
|
||||
*(_exists) = false; \
|
||||
uint32_t size = (self)->size - *(_index); \
|
||||
if (size == 0) break; \
|
||||
int comparison; \
|
||||
while (size > 1) { \
|
||||
uint32_t half_size = size / 2; \
|
||||
uint32_t mid_index = *(_index) + half_size; \
|
||||
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
|
||||
if (comparison <= 0) *(_index) = mid_index; \
|
||||
size -= half_size; \
|
||||
} \
|
||||
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
|
||||
if (comparison == 0) *(_exists) = true; \
|
||||
else if (comparison < 0) *(_index) += 1; \
|
||||
} while (0)
|
||||
|
||||
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
|
||||
/// parameter by reference in order to work with the generic sorting function above.
|
||||
#define _compare_int(a, b) ((int)*(a) - (int)(b))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_ARRAY_H_
|
||||
@@ -0,0 +1,286 @@
|
||||
#ifndef TREE_SITTER_PARSER_H_
|
||||
#define TREE_SITTER_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ts_builtin_sym_error ((TSSymbol)-1)
|
||||
#define ts_builtin_sym_end 0
|
||||
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
|
||||
|
||||
#ifndef TREE_SITTER_API_H_
|
||||
typedef uint16_t TSStateId;
|
||||
typedef uint16_t TSSymbol;
|
||||
typedef uint16_t TSFieldId;
|
||||
typedef struct TSLanguage TSLanguage;
|
||||
typedef struct TSLanguageMetadata {
|
||||
uint8_t major_version;
|
||||
uint8_t minor_version;
|
||||
uint8_t patch_version;
|
||||
} TSLanguageMetadata;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
TSFieldId field_id;
|
||||
uint8_t child_index;
|
||||
bool inherited;
|
||||
} TSFieldMapEntry;
|
||||
|
||||
// Used to index the field and supertype maps.
|
||||
typedef struct {
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
} TSMapSlice;
|
||||
|
||||
typedef struct {
|
||||
bool visible;
|
||||
bool named;
|
||||
bool supertype;
|
||||
} TSSymbolMetadata;
|
||||
|
||||
typedef struct TSLexer TSLexer;
|
||||
|
||||
struct TSLexer {
|
||||
int32_t lookahead;
|
||||
TSSymbol result_symbol;
|
||||
void (*advance)(TSLexer *, bool);
|
||||
void (*mark_end)(TSLexer *);
|
||||
uint32_t (*get_column)(TSLexer *);
|
||||
bool (*is_at_included_range_start)(const TSLexer *);
|
||||
bool (*eof)(const TSLexer *);
|
||||
void (*log)(const TSLexer *, const char *, ...);
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TSParseActionTypeShift,
|
||||
TSParseActionTypeReduce,
|
||||
TSParseActionTypeAccept,
|
||||
TSParseActionTypeRecover,
|
||||
} TSParseActionType;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t type;
|
||||
TSStateId state;
|
||||
bool extra;
|
||||
bool repetition;
|
||||
} shift;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t child_count;
|
||||
TSSymbol symbol;
|
||||
int16_t dynamic_precedence;
|
||||
uint16_t production_id;
|
||||
} reduce;
|
||||
uint8_t type;
|
||||
} TSParseAction;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
} TSLexMode;
|
||||
|
||||
typedef struct {
|
||||
uint16_t lex_state;
|
||||
uint16_t external_lex_state;
|
||||
uint16_t reserved_word_set_id;
|
||||
} TSLexerMode;
|
||||
|
||||
typedef union {
|
||||
TSParseAction action;
|
||||
struct {
|
||||
uint8_t count;
|
||||
bool reusable;
|
||||
} entry;
|
||||
} TSParseActionEntry;
|
||||
|
||||
typedef struct {
|
||||
int32_t start;
|
||||
int32_t end;
|
||||
} TSCharacterRange;
|
||||
|
||||
struct TSLanguage {
|
||||
uint32_t abi_version;
|
||||
uint32_t symbol_count;
|
||||
uint32_t alias_count;
|
||||
uint32_t token_count;
|
||||
uint32_t external_token_count;
|
||||
uint32_t state_count;
|
||||
uint32_t large_state_count;
|
||||
uint32_t production_id_count;
|
||||
uint32_t field_count;
|
||||
uint16_t max_alias_sequence_length;
|
||||
const uint16_t *parse_table;
|
||||
const uint16_t *small_parse_table;
|
||||
const uint32_t *small_parse_table_map;
|
||||
const TSParseActionEntry *parse_actions;
|
||||
const char * const *symbol_names;
|
||||
const char * const *field_names;
|
||||
const TSMapSlice *field_map_slices;
|
||||
const TSFieldMapEntry *field_map_entries;
|
||||
const TSSymbolMetadata *symbol_metadata;
|
||||
const TSSymbol *public_symbol_map;
|
||||
const uint16_t *alias_map;
|
||||
const TSSymbol *alias_sequences;
|
||||
const TSLexerMode *lex_modes;
|
||||
bool (*lex_fn)(TSLexer *, TSStateId);
|
||||
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
|
||||
TSSymbol keyword_capture_token;
|
||||
struct {
|
||||
const bool *states;
|
||||
const TSSymbol *symbol_map;
|
||||
void *(*create)(void);
|
||||
void (*destroy)(void *);
|
||||
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
|
||||
unsigned (*serialize)(void *, char *);
|
||||
void (*deserialize)(void *, const char *, unsigned);
|
||||
} external_scanner;
|
||||
const TSStateId *primary_state_ids;
|
||||
const char *name;
|
||||
const TSSymbol *reserved_words;
|
||||
uint16_t max_reserved_word_set_size;
|
||||
uint32_t supertype_count;
|
||||
const TSSymbol *supertype_symbols;
|
||||
const TSMapSlice *supertype_map_slices;
|
||||
const TSSymbol *supertype_map_entries;
|
||||
TSLanguageMetadata metadata;
|
||||
};
|
||||
|
||||
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
|
||||
uint32_t index = 0;
|
||||
uint32_t size = len - index;
|
||||
while (size > 1) {
|
||||
uint32_t half_size = size / 2;
|
||||
uint32_t mid_index = index + half_size;
|
||||
const TSCharacterRange *range = &ranges[mid_index];
|
||||
if (lookahead >= range->start && lookahead <= range->end) {
|
||||
return true;
|
||||
} else if (lookahead > range->end) {
|
||||
index = mid_index;
|
||||
}
|
||||
size -= half_size;
|
||||
}
|
||||
const TSCharacterRange *range = &ranges[index];
|
||||
return (lookahead >= range->start && lookahead <= range->end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Lexer Macros
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define UNUSED __pragma(warning(suppress : 4101))
|
||||
#else
|
||||
#define UNUSED __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#define START_LEXER() \
|
||||
bool result = false; \
|
||||
bool skip = false; \
|
||||
UNUSED \
|
||||
bool eof = false; \
|
||||
int32_t lookahead; \
|
||||
goto start; \
|
||||
next_state: \
|
||||
lexer->advance(lexer, skip); \
|
||||
start: \
|
||||
skip = false; \
|
||||
lookahead = lexer->lookahead;
|
||||
|
||||
#define ADVANCE(state_value) \
|
||||
{ \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ADVANCE_MAP(...) \
|
||||
{ \
|
||||
static const uint16_t map[] = { __VA_ARGS__ }; \
|
||||
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
|
||||
if (map[i] == lookahead) { \
|
||||
state = map[i + 1]; \
|
||||
goto next_state; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SKIP(state_value) \
|
||||
{ \
|
||||
skip = true; \
|
||||
state = state_value; \
|
||||
goto next_state; \
|
||||
}
|
||||
|
||||
#define ACCEPT_TOKEN(symbol_value) \
|
||||
result = true; \
|
||||
lexer->result_symbol = symbol_value; \
|
||||
lexer->mark_end(lexer);
|
||||
|
||||
#define END_STATE() return result;
|
||||
|
||||
/*
|
||||
* Parse Table Macros
|
||||
*/
|
||||
|
||||
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
|
||||
|
||||
#define STATE(id) id
|
||||
|
||||
#define ACTIONS(id) id
|
||||
|
||||
#define SHIFT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = (state_value) \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_REPEAT(state_value) \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.state = (state_value), \
|
||||
.repetition = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define SHIFT_EXTRA() \
|
||||
{{ \
|
||||
.shift = { \
|
||||
.type = TSParseActionTypeShift, \
|
||||
.extra = true \
|
||||
} \
|
||||
}}
|
||||
|
||||
#define REDUCE(symbol_name, children, precedence, prod_id) \
|
||||
{{ \
|
||||
.reduce = { \
|
||||
.type = TSParseActionTypeReduce, \
|
||||
.symbol = symbol_name, \
|
||||
.child_count = children, \
|
||||
.dynamic_precedence = precedence, \
|
||||
.production_id = prod_id \
|
||||
}, \
|
||||
}}
|
||||
|
||||
#define RECOVER() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeRecover \
|
||||
}}
|
||||
|
||||
#define ACCEPT_INPUT() \
|
||||
{{ \
|
||||
.type = TSParseActionTypeAccept \
|
||||
}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TREE_SITTER_PARSER_H_
|
||||
@@ -0,0 +1,725 @@
|
||||
type IDS_AuditExpr = class
|
||||
|
||||
class function FormulaeCount(data, precision);
|
||||
class function FormulaeConvert(v);
|
||||
class function GetReportInfo(data);
|
||||
class function analysisFormulae(Formulae); //解析勾稽表达式
|
||||
class function specialStrReplace(str, r_type); //针对部分特殊字符进行临时转换 r_type: 1. 转化为特殊串 2. 转化为原字符串
|
||||
class function encryptFormulae(s); //base64编码
|
||||
class function decryptFormulae(s); //base64解码
|
||||
class function XBRLInsert(Formulae, FundType, Classify, isencrypt); //勾稽条目插入
|
||||
|
||||
end;
|
||||
|
||||
|
||||
class function IDS_AuditExpr.FormulaeCount(data, precision);
|
||||
begin
|
||||
if not precision then
|
||||
precision := 0;
|
||||
|
||||
if ansipos("#替换文本#", data) then // 将替换标志去除
|
||||
data := ansireplaceText(data, "#替换文本#", "");
|
||||
|
||||
sysparams["LResult"] := "";
|
||||
sysparams["RResult"] := "";
|
||||
sysparams["chaE"] := "";
|
||||
|
||||
fStr := "##0"$(precision>0?"."$DupeString('0', precision):"");
|
||||
data := ansireplaceText(data, "≠", "<>"); // eval不支持 ≠ , 需要转为<> 才能进行计算
|
||||
WCZ := GetSysParam("WuChaZhi");
|
||||
|
||||
if data like "\\) or \\(" or data like ":true" or data like "nil" or data like ' in ' or data like ' without ' or data like "\\) and \\("
|
||||
or data like '<>' or data like "funcOfIf" or data like "ifThen" or data like "isNull" or data like " and "
|
||||
or ansipos("公募基金代码", data) or ansipos("公募基金简称(", data) or ansipos("公募基金全称", data) or ansipos("textMatch", data) or ansipos("getMonthSpan", data)
|
||||
or ansipos("fundInfo", data) or ansipos(" or ", data) or ansipos("基金存续起始日", data) then
|
||||
begin
|
||||
//修复 XXX=nil xxx<>nil xxx为字符串时eval执行报错问题 -by fangf
|
||||
if data like '<>nil' and not (data like "\\) and \\(") then
|
||||
begin
|
||||
if str2array(data,"<>")[0]='0' or ifstring(str2array(data,"<>")[0]) then
|
||||
begin
|
||||
if str2array(data,"<>")[0]='nil' then data:='nil<>nil';
|
||||
else if data like "\\) or \\(" then //修复(XXX<>nil) or (XXX<>nil) 勾稽不生效问题 ex-wanzl
|
||||
begin
|
||||
data:= replaceText(data, ")", "");
|
||||
data:= replaceText(data, "(", "");
|
||||
end
|
||||
else
|
||||
data:="'"$tostring(str2array(data,"<>")[0])$"'"$'<>nil';
|
||||
end
|
||||
|
||||
end
|
||||
if data like '=nil' and not (data like "\\) and \\(") and not (data like "\\) or \\(") then
|
||||
begin
|
||||
if str2array(data,"=")[0]='0' or ifstring(str2array(data,"=")[0]) then
|
||||
begin
|
||||
if str2array(data,"=")[0]='nil' then data:='nil=nil';
|
||||
else
|
||||
data:="'"$tostring(str2array(data,"=")[0])$"'"$'=nil';
|
||||
end
|
||||
end
|
||||
//用于处理<> 条件下左右两边都不等于nil的情况下勾稽不到的情况 -by fangf
|
||||
if data like '<>' and not (data like "\\) and \\(") and not (data like "\\) or \\(") and not (data like "ifThen") then
|
||||
begin
|
||||
if not ( str2array(data,"<>")[0] like 'nil') and not (str2array(data,"<>")[1] like 'nil') then
|
||||
begin
|
||||
try
|
||||
StrToCurr(str2array(data,"<>")[0]);
|
||||
except
|
||||
LSTR:=1;
|
||||
end;
|
||||
try
|
||||
StrToCurr(str2array(data,"<>")[1]);
|
||||
except
|
||||
RSTR:=1;
|
||||
end;
|
||||
IF LSTR AND RSTR THEN
|
||||
begin
|
||||
if not (str2array(data,"<>")[0]=str2array(data,"<>")[1]) then
|
||||
return 1;
|
||||
return data;
|
||||
end
|
||||
end
|
||||
end
|
||||
if data like "ifThen" then
|
||||
begin
|
||||
try
|
||||
paramList := ansireplaceText(ansireplaceText(data, "ifThen(", ""), ")", "");
|
||||
paramList := str2array(paramList, ",");
|
||||
for paramNum:=0 to length(paramList)-1 do
|
||||
begin
|
||||
if ParseRegExpr("^([\\d\\.+\\-\\*\\/\\)\\(]+)([=<>]{1,2})([\\d\\.+\\-\\*\\/\\)\\(]+)$",trim(paramList[paramNum]),"",res,MPos,Mlen)=1 then
|
||||
begin
|
||||
leftS := eval(&res[0][1]);
|
||||
mark := res[0][2];
|
||||
rightS := eval(&res[0][3]);
|
||||
replaceS := leftS$mark$rightS;
|
||||
data := replaceText(data, paramList[paramNum] ,replaceS);
|
||||
end
|
||||
else
|
||||
continue;
|
||||
end;
|
||||
except
|
||||
end;
|
||||
end;
|
||||
if data like "without" then //用于处理集合1不存在于集合2 ex-wanzl
|
||||
begin
|
||||
data := replaceText(data, "array", "");
|
||||
tmp := replaceText(replaceText(data, ")", ""), "(", "");
|
||||
tmp := str2array(tmp, " without ");
|
||||
|
||||
if length(tmp)=2 then
|
||||
begin
|
||||
tmp1 := str2array(tmp[0], ",");
|
||||
tmp2 := str2array(tmp[1], ",");
|
||||
arr := array();
|
||||
for i := 0 to length(tmp1) do
|
||||
begin
|
||||
if tmp1[i] in tmp2 then
|
||||
arr[length(arr)] := tmp1[i] ;
|
||||
end
|
||||
if istable(arr) then
|
||||
begin
|
||||
tmp3 := "【不符合项:"$array2str(DistinctStr(arr), ",")$"】" ;
|
||||
return replaceText(data, "array", "")$tmp3;
|
||||
end
|
||||
else return 1;
|
||||
end
|
||||
else
|
||||
tmp2 := "";
|
||||
return replaceText(data, "array", "")$tmp2;
|
||||
end
|
||||
else if eval(&data)=1 then
|
||||
return 1;
|
||||
else if data like " in " then //用于处理集合函数公式
|
||||
begin
|
||||
data := replaceText(data, "array", "");
|
||||
tmp2 := "以下项目存在差异,请检查。【";
|
||||
dataRe := str2array(data, " and ");
|
||||
for j:=0 to length(dataRe)-1 do
|
||||
begin
|
||||
tmp := replaceText(replaceText(dataRe[j], ")", ""), "(", "");
|
||||
tmp := str2array(tmp, " in ");
|
||||
if length(tmp)=2 then
|
||||
begin
|
||||
chayi := str2array(tmp[0], ",") minus str2array(tmp[1], ",");
|
||||
if istable(chayi) then
|
||||
tmp2 += (j=0?"":";")$array2str(chayi, ",");
|
||||
end else
|
||||
tmp2 += "";
|
||||
end;
|
||||
tmp2 += "】";
|
||||
data := replaceText(data, "in", "与");
|
||||
return tmp2;
|
||||
end
|
||||
else if data like "nil" and not (data like "\\) and \\(") then
|
||||
begin
|
||||
if (data like '<>' or data like '=') and (str2array(data,"<>")[0]='nil' or str2array(data,"<>")[0]=nil or str2array(data,"<>")[1]=nil or str2array(data,"<>")[1]='nil') then
|
||||
return data$"【nil】";
|
||||
return data$"【"$FormatFloat(fStr,setPrecision(eval(&str2array(data,"=")[1]),precision))$"】";
|
||||
end
|
||||
else
|
||||
return data$"【"$eval(&data)$"】";
|
||||
|
||||
end;
|
||||
ParseRegExpr("([<|>|=])+",data, "" , ret, MPos, Mlen);
|
||||
if istable(ret) then
|
||||
flag := ret[0][0];
|
||||
|
||||
tmp := str2array(data, flag);
|
||||
|
||||
for i:=0 to length(tmp)-1 do
|
||||
tmp[i] := replaceText(tmp[i], "--", "+");
|
||||
try
|
||||
Rresult := eval(&tmp[1]);
|
||||
except
|
||||
//dolog("zhang1021",tmp[1]);//记录报错公式
|
||||
end;
|
||||
{if length(tmp)>2 then
|
||||
return "公式错误."; }
|
||||
|
||||
try
|
||||
LResult := eval(&tmp[0]);
|
||||
if WCZ then
|
||||
begin
|
||||
WCZ += 0.000000001;
|
||||
if samevalue(setPrecision(LResult,precision),setPrecision(Rresult,precision),WCZ) then
|
||||
return 1;
|
||||
end;
|
||||
LResult := isNan(LResult)?0:Lresult;
|
||||
Rresult := isNan(Rresult)?0:Rresult;
|
||||
//if eval(&floattostr(setPrecision(LResult,precision))$flag$floattostr(setPrecision(Rresult,precision))) then
|
||||
|
||||
// 获取勾稽的左边结果/右边结果/差额,并给予入库
|
||||
sysparams["LResult"] := FormatFloat(fStr, Lresult);
|
||||
sysparams["RResult"] := FormatFloat(fStr, Rresult);
|
||||
sysparams["chaE"] := strtofloat(FormatFloat(fStr, Lresult))-strtofloat(FormatFloat(fStr, Rresult));
|
||||
|
||||
if eval(&FormatFloat(fStr, LResult)$flag$FormatFloat(fStr,Rresult)) then
|
||||
return 1;
|
||||
return tmp[0]$(tmp[0] like "[\\+\\-\\*\\/]"?"【"$FormatFloat(fStr, Lresult)$"】":"")$flag$tmp[1]$
|
||||
(tmp[1] like "[\\+\\-\\*\\/]"?"【"$FormatFloat(fStr, Rresult)$"】":"");
|
||||
except
|
||||
end;
|
||||
|
||||
end;
|
||||
|
||||
//将公式的数值转化为千分位
|
||||
class function IDS_AuditExpr.FormulaeConvert(v);
|
||||
begin
|
||||
if not v then
|
||||
return v;
|
||||
ParseRegExpr("\\d+\\.\\d+|\\d+",v,"",ret,MPos,Mlen);
|
||||
|
||||
tmp := v;
|
||||
ret := select distinct * from ret order by length([0]) desc end;
|
||||
for i:=0 to length(ret)-1 do
|
||||
begin
|
||||
if length(ret[i][0])>3 then
|
||||
begin
|
||||
//转化为千分位后根据原值小数位数保留小数位
|
||||
if ret[i][0] like "\\." then
|
||||
p := length(str2array(ret[i][0], ".")[1]);
|
||||
|
||||
tmpvalue := FormatFloat("#,##0"$(p?"."$DupeString('0', p):""), strtofloat(ret[i][0]));
|
||||
end else
|
||||
continue;
|
||||
|
||||
tmp := replaceText(tmp, ret[i][0], tmpvalue);
|
||||
end;
|
||||
|
||||
return tmp;
|
||||
end;
|
||||
|
||||
//获取报告讯息
|
||||
class function IDS_AuditExpr.GetReportInfo(data);
|
||||
begin
|
||||
//针对提交勾稽去取报告id
|
||||
if istable(data) then
|
||||
begin
|
||||
did:=data[0];
|
||||
sql:="select a.ID,
|
||||
a.fundid,
|
||||
a.reportdate,
|
||||
a.begindate,
|
||||
"$ids_tdbc("td_ifnull", array("g.ORG_ESTABLISH_DATE", ids_tdbc("td_strtofloat", array(ids_tdbc("td_formatDateTime", array("p.establishdate", "yyyymmdd"))))))$" Fdate,
|
||||
a.CLASSIFY
|
||||
from ts_rformaldata c
|
||||
left join ts_reportinfo a
|
||||
on a.fundid = c.tip2
|
||||
and a.classify = c.classify
|
||||
and ((a.change_date is null and a.publishdate = c.enddate and
|
||||
a.begindate = c.begindate) or
|
||||
(a.change_date is not null and
|
||||
((c.enddate = a.publishdate and
|
||||
c.begindate = "$ids_tdbc("td_strtofloat", array(ids_tdbc("td_formatDateTime", array("a.change_date", "yyyymmdd"))))$") or
|
||||
(c.enddate = "$ids_tdbc("td_incDay", array("a.change_date", -1))$" and
|
||||
c.begindate = a.begindate))))
|
||||
left join ts_productinfo p
|
||||
on a.fundid = p.productid
|
||||
and p.isvalid = 1
|
||||
left join TS_FUNDCHANGELOG g
|
||||
on p.productid = g.fundid
|
||||
and g.isvalid = 1
|
||||
where c.id = '"$did$"' and p.isvalid = 1
|
||||
and c.status <> 0 order by a.isvalid desc";
|
||||
|
||||
ret:=ids_execsql(sql,r);
|
||||
return r;
|
||||
|
||||
end else
|
||||
rid := data;
|
||||
|
||||
sql :="select ID,r.fundid,reportdate,begindate,"$ids_TDBC("td_ifnull", array("ORG_ESTABLISH_DATE", ids_TDBC("td_strtofloat",array(ids_TDBC("td_formatDateTime", array("p.establishdate", "yyyymmdd"))))))$" Fdate, CLASSIFY, r.CHANGE_DATE
|
||||
from ts_reportinfo r join ts_productinfo p on r.fundid = p.productid
|
||||
left join TS_FUNDCHANGELOG g on p.productid =g.fundid
|
||||
where r.isvalid=1 and id = '"$rid$"' and p.isvalid = 1 order by Fdate";
|
||||
ids_execsql(sql,r);
|
||||
|
||||
return r;
|
||||
end;
|
||||
|
||||
//解析勾稽表达式,传入一个字符串类型的勾稽表达式,去掉运算符,返回一个数组。
|
||||
class function IDS_AuditExpr.analysisFormulae(Formulae);
|
||||
Begin
|
||||
//去除空格
|
||||
sysparams["StrReplace"] := array();
|
||||
Formulae := specialStrReplace(Formulae, 0);
|
||||
if Pos('or', Formulae) or Pos('and', Formulae) then
|
||||
ReplaceStr := ReplaceText(Formulae, ' ', '');
|
||||
else
|
||||
ReplaceStr := Formulae;
|
||||
// 勾稽公式页面获取章节公式指标额外增加的文本需替换掉
|
||||
addReplace := array("(总和)","整表","(上期末)","上期年报","一季报","二季报","三季报","四季报",
|
||||
"中报","上期报告","前年报告","(期初)","(期末)","(集合)","(份额总和)","TXT","#");
|
||||
//替换字符串中的运算符
|
||||
wantReplace := Array('GetMaxValue', 'GetMinValue', '>=', '<=', '+', '-', '*', '/', '>', '<', '=', 'and', 'or', 'Min', 'Max', 'abs', 'AnsiContainsText', 'in',
|
||||
'without', '?', ':ture', ';;;', ';;', ':true',',','(买入)','(卖出)','(下属数据总和)','funcOfIf'{, "'"}, "funcOfRoundTo", "funcOfRoundDown",
|
||||
"funcOfIsNull", "not", "SameText", "ifThen", "isNull", "≠", "公募基金代码", "公募基金全称", "公募基金简称", "textMatch", "getMonthSpan", "fundInfo", "基金存续起始日");
|
||||
if SYSPARAMS["addChapterRow"] then
|
||||
wantReplace &= addReplace;
|
||||
|
||||
for i:=0 to length(wantReplace)-1 do
|
||||
Begin
|
||||
if Pos(wantReplace[i], ReplaceStr) then
|
||||
ReplaceStr := ReplaceStr(ReplaceStr, wantReplace[i], ';');
|
||||
End;
|
||||
|
||||
//正则替换掉and or min等情况的字符
|
||||
reAry := array(';\\d+;', ';\\d+$', ';Min\\\(', ';\\d+;', ';\\d+\\\);\\\(', ';\\d+\\\)', ';\\\)\\\);', ';\\\(\\\(;', ';Max\\\(',';\\d+\\.\\d+',';abs\\\(');
|
||||
for k := 0 to length(reAry) - 1 do
|
||||
begin
|
||||
ParseRegExpr(reAry[k], ReplaceStr, "", matchResult, MPos, Mlen);
|
||||
if matchResult<>0 then
|
||||
Begin
|
||||
for j:=0 to length(matchResult)-1 do
|
||||
ReplaceStr := ReplaceText(ReplaceStr, matchResult[j][0], ';');
|
||||
End;
|
||||
end;
|
||||
|
||||
if ReplaceStr like ';$' then ReplaceStr := ReplaceStr[1:length(ReplaceStr)-1];
|
||||
if ReplaceStr like '^;' then ReplaceStr := ReplaceStr[2:length(ReplaceStr)];
|
||||
|
||||
//将字符串转化为数组
|
||||
tAry := Str2Array(ReplaceStr,';');
|
||||
//去除每个元素首尾的空格
|
||||
sAry := array();
|
||||
for h := 0 to length(tAry) - 1 do
|
||||
begin
|
||||
sAry[h] := Trim(tAry[h]);
|
||||
end;
|
||||
|
||||
if not (Pos('(', ReplaceStr) or Pos(')', ReplaceStr)) then
|
||||
begin
|
||||
sAry := sselect distinct specialStrReplace(thisrow, 1) from sAry where not (thisrow like "^\\d+$") order by lengthW(specialStrReplace(thisrow, 1)) desc end;
|
||||
return sAry;
|
||||
//return array2str(sAry);
|
||||
end;
|
||||
|
||||
//去掉每个元素中多余的括号
|
||||
nAry := array();
|
||||
|
||||
for m := 0 to length(sAry) - 1 do
|
||||
begin
|
||||
s := sAry[m];
|
||||
|
||||
//查找"("与")"的位置
|
||||
sLen := length(s);
|
||||
brackets := array('(',')');
|
||||
markAry := array(array(),array());
|
||||
|
||||
for idx := 0 to length(brackets)-1 do
|
||||
begin
|
||||
t:=s;
|
||||
i:=1;
|
||||
j:=0;
|
||||
k:=0;
|
||||
|
||||
while AnsiContainsText(t,brackets[idx]) do
|
||||
begin
|
||||
i := pos(brackets[idx], t);
|
||||
k := k + i;
|
||||
markAry[idx][j]:=k;
|
||||
j:=j+1;
|
||||
if k+1>sLen then break;
|
||||
t:=s[k+1:sLen];
|
||||
end;
|
||||
end;
|
||||
|
||||
if not markAry[0] then
|
||||
begin
|
||||
if not markAry[1] then
|
||||
begin
|
||||
nAry[m] := s;
|
||||
continue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
s := ReplaceText(s, ')', '');
|
||||
nAry[m] := s;
|
||||
continue;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if not markAry[1] then
|
||||
begin
|
||||
s := ReplaceText(s, '(', '');
|
||||
nAry[m] := s;
|
||||
continue;
|
||||
end;
|
||||
end;
|
||||
|
||||
//就近原则匹配相近的左右括号
|
||||
leftPair := array();
|
||||
rightPair := array();
|
||||
for i := 0 to length(markAry[1]) - 1 do
|
||||
begin
|
||||
for j := 0 to length(markAry[0]) - 1 do
|
||||
begin
|
||||
if markAry[0][j] in leftPair then continue;
|
||||
if markAry[0][j] < markAry[1][i] then
|
||||
begin
|
||||
k := 1;
|
||||
while markAry[0][j+k] do
|
||||
begin
|
||||
if not (markAry[0][j+k] in leftPair) then break;
|
||||
k := k + 1;
|
||||
end;
|
||||
if markAry[0][j+k] then
|
||||
begin
|
||||
if markAry[0][j+k] > markAry[1][i] then
|
||||
begin
|
||||
leftPair[length(leftPair)] := markAry[0][j];
|
||||
rightPair[length(rightPair)] := markAry[1][i];
|
||||
end
|
||||
else continue;
|
||||
end
|
||||
else
|
||||
begin
|
||||
leftPair[length(leftPair)] := markAry[0][j];
|
||||
rightPair[length(rightPair)] := markAry[1][i];
|
||||
end;
|
||||
end
|
||||
else break;
|
||||
end;
|
||||
end;
|
||||
|
||||
//删除多余的括号
|
||||
for l := 0 to length(markAry[0]) - 1 do
|
||||
begin
|
||||
if not (markAry[0][l] in leftPair) then s[markAry[0][l]:markAry[0][l]] := '';
|
||||
end;
|
||||
|
||||
for n := 0 to length(markAry[1]) -1 do
|
||||
begin
|
||||
if not (markAry[1][n] in rightPair) then s[markAry[1][n]:markAry[1][n]] := '';
|
||||
end;
|
||||
|
||||
//删除占位符
|
||||
//s := replaceStr(trim(s), '\0', '');
|
||||
|
||||
//删除头尾能够配对的括号,针对不规范的公式,需要加try包裹防止公式列表页面查询时报错
|
||||
try
|
||||
if rightPair[length(rightPair)-1] - leftPair[length(leftPair)-1] + 1 = length(s) then s := s[2:length(s)-1];
|
||||
except
|
||||
end;
|
||||
|
||||
nAry[m] := trim(s);
|
||||
end;
|
||||
|
||||
t := sselect distinct trim(specialStrReplace(thisrow, 1)) from nAry where not (trim(thisrow) like "^\\d+$" or thisrow='' or thisrow like "'[\\s\\S]+'" or specialStrReplace(thisrow, 1) like "^'[\\s\\S]+'$") order by lengthW(specialStrReplace(thisrow, 1)) desc end;
|
||||
|
||||
//t := sselect distinct thisrow from nAry where not (thisrow like "^\\d+$") order by lengthW(thisrow) desc end;
|
||||
//t := array2str(t);
|
||||
return t;
|
||||
End;
|
||||
|
||||
class function IDS_AuditExpr.encryptFormulae(s);
|
||||
begin
|
||||
result := Base64Encode(tostring(s));
|
||||
return result;
|
||||
end;
|
||||
|
||||
class function IDS_AuditExpr.decryptFormulae(s);
|
||||
begin
|
||||
result := Base64Decode(tostring(s));
|
||||
return result;
|
||||
end;
|
||||
|
||||
class function IDS_AuditExpr.XBRLInsert(Formulae, FundType, Classify, isencrypt);
|
||||
Begin
|
||||
//新勾稽条目插入,接收四个参数,Formulae勾稽表达式,FundType基金类型,Classify报告类型,isencrypt是否需要加密
|
||||
|
||||
table := "XBRL_DataAuditConf";
|
||||
|
||||
eFormulae := class(IDS_AuditExpr).encryptFormulae(Formulae);
|
||||
sql := "select * from "$table$"
|
||||
where formulae in ('"$Formulae$"','"$eFormulae$"')
|
||||
and classify='"$Classify$"'";
|
||||
ids_execsql(sql, r1);
|
||||
if istable(r1) then return '该勾稽关系式已存在';
|
||||
|
||||
if isencrypt then Formulae := eFormulae;
|
||||
|
||||
sql:="INSERT INTO "$table$"
|
||||
(
|
||||
Formulae,
|
||||
FundType,
|
||||
Classify
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
"
|
||||
$ "'" $ Formulae $ "'" $ ","
|
||||
$ (FundType?("'" $ FundType $ "'"):"null") $ ","
|
||||
$ "'" $ Classify $ "'" $
|
||||
")";
|
||||
|
||||
ret1 := ids_execsql(sql,r);
|
||||
if ret1=0 then
|
||||
errorMsg := SQLErrorMsg();
|
||||
else
|
||||
return 'success';
|
||||
if errorMsg then
|
||||
return errorMsg;
|
||||
|
||||
End;
|
||||
|
||||
class function IDS_AuditExpr.specialStrReplace(str, r_type); //针对部分特殊字符进行临时转换 r_type: 0-转化为特殊串 1-转化为原字符串
|
||||
begin
|
||||
if not str then
|
||||
return '';
|
||||
arr := specialStrConf();
|
||||
StrList := array();
|
||||
SNum := 0;
|
||||
if r_type then
|
||||
begin
|
||||
StrList := sysparams["StrReplace"];
|
||||
if istable(StrList) then
|
||||
begin
|
||||
for StrNum:=length(StrList)-1 downto 0 do
|
||||
str := replaceStr(str, StrList[StrNum][1], StrList[StrNum][0]);
|
||||
end;
|
||||
for StrNum:=0 to length(arr)-1 do
|
||||
str := replaceStr(str, arr[StrNum][1], arr[StrNum][0]);
|
||||
end
|
||||
else
|
||||
begin
|
||||
for StrNum:=0 to length(arr)-1 do
|
||||
str := replaceStr(str, arr[StrNum][0], arr[StrNum][1]);
|
||||
|
||||
ParseRegExpr("'+[^']+'+",str,"",StrArr,MPos,Mlen);
|
||||
for StrArrNum:=0 to length(StrArr)-1 do
|
||||
begin
|
||||
str := replaceStr(str, StrArr[StrArrNum][0], "@STR"$SNum$"@");
|
||||
sysparams["StrReplace"][SNum] := array(StrArr[StrArrNum][0], "@STR"$SNum$"@");
|
||||
SNum += 1;
|
||||
end;
|
||||
ParseRegExpr("[^+\\-\\*/<> =]+",str,"",result,MPos,Mlen);
|
||||
result := select * from result order by length([0]) desc end;
|
||||
for StrNum:=0 to length(result)-1 do
|
||||
begin
|
||||
if ansipos("#", result[StrNum][0]) and ansipos("getLastYear", result[StrNum][0])=0
|
||||
and ansipos("AnsiContainsText", result[StrNum][0])=0 and ansipos("TXT", result[StrNum][0])=0
|
||||
and ansipos("funcOfRowCount", result[StrNum][0])=0 and ansipos("isNull", result[StrNum][0])=0 then
|
||||
begin
|
||||
filterStr := result[StrNum][0];
|
||||
if filterStr like "^\\([\\s\\S]+\\)$" and ansipos("fundInfo", filterStr)=0 then
|
||||
filterStr := filterStr[2:length(filterStr)-1]; // 如果条件替换串的首位都是括号,则需要去掉
|
||||
str := replaceStr(str, filterStr, "@FILTER"$StrNum$"@");
|
||||
|
||||
sysparams["StrReplace"][SNum] := array(filterStr, "@FILTER"$StrNum$"@");
|
||||
SNum += 1;
|
||||
end
|
||||
end;
|
||||
end;
|
||||
return str;
|
||||
end;
|
||||
|
||||
function specialStrConf();
|
||||
begin
|
||||
return array(
|
||||
("“-”", "@SP1@"),
|
||||
("定期存款/协议存款", "@SP2@"),
|
||||
("报告期末基金资产组合情况-注", "@SP3@"),
|
||||
("资产负债表-注", "@SP4@"),
|
||||
("银行间市场债券正回购-文", "@SP5@"),
|
||||
("管理人对报告期内基金利润分配情况的说明-FA", "@SP6@"),
|
||||
("(利率风险的敏感性分析)对资产负债表日基金资产净值的影响金额", "@SP7@"),
|
||||
("积极投资前五名股票明细(指数基金)", "@SP8@"),
|
||||
("(基金中基金)报告期末按公允价值占基金资产净值比例大小排序的基金投资明细", "@SP9@"),
|
||||
("#like ", "@SP10@")
|
||||
);
|
||||
end;
|
||||
|
||||
function replace_FH(str);
|
||||
begin
|
||||
FHconf := array(
|
||||
("@横杠@", "-")
|
||||
);
|
||||
|
||||
for r_i:=0 to length(FHconf)-1 do
|
||||
begin
|
||||
if str like FHconf[r_i][0] then
|
||||
str := replaceStr(str, FHconf[r_i][0], FHconf[r_i][1]);
|
||||
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
// 以下为公募勾稽构筑新增函数
|
||||
function funcOfIf(a, b, c); // if判断函数
|
||||
begin
|
||||
if eval(&a) then
|
||||
return eval(&b);
|
||||
else
|
||||
return eval(&c);
|
||||
end;
|
||||
|
||||
function funcOfRoundTo(n, p); // 精度进位函数
|
||||
begin
|
||||
return SimpleRoundTo(n, -p);
|
||||
end;
|
||||
|
||||
function funcOfRoundDown(n, p); // 精度舍位函数
|
||||
begin
|
||||
ns := tostring(n);
|
||||
if ansipos(".", ns) then
|
||||
begin
|
||||
tmp := str2array(ns, ".");
|
||||
return strtofloat(tmp[0]$"."$leftStr(tmp[1],p));
|
||||
end
|
||||
else
|
||||
return strtofloat(ns);
|
||||
end;
|
||||
|
||||
function isNull(value); // 空判断, 原函数只能处理数值类型,与系统函数重名,但只生效于勾稽公式中的变量
|
||||
begin
|
||||
if tostring(value)<>"" and not ifnil(value) then
|
||||
return 0;
|
||||
return 1;
|
||||
end;
|
||||
|
||||
function 公募基金代码(fundid);
|
||||
begin
|
||||
pinfo := sysparams["productInfo"];
|
||||
if not istable(pinfo) then
|
||||
pinfo := getProductInfoByGM();
|
||||
pinfo := select ["PRODUCTID"] from pinfo where ["PRODUCTID"]=fundid end;
|
||||
|
||||
if istable(pinfo) then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
end;
|
||||
|
||||
function 公募基金简称(shortname);
|
||||
begin
|
||||
pinfo := sysparams["productInfo"];
|
||||
if not istable(pinfo) then
|
||||
pinfo := getProductInfoByGM();
|
||||
pinfo := select ["SHORTNAME"], ["SUB_SHORTNAME"] from pinfo where ["SUB_SHORTNAME"]=trim(shortname) or ["SHORTNAME"]=trim(shortname) end;
|
||||
if istable(pinfo) then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
end;
|
||||
|
||||
function 公募基金全称(fullname);
|
||||
begin
|
||||
pinfo := sysparams["productInfo"];
|
||||
if not istable(pinfo) then
|
||||
pinfo := getProductInfoByGM();
|
||||
pinfo := select ["FULLNAME"] from pinfo where ["FULLNAME"]=trim(fullname) end;
|
||||
|
||||
if istable(pinfo) then
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
end;
|
||||
|
||||
function 基金存续起始日(fundid);
|
||||
begin
|
||||
pinfo := sysparams["productInfo"];
|
||||
if not istable(pinfo) then
|
||||
pinfo := getProductInfoByGM();
|
||||
pinfo := select ["EXISTENCEDATE"], ["ESTABLISHDATE"] from pinfo where ["PRODUCTID"]=fundid end;
|
||||
if istable(pinfo) then
|
||||
return pinfo[0]["EXISTENCEDATE"]?:pinfo[0]["ESTABLISHDATE"];
|
||||
else
|
||||
return 0;
|
||||
end;
|
||||
|
||||
|
||||
function getProductInfoByGM();
|
||||
begin
|
||||
sql := "select PRODUCTID, SHORTNAME, FULLNAME, SUB_SHORTNAME, MANAGER, CUSTODIAN, ESTABLISHDATE, NOTICEDATE, EXISTENCEDATE, LISTING_DATE from ts_productinfo where isvalid = 1 and (FULLNAME like '%证券投资基金' or FUNDPRODUCTTYPE = '公募基金')";
|
||||
ret := ids_execsql(sql, r);
|
||||
if not (ret and istable(r)) then
|
||||
r := array();
|
||||
sysparams["productInfo"] := r;
|
||||
return r;
|
||||
end;
|
||||
|
||||
function GetMaxValue();
|
||||
begin
|
||||
tmpParams := params;
|
||||
valArr := array();
|
||||
if istable(tmpParams) then
|
||||
begin
|
||||
for i:=0 to length(tmpParams)-1 do
|
||||
begin
|
||||
if istable(tmpParams[i]) then
|
||||
valArr &= tmpParams[i];
|
||||
else if ifstring(tmpParams[i]) or ifnumber(tmpParams[i]) then
|
||||
valArr[length(valArr)] := tmpParams[i];
|
||||
end;
|
||||
end;
|
||||
if istable(valArr) then
|
||||
v := MaxValue(valArr);
|
||||
else
|
||||
v := 0;
|
||||
return v;
|
||||
end;
|
||||
|
||||
function GetMinValue();
|
||||
begin
|
||||
tmpParams := params;
|
||||
valArr := array();
|
||||
if istable(tmpParams) then
|
||||
begin
|
||||
for i:=0 to length(tmpParams)-1 do
|
||||
begin
|
||||
if istable(tmpParams[i]) then
|
||||
valArr &= tmpParams[i];
|
||||
else if ifstring(tmpParams[i]) or ifnumber(tmpParams[i]) then
|
||||
valArr[length(valArr)] := tmpParams[i];
|
||||
end;
|
||||
end;
|
||||
if istable(valArr) then
|
||||
v := MinValue(valArr);
|
||||
else
|
||||
v := 0;
|
||||
return v;
|
||||
end;
|
||||
@@ -0,0 +1,258 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
递归读取文件,提取 SQL 语句:
|
||||
- select/vselect/sselect ... end; (不匹配字符串中的关键字,select和end之间不能有分号)
|
||||
- update ... end; (update和end之间不能有分号)
|
||||
- delete ... ; (delete到分号)
|
||||
- insert ... ; (insert到分号)
|
||||
- 按文件分组输出
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def extract_sql_statements(content):
|
||||
"""
|
||||
从文本内容中提取 SQL 语句:
|
||||
- select/vselect/sselect ... end; (select和end之间不能有分号)
|
||||
- update ... end; (update和end之间不能有分号)
|
||||
- delete ... ; (delete到分号)
|
||||
- insert ... ; (insert到分号)
|
||||
不会匹配字符串中的关键字
|
||||
|
||||
Args:
|
||||
content: 文件内容字符串
|
||||
|
||||
Returns:
|
||||
按类型分类的SQL语句字典
|
||||
"""
|
||||
# 将所有字符串替换为占位符(保持长度不变)
|
||||
def replace_string_content(match):
|
||||
quote = match.group(0)[0]
|
||||
length = len(match.group(0))
|
||||
return quote + ' ' * (length - 2) + quote
|
||||
|
||||
# 将注释替换为空格(保持长度不变)
|
||||
def replace_comment(match):
|
||||
return ' ' * len(match.group(0))
|
||||
|
||||
# 替换单引号字符串
|
||||
content_cleaned = re.sub(r"'(?:[^'\\]|\\.)*?'", replace_string_content, content)
|
||||
# 替换双引号字符串
|
||||
content_cleaned = re.sub(r'"(?:[^"\\]|\\.)*?"', replace_string_content, content_cleaned)
|
||||
# 替换单行注释 //
|
||||
content_cleaned = re.sub(r'//.*?$', replace_comment, content_cleaned, flags=re.MULTILINE)
|
||||
# 替换多行注释 /* */
|
||||
content_cleaned = re.sub(r'/\*.*?\*/', replace_comment, content_cleaned, flags=re.DOTALL)
|
||||
|
||||
results = {
|
||||
'select': [],
|
||||
'sselect': [],
|
||||
'vselect': [],
|
||||
'update': [],
|
||||
'delete': [],
|
||||
'insert': []
|
||||
}
|
||||
|
||||
# 在清理后的内容中匹配,但从原始内容中提取
|
||||
|
||||
# 匹配 vselect ... end; (中间不能有分号)
|
||||
vselect_pattern = r'(?i)\bvselect\b(?!\s*\()[^;]*?end\s*;'
|
||||
for match in re.finditer(vselect_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['vselect'].append(original_text)
|
||||
|
||||
# 匹配 sselect ... end; (中间不能有分号)
|
||||
sselect_pattern = r'(?i)\bsselect\b(?!\s*\()[^;]*?end\s*;'
|
||||
for match in re.finditer(sselect_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['sselect'].append(original_text)
|
||||
|
||||
# 匹配 select ... end; (但不包括 vselect 和 sselect,中间不能有分号)
|
||||
select_pattern = r'(?i)(?<![vs])\bselect\b(?!\s*\()[^;]*?end\s*;'
|
||||
for match in re.finditer(select_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['select'].append(original_text)
|
||||
|
||||
# 匹配 update ... end; (中间不能有分号)
|
||||
update_pattern = r'(?i)\bupdate\b(?!\s*\()[^;]*?end\s*;'
|
||||
for match in re.finditer(update_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['update'].append(original_text)
|
||||
|
||||
# 匹配 delete ... ; (到第一个分号为止)
|
||||
delete_pattern = r'(?i)\bdelete\b(?!\s*\()(?:\s+from\b)[^;]*?;'
|
||||
for match in re.finditer(delete_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['delete'].append(original_text)
|
||||
|
||||
# 匹配 insert ... ; (到第一个分号为止)
|
||||
insert_pattern = r'(?i)\binsert\b(?!\s*\()[^;]*?;'
|
||||
for match in re.finditer(insert_pattern, content_cleaned, re.DOTALL):
|
||||
original_text = content[match.start():match.end()].strip()
|
||||
results['insert'].append(original_text)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def read_files_recursively(directory, output_file, file_extensions=None):
|
||||
"""
|
||||
递归读取目录下的所有文件,提取SQL语句并按文件分组输出
|
||||
|
||||
Args:
|
||||
directory: 要扫描的目录路径
|
||||
output_file: 输出文件路径
|
||||
file_extensions: 要处理的文件扩展名列表,如 ['.sql', '.txt'],None表示所有文件
|
||||
"""
|
||||
# 按文件存储SQL语句
|
||||
# 结构: {file_path: {'select': [...], 'sselect': [...], 'vselect': [...]}}
|
||||
files_statements = {}
|
||||
|
||||
processed_files = 0
|
||||
error_files = []
|
||||
|
||||
# 递归遍历目录
|
||||
for root, dirs, files in os.walk(directory, followlinks=True):
|
||||
for filename in files:
|
||||
file_path = os.path.join(root, filename)
|
||||
|
||||
# 跳过输出文件本身
|
||||
if os.path.abspath(file_path) == os.path.abspath(output_file):
|
||||
continue
|
||||
|
||||
# 如果指定了文件扩展名,只处理匹配的文件
|
||||
if file_extensions:
|
||||
if not any(filename.lower().endswith(ext.lower()) for ext in file_extensions):
|
||||
continue
|
||||
|
||||
try:
|
||||
# 尝试多种编码读取文件
|
||||
encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
|
||||
content = None
|
||||
|
||||
for encoding in encodings:
|
||||
try:
|
||||
with open(file_path, 'r', encoding=encoding) as f:
|
||||
content = f.read()
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
|
||||
if content is None:
|
||||
print(f"警告: 无法读取文件 {file_path} (编码问题)")
|
||||
error_files.append(file_path)
|
||||
continue
|
||||
|
||||
# 提取SQL语句(按类型分类)
|
||||
matches = extract_sql_statements(content)
|
||||
|
||||
# 统计该文件中的语句数量
|
||||
total_matches = sum(len(stmts) for stmts in matches.values())
|
||||
|
||||
if total_matches > 0:
|
||||
files_statements[file_path] = matches
|
||||
print(f"✓ {file_path}: 找到 {total_matches} 条语句 "
|
||||
f"(select: {len(matches['select'])}, "
|
||||
f"sselect: {len(matches['sselect'])}, "
|
||||
f"vselect: {len(matches['vselect'])}, "
|
||||
f"update: {len(matches['update'])}, "
|
||||
f"delete: {len(matches['delete'])}, "
|
||||
f"insert: {len(matches['insert'])})")
|
||||
|
||||
processed_files += 1
|
||||
|
||||
except Exception as e:
|
||||
print(f"错误: 处理文件 {file_path} 时出错: {str(e)}")
|
||||
error_files.append(file_path)
|
||||
|
||||
# 计算总数
|
||||
total_select = sum(len(stmts['select']) for stmts in files_statements.values())
|
||||
total_sselect = sum(len(stmts['sselect']) for stmts in files_statements.values())
|
||||
total_vselect = sum(len(stmts['vselect']) for stmts in files_statements.values())
|
||||
total_update = sum(len(stmts['update']) for stmts in files_statements.values())
|
||||
total_delete = sum(len(stmts['delete']) for stmts in files_statements.values())
|
||||
total_insert = sum(len(stmts['insert']) for stmts in files_statements.values())
|
||||
total_statements = total_select + total_sselect + total_vselect + total_update + total_delete + total_insert
|
||||
|
||||
# 写入输出文件(按文件分组输出)
|
||||
if total_statements > 0:
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(f"// 共提取到 {total_statements} 条SQL语句\n")
|
||||
f.write(f"// 处理了 {processed_files} 个文件\n")
|
||||
f.write(f"// SELECT: {total_select} 条\n")
|
||||
f.write(f"// SSELECT: {total_sselect} 条\n")
|
||||
f.write(f"// VSELECT: {total_vselect} 条\n")
|
||||
f.write(f"// UPDATE: {total_update} 条\n")
|
||||
f.write(f"// DELETE: {total_delete} 条\n")
|
||||
f.write(f"// INSERT: {total_insert} 条\n")
|
||||
f.write("//" + "=" * 80 + "\n")
|
||||
|
||||
# 按文件输出
|
||||
for file_path, statements in sorted(files_statements.items()):
|
||||
file_total = sum(len(stmts) for stmts in statements.values())
|
||||
|
||||
f.write("\n")
|
||||
f.write("//" + "=" * 80 + "\n")
|
||||
f.write(f"// 文件: {file_path}\n")
|
||||
f.write(f"// 共 {file_total} 条语句 "
|
||||
f"(SELECT: {len(statements['select'])}, "
|
||||
f"SSELECT: {len(statements['sselect'])}, "
|
||||
f"VSELECT: {len(statements['vselect'])}, "
|
||||
f"UPDATE: {len(statements['update'])}, "
|
||||
f"DELETE: {len(statements['delete'])}, "
|
||||
f"INSERT: {len(statements['insert'])})\n")
|
||||
f.write("//" + "=" * 80 + "\n")
|
||||
|
||||
# 按顺序输出:select -> sselect -> vselect -> update -> delete -> insert
|
||||
for stmt_type in ['select', 'sselect', 'vselect', 'update', 'delete', 'insert']:
|
||||
stmts = statements[stmt_type]
|
||||
|
||||
if stmts:
|
||||
for idx, stmt in enumerate(stmts, 1):
|
||||
f.write(stmt)
|
||||
f.write("\n")
|
||||
|
||||
print(f"\n✓ 成功提取 {total_statements} 条SQL语句")
|
||||
print(f" - SELECT: {total_select} 条")
|
||||
print(f" - SSELECT: {total_sselect} 条")
|
||||
print(f" - VSELECT: {total_vselect} 条")
|
||||
print(f" - UPDATE: {total_update} 条")
|
||||
print(f" - DELETE: {total_delete} 条")
|
||||
print(f" - INSERT: {total_insert} 条")
|
||||
print(f"✓ 结果已保存到: {output_file}")
|
||||
else:
|
||||
print(f"\n! 没有找到匹配的SQL语句")
|
||||
|
||||
if error_files:
|
||||
print(f"\n! 有 {len(error_files)} 个文件处理失败")
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
# 配置参数
|
||||
source_directory = "/mnt/c/Programs/Tinysoft/TSLGen2/funcext" # 当前目录,可以修改为你的目标目录
|
||||
output_file = "test_sql_statements.tsf"
|
||||
|
||||
# 可以指定只处理特定扩展名的文件,如 ['.sql', '.txt']
|
||||
# 设为 None 则处理所有文件
|
||||
file_extensions = ['.tsf']
|
||||
|
||||
print(f"开始扫描目录: {os.path.abspath(source_directory)}")
|
||||
print(f"输出文件: {output_file}")
|
||||
print(f"文件类型: {file_extensions if file_extensions else '所有文件'}")
|
||||
print("-" * 80)
|
||||
|
||||
# 检查目录是否存在
|
||||
if not os.path.exists(source_directory):
|
||||
print(f"错误: 目录不存在: {source_directory}")
|
||||
return
|
||||
|
||||
# 执行提取
|
||||
read_files_recursively(source_directory, output_file, file_extensions)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 生成 Tree-sitter 解析器
|
||||
echo "=== 生成 Tree-sitter 解析器 ==="
|
||||
# tree-sitter generate || { echo "❌ tree-sitter generate 失败"; exit 1; }
|
||||
|
||||
# 要解析的根目录数组
|
||||
ROOT_DIRS=(
|
||||
# "/mnt/d/code/tinysoft/OfficeXml-dev/funcext/OfficeXml/autounit"
|
||||
# "/mnt/d/code/tinysoft/OfficeXml-dev/funcext/OfficeXml/openxml"
|
||||
# "/mnt/d/code/tinysoft/OfficeXml-dev/funcext/OfficeXml/utils"
|
||||
# "/mnt/d/code/tinysoft/OfficeXml-dev/funcext/OfficeXml/docx"
|
||||
# "/mnt/d/code/tinysoft/OfficeXml-dev/generator"
|
||||
# "/mnt/d/code/tinysoft/tsoffice/"
|
||||
# "/mnt/d/code/tinysoft/pdfconverter"
|
||||
# "/mnt/c/Programs/Tinysoft/TSLGen2/funcext/other"
|
||||
# "/mnt/c/Programs/Tinysoft/TSLGen2/funcext/tsword"
|
||||
# "/mnt/c/Programs/Tinysoft/TSLGen2/funcext/word2arr"
|
||||
# "/mnt/c/Programs/Tinysoft/TSLGen2/funcext/tsoffice"
|
||||
# "/mnt/c/Programs/Tinysoft/TSLGen2/funcext/OfficeXml-dev"
|
||||
# "/mnt/d/code/tinysoft/PdfConverter"
|
||||
"/mnt/c/Programs/Tinysoft/TSLGen2/funcext"
|
||||
# 可以添加更多目录
|
||||
# "/path/to/third/directory"
|
||||
)
|
||||
|
||||
echo "=== 开始递归解析所有 .tsf 文件 ==="
|
||||
|
||||
# 错误标志
|
||||
has_error=false
|
||||
|
||||
# 遍历所有根目录
|
||||
for root_dir in "${ROOT_DIRS[@]}"; do
|
||||
echo "--- 处理目录: $root_dir"
|
||||
|
||||
# 检查目录是否存在
|
||||
if [ ! -d "$root_dir" ]; then
|
||||
echo "❌ 目录不存在: $root_dir"
|
||||
has_error=true
|
||||
continue
|
||||
fi
|
||||
|
||||
# 遍历当前目录下的所有 .tsf 文件
|
||||
while IFS= read -r -d '' file; do
|
||||
echo "--- 正在解析: $file"
|
||||
# output=$(tree-sitter parse "$file" 2>&1)
|
||||
output=$(tree-sitter parse "$file" 2>&1 | tr -d '\0')
|
||||
if echo "$output" | grep -q "ERROR\|MISSING"; then
|
||||
echo "❌ 语法错误在文件: $file"
|
||||
echo "$output"
|
||||
echo "--- 错误详情结束 ---"
|
||||
has_error=true
|
||||
# 如果希望遇到错误立即停止,取消注释下面这行
|
||||
break
|
||||
else
|
||||
echo "✓ 解析成功: $file"
|
||||
fi
|
||||
done < <(find "$root_dir" -type f -name "*.tsf" -print0)
|
||||
done
|
||||
|
||||
# 检查是否有错误
|
||||
if [ "$has_error" = true ]; then
|
||||
echo "❌ 解析过程中发现错误"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ 所有文件解析成功"
|
||||
@@ -0,0 +1,12 @@
|
||||
<?tslx>
|
||||
<?tsl echo "123"; ?>
|
||||
aaaa
|
||||
<?= echo "123" ?>
|
||||
<?tsl
|
||||
|
||||
a := 1;
|
||||
|
||||
function abc();
|
||||
begin
|
||||
a := 1;
|
||||
end
|
||||
@@ -0,0 +1,606 @@
|
||||
// ============================================
|
||||
// TSF 语法单元测试
|
||||
// ============================================
|
||||
|
||||
// ============================================
|
||||
// 1. 字面量测试
|
||||
// ============================================
|
||||
|
||||
// 数字字面量
|
||||
123;
|
||||
+456;
|
||||
-789;
|
||||
123.456;
|
||||
.456;
|
||||
123.;
|
||||
123e10;
|
||||
123e-5;
|
||||
+123.456e+10;
|
||||
0xFF;
|
||||
0xABCD;
|
||||
0b1010;
|
||||
0o777;
|
||||
|
||||
// 字符串字面量
|
||||
"hello world";
|
||||
'single quote';
|
||||
"escape \n \r \t \\ \" \'";
|
||||
"unicode \u4E2D \U00004E2D";
|
||||
"hex \x41 \x42";
|
||||
L"wide string";
|
||||
L'wide char';
|
||||
|
||||
// 字符字面量
|
||||
#65;
|
||||
#$41;
|
||||
#$FF;
|
||||
|
||||
// 布尔值
|
||||
true;
|
||||
false;
|
||||
TRUE;
|
||||
FALSE;
|
||||
True;
|
||||
False;
|
||||
|
||||
// 特殊值
|
||||
nil;
|
||||
nan;
|
||||
+inf;
|
||||
-inf;
|
||||
...;
|
||||
|
||||
// ============================================
|
||||
// 2. 标识符测试
|
||||
// ============================================
|
||||
|
||||
identifier;
|
||||
_underscore;
|
||||
camelCase;
|
||||
PascalCase;
|
||||
snake_case;
|
||||
with123numbers;
|
||||
中文标识符;
|
||||
混合Chinese123标识符;
|
||||
|
||||
// ============================================
|
||||
// 3. 一元表达式测试
|
||||
// ============================================
|
||||
|
||||
// 前缀一元运算符
|
||||
+x;
|
||||
-x;
|
||||
not x;
|
||||
.!x;
|
||||
.!!x;
|
||||
##x();
|
||||
|
||||
// 表达式运算符
|
||||
@expr;
|
||||
&expr;
|
||||
|
||||
// 前缀自增自减
|
||||
++x;
|
||||
--x;
|
||||
|
||||
// 后缀自增自减
|
||||
x++;
|
||||
x--;
|
||||
|
||||
// ============================================
|
||||
// 4. 二元表达式测试
|
||||
// ============================================
|
||||
|
||||
// 算术运算
|
||||
a + b;
|
||||
a - b;
|
||||
a * b;
|
||||
a / b;
|
||||
a \ b;
|
||||
a % b;
|
||||
a mod b;
|
||||
a div b;
|
||||
|
||||
// 幂运算(右结合)
|
||||
a ^ b;
|
||||
a :^ b;
|
||||
a ^ b ^ c;
|
||||
|
||||
// 矩阵运算
|
||||
a :* b;
|
||||
a :/ b;
|
||||
a :\ b;
|
||||
a | b;
|
||||
a :| b;
|
||||
|
||||
// 位运算
|
||||
a .| b;
|
||||
a .& b;
|
||||
a .^ b;
|
||||
|
||||
// 移位运算
|
||||
a shl b;
|
||||
a shr b;
|
||||
a rol b;
|
||||
a ror b;
|
||||
|
||||
// 比较运算
|
||||
a = b;
|
||||
a .= b;
|
||||
a <> b;
|
||||
a .<> b;
|
||||
a > b;
|
||||
a .> b;
|
||||
a < b;
|
||||
a .< b;
|
||||
a >= b;
|
||||
a .>= b;
|
||||
a <= b;
|
||||
a .<= b;
|
||||
a like b;
|
||||
a in b;
|
||||
a is b;
|
||||
|
||||
// 逻辑运算
|
||||
a or b;
|
||||
a and b;
|
||||
a .|| b;
|
||||
a .&& b;
|
||||
a || b;
|
||||
a && b;
|
||||
|
||||
// 集合运算
|
||||
a union b;
|
||||
a union2 b;
|
||||
a intersect b;
|
||||
a outersect b;
|
||||
a minus b;
|
||||
|
||||
// 范围
|
||||
a -> b;
|
||||
|
||||
// 连接运算
|
||||
a $ b;
|
||||
|
||||
// 对数运算
|
||||
a ~ b;
|
||||
|
||||
// ============================================
|
||||
// 5. 三元表达式测试
|
||||
// ============================================
|
||||
|
||||
condition ? consequence : alternative;
|
||||
a > b ? a : b;
|
||||
nested ? (inner ? x : y) : z;
|
||||
condition ? : default_value;
|
||||
|
||||
// ============================================
|
||||
// 6. 赋值表达式测试
|
||||
// ============================================
|
||||
|
||||
// 基本赋值
|
||||
x := 10;
|
||||
|
||||
// 复合赋值
|
||||
x += 1;
|
||||
x -= 1;
|
||||
x *= 2;
|
||||
x /= 2;
|
||||
x \= 2;
|
||||
x ^= 2;
|
||||
x ~= 2;
|
||||
x %= 2;
|
||||
x div= 2;
|
||||
x |= 1;
|
||||
x :|= 1;
|
||||
x &= 1;
|
||||
x :*= 1;
|
||||
x :/= 1;
|
||||
x :\= 1;
|
||||
x :^= 1;
|
||||
x ::= 1;
|
||||
x .|= 1;
|
||||
x .&= 1;
|
||||
x .||= 1;
|
||||
x .&&= 1;
|
||||
x .^= 1;
|
||||
x union= set1;
|
||||
x union2= set1;
|
||||
x intersect= set1;
|
||||
x outersect= set1;
|
||||
x minus= set1;
|
||||
|
||||
// 下标赋值
|
||||
arr[0] := 10;
|
||||
matrix[i, j] := 20;
|
||||
|
||||
// 属性赋值
|
||||
obj.property := value;
|
||||
|
||||
// 解包赋值
|
||||
[a, b, c] := array(1, 2, 3);
|
||||
[x, y] := tuple;
|
||||
|
||||
// ============================================
|
||||
// 7. 数组测试(重点)
|
||||
// ============================================
|
||||
|
||||
// 空数组
|
||||
array();
|
||||
|
||||
// 简单数组
|
||||
array(1, 2, 3);
|
||||
array(1, 2, 3,);
|
||||
|
||||
// 多种类型混合
|
||||
array(1, "string", true, nil, 3.14);
|
||||
|
||||
// 键值对数组
|
||||
array(a: 1, b: 2, c: 3);
|
||||
array("key1": "value1", "key2": "value2");
|
||||
array(1: "one", 2: "two", 3: "three");
|
||||
|
||||
// 隐式数组(嵌套括号)
|
||||
array((1, 2, 3));
|
||||
array((a, b), (c, d));
|
||||
|
||||
// 键值对带隐式数组
|
||||
array(
|
||||
point1: (x, y, z),
|
||||
point2: (1, 2, 3)
|
||||
);
|
||||
|
||||
// 混合数组元素
|
||||
array(
|
||||
1,
|
||||
key: value,
|
||||
(a, b, c),
|
||||
nested: (1, 2, 3),
|
||||
"string"
|
||||
);
|
||||
|
||||
// 嵌套数组
|
||||
array(
|
||||
array(1, 2, 3),
|
||||
array(4, 5, 6),
|
||||
array(7, 8, 9)
|
||||
);
|
||||
|
||||
// 多层嵌套
|
||||
array(
|
||||
array(
|
||||
array(1, 2),
|
||||
array(3, 4)
|
||||
),
|
||||
array(
|
||||
array(5, 6),
|
||||
array(7, 8)
|
||||
)
|
||||
);
|
||||
|
||||
// 复杂键值对嵌套
|
||||
array(
|
||||
matrix: array(
|
||||
row1: array(1, 2, 3),
|
||||
row2: array(4, 5, 6)
|
||||
),
|
||||
vector: array(x: 1, y: 2, z: 3),
|
||||
nested: (
|
||||
(1, 2),
|
||||
(3, 4)
|
||||
)
|
||||
);
|
||||
|
||||
// 数组带表达式
|
||||
array(1 + 2, 3 * 4, 5 ^ 6);
|
||||
array(func(), obj.method(), arr[0]);
|
||||
|
||||
// 数组带条件表达式
|
||||
array(
|
||||
a > b ? a : b,
|
||||
condition ? x : y
|
||||
);
|
||||
|
||||
|
||||
// 尾随逗号测试
|
||||
array(1, 2, 3,);
|
||||
array(a: 1, b: 2,);
|
||||
array((1, 2, 3,));
|
||||
|
||||
// ============================================
|
||||
// 8. 下标访问测试
|
||||
// ============================================
|
||||
|
||||
// 基本下标
|
||||
arr[0];
|
||||
arr[i];
|
||||
matrix[x, y];
|
||||
|
||||
// 切片
|
||||
arr[:];
|
||||
arr[1:];
|
||||
arr[:10];
|
||||
arr[1:10];
|
||||
|
||||
// 矩阵切片
|
||||
matrix[:, :];
|
||||
matrix[1:5, 2:8];
|
||||
matrix[:, 0];
|
||||
matrix[0, :];
|
||||
matrix[1:, :5];
|
||||
|
||||
// 多维切片
|
||||
tensor[1:5, 2:8, 3:9];
|
||||
tensor[:, :, 0];
|
||||
|
||||
// 嵌套下标
|
||||
arr[0][1];
|
||||
matrix[i][j];
|
||||
arr[func()][obj.attr];
|
||||
|
||||
// ============================================
|
||||
// 9. 属性访问测试
|
||||
// ============================================
|
||||
|
||||
obj.property;
|
||||
obj.method;
|
||||
nested.obj.property;
|
||||
arr[0].attribute;
|
||||
func().result;
|
||||
(expr).attr;
|
||||
|
||||
// ============================================
|
||||
// 9.5. 链式调用测试(属性和方法混合)
|
||||
// ============================================
|
||||
|
||||
// 方法后访问属性
|
||||
obj.method().property;
|
||||
func().result.value;
|
||||
|
||||
// 属性后调用方法
|
||||
obj.property.method();
|
||||
data.field.toString();
|
||||
|
||||
// 混合链式调用
|
||||
obj.Abc().def.FGH();
|
||||
obj.method1().property.method2();
|
||||
obj.a().b().c().d();
|
||||
obj.a.b().c.d();
|
||||
|
||||
// 复杂链式
|
||||
obj.getData().results[0].format();
|
||||
obj.query().filter().map().reduce();
|
||||
api.connect().auth().request().parse();
|
||||
|
||||
// 链式调用带参数
|
||||
obj.method(arg).property.next(param);
|
||||
builder.setX(1).setY(2).setZ(3).build();
|
||||
|
||||
// 链式调用带下标
|
||||
obj.method()[0].property;
|
||||
arr.filter()[0].name;
|
||||
data.get("key").items[0].process();
|
||||
|
||||
// 超长链式
|
||||
obj.a.b.c.d.e.f.g.h.i.j.k();
|
||||
func1().func2().func3().func4().func5();
|
||||
|
||||
// 混合运算符的链式
|
||||
obj.fetch().result := value;
|
||||
|
||||
// 链式调用在表达式中
|
||||
obj.calculate().result + other.getValue().data;
|
||||
arr.first().value * matrix.last().coefficient;
|
||||
|
||||
// ============================================
|
||||
// 10. 函数调用测试
|
||||
// ============================================
|
||||
|
||||
// 无参数调用
|
||||
func();
|
||||
|
||||
// 单参数
|
||||
func(arg);
|
||||
|
||||
// 多参数
|
||||
func(a, b, c);
|
||||
|
||||
// 命名参数
|
||||
func(name: value);
|
||||
func(x: 1, y: 2, z: 3);
|
||||
|
||||
// 混合参数
|
||||
func(1, 2, name: value, 3, key: data);
|
||||
|
||||
// const 参数
|
||||
func(const arg);
|
||||
func(const x, const y);
|
||||
|
||||
// 星号参数
|
||||
// func(*);
|
||||
// func(a, *, b);
|
||||
|
||||
// 嵌套调用
|
||||
func1(func2(func3()));
|
||||
|
||||
// 链式调用
|
||||
obj.method1().method2().method3();
|
||||
|
||||
// ============================================
|
||||
// 11. 括号表达式测试
|
||||
// ============================================
|
||||
|
||||
(expr);
|
||||
((nested));
|
||||
(a + b) * (c + d);
|
||||
(condition ? x : y);
|
||||
|
||||
// ============================================
|
||||
// 12. 内置表达式测试
|
||||
// ============================================
|
||||
|
||||
// new 表达式
|
||||
new ClassName;
|
||||
new MyClass();
|
||||
|
||||
// echo 表达式
|
||||
echo "message";
|
||||
echo x, y, z;
|
||||
echo "value:", value, "result:", result;
|
||||
|
||||
// raise 表达式
|
||||
raise Exception;
|
||||
raise CustomError("message");
|
||||
|
||||
// inherited 表达式
|
||||
inherited;
|
||||
inherited method();
|
||||
inherited ParentClass.method();
|
||||
|
||||
// ============================================
|
||||
// 13. 复杂组合测试
|
||||
// ============================================
|
||||
|
||||
// 运算符优先级混合
|
||||
a + b * c;
|
||||
(a + b) * c;
|
||||
a ^ b * c;
|
||||
a + b ^ c;
|
||||
a and b or c;
|
||||
(a and b) or c;
|
||||
|
||||
// 链式运算
|
||||
a.b.c.d;
|
||||
arr[0][1][2];
|
||||
obj.method().property[0];
|
||||
|
||||
// 复杂赋值
|
||||
obj.arr[i].prop := value;
|
||||
matrix[x, y] += delta;
|
||||
obj.counter++;
|
||||
|
||||
// 复杂数组初始化
|
||||
array(
|
||||
id: 1,
|
||||
name: "test",
|
||||
values: array(1, 2, 3),
|
||||
matrix: array(
|
||||
array(1, 2),
|
||||
array(3, 4)
|
||||
),
|
||||
computed: func(),
|
||||
conditional: x > 0 ? pos : neg,
|
||||
nested: (
|
||||
(a, b),
|
||||
(c, d)
|
||||
)
|
||||
);
|
||||
|
||||
// 复杂表达式
|
||||
((a + b) * c - d) / (e ^ f);
|
||||
func(x: a + b, y: c * d, z: array(1, 2, 3));
|
||||
obj.method(arr[0], key: value).property++;
|
||||
|
||||
// 多层嵌套结构
|
||||
array(
|
||||
level1: array(
|
||||
level2: array(
|
||||
level3: array(
|
||||
data: (1, 2, 3)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 14. 边界情况测试
|
||||
// ============================================
|
||||
|
||||
// 空切片
|
||||
arr[];
|
||||
|
||||
// 单元素数组
|
||||
array(1);
|
||||
array(1,);
|
||||
|
||||
// 单键值对
|
||||
array(key: value);
|
||||
|
||||
// 空隐式数组(语法上可能无效,但测试边界)
|
||||
array(());
|
||||
|
||||
// 连续运算符
|
||||
a+-b;
|
||||
a-+b;
|
||||
|
||||
// 长标识符链
|
||||
very.long.chain.of.attributes.and.calls().more[0].data;
|
||||
|
||||
// 深层嵌套表达式
|
||||
((((((expr))))));
|
||||
|
||||
// 多行数组格式
|
||||
array(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
);
|
||||
|
||||
// ============================================
|
||||
// 15. 解包模式测试
|
||||
// ============================================
|
||||
|
||||
[a] := array(1);
|
||||
[a, b] := array(1, 2);
|
||||
[x, y, z] := tuple;
|
||||
[first, second, third] := values;
|
||||
|
||||
// ============================================
|
||||
// 16. 组合运算测试
|
||||
// ============================================
|
||||
|
||||
// 矩阵和标量混合
|
||||
matrix :* scalar + vector;
|
||||
(matrix :| vector) :^ 2;
|
||||
|
||||
// 位运算和逻辑运算
|
||||
(a .& b) .|| (c .^ d);
|
||||
a and (b .| c);
|
||||
|
||||
// 集合运算链
|
||||
set1 union set2 intersect set3;
|
||||
(set1 union set2) minus set3;
|
||||
|
||||
// 范围和运算
|
||||
(1 -> 10) union (20 -> 30);
|
||||
array(0 -> 9);
|
||||
|
||||
// 字符串连接
|
||||
"hello" $ " " $ "world";
|
||||
str1 $ str2 $ str3;
|
||||
|
||||
// ============================================
|
||||
// 17. 特殊语法组合
|
||||
// ============================================
|
||||
|
||||
// 三元嵌套
|
||||
a ? b ? c : d : e ? f : g;
|
||||
|
||||
// 赋值链(如果支持)
|
||||
a := b := c := 0;
|
||||
|
||||
// 调用后自增
|
||||
arr[0]++;
|
||||
|
||||
// 属性链式赋值
|
||||
obj.a.b.c := value;
|
||||
|
||||
// 复杂下标表达式
|
||||
arr[i + 1][j * 2];
|
||||
matrix[func(x), obj.y];
|
||||
|
||||
// // ============================================
|
||||
// // 测试完成
|
||||
// // ============================================
|
||||
@@ -0,0 +1,87 @@
|
||||
class(test).test1(); // 允许这样调用class function
|
||||
// class(); // 不允许这么调用函数
|
||||
// in();
|
||||
// do();
|
||||
// select();
|
||||
// sselect();
|
||||
// vselect();
|
||||
// update();
|
||||
// delete();
|
||||
// insert();
|
||||
type(); // 仅有type允许函数调用
|
||||
|
||||
// var global static const
|
||||
var type := 1; // 仅var允许
|
||||
// global type: string := "123";
|
||||
// static type: integer := 123;
|
||||
// const type = 123;
|
||||
|
||||
// 赋值
|
||||
type := 1; // 允许左值,也要允许右值
|
||||
// class := 1; // 不允许
|
||||
// do := 1; // 不允许
|
||||
// select := 1; // 不允许
|
||||
// sselect := 1; // 不允许
|
||||
// vselect := 1; // 不允许
|
||||
// update := 1; // 不允许
|
||||
// delete := 1; // 不允许
|
||||
// insert := 1; // 不允许
|
||||
// in := 1; // 不允许
|
||||
|
||||
// 对象调用 除了class都允许
|
||||
o := new test();
|
||||
o.In();
|
||||
o.type();
|
||||
o.Do();
|
||||
o.Select();
|
||||
o.SSelect();
|
||||
o.VSelect();
|
||||
o.Delete();
|
||||
o.Update();
|
||||
o.Insert();
|
||||
|
||||
// function class(); // 不允许函数名
|
||||
// begin
|
||||
// end;
|
||||
// function In(); // 不允许
|
||||
// begin
|
||||
// end;
|
||||
// function Do();
|
||||
// begin
|
||||
// end;
|
||||
// function Select();
|
||||
// begin
|
||||
// end;
|
||||
// function SSelect();
|
||||
// begin
|
||||
// end;
|
||||
// function VSelect();
|
||||
// begin
|
||||
// end;
|
||||
// function Delete();
|
||||
// begin
|
||||
// end;
|
||||
// function Update();
|
||||
// begin
|
||||
// end;
|
||||
// function Insert();
|
||||
// begin
|
||||
// end;
|
||||
function type();
|
||||
begin
|
||||
end;
|
||||
|
||||
type test = class
|
||||
class function test1();
|
||||
|
||||
// function class(); //不允许
|
||||
function In();
|
||||
function type();
|
||||
function Do();
|
||||
function Select();
|
||||
function SSelect();
|
||||
function VSelect();
|
||||
function Delete();
|
||||
function Update();
|
||||
function Insert();
|
||||
end;
|
||||
@@ -0,0 +1,15 @@
|
||||
function(arr, i);
|
||||
begin
|
||||
end
|
||||
function(arr, i);
|
||||
begin
|
||||
echo "123";
|
||||
end;
|
||||
pf := function(arr, i);
|
||||
begin
|
||||
echo "123";
|
||||
end
|
||||
pf := function(arr, i);
|
||||
begin
|
||||
echo "123";
|
||||
end;;
|
||||
@@ -0,0 +1,242 @@
|
||||
// 共提取到 127 条SQL语句
|
||||
// 处理了 115 个文件
|
||||
// SELECT: 64 条
|
||||
// SSELECT: 23 条
|
||||
// VSELECT: 11 条
|
||||
// UPDATE: 24 条
|
||||
// DELETE: 3 条
|
||||
// INSERT: 2 条
|
||||
//================================================================================
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/OfficeXml-dev/funcext/OfficeXml/docx/vba/DocxVba.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 1, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
sselect ['FileName'] from zip.Files() where AnsiStartsText('word/media/image', ['FileName']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/OfficeXml-dev/generator/CreateAdapter.tsf
|
||||
// 共 3 条语句 (SELECT: 2, SSELECT: 0, VSELECT: 0, UPDATE: 1, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select * from children where not ifnil(['adapter_key']) end;
|
||||
select * from children where not ifnil(['adapter_child_key']) end;
|
||||
update children set ['adapter_key'] = array(['adapter_key']) where ifString(['adapter_key']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/OfficeXml-dev/generator/CreateDecorator.tsf
|
||||
// 共 6 条语句 (SELECT: 1, SSELECT: 1, VSELECT: 0, UPDATE: 4, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select ['field'], select * from thisgroup end as 'detail' from children group by ['field'] having countof(['field']) > 1 end;
|
||||
sselect["field"] from ml_children end;
|
||||
update attrs set ['new_field'] = format('XmlAttr%s', ['field']) end;
|
||||
update children set ['origin_field'] = ['field'] end;
|
||||
update children set ['field'] = uppercase(['prefix']) + ['field'] where not ifnil(['ml']) and ['field'] in fields end;
|
||||
update children set ['new_field'] = format('XmlChild%s', ['field']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/OfficeXml-dev/generator/CreateTslUnit.tsf
|
||||
// 共 16 条语句 (SELECT: 5, SSELECT: 3, VSELECT: 0, UPDATE: 8, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select ['field'], select * from thisgroup end as 'detail' from attrs group by ['field'] having countof(['field']) > 1 end;
|
||||
select ['field'], select * from thisgroup end as 'detail' from children group by ['field'] having countof(['field']) > 1 end;
|
||||
select ['origin_field'], select * from thisgroup end as 'detail' from attrs group by ['origin_field'] having countof(['origin_field']) > 1 end;
|
||||
select ['origin_field'], select * from thisgroup end as 'detail' from children group by ['origin_field'] having countof(['origin_field']) > 1 end;
|
||||
select * from children where ['multi'] <> 1 end;
|
||||
sselect ['ml'] from children where ifString(['ml']) end;
|
||||
sselect ['field'] from mu_attrs end;
|
||||
sselect ['field'] from mu_children end;
|
||||
update attrs set ['origin_field'] = ['field'] end;
|
||||
update attrs set ['field'] = uppercase(['prefix']) + ['field'] where ifstring(['prefix']) and ['field'] in fields end;
|
||||
update attrs set ['field'] = ['field'] + 'N' where ifnil(['prefix']) and ['field'] in fields end;
|
||||
update attrs set ['new_field'] = format('XmlAttr%s', ['field']) end;
|
||||
update children set ['origin_field'] = ['field'] end;
|
||||
update children set ['field'] = uppercase(['prefix']) + ['field'] where ifstring(['prefix']) and ['field'] in fields end;
|
||||
update children set ['field'] = ['field'] + 'N' where ifnil(['prefix']) and ['field'] in fields end;
|
||||
update children set ['new_field'] = format('XmlChild%s', ['field']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/TOfficeObj.tsf
|
||||
// 共 10 条语句 (SELECT: 3, SSELECT: 5, VSELECT: 1, UPDATE: 1, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select thisrowindex as 'Index' from commentsArray_ where ['ID'] = id end;
|
||||
select * from commentsArray_ where thisrowindex <= r[1]['Index'] and thisrowindex >= r[0]['Index'] end;
|
||||
select * from Tabs where thisrowindex <> ind end;
|
||||
sselect distinct ['ID'] from commentsArray_ where ['ID'] >= 0 end;
|
||||
sselect ['obj'] from Tabs end;
|
||||
sselect ['FileName'] from zipfile.Files() where AnsiStartsText('word/media/image', ['FileName']) end;
|
||||
sselect ['FileName'] from zipfile_.Files() where AnsiStartsText('word/media/image', ['FileName']) end;
|
||||
sselect ['FileName'] from zipfile_.Files() where AnsiStartsText('word/' $ headerFooter, ['FileName']) end;
|
||||
vselect countof( ['FileName'] ) from docx.Zip().Files() where AnsiStartsText('word/embeddings/Workbook', ['FileName']) end;
|
||||
update pArr set ['pIndex'] = i end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/TSDocxFile.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 0, VSELECT: 1, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
vselect thisrowindex from files where ['FileName']=file end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/TSUtils/NodeInfo.tsf
|
||||
// 共 4 条语句 (SELECT: 2, SSELECT: 2, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select * from children where lName = lowerCase(['field']) end;
|
||||
select * from children where lName = lowerCase(['field']) end;
|
||||
sselect * from attrs where lName = lowerCase([0]) end;
|
||||
sselect * from attrs where lName = lowerCase([0]) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/document/TDocxChart.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 0, VSELECT: 1, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
vselect countof( ['FileName'] ) from docx.Zip().Files() where AnsiStartsText('word/charts/chart', ['FileName']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/document/TDocxCopy.tsf
|
||||
// 共 3 条语句 (SELECT: 0, SSELECT: 3, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
sselect ['FileName'] from zip.Files() where AnsiStartsText('word/' $ tar_prefix, ['FileName']) end;
|
||||
sselect ['FileName'] from zip.Files() where AnsiStartsText('word/media/image', ['FileName']) end;
|
||||
sselect ['FileName'] from zip.Files() where AnsiStartsText('word/charts/chart', ['FileName']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/worksheet/xlsxImage.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 1, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
sselect ['FileName'] from zipfile_.Files() where AnsiStartsText('xl/media/image', ['FileName']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/TSOffice/funcext/TSOffice/worksheet/xlsxWorkBook.tsf
|
||||
// 共 6 条语句 (SELECT: 1, SSELECT: 2, VSELECT: 3, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select * from sheetNames_ where thisrowindex <> ind end;
|
||||
sselect ['FileName'] from files where AnsiContainsStr(['FileName'], 'tables/table') end;
|
||||
sselect ['name'] from sheetNames_ end;
|
||||
vselect maxof(['sheetId']) from sheetNames_ end;
|
||||
vselect thisrowindex from files where ['FileName'] = oldname end;
|
||||
vselect maxof(['sheetId']) from sheetNames_ end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/other/TS_Excel.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 1, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
sselect length(str2array(thisrow, "@"))-1 from arr order by length(str2array(thisrow, "@")) desc end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/other/sysconfdb.tsf
|
||||
// 共 17 条语句 (SELECT: 12, SSELECT: 1, VSELECT: 0, UPDATE: 2, DELETE: 1, INSERT: 1)
|
||||
//================================================================================
|
||||
select ['TSID'],['CID'],['CNAME'],['KEY_NAME'] FROM sqltable 'ts_sys_config' of GetDBAlias() where ["PID"] = arr['pid'] and (['CNAME'] = arr['cname'] or ['KEY_NAME'] = arr['key_name']) end;
|
||||
select ['cid'],['pid'],['cname'],['c_type'],['key_name'],['c_remarks'],['created_name'],['created_time'],setEncodeRSA(['c_type'], ['value_s']) AS 'value_s',['value_list'] from arr end;
|
||||
select * from data where ['PID'] = '0' AND ['KEY_NAME'] = RootKey END;
|
||||
Select * from data where ['PID'] = d1[0]['CID'] END;
|
||||
Select * from d2 where ['KEY_NAME'] = NodeKeyArr[i] END;
|
||||
select * from data where ['PID'] = '0' AND ['KEY_NAME'] = RootKey END;
|
||||
Select * from data where ['PID'] = d1[0]['CID'] END;
|
||||
Select * from d2 where ['KEY_NAME'] = NodeKeyArr[i] END;
|
||||
select * from data where ['CID'] = cid end;
|
||||
select * from data where ['PID'] = cid end;
|
||||
select ['CNAME'] as "配置名称",
|
||||
['KEY_NAME'] as "配置KEY",
|
||||
GetConfigurationKey(['C_TYPE'],['VALUE_S'],['VALUE_LIST']) as "配置值",
|
||||
['C_TYPE'] as "配置类型",
|
||||
['C_REMARKS'] as "备注",
|
||||
GetConfigurationValueList(['C_TYPE'],['VALUE_LIST']) as "配置可选值" from data where ['CID'] = cid end;
|
||||
select * from data where ['PID'] = cid end;
|
||||
sselect ['VALUE'] from d2 where ['KEY'] in t1 end;
|
||||
Update sqltable 'ts_sys_config' of GetDBAlias() set ['PID'] = arr['pid'],
|
||||
['CNAME'] = arr['cname'],
|
||||
['KEY_NAME'] = arr['key_name'],
|
||||
['VALUE_S'] = arr['value_s'],
|
||||
['C_TYPE'] = arr['c_type'],
|
||||
['C_REMARKS'] = arr['c_remarks'],
|
||||
['UPDATED_BY'] = arr['updated_by'],
|
||||
['VALUE_LIST'] = arr['value_list'],
|
||||
['UPDATED_TIME'] = arr['updated_time'] where ['CID'] = arr['cid'] end;
|
||||
Update sqltable 'ts_sys_config' of GetDBAlias() set ['VALUE_S'] = arr['value_s'],
|
||||
['UPDATED_BY'] = arr['updated_by'],
|
||||
['UPDATED_TIME'] = arr['updated_time'] where ['CID'] = arr['cid'] end;
|
||||
DELETE FROM sqltable 'SELECT * FROM ts_sys_config' of GetDBAlias() where ["CID"] IN arr ;
|
||||
Insert INTO sqltable 'ts_sys_config' of GetDBAlias() arr;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/other/tgenreport.tsf
|
||||
// 共 21 条语句 (SELECT: 10, SSELECT: 2, VSELECT: 3, UPDATE: 6, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select * from t order by ["名称"] end;
|
||||
select * from r where not (['did'] in (sselect ['ID'] from existsDidArr end)) end;
|
||||
select * from preData where ['EID']= r[i]['EID'] end;
|
||||
select * from preData where ['EID']= r[i]['EID'] end;
|
||||
select * from wordConf where ['Value']=reportInfo['TType'] end;
|
||||
select [xName] from data end;
|
||||
select * from xData join data on [1].[xName] = [2].[xName] end;
|
||||
select [1],[3] from mgConf where [1]=num_row and [1]<>[3] and ([1]= num_colunm or [3]= num_colunm) end;
|
||||
select ['doc_order_no'],trim(['org_content']) as 'org_content' from reportData where ['type'] = 'title' end;
|
||||
select * from fzhTable where ['doc_order_no'] like '^'$ZXCWBB end;
|
||||
select * from r where not (['did'] in (sselect ['ID'] from existsDidArr end)) end;
|
||||
sselect distinct ['DATA_ID'] from EArr where ['type']='pdf' end;
|
||||
vselect ['PRE_DATA'] from rpt_latestData where ['EID']= EArr[j]['EID'] and ['PRE_TYPE']= EArr[j]['type'] end;
|
||||
vselect countof( * ) from fuZhuHaoTable where ['org_content'] like '转型前' end;
|
||||
vselect ['doc_order_no'] from fzhTable where ['org_content'] = title end;
|
||||
update r set ['did']= GenDataId(['EID'],productionID,pubDate,init_begindate,classify) end;
|
||||
update r set ['DATASOURCE']= class(Element).dataSource_autoInherit() where not (['EID'] in array('20150512171332212_95089541912828646461640993495')) end;
|
||||
update r set ['DATA_INIT_STATE']= 4 where not (['EID'] in array('20150512171332212_95089541912828646461640993495','20150304151252139_31808466412173073041697290538')) end;
|
||||
update EArr set ['content'] = ['doc_order_no']$' '$['content'] where ['doc_order_no'] and pos('、',['doc_order_no'])=0 end;
|
||||
update EArr set ['content'] = ['doc_order_no']$['content'] where ['doc_order_no'] and pos('、',['doc_order_no'])<>0 end;
|
||||
update reportConf set ['content'] = updateFuZhuHaoSub(fuzhuhaoHash,['content']) ,['Data'] = updateFuZhuHaoSub(fuzhuhaoHash,['Data'])
|
||||
where ['ename'] in array('资产负债表','利润表') and istable(['Data']) end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/tsword/ts_word.tsf
|
||||
// 共 1 条语句 (SELECT: 0, SSELECT: 1, VSELECT: 0, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
sselect thisrow from rules where thisrow <> "" end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/tsword/tsword_report.tsf
|
||||
// 共 2 条语句 (SELECT: 1, SSELECT: 0, VSELECT: 0, UPDATE: 1, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select [1],[3] from mgConf where [1]=num_row and [1]<>[3] and ([1]= num_colunm or [3]= num_colunm) end;
|
||||
update cellAlignConf set ["horizAlign"] = "left" end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/word2arr/helpdoctools.tsf
|
||||
// 共 29 条语句 (SELECT: 27, SSELECT: 0, VSELECT: 2, UPDATE: 0, DELETE: 0, INSERT: 0)
|
||||
//================================================================================
|
||||
select ["node_id"],["parent_id"],["node_name"],"sys" as "created_by","sys" as "updated_by",["node_order"],["node_type"],["bus_key"],1 as "is_valid" from data end;
|
||||
select ["node_id"],(["content"] + ".md") as "content","sys" as "created_by",["describe"] from data where ["describe"] <> "" and ["describe"] <> nil end;
|
||||
select ["node_id"],["content"],["created_by"] from tmp_contentdata end;
|
||||
select ["node_id"],["title"] from data where ["node_id"] = id end;
|
||||
select ["node_id"],["title"] from data where ["node_id"] = id or ["title"] = name end;
|
||||
select ["node_id"], ["parent_id"], ["node_order"], ["node_type"], ["bus_key"], ["node_name"] AS "title" from MenuData ORDER BY ["node_order"] end;
|
||||
select * from MenuData where ["node_id"] = id end;
|
||||
select ["node_id"], ["parent_id"], ["node_order"], ["node_type"], ["bus_key"], ["node_name"] AS "title" from MenuData ORDER BY ["node_order"] end;
|
||||
select * from MenuData where ["node_id"] = id end;
|
||||
select ["node_id"] AS "value", ["parent_id"], ["node_name"] AS "label", ["node_order"] from MenuData end;
|
||||
select ["value"], ["label"] from MenuData where ["parent_id"] = id end;
|
||||
select ["node_id"], ["parent_id"], ["node_order"], ["node_type"], ["bus_key"], ["node_name"] AS "title" from MenuData ORDER BY ["node_order"] end;
|
||||
select *, 1 as "expand" from MenuData where ["parent_id"] = id end;
|
||||
select * from MenuData where ["parent_id"] = nodeData[i]["value"] ORDER BY ["node_order"] end;
|
||||
select * from MenuData where ["parent_id"] = nodeData[i]["node_id"] ORDER BY ["node_order"] end;
|
||||
select * from MenuData where ["parent_id"] = nodeData[i]["node_id"] ORDER BY ["node_order"] end;
|
||||
select ["node_id"], ["parent_id"], ["node_name"] AS "title" from MenuData where ["node_id"] = id end;
|
||||
select ["node_id"], ["parent_id"], ["node_name"] AS "title", ["bus_key"] from MenuData where ["parent_id"] = id end;
|
||||
select ["node_id"],["node_name"] AS "title" from res["data"] end;
|
||||
select ["node_id"], (["node_order"] + 1) AS "node_order" from MenuList where ["node_order"] >= index ORDER BY ["node_order"] end;
|
||||
select ["node_id"] from oldMenuData where ["parent_id"] = pid end;
|
||||
select ["node_id"] from oldMenuData where ["parent_id"] = pid and ["title"] = newMenuData[i]["title"] and IsEmpty(["bus_key"]) end;
|
||||
select ["node_id"], ["parent_id"], ["node_order"], ["node_type"], ["bus_key"], ["node_name"] AS "title" from res["data"] ORDER BY ["node_order"] end;
|
||||
select ["node_id"], ["parent_id"], ["title"] from MenuData where ["node_id"] = nodeId end;
|
||||
select ["node_id"], ["parent_id"], ["node_order"] from MenuData where ["parent_id"] = nodeData[0]["node_id"] ORDER BY ["node_order"] end;
|
||||
select ["node_id"],["node_name"] AS "title" from res["data"] end;
|
||||
select ["parent_id"],["node_id"],["node_order"] from res["data"] where ["node_id"] <> param["bid"] end;
|
||||
vselect ["content"] from menuList where ["node_id"] = pid end;
|
||||
vselect ["node_order"] from res["data"] ORDER BY ["node_order"] desc end;
|
||||
|
||||
//================================================================================
|
||||
// 文件: /mnt/c/Programs/Tinysoft/TSLGen2/funcext/word2arr/sethelptreedocdb.tsf
|
||||
// 共 4 条语句 (SELECT: 0, SSELECT: 0, VSELECT: 0, UPDATE: 1, DELETE: 2, INSERT: 1)
|
||||
//================================================================================
|
||||
update sqltable "ts_helpDocMenu" of FDBAlias set ["is_valid"] = 0 where ["node_id"] in data end;
|
||||
delete from sqltable "ts_helpDocContent" of FDBAlias where ["node_id"] in data;
|
||||
delete from sqltable "ts_helpDocMenu" of FDBAlias where ["node_id"] in data;
|
||||
insert into sqltable tableName of FDBAlias data[i:i+999-1];
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
<?tslx>
|
||||
aa<?=ids_version()?>"
|
||||
src='js?v=<?=ids_version()?>'
|
||||
style="display: none;">
|
||||
@@ -0,0 +1,201 @@
|
||||
// TSF 变量声明测试代码示例
|
||||
// 用于测试 var, static, global, const 语法
|
||||
|
||||
//================================================================================
|
||||
// 1. var 声明测试
|
||||
//================================================================================
|
||||
// 保留关键字
|
||||
do := 13;
|
||||
type := "1234";
|
||||
in := f2();
|
||||
class := defff;
|
||||
delete := +inf;
|
||||
|
||||
// 基本声明
|
||||
var simple;
|
||||
var withType: integer;
|
||||
var withInit := 42;
|
||||
var complete: real := 3.14;
|
||||
|
||||
// 多变量声明
|
||||
var a, b, c;
|
||||
var x, y, z: integer;
|
||||
var m, n := 100;
|
||||
var p, q, r: string := "default";
|
||||
|
||||
// 数组类型
|
||||
var intArray: array of integer;
|
||||
var stringArray: array of string := null;
|
||||
var matrix: array of real;
|
||||
var tensor: array of float;
|
||||
|
||||
// 复杂类型名
|
||||
var list: System.Collections.List;
|
||||
var dict: System.Collections.Generic.Dictionary_string_int;
|
||||
var custom: MyNamespace.MyClass.NestedType;
|
||||
|
||||
// 复杂初始化器
|
||||
var fromFunc := getValue();
|
||||
var fromExpr := (a + b) * c;
|
||||
var fromArray := array(1, 2, 3, 4, 5);
|
||||
var fromCall := createObject("param1", 123, true);
|
||||
|
||||
//================================================================================
|
||||
// 2. static 声明测试
|
||||
//================================================================================
|
||||
|
||||
// 基本声明
|
||||
static counter;
|
||||
static typed: integer;
|
||||
static initialized := 0;
|
||||
static full: string := "static";
|
||||
|
||||
// 多变量声明
|
||||
static s1, s2, s3;
|
||||
static sx, sy: real;
|
||||
static sa, sb := 999;
|
||||
static sp, sq, sr: boolean := false;
|
||||
|
||||
// 静态数组
|
||||
static cache: array of object;
|
||||
static buffer: array of byte := null;
|
||||
static lookupTable: array of integer := createTable();
|
||||
|
||||
// 复杂类型和初始化
|
||||
static singleton: MyClass := MyClass.getInstance();
|
||||
static config: dictionary := loadConfig("app.config");
|
||||
static handler: EventHandler := lambda(e) { handleEvent(e); };
|
||||
|
||||
//================================================================================
|
||||
// 3. global 声明测试
|
||||
//================================================================================
|
||||
|
||||
// 基本声明
|
||||
global appConfig;
|
||||
global settings: object;
|
||||
global database := null;
|
||||
global connection: DBConnection := connect();
|
||||
|
||||
// 多变量声明
|
||||
global g1, g2;
|
||||
global gx, gy, gz: any;
|
||||
global ga, gb := "global";
|
||||
global gp, gq: integer := 0;
|
||||
|
||||
// 全局数组和集合
|
||||
global users: array of User;
|
||||
global cache: dictionary := createDictionary();
|
||||
global eventQueue: array of Event := array();
|
||||
|
||||
// 复杂全局变量
|
||||
global logger: ILogger := createLogger("app.log");
|
||||
global threadPool: ThreadPool := ThreadPool(4);
|
||||
global serviceLocator: ServiceLocator := ServiceLocator.default;
|
||||
|
||||
//================================================================================
|
||||
// 4. const 声明测试
|
||||
//================================================================================
|
||||
|
||||
// 数值常量
|
||||
const PI = 3.14159265359;
|
||||
const E = 2.71828;
|
||||
const MAX_INT: integer = 2147483647;
|
||||
const MIN_INT: integer = -2147483648;
|
||||
|
||||
// 字符串常量
|
||||
const VERSION = "1.0.0";
|
||||
const APP_NAME: string = "MyApplication";
|
||||
const PATH_SEPARATOR = "/";
|
||||
const EMPTY = "";
|
||||
|
||||
// 布尔常量
|
||||
const DEBUG = true;
|
||||
const RELEASE: boolean = false;
|
||||
const ENABLED = true;
|
||||
|
||||
// 表达式常量
|
||||
const BUFFER_SIZE = 1024 * 8;
|
||||
const TIMEOUT = 60 * 1000;
|
||||
const MASK = 0xFF;
|
||||
const COMBINED = "Hello" $ " " $ "World";
|
||||
|
||||
// 特殊值常量
|
||||
const NULL_VALUE = null;
|
||||
const DEFAULT_PORT = 8080;
|
||||
const MAX_RETRIES: integer = 3;
|
||||
|
||||
//================================================================================
|
||||
// 5. 混合声明测试
|
||||
//================================================================================
|
||||
|
||||
// 同一作用域内的多种声明
|
||||
var localVar: integer;
|
||||
static sharedStatic := 0;
|
||||
global globalResource: Resource;
|
||||
const CONFIG_FILE = "config.json";
|
||||
|
||||
// 连续声明
|
||||
var v1; var v2; var v3;
|
||||
static s1; static s2;
|
||||
global g1; global g2;
|
||||
const C1 = 1; const C2 = 2;
|
||||
|
||||
//================================================================================
|
||||
// 6. 特殊字符和命名测试
|
||||
//================================================================================
|
||||
|
||||
// 下划线开头
|
||||
var _private;
|
||||
static __internal: integer;
|
||||
const _CONSTANT = 100;
|
||||
|
||||
// 数字结尾
|
||||
var var1, var2, var3;
|
||||
static counter_2024;
|
||||
global data_123: array of integer;
|
||||
const VERSION_2 = "2.0";
|
||||
|
||||
// Unicode标识符(如果支持)
|
||||
var 变量: string;
|
||||
static 静态变量 := 0;
|
||||
global 全局设置: dictionary;
|
||||
const 常量值 = "中文";
|
||||
|
||||
//================================================================================
|
||||
// 7. 边界和错误情况(这些应该导致解析错误)
|
||||
//================================================================================
|
||||
|
||||
// 以下是故意的错误示例,用于测试错误处理
|
||||
|
||||
// var x = 10; // 错误:应该使用 :=
|
||||
// const C := 5; // 错误:const应该使用 =
|
||||
// const EMPTY_CONST; // 错误:const必须有值
|
||||
// var ; // 错误:缺少标识符
|
||||
// var x: integer // 错误:缺少分号
|
||||
|
||||
//================================================================================
|
||||
// 8. 格式化和空白测试
|
||||
//================================================================================
|
||||
|
||||
// 紧凑格式
|
||||
var a,b,c:integer:=0;
|
||||
static x,y:real;
|
||||
global m:string:="test";
|
||||
const K=999;
|
||||
|
||||
// 宽松格式
|
||||
var spaced , names : type := value ;
|
||||
static wide : integer ;
|
||||
global lots , of , spaces ;
|
||||
const SPACEY = "value" ;
|
||||
|
||||
// 多行格式
|
||||
var
|
||||
multiline,
|
||||
declaration,
|
||||
test: integer
|
||||
:= 0;
|
||||
|
||||
//================================================================================
|
||||
// 测试结束
|
||||
//================================================================================
|
||||
@@ -0,0 +1,607 @@
|
||||
uid := OnlineUserId();
|
||||
if not uid then
|
||||
begin
|
||||
rqUrl := createObject("TWebRequest").url;
|
||||
return CreateObject('TWebResponse').SendRedirect('/website/security/login.tsl?url='$base64encode(rqUrl)$'&e=base64');
|
||||
end;
|
||||
|
||||
isAdmin := class(IDS_ResponseRightDB).isAdmin(uid);
|
||||
// 公式操作权限
|
||||
opRight := 0;
|
||||
uinfo := class(IDS_ResponseRightDB).getUserInfoByRoleName("勾稽公式操作权限");
|
||||
if isAdmin or (istable(uinfo) and uid in (sselect ["MEMBERID"] from uinfo end)) then
|
||||
begin
|
||||
opRight := 1;
|
||||
end;
|
||||
|
||||
classify := Q("classify") ?: ''; //业务类型
|
||||
tid := Q("tid") ?:''; // 模板id
|
||||
key := Q("key") ?:''; // 公式id
|
||||
onlyFormula := Q('onlyFormula')?:''; //仅显示当前公式相关
|
||||
zhiBiaoJson := ''; // 指标json串
|
||||
zhiBiaoArr := array(); // 指标数据
|
||||
GJGongShi := ''; // 勾稽公式
|
||||
onlyFormulaCheck := ''; // 仅显示当前公式相关选择
|
||||
GJWuChaZhi := ""; // 容差范围:默认万分之一
|
||||
GJBeiZhu := "";
|
||||
checkedClassifyArr := array();
|
||||
|
||||
elements := Q("elements") ?: '';
|
||||
|
||||
xbrlFormulaSign := class(xbrl_formula).getAllFormulaSign();
|
||||
xbrlFormulaOperatorSign := class(xbrl_formula).operatorSign();
|
||||
xbrlFormulaFunctionSign := class(xbrl_formula).functionSign();
|
||||
xbrlFormulaAttributeSign := class(xbrl_formula).attributeSign();
|
||||
xbrlFormulaCondition := class(xbrl_formula).formulaCondition();
|
||||
ele := createobject("ids_element");
|
||||
// 获取报告参数属性标签集合
|
||||
DictionaryByReport := ele.DictionaryByReport();
|
||||
xbrlFormulaReportAttrSign := select distinct ["标签中文名称"] as "key",["标签中文名称"] as "title",["标签ID"] as "e_id" from DictionaryByReport where ["标签英文名称"]<>"GongGaoXinXi_#_ZTGG" end;
|
||||
|
||||
formulaAttrs := array(
|
||||
"is_sanxing": -1,
|
||||
"is_fenji": -1,
|
||||
"is_shangshi": -1,
|
||||
"is_etf": -1,
|
||||
"is_etf_lianjie": -1,
|
||||
"is_zhishu": -1,
|
||||
"is_jiji": -1,
|
||||
"is_fof": -1,
|
||||
"is_mom": -1,
|
||||
"is_xinjijin": -1,
|
||||
"is_faqishi": -1,
|
||||
"fundtype": array2str(xbrlFormulaCondition["基金类别"]["default"], ";"),
|
||||
"guzhifangshi": array2str(xbrlFormulaCondition["估值方式"]["default"], ";"),
|
||||
"yunzuofangshi": array2str(xbrlFormulaCondition["运作方式"]["default"], ";"),
|
||||
"adaptType":"limit",
|
||||
"fundid": "",
|
||||
);
|
||||
errorMsg := '';
|
||||
|
||||
//修改公式
|
||||
if key then
|
||||
begin
|
||||
obj := createObject("ids_xbrl_expr");
|
||||
obj.exprAttr(key);
|
||||
GJWuChaZhi := obj.GJWuChaZhi ?: "";
|
||||
(*
|
||||
if istable(obj.GJZhiBiao) then
|
||||
begin
|
||||
GJGongShi := obj.GJZhiBiao;
|
||||
if istable(obj.GJXiangMu) then
|
||||
begin
|
||||
for i,v in obj.GJXiangMu do
|
||||
update GJGongShi set thisrow = v[1] where thisrow = v[0] end;
|
||||
end;
|
||||
GJGongShi := sselect "[[" $ thisrow $ "]]" as thisrow from GJGongShi end;
|
||||
GJGongShi := array2str(GJGongShi, "");
|
||||
end;
|
||||
*)
|
||||
gongShi := obj.GJGongShi;
|
||||
if gongShi then
|
||||
begin
|
||||
GJGongShi := _getSplitFormula(gongShi);
|
||||
GJBeiZhu := obj.GJBeiZhu ?: "";
|
||||
formulaAttrs := array(
|
||||
"is_sanxing": obj.isSanXing,
|
||||
"is_fenji": obj.isFenJi,
|
||||
"is_shangshi": obj.isShangShi,
|
||||
"is_etf": obj.isETF,
|
||||
"is_etf_lianjie": obj.isETFLianJie,
|
||||
"is_zhishu": obj.isZhiShu,
|
||||
"is_jiji": obj.isJianJuJiJi,
|
||||
"is_fof": obj.isFOF,
|
||||
"is_mom": obj.isMOM,
|
||||
"is_xinjijin": obj.isXinJiJin,
|
||||
"is_faqishi": obj.isFaQiShi,
|
||||
"fundtype": obj.GJFanWei,
|
||||
"guzhifangshi": obj.GuZhiFangShi,
|
||||
"yunzuofangshi": obj.YunZuoFangShi,
|
||||
"adaptType":obj.adaptType,
|
||||
"fundid": obj.fundid,
|
||||
);
|
||||
zhiBiaoArr := obj.GJZhiBiao;
|
||||
if istable(zhiBiaoArr) then
|
||||
zhiBiaoJson := class(TSTool).Arr2Json(zhiBiaoArr);
|
||||
// json 串内有单引号需转义
|
||||
if ansipos("'", zhiBiaoJson) then
|
||||
zhiBiaoJson := ansireplacetext(zhiBiaoJson,"'","\\'");
|
||||
if ansipos("'", GJGongShi) then
|
||||
GJGongShi := ansireplacetext(GJGongShi,"'","\\'");
|
||||
if obj.classify then
|
||||
classifyArr := str2array(obj.classify, ";");
|
||||
|
||||
if not classify and classifyArr then
|
||||
begin
|
||||
classify := classifyArr[0];
|
||||
checkedClassifyArr &= classifyArr;
|
||||
end else
|
||||
begin
|
||||
if classify then
|
||||
checkedClassifyArr &= str2array(classify, ";");
|
||||
if classifyArr then
|
||||
checkedClassifyArr &= classifyArr;
|
||||
end;
|
||||
onlyFormulaCheck := '<div class="filter-tool">'
|
||||
$ '<label class="ivu-checkbox-wrapper ivu-checkbox-small ivu-checkbox-border">'
|
||||
$ '<span class="ivu-checkbox '$(onlyFormula?'ivu-checkbox-checked':'')$'">'
|
||||
$ '<span class="ivu-checkbox-inner"></span>'
|
||||
$ '<input type="checkbox" class="js-onlyFormula ivu-checkbox-input" '$(onlyFormula?'checked':'')$'>'
|
||||
$ '</span> 仅显示当前公式相关</label>'
|
||||
$ '</div>';
|
||||
end else
|
||||
begin
|
||||
errorMsg := '<div class="alert alert-danger">无效公式,请确认该公式是否删除!</div>';
|
||||
end;
|
||||
end else
|
||||
begin // 新增公式
|
||||
if classify then
|
||||
begin
|
||||
if classify = "SEMIYEAR_REP" or classify = "YEAR_REP" then
|
||||
checkedClassifyArr := array("SEMIYEAR_REP", "YEAR_REP");
|
||||
else
|
||||
checkedClassifyArr &= str2array(classify, ";");
|
||||
end;
|
||||
end;
|
||||
checkedClassifyJson := '';
|
||||
if istable(checkedClassifyArr) then
|
||||
checkedClassifyJson := class(TStool).Arr2Json(distinctstr(checkedClassifyArr)); // 默认选中的业务
|
||||
|
||||
businessOfUser := class(IDS_BusinessDB).getKeyByUID(uid);
|
||||
classifyList := class(ts_switch).getSwitchApplyClassify("report_audit_view");
|
||||
classifyData := select ["BUSINESS_KEY"], ["BUSINESS_NAME"] from businessOfUser where ["BUSINESS_KEY"] in classifyList order by ["BUSINESS_NAME"] end;
|
||||
classifyList := array(("BUSINESS_KEY": "", "BUSINESS_NAME": "-")) union classifyData;
|
||||
|
||||
if not tid then
|
||||
begin
|
||||
templateList := select ["TID"], ["TNAME"] from class(IDS_TemplateDB).getTemplateByClassify(classify) end;
|
||||
tid := _getTemplateID(templateList);
|
||||
end else
|
||||
begin
|
||||
templateList := select ["TID"], ["TNAME"] from class(IDS_TemplateDB).getTemplateByClassify(classify) end;
|
||||
end;
|
||||
|
||||
templateList := array(("TID": "", "TNAME": "-")) union templateList;
|
||||
|
||||
temptList := '';
|
||||
dataContent := '';
|
||||
emListHtml := '';
|
||||
if tid then
|
||||
begin
|
||||
// 元素标签相关信息
|
||||
r := class(xbrl_formula).getElementTagInfo(tid); // 根据模板获取指标标签信息
|
||||
// 根据业务获取业务相关标签
|
||||
baseData := class(xbrl_formula).getBasicIndexByClassify(classify);
|
||||
// 模板相关元素
|
||||
emList := class(IDS_RformalDB).getTempleteElementList(tid);
|
||||
// 标签数据字典
|
||||
Dictionary := ele.Dictionary();
|
||||
Dictionary := select ["标签ID"] as "E_ID",["标签中文名称"] as "E_CN_NAME" from Dictionary end;
|
||||
|
||||
emArr := array();
|
||||
cnArr := array();
|
||||
rt := select distinct ["E_ID"], ["E_CN_NAME"] from r end;
|
||||
if istable(baseData) then
|
||||
rt := rt union2 baseData union2 Dictionary;
|
||||
|
||||
for i := 0 to length(rt) - 1 do
|
||||
begin
|
||||
emArr[rt[i]["E_ID"]] := rt[i]["E_CN_NAME"];
|
||||
cnArr[rt[i]["E_CN_NAME"]] := rt[i]["E_ID"];
|
||||
end;
|
||||
// 元素标签
|
||||
(*elementArr := class(IDS_ElementDB).getElementNameAndXbTag();
|
||||
elementTagArr := array();
|
||||
vv := 0;
|
||||
for i := 0 to length(elementArr) - 1 do
|
||||
begin
|
||||
if not elementArr[i]["XBRL_TAG"] then continue;
|
||||
elementTagArr[elementArr[i]["NAME"]] := elementArr[i]["NAME"];
|
||||
end;
|
||||
*)
|
||||
|
||||
// xbElementJson := class(TStool).Arr2Json(elementTagArr); // 含xbtag标签的元素,用来匹配元素()这个函数
|
||||
xbElementJson := "";
|
||||
elementJson := class(TStool).Arr2Json(emArr); // 元素id标签对照 {"1702":"本报告期基金份额总额", ...}
|
||||
cn_nameJson := class(TStool).Arr2Json(cnArr); // 中文标签对照 {"本报告期基金份额总额":"1702", ...}
|
||||
// \转义
|
||||
if ansipos("\\", elementJson) then
|
||||
elementJson := AnsiReplaceText(elementJson, "\\", "\\\\");
|
||||
//文本类的e_id
|
||||
eTxt := select ["E_ID"],["EID"],["E_CN_NAME"],["ISEM"] from r where ["ISEM"] = 1 end;
|
||||
rela_eid := array();
|
||||
if istable(zhiBiaoArr) and istable(r) then
|
||||
begin
|
||||
// 获取仅在公式指标中的相关元素
|
||||
rela_eid := sselect distinct ["EID"] from r where ["E_ID"] in zhiBiaoArr end;
|
||||
end;
|
||||
|
||||
if istable(emList) then
|
||||
begin
|
||||
filterList := array(("title": "元素筛选", "key": "ELEMENT-NAME", "option": emList, "mulitList": "mulitEm"));
|
||||
emListHtml := '<div class="filter-tool">';
|
||||
emListHtml += checkFilter(filterList, 'formulae-filter', '');
|
||||
emListHtml += '</div>';
|
||||
end;
|
||||
|
||||
// 模板元素数据
|
||||
data := class(xbrl_formula).getTemplateData(tid);
|
||||
if istable(data) then
|
||||
begin
|
||||
elementArr := array();
|
||||
if elements then
|
||||
elementArr := str2array(elements, ";") ;
|
||||
|
||||
if istable(rela_eid) and onlyFormula then
|
||||
begin
|
||||
if istable(elementArr) then
|
||||
rela_eid &= elementArr;
|
||||
data := select * from data where ["EID"] in rela_eid or ["TYPE"] = "title" end;
|
||||
data := class(ReportData).deleteEmptyChapter(data); // 去除空章节
|
||||
end
|
||||
else if istable(elementArr) then
|
||||
begin
|
||||
data := select * from data where ["EID"] in elementArr or ["TYPE"] = "title" end;
|
||||
data := class(ReportData).deleteEmptyChapter(data); // 去除空章节
|
||||
end;
|
||||
temptList := class(xbrl_formula).getTemplateHtml(data);
|
||||
end;
|
||||
|
||||
end else
|
||||
begin
|
||||
data := array();
|
||||
temptList := '';
|
||||
end;
|
||||
|
||||
<?tslx>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>勾稽公式构建</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=gb2312" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<link rel="stylesheet" type="text/css" href="/resource/iview/iview.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/jquery-ui/jquery.ui.all.css">
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/bootstrap/bootstrap.min.css">
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/bootstrap/button.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/font-awesome.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/style.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/report.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/live_report.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/xbrl_data_audit_view.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/fundids/css/formula.css?v=<?=ids_version()?>" />
|
||||
<link rel="stylesheet" type="text/css" href="/resource/codemirror/lib/codemirror.css" />
|
||||
<script type="text/javascript" src="/resource/js/jquery-1.8.3.min.js" ></script>
|
||||
<script type="text/javascript" src="/resource/js/jquery-migrate-1.8.3.min.js" ></script>
|
||||
<script type="text/javascript" src="/resource/js/jquery-ui-1.10.2.custom.min.js"></script>
|
||||
<script type="text/javascript" src="/resource/vue/vue.min.js" charset="UTF-8"></script>
|
||||
<script type="text/javascript" src="/resource/iview/iview.min.js" charset="UTF-8"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/tsalert.js"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/edittable.js"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/global.js?v=<?=ids_version()?>"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/autoTextarea.js?v=<?=ids_version()?>"></script>
|
||||
<script type="text/javascript" src="/resource/js/dropdown-button.js"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/dm.ext.js?v=<?=ids_version()?>"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/live_report.js?v=<?=ids_version()?>"></script>
|
||||
<script type='text/javascript' src='/resource/fundids/js/xbrl_formula_page.js?v=<?=ids_version()?>'></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/xbrl_formula_view.js?v=<?=ids_version()?>"></script>
|
||||
<script type="text/javascript" src="/resource/fundids/js/check_xbrldata.js?v=<?=ids_version()?>"></script>
|
||||
<script type="text/javascript" src="/resource/codemirror/lib/codemirror.umd.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="xbrl-formula-view-wrapper">
|
||||
<div class="top-banner">
|
||||
<div class="title-wrapper"></div>
|
||||
<div class="tools-wrapper">
|
||||
<div class="left-tools">
|
||||
<div class="filter-tool">
|
||||
<span>业务类型:</span>
|
||||
<?=class(html).makeSelect(classifyList, ' class="formula-classify-select" ', classify, 'BUSINESS_NAME', 'BUSINESS_KEY')?>
|
||||
</div>
|
||||
<div class="filter-tool">
|
||||
<span>模板:</span>
|
||||
<?=class(html).makeSelect(templateList, ' class="formula-model-select" ', tid, 'TNAME', 'TID')?>
|
||||
</div>
|
||||
<?=emListHtml?>
|
||||
<?=onlyFormulaCheck?>
|
||||
<div id="page-params" class="filter-tool">
|
||||
<input type="hidden" name="elements" value="<?=elements?>">
|
||||
<input type="hidden" name="classify" value="<?=classify?>">
|
||||
<input type="hidden" name="tid" value="<?=tid?>">
|
||||
<input type="hidden" name="key" value="<?=key?>">
|
||||
<input type="hidden" name="onlyFormula" value="<?=onlyFormula?>">
|
||||
</div>
|
||||
<div class="filter-tool">
|
||||
<button class="btn btn-primary" @click="clickQueryBtn"> 查 询 </button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-tools">
|
||||
<div class="filter-tool">
|
||||
<?=key and opRight?'<button class="btn btn-primary btn-add-formulae" data-classify="'$classify$'"> + 新增 </button>':''?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aui-page-panel-inner">
|
||||
<!--目录-->
|
||||
<div class="aui-page-panel-nav">
|
||||
<div class="report_navigator">
|
||||
<div class="filter-panel">导航栏</div>
|
||||
<?=temptList?>
|
||||
<div class="bottomth"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="aui-page-panel-content row-fluid">
|
||||
<!--数据-->
|
||||
<div class="model-data-area js-rpt-content">
|
||||
<div class="report_page data_page">
|
||||
<?tsl
|
||||
if errorMsg then
|
||||
echo errorMsg;
|
||||
sysparams["xbrl_formula_view"] := true;
|
||||
for i := 0 to length(data) - 1 do
|
||||
begin
|
||||
textClass := '';
|
||||
zhibiaoSpan := '';
|
||||
echo '<div class="element-data-container">';
|
||||
if data[i]['EID'] then
|
||||
begin
|
||||
editBtn := '';
|
||||
zhibiaoid := '';
|
||||
if istable(eTxt) then
|
||||
begin
|
||||
try
|
||||
zhibiaoid := sselect ["E_ID"] from eTxt where ["EID"] = data[i]["EID"] and ["ISEM"] = 1 end[0] ?:'';
|
||||
if zhibiaoid then
|
||||
zhibiaoSpan := '<span class="zhibiaoid" data-zhibiaoid="'$zhibiaoid$'"> ['$zhibiaoid$']</span>';
|
||||
except
|
||||
zhibiaoSpan := '';
|
||||
end;
|
||||
end;
|
||||
(*
|
||||
if data[i]["TYPE"] = 'txt' then
|
||||
begin
|
||||
textClass := 'hasTextSample';
|
||||
if zhibiaoid then
|
||||
editBtn := '<div class="text-right element-data-actions">'
|
||||
$ '<button class="btn btn-mini edit-txt-index" data-zhibiaoid="'$zhibiaoid$'" title="设置文本变量指标">指标</button>'
|
||||
$ '<button class="btn btn-mini edit-template-txt" title="修改文本样例">样例</button>'
|
||||
$ '<button class="btn btn-mini btn-formula-list" title="相关公式">公式</button>'
|
||||
$ '</div>';
|
||||
end else
|
||||
begin
|
||||
editBtn := '<div class="text-right element-data-actions">'
|
||||
$ '<button class="btn btn-mini btn-formula-list" title="相关公式">公式</button>'
|
||||
$ '</div>';
|
||||
end;
|
||||
*)
|
||||
editBtn := '<div class="text-right element-data-actions">'
|
||||
$ '<button class="btn btn-mini btn-formula-list" data-eid="'$data[i]['EID']$'" title="相关公式">公式</button>'
|
||||
$ '</div>';
|
||||
echo '<div class="element-bar"><span class="element-name" data-eid="'$data[i]["EID"]$'"><i class="'$getTypetag(data[i]["TYPE"])$'"></i> '$data[i]["NAME"]$zhibiaoSpan$'</span>'$editBtn$'</div>';
|
||||
end;
|
||||
echo '<div class="row">
|
||||
<div class="element-data-content '$textClass$'">';
|
||||
class(xbrldataauditreport).rpt_show_data(data[i], true);
|
||||
echo '</div></div>';
|
||||
|
||||
echo '</div>';
|
||||
end;
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<!--公式区-->
|
||||
<div class="formula-edit-area" v-cloak>
|
||||
<tabs :animated="true" size="small">
|
||||
<tab-pane label="公式编辑">
|
||||
<div class="formula-tools">
|
||||
<div class="formula-tools-list">
|
||||
<div v-for="(item, index) of toolListData" :key="index" class="formula-tools-list-item">
|
||||
<i-button type="small" class="formula-tools-item" @click="insertSign(item)" :title="item.info">{{ item.label }}</i-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formula-tools-list" style="display: none;">
|
||||
<div v-for="(item, index) of reportAttrListData" :key="index" class="formula-tools-list-item">
|
||||
<i-button type="small" class="formula-tools-item" @click="insertSign(item)" :title="item.info">{{ item.label }}</i-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formula-editor">
|
||||
<editor-component ref="editor" :editor-data.sync="formula" :completion-options="formulaRule" :vaild-params="vaildParams" :invalid-param-msg="invalidParamMsg" symbol-sets="()" />
|
||||
</div>
|
||||
</tab-pane>
|
||||
<tab-pane label="公式属性">
|
||||
<div class="formula-tools">
|
||||
<div class="formula-attrs">
|
||||
<div class="formula-attrs-list">
|
||||
<p>适用业务:</p>
|
||||
<checkbox-group v-model="formulaClassify" class="formula-classify" size="small">
|
||||
<?tsl
|
||||
for i,v in classifyData do
|
||||
echo '<div class="formula-classify-item"><checkbox label="'$v["BUSINESS_KEY"]$'">'$v["BUSINESS_NAME"]$'</checkbox></div>';
|
||||
?>
|
||||
</checkbox-group>
|
||||
</div>
|
||||
<?tsl
|
||||
for i,v in xbrlFormulaCondition do
|
||||
begin
|
||||
if not pos("IS_", v["name"]) then
|
||||
begin
|
||||
echo '<div class="formula-attrs-list"><p>'$i$':</p> <checkbox-group v-model="'$lowerCase(v["name"])$'" class="formula-prod-attr" size="small">';
|
||||
for si,sv in v["value"] do
|
||||
echo '<div class="formula-prod-attr-item"><checkbox label="'$sv$'">'$sv$'</checkbox></div>';
|
||||
echo '</checkbox-group></div>';
|
||||
end;
|
||||
end;
|
||||
?>
|
||||
<div class="formula-attrs-list">
|
||||
<p>其它属性:</p>
|
||||
<div class="formula-prod-attr ">
|
||||
<?tsl
|
||||
otherAttrs := select * from xbrlFormulaCondition where pos("IS_", thisrow["name"]) end;
|
||||
for i,v in otherAttrs do
|
||||
begin
|
||||
//echo '<div class="formula-prod-attr-item"><checkbox v-model="'$lowerCase(v["name"])$'" size="small">'$i$'</checkbox></div>';
|
||||
echo
|
||||
'<div class="formula-prod-attr-item">
|
||||
<label>'$i$'</label>
|
||||
<i-select placeholder="" v-model="'$lowerCase(v["name"])$'" style="width:70px; margin-left:4px;">
|
||||
<i-option value=-1 key=""> </i-option>
|
||||
<i-option value=1 key="1">是</i-option>
|
||||
<i-option value=0 key="0">否</i-option>
|
||||
</i-select>
|
||||
</div>';
|
||||
end;
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formula-attrs-list">
|
||||
<p>基 金:</p>
|
||||
<div class="formula-prod-attr">
|
||||
<i-select placeholder="" v-model="adaptType" style="width:100px">
|
||||
<i-option value="limit" key="1">仅适用</i-option>
|
||||
<i-option value="defy" key="0">不适用</i-option>
|
||||
<i-option value="extend" key="2">额外适用</i-option>
|
||||
</i-select>
|
||||
<input value="<?=formulaAttrs["fundid"]?>" type="text" class="form-control mul_produnct ui-autocomplete-input" autocomplete="off" placeholder="请输入主基金代码"> <button type="button" title="基金选择" class="btn CheckfundList">...</button></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formula-attrs-list">
|
||||
<p>容差范围:</p>
|
||||
<input-number class="formula-wucha" :max="1" :min="0" :step="0.0001" v-model="formulaWucha" size="small" style="height:30px;"></input-number>
|
||||
</div>
|
||||
<div class="formula-attrs-list">
|
||||
<p>备 注:</p>
|
||||
<i-input class="formula-beizhu" v-model="beizhu" type="textarea" :autosize="{minRows: 2,maxRows: 3}" size="small" ></i-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</tab-pane>
|
||||
<tab-pane label="数据字典"></tab-pane>
|
||||
<?tsl
|
||||
if opRight then
|
||||
echo '<template #extra>
|
||||
<i-button size="small" type="primary" :disabled="!formula" @click="saveFormula(\'save\')"> 保存 </i-button>
|
||||
<i-button size="small" :disabled="!formula" @click="saveFormula(\'saveAS\')" title="另存为新的公式"> 另存 </i-button>
|
||||
<i-button size="small" :disabled="!formula" @click="saveFormula(\'test\')" title="测试勾稽校验"> 校验 </i-button>
|
||||
<i-button size="small" type="error" :disabled="!formula" @click="clearFormula"> 清空 </i-button>
|
||||
</template>';
|
||||
?>
|
||||
</tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var XBRL_FORMULA_SIGN = <?=class(TSTool).Arr2Json(xbrlFormulaSign)?>;
|
||||
var XBRL_FORMULA_OPERATOR_SIGN = <?=class(TSTool).Arr2Json(xbrlFormulaOperatorSign)?>;
|
||||
var XBRL_FORMULA_FUNCTION_SIGN = <?=class(TSTool).Arr2Json(xbrlFormulaFunctionSign)?>;
|
||||
var XBRL_FORMULA_ATTRIBUTE_SIGN = <?=class(TSTool).Arr2Json(xbrlFormulaAttributeSign)?>;
|
||||
var XBRL_FORMULA_CONDITION = <?=class(TSTool).Arr2Json(xbrlFormulaCondition)?>;
|
||||
var XBRL_FORMULA_REPORTATTR_SIGN = <?=class(TSTool).Arr2Json(xbrlFormulaReportAttrSign)?>;
|
||||
var elementJson = '<?=elementJson?>';
|
||||
if(elementJson && !Array.isArray(elementJson)){
|
||||
elementJson = JSON.parse(elementJson);
|
||||
}
|
||||
var xbElementJson = '<?=xbElementJson?>';
|
||||
if(xbElementJson && !Array.isArray(xbElementJson)){
|
||||
xbElementJson = JSON.parse(xbElementJson);
|
||||
}
|
||||
var cn_nameJson = '<?=cn_nameJson?>';
|
||||
if(cn_nameJson && !Array.isArray(cn_nameJson)){
|
||||
cn_nameJson = JSON.parse(cn_nameJson);
|
||||
}
|
||||
var zhiBiaoJson = '<?=zhiBiaoJson?>';
|
||||
if(zhiBiaoJson && !Array.isArray(zhiBiaoJson)){
|
||||
zhiBiaoJson = JSON.parse(zhiBiaoJson);
|
||||
}
|
||||
var GOUJIGONGSHI = '<?=GJGongShi?:""?>';
|
||||
var FORMULAID = '<?=key?:""?>';
|
||||
var formulaWucha = '<?=GJWuChaZhi?:""?>';
|
||||
var formulaClassify = '<?=checkedClassifyJson?:""?>';
|
||||
var formulaBeizhu = '<?=GJBeiZhu?:""?>';
|
||||
<?tsl
|
||||
for i,v in formulaAttrs do
|
||||
Begin
|
||||
// echo "var "$i$" = "$(v <> "" ? '"'$v$'"' : "false")$";";
|
||||
echo "var "$i$" = '"$v$"';";
|
||||
|
||||
end;
|
||||
|
||||
?>
|
||||
$(function(){
|
||||
// 基金代码选择器
|
||||
AddAutoComplete_mul(".mul_produnct","product","");
|
||||
// 添加文本指标标签
|
||||
addTextTag(cn_nameJson);
|
||||
// 指标标签
|
||||
addElementTag(elementJson, zhiBiaoJson);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<?tsl
|
||||
|
||||
function getTypetag(types);
|
||||
begin
|
||||
case types of
|
||||
'txt': typetag := 'icon-text-width';
|
||||
'table': typetag := 'icon-table';
|
||||
'pic':typetag := 'icon-picture';
|
||||
'complex': typetag := 'icon-list';
|
||||
'mix':typetag := 'icon-th-large';
|
||||
'radio': typetag := 'icon-ok-circle';
|
||||
else
|
||||
typetag := '';
|
||||
end;
|
||||
return typetag;
|
||||
end;
|
||||
|
||||
function _getTemplateID(t);
|
||||
begin
|
||||
if not istable(t) then
|
||||
return '';
|
||||
t1 := sselect ["TID"] from t where LeftStr(["TNAME"], 2) = "普通" order by ["TNAME"],["IS_BASIC"] desc end;
|
||||
if istable(t1) then
|
||||
return t1[0];
|
||||
t2 := sselect ["TID"] from t order by ["IS_BASIC"] desc end;
|
||||
if istable(t1) then
|
||||
return t2[0];
|
||||
return '';
|
||||
end;
|
||||
|
||||
function _getSplitFormula(f);
|
||||
begin
|
||||
f1 := f;
|
||||
t := class(IDS_AuditExpr).analysisFormulae(f1);
|
||||
|
||||
item := array();
|
||||
for i := 0 to length(t) - 1 do
|
||||
begin
|
||||
k := "[[REP_"$i$"]]";
|
||||
item[i]:= array("v": "[["$t[i]$"]]", "k": k );
|
||||
f := replaceStr(f, t[i], k );
|
||||
end;
|
||||
|
||||
for i := 0 to length(item) - 1 do
|
||||
begin
|
||||
f := replaceStr(f, item[i]["k"], item[i]["v"]);
|
||||
end;
|
||||
|
||||
attrArr := class(xbrl_formula).attributeSign();
|
||||
for i := 0 to length(attrArr) - 1 do
|
||||
begin
|
||||
attr := attrArr[i]["key"];
|
||||
if pos(attr, f) then
|
||||
f := replaceStr(f, "("$attr$")", "]][[("$attr$")");
|
||||
end;
|
||||
|
||||
f := replaceStr(f, "#", "]]#[[" );
|
||||
return f;
|
||||
end;
|
||||
@@ -0,0 +1,7 @@
|
||||
// function 公募基金简称(shortname);
|
||||
function abc(shortname);
|
||||
begin
|
||||
中文 := 123;
|
||||
pinfo := sysparams["productInfo"];
|
||||
end;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json",
|
||||
"grammars": [
|
||||
{
|
||||
"name": "tsf",
|
||||
"camelcase": "Tsf",
|
||||
"title": "TSF",
|
||||
"scope": "source.tsf",
|
||||
"file-types": [
|
||||
"tsf",
|
||||
"tsl"
|
||||
],
|
||||
"injection-regex": "^tsf$",
|
||||
"class-name": "TreeSitterTsf"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"description": "tsf",
|
||||
"authors": [
|
||||
{
|
||||
"name": "csh"
|
||||
}
|
||||
],
|
||||
"links": {
|
||||
"repository": "https://github.com/tree-sitter/tree-sitter-tsf"
|
||||
}
|
||||
},
|
||||
"bindings": {
|
||||
"c": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user