Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Marco Bubke
flatpak-qt-creator
Commits
f76234f1
Commit
f76234f1
authored
Feb 21, 2011
by
Erik Verbruggen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removed left-overs from initial development.
parent
3787aa7a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
0 additions
and
597 deletions
+0
-597
src/libs/glsl/tests/main.cpp
src/libs/glsl/tests/main.cpp
+0
-92
src/libs/glsl/tests/test.pro
src/libs/glsl/tests/test.pro
+0
-14
src/libs/glsl/tools/kwgen.cpp
src/libs/glsl/tools/kwgen.cpp
+0
-406
src/libs/glsl/tools/mkvisitor.py
src/libs/glsl/tools/mkvisitor.py
+0
-85
No files found.
src/libs/glsl/tests/main.cpp
deleted
100644 → 0
View file @
3787aa7a
#include <glslengine.h>
#include <glslparser.h>
#include <glsllexer.h>
#include <glslastdump.h>
#include <glslsemantic.h>
#include <glslsymbols.h>
#include <glsltypes.h>
#include <QtCore/QTextStream>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cassert>
#include <cstdio>
using
namespace
GLSL
;
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
namespace
{
QTextStream
qout
(
stdout
,
QIODevice
::
WriteOnly
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
int
variant
=
0
;
while
(
argc
>
1
&&
argv
[
1
][
0
]
==
'-'
&&
argv
[
1
][
1
]
==
'-'
)
{
if
(
!
strcmp
(
argv
[
1
],
"--version=1.20"
))
{
variant
|=
Lexer
::
Variant_GLSL_120
;
}
else
if
(
!
strcmp
(
argv
[
1
],
"--version=1.50"
))
{
variant
|=
Lexer
::
Variant_GLSL_150
;
}
else
if
(
!
strcmp
(
argv
[
1
],
"--version=4.00"
))
{
variant
|=
Lexer
::
Variant_GLSL_400
;
}
else
if
(
!
strcmp
(
argv
[
1
],
"--version=es"
))
{
variant
|=
Lexer
::
Variant_GLSL_ES_100
;
}
else
if
(
!
strcmp
(
argv
[
1
],
"--shader=vertex"
))
{
variant
|=
Lexer
::
Variant_VertexShader
;
}
else
if
(
!
strcmp
(
argv
[
1
],
"--shader=fragment"
))
{
variant
|=
Lexer
::
Variant_FragmentShader
;
}
else
{
std
::
cerr
<<
"glsl: unknown option: "
<<
argv
[
1
]
<<
std
::
endl
;
return
EXIT_FAILURE
;
}
++
argv
;
--
argc
;
}
if
(
argc
!=
2
)
{
std
::
cerr
<<
"glsl: no input file"
<<
std
::
endl
;
return
EXIT_FAILURE
;
}
std
::
ifstream
fin
(
argv
[
1
]);
if
(
!
fin
)
{
std
::
cerr
<<
"glsl: No such file or directory"
<<
std
::
endl
;
return
EXIT_FAILURE
;
}
fin
.
seekg
(
0
,
std
::
ios
::
end
);
size_t
size
=
fin
.
tellg
();
fin
.
seekg
(
0
,
std
::
ios
::
beg
);
char
*
source
=
new
char
[
size
];
fin
.
read
(
source
,
size
);
fin
.
close
();
if
(
!
variant
)
variant
=
Lexer
::
Variant_Mask
&
~
Lexer
::
Variant_Reserved
;
else
if
((
variant
&
(
Lexer
::
Variant_VertexShader
|
Lexer
::
Variant_FragmentShader
))
==
0
)
variant
|=
Lexer
::
Variant_VertexShader
|
Lexer
::
Variant_FragmentShader
;
Engine
engine
;
Parser
parser
(
&
engine
,
source
,
size
,
variant
);
TranslationUnitAST
*
ast
=
parser
.
parse
();
std
::
cout
<<
argv
[
1
]
<<
(
ast
?
" OK "
:
" KO "
)
<<
std
::
endl
;
ASTDump
dump
(
qout
);
dump
(
ast
);
Semantic
sem
;
Scope
*
globalScope
=
engine
.
newNamespace
();
sem
.
translationUnit
(
ast
,
globalScope
,
&
engine
);
delete
source
;
delete
ast
;
return
EXIT_SUCCESS
;
}
src/libs/glsl/tests/test.pro
deleted
100644 → 0
View file @
3787aa7a
TEMPLATE
=
app
CONFIG
-=
app_bundle
CONFIG
+=
console
TARGET
=
glsl
DEPENDPATH
+=
.
INCLUDEPATH
+=
.
..
QT
=
core
#
Input
SOURCES
+=
main
.
cpp
include
(..
/
glsl
-
lib
.
pri
)
src/libs/glsl/tools/kwgen.cpp
deleted
100644 → 0
View file @
3787aa7a
/*
Copyright 2007 Roberto Raggi <roberto@kdevelop.org>
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
KDEVELOP TEAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string>
#include <iostream>
#include <map>
#include <list>
#include <vector>
#include <set>
#include <cstdlib>
#include <cctype>
#include <functional>
#include <algorithm>
class
State
;
class
DottedItem
;
typedef
std
::
list
<
std
::
string
>
RuleList
;
typedef
RuleList
::
iterator
RulePtr
;
typedef
std
::
list
<
State
>
StateList
;
typedef
StateList
::
iterator
StatePtr
;
typedef
std
::
string
::
iterator
Dot
;
typedef
std
::
vector
<
DottedItem
>::
iterator
DottedItemPtr
;
class
DottedItem
{
public:
RulePtr
rule
;
Dot
dot
;
DottedItem
()
{}
DottedItem
(
RulePtr
rule
,
Dot
dot
)
:
rule
(
rule
),
dot
(
dot
)
{}
bool
operator
==
(
const
DottedItem
&
other
)
const
{
return
rule
==
other
.
rule
&&
dot
==
other
.
dot
;
}
bool
operator
!=
(
const
DottedItem
&
other
)
const
{
return
!
operator
==
(
other
);
}
bool
terminal
()
const
{
return
dot
==
rule
->
end
();
}
DottedItem
next
()
const
{
DottedItem
item
;
item
.
rule
=
rule
;
item
.
dot
=
dot
;
++
item
.
dot
;
return
item
;
}
};
struct
State
{
public:
State
()
{}
template
<
typename
_ForwardIterator
>
State
(
_ForwardIterator
first
,
_ForwardIterator
last
)
{
_items
.
insert
(
_items
.
end
(),
first
,
last
);
}
static
State
&
intern
(
const
State
&
state
)
{
StatePtr
ptr
=
std
::
find
(
first_state
(),
last_state
(),
state
);
if
(
ptr
==
last_state
())
ptr
=
states
().
insert
(
last_state
(),
state
);
return
*
ptr
;
}
State
&
next
(
char
ch
)
{
std
::
vector
<
DottedItem
>
n
;
for
(
DottedItemPtr
it
=
first_item
();
it
!=
last_item
();
++
it
)
{
if
(
!
it
->
terminal
()
&&
*
it
->
dot
==
ch
)
n
.
push_back
(
it
->
next
());
}
return
intern
(
State
(
n
.
begin
(),
n
.
end
()));
}
std
::
set
<
char
>
firsts
()
{
std
::
set
<
char
>
s
;
for
(
DottedItemPtr
it
=
first_item
();
it
!=
last_item
();
++
it
)
{
if
(
!
it
->
terminal
())
s
.
insert
(
*
it
->
dot
);
}
return
s
;
}
size_t
item_count
()
const
{
return
_items
.
size
();
}
DottedItemPtr
first_item
()
{
return
_items
.
begin
();
}
DottedItemPtr
last_item
()
{
return
_items
.
end
();
}
static
StatePtr
first_state
()
{
return
states
().
begin
();
}
static
StatePtr
last_state
()
{
return
states
().
end
();
}
bool
operator
==
(
const
State
&
other
)
const
{
return
_items
==
other
.
_items
;
}
bool
operator
!=
(
const
State
&
other
)
const
{
return
_items
!=
other
.
_items
;
}
template
<
typename
_Iterator
>
static
State
&
start
(
_Iterator
first
,
_Iterator
last
)
{
std
::
vector
<
DottedItem
>
items
;
for
(;
first
!=
last
;
++
first
)
items
.
push_back
(
DottedItem
(
first
,
first
->
begin
()));
return
intern
(
State
(
items
.
begin
(),
items
.
end
()));
}
static
void
reset
()
{
states
().
clear
();
}
private:
static
StateList
&
states
()
{
static
StateList
_states
;
return
_states
;
}
private:
std
::
vector
<
DottedItem
>
_items
;
};
static
bool
option_no_enums
=
false
;
static
bool
option_toupper
=
false
;
static
std
::
string
option_namespace_name
;
static
std
::
string
option_class_name
;
static
std
::
string
option_token_prefix
=
"Token_"
;
static
std
::
string
option_variant_prefix
=
"Variant_"
;
static
std
::
string
option_char_type
=
"char"
;
static
std
::
string
option_unicode_function
=
""
;
static
std
::
map
<
std
::
string
,
std
::
string
>
variants
;
std
::
string
token_id
(
const
std
::
string
&
id
)
{
std
::
string
token
=
option_token_prefix
;
if
(
!
option_toupper
)
token
+=
id
;
else
{
for
(
size_t
i
=
0
;
i
<
id
.
size
();
++
i
)
token
+=
toupper
(
id
[
i
]);
}
return
token
;
}
std
::
string
variant_id
(
const
std
::
string
&
id
)
{
if
(
variants
.
find
(
id
)
==
variants
.
end
())
return
""
;
std
::
string
variant
=
variants
[
id
];
size_t
posn
=
0
;
bool
sep
=
true
;
std
::
string
result
;
while
(
posn
<
variant
.
size
())
{
char
ch
=
variant
[
posn
++
];
if
(
isalnum
(
ch
)
||
ch
==
'_'
)
{
if
(
sep
)
{
result
+=
" | "
+
option_variant_prefix
;
sep
=
false
;
}
result
+=
ch
;
}
else
if
(
!
sep
)
{
sep
=
true
;
}
}
return
result
;
}
bool
starts_with
(
const
std
::
string
&
line
,
const
std
::
string
&
text
)
{
if
(
text
.
length
()
<
line
.
length
())
{
return
std
::
equal
(
line
.
begin
(),
line
.
begin
()
+
text
.
size
(),
text
.
begin
());
}
return
false
;
}
void
doit
(
State
&
state
)
{
static
int
depth
=
0
;
++
depth
;
std
::
string
indent
(
depth
*
2
,
' '
);
std
::
set
<
char
>
firsts
=
state
.
firsts
();
for
(
std
::
set
<
char
>::
iterator
it
=
firsts
.
begin
();
it
!=
firsts
.
end
();
++
it
)
{
std
::
string
_else
=
it
==
firsts
.
begin
()
?
""
:
"else "
;
std
::
cout
<<
indent
<<
_else
<<
"if (s["
<<
(
depth
-
1
)
<<
"]"
<<
option_unicode_function
<<
" == '"
<<
*
it
<<
"') {"
<<
std
::
endl
;
State
&
next_state
=
state
.
next
(
*
it
);
bool
found
=
false
;
for
(
DottedItemPtr
item
=
next_state
.
first_item
();
item
!=
next_state
.
last_item
();
++
item
)
{
if
(
item
->
terminal
())
{
if
(
found
)
{
std
::
cerr
<<
"*** Error. Too many accepting states"
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
found
=
true
;
std
::
cout
<<
indent
<<
" return "
<<
option_namespace_name
<<
token_id
(
*
item
->
rule
)
<<
variant_id
(
*
item
->
rule
)
<<
";"
<<
std
::
endl
;
}
}
if
(
!
found
)
doit
(
next_state
);
std
::
cout
<<
indent
<<
"}"
<<
std
::
endl
;
}
--
depth
;
}
void
gen_classify_n
(
State
&
start_state
,
int
N
)
{
std
::
cout
<<
"static inline int classify"
<<
N
<<
"(const "
<<
option_char_type
<<
" *s) {"
<<
std
::
endl
;
doit
(
start_state
);
std
::
cout
<<
" return "
<<
option_namespace_name
<<
token_id
(
"identifier"
)
<<
";"
<<
std
::
endl
<<
"}"
<<
std
::
endl
<<
std
::
endl
;
}
void
gen_classify
(
const
std
::
multimap
<
size_t
,
std
::
string
>
&
keywords
)
{
std
::
cout
<<
"int "
<<
option_class_name
<<
"classify(const "
<<
option_char_type
<<
" *s, int n) {"
<<
std
::
endl
<<
" switch (n) {"
<<
std
::
endl
;
std
::
multimap
<
size_t
,
std
::
string
>::
const_iterator
it
=
keywords
.
begin
();
while
(
it
!=
keywords
.
end
())
{
size_t
size
=
it
->
first
;
std
::
cout
<<
" case "
<<
size
<<
": return classify"
<<
size
<<
"(s);"
<<
std
::
endl
;
do
{
++
it
;
}
while
(
it
!=
keywords
.
end
()
&&
it
->
first
==
size
);
}
std
::
cout
<<
" default: return "
<<
option_namespace_name
<<
token_id
(
"identifier"
)
<<
";"
<<
std
::
endl
<<
" } // switch"
<<
std
::
endl
<<
"}"
<<
std
::
endl
<<
std
::
endl
;
}
void
gen_keyword_list
(
const
std
::
multimap
<
size_t
,
std
::
string
>
&
keywords
)
{
std
::
cout
<<
"QStringList "
<<
option_class_name
<<
"keywords(int variant) {"
<<
std
::
endl
<<
" QStringList list;"
<<
std
::
endl
;
std
::
multimap
<
size_t
,
std
::
string
>::
const_iterator
it
=
keywords
.
begin
();
for
(;
it
!=
keywords
.
end
();
++
it
)
{
std
::
string
varid
=
variant_id
(
it
->
second
);
if
(
varid
.
empty
())
{
std
::
cout
<<
" list += QLatin1String(
\"
"
<<
it
->
second
<<
"
\"
);"
<<
std
::
endl
;
}
else
{
varid
=
varid
.
substr
(
3
);
std
::
cout
<<
" if (variant & ("
<<
varid
<<
"))"
<<
std
::
endl
;
std
::
cout
<<
" list += QLatin1String(
\"
"
<<
it
->
second
<<
"
\"
);"
<<
std
::
endl
;
}
}
std
::
cout
<<
" return list;"
<<
std
::
endl
<<
"}"
<<
std
::
endl
<<
std
::
endl
;
}
void
gen_enums
(
const
std
::
multimap
<
size_t
,
std
::
string
>
&
keywords
)
{
std
::
cout
<<
"enum {"
<<
std
::
endl
;
std
::
multimap
<
size_t
,
std
::
string
>::
const_iterator
it
=
keywords
.
begin
();
for
(;
it
!=
keywords
.
end
();
++
it
)
{
std
::
cout
<<
" "
<<
token_id
(
it
->
second
)
<<
variant_id
(
it
->
second
)
<<
","
<<
std
::
endl
;
}
std
::
cout
<<
" "
<<
token_id
(
"identifier"
)
<<
std
::
endl
<<
"};"
<<
std
::
endl
<<
std
::
endl
;
}
inline
bool
not_whitespace_p
(
char
ch
)
{
return
!
std
::
isspace
(
ch
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
const
std
::
string
ns
=
"--namespace="
;
for
(
int
i
=
0
;
i
<
argc
;
++
i
)
{
const
std
::
string
arg
(
argv
[
i
]);
if
(
arg
==
"--no-enums"
)
option_no_enums
=
true
;
else
if
(
starts_with
(
arg
,
ns
))
{
option_namespace_name
.
assign
(
arg
.
begin
()
+
ns
.
size
(),
arg
.
end
());
option_namespace_name
+=
"::"
;
}
}
std
::
multimap
<
size_t
,
std
::
string
>
keywords
;
std
::
string
textline
;
bool
readKeywords
=
false
;
const
std
::
string
opt_no_enums
=
"%no-enums"
;
const
std
::
string
opt_toupper
=
"%toupper"
;
const
std
::
string
opt_ns
=
"%namespace="
;
const
std
::
string
opt_class
=
"%lexer-class="
;
const
std
::
string
opt_tok_prefix
=
"%token-prefix="
;
const
std
::
string
opt_var_prefix
=
"%variant-prefix="
;
const
std
::
string
opt_char_type
=
"%char-type="
;
const
std
::
string
opt_unicode_function
=
"%unicode-function="
;
while
(
getline
(
std
::
cin
,
textline
))
{
// remove trailing spaces
textline
.
assign
(
textline
.
begin
(),
std
::
find_if
(
textline
.
rbegin
(),
textline
.
rend
(),
not_whitespace_p
).
base
());
if
(
!
readKeywords
)
{
if
(
textline
.
size
()
>=
2
&&
textline
[
0
]
==
'%'
)
{
if
(
textline
[
1
]
==
'%'
)
{
readKeywords
=
true
;
}
else
if
(
textline
==
opt_no_enums
)
{
option_no_enums
=
true
;
}
else
if
(
textline
==
opt_toupper
)
{
option_toupper
=
true
;
}
else
if
(
starts_with
(
textline
,
opt_tok_prefix
))
{
option_token_prefix
.
assign
(
textline
.
begin
()
+
opt_tok_prefix
.
size
(),
textline
.
end
());
}
else
if
(
starts_with
(
textline
,
opt_var_prefix
))
{
option_variant_prefix
.
assign
(
textline
.
begin
()
+
opt_var_prefix
.
size
(),
textline
.
end
());
}
else
if
(
starts_with
(
textline
,
opt_char_type
))
{
option_char_type
.
assign
(
textline
.
begin
()
+
opt_char_type
.
size
(),
textline
.
end
());
}
else
if
(
starts_with
(
textline
,
opt_unicode_function
))
{
option_unicode_function
.
assign
(
textline
.
begin
()
+
opt_unicode_function
.
size
(),
textline
.
end
());
}
else
if
(
starts_with
(
textline
,
opt_ns
))
{
option_namespace_name
.
assign
(
textline
.
begin
()
+
opt_ns
.
size
(),
textline
.
end
());
option_namespace_name
+=
"::"
;
}
else
if
(
starts_with
(
textline
,
opt_class
))
{
option_class_name
.
assign
(
textline
.
begin
()
+
opt_class
.
size
(),
textline
.
end
());
option_class_name
+=
"::"
;
}
continue
;
}
std
::
cout
<<
textline
<<
std
::
endl
;
}
else
{
if
(
textline
.
empty
())
continue
;
std
::
string
::
iterator
start
=
textline
.
begin
();
while
(
start
!=
textline
.
end
()
&&
std
::
isspace
(
*
start
))
++
start
;
std
::
string
::
iterator
stop
=
start
;
while
(
stop
!=
textline
.
end
()
&&
(
std
::
isalnum
(
*
stop
)
||
*
stop
==
'_'
))
++
stop
;
if
(
start
!=
stop
)
{
std
::
string
keyword
(
start
,
stop
);
if
(
keyword
==
"identifier"
)
{
std
::
cerr
<<
"*** Error. `identifier' is reserved"
<<
std
::
endl
;
exit
(
EXIT_FAILURE
);
}
keywords
.
insert
(
std
::
make_pair
(
keyword
.
size
(),
keyword
));
start
=
stop
;
while
(
start
!=
textline
.
end
()
&&
std
::
isspace
(
*
start
))
++
start
;
if
(
start
!=
textline
.
end
()
&&
*
start
==
'%'
)
{
++
start
;
std
::
string
::
iterator
stop
=
start
;
while
(
stop
!=
textline
.
end
()
&&
(
std
::
isalnum
(
*
stop
)
||
*
stop
==
'_'
))
++
stop
;
std
::
string
directive
(
start
,
stop
);
if
(
directive
==
"variant"
)
{
while
(
stop
!=
textline
.
end
()
&&
std
::
isspace
(
*
stop
))
++
stop
;
std
::
string
variant
(
stop
,
textline
.
end
());
variants
.
insert
(
std
::
make_pair
(
keyword
,
variant
));
}
}
}
}
}
if
(
option_class_name
.
empty
())
option_class_name
=
option_namespace_name
;
if
(
!
option_no_enums
)
gen_enums
(
keywords
);
std
::
multimap
<
size_t
,
std
::
string
>::
iterator
it
=
keywords
.
begin
();
while
(
it
!=
keywords
.
end
())
{
size_t
size
=
it
->
first
;
RuleList
rules
;
do
{
rules
.
push_back
(
it
->
second
);
++
it
;
}
while
(
it
!=
keywords
.
end
()
&&
it
->
first
==
size
);
gen_classify_n
(
State
::
start
(
rules
.
begin
(),
rules
.
end
()),
size
);
State
::
reset
();
}
gen_classify
(
keywords
);
gen_keyword_list
(
keywords
);
}
src/libs/glsl/tools/mkvisitor.py
deleted
100755 → 0
View file @
3787aa7a
#!/usr/bin/python
import
sys
try
:
file
=
open
(
sys
.
argv
[
1
],
"r"
)
klass
=
sys
.
argv
[
2
]
except
:
print
(
"Usage: mkvisitor.py grammar.txt classname"
)
exit
()
lines
=
file
.
readlines
()
ruleno
=
0
print
(
"""
#include "glslast.h"
namespace GLSL {
class %s
{
typedef void (%s::*dispatch_func)(AST *);
static dispatch_func dispatch[];
public:
void accept(AST *ast)
{
if (! ast)
return;
else if (Operator *op = ast->asOperator())
(this->*dispatch[op->ruleno])(ast);
}
template <typename It>
void accept(It first, It last)
{
for (; first != last; ++first)
accept(*first);
}
private:"""
%
(
klass
,
klass
))
for
line
in
lines
:
sections
=
line
.
split
()
if
len
(
sections
)
and
sections
[
1
]
==
"::="
:
ruleno
=
ruleno
+
1
print
(
" void on_%s_%d(AST *);"
%
(
sections
[
0
],
ruleno
))
print
(
"};"
)
print
(
"} // end of namespace GLSL"
)
print
(
"""
#include <iostream>
using namespace GLSL;
namespace {
bool debug = false;
}
"""
)
print
(
"%s::dispatch_func %s::dispatch[] = {"
%
(
klass
,
klass
))
ruleno
=
0
for
line
in
lines
:
sections
=
line
.
split
()
if
len
(
sections
)
and
sections
[
1
]
==
"::="
:
ruleno
=
ruleno
+
1
print
(
" &%s::on_%s_%d,"
%
(
klass
,
sections
[
0
],
ruleno
))
print
(
"0, };
\n
"
)
ruleno
=
0
for
line
in
lines
:
sections
=
line
.
split
()
if
len
(
sections
)
and
sections
[
1
]
==
"::="
:
ruleno
=
ruleno
+
1
print
(
"""// %svoid %s::on_%s_%d(AST *ast)
{
if (debug)
std::cout << "%s" << std::endl;
Operator *op = ast->asOperator();
accept(op->begin(), op->end());
}
"""
%
(
line
,
klass
,
sections
[
0
],
ruleno
,
line
[:
-
3
]))
Write
Preview
Markdown
is supported
0%