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
const code = `
const myVar = 5
const myFn = (a) => {
fn myFn = (a) => {
return a - 2
}
const otherVar = myFn(5)

View File

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

View File

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

View File

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

View File

@ -813,16 +813,16 @@ show(part001)"#,
#[tokio::test(flavor = "multi_thread")]
async fn test_execute_fn_definitions() {
let ast = r#"const def = (x) => {
let ast = r#"fn def = (x) => {
return x
}
const ghi = (x) => {
fn ghi = (x) => {
return x
}
const jkl = (x) => {
fn jkl = (x) => {
return x
}
const hmm = (x) => {
fn hmm = (x) => {
return x
}
@ -990,7 +990,7 @@ show(firstExtrude)"#;
#[tokio::test(flavor = "multi_thread")]
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])
|> line([0, l], %)
|> line([w, 0], %)
@ -1010,7 +1010,7 @@ show(fnBox)"#;
#[tokio::test(flavor = "multi_thread")]
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)
|> line([0, obj.l], %)
|> line([obj.w, 0], %)
@ -1030,7 +1030,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")]
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"])
|> line([0, obj["l"]], %)
|> line([obj["w"], 0], %)
@ -1050,7 +1050,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")]
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"])
|> line([0, obj["l"]], %)
|> line([obj["w"], 0], %)
@ -1071,7 +1071,7 @@ show(thisBox)
#[tokio::test(flavor = "multi_thread")]
#[ignore] // ignore til we get loops
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)
|> line([0, obj.l], %)
|> 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")]
#[ignore] // ignore til we get loops
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])
|> line([0, l], %)
|> 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")]
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])
|> line([0, array[1]], %)
|> line([array[2], 0], %)

View File

@ -1339,17 +1339,40 @@ impl Parser {
fn make_variable_declaration(&self, index: usize) -> Result<VariableDeclarationResult, KclError> {
let current_token = self.get_token(index)?;
let declaration_start_token = self.next_meaningful_token(index, None)?;
let variable_declarators_result = self.make_variable_declarators(declaration_start_token.index, vec![])?;
Ok(VariableDeclarationResult {
declaration: VariableDeclaration {
start: current_token.start,
end: variable_declarators_result.declarations[variable_declarators_result.declarations.len() - 1].end,
kind: VariableKind::from_str(&current_token.value).map_err(|_| {
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![])?;
// 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 {
declaration: VariableDeclaration {
start: current_token.start,
end: variable_declarators_result.declarations[variable_declarators_result.declarations.len() - 1].end,
kind,
declarations: variable_declarators_result.declarations,
},
last_index: variable_declarators_result.last_index,
@ -3291,4 +3314,44 @@ thing(false)
let parser = crate::parser::Parser::new(tokens);
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")]
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])
|> line([0, l], %)
|> line([w, 0], %)