Remove annotations from non-code-meta and store them in nodes (#5360)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -60,7 +60,8 @@ export class KclManager {
|
|||||||
nonCodeNodes: {},
|
nonCodeNodes: {},
|
||||||
startNodes: [],
|
startNodes: [],
|
||||||
},
|
},
|
||||||
trivia: [],
|
innerAttrs: [],
|
||||||
|
outerAttrs: [],
|
||||||
}
|
}
|
||||||
private _execState: ExecState = emptyExecState()
|
private _execState: ExecState = emptyExecState()
|
||||||
private _variables: VariableMap = {}
|
private _variables: VariableMap = {}
|
||||||
@ -255,7 +256,8 @@ export class KclManager {
|
|||||||
nonCodeNodes: {},
|
nonCodeNodes: {},
|
||||||
startNodes: [],
|
startNodes: [],
|
||||||
},
|
},
|
||||||
trivia: [],
|
innerAttrs: [],
|
||||||
|
outerAttrs: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -142,7 +142,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -150,7 +150,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -158,7 +158,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -166,7 +166,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -174,7 +174,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -182,7 +182,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -190,7 +190,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
@ -198,7 +198,7 @@ describe('Testing findUniqueName', () => {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
] satisfies Node<Identifier>[]),
|
] satisfies Node<Identifier>[]),
|
||||||
'yo',
|
'yo',
|
||||||
@ -217,7 +217,8 @@ describe('Testing addSketchTo', () => {
|
|||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
nonCodeMeta: { nonCodeNodes: {}, startNodes: [] },
|
nonCodeMeta: { nonCodeNodes: {}, startNodes: [] },
|
||||||
trivia: [],
|
innerAttrs: [],
|
||||||
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
'yz'
|
'yz'
|
||||||
)
|
)
|
||||||
|
@ -278,7 +278,7 @@ export function mutateObjExpProp(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -891,7 +891,7 @@ export function createLiteral(value: LiteralValue | number): Node<Literal> {
|
|||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
value,
|
value,
|
||||||
raw,
|
raw,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -901,7 +901,7 @@ export function createTagDeclarator(value: string): Node<TagDeclarator> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
@ -913,7 +913,7 @@ export function createIdentifier(name: string): Node<Identifier> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
name,
|
name,
|
||||||
}
|
}
|
||||||
@ -925,7 +925,7 @@ export function createPipeSubstitution(): Node<PipeSubstitution> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,13 +938,13 @@ export function createCallExpressionStdLib(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
callee: {
|
callee: {
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
@ -962,13 +962,13 @@ export function createCallExpressionStdLibKw(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
callee: {
|
callee: {
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
@ -986,13 +986,13 @@ export function createCallExpression(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
callee: {
|
callee: {
|
||||||
type: 'Identifier',
|
type: 'Identifier',
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
name,
|
name,
|
||||||
},
|
},
|
||||||
@ -1008,7 +1008,7 @@ export function createArrayExpression(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
nonCodeMeta: nonCodeMetaEmpty(),
|
nonCodeMeta: nonCodeMetaEmpty(),
|
||||||
elements,
|
elements,
|
||||||
@ -1023,7 +1023,7 @@ export function createPipeExpression(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
body,
|
body,
|
||||||
nonCodeMeta: nonCodeMetaEmpty(),
|
nonCodeMeta: nonCodeMetaEmpty(),
|
||||||
@ -1041,14 +1041,14 @@ export function createVariableDeclaration(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
declaration: {
|
declaration: {
|
||||||
type: 'VariableDeclarator',
|
type: 'VariableDeclarator',
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
id: createIdentifier(varName),
|
id: createIdentifier(varName),
|
||||||
init,
|
init,
|
||||||
@ -1066,7 +1066,7 @@ export function createObjectExpression(properties: {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
nonCodeMeta: nonCodeMetaEmpty(),
|
nonCodeMeta: nonCodeMetaEmpty(),
|
||||||
properties: Object.entries(properties).map(([key, value]) => ({
|
properties: Object.entries(properties).map(([key, value]) => ({
|
||||||
@ -1074,7 +1074,7 @@ export function createObjectExpression(properties: {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
key: createIdentifier(key),
|
key: createIdentifier(key),
|
||||||
|
|
||||||
value,
|
value,
|
||||||
@ -1091,7 +1091,7 @@ export function createUnaryExpression(
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
operator,
|
operator,
|
||||||
argument,
|
argument,
|
||||||
@ -1108,7 +1108,7 @@ export function createBinaryExpression([left, operator, right]: [
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
moduleId: 0,
|
moduleId: 0,
|
||||||
trivia: [],
|
outerAttrs: [],
|
||||||
|
|
||||||
operator,
|
operator,
|
||||||
left,
|
left,
|
||||||
|
@ -1945,7 +1945,8 @@ export const updateStartProfileAtArgs: SketchLineHelper['updateArgs'] = ({
|
|||||||
startNodes: [],
|
startNodes: [],
|
||||||
nonCodeNodes: [],
|
nonCodeNodes: [],
|
||||||
},
|
},
|
||||||
trivia: [],
|
innerAttrs: [],
|
||||||
|
outerAttrs: [],
|
||||||
},
|
},
|
||||||
pathToNode,
|
pathToNode,
|
||||||
}
|
}
|
||||||
@ -2527,7 +2528,7 @@ function addTagKw(): addTagFn {
|
|||||||
start: callExpr.node.start,
|
start: callExpr.node.start,
|
||||||
end: callExpr.node.end,
|
end: callExpr.node.end,
|
||||||
moduleId: callExpr.node.moduleId,
|
moduleId: callExpr.node.moduleId,
|
||||||
trivia: callExpr.node.trivia,
|
outerAttrs: callExpr.node.outerAttrs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,14 +5,18 @@ use kittycad_modeling_cmds::coord::{System, KITTYCAD, OPENGL, VULKAN};
|
|||||||
use crate::{
|
use crate::{
|
||||||
errors::KclErrorDetails,
|
errors::KclErrorDetails,
|
||||||
execution::kcl_value::{UnitAngle, UnitLen},
|
execution::kcl_value::{UnitAngle, UnitLen},
|
||||||
parsing::ast::types::{Expr, Node, NonCodeValue, ObjectProperty},
|
parsing::ast::types::{Annotation, Expr, Node, ObjectProperty},
|
||||||
KclError, SourceRange,
|
KclError, SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Annotations which should cause re-execution if they change.
|
||||||
|
pub(super) const SIGNIFICANT_ATTRS: [&str; 2] = [SETTINGS, NO_PRELUDE];
|
||||||
|
|
||||||
pub(crate) const SETTINGS: &str = "settings";
|
pub(crate) const SETTINGS: &str = "settings";
|
||||||
pub(crate) const SETTINGS_UNIT_LENGTH: &str = "defaultLengthUnit";
|
pub(crate) const SETTINGS_UNIT_LENGTH: &str = "defaultLengthUnit";
|
||||||
pub(crate) const SETTINGS_UNIT_ANGLE: &str = "defaultAngleUnit";
|
pub(crate) const SETTINGS_UNIT_ANGLE: &str = "defaultAngleUnit";
|
||||||
pub(super) const NO_PRELUDE: &str = "no_prelude";
|
pub(super) const NO_PRELUDE: &str = "no_prelude";
|
||||||
|
|
||||||
pub(super) const IMPORT_FORMAT: &str = "format";
|
pub(super) const IMPORT_FORMAT: &str = "format";
|
||||||
pub(super) const IMPORT_FORMAT_VALUES: [&str; 9] = ["fbx", "gltf", "glb", "obj", "ply", "sldprt", "stp", "step", "stl"];
|
pub(super) const IMPORT_FORMAT_VALUES: [&str; 9] = ["fbx", "gltf", "glb", "obj", "ply", "sldprt", "stp", "step", "stl"];
|
||||||
pub(super) const IMPORT_COORDS: &str = "coords";
|
pub(super) const IMPORT_COORDS: &str = "coords";
|
||||||
@ -25,36 +29,25 @@ pub(super) enum AnnotationScope {
|
|||||||
Module,
|
Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn is_significant(attr: &&Node<Annotation>) -> bool {
|
||||||
|
match attr.name() {
|
||||||
|
Some(name) => SIGNIFICANT_ATTRS.contains(&name),
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn expect_properties<'a>(
|
pub(super) fn expect_properties<'a>(
|
||||||
for_key: &'static str,
|
for_key: &'static str,
|
||||||
annotation: &'a NonCodeValue,
|
annotation: &'a Node<Annotation>,
|
||||||
source_range: SourceRange,
|
|
||||||
) -> Result<&'a [Node<ObjectProperty>], KclError> {
|
) -> Result<&'a [Node<ObjectProperty>], KclError> {
|
||||||
match annotation {
|
assert_eq!(annotation.name().unwrap(), for_key);
|
||||||
NonCodeValue::Annotation { name, properties } => {
|
Ok(&**annotation.properties.as_ref().ok_or_else(|| {
|
||||||
assert_eq!(name.as_ref().unwrap().name, for_key);
|
|
||||||
Ok(&**properties.as_ref().ok_or_else(|| {
|
|
||||||
KclError::Semantic(KclErrorDetails {
|
KclError::Semantic(KclErrorDetails {
|
||||||
message: format!("Empty `{for_key}` annotation"),
|
message: format!("Empty `{for_key}` annotation"),
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![annotation.as_source_range()],
|
||||||
})
|
})
|
||||||
})?)
|
})?)
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn unnamed_properties<'a>(
|
|
||||||
annotations: impl Iterator<Item = &'a NonCodeValue>,
|
|
||||||
) -> Option<&'a [Node<ObjectProperty>]> {
|
|
||||||
for annotation in annotations {
|
|
||||||
if let NonCodeValue::Annotation { name: None, properties } = annotation {
|
|
||||||
return properties.as_deref();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn expect_ident(expr: &Expr) -> Result<&str, KclError> {
|
pub(super) fn expect_ident(expr: &Expr) -> Result<&str, KclError> {
|
||||||
match expr {
|
match expr {
|
||||||
|
@ -6,8 +6,8 @@ use itertools::{EitherOrBoth, Itertools};
|
|||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
execution::{memory::ProgramMemory, ExecState, ExecutorSettings},
|
execution::{annotations, memory::ProgramMemory, ExecState, ExecutorSettings},
|
||||||
parsing::ast::types::{Node, NonCodeValue, Program},
|
parsing::ast::types::{Annotation, Node, Program},
|
||||||
walk::Node as WalkNode,
|
walk::Node as WalkNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ pub(super) enum CacheResult {
|
|||||||
/// Returns `None` when there are no changes to the program, i.e. it is
|
/// Returns `None` when there are no changes to the program, i.e. it is
|
||||||
/// fully cached.
|
/// fully cached.
|
||||||
pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInformation<'_>) -> CacheResult {
|
pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInformation<'_>) -> CacheResult {
|
||||||
let mut try_reapply_settings = false;
|
let mut reapply_settings = false;
|
||||||
|
|
||||||
// If the settings are different we might need to bust the cache.
|
// If the settings are different we might need to bust the cache.
|
||||||
// We specifically do this before checking if they are the exact same.
|
// We specifically do this before checking if they are the exact same.
|
||||||
@ -107,13 +107,13 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
|
|
||||||
// If anything else is different we may not need to re-execute, but rather just
|
// If anything else is different we may not need to re-execute, but rather just
|
||||||
// run the settings again.
|
// run the settings again.
|
||||||
try_reapply_settings = true;
|
reapply_settings = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the ASTs are the EXACT same we return None.
|
// If the ASTs are the EXACT same we return None.
|
||||||
// We don't even need to waste time computing the digests.
|
// We don't even need to waste time computing the digests.
|
||||||
if old.ast == new.ast {
|
if old.ast == new.ast {
|
||||||
return CacheResult::NoAction(try_reapply_settings);
|
return CacheResult::NoAction(reapply_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to clone just because the digests are stored inline :-(
|
// We have to clone just because the digests are stored inline :-(
|
||||||
@ -127,23 +127,27 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
|
|
||||||
// Check if the digest is the same.
|
// Check if the digest is the same.
|
||||||
if old_ast.digest == new_ast.digest {
|
if old_ast.digest == new_ast.digest {
|
||||||
return CacheResult::NoAction(try_reapply_settings);
|
return CacheResult::NoAction(reapply_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the annotations are different.
|
// Check if the annotations are different.
|
||||||
if !old_ast.annotations().zip_longest(new_ast.annotations()).all(|pair| {
|
if !old_ast
|
||||||
|
.inner_attrs
|
||||||
|
.iter()
|
||||||
|
.filter(annotations::is_significant)
|
||||||
|
.zip_longest(new_ast.inner_attrs.iter().filter(annotations::is_significant))
|
||||||
|
.all(|pair| {
|
||||||
match pair {
|
match pair {
|
||||||
EitherOrBoth::Both(old, new) => {
|
EitherOrBoth::Both(old, new) => {
|
||||||
// Compare annotations, ignoring source ranges. Digests must
|
// Compare annotations, ignoring source ranges. Digests must
|
||||||
// have been computed before this.
|
// have been computed before this.
|
||||||
match (&old.value, &new.value) {
|
let Annotation { name, properties, .. } = &old.inner;
|
||||||
(
|
let Annotation {
|
||||||
NonCodeValue::Annotation { name, properties },
|
|
||||||
NonCodeValue::Annotation {
|
|
||||||
name: new_name,
|
name: new_name,
|
||||||
properties: new_properties,
|
properties: new_properties,
|
||||||
},
|
..
|
||||||
) => {
|
} = &new.inner;
|
||||||
|
|
||||||
name.as_ref().map(|n| n.digest) == new_name.as_ref().map(|n| n.digest)
|
name.as_ref().map(|n| n.digest) == new_name.as_ref().map(|n| n.digest)
|
||||||
&& properties
|
&& properties
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@ -154,10 +158,8 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
_ => false,
|
{
|
||||||
}
|
|
||||||
}) {
|
|
||||||
// If any of the annotations are different at the beginning of the
|
// If any of the annotations are different at the beginning of the
|
||||||
// program, it's likely the settings, and we have to bust the cache and
|
// program, it's likely the settings, and we have to bust the cache and
|
||||||
// re-execute the whole thing.
|
// re-execute the whole thing.
|
||||||
@ -169,12 +171,7 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the changes were only to Non-code areas, like comments or whitespace.
|
// Check if the changes were only to Non-code areas, like comments or whitespace.
|
||||||
let (clear_scene, program) = generate_changed_program(old_ast, new_ast);
|
generate_changed_program(old_ast, new_ast, reapply_settings)
|
||||||
CacheResult::ReExecute {
|
|
||||||
clear_scene,
|
|
||||||
reapply_settings: try_reapply_settings,
|
|
||||||
program,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Force-generate a new CacheResult, even if one shouldn't be made. The
|
/// Force-generate a new CacheResult, even if one shouldn't be made. The
|
||||||
@ -183,7 +180,7 @@ pub(super) async fn get_changed_program(old: CacheInformation<'_>, new: CacheInf
|
|||||||
/// how we construct a new [CacheResult].
|
/// how we construct a new [CacheResult].
|
||||||
///
|
///
|
||||||
/// Digests *must* be computed before calling this.
|
/// Digests *must* be computed before calling this.
|
||||||
fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>) -> (bool, Node<Program>) {
|
fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>, reapply_settings: bool) -> CacheResult {
|
||||||
if !old_ast.body.iter().zip(new_ast.body.iter()).all(|(old, new)| {
|
if !old_ast.body.iter().zip(new_ast.body.iter()).all(|(old, new)| {
|
||||||
let old_node: WalkNode = old.into();
|
let old_node: WalkNode = old.into();
|
||||||
let new_node: WalkNode = new.into();
|
let new_node: WalkNode = new.into();
|
||||||
@ -194,7 +191,11 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>)
|
|||||||
// means a single insertion or deletion will result in a cache
|
// means a single insertion or deletion will result in a cache
|
||||||
// bust.
|
// bust.
|
||||||
|
|
||||||
return (true, new_ast);
|
return CacheResult::ReExecute {
|
||||||
|
clear_scene: true,
|
||||||
|
reapply_settings,
|
||||||
|
program: new_ast,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise the overlapping section of the ast bodies matches.
|
// otherwise the overlapping section of the ast bodies matches.
|
||||||
@ -210,7 +211,11 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>)
|
|||||||
// supporting that.
|
// supporting that.
|
||||||
|
|
||||||
// Cache bust time.
|
// Cache bust time.
|
||||||
(true, new_ast)
|
CacheResult::ReExecute {
|
||||||
|
clear_scene: true,
|
||||||
|
reapply_settings,
|
||||||
|
program: new_ast,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
// the new AST is longer than the old AST, which means
|
// the new AST is longer than the old AST, which means
|
||||||
@ -222,7 +227,11 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>)
|
|||||||
|
|
||||||
new_ast.body = new_ast.body[old_ast.body.len()..].to_owned();
|
new_ast.body = new_ast.body[old_ast.body.len()..].to_owned();
|
||||||
|
|
||||||
(false, new_ast)
|
CacheResult::ReExecute {
|
||||||
|
clear_scene: false,
|
||||||
|
reapply_settings,
|
||||||
|
program: new_ast,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
// currently unreachable, but let's pretend like the code
|
// currently unreachable, but let's pretend like the code
|
||||||
@ -234,9 +243,7 @@ fn generate_changed_program(old_ast: Node<Program>, mut new_ast: Node<Program>)
|
|||||||
// so but i think many things. This def needs to change
|
// so but i think many things. This def needs to change
|
||||||
// when the code above changes.
|
// when the code above changes.
|
||||||
|
|
||||||
new_ast.body = vec![];
|
CacheResult::NoAction(reapply_settings)
|
||||||
|
|
||||||
(false, new_ast)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,8 +375,10 @@ shell(firstSketch, faces = ['end'], thickness = 0.25)"#;
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_get_changed_program_same_code_changed_code_comments() {
|
async fn test_get_changed_program_same_code_changed_code_comments_attrs() {
|
||||||
let old = r#" // Removed the end face for the extrusion.
|
let old = r#"@foo(whatever = whatever)
|
||||||
|
@bar
|
||||||
|
// Removed the end face for the extrusion.
|
||||||
firstSketch = startSketchOn('XY')
|
firstSketch = startSketchOn('XY')
|
||||||
|> startProfileAt([-12, 12], %)
|
|> startProfileAt([-12, 12], %)
|
||||||
|> line(end = [24, 0])
|
|> line(end = [24, 0])
|
||||||
@ -381,7 +390,9 @@ firstSketch = startSketchOn('XY')
|
|||||||
// Remove the end face for the extrusion.
|
// Remove the end face for the extrusion.
|
||||||
shell(firstSketch, faces = ['end'], thickness = 0.25) "#;
|
shell(firstSketch, faces = ['end'], thickness = 0.25) "#;
|
||||||
|
|
||||||
let new = r#"// Remove the end face for the extrusion.
|
let new = r#"@foo(whatever = 42)
|
||||||
|
@baz
|
||||||
|
// Remove the end face for the extrusion.
|
||||||
firstSketch = startSketchOn('XY')
|
firstSketch = startSketchOn('XY')
|
||||||
|> startProfileAt([-12, 12], %)
|
|> startProfileAt([-12, 12], %)
|
||||||
|> line(end = [24, 0])
|
|> line(end = [24, 0])
|
||||||
|
@ -17,9 +17,9 @@ use crate::{
|
|||||||
},
|
},
|
||||||
modules::{ModuleId, ModulePath, ModuleRepr},
|
modules::{ModuleId, ModulePath, ModuleRepr},
|
||||||
parsing::ast::types::{
|
parsing::ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
|
Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem,
|
||||||
CallExpressionKw, Expr, FunctionExpression, IfExpression, ImportPath, ImportSelector, ItemVisibility,
|
CallExpression, CallExpressionKw, Expr, FunctionExpression, IfExpression, ImportPath, ImportSelector,
|
||||||
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NodeRef, NonCodeNode, NonCodeValue,
|
ItemVisibility, LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NodeRef,
|
||||||
ObjectExpression, PipeExpression, Program, TagDeclarator, UnaryExpression, UnaryOperator,
|
ObjectExpression, PipeExpression, Program, TagDeclarator, UnaryExpression, UnaryOperator,
|
||||||
},
|
},
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
@ -37,37 +37,36 @@ enum StatementKind<'a> {
|
|||||||
impl ExecutorContext {
|
impl ExecutorContext {
|
||||||
async fn handle_annotations(
|
async fn handle_annotations(
|
||||||
&self,
|
&self,
|
||||||
annotations: impl Iterator<Item = (&NonCodeValue, SourceRange)>,
|
annotations: impl Iterator<Item = &Node<Annotation>>,
|
||||||
scope: annotations::AnnotationScope,
|
scope: annotations::AnnotationScope,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
) -> Result<bool, KclError> {
|
) -> Result<bool, KclError> {
|
||||||
let mut no_prelude = false;
|
let mut no_prelude = false;
|
||||||
for (annotation, source_range) in annotations {
|
for annotation in annotations {
|
||||||
if annotation.annotation_name() == Some(annotations::SETTINGS) {
|
if annotation.name() == Some(annotations::SETTINGS) {
|
||||||
if scope == annotations::AnnotationScope::Module {
|
if scope == annotations::AnnotationScope::Module {
|
||||||
let old_units = exec_state.length_unit();
|
let old_units = exec_state.length_unit();
|
||||||
exec_state
|
exec_state.mod_local.settings.update_from_annotation(annotation)?;
|
||||||
.mod_local
|
|
||||||
.settings
|
|
||||||
.update_from_annotation(annotation, source_range)?;
|
|
||||||
let new_units = exec_state.length_unit();
|
let new_units = exec_state.length_unit();
|
||||||
if !self.engine.execution_kind().is_isolated() && old_units != new_units {
|
if !self.engine.execution_kind().is_isolated() && old_units != new_units {
|
||||||
self.engine.set_units(new_units.into(), source_range).await?;
|
self.engine
|
||||||
|
.set_units(new_units.into(), annotation.as_source_range())
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: "Settings can only be modified at the top level scope of a file".to_owned(),
|
message: "Settings can only be modified at the top level scope of a file".to_owned(),
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![annotation.as_source_range()],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if annotation.annotation_name() == Some(annotations::NO_PRELUDE) {
|
if annotation.name() == Some(annotations::NO_PRELUDE) {
|
||||||
if scope == annotations::AnnotationScope::Module {
|
if scope == annotations::AnnotationScope::Module {
|
||||||
no_prelude = true;
|
no_prelude = true;
|
||||||
} else {
|
} else {
|
||||||
return Err(KclError::Semantic(KclErrorDetails {
|
return Err(KclError::Semantic(KclErrorDetails {
|
||||||
message: "Prelude can only be skipped at the top level scope of a file".to_owned(),
|
message: "Prelude can only be skipped at the top level scope of a file".to_owned(),
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![annotation.as_source_range()],
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,11 +86,7 @@ impl ExecutorContext {
|
|||||||
if body_type == BodyType::Root {
|
if body_type == BodyType::Root {
|
||||||
let _no_prelude = self
|
let _no_prelude = self
|
||||||
.handle_annotations(
|
.handle_annotations(
|
||||||
program
|
program.inner_attrs.iter(),
|
||||||
.non_code_meta
|
|
||||||
.start_nodes
|
|
||||||
.iter()
|
|
||||||
.filter_map(|n| n.annotation().map(|result| (result, n.as_source_range()))),
|
|
||||||
annotations::AnnotationScope::Module,
|
annotations::AnnotationScope::Module,
|
||||||
exec_state,
|
exec_state,
|
||||||
)
|
)
|
||||||
@ -100,7 +95,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let mut last_expr = None;
|
let mut last_expr = None;
|
||||||
// Iterate over the body of the program.
|
// Iterate over the body of the program.
|
||||||
for (i, statement) in program.body.iter().enumerate() {
|
for statement in &program.body {
|
||||||
match statement {
|
match statement {
|
||||||
BodyItem::ImportStatement(import_stmt) => {
|
BodyItem::ImportStatement(import_stmt) => {
|
||||||
if body_type != BodyType::Root {
|
if body_type != BodyType::Root {
|
||||||
@ -111,9 +106,9 @@ impl ExecutorContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let source_range = SourceRange::from(import_stmt);
|
let source_range = SourceRange::from(import_stmt);
|
||||||
let meta_nodes = program.non_code_meta.get(i);
|
let attrs = &import_stmt.outer_attrs;
|
||||||
let module_id = self
|
let module_id = self
|
||||||
.open_module(&import_stmt.path, meta_nodes, exec_state, source_range)
|
.open_module(&import_stmt.path, attrs, exec_state, source_range)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match &import_stmt.selector {
|
match &import_stmt.selector {
|
||||||
@ -209,7 +204,7 @@ impl ExecutorContext {
|
|||||||
let source_range = SourceRange::from(&variable_declaration.declaration.init);
|
let source_range = SourceRange::from(&variable_declaration.declaration.init);
|
||||||
let metadata = Metadata { source_range };
|
let metadata = Metadata { source_range };
|
||||||
|
|
||||||
let _meta_nodes = program.non_code_meta.get(i);
|
let _annotations = &variable_declaration.outer_attrs;
|
||||||
|
|
||||||
let memory_item = self
|
let memory_item = self
|
||||||
.execute_expr(
|
.execute_expr(
|
||||||
@ -279,7 +274,7 @@ impl ExecutorContext {
|
|||||||
async fn open_module(
|
async fn open_module(
|
||||||
&self,
|
&self,
|
||||||
path: &ImportPath,
|
path: &ImportPath,
|
||||||
non_code_meta: &[Node<NonCodeNode>],
|
attrs: &[Node<Annotation>],
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
source_range: SourceRange,
|
source_range: SourceRange,
|
||||||
) -> Result<ModuleId, KclError> {
|
) -> Result<ModuleId, KclError> {
|
||||||
@ -307,7 +302,7 @@ impl ExecutorContext {
|
|||||||
|
|
||||||
let id = exec_state.next_module_id();
|
let id = exec_state.next_module_id();
|
||||||
let path = resolved_path.expect_path();
|
let path = resolved_path.expect_path();
|
||||||
let format = super::import::format_from_annotations(non_code_meta, path, source_range)?;
|
let format = super::import::format_from_annotations(attrs, path, source_range)?;
|
||||||
let geom = super::import::import_foreign(path, format, exec_state, self, source_range).await?;
|
let geom = super::import::import_foreign(path, format, exec_state, self, source_range).await?;
|
||||||
exec_state.add_module(id, resolved_path, ModuleRepr::Foreign(geom));
|
exec_state.add_module(id, resolved_path, ModuleRepr::Foreign(geom));
|
||||||
Ok(id)
|
Ok(id)
|
||||||
@ -1838,18 +1833,7 @@ mod test {
|
|||||||
// Run each test.
|
// Run each test.
|
||||||
let func_expr = &Node::no_src(FunctionExpression {
|
let func_expr = &Node::no_src(FunctionExpression {
|
||||||
params,
|
params,
|
||||||
body: Node {
|
body: crate::parsing::ast::types::Program::empty(),
|
||||||
inner: crate::parsing::ast::types::Program {
|
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: Default::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
},
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
module_id: ModuleId::default(),
|
|
||||||
trivia: Vec::new(),
|
|
||||||
},
|
|
||||||
return_type: None,
|
return_type: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
errors::{KclError, KclErrorDetails},
|
errors::{KclError, KclErrorDetails},
|
||||||
execution::{annotations, kcl_value::UnitLen, ExecState, ExecutorContext, ImportedGeometry},
|
execution::{annotations, kcl_value::UnitLen, ExecState, ExecutorContext, ImportedGeometry},
|
||||||
fs::FileSystem,
|
fs::FileSystem,
|
||||||
parsing::ast::types::{Node, NonCodeNode},
|
parsing::ast::types::{Annotation, Node},
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -155,16 +155,18 @@ pub async fn import_foreign(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn format_from_annotations(
|
pub(super) fn format_from_annotations(
|
||||||
non_code_meta: &[Node<NonCodeNode>],
|
annotations: &[Node<Annotation>],
|
||||||
path: &Path,
|
path: &Path,
|
||||||
import_source_range: SourceRange,
|
import_source_range: SourceRange,
|
||||||
) -> Result<Option<InputFormat>, KclError> {
|
) -> Result<Option<InputFormat>, KclError> {
|
||||||
let Some(props) = annotations::unnamed_properties(non_code_meta.iter().map(|n| &n.value)) else {
|
if annotations.is_empty() {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
}
|
||||||
|
|
||||||
|
let props = annotations.iter().flat_map(|a| a.properties.as_deref().unwrap_or(&[]));
|
||||||
|
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
for p in props {
|
for p in props.clone() {
|
||||||
if p.key.name == annotations::IMPORT_FORMAT {
|
if p.key.name == annotations::IMPORT_FORMAT {
|
||||||
result = Some(
|
result = Some(
|
||||||
get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| {
|
get_import_format_from_extension(annotations::expect_ident(&p.value)?).map_err(|_| {
|
||||||
@ -422,8 +424,8 @@ mod test {
|
|||||||
// no format, no options
|
// no format, no options
|
||||||
let text = "@()\nimport '../foo.gltf' as foo";
|
let text = "@()\nimport '../foo.gltf' as foo";
|
||||||
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
||||||
let non_code_meta = parsed.non_code_meta.get(0);
|
let attrs = parsed.body[0].get_attrs();
|
||||||
let fmt = format_from_annotations(non_code_meta, Path::new("../foo.gltf"), SourceRange::default())
|
let fmt = format_from_annotations(attrs, Path::new("../foo.gltf"), SourceRange::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -434,8 +436,8 @@ mod test {
|
|||||||
// format, no options
|
// format, no options
|
||||||
let text = "@(format = gltf)\nimport '../foo.txt' as foo";
|
let text = "@(format = gltf)\nimport '../foo.txt' as foo";
|
||||||
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
||||||
let non_code_meta = parsed.non_code_meta.get(0);
|
let attrs = parsed.body[0].get_attrs();
|
||||||
let fmt = format_from_annotations(non_code_meta, Path::new("../foo.txt"), SourceRange::default())
|
let fmt = format_from_annotations(attrs, Path::new("../foo.txt"), SourceRange::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -444,7 +446,7 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// format, no extension (wouldn't parse but might some day)
|
// format, no extension (wouldn't parse but might some day)
|
||||||
let fmt = format_from_annotations(non_code_meta, Path::new("../foo"), SourceRange::default())
|
let fmt = format_from_annotations(attrs, Path::new("../foo"), SourceRange::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -455,8 +457,8 @@ mod test {
|
|||||||
// format, options
|
// format, options
|
||||||
let text = "@(format = obj, coords = vulkan, lengthUnit = ft)\nimport '../foo.txt' as foo";
|
let text = "@(format = obj, coords = vulkan, lengthUnit = ft)\nimport '../foo.txt' as foo";
|
||||||
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
||||||
let non_code_meta = parsed.non_code_meta.get(0);
|
let attrs = parsed.body[0].get_attrs();
|
||||||
let fmt = format_from_annotations(non_code_meta, Path::new("../foo.txt"), SourceRange::default())
|
let fmt = format_from_annotations(attrs, Path::new("../foo.txt"), SourceRange::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -470,8 +472,8 @@ mod test {
|
|||||||
// no format, options
|
// no format, options
|
||||||
let text = "@(coords = vulkan, lengthUnit = ft)\nimport '../foo.obj' as foo";
|
let text = "@(coords = vulkan, lengthUnit = ft)\nimport '../foo.obj' as foo";
|
||||||
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
let parsed = crate::Program::parse_no_errs(text).unwrap().ast;
|
||||||
let non_code_meta = parsed.non_code_meta.get(0);
|
let attrs = parsed.body[0].get_attrs();
|
||||||
let fmt = format_from_annotations(non_code_meta, Path::new("../foo.obj"), SourceRange::default())
|
let fmt = format_from_annotations(attrs, Path::new("../foo.obj"), SourceRange::default())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -523,8 +525,8 @@ mod test {
|
|||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_annotation_error(src: &str, path: &str, expected: &str) {
|
fn assert_annotation_error(src: &str, path: &str, expected: &str) {
|
||||||
let parsed = crate::Program::parse_no_errs(src).unwrap().ast;
|
let parsed = crate::Program::parse_no_errs(src).unwrap().ast;
|
||||||
let non_code_meta = parsed.non_code_meta.get(0);
|
let attrs = parsed.body[0].get_attrs();
|
||||||
let err = format_from_annotations(non_code_meta, Path::new(path), SourceRange::default()).unwrap_err();
|
let err = format_from_annotations(attrs, Path::new(path), SourceRange::default()).unwrap_err();
|
||||||
assert!(
|
assert!(
|
||||||
err.message().contains(expected),
|
err.message().contains(expected),
|
||||||
"Expected: `{expected}`, found `{}`",
|
"Expected: `{expected}`, found `{}`",
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
ExecOutcome, ExecutorSettings, KclValue, Operation, UnitAngle, UnitLen,
|
ExecOutcome, ExecutorSettings, KclValue, Operation, UnitAngle, UnitLen,
|
||||||
},
|
},
|
||||||
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr},
|
modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr},
|
||||||
parsing::ast::types::NonCodeValue,
|
parsing::ast::types::Annotation,
|
||||||
source_range::SourceRange,
|
source_range::SourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -236,21 +236,20 @@ pub struct MetaSettings {
|
|||||||
impl MetaSettings {
|
impl MetaSettings {
|
||||||
pub(crate) fn update_from_annotation(
|
pub(crate) fn update_from_annotation(
|
||||||
&mut self,
|
&mut self,
|
||||||
annotation: &NonCodeValue,
|
annotation: &crate::parsing::ast::types::Node<Annotation>,
|
||||||
source_range: SourceRange,
|
|
||||||
) -> Result<(), KclError> {
|
) -> Result<(), KclError> {
|
||||||
let properties = annotations::expect_properties(annotations::SETTINGS, annotation, source_range)?;
|
let properties = annotations::expect_properties(annotations::SETTINGS, annotation)?;
|
||||||
|
|
||||||
for p in properties {
|
for p in properties {
|
||||||
match &*p.inner.key.name {
|
match &*p.inner.key.name {
|
||||||
annotations::SETTINGS_UNIT_LENGTH => {
|
annotations::SETTINGS_UNIT_LENGTH => {
|
||||||
let value = annotations::expect_ident(&p.inner.value)?;
|
let value = annotations::expect_ident(&p.inner.value)?;
|
||||||
let value = kcl_value::UnitLen::from_str(value, source_range)?;
|
let value = kcl_value::UnitLen::from_str(value, annotation.as_source_range())?;
|
||||||
self.default_length_units = value;
|
self.default_length_units = value;
|
||||||
}
|
}
|
||||||
annotations::SETTINGS_UNIT_ANGLE => {
|
annotations::SETTINGS_UNIT_ANGLE => {
|
||||||
let value = annotations::expect_ident(&p.inner.value)?;
|
let value = annotations::expect_ident(&p.inner.value)?;
|
||||||
let value = kcl_value::UnitAngle::from_str(value, source_range)?;
|
let value = kcl_value::UnitAngle::from_str(value, annotation.as_source_range())?;
|
||||||
self.default_angle_units = value;
|
self.default_angle_units = value;
|
||||||
}
|
}
|
||||||
name => {
|
name => {
|
||||||
@ -260,7 +259,7 @@ impl MetaSettings {
|
|||||||
annotations::SETTINGS_UNIT_LENGTH,
|
annotations::SETTINGS_UNIT_LENGTH,
|
||||||
annotations::SETTINGS_UNIT_ANGLE
|
annotations::SETTINGS_UNIT_ANGLE
|
||||||
),
|
),
|
||||||
source_ranges: vec![source_range],
|
source_ranges: vec![annotation.as_source_range()],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
use sha2::{Digest as DigestTrait, Sha256};
|
use sha2::{Digest as DigestTrait, Sha256};
|
||||||
|
|
||||||
use super::types::{
|
use super::types::{DefaultParamVal, ItemVisibility, LabelledExpression, LiteralValue, VariableKind};
|
||||||
DefaultParamVal, ItemVisibility, LabelledExpression, LiteralValue, NonCodeMeta, NonCodeNode, NonCodeValue,
|
|
||||||
VariableKind,
|
|
||||||
};
|
|
||||||
use crate::parsing::ast::types::{
|
use crate::parsing::ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression, CallExpressionKw,
|
Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression,
|
||||||
ElseIf, Expr, ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem,
|
CallExpressionKw, ElseIf, Expr, ExpressionStatement, FnArgType, FunctionExpression, Identifier, IfExpression,
|
||||||
ImportSelector, ImportStatement, KclNone, Literal, LiteralIdentifier, MemberExpression, MemberObject,
|
ImportItem, ImportSelector, ImportStatement, KclNone, Literal, LiteralIdentifier, MemberExpression, MemberObject,
|
||||||
ObjectExpression, ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement,
|
ObjectExpression, ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement,
|
||||||
TagDeclarator, UnaryExpression, VariableDeclaration, VariableDeclarator,
|
TagDeclarator, UnaryExpression, VariableDeclaration, VariableDeclarator,
|
||||||
};
|
};
|
||||||
@ -82,49 +79,22 @@ impl Program {
|
|||||||
for body_item in slf.body.iter_mut() {
|
for body_item in slf.body.iter_mut() {
|
||||||
hasher.update(body_item.compute_digest());
|
hasher.update(body_item.compute_digest());
|
||||||
}
|
}
|
||||||
// This contains settings annotations.
|
for attr in &mut slf.inner_attrs {
|
||||||
hasher.update(slf.non_code_meta.compute_digest());
|
hasher.update(attr.compute_digest());
|
||||||
|
}
|
||||||
if let Some(shebang) = &slf.shebang {
|
if let Some(shebang) = &slf.shebang {
|
||||||
hasher.update(&shebang.inner.content);
|
hasher.update(&shebang.inner.content);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonCodeMeta {
|
impl Annotation {
|
||||||
compute_digest!(|slf, hasher| {
|
|
||||||
for non_code_node in slf.start_nodes.iter_mut() {
|
|
||||||
hasher.update(non_code_node.compute_digest());
|
|
||||||
}
|
|
||||||
for (_, non_code_nodes) in slf.non_code_nodes.iter_mut() {
|
|
||||||
for non_code_node in non_code_nodes.iter_mut() {
|
|
||||||
hasher.update(non_code_node.compute_digest());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NonCodeNode {
|
|
||||||
compute_digest!(|slf, hasher| {
|
|
||||||
hasher.update(slf.value.compute_digest());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NonCodeValue {
|
|
||||||
pub fn compute_digest(&mut self) -> Digest {
|
pub fn compute_digest(&mut self) -> Digest {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
match self {
|
if let Some(name) = &mut self.name {
|
||||||
NonCodeValue::InlineComment { .. } => {}
|
|
||||||
NonCodeValue::BlockComment { .. } => {}
|
|
||||||
NonCodeValue::NewLineBlockComment { .. } => {}
|
|
||||||
NonCodeValue::NewLine => {}
|
|
||||||
NonCodeValue::Annotation {
|
|
||||||
ref mut name,
|
|
||||||
properties,
|
|
||||||
} => {
|
|
||||||
if let Some(name) = name {
|
|
||||||
hasher.update(name.compute_digest());
|
hasher.update(name.compute_digest());
|
||||||
}
|
}
|
||||||
if let Some(properties) = properties {
|
if let Some(properties) = &mut self.properties {
|
||||||
hasher.update(properties.len().to_ne_bytes());
|
hasher.update(properties.len().to_ne_bytes());
|
||||||
for property in properties.iter_mut() {
|
for property in properties.iter_mut() {
|
||||||
hasher.update(property.compute_digest());
|
hasher.update(property.compute_digest());
|
||||||
@ -132,20 +102,24 @@ impl NonCodeValue {
|
|||||||
} else {
|
} else {
|
||||||
hasher.update("no_properties");
|
hasher.update("no_properties");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
hasher.finalize().into()
|
hasher.finalize().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyItem {
|
impl BodyItem {
|
||||||
pub fn compute_digest(&mut self) -> Digest {
|
pub fn compute_digest(&mut self) -> Digest {
|
||||||
match self {
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(match self {
|
||||||
BodyItem::ImportStatement(s) => s.compute_digest(),
|
BodyItem::ImportStatement(s) => s.compute_digest(),
|
||||||
BodyItem::ExpressionStatement(es) => es.compute_digest(),
|
BodyItem::ExpressionStatement(es) => es.compute_digest(),
|
||||||
BodyItem::VariableDeclaration(vs) => vs.compute_digest(),
|
BodyItem::VariableDeclaration(vs) => vs.compute_digest(),
|
||||||
BodyItem::ReturnStatement(rs) => rs.compute_digest(),
|
BodyItem::ReturnStatement(rs) => rs.compute_digest(),
|
||||||
|
});
|
||||||
|
|
||||||
|
for a in self.get_attrs_mut() {
|
||||||
|
hasher.update(a.compute_digest());
|
||||||
}
|
}
|
||||||
|
hasher.finalize().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ pub struct Node<T> {
|
|||||||
#[serde(default, skip_serializing_if = "ModuleId::is_top_level")]
|
#[serde(default, skip_serializing_if = "ModuleId::is_top_level")]
|
||||||
pub module_id: ModuleId,
|
pub module_id: ModuleId,
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
pub trivia: NodeList<NonCodeNode>,
|
pub outer_attrs: NodeList<Annotation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Node<T> {
|
impl<T> Node<T> {
|
||||||
@ -96,7 +96,7 @@ impl<T> Node<T> {
|
|||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
module_id,
|
module_id,
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ impl<T> Node<T> {
|
|||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
module_id: ModuleId::default(),
|
module_id: ModuleId::default(),
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ impl<T> Node<T> {
|
|||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
module_id,
|
module_id,
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +181,8 @@ pub struct Program {
|
|||||||
pub non_code_meta: NonCodeMeta,
|
pub non_code_meta: NonCodeMeta,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub shebang: Option<Node<Shebang>>,
|
pub shebang: Option<Node<Shebang>>,
|
||||||
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub inner_attrs: NodeList<Annotation>,
|
||||||
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
#[ts(optional)]
|
#[ts(optional)]
|
||||||
@ -261,28 +263,12 @@ impl Node<Program> {
|
|||||||
Ok(findings)
|
Ok(findings)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn annotations(&self) -> impl Iterator<Item = &Node<NonCodeNode>> {
|
|
||||||
self.non_code_meta
|
|
||||||
.start_nodes
|
|
||||||
.iter()
|
|
||||||
.filter(|n| n.value_is_annotation())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn annotations_mut(&mut self) -> impl Iterator<Item = &mut Node<NonCodeNode>> {
|
|
||||||
self.non_code_meta
|
|
||||||
.start_nodes
|
|
||||||
.iter_mut()
|
|
||||||
.filter(|n| n.value_is_annotation())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the annotations for the meta settings from the kcl file.
|
/// Get the annotations for the meta settings from the kcl file.
|
||||||
pub fn meta_settings(&self) -> Result<Option<crate::execution::MetaSettings>, KclError> {
|
pub fn meta_settings(&self) -> Result<Option<crate::execution::MetaSettings>, KclError> {
|
||||||
for annotation_node in self.annotations() {
|
for annotation in &self.inner_attrs {
|
||||||
let annotation = &annotation_node.value;
|
if annotation.name() == Some(annotations::SETTINGS) {
|
||||||
if annotation.annotation_name() == Some(annotations::SETTINGS) {
|
|
||||||
let source_range = annotation_node.as_source_range();
|
|
||||||
let mut meta_settings = crate::execution::MetaSettings::default();
|
let mut meta_settings = crate::execution::MetaSettings::default();
|
||||||
meta_settings.update_from_annotation(annotation, source_range)?;
|
meta_settings.update_from_annotation(annotation)?;
|
||||||
return Ok(Some(meta_settings));
|
return Ok(Some(meta_settings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,24 +279,18 @@ impl Node<Program> {
|
|||||||
pub fn change_meta_settings(&mut self, settings: crate::execution::MetaSettings) -> Result<Self, KclError> {
|
pub fn change_meta_settings(&mut self, settings: crate::execution::MetaSettings) -> Result<Self, KclError> {
|
||||||
let mut new_program = self.clone();
|
let mut new_program = self.clone();
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for node in new_program.annotations_mut() {
|
for node in &mut new_program.inner_attrs {
|
||||||
if node.value.annotation_name() == Some(annotations::SETTINGS) {
|
if node.name() == Some(annotations::SETTINGS) {
|
||||||
let annotation = NonCodeValue::new_from_meta_settings(&settings);
|
*node = Node::no_src(Annotation::new_from_meta_settings(&settings));
|
||||||
*node = Node::no_src(NonCodeNode {
|
|
||||||
value: annotation,
|
|
||||||
digest: None,
|
|
||||||
});
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
let annotation = NonCodeValue::new_from_meta_settings(&settings);
|
new_program
|
||||||
new_program.non_code_meta.start_nodes.push(Node::no_src(NonCodeNode {
|
.inner_attrs
|
||||||
value: annotation,
|
.push(Node::no_src(Annotation::new_from_meta_settings(&settings)));
|
||||||
digest: None,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(new_program)
|
Ok(new_program)
|
||||||
@ -318,6 +298,10 @@ impl Node<Program> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn empty() -> Node<Self> {
|
||||||
|
Node::no_src(Program::default())
|
||||||
|
}
|
||||||
/// Is the last body item an expression?
|
/// Is the last body item an expression?
|
||||||
pub fn ends_with_expr(&self) -> bool {
|
pub fn ends_with_expr(&self) -> bool {
|
||||||
let Some(ref last) = self.body.last() else {
|
let Some(ref last) = self.body.last() else {
|
||||||
@ -629,6 +613,33 @@ impl BodyItem {
|
|||||||
BodyItem::ReturnStatement(return_statement) => return_statement.end,
|
BodyItem::ReturnStatement(return_statement) => return_statement.end,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_attrs(&mut self, attr: NodeList<Annotation>) {
|
||||||
|
match self {
|
||||||
|
BodyItem::ImportStatement(node) => node.outer_attrs = attr,
|
||||||
|
BodyItem::ExpressionStatement(node) => node.outer_attrs = attr,
|
||||||
|
BodyItem::VariableDeclaration(node) => node.outer_attrs = attr,
|
||||||
|
BodyItem::ReturnStatement(node) => node.outer_attrs = attr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_attrs(&self) -> &[Node<Annotation>] {
|
||||||
|
match self {
|
||||||
|
BodyItem::ImportStatement(node) => &node.outer_attrs,
|
||||||
|
BodyItem::ExpressionStatement(node) => &node.outer_attrs,
|
||||||
|
BodyItem::VariableDeclaration(node) => &node.outer_attrs,
|
||||||
|
BodyItem::ReturnStatement(node) => &node.outer_attrs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_attrs_mut(&mut self) -> &mut [Node<Annotation>] {
|
||||||
|
match self {
|
||||||
|
BodyItem::ImportStatement(node) => &mut node.outer_attrs,
|
||||||
|
BodyItem::ExpressionStatement(node) => &mut node.outer_attrs,
|
||||||
|
BodyItem::VariableDeclaration(node) => &mut node.outer_attrs,
|
||||||
|
BodyItem::ReturnStatement(node) => &mut node.outer_attrs,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<BodyItem> for SourceRange {
|
impl From<BodyItem> for SourceRange {
|
||||||
@ -1134,24 +1145,6 @@ impl NonCodeNode {
|
|||||||
NonCodeValue::BlockComment { value, style: _ } => value.clone(),
|
NonCodeValue::BlockComment { value, style: _ } => value.clone(),
|
||||||
NonCodeValue::NewLineBlockComment { value, style: _ } => value.clone(),
|
NonCodeValue::NewLineBlockComment { value, style: _ } => value.clone(),
|
||||||
NonCodeValue::NewLine => "\n\n".to_string(),
|
NonCodeValue::NewLine => "\n\n".to_string(),
|
||||||
n @ NonCodeValue::Annotation { .. } => n.annotation_name().unwrap_or("").to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn annotation(&self) -> Option<&NonCodeValue> {
|
|
||||||
match &self.value {
|
|
||||||
a @ NonCodeValue::Annotation { .. } => Some(a),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn value_is_annotation(&self) -> bool {
|
|
||||||
match self.value {
|
|
||||||
NonCodeValue::InlineComment { .. }
|
|
||||||
| NonCodeValue::BlockComment { .. }
|
|
||||||
| NonCodeValue::NewLineBlockComment { .. }
|
|
||||||
| NonCodeValue::NewLine => false,
|
|
||||||
NonCodeValue::Annotation { .. } => true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1202,37 +1195,6 @@ pub enum NonCodeValue {
|
|||||||
// A new line like `\n\n` NOT a new line like `\n`.
|
// A new line like `\n\n` NOT a new line like `\n`.
|
||||||
// This is also not a comment.
|
// This is also not a comment.
|
||||||
NewLine,
|
NewLine,
|
||||||
Annotation {
|
|
||||||
name: Option<Node<Identifier>>,
|
|
||||||
properties: Option<Vec<Node<ObjectProperty>>>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NonCodeValue {
|
|
||||||
pub fn annotation_name(&self) -> Option<&str> {
|
|
||||||
match self {
|
|
||||||
NonCodeValue::Annotation { name, .. } => name.as_ref().map(|i| &*i.name),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_from_meta_settings(settings: &crate::execution::MetaSettings) -> NonCodeValue {
|
|
||||||
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()))),
|
|
||||||
)];
|
|
||||||
|
|
||||||
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()))),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
NonCodeValue::Annotation {
|
|
||||||
name: Some(Identifier::new(annotations::SETTINGS)),
|
|
||||||
properties: Some(properties),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Default, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
@ -1314,6 +1276,47 @@ impl<'de> Deserialize<'de> for NonCodeMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub struct Annotation {
|
||||||
|
pub name: Option<Node<Identifier>>,
|
||||||
|
pub properties: Option<Vec<Node<ObjectProperty>>>,
|
||||||
|
|
||||||
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
|
#[ts(optional)]
|
||||||
|
pub digest: Option<Digest>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Annotation {
|
||||||
|
pub fn is_inner(&self) -> bool {
|
||||||
|
self.name.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> Option<&str> {
|
||||||
|
self.name.as_ref().map(|n| &*n.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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()))),
|
||||||
|
)];
|
||||||
|
|
||||||
|
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()))),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Annotation {
|
||||||
|
name: Some(Identifier::new(annotations::SETTINGS)),
|
||||||
|
properties: Some(properties),
|
||||||
|
digest: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
#[ts(export)]
|
#[ts(export)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
@ -3823,12 +3826,7 @@ const cylinder = startSketchOn('-XZ')
|
|||||||
(0..=0),
|
(0..=0),
|
||||||
Node::no_src(FunctionExpression {
|
Node::no_src(FunctionExpression {
|
||||||
params: vec![],
|
params: vec![],
|
||||||
body: Node::no_src(Program {
|
body: Program::empty(),
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: Default::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
}),
|
|
||||||
return_type: None,
|
return_type: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
}),
|
}),
|
||||||
@ -3847,18 +3845,7 @@ const cylinder = startSketchOn('-XZ')
|
|||||||
labeled: true,
|
labeled: true,
|
||||||
digest: None,
|
digest: None,
|
||||||
}],
|
}],
|
||||||
body: Node {
|
body: Program::empty(),
|
||||||
inner: Program {
|
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: Default::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
},
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
module_id: ModuleId::default(),
|
|
||||||
trivia: Vec::new(),
|
|
||||||
},
|
|
||||||
return_type: None,
|
return_type: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
}),
|
}),
|
||||||
@ -3877,18 +3864,7 @@ const cylinder = startSketchOn('-XZ')
|
|||||||
labeled: true,
|
labeled: true,
|
||||||
digest: None,
|
digest: None,
|
||||||
}],
|
}],
|
||||||
body: Node {
|
body: Program::empty(),
|
||||||
inner: Program {
|
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: Default::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
},
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
module_id: ModuleId::default(),
|
|
||||||
trivia: Vec::new(),
|
|
||||||
},
|
|
||||||
return_type: None,
|
return_type: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
}),
|
}),
|
||||||
@ -3919,18 +3895,7 @@ const cylinder = startSketchOn('-XZ')
|
|||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
body: Node {
|
body: Program::empty(),
|
||||||
inner: Program {
|
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: Default::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
},
|
|
||||||
start: 0,
|
|
||||||
end: 0,
|
|
||||||
module_id: ModuleId::default(),
|
|
||||||
trivia: Vec::new(),
|
|
||||||
},
|
|
||||||
return_type: None,
|
return_type: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
}),
|
}),
|
||||||
|
@ -21,13 +21,13 @@ use crate::{
|
|||||||
errors::{CompilationError, Severity, Tag},
|
errors::{CompilationError, Severity, Tag},
|
||||||
parsing::{
|
parsing::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, BoxNode,
|
Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem,
|
||||||
CallExpression, CallExpressionKw, CommentStyle, DefaultParamVal, ElseIf, Expr, ExpressionStatement,
|
BoxNode, CallExpression, CallExpressionKw, CommentStyle, DefaultParamVal, ElseIf, Expr,
|
||||||
FnArgPrimitive, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem, ImportSelector,
|
ExpressionStatement, FnArgPrimitive, FnArgType, FunctionExpression, Identifier, IfExpression, ImportItem,
|
||||||
ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue, MemberExpression,
|
ImportSelector, ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier, LiteralValue,
|
||||||
MemberObject, Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression, ObjectProperty,
|
MemberExpression, MemberObject, Node, NodeList, NonCodeMeta, NonCodeNode, NonCodeValue, ObjectExpression,
|
||||||
Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, Shebang, TagDeclarator,
|
ObjectProperty, Parameter, PipeExpression, PipeSubstitution, Program, ReturnStatement, Shebang,
|
||||||
UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
|
TagDeclarator, UnaryExpression, UnaryOperator, VariableDeclaration, VariableDeclarator, VariableKind,
|
||||||
},
|
},
|
||||||
math::BinaryExpressionToken,
|
math::BinaryExpressionToken,
|
||||||
token::{Token, TokenSlice, TokenType},
|
token::{Token, TokenSlice, TokenType},
|
||||||
@ -284,7 +284,7 @@ fn non_code_node(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
alt((non_code_node_leading_whitespace, non_code_node_no_leading_whitespace)).parse_next(i)
|
alt((non_code_node_leading_whitespace, non_code_node_no_leading_whitespace)).parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn annotation(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
fn annotation(i: &mut TokenSlice) -> PResult<Node<Annotation>> {
|
||||||
let at = at_sign.parse_next(i)?;
|
let at = at_sign.parse_next(i)?;
|
||||||
let name = opt(binding_name).parse_next(i)?;
|
let name = opt(binding_name).parse_next(i)?;
|
||||||
let mut end = name.as_ref().map(|n| n.end).unwrap_or(at.end);
|
let mut end = name.as_ref().map(|n| n.end).unwrap_or(at.end);
|
||||||
@ -308,7 +308,7 @@ fn annotation(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
value,
|
value,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
}),
|
}),
|
||||||
comma_sep,
|
comma_sep,
|
||||||
)
|
)
|
||||||
@ -327,19 +327,16 @@ fn annotation(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = NonCodeValue::Annotation { name, properties };
|
let value = Annotation {
|
||||||
Ok(Node::new(
|
name,
|
||||||
NonCodeNode { value, digest: None },
|
properties,
|
||||||
at.start,
|
digest: None,
|
||||||
end,
|
};
|
||||||
at.module_id,
|
Ok(Node::new(value, at.start, end, at.module_id))
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Matches remaining three cases of NonCodeValue
|
// Matches remaining three cases of NonCodeValue
|
||||||
fn non_code_node_no_leading_whitespace(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
fn non_code_node_no_leading_whitespace(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
||||||
alt((
|
|
||||||
annotation,
|
|
||||||
any.verify_map(|token: Token| {
|
any.verify_map(|token: Token| {
|
||||||
if token.is_code_token() {
|
if token.is_code_token() {
|
||||||
None
|
None
|
||||||
@ -369,8 +366,7 @@ fn non_code_node_no_leading_whitespace(i: &mut TokenSlice) -> PResult<Node<NonCo
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.context(expected("Non-code token (comments or whitespace)")),
|
.context(expected("Non-code token (comments or whitespace)"))
|
||||||
))
|
|
||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,7 +423,7 @@ fn pipe_expression(i: &mut TokenSlice) -> PResult<Node<PipeExpression>> {
|
|||||||
non_code_meta,
|
non_code_meta,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -830,7 +826,7 @@ fn object_property_same_key_and_val(i: &mut TokenSlice) -> PResult<Node<ObjectPr
|
|||||||
key,
|
key,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,7 +855,7 @@ fn object_property(i: &mut TokenSlice) -> PResult<Node<ObjectProperty>> {
|
|||||||
value: expr,
|
value: expr,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if sep.token_type == TokenType::Colon {
|
if sep.token_type == TokenType::Colon {
|
||||||
@ -1131,17 +1127,7 @@ fn function_decl(i: &mut TokenSlice) -> PResult<(Node<FunctionExpression>, bool)
|
|||||||
let close: Option<(Vec<Vec<Token>>, Token)> = opt((repeat(0.., whitespace), close_brace)).parse_next(i)?;
|
let close: Option<(Vec<Vec<Token>>, Token)> = opt((repeat(0.., whitespace), close_brace)).parse_next(i)?;
|
||||||
let (body, end) = match close {
|
let (body, end) = match close {
|
||||||
Some((_, end)) => (
|
Some((_, end)) => (
|
||||||
Node::new(
|
Node::new(Program::default(), brace.end, brace.end, brace.module_id),
|
||||||
Program {
|
|
||||||
body: Vec::new(),
|
|
||||||
non_code_meta: NonCodeMeta::default(),
|
|
||||||
shebang: None,
|
|
||||||
digest: None,
|
|
||||||
},
|
|
||||||
brace.end,
|
|
||||||
brace.end,
|
|
||||||
brace.module_id,
|
|
||||||
),
|
|
||||||
end.end,
|
end.end,
|
||||||
),
|
),
|
||||||
None => (function_body(i)?, close_brace(i)?.end),
|
None => (function_body(i)?, close_brace(i)?.end),
|
||||||
@ -1277,7 +1263,6 @@ fn noncode_just_after_code(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
x @ NonCodeValue::InlineComment { .. } => x,
|
x @ NonCodeValue::InlineComment { .. } => x,
|
||||||
x @ NonCodeValue::NewLineBlockComment { .. } => x,
|
x @ NonCodeValue::NewLineBlockComment { .. } => x,
|
||||||
x @ NonCodeValue::NewLine => x,
|
x @ NonCodeValue::NewLine => x,
|
||||||
x @ NonCodeValue::Annotation { .. } => x,
|
|
||||||
};
|
};
|
||||||
Node::new(
|
Node::new(
|
||||||
NonCodeNode { value, ..nc.inner },
|
NonCodeNode { value, ..nc.inner },
|
||||||
@ -1298,7 +1283,6 @@ fn noncode_just_after_code(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
x @ NonCodeValue::InlineComment { .. } => x,
|
x @ NonCodeValue::InlineComment { .. } => x,
|
||||||
x @ NonCodeValue::NewLineBlockComment { .. } => x,
|
x @ NonCodeValue::NewLineBlockComment { .. } => x,
|
||||||
x @ NonCodeValue::NewLine => x,
|
x @ NonCodeValue::NewLine => x,
|
||||||
x @ NonCodeValue::Annotation { .. } => x,
|
|
||||||
};
|
};
|
||||||
Node::new(NonCodeNode { value, ..nc.inner }, nc.start, nc.end, nc.module_id)
|
Node::new(NonCodeNode { value, ..nc.inner }, nc.start, nc.end, nc.module_id)
|
||||||
}
|
}
|
||||||
@ -1314,6 +1298,7 @@ fn noncode_just_after_code(i: &mut TokenSlice) -> PResult<Node<NonCodeNode>> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
enum WithinFunction {
|
enum WithinFunction {
|
||||||
|
Annotation(Node<Annotation>),
|
||||||
BodyItem((BodyItem, Option<Node<NonCodeNode>>)),
|
BodyItem((BodyItem, Option<Node<NonCodeNode>>)),
|
||||||
NonCode(Node<NonCodeNode>),
|
NonCode(Node<NonCodeNode>),
|
||||||
}
|
}
|
||||||
@ -1338,9 +1323,12 @@ fn body_items_within_function(i: &mut TokenSlice) -> PResult<WithinFunction> {
|
|||||||
(import_stmt.map(BodyItem::ImportStatement), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
|
(import_stmt.map(BodyItem::ImportStatement), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
|
||||||
Token { ref value, .. } if value == "return" =>
|
Token { ref value, .. } if value == "return" =>
|
||||||
(return_stmt.map(BodyItem::ReturnStatement), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
|
(return_stmt.map(BodyItem::ReturnStatement), opt(noncode_just_after_code)).map(WithinFunction::BodyItem),
|
||||||
token if !token.is_code_token() || token.token_type == TokenType::At => {
|
token if !token.is_code_token() => {
|
||||||
non_code_node.map(WithinFunction::NonCode)
|
non_code_node.map(WithinFunction::NonCode)
|
||||||
},
|
},
|
||||||
|
token if token.token_type == TokenType::At => {
|
||||||
|
annotation.map(WithinFunction::Annotation)
|
||||||
|
},
|
||||||
_ =>
|
_ =>
|
||||||
alt((
|
alt((
|
||||||
(
|
(
|
||||||
@ -1447,16 +1435,32 @@ fn function_body(i: &mut TokenSlice) -> PResult<Node<Program>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut body = Vec::new();
|
let mut body = Vec::new();
|
||||||
|
let mut inner_attrs = Vec::new();
|
||||||
|
let mut pending_attrs = Vec::new();
|
||||||
let mut non_code_meta = NonCodeMeta::default();
|
let mut non_code_meta = NonCodeMeta::default();
|
||||||
let mut end = 0;
|
let mut end = 0;
|
||||||
let mut start = leading_whitespace_start;
|
let mut start = leading_whitespace_start;
|
||||||
for thing_in_body in things_within_body {
|
for thing_in_body in things_within_body {
|
||||||
match thing_in_body {
|
match thing_in_body {
|
||||||
WithinFunction::BodyItem((b, maybe_noncode)) => {
|
WithinFunction::Annotation(attr) => {
|
||||||
|
if start.is_none() {
|
||||||
|
start = Some((attr.start, attr.module_id))
|
||||||
|
}
|
||||||
|
if attr.is_inner() {
|
||||||
|
inner_attrs.push(attr);
|
||||||
|
} else {
|
||||||
|
pending_attrs.push(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WithinFunction::BodyItem((mut b, maybe_noncode)) => {
|
||||||
if start.is_none() {
|
if start.is_none() {
|
||||||
start = Some((b.start(), b.module_id()));
|
start = Some((b.start(), b.module_id()));
|
||||||
}
|
}
|
||||||
end = b.end();
|
end = b.end();
|
||||||
|
if !pending_attrs.is_empty() {
|
||||||
|
b.set_attrs(pending_attrs);
|
||||||
|
pending_attrs = Vec::new();
|
||||||
|
}
|
||||||
body.push(b);
|
body.push(b);
|
||||||
if let Some(nc) = maybe_noncode {
|
if let Some(nc) = maybe_noncode {
|
||||||
end = nc.end;
|
end = nc.end;
|
||||||
@ -1476,9 +1480,26 @@ fn function_body(i: &mut TokenSlice) -> PResult<Node<Program>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = start.expect(
|
let start = start.expect(
|
||||||
"the `things_within_body` vec should have looped at least once, and each loop overwrites `start` if it is None",
|
"the `things_within_body` vec should have looped at least once, and each loop overwrites `start` if it is None",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if !pending_attrs.is_empty() {
|
||||||
|
for a in pending_attrs {
|
||||||
|
ParseContext::err(CompilationError::err(
|
||||||
|
a.as_source_range(),
|
||||||
|
"Attribute is not attached to any item",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Err(ErrMode::Cut(
|
||||||
|
CompilationError::fatal(
|
||||||
|
SourceRange::new(start.0, end, start.1),
|
||||||
|
"Block contains un-attached attributes",
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
// Safe to unwrap `body.first()` because `body` is `separated1` therefore guaranteed
|
// Safe to unwrap `body.first()` because `body` is `separated1` therefore guaranteed
|
||||||
// to have len >= 1.
|
// to have len >= 1.
|
||||||
let end_ws = opt(whitespace)
|
let end_ws = opt(whitespace)
|
||||||
@ -1492,6 +1513,7 @@ fn function_body(i: &mut TokenSlice) -> PResult<Node<Program>> {
|
|||||||
Program {
|
Program {
|
||||||
body,
|
body,
|
||||||
non_code_meta,
|
non_code_meta,
|
||||||
|
inner_attrs,
|
||||||
shebang: None,
|
shebang: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
@ -1790,7 +1812,7 @@ fn return_stmt(i: &mut TokenSlice) -> PResult<Node<ReturnStatement>> {
|
|||||||
end: argument.end(),
|
end: argument.end(),
|
||||||
module_id: ret.module_id,
|
module_id: ret.module_id,
|
||||||
inner: ReturnStatement { argument, digest: None },
|
inner: ReturnStatement { argument, digest: None },
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2017,13 +2039,13 @@ fn declaration(i: &mut TokenSlice) -> PResult<BoxNode<VariableDeclaration>> {
|
|||||||
init: val,
|
init: val,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
},
|
},
|
||||||
visibility,
|
visibility,
|
||||||
kind,
|
kind,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2229,7 +2251,7 @@ fn unary_expression(i: &mut TokenSlice) -> PResult<Node<UnaryExpression>> {
|
|||||||
argument,
|
argument,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2310,7 +2332,7 @@ fn expression_stmt(i: &mut TokenSlice) -> PResult<Node<ExpressionStatement>> {
|
|||||||
expression: val,
|
expression: val,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2750,7 +2772,7 @@ fn fn_call(i: &mut TokenSlice) -> PResult<Node<CallExpression>> {
|
|||||||
arguments: args,
|
arguments: args,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2780,7 +2802,7 @@ fn fn_call_kw(i: &mut TokenSlice) -> PResult<Node<CallExpressionKw>> {
|
|||||||
arguments: args,
|
arguments: args,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
trivia: Vec::new(),
|
outer_attrs: Vec::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3023,6 +3045,7 @@ mySk1 = startSketchAt([0, 0])"#;
|
|||||||
)],
|
)],
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
|
inner_attrs: Vec::new(),
|
||||||
shebang: None,
|
shebang: None,
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
@ -3700,6 +3723,7 @@ mySk1 = startSketchAt([0, 0])"#;
|
|||||||
))],
|
))],
|
||||||
shebang: None,
|
shebang: None,
|
||||||
non_code_meta: NonCodeMeta::default(),
|
non_code_meta: NonCodeMeta::default(),
|
||||||
|
inner_attrs: Vec::new(),
|
||||||
digest: None,
|
digest: None,
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
|
@ -2,11 +2,12 @@ use std::fmt::Write;
|
|||||||
|
|
||||||
use crate::parsing::{
|
use crate::parsing::{
|
||||||
ast::types::{
|
ast::types::{
|
||||||
ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
|
Annotation, ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem,
|
||||||
CallExpressionKw, CommentStyle, DefaultParamVal, Expr, FnArgType, FormatOptions, FunctionExpression,
|
CallExpression, CallExpressionKw, CommentStyle, DefaultParamVal, Expr, FnArgType, FormatOptions,
|
||||||
IfExpression, ImportSelector, ImportStatement, ItemVisibility, LabeledArg, Literal, LiteralIdentifier,
|
FunctionExpression, IfExpression, ImportSelector, ImportStatement, ItemVisibility, LabeledArg, Literal,
|
||||||
LiteralValue, MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue, ObjectExpression, Parameter,
|
LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue,
|
||||||
PipeExpression, Program, TagDeclarator, UnaryExpression, VariableDeclaration, VariableKind,
|
ObjectExpression, Parameter, PipeExpression, Program, TagDeclarator, UnaryExpression, VariableDeclaration,
|
||||||
|
VariableKind,
|
||||||
},
|
},
|
||||||
token::NumericSuffix,
|
token::NumericSuffix,
|
||||||
PIPE_OPERATOR,
|
PIPE_OPERATOR,
|
||||||
@ -22,6 +23,9 @@ impl Program {
|
|||||||
.map(|sh| format!("{}\n\n", sh.inner.content))
|
.map(|sh| format!("{}\n\n", sh.inner.content))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
for attr in &self.inner_attrs {
|
||||||
|
result.push_str(&attr.recast(options, indentation_level));
|
||||||
|
}
|
||||||
for start in &self.non_code_meta.start_nodes {
|
for start in &self.non_code_meta.start_nodes {
|
||||||
result.push_str(&start.recast(options, indentation_level));
|
result.push_str(&start.recast(options, indentation_level));
|
||||||
}
|
}
|
||||||
@ -30,7 +34,12 @@ impl Program {
|
|||||||
let result = self
|
let result = self
|
||||||
.body
|
.body
|
||||||
.iter()
|
.iter()
|
||||||
.map(|body_item| match body_item.clone() {
|
.map(|body_item| {
|
||||||
|
let mut result = String::new();
|
||||||
|
for attr in body_item.get_attrs() {
|
||||||
|
result.push_str(&attr.recast(options, indentation_level));
|
||||||
|
}
|
||||||
|
result.push_str(&match body_item.clone() {
|
||||||
BodyItem::ImportStatement(stmt) => stmt.recast(options, indentation_level),
|
BodyItem::ImportStatement(stmt) => stmt.recast(options, indentation_level),
|
||||||
BodyItem::ExpressionStatement(expression_statement) => {
|
BodyItem::ExpressionStatement(expression_statement) => {
|
||||||
expression_statement
|
expression_statement
|
||||||
@ -50,10 +59,13 @@ impl Program {
|
|||||||
.trim_start()
|
.trim_start()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
result
|
||||||
})
|
})
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.fold(result, |mut output, (index, recast_str)| {
|
.fold(result, |mut output, (index, recast_str)| {
|
||||||
let start_string = if index == 0 && self.non_code_meta.start_nodes.is_empty() {
|
let start_string =
|
||||||
|
if index == 0 && self.non_code_meta.start_nodes.is_empty() && self.inner_attrs.is_empty() {
|
||||||
// We need to indent.
|
// We need to indent.
|
||||||
indentation.to_string()
|
indentation.to_string()
|
||||||
} else {
|
} else {
|
||||||
@ -113,9 +125,7 @@ impl NonCodeValue {
|
|||||||
fn should_cause_array_newline(&self) -> bool {
|
fn should_cause_array_newline(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::InlineComment { .. } => false,
|
Self::InlineComment { .. } => false,
|
||||||
Self::BlockComment { .. } | Self::NewLineBlockComment { .. } | Self::NewLine | Self::Annotation { .. } => {
|
Self::BlockComment { .. } | Self::NewLineBlockComment { .. } | Self::NewLine => true,
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,12 +166,17 @@ impl Node<NonCodeNode> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
NonCodeValue::NewLine => "\n\n".to_string(),
|
NonCodeValue::NewLine => "\n\n".to_string(),
|
||||||
NonCodeValue::Annotation { name, properties } => {
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Node<Annotation> {
|
||||||
|
fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
||||||
let mut result = "@".to_owned();
|
let mut result = "@".to_owned();
|
||||||
if let Some(name) = name {
|
if let Some(name) = &self.name {
|
||||||
result.push_str(&name.name);
|
result.push_str(&name.name);
|
||||||
}
|
}
|
||||||
if let Some(properties) = properties {
|
if let Some(properties) = &self.properties {
|
||||||
result.push('(');
|
result.push('(');
|
||||||
result.push_str(
|
result.push_str(
|
||||||
&properties
|
&properties
|
||||||
@ -185,8 +200,6 @@ impl Node<NonCodeNode> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ImportStatement {
|
impl ImportStatement {
|
||||||
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
pub fn recast(&self, options: &FormatOptions, indentation_level: usize) -> String {
|
||||||
|
@ -103,26 +103,9 @@ description: Result of parsing import_cycle1.kcl
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"end": 110,
|
"end": 110,
|
||||||
"nonCodeMeta": {
|
"innerAttrs": [
|
||||||
"nonCodeNodes": {
|
|
||||||
"0": [
|
|
||||||
{
|
|
||||||
"end": 71,
|
|
||||||
"start": 69,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "newLine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"startNodes": [
|
|
||||||
{
|
{
|
||||||
"end": 33,
|
"end": 33,
|
||||||
"start": 0,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "annotation",
|
|
||||||
"name": {
|
"name": {
|
||||||
"end": 9,
|
"end": 9,
|
||||||
"name": "settings",
|
"name": "settings",
|
||||||
@ -148,11 +131,26 @@ description: Result of parsing import_cycle1.kcl
|
|||||||
"type": "Identifier"
|
"type": "Identifier"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"start": 0,
|
||||||
|
"type": "Annotation"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonCodeMeta": {
|
||||||
|
"nonCodeNodes": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"end": 71,
|
||||||
|
"start": 69,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "newLine"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"startNodes": []
|
||||||
|
},
|
||||||
"start": 0
|
"start": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,26 +103,9 @@ description: Result of parsing import_function_not_sketch.kcl
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"end": 109,
|
"end": 109,
|
||||||
"nonCodeMeta": {
|
"innerAttrs": [
|
||||||
"nonCodeNodes": {
|
|
||||||
"0": [
|
|
||||||
{
|
|
||||||
"end": 70,
|
|
||||||
"start": 68,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "newLine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"startNodes": [
|
|
||||||
{
|
{
|
||||||
"end": 33,
|
"end": 33,
|
||||||
"start": 0,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "annotation",
|
|
||||||
"name": {
|
"name": {
|
||||||
"end": 9,
|
"end": 9,
|
||||||
"name": "settings",
|
"name": "settings",
|
||||||
@ -148,11 +131,26 @@ description: Result of parsing import_function_not_sketch.kcl
|
|||||||
"type": "Identifier"
|
"type": "Identifier"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"start": 0,
|
||||||
|
"type": "Annotation"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonCodeMeta": {
|
||||||
|
"nonCodeNodes": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"end": 70,
|
||||||
|
"start": 68,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "newLine"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"startNodes": []
|
||||||
|
},
|
||||||
"start": 0
|
"start": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,26 +115,9 @@ description: Result of parsing import_whole.kcl
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"end": 124,
|
"end": 124,
|
||||||
"nonCodeMeta": {
|
"innerAttrs": [
|
||||||
"nonCodeNodes": {
|
|
||||||
"0": [
|
|
||||||
{
|
|
||||||
"end": 68,
|
|
||||||
"start": 66,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "newLine"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"startNodes": [
|
|
||||||
{
|
{
|
||||||
"end": 33,
|
"end": 33,
|
||||||
"start": 0,
|
|
||||||
"type": "NonCodeNode",
|
|
||||||
"value": {
|
|
||||||
"type": "annotation",
|
|
||||||
"name": {
|
"name": {
|
||||||
"end": 9,
|
"end": 9,
|
||||||
"name": "settings",
|
"name": "settings",
|
||||||
@ -160,11 +143,26 @@ description: Result of parsing import_whole.kcl
|
|||||||
"type": "Identifier"
|
"type": "Identifier"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"start": 0,
|
||||||
|
"type": "Annotation"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonCodeMeta": {
|
||||||
|
"nonCodeNodes": {
|
||||||
|
"0": [
|
||||||
|
{
|
||||||
|
"end": 68,
|
||||||
|
"start": 66,
|
||||||
|
"type": "NonCodeNode",
|
||||||
|
"value": {
|
||||||
|
"type": "newLine"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"startNodes": []
|
||||||
|
},
|
||||||
"start": 0
|
"start": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user