cgen: error fixes; table: simplify; compiler tests

pull/4002/head
Alexander Medvednikov 2020-03-13 01:43:30 +01:00
parent b43ac2783d
commit 4b4c47461b
20 changed files with 757 additions and 675 deletions

View File

@ -107,6 +107,7 @@ pub:
mut_pos int // mut: mut_pos int // mut:
pub_pos int // pub: pub_pos int // pub:
pub_mut_pos int // pub mut: pub_mut_pos int // pub mut:
is_c bool
} }
pub struct StructInit { pub struct StructInit {
@ -488,12 +489,12 @@ pub:
pub struct AssignExpr { pub struct AssignExpr {
pub: pub:
op token.Kind op token.Kind
pos token.Position pos token.Position
left Expr left Expr
val Expr val Expr
// mut: mut:
// left_type table.Type left_type table.Type
} }
pub struct GotoLabel { pub struct GotoLabel {

View File

@ -121,7 +121,6 @@ pub fn (c mut Checker) check_struct_init(struct_init ast.StructInit) table.Type
else {} else {}
} }
if c.is_amp { if c.is_amp {
println('XAXAXAX')
return table.type_to_ptr(struct_init.typ) return table.type_to_ptr(struct_init.typ)
} }
return struct_init.typ return struct_init.typ
@ -153,7 +152,7 @@ pub fn (c mut Checker) infix_expr(infix_expr mut ast.InfixExpr) table.Type {
return left_type return left_type
} }
fn (c mut Checker) assign_expr(assign_expr ast.AssignExpr) { fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
match assign_expr.left { match assign_expr.left {
ast.Ident { ast.Ident {
if it.kind == .blank_ident { if it.kind == .blank_ident {
@ -164,6 +163,7 @@ fn (c mut Checker) assign_expr(assign_expr ast.AssignExpr) {
} }
left_type := c.expr(assign_expr.left) left_type := c.expr(assign_expr.left)
c.expected_type = left_type c.expected_type = left_type
assign_expr.left_type = left_type
// assign_expr.left_type = left_type // assign_expr.left_type = left_type
// t := c.table.get_type_symbol(left_type) // t := c.table.get_type_symbol(left_type)
// println('setting exp type to $c.expected_type $t.name') // println('setting exp type to $c.expected_type $t.name')
@ -594,7 +594,7 @@ pub fn (c mut Checker) expr(node ast.Expr) table.Type {
return it.typ return it.typ
} }
ast.AssignExpr { ast.AssignExpr {
c.assign_expr(it) c.assign_expr(mut it)
} }
ast.Assoc { ast.Assoc {
scope := c.file.scope.innermost(it.pos.pos) scope := c.file.scope.innermost(it.pos.pos)

View File

@ -58,6 +58,13 @@ pub fn (g &Gen) typ(t table.Type) string {
if nr_muls > 0 { if nr_muls > 0 {
styp += strings.repeat(`*`, nr_muls) styp += strings.repeat(`*`, nr_muls)
} }
if styp.starts_with('C__') {
styp = styp[3..]
}
if styp == 'stat' {
// TODO perf and other C structs
styp = 'struct stat'
}
return styp return styp
} }
@ -286,7 +293,9 @@ fn (g mut Gen) stmt(node ast.Stmt) {
// g.writeln('\t$field_type_sym.name $field.name;') // g.writeln('\t$field_type_sym.name $field.name;')
// } // }
// g.writeln('} $name;') // g.writeln('} $name;')
g.typedefs.writeln('typedef struct $name $name;') if !it.is_c {
g.typedefs.writeln('typedef struct $name $name;')
}
} }
ast.TypeDecl { ast.TypeDecl {
g.writeln('// type') g.writeln('// type')
@ -302,6 +311,7 @@ fn (g mut Gen) stmt(node ast.Stmt) {
fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
// multi return // multi return
// g.write('/*assign*/')
if assign_stmt.left.len > assign_stmt.right.len { if assign_stmt.left.len > assign_stmt.right.len {
mut return_type := table.void_type mut return_type := table.void_type
match assign_stmt.right[0] { match assign_stmt.right[0] {
@ -399,6 +409,9 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
if name.starts_with('_op_') { if name.starts_with('_op_') {
name = op_to_fn_name(name) name = op_to_fn_name(name)
} }
if name == 'exit' {
name = 'v_exit'
}
// type_name := g.table.type_to_str(it.return_type) // type_name := g.table.type_to_str(it.return_type)
type_name := g.typ(it.return_type) type_name := g.typ(it.return_type)
g.write('$type_name ${name}(') g.write('$type_name ${name}(')
@ -503,17 +516,30 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
ast.AssignExpr { ast.AssignExpr {
g.is_assign_expr = true g.is_assign_expr = true
mut str_add := false
if it.left_type == table.string_type_idx && it.op == .plus_assign {
// str += str2 => `str = string_add(str, str2)`
g.expr(it.left)
g.write(' = string_add(')
str_add = true
}
g.expr(it.left) g.expr(it.left)
// arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val` // arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val`
if !g.is_array_set { if !g.is_array_set && !str_add {
g.write(' $it.op.str() ') g.write(' $it.op.str() ')
} }
else if str_add {
g.write(', ')
}
g.is_assign_expr = false g.is_assign_expr = false
g.expr(it.val) g.expr(it.val)
if g.is_array_set { if g.is_array_set {
g.write(' })') g.write(' })')
g.is_array_set = false g.is_array_set = false
} }
else if str_add {
g.write(')')
}
} }
ast.Assoc { ast.Assoc {
g.write('/* assoc */') g.write('/* assoc */')
@ -523,6 +549,9 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
ast.CallExpr { ast.CallExpr {
mut name := it.name.replace('.', '__') mut name := it.name.replace('.', '__')
if name == 'exit' {
name = 'v_exit'
}
if it.is_c { if it.is_c {
// Skip "C__" // Skip "C__"
g.is_c_call = true g.is_c_call = true
@ -834,6 +863,9 @@ fn (g mut Gen) expr(node ast.Expr) {
g.expr(it.exprs[i]) g.expr(it.exprs[i])
g.writeln(', ') g.writeln(', ')
} }
if it.fields.len == 0 {
g.write('0')
}
g.write('}') g.write('}')
if g.is_amp { if g.is_amp {
g.write(', sizeof($styp))') g.write(', sizeof($styp))')
@ -865,6 +897,7 @@ fn (g mut Gen) expr(node ast.Expr) {
} }
fn (g mut Gen) infix_expr(node ast.InfixExpr) { fn (g mut Gen) infix_expr(node ast.InfixExpr) {
// g.write('/*infix*/')
// if it.left_type == table.string_type_idx { // if it.left_type == table.string_type_idx {
// g.write('/*$node.left_type str*/') // g.write('/*$node.left_type str*/')
// } // }
@ -1103,6 +1136,9 @@ fn (g mut Gen) write_sorted_types() {
fn (g mut Gen) write_types(types []table.TypeSymbol) { fn (g mut Gen) write_types(types []table.TypeSymbol) {
for typ in types { for typ in types {
if typ.name.starts_with('C.') {
continue
}
// sym := g.table.get_type_symbol(typ) // sym := g.table.get_type_symbol(typ)
match typ.info { match typ.info {
table.Struct { table.Struct {

View File

@ -49,6 +49,8 @@ fn compare_texts(a, b, path string) bool {
println('${path}: got\n$a') println('${path}: got\n$a')
println('${term_fail} ${i}') println('${term_fail} ${i}')
println(term.red('i=$i "$line_a" expected="$line_b"')) println(term.red('i=$i "$line_a" expected="$line_b"'))
// println(lines_b[i + 1])
// println(lines_b[i + 2])
// exit(1) // exit(1)
return false return false
} }

View File

@ -59,7 +59,7 @@ int main() {
println(int_str(localmod__pub_int_const)); println(int_str(localmod__pub_int_const));
int g = ((int)(3.0)); int g = ((int)(3.0));
byte* bytes = ((byte*)(0)); byte* bytes = ((byte*)(0));
User* user_ptr = (User*)memdup(&(User){}, sizeof(User)); User* user_ptr = (User*)memdup(&(User){0}, sizeof(User));
return 0; return 0;
} }
@ -82,7 +82,7 @@ i < 10; i++) {
}); });
array_User users = new_array_from_c_array(1, 1, sizeof(array_User), (User[]){ array_User users = new_array_from_c_array(1, 1, sizeof(array_User), (User[]){
(User){ (User){
}, 0},
}); });
bool b = (*(bool*)array_get(bools, 0)); bool b = (*(bool*)array_get(bools, 0));
array_string mystrings = new_array_from_c_array(2, 2, sizeof(array_string), (string[]){ array_string mystrings = new_array_from_c_array(2, 2, sizeof(array_string), (string[]){

View File

@ -30,7 +30,7 @@ void init_user() {
User get_user() { User get_user() {
User user = (User){ User user = (User){
}; 0};
return user; return user;
} }

View File

@ -17,7 +17,7 @@ tos3(""),
int main() { int main() {
User user = (User){ User user = (User){
}; 0};
user.age = 10; user.age = 10;
user.age++; user.age++;
user.name = tos3("bob"); user.name = tos3("bob");

View File

@ -1440,6 +1440,7 @@ fn (p mut Parser) struct_decl() ast.StructDecl {
mut_pos: mut_pos mut_pos: mut_pos
pub_pos: pub_pos pub_pos: pub_pos
pub_mut_pos: pub_mut_pos pub_mut_pos: pub_mut_pos
is_c: is_c
} }
} }

View File

@ -3,469 +3,3 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module table module table
import (
strings
)
pub type TypeInfo = Array | ArrayFixed | Map | Struct |
MultiReturn | Alias | Enum | SumType | Fn
pub struct TypeSymbol {
pub:
parent_idx int
mut:
info TypeInfo
kind Kind
name string
methods []Fn
// is_sum bool
}
pub const (
// primitive types
void_type_idx = 1
voidptr_type_idx = 2
byteptr_type_idx = 3
charptr_type_idx = 4
i8_type_idx = 5
i16_type_idx = 6
int_type_idx = 7
i64_type_idx = 8
byte_type_idx = 9
u16_type_idx = 10
u32_type_idx = 11
u64_type_idx = 12
f32_type_idx = 13
f64_type_idx = 14
char_type_idx = 15
bool_type_idx = 16
none_type_idx = 17
// advanced / defined from v structs
string_type_idx = 18
array_type_idx = 19
map_type_idx = 20
)
pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64',
'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'map', 'struct',
'mapnode', 'ustring']
)
pub struct MultiReturn {
pub:
name string
mut:
types []Type
}
pub enum Kind {
placeholder
void
voidptr
byteptr
charptr
i8
i16
int
i64
byte
u16
u32
u64
f32
f64
char
bool
none_
string
array
array_fixed
map
struct_
multi_return
sum_type
alias
enum_
function
}
pub fn (t &TypeSymbol) str() string {
return t.name.replace('array_', '[]')
}
[inline]
pub fn (t &TypeSymbol) enum_info() Enum {
match t.info {
Enum {
return it
}
else {
panic('TypeSymbol.enum_info(): no enum info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) mr_info() MultiReturn {
match t.info {
MultiReturn {
return it
}
else {
panic('TypeSymbol.mr_info(): no multi return info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) array_info() Array {
match t.info {
Array {
return it
}
else {
panic('TypeSymbol.array_info(): no array info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
match t.info {
ArrayFixed {
return it
}
else {
panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) map_info() Map {
match t.info {
Map {
return it
}
else {
panic('TypeSymbol.map_info(): no map info for type: $t.name')
}
}
}
/*
pub fn (t TypeSymbol) str() string {
return t.name
}
*/
pub fn (t mut Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there
// save index check, 0 will mean not found
t.register_type_symbol(TypeSymbol{
kind: .placeholder
name: 'reserved_0'
})
t.register_type_symbol(TypeSymbol{
kind: .void
name: 'void'
})
t.register_type_symbol(TypeSymbol{
kind: .voidptr
name: 'voidptr'
})
t.register_type_symbol(TypeSymbol{
kind: .byteptr
name: 'byteptr'
})
t.register_type_symbol(TypeSymbol{
kind: .charptr
name: 'charptr'
})
t.register_type_symbol(TypeSymbol{
kind: .i8
name: 'i8'
})
t.register_type_symbol(TypeSymbol{
kind: .i16
name: 'i16'
})
t.register_type_symbol(TypeSymbol{
kind: .int
name: 'int'
})
t.register_type_symbol(TypeSymbol{
kind: .i64
name: 'i64'
})
t.register_type_symbol(TypeSymbol{
kind: .byte
name: 'byte'
})
t.register_type_symbol(TypeSymbol{
kind: .u16
name: 'u16'
})
t.register_type_symbol(TypeSymbol{
kind: .u32
name: 'u32'
})
t.register_type_symbol(TypeSymbol{
kind: .u64
name: 'u64'
})
t.register_type_symbol(TypeSymbol{
kind: .f32
name: 'f32'
})
t.register_type_symbol(TypeSymbol{
kind: .f64
name: 'f64'
})
t.register_type_symbol(TypeSymbol{
kind: .char
name: 'char'
})
t.register_type_symbol(TypeSymbol{
kind: .bool
name: 'bool'
})
t.register_type_symbol(TypeSymbol{
kind: .none_
name: 'none'
})
t.register_type_symbol(TypeSymbol{
kind: .string
name: 'string'
})
t.register_type_symbol(TypeSymbol{
kind: .array
name: 'array'
})
t.register_type_symbol(TypeSymbol{
kind: .map
name: 'map'
})
// TODO: remove. for v1 map compatibility
map_string_string_idx := t.find_or_register_map(string_type, string_type)
map_string_int_idx := t.find_or_register_map(string_type, int_type)
t.register_type_symbol(TypeSymbol{
kind: .alias
name: 'map_string'
parent_idx: map_string_string_idx
})
t.register_type_symbol(TypeSymbol{
kind: .alias
name: 'map_int'
parent_idx: map_string_int_idx
})
}
[inline]
pub fn (t &TypeSymbol) is_int() bool {
return t.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64]
}
[inline]
pub fn (t &TypeSymbol) is_float() bool {
return t.kind in [.f32, .f64]
}
[inline]
pub fn (t &TypeSymbol) is_number() bool {
return t.is_int() || t.is_float()
}
pub fn (k Kind) str() string {
k_str := match k {
.placeholder{
'placeholder'
}
.void{
'void'
}
.voidptr{
'voidptr'
}
.charptr{
'charptr'
}
.byteptr{
'byteptr'
}
.struct_{
'struct'
}
.int{
'int'
}
.i8{
'i8'
}
.i16{
'i16'
}
.i64{
'i64'
}
.byte{
'byte'
}
.u16{
'u16'
}
.u32{
'u32'
}
.u64{
'u64'
}
.f32{
'f32'
}
.f64{
'f64'
}
.string{
'string'
}
.char{
'char'
}
.bool{
'bool'
}
.none_{
'none'
}
.array{
'array'
}
.array_fixed{
'array_fixed'
}
.map{
'map'
}
.multi_return{
'multi_return'
}
.sum_type{
'sum_type'
}
.alias{
'alias'
}
.enum_{
'enum'
}
else {
'unknown'}
}
return k_str
}
pub fn (kinds []Kind) str() string {
mut kinds_str := ''
for i, k in kinds {
kinds_str += k.str()
if i < kinds.len - 1 {
kinds_str += '_'
}
}
return kinds_str
}
pub struct Struct {
pub mut:
fields []Field
}
pub struct Enum {
pub mut:
vals []string
}
pub struct Alias {
pub:
foo string
}
pub struct Field {
pub:
name string
mut:
typ Type
}
pub struct Array {
pub:
nr_dims int
mut:
elem_type Type
}
pub struct ArrayFixed {
pub:
nr_dims int
size int
mut:
elem_type Type
}
pub struct Map {
pub mut:
key_type Type
value_type Type
}
pub struct SumType {
pub:
variants []Type
}
pub fn (table &Table) type_to_str(t Type) string {
sym := table.get_type_symbol(t)
if sym.kind == .multi_return {
mut res := '('
mr_info := sym.info as MultiReturn
for i, typ in mr_info.types {
res += table.type_to_str(typ)
if i < mr_info.types.len - 1 {
res += ', '
}
}
res += ')'
return res
}
mut res := sym.name
if sym.kind == .array {
res = res.replace('array_', '[]')
}
else if sym.kind == .map {
res = res.replace('map_string_', 'map[string]')
}
// mod.submod.submod2.Type => submod2.Type
if res.contains('.') {
vals := res.split('.')
if vals.len > 2 {
res = vals[vals.len - 2] + '.' + vals[vals.len - 1]
}
}
if type_is_optional(t) {
res = '?' + res
}
nr_muls := type_nr_muls(t)
if nr_muls > 0 {
res = strings.repeat(`&`, nr_muls) + res
}
/*
if res.starts_with(cur_mod +'.') {
res = res[cur_mod.len+1.. ]
}
*/
return res
}

View File

@ -0,0 +1,621 @@
module table
import (
strings
)
pub type Type int
pub type TypeInfo = Array | ArrayFixed | Map | Struct |
MultiReturn | Alias | Enum | SumType | Fn
pub struct TypeSymbol {
pub:
parent_idx int
mut:
info TypeInfo
kind Kind
name string
methods []Fn
// is_sum bool
}
pub enum TypeExtra {
unset
optional
variadic
}
pub fn (types []Type) contains(typ Type) bool {
for t in types {
if int(typ) == int(t) {
return true
}
}
return false
}
// return underlying TypeSymbol idx
[inline]
pub fn type_idx(t Type) int {
return u16(t) & 0xffff
}
// return nr_muls
[inline]
pub fn type_nr_muls(t Type) int {
return (int(t)>>16) & 0xff
}
// return true if pointer (nr_muls>0)
[inline]
pub fn type_is_ptr(t Type) bool {
return type_nr_muls(t) > 0 // || t == voidptr_type_idx
}
// set nr_muls on Type and return it
[inline]
pub fn type_set_nr_muls(t Type, nr_muls int) Type {
if nr_muls < 0 || nr_muls > 255 {
panic('typ_set_nr_muls: nr_muls must be between 0 & 255')
}
return (int(type_extra(t))<<24) | (nr_muls<<16) | u16(type_idx(t))
}
// increments nr_nuls on Type and return it
[inline]
pub fn type_to_ptr(t Type) Type {
nr_muls := type_nr_muls(t)
if nr_muls == 255 {
panic('type_to_pre: nr_muls is already at max of 255')
}
return (int(type_extra(t))<<24) | ((nr_muls + 1)<<16) | u16(type_idx(t))
}
// decrement nr_muls on Type and return it
[inline]
pub fn type_deref(t Type) Type {
nr_muls := type_nr_muls(t)
if nr_muls == 0 {
panic('deref: type `$t` is not a pointer')
}
return (int(type_extra(t))<<24) | ((nr_muls - 1)<<16) | u16(type_idx(t))
}
// return extra info
[inline]
pub fn type_extra(t Type) TypeExtra {
return (int(t)>>24) & 0xff
}
// set extra info
[inline]
pub fn type_set_extra(t Type, extra TypeExtra) Type {
return (int(extra)<<24) | (type_nr_muls(t)<<16) | u16(type_idx(t))
}
[inline]
pub fn type_is_optional(t Type) bool {
return type_extra(t) == .optional
}
[inline]
pub fn type_to_optional(t Type) Type {
return type_set_extra(t, .optional)
}
[inline]
pub fn type_is_variadic(t Type) bool {
return type_extra(t) == .variadic
}
[inline]
pub fn type_to_variadic(t Type) Type {
return type_set_extra(t, .variadic)
}
// new type with idx of TypeSymbol, not pointer (nr_muls=0)
[inline]
pub fn new_type(idx int) Type {
if idx < 1 || idx > 65536 {
panic('new_type_id: idx must be between 1 & 65536')
}
return idx
}
// return Type idx of TypeSymbol & specify if ptr (nr_muls)
[inline]
pub fn new_type_ptr(idx int, nr_muls int) Type {
if idx < 1 || idx > 65536 {
panic('typ_ptr: idx must be between 1 & 65536')
}
if nr_muls < 0 || nr_muls > 255 {
panic('typ_ptr: nr_muls must be between 0 & 255')
}
return (nr_muls<<16) | u16(idx)
}
/*
pub fn is_number(typ Type) bool {
typ_sym := c.table.get_type_symbol(typ)
return typ_sym.is_int()
//idx := type_idx(typ)
//return idx in [int_type_idx, byte_type_idx, u64_type_idx]
}
*/
pub const (
// primitive types
void_type_idx = 1
voidptr_type_idx = 2
byteptr_type_idx = 3
charptr_type_idx = 4
i8_type_idx = 5
i16_type_idx = 6
int_type_idx = 7
i64_type_idx = 8
byte_type_idx = 9
u16_type_idx = 10
u32_type_idx = 11
u64_type_idx = 12
f32_type_idx = 13
f64_type_idx = 14
char_type_idx = 15
bool_type_idx = 16
none_type_idx = 17
// advanced / defined from v structs
string_type_idx = 18
array_type_idx = 19
map_type_idx = 20
)
pub const (
number_idxs = [int_type_idx, byte_type_idx, u16_type_idx, i16_type_idx, i64_type_idx, u32_type_idx, u64_type_idx]
)
pub const (
void_type = new_type(void_type_idx)
voidptr_type = new_type(voidptr_type_idx)
byteptr_type = new_type(byteptr_type_idx)
charptr_type = new_type(charptr_type_idx)
i8_type = new_type(i8_type_idx)
int_type = new_type(int_type_idx)
i16_type = new_type(i16_type_idx)
i64_type = new_type(i64_type_idx)
byte_type = new_type(byte_type_idx)
u16_type = new_type(u16_type_idx)
u32_type = new_type(u32_type_idx)
u64_type = new_type(u64_type_idx)
f32_type = new_type(f32_type_idx)
f64_type = new_type(f64_type_idx)
char_type = new_type(char_type_idx)
bool_type = new_type(bool_type_idx)
none_type = new_type(none_type_idx)
string_type = new_type(string_type_idx)
array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx)
)
pub const (
builtin_type_names = ['void', 'voidptr', 'charptr', 'byteptr', 'i8', 'i16', 'int', 'i64', 'u16', 'u32', 'u64',
'f32', 'f64', 'string', 'char', 'byte', 'bool', 'none', 'array', 'array_fixed', 'map', 'struct',
'mapnode', 'ustring']
)
pub struct MultiReturn {
pub:
name string
mut:
types []Type
}
pub enum Kind {
placeholder
void
voidptr
byteptr
charptr
i8
i16
int
i64
byte
u16
u32
u64
f32
f64
char
bool
none_
string
array
array_fixed
map
struct_
multi_return
sum_type
alias
enum_
function
}
pub fn (t &TypeSymbol) str() string {
return t.name.replace('array_', '[]')
}
[inline]
pub fn (t &TypeSymbol) enum_info() Enum {
match t.info {
Enum {
return it
}
else {
panic('TypeSymbol.enum_info(): no enum info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) mr_info() MultiReturn {
match t.info {
MultiReturn {
return it
}
else {
panic('TypeSymbol.mr_info(): no multi return info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) array_info() Array {
match t.info {
Array {
return it
}
else {
panic('TypeSymbol.array_info(): no array info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) array_fixed_info() ArrayFixed {
match t.info {
ArrayFixed {
return it
}
else {
panic('TypeSymbol.array_fixed(): no array fixed info for type: $t.name')
}
}
}
[inline]
pub fn (t &TypeSymbol) map_info() Map {
match t.info {
Map {
return it
}
else {
panic('TypeSymbol.map_info(): no map info for type: $t.name')
}
}
}
/*
pub fn (t TypeSymbol) str() string {
return t.name
}
*/
pub fn (t mut Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there
// save index check, 0 will mean not found
t.register_type_symbol(TypeSymbol{
kind: .placeholder
name: 'reserved_0'
})
t.register_type_symbol(TypeSymbol{
kind: .void
name: 'void'
})
t.register_type_symbol(TypeSymbol{
kind: .voidptr
name: 'voidptr'
})
t.register_type_symbol(TypeSymbol{
kind: .byteptr
name: 'byteptr'
})
t.register_type_symbol(TypeSymbol{
kind: .charptr
name: 'charptr'
})
t.register_type_symbol(TypeSymbol{
kind: .i8
name: 'i8'
})
t.register_type_symbol(TypeSymbol{
kind: .i16
name: 'i16'
})
t.register_type_symbol(TypeSymbol{
kind: .int
name: 'int'
})
t.register_type_symbol(TypeSymbol{
kind: .i64
name: 'i64'
})
t.register_type_symbol(TypeSymbol{
kind: .byte
name: 'byte'
})
t.register_type_symbol(TypeSymbol{
kind: .u16
name: 'u16'
})
t.register_type_symbol(TypeSymbol{
kind: .u32
name: 'u32'
})
t.register_type_symbol(TypeSymbol{
kind: .u64
name: 'u64'
})
t.register_type_symbol(TypeSymbol{
kind: .f32
name: 'f32'
})
t.register_type_symbol(TypeSymbol{
kind: .f64
name: 'f64'
})
t.register_type_symbol(TypeSymbol{
kind: .char
name: 'char'
})
t.register_type_symbol(TypeSymbol{
kind: .bool
name: 'bool'
})
t.register_type_symbol(TypeSymbol{
kind: .none_
name: 'none'
})
t.register_type_symbol(TypeSymbol{
kind: .string
name: 'string'
})
t.register_type_symbol(TypeSymbol{
kind: .array
name: 'array'
})
t.register_type_symbol(TypeSymbol{
kind: .map
name: 'map'
})
// TODO: remove. for v1 map compatibility
map_string_string_idx := t.find_or_register_map(string_type, string_type)
map_string_int_idx := t.find_or_register_map(string_type, int_type)
t.register_type_symbol(TypeSymbol{
kind: .alias
name: 'map_string'
parent_idx: map_string_string_idx
})
t.register_type_symbol(TypeSymbol{
kind: .alias
name: 'map_int'
parent_idx: map_string_int_idx
})
}
[inline]
pub fn (t &TypeSymbol) is_int() bool {
return t.kind in [.i8, .i16, .int, .i64, .byte, .u16, .u32, .u64]
}
[inline]
pub fn (t &TypeSymbol) is_float() bool {
return t.kind in [.f32, .f64]
}
[inline]
pub fn (t &TypeSymbol) is_number() bool {
return t.is_int() || t.is_float()
}
pub fn (k Kind) str() string {
k_str := match k {
.placeholder{
'placeholder'
}
.void{
'void'
}
.voidptr{
'voidptr'
}
.charptr{
'charptr'
}
.byteptr{
'byteptr'
}
.struct_{
'struct'
}
.int{
'int'
}
.i8{
'i8'
}
.i16{
'i16'
}
.i64{
'i64'
}
.byte{
'byte'
}
.u16{
'u16'
}
.u32{
'u32'
}
.u64{
'u64'
}
.f32{
'f32'
}
.f64{
'f64'
}
.string{
'string'
}
.char{
'char'
}
.bool{
'bool'
}
.none_{
'none'
}
.array{
'array'
}
.array_fixed{
'array_fixed'
}
.map{
'map'
}
.multi_return{
'multi_return'
}
.sum_type{
'sum_type'
}
.alias{
'alias'
}
.enum_{
'enum'
}
else {
'unknown'}
}
return k_str
}
pub fn (kinds []Kind) str() string {
mut kinds_str := ''
for i, k in kinds {
kinds_str += k.str()
if i < kinds.len - 1 {
kinds_str += '_'
}
}
return kinds_str
}
pub struct Struct {
pub mut:
fields []Field
}
pub struct Enum {
pub mut:
vals []string
}
pub struct Alias {
pub:
foo string
}
pub struct Field {
pub:
name string
mut:
typ Type
}
pub struct Array {
pub:
nr_dims int
mut:
elem_type Type
}
pub struct ArrayFixed {
pub:
nr_dims int
size int
mut:
elem_type Type
}
pub struct Map {
pub mut:
key_type Type
value_type Type
}
pub struct SumType {
pub:
variants []Type
}
pub fn (table &Table) type_to_str(t Type) string {
sym := table.get_type_symbol(t)
if sym.kind == .multi_return {
mut res := '('
mr_info := sym.info as MultiReturn
for i, typ in mr_info.types {
res += table.type_to_str(typ)
if i < mr_info.types.len - 1 {
res += ', '
}
}
res += ')'
return res
}
mut res := sym.name
if sym.kind == .array {
res = res.replace('array_', '[]')
}
else if sym.kind == .map {
res = res.replace('map_string_', 'map[string]')
}
// mod.submod.submod2.Type => submod2.Type
if res.contains('.') {
vals := res.split('.')
if vals.len > 2 {
res = vals[vals.len - 2] + '.' + vals[vals.len - 1]
}
}
if type_is_optional(t) {
res = '?' + res
}
nr_muls := type_nr_muls(t)
if nr_muls > 0 {
res = strings.repeat(`&`, nr_muls) + res
}
/*
if res.starts_with(cur_mod +'.') {
res = res[cur_mod.len+1.. ]
}
*/
return res
}

View File

@ -3,6 +3,10 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module table module table
import (
strings
)
pub struct Table { pub struct Table {
// struct_fields map[string][]string // struct_fields map[string][]string
pub mut: pub mut:

View File

@ -1,153 +0,0 @@
module table
pub type Type int
pub enum TypeExtra {
unset
optional
variadic
}
pub fn (types []Type) contains(typ Type) bool {
for t in types {
if int(typ) == int(t) {
return true
}
}
return false
}
// return underlying TypeSymbol idx
[inline]
pub fn type_idx(t Type) int {
return u16(t) & 0xffff
}
// return nr_muls
[inline]
pub fn type_nr_muls(t Type) int {
return (int(t)>>16) & 0xff
}
// return true if pointer (nr_muls>0)
[inline]
pub fn type_is_ptr(t Type) bool {
return type_nr_muls(t) > 0 // || t == voidptr_type_idx
}
// set nr_muls on Type and return it
[inline]
pub fn type_set_nr_muls(t Type, nr_muls int) Type {
if nr_muls < 0 || nr_muls > 255 {
panic('typ_set_nr_muls: nr_muls must be between 0 & 255')
}
return (int(type_extra(t))<<24) | (nr_muls<<16) | u16(type_idx(t))
}
// increments nr_nuls on Type and return it
[inline]
pub fn type_to_ptr(t Type) Type {
nr_muls := type_nr_muls(t)
if nr_muls == 255 {
panic('type_to_pre: nr_muls is already at max of 255')
}
return (int(type_extra(t))<<24) | ((nr_muls + 1)<<16) | u16(type_idx(t))
}
// decrement nr_muls on Type and return it
[inline]
pub fn type_deref(t Type) Type {
nr_muls := type_nr_muls(t)
if nr_muls == 0 {
panic('deref: type `$t` is not a pointer')
}
return (int(type_extra(t))<<24) | ((nr_muls - 1)<<16) | u16(type_idx(t))
}
// return extra info
[inline]
pub fn type_extra(t Type) TypeExtra {
return (int(t)>>24) & 0xff
}
// set extra info
[inline]
pub fn type_set_extra(t Type, extra TypeExtra) Type {
return (int(extra)<<24) | (type_nr_muls(t)<<16) | u16(type_idx(t))
}
[inline]
pub fn type_is_optional(t Type) bool {
return type_extra(t) == .optional
}
[inline]
pub fn type_to_optional(t Type) Type {
return type_set_extra(t, .optional)
}
[inline]
pub fn type_is_variadic(t Type) bool {
return type_extra(t) == .variadic
}
[inline]
pub fn type_to_variadic(t Type) Type {
return type_set_extra(t, .variadic)
}
// new type with idx of TypeSymbol, not pointer (nr_muls=0)
[inline]
pub fn new_type(idx int) Type {
if idx < 1 || idx > 65536 {
panic('new_type_id: idx must be between 1 & 65536')
}
return idx
}
// return Type idx of TypeSymbol & specify if ptr (nr_muls)
[inline]
pub fn new_type_ptr(idx int, nr_muls int) Type {
if idx < 1 || idx > 65536 {
panic('typ_ptr: idx must be between 1 & 65536')
}
if nr_muls < 0 || nr_muls > 255 {
panic('typ_ptr: nr_muls must be between 0 & 255')
}
return (nr_muls<<16) | u16(idx)
}
pub const (
number_idxs = [int_type_idx, byte_type_idx, u16_type_idx, i16_type_idx, i64_type_idx, u32_type_idx, u64_type_idx]
)
/*
pub fn is_number(typ Type) bool {
typ_sym := c.table.get_type_symbol(typ)
return typ_sym.is_int()
//idx := type_idx(typ)
//return idx in [int_type_idx, byte_type_idx, u64_type_idx]
}
*/
pub const (
void_type = new_type(void_type_idx)
voidptr_type = new_type(voidptr_type_idx)
byteptr_type = new_type(byteptr_type_idx)
charptr_type = new_type(charptr_type_idx)
i8_type = new_type(i8_type_idx)
int_type = new_type(int_type_idx)
i16_type = new_type(i16_type_idx)
i64_type = new_type(i64_type_idx)
byte_type = new_type(byte_type_idx)
u16_type = new_type(u16_type_idx)
u32_type = new_type(u32_type_idx)
u64_type = new_type(u64_type_idx)
f32_type = new_type(f32_type_idx)
f64_type = new_type(f64_type_idx)
char_type = new_type(char_type_idx)
bool_type = new_type(bool_type_idx)
none_type = new_type(none_type_idx)
string_type = new_type(string_type_idx)
array_type = new_type(array_type_idx)
map_type = new_type(map_type_idx)
)

View File

@ -0,0 +1,48 @@
import os
import term
fn test_all() {
files := os.ls('.') or {
panic(err)
}
for file in files {
if !file.ends_with('.vv') {
continue
}
print(file + ' ')
program := file.replace('.vv', '.v')
os.cp(file, program) or {
panic(err)
}
os.rm('exe')
x := os.exec('v -o exe -cflags "-w" -cg -backend experimental $program') or {
panic(err)
}
println(x.output.limit(30))
os.rm(program)
res := os.exec('./exe') or {
println('nope')
panic(err)
}
// println('============')
// println(res.output)
// println('============')
mut expected := os.read_file(program.replace('.v', '') + '.out') or {
panic(err)
}
expected = expected.trim_space()
found := res.output.trim_space()
if expected != found {
println(term.red('FAIL'))
println('============')
println('expected:')
println(expected)
println('\nfound:')
println(found)
println('============')
}
else {
println(term.green('OK'))
}
}
}

View File

@ -0,0 +1 @@
hello world

View File

@ -0,0 +1,3 @@
fn main() {
println('hello world')
}

View File

@ -0,0 +1,6 @@
Hello, game developers!
Hello, web developers!
Hello, tools developers!
Hello, science developers!
Hello, systems developers!
Hello, embedded developers!

View File

@ -0,0 +1,7 @@
fn main() {
areas := ['game', 'web', 'tools', 'science', 'systems', 'embedded']
for i :=0;i<areas.len; i++{
area:=areas[i]
println('Hello, $area developers!')
}
}

View File

@ -0,0 +1 @@
compiler_test.v

10
vlib/v/tests/os.vv 100644
View File

@ -0,0 +1,10 @@
import os
fn main() {
files := os.ls('.') or { panic(err) }
for file in files {
if file.ends_with('_test.v') {
println(file)
}
}
}

View File

@ -427,46 +427,6 @@ pub fn (tok Token) is_unary() bool {
.plus, .minus, .not, .bit_not, .mul, .amp] .plus, .minus, .not, .bit_not, .mul, .amp]
} }
/*
// NOTE: do we need this for all tokens (is_left_assoc / is_right_assoc),
// or only ones with the same precedence?
// is_left_assoc returns true if the token is left associative
pub fn (tok Token) is_left_assoc() bool {
return tok.kind in [
// `.`
.dot,
// `+` | `-`
.plus, .minus, // additive
// .number,
// `++` | `--`
.inc, .dec,
// `*` | `/` | `%`
.mul, .div, .mod,
// `^` | `||` | `&`
.xor, .logical_or, .and,
// `==` | `!=`
.eq, .ne,
// `<` | `<=` | `>` | `>=`
.lt, .le, .gt, .ge, .ne, .eq,
// `,`
.comma]
}
// is_right_assoc returns true if the token is right associative
pub fn (tok Token) is_right_assoc() bool {
return tok.kind in [
// `+` | `-` | `!`
.plus, .minus, .not, // unary
// `=` | `+=` | `-=` | `*=` | `/=`
.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign,
// `%=` | `>>=` | `<<=`
.mod_assign, .right_shift_assign, .left_shift_assign,
// `&=` | `^=` | `|=`
.and_assign, .xor_assign, .or_assign]
}
*/
pub fn (tok Kind) is_relational() bool { pub fn (tok Kind) is_relational() bool {
return tok in [ return tok in [
// `<` | `<=` | `>` | `>=` // `<` | `<=` | `>` | `>=`