fn required and can only be used for fn not var (#483)

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix javascript tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix clippy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2023-09-13 11:42:09 -07:00
committed by GitHub
parent d075c4ad13
commit 990605bbea
7 changed files with 86 additions and 23 deletions

View File

@ -10,7 +10,7 @@ describe('processMemory', () => {
// Enable rotations #152 // Enable rotations #152
const code = ` const code = `
const myVar = 5 const myVar = 5
const myFn = (a) => { fn myFn = (a) => {
return a - 2 return a - 2
} }
const otherVar = myFn(5) const otherVar = myFn(5)

View File

@ -176,7 +176,7 @@ show(part001)`
}) })
describe('Testing moveValueIntoNewVariable', () => { describe('Testing moveValueIntoNewVariable', () => {
const fn = (fnName: string) => `const ${fnName} = (x) => { const fn = (fnName: string) => `fn ${fnName} = (x) => {
return x return x
} }
` `

View File

@ -224,7 +224,7 @@ const key = 'c'
expect(recasted).toBe(code) expect(recasted).toBe(code)
}) })
it('comments in a fn block', () => { it('comments in a fn block', () => {
const code = `const myFn = () => { const code = `fn myFn = () => {
// this is a comment // this is a comment
const yo = { a: { b: { c: '123' } } } const yo = { a: { b: { c: '123' } } }

View File

@ -2283,7 +2283,7 @@ show(part001)
#[test] #[test]
fn test_recast_comment_in_a_fn_block() { fn test_recast_comment_in_a_fn_block() {
let some_program_string = r#"const myFn = () => { let some_program_string = r#"fn myFn = () => {
// this is a comment // this is a comment
const yo = { a: { b: { c: '123' } } } /* block const yo = { a: { b: { c: '123' } } } /* block
comment */ comment */
@ -2299,7 +2299,7 @@ show(part001)
let recasted = program.recast(&Default::default(), 0); let recasted = program.recast(&Default::default(), 0);
assert_eq!( assert_eq!(
recasted, recasted,
r#"const myFn = () => { r#"fn myFn = () => {
// this is a comment // this is a comment
const yo = { a: { b: { c: '123' } } } const yo = { a: { b: { c: '123' } } }
/* block /* block

View File

@ -813,16 +813,16 @@ show(part001)"#,
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_execute_fn_definitions() { async fn test_execute_fn_definitions() {
let ast = r#"const def = (x) => { let ast = r#"fn def = (x) => {
return x return x
} }
const ghi = (x) => { fn ghi = (x) => {
return x return x
} }
const jkl = (x) => { fn jkl = (x) => {
return x return x
} }
const hmm = (x) => { fn hmm = (x) => {
return x return x
} }
@ -990,7 +990,7 @@ show(firstExtrude)"#;
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_execute_with_function_sketch() { async fn test_execute_with_function_sketch() {
let ast = r#"const box = (h, l, w) => { let ast = r#"fn box = (h, l, w) => {
const myBox = startSketchAt([0,0]) const myBox = startSketchAt([0,0])
|> line([0, l], %) |> line([0, l], %)
|> line([w, 0], %) |> line([w, 0], %)
@ -1010,7 +1010,7 @@ show(fnBox)"#;
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_get_member_of_object_with_function_period() { async fn test_get_member_of_object_with_function_period() {
let ast = r#"const box = (obj) => { let ast = r#"fn box = (obj) => {
let myBox = startSketchAt(obj.start) let myBox = startSketchAt(obj.start)
|> line([0, obj.l], %) |> line([0, obj.l], %)
|> line([obj.w, 0], %) |> line([obj.w, 0], %)
@ -1030,7 +1030,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_get_member_of_object_with_function_brace() { async fn test_get_member_of_object_with_function_brace() {
let ast = r#"const box = (obj) => { let ast = r#"fn box = (obj) => {
let myBox = startSketchAt(obj["start"]) let myBox = startSketchAt(obj["start"])
|> line([0, obj["l"]], %) |> line([0, obj["l"]], %)
|> line([obj["w"], 0], %) |> line([obj["w"], 0], %)
@ -1050,7 +1050,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_get_member_of_object_with_function_mix_period_brace() { async fn test_get_member_of_object_with_function_mix_period_brace() {
let ast = r#"const box = (obj) => { let ast = r#"fn box = (obj) => {
let myBox = startSketchAt(obj["start"]) let myBox = startSketchAt(obj["start"])
|> line([0, obj["l"]], %) |> line([0, obj["l"]], %)
|> line([obj["w"], 0], %) |> line([obj["w"], 0], %)
@ -1071,7 +1071,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
#[ignore] // ignore til we get loops #[ignore] // ignore til we get loops
async fn test_execute_with_function_sketch_loop_objects() { async fn test_execute_with_function_sketch_loop_objects() {
let ast = r#"const box = (obj) => { let ast = r#"fn box = (obj) => {
let myBox = startSketchAt(obj.start) let myBox = startSketchAt(obj.start)
|> line([0, obj.l], %) |> line([0, obj.l], %)
|> line([obj.w, 0], %) |> line([obj.w, 0], %)
@ -1093,7 +1093,7 @@ for var in [{start: [0,0], l: 6, w: 10, h: 3}, {start: [-10,-10], l: 3, w: 5, h:
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
#[ignore] // ignore til we get loops #[ignore] // ignore til we get loops
async fn test_execute_with_function_sketch_loop_array() { async fn test_execute_with_function_sketch_loop_array() {
let ast = r#"const box = (h, l, w, start) => { let ast = r#"fn box = (h, l, w, start) => {
const myBox = startSketchAt([0,0]) const myBox = startSketchAt([0,0])
|> line([0, l], %) |> line([0, l], %)
|> line([w, 0], %) |> line([w, 0], %)
@ -1115,7 +1115,7 @@ for var in [[3, 6, 10, [0,0]], [1.5, 3, 5, [-10,-10]]] {
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_get_member_of_array_with_function() { async fn test_get_member_of_array_with_function() {
let ast = r#"const box = (array) => { let ast = r#"fn box = (array) => {
let myBox = startSketchAt(array[0]) let myBox = startSketchAt(array[0])
|> line([0, array[1]], %) |> line([0, array[1]], %)
|> line([array[2], 0], %) |> line([array[2], 0], %)

View File

@ -1339,17 +1339,40 @@ impl Parser {
fn make_variable_declaration(&self, index: usize) -> Result<VariableDeclarationResult, KclError> { fn make_variable_declaration(&self, index: usize) -> Result<VariableDeclarationResult, KclError> {
let current_token = self.get_token(index)?; let current_token = self.get_token(index)?;
let declaration_start_token = self.next_meaningful_token(index, None)?; let declaration_start_token = self.next_meaningful_token(index, None)?;
let kind = VariableKind::from_str(&current_token.value).map_err(|_| {
KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: format!("Unexpected token: {}", current_token.value),
})
})?;
let variable_declarators_result = self.make_variable_declarators(declaration_start_token.index, vec![])?; let variable_declarators_result = self.make_variable_declarators(declaration_start_token.index, vec![])?;
// Check if we have a fn variable kind but are not assigning a function.
if !variable_declarators_result.declarations.is_empty() {
if let Some(declarator) = variable_declarators_result.declarations.get(0) {
if let Value::FunctionExpression(_) = declarator.init {
if kind != VariableKind::Fn {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: format!("Expected a `fn` variable kind, found: `{}`", current_token.value),
}));
}
} else {
// If we have anything other than a function, make sure we are not using the `fn` variable kind.
if kind == VariableKind::Fn {
return Err(KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: format!("Expected a `let` variable kind, found: `{}`", current_token.value),
}));
}
}
}
}
Ok(VariableDeclarationResult { Ok(VariableDeclarationResult {
declaration: VariableDeclaration { declaration: VariableDeclaration {
start: current_token.start, start: current_token.start,
end: variable_declarators_result.declarations[variable_declarators_result.declarations.len() - 1].end, end: variable_declarators_result.declarations[variable_declarators_result.declarations.len() - 1].end,
kind: VariableKind::from_str(&current_token.value).map_err(|_| { kind,
KclError::Syntax(KclErrorDetails {
source_ranges: vec![current_token.into()],
message: format!("Unexpected token: {}", current_token.value),
})
})?,
declarations: variable_declarators_result.declarations, declarations: variable_declarators_result.declarations,
}, },
last_index: variable_declarators_result.last_index, last_index: variable_declarators_result.last_index,
@ -3291,4 +3314,44 @@ thing(false)
let parser = crate::parser::Parser::new(tokens); let parser = crate::parser::Parser::new(tokens);
parser.ast().unwrap(); parser.ast().unwrap();
} }
#[test]
fn test_error_define_function_as_var() {
for name in ["var", "let", "const"] {
let some_program_string = format!(
r#"{} thing = (param) => {{
return true
}}
thing(false)
"#,
name
);
let tokens = crate::tokeniser::lexer(&some_program_string);
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
format!(
r#"syntax: KclErrorDetails {{ source_ranges: [SourceRange([0, {}])], message: "Expected a `fn` variable kind, found: `{}`" }}"#,
name.len(),
name
)
);
}
}
#[test]
fn test_error_define_var_as_function() {
let some_program_string = r#"fn thing = "thing""#;
let tokens = crate::tokeniser::lexer(some_program_string);
let parser = crate::parser::Parser::new(tokens);
let result = parser.ast();
assert!(result.is_err());
assert_eq!(
result.err().unwrap().to_string(),
r#"syntax: KclErrorDetails { source_ranges: [SourceRange([0, 2])], message: "Expected a `let` variable kind, found: `fn`" }"#
);
}
} }

View File

@ -61,7 +61,7 @@ async fn execute_and_snapshot(code: &str) -> Result<image::DynamicImage> {
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn test_execute_with_function_sketch() { async fn test_execute_with_function_sketch() {
let code = r#"const box = (h, l, w) => { let code = r#"fn box = (h, l, w) => {
const myBox = startSketchAt([0,0]) const myBox = startSketchAt([0,0])
|> line([0, l], %) |> line([0, l], %)
|> line([w, 0], %) |> line([w, 0], %)