use std::path::Path;
use crate::position::ShaderRange;
use crate::symbols::symbol_parser::ShaderSymbolListBuilder;
use crate::symbols::symbols::{ShaderMember, ShaderSymbolMode, ShaderSymbolRuntime};
use crate::symbols::{
symbol_parser::{get_name, SymbolTreeParser},
symbols::{ShaderParameter, ShaderScope, ShaderSignature, ShaderSymbol, ShaderSymbolData},
};
pub fn get_glsl_parsers() -> Vec<Box<dyn SymbolTreeParser>> {
vec![
Box::new(GlslFunctionTreeParser {}),
Box::new(GlslStructTreeParser {}),
Box::new(GlslVariableTreeParser {}),
Box::new(GlslUniformBlock {}),
Box::new(GlslCallExpressionTreeParser {}),
]
}
struct GlslFunctionTreeParser {}
impl SymbolTreeParser for GlslFunctionTreeParser {
fn get_query(&self) -> String {
r#"(function_definition
type: (_) @function.return
declarator: (function_declarator
declarator: (identifier) @function.label
parameters: (parameter_list
((parameter_declaration
type: (_) @function.param.type
declarator: (_) @function.param.decl
)(",")?)*
)
)
body: (compound_statement) @function.scope
)"#
.into() }
fn process_match(
&self,
symbol_match: &tree_sitter::QueryMatch,
file_path: &Path,
shader_content: &str,
scopes: &Vec<ShaderScope>,
symbols: &mut ShaderSymbolListBuilder,
) {
let label_node = symbol_match.captures[1].node;
let range = ShaderRange::from(label_node.range());
let scope_stack = self.compute_scope_stack(scopes, &range);
let scope_node = symbol_match.captures[symbol_match.captures.len() - 1].node;
debug_assert!(
scope_stack.is_empty(),
"In GLSL all function are global scope"
);
symbols.add_function(ShaderSymbol {
label: get_name(shader_content, symbol_match.captures[1].node).into(),
requirement: None,
data: ShaderSymbolData::Functions {
signatures: vec![ShaderSignature {
returnType: get_name(shader_content, symbol_match.captures[0].node).into(),
description: "".into(),
parameters: symbol_match.captures[2..symbol_match.captures.len() - 1]
.chunks(2)
.map(|w| ShaderParameter {
ty: get_name(shader_content, w[0].node).into(),
label: get_name(shader_content, w[1].node).into(),
count: None,
description: "".into(),
range: Some(ShaderRange::from(w[1].node.range())),
})
.collect::<Vec<ShaderParameter>>(),
}],
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
range,
Some(ShaderRange::from(scope_node.range())),
scope_stack,
)),
});
}
}
struct GlslUniformBlock {}
impl SymbolTreeParser for GlslUniformBlock {
fn get_query(&self) -> String {
r#"(declaration
(identifier) @uniform.identifier
(field_declaration_list
(field_declaration
type: (_) @uniform.param.type
declarator: (_) @uniform.param.decl
)+
)
(identifier)? @uniform.name
)"#
.into()
}
fn process_match(
&self,
symbol_match: &tree_sitter::QueryMatch,
file_path: &Path,
shader_content: &str,
_scopes: &Vec<ShaderScope>,
symbols: &mut ShaderSymbolListBuilder,
) {
let capture_count = symbol_match.captures.len();
if capture_count % 2 == 0 {
let identifier_node = symbol_match.captures[0].node;
let identifier_range = ShaderRange::from(identifier_node.range());
let uniform_block_name: String = get_name(shader_content, identifier_node).into();
symbols.add_type(ShaderSymbol {
label: uniform_block_name.clone(),
requirement: None,
data: ShaderSymbolData::Struct {
constructors: vec![], members: symbol_match.captures[1..capture_count - 1]
.chunks(2)
.map(|w| ShaderMember {
context: uniform_block_name.clone(),
parameters: ShaderParameter {
ty: get_name(shader_content, w[0].node).into(),
label: get_name(shader_content, w[1].node).into(),
count: None,
description: "".into(),
range: Some(ShaderRange::from(w[1].node.range())),
},
})
.collect(),
methods: vec![],
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
identifier_range,
None,
Vec::new(),
)),
});
let variable_node = symbol_match.captures.last().unwrap().node;
let variable_range = ShaderRange::from(variable_node.range());
symbols.add_variable(ShaderSymbol {
label: get_name(shader_content, variable_node).into(),
requirement: None,
data: ShaderSymbolData::Variables {
ty: get_name(shader_content, identifier_node).into(),
count: None,
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
variable_range,
None,
Vec::new(),
)),
});
} else {
let _identifier_node = symbol_match.captures[0].node;
for uniform_value in symbol_match.captures[1..].chunks(2) {
let label_node = uniform_value[1].node;
let range = ShaderRange::from(label_node.range());
symbols.add_variable(ShaderSymbol {
label: get_name(shader_content, uniform_value[1].node).into(),
requirement: None,
data: ShaderSymbolData::Variables {
ty: get_name(shader_content, uniform_value[0].node).into(),
count: None,
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
range,
None,
Vec::new(),
)),
});
}
}
}
}
struct GlslStructTreeParser {}
impl SymbolTreeParser for GlslStructTreeParser {
fn get_query(&self) -> String {
r#"(struct_specifier
name: (type_identifier) @struct.type
body: (field_declaration_list
(field_declaration
type: (_) @struct.param.type
declarator: (_) @struct.param.decl
)+
)
)"#
.into()
}
fn process_match(
&self,
symbol_match: &tree_sitter::QueryMatch,
file_path: &Path,
shader_content: &str,
scopes: &Vec<ShaderScope>,
symbols: &mut ShaderSymbolListBuilder,
) {
let label_node = symbol_match.captures[0].node;
let label = get_name(shader_content, label_node).to_string();
let range = ShaderRange::from(label_node.range());
let scope_stack = self.compute_scope_stack(&scopes, &range);
let members = symbol_match.captures[1..]
.chunks(2)
.map(|w| ShaderParameter {
ty: get_name(shader_content, w[0].node).into(),
label: get_name(shader_content, w[1].node).into(),
count: None,
description: "".into(),
range: Some(ShaderRange::from(w[1].node.range())),
})
.collect::<Vec<ShaderParameter>>();
symbols.add_type(ShaderSymbol {
label: label.clone(),
requirement: None,
data: ShaderSymbolData::Struct {
constructors: vec![ShaderSignature {
returnType: "void".into(),
description: format!("{} constructor", label),
parameters: members.clone(),
}],
members: members
.into_iter()
.map(|m| ShaderMember {
context: label.clone(),
parameters: m,
})
.collect(),
methods: vec![],
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
range,
None,
scope_stack,
)),
});
}
}
struct GlslVariableTreeParser {}
impl SymbolTreeParser for GlslVariableTreeParser {
fn get_query(&self) -> String {
r#"(declaration
type: [
(type_identifier) @variable.type
(primitive_type) @variable.type
]
declarator: [(init_declarator
declarator: (identifier) @variable.label
value: (_) @variable.value
)
(identifier) @variable.label
]
)"#
.into()
}
fn process_match(
&self,
symbol_match: &tree_sitter::QueryMatch,
file_path: &Path,
shader_content: &str,
scopes: &Vec<ShaderScope>,
symbols: &mut ShaderSymbolListBuilder,
) {
let label_node = symbol_match.captures[1].node;
let range = ShaderRange::from(label_node.range());
let scope_stack = self.compute_scope_stack(&scopes, &range);
let _type_qualifier = get_name(shader_content, symbol_match.captures[0].node);
symbols.add_variable(ShaderSymbol {
label: get_name(shader_content, symbol_match.captures[1].node).into(),
requirement: None,
data: ShaderSymbolData::Variables {
ty: get_name(shader_content, symbol_match.captures[0].node).into(),
count: None,
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
range,
None,
scope_stack,
)),
});
}
}
struct GlslCallExpressionTreeParser {}
impl SymbolTreeParser for GlslCallExpressionTreeParser {
fn get_query(&self) -> String {
r#"(call_expression
function: (identifier) @call.identifier
arguments: (argument_list
"("
(
[
(identifier)
(number_literal)
(call_expression)
(unary_expression)
(binary_expression)
] @call.parameter
(",")?)*
")"
)
)"#
.into()
}
fn process_match(
&self,
symbol_match: &tree_sitter::QueryMatch,
file_path: &Path,
shader_content: &str,
scopes: &Vec<ShaderScope>,
symbol_builder: &mut ShaderSymbolListBuilder,
) {
let label_node = symbol_match.captures[0].node;
let range = ShaderRange::from(label_node.range());
let scope_stack = self.compute_scope_stack(&scopes, &range);
let label = get_name(shader_content, label_node).into();
symbol_builder.add_call_expression(ShaderSymbol {
label: label,
requirement: None,
data: ShaderSymbolData::CallExpression {
label: get_name(shader_content, label_node).into(),
range: range.clone(),
parameters: symbol_match.captures[1..]
.iter()
.enumerate()
.map(|(i, e)| {
(format!("param{}:", i), ShaderRange::from(e.node.range()))
})
.collect(),
},
mode: ShaderSymbolMode::Runtime(ShaderSymbolRuntime::new(
file_path.into(),
range,
None,
scope_stack,
)),
});
}
}