@tishlang/tish-lsp 2.43.8 → 3.0.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.
Files changed (35) hide show
  1. package/bin/tish-lsp +0 -0
  2. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/src/lib.rs +21 -0
  3. package/crates/tish/tests/fixtures/cargo_example_project/crates/demo-shim/tish.d.tish +4 -0
  4. package/crates/tish/tests/fixtures/cargo_example_project/src/main.tish +5 -1
  5. package/crates/tish/tests/regr_typed_externs.rs +59 -0
  6. package/crates/tish_builtins/src/globals.rs +27 -0
  7. package/crates/tish_compile/src/codegen.rs +1285 -116
  8. package/crates/tish_compile/src/resolve.rs +53 -7
  9. package/crates/tish_compile/src/schemes.rs +60 -5
  10. package/crates/tish_compile/src/types.rs +64 -32
  11. package/crates/tish_compile/tests/regr_556_param_name_collision.rs +40 -0
  12. package/crates/tish_compile/tests/regr_558_struct_array_write.rs +65 -0
  13. package/crates/tish_compile/tests/regr_558b_struct_field_read.rs +21 -0
  14. package/crates/tish_compile/tests/regr_558c_wrapped_struct_array.rs +64 -0
  15. package/crates/tish_compile/tests/regr_558d_native_vec_mutators.rs +156 -0
  16. package/crates/tish_compile/tests/regr_562_wrapped_struct_array_push.rs +50 -0
  17. package/crates/tish_compile/tests/regr_fixed_native_coercions.rs +69 -0
  18. package/crates/tish_compile/tests/regr_gba_struct_reflection.rs +106 -0
  19. package/crates/tish_compile/tests/regression/name_collision_lib.tish +6 -0
  20. package/crates/tish_compile/tests/regression/name_collision_main.tish +13 -0
  21. package/crates/tish_compile/tests/regression/struct_array_write.tish +22 -0
  22. package/crates/tish_compile/tests/regression/struct_field_return_read.tish +10 -0
  23. package/crates/tish_core/src/console_style.rs +4 -0
  24. package/crates/tish_core/src/json.rs +8 -0
  25. package/crates/tish_core/src/value.rs +123 -0
  26. package/crates/tish_lsp/Cargo.toml +1 -1
  27. package/crates/tish_runtime/src/lib.rs +1 -0
  28. package/crates/tish_runtime_gba/src/lib.rs +188 -4
  29. package/crates/tish_vm/src/vm.rs +48 -0
  30. package/package.json +1 -1
  31. package/platform/darwin-arm64/tish-lsp +0 -0
  32. package/platform/darwin-x64/tish-lsp +0 -0
  33. package/platform/linux-arm64/tish-lsp +0 -0
  34. package/platform/linux-x64/tish-lsp +0 -0
  35. package/platform/win32-x64/tish-lsp.exe +0 -0
package/bin/tish-lsp CHANGED
Binary file
@@ -10,3 +10,24 @@ pub fn greet(args: &[Value]) -> Value {
10
10
  };
11
11
  Value::String(Arc::from(format!("Hello, {}!", name)))
12
12
  }
13
+
14
+ /// Boxed shim kept for dynamic call sites (`Value::Function` dispatch / a spread call).
15
+ pub fn add(args: &[Value]) -> Value {
16
+ let a = match args.first() {
17
+ Some(Value::Number(n)) => *n,
18
+ _ => 0.0,
19
+ };
20
+ let b = match args.get(1) {
21
+ Some(Value::Number(n)) => *n,
22
+ _ => 0.0,
23
+ };
24
+ Value::Number(a + b)
25
+ }
26
+
27
+ /// Typed extern (`declare fn add(a: number, b: number): number` in `tish.d.tish`): the direct, unboxed
28
+ /// entry codegen calls as `demo_shim::add_typed(..)` when the args lower to the declared native types.
29
+ /// `number` lowers to `f64` on every native target (unlike `i32`, which is native only under
30
+ /// `--target gba`), so this direct call fires on the default desktop build too.
31
+ pub fn add_typed(a: f64, b: f64) -> f64 {
32
+ a + b
33
+ }
@@ -0,0 +1,4 @@
1
+ // Typed externs shipped by the `demo_shim` crate (auto-loaded from beside its source by codegen).
2
+ // Declares the native signatures of exports so a call lowers to a DIRECT `demo_shim::<name>_typed(..)`
3
+ // instead of the boxed `value_call` path — the consuming program never writes these declarations.
4
+ declare fn add(a: number, b: number): number
@@ -1,3 +1,7 @@
1
- import { greet } from 'cargo:demo_shim'
1
+ import { greet, add } from 'cargo:demo_shim'
2
2
 
3
3
  console.log(greet('from cargo'))
4
+
5
+ // `add` has a typed signature shipped in the crate's `tish.d.tish` (auto-loaded) — this call lowers
6
+ // to a direct `demo_shim::add_typed(2, 3)`, not the boxed namespace-object dispatch.
7
+ console.log(add(2, 3))
@@ -0,0 +1,59 @@
1
+ //! Typed externs (perf lever): a native `cargo:` import whose typed signature is shipped in the
2
+ //! crate's `tish.d.tish` (auto-loaded from beside the crate source) must lower a matching call to a
3
+ //! DIRECT `<crate>::<name>_typed(..)` — no `Value` boxing of the args, no `value_call` dispatch —
4
+ //! while a call with no typed signature keeps the boxed namespace path. Uses the in-repo
5
+ //! `tests/fixtures/cargo_example_project/` fixture: `demo_shim` exports `greet` (untyped, stays boxed)
6
+ //! and `add` (declared `add(a: i32, b: i32): i32` in `crates/demo-shim/tish.d.tish`).
7
+ //!
8
+ //! Covers the three branch pieces with no other coverage: the `tish.d.tish` auto-load
9
+ //! (`compile_project_full_emit`), `collect_extern_fns` pairing, and the direct-call emission.
10
+
11
+ use std::path::PathBuf;
12
+
13
+ use tishlang_compile::compile_project_full;
14
+
15
+ fn emit_fixture() -> String {
16
+ let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
17
+ let input_path = manifest_dir
18
+ .join("tests/fixtures/cargo_example_project/src/main.tish")
19
+ .canonicalize()
20
+ .expect("cargo_example_project test fixture");
21
+ let project_root = input_path.parent().map(|p| {
22
+ if p.file_name().and_then(|n| n.to_str()) == Some("src") {
23
+ p.parent().unwrap_or(p)
24
+ } else {
25
+ p
26
+ }
27
+ });
28
+ compile_project_full(&input_path, project_root, &[], true)
29
+ .expect("compile_project_full on the cargo example fixture")
30
+ .0
31
+ }
32
+
33
+ #[test]
34
+ fn declared_extern_call_lowers_to_a_direct_typed_call() {
35
+ let rust = emit_fixture();
36
+ // The `add(2, 3)` call (typed via the auto-loaded tish.d.tish) must be a direct call into the
37
+ // crate's `add_typed`, not a boxed dispatch through the namespace object.
38
+ assert!(
39
+ rust.contains("add_typed"),
40
+ "typed extern `add` must lower to a direct `demo_shim::add_typed(..)` call; \
41
+ the auto-loaded tish.d.tish declaration was not honored.\n{rust}"
42
+ );
43
+ // The direct call targets the backing crate.
44
+ assert!(
45
+ rust.contains("demo_shim :: add_typed") || rust.contains("demo_shim::add_typed"),
46
+ "the direct typed-extern call must target the `demo_shim` crate.\n{rust}"
47
+ );
48
+ }
49
+
50
+ #[test]
51
+ fn untyped_extern_call_stays_boxed() {
52
+ let rust = emit_fixture();
53
+ // `greet` has no typed signature (no tish.d.tish entry), so it must NOT gain a `_typed` call —
54
+ // it keeps the boxed namespace/`value_call` path. Guards against collect_extern_fns over-matching.
55
+ assert!(
56
+ !rust.contains("greet_typed"),
57
+ "untyped extern `greet` must stay boxed (no `greet_typed` direct call).\n{rust}"
58
+ );
59
+ }
@@ -354,12 +354,23 @@ pub fn object_keys(args: &[Value]) -> Value {
354
354
  .collect();
355
355
  Value::Array(VmRef::new(keys))
356
356
  }
357
+ // A by-reference boxed typed struct (GBA/portable): materialise it to its ordered object and
358
+ // enumerate that, so `Object.keys(s)` / `for (k in s)` (lowered to `for-of Object.keys`) see
359
+ // the field names instead of nothing. (JSON/display already materialise; this closes the
360
+ // reflection paths so the boxed struct is enumerable exactly like the object it stands for.)
361
+ #[cfg(feature = "portable")]
362
+ Some(Value::Struct(s)) => object_keys(&[s.borrow().tish_to_object()]),
357
363
  _ => Value::Array(VmRef::new(Vec::new())),
358
364
  }
359
365
  }
360
366
 
361
367
  /// Object.values(obj)
362
368
  pub fn object_values(args: &[Value]) -> Value {
369
+ // A boxed typed struct materialises to its ordered object first (see `object_keys`).
370
+ #[cfg(feature = "portable")]
371
+ if let Some(Value::Struct(s)) = args.first() {
372
+ return object_values(&[s.borrow().tish_to_object()]);
373
+ }
363
374
  if let Some(Value::Object(obj)) = args.first() {
364
375
  let obj_borrow = obj.borrow();
365
376
  let values: Vec<Value> = obj_borrow.strings.values().cloned().collect();
@@ -371,6 +382,11 @@ pub fn object_values(args: &[Value]) -> Value {
371
382
 
372
383
  /// Object.entries(obj)
373
384
  pub fn object_entries(args: &[Value]) -> Value {
385
+ // A boxed typed struct materialises to its ordered object first (see `object_keys`).
386
+ #[cfg(feature = "portable")]
387
+ if let Some(Value::Struct(s)) = args.first() {
388
+ return object_entries(&[s.borrow().tish_to_object()]);
389
+ }
374
390
  if let Some(Value::Object(obj)) = args.first() {
375
391
  let obj_borrow = obj.borrow();
376
392
  let entries: Vec<Value> = obj_borrow
@@ -407,6 +423,17 @@ pub fn object_assign(args: &[Value]) -> Value {
407
423
  target_mut.strings.reserve(additional_capacity);
408
424
 
409
425
  for source in args.iter().skip(1) {
426
+ // A boxed typed struct source materialises to its ordered object first (GBA/portable), so
427
+ // `Object.assign(t, s)` copies its fields instead of silently skipping it (see `object_keys`).
428
+ #[cfg(feature = "portable")]
429
+ let struct_obj;
430
+ #[cfg(feature = "portable")]
431
+ let source: &Value = if let Value::Struct(s) = source {
432
+ struct_obj = s.borrow().tish_to_object();
433
+ &struct_obj
434
+ } else {
435
+ source
436
+ };
410
437
  if let Value::Object(src) = source {
411
438
  let src_borrow = src.borrow();
412
439
  for (k, v) in src_borrow.strings.iter() {