@voodocs/cli 2.5.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -252
- package/README.md +215 -399
- package/lib/cli/__init__.py +1 -3
- package/lib/cli/init.py +11 -13
- package/lib/darkarts/annotations/darkarts_parser.py +159 -142
- package/lib/darkarts/annotations/darkarts_parser_v2.py.bak +238 -0
- package/lib/darkarts/companion_files.py +62 -9
- package/lib/darkarts/context/ai_instructions.py +385 -571
- package/lib/darkarts/context/ai_instructions_v2.py.bak +741 -0
- package/lib/darkarts/darkarts_abbreviations.py +324 -0
- package/lib/darkarts/darkarts_parser_v3.py +486 -0
- package/lib/darkarts/darkarts_patterns.py +249 -0
- package/lib/darkarts/darkarts_symbols.py +276 -0
- package/lib/darkarts/plugins/voodocs/documentation_generator.py +31 -2
- package/lib/darkarts/validation/semantic.py +135 -18
- package/package.json +5 -4
- package/lib/cli/convert.py +0 -144
- package/lib/darkarts/voodocs_lite_dict.py +0 -216
- package/lib/darkarts/voodocs_lite_dict_v2.py +0 -198
- package/lib/darkarts/voodocs_lite_parser.py +0 -404
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
VooDocs Lite - Ultra-Aggressive Abbreviation Dictionary v2
|
|
3
|
-
|
|
4
|
-
Provides maximum compression by:
|
|
5
|
-
1. Removing articles (a, an, the)
|
|
6
|
-
2. Removing unnecessary words
|
|
7
|
-
3. Using aggressive abbreviations
|
|
8
|
-
4. Using symbols instead of words
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
# Core abbreviations
|
|
12
|
-
CORE_ABBR = {
|
|
13
|
-
# Entities
|
|
14
|
-
'user': 'u',
|
|
15
|
-
'users': 'us',
|
|
16
|
-
'database': 'db',
|
|
17
|
-
'token': 'tok',
|
|
18
|
-
'password': 'pw',
|
|
19
|
-
'authentication': 'auth',
|
|
20
|
-
'authorization': 'authz',
|
|
21
|
-
'service': 'svc',
|
|
22
|
-
'function': 'fn',
|
|
23
|
-
'identifier': 'id',
|
|
24
|
-
'configuration': 'cfg',
|
|
25
|
-
'parameter': 'p',
|
|
26
|
-
'argument': 'a',
|
|
27
|
-
'variable': 'v',
|
|
28
|
-
'constant': 'c',
|
|
29
|
-
'timestamp': 'ts',
|
|
30
|
-
'expiration': 'exp',
|
|
31
|
-
'response': 'r',
|
|
32
|
-
'request': 'q',
|
|
33
|
-
'error': 'e',
|
|
34
|
-
'exception': 'x',
|
|
35
|
-
|
|
36
|
-
# Actions (ultra-short)
|
|
37
|
-
'initialize': 'init',
|
|
38
|
-
'validate': 'val',
|
|
39
|
-
'verify': 'ver',
|
|
40
|
-
'generate': 'gen',
|
|
41
|
-
'create': 'cr',
|
|
42
|
-
'update': 'upd',
|
|
43
|
-
'delete': 'del',
|
|
44
|
-
'modify': 'mod',
|
|
45
|
-
'retrieve': 'get',
|
|
46
|
-
'query': 'qry',
|
|
47
|
-
'check': 'chk',
|
|
48
|
-
'returns': 'ret',
|
|
49
|
-
'contains': 'has',
|
|
50
|
-
|
|
51
|
-
# Blockchain
|
|
52
|
-
'address': 'addr',
|
|
53
|
-
'contract': 'ctr',
|
|
54
|
-
'transaction': 'tx',
|
|
55
|
-
'block': 'blk',
|
|
56
|
-
'balance': 'bal',
|
|
57
|
-
'amount': 'amt',
|
|
58
|
-
'subdomain': 'sub',
|
|
59
|
-
'registry': 'reg',
|
|
60
|
-
'owner': 'own',
|
|
61
|
-
|
|
62
|
-
# Common words
|
|
63
|
-
'with': 'w/',
|
|
64
|
-
'without': 'wo/',
|
|
65
|
-
'management': 'mgmt',
|
|
66
|
-
'system': 'sys',
|
|
67
|
-
'operations': 'ops',
|
|
68
|
-
'result': 'res',
|
|
69
|
-
'value': 'val',
|
|
70
|
-
'length': 'len',
|
|
71
|
-
'count': 'cnt',
|
|
72
|
-
'maximum': 'max',
|
|
73
|
-
'minimum': 'min',
|
|
74
|
-
'average': 'avg',
|
|
75
|
-
'information': 'info',
|
|
76
|
-
'specification': 'spec',
|
|
77
|
-
'implementation': 'impl',
|
|
78
|
-
'reference': 'ref',
|
|
79
|
-
'definition': 'def',
|
|
80
|
-
'description': 'desc',
|
|
81
|
-
|
|
82
|
-
# Types
|
|
83
|
-
'string': 'str',
|
|
84
|
-
'number': 'num',
|
|
85
|
-
'integer': 'int',
|
|
86
|
-
'boolean': 'bool',
|
|
87
|
-
'array': 'arr',
|
|
88
|
-
'object': 'obj',
|
|
89
|
-
|
|
90
|
-
# Boolean/Values
|
|
91
|
-
'true': 'T',
|
|
92
|
-
'false': 'F',
|
|
93
|
-
'null': 'N',
|
|
94
|
-
'undefined': 'U',
|
|
95
|
-
'empty': 'E',
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
# Words to remove entirely
|
|
99
|
-
REMOVE_WORDS = {'a', 'an', 'the', 'is', 'are', 'be', 'been', 'being', 'was', 'were', 'will', 'would', 'should', 'could', 'may', 'might', 'can', 'must'}
|
|
100
|
-
|
|
101
|
-
# Symbol replacements
|
|
102
|
-
SYMBOL_REPLACEMENTS = {
|
|
103
|
-
' and ': '&',
|
|
104
|
-
' or ': '|',
|
|
105
|
-
' not ': '!',
|
|
106
|
-
'greater than or equal': '>=',
|
|
107
|
-
'less than or equal': '<=',
|
|
108
|
-
'greater than': '>',
|
|
109
|
-
'less than': '<',
|
|
110
|
-
'equal to': '=',
|
|
111
|
-
'not equal': '!=',
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def ultra_compress(text: str) -> str:
|
|
116
|
-
"""
|
|
117
|
-
Ultra-aggressive compression.
|
|
118
|
-
|
|
119
|
-
Steps:
|
|
120
|
-
1. Replace symbols
|
|
121
|
-
2. Remove articles and unnecessary words
|
|
122
|
-
3. Apply abbreviations
|
|
123
|
-
4. Remove extra whitespace
|
|
124
|
-
"""
|
|
125
|
-
# Step 1: Symbol replacements (longest first)
|
|
126
|
-
for phrase, symbol in sorted(SYMBOL_REPLACEMENTS.items(), key=lambda x: -len(x[0])):
|
|
127
|
-
text = text.replace(phrase, symbol)
|
|
128
|
-
|
|
129
|
-
# Step 2: Split into words
|
|
130
|
-
words = text.split()
|
|
131
|
-
|
|
132
|
-
# Step 3: Process each word
|
|
133
|
-
compressed_words = []
|
|
134
|
-
for word in words:
|
|
135
|
-
# Check for punctuation
|
|
136
|
-
punct = ''
|
|
137
|
-
if word and word[-1] in '.,;:!?':
|
|
138
|
-
punct = word[-1]
|
|
139
|
-
word = word[:-1]
|
|
140
|
-
|
|
141
|
-
# Convert to lowercase for matching
|
|
142
|
-
word_lower = word.lower()
|
|
143
|
-
|
|
144
|
-
# Skip if in remove list
|
|
145
|
-
if word_lower in REMOVE_WORDS:
|
|
146
|
-
continue
|
|
147
|
-
|
|
148
|
-
# Apply abbreviation if exists
|
|
149
|
-
if word_lower in CORE_ABBR:
|
|
150
|
-
compressed_words.append(CORE_ABBR[word_lower] + punct)
|
|
151
|
-
else:
|
|
152
|
-
compressed_words.append(word + punct)
|
|
153
|
-
|
|
154
|
-
# Step 4: Join and clean up
|
|
155
|
-
result = ' '.join(compressed_words)
|
|
156
|
-
|
|
157
|
-
# Remove spaces around symbols
|
|
158
|
-
result = result.replace(' & ', '&')
|
|
159
|
-
result = result.replace(' | ', '|')
|
|
160
|
-
result = result.replace(' >= ', '>=')
|
|
161
|
-
result = result.replace(' <= ', '<=')
|
|
162
|
-
result = result.replace(' != ', '!=')
|
|
163
|
-
|
|
164
|
-
return result
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def ultra_expand(text: str) -> str:
|
|
168
|
-
"""
|
|
169
|
-
Expand ultra-compressed text back to full form.
|
|
170
|
-
"""
|
|
171
|
-
# Reverse mapping
|
|
172
|
-
ABBR_TO_FULL = {v: k for k, v in CORE_ABBR.items()}
|
|
173
|
-
|
|
174
|
-
# Step 1: Add spaces around symbols
|
|
175
|
-
text = text.replace('&', ' and ')
|
|
176
|
-
text = text.replace('|', ' or ')
|
|
177
|
-
text = text.replace('>=', ' greater than or equal ')
|
|
178
|
-
text = text.replace('<=', ' less than or equal ')
|
|
179
|
-
text = text.replace('!=', ' not equal ')
|
|
180
|
-
|
|
181
|
-
# Step 2: Split and expand
|
|
182
|
-
words = text.split()
|
|
183
|
-
expanded_words = []
|
|
184
|
-
|
|
185
|
-
for word in words:
|
|
186
|
-
# Check for punctuation
|
|
187
|
-
punct = ''
|
|
188
|
-
if word and word[-1] in '.,;:!?':
|
|
189
|
-
punct = word[-1]
|
|
190
|
-
word = word[:-1]
|
|
191
|
-
|
|
192
|
-
# Expand if abbreviation exists
|
|
193
|
-
if word in ABBR_TO_FULL:
|
|
194
|
-
expanded_words.append(ABBR_TO_FULL[word] + punct)
|
|
195
|
-
else:
|
|
196
|
-
expanded_words.append(word + punct)
|
|
197
|
-
|
|
198
|
-
return ' '.join(expanded_words)
|
|
@@ -1,404 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
VooDocs Lite Parser
|
|
3
|
-
|
|
4
|
-
Parses VooDocs Lite format and converts between Lite and Standard formats.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import re
|
|
8
|
-
from typing import Dict, Optional
|
|
9
|
-
from .voodocs_lite_dict import (
|
|
10
|
-
expand_text,
|
|
11
|
-
compress_text,
|
|
12
|
-
get_lite_symbol,
|
|
13
|
-
get_standard_symbol,
|
|
14
|
-
LITE_TO_STANDARD,
|
|
15
|
-
STANDARD_TO_LITE,
|
|
16
|
-
)
|
|
17
|
-
from .voodocs_lite_dict_v2 import ultra_compress, ultra_expand
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class VooDocsLiteParser:
|
|
21
|
-
"""Parser for VooDocs Lite format."""
|
|
22
|
-
|
|
23
|
-
# Lite format patterns
|
|
24
|
-
LITE_PATTERNS = {
|
|
25
|
-
'purpose': r'^>\s*(.+)$',
|
|
26
|
-
'dependencies': r'^@\s*(.+)$',
|
|
27
|
-
'assumptions': r'^!\s*(.+)$',
|
|
28
|
-
'preconditions': r'^<\s*(.+)$',
|
|
29
|
-
'postconditions': r'^>\s*(.+)$', # Same as purpose, context-dependent
|
|
30
|
-
'invariants': r'^=\s*(.+)$',
|
|
31
|
-
'complexity': r'^~\s*(.+)$',
|
|
32
|
-
'security': r'^#\s*(.+)$',
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
# Standard format patterns
|
|
36
|
-
STANDARD_PATTERNS = {
|
|
37
|
-
'purpose': r'⊢\{([^}]+)\}',
|
|
38
|
-
'dependencies': r'∂\{([^}]+)\}',
|
|
39
|
-
'assumptions': r'⚠\{([^}]+)\}',
|
|
40
|
-
'preconditions': r'⊳\{([^}]+)\}',
|
|
41
|
-
'postconditions': r'⊲\{([^}]+)\}',
|
|
42
|
-
'invariants': r'⊨\{([^}]+)\}',
|
|
43
|
-
'complexity': r'⚡\{([^}]+)\}',
|
|
44
|
-
'security': r'🔒\{([^}]+)\}',
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@classmethod
|
|
48
|
-
def convert_file_standard_to_lite(cls, file_content: str) -> str:
|
|
49
|
-
"""
|
|
50
|
-
Convert entire file from Standard to Lite format.
|
|
51
|
-
|
|
52
|
-
Finds @darkarts annotations and converts them to @darkarts-lite.
|
|
53
|
-
Preserves all other content unchanged.
|
|
54
|
-
|
|
55
|
-
Args:
|
|
56
|
-
file_content: Full file content
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
File content with annotations converted to Lite format
|
|
60
|
-
"""
|
|
61
|
-
# Pattern to match @darkarts comment blocks
|
|
62
|
-
pattern = r'/\*\*@darkarts\n(.*?)\*/'
|
|
63
|
-
|
|
64
|
-
def replace_annotation(match):
|
|
65
|
-
annotation_content = match.group(1)
|
|
66
|
-
# Convert the annotation
|
|
67
|
-
lite_content = cls.standard_to_lite(annotation_content, compress_abbreviations=True)
|
|
68
|
-
# Return as @darkarts-lite
|
|
69
|
-
return f'/**@darkarts-lite\n{lite_content}\n*/'
|
|
70
|
-
|
|
71
|
-
# Replace all @darkarts annotations
|
|
72
|
-
result = re.sub(pattern, replace_annotation, file_content, flags=re.DOTALL)
|
|
73
|
-
|
|
74
|
-
return result
|
|
75
|
-
|
|
76
|
-
@classmethod
|
|
77
|
-
def convert_file_lite_to_standard(cls, file_content: str) -> str:
|
|
78
|
-
"""
|
|
79
|
-
Convert entire file from Lite to Standard format.
|
|
80
|
-
|
|
81
|
-
Finds @darkarts-lite annotations and converts them to @darkarts.
|
|
82
|
-
Preserves all other content unchanged.
|
|
83
|
-
|
|
84
|
-
Args:
|
|
85
|
-
file_content: Full file content
|
|
86
|
-
|
|
87
|
-
Returns:
|
|
88
|
-
File content with annotations converted to Standard format
|
|
89
|
-
"""
|
|
90
|
-
# Pattern to match @darkarts-lite comment blocks
|
|
91
|
-
pattern = r'/\*\*@darkarts-lite\n(.*?)\*/'
|
|
92
|
-
|
|
93
|
-
def replace_annotation(match):
|
|
94
|
-
annotation_content = match.group(1)
|
|
95
|
-
# Convert the annotation
|
|
96
|
-
standard_content = cls.lite_to_standard(annotation_content)
|
|
97
|
-
# Return as @darkarts
|
|
98
|
-
return f'/**@darkarts\n{standard_content}\n*/'
|
|
99
|
-
|
|
100
|
-
# Replace all @darkarts-lite annotations
|
|
101
|
-
result = re.sub(pattern, replace_annotation, file_content, flags=re.DOTALL)
|
|
102
|
-
|
|
103
|
-
return result
|
|
104
|
-
|
|
105
|
-
@classmethod
|
|
106
|
-
def parse_lite(cls, content: str) -> Dict[str, any]:
|
|
107
|
-
"""
|
|
108
|
-
Parse VooDocs Lite format annotation.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
content: Lite format annotation text
|
|
112
|
-
|
|
113
|
-
Returns:
|
|
114
|
-
Dictionary with parsed fields
|
|
115
|
-
"""
|
|
116
|
-
result = {
|
|
117
|
-
'purpose': None,
|
|
118
|
-
'dependencies': [],
|
|
119
|
-
'assumptions': [],
|
|
120
|
-
'preconditions': [],
|
|
121
|
-
'postconditions': [],
|
|
122
|
-
'invariants': [],
|
|
123
|
-
'complexity': None,
|
|
124
|
-
'security': [],
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
lines = content.strip().split('\n')
|
|
128
|
-
|
|
129
|
-
for line in lines:
|
|
130
|
-
line = line.strip()
|
|
131
|
-
if not line:
|
|
132
|
-
continue
|
|
133
|
-
|
|
134
|
-
# Check each pattern
|
|
135
|
-
if line.startswith('>'):
|
|
136
|
-
# Could be purpose or postcondition
|
|
137
|
-
# If we already have purpose, it's postcondition
|
|
138
|
-
match = re.match(cls.LITE_PATTERNS['purpose'], line)
|
|
139
|
-
if match:
|
|
140
|
-
value = match.group(1).strip()
|
|
141
|
-
if result['purpose'] is None:
|
|
142
|
-
result['purpose'] = value
|
|
143
|
-
else:
|
|
144
|
-
result['postconditions'].append(value)
|
|
145
|
-
|
|
146
|
-
elif line.startswith('@'):
|
|
147
|
-
match = re.match(cls.LITE_PATTERNS['dependencies'], line)
|
|
148
|
-
if match:
|
|
149
|
-
deps = match.group(1).strip()
|
|
150
|
-
# Split by comma
|
|
151
|
-
result['dependencies'] = [d.strip() for d in deps.split(',')]
|
|
152
|
-
|
|
153
|
-
elif line.startswith('!'):
|
|
154
|
-
match = re.match(cls.LITE_PATTERNS['assumptions'], line)
|
|
155
|
-
if match:
|
|
156
|
-
result['assumptions'].append(match.group(1).strip())
|
|
157
|
-
|
|
158
|
-
elif line.startswith('<'):
|
|
159
|
-
match = re.match(cls.LITE_PATTERNS['preconditions'], line)
|
|
160
|
-
if match:
|
|
161
|
-
result['preconditions'].append(match.group(1).strip())
|
|
162
|
-
|
|
163
|
-
elif line.startswith('='):
|
|
164
|
-
match = re.match(cls.LITE_PATTERNS['invariants'], line)
|
|
165
|
-
if match:
|
|
166
|
-
result['invariants'].append(match.group(1).strip())
|
|
167
|
-
|
|
168
|
-
elif line.startswith('~'):
|
|
169
|
-
match = re.match(cls.LITE_PATTERNS['complexity'], line)
|
|
170
|
-
if match:
|
|
171
|
-
result['complexity'] = match.group(1).strip()
|
|
172
|
-
|
|
173
|
-
elif line.startswith('#'):
|
|
174
|
-
match = re.match(cls.LITE_PATTERNS['security'], line)
|
|
175
|
-
if match:
|
|
176
|
-
result['security'].append(match.group(1).strip())
|
|
177
|
-
|
|
178
|
-
return result
|
|
179
|
-
|
|
180
|
-
@classmethod
|
|
181
|
-
def parse_standard(cls, content: str) -> Dict[str, any]:
|
|
182
|
-
"""
|
|
183
|
-
Parse VooDocs Standard format annotation.
|
|
184
|
-
|
|
185
|
-
Args:
|
|
186
|
-
content: Standard format annotation text
|
|
187
|
-
|
|
188
|
-
Returns:
|
|
189
|
-
Dictionary with parsed fields
|
|
190
|
-
"""
|
|
191
|
-
result = {
|
|
192
|
-
'purpose': None,
|
|
193
|
-
'dependencies': [],
|
|
194
|
-
'assumptions': [],
|
|
195
|
-
'preconditions': [],
|
|
196
|
-
'postconditions': [],
|
|
197
|
-
'invariants': [],
|
|
198
|
-
'complexity': None,
|
|
199
|
-
'security': [],
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
# Purpose
|
|
203
|
-
match = re.search(cls.STANDARD_PATTERNS['purpose'], content)
|
|
204
|
-
if match:
|
|
205
|
-
result['purpose'] = match.group(1).strip()
|
|
206
|
-
|
|
207
|
-
# Dependencies
|
|
208
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['dependencies'], content):
|
|
209
|
-
deps = match.group(1).strip()
|
|
210
|
-
result['dependencies'].extend([d.strip() for d in deps.split(',')])
|
|
211
|
-
|
|
212
|
-
# Assumptions
|
|
213
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['assumptions'], content):
|
|
214
|
-
result['assumptions'].append(match.group(1).strip())
|
|
215
|
-
|
|
216
|
-
# Preconditions
|
|
217
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['preconditions'], content):
|
|
218
|
-
result['preconditions'].append(match.group(1).strip())
|
|
219
|
-
|
|
220
|
-
# Postconditions
|
|
221
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['postconditions'], content):
|
|
222
|
-
result['postconditions'].append(match.group(1).strip())
|
|
223
|
-
|
|
224
|
-
# Invariants
|
|
225
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['invariants'], content):
|
|
226
|
-
result['invariants'].append(match.group(1).strip())
|
|
227
|
-
|
|
228
|
-
# Complexity
|
|
229
|
-
match = re.search(cls.STANDARD_PATTERNS['complexity'], content)
|
|
230
|
-
if match:
|
|
231
|
-
result['complexity'] = match.group(1).strip()
|
|
232
|
-
|
|
233
|
-
# Security
|
|
234
|
-
for match in re.finditer(cls.STANDARD_PATTERNS['security'], content):
|
|
235
|
-
result['security'].append(match.group(1).strip())
|
|
236
|
-
|
|
237
|
-
return result
|
|
238
|
-
|
|
239
|
-
@classmethod
|
|
240
|
-
def lite_to_standard(cls, lite_content: str) -> str:
|
|
241
|
-
"""
|
|
242
|
-
Convert Lite format to Standard format.
|
|
243
|
-
|
|
244
|
-
Args:
|
|
245
|
-
lite_content: Lite format annotation
|
|
246
|
-
|
|
247
|
-
Returns:
|
|
248
|
-
Standard format annotation
|
|
249
|
-
"""
|
|
250
|
-
parsed = cls.parse_lite(lite_content)
|
|
251
|
-
|
|
252
|
-
lines = []
|
|
253
|
-
|
|
254
|
-
# Purpose
|
|
255
|
-
if parsed['purpose']:
|
|
256
|
-
text = ultra_expand(parsed['purpose'])
|
|
257
|
-
lines.append(f"⊢{{{text}}}")
|
|
258
|
-
|
|
259
|
-
# Dependencies
|
|
260
|
-
if parsed['dependencies']:
|
|
261
|
-
deps = ','.join([ultra_expand(d) for d in parsed['dependencies']])
|
|
262
|
-
lines.append(f"∂{{{deps}}}")
|
|
263
|
-
|
|
264
|
-
# Assumptions
|
|
265
|
-
if parsed['assumptions']:
|
|
266
|
-
for assumption in parsed['assumptions']:
|
|
267
|
-
text = ultra_expand(assumption)
|
|
268
|
-
lines.append(f"⚠{{{text}}}")
|
|
269
|
-
|
|
270
|
-
# Preconditions
|
|
271
|
-
if parsed['preconditions']:
|
|
272
|
-
for precond in parsed['preconditions']:
|
|
273
|
-
text = ultra_expand(precond)
|
|
274
|
-
lines.append(f"⊳{{{text}}}")
|
|
275
|
-
|
|
276
|
-
# Postconditions
|
|
277
|
-
if parsed['postconditions']:
|
|
278
|
-
for postcond in parsed['postconditions']:
|
|
279
|
-
text = ultra_expand(postcond)
|
|
280
|
-
lines.append(f"⊲{{{text}}}")
|
|
281
|
-
|
|
282
|
-
# Invariants
|
|
283
|
-
if parsed['invariants']:
|
|
284
|
-
for invariant in parsed['invariants']:
|
|
285
|
-
text = ultra_expand(invariant)
|
|
286
|
-
lines.append(f"⊨{{{text}}}")
|
|
287
|
-
|
|
288
|
-
# Complexity
|
|
289
|
-
if parsed['complexity']:
|
|
290
|
-
lines.append(f"⚡{{{parsed['complexity']}}}")
|
|
291
|
-
|
|
292
|
-
# Security
|
|
293
|
-
if parsed['security']:
|
|
294
|
-
for security in parsed['security']:
|
|
295
|
-
text = ultra_expand(security)
|
|
296
|
-
lines.append(f"🔒{{{text}}}")
|
|
297
|
-
|
|
298
|
-
return '\n'.join(lines)
|
|
299
|
-
|
|
300
|
-
@classmethod
|
|
301
|
-
def standard_to_lite(cls, standard_content: str, compress_abbreviations: bool = True) -> str:
|
|
302
|
-
"""
|
|
303
|
-
Convert Standard format to Lite format.
|
|
304
|
-
|
|
305
|
-
Args:
|
|
306
|
-
standard_content: Standard format annotation
|
|
307
|
-
compress_abbreviations: Whether to compress to abbreviations
|
|
308
|
-
|
|
309
|
-
Returns:
|
|
310
|
-
Lite format annotation
|
|
311
|
-
"""
|
|
312
|
-
parsed = cls.parse_standard(standard_content)
|
|
313
|
-
|
|
314
|
-
lines = []
|
|
315
|
-
|
|
316
|
-
# Purpose
|
|
317
|
-
if parsed['purpose']:
|
|
318
|
-
text = parsed['purpose']
|
|
319
|
-
if compress_abbreviations:
|
|
320
|
-
text = ultra_compress(text)
|
|
321
|
-
lines.append(f">{text}")
|
|
322
|
-
|
|
323
|
-
# Dependencies
|
|
324
|
-
if parsed['dependencies']:
|
|
325
|
-
deps = ','.join(parsed['dependencies'])
|
|
326
|
-
if compress_abbreviations:
|
|
327
|
-
deps = ultra_compress(deps)
|
|
328
|
-
lines.append(f"@{deps}")
|
|
329
|
-
|
|
330
|
-
# Assumptions
|
|
331
|
-
if parsed['assumptions']:
|
|
332
|
-
for assumption in parsed['assumptions']:
|
|
333
|
-
text = assumption
|
|
334
|
-
if compress_abbreviations:
|
|
335
|
-
text = ultra_compress(text)
|
|
336
|
-
lines.append(f"!{text}")
|
|
337
|
-
|
|
338
|
-
# Preconditions
|
|
339
|
-
if parsed['preconditions']:
|
|
340
|
-
for precond in parsed['preconditions']:
|
|
341
|
-
text = precond
|
|
342
|
-
if compress_abbreviations:
|
|
343
|
-
text = ultra_compress(text)
|
|
344
|
-
lines.append(f"<{text}")
|
|
345
|
-
|
|
346
|
-
# Postconditions
|
|
347
|
-
if parsed['postconditions']:
|
|
348
|
-
for postcond in parsed['postconditions']:
|
|
349
|
-
text = postcond
|
|
350
|
-
if compress_abbreviations:
|
|
351
|
-
text = ultra_compress(text)
|
|
352
|
-
lines.append(f">{text}")
|
|
353
|
-
|
|
354
|
-
# Invariants
|
|
355
|
-
if parsed['invariants']:
|
|
356
|
-
for invariant in parsed['invariants']:
|
|
357
|
-
text = invariant
|
|
358
|
-
if compress_abbreviations:
|
|
359
|
-
text = ultra_compress(text)
|
|
360
|
-
lines.append(f"={text}")
|
|
361
|
-
|
|
362
|
-
# Complexity
|
|
363
|
-
if parsed['complexity']:
|
|
364
|
-
text = parsed['complexity']
|
|
365
|
-
# Don't compress complexity
|
|
366
|
-
lines.append(f"~{text}")
|
|
367
|
-
|
|
368
|
-
# Security
|
|
369
|
-
if parsed['security']:
|
|
370
|
-
for security in parsed['security']:
|
|
371
|
-
text = security
|
|
372
|
-
if compress_abbreviations:
|
|
373
|
-
text = ultra_compress(text)
|
|
374
|
-
lines.append(f"#{text}")
|
|
375
|
-
|
|
376
|
-
return '\n'.join(lines)
|
|
377
|
-
|
|
378
|
-
@classmethod
|
|
379
|
-
def detect_format(cls, content: str) -> str:
|
|
380
|
-
"""
|
|
381
|
-
Detect if content is Standard or Lite format.
|
|
382
|
-
|
|
383
|
-
Args:
|
|
384
|
-
content: Annotation content
|
|
385
|
-
|
|
386
|
-
Returns:
|
|
387
|
-
'standard', 'lite', or 'unknown'
|
|
388
|
-
"""
|
|
389
|
-
# Check for standard symbols
|
|
390
|
-
if any(symbol in content for symbol in ['⊢', '∂', '⚠', '⊳', '⊲', '⊨', '⚡', '🔒']):
|
|
391
|
-
return 'standard'
|
|
392
|
-
|
|
393
|
-
# Check for lite symbols at start of lines
|
|
394
|
-
lines = content.strip().split('\n')
|
|
395
|
-
lite_symbols = 0
|
|
396
|
-
for line in lines:
|
|
397
|
-
line = line.strip()
|
|
398
|
-
if line and line[0] in ['>', '@', '!', '<', '=', '~', '#']:
|
|
399
|
-
lite_symbols += 1
|
|
400
|
-
|
|
401
|
-
if lite_symbols > 0:
|
|
402
|
-
return 'lite'
|
|
403
|
-
|
|
404
|
-
return 'unknown'
|