Support paths to names rather than just raw idents (#5778)

* Support paths to names rather than just raw idents

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

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

* A snapshot a day keeps the bugs away! 📷🐛

---------

Signed-off-by: Nick Cameron <nrc@ncameron.org>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Nick Cameron
2025-03-24 20:58:55 +13:00
committed by GitHub
parent cfbb03765e
commit dddcd5ff46
221 changed files with 71261 additions and 16926 deletions

View File

@ -4,7 +4,7 @@ use crate::parsing::ast::types::{
Annotation, ArrayExpression, ArrayRangeExpression, Ascription, BinaryExpression, BinaryPart, BodyItem,
CallExpression, CallExpressionKw, DefaultParamVal, ElseIf, Expr, ExpressionStatement, FunctionExpression,
Identifier, IfExpression, ImportItem, ImportSelector, ImportStatement, ItemVisibility, KclNone, LabelledExpression,
Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, ObjectExpression, ObjectProperty,
Literal, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Name, ObjectExpression, ObjectProperty,
Parameter, PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, TagDeclarator, Type,
TypeDeclaration, UnaryExpression, VariableDeclaration, VariableDeclarator, VariableKind,
};
@ -128,7 +128,7 @@ impl Expr {
pub fn compute_digest(&mut self) -> Digest {
match self {
Expr::Literal(lit) => lit.compute_digest(),
Expr::Identifier(id) => id.compute_digest(),
Expr::Name(id) => id.compute_digest(),
Expr::TagDeclarator(tag) => tag.compute_digest(),
Expr::BinaryExpression(be) => be.compute_digest(),
Expr::FunctionExpression(fe) => fe.compute_digest(),
@ -157,7 +157,7 @@ impl BinaryPart {
pub fn compute_digest(&mut self) -> Digest {
match self {
BinaryPart::Literal(lit) => lit.compute_digest(),
BinaryPart::Identifier(id) => id.compute_digest(),
BinaryPart::Name(id) => id.compute_digest(),
BinaryPart::BinaryExpression(be) => be.compute_digest(),
BinaryPart::CallExpression(ce) => ce.compute_digest(),
BinaryPart::CallExpressionKw(ce) => ce.compute_digest(),
@ -377,6 +377,17 @@ impl Identifier {
});
}
impl Name {
compute_digest!(|slf, hasher| {
hasher.update(slf.name.compute_digest());
for p in &mut slf.path {
hasher.update(p.compute_digest());
}
if slf.abs_path {
hasher.update([1]);
}
});
}
impl TagDeclarator {
compute_digest!(|slf, hasher| {
let name = slf.name.as_bytes();

View File

@ -23,7 +23,7 @@ impl Expr {
pub fn module_id(&self) -> ModuleId {
match self {
Expr::Literal(literal) => literal.module_id,
Expr::Identifier(identifier) => identifier.module_id,
Expr::Name(identifier) => identifier.module_id,
Expr::TagDeclarator(tag) => tag.module_id,
Expr::BinaryExpression(binary_expression) => binary_expression.module_id,
Expr::FunctionExpression(function_expression) => function_expression.module_id,
@ -48,7 +48,7 @@ impl BinaryPart {
pub fn module_id(&self) -> ModuleId {
match self {
BinaryPart::Literal(literal) => literal.module_id,
BinaryPart::Identifier(identifier) => identifier.module_id,
BinaryPart::Name(identifier) => identifier.module_id,
BinaryPart::BinaryExpression(binary_expression) => binary_expression.module_id,
BinaryPart::CallExpression(call_expression) => call_expression.module_id,
BinaryPart::CallExpressionKw(call_expression) => call_expression.module_id,

View File

@ -35,6 +35,7 @@ mod condition;
mod literal_value;
mod none;
#[derive(Debug)]
pub enum Definition<'a> {
Variable(&'a VariableDeclarator),
Import(NodeRef<'a, ImportStatement>),
@ -166,6 +167,18 @@ impl<T> Node<T> {
self.pre_comments = comments;
self.comment_start = start;
}
pub fn map_ref<'a, U: 'a>(&'a self, f: fn(&'a 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.clone(),
pre_comments: self.pre_comments.clone(),
comment_start: self.start,
}
}
}
impl<T> Deref for Node<T> {
@ -762,7 +775,7 @@ impl From<&BodyItem> for SourceRange {
#[allow(clippy::large_enum_variant)]
pub enum Expr {
Literal(BoxNode<Literal>),
Identifier(BoxNode<Identifier>),
Name(BoxNode<Name>),
TagDeclarator(BoxNode<TagDeclarator>),
BinaryExpression(BoxNode<BinaryExpression>),
FunctionExpression(BoxNode<FunctionExpression>),
@ -814,7 +827,7 @@ impl Expr {
Expr::FunctionExpression(_func_exp) => None,
Expr::CallExpression(_call_exp) => None,
Expr::CallExpressionKw(_call_exp) => None,
Expr::Identifier(_ident) => None,
Expr::Name(_ident) => None,
Expr::TagDeclarator(_tag) => None,
Expr::PipeExpression(pipe_exp) => Some(&pipe_exp.non_code_meta),
Expr::UnaryExpression(_unary_exp) => None,
@ -842,7 +855,7 @@ impl Expr {
Expr::FunctionExpression(ref mut func_exp) => func_exp.replace_value(source_range, new_value),
Expr::CallExpression(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
Expr::CallExpressionKw(ref mut call_exp) => call_exp.replace_value(source_range, new_value),
Expr::Identifier(_) => {}
Expr::Name(_) => {}
Expr::TagDeclarator(_) => {}
Expr::PipeExpression(ref mut pipe_exp) => pipe_exp.replace_value(source_range, new_value),
Expr::UnaryExpression(ref mut unary_exp) => unary_exp.replace_value(source_range, new_value),
@ -857,7 +870,7 @@ impl Expr {
pub fn start(&self) -> usize {
match self {
Expr::Literal(literal) => literal.start,
Expr::Identifier(identifier) => identifier.start,
Expr::Name(identifier) => identifier.start,
Expr::TagDeclarator(tag) => tag.start,
Expr::BinaryExpression(binary_expression) => binary_expression.start,
Expr::FunctionExpression(function_expression) => function_expression.start,
@ -880,7 +893,7 @@ impl Expr {
pub fn end(&self) -> usize {
match self {
Expr::Literal(literal) => literal.end,
Expr::Identifier(identifier) => identifier.end,
Expr::Name(identifier) => identifier.end,
Expr::TagDeclarator(tag) => tag.end,
Expr::BinaryExpression(binary_expression) => binary_expression.end,
Expr::FunctionExpression(function_expression) => function_expression.end,
@ -904,7 +917,7 @@ impl Expr {
fn rename_identifiers(&mut self, old_name: &str, new_name: &str) {
match self {
Expr::Literal(_literal) => {}
Expr::Identifier(ref mut identifier) => identifier.rename(old_name, new_name),
Expr::Name(ref mut identifier) => identifier.rename(old_name, new_name),
Expr::TagDeclarator(ref mut tag) => tag.rename(old_name, new_name),
Expr::BinaryExpression(ref mut binary_expression) => {
binary_expression.rename_identifiers(old_name, new_name)
@ -934,7 +947,7 @@ impl Expr {
pub fn get_constraint_level(&self) -> ConstraintLevel {
match self {
Expr::Literal(literal) => literal.get_constraint_level(),
Expr::Identifier(identifier) => identifier.get_constraint_level(),
Expr::Name(identifier) => identifier.get_constraint_level(),
Expr::TagDeclarator(tag) => tag.get_constraint_level(),
Expr::BinaryExpression(binary_expression) => binary_expression.get_constraint_level(),
@ -967,35 +980,6 @@ impl Expr {
}
}
/// Describe this expression's type for a human, for typechecking.
/// This is a best-effort function, it's OK to give a shitty string here (but we should work on improving it)
pub fn human_friendly_type(&self) -> &'static str {
match self {
Expr::Literal(node) => match node.inner.value {
LiteralValue::Number { .. } => "number",
LiteralValue::String(_) => "string (text)",
LiteralValue::Bool(_) => "boolean (true/false value)",
},
Expr::Identifier(_) => "named constant",
Expr::TagDeclarator(_) => "tag declarator",
Expr::BinaryExpression(_) => "expression",
Expr::FunctionExpression(_) => "function definition",
Expr::CallExpression(_) => "function call",
Expr::CallExpressionKw(_) => "function call",
Expr::PipeExpression(_) => "pipeline of function calls",
Expr::PipeSubstitution(_) => "left-hand side of a |> pipeline",
Expr::ArrayExpression(_) => "array",
Expr::ArrayRangeExpression(_) => "array",
Expr::ObjectExpression(_) => "object",
Expr::MemberExpression(_) => "property of an object/array",
Expr::UnaryExpression(_) => "expression",
Expr::IfExpression(_) => "if expression",
Expr::LabelledExpression(_) => "labelled expression",
Expr::AscribedExpression(_) => "type-ascribed expression",
Expr::None(_) => "none",
}
}
pub fn literal_bool(&self) -> Option<bool> {
match self {
Expr::Literal(lit) => match lit.value {
@ -1028,7 +1012,7 @@ impl Expr {
pub fn ident_name(&self) -> Option<&str> {
match self {
Expr::Identifier(ident) => Some(&ident.name),
Expr::Name(ident) => Some(&ident.name.name),
_ => None,
}
}
@ -1102,7 +1086,7 @@ impl Ascription {
#[serde(tag = "type")]
pub enum BinaryPart {
Literal(BoxNode<Literal>),
Identifier(BoxNode<Identifier>),
Name(BoxNode<Name>),
BinaryExpression(BoxNode<BinaryExpression>),
CallExpression(BoxNode<CallExpression>),
CallExpressionKw(BoxNode<CallExpressionKw>),
@ -1128,7 +1112,7 @@ impl BinaryPart {
pub fn get_constraint_level(&self) -> ConstraintLevel {
match self {
BinaryPart::Literal(literal) => literal.get_constraint_level(),
BinaryPart::Identifier(identifier) => identifier.get_constraint_level(),
BinaryPart::Name(identifier) => identifier.get_constraint_level(),
BinaryPart::BinaryExpression(binary_expression) => binary_expression.get_constraint_level(),
BinaryPart::CallExpression(call_expression) => call_expression.get_constraint_level(),
BinaryPart::CallExpressionKw(call_expression) => call_expression.get_constraint_level(),
@ -1141,7 +1125,7 @@ impl BinaryPart {
pub fn replace_value(&mut self, source_range: SourceRange, new_value: Expr) {
match self {
BinaryPart::Literal(_) => {}
BinaryPart::Identifier(_) => {}
BinaryPart::Name(_) => {}
BinaryPart::BinaryExpression(ref mut binary_expression) => {
binary_expression.replace_value(source_range, new_value)
}
@ -1162,7 +1146,7 @@ impl BinaryPart {
pub fn start(&self) -> usize {
match self {
BinaryPart::Literal(literal) => literal.start,
BinaryPart::Identifier(identifier) => identifier.start,
BinaryPart::Name(identifier) => identifier.start,
BinaryPart::BinaryExpression(binary_expression) => binary_expression.start,
BinaryPart::CallExpression(call_expression) => call_expression.start,
BinaryPart::CallExpressionKw(call_expression) => call_expression.start,
@ -1175,7 +1159,7 @@ impl BinaryPart {
pub fn end(&self) -> usize {
match self {
BinaryPart::Literal(literal) => literal.end,
BinaryPart::Identifier(identifier) => identifier.end,
BinaryPart::Name(identifier) => identifier.end,
BinaryPart::BinaryExpression(binary_expression) => binary_expression.end,
BinaryPart::CallExpression(call_expression) => call_expression.end,
BinaryPart::CallExpressionKw(call_expression) => call_expression.end,
@ -1189,7 +1173,7 @@ impl BinaryPart {
fn rename_identifiers(&mut self, old_name: &str, new_name: &str) {
match self {
BinaryPart::Literal(_literal) => {}
BinaryPart::Identifier(ref mut identifier) => identifier.rename(old_name, new_name),
BinaryPart::Name(ref mut identifier) => identifier.rename(old_name, new_name),
BinaryPart::BinaryExpression(ref mut binary_expression) => {
binary_expression.rename_identifiers(old_name, new_name)
}
@ -1418,13 +1402,13 @@ impl Annotation {
pub fn new_from_meta_settings(settings: &crate::execution::MetaSettings) -> Annotation {
let mut properties: Vec<Node<ObjectProperty>> = vec![ObjectProperty::new(
Identifier::new(annotations::SETTINGS_UNIT_LENGTH),
Expr::Identifier(Box::new(Identifier::new(&settings.default_length_units.to_string()))),
Expr::Name(Box::new(Name::new(&settings.default_length_units.to_string()))),
)];
if settings.default_angle_units != Default::default() {
properties.push(ObjectProperty::new(
Identifier::new(annotations::SETTINGS_UNIT_ANGLE),
Expr::Identifier(Box::new(Identifier::new(&settings.default_angle_units.to_string()))),
Expr::Name(Box::new(Name::new(&settings.default_angle_units.to_string()))),
));
}
Annotation {
@ -1689,7 +1673,7 @@ pub struct ExpressionStatement {
#[ts(export)]
#[serde(tag = "type")]
pub struct CallExpression {
pub callee: Node<Identifier>,
pub callee: Node<Name>,
pub arguments: Vec<Expr>,
#[serde(default, skip_serializing_if = "Option::is_none")]
@ -1701,7 +1685,7 @@ pub struct CallExpression {
#[ts(export)]
#[serde(rename_all = "camelCase", tag = "type")]
pub struct CallExpressionKw {
pub callee: Node<Identifier>,
pub callee: Node<Name>,
pub unlabeled: Option<Expr>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub arguments: Vec<LabeledArg>,
@ -1775,7 +1759,7 @@ impl Node<CallExpressionKw> {
impl CallExpression {
pub fn new(name: &str, arguments: Vec<Expr>) -> Result<Node<Self>, KclError> {
Ok(Node::no_src(Self {
callee: Identifier::new(name),
callee: Name::new(name),
arguments,
digest: None,
}))
@ -1807,7 +1791,7 @@ impl CallExpression {
impl CallExpressionKw {
pub fn new(name: &str, unlabeled: Option<Expr>, arguments: Vec<LabeledArg>) -> Result<Node<Self>, KclError> {
Ok(Node::no_src(Self {
callee: Identifier::new(name),
callee: Name::new(name),
unlabeled,
arguments,
digest: None,
@ -2192,13 +2176,8 @@ impl Node<Identifier> {
/// Get the constraint level for this identifier.
/// Identifier are always fully constrained.
pub fn get_constraint_level(&self) -> ConstraintLevel {
match &*self.name {
"XY" | "XZ" | "YZ" => ConstraintLevel::None {
source_ranges: vec![self.into()],
},
_ => ConstraintLevel::Full {
source_ranges: vec![self.into()],
},
ConstraintLevel::Full {
source_ranges: vec![self.into()],
}
}
}
@ -2223,6 +2202,99 @@ impl Identifier {
}
}
/// A qualified name, e.g., `foo`, `bar::foo`, or `::bar::foo`.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type")]
pub struct Name {
pub name: Node<Identifier>,
// The qualifying parts of the name.
pub path: NodeList<Identifier>,
// The path starts with `::`.
pub abs_path: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
pub digest: Option<Digest>,
}
impl Node<Name> {
pub fn get_constraint_level(&self) -> ConstraintLevel {
match &*self.name.name {
"XY" | "XZ" | "YZ" => ConstraintLevel::None {
source_ranges: vec![self.into()],
},
_ => ConstraintLevel::Full {
source_ranges: vec![self.into()],
},
}
}
}
impl Name {
pub fn new(name: &str) -> Node<Self> {
Node::no_src(Name {
name: Node::no_src(Identifier {
name: name.to_string(),
digest: None,
}),
path: Vec::new(),
abs_path: false,
digest: None,
})
}
pub fn local_ident(&self) -> Option<Node<&str>> {
if self.path.is_empty() && !self.abs_path {
Some(self.name.map_ref(|n| &n.name))
} else {
None
}
}
/// Rename all identifiers that have the old name to the new given name.
fn rename(&mut self, old_name: &str, new_name: &str) {
if let Some(n) = self.local_ident() {
if n.inner == old_name {
self.name.name = new_name.to_owned();
}
}
}
}
impl From<Node<Identifier>> for Node<Name> {
fn from(value: Node<Identifier>) -> Self {
let start = value.start;
let end = value.end;
let mod_id = value.module_id;
Node::new(
Name {
name: value,
path: Vec::new(),
abs_path: false,
digest: None,
},
start,
end,
mod_id,
)
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.abs_path {
f.write_str("::")?;
}
for p in &self.path {
f.write_str(&p.name)?;
f.write_str("::")?;
}
f.write_str(&self.name.name)
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq)]
#[ts(export)]
#[serde(tag = "type")]

View File

@ -18,7 +18,6 @@ use super::{
DeprecationKind,
};
use crate::{
docs::StdLibFn,
errors::{CompilationError, Severity, Tag},
execution::types::ArrayLen,
parsing::{
@ -27,9 +26,9 @@ use crate::{
BoxNode, CallExpression, CallExpressionKw, CommentStyle, DefaultParamVal, ElseIf, Expr,
ExpressionStatement, FunctionExpression, Identifier, IfExpression, ImportItem, ImportSelector,
ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression,
MemberObject, Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
Parameter, PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement, Shebang,
TagDeclarator, Type, TypeDeclaration, UnaryExpression, UnaryOperator, VariableDeclaration,
MemberObject, Name, Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression,
ObjectProperty, Parameter, PipeExpression, PipeSubstitution, PrimitiveType, Program, ReturnStatement,
Shebang, TagDeclarator, Type, TypeDeclaration, UnaryExpression, UnaryOperator, VariableDeclaration,
VariableDeclarator, VariableKind,
},
math::BinaryExpressionToken,
@ -631,7 +630,7 @@ fn operand(i: &mut TokenSlice) -> PResult<BinaryPart> {
}
Expr::UnaryExpression(x) => BinaryPart::UnaryExpression(x),
Expr::Literal(x) => BinaryPart::Literal(x),
Expr::Identifier(x) => BinaryPart::Identifier(x),
Expr::Name(x) => BinaryPart::Name(x),
Expr::BinaryExpression(x) => BinaryPart::BinaryExpression(x),
Expr::CallExpression(x) => BinaryPart::CallExpression(x),
Expr::CallExpressionKw(x) => BinaryPart::CallExpressionKw(x),
@ -891,7 +890,7 @@ fn object_property_same_key_and_val(i: &mut TokenSlice) -> PResult<Node<ObjectPr
key.end,
key.module_id,
ObjectProperty {
value: Expr::Identifier(Box::new(key.clone())),
value: Expr::Name(Box::new(key.clone().into())),
key,
digest: None,
},
@ -2069,7 +2068,7 @@ fn expr_allowed_in_pipe_expr(i: &mut TokenSlice) -> PResult<Expr> {
literal.map(Expr::Literal),
fn_call.map(Box::new).map(Expr::CallExpression),
fn_call_kw.map(Box::new).map(Expr::CallExpressionKw),
nameable_identifier.map(Box::new).map(Expr::Identifier),
name.map(Box::new).map(Expr::Name),
array,
object.map(Box::new).map(Expr::ObjectExpression),
pipe_sub.map(Box::new).map(Expr::PipeSubstitution),
@ -2088,7 +2087,7 @@ fn possible_operands(i: &mut TokenSlice) -> PResult<Expr> {
member_expression.map(Box::new).map(Expr::MemberExpression),
literal.map(Expr::Literal),
fn_call.map(Box::new).map(Expr::CallExpression),
nameable_identifier.map(Box::new).map(Expr::Identifier),
name.map(Box::new).map(Expr::Name),
binary_expr_in_parens.map(Box::new).map(Expr::BinaryExpression),
unnecessarily_bracketed,
))
@ -2360,6 +2359,35 @@ fn nameable_identifier(i: &mut TokenSlice) -> PResult<Node<Identifier>> {
Ok(result)
}
fn name(i: &mut TokenSlice) -> PResult<Node<Name>> {
let abs_path = opt(double_colon).parse_next(i)?;
let mut idents: NodeList<Identifier> = separated(1.., nameable_identifier, double_colon)
.parse_next(i)
.map_err(|e| e.backtrack())?;
let mut start = idents[0].start;
if let Some(abs_path) = &abs_path {
start = abs_path.start;
}
let abs_path = abs_path.is_some();
let name = idents.pop().unwrap();
let end = name.end;
let module_id = name.module_id;
Ok(Node::new(
Name {
name,
path: idents,
abs_path,
digest: None,
},
start,
end,
module_id,
))
}
impl TryFrom<Token> for Node<TagDeclarator> {
type Error = CompilationError;
@ -2671,6 +2699,10 @@ fn plus(i: &mut TokenSlice) -> PResult<Token> {
one_of((TokenType::Operator, "+")).parse_next(i)
}
fn double_colon(i: &mut TokenSlice) -> PResult<Token> {
TokenType::DoubleColon.parse_from(i)
}
fn equals(i: &mut TokenSlice) -> PResult<Token> {
one_of((TokenType::Operator, "="))
.context(expected("the equals operator, ="))
@ -2957,76 +2989,6 @@ fn binding_name(i: &mut TokenSlice) -> PResult<Node<Identifier>> {
.parse_next(i)
}
/// Typecheck the arguments in a keyword fn call.
fn typecheck_all_kw(std_fn: Box<dyn StdLibFn>, args: &[&LabeledArg]) -> PResult<()> {
for arg in args {
let label = &arg.label;
let expr = &arg.arg;
if let Some(spec_arg) = std_fn.args(false).iter().find(|spec_arg| spec_arg.name == label.name) {
typecheck(spec_arg, &expr)?;
}
}
Ok(())
}
/// Type check the arguments in a positional fn call.
fn typecheck_all_positional(std_fn: Box<dyn StdLibFn>, args: &[&Expr]) -> PResult<()> {
for (i, spec_arg) in std_fn.args(false).iter().enumerate() {
let Some(arg) = &args.get(i) else {
// The executor checks the number of arguments, so we don't need to check it here.
continue;
};
typecheck(spec_arg, arg)?;
}
Ok(())
}
fn typecheck(spec_arg: &crate::docs::StdLibFnArg, arg: &&Expr) -> PResult<()> {
match spec_arg.type_.as_ref() {
"TagNode" => match &arg {
Expr::Identifier(_) => {
// These are fine since we want someone to be able to map a variable to a tag declarator.
}
Expr::TagDeclarator(tag) => {
// TODO: Remove this check. It should be redundant.
tag.clone()
.into_valid_binding_name()
.map_err(|e| ErrMode::Cut(ContextError::from(e)))?;
}
e => {
return Err(ErrMode::Cut(
CompilationError::fatal(
SourceRange::from(*arg),
format!(
"Expected a tag declarator like `$name`, found {}",
e.human_friendly_type()
),
)
.into(),
));
}
},
"TagIdentifier" => match &arg {
Expr::Identifier(_) => {}
Expr::MemberExpression(_) => {}
e => {
return Err(ErrMode::Cut(
CompilationError::fatal(
SourceRange::from(*arg),
format!(
"Expected a tag identifier like `tagName`, found {}",
e.human_friendly_type()
),
)
.into(),
));
}
},
_ => {}
}
Ok(())
}
/// Either a positional or keyword function call.
fn fn_call_pos_or_kw(i: &mut TokenSlice) -> PResult<Expr> {
alt((
@ -3047,15 +3009,10 @@ fn labelled_fn_call(i: &mut TokenSlice) -> PResult<Expr> {
}
fn fn_call(i: &mut TokenSlice) -> PResult<Node<CallExpression>> {
let fn_name = nameable_identifier(i)?;
let fn_name = name(i)?;
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_positional(std_fn, &just_args)?;
}
let end = preceded(opt(whitespace), close_paren).parse_next(i)?.end;
let result = Node::new_node(
@ -3069,17 +3026,15 @@ fn fn_call(i: &mut TokenSlice) -> PResult<Node<CallExpression>> {
},
);
if let Some(suggestion) = super::deprecation(&result.callee.name, DeprecationKind::Function) {
let callee_str = result.callee.name.name.to_string();
if let Some(suggestion) = super::deprecation(&callee_str, DeprecationKind::Function) {
ParseContext::warn(
CompilationError::err(
result.as_source_range(),
format!(
"Calling `{}` is deprecated, prefer using `{}`.",
result.callee.name, suggestion
),
format!("Calling `{}` is deprecated, prefer using `{}`.", callee_str, suggestion),
)
.with_suggestion(
format!("Replace `{}` with `{}`", result.callee.name, suggestion),
format!("Replace `{}` with `{}`", callee_str, suggestion),
suggestion,
None,
Tag::Deprecated,
@ -3091,7 +3046,7 @@ fn fn_call(i: &mut TokenSlice) -> PResult<Node<CallExpression>> {
}
fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
let fn_name = nameable_identifier(i)?;
let fn_name = name(i)?;
opt(whitespace).parse_next(i)?;
let _ = open_paren.parse_next(i)?;
ignore_whitespace(i);
@ -3147,10 +3102,6 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
Ok((args, non_code_nodes))
},
)?;
if let Some(std_fn) = crate::std::get_stdlib_fn(&fn_name.name) {
let just_args: Vec<_> = args.iter().collect();
typecheck_all_kw(std_fn, &just_args)?;
}
ignore_whitespace(i);
opt(comma_sep).parse_next(i)?;
let end = close_paren.parse_next(i)?.end;
@ -3172,17 +3123,15 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
},
);
if let Some(suggestion) = super::deprecation(&result.callee.name, DeprecationKind::Function) {
let callee_str = result.callee.name.name.to_string();
if let Some(suggestion) = super::deprecation(&callee_str, DeprecationKind::Function) {
ParseContext::warn(
CompilationError::err(
result.as_source_range(),
format!(
"Calling `{}` is deprecated, prefer using `{}`.",
result.callee.name, suggestion
),
format!("Calling `{}` is deprecated, prefer using `{}`.", callee_str, suggestion),
)
.with_suggestion(
format!("Replace `{}` with `{}`", result.callee.name, suggestion),
format!("Replace `{}` with `{}`", callee_str, suggestion),
suggestion,
None,
Tag::Deprecated,
@ -3244,6 +3193,17 @@ mod tests {
}
}
#[test]
fn parse_names() {
for (test, expected_len) in [("someVar", 0), ("::foo", 0), ("foo::bar::baz", 2)] {
let tokens = crate::parsing::token::lex(test, ModuleId::default()).unwrap();
match name.parse(tokens.as_slice()) {
Ok(n) => assert_eq!(n.path.len(), expected_len, "Could not parse name from `{test}`: {n:?}"),
Err(e) => panic!("Could not parse name from `{test}`: {e:?}"),
}
}
}
#[test]
fn weird_program_unclosed_paren() {
let tokens = crate::parsing::token::lex("fn firstPrime(", ModuleId::default()).unwrap();

View File

@ -18,17 +18,33 @@ expression: actual
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Identifier",
"type": "Identifier",
"name": "distance",
"type": "Name",
"type": "Name",
"name": {
"type": "Identifier",
"name": "distance",
"start": 0,
"end": 8,
"commentStart": 0
},
"path": [],
"abs_path": false,
"start": 0,
"end": 8,
"commentStart": 0
},
"right": {
"type": "Identifier",
"type": "Identifier",
"name": "p",
"type": "Name",
"type": "Name",
"name": {
"type": "Identifier",
"name": "p",
"start": 11,
"end": 12,
"commentStart": 11
},
"path": [],
"abs_path": false,
"start": 11,
"end": 12,
"commentStart": 11
@ -38,9 +54,17 @@ expression: actual
"commentStart": 0
},
"right": {
"type": "Identifier",
"type": "Identifier",
"name": "FOS",
"type": "Name",
"type": "Name",
"name": {
"type": "Identifier",
"name": "FOS",
"start": 15,
"end": 18,
"commentStart": 15
},
"path": [],
"abs_path": false,
"start": 15,
"end": 18,
"commentStart": 15
@ -70,17 +94,33 @@ expression: actual
"type": "BinaryExpression",
"operator": "*",
"left": {
"type": "Identifier",
"type": "Identifier",
"name": "sigmaAllow",
"type": "Name",
"type": "Name",
"name": {
"type": "Identifier",
"name": "sigmaAllow",
"start": 26,
"end": 36,
"commentStart": 26
},
"path": [],
"abs_path": false,
"start": 26,
"end": 36,
"commentStart": 26
},
"right": {
"type": "Identifier",
"type": "Identifier",
"name": "width",
"type": "Name",
"type": "Name",
"name": {
"type": "Identifier",
"name": "width",
"start": 39,
"end": 44,
"commentStart": 39
},
"path": [],
"abs_path": false,
"start": 39,
"end": 44,
"commentStart": 39

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 26,
"end": 28,
"name": "XY",
"name": {
"commentStart": 26,
"end": 28,
"name": "XY",
"start": 26,
"type": "Identifier"
},
"path": [],
"start": 26,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 12,
"end": 25,
"name": "startSketchOn",
"name": {
"commentStart": 12,
"end": 25,
"name": "startSketchOn",
"start": 12,
"type": "Identifier"
},
"path": [],
"start": 12,
"type": "Identifier"
"type": "Name"
},
"commentStart": 12,
"end": 29,
@ -86,11 +102,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 37,
"end": 51,
"name": "startProfileAt",
"name": {
"commentStart": 37,
"end": 51,
"name": "startProfileAt",
"start": 37,
"type": "Identifier"
},
"path": [],
"start": 37,
"type": "Identifier"
"type": "Name"
},
"commentStart": 37,
"end": 62,
@ -142,11 +166,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 70,
"end": 74,
"name": "line",
"name": {
"commentStart": 70,
"end": 74,
"name": "line",
"start": 70,
"type": "Identifier"
},
"path": [],
"start": 70,
"type": "Identifier"
"type": "Name"
},
"commentStart": 70,
"end": 86,
@ -206,11 +238,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 94,
"end": 107,
"name": "tangentialArc",
"name": {
"commentStart": 94,
"end": 107,
"name": "tangentialArc",
"start": 94,
"type": "Identifier"
},
"path": [],
"start": 94,
"type": "Identifier"
"type": "Name"
},
"commentStart": 94,
"end": 119,
@ -270,11 +310,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 127,
"end": 131,
"name": "line",
"name": {
"commentStart": 127,
"end": 131,
"name": "line",
"start": 127,
"type": "Identifier"
},
"path": [],
"start": 127,
"type": "Identifier"
"type": "Name"
},
"commentStart": 127,
"end": 144,
@ -308,11 +356,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 152,
"end": 159,
"name": "extrude",
"name": {
"commentStart": 152,
"end": 159,
"name": "extrude",
"start": 152,
"type": "Identifier"
},
"path": [],
"start": 152,
"type": "Identifier"
"type": "Name"
},
"commentStart": 152,
"end": 170,

View File

@ -18,12 +18,20 @@ expression: actual
},
"init": {
"argument": {
"abs_path": false,
"commentStart": 6,
"end": 11,
"name": "scale",
"name": {
"commentStart": 6,
"end": 11,
"name": "scale",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"commentStart": 5,
"end": 11,

View File

@ -62,11 +62,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 0,
"end": 4,
"name": "line",
"name": {
"commentStart": 0,
"end": 4,
"name": "line",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Identifier"
"type": "Name"
},
"commentStart": 0,
"end": 27,

View File

@ -65,11 +65,19 @@ expression: actual
"expression": {
"arguments": [],
"callee": {
"abs_path": false,
"commentStart": 62,
"end": 78,
"name": "firstPrimeNumber",
"name": {
"commentStart": 62,
"end": 78,
"name": "firstPrimeNumber",
"start": 62,
"type": "Identifier"
},
"path": [],
"start": 62,
"type": "Identifier"
"type": "Name"
},
"commentStart": 62,
"end": 80,

View File

@ -83,11 +83,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 54,
"end": 59,
"name": "thing",
"name": {
"commentStart": 54,
"end": 59,
"name": "thing",
"start": 54,
"type": "Identifier"
},
"path": [],
"start": 54,
"type": "Identifier"
"type": "Name"
},
"commentStart": 54,
"end": 66,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 25,
"end": 27,
"name": "XY",
"name": {
"commentStart": 25,
"end": 27,
"name": "XY",
"start": 25,
"type": "Identifier"
},
"path": [],
"start": 25,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"name": {
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"start": 11,
"type": "Identifier"
},
"path": [],
"start": 11,
"type": "Identifier"
"type": "Name"
},
"commentStart": 11,
"end": 28,
@ -86,11 +102,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 40,
"end": 54,
"name": "startProfileAt",
"name": {
"commentStart": 40,
"end": 54,
"name": "startProfileAt",
"start": 40,
"type": "Identifier"
},
"path": [],
"start": 40,
"type": "Identifier"
"type": "Name"
},
"commentStart": 40,
"end": 64,
@ -163,11 +187,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 76,
"end": 80,
"name": "line",
"name": {
"commentStart": 76,
"end": 80,
"name": "line",
"start": 76,
"type": "Identifier"
},
"path": [],
"start": 76,
"type": "Identifier"
"type": "Name"
},
"commentStart": 76,
"end": 117,
@ -223,11 +255,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 129,
"end": 133,
"name": "line",
"name": {
"commentStart": 129,
"end": 133,
"name": "line",
"start": 129,
"type": "Identifier"
},
"path": [],
"start": 129,
"type": "Identifier"
"type": "Name"
},
"commentStart": 129,
"end": 155,
@ -301,11 +341,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 167,
"end": 171,
"name": "line",
"name": {
"commentStart": 167,
"end": 171,
"name": "line",
"start": 167,
"type": "Identifier"
},
"path": [],
"start": 167,
"type": "Identifier"
"type": "Name"
},
"commentStart": 167,
"end": 211,
@ -317,11 +365,19 @@ expression: actual
{
"arguments": [],
"callee": {
"abs_path": false,
"commentStart": 223,
"end": 228,
"name": "close",
"name": {
"commentStart": 223,
"end": 228,
"name": "close",
"start": 223,
"type": "Identifier"
},
"path": [],
"start": 223,
"type": "Identifier"
"type": "Name"
},
"commentStart": 223,
"end": 230,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 25,
"end": 27,
"name": "XY",
"name": {
"commentStart": 25,
"end": 27,
"name": "XY",
"start": 25,
"type": "Identifier"
},
"path": [],
"start": 25,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"name": {
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"start": 11,
"type": "Identifier"
},
"path": [],
"start": 11,
"type": "Identifier"
"type": "Name"
},
"commentStart": 11,
"end": 28,
@ -86,11 +102,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 32,
"end": 46,
"name": "startProfileAt",
"name": {
"commentStart": 32,
"end": 46,
"name": "startProfileAt",
"start": 32,
"type": "Identifier"
},
"path": [],
"start": 32,
"type": "Identifier"
"type": "Name"
},
"commentStart": 32,
"end": 56,
@ -145,11 +169,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 60,
"end": 64,
"name": "line",
"name": {
"commentStart": 60,
"end": 64,
"name": "line",
"start": 60,
"type": "Identifier"
},
"path": [],
"start": 60,
"type": "Identifier"
"type": "Name"
},
"commentStart": 60,
"end": 86,
@ -161,11 +193,19 @@ expression: actual
{
"arguments": [],
"callee": {
"abs_path": false,
"commentStart": 90,
"end": 95,
"name": "close",
"name": {
"commentStart": 90,
"end": 95,
"name": "close",
"start": 90,
"type": "Identifier"
},
"path": [],
"start": 90,
"type": "Identifier"
"type": "Name"
},
"commentStart": 90,
"end": 97,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 22,
"end": 24,
"name": "XY",
"name": {
"commentStart": 22,
"end": 24,
"name": "XY",
"start": 22,
"type": "Identifier"
},
"path": [],
"start": 22,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 8,
"end": 21,
"name": "startSketchOn",
"name": {
"commentStart": 8,
"end": 21,
"name": "startSketchOn",
"start": 8,
"type": "Identifier"
},
"path": [],
"start": 8,
"type": "Identifier"
"type": "Name"
},
"commentStart": 8,
"end": 25,
@ -45,12 +61,20 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 44,
"end": 45,
"name": "p",
"name": {
"commentStart": 44,
"end": 45,
"name": "p",
"start": 44,
"type": "Identifier"
},
"path": [],
"start": 44,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
{
"commentStart": 47,
@ -61,11 +85,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 29,
"end": 43,
"name": "startProfileAt",
"name": {
"commentStart": 29,
"end": 43,
"name": "startProfileAt",
"start": 29,
"type": "Identifier"
},
"path": [],
"start": 29,
"type": "Identifier"
"type": "Name"
},
"commentStart": 29,
"end": 49,

View File

@ -34,11 +34,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 8,
"end": 9,
"name": "f",
"name": {
"commentStart": 8,
"end": 9,
"name": "f",
"start": 8,
"type": "Identifier"
},
"path": [],
"start": 8,
"type": "Identifier"
"type": "Name"
},
"commentStart": 8,
"end": 12,
@ -69,11 +77,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 16,
"end": 17,
"name": "g",
"name": {
"commentStart": 16,
"end": 17,
"name": "g",
"start": 16,
"type": "Identifier"
},
"path": [],
"start": 16,
"type": "Identifier"
"type": "Name"
},
"commentStart": 16,
"end": 23,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 22,
"end": 24,
"name": "XY",
"name": {
"commentStart": 22,
"end": 24,
"name": "XY",
"start": 22,
"type": "Identifier"
},
"path": [],
"start": 22,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 8,
"end": 21,
"name": "startSketchOn",
"name": {
"commentStart": 8,
"end": 21,
"name": "startSketchOn",
"start": 8,
"type": "Identifier"
},
"path": [],
"start": 8,
"type": "Identifier"
"type": "Name"
},
"commentStart": 8,
"end": 25,
@ -45,12 +61,20 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 44,
"end": 45,
"name": "p",
"name": {
"commentStart": 44,
"end": 45,
"name": "p",
"start": 44,
"type": "Identifier"
},
"path": [],
"start": 44,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
{
"commentStart": 47,
@ -61,11 +85,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 29,
"end": 43,
"name": "startProfileAt",
"name": {
"commentStart": 29,
"end": 43,
"name": "startProfileAt",
"start": 29,
"type": "Identifier"
},
"path": [],
"start": 29,
"type": "Identifier"
"type": "Name"
},
"commentStart": 29,
"end": 49,
@ -100,12 +132,20 @@ expression: actual
}
},
{
"abs_path": false,
"commentStart": 68,
"end": 69,
"name": "l",
"name": {
"commentStart": 68,
"end": 69,
"name": "l",
"start": 68,
"type": "Identifier"
},
"path": [],
"start": 68,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"end": 70,
@ -116,11 +156,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 53,
"end": 57,
"name": "line",
"name": {
"commentStart": 53,
"end": 57,
"name": "line",
"start": 53,
"type": "Identifier"
},
"path": [],
"start": 53,
"type": "Identifier"
"type": "Name"
},
"commentStart": 53,
"end": 71,

View File

@ -54,11 +54,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 0,
"end": 4,
"name": "line",
"name": {
"commentStart": 0,
"end": 4,
"name": "line",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Identifier"
"type": "Name"
},
"commentStart": 0,
"end": 26,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 25,
"end": 27,
"name": "XY",
"name": {
"commentStart": 25,
"end": 27,
"name": "XY",
"start": 25,
"type": "Identifier"
},
"path": [],
"start": 25,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"name": {
"commentStart": 11,
"end": 24,
"name": "startSketchOn",
"start": 11,
"type": "Identifier"
},
"path": [],
"start": 11,
"type": "Identifier"
"type": "Name"
},
"commentStart": 11,
"end": 28,
@ -86,11 +102,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 32,
"end": 46,
"name": "startProfileAt",
"name": {
"commentStart": 32,
"end": 46,
"name": "startProfileAt",
"start": 32,
"type": "Identifier"
},
"path": [],
"start": 32,
"type": "Identifier"
"type": "Name"
},
"commentStart": 32,
"end": 56,

View File

@ -31,20 +31,36 @@ expression: actual
"value": "hello"
},
{
"abs_path": false,
"commentStart": 16,
"end": 27,
"name": "aIdentifier",
"name": {
"commentStart": 16,
"end": 27,
"name": "aIdentifier",
"start": 16,
"type": "Identifier"
},
"path": [],
"start": 16,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 0,
"end": 3,
"name": "log",
"name": {
"commentStart": 0,
"end": 3,
"name": "log",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Identifier"
"type": "Name"
},
"commentStart": 0,
"end": 28,

View File

@ -25,12 +25,20 @@ expression: actual
}
},
{
"abs_path": false,
"commentStart": 9,
"end": 10,
"name": "l",
"name": {
"commentStart": 9,
"end": 10,
"name": "l",
"start": 9,
"type": "Identifier"
},
"path": [],
"start": 9,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"end": 11,
@ -47,11 +55,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 0,
"end": 4,
"name": "line",
"name": {
"commentStart": 0,
"end": 4,
"name": "line",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Identifier"
"type": "Name"
},
"commentStart": 0,
"end": 15,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 31,
"end": 33,
"name": "XY",
"name": {
"commentStart": 31,
"end": 33,
"name": "XY",
"start": 31,
"type": "Identifier"
},
"path": [],
"start": 31,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 17,
"end": 30,
"name": "startSketchOn",
"name": {
"commentStart": 17,
"end": 30,
"name": "startSketchOn",
"start": 17,
"type": "Identifier"
},
"path": [],
"start": 17,
"type": "Identifier"
"type": "Name"
},
"commentStart": 17,
"end": 34,
@ -111,11 +127,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 42,
"end": 48,
"name": "circle",
"name": {
"commentStart": 42,
"end": 48,
"name": "circle",
"start": 42,
"type": "Identifier"
},
"path": [],
"start": 42,
"type": "Identifier"
"type": "Name"
},
"commentStart": 42,
"end": 76,
@ -150,11 +174,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 84,
"end": 91,
"name": "extrude",
"name": {
"commentStart": 84,
"end": 91,
"name": "extrude",
"start": 84,
"type": "Identifier"
},
"path": [],
"start": 84,
"type": "Identifier"
"type": "Name"
},
"commentStart": 84,
"end": 104,

View File

@ -23,12 +23,20 @@ expression: actual
"argument": {
"arguments": [
{
"abs_path": false,
"commentStart": 36,
"end": 41,
"name": "angle",
"name": {
"commentStart": 36,
"end": 41,
"name": "angle",
"start": 36,
"type": "Identifier"
},
"path": [],
"start": 36,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
{
"commentStart": 43,
@ -44,11 +52,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 28,
"end": 35,
"name": "default",
"name": {
"commentStart": 28,
"end": 35,
"name": "default",
"start": 28,
"type": "Identifier"
},
"path": [],
"start": 28,
"type": "Identifier"
"type": "Name"
},
"commentStart": 28,
"end": 47,

View File

@ -59,11 +59,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 17,
"end": 23,
"name": "legLen",
"name": {
"commentStart": 17,
"end": 23,
"name": "legLen",
"start": 17,
"type": "Identifier"
},
"path": [],
"start": 17,
"type": "Identifier"
"type": "Name"
},
"commentStart": 17,
"end": 29,
@ -80,11 +88,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 8,
"end": 11,
"name": "min",
"name": {
"commentStart": 8,
"end": 11,
"name": "min",
"start": 8,
"type": "Identifier"
},
"path": [],
"start": 8,
"type": "Identifier"
"type": "Name"
},
"commentStart": 8,
"end": 30,

View File

@ -31,11 +31,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 13,
"end": 26,
"name": "startSketchOn",
"name": {
"commentStart": 13,
"end": 26,
"name": "startSketchOn",
"start": 13,
"type": "Identifier"
},
"path": [],
"start": 13,
"type": "Identifier"
"type": "Name"
},
"commentStart": 13,
"end": 32,
@ -54,11 +62,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 109,
"end": 123,
"name": "startProfileAt",
"name": {
"commentStart": 109,
"end": 123,
"name": "startProfileAt",
"start": 109,
"type": "Identifier"
},
"path": [],
"start": 109,
"type": "Identifier"
"type": "Name"
},
"commentStart": 109,
"end": 126,

View File

@ -34,20 +34,36 @@ expression: actual
"cond": {
"arguments": [
{
"abs_path": false,
"commentStart": 51,
"end": 57,
"name": "radius",
"name": {
"commentStart": 51,
"end": 57,
"name": "radius",
"start": 51,
"type": "Identifier"
},
"path": [],
"start": 51,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 46,
"end": 50,
"name": "func",
"name": {
"commentStart": 46,
"end": 50,
"name": "func",
"start": 46,
"type": "Identifier"
},
"path": [],
"start": 46,
"type": "Identifier"
"type": "Name"
},
"commentStart": 46,
"end": 58,

View File

@ -66,12 +66,20 @@ expression: actual
"start": 22,
"type": "ObjectProperty",
"value": {
"abs_path": false,
"commentStart": 22,
"end": 23,
"name": "x",
"name": {
"commentStart": 22,
"end": 23,
"name": "x",
"start": 22,
"type": "Identifier"
},
"path": [],
"start": 22,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
{

View File

@ -8,12 +8,20 @@ expression: actual
"commentStart": 0,
"end": 5,
"expression": {
"abs_path": false,
"commentStart": 0,
"end": 5,
"name": "truee",
"name": {
"commentStart": 0,
"end": 5,
"name": "truee",
"start": 0,
"type": "Identifier"
},
"path": [],
"start": 0,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"start": 0,
"type": "ExpressionStatement",

View File

@ -47,11 +47,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 13,
"end": 19,
"name": "legLen",
"name": {
"commentStart": 13,
"end": 19,
"name": "legLen",
"start": 13,
"type": "Identifier"
},
"path": [],
"start": 13,
"type": "Identifier"
"type": "Name"
},
"commentStart": 13,
"end": 25,
@ -80,11 +88,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 8,
"end": 11,
"name": "min",
"name": {
"commentStart": 8,
"end": 11,
"name": "min",
"start": 8,
"type": "Identifier"
},
"path": [],
"start": 8,
"type": "Identifier"
"type": "Name"
},
"commentStart": 8,
"end": 29,

View File

@ -73,11 +73,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 17,
"end": 23,
"name": "myFunc",
"name": {
"commentStart": 17,
"end": 23,
"name": "myFunc",
"start": 17,
"type": "Identifier"
},
"path": [],
"start": 17,
"type": "Identifier"
"type": "Name"
},
"commentStart": 17,
"end": 30,

View File

@ -21,12 +21,20 @@ expression: actual
"end": 21,
"left": {
"argument": {
"abs_path": false,
"commentStart": 5,
"end": 9,
"name": "leg2",
"name": {
"commentStart": 5,
"end": 9,
"name": "leg2",
"start": 5,
"type": "Identifier"
},
"path": [],
"start": 5,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"commentStart": 4,
"end": 9,
@ -37,12 +45,20 @@ expression: actual
},
"operator": "+",
"right": {
"abs_path": false,
"commentStart": 12,
"end": 21,
"name": "thickness",
"name": {
"commentStart": 12,
"end": 21,
"name": "thickness",
"start": 12,
"type": "Identifier"
},
"path": [],
"start": 12,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"start": 4,
"type": "BinaryExpression",

View File

@ -21,12 +21,20 @@ expression: actual
"body": [
{
"argument": {
"abs_path": false,
"commentStart": 30,
"end": 32,
"name": "sg",
"name": {
"commentStart": 30,
"end": 32,
"name": "sg",
"start": 30,
"type": "Identifier"
},
"path": [],
"start": 30,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"commentStart": 23,
"end": 32,
@ -36,12 +44,20 @@ expression: actual
},
{
"argument": {
"abs_path": false,
"commentStart": 48,
"end": 50,
"name": "sg",
"name": {
"commentStart": 48,
"end": 50,
"name": "sg",
"start": 48,
"type": "Identifier"
},
"path": [],
"start": 48,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"commentStart": 41,
"end": 50,

View File

@ -28,12 +28,20 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 14,
"end": 15,
"name": "a",
"name": {
"commentStart": 14,
"end": 15,
"name": "a",
"start": 14,
"type": "Identifier"
},
"path": [],
"start": 14,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
{
@ -46,21 +54,37 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 21,
"end": 22,
"name": "b",
"name": {
"commentStart": 21,
"end": 22,
"name": "b",
"start": 21,
"type": "Identifier"
},
"path": [],
"start": 21,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
}
],
"callee": {
"abs_path": false,
"commentStart": 6,
"end": 9,
"name": "foo",
"name": {
"commentStart": 6,
"end": 9,
"name": "foo",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier"
"type": "Name"
},
"commentStart": 6,
"end": 23,

View File

@ -42,21 +42,37 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 19,
"end": 20,
"name": "x",
"name": {
"commentStart": 19,
"end": 20,
"name": "x",
"start": 19,
"type": "Identifier"
},
"path": [],
"start": 19,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
}
],
"callee": {
"abs_path": false,
"commentStart": 11,
"end": 12,
"name": "f",
"name": {
"commentStart": 11,
"end": 12,
"name": "f",
"start": 11,
"type": "Identifier"
},
"path": [],
"start": 11,
"type": "Identifier"
"type": "Name"
},
"commentStart": 11,
"end": 21,

View File

@ -28,12 +28,20 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 28,
"end": 29,
"name": "x",
"name": {
"commentStart": 28,
"end": 29,
"name": "x",
"start": 28,
"type": "Identifier"
},
"path": [],
"start": 28,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
{
@ -46,12 +54,20 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 50,
"end": 51,
"name": "x",
"name": {
"commentStart": 50,
"end": 51,
"name": "x",
"start": 50,
"type": "Identifier"
},
"path": [],
"start": 50,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
{
@ -64,21 +80,37 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 72,
"end": 73,
"name": "x",
"name": {
"commentStart": 72,
"end": 73,
"name": "x",
"start": 72,
"type": "Identifier"
},
"path": [],
"start": 72,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
}
],
"callee": {
"abs_path": false,
"commentStart": 6,
"end": 7,
"name": "f",
"name": {
"commentStart": 6,
"end": 7,
"name": "f",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier"
"type": "Name"
},
"commentStart": 6,
"end": 87,

View File

@ -28,12 +28,20 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 28,
"end": 29,
"name": "x",
"name": {
"commentStart": 28,
"end": 29,
"name": "x",
"start": 28,
"type": "Identifier"
},
"path": [],
"start": 28,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
{
@ -46,21 +54,37 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 75,
"end": 76,
"name": "x",
"name": {
"commentStart": 75,
"end": 76,
"name": "x",
"start": 75,
"type": "Identifier"
},
"path": [],
"start": 75,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
}
],
"callee": {
"abs_path": false,
"commentStart": 6,
"end": 7,
"name": "f",
"name": {
"commentStart": 6,
"end": 7,
"name": "f",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier"
"type": "Name"
},
"commentStart": 6,
"end": 90,

View File

@ -28,21 +28,37 @@ expression: actual
"type": "Identifier"
},
"arg": {
"abs_path": false,
"commentStart": 17,
"end": 18,
"name": "z",
"name": {
"commentStart": 17,
"end": 18,
"name": "z",
"start": 17,
"type": "Identifier"
},
"path": [],
"start": 17,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
}
],
"callee": {
"abs_path": false,
"commentStart": 6,
"end": 9,
"name": "foo",
"name": {
"commentStart": 6,
"end": 9,
"name": "foo",
"start": 6,
"type": "Identifier"
},
"path": [],
"start": 6,
"type": "Identifier"
"type": "Name"
},
"commentStart": 6,
"end": 19,
@ -50,12 +66,20 @@ expression: actual
"type": "CallExpressionKw",
"type": "CallExpressionKw",
"unlabeled": {
"abs_path": false,
"commentStart": 10,
"end": 11,
"name": "x",
"name": {
"commentStart": 10,
"end": 11,
"name": "x",
"start": 10,
"type": "Identifier"
},
"path": [],
"start": 10,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
},
"start": 0,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 19,
"end": 21,
"name": "XY",
"name": {
"commentStart": 19,
"end": 21,
"name": "XY",
"start": 19,
"type": "Identifier"
},
"path": [],
"start": 19,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 5,
"end": 18,
"name": "startSketchOn",
"name": {
"commentStart": 5,
"end": 18,
"name": "startSketchOn",
"start": 5,
"type": "Identifier"
},
"path": [],
"start": 5,
"type": "Identifier"
"type": "Name"
},
"commentStart": 5,
"end": 22,
@ -45,12 +61,20 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 41,
"end": 44,
"name": "pos",
"name": {
"commentStart": 41,
"end": 44,
"name": "pos",
"start": 41,
"type": "Identifier"
},
"path": [],
"start": 41,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
{
"commentStart": 46,
@ -61,11 +85,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 26,
"end": 40,
"name": "startProfileAt",
"name": {
"commentStart": 26,
"end": 40,
"name": "startProfileAt",
"start": 26,
"type": "Identifier"
},
"path": [],
"start": 26,
"type": "Identifier"
"type": "Name"
},
"commentStart": 26,
"end": 48,

View File

@ -21,20 +21,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 19,
"end": 21,
"name": "XY",
"name": {
"commentStart": 19,
"end": 21,
"name": "XY",
"start": 19,
"type": "Identifier"
},
"path": [],
"start": 19,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 5,
"end": 18,
"name": "startSketchOn",
"name": {
"commentStart": 5,
"end": 18,
"name": "startSketchOn",
"start": 5,
"type": "Identifier"
},
"path": [],
"start": 5,
"type": "Identifier"
"type": "Name"
},
"commentStart": 5,
"end": 22,
@ -45,20 +61,36 @@ expression: actual
{
"arguments": [
{
"abs_path": false,
"commentStart": 45,
"end": 48,
"name": "pos",
"name": {
"commentStart": 45,
"end": 48,
"name": "pos",
"start": 45,
"type": "Identifier"
},
"path": [],
"start": 45,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
}
],
"callee": {
"abs_path": false,
"commentStart": 30,
"end": 44,
"name": "startProfileAt",
"name": {
"commentStart": 30,
"end": 44,
"name": "startProfileAt",
"start": 30,
"type": "Identifier"
},
"path": [],
"start": 30,
"type": "Identifier"
"type": "Name"
},
"commentStart": 30,
"end": 49,
@ -85,12 +117,20 @@ expression: actual
},
{
"argument": {
"abs_path": false,
"commentStart": 63,
"end": 68,
"name": "scale",
"name": {
"commentStart": 63,
"end": 68,
"name": "scale",
"start": 63,
"type": "Identifier"
},
"path": [],
"start": 63,
"type": "Identifier",
"type": "Identifier"
"type": "Name",
"type": "Name"
},
"commentStart": 62,
"end": 68,
@ -114,11 +154,19 @@ expression: actual
}
],
"callee": {
"abs_path": false,
"commentStart": 53,
"end": 57,
"name": "line",
"name": {
"commentStart": 53,
"end": 57,
"name": "line",
"start": 53,
"type": "Identifier"
},
"path": [],
"start": 53,
"type": "Identifier"
"type": "Name"
},
"commentStart": 53,
"end": 73,

View File

@ -351,6 +351,8 @@ pub enum TokenType {
Comma,
/// A colon.
Colon,
/// A double colon: `::`
DoubleColon,
/// A period.
Period,
/// A double period: `..`.
@ -393,6 +395,7 @@ impl TryFrom<TokenType> for SemanticTokenType {
| TokenType::Brace
| TokenType::Comma
| TokenType::Colon
| TokenType::DoubleColon
| TokenType::Period
| TokenType::DoublePeriod
| TokenType::Hash

View File

@ -87,8 +87,8 @@ pub(super) fn token(i: &mut Input<'_>) -> PResult<Token> {
'?' => question_mark,
'@' => at,
'0'..='9' => number,
':' => colon,
';' => semi_colon,
':' => alt((double_colon, colon)),
'.' => alt((number, double_period, period)),
'#' => hash,
'$' => dollar,
@ -293,6 +293,15 @@ fn semi_colon(i: &mut Input<'_>) -> PResult<Token> {
))
}
fn double_colon(i: &mut Input<'_>) -> PResult<Token> {
let (value, range) = "::".with_span().parse_next(i)?;
Ok(Token::from_range(
range,
i.state.module_id,
TokenType::DoubleColon,
value.to_string(),
))
}
fn period(i: &mut Input<'_>) -> PResult<Token> {
let (value, range) = '.'.with_span().parse_next(i)?;
Ok(Token::from_range(