From 5b58a8f387e44bcf1f664cfc31ab7ea6ed359fa3 Mon Sep 17 00:00:00 2001 From: Willyboar Date: Sun, 28 May 2023 21:21:52 +0300 Subject: [PATCH] Implement display funtions and tests --- src/glove.gleam | 48 +++++++++++++---- test/glove_test.gleam | 119 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 151 insertions(+), 16 deletions(-) diff --git a/src/glove.gleam b/src/glove.gleam index e8f83d8..6be4eef 100644 --- a/src/glove.gleam +++ b/src/glove.gleam @@ -70,7 +70,6 @@ pub type Inst { } /// Display function for Instructions -/// UNFINISHED pub fn display_inst(inst: Inst) -> String { case inst { Add(a, b) -> "add " <> display_value(a) <> ", " <> display_value(b) @@ -115,8 +114,8 @@ pub fn display_inst(inst: Inst) -> String { Copy(val) -> "copy " <> display_value(val) Ret(val) -> { case val { - Some(val) -> "ret " <> display_value(val) - None -> "ret" + Some(val) -> "ret " <> display_value(val) <> "\n" + None -> "ret\n" } } Jnz(val, if_nonzero, if_zero) -> @@ -239,7 +238,7 @@ pub fn new_datadef() -> DataDef { pub fn display_data_def(def: DataDef) -> String { let linkage_str = display_linkage(def.linkage) let align_str = case def.align { - Some(align) -> "align " <> int.to_string(align) + Some(align) -> " align " <> int.to_string(align) None -> "" } @@ -252,7 +251,7 @@ pub fn display_data_def(def: DataDef) -> String { }) |> string.join(", ") - linkage_str <> "data $" <> def.name <> " = " <> align_str <> " { " <> items_str <> " }" + linkage_str <> "data $" <> def.name <> " =" <> align_str <> " { " <> items_str <> " }" } /// QBE aggregate type definition @@ -337,7 +336,7 @@ pub fn display_block(block: Block) -> String { |> list.map(display_statement) |> string.join("\n") - label <> ":\n" <> statements + label <> "\n" <> statements } /// Adds a new instruction to the block @@ -360,15 +359,44 @@ pub type Function { Function( linkage: Linkage, name: String, - arguments: #(Type, Value), - return_ty: Type, + arguments: List(#(Type, Value)), + return_ty: Option(Type), blocks: List(Block), ) } /// Display function for functions -pub fn display_function() -> String { - todo +pub fn display_function(func: Function) -> String { + let linkage_str = display_linkage(func.linkage) + let name_str = func.name + let return_str = case func.return_ty { + Some(ty) -> display_type(ty) + None -> "" + } + 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 <> "}" +} + +pub fn display_arguments(arguments: List(#(Type, Value))) -> String { + case arguments { + [] -> "" + _ -> + arguments + |> list.index_map(fn(_, arg) { + case arg { + #(ty, val) -> display_type(ty) <> " " <> display_value(val) + } + }) + |> string.join(", ") + } +} + +pub fn display_blocks(blocks: List(Block)) -> String { + blocks + |> list.map(fn(block) { display_block(block) }) + |> string.join("\n") } /// Instantiates an empty function and returns it diff --git a/test/glove_test.gleam b/test/glove_test.gleam index 738d35d..7a38f39 100644 --- a/test/glove_test.gleam +++ b/test/glove_test.gleam @@ -76,12 +76,12 @@ pub fn display_statement_test() { let volatile = glove.Volatile(glove.Ret(Some(glove.Const(0)))) volatile |> glove.display_statement - |> should.equal("ret 0") + |> should.equal("ret 0\n") let empty_volatile = glove.Volatile(glove.Ret(None)) empty_volatile |> glove.display_statement - |> should.equal("ret") + |> should.equal("ret\n") } // Tests for QBE.Block Display @@ -90,7 +90,7 @@ pub fn display_block_test() { let empty_block = glove.Block("label", []) empty_block |> glove.display_block() - |> should.equal("label:\n") + |> should.equal("label\n") // Test block with statements let statements = [ @@ -105,7 +105,7 @@ pub fn display_block_test() { let block_with_statements = glove.Block("label", statements) block_with_statements |> glove.display_block - |> should.equal("label:\n%temp1 =w add %a, %b\nret %temp1") + |> should.equal("label\n%temp1 =w add %a, %b\nret %temp1\n") } // Tests for QBE.Linkage Display @@ -315,13 +315,13 @@ pub fn display_inst_test() { let ret1 = glove.Ret(Some(glove.Const(10))) ret1 |> glove.display_inst - |> should.equal("ret 10") + |> should.equal("ret 10\n") // Test case for returning without a value let ret2 = glove.Ret(None) ret2 |> glove.display_inst - |> should.equal("ret") + |> should.equal("ret\n") // Test case for conditional jump if nonzero let jnz = glove.Jnz(glove.Const(1), "label1", "label2") @@ -420,3 +420,110 @@ pub fn display_data_def_test() { let result = glove.display_data_def(def) should.equal(result, expected) } + +// Tests for Linkage functions +pub fn private_test() { + let expected = glove.Linkage(exported: False, section: None, secflags: None) + let result = glove.private() + should.equal(result, expected) +} + +pub fn private_with_section_test() { + let section = "mysection" + let expected = + glove.Linkage(exported: False, section: Some(section), secflags: None) + let result = glove.private_with_section(section) + should.equal(result, expected) +} + +pub fn public_test() { + let expected = glove.Linkage(exported: True, section: None, secflags: None) + let result = glove.public() + should.equal(result, expected) +} + +pub fn public_with_section_test() { + let section = "mysection" + let expected = + glove.Linkage(exported: True, section: Some(section), secflags: None) + let result = glove.public_with_section(section) + should.equal(result, expected) +} + +pub fn display_data_test() { + let data_def = + glove.DataDef( + linkage: glove.Linkage(exported: True, section: None, secflags: None), + name: "str", + align: None, + items: [ + #(glove.Byte, glove.Str("hello world")), + #(glove.Byte, glove.Constant(0)), + ], + ) + + let expected = "export data $str = { b \"hello world\", b 0 }" + let result = glove.display_data_def(data_def) + should.equal(result, expected) +} + +pub fn display_function_test() { + let function = + glove.Function( + linkage: glove.Linkage(exported: True, section: None, secflags: None), + name: "main", + 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)))), + ], + ), + ], + ) + + let expected = + "export function w $main() {\n@start\ncall $puts(l $str)\nret 0\n}" + + let result = glove.display_function(function) + should.equal(result, expected) +} + +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)))), + ], + ), + ] + + let expected = "@start\ncall $puts(l $str)\nret 0\n" + + let result = glove.display_blocks(blocks) + should.equal(result, expected) +} + +pub fn display_arguments_test() { + let arguments = [ + #(glove.Word, glove.Global("arg1")), + #(glove.Byte, glove.Global("arg2")), + #(glove.Long, glove.Global("arg3")), + ] + + let expected = "w $arg1, b $arg2, l $arg3" + + let result = glove.display_arguments(arguments) + should.equal(result, expected) +}