1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: fix &string cast; vfmt fixes

This commit is contained in:
Alexander Medvednikov 2020-04-07 18:51:39 +02:00
parent 4aedef367c
commit 6bbd1943dd
8 changed files with 122 additions and 92 deletions

View File

@ -43,12 +43,12 @@ NB: A V string should be/is immutable from the point of view of
pub struct string {
// mut:
// hash_cache int
pub:
str byteptr // points to a C style 0 terminated string of bytes.
len int // the length of the .str field, excluding the ending 0 byte. It is always equal to strlen(.str).
}
// mut:
// hash_cache int
pub struct ustring {
pub:
@ -166,8 +166,8 @@ pub fn (s string) replace(rep, with string) string {
mut cur_idx := idxs[idx_pos]
mut b_i := 0
for i := 0; i < s.len; i++ {
// Reached the location of rep, replace it with "with"
if i == cur_idx {
// Reached the location of rep, replace it with "with"
for j in 0..with.len {
b[b_i] = with[j]
b_i++
@ -180,8 +180,8 @@ pub fn (s string) replace(rep, with string) string {
cur_idx = idxs[idx_pos]
}
}
// Rep doesnt start here, just copy
else {
// Rep doesnt start here, just copy
b[b_i] = s[i]
b_i++
}
@ -263,8 +263,8 @@ pub fn (s string) replace_each(vals []string) string {
mut cur_idx := idxs[idx_pos]
mut b_i := 0
for i := 0; i < s.len; i++ {
// Reached the location of rep, replace it with "with"
if i == cur_idx.idx {
// Reached the location of rep, replace it with "with"
rep := vals[cur_idx.val_idx]
with := vals[cur_idx.val_idx + 1]
for j in 0..with.len {
@ -279,8 +279,8 @@ pub fn (s string) replace_each(vals []string) string {
cur_idx = idxs[idx_pos]
}
}
// Rep doesnt start here, just copy
else {
// Rep doesnt start here, just copy
b[b_i] = s.str[i]
b_i++
}

View File

@ -265,6 +265,7 @@ pub struct GlobalDecl {
pub:
name string
expr Expr
has_expr bool
mut:
typ table.Type
}

View File

@ -139,7 +139,8 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
continue
}
if table.type_is_ptr(field.typ) {
c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized', struct_init.pos)
c.warn('reference field `${typ_sym.name}.${field.name}` must be initialized',
struct_init.pos)
}
}
}
@ -212,7 +213,7 @@ fn (c mut Checker) assign_expr(assign_expr mut ast.AssignExpr) {
if !c.table.check(right_type, left_type) {
left_type_sym := c.table.get_type_symbol(left_type)
right_type_sym := c.table.get_type_symbol(right_type)
c.error('cannot assign $right_type_sym.name to $left_type_sym.name', assign_expr.pos)
c.error('cannot assign `$right_type_sym.name` to `$left_type_sym.name`', assign_expr.pos)
}
}
@ -224,8 +225,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
left_type_sym := c.table.get_type_symbol(left_type)
method_name := call_expr.name
// TODO: remove this for actual methods, use only for compiler magic
if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse', 'map',
'slice'] {
if left_type_sym.kind == .array && method_name in ['filter', 'clone', 'repeat', 'reverse',
'map', 'slice'] {
if method_name in ['filter', 'map'] {
array_info := left_type_sym.info as table.Array
mut scope := c.file.scope.innermost(call_expr.pos.pos)
@ -252,7 +253,8 @@ pub fn (c mut Checker) call_expr(call_expr mut ast.CallExpr) table.Type {
}
if method := c.table.type_find_method(left_type_sym, method_name) {
no_args := method.args.len - 1
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
min_required_args := method.args.len - if method.is_variadic && method.args.len >
1 { 2 } else { 1 }
if call_expr.args.len < min_required_args {
c.error('too few arguments in call to `${left_type_sym.name}.$method_name` ($call_expr.args.len instead of $min_required_args)',
call_expr.pos)
@ -479,7 +481,8 @@ pub fn (c mut Checker) return_stmt(return_stmt mut ast.Return) {
return
}
if return_stmt.exprs.len > 0 && c.fn_return_type == table.void_type {
c.error('too many arguments to return, current function does not return anything', return_stmt.pos)
c.error('too many arguments to return, current function does not return anything',
return_stmt.pos)
return
}
expected_type := c.fn_return_type
@ -542,7 +545,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
if !c.table.check(val_type, var_type) {
val_type_sym := c.table.get_type_symbol(val_type)
var_type_sym := c.table.get_type_symbol(var_type)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`',
assign_stmt.pos)
}
}
ident_var_info.typ = val_type
@ -568,7 +572,8 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
if !c.table.check(val_type, var_type) {
val_type_sym := c.table.get_type_symbol(val_type)
var_type_sym := c.table.get_type_symbol(var_type)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`',
assign_stmt.pos)
}
}
ident_var_info.typ = val_type
@ -1181,7 +1186,8 @@ pub fn (c mut Checker) index_expr(node mut ast.IndexExpr) table.Type {
// index_type_sym.kind != .enum_) {
if typ_sym.kind in [.array, .array_fixed] && !(table.is_number(index_type) || index_type_sym.kind ==
.enum_) {
c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)', node.pos)
c.error('non-integer index `$index_type_sym.name` (array type `$typ_sym.name`)',
node.pos)
} else if typ_sym.kind == .map && table.type_idx(index_type) != table.string_type_idx {
c.error('non-string map index (map type `$typ_sym.name`)', node.pos)
}
@ -1252,12 +1258,14 @@ pub fn (c mut Checker) map_init(node mut ast.MapInit) table.Type {
if !c.table.check(key_type, key0_type) {
key0_type_sym := c.table.get_type_symbol(key0_type)
key_type_sym := c.table.get_type_symbol(key_type)
c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key', node.pos)
c.error('map init: cannot use `$key_type_sym.name` as `$key0_type_sym` for map key',
node.pos)
}
if !c.table.check(val_type, val0_type) {
val0_type_sym := c.table.get_type_symbol(val0_type)
val_type_sym := c.table.get_type_symbol(val_type)
c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value', node.pos)
c.error('map init: cannot use `$val_type_sym.name` as `$val0_type_sym` for map value',
node.pos)
}
}
map_type := table.new_type(c.table.find_or_register_map(key0_type, val0_type))

View File

@ -11,7 +11,7 @@ import (
const (
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t']
max_len = 100
max_len = 90
)
struct Fmt {
@ -137,6 +137,11 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
}
f.is_assign = false
}
ast.AssertStmt {
f.write('assert ')
f.expr(it.expr)
f.writeln('')
}
ast.Attr {
f.writeln('[$it.name]')
}
@ -159,6 +164,16 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
ast.Comment {
f.comment(it)
}
ast.CompIf {
inversion := if it.is_not { '!' } else { '' }
f.writeln('\$if ${inversion}${it.val} {')
f.stmts(it.stmts)
if it.has_else {
f.writeln('} \$else {')
f.stmts(it.else_stmts)
}
f.writeln('}')
}
ast.ConstDecl {
if it.is_pub {
f.write('pub ')
@ -252,6 +267,14 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
f.stmts(it.stmts)
f.writeln('}')
}
ast.GlobalDecl {
f.write('__global $it.name ')
f.write(f.table.type_to_str(it.typ))
if it.has_expr {
f.write(' = ')
f.expr(it.expr)
}
}
ast.GotoLabel {
f.writeln('$it.name:')
}
@ -285,29 +308,13 @@ fn (f mut Fmt) stmt(node ast.Stmt) {
ast.StructDecl {
f.struct_decl(it)
}
ast.UnsafeStmt {
f.writeln('unsafe {')
f.stmts(it.stmts)
f.writeln('}')
}
ast.Import {}
ast.TypeDecl {
// already handled in f.imports
f.type_decl(it)
}
ast.AssertStmt {
f.write('assert ')
f.expr(it.expr)
f.writeln('')
}
ast.CompIf {
inversion := if it.is_not { '!' } else { '' }
f.writeln('\$if ${inversion}${it.val} {')
ast.UnsafeStmt {
f.writeln('unsafe {')
f.stmts(it.stmts)
if it.has_else {
f.writeln('} \$else {')
f.stmts(it.else_stmts)
}
f.writeln('}')
}
else {
@ -575,6 +582,15 @@ fn (f mut Fmt) expr(node ast.Expr) {
f.write('.')
f.write(it.field)
}
ast.SizeOf {
f.writeln('sizeof(')
if it.type_name != '' {
f.writeln(it.type_name)
} else {
f.writeln(f.table.type_to_str(it.typ))
}
f.writeln(')')
}
ast.StringLiteral {
if it.val.contains("'") {
f.write('"$it.val"')

View File

@ -15,10 +15,10 @@ import (
)
const (
c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free',
'panic', 'auto', 'char', 'default', 'do', 'double', 'extern', 'float', 'inline',
'int', 'long', 'register', 'restrict', 'short', 'signed', 'sizeof', 'static', 'switch',
'typedef', 'union', 'unsigned', 'void', 'volatile', 'while']
c_reserved = ['delete', 'exit', 'unix', 'error', 'calloc', 'malloc', 'free', 'panic', 'auto',
'char', 'default', 'do', 'double', 'extern', 'float', 'inline', 'int', 'long', 'register',
'restrict', 'short', 'signed', 'sizeof', 'static', 'switch', 'typedef', 'union', 'unsigned',
'void', 'volatile', 'while']
)
struct Gen {
@ -58,8 +58,8 @@ mut:
}
const (
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t',
'\t\t\t\t\t\t\t', '\t\t\t\t\t\t\t\t']
tabs = ['', '\t', '\t\t', '\t\t\t', '\t\t\t\t', '\t\t\t\t\t', '\t\t\t\t\t\t', '\t\t\t\t\t\t\t',
'\t\t\t\t\t\t\t\t']
)
pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string {
@ -86,7 +86,7 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
indent: -1
}
g.init()
//
//
mut autofree_used := false
for file in files {
g.file = file
@ -115,10 +115,10 @@ pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string
if g.is_test {
g.write_tests_main()
}
//
//
g.finish()
return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() +
g.definitions.str() + g.gowrappers.str() + g.stringliterals.str() + g.out.str()
return g.hashes() + g.includes.str() + g.typedefs.str() + g.typedefs2.str() + g.definitions.str() +
g.gowrappers.str() + g.stringliterals.str() + g.out.str()
}
pub fn (g Gen) hashes() string {
@ -141,7 +141,7 @@ pub fn (g mut Gen) init() {
g.write_sorted_types()
g.write_multi_return_types()
g.definitions.writeln('// end of definitions #endif')
//
//
g.stringliterals.writeln('')
g.stringliterals.writeln('// >> string literal consts')
g.stringliterals.writeln('void vinit_string_literals(){')
@ -205,7 +205,7 @@ pub fn (g mut Gen) typ(t table.Type) string {
return styp
}
//
//
pub fn (g mut Gen) write_typedef_types() {
for typ in g.table.types {
match typ.kind {
@ -817,7 +817,7 @@ fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
}
}
*/
//
//
g.fn_args(it.args, it.is_variadic)
if it.no_body {
// Just a function header.
@ -1006,7 +1006,8 @@ fn (g mut Gen) expr(node ast.Expr) {
g.out.go_back(1)
}
sym := g.table.get_type_symbol(it.typ)
if sym.kind == .string {
if sym.kind == .string && !table.type_is_ptr(it.typ) {
// `string(x)` needs `tos()`, but not `&string(x)
// `tos(str, len)`, `tos2(str)`
if it.has_arg {
g.write('tos(')
@ -1135,8 +1136,7 @@ fn (g mut Gen) expr(node ast.Expr) {
g.write('tos3("$escaped_val")')
return
}
escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n',
'\\n'])
escaped_val := it.val.replace_each(['"', '\\"', '\r\n', '\\n', '\n', '\\n'])
if g.is_c_call || it.is_c {
// In C calls we have to generate C strings
// `C.printf("hi")` => `printf("hi");`
@ -1361,8 +1361,7 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) {
g.expr(node.left)
g.write(')')
}
} else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind ==
.array {
} else if node.op == .left_shift && g.table.get_type_symbol(node.left_type).kind == .array {
// arr << val
tmp := g.new_tmp_var()
sym := g.table.get_type_symbol(node.left_type)
@ -1452,7 +1451,7 @@ fn (g mut Gen) match_expr(node ast.MatchExpr) {
// sum_type_str
} else if type_sym.kind == .string {
g.write('string_eq(')
//
//
g.expr(node.cond)
g.write(', ')
// g.write('string_eq($tmp, ')
@ -1547,8 +1546,7 @@ fn (g mut Gen) if_expr(node ast.IfExpr) {
// one line ?:
// TODO clean this up once `is` is supported
// TODO: make sure only one stmt in each branch
if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind !=
.void {
if node.is_expr && node.branches.len >= 2 && node.has_else && type_sym.kind != .void {
g.inside_ternary = true
g.write('(')
for i, branch in node.branches {
@ -1952,7 +1950,7 @@ fn (g mut Gen) assoc(node ast.Assoc) {
}
fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
is_variadic := expected_types.len > 0 && table.type_is(expected_types[expected_types.len -
1], .variadic)
mut arg_no := 0
for arg in args {
@ -1996,8 +1994,7 @@ fn (g mut Gen) call_args(args []ast.CallArg, expected_types []table.Type) {
[inline]
fn (g mut Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in
table.pointer_type_idxs
arg_is_ptr := table.type_is_ptr(expected_type) || table.type_idx(expected_type) in table.pointer_type_idxs
expr_is_ptr := table.type_is_ptr(arg.typ) || table.type_idx(arg.typ) in table.pointer_type_idxs
if arg.is_mut && !arg_is_ptr {
g.write('&/*mut*/')
@ -2134,7 +2131,7 @@ fn (g mut Gen) write_types(types []table.TypeSymbol) {
g.definitions.writeln('EMPTY_STRUCT_DECLARATION;')
}
// g.definitions.writeln('} $name;\n')
//
//
g.definitions.writeln('};\n')
}
table.Alias {
@ -2201,8 +2198,8 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
// sort graph
dep_graph_sorted := dep_graph.resolve()
if !dep_graph_sorted.acyclic {
verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' +
dep_graph_sorted.display_cycles() + '\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' +
verror('cgen.sort_structs(): the following structs form a dependency cycle:\n' + dep_graph_sorted.display_cycles() +
'\nyou can solve this by making one or both of the dependant struct fields references, eg: field &MyStruct' +
'\nif you feel this is an error, please create a new issue here: https://github.com/vlang/v/issues and tag @joe-conigliaro')
}
// sort types
@ -2339,8 +2336,8 @@ fn (g mut Gen) method_call(node ast.CallExpr) {
return
}
// TODO performance, detect `array` method differently
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free',
'push_many', 'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
if typ_sym.kind == .array && node.name in ['repeat', 'sort_with_compare', 'free', 'push_many',
'trim', 'first', 'last', 'clone', 'reverse', 'slice'] {
// && rec_sym.name == 'array' {
// && rec_sym.name == 'array' && receiver_name.starts_with('array') {
// `array_byte_clone` => `array_clone`
@ -2365,7 +2362,7 @@ fn (g mut Gen) method_call(node ast.CallExpr) {
g.write('/*rec*/*')
}
g.expr(node.left)
is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len -
is_variadic := node.expected_arg_types.len > 0 && table.type_is(node.expected_arg_types[node.expected_arg_types.len -
1], .variadic)
if node.args.len > 0 || is_variadic {
g.write(', ')
@ -2743,8 +2740,7 @@ pub fn (g mut Gen) write_tests_main() {
g.definitions.writeln('int g_test_fails = 0;')
$if windows {
g.writeln('int wmain() {')
}
$else {
} $else {
g.writeln('int main() {')
}
g.writeln('\t_vinit();')

View File

@ -627,7 +627,8 @@ pub fn (p mut Parser) name_expr() ast.Expr {
name_w_mod := p.prepend_mod(name)
// type cast. TODO: finish
// if name in table.builtin_type_names {
if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat', 'C.sigaction']) {
if (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && !(name in ['C.stat',
'C.sigaction']) {
// TODO handle C.stat()
mut to_typ := p.parse_type()
if p.is_amp {
@ -660,9 +661,9 @@ pub fn (p mut Parser) name_expr() ast.Expr {
x := p.call_expr(is_c, mod) // TODO `node,typ :=` should work
node = x
}
} else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod && p.tok.lit in
table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len - 1].is_capital()) &&
!p.inside_match_case {
} else if p.peek_tok.kind == .lcbr && (p.tok.lit[0].is_capital() || is_c || (p.builtin_mod &&
p.tok.lit in table.builtin_type_names)) && (p.tok.lit.len in [1, 2] || !p.tok.lit[p.tok.lit.len -
1].is_capital()) && !p.inside_match_case {
// || p.table.known_type(p.tok.lit)) {
return p.struct_init(false) // short_syntax: false
} else if p.peek_tok.kind == .dot && (p.tok.lit[0].is_capital() && !known_var) {
@ -1714,17 +1715,19 @@ fn (p mut Parser) hash() ast.HashStmt {
}
fn (p mut Parser) global_decl() ast.GlobalDecl {
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' &&
p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod !=
'ui' && p.mod != 'gg2' && p.mod != 'uiold' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
p.error('use `v --enable-globals ...` to enable globals')
}
p.next()
name := p.check_name()
// println(name)
typ := p.parse_type()
if p.tok.kind == .assign {
mut expr := ast.Expr{}
has_expr := p.tok.kind == .assign
if has_expr {
p.next()
p.expr(0)
expr = p.expr(0)
}
// p.genln(p.table.cgen_name_type_pair(name, typ))
/*
@ -1744,6 +1747,8 @@ fn (p mut Parser) global_decl() ast.GlobalDecl {
glob := ast.GlobalDecl{
name: name
typ: typ
has_expr: has_expr
expr: expr
}
p.global_scope.register(name, glob)
return glob

View File

@ -389,34 +389,36 @@ pub fn (t &Table) value_type(typ Type) Type {
// ...string => string
return type_set(typ, .unset)
}
else if typ_sym.kind == .array {
if typ_sym.kind == .array {
// Check index type
info := typ_sym.info as Array
return info.elem_type
}
else if typ_sym.kind == .array_fixed {
if typ_sym.kind == .array_fixed {
info := typ_sym.info as ArrayFixed
return info.elem_type
}
else if typ_sym.kind == .map {
if typ_sym.kind == .map {
info := typ_sym.info as Map
return info.value_type
}
else if typ_sym.kind in [.byteptr, .string] {
if typ_sym.kind == .string && table.type_is_ptr(typ) {
// (&string)[i] => string
return string_type
}
if typ_sym.kind in [.byteptr, .string] {
return byte_type
}
else if type_is_ptr(typ) {
if type_is_ptr(typ) {
// byte* => byte
// bytes[0] is a byte, not byte*
return type_deref(typ)
}
else {
// TODO: remove when map_string is removed
if typ_sym.name == 'map_string' {
return string_type
}
return void_type
// TODO: remove when map_string is removed
if typ_sym.name == 'map_string' {
return string_type
}
return void_type
}
pub fn (t &Table) check(got, expected Type) bool {

View File

@ -1,10 +1,10 @@
import os
import time as t
import crypto.sha256 as s2
import (
os
time as t
crypto.sha256
math
log as l
crypto.sha512 as s5
crypto.sha512
)
struct TestAliasInStruct {
@ -12,7 +12,9 @@ struct TestAliasInStruct {
}
fn test_import() {
assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && s2.size == s2.size && math.pi == math.pi && l.INFO == l.INFO && s5.size == s5.size
info := l.Level.info
assert os.O_RDONLY == os.O_RDONLY && t.month_days[0] == t.month_days[0] && sha256.size ==
sha256.size && math.pi == math.pi && info == .info && sha512.size == sha512.size
}
fn test_alias_in_struct_field() {