diff --git a/lib/pinc_bytecode/instruction.ml b/lib/pinc_bytecode/instruction.ml index a91fc44..4015d17 100644 --- a/lib/pinc_bytecode/instruction.ml +++ b/lib/pinc_bytecode/instruction.ml @@ -29,6 +29,8 @@ type t = | I_Record of Int32.t | I_Index | I_Dot_Index + | I_Range + | I_Range_Inclusive let byte = function | I_Pop -> 0x00 @@ -61,6 +63,8 @@ let byte = function | I_Record _ -> 0x1B | I_Index -> 0x1C | I_Dot_Index -> 0x1D + | I_Range -> 0x1E + | I_Range_Inclusive -> 0x1F ;; let operands_length = function @@ -93,7 +97,9 @@ let operands_length = function | I_Null | I_Concat | I_Index - | I_Dot_Index -> 0 + | I_Dot_Index + | I_Range + | I_Range_Inclusive -> 0 ;; let decode bytes offset = @@ -144,6 +150,8 @@ let decode bytes offset = (offset, I_Record length) | 0x1C -> (offset, I_Index) | 0x1D -> (offset, I_Dot_Index) + | 0x1E -> (offset, I_Range) + | 0x1F -> (offset, I_Range_Inclusive) | _ -> raise_notrace (Invalid_argument (Printf.sprintf "unknown instruction: 0x%.2X" instruction)) @@ -180,6 +188,8 @@ let pp fmt = function | I_Record length -> Format.fprintf fmt "I_Record %i" (Int32.to_int length) | I_Index -> Format.fprintf fmt "I_Index" | I_Dot_Index -> Format.fprintf fmt "I_Dot_Index" + | I_Range -> Format.fprintf fmt "I_Range" + | I_Range_Inclusive -> Format.fprintf fmt "I_Range_Inclusive" ;; let to_bytes t = @@ -223,7 +233,9 @@ let to_bytes t = | I_Null | I_Concat | I_Index - | I_Dot_Index -> () + | I_Dot_Index + | I_Range + | I_Range_Inclusive -> () in bytes diff --git a/lib/pinc_compiler/compiler.ml b/lib/pinc_compiler/compiler.ml index c8d1b02..99d72c8 100644 --- a/lib/pinc_compiler/compiler.ml +++ b/lib/pinc_compiler/compiler.ml @@ -226,8 +226,14 @@ and compile_binary_expression t ~left ~op ~right = | Pinc_Types.Operators.Binary.PIPE -> raise_notrace TODO | Pinc_Types.Operators.Binary.ARRAY_ADD -> raise_notrace TODO | Pinc_Types.Operators.Binary.MERGE -> raise_notrace TODO - | Pinc_Types.Operators.Binary.RANGE -> raise_notrace TODO - | Pinc_Types.Operators.Binary.INCLUSIVE_RANGE -> raise_notrace TODO + | Pinc_Types.Operators.Binary.RANGE -> + let t = compile_expr t left in + let t = compile_expr t right in + emit t Pinc_Bytecode.Instruction.I_Range + | Pinc_Types.Operators.Binary.INCLUSIVE_RANGE -> + let t = compile_expr t left in + let t = compile_expr t right in + emit t Pinc_Bytecode.Instruction.I_Range_Inclusive and compile_conditional_expression t ~condition ~consequent ~alternate = (* Condition *) diff --git a/lib/pinc_vm/vm.ml b/lib/pinc_vm/vm.ml index 10ada72..795846c 100644 --- a/lib/pinc_vm/vm.ml +++ b/lib/pinc_vm/vm.ml @@ -46,8 +46,9 @@ let rec execute_binary_operation t op = | Pinc_Types.Operators.Binary.PIPE -> raise_notrace TODO | Pinc_Types.Operators.Binary.ARRAY_ADD -> raise_notrace TODO | Pinc_Types.Operators.Binary.MERGE -> raise_notrace TODO - | Pinc_Types.Operators.Binary.RANGE -> raise_notrace TODO - | Pinc_Types.Operators.Binary.INCLUSIVE_RANGE -> raise_notrace TODO + | Pinc_Types.Operators.Binary.RANGE -> execute_binary_range ~inclusive:false l r + | Pinc_Types.Operators.Binary.INCLUSIVE_RANGE -> + execute_binary_range ~inclusive:true l r in Stack.push t.stack result @@ -179,6 +180,43 @@ and execute_binary_bracket_access l r = ("Trying to access a property on a non record or array value: " ^ Value.to_string l) +and execute_binary_range ~inclusive l r = + let get_range from upto = + match (from, upto) with + | Value.Int from, Value.Int upto -> (from, upto) + | Value.Int from, Value.Float upto when Float.is_integer upto -> + (from, int_of_float upto) + | Value.Float from, Value.Int upto when Float.is_integer from -> + (int_of_float from, upto) + | Value.Float from, Value.Float upto + when Float.is_integer from && Float.is_integer upto -> + (int_of_float from, int_of_float upto) + | Int _, _ -> + raise_notrace + @@ Invalid_argument + "Can't construct range. The end of your range is not of type int." + | _, Int _ -> + raise_notrace + @@ Invalid_argument + "Can't construct range. The start of your range is not of type int." + | _, _ -> + raise_notrace + @@ Invalid_argument + "Can't construct range. The start and end of your range are not of type int." + in + let from_int, upto_int = get_range l r in + if from_int > upto_int then + Value.Array [||] + else ( + let start = from_int in + let stop = + if inclusive then + upto_int + 1 + else + upto_int + in + Value.Array (Array.init (stop - start) (fun i -> Value.Int (i + start)))) + and execute_binary_equal l r = if Value.equal l r then Value.constant_true @@ -286,6 +324,9 @@ let run t = | Instruction.I_Concat -> execute_binary_operation t Operators.Binary.CONCAT | Instruction.I_Index -> execute_binary_operation t Operators.Binary.BRACKET_ACCESS | Instruction.I_Dot_Index -> execute_binary_operation t Operators.Binary.DOT_ACCESS + | Instruction.I_Range -> execute_binary_operation t Operators.Binary.RANGE + | Instruction.I_Range_Inclusive -> + execute_binary_operation t Operators.Binary.INCLUSIVE_RANGE | Instruction.I_Minus -> execute_unary_operation t Operators.Unary.MINUS | Instruction.I_Not -> execute_unary_operation t Operators.Unary.NOT | Instruction.I_Jump addr -> ip := Int32.to_int addr diff --git a/test/vm/array.pi b/test/vm/array.pi index 4902336..dbab415 100644 --- a/test/vm/array.pi +++ b/test/vm/array.pi @@ -13,3 +13,11 @@ component ExpressionArray { component ArrayAccess { [1 + 2, 3 - 4, 5 * 6, 7 / 8][3 - 2] } + +component ArrayRange { + 1..10 +} + +component ArrayRangeInclusive { + 1...10 +} diff --git a/test/vm/run.t b/test/vm/run.t index 5775574..122a639 100644 --- a/test/vm/run.t +++ b/test/vm/run.t @@ -352,6 +352,24 @@ 0060 I_Index 0061 I_Pop + $ NO_COLOR="1" print_vm . ArrayRange + 1 2 3 4 5 6 7 8 9 + + $ NO_COLOR="1" print_instructions . ArrayRange + 0000 I_Constant 0x00000001 (00000001) + 0005 I_Constant 0x00000002 (00000002) + 0010 I_Range + 0011 I_Pop + + $ NO_COLOR="1" print_vm . ArrayRangeInclusive + 1 2 3 4 5 6 7 8 9 10 + + $ NO_COLOR="1" print_instructions . ArrayRangeInclusive + 0000 I_Constant 0x00000001 (00000001) + 0005 I_Constant 0x00000002 (00000002) + 0010 I_Range_Inclusive + 0011 I_Pop + $ NO_COLOR="1" print_vm . Record 1 foo