diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7854e8b..1c6182d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,13 +11,14 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 - - uses: erlef/setup-beam@v1.15.3 + - uses: actions/checkout@v3 + - uses: erlef/setup-beam@v1 with: - otp-version: "25.2" - gleam-version: "0.30.5" + otp-version: "26.0.2" + gleam-version: "0.34.1" rebar3-version: "3" - # elixir-version: "1.14.2" - - run: gleam format --check src test + # elixir-version: "1.15.4" - run: gleam deps download - run: gleam test + - run: gleam format --check src test + diff --git a/gleam.toml b/gleam.toml index 8739904..091faae 100644 --- a/gleam.toml +++ b/gleam.toml @@ -1,11 +1,11 @@ name = "glove" -version = "0.3.0" +version = "0.4.0" description = "Gleam QBE IR Generator" licences = ["MIT"] repository = { type = "github", user = "Willyboar", repo = "glove" } [dependencies] -gleam_stdlib = "~> 0.30" +gleam_stdlib = "~> 0.34 or ~> 1.0" [dev-dependencies] -gleeunit = "~> 0.10" +gleeunit = "~> 1.0" \ No newline at end of file diff --git a/manifest.toml b/manifest.toml index fb5d2c4..7762492 100644 --- a/manifest.toml +++ b/manifest.toml @@ -2,10 +2,10 @@ # You typically do not need to edit this file packages = [ - { name = "gleam_stdlib", version = "0.30.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "03710B3DA047A3683117591707FCA19D32B980229DD8CE8B0603EB5B5144F6C3" }, - { name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" }, + { name = "gleam_stdlib", version = "0.34.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "1FB8454D2991E9B4C0C804544D8A9AD0F6184725E20D63C3155F0AEB4230B016" }, + { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, ] [requirements] -gleam_stdlib = { version = "~> 0.30" } -gleeunit = { version = "~> 0.10" } +gleam_stdlib = { version = "~> 0.34 or ~> 1.0" } +gleeunit = { version = "~> 1.0" } diff --git a/src/glove.gleam b/src/glove.gleam index 3dd73df..7b9d32f 100644 --- a/src/glove.gleam +++ b/src/glove.gleam @@ -1,6 +1,6 @@ import gleam/int import gleam/string -import gleam/option.{None, Option, Some} +import gleam/option.{type Option, None, Some} import gleam/list /// QBE Comparison Operators @@ -83,29 +83,59 @@ pub fn display_inst(inst: Inst) -> String { _ -> case cmp { Slt -> - "c" <> "slt" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "slt" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) Sle -> - "c" <> "sle" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "sle" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) Sgt -> - "c" <> "sgt" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "sgt" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) Sge -> - "c" <> "sge" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "sge" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) Eq -> - "c" <> "eq" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "eq" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) Ne -> - "c" <> "ne" <> " " <> display_type(ty) <> " " <> display_value(a) <> " " <> display_value( - b, - ) + "c" + <> "ne" + <> " " + <> display_type(ty) + <> " " + <> display_value(a) + <> " " + <> display_value(b) } } } @@ -124,7 +154,7 @@ pub fn display_inst(inst: Inst) -> String { Call(name, args) -> { let arg_str = args - |> list.index_map(fn(_, arg) { + |> list.index_map(fn(arg, _) { case arg { #(ty, val) -> display_type(ty) <> " " <> display_value(val) } @@ -141,9 +171,12 @@ pub fn display_inst(inst: Inst) -> String { case typ { Aggregate(_) -> "Store to an aggregate type" _ -> - "store" <> display_type(typ) <> " " <> display_value(value) <> " " <> display_value( - dest, - ) + "store" + <> display_type(typ) + <> " " + <> display_value(value) + <> " " + <> display_value(dest) } Load(typ, val) -> @@ -152,9 +185,12 @@ pub fn display_inst(inst: Inst) -> String { _ -> "load" <> display_type(typ) <> " " <> display_value(val) } Blit(src, dest, n) -> - "blit " <> display_value(src) <> ", " <> display_value(dest) <> ", " <> int.to_string( - n, - ) + "blit " + <> display_value(src) + <> ", " + <> display_value(dest) + <> ", " + <> int.to_string(n) } } @@ -233,6 +269,7 @@ pub fn size(self) -> Int { Aggregate(td) -> case td.items { [] -> 0 + [_, ..] -> 1 } } } @@ -261,14 +298,21 @@ pub fn display_data_def(def: DataDef) -> String { let items_str = def.items - |> list.index_map(fn(_, item) { + |> list.index_map(fn(item, _) { case item { #(ty, di) -> display_type(ty) <> " " <> display_data_item(di) } }) |> string.join(", ") - linkage_str <> "data $" <> def.name <> " =" <> align_str <> " { " <> items_str <> " }" + linkage_str + <> "data $" + <> def.name + <> " =" + <> align_str + <> " { " + <> items_str + <> " }" } /// QBE aggregate type definition @@ -285,7 +329,7 @@ pub fn display_type_def(def: TypeDef) -> String { let items_str = def.items - |> list.index_map(fn(_, item) { + |> list.index_map(fn(item, _) { case item { #(ty, count) -> case count > 1 { @@ -333,9 +377,11 @@ pub type Statement { pub fn display_statement(stmt: Statement) -> String { case stmt { Assign(val, typ, inst) -> - display_value(val) <> " =" <> display_type(typ) <> " " <> display_inst( - inst, - ) + display_value(val) + <> " =" + <> display_type(typ) + <> " " + <> display_inst(inst) Volatile(inst) -> display_inst(inst) } } @@ -412,7 +458,18 @@ pub fn display_function(func: Function) -> String { let args_str = display_arguments(func.arguments) let blocks_str = display_blocks(func.blocks) - linkage_str <> "function" <> return_str <> " " <> "$" <> name_str <> "(" <> args_str <> ")" <> " {\n" <> blocks_str <> "}" + linkage_str + <> "function" + <> return_str + <> " " + <> "$" + <> name_str + <> "(" + <> args_str + <> ")" + <> " {\n" + <> blocks_str + <> "}" } /// Display functions Arguments @@ -421,7 +478,7 @@ pub fn display_arguments(arguments: List(#(Type, Value))) -> String { [] -> "" _ -> arguments - |> list.index_map(fn(_, arg) { + |> list.index_map(fn(arg, _) { case arg { #(ty, val) -> display_type(ty) <> " " <> display_value(val) } @@ -476,10 +533,14 @@ pub fn display_linkage(linkage: Linkage) -> String { } let section_str = case linkage.section { Some(section) -> - "section \"" <> section <> "\"" <> case linkage.secflags { + "section \"" + <> section + <> "\"" + <> case linkage.secflags { Some(secflags) -> " \"" <> secflags <> "\"" None -> "" - } <> " " + } + <> " " None -> "" } exported_str <> section_str diff --git a/test/glove_test.gleam b/test/glove_test.gleam index 9f17e6c..23d1b43 100644 --- a/test/glove_test.gleam +++ b/test/glove_test.gleam @@ -155,11 +155,11 @@ pub fn display_type_def_test() { // Test case 2: TypeDef with alignment and multiple items let def2 = - glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - ) + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]) def2 |> glove.display_type_def |> should.equal("type :struct = align 4 { w 2, w, w 3 }") @@ -211,13 +211,10 @@ pub fn display_type_test() { pub fn display_inst_test() { // Test case for Call with 2 args let call1 = - glove.Call( - glove.Global("vadd"), - [ - #(glove.Single, glove.Temporary("a")), - #(glove.Long, glove.Temporary("ap")), - ], - ) + glove.Call(glove.Global("vadd"), [ + #(glove.Single, glove.Temporary("a")), + #(glove.Long, glove.Temporary("ap")), + ]) call1 |> glove.display_inst |> should.equal("call $vadd(s %a, l %ap)") @@ -280,11 +277,13 @@ pub fn display_inst_test() { // Test case for comparing aggregate types let comp2 = glove.Comp( - glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - )), + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), glove.Eq, glove.Temporary("a"), glove.Temporary("b"), @@ -368,11 +367,13 @@ pub fn display_inst_test() { // Test case for storing an aggregate value let store2 = glove.Store( - glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - )), + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), glove.Const(42), glove.Temporary("%r5"), ) @@ -383,11 +384,13 @@ pub fn display_inst_test() { // Test case for loading an aggregate value let load2 = glove.Load( - glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - )), + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), glove.Temporary("%r6"), ) load2 @@ -481,16 +484,14 @@ pub fn display_function_test() { arguments: [], return_ty: Some(glove.Word), blocks: [ - glove.Block( - "@start", - [ - glove.Volatile(glove.Call( - glove.Global("puts"), - [#(glove.Long, glove.Global("str"))], - )), - glove.Volatile(glove.Ret(Some(glove.Const(0)))), - ], - ), + glove.Block("@start", [ + glove.Volatile( + glove.Call(glove.Global("puts"), [ + #(glove.Long, glove.Global("str")), + ]), + ), + glove.Volatile(glove.Ret(Some(glove.Const(0)))), + ]), ], ) @@ -504,16 +505,12 @@ pub fn display_function_test() { // Tests for display QBE.Blocks pub fn display_blocks_test() { let blocks = [ - glove.Block( - "@start", - [ - glove.Volatile(glove.Call( - glove.Global("puts"), - [#(glove.Long, glove.Global("str"))], - )), - glove.Volatile(glove.Ret(Some(glove.Const(0)))), - ], - ), + glove.Block("@start", [ + glove.Volatile( + glove.Call(glove.Global("puts"), [#(glove.Long, glove.Global("str"))]), + ), + glove.Volatile(glove.Ret(Some(glove.Const(0)))), + ]), ] let expected = "@start\ncall $puts(l $str)\nret 0\n" @@ -555,17 +552,14 @@ pub fn display_module_test() { ], return_ty: Some(glove.Word), blocks: [ - glove.Block( - label: "@start", - statements: [ - glove.Assign( - glove.Temporary("c"), - glove.Word, - glove.Add(glove.Temporary("a"), glove.Temporary("b")), - ), - glove.Volatile(glove.Ret(Some(glove.Temporary("c")))), - ], - ), + glove.Block(label: "@start", statements: [ + glove.Assign( + glove.Temporary("c"), + glove.Word, + glove.Add(glove.Temporary("a"), glove.Temporary("b")), + ), + glove.Volatile(glove.Ret(Some(glove.Temporary("c")))), + ]), ], ) @@ -576,42 +570,33 @@ pub fn display_module_test() { arguments: [], return_ty: Some(glove.Word), blocks: [ - glove.Block( - label: "@start", - statements: [ - glove.Assign( - glove.Temporary("r"), - glove.Word, - glove.Call( - glove.Global("add"), - [#(glove.Word, glove.Const(1)), #(glove.Word, glove.Const(1))], - ), - ), - glove.Volatile(glove.Call( - glove.Global("printf"), - [ - #(glove.Long, glove.Global("fmt")), - #(glove.Word, glove.Temporary("r")), - ], - )), - glove.Volatile(glove.Ret(Some(glove.Const(0)))), - ], - ), + glove.Block(label: "@start", statements: [ + glove.Assign( + glove.Temporary("r"), + glove.Word, + glove.Call(glove.Global("add"), [ + #(glove.Word, glove.Const(1)), + #(glove.Word, glove.Const(1)), + ]), + ), + glove.Volatile( + glove.Call(glove.Global("printf"), [ + #(glove.Long, glove.Global("fmt")), + #(glove.Word, glove.Temporary("r")), + ]), + ), + glove.Volatile(glove.Ret(Some(glove.Const(0)))), + ]), ], ) let functions = [add_func, main_func] let fmt_data = - glove.DataDef( - linkage: glove.private(), - name: "fmt", - align: None, - items: [ - #(glove.Byte, glove.Str("One and one make %d!\n")), - #(glove.Byte, glove.Constant(0)), - ], - ) + glove.DataDef(linkage: glove.private(), name: "fmt", align: None, items: [ + #(glove.Byte, glove.Str("One and one make %d!\n")), + #(glove.Byte, glove.Constant(0)), + ]) let data = [fmt_data] @@ -620,7 +605,17 @@ pub fn display_module_test() { module |> glove.display_module |> should.equal( - "function w $add(w %a, w %b) {\n" <> "@start\n" <> "%c =w add %a, %b\n" <> "ret %c\n}\n" <> "export function w $main() {\n" <> "@start\n" <> "%r =w call $add(w 1, w 1)\n" <> "call $printf(l $fmt, w %r)\n" <> "ret 0\n}\n" <> "data $fmt = " <> "{ b \"One and one make %d!\n\", b 0 }", + "function w $add(w %a, w %b) {\n" + <> "@start\n" + <> "%c =w add %a, %b\n" + <> "ret %c\n}\n" + <> "export function w $main() {\n" + <> "@start\n" + <> "%r =w call $add(w 1, w 1)\n" + <> "call $printf(l $fmt, w %r)\n" + <> "ret 0\n}\n" + <> "data $fmt = " + <> "{ b \"One and one make %d!\n\", b 0 }", ) } @@ -674,10 +669,9 @@ pub fn add_type_test() { // Assert the type definition is added to the module should.equal(updated_module.functions, []) - should.equal( - updated_module.types, - [glove.TypeDef("my_type", None, [#(glove.Word, 2), #(glove.Word, 3)])], - ) + should.equal(updated_module.types, [ + glove.TypeDef("my_type", None, [#(glove.Word, 2), #(glove.Word, 3)]), + ]) should.equal(updated_module.data, []) } @@ -701,58 +695,52 @@ pub fn assign_inst_test() { pub fn jumps_test() { let block_with_jump = - glove.Block( - label: "my_block", - statements: [ - glove.Assign( - glove.Temporary("r"), - glove.Word, - glove.Call( - glove.Global("add"), - [#(glove.Word, glove.Const(1)), #(glove.Word, glove.Const(1))], - ), - ), - glove.Volatile(glove.Ret(Some(glove.Const(0)))), - // Non-jump instruction - glove.Assign( - glove.Temporary("r"), - glove.Word, - glove.Call( - glove.Global("add"), - [#(glove.Word, glove.Const(1)), #(glove.Word, glove.Const(1))], - ), - ), - glove.Volatile(glove.Jmp("label")), - ], - ) + glove.Block(label: "my_block", statements: [ + glove.Assign( + glove.Temporary("r"), + glove.Word, + glove.Call(glove.Global("add"), [ + #(glove.Word, glove.Const(1)), + #(glove.Word, glove.Const(1)), + ]), + ), + glove.Volatile(glove.Ret(Some(glove.Const(0)))), + // Non-jump instruction + glove.Assign( + glove.Temporary("r"), + glove.Word, + glove.Call(glove.Global("add"), [ + #(glove.Word, glove.Const(1)), + #(glove.Word, glove.Const(1)), + ]), + ), + glove.Volatile(glove.Jmp("label")), + ]) should.equal(glove.jumps(block_with_jump), True) let block_without_jump = - glove.Block( - label: "my_block", - statements: [ - glove.Assign( - glove.Temporary("r"), - glove.Word, - glove.Call( - glove.Global("add"), - [#(glove.Word, glove.Const(1)), #(glove.Word, glove.Const(1))], - ), - ), - glove.Volatile(glove.Ret(Some(glove.Const(0)))), - // Non-jump instruction - glove.Assign( - glove.Temporary("r"), - glove.Word, - glove.Call( - glove.Global("add"), - [#(glove.Word, glove.Const(1)), #(glove.Word, glove.Const(1))], - ), - ), - glove.Volatile(glove.Add(glove.Const(1), glove.Const(2))), - ], - ) + glove.Block(label: "my_block", statements: [ + glove.Assign( + glove.Temporary("r"), + glove.Word, + glove.Call(glove.Global("add"), [ + #(glove.Word, glove.Const(1)), + #(glove.Word, glove.Const(1)), + ]), + ), + glove.Volatile(glove.Ret(Some(glove.Const(0)))), + // Non-jump instruction + glove.Assign( + glove.Temporary("r"), + glove.Word, + glove.Call(glove.Global("add"), [ + #(glove.Word, glove.Const(1)), + #(glove.Word, glove.Const(1)), + ]), + ), + glove.Volatile(glove.Add(glove.Const(1), glove.Const(2))), + ]) should.equal(glove.jumps(block_without_jump), False) } @@ -799,16 +787,22 @@ pub fn into_abi_test() { should.equal(glove.into_abi(glove.Long), glove.Long) should.equal(glove.into_abi(glove.Double), glove.Double) should.equal( - glove.into_abi(glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - ))), - glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - )), + glove.into_abi( + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), + ), + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), ) // Assuming td is a valid `TypeDef` } @@ -821,11 +815,15 @@ pub fn into_base_test() { should.equal(glove.into_base(glove.Long), glove.Long) should.equal(glove.into_base(glove.Double), glove.Double) should.equal( - glove.into_base(glove.Aggregate(glove.TypeDef( - "struct", - Some(4), - [#(glove.Word, 2), #(glove.Word, 1), #(glove.Word, 3)], - ))), + glove.into_base( + glove.Aggregate( + glove.TypeDef("struct", Some(4), [ + #(glove.Word, 2), + #(glove.Word, 1), + #(glove.Word, 3), + ]), + ), + ), glove.Long, ) // Assuming td is a valid `TypeDef`