mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-14 16:08:02 -05:00
Implement enums
This commit is contained in:
73
valuescript_compiler/src/compile_enum_value.rs
Normal file
73
valuescript_compiler/src/compile_enum_value.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use swc_common::Spanned;
|
||||
|
||||
use crate::{
|
||||
asm::{Number, Object, Value},
|
||||
static_eval_expr::static_eval_expr,
|
||||
Diagnostic, DiagnosticLevel,
|
||||
};
|
||||
|
||||
pub fn compile_enum_value(
|
||||
ts_enum: &swc_ecma_ast::TsEnumDecl,
|
||||
diagnostics: &mut Vec<Diagnostic>,
|
||||
) -> Value {
|
||||
let mut properties = Vec::<(Value, Value)>::new();
|
||||
let mut next_default_id: Option<f64> = Some(0.0);
|
||||
|
||||
for member in &ts_enum.members {
|
||||
let key = match &member.id {
|
||||
swc_ecma_ast::TsEnumMemberId::Ident(ident) => ident.sym.to_string(),
|
||||
swc_ecma_ast::TsEnumMemberId::Str(str) => str.value.to_string(),
|
||||
};
|
||||
|
||||
let init_value = match &member.init {
|
||||
Some(init) => match static_eval_expr(&init) {
|
||||
Some(init_value) => match init_value {
|
||||
Value::Number(Number(n)) => {
|
||||
next_default_id = Some(n + 1.0);
|
||||
Some(Value::Number(Number(n)))
|
||||
}
|
||||
Value::String(_) => Some(init_value),
|
||||
_ => None,
|
||||
},
|
||||
None => {
|
||||
diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: "TODO: Static eval failed".to_string(),
|
||||
span: init.span(),
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let value = match init_value {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
let id = match next_default_id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::Error,
|
||||
message: format!("Missing required initializer"),
|
||||
span: member.span,
|
||||
});
|
||||
|
||||
0.0
|
||||
}
|
||||
};
|
||||
|
||||
let value = Value::Number(Number(id));
|
||||
next_default_id = Some(id + 1.0);
|
||||
|
||||
value
|
||||
}
|
||||
};
|
||||
|
||||
properties.push((Value::String(key.clone()), value.clone()));
|
||||
properties.push((value, Value::String(key)));
|
||||
}
|
||||
|
||||
Value::Object(Box::new(Object { properties }))
|
||||
}
|
||||
@@ -10,6 +10,7 @@ use crate::asm::{
|
||||
Array, Builtin, Definition, DefinitionContent, FnLine, Function, Instruction, Label, Pointer,
|
||||
Register, Value,
|
||||
};
|
||||
use crate::compile_enum_value::compile_enum_value;
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::expression_compiler::CompiledExpression;
|
||||
use crate::expression_compiler::ExpressionCompiler;
|
||||
@@ -1279,7 +1280,30 @@ impl FunctionCompiler {
|
||||
Var(var_decl) => self.var_declaration(var_decl),
|
||||
TsInterface(interface_decl) => self.todo(interface_decl.span, "TsInterface declaration"),
|
||||
TsTypeAlias(_) => {}
|
||||
TsEnum(ts_enum) => self.todo(ts_enum.span, "TsEnum declaration"),
|
||||
TsEnum(ts_enum) => {
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &ts_enum.id)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: format!("Pointer for {} should have been in scope", ts_enum.id.sym),
|
||||
span: ts_enum.id.span,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let enum_value = compile_enum_value(ts_enum, &mut self.diagnostics);
|
||||
|
||||
self.definitions.push(Definition {
|
||||
pointer,
|
||||
content: DefinitionContent::Value(enum_value),
|
||||
});
|
||||
}
|
||||
TsModule(ts_module) => self.todo(ts_module.span, "TsModule declaration"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ pub mod asm;
|
||||
mod assembler;
|
||||
pub mod assembly_parser;
|
||||
mod compile;
|
||||
mod compile_enum_value;
|
||||
mod constants;
|
||||
mod diagnostic;
|
||||
mod expression_compiler;
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::asm::{
|
||||
Class, Definition, DefinitionContent, FnLine, Function, Instruction, Lazy, Module, Object,
|
||||
Pointer, Register, Value,
|
||||
};
|
||||
use crate::compile_enum_value::compile_enum_value;
|
||||
use crate::diagnostic::{Diagnostic, DiagnosticLevel};
|
||||
use crate::expression_compiler::{CompiledExpression, ExpressionCompiler};
|
||||
use crate::function_compiler::{FunctionCompiler, Functionish};
|
||||
@@ -199,7 +200,27 @@ impl ModuleCompiler {
|
||||
ExportDecl(ed) => self.compile_export_decl(ed),
|
||||
ExportNamed(en) => self.compile_named_export(en),
|
||||
ExportDefaultDecl(edd) => self.compile_export_default_decl(edd),
|
||||
ExportDefaultExpr(_) => self.todo(module_decl.span(), "ExportDefaultExpr declaration"),
|
||||
ExportDefaultExpr(ede) => {
|
||||
let value = match &*ede.expr {
|
||||
swc_ecma_ast::Expr::Ident(ident) => match self.scope_analysis.lookup(ident) {
|
||||
Some(name) => Some(name.value.clone()),
|
||||
None => None,
|
||||
},
|
||||
expr => static_eval_expr(expr),
|
||||
};
|
||||
|
||||
match value {
|
||||
Some(value) => {
|
||||
self.module.export_default = value;
|
||||
}
|
||||
None => {
|
||||
self.todo(
|
||||
module_decl.span(),
|
||||
"Failed to evaluate export default expression",
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
ExportAll(_) => self.todo(module_decl.span(), "ExportAll declaration"),
|
||||
TsImportEquals(_) => self.not_supported(module_decl.span(), "TsImportEquals declaration"),
|
||||
TsExportAssignment(_) => {
|
||||
@@ -326,7 +347,7 @@ impl ModuleCompiler {
|
||||
}
|
||||
TsInterface(_) => {}
|
||||
TsTypeAlias(_) => {}
|
||||
TsEnum(ts_enum) => self.todo(ts_enum.span, "TsEnum declaration"),
|
||||
TsEnum(ts_enum) => self.compile_enum_decl(false, ts_enum),
|
||||
TsModule(ts_module) => self.todo(ts_module.span, "TsModule declaration"),
|
||||
};
|
||||
}
|
||||
@@ -366,6 +387,38 @@ impl ModuleCompiler {
|
||||
self.module.definitions.append(&mut fn_defns);
|
||||
}
|
||||
|
||||
fn compile_enum_decl(&mut self, export: bool, ts_enum: &swc_ecma_ast::TsEnumDecl) {
|
||||
let pointer = match self
|
||||
.scope_analysis
|
||||
.lookup_value(&OwnerId::Module, &ts_enum.id)
|
||||
{
|
||||
Some(Value::Pointer(p)) => p,
|
||||
_ => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: format!("Pointer for {} should have been in scope", ts_enum.id.sym),
|
||||
span: ts_enum.id.span,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if export {
|
||||
self.module.export_star.properties.push((
|
||||
Value::String(ts_enum.id.sym.to_string()),
|
||||
Value::Pointer(pointer.clone()),
|
||||
));
|
||||
}
|
||||
|
||||
let enum_value = compile_enum_value(ts_enum, &mut self.diagnostics);
|
||||
|
||||
self.module.definitions.push(Definition {
|
||||
pointer,
|
||||
content: DefinitionContent::Value(enum_value),
|
||||
});
|
||||
}
|
||||
|
||||
fn compile_export_default_decl(&mut self, edd: &swc_ecma_ast::ExportDefaultDecl) {
|
||||
use swc_ecma_ast::DefaultDecl;
|
||||
|
||||
@@ -432,7 +485,7 @@ impl ModuleCompiler {
|
||||
}
|
||||
Decl::TsInterface(_) => {}
|
||||
Decl::TsTypeAlias(_) => {}
|
||||
Decl::TsEnum(ts_enum) => self.todo(ts_enum.span, "TsEnum declaration in export"),
|
||||
Decl::TsEnum(ts_enum) => self.compile_enum_decl(true, ts_enum),
|
||||
Decl::TsModule(ts_module) => self.todo(ts_module.span, "TsModule declaration in export"),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ pub enum NameType {
|
||||
Param,
|
||||
Function,
|
||||
Class,
|
||||
Enum,
|
||||
Import,
|
||||
Builtin,
|
||||
Constant,
|
||||
@@ -187,6 +188,7 @@ impl ScopeAnalysis {
|
||||
effectively_const: match type_ {
|
||||
NameType::Var | NameType::Let | NameType::Param => false,
|
||||
NameType::Const
|
||||
| NameType::Enum
|
||||
| NameType::Function
|
||||
| NameType::Class
|
||||
| NameType::Import
|
||||
@@ -434,12 +436,16 @@ impl ScopeAnalysis {
|
||||
}
|
||||
Decl::TsInterface(_) => {}
|
||||
Decl::TsTypeAlias(_) => {}
|
||||
Decl::TsEnum(ts_enum) => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
level: DiagnosticLevel::InternalError,
|
||||
message: "TODO: Implement TsEnum declarations".to_string(),
|
||||
span: ts_enum.span,
|
||||
});
|
||||
Decl::TsEnum(ts_enum) => 'b: {
|
||||
if ts_enum.declare {
|
||||
break 'b;
|
||||
}
|
||||
|
||||
for member in &ts_enum.members {
|
||||
if let Some(init) = &member.init {
|
||||
self.expr(scope, &init);
|
||||
}
|
||||
}
|
||||
}
|
||||
Decl::TsModule(ts_module) => {
|
||||
self.diagnostics.push(Diagnostic {
|
||||
@@ -510,8 +516,8 @@ impl ScopeAnalysis {
|
||||
}
|
||||
swc_ecma_ast::Decl::TsInterface(_) => {}
|
||||
swc_ecma_ast::Decl::TsTypeAlias(_) => {}
|
||||
swc_ecma_ast::Decl::TsEnum(_) => {
|
||||
// Diagnostic emitted after hoist processing
|
||||
swc_ecma_ast::Decl::TsEnum(ts_enum) => {
|
||||
self.insert_pointer_name(scope, NameType::Enum, &ts_enum.id);
|
||||
}
|
||||
swc_ecma_ast::Decl::TsModule(_) => {
|
||||
// Diagnostic emitted after hoist processing
|
||||
@@ -571,6 +577,9 @@ impl ScopeAnalysis {
|
||||
}
|
||||
}
|
||||
}
|
||||
Decl::TsEnum(ts_enum) => {
|
||||
self.insert_pointer_name(scope, NameType::Enum, &ts_enum.id);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Stmt::Block(block_stmt) => {
|
||||
@@ -687,9 +696,7 @@ impl ScopeAnalysis {
|
||||
}
|
||||
Decl::TsInterface(_) => {}
|
||||
Decl::TsTypeAlias(_) => {}
|
||||
Decl::TsEnum(_) => {
|
||||
// Diagnostic emitted after hoist processing
|
||||
}
|
||||
Decl::TsEnum(_) => {}
|
||||
Decl::TsModule(_) => {
|
||||
// Diagnostic emitted after hoist processing
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user