@tishlang/tish 1.0.29 → 1.0.34
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/Cargo.toml +1 -0
- package/crates/js_to_tish/src/transform/expr.rs +15 -6
- package/crates/tish/Cargo.toml +1 -1
- package/crates/tish/src/main.rs +1 -1
- package/crates/tish/tests/integration_test.rs +4 -3
- package/crates/tish_ast/src/ast.rs +65 -2
- package/crates/tish_build_utils/src/lib.rs +10 -2
- package/crates/tish_builtins/src/construct.rs +177 -0
- package/crates/tish_builtins/src/globals.rs +3 -5
- package/crates/tish_builtins/src/helpers.rs +2 -3
- package/crates/tish_builtins/src/lib.rs +1 -0
- package/crates/tish_builtins/src/object.rs +3 -4
- package/crates/tish_bytecode/src/compiler.rs +85 -11
- package/crates/tish_bytecode/src/opcode.rs +7 -3
- package/crates/tish_compile/Cargo.toml +1 -0
- package/crates/tish_compile/src/codegen.rs +604 -106
- package/crates/tish_compile/src/infer.rs +236 -0
- package/crates/tish_compile/src/lib.rs +52 -5
- package/crates/tish_compile/src/types.rs +42 -5
- package/crates/tish_compile_js/Cargo.toml +1 -0
- package/crates/tish_compile_js/src/codegen.rs +38 -94
- package/crates/tish_compile_js/src/lib.rs +0 -1
- package/crates/tish_compile_js/src/tests_jsx.rs +68 -0
- package/crates/tish_core/Cargo.toml +4 -0
- package/crates/tish_core/src/console_style.rs +7 -1
- package/crates/tish_core/src/json.rs +1 -2
- package/crates/tish_core/src/macros.rs +2 -3
- package/crates/tish_core/src/value.rs +13 -5
- package/crates/tish_cranelift/src/lib.rs +6 -4
- package/crates/tish_cranelift/src/lower.rs +5 -3
- package/crates/tish_cranelift_runtime/src/lib.rs +4 -2
- package/crates/tish_eval/Cargo.toml +2 -0
- package/crates/tish_eval/src/eval.rs +172 -79
- package/crates/tish_eval/src/http.rs +3 -4
- package/crates/tish_eval/src/lib.rs +7 -0
- package/crates/tish_eval/src/regex.rs +3 -2
- package/crates/tish_eval/src/value.rs +11 -13
- package/crates/tish_eval/src/value_convert.rs +4 -8
- package/crates/tish_fmt/src/lib.rs +49 -10
- package/crates/tish_lexer/src/token.rs +2 -0
- package/crates/tish_lint/src/lib.rs +9 -0
- package/crates/tish_llvm/src/lib.rs +4 -4
- package/crates/tish_lsp/README.md +1 -1
- package/crates/tish_native/src/build.rs +16 -2
- package/crates/tish_native/src/lib.rs +10 -11
- package/crates/tish_opt/src/lib.rs +15 -0
- package/crates/tish_parser/src/lib.rs +101 -1
- package/crates/tish_parser/src/parser.rs +168 -51
- package/crates/tish_runtime/src/http.rs +4 -5
- package/crates/tish_runtime/src/http_fetch.rs +17 -10
- package/crates/tish_runtime/src/lib.rs +9 -2
- package/crates/tish_runtime/src/promise.rs +2 -3
- package/crates/tish_runtime/src/promise_io.rs +2 -3
- package/crates/tish_runtime/src/ws.rs +7 -7
- package/crates/tish_ui/Cargo.toml +17 -0
- package/crates/tish_ui/src/jsx.rs +390 -0
- package/crates/tish_ui/src/lib.rs +16 -0
- package/crates/tish_ui/src/runtime/hooks.rs +122 -0
- package/crates/tish_ui/src/runtime/mod.rs +173 -0
- package/crates/tish_vm/src/vm.rs +121 -27
- 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
- package/crates/tish_compile_js/src/js_intrinsics.rs +0 -82
|
@@ -53,9 +53,9 @@ macro_rules! binary_multi_op {
|
|
|
53
53
|
|
|
54
54
|
use tishlang_ast::{
|
|
55
55
|
ArrowBody, ArrayElement, BinOp, CallArg, CompoundOp, DestructElement, DestructPattern,
|
|
56
|
-
DestructProp, ExportDeclaration, Expr, ImportSpecifier, JsxAttrValue, JsxChild,
|
|
57
|
-
Literal, LogicalAssignOp, MemberProp, ObjectProp, Program, Span, Statement,
|
|
58
|
-
TypedParam, UnaryOp,
|
|
56
|
+
DestructProp, ExportDeclaration, Expr, FunParam, ImportSpecifier, JsxAttrValue, JsxChild,
|
|
57
|
+
JsxProp, Literal, LogicalAssignOp, MemberProp, ObjectProp, Program, Span, Statement,
|
|
58
|
+
TypeAnnotation, TypedParam, UnaryOp,
|
|
59
59
|
};
|
|
60
60
|
use tishlang_lexer::{Token, TokenKind};
|
|
61
61
|
|
|
@@ -363,6 +363,55 @@ impl<'a> Parser<'a> {
|
|
|
363
363
|
self.expect(TokenKind::RBrace)?;
|
|
364
364
|
Ok(DestructPattern::Object(props))
|
|
365
365
|
}
|
|
366
|
+
|
|
367
|
+
/// One formal parameter: `name`, `name: T`, `name = expr`, or a destructuring pattern.
|
|
368
|
+
fn parse_fun_param(&mut self) -> Result<FunParam, String> {
|
|
369
|
+
if matches!(
|
|
370
|
+
self.peek_kind(),
|
|
371
|
+
Some(TokenKind::LBracket | TokenKind::LBrace)
|
|
372
|
+
) {
|
|
373
|
+
let pattern = self.parse_destruct_pattern()?;
|
|
374
|
+
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
375
|
+
self.advance();
|
|
376
|
+
Some(self.parse_type_annotation()?)
|
|
377
|
+
} else {
|
|
378
|
+
None
|
|
379
|
+
};
|
|
380
|
+
let default = if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
|
|
381
|
+
self.advance();
|
|
382
|
+
Some(self.parse_expr()?)
|
|
383
|
+
} else {
|
|
384
|
+
None
|
|
385
|
+
};
|
|
386
|
+
return Ok(FunParam::Destructure {
|
|
387
|
+
pattern,
|
|
388
|
+
type_ann,
|
|
389
|
+
default,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
let param_name = self
|
|
393
|
+
.expect(TokenKind::Ident)?
|
|
394
|
+
.literal
|
|
395
|
+
.clone()
|
|
396
|
+
.ok_or("Expected param name")?;
|
|
397
|
+
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
398
|
+
self.advance();
|
|
399
|
+
Some(self.parse_type_annotation()?)
|
|
400
|
+
} else {
|
|
401
|
+
None
|
|
402
|
+
};
|
|
403
|
+
let default = if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
|
|
404
|
+
self.advance();
|
|
405
|
+
Some(self.parse_expr()?)
|
|
406
|
+
} else {
|
|
407
|
+
None
|
|
408
|
+
};
|
|
409
|
+
Ok(FunParam::Simple(TypedParam {
|
|
410
|
+
name: param_name,
|
|
411
|
+
type_ann,
|
|
412
|
+
default,
|
|
413
|
+
}))
|
|
414
|
+
}
|
|
366
415
|
|
|
367
416
|
/// Parse a type annotation (number, string, T[], {a: T}, etc.)
|
|
368
417
|
fn parse_type_annotation(&mut self) -> Result<TypeAnnotation, String> {
|
|
@@ -480,26 +529,7 @@ impl<'a> Parser<'a> {
|
|
|
480
529
|
}
|
|
481
530
|
break;
|
|
482
531
|
}
|
|
483
|
-
|
|
484
|
-
.expect(TokenKind::Ident)?
|
|
485
|
-
.literal
|
|
486
|
-
.clone()
|
|
487
|
-
.ok_or("Expected param name")?;
|
|
488
|
-
// Optional type annotation
|
|
489
|
-
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
490
|
-
self.advance();
|
|
491
|
-
Some(self.parse_type_annotation()?)
|
|
492
|
-
} else {
|
|
493
|
-
None
|
|
494
|
-
};
|
|
495
|
-
// Optional default value
|
|
496
|
-
let default = if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
|
|
497
|
-
self.advance();
|
|
498
|
-
Some(self.parse_expr()?)
|
|
499
|
-
} else {
|
|
500
|
-
None
|
|
501
|
-
};
|
|
502
|
-
params.push(TypedParam { name: param_name, type_ann, default });
|
|
532
|
+
params.push(self.parse_fun_param()?);
|
|
503
533
|
if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
504
534
|
self.expect(TokenKind::Comma)?;
|
|
505
535
|
}
|
|
@@ -597,6 +627,12 @@ impl<'a> Parser<'a> {
|
|
|
597
627
|
span: self.span_end(span_start),
|
|
598
628
|
});
|
|
599
629
|
}
|
|
630
|
+
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
631
|
+
self.advance();
|
|
632
|
+
Some(self.parse_type_annotation()?)
|
|
633
|
+
} else {
|
|
634
|
+
None
|
|
635
|
+
};
|
|
600
636
|
let init_expr = if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
|
|
601
637
|
self.advance();
|
|
602
638
|
Some(self.parse_expr()?)
|
|
@@ -609,7 +645,7 @@ impl<'a> Parser<'a> {
|
|
|
609
645
|
Some(Box::new(Statement::VarDecl {
|
|
610
646
|
name,
|
|
611
647
|
mutable,
|
|
612
|
-
type_ann
|
|
648
|
+
type_ann,
|
|
613
649
|
init: init_expr,
|
|
614
650
|
span: self.span_end(var_span_start),
|
|
615
651
|
}))
|
|
@@ -1117,8 +1153,97 @@ impl<'a> Parser<'a> {
|
|
|
1117
1153
|
})
|
|
1118
1154
|
}
|
|
1119
1155
|
|
|
1120
|
-
|
|
1156
|
+
/// Member chain (`.`, `?.`, `[]`) without consuming a call `(...)`.
|
|
1157
|
+
fn parse_member_expression_no_call(&mut self) -> Result<Expr, String> {
|
|
1121
1158
|
let mut expr = self.parse_primary()?;
|
|
1159
|
+
while let Some(kind) = self.peek_kind() {
|
|
1160
|
+
match kind {
|
|
1161
|
+
TokenKind::Dot | TokenKind::OptionalChain => {
|
|
1162
|
+
let optional = kind == TokenKind::OptionalChain;
|
|
1163
|
+
self.advance();
|
|
1164
|
+
let prop = self
|
|
1165
|
+
.expect(TokenKind::Ident)?
|
|
1166
|
+
.literal
|
|
1167
|
+
.clone()
|
|
1168
|
+
.ok_or("Expected property name")?;
|
|
1169
|
+
let start = expr.span().start;
|
|
1170
|
+
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1171
|
+
expr = Expr::Member {
|
|
1172
|
+
object: Box::new(expr),
|
|
1173
|
+
prop: MemberProp::Name(prop),
|
|
1174
|
+
optional,
|
|
1175
|
+
span: Span { start, end },
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
TokenKind::LBracket => {
|
|
1179
|
+
self.advance();
|
|
1180
|
+
let index = self.parse_expr()?;
|
|
1181
|
+
self.expect(TokenKind::RBracket)?;
|
|
1182
|
+
let start = expr.span().start;
|
|
1183
|
+
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1184
|
+
expr = Expr::Index {
|
|
1185
|
+
object: Box::new(expr),
|
|
1186
|
+
index: Box::new(index),
|
|
1187
|
+
optional: false,
|
|
1188
|
+
span: Span { start, end },
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
_ => break,
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
Ok(expr)
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
/// ECMAScript `NewExpression`: `new` chains, then member expression without call, optional `(...)`.
|
|
1198
|
+
fn parse_new_expression(&mut self) -> Result<Expr, String> {
|
|
1199
|
+
if matches!(self.peek_kind(), Some(TokenKind::New)) {
|
|
1200
|
+
let span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
|
|
1201
|
+
self.advance();
|
|
1202
|
+
let callee = Box::new(self.parse_new_expression()?);
|
|
1203
|
+
let args = if matches!(self.peek_kind(), Some(TokenKind::LParen)) {
|
|
1204
|
+
self.advance();
|
|
1205
|
+
let mut args = Vec::new();
|
|
1206
|
+
while !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1207
|
+
if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
|
|
1208
|
+
self.advance();
|
|
1209
|
+
let arg_expr = self.parse_expr()?;
|
|
1210
|
+
args.push(CallArg::Spread(arg_expr));
|
|
1211
|
+
} else {
|
|
1212
|
+
let arg_expr = self.parse_expr()?;
|
|
1213
|
+
args.push(CallArg::Expr(arg_expr));
|
|
1214
|
+
}
|
|
1215
|
+
if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1216
|
+
self.expect(TokenKind::Comma)?;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
self.expect(TokenKind::RParen)?;
|
|
1220
|
+
args
|
|
1221
|
+
} else {
|
|
1222
|
+
Vec::new()
|
|
1223
|
+
};
|
|
1224
|
+
let end = self
|
|
1225
|
+
.peek()
|
|
1226
|
+
.map(|x| x.span.start)
|
|
1227
|
+
.unwrap_or(callee.as_ref().span().end);
|
|
1228
|
+
Ok(Expr::New {
|
|
1229
|
+
callee,
|
|
1230
|
+
args,
|
|
1231
|
+
span: Span {
|
|
1232
|
+
start: span_start,
|
|
1233
|
+
end,
|
|
1234
|
+
},
|
|
1235
|
+
})
|
|
1236
|
+
} else {
|
|
1237
|
+
self.parse_member_expression_no_call()
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
fn parse_postfix(&mut self) -> Result<Expr, String> {
|
|
1242
|
+
let mut expr = if matches!(self.peek_kind(), Some(TokenKind::New)) {
|
|
1243
|
+
self.parse_new_expression()?
|
|
1244
|
+
} else {
|
|
1245
|
+
self.parse_primary()?
|
|
1246
|
+
};
|
|
1122
1247
|
while let Some(kind) = self.peek_kind() {
|
|
1123
1248
|
match kind {
|
|
1124
1249
|
TokenKind::LParen => {
|
|
@@ -1243,7 +1368,11 @@ impl<'a> Parser<'a> {
|
|
|
1243
1368
|
let body = self.parse_arrow_body()?;
|
|
1244
1369
|
let end = self.previous_span_end();
|
|
1245
1370
|
return Ok(Expr::ArrowFunction {
|
|
1246
|
-
params: vec![TypedParam {
|
|
1371
|
+
params: vec![FunParam::Simple(TypedParam {
|
|
1372
|
+
name: name.clone(),
|
|
1373
|
+
type_ann: None,
|
|
1374
|
+
default: None,
|
|
1375
|
+
})],
|
|
1247
1376
|
body,
|
|
1248
1377
|
span: Span { start: span.start, end },
|
|
1249
1378
|
});
|
|
@@ -1418,39 +1547,26 @@ impl<'a> Parser<'a> {
|
|
|
1418
1547
|
is_arrow = true;
|
|
1419
1548
|
}
|
|
1420
1549
|
} else {
|
|
1421
|
-
// Try to parse params: (x, y,
|
|
1550
|
+
// Try to parse params: (x, y), ({ a }), ([a, b]), with optional types/defaults
|
|
1551
|
+
let mut params_ok = true;
|
|
1422
1552
|
loop {
|
|
1423
|
-
if
|
|
1424
|
-
break;
|
|
1553
|
+
if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1554
|
+
break;
|
|
1555
|
+
}
|
|
1556
|
+
match self.parse_fun_param() {
|
|
1557
|
+
Ok(param) => params.push(param),
|
|
1558
|
+
Err(_) => {
|
|
1559
|
+
params_ok = false;
|
|
1560
|
+
break;
|
|
1561
|
+
}
|
|
1425
1562
|
}
|
|
1426
|
-
let name = self.advance().unwrap().literal.clone().ok_or("Expected param name")?;
|
|
1427
|
-
|
|
1428
|
-
// Optional type annotation
|
|
1429
|
-
let type_ann = if matches!(self.peek_kind(), Some(TokenKind::Colon)) {
|
|
1430
|
-
self.advance();
|
|
1431
|
-
Some(self.parse_type_annotation()?)
|
|
1432
|
-
} else {
|
|
1433
|
-
None
|
|
1434
|
-
};
|
|
1435
|
-
|
|
1436
|
-
// Optional default value
|
|
1437
|
-
let default = if matches!(self.peek_kind(), Some(TokenKind::Assign)) {
|
|
1438
|
-
self.advance();
|
|
1439
|
-
Some(self.parse_expr()?)
|
|
1440
|
-
} else {
|
|
1441
|
-
None
|
|
1442
|
-
};
|
|
1443
|
-
|
|
1444
|
-
params.push(TypedParam { name, type_ann, default });
|
|
1445
|
-
|
|
1446
1563
|
if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
|
|
1447
1564
|
self.advance();
|
|
1448
1565
|
} else {
|
|
1449
1566
|
break;
|
|
1450
1567
|
}
|
|
1451
1568
|
}
|
|
1452
|
-
|
|
1453
|
-
if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1569
|
+
if params_ok && matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1454
1570
|
self.advance(); // consume )
|
|
1455
1571
|
if matches!(self.peek_kind(), Some(TokenKind::Arrow)) {
|
|
1456
1572
|
self.advance(); // consume =>
|
|
@@ -1787,6 +1903,7 @@ impl ExprSpan for Expr {
|
|
|
1787
1903
|
Expr::Binary { span, .. } => *span,
|
|
1788
1904
|
Expr::Unary { span, .. } => *span,
|
|
1789
1905
|
Expr::Call { span, .. } => *span,
|
|
1906
|
+
Expr::New { span, .. } => *span,
|
|
1790
1907
|
Expr::Member { span, .. } => *span,
|
|
1791
1908
|
Expr::Index { span, .. } => *span,
|
|
1792
1909
|
Expr::Conditional { span, .. } => *span,
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
//! HTTP server + shared request parsing. Client `fetch` lives in `http_fetch.rs`.
|
|
2
2
|
|
|
3
3
|
use std::cell::RefCell;
|
|
4
|
-
use std::collections::HashMap;
|
|
5
4
|
use std::fs::File;
|
|
6
5
|
use std::io::Write;
|
|
7
6
|
use std::rc::Rc;
|
|
8
7
|
use std::sync::Arc;
|
|
9
|
-
use tishlang_core::Value;
|
|
8
|
+
use tishlang_core::{ObjectMap, Value};
|
|
10
9
|
use tokio::runtime::Runtime;
|
|
11
10
|
|
|
12
11
|
thread_local! {
|
|
@@ -80,7 +79,7 @@ pub(crate) fn extract_body(options: Option<&Value>) -> Option<String> {
|
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
pub(crate) fn build_error_response(error: &str) -> Value {
|
|
83
|
-
let mut obj:
|
|
82
|
+
let mut obj: ObjectMap = ObjectMap::with_capacity(2);
|
|
84
83
|
obj.insert(Arc::from("error"), Value::String(error.into()));
|
|
85
84
|
obj.insert(Arc::from("ok"), Value::Bool(false));
|
|
86
85
|
Value::Object(Rc::new(RefCell::new(obj)))
|
|
@@ -147,7 +146,7 @@ pub fn create_server(port: u16) -> Result<tiny_http::Server, String> {
|
|
|
147
146
|
}
|
|
148
147
|
|
|
149
148
|
pub fn request_to_value(request: &mut tiny_http::Request) -> Value {
|
|
150
|
-
let mut obj:
|
|
149
|
+
let mut obj: ObjectMap = ObjectMap::with_capacity(6);
|
|
151
150
|
|
|
152
151
|
obj.insert(
|
|
153
152
|
Arc::from("method"),
|
|
@@ -164,7 +163,7 @@ pub fn request_to_value(request: &mut tiny_http::Request) -> Value {
|
|
|
164
163
|
let query_string = request.url().split('?').nth(1).unwrap_or("");
|
|
165
164
|
obj.insert(Arc::from("query"), Value::String(query_string.into()));
|
|
166
165
|
|
|
167
|
-
let mut headers_obj:
|
|
166
|
+
let mut headers_obj: ObjectMap = ObjectMap::with_capacity(request.headers().len());
|
|
168
167
|
for header in request.headers() {
|
|
169
168
|
headers_obj.insert(
|
|
170
169
|
Arc::from(header.field.as_str().as_str()),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
//! Web Fetch–aligned Response, ReadableStream, reader.read(), text()/json().
|
|
2
2
|
|
|
3
3
|
use std::cell::RefCell;
|
|
4
|
-
use std::collections::HashMap;
|
|
5
4
|
use std::pin::Pin;
|
|
6
5
|
use std::rc::Rc;
|
|
7
6
|
use std::sync::{Arc, Mutex};
|
|
@@ -9,7 +8,7 @@ use std::sync::{Arc, Mutex};
|
|
|
9
8
|
use bytes::Bytes;
|
|
10
9
|
use futures::Stream;
|
|
11
10
|
use futures::StreamExt;
|
|
12
|
-
use tishlang_core::{NativeFn, TishOpaque, TishPromise, Value};
|
|
11
|
+
use tishlang_core::{NativeFn, ObjectMap, TishOpaque, TishPromise, Value};
|
|
13
12
|
|
|
14
13
|
use crate::http::{build_error_response, extract_body, extract_headers, extract_method};
|
|
15
14
|
|
|
@@ -77,14 +76,14 @@ impl TishPromise for ReadChunkPromise {
|
|
|
77
76
|
let r = crate::http::block_on_http(rx);
|
|
78
77
|
match r {
|
|
79
78
|
Ok(Ok(ReadChunk::Done)) => {
|
|
80
|
-
let mut o =
|
|
79
|
+
let mut o = ObjectMap::default();
|
|
81
80
|
o.insert(Arc::from("done"), Value::Bool(true));
|
|
82
81
|
o.insert(Arc::from("value"), Value::Null);
|
|
83
82
|
Ok(Value::Object(Rc::new(RefCell::new(o))))
|
|
84
83
|
}
|
|
85
84
|
Ok(Ok(ReadChunk::Bytes(b))) => {
|
|
86
85
|
let arr: Vec<Value> = b.iter().map(|u| Value::Number(*u as f64)).collect();
|
|
87
|
-
let mut o =
|
|
86
|
+
let mut o = ObjectMap::default();
|
|
88
87
|
o.insert(Arc::from("done"), Value::Bool(false));
|
|
89
88
|
o.insert(
|
|
90
89
|
Arc::from("value"),
|
|
@@ -93,7 +92,7 @@ impl TishPromise for ReadChunkPromise {
|
|
|
93
92
|
Ok(Value::Object(Rc::new(RefCell::new(o))))
|
|
94
93
|
}
|
|
95
94
|
Ok(Err(e)) => Err({
|
|
96
|
-
let mut obj =
|
|
95
|
+
let mut obj = ObjectMap::default();
|
|
97
96
|
obj.insert(Arc::from("error"), Value::String(e.into()));
|
|
98
97
|
Value::Object(Rc::new(RefCell::new(obj)))
|
|
99
98
|
}),
|
|
@@ -118,13 +117,13 @@ impl TishPromise for JsonTextPromise {
|
|
|
118
117
|
Ok(Ok(s)) => match tishlang_core::json_parse(&s) {
|
|
119
118
|
Ok(v) => Ok(v),
|
|
120
119
|
Err(e) => Err({
|
|
121
|
-
let mut obj =
|
|
120
|
+
let mut obj = ObjectMap::default();
|
|
122
121
|
obj.insert(Arc::from("error"), Value::String(e.into()));
|
|
123
122
|
Value::Object(Rc::new(RefCell::new(obj)))
|
|
124
123
|
}),
|
|
125
124
|
},
|
|
126
125
|
Ok(Err(e)) => Err({
|
|
127
|
-
let mut obj =
|
|
126
|
+
let mut obj = ObjectMap::default();
|
|
128
127
|
obj.insert(Arc::from("error"), Value::String(e.into()));
|
|
129
128
|
Value::Object(Rc::new(RefCell::new(obj)))
|
|
130
129
|
}),
|
|
@@ -212,6 +211,10 @@ impl TishOpaque for HttpReadableStream {
|
|
|
212
211
|
"ReadableStream"
|
|
213
212
|
}
|
|
214
213
|
|
|
214
|
+
fn as_any(&self) -> &dyn std::any::Any {
|
|
215
|
+
self
|
|
216
|
+
}
|
|
217
|
+
|
|
215
218
|
fn get_method(&self, name: &str) -> Option<NativeFn> {
|
|
216
219
|
if name != "getReader" {
|
|
217
220
|
return None;
|
|
@@ -226,7 +229,7 @@ impl TishOpaque for HttpReadableStream {
|
|
|
226
229
|
}))
|
|
227
230
|
}
|
|
228
231
|
Err(e) => {
|
|
229
|
-
let mut m =
|
|
232
|
+
let mut m = ObjectMap::default();
|
|
230
233
|
m.insert(Arc::from("error"), Value::String(e.into()));
|
|
231
234
|
Value::Object(Rc::new(RefCell::new(m)))
|
|
232
235
|
}
|
|
@@ -248,6 +251,10 @@ impl TishOpaque for HttpStreamReader {
|
|
|
248
251
|
"ReadableStreamDefaultReader"
|
|
249
252
|
}
|
|
250
253
|
|
|
254
|
+
fn as_any(&self) -> &dyn std::any::Any {
|
|
255
|
+
self
|
|
256
|
+
}
|
|
257
|
+
|
|
251
258
|
fn get_method(&self, name: &str) -> Option<NativeFn> {
|
|
252
259
|
if name != "read" {
|
|
253
260
|
return None;
|
|
@@ -283,7 +290,7 @@ impl TishOpaque for HttpStreamReader {
|
|
|
283
290
|
}
|
|
284
291
|
|
|
285
292
|
fn headers_to_value(headers: &reqwest::header::HeaderMap) -> Value {
|
|
286
|
-
let mut headers_obj:
|
|
293
|
+
let mut headers_obj: ObjectMap = ObjectMap::with_capacity(headers.len());
|
|
287
294
|
for (key, value) in headers.iter() {
|
|
288
295
|
if let Ok(v) = value.to_str() {
|
|
289
296
|
headers_obj.insert(Arc::from(key.as_str()), Value::String(v.into()));
|
|
@@ -327,7 +334,7 @@ pub fn response_value_from_reqwest(response: reqwest::Response) -> Value {
|
|
|
327
334
|
rx: Mutex::new(Some(rx)),
|
|
328
335
|
}))
|
|
329
336
|
});
|
|
330
|
-
let mut obj:
|
|
337
|
+
let mut obj: ObjectMap = ObjectMap::default();
|
|
331
338
|
obj.insert(Arc::from("status"), Value::Number(status));
|
|
332
339
|
obj.insert(Arc::from("ok"), Value::Bool(ok));
|
|
333
340
|
obj.insert(Arc::from("headers"), headers_val);
|
|
@@ -13,8 +13,15 @@ use tishlang_builtins::helpers::extract_num;
|
|
|
13
13
|
#[cfg(feature = "fs")]
|
|
14
14
|
use tishlang_builtins::helpers::make_error_value;
|
|
15
15
|
|
|
16
|
+
pub use tishlang_core::ObjectMap;
|
|
16
17
|
pub use tishlang_core::Value;
|
|
17
18
|
|
|
19
|
+
pub use tishlang_builtins::construct::{
|
|
20
|
+
audio_context_constructor_value as tish_audio_context_constructor,
|
|
21
|
+
construct as tish_construct,
|
|
22
|
+
uint8_array_constructor_value as tish_uint8_array_constructor,
|
|
23
|
+
};
|
|
24
|
+
|
|
18
25
|
// Re-export array methods from tishlang_builtins
|
|
19
26
|
pub use tishlang_builtins::array::{
|
|
20
27
|
push as array_push_impl,
|
|
@@ -754,7 +761,7 @@ pub fn regexp_exec(re: &Value, input: &Value) -> Value {
|
|
|
754
761
|
|
|
755
762
|
#[cfg(feature = "regex")]
|
|
756
763
|
fn regexp_exec_impl(re: &mut tishlang_core::TishRegExp, input: &str) -> Value {
|
|
757
|
-
use
|
|
764
|
+
use tishlang_core::ObjectMap;
|
|
758
765
|
|
|
759
766
|
let start = if re.flags.global || re.flags.sticky {
|
|
760
767
|
re.last_index
|
|
@@ -785,7 +792,7 @@ fn regexp_exec_impl(re: &mut tishlang_core::TishRegExp, input: &str) -> Value {
|
|
|
785
792
|
let match_byte_start = byte_start + full_match.start();
|
|
786
793
|
let match_char_index = input[..match_byte_start].chars().count();
|
|
787
794
|
|
|
788
|
-
let mut obj:
|
|
795
|
+
let mut obj: ObjectMap = ObjectMap::default();
|
|
789
796
|
obj.insert(Arc::from("0"), Value::String(full_match.as_str().into()));
|
|
790
797
|
for i in 1..caps.len() {
|
|
791
798
|
let val = match caps.get(i) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
//! Promise static methods for compiled Tish (resolve, reject, all, race).
|
|
2
2
|
|
|
3
3
|
use std::cell::RefCell;
|
|
4
|
-
use std::collections::HashMap;
|
|
5
4
|
use std::rc::Rc;
|
|
6
5
|
use std::sync::Arc;
|
|
7
|
-
use tishlang_core::Value;
|
|
6
|
+
use tishlang_core::{ObjectMap, Value};
|
|
8
7
|
|
|
9
8
|
/// Promise.resolve(value) - returns the value (immediate resolve).
|
|
10
9
|
pub fn promise_resolve(args: &[Value]) -> Value {
|
|
@@ -56,7 +55,7 @@ pub fn promise_race(args: &[Value]) -> Value {
|
|
|
56
55
|
|
|
57
56
|
/// Build the Promise object with resolve, reject, all, race static methods.
|
|
58
57
|
pub fn promise_object() -> Value {
|
|
59
|
-
let mut map:
|
|
58
|
+
let mut map: ObjectMap = ObjectMap::default();
|
|
60
59
|
map.insert(
|
|
61
60
|
Arc::from("resolve"),
|
|
62
61
|
Value::Function(Rc::new(|args: &[Value]| promise_resolve(args))),
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
//! Promises carrying only Send payloads (string results for text(), etc.).
|
|
2
2
|
|
|
3
3
|
use std::cell::RefCell;
|
|
4
|
-
use std::collections::HashMap;
|
|
5
4
|
use std::rc::Rc;
|
|
6
5
|
use std::sync::{Arc, Mutex};
|
|
7
|
-
use tishlang_core::{
|
|
6
|
+
use tishlang_core::{ObjectMap, TishPromise, Value};
|
|
8
7
|
use tokio::sync::oneshot;
|
|
9
8
|
|
|
10
9
|
fn error_value(msg: String) -> Value {
|
|
11
|
-
let mut obj:
|
|
10
|
+
let mut obj: ObjectMap = ObjectMap::with_capacity(2);
|
|
12
11
|
obj.insert(Arc::from("error"), Value::String(msg.into()));
|
|
13
12
|
obj.insert(Arc::from("ok"), Value::Bool(false));
|
|
14
13
|
Value::Object(Rc::new(RefCell::new(obj)))
|
|
@@ -15,7 +15,7 @@ use std::time::{Duration, Instant};
|
|
|
15
15
|
|
|
16
16
|
use futures_util::{SinkExt, StreamExt};
|
|
17
17
|
use lazy_static::lazy_static;
|
|
18
|
-
use tishlang_core::Value;
|
|
18
|
+
use tishlang_core::{ObjectMap, Value};
|
|
19
19
|
use tokio::sync::mpsc as tokio_mpsc;
|
|
20
20
|
use tokio::runtime::Runtime;
|
|
21
21
|
|
|
@@ -194,7 +194,7 @@ pub fn ws_broadcast_native(args: &[Value]) -> Value {
|
|
|
194
194
|
|
|
195
195
|
/// Build connection object: { _id, send, close, readyState, receive }. JS-like.
|
|
196
196
|
fn conn_object(id: u32) -> Value {
|
|
197
|
-
let mut obj:
|
|
197
|
+
let mut obj: ObjectMap = ObjectMap::default();
|
|
198
198
|
obj.insert(Arc::from("_id"), Value::Number(id as f64));
|
|
199
199
|
obj.insert(Arc::from("readyState"), Value::Number(1.0)); // OPEN
|
|
200
200
|
obj.insert(
|
|
@@ -216,7 +216,7 @@ fn conn_object(id: u32) -> Value {
|
|
|
216
216
|
Value::Function(Rc::new(move |_args: &[Value]| {
|
|
217
217
|
match conn_receive(id) {
|
|
218
218
|
Some(s) => {
|
|
219
|
-
let mut ev:
|
|
219
|
+
let mut ev: ObjectMap = ObjectMap::default();
|
|
220
220
|
ev.insert(Arc::from("data"), Value::String(s.into()));
|
|
221
221
|
Value::Object(Rc::new(RefCell::new(ev)))
|
|
222
222
|
}
|
|
@@ -237,7 +237,7 @@ fn conn_object(id: u32) -> Value {
|
|
|
237
237
|
.unwrap_or(1000);
|
|
238
238
|
match conn_receive_timeout(id_timeout, timeout_ms) {
|
|
239
239
|
Some(s) => {
|
|
240
|
-
let mut ev:
|
|
240
|
+
let mut ev: ObjectMap = ObjectMap::default();
|
|
241
241
|
ev.insert(Arc::from("data"), Value::String(s.into()));
|
|
242
242
|
Value::Object(Rc::new(RefCell::new(ev)))
|
|
243
243
|
}
|
|
@@ -529,7 +529,7 @@ pub fn web_socket_server_construct(args: &[Value]) -> Value {
|
|
|
529
529
|
ws
|
|
530
530
|
});
|
|
531
531
|
|
|
532
|
-
let mut m:
|
|
532
|
+
let mut m: ObjectMap = ObjectMap::default();
|
|
533
533
|
m.insert(Arc::from("_handle"), handle_val);
|
|
534
534
|
m.insert(Arc::from("_onConnection"), Value::Null);
|
|
535
535
|
m.insert(Arc::from("clients"), Value::Array(clients));
|
|
@@ -549,7 +549,7 @@ mod tests {
|
|
|
549
549
|
fn ws_echo_roundtrip() {
|
|
550
550
|
let port: u16 = 18_742;
|
|
551
551
|
let opts = {
|
|
552
|
-
let mut m:
|
|
552
|
+
let mut m: ObjectMap = ObjectMap::default();
|
|
553
553
|
m.insert(Arc::from("port"), Value::Number(port as f64));
|
|
554
554
|
Value::Object(Rc::new(RefCell::new(m)))
|
|
555
555
|
};
|
|
@@ -632,7 +632,7 @@ mod tests {
|
|
|
632
632
|
fn ws_gateway_agent_flow() {
|
|
633
633
|
let port: u16 = 18_743;
|
|
634
634
|
let opts = {
|
|
635
|
-
let mut m:
|
|
635
|
+
let mut m: ObjectMap = ObjectMap::default();
|
|
636
636
|
m.insert(Arc::from("port"), Value::Number(port as f64));
|
|
637
637
|
Value::Object(Rc::new(RefCell::new(m)))
|
|
638
638
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "tishlang_ui"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
description = "Shared JSX lowering and UI runtime (vnode, hooks, host protocol) for Tish"
|
|
6
|
+
|
|
7
|
+
license-file = { workspace = true }
|
|
8
|
+
repository = { workspace = true }
|
|
9
|
+
|
|
10
|
+
[features]
|
|
11
|
+
default = ["runtime"]
|
|
12
|
+
compiler = ["dep:tishlang_ast"]
|
|
13
|
+
runtime = ["dep:tishlang_core"]
|
|
14
|
+
|
|
15
|
+
[dependencies]
|
|
16
|
+
tishlang_ast = { path = "../tish_ast", version = ">=0.1", optional = true }
|
|
17
|
+
tishlang_core = { path = "../tish_core", version = ">=0.1", optional = true }
|