diff --git a/lib/pinc_compiler/compiler.ml b/lib/pinc_compiler/compiler.ml index d08c116..9d06697 100644 --- a/lib/pinc_compiler/compiler.ml +++ b/lib/pinc_compiler/compiler.ml @@ -1,4 +1,4 @@ -exception TODO +exception TODO of string type emitted_instruction = { offset : int; @@ -256,6 +256,15 @@ let emit_set_symbol t symbol = t ;; +let get_declaration_id ~loc t name = + let id = StringMap.find_opt name t.declaration_ids in + match id with + | None -> Pinc_Diagnostics.raise_error loc ("Unbound declaration `" ^ name ^ "`") + | Some id -> id +;; + +let emit_get_declaration t id = emit t @@ Pinc_Bytecode.Instruction.I_Get_Declaration id + let rec compile_expr t (expr : Pinc_Types.Ast.expression) = let loc = expr.expression_loc in match expr.expression_desc with @@ -275,7 +284,7 @@ let rec compile_expr t (expr : Pinc_Types.Ast.expression) = compile_function t ~identifier ~parameters ~body | FunctionCall { function_definition; arguments } -> compile_function_call t ~fn:function_definition ~arguments - | TagExpression _ -> raise_notrace TODO + | TagExpression _ -> raise_notrace (TODO "Tag Expression") | ForInExpression { index; iterator; reverse; iterable; body } -> compile_loop_expression t ~index ~iterator ~reverse ~iterable ~body | TemplateExpression node -> compile_template_node t node @@ -324,10 +333,8 @@ and compile_lowercase_identifier t ~loc id = emit_get_symbol t symbol and compile_uppercase_identifier t ~loc name = - let id = StringMap.find_opt name t.declaration_ids in - match id with - | None -> Pinc_Diagnostics.raise_error loc ("Unbound declaration `" ^ name ^ "`") - | Some id -> emit t @@ Pinc_Bytecode.Instruction.I_Get_Declaration id + let id = get_declaration_id t ~loc name in + emit_get_declaration t id and compile_external_function t ~loc ~name ~parameters = let index = @@ -517,7 +524,7 @@ and compile_binary_expression t ~left ~op ~right = | Pinc_Types.Ast.LowercaseIdentifierExpression id -> emit_constant t (Pinc_Bytecode.Value.String id) | _ -> - (* TODO: We should be able to encode this into the type system *) + (* FIXME: We should be able to encode this into the type system *) assert false in emit t Pinc_Bytecode.Instruction.I_Dot_Index @@ -736,7 +743,12 @@ and compile_template_node t (node : Pinc_Types.Ast.template_node) = html_tag_attributes = attributes; html_tag_children = children; } -> compile_template_node_html_tag t ~id ~attributes ~children - | ComponentTemplateNode _ -> raise_notrace TODO + | ComponentTemplateNode + { + component_tag_identifier = id; + component_tag_attributes = attributes; + component_tag_children = children; + } -> compile_template_node_component t ~id ~attributes ~children and compile_template_node_html_tag t ~id ~attributes ~children = let t = emit_constant t (Pinc_Bytecode.Value.String id) in @@ -745,6 +757,15 @@ and compile_template_node_html_tag t ~id ~attributes ~children = let t = emit t @@ Pinc_Bytecode.Instruction.I_Html_Template in t +and compile_template_node_component t ~id ~attributes ~children = + let (Pinc_Types.Ast.Uppercase_Id (id, loc)) = id in + let id = get_declaration_id t ~loc id in + let t = emit_get_declaration t id in + let t = compile_template_node_attributes t attributes in + let t = compile_template_node_children t children in + let t = emit t @@ Pinc_Bytecode.Instruction.I_Call 2 in + t + and compile_template_node_fragment t children = let t = compile_template_node_children t children in let t = emit t @@ Pinc_Bytecode.Instruction.I_Fragment_Template in @@ -781,15 +802,6 @@ let compile_template_declaration t identifier declaration = ({ t with symbol_table }, symbol) in let t = add_frame t in - (* TODO: Count tag symbols in body and define them as parameters to the declaration *) - (* - let t = - List.fold_left - (fun t (Pinc_Types.Ast.Lowercase_Id (name, _)) -> - fst @@ define_symbol t name ~is_mutable:false) - t - parameters - in *) let t = let body = declaration.Pinc_Types.Ast.declaration_body in match body.Pinc_Types.Ast.expression_desc with @@ -819,8 +831,8 @@ let compile_template_declaration t identifier declaration = let num_free_variables = List.length free_variables in assert (num_free_variables = 0); - (* TODO: set num_parameters *) - let num_parameters = 0 in + (* The number of parameters is fixed to 2 (props and children) *) + let num_parameters = 2 in let instructions = Dynarray.to_array @@ frame.instructions in let fn_addr, t = add_constant t @@ -863,7 +875,7 @@ let compile_declaration ~declaration_ids name (declaration : Pinc_Types.Ast.decl (Pinc_Bytecode.Bytecode.Template, compile_template_declaration t name declaration) | Declaration_Library -> (Pinc_Bytecode.Bytecode.Library, compile_library_declaration t name declaration) - | Declaration_Store -> raise TODO + | Declaration_Store -> raise_notrace (TODO "Store Declaration") in let instructions = Dynarray.to_array @@ current_instructions t in let constants = t.constants in diff --git a/lib/pinc_vm/vm.ml b/lib/pinc_vm/vm.ml index 2a0d749..10fbf2e 100644 --- a/lib/pinc_vm/vm.ml +++ b/lib/pinc_vm/vm.ml @@ -16,6 +16,7 @@ type t = { } and declaration = { + kind : Bytecode.declaration_kind; instructions : (t -> t) Array.t; value : Value.t option; } @@ -774,6 +775,18 @@ and call_closure ~closure ~num_arguments t = call_current_instruction t ;; +let execute_root_declaration_call t = + (* + TODO: + This should be marked as the top level declaration call, + so tags can change their behavior from looking into the arguments to requesting the data dynamically + *) + let fn = Stack.top t.stack in + match fn with + | Value.Closure closure -> call_closure t ~closure ~num_arguments:0 + | _ -> assert false +;; + let execute_length t = let value = Stack.pop_value t.stack in let len = @@ -791,7 +804,7 @@ let execute_length t = let debug_print_stack t = Format.printf "--------- (STACK) -------\n%!"; - Stack.iter (fun value -> Format.printf "%a%!" Value.pp value) t.stack; + Stack.iteri (fun i value -> Format.printf "[%i] %a%!" i Value.pp value) t.stack; Format.printf "--------- (/STACK) -------\n%!" ;; @@ -901,19 +914,34 @@ let execute_get_local addr = let execute_get_declaration name = fun t -> let declaration = StringMap.find name t.declarations in - let instructions = Array.append declaration.instructions [| execute_halt |] in + let kind = declaration.kind in let t = - match declaration.value with - | Some value -> + match (kind, declaration.value) with + | Library, Some value -> Stack.push_value t.stack value; t - | None -> + | Library, None -> + let instructions = Array.append declaration.instructions [| execute_halt |] in let t' = copy t ~instructions in let t' = call_current_instruction t' in let value = Stack.top t'.stack in Stack.push_value t.stack value; - (* TODO: Only memoize library declarations *) memoize_declaration t name value + | Template, _ -> + let instructions = Array.append declaration.instructions [| execute_halt |] in + (* + TODO: (PERFORMANCE) + This copy is not needed and allocates a lot just to put a closure onto the stack. + The address spaces for the different components are separate, so they are already isolated. + I currently need the copy to create the new main frame and call its instructions. + An alternative would be to use a sequence or iterator of instructions into which I can + insert instructions in between. + *) + let t' = copy t ~instructions in + let t' = call_current_instruction t' in + let value = Stack.top t'.stack in + Stack.push_value t.stack value; + t in call_next_instruction t ;; @@ -930,6 +958,14 @@ let execute_array t = call_next_instruction t ;; +let execute_array_static length = + fun t -> + let elements = Stack.pop_n t.stack length in + let value = Value.Array elements in + Stack.push_value t.stack value; + call_next_instruction t +;; + let execute_record length = fun t -> let values = Array.to_list @@ Stack.pop_n t.stack length in @@ -1205,7 +1241,7 @@ let eval ~root bytecode = | Some { kind = Pinc_Bytecode.Bytecode.Library; _ } -> [| execute_halt |] | Some { kind = Pinc_Bytecode.Bytecode.Template; instructions; _ } -> let resolved = resolve_instructions ~declarations instructions in - Array.append resolved [| execute_function_call 0; execute_halt |] + Array.append resolved [| execute_root_declaration_call; execute_halt |] in let resolved_functions = @@ -1215,8 +1251,9 @@ let eval ~root bytecode = let declarations = StringMap.map (function - | Pinc_Bytecode.Bytecode.{ instructions; _ } -> + | Pinc_Bytecode.Bytecode.{ instructions; kind; _ } -> { + kind; instructions = resolve_instructions ~declarations instructions; value = None; }) diff --git a/lib/pinc_vm/vm_stack.ml b/lib/pinc_vm/vm_stack.ml index 3f0b018..0e239e7 100644 --- a/lib/pinc_vm/vm_stack.ml +++ b/lib/pinc_vm/vm_stack.ml @@ -249,3 +249,9 @@ let iter fn t = fn @@ nth t i done ;; + +let iteri fn t = + for i = 0 to t.stack_pointer - 1 do + fn i @@ nth t i + done +;; diff --git a/test/vm/component/component.pi b/test/vm/component/component.pi new file mode 100644 index 0000000..ab19c41 --- /dev/null +++ b/test/vm/component/component.pi @@ -0,0 +1,9 @@ +component Headline { +