Run external contributor branch through CI (#4679)

* fix: make variable declaration errors Cut instead of Backtrace

* fix: clippy, move comma to empty case and add test

* fix: add missing TokenType case

* fix: incorrect fn args after merge

* fix: clippy lint

* fix: update error message being looked for in e2e test

---------

Co-authored-by: Tom Pridham <pridham.tom@gmail.com>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
Adam Chalmers
2024-12-06 13:12:20 -06:00
committed by GitHub
parent 30d365aeb3
commit 88b51da417
2 changed files with 160 additions and 23 deletions

View File

@ -458,8 +458,8 @@ test.describe('Editor tests', () => {
/* add the following code to the editor ($ error is not a valid line)
$ error
const topAng = 30
const bottomAng = 25
topAng = 30
bottomAng = 25
*/
await u.codeLocator.click()
await page.keyboard.type('$ error')
@ -474,12 +474,14 @@ test.describe('Editor tests', () => {
await page.keyboard.type('bottomAng = 25')
await page.keyboard.press('Enter')
// error in guter
// error in gutter
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token: $').first()).toBeVisible()
await expect(
page.getByText('Tag names must not be empty').first()
).toBeVisible()
// select the line that's causing the error and delete it
await page.getByText('$ error').click()

View File

@ -1855,22 +1855,59 @@ impl TryFrom<Token> for Node<TagDeclarator> {
type Error = CompilationError;
fn try_from(token: Token) -> Result<Self, Self::Error> {
if token.token_type == TokenType::Word {
Ok(Node::new(
TagDeclarator {
// We subtract 1 from the start because the tag starts with a `$`.
name: token.value,
digest: None,
},
token.start - 1,
token.end,
token.module_id,
))
} else {
Err(CompilationError::fatal(
match token.token_type {
TokenType::Word => {
Ok(Node::new(
TagDeclarator {
// We subtract 1 from the start because the tag starts with a `$`.
name: token.value,
digest: None,
},
token.start - 1,
token.end,
token.module_id,
))
}
TokenType::Number => Err(CompilationError::fatal(
token.as_source_range(),
format!(
"Tag names must not start with a number. Tag starts with `{}`",
token.value.as_str()
),
)),
// e.g. `line(%, $)` or `line(%, $ , 5)`
TokenType::Brace | TokenType::Whitespace | TokenType::Comma => Err(CompilationError::fatal(
token.as_source_range(),
"Tag names must not be empty".to_string(),
)),
TokenType::Type => Err(CompilationError::fatal(
token.as_source_range(),
format!("Cannot assign a tag to a reserved keyword: {}", token.value.as_str()),
))
)),
TokenType::Bang
| TokenType::At
| TokenType::Hash
| TokenType::Colon
| TokenType::Period
| TokenType::Operator
| TokenType::DoublePeriod
| TokenType::QuestionMark
| TokenType::BlockComment
| TokenType::Function
| TokenType::String
| TokenType::Dollar
| TokenType::Keyword
| TokenType::Unknown
| TokenType::LineComment => Err(CompilationError::fatal(
token.as_source_range(),
// this is `start with` because if most of these cases are in the middle, it ends
// up hitting a different error path(e.g. including a bang) or being valid(e.g. including a comment) since it will get broken up into
// multiple tokens
format!("Tag names must not start with a {}", token.token_type),
)),
}
}
}
@ -1894,7 +1931,8 @@ fn tag(i: TokenSlice) -> PResult<Node<TagDeclarator>> {
let tag_declarator = any
.try_map(Node::<TagDeclarator>::try_from)
.context(expected("a tag, e.g. '$seg01' or '$line01'"))
.parse_next(i)?;
.parse_next(i)
.map_err(|e| e.cut())?;
// Now that we've parsed a tag declarator, verify that it's not a stdlib
// name. If it is, stop backtracking.
tag_declarator
@ -2372,6 +2410,7 @@ fn fn_call(i: TokenSlice) -> PResult<Node<CallExpression>> {
opt(whitespace).parse_next(i)?;
let _ = terminated(open_paren, opt(whitespace)).parse_next(i)?;
let args = arguments(i)?;
if let Some(std_fn) = crate::std::get_stdlib_fn(&fn_name.name) {
let just_args: Vec<_> = args.iter().collect();
typecheck_all(std_fn, &just_args)?;
@ -4035,12 +4074,108 @@ let myBox = box([0,0], -3, -16, -10)
}
#[test]
fn test_parse_empty_tag() {
fn test_parse_empty_tag_brace() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([5, 5], %, $)
"#;
assert_err(some_program_string, "Unexpected token: |>", [57, 59]);
|> line(%, $)
"#;
assert_err(some_program_string, "Tag names must not be empty", [69, 70]);
}
#[test]
fn test_parse_empty_tag_whitespace() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $ ,01)
"#;
assert_err(some_program_string, "Tag names must not be empty", [69, 70]);
}
#[test]
fn test_parse_empty_tag_comma() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $,)
"#;
assert_err(some_program_string, "Tag names must not be empty", [69, 70]);
}
#[test]
fn test_parse_tag_starting_with_digit() {
let some_program_string = r#"
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $01)"#;
assert_err(
some_program_string,
"Tag names must not start with a number. Tag starts with `01`",
[74, 76],
);
}
#[test]
fn test_parse_tag_including_digit() {
let some_program_string = r#"
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $var01)"#;
assert_no_err(some_program_string);
}
#[test]
fn test_parse_tag_starting_with_bang() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $!var,01)
"#;
assert_err(some_program_string, "Tag names must not start with a bang", [69, 70]);
}
#[test]
fn test_parse_tag_starting_with_dollar() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $$,01)
"#;
assert_err(some_program_string, "Tag names must not start with a dollar", [69, 70]);
}
#[test]
fn test_parse_tag_starting_with_fn() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $fn,01)
"#;
assert_err(some_program_string, "Tag names must not start with a keyword", [69, 71]);
}
#[test]
fn test_parse_tag_starting_with_a_comment() {
let some_program_string = r#"startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line(%, $//
,01)
"#;
assert_err(
some_program_string,
"Tag names must not start with a lineComment",
[69, 71],
);
}
#[test]
fn test_parse_tag_starting_with_reserved_type() {
let some_program_string = r#"
startSketchOn('XY')
|> line(%, $sketch)
"#;
assert_err(
some_program_string,
"Cannot assign a tag to a reserved keyword: sketch",
[41, 47],
);
}
#[test]
fn test_parse_tag_with_reserved_in_middle_works() {
let some_program_string = r#"
startSketchOn('XY')
|> startProfileAt([0, 0], %)
|> line([5, 5], %, $sketching)
"#;
assert_no_err(some_program_string);
}
#[test]