Support types in the standard library (#5651)

* Parse an unparse type decls (and refactor impl attributes slightly)

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Remove special treatment of geometric types from parser and executor

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Generate docs for std types

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Hover tool-tips for types and fixup the frontend

Signed-off-by: Nick Cameron <nrc@ncameron.org>

* Fixes

Signed-off-by: Nick Cameron <nrc@ncameron.org>

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-03-08 03:53:34 +13:00
committed by GitHub
parent 79d37d360a
commit 5d25f4a0e5
175 changed files with 2023 additions and 1647 deletions

View File

@ -5,8 +5,8 @@ use crate::parsing::ast::types::{
CallExpression, CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression,
Identifier, IfExpression, ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression,
Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, ObjectExpression, ObjectProperty,
Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, TagDeclarator, Type, UnaryExpression,
VariableDeclaration, VariableDeclarator, VariableKind,
Parameter, PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, TagDeclarator, Type,
TypeDeclaration, UnaryExpression, VariableDeclaration, VariableDeclarator, VariableKind,
};
/// Position-independent digest of the AST node.
@ -113,6 +113,7 @@ impl BodyItem {
BodyItem::ImportStatement(s) => s.compute_digest(),
BodyItem::ExpressionStatement(es) => es.compute_digest(),
BodyItem::VariableDeclaration(vs) => vs.compute_digest(),
BodyItem::TypeDeclaration(t) => t.compute_digest(),
BodyItem::ReturnStatement(rs) => rs.compute_digest(),
});
@ -191,11 +192,11 @@ impl Type {
match self {
Type::Primitive(prim) => {
hasher.update(b"FnArgType::Primitive");
hasher.update(prim.digestable_id())
hasher.update(prim.compute_digest())
}
Type::Array(prim) => {
hasher.update(b"FnArgType::Array");
hasher.update(prim.digestable_id())
hasher.update(prim.compute_digest())
}
Type::Object { properties } => {
hasher.update(b"FnArgType::Object");
@ -210,6 +211,21 @@ impl Type {
}
}
impl PrimitiveType {
pub fn compute_digest(&mut self) -> Digest {
let mut hasher = Sha256::new();
match self {
PrimitiveType::Named(id) => hasher.update(id.compute_digest()),
PrimitiveType::String => hasher.update(b"string"),
PrimitiveType::Number(suffix) => hasher.update(suffix.digestable_id()),
PrimitiveType::Boolean => hasher.update(b"bool"),
PrimitiveType::Tag => hasher.update(b"tag"),
}
hasher.finalize().into()
}
}
impl Parameter {
compute_digest!(|slf, hasher| {
hasher.update(slf.identifier.compute_digest());
@ -275,6 +291,18 @@ impl VariableDeclaration {
});
}
impl TypeDeclaration {
compute_digest!(|slf, hasher| {
hasher.update(slf.name.compute_digest());
if let Some(args) = &mut slf.args {
hasher.update([1]);
for a in args {
hasher.update(a.compute_digest());
}
}
});
}
impl VariableKind {
fn digestable_id(&self) -> [u8; 1] {
match self {

View File

@ -13,6 +13,7 @@ impl BodyItem {
BodyItem::ImportStatement(stmt) => stmt.module_id,
BodyItem::ExpressionStatement(expression_statement) => expression_statement.module_id,
BodyItem::VariableDeclaration(variable_declaration) => variable_declaration.module_id,
BodyItem::TypeDeclaration(ty_declaration) => ty_declaration.module_id,
BodyItem::ReturnStatement(return_statement) => return_statement.module_id,
}
}

View File

@ -55,6 +55,9 @@ pub async fn modify_ast_for_sketch(
let constraint_level = match ast_sketch {
super::types::Definition::Variable(var) => var.get_constraint_level(),
super::types::Definition::Import(import) => import.get_constraint_level(),
super::types::Definition::Type(_) => ConstraintLevel::Ignore {
source_ranges: Vec::new(),
},
};
match &constraint_level {
ConstraintLevel::None { source_ranges: _ } => {}

View File

@ -38,6 +38,7 @@ mod none;
pub enum Definition<'a> {
Variable(&'a VariableDeclarator),
Import(NodeRef<'a, ImportStatement>),
Type(NodeRef<'a, TypeDeclaration>),
}
#[derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS)]
@ -54,18 +55,6 @@ pub struct Node<T> {
pub outer_attrs: NodeList<Annotation>,
}
impl<T> Node<T> {
pub fn metadata(&self) -> Metadata {
Metadata {
source_range: SourceRange::new(self.start, self.end, self.module_id),
}
}
pub fn contains(&self, pos: usize) -> bool {
self.start <= pos && pos <= self.end
}
}
impl<T: JsonSchema> schemars::JsonSchema for Node<T> {
fn schema_name() -> String {
T::schema_name()
@ -126,6 +115,26 @@ impl<T> Node<T> {
pub fn as_source_ranges(&self) -> Vec<SourceRange> {
vec![self.as_source_range()]
}
pub fn metadata(&self) -> Metadata {
Metadata {
source_range: SourceRange::new(self.start, self.end, self.module_id),
}
}
pub fn contains(&self, pos: usize) -> bool {
self.start <= pos && pos <= self.end
}
pub fn map<U>(self, f: fn(T) -> U) -> Node<U> {
Node {
inner: f(self.inner),
start: self.start,
end: self.end,
module_id: self.module_id,
outer_attrs: self.outer_attrs,
}
}
}
impl<T> Deref for Node<T> {
@ -352,7 +361,7 @@ impl Program {
// Recurse over the item.
match item {
BodyItem::ImportStatement(_) => None,
BodyItem::ImportStatement(_) | BodyItem::TypeDeclaration(_) => None,
BodyItem::ExpressionStatement(expression_statement) => Some(&expression_statement.expression),
BodyItem::VariableDeclaration(variable_declaration) => variable_declaration.get_expr_for_position(pos),
BodyItem::ReturnStatement(return_statement) => Some(&return_statement.argument),
@ -373,6 +382,7 @@ impl Program {
Some(BodyItem::VariableDeclaration(variable_declaration)) => {
variable_declaration.get_expr_for_position(pos)
}
Some(BodyItem::TypeDeclaration(_)) => None,
Some(BodyItem::ReturnStatement(return_statement)) => Some(&return_statement.argument),
None => return false,
};
@ -395,7 +405,7 @@ impl Program {
// We only care about the top level things in the program.
for item in &self.body {
match item {
BodyItem::ImportStatement(_) => continue,
BodyItem::ImportStatement(_) | BodyItem::TypeDeclaration(_) => continue,
BodyItem::ExpressionStatement(expression_statement) => {
if let Some(folding_range) = expression_statement.expression.get_lsp_folding_range() {
ranges.push(folding_range)
@ -425,16 +435,13 @@ impl Program {
break;
}
}
BodyItem::ExpressionStatement(_expression_statement) => {
continue;
}
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
if let Some(var_old_name) = variable_declaration.rename_symbol(new_name, pos) {
old_name = Some(var_old_name);
break;
}
}
BodyItem::ReturnStatement(_return_statement) => continue,
_ => {}
}
}
@ -458,6 +465,7 @@ impl Program {
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
variable_declaration.get_mut_expr_for_position(pos)
}
BodyItem::TypeDeclaration(_) => None,
BodyItem::ReturnStatement(ref mut return_statement) => Some(&mut return_statement.argument),
};
@ -483,16 +491,17 @@ impl Program {
fn rename_identifiers(&mut self, old_name: &str, new_name: &str) {
for item in &mut self.body {
match item {
BodyItem::ImportStatement(ref mut stmt) => {
BodyItem::ImportStatement(stmt) => {
stmt.rename_identifiers(old_name, new_name);
}
BodyItem::ExpressionStatement(ref mut expression_statement) => {
BodyItem::ExpressionStatement(expression_statement) => {
expression_statement.expression.rename_identifiers(old_name, new_name);
}
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
BodyItem::VariableDeclaration(variable_declaration) => {
variable_declaration.rename_identifiers(old_name, new_name);
}
BodyItem::ReturnStatement(ref mut return_statement) => {
BodyItem::TypeDeclaration(_) => {}
BodyItem::ReturnStatement(return_statement) => {
return_statement.argument.rename_identifiers(old_name, new_name);
}
}
@ -506,7 +515,7 @@ impl Program {
BodyItem::ImportStatement(_) => {
continue;
}
BodyItem::ExpressionStatement(_expression_statement) => {
BodyItem::ExpressionStatement(_) => {
continue;
}
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
@ -515,7 +524,10 @@ impl Program {
return;
}
}
BodyItem::ReturnStatement(_return_statement) => continue,
BodyItem::TypeDeclaration(_) => {
continue;
}
BodyItem::ReturnStatement(_) => continue,
}
}
}
@ -531,6 +543,7 @@ impl Program {
BodyItem::VariableDeclaration(ref mut variable_declaration) => {
variable_declaration.replace_value(source_range, new_value.clone())
}
BodyItem::TypeDeclaration(_) => {}
BodyItem::ReturnStatement(ref mut return_statement) => {
return_statement.argument.replace_value(source_range, new_value.clone())
}
@ -555,6 +568,11 @@ impl Program {
return Some(Definition::Variable(&variable_declaration.declaration));
}
}
BodyItem::TypeDeclaration(ty_declaration) => {
if ty_declaration.name.name == name {
return Some(Definition::Type(ty_declaration));
}
}
BodyItem::ReturnStatement(_return_statement) => continue,
}
}
@ -588,6 +606,7 @@ pub enum BodyItem {
ImportStatement(BoxNode<ImportStatement>),
ExpressionStatement(Node<ExpressionStatement>),
VariableDeclaration(BoxNode<VariableDeclaration>),
TypeDeclaration(BoxNode<TypeDeclaration>),
ReturnStatement(Node<ReturnStatement>),
}
@ -597,6 +616,7 @@ impl BodyItem {
BodyItem::ImportStatement(stmt) => stmt.start,
BodyItem::ExpressionStatement(expression_statement) => expression_statement.start,
BodyItem::VariableDeclaration(variable_declaration) => variable_declaration.start,
BodyItem::TypeDeclaration(ty_declaration) => ty_declaration.start,
BodyItem::ReturnStatement(return_statement) => return_statement.start,
}
}
@ -606,6 +626,7 @@ impl BodyItem {
BodyItem::ImportStatement(stmt) => stmt.end,
BodyItem::ExpressionStatement(expression_statement) => expression_statement.end,
BodyItem::VariableDeclaration(variable_declaration) => variable_declaration.end,
BodyItem::TypeDeclaration(ty_declaration) => ty_declaration.end,
BodyItem::ReturnStatement(return_statement) => return_statement.end,
}
}
@ -615,6 +636,7 @@ impl BodyItem {
BodyItem::ImportStatement(node) => node.outer_attrs = attr,
BodyItem::ExpressionStatement(node) => node.outer_attrs = attr,
BodyItem::VariableDeclaration(node) => node.outer_attrs = attr,
BodyItem::TypeDeclaration(ty_declaration) => ty_declaration.outer_attrs = attr,
BodyItem::ReturnStatement(node) => node.outer_attrs = attr,
}
}
@ -624,6 +646,7 @@ impl BodyItem {
BodyItem::ImportStatement(node) => &node.outer_attrs,
BodyItem::ExpressionStatement(node) => &node.outer_attrs,
BodyItem::VariableDeclaration(node) => &node.outer_attrs,
BodyItem::TypeDeclaration(ty_declaration) => &ty_declaration.outer_attrs,
BodyItem::ReturnStatement(node) => &node.outer_attrs,
}
}
@ -633,6 +656,7 @@ impl BodyItem {
BodyItem::ImportStatement(node) => &mut node.outer_attrs,
BodyItem::ExpressionStatement(node) => &mut node.outer_attrs,
BodyItem::VariableDeclaration(node) => &mut node.outer_attrs,
BodyItem::TypeDeclaration(ty_declaration) => &mut ty_declaration.outer_attrs,
BodyItem::ReturnStatement(node) => &mut node.outer_attrs,
}
}
@ -1765,6 +1789,20 @@ impl ItemVisibility {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub struct TypeDeclaration {
pub name: Node<Identifier>,
pub args: Option<NodeList<Identifier>>,
#[serde(default, skip_serializing_if = "ItemVisibility::is_default")]
pub visibility: ItemVisibility,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub digest: Option<Digest>,
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
@ -2832,7 +2870,8 @@ impl PipeExpression {
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub enum PrimitiveType {
@ -2845,39 +2884,16 @@ pub enum PrimitiveType {
Boolean,
/// A tag.
Tag,
/// A sketch type.
Sketch,
/// A sketch surface type.
SketchSurface,
/// An solid type.
Solid,
/// A plane.
Plane,
/// An identifier used as a type (not really a primitive type, but whatever).
Named(Node<Identifier>),
}
impl PrimitiveType {
pub fn digestable_id(&self) -> &[u8] {
match self {
PrimitiveType::String => b"string",
PrimitiveType::Number(suffix) => suffix.digestable_id(),
PrimitiveType::Boolean => b"bool",
PrimitiveType::Tag => b"tag",
PrimitiveType::Sketch => b"Sketch",
PrimitiveType::SketchSurface => b"SketchSurface",
PrimitiveType::Solid => b"Solid",
PrimitiveType::Plane => b"Plane",
}
}
pub fn from_str(s: &str, suffix: Option<NumericSuffix>) -> Option<Self> {
pub fn primitive_from_str(s: &str, suffix: Option<NumericSuffix>) -> Option<Self> {
match (s, suffix) {
("string", None) => Some(PrimitiveType::String),
("bool", None) => Some(PrimitiveType::Boolean),
("tag", None) => Some(PrimitiveType::Tag),
("Sketch", None) => Some(PrimitiveType::Sketch),
("SketchSurface", None) => Some(PrimitiveType::SketchSurface),
("Solid", None) => Some(PrimitiveType::Solid),
("Plane", None) => Some(PrimitiveType::Plane),
("number", None) => Some(PrimitiveType::Number(NumericSuffix::None)),
("number", Some(s)) => Some(PrimitiveType::Number(s)),
_ => None,
@ -2898,10 +2914,7 @@ impl fmt::Display for PrimitiveType {
PrimitiveType::String => write!(f, "string"),
PrimitiveType::Boolean => write!(f, "bool"),
PrimitiveType::Tag => write!(f, "tag"),
PrimitiveType::Sketch => write!(f, "Sketch"),
PrimitiveType::SketchSurface => write!(f, "SketchSurface"),
PrimitiveType::Solid => write!(f, "Solid"),
PrimitiveType::Plane => write!(f, "Plane"),
PrimitiveType::Named(n) => write!(f, "{}", n.name),
}
}
}

View File

@ -27,7 +27,8 @@ use crate::{
ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression,
MemberObject, Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
Parameter, PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, Shebang,
TagDeclarator, Type, UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
TagDeclarator, Type, TypeDeclaration, UnaryExpression, UnaryOperator, VariableDeclaration,
VariableDeclarator, VariableKind,
},
math::BinaryExpressionToken,
token::{Token, TokenSlice, TokenType},
@ -1175,11 +1176,10 @@ fn function_decl(i: &mut TokenSlice) -> PResult<(Node<FunctionExpression>, bool)
/// E.g. `person.name`
fn member_expression_dot(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usize, bool)> {
period.parse_next(i)?;
let property = alt((
sketch_keyword.map(Box::new).map(LiteralIdentifier::Identifier),
nameable_identifier.map(Box::new).map(LiteralIdentifier::Identifier),
))
.parse_next(i)?;
let property = nameable_identifier
.map(Box::new)
.map(LiteralIdentifier::Identifier)
.parse_next(i)?;
let end = property.end();
Ok((property, end, false))
}
@ -1188,7 +1188,6 @@ fn member_expression_dot(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usiz
fn member_expression_subscript(i: &mut TokenSlice) -> PResult<(LiteralIdentifier, usize, bool)> {
let _ = open_bracket.parse_next(i)?;
let property = alt((
sketch_keyword.map(Box::new).map(LiteralIdentifier::Identifier),
literal.map(LiteralIdentifier::Literal),
nameable_identifier.map(Box::new).map(LiteralIdentifier::Identifier),
))
@ -1330,7 +1329,9 @@ fn body_items_within_function(i: &mut TokenSlice) -> PResult<WithinFunction> {
// Any of the body item variants, each of which can optionally be followed by a comment.
// If there is a comment, it may be preceded by whitespace.
let item = dispatch! {peek(any);
token if token.visibility_keyword().is_some() => (alt((declaration.map(BodyItem::VariableDeclaration), import_stmt.map(BodyItem::ImportStatement))), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
token if token.visibility_keyword().is_some() => (alt((import_stmt.map(BodyItem::ImportStatement), ty_decl.map(BodyItem::TypeDeclaration), declaration.map(BodyItem::VariableDeclaration))), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
token if token.value == "type" && matches!(token.token_type, TokenType::Keyword) =>
(ty_decl.map(BodyItem::TypeDeclaration), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
token if token.declaration_keyword().is_some() =>
(declaration.map(BodyItem::VariableDeclaration), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
token if token.value == "import" && matches!(token.token_type, TokenType::Keyword) =>
@ -2058,6 +2059,52 @@ fn declaration(i: &mut TokenSlice) -> PResult<BoxNode<VariableDeclaration>> {
}))
}
fn ty_decl(i: &mut TokenSlice) -> PResult<BoxNode<TypeDeclaration>> {
let (visibility, visibility_token) = opt(terminated(item_visibility, whitespace))
.parse_next(i)?
.map_or((ItemVisibility::Default, None), |pair| (pair.0, Some(pair.1)));
let decl_token = ty(i)?;
let start = visibility_token.map(|t| t.start).unwrap_or_else(|| decl_token.start);
whitespace(i)?;
let name = identifier(i)?;
let mut end = name.end;
let args = if peek(open_paren).parse_next(i).is_ok() {
ignore_whitespace(i);
open_paren(i)?;
ignore_whitespace(i);
let args: Vec<_> = separated(0.., identifier, comma_sep).parse_next(i)?;
ignore_trailing_comma(i);
ignore_whitespace(i);
end = close_paren(i)?.end;
Some(args)
} else {
None
};
let result = Box::new(Node {
start,
end,
module_id: name.module_id,
outer_attrs: Vec::new(),
inner: TypeDeclaration {
name,
args,
visibility,
digest: None,
},
});
ParseContext::warn(CompilationError::err(
result.as_source_range(),
"Type declarations are experimental, likely to change, and may or may not do anything useful.",
));
Ok(result)
}
impl TryFrom<Token> for Node<Identifier> {
type Error = CompilationError;
@ -2109,29 +2156,6 @@ fn nameable_identifier(i: &mut TokenSlice) -> PResult<Node<Identifier>> {
Ok(result)
}
fn sketch_keyword(i: &mut TokenSlice) -> PResult<Node<Identifier>> {
any.try_map(|token: Token| {
if token.token_type == TokenType::Type && token.value == "sketch" {
Ok(Node::new(
Identifier {
name: token.value,
digest: None,
},
token.start,
token.end,
token.module_id,
))
} else {
Err(CompilationError::fatal(
token.as_source_range(),
format!("Expected 'sketch' keyword, but found {}", token.value.as_str()),
))
}
})
.context(expected("the 'sketch' keyword"))
.parse_next(i)
}
impl TryFrom<Token> for Node<TagDeclarator> {
type Error = CompilationError;
@ -2467,11 +2491,19 @@ fn at_sign(i: &mut TokenSlice) -> PResult<Token> {
}
fn fun(i: &mut TokenSlice) -> PResult<Token> {
keyword(i, "fn")
}
fn ty(i: &mut TokenSlice) -> PResult<Token> {
keyword(i, "type")
}
fn keyword(i: &mut TokenSlice, expected: &str) -> PResult<Token> {
any.try_map(|token: Token| match token.token_type {
TokenType::Keyword if token.value == "fn" => Ok(token),
TokenType::Keyword if token.value == expected => Ok(token),
_ => Err(CompilationError::fatal(
token.as_source_range(),
format!("expected 'fn', found {}", token.value.as_str(),),
format!("expected '{expected}', found {}", token.value.as_str(),),
)),
})
.parse_next(i)
@ -2520,43 +2552,33 @@ fn argument_type(i: &mut TokenSlice) -> PResult<Node<Type>> {
))
}),
// Array types
(
one_of(TokenType::Type),
opt(delimited(open_paren, uom_for_type, close_paren)),
open_bracket,
close_bracket,
)
.map(|(token, uom, _, _)| {
PrimitiveType::from_str(&token.value, uom)
.map(|t| Node::new(Type::Array(t), token.start, token.end, token.module_id))
.ok_or_else(|| {
CompilationError::fatal(token.as_source_range(), format!("Invalid type: {}", token.value))
})
}),
(primitive_type, open_bracket, close_bracket).map(|(t, _, _)| Ok(t.map(Type::Array))),
// Primitive types
(
one_of(TokenType::Type),
opt(delimited(open_paren, uom_for_type, close_paren)),
)
.map(|(token, suffix)| {
if suffix.is_some() {
ParseContext::warn(CompilationError::err(
(&token).into(),
"Unit of Measure types are experimental and currently do nothing.",
));
}
PrimitiveType::from_str(&token.value, suffix)
.map(|t| Node::new(Type::Primitive(t), token.start, token.end, token.module_id))
.ok_or_else(|| {
CompilationError::fatal(token.as_source_range(), format!("Invalid type: {}", token.value))
})
}),
primitive_type.map(|t| Ok(t.map(Type::Primitive))),
))
.parse_next(i)?
.map_err(|e: CompilationError| ErrMode::Backtrack(ContextError::from(e)))?;
Ok(type_)
}
fn primitive_type(i: &mut TokenSlice) -> PResult<Node<PrimitiveType>> {
let ident = identifier(i)?;
let suffix = opt(delimited(open_paren, uom_for_type, close_paren)).parse_next(i)?;
let mut result = Node::new(PrimitiveType::Boolean, ident.start, ident.end, ident.module_id);
result.inner = PrimitiveType::primitive_from_str(&ident.name, suffix).unwrap_or(PrimitiveType::Named(ident));
if suffix.is_some() {
ParseContext::warn(CompilationError::err(
result.as_source_range(),
"Unit of Measure types are experimental and currently do nothing.",
));
}
Ok(result)
}
fn uom_for_type(i: &mut TokenSlice) -> PResult<NumericSuffix> {
any.try_map(|t: Token| t.value.parse()).parse_next(i)
}
@ -4528,18 +4550,6 @@ let myBox = box([0,0], -3, -16, -10)
);
}
#[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#"

View File

@ -51,14 +51,6 @@ lazy_static! {
set.insert("struct", TokenType::Keyword);
set.insert("object", TokenType::Keyword);
set.insert("string", TokenType::Type);
set.insert("number", TokenType::Type);
set.insert("bool", TokenType::Type);
set.insert("Sketch", TokenType::Type);
set.insert("SketchSurface", TokenType::Type);
set.insert("Solid", TokenType::Type);
set.insert("Plane", TokenType::Type);
set
};
}