@tishlang/tish 1.9.2 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/tish +0 -0
- package/crates/js_to_tish/src/transform/expr.rs +8 -6
- package/crates/js_to_tish/src/transform/stmt.rs +12 -13
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/cargo_native_registry.rs +4 -1
- package/crates/tish/src/cli_help.rs +9 -1
- package/crates/tish/src/main.rs +66 -11
- package/crates/tish/tests/integration_test.rs +145 -7
- package/crates/tish_ast/src/ast.rs +3 -9
- package/crates/tish_build_utils/src/lib.rs +74 -23
- package/crates/tish_builtins/src/array.rs +2 -3
- package/crates/tish_builtins/src/construct.rs +15 -28
- package/crates/tish_builtins/src/globals.rs +18 -16
- package/crates/tish_builtins/src/helpers.rs +1 -4
- package/crates/tish_builtins/src/lib.rs +1 -0
- package/crates/tish_builtins/src/math.rs +7 -0
- package/crates/tish_builtins/src/object.rs +10 -10
- package/crates/tish_builtins/src/string.rs +27 -3
- package/crates/tish_builtins/src/symbol.rs +83 -0
- package/crates/tish_compile/src/codegen.rs +324 -158
- package/crates/tish_compile/src/lib.rs +39 -7
- package/crates/tish_compile/src/resolve.rs +191 -6
- package/crates/tish_compile/src/types.rs +6 -6
- package/crates/tish_compile_js/src/codegen.rs +8 -5
- package/crates/tish_core/src/console_style.rs +9 -0
- package/crates/tish_core/src/json.rs +17 -7
- package/crates/tish_core/src/macros.rs +2 -2
- package/crates/tish_core/src/value.rs +213 -4
- package/crates/tish_cranelift/src/link.rs +1 -1
- package/crates/tish_cranelift_runtime/Cargo.toml +4 -0
- package/crates/tish_eval/src/eval.rs +135 -73
- package/crates/tish_eval/src/http.rs +18 -12
- package/crates/tish_eval/src/lib.rs +29 -0
- package/crates/tish_eval/src/regex.rs +1 -1
- package/crates/tish_eval/src/value.rs +89 -4
- package/crates/tish_eval/src/value_convert.rs +30 -8
- package/crates/tish_fmt/src/lib.rs +4 -1
- package/crates/tish_lexer/src/lib.rs +7 -2
- package/crates/tish_llvm/src/lib.rs +2 -2
- package/crates/tish_lsp/src/builtin_goto.rs +111 -10
- package/crates/tish_lsp/src/import_goto.rs +35 -22
- package/crates/tish_lsp/src/main.rs +118 -85
- package/crates/tish_native/src/build.rs +270 -24
- package/crates/tish_native/src/config.rs +48 -0
- package/crates/tish_native/src/lib.rs +139 -12
- package/crates/tish_parser/src/lib.rs +5 -2
- package/crates/tish_parser/src/parser.rs +45 -75
- package/crates/tish_pg/src/error.rs +1 -1
- package/crates/tish_pg/src/lib.rs +61 -73
- package/crates/tish_resolve/src/lib.rs +283 -158
- package/crates/tish_resolve/src/pos.rs +10 -2
- package/crates/tish_runtime/Cargo.toml +3 -0
- package/crates/tish_runtime/src/http.rs +39 -39
- package/crates/tish_runtime/src/http_fetch.rs +12 -12
- package/crates/tish_runtime/src/lib.rs +35 -44
- package/crates/tish_runtime/src/native_promise.rs +0 -11
- package/crates/tish_runtime/src/promise.rs +14 -1
- package/crates/tish_runtime/src/promise_io.rs +1 -4
- package/crates/tish_runtime/src/timers.rs +12 -7
- package/crates/tish_runtime/src/ws.rs +40 -27
- package/crates/tish_runtime/tests/fetch_readable_stream.rs +10 -8
- package/crates/tish_ui/src/jsx.rs +6 -4
- package/crates/tish_ui/src/lib.rs +5 -4
- package/crates/tish_ui/src/runtime/hooks.rs +123 -37
- package/crates/tish_ui/src/runtime/mod.rs +21 -41
- package/crates/tish_vm/Cargo.toml +2 -0
- package/crates/tish_vm/src/vm.rs +258 -153
- package/crates/tish_wasm/src/lib.rs +60 -7
- package/crates/tish_wasm_runtime/Cargo.toml +10 -1
- package/crates/tish_wasm_runtime/src/gpu.rs +413 -0
- package/crates/tish_wasm_runtime/src/lib.rs +7 -1
- package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
- package/crates/tishlang_cargo_bindgen/src/discover.rs +10 -5
- package/crates/tishlang_cargo_bindgen/src/infer.rs +18 -8
- package/crates/tishlang_cargo_bindgen/src/lib.rs +25 -26
- package/crates/tishlang_cargo_bindgen/src/main.rs +41 -38
- package/crates/tishlang_cargo_bindgen/src/metadata.rs +4 -1
- package/justfile +3 -3
- package/package.json +1 -1
- package/platform/darwin-arm64/tish +0 -0
- package/platform/darwin-x64/tish +0 -0
- package/platform/linux-arm64/tish +0 -0
- package/platform/linux-x64/tish +0 -0
- package/platform/win32-x64/tish.exe +0 -0
|
@@ -540,6 +540,33 @@ pub fn compile_project_full(
|
|
|
540
540
|
crate::resolve::NativeBuildArtifacts,
|
|
541
541
|
),
|
|
542
542
|
CompileError,
|
|
543
|
+
> {
|
|
544
|
+
compile_project_full_emit(
|
|
545
|
+
entry_path,
|
|
546
|
+
project_root,
|
|
547
|
+
features,
|
|
548
|
+
optimize,
|
|
549
|
+
crate::NativeEmitMode::DesktopBin,
|
|
550
|
+
None,
|
|
551
|
+
)
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/// Like [`compile_project_full`], with emit mode and optional feature cap (e.g. iOS sandbox).
|
|
555
|
+
pub fn compile_project_full_emit(
|
|
556
|
+
entry_path: &Path,
|
|
557
|
+
project_root: Option<&Path>,
|
|
558
|
+
features: &[String],
|
|
559
|
+
optimize: bool,
|
|
560
|
+
emit_mode: crate::NativeEmitMode,
|
|
561
|
+
feature_cap: Option<&std::collections::HashSet<String>>,
|
|
562
|
+
) -> Result<
|
|
563
|
+
(
|
|
564
|
+
String,
|
|
565
|
+
Vec<crate::resolve::ResolvedNativeModule>,
|
|
566
|
+
Vec<String>,
|
|
567
|
+
crate::resolve::NativeBuildArtifacts,
|
|
568
|
+
),
|
|
569
|
+
CompileError,
|
|
543
570
|
> {
|
|
544
571
|
use crate::resolve;
|
|
545
572
|
let root = project_root.unwrap_or_else(|| entry_path.parent().unwrap_or(Path::new(".")));
|
|
@@ -555,33 +582,41 @@ pub fn compile_project_full(
|
|
|
555
582
|
message: e,
|
|
556
583
|
span: None,
|
|
557
584
|
})?;
|
|
558
|
-
let native_modules =
|
|
585
|
+
let mut native_modules =
|
|
559
586
|
resolve::resolve_native_modules(&merged.program, root).map_err(|e| CompileError {
|
|
560
587
|
message: e,
|
|
561
588
|
span: None,
|
|
562
589
|
})?;
|
|
563
|
-
|
|
564
|
-
&
|
|
565
|
-
root,
|
|
566
|
-
&native_modules,
|
|
567
|
-
)
|
|
568
|
-
.map_err(|e| CompileError {
|
|
590
|
+
if resolve::program_uses_document(&merged.program) {
|
|
591
|
+
resolve::ensure_tish_canvas_module(&mut native_modules, root).map_err(|e| CompileError {
|
|
569
592
|
message: e,
|
|
570
593
|
span: None,
|
|
571
594
|
})?;
|
|
595
|
+
}
|
|
596
|
+
let native_build =
|
|
597
|
+
resolve::compute_native_build_artifacts(&merged.program, root, &native_modules).map_err(
|
|
598
|
+
|e| CompileError {
|
|
599
|
+
message: e,
|
|
600
|
+
span: None,
|
|
601
|
+
},
|
|
602
|
+
)?;
|
|
572
603
|
let mut all_features: Vec<String> = features.to_vec();
|
|
573
604
|
for f in resolve::extract_native_import_features(&merged.program) {
|
|
574
605
|
if !all_features.contains(&f) {
|
|
575
606
|
all_features.push(f);
|
|
576
607
|
}
|
|
577
608
|
}
|
|
578
|
-
let
|
|
609
|
+
if let Some(cap) = feature_cap {
|
|
610
|
+
all_features.retain(|f| cap.contains(f));
|
|
611
|
+
}
|
|
612
|
+
let rust = compile_with_native_modules_emit(
|
|
579
613
|
&merged.program,
|
|
580
614
|
project_root,
|
|
581
615
|
&all_features,
|
|
582
616
|
&native_modules,
|
|
583
617
|
&native_build.native_init,
|
|
584
618
|
optimize,
|
|
619
|
+
emit_mode,
|
|
585
620
|
)?;
|
|
586
621
|
Ok((rust, native_modules, all_features, native_build))
|
|
587
622
|
}
|
|
@@ -605,6 +640,26 @@ pub fn compile_with_native_modules(
|
|
|
605
640
|
native_modules: &[crate::resolve::ResolvedNativeModule],
|
|
606
641
|
native_init: &std::collections::HashMap<String, crate::resolve::NativeModuleInit>,
|
|
607
642
|
optimize: bool,
|
|
643
|
+
) -> Result<String, CompileError> {
|
|
644
|
+
compile_with_native_modules_emit(
|
|
645
|
+
program,
|
|
646
|
+
project_root,
|
|
647
|
+
features,
|
|
648
|
+
native_modules,
|
|
649
|
+
native_init,
|
|
650
|
+
optimize,
|
|
651
|
+
crate::NativeEmitMode::DesktopBin,
|
|
652
|
+
)
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
pub fn compile_with_native_modules_emit(
|
|
656
|
+
program: &Program,
|
|
657
|
+
project_root: Option<&Path>,
|
|
658
|
+
features: &[String],
|
|
659
|
+
native_modules: &[crate::resolve::ResolvedNativeModule],
|
|
660
|
+
native_init: &std::collections::HashMap<String, crate::resolve::NativeModuleInit>,
|
|
661
|
+
optimize: bool,
|
|
662
|
+
emit_mode: crate::NativeEmitMode,
|
|
608
663
|
) -> Result<String, CompileError> {
|
|
609
664
|
let program = if optimize {
|
|
610
665
|
tishlang_opt::optimize(program)
|
|
@@ -632,6 +687,13 @@ pub fn compile_with_native_modules(
|
|
|
632
687
|
native_init.clone()
|
|
633
688
|
};
|
|
634
689
|
let mut g = Codegen::new_with_native_modules(project_root, features, map);
|
|
690
|
+
g.emit_mode = emit_mode;
|
|
691
|
+
g.has_native_ui_host = native_modules.iter().any(|m| {
|
|
692
|
+
m.package_name == "tish-macos"
|
|
693
|
+
|| m.package_name == "tish-ios"
|
|
694
|
+
|| m.crate_name == "tishlang_macos"
|
|
695
|
+
|| m.crate_name == "tishlang_ios"
|
|
696
|
+
});
|
|
635
697
|
g.emit_program(&program)?;
|
|
636
698
|
Ok(g.output)
|
|
637
699
|
}
|
|
@@ -682,6 +744,11 @@ struct Codegen {
|
|
|
682
744
|
/// `try`/`throw` lowering uses `return Err` only at depth 0 (e.g. `run()`); inside native
|
|
683
745
|
/// closures it must not return a `Result` from a `Value`-returning closure.
|
|
684
746
|
value_fn_depth: u32,
|
|
747
|
+
emit_mode: crate::NativeEmitMode,
|
|
748
|
+
/// Program links `tish:macos` / `tish:ios` — skip HeadlessHost install.
|
|
749
|
+
has_native_ui_host: bool,
|
|
750
|
+
/// Program references browser global `document` — inject tish-canvas.
|
|
751
|
+
program_uses_document: bool,
|
|
685
752
|
}
|
|
686
753
|
|
|
687
754
|
impl Codegen {
|
|
@@ -712,6 +779,19 @@ impl Codegen {
|
|
|
712
779
|
program_has_jsx: false,
|
|
713
780
|
program_fun_decl_names: std::collections::HashSet::new(),
|
|
714
781
|
value_fn_depth: 0,
|
|
782
|
+
emit_mode: crate::NativeEmitMode::DesktopBin,
|
|
783
|
+
has_native_ui_host: false,
|
|
784
|
+
program_uses_document: false,
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/// In async `run()` bodies, propagate runtime op errors with `?`; in sync
|
|
789
|
+
/// `Value::native` closures use `.unwrap_or(Value::Null)`.
|
|
790
|
+
fn ops_result_suffix(&self) -> &'static str {
|
|
791
|
+
if self.is_async && self.async_context_stack.last().copied().unwrap_or(false) {
|
|
792
|
+
"?"
|
|
793
|
+
} else {
|
|
794
|
+
".unwrap_or(Value::Null)"
|
|
715
795
|
}
|
|
716
796
|
}
|
|
717
797
|
|
|
@@ -731,12 +811,9 @@ impl Codegen {
|
|
|
731
811
|
for _ in 0..8 {
|
|
732
812
|
let mut changed = false;
|
|
733
813
|
for (name, ann) in &raw {
|
|
734
|
-
let resolved =
|
|
735
|
-
ann,
|
|
736
|
-
|
|
737
|
-
);
|
|
738
|
-
let prev: Option<crate::types::RustType> =
|
|
739
|
-
self.type_aliases.get(name).cloned();
|
|
814
|
+
let resolved =
|
|
815
|
+
crate::types::RustType::from_annotation_with_aliases(ann, &self.type_aliases);
|
|
816
|
+
let prev: Option<crate::types::RustType> = self.type_aliases.get(name).cloned();
|
|
740
817
|
if prev.as_ref() != Some(&resolved) {
|
|
741
818
|
self.type_aliases.insert(name.clone(), resolved);
|
|
742
819
|
changed = true;
|
|
@@ -791,8 +868,11 @@ impl Codegen {
|
|
|
791
868
|
fn emit_named_struct_decls(&mut self) {
|
|
792
869
|
// Snapshot keys + values so we can mutate `self` (writing the
|
|
793
870
|
// emitted source) inside the loop.
|
|
794
|
-
let mut entries: Vec<(String, crate::types::RustType)> =
|
|
795
|
-
|
|
871
|
+
let mut entries: Vec<(String, crate::types::RustType)> = self
|
|
872
|
+
.type_aliases
|
|
873
|
+
.iter()
|
|
874
|
+
.map(|(k, v)| (k.clone(), v.clone()))
|
|
875
|
+
.collect();
|
|
796
876
|
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
|
797
877
|
let mut emitted_any = false;
|
|
798
878
|
for (name, ty) in entries {
|
|
@@ -928,7 +1008,7 @@ impl Codegen {
|
|
|
928
1008
|
}
|
|
929
1009
|
};
|
|
930
1010
|
format!(
|
|
931
|
-
"{{ let _ns = {}; match _ns {{ Value::Object(ref _o) => _o.borrow().get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }} }}",
|
|
1011
|
+
"{{ let _ns = {}; match _ns {{ Value::Object(ref _o) => _o.borrow().strings.get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }} }}",
|
|
932
1012
|
init_expr, export_name
|
|
933
1013
|
)
|
|
934
1014
|
})
|
|
@@ -954,8 +1034,9 @@ impl Codegen {
|
|
|
954
1034
|
// latter dispatches into `http_serve_per_worker`, which
|
|
955
1035
|
// calls onWorker once per accept thread to build that
|
|
956
1036
|
// thread's handler.
|
|
957
|
-
"serve" => Some("Value::native(|args: &[Value]| { let handler = args.get(1).cloned().unwrap_or(Value::Null); match handler { Value::Function(f) => tish_http_serve(args, move |req_args| f(req_args)), Value::Object(ref opts) => { let factory = opts.borrow().get(
|
|
1037
|
+
"serve" => Some("Value::native(|args: &[Value]| { let handler = args.get(1).cloned().unwrap_or(Value::Null); match handler { Value::Function(f) => tish_http_serve(args, move |req_args| f(req_args)), Value::Object(ref opts) => { let factory = opts.borrow().strings.get(\"onWorker\").cloned().unwrap_or(Value::Null); tishlang_runtime::http_serve_per_worker(args, factory) }, _ => Value::Null } })"),
|
|
958
1038
|
"Promise" => Some("tish_promise_object()"),
|
|
1039
|
+
"Symbol" => Some("tish_symbol_object()"),
|
|
959
1040
|
_ => None,
|
|
960
1041
|
},
|
|
961
1042
|
"tish:timers" if self.has_feature("timers") => match export_name {
|
|
@@ -970,8 +1051,8 @@ impl Codegen {
|
|
|
970
1051
|
"cwd" => Some("Value::native(|args: &[Value]| tish_process_cwd(args))"),
|
|
971
1052
|
"exec" => Some("Value::native(|args: &[Value]| tish_process_exec(args))"),
|
|
972
1053
|
"argv" => Some("Value::Array(VmRef::new(std::env::args().map(|s| Value::String(s.into())).collect()))"),
|
|
973
|
-
"env" => Some("Value::
|
|
974
|
-
"process" => Some("{ let mut m = ObjectMap::default(); m.insert(Arc::from(\"exit\"), Value::native(|args: &[Value]| tish_process_exit(args))); m.insert(Arc::from(\"cwd\"), Value::native(|args: &[Value]| tish_process_cwd(args))); m.insert(Arc::from(\"exec\"), Value::native(|args: &[Value]| tish_process_exec(args))); m.insert(Arc::from(\"argv\"), Value::Array(VmRef::new(std::env::args().map(|s| Value::String(s.into())).collect()))); m.insert(Arc::from(\"env\"), Value::
|
|
1054
|
+
"env" => Some("Value::object(std::env::vars().map(|(k,v)| (Arc::from(k.as_str()), Value::String(v.into()))).collect())"),
|
|
1055
|
+
"process" => Some("{ let mut m = ObjectMap::default(); m.insert(Arc::from(\"exit\"), Value::native(|args: &[Value]| tish_process_exit(args))); m.insert(Arc::from(\"cwd\"), Value::native(|args: &[Value]| tish_process_cwd(args))); m.insert(Arc::from(\"exec\"), Value::native(|args: &[Value]| tish_process_exec(args))); m.insert(Arc::from(\"argv\"), Value::Array(VmRef::new(std::env::args().map(|s| Value::String(s.into())).collect()))); m.insert(Arc::from(\"env\"), Value::object(std::env::vars().map(|(k,v)| (Arc::from(k.as_str()), Value::String(v.into()))).collect::<ObjectMap>())); Value::object(m) }"),
|
|
975
1056
|
_ => None,
|
|
976
1057
|
},
|
|
977
1058
|
"tish:ws" if self.has_feature("ws") => match export_name {
|
|
@@ -1222,11 +1303,12 @@ impl Codegen {
|
|
|
1222
1303
|
self.is_async = program_uses_async(program);
|
|
1223
1304
|
self.program_has_jsx = tishlang_ui::jsx::program_contains_jsx(program);
|
|
1224
1305
|
self.program_fun_decl_names = tishlang_ui::jsx::collect_fun_decl_names(program);
|
|
1306
|
+
self.program_uses_document = crate::resolve::program_uses_document(program);
|
|
1225
1307
|
self.write("#![allow(unused, non_snake_case)]\n\n");
|
|
1226
1308
|
self.write("use std::cell::RefCell;\n");
|
|
1227
1309
|
self.write("use std::rc::Rc;\n");
|
|
1228
1310
|
self.write("use std::sync::Arc;\n");
|
|
1229
|
-
self.write("use tishlang_runtime::{console_debug as tish_console_debug, console_info as tish_console_info, console_log as tish_console_log, console_warn as tish_console_warn, console_error as tish_console_error, boolean as tish_boolean, decode_uri as tish_decode_uri, encode_uri as tish_encode_uri, string_escape_html_impl as tish_escape_html, in_operator as tish_in_operator, is_finite as tish_is_finite, is_nan as tish_is_nan, json_parse as tish_json_parse, json_stringify as tish_json_stringify, math_abs as tish_math_abs, math_ceil as tish_math_ceil, math_floor as tish_math_floor, math_max as tish_math_max, math_min as tish_math_min, math_round as tish_math_round, math_sqrt as tish_math_sqrt, parse_float as tish_parse_float, parse_int as tish_parse_int, math_random as tish_math_random, math_pow as tish_math_pow, math_sin as tish_math_sin, math_cos as tish_math_cos, math_tan as tish_math_tan, math_log as tish_math_log, math_exp as tish_math_exp, math_sign as tish_math_sign, math_trunc as tish_math_trunc, date_now as tish_date_now, array_is_array as tish_array_is_array, string_from_char_code as tish_string_from_char_code, object_assign as tish_object_assign, object_keys as tish_object_keys, object_values as tish_object_values, object_entries as tish_object_entries, object_from_entries as tish_object_from_entries, tish_construct, tish_uint8_array_constructor, tish_audio_context_constructor, register_static_route as tish_register_static_route, ObjectMap, TishError, Value, VmRef};\n");
|
|
1311
|
+
self.write("use tishlang_runtime::{console_debug as tish_console_debug, console_info as tish_console_info, console_log as tish_console_log, console_warn as tish_console_warn, console_error as tish_console_error, boolean as tish_boolean, decode_uri as tish_decode_uri, encode_uri as tish_encode_uri, string_escape_html_impl as tish_escape_html, in_operator as tish_in_operator, is_finite as tish_is_finite, is_nan as tish_is_nan, json_parse as tish_json_parse, json_stringify as tish_json_stringify, math_abs as tish_math_abs, math_ceil as tish_math_ceil, math_floor as tish_math_floor, math_max as tish_math_max, math_min as tish_math_min, math_round as tish_math_round, math_sqrt as tish_math_sqrt, parse_float as tish_parse_float, parse_int as tish_parse_int, math_random as tish_math_random, math_pow as tish_math_pow, math_sin as tish_math_sin, math_cos as tish_math_cos, math_tan as tish_math_tan, math_log as tish_math_log, math_exp as tish_math_exp, math_sign as tish_math_sign, math_trunc as tish_math_trunc, math_imul as tish_math_imul, date_now as tish_date_now, array_is_array as tish_array_is_array, string_from_char_code as tish_string_from_char_code, object_assign as tish_object_assign, object_keys as tish_object_keys, object_values as tish_object_values, object_entries as tish_object_entries, object_from_entries as tish_object_from_entries, symbol_object as tish_symbol_object, tish_construct, tish_uint8_array_constructor, tish_audio_context_constructor, register_static_route as tish_register_static_route, ObjectMap, TishError, Value, VmRef};\n");
|
|
1230
1312
|
if self.program_has_jsx {
|
|
1231
1313
|
self.write("use tishlang_ui::{fragment_value, install_thread_local_host, native_create_root, native_use_state, ui_h, ui_text, HeadlessHost};\n");
|
|
1232
1314
|
}
|
|
@@ -1252,6 +1334,9 @@ impl Codegen {
|
|
|
1252
1334
|
if self.has_feature("regex") {
|
|
1253
1335
|
self.write("use tishlang_runtime::regexp_new;\n");
|
|
1254
1336
|
}
|
|
1337
|
+
if self.program_uses_document {
|
|
1338
|
+
self.write("use tish_canvas::document_value as tish_canvas_document;\n");
|
|
1339
|
+
}
|
|
1255
1340
|
self.write("\n");
|
|
1256
1341
|
|
|
1257
1342
|
// Collect every `type Foo = { ... }` declaration in the program
|
|
@@ -1267,35 +1352,39 @@ impl Codegen {
|
|
|
1267
1352
|
// and `x.field` becomes a direct field access.
|
|
1268
1353
|
self.emit_named_struct_decls();
|
|
1269
1354
|
|
|
1270
|
-
if self.is_async {
|
|
1355
|
+
if self.is_async && self.emit_mode == crate::NativeEmitMode::DesktopBin {
|
|
1271
1356
|
self.writeln("#[tokio::main]");
|
|
1272
1357
|
self.writeln("async fn main() {");
|
|
1273
|
-
} else {
|
|
1358
|
+
} else if self.emit_mode == crate::NativeEmitMode::DesktopBin {
|
|
1274
1359
|
self.writeln("fn main() {");
|
|
1275
1360
|
}
|
|
1276
|
-
self.
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1361
|
+
if self.emit_mode == crate::NativeEmitMode::DesktopBin {
|
|
1362
|
+
self.indent += 1;
|
|
1363
|
+
if self.is_async {
|
|
1364
|
+
self.writeln("if let Err(e) = run().await {");
|
|
1365
|
+
} else {
|
|
1366
|
+
self.writeln("if let Err(e) = run() {");
|
|
1367
|
+
}
|
|
1368
|
+
self.indent += 1;
|
|
1369
|
+
self.writeln("eprintln!(\"Error: {}\", e);");
|
|
1370
|
+
self.writeln("std::process::exit(1);");
|
|
1371
|
+
self.indent -= 1;
|
|
1372
|
+
self.writeln("}");
|
|
1373
|
+
self.indent -= 1;
|
|
1374
|
+
self.writeln("}");
|
|
1375
|
+
self.writeln("");
|
|
1281
1376
|
}
|
|
1282
|
-
self.indent += 1;
|
|
1283
|
-
self.writeln("eprintln!(\"Error: {}\", e);");
|
|
1284
|
-
self.writeln("std::process::exit(1);");
|
|
1285
|
-
self.indent -= 1;
|
|
1286
|
-
self.writeln("}");
|
|
1287
|
-
self.indent -= 1;
|
|
1288
|
-
self.writeln("}");
|
|
1289
|
-
self.writeln("");
|
|
1290
1377
|
if self.is_async {
|
|
1291
1378
|
self.writeln("async fn run() -> Result<(), Box<dyn std::error::Error>> {");
|
|
1379
|
+
} else if self.emit_mode == crate::NativeEmitMode::EmbeddedLib {
|
|
1380
|
+
self.writeln("pub fn run() -> Result<(), Box<dyn std::error::Error>> {");
|
|
1292
1381
|
} else {
|
|
1293
1382
|
self.writeln("fn run() -> Result<(), Box<dyn std::error::Error>> {");
|
|
1294
1383
|
}
|
|
1295
1384
|
self.indent += 1;
|
|
1296
1385
|
|
|
1297
1386
|
// Initialize builtins
|
|
1298
|
-
self.writeln("let mut console = Value::
|
|
1387
|
+
self.writeln("let mut console = Value::object(ObjectMap::from([");
|
|
1299
1388
|
self.indent += 1;
|
|
1300
1389
|
self.writeln("(Arc::from(\"debug\"), Value::native(|args: &[Value]| { tish_console_debug(args); Value::Null })),");
|
|
1301
1390
|
self.writeln("(Arc::from(\"info\"), Value::native(|args: &[Value]| { tish_console_info(args); Value::Null })),");
|
|
@@ -1303,147 +1392,156 @@ impl Codegen {
|
|
|
1303
1392
|
self.writeln("(Arc::from(\"warn\"), Value::native(|args: &[Value]| { tish_console_warn(args); Value::Null })),");
|
|
1304
1393
|
self.writeln("(Arc::from(\"error\"), Value::native(|args: &[Value]| { tish_console_error(args); Value::Null })),");
|
|
1305
1394
|
self.indent -= 1;
|
|
1306
|
-
self.writeln("]))
|
|
1307
|
-
self.writeln(
|
|
1308
|
-
|
|
1309
|
-
);
|
|
1310
|
-
self.writeln(
|
|
1311
|
-
|
|
1312
|
-
);
|
|
1313
|
-
self.writeln(
|
|
1314
|
-
"let parseFloat = Value::native(|args: &[Value]| tish_parse_float(args));",
|
|
1315
|
-
);
|
|
1316
|
-
self.writeln(
|
|
1317
|
-
"let decodeURI = Value::native(|args: &[Value]| tish_decode_uri(args));",
|
|
1318
|
-
);
|
|
1319
|
-
self.writeln(
|
|
1320
|
-
"let encodeURI = Value::native(|args: &[Value]| tish_encode_uri(args));",
|
|
1321
|
-
);
|
|
1395
|
+
self.writeln("]));");
|
|
1396
|
+
self.writeln("let Boolean = Value::native(|args: &[Value]| tish_boolean(args));");
|
|
1397
|
+
self.writeln("let parseInt = Value::native(|args: &[Value]| tish_parse_int(args));");
|
|
1398
|
+
self.writeln("let parseFloat = Value::native(|args: &[Value]| tish_parse_float(args));");
|
|
1399
|
+
self.writeln("let decodeURI = Value::native(|args: &[Value]| tish_decode_uri(args));");
|
|
1400
|
+
self.writeln("let encodeURI = Value::native(|args: &[Value]| tish_encode_uri(args));");
|
|
1322
1401
|
self.writeln(
|
|
1323
1402
|
r#"let registerStaticRoute = Value::native(|args: &[Value]| { let path = match args.get(0) { Some(Value::String(s)) => s.to_string(), _ => return Value::Null }; let body = match args.get(1) { Some(Value::String(s)) => s.as_bytes().to_vec(), _ => return Value::Null }; let ct = match args.get(2) { Some(Value::String(s)) => s.to_string(), _ => "application/octet-stream".to_string() }; tish_register_static_route(&path, &body, &ct); Value::Null });"#,
|
|
1324
1403
|
);
|
|
1325
1404
|
self.writeln(
|
|
1326
1405
|
"let htmlEscape = Value::native(|args: &[Value]| tish_escape_html(args.first().unwrap_or(&Value::Null)));",
|
|
1327
1406
|
);
|
|
1328
|
-
self.writeln(
|
|
1329
|
-
"let isFinite = Value::native(|args: &[Value]| tish_is_finite(args));",
|
|
1330
|
-
);
|
|
1407
|
+
self.writeln("let isFinite = Value::native(|args: &[Value]| tish_is_finite(args));");
|
|
1331
1408
|
self.writeln("let isNaN = Value::native(|args: &[Value]| tish_is_nan(args));");
|
|
1332
1409
|
self.writeln("let Infinity = Value::Number(f64::INFINITY);");
|
|
1333
1410
|
self.writeln("let NaN = Value::Number(f64::NAN);");
|
|
1334
|
-
self.writeln("let Math = Value::
|
|
1411
|
+
self.writeln("let Math = Value::object(ObjectMap::from([");
|
|
1335
1412
|
self.indent += 1;
|
|
1413
|
+
self.writeln("(Arc::from(\"abs\"), Value::native(|args: &[Value]| tish_math_abs(args))),");
|
|
1336
1414
|
self.writeln(
|
|
1337
|
-
"(Arc::from(\"
|
|
1415
|
+
"(Arc::from(\"sqrt\"), Value::native(|args: &[Value]| tish_math_sqrt(args))),",
|
|
1338
1416
|
);
|
|
1339
|
-
self.writeln("(Arc::from(\"
|
|
1417
|
+
self.writeln("(Arc::from(\"min\"), Value::native(|args: &[Value]| tish_math_min(args))),");
|
|
1418
|
+
self.writeln("(Arc::from(\"max\"), Value::native(|args: &[Value]| tish_math_max(args))),");
|
|
1340
1419
|
self.writeln(
|
|
1341
|
-
"(Arc::from(\"
|
|
1420
|
+
"(Arc::from(\"floor\"), Value::native(|args: &[Value]| tish_math_floor(args))),",
|
|
1342
1421
|
);
|
|
1343
1422
|
self.writeln(
|
|
1344
|
-
"(Arc::from(\"
|
|
1423
|
+
"(Arc::from(\"ceil\"), Value::native(|args: &[Value]| tish_math_ceil(args))),",
|
|
1345
1424
|
);
|
|
1346
|
-
self.writeln("(Arc::from(\"floor\"), Value::native(|args: &[Value]| tish_math_floor(args))),");
|
|
1347
|
-
self.writeln("(Arc::from(\"ceil\"), Value::native(|args: &[Value]| tish_math_ceil(args))),");
|
|
1348
|
-
self.writeln("(Arc::from(\"round\"), Value::native(|args: &[Value]| tish_math_round(args))),");
|
|
1349
|
-
self.writeln("(Arc::from(\"random\"), Value::native(|args: &[Value]| tish_math_random(args))),");
|
|
1350
1425
|
self.writeln(
|
|
1351
|
-
"(Arc::from(\"
|
|
1426
|
+
"(Arc::from(\"round\"), Value::native(|args: &[Value]| tish_math_round(args))),",
|
|
1352
1427
|
);
|
|
1353
1428
|
self.writeln(
|
|
1354
|
-
"(Arc::from(\"
|
|
1429
|
+
"(Arc::from(\"random\"), Value::native(|args: &[Value]| tish_math_random(args))),",
|
|
1355
1430
|
);
|
|
1431
|
+
self.writeln("(Arc::from(\"pow\"), Value::native(|args: &[Value]| tish_math_pow(args))),");
|
|
1432
|
+
self.writeln("(Arc::from(\"sin\"), Value::native(|args: &[Value]| tish_math_sin(args))),");
|
|
1433
|
+
self.writeln("(Arc::from(\"cos\"), Value::native(|args: &[Value]| tish_math_cos(args))),");
|
|
1434
|
+
self.writeln("(Arc::from(\"tan\"), Value::native(|args: &[Value]| tish_math_tan(args))),");
|
|
1435
|
+
self.writeln("(Arc::from(\"log\"), Value::native(|args: &[Value]| tish_math_log(args))),");
|
|
1436
|
+
self.writeln("(Arc::from(\"exp\"), Value::native(|args: &[Value]| tish_math_exp(args))),");
|
|
1356
1437
|
self.writeln(
|
|
1357
|
-
"(Arc::from(\"
|
|
1438
|
+
"(Arc::from(\"sign\"), Value::native(|args: &[Value]| tish_math_sign(args))),",
|
|
1358
1439
|
);
|
|
1359
1440
|
self.writeln(
|
|
1360
|
-
"(Arc::from(\"
|
|
1441
|
+
"(Arc::from(\"trunc\"), Value::native(|args: &[Value]| tish_math_trunc(args))),",
|
|
1361
1442
|
);
|
|
1362
1443
|
self.writeln(
|
|
1363
|
-
"(Arc::from(\"
|
|
1444
|
+
"(Arc::from(\"imul\"), Value::native(|args: &[Value]| tish_math_imul(args))),",
|
|
1364
1445
|
);
|
|
1365
|
-
self.writeln(
|
|
1366
|
-
"(Arc::from(\"exp\"), Value::native(|args: &[Value]| tish_math_exp(args))),",
|
|
1367
|
-
);
|
|
1368
|
-
self.writeln("(Arc::from(\"sign\"), Value::native(|args: &[Value]| tish_math_sign(args))),");
|
|
1369
|
-
self.writeln("(Arc::from(\"trunc\"), Value::native(|args: &[Value]| tish_math_trunc(args))),");
|
|
1370
1446
|
self.writeln("(Arc::from(\"PI\"), Value::Number(std::f64::consts::PI)),");
|
|
1371
1447
|
self.writeln("(Arc::from(\"E\"), Value::Number(std::f64::consts::E)),");
|
|
1372
1448
|
self.indent -= 1;
|
|
1373
|
-
self.writeln("]))
|
|
1374
|
-
self.writeln("let JSON = Value::
|
|
1449
|
+
self.writeln("]));");
|
|
1450
|
+
self.writeln("let JSON = Value::object(ObjectMap::from([");
|
|
1375
1451
|
self.indent += 1;
|
|
1376
|
-
self.writeln(
|
|
1452
|
+
self.writeln(
|
|
1453
|
+
"(Arc::from(\"parse\"), Value::native(|args: &[Value]| tish_json_parse(args))),",
|
|
1454
|
+
);
|
|
1377
1455
|
self.writeln("(Arc::from(\"stringify\"), Value::native(|args: &[Value]| tish_json_stringify(args))),");
|
|
1378
1456
|
self.indent -= 1;
|
|
1379
|
-
self.writeln("]))
|
|
1457
|
+
self.writeln("]));");
|
|
1380
1458
|
|
|
1381
|
-
self.writeln("let Array = Value::
|
|
1459
|
+
self.writeln("let Array = Value::object(ObjectMap::from([");
|
|
1382
1460
|
self.indent += 1;
|
|
1383
|
-
self.writeln(
|
|
1461
|
+
self.writeln(
|
|
1462
|
+
"(Arc::from(\"isArray\"), Value::native(|args: &[Value]| tish_array_is_array(args))),",
|
|
1463
|
+
);
|
|
1384
1464
|
self.indent -= 1;
|
|
1385
|
-
self.writeln("]))
|
|
1465
|
+
self.writeln("]));");
|
|
1386
1466
|
|
|
1387
|
-
self.writeln("let String = Value::
|
|
1467
|
+
self.writeln("let String = Value::object(ObjectMap::from([");
|
|
1388
1468
|
self.indent += 1;
|
|
1389
1469
|
self.writeln("(Arc::from(\"fromCharCode\"), Value::native(|args: &[Value]| tish_string_from_char_code(args))),");
|
|
1390
1470
|
self.indent -= 1;
|
|
1391
|
-
self.writeln("]))
|
|
1471
|
+
self.writeln("]));");
|
|
1392
1472
|
|
|
1393
|
-
self.writeln("let Date = Value::
|
|
1473
|
+
self.writeln("let Date = Value::object(ObjectMap::from([");
|
|
1394
1474
|
self.indent += 1;
|
|
1395
|
-
self.writeln(
|
|
1396
|
-
"(Arc::from(\"now\"), Value::native(|args: &[Value]| tish_date_now(args))),",
|
|
1397
|
-
);
|
|
1475
|
+
self.writeln("(Arc::from(\"now\"), Value::native(|args: &[Value]| tish_date_now(args))),");
|
|
1398
1476
|
self.indent -= 1;
|
|
1399
|
-
self.writeln("]))
|
|
1477
|
+
self.writeln("]));");
|
|
1400
1478
|
|
|
1401
|
-
self.writeln("let
|
|
1479
|
+
self.writeln("let Symbol = tish_symbol_object();");
|
|
1480
|
+
|
|
1481
|
+
self.writeln("let Object = Value::object(ObjectMap::from([");
|
|
1402
1482
|
self.indent += 1;
|
|
1403
|
-
self.writeln(
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
self.writeln(
|
|
1483
|
+
self.writeln(
|
|
1484
|
+
"(Arc::from(\"assign\"), Value::native(|args: &[Value]| tish_object_assign(args))),",
|
|
1485
|
+
);
|
|
1486
|
+
self.writeln(
|
|
1487
|
+
"(Arc::from(\"keys\"), Value::native(|args: &[Value]| tish_object_keys(args))),",
|
|
1488
|
+
);
|
|
1489
|
+
self.writeln(
|
|
1490
|
+
"(Arc::from(\"values\"), Value::native(|args: &[Value]| tish_object_values(args))),",
|
|
1491
|
+
);
|
|
1492
|
+
self.writeln(
|
|
1493
|
+
"(Arc::from(\"entries\"), Value::native(|args: &[Value]| tish_object_entries(args))),",
|
|
1494
|
+
);
|
|
1407
1495
|
self.writeln("(Arc::from(\"fromEntries\"), Value::native(|args: &[Value]| tish_object_from_entries(args))),");
|
|
1408
1496
|
self.indent -= 1;
|
|
1409
|
-
self.writeln("]))
|
|
1497
|
+
self.writeln("]));");
|
|
1410
1498
|
|
|
1411
1499
|
self.writeln("let Uint8Array = tish_uint8_array_constructor();");
|
|
1412
1500
|
self.writeln("let AudioContext = tish_audio_context_constructor();");
|
|
1501
|
+
if self.program_uses_document {
|
|
1502
|
+
self.writeln("let document = VmRef::new(tish_canvas_document());");
|
|
1503
|
+
self.refcell_wrapped_vars.insert("document".to_string());
|
|
1504
|
+
self.rc_cell_storage_define("document");
|
|
1505
|
+
if let Some(scope) = self.outer_vars_stack.last_mut() {
|
|
1506
|
+
scope.push("document".to_string());
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1413
1509
|
|
|
1414
1510
|
if self.has_feature("process") {
|
|
1415
|
-
self.writeln("let process = Value::
|
|
1511
|
+
self.writeln("let process = Value::object({");
|
|
1416
1512
|
self.indent += 1;
|
|
1417
1513
|
self.writeln("let mut p = ObjectMap::default();");
|
|
1418
1514
|
self.writeln("p.insert(Arc::from(\"exit\"), Value::native(|args: &[Value]| tish_process_exit(args)));");
|
|
1419
1515
|
self.writeln("p.insert(Arc::from(\"cwd\"), Value::native(|args: &[Value]| tish_process_cwd(args)));");
|
|
1420
1516
|
self.writeln("p.insert(Arc::from(\"exec\"), Value::native(|args: &[Value]| tish_process_exec(args)));");
|
|
1421
1517
|
self.writeln("let argv: Vec<Value> = std::env::args().map(|s| Value::String(s.into())).collect();");
|
|
1422
|
-
self.writeln(
|
|
1423
|
-
"p.insert(Arc::from(\"argv\"), Value::Array(VmRef::new(argv)));",
|
|
1424
|
-
);
|
|
1518
|
+
self.writeln("p.insert(Arc::from(\"argv\"), Value::Array(VmRef::new(argv)));");
|
|
1425
1519
|
self.writeln("let mut env_obj = ObjectMap::default();");
|
|
1426
1520
|
self.writeln("for (key, value) in std::env::vars() {");
|
|
1427
1521
|
self.indent += 1;
|
|
1428
1522
|
self.writeln("env_obj.insert(Arc::from(key.as_str()), Value::String(value.into()));");
|
|
1429
1523
|
self.indent -= 1;
|
|
1430
1524
|
self.writeln("}");
|
|
1431
|
-
self.writeln(
|
|
1432
|
-
"p.insert(Arc::from(\"env\"), Value::Object(VmRef::new(env_obj)));",
|
|
1433
|
-
);
|
|
1525
|
+
self.writeln("p.insert(Arc::from(\"env\"), Value::object(env_obj));");
|
|
1434
1526
|
self.writeln("p");
|
|
1435
1527
|
self.indent -= 1;
|
|
1436
|
-
self.writeln("})
|
|
1528
|
+
self.writeln("});");
|
|
1437
1529
|
}
|
|
1438
1530
|
|
|
1439
1531
|
if self.has_feature("timers") {
|
|
1440
|
-
self.writeln(
|
|
1532
|
+
self.writeln(
|
|
1533
|
+
"let setTimeout = Value::native(|args: &[Value]| tish_timer_set_timeout(args));",
|
|
1534
|
+
);
|
|
1441
1535
|
self.writeln("let clearTimeout = Value::native(|args: &[Value]| tish_timer_clear_timeout(args));");
|
|
1442
|
-
self.writeln(
|
|
1536
|
+
self.writeln(
|
|
1537
|
+
"let setInterval = Value::native(|args: &[Value]| tish_timer_set_interval(args));",
|
|
1538
|
+
);
|
|
1443
1539
|
self.writeln("let clearInterval = Value::native(|args: &[Value]| tish_timer_clear_interval(args));");
|
|
1444
1540
|
}
|
|
1445
1541
|
if self.has_feature("http") {
|
|
1446
|
-
self.writeln(
|
|
1542
|
+
self.writeln(
|
|
1543
|
+
"let fetch = Value::native(|args: &[Value]| tish_fetch_promise(args.to_vec()));",
|
|
1544
|
+
);
|
|
1447
1545
|
self.writeln("let fetchAll = Value::native(|args: &[Value]| tish_fetch_all_promise(args.to_vec()));");
|
|
1448
1546
|
if self.is_async {
|
|
1449
1547
|
self.writeln("let Promise = tish_promise_object();");
|
|
@@ -1461,10 +1559,12 @@ impl Codegen {
|
|
|
1461
1559
|
self.writeln("let handler = args.get(1).cloned().unwrap_or(Value::Null);");
|
|
1462
1560
|
self.writeln("match handler {");
|
|
1463
1561
|
self.indent += 1;
|
|
1464
|
-
self.writeln(
|
|
1562
|
+
self.writeln(
|
|
1563
|
+
"Value::Function(f) => tish_http_serve(args, move |req_args| f(req_args)),",
|
|
1564
|
+
);
|
|
1465
1565
|
self.writeln("Value::Object(ref opts) => {");
|
|
1466
1566
|
self.indent += 1;
|
|
1467
|
-
self.writeln("let factory = opts.borrow().get(
|
|
1567
|
+
self.writeln("let factory = opts.borrow().strings.get(\"onWorker\").cloned().unwrap_or(Value::Null);");
|
|
1468
1568
|
self.writeln("tishlang_runtime::http_serve_per_worker(args, factory)");
|
|
1469
1569
|
self.indent -= 1;
|
|
1470
1570
|
self.writeln("},");
|
|
@@ -1476,39 +1576,29 @@ impl Codegen {
|
|
|
1476
1576
|
}
|
|
1477
1577
|
|
|
1478
1578
|
if self.has_feature("fs") {
|
|
1579
|
+
self.writeln("let readFile = Value::native(|args: &[Value]| tish_read_file(args));");
|
|
1580
|
+
self.writeln("let writeFile = Value::native(|args: &[Value]| tish_write_file(args));");
|
|
1479
1581
|
self.writeln(
|
|
1480
|
-
"let
|
|
1481
|
-
);
|
|
1482
|
-
self.writeln(
|
|
1483
|
-
"let writeFile = Value::native(|args: &[Value]| tish_write_file(args));",
|
|
1484
|
-
);
|
|
1485
|
-
self.writeln("let fileExists = Value::native(|args: &[Value]| tish_file_exists(args));");
|
|
1486
|
-
self.writeln(
|
|
1487
|
-
"let isDir = Value::native(|args: &[Value]| tish_is_dir(args));",
|
|
1488
|
-
);
|
|
1489
|
-
self.writeln(
|
|
1490
|
-
"let readDir = Value::native(|args: &[Value]| tish_read_dir(args));",
|
|
1491
|
-
);
|
|
1492
|
-
self.writeln(
|
|
1493
|
-
"let mkdir = Value::native(|args: &[Value]| tish_mkdir(args));",
|
|
1582
|
+
"let fileExists = Value::native(|args: &[Value]| tish_file_exists(args));",
|
|
1494
1583
|
);
|
|
1584
|
+
self.writeln("let isDir = Value::native(|args: &[Value]| tish_is_dir(args));");
|
|
1585
|
+
self.writeln("let readDir = Value::native(|args: &[Value]| tish_read_dir(args));");
|
|
1586
|
+
self.writeln("let mkdir = Value::native(|args: &[Value]| tish_mkdir(args));");
|
|
1495
1587
|
}
|
|
1496
1588
|
|
|
1497
1589
|
if self.has_feature("regex") {
|
|
1498
|
-
self.writeln(
|
|
1499
|
-
"let RegExp = Value::native(|args: &[Value]| regexp_new(args));",
|
|
1500
|
-
);
|
|
1590
|
+
self.writeln("let RegExp = Value::native(|args: &[Value]| regexp_new(args));");
|
|
1501
1591
|
}
|
|
1502
1592
|
|
|
1503
|
-
if self.program_has_jsx {
|
|
1593
|
+
if self.program_has_jsx && !self.has_native_ui_host {
|
|
1504
1594
|
self.writeln("install_thread_local_host(Box::new(HeadlessHost::default()));");
|
|
1505
1595
|
self.writeln("let Fragment = fragment_value();");
|
|
1506
1596
|
self.writeln("let h = Value::native(|args: &[Value]| ui_h(args));");
|
|
1507
1597
|
self.writeln("let text = Value::native(|args: &[Value]| ui_text(args));");
|
|
1598
|
+
self.writeln("let useState = Value::native(|args: &[Value]| native_use_state(args));");
|
|
1508
1599
|
self.writeln(
|
|
1509
|
-
"let
|
|
1600
|
+
"let createRoot = Value::native(|args: &[Value]| native_create_root(args));",
|
|
1510
1601
|
);
|
|
1511
|
-
self.writeln("let createRoot = Value::native(|args: &[Value]| native_create_root(args));");
|
|
1512
1602
|
}
|
|
1513
1603
|
|
|
1514
1604
|
// Polars, Egui etc. are emitted via VarDecl from import { X } from 'tish:...'
|
|
@@ -1548,6 +1638,20 @@ impl Codegen {
|
|
|
1548
1638
|
self.writeln("Ok(())");
|
|
1549
1639
|
self.indent -= 1;
|
|
1550
1640
|
self.writeln("}");
|
|
1641
|
+
if self.emit_mode == crate::NativeEmitMode::EmbeddedLib {
|
|
1642
|
+
self.writeln("");
|
|
1643
|
+
self.writeln("#[no_mangle]");
|
|
1644
|
+
self.writeln("pub extern \"C\" fn tish_ios_launch() {");
|
|
1645
|
+
self.indent += 1;
|
|
1646
|
+
if self.is_async {
|
|
1647
|
+
self.writeln("let rt = tokio::runtime::Runtime::new().expect(\"tokio runtime\");");
|
|
1648
|
+
self.writeln("let _ = rt.block_on(run());");
|
|
1649
|
+
} else {
|
|
1650
|
+
self.writeln("let _ = run();");
|
|
1651
|
+
}
|
|
1652
|
+
self.indent -= 1;
|
|
1653
|
+
self.writeln("}");
|
|
1654
|
+
}
|
|
1551
1655
|
Ok(())
|
|
1552
1656
|
}
|
|
1553
1657
|
|
|
@@ -1622,10 +1726,7 @@ impl Codegen {
|
|
|
1622
1726
|
};
|
|
1623
1727
|
if self.refcell_wrapped_vars.contains(name.as_ref()) {
|
|
1624
1728
|
// Closure-mutated: same Rc<RefCell<T>> pattern as Value (assignments use borrow_mut)
|
|
1625
|
-
self.writeln(&format!(
|
|
1626
|
-
"let {} = VmRef::new({});",
|
|
1627
|
-
escaped_name, expr_str
|
|
1628
|
-
));
|
|
1729
|
+
self.writeln(&format!("let {} = VmRef::new({});", escaped_name, expr_str));
|
|
1629
1730
|
self.rc_cell_storage_define(name.as_ref());
|
|
1630
1731
|
} else {
|
|
1631
1732
|
let type_str = rust_type.to_rust_type_str();
|
|
@@ -1653,10 +1754,7 @@ impl Codegen {
|
|
|
1653
1754
|
} else {
|
|
1654
1755
|
expr_str.to_string()
|
|
1655
1756
|
};
|
|
1656
|
-
self.writeln(&format!(
|
|
1657
|
-
"let {} = VmRef::new({});",
|
|
1658
|
-
escaped_name, init_val
|
|
1659
|
-
));
|
|
1757
|
+
self.writeln(&format!("let {} = VmRef::new({});", escaped_name, init_val));
|
|
1660
1758
|
self.rc_cell_storage_define(name.as_ref());
|
|
1661
1759
|
} else if clone_needed {
|
|
1662
1760
|
self.writeln(&format!(
|
|
@@ -2036,6 +2134,7 @@ impl Codegen {
|
|
|
2036
2134
|
"setInterval",
|
|
2037
2135
|
"clearInterval",
|
|
2038
2136
|
"Promise",
|
|
2137
|
+
"Symbol",
|
|
2039
2138
|
"RegExp",
|
|
2040
2139
|
"Polars",
|
|
2041
2140
|
]
|
|
@@ -2136,6 +2235,7 @@ impl Codegen {
|
|
|
2136
2235
|
"setInterval",
|
|
2137
2236
|
"clearInterval",
|
|
2138
2237
|
"Promise",
|
|
2238
|
+
"Symbol",
|
|
2139
2239
|
"RegExp",
|
|
2140
2240
|
"Polars",
|
|
2141
2241
|
// Free-standing global functions used inside user-defined
|
|
@@ -2242,6 +2342,10 @@ impl Codegen {
|
|
|
2242
2342
|
for v in &mutable_outer_vars {
|
|
2243
2343
|
self.refcell_wrapped_vars.insert(v.clone());
|
|
2244
2344
|
}
|
|
2345
|
+
// Read-only captures are plain Value bindings inside the closure.
|
|
2346
|
+
for v in &read_only_outer_vars {
|
|
2347
|
+
self.refcell_wrapped_vars.remove(v);
|
|
2348
|
+
}
|
|
2245
2349
|
|
|
2246
2350
|
// Pre-scan body for nested functions (handles function body as Block)
|
|
2247
2351
|
if let Statement::Block { statements, .. } = body.as_ref() {
|
|
@@ -2409,7 +2513,7 @@ impl Codegen {
|
|
|
2409
2513
|
match &prop.value {
|
|
2410
2514
|
DestructElement::Ident(name, _) => {
|
|
2411
2515
|
self.writeln(&format!(
|
|
2412
|
-
"{} {} = match &({}) {{ Value::Object(ref _o) => _o.borrow().get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }};",
|
|
2516
|
+
"{} {} = match &({}) {{ Value::Object(ref _o) => _o.borrow().strings.get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }};",
|
|
2413
2517
|
mutability,
|
|
2414
2518
|
Self::escape_ident(name.as_ref()),
|
|
2415
2519
|
value_expr,
|
|
@@ -2419,7 +2523,7 @@ impl Codegen {
|
|
|
2419
2523
|
DestructElement::Pattern(nested) => {
|
|
2420
2524
|
let nested_var = format!("_nested_obj_{}", key);
|
|
2421
2525
|
self.writeln(&format!(
|
|
2422
|
-
"let {} = match &({}) {{ Value::Object(ref _o) => _o.borrow().get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }};",
|
|
2526
|
+
"let {} = match &({}) {{ Value::Object(ref _o) => _o.borrow().strings.get({:?}).cloned().unwrap_or(Value::Null), _ => Value::Null }};",
|
|
2423
2527
|
nested_var, value_expr, key
|
|
2424
2528
|
));
|
|
2425
2529
|
self.emit_destruct_bindings(nested, &nested_var, mutability, span)?;
|
|
@@ -2502,7 +2606,12 @@ impl Codegen {
|
|
|
2502
2606
|
// Convert native type to Value for compatibility with existing code
|
|
2503
2607
|
var_type.to_value_expr(&escaped)
|
|
2504
2608
|
} else {
|
|
2505
|
-
escaped.into_owned()
|
|
2609
|
+
let s = escaped.into_owned();
|
|
2610
|
+
if self.value_fn_depth > 0 || !self.loop_stack.is_empty() {
|
|
2611
|
+
format!("({}).clone()", s)
|
|
2612
|
+
} else {
|
|
2613
|
+
s
|
|
2614
|
+
}
|
|
2506
2615
|
}
|
|
2507
2616
|
}
|
|
2508
2617
|
}
|
|
@@ -2760,6 +2869,14 @@ impl Codegen {
|
|
|
2760
2869
|
obj_expr, start, end
|
|
2761
2870
|
));
|
|
2762
2871
|
}
|
|
2872
|
+
"substr" => {
|
|
2873
|
+
let start = arg_exprs.first().cloned().unwrap_or_else(|| "Value::Number(0.0)".to_string());
|
|
2874
|
+
let length = arg_exprs.get(1).cloned().unwrap_or_else(|| "Value::Null".to_string());
|
|
2875
|
+
return Ok(format!(
|
|
2876
|
+
"tishlang_runtime::string_substr(&{}, &{}, &{})",
|
|
2877
|
+
obj_expr, start, length
|
|
2878
|
+
));
|
|
2879
|
+
}
|
|
2763
2880
|
"split" => {
|
|
2764
2881
|
let sep = arg_exprs.first().cloned().unwrap_or_else(|| "Value::Null".to_string());
|
|
2765
2882
|
return Ok(format!(
|
|
@@ -2980,7 +3097,7 @@ impl Codegen {
|
|
|
2980
3097
|
if has_spread {
|
|
2981
3098
|
let args_code = self.emit_call_args(args)?;
|
|
2982
3099
|
return Ok(format!(
|
|
2983
|
-
"{{ let _callee =
|
|
3100
|
+
"{{ let _callee = ({}).clone(); let _spread_args = {}; tishlang_runtime::value_call(&_callee, _spread_args.as_slice()) }}",
|
|
2984
3101
|
callee_expr, args_code
|
|
2985
3102
|
));
|
|
2986
3103
|
}
|
|
@@ -2994,8 +3111,8 @@ impl Codegen {
|
|
|
2994
3111
|
.join(", ");
|
|
2995
3112
|
format!(
|
|
2996
3113
|
"({{\n\
|
|
2997
|
-
{} let _callee =
|
|
2998
|
-
{}
|
|
3114
|
+
{} let _callee = ({}).clone();\n\
|
|
3115
|
+
{} tishlang_runtime::value_call(&_callee, &[{}])\n\
|
|
2999
3116
|
{}}})",
|
|
3000
3117
|
" ".repeat(self.indent),
|
|
3001
3118
|
callee_expr,
|
|
@@ -3160,11 +3277,11 @@ impl Codegen {
|
|
|
3160
3277
|
}
|
|
3161
3278
|
ObjectProp::Spread(e) => {
|
|
3162
3279
|
let val = self.emit_expr(e)?;
|
|
3163
|
-
parts.push(format!("if let Value::Object(ref _spread) = {} {{ for (k, v) in _spread.borrow().iter() {{ _obj.insert(Arc::clone(k), v.clone()); }} }}", val));
|
|
3280
|
+
parts.push(format!("if let Value::Object(ref _spread) = {} {{ for (k, v) in _spread.borrow().strings.iter() {{ _obj.insert(Arc::clone(k), v.clone()); }} }}", val));
|
|
3164
3281
|
}
|
|
3165
3282
|
}
|
|
3166
3283
|
}
|
|
3167
|
-
format!("{{ let mut _obj: ObjectMap = ObjectMap::default(); {} Value::
|
|
3284
|
+
format!("{{ let mut _obj: ObjectMap = ObjectMap::default(); {} Value::object(_obj) }}", parts.join(" "))
|
|
3168
3285
|
} else {
|
|
3169
3286
|
let mut parts = Vec::new();
|
|
3170
3287
|
for prop in props {
|
|
@@ -3178,7 +3295,7 @@ impl Codegen {
|
|
|
3178
3295
|
}
|
|
3179
3296
|
}
|
|
3180
3297
|
format!(
|
|
3181
|
-
"Value::
|
|
3298
|
+
"Value::object(ObjectMap::from([{}]))",
|
|
3182
3299
|
parts.join(", ")
|
|
3183
3300
|
)
|
|
3184
3301
|
}
|
|
@@ -3274,7 +3391,8 @@ impl Codegen {
|
|
|
3274
3391
|
Value::Number(_) => \"number\".into(), Value::String(_) => \"string\".into(), \
|
|
3275
3392
|
Value::Bool(_) => \"boolean\".into(), Value::Null => \"null\".into(), \
|
|
3276
3393
|
Value::Array(_) => \"object\".into(), Value::Object(_) => \"object\".into(), \
|
|
3277
|
-
Value::Function(_) => \"function\".into(), _ => \"
|
|
3394
|
+
Value::Function(_) => \"function\".into(), Value::Symbol(_) => \"symbol\".into(), \
|
|
3395
|
+
_ => \"object\".into() }})",
|
|
3278
3396
|
o
|
|
3279
3397
|
)
|
|
3280
3398
|
}
|
|
@@ -3400,10 +3518,11 @@ impl Codegen {
|
|
|
3400
3518
|
CompoundOp::Div => "div",
|
|
3401
3519
|
CompoundOp::Mod => "modulo",
|
|
3402
3520
|
};
|
|
3521
|
+
let op_suffix = self.ops_result_suffix();
|
|
3403
3522
|
if is_refcell {
|
|
3404
3523
|
format!(
|
|
3405
|
-
"{{ let _lhs_v = (*{}.borrow()).clone(); let _rhs = ({}).clone(); let _new = tishlang_runtime::ops::{}(&_lhs_v, &_rhs)
|
|
3406
|
-
n, val, op_fn, n, n
|
|
3524
|
+
"{{ let _lhs_v = (*{}.borrow()).clone(); let _rhs = ({}).clone(); let _new = tishlang_runtime::ops::{}(&_lhs_v, &_rhs){}; *{}.borrow_mut() = _new; (*{}.borrow()).clone() }}",
|
|
3525
|
+
n, val, op_fn, op_suffix, n, n
|
|
3407
3526
|
)
|
|
3408
3527
|
} else if var_type.is_native() {
|
|
3409
3528
|
// Wrap native lhs as Value, run ops::, unbox result back to native
|
|
@@ -3411,13 +3530,13 @@ impl Codegen {
|
|
|
3411
3530
|
let result_native = var_type.from_value_expr("_result");
|
|
3412
3531
|
let n_as_value2 = var_type.to_value_expr(&n);
|
|
3413
3532
|
format!(
|
|
3414
|
-
"{{ let _lhs = {}; let _rhs = ({}).clone(); let _result = tishlang_runtime::ops::{}(&_lhs, &_rhs)
|
|
3415
|
-
n_as_value, val, op_fn, n, result_native, n_as_value2
|
|
3533
|
+
"{{ let _lhs = {}; let _rhs = ({}).clone(); let _result = tishlang_runtime::ops::{}(&_lhs, &_rhs){}; {} = {}; {} }}",
|
|
3534
|
+
n_as_value, val, op_fn, op_suffix, n, result_native, n_as_value2
|
|
3416
3535
|
)
|
|
3417
3536
|
} else {
|
|
3418
3537
|
format!(
|
|
3419
|
-
"{{ let _rhs = ({}).clone(); {} = tishlang_runtime::ops::{}(&{}, &_rhs)
|
|
3420
|
-
val, n, op_fn, n, n
|
|
3538
|
+
"{{ let _rhs = ({}).clone(); {} = tishlang_runtime::ops::{}(&{}, &_rhs){}; {}.clone() }}",
|
|
3539
|
+
val, n, op_fn, n, op_suffix, n
|
|
3421
3540
|
)
|
|
3422
3541
|
}
|
|
3423
3542
|
}
|
|
@@ -4606,6 +4725,7 @@ impl Codegen {
|
|
|
4606
4725
|
"setInterval",
|
|
4607
4726
|
"clearInterval",
|
|
4608
4727
|
"Promise",
|
|
4728
|
+
"Symbol",
|
|
4609
4729
|
"RegExp",
|
|
4610
4730
|
"Polars",
|
|
4611
4731
|
]
|
|
@@ -4679,6 +4799,7 @@ impl Codegen {
|
|
|
4679
4799
|
"setInterval",
|
|
4680
4800
|
"clearInterval",
|
|
4681
4801
|
"Promise",
|
|
4802
|
+
"Symbol",
|
|
4682
4803
|
"RegExp",
|
|
4683
4804
|
"Polars",
|
|
4684
4805
|
] {
|
|
@@ -4707,6 +4828,41 @@ impl Codegen {
|
|
|
4707
4828
|
));
|
|
4708
4829
|
}
|
|
4709
4830
|
|
|
4831
|
+
// Locals from an enclosing Value::native (e.g. captured helper fns) are not on
|
|
4832
|
+
// outer_vars_stack but must not move into multiple sibling closures.
|
|
4833
|
+
const BUILTINS: &[&str] = &[
|
|
4834
|
+
"Boolean", "console", "Math", "JSON", "Date", "Object", "process",
|
|
4835
|
+
"setTimeout", "clearTimeout", "setInterval", "clearInterval", "Promise",
|
|
4836
|
+
"Symbol", "RegExp", "Polars", "Infinity", "NaN", "serve",
|
|
4837
|
+
];
|
|
4838
|
+
let mut already_captured: HashSet<String> = outer_vars
|
|
4839
|
+
.iter()
|
|
4840
|
+
.chain(outer_params.iter())
|
|
4841
|
+
.chain(referenced_funcs.iter())
|
|
4842
|
+
.cloned()
|
|
4843
|
+
.collect();
|
|
4844
|
+
already_captured.extend(BUILTINS.iter().map(|s| s.to_string()));
|
|
4845
|
+
let implicit_env_captures: Vec<String> = if self.value_fn_depth > 0 {
|
|
4846
|
+
referenced
|
|
4847
|
+
.iter()
|
|
4848
|
+
.filter(|name| {
|
|
4849
|
+
!param_names.contains(name.as_str())
|
|
4850
|
+
&& !local_var_names.contains(name.as_str())
|
|
4851
|
+
&& !already_captured.contains(name.as_str())
|
|
4852
|
+
})
|
|
4853
|
+
.cloned()
|
|
4854
|
+
.collect()
|
|
4855
|
+
} else {
|
|
4856
|
+
Vec::new()
|
|
4857
|
+
};
|
|
4858
|
+
for name in &implicit_env_captures {
|
|
4859
|
+
let escaped = Self::escape_ident(name);
|
|
4860
|
+
code.push_str(&format!(
|
|
4861
|
+
" let {}_ref = VmRef::new({}.clone());\n",
|
|
4862
|
+
escaped, escaped
|
|
4863
|
+
));
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4710
4866
|
code.push_str(" Value::native(move |args: &[Value]| {\n");
|
|
4711
4867
|
self.value_fn_depth += 1;
|
|
4712
4868
|
|
|
@@ -4734,6 +4890,13 @@ impl Codegen {
|
|
|
4734
4890
|
var_escaped, var_escaped
|
|
4735
4891
|
));
|
|
4736
4892
|
}
|
|
4893
|
+
for name in &implicit_env_captures {
|
|
4894
|
+
let escaped = Self::escape_ident(name);
|
|
4895
|
+
code.push_str(&format!(
|
|
4896
|
+
" let {} = (*{}_ref.borrow()).clone();\n",
|
|
4897
|
+
escaped, escaped
|
|
4898
|
+
));
|
|
4899
|
+
}
|
|
4737
4900
|
|
|
4738
4901
|
// Make captured functions available
|
|
4739
4902
|
for func_name in &referenced_funcs {
|
|
@@ -4786,6 +4949,12 @@ impl Codegen {
|
|
|
4786
4949
|
for v in &cell_capture_outer_vars {
|
|
4787
4950
|
self.refcell_wrapped_vars.insert(v.clone());
|
|
4788
4951
|
}
|
|
4952
|
+
for v in &read_only_outer_vars {
|
|
4953
|
+
self.refcell_wrapped_vars.remove(v);
|
|
4954
|
+
}
|
|
4955
|
+
for v in &implicit_env_captures {
|
|
4956
|
+
self.refcell_wrapped_vars.remove(v);
|
|
4957
|
+
}
|
|
4789
4958
|
|
|
4790
4959
|
self.type_context.push_fun_param_scope(params, None);
|
|
4791
4960
|
|
|
@@ -4886,14 +5055,11 @@ impl Codegen {
|
|
|
4886
5055
|
// alias). Each property in source order is matched to a struct
|
|
4887
5056
|
// field; missing fields fall back to `default_value()` so the
|
|
4888
5057
|
// emit succeeds even on partial literals (rare, but harmless).
|
|
4889
|
-
if let (RustType::Named { name, fields }, Expr::Object { props, .. }) =
|
|
4890
|
-
(target_type, expr)
|
|
5058
|
+
if let (RustType::Named { name, fields }, Expr::Object { props, .. }) = (target_type, expr)
|
|
4891
5059
|
{
|
|
4892
5060
|
use std::collections::HashMap;
|
|
4893
|
-
let field_types: HashMap<&str, &RustType> =
|
|
4894
|
-
.iter()
|
|
4895
|
-
.map(|(k, t)| (k.as_ref(), t))
|
|
4896
|
-
.collect();
|
|
5061
|
+
let field_types: HashMap<&str, &RustType> =
|
|
5062
|
+
fields.iter().map(|(k, t)| (k.as_ref(), t)).collect();
|
|
4897
5063
|
let mut field_inits: HashMap<String, String> = HashMap::new();
|
|
4898
5064
|
let mut bail = false;
|
|
4899
5065
|
for prop in props {
|