diff --git a/ml-proto/host/parser.mly b/ml-proto/host/parser.mly index c79b54fe6f..55ab53c970 100644 --- a/ml-proto/host/parser.mly +++ b/ml-proto/host/parser.mly @@ -282,25 +282,28 @@ expr_list : /* Functions */ func_fields : - | expr_list - { empty_type, - fun c -> let c' = anon_label c in - {ftype = -1 @@ at(); locals = []; body = $1 c'} } + | func_body { $1 } + | LPAR RESULT VALUE_TYPE RPAR func_body + { if (fst $5).out <> None then error (at ()) "multiple return types"; + {(fst $5) with out = Some $3}, + fun c -> (snd $5) c } | LPAR PARAM value_type_list RPAR func_fields { {(fst $5) with ins = $3 @ (fst $5).ins}, fun c -> anon_locals c $3; (snd $5) c } | LPAR PARAM bind_var VALUE_TYPE RPAR func_fields /* Sugar */ { {(fst $6) with ins = $4 :: (fst $6).ins}, fun c -> bind_local c $3; (snd $6) c } - | LPAR RESULT VALUE_TYPE RPAR func_fields - { if (fst $5).out <> None then error (at ()) "multiple return types"; - {(fst $5) with out = Some $3}, - fun c -> (snd $5) c } - | LPAR LOCAL value_type_list RPAR func_fields +; +func_body : + | expr_list + { empty_type, + fun c -> let c' = anon_label c in + {ftype = -1 @@ at(); locals = []; body = $1 c'} } + | LPAR LOCAL value_type_list RPAR func_body { fst $5, fun c -> anon_locals c $3; let f = (snd $5) c in {f with locals = $3 @ f.locals} } - | LPAR LOCAL bind_var VALUE_TYPE RPAR func_fields /* Sugar */ + | LPAR LOCAL bind_var VALUE_TYPE RPAR func_body /* Sugar */ { fst $6, fun c -> bind_local c $3; let f = (snd $6) c in {f with locals = $4 :: f.locals} } diff --git a/ml-proto/test/function-local-after-body.fail.wast b/ml-proto/test/function-local-after-body.fail.wast new file mode 100644 index 0000000000..0c4cf8c3f0 --- /dev/null +++ b/ml-proto/test/function-local-after-body.fail.wast @@ -0,0 +1 @@ +(module (func (nop) (local i32))) diff --git a/ml-proto/test/function-local-before-param.fail.wast b/ml-proto/test/function-local-before-param.fail.wast new file mode 100644 index 0000000000..66f35eb6ca --- /dev/null +++ b/ml-proto/test/function-local-before-param.fail.wast @@ -0,0 +1 @@ +(module (func (local i32) (param i32))) diff --git a/ml-proto/test/function-local-before-result.fail.wast b/ml-proto/test/function-local-before-result.fail.wast new file mode 100644 index 0000000000..52026cf765 --- /dev/null +++ b/ml-proto/test/function-local-before-result.fail.wast @@ -0,0 +1 @@ +(module (func (local i32) (result i32) (get_local 0))) diff --git a/ml-proto/test/function-param-after-body.fail.wast b/ml-proto/test/function-param-after-body.fail.wast new file mode 100644 index 0000000000..399a151b83 --- /dev/null +++ b/ml-proto/test/function-param-after-body.fail.wast @@ -0,0 +1 @@ +(module (func (nop) (param i32))) diff --git a/ml-proto/test/function-result-after-body.fail.wast b/ml-proto/test/function-result-after-body.fail.wast new file mode 100644 index 0000000000..9617a2d00f --- /dev/null +++ b/ml-proto/test/function-result-after-body.fail.wast @@ -0,0 +1 @@ +(module (func (nop) (result i32))) diff --git a/ml-proto/test/function-result-before-param.fail.wast b/ml-proto/test/function-result-before-param.fail.wast new file mode 100644 index 0000000000..93a930f429 --- /dev/null +++ b/ml-proto/test/function-result-before-param.fail.wast @@ -0,0 +1 @@ +(module (func (result i32) (param i32) (get_local 0))) diff --git a/ml-proto/test/functions.wast b/ml-proto/test/functions.wast index 0510582d1f..8675e9ed67 100644 --- a/ml-proto/test/functions.wast +++ b/ml-proto/test/functions.wast @@ -1,40 +1,95 @@ (module - (func $empty) - (export "empty" $empty) + (func "empty") - (func $result-nop (nop)) - (export "result-nop" $result-nop) + (func "value-nop" (nop)) + (func "value-drop" (i32.const 1)) + (func "value-block-nop" (block (i32.const 1) (nop))) + (func "value-block-drop" (block (nop) (i32.const 1))) - (func $result-drop (i32.const 1)) - (export "result-drop" $result-drop) + (func "return" (return)) + (func "return-nop" (return (nop))) + (func "return-drop" (return (i32.const 1))) + (func "return-block-nop" (return (block (i32.const 1) (nop)))) + (func "return-block-drop" (return (block (nop) (i32.const 1)))) - (func $result-block-nop (block (i32.const 1) (nop))) - (export "result-block-nop" $result-block-nop) + (func "param" (param i32) (i32.eqz (get_local 0))) + (func "params" (param i32 f64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) + ) + (func "param-param" (param i32) (param f64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) + ) + (func "params-params" (param i32 f32) (param i32) (param f64 i64) + (i32.eqz (get_local 0)) (f32.neg (get_local 1)) (i32.eqz (get_local 2)) + (f64.neg (get_local 3)) (i64.eqz (get_local 4)) + ) - (func $result-block-drop (block (nop) (i32.const 1))) - (export "result-block-drop" $result-block-drop) + (func "result" (result i32) (i32.const 1)) - (func $return (return)) - (export "return" $return) + (func "local" (local i32) (i32.eqz (get_local 0))) + (func "locals" (local i32 f64 i64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) (i64.eqz (get_local 2)) + ) + (func "local-local" (local i32) (local f64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) + ) + (func "locals-locals" (local i32 f32) (local i32) (local f64 i64) + (i32.eqz (get_local 0)) (f32.neg (get_local 1)) (i32.eqz (get_local 2)) + (f64.neg (get_local 3)) (i64.eqz (get_local 4)) + ) - (func $return-nop (return (nop))) - (export "return-nop" $return-nop) + (func "param-result" (param i32) (result i32) (i32.eqz (get_local 0))) + (func "params-result" (param i32 f64) (result i32) + (f64.neg (get_local 1)) (i32.eqz (get_local 0)) + ) + (func "param-param-result" (param i32) (param f64) (result i32) + (f64.neg (get_local 1)) (i32.eqz (get_local 0)) + ) - (func $return-drop (return (i32.const 1))) - (export "return-drop" $return-drop) + (func "result-local" (result i32) (local i32) (i32.eqz (get_local 0))) + (func "result-locals" (result i32) (local i32 f64) + (f64.neg (get_local 1)) (i32.eqz (get_local 0)) + ) + (func "result-local-local" (result i32) (local i32) (local f64) + (f64.neg (get_local 1)) (i32.eqz (get_local 0)) + ) - (func $return-block-nop (return (block (i32.const 1) (nop)))) - (export "return-block-nop" $return-block-nop) + (func "param-local" (param i32) (local f64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) + ) + (func "params-local" (param i32 i64) (local f64) + (i32.eqz (get_local 0)) (i64.eqz (get_local 1)) (f64.neg (get_local 2)) + ) + (func "param-locals" (param i32) (local i64 f64) + (i32.eqz (get_local 0)) (i64.eqz (get_local 1)) (f64.neg (get_local 2)) + ) + (func "params-locals" (param f32 i32) (local i64 f64) + (f32.neg (get_local 0)) (i32.eqz (get_local 1)) + (i64.eqz (get_local 2)) (f64.neg (get_local 3)) + ) + (func "param-params-locals-local" (param f32) (param i32 f32) (local i64 f64) (local i32) + (f32.neg (get_local 0)) (i32.eqz (get_local 1)) (f32.neg (get_local 2)) + (i64.eqz (get_local 3)) (f64.neg (get_local 4)) (i32.eqz (get_local 5)) + ) - (func $return-block-drop (return (block (nop) (i32.const 1)))) - (export "return-block-drop" $return-block-drop) + (func "param-result-local" (param i32) (result f64) (local f64) + (i32.eqz (get_local 0)) (f64.neg (get_local 1)) + ) + (func "params-params-result-locals-locals" + (param i32 i64) (param f32 f64) (result i32) + (local i32 f64) (local i64 f32 i32) + (i32.eqz (get_local 0)) (i64.eqz (get_local 1)) (f32.neg (get_local 2)) + (f64.neg (get_local 3)) (i32.eqz (get_local 4)) (f64.neg (get_local 5)) + (i64.eqz (get_local 6)) (f32.neg (get_local 7)) (i32.eqz (get_local 8)) + ) ) (assert_return (invoke "empty")) -(assert_return (invoke "result-nop")) -(assert_return (invoke "result-drop")) -(assert_return (invoke "result-block-nop")) -(assert_return (invoke "result-block-drop")) + +(assert_return (invoke "value-nop")) +(assert_return (invoke "value-drop")) +(assert_return (invoke "value-block-nop")) +(assert_return (invoke "value-block-drop")) (assert_return (invoke "return")) (assert_return (invoke "return-nop")) @@ -42,3 +97,32 @@ (assert_return (invoke "return-block-nop")) (assert_return (invoke "return-block-drop")) +(assert_return (invoke "param" (i32.const 1))) +(assert_return (invoke "params" (i32.const 1) (f64.const 0))) +(assert_return (invoke "param-param" (i32.const 1) (f64.const 0))) +(assert_return (invoke "params-params" (i32.const 1) (f32.const 0) (i32.const 1) (f64.const 0) (i64.const 1))) + +(assert_return (invoke "result") (i32.const 1)) + +(assert_return (invoke "local")) +(assert_return (invoke "locals")) +(assert_return (invoke "local-local")) +(assert_return (invoke "locals-locals")) + +(assert_return (invoke "param-result" (i32.const 1)) (i32.const 0)) +(assert_return (invoke "params-result" (i32.const 1) (f64.const 0)) (i32.const 0)) +(assert_return (invoke "param-param-result" (i32.const 1) (f64.const 0)) (i32.const 0)) + +(assert_return (invoke "result-local") (i32.const 1)) +(assert_return (invoke "result-locals" ) (i32.const 1)) +(assert_return (invoke "result-local-local") (i32.const 1)) + +(assert_return (invoke "param-local" (i32.const 1))) +(assert_return (invoke "params-local" (i32.const 1) (i64.const 0))) +(assert_return (invoke "param-locals" (i32.const 1))) +(assert_return (invoke "params-locals" (f32.const 1) (i32.const 0))) +(assert_return (invoke "param-params-locals-local" (f32.const 1) (i32.const 0) (f32.const 1))) + +(assert_return (invoke "param-result-local" (i32.const 1)) (f64.const -0)) +(assert_return (invoke "params-params-result-locals-locals" (i32.const 1) (i64.const 1) (f32.const 0) (f64.const 1)) (i32.const 1)) +