Skip to content

Commit e4f1283

Browse files
committed
feat: implement all remaining spec features in ZynML grammar
Grammar additions: - Module declarations: module name - Aliased imports: import zynml.tensor as T - Config blocks: config { device: "cpu", ... } - Pipeline definitions: pipeline name(params) -> type { } - Decorators: @cache(ttl=1h), @memoize, @kernel, @Workgroup, @device - Render statements: render expr { options } - Stream statements: stream source |> transform() |> sink() - Try/catch blocks: try { } catch Error as e { } - Match/case expressions: match expr { case pattern { } } - Load with type cast: load("file") as image - Model with config: model("path") { input: x, output: y } - Compute expressions: compute(args) { @kernel ... } Test updates: - Converted all "not yet implemented" tests to assertions - Added new tests for all spec features - 133 e2e tests now passing - Updated spec compliance summary
1 parent 9410cb2 commit e4f1283

2 files changed

Lines changed: 486 additions & 147 deletions

File tree

crates/zynml/ml.zyn

Lines changed: 300 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ top_level_items = { top_level_item* }
250250
"args": { "declarations": "$result" }
251251
}
252252

253-
top_level_item = { trait_def | impl_block | abstract_def | enum_def | struct_def | type_def | fn_def | let_stmt | import_stmt | expr_stmt }
253+
top_level_item = { module_decl | config_block | pipeline_def | decorated_item | trait_def | impl_block | abstract_def | enum_def | struct_def | type_def | fn_def | let_stmt | import_stmt | render_stmt | stream_stmt | expr_stmt }
254254
-> TypedDeclaration {
255255
"get_child": { "index": 0 }
256256
}
@@ -261,7 +261,25 @@ top_level_item = { trait_def | impl_block | abstract_def | enum_def | struct_def
261261

262262
// import tensor
263263
// import prelude
264-
import_stmt = { "import" ~ identifier }
264+
// import zynml.tensor as T
265+
import_stmt = { import_aliased | import_simple }
266+
-> TypedDeclaration {
267+
"get_child": { "index": 0 }
268+
}
269+
270+
// import zynml.tensor as T
271+
import_aliased = { "import" ~ module_path ~ "as" ~ identifier }
272+
-> TypedDeclaration {
273+
"commands": [
274+
{ "define": "import_aliased", "args": {
275+
"module_path": "$1",
276+
"alias": "$2"
277+
}}
278+
]
279+
}
280+
281+
// import tensor
282+
import_simple = { "import" ~ identifier }
265283
-> TypedDeclaration {
266284
"commands": [
267285
{ "define": "import", "args": {
@@ -270,6 +288,164 @@ import_stmt = { "import" ~ identifier }
270288
]
271289
}
272290

291+
// Module path: zynml.tensor.ops
292+
module_path = { identifier ~ ("." ~ identifier)* }
293+
-> String {
294+
"get_text": true
295+
}
296+
297+
// ============================================================================
298+
// Module Declaration
299+
// ============================================================================
300+
301+
// module recommendation_pipeline
302+
module_decl = { "module" ~ identifier }
303+
-> TypedDeclaration {
304+
"commands": [
305+
{ "define": "module", "args": {
306+
"name": "$1"
307+
}}
308+
]
309+
}
310+
311+
// ============================================================================
312+
// Config Block
313+
// ============================================================================
314+
315+
// config { device: "cpu", precision: "float32", batch_size: 32 }
316+
config_block = { "config" ~ "{" ~ config_entries ~ "}" }
317+
-> TypedDeclaration {
318+
"commands": [
319+
{ "define": "config", "args": {
320+
"entries": "$1"
321+
}}
322+
]
323+
}
324+
325+
config_entries = { config_entry ~ ("," ~ config_entry)* ~ ","? }
326+
-> List {
327+
"get_all_children": true
328+
}
329+
330+
config_entry = { identifier ~ ":" ~ expr }
331+
-> TypedExpression {
332+
"commands": [
333+
{ "define": "config_entry", "args": {
334+
"key": "$1",
335+
"value": "$2"
336+
}}
337+
]
338+
}
339+
340+
// ============================================================================
341+
// Pipeline Definition
342+
// ============================================================================
343+
344+
// pipeline image_search(query: text, top_k: int) -> list { ... }
345+
pipeline_def = { "pipeline" ~ identifier ~ "(" ~ fn_params? ~ ")" ~ ("->" ~ type_expr)? ~ block }
346+
-> TypedDeclaration {
347+
"commands": [
348+
{ "define": "pipeline", "args": {
349+
"name": "$1",
350+
"params": "$2",
351+
"return_type": "$3",
352+
"body": "$4"
353+
}}
354+
]
355+
}
356+
357+
// ============================================================================
358+
// Decorated Items (@cache, @memoize, @kernel, @workgroup, @device)
359+
// ============================================================================
360+
361+
// @cache(ttl=1h) fn expensive() { ... }
362+
// @memoize fn compute() { ... }
363+
// @kernel elementwise
364+
decorated_item = { decorator+ ~ (fn_def | pipeline_def) }
365+
-> TypedDeclaration {
366+
"commands": [
367+
{ "define": "decorated", "args": {
368+
"decorators": "$1",
369+
"item": "$2"
370+
}}
371+
]
372+
}
373+
374+
// Decorator: @name or @name(args)
375+
decorator = { "@" ~ identifier ~ decorator_args? }
376+
-> TypedExpression {
377+
"commands": [
378+
{ "define": "decorator", "args": {
379+
"name": "$1",
380+
"args": "$2"
381+
}}
382+
]
383+
}
384+
385+
decorator_args = { "(" ~ decorator_arg_list ~ ")" }
386+
-> List {
387+
"get_child": { "index": 0 }
388+
}
389+
390+
decorator_arg_list = { decorator_arg ~ ("," ~ decorator_arg)* }
391+
-> List {
392+
"get_all_children": true
393+
}
394+
395+
// ttl=1h or just identifier for kernel types
396+
decorator_arg = { identifier ~ "=" ~ expr | identifier | expr }
397+
-> TypedExpression {
398+
"get_all_children": true,
399+
"define": "decorator_arg"
400+
}
401+
402+
// ============================================================================
403+
// Render Statement (Visualization for ZynBook)
404+
// ============================================================================
405+
406+
// render photo
407+
// render chart(data) { type: "line", title: "My Chart" }
408+
render_stmt = { render_with_options | render_simple }
409+
-> TypedDeclaration {
410+
"get_child": { "index": 0 }
411+
}
412+
413+
// render photo { title: "Original Image", width: 400 }
414+
render_with_options = { "render" ~ expr ~ "{" ~ config_entries ~ "}" }
415+
-> TypedDeclaration {
416+
"commands": [
417+
{ "define": "render", "args": {
418+
"expr": "$1",
419+
"options": "$2"
420+
}}
421+
]
422+
}
423+
424+
// render photo
425+
render_simple = { "render" ~ expr }
426+
-> TypedDeclaration {
427+
"commands": [
428+
{ "define": "render", "args": {
429+
"expr": "$1"
430+
}}
431+
]
432+
}
433+
434+
// ============================================================================
435+
// Stream Statement
436+
// ============================================================================
437+
438+
// stream sensor_data |> window(100) |> sink(alert_system)
439+
stream_stmt = { "stream" ~ identifier ~ ("|>" ~ pipe_call)+ }
440+
-> TypedDeclaration {
441+
"commands": [
442+
{ "define": "stream", "args": {
443+
"source": "$1",
444+
"pipeline": "$2"
445+
}}
446+
]
447+
}
448+
273449
// ============================================================================
274450
// Trait Definition
275451
// ============================================================================
@@ -1233,7 +1409,7 @@ fn_param = { identifier ~ (":" ~ type_expr)? }
12331409
// Statements
12341410
// ============================================================================
12351411

1236-
statement = { let_stmt | assign_stmt | if_stmt | while_stmt | for_stmt | return_stmt | break_stmt | continue_stmt | expr_stmt }
1412+
statement = { let_stmt | assign_stmt | if_stmt | while_stmt | for_stmt | try_stmt | match_stmt | return_stmt | break_stmt | continue_stmt | expr_stmt }
12371413
-> TypedStatement {
12381414
"get_child": { "index": 0 }
12391415
}
@@ -1345,6 +1521,73 @@ continue_stmt = { "continue" }
13451521
]
13461522
}
13471523

1524+
// ============================================================================
1525+
// Try/Catch Statement
1526+
// ============================================================================
1527+
1528+
// try { ... } catch ErrorType as e { ... }
1529+
try_stmt = { "try" ~ block ~ catch_clause+ }
1530+
-> TypedStatement {
1531+
"commands": [
1532+
{ "define": "try_stmt", "args": {
1533+
"body": "$1",
1534+
"catches": "$2"
1535+
}}
1536+
]
1537+
}
1538+
1539+
// catch ErrorType as e { ... }
1540+
// catch _ { ... } (catch all)
1541+
catch_clause = { "catch" ~ identifier ~ ("as" ~ identifier)? ~ block }
1542+
-> TypedStatement {
1543+
"commands": [
1544+
{ "define": "catch", "args": {
1545+
"error_type": "$1",
1546+
"binding": "$2",
1547+
"body": "$3"
1548+
}}
1549+
]
1550+
}
1551+
1552+
// ============================================================================
1553+
// Match/Case Statement
1554+
// ============================================================================
1555+
1556+
// match expr { case pattern { ... } case _ { ... } }
1557+
match_stmt = { "match" ~ expr ~ "{" ~ match_arm+ ~ "}" }
1558+
-> TypedStatement {
1559+
"commands": [
1560+
{ "define": "match_stmt", "args": {
1561+
"expr": "$1",
1562+
"arms": "$2"
1563+
}}
1564+
]
1565+
}
1566+
1567+
// case "pattern" { ... }
1568+
// case _ { ... }
1569+
match_arm = { "case" ~ pattern ~ block }
1570+
-> TypedStatement {
1571+
"commands": [
1572+
{ "define": "match_arm", "args": {
1573+
"pattern": "$1",
1574+
"body": "$2"
1575+
}}
1576+
]
1577+
}
1578+
1579+
// Pattern: literal, identifier (binding), or wildcard (_)
1580+
pattern = { string_literal | int_literal | bool_literal | wildcard | identifier }
1581+
-> TypedExpression {
1582+
"get_child": { "index": 0 }
1583+
}
1584+
1585+
// Wildcard pattern
1586+
wildcard = { "_" }
1587+
-> TypedExpression {
1588+
"define": "wildcard"
1589+
}
1590+
13481591
// expr as statement
13491592
expr_stmt = { expr }
13501593
-> TypedStatement {
@@ -1565,6 +1808,9 @@ member_op = { "." ~ identifier }
15651808

15661809
// Primary expressions
15671810
primary_expr = {
1811+
load_as_expr |
1812+
model_config_expr |
1813+
compute_expr |
15681814
extern_call |
15691815
tensor_literal |
15701816
struct_literal |
@@ -1583,6 +1829,57 @@ primary_expr = {
15831829
"get_child": { "index": 0 }
15841830
}
15851831

1832+
// ============================================================================
1833+
// Load with Type Cast
1834+
// ============================================================================
1835+
1836+
// load("image.jpg") as image
1837+
load_as_expr = { "load" ~ "(" ~ string_literal ~ ")" ~ "as" ~ identifier }
1838+
-> TypedExpression {
1839+
"commands": [
1840+
{ "define": "load_as", "args": {
1841+
"path": "$1",
1842+
"type": "$2"
1843+
}}
1844+
]
1845+
}
1846+
1847+
// ============================================================================
1848+
// Model with Config Block
1849+
// ============================================================================
1850+
1851+
// model("bert.onnx") { input: text, output: Embedding }
1852+
model_config_expr = { "model" ~ "(" ~ string_literal ~ ")" ~ "{" ~ config_entries ~ "}" }
1853+
-> TypedExpression {
1854+
"commands": [
1855+
{ "define": "model_config", "args": {
1856+
"path": "$1",
1857+
"config": "$2"
1858+
}}
1859+
]
1860+
}
1861+
1862+
// ============================================================================
1863+
// Compute Expression (GPU Kernel Dispatch)
1864+
// ============================================================================
1865+
1866+
// compute(tensor) { @kernel elementwise for i in 0..len { out[i] = x[i] * 2.0 } }
1867+
compute_expr = { "compute" ~ "(" ~ call_args ~ ")" ~ "{" ~ compute_body ~ "}" }
1868+
-> TypedExpression {
1869+
"commands": [
1870+
{ "define": "compute", "args": {
1871+
"args": "$1",
1872+
"body": "$2"
1873+
}}
1874+
]
1875+
}
1876+
1877+
// Compute body can have decorators and statements
1878+
compute_body = { (decorator | statement)* }
1879+
-> List {
1880+
"get_all_children": true
1881+
}
1882+
15861883
// Path expression: Type::method or module::function
15871884
// Used for associated functions (static methods) like Duration::from(1000)
15881885
path_expr = { identifier ~ "::" ~ identifier }

0 commit comments

Comments
 (0)