From 711f01fb84691b0ddde88171c661e279ca7fc08e Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 11:19:33 -0400 Subject: [PATCH 01/19] add StmtKind::Module --- libs/tree-sitter-wing/grammar.js | 4 ++-- libs/wingc/src/ast.rs | 4 ++++ libs/wingc/src/fold.rs | 4 ++++ libs/wingc/src/jsify.rs | 18 +++++++++++------- libs/wingc/src/parser.rs | 2 +- libs/wingc/src/type_check.rs | 3 +++ libs/wingc/src/visit.rs | 6 +++++- 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/libs/tree-sitter-wing/grammar.js b/libs/tree-sitter-wing/grammar.js index cfe29e6593a..d40b72d7ae3 100644 --- a/libs/tree-sitter-wing/grammar.js +++ b/libs/tree-sitter-wing/grammar.js @@ -96,7 +96,7 @@ module.exports = grammar({ _statement: ($) => choice( $.test_statement, - $.short_import_statement, + $.import_statement, $.expression_statement, $.variable_definition_statement, $.variable_assignment_statement, @@ -117,7 +117,7 @@ module.exports = grammar({ $.super_constructor_statement ), - short_import_statement: ($) => + import_statement: ($) => seq( "bring", field("module_name", choice($.identifier, $.string)), diff --git a/libs/wingc/src/ast.rs b/libs/wingc/src/ast.rs index b91ebae31cd..85883f6e59c 100644 --- a/libs/wingc/src/ast.rs +++ b/libs/wingc/src/ast.rs @@ -424,6 +424,10 @@ pub enum StmtKind { module_name: Symbol, // Reference? identifier: Option, }, + Module { + name: Symbol, + statements: Scope, + }, SuperConstructor { arg_list: ArgList, }, diff --git a/libs/wingc/src/fold.rs b/libs/wingc/src/fold.rs index 0e18f0ed90d..a4abc2f97ef 100644 --- a/libs/wingc/src/fold.rs +++ b/libs/wingc/src/fold.rs @@ -87,6 +87,10 @@ where module_name: f.fold_symbol(module_name), identifier: identifier.map(|id| f.fold_symbol(id)), }, + StmtKind::Module { name, statements } => StmtKind::Module { + name: f.fold_symbol(name), + statements: f.fold_scope(statements), + }, StmtKind::Let { reassignable, var_name, diff --git a/libs/wingc/src/jsify.rs b/libs/wingc/src/jsify.rs index 698ed77d346..1b79c2cddec 100644 --- a/libs/wingc/src/jsify.rs +++ b/libs/wingc/src/jsify.rs @@ -548,13 +548,6 @@ impl<'a> JSifier<'a> { fn jsify_statement(&self, env: &SymbolEnv, statement: &Stmt, ctx: &mut JSifyContext) -> CodeMaker { CompilationContext::set(CompilationPhase::Jsifying, &statement.span); match &statement.kind { - StmtKind::SuperConstructor { arg_list } => { - let args = self.jsify_arg_list(&arg_list, None, None, ctx); - match ctx.phase { - Phase::Preflight => CodeMaker::one_line(format!("super(scope,id,{});", args)), - _ => CodeMaker::one_line(format!("super({});", args)), - } - } StmtKind::Bring { module_name, identifier, @@ -578,6 +571,17 @@ impl<'a> JSifier<'a> { } )) } + StmtKind::Module { name: _, statements: _ } => { + // TODO + CodeMaker::default() + } + StmtKind::SuperConstructor { arg_list } => { + let args = self.jsify_arg_list(&arg_list, None, None, ctx); + match ctx.phase { + Phase::Preflight => CodeMaker::one_line(format!("super(scope,id,{});", args)), + _ => CodeMaker::one_line(format!("super({});", args)), + } + } StmtKind::Let { reassignable, var_name, diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index a392038c5f3..e24b0e3e81e 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -327,7 +327,7 @@ impl<'s> Parser<'s> { let span = self.node_span(statement_node); CompilationContext::set(CompilationPhase::Parsing, &span); let stmt_kind = match statement_node.kind() { - "short_import_statement" => self.build_bring_statement(statement_node)?, + "import_statement" => self.build_bring_statement(statement_node)?, "variable_definition_statement" => self.build_variable_def_statement(statement_node, phase)?, "variable_assignment_statement" => self.build_assignment_statement(statement_node, phase)?, diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index c47f3734fff..d410966b1df 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -3051,6 +3051,9 @@ impl<'a> TypeChecker<'a> { StmtKind::SuperConstructor { arg_list } => { self.type_check_arg_list(arg_list, env); } + StmtKind::Module { name: _, statements: _ } => { + // TODO + } } } diff --git a/libs/wingc/src/visit.rs b/libs/wingc/src/visit.rs index 885cd61c90e..8297e72022e 100644 --- a/libs/wingc/src/visit.rs +++ b/libs/wingc/src/visit.rs @@ -94,7 +94,6 @@ where V: Visit<'ast> + ?Sized, { match &node.kind { - StmtKind::SuperConstructor { arg_list } => v.visit_args(arg_list), StmtKind::Bring { module_name, identifier, @@ -104,6 +103,11 @@ where v.visit_symbol(identifier); } } + StmtKind::Module { name, statements } => { + v.visit_symbol(name); + v.visit_scope(statements); + } + StmtKind::SuperConstructor { arg_list } => v.visit_args(arg_list), StmtKind::Let { reassignable: _, var_name, From 7236c55483a2abd3e013f829959a061f82e4c111 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 12:14:41 -0400 Subject: [PATCH 02/19] progress --- libs/wingc/src/ast.rs | 2 +- libs/wingc/src/lifting.rs | 6 ++-- libs/wingc/src/parser.rs | 58 +++++++++++++++++++++++++++++++----- libs/wingc/src/type_check.rs | 15 ++++++++-- 4 files changed, 68 insertions(+), 13 deletions(-) diff --git a/libs/wingc/src/ast.rs b/libs/wingc/src/ast.rs index 85883f6e59c..ed2412fe4eb 100644 --- a/libs/wingc/src/ast.rs +++ b/libs/wingc/src/ast.rs @@ -632,7 +632,7 @@ pub enum InterpolatedStringPart { Expr(Expr), } -#[derive(Derivative)] +#[derive(Derivative, Default)] #[derivative(Debug)] pub struct Scope { pub statements: Vec, diff --git a/libs/wingc/src/lifting.rs b/libs/wingc/src/lifting.rs index 53c34e1980a..bb0e7ac8942 100644 --- a/libs/wingc/src/lifting.rs +++ b/libs/wingc/src/lifting.rs @@ -1,5 +1,5 @@ use crate::{ - ast::{Class, Expr, ExprKind, FunctionBody, FunctionDefinition, Phase, Reference, UserDefinedType}, + ast::{Class, Expr, ExprKind, FunctionBody, FunctionDefinition, Phase, Reference, Scope, Stmt, UserDefinedType}, comp_ctx::{CompilationContext, CompilationPhase}, diagnostic::{report_diagnostic, Diagnostic, WingSpan}, files::Files, @@ -355,14 +355,14 @@ impl<'a> Fold for LiftTransform<'a> { result } - fn fold_scope(&mut self, node: crate::ast::Scope) -> crate::ast::Scope { + fn fold_scope(&mut self, node: Scope) -> Scope { self.ctx.push_env(node.env.borrow().as_ref().unwrap().get_ref()); let result = fold::fold_scope(self, node); self.ctx.pop_env(); result } - fn fold_stmt(&mut self, node: crate::ast::Stmt) -> crate::ast::Stmt { + fn fold_stmt(&mut self, node: Stmt) -> Stmt { CompilationContext::set(CompilationPhase::Lifting, &node.span); self.ctx.push_stmt(node.idx); diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index e24b0e3e81e..781b03b12d8 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -2,7 +2,8 @@ use indexmap::{IndexMap, IndexSet}; use phf::{phf_map, phf_set}; use std::cell::RefCell; use std::collections::HashSet; -use std::{str, vec}; +use std::path::Path; +use std::{fs, str, vec}; use tree_sitter::Node; use tree_sitter_traversal::{traverse, Order}; @@ -567,13 +568,56 @@ impl<'s> Parser<'s> { } fn build_bring_statement(&self, statement_node: &Node) -> DiagnosticResult { - Ok(StmtKind::Bring { - module_name: self.node_symbol(&statement_node.child_by_field_name("module_name").unwrap())?, - identifier: if let Some(identifier) = statement_node.child_by_field_name("alias") { - Some(self.check_reserved_symbol(&identifier)?) + let module_name = self.node_symbol(&statement_node.child_by_field_name("module_name").unwrap())?; + let alias = if let Some(identifier) = statement_node.child_by_field_name("alias") { + Some(self.check_reserved_symbol(&identifier)?) + } else { + None + }; + + // if the module name is a path ending in .w, create a new Parser to parse it as a new Scope, + // and create a StmtKind::Module instead + if module_name.name.ends_with(".w\"") { + let source_path = Path::new(&module_name.name[1..module_name.name.len() - 1]); + let scope = match fs::read(&source_path) { + Ok(source) => { + let parser = Parser::new(&source, module_name.name.clone()); + let language = tree_sitter_wing::language(); + let mut tree_sitter_parser = tree_sitter::Parser::new(); + tree_sitter_parser.set_language(language).unwrap(); + let tree = match tree_sitter_parser.parse(&source, None) { + Some(tree) => tree, + None => { + panic!("Failed parsing source file: {}", source_path.display()); + } + }; + parser.wingit(&tree.root_node()) + } + Err(err) => { + report_diagnostic(Diagnostic { + message: format!("Error reading source file: {}: {:?}", source_path.display(), err), + span: None, + }); + Scope::default() + } + }; + + // parse error if no alias is provided + let module = if let Some(alias) = alias { + Ok(StmtKind::Module { + name: alias, + statements: scope, + }) } else { - None - }, + self.with_error::("No alias provided for module", statement_node) + }; + + return module; + } + + Ok(StmtKind::Bring { + module_name, + identifier: alias, }) } diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index d410966b1df..72445c35bb2 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -3051,8 +3051,19 @@ impl<'a> TypeChecker<'a> { StmtKind::SuperConstructor { arg_list } => { self.type_check_arg_list(arg_list, env); } - StmtKind::Module { name: _, statements: _ } => { - // TODO + StmtKind::Module { name: _, statements } => { + // why doesn't this work? + // self.type_check_scope(statements); + + statements.set_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); + self.inner_scopes.push(statements); } } } From 4267ff71bcdd78d6fa7c11bc59d96a2b859bcbe6 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 13:28:00 -0400 Subject: [PATCH 03/19] fix path resolution, start sketching out environment handling --- libs/wingc/src/parser.rs | 5 +++++ libs/wingc/src/type_check.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index 781b03b12d8..5b99ae433a5 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -579,6 +579,11 @@ impl<'s> Parser<'s> { // and create a StmtKind::Module instead if module_name.name.ends_with(".w\"") { let source_path = Path::new(&module_name.name[1..module_name.name.len() - 1]); + let source_path = if source_path.is_absolute() { + source_path.to_path_buf() + } else { + Path::new(&self.source_name).parent().unwrap().join(source_path) + }; let scope = match fs::read(&source_path) { Ok(source) => { let parser = Parser::new(&source, module_name.name.clone()); diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index 72445c35bb2..592c1fe495b 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -3064,6 +3064,19 @@ impl<'a> TypeChecker<'a> { stmt.idx, )); self.inner_scopes.push(statements); + + // let statement_env = statements.env.borrow().unwrap(); + // let ns = self.types.add_namespace(Namespace { + // name: name.to_string(), + // env: statement_env.get_ref(), + // loaded: true, + // }); + // match env.define(name, SymbolKind::Namespace(ns), StatementIdx::Top) { + // Err(type_error) => { + // self.type_error(type_error); + // } + // _ => {} + // }; } } } From cc2e6688278ab69817288d3e0d2033ca6b6dd0bb Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 13:39:22 -0400 Subject: [PATCH 04/19] store symbol envs in a vec --- libs/wingc/src/ast.rs | 6 +-- libs/wingc/src/lib.rs | 2 +- libs/wingc/src/type_check.rs | 88 +++++++++++++++++++++++++++++------- 3 files changed, 75 insertions(+), 21 deletions(-) diff --git a/libs/wingc/src/ast.rs b/libs/wingc/src/ast.rs index ed2412fe4eb..701b5854c5d 100644 --- a/libs/wingc/src/ast.rs +++ b/libs/wingc/src/ast.rs @@ -8,7 +8,7 @@ use indexmap::{Equivalent, IndexMap, IndexSet}; use itertools::Itertools; use crate::diagnostic::WingSpan; -use crate::type_check::symbol_env::SymbolEnv; +use crate::type_check::symbol_env::SymbolEnvRef; use crate::type_check::CLOSURE_CLASS_HANDLE_METHOD; static EXPR_COUNTER: AtomicUsize = AtomicUsize::new(0); @@ -638,7 +638,7 @@ pub struct Scope { pub statements: Vec, pub span: WingSpan, #[derivative(Debug = "ignore")] - pub env: RefCell>, // None after parsing, set to Some during type checking phase + pub env: RefCell>, // None after parsing, set to Some during type checking phase } impl Scope { @@ -650,7 +650,7 @@ impl Scope { } } - pub fn set_env(&self, new_env: SymbolEnv) { + pub fn set_env(&self, new_env: SymbolEnvRef) { let mut env = self.env.borrow_mut(); assert!((*env).is_none()); *env = Some(new_env); diff --git a/libs/wingc/src/lib.rs b/libs/wingc/src/lib.rs index ab652776e25..9536e893d9b 100644 --- a/libs/wingc/src/lib.rs +++ b/libs/wingc/src/lib.rs @@ -211,7 +211,7 @@ pub fn type_check( jsii_imports: &mut Vec, ) { assert!(scope.env.borrow().is_none(), "Scope should not have an env yet"); - let env = SymbolEnv::new(None, types.void(), false, false, Phase::Preflight, 0); + let env = types.add_symbol_env(SymbolEnv::new(None, types.void(), false, false, Phase::Preflight, 0)); scope.set_env(env); // note: Globals are emitted here and wrapped in "{ ... }" blocks. Wrapping makes these emissions, actual diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index 592c1fe495b..9f9cc14fb62 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -1087,7 +1087,8 @@ pub struct Types { // Note: we need the box so reallocations of the vec while growing won't change the addresses of the types since they are referenced from the TypeRef struct types: Vec>, namespaces: Vec>, - pub libraries: SymbolEnv, + symbol_envs: Vec>, + pub libraries: SymbolEnv, // ? numeric_idx: usize, string_idx: usize, bool_idx: usize, @@ -1136,6 +1137,7 @@ impl Types { Self { types, namespaces: Vec::new(), + symbol_envs: Vec::new(), libraries, numeric_idx, string_idx, @@ -1235,6 +1237,16 @@ impl Types { UnsafeRef::(&**t as *const Namespace) } + pub fn add_symbol_env(&mut self, s: SymbolEnv) -> SymbolEnvRef { + self.symbol_envs.push(Box::new(s)); + self.get_symbolenvref(self.symbol_envs.len() - 1) + } + + fn get_symbolenvref(&self, idx: usize) -> SymbolEnvRef { + let t = &self.symbol_envs[idx]; + UnsafeRef::(&**t as *const SymbolEnv) + } + fn resource_base_type(&mut self) -> TypeRef { // cache the resource base type ref if self.resource_base_type.is_none() { @@ -2075,14 +2087,14 @@ impl<'a> TypeChecker<'a> { let sig = function_type.as_function_sig().unwrap(); // Create an environment for the function - let mut function_env = SymbolEnv::new( + let mut function_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), sig.return_type, false, true, func_def.signature.phase, self.statement_idx, - ); + )); self.add_arguments_to_env(&func_def.signature.parameters, &sig, &mut function_env); // Type check the function body @@ -2425,7 +2437,14 @@ impl<'a> TypeChecker<'a> { _t => self.types.error(), }; - let mut scope_env = SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx); + let mut scope_env = self.types.add_symbol_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); match scope_env.define( &iterator, SymbolKind::make_free_variable(iterator.clone(), iterator_type, false, env.phase), @@ -2444,7 +2463,7 @@ impl<'a> TypeChecker<'a> { let (cond_type, _) = self.type_check_exp(condition, env); self.validate_type(cond_type, self.types.bool(), condition); - statements.set_env(SymbolEnv::new( + let scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2452,6 +2471,7 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + statements.set_env(scope_env); self.inner_scopes.push(statements); } @@ -2477,7 +2497,14 @@ impl<'a> TypeChecker<'a> { // and complete the type checking process for additional errors. let var_type = *cond_type.maybe_unwrap_option(); - let mut stmt_env = SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx); + let mut stmt_env = self.types.add_symbol_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); // Add the variable to if block scope match stmt_env.define( @@ -2495,7 +2522,7 @@ impl<'a> TypeChecker<'a> { self.inner_scopes.push(statements); if let Some(else_scope) = else_statements { - else_scope.set_env(SymbolEnv::new( + let else_scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2503,6 +2530,7 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + else_scope.set_env(else_scope_env); self.inner_scopes.push(else_scope); } } @@ -2515,7 +2543,7 @@ impl<'a> TypeChecker<'a> { let (cond_type, _) = self.type_check_exp(condition, env); self.validate_type(cond_type, self.types.bool(), condition); - statements.set_env(SymbolEnv::new( + let if_scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2523,13 +2551,14 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + statements.set_env(if_scope_env); self.inner_scopes.push(statements); for elif_scope in elif_statements { let (cond_type, _) = self.type_check_exp(&elif_scope.condition, env); self.validate_type(cond_type, self.types.bool(), condition); - (&elif_scope.statements).set_env(SymbolEnv::new( + let elif_scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2537,11 +2566,12 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + elif_scope.statements.set_env(elif_scope_env); self.inner_scopes.push(&elif_scope.statements); } if let Some(else_scope) = else_statements { - else_scope.set_env(SymbolEnv::new( + let else_scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2549,6 +2579,7 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + else_scope.set_env(else_scope_env); self.inner_scopes.push(else_scope); } } @@ -2623,7 +2654,7 @@ impl<'a> TypeChecker<'a> { self.add_module_to_env(env, library_name, namespace_filter, &alias, Some(&stmt)); } StmtKind::Scope(scope) => { - scope.set_env(SymbolEnv::new( + let scope_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -2631,6 +2662,7 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + scope.set_env(scope_env); self.inner_scopes.push(scope) } StmtKind::Return(exp) => { @@ -3012,13 +3044,27 @@ impl<'a> TypeChecker<'a> { finally_statements, } => { // Create a new environment for the try block - let try_env = SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx); + let try_env = self.types.add_symbol_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); try_statements.set_env(try_env); self.inner_scopes.push(try_statements); // Create a new environment for the catch block if let Some(catch_block) = catch_block { - let mut catch_env = SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx); + let mut catch_env = self.types.add_symbol_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); // Add the exception variable to the catch block if let Some(exception_var) = &catch_block.exception_var { @@ -3039,7 +3085,14 @@ impl<'a> TypeChecker<'a> { // Create a new environment for the finally block if let Some(finally_statements) = finally_statements { - let finally_env = SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx); + let finally_env = self.types.add_symbol_env(SymbolEnv::new( + Some(env.get_ref()), + env.return_type, + false, + false, + env.phase, + stmt.idx, + )); finally_statements.set_env(finally_env); self.inner_scopes.push(finally_statements); } @@ -3055,7 +3108,7 @@ impl<'a> TypeChecker<'a> { // why doesn't this work? // self.type_check_scope(statements); - statements.set_env(SymbolEnv::new( + let statements_env = self.types.add_symbol_env(SymbolEnv::new( Some(env.get_ref()), env.return_type, false, @@ -3063,6 +3116,7 @@ impl<'a> TypeChecker<'a> { env.phase, stmt.idx, )); + statements.set_env(statements_env); self.inner_scopes.push(statements); // let statement_env = statements.env.borrow().unwrap(); @@ -3222,14 +3276,14 @@ impl<'a> TypeChecker<'a> { // Create method environment and prime it with args let is_init = method_name.name == CLASS_INIT_NAME || method_name.name == CLASS_INFLIGHT_INIT_NAME; - let mut method_env = SymbolEnv::new( + let mut method_env = self.types.add_symbol_env(SymbolEnv::new( Some(parent_env.get_ref()), method_sig.return_type, is_init, true, method_sig.phase, statement_idx, - ); + )); // Prime the method environment with `this` if !method_def.is_static || is_init { method_env From c8b0d7e5250479bbef65e850b67da1df4e343d48 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 13:48:11 -0400 Subject: [PATCH 05/19] type checking works --- libs/wingc/src/type_check.rs | 42 +++++++++++++++--------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/libs/wingc/src/type_check.rs b/libs/wingc/src/type_check.rs index 9f9cc14fb62..927213a85f9 100644 --- a/libs/wingc/src/type_check.rs +++ b/libs/wingc/src/type_check.rs @@ -3104,33 +3104,25 @@ impl<'a> TypeChecker<'a> { StmtKind::SuperConstructor { arg_list } => { self.type_check_arg_list(arg_list, env); } - StmtKind::Module { name: _, statements } => { - // why doesn't this work? - // self.type_check_scope(statements); + StmtKind::Module { name, statements } => { + let ns = self.types.add_namespace(Namespace { + name: name.to_string(), + env: SymbolEnv::new(Some(env.get_ref()), env.return_type, false, false, env.phase, stmt.idx), + loaded: true, + }); + statements.set_env(ns.env.get_ref()); - let statements_env = self.types.add_symbol_env(SymbolEnv::new( - Some(env.get_ref()), - env.return_type, - false, - false, - env.phase, - stmt.idx, - )); - statements.set_env(statements_env); - self.inner_scopes.push(statements); + // instead of pushing `statements` into `self.inner_scopes`, + // we need to type check the statements in the module's namespace + // so that subsequence statements can reference symbols inside the module + self.type_check_scope(statements); - // let statement_env = statements.env.borrow().unwrap(); - // let ns = self.types.add_namespace(Namespace { - // name: name.to_string(), - // env: statement_env.get_ref(), - // loaded: true, - // }); - // match env.define(name, SymbolKind::Namespace(ns), StatementIdx::Top) { - // Err(type_error) => { - // self.type_error(type_error); - // } - // _ => {} - // }; + match env.define(name, SymbolKind::Namespace(ns), StatementIdx::Index(stmt.idx)) { + Err(type_error) => { + self.type_error(type_error); + } + _ => {} + }; } } } From 3d416ccd27403b9d08375ed4f38152282b04528e Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 14:18:51 -0400 Subject: [PATCH 06/19] initial code generation --- libs/wingc/src/jsify.rs | 57 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/libs/wingc/src/jsify.rs b/libs/wingc/src/jsify.rs index 1b79c2cddec..bd6f04e951b 100644 --- a/libs/wingc/src/jsify.rs +++ b/libs/wingc/src/jsify.rs @@ -571,9 +571,19 @@ impl<'a> JSifier<'a> { } )) } - StmtKind::Module { name: _, statements: _ } => { - // TODO - CodeMaker::default() + StmtKind::Module { name, statements } => { + let mut code = CodeMaker::default(); + code.open(format!("const {} = (() => {{", name.name)); + code.add_code(self.jsify_scope_body(statements, ctx)); + + let exports = get_public_symbols(statements); + code.line(format!( + "return {{ {} }};", + exports.iter().map(ToString::to_string).join(", ") + )); + + code.close("})();"); + code } StmtKind::SuperConstructor { arg_list } => { let args = self.jsify_arg_list(&arg_list, None, None, ctx); @@ -1249,6 +1259,47 @@ impl<'a> JSifier<'a> { } } +fn get_public_symbols(scope: &Scope) -> Vec { + let mut symbols = Vec::new(); + + for stmt in &scope.statements { + match &stmt.kind { + StmtKind::Bring { .. } => {} + StmtKind::Module { name, .. } => { + symbols.push(name.clone()); + } + StmtKind::SuperConstructor { .. } => {} + StmtKind::Let { .. } => {} + StmtKind::ForLoop { .. } => {} + StmtKind::While { .. } => {} + StmtKind::IfLet { .. } => {} + StmtKind::If { .. } => {} + StmtKind::Break => {} + StmtKind::Continue => {} + StmtKind::Return(_) => {} + StmtKind::Expression(_) => {} + StmtKind::Assignment { .. } => {} + StmtKind::Scope(_) => {} + StmtKind::Class(class) => { + symbols.push(class.name.clone()); + } + StmtKind::Interface(iface) => { + symbols.push(iface.name.clone()); + } + StmtKind::Struct { name, .. } => { + symbols.push(name.clone()); + } + StmtKind::Enum { name, .. } => { + symbols.push(name.clone()); + } + StmtKind::TryCatch { .. } => {} + StmtKind::CompilerDebugEnv => {} + } + } + + symbols +} + fn inflight_filename(class: &AstClass) -> String { format!("./inflight.{}.js", class.name.name) } From 640ce85d7d32acbbec8af18d67c8e8ecf60eda12 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 14:33:57 -0400 Subject: [PATCH 07/19] fix panic issue - parser needs to add to Files --- libs/wingc/src/lib.rs | 17 ++++------------ libs/wingc/src/lsp/sync.rs | 13 ++----------- libs/wingc/src/parser.rs | 40 +++++++++++++++++++++++++------------- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/libs/wingc/src/lib.rs b/libs/wingc/src/lib.rs index 9536e893d9b..06ad7a8d9a9 100644 --- a/libs/wingc/src/lib.rs +++ b/libs/wingc/src/lib.rs @@ -180,17 +180,6 @@ pub fn parse(source_path: &Path) -> (Files, Scope) { } }; - let mut files = Files::new(); - match files.add_file( - source_path.to_path_buf(), - String::from_utf8(source.clone()).expect("Invalid UTF-8 sequence"), - ) { - Ok(_) => {} - Err(err) => { - panic!("Failed adding source file to parser: {}", err); - } - } - let tree = match parser.parse(&source, None) { Some(tree) => tree, None => { @@ -198,9 +187,11 @@ pub fn parse(source_path: &Path) -> (Files, Scope) { } }; - let wing_parser = Parser::new(&source, source_path.to_str().unwrap().to_string()); + let mut files = Files::new(); + let wing_parser = Parser::new(&source, source_path.to_str().unwrap().to_string(), &mut files); + let scope = wing_parser.wingit(&tree.root_node()); - (files, wing_parser.wingit(&tree.root_node())) + (files, scope) } pub fn type_check( diff --git a/libs/wingc/src/lsp/sync.rs b/libs/wingc/src/lsp/sync.rs index 790b6569ed0..c5045b70dbe 100644 --- a/libs/wingc/src/lsp/sync.rs +++ b/libs/wingc/src/lsp/sync.rs @@ -106,19 +106,10 @@ fn partial_compile(source_file: &str, text: &[u8], jsii_types: &mut TypeSystem) } }; - let wing_parser = Parser::new(text, source_file.to_string()); + let mut files = Files::new(); + let wing_parser = Parser::new(text, source_file.to_string(), &mut files); let scope = wing_parser.wingit(&tree.root_node()); - let mut files = Files::new(); - match files.add_file( - source_file, - String::from_utf8(text.to_vec()).expect("Invalid utf-8 sequence"), - ) { - Ok(_) => {} - Err(err) => { - panic!("Failed adding source file to parser: {}", err); - } - } // -- DESUGARING PHASE -- diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index 5b99ae433a5..b79b0663128 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -2,7 +2,7 @@ use indexmap::{IndexMap, IndexSet}; use phf::{phf_map, phf_set}; use std::cell::RefCell; use std::collections::HashSet; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::{fs, str, vec}; use tree_sitter::Node; use tree_sitter_traversal::{traverse, Order}; @@ -15,19 +15,10 @@ use crate::ast::{ }; use crate::comp_ctx::{CompilationContext, CompilationPhase}; use crate::diagnostic::{report_diagnostic, Diagnostic, DiagnosticResult, WingSpan}; +use crate::files::Files; use crate::type_check::{CLASS_INFLIGHT_INIT_NAME, CLASS_INIT_NAME}; use crate::{dbg_panic, WINGSDK_STD_MODULE, WINGSDK_TEST_CLASS_NAME}; -pub struct Parser<'a> { - pub source: &'a [u8], - pub source_name: String, - pub error_nodes: RefCell>, - // Nesting level within JSON literals, a value larger than 0 means we're currently in a JSON literal - in_json: RefCell, - is_in_mut_json: RefCell, - is_in_loop: RefCell, -} - // A custom struct could be used to better maintain metadata and issue tracking, though ideally // this is meant to serve as a bandaide to be removed once wing is further developed. // k=grammar, v=optional_message, example: ("generic", "targed impl: 1.0.0") @@ -140,11 +131,23 @@ static RESERVED_WORDS: phf::Set<&'static str> = phf_set! { "Object", }; +pub struct Parser<'a> { + pub source: &'a [u8], + pub source_name: String, + pub error_nodes: RefCell>, + files: RefCell<&'a mut Files>, + // Nesting level within JSON literals, a value larger than 0 means we're currently in a JSON literal + in_json: RefCell, + is_in_mut_json: RefCell, + is_in_loop: RefCell, +} + impl<'s> Parser<'s> { - pub fn new(source: &'s [u8], source_name: String) -> Self { + pub fn new(source: &'s [u8], source_name: String, files: &'s mut Files) -> Self { Self { source, source_name, + files: RefCell::new(files), error_nodes: RefCell::new(HashSet::new()), is_in_loop: RefCell::new(false), // This is similar to what we do in the type_checker, but we need to know 2 things when @@ -157,6 +160,16 @@ impl<'s> Parser<'s> { } pub fn wingit(&self, root: &Node) -> Scope { + match self.files.borrow_mut().add_file( + PathBuf::from(self.source_name.clone()), + String::from_utf8(self.source.to_vec()).expect("Invalid UTF-8 sequence"), + ) { + Ok(_) => {} + Err(err) => { + panic!("Failed adding source file to parser: {}", err); + } + } + let scope = match root.kind() { "source" => self.build_scope(&root, Phase::Preflight), _ => Scope { @@ -586,7 +599,8 @@ impl<'s> Parser<'s> { }; let scope = match fs::read(&source_path) { Ok(source) => { - let parser = Parser::new(&source, module_name.name.clone()); + let mut files = self.files.borrow_mut(); + let parser = Parser::new(&source, module_name.name.clone(), *files); let language = tree_sitter_wing::language(); let mut tree_sitter_parser = tree_sitter::Parser::new(); tree_sitter_parser.set_language(language).unwrap(); From 93c54c64852eaca2710aed509eebf448bd25480e Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Fri, 14 Jul 2023 14:58:33 -0400 Subject: [PATCH 08/19] handle paths better --- libs/wingc/src/parser.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index b79b0663128..a9ffc274a11 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -592,15 +592,23 @@ impl<'s> Parser<'s> { // and create a StmtKind::Module instead if module_name.name.ends_with(".w\"") { let source_path = Path::new(&module_name.name[1..module_name.name.len() - 1]); + let source_path = if source_path.starts_with("./") { + source_path.strip_prefix("./").unwrap() + } else { + source_path + }; let source_path = if source_path.is_absolute() { source_path.to_path_buf() } else { Path::new(&self.source_name).parent().unwrap().join(source_path) }; + if source_path == Path::new(&self.source_name) { + return self.with_error("Cannot bring in the current module", statement_node); + } let scope = match fs::read(&source_path) { Ok(source) => { let mut files = self.files.borrow_mut(); - let parser = Parser::new(&source, module_name.name.clone(), *files); + let parser = Parser::new(&source, source_path.to_string_lossy().to_string(), *files); let language = tree_sitter_wing::language(); let mut tree_sitter_parser = tree_sitter::Parser::new(); tree_sitter_parser.set_language(language).unwrap(); From 76d05cfae3fb0dae8c1ba52b7c15ef45b705a327 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Mon, 17 Jul 2023 19:16:45 -0400 Subject: [PATCH 09/19] fix bug, add examples --- examples/tests/invalid/bring_local_self.w | 2 + examples/tests/valid/bring_local.w | 26 ++ examples/tests/valid/store.w | 26 ++ libs/wingc/src/jsify.rs | 8 +- libs/wingc/src/parser.rs | 2 +- tools/hangar/__snapshots__/invalid.ts.snap | 15 + .../valid/bring_local.w_compile_tf-aws.md | 341 ++++++++++++++++++ .../valid/bring_local.w_test_sim.md | 12 + .../valid/store.w_compile_tf-aws.md | 109 ++++++ .../test_corpus/valid/store.w_test_sim.md | 12 + 10 files changed, 546 insertions(+), 7 deletions(-) create mode 100644 examples/tests/invalid/bring_local_self.w create mode 100644 examples/tests/valid/bring_local.w create mode 100644 examples/tests/valid/store.w create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_test_sim.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/store.w_compile_tf-aws.md create mode 100644 tools/hangar/__snapshots__/test_corpus/valid/store.w_test_sim.md diff --git a/examples/tests/invalid/bring_local_self.w b/examples/tests/invalid/bring_local_self.w new file mode 100644 index 00000000000..e1f53ad5e75 --- /dev/null +++ b/examples/tests/invalid/bring_local_self.w @@ -0,0 +1,2 @@ +bring "./bring_local_self.w" as foo; +// ^ error: Cannot bring a module into itself diff --git a/examples/tests/valid/bring_local.w b/examples/tests/valid/bring_local.w new file mode 100644 index 00000000000..f2a849f88ee --- /dev/null +++ b/examples/tests/valid/bring_local.w @@ -0,0 +1,26 @@ +bring "./store.w" as file1; + +// classes from other files can be used +let store = new file1.Store(); + +test "add data to store" { + store.store("foo"); +} + +// structs from other files can be used +let s = file1.Point { + x: 1, + y: 2, +}; + +// enums from other files can be used +let c = file1.Color.BLUE; +assert(c != file1.Color.RED); + +// interfaces from other files can be used +class Triangle impl file1.Shape { + area(): num { + return 1; + } +} +let t = new Triangle(); diff --git a/examples/tests/valid/store.w b/examples/tests/valid/store.w new file mode 100644 index 00000000000..6bb65358d14 --- /dev/null +++ b/examples/tests/valid/store.w @@ -0,0 +1,26 @@ +bring cloud; + +class Store { + b: cloud.Bucket; + init() { + this.b = new cloud.Bucket(); + } + inflight store(data: str) { + this.b.put("data.txt", data); + } +} + +enum Color { + RED, + GREEN, + BLUE, +} + +struct Point { + x: num; + y: num; +} + +interface Shape { + area(): num; +} diff --git a/libs/wingc/src/jsify.rs b/libs/wingc/src/jsify.rs index bd6f04e951b..cb74c056b64 100644 --- a/libs/wingc/src/jsify.rs +++ b/libs/wingc/src/jsify.rs @@ -1283,12 +1283,8 @@ fn get_public_symbols(scope: &Scope) -> Vec { StmtKind::Class(class) => { symbols.push(class.name.clone()); } - StmtKind::Interface(iface) => { - symbols.push(iface.name.clone()); - } - StmtKind::Struct { name, .. } => { - symbols.push(name.clone()); - } + StmtKind::Interface(_) => {} + StmtKind::Struct { .. } => {} StmtKind::Enum { name, .. } => { symbols.push(name.clone()); } diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index a9ffc274a11..72a3abc8513 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -603,7 +603,7 @@ impl<'s> Parser<'s> { Path::new(&self.source_name).parent().unwrap().join(source_path) }; if source_path == Path::new(&self.source_name) { - return self.with_error("Cannot bring in the current module", statement_node); + return self.with_error("Cannot bring a module into itself", statement_node); } let scope = match fs::read(&source_path) { Ok(source) => { diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 64213a37ce8..0ec909fbfb6 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -118,6 +118,21 @@ error: Cannot find module \\"foobar\\" in source directory: Unable to load \\"fo +Tests 1 failed (1) +Test Files 1 failed (1) +Duration " +`; + +exports[`bring_local_self.w 1`] = ` +"error: Cannot bring a module into itself + --> ../../../examples/tests/invalid/bring_local_self.w:1:1 + | +1 | bring \\"./bring_local_self.w\\" as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot bring a module into itself + + + + Tests 1 failed (1) Test Files 1 failed (1) Duration " diff --git a/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md new file mode 100644 index 00000000000..96c56a7d3c5 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md @@ -0,0 +1,341 @@ +# [bring_local.w](../../../../../examples/tests/valid/bring_local.w) | compile | tf-aws + +## inflight.$Closure1.js +```js +module.exports = function({ $store }) { + class $Closure1 { + constructor({ }) { + const $obj = (...args) => this.handle(...args); + Object.setPrototypeOf($obj, this); + return $obj; + } + async handle() { + (await $store.store("foo")); + } + } + return $Closure1; +} + +``` + +## inflight.Store.js +```js +module.exports = function({ }) { + class Store { + constructor({ $this_b }) { + this.$this_b = $this_b; + } + async store(data) { + (await this.$this_b.put("data.txt",data)); + } + } + return Store; +} + +``` + +## inflight.Triangle.js +```js +module.exports = function({ }) { + class Triangle { + constructor({ }) { + } + } + return Triangle; +} + +``` + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root", + "version": "0.17.0" + }, + "outputs": { + "root": { + "Default": { + "cloud.TestRunner": { + "TestFunctionArns": "WING_TEST_RUNNER_FUNCTION_ARNS" + } + } + } + } + }, + "output": { + "WING_TEST_RUNNER_FUNCTION_ARNS": { + "value": "[[\"root/Default/Default/test:add data to store\",\"${aws_lambda_function.testadddatatostore_Handler_19066842.arn}\"]]" + } + }, + "provider": { + "aws": [ + {} + ] + }, + "resource": { + "aws_iam_role": { + "testadddatatostore_Handler_IamRole_D112FE1A": { + "//": { + "metadata": { + "path": "root/Default/Default/test:add data to store/Handler/IamRole", + "uniqueId": "testadddatatostore_Handler_IamRole_D112FE1A" + } + }, + "assume_role_policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":\"sts:AssumeRole\",\"Principal\":{\"Service\":\"lambda.amazonaws.com\"},\"Effect\":\"Allow\"}]}" + } + }, + "aws_iam_role_policy": { + "testadddatatostore_Handler_IamRolePolicy_2759864D": { + "//": { + "metadata": { + "path": "root/Default/Default/test:add data to store/Handler/IamRolePolicy", + "uniqueId": "testadddatatostore_Handler_IamRolePolicy_2759864D" + } + }, + "policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Action\":[\"s3:PutObject*\",\"s3:Abort*\"],\"Resource\":[\"${aws_s3_bucket.file1Store_cloudBucket_86CE87B1.arn}\",\"${aws_s3_bucket.file1Store_cloudBucket_86CE87B1.arn}/*\"],\"Effect\":\"Allow\"}]}", + "role": "${aws_iam_role.testadddatatostore_Handler_IamRole_D112FE1A.name}" + } + }, + "aws_iam_role_policy_attachment": { + "testadddatatostore_Handler_IamRolePolicyAttachment_1100277D": { + "//": { + "metadata": { + "path": "root/Default/Default/test:add data to store/Handler/IamRolePolicyAttachment", + "uniqueId": "testadddatatostore_Handler_IamRolePolicyAttachment_1100277D" + } + }, + "policy_arn": "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + "role": "${aws_iam_role.testadddatatostore_Handler_IamRole_D112FE1A.name}" + } + }, + "aws_lambda_function": { + "testadddatatostore_Handler_19066842": { + "//": { + "metadata": { + "path": "root/Default/Default/test:add data to store/Handler/Default", + "uniqueId": "testadddatatostore_Handler_19066842" + } + }, + "environment": { + "variables": { + "BUCKET_NAME_94dc4b3e": "${aws_s3_bucket.file1Store_cloudBucket_86CE87B1.bucket}", + "WING_FUNCTION_NAME": "Handler-c8157444", + "WING_TARGET": "tf-aws" + } + }, + "function_name": "Handler-c8157444", + "handler": "index.handler", + "publish": true, + "role": "${aws_iam_role.testadddatatostore_Handler_IamRole_D112FE1A.arn}", + "runtime": "nodejs18.x", + "s3_bucket": "${aws_s3_bucket.Code.bucket}", + "s3_key": "${aws_s3_object.testadddatatostore_Handler_S3Object_6CF2BC7E.key}", + "timeout": 30, + "vpc_config": { + "security_group_ids": [], + "subnet_ids": [] + } + } + }, + "aws_s3_bucket": { + "Code": { + "//": { + "metadata": { + "path": "root/Default/Code", + "uniqueId": "Code" + } + }, + "bucket_prefix": "code-c84a50b1-" + }, + "file1Store_cloudBucket_86CE87B1": { + "//": { + "metadata": { + "path": "root/Default/Default/file1.Store/cloud.Bucket/Default", + "uniqueId": "file1Store_cloudBucket_86CE87B1" + } + }, + "bucket_prefix": "cloud-bucket-c8b6ef02-", + "force_destroy": false + } + }, + "aws_s3_bucket_public_access_block": { + "file1Store_cloudBucket_PublicAccessBlock_542A96A5": { + "//": { + "metadata": { + "path": "root/Default/Default/file1.Store/cloud.Bucket/PublicAccessBlock", + "uniqueId": "file1Store_cloudBucket_PublicAccessBlock_542A96A5" + } + }, + "block_public_acls": true, + "block_public_policy": true, + "bucket": "${aws_s3_bucket.file1Store_cloudBucket_86CE87B1.bucket}", + "ignore_public_acls": true, + "restrict_public_buckets": true + } + }, + "aws_s3_bucket_server_side_encryption_configuration": { + "file1Store_cloudBucket_Encryption_387D9114": { + "//": { + "metadata": { + "path": "root/Default/Default/file1.Store/cloud.Bucket/Encryption", + "uniqueId": "file1Store_cloudBucket_Encryption_387D9114" + } + }, + "bucket": "${aws_s3_bucket.file1Store_cloudBucket_86CE87B1.bucket}", + "rule": [ + { + "apply_server_side_encryption_by_default": { + "sse_algorithm": "AES256" + } + } + ] + } + }, + "aws_s3_object": { + "testadddatatostore_Handler_S3Object_6CF2BC7E": { + "//": { + "metadata": { + "path": "root/Default/Default/test:add data to store/Handler/S3Object", + "uniqueId": "testadddatatostore_Handler_S3Object_6CF2BC7E" + } + }, + "bucket": "${aws_s3_bucket.Code.bucket}", + "key": "", + "source": "" + } + } + } +} +``` + +## preflight.js +```js +const $stdlib = require('@winglang/sdk'); +const $outdir = process.env.WING_SYNTH_DIR ?? "."; +const std = $stdlib.std; +const $wing_is_test = process.env.WING_IS_TEST === "true"; +class $Root extends $stdlib.std.Resource { + constructor(scope, id) { + super(scope, id); + class $Closure1 extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this.display.hidden = true; + this._addInflightOps("handle", "$inflight_init"); + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.$Closure1.js")({ + $store: ${context._lift(store)}, + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const $Closure1Client = ${$Closure1._toInflightType(this).text}; + const client = new $Closure1Client({ + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + _registerBind(host, ops) { + if (ops.includes("handle")) { + $Closure1._registerBindObject(store, host, ["store"]); + } + super._registerBind(host, ops); + } + } + class Triangle extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this._addInflightOps("$inflight_init"); + } + area() { + return 1; + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.Triangle.js")({ + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const TriangleClient = ${Triangle._toInflightType(this).text}; + const client = new TriangleClient({ + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + } + const file1 = (() => { + const cloud = require('@winglang/sdk').cloud; + class Store extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this.b = this.node.root.newAbstract("@winglang/sdk.cloud.Bucket",this,"cloud.Bucket"); + this._addInflightOps("store", "$inflight_init"); + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.Store.js")({ + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const StoreClient = ${Store._toInflightType(this).text}; + const client = new StoreClient({ + $this_b: ${this._lift(this.b)}, + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + _registerBind(host, ops) { + if (ops.includes("$inflight_init")) { + Store._registerBindObject(this.b, host, []); + } + if (ops.includes("store")) { + Store._registerBindObject(this.b, host, ["put"]); + } + super._registerBind(host, ops); + } + } + const Color = + Object.freeze((function (tmp) { + tmp[tmp["RED"] = 0] = "RED"; + tmp[tmp["GREEN"] = 1] = "GREEN"; + tmp[tmp["BLUE"] = 2] = "BLUE"; + return tmp; + })({})) + ; + return { Store, Color }; + })(); + const store = new file1.Store(this,"file1.Store"); + this.node.root.new("@winglang/sdk.std.Test",std.Test,this,"test:add data to store",new $Closure1(this,"$Closure1")); + const s = { + "x": 1, + "y": 2,} + ; + const c = file1.Color.BLUE; + {((cond) => {if (!cond) throw new Error("assertion failed: c != file1.Color.RED")})((c !== file1.Color.RED))}; + const t = new Triangle(this,"Triangle"); + } +} +const $App = $stdlib.core.App.for(process.env.WING_TARGET); +new $App({ outdir: $outdir, name: "bring_local", rootConstruct: $Root, plugins: $plugins, isTestEnvironment: $wing_is_test }).synth(); + +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_test_sim.md new file mode 100644 index 00000000000..aa54e63e208 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_test_sim.md @@ -0,0 +1,12 @@ +# [bring_local.w](../../../../../examples/tests/valid/bring_local.w) | test | sim + +## stdout.log +```log +pass ─ bring_local.wsim » root/env0/test:add data to store + + +Tests 1 passed (1) +Test Files 1 passed (1) +Duration +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/store.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/store.w_compile_tf-aws.md new file mode 100644 index 00000000000..5da0dc93f62 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/store.w_compile_tf-aws.md @@ -0,0 +1,109 @@ +# [store.w](../../../../../examples/tests/valid/store.w) | compile | tf-aws + +## inflight.Store.js +```js +module.exports = function({ }) { + class Store { + constructor({ $this_b }) { + this.$this_b = $this_b; + } + async store(data) { + (await this.$this_b.put("data.txt",data)); + } + } + return Store; +} + +``` + +## main.tf.json +```json +{ + "//": { + "metadata": { + "backend": "local", + "stackName": "root", + "version": "0.17.0" + }, + "outputs": { + "root": { + "Default": { + "cloud.TestRunner": { + "TestFunctionArns": "WING_TEST_RUNNER_FUNCTION_ARNS" + } + } + } + } + }, + "output": { + "WING_TEST_RUNNER_FUNCTION_ARNS": { + "value": "[]" + } + }, + "provider": { + "aws": [ + {} + ] + } +} +``` + +## preflight.js +```js +const $stdlib = require('@winglang/sdk'); +const $outdir = process.env.WING_SYNTH_DIR ?? "."; +const std = $stdlib.std; +const $wing_is_test = process.env.WING_IS_TEST === "true"; +const cloud = require('@winglang/sdk').cloud; +class $Root extends $stdlib.std.Resource { + constructor(scope, id) { + super(scope, id); + class Store extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this.b = this.node.root.newAbstract("@winglang/sdk.cloud.Bucket",this,"cloud.Bucket"); + this._addInflightOps("store", "$inflight_init"); + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.Store.js")({ + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const StoreClient = ${Store._toInflightType(this).text}; + const client = new StoreClient({ + $this_b: ${this._lift(this.b)}, + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + _registerBind(host, ops) { + if (ops.includes("$inflight_init")) { + Store._registerBindObject(this.b, host, []); + } + if (ops.includes("store")) { + Store._registerBindObject(this.b, host, ["put"]); + } + super._registerBind(host, ops); + } + } + const Color = + Object.freeze((function (tmp) { + tmp[tmp["RED"] = 0] = "RED"; + tmp[tmp["GREEN"] = 1] = "GREEN"; + tmp[tmp["BLUE"] = 2] = "BLUE"; + return tmp; + })({})) + ; + } +} +const $App = $stdlib.core.App.for(process.env.WING_TARGET); +new $App({ outdir: $outdir, name: "store", rootConstruct: $Root, plugins: $plugins, isTestEnvironment: $wing_is_test }).synth(); + +``` + diff --git a/tools/hangar/__snapshots__/test_corpus/valid/store.w_test_sim.md b/tools/hangar/__snapshots__/test_corpus/valid/store.w_test_sim.md new file mode 100644 index 00000000000..3632964b583 --- /dev/null +++ b/tools/hangar/__snapshots__/test_corpus/valid/store.w_test_sim.md @@ -0,0 +1,12 @@ +# [store.w](../../../../../examples/tests/valid/store.w) | test | sim + +## stdout.log +```log +pass ─ store.wsim (no tests) + + +Tests 1 passed (1) +Test Files 1 passed (1) +Duration +``` + From f090014fc787256854969ab475a251ee933d4174 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Tue, 18 Jul 2023 12:30:09 -0400 Subject: [PATCH 10/19] prevent bringing modules with bad statement types --- .../tests/invalid/bring_local_variables.w | 3 ++ examples/tests/invalid/file_with_variables.w | 11 +++++ libs/wingc/src/parser.rs | 46 +++++++++++++++++++ tools/hangar/__snapshots__/invalid.ts.snap | 35 ++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 examples/tests/invalid/bring_local_variables.w create mode 100644 examples/tests/invalid/file_with_variables.w diff --git a/examples/tests/invalid/bring_local_variables.w b/examples/tests/invalid/bring_local_variables.w new file mode 100644 index 00000000000..7182280aa46 --- /dev/null +++ b/examples/tests/invalid/bring_local_variables.w @@ -0,0 +1,3 @@ +bring "./file_with_variables.w" as stuff; + +new stuff.Bar(); diff --git a/examples/tests/invalid/file_with_variables.w b/examples/tests/invalid/file_with_variables.w new file mode 100644 index 00000000000..7c757e16698 --- /dev/null +++ b/examples/tests/invalid/file_with_variables.w @@ -0,0 +1,11 @@ +// used by bring_local_variables.w + +bring cloud; + +let x = 5; +let y = ["hello", "world"]; +let z = new cloud.Bucket(); + +class Bar {} + +throw("dummy error"); diff --git a/libs/wingc/src/parser.rs b/libs/wingc/src/parser.rs index 72a3abc8513..c1413d0bb9e 100644 --- a/libs/wingc/src/parser.rs +++ b/libs/wingc/src/parser.rs @@ -629,6 +629,21 @@ impl<'s> Parser<'s> { } }; + // Check that the module only declares bringable items (classes, interfaces, enums, structs) + // and not variables or functions + let scope = if !is_bringable(&scope) { + report_diagnostic(Diagnostic { + message: format!( + "Cannot bring \"{}\" - modules with statements besides classes, interfaces, enums, and structs cannot be brought", + module_name.name + ), + span: None, + }); + Scope::default() + } else { + scope + }; + // parse error if no alias is provided let module = if let Some(alias) = alias { Ok(StmtKind::Module { @@ -1952,3 +1967,34 @@ impl<'s> Parser<'s> { ))) } } + +fn is_bringable(scope: &Scope) -> bool { + let invalid_stmt = |stmt: &Stmt| match stmt.kind { + // these statements are ok + StmtKind::Bring { .. } => false, + StmtKind::Module { .. } => false, + StmtKind::Class(_) => false, + StmtKind::Interface(_) => false, + StmtKind::Struct { .. } => false, + StmtKind::Enum { .. } => false, + StmtKind::CompilerDebugEnv => false, + // these statements are invalid + StmtKind::SuperConstructor { .. } => true, + StmtKind::Let { .. } => true, + StmtKind::ForLoop { .. } => true, + StmtKind::While { .. } => true, + StmtKind::IfLet { .. } => true, + StmtKind::If { .. } => true, + StmtKind::Break => true, + StmtKind::Continue => true, + StmtKind::Return(_) => true, + StmtKind::Expression(_) => true, + StmtKind::Assignment { .. } => true, + StmtKind::Scope(_) => true, + StmtKind::TryCatch { .. } => true, + }; + + // A module is bringable if it doesn't have any invalid statement kinds + // (rough heuristic for now) + !scope.statements.iter().any(invalid_stmt) +} diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 0ec909fbfb6..23353a34a53 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -133,6 +133,24 @@ exports[`bring_local_self.w 1`] = ` +Tests 1 failed (1) +Test Files 1 failed (1) +Duration " +`; + +exports[`bring_local_variables.w 1`] = ` +"error: Cannot bring \\"\\"./file_with_variables.w\\"\\" - only modules that declare classes, interfaces, enums, and structs be brought + + +error: Unknown symbol \\"Bar\\" + --> ../../../examples/tests/invalid/bring_local_variables.w:3:5 + | +3 | new stuff.Bar(); + | ^^^^^^^^^ Unknown symbol \\"Bar\\" + + + + Tests 1 failed (1) Test Files 1 failed (1) Duration " @@ -603,6 +621,23 @@ error: Failed to resolve extern \\"not-installed\\": Not Found +Tests 1 failed (1) +Test Files 1 failed (1) +Duration " +`; + +exports[`file_with_variables.w 1`] = ` +"ERROR: dummy error + +../../../examples/tests/invalid/target/test/file_with_variables.wsim.460094.tmp/.wing/preflight.js:34 + const y = Object.freeze([\\"hello\\", \\"world\\"]); + const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); +>> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; + } + } + + + Tests 1 failed (1) Test Files 1 failed (1) Duration " From 4d7fa523c64632f7160f0f59b6e740fa15e44ce3 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 16:49:34 +0000 Subject: [PATCH 11/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 23353a34a53..ddc1b1f743f 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -139,7 +139,7 @@ Duration " `; exports[`bring_local_variables.w 1`] = ` -"error: Cannot bring \\"\\"./file_with_variables.w\\"\\" - only modules that declare classes, interfaces, enums, and structs be brought +"error: Cannot bring \\"\\"./file_with_variables.w\\"\\" - modules with statements besides classes, interfaces, enums, and structs cannot be brought error: Unknown symbol \\"Bar\\" @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.460094.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.291799.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 5c484a78f324ab3a7003d7aa18e3e30ecfd30fa5 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 17:14:32 +0000 Subject: [PATCH 12/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index ddc1b1f743f..7747327161e 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.291799.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.593156.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 5dc8a3bbc2ec45e16aebda66738bca9f697a2aa3 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 17:45:24 +0000 Subject: [PATCH 13/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 7747327161e..f34295f238f 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.593156.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.947632.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 14119aed8a0a496b828bdf6b0bf94d1ccc685690 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 18:08:53 +0000 Subject: [PATCH 14/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index f34295f238f..fe528014c21 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.947632.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.856784.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 762b3ffad953ed69434ae9db052c2daef4cebca0 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 18:31:54 +0000 Subject: [PATCH 15/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index fe528014c21..7a0bbec1a6e 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.856784.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.235522.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 7165471c00bfedd26d51f2026e353f845b980471 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 18:55:48 +0000 Subject: [PATCH 16/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 7a0bbec1a6e..12180b1e7b1 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.235522.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.637449.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From c33d2fdc44a0f17ed7d8c689e4bfd7e58f0ff536 Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Tue, 18 Jul 2023 19:14:40 +0000 Subject: [PATCH 17/19] chore: self mutation Signed-off-by: monada-bot[bot] --- tools/hangar/__snapshots__/invalid.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 12180b1e7b1..47fb5d73805 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -629,7 +629,7 @@ Duration " exports[`file_with_variables.w 1`] = ` "ERROR: dummy error -../../../examples/tests/invalid/target/test/file_with_variables.wsim.637449.tmp/.wing/preflight.js:34 +../../../examples/tests/invalid/target/test/file_with_variables.wsim.023247.tmp/.wing/preflight.js:34 const y = Object.freeze([\\"hello\\", \\"world\\"]); const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); >> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; From 0516603487917386c658af7ce653c10878d245e2 Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Thu, 20 Jul 2023 13:29:01 -0400 Subject: [PATCH 18/19] update examples --- examples/tests/invalid/file_with_variables.w | 5 +++-- examples/tests/valid/bring_local.w | 3 +++ examples/tests/valid/subdir/empty.w | 0 examples/tests/valid/subdir/subfile.w | 1 + tools/hangar/__snapshots__/invalid.ts.snap | 14 ++++++-------- 5 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 examples/tests/valid/subdir/empty.w create mode 100644 examples/tests/valid/subdir/subfile.w diff --git a/examples/tests/invalid/file_with_variables.w b/examples/tests/invalid/file_with_variables.w index 7c757e16698..9fbfed746af 100644 --- a/examples/tests/invalid/file_with_variables.w +++ b/examples/tests/invalid/file_with_variables.w @@ -6,6 +6,7 @@ let x = 5; let y = ["hello", "world"]; let z = new cloud.Bucket(); -class Bar {} +class Bar { + x: num; +} -throw("dummy error"); diff --git a/examples/tests/valid/bring_local.w b/examples/tests/valid/bring_local.w index f2a849f88ee..7292edd8595 100644 --- a/examples/tests/valid/bring_local.w +++ b/examples/tests/valid/bring_local.w @@ -1,7 +1,10 @@ bring "./store.w" as file1; +bring "./subdir/subfile.w" as file2; +bring "./subdir/empty.w" as file3; // classes from other files can be used let store = new file1.Store(); +let q = new file2.Q(); test "add data to store" { store.store("foo"); diff --git a/examples/tests/valid/subdir/empty.w b/examples/tests/valid/subdir/empty.w new file mode 100644 index 00000000000..e69de29bb2d diff --git a/examples/tests/valid/subdir/subfile.w b/examples/tests/valid/subdir/subfile.w new file mode 100644 index 00000000000..5b3b1be7512 --- /dev/null +++ b/examples/tests/valid/subdir/subfile.w @@ -0,0 +1 @@ +class Q {} diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index 47fb5d73805..6c53b2a3ee4 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -627,14 +627,12 @@ Duration " `; exports[`file_with_variables.w 1`] = ` -"ERROR: dummy error - -../../../examples/tests/invalid/target/test/file_with_variables.wsim.023247.tmp/.wing/preflight.js:34 - const y = Object.freeze([\\"hello\\", \\"world\\"]); - const z = this.node.root.newAbstract(\\"@winglang/sdk.cloud.Bucket\\",this,\\"cloud.Bucket\\"); ->> {((msg) => {throw new Error(msg)})(\\"dummy error\\")}; - } - } +"error: Preflight field \\"x\\" is not initialized + --> ../../../examples/tests/invalid/file_with_variables.w:10:3 + | +10 | x: num; + | ^ Preflight field \\"x\\" is not initialized + From b6c811014ebc6372151480d21f4cce419993421d Mon Sep 17 00:00:00 2001 From: "monada-bot[bot]" Date: Thu, 20 Jul 2023 17:50:06 +0000 Subject: [PATCH 19/19] chore: self mutation Signed-off-by: monada-bot[bot] --- .../valid/bring_local.w_compile_tf-aws.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md index 96c56a7d3c5..de4d0d9b817 100644 --- a/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md +++ b/tools/hangar/__snapshots__/test_corpus/valid/bring_local.w_compile_tf-aws.md @@ -18,6 +18,18 @@ module.exports = function({ $store }) { ``` +## inflight.Q.js +```js +module.exports = function({ }) { + class Q { + constructor({ }) { + } + } + return Q; +} + +``` + ## inflight.Store.js ```js module.exports = function({ }) { @@ -323,7 +335,37 @@ class $Root extends $stdlib.std.Resource { ; return { Store, Color }; })(); + const file2 = (() => { + class Q extends $stdlib.std.Resource { + constructor(scope, id, ) { + super(scope, id); + this._addInflightOps("$inflight_init"); + } + static _toInflightType(context) { + return $stdlib.core.NodeJsCode.fromInline(` + require("./inflight.Q.js")({ + }) + `); + } + _toInflight() { + return $stdlib.core.NodeJsCode.fromInline(` + (await (async () => { + const QClient = ${Q._toInflightType(this).text}; + const client = new QClient({ + }); + if (client.$inflight_init) { await client.$inflight_init(); } + return client; + })()) + `); + } + } + return { Q }; + })(); + const file3 = (() => { + return { }; + })(); const store = new file1.Store(this,"file1.Store"); + const q = new file2.Q(this,"file2.Q"); this.node.root.new("@winglang/sdk.std.Test",std.Test,this,"test:add data to store",new $Closure1(this,"$Closure1")); const s = { "x": 1,