From cec7e91714a773b3ec1b7bb0902e9bc03b871a39 Mon Sep 17 00:00:00 2001 From: div72 <60045611+div72@users.noreply.github.com> Date: Sun, 6 Feb 2022 01:16:02 +0300 Subject: [PATCH] v.parser, v.checker, v.gen: add support for [translated] tag (#13373) --- vlib/v/ast/ast.v | 13 ++-- vlib/v/checker/assign.v | 6 +- vlib/v/checker/check_types.v | 2 +- vlib/v/checker/checker.v | 59 ++++++++++--------- vlib/v/checker/fn.v | 10 ++-- vlib/v/checker/for.v | 2 +- vlib/v/checker/if.v | 4 +- vlib/v/checker/match.v | 4 +- vlib/v/checker/return.v | 4 +- vlib/v/checker/struct.v | 4 +- .../tests/static_vars_in_translated_mode.out | 2 +- vlib/v/gen/c/cgen.v | 4 +- vlib/v/gen/c/fn.v | 6 +- vlib/v/parser/assign.v | 5 +- vlib/v/parser/fn.v | 3 +- vlib/v/parser/parser.v | 9 ++- vlib/v/parser/struct.v | 4 +- vlib/v/tests/translated_test.v | 6 ++ 18 files changed, 82 insertions(+), 65 deletions(-) create mode 100644 vlib/v/tests/translated_test.v diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index f4eae42555..31c947bcd5 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -668,12 +668,13 @@ pub mut: [heap] pub struct File { pub: - nr_lines int // number of source code lines in the file (including newlines and comments) - nr_bytes int // number of processed source code bytes - mod Module // the module of the source file (from `module xyz` at the top) - global_scope &Scope - is_test bool // true for _test.v files - is_generated bool // true for `[generated] module xyz` files; turn off notices + nr_lines int // number of source code lines in the file (including newlines and comments) + nr_bytes int // number of processed source code bytes + mod Module // the module of the source file (from `module xyz` at the top) + global_scope &Scope + is_test bool // true for _test.v files + 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: path string // absolute path of the source file - '/projects/v/file.v' path_base string // file name - 'file.v' (useful for tracing) diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 545972e597..887c49f757 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -177,7 +177,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { } if obj.is_stack_obj && !c.inside_unsafe { 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_ { 'declaring `$type_sym.name` as `[heap]`' } else { @@ -278,7 +278,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { ast.PrefixExpr { // Do now allow `*x = y` outside `unsafe` 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', node.pos) } else { @@ -325,7 +325,7 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { // right type was a generic `T` 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 replace all c.pref.translated checks with `$if !translated` for performance continue diff --git a/vlib/v/checker/check_types.v b/vlib/v/checker/check_types.v index a7778687b5..1fae6276c1 100644 --- a/vlib/v/checker/check_types.v +++ b/vlib/v/checker/check_types.v @@ -369,7 +369,7 @@ fn (mut c Checker) check_shift(mut node ast.InfixExpr, left_type ast.Type, right ast.u64_type { 63 } 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)', node.right.pos()) return left_type diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index b36bf617c5..f753880eca 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -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) { - if !c.pref.is_vweb && !c.pref.translated && name.len > 0 - && (name[0] == `_` || name.contains('._')) { + if c.pref.translated || c.file.is_translated { + return + } + if !c.pref.is_vweb && name.len > 0 && (name[0] == `_` || name.contains('._')) { 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', 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) { 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) } } @@ -952,7 +954,7 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { return ast.void_type } .and, .logical_or { - if !c.pref.translated { + if !c.pref.translated && !c.file.is_translated { if node.left_type != ast.bool_type_idx { 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', node.pos) } - } else if !c.pref.translated { + } else if !c.pref.translated && !c.file.is_translated { // Regular enums c.error('only `==` and `!=` are defined on `enum`, use an explicit cast to `int` if needed', node.pos) @@ -1008,7 +1010,8 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } // Dual sides check (compatibility check) 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 if left_type == ast.void_type || right_type == 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 { if expr.obj is 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', expr.pos) } @@ -1137,7 +1140,7 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Pos) { pos = expr.pos } } 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) c.error('field `$expr.field_name` of struct `$type_str` is immutable', expr.pos) @@ -1696,7 +1699,8 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) { val := field.expr.val.i64() if val < checker.int_min || val > checker.int_max { 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) } seen << i64(val) @@ -1728,7 +1732,8 @@ pub fn (mut c Checker) enum_decl(mut node ast.EnumDecl) { last := seen[seen.len - 1] if last == checker.int_max { 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) } 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 - && !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) } else if from_type == ast.none_type && !to_type.has_flag(.optional) { 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 } } 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_ { 'declaring `$type_sym.name` as `[heap]`' } else { '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' - } - c.error('`$node.name` cannot be $mischief outside `unsafe` blocks as it might be stored on stack. Consider ${suggestion}.', - node.pos) - } + mischief := if as_interface { 'used as interface object' } 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 { c.error('cannot reference fixed array `$node.name` outside `unsafe` blocks as it is supposed to be stored on stack', node.pos) @@ -3532,15 +3532,16 @@ pub fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { if right_type.is_ptr() { 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) 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) } - 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) } // 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() } } - 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) } } @@ -3736,7 +3737,7 @@ pub fn (mut c Checker) enum_val(mut node ast.EnumVal) ast.Type { } } mut typ := ast.new_type(typ_idx) - if c.pref.translated { + if c.pref.translated || c.file.is_translated { // TODO make more strict node.typ = 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) } 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 c.error('expected type is not an enum (`$typ_sym.name`)', node.pos) return ast.void_type @@ -3839,7 +3840,7 @@ pub fn (mut c Checker) error(message string, pos token.Pos) { print_backtrace() 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 return } diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index 3735bc43ac..0c72fc8d4b 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -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, ...)` 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 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) } 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 && (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.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()) } // 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) { continue } - if c.pref.translated { + if c.pref.translated || c.file.is_translated { // TODO duplicated logic in check_types() (check_types.v) // Allow enums to be used as ints and vice versa in translated code if param.typ == ast.int_type && typ_sym.kind == .enum_ { diff --git a/vlib/v/checker/for.v b/vlib/v/checker/for.v index 05b401d2e3..91860ca871 100644 --- a/vlib/v/checker/for.v +++ b/vlib/v/checker/for.v @@ -144,7 +144,7 @@ fn (mut c Checker) for_stmt(mut node ast.ForStmt) { prev_loop_label := c.loop_label c.expected_type = ast.bool_type 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) } if mut node.cond is ast.InfixExpr { diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index b85217f8c0..1249df3a28 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -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` for i in 0 .. node.branches.len { 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) {`.', 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 cond_typ := c.unwrap_generic(c.expr(branch.cond)) 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', branch.cond.pos()) } diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index 1d0b774e8d..35a014ba6d 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -8,7 +8,7 @@ import strings pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) ast.Type { node.is_expr = c.expected_type != ast.void_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) {`.', 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 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) } return diff --git a/vlib/v/checker/return.v b/vlib/v/checker/return.v index cbbf0cf2a5..e9ea15a2d6 100644 --- a/vlib/v/checker/return.v +++ b/vlib/v/checker/return.v @@ -113,7 +113,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { } if (exp_type.is_ptr() || exp_type.is_pointer()) && (!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() if node.exprs[i].is_auto_deref_var() { continue @@ -131,7 +131,7 @@ pub fn (mut c Checker) return_stmt(mut node ast.Return) { } if obj.is_stack_obj && !c.inside_unsafe { 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_ { 'declaring `$type_sym.name` as `[heap]`' } else { diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index c8f8177ab4..c87f24cd68 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -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 { 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_ { 'declaring `$sym.name` as `[heap]`' } else { @@ -348,7 +348,7 @@ pub fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type { continue } 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', node.pos) } diff --git a/vlib/v/checker/tests/static_vars_in_translated_mode.out b/vlib/v/checker/tests/static_vars_in_translated_mode.out index 18c297a3fd..966a2d75fb 100644 --- a/vlib/v/checker/tests/static_vars_in_translated_mode.out +++ b/vlib/v/checker/tests/static_vars_in_translated_mode.out @@ -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 { 2 | mut static icounter := 0 | ~~~~~~~~ diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 42fde59c49..2181c09d37 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -4474,7 +4474,7 @@ fn (mut g Gen) ident(node ast.Ident) { } } } else if node_info is ast.IdentFn { - if g.pref.translated { + if g.pref.translated || g.file.is_translated { // `p_mobjthinker` => `P_MobjThinker` if f := g.table.find_fn(node.name) { // 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) } else { 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 /* info := sym.info as ast.FnType diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 073345e19f..c6c49889a9 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -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) } - 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 // into .o files // @@ -1176,7 +1176,7 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } else { name = c_name(name) } - if g.pref.translated { + if g.pref.translated || g.file.is_translated { // For `[c: 'P_TryMove'] fn p_trymove( ... ` // every time `p_trymove` is called, `P_TryMove` must be generated instead. 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) - 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)` // TODOC2V handle this in a better place // println(g.table.type_to_str(args[0].typ)) diff --git a/vlib/v/parser/assign.v b/vlib/v/parser/assign.v index 776b54aafb..d20f47f48a 100644 --- a/vlib/v/parser/assign.v +++ b/vlib/v/parser/assign.v @@ -158,8 +158,9 @@ fn (mut p Parser) partial_assign_stmt(left []ast.Expr, left_comments []ast.Comme iv := lx.info as ast.IdentVar share = iv.share if iv.is_static { - if !p.pref.translated && !p.pref.is_fmt && !p.inside_unsafe_fn { - return p.error_with_pos('static variables are supported only in -translated mode or in [unsafe] fn', + if !p.pref.translated && !p.is_translated && !p.pref.is_fmt + && !p.inside_unsafe_fn { + return p.error_with_pos('static variables are supported only in translated mode or in [unsafe] fn', lx.pos) } is_static = true diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 216edd2dba..0fe9e9f838 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -255,7 +255,8 @@ fn (mut p Parser) fn_decl() ast.FnDecl { if p.tok.kind == .name { // TODO high order fn 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', name_pos) return ast.FnDecl{ diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 26a26d9684..f5b0167242 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -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 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_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 expr_mod string // for constructing full type names in parse_type() scope &ast.Scope @@ -324,6 +325,7 @@ pub fn (mut p Parser) parse() &ast.File { path_base: p.file_base is_test: p.inside_test_file is_generated: p.is_generated + is_translated: p.is_translated nr_lines: p.scanner.line_nr nr_bytes: p.scanner.text.len mod: module_decl @@ -1886,7 +1888,7 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt { // TODO remove translated if p.tok.kind in [.assign, .decl_assign] || p.tok.kind.is_assign() { 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] { for node in left { 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) } } + 'translated' { + p.is_translated = true + } else { p.error_with_pos('unknown module attribute `[$ma.name]`', ma.pos) 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 - && !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') return ast.GlobalDecl{} } diff --git a/vlib/v/parser/struct.v b/vlib/v/parser/struct.v index dde842e6e5..1b670371a0 100644 --- a/vlib/v/parser/struct.v +++ b/vlib/v/parser/struct.v @@ -53,8 +53,8 @@ fn (mut p Parser) struct_decl() ast.StructDecl { p.error('`$p.tok.lit` lacks body') return ast.StructDecl{} } - if language == .v && !p.builtin_mod && name.len > 0 && !name[0].is_capital() - && !p.pref.translated { + if language == .v && !p.builtin_mod && !p.is_translated && name.len > 0 && !name[0].is_capital() + && !p.pref.translated && !p.is_translated { p.error_with_pos('struct name `$name` must begin with capital letter', name_pos) return ast.StructDecl{} } diff --git a/vlib/v/tests/translated_test.v b/vlib/v/tests/translated_test.v new file mode 100644 index 0000000000..f4149c6ae7 --- /dev/null +++ b/vlib/v/tests/translated_test.v @@ -0,0 +1,6 @@ +[translated] +module main + +import math + +fn test_NotSnakeCaseFunction() {}