Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
glslang
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
glslang
Commits
07354241
Commit
07354241
authored
Jul 01, 2016
by
John Kessenich
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
HLSL: Grammar: Recognize { } style initializers for composites.
parent
b0a63f57
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
303 additions
and
97 deletions
+303
-97
hlsl.init.frag.out
Test/baseResults/hlsl.init.frag.out
+238
-94
hlsl.init.frag
Test/hlsl.init.frag
+12
-0
hlslGrammar.cpp
hlsl/hlslGrammar.cpp
+52
-3
hlslGrammar.h
hlsl/hlslGrammar.h
+1
-0
No files found.
Test/baseResults/hlsl.init.frag.out
View file @
07354241
...
@@ -18,48 +18,99 @@ gl_FragCoord origin is upper left
...
@@ -18,48 +18,99 @@ gl_FragCoord origin is upper left
0:? 2.100000
0:? 2.100000
0:? 2.200000
0:? 2.200000
0:2 Sequence
0:2 Sequence
0:2 move second child to first child (temp float)
0:2 move second child to first child (temp
4-component vector of
float)
0:2 'a
2' (global
float)
0:2 'a
1i' (global 4-component vector of
float)
0:2 Constant:
0:2 Constant:
0:2 0.200000
0:2 1.000000
0:? Sequence
0:2 0.500000
0:2 0.000000
0:2 1.000000
0:2 move second child to first child (temp 4-component vector of float)
0:2 'b1i' (global 4-component vector of float)
0:2 Constant:
0:2 2.000000
0:2 2.500000
0:2 2.100000
0:2 2.200000
0:3 Sequence
0:3 move second child to first child (temp float)
0:3 move second child to first child (temp float)
0:3 '
b3
' (global float)
0:3 '
a2
' (global float)
0:3 Constant:
0:3 Constant:
0:3 0.
3
00000
0:3 0.
2
00000
0:? Sequence
0:? Sequence
0:4 move second child to first child (temp float)
0:4 move second child to first child (temp float)
0:4 'b
4
' (global float)
0:4 'b
3
' (global float)
0:4 Constant:
0:4 Constant:
0:4 0.400000
0:4 0.300000
0:5 Sequence
0:? Sequence
0:5 move second child to first child (temp float)
0:5 'a5' (global float)
0:5 Constant:
0:5 0.500000
0:5 move second child to first child (temp float)
0:5 move second child to first child (temp float)
0:5 '
c5
' (global float)
0:5 '
b4
' (global float)
0:5 Constant:
0:5 Constant:
0:5 1.500000
0:5 0.400000
0:13 Function Definition: ShaderFunction(vf4; (global 4-component vector of float)
0:6 Sequence
0:8 Function Parameters:
0:6 move second child to first child (temp float)
0:8 'input' (in 4-component vector of float)
0:6 'a5' (global float)
0:6 Constant:
0:6 0.500000
0:6 move second child to first child (temp float)
0:6 'c5' (global float)
0:6 Constant:
0:6 1.500000
0:25 Function Definition: ShaderFunction(vf4; (global 4-component vector of float)
0:9 Function Parameters:
0:9 'input' (in 4-component vector of float)
0:? Sequence
0:? Sequence
0:
9
Sequence
0:
10
Sequence
0:
9
move second child to first child (temp 4-component vector of float)
0:
10
move second child to first child (temp 4-component vector of float)
0:
9
'a2' (temp 4-component vector of float)
0:
10
'a2' (temp 4-component vector of float)
0:? Constant:
0:? Constant:
0:? 0.200000
0:? 0.200000
0:? 0.300000
0:? 0.300000
0:? 0.400000
0:? 0.400000
0:? 0.500000
0:? 0.500000
0:11 Branch: Return with expression
0:20 Sequence
0:11 component-wise multiply (temp 4-component vector of float)
0:20 move second child to first child (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:11 'input' (in 4-component vector of float)
0:20 's2i' (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:11 'a1' (global 4-component vector of float)
0:20 Construct structure (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 Constant:
0:20 9 (const int)
0:20 'a5' (global float)
0:20 Construct structure (temp structure{temp float f, temp int i})
0:20 Comma (temp float)
0:20 'a3' (global float)
0:20 'a4' (global float)
0:20 Constant:
0:20 12 (const int)
0:20 move second child to first child (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 's2' (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:? Construct structure (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 Constant:
0:20 9 (const int)
0:20 'a5' (global float)
0:? Construct structure (temp structure{temp float f, temp int i})
0:20 Comma (temp float)
0:20 'a3' (global float)
0:20 'a4' (global float)
0:20 Constant:
0:20 12 (const int)
0:21 Sequence
0:21 move second child to first child (temp float)
0:21 'a8' (temp float)
0:21 Comma (temp float)
0:21 'a2' (temp 4-component vector of float)
0:21 'b2' (global float)
0:21 move second child to first child (temp float)
0:21 'a9' (temp float)
0:21 'a5' (global float)
0:23 Branch: Return with expression
0:23 component-wise multiply (temp 4-component vector of float)
0:23 'input' (in 4-component vector of float)
0:23 'a1' (global 4-component vector of float)
0:? Linker Objects
0:? Linker Objects
0:? 'a1' (global 4-component vector of float)
0:? 'a1' (global 4-component vector of float)
0:? 'b1' (global 4-component vector of float)
0:? 'b1' (global 4-component vector of float)
0:? 'a1i' (global 4-component vector of float)
0:? 'b1i' (global 4-component vector of float)
0:? 'a2' (global float)
0:? 'a2' (global float)
0:? 'b2' (global float)
0:? 'b2' (global float)
0:? 'a3' (global float)
0:? 'a3' (global float)
...
@@ -94,48 +145,99 @@ gl_FragCoord origin is upper left
...
@@ -94,48 +145,99 @@ gl_FragCoord origin is upper left
0:? 2.100000
0:? 2.100000
0:? 2.200000
0:? 2.200000
0:2 Sequence
0:2 Sequence
0:2 move second child to first child (temp float)
0:2 move second child to first child (temp
4-component vector of
float)
0:2 'a
2' (global
float)
0:2 'a
1i' (global 4-component vector of
float)
0:2 Constant:
0:2 Constant:
0:2 0.200000
0:2 1.000000
0:? Sequence
0:2 0.500000
0:2 0.000000
0:2 1.000000
0:2 move second child to first child (temp 4-component vector of float)
0:2 'b1i' (global 4-component vector of float)
0:2 Constant:
0:2 2.000000
0:2 2.500000
0:2 2.100000
0:2 2.200000
0:3 Sequence
0:3 move second child to first child (temp float)
0:3 move second child to first child (temp float)
0:3 '
b3
' (global float)
0:3 '
a2
' (global float)
0:3 Constant:
0:3 Constant:
0:3 0.
3
00000
0:3 0.
2
00000
0:? Sequence
0:? Sequence
0:4 move second child to first child (temp float)
0:4 move second child to first child (temp float)
0:4 'b
4
' (global float)
0:4 'b
3
' (global float)
0:4 Constant:
0:4 Constant:
0:4 0.400000
0:4 0.300000
0:5 Sequence
0:? Sequence
0:5 move second child to first child (temp float)
0:5 'a5' (global float)
0:5 Constant:
0:5 0.500000
0:5 move second child to first child (temp float)
0:5 move second child to first child (temp float)
0:5 '
c5
' (global float)
0:5 '
b4
' (global float)
0:5 Constant:
0:5 Constant:
0:5 1.500000
0:5 0.400000
0:13 Function Definition: ShaderFunction(vf4; (global 4-component vector of float)
0:6 Sequence
0:8 Function Parameters:
0:6 move second child to first child (temp float)
0:8 'input' (in 4-component vector of float)
0:6 'a5' (global float)
0:6 Constant:
0:6 0.500000
0:6 move second child to first child (temp float)
0:6 'c5' (global float)
0:6 Constant:
0:6 1.500000
0:25 Function Definition: ShaderFunction(vf4; (global 4-component vector of float)
0:9 Function Parameters:
0:9 'input' (in 4-component vector of float)
0:? Sequence
0:? Sequence
0:
9
Sequence
0:
10
Sequence
0:
9
move second child to first child (temp 4-component vector of float)
0:
10
move second child to first child (temp 4-component vector of float)
0:
9
'a2' (temp 4-component vector of float)
0:
10
'a2' (temp 4-component vector of float)
0:? Constant:
0:? Constant:
0:? 0.200000
0:? 0.200000
0:? 0.300000
0:? 0.300000
0:? 0.400000
0:? 0.400000
0:? 0.500000
0:? 0.500000
0:11 Branch: Return with expression
0:20 Sequence
0:11 component-wise multiply (temp 4-component vector of float)
0:20 move second child to first child (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:11 'input' (in 4-component vector of float)
0:20 's2i' (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:11 'a1' (global 4-component vector of float)
0:20 Construct structure (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 Constant:
0:20 9 (const int)
0:20 'a5' (global float)
0:20 Construct structure (temp structure{temp float f, temp int i})
0:20 Comma (temp float)
0:20 'a3' (global float)
0:20 'a4' (global float)
0:20 Constant:
0:20 12 (const int)
0:20 move second child to first child (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 's2' (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:? Construct structure (temp structure{temp int j, temp float g, temp structure{temp float f, temp int i} s1})
0:20 Constant:
0:20 9 (const int)
0:20 'a5' (global float)
0:? Construct structure (temp structure{temp float f, temp int i})
0:20 Comma (temp float)
0:20 'a3' (global float)
0:20 'a4' (global float)
0:20 Constant:
0:20 12 (const int)
0:21 Sequence
0:21 move second child to first child (temp float)
0:21 'a8' (temp float)
0:21 Comma (temp float)
0:21 'a2' (temp 4-component vector of float)
0:21 'b2' (global float)
0:21 move second child to first child (temp float)
0:21 'a9' (temp float)
0:21 'a5' (global float)
0:23 Branch: Return with expression
0:23 component-wise multiply (temp 4-component vector of float)
0:23 'input' (in 4-component vector of float)
0:23 'a1' (global 4-component vector of float)
0:? Linker Objects
0:? Linker Objects
0:? 'a1' (global 4-component vector of float)
0:? 'a1' (global 4-component vector of float)
0:? 'b1' (global 4-component vector of float)
0:? 'b1' (global 4-component vector of float)
0:? 'a1i' (global 4-component vector of float)
0:? 'b1i' (global 4-component vector of float)
0:? 'a2' (global float)
0:? 'a2' (global float)
0:? 'b2' (global float)
0:? 'b2' (global float)
0:? 'a3' (global float)
0:? 'a3' (global float)
...
@@ -149,29 +251,42 @@ gl_FragCoord origin is upper left
...
@@ -149,29 +251,42 @@ gl_FragCoord origin is upper left
// Module Version 10000
// Module Version 10000
// Generated by (magic number): 80001
// Generated by (magic number): 80001
// Id's are bound by
44
// Id's are bound by
67
Capability Shader
Capability Shader
1: ExtInstImport "GLSL.std.450"
1: ExtInstImport "GLSL.std.450"
MemoryModel Logical GLSL450
MemoryModel Logical GLSL450
EntryPoint Fragment 4 "ShaderFunction"
34
EntryPoint Fragment 4 "ShaderFunction"
60
ExecutionMode 4 OriginUpperLeft
ExecutionMode 4 OriginUpperLeft
Source HLSL 450
Source HLSL 450
Name 4 "ShaderFunction"
Name 4 "ShaderFunction"
Name 9 "a1"
Name 9 "a1"
Name 14 "b1"
Name 14 "b1"
Name 21 "a2"
Name 20 "a1i"
Name 23 "b3"
Name 21 "b1i"
Name 25 "b4"
Name 23 "a2"
Name 27 "a5"
Name 25 "b3"
Name 28 "c5"
Name 27 "b4"
Name 31 "a2"
Name 29 "a5"
Name 34 "input"
Name 30 "c5"
Name 39 "b2"
Name 33 "a2"
Name 40 "a3"
Name 36 "S1"
Name 41 "a4"
MemberName 36(S1) 0 "f"
Name 42 "c4"
MemberName 36(S1) 1 "i"
Name 43 "b5"
Name 37 "S2"
MemberName 37(S2) 0 "j"
MemberName 37(S2) 1 "g"
MemberName 37(S2) 2 "s1"
Name 39 "s2i"
Name 42 "a3"
Name 43 "a4"
Name 48 "s2"
Name 54 "a8"
Name 55 "b2"
Name 57 "a9"
Name 60 "input"
Name 65 "c4"
Name 66 "b5"
2: TypeVoid
2: TypeVoid
3: TypeFunction 2
3: TypeFunction 2
6: TypeFloat 32
6: TypeFloat 32
...
@@ -188,38 +303,67 @@ gl_FragCoord origin is upper left
...
@@ -188,38 +303,67 @@ gl_FragCoord origin is upper left
17: 6(float) Constant 1074161254
17: 6(float) Constant 1074161254
18: 6(float) Constant 1074580685
18: 6(float) Constant 1074580685
19: 7(fvec4) ConstantComposite 15 16 17 18
19: 7(fvec4) ConstantComposite 15 16 17 18
20: TypePointer Private 6(float)
20(a1i): 8(ptr) Variable Private
21(a2): 20(ptr) Variable Private
21(b1i): 8(ptr) Variable Private
22: 6(float) Constant 1045220557
22: TypePointer Private 6(float)
23(b3): 20(ptr) Variable Private
23(a2): 22(ptr) Variable Private
24: 6(float) Constant 1050253722
24: 6(float) Constant 1045220557
25(b4): 20(ptr) Variable Private
25(b3): 22(ptr) Variable Private
26: 6(float) Constant 1053609165
26: 6(float) Constant 1050253722
27(a5): 20(ptr) Variable Private
27(b4): 22(ptr) Variable Private
28(c5): 20(ptr) Variable Private
28: 6(float) Constant 1053609165
29: 6(float) Constant 1069547520
29(a5): 22(ptr) Variable Private
30: TypePointer Function 7(fvec4)
30(c5): 22(ptr) Variable Private
32: 7(fvec4) ConstantComposite 22 24 26 11
31: 6(float) Constant 1069547520
33: TypePointer Input 7(fvec4)
32: TypePointer Function 7(fvec4)
34(input): 33(ptr) Variable Input
34: 7(fvec4) ConstantComposite 24 26 28 11
39(b2): 20(ptr) Variable Private
35: TypeInt 32 1
40(a3): 20(ptr) Variable Private
36(S1): TypeStruct 6(float) 35(int)
41(a4): 20(ptr) Variable Private
37(S2): TypeStruct 35(int) 6(float) 36(S1)
42(c4): 20(ptr) Variable Private
38: TypePointer Function 37(S2)
43(b5): 20(ptr) Variable Private
40: 35(int) Constant 9
42(a3): 22(ptr) Variable Private
43(a4): 22(ptr) Variable Private
45: 35(int) Constant 12
53: TypePointer Function 6(float)
55(b2): 22(ptr) Variable Private
59: TypePointer Input 7(fvec4)
60(input): 59(ptr) Variable Input
65(c4): 22(ptr) Variable Private
66(b5): 22(ptr) Variable Private
4(ShaderFunction): 2 Function None 3
4(ShaderFunction): 2 Function None 3
5: Label
5: Label
31(a2): 30(ptr) Variable Function
33(a2): 32(ptr) Variable Function
39(s2i): 38(ptr) Variable Function
48(s2): 38(ptr) Variable Function
54(a8): 53(ptr) Variable Function
57(a9): 53(ptr) Variable Function
Store 9(a1) 13
Store 9(a1) 13
Store 14(b1) 19
Store 14(b1) 19
Store 21(a2) 22
Store 20(a1i) 13
Store 23(b3) 24
Store 21(b1i) 19
Store 25(b4) 26
Store 23(a2) 24
Store 27(a5) 11
Store 25(b3) 26
Store 28(c5) 29
Store 27(b4) 28
Store 31(a2) 32
Store 29(a5) 11
35: 7(fvec4) Load 34(input)
Store 30(c5) 31
36: 7(fvec4) Load 9(a1)
Store 33(a2) 34
37: 7(fvec4) FMul 35 36
41: 6(float) Load 29(a5)
ReturnValue 37
44: 6(float) Load 43(a4)
46: 36(S1) CompositeConstruct 44 45
47: 37(S2) CompositeConstruct 40 41 46
Store 39(s2i) 47
49: 6(float) Load 29(a5)
50: 6(float) Load 43(a4)
51: 36(S1) CompositeConstruct 50 45
52: 37(S2) CompositeConstruct 40 49 51
Store 48(s2) 52
56: 6(float) Load 55(b2)
Store 54(a8) 56
58: 6(float) Load 29(a5)
Store 57(a9) 58
61: 7(fvec4) Load 60(input)
62: 7(fvec4) Load 9(a1)
63: 7(fvec4) FMul 61 62
ReturnValue 63
FunctionEnd
FunctionEnd
Test/hlsl.init.frag
View file @
07354241
float4
a1
=
float4
(
1
,
0
.
5
,
0
,
1
),
b1
=
float4
(
2
.
0
,
2
.
5
,
2
.
1
,
2
.
2
);
float4
a1
=
float4
(
1
,
0
.
5
,
0
,
1
),
b1
=
float4
(
2
.
0
,
2
.
5
,
2
.
1
,
2
.
2
);
float4
a1i
=
{
1
,
0
.
5
,
0
,
1
},
b1i
=
{
2
.
0
,
2
.
5
,
2
.
1
,
2
.
2
};
float
a2
=
0
.
2
,
b2
;
float
a2
=
0
.
2
,
b2
;
float
a3
,
b3
=
0
.
3
;
float
a3
,
b3
=
0
.
3
;
float
a4
,
b4
=
0
.
4
,
c4
;
float
a4
,
b4
=
0
.
4
,
c4
;
...
@@ -7,6 +8,17 @@ float a5 = 0.5, b5, c5 = 1.5;
...
@@ -7,6 +8,17 @@ float a5 = 0.5, b5, c5 = 1.5;
float4
ShaderFunction
(
float4
input
)
:
COLOR0
float4
ShaderFunction
(
float4
input
)
:
COLOR0
{
{
float4
a2
=
float4
(
0
.
2
,
0
.
3
,
0
.
4
,
0
.
5
);
float4
a2
=
float4
(
0
.
2
,
0
.
3
,
0
.
4
,
0
.
5
);
struct
S1
{
float
f
;
int
i
;
};
struct
S2
{
int
j
;
float
g
;
S1
s1
;
};
S2
s2i
=
{
9
,
a5
,
{
(
a3
,
a4
),
12
}
},
s2
=
S2
(
9
,
a5
,
S1
((
a3
,
a4
),
12
));
float
a8
=
(
a2
,
b2
),
a9
=
a5
;
return
input
*
a1
;
return
input
*
a1
;
}
}
hlsl/hlslGrammar.cpp
View file @
07354241
...
@@ -1173,28 +1173,77 @@ bool HlslGrammar::acceptExpression(TIntermTyped*& node)
...
@@ -1173,28 +1173,77 @@ bool HlslGrammar::acceptExpression(TIntermTyped*& node)
}
while
(
true
);
}
while
(
true
);
}
}
// initializer
// : LEFT_BRACE initializer_list RIGHT_BRACE
//
// initializer_list
// : assignment_expression COMMA assignment_expression COMMA ...
//
bool
HlslGrammar
::
acceptInitializer
(
TIntermTyped
*&
node
)
{
// LEFT_BRACE
if
(
!
acceptTokenClass
(
EHTokLeftBrace
))
return
false
;
// initializer_list
TSourceLoc
loc
=
token
.
loc
;
node
=
nullptr
;
do
{
// assignment_expression
TIntermTyped
*
expr
;
if
(
!
acceptAssignmentExpression
(
expr
))
{
expected
(
"assignment expression in initializer list"
);
return
false
;
}
node
=
intermediate
.
growAggregate
(
node
,
expr
,
loc
);
// COMMA
if
(
acceptTokenClass
(
EHTokComma
))
continue
;
// RIGHT_BRACE
if
(
acceptTokenClass
(
EHTokRightBrace
))
return
true
;
expected
(
", or }"
);
return
false
;
}
while
(
true
);
}
// Accept an assignment expression, where assignment operations
// Accept an assignment expression, where assignment operations
// associate right-to-left. Th
is
is, it is implicit, for example
// associate right-to-left. Th
at
is, it is implicit, for example
//
//
// a op (b op (c op d))
// a op (b op (c op d))
//
//
// assigment_expression
// assigment_expression
// : binary_expression op binary_expression op binary_expression ...
// : binary_expression op binary_expression op binary_expression ...
// | initializer
//
//
bool
HlslGrammar
::
acceptAssignmentExpression
(
TIntermTyped
*&
node
)
bool
HlslGrammar
::
acceptAssignmentExpression
(
TIntermTyped
*&
node
)
{
{
// initializer
if
(
peekTokenClass
(
EHTokLeftBrace
))
{
if
(
acceptInitializer
(
node
))
return
true
;
expected
(
"initializer"
);
return
false
;
}
// binary_expression
if
(
!
acceptBinaryExpression
(
node
,
PlLogicalOr
))
if
(
!
acceptBinaryExpression
(
node
,
PlLogicalOr
))
return
false
;
return
false
;
// assignment operation?
TOperator
assignOp
=
HlslOpMap
::
assignment
(
peek
());
TOperator
assignOp
=
HlslOpMap
::
assignment
(
peek
());
if
(
assignOp
==
EOpNull
)
if
(
assignOp
==
EOpNull
)
return
true
;
return
true
;
//
...
op
//
assignment
op
TSourceLoc
loc
=
token
.
loc
;
TSourceLoc
loc
=
token
.
loc
;
advanceToken
();
advanceToken
();
//
...
binary_expression
// binary_expression
// But, done by recursing this function, which automatically
// But, done by recursing this function, which automatically
// gets the right-to-left associativity.
// gets the right-to-left associativity.
TIntermTyped
*
rightNode
=
nullptr
;
TIntermTyped
*
rightNode
=
nullptr
;
...
...
hlsl/hlslGrammar.h
View file @
07354241
...
@@ -73,6 +73,7 @@ namespace glslang {
...
@@ -73,6 +73,7 @@ namespace glslang {
bool
acceptFunctionDefinition
(
TFunction
&
,
TIntermNode
*&
);
bool
acceptFunctionDefinition
(
TFunction
&
,
TIntermNode
*&
);
bool
acceptParenExpression
(
TIntermTyped
*&
);
bool
acceptParenExpression
(
TIntermTyped
*&
);
bool
acceptExpression
(
TIntermTyped
*&
);
bool
acceptExpression
(
TIntermTyped
*&
);
bool
acceptInitializer
(
TIntermTyped
*&
);
bool
acceptAssignmentExpression
(
TIntermTyped
*&
);
bool
acceptAssignmentExpression
(
TIntermTyped
*&
);
bool
acceptBinaryExpression
(
TIntermTyped
*&
,
PrecedenceLevel
);
bool
acceptBinaryExpression
(
TIntermTyped
*&
,
PrecedenceLevel
);
bool
acceptUnaryExpression
(
TIntermTyped
*&
);
bool
acceptUnaryExpression
(
TIntermTyped
*&
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment