@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
|
@@ -209,11 +209,11 @@ impl<'a> Parser<'a> {
|
|
|
209
209
|
let opened_with_brace = matches!(self.peek_kind(), Some(TokenKind::LBrace));
|
|
210
210
|
if opened_with_brace {
|
|
211
211
|
self.advance(); // {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
// After `{`, the lexer often emits `Indent` for the first indented line of the body.
|
|
213
|
+
// `parse_statement` treats a leading `Indent` as starting a *nested* indent-block, so
|
|
214
|
+
// without consuming this token we get `Block { Block { let ... } ; ... }` and the first
|
|
215
|
+
// `let`/`const` is scoped too narrowly (JS ReferenceError). This indent is layout for
|
|
216
|
+
// *this* brace block, not an inner block.
|
|
217
217
|
if matches!(self.peek_kind(), Some(TokenKind::Indent)) {
|
|
218
218
|
self.advance();
|
|
219
219
|
}
|
|
@@ -291,10 +291,7 @@ impl<'a> Parser<'a> {
|
|
|
291
291
|
start: name_tok.span.start,
|
|
292
292
|
end: name_tok.span.end,
|
|
293
293
|
};
|
|
294
|
-
let name = name_tok
|
|
295
|
-
.literal
|
|
296
|
-
.clone()
|
|
297
|
-
.ok_or("Expected identifier")?;
|
|
294
|
+
let name = name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
298
295
|
|
|
299
296
|
// Optional type annotation: `: Type`
|
|
300
297
|
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
@@ -348,10 +345,7 @@ impl<'a> Parser<'a> {
|
|
|
348
345
|
start: name_tok.span.start,
|
|
349
346
|
end: name_tok.span.end,
|
|
350
347
|
};
|
|
351
|
-
let name = name_tok
|
|
352
|
-
.literal
|
|
353
|
-
.clone()
|
|
354
|
-
.ok_or("Expected identifier")?;
|
|
348
|
+
let name = name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
355
349
|
elements.push(Some(DestructElement::Rest(name, name_span)));
|
|
356
350
|
break;
|
|
357
351
|
}
|
|
@@ -368,10 +362,7 @@ impl<'a> Parser<'a> {
|
|
|
368
362
|
start: name_tok.span.start,
|
|
369
363
|
end: name_tok.span.end,
|
|
370
364
|
};
|
|
371
|
-
let name = name_tok
|
|
372
|
-
.literal
|
|
373
|
-
.clone()
|
|
374
|
-
.ok_or("Expected identifier")?;
|
|
365
|
+
let name = name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
375
366
|
DestructElement::Ident(name, name_span)
|
|
376
367
|
}
|
|
377
368
|
_ => return Err("Expected identifier or pattern in destructuring".to_string()),
|
|
@@ -399,10 +390,7 @@ impl<'a> Parser<'a> {
|
|
|
399
390
|
start: key_tok.span.start,
|
|
400
391
|
end: key_tok.span.end,
|
|
401
392
|
};
|
|
402
|
-
let key = key_tok
|
|
403
|
-
.literal
|
|
404
|
-
.clone()
|
|
405
|
-
.ok_or("Expected identifier")?;
|
|
393
|
+
let key = key_tok.literal.clone().ok_or("Expected identifier")?;
|
|
406
394
|
|
|
407
395
|
let value = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
408
396
|
self.advance();
|
|
@@ -418,10 +406,7 @@ impl<'a> Parser<'a> {
|
|
|
418
406
|
start: name_tok.span.start,
|
|
419
407
|
end: name_tok.span.end,
|
|
420
408
|
};
|
|
421
|
-
let name = name_tok
|
|
422
|
-
.literal
|
|
423
|
-
.clone()
|
|
424
|
-
.ok_or("Expected identifier")?;
|
|
409
|
+
let name = name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
425
410
|
DestructElement::Ident(name, name_span)
|
|
426
411
|
}
|
|
427
412
|
_ => return Err("Expected identifier or pattern after ':'".to_string()),
|
|
@@ -474,10 +459,7 @@ impl<'a> Parser<'a> {
|
|
|
474
459
|
start: param_tok.span.start,
|
|
475
460
|
end: param_tok.span.end,
|
|
476
461
|
};
|
|
477
|
-
let param_name = param_tok
|
|
478
|
-
.literal
|
|
479
|
-
.clone()
|
|
480
|
-
.ok_or("Expected param name")?;
|
|
462
|
+
let param_name = param_tok.literal.clone().ok_or("Expected param name")?;
|
|
481
463
|
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
482
464
|
self.advance();
|
|
483
465
|
Some(self.parse_type_annotation()?)
|
|
@@ -549,11 +531,27 @@ impl<'a> Parser<'a> {
|
|
|
549
531
|
self.advance(); // {
|
|
550
532
|
let mut props = Vec::new();
|
|
551
533
|
while !matches!(self.peek_kind(), Some(TokenKind::RBrace)) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
534
|
+
// `for` is a keyword but a common method name (`Symbol.for`); allow it here.
|
|
535
|
+
let key: Arc<str> = match self.peek_kind() {
|
|
536
|
+
Some(TokenKind::Ident) => {
|
|
537
|
+
let tok = self.expect(TokenKind::Ident)?;
|
|
538
|
+
Arc::from(
|
|
539
|
+
tok.literal
|
|
540
|
+
.as_deref()
|
|
541
|
+
.ok_or("Expected property name")?,
|
|
542
|
+
)
|
|
543
|
+
}
|
|
544
|
+
Some(TokenKind::For) => {
|
|
545
|
+
self.advance();
|
|
546
|
+
Arc::from("for")
|
|
547
|
+
}
|
|
548
|
+
_ => {
|
|
549
|
+
return Err(format!(
|
|
550
|
+
"Expected Ident or `for` as object type property name, got {:?}",
|
|
551
|
+
self.peek_kind()
|
|
552
|
+
));
|
|
553
|
+
}
|
|
554
|
+
};
|
|
557
555
|
self.expect(TokenKind::Colon)?;
|
|
558
556
|
let typ = self.parse_type_annotation()?;
|
|
559
557
|
props.push((key, typ));
|
|
@@ -601,10 +599,7 @@ impl<'a> Parser<'a> {
|
|
|
601
599
|
start: name_tok.span.start,
|
|
602
600
|
end: name_tok.span.end,
|
|
603
601
|
};
|
|
604
|
-
let name = name_tok
|
|
605
|
-
.literal
|
|
606
|
-
.clone()
|
|
607
|
-
.ok_or("Expected function name")?;
|
|
602
|
+
let name = name_tok.literal.clone().ok_or("Expected function name")?;
|
|
608
603
|
self.expect(TokenKind::LParen)?;
|
|
609
604
|
let mut params = Vec::with_capacity(4);
|
|
610
605
|
let mut rest_param = None;
|
|
@@ -616,10 +611,7 @@ impl<'a> Parser<'a> {
|
|
|
616
611
|
start: rest_tok.span.start,
|
|
617
612
|
end: rest_tok.span.end,
|
|
618
613
|
};
|
|
619
|
-
let param_name = rest_tok
|
|
620
|
-
.literal
|
|
621
|
-
.clone()
|
|
622
|
-
.ok_or("Expected rest param name")?;
|
|
614
|
+
let param_name = rest_tok.literal.clone().ok_or("Expected rest param name")?;
|
|
623
615
|
// Optional type annotation for rest param
|
|
624
616
|
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
625
617
|
self.advance();
|
|
@@ -702,10 +694,7 @@ impl<'a> Parser<'a> {
|
|
|
702
694
|
start: name_tok.span.start,
|
|
703
695
|
end: name_tok.span.end,
|
|
704
696
|
};
|
|
705
|
-
let name = name_tok
|
|
706
|
-
.literal
|
|
707
|
-
.clone()
|
|
708
|
-
.ok_or("Expected type alias name")?;
|
|
697
|
+
let name = name_tok.literal.clone().ok_or("Expected type alias name")?;
|
|
709
698
|
self.expect(TokenKind::Assign)?;
|
|
710
699
|
let ty = self.parse_type_annotation()?;
|
|
711
700
|
Ok(Statement::TypeAlias {
|
|
@@ -747,10 +736,7 @@ impl<'a> Parser<'a> {
|
|
|
747
736
|
start: name_tok.span.start,
|
|
748
737
|
end: name_tok.span.end,
|
|
749
738
|
};
|
|
750
|
-
let name = name_tok
|
|
751
|
-
.literal
|
|
752
|
-
.clone()
|
|
753
|
-
.ok_or("Expected identifier")?;
|
|
739
|
+
let name = name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
754
740
|
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
755
741
|
self.advance();
|
|
756
742
|
Some(self.parse_type_annotation()?)
|
|
@@ -780,10 +766,7 @@ impl<'a> Parser<'a> {
|
|
|
780
766
|
start: name_tok.span.start,
|
|
781
767
|
end: name_tok.span.end,
|
|
782
768
|
};
|
|
783
|
-
let name = name_tok
|
|
784
|
-
.literal
|
|
785
|
-
.clone()
|
|
786
|
-
.ok_or("Expected function name")?;
|
|
769
|
+
let name = name_tok.literal.clone().ok_or("Expected function name")?;
|
|
787
770
|
self.expect(TokenKind::LParen)?;
|
|
788
771
|
let mut params = Vec::with_capacity(4);
|
|
789
772
|
let mut rest_param = None;
|
|
@@ -795,10 +778,7 @@ impl<'a> Parser<'a> {
|
|
|
795
778
|
start: rest_tok.span.start,
|
|
796
779
|
end: rest_tok.span.end,
|
|
797
780
|
};
|
|
798
|
-
let param_name = rest_tok
|
|
799
|
-
.literal
|
|
800
|
-
.clone()
|
|
801
|
-
.ok_or("Expected rest param name")?;
|
|
781
|
+
let param_name = rest_tok.literal.clone().ok_or("Expected rest param name")?;
|
|
802
782
|
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
803
783
|
self.advance();
|
|
804
784
|
Some(self.parse_type_annotation()?)
|
|
@@ -893,10 +873,7 @@ impl<'a> Parser<'a> {
|
|
|
893
873
|
start: for_name_tok.span.start,
|
|
894
874
|
end: for_name_tok.span.end,
|
|
895
875
|
};
|
|
896
|
-
let name = for_name_tok
|
|
897
|
-
.literal
|
|
898
|
-
.clone()
|
|
899
|
-
.ok_or("Expected identifier")?;
|
|
876
|
+
let name = for_name_tok.literal.clone().ok_or("Expected identifier")?;
|
|
900
877
|
if matches!(self.peek_kind(), Some(TokenKind::Of)) {
|
|
901
878
|
self.advance();
|
|
902
879
|
let iterable = self.parse_expr()?;
|
|
@@ -1186,10 +1163,7 @@ impl<'a> Parser<'a> {
|
|
|
1186
1163
|
start: def_tok.span.start,
|
|
1187
1164
|
end: def_tok.span.end,
|
|
1188
1165
|
};
|
|
1189
|
-
let name = def_tok
|
|
1190
|
-
.literal
|
|
1191
|
-
.clone()
|
|
1192
|
-
.ok_or("Expected identifier")?;
|
|
1166
|
+
let name = def_tok.literal.clone().ok_or("Expected identifier")?;
|
|
1193
1167
|
vec![ImportSpecifier::Default { name, name_span }]
|
|
1194
1168
|
} else {
|
|
1195
1169
|
return Err("Expected { }, * as name, or default import".to_string());
|
|
@@ -1271,7 +1245,9 @@ impl<'a> Parser<'a> {
|
|
|
1271
1245
|
// Member assignment: obj.prop = val
|
|
1272
1246
|
if let Expr::Member {
|
|
1273
1247
|
object,
|
|
1274
|
-
prop: MemberProp::Name {
|
|
1248
|
+
prop: MemberProp::Name {
|
|
1249
|
+
name: prop_name, ..
|
|
1250
|
+
},
|
|
1275
1251
|
..
|
|
1276
1252
|
} = &left
|
|
1277
1253
|
{
|
|
@@ -1510,10 +1486,7 @@ impl<'a> Parser<'a> {
|
|
|
1510
1486
|
let optional = kind == TokenKind::OptionalChain;
|
|
1511
1487
|
self.advance();
|
|
1512
1488
|
let prop_tok = self.expect_ident_or_type_member_name()?;
|
|
1513
|
-
let prop = prop_tok
|
|
1514
|
-
.literal
|
|
1515
|
-
.clone()
|
|
1516
|
-
.ok_or("Expected property name")?;
|
|
1489
|
+
let prop = prop_tok.literal.clone().ok_or("Expected property name")?;
|
|
1517
1490
|
let prop_span = Span {
|
|
1518
1491
|
start: prop_tok.span.start,
|
|
1519
1492
|
end: prop_tok.span.end,
|
|
@@ -1630,10 +1603,7 @@ impl<'a> Parser<'a> {
|
|
|
1630
1603
|
let optional = kind == TokenKind::OptionalChain;
|
|
1631
1604
|
self.advance();
|
|
1632
1605
|
let prop_tok = self.expect_ident_or_type_member_name()?;
|
|
1633
|
-
let prop = prop_tok
|
|
1634
|
-
.literal
|
|
1635
|
-
.clone()
|
|
1636
|
-
.ok_or("Expected property name")?;
|
|
1606
|
+
let prop = prop_tok.literal.clone().ok_or("Expected property name")?;
|
|
1637
1607
|
let prop_span = Span {
|
|
1638
1608
|
start: prop_tok.span.start,
|
|
1639
1609
|
end: prop_tok.span.end,
|
|
@@ -90,15 +90,9 @@ fn params_to_sql(values: &[JsonValue]) -> Result<Vec<Box<dyn ToSql + Sync + Send
|
|
|
90
90
|
} else if let Some(u) = n.as_u64() {
|
|
91
91
|
Box::new(u as i64)
|
|
92
92
|
} else if let Some(f) = n.as_f64() {
|
|
93
|
-
if f.fract() == 0.0
|
|
94
|
-
&& f >= i32::MIN as f64
|
|
95
|
-
&& f <= i32::MAX as f64
|
|
96
|
-
{
|
|
93
|
+
if f.fract() == 0.0 && f >= i32::MIN as f64 && f <= i32::MAX as f64 {
|
|
97
94
|
Box::new(f as i32)
|
|
98
|
-
} else if f.fract() == 0.0
|
|
99
|
-
&& f >= i64::MIN as f64
|
|
100
|
-
&& f <= i64::MAX as f64
|
|
101
|
-
{
|
|
95
|
+
} else if f.fract() == 0.0 && f >= i64::MIN as f64 && f <= i64::MAX as f64 {
|
|
102
96
|
Box::new(f as i64)
|
|
103
97
|
} else {
|
|
104
98
|
Box::new(f)
|
|
@@ -110,7 +104,9 @@ fn params_to_sql(values: &[JsonValue]) -> Result<Vec<Box<dyn ToSql + Sync + Send
|
|
|
110
104
|
}
|
|
111
105
|
}
|
|
112
106
|
JsonValue::String(s) => Box::new(s.clone()),
|
|
113
|
-
JsonValue::Array(_) | JsonValue::Object(_) =>
|
|
107
|
+
JsonValue::Array(_) | JsonValue::Object(_) => {
|
|
108
|
+
Box::new(tokio_postgres::types::Json(v.clone()))
|
|
109
|
+
}
|
|
114
110
|
};
|
|
115
111
|
out.push(b);
|
|
116
112
|
}
|
|
@@ -222,7 +218,7 @@ fn row_to_value_direct(row: &Row) -> tishlang_runtime::Value {
|
|
|
222
218
|
};
|
|
223
219
|
om.insert(key, v);
|
|
224
220
|
}
|
|
225
|
-
RtValue::
|
|
221
|
+
RtValue::object(om)
|
|
226
222
|
}
|
|
227
223
|
|
|
228
224
|
fn row_to_object(row: &Row) -> Result<JsonValue> {
|
|
@@ -378,8 +374,8 @@ pub struct PerWorkerClient {
|
|
|
378
374
|
impl PerWorkerClient {
|
|
379
375
|
/// Open a single direct connection (no pool).
|
|
380
376
|
pub async fn connect(connection_string: &str) -> Result<Self> {
|
|
381
|
-
let cfg =
|
|
382
|
-
.map_err(TishPgError::BadConnectionString)?;
|
|
377
|
+
let cfg =
|
|
378
|
+
parse_connection_string(connection_string).map_err(TishPgError::BadConnectionString)?;
|
|
383
379
|
let (client, connection) = cfg.connect(NoTls).await?;
|
|
384
380
|
let driver = tokio::spawn(async move {
|
|
385
381
|
if let Err(e) = connection.await {
|
|
@@ -530,13 +526,11 @@ mod tish_sync {
|
|
|
530
526
|
use super::*;
|
|
531
527
|
use once_cell::sync::Lazy;
|
|
532
528
|
use slab::Slab;
|
|
533
|
-
use std::sync::Mutex;
|
|
534
529
|
use tishlang_runtime::Value as TishValue;
|
|
535
530
|
use tokio::runtime::Runtime as TokioRuntime;
|
|
536
531
|
|
|
537
|
-
static RT: Lazy<TokioRuntime> =
|
|
538
|
-
TokioRuntime::new().expect("tish_pg: failed to build tokio runtime")
|
|
539
|
-
});
|
|
532
|
+
static RT: Lazy<TokioRuntime> =
|
|
533
|
+
Lazy::new(|| TokioRuntime::new().expect("tish_pg: failed to build tokio runtime"));
|
|
540
534
|
// `RwLock` (not `Mutex`) on the registries: hot path is read-only —
|
|
541
535
|
// every query does `get_client(id)` + `get_statement(id)`. Inserts
|
|
542
536
|
// happen once per `connect`/`prepare` at startup. With multiple HTTP
|
|
@@ -544,8 +538,7 @@ mod tish_sync {
|
|
|
544
538
|
// serialised every query through one global lock; `RwLock` lets all
|
|
545
539
|
// concurrent reads run lock-free against each other.
|
|
546
540
|
use std::sync::RwLock;
|
|
547
|
-
static CLIENTS: Lazy<RwLock<Slab<PerWorkerClient>>> =
|
|
548
|
-
Lazy::new(|| RwLock::new(Slab::new()));
|
|
541
|
+
static CLIENTS: Lazy<RwLock<Slab<PerWorkerClient>>> = Lazy::new(|| RwLock::new(Slab::new()));
|
|
549
542
|
static STATEMENTS: Lazy<RwLock<Slab<(usize, Statement)>>> =
|
|
550
543
|
Lazy::new(|| RwLock::new(Slab::new()));
|
|
551
544
|
|
|
@@ -609,12 +602,10 @@ mod tish_sync {
|
|
|
609
602
|
.map(JsonValue::Number)
|
|
610
603
|
.unwrap_or(JsonValue::Null),
|
|
611
604
|
TishValue::String(s) => JsonValue::String(s.to_string()),
|
|
612
|
-
TishValue::Array(a) =>
|
|
613
|
-
JsonValue::Array(a.borrow().iter().map(tish_to_json).collect())
|
|
614
|
-
}
|
|
605
|
+
TishValue::Array(a) => JsonValue::Array(a.borrow().iter().map(tish_to_json).collect()),
|
|
615
606
|
TishValue::Object(o) => {
|
|
616
607
|
let mut m = serde_json::Map::new();
|
|
617
|
-
for (k, v) in o.borrow().iter() {
|
|
608
|
+
for (k, v) in o.borrow().strings.iter() {
|
|
618
609
|
m.insert(k.to_string(), tish_to_json(v));
|
|
619
610
|
}
|
|
620
611
|
JsonValue::Object(m)
|
|
@@ -623,35 +614,35 @@ mod tish_sync {
|
|
|
623
614
|
}
|
|
624
615
|
}
|
|
625
616
|
|
|
626
|
-
fn json_to_tish(v: JsonValue) -> TishValue {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
}
|
|
617
|
+
// fn json_to_tish(v: JsonValue) -> TishValue {
|
|
618
|
+
// use std::cell::RefCell;
|
|
619
|
+
// use std::rc::Rc;
|
|
620
|
+
// use std::sync::Arc;
|
|
621
|
+
// use tishlang_runtime::ObjectMap;
|
|
622
|
+
// match v {
|
|
623
|
+
// JsonValue::Null => TishValue::Null,
|
|
624
|
+
// JsonValue::Bool(b) => TishValue::Bool(b),
|
|
625
|
+
// JsonValue::Number(n) => TishValue::Number(n.as_f64().unwrap_or(0.0)),
|
|
626
|
+
// JsonValue::String(s) => TishValue::String(s.into()),
|
|
627
|
+
// JsonValue::Array(a) => {
|
|
628
|
+
// let mut out = Vec::with_capacity(a.len());
|
|
629
|
+
// for item in a {
|
|
630
|
+
// out.push(json_to_tish(item));
|
|
631
|
+
// }
|
|
632
|
+
// TishValue::Array(VmRef::new(out))
|
|
633
|
+
// }
|
|
634
|
+
// JsonValue::Object(m) => {
|
|
635
|
+
// // Pre-allocate ObjectMap capacity so HashMap doesn't rehash
|
|
636
|
+
// // on every insert. Common TFB rows are 2 columns (id,
|
|
637
|
+
// // randomnumber or id, message).
|
|
638
|
+
// let mut om = ObjectMap::with_capacity(m.len());
|
|
639
|
+
// for (k, v) in m {
|
|
640
|
+
// om.insert(Arc::from(k), json_to_tish(v));
|
|
641
|
+
// }
|
|
642
|
+
// TishValue::object(om)
|
|
643
|
+
// }
|
|
644
|
+
// }
|
|
645
|
+
// }
|
|
655
646
|
|
|
656
647
|
fn tish_err(msg: impl Into<String>) -> TishValue {
|
|
657
648
|
use std::sync::Arc;
|
|
@@ -659,16 +650,14 @@ mod tish_sync {
|
|
|
659
650
|
let mut om = ObjectMap::with_capacity(2);
|
|
660
651
|
om.insert(Arc::from("error"), TishValue::String(msg.into().into()));
|
|
661
652
|
om.insert(Arc::from("ok"), TishValue::Bool(false));
|
|
662
|
-
TishValue::
|
|
653
|
+
TishValue::object(om)
|
|
663
654
|
}
|
|
664
655
|
|
|
665
|
-
fn rows_to_value(res: QueryResult) -> TishValue {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
))
|
|
671
|
-
}
|
|
656
|
+
// fn rows_to_value(res: QueryResult) -> TishValue {
|
|
657
|
+
// use std::cell::RefCell;
|
|
658
|
+
// use std::rc::Rc;
|
|
659
|
+
// TishValue::Array(VmRef::new(res.rows.into_iter().map(json_to_tish).collect()))
|
|
660
|
+
// }
|
|
672
661
|
|
|
673
662
|
/// `perWorkerClient(connection_string) -> client_handle` (blocking).
|
|
674
663
|
pub fn per_worker_client(args: &[TishValue]) -> TishValue {
|
|
@@ -682,7 +671,10 @@ mod tish_sync {
|
|
|
682
671
|
let id = g.insert(c);
|
|
683
672
|
TishValue::Number(id as f64)
|
|
684
673
|
}
|
|
685
|
-
Err(e) => tish_err(format!(
|
|
674
|
+
Err(e) => tish_err(format!(
|
|
675
|
+
"perWorkerClient: {}",
|
|
676
|
+
crate::format_tish_pg_error(&e)
|
|
677
|
+
)),
|
|
686
678
|
}
|
|
687
679
|
}
|
|
688
680
|
|
|
@@ -694,9 +686,8 @@ mod tish_sync {
|
|
|
694
686
|
let cs = match args.first() {
|
|
695
687
|
Some(TishValue::String(s)) => s.to_string(),
|
|
696
688
|
Some(TishValue::Object(obj)) => {
|
|
697
|
-
use std::sync::Arc;
|
|
698
689
|
let b = obj.borrow();
|
|
699
|
-
match b.get(
|
|
690
|
+
match b.strings.get("connectionString") {
|
|
700
691
|
Some(TishValue::String(s)) => s.to_string(),
|
|
701
692
|
_ => return tish_err("connect: options.connectionString missing"),
|
|
702
693
|
}
|
|
@@ -754,11 +745,7 @@ mod tish_sync {
|
|
|
754
745
|
return tish_err("queryPrepared: expected (client, stmt, params)");
|
|
755
746
|
};
|
|
756
747
|
let params = match args.get(2) {
|
|
757
|
-
Some(TishValue::Array(a)) => a
|
|
758
|
-
.borrow()
|
|
759
|
-
.iter()
|
|
760
|
-
.map(tish_to_json)
|
|
761
|
-
.collect::<Vec<_>>(),
|
|
748
|
+
Some(TishValue::Array(a)) => a.borrow().iter().map(tish_to_json).collect::<Vec<_>>(),
|
|
762
749
|
Some(TishValue::Null) | None => Vec::new(),
|
|
763
750
|
Some(v) => vec![tish_to_json(v)],
|
|
764
751
|
};
|
|
@@ -773,7 +760,10 @@ mod tish_sync {
|
|
|
773
760
|
// produces. Fewer allocations + interned column-name `Arc`s.
|
|
774
761
|
match block_on(client.query_prepared_to_values(&stmt, ¶ms)) {
|
|
775
762
|
Ok(rows) => TishValue::Array(VmRef::new(rows)),
|
|
776
|
-
Err(e) => tish_err(format!(
|
|
763
|
+
Err(e) => tish_err(format!(
|
|
764
|
+
"queryPrepared: {}",
|
|
765
|
+
crate::format_tish_pg_error(&e)
|
|
766
|
+
)),
|
|
777
767
|
}
|
|
778
768
|
}
|
|
779
769
|
|
|
@@ -895,10 +885,8 @@ mod tish_sync {
|
|
|
895
885
|
let rows = raw_client
|
|
896
886
|
.query("SELECT name FROM _tish_pg_migrations", &[])
|
|
897
887
|
.await?;
|
|
898
|
-
let already: std::collections::HashSet<String> =
|
|
899
|
-
.iter()
|
|
900
|
-
.map(|r| r.get::<_, String>(0))
|
|
901
|
-
.collect();
|
|
888
|
+
let already: std::collections::HashSet<String> =
|
|
889
|
+
rows.iter().map(|r| r.get::<_, String>(0)).collect();
|
|
902
890
|
|
|
903
891
|
let mut applied_now: Vec<String> = Vec::new();
|
|
904
892
|
for (name, path) in &files {
|
|
@@ -942,7 +930,7 @@ mod tish_sync {
|
|
|
942
930
|
let mut om = ObjectMap::with_capacity(2);
|
|
943
931
|
om.insert(Arc::from("ok"), TishValue::Bool(true));
|
|
944
932
|
om.insert(Arc::from("applied"), TishValue::Array(VmRef::new(applied)));
|
|
945
|
-
TishValue::
|
|
933
|
+
TishValue::object(om)
|
|
946
934
|
}
|
|
947
935
|
}
|
|
948
936
|
|