Skip to content

Commit

Permalink
Adding Type (#3)
Browse files Browse the repository at this point in the history
Create a proper `Type` type that will make more complex types possible later.
  • Loading branch information
elliotchance authored Jul 17, 2021
1 parent 799c1b5 commit 4935eed
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 31 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ V does not carry runtime information about types. Although compile-time
reflection is more performant it can be limiting in some cases that can't be
avoided.

- [Installation](#installation)
- [Values](#values)
- [Types](#types)

Installation
------------

Expand All @@ -25,7 +29,7 @@ import elliotchance.reflect
fn main() {
v := reflect.value_of(1.23)
println(v.kind) // "f64"
println(v.typ) // "f64"
println(v.get_f64()) // 1.23
println(v.get_int()) // V panic: value must be int but is f64
}
Expand All @@ -39,7 +43,7 @@ fn sum(items []reflect.Value) f64 {
mut total := 0.0
for item in items {
match item.kind {
match item.typ.kind {
.is_f64 { total += item.get_f64() }
.is_int { total += item.get_int() }
else { /* ignore */ }
Expand All @@ -58,3 +62,13 @@ fn main() {
println(sum(v)) // 8.23
}
```

Types
-----

All `Values` have a `Type` which can be accessed on the `.typ` field.

- `.kind`: one of the `Kind` values: `is_bool`, `is_string`, `is_i8`, `is_i16`,
`is_int`, `is_i64`, `is_byte`, `is_u16`, `is_u32`, `is_u64`, `is_rune`,
`is_f32`, `is_f64`.
- `.str()`: The string representation that matches the compile-time type in V.
31 changes: 31 additions & 0 deletions type.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module reflect

pub struct Type {
kind Kind
}

pub fn (t Type) str() string {
return t.kind.str()
}

// parse_type returns the Type definition from the string representation.
pub fn parse_type(t string) ?Type {
return Type{
kind: match t {
'bool' { Kind.is_bool }
'string' { Kind.is_string }
'i8' { Kind.is_i8 }
'i16' { Kind.is_i16 }
'int' { Kind.is_int }
'i64' { Kind.is_i64 }
'byte' { Kind.is_byte }
'u16' { Kind.is_u16 }
'u32' { Kind.is_u32 }
'u64' { Kind.is_u64 }
'rune' { Kind.is_rune }
'f32' { Kind.is_f32 }
'f64' { Kind.is_f64 }
else { Kind.is_bool } // TODO(elliotchance): Fix me.
}
}
}
29 changes: 29 additions & 0 deletions type_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module reflect

struct ParseTypeTest {
typ string
expected_kind Kind
}

fn test_parse_type() ? {
tests := [
ParseTypeTest{'bool', Kind.is_bool},
ParseTypeTest{'string', Kind.is_string},
ParseTypeTest{'i8', Kind.is_i8},
ParseTypeTest{'i16', Kind.is_i16},
ParseTypeTest{'int', Kind.is_int},
ParseTypeTest{'i64', Kind.is_i64},
ParseTypeTest{'byte', Kind.is_byte},
ParseTypeTest{'u16', Kind.is_u16},
ParseTypeTest{'u32', Kind.is_u32},
ParseTypeTest{'u64', Kind.is_u64},
ParseTypeTest{'rune', Kind.is_rune},
ParseTypeTest{'f32', Kind.is_f32},
ParseTypeTest{'f64', Kind.is_f64},
]
for test in tests {
typ := parse_type(test.typ) ?
assert typ.kind == test.expected_kind
assert typ.str() == test.typ
}
}
32 changes: 16 additions & 16 deletions value.v
Original file line number Diff line number Diff line change
Expand Up @@ -17,98 +17,98 @@ pub struct Value {
value_f32 f32
value_f64 f64
pub:
kind Kind
typ Type
}

// value_of is used to create a Value
pub fn value_of<T>(x T) Value {
$if T is bool {
return {
kind: Kind.is_bool
typ: Type{Kind.is_bool}
value_bool: x
}
}

$if T is string {
return {
kind: Kind.is_string
typ: Type{Kind.is_string}
value_string: x
}
}

$if T is i8 {
return {
kind: Kind.is_i8
typ: Type{Kind.is_i8}
value_i8: x
}
}

$if T is i16 {
return {
kind: Kind.is_i16
typ: Type{Kind.is_i16}
value_i16: x
}
}

$if T is int {
return {
kind: Kind.is_int
typ: Type{Kind.is_int}
value_int: x
}
}

$if T is i64 {
return {
kind: Kind.is_i64
typ: Type{Kind.is_i64}
value_i64: x
}
}

$if T is byte {
return {
kind: Kind.is_byte
typ: Type{Kind.is_byte}
value_byte: x
}
}

$if T is u16 {
return {
kind: Kind.is_u16
typ: Type{Kind.is_u16}
value_u16: x
}
}

$if T is u32 {
return {
kind: Kind.is_u32
typ: Type{Kind.is_u32}
value_u32: x
}
}

$if T is u64 {
return {
kind: Kind.is_u64
typ: Type{Kind.is_u64}
value_u64: x
}
}

$if T is rune {
return {
kind: Kind.is_rune
typ: Type{Kind.is_rune}
value_rune: x
}
}

$if T is f32 {
return {
kind: Kind.is_f32
typ: Type{Kind.is_f32}
value_f32: x
}
}

$if T is f64 {
return {
kind: Kind.is_f64
typ: Type{Kind.is_f64}
value_f64: x
}
}
Expand All @@ -117,8 +117,8 @@ pub fn value_of<T>(x T) Value {
}

fn (v Value) must_be(k Kind) {
if v.kind != k {
panic('value must be $k but is $v.kind')
if v.typ.kind != k {
panic('value must be $k but is $v.typ.kind')
}
}

Expand Down
39 changes: 26 additions & 13 deletions value_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -2,78 +2,91 @@ module reflect

fn test_value_of_bool() {
v := value_of(true)
assert v.kind == Kind.is_bool
assert v.typ.kind == Kind.is_bool
assert v.typ.str() == 'bool'
assert v.get_bool() == true
}

fn test_value_of_string() {
v := value_of('hello')
assert v.kind == Kind.is_string
assert v.typ.kind == Kind.is_string
assert v.typ.str() == 'string'
assert v.get_string() == 'hello'
}

fn test_value_of_i8() {
v := value_of(i8(57))
assert v.kind == Kind.is_i8
assert v.typ.kind == Kind.is_i8
assert v.typ.str() == 'i8'
assert v.get_i8() == 57
}

fn test_value_of_i16() {
v := value_of(i16(43))
assert v.kind == Kind.is_i16
assert v.typ.kind == Kind.is_i16
assert v.typ.str() == 'i16'
assert v.get_i16() == 43
}

fn test_value_of_int() {
v := value_of(123)
assert v.kind == Kind.is_int
assert v.typ.kind == Kind.is_int
assert v.typ.str() == 'int'
assert v.get_int() == 123
}

fn test_value_of_i64() {
v := value_of(i64(123456))
assert v.kind == Kind.is_i64
assert v.typ.kind == Kind.is_i64
assert v.typ.str() == 'i64'
assert v.get_i64() == 123456
}

fn test_value_of_byte() {
v := value_of(byte(45))
assert v.kind == Kind.is_byte
assert v.typ.kind == Kind.is_byte
assert v.typ.str() == 'byte'
assert v.get_byte() == 45
}

fn test_value_of_u16() {
v := value_of(u16(34))
assert v.kind == Kind.is_u16
assert v.typ.kind == Kind.is_u16
assert v.typ.str() == 'u16'
assert v.get_u16() == 34
}

fn test_value_of_u32() {
v := value_of(u32(4567))
assert v.kind == Kind.is_u32
assert v.typ.kind == Kind.is_u32
assert v.typ.str() == 'u32'
assert v.get_u32() == 4567
}

fn test_value_of_u64() {
v := value_of(u64(56789))
assert v.kind == Kind.is_u64
assert v.typ.kind == Kind.is_u64
assert v.typ.str() == 'u64'
assert v.get_u64() == 56789
}

fn test_value_of_rune() {
v := value_of(`😃`)
assert v.kind == Kind.is_rune
assert v.typ.kind == Kind.is_rune
assert v.typ.str() == 'rune'
assert v.get_rune() == `😃`
}

fn test_value_of_f32() {
v := value_of(f32(1.23))
assert v.kind == Kind.is_f32
assert v.typ.kind == Kind.is_f32
assert v.typ.str() == 'f32'
assert v.get_f32() == f32(1.23)
}

fn test_value_of_f64() {
v := value_of(4.56)
assert v.kind == Kind.is_f64
assert v.typ.kind == Kind.is_f64
assert v.typ.str() == 'f64'
assert v.get_f64() == 4.56
}

0 comments on commit 4935eed

Please sign in to comment.