@tishlang/tish 1.0.28 → 1.0.33
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 +8 -55
- 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 +233 -71
- package/crates/tish_compile/src/lib.rs +35 -0
- package/crates/tish_compile_js/Cargo.toml +1 -1
- package/crates/tish_compile_js/src/codegen.rs +43 -147
- package/crates/tish_compile_js/src/lib.rs +4 -7
- package/crates/tish_compile_js/src/tests_jsx.rs +89 -19
- package/crates/tish_compiler_wasm/src/lib.rs +2 -3
- 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 +10 -5
- package/crates/tish_eval/Cargo.toml +2 -0
- package/crates/tish_eval/src/eval.rs +149 -72
- package/crates/tish_eval/src/http.rs +3 -4
- 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_jsx_web/Cargo.toml +1 -1
- package/crates/tish_jsx_web/README.md +3 -16
- package/crates/tish_jsx_web/src/lib.rs +2 -157
- package/crates/tish_lexer/src/token.rs +2 -0
- package/crates/tish_lint/src/lib.rs +9 -0
- package/crates/tish_lsp/README.md +1 -1
- package/crates/tish_native/src/build.rs +16 -2
- 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 +161 -50
- package/crates/tish_runtime/src/http.rs +4 -5
- package/crates/tish_runtime/src/http_fetch.rs +9 -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
- package/crates/tish_jsx_web/vendor/Lattish.tish +0 -362
|
@@ -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
|
}
|
|
@@ -1117,8 +1147,97 @@ impl<'a> Parser<'a> {
|
|
|
1117
1147
|
})
|
|
1118
1148
|
}
|
|
1119
1149
|
|
|
1120
|
-
|
|
1150
|
+
/// Member chain (`.`, `?.`, `[]`) without consuming a call `(...)`.
|
|
1151
|
+
fn parse_member_expression_no_call(&mut self) -> Result<Expr, String> {
|
|
1121
1152
|
let mut expr = self.parse_primary()?;
|
|
1153
|
+
while let Some(kind) = self.peek_kind() {
|
|
1154
|
+
match kind {
|
|
1155
|
+
TokenKind::Dot | TokenKind::OptionalChain => {
|
|
1156
|
+
let optional = kind == TokenKind::OptionalChain;
|
|
1157
|
+
self.advance();
|
|
1158
|
+
let prop = self
|
|
1159
|
+
.expect(TokenKind::Ident)?
|
|
1160
|
+
.literal
|
|
1161
|
+
.clone()
|
|
1162
|
+
.ok_or("Expected property name")?;
|
|
1163
|
+
let start = expr.span().start;
|
|
1164
|
+
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1165
|
+
expr = Expr::Member {
|
|
1166
|
+
object: Box::new(expr),
|
|
1167
|
+
prop: MemberProp::Name(prop),
|
|
1168
|
+
optional,
|
|
1169
|
+
span: Span { start, end },
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
TokenKind::LBracket => {
|
|
1173
|
+
self.advance();
|
|
1174
|
+
let index = self.parse_expr()?;
|
|
1175
|
+
self.expect(TokenKind::RBracket)?;
|
|
1176
|
+
let start = expr.span().start;
|
|
1177
|
+
let end = self.peek().map(|x| x.span.start).unwrap_or(start);
|
|
1178
|
+
expr = Expr::Index {
|
|
1179
|
+
object: Box::new(expr),
|
|
1180
|
+
index: Box::new(index),
|
|
1181
|
+
optional: false,
|
|
1182
|
+
span: Span { start, end },
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
_ => break,
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
Ok(expr)
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/// ECMAScript `NewExpression`: `new` chains, then member expression without call, optional `(...)`.
|
|
1192
|
+
fn parse_new_expression(&mut self) -> Result<Expr, String> {
|
|
1193
|
+
if matches!(self.peek_kind(), Some(TokenKind::New)) {
|
|
1194
|
+
let span_start = self.peek().map(|t| t.span.start).unwrap_or((0, 0));
|
|
1195
|
+
self.advance();
|
|
1196
|
+
let callee = Box::new(self.parse_new_expression()?);
|
|
1197
|
+
let args = if matches!(self.peek_kind(), Some(TokenKind::LParen)) {
|
|
1198
|
+
self.advance();
|
|
1199
|
+
let mut args = Vec::new();
|
|
1200
|
+
while !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1201
|
+
if matches!(self.peek_kind(), Some(TokenKind::Spread)) {
|
|
1202
|
+
self.advance();
|
|
1203
|
+
let arg_expr = self.parse_expr()?;
|
|
1204
|
+
args.push(CallArg::Spread(arg_expr));
|
|
1205
|
+
} else {
|
|
1206
|
+
let arg_expr = self.parse_expr()?;
|
|
1207
|
+
args.push(CallArg::Expr(arg_expr));
|
|
1208
|
+
}
|
|
1209
|
+
if !matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1210
|
+
self.expect(TokenKind::Comma)?;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
self.expect(TokenKind::RParen)?;
|
|
1214
|
+
args
|
|
1215
|
+
} else {
|
|
1216
|
+
Vec::new()
|
|
1217
|
+
};
|
|
1218
|
+
let end = self
|
|
1219
|
+
.peek()
|
|
1220
|
+
.map(|x| x.span.start)
|
|
1221
|
+
.unwrap_or(callee.as_ref().span().end);
|
|
1222
|
+
Ok(Expr::New {
|
|
1223
|
+
callee,
|
|
1224
|
+
args,
|
|
1225
|
+
span: Span {
|
|
1226
|
+
start: span_start,
|
|
1227
|
+
end,
|
|
1228
|
+
},
|
|
1229
|
+
})
|
|
1230
|
+
} else {
|
|
1231
|
+
self.parse_member_expression_no_call()
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
fn parse_postfix(&mut self) -> Result<Expr, String> {
|
|
1236
|
+
let mut expr = if matches!(self.peek_kind(), Some(TokenKind::New)) {
|
|
1237
|
+
self.parse_new_expression()?
|
|
1238
|
+
} else {
|
|
1239
|
+
self.parse_primary()?
|
|
1240
|
+
};
|
|
1122
1241
|
while let Some(kind) = self.peek_kind() {
|
|
1123
1242
|
match kind {
|
|
1124
1243
|
TokenKind::LParen => {
|
|
@@ -1243,7 +1362,11 @@ impl<'a> Parser<'a> {
|
|
|
1243
1362
|
let body = self.parse_arrow_body()?;
|
|
1244
1363
|
let end = self.previous_span_end();
|
|
1245
1364
|
return Ok(Expr::ArrowFunction {
|
|
1246
|
-
params: vec![TypedParam {
|
|
1365
|
+
params: vec![FunParam::Simple(TypedParam {
|
|
1366
|
+
name: name.clone(),
|
|
1367
|
+
type_ann: None,
|
|
1368
|
+
default: None,
|
|
1369
|
+
})],
|
|
1247
1370
|
body,
|
|
1248
1371
|
span: Span { start: span.start, end },
|
|
1249
1372
|
});
|
|
@@ -1418,39 +1541,26 @@ impl<'a> Parser<'a> {
|
|
|
1418
1541
|
is_arrow = true;
|
|
1419
1542
|
}
|
|
1420
1543
|
} else {
|
|
1421
|
-
// Try to parse params: (x, y,
|
|
1544
|
+
// Try to parse params: (x, y), ({ a }), ([a, b]), with optional types/defaults
|
|
1545
|
+
let mut params_ok = true;
|
|
1422
1546
|
loop {
|
|
1423
|
-
if
|
|
1424
|
-
break;
|
|
1547
|
+
if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1548
|
+
break;
|
|
1549
|
+
}
|
|
1550
|
+
match self.parse_fun_param() {
|
|
1551
|
+
Ok(param) => params.push(param),
|
|
1552
|
+
Err(_) => {
|
|
1553
|
+
params_ok = false;
|
|
1554
|
+
break;
|
|
1555
|
+
}
|
|
1425
1556
|
}
|
|
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
1557
|
if matches!(self.peek_kind(), Some(TokenKind::Comma)) {
|
|
1447
1558
|
self.advance();
|
|
1448
1559
|
} else {
|
|
1449
1560
|
break;
|
|
1450
1561
|
}
|
|
1451
1562
|
}
|
|
1452
|
-
|
|
1453
|
-
if matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1563
|
+
if params_ok && matches!(self.peek_kind(), Some(TokenKind::RParen)) {
|
|
1454
1564
|
self.advance(); // consume )
|
|
1455
1565
|
if matches!(self.peek_kind(), Some(TokenKind::Arrow)) {
|
|
1456
1566
|
self.advance(); // consume =>
|
|
@@ -1787,6 +1897,7 @@ impl ExprSpan for Expr {
|
|
|
1787
1897
|
Expr::Binary { span, .. } => *span,
|
|
1788
1898
|
Expr::Unary { span, .. } => *span,
|
|
1789
1899
|
Expr::Call { span, .. } => *span,
|
|
1900
|
+
Expr::New { span, .. } => *span,
|
|
1790
1901
|
Expr::Member { span, .. } => *span,
|
|
1791
1902
|
Expr::Index { span, .. } => *span,
|
|
1792
1903
|
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
|
}),
|
|
@@ -226,7 +225,7 @@ impl TishOpaque for HttpReadableStream {
|
|
|
226
225
|
}))
|
|
227
226
|
}
|
|
228
227
|
Err(e) => {
|
|
229
|
-
let mut m =
|
|
228
|
+
let mut m = ObjectMap::default();
|
|
230
229
|
m.insert(Arc::from("error"), Value::String(e.into()));
|
|
231
230
|
Value::Object(Rc::new(RefCell::new(m)))
|
|
232
231
|
}
|
|
@@ -283,7 +282,7 @@ impl TishOpaque for HttpStreamReader {
|
|
|
283
282
|
}
|
|
284
283
|
|
|
285
284
|
fn headers_to_value(headers: &reqwest::header::HeaderMap) -> Value {
|
|
286
|
-
let mut headers_obj:
|
|
285
|
+
let mut headers_obj: ObjectMap = ObjectMap::with_capacity(headers.len());
|
|
287
286
|
for (key, value) in headers.iter() {
|
|
288
287
|
if let Ok(v) = value.to_str() {
|
|
289
288
|
headers_obj.insert(Arc::from(key.as_str()), Value::String(v.into()));
|
|
@@ -327,7 +326,7 @@ pub fn response_value_from_reqwest(response: reqwest::Response) -> Value {
|
|
|
327
326
|
rx: Mutex::new(Some(rx)),
|
|
328
327
|
}))
|
|
329
328
|
});
|
|
330
|
-
let mut obj:
|
|
329
|
+
let mut obj: ObjectMap = ObjectMap::default();
|
|
331
330
|
obj.insert(Arc::from("status"), Value::Number(status));
|
|
332
331
|
obj.insert(Arc::from("ok"), Value::Bool(ok));
|
|
333
332
|
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 }
|