Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 116 additions & 0 deletions cmd/gravity/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,117 @@
pub mod go;

use crate::go::GoType;
use wit_bindgen_core::{
abi::WasmType,
wit_parser::{Resolve, Result_, Type, TypeDef, TypeDefKind},
};

/// Resolves a Wasm type to a Go type.
pub fn resolve_wasm_type(typ: &WasmType) -> GoType {
match typ {
WasmType::I32 => GoType::Uint32,
WasmType::I64 => GoType::Uint64,
WasmType::F32 => GoType::Float32,
WasmType::F64 => GoType::Float64,
WasmType::Pointer => GoType::Uint64,
WasmType::PointerOrI64 => GoType::Uint64,
WasmType::Length => GoType::Uint64,
}
}

/// Resolves a WIT type to a Go type.
///
/// # Panics
///
/// This function panics if:
///
/// - The type definition cannot be found in the resolve context.
/// - The type is still unimplemented.
/// - The type does not have a name when it is expected to have one (enums, records, type aliases).
pub fn resolve_type(typ: &Type, resolve: &Resolve) -> GoType {
match typ {
// Basic types.
Type::Bool => GoType::Bool,
Type::U8 => GoType::Uint8,
Type::U16 => GoType::Uint16,
Type::U32 => GoType::Uint32,
Type::U64 => GoType::Uint64,
Type::S8 => GoType::Int8,
Type::S16 => GoType::Int16,
Type::S32 => GoType::Int32,
Type::S64 => GoType::Int64,
Type::F32 => GoType::Float32,
Type::F64 => GoType::Float64,
Type::Char => {
// Is this a Go "rune"?
todo!("TODO(#6): resolve char type")
}
Type::String => GoType::String,
Type::ErrorContext => todo!("TODO(#4): implement error context conversion"),

// Complex types.
Type::Id(id) => {
let TypeDef { name, kind, .. } = resolve
.types
.get(*id)
.expect("failed to find type definition");
match kind {
TypeDefKind::Record(_) => {
GoType::UserDefined(name.clone().expect("expected record to have a name"))
}
TypeDefKind::Resource => todo!("TODO(#5): implement resources"),
TypeDefKind::Handle(_) => todo!("TODO(#5): implement resources"),
TypeDefKind::Flags(_) => todo!("TODO(#4): implement flag conversion"),
TypeDefKind::Tuple(_) => todo!("TODO(#4): implement tuple conversion"),
// Variants are handled as an empty interfaces in type signatures; however, that
// means they require runtime type reflection
TypeDefKind::Variant(_) => GoType::Interface,
TypeDefKind::Enum(_) => {
GoType::UserDefined(name.clone().expect("expected enum to have a name"))
}
TypeDefKind::Option(value) => {
GoType::ValueOrOk(Box::new(resolve_type(value, resolve)))
}

// Various results, including specialised ones.
TypeDefKind::Result(Result_ {
ok: Some(ok),
err: Some(Type::String),
}) => GoType::ValueOrError(Box::new(resolve_type(ok, resolve))),
TypeDefKind::Result(Result_ {
ok: Some(_),
err: Some(_),
}) => {
todo!("TODO(#4): implement remaining result conversion")
}
TypeDefKind::Result(Result_ {
ok: Some(ok),
err: None,
}) => resolve_type(ok, resolve),
TypeDefKind::Result(Result_ {
ok: None,
err: Some(Type::String),
}) => GoType::Error,
TypeDefKind::Result(Result_ {
ok: None,
err: Some(_),
}) => todo!("TODO(#4): implement remaining result conversion"),
TypeDefKind::Result(Result_ {
ok: None,
err: None,
}) => GoType::Nothing,

TypeDefKind::List(inner) => GoType::Slice(Box::new(resolve_type(inner, resolve))),
TypeDefKind::Future(_) => todo!("TODO(#4): implement future conversion"),
TypeDefKind::Stream(_) => todo!("TODO(#4): implement stream conversion"),
TypeDefKind::Type(_) => {
GoType::UserDefined(name.clone().expect("expected type alias to have a name"))
}
TypeDefKind::FixedSizeList(_, _) => {
todo!("TODO(#4): implement fixed size list conversion")
}
TypeDefKind::Unknown => todo!("TODO(#4): implement unknown conversion"),
}
}
}
}
201 changes: 92 additions & 109 deletions cmd/gravity/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ use genco::{
tokens::{FormatInto, quoted},
};
use wit_bindgen_core::{
abi::{AbiVariant, Bindgen, Instruction, LiftLower, WasmType},
abi::{AbiVariant, Bindgen, Instruction, LiftLower},
wit_parser::{
Alignment, ArchitectureSize, Record, Resolve, Result_, SizeAlign, Type, TypeDef,
TypeDefKind, WorldItem,
},
};

use arcjet_gravity::go::{GoIdentifier, GoResult, GoType, Operand, comment, embed};
use arcjet_gravity::{
go::{GoIdentifier, GoResult, GoType, Operand, comment, embed},
resolve_type, resolve_wasm_type,
};

enum Direction {
Export,
Expand Down Expand Up @@ -103,6 +106,11 @@ impl Bindgen for Func {
let iter_element = "e";
let iter_base = "base";

let wazero_api_decode_i32 = &go::import("github.com/tetratelabs/wazero/api", "DecodeI32");
let wazero_api_encode_i32 = &go::import("github.com/tetratelabs/wazero/api", "EncodeI32");
let wazero_api_decode_u32 = &go::import("github.com/tetratelabs/wazero/api", "DecodeU32");
let wazero_api_encode_u32 = &go::import("github.com/tetratelabs/wazero/api", "EncodeU32");

// println!("instruction: {inst:?}, operands: {operands:?}");

match inst {
Expand Down Expand Up @@ -283,17 +291,22 @@ impl Bindgen for Func {
results.push(Operand::SingleValue(value))
}
Instruction::I32FromU32 => {
// It seems like this isn't needed because Wazero works with Go's uint32 type
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
results.push(operand.clone());
quote_in! { self.body =>
$['\r']
$result := $wazero_api_encode_u32($operand)
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::U32FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := uint32($operand)
$result := $wazero_api_decode_u32($operand)
};
results.push(Operand::SingleValue(result.into()));
}
Expand Down Expand Up @@ -1070,18 +1083,82 @@ impl Bindgen for Func {
Instruction::I32FromChar => todo!("implement instruction: {inst:?}"),
Instruction::I64FromU64 => todo!("implement instruction: {inst:?}"),
Instruction::I64FromS64 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromS32 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromU16 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromS16 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromU8 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromS8 => todo!("implement instruction: {inst:?}"),
Instruction::I32FromS32 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $wazero_api_encode_i32($operand)
}
results.push(Operand::SingleValue(value))
}
// All of these values should fit in Go's `int32` type which allows a safe cast
Instruction::I32FromU16
| Instruction::I32FromS16
| Instruction::I32FromU8
| Instruction::I32FromS8 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $wazero_api_encode_i32(int32($operand))
}
results.push(Operand::SingleValue(value))
}
Instruction::CoreF32FromF32 => todo!("implement instruction: {inst:?}"),
Instruction::CoreF64FromF64 => todo!("implement instruction: {inst:?}"),
Instruction::S8FromI32 => todo!("implement instruction: {inst:?}"),
Instruction::U8FromI32 => todo!("implement instruction: {inst:?}"),
Instruction::S16FromI32 => todo!("implement instruction: {inst:?}"),
Instruction::U16FromI32 => todo!("implement instruction: {inst:?}"),
Instruction::S32FromI32 => todo!("implement instruction: {inst:?}"),
Instruction::S8FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := int8($wazero_api_decode_i32($operand))
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::U8FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := uint8($wazero_api_decode_u32($operand))
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::S16FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := int16($wazero_api_decode_i32($operand))
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::U16FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := uint16($wazero_api_decode_u32($operand))
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::S32FromI32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := $wazero_api_decode_i32($operand)
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::S64FromI64 => todo!("implement instruction: {inst:?}"),
Instruction::U64FromI64 => todo!("implement instruction: {inst:?}"),
Instruction::CharFromI32 => todo!("implement instruction: {inst:?}"),
Expand Down Expand Up @@ -1153,100 +1230,6 @@ impl Bindgen for Func {
}
}

fn resolve_wasm_type(typ: &WasmType) -> GoType {
match typ {
WasmType::I32 => GoType::Uint32,
WasmType::I64 => GoType::Uint64,
WasmType::F32 => GoType::Float32,
WasmType::F64 => GoType::Float64,
WasmType::Pointer => GoType::Uint64,
WasmType::PointerOrI64 => GoType::Uint64,
WasmType::Length => GoType::Uint64,
}
}

fn resolve_type(typ: &Type, resolve: &Resolve) -> GoType {
match typ {
Type::Bool => GoType::Bool,
Type::U8 => GoType::Uint8,
Type::U16 => GoType::Uint16,
Type::U32 => GoType::Uint32,
Type::U64 => GoType::Uint64,
Type::S8 => GoType::Int8,
Type::S16 => GoType::Int16,
Type::S32 => GoType::Int32,
Type::S64 => GoType::Int64,
Type::F32 => GoType::Float32,
Type::F64 => GoType::Float64,
Type::Char => {
// Is this a Go "rune"?
todo!("TODO(#6): resolve char type")
}
Type::String => GoType::String,
Type::ErrorContext => todo!("TODO(#4): implement error context conversion"),
Type::Id(typ_id) => {
let TypeDef { name, kind, .. } = resolve.types.get(*typ_id).unwrap();
match kind {
TypeDefKind::Record(Record { .. }) => {
let typ = name.clone().expect("record to have a name");
GoType::UserDefined(typ)
}
TypeDefKind::Resource => todo!("TODO(#5): implement resources"),
TypeDefKind::Handle(_) => todo!("TODO(#5): implement resources"),
TypeDefKind::Flags(_) => todo!("TODO(#4): implement flag conversion"),
TypeDefKind::Tuple(_) => todo!("TODO(#4): implement tuple conversion"),
// Variants are handled as an empty interfaces in type signatures; however, that
// means they require runtime type reflection
TypeDefKind::Variant(_) => GoType::Interface,
TypeDefKind::Enum(_) => {
let typ = name.clone().expect("enum to have a name");
GoType::UserDefined(typ)
}
TypeDefKind::Option(value) => {
GoType::ValueOrOk(Box::new(resolve_type(value, resolve)))
}
TypeDefKind::Result(Result_ {
ok: Some(ok),
err: Some(Type::String),
}) => GoType::ValueOrError(Box::new(resolve_type(ok, resolve))),
TypeDefKind::Result(Result_ {
ok: Some(_),
err: Some(_),
}) => {
todo!("TODO(#4): implement remaining result conversion")
}
TypeDefKind::Result(Result_ {
ok: Some(ok),
err: None,
}) => resolve_type(ok, resolve),
TypeDefKind::Result(Result_ {
ok: None,
err: Some(Type::String),
}) => GoType::Error,
TypeDefKind::Result(Result_ {
ok: None,
err: Some(_),
}) => todo!("TODO(#4): implement remaining result conversion"),
TypeDefKind::Result(Result_ {
ok: None,
err: None,
}) => GoType::Nothing,
TypeDefKind::List(typ) => GoType::Slice(Box::new(resolve_type(typ, resolve))),
TypeDefKind::Future(_) => todo!("TODO(#4): implement future conversion"),
TypeDefKind::Stream(_) => todo!("TODO(#4): implement stream conversion"),
TypeDefKind::Type(_) => {
let typ = name.clone().expect("type alias to have a name");
GoType::UserDefined(typ)
}
TypeDefKind::FixedSizeList(_, _) => {
todo!("TODO(#4): implement fixed size list conversion")
}
TypeDefKind::Unknown => todo!("TODO(#4): implement unknown conversion"),
}
}
}
}

struct Bindings {
out: Tokens<Go>,
}
Expand Down
Empty file.
Loading