BREAKING: Change to disallow indexing KCL records/objects with strings (#6529)
* Change to disallow indexing records/objects with strings * Update output * Remove outdated sim test * Fix tests
This commit is contained in:
@ -861,8 +861,8 @@ impl Node<MemberExpression> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check the property and object match -- e.g. ints for arrays, strs for objects.
|
// Check the property and object match -- e.g. ints for arrays, strs for objects.
|
||||||
match (object, property) {
|
match (object, property, self.computed) {
|
||||||
(KclValue::Object { value: map, meta: _ }, Property::String(property)) => {
|
(KclValue::Object { value: map, meta: _ }, Property::String(property), false) => {
|
||||||
if let Some(value) = map.get(&property) {
|
if let Some(value) = map.get(&property) {
|
||||||
Ok(value.to_owned())
|
Ok(value.to_owned())
|
||||||
} else {
|
} else {
|
||||||
@ -872,7 +872,11 @@ impl Node<MemberExpression> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(KclValue::Object { .. }, p) => {
|
(KclValue::Object { .. }, Property::String(property), true) => Err(KclError::Semantic(KclErrorDetails {
|
||||||
|
message: format!("Cannot index object with string; use dot notation instead, e.g. `obj.{property}`"),
|
||||||
|
source_ranges: vec![self.clone().into()],
|
||||||
|
})),
|
||||||
|
(KclValue::Object { .. }, p, _) => {
|
||||||
let t = p.type_name();
|
let t = p.type_name();
|
||||||
let article = article_for(t);
|
let article = article_for(t);
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -885,6 +889,7 @@ impl Node<MemberExpression> {
|
|||||||
(
|
(
|
||||||
KclValue::MixedArray { value: arr, .. } | KclValue::HomArray { value: arr, .. },
|
KclValue::MixedArray { value: arr, .. } | KclValue::HomArray { value: arr, .. },
|
||||||
Property::UInt(index),
|
Property::UInt(index),
|
||||||
|
_,
|
||||||
) => {
|
) => {
|
||||||
let value_of_arr = arr.get(index);
|
let value_of_arr = arr.get(index);
|
||||||
if let Some(value) = value_of_arr {
|
if let Some(value) = value_of_arr {
|
||||||
@ -896,7 +901,7 @@ impl Node<MemberExpression> {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(KclValue::MixedArray { .. } | KclValue::HomArray { .. }, p) => {
|
(KclValue::MixedArray { .. } | KclValue::HomArray { .. }, p, _) => {
|
||||||
let t = p.type_name();
|
let t = p.type_name();
|
||||||
let article = article_for(t);
|
let article = article_for(t);
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -906,10 +911,10 @@ impl Node<MemberExpression> {
|
|||||||
source_ranges: vec![self.clone().into()],
|
source_ranges: vec![self.clone().into()],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
(KclValue::Solid { value }, Property::String(prop)) if prop == "sketch" => Ok(KclValue::Sketch {
|
(KclValue::Solid { value }, Property::String(prop), false) if prop == "sketch" => Ok(KclValue::Sketch {
|
||||||
value: Box::new(value.sketch),
|
value: Box::new(value.sketch),
|
||||||
}),
|
}),
|
||||||
(KclValue::Sketch { value: sk }, Property::String(prop)) if prop == "tags" => Ok(KclValue::Object {
|
(KclValue::Sketch { value: sk }, Property::String(prop), false) if prop == "tags" => Ok(KclValue::Object {
|
||||||
meta: vec![Metadata {
|
meta: vec![Metadata {
|
||||||
source_range: SourceRange::from(self.clone()),
|
source_range: SourceRange::from(self.clone()),
|
||||||
}],
|
}],
|
||||||
@ -919,7 +924,7 @@ impl Node<MemberExpression> {
|
|||||||
.map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
|
.map(|(k, tag)| (k.to_owned(), KclValue::TagIdentifier(Box::new(tag.to_owned()))))
|
||||||
.collect(),
|
.collect(),
|
||||||
}),
|
}),
|
||||||
(being_indexed, _) => {
|
(being_indexed, _, _) => {
|
||||||
let t = being_indexed.human_friendly_type();
|
let t = being_indexed.human_friendly_type();
|
||||||
let article = article_for(t);
|
let article = article_for(t);
|
||||||
Err(KclError::Semantic(KclErrorDetails {
|
Err(KclError::Semantic(KclErrorDetails {
|
||||||
@ -1919,10 +1924,11 @@ impl Property {
|
|||||||
LiteralIdentifier::Identifier(identifier) => {
|
LiteralIdentifier::Identifier(identifier) => {
|
||||||
let name = &identifier.name;
|
let name = &identifier.name;
|
||||||
if !computed {
|
if !computed {
|
||||||
// Treat the property as a literal
|
// This is dot syntax. Treat the property as a literal.
|
||||||
Ok(Property::String(name.to_string()))
|
Ok(Property::String(name.to_string()))
|
||||||
} else {
|
} else {
|
||||||
// Actually evaluate memory to compute the property.
|
// This is bracket syntax. Actually evaluate memory to
|
||||||
|
// compute the property.
|
||||||
let prop = exec_state.stack().get(name, property_src)?;
|
let prop = exec_state.stack().get(name, property_src)?;
|
||||||
jvalue_to_prop(prop, property_sr, name)
|
jvalue_to_prop(prop, property_sr, name)
|
||||||
}
|
}
|
||||||
@ -1940,10 +1946,9 @@ impl Property {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LiteralValue::String(s) => Ok(Property::String(s)),
|
|
||||||
_ => Err(KclError::Semantic(KclErrorDetails {
|
_ => Err(KclError::Semantic(KclErrorDetails {
|
||||||
source_ranges: vec![sr],
|
source_ranges: vec![sr],
|
||||||
message: "Only strings or numbers (>= 0) can be properties/indexes".to_owned(),
|
message: "Only numbers (>= 0) can be indexes".to_owned(),
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1515,44 +1515,6 @@ const fnBox = box(3, 6, 10)"#;
|
|||||||
return myBox
|
return myBox
|
||||||
}
|
}
|
||||||
|
|
||||||
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
|
||||||
"#;
|
|
||||||
parse_execute(ast).await.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
|
||||||
async fn test_get_member_of_object_with_function_brace() {
|
|
||||||
let ast = r#"fn box = (obj) => {
|
|
||||||
let myBox = startSketchOn(XY)
|
|
||||||
|> startProfile(at = obj["start"])
|
|
||||||
|> line(end = [0, obj["l"]])
|
|
||||||
|> line(end = [obj["w"], 0])
|
|
||||||
|> line(end = [0, -obj["l"]])
|
|
||||||
|> close()
|
|
||||||
|> extrude(length = obj["h"])
|
|
||||||
|
|
||||||
return myBox
|
|
||||||
}
|
|
||||||
|
|
||||||
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
|
||||||
"#;
|
|
||||||
parse_execute(ast).await.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
|
||||||
async fn test_get_member_of_object_with_function_mix_period_brace() {
|
|
||||||
let ast = r#"fn box = (obj) => {
|
|
||||||
let myBox = startSketchOn(XY)
|
|
||||||
|> startProfile(at = obj["start"])
|
|
||||||
|> line(end = [0, obj["l"]])
|
|
||||||
|> line(end = [obj["w"], 0])
|
|
||||||
|> line(end = [10 - obj["w"], -obj.l])
|
|
||||||
|> close()
|
|
||||||
|> extrude(length = obj["h"])
|
|
||||||
|
|
||||||
return myBox
|
|
||||||
}
|
|
||||||
|
|
||||||
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
const thisBox = box({start: [0,0], l: 6, w: 10, h: 3})
|
||||||
"#;
|
"#;
|
||||||
parse_execute(ast).await.unwrap();
|
parse_execute(ast).await.unwrap();
|
||||||
|
@ -1310,6 +1310,7 @@ fn member_expression_dot(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usiz
|
|||||||
/// E.g. `people[0]` or `people[i]` or `people['adam']`
|
/// E.g. `people[0]` or `people[i]` or `people['adam']`
|
||||||
fn member_expression_subscript(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usize, bool)> {
|
fn member_expression_subscript(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usize, bool)> {
|
||||||
let _ = open_bracket.parse_next(i)?;
|
let _ = open_bracket.parse_next(i)?;
|
||||||
|
// TODO: This should be an expression, not just a literal or identifier.
|
||||||
let property = alt((
|
let property = alt((
|
||||||
literal.map(LiteralIdentifier::Literal),
|
literal.map(LiteralIdentifier::Literal),
|
||||||
nameable_identifier.map(Box::new).map(LiteralIdentifier::Identifier),
|
nameable_identifier.map(Box::new).map(LiteralIdentifier::Identifier),
|
||||||
|
@ -498,27 +498,6 @@ mod double_map_fn {
|
|||||||
super::execute(TEST_NAME, false).await
|
super::execute(TEST_NAME, false).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod property_of_object {
|
|
||||||
const TEST_NAME: &str = "property_of_object";
|
|
||||||
|
|
||||||
/// Test parsing KCL.
|
|
||||||
#[test]
|
|
||||||
fn parse() {
|
|
||||||
super::parse(TEST_NAME)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test that parsing and unparsing KCL produces the original KCL input.
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
|
||||||
async fn unparse() {
|
|
||||||
super::unparse(TEST_NAME).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test that KCL is executed correctly.
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
|
||||||
async fn kcl_test_execute() {
|
|
||||||
super::execute(TEST_NAME, false).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mod index_of_array {
|
mod index_of_array {
|
||||||
const TEST_NAME: &str = "index_of_array";
|
const TEST_NAME: &str = "index_of_array";
|
||||||
|
|
||||||
@ -816,6 +795,27 @@ mod invalid_member_object_prop {
|
|||||||
super::execute(TEST_NAME, false).await
|
super::execute(TEST_NAME, false).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mod invalid_member_object_using_string {
|
||||||
|
const TEST_NAME: &str = "invalid_member_object_using_string";
|
||||||
|
|
||||||
|
/// Test parsing KCL.
|
||||||
|
#[test]
|
||||||
|
fn parse() {
|
||||||
|
super::parse(TEST_NAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test that parsing and unparsing KCL produces the original KCL input.
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn unparse() {
|
||||||
|
super::unparse(TEST_NAME).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test that KCL is executed correctly.
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn kcl_test_execute() {
|
||||||
|
super::execute(TEST_NAME, false).await
|
||||||
|
}
|
||||||
|
}
|
||||||
mod non_string_key_of_object {
|
mod non_string_key_of_object {
|
||||||
const TEST_NAME: &str = "non_string_key_of_object";
|
const TEST_NAME: &str = "non_string_key_of_object";
|
||||||
|
|
||||||
|
@ -249,36 +249,6 @@ description: Result of parsing computed_var.kcl
|
|||||||
"type": "ExpressionStatement",
|
"type": "ExpressionStatement",
|
||||||
"type": "ExpressionStatement"
|
"type": "ExpressionStatement"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"commentStart": 0,
|
|
||||||
"declaration": {
|
|
||||||
"commentStart": 0,
|
|
||||||
"end": 0,
|
|
||||||
"id": {
|
|
||||||
"commentStart": 0,
|
|
||||||
"end": 0,
|
|
||||||
"name": "p",
|
|
||||||
"start": 0,
|
|
||||||
"type": "Identifier"
|
|
||||||
},
|
|
||||||
"init": {
|
|
||||||
"commentStart": 0,
|
|
||||||
"end": 0,
|
|
||||||
"raw": "\"foo\"",
|
|
||||||
"start": 0,
|
|
||||||
"type": "Literal",
|
|
||||||
"type": "Literal",
|
|
||||||
"value": "foo"
|
|
||||||
},
|
|
||||||
"start": 0,
|
|
||||||
"type": "VariableDeclarator"
|
|
||||||
},
|
|
||||||
"end": 0,
|
|
||||||
"kind": "const",
|
|
||||||
"start": 0,
|
|
||||||
"type": "VariableDeclaration",
|
|
||||||
"type": "VariableDeclaration"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"commentStart": 0,
|
"commentStart": 0,
|
||||||
"declaration": {
|
"declaration": {
|
||||||
@ -373,7 +343,7 @@ description: Result of parsing computed_var.kcl
|
|||||||
},
|
},
|
||||||
"init": {
|
"init": {
|
||||||
"commentStart": 0,
|
"commentStart": 0,
|
||||||
"computed": true,
|
"computed": false,
|
||||||
"end": 0,
|
"end": 0,
|
||||||
"object": {
|
"object": {
|
||||||
"commentStart": 0,
|
"commentStart": 0,
|
||||||
@ -386,7 +356,7 @@ description: Result of parsing computed_var.kcl
|
|||||||
"property": {
|
"property": {
|
||||||
"commentStart": 0,
|
"commentStart": 0,
|
||||||
"end": 0,
|
"end": 0,
|
||||||
"name": "p",
|
"name": "foo",
|
||||||
"start": 0,
|
"start": 0,
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"type": "Identifier"
|
"type": "Identifier"
|
||||||
@ -820,6 +790,17 @@ description: Result of parsing computed_var.kcl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"5": [
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"start": 0,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "newLine"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"6": [
|
"6": [
|
||||||
{
|
{
|
||||||
"commentStart": 0,
|
"commentStart": 0,
|
||||||
@ -841,17 +822,6 @@ description: Result of parsing computed_var.kcl
|
|||||||
"type": "newLine"
|
"type": "newLine"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"8": [
|
|
||||||
{
|
|
||||||
"commentStart": 0,
|
|
||||||
"end": 0,
|
|
||||||
"start": 0,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "newLine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"startNodes": [
|
"startNodes": [
|
||||||
|
@ -7,9 +7,8 @@ ten = arr[i]
|
|||||||
|
|
||||||
assert(ten, isEqualTo = 10, error = "oops")
|
assert(ten, isEqualTo = 10, error = "oops")
|
||||||
|
|
||||||
p = "foo"
|
|
||||||
obj = { foo = 1, bar = 0 }
|
obj = { foo = 1, bar = 0 }
|
||||||
one = obj[p]
|
one = obj.foo
|
||||||
|
|
||||||
assert(one, isEqualTo = 1, error = "oops")
|
assert(one, isEqualTo = 1, error = "oops")
|
||||||
|
|
||||||
|
@ -117,10 +117,6 @@ description: Variables in memory after executing computed_var.kcl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"p": {
|
|
||||||
"type": "String",
|
|
||||||
"value": "foo"
|
|
||||||
},
|
|
||||||
"ten": {
|
"ten": {
|
||||||
"type": "Number",
|
"type": "Number",
|
||||||
"value": 10.0,
|
"value": 10.0,
|
||||||
|
@ -11,9 +11,8 @@ ten = arr[i]
|
|||||||
|
|
||||||
assert(ten, isEqualTo = 10, error = "oops")
|
assert(ten, isEqualTo = 10, error = "oops")
|
||||||
|
|
||||||
p = "foo"
|
|
||||||
obj = { foo = 1, bar = 0 }
|
obj = { foo = 1, bar = 0 }
|
||||||
one = obj[p]
|
one = obj.foo
|
||||||
|
|
||||||
assert(one, isEqualTo = 1, error = "oops")
|
assert(one, isEqualTo = 1, error = "oops")
|
||||||
|
|
||||||
|
@ -4,8 +4,7 @@ description: Error from executing invalid_index_str.kcl
|
|||||||
---
|
---
|
||||||
KCL Semantic error
|
KCL Semantic error
|
||||||
|
|
||||||
× semantic: Only integers >= 0 can be used as the index of an array, but
|
× semantic: Only numbers (>= 0) can be indexes
|
||||||
│ you're using a string
|
|
||||||
╭─[2:5]
|
╭─[2:5]
|
||||||
1 │ arr = [1, 2, 3]
|
1 │ arr = [1, 2, 3]
|
||||||
2 │ x = arr["s"]
|
2 │ x = arr["s"]
|
||||||
|
@ -4,8 +4,7 @@ description: Error from executing invalid_member_object_prop.kcl
|
|||||||
---
|
---
|
||||||
KCL Semantic error
|
KCL Semantic error
|
||||||
|
|
||||||
× semantic: Only arrays and objects can be indexed, but you're trying to
|
× semantic: Only numbers (>= 0) can be indexes
|
||||||
│ index a boolean (true/false value)
|
|
||||||
╭─[2:5]
|
╭─[2:5]
|
||||||
1 │ b = true
|
1 │ b = true
|
||||||
2 │ x = b["property"]
|
2 │ x = b["property"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: kcl-lib/src/simulation_tests.rs
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
description: Artifact commands property_of_object.kcl
|
description: Artifact commands invalid_member_object_using_string.kcl
|
||||||
---
|
---
|
||||||
[
|
[
|
||||||
{
|
{
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
|
description: Artifact graph flowchart invalid_member_object_using_string.kcl
|
||||||
|
extension: md
|
||||||
|
snapshot_kind: binary
|
||||||
|
---
|
196
rust/kcl-lib/tests/invalid_member_object_using_string/ast.snap
Normal file
196
rust/kcl-lib/tests/invalid_member_object_using_string/ast.snap
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
|
description: Result of parsing invalid_member_object_using_string.kcl
|
||||||
|
---
|
||||||
|
{
|
||||||
|
"Ok": {
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"declaration": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"id": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "p",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"raw": "\"foo\"",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": "foo"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
},
|
||||||
|
"end": 0,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"declaration": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"id": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "obj",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"key": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "foo",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"value": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"raw": "1",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 1.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"key": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "bar",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"value": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"raw": "0",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Literal",
|
||||||
|
"type": "Literal",
|
||||||
|
"value": {
|
||||||
|
"value": 0.0,
|
||||||
|
"suffix": "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start": 0,
|
||||||
|
"type": "ObjectExpression",
|
||||||
|
"type": "ObjectExpression"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
},
|
||||||
|
"end": 0,
|
||||||
|
"kind": "const",
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"declaration": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"id": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "one",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"computed": true,
|
||||||
|
"end": 0,
|
||||||
|
"object": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "obj",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"property": {
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"name": "p",
|
||||||
|
"start": 0,
|
||||||
|
"type": "Identifier",
|
||||||
|
"type": "Identifier"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "MemberExpression",
|
||||||
|
"type": "MemberExpression"
|
||||||
|
},
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclarator"
|
||||||
|
},
|
||||||
|
"end": 0,
|
||||||
|
"kind": "const",
|
||||||
|
"preComments": [
|
||||||
|
"// Try to index with a string."
|
||||||
|
],
|
||||||
|
"start": 0,
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"type": "VariableDeclaration"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"nonCodeMeta": {
|
||||||
|
"nonCodeNodes": {},
|
||||||
|
"startNodes": [
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"start": 0,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "blockComment",
|
||||||
|
"value": "This tests computed properties.",
|
||||||
|
"style": "line"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commentStart": 0,
|
||||||
|
"end": 0,
|
||||||
|
"start": 0,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "newLine"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"start": 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
|
description: Error from executing invalid_member_object_using_string.kcl
|
||||||
|
---
|
||||||
|
KCL Semantic error
|
||||||
|
|
||||||
|
× semantic: Cannot index object with string; use dot notation instead, e.g.
|
||||||
|
│ `obj.foo`
|
||||||
|
╭─[6:7]
|
||||||
|
5 │ // Try to index with a string.
|
||||||
|
6 │ one = obj[p]
|
||||||
|
· ───┬──
|
||||||
|
· ╰── tests/invalid_member_object_using_string/input.kcl
|
||||||
|
╰────
|
@ -0,0 +1,6 @@
|
|||||||
|
// This tests computed properties.
|
||||||
|
|
||||||
|
p = "foo"
|
||||||
|
obj = { foo = 1, bar = 0 }
|
||||||
|
// Try to index with a string.
|
||||||
|
one = obj[p]
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
|
description: Operations executed invalid_member_object_using_string.kcl
|
||||||
|
---
|
||||||
|
[]
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
|
description: Result of unparsing invalid_member_object_using_string.kcl
|
||||||
|
---
|
||||||
|
// This tests computed properties.
|
||||||
|
|
||||||
|
|
||||||
|
p = "foo"
|
||||||
|
obj = { foo = 1, bar = 0 }
|
||||||
|
// Try to index with a string.
|
||||||
|
one = obj[p]
|
@ -2,9 +2,9 @@
|
|||||||
source: kcl-lib/src/simulation_tests.rs
|
source: kcl-lib/src/simulation_tests.rs
|
||||||
description: Error from executing object_prop_not_found.kcl
|
description: Error from executing object_prop_not_found.kcl
|
||||||
---
|
---
|
||||||
KCL UndefinedValue error
|
KCL Semantic error
|
||||||
|
|
||||||
× undefined value: Property 'age' not found in object
|
× semantic: Only numbers (>= 0) can be indexes
|
||||||
╭─[2:5]
|
╭─[2:5]
|
||||||
1 │ obj = { }
|
1 │ obj = { }
|
||||||
2 │ k = obj["age"]
|
2 │ k = obj["age"]
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
source: kcl/src/simulation_tests.rs
|
|
||||||
description: Artifact graph flowchart property_of_object.kcl
|
|
||||||
extension: md
|
|
||||||
snapshot_kind: binary
|
|
||||||
---
|
|
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
|||||||
// This tests evaluating properties of objects.
|
|
||||||
|
|
||||||
|
|
||||||
obj = { foo = 1, bar = 0 }
|
|
||||||
|
|
||||||
// Test: the property is a literal.
|
|
||||||
|
|
||||||
|
|
||||||
one_a = obj["foo"]
|
|
||||||
|
|
||||||
assert(one_a, isLessThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
assert(one_a, isGreaterThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
|
|
||||||
// Test: the property is a variable,
|
|
||||||
// which must be evaluated before looking it up.
|
|
||||||
|
|
||||||
|
|
||||||
p = "foo"
|
|
||||||
one_b = obj[p]
|
|
||||||
|
|
||||||
assert(one_b, isLessThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
assert(one_b, isGreaterThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
|
|
||||||
// Test: multiple literal properties.
|
|
||||||
|
|
||||||
|
|
||||||
obj2 = { inner = obj }
|
|
||||||
|
|
||||||
one_c = obj2.inner["foo"]
|
|
||||||
|
|
||||||
assert(one_c, isLessThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
assert(one_c, isGreaterThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
|
|
||||||
// Test: multiple properties, mix of literal and computed.
|
|
||||||
|
|
||||||
|
|
||||||
one_d = obj2.inner[p]
|
|
||||||
|
|
||||||
assert(one_d, isLessThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
assert(one_d, isGreaterThanOrEqual = 1, error = "Computed property lookup")
|
|
@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
source: kcl/src/simulation_tests.rs
|
|
||||||
description: Operations executed property_of_object.kcl
|
|
||||||
---
|
|
||||||
[]
|
|
@ -1,129 +0,0 @@
|
|||||||
---
|
|
||||||
source: kcl-lib/src/simulation_tests.rs
|
|
||||||
description: Variables in memory after executing property_of_object.kcl
|
|
||||||
---
|
|
||||||
{
|
|
||||||
"obj": {
|
|
||||||
"type": "Object",
|
|
||||||
"value": {
|
|
||||||
"bar": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 0.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"foo": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"obj2": {
|
|
||||||
"type": "Object",
|
|
||||||
"value": {
|
|
||||||
"inner": {
|
|
||||||
"type": "Object",
|
|
||||||
"value": {
|
|
||||||
"bar": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 0.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"foo": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"one_a": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"one_b": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"one_c": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"one_d": {
|
|
||||||
"type": "Number",
|
|
||||||
"value": 1.0,
|
|
||||||
"ty": {
|
|
||||||
"type": "Default",
|
|
||||||
"len": {
|
|
||||||
"type": "Mm"
|
|
||||||
},
|
|
||||||
"angle": {
|
|
||||||
"type": "Degrees"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"p": {
|
|
||||||
"type": "String",
|
|
||||||
"value": "foo"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
---
|
|
||||||
source: kcl-lib/src/simulation_tests.rs
|
|
||||||
description: Result of unparsing property_of_object.kcl
|
|
||||||
---
|
|
||||||
// This tests evaluating properties of objects.
|
|
||||||
|
|
||||||
|
|
||||||
obj = { foo = 1, bar = 0 }
|
|
||||||
|
|
||||||
// Test: the property is a literal.
|
|
||||||
|
|
||||||
|
|
||||||
one_a = obj["foo"]
|
|
||||||
|
|
||||||
assert(one_a, isLessThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
assert(one_a, isGreaterThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
|
|
||||||
// Test: the property is a variable,
|
|
||||||
// which must be evaluated before looking it up.
|
|
||||||
|
|
||||||
|
|
||||||
p = "foo"
|
|
||||||
one_b = obj[p]
|
|
||||||
|
|
||||||
assert(one_b, isLessThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
assert(one_b, isGreaterThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
|
|
||||||
// Test: multiple literal properties.
|
|
||||||
|
|
||||||
|
|
||||||
obj2 = { inner = obj }
|
|
||||||
|
|
||||||
one_c = obj2.inner["foo"]
|
|
||||||
|
|
||||||
assert(one_c, isLessThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
assert(one_c, isGreaterThanOrEqual = 1, error = "Literal property lookup")
|
|
||||||
|
|
||||||
// Test: multiple properties, mix of literal and computed.
|
|
||||||
|
|
||||||
|
|
||||||
one_d = obj2.inner[p]
|
|
||||||
|
|
||||||
assert(one_d, isLessThanOrEqual = 1, error = "Computed property lookup")
|
|
||||||
assert(one_d, isGreaterThanOrEqual = 1, error = "Computed property lookup")
|
|
@ -293,7 +293,7 @@ const newVar = myVar + 1`
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
it('execute memberExpression', async () => {
|
it('execute memberExpression', async () => {
|
||||||
const code = ["const yo = {a: {b: '123'}}", "const myVar = yo.a['b']"].join(
|
const code = ["const yo = {a: {b: '123'}}", 'const myVar = yo.a.b'].join(
|
||||||
'\n'
|
'\n'
|
||||||
)
|
)
|
||||||
const mem = await exe(code)
|
const mem = await exe(code)
|
||||||
|
Reference in New Issue
Block a user