v.parser, v.checker, v.gen: add support for [translated] tag (#13373)
parent
054c8b1f13
commit
cec7e91714
|
@ -668,12 +668,13 @@ pub mut:
|
||||||
[heap]
|
[heap]
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub:
|
pub:
|
||||||
nr_lines int // number of source code lines in the file (including newlines and comments)
|
nr_lines int // number of source code lines in the file (including newlines and comments)
|
||||||
nr_bytes int // number of processed source code bytes
|
nr_bytes int // number of processed source code bytes
|
||||||
mod Module // the module of the source file (from `module xyz` at the top)
|
mod Module // the module of the source file (from `module xyz` at the top)
|
||||||
global_scope &Scope
|
global_scope &Scope
|
||||||
is_test bool // true for _test.v files
|
is_test bool // true for _test.v files
|
||||||
is_generated bool // true for `[generated] module xyz` files; turn off notices
|
is_generated bool // true for `[generated] module xyz` files; turn off notices
|
||||||
|
is_translated bool // true for `[translated] module xyz` files; turn off some checks
|
||||||
pub mut:
|
pub mut:
|
||||||
path string // absolute path of the source file - '/projects/v/file.v'
|
path string // absolute path of the source file - '/projects/v/file.v'
|
||||||
path_base string // file name - 'file.v' (useful for tracing)
|
path_base string // file name - 'file.v' (useful for tracing)
|
||||||
|
|
|
@ -177,7 +177,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
if obj.is_stack_obj && !c.inside_unsafe {
|
if obj.is_stack_obj && !c.inside_unsafe {
|
||||||
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
||||||
if !type_sym.is_heap() && !c.pref.translated {
|
if !type_sym.is_heap() && !c.pref.translated && !c.file.is_translated {
|
||||||
suggestion := if type_sym.kind == .struct_ {
|
suggestion := if type_sym.kind == .struct_ {
|
||||||
'declaring `$type_sym.name` as `[heap]`'
|
'declaring `$type_sym.name` as `[heap]`'
|
||||||
} else {
|
} else {
|
||||||
|
@ -278,7 +278,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
// Do now allow `*x = y` outside `unsafe`
|
// Do now allow `*x = y` outside `unsafe`
|
||||||
if left.op == .mul {
|
if left.op == .mul {
|
||||||
if !c.inside_unsafe && !c.pref.translated {
|
if !c.inside_unsafe && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
|
c.error('modifying variables via dereferencing can only be done in `unsafe` blocks',
|
||||||
node.pos)
|
node.pos)
|
||||||
} else {
|
} else {
|
||||||
|
@ -325,7 +325,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
// right type was a generic `T`
|
// right type was a generic `T`
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.pref.translated {
|
if c.pref.translated || c.file.is_translated {
|
||||||
// TODO fix this in C2V instead, for example cast enums to int before using `|` on them.
|
// TODO fix this in C2V instead, for example cast enums to int before using `|` on them.
|
||||||
// TODO replace all c.pref.translated checks with `$if !translated` for performance
|
// TODO replace all c.pref.translated checks with `$if !translated` for performance
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -369,7 +369,7 @@ fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type ast.Type, right
|
||||||
ast.u64_type { 63 }
|
ast.u64_type { 63 }
|
||||||
else { 64 }
|
else { 64 }
|
||||||
}
|
}
|
||||||
if ival > moffset && !c.pref.translated {
|
if ival > moffset && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('shift count for type `$left_sym_final.name` too large (maximum: $moffset bits)',
|
c.error('shift count for type `$left_sym_final.name` too large (maximum: $moffset bits)',
|
||||||
node.right.pos())
|
node.right.pos())
|
||||||
return left_type
|
return left_type
|
||||||
|
|
|
@ -390,11 +390,13 @@ fn (mut c Checker) file_has_main_fn(file &ast.File) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut c Checker) check_valid_snake_case(name string, identifier string, pos token.Pos) {
|
fn (mut c Checker) check_valid_snake_case(name string, identifier string, pos token.Pos) {
|
||||||
if !c.pref.is_vweb && !c.pref.translated && name.len > 0
|
if c.pref.translated || c.file.is_translated {
|
||||||
&& (name[0] == `_` || name.contains('._')) {
|
return
|
||||||
|
}
|
||||||
|
if !c.pref.is_vweb && name.len > 0 && (name[0] == `_` || name.contains('._')) {
|
||||||
c.error('$identifier `$name` cannot start with `_`', pos)
|
c.error('$identifier `$name` cannot start with `_`', pos)
|
||||||
}
|
}
|
||||||
if !c.pref.experimental && !c.pref.translated && util.contains_capital(name) {
|
if !c.pref.experimental && util.contains_capital(name) {
|
||||||
c.error('$identifier `$name` cannot contain uppercase letters, use snake_case instead',
|
c.error('$identifier `$name` cannot contain uppercase letters, use snake_case instead',
|
||||||
pos)
|
pos)
|
||||||
}
|
}
|
||||||
|
@ -407,7 +409,7 @@ fn stripped_name(name string) string {
|
||||||
|
|
||||||
fn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos token.Pos) {
|
fn (mut c Checker) check_valid_pascal_case(name string, identifier string, pos token.Pos) {
|
||||||
sname := stripped_name(name)
|
sname := stripped_name(name)
|
||||||
if sname.len > 0 && !sname[0].is_capital() && !c.pref.translated {
|
if sname.len > 0 && !sname[0].is_capital() && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('$identifier `$name` must begin with capital letter', pos)
|
c.error('$identifier `$name` must begin with capital letter', pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -952,7 +954,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
}
|
}
|
||||||
.and, .logical_or {
|
.and, .logical_or {
|
||||||
if !c.pref.translated {
|
if !c.pref.translated && !c.file.is_translated {
|
||||||
if node.left_type != ast.bool_type_idx {
|
if node.left_type != ast.bool_type_idx {
|
||||||
c.error('left operand for `$node.op` is not a boolean', node.left.pos())
|
c.error('left operand for `$node.op` is not a boolean', node.left.pos())
|
||||||
}
|
}
|
||||||
|
@ -987,7 +989,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
c.error('only `==`, `!=`, `|` and `&` are defined on `[flag]` tagged `enum`, use an explicit cast to `int` if needed',
|
c.error('only `==`, `!=`, `|` and `&` are defined on `[flag]` tagged `enum`, use an explicit cast to `int` if needed',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
} else if !c.pref.translated {
|
} else if !c.pref.translated && !c.file.is_translated {
|
||||||
// Regular enums
|
// Regular enums
|
||||||
c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed',
|
c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed',
|
||||||
node.pos)
|
node.pos)
|
||||||
|
@ -1008,7 +1010,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
}
|
}
|
||||||
// Dual sides check (compatibility check)
|
// Dual sides check (compatibility check)
|
||||||
if !(c.symmetric_check(left_type, right_type) && c.symmetric_check(right_type, left_type))
|
if !(c.symmetric_check(left_type, right_type) && c.symmetric_check(right_type, left_type))
|
||||||
&& !c.pref.translated && !node.left.is_auto_deref_var() && !node.right.is_auto_deref_var() {
|
&& !c.pref.translated && !c.file.is_translated && !node.left.is_auto_deref_var()
|
||||||
|
&& !node.right.is_auto_deref_var() {
|
||||||
// for type-unresolved consts
|
// for type-unresolved consts
|
||||||
if left_type == ast.void_type || right_type == ast.void_type {
|
if left_type == ast.void_type || right_type == ast.void_type {
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
|
@ -1047,7 +1050,7 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Pos) {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
if expr.obj is ast.Var {
|
if expr.obj is ast.Var {
|
||||||
mut v := expr.obj as ast.Var
|
mut v := expr.obj as ast.Var
|
||||||
if !v.is_mut && !c.pref.translated && !c.inside_unsafe {
|
if !v.is_mut && !c.pref.translated && !c.file.is_translated && !c.inside_unsafe {
|
||||||
c.error('`$expr.name` is immutable, declare it with `mut` to make it mutable',
|
c.error('`$expr.name` is immutable, declare it with `mut` to make it mutable',
|
||||||
expr.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
|
@ -1137,7 +1140,7 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Pos) {
|
||||||
pos = expr.pos
|
pos = expr.pos
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !field_info.is_mut && !c.pref.translated {
|
if !field_info.is_mut && !c.pref.translated && !c.file.is_translated {
|
||||||
type_str := c.table.type_to_str(expr.expr_type)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('field `$expr.field_name` of struct `$type_str` is immutable',
|
c.error('field `$expr.field_name` of struct `$type_str` is immutable',
|
||||||
expr.pos)
|
expr.pos)
|
||||||
|
@ -1696,7 +1699,8 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
|
||||||
val := field.expr.val.i64()
|
val := field.expr.val.i64()
|
||||||
if val < checker.int_min || val > checker.int_max {
|
if val < checker.int_min || val > checker.int_max {
|
||||||
c.error('enum value `$val` overflows int', field.expr.pos)
|
c.error('enum value `$val` overflows int', field.expr.pos)
|
||||||
} else if !c.pref.translated && !node.is_multi_allowed && i64(val) in seen {
|
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
|
||||||
|
&& i64(val) in seen {
|
||||||
c.error('enum value `$val` already exists', field.expr.pos)
|
c.error('enum value `$val` already exists', field.expr.pos)
|
||||||
}
|
}
|
||||||
seen << i64(val)
|
seen << i64(val)
|
||||||
|
@ -1728,7 +1732,8 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) {
|
||||||
last := seen[seen.len - 1]
|
last := seen[seen.len - 1]
|
||||||
if last == checker.int_max {
|
if last == checker.int_max {
|
||||||
c.error('enum value overflows', field.pos)
|
c.error('enum value overflows', field.pos)
|
||||||
} else if !c.pref.translated && !node.is_multi_allowed && last + 1 in seen {
|
} else if !c.pref.translated && !c.file.is_translated && !node.is_multi_allowed
|
||||||
|
&& last + 1 in seen {
|
||||||
c.error('enum value `${last + 1}` already exists', field.pos)
|
c.error('enum value `${last + 1}` already exists', field.pos)
|
||||||
}
|
}
|
||||||
seen << last + 1
|
seen << last + 1
|
||||||
|
@ -2720,7 +2725,7 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe
|
} else if to_type == ast.bool_type && from_type != ast.bool_type && !c.inside_unsafe
|
||||||
&& !c.pref.translated {
|
&& !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
c.error('cannot cast to bool - use e.g. `some_int != 0` instead', node.pos)
|
||||||
} else if from_type == ast.none_type && !to_type.has_flag(.optional) {
|
} else if from_type == ast.none_type && !to_type.has_flag(.optional) {
|
||||||
type_name := c.table.type_to_str(to_type)
|
type_name := c.table.type_to_str(to_type)
|
||||||
|
@ -3404,21 +3409,16 @@ pub fn (mut c Checker) mark_as_referenced(mut node ast.Expr, as_interface bool)
|
||||||
obj = c.fn_scope.find_var(node.obj.name) or { obj }
|
obj = c.fn_scope.find_var(node.obj.name) or { obj }
|
||||||
}
|
}
|
||||||
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
||||||
if obj.is_stack_obj && !type_sym.is_heap() && !c.pref.translated {
|
if obj.is_stack_obj && !type_sym.is_heap() && !c.pref.translated
|
||||||
|
&& !c.file.is_translated {
|
||||||
suggestion := if type_sym.kind == .struct_ {
|
suggestion := if type_sym.kind == .struct_ {
|
||||||
'declaring `$type_sym.name` as `[heap]`'
|
'declaring `$type_sym.name` as `[heap]`'
|
||||||
} else {
|
} else {
|
||||||
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
'wrapping the `$type_sym.name` object in a `struct` declared as `[heap]`'
|
||||||
}
|
}
|
||||||
if !c.pref.translated {
|
mischief := if as_interface { 'used as interface object' } else { 'referenced' }
|
||||||
mischief := if as_interface {
|
c.error('`$node.name` cannot be $mischief outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
|
||||||
'used as interface object'
|
node.pos)
|
||||||
} else {
|
|
||||||
'referenced'
|
|
||||||
}
|
|
||||||
c.error('`$node.name` cannot be $mischief outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.',
|
|
||||||
node.pos)
|
|
||||||
}
|
|
||||||
} else if type_sym.kind == .array_fixed {
|
} else if type_sym.kind == .array_fixed {
|
||||||
c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack',
|
c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack',
|
||||||
node.pos)
|
node.pos)
|
||||||
|
@ -3532,15 +3532,16 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type {
|
||||||
if right_type.is_ptr() {
|
if right_type.is_ptr() {
|
||||||
return right_type.deref()
|
return right_type.deref()
|
||||||
}
|
}
|
||||||
if !right_type.is_pointer() && !c.pref.translated {
|
if !right_type.is_pointer() && !c.pref.translated && !c.file.is_translated {
|
||||||
s := c.table.type_to_str(right_type)
|
s := c.table.type_to_str(right_type)
|
||||||
c.error('invalid indirect of `$s`', node.pos)
|
c.error('invalid indirect of `$s`', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if node.op == .bit_not && !right_type.is_int() && !c.pref.translated {
|
if node.op == .bit_not && !right_type.is_int() && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('operator ~ only defined on int types', node.pos)
|
c.error('operator ~ only defined on int types', node.pos)
|
||||||
}
|
}
|
||||||
if node.op == .not && right_type != ast.bool_type_idx && !c.pref.translated {
|
if node.op == .not && right_type != ast.bool_type_idx && !c.pref.translated
|
||||||
|
&& !c.file.is_translated {
|
||||||
c.error('! operator can only be used with bool types', node.pos)
|
c.error('! operator can only be used with bool types', node.pos)
|
||||||
}
|
}
|
||||||
// FIXME
|
// FIXME
|
||||||
|
@ -3654,7 +3655,7 @@ pub fn (mut c Checker) index_expr(mut node ast.IndexExpr) ast.Type {
|
||||||
is_ok = v.is_mut && v.is_arg && !typ.deref().is_ptr()
|
is_ok = v.is_mut && v.is_arg && !typ.deref().is_ptr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !is_ok && !c.pref.translated {
|
if !is_ok && !c.pref.translated && !c.file.is_translated {
|
||||||
c.warn('pointer indexing is only allowed in `unsafe` blocks', node.pos)
|
c.warn('pointer indexing is only allowed in `unsafe` blocks', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3736,7 +3737,7 @@ pub fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut typ := ast.new_type(typ_idx)
|
mut typ := ast.new_type(typ_idx)
|
||||||
if c.pref.translated {
|
if c.pref.translated || c.file.is_translated {
|
||||||
// TODO make more strict
|
// TODO make more strict
|
||||||
node.typ = typ
|
node.typ = typ
|
||||||
return typ
|
return typ
|
||||||
|
@ -3752,7 +3753,7 @@ pub fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type {
|
||||||
typ_sym = c.table.sym(typ)
|
typ_sym = c.table.sym(typ)
|
||||||
}
|
}
|
||||||
fsym := c.table.final_sym(typ)
|
fsym := c.table.final_sym(typ)
|
||||||
if fsym.kind != .enum_ && !c.pref.translated {
|
if fsym.kind != .enum_ && !c.pref.translated && !c.file.is_translated {
|
||||||
// TODO in C int fields can be compared to enums, need to handle that in C2V
|
// TODO in C int fields can be compared to enums, need to handle that in C2V
|
||||||
c.error('expected type is not an enum (`$typ_sym.name`)', node.pos)
|
c.error('expected type is not an enum (`$typ_sym.name`)', node.pos)
|
||||||
return ast.void_type
|
return ast.void_type
|
||||||
|
@ -3839,7 +3840,7 @@ pub fn (mut c Checker) error(message string, pos token.Pos) {
|
||||||
print_backtrace()
|
print_backtrace()
|
||||||
exit(1)
|
exit(1)
|
||||||
}
|
}
|
||||||
if c.pref.translated && message.starts_with('mismatched types') {
|
if (c.pref.translated || c.file.is_translated) && message.starts_with('mismatched types') {
|
||||||
// TODO move this
|
// TODO move this
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,8 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.pref.translated && node.is_variadic && node.params.len == 1 && param.typ.is_ptr() {
|
if (c.pref.translated || c.file.is_translated) && node.is_variadic
|
||||||
|
&& node.params.len == 1 && param.typ.is_ptr() {
|
||||||
// TODO c2v hack to fix `(const char *s, ...)`
|
// TODO c2v hack to fix `(const char *s, ...)`
|
||||||
param.typ = ast.int_type.ref()
|
param.typ = ast.int_type.ref()
|
||||||
}
|
}
|
||||||
|
@ -679,7 +680,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
}
|
}
|
||||||
node.is_keep_alive = func.is_keep_alive
|
node.is_keep_alive = func.is_keep_alive
|
||||||
if func.mod != 'builtin' && func.language == .v && func.no_body && !c.pref.translated
|
if func.mod != 'builtin' && func.language == .v && func.no_body && !c.pref.translated
|
||||||
&& !func.is_unsafe {
|
&& !c.file.is_translated && !func.is_unsafe {
|
||||||
c.error('cannot call a function that does not have a body', node.pos)
|
c.error('cannot call a function that does not have a body', node.pos)
|
||||||
}
|
}
|
||||||
for concrete_type in node.concrete_types {
|
for concrete_type in node.concrete_types {
|
||||||
|
@ -827,7 +828,8 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
if call_arg.typ != param.typ
|
if call_arg.typ != param.typ
|
||||||
&& (param.typ == ast.voidptr_type || final_param_sym.idx == ast.voidptr_type_idx)
|
&& (param.typ == ast.voidptr_type || final_param_sym.idx == ast.voidptr_type_idx)
|
||||||
&& !call_arg.typ.is_any_kind_of_pointer() && func.language == .v
|
&& !call_arg.typ.is_any_kind_of_pointer() && func.language == .v
|
||||||
&& !call_arg.expr.is_lvalue() && func.name != 'json.encode' && !c.pref.translated {
|
&& !call_arg.expr.is_lvalue() && func.name != 'json.encode' && !c.pref.translated
|
||||||
|
&& !c.file.is_translated {
|
||||||
c.error('expression cannot be passed as `voidptr`', call_arg.expr.pos())
|
c.error('expression cannot be passed as `voidptr`', call_arg.expr.pos())
|
||||||
}
|
}
|
||||||
// Handle expected interface
|
// Handle expected interface
|
||||||
|
@ -853,7 +855,7 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
||||||
if param.typ.has_flag(.generic) {
|
if param.typ.has_flag(.generic) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.pref.translated {
|
if c.pref.translated || c.file.is_translated {
|
||||||
// TODO duplicated logic in check_types() (check_types.v)
|
// TODO duplicated logic in check_types() (check_types.v)
|
||||||
// Allow enums to be used as ints and vice versa in translated code
|
// Allow enums to be used as ints and vice versa in translated code
|
||||||
if param.typ == ast.int_type && typ_sym.kind == .enum_ {
|
if param.typ == ast.int_type && typ_sym.kind == .enum_ {
|
||||||
|
|
|
@ -144,7 +144,7 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) {
|
||||||
prev_loop_label := c.loop_label
|
prev_loop_label := c.loop_label
|
||||||
c.expected_type = ast.bool_type
|
c.expected_type = ast.bool_type
|
||||||
typ := c.expr(node.cond)
|
typ := c.expr(node.cond)
|
||||||
if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated {
|
if !node.is_inf && typ.idx() != ast.bool_type_idx && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('non-bool used as for condition', node.pos)
|
c.error('non-bool used as for condition', node.pos)
|
||||||
}
|
}
|
||||||
if mut node.cond is ast.InfixExpr {
|
if mut node.cond is ast.InfixExpr {
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
mut is_comptime_type_is_expr := false // if `$if T is string`
|
mut is_comptime_type_is_expr := false // if `$if T is string`
|
||||||
for i in 0 .. node.branches.len {
|
for i in 0 .. node.branches.len {
|
||||||
mut branch := node.branches[i]
|
mut branch := node.branches[i]
|
||||||
if branch.cond is ast.ParExpr && !c.pref.translated {
|
if branch.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('unnecessary `()` in `$if_kind` condition, use `$if_kind expr {` instead of `$if_kind (expr) {`.',
|
c.error('unnecessary `()` in `$if_kind` condition, use `$if_kind expr {` instead of `$if_kind (expr) {`.',
|
||||||
branch.pos)
|
branch.pos)
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
|
||||||
c.expected_type = ast.bool_type
|
c.expected_type = ast.bool_type
|
||||||
cond_typ := c.unwrap_generic(c.expr(branch.cond))
|
cond_typ := c.unwrap_generic(c.expr(branch.cond))
|
||||||
if (cond_typ.idx() != ast.bool_type_idx || cond_typ.has_flag(.optional))
|
if (cond_typ.idx() != ast.bool_type_idx || cond_typ.has_flag(.optional))
|
||||||
&& !c.pref.translated {
|
&& !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('non-bool type `${c.table.type_to_str(cond_typ)}` used as if condition',
|
c.error('non-bool type `${c.table.type_to_str(cond_typ)}` used as if condition',
|
||||||
branch.cond.pos())
|
branch.cond.pos())
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import strings
|
||||||
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type {
|
||||||
node.is_expr = c.expected_type != ast.void_type
|
node.is_expr = c.expected_type != ast.void_type
|
||||||
node.expected_type = c.expected_type
|
node.expected_type = c.expected_type
|
||||||
if mut node.cond is ast.ParExpr && !c.pref.translated {
|
if mut node.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.',
|
c.error('unnecessary `()` in `match` condition, use `match expr {` instead of `match (expr) {`.',
|
||||||
node.cond.pos)
|
node.cond.pos)
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_exhaustive {
|
if is_exhaustive {
|
||||||
if has_else && !c.pref.translated {
|
if has_else && !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('match expression is exhaustive, `else` is unnecessary', else_branch.pos)
|
c.error('match expression is exhaustive, `else` is unnecessary', else_branch.pos)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
}
|
}
|
||||||
if (exp_type.is_ptr() || exp_type.is_pointer())
|
if (exp_type.is_ptr() || exp_type.is_pointer())
|
||||||
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
|
&& (!got_typ.is_ptr() && !got_typ.is_pointer()) && got_typ != ast.int_literal_type
|
||||||
&& !c.pref.translated {
|
&& !c.pref.translated && !c.file.is_translated {
|
||||||
pos := node.exprs[i].pos()
|
pos := node.exprs[i].pos()
|
||||||
if node.exprs[i].is_auto_deref_var() {
|
if node.exprs[i].is_auto_deref_var() {
|
||||||
continue
|
continue
|
||||||
|
@ -131,7 +131,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) {
|
||||||
}
|
}
|
||||||
if obj.is_stack_obj && !c.inside_unsafe {
|
if obj.is_stack_obj && !c.inside_unsafe {
|
||||||
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
type_sym := c.table.sym(obj.typ.set_nr_muls(0))
|
||||||
if !type_sym.is_heap() && !c.pref.translated {
|
if !type_sym.is_heap() && !c.pref.translated && !c.file.is_translated {
|
||||||
suggestion := if type_sym.kind == .struct_ {
|
suggestion := if type_sym.kind == .struct_ {
|
||||||
'declaring `$type_sym.name` as `[heap]`'
|
'declaring `$type_sym.name` as `[heap]`'
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -313,7 +313,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||||
}
|
}
|
||||||
if obj.is_stack_obj && !c.inside_unsafe {
|
if obj.is_stack_obj && !c.inside_unsafe {
|
||||||
sym := c.table.sym(obj.typ.set_nr_muls(0))
|
sym := c.table.sym(obj.typ.set_nr_muls(0))
|
||||||
if !sym.is_heap() && !c.pref.translated {
|
if !sym.is_heap() && !c.pref.translated && !c.file.is_translated {
|
||||||
suggestion := if sym.kind == .struct_ {
|
suggestion := if sym.kind == .struct_ {
|
||||||
'declaring `$sym.name` as `[heap]`'
|
'declaring `$sym.name` as `[heap]`'
|
||||||
} else {
|
} else {
|
||||||
|
@ -348,7 +348,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if field.typ.is_ptr() && !field.typ.has_flag(.shared_f) && !node.has_update_expr
|
if field.typ.is_ptr() && !field.typ.has_flag(.shared_f) && !node.has_update_expr
|
||||||
&& !c.pref.translated {
|
&& !c.pref.translated && !c.file.is_translated {
|
||||||
c.error('reference field `${type_sym.name}.$field.name` must be initialized',
|
c.error('reference field `${type_sym.name}.$field.name` must be initialized',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vlib/v/checker/tests/static_vars_in_translated_mode.vv:2:13: error: static variables are supported only in -translated mode or in [unsafe] fn
|
vlib/v/checker/tests/static_vars_in_translated_mode.vv:2:13: error: static variables are supported only in translated mode or in [unsafe] fn
|
||||||
1 | fn counter() int {
|
1 | fn counter() int {
|
||||||
2 | mut static icounter := 0
|
2 | mut static icounter := 0
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
|
|
|
@ -4474,7 +4474,7 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if node_info is ast.IdentFn {
|
} else if node_info is ast.IdentFn {
|
||||||
if g.pref.translated {
|
if g.pref.translated || g.file.is_translated {
|
||||||
// `p_mobjthinker` => `P_MobjThinker`
|
// `p_mobjthinker` => `P_MobjThinker`
|
||||||
if f := g.table.find_fn(node.name) {
|
if f := g.table.find_fn(node.name) {
|
||||||
// TODO PERF fn lookup for each fn call in translated mode
|
// TODO PERF fn lookup for each fn call in translated mode
|
||||||
|
@ -4511,7 +4511,7 @@ fn (mut g Gen) cast_expr(node ast.CastExpr) {
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
} else {
|
} else {
|
||||||
styp := g.typ(node.typ)
|
styp := g.typ(node.typ)
|
||||||
if g.pref.translated && sym.kind == .function {
|
if (g.pref.translated || g.file.is_translated) && sym.kind == .function {
|
||||||
// TODO handle the type in fn casts, not just exprs
|
// TODO handle the type in fn casts, not just exprs
|
||||||
/*
|
/*
|
||||||
info := sym.info as ast.FnType
|
info := sym.info as ast.FnType
|
||||||
|
|
|
@ -436,7 +436,7 @@ fn (mut g Gen) c_fn_name(node &ast.FnDecl) ?string {
|
||||||
name = g.generic_fn_name(g.cur_concrete_types, name, true)
|
name = g.generic_fn_name(g.cur_concrete_types, name, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.pref.translated && node.attrs.contains('c') {
|
if (g.pref.translated || g.file.is_translated) && node.attrs.contains('c') {
|
||||||
// This fixes unknown symbols errors when building separate .c => .v files
|
// This fixes unknown symbols errors when building separate .c => .v files
|
||||||
// into .o files
|
// into .o files
|
||||||
//
|
//
|
||||||
|
@ -1176,7 +1176,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) {
|
||||||
} else {
|
} else {
|
||||||
name = c_name(name)
|
name = c_name(name)
|
||||||
}
|
}
|
||||||
if g.pref.translated {
|
if g.pref.translated || g.file.is_translated {
|
||||||
// For `[c: 'P_TryMove'] fn p_trymove( ... `
|
// For `[c: 'P_TryMove'] fn p_trymove( ... `
|
||||||
// every time `p_trymove` is called, `P_TryMove` must be generated instead.
|
// every time `p_trymove` is called, `P_TryMove` must be generated instead.
|
||||||
if f := g.table.find_fn(node.name) {
|
if f := g.table.find_fn(node.name) {
|
||||||
|
@ -1573,7 +1573,7 @@ fn (mut g Gen) call_args(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem_type := g.typ(arr_info.elem_type)
|
elem_type := g.typ(arr_info.elem_type)
|
||||||
if g.pref.translated && args.len == 1 {
|
if (g.pref.translated || g.file.is_translated) && args.len == 1 {
|
||||||
// Handle `foo(c'str')` for `fn foo(args ...&u8)`
|
// Handle `foo(c'str')` for `fn foo(args ...&u8)`
|
||||||
// TODOC2V handle this in a better place
|
// TODOC2V handle this in a better place
|
||||||
// println(g.table.type_to_str(args[0].typ))
|
// println(g.table.type_to_str(args[0].typ))
|
||||||
|
|
|
@ -158,8 +158,9 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme
|
||||||
iv := lx.info as ast.IdentVar
|
iv := lx.info as ast.IdentVar
|
||||||
share = iv.share
|
share = iv.share
|
||||||
if iv.is_static {
|
if iv.is_static {
|
||||||
if !p.pref.translated && !p.pref.is_fmt && !p.inside_unsafe_fn {
|
if !p.pref.translated && !p.is_translated && !p.pref.is_fmt
|
||||||
return p.error_with_pos('static variables are supported only in -translated mode or in [unsafe] fn',
|
&& !p.inside_unsafe_fn {
|
||||||
|
return p.error_with_pos('static variables are supported only in translated mode or in [unsafe] fn',
|
||||||
lx.pos)
|
lx.pos)
|
||||||
}
|
}
|
||||||
is_static = true
|
is_static = true
|
||||||
|
|
|
@ -255,7 +255,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||||
if p.tok.kind == .name {
|
if p.tok.kind == .name {
|
||||||
// TODO high order fn
|
// TODO high order fn
|
||||||
name = if language == .js { p.check_js_name() } else { p.check_name() }
|
name = if language == .js { p.check_js_name() } else { p.check_name() }
|
||||||
if language == .v && !p.pref.translated && util.contains_capital(name) && !p.builtin_mod {
|
if language == .v && !p.pref.translated && !p.is_translated && util.contains_capital(name)
|
||||||
|
&& !p.builtin_mod {
|
||||||
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
p.error_with_pos('function names cannot contain uppercase letters, use snake_case instead',
|
||||||
name_pos)
|
name_pos)
|
||||||
return ast.FnDecl{
|
return ast.FnDecl{
|
||||||
|
|
|
@ -63,6 +63,7 @@ mut:
|
||||||
is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree
|
is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree
|
||||||
has_globals bool // `[has_globals] module abc` - allow globals declarations, even without -enable-globals, in that single .v file __only__
|
has_globals bool // `[has_globals] module abc` - allow globals declarations, even without -enable-globals, in that single .v file __only__
|
||||||
is_generated bool // `[generated] module abc` - turn off compiler notices for that single .v file __only__.
|
is_generated bool // `[generated] module abc` - turn off compiler notices for that single .v file __only__.
|
||||||
|
is_translated bool // `[translated] module abc` - mark a file as translated, to relax some compiler checks for translated code.
|
||||||
attrs []ast.Attr // attributes before next decl stmt
|
attrs []ast.Attr // attributes before next decl stmt
|
||||||
expr_mod string // for constructing full type names in parse_type()
|
expr_mod string // for constructing full type names in parse_type()
|
||||||
scope &ast.Scope
|
scope &ast.Scope
|
||||||
|
@ -324,6 +325,7 @@ pub fn (mut p Parser) parse() &ast.File {
|
||||||
path_base: p.file_base
|
path_base: p.file_base
|
||||||
is_test: p.inside_test_file
|
is_test: p.inside_test_file
|
||||||
is_generated: p.is_generated
|
is_generated: p.is_generated
|
||||||
|
is_translated: p.is_translated
|
||||||
nr_lines: p.scanner.line_nr
|
nr_lines: p.scanner.line_nr
|
||||||
nr_bytes: p.scanner.text.len
|
nr_bytes: p.scanner.text.len
|
||||||
mod: module_decl
|
mod: module_decl
|
||||||
|
@ -1886,7 +1888,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
|
||||||
// TODO remove translated
|
// TODO remove translated
|
||||||
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() {
|
if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() {
|
||||||
return p.partial_assign_stmt(left, left_comments)
|
return p.partial_assign_stmt(left, left_comments)
|
||||||
} else if !p.pref.translated && !p.pref.is_fmt
|
} else if !p.pref.translated && !p.is_translated && !p.pref.is_fmt
|
||||||
&& tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock, .key_select] {
|
&& tok.kind !in [.key_if, .key_match, .key_lock, .key_rlock, .key_select] {
|
||||||
for node in left {
|
for node in left {
|
||||||
if (is_top_level || p.tok.kind != .rcbr) && node !is ast.CallExpr
|
if (is_top_level || p.tok.kind != .rcbr) && node !is ast.CallExpr
|
||||||
|
@ -3046,6 +3048,9 @@ fn (mut p Parser) module_decl() ast.Module {
|
||||||
ma.pos)
|
ma.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
'translated' {
|
||||||
|
p.is_translated = true
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
p.error_with_pos('unknown module attribute `[$ma.name]`', ma.pos)
|
p.error_with_pos('unknown module attribute `[$ma.name]`', ma.pos)
|
||||||
return mod_node
|
return mod_node
|
||||||
|
@ -3315,7 +3320,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
|
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
|
||||||
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
|
&& !p.is_translated && !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
|
||||||
p.error('use `v -enable-globals ...` to enable globals')
|
p.error('use `v -enable-globals ...` to enable globals')
|
||||||
return ast.GlobalDecl{}
|
return ast.GlobalDecl{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ fn (mut p Parser) struct_decl() ast.StructDecl {
|
||||||
p.error('`$p.tok.lit` lacks body')
|
p.error('`$p.tok.lit` lacks body')
|
||||||
return ast.StructDecl{}
|
return ast.StructDecl{}
|
||||||
}
|
}
|
||||||
if language == .v && !p.builtin_mod && name.len > 0 && !name[0].is_capital()
|
if language == .v && !p.builtin_mod && !p.is_translated && name.len > 0 && !name[0].is_capital()
|
||||||
&& !p.pref.translated {
|
&& !p.pref.translated && !p.is_translated {
|
||||||
p.error_with_pos('struct name `$name` must begin with capital letter', name_pos)
|
p.error_with_pos('struct name `$name` must begin with capital letter', name_pos)
|
||||||
return ast.StructDecl{}
|
return ast.StructDecl{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
[translated]
|
||||||
|
module main
|
||||||
|
|
||||||
|
import math
|
||||||
|
|
||||||
|
fn test_NotSnakeCaseFunction() {}
|
Loading…
Reference in New Issue