Factor out a modules module and add main.rs (#5329)
* Factor out a modules module Signed-off-by: Nick Cameron <nrc@ncameron.org> * Very simple cargo run Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
		@ -5,7 +5,8 @@ use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity};
 | 
			
		||||
use crate::{
 | 
			
		||||
    execution::{ArtifactCommand, ArtifactGraph, Operation},
 | 
			
		||||
    lsp::IntoDiagnostic,
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// How did the KCL execution fail
 | 
			
		||||
 | 
			
		||||
@ -10,16 +10,17 @@ use crate::{
 | 
			
		||||
        annotations,
 | 
			
		||||
        cad_op::{OpArg, Operation},
 | 
			
		||||
        state::ModuleState,
 | 
			
		||||
        BodyType, ExecState, ExecutorContext, KclValue, MemoryFunction, Metadata, ModulePath, ModuleRepr,
 | 
			
		||||
        ProgramMemory, TagEngineInfo, TagIdentifier,
 | 
			
		||||
        BodyType, ExecState, ExecutorContext, KclValue, MemoryFunction, Metadata, ProgramMemory, TagEngineInfo,
 | 
			
		||||
        TagIdentifier,
 | 
			
		||||
    },
 | 
			
		||||
    modules::{ModuleId, ModulePath, ModuleRepr},
 | 
			
		||||
    parsing::ast::types::{
 | 
			
		||||
        ArrayExpression, ArrayRangeExpression, BinaryExpression, BinaryOperator, BinaryPart, BodyItem, CallExpression,
 | 
			
		||||
        CallExpressionKw, Expr, FunctionExpression, IfExpression, ImportPath, ImportSelector, ItemVisibility,
 | 
			
		||||
        LiteralIdentifier, LiteralValue, MemberExpression, MemberObject, Node, NodeRef, NonCodeValue, ObjectExpression,
 | 
			
		||||
        PipeExpression, TagDeclarator, UnaryExpression, UnaryOperator,
 | 
			
		||||
    },
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    std::{
 | 
			
		||||
        args::{Arg, KwArgs},
 | 
			
		||||
        FunctionKind,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
//! The executor for the AST.
 | 
			
		||||
 | 
			
		||||
use std::{fmt, path::PathBuf, sync::Arc};
 | 
			
		||||
use std::{path::PathBuf, sync::Arc};
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
pub use artifact::{Artifact, ArtifactCommand, ArtifactGraph, ArtifactId};
 | 
			
		||||
@ -9,7 +9,9 @@ use cache::OldAstState;
 | 
			
		||||
pub use cad_op::Operation;
 | 
			
		||||
pub use exec_ast::FunctionParam;
 | 
			
		||||
pub use geometry::*;
 | 
			
		||||
pub(crate) use import::{import_foreign, send_to_engine as send_import_to_engine, ZOO_COORD_SYSTEM};
 | 
			
		||||
pub(crate) use import::{
 | 
			
		||||
    import_foreign, send_to_engine as send_import_to_engine, PreImportedGeometry, ZOO_COORD_SYSTEM,
 | 
			
		||||
};
 | 
			
		||||
use indexmap::IndexMap;
 | 
			
		||||
pub use kcl_value::{KclObjectFields, KclValue, UnitAngle, UnitLen};
 | 
			
		||||
use kcmc::{
 | 
			
		||||
@ -26,15 +28,15 @@ pub use state::{ExecState, IdGenerator, MetaSettings};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    engine::EngineManager,
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    errors::KclError,
 | 
			
		||||
    execution::{
 | 
			
		||||
        artifact::build_artifact_graph,
 | 
			
		||||
        cache::{CacheInformation, CacheResult},
 | 
			
		||||
    },
 | 
			
		||||
    fs::{FileManager, FileSystem},
 | 
			
		||||
    parsing::ast::types::{Expr, FunctionExpression, ImportPath, Node, NodeRef, Program},
 | 
			
		||||
    fs::FileManager,
 | 
			
		||||
    parsing::ast::types::{Expr, FunctionExpression, Node, NodeRef, Program},
 | 
			
		||||
    settings::types::UnitLength,
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    std::{args::Arg, StdLib},
 | 
			
		||||
    ExecError, KclErrorWithOutputs,
 | 
			
		||||
};
 | 
			
		||||
@ -162,118 +164,6 @@ pub enum BodyType {
 | 
			
		||||
    Block,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Info about a module.  Right now, this is pretty minimal.  We hope to cache
 | 
			
		||||
/// modules here in the future.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
pub struct ModuleInfo {
 | 
			
		||||
    /// The ID of the module.
 | 
			
		||||
    id: ModuleId,
 | 
			
		||||
    /// Absolute path of the module's source file.
 | 
			
		||||
    path: ModulePath,
 | 
			
		||||
    repr: ModuleRepr,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
 | 
			
		||||
pub enum ModulePath {
 | 
			
		||||
    Local(std::path::PathBuf),
 | 
			
		||||
    Std(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ModulePath {
 | 
			
		||||
    fn expect_path(&self) -> &std::path::PathBuf {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(p) => p,
 | 
			
		||||
            _ => unreachable!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn source(&self, fs: &FileManager, source_range: SourceRange) -> Result<String, KclError> {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(p) => fs.read_to_string(p, source_range).await,
 | 
			
		||||
            ModulePath::Std(_) => unimplemented!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn from_import_path(path: &ImportPath, project_directory: &Option<PathBuf>) -> Self {
 | 
			
		||||
        match path {
 | 
			
		||||
            ImportPath::Kcl { filename: path } | ImportPath::Foreign { path } => {
 | 
			
		||||
                let resolved_path = if let Some(project_dir) = project_directory {
 | 
			
		||||
                    project_dir.join(path)
 | 
			
		||||
                } else {
 | 
			
		||||
                    std::path::PathBuf::from(path)
 | 
			
		||||
                };
 | 
			
		||||
                ModulePath::Local(resolved_path)
 | 
			
		||||
            }
 | 
			
		||||
            ImportPath::Std { path } => {
 | 
			
		||||
                // For now we only support importing from singly-nested modules inside std.
 | 
			
		||||
                assert_eq!(path.len(), 2);
 | 
			
		||||
                assert_eq!(&path[0], "std");
 | 
			
		||||
 | 
			
		||||
                ModulePath::Std(path[1].clone())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for ModulePath {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(path) => path.display().fmt(f),
 | 
			
		||||
            ModulePath::Std(s) => write!(f, "std::{s}"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
pub enum ModuleRepr {
 | 
			
		||||
    Root,
 | 
			
		||||
    Kcl(Node<Program>),
 | 
			
		||||
    Foreign(import::PreImportedGeometry),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct ModuleLoader {
 | 
			
		||||
    /// The stack of import statements for detecting circular module imports.
 | 
			
		||||
    /// If this is empty, we're not currently executing an import statement.
 | 
			
		||||
    pub import_stack: Vec<PathBuf>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ModuleLoader {
 | 
			
		||||
    pub(crate) fn cycle_check(&self, path: &ModulePath, source_range: SourceRange) -> Result<(), KclError> {
 | 
			
		||||
        if self.import_stack.contains(path.expect_path()) {
 | 
			
		||||
            return Err(KclError::ImportCycle(KclErrorDetails {
 | 
			
		||||
                message: format!(
 | 
			
		||||
                    "circular import of modules is not allowed: {} -> {}",
 | 
			
		||||
                    self.import_stack
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|p| p.as_path().to_string_lossy())
 | 
			
		||||
                        .collect::<Vec<_>>()
 | 
			
		||||
                        .join(" -> "),
 | 
			
		||||
                    path,
 | 
			
		||||
                ),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn enter_module(&mut self, path: &ModulePath) {
 | 
			
		||||
        if let ModulePath::Local(ref path) = path {
 | 
			
		||||
            self.import_stack.push(path.clone());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn leave_module(&mut self, path: &ModulePath) {
 | 
			
		||||
        if let ModulePath::Local(ref path) = path {
 | 
			
		||||
            let popped = self.import_stack.pop().unwrap();
 | 
			
		||||
            assert_eq!(path, &popped);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Metadata.
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Eq, Copy)]
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
@ -884,7 +774,7 @@ mod tests {
 | 
			
		||||
    use pretty_assertions::assert_eq;
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::errors::KclErrorDetails;
 | 
			
		||||
    use crate::{errors::KclErrorDetails, ModuleId};
 | 
			
		||||
 | 
			
		||||
    /// Convenience function to get a JSON value from memory and unwrap.
 | 
			
		||||
    #[track_caller]
 | 
			
		||||
 | 
			
		||||
@ -9,11 +9,11 @@ use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{
 | 
			
		||||
        annotations, kcl_value, Artifact, ArtifactCommand, ArtifactGraph, ArtifactId, ExecOutcome, ExecutorSettings,
 | 
			
		||||
        KclValue, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr, Operation, ProgramMemory, SolidLazyIds, UnitAngle,
 | 
			
		||||
        UnitLen,
 | 
			
		||||
        KclValue, Operation, ProgramMemory, SolidLazyIds, UnitAngle, UnitLen,
 | 
			
		||||
    },
 | 
			
		||||
    modules::{ModuleId, ModuleInfo, ModuleLoader, ModulePath, ModuleRepr},
 | 
			
		||||
    parsing::ast::types::NonCodeValue,
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// State for executing a program.
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,7 @@ mod fs;
 | 
			
		||||
pub mod lint;
 | 
			
		||||
mod log;
 | 
			
		||||
mod lsp;
 | 
			
		||||
mod modules;
 | 
			
		||||
mod parsing;
 | 
			
		||||
mod settings;
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
@ -87,9 +88,10 @@ pub use lsp::{
 | 
			
		||||
    copilot::Backend as CopilotLspBackend,
 | 
			
		||||
    kcl::{Backend as KclLspBackend, Server as KclLspServerSubCommand},
 | 
			
		||||
};
 | 
			
		||||
pub use modules::ModuleId;
 | 
			
		||||
pub use parsing::ast::{modify::modify_ast_for_sketch, types::FormatOptions};
 | 
			
		||||
pub use settings::types::{project::ProjectConfiguration, Configuration, UnitLength};
 | 
			
		||||
pub use source_range::{ModuleId, SourceRange};
 | 
			
		||||
pub use source_range::SourceRange;
 | 
			
		||||
 | 
			
		||||
// Rather than make executor public and make lots of it pub(crate), just re-export into a new module.
 | 
			
		||||
// Ideally we wouldn't export these things at all, they should only be used for testing.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										157
									
								
								src/wasm-lib/kcl/src/modules.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								src/wasm-lib/kcl/src/modules.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,157 @@
 | 
			
		||||
use std::{fmt, path::PathBuf};
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use schemars::JsonSchema;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::PreImportedGeometry,
 | 
			
		||||
    fs::{FileManager, FileSystem},
 | 
			
		||||
    parsing::ast::types::{ImportPath, Node, Program},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Identifier of a source file.  Uses a u32 to keep the size small.
 | 
			
		||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
pub struct ModuleId(u32);
 | 
			
		||||
 | 
			
		||||
impl ModuleId {
 | 
			
		||||
    pub fn from_usize(id: usize) -> Self {
 | 
			
		||||
        Self(u32::try_from(id).expect("module ID should fit in a u32"))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn as_usize(&self) -> usize {
 | 
			
		||||
        usize::try_from(self.0).expect("module ID should fit in a usize")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Top-level file is the one being executed.
 | 
			
		||||
    /// Represented by module ID of 0, i.e. the default value.
 | 
			
		||||
    pub fn is_top_level(&self) -> bool {
 | 
			
		||||
        *self == Self::default()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
 | 
			
		||||
#[serde(rename_all = "camelCase")]
 | 
			
		||||
pub struct ModuleLoader {
 | 
			
		||||
    /// The stack of import statements for detecting circular module imports.
 | 
			
		||||
    /// If this is empty, we're not currently executing an import statement.
 | 
			
		||||
    pub import_stack: Vec<PathBuf>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ModuleLoader {
 | 
			
		||||
    pub(crate) fn cycle_check(&self, path: &ModulePath, source_range: SourceRange) -> Result<(), KclError> {
 | 
			
		||||
        if self.import_stack.contains(path.expect_path()) {
 | 
			
		||||
            return Err(KclError::ImportCycle(KclErrorDetails {
 | 
			
		||||
                message: format!(
 | 
			
		||||
                    "circular import of modules is not allowed: {} -> {}",
 | 
			
		||||
                    self.import_stack
 | 
			
		||||
                        .iter()
 | 
			
		||||
                        .map(|p| p.as_path().to_string_lossy())
 | 
			
		||||
                        .collect::<Vec<_>>()
 | 
			
		||||
                        .join(" -> "),
 | 
			
		||||
                    path,
 | 
			
		||||
                ),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn enter_module(&mut self, path: &ModulePath) {
 | 
			
		||||
        if let ModulePath::Local(ref path) = path {
 | 
			
		||||
            self.import_stack.push(path.clone());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn leave_module(&mut self, path: &ModulePath) {
 | 
			
		||||
        if let ModulePath::Local(ref path) = path {
 | 
			
		||||
            let popped = self.import_stack.pop().unwrap();
 | 
			
		||||
            assert_eq!(path, &popped);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn read_std(_mod_name: &str) -> Option<&'static str> {
 | 
			
		||||
    None
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Info about a module.  Right now, this is pretty minimal.  We hope to cache
 | 
			
		||||
/// modules here in the future.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
pub struct ModuleInfo {
 | 
			
		||||
    /// The ID of the module.
 | 
			
		||||
    pub(crate) id: ModuleId,
 | 
			
		||||
    /// Absolute path of the module's source file.
 | 
			
		||||
    pub(crate) path: ModulePath,
 | 
			
		||||
    pub(crate) repr: ModuleRepr,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
 | 
			
		||||
pub enum ModuleRepr {
 | 
			
		||||
    Root,
 | 
			
		||||
    Kcl(Node<Program>),
 | 
			
		||||
    Foreign(PreImportedGeometry),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, Hash)]
 | 
			
		||||
pub enum ModulePath {
 | 
			
		||||
    Local(PathBuf),
 | 
			
		||||
    Std(String),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ModulePath {
 | 
			
		||||
    pub(crate) fn expect_path(&self) -> &PathBuf {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(p) => p,
 | 
			
		||||
            _ => unreachable!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) async fn source(&self, fs: &FileManager, source_range: SourceRange) -> Result<String, KclError> {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(p) => fs.read_to_string(p, source_range).await,
 | 
			
		||||
            ModulePath::Std(name) => read_std(name)
 | 
			
		||||
                .ok_or_else(|| {
 | 
			
		||||
                    KclError::Semantic(KclErrorDetails {
 | 
			
		||||
                        message: format!("Cannot find standard library module to import: std::{name}."),
 | 
			
		||||
                        source_ranges: vec![source_range],
 | 
			
		||||
                    })
 | 
			
		||||
                })
 | 
			
		||||
                .map(str::to_owned),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn from_import_path(path: &ImportPath, project_directory: &Option<PathBuf>) -> Self {
 | 
			
		||||
        match path {
 | 
			
		||||
            ImportPath::Kcl { filename: path } | ImportPath::Foreign { path } => {
 | 
			
		||||
                let resolved_path = if let Some(project_dir) = project_directory {
 | 
			
		||||
                    project_dir.join(path)
 | 
			
		||||
                } else {
 | 
			
		||||
                    std::path::PathBuf::from(path)
 | 
			
		||||
                };
 | 
			
		||||
                ModulePath::Local(resolved_path)
 | 
			
		||||
            }
 | 
			
		||||
            ImportPath::Std { path } => {
 | 
			
		||||
                // For now we only support importing from singly-nested modules inside std.
 | 
			
		||||
                assert_eq!(path.len(), 2);
 | 
			
		||||
                assert_eq!(&path[0], "std");
 | 
			
		||||
 | 
			
		||||
                ModulePath::Std(path[1].clone())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for ModulePath {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            ModulePath::Local(path) => path.display().fmt(f),
 | 
			
		||||
            ModulePath::Std(s) => write!(f, "std::{s}"),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -4,7 +4,7 @@ pub mod types;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    parsing::ast::types::{BinaryPart, BodyItem, Expr, LiteralIdentifier, MemberObject},
 | 
			
		||||
    source_range::ModuleId,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
impl BodyItem {
 | 
			
		||||
 | 
			
		||||
@ -15,8 +15,8 @@ use crate::{
 | 
			
		||||
        ArrayExpression, CallExpression, ConstraintLevel, FormatOptions, Literal, Node, PipeExpression,
 | 
			
		||||
        PipeSubstitution, VariableDeclarator,
 | 
			
		||||
    },
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    Program,
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    ModuleId, Program,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type Point3d = kcmc::shared::Point3d<f64>;
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,8 @@ use crate::{
 | 
			
		||||
    execution::{annotations, KclValue, Metadata, TagIdentifier},
 | 
			
		||||
    parsing::{ast::digest::Digest, PIPE_OPERATOR},
 | 
			
		||||
    pretty::NumericSuffix,
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mod condition;
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ mod tests {
 | 
			
		||||
            ast::types::{Literal, LiteralValue},
 | 
			
		||||
            token::NumericSuffix,
 | 
			
		||||
        },
 | 
			
		||||
        source_range::ModuleId,
 | 
			
		||||
        ModuleId,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,8 @@ use crate::{
 | 
			
		||||
        ast::types::{Node, Program},
 | 
			
		||||
        token::TokenStream,
 | 
			
		||||
    },
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub(crate) mod ast;
 | 
			
		||||
 | 
			
		||||
@ -18,8 +18,8 @@ use winnow::{
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::KclError,
 | 
			
		||||
    parsing::ast::types::{ItemVisibility, VariableKind},
 | 
			
		||||
    source_range::{ModuleId, SourceRange},
 | 
			
		||||
    CompilationError,
 | 
			
		||||
    source_range::SourceRange,
 | 
			
		||||
    CompilationError, ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
mod tokeniser;
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ use winnow::{
 | 
			
		||||
use super::TokenStream;
 | 
			
		||||
use crate::{
 | 
			
		||||
    parsing::token::{Token, TokenType},
 | 
			
		||||
    source_range::ModuleId,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
lazy_static! {
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ use crate::{
 | 
			
		||||
    exec::ArtifactCommand,
 | 
			
		||||
    execution::{ArtifactGraph, Operation},
 | 
			
		||||
    parsing::ast::types::{Node, Program},
 | 
			
		||||
    source_range::ModuleId,
 | 
			
		||||
    ModuleId,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// Deserialize the data from a snapshot.
 | 
			
		||||
 | 
			
		||||
@ -2,26 +2,7 @@ use schemars::JsonSchema;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use tower_lsp::lsp_types::{Position as LspPosition, Range as LspRange};
 | 
			
		||||
 | 
			
		||||
/// Identifier of a source file.  Uses a u32 to keep the size small.
 | 
			
		||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize, ts_rs::TS, JsonSchema)]
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
pub struct ModuleId(u32);
 | 
			
		||||
 | 
			
		||||
impl ModuleId {
 | 
			
		||||
    pub fn from_usize(id: usize) -> Self {
 | 
			
		||||
        Self(u32::try_from(id).expect("module ID should fit in a u32"))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn as_usize(&self) -> usize {
 | 
			
		||||
        usize::try_from(self.0).expect("module ID should fit in a usize")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Top-level file is the one being executed.
 | 
			
		||||
    /// Represented by module ID of 0, i.e. the default value.
 | 
			
		||||
    pub fn is_top_level(&self) -> bool {
 | 
			
		||||
        *self == Self::default()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
use crate::modules::ModuleId;
 | 
			
		||||
 | 
			
		||||
/// The first two items are the start and end points (byte offsets from the start of the file).
 | 
			
		||||
/// The third item is whether the source range belongs to the 'main' file, i.e., the file currently
 | 
			
		||||
 | 
			
		||||
@ -795,7 +795,7 @@ mod tests {
 | 
			
		||||
    use pretty_assertions::assert_eq;
 | 
			
		||||
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::{parsing::ast::types::FormatOptions, source_range::ModuleId};
 | 
			
		||||
    use crate::{parsing::ast::types::FormatOptions, ModuleId};
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_recast_if_else_if_same() {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										41
									
								
								src/wasm-lib/src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/wasm-lib/src/main.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
use std::{env, fs::File, io::Read};
 | 
			
		||||
 | 
			
		||||
use kcl_lib::{ExecState, ExecutorContext, ExecutorSettings, Program};
 | 
			
		||||
 | 
			
		||||
// An extremely simple script, definitely not to be released or used for anything important, but
 | 
			
		||||
// sometimes useful for debugging. It reads in a file specified on the command line and runs it.
 | 
			
		||||
// It will report any errors in a developer-oriented way and discard the result.
 | 
			
		||||
//
 | 
			
		||||
// e.g., `cargo run -- foo.kcl`
 | 
			
		||||
#[tokio::main]
 | 
			
		||||
async fn main() {
 | 
			
		||||
    let mut args = env::args();
 | 
			
		||||
    args.next();
 | 
			
		||||
    let filename = args.next().unwrap_or_else(|| "main.kcl".to_owned());
 | 
			
		||||
 | 
			
		||||
    let mut f = File::open(&filename).unwrap();
 | 
			
		||||
    let mut text = String::new();
 | 
			
		||||
    f.read_to_string(&mut text).unwrap();
 | 
			
		||||
 | 
			
		||||
    let (program, errs) = Program::parse(&text).unwrap();
 | 
			
		||||
    if !errs.is_empty() {
 | 
			
		||||
        for e in errs {
 | 
			
		||||
            eprintln!("{e:#?}");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    let program = program.unwrap();
 | 
			
		||||
 | 
			
		||||
    let project_directory = filename.rfind('/').map(|i| filename[..i].into());
 | 
			
		||||
    let ctx = ExecutorContext::new_with_client(
 | 
			
		||||
        ExecutorSettings {
 | 
			
		||||
            project_directory,
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        },
 | 
			
		||||
        None,
 | 
			
		||||
        None,
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
    .unwrap();
 | 
			
		||||
    let mut exec_state = ExecState::new(&ctx.settings);
 | 
			
		||||
    ctx.run(&program, &mut exec_state).await.unwrap();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user