Skip to content

Commit 380e22c

Browse files
author
Jane
committed
Merge branch 'master' of https://github.com/henry-luo/lambda
2 parents 28fa13b + 6b40c60 commit 380e22c

34 files changed

Lines changed: 7037 additions & 513 deletions

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ TREE_SITTER_JAVASCRIPT_LIB = lambda/tree-sitter-javascript/libtree-sitter-javasc
139139
TREE_SITTER_BASH_LIB = lambda/tree-sitter-bash/libtree-sitter-bash.a
140140
TREE_SITTER_PYTHON_LIB = lambda/tree-sitter-python/libtree-sitter-python.a
141141
TREE_SITTER_TYPESCRIPT_LIB = lambda/tree-sitter-typescript/libtree-sitter-typescript.a
142+
TREE_SITTER_RUBY_LIB = lambda/tree-sitter-ruby/libtree-sitter-ruby.a
142143
TREE_SITTER_LATEX_LIB = lambda/tree-sitter-latex/libtree-sitter-latex.a
143144
TREE_SITTER_LATEX_MATH_LIB = lambda/tree-sitter-latex-math/libtree-sitter-latex-math.a
144145
RE2_LIB = build_temp/re2-noabsl/cmake_build/libre2.a
@@ -206,6 +207,11 @@ $(TREE_SITTER_TYPESCRIPT_LIB):
206207
@echo "Building tree-sitter-typescript library..."
207208
env -u OS PATH="/mingw64/bin:$$PATH" $(MAKE) -C lambda/tree-sitter-typescript libtree-sitter-typescript.a CC="$(CC)" CXX="$(CXX)" V=1 VERBOSE=1
208209

210+
# Build tree-sitter-ruby library
211+
$(TREE_SITTER_RUBY_LIB):
212+
@echo "Building tree-sitter-ruby library..."
213+
env -u OS PATH="/mingw64/bin:$$PATH" $(MAKE) -C lambda/tree-sitter-ruby libtree-sitter-ruby.a CC="$(CC)" CXX="$(CXX)" V=1 VERBOSE=1
214+
209215
# Generate LaTeX parser from grammar.js when it changes
210216
$(LATEX_PARSER_C) $(LATEX_GRAMMAR_JSON) $(LATEX_NODE_TYPES_JSON): $(LATEX_GRAMMAR_JS)
211217
@echo "Generating LaTeX parser from grammar.js..."
@@ -350,7 +356,7 @@ define run_make_with_error_summary
350356
endef
351357

352358
# Combined tree-sitter libraries target
353-
tree-sitter-libs: $(TREE_SITTER_LIB) $(TREE_SITTER_LAMBDA_LIB) $(TREE_SITTER_JAVASCRIPT_LIB) $(TREE_SITTER_BASH_LIB) $(TREE_SITTER_PYTHON_LIB) $(TREE_SITTER_TYPESCRIPT_LIB) $(TREE_SITTER_LATEX_LIB) $(TREE_SITTER_LATEX_MATH_LIB)
359+
tree-sitter-libs: $(TREE_SITTER_LIB) $(TREE_SITTER_LAMBDA_LIB) $(TREE_SITTER_JAVASCRIPT_LIB) $(TREE_SITTER_BASH_LIB) $(TREE_SITTER_PYTHON_LIB) $(TREE_SITTER_TYPESCRIPT_LIB) $(TREE_SITTER_RUBY_LIB) $(TREE_SITTER_LATEX_LIB) $(TREE_SITTER_LATEX_MATH_LIB)
354360

355361
# Default target
356362
.DEFAULT_GOAL := build
@@ -707,6 +713,7 @@ clean-all: clean-premake clean-test
707713
@rm -f lambda/tree-sitter-bash/libtree-sitter-bash.a lambda/tree-sitter-bash/src/*.o
708714
@rm -f lambda/tree-sitter-python/libtree-sitter-python.a lambda/tree-sitter-python/src/*.o
709715
@rm -f lambda/tree-sitter-typescript/libtree-sitter-typescript.a lambda/tree-sitter-typescript/src/*.o
716+
@rm -f lambda/tree-sitter-ruby/libtree-sitter-ruby.a lambda/tree-sitter-ruby/src/*.o
710717
@rm -f lambda/tree-sitter-latex/libtree-sitter-latex.a lambda/tree-sitter-latex/src/*.o
711718
@rm -f lambda/tree-sitter-latex-math/libtree-sitter-latex-math.a lambda/tree-sitter-latex-math/src/*.o
712719
@rm -rf build_temp/re2-noabsl/cmake_build

build_lambda_config.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2679,13 +2679,25 @@
26792679
{
26802680
"source": "test/test_js_test262_gtest.cpp",
26812681
"name": "test262 Compliance Tests",
2682+
"category": "extended",
26822683
"dependencies": [],
26832684
"binary": "test_js_test262_gtest.exe",
26842685
"libraries": [
26852686
"gtest"
26862687
],
26872688
"icon": "📋"
26882689
},
2690+
{
2691+
"source": "test/test_wpt_css_syntax_gtest.cpp",
2692+
"name": "WPT CSS Syntax Tests",
2693+
"category": "extended",
2694+
"dependencies": [],
2695+
"binary": "test_wpt_css_syntax_gtest.exe",
2696+
"libraries": [
2697+
"gtest"
2698+
],
2699+
"icon": "🎨"
2700+
},
26892701
{
26902702
"source": "test/test_c2mir_gtest.cpp",
26912703
"name": "C2MIR JIT Execution Tests",
@@ -2754,7 +2766,8 @@
27542766
"gtest"
27552767
],
27562768
"requires_lambda_exe": true,
2757-
"icon": "💎"
2769+
"icon": "💎",
2770+
"category": "extended"
27582771
},
27592772
{
27602773
"source": "test/test_ts_gtest.cpp",

lambda/js/build_js_ast.cpp

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,23 @@ JsAstNode* build_js_literal(JsTranspiler* tp, TSNode literal_node) {
186186
break;
187187
}
188188
}
189-
// Create null-terminated string for strtod
189+
// Create null-terminated string, stripping numeric separators (_)
190190
char* temp_str = (char*)malloc(source.length + 1);
191191
if (temp_str) {
192-
memcpy(temp_str, source.str, source.length);
193-
temp_str[source.length] = '\0';
192+
size_t j = 0;
193+
for (size_t i = 0; i < source.length; i++) {
194+
if (source.str[i] != '_') temp_str[j++] = source.str[i];
195+
}
196+
temp_str[j] = '\0';
194197
char* endptr;
195-
literal->value.number_value = strtod(temp_str, &endptr);
198+
// strtod handles decimal and 0x hex, but not 0b binary or 0o octal
199+
if (j > 2 && temp_str[0] == '0' && (temp_str[1] == 'b' || temp_str[1] == 'B')) {
200+
literal->value.number_value = (double)strtoull(temp_str + 2, &endptr, 2);
201+
} else if (j > 2 && temp_str[0] == '0' && (temp_str[1] == 'o' || temp_str[1] == 'O')) {
202+
literal->value.number_value = (double)strtoull(temp_str + 2, &endptr, 8);
203+
} else {
204+
literal->value.number_value = strtod(temp_str, &endptr);
205+
}
196206
free(temp_str);
197207
} else {
198208
literal->value.number_value = 0.0;
@@ -555,17 +565,35 @@ JsAstNode* build_js_member_expression(JsTranspiler* tp, TSNode member_node) {
555565
JsAstNode* build_js_array_expression(JsTranspiler* tp, TSNode array_node) {
556566
JsArrayNode* array = (JsArrayNode*)alloc_js_ast_node(tp, JS_AST_NODE_ARRAY_EXPRESSION, array_node, sizeof(JsArrayNode));
557567

558-
uint32_t element_count = ts_node_named_child_count(array_node);
559-
array->length = element_count;
568+
// v18: Use all children (including unnamed commas) to correctly handle elisions [1,,3]
569+
uint32_t total_children = ts_node_child_count(array_node);
560570

561571
JsAstNode* prev_element = NULL;
562572
uint32_t actual_count = 0;
563-
for (uint32_t i = 0; i < element_count; i++) {
564-
TSNode element_node = ts_node_named_child(array_node, i);
565-
const char* child_type = ts_node_type(element_node);
573+
bool expect_elem = true; // true = next non-comma token should be an element
574+
for (uint32_t i = 0; i < total_children; i++) {
575+
TSNode child = ts_node_child(array_node, i);
576+
const char* child_type = ts_node_type(child);
577+
if (strcmp(child_type, "[") == 0 || strcmp(child_type, "]") == 0) continue;
578+
if (strcmp(child_type, ",") == 0) {
579+
if (expect_elem) {
580+
// consecutive comma or leading comma = elision: insert undefined hole
581+
JsAstNode* elision = (JsAstNode*)alloc_js_ast_node(
582+
tp, JS_AST_NODE_NULL, child, sizeof(JsAstNode));
583+
elision->type = &TYPE_ANY;
584+
if (!prev_element) array->elements = elision;
585+
else prev_element->next = elision;
586+
prev_element = elision;
587+
actual_count++;
588+
} else {
589+
expect_elem = true;
590+
}
591+
continue;
592+
}
566593
// skip comment nodes inside array literals
567594
if (strcmp(child_type, "comment") == 0) continue;
568-
JsAstNode* element = build_js_expression(tp, element_node);
595+
expect_elem = false;
596+
JsAstNode* element = build_js_expression(tp, child);
569597
if (!element) continue;
570598

571599
if (!prev_element) {
@@ -2186,18 +2214,14 @@ JsAstNode* build_js_switch_statement(JsTranspiler* tp, TSNode switch_node) {
21862214
// Get consequent statements
21872215
JsAstNode* prev_stmt = NULL;
21882216
uint32_t stmt_count = ts_node_named_child_count(child);
2217+
// Determine position of the value node so we can skip it in the body
2218+
TSNode case_value = ts_node_child_by_field_name(child, "value", strlen("value"));
2219+
uint32_t value_start = ts_node_is_null(case_value) ? UINT32_MAX : ts_node_start_byte(case_value);
21892220
for (uint32_t j = 0; j < stmt_count; j++) {
21902221
TSNode stmt_child = ts_node_named_child(child, j);
2191-
const char* stmt_type = ts_node_type(stmt_child);
2192-
// Skip the value node itself
2193-
if (strcmp(stmt_type, "number") == 0 || strcmp(stmt_type, "string") == 0 ||
2194-
strcmp(stmt_type, "identifier") == 0 || strcmp(stmt_type, "true") == 0 ||
2195-
strcmp(stmt_type, "false") == 0) {
2196-
// Check if this is the case value by position
2197-
TSNode value = ts_node_child_by_field_name(child, "value", strlen("value"));
2198-
if (!ts_node_is_null(value) && ts_node_start_byte(stmt_child) == ts_node_start_byte(value)) {
2199-
continue;
2200-
}
2222+
// Skip the value node itself (any expression type)
2223+
if (ts_node_start_byte(stmt_child) == value_start) {
2224+
continue;
22012225
}
22022226
JsAstNode* stmt = build_js_statement(tp, stmt_child);
22032227
if (!stmt) continue;
@@ -2409,6 +2433,7 @@ JsAstNode* build_js_field_definition(JsTranspiler* tp, TSNode field_node) {
24092433
tp, JS_AST_NODE_FIELD_DEFINITION, field_node, sizeof(JsFieldDefinitionNode));
24102434
field->is_static = false;
24112435
field->is_private = false;
2436+
field->computed = false;
24122437
field->key = NULL;
24132438
field->value = NULL;
24142439

@@ -2430,6 +2455,9 @@ JsAstNode* build_js_field_definition(JsTranspiler* tp, TSNode field_node) {
24302455
if (strcmp(prop_type, "private_property_identifier") == 0) {
24312456
field->is_private = true;
24322457
}
2458+
if (strcmp(prop_type, "computed_property_name") == 0) {
2459+
field->computed = true;
2460+
}
24332461
field->key = build_js_expression(tp, prop_node);
24342462
}
24352463

@@ -2456,6 +2484,16 @@ JsAstNode* build_js_class_body(JsTranspiler* tp, TSNode body_node) {
24562484
JsAstNode* method = NULL;
24572485
if (strcmp(child_type, "field_definition") == 0) {
24582486
method = build_js_field_definition(tp, child_node);
2487+
} else if (strcmp(child_type, "class_static_block") == 0) {
2488+
// static { ... } block
2489+
JsStaticBlockNode* sb = (JsStaticBlockNode*)alloc_js_ast_node(
2490+
tp, JS_AST_NODE_STATIC_BLOCK, child_node, sizeof(JsStaticBlockNode));
2491+
sb->body = NULL;
2492+
TSNode body_node = ts_node_child_by_field_name(child_node, "body", strlen("body"));
2493+
if (!ts_node_is_null(body_node)) {
2494+
sb->body = build_js_block_statement(tp, body_node);
2495+
}
2496+
method = (JsAstNode*)sb;
24592497
} else {
24602498
method = build_js_method_definition(tp, child_node);
24612499
}

lambda/js/js_ast.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ typedef enum JsAstNodeType {
104104
JS_AST_NODE_CLASS_EXPRESSION,
105105
JS_AST_NODE_METHOD_DEFINITION,
106106
JS_AST_NODE_FIELD_DEFINITION,
107+
JS_AST_NODE_STATIC_BLOCK,
107108
JS_AST_NODE_TRY_STATEMENT,
108109
JS_AST_NODE_CATCH_CLAUSE,
109110
JS_AST_NODE_FINALLY_CLAUSE,
@@ -447,12 +448,19 @@ typedef struct JsMethodDefinitionNode {
447448
// JavaScript static field definition node (class body field)
448449
typedef struct JsFieldDefinitionNode {
449450
JsAstNode base;
450-
JsAstNode* key; // Field name (identifier)
451+
JsAstNode* key; // Field name (identifier or computed expression)
451452
JsAstNode* value; // Initializer expression (optional)
452453
bool is_static; // Whether it's a static field
453454
bool is_private; // Whether it's a private field (#field)
455+
bool computed; // Whether key is a computed property [expr]
454456
} JsFieldDefinitionNode;
455457

458+
// JavaScript class static block node: static { ... }
459+
typedef struct JsStaticBlockNode {
460+
JsAstNode base;
461+
JsAstNode* body; // Block statement body
462+
} JsStaticBlockNode;
463+
456464
// JavaScript try statement node
457465
typedef struct JsTryNode {
458466
JsAstNode base;

0 commit comments

Comments
 (0)