1use nom::combinator::all_consuming;
2use nom::{
3 branch::alt,
4 bytes::complete::tag,
5 character::complete::{alphanumeric1, one_of},
6 combinator::{map, map_parser, recognize},
7 multi::many1,
8 IResult, Parser,
9};
10#[cfg(feature = "deserialize")]
11use serde::Deserialize;
12#[cfg(feature = "serialize")]
13use serde::Serialize;
14
15use crate::attribute::parse_function_call;
16use crate::{
17 attribute::{
18 function::{parse_expression_token_variable_parameter, ExpressionToken},
19 FunctionCall,
20 },
21 string::parse_string,
22 util::{parse_until_eol, ws},
23 KconfigInput,
24};
25
26#[derive(Debug, PartialEq, Clone)]
27#[cfg_attr(feature = "hash", derive(Hash))]
28#[cfg_attr(feature = "serialize", derive(Serialize))]
29#[cfg_attr(feature = "deserialize", derive(Deserialize))]
30pub struct VariableAssignment {
31 pub identifier: VariableIdentifier,
32 pub operator: String,
33 pub right: Value,
34}
35
36impl VariableIdentifier {
37 fn raw(&self) -> String {
38 match self {
39 VariableIdentifier::Identifier(s) => s.clone(),
40 VariableIdentifier::VariableRef(reff) => reff
41 .iter()
42 .map(|e| e.to_string())
43 .collect::<Vec<_>>()
44 .join(" "),
45 }
46 }
47}
48
49#[derive(Debug, PartialEq, Clone)]
50#[cfg_attr(feature = "hash", derive(Hash))]
51#[cfg_attr(feature = "serialize", derive(Serialize))]
52#[cfg_attr(feature = "deserialize", derive(Deserialize))]
53pub enum VariableIdentifier {
54 Identifier(String),
55 VariableRef(Vec<ExpressionToken>),
56}
57
58#[derive(Debug, PartialEq, Clone)]
59#[cfg_attr(feature = "hash", derive(Hash))]
60#[cfg_attr(feature = "serialize", derive(Serialize))]
61#[cfg_attr(feature = "deserialize", derive(Deserialize))]
62pub enum Value {
63 Literal(String),
64 ExpandedVariable(String),
65 FunctionCall(FunctionCall),
66}
67
68impl Value {
69 fn raw(&self) -> String {
70 match self {
71 Value::Literal(s) => s.clone(),
72 Value::ExpandedVariable(s) => s.clone(),
73 Value::FunctionCall(function_call) => function_call.to_string(),
74 }
75 }
76}
77
78pub fn parse_value(input: KconfigInput) -> IResult<KconfigInput, Value> {
79 alt((
80 map(map_parser(parse_until_eol, parse_string), |s| {
81 Value::Literal(s)
82 }),
83 map(
84 all_consuming(map_parser(parse_until_eol, ws(parse_function_call))),
85 Value::FunctionCall,
86 ),
87 map(parse_until_eol, |s| {
88 Value::Literal(s.fragment().to_string())
89 }),
90 ))
91 .parse(input)
92}
93
94pub fn parse_variable_identifier(input: KconfigInput) -> IResult<KconfigInput, VariableIdentifier> {
95 alt((
96 map(
97 recognize(ws(many1(alt((alphanumeric1, recognize(one_of("-_"))))))),
98 |l: KconfigInput| VariableIdentifier::Identifier(l.trim().to_string()),
99 ),
100 map(many1(parse_expression_token_variable_parameter), |v| {
101 VariableIdentifier::VariableRef(v)
102 }),
103 ))
104 .parse(input)
105}
106
107pub fn parse_variable_assignment(input: KconfigInput) -> IResult<KconfigInput, VariableAssignment> {
108 let (mut remaining, assignment) = map(
109 (
110 ws(parse_variable_identifier),
111 ws(parse_assign),
112 ws(parse_value),
113 ),
114 |(l, o, r)| VariableAssignment {
115 identifier: l,
116 operator: o.to_string(),
117 right: r,
118 },
119 )
120 .parse(input)?;
121
122 remaining
125 .extra
126 .add_local_var(assignment.identifier.raw(), assignment.right.raw());
127 Ok((remaining, assignment))
128}
129
130pub fn parse_assign(input: KconfigInput<'_>) -> IResult<KconfigInput<'_>, &str> {
131 map(alt((tag("="), tag(":="), tag("+="))), |d: KconfigInput| {
132 d.fragment().to_owned()
133 })
134 .parse(input)
135}
136
137#[test]
138#[ignore]
139fn test_parse_value() {
140 assert_eq!(
141 parse_value(KconfigInput::new_extra("hello world", Default::default())),
142 Ok((
143 KconfigInput::new_extra("", Default::default()),
144 Value::Literal("hello world".to_string())
145 ))
146 );
147
148 assert_eq!(
149 parse_value(KconfigInput::new_extra(
150 r#""hello world""#,
151 Default::default()
152 )),
153 Ok((
154 KconfigInput::new_extra("", Default::default()),
155 Value::Literal("hello world".to_string())
156 ))
157 );
158}