Prototype scope_analysis

This commit is contained in:
Andrew Morris
2023-02-19 20:58:41 +11:00
parent 0264b81340
commit 1925f6c40c
7 changed files with 1179 additions and 138 deletions

View File

@@ -7,7 +7,7 @@
"deno.enable": true,
"deno.lint": true,
"deno.unstable": true,
"editor.formatOnSave": false,
"editor.formatOnSave": true,
"editor.defaultFormatter": "denoland.vscode-deno",
"rust-analyzer.inlayHints.bindingModeHints.enable": false,
"rust-analyzer.inlayHints.chainingHints.enable": false,
@@ -16,5 +16,8 @@
"rust-analyzer.inlayHints.lifetimeElisionHints.enable": "never",
"rust-analyzer.inlayHints.parameterHints.enable": false,
"rust-analyzer.inlayHints.reborrowHints.enable": "never",
"rust-analyzer.inlayHints.typeHints.enable": false
"rust-analyzer.inlayHints.typeHints.enable": false,
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}

1
rustfmt.toml Normal file
View File

@@ -0,0 +1 @@
tab_spaces = 2

View File

@@ -1,23 +1,24 @@
use std::process::exit;
use std::{path::Path, sync::Arc};
use std::cell::RefCell;
use std::fs::File;
use std::io::prelude::*;
use std::process::exit;
use std::rc::Rc;
use std::cell::RefCell;
use std::{path::Path, sync::Arc};
use swc_common::errors::{DiagnosticBuilder, Emitter};
use swc_common::FileName;
use swc_common::errors::{Emitter, DiagnosticBuilder};
use swc_ecma_ast::{EsVersion};
use swc_common::{
errors::{ColorConfig, Handler},
SourceMap,
errors::{ColorConfig, Handler},
SourceMap,
};
use swc_ecma_parser::{TsConfig, Syntax};
use swc_ecma_ast::EsVersion;
use swc_ecma_parser::{Syntax, TsConfig};
use super::scope::{Scope, MappedName, init_std_scope, ScopeTrait};
use super::name_allocator::NameAllocator;
use super::expression_compiler::string_literal;
use super::function_compiler::{FunctionCompiler, Functionish};
use super::expression_compiler::{string_literal};
use super::name_allocator::NameAllocator;
use super::scope::{init_std_scope, MappedName, Scope, ScopeTrait};
use super::scope_analysis::ScopeAnalysis;
pub fn command(args: &Vec<String>) {
if args.len() != 3 {
@@ -32,7 +33,9 @@ pub fn command(args: &Vec<String>) {
let mut file = File::create("out.vsm").expect("Couldn't create out.vsm");
for line in assembly {
file.write_all(line.as_bytes()).expect("Failed to write line");
file
.write_all(line.as_bytes())
.expect("Failed to write line");
file.write_all(b"\n").expect("Failed to write line");
}
}
@@ -57,32 +60,23 @@ impl Emitter for VsEmitter {
pub fn parse(file_path: &String) -> swc_ecma_ast::Program {
let source_map = Arc::<SourceMap>::default();
Handler::with_emitter(
true,
false,
Box::new(VsEmitter{}),
);
Handler::with_emitter(true, false, Box::new(VsEmitter {}));
let handler = Handler::with_tty_emitter(
ColorConfig::Auto,
true,
false,
Some(source_map.clone()),
);
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(source_map.clone()));
let swc_compiler = swc::Compiler::new(source_map.clone());
let file = source_map
.load_file(Path::new(&file_path))
.expect("failed to load file");
.load_file(Path::new(&file_path))
.expect("failed to load file");
let result = swc_compiler.parse_js(
file,
&handler,
EsVersion::Es2022,
Syntax::Typescript(TsConfig::default()),
swc::config::IsModule::Bool(true),
None,
file,
&handler,
EsVersion::Es2022,
Syntax::Typescript(TsConfig::default()),
swc::config::IsModule::Bool(true),
None,
);
return result.expect("Parse failed");
@@ -113,24 +107,19 @@ pub fn compile(program: &swc_ecma_ast::Program) -> Vec<String> {
pub fn full_compile_raw(source: &str) -> String {
let source_map = Arc::<SourceMap>::default();
let handler = Handler::with_emitter(
true,
false,
Box::new(VsEmitter{}),
);
let handler = Handler::with_emitter(true, false, Box::new(VsEmitter {}));
let swc_compiler = swc::Compiler::new(source_map.clone());
let file = source_map
.new_source_file(FileName::Anon, source.into());
let file = source_map.new_source_file(FileName::Anon, source.into());
let result = swc_compiler.parse_js(
file,
&handler,
EsVersion::Es2022,
Syntax::Typescript(TsConfig::default()),
swc::config::IsModule::Bool(true),
None,
file,
&handler,
EsVersion::Es2022,
Syntax::Typescript(TsConfig::default()),
swc::config::IsModule::Bool(true),
None,
);
let program = result.expect("Parse failed");
@@ -157,12 +146,13 @@ impl Compiler {
}
fn compile_module(&mut self, module: &swc_ecma_ast::Module) {
let scope_analysis = ScopeAnalysis::run(module);
let scope = init_std_scope();
use swc_ecma_ast::ModuleItem;
use swc_ecma_ast::ModuleDecl;
use swc_ecma_ast::Stmt;
use swc_ecma_ast::Decl;
use swc_ecma_ast::ModuleDecl;
use swc_ecma_ast::ModuleItem;
use swc_ecma_ast::Stmt;
let mut default_export_name = None;
@@ -171,39 +161,52 @@ impl Compiler {
match module_item {
ModuleItem::ModuleDecl(module_decl) => match module_decl {
ModuleDecl::Import(_) => std::panic!("Not implemented: Import module declaration"),
ModuleDecl::ExportDecl(_) => std::panic!("Not implemented: ExportDecl module declaration"),
ModuleDecl::ExportNamed(_) => std::panic!("Not implemented: ExportNamed module declaration"),
ModuleDecl::ExportDecl(_) => {
std::panic!("Not implemented: ExportDecl module declaration")
}
ModuleDecl::ExportNamed(_) => {
std::panic!("Not implemented: ExportNamed module declaration")
}
ModuleDecl::ExportDefaultDecl(edd) => {
match &edd.decl {
swc_ecma_ast::DefaultDecl::Fn(fn_) => {
match &fn_.ident {
Some(id) => {
let allocated_name = self.definition_allocator.borrow_mut().allocate(
&id.sym.to_string()
);
let allocated_name = self
.definition_allocator
.borrow_mut()
.allocate(&id.sym.to_string());
default_export_name = Some(allocated_name.clone());
scope.set(
id.sym.to_string(),
MappedName::Definition(allocated_name),
);
},
scope.set(id.sym.to_string(), MappedName::Definition(allocated_name));
}
None => {
default_export_name = Some(
self.definition_allocator.borrow_mut().allocate_numbered(&"_anon".to_string())
self
.definition_allocator
.borrow_mut()
.allocate_numbered(&"_anon".to_string()),
);
},
}
};
},
}
_ => std::panic!("Not implemented: Non-function default export"),
};
},
ModuleDecl::ExportDefaultExpr(_) => std::panic!("Not implemented: ExportDefaultExpr module declaration"),
}
ModuleDecl::ExportDefaultExpr(_) => {
std::panic!("Not implemented: ExportDefaultExpr module declaration")
}
ModuleDecl::ExportAll(_) => std::panic!("Not implemented: ExportAll module declaration"),
ModuleDecl::TsImportEquals(_) => std::panic!("Not implemented: TsImportEquals module declaration"),
ModuleDecl::TsExportAssignment(_) => std::panic!("Not implemented: TsExportAssignment module declaration"),
ModuleDecl::TsNamespaceExport(_) => std::panic!("Not implemented: TsNamespaceExport module declaration"),
ModuleDecl::TsImportEquals(_) => {
std::panic!("Not implemented: TsImportEquals module declaration")
}
ModuleDecl::TsExportAssignment(_) => {
std::panic!("Not implemented: TsExportAssignment module declaration")
}
ModuleDecl::TsNamespaceExport(_) => {
std::panic!("Not implemented: TsNamespaceExport module declaration")
}
},
ModuleItem::Stmt(stmt) => match stmt {
Stmt::Block(_) => std::panic!("Not implemented: module level Block statement"),
@@ -229,29 +232,37 @@ impl Compiler {
scope.set(
class.ident.sym.to_string(),
MappedName::Definition(
self.definition_allocator.borrow_mut().allocate(&class.ident.sym.to_string()),
self
.definition_allocator
.borrow_mut()
.allocate(&class.ident.sym.to_string()),
),
);
},
}
Decl::Fn(fn_) => {
scope.set(
fn_.ident.sym.to_string(),
MappedName::Definition(
self.definition_allocator.borrow_mut().allocate(&fn_.ident.sym.to_string()),
self
.definition_allocator
.borrow_mut()
.allocate(&fn_.ident.sym.to_string()),
),
);
},
}
Decl::Var(var_decl) => {
if !var_decl.declare {
std::panic!("Not implemented: non-declare module level var declaration");
}
},
Decl::TsInterface(_) => {},
Decl::TsTypeAlias(_) => {},
}
Decl::TsInterface(_) => {}
Decl::TsTypeAlias(_) => {}
Decl::TsEnum(_) => std::panic!("Not implemented: module level TsEnum declaration"),
Decl::TsModule(_) => std::panic!("Not implemented: module level TsModule declaration"),
Decl::TsModule(_) => {
std::panic!("Not implemented: module level TsModule declaration")
}
};
},
}
Stmt::Expr(_) => std::panic!("Not implemented: module level Expr statement"),
},
};
@@ -260,35 +271,30 @@ impl Compiler {
// First compile default
for module_item in &module.body {
match module_item {
ModuleItem::ModuleDecl(
ModuleDecl::ExportDefaultDecl(edd)
) => self.compile_export_default_decl(
edd,
// FIXME: clone() shouldn't be necessary here (we want to move)
default_export_name.clone().expect("Default export name should have been set"),
self.definition_allocator.clone(),
&scope,
),
_ => {},
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(edd)) => self
.compile_export_default_decl(
edd,
// FIXME: clone() shouldn't be necessary here (we want to move)
default_export_name
.clone()
.expect("Default export name should have been set"),
self.definition_allocator.clone(),
&scope,
),
_ => {}
}
}
// Then compile others
for module_item in &module.body {
match module_item {
ModuleItem::ModuleDecl(
ModuleDecl::ExportDefaultDecl(_)
) => {},
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(_)) => {}
_ => self.compile_module_item(module_item, &scope),
}
}
}
fn compile_module_item(
&mut self,
module_item: &swc_ecma_ast::ModuleItem,
scope: &Scope,
) {
fn compile_module_item(&mut self, module_item: &swc_ecma_ast::ModuleItem, scope: &Scope) {
use swc_ecma_ast::ModuleItem::*;
match module_item {
@@ -297,11 +303,7 @@ impl Compiler {
}
}
fn compile_module_decl(
&mut self,
module_decl: &swc_ecma_ast::ModuleDecl,
_scope: &Scope,
) {
fn compile_module_decl(&mut self, module_decl: &swc_ecma_ast::ModuleDecl, _scope: &Scope) {
use swc_ecma_ast::ModuleDecl::*;
match module_decl {
@@ -310,11 +312,7 @@ impl Compiler {
}
}
fn compile_module_statement(
&mut self,
stmt: &swc_ecma_ast::Stmt,
scope: &Scope,
) {
fn compile_module_statement(&mut self, stmt: &swc_ecma_ast::Stmt, scope: &Scope) {
use swc_ecma_ast::Stmt::*;
match stmt {
@@ -349,20 +347,22 @@ impl Compiler {
let fn_name = fn_.ident.sym.to_string();
self.compile_fn(
scope.get_defn(&fn_name).expect("Definition should have been in scope"),
scope
.get_defn(&fn_name)
.expect("Definition should have been in scope"),
Some(fn_.ident.sym.to_string()),
Functionish::Fn(fn_.function.clone()),
self.definition_allocator.clone(),
scope,
)
},
}
Var(var_decl) => {
if !var_decl.declare {
std::panic!("Not implemented: non-declare module level var declaration");
}
},
TsInterface(_) => {},
TsTypeAlias(_) => {},
}
TsInterface(_) => {}
TsTypeAlias(_) => {}
TsEnum(_) => std::panic!("Not implemented: TsEnum declaration"),
TsModule(_) => std::panic!("Not implemented: TsModule declaration"),
};
@@ -379,7 +379,9 @@ impl Compiler {
match &edd.decl {
Fn(fn_) => self.compile_fn(
scope.get_defn(&fn_name).expect("Definition should have been in scope"),
scope
.get_defn(&fn_name)
.expect("Definition should have been in scope"),
Some(fn_name),
Functionish::Fn(fn_.function.clone()),
definition_allocator,
@@ -397,15 +399,13 @@ impl Compiler {
definition_allocator: Rc<RefCell<NameAllocator>>,
parent_scope: &Scope,
) {
self.definitions.push(
FunctionCompiler::compile(
defn_name,
fn_name,
functionish,
definition_allocator,
parent_scope,
),
);
self.definitions.push(FunctionCompiler::compile(
defn_name,
fn_name,
functionish,
definition_allocator,
parent_scope,
));
}
fn compile_class_decl(
@@ -420,7 +420,7 @@ impl Compiler {
let defn_name = match parent_scope.get(&class_name) {
Some(MappedName::Definition(d)) => d,
_ => std::panic!("Definition name should have been in scope")
_ => std::panic!("Definition name should have been in scope"),
};
let mut constructor_defn_name: Option<String> = None;
@@ -428,9 +428,9 @@ impl Compiler {
for class_member in &class_decl.class.body {
match class_member {
swc_ecma_ast::ClassMember::Constructor(constructor) => {
let ctor_defn_name = definition_allocator.borrow_mut().allocate(
&format!("{}_constructor", class_name),
);
let ctor_defn_name = definition_allocator
.borrow_mut()
.allocate(&format!("{}_constructor", class_name));
self.compile_fn(
ctor_defn_name.clone(),
@@ -441,8 +441,8 @@ impl Compiler {
);
constructor_defn_name = Some(ctor_defn_name);
},
_ => {},
}
_ => {}
}
}
@@ -459,16 +459,16 @@ impl Compiler {
use swc_ecma_ast::ClassMember::*;
match class_member {
Constructor(_) => {},
Constructor(_) => {}
Method(method) => {
let name = match &method.key {
swc_ecma_ast::PropName::Ident(ident) => ident.sym.to_string(),
_ => std::panic!("Not implemented: Non-identifier method name"),
};
let method_defn_name = definition_allocator.borrow_mut().allocate(
&format!("{}_{}", defn_name, name),
);
let method_defn_name = definition_allocator
.borrow_mut()
.allocate(&format!("{}_{}", defn_name, name));
self.compile_fn(
method_defn_name.clone(),
@@ -483,20 +483,20 @@ impl Compiler {
string_literal(&name),
method_defn_name,
));
},
}
PrivateMethod(_) => std::panic!("Not implemented: PrivateMethod"),
ClassProp(prop) => {
if prop.value.is_some() {
std::panic!("Not implemented: class property initializers");
}
},
}
PrivateProp(prop) => {
if prop.value.is_some() {
std::panic!("Not implemented: class property initializers");
}
},
TsIndexSignature(_) => {},
Empty(_) => {},
}
TsIndexSignature(_) => {}
Empty(_) => {}
StaticBlock(_) => std::panic!("Not implemented: StaticBlock"),
}
}

View File

@@ -5,6 +5,7 @@ mod compile;
mod scope;
mod name_allocator;
mod expression_compiler;
mod scope_analysis;
mod function_compiler;
mod capture_finder;

View File

@@ -1,6 +1,7 @@
pub mod virtual_machine;
pub mod compile;
pub mod run;
pub mod scope_analysis;
mod scope;
mod name_allocator;
mod function_compiler;

View File

@@ -1,10 +1,10 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use super::function_compiler::QueuedFunction;
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Builtin {
Math,
Debug,
@@ -51,7 +51,7 @@ impl ScopeTrait for Scope {
fn get_defn(&self, name: &String) -> Option<String> {
let get_result = self.get(name);
return match get_result {
Some(MappedName::Definition(d)) => Some(d.clone()),
_ => None,
@@ -88,5 +88,6 @@ pub fn init_std_scope() -> Scope {
("Debug".to_string(), MappedName::Builtin(Builtin::Debug)),
]),
parent: None,
})).nest();
}))
.nest();
}

1034
src/vstc/scope_analysis.rs Normal file

File diff suppressed because it is too large Load Diff