diff --git a/crates/samlang-ast/src/hir.rs b/crates/samlang-ast/src/hir.rs index d18a1668..f5a1dea5 100644 --- a/crates/samlang-ast/src/hir.rs +++ b/crates/samlang-ast/src/hir.rs @@ -317,7 +317,7 @@ impl Expression { pub fn debug_print(&self, heap: &samlang_heap::Heap) -> String { match self { Expression::IntLiteral(i) => i.to_string(), - Expression::StringName(n) => n.as_str(heap).to_string(), + Expression::StringName(n) => format!("\"{}\"", n.as_str(heap)), Expression::Variable(v) => v.debug_print(heap), } } @@ -661,14 +661,11 @@ impl Function { } #[derive(Debug, Clone, Copy)] -pub struct GlobalVariable { - pub name: PStr, - pub content: PStr, -} +pub struct GlobalString(pub PStr); #[derive(Debug)] pub struct Sources { - pub global_variables: Vec, + pub global_variables: Vec, pub closure_types: Vec, pub type_definitions: Vec, pub main_function_names: Vec, @@ -678,8 +675,8 @@ pub struct Sources { impl Sources { pub fn debug_print(&self, heap: &samlang_heap::Heap) -> String { let mut lines = vec![]; - for v in &self.global_variables { - lines.push(format!("const {} = '{}';\n", v.name.as_str(heap), v.content.as_str(heap))); + for (i, v) in self.global_variables.iter().enumerate() { + lines.push(format!("const GLOBAL_STRING_{} = '{}';\n", i, v.0.as_str(heap))); } for d in &self.closure_types { lines.push(d.pretty_print(heap)); diff --git a/crates/samlang-ast/src/hir_tests.rs b/crates/samlang-ast/src/hir_tests.rs index feba5740..7b4802bd 100644 --- a/crates/samlang-ast/src/hir_tests.rs +++ b/crates/samlang-ast/src/hir_tests.rs @@ -163,7 +163,7 @@ mod tests { Expression::var_name(PStr::LOWER_A, Type::new_id(PStr::UPPER_A, vec![(INT_TYPE)])) .debug_print(heap) ); - assert_eq!("a", Expression::StringName(PStr::LOWER_A).clone().debug_print(heap)); + assert_eq!("\"a\"", Expression::StringName(PStr::LOWER_A).clone().debug_print(heap)); } #[test] @@ -414,8 +414,8 @@ mod tests { format!("{:?}", stmt.clone()); let expected = r#"let bar: int; if 0 { - let baz: DUMMY_FooBar = [meggo]; - let baz: DUMMY_Enum = [0, meggo]; + let baz: DUMMY_FooBar = ["meggo"]; + let baz: DUMMY_Enum = [0, "meggo"]; let closure: DUMMY_CCC = Closure { fun: (A$foo: (int) -> int), context: 0 }; let dd = 0 < 0; let dd = 0 <= 0; @@ -461,11 +461,7 @@ if 0 { let heap = &mut Heap::new(); let sources1 = Sources { - global_variables: vec![GlobalVariable { - name: heap.alloc_str_for_test("dev_meggo"), - content: heap.alloc_str_for_test("vibez"), - } - .clone()], + global_variables: vec![GlobalString(heap.alloc_str_for_test("dev_meggo_vibez")).clone()], closure_types: vec![ClosureTypeDefinition { name: TypeName { module_reference: None, type_name: PStr::UPPER_C }, type_parameters: vec![], @@ -504,7 +500,7 @@ if 0 { .clone()], }; format!("{sources1:?}"); - let expected1 = r#"const dev_meggo = 'vibez'; + let expected1 = r#"const GLOBAL_STRING_0 = 'dev_meggo_vibez'; closure type C = () -> int object type Foo = [int, int] diff --git a/crates/samlang-ast/src/lir.rs b/crates/samlang-ast/src/lir.rs index 3b4ce1b2..4a848a24 100644 --- a/crates/samlang-ast/src/lir.rs +++ b/crates/samlang-ast/src/lir.rs @@ -1,7 +1,9 @@ +use std::collections::HashMap; + use crate::hir; use super::{ - hir::{BinaryOperator, GlobalVariable, UnaryOperator}, + hir::{BinaryOperator, GlobalString, UnaryOperator}, mir::{FunctionName, SymbolTable, TypeNameId}, }; use enum_as_inner::EnumAsInner; @@ -116,11 +118,21 @@ impl Expression { } } - fn pretty_print(&self, collector: &mut String, heap: &Heap, table: &SymbolTable) { + fn pretty_print( + &self, + collector: &mut String, + heap: &Heap, + symbol_table: &SymbolTable, + str_table: &HashMap, + ) { match self { Expression::IntLiteral(i) => collector.push_str(&i.to_string()), - Expression::StringName(n) | Expression::Variable(n, _) => collector.push_str(n.as_str(heap)), - Expression::FnName(n, _) => n.write_encoded(collector, heap, table), + Expression::Variable(n, _) => collector.push_str(n.as_str(heap)), + Expression::StringName(n) => { + collector.push_str("GLOBAL_STRING_"); + collector.push_str(&str_table.get(n).unwrap().to_string()); + } + Expression::FnName(n, _) => n.write_encoded(collector, heap, symbol_table), } } } @@ -220,15 +232,16 @@ impl Statement { fn print_expression_list( collector: &mut String, heap: &Heap, - table: &SymbolTable, + symbol_table: &SymbolTable, + str_table: &HashMap, expressions: &[Expression], ) { let mut iter = expressions.iter(); if let Some(e) = iter.next() { - e.pretty_print(collector, heap, table); + e.pretty_print(collector, heap, symbol_table, str_table); for e in iter { collector.push_str(", "); - e.pretty_print(collector, heap, table); + e.pretty_print(collector, heap, symbol_table, str_table); } } } @@ -236,7 +249,8 @@ impl Statement { fn pretty_print_internal( &self, heap: &Heap, - table: &SymbolTable, + symbol_table: &SymbolTable, + str_table: &HashMap, level: usize, break_collector: &Option<(PStr, Type)>, collector: &mut String, @@ -247,7 +261,7 @@ impl Statement { collector.push_str("let "); collector.push_str(name.as_str(heap)); collector.push_str(" = !"); - operand.pretty_print(collector, heap, table); + operand.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Statement::Unary { name, operator: hir::UnaryOperator::IsPointer, operand } => { @@ -255,7 +269,7 @@ impl Statement { collector.push_str("let "); collector.push_str(name.as_str(heap)); collector.push_str(" = typeof "); - operand.pretty_print(collector, heap, table); + operand.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(" === 'object';\n"); } Statement::Binary { name, operator, e1, e2 } => { @@ -267,11 +281,11 @@ impl Statement { BinaryOperator::DIV => { // Necessary to preserve semantics collector.push_str("Math.floor("); - e1.pretty_print(collector, heap, table); + e1.pretty_print(collector, heap, symbol_table, str_table); collector.push(' '); collector.push_str(operator.as_str()); collector.push(' '); - e2.pretty_print(collector, heap, table); + e2.pretty_print(collector, heap, symbol_table, str_table); collector.push(')'); } BinaryOperator::LT @@ -282,11 +296,11 @@ impl Statement { | BinaryOperator::NE => { // Necessary to make TS happy collector.push_str("Number("); - e1.pretty_print(collector, heap, table); + e1.pretty_print(collector, heap, symbol_table, str_table); collector.push(' '); collector.push_str(operator.as_str()); collector.push(' '); - e2.pretty_print(collector, heap, table); + e2.pretty_print(collector, heap, symbol_table, str_table); collector.push(')'); } BinaryOperator::MUL @@ -298,11 +312,11 @@ impl Statement { | BinaryOperator::SHL | BinaryOperator::SHR | BinaryOperator::XOR => { - e1.pretty_print(collector, heap, table); + e1.pretty_print(collector, heap, symbol_table, str_table); collector.push(' '); collector.push_str(operator.as_str()); collector.push(' '); - e2.pretty_print(collector, heap, table); + e2.pretty_print(collector, heap, symbol_table, str_table); } }; collector.push_str(";\n"); @@ -312,20 +326,20 @@ impl Statement { collector.push_str("let "); collector.push_str(name.as_str(heap)); collector.push_str(": "); - type_.pretty_print(collector, heap, table); + type_.pretty_print(collector, heap, symbol_table); collector.push_str(" = "); - pointer_expression.pretty_print(collector, heap, table); + pointer_expression.pretty_print(collector, heap, symbol_table, str_table); collector.push('['); collector.push_str(&index.to_string()); collector.push_str("];\n"); } Statement::IndexedAssign { assigned_expression, pointer_expression, index } => { Self::append_spaces(collector, level); - pointer_expression.pretty_print(collector, heap, table); + pointer_expression.pretty_print(collector, heap, symbol_table, str_table); collector.push('['); collector.push_str(&index.to_string()); collector.push_str("] = "); - assigned_expression.pretty_print(collector, heap, table); + assigned_expression.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Statement::Call { callee, arguments, return_type, return_collector } => { @@ -334,12 +348,12 @@ impl Statement { collector.push_str("let "); collector.push_str(c.as_str(heap)); collector.push_str(": "); - return_type.pretty_print(collector, heap, table); + return_type.pretty_print(collector, heap, symbol_table); collector.push_str(" = "); } - callee.pretty_print(collector, heap, table); + callee.pretty_print(collector, heap, symbol_table, str_table); collector.push('('); - Self::print_expression_list(collector, heap, table, arguments); + Self::print_expression_list(collector, heap, symbol_table, str_table, arguments); collector.push_str(");\n"); } Statement::IfElse { condition, s1, s2, final_assignments } => { @@ -348,33 +362,47 @@ impl Statement { collector.push_str("let "); collector.push_str(n.as_str(heap)); collector.push_str(": "); - t.pretty_print(collector, heap, table); + t.pretty_print(collector, heap, symbol_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); collector.push_str("if ("); - condition.pretty_print(collector, heap, table); + condition.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(") {\n"); for s in s1 { - s.pretty_print_internal(heap, table, level + 1, break_collector, collector); + s.pretty_print_internal( + heap, + symbol_table, + str_table, + level + 1, + break_collector, + collector, + ); } for (n, _, v1, _) in final_assignments { Self::append_spaces(collector, level + 1); collector.push_str(n.as_str(heap)); collector.push_str(" = "); - v1.pretty_print(collector, heap, table); + v1.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); collector.push_str("} else {\n"); for s in s2 { - s.pretty_print_internal(heap, table, level + 1, break_collector, collector); + s.pretty_print_internal( + heap, + symbol_table, + str_table, + level + 1, + break_collector, + collector, + ); } for (n, _, _, v2) in final_assignments { Self::append_spaces(collector, level + 1); collector.push_str(n.as_str(heap)); collector.push_str(" = "); - v2.pretty_print(collector, heap, table); + v2.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); @@ -386,10 +414,17 @@ impl Statement { if *invert_condition { collector.push('!'); } - condition.pretty_print(collector, heap, table); + condition.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(") {\n"); for s in statements { - s.pretty_print_internal(heap, table, level + 1, break_collector, collector); + s.pretty_print_internal( + heap, + symbol_table, + str_table, + level + 1, + break_collector, + collector, + ); } Self::append_spaces(collector, level); collector.push_str("}\n"); @@ -399,7 +434,7 @@ impl Statement { Self::append_spaces(collector, level); collector.push_str(break_collector_str.as_str(heap)); collector.push_str(" = "); - break_value.pretty_print(collector, heap, table); + break_value.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); @@ -411,9 +446,9 @@ impl Statement { collector.push_str("let "); collector.push_str(v.name.as_str(heap)); collector.push_str(": "); - v.type_.pretty_print(collector, heap, table); + v.type_.pretty_print(collector, heap, symbol_table); collector.push_str(" = "); - v.initial_value.pretty_print(collector, heap, table); + v.initial_value.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } if let Some((n, t)) = break_collector { @@ -421,19 +456,26 @@ impl Statement { collector.push_str("let "); collector.push_str(n.as_str(heap)); collector.push_str(": "); - t.pretty_print(collector, heap, table); + t.pretty_print(collector, heap, symbol_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); collector.push_str("while (true) {\n"); for nested in statements { - nested.pretty_print_internal(heap, table, level + 1, break_collector, collector); + nested.pretty_print_internal( + heap, + symbol_table, + str_table, + level + 1, + break_collector, + collector, + ); } for v in loop_variables { Self::append_spaces(collector, level + 1); collector.push_str(v.name.as_str(heap)); collector.push_str(" = "); - v.loop_value.pretty_print(collector, heap, table); + v.loop_value.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Self::append_spaces(collector, level); @@ -444,9 +486,9 @@ impl Statement { collector.push_str("let "); collector.push_str(name.as_str(heap)); collector.push_str(" = "); - assigned_expression.pretty_print(collector, heap, table); + assigned_expression.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(" as unknown as "); - type_.pretty_print(collector, heap, table); + type_.pretty_print(collector, heap, symbol_table); collector.push_str(";\n"); } Statement::LateInitDeclaration { name, type_ } => { @@ -454,14 +496,14 @@ impl Statement { collector.push_str("let "); collector.push_str(name.as_str(heap)); collector.push_str(": "); - type_.pretty_print(collector, heap, table); + type_.pretty_print(collector, heap, symbol_table); collector.push_str(" = undefined as any;\n"); } Statement::LateInitAssignment { name, assigned_expression } => { Self::append_spaces(collector, level); collector.push_str(name.as_str(heap)); collector.push_str(" = "); - assigned_expression.pretty_print(collector, heap, table); + assigned_expression.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n"); } Statement::StructInit { struct_variable_name, type_, expression_list } => { @@ -469,9 +511,9 @@ impl Statement { collector.push_str("let "); collector.push_str(struct_variable_name.as_str(heap)); collector.push_str(": "); - type_.pretty_print(collector, heap, table); + type_.pretty_print(collector, heap, symbol_table); collector.push_str(" = ["); - Self::print_expression_list(collector, heap, table, expression_list); + Self::print_expression_list(collector, heap, symbol_table, str_table, expression_list); collector.push_str("];\n"); } } @@ -487,30 +529,36 @@ pub struct Function { } impl Function { - fn pretty_print(&self, collector: &mut String, heap: &Heap, table: &SymbolTable) { + fn pretty_print( + &self, + collector: &mut String, + heap: &Heap, + symbol_table: &SymbolTable, + str_table: &HashMap, + ) { collector.push_str("function "); - self.name.write_encoded(collector, heap, table); + self.name.write_encoded(collector, heap, symbol_table); collector.push('('); let mut iter = self.parameters.iter().zip(&self.type_.argument_types); if let Some((n, t)) = iter.next() { collector.push_str(n.as_str(heap)); collector.push_str(": "); - t.pretty_print(collector, heap, table); + t.pretty_print(collector, heap, symbol_table); for (n, t) in iter { collector.push_str(", "); collector.push_str(n.as_str(heap)); collector.push_str(": "); - t.pretty_print(collector, heap, table); + t.pretty_print(collector, heap, symbol_table); } } collector.push_str("): "); - self.type_.return_type.pretty_print(collector, heap, table); + self.type_.return_type.pretty_print(collector, heap, symbol_table); collector.push_str(" {\n"); for s in &self.body { - s.pretty_print_internal(heap, table, 1, &None, collector); + s.pretty_print_internal(heap, symbol_table, str_table, 1, &None, collector); } collector.push_str(" return "); - self.return_value.pretty_print(collector, heap, table); + self.return_value.pretty_print(collector, heap, symbol_table, str_table); collector.push_str(";\n}\n"); } } @@ -522,7 +570,7 @@ pub struct TypeDefinition { pub struct Sources { pub symbol_table: SymbolTable, - pub global_variables: Vec, + pub global_variables: Vec, pub type_definitions: Vec, pub main_function_names: Vec, pub functions: Vec, @@ -566,12 +614,14 @@ impl Sources { pub fn pretty_print(&self, heap: &Heap) -> String { let mut collector = ts_prolog(); - for v in &self.global_variables { - collector.push_str("const "); - collector.push_str(v.name.as_str(heap)); + let mut str_lookup_table = HashMap::new(); + for (i, hir::GlobalString(s)) in self.global_variables.iter().enumerate() { + collector.push_str("const GLOBAL_STRING_"); + collector.push_str(&i.to_string()); collector.push_str(": _Str = [0, `"); - collector.push_str(v.content.as_str(heap)); + collector.push_str(s.as_str(heap)); collector.push_str("` as unknown as number];\n"); + str_lookup_table.insert(*s, i); } for d in &self.type_definitions { collector.push_str("type "); @@ -588,7 +638,7 @@ impl Sources { collector.push_str("];\n"); } for f in &self.functions { - f.pretty_print(&mut collector, heap, &self.symbol_table); + f.pretty_print(&mut collector, heap, &self.symbol_table, &str_lookup_table); } collector } diff --git a/crates/samlang-ast/src/lir_tests.rs b/crates/samlang-ast/src/lir_tests.rs index cf73ffa2..5c5402a8 100644 --- a/crates/samlang-ast/src/lir_tests.rs +++ b/crates/samlang-ast/src/lir_tests.rs @@ -2,7 +2,7 @@ mod tests { use super::super::lir::*; use crate::{ - hir::{BinaryOperator, GlobalVariable, UnaryOperator}, + hir::{BinaryOperator, GlobalString, UnaryOperator}, mir::{FunctionName, SymbolTable}, }; use pretty_assertions::assert_eq; @@ -52,14 +52,8 @@ mod tests { let sources = Sources { global_variables: vec![ - GlobalVariable { - name: heap.alloc_str_for_test("dev_meggo"), - content: heap.alloc_str_for_test("vibez"), - }, - GlobalVariable { - name: heap.alloc_str_for_test("esc"), - content: heap.alloc_str_for_test(r#"f"\""#), - }, + GlobalString(heap.alloc_str_for_test("dev_meggo_vibez")), + GlobalString(heap.alloc_str_for_test(r#"f"\""#)), ], type_definitions: vec![ TypeDefinition { @@ -121,7 +115,9 @@ mod tests { Statement::StructInit { struct_variable_name: heap.alloc_str_for_test("baz"), type_: Type::Id(table.create_type_name_for_test(heap.alloc_str_for_test("FooBar"))), - expression_list: vec![Expression::StringName(heap.alloc_str_for_test("meggo"))], + expression_list: vec![Expression::StringName( + heap.alloc_str_for_test("dev_meggo_vibez"), + )], }, Statement::binary(heap.alloc_str_for_test("dd"), BinaryOperator::LT, ZERO, ZERO), Statement::binary(heap.alloc_str_for_test("dd"), BinaryOperator::LE, ZERO, ZERO), @@ -262,8 +258,8 @@ mod tests { symbol_table: table, }; let expected = format!( - r#"{}const dev_meggo: _Str = [0, `vibez` as unknown as number]; -const esc: _Str = [0, `f"\"` as unknown as number]; + r#"{}const GLOBAL_STRING_0: _Str = [0, `dev_meggo_vibez` as unknown as number]; +const GLOBAL_STRING_1: _Str = [0, `f"\"` as unknown as number]; type _Foo = [number, i31]; type _Foo = []; function __$main(): number {{ @@ -279,7 +275,7 @@ function __$Bar2(f: (t0: number, t1: number) => number, g: () => number): number function __$f(v1: (t0: number) => number): number {{ let bar: number; if (0) {{ - let baz: _FooBar = [meggo]; + let baz: _FooBar = [GLOBAL_STRING_0]; let dd = Number(0 < 0); let dd = Number(0 <= 0); let dd = Number(0 > 0); diff --git a/crates/samlang-ast/src/mir.rs b/crates/samlang-ast/src/mir.rs index 03c0bd71..1217f691 100644 --- a/crates/samlang-ast/src/mir.rs +++ b/crates/samlang-ast/src/mir.rs @@ -414,7 +414,7 @@ impl Expression { pub fn debug_print(&self, heap: &Heap, table: &SymbolTable) -> String { match self { Expression::IntLiteral(i) => i.to_string(), - Expression::StringName(n) => n.as_str(heap).to_string(), + Expression::StringName(n) => format!("\"{}\"", n.as_str(heap)), Expression::Variable(v) => v.debug_print(heap, table), } } @@ -897,7 +897,7 @@ impl Function { #[derive(Debug)] pub struct Sources { pub symbol_table: SymbolTable, - pub global_variables: Vec, + pub global_variables: Vec, pub closure_types: Vec, pub type_definitions: Vec, pub main_function_names: Vec, @@ -907,8 +907,8 @@ pub struct Sources { impl Sources { pub fn debug_print(&self, heap: &Heap) -> String { let mut lines = vec![]; - for v in &self.global_variables { - lines.push(format!("const {} = '{}';\n", v.name.as_str(heap), v.content.as_str(heap))); + for (i, v) in self.global_variables.iter().enumerate() { + lines.push(format!("const GLOBAL_STRING_{} = '{}';\n", i, v.0.as_str(heap))); } for d in &self.closure_types { lines.push(d.pretty_print(heap, &self.symbol_table)); diff --git a/crates/samlang-ast/src/mir_tests.rs b/crates/samlang-ast/src/mir_tests.rs index 76ebb6a3..138dcaec 100644 --- a/crates/samlang-ast/src/mir_tests.rs +++ b/crates/samlang-ast/src/mir_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use super::super::hir::{BinaryOperator, GlobalVariable, UnaryOperator}; + use super::super::hir::{BinaryOperator, GlobalString, UnaryOperator}; use super::super::mir::*; use pretty_assertions::assert_eq; use samlang_heap::{Heap, ModuleReference, PStr}; @@ -127,7 +127,7 @@ mod tests { Expression::var_name(PStr::LOWER_A, Type::Id(table.create_type_name_for_test(PStr::UPPER_A))) .debug_print(heap, table) ); - assert_eq!("a", Expression::StringName(PStr::LOWER_A).clone().debug_print(heap, table)); + assert_eq!("\"a\"", Expression::StringName(PStr::LOWER_A).clone().debug_print(heap, table)); } #[test] @@ -297,7 +297,7 @@ mod tests { format!("{:?}", stmt.clone()); let expected = r#"let bar: int; if 0 { - let baz: _FooBar = [meggo]; + let baz: _FooBar = ["meggo"]; let closure: _CCC = Closure { fun: (__$foo: (int) -> int), context: 0 }; let dd = 0 < 0; let dd = 0 <= 0; @@ -353,11 +353,7 @@ if 0 { let mut table = SymbolTable::new(); let sources1 = Sources { - global_variables: vec![GlobalVariable { - name: heap.alloc_str_for_test("dev_meggo"), - content: heap.alloc_str_for_test("vibez"), - } - .clone()], + global_variables: vec![GlobalString(heap.alloc_str_for_test("dev_meggo_vibez")).clone()], closure_types: vec![ClosureTypeDefinition { name: table.create_type_name_for_test(PStr::UPPER_A), function_type: Type::new_fn_unwrapped(vec![], INT_32_TYPE), @@ -388,7 +384,7 @@ if 0 { symbol_table: table, }; format!("{sources1:?}"); - let expected1 = r#"const dev_meggo = 'vibez'; + let expected1 = r#"const GLOBAL_STRING_0 = 'dev_meggo_vibez'; closure type _A = () -> int object type _Foo = [int, int] diff --git a/crates/samlang-compiler/src/hir_lowering.rs b/crates/samlang-compiler/src/hir_lowering.rs index b27376f1..9e412ab3 100644 --- a/crates/samlang-compiler/src/hir_lowering.rs +++ b/crates/samlang-compiler/src/hir_lowering.rs @@ -209,7 +209,7 @@ impl<'a> ExpressionLoweringManager<'a> { } source::expr::E::Literal(_, source::Literal::String(s)) => LoweringResult { statements: vec![], - expression: hir::Expression::StringName(self.string_manager.allocate(self.heap, *s).name), + expression: hir::Expression::StringName(self.string_manager.allocate(*s).0), }, source::expr::E::LocalId(_, id) => LoweringResult { statements: vec![], @@ -528,9 +528,7 @@ impl<'a> ExpressionLoweringManager<'a> { let concat_pstr = self.heap.alloc_string(concat_string); return LoweringResult { statements: vec![], - expression: hir::Expression::StringName( - self.string_manager.allocate(self.heap, concat_pstr).name, - ), + expression: hir::Expression::StringName(self.string_manager.allocate(concat_pstr).0), }; } let mut lowered_stmts = vec![]; @@ -869,7 +867,7 @@ impl<'a> ExpressionLoweringManager<'a> { }), arguments: vec![ hir::ZERO, - hir::Expression::StringName(self.string_manager.allocate(self.heap, PStr::EMPTY).name), + hir::Expression::StringName(self.string_manager.allocate(PStr::EMPTY).0), ], return_type: final_return_type.clone(), return_collector: Some(unreachable_branch_collector), @@ -1599,7 +1597,7 @@ mod tests { source::Literal::String(heap.alloc_str_for_test("foo")), ), heap, - "const GLOBAL_STRING_0 = 'foo';\n\n\nreturn GLOBAL_STRING_0;", + "const GLOBAL_STRING_0 = 'foo';\n\n\nreturn \"foo\";", ); // This & variable lowering works. @@ -2050,7 +2048,7 @@ return (_t1: _Str);"#, )), }), heap, - "const GLOBAL_STRING_0 = 'hello world';\n\n\nreturn GLOBAL_STRING_0;", + "const GLOBAL_STRING_0 = 'hello world';\n\n\nreturn \"hello world\";", ); } @@ -2343,7 +2341,7 @@ if (_t8: int) { if (_t4: int) { _t2 = (_this: DUMMY_Dummy); } else { - let _t1: DUMMY_Dummy = _Process$panic(0, GLOBAL_STRING_0); + let _t1: DUMMY_Dummy = _Process$panic(0, ""); _t2 = (_t1: DUMMY_Dummy); } _t5 = (_t2: DUMMY_Dummy); @@ -2463,7 +2461,7 @@ if (_t11: int) { if (_t4: int) { _t2 = (_this: DUMMY_Dummy); } else { - let _t1: DUMMY_Dummy = _Process$panic(0, GLOBAL_STRING_0); + let _t1: DUMMY_Dummy = _Process$panic(0, ""); _t2 = (_t1: DUMMY_Dummy); } _t5 = (_t2: DUMMY_Dummy); @@ -3399,7 +3397,7 @@ return (_t2: int);"#, r#"const GLOBAL_STRING_0 = 'foo'; let _t1: int; -_t1 = GLOBAL_STRING_0; +_t1 = "foo"; let _t2: int; _t2 = (_t1: int); return (_t2: int);"#, diff --git a/crates/samlang-compiler/src/hir_string_manager.rs b/crates/samlang-compiler/src/hir_string_manager.rs index 1ea6012f..75ae3bff 100644 --- a/crates/samlang-compiler/src/hir_string_manager.rs +++ b/crates/samlang-compiler/src/hir_string_manager.rs @@ -1,37 +1,24 @@ -use samlang_ast::hir::GlobalVariable; -use samlang_heap::{Heap, PStr}; -use std::collections::BTreeMap; +use samlang_ast::hir::GlobalString; +use samlang_heap::PStr; +use std::collections::BTreeSet; // TODO: move this to global variable since heap allows us to provide a better API pub(super) struct StringManager { - global_variable_reference_map: BTreeMap, + global_variable_reference_map: BTreeSet, } impl StringManager { pub(super) fn new() -> StringManager { - StringManager { global_variable_reference_map: BTreeMap::new() } + StringManager { global_variable_reference_map: BTreeSet::new() } } - pub(super) fn all_global_variables(self) -> Vec { - let mut vars = vec![]; - for (_, v) in self.global_variable_reference_map { - vars.push(v); - } - vars + pub(super) fn all_global_variables(self) -> Vec { + self.global_variable_reference_map.into_iter().map(GlobalString).collect() } - pub(super) fn allocate(&mut self, heap: &mut Heap, str: PStr) -> GlobalVariable { - if let Some(existing) = self.global_variable_reference_map.get(&str) { - *existing - } else { - let v = GlobalVariable { - name: heap - .alloc_string(format!("GLOBAL_STRING_{}", self.global_variable_reference_map.len())), - content: str, - }; - self.global_variable_reference_map.insert(str, v); - v - } + pub(super) fn allocate(&mut self, str: PStr) -> GlobalString { + self.global_variable_reference_map.insert(str); + GlobalString(str) } } @@ -39,15 +26,14 @@ impl StringManager { mod tests { use super::StringManager; use pretty_assertions::assert_eq; - use samlang_heap::{Heap, PStr}; + use samlang_heap::PStr; #[test] fn tests() { - let heap = &mut Heap::new(); let mut s = StringManager::new(); - assert_eq!(PStr::LOWER_A, s.allocate(heap, PStr::LOWER_A).content); - assert_eq!(PStr::LOWER_B, s.allocate(heap, PStr::LOWER_B).content); - assert_eq!(PStr::LOWER_A, s.allocate(heap, PStr::LOWER_A).content); + assert_eq!(PStr::LOWER_A, s.allocate(PStr::LOWER_A).0); + assert_eq!(PStr::LOWER_B, s.allocate(PStr::LOWER_B).0); + assert_eq!(PStr::LOWER_A, s.allocate(PStr::LOWER_A).0); assert_eq!(2, s.all_global_variables().len()); } } diff --git a/crates/samlang-compiler/src/lir_lowering.rs b/crates/samlang-compiler/src/lir_lowering.rs index 118b5fd6..3840598e 100644 --- a/crates/samlang-compiler/src/lir_lowering.rs +++ b/crates/samlang-compiler/src/lir_lowering.rs @@ -742,7 +742,7 @@ pub fn compile_mir_to_lir(heap: &mut Heap, sources: mir::Sources) -> lir::Source mod tests { use pretty_assertions::assert_eq; use samlang_ast::{ - hir::{BinaryOperator, UnaryOperator}, + hir::{self, BinaryOperator, UnaryOperator}, lir, mir::{ Callee, ClosureTypeDefinition, EnumTypeDefinition, Expression, Function, FunctionName, @@ -791,7 +791,7 @@ mod tests { let variant_type = &Type::Id(table.create_type_name_for_test(heap.alloc_str_for_test("Variant"))); let sources = Sources { - global_variables: vec![], + global_variables: vec![hir::GlobalString(heap.alloc_str_for_test("G1"))], closure_types: vec![ClosureTypeDefinition { name: table.create_type_name_for_test(heap.alloc_str_for_test("CC")), function_type: Type::new_fn_unwrapped(vec![INT_32_TYPE], INT_32_TYPE), @@ -1053,7 +1053,8 @@ mod tests { symbol_table: table, }; let expected = format!( - r#"{}type _CC = [number, (t0: any, t1: number) => number, any]; + r#"{}const GLOBAL_STRING_0: _Str = [0, `G1` as unknown as number]; +type _CC = [number, (t0: any, t1: number) => number, any]; type _Object = [number, number, number]; type _Variant = [number, number]; function __$cc(): i31 {{ @@ -1087,13 +1088,13 @@ function __$main(): number {{ __$inc_ref(_t3); let O: _Object = [131073, 0, obj]; let v1: _Variant = [1, 0, 0]; - let _t4 = G1 as unknown as any; + let _t4 = GLOBAL_STRING_0 as unknown as any; __$inc_ref(_t4); - let v2: _Variant = [131073, 0, G1]; - let _t5 = G1 as unknown as any; + let v2: _Variant = [131073, 0, GLOBAL_STRING_0]; + let _t5 = GLOBAL_STRING_0 as unknown as any; __$inc_ref(_t5); let _t6 = __$aaa as unknown as (t0: any) => number; - let _t7 = G1 as unknown as any; + let _t7 = GLOBAL_STRING_0 as unknown as any; let c1: _CC = [131073, _t6, _t7]; let _t8 = __$bbb as unknown as (t0: any) => number; let _t9 = 0 as unknown as any; diff --git a/crates/samlang-compiler/src/lir_unused_name_elimination.rs b/crates/samlang-compiler/src/lir_unused_name_elimination.rs index d3d433d2..dd729406 100644 --- a/crates/samlang-compiler/src/lir_unused_name_elimination.rs +++ b/crates/samlang-compiler/src/lir_unused_name_elimination.rs @@ -196,7 +196,7 @@ pub(super) fn optimize_lir_sources_by_eliminating_unused_ones( symbol_table, global_variables: global_variables .into_iter() - .filter(|it| used_str_names.contains(&it.name)) + .filter(|it| used_str_names.contains(&it.0)) .collect_vec(), type_definitions: type_definitions .into_iter() @@ -228,14 +228,8 @@ mod tests { let optimized = super::optimize_lir_sources_by_eliminating_unused_ones(Sources { global_variables: vec![ - hir::GlobalVariable { - name: heap.alloc_str_for_test("bar"), - content: heap.alloc_str_for_test("fff"), - }, - hir::GlobalVariable { - name: heap.alloc_str_for_test("fsdfsdf"), - content: heap.alloc_str_for_test("fff"), - }, + hir::GlobalString(heap.alloc_str_for_test("bar")), + hir::GlobalString(heap.alloc_str_for_test("fsdfsdf")), ], type_definitions: vec![ TypeDefinition { @@ -383,7 +377,7 @@ mod tests { assert_eq!( vec!["bar"], - optimized.global_variables.iter().map(|it| it.name.as_str(heap)).collect_vec() + optimized.global_variables.iter().map(|it| it.0.as_str(heap)).collect_vec() ); assert_eq!( vec!["_Foo"], diff --git a/crates/samlang-compiler/src/mir_constant_param_elimination.rs b/crates/samlang-compiler/src/mir_constant_param_elimination.rs index 91ce85f8..5483d8fc 100644 --- a/crates/samlang-compiler/src/mir_constant_param_elimination.rs +++ b/crates/samlang-compiler/src/mir_constant_param_elimination.rs @@ -631,7 +631,7 @@ function __$otherwise_optimizable(a: int, b: int): int { } function __$str_const(): int { - undefined = STR; + undefined = "STR"; break; return 0; } diff --git a/crates/samlang-compiler/src/mir_generics_specialization.rs b/crates/samlang-compiler/src/mir_generics_specialization.rs index 3e3ad126..a0bfeae6 100644 --- a/crates/samlang-compiler/src/mir_generics_specialization.rs +++ b/crates/samlang-compiler/src/mir_generics_specialization.rs @@ -697,7 +697,7 @@ pub(super) fn perform_generics_specialization( symbol_table, global_variables: global_variables .into_iter() - .filter(|it| used_string_names.contains(&it.name)) + .filter(|it| used_string_names.contains(&it.0)) .collect(), closure_types: specialized_closure_definitions.into_iter().sorted_by_key(|d| d.name).collect(), type_definitions: specialized_type_definitions @@ -713,7 +713,7 @@ pub(super) fn perform_generics_specialization( mod tests { use super::*; use pretty_assertions::assert_eq; - use samlang_ast::hir::{BinaryOperator, GlobalVariable, UnaryOperator}; + use samlang_ast::hir::{BinaryOperator, GlobalString, UnaryOperator}; use samlang_heap::{Heap, ModuleReference, PStr}; fn assert_specialized(sources: hir::Sources, heap: &mut Heap, expected: &str) { @@ -790,10 +790,7 @@ sources.mains = [_DUMMY_I$main] assert_specialized( hir::Sources { - global_variables: vec![GlobalVariable { - name: heap.alloc_str_for_test("G1"), - content: PStr::LOWER_A, - }], + global_variables: vec![GlobalString(heap.alloc_str_for_test("G1"))], closure_types: vec![], type_definitions: vec![hir::TypeDefinition { name: hir::STRING_TYPE.into_id().unwrap().name, @@ -832,11 +829,11 @@ sources.mains = [_DUMMY_I$main] }], }, heap, - r#"const G1 = 'a'; + r#"const GLOBAL_STRING_0 = 'G1'; variant type _Str = [] function _DUMMY_I$main(): int { - __Process$println(G1); + __Process$println("G1"); return 0; } @@ -863,8 +860,8 @@ sources.mains = [_DUMMY_I$main] assert_specialized( hir::Sources { global_variables: vec![ - GlobalVariable { name: heap.alloc_str_for_test("G1"), content: PStr::LOWER_A }, - GlobalVariable { name: heap.alloc_str_for_test("G2"), content: PStr::LOWER_A }, + GlobalString(heap.alloc_str_for_test("G1")), + GlobalString(heap.alloc_str_for_test("G2")), ], closure_types: vec![hir::ClosureTypeDefinition { name: hir::TypeName::new_for_test(heap.alloc_str_for_test("CC")), @@ -1296,7 +1293,7 @@ sources.mains = [_DUMMY_I$main] }, heap, r#" -const G1 = 'a'; +const GLOBAL_STRING_0 = 'G1'; closure type DUMMY_CC___Str__Str = (_Str) -> _Str closure type DUMMY_CC__int__Str = (int) -> _Str @@ -1311,10 +1308,10 @@ function _DUMMY_I$main(): int { let finalV: int; if 1 { let a: DUMMY_I__int__Str = _DUMMY_I__int$creatorIA(0); - let a2: DUMMY_I__int__Str = _DUMMY_I___Str$creatorIA(G1); - let b: DUMMY_I__int__Str = _DUMMY_I___Str$creatorIB(G1); - _DUMMY_I__DUMMY_I__int__Str$functor_fun(G1); - _DUMMY_I__DUMMY_J$functor_fun(G1); + let a2: DUMMY_I__int__Str = _DUMMY_I___Str$creatorIA("G1"); + let b: DUMMY_I__int__Str = _DUMMY_I___Str$creatorIB("G1"); + _DUMMY_I__DUMMY_I__int__Str$functor_fun("G1"); + _DUMMY_I__DUMMY_J$functor_fun("G1"); let v1: int = (a: DUMMY_I__int__Str)[0]; let late_init: int; late_init = (a: int); @@ -1325,8 +1322,8 @@ function _DUMMY_I$main(): int { let v1 = 0 + 0; let j: DUMMY_J = [0]; let v2: int = (j: DUMMY_J)[0]; - let c1: DUMMY_CC___Str__Str = Closure { fun: (_DUMMY_I___Str$creatorIA: (_Str) -> DUMMY_I___Str__Str), context: G1 }; - let c2: DUMMY_CC__int__Str = Closure { fun: (_DUMMY_I___Str$creatorIA: (_Str) -> DUMMY_I___Str__Str), context: G1 }; + let c1: DUMMY_CC___Str__Str = Closure { fun: (_DUMMY_I___Str$creatorIA: (_Str) -> DUMMY_I___Str__Str), context: "G1" }; + let c2: DUMMY_CC__int__Str = Closure { fun: (_DUMMY_I___Str$creatorIA: (_Str) -> DUMMY_I___Str__Str), context: "G1" }; finalV = (v2: int); } let b = 0 as DUMMY_Enum; @@ -1532,7 +1529,7 @@ function _DUMMY_I$creatorJ(): DUMMY_J { function _DUMMY_I$main(): int { _DUMMY_I$creatorJ(); (v: int)((b: DUMMY_StrOption)); - return creatorJ; + return "creatorJ"; } sources.mains = [_DUMMY_I$main]"#, diff --git a/crates/samlang-compiler/src/wasm_lowering.rs b/crates/samlang-compiler/src/wasm_lowering.rs index c44ef053..2ebe3dfd 100644 --- a/crates/samlang-compiler/src/wasm_lowering.rs +++ b/crates/samlang-compiler/src/wasm_lowering.rs @@ -278,13 +278,13 @@ pub(super) fn compile_lir_to_wasm(heap: &Heap, sources: &lir::Sources) -> wasm:: let mut global_variables_to_pointer_mapping = HashMap::new(); let mut function_index_mapping = HashMap::new(); let mut global_variables = vec![]; - for hir::GlobalVariable { name, content } in &sources.global_variables { + for hir::GlobalString(content) in &sources.global_variables { let content_str = content.as_str(heap); let mut bytes = vec![0, 0, 0, 0]; bytes.extend_from_slice(&(content_str.len() as u32).to_le_bytes()); bytes.extend_from_slice(content_str.as_bytes()); let global_variable = wasm::GlobalData { constant_pointer: data_start, bytes }; - global_variables_to_pointer_mapping.insert(*name, data_start); + global_variables_to_pointer_mapping.insert(*content, data_start); data_start += content_str.len() + 8; let pad = data_start % 8; if pad != 0 { @@ -319,7 +319,7 @@ pub(super) fn compile_lir_to_wasm(heap: &Heap, sources: &lir::Sources) -> wasm:: mod tests { use pretty_assertions::assert_eq; use samlang_ast::{ - hir::{BinaryOperator, GlobalVariable, UnaryOperator}, + hir::{BinaryOperator, GlobalString, UnaryOperator}, lir::{Expression, Function, GenenalLoopVariable, Sources, Statement, Type, INT_32_TYPE, ZERO}, mir, wasm, }; @@ -340,14 +340,8 @@ mod tests { let sources = Sources { symbol_table: mir::SymbolTable::new(), global_variables: vec![ - GlobalVariable { - name: heap.alloc_str_for_test("FOO"), - content: heap.alloc_str_for_test("foo"), - }, - GlobalVariable { - name: heap.alloc_str_for_test("BAR"), - content: heap.alloc_str_for_test("bar"), - }, + GlobalString(heap.alloc_str_for_test("FOO")), + GlobalString(heap.alloc_str_for_test("BAR")), ], type_definitions: vec![], main_function_names: vec![mir::FunctionName::new_for_test(PStr::MAIN_FN)], @@ -474,8 +468,8 @@ mod tests { let actual = super::compile_lir_to_wasm(heap, &sources).pretty_print(heap, &sources.symbol_table); let expected = r#"(type $i32_=>_i32 (func (param i32) (result i32))) -(data (i32.const 4096) "\00\00\00\00\03\00\00\00foo") -(data (i32.const 4112) "\00\00\00\00\03\00\00\00bar") +(data (i32.const 4096) "\00\00\00\00\03\00\00\00FOO") +(data (i32.const 4112) "\00\00\00\00\03\00\00\00BAR") (table $0 1 funcref) (elem $0 (i32.const 0) $__$main) (func $__$main (param $bar i32) (result i32) diff --git a/crates/samlang-optimization/src/unused_name_elimination.rs b/crates/samlang-optimization/src/unused_name_elimination.rs index 27d8d2f6..1187cf06 100644 --- a/crates/samlang-optimization/src/unused_name_elimination.rs +++ b/crates/samlang-optimization/src/unused_name_elimination.rs @@ -236,7 +236,7 @@ pub(super) fn optimize_sources(sources: &mut Sources) { &sources.type_definitions, &sources.main_function_names, ); - sources.global_variables.retain(|it| used_str_names.contains(&it.name)); + sources.global_variables.retain(|it| used_str_names.contains(&it.0)); sources.closure_types.retain(|it| used_types.contains(&it.name)); sources.type_definitions.retain(|it| used_types.contains(&it.name)); sources.functions.retain(|it| used_fn_names.contains(&it.name)); @@ -247,7 +247,7 @@ mod tests { use itertools::Itertools; use pretty_assertions::assert_eq; use samlang_ast::{ - hir::GlobalVariable, + hir::GlobalString, mir::{ Callee, ClosureTypeDefinition, EnumTypeDefinition, Expression, Function, FunctionName, FunctionNameExpression, GenenalLoopVariable, Sources, Statement, SymbolTable, Type, @@ -263,14 +263,8 @@ mod tests { let mut sources = Sources { global_variables: vec![ - GlobalVariable { - name: heap.alloc_str_for_test("bar"), - content: heap.alloc_str_for_test("fff"), - }, - GlobalVariable { - name: heap.alloc_str_for_test("fsdfsdf"), - content: heap.alloc_str_for_test("fff"), - }, + GlobalString(heap.alloc_str_for_test("bar")), + GlobalString(heap.alloc_str_for_test("fsdfsdf")), ], closure_types: vec![ ClosureTypeDefinition { @@ -475,7 +469,7 @@ mod tests { assert_eq!( vec!["bar"], - sources.global_variables.iter().map(|it| it.name.as_str(heap)).collect_vec() + sources.global_variables.iter().map(|it| it.0.as_str(heap)).collect_vec() ); assert_eq!( vec!["_Foo", "_Bar", "_RefByType", "_RefByType2", "_RefByType3"],