diff --git a/lib/ast.ml b/lib/ast.ml index 27eea91..2ef75ae 100644 --- a/lib/ast.ml +++ b/lib/ast.ml @@ -51,6 +51,16 @@ module ReadSpreadsheet = struct ;; end +module Import = struct + type t = + { var : Variable.T.t + ; from : Variable.T.t + } + [@@deriving sexp] + + let to_string node = Printf.sprintf "Import %s from %s" node.var node.from +end + module Export = struct type t = | File of string @@ -71,6 +81,7 @@ module Node = struct | ReadConstant of ReadConstant.t | ReadVariable of ReadVariable.t | ReadSpreadsheet of ReadSpreadsheet.t + | Import of Import.t | Export of Export.t [@@deriving sexp] @@ -79,6 +90,7 @@ module Node = struct | ReadConstant n -> ReadConstant.to_string n | ReadVariable n -> ReadVariable.to_string n | ReadSpreadsheet n -> ReadSpreadsheet.to_string n + | Import n -> Import.to_string n | Export n -> Export.to_string n ;; end diff --git a/lib/ast.mli b/lib/ast.mli index 1767a48..4fc489c 100644 --- a/lib/ast.mli +++ b/lib/ast.mli @@ -32,6 +32,17 @@ module ReadSpreadsheet : sig val to_string : t -> string end +module Import : sig + type t = + { var : Variable.T.t + ; from : Variable.T.t + } + + val t_of_sexp : Sexplib0.Sexp.t -> t + val sexp_of_t : t -> Sexplib0.Sexp.t + val to_string : t -> string +end + module Export : sig type t = | File of string @@ -47,6 +58,7 @@ module Node : sig | ReadConstant of ReadConstant.t | ReadVariable of ReadVariable.t | ReadSpreadsheet of ReadSpreadsheet.t + | Import of Import.t | Export of Export.t val t_of_sexp : Sexplib0.Sexp.t -> t diff --git a/lib/import.ml b/lib/import.ml new file mode 100644 index 0000000..c2af255 --- /dev/null +++ b/lib/import.ml @@ -0,0 +1,3 @@ +module T = struct + let to_string (var, from) = Printf.sprintf "import { %s } from \"%s\";" var from +end diff --git a/lib/import.mli b/lib/import.mli new file mode 100644 index 0000000..707ccbb --- /dev/null +++ b/lib/import.mli @@ -0,0 +1,3 @@ +module T : sig + val to_string : string * Variable.T.t -> string +end diff --git a/lib/interpreter.ml b/lib/interpreter.ml index 0b36f8c..9e2fdeb 100644 --- a/lib/interpreter.ml +++ b/lib/interpreter.ml @@ -3,6 +3,7 @@ module T = struct { variable_store : Literal.T.v Store.T.t ; spreadsheet_store : Spreadsheet.t Store.T.t ; interface_set : Variable.T.t Store.T.t + ; import_store : Variable.T.t Store.T.t } let interpret_read_constant state (node : Ast.ReadConstant.t) = @@ -39,7 +40,15 @@ module T = struct | Csv p -> interpret_csv_spreadsheet state variable interface p ;; + let interpret_import state (node : Ast.Import.t) = + let target, from = node.var, node.from in + if not (Variable.T.is_valid target) + then failwith ("invalid import value name " ^ target); + Store.T.set_key state.import_store target from + ;; + let interpret_export state (node : Ast.Export.t) = + let import_contents = Store.T.to_string state.import_store Import.T.to_string in let var_contents = Store.T.to_string state.variable_store Literal.T.to_string in let spreadsheet_contents = Store.T.to_string state.spreadsheet_store Spreadsheet.Writer.to_string @@ -48,8 +57,10 @@ module T = struct Printf.sprintf {| %s +%s %s |} + import_contents var_contents spreadsheet_contents in @@ -69,6 +80,7 @@ module T = struct | Ast.Node.ReadConstant n -> interpret_read_constant state n | Ast.Node.ReadVariable n -> interpret_read_variable state n | Ast.Node.ReadSpreadsheet n -> interpret_read_spreadsheet state n + | Ast.Node.Import n -> interpret_import state n | Ast.Node.Export n -> interpret_export state n; reset_state state @@ -78,6 +90,7 @@ module T = struct { variable_store = Store.T.create () ; spreadsheet_store = Store.T.create () ; interface_set = Store.T.create () + ; import_store = Store.T.create () } ;; diff --git a/lib/interpreter.mli b/lib/interpreter.mli index 6164053..3b9ef55 100644 --- a/lib/interpreter.mli +++ b/lib/interpreter.mli @@ -3,6 +3,7 @@ module T : sig { variable_store : Literal.T.v Store.T.t ; spreadsheet_store : Spreadsheet.t Store.T.t ; interface_set : Variable.T.t Store.T.t + ; import_store : Variable.T.t Store.T.t } val interpret_node : state -> Ast.Node.t -> unit diff --git a/test/expect_tests/cases/basic_program_test.sexp b/test/expect_tests/cases/basic_program_test.sexp index 056eaa3..8337b5c 100644 --- a/test/expect_tests/cases/basic_program_test.sexp +++ b/test/expect_tests/cases/basic_program_test.sexp @@ -1,4 +1,5 @@ ( + (Import ((var SomeEnum) (from some-file.ts))) (ReadConstant ((var "thing") (value (String "ABCDEF")))) (ReadConstant ((var "thing2") (value (Integer 123)))) (ReadVariable ((var "thing3") (value (Float 3.14)))) diff --git a/test/expect_tests/cases/fail_dupe_import.sexp b/test/expect_tests/cases/fail_dupe_import.sexp new file mode 100644 index 0000000..294cfde --- /dev/null +++ b/test/expect_tests/cases/fail_dupe_import.sexp @@ -0,0 +1,5 @@ +( + (Import ((var SomeEnum) (from some-file.ts))) + (Import ((var SomeEnum) (from some-file-2.ts))) + (Export Stdout) +) diff --git a/test/expect_tests/cases/long_program_test.sexp b/test/expect_tests/cases/long_program_test.sexp index ea05f94..c837838 100644 --- a/test/expect_tests/cases/long_program_test.sexp +++ b/test/expect_tests/cases/long_program_test.sexp @@ -1,4 +1,7 @@ ( + (Import ((var SomeEnum) (from some-file.ts))) + (Import ((var SomeOtherEnum) (from some-other-file.ts))) + (Import ((var SomeOtherEnum2) (from some-other-file.ts))) (ReadConstant ((var "thing") (value (String "ABCDEF")))) (ReadConstant ((var "thing2") (value (Integer 123)))) (ReadSpreadsheet ((var "spreadsheet_123") (interface "SomeType") (path (Csv "./data/sample_spreadsheet.csv")))) diff --git a/test/expect_tests/cases/medium_program_test.sexp b/test/expect_tests/cases/medium_program_test.sexp index f6fa36b..d66e135 100644 --- a/test/expect_tests/cases/medium_program_test.sexp +++ b/test/expect_tests/cases/medium_program_test.sexp @@ -1,4 +1,6 @@ ( + (Import ((var SomeEnum) (from some-file.ts))) + (Import ((var SomeOtherEnum) (from some-other-file.ts))) (ReadConstant ((var "dataset_name") (value (String "PEOPLE_NAMES")))) (ReadSpreadsheet ((var "people_names") (interface "Person") (path (Csv "./data/sample_spreadsheet_medium.csv")))) (Export Stdout) diff --git a/test/expect_tests/end_to_end_program_tests.ml b/test/expect_tests/end_to_end_program_tests.ml index e9b473c..1c15f4d 100644 --- a/test/expect_tests/end_to_end_program_tests.ml +++ b/test/expect_tests/end_to_end_program_tests.ml @@ -6,6 +6,7 @@ let%expect_test "passes basic end to end test" = Entry.entry_point "basic_program_test.sexp"; [%expect {| + import { SomeEnum } from "some-file.ts"; export const thing2: number = 123; export const thing5: string = "a afsdafds afsdsa"; export const thing: string = "ABCDEF"; @@ -31,6 +32,8 @@ let%expect_test "passes long end to end test" = Entry.entry_point "medium_program_test.sexp"; [%expect {| + import { SomeEnum } from "some-file.ts"; + import { SomeOtherEnum } from "some-other-file.ts"; export const dataset_name: string = "PEOPLE_NAMES"; export interface Person { @@ -79,6 +82,9 @@ let%expect_test "passes long end to end test" = Entry.entry_point "long_program_test.sexp"; [%expect {| + import { SomeEnum } from "some-file.ts"; + import { SomeOtherEnum } from "some-other-file.ts"; + import { SomeOtherEnum2 } from "some-other-file.ts"; export const thing2: number = 123; export const thing: string = "ABCDEF"; @@ -260,3 +266,10 @@ let%expect_test "fails on duplicate interface name" = print_endline msg; [%expect {| variable SomeType already set |}] ;; + +let%expect_test "fails on duplicate imported modules" = + try Entry.entry_point "fail_dupe_import.sexp" with + | Failure msg -> + print_endline msg; + [%expect {| variable SomeEnum already set |}] +;; diff --git a/test/expect_tests/import_tests.ml b/test/expect_tests/import_tests.ml new file mode 100644 index 0000000..0d097c9 --- /dev/null +++ b/test/expect_tests/import_tests.ml @@ -0,0 +1,66 @@ +open Conkeldurr + +let%expect_test "can import a basic file" = + let program = + {| + ((Import ((var abc) (from banana.ts))) + (Export Stdout)) + |} + in + program |> Program.T.of_string |> Interpreter.T.interpret; + [%expect + {| + import { abc } from "banana.ts"; + |}] +;; + +let%expect_test "can import multiple files" = + let program = + {| + ( + (Import ((var abc) (from banana/banana))) + (Import ((var def) (from abcdef))) + (Import ((var react) (from react))) + (Export Stdout)) + |} + in + program |> Program.T.of_string |> Interpreter.T.interpret; + [%expect + {| + import { abc } from "banana/banana"; + import { def } from "abcdef"; + import { react } from "react"; + |}] +;; + +let%expect_test "can import multiple exports from one file" = + let program = + {| + ( + (Import ((var abc) (from banana/banana))) + (Import ((var def) (from banana/banana))) + (Export Stdout)) + |} + in + program |> Program.T.of_string |> Interpreter.T.interpret; + [%expect + {| + import { abc } from "banana/banana"; + import { def } from "banana/banana"; + |}] +;; + +let%expect_test "fails on importing identical exports" = + let program = + {| + ( + (Import ((var abc) (from banana/banana))) + (Import ((var abc) (from abcdef))) + (Export Stdout)) + |} + in + try program |> Program.T.of_string |> Interpreter.T.interpret with + | Failure msg -> + print_endline msg; + [%expect {| variable abc already set |}] +;;