This commit is contained in:
Andrew Morris
2023-07-25 14:35:41 +10:00
parent 5fd2a046e2
commit 3a8a015f21
6 changed files with 70 additions and 43 deletions

View File

@@ -136,8 +136,13 @@ impl<'a, 'fnc> ExpressionCompiler<'a, 'fnc> {
}
Arrow(arrow) => self.arrow_expression(arrow, target_register),
Class(class_exp) => {
self.todo(class_exp.span(), "Class expression");
CompiledExpression::empty()
// TODO: Handle captures
let p = self
.fnc
.mc
.compile_class(None, class_exp.ident.as_ref(), &class_exp.class);
CompiledExpression::new(Value::Pointer(p), vec![])
}
Yield(yield_expr) => self.yield_expr(yield_expr, target_register),
MetaProp(meta_prop) => {

View File

@@ -275,7 +275,11 @@ impl<'a> FunctionCompiler<'a> {
Some(block) => {
self.handle_block_body(block);
}
None => self.todo(constructor.span(), "constructor without body"),
// This case is constructed artificially when there is no explicit constructor but there
// are member initializer expressions which need to be compiled into a constructor. I'm
// not sure whether SWC ever produces this case.
None => {}
};
}
};
@@ -1113,7 +1117,12 @@ impl<'a> FunctionCompiler<'a> {
use swc_ecma_ast::Decl::*;
match decl {
Class(class) => self.todo(class.span(), "Class declaration"),
Class(class) => {
// TODO: Handle captures
self
.mc
.compile_class(None, Some(&class.ident), &class.class);
}
Fn(fn_decl) => {
let p = match self.lookup_value(&Ident::from_swc_ident(&fn_decl.ident)) {
Some(Value::Pointer(p)) => p,

View File

@@ -7,8 +7,8 @@ use swc_ecma_ast::EsVersion;
use swc_ecma_parser::{Syntax, TsConfig};
use crate::asm::{
Class, Definition, DefinitionContent, FnLine, Function, Instruction, Lazy, Module, Number,
Object, Pointer, Register, Value,
Class, Definition, DefinitionContent, FnLine, Instruction, Lazy, Module, Number, Object, Pointer,
Register, Value,
};
use crate::diagnostic::{Diagnostic, DiagnosticContainer, DiagnosticReporter};
use crate::expression_compiler::{CompiledExpression, ExpressionCompiler};
@@ -769,39 +769,34 @@ impl ModuleCompiler {
let mut member_initializers_assembly = Vec::<FnLine>::new();
member_initializers_assembly.append(&mut mi_fnc.fn_.body);
let mut has_constructor = false;
let mut ctor = swc_ecma_ast::Constructor {
span: class.span,
key: swc_ecma_ast::PropName::Str(swc_ecma_ast::Str {
span: class.span,
value: swc_atoms::JsWord::from(""),
raw: None,
}),
params: vec![],
body: None,
accessibility: None,
is_optional: false,
};
for class_member in &class.body {
if let swc_ecma_ast::ClassMember::Constructor(ctor) = class_member {
has_constructor = true;
let ctor_defn_name = self.allocate_defn(&format!("{}_constructor", defn_name.name));
self.compile_fn(
ctor_defn_name.clone(),
Functionish::Constructor(
member_initializers_assembly.clone(),
class.span,
ctor.clone(),
),
);
constructor = Value::Pointer(ctor_defn_name);
if let swc_ecma_ast::ClassMember::Constructor(concrete_ctor) = class_member {
ctor = concrete_ctor.clone();
}
}
if !member_initializers_assembly.is_empty() && !has_constructor {
if !member_initializers_assembly.is_empty() || ctor.body.is_some() {
let ctor_defn_name = self.allocate_defn(&format!("{}_constructor", defn_name.name));
constructor = Value::Pointer(ctor_defn_name.clone());
self.module.definitions.push(Definition {
pointer: ctor_defn_name,
content: DefinitionContent::Function(Function {
is_generator: false,
parameters: vec![],
body: member_initializers_assembly,
}),
});
self.compile_fn(
ctor_defn_name.clone(),
Functionish::Constructor(member_initializers_assembly.clone(), class.span, ctor),
);
constructor = Value::Pointer(ctor_defn_name);
}
for class_member in &class.body {
@@ -855,15 +850,19 @@ impl ModuleCompiler {
}
}
let class_value = Value::Class(Box::new(Class {
constructor,
prototype: Value::Object(Box::new(prototype)),
static_: Value::Object(Box::new(static_)),
}));
self.module.definitions.push(Definition {
pointer: defn_name.clone(),
content: DefinitionContent::Value(Value::Class(Box::new(Class {
constructor,
prototype: Value::Object(Box::new(prototype)),
static_: Value::Object(Box::new(static_)),
}))),
content: DefinitionContent::Value(class_value.clone()),
});
self.constants_map.insert(defn_name.clone(), class_value);
defn_name
}

View File

@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
use crate::asm::{Pointer, Register};
#[derive(Default, Clone)]
#[derive(Default, Clone, Debug)]
pub struct NameAllocator {
used_names: BTreeSet<String>,
released_names: Vec<String>,
@@ -102,7 +102,7 @@ pub fn ident_from_str(str: &str) -> String {
}
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct PointerAllocator {
alloc: NameAllocator,
}
@@ -115,7 +115,7 @@ impl PointerAllocator {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct RegAllocator {
pub alloc: NameAllocator,
}

View File

@@ -61,7 +61,14 @@ pub fn shake_tree(module: &mut Module) {
for pointer in &ordered_pointers {
if required_pointers.contains(pointer) {
let defn = new_definitions_map.get_mut(pointer).unwrap();
let defn = match new_definitions_map.get_mut(pointer) {
Some(defn) => defn,
None => {
// This can happen due to errors in the input program. Ideally we should ensure there are
// error diagnostics when we hit this case (TODO).
continue;
}
};
// First include pointers that are allowed to be circular
match &defn.content {
@@ -75,7 +82,14 @@ pub fn shake_tree(module: &mut Module) {
for pointer in ordered_pointers {
if required_pointers.contains(&pointer) {
let defn = new_definitions_map.get_mut(&pointer).unwrap();
let defn = match new_definitions_map.get_mut(&pointer) {
Some(defn) => defn,
None => {
// This can happen due to errors in the input program. Ideally we should ensure there are
// error diagnostics when we hit this case (TODO).
continue;
}
};
if defn.pointer.name.is_empty() {
// "" isn't a valid pointer name - this happens when `take` has already been used on the

View File

@@ -62,7 +62,7 @@ pub struct Ref {
pub span: swc_common::Span,
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct ScopeAnalysis {
pub names: HashMap<NameId, Name>,
pub owners: HashMap<OwnerId, HashSet<swc_common::Span>>,