From 7cad696996e23764a2f71d9c38a1a9023e7503ea Mon Sep 17 00:00:00 2001 From: Willyboar Date: Tue, 16 May 2023 19:32:01 +0300 Subject: [PATCH] Initial commit --- .github/workflows/test.yml | 23 +++ .gitignore | 5 + README.md | 28 ++++ gleam.toml | 16 ++ manifest.toml | 11 ++ src/glove.gleam | 298 +++++++++++++++++++++++++++++++++++++ test/glove_test.gleam | 31 ++++ 7 files changed, 412 insertions(+) create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 gleam.toml create mode 100644 manifest.toml create mode 100644 src/glove.gleam create mode 100644 test/glove_test.gleam diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..c8170eb --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: test + +on: + push: + branches: + - master + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3.5.1 + - uses: erlef/setup-beam@v1.15.3 + with: + otp-version: "25.2" + gleam-version: "0.28.3" + rebar3-version: "3" + # elixir-version: "1.14.2" + - run: gleam format --check src test + - run: gleam deps download + - run: gleam test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fc4c01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.beam +*.ez +build +erl_crash.dump +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..508deb2 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# glove + + + +## Don't Use it (WIP) + +[![Package Version](https://img.shields.io/hexpm/v/glove)](https://hex.pm/packages/glove) +[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/glove/) + +A Gleam project + +## Quick start + +```sh +gleam run # Run the project +gleam test # Run the tests +gleam shell # Run an Erlang shell +``` + +## Installation + +If available on Hex this package can be added to your Gleam project: + +```sh +gleam add glove +``` + +and its documentation can be found at . diff --git a/gleam.toml b/gleam.toml new file mode 100644 index 0000000..d50d5e5 --- /dev/null +++ b/gleam.toml @@ -0,0 +1,16 @@ +name = "glove" +version = "0.1.0" +description = "A Gleam project" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "username", repo = "project" } +# links = [{ title = "Website", href = "https://gleam.run" }] + +[dependencies] +gleam_stdlib = "~> 0.28" + +[dev-dependencies] +gleeunit = "~> 0.10" diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..5f121db --- /dev/null +++ b/manifest.toml @@ -0,0 +1,11 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_stdlib", version = "0.28.2", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "088E334A00C9530D4B194F31406E51B6E4E4697C6A380D11591E60CC2F239724" }, + { name = "gleeunit", version = "0.10.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "ECEA2DE4BE6528D36AFE74F42A21CDF99966EC36D7F25DEB34D47DD0F7977BAF" }, +] + +[requirements] +gleam_stdlib = "~> 0.28" +gleeunit = "~> 0.10" diff --git a/src/glove.gleam b/src/glove.gleam new file mode 100644 index 0000000..a9abec2 --- /dev/null +++ b/src/glove.gleam @@ -0,0 +1,298 @@ +import gleam/int + +// QBE Comparison Operators +pub type Comp { + // Less Than + Slt + // Less or Equal + Sle + // Greater than + Sgt + // Greater or equal + Sge + // Equal + Eq + // Not equal + Ne +} + +pub type Option { + Option(Value) +} + +// QBE instruction +pub type Inst { + // Adds values + Add(Value, Value) + // Substracts value(b) from value(a) + Sub(Value, Value) + // Multiplies values + Mul(Value, Value) + // Divides value(a) by value(b) + Div(Value, Value) + // Returns a remaider from division + Rem(Value, Value) + // Perform a Comparison + Comp(Type, Comp, Value, Value) + // Bitwise AND + And(Value, Value) + // Bitwise OR + Or(Value, Value) + // Copies either temporary or literal value + Copy(Value) + // Return from a function, optionally with a value + Ret(Option) + // Jumps to first label if a value is nonzero or to the second one otherwise + Jnz(Value, String, String) + // Unconditionally jumps to a label + Jmp(String) + // Calls a function + Call(String, #(Type, Value)) + // Allocates a 4-byte aligned area on the stack + Alloc4(Int) + // Allocates a 8-byte aligned area on the stack + Alloc8(Int) + // Allocates a 16-byte aligned area on the stack + Alloc16(Int) + // Stores a value into memory pointed to by destination. + // (type, destination, value) + Store(Type, Value, Value) + // Loads a value from memory pointed to by source + // (type, source) + Load(Type, Value) + // (source, destination, n) + // + // Copy `n` bytes from the source address to the destination address. + // + // n must be a constant value. + // + // Minimum supported QBE version 1.1 + Blit(Value, Value, Int) +} + +// Display function for Instructions +pub fn display_inst() -> String { + todo +} + +// QBE Value for instructions +pub type Value { + // `%`-temporary + Temporary(name: String) + // `$`-global + Global(name: String) + // Constant + Const(value: Int) +} + +// Display Value function +pub fn display_value(value: Value) -> String { + case value { + Temporary(name) -> "%{" <> name <> "}" + Global(name) -> "${" <> name <> "}" + Const(value) -> "{" <> int.to_string(value) <> "}" + } +} + +// QBE Types +pub type Type { + // Base Types + Word + Long + Single + Double + // Extended Types + Byte + Halfword + // Agreegate type with a specified name + Agreegate(TypeDef) +} + +// Display Type function +pub fn display_type(ty: Type) -> String { + case ty { + Byte -> "b" + Halfword -> "h" + Word -> "w" + Long -> "l" + Single -> "s" + Double -> "d" + Agreegate(TypeDef) -> display_type_def(TypeDef) + } +} + +// Returns a C ABI type. Extended types are converted to closest base +// types +pub fn into_abi() -> Nil { + todo +} + +// Returns the closest base type +pub fn into_base() -> Nil { + todo +} + +// Returns byte size for values of the type +pub fn size() -> Int { + todo +} + +// QBE data definition +pub type DataDef { + DataDef(linkage: Linkage, name: String, align: Int, items: #(Type, DataItem)) +} + +pub fn new_datadef() -> DataDef { + todo +} + +// Display function for Datadef +pub fn display_datadef() -> String { + todo +} + +// QBE aggregate type definition +pub type TypeDef { + TypeDef(name: String, align: Option, items: #(Type, Int)) +} + +// Display function for TypeDef +pub fn display_type_def() -> Nil { + todo +} + +// QBE Data definition item +pub type DataItem { + // Symbol and offset + Symbol(String, Int) + // String + Str(String) + // + Constant(Int) +} + +// Display function for DataItem +pub fn display_data_item() -> String { + todo +} + +// IR Statement +pub type Statement { + Assign(Value, Type, Inst) + Volatile(Inst) +} + +// Display function for Statement +pub fn display_statement() -> String { + todo +} + +// Function block with a label +pub type Block { + Block(label: String, statements: #(Statement)) +} + +// Display function for block +pub fn display_block() -> String { + todo +} + +/// Adds a new instruction to the block +pub fn add_inst() -> Nil { + todo +} + +/// Adds a new instruction assigned to a temporary +pub fn assign_inst() -> Nil { + todo +} + +/// Returns true if the block's last instruction is a jump +pub fn jumps() -> Bool { + todo +} + +// QBE Function +pub type Function { + Function( + linkage: Linkage, + name: String, + arguments: #(Type, Value), + return_ty: Option(Type), + blocks: #(Block), + ) +} + +// Display function for functions +pub fn display_function() -> String { + todo +} + +// Instantiates an empty function and returns it +pub fn new_function() -> Function { + todo +} + +// Adds a new empty block with a specified label and returns +// a reference to it +pub fn add_block() -> Block { + todo +} + +// Returns a reference to the last block +pub fn last_block() -> Nil { + todo +} + +// Adds a new instruction to the last block +pub fn add_instr() -> Nil { + todo +} + +// Adds a new instruction assigned to a temporary +pub fn assign_instr() -> Nil { + todo +} + +// Linkage of a function or data defintion (e.g. section and +// private/public status) +pub type Linkage { + Linkage(exported: Bool, section: Option(String), secflags: Option(String)) +} + +// Returns the default configuration for private linkage +pub fn private() -> Linkage { + todo +} + +// Returns the configuration for private linkage with a provided section +pub fn private_with_section() -> Nil { + todo +} + +/// A complete IL file +pub type Module { + Module(functions: #(Function), types: #(TypeDef), data: #(DataDef)) +} + +// Creates a new module +pub fn new_module() -> Module { + Module(functions: #(), types: #(), data: #()) +} + +// Display function for Module +pub fn display_module(module: Module) -> String { + todo +} + +pub fn add_function(module: Module, function: Function) -> Module { + todo +} + +pub fn add_type(module: Module, type_def: TypeDef) -> Module { + todo +} + +pub fn add_data(module: Module, data_def: DataDef) -> Module { + todo +} diff --git a/test/glove_test.gleam b/test/glove_test.gleam new file mode 100644 index 0000000..b1b97ac --- /dev/null +++ b/test/glove_test.gleam @@ -0,0 +1,31 @@ +import gleeunit +import gleeunit/should +import glove + +pub fn main() { + gleeunit.main() +} + +// gleeunit test functions end in `_test` + +// Tests for QBE.Value +// Test QBE.Value.Temporary +pub fn qbe_value_temp_test() { + glove.Temporary("temp") + |> glove.display_value() + |> should.equal("%{temp}") +} + +// Test QBE.Value.Global +pub fn qbe_value_global_test() { + glove.Global("global") + |> glove.display_value() + |> should.equal("${global}") +} + +// Test QBE.Value.Const +pub fn qbe_value_const_test() { + glove.Const(1) + |> glove.display_value() + |> should.equal("{1}") +}