compiler: implement typeof(x)
parent
794ee6fc9d
commit
b17ade1257
|
@ -843,9 +843,13 @@ fn (p mut Parser) type_decl() {
|
||||||
is_public: is_pub
|
is_public: is_pub
|
||||||
})
|
})
|
||||||
*/
|
*/
|
||||||
|
if p.pass == .main {
|
||||||
|
p.cgen.consts << '//// SUMTYPE: ${p.mod} | parent: ${name} | name: ${parent.name}'
|
||||||
|
}
|
||||||
// Register the rest of them
|
// Register the rest of them
|
||||||
mut idx := 0
|
mut idx := 0
|
||||||
mut done := false
|
mut done := false
|
||||||
|
mut ctype_names := []string
|
||||||
for {
|
for {
|
||||||
// p.tok == .pipe {
|
// p.tok == .pipe {
|
||||||
idx++
|
idx++
|
||||||
|
@ -865,6 +869,7 @@ fn (p mut Parser) type_decl() {
|
||||||
t.parent = name
|
t.parent = name
|
||||||
p.table.rewrite_type(t)
|
p.table.rewrite_type(t)
|
||||||
p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2'
|
p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2'
|
||||||
|
ctype_names << child_type_name
|
||||||
}
|
}
|
||||||
if done {
|
if done {
|
||||||
break
|
break
|
||||||
|
@ -888,7 +893,15 @@ fn (p mut Parser) type_decl() {
|
||||||
mod: p.mod
|
mod: p.mod
|
||||||
cat: .alias
|
cat: .alias
|
||||||
is_public: is_pub
|
is_public: is_pub
|
||||||
|
ctype_names: ctype_names
|
||||||
})
|
})
|
||||||
|
if p.pass == .main {
|
||||||
|
p.cgen.consts << 'const char * __SumTypeNames__${name}[] = {'
|
||||||
|
for ctype_name in ctype_names {
|
||||||
|
p.cgen.consts << ' "$ctype_name",'
|
||||||
|
}
|
||||||
|
p.cgen.consts << '};'
|
||||||
|
}
|
||||||
p.gen_typedef('typedef struct {
|
p.gen_typedef('typedef struct {
|
||||||
void* obj;
|
void* obj;
|
||||||
int typ;
|
int typ;
|
||||||
|
|
|
@ -109,6 +109,7 @@ $c_common_macros
|
||||||
#include <direct.h> // _wgetcwd
|
#include <direct.h> // _wgetcwd
|
||||||
//#include <WinSock2.h>
|
//#include <WinSock2.h>
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
// On MSVC these are the same (as long as /volatile:ms is passed)
|
// On MSVC these are the same (as long as /volatile:ms is passed)
|
||||||
#define _Atomic volatile
|
#define _Atomic volatile
|
||||||
|
|
||||||
|
|
|
@ -68,8 +68,7 @@ fn (p mut Parser) bool_expression() string {
|
||||||
//p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type')
|
//p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type')
|
||||||
T := p.table.find_type(typ)
|
T := p.table.find_type(typ)
|
||||||
if T.parent == expected {
|
if T.parent == expected {
|
||||||
p.cgen.set_placeholder(start_ph,
|
p.cgen.set_placeholder(start_ph, '/*SUM TYPE CAST2*/ ($expected) { .obj = memdup( &($typ[]) { ')
|
||||||
'/*SUM TYPE CAST2*/($expected) { .obj = memdup( &($typ[]) { ')
|
|
||||||
tt := typ.all_after('_') // TODO
|
tt := typ.all_after('_') // TODO
|
||||||
p.gen('}, sizeof($typ) ), .typ = SumType_${tt} }')//${val}_type }')
|
p.gen('}, sizeof($typ) ), .typ = SumType_${tt} }')//${val}_type }')
|
||||||
}
|
}
|
||||||
|
@ -824,13 +823,29 @@ fn (p mut Parser) factor() string {
|
||||||
// p.fgen('$sizeof_typ)')
|
// p.fgen('$sizeof_typ)')
|
||||||
return 'int'
|
return 'int'
|
||||||
}
|
}
|
||||||
|
.key_typeof {
|
||||||
|
p.next()
|
||||||
|
p.check(.lpar)
|
||||||
|
p.cgen.nogen = true
|
||||||
|
vname := if p.tok == .name && p.peek() == .rpar { p.lit } else { '' }
|
||||||
|
type_of_var := p.expression()
|
||||||
|
p.cgen.nogen = false
|
||||||
|
p.check(.rpar)
|
||||||
|
is_sum_type := type_of_var in p.table.sum_types
|
||||||
|
if is_sum_type && vname.len > 0 {
|
||||||
|
// TODO: make this work for arbitrary sumtype expressions, not just simple vars
|
||||||
|
p.gen('tos3(__SumTypeNames__${type_of_var}[${vname}.typ - 1])')
|
||||||
|
}else{
|
||||||
|
p.gen('tos3("$type_of_var")')
|
||||||
|
}
|
||||||
|
return 'string'
|
||||||
|
}
|
||||||
.key_nameof {
|
.key_nameof {
|
||||||
p.next()
|
p.next()
|
||||||
p.check(.lpar)
|
p.check(.lpar)
|
||||||
mut nameof_typ := p.get_type()
|
mut nameof_typ := p.get_type()
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
p.gen('tos3("$nameof_typ")')
|
p.gen('tos3("$nameof_typ")')
|
||||||
// return 'byteptr'
|
|
||||||
return 'string'
|
return 'string'
|
||||||
}
|
}
|
||||||
.key_offsetof {
|
.key_offsetof {
|
||||||
|
|
|
@ -627,8 +627,22 @@ fn (p mut Parser) cast(typ string) {
|
||||||
if expr_typ == 'bool' {
|
if expr_typ == 'bool' {
|
||||||
p.error('cannot cast `bool` to `$typ`')
|
p.error('cannot cast `bool` to `$typ`')
|
||||||
}
|
}
|
||||||
|
if typ != expr_typ && typ in p.table.sum_types {
|
||||||
|
T := p.table.find_type(typ)
|
||||||
|
if expr_typ in T.ctype_names {
|
||||||
|
// There is no need for a cast here, since it was already done
|
||||||
|
// in p.bool_expression, SUM TYPE CAST2 . Besides, doubling the
|
||||||
|
// cast here causes MSVC to complain with:
|
||||||
|
// error C2440: 'type cast': cannot convert from 'ExprType' to 'ExprType'
|
||||||
|
p.cgen.set_placeholder(pos, '(')
|
||||||
|
}else{
|
||||||
|
p.warn('only $T.ctype_names can be casted to `$typ`')
|
||||||
|
p.error('cannot cast `$expr_typ` to `$typ`')
|
||||||
|
}
|
||||||
|
}else{
|
||||||
p.cgen.set_placeholder(pos, '($typ)(')
|
p.cgen.set_placeholder(pos, '($typ)(')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
p.check(.rpar)
|
p.check(.rpar)
|
||||||
p.gen(')')
|
p.gen(')')
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,7 @@ pub mut:
|
||||||
is_flag bool // enum bitfield flag
|
is_flag bool // enum bitfield flag
|
||||||
// max_field_len int
|
// max_field_len int
|
||||||
is_generic bool
|
is_generic bool
|
||||||
|
ctype_names []string
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TypeNode {
|
struct TypeNode {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
|
||||||
|
fn test_typeof_on_simple_expressions() {
|
||||||
|
a := 123
|
||||||
|
assert typeof(42) == 'int'
|
||||||
|
assert typeof(3.14) == 'f32'
|
||||||
|
assert typeof(2+2*10) == 'int'
|
||||||
|
assert typeof(1.0 * 12.2) == 'f32'
|
||||||
|
assert typeof(a) == 'int'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_typeof_on_atypes(){
|
||||||
|
aint := []int
|
||||||
|
astring := []string
|
||||||
|
assert typeof(aint) == 'array_int'
|
||||||
|
assert typeof(astring) == 'array_string'
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FooBar {
|
||||||
|
x int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_typeof_on_structs(){
|
||||||
|
assert typeof(FooBar{}) == "FooBar"
|
||||||
|
astruct_static := [2]FooBar
|
||||||
|
astruct_dynamic := [FooBar{}, FooBar{}]
|
||||||
|
assert typeof(astruct_static) == '[2]FooBar'
|
||||||
|
assert typeof(astruct_dynamic) == 'array_FooBar'
|
||||||
|
}
|
||||||
|
|
||||||
|
type MySumType = int | f32 | FooBar
|
||||||
|
pub fn (ms MySumType) str() string {
|
||||||
|
match ms {
|
||||||
|
int { return it.str() }
|
||||||
|
f32 { return it.str() }
|
||||||
|
//FooBar { return it.x.str() }
|
||||||
|
else { return 'unknown: ' + typeof(ms) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_typeof_on_sumtypes(){
|
||||||
|
a := MySumType(32)
|
||||||
|
b := MySumType(123.0)
|
||||||
|
c := MySumType(FooBar{x:43})
|
||||||
|
assert typeof(a) == 'int'
|
||||||
|
assert typeof(b) == 'f32'
|
||||||
|
assert typeof(c) == 'FooBar'
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
struct UnaryExpr { a string }
|
||||||
|
struct BinExpr { a string b string }
|
||||||
|
struct BoolExpr { z int }
|
||||||
|
type ExprType = BoolExpr | BinExpr | UnaryExpr
|
||||||
|
|
||||||
|
fn fexpr(k int) ExprType {
|
||||||
|
match k {
|
||||||
|
1 { return UnaryExpr{} }
|
||||||
|
2 { return BinExpr{} }
|
||||||
|
3 { return BoolExpr{} }
|
||||||
|
else { return UnaryExpr{} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_typeof_on_sumtypes_of_structs() {
|
||||||
|
a := fexpr(1)
|
||||||
|
b := fexpr(2)
|
||||||
|
c := fexpr(3)
|
||||||
|
d := ExprType( UnaryExpr{} )
|
||||||
|
assert typeof(a) == 'UnaryExpr'
|
||||||
|
assert typeof(b) == 'BinExpr'
|
||||||
|
assert typeof(c) == 'BoolExpr'
|
||||||
|
assert typeof(d) == 'UnaryExpr'
|
||||||
|
}
|
|
@ -115,7 +115,7 @@ enum TokenKind {
|
||||||
key_switch
|
key_switch
|
||||||
key_true
|
key_true
|
||||||
key_type
|
key_type
|
||||||
// typeof
|
key_typeof
|
||||||
key_orelse
|
key_orelse
|
||||||
key_union
|
key_union
|
||||||
key_pub
|
key_pub
|
||||||
|
@ -224,7 +224,7 @@ fn build_token_str() []string {
|
||||||
s[TokenKind.key_import] = 'import'
|
s[TokenKind.key_import] = 'import'
|
||||||
s[TokenKind.key_embed] = 'embed'
|
s[TokenKind.key_embed] = 'embed'
|
||||||
s[TokenKind.key_unsafe] = 'unsafe'
|
s[TokenKind.key_unsafe] = 'unsafe'
|
||||||
// Tokens[key_typeof] = 'typeof'
|
s[TokenKind.key_typeof] = 'typeof'
|
||||||
s[TokenKind.key_enum] = 'enum'
|
s[TokenKind.key_enum] = 'enum'
|
||||||
s[TokenKind.key_interface] = 'interface'
|
s[TokenKind.key_interface] = 'interface'
|
||||||
s[TokenKind.key_pub] = 'pub'
|
s[TokenKind.key_pub] = 'pub'
|
||||||
|
|
Loading…
Reference in New Issue