KCL: End-exclusive ranges like [0..<10] (#7179)
Closes https://github.com/KittyCAD/modeling-app/issues/6843 To clarify: `[1..10]` is 1, 2, ..., 8, 9, 10 `[1..<10]` is 1, 2, ... 8, 9
This commit is contained in:
@ -1189,6 +1189,7 @@ impl LanguageServer for Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn completion(&self, params: CompletionParams) -> RpcResult<Option<CompletionResponse>> {
|
async fn completion(&self, params: CompletionParams) -> RpcResult<Option<CompletionResponse>> {
|
||||||
|
// ADAM: This is the entrypoint.
|
||||||
let mut completions = vec![CompletionItem {
|
let mut completions = vec![CompletionItem {
|
||||||
label: PIPE_OPERATOR.to_string(),
|
label: PIPE_OPERATOR.to_string(),
|
||||||
label_details: None,
|
label_details: None,
|
||||||
|
@ -886,7 +886,7 @@ fn array_end_start(i: &mut TokenSlice) -> PResult<Node<ArrayRangeExpression>> {
|
|||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
let start_element = expression.parse_next(i)?;
|
let start_element = expression.parse_next(i)?;
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
double_period.parse_next(i)?;
|
let end_inclusive = alt((end_inclusive_range.map(|_| true), end_exclusive_range.map(|_| false))).parse_next(i)?;
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
let end_element = expression.parse_next(i)?;
|
let end_element = expression.parse_next(i)?;
|
||||||
ignore_whitespace(i);
|
ignore_whitespace(i);
|
||||||
@ -895,7 +895,7 @@ fn array_end_start(i: &mut TokenSlice) -> PResult<Node<ArrayRangeExpression>> {
|
|||||||
ArrayRangeExpression {
|
ArrayRangeExpression {
|
||||||
start_element,
|
start_element,
|
||||||
end_element,
|
end_element,
|
||||||
end_inclusive: true,
|
end_inclusive,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
start,
|
start,
|
||||||
@ -2705,7 +2705,7 @@ fn period(i: &mut TokenSlice) -> PResult<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn double_period(i: &mut TokenSlice) -> PResult<Token> {
|
fn end_inclusive_range(i: &mut TokenSlice) -> PResult<Token> {
|
||||||
any.try_map(|token: Token| {
|
any.try_map(|token: Token| {
|
||||||
if matches!(token.token_type, TokenType::DoublePeriod) {
|
if matches!(token.token_type, TokenType::DoublePeriod) {
|
||||||
Ok(token)
|
Ok(token)
|
||||||
@ -2724,6 +2724,21 @@ fn double_period(i: &mut TokenSlice) -> PResult<Token> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn end_exclusive_range(i: &mut TokenSlice) -> PResult<Token> {
|
||||||
|
any.try_map(|token: Token| {
|
||||||
|
if matches!(token.token_type, TokenType::DoublePeriodLessThan) {
|
||||||
|
Ok(token)
|
||||||
|
} else {
|
||||||
|
Err(CompilationError::fatal(
|
||||||
|
token.as_source_range(),
|
||||||
|
format!("expected a '..<' but found {}", token.value.as_str()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.context(expected("the ..< operator, used for array ranges like [0..<10]"))
|
||||||
|
.parse_next(i)
|
||||||
|
}
|
||||||
|
|
||||||
fn colon(i: &mut TokenSlice) -> PResult<Token> {
|
fn colon(i: &mut TokenSlice) -> PResult<Token> {
|
||||||
TokenType::Colon.parse_from(i)
|
TokenType::Colon.parse_from(i)
|
||||||
}
|
}
|
||||||
@ -5344,7 +5359,6 @@ mod snapshot_tests {
|
|||||||
);
|
);
|
||||||
snapshot_test!(aa, r#"sg = -scale"#);
|
snapshot_test!(aa, r#"sg = -scale"#);
|
||||||
snapshot_test!(ab, "line(endAbsolute = [0, -1])");
|
snapshot_test!(ab, "line(endAbsolute = [0, -1])");
|
||||||
snapshot_test!(ac, "myArray = [0..10]");
|
|
||||||
snapshot_test!(
|
snapshot_test!(
|
||||||
ad,
|
ad,
|
||||||
r#"
|
r#"
|
||||||
@ -5485,6 +5499,11 @@ my14 = 4 ^ 2 - 3 ^ 2 * 2
|
|||||||
)"#
|
)"#
|
||||||
);
|
);
|
||||||
snapshot_test!(kw_function_in_binary_op, r#"val = f(x = 1) + 1"#);
|
snapshot_test!(kw_function_in_binary_op, r#"val = f(x = 1) + 1"#);
|
||||||
|
snapshot_test!(
|
||||||
|
array_ranges,
|
||||||
|
r#"incl = [1..10]
|
||||||
|
excl = [0..<10]"#
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/parsing/parser.rs
|
||||||
|
expression: actual
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"declaration": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 14,
|
||||||
|
"id": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 4,
|
||||||
|
"name": "incl",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"commentStart": 7,
|
||||||
|
"end": 14,
|
||||||
|
"endElement": {
|
||||||
|
"commentStart": 11,
|
||||||
|
"end": 13,
|
||||||
|
"raw": "10",
|
||||||
|
"start": 11,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 10.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"endInclusive": true,
|
||||||
|
"start": 7,
|
||||||
|
"startElement": {
|
||||||
|
"commentStart": 8,
|
||||||
|
"end": 9,
|
||||||
|
"raw": "1",
|
||||||
|
"start": 8,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 1.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "ArrayRangeExpression",
|
||||||
|
"type": "ArrayRangeExpression"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
},
|
||||||
|
"end": 14,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commentStart": 23,
|
||||||
|
"declaration": {
|
||||||
|
"commentStart": 23,
|
||||||
|
"end": 38,
|
||||||
|
"id": {
|
||||||
|
"commentStart": 23,
|
||||||
|
"end": 27,
|
||||||
|
"name": "excl",
|
||||||
|
"start": 23,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"commentStart": 30,
|
||||||
|
"end": 38,
|
||||||
|
"endElement": {
|
||||||
|
"commentStart": 35,
|
||||||
|
"end": 37,
|
||||||
|
"raw": "10",
|
||||||
|
"start": 35,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 10.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"endInclusive": false,
|
||||||
|
"start": 30,
|
||||||
|
"startElement": {
|
||||||
|
"commentStart": 31,
|
||||||
|
"end": 32,
|
||||||
|
"raw": "0",
|
||||||
|
"start": 31,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 0.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "ArrayRangeExpression",
|
||||||
|
"type": "ArrayRangeExpression"
|
||||||
|
},
|
||||||
|
"start": 23,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
},
|
||||||
|
"end": 38,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 23,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 38,
|
||||||
|
"start": 0
|
||||||
|
}
|
@ -369,6 +369,8 @@ pub enum TokenType {
|
|||||||
Period,
|
Period,
|
||||||
/// A double period: `..`.
|
/// A double period: `..`.
|
||||||
DoublePeriod,
|
DoublePeriod,
|
||||||
|
/// A double period and a less than: `..<`.
|
||||||
|
DoublePeriodLessThan,
|
||||||
/// A line comment.
|
/// A line comment.
|
||||||
LineComment,
|
LineComment,
|
||||||
/// A block comment.
|
/// A block comment.
|
||||||
@ -410,6 +412,7 @@ impl TryFrom<TokenType> for SemanticTokenType {
|
|||||||
| TokenType::DoubleColon
|
| TokenType::DoubleColon
|
||||||
| TokenType::Period
|
| TokenType::Period
|
||||||
| TokenType::DoublePeriod
|
| TokenType::DoublePeriod
|
||||||
|
| TokenType::DoublePeriodLessThan
|
||||||
| TokenType::Hash
|
| TokenType::Hash
|
||||||
| TokenType::Dollar
|
| TokenType::Dollar
|
||||||
| TokenType::At
|
| TokenType::At
|
||||||
|
@ -87,7 +87,7 @@ pub(super) fn token(i: &mut Input<'_>) -> PResult<Token> {
|
|||||||
'0'..='9' => number,
|
'0'..='9' => number,
|
||||||
';' => semi_colon,
|
';' => semi_colon,
|
||||||
':' => alt((double_colon, colon)),
|
':' => alt((double_colon, colon)),
|
||||||
'.' => alt((number, double_period, period)),
|
'.' => alt((number, double_period_less_than, double_period, period)),
|
||||||
'#' => hash,
|
'#' => hash,
|
||||||
'$' => dollar,
|
'$' => dollar,
|
||||||
'!' => alt((operator, bang)),
|
'!' => alt((operator, bang)),
|
||||||
@ -320,6 +320,16 @@ fn double_period(i: &mut Input<'_>) -> PResult<Token> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn double_period_less_than(i: &mut Input<'_>) -> PResult<Token> {
|
||||||
|
let (value, range) = "..<".with_span().parse_next(i)?;
|
||||||
|
Ok(Token::from_range(
|
||||||
|
range,
|
||||||
|
i.state.module_id,
|
||||||
|
TokenType::DoublePeriodLessThan,
|
||||||
|
value.to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Zero or more of either:
|
/// Zero or more of either:
|
||||||
/// 1. Any character except " or \
|
/// 1. Any character except " or \
|
||||||
/// 2. Any character preceded by \
|
/// 2. Any character preceded by \
|
||||||
|
Reference in New Issue
Block a user