KCL: Allow comments in CallExpressionKw (#5381)
Before, this would not parse: ``` line( end = [44.09, 306.95], // tag this for later tag = $hello ) ``` Now it does.
This commit is contained in:
@ -964,6 +964,7 @@ export function createCallExpressionStdLibKw(
|
||||
end: 0,
|
||||
moduleId: 0,
|
||||
outerAttrs: [],
|
||||
nonCodeMeta: nonCodeMetaEmpty(),
|
||||
callee: {
|
||||
type: 'Identifier',
|
||||
start: 0,
|
||||
@ -1585,7 +1586,7 @@ export async function deleteFromSelection(
|
||||
return new Error('Selection not recognised, could not delete')
|
||||
}
|
||||
|
||||
const nonCodeMetaEmpty = () => {
|
||||
export const nonCodeMetaEmpty = () => {
|
||||
return { nonCodeNodes: {}, startNodes: [], start: 0, end: 0 }
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ import { toolTips, ToolTip } from 'lang/langHelpers'
|
||||
import {
|
||||
createPipeExpression,
|
||||
mutateKwArg,
|
||||
nonCodeMetaEmpty,
|
||||
splitPathAtPipeExpression,
|
||||
} from '../modifyAst'
|
||||
|
||||
@ -2509,6 +2510,7 @@ function addTagKw(): addTagFn {
|
||||
unlabeled: callExpr.node.arguments.length
|
||||
? callExpr.node.arguments[0]
|
||||
: null,
|
||||
nonCodeMeta: nonCodeMetaEmpty(),
|
||||
arguments: [],
|
||||
}
|
||||
const tagArg = findKwArg(ARG_TAG, primaryCallExp)
|
||||
|
@ -1581,7 +1581,7 @@ pub struct CallExpression {
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(tag = "type")]
|
||||
#[serde(rename_all = "camelCase", tag = "type")]
|
||||
pub struct CallExpressionKw {
|
||||
pub callee: Node<Identifier>,
|
||||
pub unlabeled: Option<Expr>,
|
||||
@ -1591,6 +1591,9 @@ pub struct CallExpressionKw {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub digest: Option<Digest>,
|
||||
|
||||
#[serde(default, skip_serializing_if = "NonCodeMeta::is_empty")]
|
||||
pub non_code_meta: NonCodeMeta,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||
@ -1714,6 +1717,7 @@ impl CallExpressionKw {
|
||||
unlabeled,
|
||||
arguments,
|
||||
digest: None,
|
||||
non_code_meta: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -882,6 +882,17 @@ fn property_separator(i: &mut TokenSlice) -> PResult<()> {
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// Match something that separates the labeled arguments of a fn call.
|
||||
fn labeled_arg_separator(i: &mut TokenSlice) -> PResult<()> {
|
||||
alt((
|
||||
// Normally you need a comma.
|
||||
comma_sep,
|
||||
// But, if the argument list is ending, no need for a comma.
|
||||
peek(preceded(opt(whitespace), close_paren)).void(),
|
||||
))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// Parse a KCL object value.
|
||||
pub(crate) fn object(i: &mut TokenSlice) -> PResult<Node<ObjectExpression>> {
|
||||
let open = open_brace(i)?;
|
||||
@ -2496,14 +2507,6 @@ fn labeled_argument(i: &mut TokenSlice) -> PResult<LabeledArg> {
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// Arguments are passed into a function,
|
||||
/// preceded by the name of the parameter (the label).
|
||||
fn labeled_arguments(i: &mut TokenSlice) -> PResult<Vec<LabeledArg>> {
|
||||
separated(0.., labeled_argument, comma_sep)
|
||||
.context(expected("function arguments"))
|
||||
.parse_next(i)
|
||||
}
|
||||
|
||||
/// A type of a function argument.
|
||||
/// This can be:
|
||||
/// - a primitive type, e.g. 'number' or 'string' or 'bool'
|
||||
@ -2783,7 +2786,28 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
ignore_whitespace(i);
|
||||
|
||||
let initial_unlabeled_arg = opt((expression, comma, opt(whitespace)).map(|(arg, _, _)| arg)).parse_next(i)?;
|
||||
let args = labeled_arguments(i)?;
|
||||
let args: Vec<_> = repeat(
|
||||
0..,
|
||||
alt((
|
||||
terminated(non_code_node.map(NonCodeOr::NonCode), whitespace),
|
||||
terminated(labeled_argument, labeled_arg_separator).map(NonCodeOr::Code),
|
||||
)),
|
||||
)
|
||||
.parse_next(i)?;
|
||||
let (args, non_code_nodes): (Vec<_>, BTreeMap<usize, _>) = args.into_iter().enumerate().fold(
|
||||
(Vec::new(), BTreeMap::new()),
|
||||
|(mut args, mut non_code_nodes), (i, e)| {
|
||||
match e {
|
||||
NonCodeOr::NonCode(x) => {
|
||||
non_code_nodes.insert(i, vec![x]);
|
||||
}
|
||||
NonCodeOr::Code(x) => {
|
||||
args.push(x);
|
||||
}
|
||||
}
|
||||
(args, non_code_nodes)
|
||||
},
|
||||
);
|
||||
if let Some(std_fn) = crate::std::get_stdlib_fn(&fn_name.name) {
|
||||
let just_args: Vec<_> = args.iter().collect();
|
||||
typecheck_all_kw(std_fn, &just_args)?;
|
||||
@ -2792,6 +2816,10 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
opt(comma_sep).parse_next(i)?;
|
||||
let end = close_paren.parse_next(i)?.end;
|
||||
|
||||
let non_code_meta = NonCodeMeta {
|
||||
non_code_nodes,
|
||||
..Default::default()
|
||||
};
|
||||
Ok(Node {
|
||||
start: fn_name.start,
|
||||
end,
|
||||
@ -2801,6 +2829,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
||||
unlabeled: initial_unlabeled_arg,
|
||||
arguments: args,
|
||||
digest: None,
|
||||
non_code_meta,
|
||||
},
|
||||
outer_attrs: Vec::new(),
|
||||
})
|
||||
@ -4390,14 +4419,6 @@ let myBox = box([0,0], -3, -16, -10)
|
||||
crate::parsing::top_level_parse(some_program_string).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_labels() {
|
||||
let input = r#"length: 3"#;
|
||||
let module_id = ModuleId::default();
|
||||
let tokens = crate::parsing::token::lex(input, module_id).unwrap();
|
||||
super::labeled_arguments(&mut tokens.as_slice()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kw_fn() {
|
||||
for input in ["val = foo(x, y = z)", "val = foo(y = z)"] {
|
||||
@ -4879,6 +4900,22 @@ my14 = 4 ^ 2 - 3 ^ 2 * 2
|
||||
r#"fn foo(x?: number = 2) { return 1 }"#
|
||||
);
|
||||
snapshot_test!(kw_function_call_in_pipe, r#"val = 1 |> f(arg = x)"#);
|
||||
snapshot_test!(
|
||||
kw_function_call_multiline,
|
||||
r#"val = f(
|
||||
arg = x,
|
||||
foo = x,
|
||||
bar = x,
|
||||
)"#
|
||||
);
|
||||
snapshot_test!(
|
||||
kw_function_call_multiline_with_comments,
|
||||
r#"val = f(
|
||||
arg = x,
|
||||
// foo = x,
|
||||
bar = x,
|
||||
)"#
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -0,0 +1,86 @@
|
||||
---
|
||||
source: kcl/src/parsing/parser.rs
|
||||
expression: actual
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"body": [
|
||||
{
|
||||
"declaration": {
|
||||
"end": 87,
|
||||
"id": {
|
||||
"end": 3,
|
||||
"name": "val",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "arg"
|
||||
},
|
||||
"arg": {
|
||||
"end": 29,
|
||||
"name": "x",
|
||||
"start": 28,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "foo"
|
||||
},
|
||||
"arg": {
|
||||
"end": 51,
|
||||
"name": "x",
|
||||
"start": 50,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "bar"
|
||||
},
|
||||
"arg": {
|
||||
"end": 73,
|
||||
"name": "x",
|
||||
"start": 72,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 7,
|
||||
"name": "f",
|
||||
"start": 6,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 87,
|
||||
"start": 6,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": null
|
||||
},
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 87,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 87,
|
||||
"start": 0
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
---
|
||||
source: kcl/src/parsing/parser.rs
|
||||
expression: actual
|
||||
snapshot_kind: text
|
||||
---
|
||||
{
|
||||
"body": [
|
||||
{
|
||||
"declaration": {
|
||||
"end": 90,
|
||||
"id": {
|
||||
"end": 3,
|
||||
"name": "val",
|
||||
"start": 0,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"init": {
|
||||
"arguments": [
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "arg"
|
||||
},
|
||||
"arg": {
|
||||
"end": 29,
|
||||
"name": "x",
|
||||
"start": 28,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "LabeledArg",
|
||||
"label": {
|
||||
"type": "Identifier",
|
||||
"name": "bar"
|
||||
},
|
||||
"arg": {
|
||||
"end": 76,
|
||||
"name": "x",
|
||||
"start": 75,
|
||||
"type": "Identifier",
|
||||
"type": "Identifier"
|
||||
}
|
||||
}
|
||||
],
|
||||
"callee": {
|
||||
"end": 7,
|
||||
"name": "f",
|
||||
"start": 6,
|
||||
"type": "Identifier"
|
||||
},
|
||||
"end": 90,
|
||||
"nonCodeMeta": {
|
||||
"nonCodeNodes": {
|
||||
"1": [
|
||||
{
|
||||
"end": 55,
|
||||
"start": 44,
|
||||
"type": "NonCodeNode",
|
||||
"value": {
|
||||
"type": "blockComment",
|
||||
"value": "foo = x,",
|
||||
"style": "line"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"startNodes": []
|
||||
},
|
||||
"start": 6,
|
||||
"type": "CallExpressionKw",
|
||||
"type": "CallExpressionKw",
|
||||
"unlabeled": null
|
||||
},
|
||||
"start": 0,
|
||||
"type": "VariableDeclarator"
|
||||
},
|
||||
"end": 90,
|
||||
"kind": "const",
|
||||
"start": 0,
|
||||
"type": "VariableDeclaration",
|
||||
"type": "VariableDeclaration"
|
||||
}
|
||||
],
|
||||
"end": 90,
|
||||
"start": 0
|
||||
}
|
Reference in New Issue
Block a user