2 커밋 20fcb5529e ... 4d060b8bb7

작성자 SHA1 메시지 날짜
  Chimrod 4d060b8bb7 Added typecheck test in the for syntax 3 달 전
  Chimrod 670eac9c96 Included the inline for loop syntax 3 달 전
4개의 변경된 파일107개의 추가작업 그리고 12개의 파일을 삭제
  1. 21 0
      lib/qparser/qsp_single_line.mly
  2. 34 12
      lib/syntax/type_of.ml
  3. 35 0
      test/syntax.ml
  4. 17 0
      test/type_of.ml

+ 21 - 0
lib/qparser/qsp_single_line.mly

@@ -38,6 +38,27 @@ empty:
             ~elifs
             ~else_
       }
+    | FOR
+      local = option(LOCAL)
+      variable = variable
+      EQUAL
+      start = expression
+      TO 
+      to_ = expression
+      step = option(pair(STEP, expression))
+      COLUMN
+      s = rev (final_inline_instruction)
+      END
+      { 
+          let local = match local with 
+            | Some () -> true
+            | _ -> false in
+          let variable = { (Helper.variable variable) with local } in
+          let start = Analyzer.Expression.v start in
+          let to_ = Analyzer.Expression.v to_ in
+          let step = Option.map (fun v -> Analyzer.Expression.v (snd v)) step in
+          Analyzer.Instruction.for_ $loc variable ~start ~to_ ~step s
+      }
 
 final_inline_instruction:
     | hd = inline_instruction 

+ 34 - 12
lib/syntax/type_of.ml

@@ -144,6 +144,7 @@ module TypeBuilder = Compose.Expression (Get_type)
 
 type t' = { result : Get_type.t Lazy.t; pos : S.pos }
 
+(** Evaluate the expression, and extract it’s type. *)
 let arg_of_repr : Get_type.t Lazy.t -> S.pos -> Helper.argument_repr =
  fun type_of pos -> { pos; t = Lazy.force type_of }
 
@@ -210,7 +211,6 @@ module TypedExpression = struct
     let types, report =
       List.fold_left params ~init:([], [])
         ~f:(fun (types, report) (type_of, param) ->
-          ignore type_of;
           let t, r = param in
           let arg = arg_of_repr type_of t.pos in
           (arg :: types, r @ report))
@@ -359,6 +359,10 @@ end
 
 module Expression = TypeBuilder.Make (TypedExpression)
 
+let arg_of_expr : Expression.t' -> Helper.argument_repr * Report.t list =
+ fun (expression, report) ->
+  ({ pos = expression.pos; t = Lazy.force expression.result }, report)
+
 module Instruction = struct
   type t = Report.t list
   type t' = Report.t list
@@ -470,21 +474,39 @@ module Instruction = struct
               [ op1; op2 ] report
         | reports -> reports @ report)
 
+  let ( @@ ) = List.rev_append
+
   let for_ :
       S.pos ->
-      (S.pos, Expression.t') S.variable ->
-      start:Expression.t' ->
-      to_:Expression.t' ->
-      step:Expression.t' option ->
+      (S.pos, expression) S.variable ->
+      start:expression ->
+      to_:expression ->
+      step:expression option ->
       t list ->
       t =
-   fun _loc variable ~start ~to_ ~step statements ->
-    ignore variable;
-    ignore start;
-    ignore to_;
-    ignore step;
-    (* TODO ensure all the variable are INT *)
-    let report = [] in
+   fun pos variable ~start ~to_ ~step statements ->
+    let expected = Helper.[ Fixed Integer ] in
+
+    let variable' =
+      arg_of_repr (Lazy.from_val (Get_type.ident variable)) variable.pos
+    in
+
+    let step_report =
+      Option.map
+        (fun step ->
+          let step, report = arg_of_expr step in
+          Helper.compare_args pos expected [ step ] report)
+        step
+      |> Option.value ~default:[]
+    in
+    let start', report_start = arg_of_expr start
+    and to', report_to = arg_of_expr to_ in
+    let report =
+      Helper.compare_args ~strict:true pos expected [ start' ]
+        (step_report @@ report_start @@ report_to)
+      |> Helper.compare_args ~strict:true pos expected [ to' ]
+      |> Helper.compare_args ~strict:true pos expected [ variable' ]
+    in
     List.fold_left statements ~init:report ~f:(fun acc a ->
         let report = a in
         (List.rev_append report) acc)

+ 35 - 0
test/syntax.ml

@@ -1004,6 +1004,40 @@ end|}
         };
     ]
 
+let inline_for () =
+  _test_instruction {|for i = 0 to 5: msg i|}
+    [
+      Tree.Ast.For
+        {
+          loc = _position;
+          variable =
+            {
+              Tree.Ast.pos = _position;
+              name = "I";
+              index = None;
+              local = false;
+            };
+          start = Tree.Ast.Integer (_position, "0");
+          to_ = Tree.Ast.Integer (_position, "5");
+          step = None;
+          statements =
+            [
+              Tree.Ast.Call
+                ( _position,
+                  T.Msg,
+                  [
+                    Tree.Ast.Ident
+                      {
+                        Tree.Ast.pos = _position;
+                        name = "I";
+                        index = None;
+                        local = false;
+                      };
+                  ] );
+            ];
+        };
+    ]
+
 let test =
   ( "Syntax",
     [
@@ -1077,4 +1111,5 @@ let test =
       Alcotest.test_case "for step ... end" `Quick test_for_end_with_step;
       Alcotest.test_case "local variable" `Quick test_local;
       Alcotest.test_case "local variable in for loop" `Quick test_local_for;
+      Alcotest.test_case "inline for" `Quick inline_for;
     ] )

+ 17 - 0
test/type_of.ml

@@ -76,6 +76,19 @@ let wrong_predicate () =
 
 let concat_text () = _test_instruction {|$a = 'A' + 1|} []
 let increment_string () = _test_instruction {|$a += 1|} (message' Error)
+let for_ok () = _test_instruction {|for i = 0 to 5 step 1: msg i|} []
+
+let for_start_string () =
+  _test_instruction {|for i = '' to 5: msg i|} (message Warn)
+
+let for_to_string () =
+  _test_instruction {|for i = 0 to '': msg i|} (message Warn)
+
+let for_variable () =
+  _test_instruction {|for $i = 0 to 5: msg i|} (message Warn)
+
+let for_step () =
+  _test_instruction {|for i = 0 to 5 step '': msg i|} (message Warn)
 
 let test =
   ( "Typechecking",
@@ -96,4 +109,8 @@ let test =
       Alcotest.test_case "Wrong predicate" `Quick wrong_predicate;
       Alcotest.test_case "+(int, str)" `Quick concat_text;
       Alcotest.test_case "str += int" `Quick increment_string;
+      Alcotest.test_case "correct for" `Quick for_ok;
+      Alcotest.test_case "for i = ''" `Quick for_start_string;
+      Alcotest.test_case "for $i" `Quick for_variable;
+      Alcotest.test_case "for … step ''" `Quick for_step;
     ] )